pdirt/data/
pdirt/data/HELP/
pdirt/data/HELP/0/
pdirt/data/HELP/F/
pdirt/data/HELP/G/
pdirt/data/HELP/H/
pdirt/data/HELP/J/
pdirt/data/HELP/K/
pdirt/data/HELP/O/
pdirt/data/HELP/Q/
pdirt/data/HELP/R/
pdirt/data/HELP/U/
pdirt/data/HELP/V/
pdirt/data/HELP/Y/
pdirt/data/HELP/Z/
pdirt/data/MESSAGES/
pdirt/data/POWERINFO/
pdirt/data/WIZ_ZONES/
pdirt/drv/
pdirt/drv/bin/
pdirt/drv/compiler/converter/
pdirt/drv/compiler/libs/
pdirt/drv/compiler/scripts/
pdirt/drv/include/AberChat/
pdirt/drv/include/InterMud/
pdirt/drv/include/machine/
pdirt/drv/src/InterMud/
pdirt/drv/src/Players/
pdirt/drv/utils/UAFPort/
pdirt/drv/utils/dnsresolv/
pdirt/drv/utils/gdbm/
/**************************************************************************
 ** Module: uaf.c
 ** Author: Various Aber coders
 ** Description: This module holds all the functions to handle the database
 **              which holds the players data. (uaf_rand).
 **************************************************************************/
#define UAF_C

#include <sys/file.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "kernel.h"
#include <errno.h>
#include <gdbm.h>
#include "machines.h"
#include "pflags.h"
#include "sflags.h"
#include "uaf.h"
#include "bprintf.h"
#include "log.h"
#include "mobile.h"
#include "mud.h"
#include "wizlist.h"
#include "flags.h"
#include "bootstrap.h"
#include "commands.h"
#include "sendsys.h"
#include "rooms.h"

GDBM_FILE dbf;
extern int errno;
extern char *WizLevels[];


void get_gender (char *gen);
time_t time (time_t * v);

void pers2player (PERSONA * d, int plx)
{
  setpstr (plx, d->p_strength);
  setpdam (plx, d->p_damage);
  setphome (plx, d->p_home[0] == '\0' ? 0 : findroomnum(d->p_home));
  setpscore (plx, d->p_score);
  setparmor (plx, d->p_armor);
  setsflags (plx, d->p_sflags);
  setpflags (plx, d->p_pflags);
  setpmask (plx, d->p_mask);
  qflags(plx) = d->p_quests;
  qpoints(plx) = d->p_questpoints;
  setpvis (plx, ptstflg (plx, PFL_STARTINVIS) ? d->p_vlevel : 0);
  setplev (plx, d->p_level);
  setpkilled(plx, d->p_killed);
  setpdied(plx,d->p_died);
  /* Fix score for people who died */
  if (d->p_strength < 0)
      setpstr(plx, pmaxstrength(d->p_level));
  setpwimpy (plx, d->p_wimpy);
  mob_id (plx) = d->p_id;
  if (plx < max_players)
    {
      setptitle (plx, d->p_title);
      players[plx].last_cmd = players[plx].last_command = global_clock;
      (void) strcpy(players[plx].email, d->p_email);
      (void) strcpy (players[plx].passwd, d->p_passwd);
      (void) strcpy (players[plx].prompt, d->p_prompt);
      (void) strcpy (players[plx].cprompt, d->p_prompt);
      setppager (plx,d->p_pager);
    }
}

void 
player2pers (PERSONA * d, time_t * last_on, int plx)
{
  d->p_strength = pstr (plx);
  d->p_damage = pdam (plx);
  d->p_score = pscore (plx);
  d->p_armor = parmor (plx);
  d->p_sflags = sflags (plx);
  d->p_quests = qflags(plx);
  d->p_questpoints = qpoints(plx);
  d->p_vlevel = pvis (plx);
  d->p_level = plev (plx);
  d->p_damage = pdam (plx);
  d->p_armor = parmor (plx);
  d->p_wimpy = pwimpy (plx);
  d->p_id = mob_id (plx);
  /* clear spare fields */
  d->spareint5 = 0;
  
  d->p_killed = pkilled(plx);
  d->p_died = pdied(plx);
  if (plx < max_players)
  {
      (void) strcpy (d->p_title, ptitle (plx));
      (void) strcpy (d->p_passwd, players[plx].passwd);
      (void) strcpy (d->p_email, pemail(plx));
      (void) strcpy (d->p_prompt, players[plx].prompt);
      d->p_pager = ppager(plx);
      d->p_pager = ppager(plx);
      d->p_pflags = (players[plx].defrob != NULL) ? players[plx].defrob->real_pflags : pflags (plx);
      d->p_mask   = (players[plx].defrob != NULL) ? players[plx].defrob->real_mask : pmask (plx);
      d->p_level = (players[plx].defrob != NULL) ? players[plx].defrob->real_level : plev (plx);
      (void) strcpy (d->p_idname, pname(plx));
      (void) strcpy (d->p_lasthost, players[plx].realhostname);
  }
  else
  {   d->p_pflags = pflags(plx);
      d->p_mask = pmask(plx);
      d->p_level = plev(plx);
  }
 
  (void) strcpy (d->p_home, phome(plx) >= 0 ? "" : showname(phome(plx)));
  (void) strcpy (d->p_name, pname (plx));
  if (last_on != NULL)
    d->p_last_on = *last_on;
}

