recognize and handle carrier loss
[unix-history] / usr / src / usr.bin / tip / cmds.c
CommitLineData
05862919 1#ifndef lint
e2326c44 2static char sccsid[] = "@(#)cmds.c 4.13 (Berkeley) %G%";
05862919
SL
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
e2326c44
SL
542abort(msg)
543 char *msg;
22daf918 544{
6b46907f 545
22daf918 546 kill(pid, SIGTERM);
e2326c44
SL
547 disconnect(msg);
548 if (msg != NOSTR)
549 printf("\r\n%s", msg);
22daf918
BJ
550 printf("\r\n[EOT]\r\n");
551 delock(uucplock);
22daf918
BJ
552 unraw();
553 exit(0);
554}
555
e2326c44
SL
556finish()
557{
558 char *dismsg;
559
560 if ((dismsg = value(DISCONNECT)) != NOSTR) {
561 write(FD, dismsg, strlen(dismsg));
562 sleep(5);
563 }
564 abort(NOSTR);
565}
566
22daf918
BJ
567intcopy()
568{
05862919 569
22daf918
BJ
570 raw();
571 quit = 1;
05862919 572 longjmp(intbuf, 1);
22daf918
BJ
573}
574
575execute(s)
576 char *s;
577{
578 register char *cp;
579
580 if ((cp = rindex(value(SHELL), '/')) == NULL)
581 cp = value(SHELL);
582 else
583 cp++;
584 execl(value(SHELL), cp, "-c", s, 0);
585}
586
587args(buf, a)
588 char *buf, *a[];
589{
590 register char *p = buf, *start;
591 register char **parg = a;
592 register int n = 0;
593
594 do {
595 while (*p && (*p == ' ' || *p == '\t'))
596 p++;
597 start = p;
598 if (*p)
599 *parg = p;
600 while (*p && (*p != ' ' && *p != '\t'))
601 p++;
602 if (p != start)
603 parg++, n++;
604 if (*p)
605 *p++ = '\0';
606 } while (*p);
607
608 return(n);
609}
610
611prtime(s, a)
612 char *s;
613 time_t a;
614{
615 register i;
616 int nums[3];
617
618 for (i = 0; i < 3; i++) {
619 nums[i] = (int)(a % quant[i]);
620 a /= quant[i];
621 }
622 printf("%s", s);
623 while (--i >= 0)
624 if (nums[i])
625 printf("%d %s%c ", nums[i], sep[i],
626 nums[i] == 1 ? '\0' : 's');
627 printf("\r\n!\r\n");
628}
629
630variable()
631{
632 char buf[256];
633
634 if (prompt("[set] ", buf))
635 return;
636 vlex(buf);
637 if (vtable[BEAUTIFY].v_access&CHANGED) {
638 vtable[BEAUTIFY].v_access &= ~CHANGED;
3463e9c6 639 kill(pid, SIGSYS);
22daf918
BJ
640 }
641 if (vtable[SCRIPT].v_access&CHANGED) {
642 vtable[SCRIPT].v_access &= ~CHANGED;
643 setscript();
7367df0e
SL
644 /*
645 * So that "set record=blah script" doesn't
646 * cause two transactions to occur.
647 */
648 if (vtable[RECORD].v_access&CHANGED)
649 vtable[RECORD].v_access &= ~CHANGED;
22daf918
BJ
650 }
651 if (vtable[RECORD].v_access&CHANGED) {
652 vtable[RECORD].v_access &= ~CHANGED;
653 if (boolean(value(SCRIPT)))
654 setscript();
655 }
6b46907f
RC
656 if (vtable[TAND].v_access&CHANGED) {
657 vtable[TAND].v_access &= ~CHANGED;
658 if (boolean(value(TAND)))
659 tandem("on");
660 else
661 tandem("off");
662 }
663 if (vtable[LECHO].v_access&CHANGED) {
664 vtable[LECHO].v_access &= ~CHANGED;
665 HD = boolean(value(LECHO));
666 }
667 if (vtable[PARITY].v_access&CHANGED) {
668 vtable[PARITY].v_access &= ~CHANGED;
669 setparity();
670 }
671}
672
673/*
05862919 674 * Turn tandem mode on or off for remote tty.
6b46907f 675 */
6b46907f 676tandem(option)
05862919 677 char *option;
6b46907f
RC
678{
679 struct sgttyb rmtty;
680
681 ioctl(FD, TIOCGETP, &rmtty);
682 if (strcmp(option,"on") == 0) {
683 rmtty.sg_flags |= TANDEM;
684 arg.sg_flags |= TANDEM;
05862919 685 } else {
6b46907f
RC
686 rmtty.sg_flags &= ~TANDEM;
687 arg.sg_flags &= ~TANDEM;
688 }
689 ioctl(FD, TIOCSETP, &rmtty);
690 ioctl(0, TIOCSETP, &arg);
22daf918 691}
061754f3
SL
692
693/*
694 * Send a break.
061754f3
SL
695 */
696genbrk()
697{
05862919 698
061754f3
SL
699 ioctl(FD, TIOCSBRK, NULL);
700 sleep(1);
701 ioctl(FD, TIOCCBRK, NULL);
061754f3 702}
3f48242d 703
3f48242d
SL
704/*
705 * Suspend tip
706 */
707suspend()
708{
05862919 709
3f48242d
SL
710 unraw();
711 kill(0, SIGTSTP);
712 raw();
713}
6b46907f
RC
714
715/*
716 * expand a file name if it includes shell meta characters
717 */
718
719char *
720expand(name)
721 char name[];
722{
723 static char xname[BUFSIZ];
724 char cmdbuf[BUFSIZ];
725 register int pid, l, rc;
726 register char *cp, *Shell;
727 int s, pivec[2], (*sigint)();
728
729 if (!anyof(name, "~{[*?$`'\"\\"))
730 return(name);
731 /* sigint = signal(SIGINT, SIG_IGN); */
732 if (pipe(pivec) < 0) {
733 perror("pipe");
734 /* signal(SIGINT, sigint) */
735 return(name);
736 }
737 sprintf(cmdbuf, "echo %s", name);
738 if ((pid = vfork()) == 0) {
739 Shell = value(SHELL);
740 if (Shell == NOSTR)
741 Shell = "/bin/sh";
742 close(pivec[0]);
743 close(1);
744 dup(pivec[1]);
745 close(pivec[1]);
746 close(2);
747 execl(Shell, Shell, "-c", cmdbuf, 0);
748 _exit(1);
749 }
750 if (pid == -1) {
751 perror("fork");
752 close(pivec[0]);
753 close(pivec[1]);
754 return(NOSTR);
755 }
756 close(pivec[1]);
757 l = read(pivec[0], xname, BUFSIZ);
758 close(pivec[0]);
759 while (wait(&s) != pid);
760 ;
761 s &= 0377;
762 if (s != 0 && s != SIGPIPE) {
763 fprintf(stderr, "\"Echo\" failed\n");
764 return(NOSTR);
765 }
766 if (l < 0) {
767 perror("read");
768 return(NOSTR);
769 }
770 if (l == 0) {
771 fprintf(stderr, "\"%s\": No match\n", name);
772 return(NOSTR);
773 }
774 if (l == BUFSIZ) {
775 fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
776 return(NOSTR);
777 }
778 xname[l] = 0;
779 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
780 ;
781 *++cp = '\0';
782 return(xname);
783}
784
785/*
786 * Are any of the characters in the two strings the same?
787 */
788
789anyof(s1, s2)
790 register char *s1, *s2;
791{
792 register int c;
793
794 while (c = *s1++)
795 if (any(c, s2))
796 return(1);
797 return(0);
798}