public static ImapSession CreateSession(IImapSessionProfile profile,
                                            SaslClientMechanism authMechanismSpecified,
                                            UpgradeConnectionStreamCallback createSslStreamCallback)
        {
            ImapSession session;

              var result = CreateSession(profile, authMechanismSpecified, createSslStreamCallback, out session);

              if (result.Succeeded)
            return session;
              else
            throw new ImapAuthenticationException(result);
        }
        internal static ImapSession CreateSession(IImapSessionProfile profile)
        {
            try {
            ImapSession session = null;

            var result = ImapSessionCreator.CreateSession(profile, null, createSslStreamCallback, out session);

            if (result.Failed)
              throw new WebException(result.ResultText, null, WebExceptionStatus.ProtocolError, new ImapWebResponse(result));

            // update server info
            if (session.ServerCapabilities.Has(ImapCapability.Namespace))
              session.Namespace();

            if (session.ServerCapabilities.Has(ImapCapability.ID))
              session.ID(ImapWebRequestDefaults.ClientID);

            return session;
              }
              catch (ImapSecureConnectionException ex) {
            throw new WebException(ex.Message, ex.InnerException, WebExceptionStatus.SecureChannelFailure, null);
              }
              catch (ImapConnectionException ex) {
            throw new WebException("connection error", ex, WebExceptionStatus.ConnectFailure, null);
              }
              catch (ImapIncapableException ex) {
            throw new WebException(ex.Message, ex, WebExceptionStatus.RequestCanceled, null);
              }
              catch (ImapException ex) {
            if (ex.InnerException == null)
              throw new WebException(ex.Message, ex, WebExceptionStatus.RequestCanceled, null);
            else
              throw new WebException("internal error", ex, WebExceptionStatus.UnknownError, null);
              }
              catch (TimeoutException ex) {
            throw new WebException("timed out", ex, WebExceptionStatus.Timeout, null);
              }
              catch (WebException ex) {
            throw ex;
              }
        }
        public static ImapCommandResult CreateSession(IImapSessionProfile profile,
                                                  SaslClientMechanism authMechanismSpecified,
                                                  UpgradeConnectionStreamCallback createSslStreamCallback,
                                                  out ImapSession session)
        {
            if (profile == null)
            throw new ArgumentNullException("profile");

              var authority = profile.Authority;
              var securePort = string.Equals(authority.Scheme, ImapUri.UriSchemeImaps, StringComparison.OrdinalIgnoreCase);

              if (securePort && createSslStreamCallback == null)
            throw new ArgumentNullException("createSslStreamCallback");

              ImapCommandResult result;
              session = null;

              session = new ImapSession(authority.Host,
                                authority.Port,
                                true,
                                profile.Timeout,
                                securePort
                                  ? createSslStreamCallback
                                  : null);

              session.HandlesIncapableAsException = false;
              session.HandlesReferralAsException = false;
              session.TransactionTimeout  = profile.Timeout;
              session.SendTimeout         = profile.SendTimeout;
              session.ReceiveTimeout      = profile.ReceiveTimeout;

              if (session.ServerCapabilities.Count == 0)
            // try querying server capability (ignore error)
            session.Capability();

              if (!session.ServerCapabilities.Has(ImapCapability.Imap4Rev1))
            throw new ImapIncapableException(ImapCapability.Imap4Rev1);

              if (profile.UseTlsIfAvailable && session.ServerCapabilities.Has(ImapCapability.StartTls) && !session.IsSecureConnection) {
            var r = session.StartTls(createSslStreamCallback, true);

            if (r.Failed)
              throw new ImapSecureConnectionException(r.ResultText);
            else if (!session.ServerCapabilities.Has(ImapCapability.Imap4Rev1))
              throw new ImapIncapableException(ImapCapability.Imap4Rev1);
              }

              if (profile.UseDeflateIfAvailable && session.ServerCapabilities.Has(ImapCapability.CompressDeflate)) {
            var r = session.Compress(ImapCompressionMechanism.Deflate);

            if (r.Failed)
              throw new WebException(r.ResultText, null, WebExceptionStatus.RequestCanceled, null);
              }

              if (authMechanismSpecified == null)
            result = Authenticate(session, profile);
              else
            result = session.Authenticate(authMechanismSpecified);

              if (result == null) {
            throw new ImapAuthenticationException("appropriate authentication mechanism not found");
              }
              else if (result.Failed) {
            try {
              try {
            session.Disconnect(false);
              }
              catch (ImapConnectionException) {
            // ignore
              }
            }
            finally {
              session = null;
            }
              }

              return result;
        }
        private static ImapCommandResult Authenticate(ImapSession session, IImapSessionProfile profile)
        {
            var authority = profile.Authority;
              var username = ImapStyleUriParser.GetUser(authority);
              var authMechanism = ImapStyleUriParser.GetAuthType(authority);

              /*
               * http://tools.ietf.org/html/rfc5092
               * 3.2. IMAP User Name and Authentication Mechanism
               *
               *    An authentication mechanism (as used by the IMAP AUTHENTICATE
               *    command) can be expressed by adding ";AUTH=<enc-auth-type>" to the
               *    end of the user name in an IMAP URL.  When such an <enc-auth-type> is
               *    indicated, the client SHOULD request appropriate credentials from
               *    that mechanism and use the "AUTHENTICATE" command instead of the
               *    "LOGIN" command.  If no user name is specified, one MUST be obtained
               *    from the mechanism or requested from the user/configuration as
               *    appropriate.
               *
               *    If a user name is included with no authentication mechanism, then
               *    ";AUTH=*" is assumed.
               */

              // TODO: URLAUTH
              /*
              if (!session.ServerCapabilities.Has(ImapCapability.UrlAuth)
            throw new ImapWebException("URLAUTH incapable", WebExceptionStatus.ProtocolError);
              */
              var canFallback = false;

              if (authMechanism == null) {
            if (string.IsNullOrEmpty(username)) {
              authMechanism = ImapAuthenticationMechanism.Anonymous;
              canFallback = true;
            }
            else {
              authMechanism = ImapAuthenticationMechanism.SelectAppropriate;
            }
              }

              if (authMechanism == ImapAuthenticationMechanism.SelectAppropriate) {
            var allowPlainTextMechanism = session.IsSecureConnection || profile.AllowInsecureLogin;

            return AuthenticateWithAppropriateMechanism(session,
                                                    allowPlainTextMechanism,
                                                    profile.Credentials,
                                                    username,
                                                    GetUsingSaslMechanisms(profile.UsingSaslMechanisms ?? new string[0]));
              }
              else if (authMechanism == ImapAuthenticationMechanism.Anonymous) {
            return AuthenticateAsAnonymous(session,
                                       username,
                                       canFallback);
              }
              else {
            return AuthenticateWithSuppliedMechanism(session,
                                                 profile.Credentials,
                                                 username,
                                                 authMechanism);
              }
        }