void 
get_gender (char *gen)
{
  Boolean ok = False;
  Boolean female = False;
  PERSONA d;
  
  if (gen == NULL)
    {
      replace_input_handler (get_gender);
    }
  else if (*gen == 'M' || *gen == 'm')
    {
      sclrflg (mynum, SFL_FEMALE);
      ok = True;
    }
  else if (*gen == 'F' || *gen == 'f')
    {
      ssetflg (mynum, SFL_FEMALE);
      ok = female = True;
    }
  else
    {
      bprintf ("M or F");
    }
  if (ok)
    {
      /* initialize a very new user */
      if (OPERATOR (pname (mynum)))
	{
	  /* We make him a god */
          bprintf("\nWelcome MasterUser %s!\n",pname(mynum));
	  sprintf (ptitle (mynum), "%%s the %s", WizLevels[LEV_GOD]);
	  setplev (mynum, LVL_MASTER);
	  setpstr (mynum, pmaxstrength (LVL_MASTER));
	  setpscore (mynum, levels[LVL_APPREN]);
	  update_wizlist (pname (mynum), LEV_MASTER);
          strcpy(cur_player->cprompt,"&+wAdmin&+w>&* ");
	}
      else
	{
	  sprintf(ptitle(mynum), "%%s the %s",
		  (female ? FLevels: MLevels)[LVL_ONE]);
	  setplev(mynum, LVL_ONE);
	  setpstr(mynum, 40);
	  setpscore(mynum, 0);
          strcpy(cur_player->prompt, cur_player->cprompt);
	}
      setpwimpy (mynum, 0);
      cur_player->defrob = False;
      mob_id (mynum) = id_counter++;
      setphome (mynum, 0);
      setpdam (mynum, 8);
      setparmor (mynum, 0);
      setpvis (mynum, 0);
      sflags(mynum).b3 = sflags(mynum).b2 = sflags(mynum).b1 = 0;
      ssetflg(mynum,SFL_AUTOEXIT);
      ssetflg(mynum,SFL_SAYBACK);
      setppager(mynum,24);
      setpkilled(mynum,0);
      setpdied(mynum,0);

      if (female)
	ssetflg (mynum, SFL_FEMALE);

      qflags(mynum).l = qflags(mynum).h = 0;
      qpoints(mynum) = 0;
      pflags(mynum).b1 = pflags(mynum).b2 = pflags(mynum).b3 = 0;
      set_xpflags (plev (mynum), &(pflags (mynum)), &(pmask (mynum)));

      /* Reset the prompt before saving */
      strcpy(cur_player->prompt, cur_player->cprompt);
      player2pers (&d, &global_clock, mynum);
      putuaf (&d);

      save_id_counter ();
      give_options (NULL);
    }
  else
    {
      bprintf ("\n");
      bprintf (strcpy (cur_player->prompt, "Sex (M/F) : >"));
    }
}

/* Utilizing the save_player routine now */
A_COMMAND(saveme)
{
  if (cur_player->aliased || cur_player->polymorphed >= 0)
    {
      bprintf ("Not while aliased.\n");
      return;
    }
  save_player(mynum,False);
  bflush();
}


void save_player(int plx,Boolean UnAlias)
{  PERSONA d;
   
   if (plx <0)
      return;
      
   if (plx >= max_players || plx < 0)
   {  mudlog("ERROR: save_player() with invalid parameter.");
      return;
   }
   if (players[plx].aliased || players->polymorphed >= 0)
   {  if (UnAlias)
      {  unalias(plx);
         unpolymorph(plx);
         setup_globals(plx);
      }
   }
   player2pers(&d,&global_clock, plx);
   sendf(plx,"\n&+w[&+wSaving %s&+w]&*\n",pname(plx));
   putuaf(&d);
}

/* -------------------------------------------------------------------------*/


