#include <string.h>
#include "memStuffForPipSqueeks.h"
#include "cci.h"
#include "connect.h"
#include "list.h"

static int initialized = 0;
static List anchorCBList = 0;
static List outputCBList = 0;
static List browserViewCBList = 0;

extern char *GetLine();

typedef struct {
		MCCIPort serverPort;
		void (*callBack)();
		void *callBackData;
		} AnchorCallBack;

typedef struct {
		MCCIPort serverPort;
		char *type;
		void (*callBack)();
		void *callBackData;
		} OutputCallBack;

typedef struct {
		MCCIPort serverPort;
		void (*callBack)();
		void *callBackData;
		} BrowserViewCallBack;

int MCCIGetSocketDescriptor(serverPort)
/* this routine is platform dependent and is not assumed to be supported
 * on all platforms.  It is only here for those routines that wish to have
 * a select() external to the MCCI library.
 * this routine extracts the socket descriptor from the MCCIPort and
 * returns it */
MCCIPort serverPort;
{
	return(NetGetSocketDescriptor(serverPort));
}

int MCCIIsConnected(serverPort)
/* return 1 if connected, 0 if not */
MCCIPort serverPort;
{
	return(NetIsConnected(serverPort));
}

void MCCIReadBrowserViewOutput(serverPort,response)
MCCIPort serverPort;
char *response;
/* Read output from BrowserView */
{
char *line;
char *url = (char *) 0;
BrowserViewCallBack *bvCB;
char *start,*end,*s,*contentType;
int contentLength;
char *data = (char *) 0;
int numRead;

	/* expect response line to be 'MCCIR_SEND_BROWSERVIEW <URL>' */
	/* skip over MCCIR_SEND_BROWSERVIEW */
	s = response;
	s+=4; /* skip over repsonse code */
	GetWordFromString(s,&url,&end);
	if (url && (url != end)) {
		url = strdup(url);
		}
	else {
		url = (char *) 0;
		}
	
#ifdef DEBUG
printf("MCCIReadBrowserViewOutput(): I've been called\n");
printf("MCCIReadBrowserViewOutput(): url = \"%s\"\n",url);
#endif
	line = GetLine(serverPort);
	if (!line) {
		return;
		}
#ifdef DEBUG
printf("MCCIReadBrowserViewOutput(): got line:%s\n",line);
#endif
	contentType = (char *) 0;
	if (!strncasecmp("Content-Type:",line,13)) {
		start = line;
		start += 13;
		GetWordFromString(start,&s,&end);
		*end = '\0';
		contentType = strdup(s);

		line = GetLine(serverPort);
#ifdef DEBUG
printf("MCCIReadBrowserViewOutput(): 2 got line:%s\n",line);
#endif
		if (!line) {
			return;
			}
		}
#ifdef DEBUG
printf("MCCIReadBrowserViewOutput(): contentType:%s\n",contentType);
#endif
	if (!strncasecmp("Content-Length:",line,15)) {
		start = line;
		start += 15;
		GetWordFromString(start,&s,&end);
		contentLength = atoi(s);
		if (contentLength < 1){
			return; /* error */
			}
		if (!(data = (char *) MALLOC(contentLength))) {
			return; /* error */
			}
#ifdef DEBUG
printf("MCCIReadBrowserViewOutput(): type=%s,length=%d\n",
			contentType,contentLength);
#endif

		numRead = ReadBuffer(serverPort,data,contentLength);
#ifdef DEBUG
printf("MCCIReadBrowserViewOutput(): number of bytes read = %d\n",numRead);
#endif

		/*******************************************************
		 * done parsing getting message from network, 
		 *       now notify my callbacks 
		 */

		bvCB = (BrowserViewCallBack *) ListHead(browserViewCBList);
		while (bvCB) {
			if (bvCB->callBack) {
				(void)(bvCB->callBack)(url,contentType,
						data, contentLength,
						bvCB->callBackData);
				}
	
			bvCB = (BrowserViewCallBack *) 
						ListNext(browserViewCBList);
			}
		}
	
#ifdef DEBUG
printf("MCCIReadBrowserViewOutput(): returning\n");
#endif
	
} /* MCCIReadBrowserViewOutput() */




