/// <summary> /// Format the IMAP NOTIFY command for this particular IMAP mailbox filter. /// </summary> /// <remarks> /// Formats the IMAP NOTIFY command for this particular IMAP mailbox filter. /// </remarks> /// <param name="engine">The IMAP engine.</param> /// <param name="command">The IMAP command builder.</param> /// <param name="args">The IMAP command argument builder.</param> /// <param name="isSelectedFilter"><c>true</c> if the event is being registered for a /// <see cref="ImapMailboxFilter.Selected"/> or <see cref="ImapMailboxFilter.SelectedDelayed"/> /// mailbox filter.</param> internal override void Format(ImapEngine engine, StringBuilder command, IList <object> args, bool isSelectedFilter) { command.Append(Name); if (ImapFolder.IsEmptyFetchRequest(request)) { return; } if (!isSelectedFilter) { throw new InvalidOperationException("The MessageNew event cannot have any parameters for mailbox filters other than SELECTED and SELECTED-DELAYED."); } command.Append(" "); command.Append(ImapFolder.FormatSummaryItems(engine, request, out _, isNotify: true)); }
/// <summary> /// Format the IMAP NOTIFY command for this particular IMAP mailbox filter. /// </summary> /// <remarks> /// Formats the IMAP NOTIFY command for this particular IMAP mailbox filter. /// </remarks> /// <param name="engine">The IMAP engine.</param> /// <param name="command">The IMAP command builder.</param> /// <param name="args">The IMAP command argument builder.</param> /// <param name="isSelectedFilter"><c>true</c> if the event is being registered for a /// <see cref="ImapMailboxFilter.Selected"/> or <see cref="ImapMailboxFilter.SelectedDelayed"/> /// mailbox filter.</param> internal override void Format(ImapEngine engine, StringBuilder command, IList <object> args, bool isSelectedFilter) { command.Append(Name); if (items == MessageSummaryItems.None && headers.Count == 0) { return; } if (!isSelectedFilter) { throw new InvalidOperationException("The MessageNew event cannot have any parameters for mailbox filters other than SELECTED and SELECTED-DELAYED."); } var xitems = items; bool previewText; command.Append(" "); command.Append(ImapFolder.FormatSummaryItems(engine, ref xitems, headers, out previewText, isNotify: true)); }
/// <summary> /// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapCommand"/> class. /// </summary> /// <remarks> /// Creates a new <see cref="MailKit.Net.Imap.ImapCommand"/>. /// </remarks> /// <param name="engine">The IMAP engine that will be sending the command.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="folder">The IMAP folder that the command operates on.</param> /// <param name="options">The formatting options.</param> /// <param name="format">The command format.</param> /// <param name="args">The command arguments.</param> public ImapCommand(ImapEngine engine, CancellationToken cancellationToken, ImapFolder folder, FormatOptions options, string format, params object[] args) { UntaggedHandlers = new Dictionary <string, ImapUntaggedHandler> (); RespCodes = new List <ImapResponseCode> (); CancellationToken = cancellationToken; Status = ImapCommandStatus.Created; Result = ImapCommandResult.None; Engine = engine; Folder = folder; using (var builder = new MemoryStream()) { var plus = (Engine.Capabilities & ImapCapabilities.LiteralPlus) != 0 ? "+" : string.Empty; int argc = 0; byte[] buf; string str; char c; for (int i = 0; i < format.Length; i++) { if (format[i] == '%') { switch (format[++i]) { case '%': // a literal % builder.WriteByte((byte)'%'); break; case 'c': // a character c = (char)args[argc++]; builder.WriteByte((byte)c); break; case 'd': // an integer str = ((int)args[argc++]).ToString(); buf = Encoding.ASCII.GetBytes(str); builder.Write(buf, 0, buf.Length); break; case 'u': // an unsigned integer str = ((uint)args[argc++]).ToString(); buf = Encoding.ASCII.GetBytes(str); builder.Write(buf, 0, buf.Length); break; case 'F': // an ImapFolder var utf7 = ((ImapFolder)args[argc++]).EncodedName; AppendString(options, true, builder, utf7); break; case 'L': var literal = new ImapLiteral(options, args[argc++]); var length = literal.Length; if (options.International) { str = "UTF8 (~{" + length + plus + "}\r\n"; } else { str = "{" + length + plus + "}\r\n"; } buf = Encoding.ASCII.GetBytes(str); builder.Write(buf, 0, buf.Length); parts.Add(new ImapCommandPart(builder.ToArray(), literal)); builder.SetLength(0); if (options.International) { builder.WriteByte((byte)')'); } break; case 'S': // a string which may need to be quoted or made into a literal AppendString(options, true, builder, (string)args[argc++]); break; case 'Q': // similar to %S but string must be quoted at a minimum AppendString(options, false, builder, (string)args[argc++]); break; case 's': // a safe atom string buf = Encoding.ASCII.GetBytes((string)args[argc++]); builder.Write(buf, 0, buf.Length); break; default: throw new FormatException(); } } else { builder.WriteByte((byte)format[i]); } } parts.Add(new ImapCommandPart(builder.ToArray(), null)); } }
/// <summary> /// Queues the command. /// </summary> /// <returns>The command.</returns> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="folder">The folder that the command operates on.</param> /// <param name="format">The command format.</param> /// <param name="args">The command arguments.</param> public ImapCommand QueueCommand(CancellationToken cancellationToken, ImapFolder folder, string format, params object[] args) { var ic = new ImapCommand (this, cancellationToken, folder, format, args); QueueCommand (ic); return ic; }
void UpdateNamespaces(CancellationToken cancellationToken) { var namespaces = new List<FolderNamespaceCollection> { PersonalNamespaces, SharedNamespaces, OtherNamespaces }; ImapFolder folder; ImapToken token; string path; char delim; int n = 0; PersonalNamespaces.Clear (); SharedNamespaces.Clear (); OtherNamespaces.Clear (); token = stream.ReadToken (cancellationToken); do { if (token.Type == ImapTokenType.OpenParen) { // parse the list of namespace pairs... token = stream.ReadToken (cancellationToken); while (token.Type == ImapTokenType.OpenParen) { // parse the namespace pair - first token is the path token = stream.ReadToken (cancellationToken); if (token.Type != ImapTokenType.QString && token.Type != ImapTokenType.Atom) { Debug.WriteLine ("Expected string token as first element in namespace pair, but got: {0}", token); throw UnexpectedToken (token, false); } path = (string) token.Value; // second token is the directory separator token = stream.ReadToken (cancellationToken); if (token.Type != ImapTokenType.QString && token.Type != ImapTokenType.Nil) { Debug.WriteLine ("Expected string or nil token as second element in namespace pair, but got: {0}", token); throw UnexpectedToken (token, false); } var qstring = token.Type == ImapTokenType.Nil ? string.Empty : (string) token.Value; if (qstring.Length > 0) { delim = qstring[0]; // canonicalize the namespace path path = path.TrimEnd (delim); } else { delim = '\0'; } namespaces[n].Add (new FolderNamespace (delim, ImapEncoding.Decode (path))); if (!FolderCache.TryGetValue (path, out folder)) { folder = new ImapFolder (this, path, FolderAttributes.None, delim); FolderCache.Add (path, folder); } folder.IsNamespace = true; do { token = stream.ReadToken (cancellationToken); if (token.Type == ImapTokenType.CloseParen) break; // NAMESPACE extension if (token.Type != ImapTokenType.QString && token.Type != ImapTokenType.Atom) throw UnexpectedToken (token, false); token = stream.ReadToken (cancellationToken); if (token.Type != ImapTokenType.OpenParen) throw UnexpectedToken (token, false); do { token = stream.ReadToken (cancellationToken); if (token.Type == ImapTokenType.CloseParen) break; if (token.Type != ImapTokenType.QString && token.Type != ImapTokenType.Atom) throw UnexpectedToken (token, false); } while (true); } while (true); // read the next token - it should either be '(' or ')' token = stream.ReadToken (cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { Debug.WriteLine ("Expected ')' to close namespace pair, but got: {0}", token); throw UnexpectedToken (token, false); } } else if (token.Type != ImapTokenType.Nil) { Debug.WriteLine ("Expected '(' or 'NIL' token after untagged 'NAMESPACE' response, but got: {0}", token); throw UnexpectedToken (token, false); } token = stream.ReadToken (cancellationToken); n++; } while (n < 3); while (token.Type != ImapTokenType.Eoln) token = stream.ReadToken (cancellationToken); }
/// <summary> /// Looks up and sets the <see cref="ImapFolder.ParentFolder"/> property of each of the folders. /// </summary> /// <param name="folders">The IMAP folders.</param> /// <param name="cancellationToken">The cancellation token.</param> void LookupParentFolders(IEnumerable<ImapFolder> folders, CancellationToken cancellationToken) { var list = new List<ImapFolder> (folders); string encodedName; ImapFolder parent; int index; foreach (var folder in list) { if (folder.ParentFolder != null) continue; if ((index = folder.FullName.LastIndexOf (folder.DirectorySeparator)) != -1) { if (index == 0) continue; var parentName = folder.FullName.Substring (0, index); encodedName = ImapEncoding.Encode (parentName); } else { encodedName = string.Empty; } if (FolderCache.TryGetValue (encodedName, out parent)) { folder.SetParentFolder (parent); continue; } var ic = new ImapCommand (this, cancellationToken, null, "LIST \"\" %S\r\n", encodedName); ic.RegisterUntaggedHandler ("LIST", ImapUtils.ParseFolderList); ic.UserData = new List<ImapFolder> (); QueueCommand (ic); Wait (ic); if (!FolderCache.TryGetValue (encodedName, out parent)) { parent = new ImapFolder (this, encodedName, FolderAttributes.NonExistent, folder.DirectorySeparator); FolderCache.Add (encodedName, parent); } else if (parent.ParentFolder == null && !parent.IsNamespace) { list.Add (parent); } folder.SetParentFolder (parent); } }
/// <summary> /// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapCommand"/> class. /// </summary> /// <param name="engine">The IMAP engine that will be sending the command.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="folder">The IMAP folder that the command operates on.</param> /// <param name="format">The command format.</param> /// <param name="args">The command arguments.</param> public ImapCommand (ImapEngine engine, CancellationToken cancellationToken, ImapFolder folder, string format, params object[] args) { UntaggedHandlers = new Dictionary<string, ImapUntaggedHandler> (); RespCodes = new List<ImapResponseCode> (); CancellationToken = cancellationToken; Status = ImapCommandStatus.Created; Result = ImapCommandResult.None; Engine = engine; Folder = folder; using (var builder = new MemoryStream ()) { int argc = 0; byte[] buf; string str; char c; for (int i = 0; i < format.Length; i++) { if (format[i] == '%') { switch (format[++i]) { case '%': // a literal % builder.WriteByte ((byte) '%'); break; case 'c': // a character c = (char) args[argc++]; builder.WriteByte ((byte) c); break; case 'd': // an integer str = ((int) args[argc++]).ToString (); buf = Encoding.ASCII.GetBytes (str); builder.Write (buf, 0, buf.Length); break; case 'u': // an unsigned integer str = ((uint) args[argc++]).ToString (); buf = Encoding.ASCII.GetBytes (str); builder.Write (buf, 0, buf.Length); break; case 'F': // an ImapFolder var utf7 = ((ImapFolder) args[argc++]).EncodedName; AppendString (builder, utf7); break; case 'L': var literal = new ImapLiteral (args[argc++]); var length = literal.Length; buf = Encoding.ASCII.GetBytes (length.ToString ()); // FIXME: support LITERAL+? builder.WriteByte ((byte) '{'); builder.Write (buf, 0, buf.Length); builder.WriteByte ((byte) '}'); builder.WriteByte ((byte) '\r'); builder.WriteByte ((byte) '\n'); parts.Add (new ImapCommandPart (builder.ToArray (), literal)); builder.SetLength (0); break; case 'S': // a string which may need to be quoted or made into a literal AppendString (builder, (string) args[argc++]); break; case 's': // a safe atom string buf = Encoding.ASCII.GetBytes ((string) args[argc++]); builder.Write (buf, 0, buf.Length); break; default: throw new FormatException (); } } else { builder.WriteByte ((byte) format[i]); } } parts.Add (new ImapCommandPart (builder.ToArray (), null)); } }
/// <summary> /// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapCommand"/> class. /// </summary> /// <param name="engine">The IMAP engine that will be sending the command.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="folder">The IMAP folder that the command operates on.</param> /// <param name="format">The command format.</param> /// <param name="args">The command arguments.</param> public ImapCommand(ImapEngine engine, CancellationToken cancellationToken, ImapFolder folder, string format, params object[] args) { UntaggedHandlers = new Dictionary <string, ImapUntaggedHandler> (); RespCodes = new List <ImapResponseCode> (); CancellationToken = cancellationToken; Status = ImapCommandStatus.Created; Result = ImapCommandResult.None; Engine = engine; Folder = folder; using (var builder = new MemoryStream()) { int argc = 0; byte[] buf; string str; char c; for (int i = 0; i < format.Length; i++) { if (format[i] == '%') { switch (format[++i]) { case '%': // a literal % builder.WriteByte((byte)'%'); break; case 'c': // a character c = (char)args[argc++]; builder.WriteByte((byte)c); break; case 'd': // an integer str = ((int)args[argc++]).ToString(); buf = Encoding.ASCII.GetBytes(str); builder.Write(buf, 0, buf.Length); break; case 'u': // an unsigned integer str = ((uint)args[argc++]).ToString(); buf = Encoding.ASCII.GetBytes(str); builder.Write(buf, 0, buf.Length); break; case 'F': // an ImapFolder var utf7 = ((ImapFolder)args[argc++]).EncodedName; AppendString(builder, utf7); break; case 'L': var literal = new ImapLiteral(args[argc++]); var length = literal.Length; buf = Encoding.ASCII.GetBytes(length.ToString()); // FIXME: support LITERAL+? builder.WriteByte((byte)'{'); builder.Write(buf, 0, buf.Length); builder.WriteByte((byte)'}'); builder.WriteByte((byte)'\r'); builder.WriteByte((byte)'\n'); parts.Add(new ImapCommandPart(builder.ToArray(), literal)); builder.SetLength(0); break; case 'S': // a string which may need to be quoted or made into a literal AppendString(builder, (string)args[argc++]); break; case 's': // a safe atom string buf = Encoding.ASCII.GetBytes((string)args[argc++]); builder.Write(buf, 0, buf.Length); break; default: throw new FormatException(); } } else { builder.WriteByte((byte)format[i]); } } parts.Add(new ImapCommandPart(builder.ToArray(), null)); } }
/// <summary> /// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapCommand"/> class. /// </summary> /// <remarks> /// Creates a new <see cref="MailKit.Net.Imap.ImapCommand"/>. /// </remarks> /// <param name="engine">The IMAP engine that will be sending the command.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="folder">The IMAP folder that the command operates on.</param> /// <param name="options">The formatting options.</param> /// <param name="format">The command format.</param> /// <param name="args">The command arguments.</param> public ImapCommand (ImapEngine engine, CancellationToken cancellationToken, ImapFolder folder, FormatOptions options, string format, params object[] args) { UntaggedHandlers = new Dictionary<string, ImapUntaggedHandler> (); RespCodes = new List<ImapResponseCode> (); CancellationToken = cancellationToken; Response = ImapCommandResponse.None; Status = ImapCommandStatus.Created; Engine = engine; Folder = folder; using (var builder = new MemoryStream ()) { var plus = (Engine.Capabilities & ImapCapabilities.LiteralPlus) != 0 ? "+" : string.Empty; int argc = 0; byte[] buf; string str; char c; for (int i = 0; i < format.Length; i++) { if (format[i] == '%') { switch (format[++i]) { case '%': // a literal % builder.WriteByte ((byte) '%'); break; case 'c': // a character c = (char) args[argc++]; builder.WriteByte ((byte) c); break; case 'd': // an integer str = ((int) args[argc++]).ToString (); buf = Encoding.ASCII.GetBytes (str); builder.Write (buf, 0, buf.Length); break; case 'u': // an unsigned integer str = ((uint) args[argc++]).ToString (); buf = Encoding.ASCII.GetBytes (str); builder.Write (buf, 0, buf.Length); break; case 'F': // an ImapFolder var utf7 = ((ImapFolder) args[argc++]).EncodedName; AppendString (options, true, builder, utf7); break; case 'L': var literal = new ImapLiteral (options, args[argc++], UpdateProgress); var length = literal.Length; totalSize += length; if (options.International) str = "UTF8 (~{" + length + plus + "}\r\n"; else str = "{" + length + plus + "}\r\n"; buf = Encoding.ASCII.GetBytes (str); builder.Write (buf, 0, buf.Length); parts.Add (new ImapCommandPart (builder.ToArray (), literal)); builder.SetLength (0); if (options.International) builder.WriteByte ((byte) ')'); break; case 'S': // a string which may need to be quoted or made into a literal AppendString (options, true, builder, (string) args[argc++]); break; case 'Q': // similar to %S but string must be quoted at a minimum AppendString (options, false, builder, (string) args[argc++]); break; case 's': // a safe atom string buf = Encoding.ASCII.GetBytes ((string) args[argc++]); builder.Write (buf, 0, buf.Length); break; default: throw new FormatException (); } } else { builder.WriteByte ((byte) format[i]); } } parts.Add (new ImapCommandPart (builder.ToArray (), null)); } }
/// <summary> /// Parses an untagged LIST or LSUB response. /// </summary> /// <param name="engine">The IMAP engine.</param> /// <param name="ic">The IMAP command.</param> /// <param name="index">The index.</param> /// <param name="tok">The token.</param> public static void ParseFolderList(ImapEngine engine, ImapCommand ic, int index, ImapToken tok) { var token = engine.ReadToken (ic.CancellationToken); var list = (List<ImapFolder>) ic.UserData; var attrs = FolderAttributes.None; string encodedName; ImapFolder folder; char delim; // parse the folder attributes list if (token.Type != ImapTokenType.OpenParen) throw ImapEngine.UnexpectedToken (token, false); token = engine.ReadToken (ic.CancellationToken); while (token.Type == ImapTokenType.Flag || token.Type == ImapTokenType.Atom) { string atom = (string) token.Value; switch (atom) { case "\\NoInferiors": attrs |= FolderAttributes.NoInferiors; break; case "\\Noselect": attrs |= FolderAttributes.NoSelect; break; case "\\Marked": attrs |= FolderAttributes.Marked; break; case "\\Unmarked": attrs |= FolderAttributes.Unmarked; break; case "\\NonExistent": attrs |= FolderAttributes.NonExistent; break; case "\\Subscribed": attrs |= FolderAttributes.Subscribed; break; case "\\Remote": attrs |= FolderAttributes.Remote; break; case "\\HasChildren": attrs |= FolderAttributes.HasChildren; break; case "\\HasNoChildren": attrs |= FolderAttributes.HasNoChildren; break; case "\\All": attrs |= FolderAttributes.All; break; case "\\Archive": attrs |= FolderAttributes.Archive; break; case "\\Drafts": attrs |= FolderAttributes.Drafts; break; case "\\Flagged": attrs |= FolderAttributes.Flagged; break; case "\\Junk": attrs |= FolderAttributes.Junk; break; case "\\Sent": attrs |= FolderAttributes.Sent; break; case "\\Trash": attrs |= FolderAttributes.Trash; break; // XLIST flags: case "\\AllMail": attrs |= FolderAttributes.All; break; case "\\Important": attrs |= FolderAttributes.Flagged; break; case "\\Inbox": break; case "\\Spam": attrs |= FolderAttributes.Junk; break; case "\\Starred": attrs |= FolderAttributes.Flagged; break; } token = engine.ReadToken (ic.CancellationToken); } if (token.Type != ImapTokenType.CloseParen) throw ImapEngine.UnexpectedToken (token, false); // parse the path delimeter token = engine.ReadToken (ic.CancellationToken); if (token.Type == ImapTokenType.QString) { var qstring = (string) token.Value; delim = qstring[0]; } else if (token.Type == ImapTokenType.Nil) { delim = '\0'; } else { throw ImapEngine.UnexpectedToken (token, false); } // parse the folder name token = engine.ReadToken (ic.CancellationToken); switch (token.Type) { case ImapTokenType.Literal: encodedName = engine.ReadLiteral (ic.CancellationToken); break; case ImapTokenType.QString: case ImapTokenType.Atom: encodedName = (string) token.Value; break; default: throw ImapEngine.UnexpectedToken (token, false); } if (engine.FolderCache.TryGetValue (encodedName, out folder)) { folder.Attributes = (folder.Attributes & ~(FolderAttributes.Marked | FolderAttributes.Unmarked)) | attrs; } else { folder = new ImapFolder (engine, encodedName, attrs, delim); engine.FolderCache.Add (encodedName, folder); } list.Add (folder); }
/// <summary> /// Queries the special folders. /// </summary> /// <returns>The command result.</returns> /// <param name="cancellationToken">The cancellation token.</param> public void QuerySpecialFolders(CancellationToken cancellationToken) { if (stream == null) throw new InvalidOperationException (); ImapFolder folder; if (!FolderCache.TryGetValue ("INBOX", out folder)) { var list = new List<ImapFolder> (); var ic = QueueCommand (cancellationToken, null, "LIST \"\" \"INBOX\"\r\n"); ic.RegisterUntaggedHandler ("LIST", ImapUtils.HandleUntaggedListResponse); ic.UserData = list; Wait (ic); Inbox = list.Count > 0 ? list[0] : null; } if ((Capabilities & ImapCapabilities.SpecialUse) != 0) { var list = new List<ImapFolder> (); var ic = QueueCommand (cancellationToken, null, "LIST (SPECIAL-USE) \"\" \"*\"\r\n"); ic.RegisterUntaggedHandler ("LIST", ImapUtils.HandleUntaggedListResponse); ic.UserData = list; Wait (ic); ImapUtils.LookupParentFolders (this, list, cancellationToken); for (int i = 0; i < list.Count; i++) { folder = list[i]; if ((folder.Attributes & FolderAttributes.All) != 0) All = folder; if ((folder.Attributes & FolderAttributes.Archive) != 0) Archive = folder; if ((folder.Attributes & FolderAttributes.Drafts) != 0) Drafts = folder; if ((folder.Attributes & FolderAttributes.Flagged) != 0) Flagged = folder; if ((folder.Attributes & FolderAttributes.Junk) != 0) Junk = folder; if ((folder.Attributes & FolderAttributes.Sent) != 0) Sent = folder; if ((folder.Attributes & FolderAttributes.Trash) != 0) Trash = folder; } } else if ((Capabilities & ImapCapabilities.XList) != 0) { var list = new List<ImapFolder> (); var ic = QueueCommand (cancellationToken, null, "XLIST \"\" \"*\"\r\n"); ic.RegisterUntaggedHandler ("XLIST", ImapUtils.HandleUntaggedListResponse); ic.UserData = list; Wait (ic); ImapUtils.LookupParentFolders (this, list, cancellationToken); for (int i = 0; i < list.Count; i++) { folder = list[i]; if ((folder.Attributes & FolderAttributes.All) != 0) All = folder; if ((folder.Attributes & FolderAttributes.Archive) != 0) Archive = folder; if ((folder.Attributes & FolderAttributes.Drafts) != 0) Drafts = folder; if ((folder.Attributes & FolderAttributes.Flagged) != 0) Flagged = folder; if ((folder.Attributes & FolderAttributes.Junk) != 0) Junk = folder; if ((folder.Attributes & FolderAttributes.Sent) != 0) Sent = folder; if ((folder.Attributes & FolderAttributes.Trash) != 0) Trash = folder; } } }
/// <summary> /// Looks up and sets the <see cref="ImapFolder.ParentFolder"/> property of each of the folders. /// </summary> /// <param name="engine">The IMAP engine.</param> /// <param name="folders">The IMAP folders.</param> /// <param name="cancellationToken">The cancellation token.</param> public static void LookupParentFolders(ImapEngine engine, IEnumerable<ImapFolder> folders, CancellationToken cancellationToken) { int index; foreach (var folder in folders) { if (folder.ParentFolder != null) continue; if ((index = folder.FullName.LastIndexOf (folder.DirectorySeparator)) == -1) continue; if (index == 0) continue; var parentName = folder.FullName.Substring (0, index); var encodedName = ImapEncoding.Encode (parentName); ImapFolder parent; if (engine.FolderCache.TryGetValue (encodedName, out parent)) { folder.SetParentFolder (parent); continue; } var ic = engine.QueueCommand (cancellationToken, null, "LIST \"\" %S\r\n", encodedName); ic.RegisterUntaggedHandler ("LIST", ImapUtils.HandleUntaggedListResponse); ic.UserData = new List<ImapFolder> (); engine.Wait (ic); if (!engine.FolderCache.TryGetValue (encodedName, out parent)) { parent = new ImapFolder (engine, encodedName, FolderAttributes.NonExistent, folder.DirectorySeparator); engine.FolderCache.Add (encodedName, parent); } folder.SetParentFolder (parent); } }
/// <summary> /// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapCommand"/> class. /// </summary> /// <remarks> /// Creates a new <see cref="MailKit.Net.Imap.ImapCommand"/>. /// </remarks> /// <param name="engine">The IMAP engine that will be sending the command.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="folder">The IMAP folder that the command operates on.</param> /// <param name="options">The formatting options.</param> /// <param name="format">The command format.</param> /// <param name="args">The command arguments.</param> public ImapCommand(ImapEngine engine, CancellationToken cancellationToken, ImapFolder folder, FormatOptions options, string format, params object[] args) { UntaggedHandlers = new Dictionary <string, ImapUntaggedHandler> (StringComparer.OrdinalIgnoreCase); Logout = format.Equals("LOGOUT\r\n", StringComparison.Ordinal); RespCodes = new List <ImapResponseCode> (); CancellationToken = cancellationToken; Response = ImapCommandResponse.None; Status = ImapCommandStatus.Created; Engine = engine; Folder = folder; using (var builder = new ByteArrayBuilder(1024)) { byte[] buf, utf8 = new byte[8]; int argc = 0; string str; for (int i = 0; i < format.Length; i++) { if (format[i] == '%') { switch (format[++i]) { case '%': // a literal % builder.Append((byte)'%'); break; case 'd': // an integer str = ((int)args[argc++]).ToString(CultureInfo.InvariantCulture); buf = Encoding.ASCII.GetBytes(str); builder.Append(buf, 0, buf.Length); break; case 'u': // an unsigned integer str = ((uint)args[argc++]).ToString(CultureInfo.InvariantCulture); buf = Encoding.ASCII.GetBytes(str); builder.Append(buf, 0, buf.Length); break; case 's': str = (string)args[argc++]; buf = Encoding.ASCII.GetBytes(str); builder.Append(buf, 0, buf.Length); break; case 'F': // an ImapFolder var utf7 = ((ImapFolder)args[argc++]).EncodedName; AppendString(options, true, builder, utf7); break; case 'L': // a MimeMessage or a byte[] var arg = args[argc++]; ImapLiteral literal; byte[] prefix; if (arg is MimeMessage message) { prefix = options.International ? UTF8LiteralTokenPrefix : LiteralTokenPrefix; literal = new ImapLiteral(options, message, UpdateProgress); } else { literal = new ImapLiteral(options, (byte[])arg); prefix = LiteralTokenPrefix; } var length = literal.Length; bool wait = true; builder.Append(prefix, 0, prefix.Length); buf = Encoding.ASCII.GetBytes(length.ToString(CultureInfo.InvariantCulture)); builder.Append(buf, 0, buf.Length); if (CanUseNonSynchronizedLiteral(Engine, length)) { builder.Append((byte)'+'); wait = false; } builder.Append(LiteralTokenSuffix, 0, LiteralTokenSuffix.Length); totalSize += length; parts.Add(new ImapCommandPart(builder.ToArray(), literal, wait)); builder.Clear(); if (prefix == UTF8LiteralTokenPrefix) { builder.Append((byte)')'); } break; case 'S': // a string which may need to be quoted or made into a literal AppendString(options, true, builder, (string)args[argc++]); break; case 'Q': // similar to %S but string must be quoted at a minimum AppendString(options, false, builder, (string)args[argc++]); break; default: throw new FormatException(); } } else if (format[i] < 128) { builder.Append((byte)format[i]); } else { int nchars = char.IsSurrogate(format[i]) ? 2 : 1; int nbytes = Encoding.UTF8.GetBytes(format, i, nchars, utf8, 0); builder.Append(utf8, 0, nbytes); i += nchars - 1; } } parts.Add(new ImapCommandPart(builder.ToArray(), null)); } }
/// <summary> /// Instantiate a new <see cref="ImapFolder"/>. /// </summary> /// <remarks> /// <para>Creates a new <see cref="ImapFolder"/> instance.</para> /// <note type="note">This method's purpose is to allow subclassing <see cref="ImapFolder"/>.</note> /// </remarks> /// <returns>The IMAP folder instance.</returns> /// <param name="args">The constructior arguments.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="args"/> is <c>null</c>. /// </exception> protected virtual ImapFolder CreateImapFolder (ImapFolderConstructorArgs args) { var folder = new ImapFolder (args); folder.UpdateAppendLimit (AppendLimit); return folder; }
/// <summary> /// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapCommand"/> class. /// </summary> /// <remarks> /// Creates a new <see cref="MailKit.Net.Imap.ImapCommand"/>. /// </remarks> /// <param name="engine">The IMAP engine that will be sending the command.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="folder">The IMAP folder that the command operates on.</param> /// <param name="options">The formatting options.</param> /// <param name="format">The command format.</param> /// <param name="args">The command arguments.</param> public ImapCommand(ImapEngine engine, CancellationToken cancellationToken, ImapFolder folder, FormatOptions options, string format, params object[] args) { UntaggedHandlers = new Dictionary <string, ImapUntaggedHandler> (); Logout = format.Equals("LOGOUT\r\n", StringComparison.Ordinal); RespCodes = new List <ImapResponseCode> (); CancellationToken = cancellationToken; Response = ImapCommandResponse.None; Status = ImapCommandStatus.Created; Engine = engine; Folder = folder; using (var builder = new MemoryStream()) { int argc = 0; byte[] buf; string str; for (int i = 0; i < format.Length; i++) { if (format[i] == '%') { switch (format[++i]) { case '%': // a literal % builder.WriteByte((byte)'%'); break; case 'd': // an integer str = ((int)args[argc++]).ToString(CultureInfo.InvariantCulture); buf = Encoding.ASCII.GetBytes(str); builder.Write(buf, 0, buf.Length); break; case 'u': // an unsigned integer str = ((uint)args[argc++]).ToString(CultureInfo.InvariantCulture); buf = Encoding.ASCII.GetBytes(str); builder.Write(buf, 0, buf.Length); break; case 's': str = (string)args[argc++]; buf = Encoding.ASCII.GetBytes(str); builder.Write(buf, 0, buf.Length); break; case 'F': // an ImapFolder var utf7 = ((ImapFolder)args[argc++]).EncodedName; AppendString(options, true, builder, utf7); break; case 'L': // a MimeMessage var literal = new ImapLiteral(options, (MimeMessage)args[argc++], UpdateProgress); var prefix = options.International ? UTF8LiteralTokenPrefix : LiteralTokenPrefix; var length = literal.Length; bool wait = true; builder.Write(prefix, 0, prefix.Length); buf = Encoding.ASCII.GetBytes(length.ToString(CultureInfo.InvariantCulture)); builder.Write(buf, 0, buf.Length); if (CanUseNonSynchronizedLiteral(Engine, length)) { builder.WriteByte((byte)'+'); wait = false; } builder.Write(LiteralTokenSuffix, 0, LiteralTokenSuffix.Length); totalSize += length; parts.Add(new ImapCommandPart(builder.ToArray(), literal, wait)); builder.SetLength(0); if (options.International) { builder.WriteByte((byte)')'); } break; case 'S': // a string which may need to be quoted or made into a literal AppendString(options, true, builder, (string)args[argc++]); break; case 'Q': // similar to %S but string must be quoted at a minimum AppendString(options, false, builder, (string)args[argc++]); break; default: throw new FormatException(); } } else { builder.WriteByte((byte)format[i]); } } parts.Add(new ImapCommandPart(builder.ToArray(), null)); } }
/// <summary> /// Parses an untagged LIST or LSUB response. /// </summary> /// <param name="engine">The IMAP engine.</param> /// <param name="ic">The IMAP command.</param> /// <param name="index">The index.</param> /// <param name="tok">The token.</param> public static void ParseFolderList(ImapEngine engine, ImapCommand ic, int index, ImapToken tok) { var token = engine.ReadToken(ic.CancellationToken); var list = (List <ImapFolder>)ic.UserData; var attrs = FolderAttributes.None; string encodedName; ImapFolder folder; char delim; // parse the folder attributes list if (token.Type != ImapTokenType.OpenParen) { throw ImapEngine.UnexpectedToken(token, false); } token = engine.ReadToken(ic.CancellationToken); while (token.Type == ImapTokenType.Flag || token.Type == ImapTokenType.Atom) { string atom = (string)token.Value; switch (atom) { case "\\NoInferiors": attrs |= FolderAttributes.NoInferiors; break; case "\\Noselect": attrs |= FolderAttributes.NoSelect; break; case "\\Marked": attrs |= FolderAttributes.Marked; break; case "\\Unmarked": attrs |= FolderAttributes.Unmarked; break; case "\\NonExistent": attrs |= FolderAttributes.NonExistent; break; case "\\Subscribed": attrs |= FolderAttributes.Subscribed; break; case "\\Remote": attrs |= FolderAttributes.Remote; break; case "\\HasChildren": attrs |= FolderAttributes.HasChildren; break; case "\\HasNoChildren": attrs |= FolderAttributes.HasNoChildren; break; case "\\All": attrs |= FolderAttributes.All; break; case "\\Archive": attrs |= FolderAttributes.Archive; break; case "\\Drafts": attrs |= FolderAttributes.Drafts; break; case "\\Flagged": attrs |= FolderAttributes.Flagged; break; case "\\Junk": attrs |= FolderAttributes.Junk; break; case "\\Sent": attrs |= FolderAttributes.Sent; break; case "\\Trash": attrs |= FolderAttributes.Trash; break; // XLIST flags: case "\\AllMail": attrs |= FolderAttributes.All; break; case "\\Important": attrs |= FolderAttributes.Flagged; break; case "\\Inbox": break; case "\\Spam": attrs |= FolderAttributes.Junk; break; case "\\Starred": attrs |= FolderAttributes.Flagged; break; } token = engine.ReadToken(ic.CancellationToken); } if (token.Type != ImapTokenType.CloseParen) { throw ImapEngine.UnexpectedToken(token, false); } // parse the path delimeter token = engine.ReadToken(ic.CancellationToken); if (token.Type == ImapTokenType.QString) { var qstring = (string)token.Value; delim = qstring[0]; } else if (token.Type == ImapTokenType.Nil) { delim = '\0'; } else { throw ImapEngine.UnexpectedToken(token, false); } // parse the folder name token = engine.ReadToken(ic.CancellationToken); switch (token.Type) { case ImapTokenType.Literal: encodedName = engine.ReadLiteral(ic.CancellationToken); break; case ImapTokenType.QString: case ImapTokenType.Atom: encodedName = (string)token.Value; break; default: throw ImapEngine.UnexpectedToken(token, false); } if (engine.FolderCache.TryGetValue(encodedName, out folder)) { folder.Attributes = (folder.Attributes & ~(FolderAttributes.Marked | FolderAttributes.Unmarked)) | attrs; } else { folder = new ImapFolder(engine, encodedName, attrs, delim); engine.FolderCache.Add(encodedName, folder); } list.Add(folder); }
/// <summary> /// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapCommand"/> class. /// </summary> /// <remarks> /// Creates a new <see cref="MailKit.Net.Imap.ImapCommand"/>. /// </remarks> /// <param name="engine">The IMAP engine that will be sending the command.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="folder">The IMAP folder that the command operates on.</param> /// <param name="format">The command format.</param> /// <param name="args">The command arguments.</param> public ImapCommand(ImapEngine engine, CancellationToken cancellationToken, ImapFolder folder, string format, params object[] args) : this(engine, cancellationToken, folder, FormatOptions.Default, format, args) { }
/// <summary> /// Queues the command. /// </summary> /// <returns>The command.</returns> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="folder">The folder that the command operates on.</param> /// <param name="format">The command format.</param> /// <param name="args">The command arguments.</param> public ImapCommand QueueCommand(CancellationToken cancellationToken, ImapFolder folder, string format, params object[] args) { return QueueCommand (cancellationToken, folder, FormatOptions.Default, format, args); }
/// <summary> /// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapCommand"/> class. /// </summary> /// <remarks> /// Creates a new <see cref="MailKit.Net.Imap.ImapCommand"/>. /// </remarks> /// <param name="engine">The IMAP engine that will be sending the command.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="folder">The IMAP folder that the command operates on.</param> /// <param name="format">The command format.</param> /// <param name="args">The command arguments.</param> public ImapCommand (ImapEngine engine, CancellationToken cancellationToken, ImapFolder folder, string format, params object[] args) : this (engine, cancellationToken, folder, FormatOptions.Default, format, args) { }
public MessageNew(MessageSummaryItems messageSummaryItems, HashSet <HeaderId> fields) : base("MessageNew", true) { MessageSummaryItems = messageSummaryItems; Headers = ImapFolder.GetHeaderNames(fields); }