source: trunk/third/nmh/uip/show.c @ 13184

Revision 13184, 11.9 KB checked in by danw, 25 years ago (diff)
default to -nocheckmime if showing multiple messages
RevLine 
[12454]1
2/*
3 * show.c -- show/list messages
4 *
[13184]5 * $Id: show.c,v 1.2 1999-06-07 15:56:15 danw Exp $
[12454]6 */
7
8#include <h/mh.h>
9#include <h/mime.h>
10
11static struct swit switches[] = {
12#define CHECKMIMESW          0
13    { "checkmime", 0 },
14#define NOCHECKMIMESW        1
15    { "nocheckmime", 0 },
16#define HEADSW               2
17    { "header", 0 },
18#define NHEADSW              3
19    { "noheader", 0 },
20#define FORMSW               4
21    { "form formfile", 0 },
22#define PROGSW               5
23    { "moreproc program", 0 },
24#define NPROGSW              6
25    { "nomoreproc", 0 },
26#define LENSW                7
27    { "length lines", 0 },
28#define WIDTHSW              8
29    { "width columns", 0 },
30#define SHOWSW               9
31    { "showproc program", 0 },
32#define SHOWMIMESW          10
33    { "showmimeproc program", 0 },
34#define NSHOWSW             11
35    { "noshowproc", 0 },
36#define DRFTSW              12
37    { "draft", 0 },
38#define FILESW              13
39    { "file file", -4 },                /* interface from showfile */
40#define VERSIONSW           14
41    { "version", 0 },
42#define HELPSW              15
43    { "help", 0 },
44    { NULL, 0 }
45};
46
47/*
48 * static prototypes
49 */
50static int is_nontext(char *);
51
52#define SHOW  0
53#define NEXT  1
54#define PREV  2
55
56
57int
58main (int argc, char **argv)
59{
60    int draftsw = 0, headersw = 1, msgp = 0;
61    int nshow = 0, checkmime = 1, mime;
62    int vecp = 1, procp = 1, isdf = 0, mode = SHOW, msgnum;
63    char *cp, *maildir, *file = NULL, *folder = NULL, *proc;
64    char buf[BUFSIZ], **argp, **arguments;
65    char *msgs[MAXARGS], *vec[MAXARGS];
66    struct msgs *mp;
67
68#ifdef LOCALE
69    setlocale(LC_ALL, "");
70#endif
71    invo_name = r1bindex (argv[0], '/');
72
73    /* read user profile/context */
74    context_read();
75
76    if (!strcasecmp (invo_name, "next")) {
77        mode = NEXT;
78    } else if (!strcasecmp (invo_name, "prev")) {
79        mode = PREV;
80    }
81    arguments = getarguments (invo_name, argc, argv, 1);
82    argp = arguments;
83
84    while ((cp = *argp++)) {
85        if (*cp == '-') {
86            switch (smatch (++cp, switches)) {
87                case AMBIGSW:
88                    ambigsw (cp, switches);
89                    done (1);
90                case UNKWNSW:
91                case NPROGSW:
92                    vec[vecp++] = --cp;
93                    continue;
94
95                case HELPSW:
96                    snprintf (buf, sizeof(buf),
97                        "%s [+folder] %s[switches] [switches for showproc]",
98                        invo_name, mode == SHOW ? "[msgs] ": "");
99                    print_help (buf, switches, 1);
100                    done (1);
101                case VERSIONSW:
102                    print_version(invo_name);
103                    done (1);
104
105                case DRFTSW:
106                    if (file)
107                        adios (NULL, "only one file at a time!");
108                    draftsw++;
109                    if (mode == SHOW)
110                        continue;
111usage:
112                    adios (NULL,
113                            "usage: %s [+folder] [switches] [switches for showproc]",
114                            invo_name);
115                case FILESW:
116                    if (mode != SHOW)
117                        goto usage;
118                    if (draftsw || file)
119                        adios (NULL, "only one file at a time!");
120                    if (!(cp = *argp++) || *cp == '-')
121                        adios (NULL, "missing argument to %s", argp[-2]);
122                    file = path (cp, TFILE);
123                    continue;
124
125                case HEADSW:
126                    headersw++;
127                    continue;
128                case NHEADSW:
129                    headersw = 0;
130                    continue;
131
132                case FORMSW:
133                    vec[vecp++] = --cp;
134                    if (!(cp = *argp++) || *cp == '-')
135                        adios (NULL, "missing argument to %s", argp[-2]);
136                    vec[vecp++] = getcpy (etcpath(cp));
137                    continue;
138
139                case PROGSW:
140                case LENSW:
141                case WIDTHSW:
142                    vec[vecp++] = --cp;
143                    if (!(cp = *argp++) || *cp == '-')
144                        adios (NULL, "missing argument to %s", argp[-2]);
145                    vec[vecp++] = cp;
146                    continue;
147
148                case SHOWSW:
149                    if (!(showproc = *argp++) || *showproc == '-')
150                        adios (NULL, "missing argument to %s", argp[-2]);
151                    nshow = 0;
152                    continue;
153                case NSHOWSW:
154                    nshow++;
155                    continue;
156
157                case SHOWMIMESW:
158                    if (!(showmimeproc = *argp++) || *showmimeproc == '-')
159                        adios (NULL, "missing argument to %s", argp[-2]);
160                    nshow = 0;
161                    continue;
162                case CHECKMIMESW:
163                    checkmime++;
164                    continue;
165                case NOCHECKMIMESW:
166                    checkmime = 0;
167                    continue;
168            }
169        }
170        if (*cp == '+' || *cp == '@') {
171            if (folder)
172                adios (NULL, "only one folder at a time!");
173            else
174                folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
175        } else {
176            if (mode != SHOW)
177                goto usage;
178            else
179                msgs[msgp++] = cp;
180        }
181    }
182    procp = vecp;
183
[13184]184    /* If showing multiple messages, default to -nocheckmime.
185     * (But just decrement it rather than setting to 0, so user
186     * can specify -checkmime to override.
187     */
188    if (msgp > 1)
189      checkmime--;
190
[12454]191    if (!context_find ("path"))
192        free (path ("./", TFOLDER));
193
194    if (draftsw || file) {
195        if (msgp)
196            adios (NULL, "only one file at a time!");
197        vec[vecp++] = draftsw
198            ? getcpy (m_draft (folder, msgp ? msgs[0] : NULL, 1, &isdf))
199            : file;
200        goto go_to_it;
201    }
202
203#ifdef WHATNOW
204    if (!msgp && !folder && mode == SHOW && (cp = getenv ("mhdraft")) && *cp) {
205        draftsw++;
206        vec[vecp++] = cp;
207        goto go_to_it;
208    }
209#endif /* WHATNOW */
210
211    if (!msgp) {
212        switch (mode) {
213            case NEXT:
214                msgs[msgp++] = "next";
215                break;
216            case PREV:
217                msgs[msgp++] = "prev";
218                break;
219            default:
220                msgs[msgp++] = "cur";
221                break;
222        }
223    }
224
225    if (!folder)
226        folder = getfolder (1);
227    maildir = m_maildir (folder);
228
229    if (chdir (maildir) == NOTOK)
230        adios (maildir, "unable to change directory to");
231
232    /* read folder and create message structure */
233    if (!(mp = folder_read (folder)))
234        adios (NULL, "unable to read folder %s", folder);
235
236    /* check for empty folder */
237    if (mp->nummsg == 0)
238        adios (NULL, "no messages in %s", folder);
239
240    /* parse all the message ranges/sequences and set SELECTED */
241    for (msgnum = 0; msgnum < msgp; msgnum++)
242        if (!m_convert (mp, msgs[msgnum]))
243            done (1);
244
245    /*
246     * Set the SELECT_UNSEEN bit for all the SELECTED messages,
247     * since we will use that as a tag to know which messages
248     * to remove from the "unseen" sequence.
249     */
250    for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
251        if (is_selected(mp, msgnum))
252            set_unseen (mp, msgnum);
253
254    seq_setprev (mp);           /* set the Previous-Sequence */
255    seq_setunseen (mp, 1);      /* unset the Unseen-Sequence */
256
257    if (mp->numsel > MAXARGS - 2)
258        adios (NULL, "more than %d messages for show exec", MAXARGS - 2);
259
260    for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
261        if (is_selected(mp, msgnum))
262            vec[vecp++] = getcpy (m_name (msgnum));
263
264    seq_setcur (mp, mp->hghsel);        /* update current message  */
265    seq_save (mp);                      /* synchronize sequences   */
266    context_replace (pfolder, folder);  /* update current folder   */
267    context_save ();                    /* save the context file   */
268
269    if (headersw && vecp == 2)
270        printf ("(Message %s:%s)\n", folder, vec[1]);
271
272go_to_it: ;
273    fflush (stdout);
274
275    vec[vecp] = NULL;
276
277    /*
278     * Decide which "proc" to use
279     */
280    mime = 0;
281    if (nshow) {
282        proc = catproc;
283    } else {
284        /* check if any messages are non-text MIME messages */
285        if (checkmime && !getenv ("NOMHNPROC")) {
286            if (!draftsw && !file) {
287                /* loop through selected messages and check for MIME */
288                for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
289                    if (is_selected (mp, msgnum) && is_nontext (m_name (msgnum))) {
290                        mime = 1;
291                        break;
292                    }
293            } else {
294                /* check the file or draft for MIME */
295                if (is_nontext (vec[vecp - 1]))
296                    mime = 1;
297            }
298        }
299
300        /* Set the "proc" */
301        if (mime)
302            proc = showmimeproc;
303        else
304            proc = showproc;
305    }
306
307    if (folder && !draftsw && !file)
308        m_putenv ("mhfolder", folder);
309
310    /*
311     * For backward compatibility, if the "proc" is mhn,
312     * then add "-show" option.  Add "-file" if showing
313     * file or draft.
314     */
315    if (strcmp (r1bindex (proc, '/'), "mhn") == 0) {
316        if (draftsw || file) {
317            vec[vecp] = vec[vecp - 1];
318            vec[vecp - 1] = "-file";
319            vecp++;
320        }
321        vec[vecp++] = "-show";
322        vec[vecp] = NULL;
323    }
324
325    /*
326     * If "proc" is mhl, then run it internally
327     * rather than exec'ing it.
328     */
329    if (strcmp (r1bindex (proc, '/'), "mhl") == 0) {
330        vec[0] = "mhl";
331        mhl (vecp, vec);
332        done (0);
333    }
334
335    /*
336     * If you are not using a nmh command as your "proc", then
337     * add the path to the message names.  Currently, we are just
338     * checking for mhn here, since we've already taken care of mhl.
339     */
340    if (!strcmp (r1bindex (proc, '/'), "mhl")
341            && !draftsw
342            && !file
343            && chdir (maildir = concat (m_maildir (""), "/", NULL)) != NOTOK) {
344        mp->foldpath = concat (mp->foldpath, "/", NULL);
345        cp = ssequal (maildir, mp->foldpath)
346            ? mp->foldpath + strlen (maildir)
347            : mp->foldpath;
348        for (msgnum = procp; msgnum < vecp; msgnum++)
349            vec[msgnum] = concat (cp, vec[msgnum], NULL);
350    }
351
352    vec[0] = r1bindex (proc, '/');
353    execvp (proc, vec);
354    adios (proc, "unable to exec");
355}
356
357/*
358 * Cheat:  we are loaded with adrparse, which wants a routine called
359 * OfficialName().  We call adrparse:getm() with the correct arguments
360 * to prevent OfficialName() from being called.  Hence, the following
361 * is to keep the loader happy.
362 */
363
364char *
365OfficialName (char *name)
366{
367    return name;
368}
369
370
371/*
372 * Check if a message or file contains any non-text parts
373 */
374static int
375is_nontext (char *msgnam)
376{
377    int result, state;
378    char *bp, *cp, *dp;
379    char buf[BUFSIZ], name[NAMESZ];
380    FILE *fp;
381
382    if ((fp = fopen (msgnam, "r")) == NULL)
383        return 0;
384
385    for (state = FLD;;) {
386        switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) {
387        case FLD:
388        case FLDPLUS:
389        case FLDEOF:
390            /*
391             * Check Content-Type field
392             */
393            if (!strcasecmp (name, TYPE_FIELD)) {
394                int passno;
395                char c;
396
397                cp = add (buf, NULL);
398                while (state == FLDPLUS) {
399                    state = m_getfld (state, name, buf, sizeof(buf), fp);
400                    cp = add (buf, cp);
401                }
402                bp = cp;
403                passno = 1;
404
405again:
406                for (; isspace (*bp); bp++)
407                    continue;
408                if (*bp == '(') {
409                    int i;
410
411                    for (bp++, i = 0;;) {
412                        switch (*bp++) {
413                        case '\0':
414invalid:
415                            result = 0;
416                            goto out;
417                        case '\\':
418                            if (*bp++ == '\0')
419                                goto invalid;
420                            continue;
421                        case '(':
422                            i++;
423                            /* and fall... */
424                        default:
425                            continue;
426                        case ')':
427                            if (--i < 0)
428                                break;
429                            continue;
430                        }
431                        break;
432                    }
433                }
434                if (passno == 2) {
435                    if (*bp != '/')
436                        goto invalid;
437                    bp++;
438                    passno = 3;
439                    goto again;
440                }
441                for (dp = bp; istoken (*dp); dp++)
442                    continue;
443                c = *dp;
444                *dp = '\0';
445                if (!*bp)
446                    goto invalid;
447                if (passno > 1) {
448                    if ((result = (strcasecmp (bp, "plain") != 0)))
449                        goto out;
450                    *dp = c;
451                    for (dp++; isspace (*dp); dp++)
452                        continue;
453                    if (*dp) {
454                        if ((result = !uprf (dp, "charset")))
455                            goto out;
456                        dp += sizeof("charset") - 1;
457                        while (isspace (*dp))
458                            dp++;
459                        if (*dp++ != '=')
460                            goto invalid;
461                        while (isspace (*dp))
462                            dp++;
463                        if (*dp == '"') {
464                            if ((bp = strchr(++dp, '"')))
465                                *bp = '\0';
466                        } else {
467                            for (bp = dp; *bp; bp++)
468                                if (isspace (*bp)) {
469                                    *bp = '\0';
470                                    break;
471                                }
472                        }
473                    } else {
474                        /* Default character set */
475                        dp = "US-ASCII";
476                    }
477                    /* Check the character set */
478                    result = !check_charset (dp, strlen (dp));
479                } else {
480                    if (!(result = (strcasecmp (bp, "text") != 0))) {
481                        *dp = c;
482                        bp = dp;
483                        passno = 2;
484                        goto again;
485                    }
486                }
487out:
488                free (cp);
489                if (result) {
490                    fclose (fp);
491                    return result;
492                }
493                break;
494            }
495
496            /*
497             * Check Content-Transfer-Encoding field
498             */
499            if (!strcasecmp (name, ENCODING_FIELD)) {
500                cp = add (buf, NULL);
501                while (state == FLDPLUS) {
502                    state = m_getfld (state, name, buf, sizeof(buf), fp);
503                    cp = add (buf, cp);
504                }
505                for (bp = cp; isspace (*bp); bp++)
506                    continue;
507                for (dp = bp; istoken (*dp); dp++)
508                    continue;
509                *dp = '\0';
510                result = (strcasecmp (bp, "7bit")
511                       && strcasecmp (bp, "8bit")
512                       && strcasecmp (bp, "binary"));
513
514                free (cp);
515                if (result) {
516                    fclose (fp);
517                    return result;
518                }
519                break;
520            }
521
522            /*
523             * Just skip the rest of this header
524             * field and go to next one.
525             */
526            while (state == FLDPLUS)
527                state = m_getfld (state, name, buf, sizeof(buf), fp);
528            break;
529
530            /*
531             * We've passed the message header,
532             * so message is just text.
533             */
534        default:
535            fclose (fp);
536            return 0;
537        }
538    }
539}
Note: See TracBrowser for help on using the repository browser.