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