1
/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
6
#include "message-header-encode.h"
8
#define MIME_WRAPPER_LEN (strlen("=?utf-8?q?""?="))
9
#define MIME_MAX_LINE_LEN 76
12
((c) == ' ' || (c) == '\t' || (c) == '\n')
14
static bool input_idx_need_encoding(const unsigned char *input, unsigned int i)
16
if ((input[i] & 0x80) != 0)
19
if (input[i] == '=' && input[i+1] == '?' &&
20
(i == 0 || IS_LWSP(input[i-1])))
25
static unsigned int str_last_line_len(string_t *str)
27
const unsigned char *data = str_data(str);
28
unsigned int i = str_len(str);
30
while (i > 0 && data[i-1] != '\n')
32
return str_len(str) - i;
35
void message_header_encode_q(const unsigned char *input, unsigned int len,
38
unsigned int i, line_len, line_len_left;
40
line_len = str_last_line_len(output);
41
if (line_len >= MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN - 3) {
42
str_append(output, "\n\t");
46
str_append(output, "=?utf-8?q?");
47
line_len_left = MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN - line_len;
48
for (i = 0; i < len; i++) {
49
if (line_len_left < 3) {
50
/* if we're not at the beginning of a character,
51
go backwards until we are */
52
while ((input[i] & 0xc0) == 0x80) {
53
str_truncate(output, str_len(output)-3);
56
str_append(output, "?=\n\t=?utf-8?q?");
57
line_len_left = MIME_MAX_LINE_LEN -
62
str_append_c(output, '_');
68
str_printfa(output, "=%2X", input[i]);
71
if (input[i] < 32 || (input[i] & 0x80) != 0) {
73
str_printfa(output, "=%2X", input[i]);
75
str_append_c(output, input[i]);
81
str_append(output, "?=");
84
void message_header_encode_b(const unsigned char *input, unsigned int len,
87
unsigned int line_len, line_len_left, max;
89
line_len = str_last_line_len(output);
90
if (line_len >= MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN) {
91
str_append(output, "\n\t");
96
line_len_left = MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN - line_len;
97
max = MAX_BASE64_DECODED_SIZE(line_len_left);
103
/* all of it doesn't fit. find a character where we
104
can split it from. */
105
while (max > 0 && (input[max] & 0xc0) == 0x80)
108
} while (MAX_BASE64_ENCODED_SIZE(max) > line_len_left &&
112
str_append(output, "=?utf-8?b?");
113
base64_encode(input, max, output);
114
str_append(output, "?=");
123
str_append(output, "\n\t");
128
void message_header_encode(const char *_input, string_t *output)
130
const unsigned char *input = (const unsigned char *)_input;
131
unsigned int i, first_idx, last_idx;
132
unsigned int enc_chars, enc_len, base64_len, q_len;
135
/* find the first word that needs encoding */
136
for (i = 0; input[i] != '\0'; i++) {
137
if (input_idx_need_encoding(input, i))
140
if (input[i] == '\0') {
141
/* no encoding necessary */
142
str_append(output, _input);
146
while (first_idx > 0 && !IS_LWSP(input[first_idx-1]))
149
/* find the last word that needs encoding */
150
last_idx = ++i; enc_chars = 1;
151
for (; input[i] != '\0'; i++) {
152
if (input_idx_need_encoding(input, i)) {
157
while (input[last_idx] != '\0' && !IS_LWSP(input[last_idx]))
160
/* figure out if we should use Q or B encoding. Prefer Q if it's not
162
enc_len = last_idx - first_idx;
163
base64_len = MAX_BASE64_ENCODED_SIZE(enc_len);
164
q_len = enc_len + enc_chars*3;
165
use_q = q_len*2/3 <= base64_len;
168
str_append_n(output, input, first_idx);
170
message_header_encode_q(input + first_idx, enc_len, output);
172
message_header_encode_b(input + first_idx, enc_len, output);
173
str_append(output, _input + last_idx);