/*
 * Initialize userfile and keep it open
 */

void init_userfile()
{
 /* void (*mudlog)();*/
  
  if (dbf) return; /* already open */
#ifdef SAFE_USERFILE
  if ((dbf = gdbm_open(UAF_RAND,/*sizeof(PERSONA)*/ 1024,GDBM_WRCREAT,S_IRUSR|S_IWUSR,(void *)mudlog)) == NULL) {
#else
    if ((dbf = gdbm_open(UAF_RAND,/*sizeof(PERSONA)*/ 1024,GDBM_WRCREAT|GDBM_FAST,S_IRUSR|S_IWUSR,mudlog)) == NULL) {
#endif
      mudlog ("GDBM failed to access user file (%s)",UAF_RAND);
      exit (1);
    }
    return;
  }
  
  /*
   * sync userfile (safety for GDBM_FAST writes)
   */
  
  void sync_userfile()
    {
#ifndef SAFE_USERFILE /* no need if SAFE is on */
      if (dbf) gdbm_sync(dbf);
#endif
      return;
    }
  
  /*
   * reorganize userfile (at startup usually)
   */
  
  int reorg_userfile()
    {
      return(gdbm_reorganize(dbf));
    }
  
  
  void close_userfile()
    {
      
      if (dbf) gdbm_close(dbf);
      dbf = NULL;
    }
  
  
  Boolean getuaf (char *name, PERSONA * d)
    {
      datum in;
      datum key;
      datum data;
      char  idname[PNAME_LEN+1];	/* Lowercase version of the name */

      if (name == NULL || strlen(name) > PNAME_LEN)
          return False;
 
      strncpy(idname,name,PNAME_LEN); 	/* Potential crash bug if one tries
                                         * to copy more than 16 letters */
      idname[strlen(name)] = '\0';         
      key.dptr = idname;
      lowercase(key.dptr);
      key.dptr[0]=toupper(key.dptr[0]);
  /*    key.dsize = strlen(name) + 1;*/
      key.dsize = strlen(idname) + 1;
      data.dptr = (char *)d;
      data.dsize = sizeof(PERSONA) +1;
      
      if (!dbf) init_userfile();
      
      /* locate a user */
      in = gdbm_fetch(dbf,key);
      if (in.dptr == NULL) return (False);  /* no such entry */
      
      /* copy it to our given pointer */
      bcopy(in.dptr,d,sizeof(PERSONA));
      /*setpname(mynum,d->p_name);*/

      /* free the pointer */
      if (in.dptr) free(in.dptr);

      return (True);
      
    }
  
  
  /*
   * opens the userfile and writes a record to it; if the record exists,
   * it will replace it
   */
  
  void 
    putuaf (PERSONA * d)
      {
	int ret;
/*	PERSONA x;*/
	datum key;
	datum data;
	
	key.dptr = d->p_idname;
	lowercase(key.dptr);
	key.dptr[0]=toupper(key.dptr[0]);
	key.dsize = strlen(d->p_idname) + 1;
	data.dptr = (char *)d;
	data.dsize = sizeof(PERSONA) + 1;
	
	
	/* store the user */
	
	ret = gdbm_store(dbf,key,data,GDBM_REPLACE);
	switch(ret) {
	case 1:
	  mudlog("gdbm_store() - caller not official writer, or key or datum is null");
	  exit(1);
	  break;
	case -1:
	  mudlog("gdbm_store() - key exists and not allowed to replace.");
	  exit(1);
	  break;
	default:;
	}
	
	return;
      }
  
  void 
    deluaf (char *name)
      {
	int ret;
	datum key;
	
	
	key.dptr = name;
	lowercase(key.dptr);
	key.dptr[0]=toupper(key.dptr[0]);
	key.dsize = strlen(name) + 1;
	
	ret = gdbm_delete(dbf,key);
	
      }
  
  /*
   * Load the user's name as it appears in the database
   */
  
  Boolean getuafinfo (char *name)
    {
      PERSONA d;
      Boolean b;
      
      b = getuaf (name, &d);
      if (b)
	{
	  pers2player (&d, mynum);
	  setpname (mynum, d.p_name);
	}
      return b;
    }
  
  Boolean findsetins (char *name, SETIN_REC * s, int fd)
    {
      while (read (fd, s, sizeof (SETIN_REC)) == sizeof (SETIN_REC))
	if (EQ (s->name, name))
	  {
	    return True;
	  }
      return False;
    }
  
  Boolean getsetins (char *name, SETIN_REC * s)
    {
      int fd;
      Boolean b;
      
      if ((fd = open (SETIN_FILE, O_RDONLY, 0)) < 0)
	return False;
      
      b = findsetins (name, s, fd);
      close (fd);
      return b;
    }
  
  void 
    putsetins (char *name, SETIN_REC * s)
      {
	SETIN_REC v;
	int fd;
	Boolean b;
	
	if ((fd = open (SETIN_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0)
	  {
	    mudlog ("putsetins: Error in open for " SETIN_FILE);
	    progerror ("open");
	    exit (1);
	  }
	if ((b = findsetins (name, &v, fd)))
	  {
	    lseek (fd, (long) -sizeof (SETIN_REC), SEEK_CUR);
	  }
	else
	  {
	    lseek (fd, 0L, SEEK_END);
	  }
	if (write (fd, s, sizeof (SETIN_REC)) != sizeof (SETIN_REC))
	  {
	    mudlog ("putsetins: Error in write for " SETIN_FILE);
	    progerror ("write");
	  }
	lseek (fd, 0L, SEEK_END);
	close (fd);
      }
  
  void fetchprmpt (int plr)
    {
      SETIN_REC s;
      
      if (plr >= max_players || plr < 0)
	return;
      strcpy(players[plr].awaymsg,"Away Message lost in Reboot.");

      if (plev (plr) >= LVL_APPREN && getsetins (pname (plr), &s))
	{
	  /*strcpy (players[plr].prompt, s.prompt);*/
	  strcpy (players[plr].setin, s.setin);
	  strcpy (players[plr].setout, s.setout);
	  strcpy (players[plr].setmin, s.setmin);
	  strcpy (players[plr].setmout, s.setmout);
	  strcpy (players[plr].setvin, s.setvin);
	  strcpy (players[plr].setvout, s.setvout);
	  strcpy (players[plr].setqin, s.setqin);
	  strcpy (players[plr].setqout, s.setqout);
	  strcpy (players[plr].setsit, s.setsit);
	  strcpy (players[plr].setstand, s.setstand);
	  strcpy (players[plr].settrenter, s.settrenter);
	  strcpy (players[plr].settrvict, s.settrvict);
	  strcpy (players[plr].settrroom, s.settrroom);
          strcpy (players[plr].setsleep, s.setsleep);
          strcpy (players[plr].settrance, s.settrance);
          strcpy (players[plr].setaway, s.setaway);
	}
      else
	{
	  strcpy (players[plr].setin, "%n has arrived.");
	  strcpy (players[plr].setout, "%n has gone %d.");
	  strcpy (players[plr].setmin, "%n appears with an ear-splitting bang.");
	  strcpy (players[plr].setmout, "%n vanishes in a puff of smoke.");
	  strcpy (players[plr].setvin, "%n suddenly appears!");
	  strcpy (players[plr].setvout, "%n has vanished!");
	  strcpy (players[plr].setqin, "%n has entered the game.");
	  strcpy (players[plr].setqout, "%n has left the game.");
	  strcpy (players[plr].setsit, "%n is sitting here.");
	  strcpy (players[plr].setstand, "%n is standing here.");
	  strcpy (players[plr].settrenter, "%n appears, looking bewildered.");
	  strcpy (players[plr].settrvict, "You are summoned by %n.");
	  strcpy (players[plr].settrroom, "%n evocates the summoning spell.");
          strcpy (players[plr].setsleep, "%n is sleeping here.");
          strcpy (players[plr].settrance, "%n is standing here deep in trance.");
          strcpy (players[plr].setaway, "%n is marked as being away, and might not answer immediately.\n"); 
	}
    }
  
char *build_setin (int plx, char *b, char *s, char *n, char *d)
{  char *p, *q, *r;
	
   for (p = b, q = s; *q != 0;)
   {
      if (*q != '%')
         *p++ = *q++;
      else
      {
         switch (*++q) {
         case 'n':
	    for (r = n; *r != 0;)
	      *p++ = *r++;
	    break;
	 case 'd':
	    if (d == NULL)
	      return NULL;
	    for (r = d; *r != 0;)
	      *p++ = *r++;
	    break;
	 case 'N':
	    for (r = xname (n); *r != 0;)
	      *p++ = *r++;
	    break;
	 case 'f':
	    for (r = (psex (plx) ? "her" : "his"); *r != 0;)
	      *p++ = *r++;
	    break;
	  case 'F':
	    for (r = (psex (plx) ? "her" : "him"); *r != 0;)
	      *p++ = *r++;
	    break;
	  case 0:
	    --q;
	    break;
	  default:
	    *p++ = *q;
	  }
	++q;
      }
   }
   if (p[-1] == '\n')
     --p;
     *p = 0;
   return b;
}