예제 #1
0
        /// <summary>
        /// Parses mime entity from stream.
        /// </summary>
        /// <param name="stream">Data stream from where to read data.</param>
        /// <param name="toBoundary">Entity data is readed to specified boundary.</param>
        /// <returns>Returns false if last entity. Returns true for mulipart entity, if there are more entities.</returns>
        internal bool Parse(SmartStream stream, string toBoundary)
        {
            // Clear header fields
            m_pHeader.Clear();
            m_pHeaderFieldCache.Clear();

            // Parse header
            m_pHeader.Parse(stream);

            // Parse entity and child entities if any (Conent-Type: multipart/xxx...)

            // Multipart entity
            if ((ContentType & MediaType_enum.Multipart) != 0)
            {
                // There must be be boundary ID (rfc 1341 7.2.1  The Content-Type field for multipart entities requires one parameter,
                // "boundary", which is used to specify the encapsulation boundary.)
                string boundaryID = ContentType_Boundary;
                if (boundaryID == null)
                {
                    // This is invalid message, just skip this mime entity
                }
                else
                {
                    // There is one or more mime entities

                    // Find first boundary start position
                    SmartStream.ReadLineAsyncOP args = new SmartStream.ReadLineAsyncOP(new byte[8000],
                                                                                       SizeExceededAction.
                                                                                           JunkAndThrowException);
                    stream.ReadLine(args, false);
                    if (args.Error != null)
                    {
                        throw args.Error;
                    }
                    string lineString = args.LineUtf8;

                    while (lineString != null)
                    {
                        if (lineString.StartsWith("--" + boundaryID))
                        {
                            break;
                        }

                        stream.ReadLine(args, false);
                        if (args.Error != null)
                        {
                            throw args.Error;
                        }
                        lineString = args.LineUtf8;
                    }
                    // This is invalid entity, boundary start not found. Skip that entity.
                    if (string.IsNullOrEmpty(lineString))
                    {
                        return false;
                    }

                    // Start parsing child entities of this entity
                    while (true)
                    {
                        // Parse and add child entity
                        MimeEntity childEntity = new MimeEntity();
                        ChildEntities.Add(childEntity);

                        // This is last entity, stop parsing
                        if (childEntity.Parse(stream, boundaryID) == false)
                        {
                            break;
                        }
                        // else{
                        // There are more entities, parse them
                    }

                    // This entity is child of mulipart entity.
                    // All this entity child entities are parsed,
                    // we need to move stream position to next entity start.
                    if (!string.IsNullOrEmpty(toBoundary))
                    {
                        stream.ReadLine(args, false);
                        if (args.Error != null)
                        {
                            throw args.Error;
                        }
                        lineString = args.LineUtf8;

                        while (lineString != null)
                        {
                            if (lineString.StartsWith("--" + toBoundary))
                            {
                                break;
                            }

                            stream.ReadLine(args, false);
                            if (args.Error != null)
                            {
                                throw args.Error;
                            }
                            lineString = args.LineUtf8;
                        }

                        // Invalid boundary end, there can't be more entities 
                        if (string.IsNullOrEmpty(lineString))
                        {
                            return false;
                        }

                        // See if last boundary or there is more. Last boundary ends with --
                        if (lineString.EndsWith(toBoundary + "--"))
                        {
                            return false;
                        }
                        // else{
                        // There are more entities					
                        return true;
                    }
                }
            }
                // Singlepart entity.
            else
            {
                // Boundary is specified, read data to specified boundary.
                if (!string.IsNullOrEmpty(toBoundary))
                {
                    MemoryStream entityData = new MemoryStream();
                    SmartStream.ReadLineAsyncOP readLineOP = new SmartStream.ReadLineAsyncOP(new byte[Workaround.Definitions.MaxStreamLineLength],
                                                                                             SizeExceededAction
                                                                                                 .
                                                                                                 JunkAndThrowException);

                    // Read entity data while get boundary end tag --boundaryID-- or EOS.
                    while (true)
                    {
                        stream.ReadLine(readLineOP, false);
                        if (readLineOP.Error != null)
                        {
                            throw readLineOP.Error;
                        }
                        // End of stream reached. Normally we should get boundary end tag --boundaryID--, but some x mailers won't add it, so
                        // if we reach EOS, consider boundary closed.
                        if (readLineOP.BytesInBuffer == 0)
                        {
                            // Just return data what was readed.
                            m_EncodedData = entityData.ToArray();
                            return false;
                        }
                            // We readed a line.
                        else
                        {
                            // We have boundary start/end tag or just "--" at the beginning of line.
                            if (readLineOP.LineBytesInBuffer >= 2 && readLineOP.Buffer[0] == '-' &&
                                readLineOP.Buffer[1] == '-')
                            {
                                string lineString = readLineOP.LineUtf8;
                                // We have boundary end tag, no more boundaries.
                                if (lineString == "--" + toBoundary + "--")
                                {
                                    m_EncodedData = entityData.ToArray();
                                    return false;
                                }
                                    // We have new boundary start.
                                else if (lineString == "--" + toBoundary)
                                {
                                    m_EncodedData = entityData.ToArray();
                                    return true;
                                }
                                else
                                {
                                    // Just skip
                                }
                            }

                            // Write readed line.
                            entityData.Write(readLineOP.Buffer, 0, readLineOP.BytesInBuffer);
                        }
                    }
                }
                    // Boundary isn't specified, read data to the stream end. 
                else
                {
                    MemoryStream ms = new MemoryStream();
                    stream.ReadAll(ms);
                    m_EncodedData = ms.ToArray();
                }
            }

            return false;
        }