diff options
Diffstat (limited to 'mimelib/field.cpp')
-rw-r--r-- | mimelib/field.cpp | 514 |
1 files changed, 514 insertions, 0 deletions
diff --git a/mimelib/field.cpp b/mimelib/field.cpp new file mode 100644 index 000000000..a9f140b89 --- /dev/null +++ b/mimelib/field.cpp @@ -0,0 +1,514 @@ +//============================================================================= +// File: field.cpp +// Contents: Definitions for DwField +// 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 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 <mimelib/config.h> +#include <mimelib/debug.h> +#include <assert.h> +#include <ctype.h> +#include <iostream> +#include <stdlib.h> +#include <string.h> +#include <mimelib/string.h> +#include <mimelib/field.h> +#include <mimelib/headers.h> +#include <mimelib/fieldbdy.h> +#include <mimelib/datetime.h> +#include <mimelib/mailbox.h> +#include <mimelib/mboxlist.h> +#include <mimelib/address.h> +#include <mimelib/addrlist.h> +#include <mimelib/mechansm.h> +#include <mimelib/mediatyp.h> +#include <mimelib/msgid.h> +#include <mimelib/text.h> + + +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) +} |