3 * mhoutsbr.c -- routines to output MIME messages
4 * -- given a Content structure
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.
15 #include <h/signals.h>
22 #include <h/mhparse.h>
24 #ifdef HAVE_SYS_WAIT_H
25 # include <sys/wait.h>
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
66 static char nib2b64[0x40+1] =
67 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
72 int output_message (CT, char *);
73 int output_message_fp (CT, FILE *, char *);
74 int writeBase64aux (FILE *, FILE *);
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 *);
88 * Main routine to output a MIME message contained
89 * in a Content structure, to a file. Any necessary
90 * transfer encoding is added.
94 output_message_fp (CT ct, FILE *fp, char *file)
96 if (output_content (ct, fp) == NOTOK)
100 advise ((file?file:"<FILE*>"), "error writing to");
107 output_message (CT ct, char *file)
112 if ((fp = fopen (file, "w")) == NULL) {
113 advise (file, "unable to open for writing");
116 status = output_message_fp(ct, fp, file);
123 * Output a Content structure to a file.
127 output_content (CT ct, FILE *out)
130 CI ci = &ct->c_ctinfo;
133 * Output all header fields for this content
135 output_headers (ct, out);
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).
146 * Now output the content bodies.
148 switch (ct->c_type) {
157 m = (struct multipart *) ct->c_ctparams;
158 for (part = m->mp_parts; part; part = part->mp_next) {
159 CT p = part->mp_part;
161 fprintf (out, "\n--%s\n", ci->ci_values[0]);
162 if (output_content (p, out) == NOTOK)
165 fprintf (out, "\n--%s--\n", ci->ci_values[0]);
171 if (ct->c_subtype == MESSAGE_EXTERNAL) {
174 e = (struct exbody *) ct->c_ctparams;
175 if (output_content (e->eb_content, out) == NOTOK)
178 /* output phantom body for access-type "mail-server" */
180 writeExternalBody (ct, out);
182 result = write8Bit (ct, out);
187 * Handle discrete types (text/application/audio/image/video)
190 switch (ct->c_encoding) {
193 result = write8Bit (ct, out);
198 result = write8Bit (ct, out);
203 result = writeQuoted (ct, out);
208 result = writeBase64 (ct, out);
212 advise (NULL, "can't handle binary transfer encoding in content");
217 advise (NULL, "unknown transfer encoding in content");
229 * Output all the header fields for a content
233 output_headers (CT ct, FILE *out)
239 fprintf (out, "%s:%s", hp->name, hp->value);
246 * Write the phantom body for access-type "mail-server".
250 writeExternalBody (CT ct, FILE *out)
252 char **ap, **ep, *cp;
253 struct exbody *e = (struct exbody *) ct->c_ctparams;
256 for (cp = e->eb_body; *cp; cp++) {
257 CT ct2 = e->eb_content;
258 CI ci2 = &ct2->c_ctinfo;
264 char *dp = trimcpy (ct2->c_id);
272 for (ap = ci2->ci_attrs, ep = ci2->ci_values; *ap; ap++, ep++)
273 if (!mh_strcasecmp (*ap, "name")) {
274 fprintf (out, "%s", *ep);
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);
315 * Output a content without any transfer encoding
319 write8Bit (CT ct, FILE *out)
322 char c, *file, buffer[BUFSIZ];
323 CE ce = ct->c_cefile;
326 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
330 while (fgets (buffer, sizeof(buffer) - 1, ce->ce_fp)) {
331 c = buffer[strlen (buffer) - 1];
337 (*ct->c_ceclosefnx) (ct);
343 * Output a content using quoted-printable
347 writeQuoted (CT ct, FILE *out)
351 char c, buffer[BUFSIZ];
352 CE ce = ct->c_cefile;
355 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
358 while (fgets (buffer, sizeof(buffer) - 1, ce->ce_fp)) {
361 cp = buffer + strlen (buffer) - 1;
362 if ((c = *cp) == '\n')
365 if (strncmp (cp = buffer, "From ", sizeof("From ") - 1) == 0) {
366 fprintf (out, "=%02X", *cp++ & 0xff);
372 if (n > CPERLIN - 3) {
385 if (*cp < '!' || *cp > '~'
386 || (ebcdicsw && !ebcdicsafe[*cp & 0xff]))
394 fprintf (out, "=%02X", *cp & 0xff);
401 if (cp > buffer && (*--cp == ' ' || *cp == '\t'))
410 (*ct->c_ceclosefnx) (ct);
416 * Output a content using base64
420 writeBase64 (CT ct, FILE *out)
424 CE ce = ct->c_cefile;
427 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
430 result = writeBase64aux (ce->ce_fp, out);
431 (*ct->c_ceclosefnx) (ct);
437 writeBase64aux (FILE *in, FILE *out)
443 while ((cc = fread (inbuf, sizeof(*inbuf), sizeof(inbuf), in)) > 0) {
448 if (cc < sizeof(inbuf)) {
450 if (cc < sizeof(inbuf) - 1)
453 bits = (inbuf[0] & 0xff) << 16;
454 bits |= (inbuf[1] & 0xff) << 8;
455 bits |= inbuf[2] & 0xff;
457 for (bp = outbuf + sizeof(outbuf); bp > outbuf; bits >>= 6)
458 *--bp = nib2b64[bits & 0x3f];
459 if (cc < sizeof(inbuf)) {
461 if (cc < sizeof inbuf - 1)
465 fwrite (outbuf, sizeof(*outbuf), sizeof(outbuf), out);
467 if (cc < sizeof(inbuf)) {