
		****  terminal_2.c ****

*
 * Program Name:  terminal_2.c 
 * This program demonstrates the use of the second method of using non
 * blocking features in the socket library  where the user does the wait.
 * This program runs on CTOS only (not UNIX).
 * It must be linked with terminal.obj.
 *
 * Usage: terminal_2 hostname [remote_port [local_echo [debug level]]]
 *
 * The program supports a small subset of the Telnet protocol, which
 * allows it to act as a very dumb terminal on some unix hosts
 *   use hostname 23 n to log on to unix
 *
 *
 * If the server is echoserver or multecho remote_port is 3000.
 * local echo: use y for yes.
 *
 * OGA 090991  		MCsocket.lib build
 * efw 092193  		TCP 2.2 build
 *
 *

include <stdio.h>
include systypes.h
include syssocket.h
include netinetin.h
include netdb.h

	**** CTOSLIB functions ****

ifdef __BTOSC__
int AllocExch plm far(int *exch);	
int Request plm far(char *rq);
int Wait plm far(int ex, char **r);
else
define AllocExch @
define Request @
define Wait @
include <ctos.lib.h>
endif


	**** defines ****

define CR 13				* ASCII                    * 
define LF 10				* ASCII                    * 
define BUFSZ 512			* Buffer size for TCP      *
define KBDBUFFSZ 512		* Keyboard Buffer size     *
define READKBDREQ 54		* Keyboard	Request Code    * 

	**** functions imported from terminal.c ****

void CheckArgs(int argc, char *argv[]);	* CheckArgs *
void CheckP(int n, char *msg);	* UNIX style return code check *
void CheckZ(int n, char *msg);	* CTOS Erc check               *
void InitTelnet();              * Telnet startup for unix      *
void RecvTelnet(unsigned char *iBf, int iBfSz);
                                * Telnet input processing for unix  *
	**** Global Data ****

typedef struct kbd_read		* Kbd request block structure	*
{
char	sCntlInfo;
char	rtCode;
char	nReqPbCb;
char	nRespPbCb;
int		UserNum;
int 	exchResp;
int 	ercRet;
int		rqCode;
int		mode;
int		resv[2];
char	*pCharRet;
int 	sCharRet;
} READKBD;

extern unsigned int errno;	* global error code returned from system calls *
int Debug;					* Debugging level                           *
int LocalEcho=0;			* False if the host does echo (eg, UNIX)       *
int Erc;					* Application Global for CTOS erc's            *
char Kbuff[KBDBUFFSZ+1];	* Keyboard Buffer                              *
int Ksz=0;					* Keyboard Bufferpointer                       *
char KeyChar;				* character read stored here                   *
READKBD KbdReq;				* Keyboard Request Block                       *
char *pKbdReq;				* pointer to request block                     *
char *ReqPointer;			* pointer to request block                     *
char **pReqPointer;			* pointer to request block pointer             *
int Exch;					* address of exchange stored here              *
int S;      				* file descriptor returned by socket call      *
int N;         				* return value of function calls               *
struct sockaddr_in server; 	* server socket address                        *
struct hostent *hp;    		* pointer to structure containing host address *
char inbuff[BUFSZ];			* buffer for data from remote host             *
int RemotePort=23;			* Default to the Telnet port               *

**** Local functions ****

void MakeKbdReq();				* Make Keyboard Request        *

void MakeKbdReq()
****************
 *  make Keyboard Request 
 *
{
	memset(KbdReq, 0, sizeof(KbdReq));
	KbdReq.sCntlInfo	=6;
	KbdReq.nRespPbCb	=1;
	KbdReq.exchResp		=Exch;
	KbdReq.rqCode		=READKBDREQ;
	KbdReq.pCharRet		=KeyChar;
	KbdReq.sCharRet		=1;
		
	Erc=Request((char*)KbdReq);
	CheckZ(Erc, Request KbdReq);
}
main(int argc, char *argv[])
**************************
{
	CheckArgs(argc, argv);
	Erc = AllocExch(Exch);						* allocate an exchage *
	CheckZ(Erc, AllocExch);
	
* AF_INET is communications domain, SOCK_STREAM specifies the type of 
 * communications, and IPPROTO_TCP represents the protocol to be used. 
 *
	S = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	CheckP((int)S, socket);
	server.sin_family = AF_INET;  					* assign domain *
	server.sin_port = htons(RemotePort);			* assign remote port*
	
* take the host name entered as an argument to this program
 *  and uses it to get the address of the remote host we connect to.
 *
	hp = gethostbyname(argv[1]);
	if (hp == NULL) {
        printf(invalid host argument = s\n,argv[1]);
        exit(1);
	}
	CheckP( (hp==NULL ? 1 : 0) , gethostbyname);
	
* take the h_addr field of the hostent structure returned by
 *  gethostbyname and copies it to the server address.
 *
	memcpy((char*)server.sin_addr.s_addr, hp>h_addr, hp>h_length);
	
												*connect to the remote host. *
	N = connect(S, server, sizeof(server)); 	
	checkp (N,connect);
	printf(Method 2 Terminal  connect successful\n);
	printf(\nFINISH to Exit\n\n);

	if (server.sin_port==23){
		InitTelnet();
		printf(InitTelnet\n);
	}

	MakeKbdReq();								* make KBD Request				*

												* set up TCPinitial request *
  	N = setctossockexch (S, Exch, (char***) pReqPointer);
	CheckP(N, setctossockexch);
	N = recv(S, inbuff, sizeof(inbuff), MSG_NOBLOCK | MSG_POSTREQ);
	if (N<0){
		if (errno = EWOULDBLOCK)
			checkp(N,recv);
	}		
 	for(;;){

		Erc=Wait(Exch, pReqPointer);
		CheckZ(Erc, Wait);

		if (((READKBD*)*pReqPointer)>rqCode=READKBDREQ){
			N = recv(S, inbuff, sizeof(inbuff), MSG_TCPREQ);
			if (N > 0) {
			RecvTelnet((unsigned char*)inbuff, N);
												* Make another TCP request *
				N = recv(S, inbuff, sizeof(inbuff), MSG_NOBLOCK | MSG_POSTREQ);
				if (N<0){
					if (errno = EWOULDBLOCK)
						checkp(N,nonblocking recv);
				}		
			}else{
				CheckP(N, recv after wait);
			}
		}else{
			CheckZ(KbdReq.ercRet, recv nz erc);
			if (KeyChar==0x04){
				sclose(S);
				exit (0);
			}
			if (LocalEcho){
				fwrite(KeyChar, 1, 1, stdout);
				if (Ksz>=KBDBUFFSZ) Ksz;
				Kbuff[Ksz++]=KeyChar;
				if (KeyChar == LF){ * CRLF required for SMTP *
					Kbuff[Ksz1]=CR;	
					Kbuff[Ksz++]=LF;
					N = ssend (S, Kbuff, Ksz, 0);
					CheckP(N, ssend);
					Ksz=0;
				}
			}else{
				N = ssend (S, KeyChar, 1, 0);
				CheckP(N, ssend); * CRLF not required for Telnet echo *
			}
			MakeKbdReq();						* Make another KBD request *
		}
	} *end for *
} * end main *
