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.
15 #include <h/mhparse.h>
18 static char nib2b64[0x40+1] =
19 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
24 int output_message(CT, char *);
25 int output_message_fp(CT, FILE *, char *);
30 static int output_content(CT, FILE *);
31 static void output_headers(CT, FILE *);
32 static int write8Bit(CT, FILE *);
33 static int writeQuoted(CT, FILE *);
34 static int writeBase64(CT, FILE *);
35 static int writeBase64aux(FILE *, FILE *);
39 ** Main routine to output a MIME message contained
40 ** in a Content structure, to a file. Any necessary
41 ** transfer encoding is added.
45 output_message_fp(CT ct, FILE *fp, char *file)
47 if (output_content(ct, fp) == NOTOK)
51 advise((file?file:"<FILE*>"), "error writing to");
58 output_message(CT ct, char *file)
63 if ((fp = fopen(file, "w")) == NULL) {
64 advise(file, "unable to open for writing");
67 status = output_message_fp(ct, fp, file);
74 ** Output a Content structure to a file.
78 output_content(CT ct, FILE *out)
81 CI ci = &ct->c_ctinfo;
84 ** Output all header fields for this content
86 output_headers(ct, out);
89 ** Now output the content bodies.
97 m = (struct multipart *) ct->c_ctparams;
98 for (part = m->mp_parts; part; part = part->mp_next) {
101 fprintf(out, "\n--%s\n", ci->ci_values[0]);
102 if (output_content(p, out) == NOTOK)
105 fprintf(out, "\n--%s--\n", ci->ci_values[0]);
111 result = write8Bit(ct, out);
115 ** Handle discrete types (text/application/audio/image/video)
118 switch (ct->c_encoding) {
121 result = write8Bit(ct, out);
126 result = write8Bit(ct, out);
131 result = writeQuoted(ct, out);
136 result = writeBase64(ct, out);
140 advise(NULL, "can't handle binary transfer encoding in content");
145 advise(NULL, "unknown transfer encoding in content");
157 ** Output all the header fields for a content
161 output_headers(CT ct, FILE *out)
164 charstring_t body = charstring_create(0);
168 fold(body, strlen(hp->name), hp->value);
169 fprintf(out, "%s:%s", hp->name, charstring_buffer(body));
172 charstring_free(body);
177 ** Output a content without any transfer encoding
181 write8Bit(CT ct, FILE *out)
184 char c, *file, buffer[BUFSIZ];
185 CE ce = ct->c_cefile;
188 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
192 while (fgets(buffer, sizeof(buffer) - 1, ce->ce_fp)) {
193 c = buffer[strlen(buffer) - 1];
199 (*ct->c_ceclosefnx) (ct);
205 ** Output a content using quoted-printable
209 writeQuoted(CT ct, FILE *out)
213 char c, buffer[BUFSIZ];
214 CE ce = ct->c_cefile;
217 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
220 while (fgets(buffer, sizeof(buffer) - 1, ce->ce_fp)) {
223 cp = buffer + strlen(buffer) - 1;
224 if ((c = *cp) == '\n')
227 if (strncmp(cp = buffer, "From ", sizeof("From ") - 1) == 0) {
228 fprintf(out, "=%02X", *cp++ & 0xff);
234 if (n + 1 >= CPERLIN) {
247 if (*cp < '!' || *cp > '~') {
250 if (n == 0 && *cp == '.') {
252 ** encode dot at start of line,
253 ** because it could be alone ...
263 fprintf(out, "=%02X", *cp & 0xff);
270 if (cp > buffer && (*--cp == ' ' || *cp == '\t'))
279 (*ct->c_ceclosefnx) (ct);
285 ** Output a content using base64
289 writeBase64(CT ct, FILE *out)
293 CE ce = ct->c_cefile;
296 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
299 result = writeBase64aux(ce->ce_fp, out);
300 (*ct->c_ceclosefnx) (ct);
306 writeBase64aux(FILE *in, FILE *out)
312 while ((cc = fread(inbuf, sizeof(*inbuf), sizeof(inbuf), in)) > 0) {
317 if (cc < sizeof(inbuf)) {
319 if (cc < sizeof(inbuf) - 1)
322 bits = (inbuf[0] & 0xff) << 16;
323 bits |= (inbuf[1] & 0xff) << 8;
324 bits |= inbuf[2] & 0xff;
326 for (bp = outbuf + sizeof(outbuf); bp > outbuf; bits >>= 6)
327 *--bp = nib2b64[bits & 0x3f];
328 if (cc < sizeof(inbuf)) {
330 if (cc < sizeof inbuf - 1)
334 fwrite(outbuf, sizeof(*outbuf), sizeof(outbuf), out);
336 if (cc < sizeof(inbuf)) {