/*   
     SCOL TELNET sockets - windows  . Magma 1.0 . 1996 . Sylvain HUET
     Modified on 18/02/97 by Sebastien Metrot

         TELNET.c : routines sockets bas-niveau
*/
// Modification history:
//
//$ LB(21/06/2001): modify TELNETconnect function : replaced old socks4 protocol by SOCKSconnect function call



#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "../include/vscol.h"
#ifdef VERSION_WIN
#include <winsock.h>
#include <windows.h>
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <signal.h>
#endif
#include "../include/kernel.h"
#include "../scolobj.h"
#include "../include/socket.h"
//$LB : use socks 4 and 5 interface
#include "../include/socks.h"
//
int WSA_TELNET;
int OBJTYPTELNET;

/* definition des reflexes pour les connexions telnet */
#define RFLTELNET_NB        4
#define RFLTELNET_CONNECTED 0
#define RFLTELNET_CLOSED    1
#define RFLTELNET_READ      2                                 
#define RFLTELNET_WRITE     3

#define mWSANOTINITIALISED	"A successful WSAStartup must occur before using this function."
#define mWSAENETDOWN	      "The Windows Sockets implementation has detected that the network subsystem has failed."
#define mWSAENOTCONN	      "The socket is not connected."
#define mWSAEINTR	          "The (blocking) call was canceled using WSACancelBlockingCall."
#define mWSAEINPROGRESS	    "A blocking Windows Sockets operation is in progress."
#define mWSAENOTSOCK	      "The descriptor is not a socket."
#define mWSAEOPNOTSUPP	    "MSG_OOB was specified, but the socket is not of type SOCK_STREAM."
#define mWSAESHUTDOWN	      "The socket has been shut down; it is not possible to recv on a socket after shutdown has been invoked with how set to 0 or 2."
#define mWSAEWOULDBLOCK	    "The socket is marked as nonblocking and the receive operation would block."
#define mWSAEMSGSIZE	      "The datagram was too large to fit into the specified buffer and was truncated."
#define mWSAEINVAL	        "The socket has not been bound with bind."
#define mWSAECONNABORTED	  "The virtual circuit was aborted due to timeout or other failure."
#define mWSAECONNRESET	    "The virtual circuit was reset by the remote side."

#ifdef VERSION_WIN
extern HWND hscol;
#endif

#if defined(VERSION_X11) || defined(VERSION_NOX)
#define SOCKET int
#define BOOL int
#define TRUE (1)
#define FALSE (0)
#define SOCKADDR_IN struct sockaddr_in
#define INVALID_SOCKET -1
#define HANDLE FILE*
#define INVALID_HANDLE_VALUE NULL
#define closesocket close
#endif

typedef struct TTELNETStack 
{
  char *url;
  char *tosend;
  char buffer[512];
  int togive;
  int toget;
  BOOL pending;
  SOCKET TELNETsock;
  int started;
} TTELNETStack;

/*TTELNETStack TELNETStack[MAX_TELNET_GET];*/

int CreateTelnet (mmachine m,TTELNETStack* t)
{
  int res;

  res=MMmalloc(m,1,TYPEBUF); 
  if (res<0) return res;

  MMstore(m,res,0,(int)t);

  return res;
}

TTELNETStack* GetTelnet (mmachine m,int n)
{
  return (TTELNETStack*)MMfetch(m,n,0);
}

void EchoSckError (int err)
{


LPVOID lpMsgBuf;
FormatMessage( 
    FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    FORMAT_MESSAGE_FROM_SYSTEM | 
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    err,
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    (LPTSTR) &lpMsgBuf,
    0,
    NULL 
);


  MMechostr (MSKDEBUG,"TELNET ERROR : %d\n",err);
  MMechostr (MSKDEBUG, "TELNET ERROR precision : %s\n", lpMsgBuf);


// Free the buffer.
LocalFree( lpMsgBuf );

}



int cutaddr (char *,char *);
/* creation d'une liaison de type client
   retourne le descripteur de socket si succes
   retourne un code negatif si erreur */
