SMOLNET PORTAL home about changes
/********************************************************************
 * wilkinson
 * 3.27VMS
 * 1996/01/24  11:00   
 * gopher_root1:[gopher.g2.vms2_13.gopherd]index.c,v
 * 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:
 * index.c,v
 * Revision 3.27VMS-1 1996/01/24 11:00  wilkinson
 * Made OPCOM message console selection configurable
 *    
 * Revision 3.27VMS 1995/09/25 14:45    wilkinson
 * Consolodate VMS/Unix source code for server as well as client
 *
 * 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 "fileio.h"
#include "Debug.h"
#ifdef VMS_SERVER
#undef stat		   /** Stupid openers thing **/
#undef chdir		   /** Use the real runtime routine under VMS **/
#include "serverutil.h"
#include <opcdef.h>
#endif
#include <stdio.h>

#ifndef NO_INDEXING

#define WAISTYPE 1
#define NEXTTYPE 2
#define SHLLTYPE 3
#define GREPTYPE 4
#ifdef VMS_SERVER
#define CMD1TYPE 5

#include <syidef.h>
void SearchVersion(int, GopherObj *, GopherDirObj *);
void Kaboom(int, GopherObj *, GopherDirObj *);
void CreateGO4link(GopherObj *, GopherDirObj *, char *);
void CreateFTPlink(GopherObj *, GopherDirObj *, char *);
void CreateEXElink(GopherObj *, GopherDirObj *, char *, char, char *);
void GDpostprocVMS(GopherDirObj *, GDCobj *, int, boolean);
#ifdef system
#undef system
#endif
#define system(a) VMS$system(a)

boolean	    Do_Sort;
boolean	    Do_DateNsize;
boolean	    Do_Gplus;
boolean	    tried_support;
#endif


void 
Do_IndexTrans(sockfd, IndexDirectory, cmd, SendEOF)
  int sockfd;
  char *IndexDirectory;
  CMDobj *cmd;
  boolean SendEOF;
{
     char *cp = NULL;
     char *dbName = NULL;
#ifndef VMS_SERVER
     char INDEXHost[256], INDEXPath[256];  /** Hard coded limits, ugh! **/
#else
     String *INDEXHost;			   /** No hard coded limits this way **/
     String *INDEXPath;
     int  status;
     char *inputline = CMDgetSelstr(cmd);
#endif
     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);

#ifdef VMS_SERVER
  {
     /** First siphon off the sorting & DateNsize tokens, if any **/
     char *cp;

     Do_Sort = -1;	    /* Do Sort: Not TRUE, Not FALSE */
     Do_DateNsize = -1;	    /* Same for Do DateNsize	    */
     Do_Gplus = FALSE;	    /* G+ is *not* the default	    */
     cp = inputline;

     while (*cp==':')
     {
	if (strncasecmp(cp,":sort:",strlen(":sort:"))==0) {
	    inputline = (cp += strlen(":sort")) + 1;
	    Do_Sort = TRUE;
	}
	else
	if (strncasecmp(cp,":nosort:",strlen(":nosort:"))==0) {
	    inputline = (cp += strlen(":nosort")) + 1;
	    Do_Sort = FALSE;
	}
	else
	if (strncasecmp(cp,":G+:",strlen(":G+:"))==0) {
	    inputline = (cp += strlen(":G+")) + 1;
	    Do_Gplus = TRUE;
	}
	else
	if (strncasecmp(cp,":noG+:",strlen(":noG+:"))==0) {
	    inputline = (cp += strlen(":noG+")) + 1;
	    Do_Gplus = FALSE;
	}
	else
	if (strncasecmp(cp,":G0:",strlen(":G0:"))==0) {
	    inputline = (cp += strlen(":G0")) + 1;
	    Do_Gplus = FALSE;
	}
	else
	if (strncasecmp(cp,":D&Sz:",strlen(":D&Sz:"))==0) {
	    inputline = (cp += strlen(":D&Sz")) + 1;
	    Do_DateNsize = TRUE;
	}
	else
	if (strncasecmp(cp,":noD&Sz:",strlen(":noD&Sz:"))==0) {
	    inputline = (cp += strlen(":noD&Sz")) + 1;
	    Do_DateNsize = FALSE;
	}
     } 
  }
#endif

     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... ****/
#ifdef VMS_SERVER
	  SetAbrtFile(IndexErr, NULL /* AbortGS ??? */, KeepAbrtGS, NULL);
#endif
	  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';
	  }
     }
#ifndef VMS_SERVER
     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, &INDEXPort, INDEXPath, 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);
#else
    else 
	if (Index_type == SHLLTYPE)
	    if (tried_support)
		uchdir(GDCgetSupportDir(Config));
    INDEXHost = STRnew();
    STRset(INDEXHost, GDCgetHostname(Config));
    INDEXPath = STRnew();
    STRset(INDEXPath, IndexDirectory);
    INDEXPort = GDCgetPort(Config);
#endif

     /** 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:
#ifndef VMS_SERVER
	  GrepIndexQuery(sockfd, IndexDirectory, SearchString, 
			 INDEXHost, INDEXPort, INDEXPath);
#else
          if (Do_DateNsize == -1)
	    Do_DateNsize = TRUE;
	  if (Do_Sort == -1)
	    Do_Sort = GDCgetSortGREP(Config);
	  if (Do_Gplus == -1)
	    Do_Gplus = GDCgetIsGplus(Config);
	  GrepIndexQuery(sockfd, IndexDirectory, SearchString, 
			 STRget(INDEXHost), INDEXPort, STRget(INDEXPath));
#endif
	  break;
	  
     case SHLLTYPE:
#ifndef VMS_SERVER
	  ShellIndexQuery(sockfd, IndexDirectory, SearchString, isgplus);
#else
          if (Do_DateNsize == -1)
	    Do_DateNsize = TRUE;
	  if (Do_Sort == -1)
	    Do_Sort = GDCgetSortShell(Config);
	  if (Do_Gplus == -1)
	    Do_Gplus = GDCgetIsGplus(Config);
	  ShellIndexQuery(sockfd, IndexDirectory, SearchString, isgplus,
			 STRget(INDEXHost), INDEXPort, STRget(INDEXPath));
#endif
	  break;
#ifdef VMS_SERVER
     case CMD1TYPE:
          if (Do_DateNsize == -1)
	    Do_DateNsize = TRUE;
	  if (Do_Sort == -1)
	    Do_Sort = GDCgetSortCMD1(Config);
	  if (Do_Gplus == -1)
	    Do_Gplus = GDCgetIsGplus(Config);
	  CMD1IndexQuery(sockfd, IndexDirectory, SearchString, 
			 STRget(INDEXHost), INDEXPort, STRget(INDEXPath));
	  break;
#endif
     }
#ifdef VMS_SERVER
     STRdestroy(INDEXHost);
     STRdestroy(INDEXPath);
#endif

     /** 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
 */

