Ejemplo n.º 1
0
        private async void SaveClick(object sender, EventArgs e)
        {
            // Filter out special labels that don't match mailbox names.
            List <string> labelsBefore = GmailExtensions.GetNonSpecialLabels(Conversation.Labels);
            List <string> labelsAfter  = LabelList.SelectedItems.Cast <LabelInfo>()
                                         .Select(info => info.Name).ToList();

            Account       account    = App.AccountManager.GetCurrentAccount();
            List <string> addTo      = new List <string>();
            List <string> removeFrom = new List <string>();

            // Diff before and after.  For new labels, add that label.
            // For old labels, remove that label.
            SyncUtilities.CompareLists(labelsBefore, labelsAfter, input => input,
                                       (before, after) => { },     // Match, do nothing
                                       (before) => removeFrom.Add(before),
                                       (after) => addTo.Add(after) // Added
                                       );

            // Do additions before removals.  Additions will fail if you first remove the current label because you'll
            // have deleted the message from the current mailbox.
            foreach (string label in addTo)
            {
                await account.AddLabelAsync(Conversation.Messages, label); // Added
            }
            foreach (string label in removeFrom)
            {
                await account.RemoveLabelAsync(Conversation.Messages, label); // Removed
            }

            NavigationService.GoBack();
        }
Ejemplo n.º 2
0
        // Removing labels for the non-active mailboxes is a bit more work.  We must:
        // - Switch to that mailbox
        // - Find the message mailbox UID for that message
        // -- Search storage first, then online
        // - Delete the message from the mailbox & storage
        // - Switch back to the original mailbox
        private async Task RemoveOtherLabelAsync(List <MailMessage> messages, string labelName)
        {
            List <MailMessage> changedMessages = new List <MailMessage>();

            // Remove the label from the messages and store the changes.
            // TODO: Remove message from disk if the message is no longer referenced by any sync'd labels.
            foreach (var message in messages)
            {
                if (message.RemoveLabel(labelName))
                {
                    changedMessages.Add(message);
                    if (MailStorage.HasMessageLables(message.GetThreadId(), message.GetMessageId()))
                    {
                        // Update on disk
                        await MailStorage.StoreMessageLabelsAsync(message);
                    }
                }
            }

            LabelInfo labelInfo = Labels.Where(info => info.Name.Equals(labelName)).FirstOrDefault() ?? new LabelInfo()
            {
                Name = labelName
            };

            // Look up UIDs. If they're not here, we may need to check online.
            List <string>        localMessageIds    = new List <string>(); // Ids for messages we have referenced from a locally sync'd label.
            List <string>        nonlocalMessageIds = new List <string>(); // Ids for messages we'll have to lookup online.
            List <MessageIdInfo> labelMessageIds    = (labelInfo.StoreMessages ? await MailStorage.GetLabelMessageListAsync(labelName) : null)
                                                      ?? new List <MessageIdInfo>();

            SyncUtilities.CompareLists(changedMessages.Select(message => message.GetMessageId()), labelMessageIds.Select(ids => ids.MessageId), id => id,
                                       (searchId, localId) => localMessageIds.Add(localId),
                                       (searchId) => nonlocalMessageIds.Add(searchId),
                                       (localId) => { } // Only in storage, ignore.
                                       );

            // Remove from that labelList
            List <MessageIdInfo> updatedLabelMessageIds = labelMessageIds.Where(messageIds => !localMessageIds.Contains(messageIds.MessageId)).ToList();

            if (labelInfo.StoreMessages)
            {
                await MailStorage.StoreLabelMessageListAsync(labelName, updatedLabelMessageIds);
            }

            List <string> uidsToRemove = labelMessageIds.Where(messageIds => localMessageIds.Contains(messageIds.MessageId)).Select(ids => ids.Uid).ToList();

            // TODO: Queue up this action for later
            if (nonlocalMessageIds.Count > 0)
            {
                List <string> remoteUids = await GmailImap.GetUidsFromMessageIds(labelName, nonlocalMessageIds);

                uidsToRemove.AddRange(remoteUids);
            }
            if (uidsToRemove.Count > 0)
            {
                await GmailImap.RemoveOtherLabelAsync(labelName, uidsToRemove);
            }
        }
