Ejemplo n.º 1
0
        // =============================================================================
        // Mailbox Export
        // =============================================================================
        /// <summary>
        /// Export mail from a single mailbox.
        /// </summary>
        /// <param name="mbox">
        /// A reference to the mailbox.
        /// </param>
        /// <param name="quoted">
        /// If <c>true</c> export using "From" quoting instead of "Content-Length" headers.
        /// </param>
        /// <param name="uids">
        /// A list of uids to be exported or <c>null</c>
        /// </param>
        /// <param name="mailTotal">
        /// Can specify a total number of mails when multiple mailboxes are going to be
        /// exported.
        /// </param>
        /// <param name="mailCounter">
        /// Incremented for each exported mail.
        /// </param>
        /// <returns>
        /// <c>true</c> on success.
        /// </returns>
        public bool MailboxExport(MBoxRef mbox, bool quoted, 
                                  uint[] uids, uint mailTotal, ref uint mailCounter)
        {
            if(!mbox.IsValid) return false;

            uint ucnt = (uids == null) ? mbox.Messages : (uint)uids.Length;
            if(ucnt > mailTotal) mailTotal = ucnt;
            string mailbox = mbox.Name;

            // get rid of INBOX and prefix personal mailboxes with the account name
            uint rnsi;
            string fullname = server.FriendlyName(mailbox, out rnsi);
            string prefix = server[rnsi].Prefix;
            if(prefix != "" && fullname.StartsWith(prefix))     // strip the ns prefix
                fullname = fullname.Substring(prefix.Length);

            // create the output file
            if (!application.ExportMailbox(fullname, rnsi)) return false;
            if(ucnt == 0) {
                MonitorInfo("Mailbox exported: {0} [no mails]", fullname.PadRight(32));
                return true;
            }

            // open the IMAP mailbox
            if(data.Current.Name != mailbox)
            {   ZIMapCommand.Examine exa = new ZIMapCommand.Examine(factory);
                exa.Queue(mailbox);
                if(!exa.CheckSuccess(":Cannot open Mailbox: " + mailbox))
                    return false;
            }

            // loop over mail items
            ZIMapCommand.Fetch.Item item = new ZIMapCommand.Fetch.Item();
            byte[] head = null;
            byte[] body = null;
            ZIMapCommand.Generic current = null;
            ZIMapFactory.Bulk bulk = factory.CreateBulk("FETCH", 4, uids != null);
            ZIMapMessage msg = new ZIMapMessage();
            uint ucur = 0;                      // current item/UID
            uint uerr = 0;                      // error counter
            uint urun = 0;                      // mail counter
            uint urdy = 0;
            string key = (uids == null) ? "item" : "UID";
            while(urdy < ucnt)
            {   // step 1: queue request and check for response ...
                bool done = bulk.NextCommand(ref current);
                ZIMapCommand.Fetch cmd = (ZIMapCommand.Fetch)current;

                // step 2: check server reply for error ...
                if(done)
                {   ucur = (uids == null) ? ++urdy : uids[urdy++];
                    if (cmd.Items == null || cmd.Items.Length != 1)
                    {   MonitorError(!cmd.CheckSuccess() ?
                            "Cannot fetch mail ({0}={1}): {2}" :
                            "Mail not existing ({0}={1})", key, ucur, cmd.Result.Message);
                        done = false; uerr++;
                    }
                }

                // step 3: process data sent by server ...
                if(done)
                {   item = cmd.Items[0];
                    head = item.Literal(0);
                    body = item.Literal(1);
                    if (head == null)
                    {   MonitorError("Mail data incomplete ({0}={1})", key, ucur);
                        done = false; uerr++;
                    }
                    if(body == null) body = new byte[0];        // message without body
                }
                if(done)
                {   msg.Parse(head, true);

                    // use the server's INTERNALDATE if we got it...
                    DateTime date;
                    string sdat;
                    if (ZIMapFactory.FindInParts(item.Parts, "INTERNALDATE", out sdat))
                        date = ZIMapConverter.DecodeIMapTime(sdat, true);
                    else
                        date = msg.DateBinary;

                    // finally write mail data to file ...
                    string flags = (item.Flags == null) ? null : string.Join(" ", item.Flags);
                    if (!application.Export.WriteMail(msg.From, date, flags, head, body, quoted))
                    {   MonitorError("Mail could not be written ({0}={1})", key, ucur);
                        uerr++;
                    }
                    progress.Update(mailCounter++, mailTotal);
                }

                // step 4: create a new request
                if(urun < ucnt)
                {   ucur = (uids == null) ? ++urun : uids[urun++];
                    cmd.Reset();
                    cmd.Queue(ucur, "FLAGS INTERNALDATE BODY.PEEK[HEADER] BODY.PEEK[TEXT]");
                }
            }
            bulk.Dispose();
            MonitorInfo("Mailbox exported: {0} [{1,4} mails]", fullname.PadRight(32), urun);
            return (uerr == 0);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Get information about mailboxes and subfolders.
        /// </summary>
        /// <param name="qualifier">
        /// Can be a prefix like "user" or "MyFolder.Something" that gets prepended
        /// to the filter argument.  There is no need to put a hierarchy delimiter
        /// at the end, this function automatically inserts it to separate qualifier
        /// and filter. 
        /// </param>
        /// <param name="filter">
        /// Can be a folder name optionally containing a '*' or a '%' character.
        /// </param>
        /// <param name="subscribed">
        /// A number indicating if the subscription status should by loaded (for
        /// <c>subscribed != 0</c>, if the status should be loaded (<c>1</c>) or
        /// if only subscribed mailboxes should be returned (<c>2</c>). 
        /// </param>
        /// <param name="detailed">
        /// When <c>false</c> only the mailbox name and the subscription status are
        /// returned (which is quite fast). A value of <c>true</c> also gets the
        /// message, seen and recent counts for each mailbox.
        /// </param>
        /// <returns>
        /// On success an array of Mailbox info structures or <c>null</c> on error.
        /// </returns>
        public MailBox[] Mailboxes(string qualifier, string filter, 
                                   uint subscribed, bool detailed)
        {
            if(factory == null) return null;
            ZIMapCommand.List cmdList =
                (ZIMapCommand.List)factory.CreateByName((subscribed == 2) ? "LSUB" : "LIST");
            if(cmdList == null) return null;
            progress.Update(0);

            ZIMapCommand.Lsub cmdLSub = null;
            if(subscribed == 1) cmdLSub = new ZIMapCommand.Lsub(factory);

            // does server specific things ...
            Server.NormalizeQualifierFilter(ref qualifier, ref filter);

            // send the commands ...
            cmdList.Queue(qualifier, filter);
            if(cmdLSub != null) cmdLSub.Queue(qualifier, filter);
            progress.Update(5);

            // wait for the mailbox list ...
            ZIMapCommand.List.Item[] items = cmdList.Items;
            cmdList.Dispose();
            if(items == null)
            {   MonitorError("Mailboxes: got no mailboxes");
                return null;
            }
            progress.Update(15);

            // create mailbox data ...
            MailBox[] mbox = new MailBox[items.Length];
            int irun = 0;
            foreach(ZIMapCommand.List.Item i in items)
            {   mbox[irun].Name = i.Name;
                mbox[irun].Delimiter = i.Delimiter;
                mbox[irun].Attributes = i.Attributes;
                mbox[irun].Subscribed = (subscribed == 2);
                if(detailed)
                {   ZIMapCommand.Examine cmd = new ZIMapCommand.Examine(factory);
                    cmd.UserData = irun;
                    cmd.Queue(i.Name);
                }
                irun++;
            }

            // get subscription info ...
            if(cmdLSub != null)
            {   items = cmdLSub.Items;
                progress.Update(20);
                if(!cmdLSub.CheckSuccess())
                    MonitorError("Mailboxes: got no subscription info");
                else
                {   for(uint usub=0; usub < mbox.Length; usub++)
                        mbox[usub].HasSubscription = true;
                    if(items != null)
                    {   int icur = 0;
                        foreach(ZIMapCommand.List.Item i in items)
                        {   for(int imax=irun; imax > 0; imax--)
                            {   if(icur >= irun) icur = 0;
                                if(i.Name  == mbox[icur].Name)
                                {   mbox[icur++].Subscribed = true;
                                    break;
                                }
                                icur++;
                            }
                        }
                    }
                }
                cmdLSub.Dispose();
            }

            // fetch details ...
            if(!detailed)
            {   progress.Done();
                return mbox;
            }
            items = null;
            MonitorInfo("Mailboxes: Fetching " + irun + " details");
            progress.Update(25);
            // TODO: ZIMapApplication - The Mailboxes() code needs rewrite using bulk
            factory.ExecuteCommands(true);
            ZIMapCommand[] cmds = factory.CompletedCommands;
            progress.Push(30, 100);

            foreach(ZIMapCommand c in cmds)
            {   ZIMapCommand.Examine cmd = c as ZIMapCommand.Examine;
                if(cmd == null) continue;
                irun = (int)(cmd.UserData);
                mbox[irun].HasDetails = cmd.CheckSuccess();
                mbox[irun].Messages   = cmd.Messages;
                mbox[irun].Recent     = cmd.Recent;
                mbox[irun].Unseen     = cmd.Unseen;
                mbox[irun].Flags      = cmd.Flags;
                progress.Update((uint)irun, (uint)mbox.Length);
            }

            progress.Pop();
            factory.DisposeCommands(null, false);
            progress.Done();
            return mbox;
        }