int
Find_index_type(gopherpath)
  char *gopherpath;
{
     char Teststr[512];
     FILE *Testfile;
#ifdef VMS_SERVER
     char VMSdirectory[256];
     char *cp;


     tried_support = FALSE;
     /*** Check for the VMS CMD1TYPE designator ($) ***/
     if (gopherpath[0] == '$') {
	cp = skip_whitespace(gopherpath+1);
	strcpy(Teststr, cp);
	if ((cp=strchr(Teststr,' '))!=NULL)
	    *cp = '\0';
	/*** Check for a valid CMD1TYPE sub-type ***/
	if ((strcasecmp(Teststr,"SEARCH")==0)
	    || (strcasecmp(Teststr,"SEARCH&")==0)
	    || (strcasecmp(Teststr,"SEARCH|")==0)
	    || (strcasecmp(Teststr,"SEARCH~&")==0)
	    || (strcasecmp(Teststr,"SEARCH~|")==0)
	    || (strcasecmp(Teststr,"SINCE")==0)
	    || (strcasecmp(Teststr,"BEFORE")==0)
	    || (strcasecmp(Teststr,"VERSION")==0)
	    || (strcasecmp(Teststr,"KABOOM")==0)
	    || (strcasecmp(Teststr,"GO4LINK")==0)
	    || (strcasecmp(Teststr,"FTPLINK")==0)
	    || (strcasecmp(Teststr,"EXELINK")==0)) {
	    return(CMD1TYPE);
	}
     }

     {
	char *cp1, path[256];

	strcpy(Teststr, gopherpath);
	/* find end of first selector token */
	if ((cp=strchr(Teststr,' '))!=NULL)
	*cp = '\0';
	if (Teststr[0] == '/') {
	 /* Convert to VMS pathspec before testing */
	 strcpy(path, (cp1=VMS$WWW_to_VMS(Teststr, A_FILE)) ? cp1 : Teststr);
	 strcpy(Teststr, path);
	}
	else
	    strcpy(path, Teststr);  /*	In case we need it later... */
    Try_Support:
	Testfile = fopen_VMSopt(Teststr, "r");
	if (Testfile != NULL) {
	  /** Shell script? **/
	if (strcasecmp(Teststr+strlen(Teststr)-strlen(".SHELL"),".SHELL")==0)
	  if (getc(Testfile) == '$')
	       if (getc(Testfile) == '!') {
		    fclose(Testfile);
		    return(SHLLTYPE);
	       }
	}
	else 
	    if (!tried_support) {
		tried_support = TRUE;
		strcpy(Teststr, GDCgetSupportDir(Config));
		strcat(Teststr, path);	/* Told ya we'd need it...  */
		goto Try_Support;
	}
     }

     strcpy(Teststr, gopherpath);
     if (Teststr[0] == '/') {
         /* Convert to VMS pathspec */
         char *cp1, path[256];
	 strcpy(path, (cp1=VMS$WWW_to_VMS(Teststr, A_FILE)) ? cp1 : Teststr);
	 strcpy(Teststr, path);
     }
     if ((cp=strchr(Teststr,'[')) && strchr(cp,']'))
          return(GREPTYPE);

#else
     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);
	       }
     }
#endif

     return(-1);
}
     
#ifndef VMS_SERVER
/*
 * 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 ***/
	  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);
}
#endif

/*
 * 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;
#ifdef VMS_SERVER
     char path[256];
     char *c2, *c3;

     if (Indexdir[0] == '/') {
         /* Convert to VMS pathspec */
	 strcpy(path, (c2=VMS$WWW_to_VMS(Indexdir, A_FILE)) ? c2 : Indexdir);
	 strcpy(Indexdir, path);
     }

     c3 = c2 = (char *) malloc(sizeof(char)*strlen(Indexdir)+1);
     strcpy(c3,Indexdir);

     while (strlen(c2)) {
	cp = strpbrk(c2,",");
	if (cp)
	    *cp = '\0';
	if (!VMS$Validate_Filespec(c2)) {
	    LOGGopher(sockfd, "GREP Illegal syntax for %s", Indexdir);
	    SetAbrtFile(SyntaxErr, NULL /* AbortGS ??? */, KeepAbrtGS, NULL);
	    Abortoutput(sockfd, "Eh? Confusing Request");
	    free(c3);
	    return;
	}
	c2 += strlen(c2) + ((cp==NULL) ? 0 : 1);
     }
     free(c3);
#endif

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

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

     sprintf(command, "egrep \"%s\" \"%s\"/*", Searchstr, Indexdir);
#else
     GSsetDefaults(gs);	    /* Oughtn't Unix do this to?    */
     strcpy(vms_pipe_file, cp=tempnam(GDCgetScratchDir(Config),NULL));
     free(cp);
     /*** If not Inetd/MULTINET_SERVER and no EGREP, use SEARCH ***/
     if (!RunFromInetd && getenv("EGREP") == NULL) {
          while(cp=strpbrk(Searchstr," \t\r\n")) {
	     if (*(cp-1)==',')
	         strcpy(cp,cp+1);
	     else
	         *cp = ',';
          }
          sprintf(command,"$ search/nohead/output=%s/window=0 %s %s",
			vms_pipe_file, Indexdir, Searchstr);
     }
     /*** Use EGREP ***/
     else {
          cp = Searchstr;
          while (*cp != '\0') {
	       if (*cp == '"' || *cp == '`')
	            *cp = '.';
	       cp++;
          }
          if (Indexdir[strlen(Indexdir)-1] == ']')
               sprintf(command,"$ egrep -il \">%s\" -e \"%s\" \"%s*.*;\"",
			       vms_pipe_file, Searchstr, Indexdir);
          else
               sprintf(command,"$ egrep -il \">%s\" -e \"%s\" \"%s\"",
			       vms_pipe_file, Searchstr, Indexdir);     
     }
     if (strlen(Searchstr)==0) {
	writestring(sockfd, ".\r\n");
	LOGGopher(sockfd, "Null Search String");
	GSdestroy(gs);
	GDdestroy(gd);
	return;
     }
#endif
     Debug("Grep command is %s\n", command);

     moocow = Gpopen(sockfd, command, "r");
     
     if (moocow == NULL) {
	  LOGGopher(sockfd, "Couldn't open grep command");
#ifdef VMS_SERVER
	  GSdestroy(gs);	/*  Oughtn't Unix do this too?	*/
	  GDdestroy(gd);
#endif
	  return;
     }

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

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

	  cp = strchr(inputline, ':');
	  *cp='\0';
	  cp =strstr(inputline, INDEXPath) + strlen(INDEXPath);