int TELNETconnect(char *addr,int *ip,int *prt)
{
    SOCKADDR_IN ina;
    SOCKET s;
    int port,x;
    char buf[256];
    long argp=1;


    if (strlen(addr)>256) {/*MMechostr(MSKDEBUG,"Adresse invalide\n");*/return -1;}
    port=cutaddr(addr,buf);
    if (port==-1) port=80;
    if (buf[0]==0) x=localscolIP;
    else x=inet_addr(buf);


    
//    MMechostr(MSKDEBUG,"TELNET CONNECT %s (%x):%x\n",buf,x,port);

    s=socket(PF_INET,SOCK_STREAM,0);
    if (s==INVALID_SOCKET) {/*MMechostr(MSKDEBUG,"Socket invalide\n");*/return -1;}
	// passage direct sans proxy
    if ((proxyIp==0)||(x==SCKlocalconnection())||((proxyIp&proxyMask)==(x&proxyMask)))
      {
#ifdef VERSION_WIN
	if (WSAAsyncSelect(s,hscol,WSA_TELNET,(FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE))==SOCKET_ERROR)
	{
		/*MMechostr(MSKDEBUG,"Ya pas bon WSAAsyncSelect\n");*/
		closesocket(s);
		return -1;
	}
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
	ioctl (s, FIONBIO, &argp);
#endif
#ifdef VERSION_MAC
  TODO
#endif
	ina.sin_family = PF_INET;
	ina.sin_port   = htons((short)port);
	ina.sin_addr.s_addr = x;
#ifdef VERSION_WIN
	if ( (connect(s,(struct sockaddr *)&ina,sizeof(ina))!=0)
	     &&(WSAGetLastError()!=WSAEWOULDBLOCK) )
	{
		/*MMechostr(MSKDEBUG,"Ya pas bon connect\n");*/
		closesocket(s);
		return -1;
	}
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
	if ( (connect(s,(struct sockaddr *)&ina,sizeof(ina))!=0)
	     &&(errno!=EINPROGRESS) )
	{
		/*MMechostr(MSKDEBUG,"Ya pas bon connect\n");*/
		closesocket(s);
		return -1;
	}
	if (SCKaddsock(s,SC_TYPTELNET))
	{
		/*MMechostr(MSKDEBUG,"Ya pas bon addsock\n");*/
		closesocket(s);
		return -1;
	}
#endif
#ifdef VERSION_MAC
  TODO
#endif
      }
	// passage par proxy
    else
      {

    // $ LB : replace old socks4 protocol by SOCKSconnect function call from socks.c
	if (SOCKSconnect (s, x, htons ((short)port)) != SOCKS_SUCCESS)
	{
		MMechostr (MSKDEBUG, "TELNETconnect : error connecting socket %d\n", s);
		closesocket(s);
		return -1;
	}
	else MMechostr (MSKDEBUG, "TELNETconnect : socket %d connected\n", s);

#ifdef VERSION_WIN
	if (WSAAsyncSelect(s,hscol,WSA_TELNET,(FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE))==SOCKET_ERROR)
	{
		/*MMechostr(MSKDEBUG,"Ya pas bon WSAAsyncSelect\n");*/
		closesocket(s);
		return -1;
	}
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
	ioctl (s, FIONBIO, &argp);
	if (SCKaddsock(s,SC_TYPTELNET))
	{
		/*MMechostr(MSKDEBUG,"Ya pas bon addsock\n");*/
		closesocket(s);
		return -1;
	}
#endif
#ifdef VERSION_MAC
  TODO
#endif
	//      MMechostr(MSKDEBUG,"YA BON PROXY !!! PAS BADABOOM !!!\n");
      }
    //    MMechostr(MSKDEBUG,"YA BON !!!\n");
	*ip=x;
	*prt=port;
    return (int)s;
}

int TELNETchannelreset(TTELNETStack * T)
{
  T->url=NULL;
  T->tosend=NULL;
  //  T->buffer=NULL;
  T->togive=0;
  T->toget=0;
  T->pending=FALSE;
  T->TELNETsock=-1;
  return 0;
}


int TELNETchanneldown(mmachine m,TTELNETStack * t)
{
  if (t)
    {
      OBJdelTH(m,OBJTYPTELNET,t->TELNETsock);
    }
  return 0;
}

/* envoie un paquet de caracteres sur une socket
   retourne le nombre d'octets effectivement envoyés (eventuellement 0)
   retourne un code negatif si erreur autre que WouldBlock */
