1 /* tip.c 4.9 81/11/20 */ 2 /* 3 * tip - Unix link to other systems 4 * tip [-v] [-speed] system-name 5 * 6 * Uses remote file for system descriptions. 7 * Current commands (escapes): 8 * 9 * ~! fork a shell on the local machine 10 * ~c change working directory on local machine 11 * ~^D exit tip 12 * ~< fetch file from remote system 13 * ~> send file to remote system 14 * ~t take a file from a remote UNIX (uses cat & echo) 15 * ~p send a file to a remote UNIX (uses cat) 16 * ~| fetch file from remote system and pipe it to 17 * a local process 18 * ~% fork and wait for a program which inherits file 19 * descriptors 3 & 4 attached to the remote machine 20 * (optional by CONNECT define) 21 * ~s set or show variable 22 * ~? give a help summary 23 * 24 * Samuel J. Leffler 1-18-81 25 * 26 * sjl 2-11-81 27 * add auto-dial stuff for the BIZCOMP 28 * 29 * sjl 2-14-81 30 * cleaned up auto-dialer stuff and added variables 31 * 32 * sjl 2-19-81 33 * handle quit and interrupt during calls 34 * 35 * sjl 3-8-81 36 * made to pass lint 37 * 38 * sjl 4-11-81 39 * mods to handle both FIOCAPACITY and FIONREAD in biz.c 40 * 41 * sjl 4-17-81 42 * added take and put, made piping stuff work 43 * honor uucp locks 44 * rewrite remote file stuff for DN-11 like acu's and just to clean 45 * it up 46 * 47 * sjl 6-16-81 48 * real working setup for DN-11's 49 */ 50 51 #include "tip.h" 52 53 /* 54 * Baud rate mapping table 55 */ 56 int bauds[] = { 57 0, 50, 75, 110, 134, 150, 200, 300, 600, 58 1200, 1800, 2400, 4800, 9600, 19200, -1 59 }; 60 61 #ifdef VMUNIX 62 int disc = OTTYDISC; /* tip normally runs this way */ 63 #endif 64 65 int intprompt(); 66 int timeout(); 67 static int cleanup(); 68 69 main(argc, argv) 70 char *argv[]; 71 { 72 char *system = NOSTR; 73 register int i; 74 char *p; 75 76 if (argc > 4) { 77 fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n"); 78 exit(1); 79 } 80 if (!isatty(0)) { 81 fprintf(stderr, "tip: must be interactive\n"); 82 exit(1); 83 } 84 if (argc > 1 && argv[argc-1][0] != '-') 85 system = argv[argc-1]; /* always last item */ 86 signal(SIGINT, cleanup); 87 signal(SIGQUIT, cleanup); 88 signal(SIGHUP, cleanup); 89 signal(SIGTERM, cleanup); 90 91 if ((i = hunt(system)) == 0) { 92 printf("all ports busy\n"); 93 exit(3); 94 } 95 if (i == -1) { 96 printf("link down\n"); 97 delock(uucplock); 98 exit(3); 99 } 100 setbuf(stdout, NULL); 101 loginit(); 102 /* 103 * Now that we have the logfile and the ACU open 104 * return to the real uid and gid. These things will 105 * be closed on exit. Note that we can't run as root, 106 * because locking mechanism on the tty and the accounting 107 * will be bypassed. 108 */ 109 setuid(getuid()); 110 setgid(getgid()); 111 for (i = 1; i < argc-1; i++) 112 if (equal(argv[i], "-v")) 113 vflag++; 114 /* 115 * Kludge, their's no easy way to get the initialization 116 * in the right order, so force it here 117 */ 118 if ((PH = getenv("PHONES")) == NOSTR) 119 PH = "/etc/phones"; 120 vinit(); /* init variables */ 121 for (i = 1; i < argc-1; i++) 122 if (argv[i][0] == '-' && argv[i][1] != 'v') { 123 if (isnum(argv[i][1])) 124 number(value(BAUDRATE)) = atoi(&argv[i][1]); 125 else 126 printf("%s: unknown option\n", argv[i]); 127 } 128 if ((i = speed(number(value(BAUDRATE)))) == NULL) { 129 printf("tip: bad baud rate %d\n", number(value(BAUDRATE))); 130 delock(uucplock); 131 exit(3); 132 } 133 134 /* 135 * Hardwired connections require the 136 * line speed set before they make any transmissions 137 * (this is particularly true of things like a DF03-AC) 138 */ 139 if (HW) 140 ttysetup(i); 141 if (p = connect()) { 142 printf("\07%s\n[EOT]\n", p); 143 delock(uucplock); 144 exit(1); 145 } 146 if (!HW) 147 ttysetup(i); 148 149 /* 150 * Set up local tty state 151 */ 152 ioctl(0, TIOCGETP, (char *)&defarg); 153 ioctl(0, TIOCGETC, (char *)&defchars); 154 #ifdef VMUNIX 155 ioctl(0, TIOCGETD, (char *)&odisc); 156 #endif 157 arg = defarg; 158 arg.sg_flags = ANYP | CBREAK; 159 tchars = defchars; 160 tchars.t_intrc = tchars.t_quitc = -1; 161 raw(); 162 163 pipe(fildes); pipe(repdes); 164 signal(SIGALRM, timeout); 165 166 /* 167 * Everything's set up now: 168 * connection established (hardwired or diaulup) 169 * line conditioned (baud rate, mode, etc.) 170 * internal data structures (variables) 171 * so, fork one process for local side and one for remote. 172 */ 173 write(1, "\07connected\r\n", 12); 174 if (pid = fork()) 175 tipin(); 176 else 177 tipout(); 178 /*NOTREACHED*/ 179 } 180 181 static 182 cleanup() 183 { 184 delock(uucplock); 185 #ifdef VMUNIX 186 if (odisc) 187 ioctl(0, TIOCSETD, (char *)&odisc); 188 #endif 189 exit(0); 190 } 191 192 /* 193 * put the controlling keyboard into raw mode 194 */ 195 raw() 196 { 197 ioctl(0, TIOCSETP, &arg); 198 ioctl(0, TIOCSETC, &tchars); 199 #ifdef VMUNIX 200 ioctl(0, TIOCSETD, (char *)&disc); 201 #endif 202 } 203 204 205 /* 206 * return keyboard to normal mode 207 */ 208 unraw() 209 { 210 #ifdef VMUNIX 211 ioctl(0, TIOCSETD, (char *)&odisc); 212 #endif 213 ioctl(0, TIOCSETP, (char *)&defarg); 214 ioctl(0, TIOCSETC, (char *)&defchars); 215 } 216 217 /* 218 * Print string ``s'', then read a string 219 * in from the terminal. Handles signals & allows use of 220 * normal erase and kill characters. 221 */ 222 prompt(s, p) 223 char *s; 224 register char *p; 225 { 226 register char *b = p; 227 228 stoprompt = 0; 229 signal(SIGINT, intprompt); 230 signal(SIGQUIT, SIG_IGN); 231 unraw(); 232 printf("%s", s); 233 while ((*p = getchar()) != EOF && *p != '\n') { 234 if (stoprompt) 235 goto pbreak; 236 p++; 237 } 238 *p = '\0'; 239 pbreak: 240 raw(); 241 signal(SIGINT, SIG_DFL); 242 signal(SIGQUIT,SIG_DFL); 243 return(stoprompt || p == b); 244 } 245 246 /* 247 * Interrupt service routine during prompting 248 */ 249 intprompt() 250 { 251 signal(SIGINT, SIG_IGN); 252 stoprompt = 1; 253 printf("\r\n"); 254 } 255 256 /* 257 * ****TIPIN TIPIN**** 258 */ 259 tipin() 260 { 261 char gch, bol = 1; 262 263 /* 264 * Kinda klugey here... 265 * check for scripting being turned on from the .tiprc file, 266 * but be careful about just using setscript(), as we may 267 * send a SIGEMT before tipout has a chance to set up catching 268 * it; so wait a second, then setscript() 269 */ 270 if (boolean(value(SCRIPT))) { 271 sleep(1); 272 setscript(); 273 } 274 275 while (1) { 276 gch = getchar()&0177; 277 if ((gch == character(value(ESCAPE))) && bol) { 278 if (!(gch = escape())) 279 continue; 280 } else if (gch == character(value(RAISECHAR))) { 281 boolean(value(RAISE)) = !boolean(value(RAISE)); 282 printf("%s", ctrl(character(value(RAISECHAR)))); 283 continue; 284 } else if (gch == '\r') { 285 bol = 1; 286 write(FD, &gch, 1); 287 continue; 288 } else if (gch == character(value(FORCE))) { 289 printf("%s", ctrl(character(value(FORCE)))); 290 gch = getchar()&0177; 291 } 292 bol = any(gch, value(EOL)); 293 if (boolean(value(RAISE)) && islower(gch)) 294 toupper(gch); 295 write(FD, &gch, 1); 296 } 297 } 298 299 /* 300 * Escape handler -- 301 * called on recognition of ``escapec'' at the beginning of a line 302 */ 303 escape() 304 { 305 register char gch; 306 register esctable_t *p; 307 char c = character(value(ESCAPE)); 308 extern esctable_t etable[]; 309 310 gch = (getchar()&0177); 311 for (p = etable; p->e_char; p++) 312 if (p->e_char == gch) { 313 if ((p->e_flags&PRIV) && getuid()) 314 continue; 315 printf("%s", ctrl(c)); 316 (*p->e_func)(gch); 317 return(0); 318 } 319 /* ESCAPE ESCAPE forces ESCAPE */ 320 if (c != gch) 321 write(FD, &c, 1); 322 return(gch); 323 } 324 325 speed(n) 326 { 327 register int *p; 328 329 for (p = bauds; *p != -1; p++) 330 if (*p == n) 331 return(p-bauds); 332 return(NULL); 333 } 334 335 any(c, p) 336 register char c, *p; 337 { 338 while (*p) 339 if (*p++ == c) 340 return(1); 341 return(0); 342 } 343 344 size(s) 345 register char *s; 346 { 347 register int i = 0; 348 349 while (*s++) i++; 350 return(i); 351 } 352 353 char * 354 interp(s) 355 register char *s; 356 { 357 static char buf[256]; 358 register char *p = buf, c, *q; 359 360 while (c = *s++) { 361 for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++) 362 if (*q++ == c) { 363 *p++ = '\\'; *p++ = *q; 364 goto next; 365 } 366 if (c < 040) { 367 *p++ = '^'; *p++ = c + 'A'-1; 368 } else if (c == 0177) { 369 *p++ = '^'; *p++ = '?'; 370 } else 371 *p++ = c; 372 next: 373 ; 374 } 375 *p = '\0'; 376 return(buf); 377 } 378 379 char * 380 ctrl(c) 381 char c; 382 { 383 static char s[3]; 384 385 if (c < 040 || c == 0177) { 386 s[0] = '^'; 387 s[1] = c == 0177 ? '?' : c+'A'-1; 388 s[2] = '\0'; 389 } else { 390 s[0] = c; 391 s[1] = '\0'; 392 } 393 return(s); 394 } 395 396 /* 397 * Help command 398 */ 399 help(c) 400 char c; 401 { 402 register esctable_t *p; 403 extern esctable_t etable[]; 404 405 printf("%c\r\n", c); 406 for (p = etable; p->e_char; p++) { 407 if ((p->e_flags&PRIV) && getuid()) 408 continue; 409 printf("%2s", ctrl(character(value(ESCAPE)))); 410 printf("%-2s %c %s\r\n", ctrl(p->e_char), 411 p->e_flags&EXP ? '*': ' ', p->e_help); 412 } 413 } 414 415 /* 416 * Set up the "remote" tty's state 417 */ 418 static 419 ttysetup(speed) 420 { 421 #ifdef VMUNIX 422 unsigned bits = LDECCTQ; 423 #endif 424 425 arg.sg_ispeed = arg.sg_ospeed = speed; 426 arg.sg_flags = TANDEM|RAW; 427 ioctl(FD, TIOCSETP, (char *)&arg); 428 #ifdef VMUNIX 429 ioctl(FD, TIOCLBIS, (char *)&bits); 430 #endif 431 } 432