254 #ifdef STRCASECMP_IN_STRINGS_H
290 #define MIME_MAX_TOKEN 3
328 #define MIME_CTYPE_OTHER 0
329 #define MIME_CTYPE_TEXT 1
330 #define MIME_CTYPE_MESSAGE 2
331 #define MIME_CTYPE_MULTIPART 3
333 #define MIME_STYPE_OTHER 0
334 #define MIME_STYPE_PLAIN 1
335 #define MIME_STYPE_RFC822 2
336 #define MIME_STYPE_PARTIAL 3
337 #define MIME_STYPE_EXTERN_BODY 4
338 #define MIME_STYPE_GLOBAL 5
343 #define MIME_STATE_PRIMARY MIME_HDR_PRIMARY
344 #define MIME_STATE_MULTIPART MIME_HDR_MULTIPART
345 #define MIME_STATE_NESTED MIME_HDR_NESTED
346 #define MIME_STATE_BODY (MIME_HDR_NESTED + 1)
348 #define SET_MIME_STATE(ptr, state, ctype, stype, encoding, domain) do { \
349 (ptr)->curr_state = (state); \
350 (ptr)->curr_ctype = (ctype); \
351 (ptr)->curr_stype = (stype); \
352 (ptr)->curr_encoding = (encoding); \
353 (ptr)->curr_domain = (domain); \
354 if ((state) == MIME_STATE_BODY) \
355 (ptr)->body_offset = 0; \
357 (ptr)->head_offset = 0; \
360 #define SET_CURR_STATE(ptr, state) do { \
361 (ptr)->curr_state = (state); \
362 if ((state) == MIME_STATE_BODY) \
363 (ptr)->body_offset = 0; \
365 (ptr)->head_offset = 0; \
380 #define MIME_ENC_QP 1
381 #define MIME_ENC_BASE64 2
383 #ifndef MIME_ENC_7BIT
384 #define MIME_ENC_7BIT 7
385 #define MIME_ENC_8BIT 8
386 #define MIME_ENC_BINARY 9
401 #define STR(x) vstring_str(x)
402 #define LEN(x) VSTRING_LEN(x)
403 #define END(x) vstring_end(x)
404 #define CU_CHAR_PTR(x) ((const unsigned char *) (x))
406 #define REPORT_ERROR_LEN(state, err_type, text, len) do { \
407 if ((state->err_flags & err_type) == 0) { \
408 if (state->err_print != 0) \
409 state->err_print(state->app_context, err_type, text, len); \
410 state->err_flags |= err_type; \
414 #define REPORT_ERROR(state, err_type, text) do { \
415 const char *_text = text; \
416 ssize_t _len = strlen(text); \
417 REPORT_ERROR_LEN(state, err_type, _text, _len); \
420 #define REPORT_ERROR_BUF(state, err_type, buf) \
421 REPORT_ERROR_LEN(state, err_type, STR(buf), LEN(buf))
428 #define HEAD_OUT(ptr, info, len) do { \
429 if ((ptr)->head_out) { \
430 (ptr)->head_out((ptr)->app_context, (ptr)->curr_state, \
431 (info), (ptr)->output_buffer, (ptr)->head_offset); \
432 (ptr)->head_offset += (len) + 1; \
436 #define BODY_OUT(ptr, rec_type, text, len) do { \
437 if ((ptr)->body_out) { \
438 (ptr)->body_out((ptr)->app_context, (rec_type), \
439 (text), (len), (ptr)->body_offset); \
440 (ptr)->body_offset += (len) + 1; \
446 static void mime_state_push(
MIME_STATE *state,
int def_ctype,
int def_stype,
447 const char *boundary)
470 state->
stack = stack;
481 if ((stack = state->
stack) == 0)
482 msg_panic(
"mime_state_pop: there is no stack");
534 mime_state_pop(state);
543 static void mime_state_content_type(
MIME_STATE *state,
551 #define TOKEN_MATCH(tok, text) \
552 ((tok).type == HEADER_TOK_TOKEN && strcasecmp((tok).u.value, (text)) == 0)
554 #define RFC2045_TSPECIALS "()<>@,;:\\\"/[]?="
556 #define PARSE_CONTENT_TYPE_HEADER(state, ptr) \
557 header_token(state->token, MIME_MAX_TOKEN, \
558 state->token_buffer, ptr, RFC2045_TSPECIALS, ';')
636 mime_state_push(state, def_ctype, def_stype,
656 static void mime_state_content_encoding(
MIME_STATE *state,
662 #define PARSE_CONTENT_ENCODING_HEADER(state, ptr) \
663 header_token(state->token, 1, state->token_buffer, ptr, (char *) 0, 0)
673 for (cmp = mime_encoding_map; cmp->
name != 0; cmp++) {
685 static const char *mime_state_enc_name(
int encoding)
689 for (cmp = mime_encoding_map; cmp->
name != 0; cmp++)
697 static void mime_state_downgrade(
MIME_STATE *state,
int rec_type,
698 const char *text, ssize_t len)
700 static char hexchars[] =
"0123456789ABCDEF";
701 const unsigned char *cp;
704 #define QP_ENCODE(buffer, ch) { \
705 VSTRING_ADDCH(buffer, '='); \
706 VSTRING_ADDCH(buffer, hexchars[(ch >> 4) & 0xff]); \
707 VSTRING_ADDCH(buffer, hexchars[ch & 0xf]); \
726 if ((ch < 32 && ch !=
'\t') || ch ==
'=' || ch > 126) {
756 const char *text, ssize_t len)
762 const unsigned char *cp;
764 #define SAVE_PREV_REC_TYPE_AND_RETURN_ERR_FLAGS(state, rec_type) do { \
765 state->prev_rec_type = rec_type; \
766 return (state->err_flags); \
833 && header_info != 0) {
835 mime_state_content_type(state, header_info);
837 mime_state_content_encoding(state, header_info);
877 for (text += header_len, len -= header_len;
909 "Content-Transfer-Encoding: %s", cp);
1030 && (strncmp(text + (*text ==
'>'),
"From ", 5) == 0
1031 || strncmp(text,
"=46rom ", 7) == 0))
1074 if (input_is_text) {
1086 && len > 2 && text[0] ==
'-' && text[1] ==
'-') {
1087 for (sp = state->
stack; sp != 0; sp = sp->
next) {
1090 while (sp != state->
stack)
1091 mime_state_pop(state);
1093 strncmp(text + 2 + sp->
bound_len,
"--", 2) == 0) {
1094 mime_state_pop(state);
1110 mime_state_downgrade(state, rec_type, text, len);
1112 BODY_OUT(state, rec_type, text, len);
1153 if (error_code == 0)
1154 msg_panic(
"mime_state_error: there is no error");
1155 for (mp = mime_err_detail; mp->
code; mp++)
1156 if (mp->
code & error_code)
1158 msg_panic(
"mime_state_error: unknown error code %d", error_code);
1167 if (error_code == 0)
1168 msg_panic(
"mime_state_detail: there is no error");
1169 for (mp = mime_err_detail; mp->
code; mp++)
1170 if (mp->
code & error_code)
1172 msg_panic(
"mime_state_detail: unknown error code %d", error_code);
1189 #define REC_LEN 1024
1191 static void head_out(
void *context,
int class,
const HEADER_OPTS *unused_info,
1200 "ERROR", (
long) offset,
STR(buf));
1203 static void head_end(
void *context)
1210 static void body_out(
void *context,
int rec_type,
const char *buf, ssize_t len,
1221 static void body_end(
void *context)
1228 static void err_print(
void *unused_context,
int err_flag,
1229 const char *text, ssize_t len)
1232 len < 100 ? (
int) len : 100, text);
1240 int main(
int unused_argc,
char **argv)
1251 #define MIME_OPTIONS \
1252 (MIME_OPT_REPORT_8BIT_IN_7BIT_BODY \
1253 | MIME_OPT_REPORT_8BIT_IN_HEADER \
1254 | MIME_OPT_REPORT_ENCODING_DOMAIN \
1255 | MIME_OPT_REPORT_TRUNC_HEADER \
1256 | MIME_OPT_REPORT_NESTING \
1257 | MIME_OPT_DOWNGRADE)
1276 }
while (rec_type > 0);
1282 msg_warn(
"message header length exceeds safety limit");
1284 msg_warn(
"MIME nesting exceeds safety limit");
1286 msg_warn(
"improper use of 8-bit data in message header");
1288 msg_warn(
"improper use of 8-bit data in message body");
1290 msg_warn(
"improper message/* or multipart/* encoding domain");
#define MIME_CTYPE_MESSAGE
#define MIME_STYPE_GLOBAL
#define MIME_STYPE_RFC822
MIME_STATE * mime_state_alloc(int flags, MIME_STATE_HEAD_OUT head_out, MIME_STATE_ANY_END head_end, MIME_STATE_BODY_OUT body_out, MIME_STATE_ANY_END body_end, MIME_STATE_ERR_PRINT err_print, void *context)
NORETURN msg_panic(const char *fmt,...)
#define MIME_ERR_ENCODING_DOMAIN
#define REPORT_ERROR(state, err_type, text)
int main(int argc, char **argv)
#define MIME_HDR_MULTIPART
VSTRING * vstring_strncat(VSTRING *vp, const char *src, ssize_t len)
#define MIME_OPT_REPORT_ENCODING_DOMAIN
VSTRING * vstring_truncate(VSTRING *vp, ssize_t len)
#define REPORT_ERROR_BUF(state, err_type, buf)
#define SAVE_PREV_REC_TYPE_AND_RETURN_ERR_FLAGS(state, rec_type)
#define MIME_OPT_REPORT_8BIT_IN_HEADER
#define MIME_ERR_8BIT_IN_HEADER
int rec_streamlf_get(VSTREAM *stream, VSTRING *buf, int maxlen)
#define MIME_OPT_DISABLE_MIME
#define VSTRING_TERMINATE(vp)
#define MIME_OPT_REPORT_8BIT_IN_7BIT_BODY
#define SET_CURR_STATE(ptr, state)
MIME_STATE_BODY_OUT body_out
#define VSTRING_ADDCH(vp, ch)
#define TOKEN_MATCH(tok, text)
void(* MIME_STATE_BODY_OUT)(void *, int, const char *, ssize_t, off_t)
#define QP_ENCODE(buffer, ch)
MIME_STATE_ANY_END head_end
int mime_state_update(MIME_STATE *state, int rec_type, const char *text, ssize_t len)
#define MIME_CTYPE_MULTIPART
VSTREAM * vstream_fprintf(VSTREAM *stream, const char *fmt,...)
MIME_STATE * mime_state_free(MIME_STATE *state)
#define MIME_ERR_TRUNC_HEADER
#define REPORT_ERROR_LEN(state, err_type, text, len)
void(* MIME_STATE_ANY_END)(void *)
void(* MIME_STATE_HEAD_OUT)(void *, int, const HEADER_OPTS *, VSTRING *, off_t)
#define VSTRING_RESET(vp)
#define MIME_STATE_MULTIPART
void msg_warn(const char *fmt,...)
VSTRING * vstring_alloc(ssize_t len)
#define MIME_OPT_REPORT_TRUNC_HEADER
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
const MIME_STATE_DETAIL * mime_state_detail(int error_code)
#define MIME_ERR_8BIT_IN_7BIT_BODY
HEADER_TOKEN token[MIME_MAX_TOKEN]
#define MIME_STYPE_EXTERN_BODY
const char * mime_state_error(int error_code)
int vstream_fflush(VSTREAM *stream)
char * mystrndup(const char *str, ssize_t len)
MIME_STATE_HEAD_OUT head_out
#define MIME_STATE_PRIMARY
#define PARSE_CONTENT_ENCODING_HEADER(state, ptr)
#define vstream_fwrite(v, b, n)
#define MIME_STYPE_PARTIAL
#define MIME_OPT_DOWNGRADE
#define MIME_STATE_NESTED
int strcasecmp(const char *s1, const char *s2)
void(* MIME_STATE_ERR_PRINT)(void *, int, const char *, ssize_t)
VSTRING * vstring_free(VSTRING *vp)
void msg_vstream_init(const char *name, VSTREAM *vp)
MIME_STATE_ERR_PRINT err_print
#define VSTREAM_PUTC(ch, vp)
#define BODY_OUT(ptr, rec_type, text, len)
#define MIME_OPT_REPORT_NESTING
struct MIME_STACK MIME_STACK
#define HEAD_OUT(ptr, info, len)
VSTRING * vstring_strncpy(VSTRING *vp, const char *src, ssize_t len)
#define PARSE_CONTENT_TYPE_HEADER(state, ptr)
VSTRING * vstring_strcat(VSTRING *vp, const char *src)
#define SET_MIME_STATE(ptr, state, ctype, stype, encoding, domain)
struct MIME_ENCODING MIME_ENCODING
void * mymalloc(ssize_t len)
MIME_STATE_ANY_END body_end
void msg_info(const char *fmt,...)