Metropoli BBS
VIEWER: tel.c MODE: TEXT (CP437)
//#define DEBUG
//****************************************************************************}
//program TelnetClient                                                        }
#define VeRsIoN "1.04"
//----------------------------------------------------------------------------}
// date of origin   :  15.12. 1996                                            }
//define LaSt_DaTe "6. Jan 1996"
// last change time :  17.30                                                  }
// Author :  Petr Jaklin , V Závetrí 1678, Teplice 415 01                     }
//----------------------------------------------------------------------------}
// Open telnet session to specified host                                      }
// not supported: scr attributes
// support for TERMINAL TYPE disabled: NW xconsole use ANSI term as Xterm ...
// v1.02: displayInputCursor
// v1.03: new ESC sequences for XCONSOLE compatibility (e[?2J is supposed to
//        be CLRSCR; at e[12h I switch from 0-based cursor to 1-based one)
// v1.04: TermType VT100
//****************************************************************************}
#include <arpa/inet.h>
#include <conio.h>
#include <errno.h>
#include <io.h>
#include <netinet/in.h>
#include <nwsemaph.h>
#include <process.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
//---------------------------------------------------------------------------}
/*    DESCRIPTION FILE
copyright	"Copyright (C) 1996, Petr Jaklin, 3NET s.r.o."
version		VeRsIoN
description	"Telnet client"
screenname	"Telnet"
threadname	"telnet"
output		f:\tc\tel
input		tel g:\progbase\c386\novi\prelude
stack		8192
type		0
debug
multiple
import		__WATCOM_Prelude
import          @g:\progbase\c386\novi\clib.imp
import		@g:\progbase\c386\novi\socklib.imp
#import		@f:\tc\h\server4.imp
module		clib, tcpip
*/
//---------------------------------------------------------------------------
// TYPEs
typedef enum {
      TSdata,
      TSiac,
      TSdo,
      TSdn,
      TSwl,
      TSwn,
      TSsub,
      TSsubOpt,
      TSsubIac
      }  TelnetStatus;
typedef enum {
      ASdata,
      ASesc,
      ASprefix,
      AScharSet,
      ASnum,
      ASchar,
      AScharEnd,
      ASsepar,
      }  ANSIStatus;
char           protErr[]="PROTO_ERROR: ";
char           eraseLine[80] = {
                    "                                        "
                    "                                        "};

//---------------------------------------------------------------------------
// variables

TelnetStatus   telStat=TSdata;        // telnet automat status
ANSIStatus     ansiStat=ASdata;       // ansi automat status
char          *myname;                // prg name string
char           host[80];              // name of host to telnet
char           iobuf[4097];           // reading buffer

struct sockaddr_in server_sockaddr;   // IP target address
int            sock;                  // IP socket

int            readData=FALSE;        // do read flag
int            endTel=FALSE;          // main quit flag
char           oline[120];            // keyboard buffer
LONG           wrtSem;                // IP write semaphore (I dont know
                                      // if 'write' is reentrant
LONG           readID;                // read thread ID
char          *CMD[] =                // telnet cmd names for 'logging'
      { "End of subnegotiation",
        "No operation",
        "Data Mark",
        "Break",
        "Interrupt process",
        "Abort output",
        "Are You there ?",
        "Erase charecter",
        "Erase line",
        "Go ahead",
        "SubNegotiation",
        "WILL",
        "WON'T",
        "DO",
        "DON'T",
        "IAC"
      };
char           strOpt[20];            // buffer for telnet cmd logging
#define        SbMax 50
char           sbC[SbMax];            // sub negotiation buffer
int            sbNum;                 // counter of sbC buffer
int            remEcho=FALSE;         // echo option status
int            isANSI=TRUE;           // is ANSI code supported
#define        AsMaxNum 20
BYTE           asNum[AsMaxNum];       // array of ansi arguments
int            asNums=0;              // # of valid asNum[]
int            asPrefix=0;            // ESC prefix  [  ... 1 , (  ... 2
                                      //             )  ... 3 , [= ... 4
                                      //             [? ... 5 ,    ... 0
