xref: /original-bsd/usr.bin/tip/cmds.c (revision a910c8b7)
1 #ifndef lint
2 static char sccsid[] = "@(#)cmds.c	4.14 (Berkeley) 09/12/84";
3 #endif
4 
5 #include "tip.h"
6 /*
7  * tip
8  *
9  * miscellaneous commands
10  */
11 
12 int	quant[] = { 60, 60, 24 };
13 
14 char	null = '\0';
15 char	*sep[] = { "second", "minute", "hour" };
16 static char *argv[10];		/* argument vector for take and put */
17 
18 int	timeout();		/* timeout function called on alarm */
19 int	stopsnd();		/* SIGINT handler during file transfers */
20 int	intprompt();		/* used in handling SIG_INT during prompt */
21 int	intcopy();		/* interrupt routine for file transfers */
22 
23 /*
24  * FTP - remote ==> local
25  *  get a file from the remote host
26  */
27 getfl(c)
28 	char c;
29 {
30 	char buf[256], *cp, *expand();
31 
32 	putchar(c);
33 	/*
34 	 * get the UNIX receiving file's name
35 	 */
36 	if (prompt("Local file name? ", copyname))
37 		return;
38 	cp = expand(copyname);
39 	if ((sfd = creat(cp, 0666)) < 0) {
40 		printf("\r\n%s: cannot creat\r\n", copyname);
41 		return;
42 	}
43 
44 	/*
45 	 * collect parameters
46 	 */
47 	if (prompt("List command for remote system? ", buf)) {
48 		unlink(copyname);
49 		return;
50 	}
51 	transfer(buf, sfd, value(EOFREAD));
52 }
53 
54 /*
55  * Cu-like take command
56  */
57 cu_take(cc)
58 	char cc;
59 {
60 	int fd, argc;
61 	char line[BUFSIZ], *expand(), *cp;
62 
63 	if (prompt("[take] ", copyname))
64 		return;
65 	if ((argc = args(copyname, argv)) < 1 || argc > 2) {
66 		printf("usage: <take> from [to]\r\n");
67 		return;
68 	}
69 	if (argc == 1)
70 		argv[1] = argv[0];
71 	cp = expand(argv[1]);
72 	if ((fd = creat(cp, 0666)) < 0) {
73 		printf("\r\n%s: cannot create\r\n", argv[1]);
74 		return;
75 	}
76 	sprintf(line, "cat %s;echo \01", argv[0]);
77 	transfer(line, fd, "\01");
78 }
79 
80 static	jmp_buf intbuf;
81 /*
82  * Bulk transfer routine --
83  *  used by getfl(), cu_take(), and pipefile()
84  */
85 transfer(buf, fd, eofchars)
86 	char *buf, *eofchars;
87 {
88 	register int ct;
89 	char c, buffer[BUFSIZ];
90 	register char *p = buffer;
91 	register int cnt, eof;
92 	time_t start;
93 	int (*f)();
94 
95 	pwrite(FD, buf, size(buf));
96 	quit = 0;
97 	kill(pid, SIGIOT);
98 	read(repdes[0], (char *)&ccc, 1);  /* Wait until read process stops */
99 
100 	/*
101 	 * finish command
102 	 */
103 	pwrite(FD, "\r", 1);
104 	do
105 		read(FD, &c, 1);
106 	while ((c&0177) != '\n');
107 	ioctl(0, TIOCSETC, &defchars);
108 
109 	(void) setjmp(intbuf);
110 	f = signal(SIGINT, intcopy);
111 	start = time(0);
112 	for (ct = 0; !quit;) {
113 		eof = read(FD, &c, 1) <= 0;
114 		c &= 0177;
115 		if (quit)
116 			continue;
117 		if (eof || any(c, eofchars))
118 			break;
119 		if (c == 0)
120 			continue;	/* ignore nulls */
121 		if (c == '\r')
122 			continue;
123 		*p++ = c;
124 
125 		if (c == '\n' && boolean(value(VERBOSE)))
126 			printf("\r%d", ++ct);
127 		if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) {
128 			if (write(fd, buffer, cnt) != cnt) {
129 				printf("\r\nwrite error\r\n");
130 				quit = 1;
131 			}
132 			p = buffer;
133 		}
134 	}
135 	if (cnt = (p-buffer))
136 		if (write(fd, buffer, cnt) != cnt)
137 			printf("\r\nwrite error\r\n");
138 
139 	if (boolean(value(VERBOSE)))
140 		prtime(" lines transferred in ", time(0)-start);
141 	ioctl(0, TIOCSETC, &tchars);
142 	write(fildes[1], (char *)&ccc, 1);
143 	signal(SIGINT, f);
144 	close(fd);
145 }
146 
147 /*
148  * FTP - remote ==> local process
149  *   send remote input to local process via pipe
150  */
151 pipefile()
152 {
153 	int cpid, pdes[2];
154 	char buf[256];
155 	int status, p;
156 	extern int errno;
157 
158 	if (prompt("Local command? ", buf))
159 		return;
160 
161 	if (pipe(pdes)) {
162 		printf("can't establish pipe\r\n");
163 		return;
164 	}
165 
166 	if ((cpid = fork()) < 0) {
167 		printf("can't fork!\r\n");
168 		return;
169 	} else if (cpid) {
170 		if (prompt("List command for remote system? ", buf)) {
171 			close(pdes[0]), close(pdes[1]);
172 			kill (cpid, SIGKILL);
173 		} else {
174 			close(pdes[0]);
175 			signal(SIGPIPE, intcopy);
176 			transfer(buf, pdes[1], value(EOFREAD));
177 			signal(SIGPIPE, SIG_DFL);
178 			while ((p = wait(&status)) > 0 && p != cpid)
179 				;
180 		}
181 	} else {
182 		register int f;
183 
184 		dup2(pdes[0], 0);
185 		close(pdes[0]);
186 		for (f = 3; f < 20; f++)
187 			close(f);
188 		execute(buf);
189 		printf("can't execl!\r\n");
190 		exit(0);
191 	}
192 }
193 
194 /*
195  * Interrupt service routine for FTP
196  */
197 stopsnd()
198 {
199 
200 	stop = 1;
201 	signal(SIGINT, SIG_IGN);
202 }
203 
204 /*
205  * FTP - local ==> remote
206  *  send local file to remote host
207  *  terminate transmission with pseudo EOF sequence
208  */
209 sendfile(cc)
210 	char cc;
211 {
212 	FILE *fd;
213 	char *fnamex;
214 	char *expand();
215 
216 	putchar(cc);
217 	/*
218 	 * get file name
219 	 */
220 	if (prompt("Local file name? ", fname))
221 		return;
222 
223 	/*
224 	 * look up file
225 	 */
226 	fnamex = expand(fname);
227 	if ((fd = fopen(fnamex, "r")) == NULL) {
228 		printf("%s: cannot open\r\n", fname);
229 		return;
230 	}
231 	transmit(fd, value(EOFWRITE), NULL);
232 	if (!boolean(value(ECHOCHECK))) {
233 		struct sgttyb buf;
234 
235 		ioctl(FD, TIOCGETP, &buf);	/* this does a */
236 		ioctl(FD, TIOCSETP, &buf);	/*   wflushtty */
237 	}
238 }
239 
240 /*
241  * Bulk transfer routine to remote host --
242  *   used by sendfile() and cu_put()
243  */
244 transmit(fd, eofchars, command)
245 	FILE *fd;
246 	char *eofchars, *command;
247 {
248 	char *pc, lastc;
249 	int c, ccount, lcount;
250 	time_t start_t, stop_t;
251 	int (*f)();
252 
253 	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
254 	stop = 0;
255 	f = signal(SIGINT, stopsnd);
256 	ioctl(0, TIOCSETC, &defchars);
257 	read(repdes[0], (char *)&ccc, 1);
258 	if (command != NULL) {
259 		for (pc = command; *pc; pc++)
260 			send(*pc);
261 		if (boolean(value(ECHOCHECK)))
262 			read(FD, (char *)&c, 1);	/* trailing \n */
263 		else {
264 			struct sgttyb buf;
265 
266 			ioctl(FD, TIOCGETP, &buf);	/* this does a */
267 			ioctl(FD, TIOCSETP, &buf);	/*   wflushtty */
268 			sleep(5); /* wait for remote stty to take effect */
269 		}
270 	}
271 	lcount = 0;
272 	lastc = '\0';
273 	start_t = time(0);
274 	while (1) {
275 		ccount = 0;
276 		do {
277 			c = getc(fd);
278 			if (stop)
279 				goto out;
280 			if (c == EOF)
281 				goto out;
282 			if (c == 0177 && !boolean(value(RAWFTP)))
283 				continue;
284 			lastc = c;
285 			if (c < 040) {
286 				if (c == '\n') {
287 					if (!boolean(value(RAWFTP)))
288 						c = '\r';
289 				}
290 				else if (c == '\t') {
291 					if (!boolean(value(RAWFTP))) {
292 						if (boolean(value(TABEXPAND))) {
293 							send(' ');
294 							while ((++ccount % 8) != 0)
295 								send(' ');
296 							continue;
297 						}
298 					}
299 				} else
300 					if (!boolean(value(RAWFTP)))
301 						continue;
302 			}
303 			send(c);
304 		} while (c != '\r' && !boolean(value(RAWFTP)));
305 		if (boolean(value(VERBOSE)))
306 			printf("\r%d", ++lcount);
307 		if (boolean(value(ECHOCHECK))) {
308 			timedout = 0;
309 			alarm(value(ETIMEOUT));
310 			do {	/* wait for prompt */
311 				read(FD, (char *)&c, 1);
312 				if (timedout || stop) {
313 					if (timedout)
314 						printf("\r\ntimed out at eol\r\n");
315 					alarm(0);
316 					goto out;
317 				}
318 			} while ((c&0177) != character(value(PROMPT)));
319 			alarm(0);
320 		}
321 	}
322 out:
323 	if (lastc != '\n' && !boolean(value(RAWFTP)))
324 		send('\r');
325 	for (pc = eofchars; *pc; pc++)
326 		send(*pc);
327 	stop_t = time(0);
328 	fclose(fd);
329 	signal(SIGINT, f);
330 	if (boolean(value(VERBOSE)))
331 		if (boolean(value(RAWFTP)))
332 			prtime(" chars transferred in ", stop_t-start_t);
333 		else
334 			prtime(" lines transferred in ", stop_t-start_t);
335 	write(fildes[1], (char *)&ccc, 1);
336 	ioctl(0, TIOCSETC, &tchars);
337 }
338 
339 /*
340  * Cu-like put command
341  */
342 cu_put(cc)
343 	char cc;
344 {
345 	FILE *fd;
346 	char line[BUFSIZ];
347 	int argc;
348 	char *expand();
349 	char *copynamex;
350 
351 	if (prompt("[put] ", copyname))
352 		return;
353 	if ((argc = args(copyname, argv)) < 1 || argc > 2) {
354 		printf("usage: <put> from [to]\r\n");
355 		return;
356 	}
357 	if (argc == 1)
358 		argv[1] = argv[0];
359 	copynamex = expand(argv[0]);
360 	if ((fd = fopen(copynamex, "r")) == NULL) {
361 		printf("%s: cannot open\r\n", copynamex);
362 		return;
363 	}
364 	if (boolean(value(ECHOCHECK)))
365 		sprintf(line, "cat>%s\r", argv[1]);
366 	else
367 		sprintf(line, "stty -echo;cat>%s;stty echo\r", argv[1]);
368 	transmit(fd, "\04", line);
369 }
370 
371 /*
372  * FTP - send single character
373  *  wait for echo & handle timeout
374  */
375 send(c)
376 	char c;
377 {
378 	char cc;
379 	int retry = 0;
380 
381 	cc = c;
382 	pwrite(FD, &cc, 1);
383 #ifdef notdef
384 	if (number(value(CDELAY)) > 0 && c != '\r')
385 		nap(number(value(CDELAY)));
386 #endif
387 	if (!boolean(value(ECHOCHECK))) {
388 #ifdef notdef
389 		if (number(value(LDELAY)) > 0 && c == '\r')
390 			nap(number(value(LDELAY)));
391 #endif
392 		return;
393 	}
394 tryagain:
395 	timedout = 0;
396 	alarm(value(ETIMEOUT));
397 	read(FD, &cc, 1);
398 	alarm(0);
399 	if (timedout) {
400 		printf("\r\ntimeout error (%s)\r\n", ctrl(c));
401 		if (retry++ > 3)
402 			return;
403 		pwrite(FD, &null, 1); /* poke it */
404 		goto tryagain;
405 	}
406 }
407 
408 timeout()
409 {
410 	signal(SIGALRM, timeout);
411 	timedout = 1;
412 }
413 
414 #ifdef CONNECT
415 /*
416  * Fork a program with:
417  *  0 <-> local tty in
418  *  1 <-> local tty out
419  *  2 <-> local tty out
420  *  3 <-> remote tty in
421  *  4 <-> remote tty out
422  */
423 consh(c)
424 {
425 	char buf[256];
426 	int cpid, status, p;
427 	time_t start;
428 
429 	putchar(c);
430 	if (prompt("Local command? ", buf))
431 		return;
432 	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
433 	signal(SIGINT, SIG_IGN);
434 	signal(SIGQUIT, SIG_IGN);
435 	ioctl(0, TIOCSETC, &defchars);
436 	read(repdes[0], (char *)&ccc, 1);
437 	/*
438 	 * Set up file descriptors in the child and
439 	 *  let it go...
440 	 */
441 	if ((cpid = fork()) < 0)
442 		printf("can't fork!\r\n");
443 	else if (cpid) {
444 		start = time(0);
445 		while ((p = wait(&status)) > 0 && p != cpid)
446 			;
447 	} else {
448 		register int i;
449 
450 		dup2(FD, 3);
451 		dup2(3, 4);
452 		for (i = 5; i < 20; i++)
453 			close(i);
454 		signal(SIGINT, SIG_DFL);
455 		signal(SIGQUIT, SIG_DFL);
456 		execute(buf);
457 		printf("can't find `%s'\r\n", buf);
458 		exit(0);
459 	}
460 	if (boolean(value(VERBOSE)))
461 		prtime("away for ", time(0)-start);
462 	write(fildes[1], (char *)&ccc, 1);
463 	ioctl(0, TIOCSETC, &tchars);
464 	signal(SIGINT, SIG_DFL);
465 	signal(SIGQUIT, SIG_DFL);
466 }
467 #endif
468 
469 /*
470  * Escape to local shell
471  */
472 shell()
473 {
474 	int shpid, status;
475 	extern char **environ;
476 	char *cp;
477 
478 	printf("[sh]\r\n");
479 	signal(SIGINT, SIG_IGN);
480 	signal(SIGQUIT, SIG_IGN);
481 	unraw();
482 	if (shpid = fork()) {
483 		while (shpid != wait(&status));
484 		raw();
485 		printf("\r\n!\r\n");
486 		signal(SIGINT, SIG_DFL);
487 		signal(SIGQUIT, SIG_DFL);
488 		return;
489 	} else {
490 		signal(SIGQUIT, SIG_DFL);
491 		signal(SIGINT, SIG_DFL);
492 		if ((cp = rindex(value(SHELL), '/')) == NULL)
493 			cp = value(SHELL);
494 		else
495 			cp++;
496 		execl(value(SHELL), cp, 0);
497 		printf("\r\ncan't execl!\r\n");
498 		exit(1);
499 	}
500 }
501 
502 /*
503  * TIPIN portion of scripting
504  *   initiate the conversation with TIPOUT
505  */
506 setscript()
507 {
508 	char c;
509 	/*
510 	 * enable TIPOUT side for dialogue
511 	 */
512 	kill(pid, SIGEMT);
513 	if (boolean(value(SCRIPT)))
514 		write(fildes[1], value(RECORD), size(value(RECORD)));
515 	write(fildes[1], "\n", 1);
516 	/*
517 	 * wait for TIPOUT to finish
518 	 */
519 	read(repdes[0], &c, 1);
520 	if (c == 'n')
521 		printf("can't create %s\r\n", value(RECORD));
522 }
523 
524 /*
525  * Change current working directory of
526  *   local portion of tip
527  */
528 chdirectory()
529 {
530 	char dirname[80];
531 	register char *cp = dirname;
532 
533 	if (prompt("[cd] ", dirname)) {
534 		if (stoprompt)
535 			return;
536 		cp = value(HOME);
537 	}
538 	if (chdir(cp) < 0)
539 		printf("%s: bad directory\r\n", cp);
540 	printf("!\r\n");
541 }
542 
543 abort(msg)
544 	char *msg;
545 {
546 
547 	kill(pid, SIGTERM);
548 	disconnect(msg);
549 	if (msg != NOSTR)
550 		printf("\r\n%s", msg);
551 	printf("\r\n[EOT]\r\n");
552 	delock(uucplock);
553 	unraw();
554 	exit(0);
555 }
556 
557 finish()
558 {
559 	char *dismsg;
560 
561 	if ((dismsg = value(DISCONNECT)) != NOSTR) {
562 		write(FD, dismsg, strlen(dismsg));
563 		sleep(5);
564 	}
565 	abort(NOSTR);
566 }
567 
568 intcopy()
569 {
570 
571 	raw();
572 	quit = 1;
573 	longjmp(intbuf, 1);
574 }
575 
576 execute(s)
577 	char *s;
578 {
579 	register char *cp;
580 
581 	if ((cp = rindex(value(SHELL), '/')) == NULL)
582 		cp = value(SHELL);
583 	else
584 		cp++;
585 	execl(value(SHELL), cp, "-c", s, 0);
586 }
587 
588 args(buf, a)
589 	char *buf, *a[];
590 {
591 	register char *p = buf, *start;
592 	register char **parg = a;
593 	register int n = 0;
594 
595 	do {
596 		while (*p && (*p == ' ' || *p == '\t'))
597 			p++;
598 		start = p;
599 		if (*p)
600 			*parg = p;
601 		while (*p && (*p != ' ' && *p != '\t'))
602 			p++;
603 		if (p != start)
604 			parg++, n++;
605 		if (*p)
606 			*p++ = '\0';
607 	} while (*p);
608 
609 	return(n);
610 }
611 
612 prtime(s, a)
613 	char *s;
614 	time_t a;
615 {
616 	register i;
617 	int nums[3];
618 
619 	for (i = 0; i < 3; i++) {
620 		nums[i] = (int)(a % quant[i]);
621 		a /= quant[i];
622 	}
623 	printf("%s", s);
624 	while (--i >= 0)
625 		if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
626 			printf("%d %s%c ", nums[i], sep[i],
627 				nums[i] == 1 ? '\0' : 's');
628 	printf("\r\n!\r\n");
629 }
630 
631 variable()
632 {
633 	char	buf[256];
634 
635 	if (prompt("[set] ", buf))
636 		return;
637 	vlex(buf);
638 	if (vtable[BEAUTIFY].v_access&CHANGED) {
639 		vtable[BEAUTIFY].v_access &= ~CHANGED;
640 		kill(pid, SIGSYS);
641 	}
642 	if (vtable[SCRIPT].v_access&CHANGED) {
643 		vtable[SCRIPT].v_access &= ~CHANGED;
644 		setscript();
645 		/*
646 		 * So that "set record=blah script" doesn't
647 		 *  cause two transactions to occur.
648 		 */
649 		if (vtable[RECORD].v_access&CHANGED)
650 			vtable[RECORD].v_access &= ~CHANGED;
651 	}
652 	if (vtable[RECORD].v_access&CHANGED) {
653 		vtable[RECORD].v_access &= ~CHANGED;
654 		if (boolean(value(SCRIPT)))
655 			setscript();
656 	}
657 	if (vtable[TAND].v_access&CHANGED) {
658 		vtable[TAND].v_access &= ~CHANGED;
659 		if (boolean(value(TAND)))
660 			tandem("on");
661 		else
662 			tandem("off");
663 	}
664  	if (vtable[LECHO].v_access&CHANGED) {
665  		vtable[LECHO].v_access &= ~CHANGED;
666  		HD = boolean(value(LECHO));
667  	}
668 	if (vtable[PARITY].v_access&CHANGED) {
669 		vtable[PARITY].v_access &= ~CHANGED;
670 		setparity();
671 	}
672 }
673 
674 /*
675  * Turn tandem mode on or off for remote tty.
676  */
677 tandem(option)
678 	char *option;
679 {
680 	struct sgttyb rmtty;
681 
682 	ioctl(FD, TIOCGETP, &rmtty);
683 	if (strcmp(option,"on") == 0) {
684 		rmtty.sg_flags |= TANDEM;
685 		arg.sg_flags |= TANDEM;
686 	} else {
687 		rmtty.sg_flags &= ~TANDEM;
688 		arg.sg_flags &= ~TANDEM;
689 	}
690 	ioctl(FD, TIOCSETP, &rmtty);
691 	ioctl(0,  TIOCSETP, &arg);
692 }
693 
694 /*
695  * Send a break.
696  */
697 genbrk()
698 {
699 
700 	ioctl(FD, TIOCSBRK, NULL);
701 	sleep(1);
702 	ioctl(FD, TIOCCBRK, NULL);
703 }
704 
705 /*
706  * Suspend tip
707  */
708 suspend()
709 {
710 
711 	unraw();
712 	kill(0, SIGTSTP);
713 	raw();
714 }
715 
716 /*
717  *	expand a file name if it includes shell meta characters
718  */
719 
720 char *
721 expand(name)
722 	char name[];
723 {
724 	static char xname[BUFSIZ];
725 	char cmdbuf[BUFSIZ];
726 	register int pid, l, rc;
727 	register char *cp, *Shell;
728 	int s, pivec[2], (*sigint)();
729 
730 	if (!anyof(name, "~{[*?$`'\"\\"))
731 		return(name);
732 	/* sigint = signal(SIGINT, SIG_IGN); */
733 	if (pipe(pivec) < 0) {
734 		perror("pipe");
735 		/* signal(SIGINT, sigint) */
736 		return(name);
737 	}
738 	sprintf(cmdbuf, "echo %s", name);
739 	if ((pid = vfork()) == 0) {
740 		Shell = value(SHELL);
741 		if (Shell == NOSTR)
742 			Shell = "/bin/sh";
743 		close(pivec[0]);
744 		close(1);
745 		dup(pivec[1]);
746 		close(pivec[1]);
747 		close(2);
748 		execl(Shell, Shell, "-c", cmdbuf, 0);
749 		_exit(1);
750 	}
751 	if (pid == -1) {
752 		perror("fork");
753 		close(pivec[0]);
754 		close(pivec[1]);
755 		return(NOSTR);
756 	}
757 	close(pivec[1]);
758 	l = read(pivec[0], xname, BUFSIZ);
759 	close(pivec[0]);
760 	while (wait(&s) != pid);
761 		;
762 	s &= 0377;
763 	if (s != 0 && s != SIGPIPE) {
764 		fprintf(stderr, "\"Echo\" failed\n");
765 		return(NOSTR);
766 	}
767 	if (l < 0) {
768 		perror("read");
769 		return(NOSTR);
770 	}
771 	if (l == 0) {
772 		fprintf(stderr, "\"%s\": No match\n", name);
773 		return(NOSTR);
774 	}
775 	if (l == BUFSIZ) {
776 		fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
777 		return(NOSTR);
778 	}
779 	xname[l] = 0;
780 	for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
781 		;
782 	*++cp = '\0';
783 	return(xname);
784 }
785 
786 /*
787  * Are any of the characters in the two strings the same?
788  */
789 
790 anyof(s1, s2)
791 	register char *s1, *s2;
792 {
793 	register int c;
794 
795 	while (c = *s1++)
796 		if (any(c, s2))
797 			return(1);
798 	return(0);
799 }
800