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