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

Revision 12455, 15.3 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 * mhn.c -- display, list, cache, or store the contents of MIME messages
4 *
5 * $Id: mhn.c,v 1.1.1.1 1999-02-07 18:14:14 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 AUTOSW                  0
33    { "auto", 0 },
34#define NAUTOSW                 1
35    { "noauto", 0 },
36#define CACHESW                 2
37    { "cache", 0 },
38#define NCACHESW                3
39    { "nocache", 0 },
40#define CHECKSW                 4
41    { "check", 0 },
42#define NCHECKSW                5
43    { "nocheck", 0 },
44#define HEADSW                  6
45    { "headers", 0 },
46#define NHEADSW                 7
47    { "noheaders", 0 },
48#define LISTSW                  8
49    { "list", 0 },
50#define NLISTSW                 9
51    { "nolist", 0 },
52#define PAUSESW                10
53    { "pause", 0 },
54#define NPAUSESW               11
55    { "nopause", 0 },
56#define SIZESW                 12
57    { "realsize", 0 },
58#define NSIZESW                13
59    { "norealsize", 0 },
60#define SERIALSW               14
61    { "serialonly", 0 },
62#define NSERIALSW              15
63    { "noserialonly", 0 },
64#define SHOWSW                 16
65    { "show", 0 },
66#define NSHOWSW                17
67    { "noshow", 0 },
68#define STORESW                18
69    { "store", 0 },
70#define NSTORESW               19
71    { "nostore", 0 },
72#define VERBSW                 20
73    { "verbose", 0 },
74#define NVERBSW                21
75    { "noverbose", 0 },
76#define FILESW                 22       /* interface from show */
77    { "file file", 0 },
78#define FORMSW                 23
79    { "form formfile", 0 },
80#define PARTSW                 24
81    { "part number", 0 },
82#define TYPESW                 25
83    { "type content", 0 },
84#define RCACHESW               26
85    { "rcache policy", 0 },
86#define WCACHESW               27
87    { "wcache policy", 0 },
88#define VERSIONSW              28
89    { "version", 0 },
90#define HELPSW                 29
91    { "help", 4 },
92
93/*
94 * switches for debugging
95 */
96#define DEBUGSW                30
97    { "debug", -5 },
98
99/*
100 * switches for moreproc/mhlproc
101 */
102#define PROGSW                 31
103    { "moreproc program", -4 },
104#define NPROGSW                32
105    { "nomoreproc", -3 },
106#define LENSW                  33
107    { "length lines", -4 },
108#define WIDTHSW                34
109    { "width columns", -4 },
110
111/*
112 * switches for mhbuild
113 */
114#define BUILDSW                35
115    { "build", -5 },
116#define NBUILDSW               36
117    { "nobuild", -7 },
118#define EBCDICSW               37
119    { "ebcdicsafe", -10 },
120#define NEBCDICSW              38
121    { "noebcdicsafe", -12 },
122#define RFC934SW               39
123    { "rfc934mode", -10 },
124#define NRFC934SW              40
125    { "norfc934mode", -12 },
126    { NULL, 0 }
127};
128
129
130extern int errno;
131
132/* mhparse.c */
133extern int checksw;
134extern char *tmp;       /* directory to place temp files */
135
136/* mhcachesbr.c */
137extern int rcachesw;
138extern int wcachesw;
139extern char *cache_public;
140extern char *cache_private;
141
142/* mhshowsbr.c */
143extern int pausesw;
144extern int serialsw;
145extern char *progsw;
146extern int nolist;
147extern int nomore;      /* flags for moreproc/header display */
148extern char *formsw;
149
150/* mhstoresbr.c */
151extern int autosw;
152extern char *cwd;       /* cache current working directory */
153
154/* mhmisc.c */
155extern int npart;
156extern int ntype;
157extern char *parts[NPARTS + 1];
158extern char *types[NTYPES + 1];
159extern int userrs;
160
161int debugsw = 0;
162int verbosw = 0;
163
164/* The list of top-level contents to display */
165CT *cts = NULL;
166
167/*
168 * variables for mhbuild (mhn -build)
169 */
170static int buildsw  = 0;
171static int ebcdicsw = 0;
172static int rfc934sw = 0;
173
174/*
175 * what action to take?
176 */
177static int cachesw = 0;
178static int listsw  = 0;
179static int showsw  = 0;
180static int storesw = 0;
181
182#define quitser pipeser
183
184/* mhparse.c */
185CT parse_mime (char *);
186
187/* mhmisc.c */
188int part_ok (CT, int);
189int type_ok (CT, int);
190void set_endian (void);
191void flush_errors (void);
192
193/* mhshowsbr.c */
194void show_all_messages (CT *);
195
196/* mhlistsbr.c */
197void list_all_messages (CT *, int, int, int, int);
198
199/* mhstoresbr.c */
200void store_all_messages (CT *);
201
202/* mhcachesbr.c */
203void cache_all_messages (CT *);
204
205/* mhfree.c */
206void free_content (CT);
207
208/*
209 * static prototypes
210 */
211static RETSIGTYPE pipeser (int);
212
213
214int
215main (int argc, char **argv)
216{
217    int sizesw = 1, headsw = 1;
218    int nummsgs, maxmsgs, msgnum, *icachesw;
219    char *cp, *file = NULL, *folder = NULL;
220    char *maildir, buf[100], **argp;
221    char **arguments, **msgs;
222    struct msgs *mp = NULL;
223    CT ct, *ctp;
224    FILE *fp;
225
226#ifdef LOCALE
227    setlocale(LC_ALL, "");
228#endif
229    invo_name = r1bindex (argv[0], '/');
230
231    /* read user profile/context */
232    context_read();
233
234    arguments = getarguments (invo_name, argc, argv, 1);
235    argp = arguments;
236
237    /*
238     * Allocate the initial space to record message
239     * names, ranges, and sequences.
240     */
241    nummsgs = 0;
242    maxmsgs = MAXMSGS;
243    if (!(msgs = (char **) malloc ((size_t) (maxmsgs * sizeof(*msgs)))))
244        adios (NULL, "unable to allocate storage");
245
246    /*
247     * Parse arguments
248     */
249    while ((cp = *argp++)) {
250        if (*cp == '-') {
251            switch (smatch (++cp, switches)) {
252            case AMBIGSW:
253                ambigsw (cp, switches);
254                done (1);
255            case UNKWNSW:
256                adios (NULL, "-%s unknown", cp);
257
258            case HELPSW:
259                snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]",
260                        invo_name);
261                print_help (buf, switches, 1);
262                done (1);
263            case VERSIONSW:
264                print_version(invo_name);
265                done (1);
266
267            case AUTOSW:
268                autosw++;
269                continue;
270            case NAUTOSW:
271                autosw = 0;
272                continue;
273
274            case CACHESW:
275                cachesw++;
276                continue;
277            case NCACHESW:
278                cachesw = 0;
279                continue;
280
281            case RCACHESW:
282                icachesw = &rcachesw;
283                goto do_cache;
284            case WCACHESW:
285                icachesw = &wcachesw;
286do_cache:
287                if (!(cp = *argp++) || *cp == '-')
288                    adios (NULL, "missing argument to %s", argp[-2]);
289                switch (*icachesw = smatch (cp, caches)) {
290                case AMBIGSW:
291                    ambigsw (cp, caches);
292                    done (1);
293                case UNKWNSW:
294                    adios (NULL, "%s unknown", cp);
295                default:
296                    break;
297                }
298                continue;
299
300            case CHECKSW:
301                checksw++;
302                continue;
303            case NCHECKSW:
304                checksw = 0;
305                continue;
306
307            case HEADSW:
308                headsw = 1;
309                continue;
310            case NHEADSW:
311                headsw = 0;
312                continue;
313
314            case LISTSW:
315                listsw = 1;
316                continue;
317            case NLISTSW:
318                listsw = 0;
319                continue;
320
321            case PAUSESW:
322                pausesw = 1;
323                continue;
324            case NPAUSESW:
325                pausesw = 0;
326                continue;
327
328            case SERIALSW:
329                serialsw = 1;
330                continue;
331            case NSERIALSW:
332                serialsw = 0;
333                continue;
334
335            case SHOWSW:
336                showsw = 1;
337                continue;
338            case NSHOWSW:
339                showsw = 0;
340                continue;
341
342            case SIZESW:
343                sizesw = 1;
344                continue;
345            case NSIZESW:
346                sizesw = 0;
347                continue;
348
349            case STORESW:
350                storesw = 1;
351                continue;
352            case NSTORESW:
353                storesw = 0;
354                continue;
355
356            case PARTSW:
357                if (!(cp = *argp++) || *cp == '-')
358                    adios (NULL, "missing argument to %s", argp[-2]);
359                if (npart >= NPARTS)
360                    adios (NULL, "too many parts (starting with %s), %d max",
361                           cp, NPARTS);
362                parts[npart++] = cp;
363                continue;
364
365            case TYPESW:
366                if (!(cp = *argp++) || *cp == '-')
367                    adios (NULL, "missing argument to %s", argp[-2]);
368                if (ntype >= NTYPES)
369                    adios (NULL, "too many types (starting with %s), %d max",
370                           cp, NTYPES);
371                types[ntype++] = cp;
372                continue;
373
374            case FILESW:
375                if (!(cp = *argp++) || (*cp == '-' && cp[1]))
376                    adios (NULL, "missing argument to %s", argp[-2]);
377                file = *cp == '-' ? cp : path (cp, TFILE);
378                continue;
379
380            case FORMSW:
381                if (!(cp = *argp++) || *cp == '-')
382                    adios (NULL, "missing argument to %s", argp[-2]);
383                if (formsw)
384                    free (formsw);
385                formsw = getcpy (etcpath (cp));
386                continue;
387
388            /*
389             * Switches for moreproc/mhlproc
390             */
391            case PROGSW:
392                if (!(progsw = *argp++) || *progsw == '-')
393                    adios (NULL, "missing argument to %s", argp[-2]);
394                continue;
395            case NPROGSW:
396                nomore++;
397                continue;
398
399            case LENSW:
400            case WIDTHSW:
401                if (!(cp = *argp++) || *cp == '-')
402                    adios (NULL, "missing argument to %s", argp[-2]);
403                continue;
404
405            /*
406             * Switches for mhbuild
407             */
408            case BUILDSW:
409                buildsw = 1;
410                continue;
411            case NBUILDSW:
412                buildsw = 0;
413                continue;
414            case RFC934SW:
415                rfc934sw = 1;
416                continue;
417            case NRFC934SW:
418                rfc934sw = -1;
419                continue;
420            case EBCDICSW:
421                ebcdicsw = 1;
422                continue;
423            case NEBCDICSW:
424                ebcdicsw = -1;
425                continue;
426
427            case VERBSW:
428                verbosw = 1;
429                continue;
430            case NVERBSW:
431                verbosw = 0;
432                continue;
433            case DEBUGSW:
434                debugsw = 1;
435                continue;
436            }
437        }
438        if (*cp == '+' || *cp == '@') {
439            if (folder)
440                adios (NULL, "only one folder at a time!");
441            else
442                folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
443        } else {
444            /*
445             * Check if we need to allocate more space
446             * for message names/ranges/sequences.
447             */
448            if (nummsgs >= maxmsgs) {
449                maxmsgs += MAXMSGS;
450                if (!(msgs = (char **) realloc (msgs,
451                        (size_t) (maxmsgs * sizeof(*msgs)))))
452                    adios (NULL, "unable to reallocate msgs storage");
453            }
454            msgs[nummsgs++] = cp;
455        }
456    }
457
458    /* null terminate the list of acceptable parts/types */
459    parts[npart] = NULL;
460    types[ntype] = NULL;
461
462    set_endian ();
463
464    if ((cp = getenv ("MM_NOASK")) && !strcmp (cp, "1")) {
465        nolist  = 1;
466        listsw  = 0;
467        pausesw = 0;
468    }
469
470    /*
471     * Check if we've specified an additional profile
472     */
473    if ((cp = getenv ("MHN"))) {
474        if ((fp = fopen (cp, "r"))) {
475            readconfig ((struct node **) 0, fp, cp, 0);
476            fclose (fp);
477        } else {
478            admonish ("", "unable to read $MHN profile (%s)", cp);
479        }
480    }
481
482    /*
483     * Read the standard profile setup
484     */
485    if ((fp = fopen (cp = etcpath ("mhn.defaults"), "r"))) {
486        readconfig ((struct node **) 0, fp, cp, 0);
487        fclose (fp);
488    }
489
490    /* Check for public cache location */
491    if ((cache_public = context_find (nmhcache)) && *cache_public != '/')
492        cache_public = NULL;
493
494    /* Check for private cache location */
495    if (!(cache_private = context_find (nmhprivcache)))
496        cache_private = ".cache";
497    cache_private = getcpy (m_maildir (cache_private));
498
499    /*
500     * Cache the current directory before we do any chdirs()'s.
501     */
502    cwd = getcpy (pwd());
503
504    /*
505     * Check for storage directory.  If specified,
506     * then store temporary files there.  Else we
507     * store them in standard nmh directory.
508     */
509    if ((cp = context_find (nmhstorage)) && *cp)
510        tmp = concat (cp, "/", invo_name, NULL);
511    else
512        tmp = add (m_maildir (invo_name), NULL);
513
514    if (!context_find ("path"))
515        free (path ("./", TFOLDER));
516
517    /*
518     * Process a mhn composition file (mhn -build)
519     */
520    if (buildsw) {
521        char *vec[MAXARGS];
522        int vecp;
523
524        if (showsw || storesw || cachesw)
525            adios (NULL, "cannot use -build with -show, -store, -cache");
526        if (nummsgs < 1)
527            adios (NULL, "need to specify a %s composition file", invo_name);
528        if (nummsgs > 1)
529            adios (NULL, "only one %s composition file at a time", invo_name);
530
531        vecp = 0;
532        vec[vecp++] = "mhbuild";
533
534        if (ebcdicsw == 1)
535            vec[vecp++] = "-ebcdicsafe";
536        else if (ebcdicsw == -1)
537            vec[vecp++] = "-noebcdicsafe";
538
539        if (rfc934sw == 1)
540            vec[vecp++] = "-rfc934mode";
541        else if (rfc934sw == -1)
542            vec[vecp++] = "-norfc934mode";
543
544        vec[vecp++] = msgs[0];
545        vec[vecp] = NULL;
546
547        execvp ("mhbuild", vec);
548        fprintf (stderr, "unable to exec ");
549        _exit (-1);
550    }
551
552    /*
553     * Process a mhn composition file (old MH style)
554     */
555    if (nummsgs == 1 && !folder && !npart && !cachesw
556        && !showsw && !storesw && !ntype && !file
557        && (cp = getenv ("mhdraft"))
558        && strcmp (cp, msgs[0]) == 0) {
559
560        char *vec[MAXARGS];
561        int vecp;
562
563        vecp = 0;
564        vec[vecp++] = "mhbuild";
565
566        if (ebcdicsw == 1)
567            vec[vecp++] = "-ebcdicsafe";
568        else if (ebcdicsw == -1)
569            vec[vecp++] = "-noebcdicsafe";
570
571        if (rfc934sw == 1)
572            vec[vecp++] = "-rfc934mode";
573        else if (rfc934sw == -1)
574            vec[vecp++] = "-norfc934mode";
575
576        vec[vecp++] = cp;
577        vec[vecp] = NULL;
578
579        execvp ("mhbuild", vec);
580        fprintf (stderr, "unable to exec ");
581        _exit (-1);
582    }
583
584    if (file && nummsgs)
585        adios (NULL, "cannot specify msg and file at same time!");
586
587    /*
588     * check if message is coming from file
589     */
590    if (file) {
591        if (!(cts = (CT *) calloc ((size_t) 2, sizeof(*cts))))
592            adios (NULL, "out of memory");
593        ctp = cts;
594
595        if ((ct = parse_mime (file)));
596            *ctp++ = ct;
597    } else {
598        /*
599         * message(s) are coming from a folder
600         */
601        if (!nummsgs)
602            msgs[nummsgs++] = "cur";
603        if (!folder)
604            folder = getfolder (1);
605        maildir = m_maildir (folder);
606
607        if (chdir (maildir) == NOTOK)
608            adios (maildir, "unable to change directory to");
609
610        /* read folder and create message structure */
611        if (!(mp = folder_read (folder)))
612            adios (NULL, "unable to read folder %s", folder);
613
614        /* check for empty folder */
615        if (mp->nummsg == 0)
616            adios (NULL, "no messages in %s", folder);
617
618        /* parse all the message ranges/sequences and set SELECTED */
619        for (msgnum = 0; msgnum < nummsgs; msgnum++)
620            if (!m_convert (mp, msgs[msgnum]))
621                done (1);
622        seq_setprev (mp);       /* set the previous-sequence */
623
624        if (!(cts = (CT *) calloc ((size_t) (mp->numsel + 1), sizeof(*cts))))
625            adios (NULL, "out of memory");
626        ctp = cts;
627
628        for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
629            if (is_selected(mp, msgnum)) {
630                char *msgnam;
631
632                msgnam = m_name (msgnum);
633                if ((ct = parse_mime (msgnam)))
634                    *ctp++ = ct;
635            }
636        }
637    }
638
639    if (!*cts)
640        done (1);
641
642    /*
643     * You can't give more than one of these flags
644     * at a time.
645     */
646    if (showsw + listsw + storesw + cachesw > 1)
647        adios (NULL, "can only use one of -show, -list, -store, -cache at same time");
648
649    /* If no action is specified, assume -show */
650    if (!listsw && !showsw && !storesw && !cachesw)
651        showsw = 1;
652
653    userrs = 1;
654    SIGNAL (SIGQUIT, quitser);
655    SIGNAL (SIGPIPE, pipeser);
656
657    /*
658     * Get the associated umask for the relevant contents.
659     */
660    for (ctp = cts; *ctp; ctp++) {
661        struct stat st;
662
663        ct = *ctp;
664        if (type_ok (ct, 1) && !ct->c_umask) {
665            if (stat (ct->c_file, &st) != NOTOK)
666                ct->c_umask = ~(st.st_mode & 0777);
667            else
668                ct->c_umask = ~m_gmprot();
669        }
670    }
671
672    /*
673     * List the message content
674     */
675    if (listsw)
676        list_all_messages (cts, headsw, sizesw, verbosw, debugsw);
677
678    /*
679     * Store the message content
680     */
681    if (storesw)
682        store_all_messages (cts);
683
684    /*
685     * Cache the message content
686     */
687    if (cachesw)
688        cache_all_messages (cts);
689
690    /*
691     * Show the message content
692     */
693    if (showsw)
694        show_all_messages (cts);
695
696    /* Now free all the structures for the content */
697    for (ctp = cts; *ctp; ctp++)
698        free_content (*ctp);
699
700    free ((char *) cts);
701    cts = NULL;
702
703    /* If reading from a folder, do some updating */
704    if (mp) {
705        context_replace (pfolder, folder);/* update current folder  */
706        seq_setcur (mp, mp->hghsel);      /* update current message */
707        seq_save (mp);                    /* synchronize sequences  */
708        context_save ();                  /* save the context file  */
709    }
710
711    done (0);
712    /* NOTREACHED */
713}
714
715
716static RETSIGTYPE
717pipeser (int i)
718{
719    if (i == SIGQUIT) {
720        unlink ("core");
721        fflush (stdout);
722        fprintf (stderr, "\n");
723        fflush (stderr);
724    }
725
726    done (1);
727    /* NOTREACHED */
728}
729
730
731void
732done (int status)
733{
734    CT *ctp;
735
736    if ((ctp = cts))
737        for (; *ctp; ctp++)
738            free_content (*ctp);
739
740    exit (status);
741}
Note: See TracBrowser for help on using the repository browser.