Exemplo n.º 1
0
 public cCommandHookSelect(cMailboxCache pMailboxCache, cCapabilities pCapabilities, iMailboxHandle pMailboxHandle, bool pForUpdate)
 {
     mMailboxCache  = pMailboxCache ?? throw new ArgumentNullException(nameof(pMailboxCache));
     mCapabilities  = pCapabilities ?? throw new ArgumentNullException(nameof(pCapabilities));
     mMailboxHandle = pMailboxHandle ?? throw new ArgumentNullException(nameof(pMailboxHandle));
     mForUpdate     = pForUpdate;
 }
Exemplo n.º 2
0
            private void ZSetCapabilities(cStrings pCapabilities, cStrings pAuthenticationMechanisms, cTrace.cContext pParentContext)
            {
                var lContext = pParentContext.NewMethod(nameof(cSession), nameof(ZSetCapabilities), pCapabilities, pAuthenticationMechanisms);

                _Capabilities = new cCapabilities(pCapabilities, pAuthenticationMechanisms, mIgnoreCapabilities);
                mPipeline.SetCapabilities(_Capabilities, lContext);
                mSynchroniser.InvokePropertyChanged(nameof(cIMAPClient.Capabilities), lContext);
            }
Exemplo n.º 3
0
 public cMailboxCache(cCallbackSynchroniser pSynchroniser, fMailboxCacheDataItems pMailboxCacheDataItems, cCommandPartFactory pCommandPartFactory, cCapabilities pCapabilities, Action <eConnectionState, cTrace.cContext> pSetState)
 {
     mSynchroniser          = pSynchroniser ?? throw new ArgumentNullException(nameof(pSynchroniser));
     mMailboxCacheDataItems = pMailboxCacheDataItems;
     mCommandPartFactory    = pCommandPartFactory ?? throw new ArgumentNullException(nameof(pCommandPartFactory));
     mCapabilities          = pCapabilities ?? throw new ArgumentNullException(nameof(pCapabilities));
     mSetState = pSetState ?? throw new ArgumentNullException(nameof(pSetState));
 }
Exemplo n.º 4
0
                public void SetCapabilities(cCapabilities pCapabilities, cTrace.cContext pParentContext)
                {
                    var lContext = pParentContext.NewMethod(nameof(cCommandPipeline), nameof(SetCapabilities));

                    if (mDisposed)
                    {
                        throw new ObjectDisposedException(nameof(cCommandPipeline));
                    }
                    if (mState != eState.connected)
                    {
                        throw new InvalidOperationException(kInvalidOperationExceptionMessage.NotConnected);
                    }
                    if (pCapabilities == null)
                    {
                        throw new ArgumentNullException(nameof(pCapabilities));
                    }

                    mLiteralPlus  = pCapabilities.LiteralPlus;
                    mLiteralMinus = pCapabilities.LiteralMinus;
                }
