/********************************************************************
 * $Author: lindner $
 * $Revision: 1.2 $
 * $Date: 1992/12/14 21:36:05 $
 * $Source: /home/mudhoney/GopherSrc/release1.11/gopherd/RCS/index.c,v $
 * $Status: $
 *
 * Paul Lindner, University of Minnesota CIS.
 *
 * Copyright 1991, 1992 by the Regents of the University of Minnesota
 * see the file "Copyright" in the distribution for conditions of use.
 *********************************************************************
 * MODULE: index.c
 * Routines to deal with various types of indexes.
 *********************************************************************
 * Revision History:
 * $Log: index.c,v $
 * Revision 1.2  1992/12/14  21:36:05  lindner
 * Fixed problem in ShellIndexQuery, cp wasn't being incremented.
 * Also added special character elimination from GrepIndexQuery
 *
 * Revision 1.1  1992/12/10  23:13:27  lindner
 * gopher 1.1 release
 *
 *
 *********************************************************************/

#include "gopherd.h"
#include <stdio.h>

#define WAISTYPE 1
#define NEXTTYPE 2
#define SHLLTYPE 3
#define GREPTYPE 4


void 
Do_IndexTrans(sockfd, inputline)
  int sockfd;
  char *inputline;
{
     char *IndexDirectory = NULL;
     char *SearchString = NULL;
     char *cp = NULL;
     char *dbName = NULL;
     char INDEXHost[256], INDEXPath[256];  /** Hard coded limits, ugh! **/
     int  INDEXPort=0;
     char logline[256];
     int  Index_type=0;

     /** First siphon off the directory pathname **/
     IndexDirectory = inputline;

     if (UsingHTML)
	  cp = strchr(inputline, '?');
     else
	  cp = strchr(inputline, '\t');
     
     if (cp == NULL) {
	  if (UsingHTML) {
	       Index_type = Find_index_type(IndexDirectory);

	       if (Index_type == -1) {
		    writestring(sockfd, "Server error....<P>\r\n");
		    writestring(sockfd, inputline);
		    writestring(sockfd, " is not a valid index<P>\r\n");
		    return;
	       }
	       writestring(sockfd, "<ISINDEX>\r\n");
	       writestring(sockfd, "This is a gopher index of ");
	       writestring(sockfd, inputline+1);
	       writestring(sockfd, ". <P>This is a ");
	       switch (Index_type) {
	       case WAISTYPE:
		    writestring(sockfd, "WAIS index\r\n");
		    break;
	       case NEXTTYPE:
		    writestring(sockfd, "NeXT Digital Librarian index\r\n");
		    break;
	       case GREPTYPE:
		    writestring(sockfd, "Brute force search of items in this directory\r\n");
		    break;
	       case SHLLTYPE:
		    writestring(sockfd, "strange gateway search\r\n");
		    break;
	       } 
	       writestring(sockfd, "<P>\r\n");
	       return;

	  } else {
	       /** Give up it won't work..... **/
	       writestring(sockfd, ".\r\n");
	       return;
	  } 
     }
     else
	  *cp = '\0';

     
     /** And siphon off the search string **/

     SearchString = cp +1;

     /** Just in case, get rid of anything following a tab **/

     cp = strchr(SearchString, '\t');
     if (cp != NULL)
	  *cp = '\0';


     Index_type = Find_index_type(IndexDirectory);

     if (DEBUG) 
	  printf("Index type is %d\n", Index_type);

     if (Index_type < 0) {
	  /**** Error condition, unknown index type... ****/
	  Abortoutput(sockfd, "Unknown index type");
	  return;
     }
	  
     if (Index_type == WAISTYPE) {
	  /*** The selector string has both the directory and the dbname... ***/
	  cp = strrchr(IndexDirectory, '/');
	  
	  if (cp == NULL)
	       dbName = "index";
	  else {
	       dbName= cp+1;
	       *cp='\0';
	  }
     }

     if (Read_hostdata(IndexDirectory, INDEXHost, &INDEXPort, INDEXPath, dbName) <0) {
	  LOGGopher(sockfd, "Malformed hostdata file\n");
	  writestring(sockfd, "0Error on server, malformed hostdata\t\t\t1\r\n.\r\n");
	  return;
     }
     
     /* Doctor up the indexdirectory path if we're not running chroot()
      * we use fixfile to keep things secure....
      */

     if (!dochroot) {
	  IndexDirectory = fixfile(IndexDirectory);
	  
	  cp = (char *) malloc(250);
	  strcpy(cp, Data_Dir);
	  strcat(cp, "/");
	  strcat(cp, IndexDirectory);

	  IndexDirectory = cp;
     }


     /** And call the appropriate query function **/

     switch (Index_type) {

     case NEXTTYPE:
	  
	  NeXTIndexQuery(sockfd, SearchString, IndexDirectory, NULL, 
			 INDEXHost, INDEXPort, INDEXPath);
	  break;

     case WAISTYPE:
	  WaisIndexQuery(sockfd, IndexDirectory, SearchString, dbName, 
			 INDEXHost, INDEXPort, INDEXPath);
	  break;

     case GREPTYPE:
	  GrepIndexQuery(sockfd, IndexDirectory, SearchString, 
			 INDEXHost, INDEXPort, INDEXPath);
	  break;
	  
     case SHLLTYPE:
	  ShellIndexQuery(sockfd, IndexDirectory, SearchString);
	  break;
     }
     
     /** Log it here so we get the query in the logfile **/

     if (dbName)
	  sprintf(logline, "search %s/%s for %s", IndexDirectory,
		  dbName, SearchString);
     else
	  sprintf(logline, "search %s for %s", IndexDirectory, SearchString);

     LOGGopher(sockfd, logline);
}



