/// <summary> /// Parses an untagged ID response. /// </summary> /// <param name="engine">The IMAP engine.</param> /// <param name="ic">The IMAP command.</param> /// <param name="index">The index.</param> public static void ParseImplementation(ImapEngine engine, ImapCommand ic, int index) { var token = engine.ReadToken(ic.CancellationToken); var implementation = new ImapImplementation(); ic.UserData = implementation; if (token.Type == ImapTokenType.Nil) { return; } if (token.Type != ImapTokenType.OpenParen) { throw ImapEngine.UnexpectedToken(token, false); } token = engine.PeekToken(ic.CancellationToken); while (token.Type != ImapTokenType.CloseParen) { var property = ImapUtils.ReadStringToken(engine, ic.CancellationToken); var value = ImapUtils.ReadNStringToken(engine, false, ic.CancellationToken); implementation.Properties[property] = value; token = engine.PeekToken(ic.CancellationToken); } // read the ')' token engine.ReadToken(ic.CancellationToken); }
public static void Capabilities () { using (var client = new ImapClient ()) { client.Connect ("imap.gmail.com", 993, SecureSocketOptions.SslOnConnect); var mechanisms = string.Join (", ", client.AuthenticationMechanisms); Console.WriteLine ("The IMAP server supports the following SASL authentication mechanisms: {0}", mechanisms); client.Authenticate ("username", "password"); if (client.Capabilities.HasFlag (ImapCapabilities.Id)) { var clientImplementation = new ImapImplementation { Name = "MailKit", Version = "1.0" }; var serverImplementation = client.Identify (clientImplementation); Console.WriteLine ("Server implementation details:"); foreach (var property in serverImplementation.Properties) Console.WriteLine (" {0} = {1}", property.Key, property.Value); } if (client.Capabilities.HasFlag (ImapCapabilities.Acl)) { Console.WriteLine ("The IMAP server supports Access Control Lists."); Console.WriteLine ("The IMAP server supports the following access rights: {0}", client.Rights); Console.WriteLine ("The Inbox has the following access controls:"); var acl = client.Inbox.GetAccessControlList (); foreach (var ac in acl) Console.WriteLine (" {0} = {1}", ac.Name, ac.Rights); var myRights = client.Inbox.GetMyAccessRights (); Console.WriteLine ("Your current rights for the Inbox folder are: {0}", myRights); } if (client.Capabilities.HasFlag (ImapCapabilities.Quota)) { Console.WriteLine ("The IMAP server supports quotas."); Console.WriteLine ("The current quota for the Inbox is:"); var quota = client.Inbox.GetQuota (); if (quota.StorageLimit.HasValue && quota.StorageLimit.Value) Console.WriteLine (" Limited by storage space. Using {0} out of {1} bytes.", quota.CurrentStorageSize.Value, quota.StorageLimit.Value); if (quota.MessageLimit.HasValue && quota.MessageLimit.Value) Console.WriteLine (" Limited by the number of messages. Using {0} out of {1} bytes.", quota.CurrentMessageCount.Value, quota.MessageLimit.Value); Console.WriteLine ("The quota root is: {0}", quota.QuotaRoot); } if (client.Capabilities.HasFlag (ImapCapabilities.Thread)) { if (client.ThreadingAlgorithms.Contains (ThreadingAlgorithm.OrderedSubject)) Console.WriteLine ("The IMAP server supports threading by subject."); if (client.ThreadingAlgorithms.Contains (ThreadingAlgorithm.References)) Console.WriteLine ("The IMAP server supports threading by references."); } client.Disconnect (true); } }
/// <summary> /// Asynchronously identify the client implementation to the server and obtain the server implementation details. /// </summary> /// <remarks> /// <para>Passes along the client implementation details to the server while also obtaining implementation /// details from the server.</para> /// <para>If the <paramref name="clientImplementation"/> is <c>null</c> or no properties have been set, no /// identifying information will be sent to the server.</para> /// <note type="security"> /// <para>Security Implications</para> /// <para>This command has the danger of violating the privacy of users if misused. Clients should /// notify users that they send the ID command.</para> /// <para>It is highly desirable that implementations provide a method of disabling ID support, perhaps by /// not calling this method at all, or by passing <c>null</c> as the <paramref name="clientImplementation"/> /// argument.</para> /// <para>Implementors must exercise extreme care in adding properties to the <paramref name="clientImplementation"/>. /// Some properties, such as a processor ID number, Ethernet address, or other unique (or mostly unique) identifier /// would allow tracking of users in ways that violate user privacy expectations and may also make it easier for /// attackers to exploit security holes in the client.</para> /// </note> /// </remarks> /// <returns>The implementation details of the server if available; otherwise, <c>null</c>.</returns> /// <param name="clientImplementation">The client implementation.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <exception cref="System.ObjectDisposedException"> /// The <see cref="ImapClient"/> has been disposed. /// </exception> /// <exception cref="ServiceNotConnectedException"> /// The <see cref="ImapClient"/> is not connected. /// </exception> /// <exception cref="System.NotSupportedException"> /// The IMAP server does not support the ID extension. /// </exception> /// <exception cref="System.OperationCanceledException"> /// The operation was canceled via the cancellation token. /// </exception> /// <exception cref="System.IO.IOException"> /// An I/O error occurred. /// </exception> /// <exception cref="ImapCommandException"> /// The server replied to the ID command with a NO or BAD response. /// </exception> /// <exception cref="ImapProtocolException"> /// An IMAP protocol error occurred. /// </exception> public Task <ImapImplementation> IdentifyAsync(ImapImplementation clientImplementation, CancellationToken cancellationToken = default(CancellationToken)) { return(IdentifyAsync(clientImplementation, true, cancellationToken)); }
/// <summary> /// Asynchronously identify the client implementation to the server and obtain the server implementation details. /// </summary> /// <remarks> /// <para>Passes along the client implementation details to the server while also obtaining implementation /// details from the server.</para> /// <para>If the <paramref name="clientImplementation"/> is null or no properties have been set, no /// identifying information will be sent to the server.</para> /// <para>Security Implications</para> /// <para>This command has the danger of violating the privacy of users if misused. Clients should /// notify users that they send the ID command.</para> /// <para>It is highly desirable that implementations provide a method of disabling ID support, perhaps by /// not calling this method at all, or by passing <c>null</c> as the <paramref name="clientImplementation"/> /// argument.</para> /// <para>Implementors must exercise extreme care in adding properties to the <paramref name="clientImplementation"/>. /// Some properties, such as a processor ID number, Ethernet address, or other unique (or mostly unique) identifier /// would allow tracking of users in ways that violate user privacy expectations and may also make it easier for /// attackers to exploit security holes in the client.</para> /// </remarks> /// <returns>The implementation details of the server.</returns> /// <param name="clientImplementation">The client implementation.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <exception cref="System.ObjectDisposedException"> /// The <see cref="ImapClient"/> has been disposed. /// </exception> /// <exception cref="ServiceNotConnectedException"> /// The <see cref="ImapClient"/> is not connected. /// </exception> /// <exception cref="System.NotSupportedException"> /// The IMAP server does not support the ID extension. /// </exception> /// <exception cref="System.OperationCanceledException"> /// The operation was canceled via the cancellation token. /// </exception> /// <exception cref="System.IO.IOException"> /// An I/O error occurred. /// </exception> /// <exception cref="ImapCommandException"> /// The server replied to the ID command with a NO or BAD response. /// </exception> /// <exception cref="ImapProtocolException"> /// An IMAP protocol error occurred. /// </exception> public Task<ImapImplementation> IdentifyAsync (ImapImplementation clientImplementation, CancellationToken cancellationToken = default (CancellationToken)) { return Task.Factory.StartNew (() => { lock (SyncRoot) { return Identify (clientImplementation, cancellationToken); } }, cancellationToken, TaskCreationOptions.None, TaskScheduler.Default); }
/// <summary> /// Identify the client implementation to the server and obtain the server implementation details. /// </summary> /// <remarks> /// <para>Passes along the client implementation details to the server while also obtaining implementation /// details from the server.</para> /// <para>If the <paramref name="clientImplementation"/> is null or no properties have been set, no /// identifying information will be sent to the server.</para> /// <para>Security Implications</para> /// <para>This command has the danger of violating the privacy of users if misused. Clients should /// notify users that they send the ID command.</para> /// <para>It is highly desirable that implementations provide a method of disabling ID support, perhaps by /// not calling this method at all, or by passing <c>null</c> as the <paramref name="clientImplementation"/> /// argument.</para> /// <para>Implementors must exercise extreme care in adding properties to the <paramref name="clientImplementation"/>. /// Some properties, such as a processor ID number, Ethernet address, or other unique (or mostly unique) identifier /// would allow tracking of users in ways that violate user privacy expectations and may also make it easier for /// attackers to exploit security holes in the client.</para> /// </remarks> /// <example> /// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/> /// </example> /// <returns>The implementation details of the server.</returns> /// <param name="clientImplementation">The client implementation.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <exception cref="System.ObjectDisposedException"> /// The <see cref="ImapClient"/> has been disposed. /// </exception> /// <exception cref="ServiceNotConnectedException"> /// The <see cref="ImapClient"/> is not connected. /// </exception> /// <exception cref="System.NotSupportedException"> /// The IMAP server does not support the ID extension. /// </exception> /// <exception cref="System.OperationCanceledException"> /// The operation was canceled via the cancellation token. /// </exception> /// <exception cref="System.IO.IOException"> /// An I/O error occurred. /// </exception> /// <exception cref="ImapCommandException"> /// The server replied to the ID command with a NO or BAD response. /// </exception> /// <exception cref="ImapProtocolException"> /// An IMAP protocol error occurred. /// </exception> public ImapImplementation Identify (ImapImplementation clientImplementation, CancellationToken cancellationToken = default (CancellationToken)) { CheckDisposed (); CheckConnected (); if ((engine.Capabilities & ImapCapabilities.Id) == 0) throw new NotSupportedException ("The IMAP server does not support the ID extension."); var command = new StringBuilder ("ID "); var args = new List<object> (); if (clientImplementation != null && clientImplementation.Properties.Count > 0) { command.Append ('('); foreach (var property in clientImplementation.Properties) { command.Append ("%Q "); args.Add (property.Key); if (property.Value != null) { command.Append ("%Q "); args.Add (property.Value); } else { command.Append ("NIL "); } } command[command.Length - 1] = ')'; command.Append ("\r\n"); } else { command.Append ("NIL\r\n"); } var ic = new ImapCommand (engine, cancellationToken, null, command.ToString (), args.ToArray ()); ic.RegisterUntaggedHandler ("ID", ImapUtils.ParseImplementation); engine.QueueCommand (ic); engine.Wait (ic); if (ic.Response != ImapCommandResponse.Ok) throw ImapCommandException.Create ("ID", ic); return (ImapImplementation) ic.UserData; }
/// <summary> /// Parses an untagged ID response. /// </summary> /// <param name="engine">The IMAP engine.</param> /// <param name="ic">The IMAP command.</param> /// <param name="index">The index.</param> public static void ParseImplementation (ImapEngine engine, ImapCommand ic, int index) { var token = engine.ReadToken (ic.CancellationToken); var implementation = new ImapImplementation (); ic.UserData = implementation; if (token.Type == ImapTokenType.Nil) return; if (token.Type != ImapTokenType.OpenParen) throw ImapEngine.UnexpectedToken (token, false); token = engine.PeekToken (ic.CancellationToken); while (token.Type != ImapTokenType.CloseParen) { var property = ImapUtils.ReadStringToken (engine, ic.CancellationToken); var value = ImapUtils.ReadNStringToken (engine, false, ic.CancellationToken); implementation.Properties[property] = value; token = engine.PeekToken (ic.CancellationToken); } // read the ')' token engine.ReadToken (ic.CancellationToken); }
public async void TestImapClientFeatures () { var commands = new List<ImapReplayCommand> (); commands.Add (new ImapReplayCommand ("", "gmail.greeting.txt")); commands.Add (new ImapReplayCommand ("A00000000 CAPABILITY\r\n", "gmail.capability.txt")); commands.Add (new ImapReplayCommand ("A00000001 AUTHENTICATE PLAIN AHVzZXJuYW1lAHBhc3N3b3Jk\r\n", "gmail.authenticate.txt")); commands.Add (new ImapReplayCommand ("A00000002 NAMESPACE\r\n", "gmail.namespace.txt")); commands.Add (new ImapReplayCommand ("A00000003 LIST \"\" \"INBOX\"\r\n", "gmail.list-inbox.txt")); commands.Add (new ImapReplayCommand ("A00000004 XLIST \"\" \"*\"\r\n", "gmail.xlist.txt")); commands.Add (new ImapReplayCommand ("A00000005 ID (\"name\" \"MailKit\" \"version\" \"1.0\" \"vendor\" \"Xamarin Inc.\")\r\n", "common.id.txt")); commands.Add (new ImapReplayCommand ("A00000006 GETQUOTAROOT INBOX\r\n", "common.getquota.txt")); commands.Add (new ImapReplayCommand ("A00000007 SETQUOTA \"\" (MESSAGE 1000000 STORAGE 5242880)\r\n", "common.setquota.txt")); using (var client = new ImapClient ()) { try { client.ReplayConnect ("localhost", new ImapReplayStream (commands, false)); } catch (Exception ex) { Assert.Fail ("Did not expect an exception in Connect: {0}", ex); } Assert.IsTrue (client.IsConnected, "Client failed to connect."); Assert.IsFalse (client.IsSecure, "IsSecure should be false."); Assert.AreEqual (GMailInitialCapabilities, client.Capabilities); Assert.AreEqual (5, client.AuthenticationMechanisms.Count); Assert.IsTrue (client.AuthenticationMechanisms.Contains ("XOAUTH"), "Expected SASL XOAUTH auth mechanism"); Assert.IsTrue (client.AuthenticationMechanisms.Contains ("XOAUTH2"), "Expected SASL XOAUTH2 auth mechanism"); Assert.IsTrue (client.AuthenticationMechanisms.Contains ("OAUTHBEARER"), "Expected SASL OAUTHBEARER auth mechanism"); Assert.IsTrue (client.AuthenticationMechanisms.Contains ("PLAIN"), "Expected SASL PLAIN auth mechanism"); Assert.IsTrue (client.AuthenticationMechanisms.Contains ("PLAIN-CLIENTTOKEN"), "Expected SASL PLAIN-CLIENTTOKEN auth mechanism"); Assert.AreEqual (100000, client.Timeout, "Timeout"); client.Timeout *= 2; // Note: Do not try XOAUTH2 client.AuthenticationMechanisms.Remove ("XOAUTH2"); try { await client.AuthenticateAsync (new NetworkCredential ("username", "password")); } catch (Exception ex) { Assert.Fail ("Did not expect an exception in Authenticate: {0}", ex); } Assert.AreEqual (GMailAuthenticatedCapabilities, client.Capabilities); Assert.IsTrue (client.SupportsQuotas, "SupportsQuotas"); var implementation = new ImapImplementation { Name = "MailKit", Version = "1.0", Vendor = "Xamarin Inc." }; implementation = await client.IdentifyAsync (implementation); Assert.IsNotNull (implementation, "Expected a non-null ID response."); Assert.AreEqual ("GImap", implementation.Name); Assert.AreEqual ("Google, Inc.", implementation.Vendor); Assert.AreEqual ("http://support.google.com/mail", implementation.SupportUrl); Assert.AreEqual ("gmail_imap_150623.03_p1", implementation.Version); Assert.AreEqual ("127.0.0.1", implementation.Properties["remote-host"]); var personal = client.GetFolder (client.PersonalNamespaces[0]); var inbox = client.Inbox; Assert.IsNotNull (inbox, "Expected non-null Inbox folder."); Assert.AreEqual (FolderAttributes.Inbox | FolderAttributes.HasNoChildren, inbox.Attributes, "Expected Inbox attributes to be \\HasNoChildren."); var quota = await inbox.GetQuotaAsync (); Assert.IsNotNull (quota, "Expected a non-null GETQUOTAROOT response."); Assert.AreEqual (personal.FullName, quota.QuotaRoot.FullName); Assert.AreEqual (personal, quota.QuotaRoot); Assert.AreEqual (3783, quota.CurrentStorageSize.Value); Assert.AreEqual (15728640, quota.StorageLimit.Value); Assert.IsFalse (quota.CurrentMessageCount.HasValue); Assert.IsFalse (quota.MessageLimit.HasValue); quota = await personal.SetQuotaAsync (1000000, 5242880); Assert.IsNotNull (quota, "Expected non-null SETQUOTA response."); Assert.AreEqual (1107, quota.CurrentMessageCount.Value); Assert.AreEqual (3783, quota.CurrentStorageSize.Value); Assert.AreEqual (1000000, quota.MessageLimit.Value); Assert.AreEqual (5242880, quota.StorageLimit.Value); await client.DisconnectAsync (false); } }
public Task<ImapImplementation> IdentifyAsync(ImapImplementation clientImplementation, CancellationToken cancellationToken = new CancellationToken()) { return _imapClient.IdentifyAsync(clientImplementation, cancellationToken); }
public ImapImplementation Identify(ImapImplementation clientImplementation, CancellationToken cancellationToken = new CancellationToken()) { return _imapClient.Identify(clientImplementation, cancellationToken); }
/// <summary> /// Parses an untagged ID response. /// </summary> /// <param name="engine">The IMAP engine.</param> /// <param name="ic">The IMAP command.</param> /// <param name="index">The index.</param> public static void ParseImplementation (ImapEngine engine, ImapCommand ic, int index) { string format = string.Format (ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "ID", "{0}"); var token = engine.ReadToken (ic.CancellationToken); ImapImplementation implementation; if (token.Type == ImapTokenType.Nil) return; if (token.Type != ImapTokenType.OpenParen) throw ImapEngine.UnexpectedToken (format, token); token = engine.PeekToken (ic.CancellationToken); implementation = new ImapImplementation (); while (token.Type != ImapTokenType.CloseParen) { var property = ReadStringToken (engine, format, ic.CancellationToken); var value = ReadNStringToken (engine, format, false, ic.CancellationToken); implementation.Properties[property] = value; token = engine.PeekToken (ic.CancellationToken); } ic.UserData = implementation; // read the ')' token engine.ReadToken (ic.CancellationToken); }