#else
	  if (isadir(inputline)==1)
		GSsetType(gs,A_DIRECTORY);
	  /* force names lowercase */
	  str_tolower(cp=inputline);
	  /* create the path and filename */
	  strcpy(path, cp);
	  c2 = strchr(path,']') + 1;
	  *c2 = '\0';
	  c2 = strchr(inputline,';');
	  *c2 = '\0';
	  c2 = strchr(inputline,']')+1;
	  if (GDCignore(Config,c2))
		continue;
	  if (chdir(path)<0)
		continue;
	  c2 = (char *)malloc(2+strlen(inputline));
	  *c2 = GSgetType(gs);
	  strcpy(c2+1,inputline);
	  strcpy(inputline, c2);
	  free(c2);
	  cp = inputline;
#endif
	  GSsetPath(gs, cp);
	  GSsetHost(gs, INDEXHost);
	  GSsetPort(gs, INDEXPort);

	  GDaddGS(gd, gs);
     }
#ifdef VMS_SERVER
     if (GDgetNumitems(gd)) {
	  GDpostprocVMS(gd,Config,GopherPort,Do_Gplus);
	  if (Do_DateNsize) GDaddDateNsize(gd);
	  if (Do_Sort) GDsort(gd);
#endif
     if (UsingHTML)
	  GDtoNet(gd, sockfd, GSFORM_HTML, Gticket, NULL);
     else {
	  GDtoNet(gd, sockfd, GSFORM_G0, Gticket, NULL);
     }
#ifdef VMS_SERVER
 }
     GSdestroy(gs);
     GDdestroy(gd);
#endif
     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.
 */

#ifndef VMS_SERVER
void
ShellIndexQuery(sockfd, Script, Searchstring, isgplus)
#else
void
ShellIndexQuery(sockfd, Script, Searchstring, isgplus,
				INDEXHost, INDEXPort, INDEXPath)
  char *INDEXHost;
  int INDEXPort;
  char *INDEXPath;
#endif
  int sockfd;
  char *Script;
  char *Searchstring;
  boolean isgplus;
{
     GopherDirObj *gd;
     char          Command[512];
#ifndef VMS_SERVER
     FileIO       *Searchf;
#else
     FILE	  *Searchf;
#endif
     int           result;

#ifdef VMS_SERVER
     char	  *cp;
     char	  *cfg;
     int          status;

     if((cp=strchr(Script,' '))!=NULL) {
         char *cp1, path[256];
	 *cp = '\0';
         if(Script[0] == '/')
             /* Convert to first pathspec to VMS syntax */
	     sprintf(path, "%s ",
	     		   (cp1=VMS$WWW_to_VMS(Script, A_FILE)) ? cp1 : Script);
	 else
	     sprintf(path, "%s ", Script);
         if(*(cp+1) == '/')
             /* Convert to second pathspec to VMS syntax */
	     strcat(path, (cp1=VMS$WWW_to_VMS(cp+1, A_FILE)) ? cp1 : cp+1);
	 else
	     strcat(path, cp+1);
	 *cp = ' ';
	 strcpy(Script, path); 
     
	 strcpy(vms_pipe_file, Script);
	 if ((cp=strchr(vms_pipe_file,' '))!=NULL)
	    *cp = '\0';
	 if (!VMS$Validate_Filespec(vms_pipe_file)) {
	    LOGGopher(sockfd, "SHELL Illegal syntax for %s", Script);
	    SetAbrtFile(SyntaxErr, NULL /* AbortGS ??? */, KeepAbrtGS, NULL);
	    Abortoutput(sockfd, "Eh? Confusing Request","syntax");
	    return;
	 }
	 /*** Clean up the arguments, remove  ; and " and `**/
	 cp = Searchstring;
	 while (*cp != '\0') {
	      if (*cp == ';' ||*cp == '"' || *cp == '`')
		   *cp = '.';
	      cp++;
	 }
     }     
#endif     

     gd = GDnew(32);

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

     Searchf = FIOopenCmdline(Command, "r");
#else
     strcpy(vms_pipe_file, cp=tempnam(GDCgetScratchDir(Config),NULL));
     free(cp);
     cp = GDCgetDatadir(Config);
     cfg = (char *) malloc(sizeof(char)*strlen(cp+1));
     strcpy(cfg, cp);
     if ((cp=strchr(cfg,':'))!=NULL)
	*cp='\0';
     sprintf(Command, "$ @%s %s \"%s\" \"%s\" %d %s", Script, vms_pipe_file, 
				    Searchstring, INDEXHost, INDEXPort,
					cfg);
     LOGGopher(sockfd, "Command: %s", Command);
     free(cfg);

     Searchf = Gpopen(sockfd, Command, "r");
#endif

     if (Searchf == NULL) {
#ifdef VMS_SERVER
	  SetAbrtFile(NothingThere, NULL /* AbortGS ??? */, KeepAbrtGS, NULL);
#endif
	  Abortoutput(sockfd,"Cannot execute shell script");
#ifdef VMS_SERVER
	  GDdestroy(gd);	/* Oughtn't Unix do this, too?	*/
	  return;
#endif
     }

#ifndef VMS_SERVER
     GDfromNet(gd, FIOgetfd(Searchf), NULL);
#else
     GDfromNet(gd, fileno(Searchf), NULL);

     if (GDgetNumitems(gd)) {
	  GDpostprocVMS(gd,Config,GopherPort,Do_Gplus);
	  if (Do_DateNsize) GDaddDateNsize(gd);
	  if (Do_Sort) GDsort(gd);
#endif

     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);
     }
#ifdef VMS_SERVER
     }
     result = pclose(Searchf);
#else

     result = FIOclose(Searchf);
#endif

     GDdestroy(gd);
}

	  
#ifndef WAISSEARCH

void
WaisIndexQuery(sockfd, index_directory, SearchWords, new_db_name, INDEXHost, INDEXPort, INDEXPath, isgplus, view)
  int sockfd;
  char *index_directory;
  char *SearchWords;
  char *new_db_name;
  char *INDEXHost;
  int  INDEXPort;
  char *INDEXPath;
  boolean isgplus;
  char *view;
{
#ifdef VMS_SERVER
     LOGGopher(sockfd, "WAIS index %s, srch '%s', Db %s", index_directory,
				SearchWords, new_db_name);
     SetAbrtFile(IndexErr, NULL, KeepAbrtGS, NULL);
     Abortoutput(sockfd, "Sorry, no WAIS indexing supported");
#else
     Abortoutput(sockfd, "This Server doesn't have WAIS compiled in it...");
#endif
     return;
}
#endif 

#ifndef NEXTSEARCH
void
NeXTIndexQuery(sockfd, SearchWords, ZIndexDirectory, DatabaseNm, INDEXHost, INDEXPort, INDEXPath, isgplus, view)
  int sockfd;
  char *SearchWords;
  char *ZIndexDirectory;
  char *DatabaseNm;  /*** Not used by the next indexer... ***/
  char *INDEXHost;
  int INDEXPort;
  char *INDEXPath;
  boolean isgplus;
  char *view;
{
#ifdef VMS_SERVER
     LOGGopher(sockfd, "NeXT index %s, srch '%s'", ZIndexDirectory,
				SearchWords);
     SetAbrtFile(IndexErr, NULL, KeepAbrtGS, NULL);
     Abortoutput(sockfd, "Sorry, no NeXT indexing supported");
#else
     Abortoutput(sockfd, "This isn't a NeXT... is it?");
#endif
     return;
}
#endif

