HTWAIS.c
上传用户:zlh9724
上传日期:2007-01-04
资源大小:1991k
文件大小:28k
源码类别:

浏览器

开发平台:

Unix_Linux

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