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