Fixed wrong encoding of line breaks in QP-encoded text (issue #7).

This commit is contained in:
Vincent Richard 2012-04-05 23:15:04 +02:00
parent ec715e6058
commit 0633a49b04
4 changed files with 91 additions and 10 deletions

View File

@ -34,19 +34,28 @@ namespace vmime
encoding::encoding() encoding::encoding()
: m_name(encodingTypes::SEVEN_BIT) : m_name(encodingTypes::SEVEN_BIT),
m_usage(USAGE_UNKNOWN)
{ {
} }
encoding::encoding(const string& name) 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) 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, void encoding::parse(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition) const string::size_type end, string::size_type* newPosition)
{ {
m_usage = USAGE_UNKNOWN;
m_name = utility::stringUtils::toLower(utility::stringUtils::trim m_name = utility::stringUtils::toLower(utility::stringUtils::trim
(utility::stringUtils::unquote(utility::stringUtils::trim (utility::stringUtils::unquote(utility::stringUtils::trim
(string(buffer.begin() + position, buffer.begin() + end))))); (string(buffer.begin() + position, buffer.begin() + end)))));
@ -80,7 +91,14 @@ void encoding::generate(utility::outputStream& os, const string::size_type /* ma
ref <utility::encoder::encoder> encoding::getEncoder() const ref <utility::encoder::encoder> encoding::getEncoder() const
{ {
return (utility::encoder::encoderFactory::getInstance()->create(generate())); ref <utility::encoder::encoder> 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) encoding& encoding::operator=(const string& name)
{ {
m_name = utility::stringUtils::toLower(name); m_name = utility::stringUtils::toLower(name);
m_usage = USAGE_UNKNOWN;
return (*this); return (*this);
} }
@ -167,6 +186,8 @@ const encoding encoding::decideImpl
const encoding encoding::decide const encoding encoding::decide
(ref <const contentHandler> data, const EncodingUsage usage) (ref <const contentHandler> data, const EncodingUsage usage)
{ {
encoding enc;
if (usage == USAGE_TEXT && data->isBuffered() && if (usage == USAGE_TEXT && data->isBuffered() &&
data->getLength() > 0 && data->getLength() < 32768) data->getLength() > 0 && data->getLength() < 32768)
{ {
@ -177,12 +198,16 @@ const encoding encoding::decide
data->extract(os); data->extract(os);
os.flush(); os.flush();
return decideImpl(buffer.begin(), buffer.end()); enc = decideImpl(buffer.begin(), buffer.end());
} }
else else
{ {
return encoding(encodingTypes::BASE64); enc = encoding(encodingTypes::BASE64);
} }
enc.setUsage(usage);
return enc;
} }
@ -194,8 +219,11 @@ const encoding encoding::decide(ref <const contentHandler> data,
encoding recEncoding; encoding recEncoding;
if (chset.getRecommendedEncoding(recEncoding)) if (chset.getRecommendedEncoding(recEncoding))
{
recEncoding.setUsage(usage);
return recEncoding; return recEncoding;
} }
}
return decide(data, usage); 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 <ref <const component> > encoding::getChildComponents() const const std::vector <ref <const component> > encoding::getChildComponents() const
{ {
return std::vector <ref <const component> >(); return std::vector <ref <const component> >();

View File

@ -292,14 +292,15 @@ utility::stream::size_type qpEncoder::encode(utility::inputStream& in,
case 13: // CR case 13: // CR
case 10: // LF case 10: // LF
{ {
// Text mode (where using CRLF or LF or ... does not // RFC-2045/6.7(4)
// care for a new line...)
if (text) // Text data
if (text && !rfc2047)
{ {
outBuffer[outBufferPos++] = c; outBuffer[outBufferPos++] = c;
++curCol; ++curCol;
} }
// Binary mode (where CR and LF bytes are important!) // Binary data
else else
{ {
QP_ENCODE_HEX(c); QP_ENCODE_HEX(c);

View File

@ -38,6 +38,7 @@ VMIME_TEST_SUITE_BEGIN
VMIME_TEST(testPrologEncoding) VMIME_TEST(testPrologEncoding)
VMIME_TEST(testSuccessiveBoundaries) VMIME_TEST(testSuccessiveBoundaries)
VMIME_TEST(testGenerate7bit) VMIME_TEST(testGenerate7bit)
VMIME_TEST(testTextUsageForQPEncoding)
VMIME_TEST_LIST_END VMIME_TEST_LIST_END
@ -214,5 +215,28 @@ VMIME_TEST_SUITE_BEGIN
VASSERT_EQ("1", "7bit", header1->ContentTransferEncoding()->getValue()->generate()); VASSERT_EQ("1", "7bit", header1->ContentTransferEncoding()->getValue()->generate());
} }
void testTextUsageForQPEncoding()
{
vmime::ref <vmime::plainTextPart> part = vmime::create <vmime::plainTextPart>();
part->setText(vmime::create <vmime::stringContentHandler>("Part1-line1\r\nPart1-line2\r\n\x89"));
vmime::ref <vmime::message> msg = vmime::create <vmime::message>();
part->generateIn(msg, msg);
vmime::ref <vmime::body> body = msg->getBody()->getPartAt(0)->getBody();
vmime::ref <vmime::header> 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 VMIME_TEST_SUITE_END

View File

@ -47,6 +47,7 @@ public:
enum EncodingUsage enum EncodingUsage
{ {
USAGE_UNKNOWN,
USAGE_TEXT, /**< Use for body text. */ USAGE_TEXT, /**< Use for body text. */
USAGE_BINARY_DATA /**< Use for attachment, image... */ USAGE_BINARY_DATA /**< Use for attachment, image... */
}; };
@ -54,6 +55,7 @@ public:
encoding(); encoding();
explicit encoding(const string& name); explicit encoding(const string& name);
encoding(const string& name, const EncodingUsage usage);
encoding(const encoding& enc); encoding(const encoding& enc);
public: public:
@ -72,6 +74,19 @@ public:
*/ */
void setName(const string& name); 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 encoding& other);
encoding& operator=(const string& name); encoding& operator=(const string& name);
@ -113,6 +128,7 @@ public:
private: private:
string m_name; string m_name;
EncodingUsage m_usage;
/** Decide which encoding to use based on the specified data. /** Decide which encoding to use based on the specified data.
* *