about summary refs log tree commit diff stats
path: root/WWW/Library/Implementation/HTWAIS.c
diff options
context:
space:
mode:
Diffstat (limited to 'WWW/Library/Implementation/HTWAIS.c')
-rw-r--r--WWW/Library/Implementation/HTWAIS.c1103
1 files changed, 1103 insertions, 0 deletions
diff --git a/WWW/Library/Implementation/HTWAIS.c b/WWW/Library/Implementation/HTWAIS.c
new file mode 100644
index 00000000..e0659f17
--- /dev/null
+++ b/WWW/Library/Implementation/HTWAIS.c
@@ -0,0 +1,1103 @@
+/*	WorldWideWeb - Wide Area Informaion Server Access	HTWAIS.c
+**	==================================================
+**
+**	This module allows a WWW server or client to read data from a
+**	remote  WAIS
+**  server, and provide that data to a WWW client in hypertext form.
+**  Source files, once retrieved, are stored and used to provide
+**  information about the index when that is acessed.
+**
+** Authors
+**	BK	Brewster Kahle, Thinking Machines, <Brewster@think.com>
+**	TBL	Tim Berners-Lee, CERN <timbl@info.cern.ch>
+**	FM	Foteos Macrides, WFEB <macrides@sci.wfeb.edu>
+**
+** History
+**	   Sep 91	TBL adapted shell-ui.c (BK) with HTRetrieve.c from WWW.
+**	   Feb 91	TBL Generated HTML cleaned up a bit (quotes, escaping)
+**			    Refers to lists of sources. 
+**	   Mar 93	TBL Lib 2.0 compatible module made.
+**	   May 94	FM  Added DIRECT_WAIS support for VMS.
+**
+** Bugs
+**	Uses C stream i/o to read and write sockets, which won't work
+**	on VMS TCP systems.
+**
+**	Should cache connections.
+**
+**	ANSI C only as written
+**
+** Bugs fixed
+**      NT Nathan Torkington (Nathan.Torkington@vuw.ac.nz)
+**
+** WAIS comments:
+**
+**	1.	Separate directories for different system's .o would help
+**	2.	Document ids are rather long!
+**
+** WWW Address mapping convention:
+**
+**	/servername/database/type/length/document-id
+**
+**	/servername/database?word+word+word
+*/
+/* WIDE AREA INFORMATION SERVER SOFTWARE:
+   No guarantees or restrictions.  See the readme file for the full standard
+   disclaimer.
+
+   Brewster@think.com
+*/
+
+#include "HTUtils.h"
+#include "tcp.h"
+#include "HTParse.h"
+#include "HTAccess.h"		/* We implement a protocol */
+#include "HTML.h"		/* The object we will generate */
+#include "HTFormat.h"
+#include "HTTCP.h"
+#include "HTCJK.h"
+#include "HTAlert.h"
+/* #include "HTWSRC.h"	*/	/* Need some bits from here */
+/* #include "ParseWSRC.h" */
+
+
+/*			From WAIS
+**			---------
+*/
+
+#ifdef VMS
+#include "HTVMS_WaisUI.h"
+#include "HTVMS_WaisProt.h"
+#else
+#include <ui.h>
+#endif /* VMS */
+
+#define MAX_MESSAGE_LEN 100000
+#define CHARS_PER_PAGE 10000 /* number of chars retrieved in each request */
+
+#define WAISSEARCH_DATE "Fri Jul 19 1991"
+
+
+/*			FROM WWW
+**			--------
+*/
+#include "LYLeaks.h"
+
+#define FREE(x) if (x) {free(x); x = NULL;}
+
+extern int HTCheckForInterrupt NOPARAMS;
+
+#define DIRECTORY "/cnidr.org:210/directory-of-servers"
+/* #define DIRECTORY "/quake.think.com:210/directory-of-servers" */
+
+#define BIG 1024	/* identifier size limit  @@@@@ */
+
+#define BUFFER_SIZE 4096	/* Arbitrary size for efficiency */
+
+#define HEX_ESCAPE '%'
+
+extern HTCJKlang HTCJK;
+
+extern int WWW_TraceFlag;	/* Control diagnostic output */
+extern FILE * logfile;		/* Log file output */
+
+PRIVATE BOOL	as_gate;	/* Client is using us as gateway */
+
+PRIVATE char	line[2048];	/* For building strings to display */
+				/* Must be able to take id */
+
+#define PUTC(c) (*target->isa->put_character)(target, c)
+#define PUTS(s) (*target->isa->put_string)(target, s)
+#define START(e) (*target->isa->start_element)(target, e, 0, 0, 0)
+#define END(e) (*target->isa->end_element)(target, e, 0)
+#define FREE_TARGET (*target->isa->_free)(target)
+
+struct _HTStructured {
+	CONST HTStructuredClass *	isa;
+	/* ... */
+};
+
+struct _HTStream {
+	CONST HTStreamClass *	isa;
+	/* ... */
+};
+
+
+/* ------------------------------------------------------------------------ */
+/* ---------------- Local copy of connect_to_server calls ----------------- */
+/* ------------------------------------------------------------------------ */
+
+/* Returns 1 on success, 0 on fail, -1 on interrupt. */
+static int fd_mosaic_connect_to_server ARGS3(char *, host_name, long, port,
+long *, fd)
+{
+  /* New version. */
+  char dummy[256];
+  int status;
+
+  sprintf (dummy, "wais://%s:%d/", host_name, port);
+
+  status = HTDoConnect (dummy, "WAIS", 210, (int *)fd);
+  if (status == HT_INTERRUPTED)
+    {
+      if (TRACE)
+        fprintf (stderr, "===WAIS=== interrupted in connect\n");
+      HTAlert ("Connection interrupted.");
+      return -1;
+    }
+  if (status < 0)
+    return 0;
+  return 1;
+}
+
+/* Returns 1 on success, 0 on fail, -1 on interrupt. */
+#ifdef VMS
+static int mosaic_connect_to_server ARGS3(char *, host_name, long, port,
+					  long *, fdp)
+#else
+static int mosaic_connect_to_server ARGS3(char *, host_name, long, port,
+					  FILE **, fp)
+#endif /* VMS */
+{
+#ifndef VMS
+  FILE* file;
+#endif /* VMS */
+  long fd;
+  int rv;
+  
+  rv = fd_mosaic_connect_to_server (host_name, port, &fd);
+  if(rv == 0) 
+    {
+      HTAlert ("Could not connect to WAIS server.");
+      return 0;
+    }
+  else if (rv == -1)
+    {
+      HTAlert ("Connection interrupted.");
+      return -1;
+    }
+
+#ifndef VMS
+  if ((file = fdopen(fd,"r+")) == NULL) 
+    {
+      HTAlert ("Could not open WAIS connection for reading.");
+      return 0;
+    }
+
+  *fp = file;
+#else
+  *fdp = fd;
+#endif /* VMS */
+  return 1;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+
+
+/*								showDiags
+*/
+/* modified from Jonny G's version in ui/question.c */
+
+void showDiags ARGS2(
+	HTStream *, 		target,
+	diagnosticRecord **, 	d)
+{
+  long i;
+
+  for (i = 0; d[i] != NULL; i++) {
+    if (d[i]->ADDINFO != NULL) {
+      PUTS("Diagnostic code is ");
+      PUTS(d[i]->DIAG);
+      PUTC(' ');
+      PUTS(d[i]->ADDINFO);
+      PUTC('\n'); ;
+    }
+  }
+}
+
+/*	Matrix of allowed characters in filenames
+**	-----------------------------------------
+*/
+
+PRIVATE BOOL acceptable[256];
+PRIVATE BOOL acceptable_inited = NO;
+
+PRIVATE void init_acceptable NOARGS
+{
+    unsigned int i;
+    char * good = 
+      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_$";
+    for(i=0; i<256; i++) acceptable[i] = NO;
+    for(;*good; good++) acceptable[(unsigned int)*good] = YES;
+    acceptable_inited = YES;
+}
+
+/*	Transform file identifier into WWW address
+**	------------------------------------------
+**
+**
+** On exit,
+**	returns		nil if error
+**			pointer to malloced string (must be freed) if ok
+*/
+char * WWW_from_archie ARGS1 (char *, file)
+{
+    char * end;
+    char * result;
+    char * colon;
+    for(end=file; *end > ' '; end++);	/* assumes ASCII encoding*/
+    result = (char *)malloc(10 + (end-file));
+    if (!result) return result;		/* Malloc error */
+    strcpy(result, "file://");
+    strncat(result, file, end-file);
+    colon = strchr(result+7, ':');	/* Expect colon after host */
+    if (colon) {
+	for(; colon[0]; colon[0]=colon[1], colon++);	/* move down */
+    }
+    return result;
+} /* WWW_from_archie */
+
+/*	Transform document identifier into URL
+**	--------------------------------------
+**
+** Bugs: A static buffer of finite size is used!
+**	The format of the docid MUST be good!
+**
+** On exit,
+**	returns		nil if error
+**			pointer to malloced string (must be freed) if ok
+*/
+PRIVATE char hex [17] = "0123456789ABCDEF";
+extern char from_hex PARAMS((char a));			/* In HTWSRC @@ */
+
+PRIVATE char * WWW_from_WAIS ARGS1(any *, docid)
+
+{
+    static char buf[BIG];
+    char * q = buf;
+    char * p = (docid->bytes);
+    int i, l;
+    if (TRACE) {
+	char *p;
+	fprintf(stderr, "WAIS id (%d bytes) is ", (int)docid->size);
+	for(p=docid->bytes; p<docid->bytes+docid->size; p++) {
+	    if ((*p >= ' ') && (*p<= '~')) /* Assume ASCII! */
+		fprintf(stderr, "%c", *p);
+	    else
+		fprintf(stderr, "<%x>", (unsigned)*p);
+	}
+	fprintf(stderr, "\n");
+    }	 
+    for (p=docid->bytes; (p<docid->bytes+docid->size) && (q<&buf[BIG]);) {
+	if (TRACE) fprintf(stderr, "    Record type %d, length %d\n",
+		p[0], p[1]);
+        if (*p>10) {
+	    if(TRACE)
+	        fprintf(stderr, "Eh? DOCID record type of %d!\n", *p);
+	    return 0;
+	}
+	{	/* Bug fix -- allow any byte value 15 Apr 93 */
+	    unsigned int i = (unsigned) *p++;
+	    
+	    if (i > 99) {
+		*q++ = (i/100) + '0';
+		i = i % 100;
+	    }
+	    if (i > 9) {
+		*q++ = (i/10) + '0';
+		i = i % 10;
+	    }
+	    *q++ = i + '0';	/* Record type */
+	}
+	*q++ = '=';		/* Separate */
+	l = *p++;		/* Length */
+	for(i=0; i<l; i++, p++){
+	    if (!acceptable[*p]) {
+		*q++ = HEX_ESCAPE;	/* Means hex commming */
+		*q++ = hex[(*p) >> 4];
+		*q++ = hex[(*p) & 15];
+	    }
+	    else *q++ = *p;
+	}
+	*q++= ';';		/* Terminate field */
+    }
+    *q++ = 0;			/* Terminate string */
+    if (TRACE) fprintf(stderr, "WWW form of id: %s\n", buf); 
+    {
+        char * result = (char *)malloc(strlen(buf)+1);
+	if (!result)
+	    outofmem(__FILE__, "WWW_from_WAIS");
+	strcpy(result, buf);
+	return result;
+    }
+} /* WWW_from_WAIS */
+
+
+/*	Transform URL into WAIS document identifier
+**	-------------------------------------------
+**
+** On entry,
+**	docname		points to valid name produced originally by
+**			WWW_from_WAIS
+** On exit,
+**	docid->size	is valid
+**	docid->bytes	is malloced and must later be freed.
+*/
+PRIVATE any * WAIS_from_WWW ARGS2 (any *, docid, char *, docname)
+{
+    char *z; 	/* Output pointer */
+    char *sor;	/* Start of record - points to size field. */
+    char *p; 	/* Input pointer */
+    char *q; 	/* Poisition of "=" */
+    char *s; 	/* Position of semicolon */
+    int n;	/* size */
+    if (TRACE) fprintf(stderr, "WWW id (to become WAIS id): %s\n", docname); 
+    for(n=0, p = docname; *p; p++) {	/* Count sizes of strings */
+        n++;
+	if (*p == ';')  n--;		/* Not converted */
+	else if (*p == HEX_ESCAPE) n=n-2;	/* Save two bytes */
+        docid->size = n;
+    }
+    
+    if (!(docid->bytes = (char *) malloc(docid->size))) /* result record */
+	    outofmem(__FILE__, "WAIS_from_WWW");
+    z = docid->bytes;
+    
+    for(p = docname; *p; ) {	/* Convert of strings */
+    				/* Record type */
+				
+	*z = 0;			/* Initialize record type */
+	while (*p >= '0' && *p <= '9') {
+	    *z = *z*10 + (*p++ - '0');	/* Decode decimal record type */
+	}
+	z++;
+	if (*p != '=') return 0;
+	q = p;
+	
+/*        *z++ = *p++ - '0';
+	q = strchr(p , '=');
+	if (!q) return 0;
+*/
+	s = strchr(q, ';');	/* (Check only) */
+	if (!s) return 0;	/* Bad! No ';';	*/
+        sor = z;		/* Remember where the size field was */
+	z++;			/* Skip record size for now	*/
+	for(p=q+1; *p!=';' ; ) {
+	   if (*p == HEX_ESCAPE) {
+	        char c;
+		unsigned int b;
+		p++;
+	        c = *p++;
+		b =   from_hex(c);
+		c = *p++;
+		if (!c) break;	/* Odd number of chars! */
+		*z++ = (b<<4) + from_hex(c);
+	    } else {
+	        *z++ = *p++;	/* Record */
+	    }
+	}
+	*sor = (z-sor-1);	/* Fill in size -- not counting size itself */
+	p++;			/* After semicolon: start of next record */
+    }
+    
+    if (TRACE) {
+	char *p;
+	fprintf(stderr, "WAIS id (%d bytes) is ", (int)docid->size);
+	for(p=docid->bytes; p<docid->bytes+docid->size; p++) {
+	    if ((*p >= ' ') && (*p<= '~')) /* Assume ASCII! */
+		fprintf(stderr, "%c", *p);
+	    else
+		fprintf(stderr, "<%x>", (unsigned)*p);
+	}
+	fprintf(stderr, "\n");
+    }	 
+    return docid;		/* Ok */
+    
+} /* WAIS_from_WWW */
+
+
+/*	Send a plain text record to the client		output_text_record()
+**	--------------------------------------
+*/
+
+PRIVATE void output_text_record ARGS4(
+    HTStream *,			target,
+    WAISDocumentText *,		record,
+    boolean,			quote_string_quotes,
+    boolean,                    binary)
+{
+  long count;
+  /* printf(" Text\n");
+     print_any("     DocumentID:  ", record->DocumentID);
+     printf("     VersionNumber:  %d\n", record->VersionNumber);
+     */
+
+  if (binary) {
+    (*target->isa->put_block)(target,
+			      record->DocumentText->bytes,
+			      record->DocumentText->size);
+    return;
+  }
+
+  for(count = 0; count < record->DocumentText->size; count++){
+    long ch = (unsigned char)record->DocumentText->bytes[count];
+    if (ch == 27) {	/* What is this in for? Tim */
+
+	    /* then we have an escape code */
+	    /* if the next letter is '(' or ')', then ignore two letters */
+	    if('(' == record->DocumentText->bytes[count + 1] ||
+		')' == record->DocumentText->bytes[count + 1])
+	    count += 1;             /* it is a term marker */
+	    else count += 4;		/* it is a paragraph marker */
+    } else if (ch == '\n' || ch == '\r') {
+	    PUTC('\n');
+    } else if (HTCJK != NOCJK || ch == '\t' || isprint(ch)){
+	    PUTC(ch);
+    } 
+  }
+} /* output text record */
+
+
+
+/*	Format A Search response for the client		display_search_response
+**	---------------------------------------
+*/
+/* modified from tracy shen's version in wutil.c
+ * displays either a text record or a set of headlines.
+ */
+void
+display_search_response ARGS4(
+    HTStructured *,		target,
+    SearchResponseAPDU *,	response,
+    char *,			database,
+    char *,	 		keywords)
+{
+  WAISSearchResponse  *info;
+  long i, k;
+  
+  BOOL archie =  strstr(database, "archie")!=0;	/* Specical handling */
+  
+  if (TRACE) fprintf(stderr, "HTWAIS: Displaying search response\n");
+  PUTS("Index ");
+  START(HTML_EM);
+  PUTS(database);
+  END(HTML_EM);
+  sprintf(line, " contains the following %d item%s relevant to \"",
+	  (int)(response->NumberOfRecordsReturned),
+	  response->NumberOfRecordsReturned ==1 ? "" : "s");
+  PUTS(line);
+  START(HTML_EM);
+  PUTS(keywords);
+  END(HTML_EM);
+  PUTS("\".\n");
+  PUTS("The first figure after each entry is its relative score, ");
+  PUTS("the second is the number of lines in the item.");
+  START(HTML_BR);
+  START(HTML_BR);
+  PUTS("\n");
+  START(HTML_OL);
+
+  if ( response->DatabaseDiagnosticRecords != 0 ) {
+    info = (WAISSearchResponse *)response->DatabaseDiagnosticRecords;
+    i =0; 
+
+    if (info->Diagnostics != NULL)
+      showDiags((HTStream*)target, info->Diagnostics);
+
+    if ( info->DocHeaders != 0 ) {
+      for (k=0; info->DocHeaders[k] != 0; k++ ) {
+	WAISDocumentHeader* head = info->DocHeaders[k];
+	char * headline = trim_junk(head->Headline);
+	any * docid = head->DocumentID;
+	char * docname;			/* printable version of docid */
+	i++;
+
+/*	Make a printable string out of the document id.
+*/
+	if (TRACE) fprintf(stderr, 
+		"HTWAIS:  %2ld: Score: %4ld, lines:%4ld '%s'\n", 
+	       i,
+	       (long int)(info->DocHeaders[k]->Score),
+	       (long int)(info->DocHeaders[k]->Lines),
+	       headline);
+
+	START(HTML_LI);
+
+	if (archie) {
+	    char * www_name = WWW_from_archie(headline);
+	    if (www_name) {
+		HTStartAnchor(target, NULL, www_name);
+		PUTS(headline);
+		
+		END(HTML_A);
+		FREE(www_name);
+	    } else {
+		 PUTS(headline);
+		 PUTS(" (bad file name)");
+	    }
+	} else { /* Not archie */
+	    docname =  WWW_from_WAIS(docid);
+	    if (docname) {
+		char * dbname = HTEscape(database, URL_XPALPHAS);
+		sprintf(line, "/%s/%s/%d/%s",		/* W3 address */
+				    dbname,
+		    head->Types ? head->Types[0] : "TEXT",
+		    (int)(head->DocumentLength),
+		    docname);
+		HTStartAnchor(target, NULL, ( (head->Types) 
+		      && (!strcmp(head->Types[0], "URL"))) ? 
+			      headline : line); /* NT, Sep 93 */
+		PUTS(headline);
+		END(HTML_A);
+		FREE(dbname);
+		FREE(docname);
+	    } else {
+		 PUTS("(bad doc id)");
+	    }
+	  }
+
+	sprintf(line, "%5ld  %5ld  ",
+	    head->Score,
+	    head->Lines);
+	PUTS( line);
+      } /* next document header */
+    } /* if there were any document headers */
+    
+    if ( info->ShortHeaders != 0 ) {
+      k =0;
+      while (info->ShortHeaders[k] != 0 ) {
+	i++;
+	PUTS( "(Short Header record, can't display)");
+      }
+    }
+    if ( info->LongHeaders != 0 ) {
+      k =0;
+      while (info->LongHeaders[k] != 0) {
+	i++;
+	PUTS( "\nLong Header record, can't display\n");
+      }
+    }
+    if ( info->Text != 0 ) {
+      k =0;
+      while (info->Text[k] != 0) {
+	i++;
+	PUTS( "\nText record\n");
+	output_text_record((HTStream*)target, info->Text[k++], false, false);
+      }
+    }
+    if ( info->Headlines != 0 ) {
+      k =0;
+      while (info->Headlines[k] != 0) {
+	i++;
+	PUTS( "\nHeadline record, can't display\n");
+	/* dsply_headline_record( info->Headlines[k++]); */
+      }
+    }
+    if ( info->Codes != 0 ) {
+      k =0;
+      while (info->Codes[k] != 0) {
+	i++;
+	PUTS( "\nCode record, can't display\n");
+	/* dsply_code_record( info->Codes[k++]); */
+      }
+    }
+  }				/* Loop: display user info */
+  END(HTML_OL);
+  PUTC('\n'); ;
+}
+
+
+
+
+/*		Load by name					HTLoadWAIS
+**		============
+**
+**	This renders any object or search as required
+*/
+PUBLIC int HTLoadWAIS ARGS4(
+	CONST char *,		arg,
+	HTParentAnchor *,	anAnchor,
+	HTFormat,		format_out,
+	HTStream*,		sink)
+
+#define MAX_KEYWORDS_LENGTH 1000
+#define MAX_SERVER_LENGTH 1000
+#define MAX_DATABASE_LENGTH 1000
+#define MAX_SERVICE_LENGTH 1000
+#define MAXDOCS 200
+
+{
+    static CONST char * error_header =
+"<h1>Access error</h1>\nThe following error occured in accesing a WAIS server:<P>\n";
+    char * key;			  /* pointer to keywords in URL */
+    char* request_message = NULL; /* arbitrary message limit */
+    char* response_message = NULL; /* arbitrary message limit */
+    long request_buffer_length;	/* how of the request is left */
+    SearchResponseAPDU  *retrieval_response = 0;
+    char keywords[MAX_KEYWORDS_LENGTH + 1];
+    char *server_name;	
+    char *wais_database = NULL;		/* name of current database */
+    char *www_database;			/* Same name escaped */
+    char *service;
+    char *doctype;
+    char *doclength;
+    long document_length;
+    char *docname;
+#ifdef VMS
+    long connection = 0;
+#else
+    FILE *connection = NULL;
+#endif /* VMS */
+    char * names;		/* Copy of arg to be hacked up */
+    BOOL ok = NO;
+    int return_status = HT_LOADED;
+    int rv;
+    
+    extern FILE * connect_to_server();
+    
+    if (!acceptable_inited) init_acceptable();
+    
+        
+/*	Decipher and check syntax of WWW address:
+**	----------------------------------------
+**
+**	First we remove the "wais:" if it was spcified.  920110
+*/  
+    names = HTParse(arg, "", PARSE_HOST | PARSE_PATH | PARSE_PUNCTUATION);
+    key = strchr(names, '?');
+    
+    if (key) {
+    	char * p;
+	*key++ = 0;	/* Split off keywords */
+	for (p=key; *p; p++) if (*p == '+') *p = ' ';
+	HTUnEscape(key);
+    }
+    if (names[0]== '/') {
+	server_name = names+1;
+	if (as_gate =(*server_name == '/'))
+	    server_name++;	/* Accept one or two */
+	www_database = strchr(server_name,'/');
+	if (www_database) {
+	    *www_database++ = 0;		/* Separate database name */
+	    doctype = strchr(www_database, '/');
+	    if (key) ok = YES;	/* Don't need doc details */
+	    else if (doctype) {	/* If not search parse doc details */
+		*doctype++ = 0;	/* Separate rest of doc address */
+		doclength = strchr(doctype, '/');
+		if(doclength) {
+		    *doclength++ = 0;
+		    document_length = atol(doclength);
+		    if (document_length) {
+			docname=strchr(doclength, '/');
+			if (docname) {
+			    *docname++ = 0;
+			    ok = YES;	/* To avoid a goto! */
+			} /* if docname */
+		    } /* if document_length valid */
+		} /* if doclength */
+	    } else { /* no doctype?  Assume index required */
+	        if (!key) key = "";
+		ok = YES;
+	    } /* if doctype */
+	} /* if database */
+     }
+     
+     if (!ok)
+	 return HTLoadError(sink, 500, "Syntax error in WAIS URL");
+
+     if (TRACE) fprintf(stderr, "HTWAIS: Parsed OK\n");
+     
+     service = strchr(names, ':');
+     if (service)  *service++ = 0;
+     else service = "210";
+     
+     if (server_name[0] == 0)
+#ifdef VMS
+        connection = 0;
+#else
+        connection = NULL;
+#endif /* VMS */
+
+     else if (!(key && !*key))
+    {
+      int status;
+      if (TRACE)
+        fprintf (stderr, "===WAIS=== calling mosaic_connect_to_server\n");
+      status = mosaic_connect_to_server
+        			(server_name, atoi(service), &connection);
+      if (status == 0)
+        {
+          if (TRACE)
+            fprintf (stderr, "===WAIS=== connection failed\n");
+          FREE(names);
+          return HT_NOT_LOADED;
+        }
+      else if (status == -1)
+        {
+          if (TRACE)
+            fprintf (stderr, "===WAIS=== connection interrupted\n");
+          FREE(names);
+          return HT_INTERRUPTED;
+        }
+    }
+
+    StrAllocCopy(wais_database,www_database);
+    HTUnEscape(wais_database);
+    
+	/* This below fixed size stuff is terrible */
+#ifdef VMS
+    if (!(request_message =
+    	  (char*)calloc((size_t)MAX_MESSAGE_LEN*sizeof(char),1)))
+	outofmem(__FILE__, "HTLoadWAIS");
+    if (!(response_message =
+    	  (char*)calloc((size_t)MAX_MESSAGE_LEN*sizeof(char),1)))
+	outofmem(__FILE__, "HTLoadWAIS");
+#else
+    request_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
+    response_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
+#endif /* VMS */
+
+/*	If keyword search is performed but there are no keywords,
+**	the user has followed a link to the index itself. It would be
+**	appropriate at this point to send him the .SRC file - how?
+*/
+
+    if (key && !*key) {				/* I N D E X */
+    
+#ifdef CACHE_FILE_PREFIX
+	char filename[256];
+	FILE * fp;
+#endif
+	HTStructured * target = HTML_new(anAnchor, format_out, sink);
+	
+	START(HTML_HEAD);
+	PUTS("\n");
+	HTStartIsIndex(target, "Enter WAIS query: ", NULL);
+	PUTS("\n");
+
+	{
+	    START(HTML_TITLE);
+	    PUTS(wais_database);
+	    PUTS(" (WAIS Index)");
+	    END(HTML_TITLE);
+	    PUTS("\n");
+	    END(HTML_HEAD);
+	    PUTS("\n");
+	    
+	    START(HTML_H1);
+	    PUTS("WAIS Index: ");
+	    START(HTML_EM);
+	    PUTS(wais_database);
+	    END(HTML_EM);
+	    END(HTML_H1);
+	    PUTS("\n");
+	    PUTS("This is a link for searching the ");
+	    START(HTML_EM);
+	    PUTS(wais_database);
+	    END(HTML_EM);
+	    PUTS(" WAIS Index.\n"); 
+	    
+	}
+	/* If we have seen a source file for this database, use that:
+	*/
+
+#ifdef CACHE_FILE_PREFIX
+	sprintf(filename, "%sWSRC-%s:%s:%.100s.txt",
+		CACHE_FILE_PREFIX,
+		server_name, service, www_database);
+
+	fp = fopen(filename, "r");	/* Have we found this already? */
+	if (TRACE) fprintf(stderr,
+		"HTWAIS: Description of server %s %s.\n",
+		filename,
+		fp ? "exists already" : "does NOT exist!");
+
+	if (fp) {
+	    char c;
+	    START(HTML_PRE);		/* Preformatted description */
+	    PUTS("\n");
+	    while((c=getc(fp))!=EOF) PUTC(c);	/* Transfer file */
+	    END(HTML_PRE);
+	    fclose(fp);
+#endif
+	START(HTML_P);
+	PUTS("\nEnter the 's'earch command and then specify search words.\n");
+	
+	FREE_TARGET;
+	
+    } else if (key) {					/* S E A R C H */
+	char *p;
+	HTStructured * target;
+	
+	strncpy(keywords, key, MAX_KEYWORDS_LENGTH);
+	while(p=strchr(keywords, '+')) *p = ' ';
+    
+        /* Send advance title to get something fast to the other end */
+	
+	target = HTML_new(anAnchor, format_out, sink);
+	
+	START(HTML_HEAD);
+	PUTS("\n");
+	HTStartIsIndex(target, "Enter WAIS query: ", NULL);
+	PUTS("\n");
+	START(HTML_TITLE);
+	PUTS(keywords);
+	PUTS(" (in ");
+	PUTS(wais_database);
+	PUTS(")");
+	END(HTML_TITLE);
+	PUTS("\n");
+	END(HTML_HEAD);
+	PUTS("\n");
+	
+	START(HTML_H1);
+	PUTS("WAIS Search of \"");
+	START(HTML_EM);
+	PUTS(keywords);
+	END(HTML_EM);
+	PUTS("\" in: ");
+	START(HTML_EM);
+	PUTS(wais_database);
+	END(HTML_EM);
+	END(HTML_H1);
+	PUTS("\n");
+
+	request_buffer_length = MAX_MESSAGE_LEN; /* Amount left */
+	if (TRACE) fprintf(stderr, "HTWAIS: Search for `%s' in `%s'\n",
+		keywords, wais_database);
+	if(NULL ==
+	generate_search_apdu(request_message + HEADER_LENGTH, 
+				&request_buffer_length, 
+				keywords, wais_database, NULL, MAXDOCS)) {
+#ifdef VMS
+	    HTAlert ("HTWAIS: Request too large.");
+	    return_status = HT_NOT_LOADED;
+	    FREE_TARGET;
+	    goto CleanUp;
+#else
+	    panic("request too large");
+#endif /* VMS */
+        }
+	
+	HTProgress("Searching WAIS database...");
+	rv = interpret_message (request_message, 
+				MAX_MESSAGE_LEN - request_buffer_length, 
+				response_message,
+				MAX_MESSAGE_LEN,
+				connection,
+				false	/* true verbose */
+			       );
+
+	if (rv == HT_INTERRUPTED) {
+	    HTAlert ("Search interrupted.");
+	    return_status = HT_INTERRUPTED;
+	    FREE_TARGET;
+	    goto CleanUp;
+	}
+
+	else if(!rv) {
+#ifdef VMS
+	    HTAlert ("HTWAIS: Return message too large.");
+	    return_status = HT_NOT_LOADED;
+	    FREE_TARGET;
+	    goto CleanUp;
+#else
+	    panic("returned message too large");
+#endif /* VMS */
+    
+        } else {	/* returned message ok */
+	
+	    SearchResponseAPDU  *query_response = 0;
+	    readSearchResponseAPDU(&query_response,
+	    	response_message + HEADER_LENGTH);
+	    display_search_response(target, 
+	    	query_response, wais_database, keywords);
+	    if (query_response->DatabaseDiagnosticRecords)
+		freeWAISSearchResponse(
+			query_response->DatabaseDiagnosticRecords);         
+	    freeSearchResponseAPDU( query_response);
+	}	/* returned message not too large */
+    
+	FREE_TARGET;
+
+    } else {			/* D O C U M E N T    F E T C H */
+    
+	HTFormat format_in;
+	boolean binary;     /* how to transfer stuff coming over */
+	HTStream * target;
+	long count;
+	any   doc_chunk;
+	any * docid = &doc_chunk;
+	if (TRACE) fprintf(stderr,
+		"HTWAIS: Retrieve document id `%s' type `%s' length %ld\n",
+		docname, doctype, document_length);
+		
+	format_in = 
+	  !strcmp(doctype, "WSRC") ? HTAtom_for("application/x-wais-source") :
+	  !strcmp(doctype, "TEXT") ? HTAtom_for("text/plain") :
+	  !strcmp(doctype, "HTML") ? HTAtom_for("text/html") :
+	  !strcmp(doctype, "GIF")  ? HTAtom_for("image/gif") :
+	   		             HTAtom_for("application/octet-stream");
+	binary = 
+	  0 != strcmp(doctype, "WSRC") &&
+	  0 != strcmp(doctype, "TEXT") &&
+	  0 != strcmp(doctype, "HTML") ;
+
+
+	target = HTStreamStack(format_in, format_out, sink, anAnchor);
+	if (!target) return HTLoadError(sink, 500,
+		"Can't convert format of WAIS document");
+/*	Decode hex or litteral format for document ID
+*/	
+	WAIS_from_WWW(docid, docname);
+
+	
+/*	Loop over slices of the document
+*/	
+	for(count = 0; 
+	    count * CHARS_PER_PAGE < document_length;
+	    count++){
+#ifdef VMS
+          char *type = NULL;
+	  
+	  StrAllocCopy(type, doctype);
+#else
+	  char *type = s_strdup(doctype);	/* Gets freed I guess */
+#endif /* VMS */
+	  request_buffer_length = MAX_MESSAGE_LEN; /* Amount left */
+	  if (TRACE) fprintf(stderr, "HTWAIS: Slice number %ld\n", count);
+
+            if(HTCheckForInterrupt())
+              {
+                HTAlert ("Data transfer interrupted.");
+                (*target->isa->_abort)(target, NULL);
+#ifdef VMS
+		FREE(type);
+#endif /* VMS */
+		return_status = HT_NOT_LOADED;
+		goto CleanUp;
+              }
+
+	  if(0 ==
+	      generate_retrieval_apdu(request_message + HEADER_LENGTH,
+		    &request_buffer_length, 
+		    docid, 
+		    CT_byte,
+		    count * CHARS_PER_PAGE,
+		    ((count + 1) * CHARS_PER_PAGE <= document_length ?
+		             (count + 1) * CHARS_PER_PAGE :
+			     document_length),
+		    type,
+		    wais_database
+		    )) {
+#ifdef VMS
+		    HTAlert ("HTWAIS: Request too long.");
+		    return_status = HT_NOT_LOADED;
+		    FREE_TARGET;
+		    FREE(type);
+		    FREE(docid->bytes);
+		    goto CleanUp;
+#else
+		    panic("request too long");
+#endif /* VMS */
+		}
+	  
+	  /*	Actually do the transaction given by request_message */
+	  HTProgress("Fetching WAIS document...");
+	  rv = interpret_message (request_message, 
+				  MAX_MESSAGE_LEN - request_buffer_length, 
+				  response_message,
+				  MAX_MESSAGE_LEN,
+				  connection,
+				  false /* true verbose */	
+			         );
+
+	  if (rv == HT_INTERRUPTED)
+	    {
+		HTAlert ("Data transfer interrupted.");
+		return_status = HT_INTERRUPTED;
+		FREE_TARGET;
+		FREE(type);
+		FREE(docid->bytes);
+		goto CleanUp;
+	    }
+
+	  else if (!rv)
+	    {
+#ifdef VMS
+		HTAlert ("HTWAIS: Return message too large.");
+		return_status = HT_NOT_LOADED;
+		FREE_TARGET;
+		FREE(type);
+		FREE(docid->bytes);
+		goto CleanUp;
+#else
+	        panic("Returned message too large");
+#endif /* VMS */
+	    }
+
+	  /* 	Parse the result which came back into memory.
+	  */
+	  readSearchResponseAPDU(&retrieval_response, 
+				 response_message + HEADER_LENGTH);
+
+	  if(NULL == ((WAISSearchResponse *)
+	  	retrieval_response->DatabaseDiagnosticRecords)->Text){
+		/* display_search_response(target, retrieval_response,
+					wais_database, keywords); */
+		PUTS("No text was returned!\n");
+		/* panic("No text was returned"); */
+	  } else {
+	  
+		output_text_record(target,
+		   ((WAISSearchResponse *)
+		    retrieval_response->DatabaseDiagnosticRecords)->Text[0],
+		false, binary);
+	  
+	  } /* If text existed */
+	  
+#ifdef VMS
+	  FREE(type);
+#endif /* VMS */
+	}	/* Loop over slices */
+
+	FREE_TARGET;
+	FREE(docid->bytes);
+
+	freeWAISSearchResponse( retrieval_response->DatabaseDiagnosticRecords); 
+	freeSearchResponseAPDU( retrieval_response);
+
+    } /* If document rather than search */
+
+
+
+CleanUp:
+/*	(This postponed until later,  after a timeout:)
+*/
+#ifdef VMS
+    if (connection)
+        NETCLOSE((int)connection);
+#else
+    if (connection)
+        fclose(connection);
+#endif /* VMS */
+    FREE(wais_database);
+#ifdef VMS
+    FREE(request_message);
+    FREE(response_message);
+#else
+    s_free(request_message);
+    s_free(response_message);
+#endif /* VMS */
+    FREE(names);
+    return (return_status);
+}
+
+#ifdef GLOBALDEF_IS_MACRO
+#define _HTWAIS_C_1_INIT { "wais", HTLoadWAIS, NULL }
+GLOBALDEF(HTProtocol, HTWAIS, _HTWAIS_C_1_INIT);
+#else
+GLOBALDEF PUBLIC HTProtocol HTWAIS = { "wais", HTLoadWAIS, NULL };
+#endif /* GLOBALDEF_IS_MACRO */