Commit | Line | Data |
---|---|---|
a2c6551c | 1 | /* cmds.c 4.3 81/06/02 */ |
22daf918 BJ |
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); | |
a2c6551c SL |
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 | } | |
22daf918 BJ |
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; | |
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); | |
a2c6551c SL |
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 | } | |
22daf918 BJ |
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 | |
283 | continue; | |
284 | } | |
285 | send(c); | |
286 | } while (c != '\r'); | |
287 | if (boolean(value(VERBOSE))) | |
288 | printf("\r%d", ++lcount); | |
a2c6551c SL |
289 | if (boolean(value(ECHOCHECK))) { |
290 | alarm(10); | |
291 | timedout = 0; | |
292 | do { /* wait for prompt */ | |
293 | read(FD, (char *)&c, 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 ((c&0177) != character(value(PROMPT))); | |
301 | alarm(0); | |
302 | } | |
22daf918 BJ |
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 | } | |
a2c6551c SL |
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]); | |
22daf918 BJ |
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 | int cc; | |
355 | int retry = 0; | |
356 | ||
357 | cc = c; | |
358 | write(FD, (char *)&cc, 1); | |
a2c6551c SL |
359 | if (!boolean(value(ECHOCHECK))) |
360 | return; | |
22daf918 BJ |
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 | #ifdef VMUNIX | |
517 | ioctl(0, TIOCSETD, (char *)&odisc); | |
518 | #endif | |
519 | unraw(); | |
520 | exit(0); | |
521 | } | |
522 | ||
523 | intcopy() | |
524 | { | |
525 | raw(); | |
526 | quit = 1; | |
527 | } | |
528 | ||
529 | execute(s) | |
530 | char *s; | |
531 | { | |
532 | register char *cp; | |
533 | ||
534 | if ((cp = rindex(value(SHELL), '/')) == NULL) | |
535 | cp = value(SHELL); | |
536 | else | |
537 | cp++; | |
538 | execl(value(SHELL), cp, "-c", s, 0); | |
539 | } | |
540 | ||
541 | args(buf, a) | |
542 | char *buf, *a[]; | |
543 | { | |
544 | register char *p = buf, *start; | |
545 | register char **parg = a; | |
546 | register int n = 0; | |
547 | ||
548 | do { | |
549 | while (*p && (*p == ' ' || *p == '\t')) | |
550 | p++; | |
551 | start = p; | |
552 | if (*p) | |
553 | *parg = p; | |
554 | while (*p && (*p != ' ' && *p != '\t')) | |
555 | p++; | |
556 | if (p != start) | |
557 | parg++, n++; | |
558 | if (*p) | |
559 | *p++ = '\0'; | |
560 | } while (*p); | |
561 | ||
562 | return(n); | |
563 | } | |
564 | ||
565 | prtime(s, a) | |
566 | char *s; | |
567 | time_t a; | |
568 | { | |
569 | register i; | |
570 | int nums[3]; | |
571 | ||
572 | for (i = 0; i < 3; i++) { | |
573 | nums[i] = (int)(a % quant[i]); | |
574 | a /= quant[i]; | |
575 | } | |
576 | printf("%s", s); | |
577 | while (--i >= 0) | |
578 | if (nums[i]) | |
579 | printf("%d %s%c ", nums[i], sep[i], | |
580 | nums[i] == 1 ? '\0' : 's'); | |
581 | printf("\r\n!\r\n"); | |
582 | } | |
583 | ||
584 | variable() | |
585 | { | |
586 | char buf[256]; | |
587 | ||
588 | if (prompt("[set] ", buf)) | |
589 | return; | |
590 | vlex(buf); | |
591 | if (vtable[BEAUTIFY].v_access&CHANGED) { | |
592 | vtable[BEAUTIFY].v_access &= ~CHANGED; | |
593 | signal(pid, SIGSYS); | |
594 | } | |
595 | if (vtable[SCRIPT].v_access&CHANGED) { | |
596 | vtable[SCRIPT].v_access &= ~CHANGED; | |
597 | setscript(); | |
598 | } | |
599 | if (vtable[RECORD].v_access&CHANGED) { | |
600 | vtable[RECORD].v_access &= ~CHANGED; | |
601 | if (boolean(value(SCRIPT))) | |
602 | setscript(); | |
603 | } | |
604 | } | |
061754f3 SL |
605 | |
606 | /* | |
607 | * Send a break. | |
608 | * If we can't do it directly (as on VMUNIX), then simulate it. | |
609 | */ | |
610 | genbrk() | |
611 | { | |
612 | #ifdef VMUNIX | |
613 | ioctl(FD, TIOCSBRK, NULL); | |
614 | sleep(1); | |
615 | ioctl(FD, TIOCCBRK, NULL); | |
616 | #else | |
617 | struct sgttyb ttbuf; | |
618 | int sospeed; | |
619 | ||
620 | ioctl(FD, TIOCGETP, &ttbuf); | |
621 | sospeed = ttbuf.sg_ospeed; | |
622 | ttbuf.sg_ospeed = B150; | |
623 | ioctl(FD, TIOCSETP, &ttbuf); | |
624 | write(FD, "\0\0\0\0\0\0\0\0\0\0", 10); | |
625 | ttbuf.sg_ospeed = sospeed; | |
626 | ioctl(FD, TIOCSETP, &ttbuf); | |
627 | write(FD, "@", 1); | |
628 | #endif | |
629 | } |