int TELNETsend(int s,char *buf, int len)
{
  int res;
  res=send((SOCKET)s,buf,len,0);

  if (res<0)
    {
#ifdef VERSION_WIN
      if (WSAGetLastError()!=WSAEWOULDBLOCK) 
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
      if (errno!=EAGAIN)
#endif
#ifdef VERSION_MAC
  TODO
#endif
	{
		  MMechostr(MSKDEBUG, "\nTELNETsend error\n");
	  EchoSckError(res);
	  res=-1;
	}
      else res=0;
    }
  return res;
}

/* lit un paquet de caracteres sur une socket
   retourne le nombre d'octets effectivement lus (eventuellement 0)
   retourne un code negatif si erreur autre que WouldBlock */
int TELNETrecv(int s,char *buf, int len)
{
  int res;
  res=recv((SOCKET)s,buf,len,0);
  if (res<0)
    {
#ifdef VERSION_WIN
      if (WSAGetLastError()!=WSAEWOULDBLOCK) 
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
	if (errno!=EAGAIN)
#endif
#ifdef VERSION_MAC
  TODO
#endif
	  {
	    EchoSckError(res);
	    res=-2;
	  }
	else res=0;
    }
  else if (res==0) res=-1;
  return res;
}

int TELNETConnect(mmachine m)
{
  TTELNETStack * h;
  int t;
  int url;
  int ip,port;


//  MMechostr(MSKDEBUG,"TELNET CONNECT !!!!!\n");

  url=MMpull(m)>>1;
//  MMechostr(MSKDEBUG,"pull\n");
//  scolsock=MMget(m,0)>>1;
//  MMset(m,0,NIL);
  if (url==NIL) 
  {
//    MMechostr(MSKDEBUG,"err1\n");
    MMset(m,0,NIL);
    return 0; 
  }
//  MMechostr(MSKDEBUG,"noerr1\n");

  h=(TTELNETStack*)malloc(sizeof(TTELNETStack));
  //  MMechostr(MSKDEBUG,"malloc...%x\n",h);
  if (!h) 
  { 
//    MMechostr(MSKDEBUG,"Not enough mem for telnet");
    MMset(m,0,NIL);
    return 0; 
  }
  
  h->url=(char*)malloc(MMsizestr(m,url)+1);
  if (h->url==NULL) 
  {
//    MMechostr(MSKDEBUG,"Not enough mem for telnet url");
    free(h);
    MMset(m,0,NIL);
    return 0;
  }

  memcpy(h->url,MMstartstr(m,url),MMsizestr(m,url));
  h->url[MMsizestr(m,url)]=0;

  h->tosend=NULL;
  h->togive=0;
  h->started=0;

/*  sprintf(h->tosend,"GET %s\n",h->url);
  h->togive=strlen(h->tosend);*/

  h->TELNETsock=TELNETconnect(h->url,&ip,&port);
  if (h->TELNETsock < 0)
  {
//    MMechostr(MSKDEBUG,"connection error");
    free(h->url);
    free(h);
    MMset(m,0,NIL);
    return 0;
  }
//  h->buffer=NULL;
//  MMechostr(MSKDEBUG,"h=%X\n",h);
  t=CreateTelnet (m,h);
  if (t < 0)
  {
//    MMechostr(MSKDEBUG,"CreateTelnet error");
#if defined(VERSION_X11) || defined(VERSION_NOX)
    SCKdelsock(h->TELNETsock);
#endif
	closesocket(h->TELNETsock);
    free(h->url);
    free(h);
    MMset(m,0,NIL);
    return 0;
  }
  MMpush(m,(int)t*2+1);
  return OBJcreate(m,OBJTYPTELNET,h->TELNETsock,-1,(int)NULL);
}

int TELNETClose(mmachine m)
{
	int p;

    p=MMget(m,0);
    if (p==NIL) return 0;
	OBJdelTM(m,OBJTYPTELNET,p);
	MMset(m,0,NIL);
	return 0;
}

TTELNETStack* findTELNET(mmachine m,int hSock)
{
  int k;
  k=OBJfindTH(m,OBJTYPTELNET,hSock);
  if (k==NIL) return NULL;
  k=MMfetch(m,k,OFFOBJMAG)>>1;
  return GetTelnet(m,k);
}


