#include "uirc.h"


#define HASH_SIZE					1000
#define MAX_SCREEN_HISTORY_LINES	1000


int readline(FILE *file, char *contents)
{
int c, i;

for(i = 0; i < 512; i++)
	{
	c = getc(file);
	if(c == EOF)
		{
		fclose(file);
		contents[i] = 0;/* EOF marker */
		return(EOF);
		}
	if(c == '\n')
		{
		contents[i] = 0;/* EOF marker */
		return(1);/* end of line */
		}
	contents[i] = c;
	}
return(0);
}


void replace(char *text, char *string, char *replace, char *result)
{
while(1)
	{
	if( (char *)strstr(text, string) == text)
		{
		*result = 0;
		strcat(result, replace);
		text += strlen(string);
		result += strlen(replace);
		}
	*result = *text;
	if(*text == 0)break;
	result++;
	text++;
	}
}/* end function replace */


char *strsave(char *s) /*save char array s somewhere*/
{
char *p, *malloc();
if(p = malloc( strlen(s) +  1) )strcpy(p, s);
return(p);
}


hash(s)/* form hash value for string s */
char *s;
{
int hashval;

for(hashval = 0; *s != '\0';) hashval += *s++;
/* sum of ascii value of characters divided by tablesize */
return(hashval % HASH_SIZE);
}


struct screen_history
	{
	char *name;
	char *def;
	struct screen_history *nxtentr;
	};
struct screen_history *screen_historytab[HASH_SIZE];


struct screen_history *lookup_screen_history(char *name)
{
struct screen_history *pa;

/*pa points to next entry*/
for(pa = screen_historytab[hash(name)]; pa != 0; pa = pa -> nxtentr)
	{
	if(strcmp(pa -> name, name) == 0) return(pa);/* found sequence entry */
	}
return(0);/*not found*/
}


struct screen_history *install_screen_history(char *name, char *def)
{
struct screen_history *pa, *lookup_screen_history();
char *strsave();
char *malloc();
int hashval;

pa = lookup_screen_history(name);/* find first, and this is any :) */

if(!pa) /* not found */
	{
	pa = (struct screen_history *) malloc( sizeof(*pa) );
	if(!pa) return(0);
	pa -> name = strsave(name);
	if(! pa -> name) return(0);
	hashval = hash(pa -> name);
	pa -> nxtentr = screen_historytab[hashval];
	screen_historytab[hashval] = pa;
	}
else /*already there*/
	{
	free (pa -> def); /* free previous definition */
	/* test for space */
	}
pa -> def = strsave(def);
if(!pa -> def) return(0);
return(pa);
}


int delete_screen_history(char *name)/* delete entry from table */
{
int hashval;
struct screen_history *pa, *pprev;/* pa points to next entry */
int i;

i = 0;
hashval = hash(name);
pa = screen_historytab[hashval];
if(! pa) return(0);/* no entry */
while(1)/* for all structures hashing to this value */
	{
	if(strcmp(name, pa -> name) == 0)/* found it */
		{
		if(i == 0)/* first entry */
			{
			screen_historytab[hashval] = pa -> nxtentr;
			}
		else/* not first one */
			{
			pprev -> nxtentr = pa -> nxtentr;
			}
		free(pa -> name);/* free name */
		free(pa -> def);/* free definition*/
		free(pa);/* free structure */
		return(1);
		}/* end found */
	pprev = pa;/* save this pointer */
	pa = pa -> nxtentr;
	if(! pa)return(0);/* end of chain of structures */
	i++;
	}/* end while all structures hashing to this value */ 
return(0);/* not found */
}/* end function delete_screen_history */


int set_screen_history(char *window, int hsize, int vsize, char *lineoftext)
{
struct screen_history *pa;
long lastline, position;
char name[80];
char def[512];
int a;
extern int global_page_back_flag; 
/* WARNING STACK PROBLEMS HERE DO NOT REMOVE temp IT IS NOT USED, BUT IF
/* REMOVED DATA IS NO LONGER STORED IN STRUCTURE IT SEEMS.
*/
char temp[512];
/* saving both text and line information in the same structure for all
/* windows
*/

/* get the last line entered */
sprintf(name, "lastline %s", window);
pa = lookup_screen_history(name);
/* if lastline not present this is the first entry */
if(! pa)
	{
	/* line 0 position 0 is the first line */
	lastline = 0;
	position = 0;
	} 
else
	{
	/* get the lastline */
	/* a is dummy for vsize and hsize */
	sscanf(pa -> def, "%ld %ld %d %d", &lastline, &position, &a, &a);
	lastline++;
	}

/* save the new line in the structure */
/* a line entry has the name format: lastline window,
/* def format: long long int
*/
sprintf(name, "lastline %s", window);

if(! global_page_back_flag) position = lastline;
/* point to next line */
sprintf(def, "%ld %ld %d %d", lastline, position, vsize, hsize);
if(! install_screen_history(name, def) ) return(0);

/* save the text entry */
/* a text entry has the name format: long window, def format: text
*/
sprintf(name, "%ld %s", lastline, window);
sprintf(def, "%s", lineoftext);
pa = install_screen_history(name, def);
if(! pa) return(0);

/* limit the amount of memory used to 1000 lines.
/* For an estimated average line length in irc of 40 characters,
/* and 2 lines a second coming in, in 24 hours you would have 
/* 24 * 3600 * 2 * 40 = 6912000 bytes so 7 Mbytes...
/* 
/* It will take a while before lastline toggles negative (its a long). 
/* So the maximum memory use possible is now 1000 x 512 = 512 Kbyte,
/* but probably more like 1000 x 40 = 40 Kbyte.
/*
/* delete entries older then 1000 lines, this will limit the memory use.
/* Nothing will be deleted if lastline is not in storage (for example neg.).
*/
sprintf(name, "%ld %s", lastline - MAX_SCREEN_HISTORY_LINES, window);
delete_screen_history(name);
return(1);
}
	

/*int print_line_at_vpos(int hsize, int vpos, char *text)
/*{
/*char c;
/*int i;

/*for(i = 0; i < hsize; i++)
/*	{
/*	print_at(i, vpos, " ");
/*	}
/* print the text */
/* print_at(0, vpos, text);
/* fill rest of line with spaces */
/* problem with ansi sequences in text, strlen is not giving the real
/* display width, but more
*/

/*}/* end function print line at */


