|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: static char *sccsid = "@(#)collect.c 5.2 (Berkeley) 6/21/85";
9: #endif not lint
10:
11: /*
12: * Mail -- a mail program
13: *
14: * Collect input from standard input, handling
15: * ~ escapes.
16: */
17:
18: #include "rcv.h"
19: #include <sys/stat.h>
20:
21: /*
22: * Read a message from standard output and return a read file to it
23: * or NULL on error.
24: */
25:
26: /*
27: * The following hokiness with global variables is so that on
28: * receipt of an interrupt signal, the partial message can be salted
29: * away on dead.letter. The output file must be available to flush,
30: * and the input to read. Several open files could be saved all through
31: * Mail if stdio allowed simultaneous read/write access.
32: */
33:
34: static int (*savesig)(); /* Previous SIGINT value */
35: static int (*savehup)(); /* Previous SIGHUP value */
36: # ifdef VMUNIX
37: static int (*savecont)(); /* Previous SIGCONT value */
38: # endif VMUNIX
39: static FILE *newi; /* File for saving away */
40: static FILE *newo; /* Output side of same */
41: static int hf; /* Ignore interrups */
42: static int hadintr; /* Have seen one SIGINT so far */
43:
44: static jmp_buf coljmp; /* To get back to work */
45:
46: FILE *
47: collect(hp)
48: struct header *hp;
49: {
50: FILE *ibuf, *fbuf, *obuf;
51: int lc, cc, escape, collrub(), intack(), collhup, collcont(), eof;
52: register int c, t;
53: char linebuf[LINESIZE], *cp;
54: extern char tempMail[];
55: int notify();
56: extern collintsig(), collhupsig();
57: char getsub;
58:
59: noreset++;
60: ibuf = obuf = NULL;
61: if (value("ignore") != NOSTR)
62: hf = 1;
63: else
64: hf = 0;
65: hadintr = 0;
66: # ifdef VMUNIX
67: if ((savesig = sigset(SIGINT, SIG_IGN)) != SIG_IGN)
68: sigset(SIGINT, hf ? intack : collrub), sigblock(sigmask(SIGINT));
69: if ((savehup = sigset(SIGHUP, SIG_IGN)) != SIG_IGN)
70: sigset(SIGHUP, collrub), sigblock(sigmask(SIGHUP));
71: savecont = sigset(SIGCONT, collcont);
72: # else VMUNIX
73: savesig = signal(SIGINT, SIG_IGN);
74: savehup = signal(SIGHUP, SIG_IGN);
75: # endif VMUNIX
76: newi = NULL;
77: newo = NULL;
78: if ((obuf = fopen(tempMail, "w")) == NULL) {
79: perror(tempMail);
80: goto err;
81: }
82: newo = obuf;
83: if ((ibuf = fopen(tempMail, "r")) == NULL) {
84: perror(tempMail);
85: newo = NULL;
86: fclose(obuf);
87: goto err;
88: }
89: newi = ibuf;
90: remove(tempMail);
91:
92: /*
93: * If we are going to prompt for a subject,
94: * refrain from printing a newline after
95: * the headers (since some people mind).
96: */
97:
98: t = GTO|GSUBJECT|GCC|GNL;
99: getsub = 0;
100: if (intty && sflag == NOSTR && hp->h_subject == NOSTR && value("ask"))
101: t &= ~GNL, getsub++;
102: if (hp->h_seq != 0) {
103: puthead(hp, stdout, t);
104: fflush(stdout);
105: }
106: escape = ESCAPE;
107: if ((cp = value("escape")) != NOSTR)
108: escape = *cp;
109: eof = 0;
110: for (;;) {
111: int omask = sigblock(0) &~ (sigmask(SIGINT)|sigmask(SIGHUP));
112:
113: setjmp(coljmp);
114: # ifdef VMUNIX
115: sigsetmask(omask);
116: # else VMUNIX
117: if (savesig != SIG_IGN)
118: signal(SIGINT, hf ? intack : collintsig);
119: if (savehup != SIG_IGN)
120: signal(SIGHUP, collhupsig);
121: # endif VMUNIX
122: fflush(stdout);
123: if (getsub) {
124: grabh(hp, GSUBJECT);
125: getsub = 0;
126: continue;
127: }
128: if (readline(stdin, linebuf) <= 0) {
129: if (intty && value("ignoreeof") != NOSTR) {
130: if (++eof > 35)
131: break;
132: printf("Use \".\" to terminate letter\n",
133: escape);
134: continue;
135: }
136: break;
137: }
138: eof = 0;
139: hadintr = 0;
140: if (intty && equal(".", linebuf) &&
141: (value("dot") != NOSTR || value("ignoreeof") != NOSTR))
142: break;
143: if (linebuf[0] != escape || rflag != NOSTR) {
144: if ((t = putline(obuf, linebuf)) < 0)
145: goto err;
146: continue;
147: }
148: c = linebuf[1];
149: switch (c) {
150: default:
151: /*
152: * On double escape, just send the single one.
153: * Otherwise, it's an error.
154: */
155:
156: if (c == escape) {
157: if (putline(obuf, &linebuf[1]) < 0)
158: goto err;
159: else
160: break;
161: }
162: printf("Unknown tilde escape.\n");
163: break;
164:
165: case 'C':
166: /*
167: * Dump core.
168: */
169:
170: core();
171: break;
172:
173: case '!':
174: /*
175: * Shell escape, send the balance of the
176: * line to sh -c.
177: */
178:
179: shell(&linebuf[2]);
180: break;
181:
182: case ':':
183: case '_':
184: /*
185: * Escape to command mode, but be nice!
186: */
187:
188: execute(&linebuf[2], 1);
189: printf("(continue)\n");
190: break;
191:
192: case '.':
193: /*
194: * Simulate end of file on input.
195: */
196: goto eofl;
197:
198: case 'q':
199: case 'Q':
200: /*
201: * Force a quit of sending mail.
202: * Act like an interrupt happened.
203: */
204:
205: hadintr++;
206: collrub(SIGINT);
207: exit(1);
208:
209: case 'h':
210: /*
211: * Grab a bunch of headers.
212: */
213: if (!intty || !outtty) {
214: printf("~h: no can do!?\n");
215: break;
216: }
217: grabh(hp, GTO|GSUBJECT|GCC|GBCC);
218: printf("(continue)\n");
219: break;
220:
221: case 't':
222: /*
223: * Add to the To list.
224: */
225:
226: hp->h_to = addto(hp->h_to, &linebuf[2]);
227: hp->h_seq++;
228: break;
229:
230: case 's':
231: /*
232: * Set the Subject list.
233: */
234:
235: cp = &linebuf[2];
236: while (any(*cp, " \t"))
237: cp++;
238: hp->h_subject = savestr(cp);
239: hp->h_seq++;
240: break;
241:
242: case 'c':
243: /*
244: * Add to the CC list.
245: */
246:
247: hp->h_cc = addto(hp->h_cc, &linebuf[2]);
248: hp->h_seq++;
249: break;
250:
251: case 'b':
252: /*
253: * Add stuff to blind carbon copies list.
254: */
255: hp->h_bcc = addto(hp->h_bcc, &linebuf[2]);
256: hp->h_seq++;
257: break;
258:
259: case 'd':
260: copy(deadletter, &linebuf[2]);
261: /* fall into . . . */
262:
263: case 'r':
264: /*
265: * Invoke a file:
266: * Search for the file name,
267: * then open it and copy the contents to obuf.
268: */
269:
270: cp = &linebuf[2];
271: while (any(*cp, " \t"))
272: cp++;
273: if (*cp == '\0') {
274: printf("Interpolate what file?\n");
275: break;
276: }
277: cp = expand(cp);
278: if (cp == NOSTR)
279: break;
280: if (isdir(cp)) {
281: printf("%s: directory\n");
282: break;
283: }
284: if ((fbuf = fopen(cp, "r")) == NULL) {
285: perror(cp);
286: break;
287: }
288: printf("\"%s\" ", cp);
289: fflush(stdout);
290: lc = 0;
291: cc = 0;
292: while (readline(fbuf, linebuf) > 0) {
293: lc++;
294: if ((t = putline(obuf, linebuf)) < 0) {
295: fclose(fbuf);
296: goto err;
297: }
298: cc += t;
299: }
300: fclose(fbuf);
301: printf("%d/%d\n", lc, cc);
302: break;
303:
304: case 'w':
305: /*
306: * Write the message on a file.
307: */
308:
309: cp = &linebuf[2];
310: while (any(*cp, " \t"))
311: cp++;
312: if (*cp == '\0') {
313: fprintf(stderr, "Write what file!?\n");
314: break;
315: }
316: if ((cp = expand(cp)) == NOSTR)
317: break;
318: fflush(obuf);
319: rewind(ibuf);
320: exwrite(cp, ibuf, 1);
321: break;
322:
323: case 'm':
324: case 'f':
325: /*
326: * Interpolate the named messages, if we
327: * are in receiving mail mode. Does the
328: * standard list processing garbage.
329: * If ~f is given, we don't shift over.
330: */
331:
332: if (!rcvmode) {
333: printf("No messages to send from!?!\n");
334: break;
335: }
336: cp = &linebuf[2];
337: while (any(*cp, " \t"))
338: cp++;
339: if (forward(cp, obuf, c) < 0)
340: goto err;
341: printf("(continue)\n");
342: break;
343:
344: case '?':
345: if ((fbuf = fopen(THELPFILE, "r")) == NULL) {
346: perror(THELPFILE);
347: break;
348: }
349: t = getc(fbuf);
350: while (t != -1) {
351: putchar(t);
352: t = getc(fbuf);
353: }
354: fclose(fbuf);
355: break;
356:
357: case 'p':
358: /*
359: * Print out the current state of the
360: * message without altering anything.
361: */
362:
363: fflush(obuf);
364: rewind(ibuf);
365: printf("-------\nMessage contains:\n");
366: puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL);
367: t = getc(ibuf);
368: while (t != EOF) {
369: putchar(t);
370: t = getc(ibuf);
371: }
372: printf("(continue)\n");
373: break;
374:
375: case '^':
376: case '|':
377: /*
378: * Pipe message through command.
379: * Collect output as new message.
380: */
381:
382: obuf = mespipe(ibuf, obuf, &linebuf[2]);
383: newo = obuf;
384: ibuf = newi;
385: newi = ibuf;
386: printf("(continue)\n");
387: break;
388:
389: case 'v':
390: case 'e':
391: /*
392: * Edit the current message.
393: * 'e' means to use EDITOR
394: * 'v' means to use VISUAL
395: */
396:
397: if ((obuf = mesedit(ibuf, obuf, c)) == NULL)
398: goto err;
399: newo = obuf;
400: ibuf = newi;
401: printf("(continue)\n");
402: break;
403: }
404: }
405: eofl:
406: fclose(obuf);
407: rewind(ibuf);
408: sigset(SIGINT, savesig);
409: sigset(SIGHUP, savehup);
410: # ifdef VMUNIX
411: sigset(SIGCONT, savecont);
412: sigsetmask(0);
413: # endif VMUNIX
414: noreset = 0;
415: return(ibuf);
416:
417: err:
418: if (ibuf != NULL)
419: fclose(ibuf);
420: if (obuf != NULL)
421: fclose(obuf);
422: sigset(SIGINT, savesig);
423: sigset(SIGHUP, savehup);
424: # ifdef VMUNIX
425: sigset(SIGCONT, savecont);
426: sigsetmask(0);
427: # endif VMUNIX
428: noreset = 0;
429: return(NULL);
430: }
431:
432: /*
433: * Non destructively interrogate the value of the given signal.
434: */
435:
436: psig(n)
437: {
438: register (*wassig)();
439:
440: wassig = sigset(n, SIG_IGN);
441: sigset(n, wassig);
442: return((int) wassig);
443: }
444:
445: /*
446: * Write a file, ex-like if f set.
447: */
448:
449: exwrite(name, ibuf, f)
450: char name[];
451: FILE *ibuf;
452: {
453: register FILE *of;
454: register int c;
455: long cc;
456: int lc;
457: struct stat junk;
458:
459: if (f) {
460: printf("\"%s\" ", name);
461: fflush(stdout);
462: }
463: if (stat(name, &junk) >= 0 && (junk.st_mode & S_IFMT) == S_IFREG) {
464: if (!f)
465: fprintf(stderr, "%s: ", name);
466: fprintf(stderr, "File exists\n", name);
467: return(-1);
468: }
469: if ((of = fopen(name, "w")) == NULL) {
470: perror(NOSTR);
471: return(-1);
472: }
473: lc = 0;
474: cc = 0;
475: while ((c = getc(ibuf)) != EOF) {
476: cc++;
477: if (c == '\n')
478: lc++;
479: putc(c, of);
480: if (ferror(of)) {
481: perror(name);
482: fclose(of);
483: return(-1);
484: }
485: }
486: fclose(of);
487: printf("%d/%ld\n", lc, cc);
488: fflush(stdout);
489: return(0);
490: }
491:
492: /*
493: * Edit the message being collected on ibuf and obuf.
494: * Write the message out onto some poorly-named temp file
495: * and point an editor at it.
496: *
497: * On return, make the edit file the new temp file.
498: */
499:
500: FILE *
501: mesedit(ibuf, obuf, c)
502: FILE *ibuf, *obuf;
503: {
504: int pid, s;
505: FILE *fbuf;
506: register int t;
507: int (*sig)(), (*scont)(), signull();
508: struct stat sbuf;
509: extern char tempMail[], tempEdit[];
510: register char *edit;
511:
512: sig = sigset(SIGINT, SIG_IGN);
513: # ifdef VMUNIX
514: scont = sigset(SIGCONT, signull);
515: # endif VMUNIX
516: if (stat(tempEdit, &sbuf) >= 0) {
517: printf("%s: file exists\n", tempEdit);
518: goto out;
519: }
520: close(creat(tempEdit, 0600));
521: if ((fbuf = fopen(tempEdit, "w")) == NULL) {
522: perror(tempEdit);
523: goto out;
524: }
525: fflush(obuf);
526: rewind(ibuf);
527: t = getc(ibuf);
528: while (t != EOF) {
529: putc(t, fbuf);
530: t = getc(ibuf);
531: }
532: fflush(fbuf);
533: if (ferror(fbuf)) {
534: perror(tempEdit);
535: remove(tempEdit);
536: goto fix;
537: }
538: fclose(fbuf);
539: if ((edit = value(c == 'e' ? "EDITOR" : "VISUAL")) == NOSTR)
540: edit = c == 'e' ? EDITOR : VISUAL;
541: pid = vfork();
542: if (pid == 0) {
543: sigchild();
544: if (sig != SIG_IGN)
545: sigsys(SIGINT, SIG_DFL);
546: execl(edit, edit, tempEdit, 0);
547: perror(edit);
548: _exit(1);
549: }
550: if (pid == -1) {
551: perror("fork");
552: remove(tempEdit);
553: goto out;
554: }
555: while (wait(&s) != pid)
556: ;
557: if ((s & 0377) != 0) {
558: printf("Fatal error in \"%s\"\n", edit);
559: remove(tempEdit);
560: goto out;
561: }
562:
563: /*
564: * Now switch to new file.
565: */
566:
567: if ((fbuf = fopen(tempEdit, "a")) == NULL) {
568: perror(tempEdit);
569: remove(tempEdit);
570: goto out;
571: }
572: if ((ibuf = fopen(tempEdit, "r")) == NULL) {
573: perror(tempEdit);
574: fclose(fbuf);
575: remove(tempEdit);
576: goto out;
577: }
578: remove(tempEdit);
579: fclose(obuf);
580: fclose(newi);
581: obuf = fbuf;
582: goto out;
583: fix:
584: perror(tempEdit);
585: out:
586: # ifdef VMUNIX
587: sigset(SIGCONT, scont);
588: # endif VMUNIX
589: sigset(SIGINT, sig);
590: newi = ibuf;
591: return(obuf);
592: }
593:
594: /*
595: * Pipe the message through the command.
596: * Old message is on stdin of command;
597: * New message collected from stdout.
598: * Sh -c must return 0 to accept the new message.
599: */
600:
601: FILE *
602: mespipe(ibuf, obuf, cmd)
603: FILE *ibuf, *obuf;
604: char cmd[];
605: {
606: register FILE *ni, *no;
607: int pid, s;
608: int (*savesig)();
609: char *Shell;
610:
611: newi = ibuf;
612: if ((no = fopen(tempEdit, "w")) == NULL) {
613: perror(tempEdit);
614: return(obuf);
615: }
616: if ((ni = fopen(tempEdit, "r")) == NULL) {
617: perror(tempEdit);
618: fclose(no);
619: remove(tempEdit);
620: return(obuf);
621: }
622: remove(tempEdit);
623: savesig = sigset(SIGINT, SIG_IGN);
624: fflush(obuf);
625: rewind(ibuf);
626: if ((Shell = value("SHELL")) == NULL)
627: Shell = "/bin/sh";
628: if ((pid = vfork()) == -1) {
629: perror("fork");
630: goto err;
631: }
632: if (pid == 0) {
633: /*
634: * stdin = current message.
635: * stdout = new message.
636: */
637:
638: sigchild();
639: close(0);
640: dup(fileno(ibuf));
641: close(1);
642: dup(fileno(no));
643: for (s = 4; s < 15; s++)
644: close(s);
645: execl(Shell, Shell, "-c", cmd, 0);
646: perror(Shell);
647: _exit(1);
648: }
649: while (wait(&s) != pid)
650: ;
651: if (s != 0 || pid == -1) {
652: fprintf(stderr, "\"%s\" failed!?\n", cmd);
653: goto err;
654: }
655: if (fsize(ni) == 0) {
656: fprintf(stderr, "No bytes from \"%s\" !?\n", cmd);
657: goto err;
658: }
659:
660: /*
661: * Take new files.
662: */
663:
664: newi = ni;
665: fclose(ibuf);
666: fclose(obuf);
667: sigset(SIGINT, savesig);
668: return(no);
669:
670: err:
671: fclose(no);
672: fclose(ni);
673: sigset(SIGINT, savesig);
674: return(obuf);
675: }
676:
677: /*
678: * Interpolate the named messages into the current
679: * message, preceding each line with a tab.
680: * Return a count of the number of characters now in
681: * the message, or -1 if an error is encountered writing
682: * the message temporary. The flag argument is 'm' if we
683: * should shift over and 'f' if not.
684: */
685: forward(ms, obuf, f)
686: char ms[];
687: FILE *obuf;
688: {
689: register int *msgvec, *ip;
690: extern char tempMail[];
691:
692: msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec);
693: if (msgvec == (int *) NOSTR)
694: return(0);
695: if (getmsglist(ms, msgvec, 0) < 0)
696: return(0);
697: if (*msgvec == NULL) {
698: *msgvec = first(0, MMNORM);
699: if (*msgvec == NULL) {
700: printf("No appropriate messages\n");
701: return(0);
702: }
703: msgvec[1] = NULL;
704: }
705: printf("Interpolating:");
706: for (ip = msgvec; *ip != NULL; ip++) {
707: touch(*ip);
708: printf(" %d", *ip);
709: if (f == 'm') {
710: if (transmit(&message[*ip-1], obuf) < 0L) {
711: perror(tempMail);
712: return(-1);
713: }
714: } else
715: if (send(&message[*ip-1], obuf, 0) < 0) {
716: perror(tempMail);
717: return(-1);
718: }
719: }
720: printf("\n");
721: return(0);
722: }
723:
724: /*
725: * Send message described by the passed pointer to the
726: * passed output buffer. Insert a tab in front of each
727: * line. Return a count of the characters sent, or -1
728: * on error.
729: */
730:
731: long
732: transmit(mailp, obuf)
733: struct message *mailp;
734: FILE *obuf;
735: {
736: register struct message *mp;
737: register int ch;
738: long c, n;
739: int bol;
740: FILE *ibuf;
741:
742: mp = mailp;
743: ibuf = setinput(mp);
744: c = mp->m_size;
745: n = c;
746: bol = 1;
747: while (c-- > 0L) {
748: if (bol) {
749: bol = 0;
750: putc('\t', obuf);
751: n++;
752: if (ferror(obuf)) {
753: perror("/tmp");
754: return(-1L);
755: }
756: }
757: ch = getc(ibuf);
758: if (ch == '\n')
759: bol++;
760: putc(ch, obuf);
761: if (ferror(obuf)) {
762: perror("/tmp");
763: return(-1L);
764: }
765: }
766: return(n);
767: }
768:
769: /*
770: * Print (continue) when continued after ^Z.
771: */
772: collcont(s)
773: {
774:
775: printf("(continue)\n");
776: fflush(stdout);
777: }
778:
779: /*
780: * On interrupt, go here to save the partial
781: * message on ~/dead.letter.
782: * Then restore signals and execute the normal
783: * signal routine. We only come here if signals
784: * were previously set anyway.
785: */
786:
787: # ifndef VMUNIX
788: collintsig()
789: {
790: signal(SIGINT, SIG_IGN);
791: collrub(SIGINT);
792: }
793:
794: collhupsig()
795: {
796: signal(SIGHUP, SIG_IGN);
797: collrub(SIGHUP);
798: }
799: # endif VMUNIX
800:
801: collrub(s)
802: {
803: register FILE *dbuf;
804: register int c;
805:
806: if (s == SIGINT && hadintr == 0) {
807: hadintr++;
808: fflush(stdout);
809: fprintf(stderr, "\n(Interrupt -- one more to kill letter)\n");
810: longjmp(coljmp, 1);
811: }
812: fclose(newo);
813: rewind(newi);
814: if (s == SIGINT && value("nosave") != NOSTR || fsize(newi) == 0)
815: goto done;
816: if ((dbuf = fopen(deadletter, "w")) == NULL)
817: goto done;
818: chmod(deadletter, 0600);
819: while ((c = getc(newi)) != EOF)
820: putc(c, dbuf);
821: fclose(dbuf);
822:
823: done:
824: fclose(newi);
825: sigset(SIGINT, savesig);
826: sigset(SIGHUP, savehup);
827: # ifdef VMUNIX
828: sigset(SIGCONT, savecont);
829: # endif VMUNIX
830: if (rcvmode) {
831: if (s == SIGHUP)
832: hangup(SIGHUP);
833: else
834: stop(s);
835: }
836: else
837: exit(1);
838: }
839:
840: /*
841: * Acknowledge an interrupt signal from the tty by typing an @
842: */
843:
844: intack(s)
845: {
846:
847: puts("@");
848: fflush(stdout);
849: clearerr(stdin);
850: }
851:
852: /*
853: * Add a string to the end of a header entry field.
854: */
855:
856: char *
857: addto(hf, news)
858: char hf[], news[];
859: {
860: register char *cp, *cp2, *linebuf;
861:
862: if (hf == NOSTR)
863: hf = "";
864: if (*news == '\0')
865: return(hf);
866: linebuf = salloc(strlen(hf) + strlen(news) + 2);
867: for (cp = hf; any(*cp, " \t"); cp++)
868: ;
869: for (cp2 = linebuf; *cp;)
870: *cp2++ = *cp++;
871: *cp2++ = ' ';
872: for (cp = news; any(*cp, " \t"); cp++)
873: ;
874: while (*cp != '\0')
875: *cp2++ = *cp++;
876: *cp2 = '\0';
877: return(linebuf);
878: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.