/
2.0.4beta/doc/
2.0.4beta/gnu/
2.0.4beta/sha/
/* help.c */

#include "config.h"

/*
 *		       This file is part of TeenyMUD II.
 *		 Copyright(C) 1993, 1994, 1995 by Jason Downs.
 *                           All rights reserved.
 * 
 * TeenyMUD II is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * TeenyMUD II is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (see the file 'COPYING'); if not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA.
 *
 */

#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif			/* HAVE_STRING_H */
#include <ctype.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif			/* HAVE_SYS_TIME_H */
#include <sys/stat.h>

#include "conf.h"
#include "teeny.h"
#include "commands.h"
#include "externs.h"

#include "hash/hash.h"

/*
 * The TeenyMUD help system is implemented by scanning the file(s) and
 * building an associative array (hash table), resolving subjects to
 * file offsets.  It hadles both ``old fashioned'' 32bit offsets, and
 * newer, large, file offsets.
 *
 * The table(s) are rebuilt automatically, if the time stamp on the file(s)
 * change.
 */

static Hash_Table HelpTable;
static Hash_Table NewsTable;
static int HelpTableInited = 0;
static int NewsTableInited = 0;
static char buffer[128];
static struct stat sbuf;
static char *Mod_Entry = "FMODTIME";

static void init_table _ANSI_ARGS_((FILE *, Hash_Table *));
static void free_help _ANSI_ARGS_((Hash_Table *));

static void init_table(fd, table)
    FILE *fd;
    Hash_Table *table;
{
  register char *p;
  Hash_Entry *hash;
  int new;
#if (SIZEOF_OFF_T > SIZEOF_INT_P)
  register int *offset;
  off_t where;
#endif

  Hash_InitTable(table, 0, HASH_STRCASE_KEYS);
  while (!feof(fd) && (fgets(buffer, sizeof(buffer), fd) != NULL)) {
    if ((buffer[0] == '&') && buffer[1]) {
      remove_newline(buffer);
      for (p = buffer; p[0] && !isspace(p[0]); p++);
      for (; p[0] && isspace(p[0]); p++);
      if (!p[0])
	continue;
      hash = Hash_CreateEntry(table, p, &new);

#if (SIZEOF_OFF_T > SIZEOF_INT_P)
      offset = (int *)ty_malloc(sizeof(off_t), "init_table");
      where = ftell(fd);
      bcopy((VOID *)&where, (VOID *)offset, sizeof(off_t));
      Hash_SetValue(hash, offset);
#else
      Hash_SetValue(hash, (int *) ftell(fd));
#endif
    }
  }
}

void help_init()
{
  Hash_Entry *hash;
  int new;
  FILE *fd;

  if (!HelpTableInited) {
    if ((stat(mudconf.help_file, &sbuf) != 0) ||
	((fd = fopen(mudconf.help_file, "r")) == NULL)) {
      logfile(LOG_ERROR, "help_init: couldn't open help file, %s\n",
	      mudconf.help_file);
    } else {
      init_table(fd, &HelpTable);
      fclose(fd);
      HelpTableInited = 1;
      hash = Hash_CreateEntry(&HelpTable, Mod_Entry, &new);
      Hash_SetValue(hash, (int *) sbuf.st_mtime);
    }
  }
  if (!NewsTableInited) {
    if ((stat(mudconf.news_file, &sbuf) != 0) ||
	((fd = fopen(mudconf.news_file, "r")) == NULL)) {
      logfile(LOG_ERROR, "help_init: couldn't open news file, %s\n",
	      mudconf.news_file);
    } else {
      init_table(fd, &NewsTable);
      fclose(fd);
      NewsTableInited = 1;
      hash = Hash_CreateEntry(&NewsTable, Mod_Entry, &new);
      Hash_SetValue(hash, (int *) sbuf.st_mtime);
    }
  }
}

static void free_help(table)
    Hash_Table *table;
{
#if (SIZEOF_OFF_T > SIZEOF_INT_P)
  Hash_Entry *entry;
  Hash_Search srch;

  for(entry = Hash_EnumFirst(table, &srch); entry != (Hash_Entry *)NULL;
      entry = Hash_EnumNext(&srch)) {
    ty_free((VOID *)Hash_GetValue(entry));
  }
#endif
  Hash_DeleteTable(table);
}