int get_screen_history(char *window, int direction)
{
struct screen_history *pa;
long lastline, position;
char name[80];
char def[512];
int vsize, hsize;
int i;
long top;
long end;
char temp[512]; 
extern global_page_back_flag;
extern long global_screen_history_position;
int delta;

/* get the lastline */
sprintf(name, "lastline %s", window);
pa = lookup_screen_history(name);
if(! pa) return(0);
sscanf(pa -> def, "%ld %ld %d %d", &lastline, &position, &vsize, &hsize);

/*delta = 5;*/
delta = vsize; 

/* set direction depending on key */
if(direction == -1)/* page up grey */
	{
	top = position - vsize;
	end = lastline - MAX_SCREEN_HISTORY_LINES;
	if(end < 0) end = 0;
	if(top <= end) return(1); 
	if(position == vsize) return(1);/* earliest data on screen */
	position -= delta;
	if(position < vsize) position = vsize;
	/* indicate page back mode to function to_screen() and to this one */
	global_page_back_flag = 1;
	}
if(direction == 1)/* page down grey */
	{
	if(position == lastline) return(1);/* latest data on screen */
	position += delta;
	if(position < lastline)
		{
		/* indicate page back mode to function to_screen() and to this one */
		global_page_back_flag = 1;
		}
	else		
		{
		position = lastline;
		global_page_back_flag = 0;
		}		
	}
if(direction == 0)/* reset screen history */
	{
	/* prevent redraw 'flashing' screen */
	if(! global_page_back_flag) return(1);
	/* reset to last data read */
	position = lastline;
	/* reset the page back mode */
	global_page_back_flag = 0;
	}

/* print a screen of vsize */
for(i = 0; i <= vsize; i++)
	{
	sprintf(name, "%ld %s", position + i - vsize, window);
	pa = lookup_screen_history(name);
	if(! pa)
		{
		print_it("");/* empty line to clear screen area */
		}
	else print_it(pa -> def);
	}

/* the following is to slow */
/*for(i = 0; i <= vsize; i++)
/*	{
/*	sprintf(name, "%ld %s", position + i - vsize, window);
/*	pa = lookup_screen_history(name);
/*	if(! pa)
/*		{
/*		print_line_at_vpos(hsize, i, "");/* empty line to clear screen area */
/*		}
/*	else print_line_at_vpos(hsize, i, pa -> def);
/*	}
*/

/* save new position  (and old lastline) */
sprintf(name, "lastline %s", window);
sprintf(def, "%ld %ld %d %d", lastline, position, vsize, hsize);
if(! install_screen_history(name, def) ) return(0);
global_screen_history_position = lastline - position;
return(1);
}/* end function get_screen_history */


struct alias
	{
	char *name;
	char *def;
	struct alias *nxtentr;
	};
struct alias *aliastab[HASH_SIZE];

	
struct alias *lookup_alias(char *name)
{
struct alias *pa;

/*pa points to next entry*/
for(pa = aliastab[hash(name)]; pa != 0; pa = pa -> nxtentr)
	{
	if(strcmp(pa -> name, name) == 0) return(pa);/* found sequence entry */
	}
return(0);/*not found*/
}


struct alias *install_alias(char *name, char *def)
{
struct alias *pa, *lookup_alias();
char *strsave();
char *malloc();
int hashval;

pa = lookup_alias(name);/* find first, and this is any :) */

if(!pa) /* not found */
	{
	pa = (struct alias *) malloc( sizeof(*pa) );
	if(!pa) return(0);
	pa -> name = strsave(name);
	if(! pa -> name) return(0);
	hashval = hash(pa -> name);
	pa -> nxtentr = aliastab[hashval];
	aliastab[hashval] = pa;
	}
else /*already there*/
	{
	free (pa -> def); /* free previous definition */
	}
/* test for space */
pa -> def = strsave(def);
if(!pa -> def) return(0);
return(pa);
}


int delete_alias(char *s)/* delete entry from table */
{
int hashval;
struct alias *pa, *pprev;/* pa points to next entry */
int i;

/* we want the previous one (if there is a previous one), 
/* to point past this one, to the next one (if there is a next one) .
/* if this is the only one, the entry in aliastab should be removed. 
/* if there is no previous one, pa should point to the next one.
/* if there is no next one, the pa should be set to zero.
*/

i = 0;
hashval = hash(s);
pa = aliastab[hashval];
if(! pa) return(0);/* no entry */
while(1)/* for all structures hashing to this value */
	{
	if(strcmp(s, pa -> name) == 0)/* found it */
		{
/*
		fprintf(stdout, "\nFOUND it hashval=%d i=%d pa=%ld ", hashval, i, pa);
		fprintf(stdout, "pan=%ld ", pa -> nxtentr);
*/
		if(i == 0)/* first entry */
			{
			aliastab[hashval] = pa -> nxtentr;
									/* aliastab entry points to next one,
									/* this could be 0 */
/*
			fprintf(stdout, "aliastab[hashval] set to %ld", aliastab[hashval]);
*/
			}
		else/* not first one */
			{
			pprev -> nxtentr = pa -> nxtentr;
									/* the previous one points to the next one,
									/* this could be 0 */ 
/*
			fprintf(stdout, "aliastab[hashval] set to %ld", aliastab[hashval]);
*/
			}
		free(pa -> name);/* free name */
		free(pa -> def);/* free definition*/
		free(pa);/* free structure */
		return(1);
		}/* end found */
	pprev = pa;/* save this pointer */
	pa = pa -> nxtentr;
	if(! pa)return(0);/* end of chain of structures */
	i++;
	}/* end while all structures hashing to this value */ 
return(0);/* not found */
}/* end function delete_alias */


int load_aliases(char *filename)
{
char temp[512];
char pathfilename[512];
FILE *aliasesfile;
char arg0[52], arg1[512];
int a;
extern char home_dir[];

arg0[0] = 0;
arg1[0] = 0;
sprintf(pathfilename, "%s/.uirc/uirc.aliases.%s", home_dir, filename);
aliasesfile = fopen(pathfilename, "r");
if(! aliasesfile)
	{
	sprintf(temp, "Cannot open file %s for read", pathfilename);
	to_screen(temp, "");
	return(0);
	}
/* read all entries from aliases file */
while(1)
	{
	/* read a line from the uirc.aliases file */
	a = readline(aliasesfile, temp);
	if(a == EOF) break;
	if(a == 0)
		{
		sprintf(temp, "Format error in file %s (line too long?)",\
		pathfilename);
		to_screen(temp, "");	
		return(0);
		}
	/* parse the line, array arg1 is used to get the start of the deinition */
	sscanf(temp, "%s %s\n", arg0, arg1);

	/* install in ram */
	if(! install_alias(arg0, strstr(temp, arg1) ) )
		{
		sprintf(temp, "Cannot install entry from file %s in memory",\
		pathfilename);
		to_screen(temp, "");
		return(0);
		}
	}
return(1);
}/* end function load aliases */


int delete_aliases(char *name)
{
struct alias *pa;
int i;

if(strlen(name) != 0)/* specific */
	{
	delete_alias(name);
	}
else/* all */
	{
	for(i = 0; i < HASH_SIZE; i++)/* for all structures at this position */
		{
		while(1)
			{
			pa = aliastab[i];
			if(! pa) break;
			aliastab[i] = pa -> nxtentr;/* aliastab entry points to next one,
										/* this could be 0 */
			free(pa -> name);/* free name */
			free(pa -> def);/* free definition*/
			free(pa);/* free structure */
			}
		}/* end while all structures hashing to this value */ 
	}
return(0);/* not found */
}/* end function delete_aliases */


int set_alias(char *name, char *definition)
{
char temp[512];

sprintf(temp, "set_alias: name=%s", name);
to_screen(temp, "");
sprintf(temp, "set_alias: definition=%s", definition);
to_screen(temp, "");

if(! install_alias(name, definition) )return(0);
return(1);
}/* end functiom set_alias */


char *get_next_argument(char *text, char *argument)
{
char *pc;

if( sscanf(text, "%s", argument) != 1) return(0);
pc = text + strlen(argument) + 1;
return(pc);
}


int get_nth_argument(int n, char *text, char *argument)
{
int i;
char *pc;

pc = text;
for(i = 0; i <= n; i++)
	{
	pc = get_next_argument(pc, argument);
	if(!pc) break;
	}
return(1);
}/* end function get_nth_argument */


