/****************************************************************************
 * NCSA Mosaic for the X Window System                                      *
 * Software Development Group                                               *
 * National Center for Supercomputing Applications                          *
 * University of Illinois at Urbana-Champaign                               *
 * 605 E. Springfield, Champaign IL 61820                                   *
 * mosaic@ncsa.uiuc.edu                                                     *
 *                                                                          *
 * Copyright (C) 1993, Board of Trustees of the University of Illinois      *
 *                                                                          *
 * NCSA Mosaic software, both binary and source (hereafter, Software) is    *
 * copyrighted by The Board of Trustees of the University of Illinois       *
 * (UI), and ownership remains with the UI.                                 *
 *                                                                          *
 * The UI grants you (hereafter, Licensee) a license to use the Software    *
 * for academic, research and internal business purposes only, without a    *
 * fee.  Licensee may distribute the binary and source code (if released)   *
 * to third parties provided that the copyright notice and this statement   *
 * appears on all copies and that no charge is associated with such         *
 * copies.                                                                  *
 *                                                                          *
 * Licensee may make derivative works.  However, if Licensee distributes    *
 * any derivative work based on or derived from the Software, then          *
 * Licensee will (1) notify NCSA regarding its distribution of the          *
 * derivative work, and (2) clearly notify users that such derivative       *
 * work is a modified version and not the original NCSA Mosaic              *
 * distributed by the UI.                                                   *
 *                                                                          *
 * Any Licensee wishing to make commercial use of the Software should       *
 * contact the UI, c/o NCSA, to negotiate an appropriate license for such   *
 * commercial use.  Commercial use includes (1) integration of all or       *
 * part of the source code into a product for sale or license by or on      *
 * behalf of Licensee to third parties, or (2) distribution of the binary   *
 * code or source code to third parties that need it to utilize a           *
 * commercial product sold or licensed by or on behalf of Licensee.         *
 *                                                                          *
 * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR   *
 * ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED          *
 * WARRANTY.  THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE    *
 * USERS OF THIS SOFTWARE.                                                  *
 *                                                                          *
 * By using or copying this Software, Licensee agrees to abide by the       *
 * copyright law and all other applicable laws of the U.S. including, but   *
 * not limited to, export control laws, and the terms of this license.      *
 * UI shall have the right to terminate this license immediately by         *
 * written notice upon Licensee's breach of, or non-compliance with, any    *
 * of its terms.  Licensee may be held legally responsible for any          *
 * copyright infringement that is caused or encouraged by Licensee's        *
 * failure to abide by the terms of this license.                           *
 *                                                                          *
 * Comments and questions are welcome and can be sent to                    *
 * mosaic-x@ncsa.uiuc.edu.                                                  *
 ****************************************************************************/
#include "../config.h"
#include "mosaic.h"
#include <sys/types.h>
#if defined(__DECC) && (__VMS_VER >= 70000000)
#define _VMS_V6_SOURCE
#endif /* avoid __UTC_STAT in VMS V7.0, GEC */
#include <sys/stat.h>
#if defined(__DECC) && (__VMS_VER >= 70000000)
#undef _VMS_V6_SOURCE
#endif

#include "memStuffForPipSqueeks.h"
#include "cci.h"
#include "cciBindings.h"
#include "cciBindings2.h"
#include "cciServer.h"
#include "accept.h"
#include "../libnut/str-tools.h"
#include "support.h"

static ListenAddress listenPort;

int MCCIanchorcached = 0;       /* Another ugly ADC hack ZZZZ */

#ifndef DISABLE_TRACE
extern int cciTrace;
#endif

#ifndef VMS   /* PGE, conflict with URL-UTILS.C */
extern char *GetLine();
#else
extern char *NNTPGetLine();
#endif

int MCCIReturnListenPortSocketDescriptor()
{
	return(listenPort);
}

MCCICloseConnection(clientPort)
MCCIPort clientPort;
{

#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"CloseConnection(): I've been called\n");
	}
#endif

	MoCCITerminateAConnection(clientPort);
	NetCloseConnection(clientPort);

}

MCCICloseAcceptPort()
{
	NetCloseAcceptPort(listenPort);
}

int MCCIServerInitialize(portNumber)
/* return 0 on failure */
/* return listenPort on success */
int portNumber;
{

	listenPort = NetServerInitSocket(portNumber);

	if (listenPort == -1)
		return(0);
	else
		return(1);

}

int MCCIGetSocketDescriptor(clientPort)
/* 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 clientPort;
{
        return(NetGetSocketDescriptor(clientPort));
}



int MCCISendResponseLine(client,code,text)
MCCIPort client;
int code; 	/* response code */
char *text; 	/* text response (no newline)*/
{
int length;
char *buff;

	if (!(buff = (char *) MALLOC(strlen(text) + 7))) {
		/* out of memory */
		return(MCCI_OUTOFMEMORY);
		}

	sprintf(buff, "%d %s\r\n", code, text);
	length = strlen(buff);
	if (length != NetServerWrite(client, buff, length)) {
		return(MCCI_FAIL);
		}

	return(MCCI_OK);
}

