FreeCalypso > hg > falcon-mail-tools
view f-demime/header_end.c @ 8:a92d0d59b669 default tip
f-demime: indicate X-backslash-escapes encoding in output
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 06 May 2023 17:00:23 +0000 |
parents | 1857d0d5a7bd |
children |
line wrap: on
line source
/* * This module implements final processing of message and body part headers, * deciding what to do at the end of each header. */ #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include "defs.h" extern enum msg_state msg_state; extern enum msg_hdr_state hdr_state; extern unsigned mp_nest_level; extern char mp_boundaries[MAX_MP_NESTING][MAX_MP_BOUNDARY+1]; extern int mp_is_digest[MAX_MP_NESTING]; extern char cont_type_buf[HDR_BUF_SIZE], cont_te_buf[HDR_BUF_SIZE]; extern int got_cont_type, got_cont_te; static int is_valid_tchar(ch) { if (ch < '!' || ch > '~') return(0); switch (ch) { case '(': case ')': case '<': case '>': case '@': case ',': case ';': case ':': case '\\': case '"': case '/': case '[': case ']': case '?': case '=': return(0); default: return(1); } } static int gettoken(cpp, tokbuf) char **cpp, *tokbuf; { register char *cp, *dp; register int i; /* skip initial white space and comments */ for (cp = *cpp; ; ) { if (isspace(*cp)) { cp++; continue; } if (*cp != '(') break; for (i = 0; ; ) { if (!*cp) break; if (*cp == '\\') cp++; else if (*cp == '(') i++; else if (*cp == ')') i--; if (*cp) cp++; if (!i) break; } } if (!*cp) { *cpp = cp; return(0); } if (*cp == '/' || *cp == ';' || *cp == '=') { i = *cp++; *cpp = cp; return(i); } if (*cp == '"') { cp++; for (dp = tokbuf; *cp; ) { if (*cp == '"') { cp++; break; } if (cp[0] == '\\' && cp[1]) cp++; *dp++ = *cp++; } *dp = '\0'; *cpp = cp; return(2); } if (!is_valid_tchar(*cp)) { *cpp = cp; return(-1); } for (dp = tokbuf; is_valid_tchar(*cp); ) *dp++ = *cp++; *dp = '\0'; *cpp = cp; return(1); } static int parse_content_type(type, subtype, charset, boundary) char *type, *subtype, *charset, *boundary; { char *ctstr; char tokbuf[HDR_BUF_SIZE], attr[HDR_BUF_SIZE]; int rc; ctstr = index(cont_type_buf, ':') + 1; if (gettoken(&ctstr, type) != 1) return(-1); if (gettoken(&ctstr, tokbuf) != '/') return(-1); if (gettoken(&ctstr, subtype) != 1) return(-1); charset[0] = '\0'; boundary[0] = '\0'; for (;;) { rc = gettoken(&ctstr, tokbuf); if (!rc) return(0); if (rc != ';') return(-1); if (gettoken(&ctstr, attr) != 1) return(-1); if (gettoken(&ctstr, tokbuf) != '=') return(-1); rc = gettoken(&ctstr, tokbuf); if (rc != 1 && rc != 2) return(-1); if (!strcasecmp(attr, "charset")) strcpy(charset, tokbuf); else if (!strcasecmp(attr, "boundary")) strcpy(boundary, tokbuf); } } static int parse_content_te(ctetoken) char *ctetoken; { char *ctestr; char tokbuf[HDR_BUF_SIZE]; ctestr = index(cont_te_buf, ':') + 1; if (gettoken(&ctestr, ctetoken) != 1) return(-1); if (gettoken(&ctestr, tokbuf) == 0) return(0); else return(-1); } static void handle_multipart(cont_subtype, boundary_attr) char *cont_subtype, *boundary_attr; { if (!boundary_attr[0]) { puts("X-Fdemime-Error: multipart without boundary attr"); putchar('\n'); msg_state = MSG_STATE_BODY_PASS; return; } if (index(boundary_attr, '\n')) { puts("X-Fdemime-Error: multipart boundary attr contains newline"); putchar('\n'); msg_state = MSG_STATE_BODY_PASS; return; } if (strlen(boundary_attr) > MAX_MP_BOUNDARY) { puts("X-Fdemime-Error: multipart boundary attr is too long"); putchar('\n'); msg_state = MSG_STATE_BODY_PASS; return; } if (mp_nest_level >= MAX_MP_NESTING) { puts("X-Fdemime-Error: multipart nesting is too deep"); putchar('\n'); msg_state = MSG_STATE_BODY_PASS; return; } putchar('\n'); strcpy(mp_boundaries[mp_nest_level], boundary_attr); mp_is_digest[mp_nest_level] = !strcasecmp(cont_subtype, "digest"); mp_nest_level++; msg_state = MSG_STATE_BODY_PASS; } void process_header_end() { char cont_type[HDR_BUF_SIZE], cont_subtype[HDR_BUF_SIZE]; char charset_attr[HDR_BUF_SIZE], boundary_attr[HDR_BUF_SIZE]; char content_te[HDR_BUF_SIZE]; int in_digest, rc; if (hdr_state == HDR_STATE_ERROR) { if (got_cont_type) fputs(cont_type_buf, stdout); if (got_cont_te) fputs(cont_te_buf, stdout); putchar('\n'); msg_state = MSG_STATE_BODY_PASS; return; } if (mp_nest_level) in_digest = mp_is_digest[mp_nest_level-1]; else in_digest = 0; if (got_cont_type) { fputs(cont_type_buf, stdout); rc = parse_content_type(cont_type, cont_subtype, charset_attr, boundary_attr); if (rc < 0) { puts("X-Fdemime-Error: unable to parse Content-Type"); if (got_cont_te) fputs(cont_te_buf, stdout); putchar('\n'); msg_state = MSG_STATE_BODY_PASS; return; } } else { if (in_digest) { strcpy(cont_type, "message"); strcpy(cont_subtype, "rfc822"); } else { strcpy(cont_type, "text"); strcpy(cont_subtype, "plain"); } charset_attr[0] = '\0'; boundary_attr[0] = '\0'; } if (!strcasecmp(cont_type, "multipart")) { if (got_cont_te) fputs(cont_te_buf, stdout); handle_multipart(cont_subtype, boundary_attr); return; } if (!strcasecmp(cont_type, "message")) { if (got_cont_te) fputs(cont_te_buf, stdout); putchar('\n'); msg_state = MSG_STATE_BODY_PASS; return; } if (got_cont_te) { rc = parse_content_te(content_te); if (rc < 0) { fputs(cont_te_buf, stdout); puts( "X-Fdemime-Error: unable to parse Content-Transfer-Encoding"); putchar('\n'); msg_state = MSG_STATE_BODY_PASS; return; } } else content_te[0] = '\0'; if (!strcasecmp(content_te, "base64")) { if (!strcasecmp(cont_type, "text")) { if (!strcasecmp(cont_subtype, "plain")) init_base64_text_plain(charset_attr); else init_base64_text_other(); } else init_base64_nontext(); return; } if (!strcasecmp(content_te, "quoted-printable") && !strcasecmp(cont_type, "text") && !strcasecmp(cont_subtype, "plain")) { init_qp_text_plain(charset_attr); return; } if (got_cont_te) fputs(cont_te_buf, stdout); putchar('\n'); msg_state = MSG_STATE_BODY_PASS; }