"Fossies" - the Fresh Open Source Software Archive

Member "lynx2.9.0dev.1/WWW/Library/Implementation/HTWAIS.c" (5 Mar 2018, 28187 Bytes) of package /linux/www/lynx2.9.0dev.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "HTWAIS.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.8.8rel.2_vs_2.8.9rel.1.

    1 /*
    2  * $LynxId: HTWAIS.c,v 1.39 2018/03/05 22:33:35 tom Exp $
    3  *
    4  *  WorldWideWeb - Wide Area Informaion Server Access   HTWAIS.c
    5  *  ==================================================
    6  *
    7  *  This module allows a WWW server or client to read data from a
    8  *  remote  WAIS
    9  *  server, and provide that data to a WWW client in hypertext form.
   10  *  Source files, once retrieved, are stored and used to provide
   11  *  information about the index when that is acessed.
   12  *
   13  *  Authors
   14  *  BK  Brewster Kahle, Thinking Machines, <Brewster@think.com>
   15  *  TBL Tim Berners-Lee, CERN <timbl@info.cern.ch>
   16  *  FM  Foteos Macrides, WFEB <macrides@sci.wfeb.edu>
   17  *
   18  *  History
   19  *     Sep 91   TBL adapted shell-ui.c (BK) with HTRetrieve.c from WWW.
   20  *     Feb 91   TBL Generated HTML cleaned up a bit (quotes, escaping)
   21  *              Refers to lists of sources.
   22  *     Mar 93   TBL Lib 2.0 compatible module made.
   23  *     May 94   FM  Added DIRECT_WAIS support for VMS.
   24  *
   25  *  Bugs
   26  *  Uses C stream i/o to read and write sockets, which won't work
   27  *  on VMS TCP systems.
   28  *
   29  *  Should cache connections.
   30  *
   31  *  ANSI C only as written
   32  *
   33  *  Bugs fixed
   34  *  NT Nathan Torkington (Nathan.Torkington@vuw.ac.nz)
   35  *
   36  *  WAIS comments:
   37  *
   38  *  1.  Separate directories for different system's .o would help
   39  *  2.  Document ids are rather long!
   40  *
   41  * W WW Address mapping convention:
   42  *
   43  *  /servername/database/type/length/document-id
   44  *
   45  *  /servername/database?word+word+word
   46  */
   47 /* WIDE AREA INFORMATION SERVER SOFTWARE:
   48    No guarantees or restrictions.  See the readme file for the full standard
   49    disclaimer.
   50 
   51    Brewster@think.com
   52 */
   53 
   54 #include <HTUtils.h>
   55 #include <HTParse.h>
   56 #include <HTAccess.h>       /* We implement a protocol */
   57 #include <HTML.h>       /* The object we will generate */
   58 #include <HTWSRC.h>
   59 #include <HTTCP.h>
   60 #include <HTCJK.h>
   61 #include <HTAlert.h>
   62 #include <LYStrings.h>
   63 
   64 #undef lines            /* term.h conflict with wais.h */
   65 #undef alloca           /* alloca.h conflict with wais.h */
   66 
   67 /*          From WAIS
   68  *          ---------
   69  */
   70 #ifdef VMS
   71 #include <HTVMS_WaisUI.h>
   72 #include <HTVMS_WaisProt.h>
   73 #elif defined(HAVE_WAIS_H)
   74 #include <wais.h>
   75 #else
   76 #include <ui.h>
   77 #endif /* VMS */
   78 
   79 #define MAX_MESSAGE_LEN 100000
   80 #define CHARS_PER_PAGE 10000    /* number of chars retrieved in each request */
   81 
   82 #define WAISSEARCH_DATE "Fri Jul 19 1991"
   83 
   84 /*          FROM WWW
   85  *          --------
   86  */
   87 #include <LYUtils.h>
   88 #include <LYLeaks.h>
   89 
   90 #define DIRECTORY "/cnidr.org:210/directory-of-servers"
   91 /* #define DIRECTORY "/quake.think.com:210/directory-of-servers" */
   92 
   93 #define BIG 1024        /* identifier size limit  @@@@@ */
   94 
   95 #define BUFFER_SIZE 4096    /* Arbitrary size for efficiency */
   96 
   97 #define HEX_ESCAPE '%'
   98 
   99 static BOOL as_gate;        /* Client is using us as gateway */
  100 
  101 static char line[2048];     /* For building strings to display */
  102 
  103                 /* Must be able to take id */
  104 
  105 #define PUTC(c) (*target->isa->put_character)(target, c)
  106 #define PUTS(s) (*target->isa->put_string)(target, s)
  107 #define START(e) (*target->isa->start_element)(target, e, 0, 0, -1, 0)
  108 #define END(e) (*target->isa->end_element)(target, e, 0)
  109 #define MAYBE_END(e) if (HTML_dtd.tags[e].contents != SGML_EMPTY) \
  110             (*target->isa->end_element)(target, e, 0)
  111 #define FREE_TARGET (*target->isa->_free)(target)
  112 
  113 struct _HTStructured {
  114     const HTStructuredClass *isa;
  115     /* ... */
  116 };
  117 
  118 /* ------------------------------------------------------------------------ */
  119 /* ---------------- Local copy of connect_to_server calls ----------------- */
  120 /* ------------------------------------------------------------------------ */
  121 /* Returns 1 on success, 0 on fail, -1 on interrupt. */
  122 static int fd_mosaic_connect_to_server(char *host_name,
  123                        long port,
  124                        long *fd)
  125 {
  126     char *dummy = NULL;
  127     int status;
  128     int result;
  129 
  130     HTSprintf0(&dummy, "%s//%s:%ld/", STR_WAIS_URL, host_name, port);
  131 
  132     status = HTDoConnect(dummy, "WAIS", 210, (int *) fd);
  133     if (status == HT_INTERRUPTED) {
  134     result = -1;
  135     } else if (status < 0) {
  136     result = 0;
  137     } else {
  138     result = 1;
  139     }
  140     FREE(dummy);
  141     return result;
  142 }
  143 
  144 /* Returns 1 on success, 0 on fail, -1 on interrupt. */
  145 #ifdef VMS
  146 static int mosaic_connect_to_server(char *host_name,
  147                     long port,
  148                     long *fdp)
  149 #else
  150 static int mosaic_connect_to_server(char *host_name,
  151                     long port,
  152                     FILE **fp)
  153 #endif              /* VMS */
  154 {
  155 #ifndef VMS
  156     FILE *file;
  157 #endif /* VMS */
  158     long fd;
  159     int rv;
  160 
  161     rv = fd_mosaic_connect_to_server(host_name, port, &fd);
  162     if (rv == 0) {
  163     HTAlert(gettext("Could not connect to WAIS server."));
  164     return 0;
  165     } else if (rv == -1) {
  166     HTAlert(CONNECTION_INTERRUPTED);
  167     return -1;
  168     }
  169 #ifndef VMS
  170     if ((file = fdopen(fd, "r+")) == NULL) {
  171     HTAlert(gettext("Could not open WAIS connection for reading."));
  172     return 0;
  173     }
  174 
  175     *fp = file;
  176 #else
  177     *fdp = fd;
  178 #endif /* VMS */
  179     return 1;
  180 }
  181 /* ------------------------------------------------------------------------ */
  182 /* ------------------------------------------------------------------------ */
  183 
  184 /*                              showDiags
  185 */
  186 /* modified from Jonny G's version in ui/question.c */
  187 static void showDiags(HTStream *target, diagnosticRecord ** d)
  188 {
  189     long i;
  190 
  191     for (i = 0; d[i] != NULL; i++) {
  192     if (d[i]->ADDINFO != NULL) {
  193         PUTS(gettext("Diagnostic code is "));
  194         PUTS(d[i]->DIAG);
  195         PUTC(' ');
  196         PUTS(d[i]->ADDINFO);
  197         PUTC('\n');
  198     }
  199     }
  200 }
  201 
  202 /*  Matrix of allowed characters in filenames
  203  *  -----------------------------------------
  204  */
  205 
  206 static BOOL acceptable[256];
  207 static BOOL acceptable_inited = NO;
  208 
  209 static void init_acceptable(void)
  210 {
  211     unsigned int i;
  212     char *good =
  213     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_$";
  214 
  215     for (i = 0; i < 256; i++)
  216     acceptable[i] = NO;
  217     for (; *good; good++)
  218     acceptable[(unsigned int) *good] = YES;
  219     acceptable_inited = YES;
  220 }
  221 
  222 /*  Transform file identifier into WWW address
  223  *  ------------------------------------------
  224  *
  225  *
  226  * On exit,
  227  *  returns     nil if error
  228  *          pointer to malloced string (must be freed) if ok
  229  */
  230 static char *WWW_from_archie(char *file)
  231 {
  232     char *end;
  233     char *result;
  234     char *colon;
  235 
  236     for (end = file; *end > ' '; end++) ;   /* assumes ASCII encoding */
  237     result = (char *) malloc(10 + (end - file));
  238     if (!result)
  239     return result;      /* Malloc error */
  240     strcpy(result, "file://");
  241     StrNCat(result, file, end - file);
  242     colon = StrChr(result + 7, ':');    /* Expect colon after host */
  243     if (colon) {
  244     for (; colon[0]; colon[0] = colon[1], colon++) ;    /* move down */
  245     }
  246     return result;
  247 }               /* WWW_from_archie */
  248 
  249 /*  Transform document identifier into URL
  250  *  --------------------------------------
  251  *
  252  *  Bugs: A static buffer of finite size is used!
  253  *  The format of the docid MUST be good!
  254  *
  255  *  On exit,
  256  *  returns     nil if error
  257  *          pointer to malloced string (must be freed) if ok
  258  */
  259 static char hex[17] = "0123456789ABCDEF";
  260 
  261 static char *WWW_from_WAIS(any *docid)
  262 {
  263     static char buf[BIG];
  264     char *q = buf;
  265     char *p = (docid->bytes);
  266     char *result = NULL;
  267     int i, l;
  268 
  269     if (TRACE) {
  270     char *p2;
  271 
  272     fprintf(tfp, "WAIS id (%d bytes) is ", (int) docid->size);
  273     for (p2 = docid->bytes; p2 < docid->bytes + docid->size; p2++) {
  274         if ((*p2 >= ' ') && (*p2 <= '~'))   /* Assume ASCII! */
  275         fprintf(tfp, "%c", *p2);
  276         else
  277         fprintf(tfp, "<%x>", (unsigned) *p2);
  278     }
  279     fprintf(tfp, "\n");
  280     }
  281     for (p = docid->bytes;
  282      (p < docid->bytes + docid->size) && (q < &buf[BIG]);) {
  283     CTRACE((tfp, "    Record type %d, length %d\n", p[0], p[1]));
  284     if (*p > 10) {
  285         CTRACE((tfp, "Eh?  DOCID record type of %d!\n", *p));
  286         return 0;
  287     } {         /* Bug fix -- allow any byte value 15 Apr 93 */
  288         unsigned int i2 = (unsigned) *p++;
  289 
  290         if (i2 > 99) {
  291         *q++ = (i2 / 100) + '0';
  292         i2 = i2 % 100;
  293         }
  294         if (i2 > 9) {
  295         *q++ = (i2 / 10) + '0';
  296         i2 = i2 % 10;
  297         }
  298         *q++ = i2 + '0';    /* Record type */
  299     }
  300     *q++ = '=';     /* Separate */
  301     l = *p++;       /* Length */
  302     for (i = 0; i < l; i++, p++) {
  303         if (!acceptable[UCH(*p)]) {
  304         *q++ = HEX_ESCAPE;  /* Means hex coming */
  305         *q++ = hex[(*p) >> 4];
  306         *q++ = hex[(*p) & 15];
  307         } else
  308         *q++ = *p;
  309     }
  310     *q++ = ';';     /* Terminate field */
  311     }
  312     *q++ = 0;           /* Terminate string */
  313     CTRACE((tfp, "WWW form of id: %s\n", buf));
  314     StrAllocCopy(result, buf);
  315     return result;
  316 }               /* WWW_from_WAIS */
  317 
  318 /*  Transform URL into WAIS document identifier
  319  *  -------------------------------------------
  320  *
  321  *  On entry,
  322  *  docname     points to valid name produced originally by
  323  *          WWW_from_WAIS
  324  *  On exit,
  325  *  docid->size is valid
  326  *  docid->bytes    is malloced and must later be freed.
  327  */
  328 static any *WAIS_from_WWW(any *docid, char *docname)
  329 {
  330     char *z;            /* Output pointer */
  331     char *sor;          /* Start of record - points to size field. */
  332     char *p;            /* Input pointer */
  333     char *q;            /* Poisition of "=" */
  334     char *s;            /* Position of semicolon */
  335     int n;          /* size */
  336 
  337     CTRACE((tfp, "WWW id (to become WAIS id): %s\n", docname));
  338     for (n = 0, p = docname; *p; p++) {     /* Count sizes of strings */
  339     n++;
  340     if (*p == ';')
  341         n--;        /* Not converted */
  342     else if (*p == HEX_ESCAPE)
  343         n = n - 2;      /* Save two bytes */
  344     docid->size = n;
  345     }
  346 
  347     if (!(docid->bytes = (char *) malloc(docid->size)))     /* result record */
  348     outofmem(__FILE__, "WAIS_from_WWW");
  349     z = docid->bytes;
  350 
  351     for (p = docname; *p;) {    /* Convert of strings */
  352     /* Record type */
  353 
  354     *z = 0;         /* Initialize record type */
  355     while (*p >= '0' && *p <= '9') {
  356         *z = *z * 10 + (*p++ - '0');    /* Decode decimal record type */
  357     }
  358     z++;
  359     if (*p != '=')
  360         return 0;
  361     q = p;
  362 
  363     s = StrChr(q, ';'); /* (Check only) */
  364     if (!s)
  365         return 0;       /* Bad! No ';'; */
  366     sor = z;        /* Remember where the size field was */
  367     z++;            /* Skip record size for now     */
  368     for (p = q + 1; *p != ';';) {
  369         if (*p == HEX_ESCAPE) {
  370         char c;
  371         unsigned int b;
  372 
  373         p++;
  374         c = *p++;
  375         b = from_hex(c);
  376         c = *p++;
  377         if (!c)
  378             break;  /* Odd number of chars! */
  379         *z++ = (b << 4) + from_hex(c);
  380         } else {
  381         *z++ = *p++;    /* Record */
  382         }
  383     }
  384     *sor = (z - sor - 1);   /* Fill in size -- not counting size itself */
  385     p++;            /* After semicolon: start of next record */
  386     }
  387 
  388     if (TRACE) {
  389     char *p2;
  390 
  391     fprintf(tfp, "WAIS id (%d bytes) is ", (int) docid->size);
  392     for (p2 = docid->bytes; p2 < docid->bytes + docid->size; p2++) {
  393         if ((*p2 >= ' ') && (*p2 <= '~'))   /* Assume ASCII! */
  394         fprintf(tfp, "%c", *p2);
  395         else
  396         fprintf(tfp, "<%x>", (unsigned) *p2);
  397     }
  398     fprintf(tfp, "\n");
  399     }
  400     return docid;       /* Ok */
  401 
  402 }               /* WAIS_from_WWW */
  403 
  404 /*  Send a plain text record to the client      output_text_record()
  405  *  --------------------------------------
  406  */
  407 static void output_text_record(HTStream *target,
  408                    WAISDocumentText *record,
  409                    boolean binary)
  410 {
  411     unsigned long count;
  412 
  413     /* printf(" Text\n");
  414        print_any("     DocumentID:  ", record->DocumentID);
  415        printf("     VersionNumber:  %d\n", record->VersionNumber);
  416      */
  417 
  418     if (binary) {
  419     (*target->isa->put_block) (target,
  420                    record->DocumentText->bytes,
  421                    record->DocumentText->size);
  422     return;
  423     }
  424 
  425     for (count = 0; count < record->DocumentText->size; count++) {
  426     long ch = (unsigned char) record->DocumentText->bytes[count];
  427 
  428     if (ch == 27) {     /* What is this in for?  Tim */
  429         /* then we have an escape code */
  430         /* if the next letter is '(' or ')', then ignore two letters */
  431         if ('(' == record->DocumentText->bytes[count + 1] ||
  432         ')' == record->DocumentText->bytes[count + 1])
  433         count += 1; /* it is a term marker */
  434         else
  435         count += 4; /* it is a paragraph marker */
  436     } else if (ch == '\n' || ch == '\r') {
  437         PUTC('\n');
  438     } else if (IS_CJK_TTY || ch == '\t' || isprint(ch)) {
  439         PUTC(ch);
  440     }
  441     }
  442 }               /* output text record */
  443 
  444 /*  Format A Search response for the client     display_search_response
  445  *  ---------------------------------------
  446  */
  447 /* modified from tracy shen's version in wutil.c
  448  * displays either a text record or a set of headlines.
  449  */
  450 static void display_search_response(HTStructured * target, SearchResponseAPDU *response,
  451                     char *the_database,
  452                     char *keywords)
  453 {
  454     WAISSearchResponse *info;
  455     long i, k;
  456 
  457     BOOL archie = strstr(the_database, "archie") != 0;  /* Special handling */
  458 
  459     CTRACE((tfp, "HTWAIS: Displaying search response\n"));
  460     PUTS(gettext("Index "));
  461     START(HTML_EM);
  462     PUTS(the_database);
  463     END(HTML_EM);
  464     sprintf(line, gettext(" contains the following %d item%s relevant to \""),
  465         (int) (response->NumberOfRecordsReturned),
  466         response->NumberOfRecordsReturned == 1 ? "" : "s");
  467     PUTS(line);
  468     START(HTML_EM);
  469     PUTS(keywords);
  470     END(HTML_EM);
  471     PUTS("\".\n");
  472     PUTS(gettext("The first figure after each entry is its relative score, "));
  473     PUTS(gettext("the second is the number of lines in the item."));
  474     START(HTML_BR);
  475     START(HTML_BR);
  476     PUTC('\n');
  477     START(HTML_OL);
  478 
  479     if (response->DatabaseDiagnosticRecords != 0) {
  480     info = (WAISSearchResponse *) response->DatabaseDiagnosticRecords;
  481     i = 0;
  482 
  483     if (info->Diagnostics != NULL)
  484         showDiags((HTStream *) target, info->Diagnostics);
  485 
  486     if (info->DocHeaders != 0) {
  487         for (k = 0; info->DocHeaders[k] != 0; k++) {
  488         WAISDocumentHeader *head = info->DocHeaders[k];
  489         char *headline = trim_junk(head->Headline);
  490         any *docid = head->DocumentID;
  491         char *docname;  /* printable version of docid */
  492 
  493         i++;
  494         /*
  495          * Make a printable string out of the document id.
  496          */
  497         CTRACE((tfp, "HTWAIS:  %2ld: Score: %4ld, lines:%4ld '%s'\n",
  498             i,
  499             (long int) (info->DocHeaders[k]->Score),
  500             (long int) (info->DocHeaders[k]->Lines),
  501             headline));
  502 
  503         START(HTML_LI);
  504 
  505         if (archie) {
  506             char *www_name = WWW_from_archie(headline);
  507 
  508             if (www_name) {
  509             HTStartAnchor(target, NULL, www_name);
  510             PUTS(headline);
  511             END(HTML_A);
  512             FREE(www_name);
  513             } else {
  514             PUTS(headline);
  515             PUTS(gettext(" (bad file name)"));
  516             }
  517         } else {    /* Not archie */
  518             docname = WWW_from_WAIS(docid);
  519             if (docname) {
  520             if ((head->Types) &&
  521                 (!strcmp(head->Types[0], "URL"))) {
  522                 HTStartAnchor(target, NULL, headline);
  523             } else {
  524                 char *dbname = HTEscape(the_database, URL_XPALPHAS);
  525                 char *w3_address = NULL;
  526 
  527                 HTSprintf0(&w3_address,
  528                        "/%s/%s/%d/%s",
  529                        dbname,
  530                        head->Types ? head->Types[0] : "TEXT",
  531                        (int) (head->DocumentLength),
  532                        docname);
  533                 HTStartAnchor(target, NULL, w3_address);
  534                 FREE(w3_address);
  535                 FREE(dbname);
  536             }
  537             PUTS(headline);
  538             END(HTML_A);
  539             FREE(docname);
  540             } else {
  541             PUTS(gettext("(bad doc id)"));
  542             }
  543         }
  544 
  545         sprintf(line, "%5ld  %5ld  ",
  546             head->Score,
  547             head->Lines);
  548         PUTS(line);
  549         MAYBE_END(HTML_LI);
  550         }           /* next document header */
  551     }
  552     /* if there were any document headers */
  553     if (info->ShortHeaders != 0) {
  554         k = 0;
  555         while (info->ShortHeaders[k] != 0) {
  556         i++;
  557         PUTS(gettext("(Short Header record, can't display)"));
  558         }
  559     }
  560     if (info->LongHeaders != 0) {
  561         k = 0;
  562         while (info->LongHeaders[k] != 0) {
  563         i++;
  564         PUTS(gettext("\nLong Header record, can't display\n"));
  565         }
  566     }
  567     if (info->Text != 0) {
  568         k = 0;
  569         while (info->Text[k] != 0) {
  570         i++;
  571         PUTS(gettext("\nText record\n"));
  572         output_text_record((HTStream *) target,
  573                    info->Text[k++], false);
  574         }
  575     }
  576     if (info->Headlines != 0) {
  577         k = 0;
  578         while (info->Headlines[k] != 0) {
  579         i++;
  580         PUTS(gettext("\nHeadline record, can't display\n"));
  581         /* dsply_headline_record( info->Headlines[k++]); */
  582         }
  583     }
  584     if (info->Codes != 0) {
  585         k = 0;
  586         while (info->Codes[k] != 0) {
  587         i++;
  588         PUTS(gettext("\nCode record, can't display\n"));
  589         /* dsply_code_record( info->Codes[k++]); */
  590         }
  591     }
  592     }               /* Loop: display user info */
  593     END(HTML_OL);
  594     PUTC('\n');
  595 }
  596 
  597 /*      Load by name                    HTLoadWAIS
  598  *      ============
  599  *
  600  *  This renders any object or search as required.
  601  */
  602 int HTLoadWAIS(const char *arg,
  603            HTParentAnchor *anAnchor,
  604            HTFormat format_out,
  605            HTStream *sink)
  606 #define MAX_KEYWORDS_LENGTH 1000
  607 #define MAX_SERVER_LENGTH 1000
  608 #define MAX_DATABASE_LENGTH 1000
  609 #define MAX_SERVICE_LENGTH 1000
  610 #define MAXDOCS 200
  611 
  612 {
  613     char *key;          /* pointer to keywords in URL */
  614     char *request_message = NULL;   /* arbitrary message limit */
  615     char *response_message = NULL;  /* arbitrary message limit */
  616     long request_buffer_length; /* how of the request is left */
  617     SearchResponseAPDU *retrieval_response = 0;
  618     char keywords[MAX_KEYWORDS_LENGTH + 1];
  619     char *the_server_name;
  620     char *wais_database = NULL; /* name of current database */
  621     char *www_database;     /* Same name escaped */
  622     char *service;
  623     char *doctype;
  624     char *doclength;
  625     long document_length = 0;
  626     char *docname = 0;
  627 
  628 #ifdef VMS
  629     long connection = 0;
  630 
  631 #else
  632     FILE *connection = NULL;
  633 #endif /* VMS */
  634     char *names;        /* Copy of arg to be hacked up */
  635     BOOL ok = NO;
  636     int return_status = HT_LOADED;
  637     int rv;
  638 
  639     if (!acceptable_inited)
  640     init_acceptable();
  641 
  642     /* Decipher and check syntax of WWW address:
  643      * ----------------------------------------
  644      *
  645      * First we remove the "wais:" if it was specified.  920110
  646      */
  647     names = HTParse(arg, "", PARSE_HOST | PARSE_PATH | PARSE_PUNCTUATION);
  648     key = StrChr(names, '?');
  649 
  650     if (key) {
  651     char *p;
  652 
  653     *key++ = 0;     /* Split off keywords */
  654     for (p = key; *p; p++)
  655         if (*p == '+')
  656         *p = ' ';
  657     HTUnEscape(key);
  658     }
  659     if (names[0] == '/') {
  660     the_server_name = names + 1;
  661     if ((as_gate = (*the_server_name == '/')) != 0)
  662         the_server_name++;  /* Accept one or two */
  663     www_database = StrChr(the_server_name, '/');
  664     if (www_database) {
  665         *www_database++ = 0;    /* Separate database name */
  666         doctype = StrChr(www_database, '/');
  667         if (key)
  668         ok = YES;   /* Don't need doc details */
  669         else if (doctype) { /* If not search parse doc details */
  670         *doctype++ = 0; /* Separate rest of doc address */
  671         doclength = StrChr(doctype, '/');
  672         if (doclength) {
  673             *doclength++ = 0;
  674             document_length = atol(doclength);
  675             if (document_length) {
  676             docname = StrChr(doclength, '/');
  677             if (docname) {
  678                 *docname++ = 0;
  679                 ok = YES;   /* To avoid a goto! */
  680             }   /* if docname */
  681             }       /* if document_length valid */
  682         }       /* if doclength */
  683         } else {        /* no doctype?  Assume index required */
  684         if (!key)
  685             key = "";
  686         ok = YES;
  687         }           /* if doctype */
  688     }           /* if database */
  689     }
  690 
  691     if (!ok)
  692     return HTLoadError(sink, 500, gettext("Syntax error in WAIS URL"));
  693 
  694     CTRACE((tfp, "HTWAIS: Parsed OK\n"));
  695 
  696     service = StrChr(names, ':');
  697     if (service)
  698     *service++ = 0;
  699     else
  700     service = "210";
  701 
  702     if (the_server_name[0] == 0) {
  703 #ifdef VMS
  704     connection = 0;
  705 #else
  706     connection = NULL;
  707 #endif /* VMS */
  708 
  709     } else if (!(key && !*key)) {
  710     int status;
  711 
  712     CTRACE((tfp, "===WAIS=== calling mosaic_connect_to_server\n"));
  713     status = mosaic_connect_to_server(the_server_name,
  714                       atoi(service),
  715                       &connection);
  716     if (status == 0) {
  717         CTRACE((tfp, "===WAIS=== connection failed\n"));
  718         FREE(names);
  719         return HT_NOT_LOADED;
  720     } else if (status == -1) {
  721         CTRACE((tfp, "===WAIS=== connection interrupted\n"));
  722         FREE(names);
  723         return HT_NOT_LOADED;
  724     }
  725     }
  726 
  727     StrAllocCopy(wais_database, www_database);
  728     HTUnEscape(wais_database);
  729 
  730     /*
  731      * This below fixed size stuff is terrible.
  732      */
  733 #ifdef VMS
  734     if ((request_message = typecallocn(char, MAX_MESSAGE_LEN)) == 0)
  735       outofmem(__FILE__, "HTLoadWAIS");
  736     if ((response_message = typecallocn(char, MAX_MESSAGE_LEN)) == 0)
  737       outofmem(__FILE__, "HTLoadWAIS");
  738 
  739 #else
  740     request_message = (char *) s_malloc((size_t) MAX_MESSAGE_LEN * sizeof(char));
  741     response_message = (char *) s_malloc((size_t) MAX_MESSAGE_LEN * sizeof(char));
  742 #endif /* VMS */
  743 
  744     /*
  745      * If keyword search is performed but there are no keywords, the user has
  746      * followed a link to the index itself.  It would be appropriate at this
  747      * point to send him the .SRC file - how?
  748      */
  749     if (key && !*key) {     /* I N D E X */
  750 #ifdef CACHE_FILE_PREFIX
  751     char *filename = NULL;
  752     FILE *fp;
  753 #endif
  754     HTStructured *target = HTML_new(anAnchor, format_out, sink);
  755 
  756     START(HTML_HEAD);
  757     PUTC('\n');
  758     HTStartIsIndex(target, HTWAIS_SOLICIT_QUERY, NULL);
  759     PUTC('\n');
  760 
  761     {
  762         START(HTML_TITLE);
  763         PUTS(wais_database);
  764         PUTS(gettext(" (WAIS Index)"));
  765         END(HTML_TITLE);
  766         PUTC('\n');
  767         END(HTML_HEAD);
  768         PUTC('\n');
  769 
  770         START(HTML_H1);
  771         PUTS(gettext("WAIS Index: "));
  772         START(HTML_EM);
  773         PUTS(wais_database);
  774         END(HTML_EM);
  775         END(HTML_H1);
  776         PUTC('\n');
  777         PUTS(gettext("This is a link for searching the "));
  778         START(HTML_EM);
  779         PUTS(wais_database);
  780         END(HTML_EM);
  781         PUTS(gettext(" WAIS Index.\n"));
  782 
  783     }
  784     /*
  785      * If we have seen a source file for this database, use that.
  786      */
  787 #ifdef CACHE_FILE_PREFIX
  788     HTSprintf0(&filename, "%sWSRC-%s:%s:%.100s.txt",
  789            CACHE_FILE_PREFIX,
  790            the_server_name, service, www_database);
  791 
  792     fp = fopen(filename, "r");  /* Have we found this already? */
  793     CTRACE((tfp, "HTWAIS: Description of server %s %s.\n",
  794         filename,
  795         fp ? "exists already" : "does NOT exist!"));
  796 
  797     if (fp) {
  798         char c;
  799 
  800         START(HTML_PRE);    /* Preformatted description */
  801         PUTC('\n');
  802         while ((c = getc(fp)) != EOF)
  803         PUTC(c);    /* Transfer file */
  804         END(HTML_PRE);
  805         fclose(fp);
  806     }
  807     FREE(filename);
  808 #endif
  809     START(HTML_P);
  810     PUTS(gettext("\nEnter the 's'earch command and then specify search words.\n"));
  811 
  812     FREE_TARGET;
  813     } else if (key) {       /* S E A R C H */
  814     char *p;
  815     HTStructured *target;
  816 
  817     LYStrNCpy(keywords, key, MAX_KEYWORDS_LENGTH);
  818     while ((p = StrChr(keywords, '+')) != 0)
  819         *p = ' ';
  820 
  821     /*
  822      * Send advance title to get something fast to the other end.
  823      */
  824     target = HTML_new(anAnchor, format_out, sink);
  825 
  826     START(HTML_HEAD);
  827     PUTC('\n');
  828     HTStartIsIndex(target, HTWAIS_SOLICIT_QUERY, NULL);
  829     PUTC('\n');
  830     START(HTML_TITLE);
  831     PUTS(keywords);
  832     PUTS(gettext(" (in "));
  833     PUTS(wais_database);
  834     PUTC(')');
  835     END(HTML_TITLE);
  836     PUTC('\n');
  837     END(HTML_HEAD);
  838     PUTC('\n');
  839 
  840     START(HTML_H1);
  841     PUTS(gettext("WAIS Search of \""));
  842     START(HTML_EM);
  843     PUTS(keywords);
  844     END(HTML_EM);
  845     PUTS(gettext("\" in: "));
  846     START(HTML_EM);
  847     PUTS(wais_database);
  848     END(HTML_EM);
  849     END(HTML_H1);
  850     PUTC('\n');
  851 
  852     request_buffer_length = MAX_MESSAGE_LEN;    /* Amount left */
  853     CTRACE((tfp, "HTWAIS: Search for `%s' in `%s'\n",
  854         keywords, wais_database));
  855     if (NULL ==
  856         generate_search_apdu(request_message + HEADER_LENGTH,
  857                  &request_buffer_length,
  858                  keywords, wais_database, NULL, MAXDOCS)) {
  859 #ifdef VMS
  860         HTAlert(gettext("HTWAIS: Request too large."));
  861         return_status = HT_NOT_LOADED;
  862         FREE_TARGET;
  863         goto CleanUp;
  864 #else
  865         panic("request too large");
  866 #endif /* VMS */
  867     }
  868 
  869     HTProgress(gettext("Searching WAIS database..."));
  870     rv = interpret_message(request_message,
  871                    MAX_MESSAGE_LEN - request_buffer_length,
  872                    response_message,
  873                    MAX_MESSAGE_LEN,
  874                    connection,
  875                    false    /* true verbose */
  876         );
  877 
  878     if (rv == HT_INTERRUPTED) {
  879         HTAlert(gettext("Search interrupted."));
  880         return_status = HT_INTERRUPTED;
  881         FREE_TARGET;
  882         goto CleanUp;
  883     } else if (!rv) {
  884 #ifdef VMS
  885         HTAlert(HTWAIS_MESSAGE_TOO_BIG);
  886         return_status = HT_NOT_LOADED;
  887         FREE_TARGET;
  888         goto CleanUp;
  889 #else
  890         panic("returned message too large");
  891 #endif /* VMS */
  892     } else {        /* returned message ok */
  893         SearchResponseAPDU *query_response = 0;
  894 
  895         readSearchResponseAPDU(&query_response,
  896                    response_message + HEADER_LENGTH);
  897         display_search_response(target,
  898                     query_response, wais_database, keywords);
  899         if (query_response->DatabaseDiagnosticRecords)
  900         freeWAISSearchResponse(query_response->DatabaseDiagnosticRecords);
  901         freeSearchResponseAPDU(query_response);
  902     }           /* returned message not too large */
  903     FREE_TARGET;
  904     } else {            /* D O C U M E N T    F E T C H */
  905     HTFormat format_in;
  906     boolean binary;     /* how to transfer stuff coming over */
  907     HTStream *target;
  908     long count;
  909     any doc_chunk;
  910     any *docid = &doc_chunk;
  911 
  912     CTRACE((tfp,
  913         "HTWAIS: Retrieve document id `%s' type `%s' length %ld\n",
  914         NonNull(docname), doctype, document_length));
  915 
  916     format_in =
  917         !strcmp(doctype, "WSRC") ? HTAtom_for("application/x-wais-source") :
  918         !strcmp(doctype, "TEXT") ? HTAtom_for(STR_PLAINTEXT) :
  919         !strcmp(doctype, "HTML") ? HTAtom_for(STR_HTML) :
  920         !strcmp(doctype, "GIF") ? HTAtom_for("image/gif") :
  921         HTAtom_for(STR_BINARY);
  922     binary =
  923         0 != strcmp(doctype, "WSRC") &&
  924         0 != strcmp(doctype, "TEXT") &&
  925         0 != strcmp(doctype, "HTML");
  926 
  927     target = HTStreamStack(format_in, format_out, sink, anAnchor);
  928     if (!target)
  929         return HTLoadError(sink, 500,
  930                    gettext("Can't convert format of WAIS document"));
  931     /*
  932      * Decode hex or litteral format for document ID.
  933      */
  934     WAIS_from_WWW(docid, docname);
  935 
  936     /*
  937      * Loop over slices of the document.
  938      */
  939     for (count = 0;
  940          count * CHARS_PER_PAGE < document_length;
  941          count++) {
  942 #ifdef VMS
  943         char *type = NULL;
  944 
  945         StrAllocCopy(type, doctype);
  946 #else
  947         char *type = s_strdup(doctype); /* Gets freed I guess */
  948 #endif /* VMS */
  949         request_buffer_length = MAX_MESSAGE_LEN;    /* Amount left */
  950         CTRACE((tfp, "HTWAIS: Slice number %ld\n", count));
  951 
  952         if (HTCheckForInterrupt()) {
  953         HTAlert(TRANSFER_INTERRUPTED);
  954         (*target->isa->_abort) (target, NULL);
  955 #ifdef VMS
  956         FREE(type);
  957 #endif /* VMS */
  958         return_status = HT_NOT_LOADED;
  959         goto CleanUp;
  960         }
  961 
  962         if (0 ==
  963         generate_retrieval_apdu(request_message + HEADER_LENGTH,
  964                     &request_buffer_length,
  965                     docid,
  966                     CT_byte,
  967                     count * CHARS_PER_PAGE,
  968                     (((count + 1) * CHARS_PER_PAGE <= document_length)
  969                      ? (count + 1) * CHARS_PER_PAGE
  970                      : document_length),
  971                     type,
  972                     wais_database)) {
  973 #ifdef VMS
  974         HTAlert(gettext("HTWAIS: Request too long."));
  975         return_status = HT_NOT_LOADED;
  976         FREE_TARGET;
  977         FREE(type);
  978         FREE(docid->bytes);
  979         goto CleanUp;
  980 #else
  981         panic("request too long");
  982 #endif /* VMS */
  983         }
  984 
  985         /*
  986          * Actually do the transaction given by request_message.
  987          */
  988         HTProgress(gettext("Fetching WAIS document..."));
  989         rv = interpret_message(request_message,
  990                    MAX_MESSAGE_LEN - request_buffer_length,
  991                    response_message,
  992                    MAX_MESSAGE_LEN,
  993                    connection,
  994                    false    /* true verbose */
  995         );
  996         if (rv == HT_INTERRUPTED) {
  997         HTAlert(TRANSFER_INTERRUPTED);
  998         return_status = HT_INTERRUPTED;
  999         FREE_TARGET;
 1000         FREE(type);
 1001         FREE(docid->bytes);
 1002         goto CleanUp;
 1003         } else if (!rv) {
 1004 #ifdef VMS
 1005         HTAlert(HTWAIS_MESSAGE_TOO_BIG);
 1006         return_status = HT_NOT_LOADED;
 1007         FREE_TARGET;
 1008         FREE(type);
 1009         FREE(docid->bytes);
 1010         goto CleanUp;
 1011 #else
 1012         panic("Returned message too large");
 1013 #endif /* VMS */
 1014         }
 1015 
 1016         /*
 1017          * Parse the result which came back into memory.
 1018          */
 1019         readSearchResponseAPDU(&retrieval_response,
 1020                    response_message + HEADER_LENGTH);
 1021 
 1022         if (NULL ==
 1023         ((WAISSearchResponse *)
 1024          retrieval_response->DatabaseDiagnosticRecords)->Text) {
 1025         /* display_search_response(target, retrieval_response,
 1026            wais_database, keywords); */
 1027         PUTS(gettext("No text was returned!\n"));
 1028         /* panic("No text was returned"); */
 1029         } else {
 1030         output_text_record(target,
 1031                    ((WAISSearchResponse *)
 1032                     retrieval_response->DatabaseDiagnosticRecords)->Text[0],
 1033                    binary);
 1034         }           /* If text existed */
 1035 
 1036 #ifdef VMS
 1037         FREE(type);
 1038 #endif /* VMS */
 1039     }           /* Loop over slices */
 1040 
 1041     FREE_TARGET;
 1042     FREE(docid->bytes);
 1043 
 1044     freeWAISSearchResponse(retrieval_response->DatabaseDiagnosticRecords);
 1045     freeSearchResponseAPDU(retrieval_response);
 1046 
 1047     }               /* If document rather than search */
 1048 
 1049   CleanUp:
 1050     /*
 1051      * (This postponed until later, after a timeout:)
 1052      */
 1053 #ifdef VMS
 1054     if (connection)
 1055     NETCLOSE((int) connection);
 1056 #else
 1057     if (connection)
 1058     fclose(connection);
 1059 #endif /* VMS */
 1060     FREE(wais_database);
 1061 #ifdef VMS
 1062     FREE(request_message);
 1063     FREE(response_message);
 1064 #else
 1065     s_free(request_message);
 1066     s_free(response_message);
 1067 #endif /* VMS */
 1068     FREE(names);
 1069     return (return_status);
 1070 }
 1071 
 1072 #ifdef GLOBALDEF_IS_MACRO
 1073 #define _HTWAIS_C_1_INIT { "wais", HTLoadWAIS, NULL }
 1074 GLOBALDEF(HTProtocol, HTWAIS, _HTWAIS_C_1_INIT);
 1075 #else
 1076 GLOBALDEF HTProtocol HTWAIS =
 1077 {"wais", HTLoadWAIS, NULL};
 1078 #endif /* GLOBALDEF_IS_MACRO */