/* telnet.c Routines for simple telnet negotiation */ #include "tcp.h" #ifdef TELNET #define TELOPTS #include <arpa/telnet.h> #else #include "telnet.h" #endif #ifdef SHORT_IAC #undef WILL #define WILL (-5) #undef WONT #define WONT (-4) #undef DO #define DO (-3) #undef DONT #define DONT (-2) #undef IAC #define IAC (-1) #endif /* SHORT_IAC */ int istelnet=0; /* Is this a telnet connection? */ static void print_opts(nego_str) char nego_str[]; { char *opt_str, opt_ind[24]; switch (nego_str[1]) { case WILL: opt_str="WILL"; break; case WONT: opt_str="WONT"; break; case DO: opt_str="DO"; break; case DONT: opt_str="DONT"; break; default: opt_str="??"; } if ( nego_str[2] < 22 ) strcpy(opt_ind, telopts[nego_str[2]]); else sprintf(opt_ind, "%d", nego_str[2]); fprintf(stderr, "%s %s\r\n", opt_str, opt_ind); return; } /* Routine to initialize the telnet options. The structure of the arguments is hardcoded, be sure to get it right. */ #define NORMAL 0 #define AT_IAC 1 #define AT_IAC_A 2 static int status=NORMAL; /* Current status of telnet negotiation */ static int OPTIONS[126]; void init_telnet(sockfd, will_echo) int will_echo; { int i; char sendstr[3]; istelnet=0; /* Initialize istelnet to not a telnet connection */ /* Send initializing negotiations */ status=NORMAL; sendstr[0]=IAC; sendstr[1]=WILL; sendstr[2]=TELOPT_SGA; write(sockfd, sendstr, 3); if ( netdebug ) { fprintf(stderr, "Sent: "); print_opts(sendstr); } for ( i=0; i<=126; ++i ) { switch (i) { case TELOPT_ECHO: if ( will_echo ) OPTIONS[i]=WILL; else OPTIONS[i]=WONT; break; case TELOPT_SGA: OPTIONS[i]=WILL; break; default: OPTIONS[i]=WONT; } } sendstr[1]=OPTIONS[TELOPT_ECHO]; sendstr[2]=TELOPT_ECHO; write(sockfd, sendstr, 3); if ( netdebug ) { fprintf(stderr, "Sent: "); print_opts(sendstr); } return; } /* Routine to perform telnet negotiation. It takes a Buf_Len structure and a socket file descriptor. It checks the buffer for telnet negotiation, negotiates, and returns a Buf_Len structure with the modified buffer */ struct Buf_Len modified; static char sent[2]={IAC}; /* The negotiation sent */ static char reply[2]={IAC}; /* The negotiation reply */ struct Buf_Len *negotiate(sockfd, recvd) int sockfd; struct Buf_Len *recvd; { int i, j=0; modified.len=0; for ( i=0; i<recvd->len; ++i ) { switch (status) { case AT_IAC: status=AT_IAC_A; sent[1]=recvd->buffer[i]; break; case AT_IAC_A: status=NORMAL; sent[2]=recvd->buffer[i]; if ( netdebug ) { fprintf(stderr, "Received: "); print_opts(sent); } if ( sent[1] == DO ) { reply[1]=OPTIONS[sent[2]]; reply[2]=sent[2]; write(sockfd, reply, 3); if ( netdebug ) { fprintf(stderr, "Sent: "); print_opts(reply); } } break; case NORMAL: switch (recvd->buffer[i]) { case IAC: if ( ! istelnet ) istelnet=1; status=AT_IAC; continue; default: status=NORMAL; modified.buffer[j++]=recvd->buffer[i]; ++modified.len; break; } break; default: fprintf(stderr,"status error: %d\r\n",status); break; } } return(&modified); }