minix/commands/telnetd/telnet.c

264 lines
4.2 KiB
C
Raw Normal View History

2005-04-21 16:53:53 +02:00
/*
* TNET A server program for MINIX which implements the TCP/IP
* suite of networking protocols. It is based on the
* TCP/IP code written by Phil Karn et al, as found in
* his NET package for Packet Radio communications.
*
* This module handles telnet option processing.
*
* Author: Michael Temari, <temari@temari.ae.ge.com> 01/13/93
*
*/
#include <sys/types.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include "telnetd.h"
#include "telnet.h"
#include <stdio.h>
#define IN_DATA 0
#define IN_CR 1
#define IN_IAC 2
#define IN_IAC2 3
_PROTOTYPE(static void dowill, (int c));
_PROTOTYPE(static void dowont, (int c));
_PROTOTYPE(static void dodo, (int c));
_PROTOTYPE(static void dodont, (int c));
_PROTOTYPE(static void respond, (int ack, int option));
#define LASTTELOPT TELOPT_SGA
static int TelROpts[LASTTELOPT+1];
static int TelLOpts[LASTTELOPT+1];
static int telfdout;
void tel_init()
{
int i;
for(i = 0; i <= LASTTELOPT; i++) {
TelROpts[i] = 0;
TelLOpts[i] = 0;
}
}
void telopt(fdout, what, option)
int fdout;
int what;
int option;
{
char buf[3];
int len;
buf[0] = IAC;
buf[1] = what;
buf[2] = option;
len = 0;
switch(what) {
case DO:
if(option <= LASTTELOPT) {
TelROpts[option] = 1;
len = 3;
}
break;
case DONT:
if(option <= LASTTELOPT) {
TelROpts[option] = 1;
len = 3;
}
break;
case WILL:
if(option <= LASTTELOPT) {
TelLOpts[option] = 1;
len = 3;
}
break;
case WONT:
if(option <= LASTTELOPT) {
TelLOpts[option] = 1;
len = 3;
}
break;
}
if(len > 0)
(void) write(fdout, buf, len);
}
int tel_in(fdout, telout, buffer, len)
int fdout;
int telout;
char *buffer;
int len;
{
static int InState = IN_DATA;
static int ThisOpt = 0;
char *p;
char *p2;
int size;
int c;
telfdout = telout;
p = p2 = buffer;
size = 0;
while(len > 0) {
c = (unsigned char)*p++; len--;
switch(InState) {
case IN_CR:
InState = IN_DATA;
if(c == 0 || c == '\n')
break;
/* fall through */
case IN_DATA:
if(c == IAC) {
InState = IN_IAC;
break;
}
*p2++ = c; size++;
if(c == '\r') InState = IN_CR;
break;
case IN_IAC:
switch(c) {
case IAC:
*p2++ = c; size++;
InState = IN_DATA;
break;
case WILL:
case WONT:
case DO:
case DONT:
InState = IN_IAC2;
ThisOpt = c;
break;
case EOR:
case SE:
case NOP:
case BREAK:
case IP:
case AO:
case AYT:
case EC:
case EL:
case GA:
case SB:
break;
default:
break;
}
break;
case IN_IAC2:
if(size > 0) {
write(fdout, buffer, size);
p2 = buffer;
size = 0;
}
InState = IN_DATA;
switch(ThisOpt) {
case WILL: dowill(c); break;
case WONT: dowont(c); break;
case DO: dodo(c); break;
case DONT: dodont(c); break;
}
break;
}
}
if(size > 0)
write(fdout, buffer, size);
}
int tel_out(fdout, buf, size)
int fdout;
char *buf;
int size;
{
char *p;
int got_iac, len;
p = buf;
while(size > 0) {
buf = p;
got_iac = 0;
if((p = (char *)memchr(buf, IAC, size)) != (char *)NULL) {
got_iac = 1;
p++;
} else
p = buf + size;
len = p - buf;
if(len > 0)
(void) write(fdout, buf, len);
if(got_iac)
(void) write(fdout, p - 1, 1);
size = size - len;
}
}
static void dowill(c)
int c;
{
int ack;
switch(c) {
case TELOPT_BINARY:
case TELOPT_ECHO:
case TELOPT_SGA:
if(TelROpts[c] == 1)
return;
TelROpts[c] = 1;
ack = DO;
break;
default:
ack = DONT;
}
respond(ack, c);
}
static void dowont(c)
int c;
{
if(c <= LASTTELOPT) {
if(TelROpts[c] == 0)
return;
TelROpts[c] = 0;
}
respond(DONT, c);
}
static void dodo(c)
int c;
{
int ack;
switch(c) {
default:
ack = WONT;
}
respond(ack, c);
}
static void dodont(c)
int c;
{
if(c <= LASTTELOPT) {
if(TelLOpts[c] == 0)
return;
TelLOpts[c] = 0;
}
respond(WONT, c);
}
static void respond(ack, option)
int ack, option;
{
unsigned char c[3];
c[0] = IAC;
c[1] = ack;
c[2] = option;
/* write(telfdout, c, 3); */
}