[bug #4302] errno is not always an extern int
[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 /* mhmisc.c */
24 int part_ok (CT, int);
25 int type_ok (CT, int);
26 void flush_errors (void);
27
28 /*
29  * prototypes
30  */
31 void list_all_messages (CT *, int, int, int, int);
32 int list_switch (CT, int, int, int, int);
33 int list_content (CT, int, int, int, int);
34
35 /*
36  * static prototypes
37  */
38 static void list_single_message (CT, int, int, int);
39 static int list_debug (CT);
40 static int list_multi (CT, int, int, int, int);
41 static int list_partial (CT, int, int, int, int);
42 static int list_external (CT, int, int, int, int);
43 static int list_application (CT, int, int, int, int);
44 static int list_encoding (CT);
45
46
47 /*
48  * various formats for -list option
49  */
50 #define LSTFMT1         "%4s %-5s %-24s %5s %-36s\n"
51 #define LSTFMT2a        "%4d "
52 #define LSTFMT2b        "%-5s %-24.24s "
53 #define LSTFMT2c1       "%5lu"
54 #define LSTFMT2c2       "%4lu%c"
55 #define LSTFMT2c3       "huge "
56 #define LSTFMT2c4       "     "
57 #define LSTFMT2d1       " %-36.36s"
58 #define LSTFMT2d2       "\t     %-65.65s\n"
59
60
61 /*
62  * Top level entry point to list group of messages
63  */
64
65 void
66 list_all_messages (CT *cts, int headers, int realsize, int verbose, int debug)
67 {
68     CT ct, *ctp;
69
70     if (headers)
71         printf (LSTFMT1, "msg", "part", "type/subtype", "size", "description");
72
73     for (ctp = cts; *ctp; ctp++) {
74         ct = *ctp;
75         list_single_message (ct, realsize, verbose, debug);
76     }
77
78     flush_errors ();
79 }
80
81
82 /*
83  * Entry point to list a single message
84  */
85
86 static void
87 list_single_message (CT ct, int realsize, int verbose, int debug)
88 {
89     if (type_ok (ct, 1)) {
90         umask (ct->c_umask);
91         list_switch (ct, 1, realsize, verbose, debug);
92         if (ct->c_fp) {
93             fclose (ct->c_fp);
94             ct->c_fp = NULL;
95         }
96         if (ct->c_ceclosefnx)
97             (*ct->c_ceclosefnx) (ct);
98     }
99 }
100
101
102 /*
103  * Primary switching routine to list information about a content
104  */
105
106 int
107 list_switch (CT ct, int toplevel, int realsize, int verbose, int debug)
108 {
109     switch (ct->c_type) {
110         case CT_MULTIPART:
111             return list_multi (ct, toplevel, realsize, verbose, debug);
112             break;
113
114         case CT_MESSAGE:
115             switch (ct->c_subtype) {
116                 case MESSAGE_PARTIAL:
117                     return list_partial (ct, toplevel, realsize, verbose, debug);
118                     break;
119
120                 case MESSAGE_EXTERNAL:
121                     return list_external (ct, toplevel, realsize, verbose, debug);
122                     break;
123
124                 case MESSAGE_RFC822:
125                 default:
126                     return list_content (ct, toplevel, realsize, verbose, debug);
127                     break;
128             }
129             break;
130
131         case CT_TEXT:
132         case CT_AUDIO:
133         case CT_IMAGE:
134         case CT_VIDEO:
135             return list_content (ct, toplevel, realsize, verbose, debug);
136             break;
137
138         case CT_APPLICATION:
139             return list_application (ct, toplevel, realsize, verbose, debug);
140             break;
141
142         default:
143             /* list_debug (ct); */
144             adios (NULL, "unknown content type %d", ct->c_type);
145             break;
146     }
147
148     return 0;   /* NOT REACHED */
149 }
150
151
152 #define empty(s) ((s) ? (s) : "")
153
154 /*
155  * Method for listing information about a simple/generic content
156  */
157
158 int
159 list_content (CT ct, int toplevel, int realsize, int verbose, int debug)
160 {
161     unsigned long size;
162     char *cp, buffer[BUFSIZ];
163     CI ci = &ct->c_ctinfo;
164
165     printf (toplevel > 0 ? LSTFMT2a : toplevel < 0 ? "part " : "     ",
166             atoi (r1bindex (empty (ct->c_file), '/')));
167     snprintf (buffer, sizeof(buffer), "%s/%s", empty (ci->ci_type),
168                 empty (ci->ci_subtype));
169     printf (LSTFMT2b, empty (ct->c_partno), buffer);
170
171     if (ct->c_cesizefnx && realsize)
172         size = (*ct->c_cesizefnx) (ct);
173     else
174         size = ct->c_end - ct->c_begin;
175
176     /* find correct scale for size (Kilo/Mega/Giga/Tera) */
177     for (cp = " KMGT"; size > 9999; size >>= 10)
178         if (!*++cp)
179             break;
180
181     /* print size of this body part */
182     switch (*cp) {
183         case ' ':
184             if (size > 0 || ct->c_encoding != CE_EXTERNAL)
185                 printf (LSTFMT2c1, size);
186             else
187                 printf (LSTFMT2c4);
188             break;
189
190         default:
191             printf (LSTFMT2c2, size, *cp);
192             break;
193
194         case '\0':
195             printf (LSTFMT2c3);
196     }
197
198     /* print Content-Description */
199     if (ct->c_descr) {
200         char *dp;
201
202         dp = trimcpy (cp = add (ct->c_descr, NULL));
203         free (cp);
204         printf (LSTFMT2d1, dp);
205         free (dp);
206     }
207
208     printf ("\n");
209
210     /*
211      * If verbose, print any RFC-822 comments in the
212      * Content-Type line.
213      */
214     if (verbose && ci->ci_comment) {
215         char *dp;
216
217         dp = trimcpy (cp = add (ci->ci_comment, NULL));
218         free (cp);
219         snprintf (buffer, sizeof(buffer), "(%s)", dp);
220         free (dp);
221         printf (LSTFMT2d2, buffer);
222     }
223
224     if (debug)
225         list_debug (ct);
226
227     return OK;
228 }
229
230
231 /*
232  * Print debugging information about a content
233  */
234
235 static int
236 list_debug (CT ct)
237 {
238     char **ap, **ep;
239     CI ci = &ct->c_ctinfo;
240
241     fflush (stdout);
242     fprintf (stderr, "  partno \"%s\"\n", empty (ct->c_partno));
243
244     /* print MIME-Version line */
245     if (ct->c_vrsn)
246         fprintf (stderr, "  %s:%s\n", VRSN_FIELD, ct->c_vrsn);
247
248     /* print Content-Type line */
249     if (ct->c_ctline)
250         fprintf (stderr, "  %s:%s\n", TYPE_FIELD, ct->c_ctline);
251
252     /* print parsed elements of content type */
253     fprintf (stderr, "    type    \"%s\"\n", empty (ci->ci_type));
254     fprintf (stderr, "    subtype \"%s\"\n", empty (ci->ci_subtype));
255     fprintf (stderr, "    comment \"%s\"\n", empty (ci->ci_comment));
256     fprintf (stderr, "    magic   \"%s\"\n", empty (ci->ci_magic));
257
258     /* print parsed parameters attached to content type */
259     fprintf (stderr, "    parameters\n");
260     for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++)
261         fprintf (stderr, "      %s=\"%s\"\n", *ap, *ep);
262
263     /* print internal flags for type/subtype */
264     fprintf (stderr, "    type 0x%x subtype 0x%x params 0x%x\n",
265              ct->c_type, ct->c_subtype, (unsigned int) 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) 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) 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) ce->ce_fp, ce->ce_file ? ce->ce_file : "");
428
429     return OK;
430 }