/// <summary>
        /// Fetch Mail Header for a list of UIDs (or IDs).
        /// </summary>
        /// <param name="ids">
        /// Depending on <see cref="EnableUidCommands"/> this is an array of UIDs 
        /// (<c>true</c>) or IDs (<c>false</c>).
        /// </param>
        /// <param name="what">
        /// A list of IMap items to be returned. If empty or null the default is:
        /// "<c>(UID FLAGS RFC822.SIZE BODY.PEEK[HEADER])</c>".
        /// </param>
        /// <returns>
        /// An array of mail headers (may be zero-sized) or <c>null</c> on error.
        /// </returns>
        /// <remarks>
        /// This method is used by <see cref="MailSearch(string, string, string[])"/>.
        /// It is recommended to set <see cref="EnableUidCommands"/> to <c>true</c>. 
        /// </remarks>
        public MailInfo[] MailHeaders(uint[] ids, string what)
        {
            if(factory == null || ids == null) return null;
            if(ids.Length <= 0) return new MailInfo[0];
            if(string.IsNullOrEmpty(what)) what = "UID FLAGS RFC822.SIZE BODY.PEEK[HEADER]";

            ZIMapCommand.Fetch fetch = new ZIMapCommand.Fetch(factory);
            if(fetch == null) return null;
            progress.Update(0);
            fetch.UidCommand = enableUid;

            uint count = (uint)ids.Length;
            uint block = fetchBlock;
            ZIMapCommand.Fetch.Item[] part = null;
            MailInfo[] rval = null;

            if(count <= block)
            {   fetch.Queue(ids, what);
                progress.Update(20);
                part = fetch.Items;
                if(part == null)
                {   MonitorError("MailHeaders: FETCH failed: " + fetch.Result.Message);
                    factory.DisposeCommands(null, false);
                    return null;
                }
                rval = new MailInfo[part.Length];
                for(uint irun=0; irun < part.Length; irun++)
                    rval[irun] = new MailInfo(part[irun]);
            }
            else
            {   List<MailInfo> items = new List<MailInfo>();
                uint last = 0;
                uint offs = 0;
                uint[] sub = null;
                while(count > 0)
                {   uint chunk = Math.Min(count, block);
                    if(chunk != last)
                    {   sub = new uint[chunk];
                        last = chunk;
                    }
                    Array.Copy(ids, offs, sub, 0, chunk);
                    progress.Update(offs, (uint)ids.Length);
                    fetch.Queue(sub, what);

                    part = fetch.Items;
                    if(part == null)
                    {   MonitorError("MailHeaders: FETCH failed: " + fetch.Result.Message);
                        factory.DisposeCommands(null, false);
                        return null;
                    }

                    foreach(ZIMapCommand.Fetch.Item item in part)
                        items.Add(new MailInfo(item));
                    fetch.Reset();
                    count -= chunk; offs += chunk;
                }
                rval = items.ToArray();
            }

            factory.DisposeCommands(null, false);
            if(rval == null) rval = new MailInfo[0];
            MonitorInfo("MailHeaders: Got " + rval.Length + " mails");
            progress.Done();
            return rval;
        }
