2 ** show.c -- show/list messages
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.
13 static struct swit switches[] = {
16 #define NOCHECKMIMESW 1
23 { "form formfile", 0 },
25 { "moreproc program", 0 },
29 { "length lines", 0 },
31 { "width columns", 0 },
33 { "showproc program", 0 },
35 { "showmimeproc program", 0 },
37 { "file file", -4 }, /* interface from showfile */
48 static int is_nontext(char *);
50 /* prototype from mhlsbr.c */
51 int mhl(int, char **);
59 main(int argc, char **argv)
61 int headersw = 1, msgp = 0;
62 int checkmime = 1, mime;
63 int vecp = 1, procp = 1, mode = SHOW, msgnum;
64 char *cp, *maildir, *file = NULL, *folder = NULL, *proc;
65 char buf[BUFSIZ], **argp, **arguments;
66 char *msgs[MAXARGS], *vec[MAXARGS];
67 struct msgs *mp = NULL;
70 setlocale(LC_ALL, "");
72 invo_name = mhbasename(argv[0]);
74 /* read user profile/context */
77 if (!mh_strcasecmp(invo_name, "next")) {
79 } else if (!mh_strcasecmp(invo_name, "prev")) {
82 arguments = getarguments(invo_name, argc, argv, 1);
85 while ((cp = *argp++)) {
87 switch (smatch(++cp, switches)) {
89 ambigsw(cp, switches);
97 snprintf(buf, sizeof(buf), "%s [+folder] %s[switches] [switches for showproc]", invo_name, mode == SHOW ? "[msgs] ": "");
98 print_help(buf, switches, 1);
101 print_version(invo_name);
107 adios(NULL, "usage: %s [+folder] [switches] [switches for showproc]", invo_name);
110 adios(NULL, "only one file at a time!");
111 if (!(cp = *argp++) || *cp == '-')
112 adios(NULL, "missing argument to %s", argp[-2]);
113 file = getcpy(expanddir(cp));
125 if (!(cp = *argp++) || *cp == '-')
126 adios(NULL, "missing argument to %s",
128 vec[vecp++] = getcpy(etcpath(cp));
135 if (!(cp = *argp++) || *cp == '-')
136 adios(NULL, "missing argument to %s",
142 if (!(showproc = *argp++) || *showproc == '-')
143 adios(NULL, "missing argument to %s",
148 if (!(showmimeproc = *argp++) ||
149 *showmimeproc == '-')
150 adios(NULL, "missing argument to %s",
161 if (*cp == '+' || *cp == '@') {
163 adios(NULL, "only one folder at a time!");
165 folder = getcpy(expandfol(cp));
166 } else if (mode != SHOW) {
176 adios(NULL, "only one file at a time!");
182 if (!msgp && !folder && mode == SHOW &&
183 (cp = getenv("mhdraft")) && *cp) {
192 msgs[msgp++] = seq_next;
195 msgs[msgp++] = seq_prev;
198 msgs[msgp++] = seq_cur;
204 folder = getcurfol();
205 maildir = toabsdir(folder);
207 if (chdir(maildir) == NOTOK)
208 adios(maildir, "unable to change directory to");
210 /* read folder and create message structure */
211 if (!(mp = folder_read(folder)))
212 adios(NULL, "unable to read folder %s", folder);
214 /* check for empty folder */
216 adios(NULL, "no messages in %s", folder);
218 /* parse all the message ranges/sequences and set SELECTED */
219 for (msgnum = 0; msgnum < msgp; msgnum++)
220 if (!m_convert(mp, msgs[msgnum]))
224 ** Set the SELECT_UNSEEN bit for all the SELECTED messages,
225 ** since we will use that as a tag to know which messages
226 ** to remove from the "unseen" sequence.
228 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
229 if (is_selected(mp, msgnum))
230 set_unseen(mp, msgnum);
232 seq_setprev(mp); /* set the Previous-Sequence */
233 seq_setunseen(mp, 0); /* unset unseen seqs for shown msgs */
235 if (mp->numsel > MAXARGS - 2)
236 adios(NULL, "more than %d messages for show exec",
239 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
240 if (is_selected(mp, msgnum))
241 vec[vecp++] = getcpy(m_name(msgnum));
243 seq_setcur(mp, mp->hghsel); /* update current message */
244 seq_save(mp); /* synchronize sequences */
245 context_replace(curfolder, folder); /* update current folder */
246 context_save(); /* save the context file */
248 if (headersw && vecp == 2)
249 printf("(Message %s:%s)\n", folder, vec[1]);
257 ** Decide which "proc" to use
260 /* check if any messages are non-text MIME messages */
264 ** loop through selected messages
265 ** and check for MIME
267 for (msgnum = mp->lowsel;
268 msgnum <= mp->hghsel;
270 if (is_selected(mp, msgnum) && is_nontext(m_name(msgnum))) {
275 /* check the file for MIME */
276 if (is_nontext(vec[vecp - 1]))
288 m_putenv("mhfolder", folder);
290 /* If the "proc" is "mhshow", add "-file" if showing file. */
291 if (strcmp(mhbasename(proc), "mhshow") == 0 && file ) {
292 vec[vecp] = vec[vecp - 1];
293 vec[vecp - 1] = "-file";
298 ** If "proc" is mhl, then run it internally
299 ** rather than exec'ing it.
301 if (strcmp(mhbasename(proc), "mhl") == 0) {
308 ** If you are not using a nmh command as your "proc", then
309 ** add the path to the message names.
311 if (strcmp(mhbasename(proc), "mhl")==0
314 concat(toabsdir("+"), "/", NULL)) != NOTOK) {
315 mp->foldpath = concat(mp->foldpath, "/", NULL);
316 cp = (strncmp(mp->foldpath, maildir, strlen(maildir))==0) ?
317 mp->foldpath + strlen(maildir) :
319 for (msgnum = procp; msgnum < vecp; msgnum++)
320 vec[msgnum] = concat(cp, vec[msgnum], NULL);
323 vec[0] = mhbasename(proc);
325 adios(proc, "unable to exec");
326 return 0; /* dead code to satisfy the compiler */
330 ** Check if a message or file contains any non-text parts
333 is_nontext(char *msgnam)
336 unsigned char *bp, *dp;
338 char buf[BUFSIZ], name[NAMESZ];
341 if ((fp = fopen(msgnam, "r")) == NULL)
344 for (state = FLD;;) {
345 switch (state = m_getfld(state, name, buf, sizeof(buf), fp)) {
350 ** Check Content-Type field
352 if (!mh_strcasecmp(name, TYPE_FIELD)) {
357 while (state == FLDPLUS) {
358 state = m_getfld(state, name, buf,
366 for (; isspace(*bp); bp++)
371 for (bp++, i = 0;;) {
401 for (dp = bp; istoken(*dp); dp++)
408 if ((result = (mh_strcasecmp(bp,
412 for (dp++; isspace(*dp); dp++)
415 if ((result = !uprf(dp,
418 dp += sizeof("charset") - 1;
426 if ((bp = strchr(++dp, '"')))
429 for (bp = dp; *bp; bp++)
436 /* Default character set */
439 /* Check the character set */
440 result = !check_charset(dp, strlen(dp));
442 if (!(result = (mh_strcasecmp(bp, "text") != 0))) {
459 ** Check Content-Transfer-Encoding field
461 if (!mh_strcasecmp(name, ENCODING_FIELD)) {
463 while (state == FLDPLUS) {
464 state = m_getfld(state, name, buf,
468 for (bp = cp; isspace(*bp); bp++)
470 for (dp = bp; istoken(*dp); dp++)
473 result = (mh_strcasecmp(bp, "7bit")
474 && mh_strcasecmp(bp, "8bit")
475 && mh_strcasecmp(bp, "binary"));
486 ** Just skip the rest of this header
487 ** field and go to next one.
489 while (state == FLDPLUS)
490 state = m_getfld(state, name, buf, sizeof(buf),
495 ** We've passed the message header,
496 ** so message is just text.