X-Git-Url: https://git.distorted.org.uk/~mdw/disorder/blobdiff_plain/bb6ae3fb80fff36cd342d6f6bff3dfabd7dd243e..f902253a124bd45a5011204ea4f9e6226b12d561:/lib/mime.c?ds=sidebyside diff --git a/lib/mime.c b/lib/mime.c index 422e1f5..0e7d097 100644 --- a/lib/mime.c +++ b/lib/mime.c @@ -35,6 +35,7 @@ #include "hex.h" #include "log.h" #include "base64.h" +#include "kvp.h" /** @brief Match whitespace characters */ static int whitespace(int c) { @@ -73,7 +74,7 @@ static int tspecial(int c) { } } -/** @brief Match RFC2616 seprator characters */ +/** @brief Match RFC2616 separator characters */ static int http_separator(int c) { switch(c) { case '(': @@ -133,12 +134,14 @@ static const char *skipwhite(const char *s, int rfc822_comments) { case '(': ++depth; break; case ')': --depth; break; case '\\': - if(!*s) return 0; + if(!*s) + return 0; ++s; break; } } - if(depth) return 0; + if(depth) + return 0; break; default: return s; @@ -174,13 +177,15 @@ static const char *parseword(const char *s, char **valuep, while((c = *s++) != '"') { switch(c) { case '\\': - if(!(c = *s++)) return 0; + if(!(c = *s++)) + return 0; default: dynstr_append(value, c); break; } } - if(!c) return 0; + if(!c) + return 0; } else { if(!iswordchar((unsigned char)*s, special)) return NULL; @@ -201,56 +206,70 @@ static const char *parseword(const char *s, char **valuep, */ static const char *parsetoken(const char *s, char **valuep, int (*special)(int)) { - if(*s == '"') return 0; + if(*s == '"') + return 0; return parseword(s, valuep, special); } /** @brief Parse a MIME content-type field * @param s Start of field * @param typep Where to store type - * @param parameternamep Where to store parameter name - * @param parametervaluep Wher to store parameter value + * @param parametersp Where to store parameter list * @return 0 on success, non-0 on error * * See RFC 2045 s5. */ int mime_content_type(const char *s, char **typep, - char **parameternamep, - char **parametervaluep) { + struct kvp **parametersp) { struct dynstr type, parametername; + struct kvp *parameters = 0; + char *parametervalue; dynstr_init(&type); - if(!(s = skipwhite(s, 1))) return -1; - if(!*s) return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(!*s) + return -1; while(*s && !tspecial(*s) && !whitespace(*s)) dynstr_append(&type, tolower((unsigned char)*s++)); - if(!(s = skipwhite(s, 1))) return -1; - if(*s++ != '/') return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(*s++ != '/') + return -1; dynstr_append(&type, '/'); - if(!(s = skipwhite(s, 1))) return -1; + if(!(s = skipwhite(s, 1))) + return -1; while(*s && !tspecial(*s) && !whitespace(*s)) dynstr_append(&type, tolower((unsigned char)*s++)); - if(!(s = skipwhite(s, 1))) return -1; + if(!(s = skipwhite(s, 1))) + return -1; - if(*s == ';') { + while(*s == ';') { dynstr_init(¶metername); ++s; - if(!(s = skipwhite(s, 1))) return -1; - if(!*s) return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(!*s) + return -1; while(*s && !tspecial(*s) && !whitespace(*s)) dynstr_append(¶metername, tolower((unsigned char)*s++)); - if(!(s = skipwhite(s, 1))) return -1; - if(*s++ != '=') return -1; - if(!(s = skipwhite(s, 1))) return -1; - if(!(s = parseword(s, parametervaluep, tspecial))) return -1; - if(!(s = skipwhite(s, 1))) return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(*s++ != '=') + return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(!(s = parseword(s, ¶metervalue, tspecial))) + return -1; + if(!(s = skipwhite(s, 1))) + return -1; dynstr_terminate(¶metername); - *parameternamep = parametername.vec; - } else - *parametervaluep = *parameternamep = 0; + kvp_set(¶meters, parametername.vec, parametervalue); + } dynstr_terminate(&type); *typep = type.vec; + *parametersp = parameters; return 0; } @@ -277,12 +296,25 @@ const char *mime_parse(const char *s, dynstr_init(&value); while(*s && !tspecial(*s) && !whitespace(*s)) dynstr_append(&name, tolower((unsigned char)*s++)); - if(!(s = skipwhite(s, 1))) return 0; - if(*s != ':') return 0; + if(!(s = skipwhite(s, 1))) + return 0; + if(*s != ':') + return 0; ++s; - while(*s && !(*s == '\n' && !(s[1] == ' ' || s[1] == '\t'))) - dynstr_append(&value, *s++); - if(*s) ++s; + while(*s && !(*s == '\n' && !(s[1] == ' ' || s[1] == '\t'))) { + const int c = *s++; + /* Strip leading whitespace */ + if(value.nvec || !(c == ' ' || c == '\t' || c == '\n' || c == '\r')) + dynstr_append(&value, c); + } + /* Strip trailing whitespace */ + while(value.nvec > 0 && (value.vec[value.nvec - 1] == ' ' + || value.vec[value.nvec - 1] == '\t' + || value.vec[value.nvec - 1] == '\n' + || value.vec[value.nvec - 1] == '\r')) + --value.nvec; + if(*s) + ++s; dynstr_terminate(&name); dynstr_terminate(&value); if(!strcmp(name.vec, "content-transfer-encoding")) { @@ -290,12 +322,20 @@ const char *mime_parse(const char *s, for(p = cte; *p; p++) *p = tolower((unsigned char)*p); } - if(callback(name.vec, value.vec, u)) return 0; + if(callback(name.vec, value.vec, u)) + return 0; } - if(*s) s += 2; + if(*s) + s += 2; if(cte) { - if(!strcmp(cte, "base64")) return mime_base64(s, 0); - if(!strcmp(cte, "quoted-printable")) return mime_qp(s); + if(!strcmp(cte, "base64")) + return mime_base64(s, 0); + if(!strcmp(cte, "quoted-printable")) + return mime_qp(s); + if(!strcmp(cte, "7bit") || !strcmp(cte, "8bit")) + return s; + error(0, "unknown content-transfer-encoding '%s'", cte); + return 0; } return s; } @@ -377,24 +417,34 @@ int mime_rfc2388_content_disposition(const char *s, struct dynstr disposition, parametername; dynstr_init(&disposition); - if(!(s = skipwhite(s, 1))) return -1; - if(!*s) return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(!*s) + return -1; while(*s && !tspecial(*s) && !whitespace(*s)) dynstr_append(&disposition, tolower((unsigned char)*s++)); - if(!(s = skipwhite(s, 1))) return -1; + if(!(s = skipwhite(s, 1))) + return -1; if(*s == ';') { dynstr_init(¶metername); ++s; - if(!(s = skipwhite(s, 1))) return -1; - if(!*s) return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(!*s) + return -1; while(*s && !tspecial(*s) && !whitespace(*s)) dynstr_append(¶metername, tolower((unsigned char)*s++)); - if(!(s = skipwhite(s, 1))) return -1; - if(*s++ != '=') return -1; - if(!(s = skipwhite(s, 1))) return -1; - if(!(s = parseword(s, parametervaluep, tspecial))) return -1; - if(!(s = skipwhite(s, 1))) return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(*s++ != '=') + return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(!(s = parseword(s, parametervaluep, tspecial))) + return -1; + if(!(s = skipwhite(s, 1))) + return -1; dynstr_terminate(¶metername); *parameternamep = parametername.vec; } else @@ -473,11 +523,14 @@ int parse_cookie(const char *s, s = skipwhite(s, 0); continue; } - if(!(s = parsetoken(s, &n, http_separator))) return -1; + if(!(s = parsetoken(s, &n, http_separator))) + return -1; s = skipwhite(s, 0); - if(*s++ != '=') return -1; + if(*s++ != '=') + return -1; s = skipwhite(s, 0); - if(!(s = parseword(s, &v, http_separator))) return -1; + if(!(s = parseword(s, &v, http_separator))) + return -1; if(n[0] == '$') { /* Some bit of meta-information */ if(!strcmp(n, "$Version"))