talker/
talker/bin/
talker/files/whois/
talker/update/
talker/update/bin/
/* note, this is still under construction... */

/*
 * items.c
 */

#include <ctype.h>
#include <string.h>
#include <malloc.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdio.h>
#include <fcntl.h>
#include <memory.h>

#include "config.h"
#include "player.h"
#include "fix.h"
#include "items.h"
/* externs */

extern char    *upper_from_saved(saved_player * sp);
extern char    *check_legal_entry(player *, char *, int);
extern char    *store_string(), *store_int();
extern char    *get_string(), *get_int();
extern char    *gstring_possessive(), *gstring(), *end_string(), *next_space();
extern player  *find_player_global_quiet(char *), *find_player_global(char *);
extern player  *find_player_absolute_quiet(char *);
extern saved_player *find_saved_player(char *);
extern void     log(char *, char *);
extern void     tell_player(player *, char *);
extern char    *number2string(int);
extern char    *full_name(player *);
extern char    *get_gender_string(player *);
extern void     save_player(player *);
extern void     pager(player *, char *, int);
extern int      global_tag(player *, char *);
extern void     cleanup_tag(player **, int);
extern void     TELLROOM(), ADDSTACK(), ENDSTACK(), TELLPLAYER(), LOGF(), 
		SUWALL();
extern saved_player **saved_hash[];
extern int	strnomatch(char *, char *, int);

struct s_item	*top_item;
int		item_unique;
void		check_special_effect();

/* delete and entry from someones list */

void            delete_entry_item(saved_player * sp, item * l)
{
   item    *scan;
   if (!sp)
      return;
   scan = sp->item_top;
   if (scan == l)
   {
      sp->item_top = l->next;
      FREE(l);
      return;
   }
   while (scan)
      if (scan->next == l)
      {
    scan->next = l->next;
    FREE(l);
    return;
      } else
    scan = scan->next;
   log("error", "Tried to delete item that wasn't there.\n");
}


/* compress list */

void            tmp_comp_item(saved_player * sp)
{
   char           *oldstack;
   item          *l, *next, *z, *znext;

   l = sp->item_top;

   oldstack = stack;
   stack = store_int(stack, 0);

   while (l)
   {
      next = l->next;
      if (l->id < 0)
      {
    log("error", "Bad item entry on compress .. auto deleted.\n");
    delete_entry_item(sp, l);
      } else {
    stack = store_int(stack, l->id);
    stack = store_int(stack, l->number);
    stack = store_int(stack, l->flags);
      }
      l = next;
   }
   store_int(oldstack, ((int) stack - (int) oldstack));
}


void            compress_item(saved_player * sp)
{
   char           *oldstack;
   int             length;
   item           *new, *l, *next;
   if (sp->system_flags & COMPRESSED_ITEMS)
      return;
   sp->system_flags |= COMPRESSED_ITEMS;
   oldstack = stack;
   tmp_comp_item(sp);
   length = (int) stack - (int) oldstack;
   if (length == 4)
   {
      sp->item_top = 0;
      stack = oldstack;
      return;
   }
   new = (item *) MALLOC(length);
   memcpy(new, oldstack, length);

   l = sp->item_top;
   while (l)
   {
      next = l->next;
      FREE(l);
      l = next;
   }
   sp->item_top = new;
   stack = oldstack;
}

/* decompress list */

void            decompress_item(saved_player * sp)
{
   item          *l;
   char           *old, *end, *start;
   int             length;

   if (!(sp->system_flags & COMPRESSED_ITEMS))
      return;
   sp->system_flags &= ~COMPRESSED_ITEMS;

   old = (char *) sp->item_top;
   start = old;
   if (!old)
      return;
   old = get_int(&length, old);
   end = old + length - 4;
   sp->item_top = 0;
   while (old < end)
   {
      l = (item *) MALLOC(sizeof(item));
      old = get_int(&(l->id), old);
      old = get_int(&(l->number), old);
      old = get_int(&(l->flags), old);
      l->next = sp->item_top;
      l->loc_next = 0;
      sp->item_top = l;
      l->owner = sp;
   }
   FREE(start);
}

/* save list */

void            construct_item_save(saved_player * sp)
{
   int             length;
   char           *where;

   if (!(sp->system_flags & COMPRESSED_ITEMS) &&
       (!find_player_absolute_quiet(sp->lower_name)))
      compress_item(sp);

   if (sp->system_flags & COMPRESSED_ITEMS)
   {
      if (sp->item_top)
      {
    where = (char *) sp->item_top;
    (void) get_int(&length, where);
    memcpy(stack, where, length);
    stack += length;
      } else
    stack = store_int(stack, 4);
   } else
      tmp_comp_item(sp);
}