static void MCCIReadSendDataOutput(serverPort)
/* read output sent from the Mosaic */
/* error recovery could be better in this routine */
MCCIPort serverPort;
{
char *line;
char *start,*end,*s,*contentType;
int contentLength;
char *data = (char *) 0;
OutputCallBack *outCB;
int numRead;

#ifdef DEBUG
printf("MCCIReadSendDataOutput(): I've been called\n");
#endif
	line = GetLine(serverPort);
	if (!line) {
		return;
		}
#ifdef DEBUG
printf("MCCIReadSendDataOutput(): got line:%s\n",line);
#endif
	contentType = (char *) 0;
	if (!strncasecmp("Content-Type:",line,13)) {
		start = line;
		start += 13;
		GetWordFromString(start,&s,&end);
		*end = '\0';
		contentType = strdup(s);

		line = GetLine(serverPort);
#ifdef DEBUG
printf("MCCIReadSendDataOutput(): 2 got line:%s\n",line);
#endif
		if (!line) {
			return;
			}
		}
#ifdef DEBUG
printf("MCCIReadSendDataOutput(): contentType:%s\n",contentType);
#endif
	if (!strncasecmp("Content-Length:",line,15)) {
		start = line;
		start += 15;
		GetWordFromString(start,&s,&end);
		contentLength = atoi(s);
		if (contentLength < 1){
			return; /* error */
			}
		if (!(data = (char *) MALLOC(contentLength))) {
			return; /* error */
			}
#ifdef DEBUG
printf("MCCIReadSendDataOutput(): type=%s,length=%d\n",
			contentType,contentLength);
#endif

		numRead = ReadBuffer(serverPort,data,contentLength);
#ifdef DEBUG
printf("MCCIReadSendDataOutput(): number of bytes read = %d\n",numRead);
#endif
		/* find callback */
		outCB = (OutputCallBack *) ListHead(outputCBList);
		while(outCB) {
#ifdef DEBUG
printf("MCCIReadSendDataOutput(): Checking a call back\n");
printf("MCCIReadSendDataOutput(): comparing \"%s\" with \"%s\"\n",outCB->type,contentType);
#endif
			if ((outCB->serverPort == serverPort) && 
				(!strcasecmp(outCB->type,contentType))) {
	
				if (outCB->callBack) {
					(void)(outCB->callBack)(contentType,
						data,numRead,outCB->callBackData);
#ifdef DEBUG
printf("MCCIReadSendDataOutput(): calling a cb\n");
#endif
					}
				}
			outCB = (OutputCallBack *) ListNext(outputCBList);
			}
		}
	
#ifdef DEBUG
printf("MCCIReadSendDataOutput(): returning\n");
#endif
	if (!line) {
		return;
		}

}

static void MCCIHandleAddOutput(serverPort,response)
MCCIPort serverPort;
char *response;
{
char respCode[10];
char *start,*end;
static char url[1024];


#ifdef DEBUG
printf("MCCIHandleAddOutput I've been called with");
#endif
	if ((!response) || (!MCCIIsConnected(serverPort))) {
		return;
		}
#ifdef DEBUG
printf("\n\"%s\"\n",response);
#endif
	sprintf(respCode,"%d",MCCIR_ANCHOR_INFO);
	if (!strncmp(respCode,response,3)) {
		/* It's an ANCHOR INFO */
		AnchorCallBack *acb;

		start = strchr(response,'<');
		end = strchr(response,'>');

		start++;
		*end='\0';
		strcpy(url,start);

		/* call all the anchor callbacks */
		acb = (AnchorCallBack *) ListHead(anchorCBList);
		while (acb) {
			if (acb->serverPort == serverPort) {
				if (acb->callBack) {
					(acb->callBack)(url,acb->callBackData);
					}
				}
			acb = (AnchorCallBack *) ListNext(anchorCBList);
			}
		return;
		}

	sprintf(respCode,"%d",MCCIR_SEND_DATA_OUTPUT);
	if (!strncmp(respCode,response,3)) {
		/* It's send output data */
		MCCIReadSendDataOutput(serverPort);
		}

	sprintf(respCode,"%d",MCCIR_SEND_BROWSERVIEW);
	if (!strncmp(respCode,response,3)) {
		/* It's send output data */
		MCCIReadBrowserViewOutput(serverPort,response);
		}

        sprintf(respCode, "%d", MCCIR_GET_OK);
        if (!strncmp(respCode,response,3)) {
	        /* It's a GET OK */
#ifdef DEBUG
              	printf("GET reply: %s\n",response);
#endif
	        }

        sprintf(respCode, "%d", MCCIR_GET_FAILED);
        if (!strncmp(respCode,response,3)) {
	        /* It's a GET FAILED */
#ifdef DEBUG
              	printf("GET reply: %s\n",response);
#endif
	        }
	        
	/* I don't know what this is Additional Output is... */
	return;
	
}


