]> diplodocus.org Git - nmh/blob - uip/mhoutsbr.c
Convert the MIME content cache switches over to the smatch() New World Order.
[nmh] / uip / mhoutsbr.c
1
2 /*
3 * mhoutsbr.c -- routines to output MIME messages
4 * -- given a Content structure
5 *
6 * This code is Copyright (c) 2002, by the authors of nmh. See the
7 * COPYRIGHT file in the root directory of the nmh distribution for
8 * complete copyright information.
9 */
10
11 #include <h/mh.h>
12 #include <fcntl.h>
13 #include <h/signals.h>
14 #include <h/md5.h>
15 #include <errno.h>
16 #include <signal.h>
17 #include <h/mts.h>
18 #include <h/tws.h>
19 #include <h/mime.h>
20 #include <h/mhparse.h>
21
22
23 /*
24 * prototypes
25 */
26 int output_message (CT, char *);
27 int output_message_fp (CT, FILE *, char *);
28
29 /*
30 * static prototypes
31 */
32 static int output_content (CT, FILE *);
33 static void output_headers (CT, FILE *);
34 static int writeExternalBody (CT, FILE *);
35 static int write8Bit (CT, FILE *);
36 static int writeQuoted (CT, FILE *);
37 static int writeBase64ct (CT, FILE *);
38
39
40 /*
41 * Main routine to output a MIME message contained
42 * in a Content structure, to a file. Any necessary
43 * transfer encoding is added.
44 */
45
46 int
47 output_message_fp (CT ct, FILE *fp, char *file)
48 {
49 if (output_content (ct, fp) == NOTOK)
50 return NOTOK;
51
52 if (fflush (fp)) {
53 advise ((file?file:"<FILE*>"), "error writing to");
54 return NOTOK;
55 }
56 return OK;
57 }
58
59 int
60 output_message (CT ct, char *file)
61 {
62 FILE *fp;
63 int status;
64
65 if ((fp = fopen (file, "w")) == NULL) {
66 advise (file, "unable to open for writing");
67 return NOTOK;
68 }
69 status = output_message_fp(ct, fp, file);
70 fclose(fp);
71 return status;
72 }
73
74
75 /*
76 * Output a Content structure to a file.
77 */
78
79 static int
80 output_content (CT ct, FILE *out)
81 {
82 int result = 0;
83 CI ci = &ct->c_ctinfo;
84
85 /*
86 * Output all header fields for this content
87 */
88 output_headers (ct, out);
89
90 /*
91 * If this is the internal content structure for a
92 * "message/external", then we are done with the
93 * headers (since it has no body).
94 */
95 if (ct->c_ctexbody)
96 return OK;
97
98 /*
99 * Now output the content bodies.
100 */
101 switch (ct->c_type) {
102 case CT_MULTIPART:
103 {
104 struct multipart *m;
105 struct part *part;
106
107 if (ct->c_rfc934)
108 putc ('\n', out);
109
110 m = (struct multipart *) ct->c_ctparams;
111 for (part = m->mp_parts; part; part = part->mp_next) {
112 CT p = part->mp_part;
113
114 fprintf (out, "\n--%s\n", ci->ci_values[0]);
115 if (output_content (p, out) == NOTOK)
116 return NOTOK;
117 }
118 fprintf (out, "\n--%s--\n", ci->ci_values[0]);
119 }
120 break;
121
122 case CT_MESSAGE:
123 putc ('\n', out);
124 if (ct->c_subtype == MESSAGE_EXTERNAL) {
125 struct exbody *e;
126
127 e = (struct exbody *) ct->c_ctparams;
128 if (output_content (e->eb_content, out) == NOTOK)
129 return NOTOK;
130
131 /* output phantom body for access-type "mail-server" */
132 if (e->eb_body)
133 writeExternalBody (ct, out);
134 } else {
135 result = write8Bit (ct, out);
136 }
137 break;
138
139 /*
140 * Handle discrete types (text/application/audio/image/video)
141 */
142 default:
143 switch (ct->c_encoding) {
144 case CE_7BIT:
145 putc ('\n', out);
146 result = write8Bit (ct, out);
147 break;
148
149 case CE_8BIT:
150 putc ('\n', out);
151 result = write8Bit (ct, out);
152 break;
153
154 case CE_QUOTED:
155 putc ('\n', out);
156 result = writeQuoted (ct, out);
157 break;
158
159 case CE_BASE64:
160 putc ('\n', out);
161 result = writeBase64ct (ct, out);
162 break;
163
164 case CE_BINARY:
165 advise (NULL, "can't handle binary transfer encoding in content");
166 result = NOTOK;
167 break;
168
169 default:
170 advise (NULL, "unknown transfer encoding in content");
171 result = NOTOK;
172 break;
173 }
174 break;
175 }
176
177 return result;
178 }
179
180
181 /*
182 * Output all the header fields for a content
183 */
184
185 static void
186 output_headers (CT ct, FILE *out)
187 {
188 HF hp;
189
190 hp = ct->c_first_hf;
191 while (hp) {
192 fprintf (out, "%s:%s", hp->name, hp->value);
193 hp = hp->next;
194 }
195 }
196
197
198 /*
199 * Write the phantom body for access-type "mail-server".
200 */
201
202 static int
203 writeExternalBody (CT ct, FILE *out)
204 {
205 char **ap, **ep, *cp;
206 struct exbody *e = (struct exbody *) ct->c_ctparams;
207
208 putc ('\n', out);
209 for (cp = e->eb_body; *cp; cp++) {
210 CT ct2 = e->eb_content;
211 CI ci2 = &ct2->c_ctinfo;
212
213 if (*cp == '\\') {
214 switch (*++cp) {
215 case 'I':
216 if (ct2->c_id) {
217 char *dp = trimcpy (ct2->c_id);
218
219 fputs (dp, out);
220 free (dp);
221 }
222 continue;
223
224 case 'N':
225 for (ap = ci2->ci_attrs, ep = ci2->ci_values; *ap; ap++, ep++)
226 if (!mh_strcasecmp (*ap, "name")) {
227 fprintf (out, "%s", *ep);
228 break;
229 }
230 continue;
231
232 case 'T':
233 fprintf (out, "%s/%s", ci2->ci_type, ci2->ci_subtype);
234 for (ap = ci2->ci_attrs, ep = ci2->ci_values; *ap; ap++, ep++)
235 fprintf (out, "; %s=\"%s\"", *ap, *ep);
236 continue;
237
238 case 'n':
239 putc ('\n', out);
240 continue;
241
242 case 't':
243 putc ('\t', out);
244 continue;
245
246 case '\0':
247 cp--;
248 break;
249
250 case '\\':
251 case '"':
252 break;
253
254 default:
255 putc ('\\', out);
256 break;
257 }
258 }
259 putc (*cp, out);
260 }
261 putc ('\n', out);
262
263 return OK;
264 }
265
266
267 /*
268 * Output a content without any transfer encoding
269 */
270
271 static int
272 write8Bit (CT ct, FILE *out)
273 {
274 int fd;
275 char c, *file, buffer[BUFSIZ];
276 CE ce = ct->c_cefile;
277
278 file = NULL;
279 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
280 return NOTOK;
281
282 c = '\n';
283 while (fgets (buffer, sizeof(buffer) - 1, ce->ce_fp)) {
284 c = buffer[strlen (buffer) - 1];
285 fputs (buffer, out);
286 }
287 if (c != '\n')
288 putc ('\n', out);
289
290 (*ct->c_ceclosefnx) (ct);
291 return OK;
292 }
293
294
295 /*
296 * Output a content using quoted-printable
297 */
298
299 static int
300 writeQuoted (CT ct, FILE *out)
301 {
302 int fd;
303 char *cp, *file;
304 char c, buffer[BUFSIZ];
305 CE ce = ct->c_cefile;
306
307 file = NULL;
308 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
309 return NOTOK;
310
311 while (fgets (buffer, sizeof(buffer) - 1, ce->ce_fp)) {
312 int n;
313
314 cp = buffer + strlen (buffer) - 1;
315 if ((c = *cp) == '\n')
316 *cp = '\0';
317
318 if (strncmp (cp = buffer, "From ", sizeof("From ") - 1) == 0) {
319 fprintf (out, "=%02X", *cp++ & 0xff);
320 n = 3;
321 } else {
322 n = 0;
323 }
324 for (; *cp; cp++) {
325 if (n > CPERLIN - 3) {
326 fputs ("=\n", out);
327 n = 0;
328 }
329
330 switch (*cp) {
331 case ' ':
332 case '\t':
333 putc (*cp, out);
334 n++;
335 break;
336
337 default:
338 if (*cp < '!' || *cp > '~')
339 goto three_print;
340 putc (*cp, out);
341 n++;
342 break;
343
344 case '=':
345 three_print:
346 fprintf (out, "=%02X", *cp & 0xff);
347 n += 3;
348 break;
349 }
350 }
351
352 if (c == '\n') {
353 if (cp > buffer && (*--cp == ' ' || *cp == '\t'))
354 fputs ("=\n", out);
355
356 putc ('\n', out);
357 } else {
358 fputs ("=\n", out);
359 }
360 }
361
362 (*ct->c_ceclosefnx) (ct);
363 return OK;
364 }
365
366
367 /*
368 * Output a content using base64
369 */
370
371 static int
372 writeBase64ct (CT ct, FILE *out)
373 {
374 int fd, result;
375 char *file;
376 CE ce = ct->c_cefile;
377
378 file = NULL;
379 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
380 return NOTOK;
381
382 result = writeBase64aux (ce->ce_fp, out);
383 (*ct->c_ceclosefnx) (ct);
384 return result;
385 }