2 ** mhoutsbr.c -- routines to output MIME messages
3 ** -- given a Content structure
5 ** This code is Copyright (c) 2002, by the authors of nmh. See the
6 ** COPYRIGHT file in the root directory of the nmh distribution for
7 ** complete copyright information.
12 #include <h/signals.h>
18 #include <h/mhparse.h>
20 #ifdef HAVE_SYS_WAIT_H
21 # include <sys/wait.h>
27 static char ebcdicsafe[0x100] = {
28 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
30 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
32 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
33 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
34 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
35 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
36 0x00, 0x01, 0x01, 0x01, 0x01, 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, 0x00, 0x00, 0x00, 0x00, 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, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
62 static char nib2b64[0x40+1] =
63 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
68 int output_message(CT, char *);
69 int output_message_fp(CT, FILE *, char *);
70 int writeBase64aux(FILE *, FILE *);
75 static int output_content(CT, FILE *);
76 static void output_headers(CT, FILE *);
77 static int writeExternalBody(CT, FILE *);
78 static int write8Bit(CT, FILE *);
79 static int writeQuoted(CT, FILE *);
80 static int writeBase64(CT, FILE *);
84 ** Main routine to output a MIME message contained
85 ** in a Content structure, to a file. Any necessary
86 ** transfer encoding is added.
90 output_message_fp(CT ct, FILE *fp, char *file)
92 if (output_content(ct, fp) == NOTOK)
96 advise((file?file:"<FILE*>"), "error writing to");
103 output_message(CT ct, char *file)
108 if ((fp = fopen(file, "w")) == NULL) {
109 advise(file, "unable to open for writing");
112 status = output_message_fp(ct, fp, file);
119 ** Output a Content structure to a file.
123 output_content(CT ct, FILE *out)
126 CI ci = &ct->c_ctinfo;
129 ** Output all header fields for this content
131 output_headers(ct, out);
134 ** If this is the internal content structure for a
135 ** "message/external", then we are done with the
136 ** headers (since it has no body).
142 ** Now output the content bodies.
144 switch (ct->c_type) {
153 m = (struct multipart *) ct->c_ctparams;
154 for (part = m->mp_parts; part; part = part->mp_next) {
155 CT p = part->mp_part;
157 fprintf(out, "\n--%s\n", ci->ci_values[0]);
158 if (output_content(p, out) == NOTOK)
161 fprintf(out, "\n--%s--\n", ci->ci_values[0]);
167 if (ct->c_subtype == MESSAGE_EXTERNAL) {
170 e = (struct exbody *) ct->c_ctparams;
171 if (output_content(e->eb_content, out) == NOTOK)
174 /* output phantom body for access-type "mail-server" */
176 writeExternalBody(ct, out);
178 result = write8Bit(ct, out);
183 ** Handle discrete types (text/application/audio/image/video)
186 switch (ct->c_encoding) {
189 result = write8Bit(ct, out);
194 result = write8Bit(ct, out);
199 result = writeQuoted(ct, out);
204 result = writeBase64(ct, out);
208 advise(NULL, "can't handle binary transfer encoding in content");
213 advise(NULL, "unknown transfer encoding in content");
225 ** Output all the header fields for a content
229 output_headers(CT ct, FILE *out)
235 fprintf(out, "%s:%s", hp->name, hp->value);
242 ** Write the phantom body for access-type "mail-server".
246 writeExternalBody(CT ct, FILE *out)
248 char **ap, **ep, *cp;
249 struct exbody *e = (struct exbody *) ct->c_ctparams;
252 for (cp = e->eb_body; *cp; cp++) {
253 CT ct2 = e->eb_content;
254 CI ci2 = &ct2->c_ctinfo;
260 char *dp = trimcpy(ct2->c_id);
268 for (ap = ci2->ci_attrs, ep = ci2->ci_values;
270 if (!mh_strcasecmp(*ap, "name")) {
271 fprintf(out, "%s", *ep);
277 fprintf(out, "%s/%s", ci2->ci_type,
279 for (ap = ci2->ci_attrs, ep = ci2->ci_values;
281 fprintf(out, "; %s=\"%s\"", *ap, *ep);
314 ** Output a content without any transfer encoding
318 write8Bit(CT ct, FILE *out)
321 char c, *file, buffer[BUFSIZ];
322 CE ce = ct->c_cefile;
325 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
329 while (fgets(buffer, sizeof(buffer) - 1, ce->ce_fp)) {
330 c = buffer[strlen(buffer) - 1];
336 (*ct->c_ceclosefnx) (ct);
342 ** Output a content using quoted-printable
346 writeQuoted(CT ct, FILE *out)
350 char c, buffer[BUFSIZ];
351 CE ce = ct->c_cefile;
354 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
357 while (fgets(buffer, sizeof(buffer) - 1, ce->ce_fp)) {
360 cp = buffer + strlen(buffer) - 1;
361 if ((c = *cp) == '\n')
364 if (strncmp(cp = buffer, "From ", sizeof("From ") - 1) == 0) {
365 fprintf(out, "=%02X", *cp++ & 0xff);
371 if (n > CPERLIN - 3) {
384 if (*cp < '!' || *cp > '~' || (ebcdicsw && !ebcdicsafe[*cp & 0xff]))
392 fprintf(out, "=%02X", *cp & 0xff);
399 if (cp > buffer && (*--cp == ' ' || *cp == '\t'))
408 (*ct->c_ceclosefnx) (ct);
414 ** Output a content using base64
418 writeBase64(CT ct, FILE *out)
422 CE ce = ct->c_cefile;
425 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
428 result = writeBase64aux(ce->ce_fp, out);
429 (*ct->c_ceclosefnx) (ct);
435 writeBase64aux(FILE *in, FILE *out)
441 while ((cc = fread(inbuf, sizeof(*inbuf), sizeof(inbuf), in)) > 0) {
446 if (cc < sizeof(inbuf)) {
448 if (cc < sizeof(inbuf) - 1)
451 bits = (inbuf[0] & 0xff) << 16;
452 bits |= (inbuf[1] & 0xff) << 8;
453 bits |= inbuf[2] & 0xff;
455 for (bp = outbuf + sizeof(outbuf); bp > outbuf; bits >>= 6)
456 *--bp = nib2b64[bits & 0x3f];
457 if (cc < sizeof(inbuf)) {
459 if (cc < sizeof inbuf - 1)
463 fwrite(outbuf, sizeof(*outbuf), sizeof(outbuf), out);
465 if (cc < sizeof(inbuf)) {