|
|
1.1 root 1: /* mhlsbr.c - implement the "nifty" message lister */
2:
3: #include "../h/mh.h"
4: #include "../h/addrsbr.h"
5: #include "../h/formatsbr.h"
6: #include "../zotnet/tws.h"
7: #include <ctype.h>
8: #include <setjmp.h>
9: #include <signal.h>
10: #include <stdio.h>
11: #include <sys/types.h>
12: #include <sys/stat.h>
13:
14:
15: /* MAJOR BUG:
16: for a component containing addresses, ADDRFMT, if COMPRESS is also
17: set, then addresses get split wrong (not at the spaces between commas).
18: To fix this correctly, putstr() should know about "atomic" strings that
19: must NOT be broken across lines. That's too difficult for right now
20: (it turns out that there are a number of degernate cases), so in
21: oneline(), instead of
22:
23: (*onelp == '\n' && !onelp[1])
24:
25: being a terminating condition,
26:
27: (*onelp == '\n' && (!onelp[1] || (flags & ADDRFMT)))
28:
29: is used instead. This cuts the line prematurely, and gives us a much
30: better chance of getting things right.
31: */
32:
33:
34: #define ONECOMP 0
35: #define TWOCOMP 1
36: #define BODYCOMP 2
37:
38: #define adios mhladios
39:
40: #define QUOTE '\\'
41:
42: /* */
43:
44: static struct swit mhlswitches[] = {
45: #define BELLSW 0
46: "bell", 0,
47: #define NBELLSW 1
48: "nobell", 0,
49:
50: #define CLRSW 2
51: "clear", 0,
52: #define NCLRSW 3
53: "noclear", 0,
54:
55: #define FOLDSW 4
56: "folder +folder", 0,
57: #define FORMSW 5
58: "form formfile", 0,
59:
60: #define PROGSW 6
61: "moreproc program", 0,
62: #define NPROGSW 7
63: "nomoreproc", 0,
64:
65: #define LENSW 8
66: "length lines", 0,
67: #define WIDSW 9
68: "width columns", 0,
69:
70: #define HELPSW 10
71: "help", 4,
72:
73: #define FORW1SW 11
74: "forward", -7, /* interface from forw */
75: #define FORW2SW 12
76: "forwall", -7, /* .. */
77:
78: #define DASHSW 13
79: "dashmunging", 4,
80: #define NDASHSW 14
81: "nodashmunging", 6,
82:
83: #define DGSTSW 15
84: "digest list", -6,
85:
86: NULL, NULL
87: };
88:
89: /* */
90:
91: struct mcomp {
92: char *c_name; /* component name */
93: char *c_text; /* component text */
94: char *c_ovtxt; /* text overflow indicator */
95: char *c_nfs; /* iff FORMAT */
96: struct format *c_fmt; /* .. */
97:
98: int c_offset; /* left margin indentation */
99: int c_ovoff; /* overflow indentation */
100: int c_width; /* width of field */
101: int c_cwidth; /* width of component */
102: int c_length; /* length in lines */
103:
104: short c_flags;
105: #define NOCOMPONENT 0x0001 /* don't show component name */
106: #define UPPERCASE 0x0002 /* display in all upper case */
107: #define CENTER 0x0004 /* center line */
108: #define CLEARTEXT 0x0008 /* cleartext */
109: #define EXTRA 0x0010 /* an "extra" component */
110: #define HDROUTPUT 0x0020 /* already output */
111: #define CLEARSCR 0x0040 /* clear screen */
112: #define LEFTADJUST 0x0080 /* left justify multiple lines */
113: #define COMPRESS 0x0100 /* compress text */
114: #define ADDRFMT 0x0200 /* contains addresses */
115: #define BELL 0x0400 /* sound bell at EOP */
116: #define DATEFMT 0x0800 /* contains dates */
117: #define FORMAT 0x1000 /* parse address/date */
118: #define INIT 0x2000
119: #define LBITS "\020\01NOCOMPONENT\02UPPERCASE\03CENTER\04CLEARTEXT\05EXTRA\06HDROUTPUT\07CLEARSCR\010LEFTADJUST\011COMPRESS\012ADDRFMT\013BELL\014DATEFMT\015FORMAT\016INIT"
120: #define GFLAGS (NOCOMPONENT | UPPERCASE | CENTER | LEFTADJUST | COMPRESS)
121:
122: struct mcomp *c_next;
123: };
124:
125: static struct mcomp *msghd = NULL;
126: static struct mcomp *msgtl = NULL;
127: static struct mcomp *fmthd = NULL;
128: static struct mcomp *fmttl = NULL;
129:
130: static struct mcomp global = {
131: NULL, NULL, "", NULL, NULL, 0, -1, 80, -1, 40, BELL, NULL
132: };
133: static struct mcomp holder =
134: {
135: NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, NOCOMPONENT, NULL
136: };
137:
138:
139: static struct pair {
140: char *p_name;
141: short p_flags;
142: } pairs[] = {
143: "Date", DATEFMT,
144: "From", ADDRFMT,
145: "Sender", ADDRFMT,
146: "Reply-To", ADDRFMT,
147: "To", ADDRFMT,
148: "cc", ADDRFMT,
149: "Bcc", ADDRFMT,
150: "Resent-Date", DATEFMT,
151: "Resent-From", ADDRFMT,
152: "Resent-Sender", ADDRFMT,
153: "Resent-Reply-To", ADDRFMT,
154: "Resent-To", ADDRFMT,
155: "Resent-cc", ADDRFMT,
156: "Resent-Bcc", ADDRFMT,
157:
158: NULL
159: };
160:
161: static struct triple {
162: char *t_name;
163: short t_on;
164: short t_off;
165: } triples[] = {
166: "nocomponent", NOCOMPONENT, 0,
167: "uppercase", UPPERCASE, 0,
168: "nouppercase", 0, UPPERCASE,
169: "center", CENTER, 0,
170: "nocenter", 0, CENTER,
171: "clearscreen", CLEARSCR, 0,
172: "noclearscreen", 0, CLEARSCR,
173: "noclear", 0, CLEARSCR,
174: "leftadjust", LEFTADJUST, 0,
175: "noleftadjust", 0, LEFTADJUST,
176: "compress", COMPRESS, 0,
177: "nocompress", 0, COMPRESS,
178: "addrfield", ADDRFMT, DATEFMT,
179: "bell", BELL, 0,
180: "nobell", 0, BELL,
181: "datefield", DATEFMT, ADDRFMT,
182:
183: NULL
184: };
185:
186: /* */
187:
188: static int bellflg = 0;
189: static int clearflg = 0;
190: static int forwflg = 0;
191: static int forwall = 0;
192: static int dashflg = 1;
193:
194: static char *digest = NULL;
195:
196: static int exitstat = 0;
197: static int mhldebug = 0;
198:
199: #define PITTY (-1)
200: #define NOTTY 0
201: #define ISTTY 1
202: static int ontty = NOTTY;
203:
204: static int row;
205: static int column;
206:
207: static int lm;
208: static int llim;
209: static int ovoff;
210: static int term;
211: static int wid;
212:
213:
214: static char *ovtxt;
215:
216: static char *onelp;
217:
218:
219: static char *parptr;
220: static char *ignores[MAXARGS];
221:
222:
223: static jmp_buf env;
224: static jmp_buf mhlenv;
225:
226:
227: static char delim3[] = /* from forw.c */
228: "\n------------------------------------------------------------\n\n";
229: static char delim4[] = "\n------------------------------\n\n";
230:
231:
232: static FP (*mhl_action) () = (FP (*) ()) 0;
233:
234: void clear_screen(), mhldone();
235:
236: static int evalvar(), ptoi(), ptos(), mcomp_flags();
237: static char *parse(), *mcomp_add(), *oneline();
238: static void mhl_format(), process(), mhlfile(), mcomp_format(),
239: free_queue(), putcomp(), putstr(), putch(), mhladios(),
240: m_popen();
241: static struct mcomp *add_queue();
242: static SIGDECL intrser(), pipeser(), quitser();
243:
244:
245: /* */
246:
247: /* ARGSUSED */
248:
249: mhl(argc, argv)
250: int argc;
251: char *argv[];
252: {
253: int length = 0,
254: nomore = 0,
255: width = 0,
256: vecp = 0,
257: i;
258: register char *cp,
259: *folder = NULL,
260: *form = NULL,
261: **ap,
262: **argp;
263: char buf[80],
264: *arguments[MAXARGS],
265: *files[MAXARGS];
266:
267: invo_name = r1bindex (argv[0], '/');
268: if ((cp = getenv ("MHLDEBUG")) && *cp)
269: mhldebug++;
270: if ((cp = m_find (invo_name)) != NULL) {
271: ap = brkstring (getcpy (cp), " ", "\n");
272: ap = copyip (ap, arguments);
273: }
274: else
275: ap = arguments;
276: (void) copyip (argv + 1, ap);
277: argp = arguments;
278:
279: /* */
280:
281: vecp = 0;
282: while (cp = *argp++) {
283: if (*cp == '-')
284: switch (smatch (++cp, mhlswitches)) {
285: case AMBIGSW:
286: ambigsw (cp, mhlswitches);
287: mhldone (1);
288: case UNKWNSW:
289: adios (NULLCP, "-%s unknown\n", cp);
290: case HELPSW:
291: (void) sprintf (buf, "%s [switches] [files ...]",
292: invo_name);
293: help (buf, mhlswitches);
294: mhldone (1);
295:
296: case BELLSW:
297: bellflg = 1;
298: continue;
299: case NBELLSW:
300: bellflg = -1;
301: continue;
302:
303: case CLRSW:
304: clearflg = 1;
305: continue;
306: case NCLRSW:
307: clearflg = -1;
308: continue;
309:
310: case FOLDSW:
311: if (!(folder = *argp++) || *folder == '-')
312: adios (NULLCP, "missing argument to %s", argp[-2]);
313: continue;
314: case FORMSW:
315: if (!(form = *argp++) || *form == '-')
316: adios (NULLCP, "missing argument to %s", argp[-2]);
317: continue;
318:
319: case PROGSW:
320: if (!(moreproc = *argp++) || *moreproc == '-')
321: adios (NULLCP, "missing argument to %s", argp[-2]);
322: continue;
323: case NPROGSW:
324: nomore++;
325: continue;
326:
327: case LENSW:
328: if (!(cp = *argp++) || *cp == '-')
329: adios (NULLCP, "missing argument to %s", argp[-2]);
330: if ((length = atoi (cp)) < 1)
331: adios (NULLCP, "bad argument %s %s", argp[-2], cp);
332: continue;
333: case WIDSW:
334: if (!(cp = *argp++) || *cp == '-')
335: adios (NULLCP, "missing argument to %s", argp[-2]);
336: if ((width = atoi (cp)) < 1)
337: adios (NULLCP, "bad argument %s %s", argp[-2], cp);
338: continue;
339:
340: case DGSTSW:
341: if (!(digest = *argp++) || *digest == '-')
342: adios (NULLCP, "missing argument to %s", argp[-2]);
343: case FORW2SW:
344: forwall++; /* fall */
345: case FORW1SW:
346: forwflg++;
347: clearflg = -1;/* XXX */
348: continue;
349:
350: case DASHSW:
351: dashflg++;
352: continue;
353: case NDASHSW:
354: dashflg = 0;
355: continue;
356: }
357: files[vecp++] = cp;
358: }
359:
360: /* */
361:
362: if (!folder)
363: folder = getenv ("mhfolder");
364:
365: if (isatty (fileno (stdout)))
366: if (!nomore && moreproc && *moreproc) {
367: if (mhl_action) {
368: setsig (SIGINT, SIG_IGN);
369: setsig (SIGQUIT, quitser);
370: }
371: m_popen (moreproc);
372: ontty = PITTY;
373: }
374: else {
375: setsig (SIGINT, SIG_IGN);
376: setsig (SIGQUIT, quitser);
377: ontty = ISTTY;
378: }
379: else
380: ontty = NOTTY;
381:
382: mhl_format (form ? form : mhlformat, length, width);
383:
384: if (vecp == 0)
385: process (folder, NULLCP, 1, vecp = 1);
386: else
387: for (i = 0; i < vecp; i++)
388: process (folder, files[i], i + 1, vecp);
389:
390: if (forwall) {
391: if (digest) {
392: printf ("%s", delim4);
393: (void) sprintf (buf, "End of %s Digest\n", digest);
394: i = strlen (buf);
395: for (cp = buf + i; i > 1; i--)
396: *cp++ = '*';
397: *cp++ = '\n';
398: *cp = NULL;
399: printf ("%s", buf);
400: }
401: else
402: printf ("\n------- End of Forwarded Message%s\n\n",
403: vecp > 1 ? "s" : "");
404: }
405:
406: if (clearflg > 0 && ontty == NOTTY)
407: clear_screen ();
408:
409: if (ontty == PITTY)
410: m_pclose ();
411:
412: return exitstat;
413: }
414:
415: /* */
416:
417: static void
418: mhl_format(file, length, width)
419: register char *file;
420: int length, width;
421: {
422: int i;
423: register char *bp,
424: *cp,
425: **ip;
426: char *ap,
427: buffer[BUFSIZ],
428: name[NAMESZ];
429: register struct mcomp *c1;
430: struct stat st;
431: register FILE *fp;
432: static dev_t dev = 0;
433: static ino_t ino = 0;
434: static time_t mtime = 0;
435:
436: if (fmthd != NULL)
437: if (stat (libpath (file), &st) != NOTOK
438: && mtime == st.st_mtime
439: && dev == st.st_dev
440: && ino == st.st_ino)
441: goto out;
442: else
443: free_queue (&fmthd, &fmttl);
444:
445: if ((fp = fopen (libpath (file), "r")) == NULL)
446: adios (file, "unable to open format file");
447:
448: if (fstat (fileno (fp), &st) != NOTOK)
449: mtime = st.st_mtime, dev = st.st_dev, ino = st.st_ino;
450:
451: global.c_ovtxt = global.c_nfs = NULL;
452: global.c_fmt = NULL;
453: global.c_offset = 0;
454: global.c_ovoff = -1;
455: if ((i = sc_width ()) > 5)
456: global.c_width = i;
457: global.c_cwidth = -1;
458: if ((i = sc_length ()) > 5)
459: global.c_length = i - 1;
460: global.c_flags = BELL; /* BELL is default */
461: *(ip = ignores) = NULL;
462:
463: while (vfgets (fp, &ap) == OK) {
464: bp = ap;
465: if (*bp == ';')
466: continue;
467:
468: if (cp = index (bp, '\n'))
469: *cp = NULL;
470:
471: if (*bp == ':') {
472: c1 = add_queue (&fmthd, &fmttl, NULLCP, bp + 1, CLEARTEXT);
473: continue;
474: }
475:
476: parptr = bp;
477: (void) strcpy (name, parse ());
478: switch (*parptr) {
479: case '\0':
480: case ',':
481: case '=':
482: if (uleq (name, "ignores")) {
483: ip = copyip (brkstring (getcpy (++parptr), ",", NULLCP), ip);
484: continue;
485: }
486: parptr = bp;
487: while (*parptr) {
488: if (evalvar (&global))
489: adios (NULLCP, "format file syntax error: %s", bp);
490: if (*parptr)
491: parptr++;
492: }
493: continue;
494:
495: case ':':
496: c1 = add_queue (&fmthd, &fmttl, name, NULLCP, INIT);
497: while (*parptr == ':' || *parptr == ',') {
498: parptr++;
499: if (evalvar (c1))
500: adios (NULLCP, "format file syntax error: %s", bp);
501: }
502: if (!c1 -> c_nfs && global.c_nfs)
503: if (c1 -> c_flags & DATEFMT) {
504: if (global.c_flags & DATEFMT)
505: c1 -> c_nfs = getcpy (global.c_nfs);
506: }
507: else
508: if (c1 -> c_flags & ADDRFMT) {
509: if (global.c_flags & ADDRFMT)
510: c1 -> c_nfs = getcpy (global.c_nfs);
511: }
512: continue;
513:
514: default:
515: adios (NULLCP, "format file syntax error: %s", bp);
516: }
517: }
518: (void) fclose (fp);
519:
520: if (mhldebug)
521: for (c1 = fmthd; c1; c1 = c1 -> c_next) {
522: fprintf (stderr, "c1: name=\"%s\" text=\"%s\" ovtxt=\"%s\"\n",
523: c1 -> c_name, c1 -> c_text, c1 -> c_ovtxt);
524: fprintf (stderr, "\tnfs=0x%x fmt=0x%x\n",
525: c1 -> c_nfs, c1 -> c_fmt);
526: fprintf (stderr, "\toffset=%d ovoff=%d width=%d cwidth=%d length=%d\n",
527: c1 -> c_offset, c1 -> c_ovoff, c1 -> c_width,
528: c1 -> c_cwidth, c1 -> c_length);
529: fprintf (stderr, "\tflags=%s\n",
530: sprintb (buffer, (unsigned) c1 -> c_flags, LBITS));
531: }
532:
533: out: ;
534: if (clearflg == 1)
535: global.c_flags |= CLEARSCR;
536: else
537: if (clearflg == -1)
538: global.c_flags &= ~CLEARSCR;
539:
540: switch (bellflg) { /* command line may override format file */
541: case 1:
542: global.c_flags |= BELL;
543: break;
544: case -1:
545: global.c_flags &= ~BELL;
546: break;
547: }
548:
549: if (length)
550: global.c_length = length;
551: if (width)
552: global.c_width = width;
553: if (global.c_length < 5)
554: global.c_length = 10000;
555: if (global.c_width < 5)
556: global.c_width = 10000;
557: }
558:
559: /* */
560:
561: static int
562: evalvar(c1)
563: register struct mcomp *c1;
564: {
565: char *cp,
566: name[NAMESZ];
567: register struct triple *ap;
568:
569: if (!*parptr)
570: return 0;
571: (void) strcpy (name, parse ());
572:
573: if (uleq (name, "component")) {
574: if (ptos (name, &c1 -> c_text))
575: return 1;
576: c1 -> c_flags &= ~NOCOMPONENT;
577: return 0;
578: }
579: if (uleq (name, "overflowtext"))
580: return ptos (name, &c1 -> c_ovtxt);
581: if (uleq (name, "formatfield")) {
582: if (ptos (name, &cp))
583: return 1;
584: c1 -> c_nfs = getcpy (new_fs (NULLCP, NULLCP, cp));
585: c1 -> c_flags |= FORMAT;
586: return 0;
587: }
588:
589: if (uleq (name, "offset"))
590: return ptoi (name, &c1 -> c_offset);
591: if (uleq (name, "overflowoffset"))
592: return ptoi (name, &c1 -> c_ovoff);
593: if (uleq (name, "width"))
594: return ptoi (name, &c1 -> c_width);
595: if (uleq (name, "compwidth"))
596: return ptoi (name, &c1 -> c_cwidth);
597: if (uleq (name, "length"))
598: return ptoi (name, &c1 -> c_length);
599:
600: for (ap = triples; ap -> t_name; ap++)
601: if (uleq (ap -> t_name, name)) {
602: c1 -> c_flags |= ap -> t_on;
603: c1 -> c_flags &= ~ap -> t_off;
604: return 0;
605: }
606:
607: return 1;
608: }
609:
610: /* */
611:
612: static int
613: ptoi(name, i)
614: register char *name;
615: register int *i;
616: {
617: char *cp;
618:
619: if (*parptr++ != '=' || !*(cp = parse ())) {
620: advise (NULLCP, "missing argument to variable %s", name);
621: return 1;
622: }
623:
624: *i = atoi (cp);
625: return 0;
626: }
627:
628:
629: static int
630: ptos(name, s)
631: register char *name, **s;
632: {
633: char c,
634: *cp;
635:
636: if (*parptr++ != '=') {
637: advise (NULLCP, "missing argument to variable %s", name);
638: return 1;
639: }
640:
641: if (*parptr != '"')
642: for (cp = parptr;
643: *parptr && *parptr != ':' && *parptr != ',';
644: parptr++)
645: continue;
646: else
647: for (cp = ++parptr; *parptr && *parptr != '"'; parptr++)
648: if (*parptr == QUOTE)
649: if (!*++parptr)
650: parptr--;
651: c = *parptr;
652: *parptr = NULL;
653: *s = getcpy (cp);
654: if ((*parptr = c) == '"')
655: parptr++;
656: return 0;
657: }
658:
659: /* */
660:
661: static char *
662: parse()
663: {
664: int c;
665: register char *cp;
666: static char result[NAMESZ];
667:
668: for (cp = result; c = *parptr; parptr++)
669: if (isalnum (c)
670: || c == '.'
671: || c == '-'
672: || c == '_'
673: || c =='['
674: || c == ']')
675: *cp++ = c;
676: else
677: break;
678: *cp = NULL;
679:
680: return result;
681: }
682:
683: /* */
684:
685: static void
686: process(folder, fname, ofilen, ofilec)
687: register char *folder, *fname;
688: int ofilen, ofilec;
689: {
690: register char *cp;
691: register struct mcomp *c1;
692: register FILE *fp;
693:
694: switch (setjmp (env)) {
695: case OK:
696: if (fname) {
697: fp = mhl_action ? (*mhl_action) (fname) : fopen (fname, "r");
698: if (fp == NULL) {
699: advise (fname, "unable to open");
700: exitstat++;
701: return;
702: }
703: }
704: else {
705: fname = "(stdin)";
706: fp = stdin;
707: }
708: cp = folder ? concat (folder, ":", fname, NULLCP) : getcpy (fname);
709: if (ontty != PITTY)
710: (void) signal (SIGINT, intrser);
711: mhlfile (fp, cp, ofilen, ofilec);/* fall */
712:
713: default:
714: if (ontty != PITTY)
715: (void) signal (SIGINT, SIG_IGN);
716: if (mhl_action == NULL && fp != stdin)
717: (void) fclose (fp);
718: free (cp);
719: if (holder.c_text) {
720: free (holder.c_text);
721: holder.c_text = NULL;
722: }
723: free_queue (&msghd, &msgtl);
724: for (c1 = fmthd; c1; c1 = c1 -> c_next)
725: c1 -> c_flags &= ~HDROUTPUT;
726: break;
727: }
728: }
729:
730: /* */
731:
732: static void
733: mhlfile(fp, mname, ofilen, ofilec)
734: register FILE *fp;
735: register char *mname;
736: int ofilen, ofilec;
737: {
738: int state;
739: register struct mcomp *c1,
740: *c2;
741: register char **ip;
742: char name[NAMESZ],
743: buf[BUFSIZ];
744:
745: if (forwall) {
746: if (digest)
747: printf ("%s", ofilen == 1 ? delim3 : delim4);
748: else {
749: printf ("\n-------");
750: if (ofilen == 1)
751: printf (" Forwarded Message%s", ofilec > 1 ? "s" : "");
752: else
753: printf (" Message %d", ofilen);
754: printf ("\n\n");
755: }
756: }
757: else
758: switch (ontty) {
759: case PITTY:
760: if (ofilec > 1) {
761: if (ofilen > 1) {
762: if ((global.c_flags & CLEARSCR))
763: clear_screen ();
764: else
765: printf ("\n\n\n");
766: }
767: printf (">>> %s\n\n", mname);
768: }
769: break;
770:
771: case ISTTY:
772: (void) strcpy (buf, "\n");
773: if (ofilec > 1) {
774: if (SOprintf ("Press <return> to list \"%s\"...", mname)) {
775: if (ofilen > 1)
776: printf ("\n\n\n");
777: printf ("Press <return> to list \"%s\"...", mname);
778: }
779: (void) fflush (stdout);
780: buf[0] = NULL;
781: (void) read (fileno (stdout), buf, sizeof buf);
782: }
783: if (index (buf, '\n')) {
784: if ((global.c_flags & CLEARSCR))
785: clear_screen ();
786: }
787: else
788: printf ("\n");
789: break;
790:
791: default:
792: if (ofilec > 1) {
793: if (ofilen > 1) {
794: printf ("\n\n\n");
795: if (clearflg > 0)
796: clear_screen ();
797: }
798: printf (">>> %s\n\n", mname);
799: }
800: break;
801: }
802:
803: /* */
804:
805: for (state = FLD;;)
806: switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
807: case FLD:
808: case FLDPLUS:
809: for (ip = ignores; *ip; ip++)
810: if (uleq (name, *ip)) {
811: while (state == FLDPLUS)
812: state = m_getfld (state, name, buf, sizeof buf, fp);
813: break;
814: }
815: if (*ip)
816: continue;
817:
818: for (c1 = msghd; c1; c1 = c1 -> c_next)
819: if (uleq (name, c1 -> c_name)) {
820: c1 -> c_text =
821: mcomp_add (c1 -> c_flags, buf, c1 -> c_text);
822: break;
823: }
824: if (c1 == NULL)
825: c1 = add_queue (&msghd, &msgtl, name, buf, 0);
826: while (state == FLDPLUS) {
827: state = m_getfld (state, name, buf, sizeof buf, fp);
828: c1 -> c_text = add (buf, c1 -> c_text);
829: }
830:
831: for (c2 = fmthd; c2; c2 = c2 -> c_next)
832: if (uleq (c2 -> c_name, c1 -> c_name))
833: break;
834: if (c2 == NULL)
835: c1 -> c_flags |= EXTRA;
836: continue;
837:
838: case BODY:
839: case FILEEOF:
840: row = column = 0;
841: for (c1 = fmthd; c1; c1 = c1 -> c_next) {
842: if (c1 -> c_flags & CLEARTEXT) {
843: putcomp (c1, c1, ONECOMP);
844: continue;
845: }
846: if (uleq (c1 -> c_name, "messagename")) {
847: holder.c_text = concat ("(Message ", mname, ")\n",
848: NULLCP);
849: putcomp (c1, &holder, ONECOMP);
850: free (holder.c_text);
851: holder.c_text = NULL;
852: continue;
853: }
854: if (uleq (c1 -> c_name, "extras")) {
855: for (c2 = msghd; c2; c2 = c2 -> c_next)
856: if (c2 -> c_flags & EXTRA)
857: putcomp (c1, c2, TWOCOMP);
858: continue;
859: }
860: if (uleq (c1 -> c_name, "body")) {
861: if ((holder.c_text = malloc (sizeof buf)) == NULL)
862: adios (NULLCP, "unable to allocate buffer memory");
863: (void) strcpy (holder.c_text, buf);
864: while (state == BODY) {
865: putcomp (c1, &holder, BODYCOMP);
866: state = m_getfld (state, name, holder.c_text,
867: sizeof buf, fp);
868: }
869: free (holder.c_text);
870: holder.c_text = NULL;
871: continue;
872: }
873: for (c2 = msghd; c2; c2 = c2 -> c_next)
874: if (uleq (c2 -> c_name, c1 -> c_name)) {
875: putcomp (c1, c2, ONECOMP);
876: break;
877: }
878: }
879: return;
880:
881: case LENERR:
882: case FMTERR:
883: advise (NULLCP, "format error in message %s", mname);
884: exitstat++;
885: return;
886:
887: default:
888: adios (NULLCP, "getfld() returned %d", state);
889: }
890: }
891:
892: /* */
893:
894: static int
895: mcomp_flags(name)
896: register char *name;
897: {
898: register struct pair *ap;
899:
900: for (ap = pairs; ap -> p_name; ap++)
901: if (uleq (ap -> p_name, name))
902: return (ap -> p_flags);
903:
904: return NULL;
905: }
906:
907:
908: static char *
909: mcomp_add(flags, s1, s2)
910: short flags;
911: register char *s1, *s2;
912: {
913: register char *dp;
914:
915: if (!(flags & ADDRFMT))
916: return add (s1, s2);
917:
918: if (s2 && *(dp = s2 + strlen (s2) - 1) == '\n')
919: *dp = NULL;
920:
921: return add (s1, add (",\n", s2));
922: }
923:
924: /* */
925:
926: struct pqpair {
927: char *pq_text;
928: char *pq_error;
929: struct pqpair *pq_next;
930: };
931:
932:
933: static void
934: mcomp_format(c1, c2)
935: register struct mcomp *c1, *c2;
936: {
937: int dat[4];
938: register char *ap,
939: *cp;
940: char buffer[BUFSIZ],
941: error[BUFSIZ];
942: register struct comp *cptr;
943: register struct pqpair *p,
944: *q;
945: struct pqpair pq;
946: register struct mailname *mp;
947:
948: ap = c2 -> c_text;
949: c2 -> c_text = NULL;
950: dat[0] = dat[1] = dat[2] = 0;
951: dat[3] = sizeof buffer - 1;
952: (void) fmt_compile (c1 -> c_nfs, &c1 -> c_fmt);
953:
954: if (c1 -> c_flags & DATEFMT) {
955: FINDCOMP (cptr, "text");
956: if (cptr)
957: cptr -> c_text = ap;
958:
959: (void) fmtscan (c1 -> c_fmt, buffer, sizeof buffer - 1, dat);
960: /* Don't need to append a newline, dctime() already did */
961: c2 -> c_text = getcpy (buffer);
962:
963: free (ap);
964: return;
965: }
966:
967: (q = &pq) -> pq_next = NULL;
968: while (cp = getname (ap)) {
969: if ((p = (struct pqpair *) calloc ((unsigned) 1, sizeof *p)) == NULL)
970: adios (NULLCP, "unable to allocate pqpair memory");
971:
972: if ((mp = getm (cp, NULLCP, 0, AD_NAME, error)) == NULL) {
973: p -> pq_text = getcpy (cp);
974: p -> pq_error = getcpy (error);
975: }
976: else {
977: p -> pq_text = getcpy (mp -> m_text);
978: mnfree (mp);
979: }
980: q = (q -> pq_next = p);
981: }
982:
983: for (p = pq.pq_next; p; p = q) {
984: FINDCOMP (cptr, "text");
985: if (cptr)
986: cptr -> c_text = p -> pq_text;
987: FINDCOMP (cptr, "error");
988: if (cptr)
989: cptr -> c_text = p -> pq_error;
990:
991: (void) fmtscan (c1 -> c_fmt, buffer, sizeof buffer - 1, dat);
992: if (*buffer) {
993: if (c2 -> c_text)
994: c2 -> c_text = add (",\n", c2 -> c_text);
995: if (*(cp = buffer + strlen (buffer) - 1) == '\n')
996: *cp = NULL;
997: c2 -> c_text = add (buffer, c2 -> c_text);
998: }
999:
1000: free (p -> pq_text);
1001: if (p -> pq_error)
1002: free (p -> pq_error);
1003: q = p -> pq_next;
1004: free ((char *) p);
1005: }
1006:
1007: c2 -> c_text = add ("\n", c2 -> c_text);
1008: free (ap);
1009: }
1010:
1011: /* */
1012:
1013: static struct mcomp *
1014: add_queue(head, tail, name, text, flags)
1015: register struct mcomp **head, **tail;
1016: register char *name, *text;
1017: int flags;
1018: {
1019: register struct mcomp *c1;
1020:
1021: if ((c1 = (struct mcomp *) calloc ((unsigned) 1, sizeof *c1)) == NULL)
1022: adios (NULLCP, "unable to allocate comp memory");
1023:
1024: c1 -> c_flags = flags & ~INIT;
1025: if (c1 -> c_name = name ? getcpy (name) : NULL)
1026: c1 -> c_flags |= mcomp_flags (c1 -> c_name);
1027: c1 -> c_text = text ? getcpy (text) : NULL;
1028: if (flags & INIT) {
1029: if (global.c_ovtxt)
1030: c1 -> c_ovtxt = getcpy (global.c_ovtxt);
1031: c1 -> c_offset = global.c_offset;
1032: c1 -> c_ovoff = global. c_ovoff;
1033: c1 -> c_width = c1 -> c_length = 0;
1034: c1 -> c_cwidth = global.c_cwidth;
1035: c1 -> c_flags |= global.c_flags & GFLAGS;
1036: }
1037: if (*head == NULL)
1038: *head = c1;
1039: if (*tail != NULL)
1040: (*tail) -> c_next = c1;
1041: *tail = c1;
1042:
1043: return c1;
1044: }
1045:
1046:
1047: static void
1048: free_queue(head, tail)
1049: register struct mcomp **head, **tail;
1050: {
1051: register struct mcomp *c1,
1052: *c2;
1053:
1054: for (c1 = *head; c1; c1 = c2) {
1055: c2 = c1 -> c_next;
1056: if (c1 -> c_name)
1057: free (c1 -> c_name);
1058: if (c1 -> c_text)
1059: free (c1 -> c_text);
1060: if (c1 -> c_ovtxt)
1061: free (c1 -> c_ovtxt);
1062: if (c1 -> c_nfs)
1063: free (c1 -> c_nfs);
1064: if (c1 -> c_fmt)
1065: free ((char *) c1 -> c_fmt);
1066: free ((char *) c1);
1067: }
1068:
1069: *head = *tail = NULL;
1070: }
1071:
1072: /* */
1073:
1074: static void
1075: putcomp(c1, c2, flag)
1076: register struct mcomp *c1, *c2;
1077: int flag;
1078: {
1079: int count,
1080: cchdr;
1081: register char *cp;
1082: static int lastterm = '\n'; /* initial state */
1083:
1084: cchdr = 0;
1085: lm = 0;
1086: llim = c1 -> c_length ? c1 -> c_length : -1;
1087: wid = c1 -> c_width ? c1 -> c_width : global.c_width;
1088: ovoff = (c1 -> c_ovoff >= 0 ? c1 -> c_ovoff : global.c_ovoff)
1089: + c1 -> c_offset;
1090: if ((ovtxt = c1 -> c_ovtxt ? c1 -> c_ovtxt : global.c_ovtxt) == NULL)
1091: ovtxt = "";
1092: if (wid < ovoff + strlen (ovtxt) + 5)
1093: adios (NULLCP, "component: %s width(%d) too small for overflow(%d)",
1094: c1 -> c_name, wid, ovoff + strlen (ovtxt) + 5);
1095: onelp = NULL;
1096:
1097: if (c1 -> c_flags & CLEARTEXT) {
1098: putstr (c1 -> c_text);
1099: putstr ("\n");
1100: return;
1101: }
1102:
1103: if (c1 -> c_nfs && (c1 -> c_flags & (ADDRFMT | DATEFMT)))
1104: mcomp_format (c1, c2);
1105:
1106: if (c1 -> c_flags & CENTER) {
1107: count = (c1 -> c_width ? c1 -> c_width : global.c_width)
1108: - c1 -> c_offset - strlen (c2 -> c_text);
1109: if (!(c1 -> c_flags & HDROUTPUT) && !(c1 -> c_flags & NOCOMPONENT))
1110: count -= strlen (c1 -> c_text ? c1 -> c_text : c1 -> c_name) + 2;
1111: lm = c1 -> c_offset + (count / 2);
1112: }
1113: else
1114: if (c1 -> c_offset)
1115: lm = c1 -> c_offset;
1116:
1117: if (!(c1 -> c_flags & HDROUTPUT) && !(c1 -> c_flags & NOCOMPONENT)) {
1118: if (c1 -> c_flags & UPPERCASE) /* uppercase component also */
1119: for (cp = (c1 -> c_text ? c1 -> c_text : c1 -> c_name); *cp; cp++)
1120: if (islower (*cp))
1121: *cp = toupper (*cp);
1122: if (flag != BODYCOMP || lastterm == '\n')
1123: putstr (c1 -> c_text ? c1 -> c_text : c1 -> c_name);
1124: if (flag != BODYCOMP) {
1125: putstr (": ");
1126: c1 -> c_flags |= HDROUTPUT;
1127: }
1128:
1129: cchdr++;
1130: if ((count = c1 -> c_cwidth -
1131: strlen (c1 -> c_text ? c1 -> c_text : c1 -> c_name) - 2) > 0)
1132: while (count--)
1133: putstr (" ");
1134: }
1135:
1136: if (flag == TWOCOMP
1137: && !(c2 -> c_flags & HDROUTPUT)
1138: && !(c2 -> c_flags & NOCOMPONENT)) {
1139: if (c1 -> c_flags & UPPERCASE)
1140: for (cp = c2 -> c_name; *cp; cp++)
1141: if (islower (*cp))
1142: *cp = toupper (*cp);
1143: putstr (c2 -> c_name);
1144: putstr (": ");
1145: c2 -> c_flags |= HDROUTPUT;
1146: }
1147: if (c1 -> c_flags & UPPERCASE)
1148: for (cp = c2 -> c_text; *cp; cp++)
1149: if (islower (*cp))
1150: *cp = toupper (*cp);
1151:
1152: count = 0;
1153: if (cchdr)
1154: count = (c1 -> c_cwidth >= 0) ? c1 -> c_cwidth
1155: : strlen (c1 -> c_text ? c1 -> c_text : c1 -> c_name) + 2;
1156: count += c1 -> c_offset;
1157:
1158: putstr (oneline (c2 -> c_text, c1 -> c_flags));
1159: if (term == '\n')
1160: putstr ("\n");
1161: lastterm = term;
1162: while (cp = oneline (c2 -> c_text, c1 -> c_flags)) {
1163: if (flag == BODYCOMP
1164: && lastterm == '\n'
1165: && !(c1 -> c_flags & HDROUTPUT)
1166: && !(c1 -> c_flags & NOCOMPONENT))
1167: putstr (c1 -> c_text ? c1 -> c_text : c1 -> c_name);
1168: if (*cp) {
1169: lm = count;
1170: putstr (cp);
1171: }
1172: if (term == '\n')
1173: putstr ("\n");
1174: lastterm = term;
1175: }
1176: }
1177:
1178: /* */
1179:
1180: static char *
1181: oneline(stuff, flags)
1182: register char *stuff;
1183: short flags;
1184: {
1185: int spc;
1186: register char *cp,
1187: *ret;
1188:
1189: if (onelp == NULL)
1190: onelp = stuff;
1191: if (*onelp == NULL)
1192: return (onelp = NULL);
1193:
1194: ret = onelp;
1195: term = 0;
1196: if (flags & COMPRESS) {
1197: for (spc = 1, cp = ret; *onelp; onelp++)
1198: if (isspace (*onelp)) {
1199: if (*onelp == '\n' && (!onelp[1] || (flags & ADDRFMT))) {
1200: term = '\n';
1201: *onelp++ = NULL;
1202: break;
1203: }
1204: else
1205: if (!spc) {
1206: *cp++ = ' ';
1207: spc++;
1208: }
1209: }
1210: else {
1211: *cp++ = *onelp;
1212: spc = 0;
1213: }
1214:
1215: *cp = NULL;
1216: }
1217: else {
1218: while (*onelp && *onelp != '\n')
1219: onelp++;
1220: if (*onelp == '\n') {
1221: term = '\n';
1222: *onelp++ = NULL;
1223: }
1224: if (flags & LEFTADJUST)
1225: while (*ret == ' ' || *ret == '\t')
1226: ret++;
1227: }
1228:
1229: return ret;
1230: }
1231:
1232: /* */
1233:
1234: static void
1235: putstr(string)
1236: register char *string;
1237: {
1238: if (!column && lm > 0)
1239: while (lm > 0)
1240: if (lm >= 8) {
1241: putch ('\t');
1242: lm -= 8;
1243: }
1244: else {
1245: putch (' ');
1246: lm--;
1247: }
1248: lm = 0;
1249: while (*string)
1250: putch (*string++);
1251: }
1252:
1253: /* */
1254:
1255: static void
1256: putch(ch)
1257: register char ch;
1258: {
1259: char buf[BUFSIZ];
1260:
1261: if (llim == 0)
1262: return;
1263:
1264: switch (ch) {
1265: case '\n':
1266: if (llim > 0)
1267: llim--;
1268: column = 0;
1269: row++;
1270: if (ontty != ISTTY || row != global.c_length)
1271: break;
1272: if (global.c_flags & BELL)
1273: (void) putchar ('\007');
1274: (void) fflush (stdout);
1275: buf[0] = NULL;
1276: (void) read (fileno (stdout), buf, sizeof buf);
1277: if (index (buf, '\n')) {
1278: if (global.c_flags & CLEARSCR)
1279: clear_screen ();
1280: row = 0;
1281: }
1282: else {
1283: (void) putchar ('\n');
1284: row = global.c_length / 3;
1285: }
1286: return;
1287:
1288: case '\t':
1289: column |= 07;
1290: column++;
1291: break;
1292:
1293: case '\b':
1294: column--;
1295: break;
1296:
1297: case '\r':
1298: column = 0;
1299: break;
1300:
1301: default:
1302: if (column == 0 && forwflg && dashflg && ch == '-')
1303: (void) putchar ('-'), putchar (' ');
1304: if (ch >= ' ')
1305: column++;
1306: break;
1307: }
1308:
1309: if (column >= wid) {
1310: putch ('\n');
1311: if (ovoff > 0)
1312: lm = ovoff;
1313: putstr (ovtxt ? ovtxt : "");
1314: putch (ch);
1315: return;
1316: }
1317:
1318: (void) putchar (ch);
1319: }
1320:
1321: /* */
1322:
1323: /* ARGSUSED */
1324:
1325: static SIGDECL
1326: intrser(i)
1327: int i;
1328: {
1329: #ifndef BSD42
1330: (void) signal (SIGINT, intrser);
1331: #endif BSD42
1332:
1333: discard (stdout);
1334: (void) putchar ('\n');
1335:
1336: longjmp (env, DONE);
1337: }
1338:
1339:
1340: /* ARGSUSED */
1341:
1342: static SIGDECL
1343: pipeser(i)
1344: int i;
1345: {
1346: #ifndef BSD42
1347: (void) signal (SIGPIPE, pipeser);
1348: #endif BSD42
1349:
1350: mhldone (NOTOK);
1351: }
1352:
1353:
1354: /* ARGSUSED */
1355:
1356: static SIGDECL
1357: quitser(i)
1358: int i;
1359: {
1360: #ifndef BSD42
1361: (void) signal (SIGQUIT, quitser);
1362: #endif BSD42
1363:
1364: (void) putchar ('\n');
1365: (void) fflush (stdout);
1366:
1367: mhldone (NOTOK);
1368: }
1369:
1370: /* */
1371:
1372: #undef adios
1373:
1374: mhlsbr(argc, argv, action)
1375: int argc;
1376: register char **argv;
1377: register FP (*action)();
1378: {
1379: SIGDECL (*istat)(), (*pstat)(), (*qstat)();
1380: register char *cp;
1381: register struct mcomp *c1;
1382:
1383: switch (setjmp (mhlenv)) {
1384: case OK:
1385: cp = invo_name;
1386: bellflg = clearflg = forwflg = forwall = exitstat = 0;
1387: digest = NULL;
1388: ontty = NOTTY;
1389: mhl_action = action;
1390: if ((istat = signal (SIGINT, SIG_IGN)) != SIG_DFL)
1391: (void) signal (SIGINT, istat);
1392: if ((qstat = signal (SIGQUIT, SIG_IGN)) != SIG_DFL)
1393: (void) signal (SIGQUIT, qstat);
1394: pstat = signal (SIGPIPE, pipeser);
1395: (void) mhl (argc, argv); /* fall */
1396:
1397: default:
1398: (void) signal (SIGINT, istat);
1399: (void) signal (SIGQUIT, qstat);
1400: (void) signal (SIGPIPE, SIG_IGN);/* XXX */
1401: if (ontty == PITTY)
1402: m_pclose ();
1403: (void) signal (SIGPIPE, pstat);
1404: invo_name = cp;
1405: if (holder.c_text) {
1406: free (holder.c_text);
1407: holder.c_text = NULL;
1408: }
1409: free_queue (&msghd, &msgtl);
1410: for (c1 = fmthd; c1; c1 = c1 -> c_next)
1411: c1 -> c_flags &= ~HDROUTPUT;
1412: return exitstat;
1413: }
1414: }
1415:
1416: /* */
1417:
1418: /* VARARGS2 */
1419:
1420: static void
1421: mhladios(what, fmt, a, b, c, d, e, f)
1422: char *what, *fmt, *a, *b, *c, *d, *e, *f;
1423: {
1424: advise (what, fmt, a, b, c, d, e, f);
1425: mhldone (1);
1426: }
1427:
1428:
1429: void
1430: mhldone(status)
1431: int status;
1432: {
1433: exitstat = status;
1434: if (mhl_action)
1435: longjmp (mhlenv, DONE);
1436: else
1437: done(exitstat); /* call real done() */
1438: }
1439:
1440: /* */
1441:
1442: static int m_pid = NOTOK;
1443: static int sd = NOTOK;
1444:
1445:
1446: static void
1447: m_popen(name)
1448: char *name;
1449: {
1450: int pd[2];
1451:
1452: if (mhl_action && (sd = dup (fileno (stdout))) == NOTOK)
1453: adios ("standard output", "unable to dup()");
1454:
1455: if (pipe (pd) == NOTOK)
1456: adios ("pipe", "unable to");
1457:
1458: switch (m_pid = vfork ()) {
1459: case NOTOK:
1460: adios ("fork", "unable to");
1461:
1462: case OK:
1463: (void) signal (SIGINT, SIG_DFL);
1464: (void) signal (SIGQUIT, SIG_DFL);
1465:
1466: (void) close (pd[1]);
1467: if (pd[0] != fileno (stdin)) {
1468: (void) dup2 (pd[0], fileno (stdin));
1469: (void) close (pd[0]);
1470: }
1471: execlp (name, r1bindex (name, '/'), NULLCP);
1472: fprintf (stderr, "unable to exec ");
1473: perror (name);
1474: _exit (-1);
1475:
1476: default:
1477: (void) close (pd[0]);
1478: if (pd[1] != fileno (stdout)) {
1479: (void) dup2 (pd[1], fileno (stdout));
1480: (void) close (pd[1]);
1481: }
1482: }
1483: }
1484:
1485:
1486: m_pclose()
1487: {
1488: if (m_pid == NOTOK)
1489: return;
1490:
1491: if (sd != NOTOK) {
1492: (void) fflush (stdout);
1493: if (dup2 (sd, fileno (stdout)) == NOTOK)
1494: adios ("standard output", "unable to dup2()");
1495:
1496: clearerr (stdout);
1497: (void) close (sd);
1498: sd = NOTOK;
1499: }
1500: else
1501: (void) fclose (stdout);
1502:
1503: (void) pidwait (m_pid, OK);
1504: m_pid = NOTOK;
1505: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.