예제 #1
0
        internal Task UIDFetchAsync(iMailboxHandle pMailboxHandle, cUID pUID, cSection pSection, eDecodingRequired pDecoding, Stream pStream, cBodyFetchConfiguration pConfiguration)
        {
            // note: if it fails bytes could have been written to the stream
            var lContext = mRootContext.NewMethod(nameof(cIMAPClient), nameof(UIDFetchAsync));

            return(ZUIDFetchBodyAsync(pMailboxHandle, pUID, pSection, pDecoding, pStream, pConfiguration, lContext));
        }
예제 #2
0
 internal cMessageBodyPart(cSection pSection, cBodyStructureParameters pParameters, string pContentId, cCulturedString pDescription, string pContentTransferEncoding, uint pSizeInBytes, cEnvelope pEnvelope, cBodyPart pBody, cBodyPart pBodyStructure, uint pSizeInLines, cSinglePartExtensionData pExtensionData) : base(kMimeType.Message, kMimeSubType.RFC822, pSection, pParameters, pContentId, pDescription, pContentTransferEncoding, pSizeInBytes, pExtensionData)
 {
     Envelope      = pEnvelope;
     mBody         = pBody;
     BodyStructure = pBodyStructure;
     SizeInLines   = pSizeInLines;
 }
예제 #3
0
        internal cMultiPartBody(IList <cBodyPart> pParts, string pSubType, cSection pSection, cMultiPartExtensionData pExtensionData) : base(kMimeType.Multipart, pSubType, pSection)
        {
            Parts = new cBodyParts(pParts);

            if (SubType.Equals("MIXED", StringComparison.InvariantCultureIgnoreCase))
            {
                SubTypeCode = eMultiPartBodySubTypeCode.mixed;
            }
            else if (SubType.Equals("DIGEST", StringComparison.InvariantCultureIgnoreCase))
            {
                SubTypeCode = eMultiPartBodySubTypeCode.digest;
            }
            else if (SubType.Equals("ALTERNATIVE", StringComparison.InvariantCultureIgnoreCase))
            {
                SubTypeCode = eMultiPartBodySubTypeCode.alternative;
            }
            else if (SubType.Equals("RELATED", StringComparison.InvariantCultureIgnoreCase))
            {
                SubTypeCode = eMultiPartBodySubTypeCode.related;
            }
            else
            {
                SubTypeCode = eMultiPartBodySubTypeCode.other;
            }

            ExtensionData = pExtensionData;
        }
예제 #4
0
        internal cSinglePartBody(string pType, string pSubType, cSection pSection, cBodyStructureParameters pParameters, string pContentId, cCulturedString pDescription, string pContentTransferEncoding, uint pSizeInBytes, cSinglePartExtensionData pExtensionData) : base(pType, pSubType, pSection)
        {
            Parameters              = pParameters;
            ContentId               = pContentId;
            Description             = pDescription;
            ContentTransferEncoding = pContentTransferEncoding ?? throw new ArgumentNullException(nameof(pContentTransferEncoding));

            if (ContentTransferEncoding.Equals("7BIT", StringComparison.InvariantCultureIgnoreCase))
            {
                DecodingRequired = eDecodingRequired.none;
            }
            else if (ContentTransferEncoding.Equals("8BIT", StringComparison.InvariantCultureIgnoreCase))
            {
                DecodingRequired = eDecodingRequired.none;
            }
            else if (ContentTransferEncoding.Equals("BINARY", StringComparison.InvariantCultureIgnoreCase))
            {
                DecodingRequired = eDecodingRequired.none;
            }
            else if (ContentTransferEncoding.Equals("QUOTED-PRINTABLE", StringComparison.InvariantCultureIgnoreCase))
            {
                DecodingRequired = eDecodingRequired.quotedprintable;
            }
            else if (ContentTransferEncoding.Equals("BASE64", StringComparison.InvariantCultureIgnoreCase))
            {
                DecodingRequired = eDecodingRequired.base64;
            }
            else
            {
                DecodingRequired = eDecodingRequired.other;  // note that rfc 2045 section 6.4 specifies that if 'unknown' then the part has to be treated as application/octet-stream
            }
            SizeInBytes   = pSizeInBytes;
            ExtensionData = pExtensionData;
        }
예제 #5
0
        internal void Fetch(iMessageHandle pMessageHandle, cSection pSection, eDecodingRequired pDecoding, Stream pStream, cBodyFetchConfiguration pConfiguration)
        {
            // note: if it fails bytes could have been written to the stream
            var lContext = mRootContext.NewMethod(nameof(cIMAPClient), nameof(Fetch));
            var lTask    = ZFetchBodyAsync(pMessageHandle, pSection, pDecoding, pStream, pConfiguration, lContext);

            mSynchroniser.Wait(lTask, lContext);
        }
