//============================================================================= // File: field.cpp // Contents: Definitions for DwField // Maintainer: Doug Sauder // 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 CONSEQUENTIAL 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class DwFieldParser { friend class DwField; private: DwFieldParser(const DwString&); void Parse(); const DwString mString; DwString mName; DwString mBody; }; DwFieldParser::DwFieldParser(const DwString& aStr) : mString(aStr) { Parse(); } void DwFieldParser::Parse() { const char* buf = mString.data(); size_t bufEnd = mString.length(); size_t pos = 0; size_t start = 0; size_t len = 0; // Get field name while (pos < bufEnd) { if (buf[pos] == ':') { break; } ++pos; } len = pos; // Remove any white space at end of field-name while (len > 0) { int ch = buf[len-1]; if (ch != ' ' && ch != '\t') break; --len; } mName = mString.substr(start, len); if (pos < bufEnd && buf[pos] == ':') { ++pos; } // Skip spaces and tabs (but not newline!) while (pos < bufEnd) { if (buf[pos] != ' ' && buf[pos] != '\t') break; ++pos; } start = pos; len = 0; // Get field body while (pos < bufEnd) { if (buf[pos] == '\n') { // Are we at the end of the string? if (pos == bufEnd - 1) { ++pos; break; } // Is this really the end of the field body, and not just // the end of a wrapped line? else if (buf[pos+1] != ' ' && buf[pos+1] != '\t') { ++pos; break; } } ++pos; } // Remove white space at end of field-body while (pos > start) { if (!isspace(buf[pos-1])) break; --pos; } len = pos - start; mBody = mString.substr(start, len); } //=========================================================================== const char* const DwField::sClassName = "DwField"; DwField* (*DwField::sNewField)(const DwString&, DwMessageComponent*) = 0; DwFieldBody* (*DwField::sCreateFieldBody)(const DwString&, const DwString&, DwMessageComponent*) = 0; DwField* DwField::NewField(const DwString& aStr, DwMessageComponent* aParent) { if (sNewField) { return sNewField(aStr, aParent); } else { return new DwField(aStr, aParent); } } DwField::DwField() { mNext = 0; mFieldBody = 0; mClassId = kCidField; mClassName = sClassName; } DwField::DwField(const DwField& aField) : DwMessageComponent(aField), mFieldNameStr(aField.mFieldNameStr), mFieldBodyStr(aField.mFieldBodyStr) { mNext = 0; if (aField.mFieldBody) { mFieldBody = (DwFieldBody*) aField.mFieldBody->Clone(); } else { mFieldBody = 0; } mClassId = kCidField; mClassName = sClassName; } DwField::DwField(const DwString& aStr, DwMessageComponent* aParent) : DwMessageComponent(aStr, aParent) { mNext = 0; mFieldBody = 0; mClassId = kCidField; mClassName = sClassName; } DwField::~DwField() { if (mFieldBody) { delete mFieldBody; } } const DwField& DwField::operator = (const DwField& aField) { if (this == &aField) return *this; DwMessageComponent::operator = (aField); mFieldNameStr = aField.mFieldNameStr; mFieldBodyStr = aField.mFieldBodyStr; if (mFieldBody) { delete mFieldBody; mFieldBody = (DwFieldBody*) aField.mFieldBody->Clone(); } return *this; } const DwString& DwField::FieldNameStr() const { return mFieldNameStr; } void DwField::SetFieldNameStr(const DwString& aStr) { mFieldNameStr = aStr; SetModified(); } const DwString& DwField::FieldBodyStr() const { return mFieldBodyStr; } void DwField::SetFieldBodyStr(const DwString& aStr) { mFieldBodyStr = aStr; if (mFieldBody) { delete mFieldBody; mFieldBody = 0; } SetModified(); } DwFieldBody* DwField::FieldBody() const { return mFieldBody; } void DwField::SetFieldBody(DwFieldBody* aFieldBody) { int isModified = 0; if (mFieldBody != aFieldBody) { isModified = 1; } mFieldBody = aFieldBody; if (mFieldBody) { mFieldBody->SetParent(this); } if (isModified) { SetModified(); } } void DwField::_SetFieldBody(DwFieldBody* aFieldBody) { mFieldBody = aFieldBody; if (mFieldBody) { mFieldBody->SetParent(this); } } DwField* DwField::Next() const { return (DwField*) mNext; } void DwField::SetNext(const DwField* aNext) { mNext = aNext; } void DwField::Parse() { mIsModified = 0; DwFieldParser parser(mString); mFieldNameStr = parser.mName; mFieldBodyStr = parser.mBody; mFieldBody = CreateFieldBody(mFieldNameStr, mFieldBodyStr, this); assert(mFieldBody != 0); mFieldBody->Parse(); } void DwField::Assemble() { if (!mIsModified) return; if (mFieldBody) { mFieldBody->Assemble(); mFieldBodyStr = mFieldBody->AsString(); } mString = ""; mString += mFieldNameStr; mString += ": "; mString += mFieldBodyStr; mString += DW_EOL; mIsModified = 0; } DwMessageComponent* DwField::Clone() const { return new DwField(*this); } DwFieldBody* DwField::CreateFieldBody(const DwString& aFieldName, const DwString& aFieldBody, DwMessageComponent* aParent) { DwFieldBody* fieldBody; if (sCreateFieldBody != 0) { fieldBody = sCreateFieldBody(aFieldName, aFieldBody, aParent); } else { fieldBody = _CreateFieldBody(aFieldName, aFieldBody, aParent); } return fieldBody; } DwFieldBody* DwField::_CreateFieldBody(const DwString& aFieldName, const DwString& aFieldBody, DwMessageComponent* aParent) { enum { kAddressList, kDispositionType, kDateTime, kMailbox, kMailboxList, kMechanism, kMediaType, kMsgId, kText } fieldBodyType; // Default field type is 'text' fieldBodyType = kText; int ch = aFieldName[0]; ch = tolower(ch); switch (ch) { case 'b': if (DwStrcasecmp(aFieldName, "bcc") == 0) { fieldBodyType = kAddressList; } break; case 'c': if (DwStrcasecmp(aFieldName, "cc") == 0) { fieldBodyType = kAddressList; } else if (DwStrcasecmp(aFieldName, "content-id") == 0) { fieldBodyType = kMsgId; } else if (DwStrcasecmp(aFieldName, "content-transfer-encoding") == 0) { fieldBodyType = kMechanism; } else if (DwStrcasecmp(aFieldName, "content-type") == 0) { fieldBodyType = kMediaType; } else if (DwStrcasecmp(aFieldName, "content-disposition") == 0) { fieldBodyType = kDispositionType; } break; case 'd': if (DwStrcasecmp(aFieldName, "date") == 0) { fieldBodyType = kDateTime; } break; case 'f': if (DwStrcasecmp(aFieldName, "from") == 0) { fieldBodyType = kMailboxList; } break; case 'm': if (DwStrcasecmp(aFieldName, "message-id") == 0) { fieldBodyType = kMsgId; } break; case 'r': if (DwStrcasecmp(aFieldName, "reply-to") == 0) { fieldBodyType = kAddressList; } else if (DwStrcasecmp(aFieldName, "resent-bcc") == 0) { fieldBodyType = kAddressList; } else if (DwStrcasecmp(aFieldName, "resent-cc") == 0) { fieldBodyType = kAddressList; } else if (DwStrcasecmp(aFieldName, "resent-date") == 0) { fieldBodyType = kDateTime; } else if (DwStrcasecmp(aFieldName, "resent-from") == 0) { fieldBodyType = kMailboxList; } else if (DwStrcasecmp(aFieldName, "resent-message-id") == 0) { fieldBodyType = kMsgId; } else if (DwStrcasecmp(aFieldName, "resent-reply-to") == 0) { fieldBodyType = kAddressList; } else if (DwStrcasecmp(aFieldName, "resent-sender") == 0) { fieldBodyType = kMailbox; } else if (DwStrcasecmp(aFieldName, "return-path") == 0) { fieldBodyType = kMailbox; } break; case 's': if (DwStrcasecmp(aFieldName, "sender") == 0) { fieldBodyType = kMailbox; } break; case 't': if (DwStrcasecmp(aFieldName, "to") == 0) { fieldBodyType = kAddressList; } break; } DwFieldBody* fieldBody; switch (fieldBodyType) { case kAddressList: fieldBody = DwAddressList::NewAddressList(aFieldBody, aParent); break; case kDispositionType: fieldBody = DwDispositionType::NewDispositionType(aFieldBody, aParent); break; case kMediaType: fieldBody = DwMediaType::NewMediaType(aFieldBody, aParent); break; case kMechanism: fieldBody = DwMechanism::NewMechanism(aFieldBody, aParent); break; case kDateTime: fieldBody = DwDateTime::NewDateTime(aFieldBody, aParent); break; case kMailbox: fieldBody = DwMailbox::NewMailbox(aFieldBody, aParent); break; case kMailboxList: fieldBody = DwMailboxList::NewMailboxList(aFieldBody, aParent); break; case kMsgId: fieldBody = DwMsgId::NewMsgId(aFieldBody, aParent); break; case kText: default: fieldBody = DwText::NewText(aFieldBody, aParent); break; } return fieldBody; } #if defined (DW_DEBUG_VERSION) void DwField::PrintDebugInfo(std::ostream& aStrm, int aDepth) const { aStrm << "----------------- Debug info for DwField class -----------------\n"; _PrintDebugInfo(aStrm); int depth = aDepth - 1; depth = (depth >= 0) ? depth : 0; if (mFieldBody && (aDepth == 0 || depth > 0)) { mFieldBody->PrintDebugInfo(aStrm, depth); } } #else void DwField::PrintDebugInfo(std::ostream& , int ) const {} #endif // defined (DW_DEBUG_VERSION) #if defined (DW_DEBUG_VERSION) void DwField::_PrintDebugInfo(std::ostream& aStrm) const { DwMessageComponent::_PrintDebugInfo(aStrm); aStrm << "Field name: " << mFieldNameStr << '\n'; aStrm << "Field body: " << mFieldBodyStr << '\n'; aStrm << "Field body object:"; if (mFieldBody) { aStrm << mFieldBody->ObjectId() << '\n'; } else { aStrm << "(none)\n"; } aStrm << "Next field: "; if (mNext) { aStrm << mNext->ObjectId() << '\n'; } else { aStrm << "(none)\n"; } } #else void DwField::_PrintDebugInfo(std::ostream& ) const {} #endif // defined (DW_DEBUG_VERSION) void DwField::CheckInvariants() const { #if defined (DW_DEBUG_VERSION) DwMessageComponent::CheckInvariants(); mFieldNameStr.CheckInvariants(); mFieldBodyStr.CheckInvariants(); if (mFieldBody) { mFieldBody->CheckInvariants(); } if (mFieldBody) { assert((DwMessageComponent*) this == mFieldBody->Parent()); } #endif // defined (DW_DEBUG_VERSION) }