#else /* NO_INDEXING */
void 
Do_IndexTrans(sockfd, IndexDirectory, cmd, SendEOF)
  int sockfd;
  char *IndexDirectory;
  CMDobj *cmd;
{
#ifdef VMS_SERVER
     SetAbrtFile(IndexErr, NULL, KeepAbrtGS, NULL);
#endif
     Abortoutput(sockfd, "Sorry, no indexing in this server");
}
#endif /* NO_INDEXING */

#if !defined(NO_INDEXING) && defined(VMS_SERVER)

/*
 * This starts up a 1-line command that's defined to be an "index gateway"
 * Currently this is only implemented for VMS
 *
 * Currently "SEARCH", "SINCE", "BEFORE", "VERSION", "GO4LINK", "FTPLINK" 
 * and "EXELINK" are supported.  "KABOOM" is a debugging "feature."
 *
 * "SEARCH" performs a case-insensitive search for terms, without any
 * interpretation of printable characters, with leading and trailing spaces
 * trimmed, and with embedded spaces treated as the Boolean OR.  The search
 * corresponds to the expectations of the client's Boldit() routine.  SEARCH
 * may be suffixed by &, |, ~& or ~| to select the VMS /MATCH= operand, and
 * override the default, implicit /MATCH=OR.
 *
 * "SINCE" and "BEFORE" return lists of files modified since or before
 * the supplied term, a date specification.
 *
 * "VERSION" displays version information about the server.  It's not really
 * a "search" even though it acts like one.
 *
 * "GO4LINK" uses a pseudo-SearchString (the Internet address of a Gopher
 * server) to create a link tuple which the client can use to connect to
 * a server there.
 *
 * "FTPLINK" uses a pseudo-SearchString (the Internet address of an FTP
 * archive) to create a link tuple which the client can pass to the server's
 * FTP gateway.
 *
 * "EXELINK" uses a pseudo-SearchString (the exec script arguments the user
 * wishes to pass) to create a link tuple which the client can pass to the
 * server for execution of a script.  The type of output to be expected by
 * the client and the script to be executed are specified with the execlink
 * keyword.  E.g.,  "Path=7$exelink Xscriptname"  where "X" is the Type=
 * entry for the link tuple to be generated, and "scriptname" is the script
 * file name to be used in the Path=exec:<args>:scriptname tuple entry.  The
 * <args>, if any, are supplied by the user as the terms of the pseudo-search.
 *
 * "KABOOM" causes an access violation for debugging purposes.  It will only
 *  work when the local host alias and client requestor match the values
 *  specified in the environment variables (symbols or logicals) named
 *  GOPHERD_KABOOM_HOST and GOPHERD_KABOOM_CLIENT, respectively.
 *
 * The command must write output in the same format as the GrepIndexQuery()
 * output is formatted (that is, the result must be a menu of one entry or
 * more).
 *
 */

