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