Exemplo n.º 5
0
        private async Task ZConnectAsync(cTrace.cContext pParentContext)
        {
            var lContext = mRootContext.NewMethod(nameof(cIMAPClient), nameof(ZConnectAsync));

            if (mDisposed)
            {
                throw new ObjectDisposedException(nameof(cIMAPClient));
            }

            cServer      lServer      = Server;
            cCredentials lCredentials = Credentials;

            if (lServer == null)
            {
                throw new InvalidOperationException("connect requires server to be set");
            }
            if (lCredentials == null)
            {
                throw new InvalidOperationException("connect requires credentials to be set");
            }

            bool lSessionReplaced;

            if (mSession == null)
            {
                lSessionReplaced = false;
            }
            else
            {
                if (!mSession.IsUnconnected)
                {
                    throw new InvalidOperationException(kInvalidOperationExceptionMessage.NotUnconnected);
                }
                mSession.Dispose();

                lSessionReplaced = true;

                mNamespaces = null;

                mInbox = null;
                mSynchroniser.InvokePropertyChanged(nameof(Inbox), lContext);
            }

            // initialise the SASLs
            foreach (var lSASL in lCredentials.SASLs)
            {
                lSASL.LastAuthentication = null;
            }

            mSession = new cSession(mSynchroniser, mIgnoreCapabilities, mMailboxCacheDataItems, mNetworkWriteConfiguration, mIdleConfiguration, mFetchCacheItemsConfiguration, mFetchBodyReadConfiguration, mEncoding, lContext);
            var lSession = mSession;

            if (lSessionReplaced)
            {
                mSynchroniser.InvokePropertyChanged(nameof(Capabilities), lContext);
                mSynchroniser.InvokePropertyChanged(nameof(ConnectionState), lContext);
                mSynchroniser.InvokePropertyChanged(nameof(IsConnected), lContext);
                mSynchroniser.InvokePropertyChanged(nameof(IsUnconnected), lContext);
                mSynchroniser.InvokePropertyChanged(nameof(ConnectedAccountId), lContext);
                mSynchroniser.InvokePropertyChanged(nameof(EnabledExtensions), lContext);
                mSynchroniser.InvokePropertyChanged(nameof(HomeServerReferral), lContext);
                mSynchroniser.InvokePropertyChanged(nameof(ServerId), lContext);
                mSynchroniser.InvokePropertyChanged(nameof(Namespaces), lContext);
                mSynchroniser.InvokePropertyChanged(nameof(SelectedMailbox), lContext);
                mSynchroniser.InvokePropertyChanged(nameof(SelectedMailboxDetails), lContext);
            }

            using (var lToken = mCancellationManager.GetToken(lContext))
            {
                var lMC = new cMethodControl(mTimeout, lToken.CancellationToken);

                try
                {
                    await lSession.ConnectAsync(lMC, lServer, lContext).ConfigureAwait(false);

                    if (lSession.Capabilities == null)
                    {
                        await lSession.CapabilityAsync(lMC, lContext).ConfigureAwait(false);
                    }

                    if (lSession.ConnectionState == eConnectionState.notauthenticated && !lSession.TLSInstalled && lSession.Capabilities.StartTLS)
                    {
                        await lSession.StartTLSAsync(lMC, lContext).ConfigureAwait(false);

                        await lSession.CapabilityAsync(lMC, lContext).ConfigureAwait(false);
                    }

                    object        lOriginalCapabilities = lSession.Capabilities;
                    cCapabilities lCurrentCapabilities  = lSession.Capabilities;

                    if (lSession.ConnectionState == eConnectionState.notauthenticated)
                    {
                        bool      lTLSIssue              = false;
                        bool      lTriedCredentials      = false;
                        Exception lAuthenticateException = null;

                        cAccountId lAccountId = new cAccountId(lServer.Host, lCredentials.Type, lCredentials.UserId);

                        bool lTLSInstalled = lSession.TLSInstalled;

                        if (lCredentials.TryAllSASLs)
                        {
                            foreach (var lSASL in lCredentials.SASLs)
                            {
                                if ((lSASL.TLSRequirement == eTLSRequirement.required && !lTLSInstalled) || (lSASL.TLSRequirement == eTLSRequirement.disallowed && lTLSInstalled))
                                {
                                    lTLSIssue = true;
                                }
                                else
                                {
                                    lTriedCredentials      = true;
                                    lAuthenticateException = await lSession.AuthenticateAsync(lMC, lAccountId, lSASL, lContext).ConfigureAwait(false);

                                    if (lSession.ConnectionState != eConnectionState.notauthenticated || lAuthenticateException != null)
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                        else
                        {
                            foreach (var lSASL in lCredentials.SASLs)
                            {
                                if (lCurrentCapabilities.AuthenticationMechanisms.Contains(lSASL.MechanismName)) // no case-invariance required because SASL (rfc 2222) says only uppercase is allowed
                                {
                                    if ((lSASL.TLSRequirement == eTLSRequirement.required && !lTLSInstalled) || (lSASL.TLSRequirement == eTLSRequirement.disallowed && lTLSInstalled))
                                    {
                                        lTLSIssue = true;
                                    }
                                    else
                                    {
                                        lTriedCredentials      = true;
                                        lAuthenticateException = await lSession.AuthenticateAsync(lMC, lAccountId, lSASL, lContext).ConfigureAwait(false);

                                        if (lSession.ConnectionState != eConnectionState.notauthenticated || lAuthenticateException != null)
                                        {
                                            break;
                                        }
                                    }
                                }
                            }
                        }

                        if (lSession.ConnectionState == eConnectionState.notauthenticated && lAuthenticateException == null && !lCurrentCapabilities.LoginDisabled && lCredentials.Login != null)
                        {
                            if ((lCredentials.Login.TLSRequirement == eTLSRequirement.required && !lTLSInstalled) || (lCredentials.Login.TLSRequirement == eTLSRequirement.disallowed && lTLSInstalled))
                            {
                                lTLSIssue = true;
                            }
                            else
                            {
                                lTriedCredentials      = true;
                                lAuthenticateException = await lSession.LoginAsync(lMC, lAccountId, lCredentials.Login, lContext).ConfigureAwait(false);
                            }
                        }

                        if (lSession.ConnectionState != eConnectionState.authenticated)
                        {
                            lContext.TraceError("could not authenticate");

                            // log out
                            await lSession.LogoutAsync(lMC, lContext).ConfigureAwait(false);

                            // throw an exception that indicates why we couldn't connect

                            if (lTriedCredentials)
                            {
                                if (lAuthenticateException != null)
                                {
                                    throw lAuthenticateException;
                                }
                                throw new cCredentialsException(lContext);
                            }

                            throw new cAuthenticationMechanismsException(lTLSIssue, lContext); // the server has no mechanisms that we can try
                        }

                        // re-get the capabilities if we didn't get new ones as part of the authentication/ login OR if a security layer was installed (SASL requires this)
                        if (ReferenceEquals(lOriginalCapabilities, lSession.Capabilities) || lSession.SASLSecurityInstalled)
                        {
                            await lSession.CapabilityAsync(lMC, lContext).ConfigureAwait(false);
                        }
                        lCurrentCapabilities = lSession.Capabilities;
                    }

                    if (lCurrentCapabilities.Enable)
                    {
                        fEnableableExtensions lExtensions = fEnableableExtensions.none;
                        if (lCurrentCapabilities.UTF8Accept || lCurrentCapabilities.UTF8Only)
                        {
                            lExtensions = lExtensions | fEnableableExtensions.utf8;
                        }
                        if (lExtensions != fEnableableExtensions.none)
                        {
                            await lSession.EnableAsync(lMC, lExtensions, lContext).ConfigureAwait(false);
                        }
                    }

                    // enabled (lock in the capabilities and enabled extensions)
                    lSession.SetEnabled(lContext);

                    Task lIdTask;

                    if (lCurrentCapabilities.Id)
                    {
                        cId lClientId;

                        if ((lSession.EnabledExtensions & fEnableableExtensions.utf8) == 0)
                        {
                            lClientId = mClientId;
                        }
                        else
                        {
                            lClientId = mClientIdUTF8 ?? mClientId;
                        }

                        lIdTask = lSession.IdAsync(lMC, lClientId, lContext);
                    }
                    else
                    {
                        lIdTask = null;
                    }

                    if (lCurrentCapabilities.Namespace)
                    {
                        await lSession.NamespaceAsync(lMC, lContext).ConfigureAwait(false);

                        var lPersonalNamespaceNames = lSession.NamespaceNames?.Personal;

                        if (lPersonalNamespaceNames != null)
                        {
                            foreach (var lName in lPersonalNamespaceNames)
                            {
                                // special case, where the personal namespace is "INBOX/" (where "/" is the delimiter)
                                if (lName.Delimiter != null && lName.Prefix.Equals(cMailboxName.InboxString + lName.Delimiter, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    mInbox = new cMailbox(this, lSession.GetMailboxHandle(new cMailboxName(cMailboxName.InboxString, lName.Delimiter)));
                                    mSynchroniser.InvokePropertyChanged(nameof(Inbox), lContext);
                                    break;
                                }

                                cMailboxPathPattern lPattern = new cMailboxPathPattern(lName.Prefix, "%", lName.Delimiter);

                                if (lPattern.Matches(cMailboxName.InboxString))
                                {
                                    mInbox = new cMailbox(this, lSession.GetMailboxHandle(new cMailboxName(cMailboxName.InboxString, lName.Delimiter)));
                                    mSynchroniser.InvokePropertyChanged(nameof(Inbox), lContext);
                                    break;
                                }
                            }
                        }
                    }

                    if (mInbox == null)
                    {
                        var lDelimiter = await lSession.ListDelimiterAsync(lMC, lContext).ConfigureAwait(false);

                        if (!lCurrentCapabilities.Namespace)
                        {
                            mNamespaces = new cNamespaces(this, new cNamespaceName[] { new cNamespaceName("", lDelimiter) }, null, null);
                            mSynchroniser.InvokePropertyChanged(nameof(Namespaces), lContext);
                        }

                        mInbox = new cMailbox(this, lSession.GetMailboxHandle(new cMailboxName(cMailboxName.InboxString, lDelimiter)));
                        mSynchroniser.InvokePropertyChanged(nameof(Inbox), lContext);
                    }

                    // wait for id to complete
                    if (lIdTask != null)
                    {
                        await lIdTask.ConfigureAwait(false);
                    }

                    // initialised (namespaces set, inbox available, id available (if server supports it); user may now issue commands)
                    lSession.SetInitialised(lContext);
                }
                catch when(lSession.ConnectionState != eConnectionState.disconnected)
                {
                    lSession.Disconnect(lContext);
                    throw;
                }
            }
        }
Exemplo n.º 6
0
        private static void _Tests_Capability(cTrace.cContext pParentContext)
        {
            var lContext = pParentContext.NewMethod(nameof(cBytesCursor), nameof(_Tests_Capability));

            cBytesCursor  lCursor;
            cCapabilities lCapabilities;
            cStrings      lCapabilityList;
            cStrings      lAuthenticationMechanisms;

            lCursor = new cBytesCursor("auth=angus auth=fred charlie bob");
            if (lCursor.ProcessCapability(out _, out _, lContext))
            {
                throw new cTestsException("should have failed", lContext);
            }
            if (!lCursor.Position.AtEnd)
            {
                throw new cTestsException("should have read entire response", lContext);
            }

            lCursor = new cBytesCursor("auth=angus auth=fred imap4rev1 charlie bob");
            if (!lCursor.ProcessCapability(out lCapabilityList, out lAuthenticationMechanisms, lContext))
            {
                throw new cTestsException("should have succeeded", lContext);
            }
            if (!lCursor.Position.AtEnd)
            {
                throw new cTestsException("should have read entire response", lContext);
            }
            if (lAuthenticationMechanisms.Count != 2 || !lAuthenticationMechanisms.Contains("angus") || !lAuthenticationMechanisms.Contains("fred"))
            {
                throw new cTestsException("authenticatemechanismnames not as expected", lContext);
            }
            if (lCapabilityList.Count != 3)
            {
                throw new cTestsException("capabilities not as expected", lContext);
            }

            lCursor = new cBytesCursor("auth=angus idle auth=fred literal- imap4rev1 charlie utf8=accept bob");
            if (!lCursor.ProcessCapability(out lCapabilityList, out lAuthenticationMechanisms, lContext))
            {
                throw new cTestsException("should have succeeded", lContext);
            }
            if (!lCursor.Position.AtEnd)
            {
                throw new cTestsException("should have read entire response", lContext);
            }
            if (lAuthenticationMechanisms.Count != 2 || !lAuthenticationMechanisms.Contains("angus") || !lAuthenticationMechanisms.Contains("fred"))
            {
                throw new cTestsException("authenticatemechanismnames not as expected", lContext);
            }
            if (lCapabilityList.Count != 6)
            {
                throw new cTestsException("capabilities not as expected", lContext);
            }

            lCapabilities = new cCapabilities(lCapabilityList, lAuthenticationMechanisms, 0);
            if (lCapabilities.LoginDisabled || !lCapabilities.Idle || lCapabilities.LiteralPlus || !lCapabilities.LiteralMinus || lCapabilities.Enable || !lCapabilities.UTF8Accept)
            {
                throw new cTestsException("properties not as expected", lContext);
            }
            //if (!lAuthenticationMechanisms.Contains("ANGUS") || !lAuthenticationMechanisms.Contains("FRED") || lAuthenticationMechanisms.Contains("fr€d")) throw new cTestsException("properties not as expected", lContext);

            lCapabilities = new cCapabilities(lCapabilityList, lAuthenticationMechanisms, fCapabilities.idle | fCapabilities.literalminus);
            if (lCapabilities.LoginDisabled || lCapabilities.Idle || lCapabilities.LiteralPlus || lCapabilities.LiteralMinus || lCapabilities.Enable || !lCapabilities.UTF8Accept)
            {
                throw new cTestsException("properties not as expected", lContext);
            }

            lCursor = new cBytesCursor("auth=angus idle auth=(fred literal- imap4rev1 charlie utf8=accept bob");
            if (lCursor.ProcessCapability(out _, out _, lContext))
            {
                throw new cTestsException("should have failed", lContext);
            }
            if (lCursor.Position.AtEnd)
            {
                throw new cTestsException("should not have read entire response", lContext);
            }

            lCursor = new cBytesCursor("auth=angus idle auth=fred )literal- imap4rev1 charlie utf8=accept bob");
            if (lCursor.ProcessCapability(out _, out _, lContext))
            {
                throw new cTestsException("should have failed", lContext);
            }
            if (lCursor.Position.AtEnd)
            {
                throw new cTestsException("should not have read entire response", lContext);
            }

            lCursor = new cBytesCursor("auth=angus idle auth=fred literal- imap4rev1 charlie utf8=accept bob) and there is more");
            if (!lCursor.ProcessCapability(out _, out _, lContext))
            {
                throw new cTestsException("should have succeeded", lContext);
            }
            if (lCursor.GetRestAsString() != ") and there is more")
            {
                throw new cTestsException("should have stopped at the )", lContext);
            }
        }
Exemplo n.º 7
0
 public cResponseTextCodeParserSelect(cCapabilities pCapabilities)
 {
     mCapabilities = pCapabilities ?? throw new ArgumentNullException(nameof(pCapabilities));
 }