talker/
talker/bin/
talker/files/whois/
talker/update/
talker/update/bin/
/*
 * aliases.c
 */

#include <ctype.h>
#include <string.h>
#include <malloc.h>
#include <fcntl.h>
#include <memory.h>

#include "config.h"
#include "player.h"
#include "fix.h"
#include "aliases.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(), *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 saved_player **saved_hash[];
int	strnomatch(char *, char *, int);


/* 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.\n");
}


/* 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 list entry on compress .. auto deleted.\n");
    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);
   strncpy(l->sub, "", MAX_DESC - 3);
   
   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;
  
  oldstack = stack;
  if (*str)
    {
      tell_player(p, " Format: lsa  (lists all aliases)\n");
      return;
    }
  
  if (!p->saved)
    {
      tell_player(p, " You have no alias list to view.\n");
      return;
    }
  count = count_alias(p);
  sprintf(stack, " You are using %d of your maximum %d aliases.\n",
	  count, p->max_alias);
  stack = strchr(stack, 0);
  if (count)
    {
      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) {
		strcpy(stack, "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\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';
	    }
	}
    }
  *stack++ = 0;
  pager(p, oldstack, 0);
  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;
}

/* 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;

   l = find_alias_entry(p, str);
   if (!l)
   l = create_entry_alias(p, str);
   if (l) {
        count++;
	strncpy(l->sub, doh, MAX_DESC - 3);
   }
   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)
{
   char           *t;
   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)
{
   char           *t;
   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;
}

char	*splice_argument(player *p, char *str, char *arg, int conti) {

	static char  	BUFFER[1000], arghold[1000], strhold[1000], num[2];
	static char     RARG[10][100];
	static int  	b, a, s;
	int		no, word, r1, r2;

	if (!(conti)) {   /* reset variables */
		s=0;
		a=0;
		if (*arg)
			strncpy(arghold, arg, 999);
		else
			strncpy(arghold, "", 999);
		strncpy(strhold, str, 999);
		num[0] = 0;
		num[1] = 0;
		}
	for (b=0; b<1000; b++)
		BUFFER[b] = 0;
	b=0;
	
	while (1) {

		if (!strhold[s]) { /* true end of function */
			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] != '}') {
				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 ALWAYS (finger crossed) be in range */
			RARG[r1][r2] = 0;
				
			/* now we have args -- choose one at random */
			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;

   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);
   sprintf(stack, "%s is using %d of %s maximum %d alias list entries.\n",
      p2->name, count, their_player(p2), p2->max_alias);
   stack = strchr(stack, 0);

  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, "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\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';
	    }
	}
    }
  *stack++ = 0;
   pager(p, oldstack, 0);
   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 *oldstack;
	int i = 0;
	
	oldstack = stack;
	strcpy(stack, " Listing all aliases currently in the library.\n");
	stack = strchr(stack, 0);
	strcpy(stack, " Please submit your favorite aliases that you'd like everyone to share by internal mail to traP.\n");
	stack = strchr(stack, 0);

	while (library[i].command)
	{
	if (!(library[i].privs) || p->residency & PSU) {
	   sprintf(stack, "%s, ", library[i].command);
	   stack = strchr(stack, 0);
	   }
	i++;
	}
	stack-=2;
	*stack++ = '\n';
	*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) {

	if (!p->saved) {
		tell_player(p, "You can't -- you have no alias list anyway");
		return;
	}

	p->saved->alias_top = 0;
	tell_player(p, "Aliases deleted.\n");
}