void VMIMEMessage::_ReadSinglePartMail (const VMIMEMailHeader *inHeader, VStream &inStream)
{
	xbox_assert(inHeader != NULL);

	// Read header information.

	XBOX::VString	name, fileName, contentType, contentID;
	bool			isInline, isBase64, isQuotedPrintable;

	isInline = isBase64 = isQuotedPrintable = false;

	XBOX::VString				string;
	XBOX::VNameValueCollection	params;

	if (!inHeader->fContentType.IsEmpty()) {

		contentType = inHeader->fContentType;
		VHTTPHeader::SplitParameters(inHeader->fContentType, string, params);
		if (params.Has("name")) {

			name = params.Get("name");
			_UnQuote(&name, '"', '"');
		
		}

	}

	if (!inHeader->fContentDisposition.IsEmpty()) {

		VHTTPHeader::SplitParameters(inHeader->fContentDisposition, string, params);
		isInline = HTTPTools::EqualASCIIVString(string, "inline");
		if (params.Has("filename")) {

			fileName = params.Get("filename");
			_UnQuote(&fileName, '"', '"');
				
		}

	}

	if (!inHeader->fContentTransferEncoding.IsEmpty()) {

		VHTTPHeader::SplitParameters(inHeader->fContentTransferEncoding, string, params);
		if (!(isBase64 = HTTPTools::EqualASCIIVString(string, "base64")))

			isQuotedPrintable = HTTPTools::EqualASCIIVString(string, "quoted-printable");

	}

	// Read body (a single part). Must be bigger than 5 bytes because of the ending "\r\n.\r\n" sequence.

	XBOX::VError	error;
	VSize			size;

	if ((error = inStream.OpenReading()) != XBOX::VE_OK) 

		XBOX::vThrowError(error);

	else if ((size = (VSize) inStream.GetSize()) > 5) {

		uBYTE	*buffer;

		size -= 5;
		if ((buffer = new uBYTE[size]) == NULL) 

			XBOX::vThrowError(XBOX::VE_MEMORY_FULL);

		else {

			XBOX::VMemoryBuffer<>	decodedData;
			XBOX::VPtrStream		decodedBody;

			inStream.GetData(buffer, size);

			if (isBase64) {

				XBOX::Base64Coder::Decode(buffer, size, decodedData);

				decodedBody.SetDataPtr(decodedData.GetDataPtr(), decodedData.GetDataSize());
				decodedData.ForgetData();

			} else if (isQuotedPrintable) {

				VMIMEReader::DecodeQuotedPrintable(buffer, size, &decodedData);

				decodedBody.SetDataPtr(decodedData.GetDataPtr(), decodedData.GetDataSize());
				decodedData.ForgetData();

			} else 

				decodedBody.SetDataPtr(buffer, size);		

			inStream.CloseReading();

			if (fileName.IsEmpty()) 

				_AddTextPart(name, isInline, contentType, contentID, decodedBody);

			else

				_AddFilePart(name, fileName, isInline, contentType, contentID, decodedBody);

			if (isBase64 || isQuotedPrintable)

				decodedBody.Clear();	

			else 

				decodedBody.StealData();	// Prevent VPtrStream from freeing buffer.

			delete[] buffer;

		}

	} else

		inStream.CloseReading();
}
void VMIMEMessage::_ReadMultiPartMail (const XBOX::VStream &inStream)
{
	XBOX::VStream	&stream	= const_cast<XBOX::VStream&>(inStream);
	VMIMEReader		reader(fBoundary, stream);

	while (reader.HasNextPart()) {
		
		XBOX::VHTTPMessage	message;

		reader.GetNextPart(message);

		// Parse header of part.

		XBOX::VHTTPHeader							header		= message.GetHeaders();
		const XBOX::VNameValueCollection			&headerList	= header.GetHeaderList();
		XBOX::VNameValueCollection::ConstIterator	it;

		XBOX::VString	name, fileName, contentType, contentID;
		bool			isInline, isBase64, isQuotedPrintable;

		isInline = isBase64 = isQuotedPrintable = false;
		for (it = headerList.begin(); it != headerList.end(); it++) {

			XBOX::VString				value;
			XBOX::VNameValueCollection	params;			

			if (HTTPTools::EqualASCIIVString(it->first, "Content-Type", false)) {

				header.GetHeaderValue(it->first, contentType);
				VHTTPHeader::SplitParameters(contentType, value, params);

				if (params.Has("name")) {

					name = params.Get("name");
					_UnQuote(&name, '"', '"');
				
				}

			} else if (HTTPTools::EqualASCIIVString(it->first, "Content-Disposition", false)) {

				XBOX::VString	disposition;

				header.GetHeaderValue(it->first, value);
				VHTTPHeader::SplitParameters(value, disposition, params);

				isInline = HTTPTools::EqualASCIIVString(disposition, "inline");

				if (params.Has("filename")) {

					fileName = params.Get("filename");
					_UnQuote(&fileName, '"', '"');
				
				}

			} else if (HTTPTools::EqualASCIIVString(it->first, "Content-Transfer-Encoding", false)) {

				XBOX::VString	encoding;

				header.GetHeaderValue(it->first, value);
				VHTTPHeader::SplitParameters(value, encoding, params);

				if (!(isBase64 = HTTPTools::EqualASCIIVString(encoding, "base64")))

					isQuotedPrintable = HTTPTools::EqualASCIIVString(encoding, "quoted-printable");

			} else if (HTTPTools::EqualASCIIVString(it->first, "Content-ID", false)) {

				header.GetHeaderValue(it->first, value);
				VHTTPHeader::SplitParameters(value, contentID, params);

				_UnQuote(&contentID, '<', '>');

			} else {

				// Ignore unknown fields.

			}

		}

		//  Get body of part, decode it if need.

		XBOX::VMemoryBuffer<>	decodedData;
		XBOX::VPtrStream		decodedBody;
		
		XBOX::VPtrStream		*body	= message.GetBodyPtr();

		if (isBase64) {

			XBOX::Base64Coder::Decode(body->GetDataPtr(), body->GetDataSize(), decodedData);

			decodedBody.SetDataPtr(decodedData.GetDataPtr(), decodedData.GetDataSize());
			decodedData.ForgetData();

			body = &decodedBody;

		} else if (isQuotedPrintable) {

			VMIMEReader::DecodeQuotedPrintable (body->GetDataPtr(), body->GetDataSize(), &decodedData);

			decodedBody.SetDataPtr(decodedData.GetDataPtr(), decodedData.GetDataSize());
			decodedData.ForgetData();

			body = &decodedBody;

		}

		if (fileName.IsEmpty()) 

			_AddTextPart(name, isInline, contentType, contentID, *body);

		else

			_AddFilePart(name, fileName, isInline, contentType, contentID, *body);

		decodedBody.Clear();

	}
}