int MCCIPoll(serverPort)
/* this routine is intended to be called periodically to check for input
 * from the server.  If so, it's handled.
 * return -1 on Not connected.
 * return 1 if something was read.
 * return 0 on nothing here.
 */
MCCIPort serverPort;
{
char *line;
int ret=0;

	if (!MCCIIsConnected(serverPort)) {
		return(-1);
		}

	while (MCCIIsThereInput(serverPort)) {
		line = GetLine(serverPort);
		if (!line) {
			/* server has disconnected */
			MCCIDisconnect(serverPort);
			}
		MCCIHandleAddOutput(serverPort,line);
		ret = 1;
		}

	if (!MCCIIsConnected(serverPort)) {
		return(-1);
		}
	else {
		return(ret);
		}
}



static char *MCCIGetResponse(serverPort)
MCCIPort serverPort;
/* get a response from a server.  The string returned is good only until the
   next call to GetLine() */
{
char *response;

	if (!MCCIIsConnected(serverPort)) {
		return("901 Error not connected");
		}

	response = GetLine(serverPort);
	if (response) {
		while (response[0] == '3') {
			MCCIHandleAddOutput(serverPort,response);
			response = GetLine(serverPort);
			}
		}
	else {
		MCCIDisconnect(serverPort);
		return("900 Error No response");
		}

	return(response);
}


static int MCCIWrite(serverPort,message,length)
/* This is a wrapper to NetWrite,  It's here to insure that data from the
 * server is read in before a write is sent out so as to prevent a
 * write write deadlock */
MCCIPort serverPort;
char *message;
int length;
{
int writeLength;

	if (!MCCIIsConnected(serverPort)) {
		return(0);
		}

	while(NetIsThereInput(serverPort)) {
		MCCIGetResponse(serverPort);
		if (!MCCIIsConnected(serverPort)) {
			return(0);
			}
		}
	writeLength = NetWrite(serverPort,message,length);

	return(writeLength);
}


MCCIInitialize()
{
	anchorCBList = ListCreate();
	outputCBList = ListCreate();
	browserViewCBList = ListCreate();
	initialized = 1;
}


MCCIPort MCCIConnect(serverAddress,port,callBack,callBackData)
/* connect to given address */
/* return 0 on can't connect */
/* upon termination of connection, the callback is called.  It's of the form:
 * 	void CCICloseCallBack(MCCIPort serverPort, void callBackData);
 */
char *serverAddress;
int port;
void (*callBack)(); /* disconnect callback */
void *callBackData; /* disconnect callback data */
{
MCCIPort serverPort;
char *line;

	if (!initialized) {
		MCCIInitialize();
		}

	if (!(serverPort = NetClientConnect(serverAddress,port))) {
		return((MCCIPort) 0);
		}

	line = MCCIGetResponse(serverPort);

#ifdef DEBUG
	printf("MCCIConnect(): received from server:\n%s",line);
#endif
	if (serverPort) {
		serverPort->callBack = callBack;
		serverPort->callBackData = callBackData;
		}
	return(serverPort);
}	




int MCCIIsThereInput(serverPort)
/* return 1 on true, 0 on false */
MCCIPort serverPort;
{
	if (!serverPort)
		return(0);
	if (!MCCIIsConnected(serverPort)) {
		return(0);
		}
	return(NetIsThereInput(serverPort));
}


