/// <summary> /// Asynchronously stores flags for a set of messages. The mailbox that the messages are in must be selected. /// </summary> /// <param name="pMessages"></param> /// <param name="pOperation">The type of store operation.</param> /// <param name="pFlags"></param> /// <param name="pIfUnchangedSinceModSeq"></param> /// <inheritdoc cref="Store(IEnumerable{cMessage}, eStoreOperation, cStorableFlags, ulong?)" select="returns|remarks"/> public async Task <cStoreFeedback> StoreAsync(IEnumerable <cMessage> pMessages, eStoreOperation pOperation, cStorableFlags pFlags, ulong?pIfUnchangedSinceModSeq = null) { var lContext = mRootContext.NewMethodV(nameof(cIMAPClient), nameof(StoreAsync), 3); var lFeedback = new cStoreFeedback(pMessages, pOperation, pFlags); await ZStoreAsync(lFeedback, pOperation, pFlags, pIfUnchangedSinceModSeq, lContext).ConfigureAwait(false); return(lFeedback); }
internal async Task <cStoreFeedback> StoreAsync(iMessageHandle pMessageHandle, eStoreOperation pOperation, cStorableFlags pFlags, ulong?pIfUnchangedSinceModSeq) { var lContext = mRootContext.NewMethodV(nameof(cIMAPClient), nameof(StoreAsync), 1); var lFeedback = new cStoreFeedback(pMessageHandle, pOperation, pFlags); await ZStoreAsync(lFeedback, pOperation, pFlags, pIfUnchangedSinceModSeq, lContext).ConfigureAwait(false); return(lFeedback); }
/// <summary> /// Stores flags for a set of messages. The mailbox that the messages are in must be selected. /// </summary> /// <param name="pMessages"></param> /// <param name="pOperation">The type of store operation.</param> /// <param name="pFlags"></param> /// <param name="pIfUnchangedSinceModSeq"></param> /// <returns>Feedback on the success (or otherwise) of the store.</returns> /// <remarks> /// <paramref name="pIfUnchangedSinceModSeq"/> may only be specified if the containing mailbox's <see cref="cMailbox.HighestModSeq"/> is not zero. /// (i.e. <see cref="cCapabilities.CondStore"/> is in use and the mailbox supports the persistent storage of mod-sequences.) /// If a message has been modified since the specified value then the server will fail the store for that message. /// </remarks> public cStoreFeedback Store(IEnumerable <cMessage> pMessages, eStoreOperation pOperation, cStorableFlags pFlags, ulong?pIfUnchangedSinceModSeq = null) { var lContext = mRootContext.NewMethodV(nameof(cIMAPClient), nameof(Store), 3); var lFeedback = new cStoreFeedback(pMessages, pOperation, pFlags); var lTask = ZStoreAsync(lFeedback, pOperation, pFlags, pIfUnchangedSinceModSeq, lContext); mSynchroniser.Wait(lTask, lContext); return(lFeedback); }
internal cStoreFeedback Store(iMessageHandle pMessageHandle, eStoreOperation pOperation, cStorableFlags pFlags, ulong?pIfUnchangedSinceModSeq) { var lContext = mRootContext.NewMethodV(nameof(cIMAPClient), nameof(Store), 1); var lFeedback = new cStoreFeedback(pMessageHandle, pOperation, pFlags); var lTask = ZStoreAsync(lFeedback, pOperation, pFlags, pIfUnchangedSinceModSeq, lContext); mSynchroniser.Wait(lTask, lContext); return(lFeedback); }
public async Task StoreAsync(cMethodControl pMC, cStoreFeedback pFeedback, eStoreOperation pOperation, cStorableFlags pFlags, ulong?pIfUnchangedSinceModSeq, cTrace.cContext pParentContext) { var lContext = pParentContext.NewMethod(nameof(cSession), nameof(StoreAsync), pMC, pFeedback, pOperation, pFlags, pIfUnchangedSinceModSeq); if (mDisposed) { throw new ObjectDisposedException(nameof(cSession)); } if (_ConnectionState != eConnectionState.selected) { throw new InvalidOperationException(kInvalidOperationExceptionMessage.NotSelected); } if (pFeedback == null) { throw new ArgumentNullException(nameof(pFeedback)); } if (pFlags == null) { throw new ArgumentNullException(nameof(pFlags)); } if (pFeedback.Count == 0) { throw new ArgumentOutOfRangeException(nameof(pFeedback)); } if (pIfUnchangedSinceModSeq == 0) { throw new ArgumentOutOfRangeException(nameof(pIfUnchangedSinceModSeq)); } if (pIfUnchangedSinceModSeq != null && !_Capabilities.CondStore) { throw new InvalidOperationException(kInvalidOperationExceptionMessage.CondStoreNotInUse); } cSelectedMailbox lSelectedMailbox = mMailboxCache.CheckInSelectedMailbox(pFeedback); // to be repeated inside the select lock if (!lSelectedMailbox.SelectedForUpdate) { throw new InvalidOperationException(kInvalidOperationExceptionMessage.NotSelectedForUpdate); // to be repeated inside the select lock } if (pFeedback.AllHaveUID) { cStoreFeedbackCollector lFeedbackCollector = new cStoreFeedbackCollector(pFeedback); await ZUIDStoreAsync(pMC, lSelectedMailbox.MailboxHandle, pFeedback[0].MessageHandle.UID.UIDValidity, lFeedbackCollector, pOperation, pFlags, pIfUnchangedSinceModSeq, null, lContext).ConfigureAwait(false); } else { await ZStoreAsync(pMC, pFeedback, pOperation, pFlags, pIfUnchangedSinceModSeq, lContext).ConfigureAwait(false); } }
public cStoreFeedbackCollector(cStoreFeedback pItems) { KeyType = eKeyType.uid; foreach (var lItem in pItems) { if (lItem.MessageHandle.UID == null) { throw new InvalidOperationException(); } mDictionary[lItem.MessageHandle.UID.UID] = lItem; } }
public cSelectedMailbox CheckInSelectedMailbox(cStoreFeedback pFeedback) { if (pFeedback == null) { throw new ArgumentNullException(nameof(pFeedback)); } if (pFeedback.Count == 0) { throw new ArgumentOutOfRangeException(nameof(pFeedback)); } if (mSelectedMailbox == null || !ReferenceEquals(pFeedback[0].MessageHandle.MessageCache, mSelectedMailbox.MessageCache)) { throw new InvalidOperationException(kInvalidOperationExceptionMessage.MailboxNotSelected); } return(mSelectedMailbox); }
private async Task ZStoreAsync(cStoreFeedback pFeedback, eStoreOperation pOperation, cStorableFlags pFlags, ulong?pIfUnchangedSinceModSeq, cTrace.cContext pParentContext) { var lContext = pParentContext.NewMethod(nameof(cIMAPClient), nameof(ZStoreAsync), pFeedback, pOperation, pFlags, pIfUnchangedSinceModSeq); if (mDisposed) { throw new ObjectDisposedException(nameof(cIMAPClient)); } var lSession = mSession; if (lSession == null || lSession.SelectedMailboxDetails?.SelectedForUpdate != true) { throw new InvalidOperationException(kInvalidOperationExceptionMessage.NotSelectedForUpdate); } if (pFeedback == null) { throw new ArgumentNullException(nameof(pFeedback)); } if (pFlags == null) { throw new ArgumentNullException(nameof(pFlags)); } if (pIfUnchangedSinceModSeq == 0) { throw new ArgumentOutOfRangeException(nameof(pIfUnchangedSinceModSeq)); } if (pIfUnchangedSinceModSeq != null && !lSession.Capabilities.CondStore) { throw new InvalidOperationException(kInvalidOperationExceptionMessage.CondStoreNotInUse); } if (pFeedback.Count == 0) { return; } // it is valid to add or remove zero flags according to the ABNF (!) using (var lToken = mCancellationManager.GetToken(lContext)) { var lMC = new cMethodControl(mTimeout, lToken.CancellationToken); await lSession.StoreAsync(lMC, pFeedback, pOperation, pFlags, pIfUnchangedSinceModSeq, lContext).ConfigureAwait(false); } }
private async Task ZStoreAsync(cMethodControl pMC, cStoreFeedback pFeedback, eStoreOperation pOperation, cStorableFlags pFlags, ulong?pIfUnchangedSinceModSeq, cTrace.cContext pParentContext) { var lContext = pParentContext.NewMethod(nameof(cSession), nameof(ZStoreAsync), pMC, pFeedback, pOperation, pFlags, pIfUnchangedSinceModSeq); // no validation ... all the parameters have been validated already by the cSession by the time we get here using (var lBuilder = new cCommandDetailsBuilder()) { lBuilder.Add(await mSelectExclusiveAccess.GetBlockAsync(pMC, lContext).ConfigureAwait(false)); // block select cSelectedMailbox lSelectedMailbox = mMailboxCache.CheckInSelectedMailbox(pFeedback); if (!lSelectedMailbox.SelectedForUpdate) { throw new InvalidOperationException(kInvalidOperationExceptionMessage.NotSelectedForUpdate); } lBuilder.Add(await mPipeline.GetIdleBlockTokenAsync(pMC, lContext).ConfigureAwait(false)); // stop the pipeline from iding (idle is msnunsafe) lBuilder.Add(await mMSNUnsafeBlock.GetTokenAsync(pMC, lContext).ConfigureAwait(false)); // wait until all commands that are msnunsafe complete, block all commands that are msnunsafe // uidvalidity must be captured before the handles are resolved lBuilder.AddUIDValidity(lSelectedMailbox.MessageCache.UIDValidity); // collector cStoreFeedbackCollector lFeedbackCollector = new cStoreFeedbackCollector(); // resolve the handles to MSNs foreach (var lItem in pFeedback) { var lMSN = lSelectedMailbox.GetMSN(lItem.MessageHandle); if (lMSN != 0) { lFeedbackCollector.Add(lMSN, lItem); } } // if no handles were resolved, we are done if (lFeedbackCollector.Count == 0) { return; } // build the command lBuilder.Add(kStoreCommandPartStoreSpace, new cTextCommandPart(cSequenceSet.FromUInts(lFeedbackCollector.UInts)), cCommandPart.Space); if (pIfUnchangedSinceModSeq != null) { lBuilder.Add(kStoreCommandPartLParenUnchangedSinceSpace, new cTextCommandPart(pIfUnchangedSinceModSeq.Value), kStoreCommandPartRParenSpace); } lBuilder.Add(pOperation, pFlags); // add the hook var lHook = new cCommandHookStore(lFeedbackCollector, null, lSelectedMailbox); lBuilder.Add(lHook); // submit the command var lResult = await mPipeline.ExecuteAsync(pMC, lBuilder.EmitCommandDetails(), lContext).ConfigureAwait(false); // NOTE: updates may have been done on both OK and NO responses (see rfc 2180/ 7162) so we can't throw on a NO for this command ... NO indicates that some (or all) of the messages have pending deletes // throw on a bad if (lResult.ResultType == eCommandResultType.bad) { fCapabilities lTryIgnoring; if (pIfUnchangedSinceModSeq == null) { lTryIgnoring = 0; } else { lTryIgnoring = fCapabilities.condstore; } throw new cProtocolErrorException(lResult, lTryIgnoring, lContext); } if (lResult.ResultType == eCommandResultType.ok) { lContext.TraceInformation("store success"); } else { lContext.TraceInformation("store possible partial success"); } } }