summaryrefslogtreecommitdiffstats
path: root/mimelib/field.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mimelib/field.cpp')
-rw-r--r--mimelib/field.cpp514
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)
+}