int MCCISendAnchor(serverPort,status,callBack,callBackData)
/***************************************************************************
* MCCISendAnchor - tell browser to send anchor history
*	status -	0, MCCI_SEND_BEFORE, or MCCI_SEND_AFTER		
* 			0 disables SendAnchor
*			MCCI_SEND_BEFORE, instructs the server to
*			send the anchor before the browser finishes
*			pulling down the URL.
*			MCCI_SEND_AFTER, instruts the server to
*			send the anchor after the browser finishes
*			pulling down the URL.
*	callBack - 	Routine that should be called back upon
*		   	anchor hits from browser.  This function is 
*			defined as:
*
*			void callBack(char *anchor, void *callBackData)
*		
*	callBackData - 	data to be passed back to callBack routine
*		
***************************************************************************/
MCCIPort serverPort;
int status; 
void (*callBack)();
void *callBackData;
{
char buff[80];
int length;
int lengthToSend;
AnchorCallBack *a;
int notFound;
char *line;

	if (!serverPort) {
		return(MCCI_FAIL);
		}
	if (!MCCIIsConnected(serverPort)) {
		return(MCCI_NETWORK_ERROR);
		}

	if (status) {
		/* create memory before sending request in case of failure */
		if (!(a = (AnchorCallBack *) 
			      MALLOC(sizeof(AnchorCallBack)))) {
			      return(MCCI_OUTOFMEMORY);
		              }

		if (status == MCCI_SEND_BEFORE) { /* ejb 9 March 1995 */
			sprintf(buff, "%s %s %s\r\n", MCCI_S_SEND, 
				MCCI_S_ANCHOR, MCCI_S_BEFORE);
		        }
		else {	/* defaults to send after, backwards compatible. */
			sprintf(buff, "%s %s %s\r\n", MCCI_S_SEND, 
				MCCI_S_ANCHOR, MCCI_S_AFTER);
		        }

		lengthToSend = strlen((char *)buff);
		length = MCCIWrite(serverPort, buff, lengthToSend);
		if (length != lengthToSend) {
			/* error sending */
			FREE(a);
			return(MCCI_FAIL);
			}
		/* add to callback list */
		if (callBack) {
			a->serverPort = serverPort;
			a->callBack = callBack;
			a->callBackData = callBackData;
			ListAddEntry(anchorCBList,a);
			}
		else {
			FREE(a);
			}

		}
	else {
		sprintf(buff, "%s %s %s\r\n", MCCI_S_SEND,
					MCCI_S_ANCHOR, MCCI_S_STOP);
		lengthToSend = strlen((char *)buff);
		length = MCCIWrite(serverPort, buff, lengthToSend);
		if (length != lengthToSend) {
			/* error sending */
			return(MCCI_FAIL);
			}

		/* remove from callback list */
		a = (AnchorCallBack *) ListHead(anchorCBList);
		while (a) {
			if (a->serverPort == serverPort) {
				if (callBack) {
					if (callBack == a->callBack) {
						ListDeleteEntry(anchorCBList,a);
						}
					}
				else {
					ListDeleteEntry(anchorCBList,a);
					}
				a = (AnchorCallBack *)ListCurrent(anchorCBList);
				}
			else {
				a = (AnchorCallBack *) ListNext(anchorCBList);
				}
			}
		}

	line = MCCIGetResponse(serverPort);
#ifdef DEBUG
	printf("SEND ANCHOR reply: %s\n",line);
#endif
	if (!line) {
		return(MCCI_NETWORK_ERROR);
		}
	if (line[0]=='2') {
		return(MCCI_OK);
		}
	else {
		return(MCCI_REQUEST_FAIL);
		}
}