MCCIPort MCCICheckAndAcceptConnection()
/* return NULL if no connection */
/* return a MCCIPort if connected */
{
MCCIPort client;

	if (NetIsThereAConnection(listenPort)){
		client = NetServerAccept(listenPort);
		}
	else {
		return(NULL);
		}

#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"Current cci connections: max number=%d, currentNumber=%d\n",
				MoCCIMaxNumberOfConnectionsAllowed(),
				MoCCICurrentNumberOfConnections());
	}
#endif

	if (client && MoCCIMaxNumberOfConnectionsAllowed()) {
		/* if maxNumConnections == 0, then no limit */
		if ((MoCCICurrentNumberOfConnections() + 1) >
		    MoCCIMaxNumberOfConnectionsAllowed()) {
			MCCISendResponseLine(client,MCCIR_MAX_CONNECTIONS,
			"Maximum number of allowed CCI connections exceeded");
			MCCICloseConnection(client);
			return(NULL);

			}
		}
	return(client);
}



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

int MCCIReadContent(client,content)
/* read from client. Next line should contain Content-Length: value 
   and then the content body. Returns the number of chars read. 
   0 on error. space is allocated and placed into 'content'*/
MCCIPort client;
char **content;
{
char *s;
int length;
char garbage;
char *line;
int x;

#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"MCCIReadContent(): Just entered...about to GetLine()\n");
	}
#endif
	*content = (char *) 0;
#ifndef VMS   /* PGE, conflict with URL-UTILS.C */
	line = GetLine(client);
#else
	line = NNTPGetLine(client);
#endif
#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr, "MCCIReadContent(): read line \"%s\"\n", line);
	}
#endif

	/* read content length */
	s = strchr(line,':'); /* skip to length */
	if ((!s) || (!strlen(s))) {
		/* bad value */
		return(0);
		}
	s++;
	length = atoi(s);
	if ((length > 10000000) || (length < 0)) {
		/* bad value */
		return(0);
		}
	if (!((*content) = (char*) MALLOC(length+1))) {
		/* to recover protocol, this needs to be read in
			any way before returning, but if we're out of memory,
			it's likely hopeless anyway */
		for (x = 0; x < length; x++) {
			if (!NetRead(client,&garbage,1)) {
				break;
				}
			}
		return(0);
		}
#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"ReadContent(): about to read %d bytes\n",length);
	}
#endif

	length = ReadBuffer(client,*content,length);
	(*content)[length]='\0';
	return(length);
}

int MCCIHandleSend(client,line,retText)
     /* take care of the SEND request parsing */
     /* return value to send back to cci client */
     MCCIPort client;
     char *line; 	/* GET request line */
     char *retText;	/* text to be returned to cci client */
{
  int retCode;
  char *s,*end,*start;
  
  if (!(s = strchr(line, ' ')))
    { /* skip over SEND */
      strcpy(retText, "Error in protocol");
      return(MCCIR_ERROR);
    }
  
  
  GetWordFromString(s, &start, &end);
  if (!my_strncasecmp(start, MCCI_S_ANCHOR, strlen(MCCI_S_ANCHOR)))
    {
/* SEND ANCHOR */
      s = end;
      GetWordFromString(s,&start,&end);
      /* ejb 9 March 1995 added BEFORE and AFTER cases */
      if (start && (start != end))
/* SEND ANCHOR STOP => turn off SEND ANCHOR */
	if (!my_strncasecmp(start,MCCI_S_STOP,strlen(MCCI_S_STOP))) 
	  MCCIRequestSendAnchor(&retCode,retText,client,0);
	else 
/* SEND ANCHOR BEFORE => Mosaic sends anchor, BEFORE done getting */
	  if (!my_strncasecmp(start,MCCI_S_BEFORE,strlen(MCCI_S_BEFORE)))
	    MCCIRequestSendAnchor(&retCode,retText,client,MCCI_SEND_BEFORE);
	  else
/* SEND ANCHOR AFTER => Mosaic sends anchor, AFTER done getting */
	    if (!my_strncasecmp(start,MCCI_S_AFTER,strlen(MCCI_S_AFTER)) ||
		(!(start)))
	      MCCIRequestSendAnchor(&retCode,retText,client,MCCI_SEND_AFTER);
	    else
/* SEND ANCHOR HANDLER => Mosaic sends anchor first then lets cci handle it  ADC ZZZ */
               if (!my_strncasecmp(start,MCCI_S_HANDLER,strlen(MCCI_S_HANDLER)) ||
                   (!(start)))
                 MCCIRequestSendAnchor(&retCode,retText,client,MCCI_SEND_HANDLER);
	       else
/* SEND ANCHOR XXXXX => Mosaic doesn't know what to do with it */
	          {
		    /* we don't know what to do with it. */
		    strcpy(retText,"what\'s this stuff after ANCHOR?");
		    return(MCCIR_ERROR);
	          }
/* SEND ANCHOR => Mosaic sends anchor, AFTER done getting*/
      else
	MCCIRequestSendAnchor(&retCode,retText,client,MCCI_SEND_AFTER);
    }
  else if (!my_strncasecmp(start,MCCI_S_OUTPUT,strlen(MCCI_S_OUTPUT))) {
/* SEND OUTPUT */
		s = end;
		GetWordFromString(s,&start,&end);
		if (start && (start != end)) {
			if (!my_strncasecmp(start, MCCI_S_STOP,
						strlen(MCCI_S_STOP))){
				/* SEND OUTPUT STOP*/
				s = end;
				/* check for mime type */
				GetWordFromString(s,&start,&end);
				if (start && (start != end)) {
					*end = '\0';
					MCCIRequestSendOutput(&retCode,retText,
							client,0,start);
					}
				else {
					/* no output type... so all types */
					MCCIRequestSendOutput(&retCode,retText,
							client,0,(char *)0);
					}
				}
			else {
				/* SEND OUTPUT type */
				*end = '\0';
				MCCIRequestSendOutput(&retCode,retText,
							client,1,start);
				}
			
			}
		else {
			/* "SEND OUTPUT" so send it all */
			MCCIRequestSendOutput(&retCode,retText,
							client,1,(char *)0);
			}
		}
	
  else if (!my_strncasecmp(start,MCCI_S_BROWSERVIEW,strlen(MCCI_S_BROWSERVIEW))){
/* SEND BROWSERVIEW */
		s = end;
		GetWordFromString(s,&start,&end);
		if (start && (start != end)) {
			if (!my_strncasecmp(start, MCCI_S_STOP,
						strlen(MCCI_S_STOP))){
				/* SEND BROWSERVIEW STOP*/
				MCCIRequestSendBrowserView(&retCode,retText,
							client,0);
				}
			else {
				/* SEND BROWSERVIEW garbageHere */
				MCCIRequestSendBrowserView(&retCode,retText,
							client,1);
				}
			}
		else {
			/* SEND BROWSERVIEW*/
			MCCIRequestSendBrowserView(&retCode,retText,
							client,1);
			}
		}
   
  else if (!my_strncasecmp(start,MCCI_S_EVENT,strlen(MCCI_S_EVENT))){
/* SEND EVENT */
		s = end;
		GetWordFromString(s,&start,&end);
		if (start && (start != end)) {
			if (!my_strncasecmp(start, MCCI_S_STOP,
						strlen(MCCI_S_STOP))){
				/* SEND EVENT STOP*/
				MCCIRequestSendEvent(&retCode,retText,
							client,0);
				}
			else {
				/* SEND EVENT garbageHere */
				MCCIRequestSendEvent(&retCode,retText,
							client,1);
				}
			}
		else {
			/* SEND EVENT*/
			MCCIRequestSendEvent(&retCode,retText,
							client,1);
			}
		}

	else {
/* SEND ??? */
		strcpy(retText,"SEND what???");
		return(MCCIR_ERROR);
		}
	return(retCode);
}


