/****************************************************************************** * This file is part of a software distribution, which is furnished under the * * terms of a license. Use of this software by any means is subject to this * * license and signifies the acceptance of the licensing terms stated * * therein. Please see the file LICENSE in the top-level directory of this * * software distribution for detailed copyright disclaimers and licensing * * terms. * ****************************************************************************** * Copryight (c) by Andreas S. Wetzel - All rights reserved. * ******************************************************************************/ /* $Id: vd_telopts.c,v 1.2 2001/03/19 14:54:06 mickey Exp $ */ #include #include #include /*** Globals ***/ extern u_char subopt_buf[]; extern u_char *sub_bufptr; extern u_char *sub_endptr; extern char *topts[]; extern u_short tel_option[]; extern u_short do_dont_response[]; extern u_short will_wont_response[]; extern VP vp; extern VD vd; /*** Code ***/ void dooption(u_char opcode) { int ok = 0; if(will_wont_response[opcode]) { --will_wont_response[opcode]; if(will_wont_response[opcode] && my_state_is_will(opcode)) --will_wont_response[opcode]; } if(!will_wont_response[opcode] && my_want_state_is_wont(opcode)) { if(TOPT_OK(opcode)) log(VLOG_DEBUG, "(REQ) DO %s", TOPT(opcode)); else log(VLOG_DEBUG, "(REQ) DO %d", opcode); /* In case we are willing to use */ /* the specified option, we set */ /* ok, and reply with WILL option. */ /* Otherwise we will always reject */ /* the request, and reply WONT opt */ switch(opcode) { case TELOPT_TTYPE: ok++; break; case TELOPT_BINARY: ok++; break; case TELOPT_ECHO: ok++; break; case TELOPT_SGA: ok++; break; default: break; } if(ok) { set_my_want_state_will(opcode); send_will(opcode, 1); } else { will_wont_response[opcode]++; send_wont(opcode, 1); } } else { if(TOPT_OK(opcode)) log(VLOG_DEBUG, "(ACK) DO %s", TOPT(opcode)); else log(VLOG_DEBUG, "(ACK) DO %d", opcode); } set_my_state_will(opcode); } void dontoption(u_char opcode) { if(will_wont_response[opcode]) { --will_wont_response[opcode]; if(will_wont_response[opcode] && my_state_is_wont(opcode)) --will_wont_response[opcode]; } if(!will_wont_response[opcode] && my_want_state_is_will(opcode)) { if(TOPT_OK(opcode)) log(VLOG_DEBUG, "(REQ) DONT %s", TOPT(opcode)); else log(VLOG_DEBUG, "(REQ) DONT %d", opcode); /* REMEMBER: It should always be o.k to turn off */ /* some set of options. */ switch(opcode) { case TELOPT_BINARY: /* The client wants */ /* us to do only 7 bits ... */ /* tse tse tse ... */ break; case TELOPT_ECHO: /* We are not willing to turn */ /* off our echo, but let the */ /* client think, we did so. */ break; default: break; } set_my_want_state_wont(opcode); if(my_state_is_will(opcode)) send_wont(opcode, 1); } else { if(TOPT_OK(opcode)) log(VLOG_DEBUG, "(ACK) DONT %s", TOPT(opcode)); else log(VLOG_DEBUG, "(ACK) DONT %d", opcode); } set_my_state_wont(opcode); } void willoption(u_char opcode) { int ok = 0; if(do_dont_response[opcode]) { --do_dont_response[opcode]; if(do_dont_response[opcode] && his_state_is_will(opcode)) --do_dont_response[opcode]; } if(!do_dont_response[opcode]) { if(his_want_state_is_wont(opcode)) { /* requests of client side */ if(TOPT_OK(opcode)) log(VLOG_DEBUG, "(REQ) WILL %s", TOPT(opcode)); else log(VLOG_DEBUG, "(REQ) WILL %d", opcode); switch(opcode) { case TELOPT_SGA: ok++; break; case TELOPT_BINARY: ok++; break; case TELOPT_TTYPE: ok++; break; default: break; } if(ok) { set_his_want_state_will(opcode); send_do(opcode, 1); } else { do_dont_response[opcode]++; send_dont(opcode, 1); } } else { /* confirmation of our own requests */ if(TOPT_OK(opcode)) log(VLOG_DEBUG, "(ACK) WILL %s", TOPT(opcode)); else log(VLOG_DEBUG, "(ACK) WILL %d", opcode); switch(opcode) { case TELOPT_ECHO: /* ARGH!! Client responded */ /* with WILL ECHO. Since we */ /* don't want the client to */ /* echo our chars, let us */ /* turn it off right away. */ send_dont(TELOPT_ECHO, 1); break; default: break; } } } set_his_state_will(opcode); } void wontoption(u_char opcode) { if(do_dont_response[opcode]) { --do_dont_response[opcode]; if(do_dont_response[opcode] && his_state_is_wont(opcode)) --do_dont_response[opcode]; } if(!do_dont_response[opcode]) { if(his_want_state_is_will(opcode)) { /* requests of client side */ if(TOPT_OK(opcode)) log(VLOG_DEBUG, "(REQ) WONT %s", TOPT(opcode)); else log(VLOG_DEBUG, "(REQ) WONT %d", opcode); switch(opcode) { case TELOPT_BINARY: break; default: break; } set_his_want_state_wont(opcode); if(his_state_is_will(opcode)) send_dont(opcode, 1); } else { /* confirmation of our own requests */ if(TOPT_OK(opcode)) log(VLOG_DEBUG, "(ACK) WONT %s", TOPT(opcode)); else log(VLOG_DEBUG, "(ACK) WONT %d", opcode); switch(opcode) { default: break; } } } set_his_state_wont(opcode); } void handle_suboption(void) { static char lasttype[128]; char tmp[128]; char *fuseltmp = &tmp[0]; u_short x; u_short y; u_short cmd; /* * This indeed IS --> STRAIGHTFORWARD! */ cmd = SUB_GET(); switch(cmd) { case TELOPT_NAWS: x = (0x100 * SUB_GET()); x += SUB_GET(); y = (0x100 * SUB_GET()); y += SUB_GET(); log(VLOG_INFO, "Reported screen size: %dx%d", x, y); sprintf(vd.env_cols, "COLUMNS=%d", x); putenv(vd.env_cols); sprintf(vd.env_lines, "LINES=%d", y); putenv(vd.env_lines); resize(); log(VLOG_INFO, "Changed screen size to %dx%d", x, y); break; case TELOPT_TTYPE: if((x = SUB_GET()) == TELQUAL_SEND) { /* * Terminal type? What terminal type? * We are cool, so we respond simply * with 'network' ;-) */ printf("%c%c%c%cnetwork%c%c", IAC, SB, TELOPT_TTYPE, TELQUAL_IS, IAC, SE); log(VLOG_DEBUG, "(TTYPE) Reporting terminal type network"); } else if(x == TELQUAL_IS) { while(!(SUB_EOF() || (y = SUB_GET()) == IAC)) { *fuseltmp++ = y; } *fuseltmp = '\0'; str_lower(tmp); log(VLOG_INFO, "Reported terminaltype is %s", tmp); if(check_termtype(tmp) == 1) { strcpy(vd.env_term, tmp); vp.emulation = (char *)&vd.env_term; vd.emu_ok = 0xff; } else if(strcmp(lasttype, tmp)) { strcpy(lasttype, tmp); printf("%c%c%c%c%c%c", IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE); } else { strcpy(vd.env_term, FALLBACK_TTYPE); vp.emulation = (char *)&vd.env_term; vd.emu_ok = 0xff; printf("\r\nUnable to negotiate common terminaltype for this telnet session.\r\n"); printf("Falling back to %s\r\n", FALLBACK_TTYPE); log(VLOG_INFO, "Could not negotiate common terminal type."); log(VLOG_INFO, "Falling back to %s", FALLBACK_TTYPE); } } else { log(VLOG_INFO, "(TTYPE) Huh?"); } break; default: log(VLOG_INFO, "Unknown sub command: $%02x", cmd); break; } }