home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / WAIS / ir / ui.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-02  |  13.6 KB  |  544 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. /* 
  9.  * this is a simple ui toolkit for building other ui's on top.
  10.  * -brewster
  11.  * 
  12.  * top level functions:
  13.  *   generate_search_apdu
  14.  *   generate_retrieval_apdu
  15.  *   interpret_message
  16.  *
  17.  */
  18.  
  19. /* to do:
  20.  *   generate multiple queries for long documents.
  21.  *     this will crash if the file being retrieved is larger than 100k.
  22.  *   
  23.  */
  24.  
  25. #include "ui.h"
  26. #include "wutil.h"
  27. #include "ustubs.h"
  28.  
  29. #include <ctype.h>
  30. #include <errno.h>
  31. #include <string.h>
  32. #include <sys/types.h>
  33.  
  34. #define HOSTNAME_BUFFER_SIZE 120
  35.  
  36. /* returns a pointer in the buffer of the first free byte.
  37.    if it overflows, then NULL is returned 
  38.  */
  39. char *
  40. generate_search_apdu(buff,
  41.              buff_len,
  42.              seed_words,
  43.              database_name,
  44.              docobjs,
  45.              maxDocsRetrieved)
  46. char* buff;     /* buffer to hold the apdu */
  47. long *buff_len;    /* length of the buffer changed to reflect new data written */
  48. char *seed_words;    /* string of the seed words */
  49. char *database_name;
  50. DocObj** docobjs;
  51. long maxDocsRetrieved;
  52. {
  53.   /* local variables */
  54.  
  55.   SearchAPDU *search3;
  56.   char  *end_ptr;
  57.   static char *database_names[2] = {"", 0};
  58.   any refID;
  59.   WAISSearch *query;
  60.   refID.size = 1;
  61.   refID.bytes = "3";
  62.  
  63.   database_names[0] = database_name;
  64.   query = makeWAISSearch(seed_words,
  65.                          docobjs, /* DocObjsPtr */
  66.                          0L,
  67.                          1L,     /* DateFactor */
  68.                          0L,     /* BeginDateRange */
  69.                          0L,     /* EndDateRange */
  70.                          maxDocsRetrieved
  71.                          );
  72.  
  73.   search3 = makeSearchAPDU(30L, 
  74.                5000L, /* should be large */
  75.                30L,
  76.                            1L,    /* replace indicator */
  77.                            "",    /* result set name */
  78.                            database_names, /* database name */   
  79.                            QT_RelevanceFeedbackQuery, /* query_type */
  80.                            0L,   /* element name */
  81.                            NULL, /* reference ID */
  82.                            query);
  83.  
  84.   end_ptr = writeSearchAPDU(search3, buff, buff_len);
  85.  
  86.   CSTFreeWAISSearch(query);
  87.   freeSearchAPDU(search3);
  88.   return(end_ptr);
  89. }
  90.  
  91.  
  92. /* returns a pointer into the buffer of the next free byte.
  93.    if it overflowed, then NULL is returned
  94.  */
  95.  
  96. char *
  97. generate_retrieval_apdu(buff,
  98.             buff_len,
  99.             docID,
  100.             chunk_type,
  101.             start,
  102.             end,
  103.             type,
  104.             database_name)
  105. char *buff;
  106. long *buff_len;    /* length of the buffer changed to reflect new data written */
  107. any *docID;
  108. long chunk_type;
  109. long start;
  110. long end;
  111. char *type;
  112. char *database_name;
  113. {
  114.   SearchAPDU *search;
  115.   char  *end_ptr;
  116.  
  117.   static char *database_names[2];
  118.   static char *element_names[3];
  119.   any refID;
  120.  
  121.   DocObj *DocObjs[2];
  122.   any *query;            /* changed from char* by brewster */
  123.  
  124.   if(NULL == type)
  125.     type = s_strdup("TEXT");
  126.  
  127.   database_names[0] = database_name;
  128.   database_names[1] = NULL;
  129.  
  130.   element_names[0] = " ";
  131.   element_names[1] = ES_DocumentText;
  132.   element_names[2] = NULL;
  133.  
  134.   refID.size = 1;
  135.   refID.bytes = "3";
  136.   
  137.   switch(chunk_type){
  138.   case CT_line: 
  139.     DocObjs[0] = makeDocObjUsingLines(docID, type, start, end);
  140.     break;
  141.   case CT_byte:
  142.     DocObjs[0] = makeDocObjUsingBytes(docID, type, start, end);
  143.     break;
  144.   }
  145.   DocObjs[1] = NULL;
  146.  
  147.   query = makeWAISTextQuery(DocObjs);   
  148.   search = makeSearchAPDU( 10L, 16L, 15L, 
  149.               1L,    /* replace indicator */
  150.               "FOO", /* result set name */
  151.               database_names, /* database name */   
  152.               QT_TextRetrievalQuery, /* query_type */
  153.               element_names, /* element name */
  154.               &refID, /* reference ID */
  155.               query);
  156.   end_ptr = writeSearchAPDU(search, buff, buff_len);
  157.   CSTFreeWAISTextQuery(query);
  158.   freeSearchAPDU(search);
  159.   return(end_ptr);
  160. }
  161.  
  162. /* not currently used 
  163.  
  164. static boolean isnumber _AP((char* string));
  165.  
  166. static boolean isnumber(string)
  167. char *string;
  168. {
  169.   long count;
  170.   for(count = 0; count < strlen(string); count++){
  171.     if(!isdigit(string[count])){
  172.       return(false);
  173.     }
  174.   }
  175.   return(true);
  176. }
  177.  
  178. */
  179.  
  180. /* this will negotiate with server, and returs the maximum buffer size 
  181.    the server can handle.
  182.  
  183.    A connection should be established first using open_socket.
  184.  
  185. */
  186.  
  187. long init_connection(inBuffer, outBuffer, bufferSize, connection, userInfo)
  188. char *inBuffer, *outBuffer;
  189. long bufferSize;
  190. FILE *connection;
  191. char *userInfo;
  192.   InitAPDU* init = NULL;
  193.   InitResponseAPDU* reply = NULL;
  194.   long result;
  195.   /* construct an init */
  196.   init = makeInitAPDU(true,false,false,false,false,bufferSize,bufferSize,
  197.               userInfo,defaultImplementationID(),
  198.               defaultImplementationName(),
  199.               defaultImplementationVersion(),NULL,userInfo);
  200.   /* write it to the buffer */
  201.   result = writeInitAPDU(init,inBuffer+HEADER_LENGTH,&bufferSize) - inBuffer;
  202.  
  203.   if(result < 0){
  204.     freeInitAPDU(init);
  205.     return(-1);
  206.   }
  207.   if(0 ==
  208.      interpret_message(inBuffer,
  209.                result - HEADER_LENGTH,
  210.                outBuffer,
  211.                bufferSize,
  212.                connection,
  213.                false    /* true verbose */    
  214.                )) {
  215.     /* error making a connection */
  216.     return (-1);
  217.   }
  218.   if (readInitResponseAPDU(&reply,outBuffer + HEADER_LENGTH) == NULL){
  219.     freeWAISInitResponse((WAISInitResponse*)reply->UserInformationField);
  220.     freeInitResponseAPDU(reply);
  221.     return(-1);
  222.   }
  223.   if (reply->Result == false)
  224.     {                /* the server declined service */
  225.       freeWAISInitResponse((WAISInitResponse*)reply->UserInformationField);
  226.       freeInitResponseAPDU(reply);
  227.       return(-1);
  228.     }
  229.   else                /* we got a response back */
  230.     { result = reply->MaximumRecordSize;
  231.       freeWAISInitResponse((WAISInitResponse*)reply->UserInformationField);
  232.       freeInitResponseAPDU(reply);
  233.       return(result);
  234.     }
  235. }
  236.  
  237. /* returns the length of the response, 0 if an error */
  238. long
  239. locally_answer_message(request_message,
  240.                request_length,
  241.                response_message,
  242.                response_buffer_length)
  243. char *request_message;
  244. long request_length;
  245. char *response_message;
  246. long response_buffer_length;
  247. {
  248.   long request_length_internal = request_length;
  249.   long response_length;
  250.   WAISMessage header;
  251.   long maxBufferSize = response_buffer_length;
  252.  
  253.   readWAISPacketHeader(request_message, &header);
  254.   {
  255.     char length_array[11];
  256.     strncpy(length_array, header.msg_len, 10);
  257.     length_array[10] = '\0';
  258.     request_length_internal = atol(length_array);
  259.   }
  260.   /*
  261.     printf("request length is %ld (%ld from caller)\n", 
  262.     request_length_internal,
  263.     request_length);
  264.     */
  265.   
  266.   response_length =
  267.     interpret_buffer(request_message + HEADER_LENGTH, 
  268.              request_length_internal,
  269.              response_message + HEADER_LENGTH,
  270.              response_buffer_length,
  271.              &maxBufferSize,
  272.              (long)header.hdr_vers,
  273.              NULL);
  274.   if(0 == response_length)
  275.     return(0);
  276.   writeWAISPacketHeader(response_message,
  277.             response_length,
  278.             (long)'z',    /* Z39.50 */
  279.             "DowQuest  ", /* server name */
  280.             (long)NO_COMPRESSION,    /* no compression */
  281.             (long)NO_ENCODING,(long)header.hdr_vers);
  282.   return(response_length);
  283. }
  284.  
  285. /* this is a safe version of unix 'read' it does all the checking
  286.  * and looping necessary
  287.  * to those trying to modify the transport code to use non-UNIX streams:
  288.  *  This is the function to modify!
  289.  */
  290. long read_from_stream(d,buf,nbytes)
  291. long d;                /* this is the stream */
  292. char *buf;
  293. long nbytes;
  294. {
  295.   long didRead;
  296.   long toRead = nbytes;
  297.   long totalRead = 0;        /* paranoia */
  298.  
  299.   while (toRead > 0){
  300.     didRead = read (d, buf, toRead);
  301.     if(didRead == -1)        /* error*/
  302.       return(-1);
  303.     if(didRead == 0)        /* eof */
  304.       return(-2);        /* maybe this should return 0? */
  305.     toRead -= didRead;
  306.     buf += didRead;
  307.     totalRead += didRead;
  308.   }
  309.   if(totalRead != nbytes)    /* we overread for some reason */
  310.     return(- totalRead);    /* bad news */    
  311.   return(totalRead);
  312. }
  313.  
  314. /* returns the length of the response, 0 if an error */
  315.  
  316. long 
  317. transport_message(connection,
  318.           request_message,
  319.           request_length,
  320.           response_message,
  321.           response_buffer_length)
  322. FILE *connection;
  323. char *request_message;
  324. long request_length;
  325. char *response_message;
  326. long response_buffer_length;
  327. {
  328.   WAISMessage header;
  329.   long response_length;
  330.  
  331.   
  332.   /* Write out message. Read back header. Figure out response length. */
  333.   
  334.   if( request_length + HEADER_LENGTH
  335.      != fwrite (request_message, 1L, request_length + HEADER_LENGTH, connection))
  336.     return 0;
  337.  
  338.   fflush(connection);
  339.  
  340.   /* read for the first '0' */
  341.  
  342.   while(1){
  343.     if(0 > read_from_stream(connection->_file, response_message, 1))
  344.       return 0;
  345.     if('0' == response_message[0])
  346.       break;
  347.   }
  348.  
  349.   if(0 > read_from_stream(connection->_file, 
  350.                   response_message + 1, 
  351.                   HEADER_LENGTH - 1))
  352.     return 0;
  353.  
  354.   readWAISPacketHeader(response_message, &header);
  355.   {
  356.     char length_array[11];
  357.     strncpy(length_array, header.msg_len, 10);
  358.     length_array[10] = '\0';
  359.     response_length = atol(length_array);
  360.     /*
  361.       if(verbose){
  362.       printf("WAIS header: '%s' length_array: '%s'\n", 
  363.       response_message, length_array);
  364.       }
  365.       */
  366.     if(response_length > response_buffer_length){
  367.       /* we got a message that is too long, therefore empty the message out,
  368.      and return 0 */
  369.       long i;
  370.       for(i = 0; i < response_length; i++){
  371.     read_from_stream(connection->_file, 
  372.              response_message + HEADER_LENGTH,
  373.              1);
  374. /*    fread(response_message + HEADER_LENGTH, 1, 1, connection); */
  375.       }
  376.       return(0);
  377.     }
  378.   }
  379.   if(0 > read_from_stream(connection->_file, 
  380.                   response_message + HEADER_LENGTH,
  381.                   response_length))
  382. /*  if(0 > fread(response_message + HEADER_LENGTH,
  383.            1, response_length, connection)) */
  384.     return 0;
  385.   return(response_length);
  386. }
  387.  
  388. /* returns the number of bytes writeen.  0 if an error */
  389. long
  390. interpret_message(request_message,request_length,
  391.           response_message,
  392.           response_buffer_length,
  393.           connection,
  394.           verbose)
  395. char *request_message;
  396. long request_length; /* length of the buffer */
  397. char *response_message;
  398. long response_buffer_length;
  399. FILE *connection;
  400. boolean verbose;
  401. {
  402.   long response_length;
  403.  
  404.   /* ?
  405.   if(verbose){
  406.     printf ("sending");
  407.     if(hostname_internal && strlen(hostname_internal) > 0)
  408.       printf(" to host %s", hostname_internal);
  409.     if(service_name && strlen(service_name) > 0)
  410.       printf(" for service %s", service_name);
  411.     printf("\n");
  412.     twais_dsply_rsp_apdu(request_message + HEADER_LENGTH, 
  413.              request_length);
  414.   }
  415.  
  416.   */
  417.  
  418.   writeWAISPacketHeader(request_message,
  419.             request_length,
  420.             (long)'z',    /* Z39.50 */
  421.             "wais      ", /* server name */
  422.             (long)NO_COMPRESSION,    /* no compression */
  423.             (long)NO_ENCODING,(long)HEADER_VERSION);
  424.   if(connection != NULL) {
  425.     if(0 == 
  426.        (response_length =
  427.     transport_message(connection, request_message,
  428.               request_length,
  429.               response_message,
  430.               response_buffer_length)))
  431.       return(0);
  432.   }
  433.   else{
  434.     if(0 == 
  435.        (response_length =
  436.     locally_answer_message(request_message, request_length, 
  437.                    response_message,
  438.                    response_buffer_length)))
  439.       return(0);
  440.   }
  441.   if(verbose){
  442.     printf ("decoded %ld bytes: \n", response_length);
  443.     twais_dsply_rsp_apdu(response_message + HEADER_LENGTH, 
  444.              request_length);
  445.   }
  446.   return(response_length);
  447. }
  448.  
  449. /* this closes the connection to the socket.
  450.  * the mythology is that this is cleaner than exiting
  451.  */
  452.  
  453. long close_connection(connection)
  454. FILE *connection;
  455. {
  456.   long result = 0;
  457.   
  458.   if(connection != NULL){
  459.     result = fclose(connection);
  460.   }
  461.   return(result);
  462. }
  463.   
  464. void
  465. display_text_record_completely(record,quote_string_quotes)
  466. WAISDocumentText *record;
  467. boolean quote_string_quotes;
  468. {
  469.   long count;
  470.   /* printf(" Text\n");
  471.      print_any("     DocumentID:  ", record->DocumentID);
  472.      printf("     VersionNumber:  %d\n", record->VersionNumber);
  473.      */
  474.   for(count = 0; count < record->DocumentText->size; count++){
  475.     long ch = (unsigned char)record->DocumentText->bytes[count];
  476.     if(27 == ch){
  477.       /* then we have an escape code */
  478.       /* if the next letter is '(' or ')', then ignore two letters */
  479.       if('(' == record->DocumentText->bytes[count + 1] ||
  480.      ')' == record->DocumentText->bytes[count + 1])
  481.     count += 1;             /* it is a term marker */
  482.       else count += 4;        /* it is a paragraph marker */
  483.     }
  484.     else if (ch == '\t') /* a TAB! */
  485.       putc(ch, stdout);
  486.     else if (isprint(ch)){
  487.       if(quote_string_quotes && ch == '"')
  488.     putc('\\', stdout);
  489.       putc(ch, stdout);
  490.     } 
  491.     else if (ch == '\n' || ch == '\r')
  492.       printf ("\n");
  493.   }
  494. }
  495.  
  496. /* modifies the string to exclude all seeker codes. sets length to
  497.    the new length. */
  498. char *delete_seeker_codes(string,length)
  499. char *string;
  500. long *length;
  501. {
  502.   long original_count; /* index into the original string */
  503.   long new_count = 0; /* index into the collapsed string */
  504.   for(original_count = 0; original_count < *length; original_count++){
  505.     if(27 == string[original_count]){
  506.       /* then we have an escape code */
  507.       /* if the next letter is '(' or ')', then ignore two letters */
  508.       if('(' == string[original_count + 1] ||
  509.     ')' == string[original_count + 1])
  510.      original_count += 1;    /* it is a term marker */
  511.       else original_count += 4; /* it is a paragraph marker */
  512.     }
  513.     else string[new_count++] = string[original_count];
  514.   }
  515.   *length = new_count;
  516.   return(string);
  517. }
  518.   
  519.  
  520. /* returns a pointer to a string with good stuff */
  521. char *trim_junk(headline)
  522. char *headline;
  523. {
  524.   long length = strlen(headline) + 1; /* include the trailing null */
  525.   long i;
  526.   headline = delete_seeker_codes(headline, &length);
  527.   /* delete leading spaces */
  528.   for(i=0; i < strlen(headline); i++){
  529.     if(isprint(headline[i])){
  530.       break;
  531.     }
  532.   }
  533.   headline = headline + i;
  534.   /* delete trailing stuff */
  535.   for(i=strlen(headline) - 1 ; i > 0; i--){
  536.     if(isprint(headline[i])){
  537.       break;
  538.     }
  539.     headline[i] = '\0';
  540.   }
  541.   return(headline);
  542. }
  543.