예제 #6
0
        private async Task ZFetchBodyAsync(iMessageHandle pMessageHandle, cSection pSection, eDecodingRequired pDecoding, Stream pStream, cBodyFetchConfiguration pConfiguration, cTrace.cContext pParentContext)
        {
            var lContext = pParentContext.NewMethod(nameof(cIMAPClient), nameof(ZFetchBodyAsync), pMessageHandle, pSection, pDecoding);

            if (mDisposed)
            {
                throw new ObjectDisposedException(nameof(cIMAPClient));
            }

            var lSession = mSession;

            if (lSession == null || lSession.ConnectionState != eConnectionState.selected)
            {
                throw new InvalidOperationException(kInvalidOperationExceptionMessage.NotSelected);
            }

            if (pMessageHandle == null)
            {
                throw new ArgumentNullException(nameof(pMessageHandle));
            }
            if (pSection == null)
            {
                throw new ArgumentNullException(nameof(pSection));
            }
            if (pStream == null)
            {
                throw new ArgumentNullException(nameof(pStream));
            }

            if (!pStream.CanWrite)
            {
                throw new ArgumentOutOfRangeException(nameof(pStream));
            }

            if (pConfiguration == null)
            {
                using (var lToken = mCancellationManager.GetToken(lContext))
                {
                    var lMC         = new cMethodControl(mTimeout, lToken.CancellationToken);
                    var lProgress   = new cProgress();
                    var lWriteSizer = new cBatchSizer(mFetchBodyWriteConfiguration);
                    await lSession.FetchBodyAsync(lMC, pMessageHandle, pSection, pDecoding, pStream, lProgress, lWriteSizer, lContext).ConfigureAwait(false);
                }
            }
            else
            {
                var lMC         = new cMethodControl(pConfiguration.Timeout, pConfiguration.CancellationToken);
                var lProgress   = new cProgress(mSynchroniser, pConfiguration.Increment);
                var lWriteSizer = new cBatchSizer(pConfiguration.Write ?? mFetchBodyWriteConfiguration);
                await lSession.FetchBodyAsync(lMC, pMessageHandle, pSection, pDecoding, pStream, lProgress, lWriteSizer, lContext).ConfigureAwait(false);
            }
        }
예제 #7
0
            public readonly cBytes Bytes; // may be null

            public cBody(bool pBinary, cSection pSection, uint?pOrigin, IList <byte> pBytes)
            {
                Binary  = pBinary;
                Section = pSection ?? throw new ArgumentNullException(nameof(pSection));
                Origin  = pOrigin;

                if (pBytes == null)
                {
                    Bytes = null;
                }
                else
                {
                    Bytes = new cBytes(pBytes);
                }
            }
예제 #8
0
        internal cTextBodyPart(string pSubType, cSection pSection, cBodyStructureParameters pParameters, string pContentId, cCulturedString pDescription, string pContentTransferEncoding, uint pSizeInBytes, uint pSizeInLines, cSinglePartExtensionData pExtensionData) : base(kMimeType.Text, pSubType, pSection, pParameters, pContentId, pDescription, pContentTransferEncoding, pSizeInBytes, pExtensionData)
        {
            if (SubType.Equals("PLAIN", StringComparison.InvariantCultureIgnoreCase))
            {
                SubTypeCode = eTextBodyPartSubTypeCode.plain;
            }
            else if (SubType.Equals("HTML", StringComparison.InvariantCultureIgnoreCase))
            {
                SubTypeCode = eTextBodyPartSubTypeCode.html;
            }
            else
            {
                SubTypeCode = eTextBodyPartSubTypeCode.other;
            }

            SizeInLines = pSizeInLines;
        }
예제 #9
0
        internal cBodyPart(string pType, string pSubType, cSection pSection)
        {
            Type    = pType ?? throw new ArgumentNullException(nameof(pType));
            SubType = pSubType ?? throw new ArgumentNullException(nameof(pSubType));
            Section = pSection ?? throw new ArgumentNullException(nameof(pSection));

            if (Type.Equals(kMimeType.Text, StringComparison.InvariantCultureIgnoreCase))
            {
                TypeCode = eBodyPartTypeCode.text;
            }
            else if (Type.Equals("IMAGE", StringComparison.InvariantCultureIgnoreCase))
            {
                TypeCode = eBodyPartTypeCode.image;
            }
            else if (Type.Equals("AUDIO", StringComparison.InvariantCultureIgnoreCase))
            {
                TypeCode = eBodyPartTypeCode.audio;
            }
            else if (Type.Equals("VIDEO", StringComparison.InvariantCultureIgnoreCase))
            {
                TypeCode = eBodyPartTypeCode.video;
            }
            else if (Type.Equals("APPLICATION", StringComparison.InvariantCultureIgnoreCase))
            {
                TypeCode = eBodyPartTypeCode.application;
            }
            else if (Type.Equals(kMimeType.Multipart, StringComparison.InvariantCultureIgnoreCase))
            {
                TypeCode = eBodyPartTypeCode.multipart;
            }
            else if (Type.Equals(kMimeType.Message, StringComparison.InvariantCultureIgnoreCase))
            {
                TypeCode = eBodyPartTypeCode.message;
            }
            else
            {
                TypeCode = eBodyPartTypeCode.other;
            }
        }
