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