From acfa9ffc64f56de42049bf5049810c15477729ed Mon Sep 17 00:00:00 2001 From: Vincent Richard Date: Fri, 4 Nov 2005 23:21:22 +0000 Subject: [PATCH] Refactored header field values and parameters. --- ChangeLog | 4 + SConstruct | 3 - src/addressList.cpp | 2 +- src/attachmentHelper.cpp | 12 +- src/base.cpp | 2 - src/body.cpp | 15 +- src/bodyPartAttachment.cpp | 11 +- src/contentDisposition.cpp | 2 +- src/contentDispositionField.cpp | 30 +- src/contentTypeField.cpp | 19 +- src/dateTime.cpp | 2 +- src/defaultAttachment.cpp | 2 + src/defaultParameter.cpp | 437 ------------------ src/encoding.cpp | 2 +- src/fileAttachment.cpp | 5 +- src/headerField.cpp | 47 +- src/headerFieldFactory.cpp | 103 +++-- src/htmlTextPart.cpp | 56 ++- src/mailboxField.cpp | 19 +- src/mailboxList.cpp | 2 +- src/mdn/MDNHelper.cpp | 58 ++- src/mdn/receivedMDNInfos.cpp | 7 +- src/messageBuilder.cpp | 1 + src/messageId.cpp | 2 +- src/messageIdSequence.cpp | 2 +- src/messageParser.cpp | 46 +- src/misc/importanceHelper.cpp | 15 +- src/net/transport.cpp | 28 +- src/parameter.cpp | 423 ++++++++++++++--- src/parameterFactory.cpp | 103 ----- src/parameterizedHeaderField.cpp | 7 +- src/path.cpp | 2 +- src/plainTextPart.cpp | 8 +- src/relay.cpp | 2 +- src/text.cpp | 16 +- src/word.cpp | 2 +- tests/misc/importanceHelperTest.cpp | 4 +- tests/parser/parameterTest.cpp | 59 ++- vmime/address.hpp | 4 +- vmime/addressList.hpp | 4 +- vmime/bodyPartAttachment.hpp | 3 + vmime/contentDisposition.hpp | 4 +- vmime/contentDispositionField.hpp | 59 ++- vmime/contentTypeField.hpp | 22 +- vmime/dateTime.hpp | 4 +- vmime/defaultParameter.hpp | 77 --- vmime/disposition.hpp | 4 +- vmime/encoding.hpp | 4 +- vmime/fileAttachment.hpp | 2 + vmime/header.hpp | 63 ++- vmime/headerField.hpp | 40 +- vmime/headerFieldFactory.hpp | 52 ++- .../headerFieldValue.hpp | 28 +- vmime/mailboxField.hpp | 16 +- vmime/mailboxList.hpp | 2 +- vmime/mdn/MDNHelper.hpp | 2 + vmime/mdn/receivedMDNInfos.hpp | 3 + vmime/mdn/sendableMDNInfos.hpp | 2 + vmime/mediaType.hpp | 4 +- vmime/messageId.hpp | 4 +- vmime/messageIdSequence.hpp | 2 +- vmime/messageParser.hpp | 4 + vmime/net/message.hpp | 1 + vmime/net/pop3/POP3Store.hpp | 1 + vmime/net/transport.hpp | 2 + vmime/parameter.hpp | 77 ++- vmime/parameterFactory.hpp | 97 ---- vmime/parameterizedHeaderField.hpp | 5 +- vmime/path.hpp | 4 +- vmime/relay.hpp | 4 +- vmime/text.hpp | 11 +- vmime/typeAdapter.hpp | 159 ------- vmime/vmime.hpp | 3 +- vmime/word.hpp | 4 +- 74 files changed, 1058 insertions(+), 1279 deletions(-) delete mode 100644 src/defaultParameter.cpp delete mode 100644 src/parameterFactory.cpp delete mode 100644 vmime/defaultParameter.hpp rename src/typeAdapter.cpp => vmime/headerFieldValue.hpp (67%) delete mode 100644 vmime/parameterFactory.hpp delete mode 100644 vmime/typeAdapter.hpp diff --git a/ChangeLog b/ChangeLog index 78cbf785..8367a451 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,10 @@ VERSION 0.7.2cvs ================ +2005-11-05 Vincent Richard + + * Refactored header field values and parameters. + 2005-10-19 Vincent Richard * charsetConverter.{hpp|cpp}: new object 'charsetConverter' for converting diff --git a/SConstruct b/SConstruct index 9ae6da73..000fee3e 100644 --- a/SConstruct +++ b/SConstruct @@ -91,7 +91,6 @@ libvmime_sources = [ 'contentTypeField.cpp', 'contentTypeField.hpp', 'dateTime.cpp', 'dateTime.hpp', 'defaultAttachment.cpp', 'defaultAttachment.hpp', - 'defaultParameter.cpp', 'defaultParameter.hpp', 'disposition.cpp', 'disposition.hpp', 'emptyContentHandler.cpp', 'emptyContentHandler.hpp', 'encoder.cpp', 'encoder.hpp', @@ -126,7 +125,6 @@ libvmime_sources = [ 'options.cpp', 'options.hpp', 'path.cpp', 'path.hpp', 'parameter.cpp', 'parameter.hpp', - 'parameterFactory.cpp', 'parameterFactory.hpp', 'parameterizedHeaderField.cpp', 'parameterizedHeaderField.hpp', 'parserHelpers.hpp', 'plainTextPart.cpp', 'plainTextPart.hpp', @@ -140,7 +138,6 @@ libvmime_sources = [ 'text.cpp', 'text.hpp', 'textPartFactory.cpp', 'textPartFactory.hpp', 'textPart.hpp', - 'typeAdapter.cpp', 'typeAdapter.hpp', 'types.hpp', 'word.cpp', 'word.hpp', 'vmime.hpp', diff --git a/src/addressList.cpp b/src/addressList.cpp index 09e36cd6..db3eabf7 100644 --- a/src/addressList.cpp +++ b/src/addressList.cpp @@ -37,7 +37,7 @@ addressList::addressList() addressList::addressList(const addressList& addrList) - : component() + : headerFieldValue() { copyFrom(addrList); } diff --git a/src/attachmentHelper.cpp b/src/attachmentHelper.cpp index 82e19f3f..9c080472 100644 --- a/src/attachmentHelper.cpp +++ b/src/attachmentHelper.cpp @@ -24,6 +24,7 @@ #include "vmime/attachmentHelper.hpp" #include "vmime/bodyPartAttachment.hpp" +#include "vmime/disposition.hpp" namespace vmime @@ -38,10 +39,13 @@ const bool attachmentHelper::isBodyPartAnAttachment(ref part) const contentDispositionField& cdf = dynamic_cast (*part->getHeader()->findField(fields::CONTENT_DISPOSITION)); - if (cdf.getValue().getName() != contentDispositionTypes::INLINE) + const contentDisposition disp = *cdf.getValue() + .dynamicCast (); + + if (disp.getName() != contentDispositionTypes::INLINE) return true; } - catch (exceptions::no_such_field) + catch (exceptions::no_such_field&) { // No "Content-disposition" field: assume "attachment" if // type is not "text/..." or "multipart/...". @@ -52,9 +56,9 @@ const bool attachmentHelper::isBodyPartAnAttachment(ref part) const contentTypeField& ctf = dynamic_cast (*part->getHeader()->findField(fields::CONTENT_TYPE)); - type = ctf.getValue(); + type = *ctf.getValue().dynamicCast (); } - catch (exceptions::no_such_field) + catch (exceptions::no_such_field&) { // No "Content-type" field: assume "application/octet-stream". type = mediaType(mediaTypes::APPLICATION, diff --git a/src/base.cpp b/src/base.cpp index 70651cbe..8170a9b8 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -39,7 +39,6 @@ // For initializing #include "vmime/encoderFactory.hpp" #include "vmime/headerFieldFactory.hpp" -#include "vmime/parameterFactory.hpp" #include "vmime/textPartFactory.hpp" #include "vmime/options.hpp" @@ -143,7 +142,6 @@ public: encoderFactory::getInstance(); headerFieldFactory::getInstance(); - parameterFactory::getInstance(); textPartFactory::getInstance(); #if VMIME_HAVE_MESSAGING_FEATURES diff --git a/src/body.cpp b/src/body.cpp index e2fcf0ad..cee72d0a 100644 --- a/src/body.cpp +++ b/src/body.cpp @@ -27,6 +27,7 @@ #include "vmime/options.hpp" #include "vmime/contentTypeField.hpp" +#include "vmime/text.hpp" #include "vmime/utility/random.hpp" @@ -65,7 +66,9 @@ void body::parse(const string& buffer, const string::size_type position, const ref ctf = m_header->findField(fields::CONTENT_TYPE).dynamicCast (); - if (ctf->getValue().getType() == mediaTypes::MULTIPART) + const mediaType type = *ctf->getValue().dynamicCast (); + + if (type.getType() == mediaTypes::MULTIPART) { isMultipart = true; @@ -388,7 +391,7 @@ const mediaType body::getContentType() const ref ctf = m_header->findField(fields::CONTENT_TYPE).dynamicCast (); - return (ctf->getValue()); + return (*ctf->getValue().dynamicCast ()); } catch (exceptions::no_such_field&) { @@ -424,10 +427,10 @@ const encoding body::getEncoding() const { try { - const ref cef = - m_header->findField(fields::CONTENT_TRANSFER_ENCODING).dynamicCast (); + const ref cef = + m_header->findField(fields::CONTENT_TRANSFER_ENCODING); - return (cef->getValue()); + return (*cef->getValue().dynamicCast ()); } catch (exceptions::no_such_field&) { @@ -550,7 +553,7 @@ void body::initNewPart(ref part) ctf->setBoundary(generateRandomBoundaryString()); } - if (ctf->getValue().getType() != mediaTypes::MULTIPART) + if (ctf->getValue().dynamicCast ()->getType() != mediaTypes::MULTIPART) { // Warning: multi-part body but the Content-Type is // not specified as "multipart/..." diff --git a/src/bodyPartAttachment.cpp b/src/bodyPartAttachment.cpp index adf605d3..c40b84b2 100644 --- a/src/bodyPartAttachment.cpp +++ b/src/bodyPartAttachment.cpp @@ -40,7 +40,7 @@ const mediaType bodyPartAttachment::getType() const try { - type = getContentType()->getValue(); + type = *getContentType()->getValue().dynamicCast (); } catch (exceptions::no_such_field&) { @@ -76,8 +76,7 @@ const word bodyPartAttachment::getName() const { try { - ref prm = getContentType()-> - findParameter("name").dynamicCast (); + ref prm = getContentType()->findParameter("name"); if (prm != NULL) name = prm->getValue(); @@ -102,10 +101,10 @@ const text bodyPartAttachment::getDescription() const try { - const textField& cd = dynamic_cast - (*getHeader()->findField(fields::CONTENT_DESCRIPTION)); + ref cd = + getHeader()->findField(fields::CONTENT_DESCRIPTION); - description = cd.getValue(); + description = *cd->getValue().dynamicCast (); } catch (exceptions::no_such_field&) { diff --git a/src/contentDisposition.cpp b/src/contentDisposition.cpp index b906b2da..7f17dd37 100644 --- a/src/contentDisposition.cpp +++ b/src/contentDisposition.cpp @@ -42,7 +42,7 @@ contentDisposition::contentDisposition(const string& name) contentDisposition::contentDisposition(const contentDisposition& type) - : component(), m_name(type.m_name) + : headerFieldValue(), m_name(type.m_name) { } diff --git a/src/contentDispositionField.cpp b/src/contentDispositionField.cpp index cf033ff0..f364785b 100644 --- a/src/contentDispositionField.cpp +++ b/src/contentDispositionField.cpp @@ -24,8 +24,6 @@ #include "vmime/contentDispositionField.hpp" #include "vmime/exception.hpp" -#include "vmime/standardParams.hpp" - namespace vmime { @@ -37,68 +35,68 @@ contentDispositionField::contentDispositionField() contentDispositionField::contentDispositionField(contentDispositionField&) - : headerField(), parameterizedHeaderField(), genericField () + : headerField(), parameterizedHeaderField() { } -const datetime& contentDispositionField::getCreationDate() const +const datetime contentDispositionField::getCreationDate() const { - return (dynamic_cast (*findParameter("creation-date")).getValue()); + return findParameter("creation-date")->getValueAs (); } void contentDispositionField::setCreationDate(const datetime& creationDate) { - dynamic_cast (*getParameter("creation-date")).setValue(creationDate); + getParameter("creation-date")->setValue(creationDate); } -const datetime& contentDispositionField::getModificationDate() const +const datetime contentDispositionField::getModificationDate() const { - return (dynamic_cast (*findParameter("modification-date")).getValue()); + return findParameter("modification-date")->getValueAs (); } void contentDispositionField::setModificationDate(const datetime& modificationDate) { - dynamic_cast (*getParameter("modification-date")).setValue(modificationDate); + getParameter("modification-date")->setValue(modificationDate); } -const datetime& contentDispositionField::getReadDate() const +const datetime contentDispositionField::getReadDate() const { - return (dynamic_cast (*findParameter("read-date")).getValue()); + return findParameter("read-date")->getValueAs (); } void contentDispositionField::setReadDate(const datetime& readDate) { - dynamic_cast (*getParameter("read-date")).setValue(readDate); + getParameter("read-date")->setValue(readDate); } const word contentDispositionField::getFilename() const { - return (dynamic_cast (*findParameter("filename")).getValue()); + return findParameter("filename")->getValue(); } void contentDispositionField::setFilename(const word& filename) { - dynamic_cast (*getParameter("filename")).setValue(filename); + getParameter("filename")->setValue(filename); } const string contentDispositionField::getSize() const { - return (dynamic_cast (*findParameter("size")).getValue().getBuffer()); + return findParameter("size")->getValue().getBuffer(); } void contentDispositionField::setSize(const string& size) { - dynamic_cast (*getParameter("size")).setValue(word(size)); + getParameter("size")->setValue(word(size, vmime::charsets::US_ASCII)); } diff --git a/src/contentTypeField.cpp b/src/contentTypeField.cpp index 1b46ffc3..852f9961 100644 --- a/src/contentTypeField.cpp +++ b/src/contentTypeField.cpp @@ -24,8 +24,6 @@ #include "vmime/contentTypeField.hpp" #include "vmime/exception.hpp" -#include "vmime/standardParams.hpp" - namespace vmime { @@ -37,45 +35,46 @@ contentTypeField::contentTypeField() contentTypeField::contentTypeField(contentTypeField&) - : headerField(), parameterizedHeaderField(), genericField () + : headerField(), parameterizedHeaderField() { } const string contentTypeField::getBoundary() const { - return (dynamic_cast (*findParameter("boundary")).getValue().getBuffer()); + return findParameter("boundary")->getValue().getBuffer(); } void contentTypeField::setBoundary(const string& boundary) { - dynamic_cast (*getParameter("boundary")).setValue(word(boundary)); + getParameter("boundary")->setValue(word(boundary, vmime::charsets::US_ASCII)); } -const charset& contentTypeField::getCharset() const +const charset contentTypeField::getCharset() const { - return (dynamic_cast (*findParameter("charset")).getValue()); + return findParameter("charset")->getValueAs (); } void contentTypeField::setCharset(const charset& ch) { - dynamic_cast (*getParameter("charset")).setValue(ch); + getParameter("charset")->setValue(ch); } const string contentTypeField::getReportType() const { - return (dynamic_cast (*findParameter("report-type")).getValue().getBuffer()); + return findParameter("report-type")->getValue().getBuffer(); } void contentTypeField::setReportType(const string& reportType) { - dynamic_cast (*getParameter("report-type")).setValue(word(reportType)); + getParameter("report-type")->setValue(word(reportType, vmime::charsets::US_ASCII)); } } // vmime + diff --git a/src/dateTime.cpp b/src/dateTime.cpp index 36aafe2a..ea965805 100644 --- a/src/dateTime.cpp +++ b/src/dateTime.cpp @@ -640,7 +640,7 @@ datetime::datetime(const int year, const int month, const int day, datetime::datetime(const datetime& d) - : component(), m_year(d.m_year), m_month(d.m_month), m_day(d.m_day), + : headerFieldValue(), m_year(d.m_year), m_month(d.m_month), m_day(d.m_day), m_hour(d.m_hour), m_minute(d.m_minute), m_second(d.m_second), m_zone(d.m_zone) { } diff --git a/src/defaultAttachment.cpp b/src/defaultAttachment.cpp index 909dca10..463bc89c 100644 --- a/src/defaultAttachment.cpp +++ b/src/defaultAttachment.cpp @@ -22,6 +22,8 @@ // #include "vmime/defaultAttachment.hpp" + +#include "vmime/contentDisposition.hpp" #include "vmime/encoding.hpp" diff --git a/src/defaultParameter.cpp b/src/defaultParameter.cpp deleted file mode 100644 index 2cb8c156..00000000 --- a/src/defaultParameter.cpp +++ /dev/null @@ -1,437 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2005 Vincent Richard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// Linking this library statically or dynamically with other modules is making -// a combined work based on this library. Thus, the terms and conditions of -// the GNU General Public License cover the whole combination. -// - -#include "vmime/defaultParameter.hpp" -#include "vmime/parserHelpers.hpp" - - -namespace vmime -{ - - -defaultParameter::defaultParameter() - : m_value(vmime::create ()) -{ -} - - -defaultParameter& defaultParameter::operator=(const defaultParameter& other) -{ - copyFrom(other); - return (*this); -} - - -const ref defaultParameter::getValueImp() const -{ - return (m_value); -} - - -const ref defaultParameter::getValueImp() -{ - return (m_value); -} - - -const word& defaultParameter::getValue() const -{ - return (*m_value); -} - - -word& defaultParameter::getValue() -{ - return (*m_value); -} - - -void defaultParameter::setValue(const word& value) -{ - *m_value = value; -} - - -void defaultParameter::setValue(const component& value) -{ - const word& v = dynamic_cast (value); - *m_value = v; -} - - -void defaultParameter::parse(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) -{ - m_value = vmime::create - (string(buffer.begin() + position, buffer.begin() + end), - charset(charsets::US_ASCII)); - - if (newPosition) - *newPosition = end; -} - - -void defaultParameter::parse(const std::vector & chunks) -{ - bool foundCharsetChunk = false; - - charset ch(charsets::US_ASCII); - std::ostringstream value; - - for (std::vector ::size_type i = 0 ; i < chunks.size() ; ++i) - { - const valueChunk& chunk = chunks[i]; - - // Decode following data - if (chunk.encoded) - { - const string::size_type len = chunk.data.length(); - string::size_type pos = 0; - - // If this is the first encoded chunk, extract charset - // and language information - if (!foundCharsetChunk) - { - // Eg. "us-ascii'en'This%20is%20even%20more%20" - string::size_type q = chunk.data.find_first_of('\''); - - if (q != string::npos) - { - const string chs = chunk.data.substr(0, q); - - if (!chs.empty()) - ch = charset(chs); - - ++q; - pos = q; - } - - q = chunk.data.find_first_of('\'', pos); - - if (q != string::npos) - { - // Ignore language - ++q; - pos = q; - } - - foundCharsetChunk = true; - } - - for (string::size_type i = pos ; i < len ; ++i) - { - const string::value_type c = chunk.data[i]; - - if (c == '%' && i + 2 < len) - { - string::value_type v = 0; - - // First char - switch (chunk.data[i + 1]) - { - case 'a': case 'A': v += 10; break; - case 'b': case 'B': v += 11; break; - case 'c': case 'C': v += 12; break; - case 'd': case 'D': v += 13; break; - case 'e': case 'E': v += 14; break; - case 'f': case 'F': v += 15; break; - default: // assume 0-9 - - v += (chunk.data[i + 1] - '0'); - break; - } - - v *= 16; - - // Second char - switch (chunk.data[i + 2]) - { - case 'a': case 'A': v += 10; break; - case 'b': case 'B': v += 11; break; - case 'c': case 'C': v += 12; break; - case 'd': case 'D': v += 13; break; - case 'e': case 'E': v += 14; break; - case 'f': case 'F': v += 15; break; - default: // assume 0-9 - - v += (chunk.data[i + 2] - '0'); - break; - } - - value << v; - - i += 2; // skip next 2 chars - } - else - { - value << c; - } - } - } - // Simply copy data, as it is not encoded - else - { - value << chunk.data; - } - } - - m_value = vmime::create (value.str(), ch); -} - - -void defaultParameter::generate(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type curLinePos, string::size_type* newLinePos) const -{ - const string& name = getName(); - const string& value = m_value->getBuffer(); - - // For compatibility with implementations that do not understand RFC-2231, - // also generate a normal "7bit/us-ascii" parameter - string::size_type pos = curLinePos; - - if (pos + name.length() + 10 + value.length() > maxLineLength) - { - os << NEW_LINE_SEQUENCE; - pos = NEW_LINE_SEQUENCE_LENGTH; - } - - bool needQuoting = false; - string::size_type valueLength = 0; - - for (string::size_type i = 0 ; (i < value.length()) && (pos + valueLength < maxLineLength - 4) ; ++i, ++valueLength) - { - switch (value[i]) - { - // Characters that need to be quoted _and_ escaped - case '"': - case '\\': - // Other characters that need quoting - case ' ': - case '\t': - case '(': - case ')': - case '<': - case '>': - case '@': - case ',': - case ';': - case ':': - case '/': - case '[': - case ']': - case '?': - case '=': - - needQuoting = true; - break; - } - } - - const bool cutValue = (valueLength != value.length()); // has the value been cut? - - if (needQuoting) - { - os << name << "=\""; - pos += name.length() + 2; - } - else - { - os << name << "="; - pos += name.length() + 1; - } - - bool extended = false; - - for (string::size_type i = 0 ; (i < value.length()) && (pos < maxLineLength - 4) ; ++i) - { - const char_t c = value[i]; - - if (/* needQuoting && */ (c == '"' || c == '\\')) // 'needQuoting' is implicit - { - os << '\\' << value[i]; // escape 'x' with '\x' - pos += 2; - } - else if (parserHelpers::isAscii(c)) - { - os << value[i]; - ++pos; - } - else - { - extended = true; - } - } - - if (needQuoting) - { - os << '"'; - ++pos; - } - - // Also generate an extended parameter if the value contains 8-bit characters - // or is too long for a single line - if (extended || cutValue) - { - os << ';'; - ++pos; - - /* RFC-2231 - * ======== - * - * Content-Type: message/external-body; access-type=URL; - * URL*0="ftp://"; - * URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar" - * - * Content-Type: application/x-stuff; - * title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A - * - * Content-Type: application/x-stuff; - * title*0*=us-ascii'en'This%20is%20even%20more%20 - * title*1*=%2A%2A%2Afun%2A%2A%2A%20 - * title*2="isn't it!" - */ - - // Check whether there is enough space for the first section: - // parameter name, section identifier, charset and separators - // + at least 5 characters for the value - const string::size_type firstSectionLength = - name.length() + 4 /* *0*= */ + 2 /* '' */ - + m_value->getCharset().getName().length(); - - if (pos + firstSectionLength + 5 >= maxLineLength) - { - os << NEW_LINE_SEQUENCE; - pos = NEW_LINE_SEQUENCE_LENGTH; - } - - // Split text into multiple sections that fit on one line - int sectionCount = 0; - std::vector sectionText; - - string currentSection; - string::size_type currentSectionLength = firstSectionLength; - - for (string::size_type i = 0 ; i < value.length() ; ++i) - { - // Check whether we should start a new line (taking into - // account the next character will be encoded = worst case) - if (currentSectionLength + 3 >= maxLineLength) - { - sectionText.push_back(currentSection); - sectionCount++; - - currentSection.clear(); - currentSectionLength = NEW_LINE_SEQUENCE_LENGTH - + name.length() + 6; - } - - // Output next character - const char_t c = value[i]; - bool encode = false; - - switch (c) - { - // special characters - case ' ': - case '\t': - case '\r': - case '\n': - case '"': - case ';': - case ',': - - encode = true; - break; - - default: - - encode = (!parserHelpers::isPrint(c) || - !parserHelpers::isAscii(c)); - - break; - } - - if (encode) // need encoding - { - const int h1 = static_cast (c) / 16; - const int h2 = static_cast (c) % 16; - - currentSection += '%'; - currentSection += "0123456789ABCDEF"[h1]; - currentSection += "0123456789ABCDEF"[h2]; - - pos += 3; - currentSectionLength += 3; - } - else - { - currentSection += value[i]; - - ++pos; - ++currentSectionLength; - } - } - - if (!currentSection.empty()) - { - sectionText.push_back(currentSection); - sectionCount++; - } - - // Output sections - for (int sectionNumber = 0 ; sectionNumber < sectionCount ; ++sectionNumber) - { - os << name; - - if (sectionCount != 1) // no section specifier when only a single one - { - os << '*'; - os << sectionNumber; - } - - os << "*="; - - if (sectionNumber == 0) - { - os << m_value->getCharset().getName(); - os << '\'' << /* No language */ '\''; - } - - os << sectionText[sectionNumber]; - - if (sectionNumber + 1 < sectionCount) - { - os << ';'; - os << NEW_LINE_SEQUENCE; - pos = NEW_LINE_SEQUENCE_LENGTH; - } - } - } - - if (newLinePos) - *newLinePos = pos; -} - - - -} // vmime diff --git a/src/encoding.cpp b/src/encoding.cpp index 4465021d..f2b40ed0 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -45,7 +45,7 @@ encoding::encoding(const string& name) encoding::encoding(const encoding& enc) - : component(), m_name(enc.m_name) + : headerFieldValue(), m_name(enc.m_name) { } diff --git a/src/fileAttachment.cpp b/src/fileAttachment.cpp index 584ba12a..785e0b8e 100644 --- a/src/fileAttachment.cpp +++ b/src/fileAttachment.cpp @@ -29,6 +29,8 @@ #include "vmime/streamContentHandler.hpp" +#include "vmime/contentDispositionField.hpp" + namespace vmime { @@ -78,7 +80,8 @@ void fileAttachment::generatePart(bodyPart& part) const { defaultAttachment::generatePart(part); - ref cdf = part.getHeader()->ContentDisposition(); + ref cdf = part.getHeader()->ContentDisposition(). + dynamicCast (); if (m_fileInfo.hasSize()) cdf->setSize(utility::stringUtils::toString(m_fileInfo.getSize())); if (m_fileInfo.hasFilename()) cdf->setFilename(m_fileInfo.getFilename()); diff --git a/src/headerField.cpp b/src/headerField.cpp index 87524fbf..13b6ae4f 100644 --- a/src/headerField.cpp +++ b/src/headerField.cpp @@ -62,7 +62,7 @@ void headerField::copyFrom(const component& other) { const headerField& hf = dynamic_cast (other); - getValue().copyFrom(hf.getValue()); + m_value->copyFrom(*hf.m_value); } @@ -227,7 +227,7 @@ ref headerField::parseNext(const string& buffer, const string::siz void headerField::parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition) { - getValue().parse(buffer, position, end, newPosition); + m_value->parse(buffer, position, end, newPosition); } @@ -236,13 +236,19 @@ void headerField::generate(utility::outputStream& os, const string::size_type ma { os << m_name + ": "; - getValue().generate(os, maxLineLength, curLinePos + m_name.length() + 2, newLinePos); + m_value->generate(os, maxLineLength, curLinePos + m_name.length() + 2, newLinePos); } const string headerField::getName() const { - return (m_name); + return m_name; +} + + +void headerField::setName(const string& name) +{ + m_name = name; } @@ -256,12 +262,43 @@ const std::vector > headerField::getChildComponents() con { std::vector > list; - list.push_back(getValueImp()); + list.push_back(m_value); return (list); } +ref headerField::getValue() const +{ + return m_value; +} + + +ref headerField::getValue() +{ + return m_value; +} + + +void headerField::setValue(ref value) +{ + if (value != NULL) + m_value = value; +} + + +void headerField::setValueConst(ref value) +{ + m_value = value->clone().dynamicCast (); +} + + +void headerField::setValue(const headerFieldValue& value) +{ + m_value = value.clone().dynamicCast (); +} + + void headerField::setValue(const string& value) { parse(value); diff --git a/src/headerFieldFactory.cpp b/src/headerFieldFactory.cpp index 98a6f300..61782c2b 100644 --- a/src/headerFieldFactory.cpp +++ b/src/headerFieldFactory.cpp @@ -24,11 +24,18 @@ #include "vmime/headerFieldFactory.hpp" #include "vmime/exception.hpp" -#include "vmime/standardFields.hpp" +#include "vmime/mailboxList.hpp" +#include "vmime/dateTime.hpp" +#include "vmime/text.hpp" +#include "vmime/path.hpp" +#include "vmime/relay.hpp" +#include "vmime/encoding.hpp" +#include "vmime/disposition.hpp" +#include "vmime/messageIdSequence.hpp" -#include "vmime/mailboxField.hpp" #include "vmime/contentTypeField.hpp" #include "vmime/contentDispositionField.hpp" +#include "vmime/mailboxField.hpp" namespace vmime @@ -37,34 +44,44 @@ namespace vmime headerFieldFactory::headerFieldFactory() { - // Register some default fields - registerName (vmime::fields::FROM); - registerName (vmime::fields::TO); - registerName (vmime::fields::CC); - registerName (vmime::fields::BCC); - registerName (vmime::fields::SENDER); - registerName (vmime::fields::DATE); - registerName (vmime::fields::RECEIVED); - registerName (vmime::fields::SUBJECT); - registerName (vmime::fields::REPLY_TO); - registerName (vmime::fields::DELIVERED_TO); - registerName (vmime::fields::ORGANIZATION); - registerName (vmime::fields::USER_AGENT); - registerName (vmime::fields::RETURN_PATH); - registerName (vmime::fields::CONTENT_TYPE); - registerName (vmime::fields::CONTENT_TRANSFER_ENCODING); - registerName (vmime::fields::CONTENT_DESCRIPTION); - registerName (vmime::fields::MIME_VERSION); - registerName (vmime::fields::CONTENT_DISPOSITION); - registerName (vmime::fields::CONTENT_ID); - registerName (vmime::fields::MESSAGE_ID); - registerName (vmime::fields::CONTENT_LOCATION); - registerName (vmime::fields::IN_REPLY_TO); - registerName (vmime::fields::REFERENCES); + // Register parameterized fields + registerField (vmime::fields::CONTENT_TYPE); + registerField (vmime::fields::CONTENT_TRANSFER_ENCODING); + registerField (vmime::fields::CONTENT_DISPOSITION); - registerName (vmime::fields::ORIGINAL_MESSAGE_ID); - registerName (vmime::fields::DISPOSITION); - registerName (vmime::fields::DISPOSITION_NOTIFICATION_TO); + registerField (vmime::fields::FROM); + registerField (vmime::fields::SENDER); + registerField (vmime::fields::REPLY_TO); + registerField (vmime::fields::DELIVERED_TO); + + // Register standard field values + registerFieldValue (vmime::fields::FROM); + registerFieldValue (vmime::fields::TO); + registerFieldValue (vmime::fields::CC); + registerFieldValue (vmime::fields::BCC); + registerFieldValue (vmime::fields::SENDER); + registerFieldValue (vmime::fields::DATE); + registerFieldValue (vmime::fields::RECEIVED); + registerFieldValue (vmime::fields::SUBJECT); + registerFieldValue (vmime::fields::REPLY_TO); + registerFieldValue (vmime::fields::DELIVERED_TO); + registerFieldValue (vmime::fields::ORGANIZATION); + registerFieldValue (vmime::fields::USER_AGENT); + registerFieldValue (vmime::fields::RETURN_PATH); + registerFieldValue (vmime::fields::CONTENT_TYPE); + registerFieldValue (vmime::fields::CONTENT_TRANSFER_ENCODING); + registerFieldValue (vmime::fields::CONTENT_DESCRIPTION); + registerFieldValue (vmime::fields::MIME_VERSION); + registerFieldValue (vmime::fields::CONTENT_DISPOSITION); + registerFieldValue (vmime::fields::CONTENT_ID); + registerFieldValue (vmime::fields::MESSAGE_ID); + registerFieldValue (vmime::fields::CONTENT_LOCATION); + registerFieldValue (vmime::fields::IN_REPLY_TO); + registerFieldValue (vmime::fields::REFERENCES); + + registerFieldValue (vmime::fields::ORIGINAL_MESSAGE_ID); + registerFieldValue (vmime::fields::DISPOSITION); + registerFieldValue (vmime::fields::DISPOSITION_NOTIFICATION_TO); } @@ -87,21 +104,35 @@ ref headerFieldFactory::create ref field = NULL; if (pos != m_nameMap.end()) - { field = ((*pos).second)(); - } else - { - field = registerer ::creator(); - } + field = registerer ::creator(); - field->m_name = name; + field->setName(name); + field->setValue(createValue(name)); if (body != NULL_STRING) field->parse(body); - return (field); + return field; +} + + +ref headerFieldFactory::createValue(const string& fieldName) +{ + ValueMap::const_iterator pos = m_valueMap.find + (utility::stringUtils::toLower(fieldName)); + + ref value = NULL; + + if (pos != m_valueMap.end()) + value = ((*pos).second)(); + else + value = registerer ::creator(); + + return value; } } // vmime + diff --git a/src/htmlTextPart.cpp b/src/htmlTextPart.cpp index 7d1f6896..b2cb3523 100644 --- a/src/htmlTextPart.cpp +++ b/src/htmlTextPart.cpp @@ -24,6 +24,10 @@ #include "vmime/htmlTextPart.hpp" #include "vmime/exception.hpp" +#include "vmime/contentTypeField.hpp" +#include "vmime/contentDisposition.hpp" +#include "vmime/text.hpp" + #include "vmime/emptyContentHandler.hpp" #include "vmime/stringContentHandler.hpp" @@ -66,8 +70,9 @@ void htmlTextPart::generateIn(bodyPart& /* message */, bodyPart& parent) const parent.getBody()->appendPart(part); // -- Set header fields - part->getHeader()->ContentType()->setValue(mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN)); - part->getHeader()->ContentType()->setCharset(m_charset); + part->getHeader()->ContentType()->setValue + (mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN)); + part->getHeader()->ContentType().dynamicCast ()->setCharset(m_charset); part->getHeader()->ContentTransferEncoding()->setValue(encoding(encodingTypes::QUOTED_PRINTABLE)); // -- Set contents @@ -80,7 +85,7 @@ void htmlTextPart::generateIn(bodyPart& /* message */, bodyPart& parent) const // -- Set header fields htmlPart->getHeader()->ContentType()->setValue(mediaType(mediaTypes::TEXT, mediaTypes::TEXT_HTML)); - htmlPart->getHeader()->ContentType()->setCharset(m_charset); + htmlPart->getHeader()->ContentType().dynamicCast ()->setCharset(m_charset); htmlPart->getHeader()->ContentTransferEncoding()->setValue(encoding(encodingTypes::QUOTED_PRINTABLE)); // -- Set contents @@ -167,8 +172,8 @@ void htmlTextPart::addEmbeddedObject(const bodyPart& part, const string& id) try { - const ref ctf = part.getHeader()->ContentType(); - type = ctf->getValue(); + const ref ctf = part.getHeader()->ContentType(); + type = *ctf->getValue().dynamicCast (); } catch (exceptions::no_such_field) { @@ -219,29 +224,34 @@ void htmlTextPart::parse(const bodyPart& message, const bodyPart& parent, const // found inline part, we check if its CID/Location is contained in the HTML text. for (std::vector >::const_iterator p = cidParts.begin() ; p != cidParts.end() ; ++p) { - const ref midField = - (*p)->getHeader()->findField(fields::CONTENT_ID).dynamicCast (); + const ref midField = + (*p)->getHeader()->findField(fields::CONTENT_ID); - const string searchFor("CID:" + midField->getValue().getId()); + const messageId mid = *midField->getValue().dynamicCast (); + + const string searchFor("CID:" + mid.getId()); if (data.find(searchFor) != string::npos) { // This part is referenced in the HTML text. // Add it to the embedded object list. - addEmbeddedObject(**p, "CID:" + midField->getValue().getId()); + addEmbeddedObject(**p, "CID:" + mid.getId()); } } for (std::vector >::const_iterator p = locParts.begin() ; p != locParts.end() ; ++p) { - const ref locField = - (*p)->getHeader()->findField(fields::CONTENT_LOCATION).dynamicCast (); + const ref locField = + (*p)->getHeader()->findField(fields::CONTENT_LOCATION); - if (data.find(locField->getValue()) != string::npos) + const text loc = *locField->getValue().dynamicCast (); + const string locStr = loc.getWholeBuffer(); + + if (data.find(locStr) != string::npos) { // This part is referenced in the HTML text. // Add it to the embedded object list. - addEmbeddedObject(**p, locField->getValue()); + addEmbeddedObject(**p, locStr); } } @@ -258,11 +268,13 @@ bool htmlTextPart::findPlainTextPart(const bodyPart& part, const bodyPart& paren // We search for the nearest "multipart/alternative" part. try { - const ref ctf = - part.getHeader()->findField(fields::CONTENT_TYPE).dynamicCast (); + const ref ctf = + part.getHeader()->findField(fields::CONTENT_TYPE); - if (ctf->getValue().getType() == mediaTypes::MULTIPART && - ctf->getValue().getSubType() == mediaTypes::MULTIPART_ALTERNATIVE) + const mediaType type = *ctf->getValue().dynamicCast (); + + if (type.getType() == mediaTypes::MULTIPART && + type.getSubType() == mediaTypes::MULTIPART_ALTERNATIVE) { ref foundPart = NULL; @@ -288,11 +300,13 @@ bool htmlTextPart::findPlainTextPart(const bodyPart& part, const bodyPart& paren try { - const ref ctf = - p->getHeader()->findField(fields::CONTENT_TYPE).dynamicCast (); + const ref ctf = + p->getHeader()->findField(fields::CONTENT_TYPE); - if (ctf->getValue().getType() == mediaTypes::TEXT && - ctf->getValue().getSubType() == mediaTypes::TEXT_PLAIN) + const mediaType type = *ctf->getValue().dynamicCast (); + + if (type.getType() == mediaTypes::TEXT && + type.getSubType() == mediaTypes::TEXT_PLAIN) { m_plainText = p->getBody()->getContents()->clone(); found = true; diff --git a/src/mailboxField.cpp b/src/mailboxField.cpp index bab461be..188fa17b 100644 --- a/src/mailboxField.cpp +++ b/src/mailboxField.cpp @@ -25,6 +25,9 @@ #include "vmime/mailboxGroup.hpp" +#ifndef VMIME_BUILDING_DOC + + namespace vmime { @@ -35,7 +38,7 @@ mailboxField::mailboxField() mailboxField::mailboxField(const mailboxField&) - : headerField(), genericField () + : headerField() { } @@ -43,7 +46,7 @@ mailboxField::mailboxField(const mailboxField&) void mailboxField::parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition) { - getValue().clear(); + ref mbox = vmime::create (); // Here, we cannot simply call "m_mailbox.parse()" because it // may have more than one address specified (even if this field @@ -59,16 +62,18 @@ void mailboxField::parse(const string& buffer, const string::size_type position, ref group = parsedAddress.staticCast (); if (!group->isEmpty()) - getValue() = *(group->getMailboxAt(0)); + mbox = group->getMailboxAt(0); } else { // Parse only if it is a mailbox - getValue() = *parsedAddress.staticCast (); + mbox = parsedAddress.staticCast (); } } - getValue().setParsedBounds(position, end); + mbox->setParsedBounds(position, end); + + setValue(mbox); setParsedBounds(position, end); @@ -78,3 +83,7 @@ void mailboxField::parse(const string& buffer, const string::size_type position, } // vmime + + +#endif // VMIME_BUILDING_DOC + diff --git a/src/mailboxList.cpp b/src/mailboxList.cpp index 4ff0b885..6e43059f 100644 --- a/src/mailboxList.cpp +++ b/src/mailboxList.cpp @@ -35,7 +35,7 @@ mailboxList::mailboxList() mailboxList::mailboxList(const mailboxList& mboxList) - : component(), m_list(mboxList.m_list) + : headerFieldValue(), m_list(mboxList.m_list) { } diff --git a/src/mdn/MDNHelper.cpp b/src/mdn/MDNHelper.cpp index b79b8713..a140a7a4 100644 --- a/src/mdn/MDNHelper.cpp +++ b/src/mdn/MDNHelper.cpp @@ -22,6 +22,11 @@ #include "vmime/exception.hpp" #include "vmime/stringContentHandler.hpp" +#include "vmime/contentTypeField.hpp" + +#include "vmime/path.hpp" +#include "vmime/dateTime.hpp" + namespace vmime { namespace mdn { @@ -52,7 +57,8 @@ const std::vector MDNHelper::getPossibleMDNs(const ref hasField(fields::DISPOSITION_NOTIFICATION_TO)) { - const mailboxList& dnto = hdr->DispositionNotificationTo()->getValue(); + const mailboxList& dnto = *hdr->DispositionNotificationTo()->getValue() + .dynamicCast (); for (int i = 0 ; i < dnto.getMailboxCount() ; ++i) result.push_back(sendableMDNInfos(msg, *dnto.getMailboxAt(i))); @@ -72,10 +78,13 @@ const bool MDNHelper::isMDN(const ref msg) // and its value is "disposition-notification" if (hdr->hasField(fields::CONTENT_TYPE)) { - const contentTypeField& ctf = *(hdr->ContentType()); + const contentTypeField& ctf = *(hdr->ContentType() + .dynamicCast ()); - if (ctf.getValue().getType() == vmime::mediaTypes::MULTIPART && - ctf.getValue().getSubType() == vmime::mediaTypes::MULTIPART_REPORT) + const mediaType type = *ctf.getValue().dynamicCast (); + + if (type.getType() == vmime::mediaTypes::MULTIPART && + type.getSubType() == vmime::mediaTypes::MULTIPART_REPORT) { if (ctf.hasParameter("report-type") && ctf.getReportType() == "disposition-notification") @@ -104,26 +113,29 @@ const bool MDNHelper::needConfirmation(const ref msg) // No "Return-Path" field if (!hdr->hasField(fields::RETURN_PATH)) - return (true); + return true; // More than one address in Disposition-Notification-To if (hdr->hasField(fields::DISPOSITION_NOTIFICATION_TO)) { - const mailboxList& dnto = hdr->DispositionNotificationTo()->getValue(); + const mailboxList& dnto = *hdr->DispositionNotificationTo()->getValue() + .dynamicCast (); if (dnto.getMailboxCount() > 1) - return (true); + return true; + else if (dnto.getMailboxCount() == 0) + return false; // Return-Path != Disposition-Notification-To const mailbox& mbox = *dnto.getMailboxAt(0); - const path& rp = hdr->ReturnPath()->getValue(); + const path& rp = *hdr->ReturnPath()->getValue().dynamicCast (); if (mbox.getEmail() != rp.getLocalPart() + "@" + rp.getDomain()) - return (true); + return true; } // User confirmation not needed - return (false); + return false; } @@ -143,13 +155,17 @@ ref MDNHelper::buildMDN(const sendableMDNInfos& mdnInfos, hdr->ContentType()->setValue(mediaType(vmime::mediaTypes::MULTIPART, vmime::mediaTypes::MULTIPART_REPORT)); - hdr->ContentType()->setReportType("disosition-notification"); + hdr->ContentType().dynamicCast ()->setReportType("disposition-notification"); hdr->Disposition()->setValue(dispo); - hdr->To()->getValue().appendAddress(vmime::create (mdnInfos.getRecipient())); - hdr->From()->getValue() = expeditor; - hdr->Subject()->getValue().appendWord(vmime::create ("Disposition notification")); + addressList to; + to.appendAddress(vmime::create (mdnInfos.getRecipient())); + hdr->To()->setValue(to); + + hdr->From()->setValue(expeditor); + + hdr->Subject()->setValue(vmime::text(word("Disposition notification"))); hdr->Date()->setValue(datetime::now()); hdr->MimeVersion()->setValue(string(SUPPORTED_MIME_VERSION)); @@ -174,7 +190,7 @@ ref MDNHelper::createFirstMDNPart(const sendableMDNInfos& /* mdnInfos hdr->ContentType()->setValue(mediaType(vmime::mediaTypes::TEXT, vmime::mediaTypes::TEXT_PLAIN)); - hdr->ContentType()->setCharset(ch); + hdr->ContentType().dynamicCast ()->setCharset(ch); // Body part->getBody()->setContents(vmime::create (text)); @@ -233,9 +249,8 @@ ref MDNHelper::createSecondMDNPart(const sendableMDNInfos& mdnInfos, ruaText += reportingUAProducts[i]; } - ref rua = - (headerFieldFactory::getInstance()->create - (vmime::fields::REPORTING_UA)).dynamicCast (); + ref rua = headerFieldFactory::getInstance()-> + create(vmime::fields::REPORTING_UA); rua->setValue(ruaText); @@ -243,16 +258,15 @@ ref MDNHelper::createSecondMDNPart(const sendableMDNInfos& mdnInfos, } // -- Final-Recipient - ref fr = - (headerFieldFactory::getInstance()-> - create(vmime::fields::FINAL_RECIPIENT)).dynamicCast (); + ref fr = headerFieldFactory::getInstance()-> + create(vmime::fields::FINAL_RECIPIENT); fr->setValue("rfc822; " + mdnInfos.getRecipient().getEmail()); // -- Original-Message-ID if (mdnInfos.getMessage()->getHeader()->hasField(vmime::fields::MESSAGE_ID)) { - fields.OriginalMessageId()->setValue + fields.OriginalMessageId()->setValueConst (mdnInfos.getMessage()->getHeader()->MessageId()->getValue()); } diff --git a/src/mdn/receivedMDNInfos.cpp b/src/mdn/receivedMDNInfos.cpp index dea54a0b..3578931e 100644 --- a/src/mdn/receivedMDNInfos.cpp +++ b/src/mdn/receivedMDNInfos.cpp @@ -82,7 +82,8 @@ void receivedMDNInfos::extract() if (!part->getHeader()->hasField(fields::CONTENT_TYPE)) continue; - const mediaType& type = part->getHeader()->ContentType()->getValue(); + const mediaType& type = *part->getHeader()->ContentType()-> + getValue().dynamicCast (); // Extract from second part (message/disposition-notification) if (type.getType() == vmime::mediaTypes::MESSAGE && @@ -97,10 +98,10 @@ void receivedMDNInfos::extract() header fields; fields.parse(oss.str()); - try { m_omid = fields.OriginalMessageId()->getValue(); } + try { m_omid = *fields.OriginalMessageId()->getValue().dynamicCast (); } catch (exceptions::no_such_field&) { /* Ignore */ } - try { m_disp = fields.Disposition()->getValue(); } + try { m_disp = *fields.Disposition()->getValue().dynamicCast (); } catch (exceptions::no_such_field&) { /* Ignore */ } } } diff --git a/src/messageBuilder.cpp b/src/messageBuilder.cpp index 5768ca3c..429cbd0a 100644 --- a/src/messageBuilder.cpp +++ b/src/messageBuilder.cpp @@ -23,6 +23,7 @@ #include "vmime/messageBuilder.hpp" +#include "vmime/dateTime.hpp" #include "vmime/textPartFactory.hpp" diff --git a/src/messageId.cpp b/src/messageId.cpp index b9ef32fd..705d987c 100644 --- a/src/messageId.cpp +++ b/src/messageId.cpp @@ -43,7 +43,7 @@ messageId::messageId(const string& id) messageId::messageId(const messageId& mid) - : component(), m_left(mid.m_left), m_right(mid.m_right) + : headerFieldValue(), m_left(mid.m_left), m_right(mid.m_right) { } diff --git a/src/messageIdSequence.cpp b/src/messageIdSequence.cpp index 877d4f8c..1be754c2 100644 --- a/src/messageIdSequence.cpp +++ b/src/messageIdSequence.cpp @@ -44,7 +44,7 @@ messageIdSequence::~messageIdSequence() messageIdSequence::messageIdSequence(const messageIdSequence& midSeq) - : component() + : headerFieldValue() { copyFrom(midSeq); } diff --git a/src/messageParser.cpp b/src/messageParser.cpp index 4a96cf10..8f1c1610 100644 --- a/src/messageParser.cpp +++ b/src/messageParser.cpp @@ -28,6 +28,9 @@ #include "vmime/defaultAttachment.hpp" #include "vmime/textPartFactory.hpp" +#include "vmime/relay.hpp" +#include "vmime/contentTypeField.hpp" + namespace vmime { @@ -59,16 +62,16 @@ void messageParser::parse(ref msg) #ifndef VMIME_BUILDING_DOC #define TRY_FIELD(var, type, name) \ - try { var = dynamic_cast(*msg->getHeader()->findField(name)).getValue(); } \ + try { var = *msg->getHeader()->findField(name)->getValue().dynamicCast (); } \ catch (exceptions::no_such_field) { } - TRY_FIELD(m_from, mailboxField, fields::FROM); + TRY_FIELD(m_from, mailbox, fields::FROM); - TRY_FIELD(m_to, addressListField, fields::TO); - TRY_FIELD(m_cc, addressListField, fields::CC); - TRY_FIELD(m_bcc, addressListField, fields::BCC); + TRY_FIELD(m_to, addressList, fields::TO); + TRY_FIELD(m_cc, addressList, fields::CC); + TRY_FIELD(m_bcc, addressList, fields::BCC); - TRY_FIELD(m_subject, textField, fields::SUBJECT); + TRY_FIELD(m_subject, text, fields::SUBJECT); #undef TRY_FIELD @@ -77,19 +80,15 @@ void messageParser::parse(ref msg) // Date try { - vmime::relayField& recv = dynamic_cast - (*msg->getHeader()->findField(fields::RECEIVED)); - - m_date = recv.getValue().getDate(); + const headerField& recv = *msg->getHeader()->findField(fields::RECEIVED); + m_date = recv.getValue().dynamicCast ()->getDate(); } catch (vmime::exceptions::no_such_field&) { try { - vmime::dateField& date = dynamic_cast - (*msg->getHeader()->findField(fields::DATE)); - - m_date = date.getValue(); + const headerField& date = *msg->getHeader()->findField(fields::DATE); + m_date = *date.getValue().dynamicCast (); } catch (vmime::exceptions::no_such_field&) { @@ -125,13 +124,16 @@ void messageParser::findTextParts(const bodyPart& msg, const bodyPart& part) const contentTypeField& ctf = dynamic_cast (*msg.getHeader()->findField(fields::CONTENT_TYPE)); - if (ctf.getValue().getType() == mediaTypes::TEXT) + const mediaType ctfType = + *ctf.getValue().dynamicCast (); + + if (ctfType.getType() == mediaTypes::TEXT) { - type = ctf.getValue(); + type = ctfType; accept = true; } } - catch (exceptions::no_such_field) + catch (exceptions::no_such_field&) { // No "Content-type" field: assume "text/plain". accept = true; @@ -171,12 +173,14 @@ bool messageParser::findSubTextParts(const bodyPart& msg, const bodyPart& part) const contentTypeField& ctf = dynamic_cast (*(p->getHeader()->findField(fields::CONTENT_TYPE))); - if (ctf.getValue().getType() == mediaTypes::TEXT) + const mediaType type = *ctf.getValue().dynamicCast (); + + if (type.getType() == mediaTypes::TEXT) { textParts.push_back(p); } } - catch (exceptions::no_such_field) + catch (exceptions::no_such_field&) { // No "Content-type" field. } @@ -191,9 +195,11 @@ bool messageParser::findSubTextParts(const bodyPart& msg, const bodyPart& part) const contentTypeField& ctf = dynamic_cast (*((*p)->getHeader()->findField(fields::CONTENT_TYPE))); + const mediaType type = *ctf.getValue().dynamicCast (); + try { - ref txtPart = textPartFactory::getInstance()->create(ctf.getValue()); + ref txtPart = textPartFactory::getInstance()->create(type); txtPart->parse(msg, part, **p); m_textParts.push_back(txtPart); diff --git a/src/misc/importanceHelper.cpp b/src/misc/importanceHelper.cpp index 4c5bf5d4..83df4548 100644 --- a/src/misc/importanceHelper.cpp +++ b/src/misc/importanceHelper.cpp @@ -20,6 +20,8 @@ #include "vmime/misc/importanceHelper.hpp" #include "vmime/exception.hpp" +#include "vmime/text.hpp" + namespace vmime { namespace misc { @@ -66,8 +68,8 @@ const importanceHelper::Importance importanceHelper::getImportanceHeader(ref fld = hdr->findField("X-Priority").dynamicCast (); - const string value = fld->getValue(); + const ref fld = hdr->findField("X-Priority"); + const string value = fld->getValue().dynamicCast ()->getWholeBuffer(); int n = IMPORTANCE_NORMAL; @@ -92,8 +94,9 @@ const importanceHelper::Importance importanceHelper::getImportanceHeader(ref fld = hdr->findField("Importance").dynamicCast (); - const string value = utility::stringUtils::toLower(utility::stringUtils::trim(fld->getValue())); + const ref fld = hdr->findField("Importance"); + const string value = utility::stringUtils::toLower(utility::stringUtils::trim + (fld->getValue().dynamicCast ()->getWholeBuffer())); if (value == "low") return (IMPORTANCE_LOWEST); @@ -123,7 +126,7 @@ void importanceHelper::setImportance(ref msg, const Importance i) void importanceHelper::setImportanceHeader(ref
hdr, const Importance i) { // "X-Priority:" Field - ref fld = hdr->getField("X-Priority").dynamicCast (); + ref fld = hdr->getField("X-Priority"); switch (i) { @@ -136,7 +139,7 @@ void importanceHelper::setImportanceHeader(ref
hdr, const Importance i) } // "Importance:" Field - fld = hdr->getField("Importance").dynamicCast (); + fld = hdr->getField("Importance"); switch (i) { diff --git a/src/net/transport.cpp b/src/net/transport.cpp index 85d227e4..6dcf3101 100644 --- a/src/net/transport.cpp +++ b/src/net/transport.cpp @@ -54,9 +54,10 @@ void transport::send(ref msg, utility::progressListener* progre try { - const mailboxField& from = dynamic_cast - (*msg->getHeader()->findField(fields::FROM)); - expeditor = from.getValue(); + const mailbox& mbox = *msg->getHeader()->findField(fields::FROM)-> + getValue().dynamicCast (); + + expeditor = mbox; } catch (exceptions::no_such_field&) { @@ -68,25 +69,28 @@ void transport::send(ref msg, utility::progressListener* progre try { - const addressListField& to = dynamic_cast - (*msg->getHeader()->findField(fields::TO)); - extractMailboxes(recipients, to.getValue()); + const addressList& to = *msg->getHeader()->findField(fields::TO)-> + getValue().dynamicCast (); + + extractMailboxes(recipients, to); } catch (exceptions::no_such_field&) { } try { - const addressListField& cc = dynamic_cast - (*msg->getHeader()->findField(fields::CC)); - extractMailboxes(recipients, cc.getValue()); + const addressList& cc = *msg->getHeader()->findField(fields::CC)-> + getValue().dynamicCast (); + + extractMailboxes(recipients, cc); } catch (exceptions::no_such_field&) { } try { - const addressListField& bcc = dynamic_cast - (*msg->getHeader()->findField(fields::BCC)); - extractMailboxes(recipients, bcc.getValue()); + const addressList& bcc = *msg->getHeader()->findField(fields::BCC)-> + getValue().dynamicCast (); + + extractMailboxes(recipients, bcc); } catch (exceptions::no_such_field&) { } diff --git a/src/parameter.cpp b/src/parameter.cpp index d6881a00..9b4325f8 100644 --- a/src/parameter.cpp +++ b/src/parameter.cpp @@ -22,16 +22,42 @@ // #include "vmime/parameter.hpp" -#include "vmime/parameterFactory.hpp" +#include "vmime/parserHelpers.hpp" + +#include "vmime/text.hpp" namespace vmime { +parameter::parameter(const string& name) + : m_name(name) +{ +} + + +parameter::parameter(const string& name, const word& value) + : m_name(name), m_value(value) +{ +} + + +parameter::parameter(const string& name, const string& value) + : m_name(name), m_value(value) +{ +} + + +parameter::parameter(const parameter&) + : component() +{ +} + + ref parameter::clone() const { - ref p = parameterFactory::getInstance()->create(m_name); + ref p = vmime::create (m_name); p->copyFrom(*this); return (p); @@ -43,8 +69,7 @@ void parameter::copyFrom(const component& other) const parameter& param = dynamic_cast (other); m_name = param.m_name; - - getValue().copyFrom(param.getValue()); + m_value.copyFrom(param.m_value); } @@ -57,16 +82,38 @@ parameter& parameter::operator=(const parameter& other) const string& parameter::getName() const { - return (m_name); + return m_name; +} + + +const word& parameter::getValue() const +{ + return m_value; +} + + +void parameter::setValue(const component& value) +{ + std::ostringstream oss; + utility::outputStreamAdapter vos(oss); + + value.generate(vos); + + setValue(word(oss.str(), vmime::charsets::US_ASCII)); +} + + +void parameter::setValue(const word& value) +{ + m_value = value; } void parameter::parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition) { - getValue().parse(buffer, position, end, newPosition); - - setParsedBounds(position, end); + m_value.setBuffer(string(buffer.begin() + position, buffer.begin() + end)); + m_value.setCharset(charset(charsets::US_ASCII)); if (newPosition) *newPosition = end; @@ -75,69 +122,157 @@ void parameter::parse(const string& buffer, const string::size_type position, void parameter::parse(const std::vector & chunks) { - string value; + bool foundCharsetChunk = false; - for (std::vector ::const_iterator it = chunks.begin() ; - it != chunks.end() ; ++it) + charset ch(charsets::US_ASCII); + std::ostringstream value; + + for (std::vector ::size_type i = 0 ; i < chunks.size() ; ++i) { - value += (*it).data; + const valueChunk& chunk = chunks[i]; + + // Decode following data + if (chunk.encoded) + { + const string::size_type len = chunk.data.length(); + string::size_type pos = 0; + + // If this is the first encoded chunk, extract charset + // and language information + if (!foundCharsetChunk) + { + // Eg. "us-ascii'en'This%20is%20even%20more%20" + string::size_type q = chunk.data.find_first_of('\''); + + if (q != string::npos) + { + const string chs = chunk.data.substr(0, q); + + if (!chs.empty()) + ch = charset(chs); + + ++q; + pos = q; + } + + q = chunk.data.find_first_of('\'', pos); + + if (q != string::npos) + { + // Ignore language + ++q; + pos = q; + } + + foundCharsetChunk = true; + } + + for (string::size_type i = pos ; i < len ; ++i) + { + const string::value_type c = chunk.data[i]; + + if (c == '%' && i + 2 < len) + { + string::value_type v = 0; + + // First char + switch (chunk.data[i + 1]) + { + case 'a': case 'A': v += 10; break; + case 'b': case 'B': v += 11; break; + case 'c': case 'C': v += 12; break; + case 'd': case 'D': v += 13; break; + case 'e': case 'E': v += 14; break; + case 'f': case 'F': v += 15; break; + default: // assume 0-9 + + v += (chunk.data[i + 1] - '0'); + break; + } + + v *= 16; + + // Second char + switch (chunk.data[i + 2]) + { + case 'a': case 'A': v += 10; break; + case 'b': case 'B': v += 11; break; + case 'c': case 'C': v += 12; break; + case 'd': case 'D': v += 13; break; + case 'e': case 'E': v += 14; break; + case 'f': case 'F': v += 15; break; + default: // assume 0-9 + + v += (chunk.data[i + 2] - '0'); + break; + } + + value << v; + + i += 2; // skip next 2 chars + } + else + { + value << c; + } + } + } + // Simply copy data, as it is not encoded + else + { + // This syntax is non-standard (expressly prohibited + // by RFC-2047), but is used by Mozilla: + // + // Content-Type: image/png; + // name="=?us-ascii?Q?Logo_VMime=2Epng?=" + + // Using 'vmime::text' to parse the data is safe even + // if the data is not encoded, because it can recover + // from parsing errors. + vmime::text t; + t.parse(chunk.data); + + if (t.getWordCount() != 0) + { + value << t.getWholeBuffer(); + + if (!foundCharsetChunk) + ch = t.getWordAt(0)->getCharset(); + } + } } - getValue().parse(value, 0, value.length(), NULL); + m_value.setBuffer(value.str()); + m_value.setCharset(ch); } void parameter::generate(utility::outputStream& os, const string::size_type maxLineLength, const string::size_type curLinePos, string::size_type* newLinePos) const { + const string& name = m_name; + const string& value = m_value.getBuffer(); + + // For compatibility with implementations that do not understand RFC-2231, + // also generate a normal "7bit/us-ascii" parameter string::size_type pos = curLinePos; - if (pos + m_name.length() + 10 > maxLineLength) + if (pos + name.length() + 10 + value.length() > maxLineLength) { os << NEW_LINE_SEQUENCE; pos = NEW_LINE_SEQUENCE_LENGTH; } - os << m_name << "="; - pos += m_name.length() + 1; + bool needQuoting = false; + string::size_type valueLength = 0; - generateValue(os, maxLineLength, pos, newLinePos); -} - - -void parameter::generateValue(utility::outputStream& os, const string::size_type /* maxLineLength */, - const string::size_type curLinePos, string::size_type* newLinePos) const -{ - // NOTE: This default implementation does not support parameter - // values that span on several lines ('defaultParameter' can do - // that, following rules specified in RFC-2231). - - std::ostringstream valueStream; - utility::outputStreamAdapter valueStreamV(valueStream); - - getValue().generate(valueStreamV, lineLengthLimits::infinite, 0, NULL); - - const string value(valueStream.str()); - - std::ostringstream ss; - string::const_iterator start = value.begin(); - bool quoted = false; - - for (string::const_iterator i = value.begin() ; i != value.end() ; ++i) + for (string::size_type i = 0 ; (i < value.length()) && (pos + valueLength < maxLineLength - 4) ; ++i, ++valueLength) { - switch (*i) + switch (value[i]) { // Characters that need to be quoted _and_ escaped case '"': case '\\': - - ss << string(start, i) << "\\" << *i; - - start = i + 1; - quoted = true; - - break; - // Other characters that need quoting case ' ': case '\t': @@ -155,21 +290,194 @@ void parameter::generateValue(utility::outputStream& os, const string::size_type case '?': case '=': - quoted = true; + needQuoting = true; break; } } - if (start != value.end()) - ss << string(start, value.end()); + const bool cutValue = (valueLength != value.length()); // has the value been cut? - if (quoted) - os << "\"" << ss.str() << "\""; + if (needQuoting) + { + os << name << "=\""; + pos += name.length() + 2; + } else - os << ss.str(); + { + os << name << "="; + pos += name.length() + 1; + } + + bool extended = false; + + for (string::size_type i = 0 ; (i < value.length()) && (pos < maxLineLength - 4) ; ++i) + { + const char_t c = value[i]; + + if (/* needQuoting && */ (c == '"' || c == '\\')) // 'needQuoting' is implicit + { + os << '\\' << value[i]; // escape 'x' with '\x' + pos += 2; + } + else if (parserHelpers::isAscii(c)) + { + os << value[i]; + ++pos; + } + else + { + extended = true; + } + } + + if (needQuoting) + { + os << '"'; + ++pos; + } + + // Also generate an extended parameter if the value contains 8-bit characters + // or is too long for a single line + if (extended || cutValue) + { + os << ';'; + ++pos; + + /* RFC-2231 + * ======== + * + * Content-Type: message/external-body; access-type=URL; + * URL*0="ftp://"; + * URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar" + * + * Content-Type: application/x-stuff; + * title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A + * + * Content-Type: application/x-stuff; + * title*0*=us-ascii'en'This%20is%20even%20more%20 + * title*1*=%2A%2A%2Afun%2A%2A%2A%20 + * title*2="isn't it!" + */ + + // Check whether there is enough space for the first section: + // parameter name, section identifier, charset and separators + // + at least 5 characters for the value + const string::size_type firstSectionLength = + name.length() + 4 /* *0*= */ + 2 /* '' */ + + m_value.getCharset().getName().length(); + + if (pos + firstSectionLength + 5 >= maxLineLength) + { + os << NEW_LINE_SEQUENCE; + pos = NEW_LINE_SEQUENCE_LENGTH; + } + + // Split text into multiple sections that fit on one line + int sectionCount = 0; + std::vector sectionText; + + string currentSection; + string::size_type currentSectionLength = firstSectionLength; + + for (string::size_type i = 0 ; i < value.length() ; ++i) + { + // Check whether we should start a new line (taking into + // account the next character will be encoded = worst case) + if (currentSectionLength + 3 >= maxLineLength) + { + sectionText.push_back(currentSection); + sectionCount++; + + currentSection.clear(); + currentSectionLength = NEW_LINE_SEQUENCE_LENGTH + + name.length() + 6; + } + + // Output next character + const char_t c = value[i]; + bool encode = false; + + switch (c) + { + // special characters + case ' ': + case '\t': + case '\r': + case '\n': + case '"': + case ';': + case ',': + + encode = true; + break; + + default: + + encode = (!parserHelpers::isPrint(c) || + !parserHelpers::isAscii(c)); + + break; + } + + if (encode) // need encoding + { + const int h1 = static_cast (c) / 16; + const int h2 = static_cast (c) % 16; + + currentSection += '%'; + currentSection += "0123456789ABCDEF"[h1]; + currentSection += "0123456789ABCDEF"[h2]; + + pos += 3; + currentSectionLength += 3; + } + else + { + currentSection += value[i]; + + ++pos; + ++currentSectionLength; + } + } + + if (!currentSection.empty()) + { + sectionText.push_back(currentSection); + sectionCount++; + } + + // Output sections + for (int sectionNumber = 0 ; sectionNumber < sectionCount ; ++sectionNumber) + { + os << name; + + if (sectionCount != 1) // no section specifier when only a single one + { + os << '*'; + os << sectionNumber; + } + + os << "*="; + + if (sectionNumber == 0) + { + os << m_value.getCharset().getName(); + os << '\'' << /* No language */ '\''; + } + + os << sectionText[sectionNumber]; + + if (sectionNumber + 1 < sectionCount) + { + os << ';'; + os << NEW_LINE_SEQUENCE; + pos = NEW_LINE_SEQUENCE_LENGTH; + } + } + } if (newLinePos) - *newLinePos = curLinePos + ss.str().length() + 2; + *newLinePos = pos; } @@ -177,10 +485,11 @@ const std::vector > parameter::getChildComponents() const { std::vector > list; - list.push_back(getValueImp()); + list.push_back(ref ::fromPtr(&m_value)); - return (list); + return list; } } // vmime + diff --git a/src/parameterFactory.cpp b/src/parameterFactory.cpp deleted file mode 100644 index ce183319..00000000 --- a/src/parameterFactory.cpp +++ /dev/null @@ -1,103 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2005 Vincent Richard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// Linking this library statically or dynamically with other modules is making -// a combined work based on this library. Thus, the terms and conditions of -// the GNU General Public License cover the whole combination. -// - -#include "vmime/parameterFactory.hpp" -#include "vmime/exception.hpp" - -#include "vmime/standardParams.hpp" - - -namespace vmime -{ - - -parameterFactory::parameterFactory() -{ - // Register some default names - registerName ("charset"); - registerName ("creation-date"); - registerName ("modification-date"); - registerName ("read-date"); -} - - -parameterFactory::~parameterFactory() -{ -} - - -parameterFactory* parameterFactory::getInstance() -{ - static parameterFactory instance; - return (&instance); -} - - -ref parameterFactory::create - (const string& name, const string& value) -{ - const string lcName = utility::stringUtils::toLower(name); - - NameMap::const_iterator pos = m_nameMap.find(lcName); - ref param; - - if (pos != m_nameMap.end()) - { - param = ((*pos).second)(); - } - else - { - param = registerer ::creator(); - } - - param->m_name = name; - if (value != NULL_STRING) param->parse(value); - - return (param); -} - - -ref parameterFactory::create(const string& name, const component& value) -{ - const string lcName = utility::stringUtils::toLower(name); - - NameMap::const_iterator pos = m_nameMap.find(lcName); - ref param; - - if (pos != m_nameMap.end()) - { - param = ((*pos).second)(); - } - else - { - param = registerer ::creator(); - } - - param->m_name = name; - param->setValue(value); - - return (param); -} - - -} // vmime diff --git a/src/parameterizedHeaderField.cpp b/src/parameterizedHeaderField.cpp index 096dd497..771fcbb1 100644 --- a/src/parameterizedHeaderField.cpp +++ b/src/parameterizedHeaderField.cpp @@ -22,7 +22,6 @@ // #include "vmime/parameterizedHeaderField.hpp" -#include "vmime/parameterFactory.hpp" #include "vmime/text.hpp" #include "vmime/parserHelpers.hpp" @@ -90,7 +89,7 @@ void parameterizedHeaderField::parse(const string& buffer, const string::size_ty while (p < pend && *p != ';') ++p; - getValue().parse(buffer, start, position + (p - pstart)); + getValue()->parse(buffer, start, position + (p - pstart)); removeAllParameters(); @@ -295,7 +294,7 @@ void parameterizedHeaderField::parse(const string& buffer, const string::size_ty const paramInfo& info = (*it).second; // Append this parameter to the list - ref param = parameterFactory::getInstance()->create((*it).first); + ref param = vmime::create ((*it).first); param->parse(info.value); param->setParsedBounds(info.start, info.end); @@ -404,7 +403,7 @@ ref parameterizedHeaderField::getParameter(const string& paramName) // If no parameter with this name can be found, create a new one if (pos == end) { - ref param = parameterFactory::getInstance()->create(paramName); + ref param = vmime::create (paramName); appendParameter(param); diff --git a/src/path.cpp b/src/path.cpp index 57cab716..7fefc10d 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -41,7 +41,7 @@ path::path(const string& localPart, const string& domain) path::path(const path& p) - : component(), m_localPart(p.m_localPart), m_domain(p.m_domain) + : headerFieldValue(), m_localPart(p.m_localPart), m_domain(p.m_domain) { } diff --git a/src/plainTextPart.cpp b/src/plainTextPart.cpp index 45a66e36..ad048c2b 100644 --- a/src/plainTextPart.cpp +++ b/src/plainTextPart.cpp @@ -25,6 +25,8 @@ #include "vmime/header.hpp" #include "vmime/exception.hpp" +#include "vmime/contentTypeField.hpp" + #include "vmime/emptyContentHandler.hpp" @@ -63,7 +65,7 @@ void plainTextPart::generateIn(bodyPart& /* message */, bodyPart& parent) const // Set header fields part->getHeader()->ContentType()->setValue(mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN)); - part->getHeader()->ContentType()->setCharset(m_charset); + part->getHeader()->ContentType().dynamicCast ()->setCharset(m_charset); part->getHeader()->ContentTransferEncoding()->setValue(encoding(encodingTypes::QUOTED_PRINTABLE)); // Set contents @@ -83,11 +85,11 @@ void plainTextPart::parse(const bodyPart& /* message */, m_charset = ctf.getCharset(); } - catch (exceptions::no_such_field) + catch (exceptions::no_such_field&) { // No "Content-type" field. } - catch (exceptions::no_such_parameter) + catch (exceptions::no_such_parameter&) { // No "charset" parameter. } diff --git a/src/relay.cpp b/src/relay.cpp index cddd231b..88a9097e 100644 --- a/src/relay.cpp +++ b/src/relay.cpp @@ -38,7 +38,7 @@ relay::relay() relay::relay(const relay& r) - : component() + : headerFieldValue() { copyFrom(r); } diff --git a/src/text.cpp b/src/text.cpp index 51593763..8436c44b 100644 --- a/src/text.cpp +++ b/src/text.cpp @@ -36,7 +36,7 @@ text::text() text::text(const text& t) - : component() + : headerFieldValue() { copyFrom(t); } @@ -383,4 +383,18 @@ const std::vector > text::getChildComponents() const } +const string text::getWholeBuffer() const +{ + string res; + + for (std::vector >::const_iterator it = m_words.begin() ; + it != m_words.end() ; ++it) + { + res += (*it)->getBuffer(); + } + + return res; +} + + } // vmime diff --git a/src/word.cpp b/src/word.cpp index f4fc89d2..ccb5d554 100644 --- a/src/word.cpp +++ b/src/word.cpp @@ -44,7 +44,7 @@ word::word() word::word(const word& w) - : component(), m_buffer(w.m_buffer), m_charset(w.m_charset) + : headerFieldValue(), m_buffer(w.m_buffer), m_charset(w.m_charset) { } diff --git a/tests/misc/importanceHelperTest.cpp b/tests/misc/importanceHelperTest.cpp index 9c1ee670..60af1cde 100644 --- a/tests/misc/importanceHelperTest.cpp +++ b/tests/misc/importanceHelperTest.cpp @@ -78,10 +78,10 @@ VMIME_TEST_SUITE_BEGIN vmime::misc::importanceHelper::setImportanceHeader(hdr, i); VASSERT_NO_THROW("1", hdr->findField("Importance")); - VASSERT_EQ("2", ImportanceValue, hdr->findField("Importance")->getValue().generate()); + VASSERT_EQ("2", ImportanceValue, hdr->findField("Importance")->getValue()->generate()); VASSERT_NO_THROW("3", hdr->findField("X-Priority")); - VASSERT_EQ("4", XPriorityValue, hdr->findField("X-Priority")->getValue().generate()); + VASSERT_EQ("4", XPriorityValue, hdr->findField("X-Priority")->getValue()->generate()); } void testSetImportance1() diff --git a/tests/parser/parameterTest.cpp b/tests/parser/parameterTest.cpp index 5f64a7c0..95cdf626 100644 --- a/tests/parser/parameterTest.cpp +++ b/tests/parser/parameterTest.cpp @@ -33,40 +33,30 @@ VMIME_TEST_SUITE_BEGIN VMIME_TEST_LIST_BEGIN VMIME_TEST(testParse) VMIME_TEST(testGenerate) + VMIME_TEST(testNonStandardEncodedParam) VMIME_TEST_LIST_END // HACK: parameterizedHeaderField constructor is private class parameterizedHeaderField : public vmime::parameterizedHeaderField { - private: - - vmime::ref > m_value; - public: parameterizedHeaderField() - : headerField("F"), - m_value(vmime::create >("X")) + : headerField("F") { + setValue(vmime::headerFieldFactory::getInstance()->createValue(getName())); + setValue(vmime::word("X")); } - - const vmime::component& getValue() const { return *m_value; } - vmime::component& getValue() { return *m_value; } - - void setValue(const vmime::component&) { /* Do nothing */ } - - const vmime::ref getValueImp() const { return m_value; } - vmime::ref getValueImp() { return m_value; } }; #define PARAM_VALUE(p, n) (p.getParameterAt(n)->getValue().generate()) #define PARAM_NAME(p, n) (p.getParameterAt(n)->getName()) -#define PARAM_CHARSET(p, n) ( \ - (p.getParameterAt(n).staticCast ())->getValue().getCharset().generate()) -#define PARAM_BUFFER(p, n) ( \ - (p.getParameterAt(n).staticCast ())->getValue().getBuffer()) +#define PARAM_CHARSET(p, n) \ + (p.getParameterAt(n)->getValue().getCharset().generate()) +#define PARAM_BUFFER(p, n) \ + (p.getParameterAt(n)->getValue().getBuffer()) void testParse() @@ -201,32 +191,32 @@ VMIME_TEST_SUITE_BEGIN { // Simple parameter/value parameterizedHeaderField p1; - p1.appendParameter(vmime::parameterFactory::getInstance()->create("param1", "value1")); + p1.appendParameter(vmime::create ("param1", "value1")); VASSERT_EQ("1", "F: X; param1=value1", p1.generate()); // Value that needs quoting (1/2) parameterizedHeaderField p2a; - p2a.appendParameter(vmime::parameterFactory::getInstance()->create("param1", "value1a;value1b")); + p2a.appendParameter(vmime::create ("param1", "value1a;value1b")); VASSERT_EQ("2a", "F: X; param1=\"value1a;value1b\"", p2a.generate()); // Value that needs quoting (2/2) parameterizedHeaderField p2b; - p2b.appendParameter(vmime::parameterFactory::getInstance()->create("param1", "va\\lue\"1")); + p2b.appendParameter(vmime::create ("param1", "va\\lue\"1")); VASSERT_EQ("2b", "F: X; param1=\"va\\\\lue\\\"1\"", p2b.generate()); // Extended parameter with charset specifier parameterizedHeaderField p3; - p3.appendParameter(vmime::parameterFactory::getInstance()->create("param1", + p3.appendParameter(vmime::create ("param1", vmime::word("value 1\xe9", vmime::charset("charset")))); VASSERT_EQ("3", "F: X; param1=\"value 1\";param1*=charset''value%201%E9", p3.generate()); // Value that spans on multiple lines parameterizedHeaderField p4; - p4.appendParameter(vmime::parameterFactory::getInstance()->create("param1", + p4.appendParameter(vmime::create ("param1", vmime::word("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", vmime::charset("charset")))); @@ -241,5 +231,28 @@ VMIME_TEST_SUITE_BEGIN "param1*6*=WXYZ", p4.generate(25)); // max line length = 25 } + void testNonStandardEncodedParam() + { + // This syntax is non-standard (expressly prohibited + // by RFC-2047), but is used by Mozilla: + // + // Content-Type: image/png; + // name="=?us-ascii?Q?Logo_VMime=2Epng?=" + + parameterizedHeaderField p1; + p1.parse("image/png; name=\"=?us-ascii?Q?Logo_VMime=2Epng?=\""); + + VASSERT_EQ("1.1", 1, p1.getParameterCount()); + VASSERT_EQ("1.2", "name", PARAM_NAME(p1, 0)); + VASSERT_EQ("1.3", "Logo VMime.png", PARAM_VALUE(p1, 0)); + + parameterizedHeaderField p2; + p2.parse("image/png; name=\"Logo =?us-ascii?Q?VMime=2Epng?=\""); + + VASSERT_EQ("2.1", 1, p2.getParameterCount()); + VASSERT_EQ("2.2", "name", PARAM_NAME(p2, 0)); + VASSERT_EQ("2.3", "Logo VMime.png", PARAM_VALUE(p2, 0)); + } + VMIME_TEST_SUITE_END diff --git a/vmime/address.hpp b/vmime/address.hpp index 6e73e3a1..5fb3c99d 100644 --- a/vmime/address.hpp +++ b/vmime/address.hpp @@ -26,7 +26,7 @@ #include "vmime/base.hpp" -#include "vmime/component.hpp" +#include "vmime/headerFieldValue.hpp" namespace vmime @@ -39,7 +39,7 @@ namespace vmime * and mailboxGroup classes. */ -class address : public component +class address : public headerFieldValue { friend class addressList; diff --git a/vmime/addressList.hpp b/vmime/addressList.hpp index a48aabbe..4b4e43d0 100644 --- a/vmime/addressList.hpp +++ b/vmime/addressList.hpp @@ -26,7 +26,7 @@ #include "vmime/base.hpp" -#include "vmime/component.hpp" +#include "vmime/headerFieldValue.hpp" #include "vmime/address.hpp" @@ -41,7 +41,7 @@ class mailboxList; /** A list of addresses. */ -class addressList : public component +class addressList : public headerFieldValue { public: diff --git a/vmime/bodyPartAttachment.hpp b/vmime/bodyPartAttachment.hpp index c079b0d6..7ac1914e 100644 --- a/vmime/bodyPartAttachment.hpp +++ b/vmime/bodyPartAttachment.hpp @@ -27,6 +27,9 @@ #include "vmime/attachment.hpp" +#include "vmime/contentDispositionField.hpp" +#include "vmime/contentTypeField.hpp" + namespace vmime { diff --git a/vmime/contentDisposition.hpp b/vmime/contentDisposition.hpp index 6c4a9cd0..fa3cf7f9 100644 --- a/vmime/contentDisposition.hpp +++ b/vmime/contentDisposition.hpp @@ -26,7 +26,7 @@ #include "vmime/base.hpp" -#include "vmime/component.hpp" +#include "vmime/headerFieldValue.hpp" namespace vmime @@ -36,7 +36,7 @@ namespace vmime /** Content disposition (basic type). */ -class contentDisposition : public component +class contentDisposition : public headerFieldValue { public: diff --git a/vmime/contentDispositionField.hpp b/vmime/contentDispositionField.hpp index e7f79296..e02f64fa 100644 --- a/vmime/contentDispositionField.hpp +++ b/vmime/contentDispositionField.hpp @@ -26,7 +26,6 @@ #include "vmime/parameterizedHeaderField.hpp" -#include "vmime/genericField.hpp" #include "vmime/contentDisposition.hpp" #include "vmime/dateTime.hpp" @@ -37,7 +36,7 @@ namespace vmime { -class contentDispositionField : public parameterizedHeaderField, public genericField +class contentDispositionField : public parameterizedHeaderField { friend class vmime::creator; // create ref @@ -48,19 +47,69 @@ protected: public: - const datetime& getCreationDate() const; + /** Return the value of the "creation-date" parameter. + * + * @return value of the "creation-date" parameter + * @throw exceptions::no_such_parameter if the parameter does not exist + */ + const datetime getCreationDate() const; + + /** Set the value of the "creation-date" parameter. + * + * @param creationDate new value for the "creation-date" parameter + */ void setCreationDate(const datetime& creationDate); - const datetime& getModificationDate() const; + /** Return the value of the "modification-date" parameter. + * + * @return value of the "modification-date" parameter + * @throw exceptions::no_such_parameter if the parameter does not exist + */ + const datetime getModificationDate() const; + + /** Set the value of the "modification-date" parameter. + * + * @param modificationDate new value for the "modification-date" parameter + */ void setModificationDate(const datetime& modificationDate); - const datetime& getReadDate() const; + /** Return the value of the "read-date" parameter. + * + * @return value of the "read-date" parameter + * @throw exceptions::no_such_parameter if the parameter does not exist + */ + const datetime getReadDate() const; + + /** Set the value of the "read-date" parameter. + * + * @param readDate new value for the "read-date" parameter + */ void setReadDate(const datetime& readDate); + /** Return the value of the "filename" parameter. + * + * @return value of the "filename" parameter + * @throw exceptions::no_such_parameter if the parameter does not exist + */ const word getFilename() const; + + /** Set the value of the "filename" parameter. + * + * @param filename new value for the "filename" parameter + */ void setFilename(const word& filename); + /** Return the value of the "size" parameter. + * + * @return value of the "size" parameter + * @throw exceptions::no_such_parameter if the parameter does not exist + */ const string getSize() const; + + /** Set the value of the "size" parameter. + * + * @param size new value for the "size" parameter + */ void setSize(const string& size); }; diff --git a/vmime/contentTypeField.hpp b/vmime/contentTypeField.hpp index b66f20d0..c78642f1 100644 --- a/vmime/contentTypeField.hpp +++ b/vmime/contentTypeField.hpp @@ -26,7 +26,6 @@ #include "vmime/parameterizedHeaderField.hpp" -#include "vmime/genericField.hpp" #include "vmime/mediaType.hpp" #include "vmime/charset.hpp" @@ -36,7 +35,7 @@ namespace vmime { -class contentTypeField : public parameterizedHeaderField, public genericField +class contentTypeField : public parameterizedHeaderField { friend class vmime::creator; // create ref @@ -47,25 +46,33 @@ protected: public: - /** Return the value of the "boundary" parameter. + /** Return the value of the "boundary" parameter. Boundary is a + * random string used to separate body parts. * * @return value of the "boundary" parameter + * @throw exceptions::no_such_parameter if the parameter does not exist */ const string getBoundary() const; - /** Set the value of the "boundary" parameter. + /** Set the value of the "boundary" parameter. Boundary is a + * random string used to separate body parts. Normally, the + * boundary is generated automatically by VMime, you should + * not need to call this. * * @param boundary new value for the "boundary" parameter */ void setBoundary(const string& boundary); - /** Return the value of the "charset" parameter. + /** Return the value of the "charset" parameter. It specifies the + * charset used in the body part contents. * * @return value of the "charset" parameter + * @throw exceptions::no_such_parameter if the parameter does not exist */ - const charset& getCharset() const; + const charset getCharset() const; - /** Set the value of the "charset" parameter. + /** Set the value of the "charset" parameter. It specifies the + * charset used in the body part contents. * * @param ch new value for the "charset" parameter */ @@ -74,6 +81,7 @@ public: /** Return the value of the "report-type" parameter (RFC-1892). * * @return value of the "report-type" parameter + * @throw exceptions::no_such_parameter if the parameter does not exist */ const string getReportType() const; diff --git a/vmime/dateTime.hpp b/vmime/dateTime.hpp index 5f2499ce..ffc17bde 100644 --- a/vmime/dateTime.hpp +++ b/vmime/dateTime.hpp @@ -26,7 +26,7 @@ #include "vmime/base.hpp" -#include "vmime/component.hpp" +#include "vmime/headerFieldValue.hpp" #include @@ -38,7 +38,7 @@ namespace vmime /** Date and time (basic type). */ -class datetime : public component +class datetime : public headerFieldValue { public: diff --git a/vmime/defaultParameter.hpp b/vmime/defaultParameter.hpp deleted file mode 100644 index a6546a4b..00000000 --- a/vmime/defaultParameter.hpp +++ /dev/null @@ -1,77 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2005 Vincent Richard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// Linking this library statically or dynamically with other modules is making -// a combined work based on this library. Thus, the terms and conditions of -// the GNU General Public License cover the whole combination. -// - -#ifndef VMIME_DEFAULTPARAMETER_HPP_INCLUDED -#define VMIME_DEFAULTPARAMETER_HPP_INCLUDED - - -#include "vmime/parameter.hpp" -#include "vmime/parameterFactory.hpp" - -#include "vmime/word.hpp" - - -namespace vmime -{ - - -/** Default parameter implementation (with support for RFC-2231). - */ - -class defaultParameter : public parameter -{ - friend class vmime::creator; // create ref - -protected: - - defaultParameter(); - -public: - - defaultParameter& operator=(const defaultParameter& other); - - const word& getValue() const; - word& getValue(); - - void setValue(const word& value); - void setValue(const component& value); - - void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); - void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; - -private: - - void parse(const std::vector & chunks); - - const ref getValueImp() const; - const ref getValueImp(); - - - ref m_value; -}; - - -} // vmime - - -#endif // VMIME_DEFAULTPARAMETER_HPP_INCLUDED diff --git a/vmime/disposition.hpp b/vmime/disposition.hpp index 03d476db..b98b558c 100644 --- a/vmime/disposition.hpp +++ b/vmime/disposition.hpp @@ -26,7 +26,7 @@ #include "vmime/base.hpp" -#include "vmime/component.hpp" +#include "vmime/headerFieldValue.hpp" #include @@ -38,7 +38,7 @@ namespace vmime /** Disposition - from RFC-3798 (basic type). */ -class disposition : public component +class disposition : public headerFieldValue { public: diff --git a/vmime/encoding.hpp b/vmime/encoding.hpp index 692585b0..4308de05 100644 --- a/vmime/encoding.hpp +++ b/vmime/encoding.hpp @@ -26,7 +26,7 @@ #include "vmime/base.hpp" -#include "vmime/component.hpp" +#include "vmime/headerFieldValue.hpp" #include "vmime/encoder.hpp" @@ -40,7 +40,7 @@ class contentHandler; /** Content encoding (basic type). */ -class encoding : public component +class encoding : public headerFieldValue { public: diff --git a/vmime/fileAttachment.hpp b/vmime/fileAttachment.hpp index 3fb24ebf..785690db 100644 --- a/vmime/fileAttachment.hpp +++ b/vmime/fileAttachment.hpp @@ -27,6 +27,8 @@ #include "vmime/defaultAttachment.hpp" +#include "vmime/dateTime.hpp" + namespace vmime { diff --git a/vmime/header.hpp b/vmime/header.hpp index e7a834df..bb806fc7 100644 --- a/vmime/header.hpp +++ b/vmime/header.hpp @@ -32,13 +32,6 @@ #include "vmime/headerField.hpp" #include "vmime/headerFieldFactory.hpp" -#include "vmime/mailboxField.hpp" -#include "vmime/contentTypeField.hpp" -#include "vmime/contentDispositionField.hpp" - -#include "vmime/standardFields.hpp" -#include "vmime/standardParams.hpp" - namespace vmime { @@ -61,38 +54,38 @@ public: header(); ~header(); -#define FIELD_ACCESS(methodName, fieldName, type) \ - ref methodName() { return getField(fields::fieldName).dynamicCast (); } \ - ref methodName() const { return findField(fields::fieldName).dynamicCast (); } +#define FIELD_ACCESS(methodName, fieldName) \ + ref methodName() { return getField(fields::fieldName); } \ + ref methodName() const { return findField(fields::fieldName); } - FIELD_ACCESS(From, FROM, mailboxField) - FIELD_ACCESS(Sender, SENDER, mailboxField) - FIELD_ACCESS(ReplyTo, REPLY_TO, mailboxField) - FIELD_ACCESS(DeliveredTo, DELIVERED_TO, mailboxField) - FIELD_ACCESS(InReplyTo, IN_REPLY_TO, messageIdSequenceField) - FIELD_ACCESS(ReturnPath, RETURN_PATH, pathField) - FIELD_ACCESS(References, REFERENCES, messageIdSequenceField) + FIELD_ACCESS(From, FROM) + FIELD_ACCESS(Sender, SENDER) + FIELD_ACCESS(ReplyTo, REPLY_TO) + FIELD_ACCESS(DeliveredTo, DELIVERED_TO) + FIELD_ACCESS(InReplyTo, IN_REPLY_TO) + FIELD_ACCESS(ReturnPath, RETURN_PATH) + FIELD_ACCESS(References, REFERENCES) - FIELD_ACCESS(To, TO, addressListField) - FIELD_ACCESS(Cc, CC, addressListField) - FIELD_ACCESS(Bcc, BCC, addressListField) - FIELD_ACCESS(Date, DATE, dateField) - FIELD_ACCESS(Subject, SUBJECT, textField) - FIELD_ACCESS(Organization, ORGANIZATION, textField) - FIELD_ACCESS(UserAgent, USER_AGENT, textField) + FIELD_ACCESS(To, TO) + FIELD_ACCESS(Cc, CC) + FIELD_ACCESS(Bcc, BCC) + FIELD_ACCESS(Date, DATE) + FIELD_ACCESS(Subject, SUBJECT) + FIELD_ACCESS(Organization, ORGANIZATION) + FIELD_ACCESS(UserAgent, USER_AGENT) - FIELD_ACCESS(ContentType, CONTENT_TYPE, contentTypeField) - FIELD_ACCESS(ContentDescription, CONTENT_DESCRIPTION, textField) - FIELD_ACCESS(ContentTransferEncoding, CONTENT_TRANSFER_ENCODING, contentEncodingField) - FIELD_ACCESS(MimeVersion, MIME_VERSION, defaultField) - FIELD_ACCESS(ContentDisposition, CONTENT_DISPOSITION, contentDispositionField) - FIELD_ACCESS(ContentId, CONTENT_ID, messageIdField) - FIELD_ACCESS(MessageId, MESSAGE_ID, messageIdField) - FIELD_ACCESS(ContentLocation, CONTENT_LOCATION, defaultField) + FIELD_ACCESS(ContentType, CONTENT_TYPE) + FIELD_ACCESS(ContentDescription, CONTENT_DESCRIPTION) + FIELD_ACCESS(ContentTransferEncoding, CONTENT_TRANSFER_ENCODING) + FIELD_ACCESS(MimeVersion, MIME_VERSION) + FIELD_ACCESS(ContentDisposition, CONTENT_DISPOSITION) + FIELD_ACCESS(ContentId, CONTENT_ID) + FIELD_ACCESS(MessageId, MESSAGE_ID) + FIELD_ACCESS(ContentLocation, CONTENT_LOCATION) - FIELD_ACCESS(OriginalMessageId, ORIGINAL_MESSAGE_ID, messageIdField) - FIELD_ACCESS(Disposition, DISPOSITION, dispositionField) - FIELD_ACCESS(DispositionNotificationTo, DISPOSITION_NOTIFICATION_TO, mailboxListField) + FIELD_ACCESS(OriginalMessageId, ORIGINAL_MESSAGE_ID) + FIELD_ACCESS(Disposition, DISPOSITION) + FIELD_ACCESS(DispositionNotificationTo, DISPOSITION_NOTIFICATION_TO) #undef FIELD_ACCESS diff --git a/vmime/headerField.hpp b/vmime/headerField.hpp index 9047a2ac..27d53f0c 100644 --- a/vmime/headerField.hpp +++ b/vmime/headerField.hpp @@ -27,6 +27,7 @@ #include "vmime/base.hpp" #include "vmime/component.hpp" +#include "vmime/headerFieldValue.hpp" namespace vmime @@ -41,8 +42,12 @@ class headerField : public component friend class headerFieldFactory; friend class header; + friend class vmime::creator; // create ref + protected: + // Protected constructor to prevent the user from creating + // new objects without using 'headerFieldFactory' headerField(); headerField(const string& fieldName); @@ -56,6 +61,12 @@ public: const std::vector > getChildComponents() const; + /** Sets the name of this field. + * + * @param name field name (eg: "From" or "X-MyField"). + */ + void setName(const string& name); + /** Return the name of this field. * * @return field name @@ -73,21 +84,32 @@ public: * * @return read-only value object */ - virtual const component& getValue() const = 0; + virtual ref getValue() const; /** Return the value object attached to this field. * * @return value object */ - virtual component& getValue() = 0; + virtual ref getValue(); /** Set the value of this field. * - * @throw std::bad_cast_exception if the value type is - * incompatible with the header field type - * @param value value object + * @param value new value */ - virtual void setValue(const component& value) = 0; + virtual void setValue(ref value); + + /** Set the value of this field by cloning the specified value. + * + * @param value new value + */ + virtual void setValueConst(ref value); + + /** Set the value of this field (reference version). + * The value will be cloned. + * + * @param value new value + */ + virtual void setValue(const headerFieldValue& value); /** Set the value of this field given a character string. * @@ -104,15 +126,11 @@ public: protected: - virtual const ref getValueImp() const = 0; - virtual ref getValueImp() = 0; - -private: - static ref parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); string m_name; + ref m_value; }; diff --git a/vmime/headerFieldFactory.hpp b/vmime/headerFieldFactory.hpp index 2099e341..04867547 100644 --- a/vmime/headerFieldFactory.hpp +++ b/vmime/headerFieldFactory.hpp @@ -33,6 +33,9 @@ namespace vmime { +/** Creates header field and header field value objects. + */ + class headerFieldFactory { protected: @@ -45,17 +48,23 @@ protected: NameMap m_nameMap; + typedef ref (*ValueAllocFunc)(void); + typedef std::map ValueMap; + + ValueMap m_valueMap; + public: static headerFieldFactory* getInstance(); #ifndef VMIME_BUILDING_DOC - template + // TYPE must inherit from BASE_TYPE + template class registerer { public: - static ref creator() + static ref creator() { // Allocate a new object return vmime::create (); @@ -64,14 +73,49 @@ public: #endif // VMIME_BUILDING_DOC + /** Register a field type. + * + * @param T field class (must inherit from 'headerField') + * @param name field name (eg. "X-MyField") + */ template - void registerName(const string& name) + void registerField(const string& name) { m_nameMap.insert(NameMap::value_type - (utility::stringUtils::toLower(name), ®isterer::creator)); + (utility::stringUtils::toLower(name), + ®isterer ::creator)); } + /** Register a field value type. + * + * @param T value class (must inherit from 'headerFieldValue') + * @param name field name + */ + template + void registerFieldValue(const string& name) + { + m_valueMap.insert(ValueMap::value_type + (utility::stringUtils::toLower(name), + ®isterer ::creator)); + } + + /** Create a new field object for the specified field name. + * If the field name has not been registered, a default type + * is used. + * + * @param name field name + * @param body string that will be parsed to initialize + * the value of the field + * @return a new field object + */ ref create(const string& name, const string& body = NULL_STRING); + + /** Create a new field value for the specified field. + * + * @param fieldName name of the field for which to create value + * @return a new value object for the field + */ + ref createValue(const string& fieldName); }; diff --git a/src/typeAdapter.cpp b/vmime/headerFieldValue.hpp similarity index 67% rename from src/typeAdapter.cpp rename to vmime/headerFieldValue.hpp index 1646edc2..ed26bb51 100644 --- a/src/typeAdapter.cpp +++ b/vmime/headerFieldValue.hpp @@ -21,29 +21,31 @@ // the GNU General Public License cover the whole combination. // +#ifndef VMIME_HEADERFIELDVALUE_HPP_INCLUDED +#define VMIME_HEADERFIELDVALUE_HPP_INCLUDED -#include "vmime/typeAdapter.hpp" + +#include "vmime/base.hpp" +#include "vmime/component.hpp" namespace vmime { -#if (!defined(__GNUC__) || ((__GNUC__ >= 3) && (__GNUC_MINOR__ >= 3))) && !defined(_MSC_VER) +/** Base class for all classes that can be used as a value + * for a header field. + */ -template <> -void typeAdapter ::parse(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) +class headerFieldValue : public component { - m_value = string(buffer.begin() + position, buffer.begin() + end); +public: - setParsedBounds(position, end); - - if (newPosition) - *newPosition = end; -} - -#endif // (!defined(__GNUC__) || ((__GNUC__ >= 3) && (__GNUC_MINOR__ >= 3))) && !defined(_MSC_VER) +}; } // vmime + + +#endif // VMIME_HEADERFIELDVALUE_HPP_INCLUDED + diff --git a/vmime/mailboxField.hpp b/vmime/mailboxField.hpp index afd61ac7..18a016de 100644 --- a/vmime/mailboxField.hpp +++ b/vmime/mailboxField.hpp @@ -25,15 +25,23 @@ #define VMIME_MAILBOXFIELD_HPP_INCLUDED -#include "vmime/genericField.hpp" +#include "vmime/headerField.hpp" #include "vmime/mailbox.hpp" +// Hide implementation details from user +#ifndef VMIME_BUILDING_DOC + + namespace vmime { -class mailboxField : public genericField +/** Work-around for malformed header fields that are of type 'mailbox' + * and contains multiple addresses. + */ + +class mailboxField : public headerField { friend class vmime::creator; // create ref @@ -48,7 +56,11 @@ public: }; +#endif // VMIME_BUILDING_DOC + + } // vmime #endif // VMIME_MAILBOXFIELD_HPP_INCLUDED + diff --git a/vmime/mailboxList.hpp b/vmime/mailboxList.hpp index fe417c42..126d1ae6 100644 --- a/vmime/mailboxList.hpp +++ b/vmime/mailboxList.hpp @@ -39,7 +39,7 @@ namespace vmime * from inserting mailbox groups where it is not allowed by the RFC. */ -class mailboxList : public component +class mailboxList : public headerFieldValue { public: diff --git a/vmime/mdn/MDNHelper.hpp b/vmime/mdn/MDNHelper.hpp index 322c61ab..ad6b9409 100644 --- a/vmime/mdn/MDNHelper.hpp +++ b/vmime/mdn/MDNHelper.hpp @@ -28,6 +28,8 @@ #include "vmime/mdn/receivedMDNInfos.hpp" #include "vmime/mdn/sendableMDNInfos.hpp" +#include "vmime/mailboxList.hpp" + namespace vmime { namespace mdn { diff --git a/vmime/mdn/receivedMDNInfos.hpp b/vmime/mdn/receivedMDNInfos.hpp index 0ba88fc6..b8041d16 100644 --- a/vmime/mdn/receivedMDNInfos.hpp +++ b/vmime/mdn/receivedMDNInfos.hpp @@ -26,7 +26,10 @@ #include "vmime/mdn/MDNInfos.hpp" + #include "vmime/disposition.hpp" +#include "vmime/messageId.hpp" +#include "vmime/mailbox.hpp" namespace vmime { diff --git a/vmime/mdn/sendableMDNInfos.hpp b/vmime/mdn/sendableMDNInfos.hpp index ae3c8ea0..ea01edd0 100644 --- a/vmime/mdn/sendableMDNInfos.hpp +++ b/vmime/mdn/sendableMDNInfos.hpp @@ -27,6 +27,8 @@ #include "vmime/mdn/MDNInfos.hpp" +#include "vmime/mailbox.hpp" + namespace vmime { namespace mdn { diff --git a/vmime/mediaType.hpp b/vmime/mediaType.hpp index 3e5c86ce..1bdda268 100644 --- a/vmime/mediaType.hpp +++ b/vmime/mediaType.hpp @@ -26,7 +26,7 @@ #include "vmime/base.hpp" -#include "vmime/component.hpp" +#include "vmime/headerFieldValue.hpp" namespace vmime @@ -36,7 +36,7 @@ namespace vmime /** Content media type (basic type). */ -class mediaType : public component +class mediaType : public headerFieldValue { public: diff --git a/vmime/messageId.hpp b/vmime/messageId.hpp index 1853d24d..d83bf242 100644 --- a/vmime/messageId.hpp +++ b/vmime/messageId.hpp @@ -26,7 +26,7 @@ #include "vmime/base.hpp" -#include "vmime/component.hpp" +#include "vmime/headerFieldValue.hpp" namespace vmime @@ -36,7 +36,7 @@ namespace vmime /** Message identifier (basic type). */ -class messageId : public component +class messageId : public headerFieldValue { friend class messageIdSequence; diff --git a/vmime/messageIdSequence.hpp b/vmime/messageIdSequence.hpp index a33d8a57..f7c96151 100644 --- a/vmime/messageIdSequence.hpp +++ b/vmime/messageIdSequence.hpp @@ -35,7 +35,7 @@ namespace vmime /** A list of message identifiers (basic type). */ -class messageIdSequence : public component +class messageIdSequence : public headerFieldValue { public: diff --git a/vmime/messageParser.hpp b/vmime/messageParser.hpp index 73bd4769..8c539c4f 100644 --- a/vmime/messageParser.hpp +++ b/vmime/messageParser.hpp @@ -30,6 +30,10 @@ #include "vmime/message.hpp" #include "vmime/attachment.hpp" +#include "vmime/mailbox.hpp" +#include "vmime/addressList.hpp" +#include "vmime/dateTime.hpp" + #include "vmime/textPart.hpp" diff --git a/vmime/net/message.hpp b/vmime/net/message.hpp index 7f77747e..63656608 100644 --- a/vmime/net/message.hpp +++ b/vmime/net/message.hpp @@ -26,6 +26,7 @@ #include "vmime/header.hpp" +#include "vmime/mediaType.hpp" #include "vmime/utility/progressListener.hpp" #include "vmime/utility/stream.hpp" diff --git a/vmime/net/pop3/POP3Store.hpp b/vmime/net/pop3/POP3Store.hpp index ad58f043..2839d198 100644 --- a/vmime/net/pop3/POP3Store.hpp +++ b/vmime/net/pop3/POP3Store.hpp @@ -26,6 +26,7 @@ #include "vmime/config.hpp" +#include "vmime/messageId.hpp" #include "vmime/net/store.hpp" #include "vmime/net/socket.hpp" diff --git a/vmime/net/transport.hpp b/vmime/net/transport.hpp index 8d297166..b43c05f0 100644 --- a/vmime/net/transport.hpp +++ b/vmime/net/transport.hpp @@ -28,6 +28,8 @@ #include "vmime/net/service.hpp" #include "vmime/utility/stream.hpp" +#include "vmime/mailboxList.hpp" + namespace vmime { diff --git a/vmime/parameter.hpp b/vmime/parameter.hpp index cf676084..8ac7e82c 100644 --- a/vmime/parameter.hpp +++ b/vmime/parameter.hpp @@ -27,6 +27,7 @@ #include "vmime/base.hpp" #include "vmime/component.hpp" +#include "vmime/word.hpp" namespace vmime @@ -35,11 +36,19 @@ namespace vmime class parameter : public component { - friend class parameterFactory; friend class parameterizedHeaderField; +private: + + parameter(const parameter&); + public: + parameter(const string& name); + parameter(const string& name, const word& value); + parameter(const string& name, const string& value); + + #ifndef VMIME_BUILDING_DOC /** A single section of a multi-section parameter, @@ -60,31 +69,58 @@ public: const std::vector > getChildComponents() const; - /** Return the name of the parameter. + /** Return the name of this parameter. * - * @return name of the parameter + * @return name of this parameter */ const string& getName() const; - /** Return the read-only value object attached to this field. + /** Return the raw value of this parameter. * - * @return read-only value object + * @return read-only value */ - virtual const component& getValue() const = 0; + const word& getValue() const; - /** Return the value object attached to this field. + /** Return the value of this object in the specified type. + * For example, the following code: * - * @return value object + *
+	  *    getParameter("creation-date")->getValueAs ()
+ * + * + * is equivalent to: + * + *
+	  *    ref  rawValue = getParameter("creation-date");
+	  *
+	  *    vmime::dateTime theDate;
+	  *    theDate.parse(rawValue->getBuffer());
+	  * 
+ * + * @param T type to which convert the value + * @return value */ - virtual component& getValue() = 0; + template + const T getValueAs() const + { + T ret; + ret.parse(m_value.getBuffer()); - /** Set the value of the parameter. + return ret; + } + + /** Set the value of this parameter. * - * @throw std::bad_cast_exception if the value type is - * incompatible with the parameter type - * @param value value object + * @param value new value */ - virtual void setValue(const component& value) = 0; + void setValue(const component& value); + + /** Set the raw value of this parameter. + * + * @param value new value + */ + void setValue(const word& value); + using component::parse; using component::generate; @@ -92,18 +128,13 @@ public: void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -protected: - - virtual const ref getValueImp() const = 0; - virtual const ref getValueImp() = 0; - private: + void parse(const std::vector & chunks); + + string m_name; - - void generateValue(utility::outputStream& os, const string::size_type maxLineLength, const string::size_type curLinePos, string::size_type* newLinePos) const; - - virtual void parse(const std::vector & chunks); + word m_value; }; diff --git a/vmime/parameterFactory.hpp b/vmime/parameterFactory.hpp deleted file mode 100644 index 358f2172..00000000 --- a/vmime/parameterFactory.hpp +++ /dev/null @@ -1,97 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2005 Vincent Richard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// Linking this library statically or dynamically with other modules is making -// a combined work based on this library. Thus, the terms and conditions of -// the GNU General Public License cover the whole combination. -// - -#ifndef VMIME_PARAMETERFACTORY_HPP_INCLUDED -#define VMIME_PARAMETERFACTORY_HPP_INCLUDED - - -#include "vmime/parameter.hpp" -#include "vmime/utility/stringUtils.hpp" - - -namespace vmime -{ - - -class parameterFactory -{ -protected: - - parameterFactory(); - ~parameterFactory(); - - typedef ref (*AllocFunc)(void); - typedef std::map NameMap; - - NameMap m_nameMap; - -public: - - static parameterFactory* getInstance(); - -#ifndef VMIME_BUILDING_DOC - template - class registerer - { - public: - - static ref creator() - { - // Allocate a new object - return vmime::create (); - } - }; -#endif // VMIME_BUILDING_DOC - - - template - void registerName(const string& name) - { - m_nameMap.insert(NameMap::value_type - (utility::stringUtils::toLower(name), ®isterer::creator)); - } - - /** Create a new parameter and parse its value. The returned parameter - * can then be added in a vmime::parameterizedHeaderField object. - * - * @param name parameter name (ASCII characters only) - * @param value value to be parsed - * @return created parameter - */ - ref create(const string& name, const string& value = NULL_STRING); - - /** Create a new parameter and set its value. The returned parameter - * can then be added in a vmime::parameterizedHeaderField object. - * - * @param name parameter name (ASCII characters only) - * @param value value to be set - * @return created parameter - */ - ref create(const string& name, const component& value); -}; - - -} // vmime - - -#endif // VMIME_PARAMETERFACTORY_HPP_INCLUDED diff --git a/vmime/parameterizedHeaderField.hpp b/vmime/parameterizedHeaderField.hpp index 79ab49b5..bc1dc5be 100644 --- a/vmime/parameterizedHeaderField.hpp +++ b/vmime/parameterizedHeaderField.hpp @@ -29,7 +29,6 @@ #include "vmime/headerFieldFactory.hpp" #include "vmime/parameter.hpp" #include "vmime/exception.hpp" -#include "vmime/parameterFactory.hpp" namespace vmime @@ -42,10 +41,12 @@ namespace vmime class parameterizedHeaderField : virtual public headerField { - friend class headerFieldFactory::registerer ; + friend class vmime::creator; // create ref protected: + // Protected constructor to prevent the user from creating + // new objects without using 'headerFieldFactory' parameterizedHeaderField(); public: diff --git a/vmime/path.hpp b/vmime/path.hpp index 5e45aa2c..0e8f6d3b 100644 --- a/vmime/path.hpp +++ b/vmime/path.hpp @@ -25,7 +25,7 @@ #define VMIME_PATH_HPP_INCLUDED -#include "vmime/component.hpp" +#include "vmime/headerFieldValue.hpp" namespace vmime @@ -35,7 +35,7 @@ namespace vmime /** A path: a local part + '@' + a domain. */ -class path : public component +class path : public headerFieldValue { public: diff --git a/vmime/relay.hpp b/vmime/relay.hpp index 9f21da2b..f6391221 100644 --- a/vmime/relay.hpp +++ b/vmime/relay.hpp @@ -26,7 +26,7 @@ #include "vmime/base.hpp" -#include "vmime/component.hpp" +#include "vmime/headerFieldValue.hpp" #include "vmime/dateTime.hpp" @@ -38,7 +38,7 @@ namespace vmime /** Trace information about a relay (basic type). */ -class relay : public component +class relay : public headerFieldValue { public: diff --git a/vmime/text.hpp b/vmime/text.hpp index a2914fa4..8da6d9e0 100644 --- a/vmime/text.hpp +++ b/vmime/text.hpp @@ -25,6 +25,7 @@ #define VMIME_TEXT_HPP_INCLUDED +#include "vmime/headerFieldValue.hpp" #include "vmime/base.hpp" #include "vmime/word.hpp" @@ -36,7 +37,7 @@ namespace vmime /** List of encoded-words, as defined in RFC-2047 (basic type). */ -class text : public component +class text : public headerFieldValue { public: @@ -142,6 +143,14 @@ public: */ const string getConvertedText(const charset& dest) const; + /** Return the unconverted (raw) data of all words. This is the + * concatenation of the results returned by getBuffer() on + * the contained words. + * + * @return raw data + */ + const string getWholeBuffer() const; + /** This function can be used to make several encoded words from a text. * All the characters in the text must be in the same specified charset. * diff --git a/vmime/typeAdapter.hpp b/vmime/typeAdapter.hpp deleted file mode 100644 index 2ad8e80a..00000000 --- a/vmime/typeAdapter.hpp +++ /dev/null @@ -1,159 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2005 Vincent Richard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of -// the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// Linking this library statically or dynamically with other modules is making -// a combined work based on this library. Thus, the terms and conditions of -// the GNU General Public License cover the whole combination. -// - -#ifndef VMIME_TYPEADAPTER_HPP_INCLUDED -#define VMIME_TYPEADAPTER_HPP_INCLUDED - - -#include - -#include "vmime/component.hpp" - - -namespace vmime -{ - - -/** An adapter to allow any type to act as a 'component'. - */ - -template -class typeAdapter : public component -{ -public: - - typeAdapter() - { - } - - typeAdapter(typeAdapter& a) - : component(), m_value(a.m_value) - { - } - - typeAdapter(const TYPE& v) - : m_value(v) - { - } - - - ref clone() const - { - return create (*this); - } - - - void copyFrom(const component& other) - { - m_value = dynamic_cast &>(other).m_value; - } - - - typeAdapter& operator=(const TYPE& v) - { - m_value = v; - return (*this); - } - - - typeAdapter& operator=(const component& other) - { - copyFrom(other); - return (*this); - } - - - operator TYPE() const - { - return (m_value); - } - - - void parse(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition = NULL) - { - std::istringstream iss(string(buffer.begin() + position, buffer.begin() + end)); - iss >> m_value; - - setParsedBounds(position, end); - - if (newPosition) - *newPosition = end; - } - - - void generate(utility::outputStream& os, - const string::size_type /* maxLineLength */ = lineLengthLimits::infinite, - const string::size_type curLinePos = 0, - string::size_type* newLinePos = NULL) const - { - std::ostringstream oss; - oss << m_value; - - os << oss.str(); - - if (newLinePos) - *newLinePos = curLinePos + oss.str().length(); - } - - const std::vector > getChildComponents() const - { - return std::vector >(); - } - -private: - - TYPE m_value; -}; - - -#if (defined(__GNUC__) && (__GNUC__ >= 3) && (__GNUC_MINOR__ <= 2)) || defined(_MSC_VER) - - // Because of a bug with g++ <= 3.2, we have to put the implementation - // of the function inline. - - template <> - inline void typeAdapter ::parse - (const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - m_value = string(buffer.begin() + position, buffer.begin() + end); - - if (newPosition) - *newPosition = end; - } - -#else - - template <> - void typeAdapter ::parse - (const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition); - -#endif // (defined(__GNUC__) && (__GNUC__ >= 3) && (__GNUC_MINOR__ <= 2)) || defined(_MSC_VER) - - -} // vmime - - -#endif // VMIME_TYPEADAPTE_HPP_INCLUDED diff --git a/vmime/vmime.hpp b/vmime/vmime.hpp index 36b9e0e3..cbae859e 100644 --- a/vmime/vmime.hpp +++ b/vmime/vmime.hpp @@ -48,8 +48,10 @@ #include "vmime/addressList.hpp" #include "vmime/mediaType.hpp" #include "vmime/messageId.hpp" +#include "vmime/messageIdSequence.hpp" #include "vmime/relay.hpp" #include "vmime/disposition.hpp" +#include "vmime/path.hpp" #include "vmime/emptyContentHandler.hpp" #include "vmime/stringContentHandler.hpp" @@ -62,7 +64,6 @@ #include "vmime/headerFieldFactory.hpp" #include "vmime/mailboxField.hpp" #include "vmime/parameterizedHeaderField.hpp" -#include "vmime/standardFields.hpp" // Encoders #include "vmime/encoderFactory.hpp" diff --git a/vmime/word.hpp b/vmime/word.hpp index 79aef9c8..284b64d6 100644 --- a/vmime/word.hpp +++ b/vmime/word.hpp @@ -25,7 +25,7 @@ #define VMIME_WORD_HPP_INCLUDED -#include "vmime/component.hpp" +#include "vmime/headerFieldValue.hpp" #include "vmime/charset.hpp" @@ -37,7 +37,7 @@ namespace vmime * some text encoded into one specified charset. */ -class word : public component +class word : public headerFieldValue { friend class text;