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