[cvslog] (2004-10-04 15:48:40 UTC) Module eggdrop1.9: Change committed!

cvslog cvs at tsss.org
Mon Oct 4 09:48:40 CST 2004


CVSROOT    : /usr/local/cvsroot
Module     : eggdrop1.9
Commit time: 2004-10-04 15:48:40 UTC
Commited by: stdarg <stdarg at techmonkeys.org>

Modified files:
     lib/eggdrop/hash_table.c lib/eggdrop/help.c
     lib/eggdrop/partymember.c lib/eggdrop/string.c
     lib/eggdrop/string.h modules/server/Makefile.am
     modules/server/channels.c modules/server/channels.h
     modules/server/egg_server_internal.h modules/server/input.c
     modules/server/party_commands.c modules/server/scriptcmds.c
     modules/server/server.c modules/server/server.h src/logfile.c

Added files:
     modules/server/channel_events.c modules/server/uhost_cache.c

Removed files:
     modules/server/schan.c modules/server/schan.h

Log message:

* Reorganized channel functions into several files to aid readability
* Got rid of separate "static" channels since it was confusing

---------------------- diff included ----------------------
Index: eggdrop1.9/lib/eggdrop/hash_table.c
diff -u eggdrop1.9/lib/eggdrop/hash_table.c:1.13 eggdrop1.9/lib/eggdrop/hash_table.c:1.14
--- eggdrop1.9/lib/eggdrop/hash_table.c:1.13	Sun Sep 26 04:42:09 2004
+++ eggdrop1.9/lib/eggdrop/hash_table.c	Mon Oct  4 10:48:29 2004
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: hash_table.c,v 1.13 2004/09/26 09:42:09 stdarg Exp $";
+static const char rcsid[] = "$Id: hash_table.c,v 1.14 2004/10/04 15:48:29 stdarg Exp $";
 #endif
 
 #include <stdio.h>
@@ -63,6 +63,8 @@
 	hash_table_row_t *row;
 	int i;
 
