// // AsyncImapClient.cs // // Author: Jeffrey Stedfast // // Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; using System.IO; using System.Net; using System.Text; using System.Threading; using System.Net.Sockets; using System.Threading.Tasks; using System.Collections.Generic; using MailKit.Security; namespace MailKit.Net.Imap { public partial class ImapClient { /// /// Asynchronously enable compression over the IMAP connection. /// /// /// Asynchronously enables compression over the IMAP connection. /// If the IMAP server supports the extension, /// it is possible at any point after connecting to enable compression to reduce network /// bandwidth usage. Ideally, this method should be called before authenticating. /// /// An asynchronous task context. /// The cancellation token. /// /// The has been disposed. /// /// /// The is not connected. /// /// /// Compression must be enabled before a folder has been selected. /// /// /// The IMAP server does not support the COMPRESS extension. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server replied to the COMPRESS command with a NO or BAD response. /// /// /// An IMAP protocol error occurred. /// public Task CompressAsync (CancellationToken cancellationToken = default (CancellationToken)) { return CompressAsync (true, cancellationToken); } /// /// Asynchronously enable the QRESYNC feature. /// /// /// Enables the QRESYNC feature. /// The QRESYNC extension improves resynchronization performance of folders by /// querying the IMAP server for a list of changes when the folder is opened using the /// /// method. /// If this feature is enabled, the event is replaced /// with the event. /// This method needs to be called immediately after calling one of the /// Authenticate methods, before /// opening any folders. /// /// An asynchronous task context. /// The cancellation token. /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// Quick resynchronization needs to be enabled before selecting a folder. /// /// /// The IMAP server does not support the QRESYNC extension. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server replied to the ENABLE command with a NO or BAD response. /// /// /// An IMAP protocol error occurred. /// public override Task EnableQuickResyncAsync (CancellationToken cancellationToken = default (CancellationToken)) { return EnableQuickResyncAsync (true, cancellationToken); } /// /// Asynchronously enable the UTF8=ACCEPT extension. /// /// /// Enables the UTF8=ACCEPT extension. /// /// An asynchronous task context. /// The cancellation token. /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// UTF8=ACCEPT needs to be enabled before selecting a folder. /// /// /// The IMAP server does not support the UTF8=ACCEPT extension. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server replied to the ENABLE command with a NO or BAD response. /// /// /// An IMAP protocol error occurred. /// public Task EnableUTF8Async (CancellationToken cancellationToken = default (CancellationToken)) { return EnableUTF8Async (true, cancellationToken); } /// /// Asynchronously identify the client implementation to the server and obtain the server implementation details. /// /// /// Passes along the client implementation details to the server while also obtaining implementation /// details from the server. /// If the is null or no properties have been set, no /// identifying information will be sent to the server. /// /// Security Implications /// This command has the danger of violating the privacy of users if misused. Clients should /// notify users that they send the ID command. /// It is highly desirable that implementations provide a method of disabling ID support, perhaps by /// not calling this method at all, or by passing null as the /// argument. /// Implementors must exercise extreme care in adding properties to the . /// 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. /// /// /// The implementation details of the server if available; otherwise, null. /// The client implementation. /// The cancellation token. /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The IMAP server does not support the ID extension. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server replied to the ID command with a NO or BAD response. /// /// /// An IMAP protocol error occurred. /// public Task IdentifyAsync (ImapImplementation clientImplementation, CancellationToken cancellationToken = default (CancellationToken)) { return IdentifyAsync (clientImplementation, true, cancellationToken); } /// /// Asynchronously authenticate using the specified SASL mechanism. /// /// /// Authenticates using the specified SASL mechanism. /// For a list of available SASL authentication mechanisms supported by the server, /// check the property after the service has been /// connected. /// /// An asynchronous task context. /// The SASL mechanism. /// The cancellation token. /// /// is null. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is already authenticated. /// /// /// The operation was canceled via the cancellation token. /// /// /// Authentication using the supplied credentials has failed. /// /// /// A SASL authentication error occurred. /// /// /// An I/O error occurred. /// /// /// An IMAP command failed. /// /// /// An IMAP protocol error occurred. /// public override Task AuthenticateAsync (SaslMechanism mechanism, CancellationToken cancellationToken = default (CancellationToken)) { return AuthenticateAsync (mechanism, true, cancellationToken); } /// /// Asynchronously authenticate using the supplied credentials. /// /// /// If the IMAP server supports one or more SASL authentication mechanisms, /// then the SASL mechanisms that both the client and server support are tried /// in order of greatest security to weakest security. Once a SASL /// authentication mechanism is found that both client and server support, /// the credentials are used to authenticate. /// If the server does not support SASL or if no common SASL mechanisms /// can be found, then LOGIN command is used as a fallback. /// To prevent the usage of certain authentication mechanisms, /// simply remove them from the hash set /// before calling this method. /// /// An asynchronous task context. /// The text encoding to use for the user's credentials. /// The user's credentials. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is already authenticated. /// /// /// The operation was canceled via the cancellation token. /// /// /// Authentication using the supplied credentials has failed. /// /// /// A SASL authentication error occurred. /// /// /// An I/O error occurred. /// /// /// An IMAP command failed. /// /// /// An IMAP protocol error occurred. /// public override Task AuthenticateAsync (Encoding encoding, ICredentials credentials, CancellationToken cancellationToken = default (CancellationToken)) { return AuthenticateAsync (encoding, credentials, true, cancellationToken); } /// /// Asynchronously establish a connection to the specified IMAP server. /// /// /// Establishes a connection to the specified IMAP or IMAP/S server. /// If the has a value of 0, then the /// parameter is used to determine the default port to /// connect to. The default port used with /// is 993. All other values will use a default port of 143. /// If the has a value of /// , then the is used /// to determine the default security options. If the has a value /// of 993, then the default options used will be /// . All other values will use /// . /// Once a connection is established, properties such as /// and will be /// populated. /// /// /// /// /// An asynchronous task context. /// The host name to connect to. /// The port to connect to. If the specified port is 0, then the default port will be used. /// The secure socket options to when connecting. /// The cancellation token. /// /// is null. /// /// /// is not between 0 and 65535. /// /// /// The is a zero-length string. /// /// /// The has been disposed. /// /// /// The is already connected. /// /// /// was set to /// /// and the IMAP server does not support the STARTTLS extension. /// /// /// The operation was canceled via the cancellation token. /// /// /// A socket error occurred trying to connect to the remote host. /// /// /// An error occurred during the SSL/TLS negotiations. /// /// /// An I/O error occurred. /// /// /// An IMAP command failed. /// /// /// An IMAP protocol error occurred. /// public override Task ConnectAsync (string host, int port = 0, SecureSocketOptions options = SecureSocketOptions.Auto, CancellationToken cancellationToken = default (CancellationToken)) { return ConnectAsync (host, port, options, true, cancellationToken); } /// /// Asynchronously establish a connection to the specified IMAP or IMAP/S server using the provided socket. /// /// /// Establishes a connection to the specified IMAP or IMAP/S server using /// the provided socket. /// If the has a value of /// , then the is used /// to determine the default security options. If the has a value /// of 993, then the default options used will be /// . All other values will use /// . /// Once a connection is established, properties such as /// and will be /// populated. /// With the exception of using the to determine the /// default to use when the value /// is , the and /// parameters are only used for logging purposes. /// /// An asynchronous task context. /// The socket to use for the connection. /// The host name to connect to. /// The port to connect to. If the specified port is 0, then the default port will be used. /// The secure socket options to when connecting. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// is not between 0 and 65535. /// /// /// is not connected. /// -or- /// The is a zero-length string. /// /// /// The has been disposed. /// /// /// The is already connected. /// /// /// was set to /// /// and the IMAP server does not support the STARTTLS extension. /// /// /// The operation was canceled via the cancellation token. /// /// /// An error occurred during the SSL/TLS negotiations. /// /// /// An I/O error occurred. /// /// /// An IMAP command failed. /// /// /// An IMAP protocol error occurred. /// public override Task ConnectAsync (Socket socket, string host, int port = 0, SecureSocketOptions options = SecureSocketOptions.Auto, CancellationToken cancellationToken = default (CancellationToken)) { return ConnectAsync (socket, host, port, options, true, cancellationToken); } /// /// Asynchronously establish a connection to the specified IMAP or IMAP/S server using the provided stream. /// /// /// Establishes a connection to the specified IMAP or IMAP/S server using /// the provided stream. /// If the has a value of /// , then the is used /// to determine the default security options. If the has a value /// of 993, then the default options used will be /// . All other values will use /// . /// Once a connection is established, properties such as /// and will be /// populated. /// With the exception of using the to determine the /// default to use when the value /// is , the and /// parameters are only used for logging purposes. /// /// An asynchronous task context. /// The stream to use for the connection. /// The host name to connect to. /// The port to connect to. If the specified port is 0, then the default port will be used. /// The secure socket options to when connecting. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// is not between 0 and 65535. /// /// /// The is a zero-length string. /// /// /// The has been disposed. /// /// /// The is already connected. /// /// /// was set to /// /// and the IMAP server does not support the STARTTLS extension. /// /// /// The operation was canceled via the cancellation token. /// /// /// An error occurred during the SSL/TLS negotiations. /// /// /// An I/O error occurred. /// /// /// An IMAP command failed. /// /// /// An IMAP protocol error occurred. /// public override Task ConnectAsync (Stream stream, string host, int port = 0, SecureSocketOptions options = SecureSocketOptions.Auto, CancellationToken cancellationToken = default (CancellationToken)) { return ConnectAsync (stream, host, port, options, true, cancellationToken); } /// /// Asynchronously disconnect the service. /// /// /// If is true, a LOGOUT command will be issued in order to disconnect cleanly. /// /// /// /// /// An asynchronous task context. /// If set to true, a LOGOUT command will be issued in order to disconnect cleanly. /// The cancellation token. /// /// The has been disposed. /// public override Task DisconnectAsync (bool quit, CancellationToken cancellationToken = default (CancellationToken)) { return DisconnectAsync (quit, true, cancellationToken); } /// /// Asynchronously ping the IMAP server to keep the connection alive. /// /// /// The NOOP command is typically used to keep the connection with the IMAP server /// alive. When a client goes too long (typically 30 minutes) without sending any commands to the /// IMAP server, the IMAP server will close the connection with the client, forcing the client to /// reconnect before it can send any more commands. /// The NOOP command also provides a great way for a client to check for new /// messages. /// When the IMAP server receives a NOOP command, it will reply to the client with a /// list of pending updates such as EXISTS and RECENT counts on the currently /// selected folder. To receive these notifications, subscribe to the /// and events, /// respectively. /// For more information about the NOOP command, see /// rfc3501. /// /// /// /// /// An asynchronous task context. /// The cancellation token. /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server replied to the NOOP command with a NO or BAD response. /// /// /// The server responded with an unexpected token. /// public override Task NoOpAsync (CancellationToken cancellationToken = default (CancellationToken)) { return NoOpAsync (true, cancellationToken); } /// /// Asynchronously toggle the into the IDLE state. /// /// /// When a client enters the IDLE state, the IMAP server will send /// events to the client as they occur on the selected folder. These events /// may include notifications of new messages arriving, expunge notifications, /// flag changes, etc. /// Due to the nature of the IDLE command, a folder must be selected /// before a client can enter into the IDLE state. This can be done by /// opening a folder using /// /// or any of the other variants. /// While the IDLE command is running, no other commands may be issued until the /// is cancelled. /// It is especially important to cancel the /// before cancelling the when using SSL or TLS due to /// the fact that cannot be polled. /// /// An asynchronous task context. /// The cancellation token used to return to the non-idle state. /// The cancellation token. /// /// must be cancellable (i.e. cannot be used). /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// A has not been opened. /// /// /// The IMAP server does not support the IDLE extension. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server replied to the IDLE command with a NO or BAD response. /// /// /// The server responded with an unexpected token. /// public Task IdleAsync (CancellationToken doneToken, CancellationToken cancellationToken = default (CancellationToken)) { return IdleAsync (doneToken, true, cancellationToken); } /// /// Asynchronously request the specified notification events from the IMAP server. /// /// /// The NOTIFY command is used to expand /// which notifications the client wishes to be notified about, including status notifications /// about folders other than the currently selected folder. It can also be used to automatically /// FETCH information about new messages that have arrived in the currently selected folder. /// This, combined with , /// can be used to get instant notifications for changes to any of the specified folders. /// /// An asynchronous task context. /// true if the server should immediately notify the client of the /// selected folder's status; otherwise, false. /// The specific event groups that the client would like to receive notifications for. /// The cancellation token. /// /// is null. /// /// /// is empty. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// One or more is invalid. /// /// /// The IMAP server does not support the NOTIFY extension. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server replied to the NOTIFY command with a NO or BAD response. /// /// /// The server responded with an unexpected token. /// public Task NotifyAsync (bool status, IList eventGroups, CancellationToken cancellationToken = default (CancellationToken)) { return NotifyAsync (status, eventGroups, true, cancellationToken); } /// /// Asynchronously disable any previously requested notification events from the IMAP server. /// /// /// Disables any notification events requested in a prior call to /// . /// request. /// /// An asynchronous task context. /// The cancellation token. /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The IMAP server does not support the NOTIFY extension. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server replied to the NOTIFY command with a NO or BAD response. /// /// /// The server responded with an unexpected token. /// public Task DisableNotifyAsync (CancellationToken cancellationToken = default (CancellationToken)) { return DisableNotifyAsync (true, cancellationToken); } /// /// Asynchronously get all of the folders within the specified namespace. /// /// /// Gets all of the folders within the specified namespace. /// /// The folders. /// The namespace. /// The status items to pre-populate. /// If set to true, only subscribed folders will be listed. /// The cancellation token. /// /// is null. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The operation was canceled via the cancellation token. /// /// /// The namespace folder could not be found. /// /// /// An I/O error occurred. /// /// /// The server replied to the LIST or LSUB command with a NO or BAD response. /// /// /// The server responded with an unexpected token. /// public override Task> GetFoldersAsync (FolderNamespace @namespace, StatusItems items = StatusItems.None, bool subscribedOnly = false, CancellationToken cancellationToken = default (CancellationToken)) { return GetFoldersAsync (@namespace, items, subscribedOnly, true, cancellationToken); } /// /// Asynchronously get the folder for the specified path. /// /// /// Gets the folder for the specified path. /// /// The folder. /// The folder path. /// The cancellation token. /// /// is null. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The operation was canceled via the cancellation token. /// /// /// The folder could not be found. /// /// /// An I/O error occurred. /// /// /// The server replied to the IDLE command with a NO or BAD response. /// /// /// The server responded with an unexpected token. /// public override async Task GetFolderAsync (string path, CancellationToken cancellationToken = default (CancellationToken)) { if (path == null) throw new ArgumentNullException (nameof (path)); CheckDisposed (); CheckConnected (); CheckAuthenticated (); return await engine.GetFolderAsync (path, true, cancellationToken).ConfigureAwait (false); } /// /// Asynchronously gets the specified metadata. /// /// /// Gets the specified metadata. /// /// The requested metadata value. /// The metadata tag. /// The cancellation token. /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The IMAP server does not support the METADATA or METADATA-SERVER extension. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task GetMetadataAsync (MetadataTag tag, CancellationToken cancellationToken = default (CancellationToken)) { return GetMetadataAsync (tag, true, cancellationToken); } /// /// Asynchronously gets the specified metadata. /// /// /// Gets the specified metadata. /// /// The requested metadata. /// The metadata options. /// The metadata tags. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The IMAP server does not support the METADATA or METADATA-SERVER extension. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task GetMetadataAsync (MetadataOptions options, IEnumerable tags, CancellationToken cancellationToken = default (CancellationToken)) { return GetMetadataAsync (options, tags, true, cancellationToken); } /// /// Asynchronously gets the specified metadata. /// /// /// Sets the specified metadata. /// /// An asynchronous task context. /// The metadata. /// The cancellation token. /// /// is null. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The IMAP server does not support the METADATA or METADATA-SERVER extension. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task SetMetadataAsync (MetadataCollection metadata, CancellationToken cancellationToken = default (CancellationToken)) { return SetMetadataAsync (metadata, true, cancellationToken); } } }