int get_alias(char *user_data)
{
/* gona replace name with def, substituting any predefined variables in def,
/* and any arguments like $0 and $1 by the corresponding fields in user_data.
/* $1- means all the arguments in user_data following $1.
/* recognised are $channel, $me, $hostname.
*/
struct alias *pa;
char definition[1024];
char output[1024];
char temp[512];
char temp2[512];
char argument[512];
char replacement[512];

extern char addressed_channel[], ircname[], hostname[];
int a, b, c, i, j;
char *pb , *pc;

/* extract the name part (first field) */
sscanf(user_data, "%s", temp);

pa = lookup_alias(temp);
if(!pa) return(0);/* not an alias */
strcpy(definition, pa -> def);

/* parse the definition */
/* have to replace $nick in action with nick, and $channel with channel,
/* $me with ircname, and $server with hostname */
replace(definition, "$channel", addressed_channel, temp);
replace(temp, "$me", ircname, temp2);
replace(temp2, "$server", hostname, definition);

pc = definition;
i = 0;
while(1)
	{
	/* parse the definition */
	pc = get_next_argument(pc, argument);
	if(!pc) break;
	if(argument[0] == '$')
		{
		/* make something like $0 to compare this field with */
		a = sscanf(argument, "$%d", &i);
		if(a)
		if(strstr(argument, "-") == 0) /* replace only this argument */
			{
			/* if anything like $0 in definition,\
			/* it is replaced with this field */ 
			/* offsett one, arg0 is alias definition */
			get_nth_argument(i + 1, user_data, replacement);
			replace(definition, argument, replacement, output); 
/*
sprintf(temp,\
"i=%d definition=%s\nuser_data=%s\nargument=%s replacement=%s output=%s",\
i, definition, user_data, argument, replacement, output);
to_screen(temp, "");
*/
			strcpy(definition, output);
			}
 		else /* replace from this argument to end of user_data */
 			{
 			replace(\
 			definition, argument, strstr(user_data, replacement), output);
 			}
 		}
	i++;
	}	
/* make it a command */
strcpy(user_data, output);
return(1);/* an alias */
}/* end function get_alias */


int show_aliases()
{
struct alias *pa;
char temp[512];
int i;

/* check ALL entries, do NOT hash */
for(i = 0; i < HASH_SIZE; i++)
	{
	for(pa = aliastab[i]; pa != 0; pa = pa -> nxtentr)	
		{
		sprintf(temp, "%s %s", pa -> name, pa -> def);
		to_screen(temp, "");
		}/* end for all structures in the chain starting from aliastab[i] */
	}/* end for all entries in aliastab */
return(1);
}/* end function show alias */


int save_aliases(char *filename, char *filename2)
{
struct alias *pa;
char temp[512];
char pathfilename[512];
FILE *aliasesfile;
int i;
extern char home_dir[];

sprintf(pathfilename, "%s/.uirc/uirc.aliases.%s", home_dir, filename);

if(strlen(filename2) == 0)
	{
	/* test if file exists */
	aliasesfile = fopen(pathfilename, "r");
	if(aliasesfile)
		{
		sprintf(temp,\
		"File %s exists!, use /save aliases %s %s to overwrite",\
		pathfilename, filename, filename);
		to_screen(temp, "");
		fclose(aliasesfile);
		return(1);
		}
	/* if not existing */
	sprintf(pathfilename, "%s/.uirc/uirc.aliases.%s", home_dir, filename);
	}
else
	/* overwrite or new filename */
	{
	sprintf(pathfilename, "%s/.uirc/uirc.aliases.%s", home_dir, filename2);
	}

/* open file for write */
aliasesfile = fopen(pathfilename, "w");
if(! aliasesfile)
	{
	sprintf(temp, "Cannot open file %s for write", pathfilename);
	to_screen(temp, "");
	return(0);
	}

/* check ALL entries, do NOT hash */
for(i = 0; i < HASH_SIZE; i++)
	{
	for(pa = aliastab[i]; pa != 0; pa = pa -> nxtentr)	
		{
		/* write to file */
		fprintf(aliasesfile, "%s %s\n", pa -> name, pa -> def);

		}/* end for all structures in the chain starting from eventtab[i] */
	}/* end for all entries in eventtab */

/* close file */
fclose(aliasesfile);
return(1);
}/* and function save aliases */


struct setup
	{
	char *name;
	char *def;
	struct setup *nxtentr;
	};
static struct setup *setuptab[1];


struct setup *lookup_setup(char *name, int sequence)
{
struct setup *pa;
int j;

j = 0;
/*pa points to next entry*/
for(pa = setuptab[0]; pa != 0; pa = pa -> nxtentr)
	{
	if(strcmp(pa -> name, name) == 0)
		{
		if(sequence == j) return(pa);/* found sequence entry */
		j++;
		}
	}
return(0);/*not found*/
}


struct setup *install_setup(char *name, char *def)
{
struct setup *pa, *lookup_setup();
char *strsave();
char *malloc();
int i;

/* pa = lookup_setup(name, 0);/* find first, and this is any :) */

/* if(!pa)	/* not found */
	{
	pa = (struct setup *) malloc( sizeof(*pa) );
	if(!pa) return(0);
	pa -> name = strsave(name);
	if(! pa -> name) return(0);
	pa -> def = strsave(def);
	if(!pa -> def) return(0);
	pa -> nxtentr = setuptab[0];
	setuptab[0] = pa;
	}
return(pa);
}


struct setup *reverse_lookup_setup(char *name, int sequence)
{
struct setup *pa, *plastentry, *allentries[256];
int i, j;

/* want the first entry in the setupfile to be the first to be tried */
/* there may be smarter ways, but I have tried ! */
/* load all structure addresses in array */
i = 0;
for(pa = setuptab[0]; pa != 0; pa = pa -> nxtentr)
	{
	if(i >= 256)
		{
		to_screen("reverse_lookup_setup: To many entries in uirc.setup", "");
		return(0);
		}
	allentries[i] = pa;
	if(pa) plastentry = pa;
	i++;
	}
/* read the array from the end */
j = 0;
for(i = i - 1; i >= 0; i--)
	{
	pa = allentries[i];
	if(strcmp(pa -> name, name) == 0)
		{
		if(sequence == j) return(pa);
		j++;
		}
	}
return(0);/*not found*/
}


int set_setup(char *name, char *def)
{
struct setup *install_setup();
if(! install_setup(name, def) ) return(0);
return(1);
}

int get_setup(char *name, char *def, int sequence)
{
struct setup *pa, *lookup_setup(), *install_setup();

pa = reverse_lookup_setup(name, sequence);
if(! pa) return(0);
strcpy(def, pa -> def);
return(1);
}


struct ignore
	{
	char *nick_user_host;
	unsigned int status;
	struct ignore *nxtentr;
	};
static struct ignore *ignoretab[1];


struct ignore *lookup_ignore_exact(char *nick_user_host)
{
struct ignore *pa;

for(pa = ignoretab[0]; pa != 0; pa = pa -> nxtentr)
	{
	if(strcmp(pa -> nick_user_host, nick_user_host) == 0) return(pa);
	}
return(0);
}


