Esempio n. 1
0
        /// <summary>
        /// Takes posession of the <see cref="Pop3Stream"/> and reads the greeting.
        /// </summary>
        /// <remarks>
        /// Takes posession of the <see cref="Pop3Stream"/> and reads the greeting.
        /// </remarks>
        /// <param name="pop3">The pop3 stream.</param>
        /// <param name="cancellationToken">The cancellation token</param>
        public void Connect(Pop3Stream pop3, CancellationToken cancellationToken)
        {
            if (stream != null)
            {
                stream.Dispose();
            }

            Capabilities = Pop3Capabilities.User;
            AuthenticationMechanisms.Clear();
            State     = Pop3EngineState.Disconnected;
            ApopToken = null;
            stream    = pop3;

            // read the pop3 server greeting
            var greeting = ReadLine(cancellationToken).TrimEnd();

            int    index = greeting.IndexOf(' ');
            string token, text;

            if (index != -1)
            {
                token = greeting.Substring(0, index);

                while (index < greeting.Length && char.IsWhiteSpace(greeting[index]))
                {
                    index++;
                }

                if (index < greeting.Length)
                {
                    text = greeting.Substring(index);
                }
                else
                {
                    text = string.Empty;
                }
            }
            else
            {
                text  = string.Empty;
                token = greeting;
            }

            if (token != "+OK")
            {
                stream.Dispose();
                stream = null;

                throw new Pop3ProtocolException(string.Format("Unexpected greeting from server: {0}", greeting));
            }

            index = text.IndexOf('>');
            if (text.Length > 0 && text[0] == '<' && index != -1)
            {
                ApopToken     = text.Substring(0, index + 1);
                Capabilities |= Pop3Capabilities.Apop;
            }

            State = Pop3EngineState.Connected;
        }
Esempio n. 2
0
        void AddAuthenticationMechanisms(string text, int startIndex)
        {
            int index = startIndex;

            while (ReadNextToken(text, ref index, out var tokenIndex, out var length))
            {
                var mechanism = text.Substring(tokenIndex, length);

                AuthenticationMechanisms.Add(mechanism);
            }
        }
Esempio n. 3
0
        private async Task ConnectToServer(IEmailConfiguration emailConfiguration, IMailService emailClient)
        {
            await emailClient.ConnectAsync(emailConfiguration.ServerAddress, emailConfiguration.Port,
                                           emailConfiguration.RequireSSL);

            // if the user has added extra authentication mechnanisms add them to the email client
            if (AuthenticationMechanisms != null && AuthenticationMechanisms.Any())
            {
                foreach (var authMechanism in AuthenticationMechanisms)
                {
                    emailClient.AuthenticationMechanisms.Add(authMechanism);
                }
            }

            emailClient.AuthenticationMechanisms.Remove("XOAUTH2");
            await emailClient.AuthenticateAsync(emailConfiguration.Username,
                                                emailConfiguration.Password);
        }
Esempio n. 4
0
        async Task <Pop3CommandStatus> QueryCapabilitiesAsync(bool doAsync, CancellationToken cancellationToken)
        {
            if (stream == null)
            {
                throw new InvalidOperationException();
            }

            // clear all CAPA response capabilities (except the APOP and USER capabilities)
            Capabilities &= Pop3Capabilities.Apop | Pop3Capabilities.User;
            AuthenticationMechanisms.Clear();
            Implementation = null;
            ExpirePolicy   = 0;
            LoginDelay     = 0;

            var pc = QueueCommand(cancellationToken, CapaHandler, "CAPA");

            while (await IterateAsync(doAsync).ConfigureAwait(false) < pc.Id)
            {
                // continue processing commands...
            }

            return(pc.Status);
        }
Esempio n. 5
0
        public Pop3CommandStatus QueryCapabilities(CancellationToken cancellationToken)
        {
            if (stream == null)
            {
                throw new InvalidOperationException();
            }

            // clear all CAPA response capabilities (except the APOP capability)
            Capabilities &= Pop3Capabilities.Apop;
            AuthenticationMechanisms.Clear();
            Implementation = null;
            ExpirePolicy   = 0;
            LoginDelay     = 0;

            var pc = QueueCommand(cancellationToken, CapaHandler, "CAPA");

            while (Iterate() < pc.Id)
            {
                // continue processing commands...
            }

            return(pc.Status);
        }
