You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
716 lines
19 KiB
716 lines
19 KiB
//=============================================================================
|
|
// File: body.cpp
|
|
// Contents: Definitions for DwBody
|
|
// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
|
|
// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
|
|
//
|
|
// Copyright (c) 1996, 1997 Douglas W. Sauder
|
|
// All rights reserved.
|
|
//
|
|
// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
|
|
// INDIRECT, SPECIAL, INCIDENTAL, OR CONSETQUENTIAL DAMAGES ARISING OUT OF
|
|
// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
|
|
// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
|
|
// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
|
|
// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
|
|
// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
//
|
|
//=============================================================================
|
|
|
|
#define DW_IMPLEMENTATION
|
|
|
|
#include <mimelib/config.h>
|
|
#include <mimelib/debug.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <iostream>
|
|
#include <mimelib/string.h>
|
|
#include <mimelib/headers.h>
|
|
#include <mimelib/bodypart.h>
|
|
#include <mimelib/body.h>
|
|
#include <mimelib/message.h>
|
|
#include <mimelib/mediatyp.h>
|
|
#include <mimelib/enum.h>
|
|
|
|
enum {
|
|
kParseSuccess,
|
|
kParseFail
|
|
};
|
|
|
|
|
|
struct DwBodyPartStr {
|
|
DwBodyPartStr(const DwString& aStr) : mString(aStr), mNext(0) {}
|
|
DwString mString;
|
|
DwBodyPartStr* mNext;
|
|
};
|
|
|
|
|
|
class DwBodyParser {
|
|
friend class DwBody;
|
|
public:
|
|
~DwBodyParser();
|
|
private:
|
|
DwBodyParser(const DwString& aStr, const DwString& aBoundaryStr);
|
|
const DwString& Preamble() const { return mPreamble; }
|
|
const DwString& Epilogue() const { return mEpilogue; }
|
|
DwBodyPartStr* FirstBodyPart() const { return mFirstBodyPartStr; }
|
|
int Parse();
|
|
int FindBoundary(size_t aStartPos, size_t* aBoundaryStart,
|
|
size_t* aBoundaryEnd, size_t* isFinal) const;
|
|
void AddPart(size_t start, size_t len);
|
|
void DeleteParts();
|
|
const DwString mString;
|
|
const DwString mBoundary;
|
|
DwString mPreamble;
|
|
DwBodyPartStr* mFirstBodyPartStr;
|
|
DwString mEpilogue;
|
|
};
|
|
|
|
|
|
DwBodyParser::DwBodyParser(const DwString& aStr, const DwString& aBoundary)
|
|
: mString(aStr), mBoundary(aBoundary)
|
|
{
|
|
mFirstBodyPartStr = 0;
|
|
Parse();
|
|
}
|
|
|
|
|
|
DwBodyParser::~DwBodyParser()
|
|
{
|
|
DeleteParts();
|
|
}
|
|
|
|
|
|
int DwBodyParser::Parse()
|
|
{
|
|
DeleteParts();
|
|
// Find the preamble
|
|
size_t pos = 0;
|
|
size_t boundaryStart, boundaryEnd, isFinal;
|
|
int result;
|
|
result = FindBoundary(pos, &boundaryStart, &boundaryEnd, &isFinal);
|
|
if (result == kParseFail) {
|
|
mPreamble = mEpilogue = "";
|
|
mFirstBodyPartStr = 0;
|
|
return kParseFail;
|
|
}
|
|
int start = pos;
|
|
int len = boundaryStart - pos;
|
|
mPreamble = mString.substr(start, len);
|
|
if ( boundaryStart < mString.size() && mString[boundaryStart] != '-' )
|
|
mPreamble += DW_EOL; // contrary to normal behaviour of
|
|
// DwBody::Parse(), we _do_ want a newline
|
|
// before the first boundary here. This is
|
|
// necessary since FindBoundary() can't
|
|
// make up it's mind on where the boundary
|
|
// starts - on the leading \n or the first
|
|
// '-'..
|
|
|
|
// Find the body parts
|
|
pos = boundaryEnd;
|
|
while (1) {
|
|
result = FindBoundary(pos, &boundaryStart, &boundaryEnd, &isFinal);
|
|
// NOTE: For enhanced fault tolerance we *accept* a missing last
|
|
// boundary.
|
|
// If no last boundary is found (but at leat a first one was
|
|
// there) we just assume the end of the text ebing the end
|
|
// of the last part.
|
|
// By doing so we can safely parse some buggy MS Outlook
|
|
// clients' messages. (khz, 12.06.2002)
|
|
start = pos;
|
|
|
|
if (result == kParseFail) {
|
|
isFinal = true;
|
|
len = mString.length() - pos;
|
|
} else {
|
|
len = boundaryStart - pos;
|
|
}
|
|
|
|
AddPart(start, len);
|
|
|
|
if (result == kParseFail) {
|
|
pos = mString.length();
|
|
} else {
|
|
pos = boundaryEnd;
|
|
}
|
|
|
|
if (isFinal) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Find the epilogue
|
|
start = pos;
|
|
len = mString.length() - pos;
|
|
if( len )
|
|
mEpilogue = mString.substr(start, len);
|
|
|
|
return kParseSuccess;
|
|
}
|
|
|
|
// checks whether [cur,end[ matches -*[\r\t ]*(\n|$)
|
|
static bool isOnlyWhiteSpaceOrDashesUntilEndOfLine( const char * cur, const char * end ) {
|
|
bool dashesStillAllowed = true;
|
|
|
|
while ( cur < end )
|
|
switch( *cur ) {
|
|
case ' ':
|
|
case '\t':
|
|
case '\r':
|
|
dashesStillAllowed = false;
|
|
++cur;
|
|
continue;
|
|
case '\n':
|
|
return true;
|
|
case '-':
|
|
if ( !dashesStillAllowed )
|
|
return false;
|
|
++cur;
|
|
continue;
|
|
default:
|
|
return false;
|
|
}
|
|
// end of buffer is ok, too:
|
|
return true;
|
|
}
|
|
|
|
int DwBodyParser::FindBoundary(size_t aStartPos, size_t* aBoundaryStart,
|
|
size_t* aBoundaryEnd, size_t* aIsFinal) const
|
|
{
|
|
// Assume the starting position is the beginning of a line
|
|
const char* buf = mString.data();
|
|
size_t pos = aStartPos;
|
|
size_t endPos = mString.length();
|
|
size_t blen = mBoundary.length();
|
|
// Search for the first boundary.
|
|
// The leading CR LF ('\n') is part of the boundary, but if there is
|
|
// no preamble, there may be no leading CR LF ('\n').
|
|
// The case of no leading CR LF ('\n') is a special case that will occur
|
|
// only when '-' is the first character of the body.
|
|
if (buf[pos] == '-'
|
|
&& pos+blen+1 < endPos
|
|
&& buf[pos+1] == '-'
|
|
&& strncmp(&buf[pos+2], mBoundary.data(), blen) == 0
|
|
&& isOnlyWhiteSpaceOrDashesUntilEndOfLine( buf + pos + blen + 2, buf + endPos ) ) {
|
|
|
|
*aBoundaryStart = pos;
|
|
pos += blen + 2;
|
|
// Check for final boundary
|
|
if (pos+1 < endPos
|
|
&& buf[pos] == '-'
|
|
&& buf[pos+1] == '-') {
|
|
|
|
pos += 2;
|
|
*aIsFinal = 1;
|
|
}
|
|
else {
|
|
*aIsFinal = 0;
|
|
}
|
|
// Advance position past end of line
|
|
while (pos < endPos) {
|
|
if (buf[pos] == '\n') {
|
|
++pos;
|
|
break;
|
|
}
|
|
++pos;
|
|
}
|
|
*aBoundaryEnd = pos;
|
|
return kParseSuccess;
|
|
}
|
|
int isFound = 0;
|
|
while (pos+blen+2 < endPos) {
|
|
// Case of leading LF
|
|
if (buf[pos] == '\n'
|
|
&& buf[pos+1] == '-'
|
|
&& buf[pos+2] == '-'
|
|
&& strncmp(&buf[pos+3], mBoundary.data(), blen) == 0
|
|
&& isOnlyWhiteSpaceOrDashesUntilEndOfLine( buf + pos + blen + 3, buf + endPos ) ) {
|
|
|
|
*aBoundaryStart = pos;
|
|
pos += blen + 3;
|
|
isFound = 1;
|
|
}
|
|
// Case of leading CR LF
|
|
else if (buf[pos] == '\r'
|
|
&& buf[pos+1] == '\n'
|
|
&& buf[pos+2] == '-'
|
|
&& pos+blen+3 < endPos
|
|
&& buf[pos+3] == '-'
|
|
&& strncmp(&buf[pos+4], mBoundary.data(), blen) == 0
|
|
&& isOnlyWhiteSpaceOrDashesUntilEndOfLine( buf + pos + blen + 4, buf + endPos ) ) {
|
|
|
|
*aBoundaryStart = pos;
|
|
pos += blen + 4;
|
|
isFound = 1;
|
|
}
|
|
if (isFound) {
|
|
// Check for final boundary
|
|
if (pos < endPos
|
|
&& buf[pos] == '-') {
|
|
|
|
// NOTE: Since we must be fault tolerant for being able to
|
|
// understand messaged that were damaged during
|
|
// transportation we now accept final boundaries
|
|
// ending with "-" instead of "--".
|
|
// (khz, 12.06.2002)
|
|
pos += 1;
|
|
*aIsFinal = 1;
|
|
|
|
// if there *is* the 2nd '-' we of course process it
|
|
if (pos+1 < endPos
|
|
&& buf[pos+1] == '-') {
|
|
pos += 1;
|
|
}
|
|
}
|
|
else {
|
|
*aIsFinal = 0;
|
|
}
|
|
// Advance position past end of line
|
|
while (pos < endPos) {
|
|
if (buf[pos] == '\n') {
|
|
++pos;
|
|
break;
|
|
}
|
|
++pos;
|
|
}
|
|
*aBoundaryEnd = pos;
|
|
return kParseSuccess;
|
|
}
|
|
++pos;
|
|
}
|
|
// Exceptional case: no boundary found
|
|
*aBoundaryStart = *aBoundaryEnd = mString.length();
|
|
*aIsFinal = 1;
|
|
return kParseFail;
|
|
}
|
|
|
|
|
|
void DwBodyParser::AddPart(size_t start, size_t len)
|
|
{
|
|
DwBodyPartStr* toAdd = new DwBodyPartStr(mString.substr(start, len));
|
|
if (toAdd != 0) {
|
|
DwBodyPartStr* curr = mFirstBodyPartStr;
|
|
if (curr == 0) {
|
|
mFirstBodyPartStr = toAdd;
|
|
return;
|
|
}
|
|
while (curr->mNext != 0) {
|
|
curr = curr->mNext;
|
|
}
|
|
curr->mNext = toAdd;
|
|
}
|
|
}
|
|
|
|
|
|
void DwBodyParser::DeleteParts()
|
|
{
|
|
DwBodyPartStr* curr = mFirstBodyPartStr;
|
|
while (curr) {
|
|
DwBodyPartStr* next = curr->mNext;
|
|
delete curr;
|
|
curr = next;
|
|
}
|
|
mFirstBodyPartStr = 0;
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
const char* const DwBody::sClassName = "DwBody";
|
|
|
|
|
|
DwBody* (*DwBody::sNewBody)(const DwString&, DwMessageComponent*) = 0;
|
|
|
|
|
|
DwBody* DwBody::NewBody(const DwString& aStr, DwMessageComponent* aParent)
|
|
{
|
|
if (sNewBody) {
|
|
DwBody* newBody = sNewBody(aStr, aParent);
|
|
//if( newBody )
|
|
// newBody->mFirstBodyPart = 0;
|
|
return newBody;
|
|
}
|
|
else {
|
|
return new DwBody(aStr, aParent);
|
|
}
|
|
}
|
|
|
|
|
|
DwBody::DwBody()
|
|
{
|
|
mFirstBodyPart = 0;
|
|
mMessage = 0;
|
|
mClassId = kCidBody;
|
|
mClassName = sClassName;
|
|
}
|
|
|
|
|
|
DwBody::DwBody(const DwBody& aBody)
|
|
: DwMessageComponent(aBody),
|
|
mBoundaryStr(aBody.mBoundaryStr),
|
|
mPreamble(aBody.mPreamble),
|
|
mEpilogue(aBody.mEpilogue)
|
|
{
|
|
mFirstBodyPart = 0;
|
|
const DwBodyPart* firstPart = aBody.mFirstBodyPart;
|
|
if (firstPart) {
|
|
CopyBodyParts(firstPart);
|
|
}
|
|
mMessage = 0;
|
|
const DwMessage* message = aBody.mMessage;
|
|
if (message) {
|
|
DwMessage* msg = (DwMessage*) message->Clone();
|
|
_SetMessage(msg);
|
|
}
|
|
mClassId = kCidBody;
|
|
mClassName = sClassName;
|
|
}
|
|
|
|
|
|
DwBody::DwBody(const DwString& aStr, DwMessageComponent* aParent)
|
|
: DwMessageComponent(aStr, aParent)
|
|
{
|
|
mFirstBodyPart = 0;
|
|
mMessage = 0;
|
|
mClassId = kCidBody;
|
|
mClassName = sClassName;
|
|
}
|
|
|
|
|
|
DwBody::~DwBody()
|
|
{
|
|
if (mFirstBodyPart) {
|
|
DeleteBodyParts();
|
|
}
|
|
if (mMessage) {
|
|
delete mMessage;
|
|
}
|
|
}
|
|
|
|
|
|
const DwBody& DwBody::operator = (const DwBody& aBody)
|
|
{
|
|
if (this == &aBody) return *this;
|
|
mBoundaryStr = aBody.mBoundaryStr;
|
|
mPreamble = aBody.mPreamble;
|
|
mEpilogue = aBody.mEpilogue;
|
|
if (mFirstBodyPart) {
|
|
DeleteBodyParts();
|
|
}
|
|
const DwBodyPart* firstPart = aBody.FirstBodyPart();
|
|
if (firstPart) {
|
|
CopyBodyParts(firstPart);
|
|
}
|
|
if (mMessage) {
|
|
delete mMessage;
|
|
}
|
|
const DwMessage* message = aBody.Message();
|
|
if (message) {
|
|
DwMessage* msg = (DwMessage*) message->Clone();
|
|
_SetMessage(msg);
|
|
}
|
|
if (mParent) {
|
|
mParent->SetModified();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
|
|
void DwBody::Parse()
|
|
{
|
|
mIsModified = 0;
|
|
// Only types "multipart" and "message" need to be parsed, and
|
|
// we cannot determine the type if there is no header.
|
|
if (!mParent) {
|
|
return;
|
|
}
|
|
// Get the content type from the headers
|
|
DwEntity* entity = (DwEntity*) mParent;
|
|
if (entity->Headers().HasContentType()) {
|
|
const DwMediaType& contentType = entity->Headers().ContentType();
|
|
int type = contentType.Type();
|
|
int subtype = contentType.Subtype();
|
|
if (type == DwMime::kTypeMultipart) {
|
|
mBoundaryStr = contentType.Boundary();
|
|
// Now parse body into body parts
|
|
DwBodyParser parser(mString, mBoundaryStr);
|
|
mPreamble = parser.Preamble();
|
|
mEpilogue = parser.Epilogue();
|
|
DwBodyPartStr* partStr = parser.FirstBodyPart();
|
|
while (partStr) {
|
|
DwBodyPart* part =
|
|
DwBodyPart::NewBodyPart(partStr->mString, this);
|
|
part->Parse();
|
|
_AddBodyPart(part);
|
|
partStr = partStr->mNext;
|
|
}
|
|
}
|
|
else if (type == DwMime::kTypeMessage &&
|
|
subtype == DwMime::kSubtypeRfc822) {
|
|
if (mMessage)
|
|
mMessage->FromString(mString);
|
|
else
|
|
mMessage = DwMessage::NewMessage(mString, this);
|
|
mMessage->Parse();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void DwBody::Assemble()
|
|
{
|
|
if (!mIsModified) return;
|
|
if (!mFirstBodyPart && !mMessage) return;
|
|
if (!mParent) return;
|
|
|
|
DwEntity* entity = (DwEntity*) mParent;
|
|
/*
|
|
DwString partStr;
|
|
*/
|
|
const DwMediaType& contentType = entity->Headers().ContentType();
|
|
int type = contentType.Type();
|
|
int subtype = contentType.Subtype();
|
|
if (type == DwMime::kTypeMultipart) {
|
|
/*
|
|
int len;
|
|
*/
|
|
mBoundaryStr = contentType.Boundary();
|
|
mString = "";
|
|
mString += mPreamble;
|
|
DwBodyPart* part = mFirstBodyPart;
|
|
while (part) {
|
|
part->Assemble();
|
|
/*
|
|
partStr = part->AsString();
|
|
len = mString.length();
|
|
if( ! ( ( (1 < len)
|
|
&& ('\n' == mString.at(len-1) )
|
|
&& ('\n' == mString.at(len-2) ) )
|
|
|| ( (2 < len)
|
|
&& ('\n' == mString.at(len-1) )
|
|
&& ('\r' == mString.at(len-2) )
|
|
&& ('\n' == mString.at(len-3) ) ) ) )
|
|
*/
|
|
if ( part != mFirstBodyPart )
|
|
mString += DW_EOL;
|
|
mString += "--";
|
|
mString += mBoundaryStr;
|
|
/*
|
|
len = partStr.length();
|
|
if( ! ( (0 < len)
|
|
&& ( ('\n' == partStr.at(0) )
|
|
|| ('\r' == partStr.at(0) ) ) ) )
|
|
*/
|
|
mString += DW_EOL;
|
|
/*
|
|
mString += partStr;
|
|
*/
|
|
mString += part->AsString();
|
|
part = part->Next();
|
|
}
|
|
/*
|
|
if( ! ( ( (1 < len)
|
|
&& ('\n' == mString.at(len-1) )
|
|
&& ('\n' == mString.at(len-2) ) )
|
|
|| ( (2 < len)
|
|
&& ('\n' == mString.at(len-1) )
|
|
&& ('\r' == mString.at(len-2) )
|
|
&& ('\n' == mString.at(len-3) ) ) ) )
|
|
*/
|
|
mString += DW_EOL;
|
|
mString += "--";
|
|
mString += mBoundaryStr;
|
|
mString += "--";
|
|
mString += DW_EOL;
|
|
mString += mEpilogue;
|
|
mIsModified = 0;
|
|
}
|
|
else if (type == DwMime::kTypeMessage &&
|
|
subtype == DwMime::kSubtypeRfc822 &&
|
|
mMessage) {
|
|
mMessage->Assemble();
|
|
mString = mMessage->AsString();
|
|
}
|
|
else {
|
|
// Empty block
|
|
}
|
|
}
|
|
|
|
|
|
DwMessageComponent* DwBody::Clone() const
|
|
{
|
|
return new DwBody(*this);
|
|
}
|
|
|
|
|
|
DwBodyPart* DwBody::FirstBodyPart() const
|
|
{
|
|
return mFirstBodyPart;
|
|
}
|
|
|
|
|
|
void DwBody::AddBodyPart(DwBodyPart* aPart)
|
|
{
|
|
_AddBodyPart(aPart);
|
|
SetModified();
|
|
}
|
|
|
|
void DwBody::RemoveBodyPart(DwBodyPart* aPart)
|
|
{
|
|
_RemoveBodyPart(aPart);
|
|
SetModified();
|
|
}
|
|
|
|
|
|
DwMessage* DwBody::Message() const
|
|
{
|
|
return mMessage;
|
|
}
|
|
|
|
|
|
void DwBody::SetMessage(DwMessage* aMessage)
|
|
{
|
|
_SetMessage(aMessage);
|
|
SetModified();
|
|
}
|
|
|
|
|
|
void DwBody::_AddBodyPart(DwBodyPart* aPart)
|
|
{
|
|
aPart->SetParent(this);
|
|
if (!mFirstBodyPart) {
|
|
mFirstBodyPart = aPart;
|
|
return;
|
|
}
|
|
DwBodyPart* part = mFirstBodyPart;
|
|
while (part->Next()) {
|
|
part = part->Next();
|
|
}
|
|
part->SetNext(aPart);
|
|
}
|
|
|
|
void DwBody::_RemoveBodyPart(DwBodyPart* aPart)
|
|
{
|
|
if ( aPart->Parent() != this )
|
|
return; // caller error
|
|
if ( !mFirstBodyPart )
|
|
return; // impossible
|
|
if ( mFirstBodyPart == aPart ) {
|
|
mFirstBodyPart = mFirstBodyPart->Next();
|
|
return;
|
|
}
|
|
DwBodyPart* part = mFirstBodyPart;
|
|
while (part->Next()) {
|
|
if ( part->Next() == aPart ) {
|
|
part->SetNext(aPart->Next());
|
|
break;
|
|
}
|
|
part = part->Next();
|
|
}
|
|
}
|
|
|
|
|
|
void DwBody::_SetMessage(DwMessage* aMessage)
|
|
{
|
|
aMessage->SetParent(this);
|
|
if (mMessage && mMessage != aMessage) {
|
|
delete mMessage;
|
|
}
|
|
mMessage = aMessage;
|
|
}
|
|
|
|
|
|
void DwBody::DeleteBodyParts()
|
|
{
|
|
DwBodyPart* part = mFirstBodyPart;
|
|
while (part) {
|
|
DwBodyPart* nextPart = part->Next();
|
|
delete part;
|
|
part = nextPart;
|
|
}
|
|
mFirstBodyPart = 0;
|
|
}
|
|
|
|
|
|
void DwBody::CopyBodyParts(const DwBodyPart* aFirst)
|
|
{
|
|
const DwBodyPart* part = aFirst;
|
|
while (part) {
|
|
DwBodyPart* newPart = (DwBodyPart*) part->Clone();
|
|
AddBodyPart(newPart);
|
|
part = part->Next();
|
|
}
|
|
}
|
|
|
|
|
|
#if defined(DW_DEBUG_VERSION)
|
|
void DwBody::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const
|
|
{
|
|
aStrm <<
|
|
"------------------ Debug info for DwBody class -----------------\n";
|
|
_PrintDebugInfo(aStrm);
|
|
}
|
|
#else
|
|
void DwBody::PrintDebugInfo(std::ostream&, int) const {}
|
|
#endif // defined(DW_DEBUG_VERSION)
|
|
|
|
|
|
#if defined(DW_DEBUG_VERSION)
|
|
void DwBody::_PrintDebugInfo(std::ostream& aStrm) const
|
|
{
|
|
DwMessageComponent::_PrintDebugInfo(aStrm);
|
|
aStrm << "Boundary: " << mBoundaryStr << '\n';
|
|
aStrm << "Preamble: " << mPreamble << '\n';
|
|
aStrm << "Epilogue: " << mEpilogue << '\n';
|
|
aStrm << "Body Parts: ";
|
|
int count = 0;
|
|
DwBodyPart* bodyPart = mFirstBodyPart;
|
|
if (bodyPart) {
|
|
while (bodyPart) {
|
|
if (count > 0) aStrm << ' ';
|
|
aStrm << bodyPart->ObjectId();
|
|
bodyPart = (DwBodyPart*) bodyPart->Next();
|
|
++count;
|
|
}
|
|
aStrm << '\n';
|
|
}
|
|
else {
|
|
aStrm << "(none)\n";
|
|
}
|
|
aStrm << "Message: ";
|
|
if (mMessage) {
|
|
aStrm << mMessage->ObjectId() << '\n';
|
|
}
|
|
else {
|
|
aStrm << "(none)\n";
|
|
}
|
|
}
|
|
#else
|
|
void DwBody::_PrintDebugInfo(std::ostream& ) const {}
|
|
#endif // defined(DW_DEBUG_VERSION)
|
|
|
|
|
|
void DwBody::CheckInvariants() const
|
|
{
|
|
#if defined(DW_DEBUG_VERSION)
|
|
DwMessageComponent::CheckInvariants();
|
|
mBoundaryStr.CheckInvariants();
|
|
mPreamble.CheckInvariants();
|
|
mEpilogue.CheckInvariants();
|
|
DwBodyPart* bodyPart = mFirstBodyPart;
|
|
while (bodyPart) {
|
|
bodyPart->CheckInvariants();
|
|
bodyPart = (DwBodyPart*) bodyPart->Next();
|
|
}
|
|
if (mMessage) {
|
|
mMessage->CheckInvariants();
|
|
}
|
|
#endif // defined(DW_DEBUG_VERSION)
|
|
}
|