Replaced mkinstalldirs with `mkdir -p'.
[mmh] / uip / mhlistsbr.c
1 /*
2 ** mhlistsbr.c -- routines to list information about the
3 **             -- contents of MIME messages
4 **
5 ** This code is Copyright (c) 2002, by the authors of nmh.  See the
6 ** COPYRIGHT file in the root directory of the nmh distribution for
7 ** complete copyright information.
8 */
9
10 #include <h/mh.h>
11 #include <fcntl.h>
12 #include <h/signals.h>
13 #include <errno.h>
14 #include <signal.h>
15 #include <h/tws.h>
16 #include <h/mime.h>
17 #include <h/mhparse.h>
18 #include <h/utils.h>
19
20 /* mhmisc.c */
21 int part_ok(CT, int);
22 int type_ok(CT, int);
23 void flush_errors(void);
24
25 /*
26 ** prototypes
27 */
28 void list_all_messages(CT *, int, int, int, int);
29 int list_switch(CT, int, int, int, int);
30 int list_content(CT, int, int, int, int);
31
32 /*
33 ** static prototypes
34 */
35 static void list_single_message(CT, int, int, int);
36 static int list_debug(CT);
37 static int list_multi(CT, int, int, int, int);
38 static int list_partial(CT, int, int, int, int);
39 static int list_external(CT, int, int, int, int);
40 static int list_application(CT, int, int, int, int);
41 static int list_encoding(CT);
42
43
44 /*
45 ** various formats for -list option
46 */
47 #define LSTFMT1    "%4s %-5s %-24s %5s %-36s\n"
48 #define LSTFMT2a   "%4d "
49 #define LSTFMT2b   "%-5s %-24.24s "
50 #define LSTFMT2c1  "%5lu"
51 #define LSTFMT2c2  "%4lu%c"
52 #define LSTFMT2c3  "huge "
53 #define LSTFMT2c4  "     "
54 #define LSTFMT2d1  " %-36.36s"
55 #define LSTFMT2d2  "\t     %-65.65s\n"
56
57
58 /*
59 ** Top level entry point to list group of messages
60 */
61
62 void
63 list_all_messages(CT *cts, int headers, int realsize, int verbose, int debug)
64 {
65         CT ct, *ctp;
66
67         if (headers)
68                 printf(LSTFMT1, "msg", "part", "type/subtype", "size",
69                                 "description");
70
71         for (ctp = cts; *ctp; ctp++) {
72                 ct = *ctp;
73                 list_single_message(ct, realsize, verbose, debug);
74         }
75
76         flush_errors();
77 }
78
79
80 /*
81 ** Entry point to list a single message
82 */
83
84 static void
85 list_single_message(CT ct, int realsize, int verbose, int debug)
86 {
87         if (type_ok(ct, 1)) {
88                 umask(ct->c_umask);
89                 list_switch(ct, 1, realsize, verbose, debug);
90                 if (ct->c_fp) {
91                         fclose(ct->c_fp);
92                         ct->c_fp = NULL;
93                 }
94                 if (ct->c_ceclosefnx)
95                         (*ct->c_ceclosefnx) (ct);
96         }
97 }
98
99
100 /*
101 ** Primary switching routine to list information about a content
102 */
103
104 int
105 list_switch(CT ct, int toplevel, int realsize, int verbose, int debug)
106 {
107         switch (ct->c_type) {
108         case CT_MULTIPART:
109                 return list_multi(ct, toplevel, realsize, verbose, debug);
110                 break;
111
112         case CT_MESSAGE:
113                 switch (ct->c_subtype) {
114                 case MESSAGE_PARTIAL:
115                         return list_partial(ct, toplevel, realsize, verbose,
116                                                 debug);
117                         break;
118
119                 case MESSAGE_EXTERNAL:
120                         return list_external(ct, toplevel, realsize, verbose,
121                                                 debug);
122                         break;
123
124                 case MESSAGE_RFC822:
125                 default:
126                         return list_content(ct, toplevel, realsize, verbose,
127                                                 debug);
128                         break;
129                 }
130                 break;
131
132         case CT_TEXT:
133         case CT_AUDIO:
134         case CT_IMAGE:
135         case CT_VIDEO:
136                 return list_content(ct, toplevel, realsize, verbose, debug);
137                 break;
138
139         case CT_APPLICATION:
140                 return list_application(ct, toplevel, realsize, verbose,
141                                 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(mhbasename(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 = getcpy(ct->c_descr));
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 = getcpy(ci->ci_comment));
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,
268                          (unsigned int)(unsigned long) ct->c_ctparams);
269
270         fprintf(stderr, "    showproc  \"%s\"\n", empty(ct->c_showproc));
271         fprintf(stderr, "    termproc  \"%s\"\n", empty(ct->c_termproc));
272         fprintf(stderr, "    storeproc \"%s\"\n", empty(ct->c_storeproc));
273
274         /* print transfer encoding information */
275         if (ct->c_celine)
276                 fprintf(stderr, "  %s:%s", ENCODING_FIELD, ct->c_celine);
277
278         /* print internal flags for transfer encoding */
279         fprintf(stderr, "    transfer encoding 0x%x params 0x%x\n",
280                         ct->c_encoding,
281                         (unsigned int)(unsigned long) ct->c_cefile);
282
283         /* print Content-ID */
284         if (ct->c_id)
285                 fprintf(stderr, "  %s:%s", ID_FIELD, ct->c_id);
286
287         /* print Content-Description */
288         if (ct->c_descr)
289                 fprintf(stderr, "  %s:%s", DESCR_FIELD, ct->c_descr);
290
291         fprintf(stderr, "    read fp 0x%x file \"%s\" begin %ld end %ld\n",
292                         (unsigned int)(unsigned long) ct->c_fp,
293                         empty(ct->c_file), ct->c_begin, ct->c_end);
294
295         /* print more information about transfer encoding */
296         list_encoding(ct);
297
298         return OK;
299 }
300
301 #undef empty
302
303
304 /*
305 ** list content information for type "multipart"
306 */
307
308 static int
309 list_multi(CT ct, int toplevel, int realsize, int verbose, int debug)
310 {
311         struct multipart *m = (struct multipart *) ct->c_ctparams;
312         struct part *part;
313
314         /* list the content for toplevel of this multipart */
315         list_content(ct, toplevel, realsize, verbose, debug);
316
317         /* now list for all the subparts */
318         for (part = m->mp_parts; part; part = part->mp_next) {
319                 CT p = part->mp_part;
320
321                 if (part_ok(p, 1) && type_ok(p, 1))
322                         list_switch(p, 0, realsize, verbose, debug);
323         }
324
325         return OK;
326 }
327
328
329 /*
330 ** list content information for type "message/partial"
331 */
332
333 static int
334 list_partial(CT ct, int toplevel, int realsize, int verbose, int debug)
335 {
336         struct partial *p = (struct partial *) ct->c_ctparams;
337
338         list_content(ct, toplevel, realsize, verbose, debug);
339         if (verbose) {
340                 printf("\t     [message %s, part %d",
341                                 p->pm_partid, p->pm_partno);
342                 if (p->pm_maxno)
343                         printf(" of %d", p->pm_maxno);
344                 printf("]\n");
345         }
346
347         return OK;
348 }
349
350
351 /*
352 ** list content information for type "message/external"
353 */
354
355 static int
356 list_external(CT ct, int toplevel, int realsize, int verbose, int debug)
357 {
358         struct exbody *e = (struct exbody *) ct->c_ctparams;
359
360         /*
361          * First list the information for the
362          * message/external content itself.
363          */
364         list_content(ct, toplevel, realsize, verbose, debug);
365
366         if (verbose) {
367                 if (e->eb_name)
368                         printf("\t     name=\"%s\"\n", e->eb_name);
369                 if (e->eb_dir)
370                         printf("\t     directory=\"%s\"\n", e->eb_dir);
371                 if (e->eb_site)
372                         printf("\t     site=\"%s\"\n", e->eb_site);
373                 if (e->eb_server)
374                         printf("\t     server=\"%s\"\n", e->eb_server);
375                 if (e->eb_subject)
376                         printf("\t     subject=\"%s\"\n", e->eb_subject);
377
378                 /* This must be defined */
379                 printf("\t     access-type=\"%s\"\n", e->eb_access);
380
381                 if (e->eb_mode)
382                         printf("\t     mode=\"%s\"\n", e->eb_mode);
383                 if (e->eb_permission)
384                         printf("\t     permission=\"%s\"\n", e->eb_permission);
385
386                 if (e->eb_flags == NOTOK)
387                         printf("\t     [service unavailable]\n");
388         }
389
390         /*
391         ** Now list the information for the external content
392         ** to which this content points.
393         */
394         list_content(e->eb_content, 0, realsize, verbose, debug);
395
396         return OK;
397 }
398
399
400 /*
401 ** list content information for type "application"
402 */
403
404 static int
405 list_application(CT ct, int toplevel, int realsize, int verbose, int debug)
406 {
407         list_content(ct, toplevel, realsize, verbose, debug);
408         if (verbose) {
409                 char **ap, **ep;
410                 CI ci = &ct->c_ctinfo;
411
412                 for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++)
413                         printf("\t     %s=\"%s\"\n", *ap, *ep);
414         }
415
416         return OK;
417 }
418
419
420 /*
421 ** list information about the Content-Transfer-Encoding
422 ** used by a content.
423 */
424
425 static int
426 list_encoding(CT ct)
427 {
428         CE ce;
429
430         if ((ce = ct->c_cefile))
431                 fprintf(stderr, "    decoded fp 0x%x file \"%s\"\n",
432                         (unsigned int)(unsigned long) ce->ce_fp,
433                         ce->ce_file ? ce->ce_file : "");
434
435         return OK;
436 }