VOID do_help(player, cause, switches, argone)
    int player, cause, switches;
    char *argone;
{
  FILE *fd;
  Hash_Entry *hash;
  time_t last;
  char buf[MEDBUFFSIZ];
  char *topic;
#if (SIZEOF_OFF_T > SIZEOF_INT_P)
  register off_t *optr;
#endif
  int err;

  if (switches & HELP_RELOAD) {
    HelpTableInited = 0;
    free_help(&HelpTable);
    help_init();

    if (!(switches & CMD_QUIET))
      notify_player(player, cause, player, "Help file reloaded.", NOT_QUIET);
    return;
  }

  if ((argone == (char *)NULL) || (argone[0] == '\0')
      || strcmp(argone, Mod_Entry) == 0)
    topic = "summary";
  else
    topic = argone;

  if (!HelpTableInited || mudconf.hfile_autoload) {
    err = ((stat(mudconf.help_file, &sbuf) != 0) ||
    	   (fd = fopen(mudconf.help_file, "r")) == NULL);
  } else {
    err = ((fd = fopen(mudconf.help_file, "r")) == NULL);
  }

  if (err) {
    if(!(switches & CMD_QUIET)) {
      snprintf(buf, sizeof(buf), "Sorry, %s seems to be broken.",
	       mudconf.help_file);
      notify_player(player, cause, player, buf, NOT_QUIET);
    }
    return;
  }
  if (!HelpTableInited
      || ((hash = Hash_FindEntry(&HelpTable, Mod_Entry)) == NULL)) {
    help_init();
    last = sbuf.st_mtime;
  } else {
    last = (time_t) Hash_GetValue(hash);
  }
  if (mudconf.hfile_autoload) {
    if (sbuf.st_mtime > last) {
      HelpTableInited = 0;
      free_help(&HelpTable);
      help_init();
    }
  }

  if (strcasecmp(topic, "-summary") == 0) {
    Hash_Search srch;

    for(hash = Hash_EnumFirst(&HelpTable, &srch); hash != NULL;
        hash = Hash_EnumNext(&srch))
      notify_player(player, cause, player, Hash_GetKey(&HelpTable, hash), 0);
    return;
  }
  if ((hash = Hash_FindEntry(&HelpTable, topic)) == NULL) {
    if(!(switches & CMD_QUIET)) {
      snprintf(buf, sizeof(buf), "No help available for %s.", topic);
      notify_player(player, cause, player, buf, NOT_QUIET);
    }
    fclose(fd);
    return;
  }

#if (SIZEOF_OFF_T > SIZEOF_INT_P)
  optr = (off_t *)Hash_GetValue(hash);
  fseek(fd, *optr, 0);
#else
  fseek(fd, (off_t) Hash_GetValue(hash), 0);
#endif
  while (!feof(fd) && (fgets(buffer, sizeof(buffer), fd) != NULL)) {
    if (!strncmp(buffer, "@@@@", 4))
      break;
    if (buffer[0] != '&') {
      remove_newline(buffer);
      notify_player(player, cause, player, (buffer[0]) ? buffer : " ", 0);
    }
  }
  fclose(fd);
}

VOID do_news(player, cause, switches, argone)
    int player, cause, switches;
    char *argone;
{
  FILE *fd;
  Hash_Entry *hash;
  time_t last;
  char buf[MEDBUFFSIZ];
  char *topic;
#if (SIZEOF_OFF_T > SIZEOF_INT_P)
  register off_t *optr;
#endif
  int err;

  if (switches & NEWS_RELOAD) {
    NewsTableInited = 0;
    free_help(&NewsTable);
    help_init();

    if (!(switches & CMD_QUIET))
      notify_player(player, cause, player, "News file reloaded.", NOT_QUIET);
    return;
  }

  if ((argone == (char *)NULL) || (argone[0] == '\0')
      || strcmp(argone, Mod_Entry) == 0)
    topic = "summary";
  else
    topic = argone;

  if (!NewsTableInited || mudconf.hfile_autoload) {
    err = ((stat(mudconf.news_file, &sbuf) != 0)
    	   || (fd = fopen(mudconf.news_file, "r")) == NULL);
  } else {
    err = ((fd = fopen(mudconf.news_file, "r")) == NULL);
  }

  if (err) {
    if(!(switches & CMD_QUIET)) {
      snprintf(buf, sizeof(buf), "Sorry, %s seems to be broken.",
	       mudconf.news_file);
      notify_player(player, cause, player, buf, NOT_QUIET);
    }
    return;
  }
  if (!NewsTableInited
      || ((hash = Hash_FindEntry(&NewsTable, Mod_Entry)) == NULL)) {
    help_init();
    last = sbuf.st_mtime;
  } else {
    last = (time_t) Hash_GetValue(hash);
  }
  if (mudconf.hfile_autoload) {
    if (sbuf.st_mtime > last) {
      NewsTableInited = 0;
      free_help(&NewsTable);
      help_init();
    }
  }

  if (strcasecmp(topic, "-summary") == 0) {
    Hash_Search srch;

    for(hash = Hash_EnumFirst(&NewsTable, &srch); hash != NULL;
        hash = Hash_EnumNext(&srch))
      notify_player(player, cause, player, Hash_GetKey(&NewsTable, hash), 0);
    return;
  }
  if ((hash = Hash_FindEntry(&NewsTable, topic)) == NULL) {
    if(!(switches & CMD_QUIET)) {
      snprintf(buf, sizeof(buf), "No news available for %s.", topic);
      notify_player(player, cause, player, buf, NOT_QUIET);
    }
    fclose(fd);
    return;
  }

#if (SIZEOF_OFF_T > SIZEOF_INT_P)
  optr = (off_t *)Hash_GetValue(hash);
  fseek(fd, *optr, 0);
#else
  fseek(fd, (off_t) Hash_GetValue(hash), 0);
#endif
  while (!feof(fd) && (fgets(buffer, sizeof(buffer), fd) != NULL)) {
    if (!strncmp(buffer, "@@@@", 4))
      break;
    if (buffer[0] != '&') {
      remove_newline(buffer);
      notify_player(player, cause, player, (buffer[0]) ? buffer : " ", 0);
    }
  }
  fclose(fd);
}

/*
 * Display the news file last modification time to a player.
 */
void check_news(player)
    int player;
{
  char buf[MEDBUFFSIZ];

  if (stat(mudconf.news_file, &sbuf) == 0) {
    strftime(buf, BUFFSIZ,
	     "News file last updated: %a %b %e %H:%M:%S %Z %Y",
	     localtime(&sbuf.st_mtime));

    notify_player(player, player, player, buf, 0);
  }
}