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