void
CMD1IndexQuery(int sockfd, char *CMDcmd, char *Searchstr, char *INDEXHost, 
		    int INDEXPort, char *INDEXPath)
{
     FILE *moocow;
     char command[512];
     char inputline[512];
     char *filename;
     char path[256];
     char *cp;
     GopherObj *gs;
     GopherDirObj *gd;
     int  status;
     char *c2, *c3;
     char *beg, *end;
     char VMSSearchstr[256];
     char *match;
     char exectype;
     int i;

     if (filename=strchr((c2 = skip_whitespace(CMDcmd+1)),' ')) {
	filename++;
	if (*c2=='e' || *c2=='E') {
	    exectype = *filename++;
	    if (*filename==' ')
		filename=skip_whitespace(filename);
	}
     }
     else switch (*c2) {    /*	Some of these CMD1 searches don't need files */
        case 'k':
	case 'K':   goto files_valid;

        case 'g':
	case 'G':   goto files_valid;

        case 'f':
	case 'F':   goto files_valid;

	case 'v':
	case 'V':   goto files_valid;

	default:    goto illegal;
     }

     if (filename[0] == '/') {
         /* Convert to VMS pathspec */
         char *cp1, path[256];
	 strcpy(path, (cp1=VMS$WWW_to_VMS(filename, A_FILE)) ? cp1 : filename);
	 strcpy(filename, path);
     }

     c3 = c2 = (char *) malloc(sizeof(char)*strlen(filename)+1);
     strcpy(c3,filename);
     while (strlen(c2)) {
	cp = strpbrk(c2,",");
	if (cp)
	    *cp = '\0';
	if (!VMS$Validate_Filespec(c2)) {
     illegal:
	    LOGGopher(sockfd, "CMD1 Illegal syntax for %s", CMDcmd);
	    SetAbrtFile(SyntaxErr, NULL /* AbortGS ??? */, KeepAbrtGS, NULL);
	    Abortoutput(sockfd, "Eh? Confusing Request");
	    free(c3);
	    return;
	}
	c2 += strlen(c2) + ((cp==NULL) ? 0 : 1);
     }
     free(c3);

files_valid:     
     /*** Establish the output file for the VMS command ***/
     strcpy(vms_pipe_file, cp=tempnam(GDCgetScratchDir(Config),NULL));
     free(cp);

     /*** Get the CMD1TYPE sub-type ***/
     cp = skip_whitespace(CMDcmd+1);

     if ((strncasecmp(cp, "SEARCH ", 7)==0)
	|| (strncasecmp(cp, "SEARCH& ", 8)==0) 
	|| (strncasecmp(cp, "SEARCH| ", 8)==0)
	|| (strncasecmp(cp, "SEARCH~& ", 9)==0)
	|| (strncasecmp(cp, "SEARCH~| ", 9)==0)) {
     /*** Determine match qualification, if any ***/
	match = NULL;
	if (strncmp(cp+6,"& ",2)==0)
	    match = "/MATCH=AND";
	else
	if (strncmp(cp+6,"| ",2)==0)
	    match = "/MATCH=OR";
	else
	if (strncmp(cp+6,"~& ",3)==0)
	    match = "/MATCH=NAND";
	else
	if (strncmp(cp+6,"~| ",3)==0)
	    match = "/MATCH=NOR";
     /*** Convert Searchstr for the VMS SEARCH command ***/ 
        beg = Searchstr;
        end = beg + strlen(Searchstr);
        i = 0;
	/*** Trim any leading spaces and prefix a double-quote ***/
	while (*(beg) == ' ' && beg < end) beg++; 
	VMSSearchstr[i++] = '"';
        while (beg < end) {
              /*** Reiterate any embedded double-quotes ***/
              if (*beg == '"') {
	         VMSSearchstr[i++] = '"';
	         VMSSearchstr[i++] = *(beg++);
	      }
	      /*** Replace any embedded spaces with a "," triplet ***/
	      /*** or omit trailing spaces                        ***/
	      else if (*beg == ' ') {
	         while (*beg == ' ' && beg < end) beg++;
		 if (beg < end) {
		    VMSSearchstr[i++] = '"';
		    VMSSearchstr[i++] = ',';
		    VMSSearchstr[i++] = '"';
		 }
	      }
	      /*** Otherwise, use the character as entered ***/
	      else VMSSearchstr[i++] = *(beg++);
        }
	/*** Append a double-quote and terminate ***/
	VMSSearchstr[i++] = '"';
        VMSSearchstr[i] = '\0';
     }
     else
     if (strncasecmp(cp, "VERSION", 7)==0 ||
         strncasecmp(cp, "KABOOM", 6)==0 ||
         strncasecmp(cp, "GO4LINK", 7)==0 ||
         strncasecmp(cp, "FTPLINK", 7)==0 ||
         strncasecmp(cp, "EXELINK", 7)==0)
     {
	/*** No further validation required ***/
     }
     else {
     /*** "SINCE" or "BEFORE" -- Validate the entry as a date ***/
        if (!Validate_Date(Searchstr)) {
	   LOGGopher(sockfd, "Illegal search term \"%s\" for %s", Searchstr,
			     CMDcmd);
	   SetAbrtFile(SyntaxErr, NULL /* AbortGS ??? */, KeepAbrtGS, NULL);
	   Abortoutput(sockfd, "Eh? Unusable Search Term(s)");
	   return;
        }
     }

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

     /*** Format the command string ***/
     if (strncasecmp(cp, "SEARCH", 6)==0) {
         sprintf(command,"$search%s/nohead/output=%s/window=0 %s %s",
	    match==NULL?"":match, vms_pipe_file, filename, VMSSearchstr);
	 /*** Log the string actually used in the search ***/
         LOGGopher(sockfd, "VMSSearchstr: %s", VMSSearchstr);
     }
     else if (strncasecmp(cp, "SINCE ", 6)==0)
	 sprintf(command, "$dir/nohead/notrail/output=%s/since=%s %s",
			  vms_pipe_file, Searchstr, filename);
     else if (strncasecmp(cp, "BEFORE ", 7)==0)
	 sprintf(command, "$dir/nohead/notrail/output=%s/before=%s %s",
			  vms_pipe_file, Searchstr, filename);
     else if (strncasecmp(cp, "VERSION", 7)==0) {
	sprintf(command, "determine version level");
	vms_pipe_file[0] = '\0';  /* Won't need output file */
     }
     else if (strncasecmp(cp, "KABOOM", 6)==0) {
	sprintf(command, "generate accvio exception");
	vms_pipe_file[0] = '\0';  /* Won't need output file */
     }
     else if (strncasecmp(cp, "GO4LINK", 7)==0) {
	sprintf(command, "create a Gopher Server tuple");
	vms_pipe_file[0] = '\0';  /* Won't need output file */
     }
     else if (strncasecmp(cp, "FTPLINK", 7)==0) {
	sprintf(command, "create an FTP gateway tuple");
	vms_pipe_file[0] = '\0';  /* Won't need output file */
     }
     else if (strncasecmp(cp, "EXELINK", 7)==0) {
	sprintf(command, "create an Exec script tuple");
	vms_pipe_file[0] = '\0';  /* Won't need output file */
     }
     Debug("CMD is %s\n", command);

     if (strlen(vms_pipe_file)==0) {
     /*	One of our non-DCL commands...VERSION, GO4LINK, FTPLINK, EXELINK... */
	moocow = NULL;
	GSsetHost(gs, INDEXHost);
	GSsetPort(gs, INDEXPort);
	switch(*cp) {
	case 'k':
	case 'K':   Kaboom(sockfd, gs, gd);        
		    break;
        case 'g':
	case 'G':   CreateGO4link(gs, gd, Searchstr);
		    break;
        case 'f':
	case 'F':   CreateFTPlink(gs, gd, Searchstr);
		    break;
        case 'e':
	case 'E':   CreateEXElink(gs, gd, Searchstr, exectype, filename);
		    break;
	case 'v':
	case 'V':   SearchVersion(sockfd, gs,gd);
		    break;
	default:    LOGGopher(sockfd, "Unknown non-DCL search %s",cp);
	}
	Do_Sort = Do_DateNsize = FALSE;
     }
     else {	/*  Read results much like we do for GREP indexes    */
	     moocow = Gpopen(sockfd, command, "r");
	     if (moocow == NULL) {
		  LOGGopher(sockfd,"Couldn't call/open CMD - %s",
							    STRerror(errno));
		  GSdestroy(gs);
		  GDdestroy(gd);
		  return;
	     }

	     cp = inputline;
	     while (fgets(cp+1, sizeof(inputline)-1, moocow)) {
		  GSsetType(gs, A_FILE);
		  if (isadir(cp+1)==1)
			GSsetType(gs,A_DIRECTORY);
		  inputline[0] = GSgetType(gs);
		  ZapCRLF(inputline);
		  /* force names lowercase */
		  str_tolower(cp+1);
		  /* create the path and filename */
		  strcpy(path, cp+1);
		  c2 = strchr(path,']') + 1;
		  *c2 = '\0';
		  c2 = strchr(inputline,';');
		  *c2 = '\0';
		  c2 = strchr(inputline,']')+1;
		  if (GDCignore(Config,c2))
			continue;
		  if (chdir(path)<0)
			continue;
		  GSsetPath(gs, inputline);
		  GSsetHost(gs, INDEXHost);
		  GSsetPort(gs, INDEXPort);

		  GDaddGS(gd, gs);
	     }
	     pclose(moocow);
	}
	if (GDgetNumitems(gd)) {
	      if (Do_Sort) GDsort(gd);
	      GDpostprocVMS(gd,Config,GopherPort,Do_Gplus);
	      if (Do_DateNsize) GDaddDateNsize(gd);
	      if (UsingHTML)
		GDtoNet(gd, sockfd, GSFORM_HTML, Gticket, NULL);
	       else {
		      GDtoNet(gd, sockfd, GSFORM_G0, Gticket, NULL);
	       }
	}
	GSdestroy(gs);
	GDdestroy(gd);
}