struct ignore *lookup_ignore(char *prefix)
{
struct ignore *pa;
char servername_or_nick[256], user[256], host[256];
char i_servername_or_nick[256], i_user[256], i_host[256];
int a, i, j;
int c;
int t1, t2, t3;
char temp[256];

servername_or_nick[0] = 0;
user[0] = 0;
host[0] = 0;
i_user[0] = 0;
i_host[0] = 0;

/* pa points to next entry */
for(pa = ignoretab[0]; pa != 0; pa = pa -> nxtentr)
	{
	/* split the prefix */
	j = 0;
	for(i = 0; i < strlen(prefix); i++)
		{
		c = prefix[i];
		if(c == '!') break;/* start of user */
		servername_or_nick[j] = c;
		if(c == 0)break;/* end of prefix */
		j++;
		}
	servername_or_nick[j] = 0;/* string termination */
	if(c == '!')/* user [@host] follows */
		{
		i++;/* scip the '!' */
		j = 0;
		for(i = i; i < strlen(prefix); i++)
			{
			c = prefix[i]; 	
			if(c == '@') break;/* start of host */
			user[j] = c;
			if(c = 0) break;/* end of prefix */
			j++;
			}
		user[j] = 0;/* string termination */
		}
	if(c == '@')/* @host */
		{
		i++;/* scip the '@' */
		j = 0;
		for(i = i; i < strlen(prefix); i++)
			{
			c = prefix[i];
			host[j] = c;
			if(c == 0) break;/* end of prefix */
			j++;
			}
		host[j] = 0;/* string termination */
		}/* end of host */
/*
sprintf(temp, "prefix=%s servername_or_nick=%s user=%s host=%s",\
prefix, servername_or_nick, user, host);
to_screen(temp, "");
*/
	/* split the nick_user_host */
	j = 0;
	for(i = 0; i < strlen(pa -> nick_user_host); i++)
		{
		c = pa -> nick_user_host[i];
		if(c == '!') break;/* start of user */
		i_servername_or_nick[j] = c;
		if(c == 0) break;/* end of prefix */
		j++;
		}
	i_servername_or_nick[j] = 0;/* string termination */
	if(c == '!')/* user [@host] follows */
		{
		i++;/* scip the '!' */
		j = 0;
		for(i = i; i < strlen(pa -> nick_user_host); i++)
			{
			c = pa -> nick_user_host[i]; 	
			if(c == '@') break;/* start of host */
			i_user[j] = c;
			if(c = 0) break;/* end of prefix */
			j++;
			}
		i_user[j] = 0;/* string termination */
		}
	if(c == '@')/* @host */
		{
		i++;/* scip the '@' */
		j = 0;
		for(i = i; i < strlen(pa -> nick_user_host); i++)
			{
			c = pa -> nick_user_host[i];
			i_host[j] = c;
			if(c == 0) break;/* end of prefix */
			j++;
			}
		i_host[j] = 0;/* string termination */
		}/* end of i_host */
/*
sprintf(temp, "nick_user_host=%s i_servername_or_nick=%s i_user=%s i_host=%s",\
pa -> nick_user_host, i_servername_or_nick, i_user, i_host);
to_screen(temp, "");
*/
	/* in the database (nick_user_host) is either:
	/* nick
	/* nick!user
	/* nick!user@host	
	/* or any wildcards, like *!user@host, or *!*!host or *!*@*
	*/
	/* test host */
	if(i_host[0] != 0)/* host specified */
		{
/*
sprintf(temp, "testing host: i_host=%s, host=%s", i_host, host);
to_screen(temp, "");		
*/
		t1 = 0;
		if(strcmp(i_host, "*") == 0) t1 = 1;
		if(strcmp(i_host, host) == 0) t1 = 1; 
		}	
	else t1 = 1;
	/* test user */
	if(i_user[0] != 0)/* user specified */
		{
		t2 = 0;
/*
sprintf(temp, "testing user: i_user=%s, user=%s", i_user, user);
to_screen(temp, "");		
*/
		if(strcmp(i_user, "*") == 0) t2 = 1;
		if(strcmp(i_user, user) == 0) t2 = 1;
		}
	else t2 = 1;
	/* test nick */
/*
sprintf(temp, "testing nick: i_servername_or_nick=%s, servername_or_nick=%s",\
i_servername_or_nick, servername_or_nick);
to_screen(temp, "");		
*/
	if(i_servername_or_nick[0] != 0)/* nick specified */
		{
		t3 = 0;
		if(strcmp(i_servername_or_nick, "*") == 0) t3 = 1;
		if(strcmp(i_servername_or_nick, servername_or_nick) == 0) t3 = 1;
		}
	else t3 = 1;	
	if(t1 && t2 && t3)	
		{
		return(pa);/* found it */
		}

	}/* end for */
return(0);/* not found */
}/* end function lookup_ignore */


struct ignore *install_ignore(char *nick_user_host)
{
struct ignore *pa, *lookup_ignore();
char *strsave();
char *malloc();

pa = lookup_ignore_exact(nick_user_host);

if(!pa)	/* not found */
	{
	pa = (struct ignore *)malloc(sizeof(*pa));
	if(!pa)return(0);
	pa -> nick_user_host = strsave(nick_user_host);
	if(! pa -> nick_user_host) return(0);
	pa -> status = NONE;
	pa -> nxtentr = ignoretab[0];
	ignoretab[0] = pa;
	}
return(pa);
}


int delete_ignore(char *nick_user_host)/* delete entry from table */
{
struct ignore *pa, *pprev;/* pa points to next entry */
int i;

/* we want the previous one (if there is a previous one), 
/* to point past this one, to the next one (if there is a next one) .
/* if this is the only one, the entry in ignoretab should be removed. 
/* if there is no previous one, pa should point to the next one.
/* if there is no next one, the pa should be set to zero.
*/

pa = ignoretab[0];
i = 0;
if(! pa)return(0);/* no entry */
while(1)/* for all structures */
	{
	if(strcmp(pa -> nick_user_host, nick_user_host) == 0)
		{
		if(i == 0)/* first entry */
			{
			ignoretab[0] = pa -> nxtentr;
									/* ignoretab entry points to next one,
									/* this could be 0 */
			}
		else/* not first one */
			{
			pprev -> nxtentr = pa -> nxtentr;
									/* the previous one points to the next one,
									/* this could be 0 */ 
			}
		free(pa -> nick_user_host);/* free name */
		free(pa);/* free structure */
/*		to_screen("STUCTURE FREED", "");*/
		return(1);
		}/* end found */
	pprev = pa;/* save this pointer */
	pa = pa -> nxtentr;
	if(! pa)return(0);/* end of chain of structures */
	i++;
	}/* end while all structures */ 
return(0);/* not found */
}/* end function delete_ignore */


