dmuck0.15-beta/docs/muf/
dmuck0.15-beta/game/
dmuck0.15-beta/game/logs/
dmuck0.15-beta/game/muf/
dmuck0.15-beta/game/muf/text/
#include "copyright.h"
#include "config.h"
#include "db.h"
#include "externs.h"
#include "params.h"

#ifdef COMPRESS
#define alloc_compressed(x) dup_string(compress(x))
#else /* !COMPRESS */
#define alloc_compressed(x) dup_string(x)
#endif /* COMPRESS */

char buf2[BUFSIZ], buf[BUFSIZ];

static propdir *freehead = NULL;

propdir *new_propdir(void)
{
	propdir *ret;

   if (freehead)
	{
		ret = freehead;
		freehead = freehead->next;
	}
	else
	{
		ret = (propdir *) malloc (sizeof(propdir));
	}

	return ret;
}

void delete_propdir(propdir *p)
{
   p->next = freehead;
   freehead = p;
}

char *unparse_perms(char perms)
{
  static char perms_buf[9];
  perms_buf[0] = (perms & PERMS_LOCKED)  ? 'l' : '-';
  perms_buf[1] = (perms & PERMS_HIDDEN)  ? 'h' : '-';
  perms_buf[2] = (perms & PERMS_COREAD)  ? 'r' : '-';
  perms_buf[3] = (perms & PERMS_COWRITE) ? 'w' : '-';
  perms_buf[4] = (perms & PERMS_COSRCH)  ? 's' : '-';
  perms_buf[5] = (perms & PERMS_OTREAD)  ? 'r' : '-';
  perms_buf[6] = (perms & PERMS_OTWRITE) ? 'w' : '-';
  perms_buf[7] = (perms & PERMS_OTSRCH)  ? 's' : '-';
  perms_buf[8] = '\0';

  return perms_buf;
}

char parse_perms(char *perms)
{
  char ret = 0;
  if (isdigit(*perms)) return (char)strtol(perms, NULL, 0);

  ret += (perms[0] == 'l') ? 0x80 : 0;
  ret += (perms[1] == 'h') ? 0x40 : 0;
  ret += (perms[2] == 'r') ? 0x20 : 0;
  ret += (perms[3] == 'w') ? 0x10 : 0;
  ret += (perms[4] == 's') ? 0x08 : 0;
  ret += (perms[5] == 'r') ? 0x04 : 0;
  ret += (perms[6] == 'w') ? 0x02 : 0;
  ret += (perms[7] == 's') ? 0x01 : 0;
  return ret;
}

char default_perms(char *line1)
{
  switch (*line1)
  {
    case '.': return (PERMS_COREAD | PERMS_COWRITE | PERMS_COSRCH);
    case '_': return (PERMS_COREAD | PERMS_COWRITE | PERMS_COSRCH |
      PERMS_OTREAD | PERMS_OTSRCH);
    case '*': return (PERMS_COREAD | PERMS_COWRITE | PERMS_COSRCH |
      PERMS_HIDDEN);
  }
  return (PERMS_COREAD | PERMS_COWRITE | PERMS_COSRCH | PERMS_OTREAD |
    PERMS_OTWRITE | PERMS_OTSRCH);
}

char access_rights(dbref player, dbref obj, dbref program)
{
  if (program != NOTHING)
  {
    if (FLAGS(program) & STICKY) player = OWNER(program);
    if ((FLAGS(program) & WIZARD) && (FLAGS(OWNER(program)) & WIZARD))
      return ACCESS_WI;
  }
  else if (FLAGS(player) & WIZARD) return ACCESS_WI;
  if (controls(player, obj)) return ACCESS_CO;
  return ACCESS_OT;
}

