Re: [CODE] Telnet code

From: Greg Buxton (gbuxton@maple.he.net)
Date: 01/15/03


#define TELOPTS
#define TELCMDS

#include <arpa/telnet.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "structs.h"
#include "db.h"                 /* to get buf, buf1, buf2 */
#include "comm.h"               /* to get SEND_TO_Q etc */
#include "telnet_support.h"
#include "utils.h"              /* to get STATE */

/* #define TELNET_DEBUG */

/* external functions */

void log(char *);
void raw_write_to_output(char *,DESCRIPTOR_DATA *,int);

/* file-local global vars */

static DESCRIPTOR_DATA *d;
static int naws_pos;
static unsigned char naws_buf[4];
unsigned char do_sga[]={ IAC, DO, TELOPT_SGA };
unsigned char do_naws[]={ IAC, DO, TELOPT_NAWS };
unsigned char timing_mark[]={ IAC, WILL, TELOPT_TM };

/* code */

void tell_telnet_supported_options(DESCRIPTOR_DATA *d) {
  if (d->telnetstate.sga==NOKNOWN)
    raw_write_to_output(do_sga,d,3);
  if (d->telnetstate.naws==NOKNOWN)
    raw_write_to_output(do_naws,d,3);
}

void process_naws(unsigned char c) {
  if (naws_pos<4) {
    naws_buf[naws_pos++]=c;
  }
}

void process_char(unsigned char cmd) {
  /* returns 0 if command is completed 1 otherwise */
  static cstate_t state=TEXT;
  static unsigned char lastcmd;
  static unsigned char subopt;
  char reply[5];
  switch(state) {
  case TEXT:
    if (cmd==IAC) state=GOT_IAC;
    return;
  case IN_NAWS:
    if (cmd==IAC) state=GOT_IAC;
    else process_naws(cmd);
    return;
  case PTCL:
#ifdef TELNET_DEBUG
    sprintf(buf,"TELNET: Received IAC %s %s",TELCMD(lastcmd),TELOPT(cmd));
    log(buf);
#endif
    switch(lastcmd) {
    case DO:
      switch(cmd) {
      case TELOPT_SGA:
        break;
      case TELOPT_NAWS:
        break;
      case TELOPT_ECHO:
        break;
      case TELOPT_TM:
        /* insert WILL TIMING MARK in output stream */
        raw_write_to_output(timing_mark,d,3);
#ifdef TELNET_DEBUG
        log("TELNET: Sent IAC WILL TIMING MARK");
#endif
        break;
      default: /* unknown option asked for */
        sprintf(reply,"%c%c%c",IAC,WONT,cmd);
        raw_write_to_output(reply,d,3);
#ifdef TELNET_DEBUG
        sprintf(buf,"TELNET: Sent IAC WONT %s",TELOPT(cmd));
        log(buf);
#endif
      }
      break;
    case DONT:
    case WILL:
    case WONT:
    }
    state=TEXT;
    return;
  case GOT_IAC:
    switch(cmd) {
    case DO:
    case DONT:
    case WILL:
    case WONT:
      state=PTCL;
      lastcmd=cmd;
      return;
    case SB:
      state=GOT_SB;
      break;
    case SE:
      if (subopt==TELOPT_NAWS) {
        d->telnetstate.winx=(naws_buf[0]<<8) + naws_buf[1];
        d->telnetstate.winy=(naws_buf[2]<<8) + naws_buf[3];
#ifdef TELNET_DEBUG
        sprintf(buf,"TELNET: Client window size=%dx%d",
                d->telnetstate.winx,
                d->telnetstate.winy);
        log(buf);
#endif
        if (STATE(d)==CON_PLAYING) {
          sprintf(buf,"Resize to
%dx%d\r\n",d->telnetstate.winx,d->telnetstate.winy);
          SEND_TO_Q(buf,d);
        }
      }
      state=TEXT;
    break;
    default:
#ifdef TELNET_DEBUG
      sprintf(buf,"TELNET: Received (and ignored) IAC %s",TELCMD(cmd));
      log(buf);
#endif
      state=TEXT;
      return;
    }
    break;

  case GOT_SB:
    switch(cmd) {

    case TELOPT_NAWS:
      state=IN_NAWS;
      subopt=TELOPT_NAWS;
#ifdef TELNET_DEBUG
      log("TELNET: Start negotiation of NAWS");
#endif
      naws_pos=0;
      break;
    default:
#ifdef TELNET_DEBUG
      sprintf(buf,"TELNET: Received (and ignored) IAC SB %s
(#%d)",TELOPT(cmd),cmd);
      log(buf);
#endif
      state=TEXT;
    }
    break;
  }
}

void telnet_parsing(unsigned char *data,int length, DESCRIPTOR_DATA *desc) {
  unsigned char *ptr=data;

  d=desc;
  for (ptr=data; ptr<data+length; ptr++) {
#ifdef TELNET_DEBUG
    fprintf(stderr,"<'%c'=#%d>\r\n",isprint(*ptr)? *ptr : '_',*ptr);
#endif
    process_char(*ptr);
  }
}

--
   +---------------------------------------------------------------+
   | FAQ: http://qsilver.queensu.ca/~fletchra/Circle/list-faq.html |
   | Archives: http://post.queensu.ca/listserv/wwwarch/circle.html |
   | Newbie List:  http://groups.yahoo.com/group/circle-newbies/   |
   +---------------------------------------------------------------+



This archive was generated by hypermail 2b30 : 06/26/03 PDT