int TELNETwrite(mmachine m,TTELNETStack *h)
{
  int len;
  int i;

  if (!h->togive) return 0;
  len=TELNETsend(h->TELNETsock,h->tosend,h->togive);
  if (len<0) 
    {
          MMechostr(MSKDEBUG,"TELNET Error on WRITE\n");
      //    TELNETchanneldown(m,h);
      return -1;
    }
  
  //$LBDEBUG
    //MMechostr (MSKDEBUG,">>>>>>>> Writing \"%s\"\n",h->tosend);
  
  if (len<h->togive)
    {
      SCKsetwrite(h->TELNETsock);
      for (i=0;i<len;i++) h->tosend[i]=h->tosend[i+len];
      h->tosend=realloc(h->tosend,h->togive-len);
    }
  else
    {
      free (h->tosend);
      h->tosend=NULL;
    }
  
  h->togive-=len;
    //MMechostr(MSKDEBUG,"TELNET WRITE LEN : %d\n",len);
  return len;
}


int TELNETSend(mmachine m)
{
  TTELNETStack *h;
  int string;
  int t;
  
  t=MMpull(m)>>1;
  string=MMget(m,0)>>1;
  MMset(m,0,NIL);
  if (t<0) return 0;
  h=GetTelnet(m,t);
  if (h==NULL) return 0;
  if (string==NIL) return 0;
  
  if (h->tosend)
    h->tosend=(char*)realloc(h->tosend,h->togive+MMsizestr(m,string));
  else
    h->tosend=(char*)malloc(MMsizestr(m,string));
  
  if (h->tosend==NULL) 
    {
      return 0;
    }


  memcpy (h->tosend+h->togive,MMstartstr(m,string),MMsizestr(m,string));
  /*  h->togive=strlen(h->tosend);*/
  
  h->togive+=MMsizestr(m,string);


  TELNETwrite(m,h);
  MMset(m,0,(h->togive)<<1);
  return 0;
}

int TELNETread(mmachine m,TTELNETStack *h,char *buf,int len)
{
  memcpy(h->buffer,buf,len);
  h->toget=len;
  return 0;
}

int TELNETGetBuffer(mmachine m)
{
  int s;
  char * S;
  TTELNETStack *h;
  int len,t;
  
  t=MMget(m,0)>>1;
  if (t<0) return 0;
  h=GetTelnet(m,t);
  if (h==NULL) return 0;
  
  //  MMechostr(MSKDEBUG,"GetBuffer h=%X\n",h);
  MMset(m,0,NIL);
  len=h->toget;
  h->toget=0;
  if (len==0) return 0;
  s=MMmalloc(m,((len+5)>>1)+1,TYPEBUF);
  if (s==NIL)
  {
    //    MMechostr(MSKDEBUG,"s=NIL");
    return MERRMEM;
  }
  S=MMstartstr(m,s);
  MMstore(m,s,0,len);
  memcpy(S,h->buffer,len);
  S[len]=0;
  MMset(m,0,(s<<1)|1);
  return 0;
}

