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