Example #2
0
        public static bool ShowInfo(object what)
        {
            if(what == null) return false;

            // -----------------------------------------------------------------
            // Server
            // -----------------------------------------------------------------
            if(what is string)
            {
                ListOutput(0, "          ", "Server Information for: " + App.ServerName);
                ListOutput(1, "Security  ", App.Connection.TlsMode.ToString());
                ListOutput(1, "Timeout   ", App.Connection.TransportTimeout.ToString() + " [s]");

                ListOutput(2, "Greeting  ", App.Connection.ProtocolLayer.ServerGreeting);
                ListOutput(1, "Type      ", App.Server.ServerType + " (Subtype: " +
                                            App.Server.ServerSubtype + ")");
                ListOutput(1, "Admin     ", App.Server.IsAdmin ? "yes" : "no");

                ListOutput(2, "Capability", string.Join(" ", App.Factory.Capabilities));
                ListOutput(1, "Rights    ", App.EnableRights ? "enabled" : "disabled");
                string sout = "disabled";
                if(App.EnableQuota)
                    sout = string.Format("enabled (STORAGE={0} MESSAGE={1})",
                                         App.Server.HasLimit("STORAGE") ? "yes" : "no",
                                         App.Server.HasLimit("MESSAGE") ? "yes" : "no");
                ListOutput(1, "Quota     ", sout);

                ListOutput(5, "Namespace ", "Personal=" + App.Server.NamespaceDataPersonal + "\n" +
                                            "Others  =" + App.Server.NamespaceDataOther + "\n" +
                                            "Shared  =" + App.Server.NamespaceDataShared + "\n" +
                                            "Search  =" + App.Server.NamespaceDataSearch);
                return true;
            }

            // -----------------------------------------------------------------
            // Application
            // -----------------------------------------------------------------
            if(what == App)
            {
                ListOutput(0, "          ", "Application Information");
                ListOutput(1, "Runtime   ",
                           System.Environment.Version.ToString() + " (" +
                           System.Environment.OSVersion.ToString() + ")" );
                ListOutput(1, "Version   ",
                           System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()
            #if DEBUG
                           + " (DEBUG build)"
            #endif
                           );

                App.Export.Open(null, (char)0, false, false);
                string bfld = ZIMapExport.BaseFolder;
                ListOutput(2, "Path      ", (bfld == "") ? "[not set]" : bfld);

                long mem1 = GC.GetTotalMemory(false) / 1024; Cache.Data.Clear(CacheData.Info.All);
                long mem2 = GC.GetTotalMemory(true)  / 1024;
                ListOutput(5, "Memory    ", string.Format("{0} kByte (minimum is {1} kByte)",
                                                          mem1, mem2));
                return true;

            }

            // -----------------------------------------------------------------
            // Mailbox
            // -----------------------------------------------------------------
            if(what is ZIMapApplication.MailBox)
            {
                ZIMapApplication.MailBox mbox = (ZIMapApplication.MailBox)what;
                ListOutput(0, "          ", "Mailbox Information");
                string msg = mbox.Name;
                if(mbox.Name ==  App.MailboxName)
                    msg = string.Format("{0} (current {1})", msg,
                          App.MailboxIsReadonly ? "Read-Only" : "Writable");
                else
                    msg += " (not current)";
                ListOutput(1, "Mailbox   ", msg);
                ListOutput(1, "Messages  ",
                              string.Format("{0} mails ({1} recent {2} unseen)",
                              mbox.Messages, mbox.Recent, mbox.Unseen));
                ListOutput(1, "Subscribed", mbox.Subscribed ? "yes" : "no");
                ListOutput(2, "Flags     ", string.Join(" ", mbox.Flags));
                ListOutput(1, "Attributes", string.Join(" ", mbox.Attributes));
                string qroot, storage, message;
                FormatQuota(mbox.Name, out storage, out message, out qroot);
                if(qroot == null)
                    ListOutput(5, "Quota     ",      "-none-");
                else
                {   if(message != null) message = "\n" + message;
                    if(storage != null) storage = "\n" + storage;
                    ListOutput(5, "Quota     ",      "Quota Root : " +
                                   qroot + message + storage);
                }
                return true;
            }

            // -----------------------------------------------------------------
            // Mail Item
            // -----------------------------------------------------------------
            if(what is uint[])
            {   uint[] uarg = (uint[])what;
                ZIMapApplication.MailInfo[] mails = Cache.Data.Headers.Array(0);

                uint uuid = uarg[0];
                uint urun;
                for(urun=0; urun < mails.Length; urun++)
                    if(mails[urun].UID == uuid) break;
                if(urun >= mails.Length)
                {   Error("UID not found: " + uuid);
                    return false;
                }
                ZIMapApplication.MailInfo mail = mails[urun];
                ZIMapMessage mesg = new ZIMapMessage();
                if(!mesg.Parse(mail.Literal, false)) return false;

                ZIMapMessage.BodyInfo info = null;
                ZIMapCommand.Fetch cmd = new ZIMapCommand.Fetch(App.Factory);
                cmd.UidCommand = App.EnableUidCommands;
                if((uarg[1] & 2) != 0)
                    cmd.Queue(uuid, "BODY BODY.PEEK[TEXT]");
                else
                    cmd.Queue(uuid, "BODY");
                if(!cmd.CheckSuccess("Failed to get status")) return false;
                if((uarg[1] & 2) != 0)
                {   if(cmd.Result.Literals == null || cmd.Result.Literals.Length < 1)
                    {  Info("Message has no body");
                       return true;
                    }
                    mesg.ParseBody(cmd.Result.Literals[0], 0);
                }
                string[] parts = cmd.Items[0].Parts;
                if(parts != null && parts.Length > 1 && parts[0] == "BODY")
                    info = ZIMapMessage.ParseBodyInfo(parts[1]);

                uint utxt = ListOutput(0, "          ", "Mail Information");

                ListOutput(1, "Item      ", string.Format("{0} (ID={1}  UID={2})",
                                            urun+1, mail.Index, mail.UID));
                ListOutput(1, "From      ", mesg.From);
                ListOutput(1, "To        ", mesg.To);
                ListOutput(1, "Subject   ", mesg.Subject);
                ListOutput(1, "Date      ", mesg.DateISO);
                ListOutput(1, "Size      ", mail.Size.ToString());

                ListOutput(2, "Flags     ", string.Join(" ", mail.Flags));

                if(info != null && info.Parts != null)
                    for(int irun=0; irun < info.Parts.Length; irun++)
                    {   string text = info.Parts[irun].ToString();
                        int icol = text.IndexOf(':');
                        if(icol > 0) text = text.Substring(icol+2);
                        ListOutput((uint)((irun == 0) ? 2 : 1),
                                   ("Part [" + info.Parts[irun].Level + "]").PadRight(10), text);
                     }

                if((uarg[1] & 1) != 0)
                {
                    List<string> llis = new List<string>();
                    //string[] names = item.FieldNames;
                    for(int irun=0; irun < mesg.HeaderCount; irun++)
                    {   string[] lines = TextTool.TextIndent(mesg.FieldKey(irun).PadRight(15) + "  " +
                                                  mesg.FieldText(irun), 17, utxt);
                        llis.AddRange(lines);
                    }
                    if(llis.Count == 0)
                        ListOutput(5, "Headers   ", "-none-");
                    if(llis.Count == 1)
                        ListOutput(5, "Headers   ", llis[0]);
                    else for(int irun=0; irun < llis.Count; irun++)
                    {   if(irun == 0)
                            ListOutput(2, "Headers   ", llis[0]);
                        else
                            ListOutput(1, "          ", llis[irun]);
                    }
                }

                if(mesg.BodyCount > 0)
                {   StringBuilder sb = new StringBuilder();
                    for(int irun=0; irun < mesg.BodyCount; irun++)
                        sb.AppendLine(mesg.BodyLine(irun, null));
                    ListOutput(2, "Body Text ", sb.ToString());
                }
                TextTool.Formatter.WriteLine(
                    TextTool.DecoLine(TextTool.Decoration.Double, 0, utxt+12));
                return true;
            }

            return false;
        }
        public MailInfo[] MailHeaders(uint firstIndex, uint lastIndex, string what)
        {
            if(what == null || what == "") what = "UID FLAGS RFC822.SIZE BODY.PEEK[HEADER]";
            if(lastIndex < firstIndex) return null;
            if(factory == null) return null;

            ZIMapCommand.Fetch fetch = new ZIMapCommand.Fetch(factory);
            if(fetch == null) return null;
            progress.Update(0);

            uint count = lastIndex - firstIndex;
            uint block = fetchBlock;
            uint progrcnt = 0;
            uint progrmax = count;
            List<MailInfo> items = null;
            ZIMapCommand.Fetch.Item[] part = null;

            while(count > 0)
            {   uint chunk = count; // Math.Min(count, block); // bug on mono?
                if(chunk > block) chunk = block;
                fetch.Reset();
                fetch.Queue(firstIndex, firstIndex+chunk-1, what);

                // semi logarithmic progress ...
                if(lastIndex == uint.MaxValue)
                {   if(progrcnt < 32*16)
                        progrcnt += 64;
                    else if(progrcnt < 64*16)
                        progrcnt += 16;
                    else if(progrcnt < 99)
                        progrcnt += 1;
                    progress.Update(progrcnt / 16);
                }
                // exact progress ...
                else
                {   progrcnt += block;
                    progress.Update(progrcnt, progrmax);
                }

                part = fetch.Items;
                if(part == null)
                {   if(fetch.CheckSuccess())
                        break;                      // server said: OK no more data
                    if(fetch.Result.State == ZIMapProtocol.ReceiveState.Error && items != null)
                        break;                      // server said: BAD no more data
                    if(fetch.Result.State == ZIMapProtocol.ReceiveState.Failure)
                        break;                      // server said: No no matching data
                    MonitorError("MailHeaders: FETCH failed: " + fetch.Result.Message);
                    factory.DisposeCommands(null, false);
                    return null;
                }

                // only one chunk, directly return the array
                if(count == chunk && items == null) break;

                // multiple chunks, store items in a list
                if(items == null)
                    items = new List<MailInfo>();
                foreach(ZIMapCommand.Fetch.Item item in part)
                    items.Add(new MailInfo(item));
                count -= chunk;
                firstIndex += chunk;
            }

            factory.DisposeCommands(null, false);
            MailInfo[] rval = null;
            if     (items != null) rval = items.ToArray();
            else if(part == null)  rval = new MailInfo[0];
            progress.Done();
            MonitorInfo("MailHeaders: Got " + rval.Length + " mails");
            return rval;
        }