| 1 | /* tip.c 4.1 81/05/09 */ |
| 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 | |
| 48 | #include "tip.h" |
| 49 | |
| 50 | /* |
| 51 | * Baud rate mapping table |
| 52 | */ |
| 53 | int bauds[] = { |
| 54 | 0, 50, 75, 110, 134, 150, 200, 300, 600, |
| 55 | 1200, 1800, 2400, 4800, 9600, 19200, -1 |
| 56 | }; |
| 57 | |
| 58 | int intprompt(); |
| 59 | int timeout(); |
| 60 | static int cleanup(); |
| 61 | |
| 62 | main(argc, argv) |
| 63 | char *argv[]; |
| 64 | { |
| 65 | char *system = NOSTR; |
| 66 | register int i; |
| 67 | #ifdef VMUNIX |
| 68 | int disc; |
| 69 | #endif |
| 70 | char *p; |
| 71 | |
| 72 | if (argc > 4) { |
| 73 | fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n"); |
| 74 | exit(1); |
| 75 | } |
| 76 | if (!isatty(0)) { |
| 77 | fprintf(stderr, "tip: must be interactive\n"); |
| 78 | exit(1); |
| 79 | } |
| 80 | if (argc > 1 && argv[argc-1][0] != '-') |
| 81 | system = argv[argc-1]; /* always last item */ |
| 82 | signal(SIGINT, cleanup); |
| 83 | signal(SIGQUIT, cleanup); |
| 84 | signal(SIGHUP, cleanup); |
| 85 | signal(SIGTERM, cleanup); |
| 86 | if ((i = hunt(system)) == 0) { |
| 87 | printf("all ports busy\n"); |
| 88 | exit(3); |
| 89 | } |
| 90 | if (i == -1) { |
| 91 | printf("link down\n"); |
| 92 | exit(3); |
| 93 | } |
| 94 | loginit(); |
| 95 | /* |
| 96 | * Now that we have the logfile and the ACU open |
| 97 | * return to the real uid and gid. These things will |
| 98 | * be closed on exit. Note that we can't run as root, |
| 99 | * because locking mechanism on the tty and the accounting |
| 100 | * will be bypassed. |
| 101 | */ |
| 102 | setuid(getuid()); |
| 103 | setgid(getgid()); |
| 104 | for (i = 1; i < argc-1; i++) |
| 105 | if (equal(argv[i], "-v")) |
| 106 | vflag++; |
| 107 | /* |
| 108 | * Kludge, their's no easy way to get the initialization |
| 109 | * in the right order, so force it here |
| 110 | */ |
| 111 | if ((PH = getenv("PHONES")) == NOSTR) |
| 112 | PH = "/etc/phones"; |
| 113 | vinit(); /* init variables */ |
| 114 | for (i = 1; i < argc-1; i++) |
| 115 | if (argv[i][0] == '-' && argv[i][1] != 'v') { |
| 116 | if (isnum(argv[i][1])) |
| 117 | number(value(BAUDRATE)) = atoi(&argv[i][1]); |
| 118 | else |
| 119 | printf("%s: unknown option\n", argv[i]); |
| 120 | } |
| 121 | if ((arg.sg_ispeed = speed(number(value(BAUDRATE)))) == NULL) { |
| 122 | printf("tip: bad baud rate %d\n", number(value(BAUDRATE))); |
| 123 | delock(uucplock); |
| 124 | exit(3); |
| 125 | } |
| 126 | arg.sg_ospeed = arg.sg_ispeed; |
| 127 | /* |
| 128 | * NOTE that remote side runs in TANDEM mode, |
| 129 | * if the host doesn't honor X-ON/X-OFF with default |
| 130 | * start/stop chars, the remote description must be |
| 131 | * extended and tchars will have to be set up here. |
| 132 | * If the host doesn't honor TANDEM mode, then watch |
| 133 | * out, as you'll get garbage. |
| 134 | */ |
| 135 | arg.sg_flags = RAW | TANDEM; |
| 136 | ioctl(FD, TIOCSETP, &arg); |
| 137 | |
| 138 | ioctl(0, TIOCGETP, &defarg); /* store initial status */ |
| 139 | ioctl(0, TIOCGETC, &defchars); |
| 140 | arg = defarg; |
| 141 | arg.sg_flags = ANYP | CBREAK; |
| 142 | tchars = defchars; |
| 143 | tchars.t_intrc = tchars.t_quitc = -1; |
| 144 | |
| 145 | if (p = connect()) { |
| 146 | printf("\07%s\n[EOT]\n", p); |
| 147 | delock(uucplock); |
| 148 | exit(1); |
| 149 | } |
| 150 | write(1, "\07connected\n", 11); |
| 151 | raw(); |
| 152 | #ifdef VMUNIX |
| 153 | ioctl(0, TIOCGETD, (char *)&odisc); |
| 154 | disc = OTTYDISC; |
| 155 | ioctl(0, TIOCSETD, (char *)&disc); |
| 156 | #endif |
| 157 | pipe(fildes); pipe(repdes); |
| 158 | signal(SIGALRM, timeout); |
| 159 | if (pid = fork()) |
| 160 | tipin(); |
| 161 | else |
| 162 | tipout(); |
| 163 | /*NOTREACHED*/ |
| 164 | } |
| 165 | |
| 166 | static |
| 167 | cleanup() |
| 168 | { |
| 169 | delock(uucplock); |
| 170 | exit(0); |
| 171 | } |
| 172 | |
| 173 | /* |
| 174 | * put the controlling keyboard into raw mode |
| 175 | */ |
| 176 | raw() |
| 177 | { |
| 178 | ioctl(0, TIOCSETP, &arg); |
| 179 | ioctl(0, TIOCSETC, &tchars); |
| 180 | } |
| 181 | |
| 182 | |
| 183 | /* |
| 184 | * return keyboard to normal mode |
| 185 | */ |
| 186 | unraw() |
| 187 | { |
| 188 | ioctl(0, TIOCSETP, &defarg); |
| 189 | ioctl(0, TIOCSETC, &defchars); |
| 190 | } |
| 191 | |
| 192 | /* |
| 193 | * Print string ``s'', then read a string |
| 194 | * in from the terminal. Handles signals & allows use of |
| 195 | * normal erase and kill characters. |
| 196 | */ |
| 197 | prompt(s, p) |
| 198 | char *s; |
| 199 | register char *p; |
| 200 | { |
| 201 | register char *b = p; |
| 202 | |
| 203 | stoprompt = 0; |
| 204 | signal(SIGINT, intprompt); |
| 205 | signal(SIGQUIT, SIG_IGN); |
| 206 | unraw(); |
| 207 | printf("%s", s); |
| 208 | while ((*p = getchar()) != EOF && *p != '\n') { |
| 209 | if (stoprompt) |
| 210 | goto pbreak; |
| 211 | p++; |
| 212 | } |
| 213 | *p = '\0'; |
| 214 | pbreak: |
| 215 | raw(); |
| 216 | signal(SIGINT, SIG_DFL); |
| 217 | signal(SIGQUIT,SIG_DFL); |
| 218 | return(stoprompt || p == b); |
| 219 | } |
| 220 | |
| 221 | /* |
| 222 | * Interrupt service routine during prompting |
| 223 | */ |
| 224 | intprompt() |
| 225 | { |
| 226 | signal(SIGINT, SIG_IGN); |
| 227 | stoprompt = 1; |
| 228 | printf("\r\n"); |
| 229 | } |
| 230 | |
| 231 | /* |
| 232 | * ****TIPIN TIPIN**** |
| 233 | */ |
| 234 | tipin() |
| 235 | { |
| 236 | char gch, bol = 1; |
| 237 | |
| 238 | while (1) { |
| 239 | gch = getchar()&0177; |
| 240 | if ((gch == character(value(ESCAPE))) && bol) { |
| 241 | if (!(gch = escape())) |
| 242 | continue; |
| 243 | } else if (gch == character(value(RAISECHAR))) { |
| 244 | boolean(value(RAISE)) = !boolean(value(RAISE)); |
| 245 | printf("%s", ctrl(character(value(RAISECHAR)))); |
| 246 | continue; |
| 247 | } else if (gch == '\r') { |
| 248 | bol = 1; |
| 249 | write(FD, &gch, 1); |
| 250 | continue; |
| 251 | } else if (gch == character(value(FORCE))) { |
| 252 | printf("%s", ctrl(character(value(FORCE)))); |
| 253 | gch = getchar()&0177; |
| 254 | } |
| 255 | bol = any(gch, value(EOL)); |
| 256 | if (boolean(value(RAISE)) && islower(gch)) |
| 257 | toupper(gch); |
| 258 | write(FD, &gch, 1); |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | /* |
| 263 | * Escape handler -- |
| 264 | * called on recognition of ``escapec'' at the beginning of a line |
| 265 | */ |
| 266 | escape() |
| 267 | { |
| 268 | register char gch; |
| 269 | register esctable_t *p; |
| 270 | char c = character(value(ESCAPE)); |
| 271 | extern esctable_t etable[]; |
| 272 | |
| 273 | gch = (getchar()&0177); |
| 274 | for (p = etable; p->e_char; p++) |
| 275 | if (p->e_char == gch) { |
| 276 | if ((p->e_flags&PRIV) && getuid()) |
| 277 | continue; |
| 278 | printf("%s", ctrl(c)); |
| 279 | (*p->e_func)(gch); |
| 280 | return(0); |
| 281 | } |
| 282 | |
| 283 | write(FD, &c, 1); |
| 284 | return(gch); |
| 285 | } |
| 286 | |
| 287 | speed(n) |
| 288 | { |
| 289 | register int *p; |
| 290 | |
| 291 | for (p = bauds; *p != -1; p++) |
| 292 | if (*p == n) |
| 293 | return(p-bauds); |
| 294 | return(NULL); |
| 295 | } |
| 296 | |
| 297 | any(c, p) |
| 298 | register char c, *p; |
| 299 | { |
| 300 | while (*p) |
| 301 | if (*p++ == c) |
| 302 | return(1); |
| 303 | return(0); |
| 304 | } |
| 305 | |
| 306 | size(s) |
| 307 | register char *s; |
| 308 | { |
| 309 | register int i = 0; |
| 310 | |
| 311 | while (*s++) i++; |
| 312 | return(i); |
| 313 | } |
| 314 | |
| 315 | char * |
| 316 | interp(s) |
| 317 | register char *s; |
| 318 | { |
| 319 | static char buf[256]; |
| 320 | register char *p = buf, c, *q; |
| 321 | |
| 322 | while (c = *s++) { |
| 323 | for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++) |
| 324 | if (*q++ == c) { |
| 325 | *p++ = '\\'; *p++ = *q; |
| 326 | goto next; |
| 327 | } |
| 328 | if (c < 040) { |
| 329 | *p++ = '^'; *p++ = c + 'A'-1; |
| 330 | } else if (c == 0177) { |
| 331 | *p++ = '^'; *p++ = '?'; |
| 332 | } else |
| 333 | *p++ = c; |
| 334 | next: |
| 335 | ; |
| 336 | } |
| 337 | *p = '\0'; |
| 338 | return(buf); |
| 339 | } |
| 340 | |
| 341 | char * |
| 342 | ctrl(c) |
| 343 | char c; |
| 344 | { |
| 345 | static char s[3]; |
| 346 | |
| 347 | if (c < 040 || c == 0177) { |
| 348 | s[0] = '^'; |
| 349 | s[1] = c == 0177 ? '?' : c+'A'-1; |
| 350 | s[2] = '\0'; |
| 351 | } else { |
| 352 | s[0] = c; |
| 353 | s[1] = '\0'; |
| 354 | } |
| 355 | return(s); |
| 356 | } |
| 357 | |
| 358 | /* |
| 359 | * Help command |
| 360 | */ |
| 361 | help(c) |
| 362 | char c; |
| 363 | { |
| 364 | register esctable_t *p; |
| 365 | extern esctable_t etable[]; |
| 366 | |
| 367 | printf("%c\r\n", c); |
| 368 | for (p = etable; p->e_char; p++) { |
| 369 | if ((p->e_flags&PRIV) && getuid()) |
| 370 | continue; |
| 371 | printf("%2s", ctrl(character(value(ESCAPE)))); |
| 372 | printf("%-2s %c %s\r\n", ctrl(p->e_char), |
| 373 | p->e_flags&EXP ? '*': ' ', p->e_help); |
| 374 | } |
| 375 | } |