comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:7e0d08176f32
1 /*
2 * This module implements final processing of message and body part headers,
3 * deciding what to do at the end of each header.
4 */
5
6 #include <ctype.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <strings.h>
11 #include "defs.h"
12
13 extern enum msg_state msg_state;
14 extern enum msg_hdr_state hdr_state;
15 extern unsigned mp_nest_level;
16 extern char mp_boundaries[MAX_MP_NESTING][MAX_MP_BOUNDARY+1];
17 extern int mp_is_digest[MAX_MP_NESTING];
18 extern char cont_type_buf[HDR_BUF_SIZE], cont_te_buf[HDR_BUF_SIZE];
19 extern int got_cont_type, got_cont_te;
20
21 static int
22 is_valid_tchar(ch)
23 {
24 if (ch < '!' || ch > '~')
25 return(0);
26 switch (ch) {
27 case '(':
28 case ')':
29 case '<':
30 case '>':
31 case '@':
32 case ',':
33 case ';':
34 case ':':
35 case '\\':
36 case '"':
37 case '/':
38 case '[':
39 case ']':
40 case '?':
41 case '=':
42 return(0);
43 default:
44 return(1);
45 }
46 }
47
48 static int
49 gettoken(cpp, tokbuf)
50 char **cpp, *tokbuf;
51 {
52 register char *cp, *dp;
53 register int i;
54
55 /* skip initial white space and comments */
56 for (cp = *cpp; ; ) {
57 if (isspace(*cp)) {
58 cp++;
59 continue;
60 }
61 if (*cp != '(')
62 break;
63 for (i = 0; ; ) {
64 if (!*cp)
65 break;
66 if (*cp == '\\')
67 cp++;
68 else if (*cp == '(')
69 i++;
70 else if (*cp == ')')
71 i--;
72 if (*cp)
73 cp++;
74 if (!i)
75 break;
76 }
77 }
78 if (!*cp) {
79 *cpp = cp;
80 return(0);
81 }
82 if (*cp == '/' || *cp == ';' || *cp == '=') {
83 i = *cp++;
84 *cpp = cp;
85 return(i);
86 }
87 if (*cp == '"') {
88 cp++;
89 for (dp = tokbuf; *cp; ) {
90 if (*cp == '"') {
91 cp++;
92 break;
93 }
94 if (cp[0] == '\\' && cp[1])
95 cp++;
96 *dp++ = *cp++;
97 }
98 *dp = '\0';
99 *cpp = cp;
100 return(2);
101 }
102 if (!is_valid_tchar(*cp)) {
103 *cpp = cp;
104 return(-1);
105 }
106 for (dp = tokbuf; is_valid_tchar(*cp); )
107 *dp++ = *cp++;
108 *dp = '\0';
109 *cpp = cp;
110 return(1);
111 }
112
113 static int
114 parse_content_type(type, subtype, charset, boundary)
115 char *type, *subtype, *charset, *boundary;
116 {
117 char *ctstr = cont_type_buf;
118 char tokbuf[HDR_BUF_SIZE], attr[HDR_BUF_SIZE];
119 int rc;
120
121 if (gettoken(&ctstr, type) != 1)
122 return(-1);
123 if (gettoken(&ctstr, tokbuf) != '/')
124 return(-1);
125 if (gettoken(&ctstr, subtype) != 1)
126 return(-1);
127 charset[0] = '\0';
128 boundary[0] = '\0';
129 for (;;) {
130 rc = gettoken(&ctstr, tokbuf);
131 if (!rc)
132 return(0);
133 if (rc != ';')
134 return(-1);
135 if (gettoken(&ctstr, attr) != 1)
136 return(-1);
137 if (gettoken(&ctstr, tokbuf) != '=')
138 return(-1);
139 rc = gettoken(&ctstr, tokbuf);
140 if (rc != 1 && rc != 2)
141 return(-1);
142 if (!strcasecmp(attr, "charset"))
143 strcpy(charset, tokbuf);
144 else if (!strcasecmp(attr, "boundary"))
145 strcpy(boundary, tokbuf);
146 }
147 }
148
149 static int
150 parse_content_te(ctetoken)
151 char *ctetoken;
152 {
153 char *ctestr = cont_te_buf;
154 char tokbuf[HDR_BUF_SIZE];
155
156 if (gettoken(&ctestr, ctetoken) != 1)
157 return(-1);
158 if (gettoken(&ctestr, tokbuf) == 0)
159 return(0);
160 else
161 return(-1);
162 }
163
164 static void
165 handle_multipart(cont_subtype, boundary_attr)
166 char *cont_subtype, *boundary_attr;
167 {
168 if (!boundary_attr[0]) {
169 puts("X-Fdemime-Error: multipart without boundary attr");
170 putchar('\n');
171 msg_state = MSG_STATE_BODY_PASS;
172 return;
173 }
174 if (index(boundary_attr, '\n')) {
175 puts("X-Fdemime-Error: multipart boundary attr contains newline");
176 putchar('\n');
177 msg_state = MSG_STATE_BODY_PASS;
178 return;
179 }
180 if (strlen(boundary_attr) > MAX_MP_BOUNDARY) {
181 puts("X-Fdemime-Error: multipart boundary attr is too long");
182 putchar('\n');
183 msg_state = MSG_STATE_BODY_PASS;
184 return;
185 }
186 if (mp_nest_level >= MAX_MP_NESTING) {
187 puts("X-Fdemime-Error: multipart nesting is too deep");
188 putchar('\n');
189 msg_state = MSG_STATE_BODY_PASS;
190 return;
191 }
192 putchar('\n');
193 strcpy(mp_boundaries[mp_nest_level], boundary_attr);
194 mp_is_digest[mp_nest_level] = !strcasecmp(cont_subtype, "digest");
195 mp_nest_level++;
196 msg_state = MSG_STATE_BODY_PASS;
197 }
198
199 void
200 process_header_end()
201 {
202 char cont_type[HDR_BUF_SIZE], cont_subtype[HDR_BUF_SIZE];
203 char charset_attr[HDR_BUF_SIZE], boundary_attr[HDR_BUF_SIZE];
204 char content_te[HDR_BUF_SIZE];
205 int in_digest, rc;
206
207 if (hdr_state == HDR_STATE_ERROR) {
208 if (got_cont_type)
209 fputs(cont_type_buf, stdout);
210 if (got_cont_te)
211 fputs(cont_te_buf, stdout);
212 putchar('\n');
213 msg_state = MSG_STATE_BODY_PASS;
214 return;
215 }
216 if (mp_nest_level)
217 in_digest = mp_is_digest[mp_nest_level-1];
218 else
219 in_digest = 0;
220 if (got_cont_type) {
221 fputs(cont_type_buf, stdout);
222 rc = parse_content_type(cont_type, cont_subtype, charset_attr,
223 boundary_attr);
224 if (rc < 0) {
225 puts("X-Fdemime-Error: unable to parse Content-Type");
226 if (got_cont_te)
227 fputs(cont_te_buf, stdout);
228 putchar('\n');
229 msg_state = MSG_STATE_BODY_PASS;
230 return;
231 }
232 } else {
233 if (in_digest) {
234 strcpy(cont_type, "message");
235 strcpy(cont_subtype, "rfc822");
236 } else {
237 strcpy(cont_type, "text");
238 strcpy(cont_subtype, "plain");
239 }
240 charset_attr[0] = '\0';
241 boundary_attr[0] = '\0';
242 }
243 if (!strcasecmp(cont_type, "multipart")) {
244 if (got_cont_te)
245 fputs(cont_te_buf, stdout);
246 handle_multipart(cont_subtype, boundary_attr);
247 return;
248 }
249 if (!strcasecmp(cont_type, "message")) {
250 if (got_cont_te)
251 fputs(cont_te_buf, stdout);
252 putchar('\n');
253 msg_state = MSG_STATE_BODY_PASS;
254 return;
255 }
256 if (got_cont_te) {
257 rc = parse_content_te(content_te);
258 if (rc < 0) {
259 fputs(cont_te_buf, stdout);
260 puts(
261 "X-Fdemime-Error: unable to parse Content-Transfer-Encoding");
262 putchar('\n');
263 msg_state = MSG_STATE_BODY_PASS;
264 return;
265 }
266 } else
267 content_te[0] = '\0';
268 if (!strcasecmp(content_te, "base64")) {
269 if (!strcasecmp(cont_type, "text")) {
270 if (!strcasecmp(cont_subtype, "plain"))
271 init_base64_text_plain(charset_attr);
272 else
273 init_base64_text_other();
274 } else
275 init_base64_nontext();
276 return;
277 }
278 if (!strcasecmp(content_te, "quoted-printable") &&
279 !strcasecmp(cont_type, "text") &&
280 !strcasecmp(cont_subtype, "plain")) {
281 init_qp_text_plain(charset_attr);
282 return;
283 }
284 if (got_cont_te)
285 fputs(cont_te_buf, stdout);
286 putchar('\n');
287 msg_state = MSG_STATE_BODY_PASS;
288 }