int            charSet=0;             // 0=ASCII, 1=graphics
int            asCx=0;                // cursor saving vars (for ANSI e[s)
int            asCy=0;
int            xy0=0;                 // cursor home address (0,0) is default
int            displayInputCursor=FALSE; // cursor state
int            setCursor=FALSE;       // inter-thread flag

#ifdef DEBUG
int            logIt=TRUE;            // log traffic into sys:system\tel.log
int            ctrl=TRUE;             // do log control too
#else
int            logIt=FALSE;            // log traffic into sys:system\tel.log
int            ctrl=FALSE;           // do log control too
#endif
FILE          *logFile=NULL;             // logfile handle

//---------------------------------------------------------------------------
void ecprintf ( char  *format,
                ...)
// printf + if control echo to log
//---------------------------------------------------------------------------
{
  va_list      params;

  va_start(params,format);
  vprintf(format,params);
  va_end(params);
  if (ctrl) {
    va_start(params,format);
    vfprintf(logFile,format,params);
    va_end(params);
    }
} // ecprintf

//---------------------------------------------------------------------------
char * Option ( int opt )
//---------------------------------------------------------------------------
{
  switch (opt) {
    case   0 : return("BinaryTransmission");
    case   1 : return("ECHO");
    case   3 : return("SuppresGA");
    case   5 : return("Status");
    case  17 : return("Extended ASCII");
    case  24 : return("Terminal Type");
    default  : sprintf(strOpt,"Unknown-%02X",opt);
               return(strOpt);
    }
} // option

//---------------------------------------------------------------------------
int WriteData ( BYTE  *buff,
                int    size)
//---------------------------------------------------------------------------
{
  int          wr;
  char         str[100];
  int          i;

  WaitOnLocalSemaphore(wrtSem);
  if (logIt) {
    for (i=0;i<size;i++)
      if (buff[i])
        str[i]=buff[i];
      else
        str[i]=255;
    str[size]=0;
    fprintf(logFile,str);
    }
  wr=write(sock,buff,size);
  if (wr==-1) {
    perror("write");
    exit(1);
    }
  SignalLocalSemaphore(wrtSem);
  return(wr);
} // writedata

//---------------------------------------------------------------------------
void WriteCtrl ( int     cmd,
                 int     option)
//---------------------------------------------------------------------------
{
  char         buff[3];

  buff[0]=255;
  buff[1]=cmd;
  buff[2]=option;
  if (ctrl)
    ecprintf("WriteCTRL(%s,%s)\r\n",CMD[cmd-240],Option(option));
  WriteData(buff,3);
} // writectrl

//---------------------------------------------------------------------------
void EraseLine ( int   from )
// erases line from 'from' to end of line
//---------------------------------------------------------------------------
{
  int          x,y;

  eraseLine[80-from]=0;
  x=wherex();
  y=wherey();
  gotoxy(from,y);
  printf(eraseLine);
  gotoxy(x,y);
  eraseLine[80-from]=' ';
} // eraseline

//---------------------------------------------------------------------------
void Mode ( int mode )
//---------------------------------------------------------------------------
{
  mode=mode;
  ecprintf("ANSI_MODE: Ignored\r\n");
} // mode

//---------------------------------------------------------------------------
void ScrAttr ( int attr )
// not supported
//---------------------------------------------------------------------------
{
  switch (attr) {
    case  0 : // normal (white on black)
              break;
    case  1 : // bold
              break;
    case  4 : // underline
              break;
    case  5 : // blink
              break;
    case  7 : // reverse
              break;
    case  8 : // no display (foreg==backg)
              break;
    // foregrounds
    case 30 : // black
              break;
    case 31 : // red
              break;
    case 32 : // green
              break;
    case 33 : // yellow
              break;
    case 34 : // blue
              break;
    case 35 : // magenta
              break;
    case 36 : // cyan
              break;
    case 37 : // white
              break;
    // backgrounds
    case 40 : // black
              break;
    case 41 : // red
              break;
    case 42 : // green
              break;
    case 43 : // yellow
              break;
    case 44 : // blue
              break;
    case 45 : // magenta
              break;
    case 46 : // cyan
              break;
    case 47 : // white
              break;
    default : ecprintf("ANSI_SCR_MODE: Unknown attribute (%d)\r\n",attr);
    }
} // scrattr

