#include #include #include /* * cu telno [-t] [-s speed] [-l line] [-a acu] * * -t is for dial-out to terminal. * speeds are: 110, 134, 150, 300, 1200. 300 is default. * * Escape with `~' at beginning of line. * Ordinary diversions are ~<, ~> and ~>>. * Silent output diversions are ~>: and ~>>:. * Terminate output diversion with ~> alone. * Quit is ~. and ~! gives local command or shell. * Also ~$ for canned procedure pumping remote. * ~%put from [to] and ~%take from [to] invoke builtins */ #define CRLF "\r\n" #define wrc(ds) write(ds,&c,1) char *devcul = "/dev/cul0"; char *devcua = "/dev/cua0"; char *lspeed = "300"; int ln; /* fd for comm line */ char tkill, terase; /* current input kill & erase */ char c; char *connmsg[] = { "", "line busy", "call dropped", "no carrier", "can't fork", "acu access", "tty access", "tty hung", "usage: cu telno [-t] [-s speed] [-l line] [-a acu]" }; rdc(ds) { ds=read(ds,&c,1); c&= 0177; return (ds); } int intr; sig2() { signal(SIGINT, SIG_IGN); intr = 1; } int set14; xsleep(n) { xalarm(n); pause(); xalarm(0); } xalarm(n) { set14=n; alarm(n); } sig14() { signal(SIGALRM, sig14); if (set14) alarm(1); } int dout; int nhup; /* * main: get connection, set speed for line. * spawn child to invoke rd to read from line, output to fd 1 * main line invokes wr to read tty, write to line */ main(ac,av) char *av[]; { int fk; int speed; char *telno; struct sgttyb stbuf; signal(SIGALRM, sig14); if (ac < 2) { prf(connmsg[8]); exit(8); } telno = av[1]; av += 2; ac -= 2; for (; ac > 0; av++) { if (equal(*av, "-t")) { dout = 1; --ac; continue; } if (ac < 2) break; if (equal(*av, "-s")) lspeed = *++av; else if (equal(*av, "-l")) devcul = *++av; else if (equal(*av, "-a")) devcua = *++av; else break; ac -= 2; } if (!exists(devcua) || !exists(devcul)) exit(9); ln = conn(devcul, devcua, telno); if (ln < 0) { prf("Connect failed: %s",connmsg[-ln]); exit(-ln); } switch(atoi(lspeed)) { case 110: speed = B110;break; case 150: speed = B150;break; default: case 300: speed = B300;break; case 1200: speed = B1200;break; } stbuf.sg_ispeed = speed; stbuf.sg_ospeed = speed; stbuf.sg_flags = EVENP|ODDP; if (!dout) stbuf.sg_flags |= RAW; ioctl(TIOCSETP, ln, &stbuf); ioctl(TIOCEXCL, ln, (struct sgttyb *)NULL); ioctl(TIOCHPCL, ln, (struct sgttyb *)NULL); prf("Connected"); if (dout) fk = -1; else fk = fork(); nhup = (int)signal(SIGINT, SIG_IGN); if (fk == 0) { rd(); prf("\007Lost carrier"); exit(3); } mode(1); wr(); mode(0); kill(fk, SIGKILL); wait((int *)NULL); stbuf.sg_ispeed = 0; stbuf.sg_ospeed = 0; ioctl(TIOCSETP, ln, &stbuf); prf("Disconnected"); exit(0); } /* * conn: establish dial-out connection. * Example: fd = conn("/dev/ttyh","/dev/dn1","4500"); * Returns descriptor open to tty for reading and writing. * Negative values (-1...-7) denote errors in connmsg. * Uses alarm and fork/wait; requires sig14 handler. * Be sure to disconnect tty when done, via HUPCL or stty 0. */ conn(dev,acu,telno) char *dev, *acu, *telno; { struct sgttyb stbuf; extern errno; char *p, *q, b[30]; int er, fk, dn, dh, t; er=0; fk=(-1); if ((dn=open(acu,1))<0) { er=(errno == 6? 1:5); goto X; } if ((fk=fork()) == (-1)) { er=4; goto X; } if (fk == 0) { open(dev,2); for (;;) pause(); } xsleep(2); /* * copy phone #, assure EON */ p=b; q=telno; while (*p++=(*q++)) ; p--; if (*(p-1)!='<') { if (*(p-1)!='-') *p++='-'; *p++='<'; } t=p-b; xalarm(5*t); t=write(dn,b,t); xalarm(0); if (t<0) { er=2; goto X; } /* close(dn) */ xalarm(40); /* was 5; sometimes missed carrier */ dh = open(dev,2); xalarm(0); if (dh<0) { er=(errno == 4? 3:6); goto X; } ioctl(TIOCGETP, ln, &stbuf); stbuf.sg_flags &= ~ECHO; xalarm(10); ioctl(TIOCSETP, dh, &stbuf); ioctl(TIOCHPCL, dh, (struct sgttyb *)NULL); xalarm(0); X: if (er) close(dn); if (fk!=(-1)) { kill(fk, SIGKILL); xalarm(10); while ((t=wait((int *)NULL))!=(-1) && t!=fk); xalarm(0); } return (er? -er:dh); } /* * wr: write to remote: 0 -> line. * ~. terminate * ~:'"); wrln(args[2]); wrln(";tee /dev/null <"); wrln(args[1]); wrln(";echo '~>'\n"); return; } else if (equal(args[0], "put")) { if (narg < 2) { prf("usage: ~%%put from [to]"); return; } if (narg < 3) args[2] = args[1]; if ((f = open(args[1], 0)) < 0) { prf("cannot open: %s", args[1]); return; } wrln("stty -echo;cat >"); wrln(args[2]); wrln(";stty echo\n"); xsleep(5); intr = 0; if (!nhup) signal(SIGINT, sig2); mode(2); rcount = 0; while(!intr && rdc(f) == 1) { rcount++; if (c == tkill || c == terase) wrln("\\"); if (wrc(ln) != 1) { xsleep(2); if (wrc(ln) != 1) { prf("character missed"); intr = 1; break; } } } signal(SIGINT, SIG_IGN); close(f); if (intr) { wrln("\n"); prf("stopped after %d bytes", rcount); } wrln("\004"); xsleep(5); mode(1); return; } prf("~%%%s unknown\n", args[0]); } equal(s1, s2) register char *s1, *s2; { while (*s1++ == *s2) if (*s2++ == '\0') return(1); return(0); } wrln(s) register char *s; { while (*s) write(ln, s++, 1); } /* * rd: read from remote: line -> 1 * catch: * ~>[>][:][file] * stuff from file... * ~> (ends diversion) */ rd() { int ds,slnt; char *p,*q,b[600]; p=b; ds=(-1); while (rdc(ln) == 1) { if (ds<0) slnt=0; if (!slnt) wrc(1); *p++=c; if (c!='\n') continue; q=p; p=b; if (b[0]!='~' || b[1]!='>') { if (*(q-2) == '\r') { q--; *(q-1)=(*q); } if (ds>=0) write(ds,b,q-b); continue; } if (ds>=0) close(ds); if (slnt) { write(1, b, q - b); write(1, CRLF, sizeof(CRLF)); } if (*(q-2) == '\r') q--; *(q-1)=0; slnt=0; q=b+2; if (*q == '>') q++; if (*q == ':') { slnt=1; q++; } if (*q == 0) { ds=(-1); continue; } if (b[2]!='>' || (ds=open(q,1))<0) ds=creat(q,0644); lseek(ds, (long)0, 2); if (ds<0) prf("Can't divert %s",b+1); } } struct {char lobyte; char hibyte;}; mode(f) { struct sgttyb stbuf; if (dout) return; ioctl(TIOCGETP, 0, &stbuf); tkill = stbuf.sg_kill; terase = stbuf.sg_erase; if (f == 0) { stbuf.sg_flags &= ~RAW; stbuf.sg_flags |= ECHO|CRMOD; } if (f == 1) { stbuf.sg_flags |= RAW; stbuf.sg_flags &= ECHO|CRMOD; } if (f == 2) { stbuf.sg_flags &= ~RAW; stbuf.sg_flags &= ~(ECHO|CRMOD); } ioctl(TIOCSETP, 0, &stbuf); } echo(s) char *s; { char *p; for (p=s;*p;p++); if (p>s) write(0,s,p-s); write(0,CRLF, sizeof(CRLF)); } prf(f, s) char *f; char *s; { fprintf(stderr, f, s); fprintf(stderr, CRLF); } exists(devname) char *devname; { if (access(devname, 0)==0) return(1); prf("%s does not exist", devname); return(0); }