// ============================================================================= // // ============================================================================= public static bool ListMails(CacheData.MailRef headers, bool bTo, bool bFrom, bool bSubject, bool bDate, bool bSize, bool bFlags, bool bUID, bool bID) { if(headers.IsNothing) return false; ZIMapApplication.MailInfo[] mails = headers.Array(0); if(mails.Length < 1) { Message("No mails"); return true; } uint ucol = 0; if(bTo) ucol++; if(bFrom) ucol++; if(bSubject) ucol++; if(bDate) ucol++; if(bSize) ucol++; if(bFlags) ucol++; if(bUID) ucol++; if(bID) ucol++; TextTool.TableBuilder tb = GetTableBuilder(ucol); object[] data = new object[ucol]; ucol = 0; if(bID) { data[ucol] = "ID"; tb.Columns[ucol].RigthAlign = true; tb.Columns[ucol++].MaxWidth = 6; } if(bUID) { data[ucol] = "UID"; tb.Columns[ucol].RigthAlign = true; tb.Columns[ucol++].MaxWidth = 6; } if(bFrom) { data[ucol] = "From"; tb.Columns[ucol].RigthAlign = false; tb.Columns[ucol++].MaxWidth = 20; } if(bTo) { data[ucol] = "To"; tb.Columns[ucol].RigthAlign = false; tb.Columns[ucol++].MaxWidth = 20; } if(bDate) { data[ucol] = "Date"; tb.Columns[ucol].RigthAlign = true; tb.Columns[ucol++].MaxWidth = 20; } if(bSize) { data[ucol] = "kByte"; tb.Columns[ucol].RigthAlign = true; tb.Columns[ucol++].MaxWidth = 6; } if(bFlags) { data[ucol] = "Flags"; tb.Columns[ucol].RigthAlign = false; tb.Columns[ucol++].MaxWidth = 32; } if(bSubject) { data[ucol] = "Subject"; tb.Columns[ucol].RigthAlign = false; tb.Columns[ucol++].MinWidth = 32; } tb.Header(data); ZIMapMessage mail = new ZIMapMessage(); for(int irun = 0; irun < mails.Length; irun++) { if(!mail.Parse(mails[irun].Literal, false)) continue; ucol = 0; if(bID) data[ucol++] = mails[irun].Index; if(bUID) data[ucol++] = mails[irun].UID; if(bFrom) data[ucol++] = mail.From; if(bTo) data[ucol++] = mail.To; if(bDate) data[ucol++] = mail.DateISO; if(bSize) data[ucol++] = (mails[irun].Size + 1023) / 1024; if(bFlags) data[ucol++] = string.Join(" ", mails[irun].Flags); if(bSubject) data[ucol++] = mail.Subject; tb.AddRow(data); } tb.Footer(""); tb.PrintTable(); return true; }
// ============================================================================= // 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); }
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 bool HeadersSort(MailRef headers, string field, bool reverse) { if(headers.IsNothing) return false; uint ulen = headers.Count; if(ulen == 0) return true; // no sort, do reverse? if(string.IsNullOrEmpty(field)) { if(reverse) Array.Reverse(headers.Array(0)); return true; } // check the field name ... ZIMapMessage mail = null; switch(field) { case "size": case "flags": case "id": case "uid": break; // no mail parsing case "to": case "from": case "subject": case "date": mail = new ZIMapMessage(); // must parse mail break; default: return false; // bad field } // build sort array ... object[] keys = new object[ulen]; for(uint urun=0; urun < ulen; urun++) { // TODO: should use an iterator or Next() ZIMapApplication.MailInfo info = headers.Array(0)[urun]; if(mail != null) { progress.Update(urun, ulen); mail.Parse(info.Literal, true); } switch(field) { case "size": keys[urun] = info.Size; break; case "flags": keys[urun] = string.Join(" ", info.Flags); break; case "id": keys[urun] = info.Index; break; case "uid": keys[urun] = info.UID; break; case "to": keys[urun] = mail.To; break; case "from": keys[urun] = mail.From; break; case "subject": keys[urun] = mail.Subject; break; case "date": keys[urun] = mail.DateBinary; break; } } // TODO: should use a sort method, this code is wrong! Array.Sort(keys, headers.Array(0)); if(reverse) Array.Reverse(headers.Array(0)); return true; }