//---------------------------------------------------------------------------
void InvalidAnsi ( char   c )
//---------------------------------------------------------------------------
{
  int          i;

  ecprintf("INVALID_ANSI:0x1b[");
  for (i=0;i<asNums;i++) {
  ecprintf("%d",asNum[i]);
  if (i<(asNum-1))
    ecprintf(";");
    }
  ecprintf("%c\r\n",c);
} // InvalidAnsi

//---------------------------------------------------------------------------
void CompleteAnsi ( char    c )
//---------------------------------------------------------------------------
{
  char         str[10];
  int          i;

  switch (asPrefix) {
    case 0 : // none
             switch (c) {
               case 'A' : gotoxy(wherex(),wherey()-1);
                          break;
               case 'B' : gotoxy(wherex(),wherey()+1);
                          break;
               case 'C' : gotoxy(wherex()+1,wherey());
                          break;
               case 'D' : gotoxy(wherex()-1,wherey());
                          break;
               case 'F' : charSet=1;
                          break;
               case 'G' : charSet=0;
                          break;
               case 'H' : gotoxy(0,0);
                          break;
               case '(' : charSet=0;
                          break;
               case ')' : charSet=1;
                          break;
               case '=' : ;
               case '>' : ;
               case 'c' : ; // reset terminal
                          break;
               default  : InvalidAnsi(c);
               }
             break;
    case 1 : // '['
             switch (c) {
               case 'f' : ;
               case 'H' : if (asNums==1)
                            gotoxy(0,asNum[0]-xy0);
                          else if (asNums==2)
                            gotoxy(asNum[1]-xy0,asNum[0]-xy0);
                          else if (asNums==0)
                            gotoxy(0,0);
                          else
                            InvalidAnsi(c);
                          break;
               case 'A' : if (asNums==1)
                            gotoxy(wherex(),wherey()-asNum[0]);
                          else
                            InvalidAnsi(c);
                          break;
               case 'B' : if (asNums==1)
                            gotoxy(wherex(),wherey()+asNum[0]);
                          else
                            InvalidAnsi(c);
                          break;
               case 'C' : if (asNums==1)
                            gotoxy(wherex()+asNum[0],wherey());
                          else
                            InvalidAnsi(c);
                          break;
               case 'D' : if (asNums==1)
                            gotoxy(wherex()-asNum[0],wherey());
                          else
                            InvalidAnsi(c);
                          break;
               case 'J' : if ((asNums==1) && (asNum[0]==2)) {
                            clrscr();
// cannot be here: waits for kbd free !?!          DisplayInputCursor();
                            displayInputCursor=TRUE;
                            setCursor=TRUE;
                            }
                          else
                            InvalidAnsi(c);
                          break;
               case 'K' : if (asNums==1) {
                            if (asNum[0]==0)
                              EraseLine(wherex());
                            else if (asNum[0]==2)
                              EraseLine(0);
                            else
                              InvalidAnsi(c);
                            }
                          else
                            InvalidAnsi(c);
                          break;
               case 'h' : if ((asNums==1) && (asNum[0]==12))
                            xy0=1;
                          else
                            InvalidAnsi(c);
                          break;
               case 'm' : for (i=0;i<asNums;i++)
                            ScrAttr(asNum[i]);
                          break;
               case 'n' : if ((asNums==1) && (asNum[0]==6)) {
                            sprintf(str,"\x1b[%d;%dR",wherey()+xy0,
                                                      wherex()+xy0);
                            WriteData(str,strlen(str));
                            }
                          else
                            InvalidAnsi(c);
                          break;
               case 'p' : ecprintf("ANSI_KEY_REMAP: Not Supported\r\n");
                          break;
               case 's' : if ((asNums==1) && (asNum[0]==0)) {
                            asCx=wherex();
                            asCy=wherey();
                            }
                          else
                            InvalidAnsi(c);
                          break;
               case 'u' : if ((asNums==1) && (asNum[0]==0))
                            gotoxy(asCx,asCy);
                          else
                            InvalidAnsi(c);
                          break;
               default  : InvalidAnsi(c);
               } //switch letter [
             break;
    case 2 : // '('
             ;
    case 3 : // ')'
             ;
             break; // fixed now: standerd is ASCII, alternate is line draw
    case 4 : // '[='
             if (asNums!=1)
               InvalidAnsi(c);
             else if ((c=='h') || (c=='l'))
               Mode(asNum[0]);
             else
               InvalidAnsi(c);
             break;
    case 5 : // '[?'
             switch (c) {
               case 'J' : if ((asNums==1) && (asNum[0]==2)) {
                            clrscr();
// cannot be here: waits for kbd free !?!          DisplayInputCursor();
                            displayInputCursor=TRUE;
                            setCursor=TRUE;
                            }
                          else
                            InvalidAnsi(c);
                          break;
               case 'h' : if (asNums==1)
                            switch(asNum[0]) {
                              case 25 : ;
                              case 50 : setCursor=TRUE;
                                        displayInputCursor=TRUE;
                                        break;
                              }
                          else
                            InvalidAnsi(c);
                          break;
               case 'l' : if (asNums==1)
                            switch(asNum[0]) {
                              case 25 : ;
                              case 50 : setCursor=TRUE;
                                        displayInputCursor=FALSE;
                                        break;
                              }
                          else
                            InvalidAnsi(c);
                          break;
               }
             break;
    }
  ansiStat=ASdata;
} // completeansi