int MCCIHandlePost(client,line,retText)
/* take care of the Post request parsing */
/* return value to send back to cci client */
MCCIPort client;
char *line; 	/* GET request line */
char *retText;	/* text to be returned to cci client */
{
char *s,*end;
char *url;
char *postData;
int postDataLength;
char *mimeType;
int retCode;
int output;
char *tmpend;
char *next;

#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"MCCIHandlePost(): parsing line: \"%s\"\n",line);
	}
#endif

	if (!(s = strchr(line,' '))){ /* skip over POST */
		strcpy(retText,"Error in protocol");
		return(MCCIR_ERROR);
		}

	GetWordFromString(s,&url,&end); /* Get <url> */
	if ((!url) || (url == end)) {
		strcpy(retText,"Hey bud, where's the URL for POST?");
		return(MCCIR_ERROR);
		}
	s = end;
	url++; /* skip over '<' */
	end--; /* backup over '>' */
	*end = '\0'; /* terminate url */

	url = strdup(url);

#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"MCCIHandlePost(): extracted url: \"%s\"\n",url);
	}
#endif

	GetWordFromString(s,&mimeType,&end); /* Get Content Type*/
	if ((!mimeType) || (mimeType == end)) {
		strcpy(retText,"No Content-Type?");
		return(MCCIR_ERROR);
		}
	tmpend = end;

	s = end;
	GetWordFromString(s,&next,&end); /* move pointer to OUTPUT */

	*tmpend = '\0'; /* terminate the content-type */
	mimeType = strdup(mimeType);

#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"MCCIHandlePost(): mimeType: \"%s\"\n",mimeType);
	}
#endif

	output = MCCI_DEFAULT;
	if (next && (next != end)) {
	    if (!my_strncasecmp(next,MCCI_S_OUTPUT,
				strlen(MCCI_S_OUTPUT))) {
		/* output tag */
		s = end;
		GetWordFromString(s,&next,&end);
		if (next && (next != end)) {
			if (!my_strncasecmp(next,MCCI_S_CURRENT,strlen(MCCI_S_CURRENT))) {
				output = MCCI_OUTPUT_CURRENT;
				}
			else if (!my_strncasecmp(next,MCCI_S_NEW,strlen(MCCI_S_NEW))) {
				output = MCCI_OUTPUT_NEW;
				}
			else if (!my_strncasecmp(next,MCCI_S_NONE,strlen(MCCI_S_NONE))) {
				output = MCCI_OUTPUT_NONE;
				}
			else {
				output = MCCI_DEFAULT;
				}
			s = end;
			GetWordFromString(s,&next,&end);
			}
		    }
	    }
	else {
		output = MCCI_DEFAULT; 
		}

