/* Copyright (c) 2002 * Marko Boomstra (m.boomstra@chello.nl). All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #ifdef IAC_DEBUG #define TELCMDS #define TELOPTS #endif #include #include #include #include #include #include #include #include #include "mudix.h" #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } void send_telnet(unsigned char command, unsigned char option) { unsigned char iac_buf[3]; #ifdef IAC_DEBUG wprintw(wMain, "SEND: %6s - %s\n", TELCMD(command), telopts[option]); #endif iac_buf[0] = IAC; iac_buf[1] = command; iac_buf[2] = option; write(settings->sock, iac_buf, 3); /* bypassing normal send */ } void send_data_telnet(unsigned char *data, int len) { #ifdef IAC_DEBUG wprintw(wMain, "SEND: %d - ", len); { unsigned char *pData = data; int len2 = len; while (len2--) { if (isprint(*pData)) waddch(wMain, *pData); else wprintw(wMain, "(%02X)", *pData); pData++; } waddch(wMain, '\n'); } #endif write(settings->sock, data, len); /* bypassing normal send */ } int telnet_command(unsigned char *pIac) { unsigned char command = pIac[1]; unsigned char option = pIac[2]; unsigned char temp[128], *cp; switch (command) { case DONT: /* you are not to use option */ send_telnet(WONT, option); break; case DO: /* please, you use option */ switch (option) { default: send_telnet(WONT, option); break; case TELOPT_TTYPE: send_telnet(WILL, option); break; case TELOPT_NEW_ENVIRON: send_telnet(WILL, option); break; case TELOPT_NAWS: send_telnet(WILL, option); break; case TELOPT_TSPEED: send_telnet(WILL, option); break; case TELOPT_ECHO: fEchoIn = TRUE; fEchoOut = TRUE; send_telnet(WILL, option); break; } break; case WONT: /* I won't use option */ switch (option) { default: break; case TELOPT_ECHO: fEchoIn = TRUE; fEchoOut = TRUE; break; } break; case WILL: /* I will use option */ switch (option) { default: break; case TELOPT_ECHO: if (settings->port == 23) /* telnet */ fEchoIn = TRUE; /* see what we type */ else fEchoIn = FALSE; fEchoOut = FALSE; break; } break; case SB: /* interpret as subnegotiation */ switch (option) { default: break; case TELOPT_TTYPE: sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, option, TELQUAL_IS, termname(), IAC, SE); send_data_telnet(temp, strlen((char *)temp+4)+4); break; case TELOPT_NEW_ENVIRON: sprintf((char *)temp, "%c%c%c%c%c%c", IAC, SB, option, TELQUAL_IS, IAC, SE); send_data_telnet(temp, strlen((char *)temp+4)+4); break; case TELOPT_NAWS: cp = temp; *cp++ = IAC; *cp++ = SB; *cp++ = option; PUTSHORT(cp, LEN_COL); PUTSHORT(cp, LEN_ROW); *cp++ = IAC; *cp++ = SE; send_data_telnet(temp, cp-temp); break; case TELOPT_TSPEED: { long speed = baudrate(); sprintf((char *)temp, "%c%c%c%c%ld,%ld%c%c", IAC, SB, option, TELQUAL_IS, speed, speed, IAC, SE); send_data_telnet(temp, strlen((char *)temp+4)+4); break; } } { /* go to the end of the buffer (IAC SE) */ unsigned char *ppIac = pIac; while (!(*ppIac == IAC && *(ppIac+1) == SE)) { if (*ppIac == IAC && *(ppIac+1) == IAC) ppIac++; #ifdef IAC_DEBUG wprintw(wMain, "(%02X)", *ppIac); #endif ppIac++; } #ifdef IAC_DEBUG wprintw(wMain, "\n"); #endif return ppIac-pIac+2; /* +2 since we didn't count IAC SE yet */ } case GA: /* you may reverse the line */ case EL: /* erase the current line */ case EC: /* erase the current character */ case AYT: /* are you there */ case AO: /* abort output--but let prog finish */ case IP: /* interrupt process--permanently */ case BREAK: /* break */ case DM: /* data mark--for connect. cleaning */ case NOP: /* nop */ case SE: /* end sub negotiation */ case EOR: /* end of record (transparent mode) */ case ABORT: /* Abort process */ case SUSP: /* Suspend process */ case xEOF: /* End of file: EOF is already used... */ default: return 2; } return 3; /* normal size of an IAC */ } int check_iac(unsigned char *pIac) { if (*pIac != IAC) return 1; #ifdef IAC_DEBUG wprintw(wMain, "RECV: %6s - %s\n", TELCMD(pIac[1]), telopts[pIac[2]]); #endif return telnet_command(pIac); }