source: trunk/third/nmh/uip/mhshow.c @ 12455

Revision 12455, 10.9 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12454, which included commits to RCS files with non-trunk default branches.
Line 
1
2/*
3 * mhshow.c -- display the contents of MIME messages
4 *
5 * $Id: mhshow.c,v 1.1.1.1 1999-02-07 18:14:15 danw Exp $
6 */
7
8#include <h/mh.h>
9#include <fcntl.h>
10#include <h/signals.h>
11#include <h/md5.h>
12#include <errno.h>
13#include <signal.h>
14#include <zotnet/mts/mts.h>
15#include <zotnet/tws/tws.h>
16#include <h/mime.h>
17#include <h/mhparse.h>
18#include <h/mhcachesbr.h>
19
20#ifdef HAVE_SYS_WAIT_H
21# include <sys/wait.h>
22#endif
23
24/*
25 * We allocate space for message names (msgs array)
26 * this number of elements at a time.
27 */
28#define MAXMSGS  256
29
30
31static struct swit switches[] = {
32#define CHECKSW                 0
33    { "check", 0 },
34#define NCHECKSW                1
35    { "nocheck", 0 },
36#define PAUSESW                 2
37    { "pause", 0 },
38#define NPAUSESW                3
39    { "nopause", 0 },
40#define SERIALSW                4
41    { "serialonly", 0 },
42#define NSERIALSW               5
43    { "noserialonly", 0 },
44#define VERBSW                  6
45    { "verbose", 0 },
46#define NVERBSW                 7
47    { "noverbose", 0 },
48#define FILESW                  8       /* interface from show */
49    { "file file", 0 },
50#define FORMSW                  9
51    { "form formfile", 0 },
52#define PARTSW                 10
53    { "part number", 0 },
54#define TYPESW                 11
55    { "type content", 0 },
56#define RCACHESW               12
57    { "rcache policy", 0 },
58#define WCACHESW               13
59    { "wcache policy", 0 },
60#define VERSIONSW              14
61    { "version", 0 },
62#define HELPSW                 15
63    { "help", 4 },
64
65/*
66 * switches for moreproc/mhlproc
67 */
68#define PROGSW                 16
69    { "moreproc program", -4 },
70#define NPROGSW                17
71    { "nomoreproc", -3 },
72#define LENSW                  18
73    { "length lines", -4 },
74#define WIDTHSW                19
75    { "width columns", -4 },
76
77/*
78 * switches for debugging
79 */
80#define DEBUGSW                20
81    { "debug", -5 },
82    { NULL, 0 }
83};
84
85
86extern int errno;
87
88/* mhparse.c */
89extern int checksw;
90extern char *tmp;       /* directory to place temp files */
91
92/* mhcachesbr.c */
93extern int rcachesw;
94extern int wcachesw;
95extern char *cache_public;
96extern char *cache_private;
97
98/* mhshowsbr.c */
99extern int pausesw;
100extern int serialsw;
101extern char *progsw;
102extern int nolist;
103extern int nomore;      /* flags for moreproc/header display */
104extern char *formsw;
105
106/* mhmisc.c */
107extern int npart;
108extern int ntype;
109extern char *parts[NPARTS + 1];
110extern char *types[NTYPES + 1];
111extern int userrs;
112
113int debugsw = 0;
114int verbosw = 0;
115
116/* The list of top-level contents to display */
117CT *cts = NULL;
118
119#define quitser pipeser
120
121/* mhparse.c */
122CT parse_mime (char *);
123
124/* mhmisc.c */
125int part_ok (CT, int);
126int type_ok (CT, int);
127void set_endian (void);
128void flush_errors (void);
129
130/* mhshowsbr.c */
131void show_all_messages (CT *);
132
133/* mhfree.c */
134void free_content (CT);
135
136/*
137 * static prototypes
138 */
139static RETSIGTYPE pipeser (int);
140
141
142int
143main (int argc, char **argv)
144{
145    int nummsgs, maxmsgs, msgnum, *icachesw;
146    char *cp, *file = NULL, *folder = NULL;
147    char *maildir, buf[100], **argp;
148    char **arguments, **msgs;
149    struct msgs *mp = NULL;
150    CT ct, *ctp;
151    FILE *fp;
152
153#ifdef LOCALE
154    setlocale(LC_ALL, "");
155#endif
156    invo_name = r1bindex (argv[0], '/');
157
158    /* read user profile/context */
159    context_read();
160
161    arguments = getarguments (invo_name, argc, argv, 1);
162    argp = arguments;
163
164    /*
165     * Allocate the initial space to record message
166     * names, ranges, and sequences.
167     */
168    nummsgs = 0;
169    maxmsgs = MAXMSGS;
170    if (!(msgs = (char **) malloc ((size_t) (maxmsgs * sizeof(*msgs)))))
171        adios (NULL, "unable to allocate storage");
172
173    /*
174     * Parse arguments
175     */
176    while ((cp = *argp++)) {
177        if (*cp == '-') {
178            switch (smatch (++cp, switches)) {
179            case AMBIGSW:
180                ambigsw (cp, switches);
181                done (1);
182            case UNKWNSW:
183                adios (NULL, "-%s unknown", cp);
184
185            case HELPSW:
186                snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]",
187                        invo_name);
188                print_help (buf, switches, 1);
189                done (1);
190            case VERSIONSW:
191                print_version(invo_name);
192                done (1);
193
194            case RCACHESW:
195                icachesw = &rcachesw;
196                goto do_cache;
197            case WCACHESW:
198                icachesw = &wcachesw;
199do_cache:
200                if (!(cp = *argp++) || *cp == '-')
201                    adios (NULL, "missing argument to %s", argp[-2]);
202                switch (*icachesw = smatch (cp, caches)) {
203                case AMBIGSW:
204                    ambigsw (cp, caches);
205                    done (1);
206                case UNKWNSW:
207                    adios (NULL, "%s unknown", cp);
208                default:
209                    break;
210                }
211                continue;
212
213            case CHECKSW:
214                checksw++;
215                continue;
216            case NCHECKSW:
217                checksw = 0;
218                continue;
219
220            case PAUSESW:
221                pausesw = 1;
222                continue;
223            case NPAUSESW:
224                pausesw = 0;
225                continue;
226
227            case SERIALSW:
228                serialsw = 1;
229                continue;
230            case NSERIALSW:
231                serialsw = 0;
232                continue;
233
234            case PARTSW:
235                if (!(cp = *argp++) || *cp == '-')
236                    adios (NULL, "missing argument to %s", argp[-2]);
237                if (npart >= NPARTS)
238                    adios (NULL, "too many parts (starting with %s), %d max",
239                           cp, NPARTS);
240                parts[npart++] = cp;
241                continue;
242
243            case TYPESW:
244                if (!(cp = *argp++) || *cp == '-')
245                    adios (NULL, "missing argument to %s", argp[-2]);
246                if (ntype >= NTYPES)
247                    adios (NULL, "too many types (starting with %s), %d max",
248                           cp, NTYPES);
249                types[ntype++] = cp;
250                continue;
251
252            case FILESW:
253                if (!(cp = *argp++) || (*cp == '-' && cp[1]))
254                    adios (NULL, "missing argument to %s", argp[-2]);
255                file = *cp == '-' ? cp : path (cp, TFILE);
256                continue;
257
258            case FORMSW:
259                if (!(cp = *argp++) || *cp == '-')
260                    adios (NULL, "missing argument to %s", argp[-2]);
261                if (formsw)
262                    free (formsw);
263                formsw = getcpy (etcpath (cp));
264                continue;
265
266            /*
267             * Switches for moreproc/mhlproc
268             */
269            case PROGSW:
270                if (!(progsw = *argp++) || *progsw == '-')
271                    adios (NULL, "missing argument to %s", argp[-2]);
272                continue;
273            case NPROGSW:
274                nomore++;
275                continue;
276
277            case LENSW:
278            case WIDTHSW:
279                if (!(cp = *argp++) || *cp == '-')
280                    adios (NULL, "missing argument to %s", argp[-2]);
281                continue;
282
283            case VERBSW:
284                verbosw = 1;
285                continue;
286            case NVERBSW:
287                verbosw = 0;
288                continue;
289            case DEBUGSW:
290                debugsw = 1;
291                continue;
292            }
293        }
294        if (*cp == '+' || *cp == '@') {
295            if (folder)
296                adios (NULL, "only one folder at a time!");
297            else
298                folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
299        } else {
300            /*
301             * Check if we need to allocate more space
302             * for message names/ranges/sequences.
303             */
304            if (nummsgs >= maxmsgs) {
305                maxmsgs += MAXMSGS;
306                if (!(msgs = (char **) realloc (msgs,
307                        (size_t) (maxmsgs * sizeof(*msgs)))))
308                    adios (NULL, "unable to reallocate msgs storage");
309            }
310            msgs[nummsgs++] = cp;
311        }
312    }
313
314    /* null terminate the list of acceptable parts/types */
315    parts[npart] = NULL;
316    types[ntype] = NULL;
317
318    set_endian ();
319
320    if ((cp = getenv ("MM_NOASK")) && !strcmp (cp, "1")) {
321        nolist  = 1;
322        pausesw = 0;
323    }
324
325    /*
326     * Check if we've specified an additional profile
327     */
328    if ((cp = getenv ("MHSHOW"))) {
329        if ((fp = fopen (cp, "r"))) {
330            readconfig ((struct node **) 0, fp, cp, 0);
331            fclose (fp);
332        } else {
333            admonish ("", "unable to read $MHSHOW profile (%s)", cp);
334        }
335    }
336
337    /*
338     * Read the standard profile setup
339     */
340    if ((fp = fopen (cp = etcpath ("mhn.defaults"), "r"))) {
341        readconfig ((struct node **) 0, fp, cp, 0);
342        fclose (fp);
343    }
344
345    /* Check for public cache location */
346    if ((cache_public = context_find (nmhcache)) && *cache_public != '/')
347        cache_public = NULL;
348
349    /* Check for private cache location */
350    if (!(cache_private = context_find (nmhprivcache)))
351        cache_private = ".cache";
352    cache_private = getcpy (m_maildir (cache_private));
353
354    /*
355     * Check for storage directory.  If specified,
356     * then store temporary files there.  Else we
357     * store them in standard nmh directory.
358     */
359    if ((cp = context_find (nmhstorage)) && *cp)
360        tmp = concat (cp, "/", invo_name, NULL);
361    else
362        tmp = add (m_maildir (invo_name), NULL);
363
364    if (!context_find ("path"))
365        free (path ("./", TFOLDER));
366
367    if (file && nummsgs)
368        adios (NULL, "cannot specify msg and file at same time!");
369
370    /*
371     * check if message is coming from file
372     */
373    if (file) {
374        if (!(cts = (CT *) calloc ((size_t) 2, sizeof(*cts))))
375            adios (NULL, "out of memory");
376        ctp = cts;
377
378        if ((ct = parse_mime (file)));
379            *ctp++ = ct;
380    } else {
381        /*
382         * message(s) are coming from a folder
383         */
384        if (!nummsgs)
385            msgs[nummsgs++] = "cur";
386        if (!folder)
387            folder = getfolder (1);
388        maildir = m_maildir (folder);
389
390        if (chdir (maildir) == NOTOK)
391            adios (maildir, "unable to change directory to");
392
393        /* read folder and create message structure */
394        if (!(mp = folder_read (folder)))
395            adios (NULL, "unable to read folder %s", folder);
396
397        /* check for empty folder */
398        if (mp->nummsg == 0)
399            adios (NULL, "no messages in %s", folder);
400
401        /* parse all the message ranges/sequences and set SELECTED */
402        for (msgnum = 0; msgnum < nummsgs; msgnum++)
403            if (!m_convert (mp, msgs[msgnum]))
404                done (1);
405
406        /*
407         * Set the SELECT_UNSEEN bit for all the SELECTED messages,
408         * since we will use that as a tag to know which messages
409         * to remove from the "unseen" sequence.
410         */
411        for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
412            if (is_selected(mp, msgnum))
413                set_unseen (mp, msgnum);
414
415        seq_setprev (mp);       /* set the Previous-Sequence */
416        seq_setunseen (mp, 1);  /* unset the Unseen-Sequence */
417
418        if (!(cts = (CT *) calloc ((size_t) (mp->numsel + 1), sizeof(*cts))))
419            adios (NULL, "out of memory");
420        ctp = cts;
421
422        /*
423         * Parse all the SELECTED messages.
424         */
425        for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
426            if (is_selected(mp, msgnum)) {
427                char *msgnam;
428
429                msgnam = m_name (msgnum);
430                if ((ct = parse_mime (msgnam)))
431                    *ctp++ = ct;
432            }
433        }
434    }
435
436    if (!*cts)
437        done (1);
438
439    userrs = 1;
440    SIGNAL (SIGQUIT, quitser);
441    SIGNAL (SIGPIPE, pipeser);
442
443    /*
444     * Get the associated umask for the relevant contents.
445     */
446    for (ctp = cts; *ctp; ctp++) {
447        struct stat st;
448
449        ct = *ctp;
450        if (type_ok (ct, 1) && !ct->c_umask) {
451            if (stat (ct->c_file, &st) != NOTOK)
452                ct->c_umask = ~(st.st_mode & 0777);
453            else
454                ct->c_umask = ~m_gmprot();
455        }
456    }
457
458    /*
459     * Show the message content
460     */
461    show_all_messages (cts);
462
463    /* Now free all the structures for the content */
464    for (ctp = cts; *ctp; ctp++)
465        free_content (*ctp);
466
467    free ((char *) cts);
468    cts = NULL;
469
470    /* If reading from a folder, do some updating */
471    if (mp) {
472        context_replace (pfolder, folder);/* update current folder  */
473        seq_setcur (mp, mp->hghsel);      /* update current message */
474        seq_save (mp);                    /* synchronize sequences  */
475        context_save ();                  /* save the context file  */
476    }
477
478    done (0);
479    /* NOTREACHED */
480}
481
482
483static RETSIGTYPE
484pipeser (int i)
485{
486    if (i == SIGQUIT) {
487        unlink ("core");
488        fflush (stdout);
489        fprintf (stderr, "\n");
490        fflush (stderr);
491    }
492
493    done (1);
494    /* NOTREACHED */
495}
496
497
498void
499done (int status)
500{
501    CT *ctp;
502
503    if ((ctp = cts))
504        for (; *ctp; ctp++)
505            free_content (*ctp);
506
507    exit (status);
508}
Note: See TracBrowser for help on using the repository browser.