/*
 * rpcd.c: main routines for Sun RPC-based webster server.
 * Copyright 1988 by the Massachusetts Institute of Technology.
 * All rights reserved.
 *
 * $Source: /mit/jik/sipbsrc/rt/webster/src/server/RCS/rpcd.c,v $
 * $Header: /mit/jik/sipbsrc/rt/webster/src/server/RCS/rpcd.c,v 1.8 1992/03/31 00:52:38 jik Exp $
 * $Author: jik $
 * 
 */

#ifndef lint
static char	rcsid_rpcd_c[] = "$Header: /mit/jik/sipbsrc/rt/webster/src/server/RCS/rpcd.c,v 1.8 1992/03/31 00:52:38 jik Exp $";
#endif lint

#ifdef SUNRPC

#include <stdio.h>
#include <dbm.h>
#include <syslog.h>
#include <rpc/rpc.h>
#include <sys/file.h>
#include <index.h>	
#include <webster.h>
#include <wordfiles.h>
#include <sunrpcweb.h>
#include <string.h>
#ifdef APRIL_FOOL
#include <sys/types.h>
#include <sys/signal.h>
#include <time.h>
#endif

char	*webster();
char	*dispatch();
extern bool_t xdr_longstring();
extern char	*malloc(), *realloc();

/*
 * globals used in creating our return message: a definition, or an
 * error message.
 */
int	howlong = 0;
int	maxdeflen = 0;
char	*curptr = (char *)NULL;
char	*curstash = (char *)NULL;
#ifdef APRIL_FOOL
int	april_fool = 0, fool_toggled = 0;
int	check_fool();
int	toggle_fool();
#endif

/* pointer we return from webster() */
static char	*reply = (char *)NULL;
char	*whoami;

FILE *indexfp;				/* index file pointer		*/
struct header hdr;			/* index file header		*/

#define NUMWORDS 50			/* one more than the number of
					 * words allowed in a phrase
					 * to be defined.
					 */ 
main(argc, argv)
int	argc;
char	**argv;
{

	/* open the logfile */
#ifdef ultrix /* or other 4.2 monstrosity */
	openlog("websterd", LOG_PID);
#else /* !ultrix */
	openlog("websterd", LOG_PID, LOG_LOCAL5);
#endif /* !ultrix */

#ifdef APRIL_FOOL
	check_fool();
	signal(SIGALRM, check_fool);
	signal(SIGUSR2,  toggle_fool);
#endif

	if ((whoami = rindex(argv[0], '/')) == (char *) NULL)
		whoami = argv[0];
	else
		whoami++;

	/* open the database */
	loadindex();

	/* tell the rpcd about us */
	registerrpc(WEBPROG, WEBVERS, WEBSTER, webster, xdr_longstring,
	     xdr_longstring);

	/* go! */
	svc_run();	/* never exits; fine with me */
}

char	*
webster(command)
char	**command;
{
	int	argcount;
	char	*args[NUMWORDS];

	/* Clean up after previous calls */
	if (reply)
		free(reply);

	/* Clean up the line. */
	clean(*command);

	/* Split the line into words. */
	split(*command, args, &argcount);

	/* Dispatch the command. */
	reply = dispatch(argcount, args);
	return (char *) & reply;
}

/*
 * dispatch - dispatch the command to the right routine.
 */
char	*
dispatch(argcount, args)
int	argcount;
char	**args;
{
	extern char	*define();
	extern char	*complete();
	extern char	*endings();
	extern char	*spell();
	extern char	*help();
	char	*error();

	if (!strcmp(*args, "DEFINE"))
		return(define(argcount, args));

	if (!strcmp(*args, "COMPLETE"))
		return(complete(argcount, args));

	if (!strcmp(*args, "ENDINGS"))
		return(endings(argcount, args));

	if (!strcmp(*args, "SPELL"))
		return(spell(argcount, args));

	if (!strcmp(*args, "HELP"))
		return(help(argcount, args));

	return(error(0, "Unknown command: %s", *args));
}

/*
 * error - returns an error message.
 */
char	*
error(fatal, s, arg)
int	fatal;
char	*s, *arg;
{
	char	buf[BUFSIZ];

	if (fatal)
		addtodef("ERROR FATAL");
	else
		addtodef("ERROR RECOVERABLE");

	(void) sprintf(buf, s, arg);
	addtodef(buf);
	addctodef('\n');

	/* null-terminate the error message */
	*curptr++ = '\0';
	/* reset the bounds so that we're clean next time */
	howlong = maxdeflen = 0;

	/* return it */
	return(curstash);
}

/*
 * clean - clean up a string.
 */
clean(s)
register char	*s;
{
	for (; *s != '\0'; s++) {
#ifdef USASCII
		*s &= 0177;
#endif
		if ((*s == '\r') || (*s == '\n'))
			*s = '\0';
	}
}

/*
 * split - turn s into separate word arguments.
 */
split(s, args, argcount)
register char	*s;
char	**args;
int	*argcount;
{
	*argcount = 0;

	/*
	 * Don't fall off the end of args.
	 */
	while (*s) {
		while ((*s != NULL) && ((*s == ' ') || (*s == '\t')))
			*s++ = NULL;

		if ((*argcount == NUMWORDS) || (*s == NULL))
			break;

		args[(*argcount)++] = s;

		while ((*s != NULL) && (*s != ' ') && (*s != '\t'))
			s++;
	}
	*s = NULL;
	args[*argcount] = NULL;
}

/* haswild - check for wildcard characters. */
haswild(s)
register char	*s;
{
	while (*s) {
		if ((*s == ONECH) || (*s == MANYCH))
			return(1);
		s++;
	}

	return(0);
}

/* isnumber - see if s is a number. */
isnumber(s)
register char	*s;
{
	while (*s) {
		if ((*s < '0') || (*s > '9'))
			return(0);
		s++;
	}

	return(1);
}

/*
 * loadindex - read in the index file header, open the database.
 */
loadindex()
{
	FILE * fp;
	char	buf[BUFSIZ];

	/*
	 * Header.
	 */
	(void) sprintf(buf, "%s/%s", wordfiledir, wordfilehdr);

	if ((fp = fopen(buf, "r")) == NULL) {
		syslog(LOG_ERR, "cannot open \"%s\".", buf);
		exit(1);
	}

	if (fread((char *) & hdr, sizeof(struct header ), 1, fp) == 0) {
		syslog(LOG_ERR, "bad hdr read from \"%s\".", buf);
		exit(1);
	}

	if (fclose(fp) == EOF)
		syslog(LOG_ERR, "cannot close \"%s\".", buf);

	/*
	 * Index file.
	 */
	(void) sprintf(buf, "%s/%s", wordfiledir, wordfileindex);

	if ((indexfp = fopen(buf, "r")) == NULL) {
		syslog(LOG_ERR, "cannot open \"%s\".", buf);
		exit(1);
	}

	/*
	 * Database.
	 */
	if (dbminit(buf) < 0) {
		syslog(LOG_ERR, "cannot open index database.");
		exit(1);
	}
}

#ifdef APRIL_FOOL
check_fool()
{
     time_t t;
     struct tm *loctime;

     (void) time(&t);
     loctime = localtime(&t);

     if ((loctime->tm_mon == 3) && (loctime->tm_mday == 1)) {
	  april_fool = (1 | fool_toggled);
     }
     else {
	  april_fool = (0 | fool_toggled);
     }

     alarm(60, check_fool);
}

toggle_fool()
{
     fool_toggled = !fool_toggled;
     check_fool();
}
#endif
     
#endif SUNRPC
