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