//---------------------------------------------------------------------------
void DataDisplay ( char  c )
// pure data automat engine (ANSI)
//---------------------------------------------------------------------------
{
  if (isANSI)
    switch (ansiStat) {
      case ASdata    : if (c==27) {
                         asPrefix=0;
                         ansiStat=ASesc;
                         }
                       else if (c==15)
                         charSet=0;          // shift in
                       else if (c==14)
                         charSet=1;          // shift out
                       else {
                         if (charSet==1)
                           switch (c) {
                             case 0x61 : c='░';break;
                             case 0x6a : c='┘';break;
                             case 0x6b : c='┐';break;
                             case 0x6c : c='┌';break;
                             case 0x6d : c='└';break;
                             case 0x71 : c='─';break;
                             case 0x74 : c='├';break;
                             case 0x75 : c='┤';break;
                             case 0x76 : c='┴';break;
                             case 0x77 : c='┬';break;
                             case 0x78 : c='│';break;
                             }
                         printf("%c",c);
                         }
                       break;
      case ASesc     : if (c=='[') {
                         asPrefix=1;
                         ansiStat=ASprefix;
                         }
                       else if (c=='(') {
                         asPrefix=2;
                         ansiStat=AScharSet;
                         }
                       else if (c==')') {
                         asPrefix=3;
                         ansiStat=AScharSet;
                         }
                       else
                         CompleteAnsi(c);
                       break;
      case AScharSet : CompleteAnsi(c);
                       break;
      case ASprefix  : if (c=='=') {
                         if (asPrefix==1)
                           asPrefix=4;
                         else
                           CompleteAnsi(c);
                         }
                       else if (c=='?') {
                         if (asPrefix==1)
                           asPrefix=5;
                         else
                           CompleteAnsi(c);
                         }
                       else if ((c>='0') && (c<='9')) {
                         asNum[0]=c-0x30;
                         asNums=1;
                         ansiStat=ASnum;
                         }
                       else if (c==';') {
                         asNum[0]=0;
                         asNums=1;
                         ansiStat=ASsepar;
                         }
                       else if (c==34) { // "
                         asNums=0;
                         ansiStat=ASchar;
                         }
                       else
                         CompleteAnsi(c);
                       break;
      case ASnum     : if ((c>='0') && (c<='9')) {
                         asNum[asNums-1]*=10;
                         asNum[asNums-1]+=c-0x30;
                         }
                       else if (c==';')
                         ansiStat=ASsepar;
                       else
                         CompleteAnsi(c);
                       break;
      case ASchar    : if (c=='"')
                         ansiStat=AScharEnd;
                       else if (asNums==AsMaxNum) {
                         ecprintf("ANSI_ERROR: TooLongData\r\n");
                         ansiStat=ASdata;
                         }
                       else
                         asNum[asNums++]=c;
                       break;
      case AScharEnd : if (c==';')
                         ansiStat=ASsepar;
                       else
                         CompleteAnsi(c);
                       break;
      case ASsepar   : if ((c>='0') && (c<='9')) {
                         if (asNums==AsMaxNum) {
                           ecprintf("ANSI_ERROR: TooLongData\r\n");
                           ansiStat=ASdata;
                           }
                         asNum[asNums]=c-0x30;
                         asNums+=1;
                         ansiStat=ASnum;
                         }
                       else if (c=='"')
                         ansiStat=ASchar;
                       else {
                         asNum[asNums]=0;
                         asNums+=1;
                         CompleteAnsi(c);
                         } //else
                       break;
      }
  else
    printf("%c",c);
} // datadisplay

