Clean up process wait to use POSIX waitpid() interface.
[mmh] / uip / mhlistsbr.c
1
2 /*
3  * mhlistsbr.c -- routines to list information about the
4  *             -- contents of MIME messages
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 <errno.h>
15 #include <signal.h>
16 #include <h/mts.h>
17 #include <h/tws.h>
18 #include <h/mime.h>
19 #include <h/mhparse.h>
20 #include <h/utils.h>
21
22 /* mhmisc.c */
23 int part_ok (CT, int);
24 int type_ok (CT, int);
25 void flush_errors (void);
26
27 /*
28  * prototypes
29  */
30 void list_all_messages (CT *, int, int, int, int);
31 int list_switch (CT, int, int, int, int);
32 int list_content (CT, int, int, int, int);
33
34 /*
35  * static prototypes
36  */
37 static void list_single_message (CT, int, int, int);
38 static int list_debug (CT);
39 static int list_multi (CT, int, int, int, int);
40 static int list_partial (CT, int, int, int, int);
41 static int list_external (CT, int, int, int, int);
42 static int list_application (CT, int, int, int, int);
43 static int list_encoding (CT);
44
45
46 /*
47  * various formats for -list option
48  */
49 #define LSTFMT1         "%4s %-5s %-24s %5s %-36s\n"
50 #define LSTFMT2a        "%4d "
51 #define LSTFMT2b        "%-5s %-24.24s "
52 #define LSTFMT2c1       "%5lu"
53 #define LSTFMT2c2       "%4lu%c"
54 #define LSTFMT2c3       "huge "
55 #define LSTFMT2c4       "     "
56 #define LSTFMT2d1       " %-36.36s"
57 #define LSTFMT2d2       "\t     %-65.65s\n"
58
59
60 /*
61  * Top level entry point to list group of messages
62  */
63
64 void
65 list_all_messages (CT *cts, int headers, int realsize, int verbose, int debug)
66 {
67     CT ct, *ctp;
68
69     if (headers)
70         printf (LSTFMT1, "msg", "part", "type/subtype", "size", "description");
71
72     for (ctp = cts; *ctp; ctp++) {
73         ct = *ctp;
74         list_single_message (ct, realsize, verbose, debug);
75     }
76
77     flush_errors ();
78 }
79
80
81 /*
82  * Entry point to list a single message
83  */
84
85 static void
86 list_single_message (CT ct, int realsize, int verbose, int debug)
87 {
88     if (type_ok (ct, 1)) {
89         umask (ct->c_umask);
90         list_switch (ct, 1, realsize, verbose, debug);
91         if (ct->c_fp) {
92             fclose (ct->c_fp);
93             ct->c_fp = NULL;
94         }
95         if (ct->c_ceclosefnx)
96             (*ct->c_ceclosefnx) (ct);
97     }
98 }
99
100
101 /*
102  * Primary switching routine to list information about a content
103  */
104
105 int
106 list_switch (CT ct, int toplevel, int realsize, int verbose, int debug)
107 {
108     switch (ct->c_type) {
109         case CT_MULTIPART:
110             return list_multi (ct, toplevel, realsize, verbose, debug);
111             break;
112
113         case CT_MESSAGE:
114             switch (ct->c_subtype) {
115                 case MESSAGE_PARTIAL:
116                     return list_partial (ct, toplevel, realsize, verbose, debug);
117                     break;
118
119                 case MESSAGE_EXTERNAL:
120                     return list_external (ct, toplevel, realsize, verbose, debug);
121                     break;
122
123                 case MESSAGE_RFC822:
124                 default:
125                     return list_content (ct, toplevel, realsize, verbose, debug);
126                     break;
127             }
128             break;
129
130         case CT_TEXT:
131         case CT_AUDIO:
132         case CT_IMAGE:
133         case CT_VIDEO:
134             return list_content (ct, toplevel, realsize, verbose, debug);
135             break;
136
137         case CT_APPLICATION:
138             return list_application (ct, toplevel, realsize, verbose, debug);
139             break;
140
141         default:
142             /* list_debug (ct); */
143             adios (NULL, "unknown content type %d", ct->c_type);
144             break;
145     }
146
147     return 0;   /* NOT REACHED */
148 }
149
150
151 #define empty(s) ((s) ? (s) : "")
152
153 /*
154  * Method for listing information about a simple/generic content
155  */
156
157 int
158 list_content (CT ct, int toplevel, int realsize, int verbose, int debug)
159 {
160     unsigned long size;
161     char *cp, buffer[BUFSIZ];
162     CI ci = &ct->c_ctinfo;
163
164     printf (toplevel > 0 ? LSTFMT2a : toplevel < 0 ? "part " : "     ",
165             atoi (r1bindex (empty (ct->c_file), '/')));
166     snprintf (buffer, sizeof(buffer), "%s/%s", empty (ci->ci_type),
167                 empty (ci->ci_subtype));
168     printf (LSTFMT2b, empty (ct->c_partno), buffer);
169
170     if (ct->c_cesizefnx && realsize)
171         size = (*ct->c_cesizefnx) (ct);
172     else
173         size = ct->c_end - ct->c_begin;
174
175     /* find correct scale for size (Kilo/Mega/Giga/Tera) */
176     for (cp = " KMGT"; size > 9999; size >>= 10)
177         if (!*++cp)
178             break;
179
180     /* print size of this body part */
181     switch (*cp) {
182         case ' ':
183             if (size > 0 || ct->c_encoding != CE_EXTERNAL)
184                 printf (LSTFMT2c1, size);
185             else
186                 printf (LSTFMT2c4);
187             break;
188
189         default:
190             printf (LSTFMT2c2, size, *cp);
191             break;
192
193         case '\0':
194             printf (LSTFMT2c3);
195     }
196
197     /* print Content-Description */
198     if (ct->c_descr) {
199         char *dp;
200
201         dp = trimcpy (cp = add (ct->c_descr, NULL));
202         free (cp);
203         printf (LSTFMT2d1, dp);
204         free (dp);
205     }
206
207     printf ("\n");
208
209     /*
210      * If verbose, print any RFC-822 comments in the
211      * Content-Type line.
212      */
213     if (verbose && ci->ci_comment) {
214         char *dp;
215
216         dp = trimcpy (cp = add (ci->ci_comment, NULL));
217         free (cp);
218         snprintf (buffer, sizeof(buffer), "(%s)", dp);
219         free (dp);
220         printf (LSTFMT2d2, buffer);
221     }
222
223     if (debug)
224         list_debug (ct);
225
226     return OK;
227 }
228
229
230 /*
231  * Print debugging information about a content
232  */
233
234 static int
235 list_debug (CT ct)
236 {
237     char **ap, **ep;
238     CI ci = &ct->c_ctinfo;
239
240     fflush (stdout);
241     fprintf (stderr, "  partno \"%s\"\n", empty (ct->c_partno));
242
243     /* print MIME-Version line */
244     if (ct->c_vrsn)
245         fprintf (stderr, "  %s:%s\n", VRSN_FIELD, ct->c_vrsn);
246
247     /* print Content-Type line */
248     if (ct->c_ctline)
249         fprintf (stderr, "  %s:%s\n", TYPE_FIELD, ct->c_ctline);
250
251     /* print parsed elements of content type */
252     fprintf (stderr, "    type    \"%s\"\n", empty (ci->ci_type));
253     fprintf (stderr, "    subtype \"%s\"\n", empty (ci->ci_subtype));
254     fprintf (stderr, "    comment \"%s\"\n", empty (ci->ci_comment));
255     fprintf (stderr, "    magic   \"%s\"\n", empty (ci->ci_magic));
256
257     /* print parsed parameters attached to content type */
258     fprintf (stderr, "    parameters\n");
259     for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++)
260         fprintf (stderr, "      %s=\"%s\"\n", *ap, *ep);
261
262     /* print internal flags for type/subtype */
263     fprintf (stderr, "    type 0x%x subtype 0x%x params 0x%x\n",
264              ct->c_type, ct->c_subtype,
265              (unsigned int)(unsigned long) ct->c_ctparams);
266
267     fprintf (stderr, "    showproc  \"%s\"\n", empty (ct->c_showproc));
268     fprintf (stderr, "    termproc  \"%s\"\n", empty (ct->c_termproc));
269     fprintf (stderr, "    storeproc \"%s\"\n", empty (ct->c_storeproc));
270
271     /* print transfer encoding information */
272     if (ct->c_celine)
273         fprintf (stderr, "  %s:%s", ENCODING_FIELD, ct->c_celine);
274
275     /* print internal flags for transfer encoding */
276     fprintf (stderr, "    transfer encoding 0x%x params 0x%x\n",
277              ct->c_encoding, (unsigned int)(unsigned long) ct->c_cefile);
278
279     /* print Content-ID */
280     if (ct->c_id)
281         fprintf (stderr, "  %s:%s", ID_FIELD, ct->c_id);
282
283     /* print Content-Description */
284     if (ct->c_descr)
285         fprintf (stderr, "  %s:%s", DESCR_FIELD, ct->c_descr);
286
287     fprintf (stderr, "    read fp 0x%x file \"%s\" begin %ld end %ld\n",
288              (unsigned int)(unsigned long) ct->c_fp, empty (ct->c_file),
289              ct->c_begin, ct->c_end);
290
291     /* print more information about transfer encoding */
292     list_encoding (ct);
293
294     return OK;
295 }
296
297 #undef empty
298
299
300 /*
301  * list content information for type "multipart"
302  */
303
304 static int
305 list_multi (CT ct, int toplevel, int realsize, int verbose, int debug)
306 {
307     struct multipart *m = (struct multipart *) ct->c_ctparams;
308     struct part *part;
309
310     /* list the content for toplevel of this multipart */
311     list_content (ct, toplevel, realsize, verbose, debug);
312
313     /* now list for all the subparts */
314     for (part = m->mp_parts; part; part = part->mp_next) {
315         CT p = part->mp_part;
316
317         if (part_ok (p, 1) && type_ok (p, 1))
318             list_switch (p, 0, realsize, verbose, debug);
319     }
320
321     return OK;
322 }
323
324
325 /*
326  * list content information for type "message/partial"
327  */
328
329 static int
330 list_partial (CT ct, int toplevel, int realsize, int verbose, int debug)
331 {
332     struct partial *p = (struct partial *) ct->c_ctparams;
333
334     list_content (ct, toplevel, realsize, verbose, debug);
335     if (verbose) {
336         printf ("\t     [message %s, part %d", p->pm_partid, p->pm_partno);
337         if (p->pm_maxno)
338             printf (" of %d", p->pm_maxno);
339         printf ("]\n");
340     }
341
342     return OK;
343 }
344
345
346 /*
347  * list content information for type "message/external"
348  */
349
350 static int
351 list_external (CT ct, int toplevel, int realsize, int verbose, int debug)
352 {
353     struct exbody *e = (struct exbody *) ct->c_ctparams;
354
355     /*
356      * First list the information for the
357      * message/external content itself.
358      */
359     list_content (ct, toplevel, realsize, verbose, debug);
360
361     if (verbose) {
362         if (e->eb_name)
363             printf ("\t     name=\"%s\"\n", e->eb_name);
364         if (e->eb_dir)
365             printf ("\t     directory=\"%s\"\n", e->eb_dir);
366         if (e->eb_site)
367             printf ("\t     site=\"%s\"\n", e->eb_site);
368         if (e->eb_server)
369             printf ("\t     server=\"%s\"\n", e->eb_server);
370         if (e->eb_subject)
371             printf ("\t     subject=\"%s\"\n", e->eb_subject);
372
373         /* This must be defined */
374         printf     ("\t     access-type=\"%s\"\n", e->eb_access);
375
376         if (e->eb_mode)
377             printf ("\t     mode=\"%s\"\n", e->eb_mode);
378         if (e->eb_permission)
379             printf ("\t     permission=\"%s\"\n", e->eb_permission);
380
381         if (e->eb_flags == NOTOK)
382             printf ("\t     [service unavailable]\n");
383     }
384
385     /*
386      * Now list the information for the external content
387      * to which this content points.
388      */
389     list_content (e->eb_content, 0, realsize, verbose, debug);
390
391     return OK;
392 }
393
394
395 /*
396  * list content information for type "application"
397  */
398
399 static int
400 list_application (CT ct, int toplevel, int realsize, int verbose, int debug)
401 {
402     list_content (ct, toplevel, realsize, verbose, debug);
403     if (verbose) {
404         char **ap, **ep;
405         CI ci = &ct->c_ctinfo;
406
407         for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++)
408             printf ("\t     %s=\"%s\"\n", *ap, *ep);
409     }
410
411     return OK;
412 }
413
414
415 /*
416  * list information about the Content-Transfer-Encoding
417  * used by a content.
418  */
419
420 static int
421 list_encoding (CT ct)
422 {
423     CE ce;
424
425     if ((ce = ct->c_cefile))
426         fprintf (stderr, "    decoded fp 0x%x file \"%s\"\n",
427                  (unsigned int)(unsigned long) ce->ce_fp,
428                  ce->ce_file ? ce->ce_file : "");
429
430     return OK;
431 }