This file is part of MXE. See index.html for further information. Cherry picked fixes from svn http://sourceforge.net/projects/vmime/develop Produced with this script: #--------------------------------------------------------------------# #!/usr/bin/env bash ( echo "This file is part of MXE." echo "See index.html for further information." echo echo "Cherry picked fixes from svn" echo "http://sourceforge.net/projects/vmime/develop" echo echo "Produced with this script:" echo "#--------------------------------------------------------------------#" cat "$0" echo "#--------------------------------------------------------------------#" ) > src/vmime-1-fixes.patch # setup git svn clone #cd ~/projects/vmime/git #git svn clone -s https://vmime.svn.sourceforge.net/svnroot/vmime #git reset --hard # get updates #git svn fetch #git svn rebase GITDIR=~/projects/vmime/git/vmime ( cd $GITDIR echo git format-patch -p --relative=vmime --stdout ":/Version 0.9.1"..master-fixed ) >> src/vmime-1-fixes.patch #--------------------------------------------------------------------# From ed4451fd3c86faf9ecc03a59ba9f1ad78417a9f9 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Tue, 16 Nov 2010 13:28:05 +0000 Subject: [PATCH 01/27] Started version 0.9.2. git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@576 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/ChangeLog b/ChangeLog index 871d055..8fdcdb0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,12 @@ +VERSION 0.9.2svn +================ + +2010-11-16 Vincent Richard + + * Started version 0.9.2. + + VERSION 0.9.1 ============= diff --git a/SConstruct b/SConstruct index fb01edf..55f9223 100644 --- a/SConstruct +++ b/SConstruct @@ -29,7 +29,7 @@ import string # Package version number packageVersionMajor = 0 packageVersionMinor = 9 -packageVersionMicro = 1 +packageVersionMicro = 2 # API version number (libtool) # -- 1.7.7.3 From bf282a05cdbbb538a1cafbd7305cece14f5b1571 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Tue, 30 Nov 2010 14:57:03 +0000 Subject: [PATCH 02/27] Initialize and delete object. git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@577 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/vmime/net/imap/IMAPParser.hpp b/vmime/net/imap/IMAPParser.hpp index 0f3e9ec..d71c3ca 100644 --- a/vmime/net/imap/IMAPParser.hpp +++ b/vmime/net/imap/IMAPParser.hpp @@ -3823,7 +3823,9 @@ public: msg_att_item() : m_date_time(NULL), m_number(NULL), m_envelope(NULL), - m_uniqueid(NULL), m_nstring(NULL), m_body(NULL), m_flag_list(NULL) + m_uniqueid(NULL), m_nstring(NULL), m_body(NULL), m_flag_list(NULL), + m_section(NULL) + { } @@ -3836,6 +3838,7 @@ public: delete (m_nstring); delete (m_body); delete (m_flag_list); + delete (m_section); } void go(IMAPParser& parser, string& line, string::size_type* currentPos) -- 1.7.7.3 From 941b10bca8e89ca61eebee1345ee3e5cbebd7530 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Mon, 6 Dec 2010 11:57:44 +0000 Subject: [PATCH 03/27] Updated deprecated function. git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@578 5301114d-f842-0410-bbdd-996ee0417009 SKIPPED -- 1.7.7.3 From 4a4c3a94db671ff7750b32ebf2c998a914717367 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Wed, 8 Dec 2010 08:52:54 +0000 Subject: [PATCH 04/27] No extra space between ':' and '<' in MAIL FROM and RCPT TO. Wait for server response after QUIT and before closing connection. git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@579 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/net/smtp/SMTPTransport.cpp b/src/net/smtp/SMTPTransport.cpp index 204daae..d9fb7b8 100644 --- a/src/net/smtp/SMTPTransport.cpp +++ b/src/net/smtp/SMTPTransport.cpp @@ -516,6 +516,7 @@ void SMTPTransport::internalDisconnect() try { sendRequest("QUIT"); + readResponse(); } catch (exception&) { @@ -565,7 +566,7 @@ void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients // Emit the "MAIL" command ref resp; - sendRequest("MAIL FROM: <" + expeditor.getEmail() + ">"); + sendRequest("MAIL FROM:<" + expeditor.getEmail() + ">"); if ((resp = readResponse())->getCode() != 250) { @@ -578,7 +579,7 @@ void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients { const mailbox& mbox = *recipients.getMailboxAt(i); - sendRequest("RCPT TO: <" + mbox.getEmail() + ">"); + sendRequest("RCPT TO:<" + mbox.getEmail() + ">"); if ((resp = readResponse())->getCode() != 250) { -- 1.7.7.3 From 4ea325c953f0cdc669b932aa4961a434656f3ecf Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Fri, 10 Dec 2010 16:24:06 +0000 Subject: [PATCH 05/27] Fixed unit test after bug fix. git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@580 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/tests/net/smtp/SMTPTransportTest.cpp b/tests/net/smtp/SMTPTransportTest.cpp index 5015552..6552f9e 100644 --- a/tests/net/smtp/SMTPTransportTest.cpp +++ b/tests/net/smtp/SMTPTransportTest.cpp @@ -165,7 +165,7 @@ public: } else if (cmd == "MAIL") { - VASSERT_EQ("MAIL", std::string("MAIL FROM: "), line); + VASSERT_EQ("MAIL", std::string("MAIL FROM:"), line); localSend("250 OK\r\n"); } -- 1.7.7.3 From ff207927a5aab002f38af0224133b345ab458144 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Fri, 10 Dec 2010 16:54:38 +0000 Subject: [PATCH 06/27] Fixed boundary parsing (thanks to John van der Kamp, Zarafa). git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@581 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/body.cpp b/src/body.cpp index 13dff6b..738d3e7 100644 --- a/src/body.cpp +++ b/src/body.cpp @@ -127,10 +127,30 @@ void body::parse(const string& buffer, const string::size_type position, const string boundarySep("--" + boundary); string::size_type partStart = position; - string::size_type pos = buffer.find(boundarySep, position); + string::size_type pos = position; bool lastPart = false; + while (pos != string::npos && pos < end) + { + pos = buffer.find(boundarySep, pos); + + if (pos == string::npos || + ((pos == 0 || buffer[pos - 1] == '\n') && + (buffer[pos + boundarySep.length()] == '\r' || + buffer[pos + boundarySep.length()] == '\n' || + buffer[pos + boundarySep.length()] == '-' + ) + ) + ) + { + break; + } + + // boundary not a beginning of line, or just a prefix of another, continue the search. + pos++; + } + if (pos != string::npos && pos < end) { m_prologText = string(buffer.begin() + position, buffer.begin() + pos); @@ -181,7 +201,26 @@ void body::parse(const string& buffer, const string::size_type position, } partStart = pos; - pos = buffer.find(boundarySep, partStart); + + while (pos != string::npos && pos < end) + { + pos = buffer.find(boundarySep, pos); + + if (pos == string::npos || + ((pos == 0 || buffer[pos - 1] == '\n') && + (buffer[pos + boundarySep.length()] == '\r' || + buffer[pos + boundarySep.length()] == '\n' || + buffer[pos + boundarySep.length()] == '-' + ) + ) + ) + { + break; + } + + // boundary not a beginning of line, or just a prefix of another, continue the search. + pos++; + } } m_contents = vmime::create (); diff --git a/tests/parser/bodyPartTest.cpp b/tests/parser/bodyPartTest.cpp index 12c4f74..df2bf85 100644 --- a/tests/parser/bodyPartTest.cpp +++ b/tests/parser/bodyPartTest.cpp @@ -84,7 +84,7 @@ VMIME_TEST_SUITE_BEGIN vmime::string str = "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\"" "\r\n\r\n" - "--MY-BOUNDARY\r\nHEADER1\r\n\r\nBODY1" + "--MY-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n" "--MY-BOUNDARY\r\nHEADER2\r\n\r\nBODY2"; vmime::bodyPart p; -- 1.7.7.3 From 3f5172e47f75f64952adef349bec875416ae9b89 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Fri, 21 Jan 2011 15:28:06 +0000 Subject: [PATCH 07/27] Fixed possible infinite loop (thanks to John van der Kamp, Zarafa). git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@582 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/word.cpp b/src/word.cpp index db720dc..1c1c1a6 100644 --- a/src/word.cpp +++ b/src/word.cpp @@ -386,7 +386,7 @@ void word::generate(utility::outputStream& os, const string::size_type maxLineLe maxRunLength = std::max(maxRunLength, curRunLength); - if (maxRunLength >= maxLineLength - 3) + if (((flags & text::FORCE_NO_ENCODING) == 0) && maxRunLength >= maxLineLength - 3) { // Generate with encoding forced generate(os, maxLineLength, curLinePos, newLinePos, flags | text::FORCE_ENCODING, state); diff --git a/tests/parser/textTest.cpp b/tests/parser/textTest.cpp index b84f376..746ac94 100644 --- a/tests/parser/textTest.cpp +++ b/tests/parser/textTest.cpp @@ -52,6 +52,7 @@ VMIME_TEST_SUITE_BEGIN VMIME_TEST(testWhitespaceMBox) VMIME_TEST(testFoldingAscii) + VMIME_TEST(testForcedNonEncoding) VMIME_TEST_LIST_END @@ -442,5 +443,15 @@ VMIME_TEST_SUITE_BEGIN " =?us-ascii?Q?9012345678901234567890123456789?=", w.generate(50)); } + void testForcedNonEncoding() + { + // Testing long unbreakable and unencodable header + vmime::relay r; + r.parse(" from User (Ee9GMqZQ8t7IQwftfAFHd2KyScCYRrFSJ50tKEoXv2bVCG4HcPU80GGWiFabAvG77FekpGgF1h@[127.0.0.1]) by servername.hostname.com\n\t" + "with esmtp id 1NGTS9-2C0sqG0; Fri, 4 Dec 2009 09:23:49 +0100"); + + VASSERT_EQ("received.long", "from User\r\n (Ee9GMqZQ8t7IQwftfAFHd2KyScCYRrFSJ50tKEoXv2bVCG4HcPU80GGWiFabAvG77FekpGgF1h@[127.0.0.1])\r\n by servername.hostname.com with esmtp id 1NGTS9-2C0sqG0; Fri, 4 Dec 2009\r\n 09:23:49 +0100", r.generate(78)); + } + VMIME_TEST_SUITE_END -- 1.7.7.3 From 4e9eb3191066dec7f17592c2ce099b16e6329941 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Fri, 28 Jan 2011 12:11:08 +0000 Subject: [PATCH 08/27] Fixed possible read to invalid memory location (thanks to Alexander Konovalov). git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@583 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/word.cpp b/src/word.cpp index 1c1c1a6..fa08d33 100644 --- a/src/word.cpp +++ b/src/word.cpp @@ -460,7 +460,7 @@ void word::generate(utility::outputStream& os, const string::size_type maxLineLe os << string(curLineStart, p); - if (parserHelpers::isSpace(*(p - 1))) + if (p != m_buffer.begin() && parserHelpers::isSpace(*(p - 1))) state->lastCharIsSpace = true; else state->lastCharIsSpace = false; -- 1.7.7.3 From 07ebf241115eba44675223e307d212c772e1cc08 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Wed, 9 Mar 2011 18:03:31 +0000 Subject: [PATCH 09/27] Fixed bug #3174903. Fixed word parsing when buffer does not end with NL. Fixed 'no encoding' when forced. git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@584 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/body.cpp b/src/body.cpp index 738d3e7..8596833 100644 --- a/src/body.cpp +++ b/src/body.cpp @@ -153,7 +153,10 @@ void body::parse(const string& buffer, const string::size_type position, if (pos != string::npos && pos < end) { - m_prologText = string(buffer.begin() + position, buffer.begin() + pos); + vmime::text text; + text.parse(buffer, position, pos); + + m_prologText = text.getWholeBuffer(); } for (int index = 0 ; !lastPart && (pos != string::npos) && (pos < end) ; ++index) @@ -246,7 +249,10 @@ void body::parse(const string& buffer, const string::size_type position, // Treat remaining text as epilog else if (partStart < end) { - m_epilogText = string(buffer.begin() + partStart, buffer.begin() + end); + vmime::text text; + text.parse(buffer, partStart, end); + + m_epilogText = text.getWholeBuffer(); } } // Treat the contents as 'simple' data @@ -333,7 +339,7 @@ void body::generate(utility::outputStream& os, const string::size_type maxLineLe if (!prologText.empty()) { - text prolog(word(prologText, getCharset())); + text prolog(prologText, vmime::charset("us-ascii")); prolog.encodeAndFold(os, maxLineLength, 0, NULL, text::FORCE_NO_ENCODING | text::NO_NEW_LINE_SEQUENCE); @@ -356,7 +362,7 @@ void body::generate(utility::outputStream& os, const string::size_type maxLineLe if (!epilogText.empty()) { - text epilog(word(epilogText, getCharset())); + text epilog(epilogText, vmime::charset("us-ascii")); epilog.encodeAndFold(os, maxLineLength, 0, NULL, text::FORCE_NO_ENCODING | text::NO_NEW_LINE_SEQUENCE); diff --git a/src/word.cpp b/src/word.cpp index fa08d33..aeaa737 100644 --- a/src/word.cpp +++ b/src/word.cpp @@ -102,7 +102,9 @@ ref word::parseNext(const string& buffer, const string::size_type positio ++pos; unencoded += buffer.substr(startPos, endPos - startPos); - unencoded += ' '; + + if (pos != end) // ignore white-spaces at end + unencoded += ' '; startPos = pos; continue; @@ -191,14 +193,15 @@ ref word::parseNext(const string& buffer, const string::size_type positio ++pos; } - // Treat unencoded text at the end of the buffer - if (end != startPos) - { - if (startPos != pos && !isFirst && prevIsEncoded) - unencoded += whiteSpaces; + if (startPos != end && !isFirst && prevIsEncoded) + unencoded += whiteSpaces; + if (startPos != end) unencoded += buffer.substr(startPos, end - startPos); + // Treat unencoded text at the end of the buffer + if (!unencoded.empty()) + { ref w = vmime::create (unencoded, charset(charsets::US_ASCII)); w->setParsedBounds(position, end); @@ -337,12 +340,14 @@ void word::generate(utility::outputStream& os, const string::size_type maxLineLe state = &defaultGeneratorState; // Find out if encoding is forced or required by contents + charset - bool encodingNeeded = (flags & text::FORCE_ENCODING) != 0; + bool encodingNeeded = false; - if (encodingNeeded == false) - encodingNeeded = wordEncoder::isEncodingNeeded(m_buffer, m_charset); - else if ((flags & text::FORCE_NO_ENCODING) != 0) + if ((flags & text::FORCE_NO_ENCODING) != 0) encodingNeeded = false; + else if ((flags & text::FORCE_ENCODING) != 0) + encodingNeeded = true; + else // auto-detect + encodingNeeded = wordEncoder::isEncodingNeeded(m_buffer, m_charset); // If possible and requested (with flag), quote the buffer (no folding is performed). // Quoting is possible if and only if: diff --git a/tests/parser/bodyPartTest.cpp b/tests/parser/bodyPartTest.cpp index df2bf85..b129913 100644 --- a/tests/parser/bodyPartTest.cpp +++ b/tests/parser/bodyPartTest.cpp @@ -34,6 +34,8 @@ VMIME_TEST_SUITE_BEGIN VMIME_TEST(testParse) VMIME_TEST(testGenerate) VMIME_TEST(testParseMissingLastBoundary) + VMIME_TEST(testPrologEpilog) + VMIME_TEST(testPrologEncoding) VMIME_TEST_LIST_END @@ -105,5 +107,79 @@ VMIME_TEST_SUITE_BEGIN VASSERT_EQ("1", "Foo: bar\r\n\r\nBaz", p1.generate()); } + void testPrologEpilog() + { + const char testMail[] = + "To: test@vmime.org\r\n" + "From: test@vmime.org\r\n" + "Subject: Prolog and epilog test\r\n" + "Content-Type: multipart/mixed; \r\n" + " boundary=\"=_boundary\"\r\n" + "\r\n" + "Prolog text\r\n" + "--=_boundary\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "Part1\r\n" + "--=_boundary--\r\n" + "Epilog text"; + + vmime::bodyPart part; + part.parse(testMail); + + VASSERT_EQ("prolog", "Prolog text", part.getBody()->getPrologText()); + VASSERT_EQ("epilog", "Epilog text", part.getBody()->getEpilogText()); + } + + // Test for bug fix: prolog should not be encoded + // http://sourceforge.net/tracker/?func=detail&atid=525568&aid=3174903&group_id=69724 + void testPrologEncoding() + { + const char testmail[] = + "To: test@vmime.org\r\n" + "From: test@vmime.org\r\n" + "Subject: Prolog encoding test\r\n" + "Content-Type: multipart/mixed; \r\n" + " boundary=\"=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\"\r\n" + "\r\n" + "This is a multi-part message in MIME format. Your mail reader does not\r\n" + "understand MIME message format.\r\n" + "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\r\n" + "Content-Type: text/html; charset=windows-1251\r\n" + "Content-Transfer-Encoding: quoted-printable\r\n" + "\r\n" + "=DD=F2=EE =F2=E5=EA=F1=F2=EE=E2=E0=FF =F7=E0=F1=F2=FC =F1=EB=EE=E6=ED=EE=E3=\r\n" + "=EE =F1=EE=EE=E1=F9=E5=ED=E8=FF\r\n" + "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\r\n" + "Content-Type: application/octet-stream; charset=windows-1251\r\n" + "Content-Disposition: attachment; filename=FNS.zip\r\n" + "Content-Transfer-Encoding: base64\r\n" + "\r\n" + "UEsDBB...snap...EEAAAAAA==\r\n" + "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q--\r\n" + "Epilog text"; + + vmime::ref msg = vmime::create(); + + std::string istr(testmail); + + std::string ostr; + vmime::utility::outputStreamStringAdapter out(ostr); + + for (int i = 0 ; i < 10 ; ++i) + { + ostr.clear(); + + msg->parse(istr); + msg->generate(out); + + istr = ostr; + } + + VASSERT_EQ("prolog", "This is a multi-part message in MIME format. Your mail reader" + " does not understand MIME message format.", msg->getBody()->getPrologText()); + VASSERT_EQ("epilog", "Epilog text", msg->getBody()->getEpilogText()); + } + VMIME_TEST_SUITE_END -- 1.7.7.3 From 22ca7dc23b6bbbc8cc6aedd569ec938ecae96e92 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Sun, 27 Mar 2011 11:26:55 +0000 Subject: [PATCH 10/27] Allow static linking in MXE. Added 'iconv' and uses 'ws2_32' instead of 'winsock32' (#3213487). git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@585 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/SConstruct b/SConstruct index 55f9223..177f5b4 100644 --- a/SConstruct +++ b/SConstruct @@ -1089,7 +1089,7 @@ def generateAutotools(target, source, env): vmime_pc_in.write("Description: " + packageDescription + "\n") vmime_pc_in.write("Version: @VERSION@\n") vmime_pc_in.write("Requires: @GSASL_REQUIRED@\n") - vmime_pc_in.write("Libs: -L${libdir} -l@GENERIC_VERSIONED_LIBRARY_NAME@ @GSASL_LIBS@ @LIBGNUTLS_LIBS@ @VMIME_ADDITIONAL_PC_LIBS@\n") + vmime_pc_in.write("Libs: -L${libdir} -l@GENERIC_VERSIONED_LIBRARY_NAME@ @GSASL_LIBS@ @LIBGNUTLS_LIBS@ @LIBICONV@ @PTHREAD_LIBS@ @VMIME_ADDITIONAL_PC_LIBS@\n") #vmime_pc_in.write("Cflags: -I${includedir}/@GENERIC_VERSIONED_LIBRARY_NAME@\n") vmime_pc_in.write("Cflags: -I${includedir}/ @LIBGNUTLS_CFLAGS@\n") vmime_pc_in.close() @@ -1709,7 +1709,7 @@ fi # -- Link with Winsock (Windows) if test "x$VMIME_DETECT_PLATFORM" = "xwindows"; then - VMIME_ADDITIONAL_PC_LIBS="$VMIME_ADDITIONAL_PC_LIBS -lwsock32" + VMIME_ADDITIONAL_PC_LIBS="$VMIME_ADDITIONAL_PC_LIBS -lws2_32" fi # -- getaddrinfo (POSIX) -- 1.7.7.3 From 9e06cc39d47e2eba8f554b337d472cc995be0d9d Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Thu, 31 Mar 2011 19:13:03 +0000 Subject: [PATCH 11/27] Flush stateful data from iconv (thanks to John van der Kamp, Zarafa). git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@586 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/charsetConverter.cpp b/src/charsetConverter.cpp index 38b9e5e..2135788 100644 --- a/src/charsetConverter.cpp +++ b/src/charsetConverter.cpp @@ -119,6 +119,7 @@ void charsetConverter::convert(utility::inputStream& in, utility::outputStream& size_t inPos = 0; bool prevIsInvalid = false; + bool breakAfterNext = false; while (true) { @@ -126,11 +127,12 @@ void charsetConverter::convert(utility::inputStream& in, utility::outputStream& size_t inLength = static_cast (in.read(inBuffer + inPos, sizeof(inBuffer) - inPos) + inPos); size_t outLength = sizeof(outBuffer); - const char* inPtr = inBuffer; + const char* inPtr = breakAfterNext ? NULL : inBuffer; + size_t *ptrLength = breakAfterNext ? NULL : &inLength; char* outPtr = outBuffer; // Convert input bytes - if (iconv(cd, ICONV_HACK(&inPtr), &inLength, + if (iconv(cd, ICONV_HACK(&inPtr), ptrLength, &outPtr, &outLength) == static_cast (-1)) { // Illegal input sequence or input sequence has no equivalent @@ -170,9 +172,12 @@ void charsetConverter::convert(utility::inputStream& in, utility::outputStream& prevIsInvalid = false; } - // Check for end of data - if (in.eof() && inPos == 0) + if (breakAfterNext) break; + + // Check for end of data, loop again to flush stateful data from iconv + if (in.eof() && inPos == 0) + breakAfterNext = true; } } diff --git a/tests/parser/charsetTest.cpp b/tests/parser/charsetTest.cpp index 8ad71d7..54a09a7 100644 --- a/tests/parser/charsetTest.cpp +++ b/tests/parser/charsetTest.cpp @@ -100,6 +100,7 @@ VMIME_TEST_SUITE_BEGIN VMIME_TEST(testFilterValid1) VMIME_TEST(testFilterValid2) VMIME_TEST(testFilterValid3) + VMIME_TEST(testEncodingHebrew1255) // Test invalid input VMIME_TEST(testFilterInvalid1) @@ -227,6 +228,15 @@ VMIME_TEST_SUITE_BEGIN VASSERT_EQ("1", toHex(expectedOut), toHex(actualOut)); } + void testEncodingHebrew1255() + { + // hewbrew string in windows-1255 charset + const char data[] = "\xe9\xf9\xf7\xf8\xe9\xf9\xf8\xf7\xe9\xe9\xf9"; + vmime::word w = vmime::word(data, "windows-1255"); + vmime::string encoded = w.generate(); + // less than 60% ascii, base64 received + VASSERT_EQ("1", "=?windows-1255?B?6fn3+On5+Pfp6fk=?=", encoded); + } // Conversion to hexadecimal for easier debugging static const vmime::string toHex(const vmime::string str) -- 1.7.7.3 From 418a39a7d33921672bd1c4beb31c8a31bc87d8dd Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Fri, 10 Jun 2011 19:39:09 +0000 Subject: [PATCH 12/27] Requested email change. git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@587 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/AUTHORS b/AUTHORS index 20a0181..bbddb30 100644 --- a/AUTHORS +++ b/AUTHORS @@ -21,7 +21,7 @@ AUTHORS file. - Rafael Fernandez - Xin Li - Benjamin Biron - - Bertrand Benoit + - Bertrand Benoit - Tim Teulings - Georg Sauthoff - Pierre Thierry (patches for STL algorithms) -- 1.7.7.3 From 4008955783ef566b98b16762c7bfa28df26e9198 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Tue, 14 Jun 2011 18:37:54 +0000 Subject: [PATCH 13/27] Fixed compilation issue following namespace change. git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@588 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/examples/example7.cpp b/examples/example7.cpp index 1ddb3d0..243b1da 100644 --- a/examples/example7.cpp +++ b/examples/example7.cpp @@ -43,18 +43,18 @@ int main() vmime::platform::setHandler(); // Enumerate encoders - vmime::encoderFactory* ef = vmime::encoderFactory::getInstance(); + vmime::utility::encoder::encoderFactory* ef = vmime::utility::encoder::encoderFactory::getInstance(); std::cout << "Available encoders:" << std::endl; for (int i = 0 ; i < ef->getEncoderCount() ; ++i) { - vmime::ref + vmime::ref enc = ef->getEncoderAt(i); std::cout << " * " << enc->getName() << std::endl; - vmime::ref e = enc->create(); + vmime::ref e = enc->create(); std::vector props = e->getAvailableProperties(); -- 1.7.7.3 From e80db1ce802a45b71659d16d77ea47368beeabc1 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Sun, 19 Jun 2011 17:51:33 +0000 Subject: [PATCH 14/27] Fixed parsing of an attachment filename that is between 66 and 76 characters long (Zarafa). git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@589 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/parameter.cpp b/src/parameter.cpp index 91a7e5c..f59d5ab 100644 --- a/src/parameter.cpp +++ b/src/parameter.cpp @@ -281,7 +281,8 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL bool needQuoting = false; string::size_type valueLength = 0; - for (string::size_type i = 0 ; (i < value.length()) && (pos + valueLength < maxLineLength - 4) ; ++i, ++valueLength) + // Use worst-case length name.length()+2 for 'name=' part of line + for (string::size_type i = 0 ; (i < value.length()) && (pos + name.length() + 2 + valueLength < maxLineLength - 4) ; ++i, ++valueLength) { switch (value[i]) { -- 1.7.7.3 From 58316dddddbfe8a7c582aa52e9abff8ca3a227b6 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Sun, 19 Jun 2011 18:08:12 +0000 Subject: [PATCH 15/27] Correctly generate attachment names which are long and have high characters for Outlook Express (Zarafa). git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@590 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/parameter.cpp b/src/parameter.cpp index f59d5ab..d757e1b 100644 --- a/src/parameter.cpp +++ b/src/parameter.cpp @@ -268,17 +268,19 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL // value is to be generated. // A stream for a temporary storage - std::ostringstream sevenBitBuffer; + std::string sevenBitBuffer; + utility::outputStreamStringAdapter sevenBitStream(sevenBitBuffer); string::size_type pos = curLinePos; if (pos + name.length() + 10 + value.length() > maxLineLength) { - sevenBitBuffer << NEW_LINE_SEQUENCE; + sevenBitStream << NEW_LINE_SEQUENCE; pos = NEW_LINE_SEQUENCE_LENGTH; } bool needQuoting = false; + bool needQuotedPrintable = false; string::size_type valueLength = 0; // Use worst-case length name.length()+2 for 'name=' part of line @@ -308,6 +310,16 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL needQuoting = true; break; + + default: + + if (!parserHelpers::isAscii(value[i])) + { + needQuotedPrintable = true; + needQuoting = true; + } + + break; } } @@ -315,12 +327,12 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL if (needQuoting) { - sevenBitBuffer << name << "=\""; + sevenBitStream << name << "=\""; pos += name.length() + 2; } else { - sevenBitBuffer << name << "="; + sevenBitStream << name << "="; pos += name.length() + 1; } @@ -332,29 +344,43 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL const bool alwaysEncode = m_value.getCharset().getRecommendedEncoding(recommendedEnc); bool extended = alwaysEncode; - for (string::size_type i = 0 ; (i < value.length()) && (pos < maxLineLength - 4) ; ++i) + if (needQuotedPrintable) { - const char_t c = value[i]; - - if (/* needQuoting && */ (c == '"' || c == '\\')) // 'needQuoting' is implicit - { - sevenBitBuffer << '\\' << value[i]; // escape 'x' with '\x' - pos += 2; - } - else if (parserHelpers::isAscii(c)) - { - sevenBitBuffer << value[i]; - ++pos; - } - else + // Send the name in quoted-printable, so outlook express et.al. + // will understand the real filename + size_t oldLen = sevenBitBuffer.length(); + m_value.generate(sevenBitStream); + pos += sevenBitBuffer.length() - oldLen; + extended = true; // also send with RFC-2231 encoding + } + else + { + // Do not chop off this value, but just add the complete name as one header line. + for (string::size_type i = 0 ; i < value.length() ; ++i) { - extended = true; + const char_t c = value[i]; + + if (/* needQuoting && */ (c == '"' || c == '\\')) // 'needQuoting' is implicit + { + sevenBitStream << '\\' << value[i]; // escape 'x' with '\x' + pos += 2; + } + else if (parserHelpers::isAscii(c)) + { + sevenBitStream << value[i]; + ++pos; + } + else + { + extended = true; + } } - } + + } // !needQuotedPrintable if (needQuoting) { - sevenBitBuffer << '"'; + sevenBitStream << '"'; ++pos; } @@ -532,7 +558,7 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL // "7bit/us-ascii" will suffice in this case. // Output what has been stored in temporary buffer so far - os << sevenBitBuffer.str(); + os << sevenBitBuffer; } #endif // !VMIME_ALWAYS_GENERATE_7BIT_PARAMETER -- 1.7.7.3 From f7ad17cffea462faf8cbe4f785644da0f3ee812a Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Sun, 19 Jun 2011 18:16:49 +0000 Subject: [PATCH 16/27] Alias for UTF-7 charset. git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@591 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/charset.cpp b/src/charset.cpp index e043186..0fda450 100644 --- a/src/charset.cpp +++ b/src/charset.cpp @@ -45,6 +45,9 @@ charset::charset() charset::charset(const string& name) : m_name(name) { + // If we receive this rfc-1642 valid MIME charset, convert it to something usefull for iconv + if (utility::stringUtils::isStringEqualNoCase(m_name, "unicode-1-1-utf-7")) + m_name = "utf-7"; } @@ -60,6 +63,10 @@ void charset::parse(const string& buffer, const string::size_type position, m_name = utility::stringUtils::trim (string(buffer.begin() + position, buffer.begin() + end)); + // If we parsed this rfc-1642 valid MIME charset, convert it to something usefull for iconv + if (utility::stringUtils::isStringEqualNoCase(m_name, "unicode-1-1-utf-7")) + m_name = "utf-7"; + setParsedBounds(position, end); if (newPosition) -- 1.7.7.3 From eac20f47a33a7fdd617f9fd905b8029621259269 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Sun, 19 Jun 2011 18:39:35 +0000 Subject: [PATCH 17/27] Fixed messageBuilder to accept an empty mailbox group in 'To:' field, to allow for undisclosed-recipients (Zarafa). git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@592 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/messageBuilder.cpp b/src/messageBuilder.cpp index 870d59e..3597b3a 100644 --- a/src/messageBuilder.cpp +++ b/src/messageBuilder.cpp @@ -51,17 +51,15 @@ ref messageBuilder::construct() const // Generate the header fields msg->getHeader()->Subject()->setValue(m_subject); - if (m_from.isEmpty()) - throw exceptions::no_expeditor(); - - if ((m_to.isEmpty() || m_to.getAddressAt(0)->isEmpty()) && + if (((m_to.isEmpty()) || (m_to.getAddressAt(0)->isEmpty() && !m_to.getAddressAt(0)->isGroup())) && (m_cc.isEmpty() || m_cc.getAddressAt(0)->isEmpty()) && (m_bcc.isEmpty() || m_bcc.getAddressAt(0)->isEmpty())) { throw exceptions::no_recipient(); } - msg->getHeader()->From()->setValue(m_from); + if (!m_from.isEmpty()) + msg->getHeader()->From()->setValue(m_from); if (!m_to.isEmpty()) msg->getHeader()->To()->setValue(m_to); -- 1.7.7.3 From 1e5dfa80a63b0a7fe90406ce4a3de1593f2e4045 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Sun, 19 Jun 2011 18:49:55 +0000 Subject: [PATCH 18/27] Added support for mailboxes that specify an (encoded) full name with an empty email address, set by a <> marker (Zarafa). git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@593 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/mailbox.cpp b/src/mailbox.cpp index 5cb0139..fea7479 100644 --- a/src/mailbox.cpp +++ b/src/mailbox.cpp @@ -88,6 +88,7 @@ void mailbox::parse(const string& buffer, const string::size_type position, // Temporary buffers for extracted name and address string name; string address; + bool hadBrackets = false; while (p < pend) { @@ -283,6 +284,7 @@ void mailbox::parse(const string& buffer, const string::size_type position, } else if (*p == '>') { + hadBrackets = true; break; } else if (!parserHelpers::isSpace(*p)) @@ -309,7 +311,7 @@ void mailbox::parse(const string& buffer, const string::size_type position, // Swap name and address when no address was found // (email address is mandatory, whereas name is optional). - if (address.empty() && !name.empty()) + if (address.empty() && !name.empty() && !hadBrackets) { m_email.clear(); m_email.reserve(name.size()); diff --git a/tests/parser/mailboxTest.cpp b/tests/parser/mailboxTest.cpp index 8411daa..9ebadca 100644 --- a/tests/parser/mailboxTest.cpp +++ b/tests/parser/mailboxTest.cpp @@ -32,6 +32,7 @@ VMIME_TEST_SUITE_BEGIN VMIME_TEST_LIST_BEGIN VMIME_TEST(testParse) + VMIME_TEST(testEmptyEmailAddress) VMIME_TEST_LIST_END @@ -113,5 +114,19 @@ VMIME_TEST_SUITE_BEGIN } } + void testEmptyEmailAddress() + { + vmime::addressList addrList; + addrList.parse("\"Full Name\" <>"); + + VASSERT_EQ("count", 1, addrList.getAddressCount()); + VASSERT_EQ("!group", false, addrList.getAddressAt(0)->isGroup()); + + vmime::ref mbox = addrList.getAddressAt(0).dynamicCast (); + + VASSERT_EQ("name", "Full Name", mbox->getName()); + VASSERT_EQ("email", "", mbox->getEmail()); + } + VMIME_TEST_SUITE_END -- 1.7.7.3 From 960f2195516eb776eea7b7e4f92612192edfdcd9 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Fri, 24 Jun 2011 15:46:23 +0000 Subject: [PATCH 19/27] Added missing libs in pkg-config file. git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@594 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/SConstruct b/SConstruct index 177f5b4..37c0ac6 100644 --- a/SConstruct +++ b/SConstruct @@ -1089,7 +1089,7 @@ def generateAutotools(target, source, env): vmime_pc_in.write("Description: " + packageDescription + "\n") vmime_pc_in.write("Version: @VERSION@\n") vmime_pc_in.write("Requires: @GSASL_REQUIRED@\n") - vmime_pc_in.write("Libs: -L${libdir} -l@GENERIC_VERSIONED_LIBRARY_NAME@ @GSASL_LIBS@ @LIBGNUTLS_LIBS@ @LIBICONV@ @PTHREAD_LIBS@ @VMIME_ADDITIONAL_PC_LIBS@\n") + vmime_pc_in.write("Libs: -L${libdir} -l@GENERIC_VERSIONED_LIBRARY_NAME@ @GSASL_LIBS@ @LIBGNUTLS_LIBS@ @LIBICONV@ @PTHREAD_LIBS@ @LIBICONV@ @PTHREAD_LIBS@ @VMIME_ADDITIONAL_PC_LIBS@\n") #vmime_pc_in.write("Cflags: -I${includedir}/@GENERIC_VERSIONED_LIBRARY_NAME@\n") vmime_pc_in.write("Cflags: -I${includedir}/ @LIBGNUTLS_CFLAGS@\n") vmime_pc_in.close() -- 1.7.7.3 From 9f9084b71b4e3c96edc6513020984ef76fe26e0c Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Sat, 25 Jun 2011 17:07:53 +0000 Subject: [PATCH 20/27] Fixed parsing of empty body parts (thanks to John van der Kamp, from Zarafa). git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@595 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/body.cpp b/src/body.cpp index 8596833..9d7d57f 100644 --- a/src/body.cpp +++ b/src/body.cpp @@ -197,6 +197,11 @@ void body::parse(const string& buffer, const string::size_type position, { ref part = vmime::create (); + // End before start may happen on empty bodyparts (directly + // successive boundaries without even a line-break) + if (partEnd < partStart) + std::swap(partStart, partEnd); + part->parse(buffer, partStart, partEnd, NULL); part->m_parent = m_part; diff --git a/tests/parser/bodyPartTest.cpp b/tests/parser/bodyPartTest.cpp index b129913..075b8f9 100644 --- a/tests/parser/bodyPartTest.cpp +++ b/tests/parser/bodyPartTest.cpp @@ -36,6 +36,7 @@ VMIME_TEST_SUITE_BEGIN VMIME_TEST(testParseMissingLastBoundary) VMIME_TEST(testPrologEpilog) VMIME_TEST(testPrologEncoding) + VMIME_TEST(testSuccessiveBoundaries) VMIME_TEST_LIST_END @@ -181,5 +182,23 @@ VMIME_TEST_SUITE_BEGIN VASSERT_EQ("epilog", "Epilog text", msg->getBody()->getEpilogText()); } + void testSuccessiveBoundaries() + { + vmime::string str = + "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\"" + "\r\n\r\n" + "--MY-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n" + "--MY-BOUNDARY\r\n" + "--MY-BOUNDARY--\r\n"; + + vmime::bodyPart p; + p.parse(str); + + VASSERT_EQ("count", 2, p.getBody()->getPartCount()); + + VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents())); + VASSERT_EQ("part2-body", "", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents())); + } + VMIME_TEST_SUITE_END -- 1.7.7.3 From 318848aa87761214a6f21c1ea1a9776a7bcbf83c Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Sun, 26 Jun 2011 08:19:11 +0000 Subject: [PATCH 21/27] Use gnutls_priority_set_direct() instead of GNUTLS deprecated functions. git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@596 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/SConstruct b/SConstruct index 37c0ac6..01ad3f3 100644 --- a/SConstruct +++ b/SConstruct @@ -816,6 +816,7 @@ else: config_hpp.write('// -- TLS/SSL support\n') if env['with_tls'] == 'yes': config_hpp.write('#define VMIME_HAVE_TLS_SUPPORT 1\n') + config_hpp.write('#define HAVE_GNUTLS_PRIORITY_FUNCS 1\n') else: config_hpp.write('#define VMIME_HAVE_TLS_SUPPORT 0\n') @@ -1626,11 +1627,42 @@ if test "x$conf_tls" = "xyes"; then else AC_MSG_ERROR(can't find an usable version of GNU TLS library) fi + + # -- check for gnutls_priority_set_direct() function + if test "x$have_gnutls" = "xyes"; then + AC_MSG_CHECKING(for gnutls_priority_set_direct) + + LIBS_save="$LIBS" + LIBS="$LIBS $LIBGNUTLS_LIBS" + CPPFLAGS_save="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $LIBGNUTLS_CFLAGS" + + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [gnutls_session s; gnutls_priority_set_direct(s, NULL, NULL);])], + [have_gnutls_priority_funcs=yes], + [have_gnutls_priority_funcs=no]) + + CPPFLAGS="$CPPFLAGS_save" + LIBS="$LIBS_save" + + AC_MSG_RESULT([$have_gnutls_priority_funcs]) + + if test "x$have_gnutls_priority_funcs" = "xyes"; then + AM_CONDITIONAL(HAVE_GNUTLS_PRIORITY_FUNCS, true) + HAVE_GNUTLS_PRIORITY_FUNCS=1 + else + AM_CONDITIONAL(HAVE_GNUTLS_PRIORITY_FUNCS, false) + HAVE_GNUTLS_PRIORITY_FUNCS=0 + fi + fi else AM_CONDITIONAL(VMIME_HAVE_TLS_SUPPORT, false) VMIME_HAVE_TLS_SUPPORT=0 fi +AC_SUBST(LIBGNUTLS_CFLAGS) +AC_SUBST(LIBGNUTLS_LIBS) + # ** platform handlers VMIME_BUILTIN_PLATFORMS='' @@ -1919,6 +1951,7 @@ typedef unsigned ${VMIME_TYPE_INT32} vmime_uint32; #define VMIME_HAVE_SASL_SUPPORT ${VMIME_HAVE_SASL_SUPPORT} // -- TLS support #define VMIME_HAVE_TLS_SUPPORT ${VMIME_HAVE_TLS_SUPPORT} +#define HAVE_GNUTLS_PRIORITY_FUNCS ${HAVE_GNUTLS_PRIORITY_FUNCS} // -- Messaging support #define VMIME_HAVE_MESSAGING_FEATURES ${VMIME_HAVE_MESSAGING_FEATURES} """) diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp index 010c007..af73a05 100644 --- a/src/net/tls/TLSSession.cpp +++ b/src/net/tls/TLSSession.cpp @@ -123,6 +123,21 @@ TLSSession::TLSSession(ref cv) // Sets some default priority on the ciphers, key exchange methods, // macs and compression methods. +#if HAVE_GNUTLS_PRIORITY_FUNCS + + if ((res = gnutls_priority_set_direct + (*m_gnutlsSession, "NORMAL:%SSL3_RECORD_VERSION", NULL)) != 0) + { + if ((res = gnutls_priority_set_direct + (*m_gnutlsSession, "NORMAL", NULL)) != 0) + { + throwTLSException + ("gnutls_priority_set_direct", res); + } + } + +#else // !HAVE_GNUTLS_PRIORITY_FUNCS + gnutls_set_default_priority(*m_gnutlsSession); // Sets the priority on the certificate types supported by gnutls. @@ -197,6 +212,8 @@ TLSSession::TLSSession(ref cv) gnutls_compression_set_priority(*m_gnutlsSession, compressionPriority); +#endif // !HAVE_GNUTLS_PRIORITY_FUNCS + // Initialize credentials gnutls_credentials_set(*m_gnutlsSession, GNUTLS_CRD_ANON, g_gnutlsGlobal.anonCred); -- 1.7.7.3 From 70a0282a3f96febf973475a298ac95ffaab82c3c Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Sun, 26 Jun 2011 12:47:25 +0000 Subject: [PATCH 22/27] Fixed encoding of whitespace. Fixed old test case. git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@597 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/text.cpp b/src/text.cpp index 2454456..66c3b35 100644 --- a/src/text.cpp +++ b/src/text.cpp @@ -320,12 +320,6 @@ void text::createFromString(const string& in, const charset& ch) } else { - if (count) - { - ref w = getWordAt(getWordCount() - 1); - w->getBuffer() += ' '; - } - appendWord(vmime::create (chunk, charset(charsets::US_ASCII))); diff --git a/tests/parser/textTest.cpp b/tests/parser/textTest.cpp index 746ac94..43ec836 100644 --- a/tests/parser/textTest.cpp +++ b/tests/parser/textTest.cpp @@ -53,6 +53,8 @@ VMIME_TEST_SUITE_BEGIN VMIME_TEST(testFoldingAscii) VMIME_TEST(testForcedNonEncoding) + + VMIME_TEST(testBugFix20110511) VMIME_TEST_LIST_END @@ -149,7 +151,7 @@ VMIME_TEST_SUITE_BEGIN VASSERT_EQ("2.1", 3, t2.getWordCount()); VASSERT_EQ("2.2", "some ASCII characters and special chars: ", t2.getWordAt(0)->getBuffer()); VASSERT_EQ("2.3", vmime::charset(vmime::charsets::US_ASCII), t2.getWordAt(0)->getCharset()); - VASSERT_EQ("2.4", "\xf1\xf2\xf3\xf4 ", t2.getWordAt(1)->getBuffer()); + VASSERT_EQ("2.4", "\xf1\xf2\xf3\xf4", t2.getWordAt(1)->getBuffer()); VASSERT_EQ("2.5", c2, t2.getWordAt(1)->getCharset()); VASSERT_EQ("2.6", "and then more ASCII chars.", t2.getWordAt(2)->getBuffer()); VASSERT_EQ("2.7", vmime::charset(vmime::charsets::US_ASCII), t2.getWordAt(2)->getCharset()); @@ -453,5 +455,43 @@ VMIME_TEST_SUITE_BEGIN VASSERT_EQ("received.long", "from User\r\n (Ee9GMqZQ8t7IQwftfAFHd2KyScCYRrFSJ50tKEoXv2bVCG4HcPU80GGWiFabAvG77FekpGgF1h@[127.0.0.1])\r\n by servername.hostname.com with esmtp id 1NGTS9-2C0sqG0; Fri, 4 Dec 2009\r\n 09:23:49 +0100", r.generate(78)); } + void testBugFix20110511() + { + /* + + Using the latest version of vmime (0.9.1), encoding the following string: Jean + Gwenaël Dutourd will result in: + Jean =?utf-8?Q?Gwena=C3=ABl_?= Dutourd + However, decoding this will result in Jean Gwenaël Dutourd (notice two spaces + between the last 2 words). The encoder adds a _ after the second word, but + since the last word is not encoded, the space between them is not ignored, and + is decoded into an additional space. + + See: http://sourceforge.net/projects/vmime/forums/forum/237357/topic/4531365 + + */ + + const std::string DECODED_TEXT = "Jean Gwenaël Dutourd"; + const std::string ENCODED_TEXT = "Jean =?utf-8?Q?Gwena=C3=ABl?= Dutourd"; + + // Encode + VASSERT_EQ("encode", ENCODED_TEXT, + vmime::text::newFromString(DECODED_TEXT, vmime::charset("utf-8"))->generate()); + + // Decode + vmime::text t; + t.parse(ENCODED_TEXT); + + // -- words + std::ostringstream oss; oss << t; + VASSERT_EQ("decode1", + "[text: [[word: charset=us-ascii, buffer=Jean ]," + "[word: charset=utf-8, buffer=Gwenaël]," + "[word: charset=us-ascii, buffer= Dutourd]]]", oss.str()); + + // -- getWholeBuffer + VASSERT_EQ("decode2", DECODED_TEXT, t.getWholeBuffer()); + } + VMIME_TEST_SUITE_END -- 1.7.7.3 From 7d399583a458abe5cd16ce0974bd4dc11daba9f6 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Sat, 20 Aug 2011 06:35:06 +0000 Subject: [PATCH 23/27] Use gnutls_strerror() for reporting errors. git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@598 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp index af73a05..7426a73 100644 --- a/src/net/tls/TLSSession.cpp +++ b/src/net/tls/TLSSession.cpp @@ -41,6 +41,9 @@ //#define GNUTLS_DEBUG 1 +#include +#include + #if VMIME_DEBUG && GNUTLS_DEBUG #include #endif // VMIME_DEBUG && GNUTLS_DEBUG @@ -257,119 +260,14 @@ ref TLSSession::getCertificateVerifier() void TLSSession::throwTLSException(const string& fname, const int code) { - string msg = fname + "() returned "; - -#define ERROR(x) \ - case x: msg += #x; break; - - switch (code) - { - ERROR(GNUTLS_E_SUCCESS) - ERROR(GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM) - ERROR(GNUTLS_E_UNKNOWN_CIPHER_TYPE) - ERROR(GNUTLS_E_LARGE_PACKET) - ERROR(GNUTLS_E_UNSUPPORTED_VERSION_PACKET) - ERROR(GNUTLS_E_UNEXPECTED_PACKET_LENGTH) - ERROR(GNUTLS_E_INVALID_SESSION) - ERROR(GNUTLS_E_FATAL_ALERT_RECEIVED) - ERROR(GNUTLS_E_UNEXPECTED_PACKET) - ERROR(GNUTLS_E_WARNING_ALERT_RECEIVED) - ERROR(GNUTLS_E_ERROR_IN_FINISHED_PACKET) - ERROR(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET) - ERROR(GNUTLS_E_UNKNOWN_CIPHER_SUITE) - ERROR(GNUTLS_E_UNWANTED_ALGORITHM) - ERROR(GNUTLS_E_MPI_SCAN_FAILED) - ERROR(GNUTLS_E_DECRYPTION_FAILED) - ERROR(GNUTLS_E_MEMORY_ERROR) - ERROR(GNUTLS_E_DECOMPRESSION_FAILED) - ERROR(GNUTLS_E_COMPRESSION_FAILED) - ERROR(GNUTLS_E_AGAIN) - ERROR(GNUTLS_E_EXPIRED) - ERROR(GNUTLS_E_DB_ERROR) - ERROR(GNUTLS_E_SRP_PWD_ERROR) - ERROR(GNUTLS_E_INSUFFICIENT_CREDENTIALS) - ERROR(GNUTLS_E_HASH_FAILED) - ERROR(GNUTLS_E_BASE64_DECODING_ERROR) - ERROR(GNUTLS_E_MPI_PRINT_FAILED) - ERROR(GNUTLS_E_REHANDSHAKE) - ERROR(GNUTLS_E_GOT_APPLICATION_DATA) - ERROR(GNUTLS_E_RECORD_LIMIT_REACHED) - ERROR(GNUTLS_E_ENCRYPTION_FAILED) - ERROR(GNUTLS_E_PK_ENCRYPTION_FAILED) - ERROR(GNUTLS_E_PK_DECRYPTION_FAILED) - ERROR(GNUTLS_E_PK_SIGN_FAILED) - ERROR(GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSION) - ERROR(GNUTLS_E_KEY_USAGE_VIOLATION) - ERROR(GNUTLS_E_NO_CERTIFICATE_FOUND) - ERROR(GNUTLS_E_INVALID_REQUEST) - ERROR(GNUTLS_E_SHORT_MEMORY_BUFFER) - ERROR(GNUTLS_E_INTERRUPTED) - ERROR(GNUTLS_E_PUSH_ERROR) - ERROR(GNUTLS_E_PULL_ERROR) - ERROR(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER) - ERROR(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) - ERROR(GNUTLS_E_PKCS1_WRONG_PAD) - ERROR(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION) - ERROR(GNUTLS_E_INTERNAL_ERROR) - ERROR(GNUTLS_E_DH_PRIME_UNACCEPTABLE) - ERROR(GNUTLS_E_FILE_ERROR) - ERROR(GNUTLS_E_TOO_MANY_EMPTY_PACKETS) - ERROR(GNUTLS_E_UNKNOWN_PK_ALGORITHM) - ERROR(GNUTLS_E_INIT_LIBEXTRA) - ERROR(GNUTLS_E_LIBRARY_VERSION_MISMATCH) - ERROR(GNUTLS_E_NO_TEMPORARY_RSA_PARAMS) - ERROR(GNUTLS_E_LZO_INIT_FAILED) - ERROR(GNUTLS_E_NO_COMPRESSION_ALGORITHMS) - ERROR(GNUTLS_E_NO_CIPHER_SUITES) - ERROR(GNUTLS_E_OPENPGP_GETKEY_FAILED) - ERROR(GNUTLS_E_PK_SIG_VERIFY_FAILED) - ERROR(GNUTLS_E_ILLEGAL_SRP_USERNAME) - ERROR(GNUTLS_E_SRP_PWD_PARSING_ERROR) - ERROR(GNUTLS_E_NO_TEMPORARY_DH_PARAMS) - ERROR(GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) - ERROR(GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUND) - ERROR(GNUTLS_E_ASN1_DER_ERROR) - ERROR(GNUTLS_E_ASN1_VALUE_NOT_FOUND) - ERROR(GNUTLS_E_ASN1_GENERIC_ERROR) - ERROR(GNUTLS_E_ASN1_VALUE_NOT_VALID) - ERROR(GNUTLS_E_ASN1_TAG_ERROR) - ERROR(GNUTLS_E_ASN1_TAG_IMPLICIT) - ERROR(GNUTLS_E_ASN1_TYPE_ANY_ERROR) - ERROR(GNUTLS_E_ASN1_SYNTAX_ERROR) - ERROR(GNUTLS_E_ASN1_DER_OVERFLOW) - //ERROR(GNUTLS_E_OPENPGP_TRUSTDB_VERSION_UNSUPPORTED) - ERROR(GNUTLS_E_OPENPGP_UID_REVOKED) - ERROR(GNUTLS_E_CERTIFICATE_ERROR) - //ERROR(GNUTLS_E_X509_CERTIFICATE_ERROR) - ERROR(GNUTLS_E_CERTIFICATE_KEY_MISMATCH) - ERROR(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE) - ERROR(GNUTLS_E_X509_UNKNOWN_SAN) - ERROR(GNUTLS_E_OPENPGP_FINGERPRINT_UNSUPPORTED) - ERROR(GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE) - ERROR(GNUTLS_E_UNKNOWN_HASH_ALGORITHM) - ERROR(GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE) - ERROR(GNUTLS_E_UNKNOWN_PKCS_BAG_TYPE) - ERROR(GNUTLS_E_INVALID_PASSWORD) - ERROR(GNUTLS_E_MAC_VERIFY_FAILED) - ERROR(GNUTLS_E_CONSTRAINT_ERROR) - ERROR(GNUTLS_E_BASE64_ENCODING_ERROR) - ERROR(GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY) - //ERROR(GNUTLS_E_INCOMPATIBLE_CRYPTO_LIBRARY) - ERROR(GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARY) - ERROR(GNUTLS_E_OPENPGP_KEYRING_ERROR) - ERROR(GNUTLS_E_X509_UNSUPPORTED_OID) - //ERROR(GNUTLS_E_RANDOM_FAILED) - ERROR(GNUTLS_E_UNIMPLEMENTED_FEATURE) - - default: - - msg += "unknown error"; - break; - } + std::ostringstream msg; -#undef ERROR + msg << fname + "() returned code "; + msg << std::hex << code; + msg << ": "; + msg << gnutls_strerror(code); - throw exceptions::tls_exception(msg); + throw exceptions::tls_exception(msg.str()); } -- 1.7.7.3 From aae321dede5e725140534a08a8b2ee997faa30be Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Sun, 21 Aug 2011 08:55:46 +0000 Subject: [PATCH 24/27] Removed dependency on gcrypt for gnutls version >= 2.12. git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@599 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp index 7426a73..d3f6d49 100644 --- a/src/net/tls/TLSSession.cpp +++ b/src/net/tls/TLSSession.cpp @@ -26,9 +26,17 @@ #include "vmime/config.hpp" +// Dependency on gcrypt is not needed since GNU TLS version 2.12. +// See here: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=638651 +#if GNUTLS_VERSION_NUMBER <= 0x020b00 +# define VMIME_GNUTLS_NEEDS_GCRYPT 1 +#endif + #if VMIME_HAVE_PTHREAD # include -# include +# if VMIME_GNUTLS_NEEDS_GCRYPT +# include +# endif # include #endif // VMIME_HAVE_PTHREAD @@ -49,7 +57,7 @@ #endif // VMIME_DEBUG && GNUTLS_DEBUG -#if VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) +#if VMIME_HAVE_PTHREAD && VMIME_GNUTLS_NEEDS_GCRYPT && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) extern "C" { GCRY_THREAD_OPTION_PTHREAD_IMPL; @@ -70,7 +78,9 @@ struct TLSGlobal TLSGlobal() { #if VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) + #if VMIME_GNUTLS_NEEDS_GCRYPT gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + #endif // VMIME_GNUTLS_NEEDS_GCRYPT #endif // VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL gnutls_global_init(); -- 1.7.7.3 From af1e5664afb663fb7d26d468adf675fb1b3f8737 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Sun, 21 Aug 2011 09:04:46 +0000 Subject: [PATCH 25/27] Fixed HAVE_GNUTLS_PRIORITY_FUNCS never defined when configured with no TLS support. git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@600 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/SConstruct b/SConstruct index 01ad3f3..11e884b 100644 --- a/SConstruct +++ b/SConstruct @@ -1654,10 +1654,16 @@ if test "x$conf_tls" = "xyes"; then AM_CONDITIONAL(HAVE_GNUTLS_PRIORITY_FUNCS, false) HAVE_GNUTLS_PRIORITY_FUNCS=0 fi + else + AM_CONDITIONAL(HAVE_GNUTLS_PRIORITY_FUNCS, false) + HAVE_GNUTLS_PRIORITY_FUNCS=0 fi else AM_CONDITIONAL(VMIME_HAVE_TLS_SUPPORT, false) VMIME_HAVE_TLS_SUPPORT=0 + + AM_CONDITIONAL(HAVE_GNUTLS_PRIORITY_FUNCS, false) + HAVE_GNUTLS_PRIORITY_FUNCS=0 fi AC_SUBST(LIBGNUTLS_CFLAGS) -- 1.7.7.3 From 41079b2f188bb4a6d8aea9ec1328653faee3e2c9 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Tue, 15 Nov 2011 11:40:42 +0000 Subject: [PATCH 26/27] GNU TLS 3 has no 'extra' (thanks to mabrand). git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@601 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp index d3f6d49..cb50acc 100644 --- a/src/net/tls/TLSSession.cpp +++ b/src/net/tls/TLSSession.cpp @@ -22,7 +22,9 @@ // #include +#if GNUTLS_VERSION_NUMBER < 0x030000 #include +#endif #include "vmime/config.hpp" -- 1.7.7.3 From eafae52d9b8ec9682c229090b6208092b1d1e6f1 Mon Sep 17 00:00:00 2001 From: vincent-richard Date: Tue, 15 Nov 2011 11:46:07 +0000 Subject: [PATCH 27/27] Set Diffie-Hellman prime size (bug SF#3434852). git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@602 5301114d-f842-0410-bbdd-996ee0417009 diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp index cb50acc..0606808 100644 --- a/src/net/tls/TLSSession.cpp +++ b/src/net/tls/TLSSession.cpp @@ -139,6 +139,7 @@ TLSSession::TLSSession(ref cv) // Sets some default priority on the ciphers, key exchange methods, // macs and compression methods. #if HAVE_GNUTLS_PRIORITY_FUNCS + gnutls_dh_set_prime_bits(*m_gnutlsSession, 128); if ((res = gnutls_priority_set_direct (*m_gnutlsSession, "NORMAL:%SSL3_RECORD_VERSION", NULL)) != 0) -- 1.7.7.3