From b8c2685a601d09455064b7116d85fb2fd0a0f860 Mon Sep 17 00:00:00 2001 From: Christian Neukirchen Date: Mon, 25 Jul 2016 15:19:19 +0200 Subject: mmime: encode headers when neccessary This is still a bit clumsy, but I'm not sure how to make it better. --- mmime.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 98 insertions(+), 9 deletions(-) (limited to 'mmime.c') diff --git a/mmime.c b/mmime.c index 93377fc..2d240f3 100644 --- a/mmime.c +++ b/mmime.c @@ -54,7 +54,7 @@ int gen_b64(uint8_t *s, off_t size) return 0; } -int gen_qp(uint8_t *s, off_t size) +int gen_qp(uint8_t *s, off_t size, int maxlinelen, int header) { off_t i; int linelen = 0; @@ -67,8 +67,17 @@ int gen_qp(uint8_t *s, off_t size) printf("=%02X", s[i]); linelen += 3; prev = s[i]; + } else if (header && + (s[i] == '\n' || s[i] == '\t' || s[i] == '_')) { + printf("=%02X", s[i]); + linelen += 3; + prev = '_'; + } else if (header && s[i] == ' ') { + putc_unlocked('_', stdout); + linelen++; + prev = '_'; } else if (s[i] == '\n') { - if (i > 1 && (prev == ' ' || prev == '\t')) + if (prev == ' ' || prev == '\t') puts("="); putc_unlocked('\n', stdout); linelen = 0; @@ -79,15 +88,15 @@ int gen_qp(uint8_t *s, off_t size) prev = s[i]; } - if (linelen >= 75) { + if (linelen >= maxlinelen-3) { linelen = 0; prev = '\n'; puts("="); } } - if (linelen > 0) + if (linelen > 0 && !header) puts("="); - return 0; + return linelen; } static const char * @@ -146,7 +155,8 @@ int gen_file(char *file, char *ct) ct = "text/plain"; printf("Content-Type: %s\n", ct); printf("Content-Transfer-Encoding: quoted-printable\n\n"); - return gen_qp(content, st.st_size); + gen_qp(content, st.st_size, 78, 0); + return 0; } else if (bitlow > st.st_size/10 || bithigh > st.st_size/4) { if (!ct) ct = "application/binary"; @@ -158,7 +168,8 @@ int gen_file(char *file, char *ct) ct = "text/plain"; printf("Content-Type: %s\n", ct); printf("Content-Transfer-Encoding: quoted-printable\n\n"); - return gen_qp(content, st.st_size); + gen_qp(content, st.st_size, 78, 0); + return 0; } } @@ -182,6 +193,84 @@ gen_mixed(int argc, char *argv[]) return 0; } +void +print_header(char *line) { + char *s, *e; + size_t l = strlen(line); + + if (line[l-1] == '\n') + line[l-1] = 0; + + /* iterate word-wise, encode words when needed. */ + + s = line; + e = s; + + if (!(*s == ' ' || *s == '\t')) { + // raw header name + while (*s && *s != ':') + putc_unlocked(*s++, stdout); + if (*s == ':') + putc_unlocked(*s++, stdout); + } + + int prevq = 0; + + int linelen = s - line; + + while (*s) { + size_t highbit = 0; + e = s; + while (*e && *e == ' ') + e++; + for (; *e && *e != ' '; e++) { + if ((uint8_t) *e >= 127) + highbit++; + } + // use qp for lines with high bit, for long lines, or + // for more than two spaces + if (highbit || + e-s > 78-linelen || + (prevq && s[0] == ' ' && s[1] == ' ')) { + if (!prevq && s[0] == ' ') + s++; + + // 13 = strlen(" =?UTF-8?Q??=") + int w; + while (s < e && (w = (78-linelen-13) / (highbit?3:1)) < e-s && w>0) { + printf(" =?UTF-8?Q?"); + gen_qp((uint8_t *)s, w>e-s?e-s:w, 999, 1); + printf("?=\n"); + s += w; + linelen = 0; + } + if (s < e) { + if (linelen + (e-s)+13 > 78) { + printf("\n"); + linelen = 0; + } + printf(" =?UTF-8?Q?"); + linelen += 13; + linelen += gen_qp((uint8_t *)s, e-s, 999, 1); + printf("?="); + } + prevq = 1; + } else { + if (linelen + (e-s) > 78) { + printf("\n"); + if (*s != ' ') + printf(" "); + linelen = 0; + } + fwrite(s, 1, e-s, stdout); + linelen += e-s; + prevq = 0; + } + s = e; + } + printf("\n"); +} + int gen_build() { @@ -210,7 +299,7 @@ gen_build() printf("\n"); printf("This is a multipart message in MIME format.\n\n"); } else { - printf("%s", line); + print_header(line); } continue; } @@ -237,7 +326,7 @@ gen_build() intext = 1; } - gen_qp((uint8_t *)line, strlen(line)); + gen_qp((uint8_t *)line, strlen(line), 78, 0); } printf("--%s--\n", sep); -- cgit 1.4.1