diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/body.cpp | 98 | ||||
-rw-r--r-- | src/charset.cpp | 50 | ||||
-rw-r--r-- | src/emptyContentHandler.cpp | 6 | ||||
-rw-r--r-- | src/encoding.cpp | 38 | ||||
-rw-r--r-- | src/htmlTextPart.cpp | 19 | ||||
-rw-r--r-- | src/net/imap/IMAPMessagePartContentHandler.cpp | 6 | ||||
-rw-r--r-- | src/plainTextPart.cpp | 9 | ||||
-rw-r--r-- | src/streamContentHandler.cpp | 7 | ||||
-rw-r--r-- | src/stringContentHandler.cpp | 6 | ||||
-rw-r--r-- | src/wordEncoder.cpp | 58 |
10 files changed, 226 insertions, 71 deletions
diff --git a/src/body.cpp b/src/body.cpp index 3f5ff0f6..13dff6b4 100644 --- a/src/body.cpp +++ b/src/body.cpp @@ -213,8 +213,26 @@ void body::parse(const string& buffer, const string::size_type position, // Treat the contents as 'simple' data else { + encoding enc; + + try + { + const ref <const headerField> cef = + m_header.acquire()->findField(fields::CONTENT_TRANSFER_ENCODING); + + enc = *cef->getValue().dynamicCast <const encoding>(); + } + catch (exceptions::no_such_field&) + { + // Defaults to "7bit" (RFC-1521) + enc = vmime::encoding(encodingTypes::SEVEN_BIT); + + // Set header field + m_header.acquire()->ContentTransferEncoding()->setValue(enc); + } + // Extract the (encoded) contents - m_contents = vmime::create <stringContentHandler>(buffer, position, end, getEncoding()); + m_contents = vmime::create <stringContentHandler>(buffer, position, end, enc); } setParsedBounds(position, end); @@ -406,6 +424,22 @@ bool body::isValidBoundary(const string& boundary) // Quick-access functions // + +void body::setContentType(const mediaType& type, const charset& chset) +{ + ref <contentTypeField> ctf = m_header.acquire()->ContentType().dynamicCast <contentTypeField>(); + + ctf->setValue(type); + ctf->setCharset(chset); +} + + +void body::setContentType(const mediaType& type) +{ + m_header.acquire()->ContentType()->setValue(type); +} + + const mediaType body::getContentType() const { try @@ -423,6 +457,25 @@ const mediaType body::getContentType() const } +void body::setCharset(const charset& chset) +{ + // If a Content-Type field exists, set charset + try + { + ref <contentTypeField> ctf = + m_header.acquire()->findField(fields::CONTENT_TYPE).dynamicCast <contentTypeField>(); + + ctf->setCharset(chset); + } + // Else, create a new Content-Type field of default type "text/plain" + // and set charset on it + catch (exceptions::no_such_field&) + { + setContentType(mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN), chset); + } +} + + const charset body::getCharset() const { try @@ -445,6 +498,12 @@ const charset body::getCharset() const } +void body::setEncoding(const encoding& enc) +{ + m_header.acquire()->ContentTransferEncoding()->setValue(enc); +} + + const encoding body::getEncoding() const { try @@ -456,8 +515,15 @@ const encoding body::getEncoding() const } catch (exceptions::no_such_field&) { - // Defaults to "7bit" (RFC-1521) - return (vmime::encoding(encodingTypes::SEVEN_BIT)); + if (m_contents->isEncoded()) + { + return m_contents->getEncoding(); + } + else + { + // Defaults to "7bit" (RFC-1521) + return vmime::encoding(encodingTypes::SEVEN_BIT); + } } } @@ -551,6 +617,32 @@ void body::setContents(ref <const contentHandler> contents) } +void body::setContents(ref <const contentHandler> contents, const mediaType& type) +{ + m_contents = contents; + + setContentType(type); +} + + +void body::setContents(ref <const contentHandler> contents, const mediaType& type, const charset& chset) +{ + m_contents = contents; + + setContentType(type, chset); +} + + +void body::setContents(ref <const contentHandler> contents, const mediaType& type, + const charset& chset, const encoding& enc) +{ + m_contents = contents; + + setContentType(type, chset); + setEncoding(enc); +} + + void body::initNewPart(ref <bodyPart> part) { part->m_parent = m_part; diff --git a/src/charset.cpp b/src/charset.cpp index e3c11daa..e0431860 100644 --- a/src/charset.cpp +++ b/src/charset.cpp @@ -24,6 +24,7 @@ #include "vmime/charset.hpp" #include "vmime/exception.hpp" #include "vmime/platform.hpp" +#include "vmime/encoding.hpp" #include "vmime/utility/stringUtils.hpp" @@ -140,4 +141,53 @@ const std::vector <ref <const component> > charset::getChildComponents() const } + +// Explicitly force encoding for some charsets +struct CharsetEncodingEntry +{ + CharsetEncodingEntry(const string& charset_, const string& encoding_) + : charset(charset_), encoding(encoding_) + { + } + + const string charset; + const string encoding; +}; + +CharsetEncodingEntry g_charsetEncodingMap[] = +{ + // Use QP encoding for ISO-8859-x charsets + CharsetEncodingEntry("iso-8859", encodingTypes::QUOTED_PRINTABLE), + CharsetEncodingEntry("iso8859", encodingTypes::QUOTED_PRINTABLE), + + // RFC-1468 states: + // " ISO-2022-JP may also be used in MIME Part 2 headers. The "B" + // encoding should be used with ISO-2022-JP text. " + // Use Base64 encoding for all ISO-2022 charsets. + CharsetEncodingEntry("iso-2022", encodingTypes::BASE64), + CharsetEncodingEntry("iso2022", encodingTypes::BASE64), + + // Last entry is not used + CharsetEncodingEntry("", "") +}; + + +bool charset::getRecommendedEncoding(encoding& enc) const +{ + // Special treatment for some charsets + const string cset = utility::stringUtils::toLower(getName()); + + for (unsigned int i = 0 ; i < (sizeof(g_charsetEncodingMap) / sizeof(g_charsetEncodingMap[0])) - 1 ; ++i) + { + if (cset.find(g_charsetEncodingMap[i].charset) != string::npos) + { + enc = g_charsetEncodingMap[i].encoding; + return true; + } + } + + return false; +} + + } // vmime diff --git a/src/emptyContentHandler.cpp b/src/emptyContentHandler.cpp index 5245341a..48dc3511 100644 --- a/src/emptyContentHandler.cpp +++ b/src/emptyContentHandler.cpp @@ -96,4 +96,10 @@ const vmime::encoding& emptyContentHandler::getEncoding() const } +bool emptyContentHandler::isBuffered() const +{ + return true; +} + + } // vmime diff --git a/src/encoding.cpp b/src/encoding.cpp index 58ce71de..0919d44c 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -110,7 +110,7 @@ bool encoding::operator!=(const encoding& value) const } -const encoding encoding::decide +const encoding encoding::decideImpl (const string::const_iterator begin, const string::const_iterator end) { const string::difference_type length = end - begin; @@ -164,10 +164,40 @@ const encoding encoding::decide } -const encoding encoding::decide(ref <const contentHandler> /* data */) +const encoding encoding::decide + (ref <const contentHandler> data, const EncodingUsage usage) { - // TODO: a better solution to do that? - return (encoding(encodingTypes::BASE64)); + if (usage == USAGE_TEXT && data->isBuffered() && + data->getLength() > 0 && data->getLength() < 32768) + { + // Extract data into temporary buffer + string buffer; + utility::outputStreamStringAdapter os(buffer); + + data->extract(os); + os.flush(); + + return decideImpl(buffer.begin(), buffer.end()); + } + else + { + return encoding(encodingTypes::BASE64); + } +} + + +const encoding encoding::decide(ref <const contentHandler> data, + const charset& chset, const EncodingUsage usage) +{ + if (usage == USAGE_TEXT) + { + encoding recEncoding; + + if (chset.getRecommendedEncoding(recEncoding)) + return recEncoding; + } + + return decide(data, usage); } diff --git a/src/htmlTextPart.cpp b/src/htmlTextPart.cpp index 7713034f..c845b576 100644 --- a/src/htmlTextPart.cpp +++ b/src/htmlTextPart.cpp @@ -69,27 +69,20 @@ void htmlTextPart::generateIn(ref <bodyPart> /* message */, ref <bodyPart> paren ref <bodyPart> part = vmime::create <bodyPart>(); parent->getBody()->appendPart(part); - // -- Set header fields - part->getHeader()->ContentType()->setValue - (mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN)); - part->getHeader()->ContentType().dynamicCast <contentTypeField>()->setCharset(m_charset); - part->getHeader()->ContentTransferEncoding()->setValue(encoding(encodingTypes::QUOTED_PRINTABLE)); - // -- Set contents - part->getBody()->setContents(m_plainText); + part->getBody()->setContents(m_plainText, + mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN), m_charset, + encoding::decide(m_plainText, m_charset, encoding::USAGE_TEXT)); } // HTML text // -- Create a new part ref <bodyPart> htmlPart = vmime::create <bodyPart>(); - // -- Set header fields - htmlPart->getHeader()->ContentType()->setValue(mediaType(mediaTypes::TEXT, mediaTypes::TEXT_HTML)); - htmlPart->getHeader()->ContentType().dynamicCast <contentTypeField>()->setCharset(m_charset); - htmlPart->getHeader()->ContentTransferEncoding()->setValue(encoding(encodingTypes::QUOTED_PRINTABLE)); - // -- Set contents - htmlPart->getBody()->setContents(m_text); + htmlPart->getBody()->setContents(m_text, + mediaType(mediaTypes::TEXT, mediaTypes::TEXT_HTML), m_charset, + encoding::decide(m_text, m_charset, encoding::USAGE_TEXT)); // Handle the case we have embedded objects if (!m_objects.empty()) diff --git a/src/net/imap/IMAPMessagePartContentHandler.cpp b/src/net/imap/IMAPMessagePartContentHandler.cpp index a226b680..4e6ba97a 100644 --- a/src/net/imap/IMAPMessagePartContentHandler.cpp +++ b/src/net/imap/IMAPMessagePartContentHandler.cpp @@ -173,6 +173,12 @@ bool IMAPMessagePartContentHandler::isEmpty() const } +bool IMAPMessagePartContentHandler::isBuffered() const +{ + return true; +} + + } // imap } // net } // vmime diff --git a/src/plainTextPart.cpp b/src/plainTextPart.cpp index 7a674e79..15bcb5eb 100644 --- a/src/plainTextPart.cpp +++ b/src/plainTextPart.cpp @@ -63,13 +63,10 @@ void plainTextPart::generateIn(ref <bodyPart> /* message */, ref <bodyPart> pare ref <bodyPart> part = vmime::create <bodyPart>(); parent->getBody()->appendPart(part); - // Set header fields - part->getHeader()->ContentType()->setValue(mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN)); - part->getHeader()->ContentType().dynamicCast <contentTypeField>()->setCharset(m_charset); - part->getHeader()->ContentTransferEncoding()->setValue(encoding(encodingTypes::QUOTED_PRINTABLE)); - // Set contents - part->getBody()->setContents(m_text); + part->getBody()->setContents(m_text, + mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN), m_charset, + encoding::decide(m_text, m_charset, encoding::USAGE_TEXT)); } diff --git a/src/streamContentHandler.cpp b/src/streamContentHandler.cpp index 9edf4aa6..2ebd073a 100644 --- a/src/streamContentHandler.cpp +++ b/src/streamContentHandler.cpp @@ -201,4 +201,11 @@ const vmime::encoding& streamContentHandler::getEncoding() const } +bool streamContentHandler::isBuffered() const +{ + // FIXME: some streams can be resetted + return false; +} + + } // vmime diff --git a/src/stringContentHandler.cpp b/src/stringContentHandler.cpp index 248fca47..4e85a6ce 100644 --- a/src/stringContentHandler.cpp +++ b/src/stringContentHandler.cpp @@ -202,4 +202,10 @@ const vmime::encoding& stringContentHandler::getEncoding() const } +bool stringContentHandler::isBuffered() const +{ + return true; +} + + } // vmime diff --git a/src/wordEncoder.cpp b/src/wordEncoder.cpp index cc8292f8..22994edf 100644 --- a/src/wordEncoder.cpp +++ b/src/wordEncoder.cpp @@ -26,6 +26,8 @@ #include "vmime/exception.hpp" #include "vmime/charsetConverter.hpp" +#include "vmime/encoding.hpp" + #include "vmime/utility/encoder/b64Encoder.hpp" #include "vmime/utility/encoder/qpEncoder.hpp" @@ -260,50 +262,14 @@ wordEncoder::Encoding wordEncoder::getEncoding() const } -// Explicitly force encoding for some charsets -struct CharsetEncodingEntry -{ - CharsetEncodingEntry(const std::string& charset_, const wordEncoder::Encoding encoding_) - : charset(charset_), encoding(encoding_) - { - } - - std::string charset; - wordEncoder::Encoding encoding; -}; - -CharsetEncodingEntry g_charsetEncodingMap[] = -{ - // Use QP encoding for ISO-8859-x charsets - CharsetEncodingEntry("iso-8859", wordEncoder::ENCODING_QP), - CharsetEncodingEntry("iso8859", wordEncoder::ENCODING_QP), - - // RFC-1468 states: - // " ISO-2022-JP may also be used in MIME Part 2 headers. The "B" - // encoding should be used with ISO-2022-JP text. " - // Use Base64 encoding for all ISO-2022 charsets. - CharsetEncodingEntry("iso-2022", wordEncoder::ENCODING_B64), - CharsetEncodingEntry("iso2022", wordEncoder::ENCODING_B64), - - // Last entry is not used - CharsetEncodingEntry("", wordEncoder::ENCODING_AUTO) -}; - - // static bool wordEncoder::isEncodingNeeded(const string& buffer, const charset& charset) { - // Special treatment for some charsets - const string cset = utility::stringUtils::toLower(charset.getName()); + // Charset-specific encoding + encoding recEncoding; - for (unsigned int i = 0 ; i < (sizeof(g_charsetEncodingMap) / sizeof(g_charsetEncodingMap[0])) - 1 ; ++i) - { - if (cset.find(g_charsetEncodingMap[i].charset) != string::npos) - { - if (g_charsetEncodingMap[i].encoding != wordEncoder::ENCODING_AUTO) - return true; - } - } + if (charset.getRecommendedEncoding(recEncoding)) + return true; // No encoding is needed if the buffer only contains ASCII chars if (utility::stringUtils::findFirstNonASCIIchar(buffer.begin(), buffer.end()) != string::npos) @@ -322,13 +288,15 @@ bool wordEncoder::isEncodingNeeded(const string& buffer, const charset& charset) wordEncoder::Encoding wordEncoder::guessBestEncoding (const string& buffer, const charset& charset) { - // Special treatment for some charsets - const string cset = utility::stringUtils::toLower(charset.getName()); + // Charset-specific encoding + encoding recEncoding; - for (unsigned int i = 0 ; i < (sizeof(g_charsetEncodingMap) / sizeof(g_charsetEncodingMap[0])) - 1 ; ++i) + if (charset.getRecommendedEncoding(recEncoding)) { - if (cset.find(g_charsetEncodingMap[i].charset) != string::npos) - return g_charsetEncodingMap[i].encoding; + if (recEncoding == encoding(encodingTypes::QUOTED_PRINTABLE)) + return ENCODING_QP; + else + return ENCODING_B64; } // Use Base64 if more than 40% non-ASCII, or Quoted-Printable else (default) |