/// <summary> /// Open a mailbox and make it current or enable write mode. /// </summary> /// <param name="mbox"> /// Reference to the mailbox the is to be opened. /// </param> /// <param name="readOnly"> /// A value of <c>false</c> (re-)opens the mailbox in write mode. /// </param> /// <returns> /// On success <c>true</c> is returned. /// </returns> /// <remarks> /// The mailbox reference must be valid for this function to succeed. See /// <see cref="OpenMailbox(bool)"/> for a simple way to reopen the current /// mailbox. /// </remarks> public bool MailboxOpen(MBoxRef mbox, bool readOnly) { if(!mbox.IsValid) return false; // we want to use the current mailbox ... if(mbox.Name == application.MailboxName) { if(!readOnly && application.MailboxIsReadonly) { if(!ZIMapAdmin.Confirm("Current mailbox '{0}' is readonly. Change mode", mbox.Name)) return false; MonitorInfo("Setting write mode for current mailbox"); } } else data.Clear(Info.Headers); // (re-)open the mailbox data.UpdateCurrent(MBoxRef.Nothing); if(!mbox.Open(application, readOnly)) return false; data.UpdateCurrent(mbox); return true; }
/// <summary> /// Delete a mailbox from the server and update the cached information. /// </summary> /// <param name="mbox"> /// A <see cref="MBoxRef"/> /// </param> /// <returns> /// A <see cref="System.Boolean"/> /// </returns> public bool MailboxDelete(MBoxRef mbox) { if(!mbox.IsValid) return false; using(ZIMapCommand.Delete cmd = new ZIMapCommand.Delete(factory)) { if(cmd == null) return false; if(mbox.Name == data.Current.Name) MailboxClose(); // TODO: MailboxDelete must update QuotaRoot MailboxAdminRigths(mbox.Name, mbox.ExtraRights, "all", false); cmd.Queue(mbox.Name); if(!cmd.CheckSuccess(string.Format( ":Failed to delete '{0}': {1}", mbox.Name, cmd.Result.Message))) return false; MonitorInfo("Mailbox deleted: {0}", mbox.Name); data.FolderDelete(mbox); } 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 bool CommandCopy(uint[] items, bool useUID, MBoxRef mbox) { if(!mbox.IsValid || items == null || items.Length < 1) return false; progress.Update(0); // make sure that our current mailbox is open ... if(!data.Current.Open(application, true)) return false; // could not reopen string dest = mbox.Name; if(dest == data.Current.Name) // content changes data.Clear(Info.Headers); data.Clear(Info.Details); // message count changes using(ZIMapCommand.Copy cmd = new ZIMapCommand.Copy(factory)) { if(cmd == null) return false; cmd.UidCommand = useUID; cmd.Queue(items, dest); progress.Update(30); bool bok = cmd.CheckSuccess(":"); progress.Done(); return bok; } }
public bool FoldersExtras(bool wantRights, bool wantQuota) { data.UpdateExtras(wantRights, wantQuota); if(!application.EnableRights) wantRights = false; if(!application.EnableQuota) wantQuota = false; if(!wantRights && !wantQuota) return true; MBoxRef boxes = data.Folders; uint ucnt = boxes.Count; if(ucnt == 0) return true; // progress report setup ... uint upro = ucnt; if(wantRights && wantQuota) upro += ucnt; progress.Update(0); MBoxRef mout = new MBoxRef(boxes.Array); // get rights ... uint ures = 0; boxes.Reset(); if(wantRights) using(ZIMapFactory.Bulk rights = factory.CreateBulk("MyRights", 3, false)) { ZIMapCommand.Generic current = null; while(ures < ucnt) { if(rights.NextCommand(ref current)) { mout.Next((uint)current.UserData); mout.ExtraRights = ((ZIMapCommand.MyRights)current).Rights; current.Reset(); ures++; progress.Update(ures, upro); } if(boxes.Next()) { if(boxes.ExtraRights != null) ures++; else { ((ZIMapCommand.MyRights)current).Queue(boxes.Name); current.UserData = boxes.Index; } } } } // get quota info ... ures = 0; boxes.Reset(); if(wantQuota) using(ZIMapFactory.Bulk rights = factory.CreateBulk("GetQuotaRoot", 3, false)) { ZIMapCommand.Generic current = null; while(ures < ucnt) { if(rights.NextCommand(ref current)) { ZIMapApplication.QuotaInfo info; application.QuotaInfos((ZIMapCommand.GetQuotaRoot)current, out info); mout.Next((uint)current.UserData); mout.ExtraSetQuota(info); // also save on failure current.Reset(); ures++; progress.Update(ures, upro); } if(boxes.Next()) { if(boxes.ExtraQuotaRoot != null) ures++; else { ((ZIMapCommand.GetQuotaRoot)current).Queue(boxes.Name); current.UserData = boxes.Index; } } } } return true; }
public new void UpdateCurrent(MBoxRef current) { base.UpdateCurrent(current); }
// ============================================================================= // Commands: Flags, Copy, Expunge // ============================================================================= public bool CommandACL(MBoxRef mailbox, bool bRecurse, string user, string rights) { if(!mailbox.IsValid) return false; progress.Update(0); using(ZIMapCommand acl = (ZIMapCommand)application.Factory.CreateByName( (rights == null) ? "DeleteACL" : "SetACL")) { CacheData.MBoxRef ubox = mailbox; if(string.IsNullOrEmpty(user)) user = application.User; uint ucnt = 0; if(bRecurse) // get count for progress report { ubox = CacheData.MBoxRef.Nothing; while(mailbox.Recurse(ref ubox, application.Server)) ucnt++; } uint urun = 0; while(bRecurse ? mailbox.Recurse(ref ubox, application.Server) : (urun == 0)) { string name = ubox.Name; if(rights == null) ((ZIMapCommand.DeleteACL)acl).Queue(name, user); else ((ZIMapCommand.SetACL)acl).Queue(name, user, rights); ubox.ExtraRights = null; if(ucnt > 0) progress.Update(urun, ucnt); else progress.Update(30); if(!acl.CheckSuccess(":Cannot change rights for: " + user)) return false; acl.Reset(); urun++; } } return true; }
protected void UpdateFolders(MBoxRef boxes, bool details) { this.boxes = boxes; SetInfo(Info.Details, details); info |= Info.Folders; boxesTime = Second(); }
protected void UpdateUsers(MBoxRef users, bool others) { this.users = users; SetInfo(Info.Others, others); SetInfo(Info.Shared, !others); usersTime = Second(); }
protected void UpdateCurrent(MBoxRef current) { this.current = current; }
/// <summary>Remove one entry from the array of cached folders.</summary> public bool FolderDelete(MBoxRef mbox) { if(boxes.IsNothing) return false; return boxes.Delete(mbox); }
/// <summary> /// Clear cached data. /// </summary> /// <remarks> /// The method does not clear or close the current mailbox. /// </remarks> public bool Clear(Info what) { //if((what & (Info.Quota | Info.Rights)) != 0) // what |= (Info.Details | Info.Quota | Info.Rights); if((what & Info.Details) != 0) info &= ~Info.Details; if((what & Info.Quota) != 0) info &= ~Info.Quota; if((what & Info.Rights) != 0) info &= ~Info.Rights; if((what & Info.Folders) != 0) { boxes = MBoxRef.Nothing; boxesTime = 0; info &= ~(Info.Folders | Info.Details | Info.Quota | Info.Rights); } if((what & (Info.Others | Info.Shared)) != 0) { users = MBoxRef.Nothing; usersTime = 0; info &= ~(Info.Others | Info.Shared); } if((what & Info.Headers) != 0) { headers = MailRef.Nothing; headersTime = 0; info &= ~(Info.Headers); } return false; }
/// <summary>Iterator to enumerate a mailbox and it's descendents.</summary> /// <param name="position"> /// Set on return, must initially be <see cref="MBoxRef.Nothing"/>. /// </param> /// <param name="server"> /// Used for namespace support <see cref="ZIMapServer.FriendlyName"/>. /// </param> /// <returns>On success <c>true</c> is returned.</returns> /// <remarks> /// The returned <paramref name="position"/> should be used to access the /// data.<para/> /// <example><code lang="C#"> /// uint udel = 0; /// CacheData.MBoxRef root = ...; /// CacheData.MBoxRef position = CacheData.MBoxRef.Nothing; /// while(umbx.Recurse(ref positioin, Server)) /// { if(position.Messages > 0) udel++ /// } /// </code></example> /// </remarks> public bool Recurse(ref MBoxRef position, ZIMapServer server) { if(!IsValid) return false; if(!position.IsValid) // start the iteration { position = this; return true; } // get the friendly root name and append a hierarchie delimiter uint rnsi; string root = boxes[index].Name; root = server.FriendlyName(root, out rnsi); root += server[rnsi].Delimiter; // now scan the list of mailboxes ... while(position.Next()) { if(position.index == index) continue; // Reset() called? uint cnsi; string name = server.FriendlyName(position.Name, out cnsi); if(rnsi == cnsi && name.StartsWith(root)) return true; } position = MBoxRef.Nothing; return false; }
/// <summary>Remove one entry from the array.</summary> public bool Delete(MBoxRef mbox) { if(boxes == null || !mbox.IsValid) return false; uint index = mbox.Index; if(!object.ReferenceEquals(boxes, mbox.boxes)) index = Search(mbox.Name); if(length == 0 || index >= length) return false; ZIMapApplication.MailBox[] dest = new ZIMapApplication.MailBox[--length]; if(index > 0) System.Array.Copy(boxes, dest, index); int tail = (int)(length - index); if(tail > 0) System.Array.Copy(boxes, index+1, dest, index, tail); boxes = dest; return true; }