#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"POST url = \"%s\",mimeType=\"%s\",output=%d\n",
					url,mimeType,output);
	}
#endif

	postDataLength = MCCIReadContent(client,&postData);
	if (postDataLength < 1) {
		strcpy(retText,"No data for POST");
		return(MCCIR_ERROR);
		}

#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"Got the data, datalength = %d\n",postDataLength);
	}
#endif

	MCCIRequestPost(client,&retCode, retText, url, mimeType, 
				postData, postDataLength, output);

	free(url);
	free(mimeType);
	
	return(retCode);
}


int MCCIHandleDisplay(client,line,retText)
/* take care of the Display request parsing */
/* return value to send back to cci client */
MCCIPort client;
char *line; 	/* GET request line */
char *retText;	/* text to be returned to cci client */
{
char *s,*end;
char *url;
char *displayData;
int displayDataLength;
char *mimeType;
int retCode;
int output;
char *tmpend;
char *next;


#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"MCCIHandleDisplay(): parsing line: \"%s\"\n",line);
	}
#endif

	if (!(s = strchr(line, ' '))){ /* skip over DISPLAY */
		strcpy(retText,"Error in protocol");
		return(MCCIR_ERROR);
		}

	GetWordFromString(s, &url, &end); /* Get <url> */
	if ((!url) || (url == end)) {
		strcpy(retText, "Hey bud, where's the URL for Display?");
		return(MCCIR_ERROR);
		}
	s = end;
	url++; /* skip over '<' */
	end--; /* backup over '>' */
	*end = '\0'; /* terminate url */

	url = strdup(url);

#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"MCCIHandleDisplay(): extracted url: \"%s\"\n",url);
	}
#endif

	GetWordFromString(s,&mimeType,&end); /* Get Content Type*/
	if ((!mimeType) || (mimeType == end)) {
		strcpy(retText,"No Content-Type?");
		return(MCCIR_ERROR);
		}
	tmpend = end;

	s = end;
	GetWordFromString(s,&next,&end); /* move pointer to OUTPUT */

	*tmpend = '\0'; /* terminate the content-type */
	mimeType = strdup(mimeType);

#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"MCCIHandleDisplay(): mimeType: \"%s\"\n",mimeType);
	}
#endif

	output = MCCI_DEFAULT;
	if (next && (next != end)) {
	    if (!my_strncasecmp(next,MCCI_S_OUTPUT,
				strlen(MCCI_S_OUTPUT))) {
		/* output tag */
		s = end;
		GetWordFromString(s,&next,&end);
		if (next && (next != end)) {
			if (!my_strncasecmp(next,MCCI_S_CURRENT,strlen(MCCI_S_CURRENT))) {
				output = MCCI_OUTPUT_CURRENT;
				}
			else if (!my_strncasecmp(next,MCCI_S_NEW,strlen(MCCI_S_NEW))) {
				output = MCCI_OUTPUT_NEW;
				}
			else if (!my_strncasecmp(next,MCCI_S_NONE,strlen(MCCI_S_NONE))) {
				output = MCCI_OUTPUT_NONE;
				}
			else {
				output = MCCI_DEFAULT;
				}
			s = end;
			GetWordFromString(s,&next,&end);
			}
		    }
	    }
	else {
		output = MCCI_DEFAULT; 
		}

#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"Display url = \"%s\",mimeType=\"%s\",output=%d\n",
					url,mimeType,output);
	}
#endif

	/* MCCIReadContent will malloc space for displayData */
	displayDataLength = MCCIReadContent(client,&displayData);
	if (displayDataLength < 1) {
		strcpy(retText,"No data for DISPLAY");
		return(MCCIR_ERROR);
		}

#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"Got the data, datalength = %d\n",displayDataLength);
	}
#endif

	MCCIRequestDisplay(client, &retCode, retText, url, mimeType, 
				displayData, displayDataLength, output);

	free(url);
	free(mimeType);
	
	return(retCode);
}


int MCCIHandleGet(client,line,retText)
/* take care of the GET request parsing */
/* return value to send back to cci client */
MCCIPort client;
char *line; 	/* GET request line */
char *retText;	/* text to be returned to cci client */
{
char *s;
char *url/*,*start*/,*end,*next;
int output/*,absRel*/;
char *headerExt;
int headerExtLength;
int retCode;

	output = MCCI_DEFAULT;
	headerExt = (char *) 0;
 	headerExtLength = 0;
	
	if (!(s = strchr(line, ' '))){ /* skip over GET */
		strcpy(retText, "Error in protocol");
		return(MCCIR_ERROR);
		}
	GetWordFromString(s,&url,&end); /* URL */
	if (my_strncasecmp(url,"URL",3)) {
		strcpy(retText,"No URL?");
		return(MCCIR_ERROR);
		}
	s = end;
	GetWordFromString(s,&url,&end); /* actual <url> */
	if ((!url) || (url == end)) {
		strcpy(retText,"Hey bud, where's the URL?");
		return(MCCIR_ERROR);
		}
	s = end;
	url++; /* skip over '<' */
	end--; /* backup over '>' */
	*end = '\0'; /* terminate url */

	url = strdup(url);
#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"GetURL: URL=\"%s\"\n",url);
	}