int set_ignore_nick(char *nick_user_host, char *status)
{
struct ignore *pa, *lookup_ignore();
char temp[80];
char temp2[80];
char *strsave();

/* test if nick in database */
pa = lookup_ignore_exact(nick_user_host);

/* if not, add nick to database */
if(! pa) pa = install_ignore(nick_user_host);

/* if nick cannot be added to database return error */
if(!pa)
	{
	sprintf(temp, "set_ignore_nick: cannot add nick %s to database",\
	nick_user_host); 
	to_screen(temp, "");
	return(0);
	}
if(status[0] == '-')
	{
	/* loose the leading '-' */
	sprintf(temp2, "%s", &status[1]);
	/* convert status in string to integer, and modify database */
	if(strcmp(temp2, "all") == 0)pa -> status = 0;
	else if(strcmp(temp2, "ctcp") == 0)pa -> status &= ALL - CTCP;
	else if(strcmp(temp2, "public") == 0)pa -> status &= ALL - PUBLIC;
	else if(strcmp(temp2, "invites") == 0)pa -> status &= ALL - INVITES;
	else if(strcmp(temp2, "notices") == 0)pa -> status &= ALL - NOTICES;
	else if(strcmp(temp2, "messages") == 0)pa -> status &= ALL - MESSAGES;
	else if(strcmp(temp2, "wallops") == 0)pa -> status &= ALL - WALLOPS;
	else if(strcmp(temp2, "notes") == 0)pa -> status &= ALL - NOTES;
	else
		{
		sprintf(temp,\
		"%s not a valid argument, type /ignore to show valid ones", status);
		to_screen(temp, "");
		return(1);
		}
	sprintf(temp, "No longer ignoring %s from %s status=%d",\
	temp2, nick_user_host, pa -> status); 

	to_screen(temp, "");
	}
else
	{
	/* convert status in string to integer, and modify database */
	if(strcmp(status, "none") == 0)pa -> status = NONE;
	else if(strcmp(status, "all") == 0)pa -> status = ALL;
	else if(strcmp(status, "ctcp") == 0)pa -> status |= CTCP;
	else if(strcmp(status, "public") == 0)pa -> status |= PUBLIC;
	else if(strcmp(status, "invites") == 0)pa -> status |= INVITES;
	else if(strcmp(status, "notices") == 0)pa -> status |= NOTICES;
	else if(strcmp(status, "messages") == 0)pa -> status |= MESSAGES;
	else if(strcmp(status, "wallops") == 0)pa -> status |= WALLOPS;
	else if(strcmp(status, "notes") == 0)pa -> status |= NOTES;
	else
		{
		sprintf(temp,\
		"%s not a valid argument, type /ignore to show valid ones", status);
		to_screen(temp, "");
		return(1);
		}
	sprintf(temp, "Ignoring %s from %s", status, nick_user_host); 
	to_screen(temp, "");
	}

/* if pa -> status is 0 nothing is ignored,
/* delete entry for nick_user_host from database */
if(pa -> status == NONE) delete_ignore(nick_user_host);

return(1);/* ok */
}


int get_ignore_nick(char *prefix)
{
struct ignore *pa, *lookup_ignore();
char temp[80];
int result;
	
/* test if nick in database */
pa = lookup_ignore(prefix);
if(! pa) return(0);/* nick not found */
result = (int)pa -> status;
return(result);
}
 

int get_all_ignore_nick(char *all)
{
struct ignore *pa;

all[0] = 0;
for(pa = ignoretab[0]; pa != 0; pa = pa -> nxtentr)
	{
	if(pa -> status)
		{
		if(pa != ignoretab[0]) strcat(all, ",");
		else strcpy(all, "ig ");
		strcat(all, pa -> nick_user_host);
		}
	}
return(1);
}


int show_ignores()
{
struct ignore *pa;
char temp[512];
char status[512];

for(pa = ignoretab[0]; pa != 0; pa = pa -> nxtentr)
	{
	status[0] = 0;
	if(pa -> status == 65535) strcat(status, "ALL");
	else
		{
		if(pa -> status & CTCP) strcat(status, "CTCP ");
		if(pa -> status & PUBLIC) strcat(status, "PUBLIC ");
		if(pa -> status & INVITES) strcat(status, "INVITES ");
		if(pa -> status & NOTICES) strcat(status, "NOTICES ");
		if(pa -> status & MESSAGES) strcat(status, "MESSAGES ");
		if(pa -> status & WALLOPS) strcat(status, "WALLOPS ");
		if(pa -> status & NOTES) strcat(status, "NOTES ");
		}
	sprintf(temp, "%s %s", pa -> nick_user_host, status);
	to_screen(temp, "");
	}
return(1);
}


int load_ignores(char *filename)
{
struct ignore *pa;
char temp[512];
char pathfilename[512];
char nick_user_host[512];
unsigned status;
FILE *ignoresfile;
int a;
extern char home_dir[];

sprintf(pathfilename, "%s/.uirc/uirc.ignores.%s", home_dir, filename);
ignoresfile = fopen(pathfilename, "r");
if(! ignoresfile)
	{
	sprintf(temp, "Cannot open file %s for read", pathfilename);
	to_screen(temp, "");
	return(0);
	}
/* read all entries from ignores file */
while(1)
	{
	/* read a line from the uirc.ignores file */
	a = readline(ignoresfile, temp);
	if(a == EOF) break;
	if(a == 0)
		{
		sprintf(temp, "Format error in file %s (line too long?)",\
		pathfilename);
		to_screen(temp, "");	
		return(0);
		}
	/* parse the line */
	a = sscanf(temp, "%s %u\n", nick_user_host, &status);
/*
sprintf(temp, "nuh=%s stat=%u", nick_user_host, status);
to_screen(temp, "");
*/
	/* install in ram */
	pa = install_ignore(nick_user_host);
	if(!pa)
		{
		sprintf(temp, "Cannot install entry from file %s in memory",\
		pathfilename);
		to_screen(temp, "");
		return(0);
		}
	pa -> status = status;
	}
return(1);
}/* end function load ignores */


int save_ignores(char *filename, char *filename2)
{
struct ignore *pa;
char temp[512];
char pathfilename[512];
FILE *ignoresfile;
extern char home_dir[];

sprintf(pathfilename, "%s/.uirc/uirc.ignores.%s", home_dir, filename);

if(strlen(filename2) == 0)
	{
	/* test if file exists */
	ignoresfile = fopen(pathfilename, "r");
	if(ignoresfile)
		{
		sprintf(temp,\
		"File %s exists!, use /save ignores %s %s to overwrite",\
		pathfilename, filename, filename);
		to_screen(temp, "");
		fclose(ignoresfile);
		return(1);
		}
	/* if not existing */
	sprintf(pathfilename, "%s/.uirc/uirc.ignores.%s", home_dir, filename);
	}
else
	/* overwrite or new filename */
	{
	sprintf(pathfilename, "%s/.uirc/uirc.ignores.%s", home_dir, filename2);
	}

/* open file for write */
ignoresfile = fopen(pathfilename, "w");
if(! ignoresfile)
	{
	sprintf(temp, "Cannot open file %s for write", pathfilename);
	to_screen(temp, "");
	return(0);
	}

/* check ALL entries, do NOT hash */
for(pa = ignoretab[0]; pa != 0; pa = pa -> nxtentr)	
	{
	/* get data and combine, add a preceeding slash and a '\n'
	/* this is so you can do /show ignores and then paste with gpm
	/* into the command line and modify that entry.
	*/
	sprintf(temp, "%s %d\n", pa -> nick_user_host, pa -> status);
	/* write to file */
	fprintf(ignoresfile, "%s", temp);

	}/* end for all structures in the chain starting from ignoretab[0] */

/* close file */
fclose(ignoresfile);
return(1);
}/* end function save_ignores */


int delete_ignores(char *definition)
{
struct ignore *pa, *pprev;/* pa points to next entry */

if(strlen(definition) != 0)/* specific */
	{
	delete_ignore(definition);
	}
else /* all */
	{
	while(1)
		{
		pa = ignoretab[0];
		if(! pa) break;
		ignoretab[0] = pa -> nxtentr;/* ignoretab entry points to next one,
										/* this could be 0 */
		free(pa -> nick_user_host);/* free name */
		free(pa);/* free structure */
		}/* end while all structures */ 
	}
return(1);
}/* end function delete_ignores */


struct color
	{
	char *nick;
	char *color;
	struct color *nxtentr;
	};
static struct color *colortab[1];


struct color *lookup_color(char *nick)
{
struct color *pa;

/*pa points to next entry*/
for(pa = colortab[0]; pa != 0; pa = pa -> nxtentr)
	{
	if(strcmp(pa -> nick, nick) == 0)
		{
		return(pa);/* found it */
		}
	}
return(0);/*not found*/
}


