/* 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 <conf.h>
#ifdef IAC_DEBUG
#define TELCMDS
#define TELOPTS
#endif
#include <arpa/telnet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <ncurses.h>
#include <panel.h>
#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);
}
syntax highlighted by Code2HTML, v. 0.9.1