]> diplodocus.org Git - nmh/blob - uip/mhoutsbr.c
Removed temporary probes added in commit
[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 <h/mts.h>
16 #include <h/tws.h>
17 #include <h/mime.h>
18 #include <h/mhparse.h>
19
20
21 /*
22 * prototypes
23 */
24 int output_message (CT, char *);
25 int output_message_fp (CT, FILE *, char *);
26
27 /*
28 * static prototypes
29 */
30 static int output_content (CT, FILE *);
31 static void output_headers (CT, FILE *);
32 static int writeExternalBody (CT, FILE *);
33 static int write8Bit (CT, FILE *);
34 static int writeQuoted (CT, FILE *);
35 static int writeBase64ct (CT, FILE *);
36
37
38 /*
39 * Main routine to output a MIME message contained
40 * in a Content structure, to a file. Any necessary
41 * transfer encoding is added.
42 */
43
44 int
45 output_message_fp (CT ct, FILE *fp, char *file)
46 {
47 if (output_content (ct, fp) == NOTOK)
48 return NOTOK;
49
50 if (fflush (fp)) {
51 advise ((file?file:"<FILE*>"), "error writing to");
52 return NOTOK;
53 }
54 return OK;
55 }
56
57 int
58 output_message (CT ct, char *file)
59 {
60 FILE *fp;
61 int status;
62
63 if (! strcmp (file, "-")) {
64 fp = stdout;
65 } else if ((fp = fopen (file, "w")) == NULL) {
66 advise (file, "unable to open for writing");
67 return NOTOK;
68 }
69 status = output_message_fp(ct, fp, file);
70 if (strcmp (file, "-")) fclose(fp);
71 return status;
72 }
73
74
75 /*
76 * Output a Content structure to a file.
77 */
78
79 static int
80 output_content (CT ct, FILE *out)
81 {
82 int result = 0;
83 CI ci = &ct->c_ctinfo;
84 char *boundary = ci->ci_values[0], **ap, **vp;
85
86 for (ap = ci->ci_attrs, vp = ci->ci_values; *ap; ++ap, ++vp) {
87 if (! strcasecmp ("boundary", *ap)) {
88 boundary = *vp;
89 break;
90 }
91 }
92
93 /*
94 * Output all header fields for this content
95 */
96 output_headers (ct, out);
97
98 /*
99 * If this is the internal content structure for a
100 * "message/external", then we are done with the
101 * headers (since it has no body).
102 */
103 if (ct->c_ctexbody)
104 return OK;
105
106 /*
107 * Now output the content bodies.
108 */
109 switch (ct->c_type) {
110 case CT_MULTIPART:
111 {
112 struct multipart *m;
113 struct part *part;
114
115 if (ct->c_rfc934)
116 putc ('\n', out);
117
118 m = (struct multipart *) ct->c_ctparams;
119
120 if (m->mp_content_before) {
121 fprintf (out, "%s", m->mp_content_before);
122 }
123
124 for (part = m->mp_parts; part; part = part->mp_next) {
125 CT p = part->mp_part;
126
127 fprintf (out, "\n--%s\n", boundary);
128 if (output_content (p, out) == NOTOK)
129 return NOTOK;
130 }
131 fprintf (out, "\n--%s--\n", boundary);
132
133 if (m->mp_content_after) {
134 fprintf (out, "%s", m->mp_content_after);
135 }
136 }
137 break;
138
139 case CT_MESSAGE:
140 putc ('\n', out);
141 if (ct->c_subtype == MESSAGE_EXTERNAL) {
142 struct exbody *e;
143
144 e = (struct exbody *) ct->c_ctparams;
145 if (output_content (e->eb_content, out) == NOTOK)
146 return NOTOK;
147
148 /* output phantom body for access-type "mail-server" */
149 if (e->eb_body)
150 writeExternalBody (ct, out);
151 } else {
152 result = write8Bit (ct, out);
153 }
154 break;
155
156 /*
157 * Handle discrete types (text/application/audio/image/video)
158 */
159 default:
160 switch (ct->c_encoding) {
161 case CE_7BIT:
162 /* Special case: if this is a non-MIME message with no
163 body, don't emit the newline that would appear between
164 the headers and body. In that case, the call to
165 write8Bit() shouldn't be needed, but is harmless. */
166 if (ct->c_ctinfo.ci_attrs[0] != NULL ||
167 ct->c_begin != ct->c_end) {
168 putc ('\n', out);
169 }
170 result = write8Bit (ct, out);
171 break;
172
173 case CE_8BIT:
174 putc ('\n', out);
175 result = write8Bit (ct, out);
176 break;
177
178 case CE_QUOTED:
179 putc ('\n', out);
180 result = writeQuoted (ct, out);
181 break;
182
183 case CE_BASE64:
184 putc ('\n', out);
185 result = writeBase64ct (ct, out);
186 break;
187
188 case CE_BINARY:
189 advise (NULL, "can't handle binary transfer encoding in content");
190 result = NOTOK;
191 break;
192
193 default:
194 advise (NULL, "unknown transfer encoding in content");
195 result = NOTOK;
196 break;
197 }
198 break;
199 }
200
201 return result;
202 }
203
204
205 /*
206 * Output all the header fields for a content
207 */
208
209 static void
210 output_headers (CT ct, FILE *out)
211 {
212 HF hp;
213
214 hp = ct->c_first_hf;
215 while (hp) {
216 fprintf (out, "%s:%s", hp->name, hp->value);
217 hp = hp->next;
218 }
219 }
220
221
222 /*
223 * Write the phantom body for access-type "mail-server".
224 */
225
226 static int
227 writeExternalBody (CT ct, FILE *out)
228 {
229 char **ap, **ep, *cp;
230 struct exbody *e = (struct exbody *) ct->c_ctparams;
231
232 putc ('\n', out);
233 for (cp = e->eb_body; *cp; cp++) {
234 CT ct2 = e->eb_content;
235 CI ci2 = &ct2->c_ctinfo;
236
237 if (*cp == '\\') {
238 switch (*++cp) {
239 case 'I':
240 if (ct2->c_id) {
241 char *dp = trimcpy (ct2->c_id);
242
243 fputs (dp, out);
244 free (dp);
245 }
246 continue;
247
248 case 'N':
249 for (ap = ci2->ci_attrs, ep = ci2->ci_values; *ap; ap++, ep++)
250 if (!strcasecmp (*ap, "name")) {
251 fprintf (out, "%s", *ep);
252 break;
253 }
254 continue;
255
256 case 'T':
257 fprintf (out, "%s/%s", ci2->ci_type, ci2->ci_subtype);
258 for (ap = ci2->ci_attrs, ep = ci2->ci_values; *ap; ap++, ep++)
259 fprintf (out, "; %s=\"%s\"", *ap, *ep);
260 continue;
261
262 case 'n':
263 putc ('\n', out);
264 continue;
265
266 case 't':
267 putc ('\t', out);
268 continue;
269
270 case '\0':
271 cp--;
272 break;
273
274 case '\\':
275 case '"':
276 break;
277
278 default:
279 putc ('\\', out);
280 break;
281 }
282 }
283 putc (*cp, out);
284 }
285 putc ('\n', out);
286
287 return OK;
288 }
289
290
291 /*
292 * Output a content without any transfer encoding
293 */
294
295 static int
296 write8Bit (CT ct, FILE *out)
297 {
298 int fd;
299 size_t inbytes;
300 char c, *file, buffer[BUFSIZ];
301 CE ce = &ct->c_cefile;
302
303 file = NULL;
304 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
305 return NOTOK;
306
307 c = '\n';
308 while ((inbytes = fread (buffer, 1, sizeof buffer, ce->ce_fp)) > 0) {
309 c = buffer[inbytes - 1];
310 fwrite (buffer, 1, inbytes, out);
311 }
312 if (c != '\n')
313 putc ('\n', out);
314
315 (*ct->c_ceclosefnx) (ct);
316 return OK;
317 }
318
319
320 /*
321 * Output a content using quoted-printable
322 */
323
324 static int
325 writeQuoted (CT ct, FILE *out)
326 {
327 int fd;
328 char *cp, *file;
329 char c, buffer[BUFSIZ];
330 CE ce = &ct->c_cefile;
331
332 file = NULL;
333 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
334 return NOTOK;
335
336 while (fgets (buffer, sizeof(buffer) - 1, ce->ce_fp)) {
337 int n;
338
339 cp = buffer + strlen (buffer) - 1;
340 if ((c = *cp) == '\n')
341 *cp = '\0';
342
343 if (strncmp (cp = buffer, "From ", sizeof("From ") - 1) == 0) {
344 fprintf (out, "=%02X", *cp++ & 0xff);
345 n = 3;
346 } else {
347 n = 0;
348 }
349 for (; *cp; cp++) {
350 if (n > CPERLIN - 3) {
351 fputs ("=\n", out);
352 n = 0;
353 }
354
355 switch (*cp) {
356 case ' ':
357 case '\t':
358 putc (*cp, out);
359 n++;
360 break;
361
362 default:
363 if (*cp < '!' || *cp > '~')
364 goto three_print;
365 putc (*cp, out);
366 n++;
367 break;
368
369 case '=':
370 three_print:
371 fprintf (out, "=%02X", *cp & 0xff);
372 n += 3;
373 break;
374 }
375 }
376
377 if (c == '\n') {
378 if (cp > buffer && (*--cp == ' ' || *cp == '\t'))
379 fputs ("=\n", out);
380
381 putc ('\n', out);
382 } else {
383 fputs ("=\n", out);
384 }
385 }
386
387 (*ct->c_ceclosefnx) (ct);
388 return OK;
389 }
390
391
392 /*
393 * Output a content using base64
394 */
395
396 static int
397 writeBase64ct (CT ct, FILE *out)
398 {
399 int fd, result;
400 char *file;
401 CE ce = &ct->c_cefile;
402
403 file = NULL;
404 if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
405 return NOTOK;
406
407 result = writeBase64aux (ce->ce_fp, out);
408 (*ct->c_ceclosefnx) (ct);
409 return result;
410 }