bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen#include "lib.h"
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen#include "buffer.h"
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen#include "str.h"
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen#include "charset-utf8.h"
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen#include "message-header-encode.h"
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen#include "message-header-decode.h"
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen#include "test-common.h"
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainenbool charset_is_utf8(const char *charset ATTR_UNUSED) { return TRUE; }
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainenint charset_to_utf8_begin(const char *charset ATTR_UNUSED,
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen normalizer_func_t *normalizer ATTR_UNUSED,
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen struct charset_translation **t_r ATTR_UNUSED) { return 0; }
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainenvoid charset_to_utf8_end(struct charset_translation **t ATTR_UNUSED) {}
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainenenum charset_result
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainencharset_to_utf8(struct charset_translation *t ATTR_UNUSED,
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen const unsigned char *src, size_t *src_size, buffer_t *dest)
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen{
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen buffer_append(dest, src, *src_size);
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen return CHARSET_RET_OK;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen}
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainenstatic void test_message_header_decode(void)
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen{
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen static const char *data[] = {
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody " \t=?utf-8?q?=c3=a4?= =?utf-8?q?=c3=a4?= b \t\r\n ", "\xC3\xA4\xC3\xA4 b \t\r\n ",
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody "a =?utf-8?q?=c3=a4?= b", "a \xC3\xA4 b",
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody "a =?utf-8?q?=c3=a4?= b", "a \xC3\xA4 b",
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody "a =?utf-8?q?=c3=a4?=\t\t\r\n =?utf-8?q?=c3=a4?= b", "a \xC3\xA4\xC3\xA4 b",
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody "a =?utf-8?q?=c3=a4?= x =?utf-8?q?=c3=a4?= b", "a \xC3\xA4 x \xC3\xA4 b",
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody "a =?utf-8?b?w6TDpCDDpA==?= b", "a \xC3\xA4\xC3\xA4 \xC3\xA4 b",
19ed8f08b23d6ed204e6b27e5d1c0c6fe6bb11ddPhil Carmody "=?utf-8?b?w6Qgw6Q=?=", "\xC3\xA4 \xC3\xA4",
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen };
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen string_t *dest;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen unsigned int i;
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen test_begin("message header decode");
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen dest = t_str_new(256);
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen for (i = 0; i < N_ELEMENTS(data); i += 2) {
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen str_truncate(dest, 0);
82d3a1d1594ed93d04d7bf999027b3e5104de6e4Timo Sirainen message_header_decode_utf8((const unsigned char *)data[i],
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainen strlen(data[i]), dest, NULL);
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen test_assert(strcmp(str_c(dest), data[i+1]) == 0);
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen }
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen test_end();
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen}
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen
79454ba23ef6baf56997cd3cc23123eb69ae4f4cTimo Sirainenstatic void test_message_header_decode_read_overflow(void)
79454ba23ef6baf56997cd3cc23123eb69ae4f4cTimo Sirainen{
79454ba23ef6baf56997cd3cc23123eb69ae4f4cTimo Sirainen const unsigned char input[] = "=?utf-8?Q?=EF?=";
79454ba23ef6baf56997cd3cc23123eb69ae4f4cTimo Sirainen string_t *dest = t_str_new(32);
79454ba23ef6baf56997cd3cc23123eb69ae4f4cTimo Sirainen
79454ba23ef6baf56997cd3cc23123eb69ae4f4cTimo Sirainen test_begin("message header decode read overflow");
79454ba23ef6baf56997cd3cc23123eb69ae4f4cTimo Sirainen message_header_decode_utf8(input, sizeof(input)-2, dest, NULL);
79454ba23ef6baf56997cd3cc23123eb69ae4f4cTimo Sirainen test_end();
79454ba23ef6baf56997cd3cc23123eb69ae4f4cTimo Sirainen}
79454ba23ef6baf56997cd3cc23123eb69ae4f4cTimo Sirainen
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainenstatic void test_message_header_decode_encode_random(void)
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen{
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen string_t *encoded, *decoded;
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen unsigned char buf[1024];
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen unsigned int i, j, buflen;
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen test_begin("message header encode & decode randomly");
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen encoded = t_str_new(256);
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen decoded = t_str_new(256);
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen for (i = 0; i < 1000; i++) {
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen /* fill only with 7bit data so we don't have to worry about
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen the data being valid UTF-8 */
2d310b66c9e541e4a3db7bac89b01534f486bb95Timo Sirainen for (j = 0; j < sizeof(buf); j++)
191153d1a5b0eb0c129139570e3aa5212f28d2acJosef 'Jeff' Sipek buf[j] = i_rand_limit(128);
191153d1a5b0eb0c129139570e3aa5212f28d2acJosef 'Jeff' Sipek buflen = i_rand_limit(sizeof(buf));
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen str_truncate(encoded, 0);
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen str_truncate(decoded, 0);
2d310b66c9e541e4a3db7bac89b01534f486bb95Timo Sirainen
2d310b66c9e541e4a3db7bac89b01534f486bb95Timo Sirainen /* test Q */
2d310b66c9e541e4a3db7bac89b01534f486bb95Timo Sirainen message_header_encode_q(buf, buflen, encoded, 0);
2d310b66c9e541e4a3db7bac89b01534f486bb95Timo Sirainen message_header_decode_utf8(encoded->data, encoded->used,
2d310b66c9e541e4a3db7bac89b01534f486bb95Timo Sirainen decoded, NULL);
2d310b66c9e541e4a3db7bac89b01534f486bb95Timo Sirainen test_assert(decoded->used == buflen &&
2d310b66c9e541e4a3db7bac89b01534f486bb95Timo Sirainen memcmp(decoded->data, buf, buflen) == 0);
2d310b66c9e541e4a3db7bac89b01534f486bb95Timo Sirainen
2d310b66c9e541e4a3db7bac89b01534f486bb95Timo Sirainen /* test B */
2d310b66c9e541e4a3db7bac89b01534f486bb95Timo Sirainen str_truncate(encoded, 0);
2d310b66c9e541e4a3db7bac89b01534f486bb95Timo Sirainen str_truncate(decoded, 0);
2d310b66c9e541e4a3db7bac89b01534f486bb95Timo Sirainen
2d310b66c9e541e4a3db7bac89b01534f486bb95Timo Sirainen message_header_encode_b(buf, buflen, encoded, 0);
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen message_header_decode_utf8(encoded->data, encoded->used,
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen decoded, NULL);
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen test_assert(decoded->used == buflen &&
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen memcmp(decoded->data, buf, buflen) == 0);
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen }
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen test_end();
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen}
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainenint main(void)
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen{
baf3e87e186453fda13bd21f7cbcb2efc8492e8bTimo Sirainen static void (*const test_functions[])(void) = {
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen test_message_header_decode,
79454ba23ef6baf56997cd3cc23123eb69ae4f4cTimo Sirainen test_message_header_decode_read_overflow,
a5f1628ad97ad649bfef86c84c3afc1d9cb0f326Timo Sirainen test_message_header_decode_encode_random,
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen NULL
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen };
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen return test_run(test_functions);
b014857be9961acf2d37ef7b76d941b20cc8c2d1Timo Sirainen}