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