[cvslog] (2002-09-20 02:06:36 UTC) Module eggdrop1.7: Change committed

cvslog cvs at tsss.org
Thu Sep 19 21:07:01 CST 2002


CVSROOT    : /usr/local/cvsroot
Module     : eggdrop1.7
Commit time: 2002-09-20 02:06:35 UTC
Commited by: stdarg <stdarg at techmonkeys.org>

Modified files:
     configure.ac lib/compat/Makefile.am lib/eggdrop/Makefile.am
     lib/eggdrop/eggdrop.h lib/eggdrop/memutil.c lib/eggdrop/memutil.h
     lib/eggdrop/module.h lib/eggdrop/script.c lib/eggdrop/script.h
     modules/Makefile.am modules/javascript/javascript.c
     modules/perlscript/perlscript.c modules/server/Makefile.am
     modules/server/channels.c modules/server/scriptcmds.c
     modules/server/server.c modules/server/server.h
     modules/tclscript/tclscript.c src/Makefile.am src/egg_timer.c
     src/main.c src/modules.c src/net.c src/tclhash.c src/userrec.c
     src/userrec.h src/users.h testcode/dnscache.c testcode/socks5.c

Added files:
     lib/eggdrop/eggdns.c lib/eggdrop/eggdns.h lib/eggdrop/eggident.c
     lib/eggdrop/eggident.h lib/eggdrop/eggnet.c lib/eggdrop/eggnet.h
     lib/eggdrop/eggtimer.c lib/eggdrop/eggtimer.h
     lib/eggdrop/linemode.c lib/eggdrop/linemode.h
     modules/server/dcc_commands.c modules/server/input.c
     modules/server/nicklist.c modules/server/nicklist.h
     modules/server/output.c modules/server/output.h
     modules/server/parse.c modules/server/parse.h
     modules/server/serverlist.c modules/server/serverlist.h
     modules/server/servsock.c modules/server/servsock.h

Removed files:
     modules/server/cmdsserv.c modules/server/servmsg.c

Log message:

* Moved several things from the core into libegg
* Server module uses new network code
* Lots of stuff removed from the server module, like flood stuff, which should go into a new module
* Moved some things from irc module to server module (mostly bind stuff, like pub)
* Not everything works right now, but I wanted to get it into cvs in case my computer dies a horrible death. I'm going to combine irc/server (mostly) and make a new one for all the default protection stuff.
* Right now server messages are not queued. I thought the code was pretty much beyond repair. The new queueing code will hopefully be more maintainable.
* I'm not sure I added/removed all the files necessary! Let me know if it doesn't compile for you.

---------------------- diff included ----------------------
Index: eggdrop1.7/configure.ac
diff -u eggdrop1.7/configure.ac:1.23 eggdrop1.7/configure.ac:1.24
--- eggdrop1.7/configure.ac:1.23	Tue Jun 18 01:12:30 2002
+++ eggdrop1.7/configure.ac	Thu Sep 19 21:06:24 2002
@@ -68,7 +68,7 @@
 AC_CHECK_HEADERS(sys/time.h)
 AC_HEADER_TIME
 AC_CHECK_HEADERS(string.h strings.h ctype.h stdlib.h limits.h unistd.h)
-AC_CHECK_HEADERS(sys/rusage.h sys/select.h stdarg.h std_args.h)
+AC_CHECK_HEADERS(sys/rusage.h sys/select.h sys/poll.h stdarg.h std_args.h)
 
 # Checks for types and structures
 AC_TYPE_PID_T
@@ -85,7 +85,7 @@
 AC_CHECK_FUNCS(random srandom rename setpgid sigaction sigemptyset uname)
 
 # Check for these functions, and replace those not found
-AC_REPLACE_FUNCS(memcpy memset strcasecmp strncasecmp strftime strdup)
+AC_REPLACE_FUNCS(memcpy memset poll strcasecmp strncasecmp strftime strdup)
 AC_REPLACE_FUNCS(inet_ntop inet_pton strerror strlcat strlcpy)
 
 # These all share a common file: snprintf.c
@@ -172,6 +172,6 @@
 EGG_LTLIBOBJS
 
 # FIXME: module's Makefiles list will prolly become dynamic
-AC_OUTPUT([Makefile doc/Makefile intl/Makefile lib/Makefile lib/adns/Makefile lib/compat/Makefile lib/eggdrop/Makefile lib/egglib/Makefile modules/Makefile modules/blowfish/Makefile modules/channels/Makefile modules/compress/Makefile modules/console/Makefile modules/ctcp/Makefile modules/filesys/Makefile modules/irc/Makefile modules/javascript/Makefile modules/notes/Makefile modules/perlscript/Makefile modules/server/Makefile modules/share/Makefile modules/tclscript/Makefile modules/transfer/Makefile modules/uptime/Makefile po/Makefile.in scripts/Makefile nettype/Makefile src/Makefile])
+AC_OUTPUT([Makefile doc/Makefile intl/Makefile lib/Makefile lib/adns/Makefile lib/compat/Makefile lib/eggdrop/Makefile lib/egglib/Makefile modules/Makefile modules/blowfish/Makefile modules/compress/Makefile modules/console/Makefile modules/javascript/Makefile modules/perlscript/Makefile modules/server/Makefile modules/tclscript/Makefile po/Makefile.in scripts/Makefile nettype/Makefile src/Makefile])
 
 EGG_MSG_CONFIGURE_END
Index: eggdrop1.7/lib/compat/Makefile.am
diff -u eggdrop1.7/lib/compat/Makefile.am:1.6 eggdrop1.7/lib/compat/Makefile.am:1.7
--- eggdrop1.7/lib/compat/Makefile.am:1.6	Sat May 18 02:41:33 2002
+++ eggdrop1.7/lib/compat/Makefile.am	Thu Sep 19 21:06:25 2002
@@ -1,4 +1,4 @@
-# $Id: Makefile.am,v 1.6 2002/05/18 07:41:33 stdarg Exp $
+# $Id: Makefile.am,v 1.7 2002/09/20 02:06:25 stdarg Exp $
 
 ## libcompat is built as convenience library
 
@@ -17,6 +17,7 @@
 			inet_pton.h \
 			memcpy.h \
 			memset.h \
+			poll.h \
 			snprintf.h \
 			strcasecmp.h \
 			strdup.h \
Index: eggdrop1.7/lib/eggdrop/Makefile.am
diff -u eggdrop1.7/lib/eggdrop/Makefile.am:1.8 eggdrop1.7/lib/eggdrop/Makefile.am:1.9
--- eggdrop1.7/lib/eggdrop/Makefile.am:1.8	Sun May 12 00:59:50 2002
+++ eggdrop1.7/lib/eggdrop/Makefile.am	Thu Sep 19 21:06:25 2002
@@ -1,4 +1,4 @@
-# $Id: Makefile.am,v 1.8 2002/05/12 05:59:50 stdarg Exp $
+# $Id: Makefile.am,v 1.9 2002/09/20 02:06:25 stdarg Exp $
 
 MAINTAINERCLEANFILES	= Makefile.in
 
@@ -11,12 +11,18 @@
 			common.h \
 			eggdrop.c \
 			eggdrop.h \
+			eggdns.c eggdns.h \
+			eggident.c eggident.h \
+			eggnet.h eggnet.c \
+			eggtimer.c eggtimer.h \
 			fileutil.c \
 			fileutil.h \
+			linemode.c linemode.h \
 			memutil.c \
 			memutil.h \
-			script.c \
-			script.h \
+			my_socket.c my_socket.h \
+			script.c script.h \
+			sockbuf.c sockbuf.h \
 			stat.h
 
 libeggdrop_la_LIBADD	= $(top_builddir)/lib/compat/libcompat.la \
Index: eggdrop1.7/lib/eggdrop/eggdns.c
diff -u /dev/null eggdrop1.7/lib/eggdrop/eggdns.c:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/lib/eggdrop/eggdns.c	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,492 @@
+#if HAVE_CONFIG_H
+	#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include "my_socket.h"
+#include "sockbuf.h"
+#include "eggnet.h"
+#include "eggdns.h"
+
+static void get_dns_idx();
+static int dns_on_read(void *client_data, int idx, char *buf, int len);
+static int dns_on_eof(void *client_data, int idx, int err, const char *errmsg);
+static const char *dns_next_server();
+static void parse_reply(char *response, int nbytes);
+static int dns_make_query(const char *host, int type, char **buf, int *query_len, int (*callback)(), void *client_data);
+
+static sockbuf_handler_t dns_handler = {
+	"dns",
+	NULL, dns_on_eof, NULL,
+	dns_on_read, NULL
+};
+
+static int dns_idx = -1;
+static const char *dns_ip = NULL;
+
+static void get_dns_idx()
+{
+	int i, sock;
+
+	sock = -1;
+	for (i = 0; i < 5; i++) {
+		if (!dns_ip) dns_ip = dns_next_server();
+		sock = socket_create(dns_ip, DNS_PORT, NULL, 0, SOCKET_CLIENT | SOCKET_NONBLOCK | SOCKET_UDP);
+		if (sock < 0) {
+			/* Try the next server. */
+			dns_ip = NULL;
+		}
+		else break;
+	}
+	if (i == 5) return;
+	dns_idx = sockbuf_new();
+	sockbuf_set_handler(dns_idx, &dns_handler, NULL);
+	sockbuf_set_sock(dns_idx, sock, 0);
+}
+
+void egg_dns_send(char *query, int len)
+{
+	if (dns_idx < 0) {
+		get_dns_idx();
+		if (dns_idx < 0) return;
+	}
+	sockbuf_write(dns_idx, query, len);
+}
+
+/* Perform an async dns lookup. This is host -> ip. For ip -> host, use
+ * egg_dns_reverse(). We return a dns id that you can use to cancel the
+ * lookup. */
+int egg_dns_lookup(const char *host, int timeout, int (*callback)(), void *client_data)
+{
+	char *query;
+	int len, id;
+
+	if (socket_valid_ip(host)) {
+		/* If it's already an ip, we're done. */
+		callback(client_data, host, host);
+		return(-1);
+	}
+	/* Nope, we have to actually do a lookup. */
+	id = dns_make_query(host, DNS_IPV4, &query, &len, callback, client_data);
+	if (id != -1) {
+		egg_dns_send(query, len);
+		free(query);
+	}
+	return(id);
+}
+
+/* Perform an async dns reverse lookup. This does ip -> host. For host -> ip
+ * use egg_dns_lookup(). We return a dns id that you can use to cancel the
+ * lookup. */
+int egg_dns_reverse(const char *ip, int timeout, int (*callback)(), void *client_data)
+{
+	char *query;
+	int len, id;
+
+	if (!socket_valid_ip(ip)) {
+		/* If it's not a valid ip, don't even make the request. */
+		callback(client_data, ip, NULL);
+		return(-1);
+	}
+	/* Nope, we have to actually do a lookup. */
+	id = dns_make_query(ip, DNS_REVERSE, &query, &len, callback, client_data);
+	if (id != -1) {
+		egg_dns_send(query, len);
+		free(query);
+	}
+	return(id);
+}
+
+static int dns_on_read(void *client_data, int idx, char *buf, int len)
+{
+	parse_reply(buf, len);
+	return(0);
+}
+
+static int dns_on_eof(void *client_data, int idx, int err, const char *errmsg)
+{
+	sockbuf_delete(idx);
+	dns_idx = -1;
+	dns_ip = NULL;
+	return(0);
+}
+
+typedef struct dns_query {
+	struct dns_query *next;
+	char *query;
+	int id;
+	int (*callback)(void *client_data, const char *query, const char *result);
+	void *client_data;
+} dns_query_t;
+
+typedef struct {
+	unsigned short id;
+	unsigned short flags;
+	unsigned short question_count;
+	unsigned short answer_count;
+	unsigned short ns_count;
+	unsigned short ar_count;
+} dns_header_t;
+
+typedef struct {
+	/* char name[]; */
+	unsigned short type;
+	unsigned short class;
+	int ttl;
+	unsigned short rdlength;
+	/* char rdata[]; */
+} dns_rr_t;
+
+/* Entries from resolv.conf */
+typedef struct dns_server {
+	char *ip;
+	int idx;
+} dns_server_t;
+
+/* Entries from hosts */
+typedef struct {
+	char *host, *ip;
+} dns_host_t;
+
+static int query_id = 1;
+static dns_header_t _dns_header = {0};
+static dns_query_t *query_head = NULL;
+static dns_host_t *hosts = NULL;
+static int nhosts = 0;
+static dns_server_t *servers = NULL;
+static int nservers = 0;
+static int cur_server = -1;
+
+static char separators[] = " ,\t\r\n";
+
+static void read_resolv(char *fname);
+static void read_hosts(char *fname);
+
+/* Read in .hosts and /etc/hosts and .resolv.conf and /etc/resolv.conf */
+int egg_dns_init()
+{
+	_dns_header.flags = htons(1 << 8 | 1 << 7);
+	_dns_header.question_count = htons(1);
+	read_resolv("/etc/resolv.conf");
+	read_resolv(".resolv.conf");
+	read_hosts("/etc/hosts");
+	read_hosts(".hosts");
+	return(0);
+}
+
+static const char *dns_next_server()
+{
+	if (!servers || nservers < 1) return("127.0.0.1");
+	cur_server++;
+	if (cur_server >= nservers) cur_server = 0;
+	return(servers[cur_server].ip);
+}
+
+static void add_server(char *ip)
+{
+	servers = (dns_server_t *)realloc(servers, (nservers+1)*sizeof(*servers));
+	servers[nservers].ip = strdup(ip);
+	nservers++;
+}
+
+static void add_host(char *host, char *ip)
+{
+	hosts = (dns_host_t *)realloc(hosts, (nhosts+1)*sizeof(*hosts));
+	hosts[nhosts].host = strdup(host);
+	hosts[nhosts].ip = strdup(ip);
+	nhosts++;
+}
+
+static int read_thing(char *buf, char *ip)
+{
+	int skip, len;
+
+	skip = strspn(buf, separators);
+	buf += skip;
+	len = strcspn(buf, separators);
+	memcpy(ip, buf, len);
+	ip[len] = 0;
+	return(skip + len);
+}
+
+static void read_resolv(char *fname)
+{
+	FILE *fp;
+	char buf[512], ip[512];
+
+	fp = fopen(fname, "r");
+	if (!fp) return;
+	while (fgets(buf, sizeof(buf), fp)) {
+		if (!strncasecmp(buf, "nameserver", 10)) {
+			read_thing(buf+10, ip);
+			if (strlen(ip)) add_server(ip);
+		}
+	}
+	fclose(fp);
+}
+
+static void read_hosts(char *fname)
+{
+	FILE *fp;
+	char buf[512], ip[512], host[512];
+	int skip, n;
+
+	fp = fopen(fname, "r");
+	if (!fp) return;
+	while (fgets(buf, sizeof(buf), fp)) {
+		if (strchr(buf, '#')) continue;
+		skip = read_thing(buf, ip);
+		if (!strlen(ip)) continue;
+		while ((n = read_thing(buf+skip, host))) {
+			skip += n;
+			if (strlen(host)) add_host(ip, host);
+		}
+	}
+	fclose(fp);
+}
+
+static int make_header(char *buf, int id)
+{
+	_dns_header.id = htons(id);
+	memcpy(buf, &_dns_header, 12);
+	return(12);
+}
+
+static int cut_host(const char *host, char *query)
+{
+	char *period, *orig;
+	int len;
+
+	orig = query;
+	while ((period = strchr(host, '.'))) {
+		len = period - host;
+		if (len > 63) return(-1);
+		*query++ = len;
+		memcpy(query, host, len);
+		query += len;
+		host = period+1;
+	}
+	len = strlen(host);
+	if (len) {
+		*query++ = len;
+		memcpy(query, host, len);
+		query += len;
+	}
+	*query++ = 0;
+	return(query-orig);
+}
+
+static int reverse_ip(const char *host, char *reverse)
+{
+	char *period;
+	int offset, len;
+
+	period = strchr(host, '.');
+	if (!period) {
+		len = strlen(host);
+		memcpy(reverse, host, len);
+		return(len);
+	}
+	else {
+		len = period - host;
+		offset = reverse_ip(host+len+1, reverse);
+		reverse[offset++] = '.';
+		memcpy(reverse+offset, host, len);
+		reverse[offset+len] = 0;
+		return(offset+len);
+	}
+}
+
+static int dns_make_query(const char *host, int type, char **buf, int *query_len, int (*callback)(), void *client_data)
+{
+	char *newhost = NULL;
+	int len = 0;
+	int ns_type = 0;
+	int i;
+	dns_query_t *q;
+
+	*buf = NULL;
+	*query_len = 0;
+	if (type == DNS_REVERSE) {
+		/* First see if we have it in our host cache. */
+		for (i = 0; i < nhosts; i++) {
+			if (!strcasecmp(hosts[i].ip, host)) {
+				callback(client_data, host, hosts[i].host);
+				return(-1);
+			}
+		}
+
+		/* We need to transform the ip address into the proper form
+		 * for reverse lookup. */
+		newhost = (char *)malloc(strlen(host) + 14);
+		reverse_ip(host, newhost);
+		strcat(newhost, ".in-addr.arpa");
+		host = newhost;
+		ns_type = 12; /* PTR (reverse lookup) */
+	}
+	else {
+		/* First see if it's in our host cache. */
+		for (i = 0; i < nhosts; i++) {
+			if (!strcasecmp(host, hosts[i].host)) {
+				callback(client_data, host, hosts[i].host);
+				return(-1);
+			}
+		}
+		if (type == DNS_IPV4) ns_type = 1; /* IPv4 */
+		else if (type == DNS_IPV6) ns_type = 28; /* IPv6 */
+		else return(-1);
+	}
+
+	*buf = (char *)malloc(strlen(host) + 512);
+	len = make_header(*buf, query_id);
+	len += cut_host(host, *buf + len);
+	(*buf)[len] = 0; len++; (*buf)[len] = ns_type; len++;
+	(*buf)[len] = 0; len++; (*buf)[len] = 1; len++;
+	if (newhost) free(newhost);
+	*query_len = len;
+
+	q = calloc(1, sizeof(*q));
+	q->id = query_id;
+	query_id++;
+	q->query = strdup(host);
+	q->callback = callback;
+	q->client_data = client_data;
+	if (query_head) q->next = query_head->next;
+	query_head = q;
+	return(q->id);
+}
+
+int egg_dns_cancel(int id, int issue_callback)
+{
+	dns_query_t *q, *prev;
+	FILE *fp;
+
+	prev = NULL;
+	for (q = query_head; q; q = q->next) {
+		if (q->id == id) break;
+		prev = q;
+	}
+	if (!q) return(-1);
+	if (prev) prev->next = q->next;
+	else query_head = q->next;
+
+	if (issue_callback) q->callback(q->client_data, q->query, NULL);
+	free(q);
+	return(0);
+}
+
+static int skip_name(unsigned char *ptr)
+{
+	int len;
+	unsigned char *start = ptr;
+
+	while ((len = *ptr++) > 0) {
+		if (len > 63) {
+			ptr++;
+			break;
+		}
+		else {
+			ptr += len;
+		}
+	}
+	return(ptr - start);
+}
+
+static void got_answer(int id, char *answer)
+{
+	dns_query_t *q, *prev;
+
+	prev = NULL;
+	for (q = query_head; q; q = q->next) {
+		if (q->id == id) break;
+		prev = q;
+	}
+	if (!q) return;
+
+	if (prev) prev->next = q->next;
+	else query_head = q->next;
+
+	q->callback(q->client_data, q->query, answer);
+	free(q->query);
+	free(q);
+}
+
+static void parse_reply(char *response, int nbytes)
+{
+	dns_header_t header;
+	dns_rr_t reply;
+	char result[512];
+	unsigned char *ptr;
+	int i;
+
+	ptr = (unsigned char *)response;
+	memcpy(&header, ptr, 12);
+	ptr += 12;
+
+	header.id = ntohs(header.id);
+	header.question_count = ntohs(header.question_count);
+	header.answer_count = ntohs(header.answer_count);
+
+	/* Pass over the question. */
+	ptr += skip_name(ptr);
+	ptr += 4;
+	/* End of question. */
+
+	for (i = 0; i < header.answer_count; i++) {
+		result[0] = 0;
+		/* Read in the answer. */
+		ptr += skip_name(ptr);
+		memcpy(&reply, ptr, 10);
+		reply.type = ntohs(reply.type);
+		reply.rdlength = ntohs(reply.rdlength);
+		ptr += 10;
+		if (reply.type == 1) {
+			//fprintf(fp, "ipv4 reply\n");
+			inet_ntop(AF_INET, ptr, result, 512);
+			got_answer(header.id, result);
+			return;
+		}
+		else if (reply.type == 28) {
+			//fprintf(fp, "ipv6 reply\n");
+			inet_ntop(AF_INET6, ptr, result, 512);
+			got_answer(header.id, result);
+			return;
+		}
+		else if (reply.type == 12) {
+			char *placeholder;
+			int len, dot;
+
+			//fprintf(fp, "reverse-lookup reply\n");
+			placeholder = ptr;
+			result[0] = 0;
+			while ((len = *ptr++) != 0) {
+				if (len > 63) {
+					ptr++;
+					break;
+				}
+				else {
+					dot = ptr[len];
+					ptr[len] = 0;
+					strcat(result, ptr);
+					strcat(result, ".");
+					ptr[len] = dot;
+					ptr += len;
+				}
+			}
+			if (strlen(result)) {
+				result[strlen(result)-1] = 0;
+				got_answer(header.id, result);
+				return;
+			}
+			ptr = placeholder;
+		}
+		ptr += reply.rdlength;
+	}
+	got_answer(header.id, NULL);
+}
Index: eggdrop1.7/lib/eggdrop/eggdns.h
diff -u /dev/null eggdrop1.7/lib/eggdrop/eggdns.h:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/lib/eggdrop/eggdns.h	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,16 @@
+#ifndef _EGGDNS_H_
+#define _EGGDNS_H_
+
+#define DNS_IPV4	1
+#define DNS_IPV6	2
+#define DNS_REVERSE	3
+
+#define DNS_PORT	53
+
+int egg_dns_init();
+void egg_dns_send(char *query, int len);
+int egg_dns_lookup(const char *host, int timeout, int (*callback)(), void *client_data);
+int egg_dns_reverse(const char *ip, int timeout, int (*callback)(), void *client_data);
+int egg_dns_cancel(int id, int issue_callback);
+
+#endif /* _EGGDNS_H_ */
Index: eggdrop1.7/lib/eggdrop/eggdrop.h
diff -u eggdrop1.7/lib/eggdrop/eggdrop.h:1.9 eggdrop1.7/lib/eggdrop/eggdrop.h:1.10
--- eggdrop1.7/lib/eggdrop/eggdrop.h:1.9	Sun May 12 00:59:50 2002
+++ eggdrop1.7/lib/eggdrop/eggdrop.h	Thu Sep 19 21:06:25 2002
@@ -21,7 +21,7 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 /*
- * $Id: eggdrop.h,v 1.9 2002/05/12 05:59:50 stdarg Exp $
+ * $Id: eggdrop.h,v 1.10 2002/09/20 02:06:25 stdarg Exp $
  */
 
 #ifndef _EGGDROP_H
@@ -33,6 +33,13 @@
 #include <eggdrop/memutil.h>
 #include <eggdrop/fileutil.h>
 #include <eggdrop/script.h>
+#include <eggdrop/my_socket.h>
+#include <eggdrop/sockbuf.h>
+#include <eggdrop/eggnet.h>
+#include <eggdrop/eggdns.h>
+#include <eggdrop/eggident.h>
+#include <eggdrop/linemode.h>
+#include <eggdrop/eggtimer.h>
 
 BEGIN_C_DECLS
 
