source: trunk/third/nmh/uip/mhlsbr.c @ 12945

Revision 12945, 40.2 KB checked in by danw, 25 years ago (diff)
exit gracefully on SIGPIPE
Line 
1
2/*
3 * mhlsbr.c -- main routines for nmh message lister
4 *
5 * $Id: mhlsbr.c,v 1.2 1999-04-20 20:03:28 danw Exp $
6 */
7
8#include <h/mh.h>
9#include <h/signals.h>
10#include <h/addrsbr.h>
11#include <h/fmt_scan.h>
12#include <zotnet/tws/tws.h>
13#include <setjmp.h>
14#include <signal.h>
15
16/*
17 * MAJOR BUG:
18 * for a component containing addresses, ADDRFMT, if COMPRESS is also
19 * set, then addresses get split wrong (not at the spaces between commas).
20 * To fix this correctly, putstr() should know about "atomic" strings that
21 * must NOT be broken across lines.  That's too difficult for right now
22 * (it turns out that there are a number of degernate cases), so in
23 * oneline(), instead of
24 *
25 *       (*onelp == '\n' && !onelp[1])
26 *
27 * being a terminating condition,
28 *
29 *       (*onelp == '\n' && (!onelp[1] || (flags & ADDRFMT)))
30 *
31 * is used instead.  This cuts the line prematurely, and gives us a much
32 * better chance of getting things right.
33 */
34
35#define ONECOMP  0
36#define TWOCOMP  1
37#define BODYCOMP 2
38
39#define QUOTE   '\\'
40
41static struct swit mhlswitches[] = {
42#define BELLSW         0
43    { "bell", 0 },
44#define NBELLSW        1
45    { "nobell", 0 },
46#define CLRSW          2
47    { "clear", 0 },
48#define NCLRSW         3
49    { "noclear", 0 },
50#define FACESW         4
51    { "faceproc program", 0 },
52#define NFACESW        5
53    { "nofaceproc", 0 },
54#define FOLDSW         6
55    { "folder +folder", 0 },
56#define FORMSW         7
57    { "form formfile", 0 },
58#define PROGSW         8
59    { "moreproc program", 0 },
60#define NPROGSW        9
61    { "nomoreproc", 0 },
62#define LENSW         10
63    { "length lines", 0 },
64#define WIDTHSW       11
65    { "width columns", 0 },
66#define SLEEPSW       12
67    { "sleep seconds",  0 },
68#define BITSTUFFSW    13
69    { "dashstuffing", -12 },    /* interface from forw */
70#define NBITSTUFFSW   14
71    { "nodashstuffing", -14 },  /* interface from forw */
72#define VERSIONSW     15
73    { "version", 0 },
74#define HELPSW        16
75    { "help", 4 },
76#define FORW1SW       17
77    { "forward", -7 },          /* interface from forw */
78#define FORW2SW       18
79    { "forwall", -7 },          /* interface from forw */
80#define DGSTSW        19
81    { "digest list", -6 },
82#define VOLUMSW       20
83    { "volume number", -6 },
84#define ISSUESW       21
85    { "issue number", -5 },
86#define NBODYSW       22
87    { "nobody", -6 },
88    { NULL, 0 }
89};
90
91#define NOCOMPONENT 0x000001    /* don't show component name         */
92#define UPPERCASE   0x000002    /* display in all upper case         */
93#define CENTER      0x000004    /* center line                       */
94#define CLEARTEXT   0x000008    /* cleartext                         */
95#define EXTRA       0x000010    /* an "extra" component              */
96#define HDROUTPUT   0x000020    /* already output                    */
97#define CLEARSCR    0x000040    /* clear screen                      */
98#define LEFTADJUST  0x000080    /* left justify multiple lines       */
99#define COMPRESS    0x000100    /* compress text                     */
100#define ADDRFMT     0x000200    /* contains addresses                */
101#define BELL        0x000400    /* sound bell at EOP                 */
102#define DATEFMT     0x000800    /* contains dates                    */
103#define FORMAT      0x001000    /* parse address/date/RFC-2047 field */
104#define INIT        0x002000    /* initialize component              */
105#define FACEFMT     0x004000    /* contains face                     */
106#define FACEDFLT    0x008000    /* default for face                  */
107#define SPLIT       0x010000    /* split headers (don't concatenate) */
108#define NONEWLINE   0x020000    /* don't write trailing newline      */
109#define LBITS   "\020\01NOCOMPONENT\02UPPERCASE\03CENTER\04CLEARTEXT\05EXTRA\06HDROUTPUT\07CLEARSCR\010LEFTADJUST\011COMPRESS\012ADDRFMT\013BELL\014DATEFMT\015FORMAT\016INIT\017FACEFMT\020FACEDFLT\021SPLIT\022NONEWLINE"
110#define GFLAGS  (NOCOMPONENT | UPPERCASE | CENTER | LEFTADJUST | COMPRESS | SPLIT)
111
112struct mcomp {
113    char *c_name;               /* component name          */
114    char *c_text;               /* component text          */
115    char *c_ovtxt;              /* text overflow indicator */
116    char *c_nfs;                /* iff FORMAT              */
117    struct format *c_fmt;       /*   ..                    */
118    char *c_face;               /* face designator         */
119    int c_offset;               /* left margin indentation */
120    int c_ovoff;                /* overflow indentation    */
121    int c_width;                /* width of field          */
122    int c_cwidth;               /* width of component      */
123    int c_length;               /* length in lines         */
124    long c_flags;
125    struct mcomp *c_next;
126};
127
128static struct mcomp *msghd = NULL;
129static struct mcomp *msgtl = NULL;
130static struct mcomp *fmthd = NULL;
131static struct mcomp *fmttl = NULL;
132
133static struct mcomp global = {
134    NULL, NULL, "", NULL, NULL, 0, -1, 80, -1, 40, BELL, 0
135};
136
137static struct mcomp holder = {
138    NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, NOCOMPONENT, 0
139};
140
141struct pair {
142    char *p_name;
143    long p_flags;
144};
145
146static struct pair pairs[] = {
147    { "Date",            DATEFMT },
148    { "From",            ADDRFMT|FACEDFLT },
149    { "Sender",          ADDRFMT },
150    { "Reply-To",        ADDRFMT },
151    { "To",              ADDRFMT },
152    { "cc",              ADDRFMT },
153    { "Bcc",             ADDRFMT },
154    { "Resent-Date",     DATEFMT },
155    { "Resent-From",     ADDRFMT },
156    { "Resent-Sender",   ADDRFMT },
157    { "Resent-Reply-To", ADDRFMT },
158    { "Resent-To",       ADDRFMT },
159    { "Resent-cc",       ADDRFMT },
160    { "Resent-Bcc",      ADDRFMT },
161    { "Face",            FACEFMT },
162    { NULL,              0 }
163};
164
165struct triple {
166    char *t_name;
167    long t_on;
168    long t_off;
169};
170
171static struct triple triples[] = {
172    { "nocomponent",   NOCOMPONENT, 0 },
173    { "uppercase",     UPPERCASE,   0 },
174    { "nouppercase",   0,           UPPERCASE },
175    { "center",        CENTER,      0 },
176    { "nocenter",      0,           CENTER },
177    { "clearscreen",   CLEARSCR,    0 },
178    { "noclearscreen", 0,           CLEARSCR },
179    { "noclear",       0,           CLEARSCR },
180    { "leftadjust",    LEFTADJUST,  0 },
181    { "noleftadjust",  0,           LEFTADJUST },
182    { "compress",      COMPRESS,    0 },
183    { "nocompress",    0,           COMPRESS },
184    { "split",         SPLIT,       0 },
185    { "nosplit",       0,           SPLIT },
186    { "addrfield",     ADDRFMT,     DATEFMT },
187    { "bell",          BELL,        0 },
188    { "nobell",        0,           BELL },
189    { "datefield",     DATEFMT,     ADDRFMT },
190    { "newline",       0,           NONEWLINE },
191    { "nonewline",     NONEWLINE,   0 },
192    { NULL,            0,           0 }
193};
194
195
196static int bellflg   = 0;
197static int clearflg  = 0;
198static int dashstuff = 0;
199static int dobody    = 1;
200static int forwflg   = 0;
201static int forwall   = 0;
202
203static int sleepsw = NOTOK;
204
205static char *digest = NULL;
206static int volume = 0;
207static int issue = 0;
208
209static int exitstat = 0;
210static int mhldebug = 0;
211
212#define PITTY   (-1)
213#define NOTTY   0
214#define ISTTY   1
215static int ontty = NOTTY;
216
217static int row;
218static int column;
219
220static int lm;
221static int llim;
222static int ovoff;
223static int term;
224static int wid;
225
226static char *ovtxt;
227
228static char *onelp;
229
230static char *parptr;
231
232static int num_ignores = 0;
233static char *ignores[MAXARGS];
234
235static  jmp_buf env;
236static  jmp_buf mhlenv;
237
238static char delim3[] =          /* from forw.c */
239    "\n----------------------------------------------------------------------\n\n";
240static char delim4[] = "\n------------------------------\n\n";
241
242static FILE *(*mhl_action) () = (FILE *(*) ()) 0;
243
244
245/*
246 * Redefine a couple of functions.
247 * These are undefined later in the code.
248 */
249#define adios mhladios
250#define done  mhldone
251
252/*
253 * prototypes
254 */
255static void mhl_format (char *, int, int);
256static int evalvar (struct mcomp *);
257static int ptoi (char *, int *);
258static int ptos (char *, char **);
259static char *parse (void);
260static void process (char *, char *, int, int);
261static void mhlfile (FILE *, char *, int, int);
262static int mcomp_flags (char *);
263static char *mcomp_add (long, char *, char *);
264static void mcomp_format (struct mcomp *, struct mcomp *);
265static struct mcomp *add_queue (struct mcomp **, struct mcomp **, char *, char *, int);
266static void free_queue (struct mcomp **, struct mcomp **);
267static void putcomp (struct mcomp *, struct mcomp *, int);
268static char *oneline (char *, long);
269static void putstr (char *);
270static void putch (char);
271static RETSIGTYPE intrser (int);
272static RETSIGTYPE pipeser (int);
273static RETSIGTYPE quitser (int);
274static void face_format (struct mcomp *);
275static int doface (struct mcomp *);
276static void mhladios (char *, char *, ...);
277static void mhldone (int);
278static void m_popen (char *);
279
280int mhl (int, char **);
281int mhlsbr (int, char **, FILE *(*)());
282void m_pclose (void);
283
284void clear_screen (void);             /* from termsbr.c */
285int SOprintf (char *, ...);           /* from termsbr.c */
286int sc_width (void);                  /* from termsbr.c */
287int sc_length (void);                 /* from termsbr.c */
288int sc_hardcopy (void);               /* from termsbr.c */
289struct hostent *gethostbystring ();
290
291
292int
293mhl (int argc, char **argv)
294{
295    int length = 0, nomore = 0;
296    int i, width = 0, vecp = 0;
297    char *cp, *folder = NULL, *form = NULL;
298    char buf[BUFSIZ], *files[MAXARGS];
299    char **argp, **arguments;
300
301    invo_name = r1bindex (argv[0], '/');
302
303    /* read user profile/context */
304    context_read();
305
306    arguments = getarguments (invo_name, argc, argv, 1);
307    argp = arguments;
308
309    if ((cp = getenv ("MHLDEBUG")) && *cp)
310        mhldebug++;
311
312    if ((cp = getenv ("FACEPROC")))
313        faceproc = cp;
314
315    while ((cp = *argp++)) {
316        if (*cp == '-') {
317            switch (smatch (++cp, mhlswitches)) {
318                case AMBIGSW:
319                    ambigsw (cp, mhlswitches);
320                    done (1);
321                case UNKWNSW:
322                    adios (NULL, "-%s unknown\n", cp);
323
324                case HELPSW:
325                    snprintf (buf, sizeof(buf), "%s [switches] [files ...]", invo_name);
326                    print_help (buf, mhlswitches, 1);
327                    done (1);
328                case VERSIONSW:
329                    print_version(invo_name);
330                    done (1);
331
332                case BELLSW:
333                    bellflg = 1;
334                    continue;
335                case NBELLSW:
336                    bellflg = -1;
337                    continue;
338
339                case CLRSW:
340                    clearflg = 1;
341                    continue;
342                case NCLRSW:
343                    clearflg = -1;
344                    continue;
345
346                case FOLDSW:
347                    if (!(folder = *argp++) || *folder == '-')
348                        adios (NULL, "missing argument to %s", argp[-2]);
349                    continue;
350                case FORMSW:
351                    if (!(form = *argp++) || *form == '-')
352                        adios (NULL, "missing argument to %s", argp[-2]);
353                    continue;
354
355                case FACESW:
356                    if (!(faceproc = *argp++) || *faceproc == '-')
357                        adios (NULL, "missing argument to %s", argp[-2]);
358                    continue;
359                case NFACESW:
360                    faceproc = NULL;
361                    continue;
362                case SLEEPSW:
363                    if (!(cp = *argp++) || *cp == '-')
364                        adios (NULL, "missing argument to %s", argp[-2]);
365                    sleepsw = atoi (cp);/* ZERO ok! */
366                    continue;
367
368                case PROGSW:
369                    if (!(moreproc = *argp++) || *moreproc == '-')
370                        adios (NULL, "missing argument to %s", argp[-2]);
371                    continue;
372                case NPROGSW:
373                    nomore++;
374                    continue;
375
376                case LENSW:
377                    if (!(cp = *argp++) || *cp == '-')
378                        adios (NULL, "missing argument to %s", argp[-2]);
379                    if ((length = atoi (cp)) < 1)
380                        adios (NULL, "bad argument %s %s", argp[-2], cp);
381                    continue;
382                case WIDTHSW:
383                    if (!(cp = *argp++) || *cp == '-')
384                        adios (NULL, "missing argument to %s", argp[-2]);
385                    if ((width = atoi (cp)) < 1)
386                        adios (NULL, "bad argument %s %s", argp[-2], cp);
387                    continue;
388
389                case DGSTSW:
390                    if (!(digest = *argp++) || *digest == '-')
391                        adios (NULL, "missing argument to %s", argp[-2]);
392                    continue;
393                case ISSUESW:
394                    if (!(cp = *argp++) || *cp == '-')
395                        adios (NULL, "missing argument to %s", argp[-2]);
396                    if ((issue = atoi (cp)) < 1)
397                        adios (NULL, "bad argument %s %s", argp[-2], cp);
398                    continue;
399                case VOLUMSW:
400                    if (!(cp = *argp++) || *cp == '-')
401                        adios (NULL, "missing argument to %s", argp[-2]);
402                    if ((volume = atoi (cp)) < 1)
403                        adios (NULL, "bad argument %s %s", argp[-2], cp);
404                    continue;
405
406                case FORW2SW:
407                    forwall++;  /* fall */
408                case FORW1SW:
409                    forwflg++;
410                    clearflg = -1;/* XXX */
411                    continue;
412
413                case BITSTUFFSW:
414                    dashstuff = 1;      /* trinary logic */
415                    continue;
416                case NBITSTUFFSW:
417                    dashstuff = -1;     /* trinary logic */
418                    continue;
419
420                case NBODYSW:
421                    dobody = 0;
422                    continue;
423            }
424        }
425        files[vecp++] = cp;
426    }
427
428    if (!folder)
429        folder = getenv ("mhfolder");
430
431    if (isatty (fileno (stdout))) {
432        if (!nomore && !sc_hardcopy() && moreproc && *moreproc != '\0') {
433            if (mhl_action) {
434                SIGNAL (SIGINT, SIG_IGN);
435                SIGNAL2 (SIGQUIT, quitser);
436            }
437            SIGNAL2 (SIGPIPE, pipeser);
438            m_popen (moreproc);
439            ontty = PITTY;
440        } else {
441            SIGNAL (SIGINT, SIG_IGN);
442            SIGNAL2 (SIGQUIT, quitser);
443            ontty = ISTTY;
444        }
445    } else {
446        ontty = NOTTY;
447    }
448
449    mhl_format (form ? form : mhlformat, length, width);
450
451    if (vecp == 0) {
452        process (folder, NULL, 1, vecp = 1);
453    } else {
454        for (i = 0; i < vecp; i++)
455            process (folder, files[i], i + 1, vecp);
456    }
457
458    if (forwall) {
459        if (digest) {
460            printf ("%s", delim4);
461            if (volume == 0) {
462                snprintf (buf, sizeof(buf), "End of %s Digest\n", digest);
463            } else {
464                snprintf (buf, sizeof(buf), "End of %s Digest [Volume %d Issue %d]\n",
465                        digest, volume, issue);
466            }
467            i = strlen (buf);
468            for (cp = buf + i; i > 1; i--)
469                *cp++ = '*';
470            *cp++ = '\n';
471            *cp = 0;
472            printf ("%s", buf);
473        }
474        else
475            printf ("\n------- End of Forwarded Message%s\n\n",
476                    vecp > 1 ? "s" : "");
477    }
478
479    if (clearflg > 0 && ontty == NOTTY)
480        clear_screen ();
481
482    if (ontty == PITTY)
483        m_pclose ();
484
485    return exitstat;
486}
487
488
489static void
490mhl_format (char *file, int length, int width)
491{
492    int i;
493    char *bp, *cp, **ip;
494    char *ap, buffer[BUFSIZ], name[NAMESZ];
495    struct mcomp *c1;
496    struct stat st;
497    FILE *fp;
498    static dev_t dev = 0;
499    static ino_t ino = 0;
500    static time_t mtime = 0;
501
502    if (fmthd != NULL)
503        if (stat (etcpath (file), &st) != NOTOK
504                && mtime == st.st_mtime
505                && dev == st.st_dev
506                && ino == st.st_ino)
507            goto out;
508        else
509            free_queue (&fmthd, &fmttl);
510
511    if ((fp = fopen (etcpath (file), "r")) == NULL)
512        adios (file, "unable to open format file");
513
514    if (fstat (fileno (fp), &st) != NOTOK) {
515        mtime = st.st_mtime;
516        dev = st.st_dev;
517        ino = st.st_ino;
518    }
519
520    global.c_ovtxt = global.c_nfs = NULL;
521    global.c_fmt = NULL;
522    global.c_offset = 0;
523    global.c_ovoff = -1;
524    if ((i = sc_width ()) > 5)
525        global.c_width = i;
526    global.c_cwidth = -1;
527    if ((i = sc_length ()) > 5)
528        global.c_length = i - 1;
529    global.c_flags = BELL;              /* BELL is default */
530    *(ip = ignores) = NULL;
531
532    while (vfgets (fp, &ap) == OK) {
533        bp = ap;
534        if (*bp == ';')
535            continue;
536
537        if ((cp = strchr(bp, '\n')))
538            *cp = 0;
539
540        if (*bp == ':') {
541            c1 = add_queue (&fmthd, &fmttl, NULL, bp + 1, CLEARTEXT);
542            continue;
543        }
544
545        parptr = bp;
546        strncpy (name, parse(), sizeof(name));
547        switch (*parptr) {
548            case '\0':
549            case ',':
550            case '=':
551                /*
552                 * Split this list of fields to ignore, and copy
553                 * it to the end of the current "ignores" list.
554                 */
555                if (!strcasecmp (name, "ignores")) {
556                    char **tmparray, **p;
557                    int n = 0;
558
559                    /* split the fields */
560                    tmparray = brkstring (getcpy (++parptr), ",", NULL);
561
562                    /* count number of fields split */
563                    p = tmparray;
564                    while (*p++)
565                        n++;
566
567                    /* copy pointers to split fields to ignores array */
568                    ip = copyip (tmparray, ip, MAXARGS - num_ignores);
569                    num_ignores += n;
570                    continue;
571                }
572                parptr = bp;
573                while (*parptr) {
574                    if (evalvar (&global))
575                        adios (NULL, "format file syntax error: %s", bp);
576                    if (*parptr)
577                        parptr++;
578                }
579                continue;
580
581            case ':':
582                c1 = add_queue (&fmthd, &fmttl, name, NULL, INIT);
583                while (*parptr == ':' || *parptr == ',') {
584                    parptr++;
585                    if (evalvar (c1))
586                        adios (NULL, "format file syntax error: %s", bp);
587                }
588                if (!c1->c_nfs && global.c_nfs)
589                    if (c1->c_flags & DATEFMT) {
590                        if (global.c_flags & DATEFMT)
591                            c1->c_nfs = getcpy (global.c_nfs);
592                    }
593                    else
594                        if (c1->c_flags & ADDRFMT) {
595                            if (global.c_flags & ADDRFMT)
596                                c1->c_nfs = getcpy (global.c_nfs);
597                        }
598                continue;
599
600            default:
601                adios (NULL, "format file syntax error: %s", bp);
602        }
603    }
604    fclose (fp);
605
606    if (mhldebug) {
607        for (c1 = fmthd; c1; c1 = c1->c_next) {
608            fprintf (stderr, "c1: name=\"%s\" text=\"%s\" ovtxt=\"%s\"\n",
609                    c1->c_name, c1->c_text, c1->c_ovtxt);
610            fprintf (stderr, "\tnfs=0x%x fmt=0x%x\n",
611                    (unsigned int) c1->c_nfs, (unsigned int) c1->c_fmt);
612            fprintf (stderr, "\toffset=%d ovoff=%d width=%d cwidth=%d length=%d\n",
613                    c1->c_offset, c1->c_ovoff, c1->c_width,
614                    c1->c_cwidth, c1->c_length);
615            fprintf (stderr, "\tflags=%s\n",
616                    snprintb (buffer, sizeof(buffer), (unsigned) c1->c_flags, LBITS));
617        }
618    }
619
620out:
621    if (clearflg == 1) {
622        global.c_flags |= CLEARSCR;
623    } else {
624        if (clearflg == -1)
625            global.c_flags &= ~CLEARSCR;
626    }
627
628    switch (bellflg) {          /* command line may override format file */
629        case 1:
630            global.c_flags |= BELL;
631            break;
632        case -1:
633            global.c_flags &= ~BELL;
634            break;
635    }
636
637    if (length)
638        global.c_length = length;
639    if (width)
640        global.c_width = width;
641    if (global.c_length < 5)
642        global.c_length = 10000;
643    if (global.c_width < 5)
644        global.c_width = 10000;
645}
646
647
648static int
649evalvar (struct mcomp *c1)
650{
651    char *cp, name[NAMESZ];
652    struct triple *ap;
653
654    if (!*parptr)
655        return 0;
656    strncpy (name, parse(), sizeof(name));
657
658    if (!strcasecmp (name, "component")) {
659        if (ptos (name, &c1->c_text))
660            return 1;
661        c1->c_flags &= ~NOCOMPONENT;
662        return 0;
663    }
664
665    if (!strcasecmp (name, "overflowtext"))
666        return ptos (name, &c1->c_ovtxt);
667
668    if (!strcasecmp (name, "formatfield")) {
669        char *nfs;
670
671        if (ptos (name, &cp))
672            return 1;
673        nfs = new_fs (NULL, NULL, cp);
674        c1->c_nfs = getcpy (nfs);
675        c1->c_flags |= FORMAT;
676        return 0;
677    }
678
679    if (!strcasecmp (name, "decode")) {
680        char *nfs;
681
682        nfs = new_fs (NULL, NULL, "%(decode{text})");
683        c1->c_nfs = getcpy (nfs);
684        c1->c_flags |= FORMAT;
685        return 0;
686    }
687
688    if (!strcasecmp (name, "offset"))
689        return ptoi (name, &c1->c_offset);
690    if (!strcasecmp (name, "overflowoffset"))
691        return ptoi (name, &c1->c_ovoff);
692    if (!strcasecmp (name, "width"))
693        return ptoi (name, &c1->c_width);
694    if (!strcasecmp (name, "compwidth"))
695        return ptoi (name, &c1->c_cwidth);
696    if (!strcasecmp (name, "length"))
697        return ptoi (name, &c1->c_length);
698    if (!strcasecmp (name, "nodashstuffing"))
699        return (dashstuff = -1);
700
701    for (ap = triples; ap->t_name; ap++)
702        if (!strcasecmp (ap->t_name, name)) {
703            c1->c_flags |= ap->t_on;
704            c1->c_flags &= ~ap->t_off;
705            return 0;
706        }
707
708    return 1;
709}
710
711
712static int
713ptoi (char *name, int *i)
714{
715    char *cp;
716
717    if (*parptr++ != '=' || !*(cp = parse ())) {
718        advise (NULL, "missing argument to variable %s", name);
719        return 1;
720    }
721
722    *i = atoi (cp);
723    return 0;
724}
725
726
727static int
728ptos (char *name, char **s)
729{
730    char c, *cp;
731
732    if (*parptr++ != '=') {
733        advise (NULL, "missing argument to variable %s", name);
734        return 1;
735    }
736
737    if (*parptr != '"') {
738        for (cp = parptr;
739                *parptr && *parptr != ':' && *parptr != ',';
740                parptr++)
741            continue;
742    } else {
743        for (cp = ++parptr; *parptr && *parptr != '"'; parptr++)
744            if (*parptr == QUOTE)
745                if (!*++parptr)
746                    parptr--;
747    }
748    c = *parptr;
749    *parptr = 0;
750    *s = getcpy (cp);
751    if ((*parptr = c) == '"')
752        parptr++;
753    return 0;
754}
755
756
757static char *
758parse (void)
759{
760    int c;
761    char *cp;
762    static char result[NAMESZ];
763
764    for (cp = result; *parptr && (cp - result < NAMESZ); parptr++) {
765        c = *parptr;
766        if (isalnum (c)
767                || c == '.'
768                || c == '-'
769                || c == '_'
770                || c =='['
771                || c == ']')
772            *cp++ = c;
773        else
774            break;
775    }
776    *cp = '\0';
777
778    return result;
779}
780
781
782static void
783process (char *folder, char *fname, int ofilen, int ofilec)
784{
785    char *cp;
786    FILE *fp;
787    struct mcomp *c1;
788
789    switch (setjmp (env)) {
790        case OK:
791            if (fname) {
792                fp = mhl_action ? (*mhl_action) (fname) : fopen (fname, "r");
793                if (fp == NULL) {
794                    advise (fname, "unable to open");
795                    exitstat++;
796                    return;
797                }
798            } else {
799                fname = "(stdin)";
800                fp = stdin;
801            }
802            cp = folder ? concat (folder, ":", fname, NULL) : getcpy (fname);
803            if (ontty != PITTY)
804                SIGNAL (SIGINT, intrser);
805            mhlfile (fp, cp, ofilen, ofilec);  /* FALL THROUGH! */
806
807        default:
808            if (ontty != PITTY)
809                SIGNAL (SIGINT, SIG_IGN);
810            if (mhl_action == NULL && fp != stdin)
811                fclose (fp);
812            free (cp);
813            if (holder.c_text) {
814                free (holder.c_text);
815                holder.c_text = NULL;
816            }
817            free_queue (&msghd, &msgtl);
818            for (c1 = fmthd; c1; c1 = c1->c_next)
819                c1->c_flags &= ~HDROUTPUT;
820            break;
821    }
822}
823
824
825static void
826mhlfile (FILE *fp, char *mname, int ofilen, int ofilec)
827{
828    int state;
829    struct mcomp *c1, *c2, *c3;
830    char **ip, name[NAMESZ], buf[BUFSIZ];
831
832    if (forwall) {
833        if (digest)
834            printf ("%s", ofilen == 1 ? delim3 : delim4);
835        else {
836            printf ("\n-------");
837            if (ofilen == 1)
838                printf (" Forwarded Message%s", ofilec > 1 ? "s" : "");
839            else
840                printf (" Message %d", ofilen);
841            printf ("\n\n");
842        }
843    } else {
844        switch (ontty) {
845            case PITTY:
846                if (ofilec > 1) {
847                    if (ofilen > 1) {
848                        if ((global.c_flags & CLEARSCR))
849                            clear_screen ();
850                        else
851                            printf ("\n\n\n");
852                    }
853                    printf (">>> %s\n\n", mname);
854                }
855                break;
856
857            case ISTTY:
858                strncpy (buf, "\n", sizeof(buf));
859                if (ofilec > 1) {
860                    if (SOprintf ("Press <return> to list \"%s\"...", mname)) {
861                        if (ofilen > 1)
862                            printf ("\n\n\n");
863                        printf ("Press <return> to list \"%s\"...", mname);
864                    }
865                    fflush (stdout);
866                    buf[0] = 0;
867                    read (fileno (stdout), buf, sizeof(buf));
868                }
869                if (strchr(buf, '\n')) {
870                    if ((global.c_flags & CLEARSCR))
871                        clear_screen ();
872                }
873                else
874                    printf ("\n");
875                break;
876
877            default:
878                if (ofilec > 1) {
879                    if (ofilen > 1) {
880                        printf ("\n\n\n");
881                        if (clearflg > 0)
882                            clear_screen ();
883                    }
884                    printf (">>> %s\n\n", mname);
885                }
886                break;
887        }
888    }
889
890    for (state = FLD;;) {
891        switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) {
892            case FLD:
893            case FLDPLUS:
894                for (ip = ignores; *ip; ip++)
895                    if (!strcasecmp (name, *ip)) {
896                        while (state == FLDPLUS)
897                            state = m_getfld (state, name, buf, sizeof(buf), fp);
898                        break;
899                    }
900                if (*ip)
901                    continue;
902
903                for (c2 = fmthd; c2; c2 = c2->c_next)
904                    if (!strcasecmp (c2->c_name, name))
905                        break;
906                c1 = NULL;
907                if (!((c3 = c2 ? c2 : &global)->c_flags & SPLIT))
908                    for (c1 = msghd; c1; c1 = c1->c_next)
909                        if (!strcasecmp (c1->c_name, c3->c_name)) {
910                            c1->c_text =
911                                mcomp_add (c1->c_flags, buf, c1->c_text);
912                            break;
913                        }
914                if (c1 == NULL)
915                    c1 = add_queue (&msghd, &msgtl, name, buf, 0);
916                while (state == FLDPLUS) {
917                    state = m_getfld (state, name, buf, sizeof(buf), fp);
918                    c1->c_text = add (buf, c1->c_text);
919                }
920                if (c2 == NULL)
921                    c1->c_flags |= EXTRA;
922                continue;
923
924            case BODY:
925            case FILEEOF:
926                row = column = 0;
927                for (c1 = fmthd; c1; c1 = c1->c_next) {
928                    if (c1->c_flags & CLEARTEXT) {
929                        putcomp (c1, c1, ONECOMP);
930                        continue;
931                    }
932                    if (!strcasecmp (c1->c_name, "messagename")) {
933                        holder.c_text = concat ("(Message ", mname, ")\n",
934                                            NULL);
935                        putcomp (c1, &holder, ONECOMP);
936                        free (holder.c_text);
937                        holder.c_text = NULL;
938                        continue;
939                    }
940                    if (!strcasecmp (c1->c_name, "extras")) {
941                        for (c2 = msghd; c2; c2 = c2->c_next)
942                            if (c2->c_flags & EXTRA)
943                                putcomp (c1, c2, TWOCOMP);
944                        continue;
945                    }
946                    if (dobody && !strcasecmp (c1->c_name, "body")) {
947                        if ((holder.c_text = malloc (sizeof(buf))) == NULL)
948                            adios (NULL, "unable to allocate buffer memory");
949                        strncpy (holder.c_text, buf, sizeof(buf));
950                        while (state == BODY) {
951                            putcomp (c1, &holder, BODYCOMP);
952                            state = m_getfld (state, name, holder.c_text,
953                                        sizeof(buf), fp);
954                        }
955                        free (holder.c_text);
956                        holder.c_text = NULL;
957                        continue;
958                    }
959                    for (c2 = msghd; c2; c2 = c2->c_next)
960                        if (!strcasecmp (c2->c_name, c1->c_name)) {
961                            putcomp (c1, c2, ONECOMP);
962                            if (!(c1->c_flags & SPLIT))
963                                break;
964                        }
965                    if (faceproc && c2 == NULL && (c1->c_flags & FACEFMT))
966                        for (c2 = msghd; c2; c2 = c2->c_next)
967                            if (c2->c_flags & FACEDFLT) {
968                                if (c2->c_face == NULL)
969                                    face_format (c2);
970                                if ((holder.c_text = c2->c_face)) {
971                                    putcomp (c1, &holder, ONECOMP);
972                                    holder.c_text = NULL;
973                                }
974                                break;
975                            }
976                }
977                return;
978
979            case LENERR:
980            case FMTERR:
981                advise (NULL, "format error in message %s", mname);
982                exitstat++;
983                return;
984
985            default:
986                adios (NULL, "getfld() returned %d", state);
987        }
988    }
989}
990
991
992static int
993mcomp_flags (char *name)
994{
995    struct pair *ap;
996
997    for (ap = pairs; ap->p_name; ap++)
998        if (!strcasecmp (ap->p_name, name))
999            return (ap->p_flags);
1000
1001    return 0;
1002}
1003
1004
1005static char *
1006mcomp_add (long flags, char *s1, char *s2)
1007{
1008    char *dp;
1009
1010    if (!(flags & ADDRFMT))
1011        return add (s1, s2);
1012
1013    if (s2 && *(dp = s2 + strlen (s2) - 1) == '\n')
1014        *dp = 0;
1015
1016    return add (s1, add (",\n", s2));
1017}
1018
1019
1020struct pqpair {
1021    char *pq_text;
1022    char *pq_error;
1023    struct pqpair *pq_next;
1024};
1025
1026
1027static void
1028mcomp_format (struct mcomp *c1, struct mcomp *c2)
1029{
1030    int dat[5];
1031    char *ap, *cp;
1032    char buffer[BUFSIZ], error[BUFSIZ];
1033    struct comp *cptr;
1034    struct pqpair *p, *q;
1035    struct pqpair pq;
1036    struct mailname *mp;
1037
1038    ap = c2->c_text;
1039    c2->c_text = NULL;
1040    dat[0] = 0;
1041    dat[1] = 0;
1042    dat[2] = 0;
1043    dat[3] = sizeof(buffer) - 1;
1044    dat[4] = 0;
1045    fmt_compile (c1->c_nfs, &c1->c_fmt);
1046
1047    if (!(c1->c_flags & ADDRFMT)) {
1048        FINDCOMP (cptr, "text");
1049        if (cptr)
1050            cptr->c_text = ap;
1051        if ((cp = strrchr(ap, '\n')))   /* drop ending newline */
1052            if (!cp[1])
1053                *cp = 0;
1054
1055        fmt_scan (c1->c_fmt, buffer, sizeof(buffer) - 1, dat);
1056        /* Don't need to append a newline, dctime() already did */
1057        c2->c_text = getcpy (buffer);
1058
1059        free (ap);
1060        return;
1061    }
1062
1063    (q = &pq)->pq_next = NULL;
1064    while ((cp = getname (ap))) {
1065        if ((p = (struct pqpair *) calloc ((size_t) 1, sizeof(*p))) == NULL)
1066            adios (NULL, "unable to allocate pqpair memory");
1067
1068        if ((mp = getm (cp, NULL, 0, AD_NAME, error)) == NULL) {
1069            p->pq_text = getcpy (cp);
1070            p->pq_error = getcpy (error);
1071        } else {
1072            if ((c1->c_flags & FACEDFLT) && c2->c_face == NULL) {
1073                char   *h, *o;
1074                if ((h = mp->m_host) == NULL)
1075                    h = LocalName ();
1076                if ((o = OfficialName (h)))
1077                    h = o;
1078                c2->c_face = concat ("address ", h, " ", mp->m_mbox,
1079                                    NULL);
1080            }
1081            p->pq_text = getcpy (mp->m_text);
1082            mnfree (mp);
1083        }
1084        q = (q->pq_next = p);
1085    }
1086
1087    for (p = pq.pq_next; p; p = q) {
1088        FINDCOMP (cptr, "text");
1089        if (cptr)
1090            cptr->c_text = p->pq_text;
1091        FINDCOMP (cptr, "error");
1092        if (cptr)
1093            cptr->c_text = p->pq_error;
1094
1095        fmt_scan (c1->c_fmt, buffer, sizeof(buffer) - 1, dat);
1096        if (*buffer) {
1097            if (c2->c_text)
1098                c2->c_text = add (",\n", c2->c_text);
1099            if (*(cp = buffer + strlen (buffer) - 1) == '\n')
1100                *cp = 0;
1101            c2->c_text = add (buffer, c2->c_text);
1102        }
1103
1104        free (p->pq_text);
1105        if (p->pq_error)
1106            free (p->pq_error);
1107        q = p->pq_next;
1108        free ((char *) p);
1109    }
1110
1111    c2->c_text = add ("\n", c2->c_text);
1112    free (ap);
1113}
1114
1115
1116static struct mcomp *
1117add_queue (struct mcomp **head, struct mcomp **tail, char *name, char *text, int flags)
1118{
1119    struct mcomp *c1;
1120
1121    if ((c1 = (struct mcomp *) calloc ((size_t) 1, sizeof(*c1))) == NULL)
1122        adios (NULL, "unable to allocate comp memory");
1123
1124    c1->c_flags = flags & ~INIT;
1125    if ((c1->c_name = name ? getcpy (name) : NULL))
1126        c1->c_flags |= mcomp_flags (c1->c_name);
1127    c1->c_text = text ? getcpy (text) : NULL;
1128    if (flags & INIT) {
1129        if (global.c_ovtxt)
1130            c1->c_ovtxt = getcpy (global.c_ovtxt);
1131        c1->c_offset = global.c_offset;
1132        c1->c_ovoff = global. c_ovoff;
1133        c1->c_width = c1->c_length = 0;
1134        c1->c_cwidth = global.c_cwidth;
1135        c1->c_flags |= global.c_flags & GFLAGS;
1136    }
1137    if (*head == NULL)
1138        *head = c1;
1139    if (*tail != NULL)
1140        (*tail)->c_next = c1;
1141    *tail = c1;
1142
1143    return c1;
1144}
1145
1146
1147static void
1148free_queue (struct mcomp **head, struct mcomp **tail)
1149{
1150    struct mcomp *c1, *c2;
1151
1152    for (c1 = *head; c1; c1 = c2) {
1153        c2 = c1->c_next;
1154        if (c1->c_name)
1155            free (c1->c_name);
1156        if (c1->c_text)
1157            free (c1->c_text);
1158        if (c1->c_ovtxt)
1159            free (c1->c_ovtxt);
1160        if (c1->c_nfs)
1161            free (c1->c_nfs);
1162        if (c1->c_fmt)
1163            free ((char *) c1->c_fmt);
1164        if (c1->c_face)
1165            free (c1->c_face);
1166        free ((char *) c1);
1167    }
1168
1169    *head = *tail = NULL;
1170}
1171
1172
1173static void
1174putcomp (struct mcomp *c1, struct mcomp *c2, int flag)
1175{
1176    int count, cchdr;
1177    char *cp;
1178
1179    cchdr = 0;
1180    lm = 0;
1181    llim = c1->c_length ? c1->c_length : -1;
1182    wid = c1->c_width ? c1->c_width : global.c_width;
1183    ovoff = (c1->c_ovoff >= 0 ? c1->c_ovoff : global.c_ovoff)
1184        + c1->c_offset;
1185    if ((ovtxt = c1->c_ovtxt ? c1->c_ovtxt : global.c_ovtxt) == NULL)
1186        ovtxt = "";
1187    if (wid < ovoff + strlen (ovtxt) + 5)
1188        adios (NULL, "component: %s width(%d) too small for overflow(%d)",
1189                c1->c_name, wid, ovoff + strlen (ovtxt) + 5);
1190    onelp = NULL;
1191
1192    if (c1->c_flags & CLEARTEXT) {
1193        putstr (c1->c_text);
1194        putstr ("\n");
1195        return;
1196    }
1197
1198    if (c1->c_flags & FACEFMT)
1199        switch (doface (c2)) {
1200            case NOTOK:         /* error */
1201            case OK:            /* async faceproc */
1202                return;
1203
1204            default:            /* sync faceproc */
1205                break;
1206        }
1207
1208    if (c1->c_nfs && (c1->c_flags & (ADDRFMT | DATEFMT | FORMAT)))
1209        mcomp_format (c1, c2);
1210
1211    if (c1->c_flags & CENTER) {
1212        count = (c1->c_width ? c1->c_width : global.c_width)
1213            - c1->c_offset - strlen (c2->c_text);
1214        if (!(c1->c_flags & HDROUTPUT) && !(c1->c_flags & NOCOMPONENT))
1215            count -= strlen (c1->c_text ? c1->c_text : c1->c_name) + 2;
1216        lm = c1->c_offset + (count / 2);
1217    } else {
1218        if (c1->c_offset)
1219            lm = c1->c_offset;
1220    }
1221
1222    if (!(c1->c_flags & HDROUTPUT) && !(c1->c_flags & NOCOMPONENT)) {
1223        if (c1->c_flags & UPPERCASE)            /* uppercase component also */
1224            for (cp = (c1->c_text ? c1->c_text : c1->c_name); *cp; cp++)
1225                if (islower (*cp))
1226                    *cp = toupper (*cp);
1227        putstr (c1->c_text ? c1->c_text : c1->c_name);
1228        if (flag != BODYCOMP) {
1229            putstr (": ");
1230            if (!(c1->c_flags & SPLIT))
1231                c1->c_flags |= HDROUTPUT;
1232
1233        cchdr++;
1234        if ((count = c1->c_cwidth -
1235                strlen (c1->c_text ? c1->c_text : c1->c_name) - 2) > 0)
1236            while (count--)
1237                putstr (" ");
1238        }
1239        else
1240            c1->c_flags |= HDROUTPUT;           /* for BODYCOMP */
1241    }
1242
1243    if (flag == TWOCOMP
1244            && !(c2->c_flags & HDROUTPUT)
1245            && !(c2->c_flags & NOCOMPONENT)) {
1246        if (c1->c_flags & UPPERCASE)
1247            for (cp = c2->c_name; *cp; cp++)
1248                if (islower (*cp))
1249                    *cp = toupper (*cp);
1250        putstr (c2->c_name);
1251        putstr (": ");
1252        if (!(c1->c_flags & SPLIT))
1253            c2->c_flags |= HDROUTPUT;
1254
1255        cchdr++;
1256        if ((count = c1->c_cwidth - strlen (c2->c_name) - 2) > 0)
1257            while (count--)
1258                putstr (" ");
1259    }
1260    if (c1->c_flags & UPPERCASE)
1261        for (cp = c2->c_text; *cp; cp++)
1262            if (islower (*cp))
1263                *cp = toupper (*cp);
1264
1265    count = 0;
1266    if (cchdr)
1267        if (flag == TWOCOMP)
1268            count = (c1->c_cwidth >= 0) ? c1->c_cwidth
1269                        : strlen (c2->c_name) + 2;
1270        else
1271            count = (c1->c_cwidth >= 0) ? c1->c_cwidth
1272                        : strlen (c1->c_text ? c1->c_text : c1->c_name) + 2;
1273    count += c1->c_offset;
1274
1275    if ((cp = oneline (c2->c_text, c1->c_flags)))
1276       putstr(cp);
1277    if (term == '\n')
1278        putstr ("\n");
1279    while ((cp = oneline (c2->c_text, c1->c_flags))) {
1280        lm = count;
1281        if (flag == BODYCOMP
1282                && !(c1->c_flags & NOCOMPONENT))
1283            putstr (c1->c_text ? c1->c_text : c1->c_name);
1284        if (*cp)
1285            putstr (cp);
1286        if (term == '\n')
1287            putstr ("\n");
1288    }
1289}
1290
1291
1292static char *
1293oneline (char *stuff, long flags)
1294{
1295    int spc;
1296    char *cp, *ret;
1297
1298    if (onelp == NULL)
1299        onelp = stuff;
1300    if (*onelp == 0)
1301        return (onelp = NULL);
1302
1303    ret = onelp;
1304    term = 0;
1305    if (flags & COMPRESS) {
1306        for (spc = 1, cp = ret; *onelp; onelp++)
1307            if (isspace (*onelp)) {
1308                if (*onelp == '\n' && (!onelp[1] || (flags & ADDRFMT))) {
1309                    term = '\n';
1310                    *onelp++ = 0;
1311                    break;
1312                }
1313                else
1314                    if (!spc) {
1315                        *cp++ = ' ';
1316                        spc++;
1317                    }
1318            }
1319            else {
1320                *cp++ = *onelp;
1321                spc = 0;
1322            }
1323
1324        *cp = 0;
1325    }
1326    else {
1327        while (*onelp && *onelp != '\n')
1328            onelp++;
1329        if (*onelp == '\n') {
1330            term = '\n';
1331            *onelp++ = 0;
1332        }
1333        if (flags & LEFTADJUST)
1334            while (*ret == ' ' || *ret == '\t')
1335                ret++;
1336    }
1337    if (*onelp == 0 && term == '\n' && (flags & NONEWLINE))
1338        term = 0;
1339
1340    return ret;
1341}
1342
1343
1344static void
1345putstr (char *string)
1346{
1347    if (!column && lm > 0)
1348        while (lm > 0)
1349            if (lm >= 8) {
1350                putch ('\t');
1351                lm -= 8;
1352            }
1353            else {
1354                putch (' ');
1355                lm--;
1356            }
1357    lm = 0;
1358    while (*string)
1359        putch (*string++);
1360}
1361
1362
1363static void
1364putch (char ch)
1365{
1366    char buf[BUFSIZ];
1367
1368    if (llim == 0)
1369        return;
1370
1371    switch (ch) {
1372        case '\n':
1373            if (llim > 0)
1374                llim--;
1375            column = 0;
1376            row++;
1377            if (ontty != ISTTY || row != global.c_length)
1378                break;
1379            if (global.c_flags & BELL)
1380                putchar ('\007');
1381            fflush (stdout);
1382            buf[0] = 0;
1383            read (fileno (stdout), buf, sizeof(buf));
1384            if (strchr(buf, '\n')) {
1385                if (global.c_flags & CLEARSCR)
1386                    clear_screen ();
1387                row = 0;
1388            } else {
1389                putchar ('\n');
1390                row = global.c_length / 3;
1391            }
1392            return;
1393
1394        case '\t':
1395            column |= 07;
1396            column++;
1397            break;
1398
1399        case '\b':
1400            column--;
1401            break;
1402
1403        case '\r':
1404            column = 0;
1405            break;
1406
1407        default:
1408            /*
1409             * If we are forwarding this message, and the first
1410             * column contains a dash, then add a dash and a space.
1411             */
1412            if (column == 0 && forwflg && (dashstuff >= 0) && ch == '-') {
1413                putchar ('-');
1414                putchar (' ');
1415            }
1416            if (ch >= ' ')
1417                column++;
1418            break;
1419    }
1420
1421    if (column >= wid) {
1422        putch ('\n');
1423        if (ovoff > 0)
1424            lm = ovoff;
1425        putstr (ovtxt ? ovtxt : "");
1426        putch (ch);
1427        return;
1428    }
1429
1430    putchar (ch);
1431}
1432
1433
1434static RETSIGTYPE
1435intrser (int i)
1436{
1437#ifndef RELIABLE_SIGNALS
1438    SIGNAL (SIGINT, intrser);
1439#endif
1440
1441    discard (stdout);
1442    putchar ('\n');
1443    longjmp (env, DONE);
1444}
1445
1446
1447static RETSIGTYPE
1448pipeser (int i)
1449{
1450#ifndef RELIABLE_SIGNALS
1451    SIGNAL (SIGPIPE, pipeser);
1452#endif
1453
1454    done (NOTOK);
1455}
1456
1457
1458static RETSIGTYPE
1459quitser (int i)
1460{
1461#ifndef RELIABLE_SIGNALS
1462    SIGNAL (SIGQUIT, quitser);
1463#endif
1464
1465    putchar ('\n');
1466    fflush (stdout);
1467    done (NOTOK);
1468}
1469
1470
1471static void
1472face_format (struct mcomp *c1)
1473{
1474    char *cp;
1475    struct mailname *mp;
1476
1477    if ((cp = c1->c_text) == NULL)
1478        return;
1479
1480    if ((cp = getname (cp))) {
1481        if ((mp = getm (cp, NULL, 0, AD_NAME, NULL))) {
1482            char *h, *o;
1483            if ((h = mp->m_host) == NULL)
1484                h = LocalName ();
1485            if ((o = OfficialName (h)))
1486                h = o;
1487            c1->c_face = concat ("address ", h, " ", mp->m_mbox, NULL);
1488        }
1489
1490        while ((cp = getname (cp)))
1491            continue;
1492    }
1493}
1494
1495
1496/*
1497 * faceproc is two elements defining the image agent's location:
1498 *     Internet host
1499 *     UDP port
1500 */
1501
1502#include <sys/socket.h>
1503#include <netinet/in.h>
1504#include <netdb.h>
1505
1506#ifdef HAVE_ARPA_INET_H
1507# include <arpa/inet.h>
1508#endif
1509
1510static int
1511doface (struct mcomp *c1)
1512{
1513    int result, sd;
1514    struct sockaddr_in in_socket;
1515    struct sockaddr_in *isock = &in_socket;
1516    static int inited = OK;
1517    static int addrlen;
1518    static struct in_addr addr;
1519    static unsigned short portno;
1520
1521    if (inited == OK) {
1522        char *cp;
1523        char **ap = brkstring (cp = getcpy (faceproc), " ", "\n");
1524        struct hostent *hp;
1525
1526        if (ap[0] == NULL || ap[1] == NULL) {
1527bad_faceproc: ;
1528            free (cp);
1529            return (inited = NOTOK);
1530        }
1531
1532        if (!(hp = gethostbystring (ap[0])))
1533            goto bad_faceproc;
1534        memcpy((char *) &addr, hp->h_addr, addrlen = hp->h_length);
1535
1536        portno = htons ((unsigned short) atoi (ap[1]));
1537        free (cp);
1538
1539        inited = DONE;
1540    }
1541    if (inited == NOTOK)
1542        return NOTOK;
1543
1544    isock->sin_family = AF_INET;
1545    isock->sin_port = portno;
1546    memcpy((char *) &isock->sin_addr, (char *) &addr, addrlen);
1547
1548    if ((sd = socket (AF_INET, SOCK_DGRAM, 0)) == NOTOK)
1549        return NOTOK;
1550
1551    result = sendto (sd, c1->c_text, strlen (c1->c_text), 0,
1552                (struct sockaddr *) isock, sizeof(*isock));
1553
1554    close (sd);
1555
1556    return (result != NOTOK ? OK : NOTOK);
1557}
1558
1559/*
1560 * COMMENTED OUT
1561 * This version doesn't use sockets
1562 */
1563#if 0
1564
1565static int
1566doface (struct mcomp *c1)
1567{
1568    int i, len, vecp;
1569    pid_t child_id;
1570    int result, pdi[2], pdo[2];
1571    char *bp, *cp;
1572    char buffer[BUFSIZ], *vec[10];
1573
1574    if (pipe (pdi) == NOTOK)
1575        return NOTOK;
1576    if (pipe (pdo) == NOTOK) {
1577        close (pdi[0]);
1578        close (pdi[1]);
1579        return NOTOK;
1580    }
1581
1582    for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++)
1583        sleep (5);
1584
1585    switch (child_id) {
1586        case NOTOK:
1587            /* oops... fork error */
1588            return NOTOK;
1589
1590        case OK:
1591            /* child process */
1592            SIGNAL (SIGINT, SIG_IGN);
1593            SIGNAL (SIGQUIT, SIG_IGN);
1594            if (pdi[0] != fileno (stdin)) {
1595                dup2 (pdi[0], fileno (stdin));
1596                close (pdi[0]);
1597            }
1598            close (pdi[1]);
1599            close (pdo[0]);
1600            if (pdo[1] != fileno (stdout)) {
1601                dup2 (pdo[1], fileno (stdout));
1602                close (pdo[1]);
1603            }
1604            vecp = 0;
1605            vec[vecp++] = r1bindex (faceproc, '/');
1606            vec[vecp++] = "-e";
1607            if (sleepsw != NOTOK) {
1608                vec[vecp++] = "-s";
1609                snprintf (buffer, sizeof(buffer), "%d", sleepsw);
1610                vec[vecp++] = buffer;
1611            }
1612            vec[vecp] = NULL;
1613            execvp (faceproc, vec);
1614            fprintf (stderr, "unable to exec ");
1615            perror (faceproc);
1616            _exit (-1);         /* NOTREACHED */
1617
1618        default:
1619            /* parent process */
1620            close (pdi[0]);
1621            i = strlen (c1->c_text);
1622            if (write (pdi[1], c1->c_text, i) != i)
1623                adios ("pipe", "error writing to");
1624            free (c1->c_text), c1->c_text = NULL;
1625            close (pdi[1]);
1626
1627            close (pdo[1]);
1628            cp = NULL, len = 0;
1629            result = DONE;
1630            while ((i = read (pdo[0], buffer, strlen (buffer))) > 0) {
1631                if (cp) {
1632                    int j;
1633                    char *dp;
1634                    if ((dp = realloc (cp, (unsigned) (j = len + i))) == NULL)
1635                        adios (NULL, "unable to allocate face storage");
1636                    memcpy(dp + len, buffer, i);
1637                    cp = dp, len = j;
1638                }
1639                else {
1640                    if ((cp = malloc ((unsigned) i)) == NULL)
1641                        adios (NULL, "unable to allocate face storage");
1642                    memcpy(cp, buffer, i);
1643                    len = i;
1644                }
1645                if (result == DONE)
1646                    for (bp = buffer + i - 1; bp >= buffer; bp--)
1647                        if (!isascii (*bp) || iscntrl (*bp)) {
1648                            result = OK;
1649                            break;
1650                        }
1651            }
1652            close (pdo[0]);
1653
1654/* no waiting for child... */
1655
1656            if (result == OK) { /* binary */
1657                if (write (1, cp, len) != len)
1658                    adios ("writing", "error");
1659                free (cp);
1660            }
1661            else                /* empty */
1662                if ((c1->c_text = cp) == NULL)
1663                    result = OK;
1664            break;
1665    }
1666
1667    return result;
1668}
1669#endif /* COMMENTED OUT */
1670
1671
1672int
1673mhlsbr (int argc, char **argv, FILE *(*action)())
1674{
1675    SIGNAL_HANDLER istat, pstat, qstat;
1676    char *cp;
1677    struct mcomp *c1;
1678
1679    switch (setjmp (mhlenv)) {
1680        case OK:
1681            cp = invo_name;
1682            sleepsw = 0;        /* XXX */
1683            bellflg = clearflg = forwflg = forwall = exitstat = 0;
1684            digest = NULL;
1685            ontty = NOTTY;
1686            mhl_action = action;
1687
1688            /*
1689             * If signal is at default action, then start ignoring
1690             * it, else let it set to its current action.
1691             */
1692            if ((istat = SIGNAL (SIGINT, SIG_IGN)) != SIG_DFL)
1693                SIGNAL (SIGINT, istat);
1694            if ((qstat = SIGNAL (SIGQUIT, SIG_IGN)) != SIG_DFL)
1695                SIGNAL (SIGQUIT, qstat);
1696            pstat = SIGNAL (SIGPIPE, pipeser);
1697            mhl (argc, argv);                  /* FALL THROUGH! */
1698
1699        default:
1700            SIGNAL (SIGINT, istat);
1701            SIGNAL (SIGQUIT, qstat);
1702            SIGNAL (SIGPIPE, SIG_IGN);/* should probably change to block instead */
1703            if (ontty == PITTY)
1704                m_pclose ();
1705            SIGNAL (SIGPIPE, pstat);
1706            invo_name = cp;
1707            if (holder.c_text) {
1708                free (holder.c_text);
1709                holder.c_text = NULL;
1710            }
1711            free_queue (&msghd, &msgtl);
1712            for (c1 = fmthd; c1; c1 = c1->c_next)
1713                c1->c_flags &= ~HDROUTPUT;
1714            return exitstat;
1715    }
1716}
1717
1718#undef adios
1719#undef done
1720
1721static void
1722mhladios (char *what, char *fmt, ...)
1723{
1724    va_list ap;
1725
1726    va_start(ap, fmt);
1727    advertise (what, NULL, fmt, ap);
1728    va_end(ap);
1729    mhldone (1);
1730}
1731
1732
1733static void
1734mhldone (int status)
1735{
1736    exitstat = status;
1737    if (mhl_action)
1738        longjmp (mhlenv, DONE);
1739    else
1740        done (exitstat);
1741}
1742
1743
1744static  int m_pid = NOTOK;
1745static  int sd = NOTOK;
1746
1747static void
1748m_popen (char *name)
1749{
1750    int pd[2];
1751
1752    if (mhl_action && (sd = dup (fileno (stdout))) == NOTOK)
1753        adios ("standard output", "unable to dup()");
1754
1755    if (pipe (pd) == NOTOK)
1756        adios ("pipe", "unable to");
1757
1758    switch (m_pid = vfork ()) {
1759        case NOTOK:
1760            adios ("fork", "unable to");
1761
1762        case OK:
1763            SIGNAL (SIGINT, SIG_DFL);
1764            SIGNAL (SIGQUIT, SIG_DFL);
1765
1766            close (pd[1]);
1767            if (pd[0] != fileno (stdin)) {
1768                dup2 (pd[0], fileno (stdin));
1769                close (pd[0]);
1770            }
1771            execlp (name, r1bindex (name, '/'), NULL);
1772            fprintf (stderr, "unable to exec ");
1773            perror (name);
1774            _exit (-1);
1775
1776        default:
1777            close (pd[0]);
1778            if (pd[1] != fileno (stdout)) {
1779                dup2 (pd[1], fileno (stdout));
1780                close (pd[1]);
1781            }
1782    }
1783}
1784
1785
1786void
1787m_pclose (void)
1788{
1789    if (m_pid == NOTOK)
1790        return;
1791
1792    if (sd != NOTOK) {
1793        fflush (stdout);
1794        if (dup2 (sd, fileno (stdout)) == NOTOK)
1795            adios ("standard output", "unable to dup2()");
1796
1797        clearerr (stdout);
1798        close (sd);
1799        sd = NOTOK;
1800    }
1801    else
1802        fclose (stdout);
1803
1804    pidwait (m_pid, OK);
1805    m_pid = NOTOK;
1806}
Note: See TracBrowser for help on using the repository browser.