/*
 * Try to figure out what each type of object is
 *
 * index types are 
 *   Error       == -1
 *   WAIS        == 1
 *   NeXT        == 2
 *   ShellScript == 3
 *   Grep        == 4
 */

int
Find_index_type(gopherpath)
  char *gopherpath;
{
     char Teststr[512];
     FILE *Testfile;

     strcpy(Teststr, gopherpath);
     strcat(Teststr, "/.index/index.ixif");

     Testfile = rfopen(Teststr, "r");
     if (Testfile != NULL) {
	  /*** Next Index ***/
	  fclose(Testfile);
	  return(NEXTTYPE);
     }


     strcpy(Teststr, gopherpath);
     strcat(Teststr, ".inv");

     Testfile = rfopen(Teststr, "r");
     if (Testfile != NULL) {
	  /*** WAIS Index ***/
	  fclose(Testfile);
	  return(WAISTYPE);
     }


     strcpy(Teststr, gopherpath);

     if (isadir(Teststr) == 1) {
	  return(GREPTYPE);
     }
     
     Testfile = rfopen(Teststr, "r");
     if (Testfile != NULL) {
	  /** Shell script? **/
	  if (getc(Testfile) == '#')
	       if (getc(Testfile) == '!') {
		    fclose(Testfile);
		    return(SHLLTYPE);
	       }
     }

     return(-1);
}
     

/*
 * Read in the data from a hostdata file...
 * 
 * Try "<dbname>.hostdata" first, fall back to "hostdata" otherwise
 */

int
Read_hostdata(IndexDirectory, INDEXHost, INDEXPort, INDEXPath, dbName)
  char *IndexDirectory;
  char *INDEXHost, *INDEXPath;
  int  *INDEXPort;
  char *dbName;
{
     FILE *Hostfile;
     char hostdataName[256];

     /** Read in the proper hostdata file.... **/

     rchdir(IndexDirectory);  /** Change into the index directory **/

     sprintf(hostdataName, "%s.hostdata", dbName);  /* try idx.hostdata */
     if ((Hostfile = ufopen(hostdataName, "r")) == NULL)
	  Hostfile = ufopen("hostdata", "r");

     if (Hostfile == NULL) {
	  /*** Use the current host/port as the default ***/
	  fclose(Hostfile);
	  strcpy(INDEXHost, Zehostname);
	  *INDEXPort = GopherPort;
	  strcpy(INDEXPath, Data_Dir);
     } 
     else {
	  char tempbuf[255];

	  if (fgets(INDEXHost, 64, Hostfile) == NULL)
	       return(-1);
	  
	  ZapCRLF(INDEXHost);
	  
	  if (fgets(tempbuf, 255, Hostfile) == NULL)
	       return(-1);
	  
	  if ((*INDEXPort=atoi(tempbuf))==0)
	       return(-1);
	  
	  if (fgets(INDEXPath, 256, Hostfile) == NULL)
	       return(-1);
	  
	  ZapCRLF(INDEXPath);
	  fclose(Hostfile);
     }
     
     return(0);
}


