|
|
1.1 root 1: #include <stdio.h>
2: #include <signal.h>
3: #include <sgtty.h>
4: #include <ctype.h>
5: /*
6: * cu telno [ class ]
7: * Escape with `~' at beginning of line.
8: * Ordinary diversions are ~<, ~> and ~>>.
9: * Silent output diversions are ~>: and ~>>:.
10: * Terminate output diversion with ~> alone.
11: * Output command requests are ~! and ~:! (silent).
12: * Quit is ~. and ~! gives local command or shell.
13: * Also ~$ for canned procedure pumping remote.
14: * ~%put from [to] and ~%take from [to] invoke builtins
15: */
16:
17: char CRLF[2] = {'\r', '\n'};
18: #define equal(s1,s2) (strcmp(s1, s2)==0)
19: char *cunfile;
20: int ln; /* fd for comm line */
21: char tkill, terase; /* current input kill & erase */
22: char c;
23: int intr;
24: int nhup;
25: int nflag;
26: int tandm;
27: int hduplx;
28: int errflg;
29: extern int optind, opterr;
30: extern char *optarg;
31: struct sgttyb realtty;
32: struct tchars realtch;
33: int sig2();
34:
35: char *connmsg[] = {
36: "",
37: "ACU busy",
38: "call dropped",
39: "no carrier",
40: "can't fork",
41: "acu access",
42: "tty access",
43: "tty hung",
44: "usage: cu [-hnt] telno [ class ]",
45: "unknown service class",
46: "stuff dk error message here",
47: };
48: extern char *dkerror;
49:
50: struct dial {
51: char *telno;
52: char *dialtype;
53: char *comment;
54: };
55:
56: char partab[] = {
57: 0001,0201,0201,0001,0201,0001,0001,0201,
58: 0202,0004,0003,0201,0005,0206,0201,0001,
59: 0201,0001,0001,0201,0001,0201,0201,0001,
60: 0001,0201,0201,0001,0201,0001,0001,0201,
61: 0200,0000,0000,0200,0000,0200,0200,0000,
62: 0000,0200,0200,0000,0200,0000,0000,0200,
63: 0000,0200,0200,0000,0200,0000,0000,0200,
64: 0200,0000,0000,0200,0000,0200,0200,0000,
65: 0200,0000,0000,0200,0000,0200,0200,0000,
66: 0000,0200,0200,0000,0200,0000,0000,0200,
67: 0000,0200,0200,0000,0200,0000,0000,0200,
68: 0200,0000,0000,0200,0000,0200,0200,0000,
69: 0000,0200,0200,0000,0200,0000,0000,0200,
70: 0200,0000,0000,0200,0000,0200,0200,0000,
71: 0200,0000,0000,0200,0000,0200,0200,0000,
72: 0000,0200,0200,0000,0200,0000,0000,0201
73: };
74:
75: /*
76: * spawn child to invoke rd to read from line, output to fd 1
77: * main line invokes wr to read tty, write to line
78: */
79:
80: main(ac, av)
81: char *av[];
82: {
83: int fk;
84: struct sgttyb stbuf;
85: struct dial d;
86:
87: signal(SIGPIPE, SIG_IGN);
88: d.telno = NULL;
89: d.dialtype = NULL;
90: d.comment = "";
91: options(ac, av);
92: if (optind >= ac || errflg) {
93: prf(connmsg[8]);
94: exit(8);
95: }
96: ioctl(0, TIOCGETP, &realtty);
97: ioctl(0, TIOCGETC, &realtch);
98: gettelno(av[optind], &d);
99: if (optind+1 < ac)
100: d.dialtype = av[optind+1];
101: if (d.dialtype==NULL || *d.dialtype=='\0')
102: d.dialtype = "D1200";
103: if (equal(d.dialtype, "300"))
104: d.dialtype = "D300";
105: else if (equal(d.dialtype, "1200"))
106: d.dialtype = "D1200";
107: else if (equal(d.dialtype, "D"))
108: d.dialtype = "D1200";
109: else if (equal(d.dialtype, "C"))
110: d.dialtype = "C1200";
111: if (nflag) {
112: printf("%s %s %s\n", d.telno, d.dialtype, d.comment);
113: exit(0);
114: }
115: if (equal(d.dialtype, "direct")) {
116: ln = open(d.telno, 2);
117: if (ln>=0) {
118: struct tchars tcr;
119:
120: ioctl(ln, TIOCGETP, &stbuf);
121: stbuf.sg_flags &= ~ECHO;
122: stbuf.sg_flags |= RAW|EVENP|ODDP;
123: stbuf.sg_ispeed = B9600;
124: stbuf.sg_ospeed = B9600;
125: tcr.t_stopc = '\027';
126: tcr.t_startc = '\031';
127: ioctl(ln, TIOCSETP, &stbuf);
128: ioctl(ln, TIOCGETC, &tcr);
129: ioctl(ln, TIOCSETC, &tcr);
130: ioctl(ln, TIOCHPCL, 0);
131: ioctl(ln, TIOCEXCL, 0);
132: }
133: } else{
134: ln = dialout(d.telno, d.dialtype);
135: if(ln==-1 && dkerror){
136: fprintf(stderr, "tdk: %s\n", dkerror);
137: ln=-10;
138: connmsg[10]=dkerror;
139: }
140: }
141: if (ln < 0) {
142: prf("Connect failed: %s",connmsg[-ln]);
143: exit(-ln);
144: }
145: ioctl(ln, TIOCGETP, &stbuf);
146: prf("Connected");
147: if (d.comment && *d.comment && *d.comment!='\n')
148: prf(d.comment);
149: if (tandm) {
150: ioctl(ln, TIOCGETP, &stbuf);
151: stbuf.sg_flags = ODDP+EVENP+TANDEM+CBREAK;
152: ioctl(ln, TIOCSETN, &stbuf);
153: }
154: fk = fork();
155: nhup = (int)signal(SIGINT, SIG_IGN);
156: if (fk == 0) {
157: rd();
158: prf("\007Lost carrier");
159: exit(3);
160: }
161: mode(1);
162: wr();
163: mode(0);
164: kill(fk, SIGKILL);
165: stbuf.sg_ispeed = 0;
166: stbuf.sg_ospeed = 0;
167: ioctl(ln, TIOCSETN, &stbuf);
168: prf("Disconnected");
169: exit(0);
170: }
171:
172: /*
173: * wr: write to remote: 0 -> line.
174: * ~. terminate
175: * ~<file send file
176: * ~! local login-style shell
177: * ~!cmd execute cmd locally
178: * ~$proc execute proc locally, send output to line
179: * ~%cmd execute builtin cmd (put and take)
180: */
181:
182: wr()
183: {
184: int ds, fk, lcl, x, nc;
185: char *p, b[600];
186:
187: for (;;) {
188: p = b;
189: while (rdc(0) >= 1) {
190: if (p == b)
191: lcl=(c == '~');
192: if (p == b+1 && b[0] == '~')
193: lcl=(c!='~');
194: if (c == 0)
195: c = 0177;
196: if (!lcl) {
197: if (c==0177)
198: ioctl(ln, TIOCFLUSH, 0);
199: if (wrc(ln, c, 1) <= 0) {
200: prf("line gone");
201: return;
202: }
203: if (c==0177)
204: ioctl(0, TIOCFLUSH, 0);
205: }
206: if (lcl) {
207: if (c == 0177)
208: c = tkill;
209: if (c == '\r' || c == '\n')
210: goto A;
211: if (!hduplx)
212: wrc(1, c, 1);
213: }
214: *p++ = c;
215: if (c == terase) {
216: p = p-2;
217: if (p<b)
218: p = b;
219: }
220: if (c == tkill || c == 0177 || c == '\r' || c == '\n')
221: p = b;
222: }
223: return;
224: A:
225: if (!hduplx || realtty.sg_flags&CRMOD)
226: echo("");
227: *p = 0;
228: switch (b[1]) {
229: case '.':
230: case '\004':
231: return;
232: case 'b':
233: sendbreak();
234: break;
235:
236: case '!':
237: case '$':
238: fk = fork();
239: if (fk == 0) {
240: close(1);
241: dup(b[1] == '$'? ln:2);
242: close(ln);
243: mode(0);
244: if (!nhup)
245: signal(SIGINT, SIG_DFL);
246: if (b[2] == 0)
247: execl("/bin/sh","sh",0);
248: else
249: execl("/bin/sh","sh","-c",b+2,(char *)0);
250: prf("Can't execute shell");
251: exit(1);
252: }
253: if (fk!=(-1)) {
254: while (wait((int *)0)!=fk)
255: ;
256: }
257: mode(1);
258: if (b[1] == '!')
259: echo("!");
260: break;
261: case '<':
262: if (b[2] == 0) break;
263: if ((ds = open(b+2,0))<0) {
264: prf("Can't divert %s",b+1);
265: break;
266: }
267: intr = x = 0;
268: mode(2);
269: if (!nhup)
270: signal(SIGINT, sig2);
271: while (!intr && (nc = rdc(ds)) >= 1) {
272: if (wrc(ln, c, nc==1) <= 0) {
273: x = 1;
274: break;
275: }
276: }
277: signal(SIGINT, SIG_IGN);
278: close(ds);
279: mode(1);
280: if (x)
281: return;
282: break;
283: case '%':
284: dopercen(&b[2]);
285: break;
286: default:
287: prf("Use `~~' to start line with `~'");
288: }
289: continue;
290: }
291: }
292:
293: dopercen(line)
294: register char *line;
295: {
296: char *args[10];
297: register narg, f;
298: int rcount, nc;
299:
300: for (narg = 0; narg < 10;) {
301: while(*line == ' ' || *line == '\t')
302: line++;
303: if (*line == '\0')
304: break;
305: args[narg++] = line;
306: while(*line != '\0' && *line != ' ' && *line != '\t')
307: line++;
308: if (*line == '\0')
309: break;
310: *line++ = '\0';
311: }
312: if (equal(args[0], "break")) {
313: sendbreak();
314: return;
315: } else if (equal(args[0], "take")) {
316: if (narg < 2) {
317: prf("usage: ~%%take from [to]");
318: return;
319: }
320: if (narg < 3)
321: args[2] = args[1];
322: wrln("echo '~>:'");
323: wrln(args[2]);
324: wrln(";tee /dev/null <");
325: wrln(args[1]);
326: wrln(";echo '~>'\n");
327: return;
328: } else if (equal(args[0], "put")) {
329: if (narg < 2) {
330: prf("usage: ~%%put from [to]");
331: return;
332: }
333: if (narg < 3)
334: args[2] = args[1];
335: if ((f = open(args[1], 0)) < 0) {
336: prf("cannot open: %s", args[1]);
337: return;
338: }
339: wrln("stty -echo;cat >");
340: wrln(args[2]);
341: wrln(";stty echo\n");
342: sleep(5);
343: intr = 0;
344: if (!nhup)
345: signal(SIGINT, sig2);
346: mode(2);
347: rcount = 0;
348: while(!intr && (nc = rdc(f)) >= 1) {
349: rcount++;
350: if (c == tkill || c == terase)
351: wrc(ln, '\\', 0);
352: if (wrc(ln, c, nc == 1) <= 0)
353: intr = 1;
354: }
355: signal(SIGINT, SIG_IGN);
356: close(f);
357: if (intr) {
358: wrc(ln, '\n', 1);
359: prf("stopped after %d bytes", rcount);
360: }
361: wrc(ln, '\004', 1);
362: sleep(5);
363: mode(1);
364: return;
365: }
366: prf("~%%%s unknown\n", args[0]);
367: }
368:
369: wrln(s)
370: register char *s;
371: {
372: register n = strlen(s);
373:
374: write(ln, s, n);
375: }
376:
377: /*
378: * rd: read from remote: line -> 1
379: * catch:
380: * ~>[>][:][file]
381: * stuff from file...
382: * ~> (ends diversion)
383: * ways for remote to run local command:
384: * ~!command (run command locally)
385: * ~:!command (run silently locally)
386: */
387:
388: rd()
389: {
390: int ds, slnt, pid, hold=0, nc;
391: char *p, *q, b[600];
392:
393: p = b;
394: ds = -1;
395: while ((nc = rdc(ln)) >= 1) {
396: if (ds < 0 && hold==0)
397: slnt = 0;
398: if (p==b && c=='~')
399: hold= ++slnt;
400: if (hold && slnt && p==b+1 && c!=':') {
401: wrc(1, '~', 1);
402: slnt--;
403: hold = 0;
404: }
405: if (!slnt)
406: wrc(1, c, nc==1);
407: *p++ = c;
408: if (c!='\n' && p < &b[599])
409: continue;
410: q = p;
411: p = b;
412: hold = 0;
413: if (strncmp(b, "~:!",3)==0||strncmp(b, "~!", 2)==0) {
414: *--q= '\0';
415: if (*--q == '\r')
416: *q= '\0';
417: mode(0);
418: if ((pid=fork())==0) {
419: p = b+2;
420: if (*p=='!')
421: p++;
422: execl("/bin/sh", "sh", "-c", p, (char *)0);
423: exit(0);
424: }
425: while (wait((int *)0)!=pid)
426: ;
427: mode(1);
428: continue;
429: }
430: if (b[0]!='~' || b[1]!='>') {
431: if (*(q-2) == '\r') {
432: q--;
433: *(q-1)=(*q);
434: }
435: if (ds>=0)
436: write(ds, b, q-b);
437: continue;
438: }
439: if (ds>=0)
440: close(ds);
441: if (slnt) {
442: write(1, b, q - b);
443: write(1, CRLF, sizeof(CRLF));
444: }
445: if (*(q-2) == '\r')
446: q--;
447: *(q-1) = 0;
448: slnt = 0;
449: q = b+2;
450: if (*q == '>')
451: q++;
452: if (*q == ':') {
453: slnt = 1;
454: q++;
455: }
456: if (*q == 0) {
457: ds = -1;
458: continue;
459: }
460: if (b[2]!='>' || (ds = open(q,1))<0)
461: ds = creat(q, 0644);
462: lseek(ds, (long)0, 2);
463: if (ds<0)
464: prf("Can't divert %s",b+1);
465: }
466: }
467:
468: mode(f)
469: {
470: struct sgttyb stbuf;
471: static struct tchars nochars = { -1, -1, -1, -1, -1, -1};
472:
473: ioctl(0, TIOCGETP, &stbuf);
474: tkill = stbuf.sg_kill;
475: terase = stbuf.sg_erase;
476: if (f == 0) {
477: ioctl(0, TIOCSETP, &realtty);
478: ioctl(0, TIOCSETC, &realtch);
479: return;
480: }
481: if (f == 1) {
482: stbuf.sg_flags |= CBREAK;
483: stbuf.sg_flags &= ~CRMOD;
484: if (!hduplx)
485: stbuf.sg_flags &= ~ECHO;
486: ioctl(0, TIOCSETP, &stbuf);
487: ioctl(0, TIOCSETC, &nochars);
488: return;
489: }
490: if (f == 2) {
491: stbuf.sg_flags &= ~(ECHO|CRMOD);
492: ioctl(0, TIOCSETP, &stbuf);
493: ioctl(0, TIOCSETC, &realtch);
494: return;
495: }
496: }
497:
498: echo(s)
499: char *s;
500: {
501: register n = strlen(s);
502:
503: if (n>0)
504: write(1, s, n);
505: write(1, CRLF, sizeof(CRLF));
506: }
507:
508: /* VARARGS1 */
509: prf(f, s)
510: char *f;
511: char *s;
512: {
513: printf(f, s);
514: printf(CRLF);
515: }
516:
517: sendbreak()
518: {
519: struct sgttyb b;
520: int olds;
521:
522: #ifdef TIOCSBRK
523: ioctl(ln, TIOCSBRK, 0);
524: #else TIOCSBRK
525: ioctl(ln, TIOCGETP, &b);
526: olds = b.sg_ispeed;
527: b.sg_ispeed = B50;
528: b.sg_ospeed = B50;
529: ioctl(ln, TIOCSETP, &b);
530: write(ln, "\0\0\0", 3);
531: b.sg_ispeed = olds;
532: b.sg_ospeed = olds;
533: ioctl(ln, TIOCSETP, &b);
534: #endif TIOCSBRK
535: }
536:
537: /*
538: * Symbolic phone numbers
539: */
540: gettelno(np, dp)
541: char *np;
542: register struct dial *dp;
543: {
544: char cunumber[128];
545: char *hp;
546: register char *xnp;
547: char *getenv();
548:
549: if (cunfile) {
550: if (look(np, dp, cunfile))
551: return;
552: } else {
553: hp = getenv("HOME");
554: if (hp) {
555: strcpy(cunumber, hp);
556: strcat(cunumber, "/lib/cunumber");
557: if (look(np, dp, cunumber))
558: return;
559: }
560: if (look(np, dp, "/usr/lib/cunumber"))
561: return;
562: }
563: xnp = np;
564: if (*np != '/')
565: while (*xnp) {
566: if (*xnp!=';' && *xnp!=':' && *xnp!='-' && *xnp!='*'
567: && *xnp!='#' && !isdigit(*xnp)) {
568: prf("Symbolic number not found");
569: exit(1);
570: }
571: xnp++;
572: }
573: dp->telno = np;
574: }
575:
576: look(np, dp, fnp)
577: register char *np;
578: register struct dial *dp;
579: char *fnp;
580: {
581: FILE *fp;
582: static char line[128];
583: register char *lp;
584: register i;
585: char *opts[8];
586: register char **optp;
587: char *w[4];
588:
589: if ((fp = fopen(fnp, "r")) == NULL)
590: return(0);
591: while (fgets(line, sizeof(line), fp)) {
592: lp = line;
593: optp = opts;
594: for (i = 0; i<4; i++) {
595: while (isspace(*lp))
596: lp++;
597: if (i==1 && *lp=='-') {
598: *optp++ = lp;
599: i--;
600: } else
601: w[i] = lp;
602: while ((!isspace(*lp) || i==3) && *lp)
603: lp++;
604: if (*lp)
605: *lp++ = '\0';
606: }
607: if (strcmp(w[0], np))
608: continue;
609: i = optind;
610: optind = 0;
611: options(optp-opts, opts);
612: optind = i;
613: dp->telno = w[1];
614: dp->dialtype = w[2];
615: dp->comment = w[3];
616: fclose(fp);
617: return(1);
618: }
619: fclose(fp);
620: return(0);
621: }
622:
623: options(ac, av)
624: char **av;
625: {
626: register o;
627:
628: opterr = 0;
629: while ((o = getopt(ac, av, "hntf:")) != EOF) {
630: switch(o) {
631:
632: case '?':
633: errflg++;
634: continue;
635:
636: case 'h':
637: hduplx++;
638: continue;
639:
640: case 'f':
641: cunfile = optarg;
642: continue;
643:
644: case 't':
645: tandm++;
646: continue;
647:
648: case 'n':
649: nflag++;
650: continue;
651: }
652: }
653: }
654:
655: wrc(f, c, flush)
656: register c;
657: {
658: static char buf[64];
659: static char *bp = buf;
660: register r;
661:
662: c &= 0177;
663: if (f==ln)
664: c |= (partab[c] & 0200);
665: *bp++ = c;
666: r = 1;
667: if (flush || bp >= &buf[64]) {
668: r = write(f, buf, bp-buf);
669: bp = buf;
670: }
671: return(r);
672: }
673:
674: rdc(ds)
675: {
676: static char buf[64];
677: static nc = 0;
678: static char *bp;
679:
680: if (nc <= 0) {
681: nc = read(ds, buf, 64);
682: bp = buf;
683: }
684: if (nc <= 0)
685: return(nc);
686: nc--;
687: c = *bp++ & 0177;
688: return(nc+1);
689: }
690:
691: sig2()
692: {
693: signal(SIGINT, SIG_IGN);
694: intr = 1;
695: }
696:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.