home *** CD-ROM | disk | FTP | other *** search
/ Internet Publisher's Toolbox 2.0 / Internet Publisher's Toolbox.iso / internet / ntserver / wtsource / ui-local.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-14  |  19.7 KB  |  720 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.
  4.  
  5.    Brewster@think.com
  6. */
  7.  
  8. /* Copyright (c) CNIDR (see ../COPYRIGHT) */
  9.  
  10.  
  11. #ifndef lint
  12. static char *RCSid = "$Header: /usr/users/freewais/FreeWAIS-0.1/ir/ui-local.c,v 1.1 1993/02/16 15:05:35 freewais Exp $";
  13. #endif
  14.  
  15. /* Change log:
  16.  * $Log: ui-local.c,v $
  17.  * Revision 1.1  1993/02/16  15:05:35  freewais
  18.  * Initial revision
  19.  *
  20.  * Revision 1.16  92/03/18  09:01:09  jonathan
  21.  * don't free DocObjs[0]->Type, it's a copy of the input!
  22.  * 
  23.  * Revision 1.15  92/03/06  12:53:03  jonathan
  24.  * Plug another memory leak.  From ericb@baker.dartmouth.edu (Eric J Bivona).
  25.  * 
  26.  * Revision 1.14  92/02/14  15:26:53  jonathan
  27.  * Conditionalized interpret_message and locally_answer_message so client need
  28.  * not include search engine.
  29.  * 
  30.  * Revision 1.13  92/02/12  13:53:41  jonathan
  31.  * Added "$Log" so RCS will put the log message in the header
  32.  * 
  33.  * 
  34. */
  35.  
  36. /* 
  37.  * this is a simple ui toolkit for building other ui's on top.
  38.  * -brewster
  39.  * 
  40.  * top level functions:
  41.  *   generate_search_apdu
  42.  *   generate_retrieval_apdu
  43.  *   interpret_message
  44.  *
  45.  */
  46.  
  47. /* to do:
  48.  *   generate multiple queries for long documents.
  49.  *     this will crash if the file being retrieved is larger than 100k.
  50.  *   
  51.  */
  52.  
  53. #include "ui.h"
  54. #include "wutil.h"
  55. #include "ustubs.h"
  56. #include "futil.h"
  57.  
  58. #include <ctype.h>
  59. #include <errno.h>
  60. #include <string.h>
  61. #include <sys/types.h>
  62.  
  63. #ifdef WIN32
  64. #include <io.h>
  65. #endif
  66.  
  67. /* returns a pointer in the buffer of the first free byte.
  68.    if it overflows, then NULL is returned 
  69.  */
  70. char *
  71. generate_search_apdu(buff,
  72.                      buff_len,
  73.                      seed_words,
  74.                      database_name,
  75.                      docobjs,
  76.                      maxDocsRetrieved)
  77. char* buff;     /* buffer to hold the apdu */
  78. long *buff_len;    /* length of the buffer changed to reflect new data written */
  79. char *seed_words;    /* string of the seed words */
  80. char *database_name;
  81. DocObj** docobjs;
  82. long maxDocsRetrieved;
  83. {
  84.   /* local variables */
  85.  
  86.   SearchAPDU *search3;
  87.   char  *end_ptr;
  88.   static char *database_names[2] = {"", 0};
  89.   any refID;
  90.   WAISSearch *query;
  91.   refID.size = 1;
  92.   refID.bytes = "3";
  93.  
  94.   database_names[0] = database_name;
  95.   query = makeWAISSearch(seed_words,
  96.                          docobjs, /* DocObjsPtr */
  97.                          0L,
  98.                          1L,     /* DateFactor */
  99.                          0L,     /* BeginDateRange */
  100.                          0L,     /* EndDateRange */
  101.                          maxDocsRetrieved
  102.                          );
  103.  
  104.   search3 = makeSearchAPDU(30L, 
  105.                            5000L, /* should be large */
  106.                            30L,
  107.                            1L,  /* replace indicator */
  108.                            "",  /* result set name */
  109.                            database_names, /* database name */   
  110.                            QT_RelevanceFeedbackQuery, /* query_type */
  111.                            0L,   /* element name */
  112.                            NULL, /* reference ID */
  113.                            query);
  114.  
  115.   end_ptr = writeSearchAPDU(search3, buff, buff_len);
  116.  
  117.   CSTFreeWAISSearch(query);
  118.   freeSearchAPDU(search3);
  119.   return(end_ptr);
  120. }
  121.  
  122.  
  123. /* returns a pointer into the buffer of the next free byte.
  124.    if it overflowed, then NULL is returned
  125.  */
  126.  
  127. char *
  128.  generate_retrieval_apdu(buff,
  129.                         buff_len,
  130.                         docID,
  131.                         chunk_type,
  132.                         start,
  133.                         end,
  134.                         type,
  135.                         database_name)
  136. char *buff;
  137. long *buff_len;    /* length of the buffer changed to reflect new data written */
  138. any *docID;
  139. long chunk_type;
  140. long start;
  141. long end;
  142. char *type;
  143. char *database_name;
  144. {
  145.   SearchAPDU *search;
  146.   char  *end_ptr;
  147.  
  148.   static char *database_names[2];
  149.   static char *element_names[3];
  150.   any refID;
  151.  
  152.   DocObj *DocObjs[2];
  153.   any *query;                   /* changed from char* by brewster */
  154.  
  155.   if(NULL == type)
  156.     type = s_strdup("TEXT");
  157.  
  158.   database_names[0] = database_name;
  159.   database_names[1] = NULL;
  160.  
  161.   element_names[0] = " ";
  162.   element_names[1] = ES_DocumentText;
  163.   element_names[2] = NULL;
  164.  
  165.   refID.size = 1;
  166.   refID.bytes = "3";
  167.   
  168.   switch(chunk_type){
  169.   case CT_line: 
  170.     DocObjs[0] = makeDocObjUsingLines(docID, type, start, end);
  171.     break;
  172.   case CT_byte:
  173.     DocObjs[0] = makeDocObjUsingBytes(docID, type, start, end);
  174.     break;
  175.   }
  176.   DocObjs[1] = NULL;
  177.  
  178.   query = makeWAISTextQuery(DocObjs);   
  179.   search = makeSearchAPDU( 10L, 16L, 15L, 
  180.                           1L,   /* replace indicator */
  181.                           "FOO", /* result set name */
  182.                           database_names, /* database name */   
  183.                           QT_TextRetrievalQuery, /* query_type */
  184.                           element_names, /* element name */
  185.                           &refID, /* reference ID */
  186.                           query);
  187.   end_ptr = writeSearchAPDU(search, buff, buff_len);
  188.   /* s_free(DocObjs[0]->Type); it's a copy of the input, don't free it! */
  189.   CSTFreeDocObj(DocObjs[0]);
  190.   CSTFreeWAISTextQuery(query);
  191.   freeSearchAPDU(search);
  192.   return(end_ptr);
  193. }
  194.  
  195. /* not currently used 
  196.  
  197. static boolean isnumber _AP((char* string));
  198.  
  199. static boolean isnumber(string)
  200. char *string;
  201. {
  202.   long count;
  203.   for(count = 0; count < strlen(string); count++){
  204.     if(!isdigit(string[count])){
  205.       return(false);
  206.     }
  207.   }
  208.   return(true);
  209. }
  210.  
  211. */
  212.  
  213. /* this will negotiate with server, and returs the maximum buffer size 
  214.    the server can handle.
  215.  
  216.    A connection should be established first using open_socket.
  217.  
  218. */
  219.  
  220. long init_connection(inBuffer, outBuffer, bufferSize, connection, userInfo)
  221. char *inBuffer, *outBuffer;
  222. long bufferSize;
  223. FILE *connection;
  224. char *userInfo;
  225.   InitAPDU* init = NULL;
  226.   InitResponseAPDU* reply = NULL;
  227.   long result;
  228.   /* construct an init */
  229.   init = makeInitAPDU(true,false,false,false,false,bufferSize,bufferSize,
  230.                       userInfo,defaultImplementationID(),
  231.                       defaultImplementationName(),
  232.                       defaultImplementationVersion(),NULL,userInfo);
  233.   /* write it to the buffer */
  234.   result = writeInitAPDU(init,inBuffer+HEADER_LENGTH,&bufferSize) - inBuffer;
  235.  
  236.   if(result < 0){
  237.     freeInitAPDU(init);
  238.     return(-1);
  239.   }
  240.   if(0 ==
  241.      interpret_message(inBuffer,
  242.                        result - HEADER_LENGTH,
  243.                        outBuffer,
  244.                        bufferSize,
  245.                        connection,
  246.                        false    /* true verbose */      
  247.                        )) {
  248.     /* error making a connection */
  249.     return (-1);
  250.   }
  251.   if (readInitResponseAPDU(&reply,outBuffer + HEADER_LENGTH) == NULL){
  252.     freeWAISInitResponse((WAISInitResponse*)reply->UserInformationField);
  253.     freeInitResponseAPDU(reply);
  254.     return(-1);
  255.   }
  256.   if (reply->Result == false)
  257.     {                           /* the server declined service */
  258.       freeWAISInitResponse((WAISInitResponse*)reply->UserInformationField);
  259.       freeInitResponseAPDU(reply);
  260.       return(-1);
  261.     }
  262.   else                          /* we got a response back */
  263.     { result = reply->MaximumRecordSize;
  264.       freeWAISInitResponse((WAISInitResponse*)reply->UserInformationField);
  265.       freeInitResponseAPDU(reply);
  266.       return(result);
  267.     }
  268. }
  269.  
  270. #ifdef LOCAL_SEARCH
  271. /* returns the length of the response, 0 if an error */
  272. long
  273. locally_answer_message(request_message,
  274.                        request_length,
  275.                        response_message,
  276.                        response_buffer_length)
  277. char *request_message;
  278. long request_length;
  279. char *response_message;
  280. long response_buffer_length;
  281. {
  282.   long request_length_internal = request_length;
  283.   long response_length;
  284.   WAISMessage header;
  285.   long maxBufferSize = response_buffer_length;
  286.  
  287.   readWAISPacketHeader(request_message, &header);
  288.   {
  289.     char length_array[11];
  290.     strncpy(length_array, header.msg_len, 10);
  291.     length_array[10] = '\0';
  292.     request_length_internal = atol(length_array);
  293.   }
  294.   /*
  295.     printf("request length is %ld (%ld from caller)\n", 
  296.     request_length_internal,
  297.     request_length);
  298.     */
  299.   
  300.   response_length =
  301.     interpret_buffer(request_message + HEADER_LENGTH, 
  302.                      request_length_internal,
  303.                      response_message + HEADER_LENGTH,
  304.                      response_buffer_length,
  305.                      &maxBufferSize,
  306.                      (long)header.hdr_vers,
  307.                      "");
  308.   if(0 > response_length)
  309.     return(0);
  310.   writeWAISPacketHeader(response_message,
  311.                         response_length,
  312.                         (long)'z',      /* Z39.50 */
  313.                         "DowQuest  ", /* server name */
  314.                         (long)NO_COMPRESSION,   /* no compression */
  315.                         (long)NO_ENCODING,(long)header.hdr_vers);
  316.   return(response_length);
  317. }
  318. #endif
  319.  
  320. /* this is a safe version of unix 'read' it does all the checking
  321.  * and looping necessary
  322.  * to those trying to modify the transport code to use non-UNIX streams:
  323.  *  This is the function to modify!
  324.  */
  325.  
  326. #ifdef LINUX
  327. long read_from_stream(stream,buf,nbytes)
  328. FILE *stream;   /* this is the stream */
  329. #else
  330. long read_from_stream(d,buf,nbytes)
  331. long d;
  332. #endif /* LINUX */
  333.  
  334. char *buf;
  335. long nbytes;
  336. {
  337.   long didRead;
  338.   long toRead = nbytes;
  339.   long totalRead = 0;           /* paranoia */
  340.  
  341.   while (toRead > 0){
  342. #ifdef LINUX
  343.     didRead = fread (buf, sizeof(char), toRead, stream);
  344. #else
  345.     didRead = read(d, buf, toRead);
  346. #endif /* LINUX */
  347.  
  348.     if(didRead == -1)           /* error*/
  349.       return(-1);
  350.     if(didRead == 0)            /* eof */
  351.       return(-2);               /* maybe this should return 0? */
  352.     toRead -= didRead;
  353.     buf += didRead;
  354.     totalRead += didRead;
  355.   }
  356.   if(totalRead != nbytes)       /* we overread for some reason */
  357.     return(- totalRead);        /* bad news */    
  358.   return(totalRead);
  359. }
  360.  
  361. /* returns the length of the response, 0 if an error */
  362.  
  363. long 
  364. transport_message(connection,
  365.                   request_message,
  366.                   request_length,
  367.                   response_message,
  368.                   response_buffer_length)
  369. FILE *connection;
  370. char *request_message;
  371. long request_length;
  372. char *response_message;
  373. long response_buffer_length;
  374. {
  375.   WAISMessage header;
  376.   long response_length;
  377.  
  378.   
  379.   /* Write out message. Read back header. Figure out response length. */
  380.   
  381. #ifdef WIN32
  382.   if( request_length + HEADER_LENGTH
  383.      != (long)fwrite (request_message, 1L, request_length + HEADER_LENGTH, connection))
  384. #else
  385.   if( request_length + HEADER_LENGTH
  386.      != fwrite (request_message, 1L, request_length + HEADER_LENGTH, connection))
  387. #endif
  388.     return 0;
  389.  
  390.   fflush(connection);
  391.  
  392.   /* read for the first '0' */
  393.  
  394.   while(1){
  395.  
  396. #ifdef LINUX
  397.     if(0 > read_from_stream(connection, response_message, 1))
  398. #else
  399.     if (0 > read_from_stream(fileno(connection), response_message, 1))
  400. #endif /* LINUX */
  401.  
  402.       return 0;
  403.     if('0' == response_message[0])
  404.       break;
  405.   }
  406.  
  407. #ifdef LINUX
  408.   if(0 > read_from_stream(connection, response_message + 1, HEADER_LENGTH - 1))
  409. #else
  410.   if (0 > read_from_stream(fileno(connection), response_message+1, HEADER_LENGTH-1))
  411. #endif /* LINUX */
  412.  
  413.     return 0;
  414.  
  415.   readWAISPacketHeader(response_message, &header);
  416.   {
  417.     char length_array[11];
  418.     strncpy(length_array, header.msg_len, 10);
  419.     length_array[10] = '\0';
  420.     response_length = atol(length_array);
  421.     /*
  422.       if(verbose){
  423.       printf("WAIS header: '%s' length_array: '%s'\n", 
  424.       response_message, length_array);
  425.       }
  426.       */
  427.     if(response_length > response_buffer_length){
  428.       /* we got a message that is too long, therefore empty the message out,
  429.          and return 0 */
  430.       long i;
  431.       for(i = 0; i < response_length; i++){
  432.  
  433. #ifdef LINUX
  434.         read_from_stream(connection, response_message + HEADER_LENGTH, 1);
  435. #else
  436.         read_from_stream(fileno(connection),response_message+HEADER_LENGTH, 1);
  437. #endif /* LINUX */
  438.  
  439.       }
  440.       return(0);
  441.     }
  442.   }
  443.  
  444. #ifdef LINUX
  445.   if(0 > read_from_stream(connection, response_message + HEADER_LENGTH,
  446.                           response_length))
  447. #else
  448.   if (0> read_from_stream(fileno(connection),response_message+HEADER_LENGTH,
  449.                           response_length))
  450. #endif /* LINUX */
  451.  
  452.     return 0;
  453.   return(response_length);
  454. }
  455.  
  456.  
  457. /* ------------------------------------------------------------*/
  458.  
  459. /*  Facility to record messages sent and recieved for testing 
  460.     and timing purposes. */
  461.  
  462. /* from c:
  463.  
  464.    putenv(strdup("IR_FILE=/users/menlo-park/brewster/tmp/infile"));
  465.  
  466.    from csh:
  467.  
  468.    setenv IR_FILE /users/menlo-park/brewster/tmp/infile
  469.  
  470.  */
  471.  
  472. boolean environment_variables_read = false; 
  473. char* ir_file_environment_variable = "IR_FILE";
  474. char* ir_file = NULL;
  475.  
  476. void read_environment_variables(host, port)
  477.      char* host;
  478.      char* port;
  479. {
  480.   
  481.   if(!environment_variables_read){
  482.     FILE *stream;
  483.     ir_file = (char*)getenv(ir_file_environment_variable);
  484.     if(ir_file){
  485.       printf("IR_file: %s\n", ir_file);
  486.       stream = fopen(ir_file, "w");
  487.       fprintf(stream, "%s %s\n", host, port);
  488.       fclose(stream);
  489.     }
  490.     environment_variables_read = true;
  491.   }
  492. }
  493.  
  494. /* returns 0 if success */
  495. long write_message_to_file(message, length, filename)
  496.      unsigned char *message;
  497.      long length;
  498.      char*filename;
  499. {
  500.   FILE *stream = fopen(filename, "a");
  501.   if(NULL == stream)
  502.     return(-1);
  503.   
  504.   printf("Writing to file: %s %d characters\n", filename, length);
  505.  
  506.   fprintf(stream, "---------------------------------\n");
  507.   
  508. #ifdef WIN32
  509.   if(length != (long)fwrite(message, sizeof(unsigned char), 
  510.                       length, stream)){
  511. #else
  512.   if(length != fwrite(message, sizeof(unsigned char), 
  513.                       length, stream)){
  514. #endif
  515.     perror("fwrite error");
  516.     fclose(stream);
  517.     return(-2);
  518.   }
  519.  
  520.   fprintf(stream, "\n");
  521.  
  522.   if(0 != fclose(stream))
  523.     return(-3);
  524.   return(0);
  525. }  
  526.  
  527. /* ------------------------------------------------------------*/
  528.  
  529. /* returns the number of bytes writeen.  0 if an error */
  530. long
  531. interpret_message(request_message,request_length,
  532.                   response_message,
  533.                   response_buffer_length,
  534.                   connection,
  535.                   verbose)
  536. char *request_message;
  537. long request_length; /* length of the buffer */
  538. char *response_message;
  539. long response_buffer_length;
  540. FILE *connection;
  541. boolean verbose;
  542. {
  543.   long response_length;
  544.  
  545.   writeWAISPacketHeader(request_message,
  546.                         request_length,
  547.                         (long)'z',      /* Z39.50 */
  548.                         "wais      ", /* server name */
  549.                         (long)NO_COMPRESSION,   /* no compression */
  550.                         (long)NO_ENCODING,(long)HEADER_VERSION);
  551.  
  552.   if(ir_file){
  553.     long error_code;
  554.     if(0 != (error_code = 
  555.              write_message_to_file((unsigned char*)request_message, 
  556.                                    request_length + HEADER_LENGTH, 
  557.                                    ir_file)))
  558.       printf("Error writing log file Code: %d\n", error_code);
  559.   }
  560.     
  561.   if(connection != NULL) {
  562.     if(0 == 
  563.        (response_length =
  564.         transport_message(connection, request_message,
  565.                           request_length,
  566.                           response_message,
  567.                           response_buffer_length)))
  568.       return(0);
  569.   }
  570.   else{
  571. #ifdef LOCAL_SEARCH    
  572.     if(0 == 
  573.        (response_length =
  574.         locally_answer_message(request_message, request_length, 
  575.                                response_message,
  576.                                response_buffer_length)))
  577.       return(0);
  578. #else
  579.     waislog(WLOG_HIGH, WLOG_ERROR, "Local search not supported in this version");
  580.     return(0);
  581. #endif
  582.   }
  583.   if(verbose){
  584.     printf ("decoded %ld bytes: \n", response_length);
  585.     twais_dsply_rsp_apdu(response_message + HEADER_LENGTH, 
  586.                          request_length);
  587.   }
  588.   if(ir_file){
  589.     long error_code;
  590.     if(0 != (error_code = 
  591.              write_message_to_file((unsigned char*)response_message, 
  592.                                    response_length + HEADER_LENGTH, 
  593.                                    ir_file)))
  594.       printf("Error writing log file Code: %d\n", error_code);
  595.   }
  596.   return(response_length);
  597. }
  598.  
  599. /* this closes the connection to the socket.
  600.  * the mythology is that this is cleaner than exiting
  601.  */
  602.  
  603. long close_connection(connection)
  604. FILE *connection;
  605. {
  606.   long result = 0;
  607.   
  608.   if(connection != NULL){
  609.     result = fclose(connection);
  610.   }
  611.   return(result);
  612. }
  613.   
  614. void
  615. display_text_record_completely(record,quote_string_quotes)
  616. WAISDocumentText *record;
  617. boolean quote_string_quotes;
  618. {
  619.   long count;
  620.   /* printf(" Text\n");
  621.      print_any("     DocumentID:  ", record->DocumentID);
  622.      printf("     VersionNumber:  %d\n", record->VersionNumber);
  623.      */
  624. #ifdef WIN32
  625.   for(count = 0; count < (long)(record->DocumentText->size); count++){
  626. #else
  627.   for(count = 0; count < record->DocumentText->size; count++){
  628. #endif
  629.     long ch = (unsigned char)record->DocumentText->bytes[count];
  630.     if(27 == ch){
  631.       /* then we have an escape code */
  632.       /* if the next letter is '(' or ')', then ignore two letters */
  633.       if('(' == record->DocumentText->bytes[count + 1] ||
  634.          ')' == record->DocumentText->bytes[count + 1])
  635.         count += 1;             /* it is a term marker */
  636.       else count += 4;          /* it is a paragraph marker */
  637.     }
  638.     else if (ch == '\t') /* a TAB! */
  639.       putc(ch, stdout);
  640.     else if (isprint(ch)){
  641.       if(quote_string_quotes && ch == '"')
  642.         putc('\\', stdout);
  643.       putc(ch, stdout);
  644.     } 
  645.     else if (ch == '\n' || ch == '\r')
  646.       printf ("\n");
  647.   }
  648. }
  649.  
  650. /* modifies the string to exclude all seeker codes. sets length to
  651.    the new length. */
  652. char *delete_seeker_codes(string,length)
  653. char *string;
  654. long *length;
  655. {
  656.   long original_count; /* index into the original string */
  657.   long new_count = 0; /* index into the collapsed string */
  658.   for(original_count = 0; original_count < *length; original_count++){
  659.     if(27 == string[original_count]){
  660.       /* then we have an escape code */
  661.       /* if the next letter is '(' or ')', then ignore two letters */
  662.       if('(' == string[original_count + 1] ||
  663.     ')' == string[original_count + 1])
  664.      original_count += 1;    /* it is a term marker */
  665.       else original_count += 4; /* it is a paragraph marker */
  666.     }
  667.     else string[new_count++] = string[original_count];
  668.   }
  669.   *length = new_count;
  670.   return(string);
  671. }
  672.  
  673.  
  674.   
  675. /* returns a pointer to a string with good stuff */
  676. char *trim_junk(headline)
  677. char *headline;
  678. {
  679.   long length = strlen(headline) + 1; /* include the trailing null */
  680.   long i,j;
  681.   headline = delete_seeker_codes(headline, &length);
  682.  
  683.  
  684.   /* delete leading spaces */
  685. #ifdef WIN32
  686.   for(i=0; i < (long)strlen(headline); i++){
  687. #else
  688.   for(i=0; i < strlen(headline); i++){
  689. #endif
  690.     if(isprint(headline[i])){
  691.       break;
  692.     }
  693.   }
  694.   headline = headline + i;
  695.   /* delete trailing stuff */
  696. #ifdef WIN32
  697.   for (i = 0, j = 0; i < (long)strlen(headline)+1; i++) {
  698. #else
  699.   for (i = 0, j = 0; i < strlen(headline)+1; i++) {
  700. #endif
  701.     if ((headline[i] != '\r') && (headline[i] != '\n')) {
  702.       headline[j++] = headline[i];
  703.     }
  704.   }
  705.   
  706.  
  707.   for(i=strlen(headline) - 1 ; i > 0; i--){
  708.     if(isprint(headline[i])){
  709.       break;
  710.     }
  711.     headline[i] = '\0';
  712.   }
  713.   
  714.   return(headline);
  715. }
  716.  
  717.  
  718.                                                                                  
  719.