struct color *install_color(char *nick, char *color)
{
struct color *pa, *lookup_color();
char *strsave();
char *malloc();

pa = lookup_color(nick);

if(!pa)	/* not found */
	{
	pa = (struct color *)malloc(sizeof(*pa));
	if(!pa)return(0);
	pa -> nick = strsave(nick);
	if(! pa -> nick) return(0);
	pa -> color = strsave(color);
	if(! pa -> color) return(0);
	pa -> nxtentr = colortab[0];
	colortab[0] = pa;
	}
else	/*already there*/
	{
	free (pa -> color); /* free previous definition */
	}
/* test for space */
pa -> color = strsave(color);
if(!pa -> color)return(0);
return(pa);
}


int delete_color(char *nick)/* delete entry from table */
{
struct color *pa, *pprev;/* pa points to next entry */
int i;

/* we want the previous one (if there is a previous one), 
/* to point past this one, to the next one (if there is a next one) .
/* if this is the only one, the entry in colortab should be removed. 
/* if there is no previous one, pa should point to the next one.
/* if there is no next one, the pa should be set to zero.
*/

pa = colortab[0];
i = 0;
if(! pa)return(0);/* no entry */
while(1)/* for all structures */
	{
	if(strcmp(pa -> nick, nick) == 0)
		{
		if(i == 0)/* first entry */
			{
			colortab[0] = pa -> nxtentr;
									/* colortab entry points to next one,
									/* this could be 0 */
			}
		else/* not first one */
			{
			pprev -> nxtentr = pa -> nxtentr;
									/* the previous one points to the next one,
									/* this could be 0 */ 
			}
		free(pa -> nick);/* free name */
		free(pa -> color);
		free(pa);/* free structure */
/*		to_screen("STUCTURE FREED", "");*/
		return(1);
		}/* end found */
	pprev = pa;/* save this pointer */
	pa = pa -> nxtentr;
	if(! pa)return(0);/* end of chain of structures */
	i++;
	}/* end while all structures */ 
return(0);/* not found */
}/* end function delete_color */


int set_color_nick(char *nick, char *color)
{
struct color *pa, *lookup_color();
char temp[80];
int a, i;
char *strsave();

/* test for correct color argument */
if( !string_to_color(color, &a) ) return(1);

/* if color is "OFF" remove nick from database,
/* so that last_addressed coloring can take over again (uirc.c).
*/
if(a == OFF)
	{
	delete_color(nick);
	return(1);
	}

/* add nick to database */
pa = install_color(nick, color);
/* if nick cannot be added to database return error */
if(!pa)
	{
	sprintf(temp, "set_color_nick: cannot add nick %s to database",\
	nick); 
	to_screen(temp, "");
	return(0);
	}
return(1);
}


int get_color_nick(char *nick, int *color)
{
struct color *pa, *lookup_color();
char temp[80];
	
/* test if nick in database */
pa = lookup_color(nick);
if(! pa)
	{
	return(0);/* nick not found */
	}
string_to_color(pa -> color, color);
return(1);
}/* end function get_color_nick */


int show_colors()
{
struct color *pa;
char temp[512];
char color[80];

/*pa points to next entry*/
for(pa = colortab[0]; pa != 0; pa = pa -> nxtentr)
	{
	sprintf(temp, "%s %s", pa -> nick, pa -> color);	
	to_screen(temp, "");
	}
return(1);
}/* end function show colors */


int load_colors(char *filename)
{
struct color *pa;
char temp[512];
char pathfilename[512];
char nick[512];
char color_as_string[512];
FILE *colorsfile;
int a;
char *strsave();
extern char home_dir[];

sprintf(pathfilename, "%s/.uirc/uirc.colors.%s", home_dir, filename);
colorsfile = fopen(pathfilename, "r");
if(! colorsfile)
	{
	sprintf(temp, "Cannot open file %s for read", pathfilename);
	to_screen(temp, "");
	return(0);
	}
/* read all entries from colors file */
while(1)
	{
	/* read a line from the uirc.colors file */
	a = readline(colorsfile, temp);
	if(a == EOF) break;
	if(a == 0)
		{
		sprintf(temp, "Format error in file %s (line too long?)",\
		pathfilename);
		to_screen(temp, "");	
		return(0);
		}
	/* parse the line */
	a = sscanf(temp, "%s %s\n", nick, color_as_string);
/*
sprintf(temp, "nick=%s coloras=%s", nick, color_as_string);
to_screen(temp, "");
*/
	/* install in ram */
	pa = install_color(nick, color_as_string);
	if(!pa)
		{
		sprintf(temp, "Cannot install entry from file %s in memory",\
		pathfilename);
		to_screen(temp, "");
		return(0);
		}
	}/* end while all lines in uirc.colors. */
return(1);
}/* end function load colors */


int save_colors(char *filename, char *filename2)
{
struct color *pa;
char temp[512];
char pathfilename[512];
FILE *colorsfile;
extern char home_dir[];

sprintf(pathfilename, "%s/.uirc/uirc.colors.%s", home_dir, filename);

if(strlen(filename2) == 0)
	{
	/* test if file exists */
	colorsfile = fopen(pathfilename, "r");
	if(colorsfile)
		{
		sprintf(temp,\
		"File %s exists!, use /save colors %s %s to overwrite",\
		pathfilename, filename, filename);
		to_screen(temp, "");
		fclose(colorsfile);
		return(1);
		}
	/* if not existing */
	sprintf(pathfilename, "%s/.uirc/uirc.colors.%s", home_dir, filename);
	}
else
	/* overwrite or new filename */
	{
	sprintf(pathfilename, "%s/.uirc/uirc.colors.%s", home_dir, filename2);
	}

/* open file for write */
colorsfile = fopen(pathfilename, "w");
if(! colorsfile)
	{
	sprintf(temp, "Cannot open file %s for write", pathfilename);
	to_screen(temp, "");
	return(0);
	}

/* check ALL entries, do NOT hash */
for(pa = colortab[0]; pa != 0; pa = pa -> nxtentr)	
	{
	/* get data and combine, add a preceeding slash and a '\n'
	/* this is so you can do /show colors and then paste with gpm
	/* into the command line and modify that entry.
	*/
	sprintf(temp, "%s %s\n", pa -> nick, pa -> color);
	/* write to file */
	fprintf(colorsfile, "%s", temp);

	}/* end for all structures in the chain starting from colortab[0] */

/* close file */
fclose(colorsfile);
return(1);
}/* end  function save_colors */


int delete_colors(char *nick)
{
struct color *pa;

if(strlen(nick) != 0) delete_color(nick);/* specific */
else /* all */
	{
	while(1)
		{
		pa = colortab[0];
		if(! pa) break;
		colortab[0] = pa -> nxtentr;/* colortab entry points to next one,
									/* this could be 0 */
		free(pa -> nick);/* free name */
		free(pa -> color);/* free color */
		free(pa);/* free structure */
		}/* end while all structures */ 
	}
return(1);
}/* end function delete_colors */


struct channel
	{
	char *channel;
	struct channel *nxtentr;
	};
struct channel *channeltab[1];	


struct channel *lookup_channel(char *channel)
{
struct channel *pa;

/*pa points to next entry*/
for(pa = channeltab[0]; pa != 0; pa = pa -> nxtentr)
	{
	if(strcmp(pa -> channel, channel) == 0)
		{
		return(pa);/* found channel entry */
		}
	}
return(0);/*not found*/
}