#endif

	GetWordFromString(s,&next,&end);
	if (next && (next != end)) {
	    if (!my_strncasecmp(next,MCCI_S_OUTPUT,
				strlen(MCCI_S_OUTPUT))) {
		/* output tag */
		s = end;
		GetWordFromString(s,&next,&end);
		if (next && (next != end)) {
			if (!my_strncasecmp(next,MCCI_S_CURRENT,strlen(MCCI_S_CURRENT))) {
				output = MCCI_OUTPUT_CURRENT;
				}
			else if (!my_strncasecmp(next,MCCI_S_NEW,strlen(MCCI_S_NEW))) {
				output = MCCI_OUTPUT_NEW;
				}
			else if (!my_strncasecmp(next,MCCI_S_NONE,strlen(MCCI_S_NONE))) {
				output = MCCI_OUTPUT_NONE;
				}
			else {
				output = MCCI_OUTPUT_CURRENT;
				}
			s = end;
			GetWordFromString(s,&next,&end);
			}
		    }
	    }
#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"pt #2 GetURL: URL=\"%s\"\n",url);
	}
#endif

	if (next && (next != end)) {
	    if (!my_strncasecmp(next,MCCI_S_HEADER,strlen(MCCI_S_HEADER))) {
		/* get header extention */
		    headerExtLength = MCCIReadContent(client,&headerExt);
		    }
		}
#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"pt #3 GetURL: URL=\"%s\"\n",url);
	}
#endif
        /* set flag to be caught in MoCCISendAnchorToCCI */
	cciStatPreventSendAnchor(client, url); 
	MCCIRequestGetURL(&retCode,retText,url,output,headerExt);
	if ((headerExtLength > 0) && (headerExt)) {
		FREE(headerExt);
		}
	free(url);
	return(retCode);
}


int MCCIHandleDoCommand(client,line,retText)
/* take care of the GET request parsing */
/* return value to send back to cci client */
MCCIPort client;
char *line; 	/* GET request line */
char *retText;	/* text to be returned to cci client */
{
char *s;
char *end, *tmpend ;
char *command;
char *parameter;
int retCode;

	/* expected line, DOCOMMAND command parameters... */
#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"line is %s\n", line);
	}
#endif

	if (!(s = strchr(line,' '))){ /* skip over DOCOMMAND */
		strcpy(retText,"Error in protocol");
		return(MCCIR_ERROR);
		}

	GetWordFromString(s,&command,&end); /* Get command */
	if ((!command) || (command == end)) {
		strcpy(retText,"You need a command");
		return(MCCIR_ERROR);
		}
	s = end;
	tmpend = end;

#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"MCCIHandleDisplay(): extracted command: \"%s\"\n",command);
	}
#endif

	parameter = strdup(s);

	*tmpend = '\0';
	command = strdup(command);

	MCCIRequestDoCommand(&retCode,retText,command, parameter);

#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"MCCIHandleDisplay(): retCode: %d -- retText: [%s]\n",retCode,retText);
	}
#endif

	return(retCode);
}


int MCCIHandleForm(client,line,retText)
/* take care of the Form request parsing */
/* return value to send back to cci client */
MCCIPort client;
char *line; 	/* GET request line */
char *retText;	/* text to be returned to cci client */
{
char *s;
char *actionID,*end,*next,*startstop, *tmp;
int output/*,absRel*/;
int retCode;
int status;

	if (!(s = strchr(line,' '))){ /* skip over FORM */
		strcpy(retText,"Error in protocol");
		return(MCCIR_ERROR);
		}

	GetWordFromString(s,&actionID,&end); /* actionID */
	if ((!actionID) || (actionID == end)) {
		strcpy(retText,"Hey bud, where's the actionID?");
		return(MCCIR_ERROR);
		}
	s = end;
	actionID = strdup(actionID);
	tmp = strchr(actionID, ' ');
	*tmp = '\0';


#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"GetURL: actionID=[%s]\n",actionID);
	}
#endif

	GetWordFromString(s,&next,&end);
	if (next && (next != end)) {
		if (!my_strncasecmp(next,
			MCCI_S_STOP, strlen(MCCI_S_STOP))) {
			status = 0;
			}
		else if(!my_strncasecmp(next,
			MCCI_S_START, strlen(MCCI_S_START))){
			status = 1;
			}
		else {
			return(MCCIR_ERROR);
			}
		}
	else
		return(MCCIR_ERROR);

#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"  actionID=\"%s\"\n",actionID);
	}
#endif

        /* set flag to be caught in MoCCISendAnchorToCCI */
/*
	cciStatPreventSendAnchor(client, url); 
*/
	MCCIRequestForm(client, &retCode,retText,actionID,status);
		
/*  	free(actionID);
*/
	return(retCode);
}

#ifdef NEW
#define NUM_ANNO_CODES 3
static int annoCodes[NUM_ANNO_CODES] = {MCCI_PUBLIC_ANNOTATION, MCCI_GROUP_ANNOTATION, MCCI_PRIVATE_ANNOTATION};
static char* annoStrings[NUM_ANNO_CODES] = {MCCI_S_PUBLIC_ANN, MCCI_S_GROUP_ANN, MCCI_S_PRIVATE_ANN};
#else /* NEW */