void
SearchVersion(int sockfd, GopherObj *gs, GopherDirObj *gd)
{
    FILE *fp;
    static long i;
    static char path[256];
    char *x, *cp;
    char image[512];
    time_t howlong  = time(NULL) - ServerStarted + 1;
    int connperhour = (Connections * 3600) / howlong;
    char *started;
    struct stat stats_buf;
    struct dsc$descriptor_s
         dsc$tstamp = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
				/* Structures IHDdef & IHIdef extrapolated from
				    $IHDDEF and $IHIDEF, respectively, as
				    found in SYS$LIBRARY:LIB.MLB, VMS v5.2  */
#ifndef __ALPHA
    struct IHDdef
	{
	    short   IHD$W_SIZE;
	    short   IHD$W_ACTIVOFF;
	    short   IHD$W_SYMDBGOFF;
	    short   IHD$W_IMGIDOFF;
	    short   IHD$W_PATCHOFF;
	    short   IHD$W_VERSION_ARRAY_OFF;
	/*  There's more, but we don't need it... */
	} *ihd$;

    struct IHIdef
	{
	    char    IHI$T_IMGNAM[40];
	    char    IHI$T_IMGID[16];
	    char    IHI$Q_LINKTIME[8];
	    char    IHI$T_LINKID[16];
	} *ihi$;
#else
    struct IHIdef
	{
	    char    IHI$Q_LINKTIME[8];
	    char    IHI$T_IMGNAM[40];
	    char    IHI$T_IMGID[16];
	    char    IHI$T_LINKID[16];
	} *ihi$;
#endif
    struct itmlst {
  unsigned short int length;
  unsigned short int code;
  char *bufadr;
  int *retlen;
    }	itmlist[3] = {  { 8, SYI$_VERSION, &path[100], (int *) &i},
			{ 31, SYI$_HW_NAME, &path[120], (int *) &i},
			{ 0, 0, 0, 0 } };

#define VCFG(a,b)\
{ sprintf(path,(a),b);GSsetTitle(gs,path);GDaddGS(gd,gs); }

#define VCFG2(a,b,c)\
{ sprintf(path,(a),b,c);GSsetTitle(gs,path);GDaddGS(gd,gs); }

#define IFAVAIL(a) (a?(strlen((a))==0?"N/A":(a)):"N/A")

#define IFAVAILQ(a) (a?(strlen((a))==0?"":"\""):""), \
		    (a?(strlen((a))==0?"N/A":(a)):"N/A"), \
		    (a?(strlen((a))==0?"":"\""):"")
       
    bzero(image, sizeof(image));
    bzero(path, sizeof(path));
    GSsetGplus(gs,TRUE);
    GSsetNum(gs, 0);
    GSsetType(gs, path[0] = A_FILE);
    strcat(path,pname);
    if ((cp = strrchr(path, ';')) != 0)
         *cp = '\0';
    GSsetPath(gs, path);
    if ((fp = ufopen(pname, "r")) == NULL)
	GSsetType(gs, A_ERROR);
    else {			/*  Read in 1st block of Image Header */
	if (fread(image, sizeof(char), sizeof(image), fp) == 0)
	    GSsetType(gs, A_ERROR);
	else {			/* Pick up offset to Image Name & Ident */
#ifndef __ALPHA
	    ihd$ = (struct IHDdef *)image;
	    i = ihd$->IHD$W_IMGIDOFF;
	    ihi$ = (struct IHIdef *)(image+i);
#else
	    ihi$ = (struct IHIdef *)(image+192);
#endif
	    strcpy(path,"%fn [%ts, %sz]");
	    GSsetTitle(gs,path);
	    ustat(pname, &stats_buf);
	    GSaddDateNsize(gs, stats_buf);
	    sprintf(path, "Image:         %s", GSgetTitle(gs));
	    GSsetTitle(gs,path);
	    GSsetType(gs, A_UNIXBIN);
	    sprintf(path,"%c%s", A_UNIXBIN, fgetname(fp,path+1));	    
	    GSsetPath(gs,path);
	    GDaddGS(gd, gs);
	    GSsetType(gs, A_INFO);
	    GSsetPath(gs,"");
	    if (DEBUG) {
		GSsetTitle(gs,"DEBUG Mode:    Debugging");
		GDaddGS(gd, gs);
	    }
	    strcpy(path,"Image Name:    \"");
	    strncat(path,ihi$->IHI$T_IMGNAM+1,ihi$->IHI$T_IMGNAM[0]);
	    strcat(path, "\"");
	    GSsetTitle(gs,path);    GDaddGS(gd, gs);
	    strcpy(path,"Image File ID: \"");
	    strncat(path,ihi$->IHI$T_IMGID+1,ihi$->IHI$T_IMGID[0]);
	    strcat(path, "\"");
	    GSsetTitle(gs,path);    GDaddGS(gd, gs);
	    bzero(path,sizeof(path)-100);
	    strcpy(path,"Link date/time: ");
	    dsc$tstamp.dsc$a_pointer = path+strlen(path);
	    dsc$tstamp.dsc$w_length = sizeof(path)-strlen(path);
	    LIB$FORMAT_DATE_TIME(&dsc$tstamp,&(ihi$->IHI$Q_LINKTIME),0,&i,0);
	    *(dsc$tstamp.dsc$a_pointer + i) = '\0';
	    if ((*dsc$tstamp.dsc$a_pointer) == ' ')
		memmove(dsc$tstamp.dsc$a_pointer,dsc$tstamp.dsc$a_pointer+1,
								i-1);
	    GSsetTitle(gs,path);    GDaddGS(gd, gs);
	    strcpy(path,"Linker ID:     \"");
	    strncat(path,ihi$->IHI$T_LINKID+1,ihi$->IHI$T_LINKID[0]);
	    strcat(path, "\"");
	    GSsetTitle(gs,path);    GDaddGS(gd, gs);
	}
	fclose(fp);
    }
    if (SS$_NORMAL!=SYS$GETSYIW(0,0,0,itmlist,0,0,0))
	GSsetType(gs, A_ERROR);
    else {
	path[120+i] = '\0';
	for (i=107; path[i]==' '; path[i--] = '\0');
	str_tolower(&path[100]);
	sprintf(path, "Host System:    %s, VMS %s",&path[120],&path[100]);
	GSsetTitle(gs,path);
	GDaddGS(gd, gs);
    }


    if (GSgetType(gs)==A_ERROR)
	LOGGopher(sockfd,"Could not report version information");
    else
	LOGGopher(sockfd,"Reported version");

#ifdef MULTINET
#define TCPIP_AGENT   "TGV Multinet"
#endif
#ifdef UCX
#define TCPIP_AGENT   "UCX"
#endif
#ifdef WOLLONGONG
#define TCPIP_AGENT   "Wollongong"
#endif
#ifdef TCPIP_AGENT
    sprintf(path, "TCP/IP agent:   %s", TCPIP_AGENT);
    GSsetTitle(gs,path);    
    GDaddGS(gd, gs);
#endif

    sprintf(path, "Revision Level: %s-%s", GOPHERD_VERSION, PATCH_LEVEL);
    GSsetTitle(gs, path);    
    GDaddGS(gd, gs);

    if (Connections) {
	started = ctime(&ServerStarted);
	*(started+24) = '\0';
	VCFG("Server Started: %s", started);
	VCFG("Connections:    %d", Connections);
	VCFG("Connects/Hr:    %d", connperhour);
	VCFG("Concurrent:     %d", ActiveSessions);
    }

    GSsetType(gs, A_DIRECTORY);
    sprintf(path,"%c%s", A_DIRECTORY, GDCgetDatadir(Config));
    GSsetPath(gs,path);
    VCFG("DataDirectory:  %s", IFAVAIL(GDCgetDatadir(Config)));
    GSsetType(gs, A_FILE);
    sprintf(path,"%c%s", A_FILE, GDCgetConfig(Config));
    if (cp=strchr(path,';'))
	*cp = '\0';
    GSsetPath(gs,path);
    strcpy (image, path+1);
    VCFG("ConfigFile:     %s", IFAVAIL(image));
    VCFG("HostAlias:      %s", IFAVAIL(GDCgetHostname(Config)));
    VCFG("Port:           %d", GDCgetPort(Config));
    VCFG("Site:           %s", IFAVAIL(GDCgetSite(Config)));
    VCFG("Abstract:       %s", IFAVAIL(GDCgetAbstract(Config)));
    VCFG("Admin:          %s", IFAVAIL(GDCgetAdmin(Config)));
    VCFG("AdminEmail:     %s", IFAVAIL(GDCgetAdminEmail(Config)));
    VCFG("Org:            %s", IFAVAIL(GDCgetOrg(Config)));
    VCFG("Loc:            %s", IFAVAIL(GDCgetLoc(Config)));
    VCFG("Lang:           %s", IFAVAIL(GDCgetLang(Config)));
    VCFG("Geog:           %s", IFAVAIL(GDCgetGeog(Config)));
    if (GDCgetTZ(Config)==-1)
	VCFG("TimeZone:       %s", GDCgetTimeZone(Config))
    else
	VCFG("TimeZone:       %d", GDCgetTZ(Config));
    VCFG("ReadTimeout:    %d", GDCgetReadTimeout(Config));
    if (GDCgetOPCOM(Config)==0)
        VCFG("Console:        %s", "None")
    else {
	int opc = GDCgetOPCOM(Config);
	int ox;
	String *cbuf = STRnew();
	for (ox=0; ox<vms_OPC$M_num; ox++) {
	    if (opc & vms_OPC$M_NM[ox]) {
		if (STRlen(cbuf))
		    STRcat(cbuf,"+");
		STRcat(cbuf, vms_OPC$M_TXT[ox]);
	    }
	}
	VCFG("Console:        %s", STRget(cbuf));
	STRdestroy(cbuf);
    }
    VCFG("InetD:          %s", GDCgetInetdActive(Config)==TRUE?"TRUE":"FALSE");
    VCFG("IgnoreAll:      %s", GDCgetIgnoreAll(Config)==TRUE?"TRUE":"FALSE");
    VCFG("IsGPlus:        %s", GDCgetIsGplus(Config)==TRUE?"TRUE":"FALSE");
    VCFG("SortDir:        %s", GDCgetSortDir(Config)==TRUE?"TRUE":"FALSE");
    if (!GDCgetFTPPort(Config))
	VCFG("FTPPort:        %s", "NONE")
    else
	VCFG("FTPPort:        %d", GDCgetFTPPort(Config));
    if (!GDCgetEXECPort(Config))
	VCFG("EXECPort:       %s", "NONE")
    else
	VCFG("EXECPort:       %d", GDCgetEXECPort(Config));
    if (!GDCgetSRCHPort(Config))
	VCFG("SRCHPort:       %s", "NONE")
    else
	VCFG("SRCHPort:       %d", GDCgetSRCHPort(Config));
    if (!GDCgetOVERPort(Config) || (GDCgetOVERSize(Config)==-1))
	VCFG("OVERPort:       %s", "NONE")
    else
	VCFG2("OVERPort:       %d, %d", GDCgetOVERPort(Config),
					    GDCgetOVERSize(Config));
    VCFG("SortGREP:       %s", GDCgetSortGREP(Config)==TRUE?"TRUE":"FALSE");
    VCFG("SortCMD1:       %s", GDCgetSortCMD1(Config)==TRUE?"TRUE":"FALSE");
    VCFG("SortShell:      %s", GDCgetSortShell(Config)==TRUE?"TRUE":"FALSE");
    VCFG("Veronica:       %s", GDCgetShouldIndex(Config)==TRUE?"TRUE":"FALSE");
    VCFG("Cache:          %s", GDCgetCaching(Config)==TRUE?"TRUE":"FALSE");
    if (GDCgetCaching(Config))
	VCFG("CacheTime:          %d", GDCgetCachetime(Config));
    VCFG("MaxLoad:        %g", GDCgetMaxLoad(Config));
    VCFG("MaxConnections: %d", GDCgetMaxconns(Config));
    VCFG("Do_chroot:      %s", GDCgetchroot(Config)==TRUE?"TRUE":"FALSE");
    VCFG("BummerMsg:      %s%s%s", IFAVAILQ(GDCgetBummerMsg(Config)));
    VCFG("DName:          %s%s%s", IFAVAILQ(GDCgetDName(Config)));
    VCFG("DHead:          %s%s%s", IFAVAILQ(GDCgetDHead(Config)));
    VCFG("DFoot:          %s%s%s", IFAVAILQ(GDCgetDFoot(Config)));
    VCFG("Hidden:         %s%s%s", IFAVAILQ(GDCgetHiddenPrefix(Config)));
    VCFG("Link:           %s%s%s", IFAVAILQ(GDCgetLinkPrefix(Config)));
    VCFG("Lookaside:      %s%s%s", IFAVAILQ(GDCgetLookAside(Config)));
    VCFG("Restart:        %s", IFAVAIL(GDCgetRestart(Config)));
    GSsetType(gs,A_FILE);
    if (Config->Securityon) {
	int i;
	Site *temp;
	VCFG("Security:       %s", "ON");
	VCFG2("Access:         %s: %s", "default", 
			    AccessLevelText(Config->Defaccess,0));
	for (i=0; i< DAgetTop(Config->Sites); i++) {
	    temp = SiteArrgetEntry(Config->Sites,i);
	    VCFG2("Access:         %s: %s", STRget(temp->domain), 
			    AccessLevelText(temp->Level,temp->maxsessions));
	}
	
	if (Config->Authroutines || Config->Authitems || Config->Serverpw
		|| Config->Tixfile) {
	    /*	Need to provide for an Authorizations routine dump  */
	}
    }
    if (Config->Extensions) {
	/* Need to provide for an extensions dump yet */
    }
    if (Config->other_dirs) {
	/* Need to provide for an other_dirs dump yet */
    }
    if (Config->other_gdcs) {
	/* Need to provide for an other_gdcs dump yet */
    }
    if (Config->FileSeparators) {
	/* Need to provide for a FileSeparators dump yet */
    }
    if (Config->BlkScriptBlocks) {
	/* Need to provide for a BlkScriptBlocks dump yet */
    }
    if (Config->BlkScripts) {
	/* Need to provide for a BlkScripts dump yet */
    }
    if (strcasecmp(GDCgetLogfile(Config),"syslog")==0) {
	path[0] = A_FILE;	/*  Kind of tough to display the syslog */
	path[1] = '\0';
    }
    else
	sprintf(path,"%c%s", A_FILE, GDCgetLogfile(Config));
    GSsetType(gs,A_FILE);
    if (strlen(path)>1) {
	GSsetPath(gs,path);
    }
    else 
	GSsetPath(gs,BummerMsg);
    VCFG("LogFile:        %s", IFAVAIL(GDCgetLogfile(Config)));
    x =  "Rollover:       %s";
    switch(GDCgetRollover(Config)) {
    case ROLLOVER_DAILY:    VCFG(x,"DAILY");	    break;
    case ROLLOVER_HOURLY:   VCFG(x,"HOURLY");	    break;
    case ROLLOVER_MONTHLY:  VCFG(x,"MONTHLY");	    break;
    case ROLLOVER_ANNUALLY: VCFG(x,"ANNUALLY");	    break;
    case ROLLOVER_WEEKLY:   VCFG(x,"WEEKLY");	    break;
    case ROLLOVER_NEVER:    
    default:		    VCFG(x,"NEVER");	
    }
    VCFG("LogTag:         %s", IFAVAIL(GDCgetLogTag(Config)));
    sprintf(path,"%c%s", A_FILE, GDCgetErrorfile(Config));
    if (strlen(path)>1)
	GSsetPath(gs,path);
    else
	GSsetPath(gs,NoSuchFile);
    VCFG("ErrorFile:      %s", IFAVAIL(GDCgetErrorfile(Config)));
    sprintf(path,"%c%s", A_DIRECTORY, GDCgetScratchDir(Config));
    if (strlen(path)>1) {
	GSsetPath(gs,path);
	GSsetType(gs,A_DIRECTORY);
    }
    else {
	GSsetPath(gs,BummerMsg);
	GSsetType(gs,A_FILE);
    }
    VCFG("ScratchDir:     %s", IFAVAIL(GDCgetScratchDir(Config)));
    GSsetType(gs, A_FILE);
    sprintf(path,"%c%s", A_FILE, GDCgetSpawnInit(Config));
    if (strlen(path)>1)
	GSsetPath(gs,path);
    else
	GSsetPath(gs,NoSuchFile);
    VCFG("SpawnInit:      %s", IFAVAIL(GDCgetSpawnInit(Config)));
    sprintf(path,"%c%s", A_DIRECTORY, GDCgetSupportDir(Config));
    if (strlen(path)>1) {
	GSsetPath(gs,path);
        GSsetType(gs,A_DIRECTORY);
    }
    else {
	GSsetPath(gs,BummerMsg);
	GSsetType(gs,A_FILE);
    }
    VCFG("SupportDir:     %s", IFAVAIL(GDCgetSupportDir(Config)));
}

