private ImapCommandResult PostProcessTransaction(IImapTransaction t) { lastTransactionResult = t.Result; switch (t.Result.Code) { /* * disconnect without processing responses */ case ImapCommandResultCode.InternalError: CloseConnection(); throw new ImapException(t.Result.Description, t.Result.Exception); case ImapCommandResultCode.SocketTimeout: CloseConnection(); throw new TimeoutException(string.Format("socket timeout in {0}", t.GetType().FullName), t.Result.Exception); case ImapCommandResultCode.ConnectionError: case ImapCommandResultCode.UpgradeError: CloseConnection(); throw t.Result.Exception; } ProcessUpdatedSizeAndStatusResponse(t.Result); if (t.Result.Code == ImapCommandResultCode.Bye) { TransitStateTo(ImapSessionState.NotAuthenticated); CloseConnection(); } return t.Result; }
public static void Log(IImapTransaction transaction, string format, params object[] args) { Verbose("CID:{0} {1}: {2}", transaction.Connection.Id, transaction.GetType().Name.Replace("Transaction", string.Empty), args == null ? format : string.Format(format, args)); }
private IAsyncResult BeginProcessTransaction(IImapTransaction t, bool exceptionIfIncapable) { PreProcessTransaction(t, exceptionIfIncapable); var processTransaction = new ProcessTransactionDelegate(ProcessTransactionInternal); return new TransactionAsyncResult(t, processTransaction.BeginInvoke(t, null, null)); }
public static void LogRequest(IImapTransaction transaction) { var args = new StringBuilder(); foreach (var p in transaction.RequestArguments) { var val = (p.Value == null) ? string.Empty : p.Value.ToString(); if (0x100 < val.Length) val = val.Substring(0, 0x100) + " ..."; args.AppendFormat("'{0}'=>'{1}'; ", p.Key, val); } Log(transaction, args.ToString(), null); }
private ImapCommandResult AuthenticateInternal(IImapTransaction t, string username, ImapAuthenticationMechanism authenticationMechanism, bool reissueCapability) { var result = ProcessTransaction(t); var refferalResponseCode = result.GetResponseCode(ImapResponseCode.Referral); if (refferalResponseCode != null) { // RFC 2221 IMAP4 Login Referrals // http://tools.ietf.org/html/rfc2221 // 4.1. LOGIN and AUTHENTICATE Referrals // An IMAP4 server MAY respond to a LOGIN or AUTHENTICATE command with a // home server referral if it wishes to direct the user to another IMAP4 // server. var referToUri = ImapResponseTextConverter.FromReferral(refferalResponseCode.ResponseText)[0]; if (handlesReferralAsException) { throw new ImapLoginReferralException(string.Format("try another server: '{0}'", refferalResponseCode.ResponseText.Text), referToUri); } else { Trace.Info("login referral: '{0}'", refferalResponseCode.ResponseText.Text); if (result.Succeeded) Trace.Info(" another server available at {0}", referToUri); else Trace.Info(" try to connect to {0}", referToUri); } } if (result.Succeeded) { UpdateAuthority(username, authenticationMechanism); TransitStateTo(ImapSessionState.Authenticated); // 6.2.2. AUTHENTICATE Command // A server MAY include a CAPABILITY response code in the tagged OK // response of a successful AUTHENTICATE command in order to send // capabilities automatically. // 6.2.3. LOGIN Command // A server MAY include a CAPABILITY response code in the tagged OK // response to a successful LOGIN command in order to send // capabilities automatically. It is unnecessary for a client to // send a separate CAPABILITY command if it recognizes these // automatic capabilities. var capabilityResponseCode = result.GetResponseCode(ImapResponseCode.Capability); if (capabilityResponseCode == null) { var capability = result.GetResponse(ImapDataResponseType.Capability); if (capability != null) { SetServerCapabilities(ImapDataResponseConverter.FromCapability(capability)); reissueCapability = false; } } else { SetServerCapabilities(ImapResponseTextConverter.FromCapability(capabilityResponseCode.ResponseText)); reissueCapability = false; } } else { return result; } if (reissueCapability) Capability(); return result; }
public static void LogResponse(IImapTransaction transaction) { Log(transaction, "{0} {1}", transaction.Result.Code, transaction.Result.ResultText); }
public TransactionAsyncResult(IImapTransaction transaction, IAsyncResult processTransactionAsyncResult) { this.transaction = transaction; this.processTransactionAsyncResult = processTransactionAsyncResult; }
private IImapTransaction ProcessTransactionInternal(IImapTransaction t) { lock (transactionLockObject) { Trace.LogRequest(t); if (t is IdleTransaction) TraceInfo("idling"); t.Process(); if (t is IdleTransaction) TraceInfo("done"); Trace.LogResponse(t); return t; } }
private ImapCommandResult ProcessTransaction(IImapTransaction t) { if (transactionTimeout == Timeout.Infinite) { // no timeout PreProcessTransaction(t, handlesIncapableAsException); ProcessTransactionInternal(t); return PostProcessTransaction(t); } else { var async = BeginProcessTransaction(t, handlesIncapableAsException); if (async.AsyncWaitHandle.WaitOne(transactionTimeout, false)) { return EndProcessTransaction(async); } else { CloseConnection(); throw new TimeoutException(string.Format("transaction timeout ({0})", t.GetType().FullName)); } } }
private void PreProcessTransaction(IImapTransaction t, bool exceptionIfIncapable) { // TODO: '5.5. Multiple Commands in Progress' // The following are examples of valid non-waiting command sequences: // FETCH + STORE + SEARCH + CHECK // STORE + COPY + EXPUNGE if (IsTransactionProceeding) throw new InvalidOperationException("another transaction proceesing"); RejectIdling(); // check and set literal options var isNonSyncLiteralCapable = serverCapabilities.Has(ImapCapability.LiteralNonSync); var isLiteral8Capable = serverCapabilities.Has(ImapCapability.Binary); var containsNonSyncLiteral = false; var containsLiteral8 = false; TraverseTransactionRequestArgumentLiterals(t.RequestArguments, delegate(IImapLiteralString literal) { var syncMode = literal.Options & ImapLiteralOptions.SynchronizationMode; var literalMode = literal.Options & ImapLiteralOptions.LiteralMode; switch (syncMode) { case ImapLiteralOptions.NonSynchronizingIfCapable: syncMode = isNonSyncLiteralCapable ? ImapLiteralOptions.NonSynchronizing : ImapLiteralOptions.Synchronizing; break; case ImapLiteralOptions.NonSynchronizing: containsNonSyncLiteral = true; break; } switch (literalMode) { case ImapLiteralOptions.Literal8IfCapable: literalMode = isLiteral8Capable ? ImapLiteralOptions.Literal8 : ImapLiteralOptions.Literal; break; case ImapLiteralOptions.Literal8: containsLiteral8 = true; break; } literal.Options = (syncMode | literalMode) | (literal.Options & ~(ImapLiteralOptions.SynchronizationMode | ImapLiteralOptions.LiteralMode)); }); // check capability if (!exceptionIfIncapable) return; if (!serverCapabilities.Has(Imap4.ImapCapability.Imap4Rev1) && !(t is CapabilityTransaction)) throw new ImapIncapableException(ImapCapability.Imap4Rev1); if (containsNonSyncLiteral && !isNonSyncLiteralCapable) throw new ImapIncapableException(ImapCapability.LiteralNonSync); if (containsLiteral8 && !isLiteral8Capable) throw new ImapIncapableException(ImapCapability.Binary); CheckServerCapability(t as IImapExtension); CheckServerCapability(t as IImapMultipleExtension); foreach (var arg in t.RequestArguments.Values) { CheckServerCapability(arg as IImapExtension); CheckServerCapability(arg as IImapMultipleExtension); } }