Added mhmail.in. start of a replacement for compiled mhmail.
[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     if (verbose) {
210         char **ap, **ep;
211         CI ci = &ct->c_ctinfo;
212
213         for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++)
214             printf ("\t     %s=\"%s\"\n", *ap, *ep);
215
216         /*
217          * If verbose, print any RFC-822 comments in the
218          * Content-Type line.
219          */
220         if (ci->ci_comment) {
221             char *dp;
222
223             dp = trimcpy (cp = add (ci->ci_comment, NULL));
224             free (cp);
225             snprintf (buffer, sizeof(buffer), "(%s)", dp);
226             free (dp);
227             printf (LSTFMT2d2, buffer);
228         }
229     }
230
231     if (debug)
232         list_debug (ct);
233
234     return OK;
235 }
236
237
238 /*
239  * Print debugging information about a content
240  */
241
242 static int
243 list_debug (CT ct)
244 {
245     char **ap, **ep;
246     CI ci = &ct->c_ctinfo;
247
248     fflush (stdout);
249     fprintf (stderr, "  partno \"%s\"\n", empty (ct->c_partno));
250
251     /* print MIME-Version line */
252     if (ct->c_vrsn)
253         fprintf (stderr, "  %s:%s\n", VRSN_FIELD, ct->c_vrsn);
254
255     /* print Content-Type line */
256     if (ct->c_ctline)
257         fprintf (stderr, "  %s:%s\n", TYPE_FIELD, ct->c_ctline);
258
259     /* print parsed elements of content type */
260     fprintf (stderr, "    type    \"%s\"\n", empty (ci->ci_type));
261     fprintf (stderr, "    subtype \"%s\"\n", empty (ci->ci_subtype));
262     fprintf (stderr, "    comment \"%s\"\n", empty (ci->ci_comment));
263     fprintf (stderr, "    magic   \"%s\"\n", empty (ci->ci_magic));
264
265     /* print parsed parameters attached to content type */
266     fprintf (stderr, "    parameters\n");
267     for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++)
268         fprintf (stderr, "      %s=\"%s\"\n", *ap, *ep);
269
270     /* print internal flags for type/subtype */
271     fprintf (stderr, "    type 0x%x subtype 0x%x params 0x%x\n",
272              ct->c_type, ct->c_subtype,
273              (unsigned int)(unsigned long) ct->c_ctparams);
274
275     fprintf (stderr, "    showproc  \"%s\"\n", empty (ct->c_showproc));
276     fprintf (stderr, "    termproc  \"%s\"\n", empty (ct->c_termproc));
277     fprintf (stderr, "    storeproc \"%s\"\n", empty (ct->c_storeproc));
278
279     /* print transfer encoding information */
280     if (ct->c_celine)
281         fprintf (stderr, "  %s:%s", ENCODING_FIELD, ct->c_celine);
282
283     /* print internal flags for transfer encoding */
284     fprintf (stderr, "    transfer encoding 0x%x params 0x%x\n",
285              ct->c_encoding, (unsigned int)(unsigned long) ct->c_cefile);
286
287     /* print Content-ID */
288     if (ct->c_id)
289         fprintf (stderr, "  %s:%s", ID_FIELD, ct->c_id);
290
291     /* print Content-Description */
292     if (ct->c_descr)
293         fprintf (stderr, "  %s:%s", DESCR_FIELD, ct->c_descr);
294
295     fprintf (stderr, "    read fp 0x%x file \"%s\" begin %ld end %ld\n",
296              (unsigned int)(unsigned long) ct->c_fp, empty (ct->c_file),
297              ct->c_begin, ct->c_end);
298
299     /* print more information about transfer encoding */
300     list_encoding (ct);
301
302     return OK;
303 }
304
305 #undef empty
306
307
308 /*
309  * list content information for type "multipart"
310  */
311
312 static int
313 list_multi (CT ct, int toplevel, int realsize, int verbose, int debug)
314 {
315     struct multipart *m = (struct multipart *) ct->c_ctparams;
316     struct part *part;
317
318     /* list the content for toplevel of this multipart */
319     list_content (ct, toplevel, realsize, verbose, debug);
320
321     /* now list for all the subparts */
322     for (part = m->mp_parts; part; part = part->mp_next) {
323         CT p = part->mp_part;
324
325         if (part_ok (p, 1) && type_ok (p, 1))
326             list_switch (p, 0, realsize, verbose, debug);
327     }
328
329     return OK;
330 }
331
332
333 /*
334  * list content information for type "message/partial"
335  */
336
337 static int
338 list_partial (CT ct, int toplevel, int realsize, int verbose, int debug)
339 {
340     struct partial *p = (struct partial *) ct->c_ctparams;
341
342     list_content (ct, toplevel, realsize, verbose, debug);
343     if (verbose) {
344         printf ("\t     [message %s, part %d", p->pm_partid, p->pm_partno);
345         if (p->pm_maxno)
346             printf (" of %d", p->pm_maxno);
347         printf ("]\n");
348     }
349
350     return OK;
351 }
352
353
354 /*
355  * list content information for type "message/external"
356  */
357
358 static int
359 list_external (CT ct, int toplevel, int realsize, int verbose, int debug)
360 {
361     struct exbody *e = (struct exbody *) ct->c_ctparams;
362
363     /*
364      * First list the information for the
365      * message/external content itself.
366      */
367     list_content (ct, toplevel, realsize, verbose, debug);
368
369     if (verbose) {
370         if (e->eb_name)
371             printf ("\t     name=\"%s\"\n", e->eb_name);
372         if (e->eb_dir)
373             printf ("\t     directory=\"%s\"\n", e->eb_dir);
374         if (e->eb_site)
375             printf ("\t     site=\"%s\"\n", e->eb_site);
376         if (e->eb_server)
377             printf ("\t     server=\"%s\"\n", e->eb_server);
378         if (e->eb_subject)
379             printf ("\t     subject=\"%s\"\n", e->eb_subject);
380
381         /* This must be defined */
382         printf     ("\t     access-type=\"%s\"\n", e->eb_access);
383
384         if (e->eb_mode)
385             printf ("\t     mode=\"%s\"\n", e->eb_mode);
386         if (e->eb_permission)
387             printf ("\t     permission=\"%s\"\n", e->eb_permission);
388
389         if (e->eb_flags == NOTOK)
390             printf ("\t     [service unavailable]\n");
391     }
392
393     /*
394      * Now list the information for the external content
395      * to which this content points.
396      */
397     list_content (e->eb_content, 0, realsize, verbose, debug);
398
399     return OK;
400 }
401
402
403 /*
404  * list content information for type "application"
405  * This no longer needs to be a separate function.  It used to
406  * produce some output with verbose enabled, but that has been
407  * moved to list_content ().
408  */
409
410 static int
411 list_application (CT ct, int toplevel, int realsize, int verbose, int debug)
412 {
413     list_content (ct, toplevel, realsize, verbose, debug);
414
415     return OK;
416 }
417
418
419 /*
420  * list information about the Content-Transfer-Encoding
421  * used by a content.
422  */
423
424 static int
425 list_encoding (CT ct)
426 {
427     CE ce;
428
429     if ((ce = ct->c_cefile))
430         fprintf (stderr, "    decoded fp 0x%x file \"%s\"\n",
431                  (unsigned int)(unsigned long) ce->ce_fp,
432                  ce->ce_file ? ce->ce_file : "");
433
434     return OK;
435 }