home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / infoserv / gopher / Unix / gopher-gateways / techinfo / gophtech / v1.6 / gophtech.c.Z / gophtech.c
Encoding:
C/C++ Source or Header  |  1993-07-08  |  27.4 KB  |  1,134 lines

  1. /* 
  2.   Gopher --> TechInfo Gateway
  3.   Copyright November 1992, January 1993 by the University of Pennsylvania.
  4.  
  5.   Export of this software from the United States of America is assumed
  6.   to require a specific license from the United States Government.  It
  7.   is the responsibility of any person or organization contemplating
  8.   export to obtain such a license before exporting.  Within that
  9.   constraint, permission to use, distribute, or copy this software is
  10.   granted, provided that this copyright notice appear on all copies.
  11.   This software is provided as is, with no explicit nor implicit
  12.   warranty.
  13.  
  14. */
  15.  
  16. /* HISTORY:
  17. May/June 1993: version 1.6
  18.       Changed search capability so that ALL techinfo search functions
  19.       are available to gophtech gateway users.  (Took out #ifdef WAIS).
  20.  
  21.       Changed SOURCES_MSGFILE to SOURCES_MSG_NODEID and added 
  22.       send_ti_doc() call.
  23.  
  24.       Got rid of MSGFILE completely.
  25.  
  26. Mar 1993: version 1.5
  27.       Added recognition of telnet and tn3270 file types (TI_TELNETSESS).
  28.       Fixed bug which caused NeXT gopher to barf -- 
  29.           Changed "\r\n.\r\n" to ".\r\n" at the end of each element sent.
  30.       Commented out various lines which logged extra information.
  31.       Took out the test "University of Pennsylvania" system
  32.           from techinfo-telnet menu.
  33.  
  34. Jan 1993: version 1.4
  35.       Added ability to point at local Sources document
  36.  
  37. Jan 1993: version 1.3 
  38.       Added ability to point at local Gopher server.
  39.       Added TechInfo Source to Path (informational only --
  40.               the gateway ignores it).
  41.       Added Full Text Searching (do #define WAIS or CFLAGS=-DWAIS)
  42.  
  43. Nov 1992: version 1.2 added GIF.
  44. Feb 1992: Created the gateway.
  45.  
  46. */
  47. #include <stdio.h>
  48. #include <strings.h>
  49. #include <errno.h>
  50. #include <sys/types.h>
  51. #include <sys/socket.h>
  52. #include <netinet/in.h>
  53. #include <netdb.h>
  54. #include "gw.h"
  55.  
  56. #define GWVERSION     "GOPH-TIGW:1.6"
  57. #define TERMBASEDTI   "telnet-techinfo"     /* Telnet session to techinfo */
  58. #define WORLDWIDETI   "worldwide-techinfo"  /* List of all TechInfo servers */
  59. #define SOURCESINFO   "sources "
  60.  
  61. int gophsock = -1;
  62. int gophinsock = -1;
  63.  
  64. char tibuf[200000];
  65. char gophbuf[10000];
  66. char *gatewayhost;
  67. char gatewayport[40];
  68. char remotehost[500];
  69.  
  70. #define CR '\r'
  71. #define LF '\n'
  72. #define EOM             ".\r\n"
  73. #define EOM_LEN         (sizeof(EOM) -1)
  74. #define    terminator(str)    (!strncmp(str, EOM, EOM_LEN))
  75.  
  76. #ifndef RUNTIME_UID
  77. #define RUNTIME_UID 1   /* 1 is usually the DAEMON */
  78. #endif
  79.  
  80. /* TechInfo Protocol */
  81. #define TICMD_GETSERVERS        "m"
  82. #define TICMD_GETMENU           "w:2:%s:1"
  83. #define TICMD_GETDOC            "t:%s:%d:%d"
  84. #define TICMD_VERSION           "v:%s"
  85. #define TICMD_SHOWFLAGS         "O:2"
  86. #define TIOKAY                  "0:"
  87. #define TIMAXFIELDS             40
  88. #define TIDELIM                 ':'
  89. #define TOTCHARSTR              "Total Characters :"
  90. #define TI_GIFIMAGE              0x40
  91. #define TI_TELNETSESS            0x2000
  92.  
  93. #define TICMD_KEYSRCH_NODEID       "b:%s:%s"   /* target:nodeid */
  94. #define TICMD_FULLTEXTSRCH_NODEID  "J:%s:%s"   /* target:nodeid:max#docs */
  95. #define TICMD_TITLESRCH_NODEID     "T:%s:%s"   /* target:nodeid */
  96.  
  97. #define TICMD_DATESRCH_NODEID      "I:%s:%s"   /* nodeid:mm:dd:yy */
  98. #define TICMD_SOURCESRCH_NODEID    "K:%s:%s"   /* nodeid:target */
  99.  
  100.  
  101.  
  102.  
  103. /* Gopher Protocol */
  104. #define GO_DOC        '0'
  105. #define GO_MENU        '1'
  106. #define GO_CSO          '2'
  107. #define GO_ERR          '3'
  108. #define GO_MACHQX       '4'
  109. #define GO_DOSBIN       '5'
  110. #define GO_UUENCODED    '6'
  111. #define GO_SEARCH       '7'
  112. #define GO_TELNET       '8'
  113. #define GO_BINARY       '9'
  114. #define GO_GIF          'g'
  115. #define GO_DUPLSERV     '+'
  116. #define GO_TN3270       'T'
  117.  
  118. #define GO_DELIM        '\t'
  119.  
  120. /* Intermediary protocol */
  121. #define I_DELIM         ' '
  122. #define I_DOC           'D'
  123. #define I_MENU          'M'
  124. #define I_GIFIMAGE      'I'
  125. #define I_SEARCHMENU    'S'
  126. #define I_KEYSRCH       'K'
  127. #define I_TITLESRCH     'T'
  128. #define I_DATESRCH      'N'
  129. #define I_SOURCESRCH    'O'
  130. #define I_FULLTEXTSRCH   'F'
  131.  
  132.  
  133. getreq (char *request, int max, int insock)
  134. {
  135.   int idx;
  136.   char *cp;
  137.  
  138.   readline (request, max, insock, &idx);
  139.   cp = index (request, CR);
  140.   if (cp) *cp = 0;
  141.   cp = index (request, LF);
  142.   if (cp) *cp = 0;
  143. }
  144.  
  145.  
  146. write_doc (int gophsock, int readlast, int len, int TextDoc, char *docbuf, 
  147.        int *totalsent)
  148. {
  149.   int wrote;
  150.   int towrite;
  151.   int pos1, pos2;
  152.  
  153.   /*
  154.     if TextDoc is set, then we need to add CR before each LF,
  155.     since the TI server doesn't send CR LF at the end of every line 
  156.     Also, assuming that if TextDoc contains LF . LF, it should
  157.     be changed to CF LF . . CF LF
  158.     
  159.     known problem -- if the TI server breaks up the chunks it
  160.     sends on a line boundary, and sends a period LF, then
  161.     this code will NOT properly quote that period with another one.
  162.     */
  163.   
  164.   if (readlast)         /* if these were the last chars to be read */
  165.     towrite = len - 4;
  166.   else
  167.     towrite = len;
  168.  
  169.   if (TextDoc) {
  170.     pos1 = 0;
  171.     do {
  172.       for (pos2=pos1; docbuf[pos2] != LF && pos2 < towrite-1; 
  173.        pos2++);
  174.  
  175.       if (docbuf[pos2] == LF) {  /* found an End of Line */
  176.     wrote = write (gophsock, docbuf+pos1, pos2-pos1);
  177.     if (wrote < 0)
  178.       ErrExit("Error writing document to gopher");
  179.     *totalsent = *totalsent + wrote;
  180.     write (gophsock, "\r", 1); (*totalsent)++; 
  181.     write (gophsock, "\n", 1); (*totalsent)++;
  182.     
  183.     if (pos2 + 2 < towrite && 
  184.         docbuf[pos2+1] == '.' && docbuf[pos2+2] == LF) {
  185.       write (gophsock, ".", 1);
  186.       (*totalsent)++;
  187.     }
  188.     pos1 = pos2 + 1;
  189.       }
  190.       
  191.       else { /* No more LF left in the buffer */
  192.     wrote = write (gophsock, docbuf+pos1, towrite-pos1);
  193.     if (wrote < 0)
  194.       ErrExit ("Error sending document to gopher");
  195.     (*totalsent) += wrote;
  196.     pos1 = towrite;
  197.       }
  198.       
  199.     } while (pos1 < towrite);
  200.   }
  201.   
  202.   else {  /* Document is not Text, so just send it as it comes from TI */
  203.     wrote = write (gophsock, docbuf, towrite);
  204.     if (wrote < 0)
  205.       ErrExit ("Error sending nontext document to gopher");
  206.     (*totalsent) += wrote;
  207.   }
  208. }
  209.  
  210.  
  211.  
  212.  
  213. int send_ti_doc (int tisock, int gophsock, char *nodeid, int TextDoc)
  214. {
  215.   char docbuf[12200];
  216. #define DOC_BLKSZ (sizeof(docbuf)-200)
  217.   long startat;
  218.   long totalchars;
  219.   long totalsent = 0;
  220.   char *cp;
  221.   int len;
  222.   int toread;
  223.   int red;
  224.  
  225.   startat = 0;
  226.   do {
  227.     sprintf (tibuf, TICMD_GETDOC, nodeid, startat, DOC_BLKSZ);
  228.     /*    sprintf (docbuf, "ToTechinfo:%s", tibuf);
  229.       logdebug (docbuf); */
  230.     send_msg (tisock, tibuf, strlen(tibuf));
  231.     readline (docbuf, DOC_BLKSZ, tisock, &len);
  232.  
  233.     if (startat == 0) {
  234.       totalchars = atoi (docbuf);
  235. /*      sprintf (tibuf, "Document is %d bytes", totalchars);
  236.       logdebug (tibuf); */
  237.     }
  238.  
  239.     cp = strstr (docbuf, TOTCHARSTR);
  240.     if (cp) {
  241.       cp = cp + sizeof(TOTCHARSTR) - 1;
  242.       toread = atoi(cp);
  243.       read (tisock, docbuf, 1);  /* TI server sends 1 extra character (a LF)
  244.                     between 1st line & the document */
  245.  
  246.       do {
  247.     red = read (tisock, docbuf, toread);
  248.     toread = toread - red;
  249.     write_doc (gophsock, toread < 1, red, TextDoc, docbuf, &totalsent);
  250.       } while (toread > 0);
  251.  
  252.       startat = startat + DOC_BLKSZ;
  253.     }
  254.     else {
  255.       sprintf (tibuf, "Unable to find %s in TI server's response %s\n",
  256.           TOTCHARSTR, docbuf);
  257.       ErrExit (tibuf);
  258.     }
  259.  
  260.   } while (totalchars - startat > 0);
  261.  
  262.   sprintf (docbuf, "Sent %d bytes", totalsent);
  263.   logdebug (docbuf);
  264.  
  265.   if (totalsent < 1) {
  266.     sprintf (docbuf, "%s", "File does not exist!!!!!");
  267.     send_msg (gophsock, docbuf, strlen(docbuf));
  268.   }
  269.   return totalsent;
  270. }
  271.  
  272.  
  273.  
  274.  
  275. ErrExit (char * msg)
  276. {
  277.   char *buf;
  278.  
  279.   write (gophsock, "\r\n.\r\n", 5);
  280.  
  281.   buf = (char *) malloc (strlen(msg)+20);
  282.   sprintf (buf, "FatalError:%s", msg);
  283.   logdebug (buf);
  284.   exit(-100);
  285. }
  286.  
  287.  
  288. int parse_fields (char delim, char *line, char *fields[], int maxfields)
  289. {
  290.   char *cp = line;
  291.   int argcnt = 0;
  292.  
  293.   while (argcnt < maxfields) {
  294.     fields[argcnt] = cp;
  295.     argcnt++;
  296.     while (*cp && *cp != delim)
  297.       cp++;
  298.     if (!*cp)
  299.       break;
  300.     *cp = 0;
  301.     cp++;
  302.   }
  303.   fields[argcnt] = (char *) 0;
  304.   return argcnt;
  305. }
  306.  
  307.  
  308. struct hostent *
  309. gethostbyn_or_ad (host)
  310.      char *host;
  311. {
  312.   u_long ip_addrl;
  313.   struct hostent *h;
  314.  
  315.   if (isdigit (host[0])) {     /* if name begins with a digit, assume IP adr */
  316.     ip_addrl = inet_addr (host);
  317.     h = gethostbyaddr (&ip_addrl, sizeof(u_long), AF_INET);
  318.     return (h);
  319.   }
  320.   else {
  321.     h = gethostbyname (host); 
  322.     return (h);
  323.   }
  324. }
  325.  
  326.  
  327. int getportbyn_or_num (str, port)
  328.      int *port;
  329.      char *str;
  330. {
  331.   struct servent *servent;
  332.  
  333.   if ( isdigit(str[0]) ) {   /* if its a number, convert ascii to int */
  334.     *port = atoi(str);
  335.     *port = htons( (u_short) *port);
  336.   }
  337.   else {        /* if not a number, look up name in Ultrix */
  338.     servent = getservbyname (str, "tcp");
  339.     if (servent == NULL)
  340.       return (-1);
  341.     *port = servent->s_port;
  342.   }
  343.   return (1);
  344. }
  345.  
  346.  
  347.  
  348.  
  349.  
  350. int
  351. inet_connect(char *hostname, char *service, char **errstr)
  352. {
  353. #define ERRORMSG_SIZE 200
  354.   struct hostent *host;
  355.   int toport;
  356.   struct sockaddr_in sin;
  357.   int sock;
  358.   extern char *sys_errlist[];
  359.   extern int sys_nerr;
  360.  
  361.   *errstr = (char *) malloc (ERRORMSG_SIZE);
  362.   (*errstr)[0] = 0;
  363.  
  364.   host = gethostbyn_or_ad (hostname);
  365.  
  366.   if (host == NULL) {
  367.     sprintf (*errstr, "%s: Unknown host", hostname);
  368.     return -1;
  369.   }
  370.  
  371.   else  if (getportbyn_or_num (service, &toport) < 0)  {
  372.     sprintf (*errstr, "%s: Unknown TCP service", service);
  373.     return -1;
  374.   }
  375.  
  376.   else {
  377.     sin.sin_family = host->h_addrtype;
  378.     bcopy(host->h_addr,  &(sin.sin_addr), host->h_length);
  379.     sin.sin_port = toport;
  380.  
  381.     sock = socket (AF_INET, SOCK_STREAM, 0, 0);
  382.     if (sock < 0) {
  383.       strcat (*errstr, "socket: ");
  384.      }
  385.  
  386.     else {
  387.       if (connect (sock, &sin, sizeof (sin)) < 0) {
  388.     strcat (*errstr, hostname);
  389.     strcat (*errstr, ":");
  390.     strcat (*errstr, service);
  391.     strcat (*errstr, ":");
  392.     close (sock);
  393.     sock = -1;
  394.       }
  395.     }
  396.   } 
  397.  
  398.   if (errno >= 0 && errno < sys_nerr)  {
  399.     strcat (*errstr, sys_errlist[errno]);
  400.   }
  401.  
  402.   if (sock >= 0)
  403.     free(*errstr);
  404.   return (sock);
  405. }
  406.  
  407. int 
  408. send_msg(sock,str,len) /* BEWARE! this routine writes into str beyond len! */
  409.      int sock;
  410.      char *str;
  411.      int len;
  412. {
  413.   int wrote;
  414.   char msg[100];
  415.  
  416.   if (sock < 0) return 0;
  417.   if (len < 1) return 0;
  418.  
  419.   str[len] = CR;
  420.   str[len+1] = LF;
  421.   wrote = write(sock, str, len+2);
  422.   if (wrote < 1) {
  423.     sprintf (msg, "Unable to write %d chars to sock %d, errno %d",
  424.          len+2, sock, errno);
  425.     ErrExit (msg);
  426.   }
  427.   else
  428.     return 1;
  429. }
  430.  
  431.  
  432. int readline (char *line, int sz, int sock, int *idx)
  433. {
  434.   int rc;
  435.   char msg[100];
  436.  
  437.   *idx = 0;
  438.   line[*idx] = 0;
  439.   do {
  440.     rc = read(sock, line + *idx, 1);
  441.     if (rc < 0) {
  442.       sprintf (msg, "Error reading line from socket %d, errno %d",
  443.            sock, errno);
  444.       ErrExit (msg);
  445.     }
  446.     (*idx)++;
  447.   } while (*idx < sz-1 && line[*idx-1] != LF);
  448.   line[*idx] = 0;
  449. }
  450.  
  451.  
  452. get_msg(sock, buff, buffsize)   /* read message off socket */
  453.      int             sock;
  454.      char           *buff;
  455.      int             buffsize;
  456. {
  457.   int rc, len;
  458.   char errmsg[100];
  459.  
  460.   len = 0;
  461.   bzero (buff, buffsize);
  462.  
  463.   do {
  464.     rc = read(sock, &buff[len], buffsize - len);
  465.     if (rc < 0 ) {
  466.       sprintf (errmsg, "get_msg: unable to read %d chars from sock %d, errno %d", buffsize-len, sock, errno);
  467.       ErrExit(errmsg);
  468.     }
  469.     len = rc + len;
  470.   } while (rc >= 0 && len <= buffsize && !terminator(&buff[len - EOM_LEN]));
  471.  
  472.   if (terminator (&buff[len - EOM_LEN]))
  473.     len -= EOM_LEN;
  474.  
  475.   buff[len] = '\0';
  476.   return (len);
  477. }
  478.  
  479.  
  480.  
  481.  
  482. logdebug (char *string)
  483. {
  484.   FILE *debugfp;
  485.   long now;
  486.  
  487.   debugfp = fopen (DEBUGLOG, "a");
  488.   if (debugfp != NULL) {
  489.     now = time(0);
  490.     fprintf (debugfp, "%d:%s:%s:%s", getpid(),string, remotehost,ctime(&now));
  491.     fclose(debugfp);
  492.   }
  493. }
  494.  
  495. make_menu_line (char *line, char typ, char *title, char ityp,
  496.         char *tiserver, char *tiport, char *nodeid, char *source,
  497.         char *keys, char *filename)
  498. {
  499.   char *portnum;
  500.   char *loginname;
  501.   char *host;
  502.   char *cp;
  503.   
  504.   if (typ == GO_TELNET || typ == GO_TN3270) {
  505.     /* if it's a telnet/tn3270 type of thing, then
  506.        need to change it to gopher style information */
  507.     
  508.     /* From TI server: keys format: <type><space><port>  E.g.: 8 23  */
  509.     cp = index (keys, ' ');
  510.     if (cp) portnum = cp+1;
  511.     else portnum = "0";         /* DEFAULT TELNET PORT ACCORDING TO GOPHER */
  512.  
  513.     /* From TI server, for Telnet or TN3270 objects:
  514.        filename format: <login><space><host>  E.g.: gopher dccs.upenn.edu */
  515.     cp = rindex (filename, ' ');
  516.     if (cp) {
  517.       host = cp+1;
  518.       *cp = 0;
  519.       loginname = filename;
  520.     }
  521.     else {
  522.       host = filename;
  523.       loginname = "";
  524.     }
  525.  
  526.     sprintf (line, "%c%s%c%s%c%s%c%s",
  527.          typ, title, GO_DELIM, loginname, GO_DELIM,
  528.          host, GO_DELIM, portnum);
  529.   }
  530.   else {
  531.     sprintf (line, "%c%s%c%c%c%s%c%s%c%s%c%s%c%s%c%s",
  532.          typ, title, GO_DELIM,
  533.          ityp, I_DELIM, tiserver, I_DELIM, tiport, I_DELIM, nodeid,
  534.          I_DELIM, source,
  535.          GO_DELIM, gatewayhost, GO_DELIM, gatewayport);
  536.   }
  537. }
  538.  
  539.  
  540. static void send_server_line(char *line)
  541. {
  542.   char *fields[TIMAXFIELDS];
  543.   char *nodeid, *server, *port, *title;
  544.   char *Title;
  545.   
  546.   parse_fields (TIDELIM, line, fields, TIMAXFIELDS);
  547.   nodeid = fields[0];
  548.   port = fields[1];
  549.   title = fields[5];
  550.   server = fields[6];
  551.  
  552.   Title = (char *) malloc (strlen(title) +  strlen (" TechInfo") + 1);
  553.   strcpy (Title, title);
  554.   strcat (Title, " TechInfo");
  555.  
  556.   make_menu_line (gophbuf, GO_MENU, Title, I_MENU, server, port, nodeid, "",
  557.           "", "");
  558.   send_msg (gophsock, gophbuf, strlen(gophbuf));
  559. }
  560.  
  561. send_ti_server_list()
  562. {
  563.   char *errstr;
  564.   int length;
  565.   int toread, numlines;
  566.   int tisock;
  567.  
  568.   tisock = inet_connect (TISERVERS_HOST, TISERVERS_PORT, &errstr);
  569.   if (tisock < 0) {
  570.     sprintf(gophbuf, "Couldn't get list of TechInfo servers. %s (port %s)",
  571.         errstr, TISERVERS_PORT);
  572.     ErrExit (gophbuf);
  573.   }
  574.   else {
  575.     init_connect (tisock);
  576.  
  577.     sprintf (tibuf, "%s", TICMD_GETSERVERS);
  578.     /*    sprintf (gophbuf, "ToTechinfo:%s", tibuf);
  579.       logdebug (gophbuf); */
  580.  
  581.     send_msg (tisock, tibuf, strlen(tibuf));
  582.     readline (tibuf, sizeof(tibuf), tisock, &length);
  583.  
  584.     toread = atoi (tibuf);
  585.     numlines = 0;
  586.   
  587.     while (numlines < toread) {
  588.       readline (tibuf, sizeof(tibuf), tisock, &length);
  589.       numlines++;
  590.       send_server_line(tibuf);
  591.     }
  592.     sprintf (gophbuf, "Sent %d server lines", numlines);
  593.     logdebug (gophbuf);
  594.   }
  595. }
  596.  
  597. /*
  598.   Disgusting hack:
  599.   The TI nodetype is NOT entirely in one place in the nodes' info string.
  600.   Telnet session type files may actually be TN3270 things.
  601.   Look in keys to get the scoop.
  602.   */
  603.  
  604. whatis_type (char *flags, char *filename, char *intermedtype, char *gophertype,
  605.          char *keys)
  606. {
  607.   int iflags;
  608.  
  609.   iflags = atoi(flags);
  610.  
  611.   if (iflags & TI_GIFIMAGE) {
  612.     *gophertype = GO_GIF;
  613.     *intermedtype = I_GIFIMAGE;
  614.   }
  615.   else if (iflags & TI_TELNETSESS) {
  616.     /* ASSUMPTION: TI Server uses the Gopher characters to indicate
  617.        whether it's a Telnet or a TN3270 type of file */
  618.     *gophertype = *keys;
  619.     *intermedtype = *gophertype;
  620.   }
  621.  
  622.   else if (strlen(filename) > 0) {
  623.     *gophertype = GO_DOC;
  624.     *intermedtype = I_DOC;
  625.   }
  626.   else {
  627.     *intermedtype = I_MENU;
  628.     *gophertype = GO_MENU;
  629.   }
  630.  
  631. }
  632.  
  633.  
  634.  
  635. static int send_menu_item (char *line, char *tiserver, char *tiport, int minlevel)
  636. {
  637.   char *fields[TIMAXFIELDS];
  638.   char selector[500];
  639.   char *title, *filename, *nodeid, *level, *flags, *source, *keys;
  640.   char ityp, gtyp;
  641.  
  642.   parse_fields (TIDELIM, line, fields, TIMAXFIELDS);
  643.   level = fields[0];
  644.   nodeid = fields[1];
  645.   flags = fields[2];
  646.   keys = fields[4];
  647.   title = fields[5];
  648.   filename = fields[8];
  649.   source = fields[6];
  650.   
  651.   if (atoi(level) < minlevel)
  652.     return 0;
  653.   
  654.   whatis_type (flags, filename, &ityp, >yp, keys);
  655.   make_menu_line (gophbuf, gtyp, title, ityp, tiserver, tiport, nodeid,source,
  656.           keys, filename);
  657.   send_msg (gophsock, gophbuf, strlen(gophbuf));
  658.   return 1;
  659. }
  660.  
  661. send_searchmenu_item (char *title, char *tiserver, char *tiport, 
  662.               char *nodeid)
  663. {
  664.   sprintf (gophbuf, "%cSearch %s%c%c%c%s%c%s%c%s%c%s%c%s",
  665.        GO_MENU, title, GO_DELIM,
  666.        I_SEARCHMENU, I_DELIM, tiserver, I_DELIM, tiport, I_DELIM, nodeid,
  667.        GO_DELIM, gatewayhost, GO_DELIM, gatewayport);
  668.   send_msg (gophsock,gophbuf, strlen(gophbuf));
  669. }
  670.  
  671. static int
  672. send_searches (char *tiserver, char *tiport, char *nodeid)
  673. {
  674.   char *thename;
  675.  
  676.   if (strcasecmp(tiserver, LOCALTI_SERVER) == 0) 
  677.     thename = LOCALTI_NAME;
  678.   else
  679.     thename = "TechInfo";
  680.  
  681.   if (strcmp(nodeid, "0") != 0 && strcmp(nodeid, "") != 0) {
  682.     send_searchmenu_item ("current menu and below", tiserver,tiport,nodeid);
  683.     send_searchmenu_item (thename, tiserver,tiport, "");
  684.     return 2;
  685.   }
  686.   else {
  687.     send_searchmenu_item (thename, tiserver,tiport, "");
  688.     return 1;
  689.   }
  690. }
  691.  
  692.  
  693. static void
  694. send_search_item (char itype, char *tiserver, char *tiport, char *nodeid)
  695. {
  696.   char title [100];
  697.  
  698.   switch  (itype)
  699.     {
  700.     case I_KEYSRCH: strcpy (title, "Keyword Search"); break;
  701.     case I_TITLESRCH: strcpy (title, "Title Search"); break;
  702.     case I_DATESRCH: strcpy (title, "What's New Search (specify date as mm/dd/yy)"); break;
  703.     case I_FULLTEXTSRCH: strcpy (title, "Full Text Search"); break;
  704.     case I_SOURCESRCH: strcpy (title, "Source (owner) Search"); break;
  705.       default : return;
  706.     }
  707.  
  708.   sprintf (gophbuf, "%c%s%c%c%c%s%c%s%c%s%c%s%c%s",
  709.        GO_SEARCH, title, GO_DELIM,
  710.        itype, I_DELIM, tiserver,
  711.        I_DELIM, tiport, I_DELIM, nodeid,
  712.        GO_DELIM, gatewayhost, GO_DELIM, gatewayport);
  713.   send_msg (gophsock, gophbuf, strlen(gophbuf));
  714. }
  715.  
  716.  
  717.  
  718. static void
  719. send_ti_nodelist (int tisock, char *tiserver, char *tiport, int *sent, int minlevel)
  720. {
  721.   int toread, numlines;
  722.   int length;
  723.   char *cp, *cp2;
  724.  
  725.   *sent = 0;
  726.   readline (tibuf, sizeof(tibuf), tisock, &length);
  727.   cp = index (tibuf, TIDELIM);
  728.   if (cp) {
  729.     cp++;
  730.     for (cp2 = cp; *cp2 && *cp2 != '\n'; cp2++);
  731.     *cp2 = 0;
  732.     sprintf (gophbuf, "%s", cp); logdebug (gophbuf);
  733.     if (cp2-cp > 0) 
  734.       return;
  735.   }
  736.   toread = atoi (tibuf);
  737.   numlines = 0;
  738.   while (numlines < toread) {
  739.     readline (tibuf, sizeof(tibuf), tisock, &length);
  740.     numlines++;
  741.     *sent += send_menu_item (tibuf, tiserver, tiport, minlevel);
  742.   }
  743.   readline (tibuf, sizeof(tibuf), tisock, &length);
  744. }
  745.  
  746.  
  747. static void send_sources_info (char *srvr)
  748. {
  749.   int tisock;
  750.   char *errstr;
  751.  
  752.   if (*LOCAL_SOURCES_NODEID && *LOCALTI_SERVER &&
  753.       strcmp (LOCALTI_SERVER, srvr) == 0) {
  754.  
  755.     /* connect to localti server, retrieve the document associated
  756.        with local sources nodeid, translate it, send it to gopher client */
  757.  
  758.     tisock = inet_connect (LOCALTI_SERVER, LOCALTI_PORT, &errstr);
  759.     if (tisock < 0) {
  760.       sprintf(gophbuf, "Couldn't connect to Techinfo:%s (port %s)",
  761.         errstr, LOCALTI_PORT);
  762.       ErrExit (gophbuf);
  763.     }
  764.     else {
  765.       init_connect (tisock);
  766.       if (*SOURCES_MSG_NODEID)
  767.     send_ti_doc (tisock, gophsock, SOURCES_MSG_NODEID, 1);
  768.  
  769.       send_ti_doc (tisock, gophsock, LOCAL_SOURCES_NODEID, 1);
  770.     }
  771.   }
  772. }
  773.  
  774.  
  775.  
  776.  
  777. int send_sources_item (char *tiserver)
  778. {
  779.   /* Only offer this item if
  780.      the server is the local one and there's a LOCAL SOURCES NODEID 
  781.      */
  782.  
  783.   if ((strcasecmp(tiserver, LOCALTI_SERVER) == 0) && *LOCAL_SOURCES_NODEID) {
  784.     sprintf (gophbuf, "%cSources (Providers) of Information\t%s%s\t%s\t%s",
  785.          GO_DOC, SOURCESINFO, tiserver, gatewayhost, gatewayport);
  786.     send_msg (gophsock, gophbuf, strlen(gophbuf));
  787.     return 1;
  788.   }
  789.   else
  790.     return 0;
  791. }
  792.  
  793.  
  794. init_connect (int tisock)  /* call this after successful inet_estab */
  795. {
  796.   get_msg (tisock, tibuf, sizeof(tibuf)); /* get the banner */
  797.   send_version(tisock);
  798.   turnon_tiflags (tisock);
  799. }
  800.  
  801. static void
  802. create_tisearchcmd (char srchtyp, char *target, char *nodeid, char *tibuf)
  803. {
  804.   char *nodeidtouse;
  805.   
  806.   if (strlen(nodeid) > 0)
  807.     nodeidtouse = nodeid;
  808.   else
  809.     nodeidtouse = "0"; /* if there was no nodeid given, then use 0 because
  810.               that is SUPPOSED to be the main menu */
  811.   
  812.   switch (srchtyp) {
  813.   case I_KEYSRCH:
  814.     sprintf (tibuf, TICMD_KEYSRCH_NODEID, target, nodeidtouse);
  815.     break;
  816.   case I_FULLTEXTSRCH:
  817.     sprintf (tibuf, TICMD_FULLTEXTSRCH_NODEID, target, nodeidtouse);
  818.     break;
  819.   case I_TITLESRCH:
  820.     sprintf (tibuf, TICMD_TITLESRCH_NODEID, target, nodeidtouse);
  821.     break;
  822.  
  823.     /* TechInfo protocol:
  824.        Change the order of target & nodeid for the SOURCE & DATE search! */
  825.  
  826.   case I_DATESRCH:
  827.     sprintf (tibuf, TICMD_DATESRCH_NODEID, nodeidtouse, target);
  828.     break;
  829.  
  830.   case I_SOURCESRCH:
  831.     sprintf (tibuf, TICMD_SOURCESRCH_NODEID, nodeidtouse, target);
  832.     break;
  833.   }
  834. }
  835.  
  836.  
  837.  
  838. static void do_ti_trans(char *request)
  839. {
  840.   char *fields[4];
  841.   int tisock;
  842.   char *tiserver, *tiport, *typ, *nodeid;
  843.   char *errstr;
  844.   char *target = NULL;
  845.   char *cp;
  846.   int numitems, numslash;
  847.   
  848.   switch (*request) {
  849.   case I_KEYSRCH:
  850.   case I_FULLTEXTSRCH:
  851.   case I_TITLESRCH:
  852.   case I_DATESRCH:
  853.   case I_SOURCESRCH:
  854.     /* expect selector-string TAB search-string */
  855.     target = index (request, GO_DELIM);
  856.     if (!target) {
  857.       sprintf (gophbuf, "Didn't understand search request %s", request);
  858.       ErrExit (gophbuf);
  859.       return;
  860.     }
  861.     /* Replace the delimiter with end-of-string marker */
  862.     *target = '\0';
  863.     target++;
  864.  
  865.     if (*request == I_DATESRCH) {  /* target should be mm/dd/yy */
  866.       for (numslash=0, cp = target; *cp; cp++) {
  867.     if (*cp == '/') {
  868.       numslash++;
  869.       *cp = ':';
  870.     }
  871.       }
  872.       if (numslash != 2) {
  873.     sprintf (gophbuf, "Didn't understand date %s, expecting mm/dd/yy",
  874.         target);
  875.     ErrExit (gophbuf);
  876.     return;
  877.       }
  878.     }
  879.  
  880.     /* fall through to parse_fields intentionally */
  881.  
  882.   case I_DOC:
  883.   case I_MENU:
  884.   case I_SEARCHMENU:
  885.   case I_GIFIMAGE:
  886.     
  887.     parse_fields (I_DELIM, request, fields, 4);
  888.     typ = fields[0];
  889.     tiserver = fields[1];
  890.     tiport = fields[2];
  891.     nodeid = fields[3];
  892.     break;
  893.     
  894.   default:
  895.     sprintf (gophbuf, "Didn't understand file type %c", *request);
  896.     ErrExit (gophbuf);
  897.     return;
  898.   }
  899.  
  900. /* okay, we've parsed the Intermed. token... */
  901. /*  fprintf (stderr, "serv=%s, port=%s, nodeid=%s, target=%s.\n",
  902.       tiserver, tiport, nodeid, target);  */
  903.  
  904.   if (*typ == I_SEARCHMENU) {
  905.     send_search_item (I_KEYSRCH, tiserver, tiport, nodeid);
  906.     send_search_item (I_DATESRCH, tiserver, tiport, nodeid);
  907.     send_search_item (I_TITLESRCH, tiserver, tiport, nodeid);
  908.     send_search_item (I_FULLTEXTSRCH, tiserver, tiport, nodeid);
  909.     send_search_item (I_SOURCESRCH, tiserver, tiport, nodeid);
  910.   }
  911.   
  912.   else {
  913.     tisock = inet_connect (tiserver, tiport, &errstr);
  914.     if (tisock < 0) {
  915.       sprintf(gophbuf, "Couldn't connect to Techinfo:%s (port %s)",
  916.           errstr, tiport);
  917.       ErrExit (gophbuf);
  918.     }
  919.     else {
  920.       init_connect (tisock);
  921.       
  922.       switch (*typ) {
  923.       case I_KEYSRCH:
  924.       case I_FULLTEXTSRCH:
  925.       case I_DATESRCH:
  926.       case I_SOURCESRCH:
  927.       case I_TITLESRCH:
  928.     create_tisearchcmd (*typ, target, nodeid, tibuf);
  929.     sprintf (gophbuf, "ToTechinfo:%s", tibuf); logdebug (gophbuf);
  930.     
  931.     send_msg (tisock, tibuf, strlen(tibuf));
  932.     send_ti_nodelist(tisock, tiserver, tiport, &numitems, 0);
  933.     sprintf (tibuf, "Sent %d items", numitems);
  934.     logdebug (tibuf);
  935.     break;
  936.     
  937.       case I_DOC:
  938.       case I_GIFIMAGE:
  939.     send_ti_doc (tisock, gophsock, nodeid, *typ != I_GIFIMAGE);
  940.     break;
  941.     
  942.       case I_MENU:
  943.     sprintf (tibuf, TICMD_GETMENU, nodeid);
  944.     /*      sprintf (gophbuf, "ToTechinfo:%s", tibuf); logdebug (gophbuf); */
  945.     send_msg (tisock, tibuf, strlen(tibuf));
  946.     
  947.     send_ti_nodelist (tisock, tiserver, tiport, &numitems, 1);
  948.     numitems += send_searches (tiserver, tiport, nodeid);
  949.     
  950.     if (send_sources_item (tiserver))
  951.       numitems = numitems + 1;
  952.     
  953.     sprintf (tibuf, "Sent %d items", numitems);
  954.     logdebug (tibuf);
  955.     break;
  956.       }
  957.     }
  958.   }
  959. }
  960.  
  961.  
  962. terminalbased_ti()
  963. {
  964.   sprintf (gophbuf, "%cMassachusetts Institute of Technology%c%ctechinfo.mit.edu%c0",
  965.        GO_TELNET, GO_DELIM, GO_DELIM,GO_DELIM);
  966.   send_msg (gophsock, gophbuf, strlen(gophbuf));
  967.  
  968.   sprintf (gophbuf, "%cUniversity of Pennsylvania%c%cpenninfo.upenn.edu%c0",
  969.        GO_TELNET, GO_DELIM, GO_DELIM,GO_DELIM);
  970.   send_msg (gophsock, gophbuf, strlen(gophbuf));
  971.  
  972.   sprintf (gophbuf, "%cMississippi State%cMSUINFO%cmsuinfo.msstate.edu%c0",
  973.        GO_TELNET, GO_DELIM, GO_DELIM,GO_DELIM);
  974.   send_msg (gophsock, gophbuf, strlen(gophbuf));
  975.  
  976. }
  977.  
  978.  
  979.  
  980.  
  981. send_message_file (char *filename)
  982. {
  983.   FILE *fp;
  984.   char line[100], *cp;
  985.  
  986.   fp = fopen (filename, "r");
  987.   if (fp == NULL) {
  988.     sprintf (gophbuf, "Unable to read msg file %s", filename);
  989.     ErrExit (gophbuf);
  990.   }
  991.  
  992.   do {
  993.     if (fgets (line,sizeof(line)-1,fp) == NULL)
  994.       break;
  995.     else {
  996.       cp = index (line, '\n');
  997.       if (cp) {
  998.     write (gophsock, line, cp-line);
  999.     write (gophsock, "\r\n", 2);
  1000.       }
  1001.       else
  1002.     write (gophsock, line, strlen(line));
  1003.     }
  1004.   } while (1);
  1005. }
  1006.  
  1007.  
  1008. send_version(int tisock)
  1009. {
  1010.   sprintf (tibuf, TICMD_VERSION, GWVERSION);
  1011.   send_msg (tisock, tibuf, strlen(tibuf));
  1012.   get_msg(tisock, gophbuf, sizeof(gophbuf));
  1013. }
  1014.  
  1015.  
  1016. turnon_tiflags (int tisock)
  1017. {
  1018.   sprintf (tibuf, TICMD_SHOWFLAGS);
  1019.   send_msg (tisock, tibuf, strlen(tibuf));
  1020.   get_msg (tisock, gophbuf, sizeof(gophbuf));
  1021. }
  1022.  
  1023. set_remote_hostname ()
  1024. {
  1025.   struct sockaddr_in sname;
  1026.   struct hostent *host;
  1027.   int namelen;
  1028.  
  1029.   namelen = sizeof(sname);
  1030.  
  1031.   if (getpeername (gophinsock, &sname, &namelen)) {
  1032.     if (errno == ENOTSOCK) 
  1033.       sprintf (remotehost, "STDIN");
  1034.     else
  1035.       sprintf (remotehost, "getpeername-errno-%d", errno);
  1036.   }
  1037.  
  1038.   else {
  1039.     host = gethostbyaddr(&sname.sin_addr, sizeof(sname.sin_addr), AF_INET);
  1040.     if (!host)
  1041.       sprintf (remotehost, "gethostbyaddr-errno-%d", errno);
  1042.     else
  1043.       sprintf (remotehost, "%s", host->h_name);
  1044.   }
  1045. }
  1046.  
  1047. main (int argc, char *argv[])
  1048. {
  1049.   char request[1000];
  1050.   char *ptr;
  1051.   int port;
  1052.   
  1053.   setreuid (RUNTIME_UID, RUNTIME_UID);
  1054.   if (getuid() == 0 || geteuid() == 0) {
  1055.     fprintf (stderr, "\r\n.\r\n");
  1056.     /* should send a message to syslog daemon */
  1057.     exit (-1);
  1058.   }
  1059.   
  1060.   gophsock =  fileno(stdout);
  1061.   gophinsock = fileno(stdin);
  1062.   set_remote_hostname ();
  1063.   
  1064. /*  logdebug ("Start"); */
  1065.   
  1066.   if (argc < 3) {
  1067.     sprintf (gophbuf, "Usage: %s <hostname> <port>", argv[0]);
  1068.     ErrExit(gophbuf);
  1069.   }
  1070.   gatewayhost = argv[1];
  1071.   if (getportbyn_or_num (argv[2], &port) < 0) {
  1072.     sprintf (gophbuf, "Unknown service port argv2: %s", argv[2]);
  1073.     ErrExit (gophbuf);
  1074.   }
  1075.   port = ntohs(port);
  1076.   sprintf (gatewayport, "%d", port);
  1077.   
  1078.   getreq (request, sizeof(request), gophinsock);
  1079.   sprintf (gophbuf, "Request:%s", request);
  1080.   logdebug (gophbuf);
  1081.   
  1082.   for (ptr = request; *ptr && isspace(*ptr) ; ptr++);
  1083.   if (*ptr == 0) {                 /* is it a blank line? */
  1084.  
  1085.     if (strlen(LOCALTI_SERVER) > 0) {
  1086.       sprintf (request, "%c%c%s%c%s%c%s",
  1087.            I_MENU, I_DELIM,  LOCALTI_SERVER, I_DELIM, LOCALTI_PORT, I_DELIM, 
  1088.            LOCALTI_MAINMENU);
  1089.       do_ti_trans(request);
  1090.     }
  1091.  
  1092.     sprintf (gophbuf, "%cWorld Wide TechInfo%c%s%c%s%c%s",
  1093.          GO_MENU, GO_DELIM, WORLDWIDETI, GO_DELIM,
  1094.          gatewayhost, GO_DELIM, gatewayport);
  1095.     send_msg (gophsock, gophbuf, strlen(gophbuf));
  1096.     
  1097.     if (strlen(LOCALGOPHTITLE) > 0) {
  1098.       sprintf (gophbuf, "%c%s%c%s%c%s%c%s",
  1099.            GO_MENU, LOCALGOPHTITLE, GO_DELIM, LOCALGOPHERPATH, GO_DELIM,
  1100.            LOCALGOPHERSERVER, GO_DELIM, LOCALGOPHERPORT);
  1101.       send_msg (gophsock, gophbuf, strlen(gophbuf));
  1102.     }
  1103.     
  1104.     sprintf (gophbuf, "%cWorld Wide Gopher%c1/Other Gopher and Information Servers%cgopher.tc.umn.edu%c70",
  1105.          GO_MENU, GO_DELIM, GO_DELIM,GO_DELIM);
  1106.     send_msg (gophsock, gophbuf, strlen(gophbuf));
  1107.   }
  1108.   
  1109.   else if (!strcmp(request, WORLDWIDETI)) {
  1110.     send_ti_server_list();
  1111.     sprintf (gophbuf, "%cTerminal-based TechInfo services%c%s%c%s%c%s",
  1112.          GO_MENU, GO_DELIM, TERMBASEDTI, GO_DELIM,
  1113.          gatewayhost, GO_DELIM, gatewayport);
  1114.     send_msg (gophsock, gophbuf, strlen(gophbuf));
  1115.   }
  1116.  
  1117.  
  1118.   else if (!strncmp(request, SOURCESINFO, strlen(SOURCESINFO)))
  1119.     send_sources_info(request + strlen(SOURCESINFO));
  1120.   
  1121.   else if (!strcmp(request, TERMBASEDTI))
  1122.     terminalbased_ti();
  1123.   
  1124.   else                            /* should be a techinfo menu request */
  1125.     do_ti_trans(request);
  1126.   
  1127.   /* this is the normal exit */
  1128. /*  write (gophsock, "\r\n.\r\n", 5); */
  1129.   write (gophsock, ".\r\n", 3);
  1130. /*  logdebug ("End"); */
  1131.   exit (0);
  1132. }
  1133.  
  1134.