Commit | Line | Data |
---|---|---|
22daf918 BJ |
1 | /* cmds.c 4.1 81/05/09 */ |
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 | } | |
221 | ||
222 | /* | |
223 | * Bulk transfer routine to remote host -- | |
224 | * used by sendfile() and cu_put() | |
225 | */ | |
226 | transmit(fd, eofchars, command) | |
227 | FILE *fd; | |
228 | char *eofchars, *command; | |
229 | { | |
230 | char *pc, lastc; | |
231 | int c, ccount, lcount; | |
232 | time_t start_t, stop_t; | |
233 | ||
234 | kill(pid, SIGIOT); /* put TIPOUT into a wait state */ | |
235 | signal(SIGINT, stopsnd); | |
236 | stop = 0; | |
237 | ioctl(0, TIOCSETC, &defchars); | |
238 | read(repdes[0], (char *)&ccc, 1); | |
239 | if (command != NULL) { | |
240 | for (pc = command; *pc; pc++) | |
241 | send(*pc); | |
242 | read(FD, (char *)&c, 1); /* trailing \n */ | |
243 | } | |
244 | lcount = 0; | |
245 | lastc = '\0'; | |
246 | start_t = time(0); | |
247 | while(1) { | |
248 | ccount = 0; | |
249 | do { | |
250 | c = getc(fd); | |
251 | if (stop) | |
252 | goto out; | |
253 | if (c == EOF) | |
254 | goto out; | |
255 | if (c == 0177) | |
256 | continue; | |
257 | lastc = c; | |
258 | if (c < 040) { | |
259 | if (c == '\n') | |
260 | c = '\r'; | |
261 | else if (c == '\t') { | |
262 | if (boolean(value(TABEXPAND))) { | |
263 | send(' '); | |
264 | while((++ccount % 8) != 0) | |
265 | send(' '); | |
266 | continue; | |
267 | } | |
268 | } else | |
269 | continue; | |
270 | } | |
271 | send(c); | |
272 | } while (c != '\r'); | |
273 | if (boolean(value(VERBOSE))) | |
274 | printf("\r%d", ++lcount); | |
275 | alarm(10); | |
276 | timedout = 0; | |
277 | do { /* wait for prompt */ | |
278 | read(FD, (char *)&c, 1); | |
279 | if (timedout || stop) { | |
280 | if (timedout) | |
281 | printf("\r\ntimed out at eol\r\n"); | |
282 | alarm(0); | |
283 | goto out; | |
284 | } | |
285 | } while ((c&0177) != character(value(PROMPT))); | |
286 | alarm(0); | |
287 | } | |
288 | out: | |
289 | if (lastc != '\n') | |
290 | send('\r'); | |
291 | for (pc = eofchars; *pc; pc++) | |
292 | send(*pc); | |
293 | stop_t = time(0); | |
294 | fclose(fd); | |
295 | signal(SIGINT, SIG_DFL); | |
296 | if (boolean(value(VERBOSE))) | |
297 | prtime(" lines transferred in ", stop_t-start_t); | |
298 | write(fildes[1], (char *)&ccc, 1); | |
299 | ioctl(0, TIOCSETC, &tchars); | |
300 | } | |
301 | ||
302 | /* | |
303 | * Cu-like put command | |
304 | */ | |
305 | cu_put(cc) | |
306 | char cc; | |
307 | { | |
308 | FILE *fd; | |
309 | char line[BUFSIZ]; | |
310 | int argc; | |
311 | ||
312 | if (prompt("[put] ", copyname)) | |
313 | return; | |
314 | if ((argc = args(copyname, argv)) < 1 || argc > 2) { | |
315 | printf("usage: <put> from [to]\r\n"); | |
316 | return; | |
317 | } | |
318 | if (argc == 1) | |
319 | argv[1] = argv[0]; | |
320 | if ((fd = fopen(argv[0], "r")) == NULL) { | |
321 | printf("%s: cannot open\r\n", argv[0]); | |
322 | return; | |
323 | } | |
324 | sprintf(line, "cat>'%s'\r", argv[1]); | |
325 | transmit(fd, "\04", line); | |
326 | } | |
327 | ||
328 | /* | |
329 | * FTP - send single character | |
330 | * wait for echo & handle timeout | |
331 | */ | |
332 | send(c) | |
333 | char c; | |
334 | { | |
335 | int cc; | |
336 | int retry = 0; | |
337 | ||
338 | cc = c; | |
339 | write(FD, (char *)&cc, 1); | |
340 | tryagain: | |
341 | timedout = 0; | |
342 | alarm(10); | |
343 | read(FD, (char *)&cc, 1); | |
344 | alarm(0); | |
345 | if (timedout) { | |
346 | printf("\r\ntimeout error (%s)\r\n", ctrl(c)); | |
347 | if (retry++ > 3) | |
348 | return; | |
349 | write(FD, &null, 1); /* poke it */ | |
350 | goto tryagain; | |
351 | } | |
352 | } | |
353 | ||
354 | timeout() | |
355 | { | |
356 | signal(SIGALRM, timeout); | |
357 | timedout = 1; | |
358 | } | |
359 | ||
360 | #ifdef CONNECT | |
361 | /* | |
362 | * Fork a program with: | |
363 | * 0 <-> local tty in | |
364 | * 1 <-> local tty out | |
365 | * 2 <-> local tty out | |
366 | * 3 <-> remote tty in | |
367 | * 4 <-> remote tty out | |
368 | */ | |
369 | consh(c) | |
370 | { | |
371 | char buf[256]; | |
372 | int cpid, status, p; | |
373 | time_t start; | |
374 | ||
375 | putchar(c); | |
376 | if (prompt("Local command? ", buf)) | |
377 | return; | |
378 | kill(pid, SIGIOT); /* put TIPOUT into a wait state */ | |
379 | signal(SIGINT, SIG_IGN); | |
380 | signal(SIGQUIT, SIG_IGN); | |
381 | ioctl(0, TIOCSETC, &defchars); | |
382 | read(repdes[0], (char *)&ccc, 1); | |
383 | /* | |
384 | * Set up file descriptors in the child and | |
385 | * let it go... | |
386 | */ | |
387 | if ((cpid = fork()) < 0) | |
388 | printf("can't fork!\r\n"); | |
389 | else if (cpid) { | |
390 | start = time(0); | |
391 | while ((p = wait(&status)) > 0 && p != cpid) | |
392 | ; | |
393 | } else { | |
394 | register int i; | |
395 | ||
396 | dup2(FD, 3); | |
397 | dup2(3, 4); | |
398 | for (i = 5; i < 20; i++) | |
399 | close(i); | |
400 | signal(SIGINT, SIG_DFL); | |
401 | signal(SIGQUIT, SIG_DFL); | |
402 | execute(buf); | |
403 | printf("can't find `%s'\r\n", buf); | |
404 | exit(0); | |
405 | } | |
406 | if (boolean(value(VERBOSE))) | |
407 | prtime("away for ", time(0)-start); | |
408 | write(fildes[1], (char *)&ccc, 1); | |
409 | ioctl(0, TIOCSETC, &tchars); | |
410 | signal(SIGINT, SIG_DFL); | |
411 | signal(SIGQUIT, SIG_DFL); | |
412 | } | |
413 | #endif | |
414 | ||
415 | /* | |
416 | * Escape to local shell | |
417 | */ | |
418 | shell() | |
419 | { | |
420 | int shpid, status; | |
421 | extern char **environ; | |
422 | char *cp; | |
423 | ||
424 | printf("[sh]\r\n"); | |
425 | signal(SIGINT, SIG_IGN); | |
426 | signal(SIGQUIT, SIG_IGN); | |
427 | unraw(); | |
428 | if (shpid = fork()) { | |
429 | while (shpid != wait(&status)); | |
430 | raw(); | |
431 | printf("\r\n!\r\n"); | |
432 | signal(SIGINT, SIG_DFL); | |
433 | signal(SIGQUIT, SIG_DFL); | |
434 | return; | |
435 | } else { | |
436 | signal(SIGQUIT, SIG_DFL); | |
437 | signal(SIGINT, SIG_DFL); | |
438 | if ((cp = rindex(value(SHELL), '/')) == NULL) | |
439 | cp = value(SHELL); | |
440 | else | |
441 | cp++; | |
442 | execl(value(SHELL), cp, 0); | |
443 | printf("\r\ncan't execl!\r\n"); | |
444 | exit(1); | |
445 | } | |
446 | } | |
447 | ||
448 | /* | |
449 | * TIPIN portion of scripting | |
450 | * initiate the conversation with TIPOUT | |
451 | */ | |
452 | setscript() | |
453 | { | |
454 | char c; | |
455 | /* | |
456 | * enable TIPOUT side for dialogue | |
457 | */ | |
458 | kill(pid, SIGEMT); | |
459 | if (boolean(value(SCRIPT))) | |
460 | write(fildes[1], value(RECORD), size(value(RECORD))); | |
461 | write(fildes[1], "\n", 1); | |
462 | /* | |
463 | * wait for TIPOUT to finish | |
464 | */ | |
465 | read(repdes[0], &c, 1); | |
466 | if (c == 'n') | |
467 | printf("can't create %s\r\n", value(RECORD)); | |
468 | } | |
469 | ||
470 | /* | |
471 | * Change current working directory of | |
472 | * local portion of tip | |
473 | */ | |
474 | chdirectory() | |
475 | { | |
476 | char dirname[80]; | |
477 | register char *cp = dirname; | |
478 | ||
479 | if (prompt("[cd] ", dirname)) | |
480 | if (stoprompt) | |
481 | return; | |
482 | else | |
483 | cp = value(HOME); | |
484 | if (chdir(cp) < 0) | |
485 | printf("%s: bad directory\r\n", cp); | |
486 | printf("!\r\n"); | |
487 | } | |
488 | ||
489 | finish() | |
490 | { | |
491 | kill(pid, SIGTERM); | |
492 | disconnect(); | |
493 | printf("\r\n[EOT]\r\n"); | |
494 | delock(uucplock); | |
495 | #ifdef VMUNIX | |
496 | ioctl(0, TIOCSETD, (char *)&odisc); | |
497 | #endif | |
498 | unraw(); | |
499 | exit(0); | |
500 | } | |
501 | ||
502 | intcopy() | |
503 | { | |
504 | raw(); | |
505 | quit = 1; | |
506 | } | |
507 | ||
508 | execute(s) | |
509 | char *s; | |
510 | { | |
511 | register char *cp; | |
512 | ||
513 | if ((cp = rindex(value(SHELL), '/')) == NULL) | |
514 | cp = value(SHELL); | |
515 | else | |
516 | cp++; | |
517 | execl(value(SHELL), cp, "-c", s, 0); | |
518 | } | |
519 | ||
520 | args(buf, a) | |
521 | char *buf, *a[]; | |
522 | { | |
523 | register char *p = buf, *start; | |
524 | register char **parg = a; | |
525 | register int n = 0; | |
526 | ||
527 | do { | |
528 | while (*p && (*p == ' ' || *p == '\t')) | |
529 | p++; | |
530 | start = p; | |
531 | if (*p) | |
532 | *parg = p; | |
533 | while (*p && (*p != ' ' && *p != '\t')) | |
534 | p++; | |
535 | if (p != start) | |
536 | parg++, n++; | |
537 | if (*p) | |
538 | *p++ = '\0'; | |
539 | } while (*p); | |
540 | ||
541 | return(n); | |
542 | } | |
543 | ||
544 | prtime(s, a) | |
545 | char *s; | |
546 | time_t a; | |
547 | { | |
548 | register i; | |
549 | int nums[3]; | |
550 | ||
551 | for (i = 0; i < 3; i++) { | |
552 | nums[i] = (int)(a % quant[i]); | |
553 | a /= quant[i]; | |
554 | } | |
555 | printf("%s", s); | |
556 | while (--i >= 0) | |
557 | if (nums[i]) | |
558 | printf("%d %s%c ", nums[i], sep[i], | |
559 | nums[i] == 1 ? '\0' : 's'); | |
560 | printf("\r\n!\r\n"); | |
561 | } | |
562 | ||
563 | variable() | |
564 | { | |
565 | char buf[256]; | |
566 | ||
567 | if (prompt("[set] ", buf)) | |
568 | return; | |
569 | vlex(buf); | |
570 | if (vtable[BEAUTIFY].v_access&CHANGED) { | |
571 | vtable[BEAUTIFY].v_access &= ~CHANGED; | |
572 | signal(pid, SIGSYS); | |
573 | } | |
574 | if (vtable[SCRIPT].v_access&CHANGED) { | |
575 | vtable[SCRIPT].v_access &= ~CHANGED; | |
576 | setscript(); | |
577 | } | |
578 | if (vtable[RECORD].v_access&CHANGED) { | |
579 | vtable[RECORD].v_access &= ~CHANGED; | |
580 | if (boolean(value(SCRIPT))) | |
581 | setscript(); | |
582 | } | |
583 | } |