home *** CD-ROM | disk | FTP | other *** search
/ ftp.muug.mb.ca / 2014.06.ftp.muug.mb.ca.tar / ftp.muug.mb.ca / pub / src / gopher / gopher1.01 / misc / waisgopher / waisgopher.c < prev   
C/C++ Source or Header  |  1992-05-14  |  17KB  |  686 lines

  1. /* WAISgopher daemon...
  2.  
  3.    Paul Lindner, March 1992
  4.    <lindner@boombox.micro.umn.edu>
  5. */
  6.  
  7. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  8.    No guarantees or restrictions.  See the readme file for the full standard
  9.    disclaimer.
  10.    
  11.    Brewster@think.com
  12.    */
  13.  
  14. #include <ctype.h>
  15. #include <string.h>
  16. #include <ui.h>
  17. #include <sockets.h>
  18. #include <docid.h>
  19.  
  20. /*#include <netinet/in.h>
  21. #include <netdb.h>
  22. */
  23. #define MAIN
  24. #include "wais.h"
  25.  
  26. #define MAX_MESSAGE_LEN 100000
  27. #define CHARS_PER_PAGE 10000 /* number of chars retrieved in each request */
  28. #define MAX_FILE_NAME_LEN 1000
  29.  
  30. #define WAISSEARCH_DATE "Fri Sep 13 1991"
  31.  
  32. char* log_file_name = NULL;
  33. FILE* logfile = NULL;
  34.  
  35.  
  36. void
  37. PrintStatus(str)
  38. char * str;
  39. {
  40.   fprintf(stderr, "%s", str);
  41. }
  42.  
  43.  
  44. void ZapTabs(in)
  45.   char *in;
  46. {
  47.      /** replace tabs with a space... **/
  48.      while (*in != '\0') {
  49.       if (*in == '\t')
  50.            *in = ' ';
  51.       in ++;
  52.      }
  53. }
  54.  
  55. /*** Modified from ../ir/ui.c to add \r\n at the ends of the line... ***/
  56. void
  57. Mydisplay_text_record_completely(record,quote_string_quotes)
  58. WAISDocumentText *record;
  59. boolean quote_string_quotes;
  60. {
  61.   long count;
  62.   /* printf(" Text\n");
  63.      print_any("     DocumentID:  ", record->DocumentID);
  64.      printf("     VersionNumber:  %d\n", record->VersionNumber);
  65.      */
  66.   for(count = 0; count < record->DocumentText->size; count++){
  67.     long ch = (unsigned char)record->DocumentText->bytes[count];
  68.     if(27 == ch){
  69.       /* then we have an escape code */
  70.       /* if the next letter is '(' or ')', then ignore two letters */
  71.       if('(' == record->DocumentText->bytes[count + 1] ||
  72.      ')' == record->DocumentText->bytes[count + 1])
  73.     count += 1;             /* it is a term marker */
  74.       else count += 4;        /* it is a paragraph marker */
  75.     }
  76.     else if (ch == '\t') /* a TAB! */
  77.       putc(ch, stdout);
  78.     else if (isprint(ch)){
  79.       if(quote_string_quotes && ch == '"')
  80.     putc('\\', stdout);
  81.       putc(ch, stdout);
  82.     } 
  83.     else if (ch == '\n' || ch == '\r')
  84.       printf ("\r\n");
  85.   }
  86. }
  87.  
  88.  
  89.  
  90. /* modified from Jonny G's version in ui/question.c */
  91. void showDiags(d)
  92.   diagnosticRecord **d;
  93. {
  94.      long i;
  95.      
  96.      for (i = 0; d[i] != NULL; i++) {
  97.       if (d[i]->ADDINFO != NULL) {
  98.            printf("Code: %s, %s\n", d[i]->DIAG, d[i] ->ADDINFO);
  99.       }
  100.      }
  101. }
  102.  
  103.  
  104.  
  105. void
  106. ZapCRLF(inputline)
  107. char *inputline;
  108. {
  109.      char *cp;
  110.      
  111.      cp = strchr(inputline, '\r');    /* Zap CR-LF */
  112.      if (cp != NULL)
  113.           *cp = '\0';
  114.      else {
  115.           cp = strchr(inputline, '\n');
  116.           if (cp != NULL)
  117.                *cp = '\0';
  118.      }
  119. }
  120.  
  121.  
  122. int
  123. acceptable(foo)
  124.   char foo;
  125. {
  126.      if (foo == '\t' || foo == '\r' || foo == '\n' || foo == '\0')
  127.       return(0);
  128.      else if (!isprint(foo))
  129.       return(0);
  130.      else
  131.       return(1);
  132. }
  133.  
  134.  
  135.  
  136. static char * hex = "0123456789ABCDEF";
  137.  
  138. /*      Decode one hex character
  139. */
  140.  
  141. char 
  142. from_hex(c)
  143.   char c;
  144. {
  145.      return                (c>='0')&&(c<='9') ? c-'0'
  146.       : (c>='A')&&(c<='F') ? c-'A'+10
  147.            : (c>='a')&&(c<='f') ? c-'a'+10
  148.             :                      0;
  149. }
  150.  
  151.  
  152. /*
  153.  * DocId_to_Gopher transforms a docid into a character string suitable for
  154.  * transmission
  155.  */
  156.  
  157. char *DocId_to_Gopher(docid, docsize)
  158.   any *docid;
  159. {
  160.      static char GopherString[512];
  161.      char *q = GopherString;
  162.      char *p;
  163.      int l, i;
  164.           
  165.      /** First lets stick on the size of the document first **/
  166.  
  167.      sprintf(GopherString, "%d", docsize);
  168.      q += strlen(GopherString);
  169.      *q++ = ':';
  170.  
  171.      for (p=docid->bytes; (p < docid->bytes + docid->size) && q<&GopherString[512];) {
  172.       if (*p >= 10) {
  173.            ; /* Bad thing happened, can't understand docid, punt */
  174.            return(NULL);
  175.       }
  176.       
  177.       *q++ = (*p++) + '0';   /* Record Type */
  178.       *q++ = '=';            /* Seperate */
  179.       l = *p++;              /* Length */
  180.       for (i=0; i<l; i++, p++) {
  181.            if (acceptable(*p)==0) {
  182.             *q++ = '%';
  183.             *q++ = hex[(*p) >> 4];
  184.             *q++ = hex[(*p) & 15];
  185.            }
  186.            else *q++ = *p;
  187.       }
  188.       *q++ = ';';
  189.      }
  190.      *q++ = 0;
  191.      return(GopherString);
  192. }
  193.  
  194. /*
  195.  * Gstring is a name produced by DocID_to_Gopher
  196.  */
  197.  
  198. any *Gopher_to_DocId(Gstring, DocSize)
  199.   char *Gstring;
  200.   int *DocSize;
  201. {
  202.      static any docid;
  203.      char *outptr;
  204.      char *inptr; 
  205.      char *sor;
  206.      char *eqptr;  
  207.      char *semiptr;
  208.      int size; 
  209.  
  210.      /* Strip off the Document size first.... */
  211.      
  212.      inptr = strchr(Gstring, ':');
  213.      if (inptr == NULL) 
  214.       return;
  215.  
  216.      *DocSize = atoi(Gstring);
  217.      
  218.      Gstring = inptr +1;
  219.  
  220.      for (size=0, inptr=Gstring; *inptr; inptr++) {
  221.       size ++;
  222.       if (*inptr == ';') 
  223.            size--;
  224.       else if (*inptr ==  '%') 
  225.            size -=2;
  226.       
  227.      }
  228.  
  229.      docid.size = size;
  230.  
  231.      docid.bytes = (char *) malloc(docid.size);
  232.      outptr = docid.bytes;
  233.  
  234.      for (inptr = Gstring; *inptr;) {
  235.       *outptr++ = *inptr++ - '0';  /* Record Type */
  236.       eqptr = strchr(inptr, '=');
  237.       if (!eqptr)
  238.            return(0);
  239.       semiptr = strchr(inptr, ';');
  240.       if (!semiptr)
  241.            return(0);
  242.       sor = outptr;
  243.       outptr++;
  244.  
  245.       for (inptr = eqptr+1; *inptr!=';' ; ) {
  246.            if (*inptr == '%') {
  247.             char c;
  248.             unsigned int b;
  249.             
  250.             inptr++;
  251.             c = *inptr++;
  252.             b = from_hex(c);
  253.             c = *inptr++;
  254.             if (!c) break;
  255.             *outptr++ = (b<<4) + from_hex(c);
  256.            } else {
  257.             *outptr++ = *inptr++;
  258.            }
  259.       }
  260.       
  261.       *sor = (outptr-sor-1);
  262.       inptr++;
  263.      }
  264.      
  265.      return(&docid);
  266.  
  267. }
  268.             
  269.  
  270.  
  271. /*-----------------------------------------------------------------*/
  272.  
  273. /* modified from tracy shen's version in wutil.c
  274.  * displays either a text record of a set of headlines.
  275.  */
  276. void
  277. display_search_response(response, hostname, port, dbname, GateHost, GatePort, SourceName)
  278.   SearchResponseAPDU *response;
  279.   char *hostname, *port, *dbname, *GateHost, *GatePort, *SourceName;
  280. {
  281.      WAISSearchResponse  *info;
  282.      long continue_viewing;
  283.      long i, k;
  284.      struct sockaddr_in serv_addr;
  285.      int length = sizeof(serv_addr);
  286.      int GopherPort;
  287.      
  288.      /** Try to figure out the port we're running on. **/
  289.      
  290.      if (getsockname(0, &serv_addr,&length) == 0)
  291.       GopherPort = ntohs(serv_addr.sin_port);
  292.      
  293.      if ( response->DatabaseDiagnosticRecords != 0 ) {
  294.       info = (WAISSearchResponse *)response->DatabaseDiagnosticRecords;
  295.       i =0; 
  296.           
  297.       if (info->Diagnostics != NULL)
  298.            showDiags(info->Diagnostics);
  299.       
  300.       if ( info->DocHeaders != 0 ) {
  301.            k =0;
  302.            while (info->DocHeaders[k] != 0 ) {
  303.             i++;
  304.             ZapCRLF(info->DocHeaders[k]->Headline);
  305.             ZapTabs(info->DocHeaders[k]->Headline);
  306.             printf("0%s\t-%s:%s\t%s\t%d\r\n", 
  307.                info->DocHeaders[k]->Headline,
  308.                SourceName,
  309.                DocId_to_Gopher(info->DocHeaders[k]->DocumentID, info->DocHeaders[k]->DocumentLength),
  310.                GateHost,
  311.                GopherPort
  312.               );
  313.  
  314.             k++;
  315.            }
  316.            printf(".\r\n");
  317.       }
  318.  
  319.       if ( info->Text != 0 ) {
  320.            k =0;
  321.            while ( (continue_viewing == 1) && (info->Text[k] != 0) ) {
  322.             i++;
  323.             printf("\n    Text record %2d, ", i);
  324.             Mydisplay_text_record_completely( info->Text[k++], false);
  325.            }
  326.       }
  327.      }                /* display user info */
  328. }
  329.  
  330.  
  331.  
  332. #define MAX_KEYWORDS_LENGTH 1000
  333. #define MAX_SERVER_LENGTH 1000
  334. #define MAX_DATABASE_LENGTH 1000
  335. #define MAX_SERVICE_LENGTH 1000
  336. #define MAXDOCS 40
  337.  
  338. /* any*
  339.      copy_any(thing)
  340. any *thing;
  341. {
  342.      int i;
  343.      any* result;
  344.      
  345.      result = NULL;
  346.      
  347.      if(thing != NULL) {
  348.       if((result = (any*)s_malloc(sizeof(any))) != NULL) {
  349.            result->bytes = NULL;
  350.            result->size = thing->size;
  351.            if((result->bytes = s_malloc(thing->size)) != NULL) {
  352.             for(i = 0; i < thing->size; i++)
  353.              result->bytes[i] = thing->bytes[i];
  354.            }
  355.       }
  356.      }
  357.      return result;
  358. }
  359.  
  360. */
  361. /******************************************************************/
  362.  
  363. void main(argc, argv)
  364.   int argc;
  365.   char *argv[];
  366. {
  367.      char* request_message = NULL; /* arbitrary message limit */
  368.      char* response_message = NULL; /* arbitrary message limit */
  369.      long request_buffer_length;    /* how of the request is left */
  370.      SearchResponseAPDU  *query_response;
  371.      SearchResponseAPDU  *retrieval_response;
  372.      WAISSearchResponse  *query_info, *retrieval_info;
  373.      char server_name[MAX_SERVER_LENGTH + 1];    
  374.      char service[MAX_SERVICE_LENGTH + 1];
  375.      char database[MAX_DATABASE_LENGTH + 1];
  376.      char *next_argument, *command_name;
  377.      long count;
  378.      FILE *connection;
  379.      int Searching = 1;  /** Default is to search **/
  380.      char *keywords;
  381.      char *DocIdString;
  382.      char *Inputline;
  383.      char *Dotsrcfile;
  384.      char *SourceName;
  385.      char *WaisGateHost=NULL, *WaisGatePort=NULL;
  386.      
  387.      next_argument = next_arg(&argc, &argv);
  388.      command_name = next_argument;
  389.      
  390.      server_name[0] = '\0';  /* null it out */
  391.      database[0] = '\0';  /* null it out */
  392.      service[0] = '\0';  /* null it out */
  393.  
  394.      while(NULL != (next_argument = next_arg(&argc, &argv))) {
  395.       /* then we have an argument to process */
  396.       if(0 == strcmp("-debug", next_argument)){
  397.            logfile = stderr;
  398.       }
  399.       else if(0 == strcmp("-v", next_argument)){
  400.            printf("%s version: %s, %s\n",
  401.               command_name, VERSION, WAISSEARCH_DATE);
  402.       }
  403.       else if(0 == strcmp("-h", next_argument)) {
  404.            if (NULL == (next_argument = next_arg(&argc, &argv)))
  405.             printf("Syntax error, need a host!!\n"), exit(-1);
  406.            else 
  407.             WaisGateHost = next_argument;
  408.       }
  409.  
  410.       else if(0== strcmp("-s", next_argument)) {
  411.            if (NULL == (next_argument = next_arg(&argc, &argv)))
  412.             printf("Syntax error, need a sourcefile!!\n"), exit(-1);
  413.            else {
  414.             FILE *Srcfile;
  415.             Source Moo;
  416.  
  417.             Moo = (Source)malloc(sizeof(_Source));
  418.  
  419.             Srcfile = fopen(next_argument, "r");
  420.             if (Srcfile == NULL) {
  421.              printf("File \"%s\" does not exist\r\n", next_argument), exit(-1);
  422.             }
  423.             
  424.             ReadSource(Moo, Srcfile);
  425.  
  426. /*            printf("server: %s, database: %s, service: %s\n", Moo->server, Moo->database, Moo->service);*/
  427.  
  428.             strcpy(server_name, Moo->server);
  429.             strcpy(database, Moo->database);
  430.             strcpy(service, Moo->service);
  431.            }
  432.       }
  433.  
  434.       else if(0 == strcmp("-p", next_argument)) {
  435.            if (NULL == (next_argument = next_arg(&argc, &argv)))
  436.             printf("Syntax error, need a port number!!\n"), exit(-1);
  437.            else 
  438.             WaisGatePort = next_argument;
  439.       }
  440.  
  441.       else if (0== strcmp("-i", next_argument)) {
  442.            Searching = 0;  /** Not searching, we're fetching by docid **/
  443.       }
  444.  
  445.       else{
  446.            panic("Don't recognize the %s option", next_argument);
  447.       }
  448.      }
  449.  
  450.      if (Searching == 1 && (WaisGateHost == NULL)) {
  451.       printf("4Must specify a gateway host and port!\r\n.\r\n"), exit(-1);
  452.      }
  453.  
  454.      Inputline = (char *) malloc(1024);
  455.      gets(Inputline);
  456.       
  457.      ZapCRLF(Inputline);
  458.      
  459.      if (Inputline[0] == '-') {
  460.       Searching = 0;  /** We got ourselves a docid... **/
  461.       Inputline++;
  462.      }
  463.      
  464.      /**
  465.       ** Next load up the name of the source...
  466.       */
  467.      
  468.      {
  469.       FILE *Srcfile;
  470.       Source Moo;
  471.       char *cp;
  472.  
  473.       /*
  474.            * A search request will have a tab separator.  A document
  475.        * request will have a : separator.
  476.        */
  477.  
  478.       if (Searching) {
  479.            cp = strchr(Inputline, '\t');
  480.            keywords = cp + 1;
  481.       }
  482.       else {
  483.            cp =strchr(Inputline, ':');
  484.            DocIdString = cp +1;
  485.       }
  486.  
  487.       if (cp == NULL) {
  488.            /** An error occured, probably old client software... **/
  489.            printf(".\r\n");
  490.       } else
  491.            *cp = '\0';
  492.       
  493.       SourceName= Inputline;
  494.  
  495.       Moo = (Source)malloc(sizeof(_Source));
  496.       
  497.       Srcfile = fopen(SourceName, "r");
  498.       if (Srcfile == NULL) {
  499.            printf("File \"%s\" does not exist\r\n.\r\n", SourceName), exit(-1);
  500.       }
  501.       
  502.       ReadSource(Moo, Srcfile);
  503.       strcpy(server_name, Moo->server);
  504.       strcpy(database, Moo->database);
  505.       strcpy(service, Moo->service);
  506.      }
  507.  
  508.      if (server_name[0] == 0)
  509.       connection = NULL;
  510.      
  511.      else if ((connection=connect_to_server(server_name,atoi(service))) == NULL) 
  512.      {
  513.       fprintf (stderr, "Error openning connection to %s via service %s.\r\n.\r\n",
  514.            server_name, service);
  515.       exit(-1);
  516.      }
  517.      
  518.      request_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
  519.      response_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
  520.      
  521.      {
  522.      char userInfo[500];
  523.      char hostname[80];
  524.      
  525.      gethostname(hostname, 80);
  526.  
  527.      sprintf(userInfo, "waisgopher %s, gateway: %s, user: gopher@boombox.micro.umn.edu",
  528.          VERSION, hostname );
  529.  
  530.      
  531.      init_connection(request_message, response_message,
  532.              MAX_MESSAGE_LEN,
  533.              connection,
  534.              userInfo);
  535.       }
  536.  
  537.      request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
  538.  
  539.      /***********************************************************************
  540.       **** Branch off here, if we have a search request do it.
  541.            otherwise if we have a docid, fetch it.
  542.       ****/
  543.  
  544.      if (Searching) {
  545.  
  546.       if(NULL ==
  547.          generate_search_apdu(request_message + HEADER_LENGTH, 
  548.                   &request_buffer_length, 
  549.                   keywords, database, NULL, MAXDOCS))
  550.            panic("request too large");
  551.       
  552.       
  553.       if(0 ==
  554.          interpret_message(request_message, 
  555.                    MAX_MESSAGE_LEN - request_buffer_length, 
  556.                    response_message,
  557.                    MAX_MESSAGE_LEN,
  558.                    connection,
  559.                    false    /* true verbose */
  560.                    )) { /* perhaps the server shut down on us, let's see: */
  561.            if ( connection != NULL) {
  562.             fclose(connection);
  563.             if ((connection=connect_to_server(server_name,atoi(service))) == NULL) 
  564.             {
  565.              printf("Error openning connection to %s via service %s.\n",
  566.                   server_name, service);
  567.              exit(-1);
  568.             }
  569.             if(0 ==
  570.                interpret_message(request_message, 
  571.                      MAX_MESSAGE_LEN - request_buffer_length, 
  572.                      response_message,
  573.                      MAX_MESSAGE_LEN,
  574.                      connection,
  575.                      false /* true verbose */
  576.                      ))
  577.              panic("really couldn't deliver message");
  578.            }
  579.            else
  580.             panic("returned message too large");
  581.       }
  582.      
  583.       readSearchResponseAPDU(&query_response, response_message + HEADER_LENGTH);
  584.  
  585.       display_search_response(query_response, server_name, service, database, WaisGateHost, WaisGatePort, SourceName);
  586.  
  587.       freeWAISSearchResponse(query_response->DatabaseDiagnosticRecords);         
  588.       freeSearchResponseAPDU( query_response);
  589.  
  590.      }  /*** Searching? ***/
  591.  
  592.  
  593.      else  {  /*** Retrieve by docid ***/
  594.  
  595.       any *docid;
  596.       int DocLen;
  597.       
  598.       docid = Gopher_to_DocId(DocIdString, &DocLen);
  599.  
  600.       /*** First let's transform the first word into a docid ***/
  601.  
  602.       /*** What we need from net:  DocumentLength, Types: (TEXT!), docid, **/
  603.  
  604.  
  605.  
  606. /*      printf("Headline: %s\n", 
  607.          query_info->DocHeaders[document_number - 1]->Headline);
  608.       /* we must retrieve the document in parts since it might be very long*/
  609.       for(count = 0; 
  610.           count * CHARS_PER_PAGE <
  611.           DocLen;
  612.           count++){
  613.  
  614.            char *type;
  615. /*           if(query_info->DocHeaders[1]->Types == NULL)*/
  616.             type = s_strdup("TEXT");
  617. /*           else
  618.             type = s_strdup(query_info->DocHeaders[1]->Types[0]);*/
  619.            request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
  620.            if(0 ==
  621.           generate_retrieval_apdu(request_message + HEADER_LENGTH,
  622.                       &request_buffer_length, 
  623.                       docid, 
  624.                       CT_byte,
  625.                       count * CHARS_PER_PAGE,
  626.                       MIN((count + 1) * CHARS_PER_PAGE,
  627.                           DocLen),
  628.                       type,
  629.                       database
  630.                       ))
  631.             panic("request too long");
  632.            
  633.            if(0 ==
  634.           interpret_message(request_message, 
  635.                     MAX_MESSAGE_LEN - request_buffer_length, 
  636.                     response_message,
  637.                     MAX_MESSAGE_LEN,
  638.                     connection,
  639.                     false /* true verbose */    
  640.                     )) { /* perhaps the server shut down on us, let's see: */
  641.             if ( connection != NULL) {
  642.              fclose(connection);
  643.              if ((connection=connect_to_server(server_name,atoi(service))) == NULL) 
  644.              {
  645.                   fprintf (stderr, "Error openning connection to %s via service %s.\n",
  646.                        server_name, service);
  647.                   exit(-1);
  648.              }
  649.              if(0 ==
  650.                 interpret_message(request_message, 
  651.                           MAX_MESSAGE_LEN - request_buffer_length, 
  652.                           response_message,
  653.                           MAX_MESSAGE_LEN,
  654.                           connection,
  655.                           false /* true verbose */
  656.                           ))
  657.                   panic("really couldn't deliver message");
  658.             }
  659.             else
  660.              panic("returned message too large");
  661.            }
  662.            
  663.            readSearchResponseAPDU(&retrieval_response, 
  664.                       response_message + HEADER_LENGTH);
  665.            
  666.            /* display_search_response(retrieval_response); the general thing */
  667.            if(NULL == ((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text){
  668.             display_search_response(retrieval_response);
  669.             panic("No text was returned");
  670.            }
  671.            Mydisplay_text_record_completely
  672.             (((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text[0], false);
  673.       }
  674.       freeWAISSearchResponse( retrieval_response->DatabaseDiagnosticRecords); 
  675.       freeSearchResponseAPDU( retrieval_response);
  676.      }
  677.      
  678.      close_connection(connection);
  679.      
  680.      s_free(request_message);
  681.      s_free(response_message);
  682.   
  683.      exit(0);
  684. }
  685.  
  686.