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