int check_perms(char perms, char access, char type)
{
  if (access & ACCESS_WI) return 1;
  if (access & ACCESS_CO)
  {
    switch(type)
    {
      case PT_SEE:    return 1;
      case PT_CHANGE: return (!(perms & PERMS_LOCKED));
      case PT_READ:   return (perms & PERMS_COREAD);
      case PT_WRITE:  return (perms & PERMS_COWRITE);
      case PT_SRCH:   return (perms & PERMS_COSRCH);
    }
  }
  else
  {
    switch(type)
    {
      case PT_SEE:    return (!(perms & PERMS_HIDDEN));
      case PT_CHANGE: return 0;
      case PT_READ:   return (perms & PERMS_OTREAD);
      case PT_WRITE:  return (perms & PERMS_OTWRITE);
      case PT_SRCH:   return (perms & PERMS_OTSRCH);
    }
  }
 return 0;
}

#define PERMS_DEFAULT_DIR PERMS_COREAD | PERMS_COWRITE | PERMS_COSRCH | \
  PERMS_OTREAD | PERMS_OTSRCH
propdir *setpropdir(propdir **p, char *name, char perms, char access)
{
  propdir *tmp;

  for (tmp = *p; tmp && (string_compare(tmp->name, name)); tmp = tmp->next);

  if (tmp)
  {
    if (!check_perms(tmp->perms, access, PT_SRCH)) return NULL;
  }
  else
  {
    /* tmp = (propdir *)malloc(sizeof(propdir)); */
	 tmp = new_propdir();
    tmp->name = dup_string(name);
    tmp->data = NULL;
    if (access & ACCESS_WI) tmp->perms = perms | PERMS_DEFAULT_DIR;
    else tmp->perms = perms | PERMS_DEFAULT_DIR & ~PERMS_LOCKED;
    tmp->next = *p;
    tmp->child = NULL;
    *p = tmp;
  }
  return tmp;
}

propdir *setpropelt(propdir **p, char *name, char *data, char perms,
  char access)
{
  propdir *tmp;

  for (tmp = *p; tmp && (string_compare(tmp->name, name)); tmp = tmp->next);

  if (tmp)
  {
    if (!check_perms(tmp->perms, access, PT_WRITE)) return NULL;
    free (tmp->data);
  }
  else
  {
    /* tmp = (propdir *)malloc(sizeof(propdir)); */
	 tmp = new_propdir();
      tmp->name = dup_string(name);
/*    tmp->name = alloc_compressed(name);  */
    if (access & ACCESS_WI) tmp->perms = perms;
    else tmp->perms = perms & ~PERMS_LOCKED;
    tmp->next = *p;
    tmp->child = NULL;
    *p = tmp;
  }

/*  tmp->data = dup_string(data); */
    tmp->data = alloc_compressed(data);
  return tmp;
}

#define split(A,B) \
{ \
  A = B; \
  while (*B && (*B != '/')) B++; \
  if (*B) *B++ = '\0'; \
  while (*B == '/') B++; \
}

#define first(A) while (*A == '/') A++;

propdir *set_propdir(propdir *p, char *name, char *data, char perms,
  char access)
{
  propdir *tmp, *loop, *ptmp, *tmp2;
  char *word;

  ptmp = p;

  first(name);
  if (*name)
  {
    split(word, name);
    if (*name) loop = setpropdir(&ptmp, word, perms, access);
    else loop = setpropelt(&ptmp, word, data, perms, access);
  }
  else return ptmp;

  while (*name && loop)
  {
    split(word, name);
    /* can only create new properties if propdir is writeable */
    if (check_perms(loop->perms, access, PT_WRITE))
    {
      /* we can write to the propdir so let's do it! */
      if (*name) tmp = setpropdir(&(loop->child), word, perms, access);
      else tmp = setpropelt(&(loop->child), word, data, perms, access);
    }
    else
    {
      for(tmp2 = loop->child;
        tmp2 && string_compare(tmp2->name, word);
        tmp2 = tmp2->next);
      /* if property exists, use the perms on the property not the dir */
      if (tmp2)
      {
        if (*name) tmp = setpropdir(&(loop->child), word, perms, access);
        else tmp = setpropelt(&(loop->child), word, data, perms, access);
      }
      else return NULL;
      /* if not then can't create */
    }
    loop = tmp;
  }
  if (*name) return NULL;
  if (!loop) return NULL;
  return ptmp;
}