/**
 *	Kaboom() causes the server to ACCVIO if, and only if, the environment
 *	    variables (that is, symbols or logicals) named GOPHERD_KABOOM_HOST
 *	    and GOPHERD_KABOOM_CLIENT match (case insensitive) the host name
 *	    this server is using and the client peer *name* making the pseudo-
 *	    search request.  Otherwise reports that the request is denied.
 **/
void
Kaboom(int sockfd, GopherObj *gs, GopherDirObj *gd)
{
    char BoomBoom[256];
    char *cp;
    void (*Die)() = NULL;

    GSsetDefaults(gs);
    GSsetType(gs, A_INFO);
    GSsetPath(gs, "");
    sprintf(BoomBoom, "KaBOOM denied on %s for %s",
			    GDCgetHostname(Config), CurrentPeerName);
    GSsetTitle(gs, BoomBoom);
    GDaddGS(gd, gs);
    if (cp = getenv("GOPHERD_KABOOM_HOST")) {
	if (strcasecmp(cp, GDCgetHostname(Config)))
	    return;
	if (cp = getenv("GOPHERD_KABOOM_CLIENT"))
	    if (strcasecmp(cp, CurrentPeerName))
		return;
    }
    if (cp) {
	LOGGopher(sockfd,"KaBOOM authorized!  BOOM!");
	Die();
    }
}