//---------------------------------------------------------------------------
void Display ( char  c)
// telnet automat engine
//---------------------------------------------------------------------------
{
  switch (telStat) {
    case TSdata   : switch (c) {
                      case 255 : telStat=TSiac;
                                 break;
                      case   0 : break;
                      default  : DataDisplay(c);
                      }
                    break;
    case TSiac    : if (c<240) {
                      ecprintf("%s IAC/%02x\r\n",protErr,c);
                      telStat=TSdata;
                      }
                    else {
                      switch (c) {
                        case 255 : DataDisplay(255); // iac
                                   telStat=TSdata;
                                   break;
                        case 240 : ecprintf(protErr);  // subnego. end
                                   telStat=TSdata;
                                   break;
                        case 246 : WriteData("OK",2); // are you there
                                   telStat=TSdata;
                                   break;
                        case 247 : printf("\8");  // erase character
                                   telStat=TSdata;
                                   break;
                        case 248 : EraseLine(0);
                                   telStat=TSdata;
                                   break;
                        case 250 : telStat=TSsub;
                                   break;
                        case 251 : telStat=TSwl;
                                   break;
                        case 252 : telStat=TSwn;
                                   break;
                        case 253 : telStat=TSdo;
                                   break;
                        case 254 : telStat=TSdn;
                                   break;
                        default  : telStat=TSdata;
                                   break;
                        }
                      if (c<250)
                        if (ctrl)
                          ecprintf("ReadCTRL(%s)\r\n",CMD[c-240]);
                      }
                    break;
    case TSdo     : if (ctrl)
                      ecprintf("ReadCTRL(DO,%s)\r\n",Option(c));
                    switch (c) {
                      case  3 : WriteCtrl(251,3);  // suppres GA (will)
                                break;
                      case 24 : WriteCtrl(251,24); // terminal type
                                break;
                      default : WriteCtrl(252,c);  // won't
                      }
                    telStat=TSdata;
                    break;
    case TSdn     : if (ctrl)
                      ecprintf("ReadCTRL(DON'T,%s)\r\n",Option(c));
                    WriteCtrl(252,c); // won't
                    telStat=TSdata;
                    break;
    case TSwl     : if (ctrl)
                      ecprintf("ReadCTRL(WILL,%s)\r\n",Option(c));
                    switch (c) {
                      case  1 : WriteCtrl(253,1);  // echo (do)
                                remEcho=TRUE;
                                break;
                      case  3 : WriteCtrl(253,3);  // suppres GA (do)
                                break;
                      default : WriteCtrl(254,c);  // don't
                      }
                    telStat=TSdata;
                    break;
    case TSwn     : if (ctrl)
                      ecprintf("ReadCTRL(WON'T,%s)\r\n",Option(c));
                    WriteCtrl(254,c); // don't
                    if (c==1)
                      remEcho=FALSE;
                    telStat=TSdata;
                    break;
    case TSsub    : if (ctrl)
                      ecprintf("ReadCTRL(SubNeg,%s)\r\n",Option(c));
                    telStat=TSsubOpt;
                    sbNum=1;
                    sbC[0]=c;
                    break;
    case TSsubOpt : if (sbNum<SbMax)
                      sbC[sbNum++]=c;
                    else
                      sbNum=SbMax+1;
                    if (c==255) // iac
                      telStat=TSsubIac;
                    break;
    case TSsubIac : if (sbNum<SbMax)
                      sbC[sbNum++]=c;
                    else
                      sbNum=SbMax+1;
                    if (c==240) { // SubNeg End
                      if ((sbNum>0) && (sbNum<SbMax)) {
                        if (sbC[0]==24) {  // terminal type
                          if ((sbNum==4) && (sbC[1]==1)) { // send terminal type
                            strcpy(sbC,"\xff\xfa\x18\0VT100\xff\xf0");
                            WriteData(sbC,12); // my term is VT100
                            if (ctrl)
                              ecprintf("WriteCTRL(SubNegSend,TermType,VT100)\r\n");
                            }
                          }
                        }
                      telStat=TSdata;
                      }
    }
} //display