int SCOLTelnetEvent(mmachine mscol,int hSock,int NetEvent,int NetError)
{
	char buf[512];
	//  char b[128];
	int len;
	int k,t;
	TTELNETStack* h;
	
	//MMechostr(MSKDEBUG,"TELNET Event %d %d\n",NetEvent,NetError);
	k=0;
	if (NetError)
    {
		k=OBJbeginreflex(mscol,OBJTYPTELNET,hSock,RFLTELNET_CLOSED);
		if (!k)
		{
			t=MMget(mscol,1)>>1;
			if (t<0) 
			{
				MMpull(mscol);
				MMpull(mscol);
				MMpull(mscol);
				MMpull(mscol);
				return 0;
			}
			h=GetTelnet(mscol,t);
			
			switch (NetEvent)
			{ 
			case FD_READ   : MMechostr(MSKDEBUG,"TELNET READ    ERROR on %d\n",h,NetEvent); break;
			case FD_WRITE  : MMechostr(MSKDEBUG,"TELNET WRITE   ERROR on %d\n",h,NetEvent); break;
			case FD_CONNECT: MMechostr(MSKDEBUG,"TELNET CONNECT ERROR on %d\n",h,NetEvent); break;
			case FD_CLOSE  : MMechostr(MSKDEBUG,"TELNET CLOSE   ERROR on %d\n",h,NetEvent); break;
			default :        MMechostr(MSKDEBUG,"TELNET ??????? ERROR on %d\n",h,NetEvent); break;
			}
			EchoSckError(NetError);
			MMstore(mscol,t,0,0);  /* SH 991028 */
			if (k=OBJcallreflex(mscol,0)) return k;
		}
		h=findTELNET(mscol,hSock);
    	TELNETchanneldown(mscol,h);
		k=-1;
    }
	else             
    {
		switch(NetEvent)
		{
		case FD_READ :
			//MMechostr(MSKDEBUG, "\nTELNET FD_READ\n");
			k=OBJbeginreflex(mscol,OBJTYPTELNET,hSock,RFLTELNET_READ);
			if (k==0)
			{
				t=MMget(mscol,1)>>1;
				h=GetTelnet(mscol,t);
				if (h==NULL) 
				{
					MMpull(mscol); 
					MMpull(mscol);
					MMpull(mscol);
					MMpull(mscol);
					return 0;
				}
				if ((len=TELNETrecv(hSock,buf,512)) >=0)
				{
					TELNETread(mscol,h,buf,len);
					MMechostr(MSKDEBUG,"Len %d\n",len);
					if (k=OBJcallreflex(mscol,0)) return k;
				}
				else
				{
					MMpull(mscol);
					MMpull(mscol);
					MMpull(mscol);
					MMpull(mscol);
					return SCOLTelnetEvent(mscol,hSock,FD_CLOSE,0);
				}
			}                                       
			break;
		case FD_WRITE :
			//MMechostr(MSKDEBUG, "\nTELNET FD_WRITE\n");
			h=findTELNET(mscol,hSock);
			if (h==NULL) return 0;
			if (!h->started)
			{

				// PAT 17-05-2002 : bloque l'exécution de la callback connected dans le cas d'un proxy
				//h->started=1;
				return SCOLTelnetEvent(mscol,hSock,FD_CONNECT,0);
			}
			
			SCKclrwrite(h->TELNETsock);
			k=OBJbeginreflex(mscol,OBJTYPTELNET,hSock,RFLTELNET_WRITE);
			if (!k)
			{
				t=MMget(mscol,1)>>1;
				h=GetTelnet(mscol,t);
				if (!h)
				{
					MMpull(mscol);
					MMpull(mscol);
					MMpull(mscol);
					MMpull(mscol);
					return 0;
				}
				//MMechostr(MSKDEBUG,"TELNET WRITE %X\n",h);
				if (TELNETwrite(mscol,h)<0)
				{
					MMpull(mscol);
					MMpull(mscol);
					MMpull(mscol);
					MMpull(mscol);
					k=-1;
					break;
				}
				return OBJcallreflex(mscol,0);
			}
			
			break;
		case FD_CLOSE :
			//MMechostr(MSKDEBUG, "\nTELNET FD_CLOSE\n");
			k=OBJbeginreflex(mscol,OBJTYPTELNET,hSock,RFLTELNET_CLOSED);
			if (!k)
			{
				t=MMget(mscol,1)>>1;
				h=GetTelnet(mscol,t);
				if (!h) 
				{
					MMpull(mscol);
					MMpull(mscol);
					MMpull(mscol);
					MMpull(mscol);
					return 0;
				}
				
				MMstore(mscol,t,0,0);
				if (k=OBJcallreflex(mscol,0)) return k;
//				TELNETchanneldown(mscol,h);   // SH 991213
				k=-1;
			}
			OBJdelTH(mscol,OBJTYPTELNET,hSock);
			break;
		case FD_CONNECT :
			//MMechostr(MSKDEBUG, "\nTELNET FD_CONNECT\n");
			h=findTELNET(mscol,hSock);
			if (h==NULL) return 0 ;
			if (h->started) break;
			h->started=1;
			k=OBJbeginreflex(mscol,OBJTYPTELNET,hSock,RFLTELNET_CONNECTED);
			if (!k)
			{
				t=MMget(mscol,1)>>1;
				h=GetTelnet(mscol,t);
				
				if (!h) 
				{
					MMpull(mscol);
					MMpull(mscol);
					MMpull(mscol);
					MMpull(mscol);
					return 0;
				}
				if (k=OBJcallreflex(mscol,0)) return k;
				k=-1;
			}
			break;
		default:
			break;
	}        
    }
	return k;
}

