# #include #include #include #include #include #include #include #include "task.h" #include "telnet.h" #define T3_LFLITOUT 0100 /* don't output CRLF for LF, not def'd in tty.h */ extern int dbg; tel_init() { register struct ucb *pucb; extern FILE *fcons(); extern int quit(); int fds; pucb = &ucb; pucb->u_state = ESTAB; pucb->u_rstate = NORMAL; pucb->u_rspecial = NORMAL; pucb->u_wstate = NORMAL; pucb->u_wspecial = NORMAL; pucb->u_sendm = EVERYC; pucb->u_echom = LOCAL; pucb->u_echongo = NORMAL; fds = dup(1); pucb->u_bwrite = fcons(fds, "w"); signal(SIGINT, quit); signal(SIGHUP, quit); signal(SIGTERM, quit); gtty(0, &pucb->u_otty); gtty(0, &pucb->u_tty); pucb->u_tty.sg_flags |= (RAW|ECHO|CRMOD); stty(0, &pucb->u_tty); tty_litout(1); } tty_litout( enter_mode ) { int cmds[2]; fflush(stdout); cmds[0] = (enter_mode?T_SET:T_CLEAR) | T_FLAG3 | T3_LFLITOUT; cmds[1] = -1; ttymod(1, cmds); } tel_exit() { register struct ucb *pucb; pucb = &ucb; stty(0, &pucb->u_otty); tty_litout(0); } /* gt_usr Read nch chars from user's terminal * When prompt char is encountered, go into * SPECIAL read mode and handle char following * prompt specially. * Tc_put puts telnet chars into an output * to net packet. */ gt_usr() { register int i, c; register struct ucb *pucb; int nch; pucb = &ucb; for (;;) { if (tk_resched || tk_rdy.tq_head != NULL) { ioctl (0, FIONREAD, &nch); if (nch == 0) { tk_yield (); continue; } } if ((c = getchar()) == EOF) { if (errno == EINTR) { continue; } printf("\r\nLocal terminal i/o error %d\r\n", errno); tcp_close(); pucb->u_state = CLOSING; pucb->u_rstate = BLOCK; return; } switch(pucb->u_rspecial) { case NORMAL: if (c == pucb->u_prompt) { pucb->u_rspecial = SPECIAL; printf("\n\rCmd:"); break; } if (c == '\r') c = '\n'; else if (c == '\n') { tc_put('\r'); tc_fput('\n'); if (pucb->u_echom == LOCAL) putchar('\r'); break; } else if (c == IAC) tc_put(IAC); if (pucb->u_sendm == EVERYC) tc_fput(c); else tc_put(c); break; case SPECIAL: pucb->u_rspecial = NORMAL; if (c == pucb->u_prompt) { if (pucb->u_sendm == EVERYC) tc_fput(c); else tc_put(c); break; } if (pucb->u_echom == REMOTE) putchar(c); putchar('\r'); putchar('\n'); switch(c) { case 'q': tel_exit (); exit (0); case 'c': tcp_close(); pucb->u_state = CLOSING; pucb->u_rstate = BLOCK; break; case 'p': stty (0, &pucb->u_otty); tty_litout(0); ptrace (0, getpid (), 0, 1); /* suspend */ tty_litout(1); stty (0, &pucb->u_tty); break; case 'n': pucb->u_sendm = NEWLINE; break; case 'e': pucb->u_sendm = EVERYC; break; case 'l': if (pucb->u_echom == LOCAL) break; echolocal(pucb); pucb->u_echongo = LECHOREQ; break; case 'r': if (pucb->u_echom == REMOTE) break; echoremote(pucb); pucb->u_echongo = RECHOREQ; break; case 'a': tc_put(IAC); tc_fput(AYT); break; case 'b': tc_put(IAC); tc_put(IP); tc_put(IAC); tc_put(DM); tcpurgent(); break; case 'i': printf("Intcpt:"); pucb->u_prompt = getchar(); printf("\n\r"); break; case '?': tty_litout(0); showcmds(); tty_litout(1); break; case 's': tty_litout(0); showstats(); tty_litout(1); break; case 'd': dbg = !dbg; tcpdebug (dbg); break; } break; default: printf("\r\nTelnet program BUG\r\n"); pucb->u_rspecial = NORMAL; break; } } } /* wr_usr manage chars coming from net and * going to user * Process received telnet special chars and * option negotiation. When wstate is URGENTM, * only process special chars. * All interrupts should be turned off * when in this routine - write to terminal * may block; an interrupt would cause * an error return from write with resulting * loss of chars to terminal */ wr_usr(buf, len, urg) char *buf; int len; int urg; { register struct ucb *pucb; register char *p; FILE *bwf; register int c; int nch; /* no. of outstanding read chars */ tc_ioff (); tm_off (); pucb = &ucb; bwf = pucb->u_bwrite; for (p = buf; p < &buf[len]; p++) { c = (*p & 0377); switch(pucb->u_wspecial) { case NORMAL: switch(c) { case '\r': putc(c, bwf); case IAC: pucb->u_wspecial = c; break; default: if (pucb->u_wstate != URGENTM) putc(c, bwf); break; } break; case '\r': if (c == '\0') c = '\r'; else if (c != '\r\n' && pucb->u_wstate != URGENTM) putc ('\r', bwf); if (pucb->u_wstate != URGENTM) putc(c, bwf); pucb->u_wspecial = NORMAL; break; case IAC: switch(c) { case IAC: if (pucb->u_wstate != URGENTM) putc(c, bwf); pucb->u_wspecial = NORMAL; break; case AO: tc_put(IAC); tc_put(DM); tcpurgent(); pucb->u_wspecial = NORMAL; break; case WILL: case WONT: case DO: case DONT: pucb->u_wspecial = c; break; /* Ignore IAC x */ default: pucb->u_wspecial = NORMAL; break; } break; case WILL: switch(c) { case OPTECHO: switch(pucb->u_echongo) { /* This host did not initiate echo negot - so respond */ case NORMAL: if (pucb->u_echom != REMOTE) echoremote(pucb); break; /* Rejecting my IAC DONT ECHO (illegit) */ case LECHOREQ: ttechoremote(pucb); break; } pucb->u_echongo = NORMAL; break; case OPTSPGA: /* suppress GA's */ tc_put(IAC); tc_put(DO); tc_fput(c); break; default: tc_put(IAC); tc_put(DONT); tc_fput(c); break; } pucb->u_wspecial = NORMAL; break; case WONT: switch(c) { case OPTECHO: switch(pucb->u_echongo) { /* This host did not initiate echo negot - so respond */ case NORMAL: if (pucb->u_echom != LOCAL) echolocal(pucb); break; /* Rejecting my IAC DO ECHO */ case RECHOREQ: ttecholocal(pucb); break; } pucb->u_echongo = NORMAL; break; } pucb->u_wspecial = NORMAL; break; case DO: tc_put(IAC); tc_put(WONT); tc_fput(c); pucb->u_wspecial = NORMAL; break; case DONT: pucb->u_wspecial = NORMAL; break; } } fflush(bwf); tm_on (); tc_ion (); ioctl (0, FIONREAD, &nch); if (nch > 0) { tk_yield (); } } echolocal(pucb) register struct ucb *pucb; { tc_put(IAC); tc_put(DONT); tc_fput(OPTECHO); pucb->u_echom = LOCAL; pucb->u_tty.sg_flags |= ECHO; stty(0, &pucb->u_tty); } ttecholocal(pucb) register struct ucb *pucb; { pucb->u_echom = LOCAL; pucb->u_tty.sg_flags |= ECHO; stty(0, &pucb->u_tty); } echoremote(pucb) register struct ucb *pucb; { tc_put(IAC); tc_put(DO); tc_fput(OPTECHO); pucb->u_echom = REMOTE; pucb->u_tty.sg_flags &= (~ECHO); stty(0, &pucb->u_tty); } ttechoremote(pucb) register struct ucb *pucb; { pucb->u_echom = REMOTE; pucb->u_tty.sg_flags &= (~ECHO); stty(0, &pucb->u_tty); } opn_usr () { printf ("Open\r\n"); } cls_usr () { printf ("Closed\r\n"); tel_exit (); exit (0); } tmo_usr () { extern int opening; if (opening != 3) { printf ("Host not responding\r\n"); tel_exit (); exit (0); } else { printf ("Host not responding; type "); showesc (ucb.u_prompt); printf ("q to exit\r\n"); } } fcls_usr () { tcp_close (); } spc_usr () { } quit() { tcp_close(); tk_yield(); tel_exit(); exit(0); }