]> diplodocus.org Git - nmh/blob - uip/mhlist.c
a9be19e1ca65add659a8b9e3a66949d85e693f49
[nmh] / uip / mhlist.c
1 /* mhlist.c -- list the contents of MIME messages
2 *
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
6 */
7
8 #include <h/mh.h>
9 #include <fcntl.h>
10 #include <h/signals.h>
11 #include <h/md5.h>
12 #include <h/mts.h>
13 #include <h/tws.h>
14 #include <h/mime.h>
15 #include <h/mhparse.h>
16 #include <h/mhcachesbr.h>
17 #include <h/utils.h>
18 #include "mhmisc.h"
19 #include "../sbr/m_maildir.h"
20 #include "mhfree.h"
21
22 #define MHLIST_SWITCHES \
23 X("check", 0, CHECKSW) \
24 X("nocheck", 0, NCHECKSW) \
25 X("headers", 0, HEADSW) \
26 X("noheaders", 0, NHEADSW) \
27 X("realsize", 0, SIZESW) \
28 X("norealsize", 0, NSIZESW) \
29 X("verbose", 0, VERBSW) \
30 X("noverbose", 0, NVERBSW) \
31 X("disposition", 0, DISPOSW) \
32 X("nodisposition", 0, NDISPOSW) \
33 X("file file", 0, FILESW) \
34 X("part number", 0, PARTSW) \
35 X("type content", 0, TYPESW) \
36 X("prefer content", 0, PREFERSW) \
37 X("rcache policy", 0, RCACHESW) \
38 X("wcache policy", 0, WCACHESW) \
39 X("changecur", 0, CHGSW) \
40 X("nochangecur", 0, NCHGSW) \
41 X("version", 0, VERSIONSW) \
42 X("help", 0, HELPSW) \
43 X("debug", -5, DEBUGSW) \
44
45 #define X(sw, minchars, id) id,
46 DEFINE_SWITCH_ENUM(MHLIST);
47 #undef X
48
49 #define X(sw, minchars, id) { sw, minchars, id },
50 DEFINE_SWITCH_ARRAY(MHLIST, switches);
51 #undef X
52
53 /*
54 * This is currently needed to keep mhparse happy.
55 * This needs to be changed.
56 */
57 int debugsw = 0;
58
59 #define quitser pipeser
60
61 /*
62 * static prototypes
63 */
64 static void pipeser (int);
65
66
67 int
68 main (int argc, char **argv)
69 {
70 int sizesw = 1, headsw = 1, chgflag = 1, verbosw = 0, dispo = 0;
71 int msgnum, *icachesw;
72 char *cp, *file = NULL, *folder = NULL;
73 char *maildir, buf[100], **argp;
74 char **arguments;
75 struct msgs_array msgs = { 0, 0, NULL };
76 struct msgs *mp = NULL;
77 CT ct, *ctp;
78
79 if (nmh_init(argv[0], 1)) { return 1; }
80
81 done=freects_done;
82
83 arguments = getarguments (invo_name, argc, argv, 1);
84 argp = arguments;
85
86 /*
87 * Parse arguments
88 */
89 while ((cp = *argp++)) {
90 if (*cp == '-') {
91 switch (smatch (++cp, switches)) {
92 case AMBIGSW:
93 ambigsw (cp, switches);
94 done (1);
95 case UNKWNSW:
96 adios (NULL, "-%s unknown", cp);
97
98 case HELPSW:
99 snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]",
100 invo_name);
101 print_help (buf, switches, 1);
102 done (0);
103 case VERSIONSW:
104 print_version(invo_name);
105 done (0);
106
107 case RCACHESW:
108 icachesw = &rcachesw;
109 goto do_cache;
110 case WCACHESW:
111 icachesw = &wcachesw;
112 do_cache:
113 if (!(cp = *argp++) || *cp == '-')
114 adios (NULL, "missing argument to %s", argp[-2]);
115 switch (*icachesw = smatch (cp, cache_policy)) {
116 case AMBIGSW:
117 ambigsw (cp, cache_policy);
118 done (1);
119 case UNKWNSW:
120 adios (NULL, "%s unknown", cp);
121 default:
122 break;
123 }
124 continue;
125
126 case CHECKSW:
127 checksw++;
128 continue;
129 case NCHECKSW:
130 checksw = 0;
131 continue;
132
133 case HEADSW:
134 headsw = 1;
135 continue;
136 case NHEADSW:
137 headsw = 0;
138 continue;
139
140 case SIZESW:
141 sizesw = 1;
142 continue;
143 case NSIZESW:
144 sizesw = 0;
145 continue;
146
147 case PARTSW:
148 if (!(cp = *argp++) || *cp == '-')
149 adios (NULL, "missing argument to %s", argp[-2]);
150 if (npart >= NPARTS)
151 adios (NULL, "too many parts (starting with %s), %d max",
152 cp, NPARTS);
153 parts[npart++] = cp;
154 continue;
155
156 case TYPESW:
157 if (!(cp = *argp++) || *cp == '-')
158 adios (NULL, "missing argument to %s", argp[-2]);
159 if (ntype >= NTYPES)
160 adios (NULL, "too many types (starting with %s), %d max",
161 cp, NTYPES);
162 types[ntype++] = cp;
163 continue;
164
165 case PREFERSW:
166 if (!(cp = *argp++) || *cp == '-')
167 adios (NULL, "missing argument to %s", argp[-2]);
168 if (npreferred >= NPREFS)
169 adios (NULL, "too many preferred types (starting with %s), %d max",
170 cp, NPREFS);
171 preferred_types[npreferred] = cp;
172 cp = strchr(cp, '/');
173 if (cp) *cp++ = '\0';
174 preferred_subtypes[npreferred++] = cp;
175 continue;
176
177 case FILESW:
178 if (!(cp = *argp++) || (*cp == '-' && cp[1]))
179 adios (NULL, "missing argument to %s", argp[-2]);
180 file = *cp == '-' ? cp : path (cp, TFILE);
181 continue;
182
183 case CHGSW:
184 chgflag++;
185 continue;
186 case NCHGSW:
187 chgflag = 0;
188 continue;
189
190 case VERBSW:
191 verbosw = 1;
192 continue;
193 case NVERBSW:
194 verbosw = 0;
195 continue;
196 case DISPOSW:
197 dispo = 1;
198 continue;
199 case NDISPOSW:
200 dispo = 0;
201 continue;
202 case DEBUGSW:
203 debugsw = 1;
204 continue;
205 }
206 }
207 if (*cp == '+' || *cp == '@') {
208 if (folder)
209 adios (NULL, "only one folder at a time!");
210 folder = pluspath (cp);
211 } else
212 app_msgarg(&msgs, cp);
213 }
214
215 /* null terminate the list of acceptable parts/types */
216 parts[npart] = NULL;
217 types[ntype] = NULL;
218
219 /* Check for public cache location */
220 if ((cache_public = context_find (nmhcache)) && *cache_public != '/')
221 cache_public = NULL;
222
223 /* Check for private cache location */
224 if (!(cache_private = context_find (nmhprivcache)))
225 cache_private = ".cache";
226 cache_private = getcpy (m_maildir (cache_private));
227
228 if (!context_find ("path"))
229 free (path ("./", TFOLDER));
230
231 if (file && msgs.size)
232 adios (NULL, "cannot specify msg and file at same time!");
233
234 /*
235 * check if message is coming from file
236 */
237 if (file) {
238 cts = mh_xcalloc(2, sizeof *cts);
239 ctp = cts;
240
241 if ((ct = parse_mime (file)))
242 *ctp++ = ct;
243 } else {
244 /*
245 * message(s) are coming from a folder
246 */
247 if (!msgs.size)
248 app_msgarg(&msgs, "cur");
249 if (!folder)
250 folder = getfolder (1);
251 maildir = m_maildir (folder);
252
253 if (chdir (maildir) == NOTOK)
254 adios (maildir, "unable to change directory to");
255
256 /* read folder and create message structure */
257 if (!(mp = folder_read (folder, 0)))
258 adios (NULL, "unable to read folder %s", folder);
259
260 /* check for empty folder */
261 if (mp->nummsg == 0)
262 adios (NULL, "no messages in %s", folder);
263
264 /* parse all the message ranges/sequences and set SELECTED */
265 for (msgnum = 0; msgnum < msgs.size; msgnum++)
266 if (!m_convert (mp, msgs.msgs[msgnum]))
267 done (1);
268 seq_setprev (mp); /* set the previous-sequence */
269
270 cts = mh_xcalloc(mp->numsel + 1, sizeof *cts);
271 ctp = cts;
272
273 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
274 if (is_selected(mp, msgnum)) {
275 char *msgnam;
276
277 msgnam = m_name (msgnum);
278 if ((ct = parse_mime (msgnam)))
279 *ctp++ = ct;
280 }
281 }
282 }
283
284 if (!*cts)
285 done (1);
286
287 userrs = 1;
288 SIGNAL (SIGQUIT, quitser);
289 SIGNAL (SIGPIPE, pipeser);
290
291 /*
292 * Get the associated umask for the relevant contents.
293 */
294 for (ctp = cts; *ctp; ctp++) {
295 struct stat st;
296
297 ct = *ctp;
298 if (type_ok (ct, 1) && !ct->c_umask) {
299 if (stat (ct->c_file, &st) != NOTOK)
300 ct->c_umask = ~(st.st_mode & 0777);
301 else
302 ct->c_umask = ~m_gmprot();
303 }
304 }
305
306 /*
307 * List the message content
308 */
309 list_all_messages (cts, headsw, sizesw, verbosw, debugsw, dispo);
310
311 /* Now free all the structures for the content */
312 for (ctp = cts; *ctp; ctp++)
313 free_content (*ctp);
314
315 free(cts);
316 cts = NULL;
317
318 /* If reading from a folder, do some updating */
319 if (mp) {
320 context_replace (pfolder, folder);/* update current folder */
321 if (chgflag)
322 seq_setcur (mp, mp->hghsel); /* update current message */
323 seq_save (mp); /* synchronize sequences */
324 context_save (); /* save the context file */
325 }
326
327 done (0);
328 return 1;
329 }
330
331
332 static void
333 pipeser (int i)
334 {
335 if (i == SIGQUIT) {
336 fflush (stdout);
337 fprintf (stderr, "\n");
338 fflush (stderr);
339 }
340
341 done (1);
342 /* NOTREACHED */
343 }