struct channel *install_channel(char *channel)
{
struct channel *pa, *lookup_channel();
char *strsave();
char *malloc();
int i;

pa = lookup_channel(channel);

if(!pa)	/* not found */
	{
	pa = (struct channel *) malloc( sizeof(*pa) );
	if(! pa) return(0);
	pa -> channel = strsave(channel);
	if(! pa -> channel) return(0);
	pa -> nxtentr = channeltab[0];
	channeltab[0] = pa;
	}
return(pa);
}


struct channel *delete_channel(char *channel)
{
struct channel *pa, *pprev;/* pa points to next entry */
int i;

/* we want the previous one (if there is a previous one), 
/* to point past this one, to the next one (if there is a next one) .
/* if this is the only one, the entry in channeltab should be removed. 
/* if there is no previous one, pa should point to the next one.
/* if there is no next one, the pa should be set to zero.
*/

pa = channeltab[0];
i = 0;
if(! pa)return(0);/* no entry */
while(1)/* for all structures */
	{
	if(strcmp(pa -> channel, channel) == 0)
		{
		if(i == 0)/* first entry */
			{
			channeltab[0] = pa -> nxtentr;
									/* channeltab entry points to next one,
									/* this could be 0 */
			}
		else/* not first one */
			{
			pprev -> nxtentr = pa -> nxtentr;
									/* the previous one points to the next one,
									/* this could be 0 */ 
			}
		free(pa -> channel);/* free name */
		free(pa);/* free structure */
/*		to_screen("STUCTURE FREED", "");*/
		return(pa);
		}/* end found */
	pprev = pa;/* save this pointer */
	pa = pa -> nxtentr;
	if(! pa)return(0);/* end of chain of structures */
	i++;
	}/* end while all structures */ 
return(0);/* not found */
}


int get_all_channels(char all_channels[])
{
struct channel *pa;
int i;
int j;

j = 0;
all_channels[0] = 0;
for(pa = channeltab[0]; pa != 0; pa = pa -> nxtentr)
	{
	if(j) strcat(all_channels, ",");
	strcat(all_channels, pa -> channel);
	j++;
	}
return(1);/*not found*/
}/* end funcion get all channels */


int add_channel(char channel[])
{
struct channel *install_channel();

if(! install_channel(channel) )return(0);
return(1);
}/* end function add channel */


int substract_channel(char channel[])
{
struct channel *delete_channel();

if(! delete_channel(channel) )return(0);
return(1);
}/* end function substract_channel */


int joined_channel(char channel[])
{
struct channel *lookup_channel();

if(! lookup_channel(channel) )return(0);
return(1);
}/* end function joined channel */


int log_channel(char channel[], char data[])
{
char temp[512];
FILE *logfile;
int i;
extern char home_dir[];

/* convert channel to lower case, sometimes #chat, #Chat, etc.,
/* do not want separate logfiles for that.
*/
for(i = 0; i < 80; i++)
	{
	channel[i] = tolower(channel[i]);
	if(channel[i] == 0) break;/* string terminator */
	}
/* channel[i] = 0;/* string termination */

/* combine filename */
sprintf(temp, "%s/.uirc/irc.log.%s", home_dir, channel);

/* open the log file for append, if not exist create it */
logfile = fopen(temp, "a");
if(! logfile) 
	{
/*	tputs_x( tgoto(CM, 0, LI - 3) ); */
	fprintf(stderr, "\nCannot append to or create logfile %s\n", temp);
	/* return error */
	return(0);
	} 

/* write to log file */
fprintf(logfile, ">%s\n", data);

/* close the logfile */
fclose(logfile);

/* return ok */
return(1);
}/* end funcion log_channel */


struct event
	{
	char *name;
	char *def;
	struct event *nxtentr;/*next entry to table*/
	};
static struct event *eventtab[HASH_SIZE];/*pointer table*/


struct event *lookup_event(char *s)  /*look for s in event */
{
struct event *pa;
/*pa points to next entry*/
for(pa = eventtab[hash(s)]; pa != 0; pa = pa -> nxtentr)
	{
	if(strcmp(s, pa -> name) == 0)return(pa);/* found it */
	}
return(0);/*not found*/
}


struct event *install_event(char *name, char *def)
/* put (name, def) in eventtab */
{
struct event *pa, *lookup_event();
char *strsave();
char *malloc();

int hashval;
pa = lookup_event(name);
if(!pa)	/* not found */
	{
	pa = (struct event *)malloc(sizeof(*pa));
	if(!pa)return(0);
	pa -> name = strsave(name);
	if(! pa -> name)return(0);
	hashval = hash(pa -> name);
	pa -> nxtentr = eventtab[hashval];
	eventtab[hashval] = pa;
	}
else	/*already there*/
	{
	free (pa -> def); /* free previous definition */
	}
/* test for space */
pa -> def = strsave(def);
if(!pa -> def)return(0);
return(pa);
}


int delete_event(char *s)/* delete entry from table */
{
int hashval;
struct event *pa, *pprev;/* pa points to next entry */
int i;

/* we want the previous one (if there is a previous one), 
/* to point past this one, to the next one (if there is a next one) .
/* if this is the only one, the entry in eventtab should be removed. 
/* if there is no previous one, pa should point to the next one.
/* if there is no next one, the pa should be set to zero.
*/

i = 0;
hashval = hash(s);
pa = eventtab[hashval];
if(! pa)return(0);/* no entry */
while(1)/* for all structures hashing to this value */
	{
	if(strcmp(s, pa -> name) == 0)/* found it */
		{
/*
		fprintf(stdout, "\nFOUND it hashval=%d i=%d pa=%ld ", hashval, i, pa);
		fprintf(stdout, "pan=%ld ", pa -> nxtentr);
*/
		if(i == 0)/* first entry */
			{
			eventtab[hashval] = pa -> nxtentr;
									/* eventtab entry points to next one,
									/* this could be 0 */
/*
			fprintf(stdout, "eventtabb[hashval] set to %ld", eventtab[hashval]);
*/
			}
		else/* not first one */
			{
			pprev -> nxtentr = pa -> nxtentr;
									/* the previous one points to the next one,
									/* this could be 0 */ 
/*
			fprintf(stdout, "eventtabb[hashval] set to %ld", eventtab[hashval]);
*/
			}
		free(pa -> name);/* free name */
		free(pa -> def);/* free definition*/
		free(pa);/* free structure */
		return(1);
		}/* end found */
	pprev = pa;/* save this pointer */
	pa = pa -> nxtentr;
	if(! pa)return(0);/* end of chain of structures */
	i++;
	}/* end while all structures hashing to this value */ 
return(0);/* not found */
}/* end function delete_event */


int set_event(\
char event[], char channel[], char nick[], int serial, char action[]\
)
{
char combined[80];
char temp[512];

/*
sprintf(temp, "set_event: event=%s channel=%s nick=%s serial=%d",\
event, channel, nick, serial);
to_screen(temp, "");
sprintf(temp, "action=%s", action);
to_screen(temp, "");
*/

sprintf(combined, "/on %s %s %s %d", event, channel, nick, serial);

sprintf(temp, "set_event: name=%s", combined);
to_screen(temp, "");
sprintf(temp, "set_event: action=%s", action);
to_screen(temp, "");

if(! install_event(combined, action) )return(0);
return(1);
}/* end function set event */


