From aa4d426b4d3527d7e166df1a05058c9a4a0f6683 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Fri, 30 Apr 2021 00:33:56 +0200 Subject: initial/final commit --- vmime-master/tests/parser/parameterTest.cpp | 722 ++++++++++++++++++++++++++++ 1 file changed, 722 insertions(+) create mode 100644 vmime-master/tests/parser/parameterTest.cpp (limited to 'vmime-master/tests/parser/parameterTest.cpp') diff --git a/vmime-master/tests/parser/parameterTest.cpp b/vmime-master/tests/parser/parameterTest.cpp new file mode 100644 index 0000000..464c305 --- /dev/null +++ b/vmime-master/tests/parser/parameterTest.cpp @@ -0,0 +1,722 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "tests/testUtils.hpp" + +#include +#include + + +VMIME_TEST_SUITE_BEGIN(parameterTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testParse) + VMIME_TEST(testParseRFC2231) + VMIME_TEST(testGenerate) + VMIME_TEST(testGetGeneratedSize) + VMIME_TEST(testGenerateRFC2231) + VMIME_TEST(testGetGeneratedSizeRFC2231) + VMIME_TEST(testNonStandardEncodedParam) + VMIME_TEST(testParseNonSignificantWS) + VMIME_TEST(testEncodeTSpecials) + VMIME_TEST(testEncodeTSpecialsInRFC2231) + VMIME_TEST(testWhitespaceBreaksTheValue) + VMIME_TEST_LIST_END + + + // HACK: parameterizedHeaderField constructor is private + class parameterizedHeaderField : public vmime::parameterizedHeaderField { + + public: + + parameterizedHeaderField() { + + setName("F"); + setValue(vmime::headerFieldFactory::getInstance()->createValue(getName())); + setValue(vmime::word("X")); + } + + using vmime::parameterizedHeaderField::generate; + + const vmime::string generate( + const vmime::generationContext::EncodedParameterValueModes genMode, + const vmime::size_t maxLineLength = 0 + ) const { + + vmime::generationContext ctx(vmime::generationContext::getDefaultContext()); + ctx.setEncodedParameterValueMode(genMode); + + if (maxLineLength != 0) { + ctx.setMaxLineLength(maxLineLength); + } + + std::ostringstream oss; + vmime::utility::outputStreamAdapter adapter(oss); + + vmime::parameterizedHeaderField::generate(ctx, adapter); + + return oss.str(); + } + }; + + + const vmime::string generateParameter( + const vmime::parameter& param, + const vmime::generationContext& ctx, + const vmime::size_t maxLineLength = 0 + ) const { + + vmime::generationContext ctx2(ctx); + + if (maxLineLength != 0) { + ctx2.setMaxLineLength(maxLineLength); + } + + std::ostringstream oss; + vmime::utility::outputStreamAdapter adapter(oss); + + param.generate(ctx2, adapter); + + return oss.str(); + } + + +#define FIELD_VALUE(f) (f.getValue()->generate()) +#define PARAM_VALUE(p, n) (p.getParameterAt(n)->getValue().generate()) +#define PARAM_NAME(p, n) (p.getParameterAt(n)->getName()) +#define PARAM_CHARSET(p, n) \ + (p.getParameterAt(n)->getValue().getCharset().generate()) +#define PARAM_LANG(p, n) \ + (p.getParameterAt(n)->getValue().getLanguage()) +#define PARAM_BUFFER(p, n) \ + (p.getParameterAt(n)->getValue().getBuffer()) + + + void setUp() { + + // Set the global C and C++ locale to the user-configured locale. + // The locale should use UTF-8 encoding for these tests to run successfully. + try { + std::locale::global(std::locale("")); + } catch (std::exception &) { + std::setlocale(LC_ALL, ""); + } + } + + void tearDown() { + + // Restore default locale + std::locale::global(std::locale("C")); + } + + + void testParse() { + + // Simple parameter + parameterizedHeaderField p1; + p1.parse("X; param1=value1;\r\n"); + + VASSERT_EQ("1.1", 1, p1.getParameterCount()); + VASSERT_EQ("1.2", "param1", PARAM_NAME(p1, 0)); + VASSERT_EQ("1.3", "value1", PARAM_VALUE(p1, 0)); + + // Multi-section parameters (1/2) + parameterizedHeaderField p2a; + p2a.parse( + "X; param1=value1;\r\n" + " param2*0=\"val\";\r\n" + " param2*1=\"ue2\";" + ); + + VASSERT_EQ("2a.1", 2, p2a.getParameterCount()); + VASSERT_EQ("2a.2", "param1", PARAM_NAME(p2a, 0)); + VASSERT_EQ("2a.3", "value1", PARAM_VALUE(p2a, 0)); + VASSERT_EQ("2a.4", "param2", PARAM_NAME(p2a, 1)); + VASSERT_EQ("2a.5", "value2", PARAM_VALUE(p2a, 1)); + + // Multi-section parameters (2/2) + parameterizedHeaderField p2b; + p2b.parse( + "X; param1=value1;\r\n" + " param2=\"should be ignored\";\r\n" + " param2*0=\"val\";\r\n" + " param2*1=\"ue2\";" + ); + + VASSERT_EQ("2b.1", 2, p2b.getParameterCount()); + VASSERT_EQ("2b.2", "param1", PARAM_NAME(p2b, 0)); + VASSERT_EQ("2b.3", "value1", PARAM_VALUE(p2b, 0)); + VASSERT_EQ("2b.4", "param2", PARAM_NAME(p2b, 1)); + VASSERT_EQ("2b.5", "value2", PARAM_VALUE(p2b, 1)); + + // Extended parameter (charset and language information) + parameterizedHeaderField p3; + p3.parse("X; param1*=charset'language'value1;\r\n"); + + VASSERT_EQ("3.1", 1, p3.getParameterCount()); + VASSERT_EQ("3.2", "param1", PARAM_NAME(p3, 0)); + VASSERT_EQ("3.3", "charset", PARAM_CHARSET(p3, 0)); + VASSERT_EQ("3.4", "value1", PARAM_BUFFER(p3, 0)); + + // Encoded characters in extended parameter values + parameterizedHeaderField p4; + p4.parse("X; param1*=a%20value%20with%20multiple%20word%73"); // 0x73 = 's' + + VASSERT_EQ("4.1", 1, p4.getParameterCount()); + VASSERT_EQ("4.2", "param1", PARAM_NAME(p4, 0)); + VASSERT_EQ("4.3", "a value with multiple words", PARAM_VALUE(p4, 0)); + + // Invalid encoded character + parameterizedHeaderField p5; + p5.parse("X; param1*=test%20value%"); + + VASSERT_EQ("5.1", 1, p5.getParameterCount()); + VASSERT_EQ("5.2", "param1", PARAM_NAME(p5, 0)); + VASSERT_EQ("5.3", "test value%", PARAM_VALUE(p5, 0)); + + // Spaces before and after '=' + parameterizedHeaderField p6; + p6.parse("X; param1\t= \"value1\""); + + VASSERT_EQ("6.1", 1, p6.getParameterCount()); + VASSERT_EQ("6.2", "param1", PARAM_NAME(p6, 0)); + VASSERT_EQ("6.3", "value1", PARAM_VALUE(p6, 0)); + + // Quoted strings and escaped chars + parameterizedHeaderField p7; + p7.parse("X; param1=\"this is a slash: \\\"\\\\\\\"\""); // \"\\\" + + VASSERT_EQ("7.1", 1, p7.getParameterCount()); + VASSERT_EQ("7.2", "param1", PARAM_NAME(p7, 0)); + VASSERT_EQ("7.3", "this is a slash: \"\\\"", PARAM_VALUE(p7, 0)); + } + + void testParseRFC2231() { + + // Extended parameter with charset specified in more than one + // section (this is forbidden by RFC, but is should not fail) + parameterizedHeaderField p1; + p1.parse( + "X; param1*0*=charset1'language1'value1;\r\n" + " param1*1*=charset2'language2'value2;" + ); + + VASSERT_EQ("1.1", 1, p1.getParameterCount()); + VASSERT_EQ("1.2", "param1", PARAM_NAME(p1, 0)); + VASSERT_EQ("1.3", "charset1", PARAM_CHARSET(p1, 0)); + VASSERT_EQ("1.4", "value1charset2'language2'value2", PARAM_BUFFER(p1, 0)); + + // Charset not specified in the first section (that is not encoded), + // but specified in the second one (legal) + parameterizedHeaderField p2; + p2.parse( + "X; param1*0=value1;\r\n" + " param1*1*=charset'language'value2;" + ); + + VASSERT_EQ("2.1", 1, p2.getParameterCount()); + VASSERT_EQ("2.2", "param1", PARAM_NAME(p2, 0)); + VASSERT_EQ("2.3", "charset", PARAM_CHARSET(p2, 0)); + VASSERT_EQ("2.4", "value1value2", PARAM_BUFFER(p2, 0)); + + // Characters prefixed with '%' in a simple (not extended) section + // should not be decoded + parameterizedHeaderField p3; + p3.parse("X; param1=val%20ue1"); + + VASSERT_EQ("3.1", 1, p3.getParameterCount()); + VASSERT_EQ("3.2", "param1", PARAM_NAME(p3, 0)); + VASSERT_EQ("3.3", "val%20ue1", PARAM_VALUE(p3, 0)); + + // Multiple sections + charset specified and encoding + parameterizedHeaderField p4; + p4.parse( + "X; param1*0*=charset'language'value1a%20;" + " param1*1*=value1b%20;" + " param1*2=value1c" + ); + + VASSERT_EQ("4.1", 1, p4.getParameterCount()); + VASSERT_EQ("4.2", "param1", PARAM_NAME(p4, 0)); + VASSERT_EQ("4.3", "charset", PARAM_CHARSET(p4, 0)); + VASSERT_EQ("4.4", "value1a value1b value1c", PARAM_BUFFER(p4, 0)); + + // No charset specified: defaults to US-ASCII + parameterizedHeaderField p5; + p5.parse("X; param1*='language'value1"); + + VASSERT_EQ("5.1", 1, p5.getParameterCount()); + VASSERT_EQ("5.2", "param1", PARAM_NAME(p5, 0)); + VASSERT_EQ("5.3", "us-ascii", PARAM_CHARSET(p5, 0)); + VASSERT_EQ("5.4", "value1", PARAM_BUFFER(p5, 0)); + + // Language specification + parameterizedHeaderField p6; + p6.parse("X; param1*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A"); + + VASSERT_EQ("6.1", 1, p6.getParameterCount()); + VASSERT_EQ("6.2", "param1", PARAM_NAME(p6, 0)); + VASSERT_EQ("6.3", "us-ascii", PARAM_CHARSET(p6, 0)); + VASSERT_EQ("6.4", "en-us", PARAM_LANG(p6, 0)); + VASSERT_EQ("6.5", "This is ***fun***", PARAM_BUFFER(p6, 0)); + } + + void testGenerate() { + + // Simple parameter/value + parameterizedHeaderField p1; + p1.appendParameter(vmime::make_shared ("param1", "value1")); + + VASSERT_EQ("1", "F: X; param1=value1", p1.generate()); + + // Value that needs quoting (1/2) + parameterizedHeaderField p2a; + p2a.appendParameter(vmime::make_shared ("param1", "value1a;value1b")); + + VASSERT_EQ("2a", "F: X; param1=\"value1a;value1b\"", p2a.generate()); + + // Value that needs quoting (2/2) + parameterizedHeaderField p2b; + p2b.appendParameter(vmime::make_shared ("param1", "va\\lue\"1")); + + VASSERT_EQ("2b", "F: X; param1=\"va\\\\lue\\\"1\"", p2b.generate()); + } + + void testGetGeneratedSize() { + + vmime::generationContext ctx(vmime::generationContext::getDefaultContext()); + + vmime::parameter p1("param1", "value1"); + VASSERT("1", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length()); + + vmime::parameter p2a("param1", "value1a;value1b"); + VASSERT("2&", p2a.getGeneratedSize(ctx) >= generateParameter(p2a, ctx).length()); + + vmime::parameter p2b("param1", "va\\lue\"1"); + VASSERT("1", p2b.getGeneratedSize(ctx) >= generateParameter(p2b, ctx).length()); + } + + void testGenerateRFC2231() { + + // Extended parameter with charset specifier + parameterizedHeaderField p1; + p1.appendParameter( + vmime::make_shared ( + "param1", + vmime::word("value 1\xe9", vmime::charset("charset")) + ) + ); + + VASSERT_EQ( + "1.no-encoding", + "F: X; param1=\"value 1\"", + p1.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING) + ); + + VASSERT_EQ( + "1.rfc2047", + "F: X; param1=\"=?charset?Q?value_1=E9?=\"", + p1.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY) + ); + + VASSERT_EQ( + "1.rfc2231", + "F: X; param1*=charset''value%201%E9", + p1.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY) + ); + + VASSERT_EQ( + "1.both", + "F: X; param1=\"=?charset?Q?value_1=E9?=\";param1*=charset''value%201%E9", + p1.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047) + ); + + // Value that spans on multiple lines + parameterizedHeaderField p2; + p2.appendParameter( + vmime::make_shared ( + "param1", + vmime::word( + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + vmime::charset("charset") + ) + ) + ); + + VASSERT_EQ( + "2.no-encoding", + "F: X; \r\n " + "param1=abcdefghijkl", + p2.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING, 25) // max line length = 25 + ); + + VASSERT_EQ( + "2.rfc2047", + "F: X; \r\n " + "param1=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + p2.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY, 25) // max line length = 25 + ); + + VASSERT_EQ( + "2.rfc2231", + "F: X; \r\n " + "param1*0*=charset''abc;\r\n " + "param1*1*=defghijkl;\r\n " + "param1*2*=mnopqrstu;\r\n " + "param1*3*=vwxyzABCD;\r\n " + "param1*4*=EFGHIJKLM;\r\n " + "param1*5*=NOPQRSTUV;\r\n " + "param1*6*=WXYZ", + p2.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY, 25) // max line length = 25 + ); + + VASSERT_EQ( + "2.both", + "F: X; \r\n " + "param1=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;\r\n " + "param1*0*=charset''abc;\r\n " + "param1*1*=defghijkl;\r\n " + "param1*2*=mnopqrstu;\r\n " + "param1*3*=vwxyzABCD;\r\n " + "param1*4*=EFGHIJKLM;\r\n " + "param1*5*=NOPQRSTUV;\r\n " + "param1*6*=WXYZ", + p2.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047, 25) // max line length = 25 + ); + + // Non-ASCII parameter value + parameterizedHeaderField p3; + p3.appendParameter( + vmime::make_shared ( + "param1", + vmime::word( + "δσσσσσσσσσσσσσσσσσσσσδσδα δσαδσδσαδσαδασδασ δσαδασδσα δσαδασδσα δασδασδασ δασαχφδδσα 2008.doc", + vmime::charset("utf-8") + ) + ) + ); + + VASSERT_EQ( + "3.no-encoding", + "F: X; \r\n " + "param1=\" 2008.doc\"", + p3.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING, 80) // max line length = 80 + ); + + VASSERT_EQ( + "3.7bit-only", + "F: X; \r\n " + "param1=\"=?utf-8?B?zrTPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+DzrTPg860?=\r\n " + "=?utf-8?B?zrEgzrTPg86xzrTPg860z4POsc60z4POsc60zrHPg860zrHPgyDOtM+DzrHOtM6x?=\r\n " + "=?utf-8?B?z4POtM+DzrEgzrTPg86xzrTOsc+DzrTPg86xIM60zrHPg860zrHPg860zrHPgyDOtA==?=\r\n " + "=?utf-8?B?zrHPg86xz4fPhs60zrTPg86xIDIwMDguZG9j?=\"", + p3.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY, 80) // max line length = 80 + ); + + VASSERT_EQ( + "3.both", + "F: X; \r\n " + "param1=\"=?utf-8?B?zrTPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+DzrTPg860?=\r\n " + "=?utf-8?B?zrEgzrTPg86xzrTPg860z4POsc60z4POsc60zrHPg860zrHPgyDOtM+DzrHOtM6x?=\r\n " + "=?utf-8?B?z4POtM+DzrEgzrTPg86xzrTOsc+DzrTPg86xIM60zrHPg860zrHPg860zrHPgyDOtA==?=\r\n " + "=?utf-8?B?zrHPg86xz4fPhs60zrTPg86xIDIwMDguZG9j?=\";\r\n " + "param1*0*=utf-8''%CE%B4%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n " + "param1*1*=%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n " + "param1*2*=%CE%B4%CF%83%CE%B4%CE%B1%20%CE%B4%CF%83%CE%B1%CE%B4%CF%83%CE%B4%CF;\r\n " + "param1*3*=%83%CE%B1%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20;\r\n " + "param1*4*=%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CF;\r\n " + "param1*5*=%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CE%B1%CF%83;\r\n " + "param1*6*=%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20%CE%B4%CE%B1%CF%83%CE%B1%CF;\r\n " + "param1*7*=%87%CF%86%CE%B4%CE%B4%CF%83%CE%B1%202008.doc", + p3.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047, 80) // max line length = 80 + ); + + VASSERT_EQ( + "3.either", + "F: X; param1*0*=utf-8''%CE%B4%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n " + "param1*1*=%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n " + "param1*2*=%CE%B4%CF%83%CE%B4%CE%B1%20%CE%B4%CF%83%CE%B1%CE%B4%CF%83%CE%B4%CF;\r\n " + "param1*3*=%83%CE%B1%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20;\r\n " + "param1*4*=%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CF;\r\n " + "param1*5*=%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CE%B1%CF%83;\r\n " + "param1*6*=%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20%CE%B4%CE%B1%CF%83%CE%B1%CF;\r\n " + "param1*7*=%87%CF%86%CE%B4%CE%B4%CF%83%CE%B1%202008.doc", + p3.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY, 80) // max line length = 80 + ); + + // No encoding needed + parameterizedHeaderField p4; + p4.appendParameter( + vmime::make_shared ( + "param1", + vmime::word("va lue", vmime::charset("charset")) + ) + ); + + VASSERT_EQ( + "4.no-encoding", + "F: X; param1=\"va lue\"", + p4.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING) + ); + + VASSERT_EQ( + "4.rfc2047", + "F: X; param1=\"va lue\"", + p4.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY) + ); + + VASSERT_EQ( + "4.rfc2231", + "F: X; param1=\"va lue\"", + p4.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY) + ); + + VASSERT_EQ( + "4.both", + "F: X; param1=\"va lue\"", + p4.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047) + ); + + // Language specification + parameterizedHeaderField p5; + p5.appendParameter( + vmime::make_shared ("param1", + vmime::word("This is ***fun***", vmime::charset("us-ascii"), "en-us")) + ); + + VASSERT_EQ( + "5.no-encoding", + "F: X; param1=\"This is ***fun***\"", + p5.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING) + ); + + VASSERT_EQ( + "5.rfc2047", + "F: X; param1=\"=?us-ascii*en-us?Q?This_is_***fun***?=\"", + p5.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY) + ); + + VASSERT_EQ( + "5.rfc2231", + "F: X; param1*=us-ascii''This%20is%20***fun***", + p5.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY) + ); + + VASSERT_EQ( + "5.both", + "F: X; " + "param1=\"=?us-ascii*en-us?Q?This_is_***fun***?=\";\r\n " + "param1*=us-ascii''This%20is%20***fun***", + p5.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047)); + } + + void testGetGeneratedSizeRFC2231() { + + vmime::generationContext ctx(vmime::generationContext::getDefaultContext()); + + // Extended parameter with charset specifier + vmime::parameter p1( + "param1", + vmime::word("value 1\xe9", vmime::charset("charset")) + ); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING); + VASSERT("1.no-encoding", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY); + VASSERT("1.rfc2047", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY); + VASSERT("1.rfc2231", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047); + VASSERT("1.both", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length()); + + // Value that spans on multiple lines + vmime::parameter p2( + "param1", + vmime::word( + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + vmime::charset("charset") + ) + ); + + ctx.setMaxLineLength(25); + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING); + VASSERT("2.no-encoding", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY); + VASSERT("2.rfc2047", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY); + VASSERT("2.rfc2231", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047); + VASSERT("2.both", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length()); + + // Non-ASCII parameter value + vmime::parameter p3( + "param1", + vmime::word( + "δσσσσσσσσσσσσσσσσσσσσδσδα δσαδσδσαδσαδασδασ δσαδασδσα δσαδασδσα δασδασδασ δασαχφδδσα 2008.doc", + vmime::charset("utf-8") + ) + ); + + ctx.setMaxLineLength(vmime::generationContext::getDefaultContext().getMaxLineLength()); + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING); + VASSERT("3.no-encoding", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY); + VASSERT("3.rfc2047", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY); + VASSERT("3.rfc2231", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047); + VASSERT("3.both", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length()); + + // No encoding needed + vmime::parameter p4( + "param1", + vmime::word("va lue", vmime::charset("charset")) + ); + + ctx.setMaxLineLength(vmime::generationContext::getDefaultContext().getMaxLineLength()); + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING); + VASSERT("4.no-encoding", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY); + VASSERT("4.rfc2047", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY); + VASSERT("4.rfc2231", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047); + VASSERT("4.both", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length()); + + // Language specification + vmime::parameter p5( + "param1", + vmime::word("This is ***fun***", vmime::charset("us-ascii"), "en-us") + ); + + ctx.setMaxLineLength(vmime::generationContext::getDefaultContext().getMaxLineLength()); + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING); + VASSERT("5.no-encoding", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY); + VASSERT("5.rfc2047", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY); + VASSERT("5.rfc2231", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047); + VASSERT("5.both", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length()); + } + + void testNonStandardEncodedParam() { + + // This syntax is non-standard (expressly prohibited + // by RFC-2047), but is used by Mozilla: + // + // Content-Type: image/png; + // name="=?us-ascii?Q?Logo_VMime=2Epng?=" + + parameterizedHeaderField p1; + p1.parse("image/png; name=\"=?us-ascii?Q?Logo_VMime=2Epng?=\""); + + VASSERT_EQ("1.1", 1, p1.getParameterCount()); + VASSERT_EQ("1.2", "name", PARAM_NAME(p1, 0)); + VASSERT_EQ("1.3", "Logo VMime.png", PARAM_VALUE(p1, 0)); + + parameterizedHeaderField p2; + p2.parse("image/png; name=\"Logo =?us-ascii?Q?VMime=2Epng?=\""); + + VASSERT_EQ("2.1", 1, p2.getParameterCount()); + VASSERT_EQ("2.2", "name", PARAM_NAME(p2, 0)); + VASSERT_EQ("2.3", "Logo VMime.png", PARAM_VALUE(p2, 0)); + } + + // Parse parameters with non-significant whitespaces + void testParseNonSignificantWS() { + + parameterizedHeaderField p1; + p1.parse(" \t X \r\n"); + + VASSERT_EQ("1.1", "X", FIELD_VALUE(p1)); + + parameterizedHeaderField p2; + p2.parse(" X ; param1 = value1 \r\n"); + + VASSERT_EQ("2.1", 1, p2.getParameterCount()); + VASSERT_EQ("2.2", "X", FIELD_VALUE(p2)); + VASSERT_EQ("2.3", "param1", PARAM_NAME(p2, 0)); + VASSERT_EQ("2.4", "value1", PARAM_VALUE(p2, 0)); + } + + // Encode "tspecials" + void testEncodeTSpecials() { + + VASSERT_EQ(" 1", "p=\"val(ue\"", vmime::make_shared ("p", "val(ue")->generate()); + VASSERT_EQ(" 2", "p=\"val)ue\"", vmime::make_shared ("p", "val)ue")->generate()); + VASSERT_EQ(" 3", "p=\"val("p", "valgenerate()); + VASSERT_EQ(" 4", "p=\"val>ue\"", vmime::make_shared ("p", "val>ue")->generate()); + VASSERT_EQ(" 5", "p=\"val@ue\"", vmime::make_shared ("p", "val@ue")->generate()); + VASSERT_EQ(" 6", "p=\"val,ue\"", vmime::make_shared ("p", "val,ue")->generate()); + VASSERT_EQ(" 7", "p=\"val;ue\"", vmime::make_shared ("p", "val;ue")->generate()); + VASSERT_EQ(" 8", "p=\"val:ue\"", vmime::make_shared ("p", "val:ue")->generate()); + VASSERT_EQ(" 9", "p=\"val/ue\"", vmime::make_shared ("p", "val/ue")->generate()); + VASSERT_EQ("10", "p=\"val[ue\"", vmime::make_shared ("p", "val[ue")->generate()); + VASSERT_EQ("11", "p=\"val]ue\"", vmime::make_shared ("p", "val]ue")->generate()); + VASSERT_EQ("12", "p=\"val?ue\"", vmime::make_shared ("p", "val?ue")->generate()); + VASSERT_EQ("13", "p=\"val=ue\"", vmime::make_shared ("p", "val=ue")->generate()); + VASSERT_EQ("14", "p=\"val ue\"", vmime::make_shared ("p", "val ue")->generate()); + VASSERT_EQ("15", "p=\"val\tue\"", vmime::make_shared ("p", "val\tue")->generate()); + } + + // http://sourceforge.net/projects/vmime/forums/forum/237356/topic/3812278 + void testEncodeTSpecialsInRFC2231() { + + VASSERT_EQ( + "1", + "filename*=UTF-8''my_file_name_%C3%B6%C3%A4%C3%BC_%281%29.txt", + vmime::make_shared ( + "filename", + vmime::word("my_file_name_\xc3\xb6\xc3\xa4\xc3\xbc_(1).txt", "UTF-8") + )->generate() + ); + } + + void testWhitespaceBreaksTheValue() { + + parameterizedHeaderField p; + p.parse("xxx yyy; param1=value1 \r\n"); + + VASSERT_EQ("count", 1, p.getParameterCount()); + VASSERT_EQ("value", "xxx", FIELD_VALUE(p)); + VASSERT_EQ("param1.name", "param1", PARAM_NAME(p, 0)); + VASSERT_EQ("param1.value", "value1", PARAM_VALUE(p, 0)); + } + +VMIME_TEST_SUITE_END -- cgit v1.2.3