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