This project is read-only.

Message enumerators

Topics: Feature Requests
Nov 26, 2016 at 11:17 AM
Edited Nov 26, 2016 at 11:19 AM
Добрый день!

Существует ли возможность перебора сообщений с сервера без предварительного скачивания всех запрошенных сообщений?

Пришлось немного взломать Вашу библиотеку для достижения нужной функциональности:
    internal static class Service
    {
        private static readonly Func<Folder, string, int, long[]> sf_SearchMessageIds_Method;
        private static readonly Func<long, ImapClient, Folder, Message> sf_CreateMessage;
        private static readonly Func<Folder, ImapClient> sf_GetFolderClient;

        static Service()
        {
            var folger_type = typeof(Folder);
            var SearchMessageIds_method = folger_type.GetMethod("SearchMessageIds", BindingFlags.Instance | BindingFlags.NonPublic);

            var folger_parameter = Expression.Parameter(typeof(Folder), "folder");
            var query_parameter = Expression.Parameter(typeof(string), "query");
            var count_parameter = Expression.Parameter(typeof(int), "count");

            Expression body = Expression.Call(folger_parameter, SearchMessageIds_method, query_parameter, count_parameter);

            var SearchMessageIds_Expression = Expression.Lambda<Func<Folder, string, int, long[]>>
            (
                body, folger_parameter,
                query_parameter,
                count_parameter
            );

            sf_SearchMessageIds_Method = SearchMessageIds_Expression.Compile();

            var message_type = typeof(Message);
            var message_ctor = message_type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(long), typeof(ImapClient), typeof(Folder) }, new ParameterModifier[0]);

            var id_parameter = Expression.Parameter(typeof(long), "id");
            var client_parameter = Expression.Parameter(typeof(ImapClient), "client");
            var folder_parameter = Expression.Parameter(typeof(Folder), "folder");

            body = Expression.New(message_ctor, id_parameter, client_parameter, folder_parameter);

            var new_message_expression = Expression.Lambda<Func<long, ImapClient, Folder, Message>>(body,
                id_parameter, client_parameter, folder_parameter);

            sf_CreateMessage = new_message_expression.Compile();

            var folder_client_field = folger_type.GetField("_client", BindingFlags.Instance | BindingFlags.NonPublic);
            body = Expression.Field(folder_parameter, folder_client_field);
            sf_GetFolderClient = Expression.Lambda<Func<Folder, ImapClient>>(body, folder_parameter).Compile();
        }

        public static T Init<T>(this T obj, Action<T> action) { action?.Invoke(obj); return obj; }

        public static long[] SearchMessageIDs(this Folder folder, string query = "ALL", int count = -1)
        {
            return sf_SearchMessageIds_Method(folder, query, count);
        }

        public static Message NewMessage(long id, ImapClient client, Folder folder)
        {
            return sf_CreateMessage(id, client, folder);
        }

        public static IEnumerable<Message> FetchMessages
        (
            this Folder folder,
            string query = "ALL",
            MessageFetchMode mode = MessageFetchMode.ClientDefault,
            int count = -1
        )
        {
            return
                folder.SearchMessageIDs(query, count)
                    .Select(id => NewMessage(id, sf_GetFolderClient(folder), folder).Init(m => m.Download(mode)));
        }
    }
Теперь сообщения извлекаются из сервера по очереди и могут быть обработаны по мере поступления, а не все скопом:
            using(var client = new ImapClient())
            {
                Console.WriteLine("Connection {0}", client.Connect(c_ServerAddress, true) ? "successful" : "failed");
                if(!client.IsConnected) return;
                Console.WriteLine("Login {0}", client.Login(c_User, c_Password) ? "successful" : "failed");
                if(!client.IsAuthenticated) return;

                client.Behavior.MessageFetchMode = MessageFetchMode.Basic | MessageFetchMode.GMailExtendedData;

                Console.WriteLine("INBOX messages");
                foreach(var msg in client.Folders.Inbox.FetchMessages())
                    Console.WriteLine("{0}[from:{1}]:{2}", msg.Date, msg.From, msg.Subject);
            }