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