botched copyright
[unix-history] / usr / src / usr.bin / mail / collect.c
CommitLineData
9552e6b8
DF
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
2ae9f53f 7#ifndef lint
2fd8b883 8static char *sccsid = "@(#)collect.c 5.2 (Berkeley) %G%";
9552e6b8 9#endif not lint
06300dd9
KS
10
11/*
12 * Mail -- a mail program
13 *
14 * Collect input from standard input, handling
15 * ~ escapes.
16 */
17
06300dd9
KS
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
34static int (*savesig)(); /* Previous SIGINT value */
7feecf47 35static int (*savehup)(); /* Previous SIGHUP value */
ea394d88 36# ifdef VMUNIX
2d55c063 37static int (*savecont)(); /* Previous SIGCONT value */
ea394d88 38# endif VMUNIX
06300dd9
KS
39static FILE *newi; /* File for saving away */
40static FILE *newo; /* Output side of same */
41static int hf; /* Ignore interrups */
06300dd9
KS
42static int hadintr; /* Have seen one SIGINT so far */
43
44static jmp_buf coljmp; /* To get back to work */
45
46FILE *
47collect(hp)
48 struct header *hp;
49{
50 FILE *ibuf, *fbuf, *obuf;
0fa68535 51 int lc, cc, escape, collrub(), intack(), collhup, collcont(), eof;
06300dd9
KS
52 register int c, t;
53 char linebuf[LINESIZE], *cp;
54 extern char tempMail[];
97bff179 55 int notify();
ea394d88 56 extern collintsig(), collhupsig();
4e161d3b 57 char getsub;
06300dd9
KS
58
59 noreset++;
06300dd9
KS
60 ibuf = obuf = NULL;
61 if (value("ignore") != NOSTR)
62 hf = 1;
63 else
64 hf = 0;
06300dd9 65 hadintr = 0;
ea394d88 66# ifdef VMUNIX
7feecf47 67 if ((savesig = sigset(SIGINT, SIG_IGN)) != SIG_IGN)
56d6aa4a 68 sigset(SIGINT, hf ? intack : collrub), sigblock(sigmask(SIGINT));
7feecf47 69 if ((savehup = sigset(SIGHUP, SIG_IGN)) != SIG_IGN)
56d6aa4a 70 sigset(SIGHUP, collrub), sigblock(sigmask(SIGHUP));
2d55c063 71 savecont = sigset(SIGCONT, collcont);
ea394d88
KS
72# else VMUNIX
73 savesig = signal(SIGINT, SIG_IGN);
74 savehup = signal(SIGHUP, SIG_IGN);
75# endif VMUNIX
06300dd9
KS
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;
4e161d3b 99 getsub = 0;
06300dd9 100 if (intty && sflag == NOSTR && hp->h_subject == NOSTR && value("ask"))
4e161d3b 101 t &= ~GNL, getsub++;
06300dd9
KS
102 if (hp->h_seq != 0) {
103 puthead(hp, stdout, t);
104 fflush(stdout);
105 }
06300dd9
KS
106 escape = ESCAPE;
107 if ((cp = value("escape")) != NOSTR)
108 escape = *cp;
0fa68535 109 eof = 0;
06300dd9 110 for (;;) {
56d6aa4a 111 int omask = sigblock(0) &~ (sigmask(SIGINT)|sigmask(SIGHUP));
4bc721c3 112
06300dd9 113 setjmp(coljmp);
ea394d88 114# ifdef VMUNIX
4bc721c3 115 sigsetmask(omask);
ea394d88
KS
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
80187484 122 fflush(stdout);
4e161d3b
RC
123 if (getsub) {
124 grabh(hp, GSUBJECT);
125 getsub = 0;
126 continue;
127 }
0fa68535
KS
128 if (readline(stdin, linebuf) <= 0) {
129 if (intty && value("ignoreeof") != NOSTR) {
130 if (++eof > 35)
131 break;
ef45c47a 132 printf("Use \".\" to terminate letter\n",
0fa68535
KS
133 escape);
134 continue;
135 }
06300dd9 136 break;
0fa68535
KS
137 }
138 eof = 0;
06300dd9 139 hadintr = 0;
b068a67e
KS
140 if (intty && equal(".", linebuf) &&
141 (value("dot") != NOSTR || value("ignoreeof") != NOSTR))
06300dd9 142 break;
3dffb9c8 143 if (linebuf[0] != escape || rflag != NOSTR) {
06300dd9
KS
144 if ((t = putline(obuf, linebuf)) < 0)
145 goto err;
146 continue;
147 }
148 c = linebuf[1];
06300dd9
KS
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
343c874e 188 execute(&linebuf[2], 1);
20a47dee 189 printf("(continue)\n");
06300dd9
KS
190 break;
191
192 case '.':
193 /*
194 * Simulate end of file on input.
195 */
ea394d88 196 goto eofl;
06300dd9
KS
197
198 case 'q':
199 case 'Q':
200 /*
201 * Force a quit of sending mail.
202 * Act like an interrupt happened.
203 */
204
06300dd9
KS
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);
80187484 289 fflush(stdout);
06300dd9
KS
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 '?':
06300dd9 345 if ((fbuf = fopen(THELPFILE, "r")) == NULL) {
e5cd0021 346 perror(THELPFILE);
06300dd9
KS
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);
06300dd9
KS
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;
06300dd9
KS
403 }
404 }
ea394d88 405eofl:
06300dd9
KS
406 fclose(obuf);
407 rewind(ibuf);
7feecf47
KS
408 sigset(SIGINT, savesig);
409 sigset(SIGHUP, savehup);
ea394d88 410# ifdef VMUNIX
97bff179 411 sigset(SIGCONT, savecont);
4bc721c3 412 sigsetmask(0);
ea394d88 413# endif VMUNIX
06300dd9
KS
414 noreset = 0;
415 return(ibuf);
416
417err:
418 if (ibuf != NULL)
419 fclose(ibuf);
420 if (obuf != NULL)
421 fclose(obuf);
7feecf47
KS
422 sigset(SIGINT, savesig);
423 sigset(SIGHUP, savehup);
ea394d88 424# ifdef VMUNIX
2d55c063 425 sigset(SIGCONT, savecont);
4bc721c3 426 sigsetmask(0);
ea394d88 427# endif VMUNIX
06300dd9
KS
428 noreset = 0;
429 return(NULL);
430}
431
432/*
433 * Non destructively interrogate the value of the given signal.
434 */
435
436psig(n)
437{
438 register (*wassig)();
439
7feecf47
KS
440 wassig = sigset(n, SIG_IGN);
441 sigset(n, wassig);
06300dd9
KS
442 return((int) wassig);
443}
444
445/*
446 * Write a file, ex-like if f set.
447 */
448
449exwrite(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 }
6d1cdf8d 463 if (stat(name, &junk) >= 0 && (junk.st_mode & S_IFMT) == S_IFREG) {
06300dd9
KS
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
500FILE *
501mesedit(ibuf, obuf, c)
502 FILE *ibuf, *obuf;
503{
504 int pid, s;
505 FILE *fbuf;
506 register int t;
5deb0e1e 507 int (*sig)(), (*scont)(), signull();
06300dd9
KS
508 struct stat sbuf;
509 extern char tempMail[], tempEdit[];
510 register char *edit;
511
7feecf47 512 sig = sigset(SIGINT, SIG_IGN);
ea394d88 513# ifdef VMUNIX
5deb0e1e 514 scont = sigset(SIGCONT, signull);
ea394d88 515# endif VMUNIX
06300dd9
KS
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) {
5388d5b8 543 sigchild();
06300dd9 544 if (sig != SIG_IGN)
7feecf47 545 sigsys(SIGINT, SIG_DFL);
06300dd9
KS
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 ;
5b0c1c37 557 if ((s & 0377) != 0) {
06300dd9
KS
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;
583fix:
584 perror(tempEdit);
585out:
ea394d88 586# ifdef VMUNIX
97bff179 587 sigset(SIGCONT, scont);
ea394d88 588# endif VMUNIX
7feecf47 589 sigset(SIGINT, sig);
06300dd9
KS
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
601FILE *
602mespipe(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);
7feecf47 623 savesig = sigset(SIGINT, SIG_IGN);
06300dd9
KS
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
5388d5b8 638 sigchild();
06300dd9
KS
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);
7feecf47 667 sigset(SIGINT, savesig);
06300dd9
KS
668 return(no);
669
670err:
671 fclose(no);
672 fclose(ni);
7feecf47 673 sigset(SIGINT, savesig);
06300dd9
KS
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 */
06300dd9
KS
685forward(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') {
5deb0e1e 710 if (transmit(&message[*ip-1], obuf) < 0L) {
06300dd9
KS
711 perror(tempMail);
712 return(-1);
713 }
714 } else
99f2cebd 715 if (send(&message[*ip-1], obuf, 0) < 0) {
06300dd9
KS
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
5deb0e1e 731long
06300dd9
KS
732transmit(mailp, obuf)
733 struct message *mailp;
734 FILE *obuf;
735{
736 register struct message *mp;
5deb0e1e
CS
737 register int ch;
738 long c, n;
739 int bol;
06300dd9
KS
740 FILE *ibuf;
741
742 mp = mailp;
743 ibuf = setinput(mp);
5deb0e1e 744 c = mp->m_size;
06300dd9
KS
745 n = c;
746 bol = 1;
5deb0e1e 747 while (c-- > 0L) {
06300dd9
KS
748 if (bol) {
749 bol = 0;
750 putc('\t', obuf);
751 n++;
752 if (ferror(obuf)) {
753 perror("/tmp");
5deb0e1e 754 return(-1L);
06300dd9
KS
755 }
756 }
757 ch = getc(ibuf);
758 if (ch == '\n')
759 bol++;
760 putc(ch, obuf);
761 if (ferror(obuf)) {
762 perror("/tmp");
5deb0e1e 763 return(-1L);
06300dd9
KS
764 }
765 }
766 return(n);
767}
768
2d55c063
KS
769/*
770 * Print (continue) when continued after ^Z.
771 */
772collcont(s)
773{
774
775 printf("(continue)\n");
776 fflush(stdout);
777}
778
06300dd9
KS
779/*
780 * On interrupt, go here to save the partial
7feecf47 781 * message on ~/dead.letter.
06300dd9
KS
782 * Then restore signals and execute the normal
783 * signal routine. We only come here if signals
784 * were previously set anyway.
785 */
786
ea394d88
KS
787# ifndef VMUNIX
788collintsig()
789{
790 signal(SIGINT, SIG_IGN);
791 collrub(SIGINT);
792}
793
794collhupsig()
795{
796 signal(SIGHUP, SIG_IGN);
797 collrub(SIGHUP);
798}
799# endif VMUNIX
800
06300dd9
KS
801collrub(s)
802{
803 register FILE *dbuf;
804 register int c;
805
7feecf47 806 if (s == SIGINT && hadintr == 0) {
06300dd9 807 hadintr++;
80187484
RC
808 fflush(stdout);
809 fprintf(stderr, "\n(Interrupt -- one more to kill letter)\n");
06300dd9
KS
810 longjmp(coljmp, 1);
811 }
812 fclose(newo);
813 rewind(newi);
7feecf47 814 if (s == SIGINT && value("nosave") != NOSTR || fsize(newi) == 0)
06300dd9
KS
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
823done:
824 fclose(newi);
7feecf47
KS
825 sigset(SIGINT, savesig);
826 sigset(SIGHUP, savehup);
ea394d88 827# ifdef VMUNIX
2d55c063 828 sigset(SIGCONT, savecont);
ea394d88 829# endif VMUNIX
7feecf47
KS
830 if (rcvmode) {
831 if (s == SIGHUP)
832 hangup(SIGHUP);
833 else
2d55c063 834 stop(s);
7feecf47 835 }
06300dd9
KS
836 else
837 exit(1);
838}
839
840/*
841 * Acknowledge an interrupt signal from the tty by typing an @
842 */
843
844intack(s)
845{
846
06300dd9
KS
847 puts("@");
848 fflush(stdout);
849 clearerr(stdin);
06300dd9
KS
850}
851
852/*
853 * Add a string to the end of a header entry field.
854 */
855
856char *
857addto(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}