/* * DCON * Connect terminal to Datakit network * Operation is line-at-a-time with remote echo. */ #include <stdio.h> #include <sys/param.h> #include <sys/types.h> #include <sgtty.h> #include <signal.h> #include <dk.h> #include <errno.h> #define CEOT 04 #define NULL 0 struct sgttyb locvec, savloc; struct tchars savechars; struct ltchars lsavechars; struct ltchars nlchars = { -1, -1, -1, -1, -1, -1 }; int rem; /* remote descriptor */ int rembit; /* 1<<rem; for select */ extern int dkp_ld, dt_ld, pk_ld, mesg_ld; int which_ld; char serv[32]; /* .login, .dcon, etc. */ int autologin; int noflush; fd_set rdfd_set; #define NSELFD (rem+1) #define LINSIZ 128 char *space = " \r\t\n"; int neofs = 0; /* die when greater than N */ int sigint(); extern dt_ld; /* TDK protocol line discipline */ extern int dkverbose ; char *mytty; extern char *strtok(); extern char *strchr(); extern char *strcpy(); extern char *strcat(); extern char *malloc(); extern FILE *scriptopen(); SIG_TYP savint, savquit; intcatch(){ /* catch interrupts, turn them into rubouts */ signal(SIGINT, intcatch); ioctl(rem, TIOCFLUSH, 0); write(rem, &savechars.t_intrc, 1); ioctl(rem, TIOCFLUSH, 0); ioctl(0, TIOCFLUSH, 0); rdfd_set.fds_bits[0] = 0; } quitcatch(){ /* catch quits, turn them into FS's */ ioctl(0, TIOCFLUSH, 0); signal(SIGQUIT, quitcatch); write(rem, &savechars.t_quitc, 1); } main(argc,argv) char **argv; { int i, traffic; char dialstr[64] ; int scriptlogin; FILE *script; extern char *getenv(); extern char *ttyname(); ioctl(0, TIOCGETC, &savechars); ioctl(0, TIOCGLTC, &lsavechars); ioctl(0, TIOCGETP, &savloc); locvec = savloc; which_ld = dkp_ld; strcpy(serv, ".dcon"); if(strcmp(argv[0], "tdcon") == 0 || getenv("TDCON") != NULL){ strcpy(serv, ".tdcon"); which_ld = dkp_ld; if(strcmp(argv[1], "-x") == 0){ argv[1][1] = 't'; } } traffic = 0; autologin = 1; scriptlogin = 0; for(i=1; i<argc && argv[i][0]=='-'; i++) { switch(argv[i][1]) { case 'f': noflush++; continue; case 's': scriptlogin = 1; case 'l': serv[0] = '\0'; autologin = 0; which_ld = dt_ld; continue; case 'x': /* deprecated */ strcpy(serv, ".dcon"); which_ld = dkp_ld; autologin = 1; break; case 't': which_ld = dkp_ld; strcpy(serv, ".tdcon"); break; case 'd': case 'b': which_ld = dkp_ld; break; case 'c': which_ld = dt_ld; break; case 'p': case 'g': which_ld = pk_ld; break; case 'v': dkverbose++ ; continue ; default: goto Usage; } } if (i>=argc){ Usage: /* don't use quit() because ioctl's aren't set up */ printf("usage: dcon [-lvs] hostname\n"); exit(1) ; } savint = signal(SIGINT, intcatch); savquit = signal(SIGQUIT, quitcatch); /* * request circuit to host. */ strcpy(dialstr, argv[i]) ; if(index(dialstr, '.')){ serv[0] = '\0'; } if(scriptlogin) { script = scriptopen(dialstr); if(script == NULL) quit("bad script"); } strcat(dialstr, serv); rem = tdkdial(dialstr, traffic); if (rem < 0) { char msg[64]; extern char *dkerror; sprintf(msg, "%s; call failed", dkerror); quit(msg); } if(dkverbose) printf("cut through\n"); rembit = 1<<rem; /* * turn on line discipline according to protocol. */ if(dkverbose) printf("pushing %d...\n", which_ld); if(dkproto(rem, which_ld) < 0) quit("can't turn on datakit protocol"); if (autologin){ if (tdklogin(rem) < 0) quit("can't log in") ; if(dkverbose) printf("logged in\n"); } else if(scriptlogin) { if (dkscript(rem,script) < 0) quit("can't log in") ; if(dkverbose) fprintf(stderr,"logged in\n"); } if(strcmp(serv, ".tdcon") == 0){ dotdcon(rem); if(dkverbose) printf("set terminal\n"); } locvec.sg_flags &= ~(CRMOD|ECHO|XTABS); locvec.sg_flags |= CBREAK; ioctl(0, TIOCSETP, &locvec); ioctl(0, TIOCSLTC, &nlchars); /* * main loop. */ ioctl(rem, DIOCSTREAM, (char *)0); do; while(scan() != -1); quit("select failed"); /*NOTREACHED*/ } scan() { extern errno; Loop: rdfd_set.fds_bits[0] = 1|(1<<rem); if(select(NSELFD, &rdfd_set, (fd_set *)0, 2000) == -1) if(errno == EINTR) goto Loop; else return -1; if(rdfd_set.fds_bits[0] == 0) /* timeout */ goto Loop; if(rdfd_set.fds_bits[0] & 1) keyboard(); if(rdfd_set.fds_bits[0] & rembit) remote(); return 0; } quit(s) char *s; { printf("dcon: %s\n", s); ioctl(0, TIOCSETP, &savloc); ioctl(0, TIOCSLTC, &lsavechars); signal(SIGINT, SIG_DFL); if (noflush==0) { ioctl(rem, TIOCFLUSH, 0); savloc.sg_ispeed = savloc.sg_ospeed = 0; /* hangup */ ioctl(rem, TIOCSETP, &savloc); } close(rem); exit(strcmp(s, "eof")); } /* * Scan data from keyboard, looking for escape lines. */ keyboard() { register c; register cc; register char *bp; register char *be, *obp; char buf[1024]; static char line[128]; static char *linep = &line[0]; static col = 0; long time(); static long timev[2]; cc = read(0, buf, sizeof buf); if(cc <0){ if(errno == EINTR) return; } if(cc <= 0) quit("read error on file descriptor 0"); be = buf+cc; bp = obp = buf; while(bp < be) { c = *bp++; if (col==0 && c=='~') { *linep++ = c; col = 1; locvec.sg_flags |= savloc.sg_flags&(CRMOD|ECHO); ioctl(0, TIOCSETP, &locvec); write(1, linep-1, 1); continue; } col++; if (c=='\r') c = '\n'; if (linep>line) { *linep++ = c; if (c==savloc.sg_kill) write(1, "\n", 1); if (c==savloc.sg_erase) linep -= 2; if (c==savloc.sg_kill || linep<=line) { linep = line; locvec.sg_flags &= ~(CRMOD|ECHO); ioctl(0, TIOCSETP, &locvec); col = 0; obp = bp; } } if (c=='\n') { col = 0; if (linep > line) { *linep = '\0'; if (escape(line+1, linep)) write(rem, line+1, linep-line-1); obp = bp; linep = line; locvec.sg_flags &= ~(CRMOD|ECHO); ioctl(0, TIOCSETP, &locvec); } } } if (bp>obp && linep==line) write(rem, obp, bp-obp); } /* * Send data from remote machine to standard output (trivial) */ remote(){ char buf[1024]; register n; n = read(rem, buf, sizeof buf); if(n < 0 && errno == EINTR) return; if(n <= 0){ if(dkverbose) printf("EOF %d\r\n", neofs); if(neofs++ > 4){ quit("Eof\r"); } return; } neofs = 0; write(1, buf, n); } escape(line, end) register char *line; { int cc; switch(*line++) { case '!': cunix(line); return(0); case '.': case CEOT: quit("eof"); case 'b': ioctl(rem, TIOCSBRK, 0); return(0); default: return(1); } } cunix(prog) char *prog; { register int upid; int retcode; if ((upid = fork()) == 0) { signal(SIGINT, savint); signal(SIGQUIT, savquit); ioctl(0, TIOCSETN, &savloc); ioctl(0, TIOCSLTC, &lsavechars); if (*prog == '\n') execl("/bin/sh", "sh", "-i", 0); else execl("/bin/sh","sh","-c",prog,0); exit(0100); } if (upid < 0) { printf("can't fork\n"); } else { while((wait(&retcode) !=upid)) ; } signal(SIGINT, intcatch); signal(SIGQUIT, quitcatch); ioctl(0, TIOCSETN, &locvec); ioctl(0, TIOCSLTC, &nlchars); printf("!!\n"); } int tfd; dotdcon(fd) { char *p, *getenv(); char buf[3000]; char c; tfd = fd; if((p = getenv("TERM")) != NULL && strlen(p) < (sizeof(buf) - 20)){ sprintf(buf, "TERM=%s", p); tsend("env", buf); } qsend("erase", savloc.sg_erase, '\b'); qsend("kill", savloc.sg_kill, '@'); qsend("intrc", savechars.t_intrc, '\177'); qsend("quitc", savechars.t_quitc, '\034'); qsend("startc", savechars.t_startc, 'q' & 037); qsend("stopc", savechars.t_stopc, 's' & 037); qsend("eofc", savechars.t_eofc, '\004'); qsend("brkc", savechars.t_brkc, '\377'); if(savloc.sg_flags & XTABS) tsend("XTABS", "yes"); if((savloc.sg_flags & CRMOD) == 0) tsend("CRMOD", "no"); if((savloc.sg_flags & ECHO) == 0) tsend("ECHO", "no"); if(savloc.sg_flags & CBREAK) tsend("CBREAK", "yes"); if(savloc.sg_flags & LCASE) tsend("LCASE", "yes"); tsend("env", "TDCON=YES"); if((p = getenv("TDKBAG")) && strlen(p) < (sizeof(buf) - 20)){ sprintf(buf, "TDKBAG=%s", p); tsend("env", buf); } /* TERMCAP is last because it might have messed up characters */ if((p = getenv("TERMCAP")) != NULL){ if(strlen(p) < (sizeof(buf) - 20)){ sprintf(buf, "TERMCAP=%s", p); tsend("env", buf); } } write(fd, "\n", 1); } tsend(a, b) char *a, *b; { char *p; p = (char *) malloc(strlen(a) + strlen(b) + 10); if(p == NULL) return; sprintf(p, "%s=%s\n", a, b); write(tfd, p, strlen(p)); if(dkverbose > 1) write(1, p, strlen(p)); free(p); } ctsend(s, c) char *s; char c; { char buf[50]; sprintf(buf, "%o", (int) c); tsend(s, buf); } qsend(s, c, wc) char *s; char c, wc; { if(c != wc) ctsend(s, c); } dkscript(rem,f) FILE *f; { char sline[LINSIZ]; while(fgets(sline,100,f)) { if(rget(rem,strtok(sline,space)) < 0) return(-1); if(fgets(sline,100,f)==0) return(-1); if(dkverbose) fprintf(stderr,"sending %s",sline); write(rem,sline,strlen(sline)); } return(1); } rget(rem,s) char *s; { int i; char buf[LINSIZ]; int brkchr = s[strlen(s)-1]; for(;;) { for(i=0; ; i++) { if(i>=LINSIZ-2) { buf[i] = 0; strcpy(buf,&buf[LINSIZ/2]); i = strlen(buf); } if(read(rem,&buf[i],1) <= 0) return(-1); buf[i] &= 0177; if(buf[i] == brkchr) break; } buf[i+1] = 0; while(i>=0 && buf[i] && !strchr(space,buf[i])) i--; i++; if(dkverbose) fprintf(stderr,"check '%s' vs '%s'\n",s,&buf[i]); if(strcmp(s,&buf[i]) == 0) return(1); } /*NOTREACHED*/ } FILE * scriptopen(s) char *s; { FILE *script = fopen(s, "r"); if(script == NULL) return(NULL); if(fgets(s,LINSIZ,script) == NULL) return(NULL); if(dkverbose) fprintf(stderr,"calling %s\n",s); strtok(s,"\n"); return script; }