int add_property(dbref obj, char *name, char *data, char perms, char access)
{
  propdir *p;
  p = set_propdir(DBFETCHPROP(obj), name, data, perms, access);
  if (p)
  {
    DBSTOREPROP(obj, p);
  }
  return (int)p;
}

void burn_proptree(propdir *p)
{
  if (p)
  {
    free(p->name);
    if(p->data) free(p->data);
    burn_proptree(p->child);
    burn_proptree(p->next);
	 /* free(p) */
    delete_propdir(p);
  }
}

propdir *burn_prop(propdir *p, char *name, int *status)
{
  propdir *tmp, *loop;

  if (!p)
  {
    *status = 0;
    return NULL;
  }
  else *status = 1;

  if (string_compare(p->name, name))
  {
    for (loop = p;
      loop->next && string_compare(loop->next->name, name);
      loop = loop->next);

    if (loop->next)
    {
      tmp = loop->next;
      loop->next = tmp->next;
    }
    else
    {
      *status = 0;
      return p;
    }
  }
  else
  {
    tmp = p;
    p = p->next;
  }

  free(tmp->name);
  free(tmp->data);
  burn_proptree(tmp->child);
  /* free(tmp); */
  delete_propdir(tmp);

  return p;
}

/* returns 0 if successful, 1 if property not found, 2 if permission denied */
int remove_property(dbref obj, char *name, char access)
{
  propdir *p, *tmp;
  char *word;
  int s;

  p = DBFETCHPROP(obj);  /* forgot one Claudius! */

  if (!name || !*name)
  {
    burn_proptree(p);
    DBSTOREPROP(obj, NULL);
    return 0;
  }

  first(name);
  split(word, name);

  if (*name)
  {
    while (p && string_compare(p->name, word)) p = p->next;
    if (!p) return 1;
  }
  else
  {
    tmp = burn_prop(p, word, &s);
    if (s)
    {
      DBSTOREPROP(obj, tmp);
      return 0;
    }
    else return 1;
  }

  split(word, name);

  while (*name && p->child)
  {
    if(check_perms(p->perms, access, PT_SRCH))
    {
      for (p = p->child; p && string_compare(p->name, word); p = p->next);
      if (!p) return 1;
      split(word, name);
    }
    else return 2;
  }

  if (p->child)
  {
    if(check_perms(p->perms, access, PT_WRITE))
    {
      tmp = burn_prop(p->child, word, &s);
      if (s) p->child = tmp;
      else return 1;
    }
    else return 2;
  }
  return 0;
}

/*
  checks if object has property, returning 1 if it or any of it's
  contents has the property stated
 */
int has_property(dbref obj, char *name, char *data, char access)
{
  if (validate_property(obj, name, data, access)) return 1;

  for (obj = DBFETCH(obj)->contents;
    obj != NOTHING;
    obj = DBFETCH(obj)->next)
    if (validate_property(obj, name, data, access)) return 1;

  return 0;
}

propdir *find_property(dbref obj, char *name, char access)
{
  propdir *tmp;
  char *word;

  tmp = DBFETCHPROP(obj);
  first(name);

  if (!*name) return NULL;

  while (*name)
  {
    split(word, name);
    while (tmp && string_compare(tmp->name, word)) tmp = tmp->next;
    if (*name)
    {
      if (tmp && check_perms(tmp->perms, access, PT_SRCH)) tmp = tmp->child;
      else return NULL;
    }
  }
  return tmp;
}

int validate_property(dbref obj, char *name, char *data, char access)
{
  propdir *p;
  if ((p = find_property(obj, name, access)) && p->data &&
    check_perms(p->perms, access, PT_READ))
  {
    return (!string_compare(uncompress(p->data), data));
  }
  return 0;
}

