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