Ejemplo n.º 1
0
		public void TestNoQuery ()
		{
			var uri = new Uri ("imap://imap.gmail.com/");
			var query = uri.ParsedQuery ();

			Assert.AreEqual (0, query.Count, "Unexpected number of queries.");
		}
Ejemplo n.º 2
0
		public void TestSimpleQuery ()
		{
			var uri = new Uri ("imap://imap.gmail.com/?starttls=false");
			var query = uri.ParsedQuery ();

			Assert.AreEqual (1, query.Count, "Unexpected number of queries.");
			Assert.AreEqual ("false", query["starttls"], "Unexpected value for 'starttls'.");
		}
Ejemplo n.º 3
0
		/// <summary>
		/// Establish a connection to the specified mail server.
		/// </summary>
		/// <remarks>
		/// Establishes a connection to the specified mail server.
		/// </remarks>
		/// <example>
		/// <code language="c#" source="Examples\SmtpExamples.cs" region="SendMessageUri"/>
		/// </example>
		/// <param name="uri">The server URI.</param>
		/// <param name="cancellationToken">The cancellation token.</param>
		/// <exception cref="System.ArgumentNullException">
		/// The <paramref name="uri"/> is <c>null</c>.
		/// </exception>
		/// <exception cref="System.ArgumentException">
		/// The <paramref name="uri"/> is not an absolute URI.
		/// </exception>
		/// <exception cref="System.ObjectDisposedException">
		/// The <see cref="MailService"/> has been disposed.
		/// </exception>
		/// <exception cref="System.InvalidOperationException">
		/// The <see cref="MailService"/> is already connected.
		/// </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="ProtocolException">
		/// A protocol error occurred.
		/// </exception>
		public void Connect (Uri uri, CancellationToken cancellationToken = default (CancellationToken))
		{
			if (uri == null)
				throw new ArgumentNullException ("uri");

			if (!uri.IsAbsoluteUri)
				throw new ArgumentException ("The uri must be absolute.", "uri");

			var protocol = uri.Scheme.ToLowerInvariant ();
			var query = uri.ParsedQuery ();
			SecureSocketOptions options;
			string value;

			// Note: early versions of MailKit used "pop3" and "pop3s"
			if (protocol == "pop3s")
				protocol = "pops";
			else if (protocol == "pop3")
				protocol = "pop";

			if (protocol == Protocol + "s") {
				options = SecureSocketOptions.SslOnConnect;
			} else if (protocol != Protocol) {
				throw new ArgumentException ("Unknown URI scheme.", "uri");
			} else if (query.TryGetValue ("starttls", out value)) {
				switch (value.ToLowerInvariant ()) {
				default:
					options = SecureSocketOptions.StartTlsWhenAvailable;
					break;
				case "always": case "true": case "yes":
					options = SecureSocketOptions.StartTls;
					break;
				case "never": case "false": case "no":
					options = SecureSocketOptions.None;
					break;
				}
			} else {
				options = SecureSocketOptions.StartTlsWhenAvailable;
			}

			Connect (uri.Host, uri.Port < 0 ? 0 : uri.Port, options, cancellationToken);
		}
