diff options
author | Thomas E. Dickey <dickey@invisible-island.net> | 2011-06-11 13:06:08 -0400 |
---|---|---|
committer | Thomas E. Dickey <dickey@invisible-island.net> | 2011-06-11 13:06:08 -0400 |
commit | f06f1fc3d95167ec780cb0963548f2afdd548b20 (patch) | |
tree | 6c12f0dea0a3c860994a46c37d7f32336d39d7db /WWW/Library/Implementation/HTWAIS.c | |
parent | 279010bc0791556e63b4951d83a2c45252142b80 (diff) | |
download | lynx-snapshots-f06f1fc3d95167ec780cb0963548f2afdd548b20.tar.gz |
snapshot of project "lynx", label v2-8-8dev_8m
Diffstat (limited to 'WWW/Library/Implementation/HTWAIS.c')
-rw-r--r-- | WWW/Library/Implementation/HTWAIS.c | 1082 |
1 files changed, 1082 insertions, 0 deletions
diff --git a/WWW/Library/Implementation/HTWAIS.c b/WWW/Library/Implementation/HTWAIS.c new file mode 100644 index 00000000..5c998ea8 --- /dev/null +++ b/WWW/Library/Implementation/HTWAIS.c @@ -0,0 +1,1082 @@ +/* + * $LynxId: HTWAIS.c,v 1.36 2011/06/11 12:13:32 tom Exp $ + * + * 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! + * + * W WW 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 <HTParse.h> +#include <HTAccess.h> /* We implement a protocol */ +#include <HTML.h> /* The object we will generate */ +#include <HTWSRC.h> +#include <HTTCP.h> +#include <HTCJK.h> +#include <HTAlert.h> +#include <LYStrings.h> + +#undef lines /* term.h conflict with wais.h */ +#undef alloca /* alloca.h conflict with wais.h */ + +/* From WAIS + * --------- + */ +#ifdef VMS +#include <HTVMS_WaisUI.h> +#include <HTVMS_WaisProt.h> +#elif defined(HAVE_WAIS_H) +#include <wais.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 <LYUtils.h> +#include <LYLeaks.h> + +#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 '%' + +static BOOL as_gate; /* Client is using us as gateway */ + +static 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, -1, 0) +#define END(e) (*target->isa->end_element)(target, e, 0) +#define MAYBE_END(e) if (HTML_dtd.tags[e].contents != SGML_EMPTY) \ + (*target->isa->end_element)(target, e, 0) +#define FREE_TARGET (*target->isa->_free)(target) + +struct _HTStructured { + const HTStructuredClass *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(char *host_name, + long port, + long *fd) +{ + char *dummy = NULL; + int status; + int result; + + HTSprintf0(&dummy, "%s//%s:%ld/", STR_WAIS_URL, host_name, port); + + status = HTDoConnect(dummy, "WAIS", 210, (int *) fd); + if (status == HT_INTERRUPTED) { + result = -1; + } else if (status < 0) { + result = 0; + } else { + result = 1; + } + FREE(dummy); + return result; +} + +/* Returns 1 on success, 0 on fail, -1 on interrupt. */ +#ifdef VMS +static int mosaic_connect_to_server(char *host_name, + long port, + long *fdp) +#else +static int mosaic_connect_to_server(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(gettext("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(gettext("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 */ +static void showDiags(HTStream *target, diagnosticRecord ** d) +{ + long i; + + for (i = 0; d[i] != NULL; i++) { + if (d[i]->ADDINFO != NULL) { + PUTS(gettext("Diagnostic code is ")); + PUTS(d[i]->DIAG); + PUTC(' '); + PUTS(d[i]->ADDINFO); + PUTC('\n'); + } + } +} + +/* Matrix of allowed characters in filenames + * ----------------------------------------- + */ + +static BOOL acceptable[256]; +static BOOL acceptable_inited = NO; + +static void init_acceptable(void) +{ + 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 + */ +static char *WWW_from_archie(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 + */ +static char hex[17] = "0123456789ABCDEF"; + +static char *WWW_from_WAIS(any *docid) +{ + static char buf[BIG]; + char *q = buf; + char *p = (docid->bytes); + char *result = NULL; + int i, l; + + if (TRACE) { + char *p2; + + fprintf(tfp, "WAIS id (%d bytes) is ", (int) docid->size); + for (p2 = docid->bytes; p2 < docid->bytes + docid->size; p2++) { + if ((*p2 >= ' ') && (*p2 <= '~')) /* Assume ASCII! */ + fprintf(tfp, "%c", *p2); + else + fprintf(tfp, "<%x>", (unsigned) *p2); + } + fprintf(tfp, "\n"); + } + for (p = docid->bytes; + (p < docid->bytes + docid->size) && (q < &buf[BIG]);) { + CTRACE((tfp, " Record type %d, length %d\n", p[0], p[1])); + if (*p > 10) { + CTRACE((tfp, "Eh? DOCID record type of %d!\n", *p)); + return 0; + } { /* Bug fix -- allow any byte value 15 Apr 93 */ + unsigned int i2 = (unsigned) *p++; + + if (i2 > 99) { + *q++ = (i2 / 100) + '0'; + i2 = i2 % 100; + } + if (i2 > 9) { + *q++ = (i2 / 10) + '0'; + i2 = i2 % 10; + } + *q++ = i2 + '0'; /* Record type */ + } + *q++ = '='; /* Separate */ + l = *p++; /* Length */ + for (i = 0; i < l; i++, p++) { + if (!acceptable[UCH(*p)]) { + *q++ = HEX_ESCAPE; /* Means hex coming */ + *q++ = hex[(*p) >> 4]; + *q++ = hex[(*p) & 15]; + } else + *q++ = *p; + } + *q++ = ';'; /* Terminate field */ + } + *q++ = 0; /* Terminate string */ + CTRACE((tfp, "WWW form of id: %s\n", buf)); + StrAllocCopy(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. + */ +static any *WAIS_from_WWW(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 */ + + CTRACE((tfp, "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 *p2; + + fprintf(tfp, "WAIS id (%d bytes) is ", (int) docid->size); + for (p2 = docid->bytes; p2 < docid->bytes + docid->size; p2++) { + if ((*p2 >= ' ') && (*p2 <= '~')) /* Assume ASCII! */ + fprintf(tfp, "%c", *p2); + else + fprintf(tfp, "<%x>", (unsigned) *p2); + } + fprintf(tfp, "\n"); + } + return docid; /* Ok */ + +} /* WAIS_from_WWW */ + +/* Send a plain text record to the client output_text_record() + * -------------------------------------- + */ +static void output_text_record(HTStream *target, + WAISDocumentText *record, + boolean binary) +{ + unsigned 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 (IS_CJK_TTY || 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. + */ +static void display_search_response(HTStructured * target, SearchResponseAPDU *response, + char *the_database, + char *keywords) +{ + WAISSearchResponse *info; + long i, k; + + BOOL archie = strstr(the_database, "archie") != 0; /* Special handling */ + + CTRACE((tfp, "HTWAIS: Displaying search response\n")); + PUTS(gettext("Index ")); + START(HTML_EM); + PUTS(the_database); + END(HTML_EM); + sprintf(line, gettext(" 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(gettext("The first figure after each entry is its relative score, ")); + PUTS(gettext("the second is the number of lines in the item.")); + START(HTML_BR); + START(HTML_BR); + PUTC('\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. + */ + CTRACE((tfp, "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(gettext(" (bad file name)")); + } + } else { /* Not archie */ + docname = WWW_from_WAIS(docid); + if (docname) { + if ((head->Types) && + (!strcmp(head->Types[0], "URL"))) { + HTStartAnchor(target, NULL, headline); + } else { + char *dbname = HTEscape(the_database, URL_XPALPHAS); + char *w3_address = NULL; + + HTSprintf0(&w3_address, + "/%s/%s/%d/%s", + dbname, + head->Types ? head->Types[0] : "TEXT", + (int) (head->DocumentLength), + docname); + HTStartAnchor(target, NULL, w3_address); + FREE(w3_address); + FREE(dbname); + } + PUTS(headline); + END(HTML_A); + FREE(docname); + } else { + PUTS(gettext("(bad doc id)")); + } + } + + sprintf(line, "%5ld %5ld ", + head->Score, + head->Lines); + PUTS(line); + MAYBE_END(HTML_LI); + } /* next document header */ + } + /* if there were any document headers */ + if (info->ShortHeaders != 0) { + k = 0; + while (info->ShortHeaders[k] != 0) { + i++; + PUTS(gettext("(Short Header record, can't display)")); + } + } + if (info->LongHeaders != 0) { + k = 0; + while (info->LongHeaders[k] != 0) { + i++; + PUTS(gettext("\nLong Header record, can't display\n")); + } + } + if (info->Text != 0) { + k = 0; + while (info->Text[k] != 0) { + i++; + PUTS(gettext("\nText record\n")); + output_text_record((HTStream *) target, + info->Text[k++], false); + } + } + if (info->Headlines != 0) { + k = 0; + while (info->Headlines[k] != 0) { + i++; + PUTS(gettext("\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(gettext("\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. + */ +int HTLoadWAIS(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 + +{ + 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 *the_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 = 0; + char *docname = 0; + +#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; + + if (!acceptable_inited) + init_acceptable(); + + /* Decipher and check syntax of WWW address: + * ---------------------------------------- + * + * First we remove the "wais:" if it was specified. 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] == '/') { + the_server_name = names + 1; + if ((as_gate = (*the_server_name == '/')) != 0) + the_server_name++; /* Accept one or two */ + www_database = strchr(the_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, gettext("Syntax error in WAIS URL")); + + CTRACE((tfp, "HTWAIS: Parsed OK\n")); + + service = strchr(names, ':'); + if (service) + *service++ = 0; + else + service = "210"; + + if (the_server_name[0] == 0) { +#ifdef VMS + connection = 0; +#else + connection = NULL; +#endif /* VMS */ + + } else if (!(key && !*key)) { + int status; + + CTRACE((tfp, "===WAIS=== calling mosaic_connect_to_server\n")); + status = mosaic_connect_to_server(the_server_name, + atoi(service), + &connection); + if (status == 0) { + CTRACE((tfp, "===WAIS=== connection failed\n")); + FREE(names); + return HT_NOT_LOADED; + } else if (status == -1) { + CTRACE((tfp, "===WAIS=== connection interrupted\n")); + FREE(names); + return HT_NOT_LOADED; + } + } + + StrAllocCopy(wais_database, www_database); + HTUnEscape(wais_database); + + /* + * This below fixed size stuff is terrible. + */ +#ifdef VMS + if ((request_message = typecallocn(char, MAX_MESSAGE_LEN)) == 0) + outofmem(__FILE__, "HTLoadWAIS"); + if ((response_message = typecallocn(char, MAX_MESSAGE_LEN)) == 0) + 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 = NULL; + FILE *fp; +#endif + HTStructured *target = HTML_new(anAnchor, format_out, sink); + + START(HTML_HEAD); + PUTC('\n'); + HTStartIsIndex(target, HTWAIS_SOLICIT_QUERY, NULL); + PUTC('\n'); + + { + START(HTML_TITLE); + PUTS(wais_database); + PUTS(gettext(" (WAIS Index)")); + END(HTML_TITLE); + PUTC('\n'); + END(HTML_HEAD); + PUTC('\n'); + + START(HTML_H1); + PUTS(gettext("WAIS Index: ")); + START(HTML_EM); + PUTS(wais_database); + END(HTML_EM); + END(HTML_H1); + PUTC('\n'); + PUTS(gettext("This is a link for searching the ")); + START(HTML_EM); + PUTS(wais_database); + END(HTML_EM); + PUTS(gettext(" WAIS Index.\n")); + + } + /* + * If we have seen a source file for this database, use that. + */ +#ifdef CACHE_FILE_PREFIX + HTSprintf0(&filename, "%sWSRC-%s:%s:%.100s.txt", + CACHE_FILE_PREFIX, + the_server_name, service, www_database); + + fp = fopen(filename, "r"); /* Have we found this already? */ + CTRACE((tfp, "HTWAIS: Description of server %s %s.\n", + filename, + fp ? "exists already" : "does NOT exist!")); + + if (fp) { + char c; + + START(HTML_PRE); /* Preformatted description */ + PUTC('\n'); + while ((c = getc(fp)) != EOF) + PUTC(c); /* Transfer file */ + END(HTML_PRE); + fclose(fp); + } + FREE(filename); +#endif + START(HTML_P); + PUTS(gettext("\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, '+')) != 0) + *p = ' '; + + /* + * Send advance title to get something fast to the other end. + */ + target = HTML_new(anAnchor, format_out, sink); + + START(HTML_HEAD); + PUTC('\n'); + HTStartIsIndex(target, HTWAIS_SOLICIT_QUERY, NULL); + PUTC('\n'); + START(HTML_TITLE); + PUTS(keywords); + PUTS(gettext(" (in ")); + PUTS(wais_database); + PUTC(')'); + END(HTML_TITLE); + PUTC('\n'); + END(HTML_HEAD); + PUTC('\n'); + + START(HTML_H1); + PUTS(gettext("WAIS Search of \"")); + START(HTML_EM); + PUTS(keywords); + END(HTML_EM); + PUTS(gettext("\" in: ")); + START(HTML_EM); + PUTS(wais_database); + END(HTML_EM); + END(HTML_H1); + PUTC('\n'); + + request_buffer_length = MAX_MESSAGE_LEN; /* Amount left */ + CTRACE((tfp, "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(gettext("HTWAIS: Request too large.")); + return_status = HT_NOT_LOADED; + FREE_TARGET; + goto CleanUp; +#else + panic("request too large"); +#endif /* VMS */ + } + + HTProgress(gettext("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(gettext("Search interrupted.")); + return_status = HT_INTERRUPTED; + FREE_TARGET; + goto CleanUp; + } else if (!rv) { +#ifdef VMS + HTAlert(HTWAIS_MESSAGE_TOO_BIG); + 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; + + CTRACE((tfp, + "HTWAIS: Retrieve document id `%s' type `%s' length %ld\n", + NonNull(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, + gettext("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 */ + CTRACE((tfp, "HTWAIS: Slice number %ld\n", count)); + + if (HTCheckForInterrupt()) { + HTAlert(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(gettext("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(gettext("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(TRANSFER_INTERRUPTED); + return_status = HT_INTERRUPTED; + FREE_TARGET; + FREE(type); + FREE(docid->bytes); + goto CleanUp; + } else if (!rv) { +#ifdef VMS + HTAlert(HTWAIS_MESSAGE_TOO_BIG); + 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(gettext("No text was returned!\n")); + /* panic("No text was returned"); */ + } else { + output_text_record(target, + ((WAISSearchResponse *) + retrieval_response->DatabaseDiagnosticRecords)->Text[0], + 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 HTProtocol HTWAIS = +{"wais", HTLoadWAIS, NULL}; +#endif /* GLOBALDEF_IS_MACRO */ |