internal static bool TryConstruct(cSequenceSets pSequenceSets, int pAsterisk, bool pDistinct, out cUIntList rResult) { if (pSequenceSets == null) { throw new ArgumentNullException(nameof(pSequenceSets)); } rResult = new cUIntList(); foreach (var lSequenceSet in pSequenceSets) { if (lSequenceSet == null) { return(false); } if (!ZExpand(lSequenceSet, pAsterisk, out var lResult)) { return(false); } rResult.AddRange(lResult); } if (pDistinct) { rResult = new cUIntList(rResult.Distinct()); } return(true); }
public cMessageHandleList SetUnseenCount(int pMessageCount, cUIntList pMSNs, cTrace.cContext pParentContext) { var lContext = pParentContext.NewMethod(nameof(cSelectedMailboxCache), nameof(SetUnseenCount), pMSNs); // the message count is required because messages can be delivered during the search, after the search results are calculated // it should be the message count that existed when the command was submitted // corrollary: fetches may arrive during the search that set the flags after the results were calculated // - that is why this code only changes the unseen == null entries // (I don't have to worry about expunges, as they are not allowed during a search command) int lMessageCount = pMessageCount; cMessageHandleList lMessageHandles = new cMessageHandleList(); bool lSetMailboxStatus = false; foreach (var lMSN in pMSNs) { int lItemIndex = (int)lMSN - 1; if (lItemIndex >= lMessageCount) { lMessageCount = lItemIndex + 1; } var lItem = mItems[lItemIndex]; if (lItem.Unseen == null) { lItem.Unseen = true; mUnseenCount++; mUnseenUnknownCount--; lSetMailboxStatus = true; } lMessageHandles.Add(lItem); } if (mUnseenUnknownCount > 0) { for (int i = 0; i < lMessageCount; i++) { var lItem = mItems[i]; if (lItem.Unseen == null) { lItem.Unseen = false; mUnseenUnknownCount--; lSetMailboxStatus = true; } } } if (lSetMailboxStatus) { ZSetMailboxStatus(lContext); } return(lMessageHandles); }
internal cCopyFeedback(uint pSourceUIDValidity, cUIntList pSourceUIDs, uint pDestinationUIDValidity, cUIntList pCreatedUIDs) { for (int i = 0; i < pSourceUIDs.Count; i++) { mItems.Add( new cCopyFeedbackItem( new cUID(pSourceUIDValidity, pSourceUIDs[i]), new cUID(pDestinationUIDValidity, pCreatedUIDs[i]))); } }
internal static bool TryConstruct(cSequenceSet pSequenceSet, int pAsterisk, bool pDistinct, out cUIntList rResult) { if (pSequenceSet == null) { throw new ArgumentNullException(nameof(pSequenceSet)); } if (!ZExpand(pSequenceSet, pAsterisk, out rResult)) { return(false); } if (pDistinct) { rResult = new cUIntList(rResult.Distinct()); } return(true); }
public override eProcessDataResult ProcessData(cBytesCursor pCursor, cTrace.cContext pParentContext) { var lContext = pParentContext.NewMethod(nameof(cCommandHookBaseSearch), nameof(ProcessData)); if (!pCursor.SkipBytes(kSearch)) { return(eProcessDataResult.notprocessed); } cUIntList lMSNs = new cUIntList(); while (true) { if (!pCursor.SkipByte(cASCII.SPACE)) { break; } if (!pCursor.GetNZNumber(out _, out var lMSN)) { lContext.TraceWarning("likely malformed search: not an nz-number list?"); return(eProcessDataResult.notprocessed); } lMSNs.Add(lMSN); } if (!pCursor.Position.AtEnd) { lContext.TraceWarning("likely malformed search: not at end?"); return(eProcessDataResult.notprocessed); } if (mMSNs == null) { mMSNs = lMSNs; } else { mMSNs.AddRange(lMSNs); } return(eProcessDataResult.processed); }
private async Task ZUIDFetchCacheItemsAsync(cMethodControl pMC, iMailboxHandle pMailboxHandle, cUIDList pUIDs, cMessageCacheItems pItems, cProgress pProgress, cTrace.cContext pParentContext) { var lContext = pParentContext.NewMethod(nameof(cSession), nameof(ZUIDFetchCacheItemsAsync), pMC, pMailboxHandle, pUIDs, pItems); // get the UIDValidity uint lUIDValidity = pUIDs[0].UIDValidity; // sort the uids so we might get good sequence sets pUIDs.Sort(); int lIndex = 0; Stopwatch lStopwatch = new Stopwatch(); while (lIndex < pUIDs.Count) { // the number of messages to fetch this time int lFetchCount = mFetchCacheItemsSizer.Current; // get the UIDs to fetch this time cUIntList lUIDs = new cUIntList(); while (lIndex < pUIDs.Count && lUIDs.Count < lFetchCount) { lUIDs.Add(pUIDs[lIndex++].UID); } // fetch lStopwatch.Restart(); await ZUIDFetchCacheItemsAsync(pMC, pMailboxHandle, lUIDValidity, lUIDs, pItems, lContext).ConfigureAwait(false); lStopwatch.Stop(); // store the time taken so the next fetch is a better size mFetchCacheItemsSizer.AddSample(lUIDs.Count, lStopwatch.ElapsedMilliseconds); // update progress pProgress.Increment(lUIDs.Count, lContext); } }
public uint GetMSN(iMessageHandle pMessageHandle) => mCache.GetMSN(pMessageHandle); // this should only be called when no msnunsafe commands are running public cMessageHandleList SetUnseenCount(int pMessageCount, cUIntList pMSNs, cTrace.cContext pParentContext) => mCache.SetUnseenCount(pMessageCount, pMSNs, pParentContext); // this should only be called from a commandcompletion
private async Task ZFetchCacheItemsAsync(cMethodControl pMC, cMessageHandleList pMessageHandles, cMessageCacheItems pItems, cTrace.cContext pParentContext) { var lContext = pParentContext.NewMethod(nameof(cSession), nameof(ZFetchCacheItemsAsync), pMC, pMessageHandles, pItems); if (mDisposed) { throw new ObjectDisposedException(nameof(cSession)); } if (_ConnectionState != eConnectionState.selected) { throw new InvalidOperationException(kInvalidOperationExceptionMessage.NotSelected); } if (pMessageHandles == null) { throw new ArgumentNullException(nameof(pMessageHandles)); } if (pItems == null) { throw new ArgumentNullException(nameof(pItems)); } if (pMessageHandles.Count == 0) { throw new ArgumentOutOfRangeException(nameof(pMessageHandles)); } if (pItems.IsEmpty) { throw new ArgumentOutOfRangeException(nameof(pItems)); } using (var lBuilder = new cCommandDetailsBuilder()) { lBuilder.Add(await mSelectExclusiveAccess.GetBlockAsync(pMC, lContext).ConfigureAwait(false)); // block select cSelectedMailbox lSelectedMailbox = mMailboxCache.CheckInSelectedMailbox(pMessageHandles); 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); // resolve MSNs cUIntList lMSNs = new cUIntList(); foreach (var lMessageHandle in pMessageHandles) { var lMSN = lSelectedMailbox.GetMSN(lMessageHandle); if (lMSN != 0) { lMSNs.Add(lMSN); } } if (lMSNs.Count == 0) { return; } // build command lBuilder.Add(kFetchCommandPartFetchSpace, new cTextCommandPart(cSequenceSet.FromUInts(lMSNs)), cCommandPart.Space); lBuilder.Add(pItems, lSelectedMailbox.MessageCache.NoModSeq); // go var lResult = await mPipeline.ExecuteAsync(pMC, lBuilder.EmitCommandDetails(), lContext).ConfigureAwait(false); if (lResult.ResultType == eCommandResultType.ok) { lContext.TraceInformation("fetch success"); return; } if (lResult.ResultType == eCommandResultType.no) { throw new cUnsuccessfulCompletionException(lResult.ResponseText, 0, lContext); } throw new cProtocolErrorException(lResult, 0, lContext); } }
private static bool ZExpand(cSequenceSet pSequenceSet, int pAsterisk, out cUIntList rResult) { if (pSequenceSet == null) { rResult = null; return(false); } rResult = new cUIntList(); foreach (var lItem in pSequenceSet) { if (lItem == cSequenceSetItem.Asterisk) { if (pAsterisk < 1) { return(false); } rResult.Add((uint)pAsterisk); continue; } if (lItem is cSequenceSetNumber lNumber) { rResult.Add(lNumber.Number); continue; } if (!(lItem is cSequenceSetRange lRange)) { return(false); } if (lRange.From == cSequenceSetItem.Asterisk) { if (pAsterisk < 1) { return(false); } rResult.Add((uint)pAsterisk); continue; } if (!(lRange.From is cSequenceSetNumber lFrom)) { return(false); } uint lTo; if (lRange.To == cSequenceSetItem.Asterisk) { if (pAsterisk < 1) { return(false); } lTo = (uint)pAsterisk; } else { if (!(lRange.To is cSequenceSetNumber lRangeTo)) { return(false); } lTo = lRangeTo.Number; } for (uint i = lFrom.Number; i <= lTo; i++) { rResult.Add(i); } } return(true); }
private static void _Tests_SequenceSet(cTrace.cContext pParentContext) { var lContext = pParentContext.NewMethod(nameof(cBytesCursor), nameof(_Tests_SequenceSet)); LTest("*", "cSequenceSet(cAsterisk())", null, new cUIntList(new uint[] { 15 }), "cSequenceSet(cSequenceSetNumber(15))"); LTest("0", null, "0", null, null); LTest("2,4:7,9,12:*", "cSequenceSet(cSequenceSetNumber(2),cSequenceSetRange(cSequenceSetNumber(4),cSequenceSetNumber(7)),cSequenceSetNumber(9),cSequenceSetRange(cSequenceSetNumber(12),cAsterisk()))", null, new cUIntList(new uint[] { 2, 4, 5, 6, 7, 9, 12, 13, 14, 15 }), "cSequenceSet(cSequenceSetNumber(2),cSequenceSetRange(cSequenceSetNumber(4),cSequenceSetNumber(7)),cSequenceSetNumber(9),cSequenceSetRange(cSequenceSetNumber(12),cSequenceSetNumber(15)))"); LTest("*:4,7:5", "cSequenceSet(cSequenceSetRange(cSequenceSetNumber(4),cAsterisk()),cSequenceSetRange(cSequenceSetNumber(5),cSequenceSetNumber(7)))", null, new cUIntList(new uint[] { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }), "cSequenceSet(cSequenceSetRange(cSequenceSetNumber(4),cSequenceSetNumber(15)))"); void LTest(string pCursor, string pExpSeqSet, string pExpRemainder, cUIntList pExpList, string pExpSeqSet2) { var lCursor = new cBytesCursor(pCursor); if (lCursor.GetSequenceSet(out var lSequenceSet)) { string lSeqSet = lSequenceSet.ToString(); if (lSeqSet != pExpSeqSet) { throw new cTestsException($"failed to get expected sequence set from {pCursor}: '{lSeqSet}' vs '{pExpSeqSet}'"); } if (!cUIntList.TryConstruct(lSequenceSet, 15, true, out var lTemp)) { throw new cTestsException($"failed to get an uintlist from {lSequenceSet}"); } if (pExpList.Count != lTemp.Count) { throw new cTestsException($"failed to get expected uintlist from {lSequenceSet}"); } var lList = new cUIntList(lTemp.OrderBy(i => i)); for (int i = 0; i < pExpList.Count; i++) { if (pExpList[i] != lList[i]) { throw new cTestsException($"failed to get expected uintlist from {lSequenceSet}"); } } string lSeqSet2 = cSequenceSet.FromUInts(lList).ToString(); if (lSeqSet2 != pExpSeqSet2) { throw new cTestsException($"failed to get expected sequence set from {lList}: '{lSeqSet2}' vs '{pExpSeqSet2}'"); } } else if (pExpSeqSet != null) { throw new cTestsException($"failed to get a sequence set from {pCursor}"); } if (lCursor.Position.AtEnd) { if (pExpRemainder == null) { return; } throw new cTestsException($"expected a remainder from {pCursor}"); } string lRemainder = lCursor.GetRestAsString(); if (lRemainder != pExpRemainder) { throw new cTestsException($"failed to get expected remainder set from {pCursor}: '{lRemainder}' vs '{pExpRemainder}'"); } } }
private async Task ZUIDFetchCacheItemsAsync(cMethodControl pMC, iMailboxHandle pMailboxHandle, uint pUIDValidity, cUIntList pUIDs, cMessageCacheItems pItems, cTrace.cContext pParentContext) { // note that this will fail if the UIDValidity has changed (this is different to the behaviour of standard fetch) // note that the caller should have checked that pAttributes contains some attributes to fetch var lContext = pParentContext.NewMethod(nameof(cSession), nameof(ZUIDFetchCacheItemsAsync), pMC, pMailboxHandle, pUIDValidity, pUIDs, pItems); 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 (pUIDs == null) { throw new ArgumentNullException(nameof(pUIDs)); } if (pItems == null) { throw new ArgumentNullException(nameof(pItems)); } if (pUIDs.Count == 0) { throw new ArgumentOutOfRangeException(nameof(pUIDs)); } if (pItems.IsEmpty) { throw new ArgumentOutOfRangeException(nameof(pItems)); } using (var lBuilder = new cCommandDetailsBuilder()) { lBuilder.Add(await mSelectExclusiveAccess.GetBlockAsync(pMC, lContext).ConfigureAwait(false)); // block select cSelectedMailbox lSelectedMailbox = mMailboxCache.CheckIsSelectedMailbox(pMailboxHandle, pUIDValidity); lBuilder.Add(await mMSNUnsafeBlock.GetBlockAsync(pMC, lContext).ConfigureAwait(false)); // this command is msnunsafe lBuilder.AddUIDValidity(pUIDValidity); // the command is sensitive to UIDValidity changes lBuilder.Add(kFetchCommandPartUIDFetchSpace, new cTextCommandPart(cSequenceSet.FromUInts(pUIDs)), cCommandPart.Space); lBuilder.Add(pItems, lSelectedMailbox.MessageCache.NoModSeq); var lResult = await mPipeline.ExecuteAsync(pMC, lBuilder.EmitCommandDetails(), lContext).ConfigureAwait(false); if (lResult.ResultType == eCommandResultType.ok) { lContext.TraceInformation("uid fetch success"); return; } if (lResult.ResultType == eCommandResultType.no) { throw new cUnsuccessfulCompletionException(lResult.ResponseText, 0, lContext); } throw new cProtocolErrorException(lResult, 0, lContext); } }
private async Task <cCopyFeedback> ZUIDCopyAsync(cMethodControl pMC, iMailboxHandle pSourceMailboxHandle, uint pSourceUIDValidity, cUIntList pSourceUIDs, cMailboxCacheItem pDestinationItem, cTrace.cContext pParentContext) { var lContext = pParentContext.NewMethod(nameof(cSession), nameof(ZCopyAsync), pMC, pSourceMailboxHandle, pSourceUIDValidity, pSourceUIDs, pDestinationItem); using (var lBuilder = new cCommandDetailsBuilder()) { lBuilder.Add(await mSelectExclusiveAccess.GetBlockAsync(pMC, lContext).ConfigureAwait(false)); // block select cSelectedMailbox lSelectedMailbox = mMailboxCache.CheckIsSelectedMailbox(pSourceMailboxHandle, pSourceUIDValidity); lBuilder.Add(await mMSNUnsafeBlock.GetBlockAsync(pMC, lContext).ConfigureAwait(false)); // this command is msnunsafe lBuilder.AddUIDValidity(pSourceUIDValidity); // the command is sensitive to UIDValidity changes // build the command lBuilder.Add(kUIDCopyCommandPart, new cTextCommandPart(cSequenceSet.FromUInts(pSourceUIDs)), cCommandPart.Space, pDestinationItem.MailboxNameCommandPart); // add the hook var lHook = new cCommandHookCopy(pSourceUIDValidity); lBuilder.Add(lHook); // submit the command var lResult = await mPipeline.ExecuteAsync(pMC, lBuilder.EmitCommandDetails(), lContext).ConfigureAwait(false); if (lResult.ResultType == eCommandResultType.ok) { lContext.TraceInformation("uid copy success"); return(lHook.Feedback); } if (lResult.ResultType == eCommandResultType.no) { throw new cUnsuccessfulCompletionException(lResult.ResponseText, 0, lContext); } throw new cProtocolErrorException(lResult, 0, lContext); } }
private async Task <cCopyFeedback> ZCopyAsync(cMethodControl pMC, cMessageHandleList pSourceMessageHandles, cMailboxCacheItem pDestinationItem, cTrace.cContext pParentContext) { var lContext = pParentContext.NewMethod(nameof(cSession), nameof(ZCopyAsync), pMC, pSourceMessageHandles, pDestinationItem); using (var lBuilder = new cCommandDetailsBuilder()) { lBuilder.Add(await mSelectExclusiveAccess.GetBlockAsync(pMC, lContext).ConfigureAwait(false)); // block select cSelectedMailbox lSelectedMailbox = mMailboxCache.CheckInSelectedMailbox(pSourceMessageHandles); 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 var lUIDValidity = lSelectedMailbox.MessageCache.UIDValidity; lBuilder.AddUIDValidity(lUIDValidity); // resolve the handles to MSNs cUIntList lMSNs = new cUIntList(); foreach (var lMessageHandle in pSourceMessageHandles) { var lMSN = lSelectedMailbox.GetMSN(lMessageHandle); if (lMSN == 0) { if (lMessageHandle.Expunged) { throw new cMessageExpungedException(lMessageHandle); } else { throw new ArgumentOutOfRangeException(nameof(pSourceMessageHandles)); } } lMSNs.Add(lMSN); } // build the command lBuilder.Add(kCopyCommandPart, new cTextCommandPart(cSequenceSet.FromUInts(lMSNs)), cCommandPart.Space, pDestinationItem.MailboxNameCommandPart); // add the hook var lHook = new cCommandHookCopy(lUIDValidity); lBuilder.Add(lHook); // submit the command var lResult = await mPipeline.ExecuteAsync(pMC, lBuilder.EmitCommandDetails(), lContext).ConfigureAwait(false); if (lResult.ResultType == eCommandResultType.ok) { lContext.TraceInformation("copy success"); return(lHook.Feedback); } if (lResult.ResultType == eCommandResultType.no) { throw new cUnsuccessfulCompletionException(lResult.ResponseText, 0, lContext); } throw new cProtocolErrorException(lResult, 0, lContext); } }