int MCCIGet(serverPort,uri,output,absRelative,additionalHeader)
/***************************************************************************
* MCCIGet - Resolve a URL 
*	uri - the URL to be resolved 	
*	output - where should the output go?
*		MCCI_DEFAULT		- same as OUTPUT_CURRENT
*		MCCI_OUTPUT_NONE	- Browser shouldn't display
*		MCCI_OUTPUT_CURRENT     - Browser should display in current
*		MCCI_OUTPUT_NEW		- Browser should display in new window
* 	absRelative - url should be treated as either a relative or
*		or absolute link to the current document 
*		MCCI_DEFAULT		- set to absolute
*		MCCI_ABSOLUTE
*		MCCI_RELATIVE
*	additionalHeader - This is a string containing additional HTTP
*		header information to pass to the server.  If this is
*		a standard HTTP GET, this field should be set to NULL.
* Example:
*	MCCIGet(port,"http://host/file",0,MCCI_ABSOLUTE,0);
***************************************************************************/
MCCIPort serverPort;
char *uri; 
int output;
int absRelative;
char *additionalHeader;
{
char *buff;
char buff2[80];
int length,lengthToSend;
char *line;
int approxSize;

	if (!serverPort) {
		return(MCCI_FAIL);
		}

	if (!MCCIIsConnected(serverPort)) {
		return(MCCI_NETWORK_ERROR);
		}

	approxSize = 256;
	if (!uri) {
		/* required parameter */
		return(MCCI_FAIL);
		}
	else {
		approxSize += strlen(uri);
		}
	if (additionalHeader) {
		approxSize += strlen(additionalHeader);
		}

	if (!(buff = (char *) MALLOC(approxSize))) {
		/* memory problems */
		return(MCCI_OUTOFMEMORY);
		}

	sprintf(buff,"GET URL <%s>",uri);
	switch (output) {
		case MCCI_OUTPUT_NONE:	
				strcat(buff," OUTPUT NONE");
				break;
		case MCCI_OUTPUT_NEW:	
				strcat(buff," OUTPUT NEW");
				break;
		case MCCI_OUTPUT_CURRENT:	
		default: 
				strcat(buff," OUTPUT CURRENT");
				break;
		}
/*
	switch (absRelative) {
		case MCCI_RELATIVE:
				strcat(buff," RELATIVE");
				break;
		case MCCI_ABSOLUTE:
		default:
				strcat(buff," ABSOLUTE");
				break;
		}
*/
	if (additionalHeader) {
		strcat(buff," HEADER\r\n");
		sprintf(buff2,"Content-Length: %d\r\n",
				strlen(additionalHeader));
		strcat(buff,buff2);
		strcat(buff,additionalHeader);
		}
	else {
		strcat(buff,"\r\n");
		}

	lengthToSend = strlen(buff);
	length = MCCIWrite(serverPort, buff, lengthToSend);
	FREE(buff);

	if (length != lengthToSend) {
		/* error sending */
		return(MCCI_FAIL);
		}

	/* get server response */
	line = MCCIGetResponse(serverPort);
#ifdef DEBUG
	printf("GET reply: %s\n",line);
#endif

	if (!line) {
		return(MCCI_NETWORK_ERROR);
		}
	if (line[0]=='2') {
		return(MCCI_OK);
		}
	else {
		return(MCCI_REQUEST_FAIL);
		}
	
}

int MCCISendOutputStop(serverPort,mimeType)
MCCIPort serverPort;
char *mimeType;
{
char buff[128];
int length,lengthToSend;
char *line;
OutputCallBack *outCB;

	if (!serverPort) {
		return(MCCI_FAIL);
		}
	if (!MCCIIsConnected(serverPort)) {
		return(MCCI_NETWORK_ERROR);
		}

	sprintf(buff,"%s %s %s %s %s\r\n",
		MCCI_S_SEND, MCCI_S_OUTPUT, MCCI_S_STOP,
		mimeType,NetReturnAddress(serverPort));

	lengthToSend = strlen(buff);
	length = MCCIWrite(serverPort, buff, lengthToSend);

	if (length != lengthToSend) {
		/* error sending */
		return(MCCI_FAIL);
		}

	/* get server response */
	line = MCCIGetResponse(serverPort);

#ifdef DEBUG
	printf("SEND OUTPUT STOP reply: %s\n",line);
#endif

	/* remove call back from list */
	outCB = (OutputCallBack *)ListHead(outputCBList);
	while (outCB) { 
		if ((outCB->serverPort == serverPort) &&
			(!(strcmp(mimeType,outCB->type)))) {
			ListDeleteEntry(outputCBList,outCB);
			FREE(outCB->type);
			FREE(outCB);
			outCB = (OutputCallBack *) 
						ListCurrent(outputCBList);
			}
		else {
			outCB = (OutputCallBack *) 
						ListNext(outputCBList);
			}
		}

	if (!line) {
		return(MCCI_NETWORK_ERROR);
		}
	if (line[0]=='2') {
		return(MCCI_OK);
		}
	else {
		return(MCCI_REQUEST_FAIL);
		}
	
}