예제 #10
0
            private async Task <cBody> ZUIDFetchBodyAsync(cMethodControl pMC, iMailboxHandle pMailboxHandle, cUID pUID, bool pBinary, cSection pSection, uint pOrigin, uint pLength, cTrace.cContext pParentContext)
            {
                // the caller must have checked that the binary option is compatible with the section (e.g. if binary is true the section can't specify a textpart)
                //  the length must be greater than zero

                var lContext = pParentContext.NewMethod(nameof(cSession), nameof(ZUIDFetchBodyAsync), pMC, pMailboxHandle, pUID, pBinary, pSection, pOrigin, pLength);

                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 (pUID == null)
                {
                    throw new ArgumentNullException(nameof(pUID));
                }
                if (pSection == null)
                {
                    throw new ArgumentNullException(nameof(pSection));
                }

                using (var lBuilder = new cCommandDetailsBuilder())
                {
                    lBuilder.Add(await mSelectExclusiveAccess.GetBlockAsync(pMC, lContext).ConfigureAwait(false)); // block select

                    mMailboxCache.CheckIsSelectedMailbox(pMailboxHandle, pUID.UIDValidity);

                    lBuilder.Add(await mMSNUnsafeBlock.GetBlockAsync(pMC, lContext).ConfigureAwait(false)); // this command is msnunsafe

                    // set uidvalidity
                    lBuilder.AddUIDValidity(pUID.UIDValidity);

                    // build command

                    lBuilder.Add(kFetchCommandPartUIDFetchSpace, new cTextCommandPart(pUID.UID));

                    if (pBinary)
                    {
                        lBuilder.Add(kFetchCommandPartSpaceBinaryPeekLBracket);
                    }
                    else
                    {
                        lBuilder.Add(kFetchCommandPartSpaceBodyPeekLBracket);
                    }

                    lBuilder.Add(pSection, pOrigin, pLength);

                    // hook
                    var lHook = new cCommandHookFetchBodyUID(pBinary, pSection, pOrigin, pUID.UID);
                    lBuilder.Add(lHook);

                    // go

                    var lResult = await mPipeline.ExecuteAsync(pMC, lBuilder.EmitCommandDetails(), lContext).ConfigureAwait(false);

                    if (lResult.ResultType == eCommandResultType.ok)
                    {
                        lContext.TraceInformation("uid fetch body success");
                        if (lHook.Body == null)
                        {
                            throw new cRequestedDataNotReturnedException(lContext);
                        }
                        return(lHook.Body);
                    }

                    if (lHook.Body != null)
                    {
                        lContext.TraceError("received body on a failed uid fetch body");
                    }

                    fCapabilities lTryIgnoring;
                    if (pBinary)
                    {
                        lTryIgnoring = fCapabilities.binary;
                    }
                    else
                    {
                        lTryIgnoring = 0;
                    }

                    if (lResult.ResultType == eCommandResultType.no)
                    {
                        throw new cUnsuccessfulCompletionException(lResult.ResponseText, lTryIgnoring, lContext);
                    }
                    throw new cProtocolErrorException(lResult, lTryIgnoring, lContext);
                }
            }
예제 #11
0
 public cCommandHookFetchBodyUID(bool pBinary, cSection pSection, uint pOrigin, uint pUID) : base(pBinary, pSection, pOrigin)
 {
     mUID = pUID;
 }
예제 #12
0
 public cCommandHookFetchBodyMSN(bool pBinary, cSection pSection, uint pOrigin, uint pMSN) : base(pBinary, pSection, pOrigin)
 {
     mMSN = pMSN;
 }
예제 #13
0
 public cCommandHookFetchBody(bool pBinary, cSection pSection, uint pOrigin)
 {
     mBinary  = pBinary;
     mSection = pSection;
     mOrigin  = pOrigin;
 }