Index: eggdrop1.7/lib/eggdrop/eggident.c
diff -u /dev/null eggdrop1.7/lib/eggdrop/eggident.c:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/lib/eggdrop/eggident.c	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,132 @@
+#if HAVE_CONFIG_H
+	#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sockbuf.h"
+#include "eggnet.h"
+
+typedef struct _ident_info {
+	struct _ident_info *next;
+	int id;
+	char *ip;
+	int their_port, our_port;
+	int idx;
+	int timeout;
+	int (*callback)();
+	void *client_data;
+} ident_info_t;
+
+static int ident_on_connect(void *client_data, int idx, const char *peer_ip, int peer_port);
+static int ident_on_read(void *client_data, int idx, char *data, int len);
+static int ident_on_eof(void *client_data, int idx, int err, const char *errmsg);
+static int ident_result(void *client_data, const char *ident);
+
+static sockbuf_handler_t ident_handler = {
+	"ident",
+	ident_on_connect, ident_on_eof, NULL,
+	ident_on_read, NULL
+};
+
+static ident_info_t *ident_head = NULL;
+
+
+/* Perform an async ident lookup and call 'callback' with the result. */
+int egg_ident_lookup(const char *ip, int their_port, int our_port, int timeout, int (*callback)(), void *client_data)
+{
+	static int ident_id = 0;
+	int idx;
+	ident_info_t *ident_info;
+	
+	idx = egg_connect(ip, 113, -1);
+	if (idx < 0) {
+		callback(client_data, ip, their_port, NULL);
+		return(-1);
+	}
+	ident_info = calloc(1, sizeof(*ident_info));
+	ident_info->ip = strdup(ip);
+	ident_info->their_port = their_port;
+	ident_info->our_port = our_port;
+	ident_info->timeout = timeout;
+	ident_info->callback = callback;
+	ident_info->client_data = client_data;
+	ident_info->idx = idx;
+	ident_info->id = ident_id++;
+	ident_info->next = ident_head;
+	ident_head = ident_info;
+	sockbuf_set_handler(idx, &ident_handler, ident_info);
+	return(ident_info->id);
+}
+
+/* Cancel an ident lookup, optionally triggering the callback. */
+int egg_ident_cancel(int id, int issue_callback)
+{
+	ident_info_t *ptr, *prev;
+
+	prev = NULL;
+	for (ptr = ident_head; ptr; ptr = ptr->next) {
+		if (ptr->id == id) break;
+		prev = ptr;
+	}
+	if (!ptr) return(-1);
+	if (prev) prev->next = ptr->next;
+	else ident_head = ptr->next;
+	if (issue_callback) {
+		ptr->callback(ptr->client_data, ptr->ip, ptr->their_port, NULL);
+	}
+	free(ptr->ip);
+	free(ptr);
+	return(0);
+}
+
+static int ident_on_connect(void *client_data, int idx, const char *peer_ip, int peer_port)
+{
+	ident_info_t *ident_info = client_data;
+
+	egg_iprintf(idx, "%d,%d\r\n", ident_info->their_port, ident_info->our_port);
+	return(0);
+}
+
+static int ident_on_read(void *client_data, int idx, char *data, int len)
+{
+	char *colon, *ident;
+	int i;
+
+	colon = strchr(data, ':');
+	if (!colon || strncasecmp(colon+1, "USERID", 6) || *(colon+7) != ':') {
+		ident_result(client_data, NULL);
+		return(0);
+	}
+	colon = strchr(colon+8, ':');
+	if (!colon) {
+		ident_result(client_data, NULL);
+		return(0);
+	}
+	ident = colon+1;
+	/* Replace bad chars. */
+	len = strlen(ident);
+	for (i = 0; i < len; i++) {
+		if (ident[i] < 'A' || ident[i] > 'z') ident[i] = 'x';
+	}
+	if (len > 20) ident[20] = 0;
+	ident_result(client_data, ident);
+	return(0);
+}
+
+static int ident_on_eof(void *client_data, int idx, int err, const char *errmsg)
+{
+	ident_result(client_data, NULL);
+	return(0);
+}
+
+static int ident_result(void *client_data, const char *ident)
+{
+	ident_info_t *ident_info = client_data;
+	sockbuf_delete(ident_info->idx);
+	ident_info->callback(ident_info->client_data, ident_info->ip, ident_info->their_port, ident);
+	free(ident_info->ip);
+	free(ident_info);
+	return(0);
+}
Index: eggdrop1.7/lib/eggdrop/eggident.h
diff -u /dev/null eggdrop1.7/lib/eggdrop/eggident.h:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/lib/eggdrop/eggident.h	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,7 @@
+#ifndef _EGGIDENT_H_
+#define _EGGIDENT_H_
+
+int egg_ident_lookup(const char *ip, int their_port, int our_port, int timeout, int (*callback)(), void *client_data);
+int egg_ident_cancel(int id);
+
+#endif /* _EGGIDENT_H_ */
Index: eggdrop1.7/lib/eggdrop/eggnet.c
diff -u /dev/null eggdrop1.7/lib/eggdrop/eggnet.c:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/lib/eggdrop/eggnet.c	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,195 @@
+#if HAVE_CONFIG_H
+	#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include "memutil.h"
+#include "my_socket.h"
+#include "sockbuf.h"
+#include "eggnet.h"
+#include "eggdns.h"
+#include "eggtimer.h"
+
+#define EGGNET_LEVEL	(SOCKBUF_LEVEL_INTERNAL+1)
+
+typedef struct connect_info {
+	int dns_id;
+	int timer_id;
+	int idx;
+	int port;
+} connect_info_t;
+
+static int connect_host_resolved(void *client_data, const char *host, const char *ip);
+static int egg_connect_timeout(void *client_data);
+static int egg_on_connect(void *client_data, int idx, const char *peer_ip, int peer_port);
+static int egg_on_eof(void *client_data, int idx, int err, const char *errmsg);
+static int egg_on_delete(void *client_data, int idx);
+static int detach(void *client_data, int idx);
+
+static sockbuf_filter_t eggnet_connect_filter = {
+	"connect", EGGNET_LEVEL,
+	egg_on_connect, egg_on_eof, NULL,
+	NULL, NULL, NULL,
+	NULL, egg_on_delete
+};
+
+/* Print to an idx, using printf notation. */
+int egg_iprintf(int idx, const char *format, ...)
+{
+	char *ptr, buf[1024];
+	int len;
+	va_list args;
+
+	va_start(args, format);
+	ptr = egg_mvsprintf(buf, sizeof(buf), &len, format, args);
+	va_end(args);
+	sockbuf_write(idx, ptr, len);
+	if (ptr != buf) free(ptr);
+	return(len);
+}
+
+/* Create a listening socket on a port. */
+int egg_server(const char *vip, int port)
+{
+	int idx, sock, ntries;
+
+	ntries = 0;
+	do {
+		sock = socket_create(NULL, 0, vip, port+ntries, SOCKET_SERVER|SOCKET_TCP|SOCKET_NONBLOCK);
+		ntries++;
+	} while (sock < 0 && ntries < 20);
+
+	idx = sockbuf_new();
+	sockbuf_set_sock(idx, sock, SOCKBUF_SERVER);
+
+	return(idx);
+}
+
+/* Create a client socket and attach it to an idx. This does not handle
+ * proxies or firewalls, just direct connections. 'ip' and 'port' are the
+ * destination, and 'vip' 'vport' are the source address (vhost). */
+int egg_client(const char *ip, int port, const char *vip, int vport)
+{
+	int idx, sock;
+
+	sock = socket_create(ip, port, vip, vport, SOCKET_CLIENT|SOCKET_TCP|SOCKET_NONBLOCK);
+	if (sock < 0) return(-1);
+	idx = sockbuf_new();
+	sockbuf_set_sock(idx, sock, SOCKBUF_CLIENT);
+	return(idx);
+}
+
+/* Open a listen port. If proxies/firewalls/vhosts are configured, it will
+ * automatically use them. Returns an idx for the new socket. */
+int egg_listen(int port)
+{
+	int idx;
+
+	/* Proxy/firewall/vhost code goes here. */
+	idx = egg_server(NULL, port);
+	return(idx);
+}
+
+/* Connect to a given host/port. If proxies/firewalls/vhosts are configured, it
+ * will automatically use them. Returns an idx for your connection. */
+int egg_connect(const char *host, int port, int timeout)
+{
+	connect_info_t *connect_info;
+	egg_timeval_t howlong;
+
+	/* Resolve the hostname. */
+	connect_info = calloc(1, sizeof(*connect_info));
+	connect_info->port = port;
+	connect_info->idx = sockbuf_new();
+	sockbuf_attach_filter(connect_info->idx, &eggnet_connect_filter, connect_info);
+	connect_info->timer_id = -1;
+	connect_info->dns_id = egg_dns_lookup(host, DNS_IPV4, connect_host_resolved, connect_info);
+	if (timeout > 0) {
+		howlong.sec = timeout;
+		howlong.usec = 0;
+		connect_info->timer_id = timer_create_complex(&howlong, egg_connect_timeout, connect_info, 0);
+	}
+	return(connect_info->idx);
+}
+
+static int connect_host_resolved(void *client_data, const char *host, const char *ip)
+{
+	connect_info_t *connect_info = client_data;
+	int sock, idx;
+
+	connect_info->dns_id = -1;
+
+	if (!ip) {
+		idx = connect_info->idx;
+		detach(client_data, idx);
+		sockbuf_on_eof(idx, EGGNET_LEVEL, -1, "Could not resolve host");
+		return(0);
+	}
+
+	/* Proxy/firewall/vhost code goes here. */
+
+	sock = socket_create(ip, connect_info->port, NULL, 0, SOCKET_CLIENT|SOCKET_TCP|SOCKET_NONBLOCK);
+	if (sock < 0) {
+		idx = connect_info->idx;
+		detach(client_data, idx);
+		sockbuf_on_eof(idx, EGGNET_LEVEL, -1, "Could not create socket");
+		return(0);
+	}
+	sockbuf_set_sock(connect_info->idx, sock, SOCKBUF_CLIENT);
+	return(0);
+}
+
+static int egg_connect_timeout(void *client_data)
+{
+	connect_info_t *connect_info = client_data;
+	int idx, dns_id;
+
+	idx = connect_info->idx;
+	dns_id = connect_info->dns_id;
+	connect_info->timer_id = -1;
+	if (dns_id != -1) {
+		/* dns_cancel will call connect_host_resolved for us. */
+		egg_dns_cancel(dns_id, 1);
+	}
+	else {
+		detach(client_data, idx);
+		sockbuf_on_eof(idx, EGGNET_LEVEL, -1, "Connect timed out");
+	}
+	return(0);
+}
+
+static int egg_on_connect(void *client_data, int idx, const char *peer_ip, int peer_port)
+{
+	detach(client_data, idx);
+	sockbuf_on_connect(idx, EGGNET_LEVEL, peer_ip, peer_port);
+	return(0);
+}
+
+static int egg_on_eof(void *client_data, int idx, int err, const char *errmsg)
+{
+	detach(client_data, idx);
+	return sockbuf_on_eof(idx, EGGNET_LEVEL, err, errmsg);
+}
+
+static int egg_on_delete(void *client_data, int idx)
+{
+	connect_info_t *connect_info = client_data;
+
+	if (connect_info->dns_id != -1) egg_dns_cancel(connect_info->dns_id, 0);
+	if (connect_info->timer_id != -1) timer_destroy(connect_info->timer_id);
+	free(connect_info);
+	return(0);
+}
+
+static int detach(void *client_data, int idx)
+{
+	connect_info_t *connect_info = client_data;
+
+	if (connect_info->timer_id != -1) timer_destroy(connect_info->timer_id);
+	sockbuf_detach_filter(idx, &eggnet_connect_filter, NULL);
+	free(connect_info);
+	return(0);
+}
Index: eggdrop1.7/lib/eggdrop/eggnet.h
diff -u /dev/null eggdrop1.7/lib/eggdrop/eggnet.h:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/lib/eggdrop/eggnet.h	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,12 @@
+#ifndef _EGGNET_H_
+#define _EGGNET_H_
+
+int egg_iprintf(int idx, const char *format, ...);
+int egg_server(const char *vip, int port);
+int egg_client(const char *ip, int port, const char *vip, int vport);
+int egg_listen(int port);
+int egg_connect(const char *host, int port, int timeout);
+int egg_ident_lookup(const char *ip, int their_port, int our_port, int timeout, int (*callback)(), void *client_data);
+int egg_dns_lookup(const char *host_or_ip, int timeout, int (*callback)(), void *client_data);
+
+#endif /* _EGGNET_H_ */
Index: eggdrop1.7/lib/eggdrop/eggtimer.c
diff -u /dev/null eggdrop1.7/lib/eggdrop/eggtimer.c:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/lib/eggdrop/eggtimer.c	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,251 @@
+/*
+ * egg_timer.c --
+ *
+ */
+/*
+ * Copyright (C) 2002 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: eggtimer.c,v 1.1 2002/09/20 02:06:25 stdarg Exp $";
+#endif
+
+#include <stdio.h> /* NULL */
+#include <string.h> /* memcpy() */
+#include <stdlib.h> /* malloc(), free() */
+#include <sys/time.h> /* gettimeofday() */
+
+#include <eggdrop/eggdrop.h>
+#include "eggtimer.h"
+
+static egg_timeval_t now;
+
+/* Internal use only. */
+typedef struct egg_timer_b {
+	struct egg_timer_b *next;
+	int id;
+	Function callback;
+	void *client_data;
+	egg_timeval_t howlong;
+	egg_timeval_t trigger_time;
+	int flags;
+} egg_timer_t;
+
+/* We keep a sorted list of active timers. */
+static egg_timer_t *timer_list_head = NULL;
+static int timer_next_id = 1;
+
+/* Based on TclpGetTime from Tcl 8.3.3 */
+int timer_get_time(egg_timeval_t *curtime)
+{
+	struct timeval tv;
+
+	(void) gettimeofday(&tv, NULL);
+	curtime->sec = tv.tv_sec;
+	curtime->usec = tv.tv_usec;
+	return(0);
+}
+
+int timer_update_now(egg_timeval_t *_now)
+{
+	timer_get_time(&now);
+	if (_now) {
+		_now->sec = now.sec;
+		_now->usec = now.usec;
+	}
+	return(now.sec);
+}
+
+/* Find difference between two timers. */
+int timer_diff(egg_timeval_t *from_time, egg_timeval_t *to_time, egg_timeval_t *diff)
+{
+	diff->sec = to_time->sec - from_time->sec;
+	if (diff->sec < 0) {
+		diff->sec = 0;
+		diff->usec = 0;
+		return(1);
+	}
+
+	diff->usec = to_time->usec - from_time->usec;
+
+	if (diff->usec < 0) {
+		if (diff->sec == 0) {
+			diff->usec = 0;
+			return(1);
+		}
+		diff->sec -= 1;
+		diff->usec += 1000000;
+	}
+
+	return(0);
+}
+
+static int timer_add_to_list(egg_timer_t *timer)
+{
+	egg_timer_t *prev, *ptr;
+
+	/* Find out where this should go in the list. */
+	prev = NULL;
+	for (ptr = timer_list_head; ptr; ptr = ptr->next) {
+		if (timer->trigger_time.sec < ptr->trigger_time.sec) break;
+		if (timer->trigger_time.sec == ptr->trigger_time.sec && timer->trigger_time.usec < ptr->trigger_time.usec) break;
+		prev = ptr;
+	}
+
+	/* Insert into timer list. */
+	if (prev) {
+		timer->next = prev->next;
+		prev->next = timer;
+	}
+	else {
+		timer->next = timer_list_head;
+		timer_list_head = timer;
+	}
+	return(0);
+}
+
+int timer_create_complex(egg_timeval_t *howlong, Function callback, void *client_data, int flags)
+{
+	egg_timer_t *timer;
+
+	/* Fill out a new timer. */
+	timer = (egg_timer_t *)malloc(sizeof(*timer));
+	timer->id = timer_next_id++;
+	timer->callback = callback;
+	timer->client_data = client_data;
+	timer->flags = flags;
+	timer->howlong.sec = howlong->sec;
+	timer->howlong.usec = howlong->usec;
+	timer->trigger_time.sec = now.sec + howlong->sec;
+	timer->trigger_time.usec = now.usec + howlong->usec;
+
+	timer_add_to_list(timer);
+
+	return(timer->id);
+}
+
+/* Destroy a timer, given an id. */
+int timer_destroy(int timer_id)
+{
+	egg_timer_t *prev, *timer;
+
+	prev = NULL;
+	for (timer = timer_list_head; timer; timer = timer->next) {
+		if (timer->id == timer_id) break;
+		prev = timer;
+	}
+
+	if (!timer) return(1); /* Not found! */
+
+	/* Unlink it. */
+	if (prev) prev->next = timer->next;
+	else timer_list_head = timer->next;
+
+	free(timer);
+	return(0);
+}
+
+int timer_destroy_all()
+{
+	egg_timer_t *timer, *next;
+
+	for (timer = timer_list_head; timer; timer = next) {
+		next = timer->next;
+		free(timer);
+	}
+	timer_list_head = NULL;
+	return(0);
+}
+
+int timer_get_shortest(egg_timeval_t *howlong)
+{
+	egg_timer_t *timer = timer_list_head;
+
+	/* No timers? Boo. */
+	if (!timer) return(1);
+
+	timer_diff(&now, &timer->trigger_time, howlong);
+
+	return(0);
+}
+
+int timer_run()
+{
+	egg_timer_t *timer;
+	Function callback;
+	void *client_data;
+
+	while (timer_list_head) {
+		timer = timer_list_head;
+		if (timer->trigger_time.sec > now.sec || (timer->trigger_time.sec == now.sec && timer->trigger_time.usec > now.usec)) break;
+
+		timer_list_head = timer_list_head->next;
+
+		callback = timer->callback;
+		client_data = timer->client_data;
+
+		if (timer->flags & TIMER_REPEAT) {
+			/* Update timer. */
+			timer->trigger_time.sec += timer->howlong.sec;
+			timer->trigger_time.usec += timer->howlong.usec;
+			if (timer->trigger_time.usec >= 1000000) {
+				timer->trigger_time.usec -= 1000000;
+				timer->trigger_time.sec += 1;
+			}
+
+			/* Add it back into the list. */
+			timer_add_to_list(timer);
+		}
+		else {
+			free(timer);
+		}
+
+		callback(client_data);
+	}
+	return(0);
+}
+
+int timer_list(int **ids)
+{
+	egg_timer_t *timer;
+	int ntimers;
+
+	/* Count timers. */
+	ntimers = 0;
+	for (timer = timer_list_head; timer; timer = timer->next) ntimers++;
+
+	/* Fill in array. */
+	*ids = malloc(sizeof(int) * (ntimers+1));
+	ntimers = 0;
+	for (timer = timer_list_head; timer; timer = timer->next) {
+		(*ids)[ntimers++] = timer->id;
+	}
+	return(ntimers);
+}
+
+int timer_info(int id, egg_timeval_t *initial_len, egg_timeval_t *trigger_time)
+{
+	egg_timer_t *timer;
+
+	for (timer = timer_list_head; timer; timer = timer->next) {
+		if (timer->id == id) break;
+	}
+	if (!timer) return(-1);
+	if (initial_len) memcpy(initial_len, &timer->howlong, sizeof(*initial_len));
+	if (trigger_time) memcpy(trigger_time, &timer->trigger_time, sizeof(*trigger_time));
+	return(0);
+}
Index: eggdrop1.7/lib/eggdrop/eggtimer.h
diff -u /dev/null eggdrop1.7/lib/eggdrop/eggtimer.h:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/lib/eggdrop/eggtimer.h	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,53 @@
+/*
+ * egg_timer.h --
+ */
+/*
+ * Copyright (C) 2002 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.
+ */
+/*
+ * $Id: eggtimer.h,v 1.1 2002/09/20 02:06:25 stdarg Exp $
+ */
+
+#ifndef _EGG_TIMER_H
+#define _EGG_TIMER_H
+
+typedef struct egg_timeval_b {
+	int sec;
+	int usec;
+} egg_timeval_t;
+
+#define TIMER_REPEAT 1
+
+/* Create a simple timer with no client data and no flags. */
+#define timer_create(howlong,callback) timer_create_complex(howlong, callback, NULL, 0)
+
+/* Create a simple timer with no client data, but it repeats. */
+#define timer_create_repeater(howlong,callback) timer_create_complex(howlong, callback, NULL, TIMER_REPEAT)
+
+extern void timer_init();
+extern int timer_get_time(egg_timeval_t *curtime);
+extern int timer_update_now(egg_timeval_t *_now);
+extern int timer_diff(egg_timeval_t *from_time, egg_timeval_t *to_time, egg_timeval_t *diff);
+extern int timer_create_complex(egg_timeval_t *howlong, Function callback, void *client_data, int flags);
+extern int timer_destroy(int timer_id);
+extern int timer_destroy_all();
+extern int timer_get_shortest(egg_timeval_t *howlong);
+extern int timer_run();
+extern int timer_list(int **ids);
+extern int timer_info(int id, egg_timeval_t *initial_len, egg_timeval_t *trigger_time);
+
+#endif				/* !_EGG_TIMER_H */
Index: eggdrop1.7/lib/eggdrop/linemode.c
diff -u /dev/null eggdrop1.7/lib/eggdrop/linemode.c:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/lib/eggdrop/linemode.c	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,123 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sockbuf.h"
+
+#define LINEMODE_LEVEL	SOCKBUF_LEVEL_TEXT_BUFFER
+
+typedef struct {
+	char *data;
+	int len;
+} linemode_t;
+
+static int linemode_on_read(void *client_data, int idx, char *data, int len)
+{
+	linemode_t *old_data = client_data;
+	char *line, *stop, *save;
+	int linelen, savelen;
+
+	while (1) {
+		/* If there's a cr or lf, we have a line. */
+		stop = memchr(data, '\n', len);
+		if (!stop) {
+			stop = memchr(data, '\r', len);
+			if (!stop) {
+				/* No line, save the whole thing. */
+				save = data;
+				savelen = len;
+				break;
+			}
+		}
+
+		/* Save the cursor position for the next iteration. */
+		save = stop+1;
+		savelen = len - (save - data);
+
+		if (stop > data && *(stop-1) == '\r') stop--;
+		linelen = stop - data;
+		*stop = 0;
+
+		/* If there is buffered data, concat it all. */
+		if (old_data->len) {
+			/* Expand the buffer. */
+			old_data->data = (char *)realloc(old_data->data, old_data->len + linelen + 1);
+			memcpy(old_data->data+old_data->len, data, linelen + 1);
+
+			line = old_data->data;
+			linelen += old_data->len;
+
+			/* All the old data is used. */
+			old_data->len = 0;
+		}
+		else {
+			line = data;
+		}
+
+		sockbuf_on_read(idx, LINEMODE_LEVEL, line, linelen);
+
+		/* If we're out of data, we're done. */
+		if (savelen <= 0) return(0);
+		/* Otherwise, do this again to check for another line. */
+		data = save;
+		len = savelen;
+	}
+
+	/* No cr/lf, so we save the remaining data for next time. */
+	old_data->data = (char *)realloc(old_data->data, savelen + old_data->len + 1);
+	memcpy(old_data->data + old_data->len, save, savelen);
+	old_data->len += savelen;
+	return(0);
+}
+
+static int linemode_on_eof(void *client_data, int idx, int err, const char *errmsg)
+{
+	linemode_t *old_data = client_data;
+	/* If there is any buffered data, do one more on->read callback. */
+	if (old_data->len) {
+		old_data->data[old_data->len] = 0;
+		sockbuf_on_read(idx, LINEMODE_LEVEL, old_data->data, old_data->len);
+	}
+
+	/* And now continue the eof event chain. */
+	return sockbuf_on_eof(idx, LINEMODE_LEVEL, err, errmsg);
+}
+
+static int linemode_on_delete(void *client_data, int idx)
+{
+	linemode_t *old_data = client_data;
+	/* When the sockbuf is deleted, just kill the associated data. */
+	if (old_data->data) free(old_data->data);
+	free(old_data);
+	return(0);
+}
+
+static sockbuf_filter_t linemode_filter = {
+	"linemode",
+	LINEMODE_LEVEL,
+	NULL, linemode_on_eof, NULL,
+	linemode_on_read, NULL, NULL,
+	NULL, linemode_on_delete
+};
+
+int linemode_on(int idx)
+{
+	linemode_t *old_data;
+
+	old_data = (linemode_t *)calloc(1, sizeof(*old_data));
+	sockbuf_attach_filter(idx, &linemode_filter, old_data);
+	return(0);
+}
+
+int linemode_off(int idx)
+{
+	linemode_t *old_data;
+
+	sockbuf_detach_filter(idx, &linemode_filter, &old_data);
+	if (old_data) {
+		if (old_data->data) free(old_data->data);
+		free(old_data);
+	}
+	return(0);
+}
Index: eggdrop1.7/lib/eggdrop/linemode.h
diff -u /dev/null eggdrop1.7/lib/eggdrop/linemode.h:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/lib/eggdrop/linemode.h	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,7 @@
+#ifndef _LINEMODE_H_
+#define _LINEMODE_H_
+
+int linemode_on(int idx);
+int linemode_off(int idx);
+
+#endif /* _LINEMODE_H_ */
Index: eggdrop1.7/lib/eggdrop/memutil.c
diff -u eggdrop1.7/lib/eggdrop/memutil.c:1.8 eggdrop1.7/lib/eggdrop/memutil.c:1.9
--- eggdrop1.7/lib/eggdrop/memutil.c:1.8	Thu May 30 22:07:22 2002
+++ eggdrop1.7/lib/eggdrop/memutil.c	Thu Sep 19 21:06:25 2002
@@ -23,12 +23,13 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: memutil.c,v 1.8 2002/05/31 03:07:22 stdarg Exp $";
+static const char rcsid[] = "$Id: memutil.c,v 1.9 2002/09/20 02:06:25 stdarg Exp $";
 #endif
 
 #include <stdio.h>
 #include <ctype.h>
 #include <string.h>
+#include <stdarg.h>
 #include "memutil.h"
 
 /*        This implementation wont overrun dst - 'max' is the max bytes that dst
@@ -266,7 +267,53 @@
 {
 	int len;
 
+	if (!newstr) {
+		if (*str) free(*str);
+		*str = NULL;
+		return;
+	}
 	len = strlen(newstr)+1;
 	*str = (char *)realloc(*str, len);
 	memcpy(*str, newstr, len);
+}
+
+char *egg_msprintf(char *buf, int len, int *final_len, const char *format, ...)
+{
+	va_list args;
+	char *ptr;
+
+	va_start(args, format);
+	ptr = egg_mvsprintf(buf, len, final_len, format, args);
+	va_end(args);
+	return(ptr);
+}
+
+char *egg_mvsprintf(char *buf, int len, int *final_len, const char *format, va_list args)
+{
+	char *output;
+	int n;
+
+	if (buf && len > 10) {
+		output = buf;
+	}
+	else {
+		output = (char *)malloc(512);
+		len = 512;
+	}
+	while (1) {
+		len -= 10;
+		n = vsnprintf(output, len, format, args);
+		if (n > -1 && n < len) break;
+		if (n > len) len = n+1;
+		else len *= 2;
+		len += 10;
+		if (output == buf) output = (char *)malloc(len);
+		else output = (char *)realloc(output, len);
+		if (!output) return(NULL);
+	}
+	if (final_len) {
+		if (!(n % 1024)) n = strlen(output);
+		*final_len = n;
+	}
+	return(output);
 }
Index: eggdrop1.7/lib/eggdrop/memutil.h
diff -u eggdrop1.7/lib/eggdrop/memutil.h:1.9 eggdrop1.7/lib/eggdrop/memutil.h:1.10
--- eggdrop1.7/lib/eggdrop/memutil.h:1.9	Thu May 30 22:07:22 2002
+++ eggdrop1.7/lib/eggdrop/memutil.h	Thu Sep 19 21:06:25 2002
@@ -22,7 +22,7 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 /*
- * $Id: memutil.h,v 1.9 2002/05/31 03:07:22 stdarg Exp $
+ * $Id: memutil.h,v 1.10 2002/09/20 02:06:25 stdarg Exp $
  */
 
 #ifndef _EGG_MEMUTIL_H
@@ -67,6 +67,9 @@
 extern void rmspace(char *);
 
 extern void str_redup(char **str, char *newstr);
+
+extern char *egg_msprintf(char *buf, int len, int *final_len, const char *format, ...);
+extern char *egg_mvsprintf(char *buf, int len, int *final_len, const char *format, va_list args);
 
 END_C_DECLS
 
Index: eggdrop1.7/lib/eggdrop/module.h
diff -u eggdrop1.7/lib/eggdrop/module.h:1.27 eggdrop1.7/lib/eggdrop/module.h:1.28
--- eggdrop1.7/lib/eggdrop/module.h:1.27	Tue Jun 18 01:12:31 2002
+++ eggdrop1.7/lib/eggdrop/module.h	Thu Sep 19 21:06:25 2002
@@ -20,7 +20,7 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 /*
- * $Id: module.h,v 1.27 2002/06/18 06:12:31 guppy Exp $
+ * $Id: module.h,v 1.28 2002/09/20 02:06:25 stdarg Exp $
  */
 
 #ifndef _EGG_MOD_MODULE_H
@@ -34,6 +34,7 @@
 /* FIXME: filter out files which are not needed (it was easier after removing
    proto.h and cleaning up main.h to just include all .h files here w/o
    validating if they aren't needed */
+#include "src/users.h"
 #include "src/bg.h"
 #include "src/botcmd.h"
 #include "src/botmsg.h"
@@ -48,7 +49,6 @@
 #include "src/debug.h"
 #include "src/dns.h"
 #include "src/egg.h"
-#include "src/egg_timer.h"
 #include "src/flags.h"
 #include "src/irccmp.h"
 #include "src/logfile.h"
@@ -64,7 +64,6 @@
 #include "src/traffic.h"
 #include "src/userent.h"
 #include "src/userrec.h"
-#include "src/users.h"
 #include "src/tandem.h"
 #include "src/logfile.h"
 #include "src/dns.h"
Index: eggdrop1.7/lib/eggdrop/script.c
diff -u eggdrop1.7/lib/eggdrop/script.c:1.7 eggdrop1.7/lib/eggdrop/script.c:1.8
--- eggdrop1.7/lib/eggdrop/script.c:1.7	Fri May 24 01:52:05 2002
+++ eggdrop1.7/lib/eggdrop/script.c	Thu Sep 19 21:06:25 2002
@@ -22,7 +22,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: script.c,v 1.7 2002/05/24 06:52:05 stdarg Exp $";
+static const char rcsid[] = "$Id: script.c,v 1.8 2002/09/20 02:06:25 stdarg Exp $";
 #endif
 
 #if HAVE_CONFIG_H
@@ -129,6 +129,35 @@
 		return(data);
 	}
 	return(NULL);
+}
+
+/* We shall provide a handy default linked var write handler. */
+
+int script_linked_var_on_write(script_linked_var_t *var, script_var_t *newval)
+{
+	int r;
+	char **charptr;
+
+	/* See if the owner provides a write callback. */
+	if (var->callbacks && var->callbacks->on_write) {
+		r = (var->callbacks->on_write)(var, newval);
+		return(r);
+	}
+
+	/* Provide default handling for strings and ints. */
+	switch (var->type & SCRIPT_TYPE_MASK) {
+		case SCRIPT_UNSIGNED:
+		case SCRIPT_INTEGER:
+			*(int *)(var->value) = (int) newval->value;
+			break;
+		case SCRIPT_STRING:
+			charptr = (char **)var->value;
+			if (*charptr) free(*charptr);
+			if (newval->type & SCRIPT_FREE) *charptr = newval->value;
+			else *charptr = strdup(newval->value);
+			break;
+	}
+	return(0);
 }
 
 /* We shall provide a handy callback interface, to reduce the amount of
Index: eggdrop1.7/lib/eggdrop/script.h
diff -u eggdrop1.7/lib/eggdrop/script.h:1.6 eggdrop1.7/lib/eggdrop/script.h:1.7
--- eggdrop1.7/lib/eggdrop/script.h:1.6	Thu May 30 23:11:36 2002
+++ eggdrop1.7/lib/eggdrop/script.h	Thu Sep 19 21:06:25 2002
@@ -21,7 +21,7 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 /*
- * $Id: script.h,v 1.6 2002/05/31 04:11:36 stdarg Exp $
+ * $Id: script.h,v 1.7 2002/09/20 02:06:25 stdarg Exp $
  */
 
 #ifndef _EGG_SCRIPT_H
@@ -80,9 +80,6 @@
 */
 #define SCRIPT_CALLBACK_ONCE	1
 
-/* Flags for linked variables. */
-#define SCRIPT_READ_ONLY	1
-
 /* Flags for variables. */
 /* SCRIPT_FREE means we will call free(retval->value) (i.e. free a malloc'd
    string or array base ptr.)
@@ -98,9 +95,11 @@
 #define SCRIPT_FREE_VAR	512
 #define SCRIPT_ARRAY	1024
 #define SCRIPT_ERROR	2048
+#define SCRIPT_READONLY	4096
 
 /* Types for variables. */
 #define SCRIPT_STRING	((int)'s')
+#define SCRIPT_STRING_LIST ((int)'S')
 #define SCRIPT_INTEGER	((int)'i')
 #define SCRIPT_UNSIGNED	((int)'u')
 #define SCRIPT_POINTER	((int)'p')
@@ -202,6 +201,7 @@
 extern int script_register_module(script_module_t *module);
 extern int script_unregister_module(script_module_t *module);
 extern int script_playback(script_module_t *module);
+extern int script_linked_var_on_write(script_linked_var_t *var, script_var_t *newval);
 
 END_C_DECLS
 
Index: eggdrop1.7/modules/Makefile.am
diff -u eggdrop1.7/modules/Makefile.am:1.4 eggdrop1.7/modules/Makefile.am:1.5
--- eggdrop1.7/modules/Makefile.am:1.4	Tue Jun 18 01:12:31 2002
+++ eggdrop1.7/modules/Makefile.am	Thu Sep 19 21:06:25 2002
@@ -1,6 +1,6 @@
-# $Id: Makefile.am,v 1.4 2002/06/18 06:12:31 guppy Exp $
+# $Id: Makefile.am,v 1.5 2002/09/20 02:06:25 stdarg Exp $
 
 # FIXME: list will prolly become dynamic
-SUBDIRS			= blowfish channels compress console ctcp filesys irc notes perlscript server share tclscript transfer uptime javascript
+SUBDIRS			= blowfish compress console notes perlscript server tclscript javascript
 
 MAINTAINERCLEANFILES	= Makefile.in
Index: eggdrop1.7/modules/javascript/javascript.c
diff -u eggdrop1.7/modules/javascript/javascript.c:1.10 eggdrop1.7/modules/javascript/javascript.c:1.11
--- eggdrop1.7/modules/javascript/javascript.c:1.10	Thu May 30 23:11:37 2002
+++ eggdrop1.7/modules/javascript/javascript.c	Thu Sep 19 21:06:25 2002
@@ -20,7 +20,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: javascript.c,v 1.10 2002/05/31 04:11:37 stdarg Exp $";
+static const char rcsid[] = "$Id: javascript.c,v 1.11 2002/09/20 02:06:25 stdarg Exp $";
 #endif
 
 #include <stdio.h>
@@ -192,28 +192,7 @@
 	}
 
 	js_to_c_var(cx, obj, argv[0], &script_var, linked_var->type);
-	if (linked_var->callbacks && linked_var->callbacks->on_write) {
-		int r;
-		r = (linked_var->callbacks->on_write)(linked_var, &script_var);
-		if (r) return JS_FALSE;
-		c_to_js_var(cx, &script_var, rval);
-		return JS_TRUE;
-	}
-	switch (linked_var->type & SCRIPT_TYPE_MASK) {
-		case SCRIPT_UNSIGNED:
-		case SCRIPT_INTEGER:
-			*(int *)(linked_var->value) = (int) script_var.value;
-			break;
-		case SCRIPT_STRING: {
-			char **charptr = (char **)(linked_var->value);
-
-			if (*charptr) free(*charptr);
-			*charptr = strdup(script_var.value);
-			break;
-		}
-		default:
-			return JS_FALSE;
-	}
+	script_linked_var_on_write(linked_var, &script_var);
 	c_to_js_var(cx, &script_var, rval);
 	return JS_TRUE;
 }
Index: eggdrop1.7/modules/perlscript/perlscript.c
diff -u eggdrop1.7/modules/perlscript/perlscript.c:1.20 eggdrop1.7/modules/perlscript/perlscript.c:1.21
--- eggdrop1.7/modules/perlscript/perlscript.c:1.20	Thu May 30 23:11:37 2002
+++ eggdrop1.7/modules/perlscript/perlscript.c	Thu Sep 19 21:06:25 2002
@@ -20,7 +20,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: perlscript.c,v 1.20 2002/05/31 04:11:37 stdarg Exp $";
+static const char rcsid[] = "$Id: perlscript.c,v 1.21 2002/09/20 02:06:25 stdarg Exp $";
 #endif
 
 #include <stdio.h>
@@ -142,29 +142,7 @@
 	script_var_t newvalue = {0};
 
 	perl_to_c_var(sv, &newvalue, linked_var->type);
-	if (linked_var->callbacks && linked_var->callbacks->on_write) {
-		(linked_var->callbacks->on_write)(linked_var, &newvalue);
-		return(0);
-	}
-	switch (linked_var->type) {
-		case SCRIPT_UNSIGNED:
-		case SCRIPT_INTEGER:
-			/* linked_var->value is a pointer to an int/uint */
-			*(int *)(linked_var->value) = (int) newvalue.value;
-			break;
-		case SCRIPT_STRING: {
-			/* linked_var->value is a pointer to a (char *) */
-			char **charptr = (char **)(linked_var->value);
-
-			/* Free the old value. */
-			if (*charptr) free(*charptr);
-
-			/* Set the new value. */
-			if (newvalue.type & SCRIPT_FREE) *charptr = newvalue.value;
-			else *charptr = strdup(newvalue.value);
-			break;
-		}
-	}
+	script_linked_var_on_write(linked_var, &newvalue);
 	return(0);
 }
 
Index: eggdrop1.7/modules/server/Makefile.am
diff -u eggdrop1.7/modules/server/Makefile.am:1.5 eggdrop1.7/modules/server/Makefile.am:1.6
--- eggdrop1.7/modules/server/Makefile.am:1.5	Sat Jun  1 00:15:54 2002
+++ eggdrop1.7/modules/server/Makefile.am	Thu Sep 19 21:06:25 2002
@@ -1,10 +1,10 @@
-# $Id: Makefile.am,v 1.5 2002/06/01 05:15:54 stdarg Exp $
+# $Id: Makefile.am,v 1.6 2002/09/20 02:06:25 stdarg Exp $
 
 # FIXME: optionally allow a system wide install by ignoring the line below.
 pkglibdir		= $(exec_prefix)/modules
 
 pkglib_LTLIBRARIES	= server.la