//---------------------------------------------------------------------------
void ReadData ( /*void*/ )
// data reading thread procedure
//---------------------------------------------------------------------------
{
  int          rc;
  int          i;

  while (!readData)
    delay(200);

  while (sock!=-1) {
    rc=read(sock,iobuf,sizeof(iobuf));
    if (rc==-1) {
      printf("\r\n");
      perror("read");
      exit(1);
      }
    else {
      for (i=0;i<rc;i++) {
        if (logIt)
          fprintf(logFile,"%c",iobuf[i]);
        Display(iobuf[i]);
        }
      }
    ThreadSwitchWithDelay();
    }
  endTel=TRUE;
  delay(1000);
  ExitThread(EXIT_NLM,0);
} // readdata

//---------------------------------------------------------------------------
void exitproc ( void )
//---------------------------------------------------------------------------
{
  if (sock!=-1) {
  	if (-1== close(sock))
      perror("close");
    sock=-1;
	  }
  if (logFile!=NULL) {
    fclose(logFile);
    logFile=NULL;
    }
  if (wrtSem!=-1) {
    CloseLocalSemaphore(wrtSem);
    wrtSem=-1;
    }
} // exitproc

//---------------------------------------------------------------------------
void WriteHelp ( int  err )
//---------------------------------------------------------------------------
{
  if (err)
    printf(" TELnet argument ERROR.\r\n\r\n");

  printf("Syntax:  %s <server_address> [/L] [/C] [/NA]\r\n\n", myname);
  printf("where    /L   ...   log traffic into SYS:SYSTEM\\TEL.LOG\r\n");
  printf("         /C   ...   log control messages too\r\n");
  printf("         /NA  ...   don't use ANSI control codes\r\n");
  exit(err);
} // writehelp

//---------------------------------------------------------------------------
void ReadParam ( int     argc,
                 char  **argv)
//---------------------------------------------------------------------------
{
  int          i;
  char         str[80];
  char         host[80];

  myname=*argv;
  if (argc<2)
    WriteHelp(0);
  host[0]=0;
  for (i=1;i<argc;i++) {
    strcpy(str,strupr(argv[i]));
    if (strcmp(str,"/L")==0)
      logIt=TRUE;
    else if (strcmp(str,"/C")==0)
      ctrl=TRUE;
    else if (strcmp(str,"/?")==0)
      WriteHelp(FALSE);
    else if (strcmp(str,"/H")==0)
      WriteHelp(FALSE);
    else if (strcmp(str,"/NA")==0)
      isANSI=FALSE;
    else if (str[0]=='/')
        WriteHelp(TRUE);
    else
      strcpy(host,str);
    }
  if (host[0]==0)
    WriteHelp(TRUE);

  if (logIt | ctrl) {
    if ((logFile=fopen("SYS:SYSTEM\\TEL.LOG","ab"))==NULL) {
      printf("LOG_ERROR: Unable to Open Log File.\r\n");
      logIt=ctrl=FALSE;
      }
    }
  server_sockaddr.sin_addr.s_addr = inet_addr(host);
} // readparam

