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;
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;
*/
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);
}
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;
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, ¶metervalue, 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);
kvp_set(¶meters, parametername.vec, parametervalue);
}
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")) {
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;
}
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
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"))
return 0;
}
+static int header_callback(const char *name, const char *value,
+ void *u) {
+ hash *const h = u;
+
+ hash_add(h, name, &value, HASH_INSERT);
+ return 0;
+}
+
void test_mime(void) {
char *t, *n, *v;
struct vector parts[1];
struct kvp *k;
+ const char *s;
+ hash *h;
fprintf(stderr, "test_mime\n");
/* Not actually valid base64 */
check_string(mime_base64("BBBBx=", 0),
"\x04\x10\x41");
+
+ h = hash_new(sizeof (char *));
+ s = mime_parse("From: sender@example.com\r\n"
+ "To: rcpt@example.com\r\n"
+ "Subject: test #1\r\n"
+ "\r\n"
+ "body\r\n",
+ header_callback, h);
+ insist(s != 0);
+ check_string(*(char **)hash_find(h, "from"), "sender@example.com");
+ check_string(*(char **)hash_find(h, "to"), "rcpt@example.com");
+ check_string(*(char **)hash_find(h, "subject"), "test #1");
+ check_string(s, "body\r\n");
+
+ h = hash_new(sizeof (char *));
+ s = mime_parse("FROM: sender@example.com\r\n"
+ "TO: rcpt@example.com\r\n"
+ "SUBJECT: test #1\r\n"
+ "CONTENT-TRANSFER-ENCODING: 7bit\r\n"
+ "\r\n"
+ "body\r\n",
+ header_callback, h);
+ insist(s != 0);
+ check_string(*(char **)hash_find(h, "from"), "sender@example.com");
+ check_string(*(char **)hash_find(h, "to"), "rcpt@example.com");
+ check_string(*(char **)hash_find(h, "subject"), "test #1");
+ check_string(*(char **)hash_find(h, "content-transfer-encoding"), "7bit");
+ check_string(s, "body\r\n");
+
+ h = hash_new(sizeof (char *));
+ s = mime_parse("From: sender@example.com\r\n"
+ "To: \r\n"
+ " rcpt@example.com\r\n"
+ "Subject: test #1\r\n"
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: text/plain\r\n"
+ "Content-Transfer-Encoding: BASE64\r\n"
+ "\r\n"
+ "d2liYmxlDQo=\r\n",
+ header_callback, h);
+ insist(s != 0);
+ check_string(*(char **)hash_find(h, "from"), "sender@example.com");
+ check_string(*(char **)hash_find(h, "to"), "rcpt@example.com");
+ check_string(*(char **)hash_find(h, "subject"), "test #1");
+ check_string(*(char **)hash_find(h, "mime-version"), "1.0");
+ check_string(*(char **)hash_find(h, "content-type"), "text/plain");
+ check_string(*(char **)hash_find(h, "content-transfer-encoding"), "BASE64");
+ check_string(s, "wibble\r\n");
}
/*