Esempio n. 6
0
        async Task ConnectAsync(Pop3Stream pop3, bool doAsync, CancellationToken cancellationToken)
        {
            if (stream != null)
            {
                stream.Dispose();
            }

            Capabilities = Pop3Capabilities.User;
            AuthenticationMechanisms.Clear();
            State     = Pop3EngineState.Disconnected;
            ApopToken = null;
            stream    = pop3;

            // read the pop3 server greeting
            var greeting = (await ReadLineAsync(doAsync, cancellationToken).ConfigureAwait(false)).TrimEnd();

            int    index = greeting.IndexOf(' ');
            string token, text;

            if (index != -1)
            {
                token = greeting.Substring(0, index);

                while (index < greeting.Length && char.IsWhiteSpace(greeting[index]))
                {
                    index++;
                }

                if (index < greeting.Length)
                {
                    text = greeting.Substring(index);
                }
                else
                {
                    text = string.Empty;
                }
            }
            else
            {
                text  = string.Empty;
                token = greeting;
            }

            if (token != "+OK")
            {
                stream.Dispose();
                stream = null;

                throw new Pop3ProtocolException(string.Format("Unexpected greeting from server: {0}", greeting));
            }

            index = text.IndexOf('<');
            if (index != -1 && index + 1 < text.Length)
            {
                int endIndex = text.IndexOf('>', index + 1);

                if (endIndex++ != -1)
                {
                    ApopToken     = text.Substring(index, endIndex - index);
                    Capabilities |= Pop3Capabilities.Apop;
                }
            }

            State = Pop3EngineState.Connected;
        }
Esempio n. 7
0
        /// <summary>
        /// Authenticates using the supplied credentials.
        /// </summary>
        /// <remarks>
        /// <para>If the SMTP server supports authentication, 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.</para>
        /// <para>If, on the other hand, authentication is not supported, then
        /// this method simply returns without attempting to authenticate.</para>
        /// </remarks>
        /// <param name="credentials">The user's credentials.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="credentials"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// The <see cref="SmtpClient"/> is not connected or is already authenticated.
        /// </exception>
        /// <exception cref="System.NotSupportedException">
        /// The SMTP server does not support authentication.
        /// </exception>
        /// <exception cref="System.OperationCanceledException">
        /// The operation was canceled via the cancellation token.
        /// </exception>
        /// <exception cref="System.Security.Authentication.AuthenticationException">
        /// Authentication using the supplied credentials has failed.
        /// </exception>
        /// <exception cref="MailKit.Security.SaslException">
        /// A SASL authentication error occurred.
        /// </exception>
        /// <exception cref="System.IO.IOException">
        /// An I/O error occurred.
        /// </exception>
        /// <exception cref="SmtpCommandException">
        /// The SMTP command failed.
        /// </exception>
        /// <exception cref="SmtpProtocolException">
        /// An SMTP protocol error occurred.
        /// </exception>
        public void Authenticate(ICredentials credentials, CancellationToken cancellationToken)
        {
            if (!IsConnected)
            {
                throw new InvalidOperationException("The SmtpClient must be connected before you can authenticate.");
            }

            if (authenticated)
            {
                throw new InvalidOperationException("The SmtpClient is already authenticated.");
            }

            if ((Capabilities & SmtpCapabilities.Authentication) == 0)
            {
                throw new NotSupportedException("The SMTP server does not support authentication.");
            }

            if (credentials == null)
            {
                throw new ArgumentNullException("credentials");
            }

            var          uri = new Uri("smtp://" + host);
            SmtpResponse response;
            string       challenge;
            string       command;

            foreach (var authmech in SaslMechanism.AuthMechanismRank)
            {
                if (!AuthenticationMechanisms.Contains(authmech))
                {
                    continue;
                }

                var sasl = SaslMechanism.Create(authmech, uri, credentials);

                cancellationToken.ThrowIfCancellationRequested();

                // send an initial challenge if the mechanism supports it
                if ((challenge = sasl.Challenge(null)) != null)
                {
                    command = string.Format("AUTH {0} {1}", authmech, challenge);
                }
                else
                {
                    command = string.Format("AUTH {0}", authmech);
                }

                response = SendCommand(command, cancellationToken);

                if (response.StatusCode == SmtpStatusCode.AuthenticationMechanismTooWeak)
                {
                    continue;
                }

                while (!sasl.IsAuthenticated)
                {
                    if (response.StatusCode != SmtpStatusCode.AuthenticationChallenge)
                    {
                        throw new SmtpCommandException(SmtpErrorCode.UnexpectedStatusCode, response.StatusCode, response.Response);
                    }

                    challenge = sasl.Challenge(response.Response);
                    response  = SendCommand(challenge, cancellationToken);
                }

                if (response.StatusCode == SmtpStatusCode.AuthenticationSuccessful)
                {
                    Ehlo(cancellationToken);
                    authenticated = true;
                    return;
                }

                throw new AuthenticationException();
            }

            throw new NotSupportedException("No compatible authentication mechanisms found.");
        }