X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/71b70599a2cd81c13cc4326499a5d0c45358cd7d..62ef2216d2c7c1c563ea163e2a0fdacccb54e31e:/lib/mime.c diff --git a/lib/mime.c b/lib/mime.c index 5562c7e..7ba4254 100644 --- a/lib/mime.c +++ b/lib/mime.c @@ -34,6 +34,7 @@ #include "vector.h" #include "hex.h" #include "log.h" +#include "base64.h" /** @brief Match whitespace characters */ static int whitespace(int c) { @@ -72,7 +73,7 @@ static int tspecial(int c) { } } -/** @brief Mathc RFC2616 seprator characters */ +/** @brief Match RFC2616 seprator characters */ static int http_separator(int c) { switch(c) { case '(': @@ -106,7 +107,9 @@ static int iscrlf(const char *ptr) { } /** @brief Skip whitespace + * @param s Pointer into string * @param rfc822_comments If true, skip RFC822 nested comments + * @return Pointer into string after whitespace */ static const char *skipwhite(const char *s, int rfc822_comments) { int c, depth; @@ -206,8 +209,10 @@ static const char *parsetoken(const char *s, char **valuep, * @param s Start of field * @param typep Where to store type * @param parameternamep Where to store parameter name - * @param parameternvaluep Wher to store parameter value + * @param parametervaluep Wher to store parameter value * @return 0 on success, non-0 on error + * + * See RFC 2045 s5. */ int mime_content_type(const char *s, char **typep, @@ -253,7 +258,12 @@ int mime_content_type(const char *s, * @param s Start of message * @param callback Called for each header field * @param u Passed to callback - * @return Pointer to decoded body (might be in original string) + * @return Pointer to decoded body (might be in original string), or NULL on error + * + * This does an RFC 822-style parse and honors Content-Transfer-Encoding as + * described in RFC 2045 + * s6. @p callback is called for each header field encountered, in order, + * with ASCII characters in the header name forced to lower case. */ const char *mime_parse(const char *s, int (*callback)(const char *name, const char *value, @@ -284,12 +294,13 @@ 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; } +/** @brief Match the boundary string */ static int isboundary(const char *ptr, const char *boundary, size_t bl) { return (ptr[0] == '-' && ptr[1] == '-' @@ -300,6 +311,7 @@ static int isboundary(const char *ptr, const char *boundary, size_t bl) { && (iscrlf(ptr + bl + 4) || *(ptr + bl + 4) == 0)))); } +/** @brief Match the final boundary string */ static int isfinal(const char *ptr, const char *boundary, size_t bl) { return (ptr[0] == '-' && ptr[1] == '-' @@ -311,10 +323,14 @@ static int isfinal(const char *ptr, const char *boundary, size_t bl) { /** @brief Parse a multipart MIME body * @param s Start of message - * @param callback CAllback for each part + * @param callback Callback for each part * @param boundary Boundary string * @param u Passed to callback * @return 0 on success, non-0 on error + * + * See RFC 2046 + * s5.1. @p callback is called for each part (not yet decoded in any way) + * in succession; you should probably call mime_parse() for each part. */ int mime_multipart(const char *s, int (*callback)(const char *s, void *u), @@ -346,10 +362,13 @@ int mime_multipart(const char *s, /** @brief Parse an RFC2388-style content-disposition field * @param s Start of field - * @param typep Where to store type + * @param dispositionp Where to store disposition * @param parameternamep Where to store parameter name - * @param parameternvaluep Wher to store parameter value + * @param parametervaluep Wher to store parameter value * @return 0 on success, non-0 on error + * + * See RFC 2388 s3 + * and RFC 2183. */ int mime_rfc2388_content_disposition(const char *s, char **dispositionp, @@ -388,6 +407,9 @@ int mime_rfc2388_content_disposition(const char *s, /** @brief Convert MIME quoted-printable * @param s Quoted-printable data * @return Decoded data + * + * See RFC 2045 + * s6.7. */ char *mime_qp(const char *s) { struct dynstr d; @@ -431,41 +453,6 @@ char *mime_qp(const char *s) { return d.vec; } -/** @brief Convert MIME base64 - * @param s base64 data - * @return Decoded data - */ -char *mime_base64(const char *s) { - 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(n == 4) { - dynstr_append(&d, (b[0] << 2) + (b[1] >> 4)); - dynstr_append(&d, (b[1] << 4) + (b[2] >> 2)); - dynstr_append(&d, (b[2] << 6) + b[3]); - n = 0; - } - } else if(c == '=') { - if(n >= 2) { - dynstr_append(&d, (b[0] << 2) + (b[1] >> 4)); - if(n == 3) - dynstr_append(&d, (b[1] << 4) + (b[2] >> 2)); - } - break; - } - } - dynstr_terminate(&d); - return d.vec; -} - /** @brief Parse a RFC2109 Cookie: header * @param s Header field value * @param cd Where to store result