int MCCISendOutput(serverPort,mimeType,callBack,callBackData)
/* Tell Mosaic to send output of type mimeType
 * When Mosaic sends this type of data, the cci client may be notified by
 * the callback.  The callback is of the form:
 *
 *	void SendOuputCallBack(char *mimeType,char *data,int length, 
 *							void *callBackData);
 *
 * The cci client is repsonsible for freeing the area allocated in the
 * data field.
 */


MCCIPort serverPort;
char *mimeType;
void (*callBack)();
void *callBackData;
{
char buff[128];
int length,lengthToSend;
char *line;
OutputCallBack *outCB;

	if (!serverPort) {
		return(MCCI_FAIL);
		}
	if (!MCCIIsConnected(serverPort)) {
		return(MCCI_NETWORK_ERROR);
		}

	if (!(outCB = (OutputCallBack *) MALLOC(
					sizeof(OutputCallBack)))) {
		return(MCCI_OUTOFMEMORY);
		}

	sprintf(buff,"%s %s %s TO %s\r\n",
			MCCI_S_SEND,MCCI_S_OUTPUT,
			mimeType, NetReturnAddress(serverPort));

	lengthToSend = strlen(buff);
	length = MCCIWrite(serverPort, buff, lengthToSend);

	if (length != lengthToSend) {
		/* error sending */
		FREE(outCB);
		return(MCCI_FAIL);
		}

	outCB->serverPort = serverPort;
	outCB->type = strdup(mimeType);
	outCB->callBack = callBack;
	outCB->callBackData = callBackData;
	ListAddEntry(outputCBList,outCB);

	/* get server response */
	line = MCCIGetResponse(serverPort);

#ifdef DEBUG
	printf("SEND OUTPUT reply: %s\n",line);
#endif

	if (!line) {
		return(MCCI_NETWORK_ERROR);
		}
	if (line[0]=='2') {
		return(MCCI_OK);
		}
	else {
		return(MCCI_REQUEST_FAIL);
		}
}

int MCCIDisconnect(serverPort)
MCCIPort serverPort;
{
char buff[80];
int length,lengthToSend;
char *line;
AnchorCallBack *a;
OutputCallBack *outCB;
BrowserViewCallBack *bvCB;

	if (!serverPort) {
		return(MCCI_FAIL);
		}
	if (!MCCIIsConnected(serverPort)) {
		return(MCCI_NETWORK_ERROR);
		}

/*
	This routine could be called due to an error...
	besides, notify the server is redundant. 

	sprintf(buff,"%s\r\n",MCCI_S_DISCONNECT);
	lengthToSend = strlen(buff);
	length = MCCIWrite(serverPort, buff, lengthToSend);

	if (length != lengthToSend) {
		return(MCCI_FAIL);
		}
*/

	NetCloseConnection(serverPort);


	/* remove any anchor callbacks on this port */
	a = (AnchorCallBack *) ListHead(anchorCBList);
	while (a) {
		if (a->serverPort == serverPort) {
			ListDeleteEntry(anchorCBList,a);
			FREE(a);
			a = (AnchorCallBack *) ListCurrent(anchorCBList);
			}
		else {
			a = (AnchorCallBack *) ListNext(anchorCBList);
			}
		}

	/* remove any send output callbacks on this port */
	outCB = (OutputCallBack *) ListHead(outputCBList);
	while(outCB) {
		if (outCB->serverPort == serverPort) {
			ListDeleteEntry(outputCBList,outCB);
			FREE(outCB->type);
			FREE(outCB);
			outCB = (OutputCallBack *) ListCurrent(outputCBList);
			}
		else {
			outCB = (OutputCallBack *) ListNext(outputCBList);
			}
		}

	bvCB = (BrowserViewCallBack *) ListHead(browserViewCBList);
	while(bvCB) {
		if (bvCB->serverPort == serverPort) {
			ListDeleteEntry(browserViewCBList,bvCB);
			FREE(bvCB);
			bvCB = (BrowserViewCallBack *) 
					ListCurrent(browserViewCBList);
			}
		else {
			bvCB = (BrowserViewCallBack*) 
					ListNext(browserViewCBList);
			}
		}

	/* call close connection callback */
	if (serverPort->callBack) {
		(void) (serverPort->callBack)(serverPort,
					serverPort->callBackData);
		}


	return(MCCI_OK);
}