/*
 * This is a searching function that runs grep across files
 * in a single directory...
 */

void
GrepIndexQuery(sockfd, Indexdir, Searchstr, INDEXHost, INDEXPort, INDEXPath)
  int sockfd;
  char *Indexdir;
  char *Searchstr;
  char *INDEXHost;
  int INDEXPort;
  char *INDEXPath;
{
     FILE *moocow;
     char command[512];
     char inputline[512];
     char *cp;
     GopherObj *gs;
     GopherDirObj *gd;

     gs = GSnew();
     gd = GDnew(32);

     cp = Searchstr;
     while (*cp != '\0') {
	  if (*cp == ';' ||*cp == '"' || *cp == '`')
	       *cp = '.';
	  cp++;
     }

     sprintf(command, "egrep \"%s\" \"%s\"/*", Searchstr, Indexdir);
     if (DEBUG) 
	  printf("Grep command is %s\n", command);

     moocow = Gpopen(sockfd, command, "r");
     
     if (moocow == NULL) {
	  writestring(sockfd, ".\r\n");
	  LOGGopher(sockfd, "Couldn't open grep command");
	  return;
     }

     while (fgets(inputline, 512, moocow)) {
	  ZapCRLF(inputline);
	  GSsetType(gs, '0');

	  cp = strstr(inputline, INDEXPath) + strlen(INDEXPath);
	  GSsetTitle(gs, cp);

	  cp = strchr(inputline, ':');
	  *cp='\0';
	  cp =strstr(inputline, INDEXPath) + strlen(INDEXPath);
	  GSsetPath(gs, cp);
	  GSsetHost(gs, INDEXHost);
	  GSsetPort(gs, INDEXPort);

	  GDaddGS(gd, gs);
     }
     if (UsingHTML)
	  GDtoNetHTML(gd, sockfd);
     else {
	  GDtoNet(gd, sockfd);
	  writestring(sockfd, ".\r\n");
     }

     pclose(moocow);
}



/*
 * This starts up a shell script that's defined to be an index gateway
 * 
 * The shell script should write out standard gopher directory protocol.
 */

void
ShellIndexQuery(sockfd, Script, Searchstring)
  int sockfd;
  char *Script;
  char *Searchstring;
{
     GopherDirObj *gd;
     char Command[512];
     FILE  *Searchprocess;
     char *cp;

     gd = GDnew(32);

     sprintf(Command, "\"%s\" \"%s\"", Script, Searchstring);

     Searchprocess = Gpopen(sockfd, Command, "r");

     if (Searchprocess == NULL) {
	  writestring(sockfd, ".\r\n");
	  return;
     }

     GDfromNet(gd, fileno(Searchprocess), NULL);
     if (UsingHTML)
	  GDtoNetHTML(gd, sockfd);
     else {
	  GDtoNet(gd, sockfd);
	  writestring(sockfd, ".\r\n");
     }

     pclose(Searchprocess);
     GDdestroy(gd);
}

	  
#ifndef WAISSEARCH

void
WaisIndexQuery(sockfd, index_directory, SearchWords, new_db_name, INDEXHost, INDEXPort, INDEXPath)
  int sockfd;
  char *index_directory;
  char *SearchWords;
  char *new_db_name;
  char *INDEXHost;
  int  INDEXPort;
  char *INDEXPath;
{
     Abortoutput(sockfd, "Sorry, this isn't a WAIS index...");
     return;
}
#endif 

#ifndef NEXTSEARCH
void
NeXTIndexQuery(sockfd, SearchWords, ZIndexDirectory, DatabaseNm, INDEXHost, INDEXPort)
  int sockfd;
  char *SearchWords;
  char *ZIndexDirectory;
  char *DatabaseNm;  /*** Not used by the next indexer... ***/
  char *INDEXHost;
  int INDEXPort;
{
     Abortoutput(sockfd, "This isn't a NeXT... is it?");
     return;
}
#endif