#endif /* NEW */
int MCCIHandleGetAnnotation(client,line,retText,retData,retDataLength)
MCCIPort client;
char *line; 	/* GET request line */
char *retText;	/* text to be returned to cci client */
char **retData;
int *retDataLength;
{
char *s;
char *end;
char *type;
char *url;
int annotationType;
int retCode;

	if (!(s = strchr(line,' '))){ /* skip over GET */
		strcpy(retText,"Error in protocol");
		return(MCCIR_ERROR);
		}

	annotationType = 0;
	GetWordFromString(s,&type,&end); /* Get type (pub,priv,group)*/
	if (!my_strncasecmp(type,MCCI_S_PUBLIC_ANN,strlen(MCCI_S_PUBLIC_ANN))) {
		annotationType = MCCI_PUBLIC_ANNOTATION;
		}
	else if (!my_strncasecmp(type,MCCI_S_GROUP_ANN,
					strlen(MCCI_S_GROUP_ANN))) {
		annotationType = MCCI_GROUP_ANNOTATION;
		}
	else if (!my_strncasecmp(type,MCCI_S_PRIVATE_ANN,
					strlen(MCCI_S_PRIVATE_ANN))) {
		annotationType = MCCI_PRIVATE_ANNOTATION;
		}
	else if (!my_strncasecmp(type,MCCI_S_ALL_ANN,
					strlen(MCCI_S_ALL_ANN))) {
		annotationType = MCCI_ALL_ANNOTATION;
		}
	else {
		strcpy(retText,"PUBLIC, PRIVATE, GROUP or ALL annotation requests only");
		return(MCCIR_ERROR);
		}

	s = end;
	GetWordFromString(s,&url,&end); /* actual <url> */
	if ((!url) || (url == end)) {
		strcpy(retText,"Hey bud, where's the URL?");
		return(MCCIR_ERROR);
		}
	s = end;
	url++; /* skip over '<' */
	end--; /* backup over '>' */
	*end = '\0'; /* terminate url */

	url = strdup(url);
#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"GetAnnotation: URL=\"%s\"\n",url);
	}
#endif

#ifdef NEW
       MCCISendResponseLine(client,retCode,retText);
       for (int index = 0; index < NUM_ANNO_CODES; ++index) {
	 if (!my_strncasecmp(type,annoStrings[index],
			  strlen(annoStrings[index])) ||
	     !my_strncasecmp(type,MCCI_S_ALL_ANN,
					strlen(MCCI_S_ALL_ANN))) {
	   MCCIRequestGetAnnotation(&retCode,retText,retData,retDataLength,
			url,annoCodes[index]);
	 }
	 else
	   MCCIGetAnnotationDummyLine(&retCode,retText,retData,retDataLength,annoCodes[index]);

		if (retDataLength != 
		    NetServerWrite(client,retData,retDataLength)) {
		  return(MCCI_FAIL);
		}
#else /* NEW */
	MCCIRequestGetAnnotation(&retCode,retText,retData,retDataLength,
			url,annotationType);

#endif /* NEW */
	free(url);
	return(retCode);
}

int MCCIHandlePutAnnotation(client,line,retText)
MCCIPort client;
char *line; 	/* PUT request line */
char *retText;	/* text to be returned to cci client */
{
char *s;
char *end;
char *type;
char *url;
char *annotation;
int annotationLength;
int retCode;
int annotationType;

	if (!(s = strchr(line,' '))){ /* skip over GET */
		strcpy(retText,"Error in protocol");
		return(MCCIR_ERROR);
		}

	annotationType = 0;
	GetWordFromString(s,&type,&end); /* Get type (pub,priv,group)*/
	if (!my_strncasecmp(type,MCCI_S_PUBLIC_ANN,strlen(MCCI_S_PUBLIC_ANN))) {
		annotationType = MCCI_PUBLIC_ANNOTATION;
		}
	else if (!my_strncasecmp(type,MCCI_S_GROUP_ANN,
					strlen(MCCI_S_GROUP_ANN))) {
		annotationType = MCCI_GROUP_ANNOTATION;
		}
	else if (!my_strncasecmp(type,MCCI_S_PRIVATE_ANN,
					strlen(MCCI_S_PRIVATE_ANN))) {
		annotationType = MCCI_PRIVATE_ANNOTATION;
		}
	else {
		strcpy(retText,"PUBLIC, PRIVATE or GROUP put annotations only");
		return(MCCIR_ERROR);
		}

	s = end;
	GetWordFromString(s,&url,&end); /* actual <url> */
	if ((!url) || (url == end)) {
		strcpy(retText,"Hey bud, where's the URL?");
		return(MCCIR_ERROR);
		}
	s = end;
	url++; /* skip over '<' */
	end--; /* backup over '>' */
	*end = '\0'; /* terminate url */

	url = strdup(url);
#ifndef DISABLE_TRACE
	if (cciTrace) {
		fprintf(stderr,"GetURL: URL=\"%s\"\n",url);
	}
#endif
	annotationLength = MCCIReadContent(client,&annotation);
	if (annotationLength < 1) {
		strcpy(retText,"No annotation data");
		return(MCCIR_ERROR);
		}
	MCCIRequestPutAnnotation(&retCode,retText,annotationType,url,
						annotation,annotationLength);
	return(retCode);
}