int MCCINBGet(serverPort,uri,output,absRelative,additionalHeader)
/***************************************************************************
* MCCIGet - Resolve a URL 
*	uri - the URL to be resolved 	
*	output - where should the output go?
*		MCCI_DEFAULT		- same as OUTPUT_CURRENT
*		MCCI_OUTPUT_NONE	- Browser shouldn't display
*		MCCI_OUTPUT_CURRENT     - Browser should display in current
*		MCCI_OUTPUT_NEW		- Browser should display in new window
* 	absRelative - url should be treated as either a relative or
*		or absolute link to the current document 
*		MCCI_DEFAULT		- set to absolute
*		MCCI_ABSOLUTE
*		MCCI_RELATIVE
*	additionalHeader - This is a string containing additional HTTP
*		header information to pass to the server.  If this is
*		a standard HTTP GET, this field should be set to NULL.
* Example:
*	MCCINBGet(port,"http://host/file",0,MCCI_ABSOLUTE,0);
***************************************************************************/
MCCIPort serverPort;
char *uri; 
int output;
int absRelative;
char *additionalHeader;
{
char *buff;
char buff2[80];
int length,lengthToSend;
char *line;
int approxSize;

	if (!serverPort) {
		return(MCCI_FAIL);
		}

	if (!MCCIIsConnected(serverPort)) {
		return(MCCI_NETWORK_ERROR);
		}

	approxSize = 256;
	if (!uri) {
		/* required parameter */
		return(MCCI_FAIL);
		}
	else {
		approxSize += strlen(uri);
		}
	if (additionalHeader) {
		approxSize += strlen(additionalHeader);
		}

	if (!(buff = (char *) MALLOC(approxSize))) {
		/* memory problems */
		return(MCCI_OUTOFMEMORY);
		}

	sprintf(buff,"GET URL <%s>",uri);
	switch (output) {
		case MCCI_OUTPUT_NONE:	
				strcat(buff," OUTPUT NONE");
				break;
		case MCCI_OUTPUT_NEW:	
				strcat(buff," OUTPUT NEW");
				break;
		case MCCI_OUTPUT_CURRENT:	
		default: 
				strcat(buff," OUTPUT CURRENT");
				break;
		}
/*
	switch (absRelative) {
		case MCCI_RELATIVE:
				strcat(buff," RELATIVE");
				break;
		case MCCI_ABSOLUTE:
		default:
				strcat(buff," ABSOLUTE");
				break;
		}
*/
	if (additionalHeader) {
		strcat(buff," HEADER\r\n");
		sprintf(buff2,"Content-Length: %d\r\n",
				strlen(additionalHeader));
		strcat(buff,buff2);
		strcat(buff,additionalHeader);
		}
	else {
		strcat(buff,"\r\n");
		}

	lengthToSend = strlen(buff);
	length = MCCIWrite(serverPort, buff, lengthToSend);
	FREE(buff);

	if (length != lengthToSend) {
		/* error sending */
		return(MCCI_FAIL);
		}

	return(MCCI_OK);
}

int MCCIPost(serverPort,url,contentType,data,dataLength,output)
/***************************************************************************
* MCCIPost- Post data to an HTTP server
*       url - the URL to be resolved
* 	contentType: MIME type for data
*	data - the data  to be posted to the HTTP server
*	dataLength - Length of the above data
*       output - where should the output go?
*               MCCI_DEFAULT            - same as OUTPUT_CURRENT
*               MCCI_OUTPUT_NONE        - Browser shouldn't display
*               MCCI_OUTPUT_CURRENT     - Browser should display in current
*               MCCI_OUTPUT_NEW         - Browser should display in new window
*/
MCCIPort serverPort;
char *url; 
char *contentType;
char *data;
int dataLength;
int output;
{
char *line;
char *buff;
int lengthToSend;
int length;

	if (!serverPort) {
		return(MCCI_FAIL);
		}
	if (!MCCIIsConnected(serverPort)) {
		return(MCCI_NETWORK_ERROR);
		}

	if (!(buff = (char *) MALLOC(strlen(url) + 256))) {
		return(MCCI_OUTOFMEMORY);
		}

	sprintf(buff, "%s <%s> %s", MCCI_S_POST, url, contentType);
	switch(output) {
		case MCCI_OUTPUT_NEW:
			strcat(buff," OUTPUT NEW");
			break;
		case MCCI_OUTPUT_NONE:
			strcat(buff," OUTPUT NONE");
			break;
		case MCCI_OUTPUT_CURRENT:
		case MCCI_DEFAULT:
			strcat(buff," OUTPUT CURRENT");
			break;
		}
	strcat(buff,"\r\n");

	lengthToSend = strlen(buff);
	length = MCCIWrite(serverPort, buff, lengthToSend);
	if (length != lengthToSend) {
		return(MCCI_FAIL);
		}
#ifdef DEBUG
	printf("Post Request: %s",buff);
#endif

	sprintf(buff, "Content-Length: %d \r\n",dataLength);
	lengthToSend = strlen(buff);
	length = MCCIWrite(serverPort, buff, lengthToSend);
	if (length != lengthToSend) {
		return(MCCI_FAIL);
		}

	length = MCCIWrite(serverPort, data, dataLength);
	if (length != dataLength) {
		return(MCCI_FAIL);
		}
#ifdef DEBUG
	printf("%s%s\n",buff,data);
#endif
	/* get server response */
	line = MCCIGetResponse(serverPort);

#ifdef DEBUG
	printf("POST reply: %s\n",line);
#endif
	free(buff);

	if (!line) {
		return(MCCI_NETWORK_ERROR);
		}
	if (line[0]=='2') {
		return(MCCI_OK);
		}
	else {
		return(MCCI_REQUEST_FAIL);
		}
} /* MCCIPost() */




