diff --git a/src/encoding.cpp b/src/encoding.cpp index 0919d44c..b4e79db7 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -34,19 +34,28 @@ namespace vmime encoding::encoding() - : m_name(encodingTypes::SEVEN_BIT) + : m_name(encodingTypes::SEVEN_BIT), + m_usage(USAGE_UNKNOWN) { } encoding::encoding(const string& name) - : m_name(utility::stringUtils::toLower(name)) + : m_name(utility::stringUtils::toLower(name)), + m_usage(USAGE_UNKNOWN) +{ +} + + +encoding::encoding(const string& name, const EncodingUsage usage) + : m_name(utility::stringUtils::toLower(name)), + m_usage(usage) { } encoding::encoding(const encoding& enc) - : headerFieldValue(), m_name(enc.m_name) + : headerFieldValue(), m_name(enc.m_name), m_usage(enc.m_usage) { } @@ -54,6 +63,8 @@ encoding::encoding(const encoding& enc) void encoding::parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition) { + m_usage = USAGE_UNKNOWN; + m_name = utility::stringUtils::toLower(utility::stringUtils::trim (utility::stringUtils::unquote(utility::stringUtils::trim (string(buffer.begin() + position, buffer.begin() + end))))); @@ -80,7 +91,14 @@ void encoding::generate(utility::outputStream& os, const string::size_type /* ma ref encoding::getEncoder() const { - return (utility::encoder::encoderFactory::getInstance()->create(generate())); + ref encoder = + utility::encoder::encoderFactory::getInstance()->create(generate()); + + // FIXME: this should not be here (move me into QP encoder instead?) + if (m_usage == USAGE_TEXT && m_name == encodingTypes::QUOTED_PRINTABLE) + encoder->getProperties()["text"] = true; + + return encoder; } @@ -94,6 +112,7 @@ encoding& encoding::operator=(const encoding& other) encoding& encoding::operator=(const string& name) { m_name = utility::stringUtils::toLower(name); + m_usage = USAGE_UNKNOWN; return (*this); } @@ -167,6 +186,8 @@ const encoding encoding::decideImpl const encoding encoding::decide (ref data, const EncodingUsage usage) { + encoding enc; + if (usage == USAGE_TEXT && data->isBuffered() && data->getLength() > 0 && data->getLength() < 32768) { @@ -177,12 +198,16 @@ const encoding encoding::decide data->extract(os); os.flush(); - return decideImpl(buffer.begin(), buffer.end()); + enc = decideImpl(buffer.begin(), buffer.end()); } else { - return encoding(encodingTypes::BASE64); + enc = encoding(encodingTypes::BASE64); } + + enc.setUsage(usage); + + return enc; } @@ -194,7 +219,10 @@ const encoding encoding::decide(ref data, encoding recEncoding; if (chset.getRecommendedEncoding(recEncoding)) + { + recEncoding.setUsage(usage); return recEncoding; + } } return decide(data, usage); @@ -227,6 +255,18 @@ void encoding::setName(const string& name) } +encoding::EncodingUsage encoding::getUsage() const +{ + return m_usage; +} + + +void encoding::setUsage(const EncodingUsage usage) +{ + m_usage = usage; +} + + const std::vector > encoding::getChildComponents() const { return std::vector >(); diff --git a/src/utility/encoder/qpEncoder.cpp b/src/utility/encoder/qpEncoder.cpp index aa95022f..ab8db2e4 100644 --- a/src/utility/encoder/qpEncoder.cpp +++ b/src/utility/encoder/qpEncoder.cpp @@ -292,14 +292,15 @@ utility::stream::size_type qpEncoder::encode(utility::inputStream& in, case 13: // CR case 10: // LF { - // Text mode (where using CRLF or LF or ... does not - // care for a new line...) - if (text) + // RFC-2045/6.7(4) + + // Text data + if (text && !rfc2047) { outBuffer[outBufferPos++] = c; ++curCol; } - // Binary mode (where CR and LF bytes are important!) + // Binary data else { QP_ENCODE_HEX(c); diff --git a/tests/parser/bodyPartTest.cpp b/tests/parser/bodyPartTest.cpp index e1d47a36..9d51262a 100644 --- a/tests/parser/bodyPartTest.cpp +++ b/tests/parser/bodyPartTest.cpp @@ -38,6 +38,7 @@ VMIME_TEST_SUITE_BEGIN VMIME_TEST(testPrologEncoding) VMIME_TEST(testSuccessiveBoundaries) VMIME_TEST(testGenerate7bit) + VMIME_TEST(testTextUsageForQPEncoding) VMIME_TEST_LIST_END @@ -214,5 +215,28 @@ VMIME_TEST_SUITE_BEGIN VASSERT_EQ("1", "7bit", header1->ContentTransferEncoding()->getValue()->generate()); } + void testTextUsageForQPEncoding() + { + vmime::ref part = vmime::create (); + part->setText(vmime::create ("Part1-line1\r\nPart1-line2\r\n\x89")); + + vmime::ref msg = vmime::create (); + part->generateIn(msg, msg); + + vmime::ref body = msg->getBody()->getPartAt(0)->getBody(); + vmime::ref header = msg->getBody()->getPartAt(0)->getHeader(); + + std::ostringstream oss; + vmime::utility::outputStreamAdapter os(oss); + body->generate(os, 80); + + VASSERT_EQ("1", "quoted-printable", header->ContentTransferEncoding()->getValue()->generate()); + + // This should *NOT* be: + // Part1-line1=0D=0APart1-line2=0D=0A=89 + VASSERT_EQ("2", "Part1-line1\r\nPart1-line2\r\n=89", oss.str()); + } + + VMIME_TEST_SUITE_END diff --git a/vmime/encoding.hpp b/vmime/encoding.hpp index ba78081a..42f5246d 100644 --- a/vmime/encoding.hpp +++ b/vmime/encoding.hpp @@ -47,6 +47,7 @@ public: enum EncodingUsage { + USAGE_UNKNOWN, USAGE_TEXT, /**< Use for body text. */ USAGE_BINARY_DATA /**< Use for attachment, image... */ }; @@ -54,6 +55,7 @@ public: encoding(); explicit encoding(const string& name); + encoding(const string& name, const EncodingUsage usage); encoding(const encoding& enc); public: @@ -72,6 +74,19 @@ public: */ void setName(const string& name); + /** Return the type of contents this encoding is used for. + * See the EncodingUsage enum. + */ + EncodingUsage getUsage() const; + + /** Set the type of contents this encoding is used for. + * See the EncodingUsage enum. + * + * @param usage type of contents + */ + void setUsage(const EncodingUsage usage); + + encoding& operator=(const encoding& other); encoding& operator=(const string& name); @@ -113,6 +128,7 @@ public: private: string m_name; + EncodingUsage m_usage; /** Decide which encoding to use based on the specified data. *