Example #1
0
        public async Task Start(StatusCb status, DataCb data, ProgressCb progress, bool compression=false)
        {
            try
            {
                status("Connecting...");
                if (await connect.Connect() != ConnectStatus.Ok)
                    throw new ConnectionFailedException();
                ImapCmd cmd = null;
                if (await connect.ConnectTls() == ConnectStatus.Failed)
                {
                    cmd = CreateImap(connect.stream);
                    if (await cmd.Run(new StarttlsCommand()) != ReturnCode.Ok)
                        throw new SslFailedException();
                }
                cmd = CreateImap(connect.stream);

                // initial Capability
                await cmd.Run(new NullCommand());

                // login to the server
                if (await cmd.Run(new LoginCommand(user, pswd)) != ReturnCode.Ok)
                    throw new FailedLoginException();
                status("Logged in to the email server");
                // check if compression is supported
                if (compression && await cmd.Run(new CapabilityCommand(new String[] { "compress=deflate" })) == ReturnCode.Ok &&
                    await cmd.Run(new DeflateCommand()) == ReturnCode.Ok)
                {
                    StreamReader reader = new StreamReader(new DeflateStream(connect.stream, CompressionMode.Decompress, true));
                    cmd = new ImapCmd(token, reader, connect.stream, true);
                    status("Compression enabled");
                }
          
                // get the list of mailboxes
                status("Fetching mailbox list...");
                mailboxes = await GetMailboxesList(cmd,status,progress);
                status("Downloading ...");
                progress(0);
                int processed = 0;
                Regex rx_msgid = new Regex("^message-id: ([^ \r\n]+)", RegexOptions.IgnoreCase | RegexOptions.Multiline);
                Func<String, String> getMsgId = (String message) =>
                {
                    int len = message.Length > 5000 ? 5000 : message.Length;
                    Match m = rx_msgid.Match(message, 0, len);
                    return (m.Success ? m.Groups[1].Value : "");
                };
                foreach (Mailbox mailbox in mailboxes)
                {
                    if (token.IsCancellationRequested)
                        return;
                    status("{0} - {1} messages: ", mailbox.name, mailbox.cnt);
                    if (mailbox.start < mailbox.cnt)
                    {
                        if (await cmd.Run(new SelectCommand(mailbox.name)) != ReturnCode.Ok)
                            throw new FailedException();

                        if (!GmailSpecial(mailbox.name))
                        {
                            if (await cmd.Run(new FetchCommand(FetchCommand.Fetch.Body,
                                async delegate (String message, String msgn)
                                {
                                    mailbox.start = int.Parse(msgn);
                                    String msgid = "";
                                    if (host == "imap.gmail.com")
                                    {
                                        msgid = getMsgId(message);
                                        messageid[msgid] = "";
                                    }
                                    progress((100.0 * (processed + int.Parse(msgn))) / messagesInAccount);
                                    await data(mailbox.name, message, msgid, msgn);
                                }, mailbox.start)) != ReturnCode.Ok)
                            {
                                status(token.IsCancellationRequested ? "Download cancelled" : "No messages downloaded");
                            }
                        }
                        else
                        {
                            List<String> unique = new List<string>();
                            progress(0);
                            if (await cmd.Run(new FetchCommand(FetchCommand.Fetch.MessageID,
                                async delegate (String message, String msgn)
                                {
                                    mailbox.start = int.Parse(msgn);
                                    String msgid = getMsgId(message);
                                    if (msgid != "" && messageid.ContainsKey(msgid))
                                        return;
                                    else
                                    {
                                        messageid[msgid] = "";
                                        unique.Add(msgn);
                                    }
                                    progress(100.0 * int.Parse(msgn) / mailbox.cnt);
                                    await Task.Yield();
                                })) != ReturnCode.Ok)
                            {
                                progress(0);
                                status(token.IsCancellationRequested ? "Download cancelled" : "No messages downloaded, failed to get the list of unique messages");
                            }
                            else
                            {
                                progress(0);
                                status("Downloading {0} out of {1}", unique.Count, mailbox.cnt);
                                status("{0} - {1} messages: ", mailbox.name, unique.Count);
                                int downloaded = 0;
                                foreach (String n in unique)
                                {
                                    int num = int.Parse(n);
                                    if (await cmd.Run(new FetchCommand(FetchCommand.Fetch.Body,
                                        async delegate (String message, String msgn)
                                        {
                                            progress((100.0 * (processed + int.Parse(msgn))) / messagesInAccount);
                                            await data(mailbox.name, message, getMsgId(message), msgn);
                                            downloaded++;
                                        }, num, num)) != ReturnCode.Ok)
                                    {
                                        status("failed to download {0}", n);
                                        continue;
                                    }
                                }
                                if (token.IsCancellationRequested)
                                    status("Download cancelled");
                                if (unique.Count != downloaded)
                                    status("{0} out of {1} failed to download", unique.Count-downloaded, unique.Count);
                            }
                        }
                    }
                    processed += mailbox.cnt;
                    mailbox.start = mailbox.cnt;
                }
                status("Download complete");
            }
            finally
            {
                connect.Close();
            }
        }
Example #2
0
        async Task<List<Mailbox>> GetMailboxesList(ImapCmd cmd, StatusCb status, ProgressCb progress)
        {
            List<Mailbox> mailboxes = new List<Mailbox>();
            if (await cmd.Run(new ListCommand(async delegate (String mailbox, String ctx)
            { await Task.Yield(); mailboxes.Add(new Mailbox(mailbox)); })) != ReturnCode.Ok)
                throw new FailedException();
            mailboxes.Sort((Mailbox m1, Mailbox m2) => {
                bool g1 = GmailSpecial(m1.name);
                bool g2 = GmailSpecial(m2.name);
                if (g1 && g2)
                    return String.Compare(m2.name, m1.name); // reverse
                else if (g1)
                    return 1;
                else if (g2)
                    return -1;
                else
                    return String.Compare(m1.name, m2.name);
            });
            for (int i = 0; i < mailboxes.Count; i++)
            {
                await cmd.Run(new StatusCommand(mailboxes[i].name, async delegate (String cnt, String ctx)
                {
                    await Task.Yield();
                    status("{0} - {1}", mailboxes[i].name, cnt);
                    mailboxes[i].cnt = int.Parse(cnt);
                    messagesInAccount += int.Parse(cnt);
                }));
            }
            status("Total messages: {0}", messagesInAccount);
            Dictionary<String, int> downloaded = await CheckResume(status, progress);

            foreach (String mbox in downloaded.Keys)
            {
                mailboxes.ForEach((Mailbox m) => {
                    if (m.name == mbox)
                        m.start = downloaded[mbox] > 0 ? downloaded[mbox] : 1;
                });
            }

            return mailboxes;
        }