/******************************************************************** * $Author: jgoerzen $ * $Revision: 1.3 $ * $Date: 2001/01/17 19:30:25 $ * $Source: /var/cvs/gopher/gopherd/index.c,v $ * $State: Exp $ * * 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.3 2001/01/17 19:30:25 jgoerzen * Change many sprintf -> snprintf * * Revision 1.2 2000/12/20 01:19:20 jgoerzen * Added patches from David Allen * * Revision 1.1.1.1 2000/08/19 00:28:56 jgoerzen * Import from UMN Gopher 2.3.1 after GPLization * * Revision 3.32 1995/09/28 21:11:31 lindner * More fixes... * * Revision 3.31 1995/09/26 05:16:23 lindner * more fixes... * * Revision 3.30 1995/09/26 04:59:47 lindner * Fix abort routines, change to Die/Warn hash over access routines.. * * Revision 3.29 1995/09/25 22:06:58 lindner * Ansification bugs * * Revision 3.28 1995/09/25 05:02:37 lindner * Convert to ANSI C * * Revision 3.27 1995/02/16 22:32:40 lindner * HTML icon support * * Revision 3.26 1994/11/29 05:07:10 lindner * Allow script paths with spaces, better error messages * * Revision 3.25 1994/10/19 03:32:17 lindner * NO_INDEXING hack * * Revision 3.24 1994/10/13 05:17:49 lindner * Compiler complaint fixes * * Revision 3.23 1994/10/02 02:58:08 lindner * Fix for gopher+ index accesses * * Revision 3.22 1994/07/21 17:22:27 lindner * /dev/null code from Brian * * Revision 3.21 1994/06/29 05:25:43 lindner * Add Gticket * * Revision 3.20 1994/05/14 04:18:14 lindner * Fix weird prob... * * Revision 3.19 1994/04/27 19:22:20 lindner * compatible.h added * * Revision 3.18 1994/04/08 21:08:07 lindner * Fix a bug in the Shell Search code * * Revision 3.17 1994/03/08 15:56:04 lindner * gcc -Wall fixes * * Revision 3.16 1994/01/21 03:55:38 lindner * Remove old dead HTML code, update function declarations * * Revision 3.15 1993/11/02 06:01:43 lindner * HTML mods * * Revision 3.14 1993/09/30 16:57:05 lindner * Fix for WAIS and $ requests * * Revision 3.13 1993/09/21 02:47:36 lindner * Fix index problem closing null file handle * * Revision 3.12 1993/09/11 04:40:44 lindner * Don't fork for localhost mindex databases * * Revision 3.11 1993/08/23 18:34:28 lindner * Add fixfile() call * * Revision 3.10 1993/08/06 14:30:44 lindner * Fixes for better security logging * * Revision 3.9 1993/08/05 20:44:02 lindner * Use Gpopen instead of popen, remove extra filtering code * * Revision 3.8 1993/08/04 22:12:43 lindner * Mods to use Gpopen * * Revision 3.7 1993/07/27 05:27:50 lindner * Mondo Debug overhaul from Mitra * * Revision 3.6 1993/07/26 15:31:13 lindner * mods for application/gopher-menu * * Revision 3.5 1993/07/20 23:56:44 lindner * LOGGopher mods * * Revision 3.4 1993/04/15 21:41:38 lindner * Added $ to list of naughty characters (just in case) * * Revision 3.3 1993/04/09 15:54:29 lindner * Fixes for indexes with gopher+ * * Revision 3.2 1993/03/26 19:47:06 lindner * First crack at gopherplussing Indexing * * Revision 3.1.1.1 1993/02/11 18:02:52 lindner * Gopher+1.2beta release * * Revision 1.3 1993/01/30 23:57:44 lindner * Removed html code, moved parsing of the inputline to gopherd.c * * 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 "compatible.h" #include "gopherd.h" #include "command.h" #include "index.h" #include "fileio.h" #include "Debug.h" #include #ifndef NO_INDEXING #define WAISTYPE 1 #define NEXTTYPE 2 #define SHLLTYPE 3 #define GREPTYPE 4 /* * Prototypes.. */ static int Read_hostdata(char *, char *, char *, int *, char *); static void GrepIndexQuery(int, char *, char *, char *, int, char *); static void ShellIndexQuery(int, char *, char *, boolean); void NeXTIndexQuery(int, char *, char *, char *, char *, int, char*, boolean, char*); static int Find_index_type(char *gopherpath); void Do_IndexTrans(int sockfd, char *IndexDirectory, CMDobj *cmd, boolean SendEOF) { char *cp = NULL; char *dbName = NULL; char INDEXHost[256], INDEXPath[256]; /** Hard coded limits, ugh! **/ int INDEXPort=0; int Index_type=0; char *SearchString = CMDgetSearch(cmd); boolean isgplus; char *view = CMDgetView(cmd); char tmp_IndexDirectory[256]; Debug("Index Dir is %s\n", IndexDirectory); Index_type = Find_index_type(IndexDirectory); isgplus = CMDisGplus(cmd); Debug("Index type is %d\n", Index_type); if (Index_type < 0) { /**** Error condition, unknown index type... ****/ Die(sockfd, 400, "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'; } } else if (Index_type == SHLLTYPE) { /*** The selector string has both the directory and the dbname... ***/ cp = strrchr(IndexDirectory, '/'); if (cp == NULL) { dbName = IndexDirectory; IndexDirectory = tmp_IndexDirectory; strcpy (tmp_IndexDirectory, "/"); } else { dbName= cp+1; *cp='\0'; } } if (Read_hostdata(IndexDirectory, INDEXHost, INDEXPath,&INDEXPort,dbName)<0) { LOGGopher(sockfd, "Malformed hostdata file"); writestring(sockfd, "0Error on server, malformed hostdata\t\t\t1\r\n.\r\n"); return; } if (Index_type == SHLLTYPE) { if (IndexDirectory == tmp_IndexDirectory) IndexDirectory = dbName; else *(dbName-1) = '/'; } /* Doctor up the indexdirectory path if we're not running chroot() * we use fixfile to keep things secure.... */ if (!dochroot) IndexDirectory = fixfile(IndexDirectory); /** And call the appropriate query function **/ switch (Index_type) { case NEXTTYPE: NeXTIndexQuery(sockfd, SearchString, IndexDirectory, NULL, INDEXHost, INDEXPort, INDEXPath, isgplus, view); break; case WAISTYPE: WaisIndexQuery(sockfd, IndexDirectory, SearchString, dbName, INDEXHost, INDEXPort, INDEXPath, isgplus, view); break; case GREPTYPE: GrepIndexQuery(sockfd, IndexDirectory, SearchString, INDEXHost, INDEXPort, INDEXPath); break; case SHLLTYPE: ShellIndexQuery(sockfd, IndexDirectory, SearchString, isgplus); break; } /** Finish the transmission attempt **/ if (SendEOF) writestring(sockfd, ".\r\n"); /** Log it here so we get the query in the logfile **/ if (dbName) LOGGopher(sockfd,"search %s/%s for %s", IndexDirectory, dbName, SearchString); else LOGGopher(sockfd, "search %s for %s", IndexDirectory, SearchString); } /* * Try to figure out what each type of object is * * index types are * Error == -1 * WAIS == 1 * NeXT == 2 * ShellScript == 3 * Grep == 4 */ static int Find_index_type(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 ".hostdata" first, fall back to "hostdata" otherwise */ static int Read_hostdata(char *IndexDirectory, char *INDEXHost, char *INDEXPath, int *INDEXPort, char *dbName) { FILE *Hostfile; char hostdataName[256]; /** Read in the proper hostdata file.... **/ rchdir(IndexDirectory); /** Change into the index directory **/ snprintf(hostdataName, sizeof(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 ***/ 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... */ static void GrepIndexQuery(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 = '.'; cp++; } snprintf(command, sizeof(command), "egrep \"%s\" \"%s\"/*", Searchstr, Indexdir); Debug("Grep command is %s\n", command); moocow = Gpopen(sockfd, command, "r"); if (moocow == NULL) { 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) GDtoNet(gd, sockfd, GSFORM_HTML, Gticket, NULL); else { GDtoNet(gd, sockfd, GSFORM_G0, Gticket, NULL); } 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. */ static void ShellIndexQuery(int sockfd, char *Script, char *Searchstring, boolean isgplus) { GopherDirObj *gd; char Command[512]; FileIO *Searchf; int result; gd = GDnew(32); snprintf(Command, sizeof(Command), "\"%s\" %s", Script, Searchstring); Searchf = FIOopenCmdline(Command, "r"); if (Searchf == NULL) { Die(sockfd, 500, "Cannot execute shell script"); } GDfromNet(gd, FIOgetfd(Searchf), NULL); if (UsingHTML) GDtoNet(gd, sockfd, GSFORM_HTML, Gticket, NULL); else { if (isgplus) GDplustoNet(gd, sockfd, NULL, Gticket); else GDtoNet(gd, sockfd, GSFORM_G0, Gticket, NULL); } result = FIOclose(Searchf); GDdestroy(gd); } #ifndef WAISSEARCH void WaisIndexQuery( int sockfd, char *index_directory, char *SearchWords, char *new_db_name, char *INDEXHost, int INDEXPort, char *INDEXPath, boolean isgplus, char *view) { Die(sockfd, 501, "This Server doesn't have WAIS compiled in it..."); return; } #endif #ifndef NEXTSEARCH void NeXTIndexQuery( int sockfd, char *SearchWords, char *ZIndexDirectory, char *DatabaseNm, /*** Not used by the next indexer... ***/ char *INDEXHost, int INDEXPort, char *INDEXPath, boolean isgplus, char *view) { Die(sockfd, 501, "This isn't a NeXT... is it?"); return; } #endif #else /* NO_INDEXING */ void Do_IndexTrans(int sockfd, char *IndexDirectory, CMDobj *cmd, boolean SendEOF) { Die(sockfd, 501, "Sorry, no indexing in this server"); } #endif /* NO_INDEXING */