1 /* cmds.c 4.10 82/09/02 */ 2 #include "tip.h" 3 /* 4 * tip 5 * 6 * miscellaneous commands 7 */ 8 9 int quant[] = { 60, 60, 24 }; 10 11 char null = '\0'; 12 char *sep[] = { "second", "minute", "hour" }; 13 static char *argv[10]; /* argument vector for take and put */ 14 15 int timeout(); /* timeout function called on alarm */ 16 int stopsnd(); /* SIGINT handler during file transfers */ 17 int intprompt(); /* used in handling SIG_INT during prompt */ 18 int intcopy(); /* interrupt routine for file transfers */ 19 20 /* 21 * FTP - remote ==> local 22 * get a file from the remote host 23 */ 24 getfl(c) 25 char c; 26 { 27 char buf[256]; 28 29 putchar(c); 30 /* 31 * get the UNIX receiving file's name 32 */ 33 if (prompt("Local file name? ", copyname)) 34 return; 35 if ((sfd = creat(copyname, 0666)) < 0) { 36 printf("\r\n%s: cannot creat\r\n", copyname); 37 return; 38 } 39 40 /* 41 * collect parameters 42 */ 43 if (prompt("List command for remote system? ", buf)) { 44 unlink(copyname); 45 return; 46 } 47 transfer(buf, sfd, value(EOFREAD)); 48 } 49 50 /* 51 * Cu-like take command 52 */ 53 cu_take(cc) 54 char cc; 55 { 56 int fd, argc; 57 char line[BUFSIZ]; 58 59 if (prompt("[take] ", copyname)) 60 return; 61 if ((argc = args(copyname, argv)) < 1 || argc > 2) { 62 printf("usage: <take> from [to]\r\n"); 63 return; 64 } 65 if (argc == 1) 66 argv[1] = argv[0]; 67 if ((fd = creat(argv[1], 0666)) < 0) { 68 printf("\r\n%s: cannot create\r\n", argv[1]); 69 return; 70 } 71 sprintf(line, "cat '%s';echo \01", argv[0]); 72 transfer(line, fd, "\01"); 73 } 74 75 /* 76 * Bulk transfer routine -- 77 * used by getfl(), cu_take(), and pipefile() 78 */ 79 transfer(buf, fd, eofchars) 80 char *buf, *eofchars; 81 { 82 register int ct; 83 char c, buffer[BUFSIZ]; 84 register char *p = buffer; 85 register int cnt, eof; 86 time_t start; 87 88 write(FD, buf, size(buf)); 89 quit = 0; 90 signal(SIGINT, intcopy); 91 kill(pid, SIGIOT); 92 read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */ 93 94 /* 95 * finish command 96 */ 97 write(FD, "\r", 1); 98 do 99 read(FD, &c, 1); 100 while ((c&0177) != '\n'); 101 ioctl(0, TIOCSETC, &defchars); 102 103 start = time(0); 104 for (ct = 0; !quit;) { 105 eof = read(FD, &c, 1) <= 0; 106 c &= 0177; 107 if (quit) 108 continue; 109 if (eof || any(c, eofchars)) 110 break; 111 if (c == 0) 112 continue; /* ignore nulls */ 113 if (c == '\r') 114 continue; 115 *p++ = c; 116 117 if (c == '\n' && boolean(value(VERBOSE))) 118 printf("\r%d", ++ct); 119 if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) { 120 if (write(fd, buffer, cnt) != cnt) { 121 printf("\r\nwrite error\r\n"); 122 quit = 1; 123 } 124 p = buffer; 125 } 126 } 127 if (cnt = (p-buffer)) 128 if (write(fd, buffer, cnt) != cnt) 129 printf("\r\nwrite error\r\n"); 130 131 if (boolean(value(VERBOSE))) 132 prtime(" lines transferred in ", time(0)-start); 133 ioctl(0, TIOCSETC, &tchars); 134 write(fildes[1], (char *)&ccc, 1); 135 signal(SIGINT, SIG_DFL); 136 close(fd); 137 } 138 139 /* 140 * FTP - remote ==> local process 141 * send remote input to local process via pipe 142 */ 143 pipefile() 144 { 145 int cpid, pdes[2]; 146 char buf[256]; 147 int status, p; 148 extern int errno; 149 150 if (prompt("Local command? ", buf)) 151 return; 152 153 if (pipe(pdes)) { 154 printf("can't establish pipe\r\n"); 155 return; 156 } 157 158 if ((cpid = fork()) < 0) { 159 printf("can't fork!\r\n"); 160 return; 161 } else if (cpid) { 162 if (prompt("List command for remote system? ", buf)) { 163 close(pdes[0]), close(pdes[1]); 164 kill (cpid, SIGKILL); 165 } else { 166 close(pdes[0]); 167 signal(SIGPIPE, intcopy); 168 transfer(buf, pdes[1], value(EOFREAD)); 169 signal(SIGPIPE, SIG_DFL); 170 while ((p = wait(&status)) > 0 && p != cpid) 171 ; 172 } 173 } else { 174 register int f; 175 176 dup2(pdes[0], 0); 177 close(pdes[0]); 178 for (f = 3; f < 20; f++) 179 close(f); 180 execute(buf); 181 printf("can't execl!\r\n"); 182 exit(0); 183 } 184 } 185 186 /* 187 * Interrupt service routine for FTP 188 */ 189 stopsnd() 190 { 191 stop = 1; 192 signal(SIGINT, SIG_IGN); 193 } 194 195 /* 196 * FTP - local ==> remote 197 * send local file to remote host 198 * terminate transmission with pseudo EOF sequence 199 */ 200 sendfile(cc) 201 char cc; 202 { 203 FILE *fd; 204 205 putchar(cc); 206 /* 207 * get file name 208 */ 209 if (prompt("Local file name? ", fname)) 210 return; 211 212 /* 213 * look up file 214 */ 215 if ((fd = fopen(fname, "r")) == NULL) { 216 printf("%s: cannot open\r\n", fname); 217 return; 218 } 219 transmit(fd, value(EOFWRITE), NULL); 220 if (!boolean(value(ECHOCHECK))) { 221 struct sgttyb buf; 222 223 ioctl(FD, TIOCGETP, &buf); /* this does a */ 224 ioctl(FD, TIOCSETP, &buf); /* wflushtty */ 225 } 226 } 227 228 /* 229 * Bulk transfer routine to remote host -- 230 * used by sendfile() and cu_put() 231 */ 232 transmit(fd, eofchars, command) 233 FILE *fd; 234 char *eofchars, *command; 235 { 236 char *pc, lastc, rc; 237 int c, ccount, lcount; 238 time_t start_t, stop_t; 239 240 kill(pid, SIGIOT); /* put TIPOUT into a wait state */ 241 signal(SIGINT, stopsnd); 242 stop = 0; 243 ioctl(0, TIOCSETC, &defchars); 244 read(repdes[0], (char *)&ccc, 1); 245 if (command != NULL) { 246 for (pc = command; *pc; pc++) 247 send(*pc); 248 if (boolean(value(ECHOCHECK))) 249 read(FD, (char *)&c, 1); /* trailing \n */ 250 else { 251 struct sgttyb buf; 252 253 ioctl(FD, TIOCGETP, &buf); /* this does a */ 254 ioctl(FD, TIOCSETP, &buf); /* wflushtty */ 255 sleep(5); /* wait for remote stty to take effect */ 256 } 257 } 258 lcount = 0; 259 lastc = '\0'; 260 start_t = time(0); 261 while (1) { 262 ccount = 0; 263 do { 264 c = getc(fd); 265 if (stop) 266 goto out; 267 if (c == EOF) 268 goto out; 269 if (c == 0177) 270 continue; 271 lastc = c; 272 if (c < 040) { 273 if (c == '\n') 274 c = '\r'; 275 else if (c == '\t') { 276 if (boolean(value(TABEXPAND))) { 277 send(' '); 278 while ((++ccount % 8) != 0) 279 send(' '); 280 continue; 281 } 282 } else if (!any(c, value(EXCEPTIONS))) 283 continue; 284 } 285 send(c); 286 } while (c != '\r'); 287 if (boolean(value(VERBOSE))) 288 printf("\r%d", ++lcount); 289 if (boolean(value(ECHOCHECK))) { 290 alarm(10); 291 timedout = 0; 292 do { /* wait for prompt */ 293 read(FD, (char *)&rc, 1); 294 if (timedout || stop) { 295 if (timedout) 296 printf("\r\ntimed out at eol\r\n"); 297 alarm(0); 298 goto out; 299 } 300 } while ((rc&0177) != character(value(PROMPT))); 301 alarm(0); 302 } 303 } 304 out: 305 if (lastc != '\n') 306 send('\r'); 307 for (pc = eofchars; *pc; pc++) 308 send(*pc); 309 stop_t = time(0); 310 fclose(fd); 311 signal(SIGINT, SIG_DFL); 312 if (boolean(value(VERBOSE))) 313 prtime(" lines transferred in ", stop_t-start_t); 314 write(fildes[1], (char *)&ccc, 1); 315 ioctl(0, TIOCSETC, &tchars); 316 } 317 318 /* 319 * Cu-like put command 320 */ 321 cu_put(cc) 322 char cc; 323 { 324 FILE *fd; 325 char line[BUFSIZ]; 326 int argc; 327 328 if (prompt("[put] ", copyname)) 329 return; 330 if ((argc = args(copyname, argv)) < 1 || argc > 2) { 331 printf("usage: <put> from [to]\r\n"); 332 return; 333 } 334 if (argc == 1) 335 argv[1] = argv[0]; 336 if ((fd = fopen(argv[0], "r")) == NULL) { 337 printf("%s: cannot open\r\n", argv[0]); 338 return; 339 } 340 if (boolean(value(ECHOCHECK))) 341 sprintf(line, "cat>'%s'\r", argv[1]); 342 else 343 sprintf(line, "stty -echo;cat>'%s';stty echo\r", argv[1]); 344 transmit(fd, "\04", line); 345 } 346 347 /* 348 * FTP - send single character 349 * wait for echo & handle timeout 350 */ 351 send(c) 352 char c; 353 { 354 char cc; 355 int retry = 0; 356 357 cc = c; 358 write(FD, (char *)&cc, 1); 359 if (!boolean(value(ECHOCHECK))) 360 return; 361 tryagain: 362 timedout = 0; 363 alarm(10); 364 read(FD, (char *)&cc, 1); 365 alarm(0); 366 if (timedout) { 367 printf("\r\ntimeout error (%s)\r\n", ctrl(c)); 368 if (retry++ > 3) 369 return; 370 write(FD, &null, 1); /* poke it */ 371 goto tryagain; 372 } 373 } 374 375 timeout() 376 { 377 signal(SIGALRM, timeout); 378 timedout = 1; 379 } 380 381 #ifdef CONNECT 382 /* 383 * Fork a program with: 384 * 0 <-> local tty in 385 * 1 <-> local tty out 386 * 2 <-> local tty out 387 * 3 <-> remote tty in 388 * 4 <-> remote tty out 389 */ 390 consh(c) 391 { 392 char buf[256]; 393 int cpid, status, p; 394 time_t start; 395 396 putchar(c); 397 if (prompt("Local command? ", buf)) 398 return; 399 kill(pid, SIGIOT); /* put TIPOUT into a wait state */ 400 signal(SIGINT, SIG_IGN); 401 signal(SIGQUIT, SIG_IGN); 402 ioctl(0, TIOCSETC, &defchars); 403 read(repdes[0], (char *)&ccc, 1); 404 /* 405 * Set up file descriptors in the child and 406 * let it go... 407 */ 408 if ((cpid = fork()) < 0) 409 printf("can't fork!\r\n"); 410 else if (cpid) { 411 start = time(0); 412 while ((p = wait(&status)) > 0 && p != cpid) 413 ; 414 } else { 415 register int i; 416 417 dup2(FD, 3); 418 dup2(3, 4); 419 for (i = 5; i < 20; i++) 420 close(i); 421 signal(SIGINT, SIG_DFL); 422 signal(SIGQUIT, SIG_DFL); 423 execute(buf); 424 printf("can't find `%s'\r\n", buf); 425 exit(0); 426 } 427 if (boolean(value(VERBOSE))) 428 prtime("away for ", time(0)-start); 429 write(fildes[1], (char *)&ccc, 1); 430 ioctl(0, TIOCSETC, &tchars); 431 signal(SIGINT, SIG_DFL); 432 signal(SIGQUIT, SIG_DFL); 433 } 434 #endif 435 436 /* 437 * Escape to local shell 438 */ 439 shell() 440 { 441 int shpid, status; 442 extern char **environ; 443 char *cp; 444 445 printf("[sh]\r\n"); 446 signal(SIGINT, SIG_IGN); 447 signal(SIGQUIT, SIG_IGN); 448 unraw(); 449 if (shpid = fork()) { 450 while (shpid != wait(&status)); 451 raw(); 452 printf("\r\n!\r\n"); 453 signal(SIGINT, SIG_DFL); 454 signal(SIGQUIT, SIG_DFL); 455 return; 456 } else { 457 signal(SIGQUIT, SIG_DFL); 458 signal(SIGINT, SIG_DFL); 459 if ((cp = rindex(value(SHELL), '/')) == NULL) 460 cp = value(SHELL); 461 else 462 cp++; 463 execl(value(SHELL), cp, 0); 464 printf("\r\ncan't execl!\r\n"); 465 exit(1); 466 } 467 } 468 469 /* 470 * TIPIN portion of scripting 471 * initiate the conversation with TIPOUT 472 */ 473 setscript() 474 { 475 char c; 476 /* 477 * enable TIPOUT side for dialogue 478 */ 479 kill(pid, SIGEMT); 480 if (boolean(value(SCRIPT))) 481 write(fildes[1], value(RECORD), size(value(RECORD))); 482 write(fildes[1], "\n", 1); 483 /* 484 * wait for TIPOUT to finish 485 */ 486 read(repdes[0], &c, 1); 487 if (c == 'n') 488 printf("can't create %s\r\n", value(RECORD)); 489 } 490 491 /* 492 * Change current working directory of 493 * local portion of tip 494 */ 495 chdirectory() 496 { 497 char dirname[80]; 498 register char *cp = dirname; 499 500 if (prompt("[cd] ", dirname)) 501 if (stoprompt) 502 return; 503 else 504 cp = value(HOME); 505 if (chdir(cp) < 0) 506 printf("%s: bad directory\r\n", cp); 507 printf("!\r\n"); 508 } 509 510 finish() 511 { 512 kill(pid, SIGTERM); 513 disconnect(); 514 printf("\r\n[EOT]\r\n"); 515 delock(uucplock); 516 unraw(); 517 exit(0); 518 } 519 520 intcopy() 521 { 522 raw(); 523 quit = 1; 524 } 525 526 execute(s) 527 char *s; 528 { 529 register char *cp; 530 531 if ((cp = rindex(value(SHELL), '/')) == NULL) 532 cp = value(SHELL); 533 else 534 cp++; 535 execl(value(SHELL), cp, "-c", s, 0); 536 } 537 538 args(buf, a) 539 char *buf, *a[]; 540 { 541 register char *p = buf, *start; 542 register char **parg = a; 543 register int n = 0; 544 545 do { 546 while (*p && (*p == ' ' || *p == '\t')) 547 p++; 548 start = p; 549 if (*p) 550 *parg = p; 551 while (*p && (*p != ' ' && *p != '\t')) 552 p++; 553 if (p != start) 554 parg++, n++; 555 if (*p) 556 *p++ = '\0'; 557 } while (*p); 558 559 return(n); 560 } 561 562 prtime(s, a) 563 char *s; 564 time_t a; 565 { 566 register i; 567 int nums[3]; 568 569 for (i = 0; i < 3; i++) { 570 nums[i] = (int)(a % quant[i]); 571 a /= quant[i]; 572 } 573 printf("%s", s); 574 while (--i >= 0) 575 if (nums[i]) 576 printf("%d %s%c ", nums[i], sep[i], 577 nums[i] == 1 ? '\0' : 's'); 578 printf("\r\n!\r\n"); 579 } 580 581 variable() 582 { 583 char buf[256]; 584 585 if (prompt("[set] ", buf)) 586 return; 587 vlex(buf); 588 if (vtable[BEAUTIFY].v_access&CHANGED) { 589 vtable[BEAUTIFY].v_access &= ~CHANGED; 590 kill(pid, SIGSYS); 591 } 592 if (vtable[SCRIPT].v_access&CHANGED) { 593 vtable[SCRIPT].v_access &= ~CHANGED; 594 setscript(); 595 /* 596 * So that "set record=blah script" doesn't 597 * cause two transactions to occur. 598 */ 599 if (vtable[RECORD].v_access&CHANGED) 600 vtable[RECORD].v_access &= ~CHANGED; 601 } 602 if (vtable[RECORD].v_access&CHANGED) { 603 vtable[RECORD].v_access &= ~CHANGED; 604 if (boolean(value(SCRIPT))) 605 setscript(); 606 } 607 } 608 609 /* 610 * Send a break. 611 * If we can't do it directly (as on VMUNIX), then simulate it. 612 */ 613 genbrk() 614 { 615 #ifdef TIOCSBRK 616 ioctl(FD, TIOCSBRK, NULL); 617 sleep(1); 618 ioctl(FD, TIOCCBRK, NULL); 619 #else 620 struct sgttyb ttbuf; 621 int sospeed; 622 623 ioctl(FD, TIOCGETP, &ttbuf); 624 sospeed = ttbuf.sg_ospeed; 625 ttbuf.sg_ospeed = B150; 626 ioctl(FD, TIOCSETP, &ttbuf); 627 write(FD, "\0\0\0\0\0\0\0\0\0\0", 10); 628 ttbuf.sg_ospeed = sospeed; 629 ioctl(FD, TIOCSETP, &ttbuf); 630 write(FD, "@", 1); 631 #endif 632 } 633 634 #ifdef SIGTSTP 635 /* 636 * Suspend tip 637 */ 638 suspend() 639 { 640 unraw(); 641 kill(0, SIGTSTP); 642 raw(); 643 } 644 #endif 645