void
CreateGO4link(GopherObj *gs, GopherDirObj *gd, char *GO4Site)
{
    char GO4buf[256], *cp;

    GSsetType(gs, A_DIRECTORY);
    if (cp=strchr(GO4Site,' ')) {
	*cp = '\0';
	GSsetPort(gs,atoi(++cp));
    }
    else
	GSsetPort(gs,70);   /* Hard coded since that's the Gopher standard,
				and we have to take a guess here */
    GSsetHost(gs, GO4Site);
    GSsetPath(gs, "");
    bzero(GO4buf, sizeof(GO4buf));
    sprintf(GO4buf, "Link to Gopher host %s on port %d",
			GO4Site, GSgetPort(gs));
    GSsetTitle(gs, GO4buf);
    GDaddGS(gd, gs);
}

void
CreateFTPlink(GopherObj *gs, GopherDirObj *gd, char *FTPSite)
{
    char ftpbuf[256], *cp;

    bzero(ftpbuf, sizeof(ftpbuf));
    sprintf(ftpbuf, "%cftp:%s@/", A_DIRECTORY, FTPSite);
    GSsetType(gs, ftpbuf[0]);
    GSsetPath(gs, ftpbuf+1);
    cp = ftpbuf + strlen(ftpbuf);
    strcat(ftpbuf, "Link to aFTP host ");
    strcat(ftpbuf, FTPSite);
    GSsetTitle(gs, cp);
    GDaddGS(gd, gs);
}

void
CreateEXElink(GopherObj *gs, GopherDirObj *gd, char *EXECargs, char EXECtype,
					char *EXECfile)
{
    char exebuf[256], *cp;

    bzero(exebuf, sizeof(exebuf));
    sprintf(exebuf, "%cexec:%s:%s", EXECtype, EXECargs, EXECfile);
    GSsetType(gs, exebuf[0]);
    GSsetPath(gs, exebuf+1);
    cp = exebuf + strlen(exebuf);
    strcat(exebuf, "Execute script with arguments ");
    strcat(exebuf, EXECargs);
    GSsetTitle(gs, cp);
    GDaddGS(gd, gs);
}

/*
 *  *date locates a date specification.  Make sure that's what it is, and
 *  return TRUE or FALSE.
 */
boolean
Validate_Date(char *date)
{
    int	status;
    char quadword[8];
    $DESCRIPTOR(dsc$date,"");
    long flags = 0x7f;
    if (date==NULL)
	return(FALSE);
    dsc$date.dsc$a_pointer = date;
    dsc$date.dsc$w_length = strlen(date);
    status = LIB$CONVERT_DATE_STRING(&dsc$date, quadword,0,&flags,0,0);
    if ((status &1)!=1)
	return(FALSE);
    return(TRUE);
}
#endif
.
Response: text/plain
Original URLgopher://bitreich.org/0/gopher2007/2007-gopher-mirror/gop...
Content-Typetext/plain; charset=utf-8