]> diplodocus.org Git - nmh/blob - uip/mhoutsbr.c
Formatting cleanup.
[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 extern int ebcdicsw;
24
25 static char ebcdicsafe[0x100] = {
26 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
27 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
28 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
31 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
32 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
33 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
34 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
35 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
36 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
37 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
38 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
39 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
40 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
41 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
58 };
59
60 static char nib2b64[0x40+1] =
61 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
62
63 /*
64 * prototypes
65 */
66 int output_message (CT, char *);
67 int output_message_fp (CT, FILE *, char *);
68
69 /*
70 * static prototypes
71 */
72 static int output_content (CT, FILE *);
73 static void output_headers (CT, FILE *);
74 static int writeExternalBody (CT, FILE *);
75 static int write8Bit (CT, FILE *);
76 static int writeQuoted (CT, FILE *);
77 static int writeBase64 (CT, FILE *);
78
79
80 /*
81 * Main routine to output a MIME message contained
82 * in a Content structure, to a file. Any necessary
83 * transfer encoding is added.
84 */
85
86 int
87 output_message_fp (CT ct, FILE *fp, char *file)
88 {
89 if (output_content (ct, fp) == NOTOK)
90 return NOTOK;
91
92 if (fflush (fp)) {
93 advise ((file?file:"<FILE*>"), "error writing to");
94 return NOTOK;
95 }
96 return OK;
97 }
98
99 int
100 output_message (CT ct, char *file)
101 {
102 FILE *fp;
103 int status;
104
105 if ((fp = fopen (file, "w")) == NULL) {
106 advise (file, "unable to open for writing");
107 return NOTOK;
108 }
109 status = output_message_fp(ct, fp, file);
110 fclose(fp);
111 return status;
112 }
113
114
115 /*
116 * Output a Content structure to a file.
117 */
118
119 static int
120 output_content (CT ct, FILE *out)
121 {
122 int result = 0;
123 CI ci = &ct->c_ctinfo;
124
125 /*
126 * Output all header fields for this content
127 */
128 output_headers (ct, out);
129
130 /*
131 * If this is the internal content structure for a
132 * "message/external", then we are done with the
133 * headers (since it has no body).
134 */
135 if (ct->c_ctexbody)
136 return OK;
137
138 /*
139 * Now output the content bodies.
140 */
141 switch (ct->c_type) {
142 case CT_MULTIPART:
143 {
144 struct multipart *m;
145 struct part *part;
146
147 if (ct->c_rfc934)
148 putc ('\n', out);
149
150 m = (struct multipart *) ct->c_ctparams;
151 for (part = m->mp_parts; part; part = part->mp_next) {
152 CT p = part->mp_part;
153
154 fprintf (out, "\n--%s\n", ci->ci_values[0]);
155 if (output_content (p, out) == NOTOK)
156 return NOTOK;
157 }
158 fprintf (out, "\n--%s--\n", ci->ci_values[0]);
159 }
160 break;
161
162 case CT_MESSAGE:
163 putc ('\n', out);
164 if (ct->c_subtype == MESSAGE_EXTERNAL) {
165 struct exbody *e;
166
167 e = (struct exbody *) ct->c_ctparams;
168 if (output_content (e->eb_content, out) == NOTOK)
169 return NOTOK;
170
171 /* output phantom body for access-type "mail-server" */
172 if (e->eb_body)
173 writeExternalBody (ct, out);
174 } else {
175 result = write8Bit (ct, out);
176 }
177 break;
178
179 /*
180 * Handle discrete types (text/application/audio/image/video)
181 */
182 default:
183 switch (ct->c_encoding) {
184 case CE_7BIT:
185 putc ('\n', out);
186 result = write8Bit (ct, out);
187 break;
188
189 case CE_8BIT:
190 putc ('\n', out);
191 result = write8Bit (ct, out);
192 break;
193
194 case CE_QUOTED:
195 putc ('\n', out);
196 result = writeQuoted (ct, out);
197 break;
198
199 case CE_BASE64:
200 putc ('\n', out);
201 result = writeBase64 (ct, out);
202 break;
203
204 case CE_BINARY:
205 advise (NULL, "can't handle binary transfer encoding in content");
206 result = NOTOK;
207 break;
208
209 default:
210 advise (NULL, "unknown transfer encoding in content");
211 result = NOTOK;
212 break;
213 }
214 break;
215 }
216
217 return result;
218 }
219
220
221 /*
222 * Output all the header fields for a content
223 */
224
225 static void
226 output_headers (CT ct, FILE *out)
227 {
228 HF hp;
229
230 hp = ct->c_first_hf;
231 while (hp) {
232 fprintf (out, "%s:%s", hp->name, hp->value);
233 hp = hp->next;
234 }
235 }
236
237
238 /*
239 * Write the phantom body for access-type "mail-server".
240 */
241
242 static int
243 writeExternalBody (CT ct, FILE *out)
244 {
245 char **ap, **ep, *cp;
246 struct exbody *e = (struct exbody *) ct->c_ctparams;
247
248 putc ('\n', out);
249 for (cp = e->eb_body; *cp; cp++) {
250 CT ct2 = e->eb_content;
251 CI ci2 = &ct2->c_ctinfo;
252
253 if (*cp == '\\') {
254 switch (*++cp) {
255 case 'I':
256 if (ct2->c_id) {
257 char *dp = trimcpy (ct2->c_id);
258
259 fputs (dp, out);
260 free (dp);
261 }
262 continue;
263
264 case 'N':
265 for (ap = ci2->ci_attrs, ep = ci2->ci_values; *ap; ap++, ep++)
266 if (!mh_strcasecmp (*ap, "name")) {
267 fprintf (out, "%s", *ep);
268 break;
269 }
270 continue;
271
272 case 'T':
273 fprintf (out, "%s/%s", ci2->ci_type, ci2->ci_subtype);
274 for (ap = ci2->ci_attrs, ep = ci2->ci_values; *ap; ap++, ep++)
275 fprintf (out, "; %s=\"%s\"", *ap, *ep);
276 continue;
277
278 case 'n':
279 putc ('\n', out);
280 continue;
281
282 case 't':
283 putc ('\t', out);
284 continue;
285
286 case '\0':
287 cp--;
288 break;
289
290 case '\\':
291 case '"':
292 break;
293
294 default:
295 putc ('\\', out);
296 break;
297 }
298 }
299 putc (*cp, out);
300 }
301 putc ('\n', out);
302
303 return OK;
304 }
305
306
307 /*
308 * Output a content without any transfer encoding
309 */
310
311 static int
312 write8Bit (CT ct, FILE *out)
313 {
314 int fd;
315 char c, *file, buffer[BUFSIZ];
316 CE ce = ct->c_cefile;
317
318 file = NULL;
319 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
320 return NOTOK;
321
322 c = '\n';
323 while (fgets (buffer, sizeof(buffer) - 1, ce->ce_fp)) {
324 c = buffer[strlen (buffer) - 1];
325 fputs (buffer, out);
326 }
327 if (c != '\n')
328 putc ('\n', out);
329
330 (*ct->c_ceclosefnx) (ct);
331 return OK;
332 }
333
334
335 /*
336 * Output a content using quoted-printable
337 */
338
339 static int
340 writeQuoted (CT ct, FILE *out)
341 {
342 int fd;
343 char *cp, *file;
344 char c, buffer[BUFSIZ];
345 CE ce = ct->c_cefile;
346
347 file = NULL;
348 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
349 return NOTOK;
350
351 while (fgets (buffer, sizeof(buffer) - 1, ce->ce_fp)) {
352 int n;
353
354 cp = buffer + strlen (buffer) - 1;
355 if ((c = *cp) == '\n')
356 *cp = '\0';
357
358 if (strncmp (cp = buffer, "From ", sizeof("From ") - 1) == 0) {
359 fprintf (out, "=%02X", *cp++ & 0xff);
360 n = 3;
361 } else {
362 n = 0;
363 }
364 for (; *cp; cp++) {
365 if (n > CPERLIN - 3) {
366 fputs ("=\n", out);
367 n = 0;
368 }
369
370 switch (*cp) {
371 case ' ':
372 case '\t':
373 putc (*cp, out);
374 n++;
375 break;
376
377 default:
378 if (*cp < '!' || *cp > '~'
379 || (ebcdicsw && !ebcdicsafe[*cp & 0xff]))
380 goto three_print;
381 putc (*cp, out);
382 n++;
383 break;
384
385 case '=':
386 three_print:
387 fprintf (out, "=%02X", *cp & 0xff);
388 n += 3;
389 break;
390 }
391 }
392
393 if (c == '\n') {
394 if (cp > buffer && (*--cp == ' ' || *cp == '\t'))
395 fputs ("=\n", out);
396
397 putc ('\n', out);
398 } else {
399 fputs ("=\n", out);
400 }
401 }
402
403 (*ct->c_ceclosefnx) (ct);
404 return OK;
405 }
406
407
408 /*
409 * Output a content using base64
410 */
411
412 static int
413 writeBase64 (CT ct, FILE *out)
414 {
415 int fd, result;
416 char *file;
417 CE ce = ct->c_cefile;
418
419 file = NULL;
420 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
421 return NOTOK;
422
423 result = writeBase64aux (ce->ce_fp, out);
424 (*ct->c_ceclosefnx) (ct);
425 return result;
426 }
427
428
429 int
430 writeBase64aux (FILE *in, FILE *out)
431 {
432 unsigned int cc, n;
433 char inbuf[3];
434
435 n = BPERLIN;
436 while ((cc = fread (inbuf, sizeof(*inbuf), sizeof(inbuf), in)) > 0) {
437 unsigned long bits;
438 char *bp;
439 char outbuf[4];
440
441 if (cc < sizeof(inbuf)) {
442 inbuf[2] = 0;
443 if (cc < sizeof(inbuf) - 1)
444 inbuf[1] = 0;
445 }
446 bits = (inbuf[0] & 0xff) << 16;
447 bits |= (inbuf[1] & 0xff) << 8;
448 bits |= inbuf[2] & 0xff;
449
450 for (bp = outbuf + sizeof(outbuf); bp > outbuf; bits >>= 6)
451 *--bp = nib2b64[bits & 0x3f];
452 if (cc < sizeof(inbuf)) {
453 outbuf[3] = '=';
454 if (cc < sizeof inbuf - 1)
455 outbuf[2] = '=';
456 }
457
458 fwrite (outbuf, sizeof(*outbuf), sizeof(outbuf), out);
459
460 if (cc < sizeof(inbuf)) {
461 putc ('\n', out);
462 return OK;
463 }
464
465 if (--n <= 0) {
466 n = BPERLIN;
467 putc ('\n', out);
468 }
469 }
470 if (n != BPERLIN)
471 putc ('\n', out);
472
473 return OK;
474 }