public bool Validate()
        {
            ImapClient imapClient = new ImapClient(Account);
            Error = string.Empty;

            int tryCount = 2;
            if (imapClient.Connect(tryCount))
            {
                imapClient.Disconnect();
            }
            else
            {
                Error = imapClient.Error;
                return false;
            }

            SmtpClient smtpClient = new SmtpClient(Account);

            if (smtpClient.Connect())
            {
                smtpClient.Disconnect();
            }
            else
            {
                Error = smtpClient.Error;
                return false;
            }

            return true;
        }
        // Updates the mailbox tree in the specified account with ones from the server.
        // Also updates the database to reflect the change.
        private void BeginSyncMailboxList(Account account)
        {
            Task.Factory.StartNew(() => {
                List<Mailbox> localMailboxes = DatabaseManager.GetMailboxes(account.AccountName);

                ImapClient imapClient = new ImapClient(account);
                if (imapClient.Connect())
                {
                    List<Mailbox> serverMailboxes = imapClient.ListMailboxes();

                    var comparer = new CompareMailbox();
                    var localNotServer = localMailboxes.Except(serverMailboxes, comparer).ToList();
                    var serverNotLocal = serverMailboxes.Except(localMailboxes, comparer).ToList();

                    if (localNotServer.Count > 0 || serverNotLocal.Count > 0)
                    {
                        account.Mailboxes.Clear();
                        account.Mailboxes.AddRange(serverMailboxes);

                        if (localNotServer.Count > 0)
                        {
                            DatabaseManager.DeleteMailboxes(localNotServer);
                        }
                        if (serverNotLocal.Count > 0)
                        {
                            DatabaseManager.InsertMailboxes(serverNotLocal);
                        }
                    }

                    imapClient.Disconnect();
                }

                while (!Common.Globals.BootStrapperLoaded)
                {
                    // We don't want to fire this event before the subscribers are ready.
                    // There must be a better way to handle these sort of things.
                    Thread.Sleep(50);
                }
                GlobalEventAggregator.Instance.GetEvent<MailboxListSyncFinishedEvent>().Publish(account);
            });
        }
        private void SyncExistingMessageHeaders(Account account, string mailboxName, ImapClient imapClientOnSelectedStatus, int firstUid, int lastUid)
        {
            Trace.WriteLine("SyncExistingMessageHeaders: Mailbox(" + mailboxName + "), UIDs(" + firstUid + ", " + lastUid + ")");

            // Decrement this at every exit point.
            openSyncOps.AddOrUpdate(account.AccountName, 1, (k, v) => v + 1);

            // Delete all messages that have been deleted from server.
            List <int> serverUids    = new List <int>();
            bool       searchSuccess = imapClientOnSelectedStatus.SearchUids("ALL", serverUids);

            if (searchSuccess)
            {
                List <string> keysToDelete = new List <string>();
                foreach (KeyValuePair <string, Message> entry in MessagesDico)
                {
                    Message msg = entry.Value;
                    if (msg.AccountName == account.AccountName &&
                        msg.MailboxPath == mailboxName &&
                        !serverUids.Contains(msg.Uid))
                    {
                        keysToDelete.Add(entry.Key);
                    }
                }

                List <Message> msgsDeleted = new List <Message>();
                foreach (string key in keysToDelete)
                {
                    Message msg = MessagesDico[key];
                    MessagesDico.Remove(key);
                    OnMessageRemoved(msg);
                    msgsDeleted.Add(msg);
                }

                DatabaseManager.DeleteMessages(msgsDeleted);
            }

            // Now synchronize the remaining messages.
            int messagesCount = lastUid - firstUid + 1;
            int downloadChunk = this.downloadChunkSize;
            int startUid      = lastUid - downloadChunk + 1;
            int endUid        = lastUid;

            while (endUid >= firstUid)
            {
                int abort = 0;
                if (abortLatches.TryGetValue(account.AccountName, out abort) && abort == 1)
                {
                    Trace.WriteLine("Aborting sync...");
                    openSyncOps.AddOrUpdate(account.AccountName, 0, (k, v) => v - 1);
                    return;
                }

                if (startUid < firstUid)
                {
                    startUid = firstUid;
                }
                List <Message> serverMsgs = imapClientOnSelectedStatus.FetchHeaders(startUid, endUid - startUid + 1, true);
                if (serverMsgs.Count > 0)
                {
                    List <Message> messagesAdded = new List <Message>();
                    foreach (Message serverMsg in serverMsgs)
                    {
                        Message localMsg;
                        if (MessagesDico.TryGetValue(serverMsg.UniqueKeyString, out localMsg))
                        {
                            // A local copy exists. Update its flags.
                            if (localMsg.FlagString != serverMsg.FlagString)
                            {
                                localMsg.FlagString = serverMsg.FlagString;
                                OnMessageModified(localMsg);
                            }
                        }
                        else
                        {
                            MessagesDico.Add(serverMsg.UniqueKeyString, serverMsg);
                            OnMessageAdded(serverMsg);
                            messagesAdded.Add(serverMsg);
                        }
                    }
                    DatabaseManager.StoreMessages(messagesAdded);
                }

                endUid   = startUid - 1;
                startUid = endUid - downloadChunk + 1;
            }

            openSyncOps.AddOrUpdate(account.AccountName, 0, (k, v) => v - 1);
        }
        private void SetMessage(Message newMessage)
        {
            if (Message != null)
            {
                Message.PropertyChanged -= HandleModelPropertyChanged;
            }

            Message = newMessage;
            Message.PropertyChanged += HandleModelPropertyChanged;

            Date = ImapParser.ParseDate(Message.DateString);

            if (string.IsNullOrEmpty(Message.Body))
            {
                DownloadMessageBodyAsync();
            }
            else
            {
                // Loading a message whose body has already been downloaded.
                TextBody = MimeUtility.GetTextBody(Message.Body);
                HtmlBody = MimeUtility.GetHtmlBody(Message.Body);
                ProcessedHtmlBody = ProcessHtmlBody(HtmlBody);
                LoadAttachments(Message.Body);

                if (!Message.IsSeen)
                {
                    // Set the \Seen flag.
                    Message.IsSeen = true;
                    DatabaseManager.Update(Message);

                    Task.Run(() => {
                        ImapClient imap = new ImapClient(notification.SelectedAccount);
                        if (imap.Connect())
                        {
                            // Not readonly because we need to set the \Seen flag.
                            bool readOnly = false;
                            if (imap.SelectMailbox(notification.SelectedMailbox.DirectoryPath, readOnly))
                            {
                                imap.SetFlag(ImapClient.FlagAction.Add, Message.Uid, "\\Seen");
                            }

                            imap.Disconnect();
                        }
                    });
                }
            }
        }
        private async void DownloadMessageBodyAsync()
        {
            Loading = true;

            string msgBody = string.Empty;

            await Task.Run(() => {
                ImapClient imap = new ImapClient(notification.SelectedAccount);
                if (imap.Connect())
                {
                    // Not readonly because we need to set the \Seen flag.
                    bool readOnly = false;
                    if (imap.SelectMailbox(notification.SelectedMailbox.DirectoryPath, readOnly))
                    {
                        msgBody = imap.FetchBody(Message.Uid);
                    }

                    imap.Disconnect();

                    if (!Message.IsSeen)
                    {
                        Message.IsSeen = true;

                        // The server should automatically set the \Seen flag when BODY is fetched.
                        // We shouldn't have to send command for this.
                    }
                }
            });

            if (msgBody != string.Empty)
            {
                Message.Body = msgBody;
            }

            // Store the Body and IsSeen flag to the database.
            DatabaseManager.Update(Message);

            Loading = false;
        }
        private void BeginMonitor(Account account, string mailboxName)
        {
            Trace.WriteLine("BeginMonitor " + account.AccountName);
            ImapClient imapClient = new ImapClient(account);
            if (!imapClient.Connect())
            {
                Debug.WriteLine(imapClient.Error);
                return;
            }

            imapClient.NewMessageAtServer += HandleNewMessageAtServer;
            imapClient.MessageDeletedAtServer += HandleMessageDeletedAtServer;
            imapClient.MessageSeenAtServer += HandleMessageSeenAtServer;
            imapClient.MessageUnseenAtServer += HandleMessageUnseenAtServer;
            imapClient.BeginMonitor(mailboxName);
        }
        public void DeleteMessages(List<Message> messages)
        {
            // Delete from memory.
            foreach (Message msg in messages)
            {
                MessagesDico.Remove(msg.UniqueKeyString);
                OnMessageRemoved(msg);
            }

            // Delete from database.
            DatabaseManager.DeleteMessages(messages);

            // Delete from server.
            Task.Run(() => {
                while (messages.Count > 0)
                {
                    Account account = AccountManager.Instance.GetAccountByName(messages[0].AccountName);

                    List<Message> accountMessages = new List<Message>();
                    for (int i = messages.Count - 1; i >= 0; --i)
                    {
                        Message msg = messages[i];
                        if (msg.AccountName == account.AccountName)
                        {
                            accountMessages.Add(msg);
                            messages.RemoveAt(i);
                        }
                    }

                    ImapClient imapClient = new ImapClient(account);
                    if (imapClient.Connect())
                    {
                        imapClient.DeleteMessages(accountMessages);
                        imapClient.Disconnect();
                    }
                }
            });
        }
        private void SyncExistingMessageHeaders(Account account, string mailboxName, ImapClient imapClientOnSelectedStatus, int firstUid, int lastUid)
        {
            Trace.WriteLine("SyncExistingMessageHeaders: Mailbox(" + mailboxName + "), UIDs(" + firstUid + ", " + lastUid + ")");

            // Decrement this at every exit point.
            openSyncOps.AddOrUpdate(account.AccountName, 1, (k, v) => v + 1);

            // Delete all messages that have been deleted from server.
            List<int> serverUids = new List<int>();
            bool searchSuccess = imapClientOnSelectedStatus.SearchUids("ALL", serverUids);
            if (searchSuccess)
            {
                List<string> keysToDelete = new List<string>();
                foreach (KeyValuePair<string, Message> entry in MessagesDico)
                {
                    Message msg = entry.Value;
                    if (msg.AccountName == account.AccountName &&
                        msg.MailboxPath == mailboxName &&
                        !serverUids.Contains(msg.Uid))
                    {
                        keysToDelete.Add(entry.Key);
                    }
                }

                List<Message> msgsDeleted = new List<Message>();
                foreach (string key in keysToDelete)
                {
                    Message msg = MessagesDico[key];
                    MessagesDico.Remove(key);
                    OnMessageRemoved(msg);
                    msgsDeleted.Add(msg);
                }

                DatabaseManager.DeleteMessages(msgsDeleted);
            }

            // Now synchronize the remaining messages.
            int messagesCount = lastUid - firstUid + 1;
            int downloadChunk = this.downloadChunkSize;
            int startUid = lastUid - downloadChunk + 1;
            int endUid = lastUid;

            while (endUid >= firstUid)
            {
                int abort = 0;
                if (abortLatches.TryGetValue(account.AccountName, out abort) && abort == 1)
                {
                    Trace.WriteLine("Aborting sync...");
                    openSyncOps.AddOrUpdate(account.AccountName, 0, (k, v) => v - 1);
                    return;
                }

                if (startUid < firstUid)
                {
                    startUid = firstUid;
                }
                List<Message> serverMsgs = imapClientOnSelectedStatus.FetchHeaders(startUid, endUid - startUid + 1, true);
                if (serverMsgs.Count > 0)
                {
                    List<Message> messagesAdded = new List<Message>();
                    foreach (Message serverMsg in serverMsgs)
                    {
                        Message localMsg;
                        if (MessagesDico.TryGetValue(serverMsg.UniqueKeyString, out localMsg))
                        {
                            // A local copy exists. Update its flags.
                            if (localMsg.FlagString != serverMsg.FlagString)
                            {
                                localMsg.FlagString = serverMsg.FlagString;
                                OnMessageModified(localMsg);
                            }
                        }
                        else
                        {
                            MessagesDico.Add(serverMsg.UniqueKeyString, serverMsg);
                            OnMessageAdded(serverMsg);
                            messagesAdded.Add(serverMsg);
                        }
                    }
                    DatabaseManager.StoreMessages(messagesAdded);
                }

                endUid = startUid - 1;
                startUid = endUid - downloadChunk + 1;
            }

            openSyncOps.AddOrUpdate(account.AccountName, 0, (k, v) => v - 1);
        }
        private void SyncNewMessageHeaders(Account account, string mailboxName, ImapClient imapClientOnSelectedStatus, int firstUid, int lastUid)
        {
            Trace.WriteLine("SyncNewMessageHeaders: Mailbox(" + mailboxName + "), UIDs(" + firstUid + ", " + lastUid + ")");

            // Decrement this at every exit point.
            openSyncOps.AddOrUpdate(account.AccountName, 1, (k, v) => v + 1);

            int messagesCount = lastUid - firstUid + 1;
            int downloadChunk = this.downloadChunkSize;
            int startUid = lastUid - downloadChunk + 1;
            int endUid = lastUid;

            while (endUid >= firstUid)
            {
                int abort = 0;
                if (abortLatches.TryGetValue(account.AccountName, out abort) && abort == 1)
                {
                    Trace.WriteLine("Aborting sync...");
                    openSyncOps.AddOrUpdate(account.AccountName, 0, (k, v) => v - 1);
                    return;
                }

                if (startUid < firstUid)
                {
                    startUid = firstUid;
                }
                List<Message> msgs = imapClientOnSelectedStatus.FetchHeaders(startUid, endUid - startUid + 1, true);
                if (msgs.Count > 0)
                {
                    foreach (Message msg in msgs)
                    {
                        if (!MessagesDico.ContainsKey(msg.UniqueKeyString))
                        {
                            MessagesDico.Add(msg.UniqueKeyString, msg);
                            OnMessageAdded(msg);
                        }
                    }
                    DatabaseManager.StoreMessages(msgs);
                }

                endUid = startUid - 1;
                startUid = endUid - downloadChunk + 1;
            }

            openSyncOps.AddOrUpdate(account.AccountName, 0, (k, v) => v - 1);
        }
        private void SyncMessage(Account account, string mailboxName)
        {
            int abort = 0;
            if (abortLatches.TryGetValue(account.AccountName, out abort) && abort == 1)
            {
                // Abort sync.
                return;
            }

            ImapClient imapClient = new ImapClient(account);
            if (!imapClient.Connect())
            {
                Trace.WriteLine(imapClient.Error);
                return;
            }

            ExamineResult status;
            bool readOnly = true;
            if (!imapClient.SelectMailbox(mailboxName, readOnly, out status))
            {
                Debug.WriteLine("MessageManager.SyncMessage(): Unable to select mailbox " + mailboxName + ".\n" + imapClient.Error);
                imapClient.Disconnect();
                return;
            }

            int localLargestUid = DatabaseManager.GetMaxUid(account.AccountName, mailboxName);

            // Download the recent message headers that have never been downloaded yet.
            int serverLargestUid = status.UidNext - 1;
            if (serverLargestUid > localLargestUid)
            {
                SyncNewMessageHeaders(account, mailboxName, imapClient, localLargestUid + 1, serverLargestUid);
            }

            // Sync changes to the existing message headers (flags, etc.).
            if (localLargestUid > 0)
            {
                SyncExistingMessageHeaders(account, mailboxName, imapClient, 1, localLargestUid);
            }

            imapClient.Disconnect();
        }