+	if (!ht) return(-1);
+
 	for (i = 0; i < ht->max_rows; i++) {
 		row = ht->rows+i;
 		for (entry = row->head; entry; entry = next) {
@@ -78,6 +80,8 @@
 
 int hash_table_check_resize(hash_table_t *ht)
 {
+	if (!ht) return(-1);
+
 	if (ht->cells_in_use / ht->max_rows > 100) {
 		hash_table_resize(ht, ht->max_rows * 3);
 	}
@@ -90,6 +94,8 @@
 	hash_table_row_t *oldrow, *newrows;
 	hash_table_entry_t *entry, *next;
 
+	if (!ht) return(-1);
+
 	/* First allocate the new rows. */
 	newrows = calloc(nrows, sizeof(*newrows));
 
@@ -118,6 +124,8 @@
 	hash_table_entry_t *entry;
 	hash_table_row_t *row;
 
+	if (!ht) return(-1);
+
 	hash = ht->hash(key);
 	idx = hash % ht->max_rows;
 	row = ht->rows+idx;
@@ -151,7 +159,7 @@
 	hash_table_entry_t *entry;
 	hash_table_row_t *row;
 
-	if (key == NULL) return (-1);
+	if (!ht) return (-1);
 
 	hash = ht->hash(key);
 	idx = hash % ht->max_rows;
@@ -173,6 +181,8 @@
 	hash_table_entry_t *entry, *last;
 	hash_table_row_t *row;
 
+	if (!ht) return(-1);
+
 	hash = ht->hash(key);
 	idx = hash % ht->max_rows;
 	row = ht->rows+idx;
@@ -201,6 +211,8 @@
 	hash_table_entry_t *entry, *next;
 	int i;
 
+	if (!ht) return(-1);
+
 	for (i = 0; i < ht->max_rows; i++) {
 		row = ht->rows+i;
 		for (entry = row->head; entry;) {
Index: eggdrop1.9/lib/eggdrop/help.c
diff -u eggdrop1.9/lib/eggdrop/help.c:1.18 eggdrop1.9/lib/eggdrop/help.c:1.19
--- eggdrop1.9/lib/eggdrop/help.c:1.18	Wed Sep 29 13:03:53 2004
+++ eggdrop1.9/lib/eggdrop/help.c	Mon Oct  4 10:48:29 2004
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: help.c,v 1.18 2004/09/29 18:03:53 stdarg Exp $";
+static const char rcsid[] = "$Id: help.c,v 1.19 2004/10/04 15:48:29 stdarg Exp $";
 #endif
 
 #include <stdio.h>
@@ -32,7 +32,6 @@
 static help_section_t *sections = NULL;
 static int nsections = 0;
 
-/* XXX: make this configurable(just how?) */
 static char *help_path = NULL;
 static char *help_lang_default = NULL;
 static char *help_lang_fallback = "en_US";
Index: eggdrop1.9/lib/eggdrop/partymember.c
diff -u eggdrop1.9/lib/eggdrop/partymember.c:1.16 eggdrop1.9/lib/eggdrop/partymember.c:1.17
--- eggdrop1.9/lib/eggdrop/partymember.c:1.16	Tue Jun 29 16:28:16 2004
+++ eggdrop1.9/lib/eggdrop/partymember.c	Mon Oct  4 10:48:29 2004
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: partymember.c,v 1.16 2004/06/29 21:28:16 stdarg Exp $";
+static const char rcsid[] = "$Id: partymember.c,v 1.17 2004/10/04 15:48:29 stdarg Exp $";
 #endif
 
 #include <stdarg.h>
@@ -58,6 +58,7 @@
 	garbage_run();
 
 	hash_table_delete(pid_ht);
+	pid_ht = NULL;
 	return (0);
 }
 
Index: eggdrop1.9/lib/eggdrop/string.c
diff -u eggdrop1.9/lib/eggdrop/string.c:1.1 eggdrop1.9/lib/eggdrop/string.c:1.2
--- eggdrop1.9/lib/eggdrop/string.c:1.1	Mon Jun 21 13:44:20 2004
+++ eggdrop1.9/lib/eggdrop/string.c	Mon Oct  4 10:48:29 2004
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: string.c,v 1.1 2004/06/21 18:44:20 wingman Exp $";
+static const char rcsid[] = "$Id: string.c,v 1.2 2004/10/04 15:48:29 stdarg Exp $";
 #endif
 
 #if HAVE_CONFIG_H
@@ -271,3 +271,10 @@
 	return (*str);
 }
 
+void str_tolower(char *str)
+{
+	while (*str) {
+		*str = tolower(*str);
+		str++;
+	}
+}
Index: eggdrop1.9/lib/eggdrop/string.h
diff -u eggdrop1.9/lib/eggdrop/string.h:1.2 eggdrop1.9/lib/eggdrop/string.h:1.3
--- eggdrop1.9/lib/eggdrop/string.h:1.2	Mon Jun 21 15:35:11 2004
+++ eggdrop1.9/lib/eggdrop/string.h	Mon Oct  4 10:48:29 2004
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  *
- * $Id: string.h,v 1.2 2004/06/21 20:35:11 wingman Exp $
+ * $Id: string.h,v 1.3 2004/10/04 15:48:29 stdarg Exp $
  */
 
 #ifndef _EGG_STRING_H_
@@ -24,6 +24,7 @@
 
 int str_ends_with(const char *text, const char *str);
 int str_starts_with(const char *text, const char *str);
+void str_tolower(char *str);
 
 int egg_get_word(const unsigned char *text, const char **next, char **word);
 int egg_get_arg(const unsigned char *text, const char **next, char **arg);
Index: eggdrop1.9/modules/server/Makefile.am
diff -u eggdrop1.9/modules/server/Makefile.am:1.17 eggdrop1.9/modules/server/Makefile.am:1.18
--- eggdrop1.9/modules/server/Makefile.am:1.17	Fri Oct  1 10:31:18 2004
+++ eggdrop1.9/modules/server/Makefile.am	Mon Oct  4 10:48:29 2004
@@ -1,9 +1,9 @@
-# $Id: Makefile.am,v 1.17 2004/10/01 15:31:18 stdarg Exp $
+# $Id: Makefile.am,v 1.18 2004/10/04 15:48:29 stdarg Exp $
 
 include $(top_srcdir)/$(ac_aux_dir)/module.mk
 
 pkglib_LTLIBRARIES	= server.la
-server_la_SOURCES	= server.c server.h binds.c binds.h channels.c channels.h input.c input.h output.c output.h serverlist.c serverlist.h nicklist.c nicklist.h schan.c schan.h scriptcmds.c servsock.c servsock.h party_commands.c dcc.c dcc.h egg_server_api.c egg_server_api.h
+server_la_SOURCES	= server.c server.h binds.c binds.h channels.c channels.h channel_events.c uhost_cache.c input.c input.h output.c output.h serverlist.c serverlist.h nicklist.c nicklist.h scriptcmds.c servsock.c servsock.h party_commands.c dcc.c dcc.h egg_server_api.c egg_server_api.h
 server_la_LDFLAGS	= -module -avoid-version -no-undefined
 server_la_LIBADD	= @LIBS@ $(top_builddir)/lib/eggdrop/libeggdrop.la
 
Index: eggdrop1.9/modules/server/channel_events.c
diff -u /dev/null eggdrop1.9/modules/server/channel_events.c:1.1
--- /dev/null	Mon Oct  4 10:48:40 2004
+++ eggdrop1.9/modules/server/channel_events.c	Mon Oct  4 10:48:30 2004
@@ -0,0 +1,693 @@
+/* channel_events.c: handle channel events
+ *
+ * Copyright (C) 2002, 2003, 2004 Eggheads Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: channel_events.c,v 1.1 2004/10/04 15:48:30 stdarg Exp $";
+ #endif
+
+#include "server.h"
+
+static bind_list_t channel_raw_binds[];
+
+/* Prototypes. */
+static void clear_masklist(channel_mask_list_t *l);
+static int got_list_item(void *client_data, char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[]);
+static int got_list_end(void *client_data, char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[]);
+static void clear_masklists(channel_t *chan);
+
+void channel_events_init()
+{
+	bind_table_t *table;
+
+	bind_add_list("raw", channel_raw_binds);
+	table = bind_table_lookup_or_fake("raw");
+	if (!table) return;
+
+	/* FIXME Putting these here for now... but they should probably be
+	 * configurable or moved to an addon module/script. */
+	bind_entry_add(table, NULL, "367", "banlistitem", BIND_WANTS_CD, got_list_item, (void *)'b');
+	bind_entry_add(table, NULL, "346", "invitelistitem", BIND_WANTS_CD, got_list_item, (void *)'I');
+	bind_entry_add(table, NULL, "348", "exceptlistitem", BIND_WANTS_CD, got_list_item, (void *)'e');
+	bind_entry_add(table, NULL, "368", "banlistend", BIND_WANTS_CD, got_list_end, (void *)'b');
+	bind_entry_add(table, NULL, "347", "invitelistend", BIND_WANTS_CD, got_list_end, (void *)'I');
+	bind_entry_add(table, NULL, "349", "exceptlistend", BIND_WANTS_CD, got_list_end, (void *)'e');
+}
+
+static inline void free_member(channel_member_t *m)
+{
+	if (m->nick) free(m->nick);
+	if (m->uhost) free(m->uhost);
+	free(m);
+}
+
+static void clear_masklists(channel_t *chan)
+{
+	int i;
+
+	for (i = 0; i < chan->nlists; i++) {
+		clear_masklist(chan->lists[i]);
+	}
+}
+
+static void clear_masklist(channel_mask_list_t *l)
+{
+	channel_mask_t *m, *next;
+
+	for (m = l->head; m; m = next) {
+		next = m->next;
+		if (m->mask) free(m->mask);
+		if (m->set_by) free(m->set_by);
+		free(m);
+	}
+	memset(l, 0, sizeof(l));
+}
+
+/* Free online data like nicklist, banmasks, etc.. */
+void channel_free_online(channel_t *chan)
+{
+	channel_member_t *m, *next_mem;
+	int i;
+
+	for (m = chan->member_head; m; m = next_mem) {
+		next_mem = m->next;
+		uhost_cache_decref(m->nick);
+		free_member(m);
+	}
+
+	if (chan->topic) free(chan->topic);
+	if (chan->topic_nick) free(chan->topic_nick);
+	if (chan->key) free(chan->key);
+
+	clear_masklists(chan);
+
+	for (i = 0; i < chan->nargs; i++) {
+		if (chan->args[i].value) free(chan->args[i].value);
+	}
+	if (chan->args) free(chan->args);
+
+	chan->topic = chan->topic_nick = chan->key = NULL;
+	chan->lists = NULL;
+	chan->args = NULL;
+	chan->member_head = NULL;
+	chan->status = chan->nlists = chan->nargs = chan->nmembers = 0;
+	chan->limit = -1;
+}
+
+void channel_events_destroy()
+{
+	bind_rem_list("raw", channel_raw_binds);
+}
+
+static channel_member_t *channel_add_member(channel_t *chan, const char *nick, const char *uhost)
+{
+	channel_member_t *m;
+
+	/* See if this member is already added. */
+	for (m = chan->member_head; m; m = m->next) {
+		if (!(current_server.strcmp)(m->nick, nick)) break;
+	}
+
+	/* Do we need to create a new member? */
+	if (!m) {
+		m = calloc(1, sizeof(*m));
+		m->nick = strdup(nick);
+		timer_get_now_sec(&m->join_time);
+		m->next = chan->member_head;
+		chan->member_head = m;
+		chan->nmembers++;
+	}
+
+	/* Do we need to fill in the uhost? */
+	if (uhost && !m->uhost) {
+		m->uhost = strdup(uhost);
+	}
+
+	uhost_cache_addref(nick, uhost);
+
+	return(m);
+}
+
+/* We just finished connecting to the server, so join our channels. */
+void channel_on_connect()
+{
+	channel_t *chan;
+	char *key;
+	int inactive;
+
+	for (chan = channel_head; chan; chan = chan->next) {
+		channel_get_int(chan, &inactive, "inactive", 0, NULL);
+		if (inactive) continue;
+		channel_get(chan, &key, "key", 0, NULL);
+		if (key && strlen(key)) printserv(SERVER_NORMAL, "JOIN %s %s", chan->name, key);
+		else printserv(SERVER_NORMAL, "JOIN %s", chan->name);
+	}
+}
+
+void channel_on_join(const char *chan_name, const char *nick, const char *uhost)
+{
+	channel_t *chan;
+	channel_member_t *m;
+
+	/* Lookup channel or create. */
+	chan = channel_probe(chan_name, 1);
+	if (!chan) return;
+
+	/* Add a new member. */
+	m = channel_add_member(chan, nick, uhost);
+
+	/* Is it me? If so, request channel lists. */
+	if (match_my_nick(nick)) {
+		int i;
+		chan->bot = m;
+		chan->status |= (CHANNEL_WHOLIST | CHANNEL_JOINED);
+		printserv(SERVER_NORMAL, "WHO %s\r\n", chan_name);
+		printserv(SERVER_NORMAL, "MODE %s\r\n", chan_name);
+		for (i = 0; i < chan->nlists; i++) {
+			chan->lists[i]->loading = 1;
+		}
+		printserv(SERVER_NORMAL, "MODE %s %s\r\n", chan_name, current_server.type1modes);
+	}
+}
+
+void channel_on_leave(const char *chan_name, const char *nick, const char *uhost, user_t *u)
+{
+	channel_t *chan;
+	channel_member_t *prev = NULL, *m;
+
+	chan = channel_probe(chan_name, 0);
+	if (!chan) return;
+
+	uhost_cache_decref(nick);
+	for (m = chan->member_head; m; m = m->next) {
+		if (!(current_server.strcmp)(m->nick, nick)) break;
+		prev = m;
+	}
+	if (!m) return;
+
+	if (prev) prev->next = m->next;
+	else chan->member_head = m->next;
+	free_member(m);
+	chan->nmembers--;
+
+	bind_check(BT_leave, u ? &u->settings[0].flags : NULL, chan_name, nick, uhost, u, chan_name);
+
+	/* Are we the ones leaving? */
+	if (match_my_nick(nick)) {
+		if (chan->status & CHANNEL_STATIC) channel_free_online(chan);
+		else channel_free(chan);
+	}
+}
+
+void channel_on_quit(const char *nick, const char *uhost, user_t *u)
+{
+	channel_t *chan;
+
+	for (chan = channel_head; chan; chan = chan->next) {
+		channel_on_leave(chan->name, nick, uhost, u);
+	}
+}
+
+void channel_on_nick(const char *old_nick, const char *new_nick)
+{
+	channel_t *chan;
+	channel_member_t *m;
+
+	uhost_cache_swap(old_nick, new_nick);
+
+	for (chan = channel_head; chan; chan = chan->next) {
+		for (m = chan->member_head; m; m = m->next) {
+			if (!(current_server.strcmp)(m->nick, old_nick)) {
+				str_redup(&m->nick, new_nick);
+				break;
+			}
+		}
+	}
+}
+
+/* :server 352 <ournick> <chan> <user> <host> <server> <nick> <H|G>[*][@|+] :<hops> <name> */
+static int got352(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *chan_name, *nick, *uhost, *flags, *ptr, changestr[3];
+	int i;
+	channel_member_t *m;
+	channel_t *chan = NULL;
+	chan_name = args[1];
+	chan = channel_probe(chan_name, 0);
+	if (!chan) return(0);
+	nick = args[5];
+	flags = args[6];
+	uhost = egg_mprintf("%s@%s", args[2], args[3]);
+	m = channel_add_member(chan, nick, uhost);
+	changestr[0] = '+';
+	changestr[2] = 0;
+	flags++;
+	while (*flags) {
+		ptr = strchr(current_server.whoprefix, *flags);
+		if (ptr) {
+			i = ptr - current_server.whoprefix;
+			changestr[1] = current_server.modeprefix[i];
+			flag_merge_str(&m->mode, changestr);
+		}
+		flags++;
+	}
+	free(uhost);
+	return(0);
+}
+
+/* :server 315 <ournick> <name> :End of /WHO list */
+static int got315(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *chan_name = args[1];
+	channel_t *chan = NULL;
+
+	channel_probe(chan_name, 0);
+	if (chan) chan->status &= ~CHANNEL_WHOLIST;
+	return(0);
+}
+
+/* :server 353 <ournick> = <chan> :<mode><nick1> <mode><nick2> ... */
+static int got353(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *chan_name, *nick, *nicks, *flags, *ptr, *prefixptr, changestr[3];
+	int i;
+	channel_member_t *m;
+	channel_t *chan = NULL;
+
+	chan_name = args[2];
+	chan = channel_probe(chan_name, 0);
+	if (!chan) return(0);
+
+	nicks = strdup(args[3]);
+	ptr = nicks;
+	changestr[0] = '+';
+	changestr[2] = 0;
+	while (ptr && *ptr) {
+		while (isspace(*ptr)) ptr++;
+		flags = ptr;
+		while (strchr(current_server.whoprefix, *ptr)) ptr++;
+		nick = ptr;
+		while (*ptr && !isspace(*ptr)) ptr++;
+		if (*ptr) *ptr = 0;
+		else ptr = NULL;
+		m = channel_add_member(chan, nick, NULL);
+		*nick = 0;
+		while (*flags) {
+			prefixptr = strchr(current_server.whoprefix, *flags);
+			if (prefixptr) {
+				i = prefixptr - current_server.whoprefix;
+				changestr[1] = current_server.modeprefix[i];
+				flag_merge_str(&m->mode, changestr);
+			}
+			flags++;
+		}
+		if (ptr) ptr++;
+	}
+	free(nicks);
+	return(0);
+}
+
+/* :server 366 <ournick> <name> :End of /NAMES list */
+static int got366(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *chan_name = args[1];
+	channel_t *chan = NULL;
+
+	chan = channel_probe(chan_name, 0);
+	if (chan) chan->status &= ~CHANNEL_NAMESLIST;
+	return(0);
+}
+
+/* :origin TOPIC <chan> :topic */
+static int gottopic(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *chan_name = args[0];
+	char *topic = args[1];
+	channel_t *chan = NULL;
+
+	chan = channel_probe(chan_name, 0);
+	if (!chan) return(0);
+
+	str_redup(&chan->topic, topic);
+	if (chan->topic_nick) free(chan->topic_nick);
+	if (from_uhost) chan->topic_nick = egg_mprintf("%s!%s", from_nick, from_uhost);
+	else chan->topic_nick = strdup(from_nick);
+	timer_get_now_sec(&chan->topic_time);
+
+	return(0);
+}
+
+/* :server 331 <ournick> <chan> :No topic is set */
+static int got331(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *chan_name = args[1];
+	channel_t *chan = NULL;
+
+	chan = channel_probe(chan_name, 0);
+	if (!chan) return(0);
+
+	str_redup(&chan->topic, "");
+	return(0);
+}
+
+/* :server 332 <ournick> <chan> :<topic> */
+static int got332(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *chan_name = args[1];
+	char *topic = args[2];
+	channel_t *chan = NULL;
+
+	chan = channel_probe(chan_name, 0);
+	if (!chan) return(0);
+
+	str_redup(&chan->topic, topic);
+	return(0);
+}
+
+/* :server 333 <ournick> <chan> <nick> <time> */
+static int got333(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *chan_name = args[1];
+	char *nick = args[2];
+	char *time = args[3];
+	channel_t *chan = NULL;
+
+	chan = channel_probe(chan_name, 0);
+	if (!chan) return(0);
+
+	str_redup(&chan->topic_nick, nick);
+	chan->topic_time = atoi(time);
+	return(0);
+}
+
+/* :server 367 <ournick> <chan> <ban> [<nick> <time>]
+ * :server 346 <ournick> <chan> <invite> [<nick> <time>]
+ * :server 348 <ournick> <chan> <except> [<nick> <time>] */
+static int got_list_item(void *client_data, char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *chan_name = args[1];
+	char *ban = args[2];
+	char type = (char) (int) client_data;
+	channel_t *chan;
+	channel_mask_list_t *l;
+
+	chan = channel_probe(chan_name, 0);
+	if (!chan) return(0);
+	l = channel_get_mask_list(chan, type);
+	if (!l || !(l->loading)) return(0);
+	channel_add_mask(chan, type, ban, (nargs > 3) ? args[3] : NULL, (nargs > 4) ? atoi(args[4]) : -1);
+	return(0);
+}
+
+/* :server 368 <ournick> <chan> :End of channel ban list */
+/* :server 347 <ournick> <chan> :End of channel invite except list */
+/* :server 349 <ournick> <chan> :End of channel ban except list */
+static int got_list_end(void *client_data, char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *chan_name = args[1];
+	char type = (char) (int) client_data;
+	channel_t *chan;
+	channel_mask_list_t *l;
+
+	chan = channel_probe(chan_name, 0);
+	if (!chan) return(0);
+	l = channel_get_mask_list(chan, type);
+	if (l) l->loading = 0;
+/* FIXME - See if we need to set any modes */
+	return(0);
+}
+
+/**********************************************
+ * Join/leave stuff.
+ */
+
+/* Got a join message. */
+static int gotjoin(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *chan = args[0];
+
+	channel_on_join(chan, from_nick, from_uhost);
+	bind_check(BT_join, u ? &u->settings[0].flags : NULL, chan, from_nick, from_uhost, u, chan);
+	return(0);
+}
+
+/* Got a part message. */
+static int gotpart(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *chan = args[0];
+	char *text = args[1];
+
+	channel_on_leave(chan, from_nick, from_uhost, u);
+	bind_check(BT_part, u ? &u->settings[0].flags : NULL, chan, from_nick, from_uhost, u, chan, text);
+	return(0);
+}
+
+/* Got a quit message. */
+static int gotquit(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *text = args[0];
+
+	channel_on_quit(from_nick, from_uhost, u);
+	bind_check(BT_quit, u ? &u->settings[0].flags : NULL, from_nick, from_nick, from_uhost, u, text);
+
+	return(0);
+}
+
+/* Got a kick message. */
+static int gotkick(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *chan = args[0];
+	char *victim = args[1];
+	char *text = args[2];
+	char *uhost;
+
+	if (!text) text = "";
+	uhost = uhost_cache_lookup(victim);
+	if (!uhost) uhost = "";
+
+	channel_on_leave(chan, victim, uhost, u);
+	bind_check(BT_kick, u ? &u->settings[0].flags : NULL, from_nick, from_nick, from_uhost, u, chan, victim, text);
+
+	return(0);
+}
+
+/* Got nick change.  */
+static int gotnick(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *newnick = args[0];
+
+	channel_on_nick(from_nick, newnick);
+	bind_check(BT_nick, u ? &u->settings[0].flags : NULL, from_nick, from_nick, from_uhost, u, newnick);
+
+	/* Is it our nick that's changing? */
+	if (match_my_nick(from_nick)) str_redup(&current_server.nick, newnick);
+
+	return(0);
+}
+
+/*************************************************
+ * Mode stuff.
+ */
+
+static void parse_chan_mode(char *from_nick, char *from_uhost, user_t *u, int nargs, char *args[], int trigger_bind)
+{
+	int hasarg, curarg, modify_member, modify_channel, modify_list;
+	int i;
+	channel_member_t *m;
+	char changestr[3];
+	char *dest;
+	char *change;
+	channel_t *chan;
+	const char *arg;
+
+	if (nargs < 2) return;
+
+	dest = args[0];
+	change = args[1];
+
+	chan = channel_probe(dest, 0);
+	if (!chan) return;
+
+	changestr[0] = '+';
+	changestr[2] = 0;
+
+	curarg = 2;
+	while (*change) {
+		/* Direction? */
+		if (*change == '+' || *change == '-') {
+			changestr[0] = *change;
+			change++;
+			continue;
+		}
+
+		/* Figure out what kind of change it is and if it takes an
+		 * argument. */
+		modify_member = modify_channel = modify_list = 0;
+		if (strchr(current_server.modeprefix, *change)) {
+			hasarg = 1;
+			modify_member = 1;
+		}
+		else if (strchr(current_server.type1modes, *change)) {
+			hasarg = 1;
+			modify_list = 1;
+		}
+		else if (strchr(current_server.type2modes, *change)) {
+			hasarg = 1;
+		}
+		else if (changestr[0] == '+' && strchr(current_server.type3modes, *change)) {
+			hasarg = 1;
+		}
+		else {
+			modify_channel = 1;
+			hasarg = 0;
+		}
+
+		if (hasarg) {
+			if (curarg >= nargs) arg = "";
+			else arg = args[curarg++];
+		}
+		else arg = NULL;
+
+		changestr[1] = *change;
+
+		if (modify_member) {
+			/* Find the person it modifies and apply. */
+			for (m = chan->member_head; m; m = m->next) {
+				if (!(current_server.strcmp)(m->nick, arg)) {
+					flag_merge_str(&m->mode, changestr);
+					break;
+				}
+			}
+		}
+		else if (modify_channel) {
+			/* Simple flag change for channel. */
+			flag_merge_str(&chan->mode, changestr);
+		}
+		else if (modify_list) {
+			/* Add/remove an address from a list. */
+			if (changestr[0] == '+') channel_add_mask(chan, *change, arg, from_nick, timer_get_now_sec(NULL));
+			else channel_del_mask(chan, *change, arg);
+		}
+		else if (changestr[0] == '+') {
+			/* + flag change that requires special handling. */
+			switch (*change) {
+				case 'k':
+					str_redup(&chan->key, arg);
+					break;
+				case 'l':
+					chan->limit = atoi(arg);
+					break;
+			}
+			for (i = 0; i < chan->nargs; i++) {
+				if (chan->args[i].type == *change) {
+					str_redup(&chan->args[i].value, arg);
+					break;
+				}
+			}
+		}
+		else {
+			/* - flag change that requires special handling. */
+			switch (*change) {
+				case 'k':
+					if (chan->key) free(chan->key);
+					chan->key = NULL;
+					break;
+				case 'l':
+					chan->limit = 0;
+					break;
+			}
+			for (i = 0; i < chan->nargs; i++) {
+				if (chan->args[i].type == *change) {
+					str_redup(&chan->args[i].value, NULL);
+					break;
+				}
+			}
+		}
+
+		/* Now trigger the mode bind. */
+		if (trigger_bind) bind_check(BT_mode, u ? &u->settings[0].flags : NULL, changestr, from_nick, from_uhost, u, dest, changestr, arg);
+		change++;
+	}
+}
+
+/* Got an absolute channel mode. */
+static int got324(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	parse_chan_mode(from_nick, from_uhost, u, nargs-1, args+1, 0);
+	return(0);
+}
+
+/* Got a mode change. */
+static int gotmode(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+{
+	char *dest = args[0];
+	char *change = args[1];
+	char changestr[3];
+
+	changestr[0] = '+';
+	changestr[2] = 0;
+
+	/* Is it a user mode? */
+	if (!strchr(current_server.chantypes, *dest)) {
+		while (*change) {
+			/* Direction? */
+			if (*change == '+' || *change == '-') {
+				changestr[0] = *change;
+				change++;
+				continue;
+			}
+
+			changestr[1] = *change;
+			bind_check(BT_mode, u ? &u->settings[0].flags : NULL, changestr, from_nick, from_uhost, u, dest, changestr, NULL);
+			change++;
+		}
+		return(0);
+	}
+
+	parse_chan_mode(from_nick, from_uhost, u, nargs, args, 1);
+	return(0);
+}
+
+static bind_list_t channel_raw_binds[] = {
+	/* WHO replies */
+	{NULL, "352", got352}, /* WHO reply */
+	{NULL, "315", got315}, /* end of WHO */
+
+	/* NAMES replies */
+	{NULL, "353", got353}, /* NAMES reply */
+	{NULL, "366", got366}, /* end of NAMES */
+
+	/* Topic info */
+	{NULL, "TOPIC", gottopic},
+	{NULL, "331", got331},
+	{NULL, "332", got332},
+	{NULL, "333", got333},
+
+	/* Channel member stuff. */
+	{NULL, "JOIN", gotjoin},
+	{NULL, "PART", gotpart},
+	{NULL, "QUIT", gotquit},
+	{NULL, "KICK", gotkick},
+	{NULL, "NICK", gotnick},
+
+	/* Mode. */
+	{NULL, "324", got324},
+	{NULL, "MODE", gotmode},
+
+	{NULL, NULL, NULL}
+};
Index: eggdrop1.9/modules/server/channels.c
diff -u eggdrop1.9/modules/server/channels.c:1.33 eggdrop1.9/modules/server/channels.c:1.34
--- eggdrop1.9/modules/server/channels.c:1.33	Fri Oct  1 11:13:31 2004
+++ eggdrop1.9/modules/server/channels.c	Mon Oct  4 10:48:30 2004
@@ -18,127 +18,73 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: channels.c,v 1.33 2004/10/01 16:13:31 stdarg Exp $";
+static const char rcsid[] = "$Id: channels.c,v 1.34 2004/10/04 15:48:30 stdarg Exp $";
  #endif
 
 #include "server.h"
 
-#define UHOST_CACHE_SIZE 47
-
 channel_t *channel_head = NULL;
-hash_table_t *uhost_cache_ht = NULL;
-
 int nchannels = 0;
 
-static bind_list_t channel_raw_binds[];
-
-/* Prototypes. */
-static int uhost_cache_delete(const void *key, void *data, void *param);
-static void clear_masklist(channel_mask_list_t *l);
-static int got_list_item(void *client_data, char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[]);
-static int got_list_end(void *client_data, char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[]);
-void uhost_cache_decref(const char *nick);
-void server_channel_destroy();
-
-static void clear_masklists(channel_t *chan);
-
-void server_channel_init()
+void channel_init()
 {
-	bind_table_t *table;
-
 	channel_head = NULL;
 	nchannels = 0;
-	uhost_cache_ht = hash_table_create(NULL, NULL, UHOST_CACHE_SIZE, HASH_TABLE_STRINGS);
-	bind_add_list("raw", channel_raw_binds);
-	table = bind_table_lookup_or_fake("raw");
-	if (!table) return;
-
-	/* FIXME Putting these here for now... but they should probably be
-	 * configurable or moved to an addon module/script. */
-	bind_entry_add(table, NULL, "367", "banlistitem", BIND_WANTS_CD, got_list_item, (void *)'b');
-	bind_entry_add(table, NULL, "346", "invitelistitem", BIND_WANTS_CD, got_list_item, (void *)'I');
-	bind_entry_add(table, NULL, "348", "exceptlistitem", BIND_WANTS_CD, got_list_item, (void *)'e');
-	bind_entry_add(table, NULL, "368", "banlistend", BIND_WANTS_CD, got_list_end, (void *)'b');
-	bind_entry_add(table, NULL, "347", "invitelistend", BIND_WANTS_CD, got_list_end, (void *)'I');
-	bind_entry_add(table, NULL, "349", "exceptlistend", BIND_WANTS_CD, got_list_end, (void *)'e');
-}
-
-static inline void free_member(channel_member_t *m)
-{
-	if (m->nick) free(m->nick);
-	if (m->uhost) free(m->uhost);
-	free(m);
-}
-
-/* Free online data like nicklist, banmasks, etc.. */
-static void free_channel(channel_t *chan)
-{
-	channel_t *chanptr;
-	channel_member_t *m, *next_mem;
-
-	for (m = chan->member_head; m; m = next_mem) {
-		next_mem = m->next;
-		uhost_cache_decref(m->nick);
-		free_member(m);
-	}
-
-	if (chan->name) free(chan->name);
-	if (chan->topic) free(chan->topic);
-	if (chan->topic_nick) free(chan->topic_nick);
-	if (chan->key) free(chan->key);
-	clear_masklists(chan);
-	if (chan->args) free(chan->args);
-
-	/* Unlink. */
-	if (channel_head == chan) channel_head = chan->next;
-	else for (chanptr = channel_head; chanptr && chanptr->next; chanptr = chanptr->next) {
-		if (chanptr->next == chan) {
-			chanptr->next = chan->next;
-			break;
-		}
-	}
+	channel_load(server_config.chanfile);
 }
 
 /* Reset everything when we disconnect from the server. */
 void channel_reset()
 {
+	channel_t *chan;
+
 	/* Clear out channel list. */
-	while (channel_head) free_channel(channel_head);
+	for (chan = channel_head; chan; chan = chan->next) {
+		channel_free_online(chan);
+	}
+	uhost_cache_reset();
+}
 
-	/* And the uhost cache. */
-	hash_table_walk(uhost_cache_ht, uhost_cache_delete, NULL);
-	hash_table_delete(uhost_cache_ht);
-	uhost_cache_ht = hash_table_create(NULL, NULL, UHOST_CACHE_SIZE, HASH_TABLE_STRINGS);
+void channel_destroy()
+{
+	channel_reset();
+	channel_save(server_config.chanfile);
 }
 
-void server_channel_destroy()
+void channel_free(channel_t *chan)
 {
+	/* Free online things. */
+	channel_free_online(chan);
+
+	/* Delete settings. */
+	if (chan->name) free(chan->name);
+	if (chan->settings) xml_node_delete(chan->settings);
+
+	/* Unlink. */
+	if (chan->prev) chan->prev->next = chan->next;
+	else channel_head = chan->next;
+	if (chan->next) chan->next->prev = chan->prev;
 }
 
 /* Find or create channel when passed 0 or 1 */
-int channel_lookup(const char *chan_name, int create, channel_t **chanptr, channel_t **prevptr)
+channel_t *channel_probe(const char *chan_name, int create)
 {
 	channel_t *chan, *prev;
 	int i;
 
-	*chanptr = NULL;
-	if (prevptr) *prevptr = NULL;
-
 	prev = NULL;
 	for (chan = channel_head; chan; chan = chan->next) {
-		if (!strcasecmp(chan->name, chan_name)) {
-			*chanptr = chan;
-			if (prevptr) *prevptr = prev;
-			return -create; /* Report error if we were supposed to
-					   create new channel */
-		}
+		if (!strcasecmp(chan->name, chan_name)) return(chan);
 		prev = chan;
 	}
-	if (!create) return -1;
+	if (!create) return(NULL);
 
+	/* Create a new channel. */
 	nchannels++;
 	chan = calloc(1, sizeof(*chan));
 	chan->name = strdup(chan_name);
+	chan->settings = xml_node_new();
+	chan->settings->name = strdup("settings");
 
 	if (current_server.type1modes) {
 		chan->nlists = strlen(current_server.type1modes);
@@ -149,8 +95,6 @@
 		}
 	}
 
-	/* FIXME - I suspect this code is buggy in the same way channel lists code was
-			few weeks ago. It will recive attention later. */
 	if (current_server.type2modes) {
 		chan->nargs = strlen(current_server.type2modes);
 		chan->args = calloc(chan->nargs, sizeof(*chan->args));
@@ -159,399 +103,34 @@
 		}
 	}
 
-	chan->next = channel_head;
-	channel_head = chan;
-	*chanptr = chan;
-	return 1;
-}
-
-static void make_lowercase(char *nick)
-{
-	while (*nick) {
-		*nick = tolower(*nick);
-		nick++;
-	}
-}
-
-static int uhost_cache_delete(const void *key, void *dataptr, void *param)
-{
-	uhost_cache_entry_t *cache = *(void **)dataptr;
-
-	if (cache->nick) free(cache->nick);
-	if (cache->uhost) free(cache->uhost);
-	free(cache);
-	return(0);
+	/* Link to list. */
+	if (prev) prev->next = chan;
+	else channel_head = chan;
+	chan->prev = prev;
+	return(chan);
 }
 
-static uhost_cache_entry_t *cache_lookup(const char *nick)
-{
-	char buf[64], *lnick;
-	uhost_cache_entry_t *cache = NULL;
-
-	lnick = egg_msprintf(buf, sizeof(buf), NULL, "%s", nick);
-	make_lowercase(lnick);
-	hash_table_find(uhost_cache_ht, lnick, &cache);
-	if (lnick != buf) free(lnick);
-	return(cache);
-}
-
-char *uhost_cache_lookup(const char *nick)
-{
-	uhost_cache_entry_t *cache;
-
-	cache = cache_lookup(nick);
-	if (cache) return(cache->uhost);
-	return(NULL);
-}
-
-void uhost_cache_addref(const char *nick, const char *uhost)
-{
-	char buf[64], *lnick;
-	uhost_cache_entry_t *cache = NULL;
-
-	lnick = egg_msprintf(buf, sizeof(buf), NULL, "%s", nick);
-	make_lowercase(lnick);
-	hash_table_find(uhost_cache_ht, lnick, &cache);
-	if (!cache) {
-		cache = calloc(1, sizeof(*cache));
-		cache->nick = strdup(nick);
-		make_lowercase(cache->nick);
-		if (uhost) cache->uhost = strdup(uhost);
-		hash_table_insert(uhost_cache_ht, cache->nick, cache);
-	}
-	cache->ref_count++;
-	if (lnick != buf) free(lnick);
-}
-
-void uhost_cache_decref(const char *nick)
-{
-	uhost_cache_entry_t *cache;
-
-	/* We don't decrement ourselves.. we always know our own host. */
-	if (match_my_nick(nick)) return;
-
-	cache = cache_lookup(nick);
-	if (!cache) return;
-
-	cache->ref_count--;
-	if (cache->ref_count <= 0) {
-		hash_table_remove(uhost_cache_ht, cache->nick, NULL);
-		uhost_cache_delete(NULL, cache, NULL);
-	}
-}
-
-static channel_member_t *channel_add_member(channel_t *chan, const char *nick, const char *uhost)
-{
-	channel_member_t *m;
-
-	/* See if this member is already added. */
-	for (m = chan->member_head; m; m = m->next) {
-		if (!(current_server.strcmp)(m->nick, nick)) break;
-	}
-
-	/* Do we need to create a new member? */
-	if (!m) {
-		m = calloc(1, sizeof(*m));
-		m->nick = strdup(nick);
-		timer_get_now_sec(&m->join_time);
-		m->next = chan->member_head;
-		chan->member_head = m;
-		chan->nmembers++;
-	}
-
-	/* Do we need to fill in the uhost? */
-	if (uhost && !m->uhost) {
-		m->uhost = strdup(uhost);
-	}
-
-	uhost_cache_addref(nick, uhost);
-
-	return(m);
-}
-
-void channel_on_join(const char *chan_name, const char *nick, const char *uhost)
+/* Add a channel to our static list. */
+channel_t *channel_add(const char *name)
 {
 	channel_t *chan;
-	channel_member_t *m;
 
-	/* Lookup channel or create. */
-	channel_lookup(chan_name, 1, &chan, NULL);
-	if (!chan) return;
-
-	/* Add a new member. */
-	m = channel_add_member(chan, nick, uhost);
-
-	/* Is it me? If so, request channel lists. */
-	if (match_my_nick(nick)) {
-		int i;
-		chan->bot = m;
-		chan->status |= (CHANNEL_WHOLIST | CHANNEL_JOINED);
-		printserv(SERVER_NORMAL, "WHO %s\r\n", chan_name);
-		printserv(SERVER_NORMAL, "MODE %s\r\n", chan_name);
-		for (i = 0; i < chan->nlists; i++) {
-			chan->lists[i]->loading = 1;
-		}
-		printserv(SERVER_NORMAL, "MODE %s %s\r\n", chan_name, current_server.type1modes);
-	}
-}
-
-void channel_on_leave(const char *chan_name, const char *nick, const char *uhost, user_t *u)
-{
-	channel_t *chan;
-	channel_member_t *prev = NULL, *m;
-
-	channel_lookup(chan_name, 0, &chan, NULL);
-	if (!chan) return;
-
-	uhost_cache_decref(nick);
-	for (m = chan->member_head; m; m = m->next) {
-		if (!(current_server.strcmp)(m->nick, nick)) break;
-		prev = m;
-	}
-	if (!m) return;
-
-	if (prev) prev->next = m->next;
-	else chan->member_head = m->next;
-	free_member(m);
-	chan->nmembers--;
-
-	bind_check(BT_leave, u ? &u->settings[0].flags : NULL, chan_name, nick, uhost, u, chan_name);
-
-	if (match_my_nick(nick)) free_channel(chan);
-}
-
-void channel_on_quit(const char *nick, const char *uhost, user_t *u)
-{
-	channel_t *chan;
-
-	for (chan = channel_head; chan; chan = chan->next) {
-		channel_on_leave(chan->name, nick, uhost, u);
-	}
+	chan = channel_probe(name, 1);
+	chan->flags |= CHANNEL_STATIC;
+	return(chan);
 }
 
-void channel_on_nick(const char *old_nick, const char *new_nick)
+/* Remove a channel from our static list. */
+int channel_remove(const char *name)
 {
 	channel_t *chan;
-	channel_member_t *m;
-	char buf[64], *lnick;
-	uhost_cache_entry_t *cache = NULL;
-
-	lnick = egg_msprintf(buf, sizeof(buf), NULL, "%s", old_nick);
-	make_lowercase(lnick);
-	hash_table_remove(uhost_cache_ht, lnick, &cache);
-	if (lnick != buf) free(lnick);
-
-	if (cache) {
-		str_redup(&cache->nick, new_nick);
-		make_lowercase(cache->nick);
-		hash_table_insert(uhost_cache_ht, cache->nick, cache);
-	}
-
-	for (chan = channel_head; chan; chan = chan->next) {
-		for (m = chan->member_head; m; m = m->next) {
-			if (!(current_server.strcmp)(m->nick, old_nick)) {
-				str_redup(&m->nick, new_nick);
-				break;
-			}
-		}
-	}
-}
-
-int channel_list(const char ***chans)
-{
-	channel_t *chan;
-	int i;
-
-	*chans = calloc(nchannels+1, sizeof(*chans));
-	i = 0;
-	for (chan = channel_head; chan; chan = chan->next) {
-		(*chans)[i] = chan->name;
-		i++;
-	}
-	(*chans)[i] = NULL;
-	return(i);
-}
-
-int channel_list_members(const char *chan, const char ***members)
-{
-	channel_t *chanptr;
-	channel_member_t *m;
-	int i;
-
-	channel_lookup(chan, 0, &chanptr, NULL);
-	if (!chanptr) {
-		*members = NULL;
-		return(-1);
-	}
-
-	*members = calloc(chanptr->nmembers+1, sizeof(*members));
-	i = 0;
-	for (m = chanptr->member_head; m; m = m->next) {
-		(*members)[i] = m->nick;
-		i++;
-	}
-	return(i);
-}
-
-/* :server 352 <ournick> <chan> <user> <host> <server> <nick> <H|G>[*][@|+] :<hops> <name> */
-static int got352(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
-{
-	char *chan_name, *nick, *uhost, *flags, *ptr, changestr[3];
-	int i;
-	channel_member_t *m;
-	channel_t *chan = NULL;
-	chan_name = args[1];
-	if (channel_lookup(chan_name, 0, &chan, NULL) == -1)
-		return 0;
-	nick = args[5];
-	flags = args[6];
-	uhost = egg_mprintf("%s@%s", args[2], args[3]);
-	m = channel_add_member(chan, nick, uhost);
-	changestr[0] = '+';
-	changestr[2] = 0;
-	flags++;
-	while (*flags) {
-		ptr = strchr(current_server.whoprefix, *flags);
-		if (ptr) {
-			i = ptr - current_server.whoprefix;
-			changestr[1] = current_server.modeprefix[i];
-			flag_merge_str(&m->mode, changestr);
-		}
-		flags++;
-	}
-	free(uhost);
-	return(0);
-}
-
-/* :server 315 <ournick> <name> :End of /WHO list */
-static int got315(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
-{
-	char *chan_name = args[1];
-	channel_t *chan = NULL;
-
-	channel_lookup(chan_name, 0, &chan, NULL);
-	if (chan) chan->status &= ~CHANNEL_WHOLIST;
-	return(0);
-}
-
-/* :server 353 <ournick> = <chan> :<mode><nick1> <mode><nick2> ... */
-static int got353(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
-{
-	char *chan_name, *nick, *nicks, *flags, *ptr, *prefixptr, changestr[3];
-	int i;
-	channel_member_t *m;
-	channel_t *chan = NULL;
-
-	chan_name = args[2];
-	if (channel_lookup(chan_name, 0, &chan, NULL) == -1)
-		return 0;
-
-	nicks = strdup(args[3]);
-	ptr = nicks;
-	changestr[0] = '+';
-	changestr[2] = 0;
-	while (ptr && *ptr) {
-		while (isspace(*ptr)) ptr++;
-		flags = ptr;
-		while (strchr(current_server.whoprefix, *ptr)) ptr++;
-		nick = ptr;
-		while (*ptr && !isspace(*ptr)) ptr++;
-		if (*ptr) *ptr = 0;
-		else ptr = NULL;
-		m = channel_add_member(chan, nick, NULL);
-		*nick = 0;
-		while (*flags) {
-			prefixptr = strchr(current_server.whoprefix, *flags);
-			if (prefixptr) {
-				i = prefixptr - current_server.whoprefix;
-				changestr[1] = current_server.modeprefix[i];
-				flag_merge_str(&m->mode, changestr);
-			}
-			flags++;
-		}
-		if (ptr) ptr++;
-	}
-	free(nicks);
-	return(0);
-}
 
-/* :server 366 <ournick> <name> :End of /NAMES list */
-static int got366(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
-{
-	char *chan_name = args[1];
-	channel_t *chan = NULL;
-
-	channel_lookup(chan_name, 0, &chan, NULL);
-	if (chan) chan->status &= ~CHANNEL_NAMESLIST;
-	return(0);
-}
-
-/* :origin TOPIC <chan> :topic */
-static int gottopic(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
-{
-	char *chan_name = args[0];
-	char *topic = args[1];
-	channel_t *chan = NULL;
-
-	channel_lookup(chan_name, 0, &chan, NULL);
-	if (!chan) return(0);
-
-	str_redup(&chan->topic, topic);
-	if (chan->topic_nick) free(chan->topic_nick);
-	if (from_uhost) chan->topic_nick = egg_mprintf("%s!%s", from_nick, from_uhost);
-	else chan->topic_nick = strdup(from_nick);
-	timer_get_now_sec(&chan->topic_time);
-
-	return(0);
-}
-
-/* :server 331 <ournick> <chan> :No topic is set */
-static int got331(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
-{
-	char *chan_name = args[1];
-	channel_t *chan = NULL;
-
-	channel_lookup(chan_name, 0, &chan, NULL);
-	if (!chan) return(0);
-
-	str_redup(&chan->topic, "");
-	return(0);
-}
-
-/* :server 332 <ournick> <chan> :<topic> */
-static int got332(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
-{
-	char *chan_name = args[1];
-	char *topic = args[2];
-	channel_t *chan = NULL;
-
-	channel_lookup(chan_name, 0, &chan, NULL);
-	if (!chan) return(0);
-
-	str_redup(&chan->topic, topic);
-	return(0);
-}
-
-/* :server 333 <ournick> <chan> <nick> <time> */
-static int got333(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
-{
-	char *chan_name = args[1];
-	char *nick = args[2];
-	char *time = args[3];
-	channel_t *chan = NULL;
-
-	channel_lookup(chan_name, 0, &chan, NULL);
-	if (!chan) return(0);
-
-	str_redup(&chan->topic_nick, nick);
-	chan->topic_time = atoi(time);
+	chan = channel_probe(name, 0);
+	if (!chan) return(-1);
+	chan->flags &= ~CHANNEL_STATIC;
 	return(0);
 }
 
-/************************************
- * Mask list handling
- */
-
 channel_mask_list_t *channel_get_mask_list(channel_t *chan, char type)
 {
 	int i;
@@ -563,10 +142,6 @@
 	return(NULL);
 }
 
-/* FIXME - int time should be long expire */
-/* Creates or updates an entry in the mask list, as a result of channel mode change.
-   It is *NOT* allowed to create new list type because, when connected to server,
-   we already know all valid types or use defaults. */
 void channel_add_mask(channel_t *chan, char type, const char *mask, const char *set_by, int time)
 {
 	channel_mask_list_t *l;
@@ -587,138 +162,26 @@
 	l->len++;
 }
 
-static void clear_masklists(channel_t *chan)
+void channel_del_mask(channel_t *chan, char type, const char *mask)
 {
-	int i;
-
-	for (i = 0; i < chan->nlists; i++) {
-		clear_masklist(chan->lists[i]);
-	}
-}
-
-static void clear_masklist(channel_mask_list_t *l)
-{
-	channel_mask_t *m, *next;
-
-	for (m = l->head; m; m = next) {
-		next = m->next;
-		if (m->mask) free(m->mask);
-		if (m->set_by) free(m->set_by);
-		free(m);
-	}
-	memset(l, 0, sizeof(l));
-}
-
-/* :server 367 <ournick> <chan> <ban> [<nick> <time>]
- * :server 346 <ournick> <chan> <invite> [<nick> <time>]
- * :server 348 <ournick> <chan> <except> [<nick> <time>] */
-static int got_list_item(void *client_data, char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
-{
-	char *chan_name = args[1];
-	char *ban = args[2];
-	char type = (char) (int) client_data;
-	channel_t *chan;
-	channel_mask_list_t *l;
-
-	channel_lookup(chan_name, 0, &chan, NULL);
-	if (!chan) return(0);
-	l = channel_get_mask_list(chan, type);
-	if (!l || !(l->loading)) return(0);
-	channel_add_mask(chan, type, ban, (nargs > 3) ? args[3] : NULL, (nargs > 4) ? atoi(args[4]) : -1);
-	return(0);
-}
-
-/* :server 368 <ournick> <chan> :End of channel ban list */
-/* :server 347 <ournick> <chan> :End of channel invite except list */
-/* :server 349 <ournick> <chan> :End of channel ban except list */
-static int got_list_end(void *client_data, char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
-{
-	char *chan_name = args[1];
-	char type = (char) (int) client_data;
-	channel_t *chan;
 	channel_mask_list_t *l;
+	channel_mask_t *m, *prev;
 
-	channel_lookup(chan_name, 0, &chan, NULL);
-	if (!chan) return(0);
 	l = channel_get_mask_list(chan, type);
-	if (l) l->loading = 0;
-/* FIXME - See if we need to set any modes */
-	return(0);
-}
-
-/**********************************************
- * Join/leave stuff.
- */
-
-/* Got a join message. */
-static int gotjoin(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
-{
-	char *chan = args[0];
-
-	channel_on_join(chan, from_nick, from_uhost);
-	bind_check(BT_join, u ? &u->settings[0].flags : NULL, chan, from_nick, from_uhost, u, chan);
-	return(0);
-}
-
-/* Got a part message. */
-static int gotpart(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
-{
-	char *chan = args[0];
-	char *text = args[1];
-
-	channel_on_leave(chan, from_nick, from_uhost, u);
-	bind_check(BT_part, u ? &u->settings[0].flags : NULL, chan, from_nick, from_uhost, u, chan, text);
-	return(0);
-}
-
-/* Got a quit message. */
-static int gotquit(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
-{
-	char *text = args[0];
-
-	channel_on_quit(from_nick, from_uhost, u);
-	bind_check(BT_quit, u ? &u->settings[0].flags : NULL, from_nick, from_nick, from_uhost, u, text);
-
-	return(0);
-}
-
-/* Got a kick message. */
-static int gotkick(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
-{
-	char *chan = args[0];
-	char *victim = args[1];
-	char *text = args[2];
-	char *uhost;
-
-	if (!text) text = "";
-	uhost = uhost_cache_lookup(victim);
-	if (!uhost) uhost = "";
-
-	channel_on_leave(chan, victim, uhost, u);
-	bind_check(BT_kick, u ? &u->settings[0].flags : NULL, from_nick, from_nick, from_uhost, u, chan, victim, text);
-
-	return(0);
-}
-
-/* Got nick change.  */
-static int gotnick(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
-{
-	char *newnick = args[0];
-
-	channel_on_nick(from_nick, newnick);
-	bind_check(BT_nick, u ? &u->settings[0].flags : NULL, from_nick, from_nick, from_uhost, u, newnick);
-
-	/* Is it our nick that's changing? */
-	if (match_my_nick(from_nick)) str_redup(&current_server.nick, newnick);
-
-	return(0);
+	prev = NULL;
+	for (m = l->head; m; m = m->next) {
+		if (m->mask && !strcasecmp(m->mask, mask)) {
+			free(m->mask);
+			if (m->set_by) free(m->set_by);
+			if (prev) prev->next = m->next;
+			else l->head = m->next;
+			l->len--;
+			free(m);
+			break;
+		}
+	}
 }
 
-/*************************************************
- * Mode stuff.
- */
-
-/* nick is NULL to get channel mode */
 int channel_mode(const char *chan_name, const char *nick, char *buf)
 {
 	channel_t *chan;
@@ -726,7 +189,7 @@
 	flags_t *flags = NULL;
 
 	buf[0] = 0;
-	channel_lookup(chan_name, 0, &chan, NULL);
+	chan = channel_probe(chan_name, 0);
 	if (!chan) return(-1);
 	if (!nick) flags = &chan->mode;
 	else {
@@ -747,7 +210,7 @@
 	int i;
 	channel_t *chan;
 
-	channel_lookup(chan_name, 0, &chan, NULL);
+	chan = channel_probe(chan_name, 0);
 	if (!chan) return(-1);
 	for (i = 0; i < chan->nargs; i++) {
 		if (chan->args[i].type == type) {
@@ -758,218 +221,100 @@
 	return(-2);
 }
 
-static void parse_chan_mode(char *from_nick, char *from_uhost, user_t *u, int nargs, char *args[], int trigger_bind)
+int channel_set(channel_t *chan, const char *value, ...)
 {
-	int hasarg, curarg, modify_member, modify_channel, modify_list;
-	int i;
-	channel_member_t *m;
-	char changestr[3];
-	char *dest;
-	char *change;
-	channel_t *chan;
-	const char *arg;
-
-	if (nargs < 2) return;
-
-	dest = args[0];
-	change = args[1];
-
-	channel_lookup(dest, 0, &chan, NULL);
-	if (!chan) return;
-
-	changestr[0] = '+';
-	changestr[2] = 0;
-
-	curarg = 2;
-	while (*change) {
-		/* Direction? */
-		if (*change == '+' || *change == '-') {
-			changestr[0] = *change;
-			change++;
-			continue;
-		}
-
-		/* Figure out what kind of change it is and if it takes an
-		 * argument. */
-		modify_member = modify_channel = modify_list = 0;
-		if (strchr(current_server.modeprefix, *change)) {
-			hasarg = 1;
-			modify_member = 1;
-		}
-		else if (strchr(current_server.type1modes, *change)) {
-			hasarg = 1;
-			modify_list = 1;
-		}
-		else if (strchr(current_server.type2modes, *change)) {
-			hasarg = 1;
-		}
-		else if (changestr[0] == '+' && strchr(current_server.type3modes, *change)) {
-			hasarg = 1;
-		}
-		else {
-			modify_channel = 1;
-			hasarg = 0;
-		}
-
-		if (hasarg) {
-			if (curarg >= nargs) arg = "";
-			else arg = args[curarg++];
-		}
-		else arg = NULL;
-
-		changestr[1] = *change;
-
-		if (modify_member) {
-			/* Find the person it modifies and apply. */
-			for (m = chan->member_head; m; m = m->next) {
-				if (!(current_server.strcmp)(m->nick, arg)) {
-					flag_merge_str(&m->mode, changestr);
-					break;
-				}
-			}
-		}
-		else if (modify_channel) {
-			/* Simple flag change for channel. */
-			flag_merge_str(&chan->mode, changestr);
-		}
-		else if (modify_list) {
-			/* Add/remove an address from a list. */
-			if (changestr[0] == '+') channel_add_mask(chan, *change, arg, from_nick, timer_get_now_sec(NULL));
-			else channel_del_mask(chan, *change, arg, 0);
-		}
-		else if (changestr[0] == '+') {
-			/* + flag change that requires special handling. */
-			switch (*change) {
-				case 'k':
-					str_redup(&chan->key, arg);
-					break;
-				case 'l':
-					chan->limit = atoi(arg);
-					break;
-			}
-			for (i = 0; i < chan->nargs; i++) {
-				if (chan->args[i].type == *change) {
-					str_redup(&chan->args[i].value, arg);
-					break;
-				}
-			}
-		}
-		else {
-			/* - flag change that requires special handling. */
-			switch (*change) {
-				case 'k':
-					if (chan->key) free(chan->key);
-					chan->key = NULL;
-					break;
-				case 'l':
-					chan->limit = 0;
-					break;
-			}
-			for (i = 0; i < chan->nargs; i++) {
-				if (chan->args[i].type == *change) {
-					str_redup(&chan->args[i].value, NULL);
-					break;
-				}
-			}
-		}
+	va_list args;
+	xml_node_t *node;
 
-		/* Now trigger the mode bind. */
-		if (trigger_bind) bind_check(BT_mode, u ? &u->settings[0].flags : NULL, changestr, from_nick, from_uhost, u, dest, changestr, arg);
-		change++;
-	}
+	va_start(args, value);
+	node = xml_node_vlookup(chan->settings, args, 1);
+	va_end(args);
+	return xml_node_set_str(value, node, NULL);
 }
 
-/* Got an absolute channel mode. */
-static int got324(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+int channel_get(channel_t *chan, char **strptr, ...)
 {
-	parse_chan_mode(from_nick, from_uhost, u, nargs-1, args+1, 0);
-	return(0);
+	va_list args;
+	xml_node_t *node;
+
+	va_start(args, strptr);
+	node = xml_node_vlookup(chan->settings, args, 0);
+	va_end(args);
+	return xml_node_get_str(strptr, node, NULL);
 }
 
-/* Got a mode change. */
-static int gotmode(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
+int channel_get_int(channel_t *chan, int *intptr, ...)
 {
-	char *dest = args[0];
-	char *change = args[1];
-	char changestr[3];
-
-	changestr[0] = '+';
-	changestr[2] = 0;
-
-	/* Is it a user mode? */
-	if (!strchr(current_server.chantypes, *dest)) {
-		while (*change) {
-			/* Direction? */
-			if (*change == '+' || *change == '-') {
-				changestr[0] = *change;
-				change++;
-				continue;
-			}
+	va_list args;
+	xml_node_t *node;
 
-			changestr[1] = *change;
-			bind_check(BT_mode, u ? &u->settings[0].flags : NULL, changestr, from_nick, from_uhost, u, dest, changestr, NULL);
-			change++;
-		}
-		return(0);
-	}
-
-	parse_chan_mode(from_nick, from_uhost, u, nargs, args, 1);
-	return(0);
+	va_start(args, intptr);
+	node = xml_node_vlookup(chan->settings, args, 0);
+	va_end(args);
+	return xml_node_get_int(intptr, node, NULL);
 }
 
-int channel_set(channel_t *chanptr, const char *setting, const char *value)
+xml_node_t *channel_get_node(channel_t *chan, ...)
 {
-	return 0;
-}
+	va_list args;
+	xml_node_t *node;
 
-int channel_info(partymember_t *p, const char *channame)
-{
-	return 0;
+	va_start(args, chan);
+	node = xml_node_vlookup(chan->settings, args, 0);
+	va_end(args);
+	return(node);
 }
 
-static int chanfile_save_channel(xml_node_t *root, channel_t *chan)
+int channel_load(const char *fname)
 {
-	return 0;
+	xml_node_t *root = xml_parse_file(fname);
+	xml_node_t *chan_node, *settings;
+	channel_t *chan;
+	char *name;
+	int flags;
+
+	if (!root) {
+		putlog(LOG_MISC, "*", "Could not load channel file '%s': %s", fname, xml_last_error());
+		return(-1);
+	}
+
+	chan_node = xml_node_lookup(root, 0, "channel", 0, 0);
+	for (; chan_node; chan_node = chan_node->next_sibling) {
+		xml_node_get_vars(chan_node, "sin", "name", &name, "flags", &flags, "settings", &settings);
+		if (!name) continue;
+		chan = channel_probe(name, 1);
+		if (settings) {
+			xml_node_unlink(settings);
+			xml_node_delete(chan->settings);
+			chan->settings = settings;
+		}
+		chan->flags = flags;
+	}
+	return(0);
 }
 
 int channel_save(const char *fname)
 {
-	return 0;
-}
+	xml_node_t *root = xml_node_new();
+	xml_node_t *chan_node;
+	channel_t *chan;
 
-int channel_load(const char *fname)
-{
-	xml_node_t *root;
+	if (!fname) fname = "channels.xml";
+	root->name = strdup("channels");
+	for (chan = channel_head; chan; chan = chan->next) {
+		if (!(chan->flags & CHANNEL_STATIC)) continue;
 
-	root = xml_node_new();
-	return 0;
+		chan_node = xml_node_new();
+		chan_node->name = strdup("channel");
+		xml_node_set_str(chan->name, chan_node, "name", 0, 0);
+		xml_node_set_int(chan->flags, chan_node, "flags", 0, 0);
+		xml_node_append(chan_node, chan->settings);
+		xml_node_append(root, chan_node);
+	}
+	xml_save_file(fname, root, XML_INDENT);
+	for (chan = channel_head; chan; chan = chan->next) {
+		if (chan->settings) xml_node_unlink(chan->settings);
+	}
+	xml_node_delete(root);
+	return(0);
 }
-
-static bind_list_t channel_raw_binds[] = {
-	/* WHO replies */
-	{NULL, "352", got352}, /* WHO reply */
-	{NULL, "315", got315}, /* end of WHO */
-
-	/* NAMES replies */
-	{NULL, "353", got353}, /* NAMES reply */
-	{NULL, "366", got366}, /* end of NAMES */
-
-	/* Topic info */
-	{NULL, "TOPIC", gottopic},
-	{NULL, "331", got331},
-	{NULL, "332", got332},
-	{NULL, "333", got333},
-
-	/* Channel member stuff. */
-	{NULL, "JOIN", gotjoin},
-	{NULL, "PART", gotpart},
-	{NULL, "QUIT", gotquit},
-	{NULL, "KICK", gotkick},
-	{NULL, "NICK", gotnick},
-
-	/* Mode. */
-	{NULL, "324", got324},
-	{NULL, "MODE", gotmode},
-
-	{NULL, NULL, NULL}
-};
Index: eggdrop1.9/modules/server/channels.h
diff -u eggdrop1.9/modules/server/channels.h:1.20 eggdrop1.9/modules/server/channels.h:1.21
--- eggdrop1.9/modules/server/channels.h:1.20	Sun Sep 26 04:42:09 2004
+++ eggdrop1.9/modules/server/channels.h	Mon Oct  4 10:48:30 2004
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
- * $Id: channels.h,v 1.20 2004/09/26 09:42:09 stdarg Exp $
+ * $Id: channels.h,v 1.21 2004/10/04 15:48:30 stdarg Exp $
  */
 
 #ifndef _EGG_MOD_SERVER_CHANNELS_H_
@@ -28,6 +28,10 @@
 #define CHANNEL_NAMESLIST	0x4
 #define CHANNEL_JOINED		0x8
 
+/* Flag bits for channels. */
+#define	CHANNEL_STATIC		0x1
+#define CHANNEL_INACTIVE	0x2
+
 #define BOT_ISOP(chanptr) (((chanptr)->status & CHANNEL_JOINED) && flag_match_single_char(&((chanptr)->bot->mode), 'o'))
 #define BOT_ISHALFOP(chanptr) (((chanptr)->status & CHANNEL_JOINED) && flag_match_single_char(&((chanptr)->bot->mode), 'h'))
 #define BOT_CAN_SET_MODES(chanptr) (((chanptr)->status & CHANNEL_JOINED) && (flag_match_single_char(&((chanptr)->bot->mode), 'o') \
@@ -70,7 +74,7 @@
 } channel_mode_arg_t;
 
 typedef struct channel {
-	struct channel *next;
+	struct channel *next, *prev;
 
 	char *name;
 
@@ -87,12 +91,14 @@
 	channel_mode_arg_t *args;	/* Stored channel modes. */
 	int nargs;
 
-	int status;
-
 	channel_member_t *member_head;	/* Member list. */
 	int nmembers;
 
 	channel_member_t *bot;		/* All you need to know about me :-) */
+
+	xml_node_t *settings;	/* Extended settings for scripts/modules/us. */
+	int status;		/* Status of channel. */
+	int flags;		/* Internal flags for channel. */
 } channel_t;
 
 extern channel_t *channel_head;
@@ -100,28 +106,40 @@
 
 extern hash_table_t *uhost_cache_ht;
 
-extern void server_channel_init();
-extern void server_channel_destroy();
-extern int channel_lookup(const char *chan_name, int create, channel_t **chanptr, channel_t **prevptr);
-extern char *uhost_cache_lookup(const char *nick);
-extern void uhost_cache_fillin(const char *nick, const char *uhost, int addref);
+/* channels.c */
+extern void channel_init();
+extern void channel_reset();
+extern void channel_destroy();
+extern void channel_free(channel_t *chan);
+extern channel_t *channel_probe(const char *chan_name, int create);
+extern channel_t *channel_add(const char *name);
+extern int channel_remove(const char *name);
+extern int channel_load(const char *fname);
+extern int channel_save(const char *fname);
+extern int channel_set(channel_t *chan, const char *value, ...);
+extern int channel_get(channel_t *chan, char **strptr, ...);
+extern int channel_get_int(channel_t *chan, int *intptr, ...);
+extern xml_node_t *channel_get_node(channel_t *chan, ...);
 extern int channel_mode(const char *chan_name, const char *nick, char *buf);
 extern int channel_mode_arg(const char *chan_name, int type, const char **value);
+extern channel_mask_list_t *channel_get_mask_list(channel_t *chan, char type);
+extern void channel_add_mask(channel_t *chan, char type, const char *mask, const char *set_by, int time);
+extern void channel_del_mask(channel_t *chan, char type, const char *mask);
 
-/* Events that hook into input.c. */
-extern void channel_on_nick(const char *old_nick, const char *new_nick);
+/* channel_events.c */
+extern void channel_events_init();
+extern void channel_events_destroy();
+extern void channel_free_online(channel_t *chan);
 extern void channel_on_quit(const char *nick, const char *uhost, user_t *u);
-extern void channel_on_leave(const char *chan_name, const char *nick, const char *uhost, user_t *u);
-extern void channel_on_join(const char *chan_name, const char *nick, const char *uhost);
+extern void channel_on_connect();
 
-/* Functions for others (scripts/modules) to access channel data. */
-extern void channel_reset();
-extern int channel_list(const char ***chans);
-extern int channel_list_members(const char *chan, const char ***members);
-extern channel_mask_list_t *channel_get_mask_list(channel_t *chan, char type);
-extern void channel_add_mask(channel_t *chan, char type, const char *mask, const char *set_by, int time);
-extern int channel_del_mask(channel_t *chan, char type, const char *mask, int remove);
-extern void channel_clear_masks(channel_t *chan, char type);
-extern int channel_list_masks(channel_mask_t ***cm, char type, channel_t *chanptr, const char *mask);
+/* uhost_cache.c */
+extern void uhost_cache_init();
+extern void uhost_cache_reset();
+extern void uhost_cache_destroy();
+extern char *uhost_cache_lookup(const char *nick);
+extern void uhost_cache_addref(const char *nick, const char *uhost);
+extern void uhost_cache_decref(const char *nick);
+void uhost_cache_swap(const char *old_nick, const char *new_nick);
 
 #endif /* !_EGG_MOD_SERVER_CHANNELS_H_ */
Index: eggdrop1.9/modules/server/egg_server_internal.h
diff -u eggdrop1.9/modules/server/egg_server_internal.h:1.6 eggdrop1.9/modules/server/egg_server_internal.h:1.7
--- eggdrop1.9/modules/server/egg_server_internal.h:1.6	Fri Oct  1 11:13:31 2004
+++ eggdrop1.9/modules/server/egg_server_internal.h	Mon Oct  4 10:48:30 2004
@@ -25,12 +25,11 @@
 
 /* Things from channels.c */
 #define channel_head server_LTX_channel_head
-#define uhost_cache_ht server_LTX_uhost_cache_ht
 #define nchannels server_LTX_nchannels
-#define server_channel_init server_LTX_server_channel_init
-#define server_channel_destroy server_LTX_server_channel_destroy
+#define channel_init server_LTX_server_channel_init
+#define channel_destroy server_LTX_server_channel_destroy
 #define channel_reset server_LTX_channel_reset
-#define channel_lookup server_LTX_channel_lookup
+#define channel_probe server_LTX_channel_probe
 #define uhost_cache_lookup server_LTX_uhost_cache_lookup
 #define uhost_cache_addref server_LTX_uhost_cache_addref
 #define uhost_cache_decref server_LTX_uhost_cache_decref
@@ -38,8 +37,6 @@
 #define channel_on_leave server_LTX_channel_on_leave
 #define channel_on_quit server_LTX_channel_on_quit
 #define channel_on_nick server_LTX_channel_on_nick
-#define channel_list server_LTX_channel_list
-#define channel_list_members server_LTX_channel_list_members
 #define channel_get_mask_list server_LTX_channel_get_mask_list
 #define channel_add_mask server_LTX_channel_add_mask
 #define channel_del_mask server_LTX_channel_del_mask
Index: eggdrop1.9/modules/server/input.c
diff -u eggdrop1.9/modules/server/input.c:1.36 eggdrop1.9/modules/server/input.c:1.37
--- eggdrop1.9/modules/server/input.c:1.36	Fri Oct  1 11:13:31 2004
+++ eggdrop1.9/modules/server/input.c	Mon Oct  4 10:48:30 2004
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: input.c,v 1.36 2004/10/01 16:13:31 stdarg Exp $";
+static const char rcsid[] = "$Id: input.c,v 1.37 2004/10/04 15:48:30 stdarg Exp $";
 #endif
 
 #include "server.h"
@@ -200,7 +200,7 @@
 	}
 
 	/* Join all channels. */
-	schan_on_connect();
+	channel_on_connect();
 	return(0);
 }
 
Index: eggdrop1.9/modules/server/party_commands.c
diff -u eggdrop1.9/modules/server/party_commands.c:1.17 eggdrop1.9/modules/server/party_commands.c:1.18
--- eggdrop1.9/modules/server/party_commands.c:1.17	Sun Sep 26 04:42:09 2004
+++ eggdrop1.9/modules/server/party_commands.c	Mon Oct  4 10:48:30 2004
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: party_commands.c,v 1.17 2004/09/26 09:42:09 stdarg Exp $";
+static const char rcsid[] = "$Id: party_commands.c,v 1.18 2004/10/04 15:48:30 stdarg Exp $";
 #endif
 
 #include "server.h"
@@ -165,21 +165,83 @@
 	return(0);
 }
 
+static void parse_chanset(channel_t *chan, const char *settings)
+{
+	char *name, *value;
+	char flagbuf[2] = {0, 0};
+
+	while (settings) {
+		egg_get_arg(settings, &settings, &name);
+		if (!name) break;
+		if (*name == '+' || *name == '-') {
+			if (*name == '+') flagbuf[0] = '1';
+			else flagbuf[0] = '0';
+			value = flagbuf;
+			if (*(name+1)) channel_set(chan, flagbuf, name+1, 0, NULL);
+		}
+		else {
+			egg_get_arg(settings, &settings, &value);
+			channel_set(chan, value, name, 0, NULL);
+			if (value) free(value);
+		}
+		free(name);
+	}
+}
+
 /* +chan <name> [settings] */
 static int party_pls_chan(partymember_t *p, const char *nick, user_t *u, const char *cmd, const char *text)
 {
+	const char *settings;
+	char *name;
+	channel_t *chan;
+
+	egg_get_arg(text, &settings, &name);
+	if (!name) {
+		partymember_printf(p, "Syntax: %s <channel> [settings]", cmd);
+		return(0);
+	}
+	chan = channel_add(name);
+	free(name);
+	parse_chanset(chan, settings);
 	return BIND_RET_LOG;
 }
 
 /* -chan <name> */
 static int party_mns_chan(partymember_t *p, const char *nick, user_t *u, const char *cmd, const char *text)
 {
+	while (text && isspace(*text)) text++;
+	if (!text || !*text) {
+		partymember_printf(p, "Syntax: %s <channel>", cmd);
+		return(0);
+	}
+	if (channel_remove(text)) {
+		partymember_printf(p, "Channel not found!");
+		return(0);
+	}
+	partymember_printf(p, "Channel removed.");
+	printserv(SERVER_NORMAL, "PART %s", text);
 	return BIND_RET_LOG;
 }
 
 /* chanset <channel / *> <setting> [data] */
 static int party_chanset(partymember_t *p, const char *nick, user_t *u, const char *cmd, const char *text)
 {
+	const char *settings;
+	char *name;
+	channel_t *chan;
+
+	egg_get_arg(text, &settings, &name);
+	if (!name) {
+		partymember_printf(p, "Syntax: %s <channel> [settings]", cmd);
+		return(0);
+	}
+	chan = channel_probe(name, 0);
+	free(name);
+	if (!chan) {
+		partymember_printf(p, "Channel not found! Use +chan if you want to create a new channel.");
+		return(0);
+	}
+	parse_chanset(chan, settings);
 	return BIND_RET_LOG;
 }
 
@@ -192,6 +254,8 @@
 /* chansave [filename] */
 static int party_chansave(partymember_t *p, const char *nick, user_t *u, const char *cmd, const char *text)
 {
+	while (text && isspace(*text)) text++;
+	channel_save(text && *text ? text : server_config.chanfile);
 	return BIND_RET_LOG;
 }
 
Index: eggdrop1.9/modules/server/schan.c
diff -u eggdrop1.9/modules/server/schan.c:1.2 eggdrop1.9/modules/server/schan.c:removed
--- eggdrop1.9/modules/server/schan.c:1.2	Fri Oct  1 11:13:31 2004
+++ eggdrop1.9/modules/server/schan.c	Mon Oct  4 10:48:40 2004
@@ -1,164 +0,0 @@
-#include "server.h"
-
-static schan_t *schan_head = NULL;
-static int nschans = 0;
-
-/* Prototypes. */
-int schan_load(const char *fname);
-int schan_save(const char *fname);
-
-void server_schan_init()
-{
-	schan_load(server_config.chanfile);
-}
-
-void server_schan_destroy()
-{
-	schan_save(server_config.chanfile);
-}
-
-/* We just finished connecting (got motd), join our channels. */
-void schan_on_connect()
-{
-	schan_t *chan;
-
-	for (chan = schan_head; chan; chan = chan->next) {
-		if (chan->key && strlen(chan->key)) printserv(SERVER_NORMAL, "JOIN %s %s", chan->name, chan->key);
-		else printserv(SERVER_NORMAL, "JOIN %s", chan->name);
-	}
-}
-
-/* Append a new channel. */
-static schan_t *schan_append(const char *chan_name, xml_node_t *settings)
-{
-	schan_t *chan, *prev = NULL;
-
-	for (chan = schan_head; chan && chan->next; chan = chan->next) {
-		prev = chan;
-	}
-	nschans++;
-	chan = calloc(1, sizeof(*chan));
-	chan->name = strdup(chan_name);
-	if (!settings) {
-		settings = xml_node_new();
-		settings->name = strdup("settings");
-	}
-	chan->settings = settings;
-	if (prev) prev->next = chan;
-	else schan_head = chan;
-	return(chan);
-}
-
-/* Find or create channel when passed 0 or 1 */
-static int schan_probe(const char *chan_name, int create, schan_t **chanptr, schan_t **prevptr)
-{
-	schan_t *chan, *prev;
-
-	*chanptr = NULL;
-	if (prevptr) *prevptr = NULL;
-
-	prev = NULL;
-	for (chan = schan_head; chan; chan = chan->next) {
-		if (!strcasecmp(chan->name, chan_name)) {
-			*chanptr = chan;
-			if (prevptr) *prevptr = prev;
-			return -create; /* Report error if we were supposed to
-					   create new channel */
-		}
-		prev = chan;
-	}
-	if (!create) return -1;
-	*chanptr = schan_append(chan_name, NULL);
-	return(0);
-}
-
-schan_t *schan_lookup(const char *chan_name, int create)
-{
-	schan_t *chan;
-
-	schan_probe(chan_name, create, &chan, NULL);
-	return(chan);
-}
-
-int schan_delete(const char *chan_name)
-{
-	schan_t *chan, *prev;
-
-	schan_probe(chan_name, 0, &chan, &prev);
-	if (!chan) return(-1);
-	if (prev) prev->next = chan->next;
-	else schan_head = chan->next;
-	xml_node_delete(chan->settings);
-	free(chan->name);
-	free(chan);
-	return(0);
-}
-
-int schan_set(schan_t *chan, const char *value, ...)
-{
-	va_list args;
-	xml_node_t *node;
-
-	va_start(args, value);
-	node = xml_node_vlookup(chan->settings, args, 1);
-	va_end(args);
-	return xml_node_set_str(value, node, NULL);
-}
-
-int schan_get(schan_t *chan, char **strptr, ...)
-{
-	va_list args;
-	xml_node_t *node;
-
-	va_start(args, strptr);
-	node = xml_node_vlookup(chan->settings, args, 0);
-	va_end(args);
-	return xml_node_get_str(strptr, node, NULL);
-}
-
-int schan_load(const char *fname)
-{
-	xml_node_t *root = xml_parse_file(fname);
-	xml_node_t *chan_node, *settings;
-	schan_t *chan;
-	char *name, *key;
-
-	if (!root) {
-		putlog(LOG_MISC, "*", "Could not load channel file '%s': %s", fname, xml_last_error());
-		return(-1);
-	}
-
-	chan_node = xml_node_lookup(root, 0, "channel", 0, 0);
-	for (; chan_node; chan_node = chan_node->next_sibling) {
-		xml_node_get_vars(chan_node, "ssn", "name", &name, "key", &key, "settings", &settings);
-		if (!name) continue;
-		if (settings) xml_node_unlink(settings);
-		chan = schan_append(name, settings);
-		if (chan) str_redup(&chan->key, key);
-	}
-	return(0);
-}
-
-int schan_save(const char *fname)
-{
-	xml_node_t *root = xml_node_new();
-	xml_node_t *chan_node;
-	schan_t *chan;
-
-	if (!fname) fname = "channels.xml";
-	root->name = strdup("channels");
-	for (chan = schan_head; chan; chan = chan->next) {
-		chan_node = xml_node_new();
-		chan_node->name = strdup("channel");
-		xml_node_set_str(chan->name, chan_node, "name", 0, 0);
-		xml_node_set_str(chan->key, chan_node, "key", 0, 0);
-		xml_node_append(chan_node, chan->settings);
-		xml_node_append(root, chan_node);
-	}
-	xml_save_file(fname, root, XML_INDENT);
-	for (chan = schan_head; chan; chan = chan->next) {
-		xml_node_unlink(chan->settings);
-	}
-	xml_node_delete(root);
-	return(0);
-}
Index: eggdrop1.9/modules/server/schan.h
diff -u eggdrop1.9/modules/server/schan.h:1.2 eggdrop1.9/modules/server/schan.h:removed
--- eggdrop1.9/modules/server/schan.h:1.2	Fri Oct  1 11:13:31 2004
+++ eggdrop1.9/modules/server/schan.h	Mon Oct  4 10:48:40 2004
@@ -1,21 +0,0 @@
-#ifndef _EGG_MOD_SERVER_SCHAN_H_
-#define _EGG_MOD_SERVER_SCHAN_H_
-
-typedef struct schan {
-	struct schan *next;
-	char *name;
-	char *key;
-	xml_node_t *settings;
-} schan_t;
-
-void server_schan_init();
-void server_schan_destroy();
-void schan_on_connect();
-schan_t *schan_lookup(const char *chan_name, int create);
-int schan_delete(const char *chan_name);
-int schan_set(schan_t *chan, const char *value, ...);
-int schan_get(schan_t *chan, char **strptr, ...);
-int schan_load(const char *fname);
-int schan_save(const char *fname);
-
-#endif
Index: eggdrop1.9/modules/server/scriptcmds.c
diff -u eggdrop1.9/modules/server/scriptcmds.c:1.45 eggdrop1.9/modules/server/scriptcmds.c:1.46
--- eggdrop1.9/modules/server/scriptcmds.c:1.45	Fri Oct  1 10:31:18 2004
+++ eggdrop1.9/modules/server/scriptcmds.c	Mon Oct  4 10:48:30 2004
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: scriptcmds.c,v 1.45 2004/10/01 15:31:18 stdarg Exp $";
+static const char rcsid[] = "$Id: scriptcmds.c,v 1.46 2004/10/04 15:48:30 stdarg Exp $";
 #endif
 
 #include "server.h"
@@ -150,7 +150,7 @@
 	retval->type = SCRIPT_ARRAY | SCRIPT_FREE | SCRIPT_VAR;
 	retval->len = 0;
 
-	channel_lookup(chan_name, 0, &chan, NULL);
+	chan = channel_probe(chan_name, 0);
 	if (!chan) return(-1);
 
 	for (m = chan->member_head; m; m = m->next) {
@@ -167,7 +167,7 @@
 	retval->type = SCRIPT_ARRAY | SCRIPT_FREE | SCRIPT_VAR;
 	retval->len = 0;
 
-	channel_lookup(chan_name, 0, &chan, NULL);
+	chan = channel_probe(chan_name, 0);
 	if (!chan) return(-1);
 
 	script_list_append(retval, script_string(chan->topic, -1));
@@ -185,7 +185,7 @@
 	retval->type = SCRIPT_ARRAY | SCRIPT_FREE | SCRIPT_VAR;
 	retval->len = 0;
 
-	channel_lookup(chan_name, 0, &chan, NULL);
+	chan = channel_probe(chan_name, 0);
 	if (!chan) return(-1);
 
 	l = channel_get_mask_list(chan, type[0]);
@@ -224,7 +224,7 @@
 {
 	channel_t *chan;
 
-	channel_lookup(chan_name, 0, &chan, NULL);
+	chan = channel_probe(chan_name, 0);
 	if (chan) return(chan->key);
 	return(NULL);
 }
@@ -233,29 +233,27 @@
 {
 	channel_t *chan;
 
-	channel_lookup(chan_name, 0, &chan, NULL);
+	chan = channel_probe(chan_name, 0);
 	if (chan) return(chan->limit);
 	return(-1);
 }
 
-/* Schan commands. */
-
 static char *script_schan_get(char *chan_name, char *setting)
 {
-	schan_t *chan = schan_lookup(chan_name, 0);
+	channel_t *chan = channel_probe(chan_name, 0);
 	char *value;
 
 	if (!chan) return(NULL);
-	schan_get(chan, &value, setting, 0, NULL);
+	channel_get(chan, &value, setting, 0, NULL);
 	return(value);
 }
 
 static int script_schan_set(char *chan_name, char *setting, char *value)
 {
-	schan_t *chan = schan_lookup(chan_name, 1);
+	channel_t *chan = channel_probe(chan_name, 1);
 
 	if (!chan) return(-1);
-	return schan_set(chan, value, setting, 0, NULL);
+	return channel_set(chan, value, setting, 0, NULL);
 }
 
 /* Output queue commands. */
Index: eggdrop1.9/modules/server/server.c
diff -u eggdrop1.9/modules/server/server.c:1.61 eggdrop1.9/modules/server/server.c:1.62
--- eggdrop1.9/modules/server/server.c:1.61	Fri Oct  1 10:31:18 2004
+++ eggdrop1.9/modules/server/server.c	Mon Oct  4 10:48:30 2004
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: server.c,v 1.61 2004/10/01 15:31:18 stdarg Exp $";
+static const char rcsid[] = "$Id: server.c,v 1.62 2004/10/04 15:48:30 stdarg Exp $";
 #endif
 
 #include "server.h"
@@ -84,6 +84,7 @@
 static int server_status(partymember_t *p, const char *text)
 {
 	int details = 0;
+	channel_t *chan;
 
 	if (text) {
 		if (!strcasecmp(text, "all") || !strcasecmp(text, "server")) details = 1;
@@ -94,27 +95,30 @@
 	if (!current_server.connected) {
 		if (current_server.idx >= 0) partymember_printf(p, _("   Connecting to server %s/%d."), current_server.server_host, current_server.port);
 		else partymember_printf(p, _("   Connecting to next server in %d seconds."), cycle_delay);
+		return(0);
 	}
-	else {
-		/* First line, who we've connected to. */
-		partymember_printf(p, _("   Connected to %s/%d."), current_server.server_self ? current_server.server_self : current_server.server_host, current_server.port);
-
-		/* Second line, who we're connected as. */
-		if (current_server.registered) {
-			if (current_server.user) partymember_printf(p, _("   Online as %s!%s@%s (%s)."), current_server.nick, current_server.user, current_server.host, current_server.real_name);
-			else partymember_printf(p, _("   Online as %s (still waiting for WHOIS result)."), current_server.nick);
-		}
-		else partymember_printf(p, _("   Still logging in."));
+	/* First line, who we've connected to. */
+	partymember_printf(p, _("   Connected to %s/%d."), current_server.server_self ? current_server.server_self : current_server.server_host, current_server.port);
 
-		/* Some traffic stats. */
-		if (details) {
-			sockbuf_stats_t *stats;
+	/* Second line, who we're connected as. */
+	if (current_server.registered) {
+		if (current_server.user) partymember_printf(p, _("   Online as %s!%s@%s (%s)."), current_server.nick, current_server.user, current_server.host, current_server.real_name);
+		else partymember_printf(p, _("   Online as %s (still waiting for WHOIS result)."), current_server.nick);
+	}
+	else partymember_printf(p, _("   Still logging in."));
 
-			sockbuf_get_stats(current_server.idx, &stats);
-			partymember_printf(p, "   Server traffic: %lld in / %lld out (raw), %lld in / %lld out (filtered)", stats->raw_bytes_in, stats->raw_bytes_out, stats->bytes_in, stats->bytes_out);
-		}
+	/* Print the channel list if we have one. */
+	for (chan = channel_head; chan; chan = chan->next) {
+		partymember_printf(p, "   %s : %d member%s", chan->name, chan->nmembers, chan->nmembers == 1 ? "" : "s");
+	}
+
+	/* Some traffic stats. */
+	if (details) {
+		sockbuf_stats_t *stats;
+
+		sockbuf_get_stats(current_server.idx, &stats);
+		partymember_printf(p, "   Server traffic: %lld in / %lld out (raw), %lld in / %lld out (filtered)", stats->raw_bytes_in, stats->raw_bytes_out, stats->bytes_in, stats->bytes_out);
 	}
-	partymember_printf(p, "");
 	return(0);
 }
 
@@ -154,7 +158,7 @@
 
 	/* Save the channel file. */
 	putlog(LOG_MISC, "*", "Saving channels file...");
-	schan_save(server_config.chanfile);
+	channel_save(server_config.chanfile);
 	return(0);
 }
 
@@ -175,9 +179,9 @@
 
 	server_binds_destroy();
 
-	server_channel_destroy();
-
-	server_schan_destroy();
+	channel_destroy();
+	channel_events_destroy();
+	uhost_cache_destroy();
 
 	server_script_destroy();
 
@@ -283,8 +287,9 @@
 	bind_add_simple("config_save", NULL, "eggdrop", server_config_save);
 
 	/* Initialize channels. */
-	server_channel_init();
-	server_schan_init();
+	channel_init();
+	channel_events_init();
+	uhost_cache_init();
 
 	/* Initialize script interface. */
 	server_script_init();
Index: eggdrop1.9/modules/server/server.h
diff -u eggdrop1.9/modules/server/server.h:1.21 eggdrop1.9/modules/server/server.h:1.22
--- eggdrop1.9/modules/server/server.h:1.21	Fri Oct  1 10:31:18 2004
+++ eggdrop1.9/modules/server/server.h	Mon Oct  4 10:48:30 2004
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
- * $Id: server.h,v 1.21 2004/10/01 15:31:18 stdarg Exp $
+ * $Id: server.h,v 1.22 2004/10/04 15:48:30 stdarg Exp $
  */
 
 #ifndef _EGG_MOD_SERVER_SERVER_H_
@@ -95,7 +95,6 @@
 #include "servsock.h"
 #include "nicklist.h"
 #include "serverlist.h"
-#include "schan.h"
 
 extern server_config_t server_config;
 extern current_server_t current_server;
Index: eggdrop1.9/modules/server/uhost_cache.c
diff -u /dev/null eggdrop1.9/modules/server/uhost_cache.c:1.1
--- /dev/null	Mon Oct  4 10:48:40 2004
+++ eggdrop1.9/modules/server/uhost_cache.c	Mon Oct  4 10:48:30 2004
@@ -0,0 +1,110 @@
+#include "server.h"
+
+#define UHOST_CACHE_SIZE 47
+
+static hash_table_t *uhost_cache_ht = NULL;
+
+/* Prototypes. */
+static int uhost_cache_delete(const void *key, void *data, void *param);
+
+void uhost_cache_init()
+{
+	uhost_cache_ht = hash_table_create(NULL, NULL, UHOST_CACHE_SIZE, HASH_TABLE_STRINGS);
+}
+
+/* Reset everything when we disconnect from the server. */
+void uhost_cache_reset()
+{
+	uhost_cache_destroy();
+	uhost_cache_init();
+}
+
+void uhost_cache_destroy()
+{
+	hash_table_walk(uhost_cache_ht, uhost_cache_delete, NULL);
+	hash_table_delete(uhost_cache_ht);
+}
+
+static int uhost_cache_delete(const void *key, void *dataptr, void *param)
+{
+	uhost_cache_entry_t *cache = *(void **)dataptr;
+
+	if (cache->nick) free(cache->nick);
+	if (cache->uhost) free(cache->uhost);
+	free(cache);
+	return(0);
+}
+
+static uhost_cache_entry_t *cache_lookup(const char *nick)
+{
+	char buf[64], *lnick;
+	uhost_cache_entry_t *cache = NULL;
+
+	lnick = egg_msprintf(buf, sizeof(buf), NULL, "%s", nick);
+	str_tolower(lnick);
+	hash_table_find(uhost_cache_ht, lnick, &cache);
+	if (lnick != buf) free(lnick);
+	return(cache);
+}
+
+char *uhost_cache_lookup(const char *nick)
+{
+	uhost_cache_entry_t *cache;
+
+	cache = cache_lookup(nick);
+	if (cache) return(cache->uhost);
+	return(NULL);
+}
+
+void uhost_cache_addref(const char *nick, const char *uhost)
+{
+	char buf[64], *lnick;
+	uhost_cache_entry_t *cache = NULL;
+
+	lnick = egg_msprintf(buf, sizeof(buf), NULL, "%s", nick);
+	str_tolower(lnick);
+	hash_table_find(uhost_cache_ht, lnick, &cache);
+	if (!cache) {
+		cache = calloc(1, sizeof(*cache));
+		cache->nick = strdup(nick);
+		str_tolower(cache->nick);
+		if (uhost) cache->uhost = strdup(uhost);
+		hash_table_insert(uhost_cache_ht, cache->nick, cache);
+	}
+	cache->ref_count++;
+	if (lnick != buf) free(lnick);
+}
+
+void uhost_cache_decref(const char *nick)
+{
+	uhost_cache_entry_t *cache;
+
+	/* We don't decrement ourselves.. we always know our own host. */
+	if (match_my_nick(nick)) return;
+
+	cache = cache_lookup(nick);
+	if (!cache) return;
+
+	cache->ref_count--;
+	if (cache->ref_count <= 0) {
+		hash_table_remove(uhost_cache_ht, cache->nick, NULL);
+		uhost_cache_delete(NULL, cache, NULL);
+	}
+}
+
+void uhost_cache_swap(const char *old_nick, const char *new_nick)
+{
+	uhost_cache_entry_t *cache;
+	char buf[64], *lnick;
+
+	lnick = egg_msprintf(buf, sizeof(buf), NULL, "%s", old_nick);
+	str_tolower(lnick);
+	hash_table_remove(uhost_cache_ht, lnick, &cache);
+	if (lnick != buf) free(lnick);
+
+	if (cache) {
+		str_redup(&cache->nick, new_nick);
+		str_tolower(cache->nick);
+		hash_table_insert(uhost_cache_ht, cache->nick, cache);
+	}
+}
Index: eggdrop1.9/src/logfile.c
diff -u eggdrop1.9/src/logfile.c:1.48 eggdrop1.9/src/logfile.c:1.49
--- eggdrop1.9/src/logfile.c:1.48	Sun Sep 26 04:42:09 2004
+++ eggdrop1.9/src/logfile.c	Mon Oct  4 10:48:30 2004
@@ -19,7 +19,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: logfile.c,v 1.48 2004/09/26 09:42:09 stdarg Exp $";
+static const char rcsid[] = "$Id: logfile.c,v 1.49 2004/10/04 15:48:30 stdarg Exp $";
 #endif
 
 #include <stdio.h>
@@ -173,6 +173,7 @@
 	logfiles = realloc(logfiles, (nlogfiles + 1) * sizeof(*logfiles));
 			
 	log = &logfiles[nlogfiles++];
+	memset(log, 0, sizeof(*log));
 	log->filename = strdup(fname);
 	log->chname = strdup(chan);
 	log->last_msg = strdup("");
----------------------- End of diff -----------------------



More information about the Changes mailing list