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