Beispiel #1
0
void body::copyFrom(const component& other)
{
    const body& bdy = dynamic_cast <const body&>(other);

    m_prologText = bdy.m_prologText;
    m_epilogText = bdy.m_epilogText;

    m_contents = bdy.m_contents;

    removeAllParts();

    for (int p = 0 ; p < bdy.getPartCount() ; ++p)
    {
        ref <bodyPart> part = bdy.getPartAt(p)->clone().dynamicCast <bodyPart>();

        part->m_parent = m_part;

        m_parts.push_back(part);
    }
}
Beispiel #2
0
void body::copyFrom(const component& other)
{
	const body& bdy = dynamic_cast <const body&>(other);

	m_prologText = bdy.m_prologText;
	m_epilogText = bdy.m_epilogText;

	m_contents = bdy.m_contents;

	removeAllParts();

	for (size_t p = 0 ; p < bdy.getPartCount() ; ++p)
	{
		shared_ptr <bodyPart> part = m_part->createChildPart();

		part->copyFrom(*bdy.getPartAt(p));

		m_parts.push_back(part);
	}
}
Beispiel #3
0
void body::parseImpl
(ref <utility::parserInputStreamAdapter> parser,
 const utility::stream::size_type position,
 const utility::stream::size_type end,
 utility::stream::size_type* newPosition)
{
    removeAllParts();

    m_prologText.clear();
    m_epilogText.clear();

    if (end == position)
    {

        setParsedBounds(position, end);

        if (newPosition)
            *newPosition = end;

        return;
    }

    // Check whether the body is a MIME-multipart
    bool isMultipart = false;
    string boundary;

    try
    {
        const ref <const contentTypeField> ctf =
            m_header.acquire()->findField(fields::CONTENT_TYPE).dynamicCast <contentTypeField>();

        const mediaType type = *ctf->getValue().dynamicCast <const mediaType>();

        if (type.getType() == mediaTypes::MULTIPART)
        {
            isMultipart = true;

            try
            {
                boundary = ctf->getBoundary();
            }
            catch (exceptions::no_such_parameter&)
            {
                // No "boundary" parameter specified: we can try to
                // guess it by scanning the body contents...
                utility::stream::size_type pos = position;

                parser->seek(pos);

                if (pos + 2 < end && parser->matchBytes("--", 2))
                {
                    pos += 2;
                }
                else
                {
                    pos = parser->findNext("\n--", position);

                    if ((pos != utility::stream::npos) && (pos + 3 < end))
                        pos += 3;  // skip \n--
                }

                if ((pos != utility::stream::npos) && (pos < end))
                {
                    parser->seek(pos);

                    // Read some bytes after boundary separator
                    utility::stream::value_type buffer[256];
                    const utility::stream::size_type bufferLen =
                        parser->read(buffer, std::min(end - pos, sizeof(buffer) / sizeof(buffer[0])));

                    buffer[sizeof(buffer) / sizeof(buffer[0]) - 1] = '\0';

                    // Extract boundary from buffer (stop at first CR or LF).
                    // We have to stop after a reasonnably long boundary length (100)
                    // not to take the whole body contents for a boundary...
                    string::value_type boundaryBytes[100];
                    string::size_type boundaryLen = 0;

                    for (string::value_type c = buffer[0] ;
                            boundaryLen < bufferLen && boundaryLen < 100 && !(c == '\r' || c == '\n') ;
                            c = buffer[++boundaryLen])
                    {
                        boundaryBytes[boundaryLen] = buffer[boundaryLen];
                    }

                    if (boundaryLen >= 1 && boundaryLen < 100)
                    {
                        // RFC #1521, Page 31:
                        // "...the boundary parameter, which consists of 1 to 70
                        //  characters from a set of characters known to be very
                        //  robust through email gateways, and NOT ending with
                        //  white space..."
                        while (boundaryLen != 0 &&
                                parserHelpers::isSpace(boundaryBytes[boundaryLen - 1]))
                        {
                            boundaryLen--;
                        }

                        if (boundaryLen >= 1)
                            boundary = string(boundaryBytes, boundaryBytes + boundaryLen);
                    }
                }
            }
        }
    }
    catch (exceptions::no_such_field&)
    {
        // No "Content-Type" field...
    }

    // This is a multi-part body
    if (isMultipart && !boundary.empty())
    {
        const string boundarySep("--" + boundary);

        utility::stream::size_type partStart = position;
        utility::stream::size_type pos = position;

        bool lastPart = false;

        while (pos != utility::stream::npos && pos < end)
        {
            pos = parser->findNext(boundarySep, pos);

            if (pos == utility::stream::npos)
                break;  // not found

            if (pos != 0)
            {
                parser->seek(pos - 1);

                if (parser->peekByte() != '\n')
                {
                    // Boundary is not at a beginning of a line
                    pos++;
                    continue;
                }

                parser->skip(1 + boundarySep.length());
            }
            else
            {
                parser->seek(pos + boundarySep.length());
            }

            const utility::stream::value_type next = parser->peekByte();

            if (next == '\r' || next == '\n' || next == '-')
                break;

            // Boundary is a prefix of another, continue the search
            pos++;
        }

        if (pos != utility::stream::npos && pos < end)
        {
            vmime::text text;
            text.parse(parser, position, pos);

            m_prologText = text.getWholeBuffer();
        }

        for (int index = 0 ; !lastPart && (pos != utility::stream::npos) && (pos < end) ; ++index)
        {
            utility::stream::size_type partEnd = pos;

            // Get rid of the [CR]LF just before the boundary string
            if (pos >= (position + 1))
            {
                parser->seek(pos - 1);

                if (parser->peekByte() == '\n')
                    --partEnd;
            }

            if (pos >= (position + 2))
            {
                parser->seek(pos - 2);

                if (parser->peekByte() == '\r')
                    --partEnd;
            }

            // Check whether it is the last part (boundary terminated by "--")
            pos += boundarySep.length();
            parser->seek(pos);

            if (pos + 1 < end && parser->matchBytes("--", 2))
            {
                lastPart = true;
                pos += 2;
            }

            // RFC #1521, Page 31:
            // "...(If a boundary appears to end with white space, the
            //  white space must be presumed to have been added by a
            //  gateway, and must be deleted.)..."
            parser->seek(pos);
            pos += parser->skipIf(parserHelpers::isSpaceOrTab, end);

            // End of boundary line
            if (pos + 1 < end && parser->matchBytes("\r\n", 2))
            {
                pos += 2;
            }
            else if (pos < end && parser->peekByte() == '\n')
            {
                ++pos;
            }

            if (index > 0)
            {
                ref <bodyPart> part = vmime::create <bodyPart>();

                // End before start may happen on empty bodyparts (directly
                // successive boundaries without even a line-break)
                if (partEnd < partStart)
                    std::swap(partStart, partEnd);

                part->parse(parser, partStart, partEnd, NULL);
                part->m_parent = m_part;

                m_parts.push_back(part);
            }

            partStart = pos;

            while (pos != utility::stream::npos && pos < end)
            {
                pos = parser->findNext(boundarySep, pos);

                if (pos == utility::stream::npos)
                    break;  // not found

                if (pos != 0)
                {
                    parser->seek(pos - 1);

                    if (parser->peekByte() != '\n')
                    {
                        // Boundary is not at a beginning of a line
                        pos++;
                        continue;
                    }

                    parser->skip(1 + boundarySep.length());
                }
                else
                {
                    parser->seek(pos + boundarySep.length());
                }

                const utility::stream::value_type next = parser->peekByte();

                if (next == '\r' || next == '\n' || next == '-')
                    break;

                // Boundary is a prefix of another, continue the search
                pos++;
            }
        }

        m_contents = vmime::create <emptyContentHandler>();

        // Last part was not found: recover from missing boundary
        if (!lastPart && pos == utility::stream::npos)
        {
            ref <bodyPart> part = vmime::create <bodyPart>();

            try
            {
                part->parse(parser, partStart, end);
            }
            catch (std::exception&)
            {
                throw;
            }

            part->m_parent = m_part;

            m_parts.push_back(part);
        }
        // Treat remaining text as epilog
        else if (partStart < end)
        {
            vmime::text text;
            text.parse(parser, partStart, end);

            m_epilogText = text.getWholeBuffer();
        }
    }
    // Treat the contents as 'simple' data
    else
    {
        encoding enc;

        try
        {
            const ref <const headerField> cef =
                m_header.acquire()->findField(fields::CONTENT_TRANSFER_ENCODING);

            enc = *cef->getValue().dynamicCast <const encoding>();
        }
        catch (exceptions::no_such_field&)
        {
            // Defaults to "7bit" (RFC-1521)
            enc = vmime::encoding(encodingTypes::SEVEN_BIT);

            // Set header field
            m_header.acquire()->ContentTransferEncoding()->setValue(enc);
        }

        // Extract the (encoded) contents
        const utility::stream::size_type length = end - position;

        ref <utility::inputStream> contentStream =
            vmime::create <utility::seekableInputStreamRegionAdapter>
            (parser->getUnderlyingStream(), position, length);

        m_contents = vmime::create <streamContentHandler>(contentStream, length, enc);
    }

    setParsedBounds(position, end);

    if (newPosition)
        *newPosition = end;
}
Beispiel #4
0
void body::parseImpl
	(const parsingContext& /* ctx */,
	 shared_ptr <utility::parserInputStreamAdapter> parser,
	 const size_t position, const size_t end, size_t* newPosition)
{
	removeAllParts();

	m_prologText.clear();
	m_epilogText.clear();

	if (end == position)
	{

		setParsedBounds(position, end);

		if (newPosition)
			*newPosition = end;

		return;
	}

	// Check whether the body is a MIME-multipart.
	// If it is, also get (or try to guess) the boundary separator.
	bool isMultipart = false;
	string boundary;

	shared_ptr <const contentTypeField> ctf =
		m_part->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);

	if (ctf)
	{
		const mediaType type = *ctf->getValue <mediaType>();

		if (type.getType() == mediaTypes::MULTIPART)
		{
			isMultipart = true;

			if (ctf->hasBoundary())
			{
				boundary = ctf->getBoundary();
			}
			else
			{
				// No "boundary" parameter specified: we can try to
				// guess it by scanning the body contents...
				size_t pos = position;

				parser->seek(pos);

				if (pos + 2 < end && parser->matchBytes("--", 2))
				{
					pos += 2;
				}
				else
				{
					pos = parser->findNext("\n--", position);

					if ((pos != npos) && (pos + 3 < end))
						pos += 3;  // skip \n--
				}

				if ((pos != npos) && (pos < end))
				{
					parser->seek(pos);

					// Read some bytes after boundary separator
					byte_t buffer[256];
					const size_t bufferLen =
						parser->read(buffer, std::min(end - pos, sizeof(buffer) / sizeof(buffer[0])));

					buffer[sizeof(buffer) / sizeof(buffer[0]) - 1] = '\0';

					// Skip transport padding bytes (SPACE or HTAB), if any
					size_t boundarySkip = 0;

					while (boundarySkip < bufferLen && parserHelpers::isSpace(buffer[boundarySkip]))
						++boundarySkip;

					// Extract boundary from buffer (stop at first CR or LF).
					// We have to stop after a reasonnably long boundary length (100)
					// not to take the whole body contents for a boundary...
					byte_t boundaryBytes[100];
					size_t boundaryLen = 0;

					for (byte_t c = buffer[boundarySkip] ;
					     boundaryLen < bufferLen && boundaryLen < 100 && !(c == '\r' || c == '\n') ;
					     ++boundaryLen, c = buffer[boundarySkip + boundaryLen])
					{
						boundaryBytes[boundaryLen] = c;
					}

					if (boundaryLen >= 1 && boundaryLen < 100)
					{
						// RFC #1521, Page 31:
						// "...the boundary parameter, which consists of 1 to 70
						//  characters from a set of characters known to be very
						//  robust through email gateways, and NOT ending with
						//  white space..."
						while (boundaryLen != 0 &&
						       parserHelpers::isSpace(boundaryBytes[boundaryLen - 1]))
						{
							boundaryLen--;
						}

						if (boundaryLen >= 1)
							boundary = string(boundaryBytes, boundaryBytes + boundaryLen);
					}
				}
			}
		}
 	}

	// This is a multi-part body
	if (isMultipart && !boundary.empty())
	{
		size_t partStart = position;
		size_t pos = position;

		bool lastPart = false;

		// Find the first boundary
		size_t boundaryStart, boundaryEnd;
		pos = findNextBoundaryPosition(parser, boundary, pos, end, &boundaryStart, &boundaryEnd);

		for (int index = 0 ; !lastPart && (pos != npos) && (pos < end) ; ++index)
		{
			size_t partEnd = boundaryStart;

			// Check whether it is the last part (boundary terminated by "--")
			parser->seek(boundaryEnd);

			if (boundaryEnd + 1 < end && parser->matchBytes("--", 2))
			{
				lastPart = true;
				boundaryEnd += 2;
			}

			// RFC #1521, Page 31:
			// "...(If a boundary appears to end with white space, the
			//  white space must be presumed to have been added by a
			//  gateway, and must be deleted.)..."
			parser->seek(boundaryEnd);
			boundaryEnd += parser->skipIf(parserHelpers::isSpaceOrTab, end);

			// End of boundary line
			if (boundaryEnd + 1 < end && parser->matchBytes("\r\n", 2))
			{
				boundaryEnd += 2;
			}
			else if (boundaryEnd < end && parser->peekByte() == '\n')
			{
				++boundaryEnd;
			}

			if (index == 0)
			{
				if (partEnd > partStart)
				{
					vmime::text text;
					text.parse(parser, partStart, partEnd);

					m_prologText = text.getWholeBuffer();
				}
				else
				{
					m_prologText = "";
				}
			}
			else // index > 0
			{
				shared_ptr <bodyPart> part = m_part->createChildPart();

				// End before start may happen on empty bodyparts (directly
				// successive boundaries without even a line-break)
				if (partEnd < partStart)
					std::swap(partStart, partEnd);

				part->parse(parser, partStart, partEnd, NULL);

				m_parts.push_back(part);
			}

			partStart = boundaryEnd;

			// Find the next boundary
			pos = findNextBoundaryPosition
				(parser, boundary, boundaryEnd, end, &boundaryStart, &boundaryEnd);
		}

		m_contents = make_shared <emptyContentHandler>();

		// Last part was not found: recover from missing boundary
		if (!lastPart && pos == npos)
		{
			shared_ptr <bodyPart> part = m_part->createChildPart();

			try
			{
				part->parse(parser, partStart, end);
			}
			catch (std::exception&)
			{
				throw;
			}

			m_parts.push_back(part);
		}
		// Treat remaining text as epilog
		else if (partStart < end)
		{
			vmime::text text;
			text.parse(parser, partStart, end);

			m_epilogText = text.getWholeBuffer();
		}
	}
	// Treat the contents as 'simple' data
	else
	{
		encoding enc;

		shared_ptr <const headerField> cef =
			m_part->getHeader()->findField(fields::CONTENT_TRANSFER_ENCODING);

		if (cef)
		{
			enc = *cef->getValue <encoding>();
		}
		else
		{
			// Defaults to "7bit" (RFC-1521)
			enc = vmime::encoding(encodingTypes::SEVEN_BIT);
		}

		// Extract the (encoded) contents
		const size_t length = end - position;

		shared_ptr <utility::inputStream> contentStream =
			make_shared <utility::seekableInputStreamRegionAdapter>
				(parser->getUnderlyingStream(), position, length);

		m_contents = make_shared <streamContentHandler>(contentStream, length, enc);
	}

	setParsedBounds(position, end);

	if (newPosition)
		*newPosition = end;
}