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; }
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); }
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)); }
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; }
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; } } }
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); } }
public cResponseTextCodeParserSelect(cCapabilities pCapabilities) { mCapabilities = pCapabilities ?? throw new ArgumentNullException(nameof(pCapabilities)); }