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