int MCCIHandleFileToURL(client,line,retText)
MCCIPort client;
char *line;
char *retText;
{
char *fileName;
char *url;
char *s;
char *end;
int retCode;

	if (!(s = strchr(line,' '))){ /* skip over FILETOURL*/
		strcpy(retText,"Error in protocol");
		return(MCCIR_ERROR);
		}

	GetWordFromString(s,&fileName,&end); /* <fileName> */
	if ((!fileName) || (fileName == end)) {
		strcpy(retText,"I need a filename to translate");
		return(MCCIR_ERROR);
		}
	fileName++; /* skip over '<' */
	end--; /* backup over '>' */
	*end = '\0'; /* terminate fileName */

	fileName = strdup(fileName);

	MCCIRequestFileToURL(&retCode,retText,fileName);

	free(fileName);

	return(retCode);

}


int MCCIHandleInput(client)
/* read input from the client and do something with it */
/* return 1 on success, 0 on failure or disconnect */
MCCIPort client;
{
int retCode;
char retText[MCCI_MAX_RETURN_TEXT];
char *blah;
char **retData = &blah;
int  retDataLength = 0;
char *line;

#ifndef VMS   /* PGE, conflict with URL-UTILS.C */
	line = GetLine(client);
#else
	line = NNTPGetLine(client);
#endif

#ifndef DISABLE_TRACE
	if (cciTrace) {
		if (line)
			fprintf(stderr,"Server Read: %s\n",line);
		else
			fprintf(stderr,"Server Read: NULL line\n");
	}
#endif

	if (!line) {
		/* error or disconnect */
		MCCICloseConnection(client);
		return(0);
		}

/* parse the request */
/* to save speed & memory this parse is destructive to the text in 'line' */

	if (!my_strncasecmp(line,MCCI_S_DISCONNECT,strlen(MCCI_S_DISCONNECT))) {
                MCCISendResponseLine(client,MCCIR_DISCONNECT_OK,
                        "DISCONNECT request received");
		return(0);
		}
/* This has to go ahead of the simple get or else it gets snagged */
	else if (!my_strncasecmp(line,MCCI_S_GETANNOTATION,
					strlen(MCCI_S_GETANNOTATION))) {
		retDataLength = 0;

/*SWP -- 7/11/95
 * In the Original line, &retData is passed. retData is a char * to begin with
 * and it eventually gets assigned the value from mo_fetch_personal_annotations
 * which sends back all of the annotations for the specified url in one char
 * * string. Not an array of strings.
 */
		retCode = MCCIHandleGetAnnotation(client,line,retText,retData,
				&retDataLength);
/*Original
		retCode = MCCIHandleGetAnnotation(client,line,retText,&retData,
				&retDataLength);
*/
		MCCISendResponseLine(client,retCode,retText);
		if (retDataLength != 
		    NetServerWrite(client,*retData,retDataLength)) {
		  return(MCCI_FAIL);
		}

/* FINISHME */	/**** if retDataLength, send data */
		/*** if retDataLength, free retData?? */

		if (retDataLength>0) {
			free(*retData);
			}

		}
	else if (!my_strncasecmp(line,MCCI_S_GET,strlen(MCCI_S_GET))) {
		retCode = MCCIHandleGet(client,line,retText);
		MCCISendResponseLine(client,retCode,retText);
		}

	else if (!my_strncasecmp(line,MCCI_S_DOCOMMAND,strlen(MCCI_S_DOCOMMAND))){
		retCode = MCCIHandleDoCommand(client,line,retText);
		MCCISendResponseLine(client,retCode,retText);
		}

	else if (!my_strncasecmp(line,MCCI_S_DISPLAY,strlen(MCCI_S_DISPLAY))) {
		retCode = MCCIHandleDisplay(client, line, retText);
                MCCISendResponseLine(client, retCode,
                        "DISPLAY request received by Mosaic");
		}
	else if (!my_strncasecmp(line, MCCI_S_FORM, strlen(MCCI_S_FORM))) {
		retCode = MCCIHandleForm(client, line, retText);
                MCCISendResponseLine(client, MCCIR_FORM_OK,
                        "FORM request received by Mosaic");
		}
	else if (!my_strncasecmp(line,MCCI_S_QUIT,strlen(MCCI_S_QUIT))) {
                MCCISendResponseLine(client,MCCIR_QUIT_OK,
                        "QUIT request received exiting...");
		MCCIRequestQuit();
		}
	else if (!my_strncasecmp(line,MCCI_S_SEND,strlen(MCCI_S_SEND))) {
		retCode = MCCIHandleSend(client,line,retText);
                MCCISendResponseLine(client,retCode,retText);
		}
	else if (!my_strncasecmp(line,MCCI_S_POST,strlen(MCCI_S_POST))) {
		retCode = MCCIHandlePost(client,line,retText);
		MCCISendResponseLine(client,retCode,retText);
		}
	else if (!my_strncasecmp(line,MCCI_S_PUTANNOTATION,
					strlen(MCCI_S_PUTANNOTATION))) {
		retCode = MCCIHandlePutAnnotation(client,line,retText);
		MCCISendResponseLine(client,retCode,retText);
		}
	else if (!my_strncasecmp(line,MCCI_S_FILE_TO_URL,
					strlen(MCCI_S_FILE_TO_URL))) {
		retCode = MCCIHandleFileToURL(client,line,retText);
		MCCISendResponseLine(client,retCode,retText);
		}
	else {
		/* 
		MCCIRRequestUnrecognized();
		*/
		MCCISendResponseLine(client,MCCIR_UNRECOGNIZED,
			"Command not recognized");
		}
		

	return(1);
}


