X-Git-Url: https://git.distorted.org.uk/~mdw/disorder/blobdiff_plain/39d4aa6b1c612305bf06760529e2a1532b9818a5..ba39faf632da43d64106536f256153c2092346e4:/lib/mime.c diff --git a/lib/mime.c b/lib/mime.c index c8ffe31..f7de533 100644 --- a/lib/mime.c +++ b/lib/mime.c @@ -27,6 +27,8 @@ #include #include +#include + #include "mem.h" #include "mime.h" #include "vector.h" @@ -282,7 +284,7 @@ const char *mime_parse(const char *s, } if(*s) s += 2; if(cte) { - if(!strcmp(cte, "base64")) return mime_base64(s); + if(!strcmp(cte, "base64")) return mime_base64(s, 0); if(!strcmp(cte, "quoted-printable")) return mime_qp(s); } return s; @@ -295,7 +297,7 @@ static int isboundary(const char *ptr, const char *boundary, size_t bl) { && (iscrlf(ptr + bl + 2) || (ptr[bl + 2] == '-' && ptr[bl + 3] == '-' - && iscrlf(ptr + bl + 4)))); + && (iscrlf(ptr + bl + 4) || *(ptr + bl + 4) == 0)))); } static int isfinal(const char *ptr, const char *boundary, size_t bl) { @@ -304,7 +306,7 @@ static int isfinal(const char *ptr, const char *boundary, size_t bl) { && !strncmp(ptr + 2, boundary, bl) && ptr[bl + 2] == '-' && ptr[bl + 3] == '-' - && iscrlf(ptr + bl + 4)); + && (iscrlf(ptr + bl + 4) || *(ptr + bl + 4) == 0)); } /** @brief Parse a multipart MIME body @@ -322,12 +324,16 @@ int mime_multipart(const char *s, const char *start, *e; int ret; - if(!isboundary(s, boundary, bl)) return -1; + /* We must start with a boundary string */ + if(!isboundary(s, boundary, bl)) + return -1; + /* Keep going until we hit a final boundary */ while(!isfinal(s, boundary, bl)) { s = strstr(s, "\r\n") + 2; start = s; while(!isboundary(s, boundary, bl)) { - if(!(e = strstr(s, "\r\n"))) return -1; + if(!(e = strstr(s, "\r\n"))) + return -1; s = e + 2; } if((ret = callback(xstrndup(start, @@ -425,22 +431,23 @@ char *mime_qp(const char *s) { return d.vec; } +static const char mime_base64_table[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + /** @brief Convert MIME base64 * @param s base64 data * @return Decoded data */ -char *mime_base64(const char *s) { +char *mime_base64(const char *s, size_t *nsp) { struct dynstr d; const char *t; int b[4], n, c; - static const char table[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; dynstr_init(&d); n = 0; while((c = (unsigned char)*s++)) { - if((t = strchr(table, c))) { - b[n++] = t - table; + if((t = strchr(mime_base64_table, c))) { + b[n++] = t - mime_base64_table; if(n == 4) { dynstr_append(&d, (b[0] << 2) + (b[1] >> 4)); dynstr_append(&d, (b[1] << 4) + (b[2] >> 2)); @@ -456,10 +463,55 @@ char *mime_base64(const char *s) { break; } } + if(nsp) + *nsp = d.nvec; dynstr_terminate(&d); return d.vec; } +/** @brief Convert a binary string to base64 + * @param s Bytes to convert + * @param ns Number of bytes to convert + * @return Encoded data + * + * This function does not attempt to split up lines. + */ +char *mime_to_base64(const uint8_t *s, size_t ns) { + struct dynstr d[1]; + + dynstr_init(d); + while(ns >= 3) { + /* Input bytes with output bits: AAAAAABB BBBBCCCC CCDDDDDD */ + /* Output bytes with input bits: 000000 001111 111122 222222 */ + dynstr_append(d, mime_base64_table[s[0] >> 2]); + dynstr_append(d, mime_base64_table[((s[0] & 3) << 4) + + (s[1] >> 4)]); + dynstr_append(d, mime_base64_table[((s[1] & 15) << 2) + + (s[2] >> 6)]); + dynstr_append(d, mime_base64_table[s[2] & 63]); + ns -= 3; + s += 3; + } + if(ns > 0) { + dynstr_append(d, mime_base64_table[s[0] >> 2]); + switch(ns) { + case 1: + dynstr_append(d, mime_base64_table[(s[0] & 3) << 4]); + dynstr_append(d, '='); + dynstr_append(d, '='); + break; + case 2: + dynstr_append(d, mime_base64_table[((s[0] & 3) << 4) + + (s[1] >> 4)]); + dynstr_append(d, mime_base64_table[(s[1] & 15) << 2]); + dynstr_append(d, '='); + break; + } + } + dynstr_terminate(d); + return d->vec; +} + /** @brief Parse a RFC2109 Cookie: header * @param s Header field value * @param cd Where to store result