private int LoadFolderMessages(IMailFolder folder, MailFolder mailFolder, int limitMessages)
        {
            var loaded = 0;

            ImapFolderUids folderUids;

            if (!Account.ImapIntervals.TryGetValue(folder.Name, out folderUids))
            {
                folderUids = new ImapFolderUids(new List <int> {
                    1, int.MaxValue
                }, 1);
                // by default - mailbox never was processed before
            }

            var imapIntervals = new ImapIntervals(folderUids.UnhandledUidIntervals);
            var beginDateUid  = folderUids.BeginDateUid;

            IList <UniqueId> allUids;

            try
            {
                allUids = folder.Fetch(0, -1, MessageSummaryItems.UniqueId, CancelToken).Select(r => r.UniqueId).ToList();
            }
            catch (NotSupportedException)
            {
                const int start     = 0;
                var       end       = folder.Count;
                const int increment = 1;

                allUids = Enumerable
                          .Repeat(start, (end - start) / 1 + 1)
                          .Select((tr, ti) => tr + increment * ti)
                          .Select(n => new UniqueId((uint)n))
                          .ToList();
            }

            foreach (var uidsInterval in imapIntervals.GetUnhandledIntervalsCopy())
            {
                var interval       = uidsInterval;
                var uidsCollection =
                    allUids.Select(u => u)
                    .Where(u => u.Id <= interval.To && u.Id >= interval.From)
                    .OrderByDescending(x => x)
                    .ToList();

                if (!uidsCollection.Any())
                {
                    if (!uidsInterval.IsToUidMax())
                    {
                        imapIntervals.AddHandledInterval(uidsInterval);
                    }
                    continue;
                }

                var first = uidsCollection.First().Id;
                var toUid = (int)(uidsInterval.IsToUidMax()
                    ? first
                    : Math.Max(uidsInterval.To, first));

                var infoList =
                    folder.Fetch(limitMessages > 0 ? uidsCollection.Take(limitMessages * 3).ToList() : uidsCollection,
                                 MessageSummaryItems.Flags | MessageSummaryItems.GMailLabels | MessageSummaryItems.InternalDate);

                foreach (var uid in uidsCollection)
                {
                    try
                    {
                        if (!Imap.IsConnected || CancelToken.IsCancellationRequested)
                        {
                            break;
                        }

                        var message = folder.GetMessage(uid, CancelToken);

                        var uid1 = uid;
                        var info = infoList.FirstOrDefault(t => t.UniqueId == uid1);

                        message.FixDateIssues(info != null ? info.InternalDate : null, Log);

                        if (message.Date < Account.BeginDate)
                        {
                            Log.Debug("Skip message (Date = {0}) on BeginDate = {1}", message.Date,
                                      Account.BeginDate);
                            imapIntervals.SetBeginIndex(toUid);
                            beginDateUid = toUid;
                            break;
                        }

                        var unread = info != null &&
                                     (info.UserFlags.Contains("\\Unseen") ||
                                      info.Flags.HasValue && !info.Flags.Value.HasFlag(MessageFlags.Seen));

                        message.FixEncodingIssues(Log);

                        OnGetMessage(message, uid.Id.ToString(), unread, mailFolder);

                        loaded++;
                    }
                    catch (OperationCanceledException)
                    {
                        break;
                    }
                    catch (Exception e)
                    {
                        Log.Error(
                            "ProcessMessages() Tenant={0} User='******' Account='{2}', MailboxId={3}, UID={4} Exception:\r\n{5}\r\n",
                            Account.TenantId, Account.UserId, Account.EMail.Address, Account.MailBoxId,
                            uid, e);

                        if (uid != uidsCollection.First() && (int)uid.Id != toUid)
                        {
                            imapIntervals.AddHandledInterval(new UidInterval((int)uid.Id + 1, toUid));
                        }
                        toUid = (int)uid.Id - 1;

                        if (e is IOException)
                        {
                            break; // stop checking other mailboxes
                        }

                        continue;
                    }

                    // after successfully message saving - lets update imap intervals state
                    imapIntervals.AddHandledInterval(
                        new UidInterval(
                            uid.Id == uidsCollection.Last().Id&& uidsInterval.IsFromUidMin()
                                ? uidsInterval.From
                                : (int)uid.Id, toUid));

                    toUid = (int)uid.Id - 1;

                    if (limitMessages > 0 && loaded >= limitMessages)
                    {
                        break;
                    }
                }

                if (CancelToken.IsCancellationRequested || limitMessages > 0 && loaded >= limitMessages)
                {
                    break;
                }
            }

            var updatedImapFolderUids = new ImapFolderUids(imapIntervals.ToIndexes(), beginDateUid);

            if (!Account.ImapIntervals.Keys.Contains(folder.Name))
            {
                Account.ImapFolderChanged = true;
                Account.ImapIntervals.Add(folder.Name, updatedImapFolderUids);
            }
            else if (Account.ImapIntervals[folder.Name] != updatedImapFolderUids)
            {
                Account.ImapFolderChanged          = true;
                Account.ImapIntervals[folder.Name] = updatedImapFolderUids;
            }

            return(loaded);
        }
