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