public async Task UIDStoreAsync(cMethodControl pMC, iMailboxHandle pMailboxHandle, cUIDStoreFeedback pFeedback, eStoreOperation pOperation, cStorableFlags pFlags, ulong?pIfUnchangedSinceModSeq, cTrace.cContext pParentContext) { var lContext = pParentContext.NewMethod(nameof(cSession), nameof(UIDStoreAsync), pMC, pMailboxHandle, pFeedback, pOperation, pFlags, pIfUnchangedSinceModSeq); if (mDisposed) { throw new ObjectDisposedException(nameof(cSession)); } if (_ConnectionState != eConnectionState.selected) { throw new InvalidOperationException(kInvalidOperationExceptionMessage.NotSelected); } if (pMailboxHandle == null) { throw new ArgumentNullException(nameof(pMailboxHandle)); } 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); } uint lUIDValidity = pFeedback[0].UID.UIDValidity; cSelectedMailbox lSelectedMailbox = mMailboxCache.CheckIsSelectedMailbox(pMailboxHandle, lUIDValidity); // to be repeated inside the select lock if (!lSelectedMailbox.SelectedForUpdate) { throw new InvalidOperationException(kInvalidOperationExceptionMessage.NotSelectedForUpdate); // to be repeated inside the select lock } cStoreFeedbackCollector lFeedbackCollector = new cStoreFeedbackCollector(pFeedback); await ZUIDStoreAsync(pMC, pMailboxHandle, lUIDValidity, lFeedbackCollector, pOperation, pFlags, pIfUnchangedSinceModSeq, pFeedback, lContext).ConfigureAwait(false); }
public cCommandHookStore(cStoreFeedbackCollector pFeedbackCollector, cUIDStoreFeedback pUIDStoreFeedback, cSelectedMailbox pSelectedMailbox) { mFeedbackCollector = pFeedbackCollector ?? throw new ArgumentNullException(nameof(pFeedbackCollector)); mUIDStoreFeedback = pUIDStoreFeedback; mSelectedMailbox = pSelectedMailbox ?? throw new ArgumentNullException(nameof(pSelectedMailbox)); }
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"); } } }
private async Task ZUIDStoreAsync(cMethodControl pMC, iMailboxHandle pMailboxHandle, uint pUIDValidity, cStoreFeedbackCollector pFeedbackCollector, eStoreOperation pOperation, cStorableFlags pFlags, ulong?pIfUnchangedSinceModSeq, cUIDStoreFeedback pFeedback, cTrace.cContext pParentContext) { var lContext = pParentContext.NewMethod(nameof(cSession), nameof(ZStoreAsync), pMC, pMailboxHandle, pUIDValidity, pFeedbackCollector, pOperation, pFlags, pIfUnchangedSinceModSeq, pFeedback); // 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.CheckIsSelectedMailbox(pMailboxHandle, pUIDValidity); if (!lSelectedMailbox.SelectedForUpdate) { throw new InvalidOperationException(kInvalidOperationExceptionMessage.NotSelectedForUpdate); } lBuilder.Add(await mMSNUnsafeBlock.GetBlockAsync(pMC, lContext).ConfigureAwait(false)); // this command is msnunsafe lBuilder.AddUIDValidity(pUIDValidity); // the command is sensitive to UIDValidity changes // build the command lBuilder.Add(kUIDStoreCommandPartUIDStoreSpace, new cTextCommandPart(cSequenceSet.FromUInts(pFeedbackCollector.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(pFeedbackCollector, pFeedback, lSelectedMailbox); lBuilder.Add(lHook); // submit the command var lResult = await mPipeline.ExecuteAsync(pMC, lBuilder.EmitCommandDetails(), lContext).ConfigureAwait(false); // note: the base spec states that non-existent UIDs are ignored without comment => a NO from a UID STORE is unexpected if (lResult.ResultType == eCommandResultType.ok) { lContext.TraceInformation("uid store success"); return; } fCapabilities lTryIgnoring; if (pIfUnchangedSinceModSeq == null) { lTryIgnoring = 0; } else { lTryIgnoring = fCapabilities.condstore; } if (lResult.ResultType == eCommandResultType.no) { throw new cUnsuccessfulCompletionException(lResult.ResponseText, lTryIgnoring, lContext); } throw new cProtocolErrorException(lResult, lTryIgnoring, lContext); } }