-server_la_SOURCES	= server.c channels.c
+server_la_SOURCES	= server.c binds.c input.c output.c parse.c serverlist.c channels.c nicklist.c scriptcmds.c servsock.c dcc_commands.c
 server_la_LDFLAGS	= -module -avoid-version -no-undefined
 server_la_LIBADD	= @TCL_LIBS@ @LIBS@ \
 			$(top_builddir)/lib/eggdrop/libeggdrop.la
Index: eggdrop1.7/modules/server/channels.c
diff -u eggdrop1.7/modules/server/channels.c:1.1 eggdrop1.7/modules/server/channels.c:1.2
--- eggdrop1.7/modules/server/channels.c:1.1	Sat Jun  1 12:57:11 2002
+++ eggdrop1.7/modules/server/channels.c	Thu Sep 19 21:06:25 2002
@@ -1,6 +1,7 @@
 /* Some channel-specific stuff. */
 
 #include "lib/eggdrop/module.h"
+#include "output.h"
 
 extern eggdrop_t *egg;
 
@@ -10,8 +11,9 @@
 	for (chan = chanset; chan; chan = chan->next) {
 		chan->status &= ~(CHAN_ACTIVE | CHAN_PEND);
 		if (!channel_inactive(chan)) {
-			dprintf(DP_SERVER, "JOIN %s %s\n",
+			printserv(SERVER_NORMAL, "JOIN %s%s%s",
 				(chan->name[0]) ? chan->name : chan->dname,
+				chan->channel.key[0] ? " " : "",
 				chan->channel.key[0] ? chan->channel.key : chan->key_prot);
 		}
 	}
Index: eggdrop1.7/modules/server/cmdsserv.c
diff -u eggdrop1.7/modules/server/cmdsserv.c:1.9 eggdrop1.7/modules/server/cmdsserv.c:removed
--- eggdrop1.7/modules/server/cmdsserv.c:1.9	Mon Jun 17 23:40:16 2002
+++ eggdrop1.7/modules/server/cmdsserv.c	Thu Sep 19 21:06:36 2002
@@ -1,148 +0,0 @@
-/*
- * cmdsserv.c --
- *
- *	handles commands from a user via dcc that cause server interaction
- */
-/*
- * Copyright (C) 1997 Robey Pointer
- * Copyright (C) 1999, 2000, 2001, 2002 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.
- */
-
-/* FIXME: #include mess
-#ifndef lint
-static const char rcsid[] = "$Id: cmdsserv.c,v 1.9 2002/06/18 04:40:16 guppy Exp $";
-#endif
-*/
-
-static void cmd_servers(struct userrec *u, int idx, char *par)
-{
-  struct server_list *x = serverlist;
-  int i;
-  char s[1024];
-
-  putlog(LOG_CMDS, "*", "#%s# servers", dcc[idx].nick);
-  if (!x) {
-    dprintf(idx, _("There are no servers in the server list.\n"));
-  } else {
-    dprintf(idx, _("Server list:\n"));
-    i = 0;
-    for (; x; x = x->next) {
-      if (x->realname)
-	snprintf(s, sizeof s, "  %s:%d (%s) %s", x->name,
-		 x->port ? x->port : default_port, x->realname,
-		 (i == curserv) ? "<- I am here" : "");
-      else 
-	snprintf(s, sizeof s, "  %s:%d %s", x->name, 
-		 x->port ? x->port : default_port, 
-		 (i == curserv) ? "<- I am here" : "");
-      dprintf(idx, "%s\n", s);
-      i++;
-    }
-    dprintf(idx, _("End of server list.\n")); 
-  }
-}
-
-static void cmd_dump(struct userrec *u, int idx, char *par)
-{
-  if (!par[0]) {
-    dprintf(idx, "Usage: dump <server stuff>\n");
-    return;
-  }
-  putlog(LOG_CMDS, "*", "#%s# dump %s", dcc[idx].nick, par);
-  dprintf(DP_SERVER, "%s\n", par);
-}
-
-static void cmd_jump(struct userrec *u, int idx, char *par)
-{
-  char *other;
-  int port;
-
-  if (par[0]) {
-    other = newsplit(&par);
-    port = atoi(newsplit(&par));
-    if (!port)
-      port = default_port;
-    putlog(LOG_CMDS, "*", "#%s# jump %s %d %s", dcc[idx].nick, other,
-	   port, par);
-    strlcpy(newserver, other, sizeof newserver);
-    newserverport = port;
-    strlcpy(newserverpass, par, sizeof newserverpass);
-  } else
-    putlog(LOG_CMDS, "*", "#%s# jump", dcc[idx].nick);
-  dprintf(idx, "%s...\n", _("Jumping servers..."));
-  cycle_time = 0;
-  nuke_server(_("changing servers"));
-}
-
-static void cmd_clearqueue(struct userrec *u, int idx, char *par)
-{
-  int	msgs;
-
-  if (!par[0]) {
-    dprintf(idx, "Usage: clearqueue <mode|server|help|all>\n");
-    return;
-  }
-  if (!strcasecmp(par, "all")) {
-    msgs = modeq.tot + mq.tot + hq.tot;
-    msgq_clear(&modeq);
-    msgq_clear(&mq);
-    msgq_clear(&hq);
-    burst = 0;
-    dprintf(idx, P_("Removed %d message from all queues\n",
-                    "Removed %d messages from all queues\n", msgs), msgs);
-  } else if (!strcasecmp(par, "mode")) {
-    msgs = modeq.tot;
-    msgq_clear(&modeq);
-    if (mq.tot == 0)
-      burst = 0;
-    dprintf(idx, P_("Removed %1$d message from the %2$s queue\n",
-                    "Removed %1$d messages from the %2$s queue\n", msgs), msgs,
-            "mode");
-  } else if (!strcasecmp(par, "help")) {
-    msgs = hq.tot;
-    msgq_clear(&hq);
-    dprintf(idx, P_("Removed %1$d message from the %2$s queue\n",
-                    "Removed %1$d messages from the %2$s queue\n", msgs), msgs,
-            "help");
-  } else if (!strcasecmp(par, "server")) {
-    msgs = mq.tot;
-    msgq_clear(&mq);
-    if (modeq.tot == 0)
-      burst = 0;
-    dprintf(idx, P_("Removed %1$d message from the %2$s queue\n",
-                   "Removed %1$d messages from the %2$s queue\n", msgs), msgs,
-            "server");
-  } else {
-    dprintf(idx, "Usage: clearqueue <mode|server|help|all>\n");
-    return;
-  }
-  putlog(LOG_CMDS, "*", "#%s# clearqueue %s", dcc[idx].nick, par);
-}
-
-/* Function call should be:
- *   int cmd_whatever(idx,"parameters");
- *
- * As with msg commands, function is responsible for any logging.
- */
-static cmd_t C_dcc_serv[] =
-{
-  {"dump",		"m",	(Function) cmd_dump,		NULL},
-  {"jump",		"m",	(Function) cmd_jump,		NULL},
-  {"servers",		"o",	(Function) cmd_servers,		NULL},
-  {"clearqueue",	"m",	(Function) cmd_clearqueue,	NULL},
-  {NULL,		NULL,	NULL,				NULL}
-};
Index: eggdrop1.7/modules/server/dcc_commands.c
diff -u /dev/null eggdrop1.7/modules/server/dcc_commands.c:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/modules/server/dcc_commands.c	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,53 @@
+#include "lib/eggdrop/module.h"
+
+#include "server.h"
+#include "serverlist.h"
+#include "output.h"
+
+static void parse_server(char *text, char **host, int *port, char **pass)
+{
+	char *sep, *sport = NULL;
+
+	*pass = NULL;
+	*port = 0;
+	*host = text;
+	sep = strchr(text, ' ');
+	if (sep) {
+		*sep++ = 0;
+		sport = sep;
+		sep = strchr(sep, ' ');
+		if (sep) {
+			*sep++ = 0;
+			*pass = sep;
+		}
+		*port = atoi(sport);
+	}
+}
+
+static int cmd_plus_server(struct userrec *u, int idx, char *text)
+{
+	char *host, *pass;
+	int port;
+
+	parse_server(text, &host, &port, &pass);
+	server_add(host, port, pass);
+	dprintf(idx, "Added %s:%d\n", host, port ? port : config.default_port);
+	return(0);
+}
+
+static int cmd_dump(struct userrec *u, int idx, char *par)
+{
+  if (!par[0]) {
+    dprintf(idx, "Usage: dump <server stuff>\n");
+    return(0);
+  }
+  putlog(LOG_CMDS, "*", "#%s# dump %s", dcc[idx].nick, par);
+  printserv(SERVER_NORMAL, "%s\r\n", par);
+  return(0);
+}
+
+cmd_t my_dcc_commands[] =
+{
+  {"dump",		"m",	(Function) cmd_dump,		NULL},
+  {NULL,		NULL,	NULL,				NULL}
+};
Index: eggdrop1.7/modules/server/input.c
diff -u /dev/null eggdrop1.7/modules/server/input.c:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/modules/server/input.c	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,411 @@
+/*
+ * servmsg.c --
+ */
+
+#include "lib/eggdrop/module.h"
+#include "server.h"
+#include "channels.h"
+#include "parse.h"
+#include "output.h"
+#include "binds.h"
+#include "servsock.h"
+#include "nicklist.h"
+
+/* 001: welcome to IRC */
+static int got001(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
+{
+	current_server.registered = 1;
+
+	/* First arg is what server decided our nick is. */
+	str_redup(&current_server.nick, args[0]);
+
+	/* Save the name the server calls itself. */
+	str_redup(&current_server.server_self, from_nick);
+
+	check_bind_event("init-server");
+
+	/* If the init-server bind made us leave the server, stop processing. */
+	if (!current_server.registered) return BIND_RET_BREAK;
+
+	/* Send a whois request so we can see our nick!user at host */
+	printserv(SERVER_MODE, "WHOIS %s", current_server.nick);
+
+	/* Join all our channels. */
+	channels_join_all();
+
+	return(0);
+}
+
+/* Got 442: not on channel
+	:server 442 nick #chan :You're not on that channel
+ */
+static int got442(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
+{
+	struct chanset_t *chan;
+	char *chname = args[1];
+
+	chan = findchan(chname);
+
+  if (chan && !channel_inactive(chan)) {
+      module_entry	*me = module_find("channels", 0, 0);
+
+      putlog(LOG_MISC, chname, _("Server says Im not on channel: %s"), chname);
+      if (me && me->funcs)
+	(me->funcs[CHANNEL_CLEAR])(chan, 1);
+      chan->status &= ~CHAN_ACTIVE;
+      printserv(SERVER_MODE, "JOIN %s %s", chan->name,
+	      chan->channel.key[0] ? chan->channel.key : chan->key_prot);
+  }
+
+  return 0;
+}
+
+static int check_ctcp_ctcr(int which, int to_channel, struct userrec *u, char *nick, char *uhost, char *dest, char *trailing)
+{
+	struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
+	char *cmd, *space, *logdest, *text, *ctcptype;
+	bind_table_t *table;
+	int r, len, flags;
+
+	len = strlen(trailing);
+	if ((len < 2) || (trailing[0] != 1) || (trailing[len-1] != 1)) {
+		/* Not a ctcp/ctcr. */
+		return(0);
+	}
+
+	space = strchr(trailing, ' ');
+	if (!space) return(1);
+
+	*space = 0;
+
+	trailing[len-1] = 0;
+	cmd = trailing+1;	/* Skip over the \001 */
+	text = space+1;
+
+	if (which == 0) table = BT_ctcp;
+	else table = BT_ctcr;
+
+	get_user_flagrec(u, &fr, dest);
+
+	r = check_bind(table, cmd, &fr, nick, uhost, u, dest, cmd, text);
+
+	trailing[len-1] = 1;
+
+	if (r & BIND_RET_BREAK) return(1);
+
+	if (which == 0) ctcptype = "";
+	else ctcptype = " reply";
+
+	/* This should probably go in the partyline module later. */
+	if (to_channel) {
+		flags = LOG_PUBLIC;
+		logdest = dest;
+	}
+	else {
+		flags = LOG_MSGS;
+		logdest = "*";
+	}
+	if (!strcasecmp(cmd, "ACTION")) putlog(flags, logdest, "Action: %s %s", nick, text);
+	else putlog(flags, logdest, "CTCP%s %s: %s from %s (%s)", ctcptype, cmd, text, nick, dest);
+
+	return(1);
+}
+
+static int check_global_notice(char *from_nick, char *from_uhost, char *dest, char *trailing)
+{
+	if (*dest == '$') {
+		putlog(LOG_MSGS | LOG_SERV, "*", "[%s!%s to %s] %s", from_nick, from_uhost, dest, trailing);
+		return(1);
+	}
+	return(0);
+}
+
+/* Got a private (or public) message.
+	:nick!uhost PRIVMSG dest :msg
+ */
+static int gotmsg(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
+{
+	char *dest, *trailing, *first, *space, *text;
+	struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
+	int to_channel;	/* Is it going to a channel? */
+	int r;
+
+	dest = args[0];
+	trailing = args[1];
+
+	/* Check if it's a global message. */
+	r = check_global_notice(from_nick, from_uhost, dest, trailing);
+	if (r) return(0);
+
+	/* Check if it's an op/voice message. */
+	if ((*dest == '@' || *dest == '+') && strchr(CHANMETA, *(dest+1))) {
+		to_channel = 1;
+		dest++;
+	}
+	else if (strchr(CHANMETA, *dest)) to_channel = 1;
+	else to_channel = 0;
+
+	/* Check if it's a ctcp. */
+	r = check_ctcp_ctcr(0, to_channel, u, from_nick, from_uhost, dest, trailing);
+	if (r) return(0);
+
+
+	/* If it's a message, it goes to msg/msgm or pub/pubm. */
+	/* Get the first word so we can do msg or pub. */
+	first = trailing;
+	space = strchr(trailing, ' ');
+	if (space) {
+		*space = 0;
+		text = space+1;
+	}
+	else text = "";
+
+	get_user_flagrec(u, &fr, dest);
+	if (to_channel) {
+		r = check_bind(BT_pub, first, &fr, from_nick, from_uhost, u, dest, text);
+		if (r & BIND_RET_LOG) {
+			putlog(LOG_CMDS, dest, "<<%s>> !%s! %s %s", from_nick, u ? u->handle : "*", first, text);
+		}
+	}
+	else {
+		r = check_bind(BT_msg, first, &fr, from_nick, from_uhost, u, text);
+		if (r & BIND_RET_LOG) {
+			putlog(LOG_CMDS, "*", "(%s!%s) !%s! %s %s", from_nick, from_uhost, u ? u->handle : "*", first, text);
+		}
+	}
+
+	if (space) *space = ' ';
+
+	if (r & BIND_RET_BREAK) return(0);
+
+	/* And now the stackable version. */
+	if (to_channel) {
+		r = check_bind(BT_pubm, trailing, &fr, from_nick, from_uhost, u, dest, trailing);
+	}
+	else {
+		r = check_bind(BT_msg, trailing, &fr, from_nick, from_uhost, u, trailing);
+	}
+
+	if (!(r & BIND_RET_BREAK)) {
+		/* This should probably go in the partyline module later. */
+		if (to_channel) {
+			putlog(LOG_PUBLIC, dest, "<%s> %s", from_nick, trailing);
+		}
+		else {
+			putlog(LOG_MSGS, "*", "[%s (%s)] %s", from_nick, from_uhost, trailing);
+		}
+	}
+	return(0);
+}
+
+/* Got a private notice.
+	:nick!uhost NOTICE dest :hello there
+ */
+static int gotnotice(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
+{
+	char *dest, *trailing;
+	struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
+	int r, to_channel;
+
+	dest = args[0];
+	trailing = args[1];
+
+	/* See if it's a server notice. */
+	if (!from_uhost) {
+		putlog(LOG_SERV, "*", "-NOTICE- %s", trailing);
+		return(0);
+	}
+
+	/* Check if it's a global notice. */
+	r = check_global_notice(from_nick, from_uhost, dest, trailing);
+	if (r) return(0);
+
+	if ((*dest == '@' || *dest == '+') && strchr(CHANMETA, *(dest+1))) {
+		to_channel = 1;
+		dest++;
+	}
+	else if (strchr(CHANMETA, *dest)) to_channel = 1;
+	else to_channel = 0;
+
+	/* Check if it's a ctcp. */
+	r = check_ctcp_ctcr(1, to_channel, u, from_nick, from_uhost, dest, trailing);
+	if (r) return(0);
+
+	get_user_flagrec(u, &fr, NULL);
+	r = check_bind(BT_notice, trailing, &fr, from_nick, from_uhost, u, dest, trailing);
+
+	if (!(r & BIND_RET_BREAK)) {
+		/* This should probably go in the partyline module later. */
+		if (to_channel) {
+			putlog(LOG_PUBLIC, dest, "-%s:%s- %s", from_nick, dest, trailing);
+		}
+		else {
+			putlog(LOG_MSGS, "*", "-%s (%s)- %s", from_nick, from_uhost, trailing);
+		}
+	}
+	return(0);
+}
+
+/* WALLOPS: oper's nuisance
+	:csd.bu.edu WALLOPS :Connect '*.uiuc.edu 6667' from Joshua
+ */
+static int gotwall(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
+{
+	char *msg;
+	int r;
+
+	msg = args[1];
+	r = check_bind(BT_wall, msg, NULL, from_nick, msg);
+	if (!(r & BIND_RET_BREAK)) {
+		if (from_uhost) putlog(LOG_WALL, "*", "!%s (%s)! %s", from_nick, from_uhost, msg);
+		else putlog(LOG_WALL, "*", "!%s! %s", from_nick, msg);
+	}
+	return 0;
+}
+
+
+/* 432 : Bad nickname
+ * If we're registered already, then just inform the user and keep the current
+ * nick. Otherwise, generate a random nick so that we can get registered. */
+static int got432(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
+{
+	char *badnick;
+
+	badnick = args[1];
+	if (current_server.registered) {
+		putlog(LOG_MISC, "*", "NICK IS INVALID: %s (keeping '%s').", badnick, botname);
+	}
+	else {
+		putlog(LOG_MISC, "*", "Server says my nickname ('%s') is invalid, trying new random nick.", badnick);
+		try_random_nick();
+	}
+	return(0);
+}
+
+/* 433 : Nickname in use
+ * Change nicks till we're acceptable or we give up
+ */
+static int got433(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
+{
+	char *badnick;
+
+	badnick = args[1];
+	if (current_server.registered) {
+		/* We are online and have a nickname, we'll keep it */
+		putlog(LOG_MISC, "*", "Nick is in use: '%s' (keeping '%s')", badnick, botname);
+	}
+	else {
+		putlog(LOG_MISC, "*", "Nick is in use: '%s' (trying next one)", badnick, botname);
+		try_next_nick();
+	}
+	return(0);
+}
+
+/* 435 : Cannot change to a banned nickname. */
+static int got435(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
+{
+	char *banned_nick, *chan;
+
+	banned_nick = args[1];
+	chan = args[2];
+	putlog(LOG_MISC, "*", "Cannot change to banned nickname (%s on %s)", banned_nick, chan);
+	return(0);
+}
+
+/* 437 : Nickname juped (IRCnet) */
+static int got437(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
+{
+	char *chan;
+
+	chan = args[1];
+	putlog(LOG_MISC, "*", "Can't change nickname to %s. Is my nickname banned?", chan);
+
+	/* If we aren't registered yet, try another nick. Otherwise just keep
+	 * our current nick (no action). */
+	if (!current_server.registered) {
+		try_next_nick();
+	}
+	return(0);
+}
+
+/* 438 : Nick change too fast */
+static int got438(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
+{
+	putlog(LOG_MISC, "*", "%s", _("Nick change was too fast."));
+	return(0);
+}
+
+static int got451(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
+{
+  /* Usually if we get this then we really messed up somewhere
+   * or this is a non-standard server, so we log it and kill the socket
+   * hoping the next server will work :) -poptix
+   */
+  putlog(LOG_MISC, "*", _("%s says I'm not registered, trying next one."), from_nick);
+  kill_server("The server says we are not registered yet.");
+  return 0;
+}
+
+/* Got error */
+static int goterror(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
+{
+  putlog(LOG_SERV | LOG_MSGS, "*", "-ERROR from server- %s", args[0]);
+  putlog(LOG_SERV, "*", "Disconnecting from server.");
+  kill_server("disconnecting due to error");
+  return 1;
+}
+
+/* Got nick change.  */
+static int gotnick(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
+{
+	char *newnick = args[0];
+
+	if (match_my_nick(from_nick)) str_redup(&botname, newnick);
+	return(0);
+}
+
+/* Pings are immediately returned, no queue. */
+static int gotping(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
+{
+	printserv(SERVER_NOQUEUE, "PONG :%s", args[0]);
+	return(0);
+}
+
+/* 311 : save our user at host from whois reply */
+static int got311(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
+{
+	char *nick, *user, *host, *realname;
+  
+	if (nargs < 6) return(0);
+
+	nick = args[1];
+	user = args[2];
+	host = args[3];
+	realname = args[5];
+  
+	if (match_my_nick(nick)) {
+		str_redup(&current_server.user, user);
+		str_redup(&current_server.host, host);
+		str_redup(&current_server.real_name, realname);
+	}
+	return(0);
+}
+
+cmd_t my_new_raw_binds[] = {
+	{"PRIVMSG", "", (Function) gotmsg, NULL},
+	{"NOTICE", "", (Function) gotnotice, NULL},
+	{"WALLOPS", "", (Function) gotwall, NULL},
+	{"PING", "", (Function) gotping, NULL},
+	{"NICK", "", (Function) gotnick, NULL},
+	{"ERROR", "", (Function) goterror, NULL},
+	{"001", "", (Function) got001, NULL},
+	{"432",	 "", (Function) got432,  NULL},
+	{"433",	 "", (Function) got433,  NULL},
+	{"435",  "", (Function) got435,  NULL},
+	{"438",  "", (Function) got438,  NULL},
+	{"437",	 "", (Function) got437,	 NULL},
+	{"451",	 "", (Function) got451,	 NULL},
+	{"442",	 "", (Function) got442,	 NULL},
+	{"311", "", (Function) got311, NULL},
+	{NULL, NULL, NULL, NULL}
+};
Index: eggdrop1.7/modules/server/nicklist.c
diff -u /dev/null eggdrop1.7/modules/server/nicklist.c:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/modules/server/nicklist.c	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,88 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "lib/eggdrop/module.h"
+#include "nicklist.h"
+#include "output.h"
+
+/*
+ * serverlist.c maintains the connection of servers and gets the next entry
+ * when we want to connect.
+ */
+
+char **nick_list = NULL;
+int nick_list_index = -1;
+int nick_list_len = 0;
+int nick_list_cycled = 0;
+
+void try_next_nick()
+{
+	const char *nick;
+
+	nick = nick_get_next();
+	if (!nick) {
+		putlog(LOG_MISC, "*", "try_next_nick: using random nick because %s.", nick_list_len ? "none of the defined nicks are valid" : "there are no nicks defined");
+		try_random_nick();
+		return;
+	}
+	printserv(SERVER_MODE, "NICK %s\r\n", nick);
+}
+
+void try_random_nick()
+{
+	printserv(SERVER_MODE, "NICK egg%d\r\n", random());
+}
+
+void nick_list_on_connect()
+{
+	nick_list_index = -1;
+	nick_list_cycled = 0;
+}
+
+/* Get the next server from the list. */
+const char *nick_get_next()
+{
+	if (nick_list_len <= 0) return(NULL);
+	nick_list_index++;
+	if (nick_list_index >= nick_list_len) {
+		if (nick_list_cycled) return(NULL);
+		nick_list_cycled = 1;
+		nick_list_index = 0;
+	}
+
+	return(nick_list[nick_list_index]);
+}
+
+/* Add a server to the server list. */
+int nick_add(const char *nick)
+{
+	nick_list = realloc(nick_list, sizeof(char *) * (nick_list_len+1));
+	nick_list[nick_list_len] = strdup(nick);
+	nick_list_len++;
+	return(0);
+}
+
+/* Remove a server from the server list based on its index. */
+int nick_del(int num)
+{
+	if (num >= 0 && num < nick_list_len) {
+		free(nick_list[num]);
+		memmove(nick_list+num, nick_list+num+1, nick_list_len-num-1);
+	}
+	if (num < nick_list_index) nick_list_index--;
+	nick_list_len--;
+
+	return(0);
+}
+
+/* Clear out the server list. */
+int nick_clear()
+{
+	int i;
+
+	for (i = 0; i < nick_list_len; i++) {
+		free(nick_list[i]);
+	}
+	if (nick_list) free(nick_list);
+	return(0);
+}
Index: eggdrop1.7/modules/server/nicklist.h
diff -u /dev/null eggdrop1.7/modules/server/nicklist.h:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/modules/server/nicklist.h	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,12 @@
+#ifndef _NICKLIST_H_
+#define _NICKLIST_H_
+
+void try_next_nick();
+void try_random_nick();
+void nick_list_on_connect();
+const char *nick_get_next();
+int nick_add(const char *nick);
+int nick_del(int num);
+int nick_clear();
+
+#endif
Index: eggdrop1.7/modules/server/output.c
diff -u /dev/null eggdrop1.7/modules/server/output.c:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/modules/server/output.c	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,51 @@
+#define MAKING_SERVER
+#include "lib/eggdrop/module.h"
+#include "server.h"
+#include "output.h"
+
+extern eggdrop_t *egg;
+extern current_server_t current_server;
+
+/* Sends formatted output to the currently connected server. */
+int printserv(int priority, const char *format, ...)
+{
+	char buf[512], *ptr;
+	int len;
+	va_list args;
+
+	va_start(args, format);
+	ptr = egg_mvsprintf(buf, sizeof(buf), &len, format, args);
+	va_end(args);
+
+	if (len > 510) {
+		ptr[508] = '\r';
+		ptr[509] = '\n';
+		ptr[510] = 0;
+		len = 510;
+	}
+
+//	if (priority == SERVER_NOQUEUE) {
+		sockbuf_write(current_server.idx, ptr, len);
+		putlog(LOG_MISC, "*", "sent '%s' to server", ptr);
+		if (len > 0 && ptr[len-1] != '\n') {
+			buf[0] = '\r';
+			buf[1] = '\n';
+			sockbuf_write(current_server.idx, buf, 2);
+		}
+/*	}
+	else {
+		queue_server(priority, ptr, len);
+	}
+	*/
+	if (ptr != buf) free(ptr);
+	return(len);
+}
+
+void queue_server(int priority, char *text, int len)
+{
+	printserv(SERVER_NOQUEUE, "%s", text);
+}
+
+void dequeue_messages()
+{
+}
Index: eggdrop1.7/modules/server/output.h
diff -u /dev/null eggdrop1.7/modules/server/output.h:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/modules/server/output.h	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,15 @@
+#ifndef _OUTPUT_H_
+#define _OUTPUT_H_
+
+/* Server output priorities. */
+#define SERVER_NOQUEUE	1
+#define SERVER_MODE	2
+#define SERVER_NORMAL	3
+#define SERVER_HELP	4
+#define SERVER_NEXT	8
+
+int printserv(int priority, const char *format, ...);
+void queue_server(int priority, char *text, int len);
+void dequeue_messages();
+
+#endif
Index: eggdrop1.7/modules/server/parse.c
diff -u /dev/null eggdrop1.7/modules/server/parse.c:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/modules/server/parse.c	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,72 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "parse.h"
+
+/* Take care of array manipulation in adding an argument. */
+static void add_arg(irc_msg_t *msg, char *text)
+{
+	if (msg->nargs >= IRC_MSG_NSTATIC_ARGS) {
+		if (msg->nargs > IRC_MSG_NSTATIC_ARGS) {
+			msg->args = (char **)realloc(msg->args, sizeof(char *) * (msg->nargs+1));
+		}
+		else {
+			msg->args = (char **)malloc(sizeof(char *) * (IRC_MSG_NSTATIC_ARGS+1));
+			memcpy(msg->args, msg->static_args, sizeof(char *) * IRC_MSG_NSTATIC_ARGS);
+		}
+	}
+	msg->args[msg->nargs] = text;
+	msg->nargs++;
+}
+
+/* Parses an irc message into standard parts. Be sure to call irc_msg_cleanup()
+ * when you are done using it, so that it can free the argument array if
+ * necessary. */
+void irc_msg_parse(char *text, irc_msg_t *msg)
+{
+	char *space;
+
+	memset(msg, 0, sizeof(*msg));
+	msg->args = msg->static_args;
+	if (*text == ':') {
+		msg->prefix = text+1;
+		space = strchr(msg->prefix, ' ');
+		if (!space) return;
+		*space = 0;
+		text = space+1;
+	}
+	msg->cmd = text;
+	space = strchr(text, ' ');
+	if (!space) return;
+	*space = 0;
+	text = space+1;
+
+	while (*text && (*text != ':')) {
+	       	space = strchr(text, ' ');
+		add_arg(msg, text);
+		if (space) {
+			*space = 0;
+			text = space+1;
+		}
+		else break;
+	}
+	if (*text == ':') add_arg(msg, text+1);
+}
+
+/* Replace nulls with spaces again, in case you want to re-use the text. */
+void irc_msg_restore(irc_msg_t *msg)
+{
+	int i;
+	for (i = 0; i < msg->nargs; i++) {
+		if (msg->args[i][-1] == ':') msg->args[i][-2] = ' ';
+		else msg->args[i][-1] = ' ';
+	}
+}
+
+/* Reset the argument array, freeing any dynamic memory. */
+void irc_msg_cleanup(irc_msg_t *msg)
+{
+	if (msg->args && msg->args != msg->static_args) free(msg->args);
+	msg->args = msg->static_args;
+	msg->nargs = 0;
+}
Index: eggdrop1.7/modules/server/parse.h
diff -u /dev/null eggdrop1.7/modules/server/parse.h:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/modules/server/parse.h	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,19 @@
+#ifndef _PARSE_H_
+#define _PARSE_H_
+
+/* Structure to hold the parts of an irc message. NSTATIC_ARGS is how much
+ * space we allocate statically for arguments. If we run out, more is
+ * allocated dynamically. */
+#define IRC_MSG_NSTATIC_ARGS	10
+typedef struct irc_msg {
+	struct irc_msg *next;
+	char *prefix, *cmd, **args, *trailing;
+	char *static_args[IRC_MSG_NSTATIC_ARGS];
+	int nargs;
+} irc_msg_t;
+
+void irc_msg_parse(char *text, irc_msg_t *msg);
+void irc_msg_restore(irc_msg_t *msg);
+void irc_msg_cleanup(irc_msg_t *msg);
+
+#endif /* _PARSE_H_ */
Index: eggdrop1.7/modules/server/scriptcmds.c
diff -u eggdrop1.7/modules/server/scriptcmds.c:1.9 eggdrop1.7/modules/server/scriptcmds.c:1.10
--- eggdrop1.7/modules/server/scriptcmds.c:1.9	Mon Jun 17 23:40:16 2002
+++ eggdrop1.7/modules/server/scriptcmds.c	Thu Sep 19 21:06:25 2002
@@ -22,67 +22,56 @@
 
 /* FIXME: #include mess
 #ifndef lint
-static const char rcsid[] = "$Id: scriptcmds.c,v 1.9 2002/06/18 04:40:16 guppy Exp $";
+static const char rcsid[] = "$Id: scriptcmds.c,v 1.10 2002/09/20 02:06:25 stdarg Exp $";
 #endif
 */
 
-#include <eggdrop/eggdrop.h> /* Eggdrop API */
+#include "lib/eggdrop/module.h"
+
+#include "server.h"
+#include "serverlist.h"
+#include "nicklist.h"
+#include "output.h"
+#include "servsock.h"
 
 static int script_isbotnick (char *nick);
 static int script_putserv(char *queue, char *next, char *text);
-static int script_jump (int nargs, char *optserver, int optport, char *optpassword);
-static int script_clearqueue (script_var_t *retval, char *queuetype);
-static int script_queuesize (script_var_t *retval, int nargs, char *queuetype, int flags);
-static int script_server_list(script_var_t *retval);
-
-static int altnick_on_write(script_linked_var_t *linked_var, script_var_t *newvalue);
-static script_var_callbacks_t altnick_callbacks = {
-	NULL,
-	altnick_on_write,
-	NULL
-};
+static int script_jump (int nargs, int num);
 
-static char *script_botname;
-static int botname_on_read(script_linked_var_t *linked_var, script_var_t *newvalue);
-static int botname_on_write(script_linked_var_t *linked_var, script_var_t *newvalue);
-static script_var_callbacks_t botname_callbacks = {
-	botname_on_read,
-	botname_on_write,
-	NULL
-};
+/* From serverlist.c */
+extern int server_list_index;
 
-static script_linked_var_t server_script_vars[] = {
-	{"", "server", &curserv, SCRIPT_INTEGER, NULL},
-	{"", "altnick", &altnick, SCRIPT_STRING, &altnick_callbacks},
-	{"", "botname", &script_botname, SCRIPT_STRING, &botname_callbacks},
-	{"", "botnick", NULL, SCRIPT_STRING, NULL},
-	{"", "nick_len", &nick_len, SCRIPT_INTEGER, NULL},
+/* From server.c */
+extern int cycle_delay;
+extern current_server_t current_server;
+
+script_linked_var_t server_script_vars[] = {
+	{"", "server", &server_list_index, SCRIPT_INTEGER | SCRIPT_READONLY, NULL},
+	{"", "botnick", &current_server.nick, SCRIPT_STRING | SCRIPT_READONLY, NULL},
 	{0}
 };
 
-static script_command_t server_script_cmds[] = {
-        {"", "jump", script_jump, NULL, 0, "sis", "server port password", SCRIPT_INTEGER, SCRIPT_VAR_ARGS | SCRIPT_PASS_COUNT},
+script_command_t server_script_cmds[] = {
+        {"", "jump", script_jump, NULL, 0, "i", "num", SCRIPT_INTEGER, SCRIPT_VAR_ARGS | SCRIPT_PASS_COUNT},
         {"", "isbotnick", script_isbotnick, NULL, 1, "s", "nick", SCRIPT_INTEGER, 0},
-        {"", "clearqueue", script_clearqueue, NULL, 1, "s", "queuetype", SCRIPT_INTEGER, SCRIPT_PASS_RETVAL},
-        {"", "queuesize", script_queuesize, NULL, 0, "s", "?queuetype?", SCRIPT_INTEGER, SCRIPT_VAR_ARGS | SCRIPT_PASS_COUNT | SCRIPT_PASS_RETVAL},
         {"", "putserv", script_putserv, NULL, 1, "sss", "?-queuetype? ?-next? text", SCRIPT_INTEGER, SCRIPT_VAR_ARGS | SCRIPT_VAR_FRONT},
 	{"", "server_add", server_add, NULL, 1, "sis", "host ?port? ?pass?", SCRIPT_INTEGER, SCRIPT_VAR_ARGS},
 	{"", "server_del", server_del, NULL, 1, "i", "server-num", SCRIPT_INTEGER, 0},
 	{"", "server_clear", server_clear, NULL, 0, "", "", SCRIPT_INTEGER, 0},
-	{"", "server_list", script_server_list, NULL, 0, "", "", 0, SCRIPT_PASS_RETVAL},
+	{"", "nick_add", nick_add, NULL, 1, "s", "nick", SCRIPT_INTEGER, 0},
+	{"", "nick_del", nick_del, NULL, 1, "i", "nick-num", SCRIPT_INTEGER, 0},
+	{"", "nick_clear", nick_clear, NULL, 0, "", "", SCRIPT_INTEGER, 0},
         {0}
 };
 
-static int script_isbotnick (char *nick)
+static int script_isbotnick(char *nick)
 {
 	return match_my_nick(nick);
 }
 
-static int script_putserv (char *queue, char *next, char *text)
+static int script_putserv(char *queue, char *next, char *text)
 {
-	char s[511];
-	int queue_num = 0;
-	int len = strlen(text);
+	int prio;
 
 	/* Figure out which arguments they've given us. */
 	if (!next) queue = "-serv";
@@ -104,202 +93,31 @@
 
 	/* Figure out which queue they want. */
 	if (!strcasecmp(queue, "-noqueue")) {
-		if (serv >= 0) {
-			/* We'll add a \r\n to the end before we send it. */
-			char *copy = msprintf("%s\r\n", text);
-			tputs(serv, copy, len+2);
-			free(copy);
-		}
-		return(0);
+		prio = SERVER_NOQUEUE;
 	}
 	else if (!strcasecmp(queue, "-help")) {
-		queue_num = next ? DP_HELP_NEXT : DP_HELP;
+		prio = SERVER_HELP;
 	}
 	else if (!strcasecmp(queue, "-quick")) {
-		queue_num = next ? DP_MODE_NEXT : DP_MODE;
+		prio = SERVER_MODE;
 	}
 	else {
-		queue_num = next ? DP_SERVER_NEXT : DP_SERVER;
+		prio = SERVER_NORMAL;
 	}
 
-	/* We trim the data to make it IRC-compatible */
-	if (len > 510) {
-		strncpy(s, text, 510);
-		s[510] = 0;
+	if (next) prio |= SERVER_NEXT;
 
-		dprintf(queue_num, "%s\n", s);
-	}
-	else dprintf(queue_num, "%s\n", text);
+	printserv(prio, "%s\r\n", text);
 
 	return(0);
 }
 
-static int script_jump (int nargs, char *optserver, int optport, char *optpassword)
+static int script_jump(int nargs, int num)
 {
-  	if (nargs >= 1) {
-    		strlcpy(newserver, optserver, sizeof(newserver));
-    		
-		if (nargs >= 2)
-      			newserverport = optport;
-    		else
-      			newserverport = default_port;
-    
-		if (nargs == 3)
-      			strlcpy(newserverpass, optpassword, sizeof(newserverpass) );
-  	}
+  	if (nargs) server_set_next(num);
   
-	cycle_time = 0;
-	
-  	nuke_server("changing servers\n");
-	
-	return(1);
-}
-
-static int script_clearqueue (script_var_t *retval, char *queuetype)
-{
-	struct msgq *q, *qq;
-	int msgs = 0;
-	retval->type = SCRIPT_INTEGER;
-	
-	if (!strcmp(queuetype,"all")) {
-		msgs = (int) (modeq.tot + mq.tot + hq.tot);
-		for (q = modeq.head; q; q = qq) { 
-			qq = q->next;
-			free(q->msg);
-			free(q);
-		}
-		for (q = mq.head; q; q = qq) {
-			qq = q->next;
-			free(q->msg);
-			free(q);
-		}
-		for (q = hq.head; q; q = qq) {
-			qq = q->next;
-			free(q->msg);
-			free(q);
-		}
-		modeq.tot = mq.tot = hq.tot = modeq.warned = mq.warned = hq.warned = 0;
-		mq.head = hq.head = modeq.head = mq.last = hq.last = modeq.last = 0;
-		burst = 0;
-		
-		retval->value = (void *)msgs;
-		return(1);
-	
-	} else if (!strncmp(queuetype,"serv", 4)) {
-		msgs = mq.tot;
-		for (q = mq.head; q; q = qq) {
-			qq = q->next;
-			free(q->msg);
-			free(q);
-		}
-		mq.tot = mq.warned = 0;
-		mq.head = mq.last = 0;
-		if (modeq.tot == 0)
-			burst = 0;
-		mq.tot = mq.warned = 0;
-		mq.head = mq.last = 0;
-		
-		retval->value = (void *)msgs;
-		return(1);
-	
-	} else if (!strcmp(queuetype,"mode")) {
-		msgs = modeq.tot;
-		for (q = modeq.head; q; q = qq) { 
-			qq = q->next;
-			free(q->msg);
-			free(q);
-		}
-		if (mq.tot == 0)
-			burst = 0;
-		modeq.tot = modeq.warned = 0;
-		modeq.head = modeq.last = 0;
-		
-		retval->value = (void *)msgs;	
-		return(1);
-		
-	} else if (!strcmp(queuetype,"help")) {
-		msgs = hq.tot;
-		for (q = hq.head; q; q = qq) {
-			qq = q->next;
-			free(q->msg);
-			free(q);
-		}
-		hq.tot = hq.warned = 0;
-		hq.head = hq.last = 0;
-	
-		retval->value = (void *)msgs;
-		return(1);
-	}
-	
-	retval->type = SCRIPT_STRING | SCRIPT_ERROR;
-	retval->value = "bad option: must be mode, server, help, or all";
+	cycle_delay = config.cycle_delay;
+	kill_server("changing servers");
 	
 	return(0);
-}
-
-static int script_queuesize (script_var_t *retval, int nargs, char *queuetype, int flags)
-{	
-	int x = 0;
-
-	retval->type = SCRIPT_INTEGER;
-	if (nargs == 0) {
-		x = (int) (modeq.tot + hq.tot + mq.tot);
-		retval->value = (void *)x;
-		return(1);
-	} else if (!strncmp(queuetype, "serv", 4)) {
-		x = (int) (mq.tot);
-		retval->value = (void *)x;
-		return(1);
-	} else if (!strcmp(queuetype, "mode")) {
-		x = (int) (modeq.tot);
-		retval->value = (void *)x;
-		return(1);
-	} else if (!strcmp(queuetype, "help")) {
-		x = (int) (hq.tot);
-		retval->value = (void *)x;
-		return(1);
-	}
-	
-	retval->type = SCRIPT_STRING | SCRIPT_ERROR;
-	retval->value = "bad option: must be mode, server, or help";
-	return(0);
-}
-
-static int script_server_list(script_var_t *retval)
-{
-	script_var_t *sublist;
-	struct server_list *ptr;
-
-	retval->type = SCRIPT_ARRAY | SCRIPT_VAR | SCRIPT_FREE;
-	retval->len = 0;
-
-	for (ptr = serverlist; ptr; ptr = ptr->next) {
-		sublist = script_list(4, script_string(ptr->name, -1),
-			script_int(ptr->port),
-			script_string(ptr->pass, -1),
-			script_string(ptr->realname, -1)
-		);
-		script_list_append(retval, sublist);
-	}
-	return(0);
-}
-
-static int altnick_on_write(script_linked_var_t *linked_var, script_var_t *newvalue)
-{
-	str_redup(&altnick, newvalue->value);
-	if (raltnick) free(raltnick);
-	raltnick = NULL;
-	return(0);
-}
-
-static int botname_on_read(script_linked_var_t *linked_var, script_var_t *newvalue)
-{
-	if (script_botname) free(script_botname);
-	script_botname = msprintf("%s%s%s", botname, botuserhost[0] ? "!" : "", botuserhost);
-	return(0);
-}
-
-static int botname_on_write(script_linked_var_t *linked_var, script_var_t *newvalue)
-{
-	return(1);
 }
Index: eggdrop1.7/modules/server/server.c
diff -u eggdrop1.7/modules/server/server.c:1.35 eggdrop1.7/modules/server/server.c:1.36
--- eggdrop1.7/modules/server/server.c:1.35	Mon Jun 17 23:40:16 2002
+++ eggdrop1.7/modules/server/server.c	Thu Sep 19 21:06:25 2002
@@ -1,1407 +1,114 @@
 /*
- * server.c --
- *
- *	basic irc server support
+ * server.c implements the eggdrop module interface
  */
-/*
- * Copyright (C) 1997 Robey Pointer
- * Copyright (C) 1999, 2000, 2001, 2002 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: server.c,v 1.35 2002/06/18 04:40:16 guppy Exp $";
-#endif
 
 #define MODULE_NAME "server"
 #define MAKING_SERVER
 #include "lib/eggdrop/module.h"
 #include "server.h"
+#include "servsock.h"
+#include "binds.h"
 
 #define start server_LTX_start
 
 eggdrop_t *egg = NULL;
 
-static int ctcp_mode;
-static int serv;		/* sock # of server currently */
-static int servidx;		/* idx of server */
-static int strict_host;		/* strict masking of hosts ? */
-static char newserver[121];	/* new server? */
-static int newserverport;	/* new server port? */
-static char newserverpass[121];	/* new server password? */
-static time_t trying_server;	/* trying to connect to a server right now? */
-static egg_timeval_t server_lag = {0}; /* how lagged is the server? */
-static char *altnick = NULL;	/* possible alternate nickname to use */
-static char *raltnick = NULL;	/* random nick created from altnick */
-static int curserv;		/* current position in server list: */
-static int flud_thr;		/* msg flood threshold */
-static int flud_time;		/* msg flood time */
-static int flud_ctcp_thr;	/* ctcp flood threshold */
-static int flud_ctcp_time;	/* ctcp flood time */
-static char botuserhost[121];	/* bot's user at host (refreshed whenever the
-				   bot joins a channel) */
-				/* may not be correct user at host BUT it's
-				   how the server sees it */
-static int keepnick;		/* keep trying to regain my intended
-				   nickname? */
-static int nick_juped = 0;	/* True if origbotname is juped(RPL437) (dw) */
-static int check_stoned;	/* Check for a stoned server? */
-static int quiet_reject;	/* Quietly reject dcc chat or sends from
-				   users without access? */
-static int waiting_for_awake;	/* set when i unidle myself, cleared when
-				   i get the response */
-static time_t server_online;	/* server connection time */
-static time_t server_cycle_wait;	/* seconds to wait before
-					   re-beginning the server list */
-static char botrealname[121];	/* realname of bot */
-static int server_timeout;	/* server timeout for connecting */
-static struct server_list *serverlist;	/* old-style queue, still used by
-					   server list */
-static int cycle_time;		/* cycle time till next server connect */
-static int default_port;	/* default IRC port */
-static char *oldnick = NULL;	/* previous nickname *before* rehash */
-static int trigger_on_ignore;	/* trigger bindings if user is ignored ? */
-static int answer_ctcp;		/* answer how many stacked ctcp's ? */
-static int check_mode_r;	/* check for IRCNET +r modes */
-static int resolvserv;		/* in the process of resolving a server host */
-static int lastpingtime;	/* IRCNet LAGmeter support -- drummer */
-static char stackablecmds[511];
-static char stackable2cmds[511];
-static time_t last_time;
-static int use_penalties;
-static int use_fastdeq;
-static int nick_len;		/* Maximal nick length allowed on the
-				   network. */
-static int kick_method;
-static int optimize_kicks;
-
-
-static void empty_msgq(void);
-static void next_server(int *, char *, unsigned int *, char *);
-static void disconnect_server();
-static char *get_altbotnick(void);
-static int calc_penalty(char *);
-static int fast_deq(int);
-static void check_queues(char *, char *);
-static void parse_q(struct msgq_head *, char *, char *);
-static void purge_kicks(struct msgq_head *);
-static int deq_kick(int);
-static void msgq_clear(struct msgq_head *qh);
-
-struct server_list *server_get_current();
-
-/* New bind tables. */
-static bind_table_t *BT_wall, *BT_new_raw, *BT_raw, *BT_notice, *BT_msg, *BT_msgm, *BT_pub, *BT_pubm;
-static bind_table_t *BT_flood, *BT_ctcr, *BT_ctcp;
-
-#include "servmsg.c"
-
-#define MAXPENALTY 10
-
-/* Number of seconds to wait between transmitting queued lines to the server
- * lower this value at your own risk.  ircd is known to start flood control
- * at 512 bytes/2 seconds.
- */
-#define msgrate 2
-
-/* Maximum messages to store in each queue. */
-static int maxqmsg;
-static struct msgq_head mq, hq, modeq;
-static int burst;
-
-/* Prototypes for serverlist manipulation. */
-static int server_add(char *host, int port, char *pass);
-static int server_del(int num);
-static int server_clear();
-
-#include "cmdsserv.c"
-#include "scriptcmds.c"
-
-
-/*
- *     Bot server queues
- */
-
-/* Called periodically to shove out another queued item.
- *
- * 'mode' queue gets priority now.
- *
- * Most servers will allow 'busts' of upto 5 msgs, so let's put something
- * in to support flushing modeq a little faster if possible.
- * Will send upto 4 msgs from modeq, and then send 1 msg every time
- * it will *not* send anything from hq until the 'burst' value drops
- * down to 0 again (allowing a sudden mq flood to sneak through).
- */
-static void deq_msg()
-{
-  struct msgq *q;
-  int ok = 0;
-
-  /* now < last_time tested 'cause clock adjustments could mess it up */
-  if ((now - last_time) >= msgrate || now < (last_time - 90)) {
-    last_time = now;
-    if (burst > 0)
-      burst--;
-    ok = 1;
-  }
-  if (serv < 0)
-    return;
-  /* Send upto 4 msgs to server if the *critical queue* has anything in it */
-  if (modeq.head) {
-    while (modeq.head && (burst < 4) && ((last_time - now) < MAXPENALTY)) {
-      if (deq_kick(DP_MODE)) {
-        burst++;
-        continue;
-      }
-      if (!modeq.head)
-        break;
-      if (fast_deq(DP_MODE)) {
-        burst++;
-        continue;
-      }
-      tputs(serv, modeq.head->msg, modeq.head->len);
-      if (debug_output) {
-	modeq.head->msg[strlen(modeq.head->msg) - 1] = 0; /* delete the "\n" */
-        putlog(LOG_SRVOUT, "*", "[m->] %s", modeq.head->msg);
-      }
-      modeq.tot--;
-      last_time += calc_penalty(modeq.head->msg);
-      q = modeq.head->next;
-      free(modeq.head->msg);
-      free(modeq.head);
-      modeq.head = q;
-      burst++;
-    }
-    if (!modeq.head)
-      modeq.last = 0;
-    return;
-  }
-  /* Send something from the normal msg q even if we're slightly bursting */
-  if (burst > 1)
-    return;
-  if (mq.head) {
-    burst++;
-    if (deq_kick(DP_SERVER))
-      return;
-    if (fast_deq(DP_SERVER))
-      return;
-    tputs(serv, mq.head->msg, mq.head->len);
-    if (debug_output) {
-      mq.head->msg[strlen(mq.head->msg) - 1] = 0; /* delete the "\n" */
-      putlog(LOG_SRVOUT, "*", "[s->] %s", mq.head->msg);
-    }
-    mq.tot--;
-    last_time += calc_penalty(mq.head->msg);
-    q = mq.head->next;
-    free(mq.head->msg);
-    free(mq.head);
-    mq.head = q;
-    if (!mq.head)
-      mq.last = NULL;
-    return;
-  }
-  /* Never send anything from the help queue unless everything else is
-   * finished.
-   */
-  if (!hq.head || burst || !ok)
-    return;
-  if (deq_kick(DP_HELP))
-    return;
-  if (fast_deq(DP_HELP))
-    return;
-  tputs(serv, hq.head->msg, hq.head->len);
-  if (debug_output) {
-    hq.head->msg[strlen(hq.head->msg) - 1] = 0; /* delete the "\n" */
-    putlog(LOG_SRVOUT, "*", "[h->] %s", hq.head->msg);
-  }
-  hq.tot--;
-  last_time += calc_penalty(hq.head->msg);
-  q = hq.head->next;
-  free(hq.head->msg);
-  free(hq.head);
-  hq.head = q;
-  if (!hq.head)
-    hq.last = NULL;
-}
-
-static int calc_penalty(char * msg)
-{
-  char *cmd, *par1, *par2, *par3;
-  register int penalty, i, ii;
-
-  if (use_penalties != 1 && use_penalties != 2)
-	  return 0;
-  if (msg[strlen(msg) - 1] == '\n')
-    msg[strlen(msg) - 1] = '\0';
-  cmd = newsplit(&msg);
-  if (msg)
-    i = strlen(msg);
-  else
-    i = strlen(cmd);
-  last_time -= 2; /* undo eggdrop standard flood prot */
-  if (use_penalties == 2) {
-    last_time += (2 + i / 120);
-    return 0;
-  }
-  penalty = (1 + i / 100);
-  if (!strcasecmp(cmd, "KICK")) {
-    par1 = newsplit(&msg); /* channel */
-    par2 = newsplit(&msg); /* victim(s) */
-    par3 = strtok(par2, ",");
-    while (par3) {
-      penalty++;
-      par3 = strtok(NULL, ",");
-    }
-    ii = penalty;
-    par3 = strtok(par1, " ");
-    while (par3) {
-      penalty += ii;
-      par3 = strtok(NULL, ",");
-    }
-  } else if (!strcasecmp(cmd, "MODE")) {
-    i = 0;
-    par1 = newsplit(&msg); /* channel */
-    par2 = newsplit(&msg); /* mode(s) */
-    if (!strlen(par2))
-      i++;
-    while (strlen(par2) > 0) {
-      if (strchr("ntimps", par2[0]))
-        i += 3;
-      else if (!strchr("+-", par2[0]))
-        i += 1;
-      par2++;
-    }
-    while (strlen(msg) > 0) {
-      newsplit(&msg);
-      i += 2;
-    }
-    ii = 0;
-    par3 = strtok(par1, ",");
-    while (par3) {
-      ii++;
-      par3 = strtok(NULL, ",");
-    }
-    penalty += (ii * i);
-  } else if (!strcasecmp(cmd, "TOPIC")) {
-    penalty++;
-    par1 = newsplit(&msg); /* channel */
-    par2 = newsplit(&msg); /* topic */
-    if (strlen(par2) > 0) {  /* topic manipulation => 2 penalty points */
-      par3 = strtok(par1, ",");
-      while (par3) {
-        penalty += 2;
-        strtok(NULL, ",");
-      }
-    }
-  } else if (!strcasecmp(cmd, "PRIVMSG") ||
-	     !strcasecmp(cmd, "NOTICE")) {
-    par1 = newsplit(&msg); /* channel(s)/nick(s) */
-    /* Add one sec penalty for each recipient */
-    par3 = strtok(par1, ",");
-    while (par3) {
-      penalty++;
-      par3 = strtok(NULL, ",");
-    }
-  } else if (!strcasecmp(cmd, "WHO")) {
-    par1 = newsplit(&msg); /* masks */
-    par2 = strtok(par1, ",");
-    while (par2) {
-      if (strlen(par2) > 4)   /* long WHO-masks receive less penalty */
-	penalty += 3;
-      else
-	penalty += 5;
-      par2 = strtok(NULL, ",");
-    }
-  } else if (!strcasecmp(cmd, "AWAY")) {
-    if (strlen(msg) > 0)
-      penalty += 2;
-    else
-      penalty += 1;
-  } else if (!strcasecmp(cmd, "INVITE")) {
-    /* Successful invite receives 2 or 3 penalty points. Let's go
-     * with the maximum.
-     */
-    penalty += 3;
-  } else if (!strcasecmp(cmd, "JOIN")) {
-    penalty += 2;
-  } else if (!strcasecmp(cmd, "PART")) {
-    penalty += 4;
-  } else if (!strcasecmp(cmd, "VERSION")) {
-    penalty += 2;
-  } else if (!strcasecmp(cmd, "TIME")) {
-    penalty += 2;
-  } else if (!strcasecmp(cmd, "TRACE")) {
-    penalty += 2;
-  } else if (!strcasecmp(cmd, "NICK")) {
-    penalty += 3;
-  } else if (!strcasecmp(cmd, "ISON")) {
-    penalty += 1;
-  } else if (!strcasecmp(cmd, "WHOIS")) {
-    penalty += 2;
-  } else if (!strcasecmp(cmd, "DNS")) {
-    penalty += 2;
-  } else
-    penalty++; /* just add standard-penalty */
-  /* Shouldn't happen, but you never know... */
-  if (penalty > 99)
-    penalty = 99;
-  if (penalty < 2) {
-    putlog(LOG_SRVOUT, "*", "Penalty < 2sec, that's impossible!");
-    penalty = 2;
-  }
-  if (debug_output && penalty != 0)
-    putlog(LOG_SRVOUT, "*", "Adding penalty: %i", penalty);
-  return penalty;
-}
-
-static int fast_deq(int which)
-{
-  struct msgq_head *h;
-  struct msgq *m, *nm;
-  char msgstr[511], nextmsgstr[511], tosend[511], victims[511], stackable[511],
-       *msg, *nextmsg, *cmd, *nextcmd, *to, *nextto, *stckbl;
-  int len, doit = 0, found = 0, who_count =0, stack_method = 1;
-
-  if (!use_fastdeq)
-    return 0;
-  switch (which) {
-    case DP_MODE:
-      h = &modeq;
-      break;
-    case DP_SERVER:
-      h = &mq;
-      break;
-    case DP_HELP:
-      h = &hq;
-      break;
-    default:
-      return 0;
-  }
-  m = h->head;
-  strlcpy(msgstr, m->msg, sizeof msgstr);
-  msg = msgstr;
-  cmd = newsplit(&msg);
-  if (use_fastdeq > 1) {
-    strlcpy(stackable, stackablecmds, sizeof stackable);
-    stckbl = stackable;
-    while (strlen(stckbl) > 0)
-      if (!strcasecmp(newsplit(&stckbl), cmd)) {
-        found = 1;
-        break;
-      }
-    /* If use_fastdeq is 2, only commands in the list should be stacked. */
-    if (use_fastdeq == 2 && !found)
-      return 0;
-    /* If use_fastdeq is 3, only commands that are _not_ in the list
-     * should be stacked.
-     */
-    if (use_fastdeq == 3 && found)
-      return 0;
-    /* we check for the stacking method (default=1) */
-    strlcpy(stackable, stackable2cmds, sizeof stackable);
-    stckbl = stackable;
-    while (strlen(stckbl) > 0)
-      if (!strcasecmp(newsplit(&stckbl), cmd)) {
-        stack_method = 2;
-        break;
-      }    
-  }
-  to = newsplit(&msg);
-  len = strlen(to);
-  if (to[len - 1] == '\n')
-    to[len -1] = 0;
-  simple_sprintf(victims, "%s", to);
-  while (m) {
-    nm = m->next;
-    if (!nm)
-      break;
-    strlcpy(nextmsgstr, nm->msg, sizeof nextmsgstr);
-    nextmsg = nextmsgstr;
-    nextcmd = newsplit(&nextmsg);
-    nextto = newsplit(&nextmsg);
-    len = strlen(nextto);
-    if (nextto[len - 1] == '\n')
-      nextto[len - 1] = 0;
-    if ( strcmp(to, nextto) /* we don't stack to the same recipients */
-        && !strcmp(cmd, nextcmd) && !strcmp(msg, nextmsg)
-        && ((strlen(cmd) + strlen(victims) + strlen(nextto)
-	     + strlen(msg) + 2) < 510)
-        && (strcasecmp(cmd, "WHO") || who_count < MAXPENALTY - 1)) {
-      if (!strcasecmp(cmd, "WHO"))
-        who_count++;
-      if (stack_method == 1)
-      	simple_sprintf(victims, "%s,%s", victims, nextto);
-      else
-      	simple_sprintf(victims, "%s %s", victims, nextto);
-      doit = 1;
-      m->next = nm->next;
-      if (!nm->next)
-        h->last = m;
-      free(nm->msg);
-      free(nm);
-      h->tot--;
-    } else
-      m = m->next;
-  }
-  if (doit) {
-    simple_sprintf(tosend, "%s %s %s", cmd, victims, msg);
-    len = strlen(tosend);
-    tosend[len - 1] = '\n';
-    tputs(serv, tosend, len);
-    m = h->head->next;
-    free(h->head->msg);
-    free(h->head);
-    h->head = m;
-    if (!h->head)
-      h->last = 0;
-    h->tot--;
-    if (debug_output) {
-      tosend[len - 1] = 0;
-      switch (which) {
-        case DP_MODE:
-          putlog(LOG_SRVOUT, "*", "[m=>] %s", tosend);
-          break;
-        case DP_SERVER:
-          putlog(LOG_SRVOUT, "*", "[s=>] %s", tosend);
-          break;
-        case DP_HELP:
-          putlog(LOG_SRVOUT, "*", "[h=>] %s", tosend);
-          break;
-      }
-    }
-    last_time += calc_penalty(tosend);
-    return 1;
-  }
-  return 0;
-}
-
-static void check_queues(char *oldnick, char *newnick)
-{
-  if (optimize_kicks == 2) {
-    if (modeq.head)
-      parse_q(&modeq, oldnick, newnick);
-    if (mq.head)
-      parse_q(&mq, oldnick, newnick);
-    if (hq.head)
-      parse_q(&hq, oldnick, newnick);
-  }
-}
-
-static void parse_q(struct msgq_head *q, char *oldnick, char *newnick)
-{
-  struct msgq *m, *lm = NULL;
-  char buf[511], *msg, *nicks, *nick, *chan, newnicks[511], newmsg[511];
-  int changed;
-
-  for (m = q->head; m;) {
-    changed = 0;
-    if (optimize_kicks == 2 && !strncasecmp(m->msg, "KICK ", 5)) {
-      newnicks[0] = 0;
-      strlcpy(buf, m->msg, sizeof buf);
-      if (buf[0] && (buf[strlen(buf)-1] == '\n'))
-	buf[strlen(buf)-1] = '\0';
-      msg = buf;
-      newsplit(&msg);
-      chan = newsplit(&msg);
-      nicks = newsplit(&msg);
-      nick = strtok(nicks, ",");
-      while (nick) {
-	if (!strcasecmp(nick, oldnick) &&
-	    ((9 + strlen(chan) + strlen(newnicks) + strlen(newnick) +
-	  strlen(nicks) + strlen(msg)) < 510)) {
-	  if (newnick)
-	    snprintf(newnicks, sizeof newnicks, "%s,%s", newnicks, newnick);
-	  changed = 1;
-	} else
-	  snprintf(newnicks, sizeof newnicks, ",%s", nick);
-	nick = strtok(NULL, ",");
-      }
-      snprintf(newmsg, sizeof newmsg, "KICK %s %s %s\n", chan,
-		   newnicks + 1, msg);
-    }
-    if (changed) {
-      if (newnicks[0] == 0) {
-	if (!lm)
-	  q->head = m->next;
-	else
-	  lm->next = m->next;
-	free(m->msg);
-	free(m);
-	m = lm;
-	q->tot--;
-	if (!q->head)
-	  q->last = 0;
-      } else {
-	free(m->msg);
-	m->msg = malloc(strlen(newmsg) + 1);
-	m->len = strlen(newmsg);
-	strcpy(m->msg, newmsg);
-      }
-    }
-    lm = m;
-    if (m)
-      m = m->next;
-    else
-      m = q->head;
-  }
-}
-
-static void purge_kicks(struct msgq_head *q)
-{
-  struct msgq *m, *lm = NULL;
-  char buf[511], *reason, *nicks, *nick, *chan, newnicks[511],
-       newmsg[511], chans[511], *chns, *ch;
-  int changed, found;
-  struct chanset_t *cs;
-
-  for (m = q->head; m;) {
-    if (!strncasecmp(m->msg, "KICK", 4)) {
-      newnicks[0] = 0;
-      changed = 0;
-      strlcpy(buf, m->msg, sizeof buf);
-      if (buf[0] && (buf[strlen(buf)-1] == '\n'))
-	buf[strlen(buf)-1] = '\0';
-      reason = buf;
-      newsplit(&reason);
-      chan = newsplit(&reason);
-      nicks = newsplit(&reason);
-      nick = strtok(nicks, ",");
-      while (nick) {
-	found = 0;
-	strlcpy(chans, chan, sizeof chans);
-	chns = chans;
-	while (strlen(chns) > 0) {
-	  ch = newsplit(&chns);
-	  cs = findchan(ch);
-	  if (!cs)
-	    continue;
-	  if (ismember(cs, nick))
-	    found = 1;
-	}
-	if (found)
-	  snprintf(newnicks, sizeof newnicks, "%s,%s", newnicks, nick);
-	else {
-	  putlog(LOG_SRVOUT, "*", "%s isn't on any target channel, removing "
-		 "kick...", nick);
-	  changed = 1;
-	}
-	nick = strtok(NULL, ",");
-      }
-      if (changed) {
-	if (newnicks[0] == 0) {
-	  if (!lm)
-	    q->head = m->next;
-	  else
-	    lm->next = m->next;
-	  free(m->msg);
-	  free(m);
-	  m = lm;
-	  q->tot--;
-	  if (!q->head)
-	    q->last = 0;
-	} else {
-	  free(m->msg);
-	  snprintf(newmsg, sizeof newmsg, "KICK %s %s %s\n", chan,
-		       newnicks + 1, reason);
-	  m->msg = malloc(strlen(newmsg) + 1);
-	  m->len = strlen(newmsg);
-	  strcpy(m->msg, newmsg);
-	}
-      }
-    }
-    lm = m;
-    if (m)
-      m = m->next;
-    else
-      m = q->head;
-  }
-}
-
-static int deq_kick(int which)
-{
-  struct msgq_head *h;
-  struct msgq *msg, *m, *lm;
-  char buf[511], buf2[511], *reason2, *nicks, *chan, *chan2, *reason, *nick,
-       newnicks[511], newnicks2[511], newmsg[511];
-  int changed = 0, nr = 0;
-
-  if (!optimize_kicks)
-    return 0;
-  newnicks[0] = 0;
-  switch (which) {
-    case DP_MODE:
-      h = &modeq;
-      break;
-    case DP_SERVER:
-      h = &mq;
-      break;
-    case DP_HELP:
-      h = &hq;
-      break;
-    default:
-      return 0;
-  }
-  if (strncasecmp(h->head->msg, "KICK", 4))
-    return 0;
-  if (optimize_kicks == 2) {
-    purge_kicks(h);
-    if (!h->head)
-      return 1;
-  }
-  if (strncasecmp(h->head->msg, "KICK", 4))
-    return 0;
-  msg = h->head;
-  strlcpy(buf, msg->msg, sizeof buf);
-  reason = buf;
-  newsplit(&reason);
-  chan = newsplit(&reason);
-  nicks = newsplit(&reason);
-  while (strlen(nicks) > 0) {
-    snprintf(newnicks, sizeof newnicks, "%s,%s", newnicks,
-		 newsplit(&nicks));
-    nr++;
-  }
-  for (m = msg->next, lm = NULL; m && (nr < kick_method);) {
-    if (!strncasecmp(m->msg, "KICK", 4)) {
-      changed = 0;
-      newnicks2[0] = 0;
-      strlcpy(buf2, m->msg, sizeof buf2);
-      if (buf2[0] && (buf2[strlen(buf2)-1] == '\n'))
-        buf2[strlen(buf2)-1] = '\0';
-      reason2 = buf2;
-      newsplit(&reason2);
-      chan2 = newsplit(&reason2);
-      nicks = newsplit(&reason2);
-      if (!strcasecmp(chan, chan2) && !strcasecmp(reason, reason2)) {
-        nick = strtok(nicks, ",");
-	while (nick) {
-          if ((nr < kick_method) &&
-             ((9 + strlen(chan) + strlen(newnicks) + strlen(nick) +
-             strlen(reason)) < 510)) {
-            snprintf(newnicks, sizeof newnicks, "%s,%s", newnicks, nick);
-            nr++;
-            changed = 1;
-          } else
-            snprintf(newnicks2, sizeof newnicks2, "%s,%s", newnicks2, nick);
-	  nick = strtok(NULL, ",");
-        }
-      }
-      if (changed) {
-        if (newnicks2[0] == 0) {
-          if (!lm)
-            h->head->next = m->next;
-          else
-            lm->next = m->next;
-          free(m->msg);
-          free(m);
-          m = lm;
-          h->tot--;
-          if (!h->head)
-            h->last = 0;
-        } else {
-          free(m->msg);
-          snprintf(newmsg, sizeof newmsg, "KICK %s %s %s\n", chan2,
-		       newnicks2 + 1, reason);
-          m->msg = malloc(strlen(newmsg) + 1);
-          m->len = strlen(newmsg);
-          strcpy(m->msg, newmsg);
-        }
-      }
-    }
-    lm = m;
-    if (m)
-      m = m->next;
-    else
-      m = h->head->next;
-  }
-  snprintf(newmsg, sizeof newmsg, "KICK %s %s %s\n", chan, newnicks + 1,
-	       reason);
-  tputs(serv, newmsg, strlen(newmsg));
-  if (debug_output) {
-    newmsg[strlen(newmsg) - 1] = 0;
-    switch (which) {
-      case DP_MODE:
-        putlog(LOG_SRVOUT, "*", "[m->] %s", newmsg);
-        break;
-      case DP_SERVER:
-        putlog(LOG_SRVOUT, "*", "[s->] %s", newmsg);
-        break;
-      case DP_HELP:
-        putlog(LOG_SRVOUT, "*", "[h->] %s", newmsg);
-        break;
-    }
-    debug3("Changed: %d, kick-method: %d, nr: %d", changed, kick_method, nr);
-  }
-  h->tot--;
-  last_time += calc_penalty(newmsg);
-  m = h->head->next;
-  free(h->head->msg);
-  free(h->head);
-  h->head = m;
-  if (!h->head)
-    h->last = 0;
-  return 1;
-}
-
-/* Clean out the msg queues (like when changing servers).
- */
-static void empty_msgq()
-{
-  msgq_clear(&modeq);
-  msgq_clear(&mq);
-  msgq_clear(&hq);
-  burst = 0;
-}
-
-/* Use when sending msgs... will spread them out so there's no flooding.
- */
-static void queue_server(int which, char *buf, int len)
-{
-  struct msgq_head *h = NULL,
-  		    tempq;
-  struct msgq	   *q;
-  int		    qnext = 0;
-
-  /* Don't even BOTHER if there's no server online. */
-  if (serv < 0)
-    return;
-  /* No queue for PING and PONG - drummer */
-  if (!strncasecmp(buf, "PING", 4) || !strncasecmp(buf, "PONG", 4)) {
-    if (buf[1] == 'I' || buf[1] == 'i')
-      lastpingtime = now;	/* lagmeter */
-    tputs(serv, buf, len);
-    return;
-  }
-
-  switch (which) {
-  case DP_MODE_NEXT:
-    qnext = 1;
-    /* Fallthrough */
-  case DP_MODE:
-    h = &modeq;
-    tempq = modeq;
-    break;
-
-  case DP_SERVER_NEXT:
-    qnext = 1;
-    /* Fallthrough */
-  case DP_SERVER:
-    h = &mq;
-    tempq = mq;
-    break;
-
-  case DP_HELP_NEXT:
-    qnext = 1;
-    /* Fallthrough */
-  case DP_HELP:
-    h = &hq;
-    tempq = hq;
-    break;
-
-  default:
-    putlog(LOG_MISC, "*", "!!! queuing unknown type to server!!");
-    return;
-  }
-
-  if (h->tot < maxqmsg) {
-    q = malloc(sizeof(struct msgq));
-    if (qnext)
-      q->next = h->head;
-    else
-      q->next = NULL;
-    if (h->head) {
-      if (!qnext)
-        h->last->next = q;
-    } else
-      h->head = q;
-    if (qnext)
-       h->head = q;
-    h->last = q;
-    q->len = len;
-    q->msg = malloc(len + 1);
-    strlcpy(q->msg, buf, len + 1);
-    h->tot++;
-    h->warned = 0;
-  } else {
-    if (!h->warned) {
-      switch (which) {   
-	case DP_MODE_NEXT:
- 	/* Fallthrough */
-	case DP_MODE:
-      putlog(LOG_MISC, "*", "!!! OVER MAXIMUM MODE QUEUE");
- 	break;
-    
-	case DP_SERVER_NEXT:
- 	/* Fallthrough */
- 	case DP_SERVER:
-	putlog(LOG_MISC, "*", "!!! OVER MAXIMUM SERVER QUEUE");
-	break;
-            
-	case DP_HELP_NEXT:
-	/* Fallthrough */
-	case DP_HELP:
-	putlog(LOG_MISC, "*", "!!! OVER MAXIMUM HELP QUEUE");
-	break;
-      }
-    }
-    h->warned = 1;
-  }
-
-  if (debug_output) {
-    if (buf[len - 1] == '\n')
-      buf[len - 1] = 0;
-    switch (which) {
-    case DP_MODE:
-      putlog(LOG_SRVOUT, "*", "[!m] %s", buf);
-      break;
-    case DP_SERVER:
-      putlog(LOG_SRVOUT, "*", "[!s] %s", buf);
-      break;
-    case DP_HELP:
-      putlog(LOG_SRVOUT, "*", "[!h] %s", buf);
-      break;
-    case DP_MODE_NEXT:
-      putlog(LOG_SRVOUT, "*", "[!!m] %s", buf);
-      break;
-    case DP_SERVER_NEXT:
-      putlog(LOG_SRVOUT, "*", "[!!s] %s", buf);
-      break;
-    case DP_HELP_NEXT:
-      putlog(LOG_SRVOUT, "*", "[!!h] %s", buf);
-      break;
-    }
-  }
-
-  if (which == DP_MODE || which == DP_MODE_NEXT)
-    deq_msg();		/* DP_MODE needs to be sent ASAP, flush if
-			   possible. */
-}
-
-/* Free a server struct and its associated data. */
-static void server_destroy(struct server_list *ptr)
-{
-	if (ptr->name) free(ptr->name);
-	if (ptr->realname) free(ptr->realname);
-	if (ptr->pass) free(ptr->pass);
-	free(ptr);
-}
-
-/* Add a server to the server list. */
-static int server_add(char *host, int port, char *pass)
-{
-	struct server_list *serv, *listend;
-
-	if (!port) port = default_port;
-
-	/* Go to the end of the serverlist. */
-	for (listend = serverlist; listend && listend->next; listend = listend->next) {
-		; /* empty */
-	}
-
-	serv = (struct server_list *)calloc(1, sizeof(*serv));
-	serv->name = strdup(host);
-	serv->port = port;
-	if (pass) serv->pass = strdup(pass);
-
-	if (listend) listend->next = serv;
-	else serverlist = serv;
-
-	return(0);
-}
-
-/* Remove a server from the server list based on its index. */
-static int server_del(int num)
-{
-	struct server_list *cur, *prev;
-	int i;
-
-	prev = NULL;
-	i = 0;
-	for (cur = serverlist; cur; cur = cur->next) {
-		if (i == num) break;
-		prev = cur;
-		i++;
-	}
-	if (i != num) return(-1);
-
-	if (prev) prev->next = cur->next;
-	else serverlist = cur->next;
-
-	server_destroy(cur);
-
-	return(0);
-}
-
-/* Clear out the server list. */
-static int server_clear()
-{
-	struct server_list *cur, *next;
-
-	for (cur = serverlist; cur; cur = next) {
-		next = cur->next;
-		server_destroy(cur);
-	}
-	serverlist = NULL;
-	return(0);
-}
-
-struct server_list *server_get_current()
-{
-	struct server_list *serv;
-	int i;
-
-	serv = serverlist;
-	for (i = curserv; i > 0 && serv; i--) {
-		serv = serv->next;
-	}
-	return(serv);
-}
-
-/* Set botserver to the next available server.
- *
- * -> if (*ptr == -1) then jump to that particular server
- */
-static void next_server(int *ptr, char *serv, unsigned int *port, char *pass)
-{
-  struct server_list *x = serverlist;
-  int i = 0;
-
-  if (x == NULL)
-    return;
-  /* -1  -->  Go to specified server */
-  if (*ptr == (-1)) {
-    for (; x; x = x->next) {
-      if (x->port == *port) {
-	if (!strcasecmp(x->name, serv)) {
-	  *ptr = i;
-	  return;
-	}
-      }
-      i++;
-    }
-    /* Gotta add it: */
-    x = malloc(sizeof(struct server_list));
-
-    x->next = 0;
-    x->realname = 0;
-    x->name = strdup(serv);
-    x->port = *port ? *port : default_port;
-    if (pass && pass[0])
-      x->pass = strdup(pass);
-    else
-      x->pass = NULL;
-    list_append((struct list_type **) (&serverlist), (struct list_type *) x);
-    *ptr = i;
-    return;
-  }
-  /* Find where i am and boogie */
-  i = (*ptr);
-  while (i > 0 && x != NULL) {
-    x = x->next;
-    i--;
-  }
-  if (x != NULL) {
-    x = x->next;
-    (*ptr)++;
-  }				/* Go to next server */
-  if (x == NULL) {
-    x = serverlist;
-    *ptr = 0;
-  }				/* Start over at the beginning */
-  strcpy(serv, x->name);
-  *port = x->port ? x->port : default_port;
-  if (x->pass)
-    strcpy(pass, x->pass);
-  else
-    pass[0] = 0;
-}
-
-/* Read/write normal string variable.
- */
-static char *nick_change(ClientData cdata, Tcl_Interp *irp, char *name1,
-			 char *name2, int flags)
-{
-  char *new;
-
-  if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
-    Tcl_SetVar2(interp, name1, name2, origbotname, TCL_GLOBAL_ONLY);
-    if (flags & TCL_TRACE_UNSETS)
-      Tcl_TraceVar(irp, name1, TCL_TRACE_READS | TCL_TRACE_WRITES |
-        	   TCL_TRACE_UNSETS, nick_change, cdata);
-  } else {			/* writes */
-    new = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY);
-    if (irccmp(origbotname, new)) {
-      if (origbotname[0]) {
-	putlog(LOG_MISC, "*", "* IRC NICK CHANGE: %s -> %s",
-	       origbotname, new);
-        nick_juped = 0;
-      }
-      strlcpy(origbotname, new, NICKLEN);
-      if (server_online)
-	dprintf(DP_SERVER, "NICK %s\n", origbotname);
-    }
-  }
-  return NULL;
-}
-
-/* Replace all '?'s in s with a random number.
- */
-static void rand_nick(char *nick)
-{
-  register char *p = nick;
-
-  while ((p = strchr(p, '?')) != NULL) {
-    *p = '0' + random() % 10;
-    p++;
-  }
-}
-
-/* Return the alternative bot nick.
- */
-static char *get_altbotnick(void)
-{
-	/* Generate a new one if necessary. */
-	if (!raltnick) {
-		raltnick = strdup(altnick);
-		rand_nick(raltnick);
-	}
-	return raltnick;
-}
-
-static tcl_strings my_tcl_strings[] =
-{
-  {"realname",			botrealname,	80,		0},
-  {"stackable_commands",	stackablecmds,	510,		0},
-  {"stackable2_commands",	stackable2cmds,	510,		0},
-  {NULL,			NULL,		0,		0}
-};
-
-static tcl_coups my_tcl_coups[] =
-{
-  {"flood_msg",		&flud_thr,		&flud_time},
-  {"flood_ctcp",	&flud_ctcp_thr, 	&flud_ctcp_time},
-  {NULL,		NULL,			NULL}
+static server_config_t default_config = {
+	0,	/* trigger on ignore */
+	0,	/* keepnick */
+	30,	/* connect_timeout */
+	10,	/* cycle delay */
+	6667,	/* default port */
+	30,	/* ping timeout */
+	NULL,	/* user */
+	NULL,	/* real name */
 };
 
-static tcl_ints my_tcl_ints[] =
-{
-  {"server_timeout",		&server_timeout,		0},
-  {"server_online",		(int *) &server_online,		2},
-  {"keep_nick",			&keepnick,			0},
-  {"check_stoned",		&check_stoned,			0},
-  {"quiet_reject",		&quiet_reject,			0},
-  {"max_queue_msg",		&maxqmsg,			0},
-  {"trigger_on_ignore",		&trigger_on_ignore,		0},
-  {"answer_ctcp",		&answer_ctcp,			0},
-  {"server_cycle_wait",		(int *) &server_cycle_wait,	0},
-  {"default_port",		&default_port,			0},
-  {"check_mode_r",		&check_mode_r,			0},
-  {"ctcp_mode",			&ctcp_mode,			0},
-  {"use_penalties",		&use_penalties,			0},
-  {"use_fastdeq",		&use_fastdeq,			0},
-  {"nicklen",                   &nick_len,                      0},
-  /* FIXME: remove this later ... before first stable release */
-  {"nick-len",			&nick_len,			0},
-  {"optimize_kicks",		&optimize_kicks,		0},
-  {"isjuped",			&nick_juped,			0},
-  {NULL,			NULL,				0}
-}; 
-
+current_server_t current_server = {0};
+server_config_t config = {0};
 
-/*
- *     CTCP DCC CHAT functions
- */
+int cycle_delay = 0;
 
-static void dcc_chat_hostresolved(int);
+/* From scriptcmds.c */
+extern script_linked_var_t server_script_vars[];
+extern script_command_t server_script_cmds[];
 
-/* This only handles CHAT requests, otherwise it's handled in filesys.
- */
-static int ctcp_DCC_CHAT(char *nick, char *from, struct userrec *u,
-			 char *object, char *keyword, char *text)
-{
-  char *action, *param, *ip, *prt, buf[512], *msg = buf;
-  int i;
-  struct flag_record fr = {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0};
-  unsigned long ipnum;
-  char ipbuf[32];
-
-  strcpy(msg, text);
-  action = newsplit(&msg);
-  param = newsplit(&msg);
-  ip = newsplit(&msg);
-  prt = newsplit(&msg);
-
-  /* Convert to a real ip address. */
-  ipnum = strtoul(ip, NULL, 10);
-  ipnum = htonl(ipnum);
-  inet_ntop(AF_INET, &ipnum, ipbuf, sizeof(ipbuf));
-  ip = ipbuf;
-
-  if (strcasecmp(action, "CHAT") || strcasecmp(object, botname) || !u)
-    return 0;
-  get_user_flagrec(u, &fr, 0);
-  if (dcc_total == max_dcc) {
-    if (!quiet_reject)
-      dprintf(DP_HELP, "NOTICE %s :%s\n", nick, _("Sorry, too many DCC connections."));
-    putlog(LOG_MISC, "*", _("DCC connections full: %s %s (%s!%s)"), "CHAT", param, nick, from);
-  } else if (!glob_party(fr)) {
-    if (glob_xfer(fr))
-      return 0;			/* Allow filesys to pick up the chat */
-    if (!quiet_reject)
-      dprintf(DP_HELP, "NOTICE %s :%s\n", nick, _("No access"));
-    putlog(LOG_MISC, "*", "%s: %s!%s", _("Refused DCC chat (no access)"), nick, from);
-  } else if (u_pass_match(u, "-")) {
-    if (!quiet_reject)
-      dprintf(DP_HELP, "NOTICE %s :%s\n", nick, _("You must have a password set."));
-    putlog(LOG_MISC, "*", "%s: %s!%s", _("Refused DCC chat (no password)"), nick, from);
-  } else if (atoi(prt) < 1024 || atoi(prt) > 65535) {
-    /* Invalid port */
-    if (!quiet_reject)
-      dprintf(DP_HELP, "NOTICE %s :%s (invalid port)\n", nick,
-	      _("Failed to connect"));
-    putlog(LOG_MISC, "*", "%s: CHAT (%s!%s)", _("DCC invalid port"),
-	   nick, from);
-  } else {
-    i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
-    if (i < 0) {
-      putlog(LOG_MISC, "*", "DCC connection: CHAT (%s!%s)", dcc[i].nick, ip);
-      return 1;
-    }
-debug1("|SERVER| dcc chat ip: (%s)", ip);
-    strlcpy(dcc[i].addr, ip, ADDRLEN);
-debug1("|SERVER| addr: (%s)", dcc[i].addr);
-    dcc[i].port = atoi(prt);
-    dcc[i].sock = -1;
-    strcpy(dcc[i].nick, u->handle);
-    strcpy(dcc[i].host, from);
-    dcc[i].timeval = now;
-    dcc[i].user = u;
-    dcc[i].u.dns->host = calloc(1, strlen(dcc[i].addr) + 1);
-    strcpy(dcc[i].u.dns->host, dcc[i].addr);
-    dcc[i].u.dns->dns_type = RES_HOSTBYIP;
-    dcc[i].u.dns->dns_success = dcc_chat_hostresolved;
-    dcc[i].u.dns->dns_failure = dcc_chat_hostresolved;
-    dcc[i].u.dns->type = &DCC_CHAT_PASS;
-    dcc_dnshostbyip(dcc[i].addr);
-  }
-  return 1;
-}
+/* From servsock.c */
+extern void connect_to_next_server();
 
-static void dcc_chat_hostresolved(int i)
-{
-  char buf[512];
-  struct flag_record fr = {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0};
+/* From output.c */
+extern void dequeue_messages();
 
-  snprintf(buf, sizeof buf, "%d", dcc[i].port);
-  dcc[i].sock = getsock(0);
-  if (dcc[i].sock < 0 ||
-          open_telnet_dcc(dcc[i].sock, dcc[i].addr, buf) < 0) {
-    neterror(buf);
-    if(!quiet_reject)
-      dprintf(DP_HELP, "NOTICE %s :%s (%s)\n", dcc[i].nick,
-	      _("Failed to connect"), buf);
-    putlog(LOG_MISC, "*", "%s: CHAT (%s!%s)", _("DCC connection failed"),
-	   dcc[i].nick, dcc[i].host);
-    putlog(LOG_MISC, "*", "    (%s)", buf);
-    killsock(dcc[i].sock);
-    lostdcc(i);
-  } else {
-    changeover_dcc(i, &DCC_CHAT_PASS, sizeof(struct chat_info));
-    dcc[i].status = STAT_ECHO;
-    get_user_flagrec(dcc[i].user, &fr, 0);
-    if (glob_party(fr))
-      dcc[i].status |= STAT_PARTY;
-    strcpy(dcc[i].u.chat->con_chan, (chanset) ? chanset->dname : "*");
-    dcc[i].timeval = now;
-    /* Ok, we're satisfied with them now: attempt the connect */
-    putlog(LOG_MISC, "*", "DCC connection: CHAT (%s!%s)", dcc[i].nick,
-	   dcc[i].host);
-    dprintf(i, "%s\n", _("Enter your password."));
-  }
-  return;
-}
+/* From input.c */
+extern cmd_t my_new_raw_binds[];
 
+/* From dcc_cmd.c */
+extern cmd_t my_dcc_commands[];
 
-/*
- *     Server timer functions
- */
+/* Every second, we want to
+ * 1. See if we're ready to connect to the next server (cycle_delay == 0)
+ * 2. Dequeue some messages if we're connected. */
 
 static void server_secondly()
 {
-  if (cycle_time)
-    cycle_time--;
-  deq_msg();
-  if (!resolvserv && serv < 0)
-    connect_server();
-}
-
-static void server_5minutely()
-{
-  if (check_stoned && server_online) {
-    if (waiting_for_awake) {
-      /* Uh oh!  Never got pong from last time, five minutes ago!
-       * Server is probably stoned.
-       */
-      disconnect_server();
-      putlog(LOG_SERV, "*", _("Server got stoned; jumping..."));
-    } else if (!trying_server) {
-	/* Check for server being stoned. */
-	dprintf(DP_MODE, "PING :%u %u\n", (egg_timeval_now).sec, (egg_timeval_now).usec);
-	waiting_for_awake = 1;
-    }
-  }
-}
-
-static void server_prerehash()
-{
-	str_redup(&oldnick, botname);
-}
-
-static void server_postrehash()
-{
-  str_redup(&botname, origbotname);
-  if (!botname[0])
-    fatal("NO BOT NAME.", 0);
-  if (serverlist == NULL)
-    fatal("NO SERVER.", 0);
-  if (oldnick && !irccmp(oldnick, botname)
-       && !irccmp(oldnick, get_altbotnick())) {
-    /* Change botname back, don't be premature. */
-    str_redup(&botname, oldnick);
-    dprintf(DP_SERVER, "NICK %s\n", origbotname);
-  }
-  /* Change botname back incase we were using altnick previous to rehash. */
-  else if (oldnick) str_redup(&botname, oldnick);
-  check_bind_event("init-server");
-}
+	if (current_server.idx < 0 && cycle_delay >= 0) {
+		/* If there's no idx, see if it's time to jump to the next
+		 * server. */
+		cycle_delay--;
+		if (cycle_delay <= 0) {
+			cycle_delay = -1;
+			connect_to_next_server();
+		}
+		return;
+	}
 
-static void server_die()
-{
-  cycle_time = 100;
-  if (server_online) {
-    dprintf(-serv, "QUIT :%s\n", quit_msg[0] ? quit_msg : "");
-    sleep(3); /* Give the server time to understand */
-  }
-  nuke_server(NULL);
+	/* Try to dequeue some stuff. */
+	dequeue_messages();
 }
 
-/* A report on the module status.
- */
+/* A report on the module status.  */
 static void server_report(int idx, int details)
 {
-  char s1[64], s[128];
+	if (!current_server.connected) {
+		if (current_server.idx >= 0) {
+			dprintf(idx, "   Connecting to server %s:%d\n", current_server.server_host, current_server.port);
+		}
+		else {
+			dprintf(idx, "   Connecting to next server in %d seconds\n", cycle_delay);
+		}
+	}
+	else {
+		/* First line, who we've connected to. */
+		dprintf(idx, "   Connected to %s:%d\n", current_server.server_self ? current_server.server_self : current_server.server_host, current_server.port);
 
-  if (server_online) {
-    dprintf(idx, "    Online as: %s%s%s (%s)\n", botname,
-        botuserhost[0] ? "!" : "", botuserhost[0] ? botuserhost : "",
-	botrealname);
-    if (nick_juped)
-	dprintf(idx, "    NICK IS JUPED: %s %s\n", origbotname,
-		keepnick ? "(trying)" : "");
-    nick_juped = 0;	/* WHY?? -- drummer */
-
-    daysdur(now, server_online, s1);
-    snprintf(s, sizeof s, "(connected %s)", s1);
-    if (!(waiting_for_awake)) {
-	sprintf(s1, "(lag: %d.%02d sec)", server_lag.sec, server_lag.usec/10000);
-	strcat(s, s1);
-    }
-  }
-  if ((trying_server || server_online) &&
-          (servidx != (-1))) {
-    dprintf(idx, "    Server %s %d %s\n", dcc[servidx].host, dcc[servidx].port,
-	    trying_server ? "(trying)" : s);
-  } else
-    dprintf(idx, "    %s\n", _("No server currently."));
-  if (modeq.tot)
-    dprintf(idx, "    %s %d%%, %d msgs\n", _("Mode queue is at"),
-            (int) ((float) (modeq.tot * 100.0) / (float) maxqmsg),
-	    (int) modeq.tot);
-  if (mq.tot)
-    dprintf(idx, "    %s %d%%, %d msgs\n", _("Server queue is at"),
-           (int) ((float) (mq.tot * 100.0) / (float) maxqmsg), (int) mq.tot);
-  if (hq.tot)
-    dprintf(idx, "    %s %d%%, %d msgs\n", _("Help queue is at"),
-           (int) ((float) (hq.tot * 100.0) / (float) maxqmsg), (int) hq.tot);
-  if (details) {
-    dprintf(idx, "    Flood is: %d msg/%ds, %d ctcp/%ds\n",
-	    flud_thr, flud_time, flud_ctcp_thr, flud_ctcp_time);
-  }
+		/* Second line, who we're connected as. */
+		if (current_server.registered) {
+			if (current_server.user) {
+				dprintf(idx, "    Online as %s!%s@%s (%s)\n", current_server.nick, current_server.user, current_server.host, current_server.real_name);
+			}
+			else {
+				dprintf(idx, "    Online as %s (still waiting for WHOIS result)\n", current_server.nick);
+			}
+		}
+		else {
+			dprintf(idx, "   Still logging in\n");
+		}
+	}
 }
 
-static void msgq_clear(struct msgq_head *qh)
+static char *server_close()
 {
-  register struct msgq	*q, *qq;
+	kill_server("Server module unloading");
+	cycle_delay = 100;
 
-  for (q = qh->head; q; q = qq) {
-    qq = q->next;
-    free(q->msg);
-    free(q);
-  }
-  qh->head = qh->last = NULL;
-  qh->tot = qh->warned = 0;
-}
+	rem_builtins("newraw", my_new_raw_binds);
 
-static cmd_t my_ctcps[] =
-{
-  {"DCC",	"",	ctcp_DCC_CHAT,		"server:DCC"},
-  {NULL,	NULL,	NULL,			NULL}
-};
+	server_binds_destroy();
 
-static char *server_close()
-{
-  cycle_time = 100;
-  nuke_server("Connection reset by peer");
-  server_clear();
-
-  rem_builtins("dcc", C_dcc_serv);
-  rem_builtins("raw", my_raw_binds);
-  rem_builtins("newraw", my_new_raw_binds);
-  rem_builtins("ctcp", my_ctcps);
-
-  bind_table_del(BT_wall);
-  bind_table_del(BT_raw);
-  bind_table_del(BT_new_raw);
-  bind_table_del(BT_notice);
-  bind_table_del(BT_msgm);
-  bind_table_del(BT_msg);
-  bind_table_del(BT_pubm);
-  bind_table_del(BT_pub);
-  bind_table_del(BT_flood);
-  bind_table_del(BT_ctcr);
-  bind_table_del(BT_ctcp);
-  rem_tcl_coups(my_tcl_coups);
-  rem_tcl_strings(my_tcl_strings);
-  rem_tcl_ints(my_tcl_ints);
-  rem_help_reference("server.help");
-  script_delete_commands(server_script_cmds);
-  script_unlink_vars(server_script_vars);
-  Tcl_UntraceVar(interp, "nick",
-		 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
-		 nick_change, NULL);
-  empty_msgq();
-  del_hook(HOOK_SECONDLY, (Function) server_secondly);
-  del_hook(HOOK_5MINUTELY, (Function) server_5minutely);
-  del_hook(HOOK_QSERV, (Function) queue_server);
-  del_hook(HOOK_MINUTELY, (Function) minutely_checks);
-  del_hook(HOOK_PRE_REHASH, (Function) server_prerehash);
-  del_hook(HOOK_REHASH, (Function) server_postrehash);
-  del_hook(HOOK_DIE, (Function) server_die);
-  module_undepend(MODULE_NAME);
-  return NULL;
+	script_delete_commands(server_script_cmds);
+	script_unlink_vars(server_script_vars);
+	del_hook(HOOK_SECONDLY, (Function) server_secondly);
+	return(NULL);
 }
 
 EXPORT_SCOPE char *start();
@@ -1412,156 +119,38 @@
   (Function) server_close,
   (Function) 0,
   (Function) server_report,
-  /* 4 - 7 */
-  (Function) NULL,		/* char * (points to botname later on)	*/
-  (Function) botuserhost,	/* char *				*/
-  (Function) & quiet_reject,	/* int					*/
-  (Function) & serv,		/* int					*/
-  /* 8 - 11 */
-  (Function) & flud_thr,	/* int					*/
-  (Function) & flud_time,	/* int					*/
-  (Function) & flud_ctcp_thr,	/* int					*/
-  (Function) & flud_ctcp_time,	/* int					*/
-  /* 12 - 15 */
-  (Function) match_my_nick,
-  (Function) check_tcl_flud,
-  (Function) NULL,		/* fixfrom - moved to the core (drummer) */
-  (Function) & answer_ctcp,	/* int					*/
-  /* 16 - 19 */
-  (Function) & trigger_on_ignore, /* int				*/
-  (Function) check_tcl_ctcpr,
-  (Function) 0,
-  (Function) nuke_server,
-  /* 20 - 23 */
-  (Function) newserver,		/* char *				*/
-  (Function) & newserverport,	/* int					*/
-  (Function) newserverpass,	/* char *				*/
-  /* 24 - 27 */
-  (Function) & cycle_time,	/* int					*/
-  (Function) & default_port,	/* int					*/
-  (Function) & server_online,	/* int					*/
-  (Function) &servidx,		/* int, server's idx			*/
-  /* 28 - 31 */
-  (Function) 0,		/* p_tcl_bind_list			*/
-  (Function) 0,		/* p_tcl_bind_list			*/
-  (Function) 0,		/* p_tcl_bind_list			*/
-  (Function) 0,		/* p_tcl_bind_list			*/
-  /* 32 - 35 */
-  (Function) 0,		/* p_tcl_bind_list			*/
-  (Function) 0,		/* p_tcl_bind_list			*/
-  (Function) 0,		/* p_tcl_bind_list			*/
-  (Function) 0,		/* p_tcl_bind_list			*/
-  /* 36 - 39 */
-  (Function) ctcp_reply,
-  (Function) get_altbotnick,	/* char *				*/
-  (Function) & nick_len,	/* int					*/
-  (Function) check_tcl_notc
 };
 
 char *start(eggdrop_t *eggdrop)
 {
-  char *s;
+	cmd_t *cmd;
+	egg = eggdrop;
+
+	/* Let's wait for the new config system before we redo all this mess. */
+	memcpy(&config, &default_config, sizeof(config));
+
+	memset(&current_server, 0, sizeof(current_server));
+	current_server.idx = -1;
+	cycle_delay = 0;
+
+	module_register(MODULE_NAME, server_table, 1, 2);
+	if (!module_depend(MODULE_NAME, "eggdrop", 107, 0)) {
+		module_undepend(MODULE_NAME);
+		return "This module requires eggdrop1.7.0 or later";
+	}
+
+	/* Create our bind tables. */
+	server_binds_init();
+
+	for (cmd = my_dcc_commands; cmd->name; cmd++) {
+		putlog(LOG_MISC, "*", "Making bind: %s", cmd->name);
+	}
+	add_builtins("newraw", my_new_raw_binds);
+	//add_builtins("dcc", my_dcc_commands);
 
-  egg = eggdrop;
+	script_create_commands(server_script_cmds);
+	script_link_vars(server_script_vars);
+	add_hook(HOOK_SECONDLY, (Function) server_secondly);
 
-  /*
-   * Init of all the variables *must* be done in _start rather than
-   * globally.
-   */
-  serv = -1;
-  servidx = -1;
-  strict_host = 1;
-  botname = strdup("");
-  trying_server = 0L;
-  memset(&server_lag, 0, sizeof(server_lag));
-  altnick = strdup("egg??????");
-  raltnick = NULL;
-  curserv = 0;
-  flud_thr = 5;
-  flud_time = 60;
-  flud_ctcp_thr = 3;
-  flud_ctcp_time = 60;
-  botuserhost[0] = 0;
-  keepnick = 1;
-  check_stoned = 1;
-  quiet_reject = 1;
-  waiting_for_awake = 0;
-  server_online = 0;
-  server_cycle_wait = 60;
-  strcpy(botrealname, "A deranged product of evil coders");
-  server_timeout = 60;
-  serverlist = NULL;
-  cycle_time = 0;
-  default_port = 6667;
-  oldnick = NULL;
-  trigger_on_ignore = 0;
-  answer_ctcp = 1;
-  check_mode_r = 0;
-  maxqmsg = 300;
-  burst = 0;
-  use_penalties = 0;
-  use_fastdeq = 0;
-  stackablecmds[0] = 0;
-  strcpy(stackable2cmds, "USERHOST ISON");
-  resolvserv = 0;
-  lastpingtime = 0;
-  last_time = 0;
-  nick_len = 9;
-  kick_method = 1;
-  optimize_kicks = 0;
-
-  server_table[4] = (Function) botname;
-  module_register(MODULE_NAME, server_table, 1, 2);
-  if (!module_depend(MODULE_NAME, "eggdrop", 107, 0)) {
-    module_undepend(MODULE_NAME);
-    return "This module requires eggdrop1.7.0 or later";
-  }
-
-  /* Fool bot in reading the values. */
-  s = Tcl_GetVar(interp, "nick", TCL_GLOBAL_ONLY);
-  if (s) strlcpy(origbotname, s, NICKLEN);
-  Tcl_TraceVar(interp, "nick",
-	       TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
-	       nick_change, NULL);
-
-	/* Create our own bind tables. */
-	BT_wall = bind_table_add("wall", 2, "ss", MATCH_MASK, BIND_STACKABLE);
-	BT_raw = bind_table_add("raw", 3, "sss", MATCH_MASK, BIND_STACKABLE);
-	BT_new_raw = bind_table_add("newraw", 6, "ssUsiS", MATCH_MASK, BIND_STACKABLE);
-	BT_notice = bind_table_add("notice", 5, "ssUss", MATCH_MASK, BIND_USE_ATTR | BIND_STACKABLE);
-	BT_msg = bind_table_add("msg", 4, "ssUs", 0, BIND_USE_ATTR);
-	BT_msgm = bind_table_add("msgm", 4, "ssUs", MATCH_MASK, BIND_USE_ATTR | BIND_STACKABLE);
-	BT_pub = bind_table_add("pub", 5, "ssUss", 0, BIND_USE_ATTR);
-	BT_pubm = bind_table_add("pubm", 5, "ssUss", MATCH_MASK, BIND_STACKABLE | BIND_USE_ATTR);
-	BT_flood = bind_table_add("flood", 5, "ssUss", MATCH_MASK, BIND_STACKABLE);
-	BT_ctcr = bind_table_add("ctcr", 6, "ssUsss", MATCH_MASK, BIND_USE_ATTR | BIND_STACKABLE);
-	BT_ctcp = bind_table_add("ctcp", 6, "ssUsss", MATCH_MASK, BIND_USE_ATTR | BIND_STACKABLE);
-
-  add_builtins("raw", my_raw_binds);
-  add_builtins("newraw", my_new_raw_binds);
-  add_builtins("ctcp", my_ctcps);
-  add_builtins("dcc", C_dcc_serv);
-
-  add_help_reference("server.help");
-  add_tcl_strings(my_tcl_strings);
-  add_tcl_ints(my_tcl_ints);
-  script_create_commands(server_script_cmds);
-  server_script_vars[3].value = &botname;
-  script_link_vars(server_script_vars);
-  add_tcl_coups(my_tcl_coups);
-  add_hook(HOOK_SECONDLY, (Function) server_secondly);
-  add_hook(HOOK_5MINUTELY, (Function) server_5minutely);
-  add_hook(HOOK_MINUTELY, (Function) minutely_checks);
-  add_hook(HOOK_QSERV, (Function) queue_server);
-  add_hook(HOOK_PRE_REHASH, (Function) server_prerehash);
-  add_hook(HOOK_REHASH, (Function) server_postrehash);
-  add_hook(HOOK_DIE, (Function) server_die);
-  mq.head = hq.head = modeq.head = NULL;
-  mq.last = hq.last = modeq.last = NULL;
-  mq.tot = hq.tot = modeq.tot = 0;
-  mq.warned = hq.warned = modeq.warned = 0;
-  newserver[0] = 0;
-  newserverport = 0;
-  curserv = 999;
-  return NULL;
+	return(NULL);
 }
Index: eggdrop1.7/modules/server/server.h
diff -u eggdrop1.7/modules/server/server.h:1.7 eggdrop1.7/modules/server/server.h:1.8
--- eggdrop1.7/modules/server/server.h:1.7	Tue May 28 15:36:06 2002
+++ eggdrop1.7/modules/server/server.h	Thu Sep 19 21:06:25 2002
@@ -1,94 +1,36 @@
-/*
- * server.h --
- */
-/*
- * Copyright (C) 1997 Robey Pointer
- * Copyright (C) 1999, 2000, 2001, 2002 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.
- */
-/*
- * $Id: server.h,v 1.7 2002/05/28 20:36:06 stdarg Exp $
- */
-
-#ifndef _EGG_MOD_SERVER_SERVER_H
-#define _EGG_MOD_SERVER_SERVER_H
-
-#define check_tcl_ctcp(a,b,c,d,e,f) check_tcl_ctcpr(a,b,c,d,e,f,BT_ctcp)
-#define check_tcl_ctcr(a,b,c,d,e,f) check_tcl_ctcpr(a,b,c,d,e,f,BT_ctcr)
-
-#define fixcolon(x)             do {                                    \
-        if ((x)[0] == ':')                                              \
-                (x)++;                                                  \
-        else                                                            \
-                (x) = newsplit(&(x));                                   \
-} while (0)
-
-#ifndef MAKING_SERVER
-/* 4 - 7 */
-#define botuserhost ((char *)(server_funcs[5]))
-#define quiet_reject (*(int *)(server_funcs[6]))
-#define serv (*(int *)(server_funcs[7]))
-/* 8 - 11 */
-#define flud_thr (*(int*)(server_funcs[8]))
-#define flud_time (*(int*)(server_funcs[9]))
-#define flud_ctcp_thr (*(int*)(server_funcs[10]))
-#define flud_ctcp_time (*(int*)(server_funcs[11]))
-/* 12 - 15 */
-#define match_my_nick ((int(*)(char *))server_funcs[12])
-#define check_tcl_flud ((int (*)(char *,char *,struct userrec *,char *,char *))server_funcs[13])
-/* #define fixfrom ((void (*)(char *))server_funcs[14]) -- moved to core */
-#define answer_ctcp (*(int *)(server_funcs[15]))
-/* 16 - 19 */
-#define trigger_on_ignore (*(int *)(server_funcs[16]))
-#define check_tcl_ctcpr ((int(*)(char*,char*,struct userrec*,char*,char*,char*,bind_table_t *))server_funcs[17])
-/* #define detect_avalanche ((int(*)(char *))server_funcs[18]) -- removed useless feature */
-#define nuke_server ((void(*)(char *))server_funcs[19])
-/* 20 - 22 */
-#define newserver ((char *)(server_funcs[20]))
-#define newserverport (*(int *)(server_funcs[21]))
-#define newserverpass ((char *)(server_funcs[22]))
-/* 23 - 26 */
-#define cycle_time (*(int *)(server_funcs[23]))
-#define default_port (*(int *)(server_funcs[24]))
-#define server_online (*(int *)(server_funcs[25]))
-#define servidx (*(int *)(server_funcs[26]))
-/* 27 - 30 */
-#define H_raw (*(p_tcl_bind_list *)(server_funcs[27]))
-#define H_wall (*(p_tcl_bind_list *)(server_funcs[28]))
-#define H_msg (*(p_tcl_bind_list *)(server_funcs[29]))
-#define H_msgm (*(p_tcl_bind_list *)(server_funcs[30]))
-/* 31 - 34 */
-#define H_notc (*(p_tcl_bind_list *)(server_funcs[31]))
-#define H_flud (*(p_tcl_bind_list *)(server_funcs[32]))
-/* #define H_ctcp (*(p_tcl_bind_list *)(server_funcs[33])) */
-/* #define H_ctcr (*(p_tcl_bind_list *)(server_funcs[34])) */
-/* 35 - 38 */
-#define ctcp_reply ((char *)(server_funcs[35]))
-#define get_altbotnick ((char *(*)(void))(server_funcs[36]))
-#define nick_len (*(int *)(server_funcs[37]))
-#define check_tcl_notc ((int (*)(char *,char *,struct userrec *,char *,char *))server_funcs[38])
-#endif		/* MAKING_SERVER */
-
-struct server_list {
-  struct server_list	*next;
-
-  char			*name;
-  int			 port;
-  char			*pass;
-  char			*realname;
-};
+#ifndef _SERVER_H_
+#define _SERVER_H_
 
-#endif				/* !_EGG_MOD_SERVER_SERVER_H */
+#define match_my_nick(test) (!irccmp(current_server.nick, test))
+
+/* Configuration data for this module. */
+typedef struct {
+	int trigger_on_ignore;
+	int keepnick;
+	int connect_timeout;
+	int cycle_delay;
+	int default_port;
+	int ping_timeout;
+	char *user;
+	char *realname;
+} server_config_t;
+
+/* All the stuff we need to know about the currently connected server. */
+typedef struct {
+	/* Connection details. */
+	int idx;	/* Sockbuf idx of this connection. */
+	char *server_host;	/* The hostname we connected to. */
+	char *server_self;	/* What the server calls itself (from 001). */
+	int port;	/* The port we connected to. */
+	int connected;	/* Are we connected yet? */
+
+	/* Our info on the server. */
+	int registered;	/* Has the server accepted our registration? */
+	char *nick, *user, *host, *real_name;
+	char *pass;
+} current_server_t;
+
+extern server_config_t config;
+extern current_server_t current_server;
+
+#endif
Index: eggdrop1.7/modules/server/serverlist.c
diff -u /dev/null eggdrop1.7/modules/server/serverlist.c:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/modules/server/serverlist.c	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,108 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "lib/eggdrop/module.h"
+#include "serverlist.h"
+
+/*
+ * serverlist.c maintains the connection of servers and gets the next entry
+ * when we want to connect.
+ */
+
+server_t *server_list = NULL;
+int server_list_index = -1;
+int server_list_len = 0;
+
+/* Get the next server from the list. */
+server_t *server_get_next()
+{
+	server_t *serv;
+	int i;
+
+	if (server_list_len <= 0) return(NULL);
+	server_list_index++;
+	if (server_list_index >= server_list_len) server_list_index = 0;
+
+	serv = server_list;
+	for (i = 0; i < server_list_index && serv; i++) {
+		serv = serv->next;
+	}
+	return(serv);
+}
+
+void server_set_next(int next)
+{
+	server_list_index = next-1;
+}
+
+/* Add a server to the server list. */
+int server_add(char *host, int port, char *pass)
+{
+	server_t *serv;
+
+	/* Fill out a server entry. */
+	serv = calloc(1, sizeof(*serv));
+	serv->host = strdup(host);
+	serv->port = port;
+	if (pass) serv->pass = strdup(pass);
+
+	/* Insert the server into the list. */
+	serv->next = server_list;
+	server_list = serv;
+
+	/* This bumps up the index of the current server and the list len. */
+	server_list_index++;
+	server_list_len++;
+
+	return(0);
+}
+
+static void server_free(server_t *serv)
+{
+	free(serv->host);
+	if (serv->pass) free(serv->pass);
+	free(serv);
+}
+
+/* Remove a server from the server list based on its index. */
+int server_del(int num)
+{
+	server_t *cur, *prev;
+	int i;
+
+	prev = NULL;
+	i = 0;
+	for (cur = server_list; cur; cur = cur->next) {
+		if (i == num) break;
+		prev = cur;
+		i++;
+	}
+	if (!cur) return(-1);
+
+	if (prev) prev->next = cur->next;
+	else server_list = cur->next;
+
+	server_free(cur);
+
+	/* If we removed a server from underneath the current pointer, we got
+	 * bumped down. The list also shrinks by 1. */
+	if (num < server_list_index) server_list_index--;
+	server_list_len--;
+
+	return(0);
+}
+
+/* Clear out the server list. */
+int server_clear()
+{
+	server_t *cur, *next;
+
+	for (cur = server_list; cur; cur = next) {
+		next = cur->next;
+		server_free(cur);
+	}
+	server_list = NULL;
+	server_list_len = 0;
+	server_list_index = -1;
+	return(0);
+}
Index: eggdrop1.7/modules/server/serverlist.h
diff -u /dev/null eggdrop1.7/modules/server/serverlist.h:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/modules/server/serverlist.h	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,17 @@
+#ifndef _SERVERLIST_H_
+#define _SERVERLIST_H_
+
+typedef struct server {
+	struct server *next;
+	char *host;
+	int port;
+	char *pass;
+} server_t;
+
+server_t *server_get_next();
+void server_set_next(int next);
+int server_add(char *host, int port, char *pass);
+int server_del(int num);
+int server_clear();
+
+#endif
Index: eggdrop1.7/modules/server/servmsg.c
diff -u eggdrop1.7/modules/server/servmsg.c:1.28 eggdrop1.7/modules/server/servmsg.c:removed
--- eggdrop1.7/modules/server/servmsg.c:1.28	Tue Jun 18 01:12:32 2002
+++ eggdrop1.7/modules/server/servmsg.c	Thu Sep 19 21:06:36 2002
@@ -1,1101 +0,0 @@
-/*
- * servmsg.c --
- */
-/*
- * Copyright (C) 1997 Robey Pointer
- * Copyright (C) 1999, 2000, 2001, 2002 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.
- */
-
-/* FIXME: #include mess
-#ifndef lint
-static const char rcsid[] = "$Id: servmsg.c,v 1.28 2002/06/18 06:12:32 guppy Exp $";
-#endif
-*/
-
-#include "channels.h"
-
-static int altnick_char = -1;
-static char altnick_chars[] = "1234567890^_-[]{}abcdefghijklmnopqrstuvwxyz";
-
-/* We try to change to a preferred unique nick here. We always first try the
- * specified alternate nick. If that failes, we repeatedly modify the nick
- * until it gets accepted.
- *
- * sent nick:
- *     "<altnick><c>"
- *                ^--- additional count character: 1-9^-_\\[]`a-z
- *          ^--------- given, alternate nick
- *
- * The last added character is always saved in altnick_char. At the very first
- * attempt (were altnick_char is 0), we try the alternate nick without any
- * additions.
- *
- * fixed by guppy (1999/02/24) and Fabian (1999/11/26)
- */
-static void choose_altnick()
-{
-	int len;
-	char *alt;
-
-	len = strlen(botname);
-	alt = get_altbotnick();
-
-	/* First run? */
-	if ((altnick_char == -1) && irccmp(alt, botname)) {
-		/* Alternate nickname defined. Let's try that first. */
-		str_redup(&botname, alt);
-	}
-	else if (altnick_char == -1) {
-		botname = (char *)realloc(botname, len+2);
-		botname[len] = altnick_chars[0];
-		altnick_char = 0;
-		botname[len+1] = 0;
-	}
-	else {
-		altnick_char++;
-		if (altnick_char >= sizeof(altnick_chars)) {
-			make_rand_str(botname, len);
-		}
-		else {
-			botname[len] = altnick_chars[altnick_char];
-			botname[len+1] = 0;
-		}
-	}
-	putlog(LOG_MISC, "*", _("NICK IN USE: Trying %s"), botname);
-	dprintf(DP_MODE, "NICK %s\n", botname);
-	return;
-}
-
-static void check_tcl_notc(char *nick, char *uhost, struct userrec *u,
-	       		   char *dest, char *arg)
-{
-  struct flag_record fr = {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0};
-
-  get_user_flagrec(u, &fr, NULL);
-  check_bind(BT_notice, arg, &fr, nick, uhost, u, arg, dest);
-}
-
-static int check_tcl_ctcpr(char *nick, char *uhost, struct userrec *u,
-			   char *dest, char *keyword, char *args,
-			   bind_table_t *table)
-{
-  struct flag_record fr = {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0};
-  get_user_flagrec(u, &fr, NULL);
-
-  return check_bind(table, keyword, &fr, nick, uhost, u, dest, keyword, args);
-}
-
-static int check_tcl_wall(char *from, char *msg)
-{
-  int x;
-
-  x = check_bind(BT_wall, msg, NULL, from, msg);
-  if (x & BIND_RET_LOG) {
-    putlog(LOG_WALL, "*", "!%s! %s", from, msg);
-    return 1;
-  }
-  else return 0;
-}
-
-static int check_tcl_flud(char *nick, char *uhost, struct userrec *u,
-			  char *ftype, char *chname)
-{
-  return check_bind(BT_flood, ftype, NULL, nick, uhost, u, ftype, chname);
-}
-
-static int match_my_nick(char *nick)
-{
-  if (!irccmp(nick, botname))
-    return 1;
-  return 0;
-}
-
-/* 001: welcome to IRC (use it to fix the server name)
- */
-static int got001(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
-{
-	/* Ok... first arg is what server decided our nick is. */
-	server_online = now;
-	str_redup(&botname, args[0]);
-
-	check_bind_event("init-server");
-
-	/* If the init-server bind made us leave the server, stop processing. */
-	if (servidx == -1) return BIND_RET_BREAK;
-
-	/* Send a whois request so we can see our nick!user at host */
-	dprintf(DP_SERVER, "WHOIS %s\n", botname);
-
-	/* Join all our channels. */
-	channels_join_all();
-
-	if (strcasecmp(from_nick, dcc[servidx].host)) {
-		struct server_list *serv;
-
-		putlog(LOG_MISC, "*", "(%s claims to be %s; updating server list)", dcc[servidx].host, from_nick);
-		serv = server_get_current();
-		if (serv) str_redup(&serv->realname, from_nick);
-	}
-
-	return(0);
-}
-
-/* Got 442: not on channel
-	:server 442 nick #chan :You're not on that channel
- */
-static int got442(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
-{
-	struct chanset_t *chan;
-	char *chname = args[1];
-
-	chan = findchan(chname);
-
-  if (chan && !channel_inactive(chan)) {
-      module_entry	*me = module_find("channels", 0, 0);
-
-      putlog(LOG_MISC, chname, _("Server says Im not on channel: %s"), chname);
-      if (me && me->funcs)
-	(me->funcs[CHANNEL_CLEAR])(chan, 1);
-      chan->status &= ~CHAN_ACTIVE;
-      dprintf(DP_MODE, "JOIN %s %s\n", chan->name,
-	      chan->channel.key[0] ? chan->channel.key : chan->key_prot);
-  }
-
-  return 0;
-}
-
-/* Close the current server connection.
- */
-static void nuke_server(char *reason)
-{
-  if (serv >= 0) {
-    if (reason && (servidx > 0)) dprintf(servidx, "QUIT :%s\r\n", reason);
-    disconnect_server();
-  }
-}
-
-static char ctcp_reply[1024] = "";
-
-static int lastmsgs[FLOOD_GLOBAL_MAX];
-static char lastmsghost[FLOOD_GLOBAL_MAX][81];
-static time_t lastmsgtime[FLOOD_GLOBAL_MAX];
-
-/* Do on NICK, PRIVMSG, NOTICE and JOIN.
- */
-static int detect_flood(char *floodnick, char *floodhost, char *from, int which)
-{
-  char *p, ftype[10], h[1024];
-  struct userrec *u;
-  int thr = 0, lapse = 0, atr;
-
-  u = get_user_by_host(from);
-  atr = u ? u->flags : 0;
-  if (atr & (USER_BOT | USER_FRIEND))
-    return 0;
-
-  /* Determine how many are necessary to make a flood */
-  switch (which) {
-  case FLOOD_PRIVMSG:
-  case FLOOD_NOTICE:
-    thr = flud_thr;
-    lapse = flud_time;
-    strcpy(ftype, "msg");
-    break;
-  case FLOOD_CTCP:
-    thr = flud_ctcp_thr;
-    lapse = flud_ctcp_time;
-    strcpy(ftype, "ctcp");
-    break;
-  }
-  if ((thr == 0) || (lapse == 0))
-    return 0;			/* No flood protection */
-  /* Okay, make sure i'm not flood-checking myself */
-  if (match_my_nick(floodnick))
-    return 0;
-  if (!strcasecmp(floodhost, botuserhost))
-    return 0;			/* My user at host (?) */
-  p = strchr(floodhost, '@');
-  if (p) {
-    p++;
-    if (strcasecmp(lastmsghost[which], p)) {	/* New */
-      strcpy(lastmsghost[which], p);
-      lastmsgtime[which] = now;
-      lastmsgs[which] = 0;
-      return 0;
-    }
-  } else
-    return 0;			/* Uh... whatever. */
-
-  if (lastmsgtime[which] < now - lapse) {
-    /* Flood timer expired, reset it */
-    lastmsgtime[which] = now;
-    lastmsgs[which] = 0;
-    return 0;
-  }
-  lastmsgs[which]++;
-  if (lastmsgs[which] >= thr) {	/* FLOOD */
-    /* Reset counters */
-    lastmsgs[which] = 0;
-    lastmsgtime[which] = 0;
-    lastmsghost[which][0] = 0;
-    u = get_user_by_host(from);
-    if (check_tcl_flud(floodnick, floodhost, u, ftype, "*"))
-      return 0;
-    /* Private msg */
-    simple_sprintf(h, "*!*@%s", p);
-    putlog(LOG_MISC, "*", _("Flood from @%s!  Placing on ignore!"), p);
-    addignore(h, botnetnick, (which == FLOOD_CTCP) ? "CTCP flood" :
-	      "MSG/NOTICE flood", now + (60 * ignore_time));
-  }
-  return 0;
-}
-
-static int check_ctcp_ctcr(int which, int to_channel, struct userrec *u, char *nick, char *uhost, char *dest, char *trailing)
-{
-	struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
-	char *cmd, *space, *logdest, *text, *ctcptype;
-	bind_table_t *table;
-	int r, len, flags;
-
-	len = strlen(trailing);
-	if ((len < 2) || (trailing[0] != 1) || (trailing[len-1] != 1)) {
-		/* Not a ctcp/ctcr. */
-		return(0);
-	}
-
-	space = strchr(trailing, ' ');
-	if (!space) return(1);
-
-	*space = 0;
-
-	trailing[len-1] = 0;
-	cmd = trailing+1;	/* Skip over the \001 */
-	text = space+1;
-
-	if (which == 0) table = BT_ctcp;
-	else table = BT_ctcr;
-
-	get_user_flagrec(u, &fr, dest);
-
-	r = check_bind(table, cmd, &fr, nick, uhost, u, dest, cmd, text);
-
-	trailing[len-1] = 1;
-
-	if (r & BIND_RET_BREAK) return(1);
-
-	if (which == 0) ctcptype = "";
-	else ctcptype = " reply";
-	/* This should probably go in the partyline module later. */
-	if (to_channel) {
-		flags = LOG_PUBLIC;
-		logdest = dest;
-	}
-	else {
-		flags = LOG_MSGS;
-		logdest = "*";
-	}
-	if (!strcasecmp(cmd, "ACTION")) putlog(flags, logdest, "Action: %s %s", nick, text);
-	else putlog(flags, logdest, "CTCP%s %s: %s from %s (%s)", ctcptype, cmd, text, nick, dest);
-
-	return(1);
-}
-
-static int check_global_notice(char *from_nick, char *from_uhost, char *dest, char *trailing)
-{
-	if (*dest == '$') {
-		putlog(LOG_MSGS | LOG_SERV, "*", "[%s!%s to %s] %s", from_nick, from_uhost, dest, trailing);
-		return(1);
-	}
-	return(0);
-}
-
-/* Got a private (or public) message.
-	:nick!uhost PRIVMSG dest :msg
- */
-static int gotmsg(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
-{
-	char *dest, *trailing, *first, *space, *text;
-	struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
-	int to_channel;	/* Is it going to a channel? */
-	int r;
-
-	dest = args[0];
-	trailing = args[1];
-
-	/* Check if it's a global message. */
-	r = check_global_notice(from_nick, from_uhost, dest, trailing);
-	if (r) return(0);
-
-	/* Check if it's an op/voice message. */
-	if ((*dest == '@' || *dest == '+') && strchr(CHANMETA, *(dest+1))) {
-		to_channel = 1;
-		dest++;
-	}
-	else if (strchr(CHANMETA, *dest)) to_channel = 1;
-	else to_channel = 0;
-
-	/* Check if it's a ctcp. */
-	r = check_ctcp_ctcr(0, to_channel, u, from_nick, from_uhost, dest, trailing);
-	if (r) return(0);
-
-
-	/* If it's a message, it goes to msg/msgm or pub/pubm. */
-	/* Get the first word so we can do msg or pub. */
-	first = trailing;
-	space = strchr(trailing, ' ');
-	if (space) {
-		*space = 0;
-		text = space+1;
-	}
-	else text = "";
-
-	get_user_flagrec(u, &fr, dest);
-	if (to_channel) {
-		r = check_bind(BT_pub, first, &fr, from_nick, from_uhost, u, dest, text);
-		if (r & BIND_RET_LOG) {
-			putlog(LOG_CMDS, dest, "<<%s>> !%s! %s %s", from_nick, u ? u->handle : "*", first, text);
-		}
-	}
-	else {
-		r = check_bind(BT_msg, first, &fr, from_nick, from_uhost, u, text);
-		if (r & BIND_RET_LOG) {
-			putlog(LOG_CMDS, "*", "(%s!%s) !%s! %s %s", from_nick, from_uhost, u ? u->handle : "*", first, text);
-		}
-	}
-
-	if (space) *space = ' ';
-
-	if (r & BIND_RET_BREAK) return(0);
-
-	/* And now the stackable version. */
-	if (to_channel) {
-		r = check_bind(BT_pubm, trailing, &fr, from_nick, from_uhost, u, dest, trailing);
-	}
-	else {
-		r = check_bind(BT_msg, trailing, &fr, from_nick, from_uhost, u, trailing);
-	}
-
-	if (!(r & BIND_RET_BREAK)) {
-		/* This should probably go in the partyline module later. */
-		if (to_channel) {
-			putlog(LOG_PUBLIC, dest, "<%s> %s", from_nick, trailing);
-		}
-		else {
-			putlog(LOG_MSGS, "*", "[%s (%s)] %s", from_nick, from_uhost, trailing);
-		}
-	}
-	return(0);
-}
-
-/* Got a private notice.
-	:nick!uhost NOTICE dest :hello there
- */
-static int gotnotice(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
-{
-	char *dest, *trailing;
-	struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
-	int r, to_channel;
-
-	dest = args[0];
-	trailing = args[1];
-
-	/* See if it's a server notice. */
-	if (!from_uhost) {
-		putlog(LOG_SERV, "*", "-NOTICE- %s", trailing);
-		return(0);
-	}
-
-	/* Check if it's a global notice. */
-	r = check_global_notice(from_nick, from_uhost, dest, trailing);
-	if (r) return(0);
-
-	if ((*dest == '@' || *dest == '+') && strchr(CHANMETA, *(dest+1))) {
-		to_channel = 1;
-		dest++;
-	}
-	else if (strchr(CHANMETA, *dest)) to_channel = 1;
-	else to_channel = 0;
-
-	/* Check if it's a ctcp. */
-	r = check_ctcp_ctcr(1, to_channel, u, from_nick, from_uhost, dest, trailing);
-	if (r) return(0);
-
-	get_user_flagrec(u, &fr, NULL);
-	r = check_bind(BT_notice, trailing, &fr, from_nick, from_uhost, u, dest, trailing);
-
-	if (!(r & BIND_RET_BREAK)) {
-		/* This should probably go in the partyline module later. */
-		if (to_channel) {
-			putlog(LOG_PUBLIC, dest, "-%s:%s- %s", from_nick, dest, trailing);
-		}
-		else {
-			putlog(LOG_MSGS, "*", "-%s (%s)- %s", from_nick, from_uhost, trailing);
-		}
-	}
-	return(0);
-}
-
-/* WALLOPS: oper's nuisance
-	:csd.bu.edu WALLOPS :Connect '*.uiuc.edu 6667' from Joshua
- */
-static int gotwall(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
-{
-	char *msg;
-	int r;
-
-	msg = args[1];
-	r = check_bind(BT_wall, msg, NULL, from_nick, msg);
-	if (!(r & BIND_RET_BREAK)) {
-		if (from_uhost) putlog(LOG_WALL, "*", "!%s (%s)! %s", from_nick, from_uhost, msg);
-		else putlog(LOG_WALL, "*", "!%s! %s", from_nick, msg);
-	}
-	return 0;
-}
-
-/* Called once a minute... but if we're the only one on the
- * channel, we only wanna send out "lusers" once every 5 mins.
- */
-static void minutely_checks()
-{
-  char *alt;
-
-  /* Only check if we have already successfully logged in.  */
-  if (!server_online)
-    return;
-  if (keepnick) {
-    /* NOTE: now that botname can but upto NICKLEN bytes long,
-     * check that it's not just a truncation of the full nick.
-     */
-    if (strncmp(botname, origbotname, strlen(botname))) {
-      /* See if my nickname is in use and if if my nick is right.  */
-	alt = get_altbotnick();
-	if (alt[0] && strcasecmp (botname, alt))
-	  dprintf(DP_SERVER, "ISON :%s %s %s\n", botname, origbotname, alt);
-	else
-          dprintf(DP_SERVER, "ISON :%s %s\n", botname, origbotname);
-    }
-  }
-}
-
-/* Pong from server.
-	:liberty.nj.us.dal.net PONG liberty.nj.us.dal.net :12345 67890
- */
-static int gotpong(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
-{
-	unsigned int sec, usec;
-
-	if (sscanf(args[1], "%u %u", &sec, &usec) != 2) return(0);
-
-	server_lag.sec = egg_timeval_now.sec - sec;
-	server_lag.usec = egg_timeval_now.usec - usec;
-
-	return(0);
-}
-
-/* This is a reply on ISON :<current> <orig> [<alt>]
- */
-static int got303(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
-{
-	char *nicks, *space, *alt;
-	int ison_orig = 0, ison_alt = 0;
-
-	if (!keepnick || !strcmp(botname, origbotname)) return(0);
-	alt = get_altbotnick();
-	nicks = args[1];
-	for (;;) {
-		space = strchr(nicks, ' ');
-		if (space) *space = 0;
-		if (!irccmp(origbotname, nicks)) ison_orig = 1;
-		else if (!irccmp(alt, nicks)) ison_alt = 1;
-		if (space) {
-			*space = ' ';
-			nicks = space+1;
-		}
-		else break;
-	}
-
-	if (!ison_orig) {
-		putlog(LOG_MISC, "*", _("Switching back to nick %s"), origbotname);
-		dprintf(DP_SERVER, "NICK %s\n", origbotname);
-	}
-	else if (!ison_alt && strcmp(botname, alt)) {
-		putlog(LOG_MISC, "*", _("Switching back to altnick %s"), alt);
-		dprintf(DP_SERVER, "NICK %s\n", alt);
-	}
-	return(0);
-}
-
-/* 432 : Bad nickname
- */
-static int got432(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
-{
-	char *badnick;
-	char newnick[10];
-
-	badnick = args[1];
-	if (server_online) putlog(LOG_MISC, "*", "NICK IS INVALID: %s (keeping '%s').", badnick, botname);
-	else {
-		putlog(LOG_MISC, "*", _("Server says my nickname is invalid, choosing new random nick."));
-		if (!keepnick) {
-			make_rand_str(newnick, 9);
-			newnick[9] = 0;
-			dprintf(DP_MODE, "NICK %s\n", newnick);
-		}
-	}
-	return(0);
-}
-
-/* 433 : Nickname in use
- * Change nicks till we're acceptable or we give up
- */
-static int got433(char *from_nick, char *from_uhost, struct userrec *u, char *cmd, int nargs, char *args[])
-{
-	char *badnick;
-
-	badnick = args[1];
-	if (server_online) {
-		/* We are online and have a nickname, we'll keep it */
-		putlog(LOG_MISC, "*", "NICK IN USE: %s (keeping '%s').", badnick, botname);
-		nick_juped = 0;
-		return(0);
-	}
-	choose_altnick();
-	return(0);
-}
-
-/* 437 : Nickname juped (IRCnet)
- */
-static int got437(char *from, char *ignore, char *msg)
-{
-  char *s;
-  struct chanset_t *chan;
-
-  newsplit(&msg);
-  s = newsplit(&msg);
-  if (s[0] && (strchr(CHANMETA, s[0]) != NULL)) {
-    chan = findchan(s);
-    if (chan) {
-      if (chan->status & CHAN_ACTIVE) {
-	putlog(LOG_MISC, "*", _("Cant change nickname on %s.  Is my nickname banned?"), s);
-      } else {
-	if (!channel_juped(chan)) {
-	  putlog(LOG_MISC, "*", _("Channel %s is juped. :("), s);
-	  chan->status |= CHAN_JUPED;
-	}
-      }
-    }
-  } else if (server_online) {
-    if (!nick_juped)
-      putlog(LOG_MISC, "*", "NICK IS JUPED: %s (keeping '%s').", s, botname);
-    if (!irccmp(s, origbotname))
-      nick_juped = 1;
-  } else {
-    putlog(LOG_MISC, "*", "%s: %s", _("Nickname has been juped"), s);
-    choose_altnick();
-  }
-  return 0;
-}
-
-/* 438 : Nick change too fast
- */
-static int got438(char *from, char *ignore, char *msg)
-{
-	putlog(LOG_MISC, "*", "%s", _("Nick change was too fast."));
-	return(0);
-}
-
-static int got451(char *from, char *ignore, char *msg)
-{
-  /* Usually if we get this then we really messed up somewhere
-   * or this is a non-standard server, so we log it and kill the socket
-   * hoping the next server will work :) -poptix
-   */
-  /* Um, this does occur on a lagged anti-spoof server connection if the
-   * (minutely) sending of joins occurs before the bot does its ping reply.
-   * Probably should do something about it some time - beldin
-   */
-  putlog(LOG_MISC, "*", _("%s says Im not registered, trying next one."), from);
-  nuke_server(_("The server says we are not registered yet."));
-  return 0;
-}
-
-/* Got error notice
- */
-static int goterror(char *from, char *ignore, char *msg)
-{
-  fixcolon(msg);
-  putlog(LOG_SERV | LOG_MSGS, "*", "-ERROR from server- %s", msg);
-  putlog(LOG_SERV, "*", "Disconnecting from server.");
-  nuke_server("Bah, stupid error messages.");
-  return 1;
-}
-
-/* Got nick change.
- */
-static int gotnick(char *from, char *ignore, char *msg)
-{
-  char *nick, *alt = get_altbotnick();
-  char buf[512];
-  struct userrec *u;
-
-  fixcolon(msg);
-  u = get_user_by_host(from);
-  strlcpy(buf, from, sizeof(buf));
-  nick = strtok(buf, "!");
-  check_queues(nick, msg);
-  if (match_my_nick(nick)) {
-    /* Regained nick! */
-    str_redup(&botname, msg);
-    altnick_char = -1;
-    if (!strcmp(msg, origbotname)) {
-      putlog(LOG_SERV | LOG_MISC, "*", "Regained nickname '%s'.", msg);
-      nick_juped = 0;
-    } else if (alt[0] && !strcmp(msg, alt))
-      putlog(LOG_SERV | LOG_MISC, "*", "Regained alternate nickname '%s'.",
-	     msg);
-    else if (keepnick && strcmp(nick, msg)) {
-      putlog(LOG_SERV | LOG_MISC, "*", "Nickname changed to '%s'???", msg);
-      if (!irccmp(nick, origbotname)) {
-        putlog(LOG_MISC, "*", _("Switching back to nick %s"), origbotname);
-        dprintf(DP_SERVER, "NICK %s\n", origbotname);
-      } else if (alt[0] && !irccmp(nick, alt)
-		 && strcasecmp(botname, origbotname)) {
-        putlog(LOG_MISC, "*", _("Switching back to altnick %s"), alt);
-        dprintf(DP_SERVER, "NICK %s\n", alt);
-      }
-    } else
-      putlog(LOG_SERV | LOG_MISC, "*", "Nickname changed to '%s'???", msg);
-  } else if ((keepnick) && (irccmp(nick, msg))) {
-    /* Only do the below if there was actual nick change, case doesn't count */
-    if (!irccmp(nick, origbotname)) {
-      putlog(LOG_MISC, "*", _("Switching back to nick %s"), origbotname);
-      dprintf(DP_SERVER, "NICK %s\n", origbotname);
-    } else if (alt[0] && !irccmp(nick, alt) &&
-	    strcasecmp(botname, origbotname)) {
-      putlog(LOG_MISC, "*", _("Switching back to altnick %s"), altnick);
-      dprintf(DP_SERVER, "NICK %s\n", altnick);
-    }
-  }
-  return 0;
-}
-
-static int gotmode(char *from, char *ignore, char *msg)
-{
-  char *ch;
-  char buf[512];
-
-  strlcpy(buf, msg, sizeof(buf));
-  msg = buf;
-  ch = newsplit(&msg);
-  /* Usermode changes? */
-  if (strchr(CHANMETA, ch[0]) == NULL) {
-    if (match_my_nick(ch) && check_mode_r) {
-      /* umode +r? - D0H dalnet uses it to mean something different */
-      fixcolon(msg);
-      if ((msg[0] == '+') && strchr(msg, 'r')) {
-	putlog(LOG_MISC | LOG_JOIN, "*",
-	       "%s has me i-lined (jumping)", dcc[servidx].host);
-	nuke_server("i-lines suck");
-      }
-    }
-  }
-  return 0;
-}
-
-static void disconnect_server()
-{
-	int idx;
-
-	if (server_online > 0) check_bind_event("disconnect-server");
-
-	server_online = 0;
-	if (servidx != -1 && dcc[servidx].sock >= 0) {
-		killsock(dcc[servidx].sock);
-		dcc[servidx].sock = (-1);
-	}
-	serv = -1;
-	botuserhost[0] = 0;
-	idx = servidx;
-	servidx = -1;
-	lostdcc(idx);
-}
-
-static void eof_server(int idx)
-{
-  putlog(LOG_SERV, "*", "%s %s", _("Disconnected from"), dcc[idx].host);
-  disconnect_server();
-}
-
-static void display_server(int idx, char *buf)
-{
-  sprintf(buf, "%s  (lag: %d.%02d)", trying_server ? "conn" : "serv",
-	  server_lag.sec, server_lag.usec / 10000);
-}
-
-static void connect_server(void);
-
-static void kill_server(int idx, void *x)
-{
-  module_entry *me;
-
-  disconnect_server();
-  if ((me = module_find("channels", 0, 0)) && me->funcs) {
-    struct chanset_t *chan;
-
-    for (chan = chanset; chan; chan = chan->next)
-      (me->funcs[CHANNEL_CLEAR]) (chan, 1);
-  }
-  /* A new server connection will be automatically initiated in
-     about 2 seconds. */
-}
-
-static void timeout_server(int idx)
-{
-  putlog(LOG_SERV, "*", "Timeout: connect to %s", dcc[idx].host);
-  disconnect_server();
-}
-
-static void server_activity(int idx, char *msg, int len);
-
-static struct dcc_table SERVER_SOCKET =
-{
-  "SERVER",
-  0,
-  eof_server,
-  server_activity,
-  NULL,
-  timeout_server,
-  display_server,
-  kill_server,
-  NULL
-};
-
-static void add_arg(int *nargs, char ***args, char *static_args[], char *arg)
-{
-	if (*nargs >= 10) {
-		if (*nargs == 10) {
-			*args = (char **)malloc(sizeof(char *) * 11);
-			memcpy(*args, static_args, sizeof(char *) * 10);
-		}
-		else *args = (char **)realloc(*args, sizeof(char *) * (*nargs+1));
-	}
-	(*args)[*nargs] = arg;
-	(*nargs)++;
-}
-
-static void server_activity(int idx, char *msg, int len)
-{
-	/* The components of any irc message. */
-	char *prefix = NULL, *cmd = NULL;
-	char *space;
-	char *from_nick = NULL, *from_uhost = NULL;
-	char *static_args[10], **args = static_args;
-	char *remainder;
-	int nargs = 0;
-	struct userrec *u = NULL;
-
-	if (trying_server) {
-		strcpy(dcc[idx].nick, "(server)");
-		putlog(LOG_SERV, "*", "Connected to %s", dcc[idx].host);
-		trying_server = 0;
-		SERVER_SOCKET.timeout_val = 0;
-	}
-	waiting_for_awake = 0;
-
-	if (!len) return;
-
-	remainder = strdup("");
-
-	/* This would be a good place to put an SFILT bind, so that scripts
-		and other modules can modify text sent from the server. */
-	if (debug_output) {
-		putlog(LOG_RAW, "*", "[@] %s", msg);
-	}
-
-	/* First word is the prefix, or command if it doesn't start with ':' */
-	if (*msg == ':') {
-		prefix = msg+1;
-		msg = strchr(msg, ' ');
-		if (!msg) goto done_parsing;
-		*msg = 0;
-		msg++;
-	}
-
-	cmd = msg;
-	msg = strchr(msg, ' ');
-	if (!msg) goto done_parsing;
-	*msg = 0;
-	msg++;
-
-	/* Save the remainder to call the old binds (temporary). */
-	str_redup(&remainder, msg);
-
-	/* Next comes the args to the command. */
-	while ((*msg != ':') && (space = strchr(msg, ' '))) {
-		add_arg(&nargs, &args, static_args, msg);
-		*space = 0;
-		msg = space+1;
-	}
-
-	if (*msg == ':') add_arg(&nargs, &args, static_args, msg+1);
-
-done_parsing:
-
-	if (prefix) {
-		u = get_user_by_host(prefix);
-		from_nick = prefix;
-		from_uhost = strchr(prefix, '!');
-		if (from_uhost) {
-			*from_uhost = 0;
-			from_uhost++;
-		}
-	}
-
-	check_bind(BT_new_raw, cmd, NULL, from_nick, from_uhost, u, cmd, nargs, args);
-
-	if (args != static_args) free(args);
-
-	/* For now, let's emulate the old style. */
-
-	if (from_nick && from_uhost) prefix = msprintf("%s!%s", from_nick, from_uhost);
-	else if (from_nick) prefix = strdup(from_nick);
-	else prefix = strdup("");
-
-	check_bind(BT_raw, cmd, NULL, prefix, cmd, remainder);
-	free(prefix);
-	free(remainder);
-}
-
-static int gotping(char *from, char *ignore, char *msg)
-{
-  fixcolon(msg);
-  dprintf(DP_MODE, "PONG :%s\n", msg);
-  return 0;
-}
-
-static int gotkick(char *from, char *ignore, char *msg)
-{
-  char *nick;
-
-  nick = from;
-  if (irccmp(nick, botname))
-    /* Not my kick, I don't need to bother about it. */
-    return 0;
-  if (use_penalties) {
-    last_time += 2;
-    if (debug_output)
-      putlog(LOG_SRVOUT, "*", "adding 2secs penalty (successful kick)");
-  }
-  return 0;
-}
-
-/* Another sec penalty if bot did a whois on another server.
- */
-static int whoispenalty(char *from, char *msg)
-{
-  struct server_list *x = serverlist;
-  int i, ii;
-
-  if (x && use_penalties) {
-    i = ii = 0;
-    for (; x; x = x->next) {
-      if (i == curserv)
-          if (strcmp(x->name, from) || strcmp(x->realname, from))
-            ii = 1;
-      i++;
-    }
-    if (ii) {
-      last_time += 1;
-      if (debug_output)
-        putlog(LOG_SRVOUT, "*", "adding 1sec penalty (remote whois)");
-    }
-  }
-  return 0;
-}
-
-static int got311(char *from, char *ignore, char *msg)
-{
-  char *n1, *n2, *u, *h;
-  
-  n1 = newsplit(&msg);
-  n2 = newsplit(&msg);
-  u = newsplit(&msg);
-  h = newsplit(&msg);
-  
-  if (!n1 || !n2 || !u || !h)
-    return 0;
-    
-  if (match_my_nick(n2))
-    snprintf(botuserhost, sizeof botuserhost, "%s@%s", u, h);
-  
-  return 0;
-}
-
-static cmd_t my_new_raw_binds[] = {
-	{"001", "", (Function) got001, NULL},
-	{"PRIVMSG", "", (Function) gotmsg, NULL},
-	{"NOTICE", "", (Function) gotnotice, NULL},
-	{"WALLOPS", "", (Function) gotwall, NULL},
-	{"PONG", "", (Function) gotpong, NULL},
-	{"303", "", (Function) got303, NULL},
-	{"432",	"", (Function) got432, NULL},
-	{"433",	"", (Function) got433, NULL},
-	{"438", "", (Function) got438, NULL},
-	{0}
-};
-
-static cmd_t my_raw_binds[] =
-{
-  {"MODE",	"",	(Function) gotmode,		NULL},
-  {"PING",	"",	(Function) gotping,		NULL},
-  {"437",	"",	(Function) got437,		NULL},
-  {"451",	"",	(Function) got451,		NULL},
-  {"442",	"",	(Function) got442,		NULL},
-  {"NICK",	"",	(Function) gotnick,		NULL},
-  {"ERROR",	"",	(Function) goterror,		NULL},
-  {"KICK",	"",	(Function) gotkick,		NULL},
-  {"318",	"",	(Function) whoispenalty,	NULL},
-  {"311",	"",	(Function) got311,		NULL},
-  {NULL,	NULL,	NULL,				NULL}
-};
-
-static void server_resolve_success(int);
-static void server_resolve_failure(int);
-
-/* Hook up to a server
- */
-static void connect_server(void)
-{
-  char pass[121], botserver[UHOSTLEN];
-  static int oldserv = -1;
-  unsigned int botserverport = 0;
-
-  waiting_for_awake = 0;
-  trying_server = now;
-  empty_msgq();
-
-  if (oldserv < 0)
-    oldserv = curserv;
-  if (newserverport) {		/* Jump to specified server */
-    curserv = (-1);		/* Reset server list */
-    strcpy(botserver, newserver);
-    botserverport = newserverport;
-    strcpy(pass, newserverpass);
-    newserver[0] = 0;
-    newserverport = 0;
-    newserverpass[0] = 0;
-    oldserv = (-1);
-  } else
-    pass[0] = 0;
-  if (!cycle_time) {
-    struct chanset_t *chan;
-    struct server_list *x = serverlist;
-
-    if (!x) {
-      putlog(LOG_SERV, "*", "No servers in server list");
-      cycle_time = 300;
-      return;
-    }
- 
-    servidx = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
-    if (servidx < 0) {
-      putlog(LOG_SERV, "*",
-	     "NO MORE DCC CONNECTIONS -- Can't create server connection.");
-      return;
-    }
-
-    check_bind_event("connect-server");
-    next_server(&curserv, botserver, &botserverport, pass);
-    putlog(LOG_SERV, "*", "%s %s %d", _("Trying server"), botserver, botserverport);
-
-    dcc[servidx].port = botserverport;
-    strcpy(dcc[servidx].nick, "(server)");
-    strlcpy(dcc[servidx].host, botserver, UHOSTLEN);
-
-    botuserhost[0] = 0;
-
-    nick_juped = 0;
-    for (chan = chanset; chan; chan = chan->next)
-      chan->status &= ~CHAN_JUPED;
-
-    dcc[servidx].timeval = now;
-    dcc[servidx].sock = -1;
-    dcc[servidx].u.dns->host = calloc(1, strlen(dcc[servidx].host) + 1);
-    strcpy(dcc[servidx].u.dns->host, dcc[servidx].host);
-    dcc[servidx].u.dns->cbuf = calloc(1, strlen(pass) + 1);
-    strcpy(dcc[servidx].u.dns->cbuf, pass);
-    dcc[servidx].u.dns->dns_success = server_resolve_success;
-    dcc[servidx].u.dns->dns_failure = server_resolve_failure;
-    dcc[servidx].u.dns->dns_type = RES_IPBYHOST;
-    dcc[servidx].u.dns->type = &SERVER_SOCKET;
-
-    if (server_cycle_wait)
-      /* Back to 1st server & set wait time.
-       * Note: Put it here, just in case the server quits on us quickly
-       */
-      cycle_time = server_cycle_wait;
-    else
-      cycle_time = 0;
-
-    /* I'm resolving... don't start another server connect request */
-    resolvserv = 1;
-    /* Resolve the hostname. */
-    dcc_dnsipbyhost(dcc[servidx].host);
-  }
-}
-
-static void server_resolve_failure(int servidx)
-{
-  serv = -1;
-  servidx = -1;
-  resolvserv = 0;
-  putlog(LOG_SERV, "*", "%s %s (%s)", _("Failed connect to"), dcc[servidx].host,
-	 _("DNS lookup failed"));
-  lostdcc(servidx);
-}
-
-static void server_resolve_success(int servidx)
-{
-  char s[121], pass[121];
-
-  resolvserv = 0;
-  
-  strcpy(dcc[servidx].addr, dcc[servidx].u.dns->host);
-  strcpy(pass, dcc[servidx].u.dns->cbuf);
-  changeover_dcc(servidx, &SERVER_SOCKET, 0);
-  serv = open_telnet(dcc[servidx].addr, dcc[servidx].port);
-  if (serv < 0) {
-    neterror(s);
-    putlog(LOG_SERV, "*", "%s %s (%s)", _("Failed connect to"), dcc[servidx].host,
-	   s);
-    lostdcc(servidx);
-    servidx = -1;
-  } else {
-    dcc[servidx].sock = serv;
-    /* Queue standard login */
-    dcc[servidx].timeval = now;
-    SERVER_SOCKET.timeout_val = &server_timeout;
-    /* Another server may have truncated it, so use the original */
-    str_redup(&botname, origbotname);
-    /* Start alternate nicks from the beginning */
-    altnick_char = -1;
-    if (pass[0]) dprintf(DP_MODE, "PASS %s\r\n", pass);
-    dprintf(DP_MODE, "NICK %s\r\n", botname);
-    dprintf(DP_MODE, "USER %s localhost %s :%s\r\n", botuser, dcc[servidx].host, botrealname);
-    /* Wait for async result now */
-  }
-}
Index: eggdrop1.7/modules/server/servsock.c
diff -u /dev/null eggdrop1.7/modules/server/servsock.c:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/modules/server/servsock.c	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,161 @@
+#include "lib/eggdrop/module.h"
+#include "lib/eggdrop/eggdrop.h"
+
+#include "server.h"
+#include "servsock.h"
+#include "serverlist.h"
+#include "channels.h"
+#include "parse.h"
+#include "nicklist.h"
+#include "output.h"
+#include "binds.h"
+
+/* From server.c. */
+extern int cycle_delay;
+
+static void disconnect_server();
+
+static int server_on_connect(void *client_data, int idx, const char *peer_ip, int peer_port);
+
+static int server_on_eof(void *client_data, int idx, int err, const char *errmsg);
+
+static int server_on_read(void *client_data, int idx, char *text, int len);
+
+static sockbuf_handler_t server_handler = {
+	"server",
+	server_on_connect, server_on_eof, NULL,
+	server_on_read, NULL
+};
+
+/**********************************************************************
+ * Connection management
+ */
+
+void connect_to_next_server() {
+	server_t *serv;
+
+	serv = server_get_next();
+	if (!serv) {
+		putlog(LOG_MISC, "*", "Error connecting to next server: no servers are defined!");
+		return;
+	}
+
+	str_redup(&current_server.server_host, serv->host);
+	str_redup(&current_server.server_self, serv->host);
+	str_redup(&current_server.pass, serv->pass);
+
+	if (serv->port) current_server.port = serv->port;
+	else current_server.port = config.default_port;
+
+	current_server.idx = egg_connect(current_server.server_host, current_server.port, config.connect_timeout);
+	sockbuf_set_handler(current_server.idx, &server_handler, NULL);
+}
+
+/* Close the current server connection. */
+void kill_server(const char *reason)
+{
+	if (reason && (current_server.idx > -1)) printserv(SERVER_NOQUEUE, "QUIT :%s\r\n", reason);
+	disconnect_server();
+}
+
+/* Clean up stuff when we want to disconnect or are disconnected. */
+static void disconnect_server()
+{
+	int connected = current_server.connected;
+
+	cycle_delay = config.cycle_delay;
+
+	current_server.connected = 0;
+	current_server.registered = 0;
+
+	if (current_server.idx != -1) {
+		sockbuf_delete(current_server.idx);
+		current_server.idx = -1;
+	}
+
+	if (connected) check_bind_event("disconnect-server");
+}
+
+
+
+
+
+
+
+
+
+
+
+/****************************************************************
+ * Sockbuf handlers
+ */
+
+/* When we get an eof or an error in the connection. */
+static int server_on_eof(void *client_data, int idx, int err, const char *errmsg)
+{
+	putlog(LOG_SERV, "*", "Disconnected from %s", current_server.server_self);
+	if (err && errmsg) putlog(LOG_SERV, "*", "Network error %d: %s", err, errmsg);
+	disconnect_server();
+	return(0);
+}
+
+static int server_on_connect(void *client_data, int idx, const char *peer_ip, int peer_port)
+{
+	linemode_on(current_server.idx);
+
+	current_server.connected = 1;
+	nick_list_on_connect();
+	putlog(LOG_SERV, "*", "Connected to %s, logging in.", current_server.server_host);
+	check_bind_event("connect-server");
+	if (!current_server.connected) return(0);
+
+	printserv(SERVER_NOQUEUE, "USER %s localhost %s :%s\r\n", config.user, current_server.server_host, config.realname);
+	if (current_server.pass) printserv(SERVER_NOQUEUE, "PASS %s\r\n", current_server.pass);
+	try_next_nick();
+	return(0);
+}
+
+static int server_on_read(void *client_data, int idx, char *text, int len)
+{
+	/* The components of any irc message. */
+	irc_msg_t msg;
+	char *from_nick = NULL, *from_uhost = NULL, *prefix = NULL;
+	struct userrec *u = NULL;
+
+	if (!len) return(0);
+
+	/* This would be a good place to put an SFILT bind, so that scripts
+		and other modules can modify text sent from the server. */
+	if (debug_output) {
+		putlog(LOG_RAW, "*", "[@] %s", text);
+	}
+
+	irc_msg_parse(text, &msg);
+
+	if (msg.prefix) {
+		from_nick = msg.prefix;
+		from_uhost = strchr(from_nick, '!');
+		if (from_uhost) {
+			u = get_user_by_host(from_nick);
+			*from_uhost = 0;
+			from_uhost++;
+		}
+	}
+
+	check_bind(BT_new_raw, msg.cmd, NULL, from_nick, from_uhost, u, msg.cmd, msg.nargs, msg.args);
+
+	/* For now, let's emulate the old style. */
+
+	if (from_nick && from_uhost) prefix = msprintf("%s!%s", from_nick, from_uhost);
+	else if (from_nick) prefix = strdup(from_nick);
+	else prefix = strdup("");
+
+	text = msg.args[0];
+	irc_msg_restore(&msg);
+	irc_msg_cleanup(&msg);
+	if (text[-1] == ':') text--;
+	text[-1] = 0;
+	check_bind(BT_raw, msg.cmd, NULL, prefix, msg.cmd, text);
+	free(prefix);
+	return(0);
+}
Index: eggdrop1.7/modules/server/servsock.h
diff -u /dev/null eggdrop1.7/modules/server/servsock.h:1.1
--- /dev/null	Thu Sep 19 21:06:36 2002
+++ eggdrop1.7/modules/server/servsock.h	Thu Sep 19 21:06:25 2002
@@ -0,0 +1,7 @@
+#ifndef _SERVSOCK_H_
+#define _SERVSOCK_H_
+
+void connect_to_next_server();
+void kill_server(const char *reason);
+
+#endif
Index: eggdrop1.7/modules/tclscript/tclscript.c
diff -u eggdrop1.7/modules/tclscript/tclscript.c:1.19 eggdrop1.7/modules/tclscript/tclscript.c:1.20
--- eggdrop1.7/modules/tclscript/tclscript.c:1.19	Thu May 30 23:11:37 2002
+++ eggdrop1.7/modules/tclscript/tclscript.c	Thu Sep 19 21:06:25 2002
@@ -20,7 +20,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: tclscript.c,v 1.19 2002/05/31 04:11:37 stdarg Exp $";
+static const char rcsid[] = "$Id: tclscript.c,v 1.20 2002/09/20 02:06:25 stdarg Exp $";
 #endif
 
 #include "lib/eggdrop/module.h"
@@ -161,37 +161,7 @@
 		if (!obj) return("Error setting variable");
 
 		tcl_to_c_var(irp, obj, &newvalue, linked_var->type);
-
-		/* If they give a callback, then let them handle it. Otherwise, we
-			do some default handling for strings and ints. */
-		if (linked_var->callbacks && linked_var->callbacks->on_write) {
-			int r;
-
-			r = (linked_var->callbacks->on_write)(linked_var, &newvalue);
-			if (r) return("Error setting variable");
-			set_linked_var(linked_var, &newvalue);
-		}
-		else switch (linked_var->type & SCRIPT_TYPE_MASK) {
-			case SCRIPT_UNSIGNED:
-			case SCRIPT_INTEGER:
-				/* linked_var->value is a pointer to an int/uint */
-				*(int *)(linked_var->value) = (int) newvalue.value;
-				break;
-			case SCRIPT_STRING: {
-				/* linked_var->value is a pointer to a (char *) */
-				char **charptr = (char **)(linked_var->value);
-
-				/* Free the old value. */
-				if (*charptr) free(*charptr);
-
-				/* If we copied the string (> 8.0) then just use the copy. */
-				if (newvalue.type & SCRIPT_FREE) *charptr = newvalue.value;
-				else *charptr = strdup(newvalue.value);
-				break;
-			}
-			default:
-				return("Error setting variable (unsupported type)");
-		}
+		script_linked_var_on_write(linked_var, &newvalue);
 	}
 	else if (flags & TCL_TRACE_UNSETS) {
 		/* If someone unsets a variable, we'll just reset it. */
Index: eggdrop1.7/src/Makefile.am
diff -u eggdrop1.7/src/Makefile.am:1.26 eggdrop1.7/src/Makefile.am:1.27
--- eggdrop1.7/src/Makefile.am:1.26	Tue Jun 18 01:12:32 2002
+++ eggdrop1.7/src/Makefile.am	Thu Sep 19 21:06:25 2002
@@ -1,4 +1,4 @@
-# $Id: Makefile.am,v 1.26 2002/06/18 06:12:32 guppy Exp $
+# $Id: Makefile.am,v 1.27 2002/09/20 02:06:25 stdarg Exp $
 
 # FIXME: optionally allow a system wide install by ignoring the line below.
 bindir			= $(exec_prefix)
@@ -43,9 +43,8 @@
 			debug.h \
 			dns.c \
 			dns.h \
-			egg_timer.c \
-			egg_timer.h \
 			egg.h \
+			egg_timer.c \
 			flags.c \
 			flags.h \
 			irccmp.c \
Index: eggdrop1.7/src/egg_timer.c
diff -u eggdrop1.7/src/egg_timer.c:1.13 eggdrop1.7/src/egg_timer.c:1.14
--- eggdrop1.7/src/egg_timer.c:1.13	Sun May 12 00:59:52 2002
+++ eggdrop1.7/src/egg_timer.c	Thu Sep 19 21:06:25 2002
@@ -21,35 +21,15 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: egg_timer.c,v 1.13 2002/05/12 05:59:52 stdarg Exp $";
+static const char rcsid[] = "$Id: egg_timer.c,v 1.14 2002/09/20 02:06:25 stdarg Exp $";
 #endif
 
 #include <stdio.h> /* NULL */
-#include <string.h> /* memcpy() */
-#include <stdlib.h> /* malloc(), free() */
-#include <sys/time.h> /* gettimeofday() */
-
 #include <eggdrop/eggdrop.h>
-#include "egg_timer.h"
 
 /* From main.c */
 extern egg_timeval_t egg_timeval_now;
 
-/* Internal use only. */
-typedef struct egg_timer_b {
-	struct egg_timer_b *next;
-	int id;
-	Function callback;
-	void *client_data;
-	egg_timeval_t howlong;
-	egg_timeval_t trigger_time;
-	int flags;
-} egg_timer_t;
-
-/* We keep a sorted list of active timers. */
-static egg_timer_t *timer_list_head = NULL;
-static int timer_next_id = 1;
-
 static int script_single_timer(int nargs, int sec, int usec, script_callback_t *callback);
 static int script_repeat_timer(int nargs, int sec, int usec, script_callback_t *callback);
 static int script_timers(script_var_t *retval);
@@ -69,166 +49,6 @@
 	script_create_commands(script_cmds);
 }
 
-/* Based on TclpGetTime from Tcl 8.3.3 */
-int timer_get_time(egg_timeval_t *curtime)
-{
-	struct timeval tv;
-
-	(void) gettimeofday(&tv, NULL);
-	curtime->sec = tv.tv_sec;
-	curtime->usec = tv.tv_usec;
-	return(0);
-}
-
-/* Find difference between two timers. */
-int timer_diff(egg_timeval_t *from_time, egg_timeval_t *to_time, egg_timeval_t *diff)
-{
-	diff->sec = to_time->sec - from_time->sec;
-	if (diff->sec < 0) {
-		diff->sec = 0;
-		diff->usec = 0;
-		return(1);
-	}
-
-	diff->usec = to_time->usec - from_time->usec;
-
-	if (diff->usec < 0) {
-		if (diff->sec == 0) {
-			diff->usec = 0;
-			return(1);
-		}
-		diff->sec -= 1;
-		diff->usec += 1000000;
-	}
-
-	return(0);
-}
-
-static int timer_add_to_list(egg_timer_t *timer)
-{
-	egg_timer_t *prev, *ptr;
-
-	/* Find out where this should go in the list. */
-	prev = NULL;
-	for (ptr = timer_list_head; ptr; ptr = ptr->next) {
-		if (timer->trigger_time.sec < ptr->trigger_time.sec) break;
-		if (timer->trigger_time.sec == ptr->trigger_time.sec && timer->trigger_time.usec < ptr->trigger_time.usec) break;
-		prev = ptr;
-	}
-
-	/* Insert into timer list. */
-	if (prev) {
-		timer->next = prev->next;
-		prev->next = timer;
-	}
-	else {
-		timer->next = timer_list_head;
-		timer_list_head = timer;
-	}
-	return(0);
-}
-
-int timer_create_complex(egg_timeval_t *howlong, Function callback, void *client_data, int flags)
-{
-	egg_timer_t *timer;
-
-	/* Fill out a new timer. */
-	timer = (egg_timer_t *)malloc(sizeof(*timer));
-	timer->id = timer_next_id++;
-	timer->callback = callback;
-	timer->client_data = client_data;
-	timer->flags = flags;
-	timer->howlong.sec = howlong->sec;
-	timer->howlong.usec = howlong->usec;
-	timer->trigger_time.sec = egg_timeval_now.sec + howlong->sec;
-	timer->trigger_time.usec = egg_timeval_now.usec + howlong->usec;
-
-	timer_add_to_list(timer);
-
-	return(timer->id);
-}
-
-/* Destroy a timer, given an id. */
-int timer_destroy(int timer_id)
-{
-	egg_timer_t *prev, *timer;
-
-	prev = NULL;
-	for (timer = timer_list_head; timer; timer = timer->next) {
-		if (timer->id == timer_id) break;
-		prev = timer;
-	}
-
-	if (!timer) return(1); /* Not found! */
-
-	/* Unlink it. */
-	if (prev) prev->next = timer->next;
-	else timer_list_head = timer->next;
-
-	free(timer);
-	return(0);
-}
-
-int timer_destroy_all()
-{
-	egg_timer_t *timer, *next;
-
-	for (timer = timer_list_head; timer; timer = next) {
-		next = timer->next;
-		free(timer);
-	}
-	timer_list_head = NULL;
-	return(0);
-}
-
-int timer_get_shortest(egg_timeval_t *howlong)
-{
-	egg_timer_t *timer = timer_list_head;
-
-	/* No timers? Boo. */
-	if (!timer) return(1);
-
-	timer_diff(&egg_timeval_now, &timer->trigger_time, howlong);
-
-	return(0);
-}
-
-int timer_run()
-{
-	egg_timer_t *timer;
-	Function callback;
-	void *client_data;
-
-	while (timer_list_head) {
-		timer = timer_list_head;
-		if (timer->trigger_time.sec > egg_timeval_now.sec || (timer->trigger_time.sec == egg_timeval_now.sec && timer->trigger_time.usec > egg_timeval_now.usec)) break;
-
-		timer_list_head = timer_list_head->next;
-
-		callback = timer->callback;
-		client_data = timer->client_data;
-
-		if (timer->flags & TIMER_REPEAT) {
-			/* Update timer. */
-			timer->trigger_time.sec += timer->howlong.sec;
-			timer->trigger_time.usec += timer->howlong.usec;
-			if (timer->trigger_time.usec >= 1000000) {
-				timer->trigger_time.usec -= 1000000;
-				timer->trigger_time.sec += 1;
-			}
-
-			/* Add it back into the list. */
-			timer_add_to_list(timer);
-		}
-		else {
-			free(timer);
-		}
-
-		callback(client_data);
-	}
-	return(0);
-}
-
 static int script_timer(int sec, int usec, script_callback_t *callback, int flags)
 {
 	egg_timeval_t howlong;
@@ -266,18 +86,8 @@
 static int script_timers(script_var_t *retval)
 {
 	int *timers, ntimers;
-	egg_timer_t *timer;
 
-	/* Count timers. */
-	ntimers = 0;
-	for (timer = timer_list_head; timer; timer = timer->next) ntimers++;
-
-	/* Fill in array. */
-	timers = (int *)malloc(sizeof(int) * ntimers);
-	ntimers = 0;
-	for (timer = timer_list_head; timer; timer = timer->next) {
-		timers[ntimers++] = timer->id;
-	}
+	ntimers = timer_list(&timers);
 
 	/* A malloc'd array of ints. */
 	retval->type = SCRIPT_ARRAY | SCRIPT_FREE | SCRIPT_INTEGER;
@@ -288,48 +98,44 @@
 
 static int script_timer_info(script_var_t *retval, int timer_id)
 {
-	egg_timer_t *timer;
-	int *timer_info;
-	egg_timeval_t start_time, diff;
+	int *info;
+	egg_timeval_t howlong, trigger_time, start_time, diff;
 
-	for (timer = timer_list_head; timer; timer = timer->next) {
-		if (timer->id == timer_id) break;
-	}
-	if (!timer) {
+	if (timer_info(timer_id, &howlong, &trigger_time)) {
 		retval->type = SCRIPT_STRING | SCRIPT_ERROR;
 		retval->value = "Timer not found";
 		return(0);
 	}
 
 	/* We have 11 fields. */
-	timer_info = (int *)malloc(sizeof(int) * 11);
+	info = (int *)malloc(sizeof(int) * 11);
 
 	/* Timer id, when it started, initial timer length,
 		how long it's run already, how long until it triggers,
 		absolute time when it triggers. */
-	timer_info[0] = timer->id;
+	info[0] = timer_id;
 
-	timer_diff(&timer->howlong, &timer->trigger_time, &start_time);
-	timer_info[1] = start_time.sec;
-	timer_info[2] = start_time.usec;
+	timer_diff(&howlong, &trigger_time, &start_time);
+	info[1] = start_time.sec;
+	info[2] = start_time.usec;
 
-	timer_info[3] = timer->howlong.sec;
-	timer_info[4] = timer->howlong.usec;
+	info[3] = howlong.sec;
+	info[4] = howlong.usec;
 
 	timer_diff(&start_time, &egg_timeval_now, &diff);
-	timer_info[5] = diff.sec;
-	timer_info[6] = diff.usec;
+	info[5] = diff.sec;
+	info[6] = diff.usec;
 
-	timer_diff(&egg_timeval_now, &timer->trigger_time, &diff);
-	timer_info[7] = diff.sec;
-	timer_info[8] = diff.usec;
+	timer_diff(&egg_timeval_now, &trigger_time, &diff);
+	info[7] = diff.sec;
+	info[8] = diff.usec;
 
-	timer_info[9] = timer->trigger_time.sec;
-	timer_info[10] = timer->trigger_time.usec;
+	info[9] = trigger_time.sec;
+	info[10] = trigger_time.usec;
 
 	/* A malloc'd array of ints. */
 	retval->type = SCRIPT_FREE | SCRIPT_ARRAY | SCRIPT_INTEGER;
-	retval->value = timer_info;
+	retval->value = info;
 	retval->len = 11;
 
 	return(0);
Index: eggdrop1.7/src/main.c
diff -u eggdrop1.7/src/main.c:1.120 eggdrop1.7/src/main.c:1.121
--- eggdrop1.7/src/main.c:1.120	Tue Jun 18 01:12:32 2002
+++ eggdrop1.7/src/main.c	Thu Sep 19 21:06:25 2002
@@ -30,7 +30,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: main.c,v 1.120 2002/06/18 06:12:32 guppy Exp $";
+static const char rcsid[] = "$Id: main.c,v 1.121 2002/09/20 02:06:25 stdarg Exp $";
 #endif
 
 #include "main.h"
@@ -62,7 +62,6 @@
 #include "modules.h"
 #include "tandem.h"
 #include "bg.h"
-#include "egg_timer.h"
 #include "core_binds.h"
 #include "logfile.h"
 #include "misc.h"
@@ -562,7 +561,7 @@
   sigaction(SIGALRM, &sv, NULL);
 
   /* Initialize variables and stuff */
-  timer_get_time(&egg_timeval_now);
+  timer_update_now(&egg_timeval_now);
   now = egg_timeval_now.sec;
   chanset = NULL;
   memcpy(&nowtm, localtime(&now), sizeof(struct tm));
@@ -585,6 +584,7 @@
   logfile_init();
   timer_init();
   dns_init();
+  egg_dns_init();
   core_binds_init();
   dcc_init();
   user_init();
@@ -756,8 +756,9 @@
     /* Free unused structures. */
     /* garbage_collect(); */
 
+    sockbuf_update_all(0);
     xx = sockgets(buf, &i);
-    timer_get_time(&egg_timeval_now);
+    timer_update_now(&egg_timeval_now);
     if (xx >= 0) {		/* Non-error */
       int idx;
 
Index: eggdrop1.7/src/modules.c
diff -u eggdrop1.7/src/modules.c:1.117 eggdrop1.7/src/modules.c:1.118
--- eggdrop1.7/src/modules.c:1.117	Tue Jun 18 01:12:32 2002
+++ eggdrop1.7/src/modules.c	Thu Sep 19 21:06:25 2002
@@ -25,7 +25,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: modules.c,v 1.117 2002/06/18 06:12:32 guppy Exp $";
+static const char rcsid[] = "$Id: modules.c,v 1.118 2002/09/20 02:06:25 stdarg Exp $";
 #endif
 
 #include "main.h"		/* NOTE: when removing this, include config.h */
@@ -65,8 +65,6 @@
 #include "irccmp.h"		/* _irccmp, _ircncmp, _irctolower, 
 				   _irctoupper				*/
 #include "match.h"		/* wild_match				*/
-#include "egg_timer.h"		/* egg_timeval_now			*/
-				   
 
 
 #include <ctype.h>
Index: eggdrop1.7/src/net.c
diff -u eggdrop1.7/src/net.c:1.62 eggdrop1.7/src/net.c:1.63
--- eggdrop1.7/src/net.c:1.62	Sat Jun  1 08:27:46 2002
+++ eggdrop1.7/src/net.c	Thu Sep 19 21:06:25 2002
@@ -9,7 +9,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: net.c,v 1.62 2002/06/01 13:27:46 wingman Exp $";
+static const char rcsid[] = "$Id: net.c,v 1.63 2002/09/20 02:06:25 stdarg Exp $";
 #endif
 
 #include <fcntl.h>
@@ -30,7 +30,6 @@
 #include <setjmp.h>
 
 #include "lib/adns/adns.h"
-#include "egg_timer.h"
 #include "logfile.h"
 #include "dns.h"
 #include "dccutil.h"			/* dprintf_eggdrop		*/
Index: eggdrop1.7/src/tclhash.c
diff -u eggdrop1.7/src/tclhash.c:1.73 eggdrop1.7/src/tclhash.c:1.74
--- eggdrop1.7/src/tclhash.c:1.73	Sun Aug 11 20:16:31 2002
+++ eggdrop1.7/src/tclhash.c	Thu Sep 19 21:06:25 2002
@@ -28,7 +28,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: tclhash.c,v 1.73 2002/08/12 01:16:31 stdarg Exp $";
+static const char rcsid[] = "$Id: tclhash.c,v 1.74 2002/09/20 02:06:25 stdarg Exp $";
 #endif
 
 #include "main.h"
@@ -39,7 +39,6 @@
 #include "userrec.h"		/* touch_laston			*/
 #include "match.h"		/* wild_match_per		*/
 #include "tclhash.h"		/* prototypes			*/
-#include "egg_timer.h"
 
 extern struct dcc_t *dcc;
 extern int dcc_total;
Index: eggdrop1.7/src/userrec.c
diff -u eggdrop1.7/src/userrec.c:1.50 eggdrop1.7/src/userrec.c:1.51
--- eggdrop1.7/src/userrec.c:1.50	Mon Jun 17 11:39:38 2002
+++ eggdrop1.7/src/userrec.c	Thu Sep 19 21:06:25 2002
@@ -25,7 +25,7 @@
  */
 
 #ifndef lint
-static const char rcsid[] = "$Id: userrec.c,v 1.50 2002/06/17 16:39:38 guppy Exp $";
+static const char rcsid[] = "$Id: userrec.c,v 1.51 2002/09/20 02:06:25 stdarg Exp $";
 #endif
 
 #include <sys/stat.h>
@@ -104,7 +104,7 @@
   return buf;
 }
 
-struct userrec *check_dcclist_hand(char *handle)
+struct userrec *check_dcclist_hand(const char *handle)
 {
   int i;
 
@@ -114,15 +114,12 @@
   return NULL;
 }
 
-struct userrec *get_user_by_handle(struct userrec *bu, char *handle)
+struct userrec *get_user_by_handle(struct userrec *bu, const char *handle)
 {
   struct userrec *u, *ret;
 
   if (!handle)
     return NULL;
-  /* FIXME: This should be done outside of this function. */
-  /*        handle might and should be const */
-  rmspace(handle);
   if (!handle[0] || (handle[0] == '*'))
     return NULL;
   if (bu == userlist) {
Index: eggdrop1.7/src/userrec.h
diff -u eggdrop1.7/src/userrec.h:1.2 eggdrop1.7/src/userrec.h:1.3
--- eggdrop1.7/src/userrec.h:1.2	Sun May  5 11:40:39 2002
+++ eggdrop1.7/src/userrec.h	Thu Sep 19 21:06:25 2002
@@ -19,7 +19,7 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 /*
- * $Id: userrec.h,v 1.2 2002/05/05 16:40:39 tothwolf Exp $
+ * $Id: userrec.h,v 1.3 2002/09/20 02:06:25 stdarg Exp $
  */
 
 #ifndef _EGG_USERREC_H
@@ -42,7 +42,7 @@
 void correct_handle(char *);
 int write_user(struct userrec *u, FILE * f, int shr);
 void write_userfile(int);
-struct userrec *check_dcclist_hand(char *);
+struct userrec *check_dcclist_hand(const char *);
 void touch_laston(struct userrec *, char *, time_t);
 void user_del_chan(char *);
 char *fixfrom(char *);
Index: eggdrop1.7/src/users.h
diff -u eggdrop1.7/src/users.h:1.13 eggdrop1.7/src/users.h:1.14
--- eggdrop1.7/src/users.h:1.13	Sun May 12 10:35:44 2002
+++ eggdrop1.7/src/users.h	Thu Sep 19 21:06:25 2002
@@ -22,7 +22,7 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 /*
- * $Id: users.h,v 1.13 2002/05/12 15:35:44 ite Exp $
+ * $Id: users.h,v 1.14 2002/09/20 02:06:25 stdarg Exp $
  */
 
 #ifndef _EGG_USERS_H
@@ -166,6 +166,8 @@
   struct user_entry *entries;
 };
 
+typedef struct userrec user_t;
+
 struct igrec {
   struct igrec *next;
   char *igmask;
@@ -184,7 +186,8 @@
  */
 
 struct userrec *adduser();
-struct userrec *get_user_by_handle(struct userrec *, char *);
+struct userrec *get_user_by_handle(struct userrec *, const char *);
+user_t *get_user_authed(char *handle, char *pass);
 struct userrec *get_user_by_host(char *);
 struct userrec *get_user_by_nick(char *);
 struct userrec *check_chanlist();
Index: eggdrop1.7/testcode/dnscache.c
diff -u eggdrop1.7/testcode/dnscache.c:1.1 eggdrop1.7/testcode/dnscache.c:1.2
--- eggdrop1.7/testcode/dnscache.c:1.1	Fri Aug  9 18:48:18 2002
+++ eggdrop1.7/testcode/dnscache.c	Thu Sep 19 21:06:25 2002
@@ -4,11 +4,17 @@
 #include <netinet/in.h>
 #include "my_socket.h"
 
-typedef struct {
-	char *host;
-	char *ip;
-	int expiration;
-} dns_entry_t;
+#define DNS_IPV4	1
+#define DNS_IPV6	2
+#define DNS_REVERSE	3
+
+typedef struct dns_query {
+	struct dns_query *next;
+	char *query;
+	int id;
+	int (*callback)(void *client_data, const char *query, const char *result);
+	void *client_data;
+} dns_query_t;
 
 typedef struct {
 	unsigned short id;
@@ -28,46 +34,114 @@
 	/* char rdata[]; */
 } dns_rr_t;
 
+/* Entries from resolv.conf */
+typedef struct dns_server {
+	char *ip;
+	int idx;
+} dns_server_t;
+
+/* Entries from hosts */
+typedef struct {
+	char *host, *ip;
+} dns_host_t;
+
 static int query_id = 1;
 static dns_header_t _dns_header = {0};
-static dns_entry_t *dns_cache = NULL;
-static int dns_cache_len;
+static dns_query_t *query_head = NULL;
+static dns_host_t *hosts = NULL;
+static int nhosts = 0;
+static dns_server_t *servers = NULL;
+static int nservers = 0;
+static int curserver = -1;
+
+static char separators[] = " ,\t";
 
-static char **nameservers = NULL;
+static void read_resolv(char *fname);
+static void read_hosts(char *fname);
 
-/* Read in ~/.hosts and /etc/hosts and ~/.resolv.conf and /etc/resolv.conf */
+/* Read in .hosts and /etc/hosts and .resolv.conf and /etc/resolv.conf */
 int dns_init()
 {
+	FILE *fp;
 	_dns_header.flags = htons(1 << 8 | 1 << 7);
 	_dns_header.question_count = htons(1);
+	read_resolv("/etc/resolv.conf");
+	read_resolv(".resolv.conf");
+	read_hosts("/etc/hosts");
+	read_hosts(".hosts");
 	return(0);
 }
 
-static char *search_cache_by_host(char *host)
+const char *dns_next_server()
 {
-	int i;
-	for (i = 0; i < dns_cache_len; i++) {
-		if (!strcasecmp(dns_cache[i].host, host)) return(dns_cache[i].ip);
-	}
-	return(NULL);
+	static int cur_server = 0;
+
+	if (!servers || nservers < 1) return("127.0.0.1");
+	if (cur_server >= nservers) cur_server = 0;
+	return(servers[cur_server].ip);
 }
 
-static char *search_cache_by_ip(char *ip)
+static void add_server(char *ip)
 {
-	int i;
-	for (i = 0; i < dns_cache_len; i++) {
-		if (!strcasecmp(dns_cache[i].ip, ip)) return(dns_cache[i].host);
+	servers = (dns_server_t *)realloc(servers, (nservers+1)*sizeof(*servers));
+	servers[nservers].ip = strdup(ip);
+	servers[nservers].idx = -1;
+	nservers++;
+}
+
+static void add_host(char *host, char *ip)
+{
+	hosts = (dns_host_t *)realloc(hosts, (nhosts+1)*sizeof(*hosts));
+	hosts[nhosts].host = strdup(host);
+	hosts[nhosts].ip = strdup(ip);
+	nhosts++;
+}
+
+static int read_thing(char *buf, char *ip)
+{
+	int skip, len;
+
+	skip = strspn(buf, separators);
+	buf += skip;
+	len = strcspn(buf, separators);
+	memcpy(ip, buf, len);
+	ip[len] = 0;
+	return(skip + len);
+}
+
+static void read_resolv(char *fname)
+{
+	FILE *fp;
+	char buf[512], ip[512];
+
+	fp = fopen(fname, "r");
+	if (!fp) return;
+	while (fgets(buf, sizeof(buf), fp)) {
+		if (!strncasecmp(buf, "nameserver", 10)) {
+			read_thing(buf+10, ip);
+			if (strlen(ip)) add_server(ip);
+		}
 	}
-	return(NULL);
+	fclose(fp);
 }
 
-static void add_cache_entry(char *host, char *ip, int expires)
+static void read_hosts(char *fname)
 {
-	dns_cache = (dns_entry_t *)realloc(dns_cache, (dns_cache_len+1) * sizeof(dns_entry_t));
-	dns_cache[dns_cache_len].host = strdup(host);
-	dns_cache[dns_cache_len].ip = strdup(ip);
-	dns_cache[dns_cache_len].expires = expires;
-	dns_cache_len++;
+	FILE *fp;
+	char buf[512], ip[512], host[512];
+	int skip, n;
+
+	fp = fopen(fname, "r");
+	if (!fp) return;
+	while (fgets(buf, sizeof(buf), fp)) {
+		if (strchr(buf, '#')) continue;
+		skip = read_thing(buf, ip);
+		if (!strlen(ip)) continue;
+		while (n = read_thing(buf+skip, host)) {
+			skip += n;
+			if (strlen(host)) add_host(ip, host);
+		}
+	}
 }
 
 static int make_header(char *buf, int id)
@@ -101,27 +175,89 @@
 	return(query-orig);
 }
 
-static int make_query(char *host, int type, unsigned char *buf)
+static int reverse_ip(char *host, char *reverse)
+{
+	char *period;
+	int offset, len;
+
+	printf("reversing %s\n", host);
+	period = strchr(host, '.');
+	if (!period) {
+		len = strlen(host);
+		memcpy(reverse, host, len);
+		return(len);
+	}
+	else {
+		len = period - host;
+		offset = reverse_ip(host+len+1, reverse);
+		reverse[offset++] = '.';
+		memcpy(reverse+offset, host, len);
+		reverse[offset+len] = 0;
+		return(offset+len);
+	}
+}
+
+int dns_make_query(char *host, int type, char **buf, int *query_len, int (*callback)(), void *client_data)
 {
+	char *newhost = NULL;
 	int len = 0;
 	int ns_type = 0;
+	dns_query_t *q;
+
+	if (type == DNS_IPV4) ns_type = 1; /* IPv4 */
+	else if (type == DNS_IPV6) ns_type = 28; /* IPv6 */
+	else if (type == DNS_REVERSE) {
+		/* We need to transform the ip address into the proper form
+		 * for reverse lookup. */
+		newhost = (char *)malloc(strlen(host) + 14);
+		reverse_ip(host, newhost);
+		strcat(newhost, ".in-addr.arpa");
+		printf("newhost: %s\n", newhost);
+		host = newhost;
+		ns_type = 12; /* PTR (reverse lookup) */
+	}
+	else return(-1);
+
+	*buf = (char *)malloc(strlen(host) + 512);
+	len = make_header(*buf, query_id);
+	len += cut_host(host, *buf + len);
+	(*buf)[len] = 0; len++; (*buf)[len] = ns_type; len++;
+	(*buf)[len] = 0; len++; (*buf)[len] = 1; len++;
+	if (newhost) free(newhost);
+	*query_len = len;
+
+	q = calloc(1, sizeof(*q));
+	q->id = query_id;
+	query_id++;
+	q->callback = callback;
+	q->client_data = client_data;
+	if (query_head) q->next = query_head->next;
+	query_head = q;
+	return(q->id);
+}
+
+static int dns_cancel_query(int id, int issue_callback)
+{
+	dns_query_t *q, *prev;
+
+	prev = NULL;
+	for (q = query_head; q; q = q->next) {
+		if (q->id == id) break;
+		prev = q;
+	}
+	if (!q) return(-1);
+	if (prev) prev->next = q->next;
+	else query_head = q->next;
 
-	if (type == IPV4_QUERY) ns_type = 1; /* IPv4 */
-	else if (type == IPV6_QUERY) ns_type = 28; /* IPv6 */
-	else if (type == REVERSE_QUERY) ns_type = 12; /* PTR (reverse lookup) */
-	else return(0);
-
-	len = make_header(buf, query_id++);
-	len += cut_host(host, buf + len);
-	buf[len] = 0; len++; buf[len] = ns_type; len++;
-	buf[len] = 0; len++; buf[len] = 1; len++;
-	return(len);
+	if (issue_callback) q->callback(q->client_data, q->query, NULL);
+	free(q);
+	return(0);
 }
 
-static int skip_name(unsigned char *ptr, char *end)
+static int skip_name(char *ptr, char *end)
 {
 	int len;
-	unsigned char *start = ptr;
+	char *start = ptr;
 
 	while ((len = *ptr++) > 0) {
 		if (len > 63) {
@@ -135,23 +271,32 @@
 	return(ptr - start);
 }
 
-static int got_answer(int id, char *answer)
+static void got_answer(int id, char *answer)
 {
-	int i;
+	dns_query_t *q, *prev;
 
-	for (i = 0; i < nquestions; i++) {
-		if (questions[i].id == id) break;
+	printf("got_answer for id %d: %s\n", id, answer);
+	prev = NULL;
+	for (q = query_head; q; q = q->next) {
+		if (q->id == id) break;
+		prev = q;
 	}
-	if (i == nquestions) break;
+	if (!q) return;
+
+	if (prev) prev->next = q->next;
+	else query_head = q->next;
 
+	q->callback(q->client_data, q->query, answer);
+	free(q->query);
+	free(q);
 }
 
-static void parse_reply(unsigned char *response, int nbytes)
+static void parse_reply(char *response, int nbytes)
 {
 	dns_header_t header;
 	dns_rr_t reply;
 	char result[512];
-	unsigned char *ptr, *end;
+	char *ptr, *end;
 	int i;
 
 	ptr = response;
@@ -176,20 +321,22 @@
 		reply.rdlength = ntohs(reply.rdlength);
 		ptr += 10;
 		if (reply.type == 1) {
-			printf("ipv4 reply\n");
+			//printf("ipv4 reply\n");
 			inet_ntop(AF_INET, ptr, result, 512);
-			if (got_answer(header.id, result)) break;
+			got_answer(header.id, result);
+			return;
 		}
 		else if (reply.type == 28) {
-			printf("ipv6 reply\n");
+			//printf("ipv6 reply\n");
 			inet_ntop(AF_INET6, ptr, result, 512);
-			if (got_answer(header.id, result)) break;
+			got_answer(header.id, result);
+			return;
 		}
 		else if (reply.type == 12) {
 			char *placeholder;
 			int len, dot;
 
-			printf("reverse-lookup reply\n");
+			//printf("reverse-lookup reply\n");
 			placeholder = ptr;
 			result[0] = 0;
 			while ((len = *ptr++) != 0) {
@@ -209,6 +356,7 @@
 			if (strlen(result)) {
 				result[strlen(result)-1] = 0;
 				got_answer(header.id, result);
+				return;
 			}
 			ptr = placeholder;
 		}
@@ -217,27 +365,32 @@
 	got_answer(header.id, NULL);
 }
 
+int dns_lookup(const char *host, int (*callback)())
+{
+}
+
 main (int argc, char *argv[])
 {
-	unsigned char query[512], response[512], *ptr, buf[512];
+	char *query, response[512], *ptr, buf[512];
 	int i, len, sock;
 	struct sockaddr_in server;
 	dns_header_t header;
 	dns_rr_t reply;
 	unsigned long addr;
 
-	if (argc != 4) {
-		printf("usage: %s <dns ip> <host> <type>\n", argv[0]);
+	if (argc != 3) {
+		printf("usage: %s <host> <type>\n", argv[0]);
 		printf("  <type> can be 1 (ipv4), 2 (ipv4), or 3 (reverse lookup)\n");
 		return(0);
 	}
 
+	dns_init();
+	if (!nservers) return(0);
 	server.sin_family = AF_INET;
 	server.sin_port = htons(53);
-	server.sin_addr.s_addr = inet_addr(argv[1]);
+	server.sin_addr.s_addr = inet_addr(servers[0].ip);
 
-	dns_init();
-	len = make_query(argv[2], atoi(argv[3]), query);
+	len = dns_make_query(argv[1], atoi(argv[2]), &query);
 
 	sock = socket(AF_INET, SOCK_DGRAM, 0);
 
@@ -246,8 +399,14 @@
 		return(1);
 	}
 
-	connect(sock, &server, sizeof(server));
+	connect(sock, (struct sockaddr *)&server, sizeof(server));
+	write(sock, query, len);
+	len = read(sock, response, 512);
+	printf("parsing reply, %d bytes\n", len);
+	parse_reply(response, len);
 	write(sock, query, len);
 	len = read(sock, response, 512);
+	printf("parsing next reply, %d bytes\n", len);
 	parse_reply(response, len);
+	return(0);
 }
Index: eggdrop1.7/testcode/socks5.c
diff -u eggdrop1.7/testcode/socks5.c:1.2 eggdrop1.7/testcode/socks5.c:1.3
--- eggdrop1.7/testcode/socks5.c:1.2	Tue Jun 18 23:51:54 2002
+++ eggdrop1.7/testcode/socks5.c	Thu Sep 19 21:06:25 2002
@@ -117,7 +117,7 @@
 		ulen = strlen(info->username) % 255;
 		plen = strlen(info->password) % 255;
 
-		buf[0] = 5;
+		buf[0] = 1;
 		buf[1] = ulen;
 		memcpy(buf+2, info->username, ulen);
 		buf[2+ulen] = plen;
@@ -240,7 +240,7 @@
 static int socks5_on_connect(void *client_data, int idx, const char *peer_ip, int peer_port)
 {
 	proxy_info_t *info = client_data;
-	char buf[] = "\005\002\001\000";
+	char buf[] = "\005\002\002\000";
 
 	printf("socks5 connected\n");
 	/* Send the accepted auth methods (user/pass and none). */
----------------------- End of diff -----------------------



More information about the Changes mailing list