/* retrieve list */

char           *retrieve_item_data(saved_player * sp, char *where)
{
   int             length;
   (void) get_int(&length, where);
   if (length == 4)
      sp->item_top = 0;
   else
   {
      sp->system_flags |= COMPRESSED_ITEMS;
      sp->item_top = (item *) MALLOC(length);
      memcpy(sp->item_top, where, length);
   }
   where += length;
   return where;
}

/* count list entries */

int             count_items(player * p)
{
   item	       *l, *s;
   int          count = 0;
   if (!p->saved)
      return 0;
   if (!p->saved->item_top)
      return 0;
   for (l = p->saved->item_top; l; l = l->next) {
      count++;
   }
   return count;
}

/* s_item stuff starts here! */


int             count_sitem()
{
   struct s_item	       *l;
   int          count = 0;
   if (!top_item)
      return 0;
   for (l = top_item; l; l = l->next) 
      count++;
   return count;
}

char *extract_sitem(char *stack2){

	struct s_item *d;

	d = (struct s_item *) MALLOC(sizeof(struct s_item));
	memset(d, 0, sizeof(struct s_item));
	stack2 = get_string(d->desc, stack2);
	stack2 = get_string(d->name, stack2);
	stack2 = get_string(d->author, stack2);
	stack2 = get_int(&d->id, stack2);
	stack2 = get_int(&d->sflags, stack2);
	stack2 = get_int(&d->value, stack2);

	d->next = top_item;
	top_item = d;
	return stack2;	
}

void	save_sitem(struct s_item *s) {

	stack = store_string(stack, s->desc);
	stack = store_string(stack, s->name);
	stack = store_string(stack, s->author);
	stack = store_int(stack, s->id);
	stack = store_int(stack, s->sflags);
	stack = store_int(stack, s->value);
}

/* throw all the saved items to disk */

void            sync_sitems(int background)
{
   int                n, fd, count, len;
   struct itimerval   new;
   char              *oldstack;
   struct s_item     *z;

   oldstack = stack;

   if (background && fork())
      return;

#ifdef PC
   fd = open("files\\notes\\track", O_CREAT | O_WRONLY | O_TRUNC | O_BINARY);
#else
   fd = open("files/items/saved.items", O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, S_IRUSR | S_IWUSR);
#endif
   if (fd < 0)
      handle_error("Failed to open items file.");
   count = count_sitem();
   stack = store_int(stack, count);
   stack = store_int(stack, item_unique);
  if (top_item)
   for (z = top_item; z; z = z->next) {
	save_sitem(z);
   }

   len = (int) stack - (int) oldstack;

   if (write(fd, oldstack, len) < 0)
	handle_error("Ack! Can't save the saved items!!");
   close(fd);

   stack = oldstack;

   if (background)
      exit(0);
}

/*
 * load all notes from disk this should be changed for arbitary hashes
 */
	

void            init_sitems()
{
   int             length, fd, count;
   char           *oldstack;
   oldstack = stack;

   if (sys_flags & VERBOSE || sys_flags & PANIC)
      log("boot", "Loading notes from disk");

   fd = open("files/items/saved.items", O_RDONLY | O_NDELAY);
   if (fd < 0)
   {
      sprintf(oldstack, "Failed to load items file");
      stack = end_string(oldstack);
      log("error", oldstack);
      top_item = 0;
      item_unique = 0;
      stack = oldstack;
   } else {
   length = lseek(fd, 0, SEEK_END);
   lseek(fd, 0, SEEK_SET);
   if (length) { 
	if (read(fd, oldstack, length) < 0)
		handle_error("Damnit, s_items aren't loading");
	stack = get_int(&count, stack);
	stack = get_int(&item_unique, stack);
	for (; count; count--) 
		stack = extract_sitem(stack);
	       }
      close(fd);
          }
      stack = oldstack;
}


struct s_item *find_item_before(struct s_item *scan) {

	struct s_item *s;

	for (s = top_item; s; s = s->next) {
		if (s->next == scan)
			return s;
		}
	return 0;
}

struct s_item *find_item(char *name, int id) {
	
	struct s_item *s;

	for (s = top_item; s; s = s->next) 
		if (((name) && !strcasecmp(s->name, name)) || s->id == id)
			return s;

	return 0;
}

item *find_pitem(saved_player *sp, int id) {
	
	item *i;

	if (sp->system_flags & COMPRESSED_ITEMS)
		decompress_item(sp);	
	if (!(sp) || !(sp->item_top))
		return 0;
	for (i = sp->item_top; i; i = i->next) 
		if (i->id == id)
			return i;

	return 0;
}