/* return class of property */
char *get_property_data(dbref obj, char *name, char access)
{
  propdir *p;

#ifdef MUSH
  if(!GoodObject(obj) || !name || !*name)
     return NULL;
#endif
  if ((p = find_property(obj, name, access)) &&
    (check_perms(p->perms, access, PT_READ))) return uncompress(p->data);
  return NULL;
}

propdir *dup_propdir(propdir *src, char access)
{
  propdir *new = NULL;
  if (src && check_perms(src->perms, access, PT_READ))
  {
    /* new = (propdir *)malloc(sizeof(propdir)); */
	 new = new_propdir();
    new->name = dup_string(src->name);
    new->data = dup_string(src->data);
    if (check_perms(src->perms, access, PT_SRCH))
      new->child = dup_propdir(src->child, access);
    new->next = dup_propdir(src->next, access);
  }
  return new;
}

/* copies properties */
void copy_prop(dbref obj, dbref dest, char access)
{
  DBSTOREPROP(dest, dup_propdir(DBFETCHPROP(obj), access));
}

/* return old gender values for pronoun substitution code */
int genderof(dbref player, char access)
{
  if (validate_property(player, "sex", "male", access)) return GENDER_MALE;
  if (validate_property(player, "sex", "female", access)) return GENDER_FEMALE;
  if (validate_property(player, "sex", "neuter", access)) return GENDER_NEUTER;
  return GENDER_UNASSIGNED;
}

void notify_pdrecurse(dbref player, propdir *p, char *match, char access,
  char longform)
{
  char *end;
  char *junk;
  char *tmp;
  char *mush=match;

  for(; p; p = p->next)
  {
    for (junk = match; (*junk != '/') && *junk; junk++);
    if (!stringn_compare(p->name, match, (int)(junk - match))
#ifdef MUSH
      || wild_match(mush, p->name)
#endif
     )
    {
      end = buf2 + strlen(buf2);
      if ((p->child) && check_perms(p->perms, access, PT_SRCH))
      {
        if (*junk)
        {
          strcat(buf2, p->name);
          strcat(buf2, "/");
          while (*junk == '/') junk++;
          notify_pdrecurse(player, p->child, junk, access, longform);
          *end = '\0';
        }
      }
      if ((!(p->perms & PERMS_HIDDEN) ||
        (access == ACCESS_WI)))
      {
        if (longform)
        {
          sprintf(buf, "%s:%s%s%s%s%s", unparse_perms(p->perms), buf2,
            p->name, p->child ? "/" : "", p->data ? ":" : "",
            check_perms(p->perms, access, PT_READ) ?
            p->data :
            "<<PERMISSION DENIED>>");
        }
        else
        {
        tmp = p->data;
/*        sprintf(buf, "%s%s%s%s%s", buf2, p->name, */
          sprintf(buf, "%s%s%s%s", buf2, p->name,
            p->child ? "/" : "", p->data ? ":" : "");
           if(!check_perms(p->perms, access, PT_READ))
             strcat(buf, "<<PERMISSION DENIED>>");
           else if(p->data && *tmp)
             strcat(buf, p->data);
        }
        notify(player, player, buf);
      }
      *end = '\0';
    }
  }
}

void notify_propdir(dbref player, dbref obj, char *match, char access,
  char longform)
{
  if (DBFETCHPROP(obj))
    notify_pdrecurse(player, DBFETCHPROP(obj), match, access, longform);
}

void change_perms(dbref obj, char *name, char perms, char access)
{
  propdir *p;

  strcpy(buf, name);
  p = find_property(obj, buf, access);
  if (p && check_perms(p->perms, access, PT_CHANGE))
  {
    if (access == ACCESS_WI) p->perms = perms;
    else p->perms = perms &= ~PERMS_LOCKED;
  }
}

propdir *find_see(propdir *p, char access)
{
  while (p && !check_perms(p->perms, access, PT_SEE)) p = p->next;
  return p;
}