int TELNETConvertString (mmachine m)
{
  int s,l,i;
  char * S;
  
  s=MMget(m,0)>>1;
  
  S=MMstartstr (m,s);
  l=MMsizestr(m,s);
  
  for (i=0;i<l;i++)
    {
      //    S[i]-=128;
      if (S[i]&0x80)
	{
	  S[i]='.';
	}
      else if (S[i]<32)
	{
	  if ((S[i]!=10) && (S[i]!=13))
	    {
	      S[i]='_';
	    }
	}
    }
  
  return 0;
}

int TELNETrflRead (mmachine m)
{
  //  MMechostr (0,"Assign Reflex TELNET READ, %x %x\n",MMget(m,1),MMget(m,0));
  return OBJaddreflex(m,OBJTYPTELNET,RFLTELNET_READ);
}

int TELNETrflWrite (mmachine m)
{
  //  MMechostr (0,"Assign Reflex TELNET WRITE");
  return OBJaddreflex(m,OBJTYPTELNET,RFLTELNET_WRITE);
}

int TELNETrflConnect (mmachine m)
{
  //  MMechostr (0,"Assign Reflex TELNET CONNECTED");
  return OBJaddreflex(m,OBJTYPTELNET,RFLTELNET_CONNECTED);
}

int TELNETrflClose (mmachine m)
{
  //  MMechostr (0,"Assign Reflex TELNET CLOSED");
  return OBJaddreflex(m,OBJTYPTELNET,RFLTELNET_CLOSED);
}
#ifdef VERSION_WIN
int ScolTelnet(mmachine m,HWND hwnd,unsigned msg,UINT wParam, LONG lParam,int *ret)
{
    int hSock;
    int NetEvent,NetError;
    
    hSock=(int)wParam;
    NetEvent=WSAGETSELECTEVENT(lParam);
    NetError=WSAGETSELECTERROR(lParam);
    return SCOLTelnetEvent(m,hSock,NetEvent,NetError);
}
#endif

int D2TELNET(mmachine m,int handsys,int objm)
{
  TTELNETStack * t;

#if defined(VERSION_X11) || defined(VERSION_NOX)
  SCKdelsock(handsys);
#endif
  closesocket((SOCKET)handsys);
  t=GetTelnet(m,objm>>1);
  if (t==NULL) return 0;
  MMstore(m,objm>>1,0,0); 
  if (t->url)
    free(t->url);
  t->url=NULL;
  if (t->tosend) free(t->tosend);
  t->tosend=NULL;
  //    t->buffer=NULL;
  t->togive=0;
  t->toget=0;
  t->pending=FALSE;
  t->TELNETsock=-1;
  free (t);
  return 0;
}


#define NTELNETPKG 10

char* telnetname[NTELNETPKG]=
{"_TELNETConnect",
 "_TELNETSend",
 "_TELNETGetBuffer",
 "_TELNETClose",
 "_TELNETConvertString",
 "_TELNETrflRead",
 "_TELNETrflWrite",
 "_TELNETrflConnect",
 "_TELNETrflClose",
 "TELNET"};
int (*telnetfun[NTELNETPKG])(mmachine m)=
{TELNETConnect,
 TELNETSend,
 TELNETGetBuffer,
 TELNETClose,
 TELNETConvertString,
 TELNETrflRead,
 TELNETrflWrite,
 TELNETrflConnect,
 TELNETrflClose,
 NULL};
int telnetnarg[NTELNETPKG]=
{2,
 2,
 1,
 1,
 1,
 3,
 3,
 3,
 3,
 TYPTYPE};
char * telnettype[NTELNETPKG]=
{"fun [Chn S] TELNET",
 "fun [S TELNET] I",
 "fun [TELNET] S",
 "fun [TELNET] I",
 "fun [S] S",
 "fun [TELNET fun [TELNET u0] u1 u0] TELNET",
 "fun [TELNET fun [TELNET u0] u1 u0] TELNET",
 "fun [TELNET fun [TELNET u0] u1 u0] TELNET",
 "fun [TELNET fun [TELNET u0] u1 u0] TELNET",
 NULL};

int IniTELNET(mmachine m)
{
  OBJTYPTELNET=OBJregister(RFLTELNET_NB,0,D2TELNET,"OBJTYPTELNET");
#ifdef VERSION_WIN
  WSA_TELNET=OBJgetUserEvent();
  OBJdefEvent(WSA_TELNET,ScolTelnet);
#endif
  return PKhardpak(m,"TELNET.pkg",NTELNETPKG,telnetname,telnetfun
		   ,telnetnarg,telnettype);
}