MCCISendAnchorHistory(client,url)
MCCIPort client;
char *url;
{
char buff[1024];
        if (MCCIanchorcached == 1)      /* ugly ADC hack ZZZ */
           sprintf(buff,"%s <%s> CACHED", MCCI_S_ANCHOR, url);
        else
	   sprintf(buff,"%s <%s>", MCCI_S_ANCHOR, url);

	return(MCCISendResponseLine(client, MCCIR_ANCHOR_INFO,buff));
}

int MCCIFormQueryToClient(client, actionID, query, contentType, post_data)  
MCCIPort client;
char *actionID;
char *query;
char *contentType;
char *post_data;
{
char buff[1024];
int length, dataLength;

	
	sprintf(buff, "%s %s ", actionID, query);
	if(MCCISendResponseLine(client, MCCIR_FORM_RESPONSE,buff)){
		return(MCCI_FAIL);
		}

	sprintf(buff,"Content-Type: %s\r\n",contentType);
	length = strlen(buff);
        if (length != NetServerWrite(client,buff,length)) {
                return(MCCI_FAIL);
                }

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

        if (dataLength!= NetServerWrite(client,post_data,dataLength)) {
                return(MCCI_FAIL);
		}
	
	return(MCCI_OK);
}

int MCCISendOutputFile(client,contentType,fileName)
MCCIPort client;
char *contentType;
char *fileName;
/* this routine used to send output back to the client */
{
int length;
int countDown;
char buff[1030];
struct stat fileInfo;
FILE *fp;

        if (stat(fileName,&fileInfo)) { /* get the length of the file */
                return(MCCI_FAIL);
		}

        if (!(fp = fopen(fileName,"r"))) {
                return(MCCI_FAIL);
                }

	sprintf(buff,"%d Send Data Output\r\n",MCCIR_SEND_DATA_OUTPUT);
	length = strlen(buff);
        if (length != NetServerWrite(client,buff,length)) {
                return(MCCI_FAIL);
                }

	sprintf(buff,"Content-Type: %s \r\n",contentType);
	length = strlen(buff);
        if (length != NetServerWrite(client,buff,length)) {
                return(MCCI_FAIL);
                }

	sprintf(buff,"Content-Length: %d \r\n",fileInfo.st_size);
	length = strlen(buff);
        if (length != NetServerWrite(client,buff,length)) {
                return(MCCI_FAIL);
                }

	countDown = fileInfo.st_size;
	while(countDown > 0) {
		if (0 < (length = fread(buff,1,1024,fp))) {
			if (length != NetServerWrite(client,buff,length)) {
				return(MCCI_FAIL);
				}
			countDown -= length;

			}
		else {
			/* error reading here...but we promised to send 
			   countDown number of bytes, so send nulls */
			while (countDown > 0) {
				if (1 != NetServerWrite(client,"\0",1)) {
					return(MCCI_FAIL);
					}
				countDown--;
				}
			}
		}
	fclose(fp);
	return(MCCI_OK);
	
}


int MCCISendBrowserViewOutput(client,url,contentType,data,dataLength)
/* Send BrowserView output response to client */
MCCIPort client;
char *url;
char *contentType;
char *data;
int dataLength;
{
char buff[1024];
int length;

	if (MCCI_OK!=MCCISendResponseLine(client,MCCIR_SEND_BROWSERVIEW,url)){
                return(MCCI_FAIL);
		}


	sprintf(buff,"Content-Type: %s\r\n",contentType);
	length = strlen(buff);
        if (length != NetServerWrite(client,buff,length)) {
                return(MCCI_FAIL);
                }

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

        if (dataLength!= NetServerWrite(client,data,dataLength)) {
                return(MCCI_FAIL);
		}
	
	return(MCCI_OK);

}


int MCCISendEventOutput(client, event_type)
/* Send Event output response to client */
MCCIPort client;
CCI_events event_type;
{
char buff[1024];
int length;

	sprintf(buff, "%d %d\r\n", MCCIR_SEND_EVENT, (int) event_type);
	length = strlen(buff);
        if (length != NetServerWrite(client, buff, length)) {
                return(MCCI_FAIL);
                }

	return(MCCI_OK);
}


int MCCISendMouseAnchorOutput(client, anchor)
/* Send MouseAnchor output response to client */
MCCIPort client;
char *anchor;
{

	if (MCCI_OK!=MCCISendResponseLine(client,MCCIR_SEND_MOUSE_ANCHOR,anchor)){
                return(MCCI_FAIL);
		}

	return(MCCI_OK);
}