예제 #14
0
            private async Task ZFetchBodyAsync(cMethodControl pMC, iMailboxHandle pMailboxHandle, cUID pUID, iMessageHandle pMessageHandle, cSection pSection, eDecodingRequired pDecoding, Stream pStream, cProgress pProgress, cBatchSizer pWriteSizer, cTrace.cContext pParentContext)
            {
                var lContext = pParentContext.NewMethod(nameof(cSession), nameof(ZFetchBodyAsync), pMC, pMailboxHandle, pUID, pMessageHandle, pSection, pDecoding);

                if (pSection == null)
                {
                    throw new ArgumentNullException(nameof(pSection));
                }
                if (pStream == null)
                {
                    throw new ArgumentNullException(nameof(pStream));
                }
                if (pProgress == null)
                {
                    throw new ArgumentNullException(nameof(pProgress));
                }
                if (pWriteSizer == null)
                {
                    throw new ArgumentNullException(nameof(pWriteSizer));
                }

                if (!pStream.CanWrite)
                {
                    throw new ArgumentOutOfRangeException(nameof(pStream));
                }

                // work out if binary can/should be used or not
                bool lBinary = _Capabilities.Binary && pSection.TextPart == eSectionTextPart.all && pDecoding != eDecodingRequired.none;

                cDecoder lDecoder;

                if (lBinary || pDecoding == eDecodingRequired.none)
                {
                    lDecoder = new cIdentityDecoder(pStream);
                }
                else if (pDecoding == eDecodingRequired.base64)
                {
                    lDecoder = new cBase64Decoder(pStream);
                }
                else if (pDecoding == eDecodingRequired.quotedprintable)
                {
                    lDecoder = new cQuotedPrintableDecoder(pStream);
                }
                else
                {
                    throw new cContentTransferDecodingException("required decoding not supported", lContext);
                }

                uint lOrigin = 0;

                Stopwatch lStopwatch = new Stopwatch();

                while (true)
                {
                    int lLength = mFetchBodyReadSizer.Current;

                    lStopwatch.Restart();

                    cBody lBody;
                    if (pUID == null)
                    {
                        lBody = await ZFetchBodyAsync(pMC, pMessageHandle, lBinary, pSection, lOrigin, (uint)lLength, lContext).ConfigureAwait(false);
                    }
                    else
                    {
                        lBody = await ZUIDFetchBodyAsync(pMC, pMailboxHandle, pUID, lBinary, pSection, lOrigin, (uint)lLength, lContext).ConfigureAwait(false);
                    }

                    lStopwatch.Stop();

                    // store the time taken so the next fetch is a better size
                    mFetchBodyReadSizer.AddSample(lBody.Bytes.Count, lStopwatch.ElapsedMilliseconds);

                    uint lBodyOrigin = lBody.Origin ?? 0;

                    // the body that we get may start before the place that we asked for
                    int lOffset = (int)(lOrigin - lBodyOrigin);

                    // write the bytes
                    await lDecoder.WriteAsync(pMC, lBody.Bytes, lOffset, pWriteSizer, lContext).ConfigureAwait(false);

                    // update progress
                    pProgress.Increment(lBody.Bytes.Count - lOffset, lContext);

                    // if the body we got was the whole body, we are done
                    if (lBody.Origin == null)
                    {
                        break;
                    }

                    // if we got less bytes than asked for then we will assume that we are at the end
                    if (lBody.Bytes.Count - lOffset < lLength)
                    {
                        break;
                    }

                    // set the start point for the next fetch
                    lOrigin = lBodyOrigin + (uint)lBody.Bytes.Count;
                }

                await lDecoder.FlushAsync(pMC, pWriteSizer, lContext).ConfigureAwait(false);
            }
예제 #15
0
            public Task UIDFetchBodyAsync(cMethodControl pMC, iMailboxHandle pMailboxHandle, cUID pUID, cSection pSection, eDecodingRequired pDecoding, Stream pStream, cProgress pProgress, cBatchSizer pWriteSizer, cTrace.cContext pParentContext)
            {
                var lContext = pParentContext.NewMethod(nameof(cSession), nameof(UIDFetchBodyAsync), pMC, pMailboxHandle, pUID, pSection, pDecoding);

                if (mDisposed)
                {
                    throw new ObjectDisposedException(nameof(cSession));
                }
                if (_ConnectionState != eConnectionState.selected)
                {
                    throw new InvalidOperationException(kInvalidOperationExceptionMessage.NotSelected);
                }

                mMailboxCache.CheckIsSelectedMailbox(pMailboxHandle, pUID.UIDValidity); // to be repeated inside the select lock

                return(ZFetchBodyAsync(pMC, pMailboxHandle, pUID, null, pSection, pDecoding, pStream, pProgress, pWriteSizer, lContext));
            }