show_events()
{
struct event *pa;
char temp[512];
int i;

/* check ALL entries, do NOT hash */
for(i = 0; i < HASH_SIZE; i++)
	{
	for(pa = eventtab[i]; pa != 0; pa = pa -> nxtentr)	
		{
		sprintf(temp, "%s %s", pa -> name, pa -> def);
		to_screen(temp, "");
		}/* end for all structures in the chain starting from eventtab[i] */
	}/* end for all entries in eventtab */
return(1);
}/* end function show_events */


int load_events(char *filename)
{
char event[512];
char channel[512];
char nick[512];
int serial;
char help[512];
char action[512];
char combined[512];
char temp[512];
char pathfilename[512];
FILE *eventsfile;
int a;
extern char home_dir[];

sprintf(pathfilename, "%s/.uirc/uirc.events.%s", home_dir, filename);
eventsfile = fopen(pathfilename, "r");
if(! eventsfile)
	{
	sprintf(temp, "Cannot open file %s for read", pathfilename);
	to_screen(temp, "");
	return(0);
	}
/* read all entries from events file */
while(1)
	{
	/* read a line from the uirc.events file */
	a = readline(eventsfile, temp);
	if(a == EOF) break;
	if(a == 0)
		{
		sprintf(temp, "Format error in file %s (line too long?)",\
		pathfilename);
		to_screen(temp, "");	
		return(0);
		}
	/* parse the line, array help is used to get the start of the action */
	sscanf(temp, "/on %s %s %s %d %s\n", event, channel, nick, &serial, help);
	sprintf(combined, "/on %s %s %s %d", event, channel, nick, serial);

	/* copy the action field */
	strcpy(action, strstr(temp, help) );
/*
sprintf(temp, "combined=%s, action=%s", combined, action);
to_screen(temp, "");
*/
	/* install in ram */
	if(! install_event(combined, action) )
		{
		sprintf(temp, "Cannot install entry from file %s in memory",\
		pathfilename);
		to_screen(temp, "");
		return(0);
		}
	}
return(1);
}/* end function load events */


int save_events(char *filename, char *filename2)
{
struct event *pa;
char temp[512];
char pathfilename[512];
FILE *eventsfile;
int i;
extern char home_dir[];

sprintf(pathfilename, "%s/.uirc/uirc.events.%s", home_dir, filename);

if(strlen(filename2) == 0)
	{
	/* test if file exists */
	eventsfile = fopen(pathfilename, "r");
	if(eventsfile)
		{
		sprintf(temp,\
		"File %s exists!, use /save events %s %s to overwrite",\
		pathfilename, filename, filename);
		to_screen(temp, "");
		fclose(eventsfile);
		return(1);
		}
	/* if not existing */
	sprintf(pathfilename, "%s/.uirc/uirc.events.%s", home_dir, filename);
	}
else
	/* overwrite or new filename */
	{
	sprintf(pathfilename, "%s/.uirc/uirc.events.%s", home_dir, filename2);
	}

/* open file for write */
eventsfile = fopen(pathfilename, "w");
if(! eventsfile)
	{
	sprintf(temp, "Cannot open file %s for write", pathfilename);
	to_screen(temp, "");
	return(0);
	}

/* check ALL entries, do NOT hash */
for(i = 0; i < HASH_SIZE; i++)
	{
	for(pa = eventtab[i]; pa != 0; pa = pa -> nxtentr)	
		{
		/* get data and combine, add a preceeding slash and a '\n'
		/* this is so you can do /show events and then paste with gpm
		/* into the command line and modify that entry.
		*/
		sprintf(temp, "%s %s\n", pa -> name, pa -> def);

		/* write to file */
		fprintf(eventsfile, "%s", temp);

		}/* end for all structures in the chain starting from eventtab[i] */
	}/* end for all entries in eventtab */

/* close file */
fclose(eventsfile);
return(1);
}/* end function save events */


int delete_events(\
char *event, char *channel, char *nick, char *serial)
{
struct event *pa;
int i;
char definition[80];

if(strlen(event) != 0)/* specific */
	{
	sprintf(definition, "/on %s %s %s %s", event, channel, nick, serial);
to_screen(definition, "");
	delete_event(definition);
	}
else/* all */
	{
	for(i = 0; i < HASH_SIZE; i++)/* for all structures at this positione */
		{
		while(1)
			{
			pa = eventtab[i];
			if(! pa) break;
			eventtab[i] = pa -> nxtentr;/* eventtab entry points to next one,
										/* this could be 0 */
			free(pa -> name);/* free name */
			free(pa -> def);/* free definition*/
			free(pa);/* free structure */
			}
		}/* end while all structures hashing to this value */ 
	}
return(0);/* not found */
}/* end function delete_events */


int get_event(\
char event[], char channel[], char nick[], char params[], int socketfd\
)
{
char combined[80];
int serial;
struct event *pa;
char id_arg0[512], id_arg1[512], id_arg2[512], id_arg3[512];
int id_serial;
int i;
char temp[512], temp1[512], temp2[512];
char action[52];
extern int listen_flag;
extern char ircname[], hostname[];
 
if(! listen_flag) return;

for(serial = 0; serial < 3; serial++)
	{
	sprintf(combined, "/on %s %s %s %d", event, channel, nick, serial);

	/* check ALL entries, do NOT hash */
	for(i = 0; i < HASH_SIZE; i++)
		{
		for(pa = eventtab[i]; pa != 0; pa = pa -> nxtentr)	
			{
			/* the wild cards are in the name */
			sscanf(pa -> name, "%s %s %s %s %d",\
			id_arg0, id_arg1, id_arg2, id_arg3, &id_serial);
/*
sprintf(temp,\
"get_event: id_arg0=%s id_arg1=%s id_arg2=%s id_arg3=%s id_serial=%d\n",\
id_arg0, id_arg1, id_arg2, id_arg3, id_serial);
fprintf(stdout, temp);
*/
			if(strcmp(id_arg0, "/on") != 0)continue;/* not an "on" entry */
			if(id_serial != serial)continue;
			if((strcmp(id_arg1, "*") != 0) && (strcmp(id_arg1, event) != 0))
				{
				continue;
				}
 			if((strcmp(id_arg2, "*") != 0) && (strcmp(id_arg2, channel) != 0))
 				{
 				continue;
 				}
 			if((strcmp(id_arg3, "*") != 0) && (strcmp(id_arg3, nick) != 0))
 				{
 				continue;
 				}
			strcpy(action, pa -> def); 
	
/*
sprintf(temp,\
"event=%s channel=%s nick=%s params=%s",\
event, channel, nick, params);
to_screen(temp, "");
sprintf(temp, "action=%s", action);
to_screen(temp, "");
*/
/* have to replace $nick in action with nick, and $channel with channel,
/* $me with ircname, and $server with hostname */
replace(action, "$channel", channel, temp);
replace(temp, "$nick", nick, temp2);
replace(temp2, "$me", ircname, temp);
replace(temp, "$server", hostname, action);

sprintf(temp, "get_event: event=on %s %s %s %d %s",\
event, channel, nick, serial, action);
to_screen(temp, "");
/*
sprintf(temp, "get_event: name=%s", combined);
to_screen(temp, "");
sprintf(temp, "get_event: send to server=%s", action);
to_screen(temp, "");
*/
			sprintf(temp, "%s\n", action);
			if(! send_to_server(socketfd, temp) )return(0);
			}/* end for all structures in the chain starting from eventtab[i] */
		}/* end for all entries in eventtab */
	}/* end for all serial */

return(1);
}/* end function get_event */