//---------------------------------------------------------------------------
void MoveCursor ( char  c )
// send ESC [ ABCD
//---------------------------------------------------------------------------
{
  char         data[3];

  data[0]=27;
  data[1]='[';
  data[2]=c;
  WriteData(data,3);
} // movecursor

//---------------------------------------------------------------------------
void KeybInput ( void )
//---------------------------------------------------------------------------
{
  int          i;
  int          c1,c2;

  endTel=FALSE;
  i=0;
  do {
    while (!kbhit()) {
      delay(60);
      if (setCursor) {
        if (displayInputCursor)
          DisplayInputCursor();
        else
          HideInputCursor();
        setCursor=FALSE;
        }
      }
    if (0==(c1=remEcho?getch():getche()))
      c2=remEcho?getch():getche();
    switch (c1) {
      case  0 : switch (c2) {
        case 0x14 : endTel=TRUE; // ALT-T
                    break;
        case 0x48 : MoveCursor('A');
                    break;
        case 0x50 : MoveCursor('B');
                    break;
        case 0x4d : MoveCursor('C');
                    break;
        case 0x4b : MoveCursor('D');
                    break;
        case 0x53 : oline[i++]=255;
                    oline[i++]=247;  // erase char (del)
                    break;
        default   : oline[i++]=0;
                    oline[i++]=c2;
        }
        break;
      case  3 : oline[i++]=255;
                oline[i++]=244; // Interrupt process
                break;
      case 13 : oline[i++]=13;  // CRLF
                oline[i++]=0;
                WriteData(oline,i);
                i=0;
                break;
      default : oline[i++]=c1;
      }
    if (i>0) {
      WriteData(oline,i);
      i=0;
      }
    } while (!endTel);
} // keybinput

//---------------------------------------------------------------------------
void main ( int     argc,
            char  **argv)
//---------------------------------------------------------------------------
{
  int          rc;

  sock=-1;
  wrtSem=-1;
  SetCtrlCharCheckMode(FALSE);
  SetAutoScreenDestructionMode(FALSE);
  SetCursorCouplingMode(TRUE);
  atexit(exitproc);

  ReadParam(argc,argv);
  if (server_sockaddr.sin_addr.s_addr == -1) {
    printf("ERROR: %s is a malformed address\r\n",host);
    exit(1);
    }
  server_sockaddr.sin_family = AF_INET;
  server_sockaddr.sin_port = htons(23);

  printf("Opening socket\r\n");
  sock=socket(PF_INET, SOCK_STREAM, 0);
  if (sock==-1) {
    perror("socket");
    exit(1);
    }

  wrtSem=OpenLocalSemaphore(1);

  readData=FALSE;
  if ((readID=BeginThread(ReadData,NULL,NULL,NULL))==-1) {
    printf(" Error creating reading thread.\r\n");
    exit(1);
    }

  printf("Connecting\r\n");
  rc=connect(sock,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr));
  if (rc==-1) {
    perror("connect");
    exit(1);
    }
  printf("Connected.   Press Alt-T to quit session.\r\n");
  WriteData("OK",0);        // ? begin of communication ?
  readData=TRUE;
  delay(800); // wait for negotiation of session

  KeybInput();

  if (logFile!=NULL) {
    fclose(logFile);
    logFile=NULL;
    }

  ExitThread(EXIT_NLM,0);
} // main

[ RETURN TO DIRECTORY ]