FreeCalypso > hg > falcon-mail-tools
diff f-demime/header_end.c @ 0:7e0d08176f32
f-demime starting code
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 06 May 2023 06:14:03 +0000 |
parents | |
children | 1857d0d5a7bd |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/f-demime/header_end.c Sat May 06 06:14:03 2023 +0000 @@ -0,0 +1,288 @@ +/* + * 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 = cont_type_buf; + char tokbuf[HDR_BUF_SIZE], attr[HDR_BUF_SIZE]; + int rc; + + 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 = cont_te_buf; + char tokbuf[HDR_BUF_SIZE]; + + 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; +}