aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/body.cpp98
-rw-r--r--src/charset.cpp50
-rw-r--r--src/emptyContentHandler.cpp6
-rw-r--r--src/encoding.cpp38
-rw-r--r--src/htmlTextPart.cpp19
-rw-r--r--src/net/imap/IMAPMessagePartContentHandler.cpp6
-rw-r--r--src/plainTextPart.cpp9
-rw-r--r--src/streamContentHandler.cpp7
-rw-r--r--src/stringContentHandler.cpp6
-rw-r--r--src/wordEncoder.cpp58
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)