Exemplo n.º 2
0
        private int LoadMailboxMessage(Mailbox mb,
                                       int folderId,
                                       int maxMessagesPerSession,
                                       string[] tagsNames, out bool quotaErrorFlag)
        {
            UpdateTimeCheckedIfNeeded();

            ImapFolderUids folderUids;

            if (!Account.ImapIntervals.TryGetValue(mb.Name, out folderUids))
            {
                folderUids = new ImapFolderUids(new List <int> {
                    1, int.MaxValue
                }, 1);                                                               // by default - mailbox never was processed before
            }

            var imapIntervals = new ImapIntervals(folderUids.UnhandledUidIntervals);
            var beginDateUid  = folderUids.BeginDateUid;

            quotaErrorFlag = false;

            int[] tagsIds       = null;
            var   tagsRetrieved = false;

            var allUids = mb.UidSearch("1:*").OrderBy(i => i).SkipWhile(i => i < beginDateUid).ToList();

            foreach (var uidsInterval in imapIntervals.GetUnhandledIntervalsCopy())
            {
                cancelToken.ThrowIfCancellationRequested();

                if (!mb.SourceClient.IsConnected)
                {
                    break;
                }

                if (maxMessagesPerSession == 0)
                {
                    break;
                }

                var interval       = uidsInterval;
                var uidsCollection =
                    allUids.Select(u => u)
                    .Where(u => u <= interval.To && u >= interval.From)
                    .OrderByDescending(x => x)
                    .ToList();

                if (!uidsCollection.Any())
                {
                    if (!uidsInterval.IsToUidMax())
                    {
                        imapIntervals.AddHandledInterval(uidsInterval);
                    }
                    continue;
                }

                var toUid = uidsInterval.IsToUidMax()
                                 ? uidsCollection.First()
                                 : Math.Max(uidsInterval.To, uidsCollection.First());

                #region Loading messages

                foreach (var uid in uidsCollection)
                {
                    var hasParseError = false;

                    cancelToken.ThrowIfCancellationRequested();

                    try
                    {
                        if (!mb.SourceClient.IsConnected)
                        {
                            log.Warn("Imap4-server is disconnected. Skip another messages.");
                            break;
                        }

                        log.Debug("Processing new message\tUID: {0}", uid);

                        // flags should be retrieved before message fetch - because mail server
                        // could add seen flag right after message was retrieved by us
                        var flags = mb.Fetch.UidFlags(uid);

                        //Peek method didn't set \Seen flag on mail
                        var message = mb.Fetch.UidMessageObjectPeek(uid);

                        if (message.ParseException != null)
                        {
                            log.Error(
                                "ActiveUp: message parsed with some errors. MailboxId = {0} Message UID = {1} Error: {2}",
                                Account.MailBoxId, uid, message.ParseException.ToString());

                            hasParseError = true;
                        }

                        UpdateTimeCheckedIfNeeded();

                        if (message.Date < Account.BeginDate)
                        {
                            log.Debug("Skip message (Date = {0}) on BeginDate = {1}", message.Date, Account.BeginDate);
                            imapIntervals.SetBeginIndex(toUid);
                            beginDateUid = toUid;
                            break;
                        }

                        var uniqueIdentifier = string.Format("{0}|{1}|{2}|{3}",
                                                             message.From.Email,
                                                             message.Subject,
                                                             message.DateString,
                                                             message.MessageId);

                        var headerMd5 = uniqueIdentifier.GetMd5();

                        //Get tags ids for folder before message proccessing only once
                        if (!tagsRetrieved)
                        {
                            tagsIds       = tagsNames.Any() ? InvokeOnGetOrCreateTags(tagsNames) : null;
                            tagsRetrieved = true;
                        }

                        var unread = null == flags["seen"];
                        var uidl   = string.Format("{0}-{1}", uid, folderId);
                        RetrieveMessage(message, folderId, uidl, headerMd5, hasParseError, unread, tagsIds);
                    }
                    catch (Exception e)
                    {
                        log.Error(
                            "ProcessMessages() Tenant={0} User='******' Account='{2}', MailboxId={3}, UID={4} Exception:\r\n{5}\r\n",
                            Account.TenantId, Account.UserId, Account.EMail.Address, Account.MailBoxId,
                            uid, e);

                        if (e is IOException || e is MailBoxOutException)
                        {
                            maxMessagesPerSession = 0; // stop checking other mailboxes
                        }
                        else if (e is TenantQuotaException)
                        {
                            quotaErrorFlag = true;
                        }

                        if (uid != uidsCollection.First() && uid != toUid)
                        {
                            imapIntervals.AddHandledInterval(new UidInterval(uid + 1, toUid));
                        }
                        toUid = uid - 1;

                        if (maxMessagesPerSession == 0)
                        {
                            break;
                        }

                        continue;
                    }

                    // after successfully message saving - lets update imap intervals state
                    imapIntervals.AddHandledInterval(
                        new UidInterval(
                            uid == uidsCollection.Last() && uidsInterval.IsFromUidMin() ? uidsInterval.From : uid, toUid));

                    toUid = uid - 1;

                    UpdateTimeCheckedIfNeeded();

                    maxMessagesPerSession--;

                    if (maxMessagesPerSession != 0)
                    {
                        continue;
                    }

                    log.Info("Limit of max messages per session is exceeded!");
                    break;
                }

                #endregion
            }

            var updatedImapFolderUids = new ImapFolderUids(imapIntervals.ToIndexes(), beginDateUid);

            if (!Account.ImapIntervals.Keys.Contains(mb.Name))
            {
                Account.ImapFolderChanged = true;
                Account.ImapIntervals.Add(mb.Name, updatedImapFolderUids);
            }
            else if (Account.ImapIntervals[mb.Name] != updatedImapFolderUids)
            {
                Account.ImapFolderChanged      = true;
                Account.ImapIntervals[mb.Name] = updatedImapFolderUids;
            }

            return(maxMessagesPerSession);
        }