Ejemplo n.º 3
0
        //   Determine oldest date: Now - Range
        //   Query server for ids of messages in folder since oldest date (async while loading local list?)
        //   Load stored message list (Ids only)
        //   For each new item in the remote list:
        //   - Download & save headers, flags, & labels, add to local list, save (TODO: What if another label already had this message?)
        //   - Anything that is unread counts as new mail. It wasn't downloaded last time we opened the app, so the message date is irrelevant.
        //   - Queue body and attachments for download later.
        //   For each item that was already in the local list
        //   - query for updated flags and labels
        //   - Anything that is unread since the last time we opened the app counts as new mail.
        //   - Queue body and attachments for download later (if they weren't downloaded on a previous sync)
        public async Task <int> SyncMessageHeadersAsync(CancellationToken cancellationToken)
        {
            DateTime syncMailSince = DateTime.Now - Info.Range;
            Task <IList <GmailMessageInfo> > remoteMessageInfoTask = GmailImap.GetCurrentMessageIdsAsync(syncMailSince);
            List <MessageIdInfo>             localIds = await MailStorage.GetLabelMessageListAsync(ActiveLabel.Info.Name) ?? new List <MessageIdInfo>();

            IList <GmailMessageInfo>    remoteMessageInfos = await remoteMessageInfoTask;
            IEnumerable <MessageIdInfo> remoteIds          = remoteMessageInfos.Select(info => new MessageIdInfo()
            {
                Uid       = info.Uid,
                MessageId = info.MessageId,
                ThreadId  = info.ThreadId,
            });

            DateTime lastAppActivation = AppSettings.LastAppActivationTime;
            int      newMessages       = remoteMessageInfos
                                         .Where(info => info.Date > lastAppActivation && !info.Flags.Contains(@"\Seen")).Count();

            IList <MessageIdInfo> messagesInBothPlaces     = new List <MessageIdInfo>();
            IList <MessageIdInfo> messagesOnlyRemote       = new List <MessageIdInfo>();
            IList <MessageIdInfo> messagesOnlyLocal        = new List <MessageIdInfo>();
            IList <MessageIdInfo> messageHeadersToDownload = new List <MessageIdInfo>();

            if (cancellationToken.IsCancellationRequested)
            {
                return(newMessages);
            }

            SyncUtilities.CompareLists(remoteIds, localIds, info => info.Uid,
                                       (remote, local) => messagesInBothPlaces.Add(local),
                                       remoteOnly => messagesOnlyRemote.Add(remoteOnly),
                                       localOnly => messagesOnlyLocal.Add(localOnly));

            if (cancellationToken.IsCancellationRequested)
            {
                return(newMessages);
            }

            bool localMessageListModified = false;

            foreach (MessageIdInfo idInfo in messagesOnlyRemote)
            {
                // Check if the item is already on disk (from another label)
                if (MailStorage.HasMessageHeaders(idInfo.ThreadId, idInfo.MessageId))
                {
                    // If so, update the labels and flags.
                    messagesInBothPlaces.Add(idInfo);
                }
                // If not, download the headers / message structure.
                else
                {
                    messageHeadersToDownload.Add(idInfo);
                }

                // Add to labe's list.
                localIds.Add(idInfo);
                localMessageListModified = true;
            }

            if (messageHeadersToDownload.Count > 0)
            {
                // Bulk download headers
                await GmailImap.GetEnvelopeAndStructureAsync(messageHeadersToDownload.Select(ids => ids.Uid),
                                                             async data =>
                {
                    // Find the matching Ids
                    string messageId      = data.GetMessageId();
                    GmailMessageInfo info = remoteMessageInfos.First(infos => infos.MessageId.Equals(messageId));

                    if (cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }

                    // Save headers, labels, and flags to disk
                    await MailStorage.StoreMessageFlagsAsync(info.ThreadId, info.MessageId, info.Flags);
                    await MailStorage.StoreMessageLabelsAsync(info.ThreadId, info.MessageId, info.Labels);
                    await MailStorage.StoreMessageHeadersAsync(data);
                },
                                                             cancellationToken);
            }

            if (cancellationToken.IsCancellationRequested)
            {
                return(newMessages);
            }

            if (localMessageListModified)
            {
                await MailStorage.StoreLabelMessageListAsync(ActiveLabel.Info.Name, localIds);
            }

            foreach (MessageIdInfo idInfo in messagesInBothPlaces)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return(newMessages);
                }
                // Find the matching Ids
                GmailMessageInfo info = remoteMessageInfos.First(infos => infos.MessageId.Equals(idInfo.MessageId));
                // Update the labels and flags.
                await MailStorage.StoreMessageFlagsAsync(info.ThreadId, info.MessageId, info.Flags);

                await MailStorage.StoreMessageLabelsAsync(info.ThreadId, info.MessageId, info.Labels);
            }

            if (cancellationToken.IsCancellationRequested)
            {
                return(newMessages);
            }

            // Only remember our last sync time if we (mostly) finished.
            ActiveLabel.Info.LastSync = DateTime.Now;
            await SaveLabelSettingsAsync();

            if (messagesOnlyLocal.Any())
            {
                // Remove deleted mails from label list
                localIds = localIds.Except(messagesOnlyLocal).ToList();
                await MailStorage.StoreLabelMessageListAsync(ActiveLabel.Info.Name, localIds);

                // TODO: GC message data.
            }

            return(newMessages);
        }