int MCCISendBrowserView(serverPort,status,callBack,callBackData)
/***************************************************************************
 *  MCCISendBrowserView()-  This routine requests the web browser to send
 *		a copy of what would normally be displayed in the browser  
 *		window.  This typically includes text/html and any inline
 *		images.  The callbacks are called as data comes in.
 *	status:  1 to turn on, 0 turn off.
 *
 *		The call back is of the form:
 *	
 *		
 *	void SendBrowserViewCallBack(char *url, char *mimeType,
 *					char *data, int dataLength, 
 *					void *callBackData) 
 */

MCCIPort serverPort;
int status;
void (*callBack)();
void *callBackData;
{
char *line;
char buff[80];
int lengthToSend;
int length;
BrowserViewCallBack *bvcb;

	if (!serverPort) {
		return(MCCI_FAIL);
		}
	if (!MCCIIsConnected(serverPort)) {
		return(MCCI_NETWORK_ERROR);
		}


	if (status) {
		sprintf(buff,"%s %s\r\n",MCCI_S_SEND, MCCI_S_BROWSERVIEW);
		}
	else {
		sprintf(buff,"%s %s %s\r\n",MCCI_S_SEND, MCCI_S_BROWSERVIEW, 
					MCCI_S_STOP);
		}

	lengthToSend = strlen(buff);
	length = MCCIWrite(serverPort, buff, lengthToSend);
	if (length != lengthToSend) {
		return(MCCI_FAIL);
		}

	if (!status) {
		/* remove the callback from callback list */

		bvcb = (BrowserViewCallBack *) 
					ListHead(browserViewCBList);
		while(bvcb) {
			if ((bvcb->serverPort == serverPort) &&
			    (bvcb->callBack == callBack) &&
			    (bvcb->callBackData == callBackData)) {
				ListDeleteEntry(browserViewCBList,bvcb);
				bvcb = (BrowserViewCallBack *) 
					ListCurrent(browserViewCBList);
				}
			else {
				bvcb = (BrowserViewCallBack *) 
					ListNext(browserViewCBList);
				}
			}
		}
	else {
		/* add callback to callback list */
		if (!(bvcb = (BrowserViewCallBack *)
			MALLOC(sizeof(BrowserViewCallBack)))) {
			return(MCCI_OUTOFMEMORY);
			}
		bvcb->serverPort = serverPort;
		bvcb->callBack = callBack;
		bvcb->callBackData = callBackData;
		ListAddEntry(browserViewCBList,bvcb);
		}

	/* get response from browser */
	line = MCCIGetResponse(serverPort);

#ifdef DEBUG
	printf("SEND BROWSERVIEW reply: %s\n",line);
#endif
	if (!line) {
		return(MCCI_NETWORK_ERROR);
		}
	if (line[0]=='2') {
		return(MCCI_OK);
		}
	else {
		return(MCCI_REQUEST_FAIL);
		}
}
