pgplus/bin/
pgplus/help_files/
pgplus/port_redirector/
pgplus/src/configure/makefiles/
/*
 * Playground+ - aliases.c
 * Aliases editing, creating and matching code
 * ---------------------------------------------------------------------------
 */

#include <ctype.h>
#include <string.h>
#ifndef BSDISH
#include <malloc.h>
#endif
#include <fcntl.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>

#include "include/config.h"
#include "include/player.h"
#include "include/fix.h"
#include "include/aliases.h"
#include "include/proto.h"

/* delete and entry from someones list */

void delete_entry_alias(saved_player * sp, alias * l)
{
  alias *scan;
  if (!sp)
    return;
  scan = sp->alias_top;
  if (scan == l)
  {
    sp->alias_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 alias that wasn't there.");
}


/* compress list */

void tmp_comp_alias(saved_player * sp)
{
  char *oldstack;
  alias *l, *next;

  l = sp->alias_top;

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

  while (l)
  {
    next = l->next;
    if (!l->cmd[0])
    {
      log("error", "Bad alias entry on compress .. auto deleted.");
      delete_entry_alias(sp, l);
    }
    else
    {
      stack = store_string(stack, l->cmd);
      stack = store_string(stack, l->sub);
    }
    l = next;
  }
  store_int(oldstack, ((int) stack - (int) oldstack));
}

/* */
void compress_alias(saved_player * sp)
{
  char *oldstack;
  int length;
  alias *new, *l, *next;
  if (sp->system_flags & COMPRESSED_ALIAS)
    return;
  sp->system_flags |= COMPRESSED_ALIAS;
  oldstack = stack;
  tmp_comp_alias(sp);
  length = (int) stack - (int) oldstack;
  if (length == 4)
  {
    sp->alias_top = 0;
    stack = oldstack;
    return;
  }
  new = (alias *) MALLOC(length);
  memcpy(new, oldstack, length);

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

/* decompress list */

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

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

  old = (char *) sp->alias_top;
  start = old;
  if (!old)
    return;
  old = get_int(&length, old);
  end = old + length - 4;
  sp->alias_top = 0;
  while (old < end)
  {
    l = (alias *) MALLOC(sizeof(alias));
    old = get_string(stack, old);
    strncpy(l->cmd, stack, MAX_NAME - 3);
    old = get_string(stack, old);
    strncpy(l->sub, stack, MAX_DESC - 3);
    l->next = sp->alias_top;
    sp->alias_top = l;
  }
  FREE(start);
}



/* save list */

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

  if (!(sp->system_flags & COMPRESSED_ALIAS) &&
      (!find_player_absolute_quiet(sp->lower_name)))
    compress_alias(sp);

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

/* retrieve list */

char *retrieve_alias_data(saved_player * sp, char *where)
{
  int length;
  (void) get_int(&length, where);
  if (length == 4)
    sp->alias_top = 0;
  else
  {
    sp->system_flags |= COMPRESSED_ALIAS;
    sp->alias_top = (alias *) MALLOC(length);
    memcpy(sp->alias_top, where, length);
  }
  where += length;
  return where;
}

/* count list entries */

int count_alias(player * p)
{
  alias *l;
  int count = 0;
  if (!p->saved)
    return 0;
  if (!p->saved->alias_top)
    return 0;
  for (l = p->saved->alias_top; l; l = l->next)
    count++;
  return count;
}

/* find list entry for a person */

alias *find_alias_entry(player * p, char *name)
{
  alias *l;

  if (!p->saved)
    return 0;
  decompress_alias(p->saved);
  l = p->saved->alias_top;
  while (l)
    if (!strcasecmp(l->cmd, name))
      return l;
    else
      l = l->next;
  return 0;
}

/* create a list entry */

alias *create_entry_alias(player * p, char *name)
{
  alias *l;

  if (!p->saved)
    return 0;
  if ((count_alias(p)) >= (p->max_alias))
  {
    tell_player(p, " Can't create new alias, "
		"because your alias list is full.\n");
    return 0;
  }
  l = (alias *) MALLOC(sizeof(alias));
  strncpy(l->cmd, name, MAX_NAME - 3);
  l->cmd[MAX_NAME - 3] = 0;
  strncpy(l->sub, "", MAX_DESC - 3);
  l->sub[MAX_DESC - 3] = 0;

  l->next = p->saved->alias_top;
  p->saved->alias_top = l;
  return l;
}

/* view alias list */

void view_alias(player * p, char *str)
{
  char *oldstack, li[] = "Logon Script", lo[] = "Logoff Script", re[] = "Reconnect Script";
  alias *l, *logon = 0, *logoff = 0, *recon = 0;
  int count;
  char top[70];

  oldstack = stack;

  if (!p->saved)
  {
    tell_player(p, " You have no alias list to view.\n");
    return;
  }
  count = count_alias(p);
  if (!count)
  {
    TELLPLAYER(p, "You are using none of your maximum %d aliases.\n", p->max_alias);
    return;
  }
  sprintf(top, "You are using %d of your maximum %d aliases",
	  count, p->max_alias);
  pstack_mid(top);

  for (l = p->saved->alias_top; l; l = l->next)
  {
    if (!strcmp(l->cmd, "_logon"))
      logon = l;
    else if (!strcmp(l->cmd, "_logoff"))
      logoff = l;
    else if (!strcmp(l->cmd, "_recon"))
      recon = l;
    else
    {
      sprintf(stack, "^B%-20s^N = %s", l->cmd, l->sub);
      stack = strchr(stack, 0);
      *stack++ = '\n';
    }
  }
  if (logon || logoff || recon)
  {
    sprintf(stack, LINE);
    stack = strchr(stack, 0);
    if (logon)
    {
      sprintf(stack, "^B%-20s^N = %s", li, logon->sub);
      stack = strchr(stack, 0);
      *stack++ = '\n';
    }
    if (logoff)
    {
      sprintf(stack, "^B%-20s^N = %s", lo, logoff->sub);
      stack = strchr(stack, 0);
      *stack++ = '\n';
    }
    if (recon)
    {
      sprintf(stack, "^B%-20s^N = %s", re, recon->sub);
      stack = strchr(stack, 0);
      *stack++ = '\n';
    }
  }
  sprintf(stack, LINE);
  stack = end_string(stack);
  pager(p, oldstack);
  stack = oldstack;
}

/* undefine a macro? */

void undefine_alias(player * p, char *str)
{
  char *oldstack, *text, msg[50];
  int count = 0;
  alias *l;

  oldstack = stack;

  if (!p->saved)
  {
    tell_player(p, " You do not have an alias list to alter, "
		"since you are not saved\n");
    return;
  }
  if (!*str)
  {
    tell_player(p, " Format: undefine <alias to undefine>\n");
    return;
  }
  {
    l = find_alias_entry(p, str);
    if (!l)
    {
      text = stack;
      sprintf(stack, " Can't find any alias list entry for '%s'.\n", str);
      stack = end_string(stack);
      tell_player(p, text);
    }
    else
    {
      count++;
      sprintf(msg, " Entry removed for '%s'\n", l->cmd);
      tell_player(p, msg);
      delete_entry_alias(p->saved, l);
    }
  }
  stack = oldstack;
  if (!count)
    tell_player(p, " No entries removed.\n");
  else
  {
    sprintf(stack, " Deleted alias.\n");
    stack = end_string(stack);
    tell_player(p, oldstack);
  }
  stack = oldstack;
}

/* check for people aliasing _logon / _logoff / _recon to something which uses the
 *  quit command -- blimey
 */
int alias_contains_quit_command(char * str)
{
    char * current;

    for (current = str; current; current = strstr(current, "%;")) {
        /* skip to the start of a commandline */
        if ((current[0] == '%') && (current[1] == ';'))
            current += 2;
        while (current[0] == ' ')
            current++;
        /* see if the commandline is prefixed by "quit",
           and has the suffix of a command delimiter */
        if ((strlen(current) >= 4) &&
            (strncasecmp(current, "quit", 4) == 0) &&
            ((current[4] == '\0') || (current[4] == ' ') ||
             (current[4] == '\n') || ((current[4] == '%') && (current[5] == ';'))))
            return 1;
    }
    return 0;
}

/* define an alias -- woowoo */

void define_alias(player * p, char *str)
{
  char *doh, *oldstack, *scanned;
  int count = 0;
  alias *l;

  if (!p->saved)
  {
    tell_player(p, " You can't alias because you have no save file.\n");
    return;
  }
  oldstack = stack;
  doh = next_space(str);
  if (!*doh)
  {
    tell_player(p, " Format: define <alias> <command to do instead>\n");
    return;
  }
  *doh++ = 0;
  /* strip extra spaces from str */
  scanned = str;
  while (*str && !(isspace(*str)))
    str++;
  *str++ = 0;
  str = scanned;

  /* check for stupid people */
  if ((!strcasecmp(str, "_logon") || !strcasecmp(str, "_logoff") || !strcasecmp(str, "_recon")) &&
      alias_contains_quit_command(doh))
  {
      tell_player(p, " You can't use the 'quit' command in such an alias.\n");
      return;
  }

  l = find_alias_entry(p, str);
  if (!l)
    l = create_entry_alias(p, str);
  if (l)
  {
    count++;
    strncpy(l->sub, doh, MAX_DESC - 3);
    l->sub[MAX_DESC - 3] = 0;
  }
  if (count)
    tell_player(p, " Alias defined.\n");
  else
    tell_player(p, " Error - could not create alias.\n");
}

char *do_alias_match(player * p, char *str)
{
  alias *scan;
  int g;

  if (!p->saved)
    return "\n";
  scan = p->saved->alias_top;
  while (scan)
  {
    g = 1;
    if (strnomatch(scan->cmd, str, 0))
      g = 0;
    if (g)
    {
      while (*str && *str != ' ')
	str++;
      while (*str && isspace(*str))
	str++;
      return str;
    }
    scan = scan->next;
  }
  return "\n";
}

alias *get_alias(player * p, char *str)
{
  alias *scan;
  int g;

  if (!p->saved)
    return 0;
  scan = p->saved->alias_top;
  while (scan)
  {
    g = 1;
    if (strnomatch(scan->cmd, str, 0))
      g = 0;
    if (g)
    {
      return scan;
    }
    scan = scan->next;
  }
  return 0;
}

/* New (spooned) splice_argument to prevent buffer overflows by Phypor */

char *splice_argument(player * p, char *str, char *arg, int conti)
{
  static char BUFFER[10000];
  char arghold[1000], strhold[1000], num[2], RARG[10][100];
  int b, no, word, r1, r2;
  static int a, s;

  memset(BUFFER, 0, 10000);
  memset(arghold, 0, 1000);

  if (*arg)
    strncpy(arghold, arg, 999);
  else
    strcpy(arghold, "");
  strncpy(strhold, str, 999);
  num[0] = 0;
  num[1] = 0;
  b = 0;

  if (!(conti))
  {				/* reset variables */
    s = 0;
    a = 0;
  }
  /* 
     buffer was getting overloaded, was 1000 bytes, now is 10000,
     no longer have break-to-stop loop, will end when way past
     length for writing out, but before buffer can be written past
   */
  while (b < 1000)
  {

    if (!strhold[s])
    {
      BUFFER[b++] = 0;
      return BUFFER;
    }
    else if (strhold[s] != '%')
    {
      BUFFER[b++] = strhold[s++];
    }
    else
    {
      if (strhold[s + 1] == ';')
      {
	BUFFER[b++] = 0;
	s += 2;
	return BUFFER;
      }
      else if (strhold[s + 1] == '%')
      {
	BUFFER[b++] = '%';
	s += 2;
      }
      else if (strhold[s + 1] == '0')
      {
	s += 2;
	a = 0;
	while (arghold[a])
	  BUFFER[b++] = arghold[a++];
      }
      else if (strhold[s + 1] == '-')
      {
	s += 3;
	num[0] = strhold[s - 1];
	num[1] = 0;
	no = atoi(num);
	a = 0;
	for (word = 0; word != no; a++)
	{
	  if (!arghold[a])
	  {
	    word = no;
	  }
	  else if (isspace(arghold[a]))
	    word++;
	}
	while (arghold[a])
	  BUFFER[b++] = arghold[a++];
      }
      else if (isdigit(strhold[s + 1]))
      {
	s += 2;
	num[0] = strhold[s - 1];
	num[1] = 0;
	no = atoi(num);
	a = 0;
	for (word = 1; word != no; a++)
	{

	  if (!arghold[a])
	  {
	    word = no;
	  }
	  else if (isspace(arghold[a]))
	    word++;
	}
	while (arghold[a] && !(isspace(arghold[a])))
	  BUFFER[b++] = arghold[a++];
      }
      else if (strhold[s + 1] == '{')
      {
	/* first, clear all the old rargs */
	for (r1 = 0; r1 < 10; r1++)
	  for (r2 = 0; r2 < 100; r2++)
	    RARG[r1][r2] = 0;

	/* now, fill in the data into RARG */
	r1 = 0;
	r2 = 0;
	s += 2;
/*	while (strhold[s] != '}') */
	while (strhold[s] && strhold[s] != '}')
	{
	  if (r1 < 10 && r2 < 99)
	  {
	    if (strhold[s] == '@')
	    {
	      RARG[r1++][r2] = 0;
	      r2 = 0;
	    }
	    else
	      RARG[r1][r2++] = strhold[s];
	  }
	  else if (r1 < 10)
	  {
	    RARG[r1++][r2] = 0;
	    r2 = 0;
	  }
	  s++;
	}
	/* this *should* be non wibblesd */
	RARG[r1][r2] = 0;

	/* cose a random arg */
	s++;			/* get the s to the space after the %{...} */
	r2 = (rand() % (r1 + 1));
	r1 = 0;
	while (RARG[r2][r1])
	{
	  BUFFER[b++] = RARG[r2][r1++];
	}
      }
      else
	s += 2;
    }
  }
  return "";
}


int strnomatch(char *str1, char *str2, int unanal)
{

  char *s1p, *s2p;

  s1p = str1;
  s2p = str2;

  for (; *s1p; s1p++, s2p++)
  {
    if (unanal && *s1p != *s2p)
      return 1;
    else if (tolower(*s1p) != tolower(*s2p))
      return 1;
  }
  if (!unanal && *s2p && (!isspace(*s2p)))
    return 1;
  return 0;
}




/* view someone else's alias list, if you are Admin */

void view_others_aliases(player * p, char *str)
{
  char *oldstack, li[] = "Login", lo[] = "Logout", re[] = "Reconnect";
  int count;
  player *p2, dummy;
  alias *l, *logon = 0, *logoff = 0, *recon = 0;
  char top[70];

  oldstack = stack;
  memset(&dummy, 0, sizeof(player));

  if (!*str)
  {
    tell_player(p, " Format: val <player>\n");
    return;
  }
  lower_case(str);
  p2 = find_player_global_quiet(str);
  if (!p2)
  {
    strcpy(dummy.lower_name, str);
    dummy.fd = p->fd;
    if (!load_player(&dummy))
    {
      tell_player(p, " That person does not exist!\n");
      return;
    }
    p2 = &dummy;
  }
  if (!p2->saved)
  {
    tell_player(p, " That person has no alias list to view.\n");
    return;
  }
  count = count_alias(p2);

  stack = oldstack;
  sprintf(top, "%s is using %d of %s %d alias list entries",
	  p2->name, count, their_player(p2), p2->max_alias);
  pstack_mid(top);

  if (count)
  {
    for (l = p2->saved->alias_top; l; l = l->next)
    {
      if (!strcmp(l->cmd, "_logon"))
	logon = l;
      else if (!strcmp(l->cmd, "_logoff"))
	logoff = l;
      else if (!strcmp(l->cmd, "_recon"))
	recon = l;
      else
      {
	sprintf(stack, "^B%-20s^N = %s", l->cmd, l->sub);
	stack = strchr(stack, 0);
	*stack++ = '\n';
      }
    }

    if (logon || logoff || recon)
    {
      strcpy(stack, LINE "\n");
      stack = strchr(stack, 0);
      if (logon)
      {
	sprintf(stack, "^B%-20s^N = %s", li, logon->sub);
	stack = strchr(stack, 0);
	*stack++ = '\n';
      }
      if (logoff)
      {
	sprintf(stack, "^B%-20s^N = %s", lo, logoff->sub);
	stack = strchr(stack, 0);
	*stack++ = '\n';
      }
      if (recon)
      {
	sprintf(stack, "^B%-20s^N = %s", re, recon->sub);
	stack = strchr(stack, 0);
	*stack++ = '\n';
      }
    }
  }
  sprintf(stack, LINE);
  stack = end_string(stack);
  pager(p, oldstack);
  stack = oldstack;
}


void define_logon_macro(player * p, char *str)
{

  char *oldstack;

  if (!*str)
  {

    undefine_alias(p, "_logon");
    return;
  }
  oldstack = stack;
  sprintf(stack, "_logon %s", str);
  stack = end_string(stack);
  define_alias(p, oldstack);
  stack = oldstack;
}

void define_logoff_macro(player * p, char *str)
{

  char *oldstack;

  if (!*str)
  {

    undefine_alias(p, "_logoff");
    return;
  }
  oldstack = stack;
  sprintf(stack, "_logoff %s", str);
  stack = end_string(stack);
  define_alias(p, oldstack);
  stack = oldstack;
}

void define_recon_macro(player * p, char *str)
{

  char *oldstack;

  if (!*str)
  {

    undefine_alias(p, "_recon");
    return;
  }
  oldstack = stack;
  sprintf(stack, "_recon %s", str);
  stack = end_string(stack);
  define_alias(p, oldstack);
  stack = oldstack;
}

void library_list(player * p, char *str)
{
  char temp[80];
  char *oldstack;
  int i = 0;

  oldstack = stack;

  sprintf(temp, "%s alias library", get_config_msg("talker_name"));
  pstack_mid(temp);

  while (library[i].command)
  {
    if (!(library[i].privs) || p->residency & PSU)
    {
      sprintf(stack, "%-18s", library[i].command);
      stack = strchr(stack, 0);
    }
    i++;
    if (i % 4 == 0)
      stack += sprintf(stack, "\n");
  }

  if (i % 4 != 0)
    stack += sprintf(stack, "\n");

  sprintf(temp, "Please send any alias submissions to %s",
	  get_config_msg("talker_email"));
  pstack_mid(temp);
  *stack++ = 0;

  tell_player(p, oldstack);
  stack = oldstack;
}

alias_library get_lib_alias(char *str)
{

  int i = 0;

  while (library[i].command)
  {

    if (!strcasecmp(str, library[i].command))
      return library[i];
    i++;
  }

  return no_library_here;
}

void library_copy(player * p, char *str)
{

  char *oldstack, *new_alias_name;
  alias_library to_be_copied;

  if (!*str)
  {
    tell_player(p, " Format: libcopy <library alias> [<Your name for alias>]\n");
    return;
  }
  new_alias_name = next_space(str);
  if (*new_alias_name)
    *new_alias_name++ = 0;

  to_be_copied = get_lib_alias(str);

  if (!to_be_copied.command || (to_be_copied.privs && !(p->residency & PSU)))
  {
    tell_player(p, " That alias not found in the library.\n");
    return;
  }
  else
  {
    oldstack = stack;
    if (*new_alias_name)
      sprintf(stack, "%s %s", new_alias_name, to_be_copied.alias_string);
    else
      sprintf(stack, "%s %s", to_be_copied.command, to_be_copied.alias_string);
    stack = end_string(stack);

    define_alias(p, oldstack);

    stack = oldstack;
  }
}

void library_examine(player * p, char *str)
{

  alias_library see_this;
  char *oldstack;

  if (!*str)
  {
    tell_player(p, " Format: Libexam <library alias to examine>\n");
    return;
  }
  see_this = get_lib_alias(str);

  if (!see_this.command || (see_this.privs && !(p->residency & PSU)))
  {

    tell_player(p, " Couldn't find that alias in the library.\n");
    return;
  }
  oldstack = stack;

  sprintf(stack, "Command: %s\nDoes   : %s\nUsage  : %s\nAuthor : %s\n",
	  see_this.command, see_this.alias_string, see_this.description, see_this.author);
  stack = end_string(stack);

  tell_player(p, oldstack);
  stack = oldstack;
}

/* well, we learned that aliases ain't perfect neither */

void blank_all_aliases(player * p, char *str)
{
  player *p2 = 0, d;

  if (*str && p->residency & ADMIN)
  {
    if (!(p2 = find_player_absolute_quiet(str)))
    {
      strncpy(d.lower_name, str, MAX_NAME - 1);
      /* we dont really have to load_player here, as the aliases
         are part of the saved_player, but i find it easier to 
         demonstrate we are working on either a player thats logged
         in or out like this
         ~phy
       */
      if (!load_player(&d))
      {
	tell_player(p, " Noone to blank aliases ...\n");
	return;
      }
      p2 = &d;
    }
  }
  else
    p2 = p;
  if (!p2->saved)
  {
    if (p == p2)
      tell_player(p, " You don't seem to have a place for an alias list.\n");
    else
      TELLPLAYER(p, " '%s' doesn't have a saved_player ...\n", p2->name);
    return;
  }
  if (p != p2 && !check_privs(p->residency, p2->residency))
  {
    tell_player(p, " You can't do that!!!\n");
    if (p2 != &d)
      TELLPLAYER(p2, " -=*> %s tried to blank all your aliases!\n", p->name);
    else
      SW_BUT(p, " -=*> %s tried to blank all of %s's aliases!\n", p->name, p2->name);
    return;
  }
  if (p != p2 && !p2->saved->alias_top)
  {
    TELLPLAYER(p, " '%s' has no aliases defined presently.\n", p2->name);
    return;
  }
  p2->saved->alias_top = 0;

  if (p == p2)
  {
    tell_player(p, "Aliases deleted.\n");
    return;
  }
  TELLPLAYER(p, " '%s' aliases have been deleted ...\n", p2->name);
  SW_BUT(p, " -=*> %s deletes all of %s's aliases ...\n", p->name, p2->name);
  LOGF("blanks", "%s blanks ALL of %s's aliases.", p->name, p2->name);
}