int nextprop(char *buffer, propdir *p, char *name, char sub, char access)
{
  char *word;
  propdir *tmp;

  if(!p) return 0;

  split(word, name);
  for(tmp = p; tmp && string_compare(uncompress(tmp->name), word);
    tmp = tmp->next);
  if(tmp && name && *name)
  {
    if(nextprop(buffer, tmp->child, name, sub, access))
    {
      strcpy(buf, uncompress(tmp->name));
      strcat(buf, "/");
      strcat(buf, buffer);
      strcpy(buffer, buf);
    }
    else
    {
      if(tmp = find_see(tmp->next, access))
	strcpy(buffer, uncompress(tmp->name));
      else return 0;
    }
  }
  else
  {
    if (!tmp) strcpy(buffer, uncompress(p->name));
    else
    {
      if (sub) p = find_see(tmp->child, access);
      else p = NULL;

      if (p)
      {
        strcpy(buffer, uncompress(tmp->name));
        strcat(buffer, "/");
        tmp = p;
      }
      else
      {
        strcpy(buffer, "");
        tmp = find_see(tmp->next, access);
      }

      if (tmp) strcat(buffer, uncompress(tmp->name));
      else return 0;
    }
  }
  return 1;
}

void next_property(char *buffer, dbref obj, char *name, char access)
{
  if (name != NULL) first(name);
  if (name != NULL && (DBFETCHPROP(obj)))
     nextprop(buffer, DBFETCHPROP(obj), name, name[strlen(name) - 1] 
              == '/', access);
  else if (DBFETCHPROP(obj))
       strcpy(buffer, DBFETCHPROP(obj)->name);
  else strcpy(buffer, "");
}

int has_next_property(dbref obj, char *name, char access, int child)
{
  propdir *p;
  if (!(p = find_property(obj, name, access))) return 0;
  return ((int)find_see(child ? p->child : p->next, access));
}

void putproperties_recurse(FILE *f, propdir *p)
{
  char *end;

  for (; p; p = p->next)
  {
    if (p->child)
    {
      end = buf2 + strlen(buf2);
      strcat(buf2, p->name);
      strcat(buf2, "/");
      putproperties_recurse(f, p->child);
      *end = '\0';
    }
    if (p->data)
    {
      sprintf (buf, "%s%s:%d:%s\n", buf2, p->name, p->perms, p->data);
      fputs(buf, f);
    }
  }
}

void putproperties(FILE *f, dbref obj)
{
  strcpy(buf2, "");
  putproperties_recurse(f, DBFETCHPROP(obj));
}

void getproperties(FILE *f, dbref obj, char permflag)
{
  char *data, *perms, getbuf[BUFSIZ];
  propdir *p = NULL;

  /* get rid of first line */
  fgets(getbuf, sizeof(getbuf), f);
  
  /* initialize first line stuff */
  fgets(getbuf, sizeof(getbuf), f);
  while (strcmp(getbuf, "***Property list end ***\n"))
  {
    data = (char *)strchr(getbuf, PROP_DELIMITER);
    if (data)
    {
      *data++ = '\0';
      if (permflag) /* permissions now stored in db... */
      {
	perms = data;
	data = (char *)strchr(data, PROP_DELIMITER);
	if (!data) abort();  /* PARSE ERROR */
	*data++ = '\0';
        data[strlen(data) - 1] = '\0';
        p = set_propdir(p, getbuf, data, atoi(perms), ACCESS_WI);
      }
      else
      {
        data[strlen(data) - 1] = '\0';
        p = set_propdir(p, getbuf, data, default_perms(getbuf), ACCESS_WI);
      }
    }
    fgets(getbuf, sizeof(getbuf), f);
  }
  DBSTOREPROP(obj, p);
}

int is_propdir(dbref player, dbref object1, char *string, dbref program)
{
  propdir *p = NULL;

    p = find_property(object1, string, access_rights(player, object1, program));
    if(!p) return 0;
    if(!p->child) return 0;

 return 1;
}