source: trunk/third/nmh/uip/mhoutsbr.c @ 12455

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