Ejemplo n.º 4
0
        /// <summary>
        /// Establishes a connection to the specified SMTP server.
        /// </summary>
        /// <remarks>
        /// <para>Establishes a connection to an SMTP or SMTP/S server. If the schema
        /// in the uri is "smtp", a clear-text connection is made and defaults to using
        /// port 25 if no port is specified in the URI. However, if the schema in the
        /// uri is "smtps", an SSL connection is made using the
        /// <see cref="ClientCertificates"/> and defaults to port 465 unless a port
        /// is specified in the URI.</para>
        /// <para>It should be noted that when using a clear-text SMTP connection,
        /// if the server advertizes support for the STARTTLS extension, the client
        /// will automatically switch into TLS mode before authenticating unless the
        /// <paramref name="uri"/> contains a query string to disable it.</para>
        /// If a successful connection is made, the <see cref="AuthenticationMechanisms"/>
        /// and <see cref="Capabilities"/> properties will be populated.
        /// </remarks>
        /// <param name="uri">The server URI. The <see cref="System.Uri.Scheme"/> should either
        /// be "smtp" to make a clear-text connection or "smtps" to make an SSL connection.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para>The <paramref name="uri"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// The <paramref name="uri"/> is not an absolute URI.
        /// </exception>
        /// <exception cref="System.ObjectDisposedException">
        /// The <see cref="SmtpClient"/> has been disposed.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// The <see cref="SmtpClient"/> is already connected.
        /// </exception>
        /// <exception cref="System.OperationCanceledException">
        /// The operation was canceled.
        /// </exception>
        /// <exception cref="System.IO.IOException">
        /// An I/O error occurred.
        /// </exception>
        /// <exception cref="SmtpCommandException">
        /// An SMTP command failed.
        /// </exception>
        /// <exception cref="SmtpProtocolException">
        /// An SMTP protocol error occurred.
        /// </exception>
        public void Connect(Uri uri, CancellationToken cancellationToken = default (CancellationToken))
        {
            CheckDisposed ();

            if (uri == null)
                throw new ArgumentNullException ("uri");

            if (!uri.IsAbsoluteUri)
                throw new ArgumentException ("The uri must be absolute.", "uri");

            if (IsConnected)
                throw new InvalidOperationException ("The SmtpClient is already connected.");

            capabilities = SmtpCapabilities.None;
            authmechs.Clear ();
            MaxSize = 0;

            var smtps = uri.Scheme.ToLowerInvariant () == "smtps";
            var port = uri.Port > 0 ? uri.Port : (smtps ? 465 : 25);
            var query = uri.ParsedQuery ();
            SmtpResponse response = null;
            string value;

            var starttls = !smtps && (!query.TryGetValue ("starttls", out value) || Convert.ToBoolean (value));

            #if !NETFX_CORE
            var ipAddresses = Dns.GetHostAddresses (uri.DnsSafeHost);
            Socket socket = null;

            for (int i = 0; i < ipAddresses.Length; i++) {
                socket = new Socket (ipAddresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                cancellationToken.ThrowIfCancellationRequested ();

                try {
                    socket.Connect (ipAddresses[i], port);
                    localEndPoint = socket.LocalEndPoint;
                    break;
                } catch {
                    if (i + 1 == ipAddresses.Length)
                        throw;
                }
            }

            if (smtps) {
                var ssl = new SslStream (new NetworkStream (socket, true), false, ValidateRemoteCertificate);
                ssl.AuthenticateAsClient (uri.Host, ClientCertificates, SslProtocols.Default, true);
                stream = ssl;
            } else {
                stream = new NetworkStream (socket, true);
            }
            #else
            socket = new StreamSocket ();

            cancellationToken.ThrowIfCancellationRequested ();
            socket.ConnectAsync (new HostName (uri.DnsSafeHost), port.ToString (), smtps ? SocketProtectionLevel.Tls12 : SocketProtectionLevel.PlainSocket)
                .AsTask (cancellationToken)
                .GetAwaiter ()
                .GetResult ();

            stream = new DuplexStream (socket.InputStream.AsStreamForRead (), socket.OutputStream.AsStreamForWrite ());
            #endif

            if (stream.CanTimeout) {
                stream.WriteTimeout = timeout;
                stream.ReadTimeout = timeout;
            }
            host = uri.Host;

            logger.LogConnect (uri);

            try {
                // read the greeting
                response = ReadResponse (cancellationToken);

                if (response.StatusCode != SmtpStatusCode.ServiceReady)
                    throw new SmtpCommandException (SmtpErrorCode.UnexpectedStatusCode, response.StatusCode, response.Response);

                // Send EHLO and get a list of supported extensions
                Ehlo (cancellationToken);

                if (starttls && (capabilities & SmtpCapabilities.StartTLS) != 0) {
                    response = SendCommand ("STARTTLS", cancellationToken);
                    if (response.StatusCode != SmtpStatusCode.ServiceReady)
                        throw new SmtpCommandException (SmtpErrorCode.UnexpectedStatusCode, response.StatusCode, response.Response);

            #if !NETFX_CORE
                    var tls = new SslStream (stream, false, ValidateRemoteCertificate);
                    tls.AuthenticateAsClient (uri.Host, ClientCertificates, SslProtocols.Tls, true);
                    stream = tls;
            #else
                    socket.UpgradeToSslAsync (SocketProtectionLevel.Tls12, new HostName (uri.DnsSafeHost))
                        .AsTask (cancellationToken)
                        .GetAwaiter ()
                        .GetResult ();
            #endif

                    // Send EHLO again and get the new list of supported extensions
                    Ehlo (cancellationToken);
                }

                IsConnected = true;
            } catch {
                stream.Dispose ();
                stream = null;
                throw;
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Establishes a connection to the specified POP3 server.
        /// </summary>
        /// <remarks>
        /// <para>Establishes a connection to an POP3 or POP3/S server. If the schema
        /// in the uri is "pop", a clear-text connection is made and defaults to using
        /// port 110 if no port is specified in the URI. However, if the schema in the
        /// uri is "pops", an SSL connection is made using the
        /// <see cref="ClientCertificates"/> and defaults to port 995 unless a port
        /// is specified in the URI.</para>
        /// <para>It should be noted that when using a clear-text POP3 connection,
        /// if the server advertizes support for the STLS extension, the client
        /// will automatically switch into TLS mode before authenticating unless
        /// the <paramref name="uri"/> contains a query string to disable it.</para>
        /// If a successful connection is made, the <see cref="AuthenticationMechanisms"/>
        /// and <see cref="Capabilities"/> properties will be populated.
        /// </remarks>
        /// <param name="uri">The server URI. The <see cref="System.Uri.Scheme"/> should either
        /// be "pop" to make a clear-text connection or "pops" to make an SSL connection.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <exception cref="System.ArgumentNullException">
        /// The <paramref name="uri"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// The <paramref name="uri"/> is not an absolute URI.
        /// </exception>
        /// <exception cref="System.ObjectDisposedException">
        /// The <see cref="Pop3Client"/> has been disposed.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// The <see cref="Pop3Client"/> is already connected.
        /// </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="Pop3CommandException">
        /// A POP3 command failed.
        /// </exception>
        /// <exception cref="Pop3ProtocolException">
        /// A POP3 protocol error occurred.
        /// </exception>
        public void Connect(Uri uri, CancellationToken cancellationToken)
        {
            CheckDisposed ();

            if (uri == null)
                throw new ArgumentNullException ("uri");

            if (!uri.IsAbsoluteUri)
                throw new ArgumentException ("The uri must be absolute.", "uri");

            if (IsConnected)
                throw new InvalidOperationException ("The Pop3Client is already connected.");

            var scheme = uri.Scheme.ToLowerInvariant ();
            var pops = scheme == "pops" || scheme == "pop3s";
            var port = uri.Port > 0 ? uri.Port : (pops ? 995 : 110);
            var query = uri.ParsedQuery ();
            #if !NETFX_CORE && !WINDOWS_APP && !WINDOWS_PHONE_APP
            var ipAddresses = Dns.GetHostAddresses (uri.DnsSafeHost);
            Socket socket = null;
            #endif
            Stream stream;
            string value;

            var starttls = !pops && (!query.TryGetValue ("starttls", out value) || Convert.ToBoolean (value));

            #if !NETFX_CORE && !WINDOWS_APP && !WINDOWS_PHONE_APP
            for (int i = 0; i < ipAddresses.Length; i++) {
                socket = new Socket (ipAddresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                cancellationToken.ThrowIfCancellationRequested ();

                try {
                    socket.Connect (ipAddresses[i], port);
                    break;
                } catch (Exception) {
                    if (i + 1 == ipAddresses.Length)
                        throw;
                }
            }

            if (pops) {
                var ssl = new SslStream (new NetworkStream (socket, true), false, ValidateRemoteCertificate);
                ssl.AuthenticateAsClient (uri.Host, ClientCertificates, SslProtocols.Default, true);
                stream = ssl;
            } else {
                stream = new NetworkStream (socket, true);
            }
            #else
            socket = new StreamSocket ();

            cancellationToken.ThrowIfCancellationRequested ();
            socket.ConnectAsync (new HostName (uri.DnsSafeHost), port.ToString (), pops ? SocketProtectionLevel.Tls12 : SocketProtectionLevel.PlainSocket)
                .AsTask (cancellationToken)
                .GetAwaiter ()
                .GetResult ();

            stream = new DuplexStream (socket.InputStream.AsStreamForRead (), socket.OutputStream.AsStreamForWrite ());
            #endif

            probed = ProbedCapabilities.None;
            host = uri.Host;

            logger.LogConnect (uri);

            engine.Connect (new Pop3Stream (stream, logger), cancellationToken);
            engine.QueryCapabilities (cancellationToken);

            if (starttls && (engine.Capabilities & Pop3Capabilities.StartTLS) != 0) {
                SendCommand (cancellationToken, "STLS");

            #if !NETFX_CORE && !WINDOWS_APP && !WINDOWS_PHONE_APP
                var tls = new SslStream (stream, false, ValidateRemoteCertificate);
                tls.AuthenticateAsClient (uri.Host, ClientCertificates, SslProtocols.Tls, true);
                engine.Stream.Stream = tls;
            #else
                socket.UpgradeToSslAsync (SocketProtectionLevel.Tls12, new HostName (uri.DnsSafeHost))
                    .AsTask (cancellationToken)
                    .GetAwaiter ()
                    .GetResult ();
            #endif

                // re-issue a CAPA command
                engine.QueryCapabilities (cancellationToken);
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Establishes a connection to the specified IMAP server.
        /// </summary>
        /// <remarks>
        /// <para>Establishes a connection to an IMAP or IMAP/S server. If the schema
        /// in the uri is "imap", a clear-text connection is made and defaults to using
        /// port 143 if no port is specified in the URI. However, if the schema in the
        /// uri is "imaps", an SSL connection is made using the
        /// <see cref="ClientCertificates"/> and defaults to port 993 unless a port
        /// is specified in the URI.</para>
        /// <para>It should be noted that when using a clear-text IMAP connection,
        /// if the server advertizes support for the STARTTLS extension, the client
        /// will automatically switch into TLS mode before authenticating unless the
        /// <paramref name="uri"/> contains a query string to disable it.</para>
        /// <para>If the IMAP server advertizes the COMPRESS extension and either does not
        /// support the STARTTLS extension or the <paramref name="uri"/> explicitly disabled
        /// the use of the STARTTLS extension, then the client will automatically opt into
        /// using a compressed data connection to optimize bandwidth usage unless the
        /// <paramref name="uri"/> contains a query string to explicitly disable it.</para>
        /// <para>If a successful connection is made, the <see cref="AuthenticationMechanisms"/>
        /// and <see cref="Capabilities"/> properties will be populated.</para>
        /// </remarks>
        /// <param name="uri">The server URI. The <see cref="System.Uri.Scheme"/> should either
        /// be "imap" to make a clear-text connection or "imaps" to make an SSL connection.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <exception cref="System.ArgumentNullException">
        /// The <paramref name="uri"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// The <paramref name="uri"/> is not an absolute URI.
        /// </exception>
        /// <exception cref="System.ObjectDisposedException">
        /// The <see cref="ImapClient"/> has been disposed.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// The <see cref="ImapClient"/> is already connected.
        /// </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="ImapProtocolException">
        /// An IMAP protocol error occurred.
        /// </exception>
        public void Connect(Uri uri, CancellationToken cancellationToken)
        {
            CheckDisposed ();

            if (uri == null)
                throw new ArgumentNullException ("uri");

            if (!uri.IsAbsoluteUri)
                throw new ArgumentException ("The uri must be absolute.", "uri");

            if (IsConnected)
                throw new InvalidOperationException ("The ImapClient is already connected.");

            var imaps = uri.Scheme.ToLowerInvariant () == "imaps";
            var port = uri.Port > 0 ? uri.Port : (imaps ? 993 : 143);
            var query = uri.ParsedQuery ();
            Stream stream;
            string value;

            var starttls = !imaps && (!query.TryGetValue ("starttls", out value) || Convert.ToBoolean (value));
            var compress = !imaps && (!query.TryGetValue ("compress", out value) || Convert.ToBoolean (value));

            #if !NETFX_CORE
            var ipAddresses = Dns.GetHostAddresses (uri.DnsSafeHost);
            Socket socket = null;

            for (int i = 0; i < ipAddresses.Length; i++) {
                socket = new Socket (ipAddresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                cancellationToken.ThrowIfCancellationRequested ();

                try {
                    socket.Connect (ipAddresses[i], port);
                    break;
                } catch {
                    if (i + 1 == ipAddresses.Length)
                        throw;
                }
            }

            if (imaps) {
                var ssl = new SslStream (new NetworkStream (socket, true), false, ValidateRemoteCertificate);
                ssl.AuthenticateAsClient (uri.Host, ClientCertificates, SslProtocols.Default, true);
                stream = ssl;
            } else {
                stream = new NetworkStream (socket, true);
            }
            #else
            socket = new StreamSocket ();

            cancellationToken.ThrowIfCancellationRequested ();
            socket.ConnectAsync (new HostName (uri.DnsSafeHost), port.ToString (), imaps ? SocketProtectionLevel.Tls12 : SocketProtectionLevel.PlainSocket)
                .AsTask (cancellationToken)
                .GetAwaiter ()
                .GetResult ();

            stream = new DuplexStream (socket.InputStream.AsStreamForRead (), socket.OutputStream.AsStreamForWrite ());
            #endif
            host = uri.Host;

            logger.LogConnect (uri);

            engine.Connect (new ImapStream (stream, logger), cancellationToken);

            // Only query the CAPABILITIES if the greeting didn't include them.
            if (engine.CapabilitiesVersion == 0)
                engine.QueryCapabilities (cancellationToken);

            if (starttls && (engine.Capabilities & ImapCapabilities.StartTLS) != 0) {
                var ic = engine.QueueCommand (cancellationToken, null, "STARTTLS\r\n");

                engine.Wait (ic);

                if (ic.Result == ImapCommandResult.Ok) {
            #if !NETFX_CORE
                    var tls = new SslStream (stream, false, ValidateRemoteCertificate);
                    tls.AuthenticateAsClient (uri.Host, ClientCertificates, SslProtocols.Tls, true);
                    engine.Stream.Stream = tls;
            #else
                    socket.UpgradeToSslAsync (SocketProtectionLevel.Tls12, new HostName (uri.DnsSafeHost))
                        .AsTask (cancellationToken)
                        .GetAwaiter ()
                        .GetResult ();
            #endif

                    // Query the CAPABILITIES again if the server did not include an
                    // untagged CAPABILITIES response to the STARTTLS command.
                    if (engine.CapabilitiesVersion == 1)
                        engine.QueryCapabilities (cancellationToken);
                }
            } else if (compress && (engine.Capabilities & ImapCapabilities.Compress) != 0) {
                var ic = engine.QueueCommand (cancellationToken, null, "COMPRESS DEFLATE\r\n");

                engine.Wait (ic);

                if (ic.Result == ImapCommandResult.Ok) {
                    var unzip = new DeflateStream (stream, CompressionMode.Decompress);
                    var zip = new DeflateStream (stream, CompressionMode.Compress);

                    engine.Stream.Stream = new DuplexStream (unzip, zip);

                    // Query the CAPABILITIES again if the server did not include an
                    // untagged CAPABILITIES response to the COMPRESS command.
                    if (engine.CapabilitiesVersion == 1)
                        engine.QueryCapabilities (cancellationToken);
                }
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Establishes a connection to the specified IMAP server.
        /// </summary>
        /// <remarks>
        /// <para>Establishes a connection to an IMAP or IMAP/S server. If the schema
        /// in the uri is "imap", a clear-text connection is made and defaults to using
        /// port 143 if no port is specified in the URI. However, if the schema in the
        /// uri is "imaps", an SSL connection is made using the
        /// <see cref="ClientCertificates"/> and defaults to port 993 unless a port
        /// is specified in the URI.</para>
        /// <para>It should be noted that when using a clear-text IMAP connection,
        /// if the server advertizes support for the STARTTLS extension, the client
        /// will automatically switch into TLS mode before authenticating unless the
        /// <paramref name="uri"/> contains a query string to disable it.</para>
        /// <para>If the IMAP server advertizes the COMPRESS extension and either does not
        /// support the STARTTLS extension or the <paramref name="uri"/> explicitly disabled
        /// the use of the STARTTLS extension, then the client will automatically opt into
        /// using a compressed data connection to optimize bandwidth usage unless the
        /// <paramref name="uri"/> contains a query string to explicitly disable it.</para>
        /// <para>If a successful connection is made, the <see cref="AuthenticationMechanisms"/>
        /// and <see cref="Capabilities"/> properties will be populated.</para>
        /// </remarks>
        /// <param name="uri">The server URI. The <see cref="System.Uri.Scheme"/> should either
        /// be "imap" to make a clear-text connection or "imaps" to make an SSL connection.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <exception cref="System.ArgumentNullException">
        /// The <paramref name="uri"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// The <paramref name="uri"/> is not an absolute URI.
        /// </exception>
        /// <exception cref="System.ObjectDisposedException">
        /// The <see cref="ImapClient"/> has been disposed.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// The <see cref="ImapClient"/> is already connected.
        /// </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="ImapProtocolException">
        /// An IMAP protocol error occurred.
        /// </exception>
        public void Connect(Uri uri, CancellationToken cancellationToken)
        {
            CheckDisposed ();

            if (uri == null)
                throw new ArgumentNullException ("uri");

            if (!uri.IsAbsoluteUri)
                throw new ArgumentException ("The uri must be absolute.", "uri");

            if (IsConnected)
                throw new InvalidOperationException ("The ImapClient is already connected.");

            bool imaps = uri.Scheme.ToLowerInvariant () == "imaps";
            int port = uri.Port > 0 ? uri.Port : (imaps ? 993 : 143);
            var ipAddresses = Dns.GetHostAddresses (uri.DnsSafeHost);
            var query = uri.ParsedQuery ();
            Socket socket = null;
            Stream stream;
            string value;

            var starttls = !imaps && (!query.TryGetValue ("starttls", out value) || Convert.ToBoolean (value));
            var compress = !imaps && (!query.TryGetValue ("compress", out value) || Convert.ToBoolean (value));

            for (int i = 0; i < ipAddresses.Length; i++) {
                socket = new Socket (ipAddresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                cancellationToken.ThrowIfCancellationRequested ();

                try {
                    socket.Connect (ipAddresses[i], port);
                    break;
                } catch (Exception) {
                    if (i + 1 == ipAddresses.Length)
                        throw;
                }
            }

            if (imaps) {
                var ssl = new SslStream (new NetworkStream (socket, true), false, ValidateRemoteCertificate);
                ssl.AuthenticateAsClient (uri.Host, ClientCertificates, SslProtocols.Default, true);
                stream = ssl;
            } else {
                stream = new NetworkStream (socket, true);
            }

            host = uri.Host;

            logger.LogConnect (uri);

            engine.Connect (new ImapStream (stream, logger), cancellationToken);

            // Only query the CAPABILITIES if the greeting didn't include them.
            if (engine.CapabilitiesVersion == 0)
                engine.QueryCapabilities (cancellationToken);

            if (!starttls)
                engine.Capabilities &= ~ImapCapabilities.StartTLS;

            if (!compress)
                engine.Capabilities &= ~ImapCapabilities.Compress;
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Establishes a connection to the specified POP3 server.
        /// </summary>
        /// <remarks>
        /// <para>Establishes a connection to an POP3 or POP3/S server. If the schema
        /// in the uri is "pop", a clear-text connection is made and defaults to using
        /// port 110 if no port is specified in the URI. However, if the schema in the
        /// uri is "pops", an SSL connection is made using the
        /// <see cref="ClientCertificates"/> and defaults to port 995 unless a port
        /// is specified in the URI.</para>
        /// <para>It should be noted that when using a clear-text POP3 connection,
        /// if the server advertizes support for the STLS extension, the client
        /// will automatically switch into TLS mode before authenticating unless
        /// the <paramref name="uri"/> contains a query string to disable it.</para>
        /// If a successful connection is made, the <see cref="AuthenticationMechanisms"/>
        /// and <see cref="Capabilities"/> properties will be populated.
        /// </remarks>
        /// <param name="uri">The server URI. The <see cref="System.Uri.Scheme"/> should either
        /// be "pop" to make a clear-text connection or "pops" to make an SSL connection.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <exception cref="System.ArgumentNullException">
        /// The <paramref name="uri"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// The <paramref name="uri"/> is not an absolute URI.
        /// </exception>
        /// <exception cref="System.ObjectDisposedException">
        /// The <see cref="Pop3Client"/> has been disposed.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// The <see cref="Pop3Client"/> is already connected.
        /// </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="Pop3CommandException">
        /// A POP3 command failed.
        /// </exception>
        /// <exception cref="Pop3ProtocolException">
        /// A POP3 protocol error occurred.
        /// </exception>
        public void Connect(Uri uri, CancellationToken cancellationToken)
        {
            CheckDisposed ();

            if (uri == null)
                throw new ArgumentNullException ("uri");

            if (!uri.IsAbsoluteUri)
                throw new ArgumentException ("The uri must be absolute.", "uri");

            if (IsConnected)
                throw new InvalidOperationException ("The Pop3Client is already connected.");

            var scheme = uri.Scheme.ToLowerInvariant ();
            bool pops = scheme == "pops" || scheme == "pop3s";
            int port = uri.Port > 0 ? uri.Port : (pops ? 995 : 110);
            var ipAddresses = Dns.GetHostAddresses (uri.DnsSafeHost);
            var query = uri.ParsedQuery ();
            Socket socket = null;
            Stream stream;
            string value;

            var starttls = !pops && (!query.TryGetValue ("starttls", out value) || Convert.ToBoolean (value));

            for (int i = 0; i < ipAddresses.Length; i++) {
                socket = new Socket (ipAddresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                cancellationToken.ThrowIfCancellationRequested ();

                try {
                    socket.Connect (ipAddresses[i], port);
                    break;
                } catch (Exception) {
                    if (i + 1 == ipAddresses.Length)
                        throw;
                }
            }

            if (pops) {
                var ssl = new SslStream (new NetworkStream (socket, true), false, ValidateRemoteCertificate);
                ssl.AuthenticateAsClient (uri.Host, ClientCertificates, SslProtocols.Default, true);
                stream = ssl;
            } else {
                stream = new NetworkStream (socket, true);
            }

            probed = ProbedCapabilities.None;
            host = uri.Host;

            logger.LogConnect (uri);

            engine.Connect (new Pop3Stream (stream, logger), cancellationToken);
            engine.QueryCapabilities (cancellationToken);

            if (starttls && (engine.Capabilities & Pop3Capabilities.StartTLS) != 0) {
                SendCommand (cancellationToken, "STLS");

                var tls = new SslStream (stream, false, ValidateRemoteCertificate);
                tls.AuthenticateAsClient (uri.Host, ClientCertificates, SslProtocols.Tls, true);
                engine.Stream.Stream = tls;

                // re-issue a CAPA command
                engine.QueryCapabilities (cancellationToken);
            }
        }