diff -Nur irc2.10.3p7/common/common_def.h irc2.10.3p7+hemp2+DK+B5/common/common_def.h
--- irc2.10.3p7/common/common_def.h	Fri Feb  5 00:26:35 1999
+++ irc2.10.3p7+hemp2+DK+B5/common/common_def.h	Tue May 11 15:25:01 2004
@@ -54,6 +54,7 @@
 #define PUNCT 8
 #define DIGIT 16
 #define SPACE 32
+#define VALID 64
 
 #define isalpha(c) (char_atribs[(u_char)(c)]&ALPHA)
 #define isspace(c) (char_atribs[(u_char)(c)]&SPACE)
@@ -74,6 +75,9 @@
 #define isgraph(c) ((char_atribs[(u_char)(c)]&PRINT) && \
 		    ((u_char)(c) != (u_char)0x20))
 #define ispunct(c) (!(char_atribs[(u_char)(c)]&(CNTRL|ALPHA|DIGIT)))
+#ifdef	RESTRICT_USERNAMES
+#define isvaliduser(c) (char_atribs[(u_char)(c)]&VALID)
+#endif
 
 #ifdef DEBUGMODE
 # define Debug(x) debug x
diff -Nur irc2.10.3p7/common/match.c irc2.10.3p7+hemp2+DK+B5/common/match.c
--- irc2.10.3p7/common/match.c	Wed Jul  4 23:44:40 2001
+++ irc2.10.3p7+hemp2+DK+B5/common/match.c	Tue May 11 15:25:01 2004
@@ -110,34 +110,37 @@
 /* 16-23 */	CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL,
 /* 24-31 */	CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL,
 /* space */	PRINT|SPACE,
-/* !"#$%&'( */	PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT,
-/* )*+,-./ */	PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT,
-/* 0123 */	PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT,
-/* 4567 */	PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT,
-/* 89:; */	PRINT|DIGIT, PRINT|DIGIT, PRINT, PRINT,
-/* <=>? */	PRINT, PRINT, PRINT, PRINT,
-/* @ */		PRINT,
-/* ABC */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* DEF */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* GHI */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* JKL */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* MNO */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* PQR */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* STU */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* VWX */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* YZ[ */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* \]^ */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* _`  */	PRINT, PRINT,
-/* abc */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* def */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* ghi */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* jkl */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* mno */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* pqr */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* stu */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* vwx */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* yz{ */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
-/* \}~ */	PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* !"#$ */	PRINT, PRINT, PRINT, PRINT,
+/* %&'( */	PRINT, PRINT, PRINT, PRINT,
+/* )*+ */	PRINT, PRINT, PRINT,
+/* ,-. */	PRINT, PRINT|VALID, PRINT|VALID,
+/* /01 */	PRINT, PRINT|DIGIT|VALID, PRINT|DIGIT|VALID,
+/* 234 */	PRINT|DIGIT|VALID, PRINT|DIGIT|VALID, PRINT|DIGIT|VALID,
+/* 567 */	PRINT|DIGIT|VALID, PRINT|DIGIT|VALID, PRINT|DIGIT|VALID,
+/* 89: */	PRINT|DIGIT|VALID, PRINT|DIGIT|VALID, PRINT,
+/* ;<= */	PRINT, PRINT, PRINT,
+/* >?@ */	PRINT, PRINT, PRINT,
+/* ABC */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* DEF */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* GHI */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* JKL */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* MNO */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* PQR */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* STU */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* VWX */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* YZ[ */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* \]^ */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA,
+/* _`  */	PRINT|VALID,PRINT,
+/* abc */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* def */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* ghi */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* jkl */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* mno */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* pqr */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* stu */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* vwx */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* yz{ */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID,
+/* \}~ */	PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA,
 /* del */	0,
 /* 80-8f */	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 /* 90-9f */	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
diff -Nur irc2.10.3p7/common/msg_def.h irc2.10.3p7+hemp2+DK+B5/common/msg_def.h
--- irc2.10.3p7/common/msg_def.h	Wed Feb 25 17:28:48 2004
+++ irc2.10.3p7+hemp2+DK+B5/common/msg_def.h	Tue May 11 15:25:01 2004
@@ -32,6 +32,12 @@
 #define MSG_QUIT     "QUIT"	/* QUIT */
 #define MSG_SQUIT    "SQUIT"	/* SQUI */
 #define MSG_KILL     "KILL"	/* KILL */
+#if defined(OPER_KLINE) || defined(LOCOP_KLINE)
+#define MSG_KLINE    "KLINE"	/* KLIN */
+#endif
+#if defined(OPER_TKLINE) || defined(LOCOP_TKLINE)
+#define MSG_TKLINE   "TKLINE"	/* TKLI */
+#endif
 #define MSG_INFO     "INFO"	/* INFO */
 #define MSG_LINKS    "LINKS"	/* LINK */
 #define MSG_SUMMON   "SUMMON"	/* SUMM */
@@ -74,5 +80,10 @@
 #define	MSG_HASH     "HAZH"	/* HASH */
 #define	MSG_DNS      "DNS"	/* DNS  -> DNSS */
 #define	MSG_POST     "POST"
-
-#define MAXPARA    15 
+#ifdef SERVER_MAP
+#define MSG_MAP                "MAP"
+#endif
+#ifdef OPER_SET
+#define MSG_SET               "SET"   /* SET */
+#endif
+#define MAXPARA    15
diff -Nur irc2.10.3p7/common/numeric_def.h irc2.10.3p7+hemp2+DK+B5/common/numeric_def.h
--- irc2.10.3p7/common/numeric_def.h	Sat Feb 10 20:11:05 2001
+++ irc2.10.3p7+hemp2+DK+B5/common/numeric_def.h	Tue May 11 15:25:01 2004
@@ -123,8 +123,18 @@
 #define	RPL_YOURHOST         002
 #define	RPL_CREATED          003
 #define	RPL_MYINFO           004
+#ifdef SEND_ISUPPORT
+#define RPL_ISUPPORT	     005
+#define RPL_BOUNCE	      10
+#else
 #define	RPL_BOUNCE           005
-
+#endif
+#ifdef SERVER_MAP
+#define RPL_MAP               15        /* Undernet extension */
+#define RPL_MAPMORE	      16        /* Undernet extension */
+#define RPL_MAPEND	      17        /* Undernet extension */
+#define RPL_MAPSTART	      18        /* +hemp */
+#endif
 /*
  * Errors are in the range from 400-599 currently and are grouped by what
  * commands they come from.
@@ -195,6 +205,10 @@
 #define ERR_NOOPERHOST       491
 #define ERR_NOSERVICEHOST    492
 
+#ifdef NOSTATSK
+#define ERR_STATSKLINE       499
+#endif
+
 #define ERR_UMODEUNKNOWNFLAG 501
 #define ERR_USERSDONTMATCH   502
 
@@ -232,6 +246,7 @@
 
 #define RPL_NOTOPIC          331
 #define RPL_TOPIC            332
+#define RPL_TOPICWHOTIME     333
 
 #define RPL_INVITING         341
 #define	RPL_SUMMONING        342
@@ -299,7 +314,7 @@
 #define RPL_STATSQLINE       217
 #define RPL_STATSYLINE       218
 #define RPL_ENDOFSTATS       219
-
+#define RPL_STATSPLINE	     220
 #define RPL_UMODEIS          221
 
 #define RPL_SERVICEINFO      231
@@ -335,3 +350,5 @@
 #define	RPL_TRACEEND         262
 #define	RPL_TRYAGAIN         263
 
+#define RPL_LOCALUSERS       265
+#define RPL_GLOBALUSERS      266
diff -Nur irc2.10.3p7/common/parse.c irc2.10.3p7+hemp2+DK+B5/common/parse.c
--- irc2.10.3p7/common/parse.c	Thu Feb 26 20:51:31 2004
+++ irc2.10.3p7+hemp2+DK+B5/common/parse.c	Tue May 11 15:25:01 2004
@@ -64,6 +64,12 @@
   { MSG_KILL,    m_kill,     MAXPARA, MSG_LAG|MSG_REG|MSG_NOU, 0, 0, 0L},
 #endif
 #ifndef CLIENT_COMPILE
+#if	defined(OPER_KLINE) || defined(LOCOP_KLINE)
+  { MSG_KLINE,   m_kline,    MAXPARA, MSG_LAG|MSG_REG|MSG_OP|MSG_LOP, 0,0, 0L},
+#endif
+#if defined(OPER_TKLINE) || defined(LOCOP_TKLINE)
+  { MSG_TKLINE,  m_tkline,   MAXPARA, MSG_LAG|MSG_REG|MSG_OP|MSG_LOP, 0,0, 0L},
+#endif
   { MSG_USER,    m_user,     MAXPARA, MSG_LAG|MSG_NOU, 0, 0, 0L},
   { MSG_AWAY,    m_away,     MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
   { MSG_UMODE,   m_umode,    MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
@@ -121,6 +127,12 @@
 # endif
 					, 0, 0, 0L},
 #endif
+#ifdef SERVER_MAP
+  { MSG_MAP,  m_map,   		MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+#endif
+#ifdef OPER_SET
+  { MSG_SET,  m_set,		MAXPARA, MSG_LAG|MSG_REGU|MSG_OP|MSG_LOP , 0, 0, 0L},
+#endif
   { MSG_POST,    m_post,     MAXPARA, MSG_NOU, 0, 0, 0L},
 #endif /* !CLIENT_COMPILE */
   { (char *) 0, (int (*)()) 0, 0, 0, 0, 0, 0L}
@@ -173,6 +185,71 @@
 	return acptr;
     }
 
+aClient *find_matching_client(mask,cptr)
+char *mask;
+Reg	aClient *cptr;
+{
+	aClient *acptr = cptr;
+	Reg char *ch;
+	int wild = 0;
+	
+	/* try to find exact match */	
+	acptr = find_client(mask,NULL);
+	if (!acptr)
+	{
+		aServer *asptr;
+		int wild = 0, dot = 0;
+		/* check if we should check against wilds */
+		for (ch = mask; *ch; ch++)
+		{
+			if (*ch == '*' || *ch == '?')
+			{
+				wild = 1;
+				break;
+			}
+			if (*ch == '.')
+			{
+				dot = 1;
+				break;
+			}
+		}
+		
+		if (!wild && !dot)
+		{
+			return cptr;
+		}
+		(void) collapse(mask);
+		
+		/* try to match some servername against mask */
+		for (asptr = svrtop; asptr; asptr = asptr->nexts)
+		{
+			if (!match(asptr->bcptr->name,mask) ||
+			    !match(mask,asptr->bcptr->name))
+			{
+				acptr = asptr->bcptr;
+				break;
+			}
+		}
+		
+		/* no match, try services */
+		if (!acptr)
+		{
+			aService *sp;
+			for (sp = svctop;sp;sp = sp->nexts)
+			{
+				if (!match(sp->bcptr->name,mask) ||
+				    !match(mask,sp->bcptr->name))
+				{
+					acptr = sp->bcptr;
+					break;
+				}
+			}
+		}
+
+	}
+
+	return acptr ? acptr : cptr;	
+}
 #else /* CLIENT_COMPILE */
 
 aClient *find_client(name, cptr)
@@ -190,7 +267,7 @@
 	return cptr;
     }
 #endif /* CLIENT_COMPILE */
-
+#ifndef CLIENT_COMPILE
 /*
 **  Find a user@host (server or user).
 **
@@ -209,20 +286,39 @@
 
 	*count = 0;
 	if (user)
-		for (c2ptr = client; c2ptr; c2ptr = c2ptr->next) 
-		    {
-			if (!MyClient(c2ptr)) /* implies mine and a user */
-				continue;
-			if ((!host || !match(host, c2ptr->user->host)) &&
-			     mycmp(user, c2ptr->user->username) == 0)
-			    {
-				(*count)++;
-				res = c2ptr;
-			    }
-		    }
+	{
+		if (host)
+		{
+			anUser *auptr;
+			for (auptr = hash_find_hostname(host,NULL); auptr; auptr = auptr->hnext)
+			{
+				if (MyConnect(auptr->bcptr) && !mycmp(user,auptr->username))
+				{
+					(*count)++;
+					res = auptr->bcptr;
+				}
+			}
+		}
+		else
+		{
+			int i;
+			for (i = 0; i <= highest_fd; i++)
+			{
+				if (!(c2ptr = local[i]) || !IsRegisteredUser(c2ptr))
+				{
+					continue;
+				}
+				if (!mycmp(user,c2ptr->user->username))
+				{
+					(*count)++;
+					res = c2ptr;
+				}
+			}
+	    }
+	}
 	return res;
     }
-
+#endif /* !CLIENT_COMPILE */
 /*
 **  Find server by name.
 **
@@ -766,7 +862,12 @@
 	if (index(sender, '.') /* <- buggy, it could be a service! */
 	    && !index(sender, '@')) /* better.. */
 	    {
-		sendto_flag(SCH_LOCAL, "Squitting unknown %s brought by %s.",
+#ifdef LOCAL_REJECTIONS_ONLY
+			sendto_flag(SCH_NOTICE,
+#else
+			sendto_flag(SCH_LOCAL, 
+#endif
+			"Squitting unknown %s brought by %s.",
 			    sender, get_client_name(cptr, FALSE));
 		sendto_one(cptr, ":%s SQUIT %s :(Unknown from %s)",
 			   me.name, sender, get_client_name(cptr, FALSE));
@@ -781,7 +882,12 @@
 	 * if we get here and sender is a service, we should probably issue
 	 * a kill in this case! -krys
 	 */
-		sendto_flag(SCH_LOCAL, "Dropping unknown %s brought by %s.",
+#ifdef LOCAL_REJECTIONS_ONLY
+	sendto_flag(SCH_NOTICE,
+#else
+	sendto_flag(SCH_LOCAL,
+#endif
+		"Dropping unknown %s brought by %s.",
 			    sender, get_client_name(cptr, FALSE));
 }
 #endif
diff -Nur irc2.10.3p7/common/parse_ext.h irc2.10.3p7+hemp2+DK+B5/common/parse_ext.h
--- irc2.10.3p7/common/parse_ext.h	Wed Sep  3 19:45:17 1997
+++ irc2.10.3p7+hemp2+DK+B5/common/parse_ext.h	Tue May 11 15:25:01 2004
@@ -44,6 +44,7 @@
 EXTERN aClient *find_mask __P((char *name, aClient *cptr));
 EXTERN aServer *find_tokserver __P((int token, aClient *cptr, aClient *c2ptr));
 EXTERN aClient *find_name __P((char *name, aClient *cptr));
+EXTERN aClient *find_matching_client __P((char *mask, aClient *cptr));
 #else /* CLIENT_COMPILE */
 EXTERN aClient *find_client __P((char *name, aClient *cptr));
 EXTERN aClient *find_server __P((char *name, aClient *cptr));
diff -Nur irc2.10.3p7/common/send.c irc2.10.3p7+hemp2+DK+B5/common/send.c
--- irc2.10.3p7/common/send.c	Sat Oct 11 03:09:36 2003
+++ irc2.10.3p7+hemp2+DK+B5/common/send.c	Tue May 11 15:25:01 2004
@@ -1391,6 +1391,9 @@
 	{ SCH_SERVICE,	"&SERVICES",	NULL },
 	{ SCH_DEBUG,	"&DEBUG",	NULL },
 	{ SCH_AUTH,	"&AUTH",	NULL },
+#ifdef CLIENTS_CHANNEL
+	{ SCH_CLIENTS,	"&CLIENTS",	NULL },
+#endif
 };
 
 
@@ -1515,6 +1518,12 @@
 	** And the rest... just count, I got 154 --Beeth
 	*/
 	char	linebuf[1500];
+#ifdef LOG_IP
+        char    *rip,*lip;
+#ifndef INET6
+        char    tip[18];
+#endif
+#endif /* LOG_IP */
 	/*
 	** This is a potential buffer overflow.
 	** I mean, when you manage to keep ircd
@@ -1522,6 +1531,9 @@
 	*/
 	char	buf[12];
 	int	logfile;
+#ifdef LOG_IP
+        u_short rport,lport;
+#endif /* LOG_IP */
 
 	logfile = msg ? connlog : userlog;
 
@@ -1543,15 +1555,63 @@
 			(int) (duration % 60));
 	}
 
+#ifdef LOG_IP
+        /*-
+         * New connection log format after looooong discussion:
+         *    [ident@remoteip#remoteport,localip#localport]
+         * --Yegg, 2001-05-09
+         */
+        lport = cptr->acpt != NULL ? cptr->acpt->port : 0;
+        rport = cptr->port;
+
+#ifdef INET6
+        lip = cptr->acpt != NULL ? inetntop(AF_INET6, (char *)&cptr->acpt->ip,
+                       mydummy, MYDUMMY_SIZE) : "<unknown>";
+        rip = inetntop(AF_INET6, (char *)&cptr->ip,
+                       mydummy2, MYDUMMY_SIZE);
+#else
+        if (cptr->acpt != NULL)
+        {
+                lip = inetntoa((char *)&cptr->acpt->ip);
+                strncpyzt(tip, lip, 18);
+                lip = tip;
+        }
+        else
+        {
+                lip = "<unknown>";
+        }
+        rip = inetntoa((char *)&cptr->ip);
+#endif
+
+#endif /* LOG_IP */
+
 	/*
 	** Aha, cptr->firsttime is time when user connected,
 	** so we syslog() it anyway. I'm waving big
 	** "rewrite log format" flag --Beeth.
 	*/
 	(void)sprintf(linebuf,
-		"%s (%s): %s@%s [%s] %c %lu %luKb %lu %luKb\n",
+#ifndef LOG_IP
+#ifdef LOG_IRCNAME
+                "%s (%s): %s@%s [%s] [%s] %c %lu %luKb %lu %luKb\n",
+#else
+                "%s (%s): %s@%s [%s] %c %lu %luKb %lu %luKb\n",
+#endif
+#else /* LOG_IP */
+#ifdef LOG_IRCNAME
+                "%s (%s): %s@%s [%s@%s#%u,%s#%u] [%s] %c %lu %luKb %lu %luKb\n",
+#else
+                "%s (%s): %s@%s [%s@%s#%u,%s#%u] %c %lu %luKb %lu %luKb\n",
+#endif
+#endif /* LOG_IP */
 		myctime(cptr->firsttime), msg ? msg : buf,
 		username, hostname, cptr->auth,
+#ifdef LOG_IP
+                rip,rport,lip,lport,
+#endif /* LOG_IP */
+#ifdef LOG_IRCNAME
+		cptr->info,
+#endif
 		cptr->exitc, cptr->sendM, cptr->sendK,
 		cptr->receiveM, cptr->receiveK);
 
diff -Nur irc2.10.3p7/common/struct_def.h irc2.10.3p7+hemp2+DK+B5/common/struct_def.h
--- irc2.10.3p7/common/struct_def.h	Mon May 14 14:02:08 2001
+++ irc2.10.3p7+hemp2+DK+B5/common/struct_def.h	Tue May 11 15:25:01 2004
@@ -25,6 +25,7 @@
 typedef	struct	Server	aServer;
 typedef	struct	Service	aService;
 typedef	struct	SLink	Link;
+typedef	struct	invSLink	invLink;
 typedef	struct	SMode	Mode;
 typedef	struct	fdarray	FdAry;
 typedef	struct	CPing	aCPing;
@@ -47,7 +48,7 @@
 				*/
 #define	USERLEN		10
 #define	REALLEN	 	50
-#define	TOPICLEN	80
+#define	TOPICLEN	160
 #define	CHANNELLEN	50
 #define	PASSWDLEN 	20
 #define	KEYLEN		23
@@ -60,7 +61,8 @@
 #define	CHIDLEN		5		/* WARNING: *DONT* CHANGE THIS!!!! */
 
 #define	READBUF_SIZE	16384	/* used in s_bsd.c *AND* s_zip.c ! */
- 
+
+#define	MAXMODEPARAMS	3 	/* do _!not!_ change this */
 /*
  * Make up some numbers which should reflect average leaf server connect
  * queue max size.
@@ -166,6 +168,9 @@
 #define	FLAGS_ZIP      0x400000 /* link is zipped */
 #define	FLAGS_ZIPRQ    0x800000 /* zip requested */
 #define	FLAGS_ZIPSTART 0x1000000 /* start of zip (ignore any CRLF) */
+#ifdef SPLIT_HANDLE
+#define FLAGS_EOBWAIT  0x2000000 /* waiting for EOB */
+#endif
 #define	FLAGS_HELD     0x8000000 /* connection held and reconnect try */
 
 #define	FLAGS_OPER       0x0001	/* Operator */
@@ -175,6 +180,11 @@
 #define FLAGS_RESTRICTED 0x0010 /* Restricted user */
 #define FLAGS_AWAY       0x0020 /* user is away */
 
+#define FLAGS_BADBOY     0x10000 /* delay close this client */
+#ifdef ILINE_FLAGS
+#define	FLAGS_EXEMPT	 0x20000 /* user is exempt from k-lines */
+
+#endif
 #define	SEND_UMODES	(FLAGS_INVISIBLE|FLAGS_OPER|FLAGS_WALLOP|FLAGS_AWAY)
 #define	ALL_UMODES	(SEND_UMODES|FLAGS_LOCOP|FLAGS_RESTRICTED)
 
@@ -222,6 +232,14 @@
 #define	ClearXAuth(x)		((x)->flags &= ~FLAGS_XAUTH)
 #define	ClearWXAuth(x)		((x)->flags &= ~FLAGS_WXAUTH)
 
+#ifdef SPLIT_HANDLE
+#define SetBurst(x)		((x)->flags |= FLAGS_EOBWAIT)
+#define ClearBurst(x)		((x)->flags &= ~FLAGS_EOBWAIT)
+#define IsBurst(x)		((x)->flags & FLAGS_EOBWAIT)
+#endif
+#ifdef ILINE_FLAGS
+#define IsKlineExempt(x)	((x)->user && (x)->user->flags & FLAGS_EXEMPT)
+#endif
 /*
  * defined debugging levels
  */
@@ -268,6 +286,7 @@
 	u_int	pref;		/* preference value */
 	struct	CPing	*ping;
 	time_t	hold;	/* Hold action until this time (calendar time) */
+	char	*source_ip;
 #ifndef VMSP
 	aClass	*class;  /* Class of connection */
 #endif
@@ -276,6 +295,15 @@
 
 #define	CONF_ILLEGAL		0x80000000
 #define	CONF_MATCH		0x40000000
+#ifdef DELAY_ACCEPT
+#define CONF_DELAY		0x20000000
+#define CONF_ACTIVE		0x10000000
+#define CONF_SERVERONLY		0x8000000
+#endif
+#ifdef ILINE_FLAGS
+#define CONF_EXEMPT		0x4000000  /* user is exempted from K: */
+#define CONF_RNODNS		0x2000000
+#endif
 #define	CONF_QUARANTINED_SERVER	0x000001
 #define	CONF_CLIENT		0x000002
 #define CONF_RCLIENT            0x000004
@@ -287,9 +315,6 @@
 #define	CONF_ME			0x000100
 #define	CONF_KILL		0x000200
 #define	CONF_ADMIN		0x000400
-#ifdef 	R_LINES
-#define	CONF_RESTRICT		0x000800
-#endif
 #define	CONF_CLASS		0x001000
 #define	CONF_SERVICE		0x002000
 #define	CONF_LEAF		0x004000
@@ -345,7 +370,7 @@
  */
 struct	User	{
 	Link	*channel;	/* chain of channel pointer blocks */
-	Link	*invited;	/* chain of invite pointer blocks */
+	invLink	*invited;	/* chain of invite pointer blocks */
 	Link	*uwas;		/* chain of whowas pointer blocks */
 	char	*away;		/* pointer to away message */
 	time_t	last;		/* "idle" time */
@@ -368,6 +393,8 @@
 	char	username[USERLEN+1];
 	char	host[HOSTLEN+1];
 	char	*server;
+	struct User *hnext;	
+	int 	hashv;		
 };
 
 struct	Server	{
@@ -382,6 +409,10 @@
 				** from anUser (field servp), aService (field
 				** servp) and aClient (field serv)
 				*/
+	int	usercnt[3]; 	/* # of clients - all, invisible, opers */
+#ifdef EXTRA_STATISTICS
+	int	usermax;	/* max # of users  on this server */
+#endif
 	struct	Server	*nexts, *prevs, *shnext;
 	aClient	*bcptr;
 	char	by[NICKLEN+1];
@@ -389,6 +420,7 @@
 	time_t	lastload;	/* penalty like counters, see s_serv.c
 				** should be in the local part, but..
 				*/
+	Link 	*down;		/* list of downlinks */
 };
 
 struct	Service	{
@@ -451,6 +483,7 @@
 				  ** accepted.
 				  */
 	char	passwd[PASSWDLEN+1];
+	char	*reason;	/* internal quit reason */
 	char	exitc;
 };
 
@@ -531,6 +564,16 @@
 	u_long	bytes;
 };
 
+#ifdef SPLIT_HANDLE
+#define SET_TYPE_INT 0
+#define SET_TYPE_STRING 1
+struct Set_Message {
+	char *cmd;
+	int *value;
+	char **values;
+};
+#endif
+
 #define	MSG_LAG		0x0001
 #define	MSG_NOU		0x0002	/* Not available to users */
 #define	MSG_SVC		0x0004	/* Services only */
@@ -563,6 +606,20 @@
 	int	flags;
 };
 
+/* invite link structure used for chains */
+struct invSLink        {
+	struct  invSLink        *next;
+	union {
+		aClient *cptr;
+		aChannel *chptr;
+		aConfItem *aconf;
+		char    *cp;
+		int     i;
+	} value;
+	int     flags;
+	char    *who;
+};
+
 /* channel structure */
 
 struct Channel	{
@@ -570,6 +627,10 @@
 	u_int	hashv;		/* raw hash value */
 	Mode	mode;
 	char	topic[TOPICLEN+1];
+#ifdef TOPICWHOTIME
+	char    topic_nuh[BANLEN+1];
+	time_t  topic_time;
+#endif
 	int	users;		/* current membership total */
 	Link	*members;	/* channel members */
 	Link	*invites;	/* outstanding invitations */
@@ -674,6 +735,18 @@
 				  x->prev->service->servp == x->serv)))
 
 typedef	struct	{
+#ifdef	EXTRA_STATISTICS
+	time_t	is_l_myclnt_t;	/* timestamp for last count */
+	u_long	is_l_myclnt;	/* last local user count */
+	time_t	is_m_users_t;	/* timestamp of last maximum users */
+	time_t	is_m_myclnt_t;	/* timestamp of last maximum local clients */
+	u_long	is_m_users;	/* maximum users connected */
+	u_long	is_m_serv;	/* maximum servers connected */
+	u_long	is_m_service;	/* maximum services connected */
+	u_long	is_m_myclnt;	/* maximum local clients */
+	u_long	is_m_myserv;	/* maximum local servers */
+	u_long	is_m_myservice;	/* maximum local services */
+#endif
 	u_long	is_user[2];	/* users, non[0] invis and invis[1] */
 	u_long	is_serv;	/* servers */
 	u_long	is_service;	/* services */
@@ -715,8 +788,21 @@
 	u_int	is_dbufmin;	/* min number of dbuf in use */
 	u_int	is_dbufmax;	/* max number of dbuf in use */
 	u_int	is_dbufmore;	/* how many times we increased the bufferpool*/
+#ifdef DELAY_CLOSE
+	u_long  is_delayclosed;
+#endif
+#ifdef SPLIT_HANDLE
+	u_long	is_eobservers;  /* # of servers which sent EOB */
+#endif
 } istat_t;
 
+typedef struct {
+	u_int split;
+	u_int aconnect; 	/* if we want aconnect or not */
+#ifdef DELAY_ACCEPT
+	u_int caccept;		/* enable/disable client ports */
+#endif
+} iconf_t;
 /* String manipulation macros */
 
 /* strncopynt --> strncpyzt to avoid confusion, sematics changed
@@ -771,8 +857,13 @@
 #define	SCH_SERVICE	9
 #define	SCH_DEBUG	10
 #define	SCH_AUTH	11
-#define	SCH_MAX		11
 
+#ifdef CLIENTS_CHANNEL 
+#define SCH_CLIENTS	12
+#define SCH_MAX 13
+#else
+#define SCH_MAX 12
+#endif
 /* used for async dns values */
 
 #define	ASYNC_NONE	(-1)
@@ -793,7 +884,6 @@
 #define EXITC_MBUF	'M'	/* mem alloc error */
 #define EXITC_PING	'P'	/* ping timeout */
 #define EXITC_SENDQ	'Q'	/* send queue exceeded */
-#define EXITC_RLINE	'r'	/* R-lined */
 #define EXITC_REF	'R'	/* Refused */
 #define EXITC_AREF	'U'	/* Unauthorized by iauth */
 #define EXITC_AREFQ	'u'	/* Unauthorized by iauth, be quiet */
diff -Nur irc2.10.3p7/common/support.c irc2.10.3p7+hemp2+DK+B5/common/support.c
--- irc2.10.3p7/common/support.c	Thu May 31 16:00:02 2001
+++ irc2.10.3p7+hemp2+DK+B5/common/support.c	Tue May 11 15:25:01 2004
@@ -849,7 +849,7 @@
 char *make_version()
 {
 	int ve, re, mi, dv, pl;
-	char ver[15];
+	char ver[50];
 
 	sscanf(PATCHLEVEL, "%2d%2d%2d%2d%2d", &ve, &re, &mi, &dv, &pl);
 	/* version & revision */
@@ -861,9 +861,31 @@
 		sprintf(ver + strlen(ver), "%c%d", DEVLEVEL, dv);
 	if (pl)	/* patchlevel */
 		sprintf(ver + strlen(ver), "p%d", pl);
+	strcat(ver,"+hemp2");
+	strcat(ver,"+DK+B5");
 	return mystrdup(ver);
 }
+#ifndef CLIENTCOMPILE
+#ifdef SEND_ISUPPORT
+/*
+ * Make ISUPPORT string 
+ */
 
+char *make_isupport()
+{
+	char tisupport[200];
+	char *p = tisupport;
+#ifdef SERVER_MAP
+	strcpy(tisupport,"MAP ");
+	p +=4;
+#endif
+	SPRINTF(p,"PREFIX=(ov)@+ MODES=%d CHANTYPES=#&!+ MAXCHANNELS=%d NICKLEN=%d TOPICLEN=%d KICKLEN=%d NETWORK=%s CHANMODES=beI,k,l,imnpstaqr",
+			      MAXMODEPARAMS, MAXCHANNELSPERUSER, NICKLEN, TOPICLEN, TOPICLEN,NETWORKNAME);
+
+	return mystrdup(tisupport);
+}
+#endif
+#endif
 #ifndef HAVE_TRUNCATE
 /* truncate: set a file to a specified length
  * I don't know of any UNIX that doesn't have truncate, but CYGWIN32 beta18
diff -Nur irc2.10.3p7/common/support_ext.h irc2.10.3p7+hemp2+DK+B5/common/support_ext.h
--- irc2.10.3p7/common/support_ext.h	Fri Dec  8 23:15:21 2000
+++ irc2.10.3p7+hemp2+DK+B5/common/support_ext.h	Tue May 11 15:25:01 2004
@@ -72,6 +72,9 @@
 #endif /* USE_STDARG */
 EXTERN int dgets __P((int fd, char *buf, int num));
 EXTERN char *make_version();
+#ifdef SEND_ISUPPORT
+EXTERN char *make_isupport();
+#endif
 #if SOLARIS_2_3
 EXTERN struct hostent *solaris_gethostbyname __P((const char *name));
 #endif /* SOLARIS_2_3 */
diff -Nur irc2.10.3p7/doc/example.conf irc2.10.3p7+hemp2+DK+B5/doc/example.conf
--- irc2.10.3p7/doc/example.conf	Wed Jul 14 18:17:23 1999
+++ irc2.10.3p7+hemp2+DK+B5/doc/example.conf	Tue May 11 15:25:01 2004
@@ -496,30 +496,6 @@
 #
 #
 ############################
-# R: [DISCOURAGED]. These lines restrict user access based on a more
-# stringent checking system than is available in the K: line. It looks for
-# a match (based on hostname and username) and then runs an outside
-# program (which MUST be specified using a full pathname). The output of
-# the program should be a string in the form "Y <message>" (which permits
-# access for the user) or "N <message>" (which denies access for the
-# user). If "Y <message>" is received by the server, the server ignores
-# the message and permits access for the user. If "N <message>" is
-# returned, the server tells the user that he/she is not permitted to
-# access that irc server, and gives the reason.
-#
-# Again, like K: lines, R: lines are local and thus not very effective in
-# blocking certain machines from having IRC access.
-#
-# Use of R: requires that you have defined R_LINES in config.h
-#
-# The fields are as follows:
-# R:hostmask:/full/path/to/program:username
-# you can use wildcards in either the hostmask or username portion
-#
-R:csl.bu.edu:/home/hrose/bin.sun3/sun3access:*::
-#
-#
-############################
 # Q: [DISCOURAGED]. These lines "quarantine" specified servers.  Because
 # of the way they operates, the same Q: lines MUST be installed by
 # everyone or the net will keep breaking. I CANNOT EMPHASIZE THIS ENOUGH.
diff -Nur irc2.10.3p7/iauth/a_conf.c irc2.10.3p7+hemp2+DK+B5/iauth/a_conf.c
--- irc2.10.3p7/iauth/a_conf.c	Sat Oct 11 16:22:56 2003
+++ irc2.10.3p7+hemp2+DK+B5/iauth/a_conf.c	Tue May 11 15:25:02 2004
@@ -26,6 +26,7 @@
 #define A_CONF_C
 #include "a_externs.h"
 #undef A_CONF_C
+#undef USE_DSM
 
 static aModule *Mlist[16];
 
@@ -87,8 +88,10 @@
 
 	Mlist[Mcnt++] = &Module_rfc931;
 	Mlist[Mcnt++] = &Module_socks;
+	Mlist[Mcnt++] = &Module_webproxy;
 	Mlist[Mcnt++] = &Module_pipe;
 	Mlist[Mcnt++] = &Module_lhex;
+	Mlist[Mcnt++] = &Module_dnsbl;
 	Mlist[Mcnt] = NULL;
 
 	cfh = fopen((cfile) ? cfile : IAUTHCONF_PATH, "r");
@@ -248,6 +251,7 @@
 			(*last)->hostname = NULL;
 			(*last)->address = NULL;
 			(*last)->timeout = timeout;
+			(*last)->reason = NULL;
 			if (Mlist[i] == &Module_rfc931)
 				ident = *last;
 
@@ -291,6 +295,17 @@
 							mystrdup(buffer + 10);
 					continue;
 				    }
+				if (!strncasecmp(buffer+1, "reason = ", 9))
+				{
+					if ((*last)->reason)
+						conf_err(lnnb,
+					"Duplicate reason keyword: ignored.",
+							cfile);
+					else
+						(*last)->reason =
+							mystrdup(buffer + 10);
+					continue;
+				}
 				if (!strncasecmp(buffer+1, "host = ", 7))
 				    {
 					needh = 1;
@@ -417,6 +432,8 @@
 		    {
 			printf("\t%s\t%s\n", itmp->mod->name,
 			       (itmp->opt) ? itmp->opt : "");
+			if (itmp->reason)
+				printf("\t\tReason = %s\n", itmp->reason);
 			if (ttmp = itmp->hostname)
 			    {
 				printf("\t\tHost = %s%s",
diff -Nur irc2.10.3p7/iauth/a_conf_def.h irc2.10.3p7+hemp2+DK+B5/iauth/a_conf_def.h
--- irc2.10.3p7/iauth/a_conf_def.h	Mon Jul  5 00:09:09 1999
+++ irc2.10.3p7+hemp2+DK+B5/iauth/a_conf_def.h	Tue May 11 15:25:02 2004
@@ -40,6 +40,7 @@
     u_char	in;			/* instance number */
     aModule	*mod;			/* module */
     char	*opt;			/* options read from file */
+    char	*reason;		/* reject reason */
     char	*popt;			/* options to send to ircd */
     void	*data;			/* private data: stats, ... */
     aTarget	*address;
diff -Nur irc2.10.3p7/iauth/a_externs.h irc2.10.3p7+hemp2+DK+B5/iauth/a_externs.h
--- irc2.10.3p7/iauth/a_externs.h	Mon Apr 12 21:45:04 1999
+++ irc2.10.3p7+hemp2+DK+B5/iauth/a_externs.h	Tue May 11 15:25:02 2004
@@ -30,5 +30,7 @@
 
 #include "mod_rfc931_ext.h"
 #include "mod_socks_ext.h"
+#include "mod_webproxy_ext.h"
 #include "mod_pipe_ext.h"
 #include "mod_lhex_ext.h"
+#include "mod_dnsbl_ext.h"
diff -Nur irc2.10.3p7/iauth/a_log_def.h irc2.10.3p7+hemp2+DK+B5/iauth/a_log_def.h
--- irc2.10.3p7/iauth/a_log_def.h	Thu Oct 18 21:51:08 2001
+++ irc2.10.3p7+hemp2+DK+B5/iauth/a_log_def.h	Tue May 11 15:25:02 2004
@@ -37,5 +37,9 @@
 #define	ALOG_DSOCKSC	0x040000	/* debug: module socks cache */
 #define	ALOG_DPIPE	0x080000	/* debug: module pipe */
 #define	ALOG_DLHEX	0x100000	/* debug: module pipe */
+#define ALOG_DNSBL      0x200000        /* debug: module dnsbl */
+#define ALOG_DNSBLC     0x200000        /* debug: module dnsbl cache */
+#define	ALOG_DWEBPROXY	0x400000	/* debug: module webproxy */
+#define	ALOG_DALL	0x7F3700	/* any debug flag */
 
-#define	ALOG_DALL	0x1F3700	/* any debug flag */
+#define	ALOG_DALL	0x7F3700	/* any debug flag */
diff -Nur irc2.10.3p7/iauth/iauth.c irc2.10.3p7+hemp2+DK+B5/iauth/iauth.c
--- irc2.10.3p7/iauth/iauth.c	Wed May 16 12:42:51 2001
+++ irc2.10.3p7+hemp2+DK+B5/iauth/iauth.c	Tue May 11 15:25:02 2004
@@ -135,6 +135,24 @@
 #endif
 }
 
+void    write_pidfile()
+{
+        int fd;
+        char buff[20];
+        (void)truncate(IAUTHPID_PATH, 0);
+        if ((fd = open(IAUTHPID_PATH, O_CREAT|O_WRONLY, 0600))>=0)
+            {
+                bzero(buff, sizeof(buff));
+                (void)sprintf(buff,"%5d\n", (int)getpid());
+                if (write(fd, buff, strlen(buff)) == -1)
+			(void)printf("Error writing to pid file %s",
+				IAUTHPID_PATH);
+                (void)close(fd);
+                return;
+            }
+}
+
+
 int	main(argc, argv)
 int	argc;
 char	*argv[];
@@ -197,6 +215,7 @@
 #endif
 		sendto_ircd("G 0");
 
+	write_pidfile();
 	while (1)
 	    {
 		loop_io();
diff -Nur irc2.10.3p7/iauth/mod_dnsbl.c irc2.10.3p7+hemp2+DK+B5/iauth/mod_dnsbl.c
--- irc2.10.3p7/iauth/mod_dnsbl.c	Thu Jan  1 01:00:00 1970
+++ irc2.10.3p7+hemp2+DK+B5/iauth/mod_dnsbl.c	Tue May 11 15:25:02 2004
@@ -0,0 +1,490 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, iauth/mod_dnsbl.c
+ *   Copyright (C) 2003 erra@RusNet
+ *   Copyright (C) 2003 Francois Baligant
+ *
+ *   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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static  char rcsid[] = "@(#)$Id$";
+#endif
+
+#include "os.h"
+#include "a_defines.h"
+#define MOD_DNSBL_C
+#include "a_externs.h"
+#undef MOD_DNSBL_C
+
+/****************************** PRIVATE *************************************/
+
+#define CACHETIME 30
+
+struct hostlog
+{
+	struct hostlog *next;
+	char ip[HOSTLEN+1];
+	u_char state; /* 0 = not found, 1 = found, 2 = timeout */
+	time_t expire;
+};
+
+#define OPT_LOG     	0x001
+#define OPT_DENY    	0x002
+#define OPT_PARANOID	0x004
+
+#define	OK		0
+#define DNSBL_FOUND	1
+#define DNSBL_FAILED	2
+
+struct dnsbl_list
+{
+	char *host;
+	struct dnsbl_list *next;
+};
+
+struct dnsbl_private
+{
+	struct hostlog *cache;
+	char *reason;
+	u_int lifetime;
+	u_char options;
+	/* stats */
+	u_int chitc, chito, chitn, cmiss, cnow, cmax;
+	u_int found, failed, good, total, rejects;
+	struct dnsbl_list *host_list;
+};
+
+/*
+ * dnsbl_succeed
+ *
+ *	Found a host in DNSBL. Deal with it.
+ */
+static void
+dnsbl_succeed(cl, listname, result)
+int cl;
+char *listname, *result;
+{
+    struct dnsbl_private *mydata = cldata[cl].instance->data;
+    char *reason = mydata->reason;
+
+    if (mydata->options & OPT_PARANOID || (mydata->options & OPT_DENY &&
+		result[0] == '\177' && result[1] == '\0' &&
+		result[2] == '\0' /*  && result[3] == '\2' */) )
+	{
+	    cldata[cl].state |= A_DENY;
+	    sendto_ircd("k %d %s %u #dnsbl %s", cl,
+			cldata[cl].itsip, cldata[cl].itsport,
+			reason ? reason : "");
+	    mydata->rejects++;
+	}
+    if (mydata->options & OPT_LOG)
+	    sendto_log(ALOG_FLOG, LOG_INFO, "%s: found: %s[%s]",
+		       listname, cldata[cl].host, cldata[cl].itsip);
+}
+
+/*
+ * dnsbl_add_cache
+ *
+ *	Add an entry to the cache.
+ */
+static void
+dnsbl_add_cache(cl, state)
+int cl, state;
+{
+    struct dnsbl_private *mydata = cldata[cl].instance->data;
+    struct hostlog *next;
+
+    if (state == DNSBL_FOUND)
+	mydata->found ++;
+    else if (state == DNSBL_FAILED)
+	mydata->failed ++;
+    else /* state == OK */
+	mydata->good ++;
+
+    if (mydata->lifetime == 0)
+	    return;
+
+    mydata->cnow ++;
+    if (mydata->cnow > mydata->cmax)
+	    mydata->cmax = mydata->cnow;
+
+    next = mydata->cache;
+    mydata->cache = (struct hostlog *)malloc(sizeof(struct hostlog));
+    mydata->cache->expire = time(NULL) + mydata->lifetime;
+    strcpy(mydata->cache->ip, cldata[cl].itsip);
+    mydata->cache->state = state;
+    mydata->cache->next = next;
+    DebugLog((ALOG_DNSBLC, 0, "dnsbl_add_cache(%d): new cache %s, result=%d",
+	      cl, mydata->cache->ip, state));
+}
+
+/*
+ * dnsbl_check_cache
+ *
+ *	Check cache for an entry.
+ */
+static int
+dnsbl_check_cache(cl)
+{
+    struct dnsbl_private *mydata = cldata[cl].instance->data;
+    struct hostlog **last, *pl;
+    time_t now = time(NULL);
+
+    if (!mydata || mydata->lifetime == 0)
+                return 0;
+
+    DebugLog((ALOG_DNSBLC, 0, "dnsbl_check_cache(%d): Checking cache for %s",
+	      cl, cldata[cl].itsip));
+
+    last = &(mydata->cache);
+    while (pl = *last)
+	{
+	    DebugLog((ALOG_DNSBLC, 0, "dnsbl_check_cache(%d): cache %s",
+		      cl, pl->ip));
+	    if (pl->expire < now)
+		{
+		    DebugLog((ALOG_DNSBLC, 0,
+			      "dnsbl_check_cache(%d): free %s (%d < %d)",
+			      cl, pl->ip, pl->expire, now));
+		    *last = pl->next;
+		    free(pl);
+		    mydata->cnow --;
+		    continue;
+		}
+	    if (!strcasecmp(pl->ip, cldata[cl].itsip))
+		{
+		    DebugLog((ALOG_DNSBLC, 0,
+			      "dnsbl_check_cache(%d): match (%u)",
+			      cl, pl->state));
+		    pl->expire = now + mydata->lifetime; /* dubious */
+		    if (pl->state == 1)
+			{
+			    dnsbl_succeed(cl, "cached", "");
+			    mydata->chito ++;
+			}
+		    else if (pl->state == 0)
+			    mydata->chitn ++;
+		    else
+			    mydata->chitc ++;
+		    return -1;
+		}
+	    last = &(pl->next);
+	}
+    mydata->cmiss ++;
+    return 0;
+}
+
+/******************************** PUBLIC ************************************/
+
+/*
+ * dnsbl_init
+ *
+ *	This procedure is called when a particular module is loaded.
+ *	Returns NULL if everything went fine,
+ *	an error message otherwise.
+ */
+char *
+dnsbl_init(self)
+AnInstance *self;
+{
+    struct dnsbl_private *mydata;
+    struct dnsbl_list *l;
+    char tmpbuf[255], cbuf[32], *s;
+    static char txtbuf[255];
+    
+    if (self->opt == NULL)
+	    return "Aie! no option(s): nothing to be done!";
+
+    mydata = (struct dnsbl_private *) malloc(sizeof(struct dnsbl_private));
+    bzero((char *) mydata, sizeof(struct dnsbl_private));
+    self->data = mydata;
+    mydata->cache = NULL;
+    mydata->host_list = NULL;
+    mydata->lifetime = CACHETIME;
+    
+    tmpbuf[0] = txtbuf[0] = '\0';
+    if (strstr(self->opt, "log"))
+	{
+	    mydata->options |= OPT_LOG;
+	    strcat(tmpbuf, ",log");
+	    strcat(txtbuf, ", Log");
+	}
+    if (strstr(self->opt, "reject"))
+	{
+	    mydata->options |= OPT_DENY;
+	    strcat(tmpbuf, ",reject");
+	    strcat(txtbuf, ", Reject");
+	}
+    if (strstr(self->opt, "paranoid"))
+	{
+	    mydata->options |= OPT_PARANOID;
+	    strcat(tmpbuf, ",paranoid");
+	    strcat(txtbuf, ", Paranoid");
+	}
+
+    if (mydata->options == 0) {
+	DebugLog((ALOG_DNSBL, 0, "dnsbl_init: Aie! unknown option(s): nothing to be done!"));
+	    return "Aie! unknown option(s): nothing to be done!";
+	}
+
+    if (s = strstr(self->opt, "list"))
+	{
+	    char *ch = index(s, '=');
+	    
+	    if (++ch)
+		{
+		    char *name, *last, *t = NULL;
+#ifdef HAVE_STRTOK
+/* much better, we can break on both comma and space! */
+		    for (name = strtok_r(ch, ", ", &last);
+			name;
+			name = strtok_r(NULL, ", ", &last))
+		    {
+#else
+		    for (name = strtoken(&last, ch, ",");
+			name;
+			name = strtoken(&last, NULL, ","))
+		    {
+			while (name && *name && isspace(*name))
+				name++;
+			if (name && *name)
+			{
+#endif
+			l = (struct dnsbl_list *)
+				malloc(sizeof(struct dnsbl_list));
+			l->host = strdup(name);
+			sendto_log(ALOG_DMISC, LOG_NOTICE,
+				"dnsbl_init: Added %s as dnsbl", name);
+			l->next = mydata->host_list;
+			mydata->host_list = l;
+#ifndef HAVE_STRTOK
+			}
+		    }
+#else
+		    }
+#endif
+		}
+	}
+
+    if (mydata->host_list == NULL) {
+		DebugLog((ALOG_DNSBL, 0, "dnsbl_init: Aie! No DNSBL host: nothing to be done!"));
+	    return "Aie! No DNSBL host: nothing to be done!";
+    }
+    
+    if (strstr(self->opt, "cache"))
+	{
+	    char *ch = index(self->opt, '=');
+	    
+	    if (ch)
+		    mydata->lifetime = atoi(++ch);
+	}
+    sprintf(cbuf, ",cache=%d", mydata->lifetime);
+    strcat(tmpbuf, cbuf);
+    sprintf(cbuf, ", Cache %d (min)", mydata->lifetime);
+    strcat(txtbuf, cbuf);
+    mydata->lifetime *= 60;
+    strcat(tmpbuf, ",list=");
+    strcat(txtbuf, ", List(s): ");
+    l = mydata->host_list;
+    strcat(tmpbuf, l->host);
+    strcat(txtbuf, l->host);
+
+    for (l = l->next; l; l = l->next)
+    {
+	strcat(tmpbuf, ",");
+	strcat(txtbuf, ", ");
+	strcat(tmpbuf, l->host);
+	strcat(txtbuf, l->host);
+    }
+    
+    if (self->reason)
+    {
+	mydata->reason = mystrdup(self->reason);
+    }
+    self->popt = strdup(tmpbuf + 1);
+    return txtbuf + 2;
+}
+
+/*
+ * dnsbl_release
+ *
+ *	This procedure is called when a particular module is unloaded.
+ */
+void
+dnsbl_release(self)
+AnInstance *self;
+{
+    struct dnsbl_private *mydata = self->data;
+    struct dnsbl_list *l, *n;
+
+    for (l = mydata->host_list; l; l = n)
+    {
+	free(l->host);
+	n = l->next;
+	free(l);
+    }
+
+    free(mydata);
+    free(self->popt);
+}
+
+/*
+ * dnsbl_stats
+ *
+ *	This procedure is called regularly to update statistics sent to ircd.
+ */
+void
+dnsbl_stats(self)
+AnInstance *self;
+{
+    struct dnsbl_private *mydata = self->data;
+
+    sendto_ircd("S dnsbl verified %u rejected %u",
+				mydata->total, mydata->rejects);
+}
+
+/*
+ * dnsbl_start
+ *
+ *	This procedure is called to start the host check procedure.
+ *	Returns 0 if everything went fine,
+ *	-1 otherwise (nothing to be done, or failure)
+ *
+ *	It is responsible for sending error messages where appropriate.
+ *	In case of failure, it's responsible for cleaning up (e.g. dnsbl_clean
+ *	will NOT be called)
+ */
+int
+dnsbl_start(cl)
+u_int cl;
+{
+    struct dnsbl_private *mydata = cldata[cl].instance->data;
+    struct dnsbl_list *l, *m;
+    char *req;
+    char *ip, *c1, *c2, *c3;
+    int  ipl;
+    struct hostent *hst = NULL;
+    
+    if (cldata[cl].state & A_DENY)
+	{
+	    /* no point of doing anything */
+	    DebugLog((ALOG_DNSBL, 0,
+		      "dnsbl_start(%d): A_DENY alredy set ", cl));
+	    return -1;
+	}
+   
+    if (strchr(cldata[cl].itsip,':')) {
+                DebugLog((ALOG_DNSBL, 0,
+                                "dnsbl_start(%d): %s is IPv6, skipping ", cl, cldata[cl].itsip));
+                return -1;
+        }
+ 
+    if (dnsbl_check_cache(cl))
+	    return -1;
+    
+    ip = strdup(cldata[cl].itsip);
+    ipl = strlen(ip);
+    DebugLog((ALOG_DNSBL, 0, "dnsbl_start(%d): checking %s", cl, ip));
+
+    strtok(ip, ".");
+    c3 = strtok(NULL, ".");
+    c2 = strtok(NULL, ".");
+    c1 = strtok(NULL, ".");
+
+    for (l = mydata->host_list; l && !hst; l = l->next)
+    {
+	req = malloc(strlen(l->host) + ipl + 3);
+	sprintf( req, "%s.%s.%s.%s.%s", c1, c2, c3, ip, l->host);
+DebugLog((ALOG_DNSBL, 0,
+                      "dnsbl_start(%d): gethostbyname() for %s",
+                                                cl, req ));
+	hst = gethostbyname(req);
+	m = l;
+	free(req);
+    }
+    mydata->total++;
+
+    if (hst)
+	dnsbl_succeed(cl, m->host, hst->h_addr_list[0]);
+    else
+	{
+	    DebugLog((ALOG_DNSBL, 0,
+		      "dnsbl_start(%d): gethostbyname() reported %s",
+						cl, hstrerror(h_errno) ));
+	    dnsbl_add_cache(cl, DNSBL_FAILED, 0);
+	}
+
+    free(ip);
+    return -1;
+}
+
+/*
+ * dnsbl_work
+ *
+ *	This procedure is called whenever there's new data in the buffer.
+ *	Returns 0 if everything went fine, and there is more work to be done,
+ *	Returns -1 if the module has finished its work (and cleaned up).
+ *
+ *	It is responsible for sending error messages where appropriate.
+ */
+int
+dnsbl_work(cl)
+u_int cl;
+{
+	    /*
+	    ** There' nothing to do here
+	    */
+	    DebugLog((ALOG_DNSBL, 0,
+		      "dnsbl_work(%d) invoked but why?", cl ));
+}
+
+/*
+ * dnsbl_clean
+ *
+ *	This procedure is called whenever the module should interrupt its work.
+ *	It is responsible for cleaning up any allocated data, and in particular
+ *	closing file descriptors.
+ */
+void
+dnsbl_clean(cl)
+u_int cl;
+{
+    DebugLog((ALOG_DNSBL, 0, "dnsbl_clean(%d): cleaning up", cl));
+    /*
+    ** only one of rfd and wfd may be set at the same time,
+    ** in any case, they would be the same fd, so only close() once
+    */
+}
+
+/*
+ * dnsbl_timeout
+ *
+ *	This procedure is called whenever the timeout set by the module is
+ *	reached.
+ *
+ *	Returns 0 if things are okay, -1 if check was aborted.
+ */
+int
+dnsbl_timeout(cl)
+u_int cl;
+{
+    DebugLog((ALOG_DNSBL, 0, "dnsbl_timeout(%d): calling dnsbl_clean ", cl));
+    dnsbl_clean(cl);
+    return -1;
+}
+
+aModule Module_dnsbl =
+	{ "dnsbl", dnsbl_init, dnsbl_release, dnsbl_stats,
+	  dnsbl_start, dnsbl_work, dnsbl_timeout, dnsbl_clean };
diff -Nur irc2.10.3p7/iauth/mod_dnsbl_ext.h irc2.10.3p7+hemp2+DK+B5/iauth/mod_dnsbl_ext.h
--- irc2.10.3p7/iauth/mod_dnsbl_ext.h	Thu Jan  1 01:00:00 1970
+++ irc2.10.3p7+hemp2+DK+B5/iauth/mod_dnsbl_ext.h	Tue May 11 15:25:02 2004
@@ -0,0 +1,29 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, iauth/mod_socks_ext.h
+ *   Copyright (C) 2003 erra@RusNet
+ *   Copyright (C) 2003 Francois Baligant
+ *
+ *   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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*  This file contains external definitions for global variables and functions
+    defined in iauth/mod_socks.c.
+ */
+
+/*  External definitions for global variables.
+ */
+#ifndef MOD_DNSBL_C
+extern aModule Module_dnsbl;
+#endif /* MOD_DNSBL_C */
diff -Nur irc2.10.3p7/iauth/mod_socks.c irc2.10.3p7+hemp2+DK+B5/iauth/mod_socks.c
--- irc2.10.3p7/iauth/mod_socks.c	Mon Oct 13 02:11:43 2003
+++ irc2.10.3p7+hemp2+DK+B5/iauth/mod_socks.c	Tue May 11 15:25:02 2004
@@ -67,6 +67,7 @@
 struct socks_private
 {
 	struct proxylog *cache;
+	char *reason;
 	u_int lifetime;
 	u_char options;
 	/* stats */
@@ -86,13 +87,19 @@
 char *strver;
 {
     struct socks_private *mydata = cldata[cl].instance->data;
+    char *reason = mydata->reason;
+#ifdef IAUTH_VERBOSE_REJECTS
+    char verbose = 'K';
+#else
+    char verbose = 'k';
+#endif
 
     /* open proxy */
     if (mydata->options & OPT_DENY)
 	{
 	    cldata[cl].state |= A_DENY;
-	    sendto_ircd("k %d %s %u ", cl, cldata[cl].itsip,
-			cldata[cl].itsport);
+	    sendto_ircd("%c %d %s %u #socks %s", verbose, cl, cldata[cl].itsip,
+			cldata[cl].itsport,reason ? reason : "");
 	}
     if (mydata->options & OPT_LOG)
 	    sendto_log(ALOG_FLOG, LOG_INFO, "socks%s: open proxy: %s[%s]",
@@ -559,7 +566,10 @@
     sprintf(cbuf, ", Cache %d (min)", mydata->lifetime);
     strcat(txtbuf, cbuf);
     mydata->lifetime *= 60;
-    
+    if (self->reason)
+    {
+        mydata->reason = mystrdup(self->reason);
+    }
     self->popt = mystrdup(tmpbuf+1);
     self->data = mydata;
     return txtbuf+2;
diff -Nur irc2.10.3p7/iauth/mod_webproxy.c irc2.10.3p7+hemp2+DK+B5/iauth/mod_webproxy.c
--- irc2.10.3p7/iauth/mod_webproxy.c	Thu Jan  1 01:00:00 1970
+++ irc2.10.3p7+hemp2+DK+B5/iauth/mod_webproxy.c	Tue May 11 15:25:02 2004
@@ -0,0 +1,597 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, iauth/mod_webproxy.c
+ *   Copyright (C) 2001 Dan Merillat
+ *   
+ *   Original code (iauth/mod_socks.c) is
+ *   Copyright (C) 1998 Christophe Kalt
+ *
+ *   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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] =
+"@(#)$Id: mod_webproxy.c,v 1.25 1999/08/13 21:06:30 chopin Exp $";
+#endif
+
+#include "os.h"
+#include "a_defines.h"
+#define MOD_WEBGATE_C
+#include "a_externs.h"
+
+/****************************** PRIVATE *************************************/
+
+#define CACHETIME 30
+
+struct proxylog {
+	struct proxylog *next;
+	char ip[HOSTLEN + 1];
+	u_char state;				/* 0 = no proxy, 1 = open proxy, 2 = closed proxy */
+	time_t expire;
+	u_int port;
+};
+
+#define OPT_LOG			0x001
+#define OPT_DENY    	0x002
+#define OPT_PARANOID	0x004
+#define OPT_CAREFUL 	0x008
+#define OPT_V4ONLY  	0x010
+#define OPT_V5ONLY  	0x020
+#define OPT_PROTOCOL	0x100
+
+#define PROXY_NONE		0
+#define PROXY_OPEN		1
+#define PROXY_CLOSE		2
+#define PROXY_UNEXPECTED	3
+#define PROXY_BADPROTO		4
+
+struct webproxy_private {
+	struct proxylog *cache;
+	u_int lifetime;
+	u_char options;
+	char *reason;
+	u_int ports[128];
+	u_int portcount;
+	/* stats */
+	u_int chitc, chito, chitn, cmiss, cnow, cmax;
+	u_int open[128], closed, noproxy;
+};
+int webproxy_start(u_int);
+
+/*
+ * webproxy_open_proxy
+ *
+ *  Found an open proxy for cl: deal with it!
+ */
+
+static void 
+webproxy_open_proxy(cl,port)
+int cl;
+u_int port;
+{
+	struct webproxy_private *mydata = cldata[cl].instance->data;
+	char *reason = mydata->reason;
+#ifdef IAUTH_VERBOSE_REJECTS
+	char verbose = 'K';
+#else
+	char verbose = 'k';
+#endif
+	char myreason[BUFSIZE];
+	if (reason)
+	{
+		if (strstr(reason,"%d"))
+		{
+			sprintf(myreason,reason,port);
+		}
+		else
+		{
+			strcpy(myreason,reason);
+		}
+		myreason[300] = '\0';
+	}
+	/* open proxy */
+	if (mydata->options & OPT_DENY) {
+		cldata[cl].state |= A_DENY;
+		sendto_ircd("%c %d %s %u %s%d %s", verbose,cl, cldata[cl].itsip,
+					cldata[cl].itsport,"#webproxy-",port,
+					reason ? myreason : "");
+	}
+	if (mydata->options & OPT_LOG)
+		sendto_log(ALOG_FLOG, LOG_INFO, "webproxy: open proxy: %s[%s], port %u",
+					cldata[cl].host, cldata[cl].itsip,
+				   port);
+}
+
+/*
+ * webproxy_add_cache
+ *
+ *  Add an entry to the cache.
+ */
+
+static void 
+webproxy_add_cache(cl, state)
+int cl, state;
+{
+	struct webproxy_private *mydata = cldata[cl].instance->data;
+	struct proxylog *next;
+
+
+	if (state == PROXY_OPEN) {
+		if (cldata[cl].mod_status < mydata->portcount)
+			mydata->open[cldata[cl].mod_status] += 1;
+			
+	} else if (state == PROXY_NONE)
+		mydata->noproxy += 1;
+	else
+		/* state == PROXY_CLOSE|PROXY_UNEXPECTED|PROXY_BADPROTO */ 
+		mydata->closed += 1;
+
+	if (mydata->lifetime == 0)
+		return;
+
+	mydata->cnow += 1;
+	if (mydata->cnow > mydata->cmax)
+		mydata->cmax = mydata->cnow;
+
+	next = mydata->cache;
+	mydata->cache = (struct proxylog *) malloc(sizeof(struct proxylog));
+	mydata->cache->expire = time(NULL) + mydata->lifetime;
+	strcpy(mydata->cache->ip, cldata[cl].itsip);
+	mydata->cache->port = mydata->ports[cldata[cl].mod_status - 1];
+	mydata->cache->state = state;
+	mydata->cache->next = next;
+	DebugLog(
+				(ALOG_DWEBPROXYC, 0,
+				 "webproxy_add_cache(%d): new cache %s, open=%d", cl,
+				 mydata->cache->ip, state));
+}
+
+/*
+ * webproxy_check_cache
+ *
+ *  Check cache for an entry.
+ */
+static int 
+webproxy_check_cache(cl)
+{
+	struct webproxy_private *mydata = cldata[cl].instance->data;
+	struct proxylog **last, *pl;
+	time_t now = time(NULL);
+
+	if (!mydata || mydata->lifetime == 0)
+		return 0;
+
+	DebugLog(
+				(ALOG_DWEBPROXYC, 0,
+				 "webproxy_check_cache(%d): Checking cache for %s", cl,
+				 cldata[cl].itsip));
+
+	last = &(mydata->cache);
+	while ((pl = *last)) {
+		DebugLog((ALOG_DWEBPROXYC, 0, "webproxy_check_cache(%d): cache %s",
+				  cl, pl->ip));
+		if (pl->expire < now) {
+			DebugLog((ALOG_DWEBPROXYC, 0,
+					  "webproxy_check_cache(%d): free %s (%d < %d)",
+					  cl, pl->ip, pl->expire, now));
+			*last = pl->next;
+			free(pl);
+			mydata->cnow -= 1;
+			continue;
+		}
+		if (!strcasecmp(pl->ip, cldata[cl].itsip)) {
+			DebugLog((ALOG_DWEBPROXYC, 0,
+					  "webproxy_check_cache(%d): match (%u)", cl,
+					  pl->state));
+			pl->expire = now + mydata->lifetime;	/* dubious */
+			if (pl->state == 1) {
+				webproxy_open_proxy(cl,pl->port);
+				mydata->chito += 1;
+			} else if (pl->state == 0)
+				mydata->chitn += 1;
+			else
+				mydata->chitc += 1;
+			return -1;
+		}
+		last = &(pl->next);
+	}
+	mydata->cmiss += 1;
+	return 0;
+}
+
+static int 
+webproxy_write(u_int cl)
+{
+
+	struct webproxy_private *mydata = cldata[cl].instance->data;
+	static u_char query[64];	/* big enough to hold all queries */
+	static int query_len;	/* lenght of socks4 query */
+	static int wlen;
+
+
+
+	query_len=snprintf(query, 64, "CONNECT %s:%d HTTP/1.0\n\n",
+			 cldata[cl].ourip, cldata[cl].ourport);
+
+	DebugLog((ALOG_DWEBPROXY, 0, "webproxy_write(%d): Checking %s:%u",
+			  cl, cldata[cl].itsip, mydata->ports[cldata[cl].mod_status]));
+	if ((wlen=write(cldata[cl].wfd, query, query_len)) != query_len) {
+		/* most likely the connection failed */
+		DebugLog(
+					(ALOG_DWEBPROXY, 0,
+				  "webproxy_write(%d): write() failed: %d %s", cl,
+					 wlen, strerror(errno)));
+		close(cldata[cl].wfd);
+		cldata[cl].rfd = cldata[cl].wfd = 0;
+		cldata[cl].buflen=0;
+		if (++cldata[cl].mod_status < mydata->portcount)
+			return webproxy_start(cl);
+		else
+			return 1;
+	}
+	cldata[cl].rfd = cldata[cl].wfd;
+	cldata[cl].wfd = 0;
+	return 0;
+}
+
+static int 
+webproxy_read(u_int cl)
+{
+	/* Looking for "Connection established"
+	 * HTTP/1.0 200 Connection established" */
+
+	struct webproxy_private *mydata = cldata[cl].instance->data;
+	int again = 1;
+	u_char state = PROXY_CLOSE;
+	char  *lookfor="HTTP/1.0 200";
+	
+	u_int looklen=strlen(lookfor);
+	/* data's in from the other end */
+	if (cldata[cl].buflen < looklen)
+		return 0;
+	
+	/* zero it out so the debug log is sane */
+	cldata[cl].inbuffer[cldata[cl].buflen]=0;
+
+	/* got all we need */
+	DebugLog(
+				(ALOG_DWEBPROXY, 0, "webproxy_read(%d): %d Got [%s]",
+			cl, mydata->ports[cldata[cl].mod_status], cldata[cl].inbuffer));
+
+
+	if (!strstr(cldata[cl].inbuffer, "Date:") &&
+		(!strncmp(cldata[cl].inbuffer, lookfor, looklen) ||
+	    	 !strncmp(cldata[cl].inbuffer, "HTTP/1.1 200",looklen))
+			)  { /* got it! */
+		DebugLog((ALOG_DWEBPROXY, 0, "webproxy_read(%d): Open proxy on %s:%u",
+				cl, cldata[cl].itsip, mydata->ports[cldata[cl].mod_status]));
+		state = PROXY_OPEN;
+		webproxy_open_proxy(cl,mydata->ports[cldata[cl].mod_status]);
+		again = 0;
+	}
+
+	cldata[cl].mod_status++;
+	close(cldata[cl].rfd);
+	cldata[cl].rfd = 0;
+
+	if (again && cldata[cl].mod_status < mydata->portcount) {
+		cldata[cl].buflen = 0;
+		return webproxy_start(cl);
+	}
+	else {
+		webproxy_add_cache(cl, state);
+		return -1;
+	}
+	return 0;
+}
+
+/******************************** PUBLIC ************************************/
+
+/*
+ * webproxy_init
+ *
+ *  This procedure is called when a particular module is loaded.
+ *  Returns NULL if everything went fine,
+ *  an error message otherwise.
+ */
+
+char *
+webproxy_init(AnInstance * self)
+{
+	struct webproxy_private *mydata;
+	char tmpbuf[80], cbuf[32];
+	static char txtbuf[80];
+	u_int portcount = 0;
+	
+	tmpbuf[0] = txtbuf[0] = '\0';
+
+	mydata = 
+		(struct webproxy_private *)
+		malloc(sizeof(struct webproxy_private));
+	bzero((char *) mydata, sizeof(struct webproxy_private));
+	mydata->cache = NULL;
+	mydata->lifetime = CACHETIME;
+	if (!self->opt)
+	{
+		/* using default config:
+		** log,deny,ports=3128;8080 
+		*/
+		mydata->options=OPT_DENY|OPT_LOG;
+		mydata->ports[portcount++] = 3128;
+		mydata->ports[portcount++] = 8080;
+		mydata->portcount=portcount;
+		strcat(tmpbuf, ",log");
+		strcat(txtbuf, ", Log");
+		strcat(tmpbuf, ",reject");
+		strcat(txtbuf, ", Reject");
+		strcat(tmpbuf, ",ports=3128;8080");
+		strcat(txtbuf, ", Ports=3128;8080");
+
+	}
+	else
+	{
+
+		char *ch = NULL, *portsp = NULL;
+	
+		if ((portsp=strstr(self->opt, "ports"))) 
+
+		{
+			char xbuf[128];
+			char *c;
+			size_t slen;
+			bzero(xbuf,sizeof(xbuf));
+			ch = strchr(portsp, '=');
+			if (!ch)
+			{
+				mydata->ports[portcount++] = 3128;
+				mydata->ports[portcount++] = 8080;
+				mydata->portcount=portcount;
+			}
+			else
+			{
+				c=index(ch, ',');
+				if (!c)
+				   c=ch+strlen(ch);
+			/* now ch is at = and c is at the end of the ports line */
+				ch++;
+				slen = (size_t) c - (size_t) ch;
+				if (slen > 30)
+				{
+					slen = 30;
+				}
+				memcpy(xbuf, ch, slen);
+				strcat(tmpbuf,",ports=");
+
+				strcat(tmpbuf,xbuf);
+				ch=xbuf;
+				while((c=index(ch, ';'))) {
+				   *c=0;
+				   mydata->ports[portcount++]=atoi(ch);
+				   ch=c+1;
+				}
+				mydata->ports[portcount++]=atoi(ch);
+				mydata->portcount=portcount;
+			}
+		}
+		if (strstr(self->opt, "log")) {
+			mydata->options |= OPT_LOG;
+			strcat(tmpbuf, ",log");
+			strcat(txtbuf, ", Log");
+		}
+		if (strstr(self->opt, "reject")) {
+			mydata->options |= OPT_DENY;
+			strcat(tmpbuf, ",reject");
+			strcat(txtbuf, ", Reject");
+		}
+		if (strstr(self->opt, "cache")) {
+			char *ch = index(self->opt, '=');
+
+			if (ch)
+				mydata->lifetime = atoi(ch + 1);
+		}
+	}	
+	sprintf(cbuf, ",cache=%d", mydata->lifetime);
+	strcat(tmpbuf, cbuf);
+	sprintf(cbuf, ", Cache %d (min)", mydata->lifetime);
+	strcat(txtbuf, cbuf);
+	mydata->lifetime *= 60;
+	if (self->reason)
+	{
+		mydata->reason = mystrdup(self->reason);
+	}
+	self->popt = mystrdup(tmpbuf + 1);
+	self->data = mydata;
+	return txtbuf + 2;
+}
+
+/*
+ * webproxy_release
+ *
+ *  This procedure is called when a particular module is unloaded.
+ */
+void 
+webproxy_release(self)
+AnInstance *self;
+{
+	struct webproxy_private *mydata = self->data;
+	free(mydata);
+	free(self->popt);
+}
+
+/*
+ * webproxy_stats
+ *
+ *  This procedure is called regularly to update statistics sent to ircd.
+ */
+void 
+webproxy_stats(self)
+AnInstance *self;
+{
+	struct webproxy_private *mydata = self->data;
+	char mybuf[256];
+	int len;
+	int i;
+
+	len=snprintf(mybuf, 256, "S webproxy port:open");
+	for (i=0;i<mydata->portcount;i++)
+		len+=snprintf(mybuf+len, 256-len, " %u:%u", 
+				mydata->ports[i], mydata->open[i]);
+
+	len+=snprintf(mybuf+len, 256-len, " closed %u noproxy %u",
+			mydata->closed, mydata->noproxy);
+
+	sendto_ircd(mybuf);
+
+	sendto_ircd
+		("S webproxy cache open %u closed %u noproxy %u miss %u (%u <= %u)",
+		 mydata->chito, mydata->chitc, mydata->chitn, mydata->cmiss,
+		 mydata->cnow, mydata->cmax);
+}
+
+/*
+ * webproxy_start
+ *
+ *  This procedure is called to start the socks check procedure.
+ *  Returns 0 if everything went fine,
+ *  -1 otherwise (nothing to be done, or failure)
+ *
+ *  It is responsible for sending error messages where appropriate.
+ *  In case of failure, it's responsible for cleaning up (e.g. webproxy_clean
+ *  will NOT be called)
+ */
+int 
+webproxy_start(cl)
+u_int cl;
+{
+
+	struct webproxy_private *mydata = cldata[cl].instance->data;
+	char *error;
+	int fd;
+
+	if (cldata[cl].state & A_DENY) {
+		/* no point of doing anything */
+		DebugLog((ALOG_DWEBPROXY, 0,
+				  "webproxy_start(%d): A_DENY alredy set ", cl));
+		return -1;
+	}
+	if (cldata[cl].mod_status == 0)
+		if (webproxy_check_cache(cl))
+			return -1;
+
+	if (strchr(cldata[cl].itsip,':'))
+		return -1;
+
+	while (cldata[cl].mod_status < mydata->portcount) {
+		DebugLog(
+				  (ALOG_DWEBPROXY, 0, "webproxy_start(%d): Connecting to %s:%u",
+				   cl, cldata[cl].itsip, mydata->ports[cldata[cl].mod_status]));
+		fd = tcp_connect(cldata[cl].ourip, cldata[cl].itsip, 
+					mydata->ports[cldata[cl].mod_status],
+					&error);
+		if (fd > 0) {
+						/*so that webproxy_work() is called when connected */
+			cldata[cl].wfd = fd;		
+			return 0;
+		}
+		DebugLog((ALOG_DWEBPROXY, 0,
+			  "webproxy_start(%d): tcp_connect() reported %s", cl,
+			  error));
+		cldata[cl].mod_status++;
+		continue;
+		
+	}
+
+	return -1;
+}
+
+/*
+ * webproxy_work
+ *
+ *  This procedure is called whenever there's new data in the buffer.
+ *  Returns 0 if everything went fine, and there is more work to be done,
+ *  Returns -1 if the module has finished its work (and cleaned up).
+ *
+ *  It is responsible for sending error messages where appropriate.
+ */
+int 
+webproxy_work(cl)
+u_int cl;
+{
+	struct webproxy_private *mydata = cldata[cl].instance->data;
+
+	if (!mydata)
+		return -1;
+
+	DebugLog(
+			  (ALOG_DWEBPROXY, 0, "webproxy_work(%d): %d %d %d buflen=%d",
+			   cl, mydata->ports[cldata[cl].mod_status],
+				cldata[cl].rfd, cldata[cl].wfd,
+			   cldata[cl].buflen));
+
+	if (cldata[cl].wfd > 0)
+		/*
+		   ** We haven't sent the query yet, the connection was just
+		   ** established.
+		 */
+		return webproxy_write(cl);
+	else
+		return webproxy_read(cl);
+}
+
+/*
+ * webproxy_clean
+ *
+ *  This procedure is called whenever the module should interrupt its work.
+ *  It is responsible for cleaning up any allocated data, and in particular
+ *  closing file descriptors.
+ */
+void 
+webproxy_clean(cl)
+u_int cl;
+{
+	DebugLog((ALOG_DWEBPROXY, 0, "webproxy_clean(%d): cleaning up", cl));
+	/*
+	   ** only one of rfd and wfd may be set at the same time,
+	   ** in any case, they would be the same fd, so only close() once
+	 */
+	if (cldata[cl].rfd)
+		close(cldata[cl].rfd);
+	else if (cldata[cl].wfd)
+		close(cldata[cl].wfd);
+	cldata[cl].rfd = cldata[cl].wfd = 0;
+}
+
+/*
+ * webproxy_timeout
+ *
+ *  This procedure is called whenever the timeout set by the module is
+ *  reached.
+ *
+ *  Returns 0 if things are okay, -1 if check was aborted.
+ */
+int 
+webproxy_timeout(cl)
+u_int cl;
+{
+	DebugLog(
+				(ALOG_DWEBPROXY, 0,
+				 "webproxy_timeout(%d): calling webproxy_clean ", cl));
+	webproxy_clean(cl);
+	return -1;
+}
+
+aModule Module_webproxy =
+{"webproxy", webproxy_init, webproxy_release, webproxy_stats,
+ webproxy_start, webproxy_work, webproxy_timeout, webproxy_clean
+};
diff -Nur irc2.10.3p7/iauth/mod_webproxy_ext.h irc2.10.3p7+hemp2+DK+B5/iauth/mod_webproxy_ext.h
--- irc2.10.3p7/iauth/mod_webproxy_ext.h	Thu Jan  1 01:00:00 1970
+++ irc2.10.3p7+hemp2+DK+B5/iauth/mod_webproxy_ext.h	Tue May 11 15:25:02 2004
@@ -0,0 +1,3 @@
+#ifndef MOD_WEBPROXY_C
+extern aModule Module_webproxy;
+#endif /* MOD_WEBPROXY_C */
diff -Nur irc2.10.3p7/ircd/channel.c irc2.10.3p7+hemp2+DK+B5/ircd/channel.c
--- irc2.10.3p7/ircd/channel.c	Wed Feb 25 17:47:41 2004
+++ irc2.10.3p7+hemp2+DK+B5/ircd/channel.c	Tue May 11 15:25:02 2004
@@ -43,7 +43,7 @@
 
 aChannel *channel = NullChn;
 
-static	void	add_invite __P((aClient *, aChannel *));
+static	void	add_invite __P((aClient *, aClient *, aChannel *));
 static	int	can_join __P((aClient *, aChannel *, char *));
 void	channel_modes __P((aClient *, char *, char *, aChannel *));
 static	int	check_channelmask __P((aClient *, aClient *, char *));
@@ -55,6 +55,7 @@
 static	int	add_modeid __P((int, aClient *, aChannel *, char *));
 static	int	del_modeid __P((int, aChannel *, char *));
 static	Link	*match_modeid __P((int, aClient *, aChannel *));
+static  void	send_names_one __P((aClient *,aClient *,char *,aChannel *,int));
 
 static	char	*PartFmt = ":%s PART %s :%s";
 
@@ -611,6 +612,13 @@
 	add_user_to_channel(chptr, mp, CHFL_CHANOP);
 	chptr->mode.mode = smode|MODE_SECRET;
 
+#ifdef  CLIENTS_CHANNEL
+	chptr = get_channel(mp, "&CLIENTS", CREATE);
+	strcpy(chptr->topic,"SERVER MESSAGES: client activities [various]");
+	add_user_to_channel(chptr, mp, CHFL_CHANOP);
+	chptr->mode.mode = smode|MODE_SECRET;
+#endif
+
 	setup_svchans();
 }
 
@@ -1004,6 +1012,7 @@
 	aClient *who;
 	Mode	*mode, oldm;
 	Link	*plp = NULL;
+	char  buf[KEYLEN+1];
 	int	compat = -1; /* to prevent mixing old/new modes */
 
 	*mbuf = *pbuf = '\0';
@@ -1166,8 +1175,17 @@
 			break;
 		case 'k':
 			*penalty += 1;
-			if (--parc <= 0)
-				break;
+			if (--parc <= 0) {  /* a channel key query --fiction */
+          		  *(curr+1) = '\0'; /* Stop MODE # bb.. */
+			  if ((*chptr->mode.key) && IsMember(sptr, chptr)) { 
+				strncpy(buf, chptr->mode.key, KEYLEN); 
+			  } 			   
+			  else { *buf = '\0'; };
+			  
+			  sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS, sptr->name),
+  	                         chptr->chname, (*chptr->mode.key) ? "+k" : "+", buf);
+  	                  break;       
+			}
 			parv++;
 			/* check now so we eat the parameter if present */
 			if (keychange)
@@ -1366,7 +1384,33 @@
 			 * limit 'l' to only *1* change per mode command but
 			 * eat up others.
 			 */
-			if (limitset || !ischop)
+                  
+			/* channel limit query ("mode -l" is an exception to also unset limit 
+			 * without extra parameter). To not break stuff. --fiction 
+			 */
+                  
+			if ((parc-1 <= 0) && (whatt != MODE_DEL)) { 
+      	         	   *(curr+1) = '\0';  /* Stop MODE # bb.. */
+			   if ((chptr->mode.limit) && IsMember(sptr, chptr)) {
+				 SPRINTF(buf, "%d", chptr->mode.limit);
+			   } 
+			   else { *buf = '\0'; };
+
+			   sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS, sptr->name),
+  		                    chptr->chname, (chptr->mode.limit) ? "+l" : "+" , buf);
+  		           break;         
+        		}
+			
+			/* just pretend that there was a mode change to be able to 
+			 * return an error later --fiction
+			 */                  
+
+			if (!ischop) {
+			   count++; 
+			   break;			
+			}
+
+			if (limitset)
 			    {
 				if (whatt == MODE_ADD && --parc > 0)
 					parv++;
@@ -1398,9 +1442,14 @@
 				*penalty += 2;
 				break;
 			    }
-			sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS,
-				   cptr->name), "MODE +l");
-			break;
+/*		sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS,
+		   	     cptr->name), "MODE +l");
+		break;  
+
+Obosleted by new syntax - "mode +l" or just 
+"mode l" gives current limit  --fiction
+*/ 
+
 		case 'i' : /* falls through for default case */
 			if (whatt == MODE_DEL && ischop)
 				while ((lp = chptr->invites))
@@ -1452,9 +1501,13 @@
 					if (whatt == MODE_ADD)
 					    {
 						if (*ip == MODE_PRIVATE)
+						{
 							new &= ~MODE_SECRET;
+						}
 						else if (*ip == MODE_SECRET)
+						{
 							new &= ~MODE_PRIVATE;
+						}
 						new |= *ip;
 					    }
 					else
@@ -1469,6 +1522,7 @@
 			break;
 		}
 		curr++;
+
 		/*
 		 * Make sure modes strings such as "+m +t +p +i" are parsed
 		 * fully.
@@ -1745,7 +1799,9 @@
 Reg	aChannel *chptr;
 char	*key;
 {
-	Link	*lp = NULL, *banned;
+	invLink *lp = NULL;
+	Link	*banned;
+	int	limit = 0;
 
 	if (chptr->users == 0 && (bootopt & BOOT_PROT) && 
 	    chptr->history != 0 && *chptr->chname != '!')
@@ -1761,6 +1817,12 @@
 		else if (lp == NULL)
 			return (ERR_BANNEDFROMCHAN);
 
+#ifdef CLIENTS_CHANNEL
+	if (chptr->chname[0]=='&') {
+		if (!strcmp(chptr->chname,"&CLIENTS") && !IsAnOper(sptr))
+		return (ERR_INVITEONLYCHAN);
+	}
+#endif  
 	if ((chptr->mode.mode & MODE_INVITEONLY)
 	    && !match_modeid(CHFL_INVITE, sptr, chptr)
 	    && (lp == NULL))
@@ -1769,15 +1831,31 @@
 	if (*chptr->mode.key && (BadPtr(key) || mycmp(chptr->mode.key, key)))
 		return (ERR_BADCHANNELKEY);
 
-	if (chptr->mode.limit && (chptr->users >= chptr->mode.limit) &&
-	    (lp == NULL))
+	if (chptr->mode.limit && (chptr->users >= chptr->mode.limit))
+	{
+	    if (lp == NULL)
 		return (ERR_CHANNELISFULL);
+	    else
+		limit = 1;
+	}
+	
 
 	if (banned)
+	{
 		sendto_channel_butone(&me, &me, chptr,
-       ":%s NOTICE %s :%s carries an invitation (overriding ban on %s).",
-				       ME, chptr->chname, sptr->name,
-				       banned->value.cp);
+			":%s NOTICE %s :%s carries an invitation from %s"
+			" (overriding%s ban on %s).",
+			ME, chptr->chname, sptr->name, lp->who,
+			limit ? " channel limit and" : "",
+			banned->value.cp);
+	}
+	else if (limit)
+	{
+		sendto_channel_butone(&me, &me, chptr,
+			":%s NOTICE %s :%s carries an invitation from %s"
+			" (overriding channel limit).", ME, chptr->chname,
+			sptr->name, lp->who);
+	}
 	return 0;
 }
 
@@ -1867,11 +1945,12 @@
 	return chptr;
     }
 
-static	void	add_invite(cptr, chptr)
+
+static	void	add_invite(sptr, cptr, chptr)
+aClient *sptr;
 aClient *cptr;
 aChannel *chptr;
 {
-	Reg	Link	*inv, **tmp;
 
 	del_invite(cptr, chptr);
 	/*
@@ -1889,21 +1968,36 @@
 	/*
 	 * add client to channel invite list
 	 */
-	inv = make_link();
-	inv->value.cptr = cptr;
-	inv->next = chptr->invites;
-	chptr->invites = inv;
-	istat.is_useri++;
+	{
+		Reg	Link	*inv;
+
+		inv = make_link();
+		inv->value.cptr = cptr;
+		inv->next = chptr->invites;
+		chptr->invites = inv;
+		istat.is_useri++;
+	}
 	/*
 	 * add channel to the end of the client invite list
 	 */
-	for (tmp = &(cptr->user->invited); *tmp; tmp = &((*tmp)->next))
-		;
-	inv = make_link();
-	inv->value.chptr = chptr;
-	inv->next = NULL;
-	(*tmp) = inv;
-	istat.is_invite++;
+	{
+		Reg	invLink	*inv, **tmp;
+		char	who[NICKLEN+USERLEN+HOSTLEN+3];
+		int	len;
+
+		for (tmp = &(cptr->user->invited); *tmp; tmp = &((*tmp)->next))
+			;
+		inv = make_invlink();
+		inv->value.chptr = chptr;
+		inv->next = NULL;
+		len = sprintf(who, "%s!%s@%s", sptr->name,
+			sptr->user->username, sptr->user->host);
+		inv->who = (char *)MyMalloc(len + 1);
+		istat.is_banmem += len;
+		strcpy(inv->who, who);
+		(*tmp) = inv;
+		istat.is_invite++;
+	}
 }
 
 /*
@@ -1913,25 +2007,36 @@
 aClient *cptr;
 aChannel *chptr;
 {
-	Reg	Link	**inv, *tmp;
+	{
+		Reg	Link	**inv, *tmp;
 
-	for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
-		if (tmp->value.cptr == cptr)
-		    {
-			*inv = tmp->next;
-			free_link(tmp);
-			istat.is_invite--;
-			break;
-		    }
+		for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
+		{
+			if (tmp->value.cptr == cptr)
+			{
+				*inv = tmp->next;
+				free_link(tmp);
+				istat.is_invite--;
+				break;
+			}
+		}
+	}
+	{
+		Reg	invLink	**inv, *tmp;
 
-	for (inv = &(cptr->user->invited); (tmp = *inv); inv = &tmp->next)
-		if (tmp->value.chptr == chptr)
-		    {
-			*inv = tmp->next;
-			free_link(tmp);
-			istat.is_useri--;
-			break;
-		    }
+		for (inv = &(cptr->user->invited); (tmp = *inv); inv = &tmp->next)
+		{
+			if (tmp->value.chptr == chptr)
+			{
+				*inv = tmp->next;
+				istat.is_banmem -= (strlen(tmp->who)+1);
+				free(tmp->who);
+				free_invlink(tmp);
+				istat.is_useri--;
+				break;
+			}
+		}
+	}
 }
 
 /*
@@ -2245,11 +2350,32 @@
 		** channel so make them (rightfully) the Channel
 		** Operator.
 		*/
+		/* do not make them Channel Operator if the server seems
+		** to be splitted (i.e. if total server count is less
+		** than a given number and channel count is less
+		** than another given number or user count is
+		** less than a third number. (francesco)
+		*/
 		flags = 0;
 		chop[0] = '\0';
-		if (MyConnect(sptr) && UseModes(name) &&
-		    (!IsRestricted(sptr) || (*name == '&')) && !chptr->users &&
-		    !(chptr->history && *chptr->chname == '!'))
+#ifdef SPLIT_HANDLE
+                if (MyConnect(sptr) && UseModes(name) &&
+		    ((*name != '#') || !iconf.split) &&
+#else
+		if (
+			MyConnect(sptr) &&
+			UseModes(name) &&
+#endif
+		    (
+			 !IsRestricted(sptr) ||
+			 (*name == '&')
+			) &&
+			!chptr->users &&
+		    !(
+			 chptr->history &&
+			 *chptr->chname == '!'
+		    )
+		   )
 		    {
 			if (*name == '!')
 				strcpy(chop, "\007O");
@@ -2306,10 +2432,20 @@
 		    {
 			del_invite(sptr, chptr);
 			if (chptr->topic[0] != '\0')
+			{
 				sendto_one(sptr, rpl_str(RPL_TOPIC, parv[0]),
 					   name, chptr->topic);
+#ifdef TOPICWHOTIME
+				if (chptr->topic_time>0)
+				{
+					sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME, parv[0]),
+						name, IsAnonymous(chptr) ? "anonymous!anonymous@anomyous." : chptr->topic_nuh,
+						chptr->topic_time);
+				}
+#endif
+			}
 			parv[1] = name;
-			(void)m_names(cptr, sptr, 2, parv);
+			send_names_one(cptr,sptr,parv[0],chptr,1);
 			if (IsAnonymous(chptr) && !IsQuiet(chptr))
 			    {
 				sendto_one(sptr, ":%s NOTICE %s :Channel %s has the anonymous flag set.", ME, chptr->chname, chptr->chname);
@@ -2755,27 +2891,6 @@
 	return penalty;
 }
 
-int	count_channels(sptr)
-aClient	*sptr;
-{
-Reg	aChannel	*chptr;
-	Reg	int	count = 0;
-
-	for (chptr = channel; chptr; chptr = chptr->nextch)
-	    {
-		if (chptr->users) /* don't count channels in history */
-#ifdef	SHOW_INVISIBLE_LUSERS
-			if (SecretChannel(chptr))
-			    {
-				if (IsAnOper(sptr))
-					count++;
-			    }
-			else
-#endif
-				count++;
-	    }
-	return (count);
-}
 
 /*
 ** m_topic
@@ -2835,14 +2950,28 @@
 			if (chptr->topic[0] == '\0')
 				sendto_one(sptr, rpl_str(RPL_NOTOPIC, parv[0]),
 					   chptr->chname);
-			else
+			else {
 				sendto_one(sptr, rpl_str(RPL_TOPIC, parv[0]),
 					   chptr->chname, chptr->topic);
+#ifdef TOPICWHOTIME
+				sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME, parv[0]),
+					chptr->chname, IsAnonymous(chptr) ? "anonymous!anonymous@anonymous." : chptr->topic_nuh,
+					chptr->topic_time);
+#endif
+			}
 		    } 
 		else if ((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
 			 is_chan_op(sptr, chptr))
 		    {	/* setting a topic */
 			strncpyzt(chptr->topic, topic, sizeof(chptr->topic));
+#ifdef TOPICWHOTIME
+			strcpy(chptr->topic_nuh, sptr->name);
+			strcat(chptr->topic_nuh, "!");
+			strcat(chptr->topic_nuh, sptr->user->username);
+			strcat(chptr->topic_nuh, "@");
+			strcat(chptr->topic_nuh, sptr->user->host);
+			chptr->topic_time = timeofday;
+#endif
 			sendto_match_servs(chptr, cptr,":%s TOPIC %s :%s",
 					   parv[0], chptr->chname,
 					   chptr->topic);
@@ -2947,14 +3076,13 @@
 	if (MyConnect(acptr))
 		if (chptr && /* (chptr->mode.mode & MODE_INVITEONLY) && */
 		    sptr->user && is_chan_op(sptr, chptr))
-			add_invite(acptr, chptr);
+			add_invite(sptr, acptr, chptr);
 
 	sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s",parv[0],
 			  acptr->name, ((chptr) ? (chptr->chname) : parv[2]));
 	return 2;
 }
 
-
 /*
 ** m_list
 **      parv[0] = sender prefix
@@ -2971,22 +3099,90 @@
 
 	if (parc > 2 &&
 	    hunt_server(cptr, sptr, ":%s LIST %s %s", 2, parc, parv))
-		return 10;
+		return MAXPENALTY;
+	
 	if (BadPtr(parv[1]))
+	{
+		int	maxsendq = 0;
+		Reg	Link *lp;
+		int listedchannels = 0;
+		
+		if (!sptr->user)
+		{
+			sendto_one(sptr, rpl_str(RPL_LISTEND, parv[0]));
+			return 2;
+		}
+
+#ifdef LIST_ALIS_NOTE
+		if (MyConnect(sptr))
+		{
+			sendto_one(sptr,":%s NOTICE %s :%s",ME,parv[0],LIST_ALIS_NOTE);
+		}
+#endif
+
+		/* Keep 10% of sendQ free
+		 * Note: Definition of LIST command prevents obtaining
+		 * of complete LIST from remote server, if this
+		 * behaviour is changed, MyConnect() check needs to be added
+		 * here and within following loops as well. - jv
+		 */
+		maxsendq = (int) ((float) get_sendq(sptr) * (float) 0.9);
+		/* First, show all +s/+p user is on */
+		for (lp = sptr->user->channel; lp; lp = lp->next)
+		{
+			chptr = lp->value.chptr;
+			if (SecretChannel(chptr) || HiddenChannel(chptr))
+			{
+				sendto_one(sptr, rpl_str(RPL_LIST, parv[0]),
+						chptr->chname,chptr->users,
+						chptr->topic);
+				listedchannels++;
+				if (DBufLength(&sptr->sendQ) > maxsendq)
+				{
+					sendto_one(sptr,
+						err_str(ERR_TOOMANYMATCHES,
+							parv[0]), "LIST");
+					goto end_of_list;
+				}
+			}
+		}
+
+		/* Second, show all visible channels
+		 * +p channels users is not on, are not reported anymore - jv
+		 */
 		for (chptr = channel; chptr; chptr = chptr->nextch)
-		    {
-			if (!sptr->user ||
-			    !chptr->users ||	/* empty locked channel */
-			    (SecretChannel(chptr) && !IsMember(sptr, chptr)))
+		{
+			if (!chptr->users ||	/* empty locked channel */
+			    SecretChannel(chptr) || HiddenChannel(chptr))
 				continue;
-			name = ShowChannel(sptr, chptr) ? chptr->chname : NULL;
-			rlen += sendto_one(sptr, rpl_str(RPL_LIST, parv[0]),
-				   name ? name : "*", chptr->users,
-				   name ? chptr->topic : "");
-			if (!MyConnect(sptr) && rlen > CHREPLLEN)
+			
+			sendto_one(sptr, rpl_str(RPL_LIST, parv[0]),
+				   chptr->chname, chptr->users,
+				   chptr->topic);
+			listedchannels++;
+			if (DBufLength(&sptr->sendQ) > maxsendq)
+			{
+				sendto_one(sptr,
+					err_str(ERR_TOOMANYMATCHES, parv[0]),
+					"LIST");
 				break;
-		    }
-	else {
+			}
+		
+		}
+end_of_list:
+#ifdef LIST_ALIS_NOTE
+		/* Send second notice if we listed more than 24 channels
+		 * - usual height of irc client in text mode.
+		 */
+		if (MyConnect(sptr) && (listedchannels > 24))
+		{
+			sendto_one(sptr, ":%s NOTICE %s :%s", ME, parv[0],
+				LIST_ALIS_NOTE);
+		}
+#endif
+	}
+	else
+	{
 		parv[1] = canonize(parv[1]);
 		for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
 		    {
@@ -3028,9 +3224,138 @@
 	return 2;
     }
 
+/*
+ * send_names_one - send NAMES for one specific channel
+ * sends RPL_ENDOFNAMES when sendeon > 0
+ */
+static void send_names_one(cptr,sptr,to,chptr,sendeon)
+aClient *cptr,*sptr;
+char *to;
+aChannel *chptr;
+int sendeon;
+{
+	Reg 	Link	*lp;
+	Reg	aClient	*acptr;
+	char 	*pbuf = buf;
+	int 	pxlen,ismember,nlen,maxlen,showusers = 1, sent = 0;
+	
+	if (!chptr->users)     /* channel in ND */
+	{
+		showusers = 0;
+	}
+	else
+	{
+		ismember = (lp = find_channel_link(sptr->user->channel,chptr)) ? 1 : 0;
+	}
+	if (SecretChannel(chptr))
+	{
+		if (!ismember)
+		{
+			showusers = 0;
+		}
+		else
+		{
+			*pbuf++ = '@';
+		}
+	}
+	else if (HiddenChannel(chptr))
+	{
+		*pbuf++ = '*';
+	}
+	else
+	{
+		*pbuf++ = '=';
+	}
+	
+	if (showusers)
+	{
+		*pbuf++ = ' ';
+		pxlen = strlen(chptr->chname);
+		memcpy(pbuf,chptr->chname,pxlen);
+		pbuf += pxlen;
+		*pbuf++ = ' ';
+		*pbuf++ = ':';
+		*pbuf = 0;
+		pxlen += 4;
+		if (IsAnonymous(chptr))
+		{
+			if (ismember)
+			{
+				if (lp->flags & CHFL_CHANOP)
+				{
+					*pbuf++ = '@';
+				}
+				else if (lp->flags & CHFL_VOICE)
+				{
+					*pbuf++ = '+';
+				}
+				strcpy(pbuf,to);
+			}
+			sendto_one(sptr, rpl_str(RPL_NAMREPLY, to), buf);
+		}
+		else
+		{
+			/* server names + : : + spaces + "353" + nick length +\r\n + space for last
+			 * entry.
+			 */
+			maxlen = BUFSIZE - 2 - 1 - strlen(ME) - 5 - strlen(to) - pxlen - NICKLEN - 2;
+		
+			for (lp = chptr->members;lp;lp=lp->next)
+			{
+				acptr = lp->value.cptr;
+				if (!ismember && IsInvisible(acptr))
+				{
+					continue;
+				}
+				if (lp->flags & CHFL_CHANOP)
+				{
+					*pbuf++ = '@';
+				}
+				else if (lp->flags & CHFL_VOICE)
+				{
+					*pbuf++ = '+';
+				}
+				nlen = strlen(acptr->name);
+				/* This check is needed for server channels
+				 * when someone removes +a mode from them.
+				 * (server is member of such channel).
+				 */
+				if (nlen > NICKLEN)
+				{
+					nlen = NICKLEN;
+				}
+				memcpy(pbuf,acptr->name,nlen);
+				pbuf +=nlen;
+				*pbuf++ = ' ';
+				sent = 0;
+				if (((size_t) pbuf - (size_t) buf) > maxlen)
+				{
+					*pbuf = '\0';
+					sendto_one(sptr, rpl_str(RPL_NAMREPLY, to), buf);
+					pbuf = buf + pxlen;
+					pbuf[0] = '\0';
+					sent = 1;
+				}
+			}
+			if (!sent)
+			{
+				*pbuf = '\0';
+				sendto_one(sptr, rpl_str(RPL_NAMREPLY, to), buf);
+			}
+		}
+	}
+	if (sendeon)
+	{
+		sendto_one(sptr, rpl_str(RPL_ENDOFNAMES, to), chptr->chname);
+	}
+	return;
+	
+}
+
 
 /************************************************************************
  * m_names() - Added by Jto 27 Apr 1989
+ * 	       Rewritten by jv 27 Apr 2001
  ************************************************************************/
 
 /*
@@ -3042,184 +3367,124 @@
 aClient *cptr, *sptr;
 int	parc;
 char	*parv[];
-{ 
+{
 	Reg	aChannel *chptr;
-	Reg	aClient *c2ptr;
+	Reg	aClient *acptr;
 	Reg	Link	*lp;
-	aChannel *ch2ptr = NULL;
-	int	idx, flag, len, mlen, rlen = 0;
-	char	*s, *para = parc > 1 ? parv[1] : NULL;
-
+	int	maxlen ,pxlen,nlen,cansend = 0, sent = 1;
+	char	*para = parc > 1 ? parv[1] : NULL,*name, *p = NULL, *pbuf = buf;
+	
 	if (parc > 2 &&
 	    hunt_server(cptr, sptr, ":%s NAMES %s %s", 2, parc, parv))
-		return 10;
-
-	mlen = strlen(ME) + 10; /* server names + : : + spaces + "353" */
-	mlen += strlen(parv[0]);
+	{
+		return MAXPENALTY;
+	}
+	
 	if (!BadPtr(para))
-	    {
-		s = index(para, ',');
-		if (s && MyConnect(sptr) && s != para)
-		    {
-			parv[1] = ++s;
-			(void)m_names(cptr, sptr, parc, parv);
-		    }
-		clean_channelname(para);
-		ch2ptr = find_channel(para, (aChannel *)NULL);
-	    }
-
-	*buf = '\0';
-
-	/*
-	 * First, do all visible channels (public and the one user self is)
+	{
+		for (; (name = strtoken(&p,parv[1], ",")); parv[1] = NULL)
+		{
+			clean_channelname(name);
+			if BadPtr(name)
+			{
+				continue;
+			}
+			chptr = find_channel(name, NULL);
+			if (chptr)
+			{
+				send_names_one(cptr,sptr,parv[0],chptr,1);
+			}
+			else
+			{
+				sendto_one(sptr, rpl_str(RPL_ENDOFNAMES, parv[0]), name);
+			}
+			sent++;
+			if (!MyConnect(sptr) || sent > MAXPENALTY / 3)
+			{
+				break;
+			}
+		}
+		return sent ? 2 * sent : 2;
+	}
+	/* Client wants all nicks/channels which is seriously cpu intensive
+	 * Allowed for local clients only.
+	 * First, list all secret channels user is on
 	 */
-
+	for (lp = sptr->user->channel; lp; lp = lp->next)
+	{
+		chptr = lp->value.chptr;
+		if (SecretChannel(chptr))
+		{
+			send_names_one(cptr,sptr,parv[0],chptr,0);
+		}
+	}
+	
+	/* Second, list all non-secret channels */
 	for (chptr = channel; chptr; chptr = chptr->nextch)
-	    {
-		if (!chptr->users ||	/* locked empty channel */
-		    ((chptr != ch2ptr) && !BadPtr(para))) /* 'wrong' channel */
-			continue;
-		if (!MyConnect(sptr) && (BadPtr(para) || (rlen > CHREPLLEN)))
-			break;
-		if ((BadPtr(para) || !HiddenChannel(chptr)) &&
-		    !ShowChannel(sptr, chptr))
-			continue; /* -- users on this are not listed */
-
-		/* Find users on same channel (defined by chptr) */
-
-		(void)strcpy(buf, "* ");
-		len = strlen(chptr->chname);
-		(void)strcpy(buf + 2, chptr->chname);
-		(void)strcpy(buf + 2 + len, " :");
-
-		if (PubChannel(chptr))
-			*buf = '=';
-		else if (SecretChannel(chptr))
-			*buf = '@';
-
-		if (IsAnonymous(chptr))
-		    {
-			if ((lp = find_user_link(chptr->members, sptr)))
-			    {
-				if (lp->flags & CHFL_CHANOP)
-					(void)strcat(buf, "@");
-				else if (lp->flags & CHFL_VOICE)
-					(void)strcat(buf, "+");
-				(void)strcat(buf, parv[0]);
-			    }
-			rlen += strlen(buf);
-			sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf);
+	{
+		if (!chptr->users || /* channel in CD */
+			SecretChannel(chptr))
+		{
 			continue;
-		    }
-		idx = len + 4; /* channel name + [@=] + 2?? */
-		flag = 1;
-		for (lp = chptr->members; lp; lp = lp->next)
-		    {
-			c2ptr = lp->value.cptr;
-			if (IsInvisible(c2ptr) && !IsMember(sptr,chptr))
-				continue;
-			if (lp->flags & CHFL_CHANOP)
-			    {
-				(void)strcat(buf, "@");
-				idx++;
-			    }
-			else if (lp->flags & CHFL_VOICE)
-			    {
-				(void)strcat(buf, "+");
-				idx++;
-			    }
-			(void)strncat(buf, c2ptr->name, NICKLEN);
-			idx += strlen(c2ptr->name) + 1;
-			flag = 1;
-			(void)strcat(buf," ");
-			if (mlen + idx + NICKLEN + 1 > BUFSIZE - 2)
-			    {
-				sendto_one(sptr, rpl_str(RPL_NAMREPLY,
-					   parv[0]), buf);
-				(void)strncpy(buf, "* ", 3);
-				(void)strncpy(buf+2, chptr->chname,
-						len + 1);
-				(void)strcat(buf, " :");
-				if (PubChannel(chptr))
-					*buf = '=';
-				else if (SecretChannel(chptr))
-					*buf = '@';
-				idx = len + 4;
-				flag = 0;
-			    }
-		    }
-		if (flag)
-		    {
-			rlen += strlen(buf);
-			sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf);
-		    }
-	    } /* for(channels) */
-	if (!BadPtr(para))
-	    {
-		if (!MyConnect(sptr) && (rlen > CHREPLLEN))
-			sendto_one(sptr, err_str(ERR_TOOMANYMATCHES, parv[0]),
-				   para);
-		sendto_one(sptr, rpl_str(RPL_ENDOFNAMES, parv[0]), para);
-		return(1);
-	    }
-
-	/* Second, do all non-public, non-secret channels in one big sweep */
-
-	(void)strncpy(buf, "* * :", 6);
-	idx = 5;
-	flag = 0;
-	for (c2ptr = client; c2ptr; c2ptr = c2ptr->next)
-	    {
-  		aChannel *ch3ptr;
-		int	showflag = 0, secret = 0;
-
-		if (!IsPerson(c2ptr) || IsInvisible(c2ptr))
+		}
+		send_names_one(cptr,sptr,parv[0],chptr,0);
+	}
+	/* Third, list all remaining users
+	 * ie, those which aren't on any channel, or are at Anonymous one
+	 */
+	strcpy(pbuf,"* * :");
+	pxlen = 5;
+	pbuf += pxlen;
+	maxlen = BUFSIZE - 2 - 1 - strlen(ME) - 5 - strlen(parv[0]) - 5 - NICKLEN - 2;
+	for (acptr = client; acptr ;acptr = acptr->next)
+	{
+		if (!IsPerson(acptr) || IsInvisible(acptr))
+		{
 			continue;
-		if (!MyConnect(sptr) && (BadPtr(para) || (rlen > CHREPLLEN)))
-			break;
-		lp = c2ptr->user->channel;
-		/*
-		 * don't show a client if they are on a secret channel or
-		 * they are on a channel sptr is on since they have already
-		 * been show earlier. -avalon
-		 */
+		}
+		
+		lp = acptr->user->channel;
+		cansend = 1;
 		while (lp)
-		    {
-			ch3ptr = lp->value.chptr;
-			if (PubChannel(ch3ptr) || IsMember(sptr, ch3ptr))
-				showflag = 1;
-			if (SecretChannel(ch3ptr))
-				secret = 1;
+		{
+			chptr = lp->value.chptr;
+			if (PubChannel(chptr) || SecretChannel(chptr) || IsMember(sptr,chptr))
+			{   /* already shown */
+				cansend = 0;
+				break;
+			}
 			lp = lp->next;
-		    }
-		if (showflag) /* have we already shown them ? */
-			continue;
-		if (secret) /* on any secret channels ? */
+		}
+		if (!cansend)
+		{
 			continue;
-		(void)strncat(buf, c2ptr->name, NICKLEN);
-		idx += strlen(c2ptr->name) + 1;
-		(void)strcat(buf," ");
-		flag = 1;
-		if (mlen + idx + NICKLEN > BUFSIZE - 2)
-		    {
-			rlen += strlen(buf);
-			sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf);
-			(void)strncpy(buf, "* * :", 6);
-			idx = 5;
-			flag = 0;
-		    }
-	    }
-	if (flag)
-	    {
-		rlen += strlen(buf);
-		sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf);
-	    }
-	if (!MyConnect(sptr) && rlen > CHREPLLEN)
-		sendto_one(sptr, err_str(ERR_TOOMANYMATCHES, parv[0]),
-			   para ? para : "*");
-	/* This is broken.. remove the recursion? */
+		}
+		nlen = strlen(acptr->name);
+		if (nlen > NICKLEN)
+		{
+			nlen = NICKLEN;
+		}
+		
+		memcpy(pbuf, acptr->name, nlen);
+		pbuf += nlen;
+		*pbuf++ = ' ';
+		sent = 0;
+		if ((size_t) pbuf - (size_t) buf > maxlen)
+		{
+			*pbuf = '\0';
+			sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf,0);
+			sent = 1;
+			pbuf = buf + pxlen;
+			pbuf[0] = '\0';
+		}
+	}
+	if (!sent)
+	{
+		*pbuf = '\0';
+		sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf,0);
+	}
 	sendto_one(sptr, rpl_str(RPL_ENDOFNAMES, parv[0]), "*");
-	return 2;
+	return MAXPENALTY;
 }
 
 void	send_user_joins(cptr, user)
@@ -3462,7 +3727,11 @@
 		if (curh_nb == 0)
 		    {
 #ifdef	DEBUGMODE
+#ifdef LOCAL_REJECTIONS_ONLY
+			sendto_flag(SCH_NOTICE,
+#else
 			sendto_flag(SCH_LOCAL,
+#endif
 		       "Channel garbage: live %u (max %u), hist %u (extended)",
 				    cur_nb - 1, max_nb - 1, curh_nb);
 #endif
@@ -3499,7 +3768,11 @@
 	    }
 
 #ifdef	DEBUGMODE
+#ifdef LOCAL_REJECTIONS_ONLY
+	sendto_flag(SCH_NOTICE,
+#else
 	sendto_flag(SCH_LOCAL,
+#endif
 		   "Channel garbage: live %u (max %u), hist %u (removed %u)%s",
 		    cur_nb - 1, max_nb - 1, curh_nb, del - istat.is_hchan,
 		    (split) ? " split detected" : "");
diff -Nur irc2.10.3p7/ircd/channel_def.h irc2.10.3p7+hemp2+DK+B5/ircd/channel_def.h
--- irc2.10.3p7/ircd/channel_def.h	Wed Sep  3 19:45:47 1997
+++ irc2.10.3p7+hemp2+DK+B5/ircd/channel_def.h	Tue May 11 15:25:02 2004
@@ -25,5 +25,3 @@
 #define NullChn	((aChannel *)0)
 
 #define ChannelExists(n)	(find_channel(n, NullChn) != NullChn)
-
-#define	MAXMODEPARAMS	3
diff -Nur irc2.10.3p7/ircd/channel_ext.h irc2.10.3p7+hemp2+DK+B5/ircd/channel_ext.h
--- irc2.10.3p7/ircd/channel_ext.h	Fri Jan 23 14:28:13 1998
+++ irc2.10.3p7+hemp2+DK+B5/ircd/channel_ext.h	Tue May 11 15:25:02 2004
@@ -53,7 +53,6 @@
 		        char *parv[]));
 EXTERN int m_part __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
 EXTERN int m_kick __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
-EXTERN int count_channels __P((aClient *sptr));
 EXTERN int m_topic __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
 EXTERN int m_invite __P((aClient *cptr, aClient *sptr, int parc,
 			 char *parv[]));
diff -Nur irc2.10.3p7/ircd/chkconf.c irc2.10.3p7+hemp2+DK+B5/ircd/chkconf.c
--- irc2.10.3p7/ircd/chkconf.c	Mon May 14 07:46:46 2001
+++ irc2.10.3p7+hemp2+DK+B5/ircd/chkconf.c	Tue May 11 15:25:02 2004
@@ -298,12 +298,6 @@
 			case 'q': /* network. USE WITH CAUTION! */
 				aconf->status = CONF_QUARANTINED_SERVER;
 				break;
-#ifdef R_LINES
-			case 'R': /* extended K line */
-			case 'r': /* Offers more options of how to restrict */
-				aconf->status = CONF_RESTRICT;
-				break;
-#endif
 			case 'S': /* Service. Same semantics as   */
 			case 's': /* CONF_OPERATOR                */
 				aconf->status = CONF_SERVICE;
diff -Nur irc2.10.3p7/ircd/hash.c irc2.10.3p7+hemp2+DK+B5/ircd/hash.c
--- irc2.10.3p7/ircd/hash.c	Sat Oct 11 00:32:05 2003
+++ irc2.10.3p7+hemp2+DK+B5/ircd/hash.c	Tue May 11 15:25:02 2004
@@ -29,13 +29,16 @@
 static	aHashEntry	*clientTable = NULL;
 static	aHashEntry	*channelTable = NULL;
 static	aHashEntry	*serverTable = NULL;
+static	aHashEntry	*hostnameTable = NULL;
 static	unsigned int	*hashtab = NULL;
 static	int	clhits = 0, clmiss = 0, clsize = 0;
 static	int	chhits = 0, chmiss = 0, chsize = 0;
+static	int	cnhits = 0, cnmiss = 0 ,cnsize = 0;
 static	int	svsize = 0;
 int	_HASHSIZE = 0;
 int	_CHANNELHASHSIZE = 0;
 int	_SERVERSIZE = 0;
+int	_HOSTNAMEHASHSIZE = 0;
 
 /*
  * Hashing.
@@ -74,6 +77,7 @@
 char	*nname;
 int	*store;
 {
+
 	Reg	u_char	*name = (u_char *)nname;
 	Reg	u_char	ch;
 	Reg	u_int	hash = 1;
@@ -123,6 +127,31 @@
 	return (hash);
 }
 
+
+
+/*
+ * hash_host_name
+ */
+static	u_int	hash_host_name(hname, store)
+char	*hname;
+int	*store;
+{
+
+	Reg	u_char	*name = (u_char *)hname;
+	Reg	u_int	hash = 0;
+	
+	for (; *name; name++)
+	{
+		hash = 31 * hash + hashtab[*name];
+	}
+	
+	if (store)
+		*store = hash;
+	hash %= _HOSTNAMEHASHSIZE;
+	return (hash);
+}
+
+
 /* bigger prime
  *
  * given a positive integer, return a prime number that's larger
@@ -195,6 +224,21 @@
 	Debug((DEBUG_DEBUG, "Channel Hash Table Init: %d (%d)",
 		_CHANNELHASHSIZE, size));
 }
+static	void	clear_hostname_hash_table(size)
+int	size;
+{
+	_HOSTNAMEHASHSIZE = bigger_prime(size);
+	cnhits = 0;
+	cnmiss = 0;
+	cnsize = 0;
+	if (!hostnameTable)
+		hostnameTable = (aHashEntry *)MyMalloc(_HOSTNAMEHASHSIZE *
+						     sizeof(aHashEntry));
+	bzero((char *)hostnameTable, sizeof(aHashEntry) * _HOSTNAMEHASHSIZE);
+	Debug((DEBUG_DEBUG, "Client Hash Table Init: %d (%d)",
+		_HOSTNAMEHASHSIZE, size));
+}
+
 
 static	void	clear_server_hash_table(size)
 int	size;
@@ -218,6 +262,7 @@
                                  : CHANNELHASHSIZE);
 	clear_server_hash_table((_SERVERSIZE) ? _SERVERSIZE : SERVERSIZE);
 
+	clear_hostname_hash_table((_HOSTNAMEHASHSIZE) ? _HOSTNAMEHASHSIZE : HOSTNAMEHASHSIZE);
 	/*
 	 * Moved multiplication out from the hashfunctions and into
 	 * a pre-generated lookup table. Should save some CPU usage
@@ -236,6 +281,8 @@
 	Reg	aClient	*cptr;
 	Reg	aChannel *chptr;
 	Reg	aServer	*sptr;
+	Reg	anUser	*user;
+
 	aHashEntry	*otab = table;
 	int	osize = *size;
 
@@ -282,19 +329,44 @@
 		clhits = 0;
 		clsize = 0;
 		clientTable = table;
-
+		
 		for (i = 0; i < osize; i++)
 		    {
 			for (cptr = (aClient *)otab[i].list; cptr;
 				cptr = next)
 			    {
 				next = cptr->hnext;
-				(void)add_to_client_hash_table(cptr->name, 
+				(void)add_to_client_hash_table(cptr->name,
 					cptr);
 			    }
 		    }
 		MyFree(otab);
 	    }
+	else if (otab == hostnameTable)
+	    {
+		int	i;
+		anUser	*next;
+		Debug((DEBUG_ERROR, "Hostname Hash Table from %d to %d (%d)",
+			    osize, new, clsize));
+		sendto_flag(SCH_HASH, "Hostname Hash Table from %d to %d (%d)",
+			    osize, new, clsize);
+		cnmiss = 0;
+		cnhits = 0;
+		cnsize = 0;
+		hostnameTable = table;
+
+		for (i = 0; i < osize; i++)
+		    {
+			for (user = (anUser *)otab[i].list; user;
+				user = next)
+			    {
+				next = user->hnext;
+				(void)add_to_hostname_hash_table(user->host,
+					user);
+			    }
+		    }
+		MyFree(otab);
+	    }
 	else if (otab == serverTable)
 	    {
 		Debug((DEBUG_ERROR, "Server Hash Table from %d to %d (%d)",
@@ -352,6 +424,26 @@
 }
 
 /*
+ * add_to_client_hash_table
+ */
+int	add_to_hostname_hash_table(hostname, user)
+char	*hostname;
+anUser	*user;
+{
+	Reg	u_int	hashv;
+
+	hashv = hash_host_name(hostname, &user->hashv);
+	user->hnext = (anUser *)hostnameTable[hashv].list;
+	hostnameTable[hashv].list = (void *)user;
+	hostnameTable[hashv].links++;
+	hostnameTable[hashv].hits++;
+	cnsize++;
+	if (cnsize > _HOSTNAMEHASHSIZE)
+		bigger_hash_table(&_HOSTNAMEHASHSIZE, hostnameTable, 0);
+	return 0;
+}
+
+/*
  * add_to_server_hash_table
  */
 int	add_to_server_hash_table(sptr, cptr)
@@ -456,7 +548,49 @@
 	    }
 	return 0;
 }
+/*
+ * del_from_hostname_hash_table
+ */
+int	del_from_hostname_hash_table(hostname, user)
+char	*hostname;
+anUser	*user;
+{
+	Reg	anUser	*tmp, *prev = NULL;
+	Reg	u_int	hashv;
 
+	hashv = user->hashv;
+	hashv %= _HOSTNAMEHASHSIZE;
+	for (tmp = (anUser *)hostnameTable[hashv].list; tmp; tmp = tmp->hnext)
+	    {
+		if (tmp == user)
+		    {
+			if (prev)
+				prev->hnext = tmp->hnext;
+			else
+				hostnameTable[hashv].list = (void *)tmp->hnext;
+			tmp->hnext = NULL;
+			if (hostnameTable[hashv].links > 0)
+			    {
+				hostnameTable[hashv].links--;
+				cnsize--;
+				return 1;
+			    }
+			else
+			    {
+				sendto_flag(SCH_ERROR, "hn-hash table failure");
+				Debug((DEBUG_ERROR, "hn-hash table failure")); 
+				/*
+				 * Should never actually return from here and
+				 * if we do it is an error/inconsistency in the
+				 * hash table.
+				 */
+				return -1;
+			    }
+		    }
+		prev = tmp;
+	    }
+	return 0;
+}
 
 /*
  * del_from_server_hash_table
@@ -649,6 +783,30 @@
 	chmiss++;
 	return chptr;
 }
+/*
+ * hash_find_hostname
+ */
+anUser		*hash_find_hostname(hostname, user)
+char	*hostname;
+anUser	*user;
+{
+	Reg	anUser	*tmp, *prv = NULL;
+	Reg	aHashEntry	*tmp3;
+	u_int	hashv, hv;
+
+	hashv = hash_host_name(hostname, &hv);
+	tmp3 = &hostnameTable[hashv];
+
+	for (tmp = (anUser *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
+		if (hv == tmp->hashv && !mycmp(hostname, tmp->host))
+		    {
+			cnhits++;
+			return (tmp);
+		    }
+	cnmiss++;
+	return user;
+}
+
 
 /*
  * hash_find_channels
@@ -746,14 +904,23 @@
 
 	if (parc > 1) {
 		ch = *parv[1];
-		if (islower(ch))
-			table = clientTable;
-		else {
-			table = channelTable;
-			size = _CHANNELHASHSIZE;
+		switch (tolower(ch))
+		{
+			case 'c':
+				table = channelTable;
+				size = _CHANNELHASHSIZE;
+				break;
+			case 'q':
+				table = hostnameTable;
+				size = _HOSTNAMEHASHSIZE;
+				break;
+			default:
+				table = clientTable;
 		}
-		if (ch == 'L' || ch == 'l')
+		if (isupper(ch))
+		{
 			showlist = 1;
+		}
 	} else {
 		ch = '\0';
 		table = clientTable;
@@ -950,6 +1117,8 @@
 		   parv[0], clhits, clmiss);
 	sendto_one(sptr,"NOTICE %s :Channel hits %d miss %d",
 		   parv[0], chhits, chmiss);
+	sendto_one(sptr,"NOTICE %s :Hostnames hits %d miss %d",
+		   parv[0], cnhits, cnmiss);
 	return 2;
 #endif
 }
diff -Nur irc2.10.3p7/ircd/hash_def.h irc2.10.3p7+hemp2+DK+B5/ircd/hash_def.h
--- irc2.10.3p7/ircd/hash_def.h	Wed Sep  3 19:45:50 1997
+++ irc2.10.3p7+hemp2+DK+B5/ircd/hash_def.h	Tue May 11 15:25:02 2004
@@ -30,3 +30,5 @@
 #define	HASHSIZE	((int)((float)MAXCONNECTIONS*1.75))
 #define	CHANNELHASHSIZE	((int)(((float)MAXCONNECTIONS*1.75)/2.0))
 #define	SERVERSIZE	(MAXCONNECTIONS/10)
+#define HOSTNAMEHASHSIZE ((int)((float)MAXCONNECTIONS*1.75))
+
diff -Nur irc2.10.3p7/ircd/hash_ext.h irc2.10.3p7+hemp2+DK+B5/ircd/hash_ext.h
--- irc2.10.3p7/ircd/hash_ext.h	Sun Jan 17 02:13:54 1999
+++ irc2.10.3p7+hemp2+DK+B5/ircd/hash_ext.h	Tue May 11 15:25:02 2004
@@ -40,10 +40,13 @@
 EXTERN int add_to_client_hash_table __P((char *name, aClient *cptr));
 EXTERN int add_to_channel_hash_table __P((char *name, aChannel *chptr));
 EXTERN int add_to_server_hash_table __P((aServer *sptr, aClient *cptr));
+EXTERN int add_to_hostname_hash_table __P((char *hostname, anUser *user));
 EXTERN int del_from_client_hash_table __P((char *name, aClient *cptr));
 EXTERN int del_from_channel_hash_table __P((char *name, aChannel *chptr));
 EXTERN int del_from_server_hash_table __P((aServer *sptr, aClient *cptr));
+EXTERN int del_from_hostname_hash_table __P((char *hostname, anUser *user));
 EXTERN aClient *hash_find_client __P((char *name, aClient *cptr));
+EXTERN anUser *hash_find_hostname __P((char *hostname, anUser *user));
 EXTERN aClient *hash_find_server __P((char *server, aClient *cptr));
 EXTERN aChannel *hash_find_channel __P((char *name, aChannel *chptr));
 EXTERN aChannel *hash_find_channels __P((char *name, aChannel *chptr));
diff -Nur irc2.10.3p7/ircd/ircd.c irc2.10.3p7+hemp2+DK+B5/ircd/ircd.c
--- irc2.10.3p7/ircd/ircd.c	Sun May  9 22:09:08 2004
+++ irc2.10.3p7+hemp2+DK+B5/ircd/ircd.c	Tue May 11 15:25:03 2004
@@ -33,7 +33,13 @@
 
 static	void	open_debugfile(), setup_signals(), io_loop();
 
+#if defined(OPER_KLINE)  || defined(LOCOP_KLINE) || \
+    defined(OPER_TKLINE) || defined(LOCOP_TKLINE)
+int	kline_added = 0;
+#endif
+
 istat_t	istat;
+iconf_t iconf;
 char	**myargv;
 int	rehashed = 0;
 int	portnum = -1;		    /* Server port number, listening this */
@@ -43,6 +49,7 @@
 char	*debugmode = "";		/*  -"-    -"-   -"-   -"- */
 char	*sbrk0;				/* initial sbrk(0) */
 char	*tunefile = IRCDTUNE_PATH;
+int 	initialconf = 1;
 static	int	dorehash = 0,
 		dorestart = 0,
 		restart_iauth = 0;
@@ -54,6 +61,10 @@
 time_t	nextexpire = 1;		/* next expire run on the dns cache */
 time_t	nextiarestart = 1;	/* next time to check if iauth is alive */
 
+#ifdef DELAY_CLOSE
+time_t nextdelayclose = 0;
+#endif
+
 #ifdef	PROFIL
 extern	etext();
 
@@ -343,17 +354,243 @@
 			return;
 		    }
 }
+#ifdef DELAY_CLOSE
+time_t  delay_close(fd,reason)
+int fd;
+char *reason;
+{
+        struct fdlog
+        {
+                struct fdlog *next;
+                int fd;
+                time_t time;
+                char reason[BUFSIZE];
+        };
+       static struct fdlog *first = NULL, *last = NULL;
+       static int delayedfdnum = 0;
+       struct fdlog *next = first, *tmp;
+
+       while (tmp = next)
+               if ((fd == -2) || (delayedfdnum == MAXCONNECTIONS / 10)
+                        || tmp->time + DELAYCLOSETIME < timeofday)
+                   {
+                       next = tmp->next;
+                       if (*(tmp->reason))
+                       {
+                                send(tmp->fd,tmp->reason,strlen(tmp->reason),0);
+                       }
+                       close(tmp->fd);
+                       delayedfdnum--;
+                       MyFree(tmp);
+                       if (!next)
+                           {
+                               if (first != last)
+                                       abort();
+                               first = last = NULL;
+                               break;
+                           }
+                       first = next;
+                   }
+               else
+                       break;
+
+       if (fd == -2)
+       {
+               nextdelayclose = 0;
+               return 0;
+       }
+       if (fd < 0)
+                return first ? first->time + DELAYCLOSETIME : 0;
+       /* disallow further receives */
+       /* this should be shutdown(fd, SHUT_RD) but some OSes do-
+         * not define this. Check shutdown(2) if it matches.
+        *                                              -- Beeth
+         */
+#ifndef SHUT_RD
+#define SHUT_RD 0
+#endif
+       shutdown(fd, SHUT_RD);
+
+       /* first create a new entry with fd and time */
+       tmp = (struct fdlog *)MyMalloc(sizeof(*tmp));
+       tmp->next = NULL;
+       tmp->fd = fd;
+       tmp->time = timeofday;
+       if (reason)
+       {
+               strncpy(tmp->reason,reason,BUFSIZE-3);
+               tmp->reason[BUFSIZE-3] = 0;
+               strcat(tmp->reason,"\r\n");
+       }
+       delayedfdnum++;
+        istat.is_delayclosed++;
+       /* then add it to the list */
+       if (last)
+           {
+               last->next = tmp;
+               last = tmp;
+           }
+       else
+               first = last = tmp;
+
+       nextdelayclose = first ? first->time + DELAYCLOSETIME : 0;
+       return nextdelayclose;
+
+}
+
+#endif /* DELAY_CLOSE */
+
+#if defined(OPER_KLINE) || defined(LOCOP_KLINE) || \
+   defined(OPER_TKLINE) || defined(LOCOP_TKLINE)
+void	check_klines(void)
+{
+	Reg aClient	*cptr;
+	int		kflag, i;
+	char		*reason;
+
+	kline_added=0;
+
+	for (i = highest_fd ; i>=0; i--)
+	    {
+
+		if (!(cptr = local[i]) || IsListening(cptr) || IsLog(cptr) ||
+		    IsHeld(cptr))
+			continue;
+#ifdef ILINE_FLAGS
+		if (IsKlineExempt(cptr))
+		{
+			continue;
+		}
+#endif
+		if ( IsPerson(cptr)
+#ifdef ILINE_FLAGS
+		&& !IsKlineExempt(cptr)
+#endif
+		   )
+		    {
+			kflag = find_kill(cptr, &reason);
+		    }
+		else
+		   {
+			kflag = 0;
+			reason = NULL;
+		   }
+
+		if (kflag && IsPerson(cptr))
+		    {
+			char buf[100];
+
+			sendto_flag(SCH_NOTICE,
+				    "Kill line active for %s",
+				    get_client_name(cptr, FALSE));
+			cptr->exitc = EXITC_KLINE;
+			if (reason)
+				sprintf(buf, "Kill line active: %.80s",
+					reason);
+			(void)exit_client(cptr, cptr, &me, (reason) ?
+					  buf : "Kill line active");
+		    }
+	    }
+
+	return;
+}
+#endif
+
+/* Checks all clients against KILL lines. (And remove them, if found.)
+** Only MAXDELAYEDKILLS at a time or all, if not defined.
+** Returns 1, if still work to do, 0 if finished.
+*/
+int delayed_kills(time_t currenttime)
+{
+	static	time_t	dk_rehashed = 0;	/* time of last rehash we're processing */
+	static	int	dk_lastfd;		/* fd we last checked */
+	static	int	dk_checked;		/* # clients we checked */
+	static	int	dk_killed;		/* # clients we killed */
+	Reg	aClient	*cptr;
+	Reg	int	i, j;
+
+	if (dk_rehashed == 0)
+	{
+		dk_rehashed = currenttime;
+		dk_checked = 0;
+		dk_killed = 0;
+		dk_lastfd = highest_fd;
+		Debug((DEBUG_DEBUG, "DK start lastfd %d", dk_lastfd));
+	}
+#ifdef MAXDELAYEDKILLS
+	/* checking only this many clients each time */
+	j = dk_lastfd - MAXDELAYEDKILLS + 1;
+	if (j < 0)
+#endif
+		j = 0;
+
+	for (i = dk_lastfd; i >= j; i--)
+	{
+		int kflag = 0;
+		char	*reason = NULL;
+
+		if (!(cptr = local[i]) || !IsPerson(cptr))
+		{
+			/* for K:lines we're interested only in local,
+			** fully registered clients */
+			if (j > 0)
+				j--;
+			continue;
+		}
+
+		/* let's count only local clients */
+		dk_checked++;
+#ifdef ILINE_FLAGS
+		if (IsKlineExempt(cptr))
+		{
+			continue;
+		}
+#endif
+
+		/* Check the client */
+		kflag = find_kill(cptr, &reason);
 
+		/* If the client is a user and a KILL line was found
+		** to be active, close this connection. */
+		if (kflag == -1)
+		{
+			char buf[100];
+
+			dk_killed++;
+			sendto_flag(SCH_NOTICE,
+				"Kill line active for %s",
+				get_client_name(cptr, FALSE));
+				cptr->exitc = EXITC_KLINE;
+			if (!BadPtr(reason))
+				sprintf(buf, "Kill line active: %.80s",
+						reason);
+			(void)exit_client(cptr, cptr, &me, (reason) ?
+					  buf : "Kill line active");
+		}
+	}
+	dk_lastfd = i;	/* from which fd to start next time */
+	Debug((DEBUG_DEBUG, "DelayedKills killed %d and counting...",
+		dk_killed));
+
+	if (dk_lastfd < 0)
+	{
+		sendto_flag(SCH_NOTICE, "DelayedKills checked %d killed %d "
+			"in %d sec", dk_checked, dk_killed,
+			currenttime - dk_rehashed);
+		dk_rehashed = 0;
+		if (rehashed == 2)
+			return 1;
+		return 0;
+	}
+	return 1;
+}
 
 static	time_t	check_pings(currenttime)
 time_t	currenttime;
 {
-	static	time_t	lkill = 0;
 	Reg	aClient	*cptr;
-	Reg	int	kflag = 0;
-	int	ping = 0, i, rflag = 0;
+	int	ping = 0, i;
 	time_t	oldest = 0, timeout;
-	char	*reason;
 
 	for (i = highest_fd; i >= 0; i--)
 	    {
@@ -361,48 +598,23 @@
 		    IsHeld(cptr))
 			continue;
 
-		/*
-		 * K and R lines once per minute, max.  This is the max.
-		 * granularity in K-lines anyway (with time field).
-		 */
-		if (
-#if defined(TIMEDKLINES) || ( defined(R_LINES) && defined(R_LINES_OFTEN) )
-			(currenttime - lkill > TIMEDKLINES) || 
-#endif /* TIMEDKLINES */
-			rehashed)
-		    {
-			if (IsPerson(cptr))
-			    {
-				kflag = find_kill(cptr, rehashed, &reason);
-#ifdef R_LINES_OFTEN
-				rflag = find_restrict(cptr);
-#endif
-			    }
-			else
-			    {
-				kflag = rflag = 0;
-				reason = NULL;
-			    }
-		    }
 		ping = IsRegistered(cptr) ? get_client_ping(cptr) :
 					    ACCEPTTIMEOUT;
-		Debug((DEBUG_DEBUG, "c(%s) %d p %d k %d r %d a %d",
-			cptr->name, cptr->status, ping, kflag, rflag,
+		Debug((DEBUG_DEBUG, "c(%s) %d p %d a %d",
+			cptr->name, cptr->status, ping,
 			currenttime - cptr->lasttime));
 		/*
 		 * Ok, so goto's are ugly and can be avoided here but this code
 		 * is already indented enough so I think its justified. -avalon
 		 */
-		if (!kflag && !rflag && IsRegistered(cptr) &&
+		if (IsRegistered(cptr) &&
 		    (ping >= currenttime - cptr->lasttime))
 			goto ping_timeout;
 		/*
 		 * If the server hasnt talked to us in 2*ping seconds
 		 * and it has a ping time, then close its connection.
-		 * If the client is a user and a KILL line was found
-		 * to be active, close this connection too.
 		 */
-		if (kflag || rflag ||
+		if (
 		    ((currenttime - cptr->lasttime) >= (2 * ping) &&
 		     (cptr->flags & FLAGS_PINGSENT)) ||
 		    (!IsRegistered(cptr) &&
@@ -472,43 +684,8 @@
 				sendto_flag(SCH_NOTICE,
 					    "No response from %s closing link",
 					    get_client_name(cptr, FALSE));
-			/*
-			 * this is used for KILL lines with time restrictions
-			 * on them - send a messgae to the user being killed
-			 * first.
-			 */
-			if (kflag && IsPerson(cptr))
-			    {
-				char buf[100];
-
-				sendto_flag(SCH_NOTICE,
-					    "Kill line active for %s",
-					    get_client_name(cptr, FALSE));
-				cptr->exitc = EXITC_KLINE;
-				if (!BadPtr(reason))
-					sprintf(buf, "Kill line active: %.80s",
-						reason);
-				(void)exit_client(cptr, cptr, &me, (reason) ?
-						  buf : "Kill line active");
-			    }
-
-#if defined(R_LINES) && defined(R_LINES_OFTEN)
-			else if (IsPerson(cptr) && rflag)
-			    {
-				sendto_flag(SCH_NOTICE,
-					   "Restricting %s, closing link.",
-					   get_client_name(cptr,FALSE));
-				cptr->exitc = EXITC_RLINE;
-				(void)exit_client(cptr, cptr, &me,
-						  "Restricting");
-			    }
-#endif
-			else
-			    {
-				cptr->exitc = EXITC_PING;
-				(void)exit_client(cptr, cptr, &me,
-						  "Ping timeout");
-			    }
+			cptr->exitc = EXITC_PING;
+			(void)exit_client(cptr, cptr, &me, "Ping timeout");
 			continue;
 		    }
 		else if (IsRegistered(cptr) &&
@@ -531,8 +708,6 @@
 		if (timeout < oldest || !oldest)
 			oldest = timeout;
 	    }
-	if (currenttime - lkill > 60)
-		lkill = currenttime;
 	if (!oldest || oldest < currenttime)
 		oldest = currenttime + PINGFREQUENCY;
 	if (oldest < currenttime + 2)
@@ -686,7 +861,9 @@
 	bzero((char *)&me, sizeof(me));
 
 	version = make_version();	/* Generate readable version string */
-
+#ifdef SEND_ISUPPORT
+	isupport = make_isupport();	/* generate 005 numeric */
+#endif
 	/*
 	** All command line parameters have the syntax "-fstring"
 	** or "-f string" (e.g. the space is optional). String may
@@ -914,7 +1091,7 @@
 		if (!find_me())
 			exit(-1);
 	    }
-
+	initialconf = 0;
 	dbuf_init();
 	setup_me(&me);
 	check_class();
@@ -990,7 +1167,11 @@
 	** active C lines, this call to Tryconnections is
 	** made once only; it will return 0. - avalon
 	*/
+#ifdef OPER_SET
+	if (iconf.aconnect && nextconnect && timeofday >= nextconnect)
+#else
 	if (nextconnect && timeofday >= nextconnect)
+#endif	
 		nextconnect = try_connections(timeofday);
 	/*
 	** Every once in a while, hunt channel structures that
@@ -1069,8 +1250,24 @@
 	if (timeofday >= nextping)
 	    {
 		nextping = check_pings(timeofday);
-		rehashed = 0;
+		if (rehashed > 0)
+		{
+			rehashed = delayed_kills(timeofday);
+		}
 	    }
+
+#ifdef DELAY_CLOSE
+        if (nextdelayclose && (timeofday >= nextdelayclose))
+        {
+                nextdelayclose = delay_close(-1,NULL);
+        }
+#endif
+
+#if defined(OPER_KLINE)  || defined(LOCOP_KLINE) || \
+    defined(OPER_TKLINE) || defined(LOCOP_TKLINE)
+	if (kline_added)
+		check_klines();
+#endif
 
 	if (dorestart)
 		restart("Caught SIGINT");
diff -Nur irc2.10.3p7/ircd/ircd_ext.h irc2.10.3p7+hemp2+DK+B5/ircd/ircd_ext.h
--- irc2.10.3p7/ircd/ircd_ext.h	Fri Feb 12 05:00:47 1999
+++ irc2.10.3p7+hemp2+DK+B5/ircd/ircd_ext.h	Tue May 11 15:25:03 2004
@@ -27,6 +27,7 @@
 extern aClient me;
 extern aClient *client;
 extern istat_t istat;
+extern iconf_t iconf;
 extern char **myargv;
 extern int rehashed;
 extern int portnum;
@@ -41,6 +42,10 @@
 extern time_t nextping;
 extern time_t nextdnscheck;
 extern time_t nextexpire;
+extern int initialconf;
+#ifdef DELAY_CLOSE
+extern time_t nextdelayclose;
+#endif
 #endif /* IRCD_C */
 
 /*  External definitions for global functions.
@@ -59,4 +64,7 @@
 EXTERN void server_reboot();
 EXTERN void ircd_writetune __P((char *filename));
 EXTERN void ircd_readtune __P((char *filename));
+#ifdef DELAY_CLOSE
+EXTERN time_t delay_close __P((int fd,char *reason));
+#endif
 #undef EXTERN
diff -Nur irc2.10.3p7/ircd/list.c irc2.10.3p7+hemp2+DK+B5/ircd/list.c
--- irc2.10.3p7/ircd/list.c	Sun May  9 21:30:27 2004
+++ irc2.10.3p7+hemp2+DK+B5/ircd/list.c	Tue May 11 15:25:03 2004
@@ -147,6 +147,11 @@
 		istat.is_auth -= 1;
 		MyFree(cptr->auth);
 	}
+	if (cptr->hopcount == 0)
+	{
+		if (cptr->reason)
+			MyFree(cptr->reason);
+	}
 	MyFree((char *)cptr);
 }
 
@@ -190,6 +195,7 @@
 	if (!serv)
 	    {
 		serv = (aServer *)MyMalloc(sizeof(aServer));
+		memset((char *) serv, 0, sizeof(aServer));
 #ifdef	DEBUGMODE
 		servs.inuse++;
 #endif
@@ -201,8 +207,11 @@
 		serv->up = NULL;
 		serv->refcnt = 1;
 		serv->nexts = NULL;
+#ifdef	SERVER_MAP
+		serv->down = NULL;
+#endif
 		cptr->serv = serv;
-
+		bzero((void *)serv->usercnt,3*sizeof(int));
 		for (sp = svrtop; sp; spp = sp, sp = sp->nexts)
 			if (spp && ((spp->ltok) + 1 < sp->ltok))
 				break;
@@ -309,6 +318,10 @@
 				    cptr, cptr ? cptr->name : "<noname>", buf);
 #endif
 		    }
+		if (serv->up && serv->up != ME)
+		{
+			MyFree((char *)serv->up);
+		}
 		MyFree((char *)serv);
 	    }
 }
@@ -499,6 +512,18 @@
 	return lp;
 }
 
+invLink	*make_invlink()
+{
+	Reg	invLink	*lp;
+
+	lp = (invLink *)MyMalloc(sizeof(invLink));
+#ifdef	DEBUGMODE
+	links.inuse++;
+#endif
+	lp->flags = 0;
+	return lp;
+}
+
 void	free_link(lp)
 Reg	Link	*lp;
 {
@@ -508,6 +533,14 @@
 #endif
 }
 
+void	free_invlink(lp)
+Reg	invLink	*lp;
+{
+	MyFree((char *)lp);
+#ifdef	DEBUGMODE
+	links.inuse--;
+#endif
+}
 
 aClass	*make_class()
 {
@@ -549,6 +582,7 @@
 	aconf->status = CONF_ILLEGAL;
 	aconf->pref = -1;
 	aconf->hold = time(NULL);
+	aconf->source_ip = NULL;
 	Class(aconf) = NULL;
 	return (aconf);
 }
@@ -586,6 +620,8 @@
 		bzero(aconf->passwd, strlen(aconf->passwd));
 	if (aconf->ping)
 		MyFree((char *)aconf->ping);
+	if (aconf->source_ip)
+		MyFree(aconf->source_ip);
 	MyFree(aconf->passwd);
 	MyFree(aconf->name);
 	MyFree((char *)aconf);
diff -Nur irc2.10.3p7/ircd/list_ext.h irc2.10.3p7+hemp2+DK+B5/ircd/list_ext.h
--- irc2.10.3p7/ircd/list_ext.h	Fri Jul  2 18:49:37 1999
+++ irc2.10.3p7+hemp2+DK+B5/ircd/list_ext.h	Tue May 11 15:25:03 2004
@@ -55,7 +55,9 @@
 EXTERN Link *find_user_link __P((Reg Link *lp, Reg aClient *ptr));
 EXTERN Link *find_channel_link __P((Reg Link *lp, Reg aChannel *ptr));
 EXTERN Link *make_link();
+EXTERN invLink *make_invlink();
 EXTERN void free_link __P((Reg Link *lp));
+EXTERN void free_invlink __P((Reg invLink *lp));
 EXTERN aClass *make_class();
 EXTERN void free_class __P((Reg aClass *tmp));
 EXTERN aConfItem *make_conf();
diff -Nur irc2.10.3p7/ircd/res.c irc2.10.3p7+hemp2+DK+B5/ircd/res.c
--- irc2.10.3p7/ircd/res.c	Sun May  9 21:59:00 2004
+++ irc2.10.3p7+hemp2+DK+B5/ircd/res.c	Tue May 11 15:25:03 2004
@@ -512,7 +512,8 @@
 		(u_int)(cp[1]&0xf), (u_int)(cp[1]>>4),
 		(u_int)(cp[0]&0xf), (u_int)(cp[0]>>4),
 #ifdef SIXBONE_HACK
-		(cp[0] == 0x3f && cp[1] == 0xfe) ? "int" :
+		((cp[0] == 0x3f && cp[1] == 0xfe) ||
+		 (cp[0] == 0x20 && cp[1] == 0x02)) ? "int" :
 #endif
 		"arpa");
 	    }
diff -Nur irc2.10.3p7/ircd/s_auth.c irc2.10.3p7+hemp2+DK+B5/ircd/s_auth.c
--- irc2.10.3p7/ircd/s_auth.c	Sat Oct 11 22:04:29 2003
+++ irc2.10.3p7+hemp2+DK+B5/ircd/s_auth.c	Tue May 11 15:25:03 2004
@@ -291,15 +291,15 @@
 				}
 			    iauth_stats = (aExtData *)
 				    MyMalloc(sizeof(aExtData));
-			    iauth_stats->line = MyMalloc(60);
+			    iauth_stats->line = MyMalloc(80);
 			    sprintf(iauth_stats->line,
 				    "iauth modules statistics (%s)",
 				    myctime(timeofday));
 			    iauth_stats->next = (aExtData *)
 				    MyMalloc(sizeof(aExtData));
-			    iauth_stats->next->line = MyMalloc(60);
+			    iauth_stats->next->line = MyMalloc(80);
 			    sprintf(iauth_stats->next->line,
-				    "spawned: %d, current options: %X (%.11s)",
+				    "spawned: %d, current options: %X (%.20s)",
 				    iauth_spawn, iauth_options,
 				    (iauth_version) ? iauth_version : "???");
 			    iauth_stats->next->next = NULL;
@@ -459,6 +459,13 @@
 			    ** yet: we don't even know if this is a server
 			    ** or a user connection!
 			    */
+			    int i;
+			    char *reason;
+			    reason = strchr(start,'#');
+			    if (reason)
+			    {
+				    cptr->reason = mystrdup(reason+1);
+			    }
 			    if (start[0] == 'K')
 				    cptr->exitc = EXITC_AREF;
 			    else
diff -Nur irc2.10.3p7/ircd/s_bsd.c irc2.10.3p7+hemp2+DK+B5/ircd/s_bsd.c
--- irc2.10.3p7/ircd/s_bsd.c	Sun May  9 22:24:07 2004
+++ irc2.10.3p7+hemp2+DK+B5/ircd/s_bsd.c	Tue May 11 15:25:03 2004
@@ -341,7 +341,32 @@
 		free_client(cptr);
 	return 0;
 }
-
+#ifdef DELAY_ACCEPT
+void activate_delayed_listeners()
+{
+	aConfItem *aconf = NULL;
+	int pcnt = 0;
+	
+	for (aconf = conf; aconf; aconf = aconf->next)
+	{
+		if (!(aconf->status & CONF_LISTEN_PORT)
+				|| (conf->status & CONF_ILLEGAL))
+		{
+			continue;
+		}
+		if (!(aconf->status & CONF_ACTIVE))
+		{
+			aconf->status |= CONF_ACTIVE;
+			pcnt++;
+			add_listener(aconf);
+		}
+	}
+	if (pcnt)
+	{
+		sendto_flag(SCH_NOTICE,"Activating delayed listening ports");
+	}
+}
+#endif
 #ifdef	UNIXPORT
 /*
  * unixport
@@ -1360,8 +1385,21 @@
 		    }
 		del_fd(i, &fdall);
 		local[i] = NULL;
-		(void)close(i);
-
+#ifdef DELAY_CLOSE
+                if (cptr->user && (cptr->user->flags & FLAGS_BADBOY))
+                {
+                        delay_close(i,cptr->buffer);
+                        if (!nextdelayclose)
+                        {
+                                nextdelayclose = timeofday + DELAYCLOSETIME;
+                        }
+                }
+                else
+#endif
+		{
+			(void)close(i);
+		}
+		
 		cptr->fd = -2;
 		DBufClear(&cptr->sendQ);
 		DBufClear(&cptr->recvQ);
@@ -1620,15 +1658,23 @@
 				report_error("Failed in connecting to %s :%s",
 					     cptr);
 add_con_refuse:
+			(void)close(fd);
+add_con_delay_refuse:
 			ircstp->is_ref++;
 			acptr->fd = -2;
 			free_client(acptr);
-			(void)close(fd);
 			return NULL;
 		    }
 		/* don't want to add "Failed in connecting to" here.. */
 		if (aconf && IsIllegal(aconf))
 			goto add_con_refuse;
+#ifdef DELAY_ACCEPT
+		/* we are not accepting connections because of split */
+		if (aconf && (aconf->status & CONF_DELAY) && (iconf.caccept < 2))
+		{
+			goto add_con_refuse;
+		}
+#endif
 		/* Copy ascii address to 'sockhost' just in case. Then we
 		 * have something valid to put into error messages...
 		 */
@@ -1670,10 +1716,15 @@
 			    (acptr->hostp) ? acptr->hostp->h_name :
 			    acptr->sockhost);
 		del_queries((char *)acptr);
+#ifdef DELAY_CLOSE
+		delay_close(fd,"ERROR :Too rapid connections from your host");
+		goto add_con_delay_refuse;
+#else
 		(void)send(fd,
 			   "ERROR :Too rapid connections from your host\r\n",
 			   46, 0);
 		goto add_con_refuse;
+#endif
 	    }
 #endif
 	acptr->fd = fd;
@@ -2580,6 +2631,8 @@
 int	*lenp;
 {
 	static	struct	SOCKADDR_IN	server;
+	struct SOCKADDR_IN outip;
+	
 	Reg	struct	hostent	*hp;
 	aClient	*acptr;
 	int	i;
@@ -2599,7 +2652,25 @@
 	bzero((char *)&server, sizeof(server));
 	server.SIN_FAMILY = AFINET;
 	get_sockhost(cptr, aconf->host);
-
+	
+	if (aconf->source_ip)
+	{
+		memset(&outip, 0, sizeof(outip));
+		outip.SIN_PORT = 0;
+		outip.SIN_FAMILY = AFINET;
+#ifdef INET6
+		if (!inetpton(AF_INET6, aconf->source_ip, outip.sin6_addr.s6_addr))
+#else
+		if ((outip.sin_addr.s_addr = inetaddr(aconf->source_ip)) == -1)
+#endif
+		{
+			memcpy(&mysk, &outip, sizeof(mysk));		
+		}
+	}
+	else
+	{
+		memcpy(&outip, &mysk, sizeof(mysk));		
+	}
 	if (cptr->fd == -1)
 	    {
 		report_error("opening stream socket to server %s:%s", cptr);
@@ -2611,7 +2682,7 @@
 	** with more than one IP#.
 	** With VIFs, M:line defines outgoing IP# and initialises mysk.
 	*/
-	if (bind(cptr->fd, (SAP)&mysk, sizeof(mysk)) == -1)
+	if (bind(cptr->fd, (SAP)&outip, sizeof(outip)) == -1)
 	    {
 		report_error("error binding to local port for %s:%s", cptr);
 		return NULL;
diff -Nur irc2.10.3p7/ircd/s_bsd_ext.h irc2.10.3p7+hemp2+DK+B5/ircd/s_bsd_ext.h
--- irc2.10.3p7/ircd/s_bsd_ext.h	Fri Feb  5 00:50:21 1999
+++ irc2.10.3p7+hemp2+DK+B5/ircd/s_bsd_ext.h	Tue May 11 15:25:03 2004
@@ -61,6 +61,9 @@
 EXTERN void get_my_name __P((aClient *cptr, char *name, int len));
 EXTERN int setup_ping __P((aConfItem *aconf));
 EXTERN void send_ping __P((aConfItem *aconf));
+#ifdef DELAY_ACCEPT
+EXTERN void activate_delayed_listeners();
+#endif
 #if defined(ENABLE_SUMMON) || defined(ENABLE_USERS)
 EXTERN int utmp_open();
 EXTERN int utmp_read __P((int fd, char *name, char *line, char *host,
diff -Nur irc2.10.3p7/ircd/s_conf.c irc2.10.3p7+hemp2+DK+B5/ircd/s_conf.c
--- irc2.10.3p7/ircd/s_conf.c	Sun May  9 21:32:40 2004
+++ irc2.10.3p7+hemp2+DK+B5/ircd/s_conf.c	Tue May 11 15:25:04 2004
@@ -178,8 +178,9 @@
 
 	for (aconf = conf; aconf; aconf = aconf->next)
 	    {
-		if ((aconf->status != CONF_CLIENT) &&
-		    (aconf->status != CONF_RCLIENT))
+		if (IsIllegal(aconf))
+			continue;
+		if (!(aconf->status & (CONF_CLIENT | CONF_RCLIENT)))
 			continue;
 		if (aconf->port && aconf->port != cptr->acpt->port)
 			continue;
@@ -230,6 +231,16 @@
 attach_iline:
 		if (aconf->status & CONF_RCLIENT)
 			SetRestricted(cptr);
+#ifdef ILINE_FLAGS
+		if (aconf->status & CONF_EXEMPT)
+		{
+			cptr->user->flags |= FLAGS_EXEMPT;
+		}
+		if (!hp && (aconf->status & CONF_RNODNS))
+		{
+			SetRestricted(cptr);
+		}
+#endif
 		get_sockhost(cptr, uhost);
 		if ((i = attach_conf(cptr, aconf)) < -1)
 			find_bounce(cptr, ConfClass(aconf), -1);
@@ -302,6 +313,7 @@
 						*aconf2 = aconf3->next;
 						aconf3->next = NULL;
 						free_conf(aconf);
+						
 					}
 					else
 					{
@@ -346,7 +358,7 @@
 aClient *cptr;
 {
 	Reg	Link	*lp;
-
+	
 	if (is_attached(aconf, cptr))
 		return 1;
 	if (IsIllegal(aconf))
@@ -359,9 +371,10 @@
 			return -3;    /* Use this for printing error message */
 	    }
 	if ((aconf->status & (CONF_CLIENT | CONF_RCLIENT)))
-	    {
+	{
 		int	hcnt = 0, ucnt = 0;
-
+		int ghcnt = 0, gucnt = 0;
+		Reg anUser *user = NULL;
 		/* check on local/global limits per host and per user@host */
 
 		/*
@@ -369,7 +382,64 @@
 		**	host check is done on the IP address.
 		**	user check is done on the IDENT reply.
 		*/
-		if (ConfMaxHLocal(aconf) > 0 || ConfMaxUHLocal(aconf) > 0) {
+		if (ConfMaxHLocal(aconf) > 0 || ConfMaxUHLocal(aconf) > 0 ||
+		    ConfMaxHGlobal(aconf) > 0 || ConfMaxUHGlobal(aconf) > 0 )
+		{
+			for ((user = hash_find_hostname(cptr->sockhost,NULL));user;user=user->hnext)
+			{
+				if (!mycmp(cptr->sockhost,user->host))
+				{
+					ghcnt++;
+					if (MyConnect(user->bcptr))
+					{
+						hcnt++;
+						if (!mycmp(user->bcptr->auth,cptr->auth))
+						{
+							ucnt++;
+							gucnt++;
+						}
+					}
+					else
+					{
+						if (!mycmp(user->username,cptr->user->username))
+						{
+							gucnt++;
+						}
+					}
+					if (ConfMaxUHLocal(aconf) > 0 &&
+					    ucnt >= ConfMaxUHLocal(aconf))
+					{
+						return -5;
+					}
+	
+					if (ConfMaxHLocal(aconf) > 0 &&
+					    hcnt >= ConfMaxHLocal(aconf))
+					{
+						return -4;
+					}
+					if (ConfMaxUHGlobal(aconf) > 0 &&
+					    gucnt >= ConfMaxUHGlobal(aconf))
+					{
+						return -7;
+					}
+					if (ConfMaxHGlobal(aconf) > 0 &&
+					     ghcnt >= ConfMaxHGlobal(aconf))
+					{
+						return -6;
+					}
+				}
+			}
+		}
+#ifndef NO_EXTENSIVE_LOCAL_LIMIT_CHECK
+		/* Part of old cpu intensive code which is checking user's 
+		 * ip against all all other local clients. Needed only when 
+		 * client changes it's hostname between connects.
+		 * Won't be needed on pure 2.11 net  -- jv
+		 */
+		
+		/* now, check local IP too */
+		if (ConfMaxHLocal(aconf) > 0 || ConfMaxUHLocal(aconf) > 0) 
+		{
 			Reg     aClient *acptr;
 			Reg     int     i;
 
@@ -391,38 +461,8 @@
 			    ucnt >= ConfMaxUHLocal(aconf))
 				return -5;      /* for error message */
 		}
-		/*
-		** Global limits
-		**	host check is done on the hostname (IP if unresolved)
-		**	user check is done on username
-		*/
-		if (ConfMaxHGlobal(aconf) > 0 || ConfMaxUHGlobal(aconf) > 0)
-		    {
-			Reg     aClient *acptr;
-			Reg     int     ghcnt = hcnt, gucnt = ucnt;
-
-			for (acptr = client; acptr; acptr = acptr->next)
-			    {
-				if (!IsPerson(acptr))
-					continue;
-				if (MyConnect(acptr) &&
-				    (ConfMaxHLocal(aconf) > 0 ||
-				     ConfMaxUHLocal(aconf) > 0))
-					continue;
-				if (!strcmp(cptr->sockhost, acptr->user->host))
-				    {
-					if (ConfMaxHGlobal(aconf) > 0 &&
-					    ++ghcnt >= ConfMaxHGlobal(aconf))
-						return -6;
-					if (ConfMaxUHGlobal(aconf) > 0 &&
-					    !strcmp(cptr->user->username,
-						    acptr->user->username) &&
-					    (++gucnt >=ConfMaxUHGlobal(aconf)))
-						return -7;
-				    }
-			    }
-		    }
-	    }
+#endif
+	}
 
 	lp = make_link();
 	istat.is_conflink++;
@@ -730,12 +770,20 @@
 		if (!BadPtr(bconf->host) && mycmp(bconf->host, aconf->host))
 			continue;
 
+#ifdef DELAY_ACCEPT
+                /* ignore ->passwd field */
+                if (!(aconf->status & CONF_LISTEN_PORT))
+                {
+#endif
 		if ((BadPtr(bconf->passwd) && !BadPtr(aconf->passwd)) ||
 		    (BadPtr(aconf->passwd) && !BadPtr(bconf->passwd)))
 			continue;
 		if (!BadPtr(bconf->passwd) &&
 		    mycmp(bconf->passwd, aconf->passwd))
 			continue;
+#ifdef DELAY_ACCEPT
+                }
+#endif
 
 		if ((BadPtr(bconf->name) && !BadPtr(aconf->name)) ||
 		    (BadPtr(aconf->name) && !BadPtr(bconf->name)))
@@ -787,18 +835,6 @@
 			 * this....-avalon
 			 */
 			acptr->hostp = NULL;
-#if defined(R_LINES) && ( defined(R_LINES_REHASH) && !defined(R_LINES_OFTEN) )
-			if (find_restrict(acptr))
-			    {
-				sendto_flag(SCH_NOTICE,
-					    "Restricting %s, closing lp",
-					    get_client_name(acptr,FALSE));
-				acptr->exitc = EXITC_RLINE;
-				if (exit_client(cptr,acptr,&me,"R-lined") ==
-				    FLUSH_BUFFER)
-					ret = FLUSH_BUFFER;
-			    }
-#endif
 		    }
 
 	while ((tmp2 = *tmp))
@@ -851,16 +887,18 @@
 		if (!(tmp2->status & CONF_ILLEGAL) || tmp2->clients)
 			tmp = &tmp2->next;
 		else
-		{
+		    {
 			*tmp = tmp2->next;
 			tmp2->next = NULL;
 			free_conf(tmp2);
-		}
-	
+		    }
 #ifdef CACHED_MOTD
 	read_motd(IRCDMOTD_PATH);
 #endif
-	rehashed = 1;
+	if (rehashed > 0)
+		rehashed = 2;	/* queue another rehash later */
+	else
+		rehashed = 1;
 	return ret;
 }
 
@@ -1134,12 +1172,6 @@
 			case 'q': /* network. USE WITH CAUTION! */
 				aconf->status = CONF_QUARANTINED_SERVER;
 				break;
-#ifdef R_LINES
-			case 'R': /* extended K line */
-			case 'r': /* Offers more options of how to restrict */
-				aconf->status = CONF_RESTRICT;
-				break;
-#endif
 			case 'S': /* Service. Same semantics as   */
 			case 's': /* CONF_OPERATOR                */
 				aconf->status = CONF_SERVICE;
@@ -1175,9 +1207,6 @@
 				|CONF_CLIENT|CONF_RCLIENT|CONF_KILL
 				|CONF_OTHERKILL|CONF_NOCONNECT_SERVER
 				|CONF_OPERATOR|CONF_LOCOP|CONF_LISTEN_PORT
-# ifdef R_LINES
-				|CONF_RESTRICT
-# endif
 				|CONF_SERVICE))
 				aconf->host = ipv6_convert(tmp);
 			else
@@ -1190,7 +1219,27 @@
 			DupString(aconf->passwd, tmp);
 			if ((tmp = getfield(NULL)) == NULL)
 				break;
-			DupString(aconf->name, tmp);
+#ifdef ILINE_FLAGS
+			if ((aconf->status & (CONF_CLIENT | CONF_RCLIENT)))
+			{
+				int shiftname = 0;
+				if (*tmp == '<' || (*tmp && *(tmp + 1) == '<'))
+				{
+					shiftname++;
+					aconf->status |= CONF_EXEMPT;
+				}
+				if (*tmp == '+' || (*tmp && *(tmp + 1) == '+'))
+				{
+					shiftname++;
+					aconf->status |= CONF_RNODNS;
+				}
+				DupString(aconf->name,tmp+shiftname);
+			}
+			else
+#endif
+			{
+				DupString(aconf->name, tmp);
+			}
 			if ((tmp = getfield(NULL)) == NULL)
 				break;
 			aconf->port = 0;
@@ -1249,26 +1298,109 @@
 			if (MaxLinks(Class(aconf)) < 0)
 				Class(aconf) = find_class(0);
 		    }
+#ifdef DELAY_ACCEPT
+                if (aconf->status & (CONF_LISTEN_PORT))
+                {
+                        if (aconf->passwd && strchr(aconf->passwd,'D'))
+                        {
+                                aconf->status |= CONF_DELAY;
+                        }
+                        if (aconf->passwd && strchr(aconf->passwd,'S'))
+                        {
+                                aconf->status |= CONF_SERVERONLY;
+                                /* feature, remove delay if serveronly */
+                                aconf->status &= ~CONF_DELAY;
+                        }
+                }
+#endif
+
 		if (aconf->status & (CONF_LISTEN_PORT|CONF_CLIENT|CONF_RCLIENT))
 		    {
-			aConfItem *bconf;
+			aConfItem *bconf = NULL;
 
 			if ((bconf = find_conf_entry(aconf, aconf->status)))
 			    {
 				delist_conf(bconf);
 				bconf->status &= ~CONF_ILLEGAL;
-				if (aconf->status == CONF_CLIENT)
+				if (aconf->status & (CONF_CLIENT | CONF_RCLIENT))
 				    {
+#ifdef ILINE_FLAGS
+					    if (aconf->status & CONF_EXEMPT)
+					    {
+						    bconf->status |= CONF_EXEMPT;
+					    }
+					    else
+					    {
+						    bconf->status &= ~CONF_EXEMPT;
+					    }
+					    if (aconf->status & CONF_RNODNS)
+					    {
+						    bconf->status |= CONF_RNODNS;
+					    }
+					    else
+					    {
+						    bconf->status &= ~CONF_RNODNS;
+					    }
+#endif
 					bconf->class->links -= bconf->clients;
 					bconf->class = aconf->class;
 					bconf->class->links += bconf->clients;
 				    }
+#ifdef DELAY_ACCEPT
+                                if (aconf->status & CONF_LISTEN_PORT)
+                                {
+                                        if (aconf->status & CONF_DELAY)
+                                        {
+                                                bconf->status &= ~CONF_SERVERONLY;
+                                                bconf->status |= CONF_DELAY;
+                                        }
+                                        else
+                                        {
+                                                bconf->status &= ~CONF_DELAY;
+                                        }
+                                        if (aconf->status & CONF_SERVERONLY)
+                                        {
+                                                bconf->status &= ~CONF_DELAY;
+                                                bconf->status |= CONF_SERVERONLY;
+                                        }
+                                        else
+                                        {
+                                                bconf->status &= ~CONF_SERVERONLY;
+                                        }
+                                }
+#endif
+
 				free_conf(aconf);
 				aconf = bconf;
 			    }
-			else if (aconf->host &&
-				 aconf->status == CONF_LISTEN_PORT)
-				(void)add_listener(aconf);
+			
+			if (aconf->host &&
+				 aconf->status & CONF_LISTEN_PORT)
+			{
+#ifdef DELAY_ACCEPT
+                                if (aconf->status & CONF_DELAY)
+                                {
+                                        /* we have Delayed ports and we
+                                         * are starting, don't bind them.
+                                         */
+                                        if (initialconf)
+                                                iconf.caccept = 1;
+                                }
+                                if (!((iconf.caccept < 2) &&
+                                    (aconf->status & CONF_DELAY)))
+                                {
+                                        aconf->status |= CONF_ACTIVE;
+                                }
+
+                                if (aconf->status & CONF_ACTIVE)
+#endif
+				{
+					if (!bconf)
+					{
+						add_listener(aconf);
+					}
+				}
+			}
 		    }
 		if (aconf->status & CONF_SERVICE)
 			aconf->port &= SERVICE_MASK_ALL;
@@ -1313,6 +1445,10 @@
 				MyFree(tmp2);
 				tmp2 = NULL;
 			    }
+			if (tmp3)
+			{
+				DupString(aconf->source_ip, tmp3);
+			}
 				
 		    }
 		/*
@@ -1435,9 +1571,8 @@
 	return -1;
 }
 
-int	find_kill(cptr, doall, comment)
+int	find_kill(cptr, comment)
 aClient	*cptr;
-int	doall;
 char	**comment;
 {
 	static char	reply[256];
@@ -1477,8 +1612,6 @@
 
 	for (tmp = kconf; tmp; tmp = tmp->next)
 	    {
-		if (!doall && (BadPtr(tmp->passwd) || !isdigit(*tmp->passwd)))
-			continue;
 		if (!(tmp->status & (CONF_KILL | CONF_OTHERKILL)))
 			continue; /* should never happen with kconf */
 		if (!tmp->host || !tmp->name)
@@ -1518,19 +1651,11 @@
 		if ((!check || match(tmp->name, check) == 0) &&
 		    (!tmp->port || (tmp->port == cptr->acpt->port)))   
 		    {
-			now = 0;
-			if (!BadPtr(tmp->passwd) && isdigit(*tmp->passwd) &&
-			    !(now = check_time_interval(tmp->passwd, reply)))
-				continue;
-			if (now == ERR_YOUWILLBEBANNED)
-				tmp = NULL;
 			break;
 		    }
 	    }
 
-	if (*reply)
-		sendto_one(cptr, reply, ME, now, cptr->name);
-	else if (tmp)
+	if (tmp)
 		sendto_one(cptr, ":%s %d %s :%s%s", ME,
 			   ERR_YOUREBANNEDCREEP, cptr->name,
 			   BadPtr(tmp->passwd) ?
@@ -1586,183 +1711,6 @@
 		    (strpbrk(key + l, tmp->passwd + l)))
 			break;
  	return (tmp ? -1 : 0);
-}
-
-#ifdef R_LINES
-/* find_restrict works against host/name and calls an outside program 
- * to determine whether a client is allowed to connect.  This allows 
- * more freedom to determine who is legal and who isn't, for example
- * machine load considerations.  The outside program is expected to 
- * return a reply line where the first word is either 'Y' or 'N' meaning 
- * "Yes Let them in" or "No don't let them in."  If the first word 
- * begins with neither 'Y' or 'N' the default is to let the person on.
- * It returns a value of 0 if the user is to be let through -Hoppie
- */
-int	find_restrict(cptr)
-aClient	*cptr;
-{
-	aConfItem *tmp;
-	char	reply[80], temprpl[80];
-	char	*rplhold = reply, *host, *name, *s;
-	char	rplchar = 'Y';
-	int	pi[2], rc = 0, n;
-
-	if (!cptr->user)
-		return 0;
-	name = cptr->user->username;
-	host = cptr->sockhost;
-	Debug((DEBUG_INFO, "R-line check for %s[%s]", name, host));
-
-	for (tmp = conf; tmp; tmp = tmp->next)
-	    {
-		if (tmp->status != CONF_RESTRICT ||
-		    (tmp->host && host && match(tmp->host, host)) ||
-		    (tmp->name && name && match(tmp->name, name)))
-			continue;
-
-		if (BadPtr(tmp->passwd))
-			continue;
-
-		if (pipe(pi) == -1)
-		    {
-			report_error("Error creating pipe for R-line %s:%s",
-				     &me);
-			return 0;
-		    }
-		switch (rc = vfork())
-		{
-		case -1 :
-			report_error("Error forking for R-line %s:%s", &me);
-			return 0;
-		case 0 :
-		    {
-			Reg	int	i;
-
-			(void)close(pi[0]);
-			for (i = 2; i < MAXCONNECTIONS; i++)
-				if (i != pi[1])
-					(void)close(i);
-			if (pi[1] != 2)
-				(void)dup2(pi[1], 2);
-			(void)dup2(2, 1);
-			if (pi[1] != 2 && pi[1] != 1)
-				(void)close(pi[1]);
-			(void)execlp(tmp->passwd, tmp->passwd, name, host,
-				     cptr->username, 0);
-			_exit(-1);
-		    }
-		default :
-			(void)close(pi[1]);
-			break;
-		}
-		*reply = '\0';
-		(void)dgets(-1, NULL, 0); /* make sure buffer marked empty */
-		while ((n = dgets(pi[0], temprpl, sizeof(temprpl)-1)) > 0)
-		    {
-			temprpl[n] = '\0';
-			if ((s = (char *)index(temprpl, '\n')))
-			      *s = '\0';
-			if (strlen(temprpl) + strlen(reply) < sizeof(reply)-2)
-				SPRINTF(rplhold,"%s %s", rplhold, temprpl);
-			else
-			    {
-				sendto_flag(SCH_ERROR,
-					    "R-line %s/%s: reply too long!",
-					    name, host);
-				break;
-			    }
-		    }
-		(void)dgets(-1, NULL, 0); /* make sure buffer marked empty */
-		(void)close(pi[0]);
-		(void)kill(rc, SIGKILL); /* cleanup time */
-#if !defined(USE_IAUTH)
-		(void)wait(0);
-#endif
-
-		rc = 0;
-		while (*rplhold == ' ')
-			rplhold++;
-		rplchar = *rplhold; /* Pull out the yes or no */
-		while (*rplhold != ' ')
-			rplhold++;
-		while (*rplhold == ' ')
-			rplhold++;
-		(void)strcpy(reply,rplhold);
-		rplhold = reply;
-
-		if ((rc = (rplchar == 'n' || rplchar == 'N')))
-			break;
-	    }
-	if (rc)
-	    {
-		sendto_one(cptr, ":%s %d %s :Restriction: %s",
-			   ME, ERR_YOUREBANNEDCREEP, cptr->name, reply);
-		return -1;
-	    }
-	return 0;
-}
-#endif
-
-
-/*
-** check against a set of time intervals
-*/
-
-static	int	check_time_interval(interval, reply)
-char	*interval, *reply;
-{
-	struct tm *tptr;
- 	char	*p;
- 	int	perm_min_hours, perm_min_minutes,
- 		perm_max_hours, perm_max_minutes;
- 	int	now, perm_min, perm_max;
-
-	tptr = localtime(&timeofday);
- 	now = tptr->tm_hour * 60 + tptr->tm_min;
-
-	while (interval)
-	    {
-		p = (char *)index(interval, ',');
-		if (p)
-			*p = '\0';
-		if (sscanf(interval, "%2d%2d-%2d%2d",
-			   &perm_min_hours, &perm_min_minutes,
-			   &perm_max_hours, &perm_max_minutes) != 4)
-		    {
-			if (p)
-				*p = ',';
-			return(0);
-		    }
-		if (p)
-			*(p++) = ',';
-		perm_min = 60 * perm_min_hours + perm_min_minutes;
-		perm_max = 60 * perm_max_hours + perm_max_minutes;
-           	/*
-           	** The following check allows intervals over midnight ...
-           	*/
-		if ((perm_min < perm_max)
-		    ? (perm_min <= now && now <= perm_max)
-		    : (perm_min <= now || now <= perm_max))
-		    {
-			(void)sprintf(reply,
-				":%%s %%d %%s :%s %d:%02d to %d:%02d.",
-				"You are not allowed to connect from",
-				perm_min_hours, perm_min_minutes,
-				perm_max_hours, perm_max_minutes);
-			return(ERR_YOUREBANNEDCREEP);
-		    }
-		if ((perm_min < perm_max)
-		    ? (perm_min <= now + 5 && now + 5 <= perm_max)
-		    : (perm_min <= now + 5 || now + 5 <= perm_max))
-		    {
-			(void)sprintf(reply, ":%%s %%d %%s :%d minute%s%s",
-				perm_min-now,(perm_min-now)>1?"s ":" ",
-				"and you will be denied for further access");
-			return(ERR_YOUWILLBEBANNED);
-		    }
-		interval = p;
-	    }
-	return(0);
 }
 
 /*
diff -Nur irc2.10.3p7/ircd/s_conf_ext.h irc2.10.3p7+hemp2+DK+B5/ircd/s_conf_ext.h
--- irc2.10.3p7/ircd/s_conf_ext.h	Fri Feb  9 12:35:34 2001
+++ irc2.10.3p7+hemp2+DK+B5/ircd/s_conf_ext.h	Tue May 11 15:25:04 2004
@@ -58,7 +58,7 @@
 EXTERN int rehash __P((aClient *cptr, aClient *sptr, int sig));
 EXTERN int openconf();
 EXTERN int initconf __P((int opt));
-EXTERN int find_kill __P((aClient *cptr, int doall, char **comment));
+EXTERN int find_kill __P((aClient *cptr, char **comment));
 EXTERN int find_two_masks __P((char *name, char *host, int stat));
 EXTERN int find_conf_flags __P((char *name, char *key, int stat));
 EXTERN int find_restrict __P((aClient *cptr));
diff -Nur irc2.10.3p7/ircd/s_debug.c irc2.10.3p7+hemp2+DK+B5/ircd/s_debug.c
--- irc2.10.3p7/ircd/s_debug.c	Fri Oct 19 20:44:27 2001
+++ irc2.10.3p7+hemp2+DK+B5/ircd/s_debug.c	Tue May 11 15:25:04 2004
@@ -36,6 +36,9 @@
 #ifndef	NO_IDENT
 'a',
 #endif
+#ifdef MIN_CHANOP_SERV
+'B',
+#endif
 #ifdef	CHROOTDIR
 'c',
 #endif
@@ -88,6 +91,9 @@
 'K',
 # endif
 #endif
+#ifdef FAILED_OPERLOG
+'l',
+#endif
 #ifdef	LEAST_IDLE
 'L',
 #endif
@@ -123,6 +129,9 @@
 #endif
 #ifdef	OPER_REMOTE
 't',
+#ifdef TOPICWHOTIME
+'T',
+#endif
 #endif
 #ifndef	NO_PREFIX
 'u',
@@ -150,6 +159,113 @@
 #endif
 '\0'};
 
+/*
+ * Option string.  Must be before #ifdef DEBUGMODE.
+ * spaces are not allowed.
+ */
+char	cropts[] = {
+#ifdef EXTRA_STATISTICS
+'E',
+#endif
+#ifdef FAILED_OPERLOG
+'F',
+#endif
+#ifdef LOG_IP
+'I',
+#endif
+#ifdef OPER_KLINE
+'K',
+#endif
+#ifdef LOCOP_KLINE
+'k',
+#endif
+#ifdef OPER_TKLINE
+'T',
+#endif
+#ifdef LOCOP_TKLINE
+'t',
+#endif
+#ifdef RESTRICT_USERNAMES
+'u',
+#endif
+'\0'};
+
+char   flopts[] = {
+#ifdef CLIENTS_CHANNEL
+'C',
+#endif
+'\0'};
+
+char	scopts[] = {
+#ifdef EXTRA_STATISTICS
+'C',
+#endif
+#ifdef FAILED_OPERLOG
+'f',
+#endif
+#ifdef OPER_KLINE
+# ifdef LOCOP_KLINE
+'K',
+# else
+'k',
+# endif
+#endif
+#ifdef LOCAL_REJECTIONS_ONLY
+'r',
+#endif
+#ifdef TOPICWHOTIME
+'t',
+#endif
+'\0' };
+
+char jvopts[] = {
+#ifdef NO_EXTENSIVE_LOCAL_LIMIT_CHECK
+'L',
+#endif
+#ifdef STATS_F
+'F',
+#endif
+#ifdef WHOIS_SIGNON_TIME
+'s',
+#endif
+#ifdef NO_OPER_TRYAGAIN
+'N',
+#endif
+#ifdef DELAY_ACCEPT
+'d',
+#endif
+#ifdef DELAY_CLOSE
+'D',
+#endif
+#ifdef SEND_ISUPPORT
+'5',
+#endif
+#ifdef STATS_QMARK
+'?',
+#endif
+#ifdef SERVER_MAP
+'M',
+#endif
+#ifdef LIST_ALIS_NOTE
+'A',
+#endif
+#ifdef SPLIT_HANDLE
+'S',
+#endif
+#ifdef OPER_SET
+'o',
+#endif
+#ifdef ILINE_FLAGS
+'I',
+#endif
+#ifdef IAUTH_VERBOSE_REJECTS
+'v',
+#endif
+#ifdef LOG_IRCNAME
+'i',
+#endif
+'\0'
+};
 #ifdef DEBUGMODE
 static	char	debugbuf[2*READBUF_SIZE]; /* needs to be big.. */
 
@@ -358,6 +474,26 @@
 		   -1, -1
 #endif
 		   );
+	sendto_one(cptr, ":%s %d %s :Sc:%s", ME, RPL_STATSDEFINE, nick,
+					scopts);
+#ifdef  EXTRA_STATISTICS
+	sendto_one(cptr, ":%s %d %s :Cr:%s %d/%d/%d/%d/%d/%d Fl:%s",
+		   ME, RPL_STATSDEFINE, nick, cropts,
+		   istat.is_m_users, istat.is_m_myclnt,
+		   istat.is_m_service, istat.is_m_myservice,
+		   istat.is_m_serv, istat.is_m_myserv,flopts);
+#else
+	sendto_one(cptr, ":%s %d %s :Cr:%s Fl:%s",
+		   ME, RPL_STATSDEFINE, nick, cropts,flopts);
+#endif
+	sendto_one(cptr, ":%s %d %s :jv:%s Split Servers: %d (%d) Users: %d",
+		   ME, RPL_STATSDEFINE,nick,jvopts,
+#ifdef SPLIT_HANDLE
+	SPLIT_SERV,istat.is_eobservers,SPLIT_USERS
+#else
+	-1,-1,-1
+#endif
+		);
 }
 
 void	count_memory(cptr, nick, debug)
diff -Nur irc2.10.3p7/ircd/s_err.c irc2.10.3p7+hemp2+DK+B5/ircd/s_err.c
--- irc2.10.3p7/ircd/s_err.c	Sat Oct 11 00:30:37 2003
+++ irc2.10.3p7+hemp2+DK+B5/ircd/s_err.c	Tue May 11 15:25:04 2004
@@ -41,7 +41,31 @@
 /* 002 */	{ RPL_YOURHOST, ":Your host is %s, running version %s" },
 /* 003 */	{ RPL_CREATED, ":This server was created %s" },
 /* 004 */	{ RPL_MYINFO, "%s %s aoOirw abeiIklmnoOpqrstv" },
+#ifdef SEND_ISUPPORT
+/* 005 */	//{ RPL_ISUPPORT, "MAP PREFIX=(ov)@+ MODES=3 CHANTYPES=#&!+ MAXCHANNELS=%d NICKLEN=%d TOPICLEN=%d KICKLEN=%d NETWORK=%s CHANMODES=beI,k,l,imnpstaqr :are supported by this server" },
+/* 005 */	{ RPL_ISUPPORT, "%s :are supported by this server" },
+#else
 /* 005 */	{ RPL_BOUNCE, ":Try server %s, port %d" },
+#endif
+/* 006 */	{ 0, (char *)NULL },
+/* 007 */	{ 0, (char *)NULL },
+/* 008 */	{ 0, (char *)NULL },
+/* 009 */	{ 0, (char *)NULL },
+#ifdef SEND_ISUPPORT
+/* 010 */	{ RPL_BOUNCE, "%s %d :Please use this Server/Port instead" },
+#else
+/* 010 */	{ 0, (char *)NULL },
+#endif
+/* 011 */	{ 0, (char *)NULL },
+/* 012 */	{ 0, (char *)NULL },
+/* 013 */	{ 0, (char *)NULL },
+#ifdef SERVER_MAP
+/* 014 */       { 0, (char *)NULL },
+/* 015 */	{ RPL_MAP, ":%s" },
+/* 016 */   	{ 0, (char *)NULL },
+/* 017 */   	{ RPL_MAPEND, ":End of /MAP" },
+/* 018 */   	{ RPL_MAPSTART, ":%-53s | %s" },
+#endif
 		{ 0, (char *)NULL }
 };
 
@@ -62,7 +86,7 @@
 /* 413 */	{ ERR_NOTOPLEVEL, "%s :No toplevel domain specified" },
 /* 414 */	{ ERR_WILDTOPLEVEL, "%s :Wildcard in toplevel Domain" },
 /* 415 */	{ ERR_BADMASK, "%s :Bad Server/host mask" },
-/* 416 */	{ ERR_TOOMANYMATCHES, "%s :Output too long (try locally)" },
+/* 416 */	{ ERR_TOOMANYMATCHES, "%s :Output too long." },
 		{ 0, (char *)NULL },
 		{ 0, (char *)NULL },
 		{ 0, (char *)NULL },
@@ -158,7 +182,11 @@
 		{ 0, (char *)NULL },
 		{ 0, (char *)NULL },
 		{ 0, (char *)NULL },
+#ifdef NOSTATSK
+/* 499 */	{ ERR_STATSKLINE, ":" NOSTATSK },
+#else
 		{ 0, (char *)NULL },
+#endif
                 { 0, (char *)NULL },
 /* 501 */	{ ERR_UMODEUNKNOWNFLAG, ":Unknown MODE flag" },
 /* 502 */	{ ERR_USERSDONTMATCH, ":Can't change mode for other users" },
@@ -183,7 +211,11 @@
 /* 314 */	{ RPL_WHOWASUSER, "%s %s %s * :%s" },
 /* 315 */	{ RPL_ENDOFWHO, "%s :End of WHO list." },
 /* 316 */	{ RPL_WHOISCHANOP, (char *)NULL },
+#ifdef WHOIS_SIGNON_TIME
+/* 317 */	{ RPL_WHOISIDLE, "%s %ld %ld :seconds idle, signon time" },
+#else
 /* 317 */	{ RPL_WHOISIDLE, "%s %ld :seconds idle" },
+#endif
 /* 318 */	{ RPL_ENDOFWHOIS, "%s :End of WHOIS list." },
 /* 319 */	{ RPL_WHOISCHANNELS, "%s :%s" },
 		{ 0, (char *)NULL },
@@ -199,7 +231,11 @@
 		{ 0, (char *)NULL },
 /* 331 */	{ RPL_NOTOPIC, "%s :No topic is set." },
 /* 332 */	{ RPL_TOPIC, "%s :%s" },
+#ifdef TOPICWHOTIME
+/* 333 */	{ RPL_TOPICWHOTIME, "%s %s %lu" },
+#else
 		{ 0, (char *)NULL },
+#endif
 		{ 0, (char *)NULL },
 		{ 0, (char *)NULL },
 		{ 0, (char *)NULL },
@@ -247,7 +283,8 @@
 		{ 0, (char *)NULL },
 		{ 0, (char *)NULL },
 		{ 0, (char *)NULL },
-/* 381 */	{ RPL_YOUREOPER, ":You are now an IRC Operator" },
+/* 381 */	{ RPL_YOUREOPER, ":You are now known as an IRC supermouse\
+ ~(,,^>." },
 /* 382 */	{ RPL_REHASHING, "%s :Rehashing" },
 /* 383 */	{ RPL_YOURESERVICE, ":You are service %s" },
 /* 384 */	{ RPL_MYPORTIS, "%d :Port to local server is\r\n" },
@@ -293,7 +330,7 @@
 /* 217 */	{ RPL_STATSQLINE, "%c %s %s %s %d %d" },
 /* 218 */	{ RPL_STATSYLINE, "%c %d %d %d %d %ld %d.%d %d.%d" },
 /* 219 */	{ RPL_ENDOFSTATS, "%c :End of STATS report" },
-		{ 0, (char *)NULL },
+/* 220 */	{ RPL_STATSPLINE, "%c %d %s %d :%s %s" },
 /* 221 */	{ RPL_UMODEIS, "%s" },
 		{ 0, (char *)NULL },
 		{ 0, (char *)NULL },
@@ -338,7 +375,13 @@
 /* 261 */	{ RPL_TRACELOG, "File %s %d" },
 /* 262 */	{ RPL_TRACEEND, "%s %s.%s :End of TRACE" },
 /* 263 */	{ RPL_TRYAGAIN, "%s :Please wait a while and try again." },
+#ifdef EXTRA_STATISTICS
+		{ 0, (char *)NULL },
+/* 265 */	{ RPL_LOCALUSERS, ":Current local users: %d  Max: %d" },
+/* 266 */	{ RPL_GLOBALUSERS, ":Current global users: %d  Max: %d" }
+#else
 		{ 0, (char *)NULL }
+#endif
 };
 
 char	*err_str(numeric, to)
diff -Nur irc2.10.3p7/ircd/s_misc.c irc2.10.3p7+hemp2+DK+B5/ircd/s_misc.c
--- irc2.10.3p7/ircd/s_misc.c	Sun May  9 22:20:33 2004
+++ irc2.10.3p7+hemp2+DK+B5/ircd/s_misc.c	Tue May 11 15:25:04 2004
@@ -370,7 +370,11 @@
 	    {
 		if (sptr->flags & FLAGS_KILLED)
 		    {
+#ifdef LOCAL_REJECTIONS_ONLY
+			sendto_flag(SCH_NOTICE, "Killed: %s.",
+#else
 			sendto_flag(SCH_LOCAL, "Killed: %s.",
+#endif
 				    get_client_name(sptr, TRUE));
 			sptr->exitc = EXITC_KILL;
 		    }
@@ -386,6 +390,11 @@
 			sendto_flog(sptr, NULL, sptr->user->username,
 				    sptr->user->host);
 # endif
+#ifdef CLIENTS_CHANNEL
+			sendto_flag(SCH_CLIENTS, "Client exiting: %s was %s from %s reason: %s",
+				sptr->name,sptr->user->username,sptr->user->host,comment);
+
+#endif
 		    }
 		else if (sptr->exitc != EXITC_REF && sptr->exitc != EXITC_AREF)
 		    {
@@ -409,15 +418,43 @@
 			else
 				istat.is_unknown--;
 
-		      if (cptr != NULL && sptr != cptr)
-			sendto_one(sptr, "ERROR :Closing Link: %s %s (%s)",
-				   get_client_name(sptr,FALSE),
-				   cptr->name, comment);
-		      else
-			sendto_one(sptr, "ERROR :Closing Link: %s (%s)",
-				   get_client_name(sptr,FALSE), comment);
-
-		      if (sptr->auth != sptr->username)
+			if (istat.is_myclnt % CLCHNO == 0 &&
+				istat.is_myclnt != istat.is_l_myclnt)
+			{
+				sendto_flag(SCH_NOTICE,
+					"Local %screase from %d to %d clients "
+					"in %d seconds",
+					istat.is_myclnt > istat.is_l_myclnt ?
+					"in" : "de", istat.is_l_myclnt,
+					istat.is_myclnt,
+					timeofday - istat.is_l_myclnt_t);
+				istat.is_l_myclnt_t = timeofday;
+				istat.is_l_myclnt = istat.is_myclnt;
+			}
+#ifdef DELAY_CLOSE
+	                if (cptr && cptr->user && (cptr->user->flags
+						& FLAGS_BADBOY))
+               		{ 
+                           SPRINTF(cptr->buffer, "ERROR :Closing Link: %s (%s)",
+                           get_client_name(sptr,FALSE), comment);
+                        }
+                        else
+#endif
+		        {
+		        	if (cptr != NULL && sptr != cptr)
+				{
+					sendto_one(sptr, "ERROR :Closing Link: %s %s (%s)",
+				   	get_client_name(sptr,FALSE),
+				   	cptr->name, comment);
+				}
+		      		else
+				{
+					sendto_one(sptr, "ERROR :Closing Link: %s (%s)",
+				   	get_client_name(sptr,FALSE), comment);
+
+		    		}
+			}
+		        if (sptr->auth != sptr->username)
 			  {
 			    istat.is_authmem -= strlen(sptr->auth) + 1;
 			    istat.is_auth -= 1;
@@ -504,6 +541,15 @@
 				    }
 			    }
 		    } /* If (IsServer(sptr)) */
+#ifdef SPLIT_HANDLE
+		if ((istat.is_user[0] + istat.is_user[1]) < SPLIT_USERS || istat.is_eobservers < SPLIT_SERV)
+		{
+			if (!iconf.split)
+			{
+				check_split();
+			}
+		}
+#endif
 	    } /* if (MyConnect(sptr) || (sptr->flags & FLAGS_HELD)) */
 
  	if (IsServer(sptr) && GotDependantClient(sptr))
@@ -531,6 +577,16 @@
  			acptr->flags |= flags;
 			exit_one_client(cptr, acptr, &me, comment1);
  		}
+#ifdef SPLIT_HANDLE
+		if ((istat.is_user[0] + istat.is_user[1]) < SPLIT_USERS || istat.is_eobservers < SPLIT_SERV)
+		{
+			if (!iconf.split)
+			{
+				check_split();
+			}
+		}
+#endif
+
  	}
  	
 	/*
@@ -585,6 +641,15 @@
 	}
 	
 	exit_one_client(cptr, sptr, from, (*comment1) ? comment1 : comment);
+#ifdef SPLIT_HANDLE
+		if ((istat.is_user[0] + istat.is_user[1]) < SPLIT_USERS || istat.is_eobservers < SPLIT_SERV)
+		{
+			if (!iconf.split)
+			{
+				check_split();
+			}
+		}
+#endif
 	return cptr == sptr ? FLUSH_BUFFER : 0;
     }
 
@@ -612,13 +677,65 @@
 			    "ERROR: tried to exit me! : %s", comment);
 		return;	/* ...must *never* exit self!! */
 	    }
-	else if (IsServer(sptr)) {
+	else if (IsServer(sptr)) 
+	{
+		Link *lpu,**tmp;
+		aClient *auptr;
+		int dcnt = 0;
+
+
 	 /*
 	 ** Old sendto_serv_but_one() call removed because we now
 	 ** need to send different names to different servers
 	 ** (domain name matching)
 	 */
 		istat.is_serv--;
+#ifdef SPLIT_HANDLE
+		if (!IsBurst(sptr))
+		{
+			istat.is_eobservers--;
+		}
+#endif
+	/* we have also remove the server from ->down */
+		auptr = find_client(sptr->serv->up,NULL);
+		/* hmm.. if it doesn't exist, it means it squitted before */
+		if (auptr)
+		{
+			lpu = auptr->serv->down;
+			if (lpu)
+			{
+				dcnt = --lpu->flags;
+			}
+			for (tmp = &(auptr->serv->down); (lpu = *tmp); tmp = &lpu->next)
+			{
+				if (lpu->value.cptr == sptr)
+				{
+					*tmp = lpu->next;
+					free_link(lpu);
+					break;
+				}
+			}
+			if (auptr->serv->down)
+			{
+					auptr->serv->down->flags = dcnt;
+			}
+		}
+		/* and free my downlinks. The squit code is SOOO broken btw */
+		if (sptr->serv->down)
+		{
+			Link *lp2;
+			lp2 = sptr->serv->down;
+			while (lp2)
+			{
+				lpu = lp2;
+				lp2 = lp2->next;
+				free_link(lpu);
+			}
+			sptr->serv->down = NULL;
+		}
+#ifdef EXTRA_STATISTICS
+		save_server_max(sptr->name,sptr->serv->usermax);
+#endif
 	 	for (i = fdas.highest; i >= 0; i--)
 		    {
 			Reg	aConfItem *aconf;
@@ -704,11 +821,21 @@
 		if (sptr->user)
 		    {
 			if (IsInvisible(sptr))
+			{
 				istat.is_user[1]--;
-			else
-				istat.is_user[0]--;
+				sptr->user->servp->usercnt[1]--;
+			}
+                        else
+                        {
+                                sptr->user->servp->usercnt[0]--;
+                                istat.is_user[0]--;
+                        }
+
 			if (IsAnOper(sptr))
+			{
 				istat.is_oper--;
+				sptr->user->servp->usercnt[2]--;
+			}
 			sendto_common_channels(sptr, ":%s QUIT :%s",
 						sptr->name, comment);
 
@@ -753,6 +880,8 @@
 			add_history(sptr, (sptr == cptr) ? &me : NULL);
 #endif
 			off_history(sptr);
+			del_from_hostname_hash_table(sptr->user->host,sptr->user);
+
 		    }
 	    }
 	else if (sptr->name[0] && IsService(sptr))
@@ -833,16 +962,33 @@
 	istat.is_serv = 1;
 	istat.is_localc = 1;	/* &me */
 	bzero((char *)&ircst, sizeof(ircst));
+
+	bzero((char *)&iconf, sizeof(iconf));
+	iconf.aconnect = 1;
+	iconf.split = 1;
+#ifdef DELAY_ACCEPT
+	iconf.caccept = 2;
+#endif
 }
 
+#ifdef	EXTRA_STATISTICS
+void	tstats(cptr, name, level)
+aClient	*cptr;
+char	*name;
+int	level;
+#else
 void	tstats(cptr, name)
 aClient	*cptr;
 char	*name;
+#endif
 {
 	Reg	aClient	*acptr;
 	Reg	int	i;
 	Reg	struct stats	*sp;
 	struct	stats	tmp;
+#ifdef	EXTRA_STATISTICS
+	Reg     time_t  now;
+#endif
 
 	sp = &tmp;
 	bcopy((char *)ircstp, (char *)sp, sizeof(*sp));
@@ -892,6 +1038,173 @@
 			sp->is_ni++;
 	    }
 
+#ifdef	EXTRA_STATISTICS
+	switch (level) {
+	case 2:	now = timeofday - me.since;
+		if (now == 0)
+			now = 1;
+
+		sendto_one(cptr,
+    ":%s %d %s :------------------------------------------------------",
+    ME, RPL_STATSDEBUG, name);
+		sendto_one(cptr,
+    ":%s %d %s :Current uptime: %4d day%s, %2d:%02d:%02d%s      %10d s",
+    ME, RPL_STATSDEBUG, name, now/86400, ( now/86400 == 1 ? "" : "s"),
+    (now/3600)%24, (now/60)%60, now%60, ( now/86400 == 1 ? " " : ""), now);
+		sendto_one(cptr,
+    ":%s %d %s :------------------------------------------------------",
+    ME, RPL_STATSDEBUG, name);
+		sendto_one(cptr,
+    ":%s %d %s :Connected  Current  Highest  Average    Total  NetHigh",
+    ME, RPL_STATSDEBUG, name);
+		sendto_one(cptr,
+    ":%s %d %s :Clients:   %6u %8u %8.1f %8u %8u",
+    ME, RPL_STATSDEBUG, name, istat.is_myclnt, istat.is_m_myclnt,
+    (float )((double ) sp->is_cti / (double ) (now)), sp->is_cl,
+    istat.is_m_users);
+		if (istat.is_m_myservice != 0)
+			sendto_one(cptr,
+	    ":%s %d %s :Services:  %6u %8u                   %8u",
+	    ME, RPL_STATSDEBUG, name, istat.is_myservice,
+	    istat.is_m_myservice, istat.is_m_service);
+		sendto_one(cptr,
+    ":%s %d %s :Servers:   %6u %8u %8.1f %8u %8u",
+    ME, RPL_STATSDEBUG, name, istat.is_myserv, istat.is_m_myserv,
+    ((float ) sp->is_sti / (float ) (now)), sp->is_sv, istat.is_m_serv);
+		sendto_one(cptr,
+    ":%s %d %s :------------------------------------------------------",
+    ME, RPL_STATSDEBUG, name);
+		sendto_one(cptr,
+    ":%s %d %s :Duration         Average                       Total",
+    ME, RPL_STATSDEBUG, name);
+		sendto_one(cptr,
+    ":%s %d %s :Clients:     %4d:%02d:%02d                %12lu s",
+    ME, RPL_STATSDEBUG, name,
+    ((sp->is_cti / (sp->is_cl ? sp->is_cl : 1))/3600),
+    (((sp->is_cti / (sp->is_cl ? sp->is_cl : 1))/60)%60),
+    ((sp->is_cti / (sp->is_cl ? sp->is_cl : 1))%60), sp->is_cti);
+		sendto_one(cptr,
+    ":%s %d %s :Servers:     %4d:%02d:%02d                %12lu s",
+    ME, RPL_STATSDEBUG, name,
+    ((sp->is_sti / (sp->is_sv ? sp->is_sv : 1))/3600),
+    (((sp->is_sti / (sp->is_sv ? sp->is_sv : 1))/60)%60),
+    ((sp->is_sti / (sp->is_sv ? sp->is_sv : 1))%60), sp->is_sti);
+		sendto_one(cptr,
+    ":%s %d %s :------------------------------------------------------",
+    ME, RPL_STATSDEBUG, name);
+		sendto_one(cptr,
+    ":%s %d %s :Data received    Average       Rate           Total",
+    ME, RPL_STATSDEBUG, name);
+		sendto_one(cptr,
+    ":%s %d %s :Clients:       %8lu Kb  %6.2f Kb/s %10lu Kb",
+    ME, RPL_STATSDEBUG, name, (sp->is_ckr / ( sp->is_cl ? sp->is_cl : 1 )),
+    ((double ) sp->is_ckr / (double ) (now)), sp->is_ckr);
+		sendto_one(cptr,
+    ":%s %d %s :Servers:       %8lu Kb  %6.2f Kb/s %10lu Kb",
+    ME, RPL_STATSDEBUG, name,
+    ( sp->is_skr / ( sp->is_sv ? sp->is_sv : 1 )),
+    (float )((double ) sp->is_skr / (double ) (now)), sp->is_skr);
+		sendto_one(cptr,
+    ":%s %d %s :UDP:           %8u",
+    ME, RPL_STATSDEBUG, name, sp->is_udpok);
+		sendto_one(cptr,
+    ":%s %d %s :------------------------------------------------------",
+    ME, RPL_STATSDEBUG, name);
+		sendto_one(cptr,
+    ":%s %d %s :Data sent        Average       Rate           Total",
+    ME, RPL_STATSDEBUG, name);
+		sendto_one(cptr,
+    ":%s %d %s :Clients:       %8lu Kb  %6.2f Kb/s %10lu Kb",
+    ME, RPL_STATSDEBUG, name, (sp->is_cks / (sp->is_cl ? sp->is_cl : 1)),
+    (float )((double ) sp->is_cks / (double ) (now)), sp->is_cks);
+		sendto_one(cptr,
+    ":%s %d %s :Servers:       %8lu Kb  %6.2f Kb/s %10lu Kb",
+    ME, RPL_STATSDEBUG, name, (sp->is_sks / (sp->is_sv ? sp->is_sv : 1)),
+    (float )((double ) sp->is_sks / (double ) (now)), sp->is_sks);
+		sendto_one(cptr,
+    ":%s %d %s :------------------------------------------------------",
+    ME, RPL_STATSDEBUG, name);
+		return;
+
+	case 1:	sendto_one(cptr,
+    ":%s %d %s :------------------------------------------------------",
+    ME, RPL_STATSDEBUG, name);
+#if !defined(USE_IAUTH)
+		sendto_one(cptr,
+    ":%s %d %s :Authorization fails:                         %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_abad);
+		sendto_one(cptr,
+    ":%s %d %s :Authorization successes:                     %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_asuc);
+#endif
+		sendto_one(cptr,
+    ":%s %d %s :Connections accepted:                        %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_ac);
+		sendto_one(cptr,
+    ":%s %d %s :Connections refused:                         %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_ref);
+		sendto_one(cptr,
+    ":%s %d %s :Local connections made:                      %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_loc);
+		sendto_one(cptr,
+    ":%s %d %s :------------------------------------------------------",
+    ME, RPL_STATSDEBUG, name);
+		sendto_one(cptr,
+    ":%s %d %s :Fakes:                                       %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_fake);
+		sendto_one(cptr,
+    ":%s %d %s :Nick Collisions:                             %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_kill);
+	sendto_one(cptr,
+    ":%s %d %s :Unknown connections dropped:                 %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_ni);
+		sendto_one(cptr,
+    ":%s %d %s :Users without servers:                       %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_nosrv);
+		sendto_one(cptr,
+    ":%s %d %s :Empty messages:                              %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_empt);
+		sendto_one(cptr,
+    ":%s %d %s :Numerics seen:                               %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_num);
+		sendto_one(cptr,
+    ":%s %d %s :Unknown commands:                            %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_unco);
+		sendto_one(cptr,
+    ":%s %d %s :Unknown prefixes:                            %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_unpf);
+		sendto_one(cptr,
+    ":%s %d %s :Wrong directions:                            %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_wrdi);
+		sendto_one(cptr,
+    ":%s %d %s :------------------------------------------------------",
+    ME, RPL_STATSDEBUG, name);
+		sendto_one(cptr,
+    ":%s %d %s :Elapsed time     Minimum   Average   Maximum     Limit",
+    ME, RPL_STATSDEBUG, name);
+		sendto_one(cptr,
+    ":%s %d %s :Nick Delay:    %8lu  %8lu  %8lu  %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_wwmt,
+    (u_int) (sp->is_wwt / (sp->is_wwcnt ? sp->is_wwcnt : 1 )),
+    sp->is_wwMt, KILLCHASETIMELIMIT);
+		sendto_one(cptr,
+    ":%s %d %s :Whowas:        %8lu  %8lu  %8lu  %8lu",
+    ME, RPL_STATSDEBUG, name, sp->is_lkmt,
+    (u_int) (sp->is_lkt / (sp->is_lkcnt ? sp->is_lkcnt : 1)),
+    sp->is_lkMt, DELAYCHASETIMELIMIT);
+		sendto_one(cptr,
+    ":%s %d %s :------------------------------------------------------",
+    ME, RPL_STATSDEBUG, name);
+#if defined(USE_IAUTH)
+	report_iauth_stats(cptr, name);
+		sendto_one(cptr,
+	":%s %d %s :------------------------------------------------------",
+	ME, RPL_STATSDEBUG, name);
+#endif
+		return;
+	}
+#endif
+
 	sendto_one(cptr, ":%s %d %s :accepts %lu refused %lu",
 		   ME, RPL_STATSDEBUG, name, sp->is_ac, sp->is_ref);
 	sendto_one(cptr, ":%s %d %s :unknown: commands %lu prefixes %lu",
@@ -939,6 +1252,13 @@
 		   sp->is_ckr, sp->is_cbr, sp->is_skr, sp->is_sbr);
 	sendto_one(cptr, ":%s %d %s :time connected %lu %lu",
 		   ME, RPL_STATSDEBUG, name, sp->is_cti, sp->is_sti);
+#ifdef DELAY_CLOSE
+        if (IsAnOper(cptr))
+        {
+                sendto_one(cptr, ":%s %d %s :delay closed %lu",
+                   ME,RPL_STATSDEBUG, name, istat.is_delayclosed);
+        }
+#endif
 #if defined(USE_IAUTH)
 	report_iauth_stats(cptr, name);
 #endif
@@ -995,4 +1315,340 @@
 	(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
 	close(fd);
 }     
+#endif
+
+
+#if defined(OPER_KLINE) || defined(LOCOP_KLINE)
+int	m_kline(cptr,sptr,parc,parv)
+aClient	*cptr, *sptr;
+int	parc;
+char	*parv[];
+{
+
+#if defined(OPER_KLINE) && defined(LOCOP_KLINE)
+	if (!MyClient(sptr) || !IsAnOper(sptr))
+#else
+#  if defined(OPER_KLINE)
+	if (!MyClient(sptr) || !IsOper(sptr))
+#  else
+	if (!MyClient(sptr) || !IsLocOp(sptr))
+#  endif
+#endif
+	    {
+		sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0]), me.name,
+		    parv[0]);
+		return 0;
+	    }
+
+	return m_dokline(cptr,sptr,parc,parv,1);
+}
+#endif
+
+
+#if defined(OPER_TKLINE) || defined(LOCOP_TKLINE)
+int	m_tkline(cptr,sptr,parc,parv)
+aClient	*cptr, *sptr;
+int	parc;
+char	*parv[];
+{
+
+#if defined(OPER_TKLINE) && defined(LOCOP_TKLINE)
+	if (!MyClient(sptr) || !IsAnOper(sptr))
+#else
+#  if defined(OPER_TKLINE)
+	if (!MyClient(sptr) || !IsOper(sptr))
+#  else
+	if (!MyClient(sptr) || !IsLocOp(sptr))
+#  endif
+#endif
+	   {
+		sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0]), me.name,
+		    parv[0]);
+		return 0;
+	    }
+
+	return m_dokline(cptr,sptr,parc,parv,0);
+}
+#endif
+
+
+#if defined(OPER_KLINE) || defined(LOCOP_KLINE) || \
+    defined(OPER_TKLINE) || defined(LOCOP_TKLINE)
+extern int kline_added;
+
+int	m_dokline(cptr, sptr, parc, parv, perm)
+aClient	*cptr, *sptr;
+int	parc;
+char	*parv[];
+int	perm;
+{
+	aConfItem	*aconf;
+	aClient		*acptr;
+	int		out, i;
+	char		buffer[1024];
+	char		*user, *host;
+	char		kline_reason[256];
+	time_t		current_time;
+
+	if (parc < 3)
+	    {
+		sendto_one(sptr, ":%s NOTICE %s :Not enough parameters",
+			me.name, parv[0]);
+		return 0;
+	    }
+
+	if (match("*@*", parv[1]))
+	    {
+		sendto_one(sptr,
+		":%s NOTICE %s :Sorry but \"%s\" needs to be of the format\
+ of user@host", me.name, parv[0], parv[1]);
+		return 0;
+	    }
+
+	user = parv[1];
+	while (*user)
+	    {
+		if ((*user == ' ') || (*user =='#') ||
+#ifdef INET6
+			(*user == '%')
+#else
+			(*user == ':')
+#endif
+			)
+			break;
+		user++;
+	    }
+
+	if (*user && (*user != ' '))
+	    {
+		sendto_one(sptr,
+		    ":%s NOTICE %s :The user@host may not contain '%c'",
+		    me.name, parv[0], *user);
+		return 0;
+	    }
+
+	host = strchr(parv[1], '@');
+	*(host++) = '\0';
+
+	if ((user = strchr(host, ' ')) != NULL)
+		*user = '\0';
+	user = parv[1];
+
+	if (!match(user, "dummyuser") && !match(host, "dumm.ystring.xx"))
+	    {
+		sendto_one(sptr,
+		    ":%s NOTICE %s :Sorry can not %skline *@*",
+		    me.name, parv[0], ( perm ? "" : "t" ));
+		return 0;
+	    }
+
+	kline_reason[0] = '\0';
+	if (isdigit(*parv[2]))
+	    {
+		sendto_one(sptr,
+		    ":%s NOTICE %s :The %skline reason may not start\
+ with a digit",
+		    me.name, parv[0], ( perm ? "" : "t" ));
+		return 0;
+	    }
+
+	for (i = 2; i < parc; i++)
+	    {
+		if (strlen(parv[i]) + strlen(kline_reason) + 2 < 256)
+		    {
+			strcat(kline_reason, parv[i]);
+			strcat(kline_reason, "\240");
+		    }
+	     }
+	kline_reason[strlen(kline_reason) - 1] = '\0';
+
+	for (i = strlen(kline_reason) - 1; i >= 0; i--)
+	    {
+		if ((kline_reason[i] == '#') || 
+#ifdef INET6
+			(kline_reason[i] == '%')
+#else
+			(kline_reason[i] == ':')
+#endif
+			)
+		    {
+			sendto_one(sptr,
+			    ":%s NOTICE %s :The %skline reason may not\
+ contain '%c'",
+			    me.name, parv[0], ( perm ? "" : "t" ),
+			    kline_reason[i]);
+			return 0;
+		    }
+		}
+
+	aconf = make_conf();
+	aconf->status = CONF_KILL;
+	DupString(aconf->host, host);
+	DupString(aconf->passwd, kline_reason);
+	DupString(aconf->name, user);
+	aconf->port = 0;
+	Class(aconf) = find_class(0);
+	aconf->next = kconf;
+	kconf = aconf;
+	aconf = NULL;
+
+	kline_added = 1;
+	rehashed    = 1;
+
+	if (perm)
+	    {
+		if ((out = open(KLINE_FILE, O_WRONLY|O_APPEND))==-1)
+		    {
+			sendto_one(sptr,
+			    ":%s NOTICE %s :Problem opening server configfile",
+			    me.name, parv[0]);
+			return 0;
+		    }
+
+		time(&current_time);
+
+		sprintf(buffer, "# Added by %s (%s@%s) on %s",
+			sptr->name, sptr->user->username, sptr->user->host,
+			asctime(localtime(&current_time)));
+		if (write(out, buffer, strlen(buffer)) <= 0)
+		    {
+			sendto_one(sptr,
+			":%s NOTICE %s :Problem writing to the configfile",
+			me.name, parv[0]);
+			close(out);
+			return 0;
+		    }
+
+#ifdef INET6
+		sprintf(buffer, "K%%%s%%%s%%%s%%\n\n", host, kline_reason, user);
+#else
+		sprintf(buffer, "K:%s:%s:%s:\n\n", host, kline_reason, user);
+#endif
+		if (write(out, buffer, strlen(buffer)) <= 0)
+		    {
+			sendto_one(sptr,
+			":%s NOTICE %s :Problem writing to the configfile",
+			me.name, parv[0]);
+			close(out);
+		        return 0;
+		    }
+		close(out);
+	    }
+
+	sendto_flag(SCH_LOCAL, "%s added a %skline for %s@%s with reason: %s",
+	    parv[0], ( perm ? "" : "t" ), user, host, kline_reason);
+	sendto_one(sptr, 
+	    ":%s NOTICE %s :Added %skline for %s@%s%s with reason: %s",
+	    me.name, parv[0], ( perm ? "" : "t" ), user, host,
+	    ( perm ? " to the server configfile" : "" ), kline_reason);
+#if defined(USE_SYSLOG) && defined(SYSLOG_KLINE)
+	syslog(LOG_INFO, "%s!%s@%s %skline %s@%s (%s)",
+		sptr->name, sptr->user->username, sptr->user->host,
+		( perm ? "" : "t" ), user, host, kline_reason);
+#endif
+
+
+	return 0;
+}
+#endif
+
+#ifdef EXTRA_STATISTICS
+static Link *saved_servers = NULL;
+void save_server_max(server,clients)
+char *server;
+int clients;
+{
+	Link *lp;
+	char *servername;
+
+	for (lp = saved_servers; lp ; lp = lp->next)
+	{
+		if (!mycmp(lp->value.cp,server))
+		{
+			sendto_flag(SCH_ERROR,"Tried to save server's user maximum for already saved server");
+			return;
+		}
+	}
+	
+	servername = mystrdup(server);
+	lp = make_link();
+	lp->value.cp = servername;
+	lp->flags = clients;
+	lp->next = saved_servers;
+	saved_servers = lp;
+}
+
+
+int restore_server_max(server)
+char *server;
+{
+	Link *lp, **curr;
+	int users = 0;
+	
+	for (curr = &saved_servers ; (lp = *curr); curr = &lp->next)
+	{
+		if (!mycmp(lp->value.cp,server))
+		{
+			users = lp->flags;
+			*curr = lp->next;
+			free_link(lp);
+			break;
+		}
+	}
+	return users; 
+}
+#endif
+
+#ifdef SPLIT_HANDLE
+void check_split()
+{
+	if (istat.is_eobservers < SPLIT_SERV ||
+	   (istat.is_user[0] + istat.is_user[1] < SPLIT_USERS))
+	{
+		if (!iconf.split)
+		{
+			sendto_flag(SCH_NOTICE,"Network split detected, split mode activated");
+		}
+		iconf.split = 1;
+	}
+	else
+	{
+		if (iconf.split)
+		{
+			sendto_flag(SCH_NOTICE,"Network rejoined, split mode deactivated");
+#ifdef DELAY_ACCEPT
+			if (iconf.caccept == 1)
+			{
+				activate_delayed_listeners();
+				iconf.caccept = 2;
+			}
+#endif
+		}
+		iconf.split = 0;
+
+	}
+	
+}
+void bubble_eob(sptr)
+aClient *sptr;
+{
+	aClient *acptr = sptr;
+	char *up = sptr->serv->up;
+	while (up && mycmp(up,me.name))
+	{
+		up = acptr->serv->up;
+		acptr = find_server(up,NULL);
+		if (!acptr)
+		{
+			sendto_flag(SCH_ERROR,"Unknown uplink %s while bubbling EOB ?!",up);
+			break;
+		}
+		if (IsBurst(acptr))
+		{
+			ClearBurst(acptr);
+			istat.is_eobservers++;
+			sendto_flag(SCH_DEBUG,"EOB from %s (bubbled)",up);
+		}
+	}
+}
 #endif
diff -Nur irc2.10.3p7/ircd/s_misc_ext.h irc2.10.3p7+hemp2+DK+B5/ircd/s_misc_ext.h
--- irc2.10.3p7/ircd/s_misc_ext.h	Mon Aug  3 16:09:23 1998
+++ irc2.10.3p7+hemp2+DK+B5/ircd/s_misc_ext.h	Tue May 11 15:25:04 2004
@@ -51,8 +51,27 @@
 			    char *comment));
 EXTERN void checklist();
 EXTERN void initstats();
+#ifdef	EXTRA_STATISTICS
+EXTERN void tstats __P((aClient *cptr, char *name, int level));
+#else
 EXTERN void tstats __P((aClient *cptr, char *name));
+#endif
 #ifdef  CACHED_MOTD
 EXTERN void read_motd __P((char *filename));
 #endif /* CACHED_MOTD */
+#if	defined(OPER_KLINE) || defined(LOCOP_KLINE)
+EXTERN int m_kline __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+#endif
+#if	defined(OPER_TKLINE) || defined(LOCOP_TKLINE)
+EXTERN int m_tkline __P((aClient *cptr, aClient *sptr, int parc,
+    char *parv[]));
+#endif
+#ifdef EXTRA_STATISTICS
+EXTERN void save_server_max __P((char *server,int clients));
+EXTERN int restore_server_max __P((char *server));
+#endif
+#ifdef SPLIT_HANDLE
+EXTERN void check_split();
+EXTERN void bubble_eob __P((aClient *sptr));
+#endif
 #undef EXTERN
diff -Nur irc2.10.3p7/ircd/s_numeric.c irc2.10.3p7+hemp2+DK+B5/ircd/s_numeric.c
--- irc2.10.3p7/ircd/s_numeric.c	Sun Dec 13 00:48:17 1998
+++ irc2.10.3p7+hemp2+DK+B5/ircd/s_numeric.c	Tue May 11 15:25:04 2004
@@ -82,7 +82,8 @@
 	    }
 	for (; (nick = strtoken(&p, parv[1], ",")); parv[1] = NULL)
 	    {
-		if ((acptr = find_client(nick, (aClient *)NULL)))
+		if ((acptr = find_client(nick, (aClient *)NULL)) ||
+		     (acptr = find_server(nick, NULL)))
 		    {
 			/*
 			** Drop to bit bucket if for me...
@@ -96,11 +97,27 @@
 			** - Avalon
 			*/
 			if (IsMe(acptr) || acptr->from == cptr)
+			{
+#ifdef SPLIT_HANDLE
+				if (IsServer(sptr) && IsBurst(sptr) &&
+					numeric == ERR_NOSUCHSERVER)
+				{    /* we got EOB-emulation reply */
+					ClearBurst(sptr);
+					sendto_flag(SCH_DEBUG,"End of burst from %s (emulated)",sptr->name);
+					istat.is_eobservers++;
+					bubble_eob(sptr);
+					check_split();
+				}
+				else
+#endif
+				{
 				sendto_flag(SCH_NUM,
 					    "From %s for %s: %s %d %s %s.",
 					    get_client_name(cptr, TRUE),
 					    acptr->name, sptr->name,
 					    numeric, nick, buffer);
+				}
+			}
 			else if (IsPerson(acptr) || IsServer(acptr) ||
 				 IsService(acptr))
 				sendto_prefix_one(acptr, sptr,":%s %d %s%s",
diff -Nur irc2.10.3p7/ircd/s_serv.c irc2.10.3p7+hemp2+DK+B5/ircd/s_serv.c
--- irc2.10.3p7/ircd/s_serv.c	Mon Mar  1 19:00:33 2004
+++ irc2.10.3p7+hemp2+DK+B5/ircd/s_serv.c	Tue May 11 15:25:04 2004
@@ -517,7 +517,11 @@
 		/* A server can only be introduced by another server. */
 		if (!IsServer(sptr))
 		    {
-			sendto_flag(SCH_LOCAL,
+#ifdef LOCAL_REJECTIONS_ONLY
+				sendto_flag(SCH_NOTICE,
+#else
+				sendto_flag(SCH_LOCAL,
+#endif
 			    "Squitting %s brought by %s (introduced by %s)",
 				    host, get_client_name(cptr, FALSE),
 				    sptr->name);
@@ -605,11 +609,38 @@
 		if (acptr->info != DefInfo)
 			MyFree(acptr->info);
 		acptr->info = mystrdup(info);
-		acptr->serv->up = sptr->name;
+		acptr->serv->up = mystrdup(sptr->name);
 		acptr->serv->stok = token;
 		acptr->serv->snum = find_server_num(acptr->name);
 		SetServer(acptr);
 		istat.is_serv++;
+#ifdef	EXTRA_STATISTICS
+		/*
+		**  Keep track of the highest number of connected
+		**  servers (hostmasks) to this network.
+		**/
+		if (istat.is_serv > istat.is_m_serv)
+			istat.is_m_serv = istat.is_serv;
+		acptr->serv->usermax = restore_server_max(acptr->name);
+#endif
+#ifdef 	SPLIT_HANDLE
+		SetBurst(acptr);
+		sendto_one(cptr,":%s PING %s :%s",my_name_for_link(ME,cptr->serv->nline->port),
+			my_name_for_link(ME,cptr->serv->nline->port),
+			acptr->name);
+#endif
+		/* add server to downlink list */
+		{
+			Link *lp;
+
+			lp = make_link();
+			bzero((char *)lp, sizeof(Link));
+			lp->value.cptr = acptr;
+			lp->next = sptr->serv->down;
+			/* we keep number of downlinks in flags */
+			lp->flags = sptr->serv->down ? sptr->serv->down->flags + 1 : 1;
+			sptr->serv->down = lp;
+		}
 		add_client_to_list(acptr);
 		(void)add_to_client_hash_table(acptr->name, acptr);
 		(void)add_to_server_hash_table(acptr->serv, cptr);
@@ -857,16 +888,50 @@
 	**	code is more neat this way...  --msa
 	*/
 	SetServer(cptr);
+#ifdef SPLIT_HANDLE
+	SetBurst(cptr);
+#endif
 	istat.is_unknown--;
 	istat.is_serv++;
+#ifdef	EXTRA_STATISTICS
+	/*
+	**  Keep track of the highest number of connected
+	**  servers to this network.
+	**/
+	if (istat.is_serv > istat.is_m_serv)
+		istat.is_m_serv = istat.is_serv;
+#endif
 	istat.is_myserv++;
+#ifdef	EXTRA_STATISTICS
+	/*
+	**  Keep track of the highest number of servers which
+	**  this server has had connected simultaniously.
+	*/
+	if (istat.is_myserv > istat.is_m_myserv)
+		istat.is_m_myserv = istat.is_myserv;
+#endif
+
+#ifdef SERVER_MAP
+		/* add server to downlink list */
+		{
+			Link *lp;
+
+			lp = make_link();
+			bzero((char *)lp, sizeof(Link));
+			lp->value.cptr = cptr;
+			lp->next = me.serv->down;
+			/* we keep number of downlinks in flags */
+			lp->flags = me.serv->down ? me.serv->down->flags + 1 : 1;
+			me.serv->down = lp;
+		}
+#endif
 	nextping = timeofday;
 	sendto_flag(SCH_NOTICE, "Link with %s established. (%X%s)", inpath,
 		    cptr->hopcount, (cptr->flags & FLAGS_ZIP) ? "z" : "");
 	(void)add_to_client_hash_table(cptr->name, cptr);
 	/* doesnt duplicate cptr->serv if allocted this struct already */
 	(void)make_server(cptr);
-	cptr->serv->up = me.name;
+	cptr->serv->up = mystrdup(me.name);
 	cptr->serv->nline = aconf;
 	cptr->serv->version = cptr->hopcount;   /* temporary location */
 	cptr->hopcount = 1;			/* local server connection */
@@ -877,6 +942,9 @@
 	Debug((DEBUG_NOTICE, "Server link established with %s V%X %d",
 		cptr->name, cptr->serv->version, cptr->serv->stok));
 	add_fd(cptr->fd, &fdas);
+#ifdef EXTRA_STATISTICS
+	cptr->serv->usermax = restore_server_max(cptr->name);
+#endif
 #ifdef	USE_SERVICES
 	check_services_butone(SERVICE_WANT_SERVER, cptr->name, cptr,
 			      ":%s SERVER %s %d %s :%s", ME, cptr->name,
@@ -1004,7 +1072,10 @@
 				send_channel_modes(cptr, chptr);
 			    }
 	    }
-
+#ifdef SPLIT_HANDLE
+	/* send PING- emulate EOB */
+	sendto_one(cptr,":%s PING %s %s",my_name_for_link(ME, aconf->port),my_name_for_link(ME, aconf->port),cptr->name);
+#endif
 	cptr->flags &= ~FLAGS_CBURST;
 #ifdef	ZIP_LINKS
  	/*
@@ -1079,7 +1150,11 @@
 {
 	char **text = infotext;
 
-	if (IsServer(cptr) && check_link(cptr))
+	if (
+#ifdef NO_OPER_TRYAGAIN
+		!IsOper(sptr) &&
+#endif
+		IsServer(cptr) && check_link(cptr))
 	    {
 		sendto_one(sptr, rpl_str(RPL_TRYAGAIN, parv[0]),
 			   "INFO");
@@ -1312,6 +1387,9 @@
 {
 	static	char	null[] = "<NULL>";
 	aConfItem *tmp;
+#ifdef ILINE_FLAGS
+	char nmbuf[HOSTLEN*2];
+#endif
 	int	*p, port;
 	char	c, *host, *pass, *name;
 	
@@ -1320,14 +1398,61 @@
 		if (tmp->status & mask)
 		    {
 			for (p = &report_array[0][0]; *p; p += 3)
-				if (*p == tmp->status)
+				if ((*p & tmp->status) && !(*p & CONF_ILLEGAL))
 					break;
 			if (!*p)
 				continue;
 			c = (char)*(p+2);
 			host = BadPtr(tmp->host) ? null : tmp->host;
 			pass = BadPtr(tmp->passwd) ? NULL : tmp->passwd;
-			name = BadPtr(tmp->name) ? null : tmp->name;
+#ifdef ILINE_FLAGS
+			if ((tmp->status & (CONF_CLIENT | CONF_RCLIENT)) &&
+					tmp->status & (CONF_EXEMPT|CONF_RNODNS))
+			{
+				if ((tmp->status & CONF_EXEMPT) &&
+				     tmp->status & CONF_RNODNS)
+				{
+					if (BadPtr(tmp->name))
+					{
+						name = "<EXEMPT|RNODNS>";
+					}
+					else
+					{
+						sprintf(nmbuf,"+<%s",tmp->name);
+						name = nmbuf;
+					}
+				}
+				else if (tmp->status & CONF_EXEMPT)
+				{
+					if (BadPtr(tmp->name))
+					{
+						name = "<EXEMPT>";
+					}
+					else
+					{
+						sprintf(nmbuf,"<%s",tmp->name);
+						name = nmbuf;
+					}
+
+				}
+				else
+				{
+					if (BadPtr(tmp->name))
+					{
+						name = "<RNODNS>";
+					}
+					else
+					{
+						sprintf(nmbuf,"+%s",tmp->name);
+						name = nmbuf;
+					}
+				}
+			}
+			else
+#endif
+			{
+				name = BadPtr(tmp->name) ? null : tmp->name;
+			}
 			port = (int)tmp->port;
 			/*
 			 * On K/V lines the passwd contents can be
@@ -1369,7 +1494,151 @@
 		    }
 	return;
 }
+#ifdef STATS_F
+static void report_fd(sptr,acptr,to)
+aClient *sptr, *acptr;
+char *to;
+{
+	static char locip[100], *ret;
+	int s;
+
+	if (IsMe(acptr) || !acptr->acpt || !IsRegistered(acptr))
+		return;
+	ret = 
+#ifdef INET6
+		inetntop(AF_INET6,
+		(char *)&acptr->acpt->ip,
+		mydummy, MYDUMMY_SIZE),
+#else
+		inetntoa((char *)&acptr->acpt->ip);
+#endif
+	s = strlen(ret) + 1;
+	memcpy(locip, ret, s < sizeof(locip) ? s : sizeof(locip));
+	locip[sizeof(locip) - 1] = 0;
+	sendto_one(sptr,":%s %d %s %d %s %d %s %d %s %s %d",
+		ME,RPL_STATSLINKINFO,to,
+		acptr->fd,
+		locip,
+		acptr->acpt->port,
+#ifdef INET6
+		inetntop(AF_INET6,
+		(char *)&acptr->ip,
+		mydummy, MYDUMMY_SIZE),
+#else
+		inetntoa((char *)&acptr->ip),
+#endif
+		acptr->port,acptr->name,
+		acptr->user ? acptr->user->username : acptr->auth,
+		acptr->user ? timeofday - acptr->user->last : -1
+		);
+}
+#endif /* STATS_F */
+#ifdef STATS_QMARK
+/* show quick info about connected servers */
+static void report_myservers(sptr,to)
+aClient *sptr;
+char *to;
+{
+	int i;
+	int timeconnected;
+	aClient *acptr;
+	aServer *asptr;
+	int users = 0, servers = 0;
 
+	for (i = fdas.highest; i >= 0; i--)
+	{
+		if (!(acptr = local[fdas.fd[i]]))
+		{
+			continue;
+		}
+		
+		if (IsMe(acptr) || !IsServer(acptr))
+		{
+			continue;
+		}
+		users = 0;
+		servers = 0;
+
+		timeconnected = timeofday - acptr->firsttime;
+#ifdef HUB
+                        for (asptr = svrtop;asptr;asptr = asptr->nexts)
+                        {
+                                if (asptr->bcptr->from == acptr)
+                                {
+                                        servers++;
+                                        users += asptr->usercnt[0];
+					users += asptr->usercnt[1];
+				}
+			}
+#else /* !HUB */
+			servers = istat.is_serv - 1;
+			users = istat.is_user[0] + istat.is_user[1];
+			users -= istat.is_myclnt;
+#endif
+		sendto_one(sptr,":%s %d %s : %s (%d, %02d:%02d:%02d) %dS %dC %ldkB sent %ldkB recv %ldkB sq%s",
+			   ME,RPL_STATSDEBUG,to,acptr->name,
+			   timeconnected / 86400,(timeconnected % 86400) / 3600,
+			   (timeconnected % 3600)/60,
+			   timeconnected % 60,servers,users,acptr->sendK,acptr->receiveK,(int) (
+	                   (int)DBufLength(&acptr->sendQ) / 1024),
+#ifdef SPLIT_HANDLE
+			   IsBurst(acptr) ? " BURST" : ""
+#else
+			   ""
+#endif
+			   );
+	}
+}
+#endif
+#ifdef DELAY_ACCEPT
+static void report_listeners(sptr,to)
+aClient *sptr;
+char *to;
+{
+	aConfItem *tmp;
+	int active,comma;
+	for (tmp = conf; tmp; tmp = tmp->next)
+	{
+		if (!(tmp->status & CONF_LISTEN_PORT))
+		{
+			continue;
+		}
+
+		/* this SUUUUX, we need some nice list of all listeners!
+		 * - jv
+		 */
+		if (tmp->status & CONF_ACTIVE)
+		{
+			active = 1;
+		}
+		else
+		{
+			active = 0;
+		}
+		*buf = 0;
+		comma = 0;
+		if (tmp->status & CONF_DELAY)
+		{
+			strcat(buf,"delay");
+			comma = 1;
+		}
+		
+		if (tmp->status & CONF_SERVERONLY)
+		{
+			if (comma)
+			{
+				strcat(buf,",");
+			}
+			strcat(buf,"server-only");
+		}
+		
+		sendto_one(sptr,":%s %d %s :%d %s %s",ME,RPL_STATSDEFINE,to,
+				tmp->port,active ? "active" : "inactive",buf);
+		
+	}
+}
+	
+#endif
 int	m_stats(cptr, sptr, parc, parv)
 aClient *cptr, *sptr;
 int	parc;
@@ -1430,14 +1699,35 @@
 				2, parc, parv) != HUNTED_ISME)
 			return 5;
 	    }
-
 	name = (parc > 2) ? parv[2] : ME;
 	cm = (parc > 3) ? parv[3]: name;
 	doall = !match(name, ME) && !match(cm, ME);
 	wilds = index(cm, '*') || index(cm, '?');
+	
+	/* no stats, just dumb client */
+	if (parv[1] && !mycmp(parv[1],ME))
+	{
+		return 2;
+	}
+	
+#ifdef CLIENTS_CHANNEL
+       if (stat && (sptr->user)) {
+		sendto_flag(SCH_CLIENTS,"Stats %c by %s from %s on %s",
+			stat,sptr->name,sptr->user->username,sptr->user->host);
+       }
+#endif
 
 	switch (stat)
 	{
+#ifdef STATS_F
+	case 'f' : case 'F' : /* send FD list */
+		if (!IsOper(sptr) || !MyConnect(sptr))
+		{
+			stat = '*';
+			break;
+		}
+		stat = 'f';
+#endif
 	case 'L' : case 'l' :
 		/*
 		 * send info about connections which match, or all if the
@@ -1457,6 +1747,13 @@
 			    {
 				if (!(acptr = local[i]))
 					continue;
+#ifdef STATS_F
+				if (stat == 'f')
+				{
+					report_fd(sptr, acptr, parv[0]);
+					continue;
+				}
+#endif	
 				if (IsPerson(acptr) && !(MyConnect(sptr) 
 				    && IsAnOper(sptr)) && acptr != sptr)
 					continue;
@@ -1475,7 +1772,12 @@
 		else
 		    {
 			if ((acptr = find_client(cm, NULL)) && MyConnect(acptr))
-				sendto_one(cptr, Lformat, ME,
+#ifdef STATS_F
+				if (stat == 'f')
+					report_fd(sptr, acptr, parv[0]);
+				else
+#endif
+					sendto_one(cptr, Lformat, ME,
 					RPL_STATSLINKINFO, parv[0],
 					get_client_name(acptr, isupper(stat)),
 					(int)DBufLength(&acptr->sendQ),
@@ -1511,6 +1813,14 @@
 					CONF_CLIENT|CONF_RCLIENT);
 		break;
 	case 'K' : case 'k' : /* K lines */
+#ifdef NOSTATSK
+                if (!IsAnOper(sptr))
+                {
+                        sendto_one(sptr, err_str(ERR_STATSKLINE, parv[0]));
+                        return 2;
+                }
+                else
+#endif
 		report_configured_links(cptr, parv[0],
 					(CONF_KILL|CONF_OTHERKILL));
 		break;
@@ -1540,8 +1850,24 @@
 	case 'S' : case 's' : /* S lines */
 		report_configured_links(cptr, parv[0], CONF_SERVICE);
 		break;
+#ifdef	EXTRA_STATISTICS
+	case 'T' : /* various statistics for operators only */
+		if (MyOper(sptr)) {
+			tstats(cptr, parv[0], 2);
+			break;
+		}
+	case 't' : /* various statistics for operators only */
+		if (MyOper(sptr)) {
+			tstats(cptr, parv[0], 1);
+			break;
+		}
+
+		/* various statistics */
+		tstats(cptr, parv[0], 0);
+#else
 	case 'T' : case 't' : /* various statistics */
 		tstats(cptr, parv[0]);
+#endif
 		break;
 	case 'U' : case 'u' : /* uptime */
 	    {
@@ -1572,6 +1898,11 @@
 	case 'z' :	      /* memory use */
 		count_memory(cptr, parv[0], 0);
 		break;
+#ifdef STATS_QMARK
+	case '?' :
+		report_myservers(sptr,parv[0]);
+		break;
+#endif
 	default :
 		stat = '*';
 		break;
@@ -1690,122 +2021,118 @@
 int	parc;
 char	*parv[];
     {
-	int	s_count = 0,	/* server */
-		c_count = 0,	/* client (visible) */
-		u_count = 0,	/* unknown */
-		i_count = 0,	/* invisible client */
-		o_count = 0,	/* oparator */
-		v_count = 0;	/* service */
-	int	m_client = 0,	/* my clients */
-		m_server = 0,	/* my server links */
-		m_service = 0;	/* my services */
-	aClient *acptr;
-
+	int		s_count = 0,	/* server */
+			c_count = 0,	/* visible client */
+			u_count = 0,	/* unknown */
+			i_count = 0,	/* invisible client */
+			o_count = 0,	/* operator */
+			v_count = 0;	/* service */
+	int		m_client = 0,	/* my clients */
+			m_server = 0,	/* my server links */
+			m_service = 0;	/* my services */
+	int		mask_max = 0;	/* max of given mask */
+	
 	if (parc > 2)
 		if (hunt_server(cptr, sptr, ":%s LUSERS %s :%s", 2, parc, parv)
 		    != HUNTED_ISME)
 			return 3;
 
 	if (parc == 1 || !MyConnect(sptr))
-	    {
-		sendto_one(sptr, rpl_str(RPL_LUSERCLIENT, parv[0]),
-			   istat.is_user[0] + istat.is_user[1],
-			   istat.is_service, istat.is_serv);
-		if (istat.is_oper)
-			sendto_one(sptr, rpl_str(RPL_LUSEROP, parv[0]),
-				   istat.is_oper);
-		if (istat.is_unknown > 0)
-			sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN, parv[0]),
-				   istat.is_unknown);
-		if (istat.is_chan)
-			sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS, parv[0]),
-				   istat.is_chan);
-		sendto_one(sptr, rpl_str(RPL_LUSERME, parv[0]),
-			   istat.is_myclnt, istat.is_myservice,
-			   istat.is_myserv);
-		return 2;
-	    }
-	(void)collapse(parv[1]);
-	for (acptr = client; acptr; acptr = acptr->next)
-	    {
-		if (!IsServer(acptr) && acptr->user)
-		    {
-			if (match(parv[1], acptr->user->server))
-				continue;
-		    }
-		else
-      			if (match(parv[1], acptr->name))
-				continue;
+	{
+		s_count = istat.is_serv;
+		c_count = istat.is_user[0];
+		i_count = istat.is_user[1];
+		u_count = istat.is_unknown;
+		o_count = istat.is_oper;
+		v_count = istat.is_service;
+		m_client = istat.is_myclnt;
+		m_server = istat.is_myserv;
+		m_service = istat.is_myservice;
+#ifdef EXTRA_STATISTICS
+		mask_max = istat.is_m_users;
+#endif
+	}
+	else
+	{	
+		aClient 	*acptr;
+        	aServer 	*asptr;
+		aService 	*svcp;
+		
+		(void)collapse(parv[1]);
+		
+		/* LUSERS <mask> */
+		for (asptr = svrtop;asptr;asptr = asptr->nexts)
+		{
+			if (!match(parv[1],asptr->bcptr->name))
+			{
+				s_count++;
+				
+				c_count += asptr->usercnt[0];
+				i_count += asptr->usercnt[1];
+				o_count += asptr->usercnt[2];
+				/* not exact probably, but oh well... */
+#ifdef EXTRA_STATISTICS
+				mask_max += asptr->usermax;				
+#endif
+				if (IsMe(asptr->bcptr))
+				{
+					m_client = istat.is_myclnt;
+					m_server = istat.is_myserv;
+					m_service = istat.is_myservice;
+					u_count = istat.is_unknown;
 
-		switch (acptr->status)
+				}
+			}
+		}
+	
+		/* Count services, but only if we found some matching server
+		 * before (to prevent wrong matches on masks like *irc*). - jv
+		 */
+		if (s_count)
 		{
-		case STAT_SERVER:
-			if (MyConnect(acptr))
-				m_server++;
-			/* flow thru */
-		case STAT_ME:
-			s_count++;
-			break;
-		case STAT_SERVICE:
-			if (MyConnect(acptr))
-				m_service++;
-			v_count++;
-			break;
-		case STAT_CLIENT:
-			if (IsOper(acptr))
-				o_count++;
-#ifdef	SHOW_INVISIBLE_LUSERS
-			if (MyConnect(acptr))
-		  		m_client++;
-			if (!IsInvisible(acptr))
-				c_count++;
-			else
-				i_count++;
-#else
-			if (MyConnect(acptr))
-			    {
-				if (IsInvisible(acptr))
-				    {
-					if (IsAnOper(sptr))
-						m_client++;
-				    }
-				else
-					m_client++;
-			    }
-	 		if (!IsInvisible(acptr))
-				c_count++;
-			else
-				i_count++;
-#endif
-			break;
-		default:
-			u_count++;
-			break;
-	 	}
-	     }
-#ifndef	SHOW_INVISIBLE_LUSERS
-	if (IsAnOper(sptr) && i_count)
+			for (svcp = svctop;svcp;svcp = svcp->nexts)
+			{
+				if (!match(parv[1],svcp->servp->bcptr->name))
+				{
+					v_count++;
+				}
+			}
+		}
+	}
+	
+#ifndef SHOW_INVISIBLE_LUSERS
+	if (!IsOper(sptr))
+	{
+		i_count = 0;
+	}
 #endif
 	sendto_one(sptr, rpl_str(RPL_LUSERCLIENT, parv[0]),
 		   c_count + i_count, v_count, s_count);
-#ifndef	SHOW_INVISIBLE_LUSERS
-	else
-		sendto_one(sptr, rpl_str(RPL_LUSERCLIENT, parv[0]),
-			   c_count, v_count, s_count);
-#endif
 	if (o_count)
+	{
 		sendto_one(sptr, rpl_str(RPL_LUSEROP, parv[0]), o_count);
-	if (u_count > 0)
+	}
+	if (u_count)
+	{
 		sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN, parv[0]), u_count);
-	if ((c_count = count_channels(sptr))>0)
-		sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS, parv[0]),
-			   count_channels(sptr));
+	}
+	sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS, parv[0]),istat.is_chan);
 	sendto_one(sptr, rpl_str(RPL_LUSERME, parv[0]), m_client, m_service,
 		   m_server);
+#ifdef EXTRA_STATISTICS
+	if (m_client)
+	{
+		sendto_one(sptr, rpl_str(RPL_LOCALUSERS, parv[0]),
+				istat.is_myclnt, istat.is_m_myclnt);
+	}
+	sendto_one(sptr, rpl_str(RPL_GLOBALUSERS, parv[0]),
+			 c_count + i_count, mask_max);
+#endif
+	
 	return 2;
     }
 
-  
+
 /***********************************************************************
  * m_connect() - Added by Jto 11 Feb 1989
  ***********************************************************************/
@@ -1836,7 +2163,7 @@
 		       3,parc,parv) != HUNTED_ISME)
 		return 1;
 
-	if (parc < 3 || *parv[1] == '\0')
+	if (parc < 2 || *parv[1] == '\0')
 	    {
 		sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]),
 			   "CONNECT");
@@ -1879,18 +2206,34 @@
 	** from there, then use the precompiled default.
 	*/
 	tmpport = port = aconf->port;
-	if ((port = atoi(parv[2])) <= 0)
-	    {
+
+	if (parc > 2)
+	{
+		port = atoi(parv[2]);
+	}
+	if (parc < 3 || !port)
+	{
+		if (tmpport < 0)
+		{
+			port = 0 - port;
+		}
+		else
+		{
+			port = tmpport;
+		}
+
+		if (!port)
+		{
+			sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number",
+				   ME, parv[0]);
+			return 0;
+		}
+	}
+	if (port < 0)
+	{
 		sendto_one(sptr, "NOTICE %s :Connect: Illegal port number",
 			   parv[0]);
-		return 0;
-	    }
-	else if (port <= 0)
-	    {
-		sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number",
-			   ME, parv[0]);
-		return 0;
-	    }
+	}
 	/*
 	** Notify all operators about remote connect requests
 	*/
@@ -2040,6 +2383,14 @@
 #ifdef USE_SYSLOG
 	syslog(LOG_INFO, "REHASH From %s\n", get_client_name(sptr, FALSE));
 #endif
+#ifdef DELAY_CLOSE
+        if (parc >1 && parv[1] && *parv[1] == 'd')
+        {
+                delay_close(-2,NULL);
+		sendto_flag(SCH_NOTICE,
+		    "%s is forcing closing of delay closed sockets", parv[0]);
+        }
+#endif
 	return rehash(cptr, sptr, (parc > 1) ? ((*parv[1] == 'q')?2:0) : 0);
 }
 #endif
@@ -2087,171 +2438,236 @@
 }
 #endif
 
-/*
-** m_trace
-**	parv[0] = sender prefix
-**	parv[1] = servername
-*/
-int	m_trace(cptr, sptr, parc, parv)
-aClient *cptr, *sptr;
-int	parc;
-char	*parv[];
+void trace_one(to,sptr,acptr)
+char *to;
+aClient *sptr,*acptr;
 {
-	Reg	int	i;
-	Reg	aClient	*acptr;
-	aClass	*cltmp;
-	char	*tname;
-	int	doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
-	int	wilds, dow;
-
-	if (parc > 1)
-		tname = parv[1];
-	else
-		tname = ME;
-
-	switch (hunt_server(cptr, sptr, ":%s TRACE :%s", 1, parc, parv))
-	{
-	case HUNTED_PASS: /* note: gets here only if parv[1] exists */
-	    {
-		aClient	*ac2ptr;
-
-		ac2ptr = next_client(client, parv[1]);
-		sendto_one(sptr, rpl_str(RPL_TRACELINK, parv[0]),
-			   version, debugmode, tname, ac2ptr->from->name,
-			   ac2ptr->from->serv->version,
-			   (ac2ptr->from->flags & FLAGS_ZIP) ? "z" : "",
-			   timeofday - ac2ptr->from->firsttime,
-			   (int)DBufLength(&ac2ptr->from->sendQ),
-			   (int)DBufLength(&sptr->from->sendQ));
-		return 5;
-	    }
-	case HUNTED_ISME:
-		break;
-	default:
-		return 1;
-	}
+	char *name;
+	int class;
 
-	doall = (parv[1] && (parc > 1)) ? !match(tname, ME): TRUE;
-	wilds = !parv[1] || index(tname, '*') || index(tname, '?');
-	dow = wilds || doall;
-
-	if (doall) {
-		for (i = 0; i < MAXCONNECTIONS; i++)
-			link_s[i] = 0, link_u[i] = 0;
-		for (acptr = client; acptr; acptr = acptr->next)
-#ifdef	SHOW_INVISIBLE_LUSERS
-			if (IsPerson(acptr))
-				link_u[acptr->from->fd]++;
-#else
-			if (IsPerson(acptr) &&
-			    (!IsInvisible(acptr) || IsOper(sptr)))
-				link_u[acptr->from->fd]++;
-#endif
-			else if (IsServer(acptr))
-				link_s[acptr->from->fd]++;
-	}
-
-	/* report all direct connections */
+	name = get_client_name(acptr,FALSE);
+	class = get_client_class(acptr);
 	
-	for (i = 0; i <= highest_fd; i++)
-	    {
-		char	*name;
-		int	class;
-
-		if (!(acptr = local[i])) /* Local Connection? */
-			continue;
-		if (IsPerson(acptr) && IsInvisible(acptr) && dow &&
-		    !(MyConnect(sptr) && IsAnOper(sptr)) &&
-		    !IsAnOper(acptr) && (acptr != sptr))
-			continue;
-		if (!doall && wilds && match(tname, acptr->name))
-			continue;
-		if (!dow && mycmp(tname, acptr->name))
-			continue;
-		name = get_client_name(acptr,FALSE);
-		class = get_client_class(acptr);
-
-		switch(acptr->status)
-		{
+	switch (acptr->status)
+	{
 		case STAT_CONNECTING:
 			sendto_one(sptr, rpl_str(RPL_TRACECONNECTING,
-				   parv[0]), class, name);
-			break;
+						to), class, name);
+	    	break;
+			
 		case STAT_HANDSHAKE:
-			sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE, parv[0]),
-				   class, name);
+			sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE, to),
+						class, name);
 			break;
+
 		case STAT_ME:
 			break;
+		
 		case STAT_UNKNOWN:
-			if (IsAnOper(sptr) || (MyPerson(sptr) && SendWallops(sptr)))
-				sendto_one(sptr,
-					   rpl_str(RPL_TRACEUNKNOWN, parv[0]),
+				sendto_one(sptr,rpl_str(RPL_TRACEUNKNOWN, to),
 					   class, name);
 			break;
+	
 		case STAT_CLIENT:
-			/* Only opers see users if there is a wildcard
-			 * but anyone can see all the opers.
-			 */
 			if (IsAnOper(acptr))
-				sendto_one(sptr,
-					   rpl_str(RPL_TRACEOPERATOR, parv[0]),
-					   class, name);
-			else if (!dow || (MyConnect(sptr) && IsAnOper(sptr)))
-				sendto_one(sptr,
-					   rpl_str(RPL_TRACEUSER, parv[0]),
-					   class, name);
+			{
+				sendto_one(sptr,rpl_str(RPL_TRACEOPERATOR,
+						to),class, name);
+			}
+			else
+			{
+				sendto_one(sptr,rpl_str(RPL_TRACEUSER,
+					to),class, name);
+			}
+
 			break;
+			
 		case STAT_SERVER:
+		{
+			/* we need to count servers/users behind this link */
+			int servers = 0, users = 0;
+			aServer *asptr;
+			aClient *next;
+#ifdef HUB
+			for (asptr = svrtop;asptr;asptr = asptr->nexts)
+			{
+				if (asptr->bcptr->from == acptr)
+				{
+					servers++;
+					users += asptr->usercnt[0];
+#ifdef SHOW_INVISIBLE_LUSERS
+					users += asptr->usercnt[1];						
+#endif
+				}
+			}
+#else /* !HUB */
+				/* we can have only one server linked */
+			servers = istat.is_serv - 1;
+			users = istat.is_user[0];
+#ifdef SHOW_INVISIBLE_LUSERS
+			users += istat.is_user[1];
+			users -= istat.is_myclnt;
+#else
+			users -= me.usercnt[0];
+#endif
+#endif /* HUB */
+	
 			if (acptr->serv->user)
-				sendto_one(sptr, rpl_str(RPL_TRACESERVER,
-					   parv[0]), class, link_s[i],
-					   link_u[i], name, acptr->serv->by,
-					   acptr->serv->user->username,
-					   acptr->serv->user->host,
-					   acptr->serv->version,
-					   (acptr->flags & FLAGS_ZIP) ?"z":"");
+			{
+					sendto_one(sptr, rpl_str(RPL_TRACESERVER,
+								to), class, servers, users, name, 
+								acptr->serv->by, acptr->serv->user->username,
+                                acptr->serv->user->host, acptr->serv->version,
+								(acptr->flags & FLAGS_ZIP) ?"z":"");
+			}
 			else
+			{
 				sendto_one(sptr, rpl_str(RPL_TRACESERVER,
-					   parv[0]), class, link_s[i],
-					   link_u[i], name,
-					   *(acptr->serv->by) ?
-					   acptr->serv->by : "*", "*", ME,
-					   acptr->serv->version,
-					   (acptr->flags & FLAGS_ZIP) ?"z":"");			break;
+						   to), class, servers, users, name,
+						   *(acptr->serv->by) ?  acptr->serv->by : "*", "*", 
+						   ME, acptr->serv->version,
+						   (acptr->flags & FLAGS_ZIP) ?"z":"");
+			}
+			break;
+		}	
 		case STAT_RECONNECT:
-			sendto_one(sptr, rpl_str(RPL_TRACERECONNECT, parv[0]),
-				   class, name);
+			sendto_one(sptr, rpl_str(RPL_TRACERECONNECT, to),
+						class, name);
 			break;
+			
 		case STAT_SERVICE:
-			sendto_one(sptr, rpl_str(RPL_TRACESERVICE, parv[0]),
-				   class, name, acptr->service->type,
-				   acptr->service->wants);
+        				sendto_one(sptr, rpl_str(RPL_TRACESERVICE, to),
+                                   class, name, acptr->service->type,
+                                   acptr->service->wants);
 			break;
+			
 		case STAT_LOG:
-			sendto_one(sptr, rpl_str(RPL_TRACELOG, parv[0]),
-				   ME, acptr->port);
+			sendto_one(sptr, rpl_str(RPL_TRACELOG, to),
+                                   ME, acptr->port);
 			break;
+			
 		default: /* ...we actually shouldn't come here... --msa */
-			sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE, parv[0]),
-				   name);
-			break;
-		}
-	    }
+			sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE, to),
+                       name);
+        	break;
+	}
+}
 
-	/*
-	 * Add these lines to summarize the above which can get rather long
-	 * and messy when done remotely - Avalon
-	 */
-	if (IsPerson(sptr) && SendWallops(sptr))
-	    for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
-		if (Links(cltmp) > 0)
-			sendto_one(sptr, rpl_str(RPL_TRACECLASS, parv[0]),
-				   Class(cltmp), Links(cltmp));
-	sendto_one(sptr, rpl_str(RPL_TRACEEND, parv[0]), tname, version,
+/*
+ * m_trace
+ * 	parv[0] = sender prefix
+ * 	parv[1] = traced nick/server/service
+ */
+int	m_trace(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int	parc;
+char	*parv[];
+{
+	aClient *acptr;
+	int maskedserv = 0;
+	int i = 0;
+	
+	if (parc > 1)
+	{
+		/* wildcards now allowed only in server/service names */
+		acptr = find_matching_client(parv[1],NULL);
+		if (!acptr)
+		{
+			sendto_one(sptr, err_str(ERR_NOSUCHSERVER,
+					parv[0]), parv[1]);
+			return 1;
+		}
+		if (IsServer(acptr))
+		{
+			if (!match(acptr->name,parv[1]))
+			{
+				/* if we are tracing masked server,
+				 * we have to send parv[1], not acptr->name
+				 */
+				maskedserv = 1;
+			}
+		}
+	}
+	else
+	{
+		acptr = &me;
+	}
+	if (!IsMe(acptr))
+	{
+		if (!MyConnect(acptr) || IsServer(acptr))
+		{
+#ifdef RESTRICT_RESTRICTED
+			if (MyConnect(sptr) && IsRestricted(sptr))
+			{
+				sendto_one(sptr,err_str(ERR_RESTRICTED,parv[0]));
+				return 5;
+			}
+#endif
+			if (acptr->from == cptr)
+			{	/* eek ?! */
+				return 1;
+			}
+			/* passthru */
+              		sendto_one(sptr, rpl_str(RPL_TRACELINK, parv[0]),
+	      	                   version, debugmode, (maskedserv) ? parv[1] : acptr->name, acptr->from->name,
+				   acptr->from->serv->version,
+				   (acptr->from->flags & FLAGS_ZIP) ? "z" : "",
+        	               	   timeofday - acptr->from->firsttime,
+                	           (int)DBufLength(&acptr->from->sendQ),
+                        	   (int)DBufLength(&sptr->from->sendQ));
+			sendto_one(acptr,":%s TRACE :%s",sptr->name, (maskedserv) ? parv[1] : acptr->name);
+			return 5;
+		}
+		else
+		{
+			/* tracing something local */
+			trace_one(parv[0],sptr,acptr);	
+		}
+	}
+	else
+	{
+		/* well, report everything */
+		aClient *a2cptr;
+		
+		for (i = 0; i <= highest_fd; i++)
+		{
+			if (!(a2cptr = local[i]))
+			{
+				continue;
+			}
+			if (IsMe(a2cptr))
+			{
+				continue;
+			}
+			if (IsPerson(a2cptr) && !(a2cptr == sptr || IsAnOper(a2cptr) ||
+						(IsAnOper(sptr) && MyConnect(sptr))) )
+			{
+				continue;
+			}
+			if (IsUnknown(a2cptr) && !((IsAnOper(sptr) || MyClient(sptr))
+						&& SendWallops(sptr)) )
+			{
+				continue;
+			}
+			trace_one(parv[0],sptr,a2cptr);	
+		}
+		if (IsPerson(sptr) && SendWallops(sptr))
+		{
+			aClass  *cltmp;
+		    	for (cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp))
+		    	{
+				if (Links(cltmp) > 0)
+				{
+					sendto_one(sptr, rpl_str(RPL_TRACECLASS, parv[0]),
+					   Class(cltmp), Links(cltmp));
+				}
+	   		}
+		}
+	}
+	sendto_one(sptr, rpl_str(RPL_TRACEEND, parv[0]), acptr->name, version,
 		   debugmode);
 	return 2;
-    }
+}
 
 /*
 ** m_motd
@@ -2274,7 +2690,11 @@
 	struct	tm	*tm;
 #endif
 
-	if (check_link(cptr))
+	if (
+#ifdef NO_OPER_TRYAGAIN
+		!IsOper(sptr) &&
+#endif
+		check_link(cptr))
 	    {
 		sendto_one(sptr, rpl_str(RPL_TRYAGAIN, parv[0]), "MOTD");
 		return 5;
@@ -2394,6 +2814,293 @@
 	return 0;
 }
 #endif
+#ifdef SERVER_MAP
+static void dump_map(sptr,root,pbuf)
+aClient *sptr;
+aClient *root;
+char *pbuf;
+{
+        Link *lp;
+        int cnt,i = 0;
+        int len;
+        int pad = 53;    /* at which position we add stats */
+        int users,max;
+        aClient *acptr;
+	
+        *pbuf= '\0';
+        strcat(pbuf,root->name);
+        len = strlen(buf);
+        buf[len] = ' ';
+        if (len < pad )
+        {
+                for (i = len+1 ; i < pad ; i++)
+                {
+                        buf[i] = '-';
+                }
+        }
+	if (IsMe(root))
+	{
+		max = istat.is_m_myclnt;
+	}
+	else
+	{
+		max = root->serv->usermax;
+	}
+        users = root->serv->usercnt[0] + root->serv->usercnt[1];
+        SPRINTF(buf + pad ," | %5d %4.1f  %5d",users,  100 * (float) users /
+                        (float) (istat.is_user[0] + istat.is_user[1]),
+                        max);
+
+	sendto_one(sptr,rpl_str(RPL_MAP,sptr->name),buf);
+	
+	i = 1;
+	if ((lp = root->serv->down))
+	{
+		cnt = lp->flags;
+		if (cnt)
+		{
+			if (pbuf > buf + 3)
+			{
+				pbuf[-2] = ' ';
+				if (pbuf[-3] == '`')
+				{
+					pbuf[-3] = ' ';
+				}
+			}
+		}
+	}
+	
+	for (; lp; lp = lp->next)
+	{
+		*pbuf = ' ';
+		if (i < cnt)
+		{
+			*(pbuf + 1) = '|';
+		}
+		else
+		{
+			*(pbuf + 1) = '`';
+		}
+
+		*(pbuf + 2) = '-';
+		*(pbuf + 3) = ' ';
+		acptr = lp->value.cptr;
+		dump_map(sptr,acptr,pbuf+4);
+		i++;
+	}
+	
+}
+/* based on ircu's m_map and kreynet's format */
+int m_map(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char    *parv[];
+{
+sendto_one(sptr,rpl_str(RPL_MAPSTART,parv[0]),"Server name","Users    %    Max");
+	dump_map(sptr,&me,buf,0);
+	sendto_one(sptr,rpl_str(RPL_MAPEND,parv[0]));
+	return 2;
+}
+#endif
+#ifdef OPER_SET
+static char *def_values[] =
+{
+	"OFF",
+	"ON",
+	NULL
+};
+static char *caccept_values[] =
+{
+	"OFF",
+	"SPLIT",
+	"ON",
+	NULL
+};
+static struct Set_Message set_msgtab[] =
+{
+	{"ACONNECT",&iconf.aconnect,def_values},
+#ifdef DELAY_ACCEPT
+	{"CACCEPT",&iconf.caccept,caccept_values},
+#endif
+	{NULL,NULL,NULL}
+};
+static void set_action(option,value)
+char *option;
+int value;
+{
+	if (!mycmp(option,"ACONNECT"))
+	{
+		if (value == 1)
+		{
+			nextconnect = timeofday;
+		}
+	}
+#ifdef DELAY_ACCEPT
+	else if (!mycmp(option,"CACCEPT"))
+	{
+		if (value == 2)
+		{
+			activate_delayed_listeners();
+		}
+	}
+#endif
+}
+int m_set(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char    *parv[];
+{
+	
+	struct Set_Message *mptr;
+	int val,i = 0;
+	char *endptr;
+	char **valstr;
+	char obuf[BUFSIZE];
+	
+	obuf[0] = 0;
+	
+	/* query for values */
+	if (parc < 2)
+	{
+		for (mptr = set_msgtab; mptr->cmd; mptr++)
+		{
+			sendto_one(sptr,":%s NOTICE %s :Value of %s is %s",ME,parv[0],
+				mptr->cmd, mptr->values[*(mptr->value)]);
+		}
+
+		return 1;
+	}
+	
+	/* query for one value */
+	if (parc == 2)
+	{
+		for (mptr = set_msgtab; mptr->cmd; mptr++)
+		{
+			if (mycmp(parv[1],mptr->cmd))
+			{
+				continue;
+			}
+			
+			sendto_one(sptr,":%s NOTICE %s :Value of %s is %s",ME,parv[0],
+				mptr->cmd, mptr->values[*(mptr->value)]);
+			return 1;
+		}
+			sendto_one(sptr,":%s NOTICE %s :Unknown option %s",ME,parv[0],parv[1]);
+
+		return 1;
+	}
+	/* setting value */	
+	for (mptr = set_msgtab; mptr->cmd; mptr++)
+	{
+		if (!mycmp(parv[1],mptr->cmd))
+		{
+			break;
+		}
+	}
+	if (!mptr->cmd)
+	{
+		sendto_one(sptr,":%s NOTICE %s :Unknown option %s",ME,parv[0],parv[1]);
+		return 1;
+	}
+	val = strtol(parv[2],&endptr,10);
+		
+	if (endptr != parv[2])
+	{
+		/* ha! a number! */
+		if (mptr->values)
+		{ /* value has symbolical names */
+			i = 0;
+			for (valstr = mptr->values; *valstr; valstr++)
+			{
+				if (i == val)
+				{
+					break;
+				}
+				strcat(obuf,*valstr);
+				strcat(obuf," ");
+				i++;
+			}
+			if (!*valstr)
+			{
+				sendto_one(sptr,":%s NOTICE %s :Uknown value %d for option %d, avaible values are %s",
+						ME,parv[0],val,mptr->cmd,obuf);
+				return 1;
+						
+			}
+			if (*(mptr->value) == i)
+			{
+				sendto_one(sptr,":%s NOTICE %s :Value of %s was already set to %s",
+					ME,parv[0],mptr->cmd,*valstr);
+				return 1;
+
+			}
+			
+			*(mptr->value) = val;
+			sendto_one(sptr,":%s NOTICE %s :Value of %s set to %s",
+					ME,parv[0],mptr->cmd,*valstr);
+			sendto_flag(SCH_NOTICE,"%s changed value of %s to %s",
+					parv[0],mptr->cmd,*valstr);
+			set_action(mptr->cmd,val);
+			return 1;
+		}
+		else
+		{ /* numeric only */
+			if (*(mptr->value) == val)
+			{
+			sendto_one(sptr, ":%s NOTICE %s :Value of %s was already set to %d",
+					ME,parv[0],mptr->cmd,val);
+
+				return 1;
+			}
+			*(mptr->value) = val;
+			sendto_one(sptr, ":%s NOTICE %s :Value of %s set to %d",
+					ME,parv[0],mptr->cmd,val);
+			sendto_flag(SCH_NOTICE,"%s changed value of %s to %d",
+					parv[0],mptr->cmd,val);
+	
+			set_action(mptr->cmd,val);
+			return 1;
+		}
+	}
+	else
+	{
+		i = 0;
+		for (valstr = mptr->values; *valstr; valstr++)
+		{
+			if (!mycmp(parv[2],*valstr))
+			{ /* found value */
+				break;	
+			}
+			i++;
+			strcat(obuf,*valstr);
+			strcat(obuf," ");
+		}
+		if (!*valstr)
+		{
+			sendto_one(sptr,":%s NOTICE %s :Unknown value for %s, avaible options are %s",
+				ME,parv[0],mptr->cmd,obuf);
+			return 1;
+		}
+		if (*(mptr->value) == i)
+		{
+			sendto_one(sptr, ":%s NOTICE %s :Value of %s was already set to %d",
+				ME,parv[0],mptr->cmd,val);
+			return 1;
+		}
+
+		*(mptr->value) = i;
+		sendto_one(sptr, ":%s NOTICE %s :Value of %s set to %s",
+			ME,parv[0],mptr->cmd,*valstr);
+		sendto_flag(SCH_NOTICE,"%s changed value of %s to %s",
+					parv[0],mptr->cmd,*valstr);
+	
+		set_action(mptr->cmd,i);
+		return 1;
+
+	}
+		
+}
+#endif
 
 /*
 ** storing server names in User structures is a real waste,
@@ -2503,6 +3210,7 @@
     return -1;
 }
 
+#ifndef DELAY_ACCEPT
 static void report_listeners(aClient *sptr, char *to)
 {
 	aConfItem *tmp;
@@ -2518,3 +3226,4 @@
 		}
 	}
 }
+#endif
diff -Nur irc2.10.3p7/ircd/s_serv_ext.h irc2.10.3p7+hemp2+DK+B5/ircd/s_serv_ext.h
--- irc2.10.3p7/ircd/s_serv_ext.h	Wed Sep  3 19:46:04 1997
+++ irc2.10.3p7+hemp2+DK+B5/ircd/s_serv_ext.h	Tue May 11 15:25:04 2004
@@ -69,4 +69,10 @@
 #if defined(OPER_DIE) || defined(LOCOP_DIE)
 EXTERN int m_die __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
 #endif /* OPER_DIE || LOCOP_DIE */
+#ifdef SERVER_MAP
+EXTERN int m_map __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+#endif
+#ifdef OPER_SET
+EXTERN int m_set __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+#endif
 #undef EXTERN
diff -Nur irc2.10.3p7/ircd/s_service.c irc2.10.3p7+hemp2+DK+B5/ircd/s_service.c
--- irc2.10.3p7/ircd/s_service.c	Mon May 14 06:12:32 2001
+++ irc2.10.3p7+hemp2+DK+B5/ircd/s_service.c	Tue May 11 15:25:04 2004
@@ -440,10 +440,26 @@
 			    get_client_name(sptr, TRUE));
 		istat.is_unknown--;
 		istat.is_myservice++;
+#ifdef	EXTRA_STATISTICS
+		/*
+		**  Keep track of maximum number of simultanious
+		**  services to this server.
+		*/
+		if (istat.is_myservice > istat.is_m_myservice)
+			istat.is_m_myservice = istat.is_myservice;
+#endif
 	    }
 #endif
 
 	istat.is_service++;
+#ifdef	EXTRA_STATISTICS
+	/*
+	**  Keep track of maximum number of services
+	**  simultaniously connected to this network.
+	*/
+	if (istat.is_service > istat.is_m_service)
+		istat.is_m_service = istat.is_service;
+#endif
 	svc = make_service(sptr);
 	SetService(sptr);
 	svc->servp = sp;
diff -Nur irc2.10.3p7/ircd/s_user.c irc2.10.3p7+hemp2+DK+B5/ircd/s_user.c
--- irc2.10.3p7/ircd/s_user.c	Thu Feb 26 19:00:59 2004
+++ irc2.10.3p7+hemp2+DK+B5/ircd/s_user.c	Tue May 11 15:25:04 2004
@@ -324,6 +324,12 @@
 		    (IsUnixSocket(cptr)) ? me.sockhost :
 		    ((cptr->hostp) ? cptr->hostp->h_name : cptr->sockhost));
 #endif
+#ifdef DELAY_CLOSE
+        if (cptr->user)
+        {
+               cptr->user->flags |= FLAGS_BADBOY;
+        }
+#endif
 	return exit_client(cptr, cptr, &me, longm);
 }
 
@@ -363,6 +369,9 @@
 #ifndef NO_PREFIX
 	char	prefix;
 #endif
+#ifdef	RESTRICT_USERNAMES
+	char	*hptr;
+#endif
 	int	i;
 
 	user->last = timeofday;
@@ -372,7 +381,6 @@
 	if (MyConnect(sptr))
 	    {
 		char *reason = NULL;
-
 #if defined(USE_IAUTH)
 		static time_t last = 0;
 		static u_int count = 0;
@@ -484,12 +492,49 @@
 
 		if (sptr->exitc == EXITC_AREF || sptr->exitc == EXITC_AREFQ)
 		    {
+			char *showres = NULL;
+			if (sptr->reason)
+			{
+				showres = strchr(sptr->reason,' ');
+				if (showres)
+				{
+					*showres = '\0';
+				}
+			}
 			if (sptr->exitc == EXITC_AREF)
-				sendto_flag(SCH_LOCAL,
-					    "Denied connection from %s.",
+			{
+				if (showres)
+				{
+					sendto_flag(SCH_LOCAL,
+					    "Denied connection from %s. (%s)",
+					    get_client_host(sptr),sptr->reason);
+					*showres = ' ';
+				}
+				else
+					sendto_flag(SCH_LOCAL,
+					    "Denied connection from %s. ",
 					    get_client_host(sptr));
-			return ereject_user(cptr, " Denied  ","Denied access");
+
+			}
+			if (showres && !*(showres+1))
+			{
+				showres = NULL;
+			}
+			return ereject_user(cptr, " Denied  ",showres ? showres+1 : "Denied access");
 		    }
+#ifdef DELAY_ACCEPT
+		/* well, this is not exactly the correct place for this
+		 * check, but oh well.. -jv */
+		{
+			aConfItem *bconf;
+			bconf = sptr->acpt->confs->value.aconf;
+			if (bconf->status & CONF_SERVERONLY)
+			{
+				sendto_flag(SCH_LOCAL,"User connection to server-only port from %s",get_client_host(sptr));
+				return ereject_user(cptr, " serveronly ", "This port is avaible for servers only.");
+			}
+		}
+#endif
 		if ((i = check_client(sptr)))
 		    {
 			struct msg_set { char *shortm; char *longm; };
@@ -514,7 +559,6 @@
 			return ereject_user(cptr, exit_msg[i].shortm,
 					    exit_msg[i].longm);
 		    }
-
 #ifndef	NO_PREFIX
 		if (IsRestricted(sptr))
 		    {
@@ -546,10 +590,32 @@
 			return exit_client(cptr, sptr, &me, "Bad Password");
 		    }
 		bzero(sptr->passwd, sizeof(sptr->passwd));
+#ifdef	RESTRICT_USERNAMES
+		/*
+		 * Do not allow special characters in the username.
+		 */
+		hptr = user->username;
+		if (prefix)
+			hptr++;
+		while (*hptr && isvaliduser(*hptr))
+			hptr++;
+		if (*hptr) {
+			ircstp->is_ref++;
+			sendto_flag(SCH_LOCAL, "Invalid username:  %s@%s.",
+				    sptr->user->username, sptr->sockhost);
+			return exit_client(cptr, sptr, &me,
+					   "Invalid username");
+		}
+#endif
 		/*
 		 * following block for the benefit of time-dependent K:-lines
 		 */
-		if (find_kill(sptr, 1, &reason))
+#ifdef ILINE_FLAGS
+		if (!IsKlineExempt(sptr) && find_kill(sptr, &reason))
+
+#else
+		if (find_kill(sptr, &reason))
+#endif
 		    {
 			/*char buf[100];*/
 
@@ -567,21 +633,21 @@
 			return exit_client(cptr, sptr, &me, (reason) ? buf :
 					   "K-lined");
 		    }
-#ifdef R_LINES
-		if (find_restrict(sptr))
-		    {
-			sendto_flag(SCH_LOCAL, "R-lined %s@%s.",
-				    user->username, sptr->sockhost);
-			ircstp->is_ref++;
-			sptr->exitc = EXITC_REF;
-# if defined(FNAME_CONNLOG) || defined(USE_SERVICES) || \
-	(defined(USE_SYSLOG) && defined(SYSLOG_CONN))
-			sendto_flog(sptr, " R lined ", user->username,
-				    user->host);
-# endif
-			return exit_client(cptr, sptr, &me , "R-lined");
-		    }
+
+#ifdef CLIENTS_CHANNEL
+		sendto_flag(SCH_CLIENTS,"Client connecting: %s is %s from %s [%s] named %s",
+				nick,user->username,user->host,
+#ifdef INET6
+                                inetntop(AF_INET6,
+                                         (char *)&sptr->ip,
+                                         mydummy, MYDUMMY_SIZE),
+#else
+                                         inetntoa((char *)&sptr->ip),
+#endif
+				
+				sptr->info);
 #endif
+
 		if (oldstatus == STAT_MASTER && MyConnect(sptr))
 			(void)m_oper(&me, sptr, 1, parv);
 /*		*user->tok = '1';
@@ -629,13 +695,76 @@
 				   (*buf) ? buf : "+", sptr->info);
 	    }	/* for(my-leaf-servers) */
 	if (IsInvisible(sptr))		/* Can be initialized in m_user() */
+	{
 		istat.is_user[1]++;	/* Local and server defaults +i */
+		user->servp->usercnt[1]++;
+	}
 	else
+	{
 		istat.is_user[0]++;
+		user->servp->usercnt[0]++;
+
+	}
+	if (istat.is_user[1] + istat.is_user[0] >= SPLIT_USERS)
+	{
+		check_split();
+	}
+#ifdef	EXTRA_STATISTICS
+	/*
+	**  Keep track of maximum number of global users.
+	*/
+	if ((istat.is_user[1] + istat.is_user[0]) > istat.is_m_users)
+	{
+		istat.is_m_users = istat.is_user[1] + istat.is_user[0];
+		if (timeofday - istat.is_m_users_t >= CLCHSEC)
+		{
+			sendto_flag(SCH_NOTICE,
+				"New highest global client connection: %d",
+				istat.is_m_users);
+			istat.is_m_users_t = timeofday;
+		}
+	}
+	if (user->servp->usercnt[0] + user->servp->usercnt[1] > user->servp->usermax)
+	{
+		user->servp->usermax = user->servp->usercnt[0] + user->servp->usercnt[1];
+	}
+#endif
 	if (MyConnect(sptr))
 	    {
 		istat.is_unknown--;
 		istat.is_myclnt++;
+#ifdef	EXTRA_STATISTICS
+		/*
+		**  Inform of highest client connection.
+		*/
+		if (istat.is_myclnt > istat.is_m_myclnt)
+		{
+			istat.is_m_myclnt = istat.is_myclnt;
+			if (timeofday - istat.is_m_myclnt_t >= CLCHSEC)
+			{
+				sendto_flag(SCH_NOTICE,
+					"New highest local client connection: %d",
+					istat.is_m_myclnt);
+				istat.is_m_myclnt_t = timeofday;
+			}
+		}
+		if ((istat.is_myclnt % CLCHNO) == 0 &&
+			istat.is_myclnt != istat.is_l_myclnt)
+		{
+			if (istat.is_l_myclnt_t == 0)
+				istat.is_l_myclnt_t = me.since;
+
+			sendto_flag(SCH_NOTICE,
+				"Local %screase from %d to %d clients "
+				"in %d seconds",
+				istat.is_myclnt > istat.is_l_myclnt ?
+				"in" : "de", istat.is_l_myclnt,
+				istat.is_myclnt,
+				timeofday - istat.is_l_myclnt_t);
+			istat.is_l_myclnt_t = timeofday;
+			istat.is_l_myclnt = istat.is_myclnt;
+		}
+#endif
 		sprintf(buf, "%s!%s@%s", nick, user->username, user->host);
 		sptr->exitc = EXITC_REG;
 		sendto_one(sptr, rpl_str(RPL_WELCOME, nick), buf);
@@ -645,13 +774,30 @@
 		sendto_one(sptr, rpl_str(RPL_CREATED, nick), creation);
 		sendto_one(sptr, rpl_str(RPL_MYINFO, parv[0]),
 			   ME, version);
+#ifdef SEND_ISUPPORT
+		sendto_one(sptr, rpl_str(RPL_ISUPPORT, parv[0]),
+				isupport);
+#endif
 		(void)m_lusers(sptr, sptr, 1, parv);
 		(void)m_motd(sptr, sptr, 1, parv);
 		if (IsRestricted(sptr))
 			sendto_one(sptr, err_str(ERR_RESTRICTED, nick));
 		send_umode(sptr, sptr, 0, ALL_UMODES, buf);
+#ifdef SPLIT_HANDLE
+		if (iconf.split)
+		{
+			sendto_one(sptr,":%s NOTICE %s :Server is currently in split-mode. You will NOT get channel operator status on new channels.",ME,nick);	
+		}
+#endif
+#ifdef DELAY_ACCEPT		
+		if (iconf.caccept < 2)
+		{
+			sendto_one(sptr,":%s NOTICE %s :Server is currently in delay-accept mode. Users can't connect.",ME,nick);
+		}
+#endif
 		nextping = timeofday;
 	    }
+
 #ifdef	USE_SERVICES
 #if 0
 	check_services_butone(SERVICE_WANT_NICK, user->server, NULL,
@@ -668,6 +814,7 @@
 		send_umode(NULL, sptr, 0, ALL_UMODES, buf);
 	check_services_num(sptr, buf);
 #endif
+	add_to_hostname_hash_table(user->host,user);
 	return 1;
     }
 
@@ -1050,6 +1197,13 @@
 		** on that channel. Propagate notice to other servers.
 		*/
 		sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick);
+#ifdef CLIENTS_CHANNEL
+		if (MyConnect(sptr) && IsRegisteredUser(sptr)) {
+			sendto_flag(SCH_CLIENTS,"Nick change %s to %s for %s from %s",
+			parv[0],nick,sptr->user->username,sptr->user->host);
+		}
+#endif
+
 		if (sptr->user) /* should always be true.. */
 		    {
 			add_history(sptr, sptr);
@@ -1403,7 +1557,7 @@
 				who_one(sptr, lp->value.cptr, chptr, lp);
 			    }
 	    }
-	else if (lp = find_user_link(chptr->members, sptr))
+	else if ((lp = find_user_link(chptr->members, sptr)))
 		who_one(sptr, lp->value.cptr, chptr, lp);
 }
 
@@ -1411,73 +1565,92 @@
 ** who_find
 **	lists all (matching) users.
 **	CPU intensive, but what can be done?
+**	
+**	Reduced CPU load - 05/2001
 */
 static	void	who_find(sptr, mask, oper)
 aClient *sptr;
 char *mask;
 int oper;
 {
-	aChannel *chptr, *ch2ptr;
-	Link	*lp;
-	int	member;
-	int	showperson, isinvis;
-	aClient	*acptr;
-
+	Reg Link	*lp,*lp2;
+	int 		myoper = 0;
+	Reg aClient	*acptr;
+	aChannel 	*chptr = NULL;	
+	if (MyConnect(sptr) && IsAnOper(sptr))
+	{
+		myoper = 1;
+	}
+	
+	/* first, show INvisible matching users on common channels */
+	for (lp = sptr->user->channel; lp ;lp = lp->next)
+	{
+		chptr = lp->value.chptr;
+		if (IsAnonymous(chptr))
+			continue;
+		for (lp2 = chptr->members; lp2 ;lp2 = lp2->next)
+		{
+			acptr = lp2->value.cptr;
+			
+			if (!IsInvisible(acptr) || (acptr->flags & FLAGS_HIDDEN))
+			{
+				continue;
+			}
+			
+			if (oper && !IsAnOper(acptr))
+			{
+				continue;
+			}
+			
+			acptr->flags |= FLAGS_HIDDEN;
+			if (!mask ||
+			     match(mask, acptr->name) == 0 ||
+			     match(mask, acptr->user->username) == 0 ||
+			     match(mask, acptr->user->host) == 0 ||
+			     match(mask, acptr->user->server) == 0 ||
+			     match(mask, acptr->info) == 0)
+				who_one(sptr, acptr, chptr, NULL);
+		
+		}
+	}
+	
+	/* second, show all matching visible clients */
 	for (acptr = client; acptr; acptr = acptr->next)
 	    {
-		ch2ptr = NULL;
 			
 		if (!IsPerson(acptr))
 			continue;
+		
+		/* clear the flag */
+		if (acptr->flags & FLAGS_HIDDEN)
+		{
+			acptr->flags &= ~FLAGS_HIDDEN;
+			continue;
+		}
+		
+		/* allow local opers to see matching clients on _LOCAL_ server */
+		if (IsInvisible(acptr) && !(MyConnect(acptr) && myoper))
+		{
+			continue;
+		}
+		/* we wanted only opers */
 		if (oper && !IsAnOper(acptr))
+		{
 			continue;
-		showperson = 0;
-		/*
-		 * Show user if they are on the same channel, or not
-		 * invisible and on a non secret channel (if any).
-		 * Do this before brute force match on all relevant
-		 * fields since these are less cpu intensive (I
-		 * hope :-) and should provide better/more shortcuts
-		 * -avalon
-		 */
-		isinvis = IsInvisible(acptr);
-		for (lp = acptr->user->channel; lp; lp = lp->next)
-		    {
-			chptr = lp->value.chptr;
-			if (IsAnonymous(chptr))
-				continue;
-			member = IsMember(sptr, chptr);
-			if (isinvis && !member)
-				continue;
-			if (member || (!isinvis && PubChannel(chptr)))
-			    {
-				showperson = 1;
-				if (!IsAnonymous(chptr) ||
-				    acptr != sptr)
-				    {
-					ch2ptr = chptr;
-					break;
-				    }
-			    }
-			if (HiddenChannel(chptr) &&
-			    !SecretChannel(chptr) && !isinvis)
-				showperson = 1;
-		    }
-		if (!acptr->user->channel && !isinvis)
-			showperson = 1;
+		}
+
 		/*
-		** This is brute force solution, not efficient...? ;( 
+		** This is brute force solution, not efficient...? ;(
 		** Show entry, if no mask or any of the fields match
 		** the mask. --msa
 		*/
-		if (showperson &&
-		    (!mask ||
+		if (!mask ||
 		     match(mask, acptr->name) == 0 ||
 		     match(mask, acptr->user->username) == 0 ||
 		     match(mask, acptr->user->host) == 0 ||
 		     match(mask, acptr->user->server) == 0 ||
-		     match(mask, acptr->info) == 0))
-			who_one(sptr, acptr, ch2ptr, NULL);
+		     match(mask, acptr->info) == 0)
+			who_one(sptr, acptr, NULL, NULL);
 	    }
 }
 
@@ -1511,7 +1684,7 @@
 	for (p = NULL, mask = strtoken(&p, parv[1], ",");
 	    mask && penalty <= MAXPENALTY;
 		mask = strtoken(&p, NULL, ","))
-	{ 
+	{
 		channame = NULL;
 		penalty += 1;
 
@@ -1523,12 +1696,11 @@
 		/* I think it's useless --Beeth */
 		clean_channelname(mask);
 #endif
-
 		/* simplify mask */
 		(void)collapse(mask);
 
 		/*
-		** We can never have here !mask 
+		** We can never have here !mask
 		** or *mask == '\0', since it would be equal
 		** to parc == 1, that is 'WHO' and/or would not
 		** pass through above for loop.
@@ -1603,6 +1775,7 @@
 				** All nice chances lost above. 
 				** We must hog our server with that.
 				*/
+				
 				who_find(sptr, mask, oper);
 				penalty += MAXPENALTY;
 			}
@@ -1695,7 +1868,11 @@
 
 	if (acptr->user && MyConnect(acptr))
 		sendto_one(sptr, rpl_str(RPL_WHOISIDLE, sptr->name),
+#ifdef WHOIS_SIGNON_TIME
+			   name, timeofday - user->last,acptr->firsttime);
+#else
 			   name, timeofday - user->last);
+#endif
 }
 
 /*
@@ -2336,10 +2513,35 @@
 	cptr->flags &= ~FLAGS_PINGSENT;
 	sptr->flags &= ~FLAGS_PINGSENT;
 
-	if (!BadPtr(destination) && mycmp(destination, ME) != 0)
+#ifdef SPLIT_HANDLE
+	if (IsServer(cptr) && IsServer(sptr) && (BadPtr(destination) || !match(destination,ME)))
+	{
+		if (IsBurst(sptr))
+		{
+			ClearBurst(sptr);
+			istat.is_eobservers++;
+			if (MyConnect(sptr))
+			{
+				sendto_flag(SCH_NOTICE,"End of burst from %s. Lasted %d seconds.",
+					cptr->name,timeofday - cptr->firsttime);
+			}
+			else
+			{
+				sendto_flag(SCH_DEBUG,"EOB from %s (PONG)",sptr->name);
+			}
+			bubble_eob(sptr);
+			if (iconf.split)
+			{
+				check_split();
+			}
+		}
+	}
+#endif
+	if (!BadPtr(destination) && match(destination, ME) != 0)
 	    {
 		if ((acptr = find_client(destination, NULL)) ||
-		    (acptr = find_server(destination, NULL))) {
+		    (acptr = find_server(destination, NULL))) 
+		{
 			if (!(MyClient(sptr) && mycmp(origin, sptr->name)))
 				sendto_one(acptr,":%s PONG %s %s",
 					   parv[0], origin, destination);
@@ -2508,12 +2710,60 @@
 				      parv[0], IsOper(sptr) ? 'o' : 'O');
 #endif
 		if (IsAnOper(sptr))
+		{
 			istat.is_oper++;
+			sptr->user->servp->usercnt[2]++;
+		}
 	    }
 	else
 	    {
 		(void)detach_conf(sptr, aconf);
 		sendto_one(sptr,err_str(ERR_PASSWDMISMATCH, parv[0]));
+#ifdef FAILED_OPERLOG
+              sendto_flag(SCH_NOTICE, "FAILED OPER %s attempt by %s!%s@%s",
+                          name, parv[0], sptr->user->username, sptr->user->host);
+#     if defined(USE_SYSLOG) && defined(SYSLOG_OPER)
+              syslog(LOG_INFO, "FAILED OPER %s attempt by %s!%s@%s [%s@%s]",
+                          name, parv[0], sptr->user->username, sptr->user->host,
+                          sptr->auth, IsUnixSocket(sptr) ?  sptr->sockhost :
+#ifdef INET6
+                          inet_ntop(AF_INET6, (char *)&sptr->ip, mydummy, MYDUMMY_SIZE));
+#else
+
+                          inetntoa((char *)&sptr->ip));
+#endif
+#     endif
+#     ifdef FNAME_OPERLOG
+            {
+              int     logfile;
+
+              (void)alarm(3);
+              if (IsPerson(sptr) &&
+                  (logfile = open(FNAME_OPERLOG, O_WRONLY|O_APPEND)) != -1)
+              {
+                (void)alarm(0);
+                SPRINTF(buf, "%s FAILED OPER %s attempt by %s!%s@%s [%s@%s]\n",
+                         myctime(timeofday), name, parv[0], sptr->user->username,
+                         sptr->user->host, sptr->auth, IsUnixSocket(sptr) ?
+                         sptr->sockhost :
+#ifdef INET6
+                         inetntop(AF_INET6, (char *)&sptr->ip, mydummy,
+                                  MYDUMMY_SIZE)
+
+#else
+                         inetntoa((char *)&sptr->ip)
+#endif
+			 );
+              (void)alarm(3);
+              (void)write(logfile, buf, strlen(buf));
+              (void)alarm(0);
+              (void)close(logfile);
+         }
+         (void)alarm(0);
+           }
+#     endif
+#endif
+
 	    }
 	return 3;
     }
@@ -2834,11 +3084,15 @@
 		    {
 			istat.is_user[1]--;
 			istat.is_user[0]++;
+			sptr->user->servp->usercnt[1]--;
+			sptr->user->servp->usercnt[0]++;
 		    }
 		if (IsInvisible(sptr) && !(setflags & FLAGS_INVISIBLE))
 		    {
 			istat.is_user[1]++;
 			istat.is_user[0]--;
+			sptr->user->servp->usercnt[1]++;
+			sptr->user->servp->usercnt[0]--;
 		    }
 		send_umode_out(cptr, sptr, setflags);
 	    }
@@ -2847,6 +3101,7 @@
 	if (IsOper(sptr) && !(setflags & FLAGS_OPER))
 	    {
 		istat.is_oper++;
+		sptr->user->servp->usercnt[2]++;
 #ifdef	USE_SERVICES
 		check_services_butone(SERVICE_WANT_OPER, sptr->user->server, 
 				      sptr, ":%s MODE %s :+o", parv[0],
@@ -2856,6 +3111,7 @@
 	else if (!IsOper(sptr) && (setflags & FLAGS_OPER))
 	    {
 		istat.is_oper--;
+		sptr->user->servp->usercnt[2]--;
 #ifdef	USE_SERVICES
 		check_services_butone(SERVICE_WANT_OPER, sptr->user->server,
 				      sptr, ":%s MODE %s :-o", parv[0],
@@ -2865,6 +3121,7 @@
 	else if (MyConnect(sptr) && !IsLocOp(sptr) && (setflags & FLAGS_LOCOP))
 	    {
 		istat.is_oper--;
+		sptr->user->servp->usercnt[2]--;
 #ifdef USE_SERVICES
 		check_services_butone(SERVICE_WANT_OPER, sptr->user->server,
 				      sptr, ":%s MODE %s :-O", parv[0],     
diff -Nur irc2.10.3p7/ircd/version.c.SH.in irc2.10.3p7+hemp2+DK+B5/ircd/version.c.SH.in
--- irc2.10.3p7/ircd/version.c.SH.in	Thu Jul 22 00:59:54 1999
+++ irc2.10.3p7+hemp2+DK+B5/ircd/version.c.SH.in	Tue May 11 15:25:04 2004
@@ -63,6 +63,7 @@
 char *generation = "$generation";
 char *creation = "$creation";
 char *version;				/* Filled by make_version() */
+char *isupport;			/* Filled by make_isupport() */
 char *pass_version = PATCHLEVEL;
 
 char *infotext[] =
@@ -108,6 +109,9 @@
 	"",
 	"[$sumsserv] [$sumchan] [$sumsbsd] [$sumsuser]",
 	"[$sumhash] [$sumsmisc] [$sumircd]",
+	"",
+	"This server has been patched by hemp2 patch, revision 2004022701.",
+	"See http://jv.irc.cz/irc/ for more information about this patch.",
 	0,
     };
 !SUB!THIS!
diff -Nur irc2.10.3p7/ircd/version_ext.h irc2.10.3p7+hemp2+DK+B5/ircd/version_ext.h
--- irc2.10.3p7/ircd/version_ext.h	Wed Sep  3 19:46:08 1997
+++ irc2.10.3p7+hemp2+DK+B5/ircd/version_ext.h	Tue May 11 15:25:04 2004
@@ -27,6 +27,7 @@
 extern char *generation;
 extern char *creation;
 extern char *version;
+extern char *isupport;
 extern char *pass_version;
 extern char *infotext[];
 #endif /* VERSION_C */
diff -Nur irc2.10.3p7/support/Makefile.in irc2.10.3p7+hemp2+DK+B5/support/Makefile.in
--- irc2.10.3p7/support/Makefile.in	Fri Feb  9 14:47:07 2001
+++ irc2.10.3p7+hemp2+DK+B5/support/Makefile.in	Tue May 11 15:25:04 2004
@@ -104,6 +104,8 @@
 IRCDPID_PATH = $(ircd_var_dir)/ircd.pid
 # server state file
 IRCDTUNE_PATH = $(ircd_var_dir)/ircd.tune
+# iauth PID file
+IAUTHPID_PATH = $(ircd_var_dir)/iauth.pid
 # ircdwatch PID file
 IRCDWATCHPID_PATH = $(ircd_var_dir)/ircdwatch.pid
 
@@ -157,7 +159,7 @@
 
 IAUTH_COMMON_OBJS = clsupport.o clmatch.o # This is a little evil
 IAUTH_OBJS = iauth.o a_conf.o a_io.o a_log.o \
-             mod_lhex.o mod_pipe.o mod_rfc931.o mod_socks.o
+             mod_lhex.o mod_pipe.o mod_rfc931.o mod_socks.o mod_webproxy.o mod_dnsbl.o
 IAUTH = iauth
 
 CHKCONF_COMMON_OBJS = match.o
@@ -408,7 +410,8 @@
 	$(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_id.c
 
 s_misc.o: ../ircd/s_misc.c setup.h config.h
-	$(CC) $(S_CFLAGS) -DFNAME_USERLOG="\"$(FNAME_USERLOG)\"" -DFNAME_CONNLOG="\"$(FNAME_CONNLOG)\"" -c -o $@ ../ircd/s_misc.c
+	$(CC) $(S_CFLAGS) -DFNAME_USERLOG="\"$(FNAME_USERLOG)\"" \
+	-DIRCDCONF_PATH="\"$(IRCDCONF_PATH)\"" -DFNAME_CONNLOG="\"$(FNAME_CONNLOG)\"" -c -o $@ ../ircd/s_misc.c
 
 s_numeric.o: ../ircd/s_numeric.c setup.h config.h
 	$(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_numeric.c
@@ -438,7 +441,7 @@
 	$(CC) $(S_CFLAGS) -c -o $@ ../ircd/res_mkquery.c
 
 iauth.o: ../iauth/iauth.c config.h setup.h
-	$(CC) $(A_CFLAGS) -c -o $@ ../iauth/iauth.c
+	$(CC) $(A_CFLAGS) -DIAUTHPID_PATH="\"$(IAUTHPID_PATH)\"" -c -o $@ ../iauth/iauth.c
 
 a_conf.o: ../iauth/a_conf.c config.h setup.h
 	$(CC) $(A_CFLAGS) -DIAUTHCONF_PATH="\"$(IAUTHCONF_PATH)\"" -c -o $@ ../iauth/a_conf.c
@@ -463,6 +466,12 @@
 
 mod_socks.o: ../iauth/mod_socks.c config.h setup.h
 	$(CC) $(A_CFLAGS) -c -o $@ ../iauth/mod_socks.c
+
+mod_dnsbl.o: ../iauth/mod_dnsbl.c config.h setup.h
+	$(CC) $(A_CFLAGS) -c -o $@ ../iauth/mod_dnsbl.c
+
+mod_webproxy.o: ../iauth/mod_webproxy.c config.h setup.h
+	$(CC) $(A_CFLAGS) -c -o $@ ../iauth/mod_webproxy.c -Wall
 
 chkconf.o: ../ircd/chkconf.c setup.h config.h
 	$(CC) $(CC_CFLAGS) -DCHKCONF_COMPILE -DIRCDCONF_PATH="\"$(IRCDCONF_PATH)\"" -DIRCDM4_PATH="\"$(IRCDM4_PATH)\"" -c -o $@ ../ircd/chkconf.c
diff -Nur irc2.10.3p7/support/config.h.dist irc2.10.3p7+hemp2+DK+B5/support/config.h.dist
--- irc2.10.3p7/support/config.h.dist	Sun May  9 21:20:10 2004
+++ irc2.10.3p7+hemp2+DK+B5/support/config.h.dist	Tue May 11 15:32:18 2004
@@ -118,11 +118,11 @@
  * if 'OPER_x' is undefined so you can't give local operators more rights
  * than global ones.
  */
-#undef	OPER_KILL
+#define	OPER_KILL
 #define	OPER_REHASH
 #undef	OPER_RESTART
-#define	OPER_DIE
-#undef	OPER_REMOTE
+#undef	OPER_DIE
+#define	OPER_REMOTE
 #undef	LOCOP_REHASH
 #undef	LOCOP_RESTART
 #undef	LOCOP_DIE
@@ -138,7 +138,7 @@
  * This should be at *least* 4: 2 listen ports (1 tcp, 1 udp)
  *				1 dns port, 1 client
  */
-#define MAXCONNECTIONS	50
+#define MAXCONNECTIONS	16000
 
 /* MAXIMUM LINKS
  *
@@ -189,39 +189,6 @@
 #endif
 
 /*
- * If you want to use timed klines, set it to frequence in seconds,
- * how often to check if client is to be removed; usually 60 seconds
- * (smallest granularity you can get in K:line anyway).
- *
- * Advised not to use it ;-) --Beeth
- */
-#undef TIMEDKLINES
-
-/* R_LINES:  The conf file now allows the existence of R lines, or
- * restrict lines.  These allow more freedom in the ability to restrict
- * who is to sign on and when.  What the R line does is call an outside
- * program which returns a reply indicating whether to let the person on.
- * Because there is another program involved, Delays and overhead could
- * result. It is for this reason that there is a line in config.h to
- * decide whether it is something you want or need. -Hoppie
- *
- * The default is no R_LINES as most people probably don't need it. --Jto
- */
-#undef	R_LINES
-
-#ifdef	R_LINES
-/* Also, even if you have R lines defined, you might not want them to be 
-   checked everywhere, since it could cost lots of time and delay.  Therefore, 
-   The following two options are also offered:  R_LINES_REHASH rechecks for 
-   R lines after a rehash, and R_LINES_OFTEN, which rechecks it as often
-   as it does K lines.  Note that R_LINES_OFTEN is *very* likely to cause 
-   a resource drain, use at your own risk.  R_LINES_REHASH shouldn't be too
-   bad, assuming the programs are fairly short. */
-#define R_LINES_REHASH
-#define R_LINES_OFTEN
-#endif
-
-/*
  * NOTE: defining CMDLINE_CONFIG and installing ircd SUID or SGID is a MAJOR
  *       security problem - they can use the "-f" option to read any files
  *       that the 'new' access lets them. Note also that defining this is
@@ -271,7 +238,7 @@
  * define this if you want to use crypted passwords for operators in your
  * ircd.conf file. See contrib/mkpasswd/README for more details on this.
  */
-#undef	CRYPT_OPER_PASSWORD
+#define	CRYPT_OPER_PASSWORD
 
 /*
  * If you want to store encrypted passwords in N-lines for server links,
@@ -323,7 +290,7 @@
  * send to the server without processing before disconnecting the client for
  * flooding it.  Values greater than 8000 make no difference to the server.
  */
-#define	CLIENT_FLOOD	1000
+#define	CLIENT_FLOOD	2048
 
 /* Remote query flood protection. */
 #define	CHREPLLEN	8192
@@ -339,6 +306,7 @@
  */
 #undef USE_SERVICES
 
+
 /*
  * Define the following to make the delay for nicks random.
  * Some people believe a bot can exactly time the delay and don't like it,
@@ -361,7 +329,7 @@
  * The library and the include files must have been found by configure,
  * if you have installed the zlib after running configure, run it again.
  */
-#undef ZIP_LINKS
+#define ZIP_LINKS
 
 /*
  * Defining this will add an artificial 2 seconds delay for accepting
@@ -389,6 +357,190 @@
  */
 #define SIXBONE_HACK
 
+/*
+ * Disclaimer: The following part concerns the Cr-patches. By defining this
+ *             you will end up with "no warranty" whatsoever - use at your
+ *             own risk.
+ *             The Cr patch does not compromize the anonymity and does
+ *             not affect users integrity in any way. The new features will
+ *             only provide extra functionality and statistics for local
+ *             IRC operators.
+ */
+#define RESTRICT_USERNAMES
+
+/*
+ * Define this if you want to allow online K-lining (permanent) for
+ * regular and local operators.
+ */
+#undef	OPER_KLINE
+#undef	LOCOP_KLINE
+
+/*
+ * Define this if you want to allow online K-lining to memory only
+ * which is removed after rehashing the configuration file or by
+ * restarting the server.
+ */
+#undef	OPER_TKLINE
+#undef	LOCOP_TKLINE
+
+/*
+ * Define this if you want (t)kline requests to go to syslog
+ * Note that you must also have USE_SYSLOG defined otherwise
+ * it won't work
+ * this is a part of patch f2 by fantomas
+ */
+#undef SYSLOG_KLINE
+
+/*
+ * This will give some extra statistics, such as highest usercount,
+ * connection duration and local client incrementation.
+ *
+ * Note: will also show local/global max in /lusers - jv
+ */
+#define	EXTRA_STATISTICS
+
+/* CrXXe8 related stuff follows. It makes the TKLINE/KLINE servernotice
+ * show the k-linereason too and does two cosmetical corrections to the
+ * "Local increase..." and the RPL_YOUREOPER servernotices. Also it
+ * doesn't suppress iauth statistics for opers using stats t.
+ *
+ * Define this to show and log failed /oper attempts too!
+ * Define LOG_IP for logging [ident@remoteip#remoteport,localip#localport].
+ */
+
+#define FAILED_OPERLOG
+#define LOG_IP
+
+/* Fl4 related stuff follows - so far, the only stuff retained from Fl3c
+ * for Fl4 is the &clients channel ; this is because the TKLINE/KLINE code
+ * from Fl3c is also present in the Cr15 code.
+ */
+
+/* define this to enable an extra local channel '&clients', which only
+ * IRC operators may join. Notification of nick-changes, connects, exits,
+ * and requests for server statistics will be sent to this channel.
+ * Some people regard this as a breach of privacy, hence (unlike Fl3c)
+ * it is turned off by default.
+ * f2 - easy clients merged - jv
+ */
+#undef CLIENTS_CHANNEL
+
+
+
+/*
+ * Define this to see when a channel topic was set and who it was set by.
+ */
+#define TOPICWHOTIME
+
+/*
+ * Define this if you want msgs normally sent to &local moved to &notices
+ * - EXCEPT unauth/rejection/too many connection notices. The reasoning
+ * behind this is if you want to see local information except the annoying
+ * and resource wasting unauths and rejections..
+ */
+#define        LOCAL_REJECTIONS_ONLY
+
+
+/* +jv patch defines follows */
+
+/* New stats - F show FDs and remote&local ports (local oper only)
+ */
+#define STATS_F
+
+/* show signon time of local clients in whois */
+#define WHOIS_SIGNON_TIME
+
+/* no RPL_TRYAGAIN for opers - i think it's right and doesn't add 
+ * privileges for opers, just allows them to administrate net better.
+ */
+#define NO_OPER_TRYAGAIN
+/* If you want to notify users that doing /LIST is bad and they should
+   use ALIS instead, define this. Notice is sent BEFORE any output.
+ */
+ 
+#define LIST_ALIS_NOTE "Usage of /list for listing all channels is deprecated. Please use \"/squery alis help\" instead."
+
+/* If you want to send server IS_SUPPORT upon connect and along with
+   VERSION reply. Also moves redirect numerics from 5 to 10.
+   also define Networkname.
+ */
+#define SEND_ISUPPORT
+#define NETWORKNAME "IRCnet"
+
+/* support for /MAP a'la ircu. */
+#define SERVER_MAP
+
+/* quick info about connected servers */
+#define STATS_QMARK
+
+/* define if you want to set some values - delay accept mode, disable/enable autoconnects */
+#define OPER_SET
+
+/* wait with closing sockets of rejected clients, in seconds  */
+#define DELAY_CLOSE
+#define DELAYCLOSETIME 16
+
+/* Split handling - replaces QPI
+ * works as follows:
+ * PINGs all servers behind the link and waits for PONG.
+ * Note: Currently does not compile when undefined. To disable split
+ * 	 protection set following values to 0.
+ */
+#define SPLIT_HANDLE
+
+/* defines minimum for GLOBAL channels */
+#define SPLIT_SERV  20
+#define SPLIT_USERS 40000
+
+/* Delay binding to listening ports with 'D' in second field until server 
+ * is out of split.
+ * Requires SPLIT_HANDLE defined
+ */
+#define DELAY_ACCEPT
+
+/* I-line flags. Allows to specify aditional flags at the beginning of
+ * name field. 
+ * current meaning:
+ *   <  exempted from k-lines
+ *   +  restrict client if no reverse dns found.
+ */
+#define ILINE_FLAGS
+
+/*
+ * Undefining this enables old portions of code, which are more precise
+ * in local u@h limit checking by comparing user's ip against all other
+ * users on server. Usable only for case when client creates another
+ * connection from same ip, but with changed hostname.
+ * This check won't be needed on pure 2.11 network.
+ * Note: He can connect to other server without any problem.
+ *
+ */
+#define NO_EXTENSIVE_LOCAL_LIMIT_CHECK
+
+/* define file which is used for saving k-lines added by /kline
+ */
+#undef KLINE_FILE IRCDCONF_PATH
+
+/* undef if you don't want to have Denied connection  because of open proxy */
+#undef IAUTH_VERBOSE_REJECTS
+
+/* end of +jv patch */
+
+/* 
+** Servers with many clients and lots of K:lines are having noticable
+** lag after rehash. Define this to lessen the load and check only this
+** number of clients at a time. (All clients will be checked, of course.)
+** Undefine (or define to bigger than MAXCONNECTIONS) to check all clients
+** in one sweep.
+*/
+#define MAXDELAYEDKILLS 200
+
+/*
+** You may want to define this to disable "STATS k" for plain users
+** and redirect them to some WWW page.
+*/
+#define NOSTATSK "Please use http://www.irc.pl/kline instead."
+
 /*   STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP  */
 /*   STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP  */
 /*   STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP  */
@@ -403,18 +555,20 @@
  * server the Operator is connected to (ie lets them deal with local
  * problem users or 'ghost' clients
  */
-#define	LOCAL_KILL_ONLY
+#undef	LOCAL_KILL_ONLY
 #endif
 
 /* Default server port, used by client. */
 #define	PORTNUM	6667
 
 /* Maximum length the queue of pending connections to one port may grow to. */ 
-#define LISTENQUEUE 128
+#define LISTENQUEUE 1024
 
 /* define DEBUGMODE to enable debugging mode.*/
 #undef	DEBUGMODE
 
+/* log ircname to logfile */
+#undef LOG_IRCNAME
 /*
  * Time interval to wait and if no messages have been received, then check for
  * PINGFREQUENCY and CONNECTFREQUENCY 
@@ -484,7 +638,7 @@
 /*
  * Max number of channels a user is allowed to join.
  */
-#define MAXCHANNELSPERUSER  10	/* Recommended value: 10 */
+#define MAXCHANNELSPERUSER  21	/* Recommended value: 10 */
 
 /*
  * USE_IAUTH makes ircd use the iauth program for authentication.
@@ -519,6 +673,7 @@
 /* #undef	NO_IDENT */
 /* #undef	NO_PREFIX */
 
+
 /* ------------------------- END CONFIGURATION SECTION -------------------- */
 #ifndef ENABLE_SUMMON
 #  undef LEAST_IDLE
@@ -586,20 +741,6 @@
 #endif
 
 /*
-** Make sure TIMEDKLINES is defined along with R_LINES_OFTEN
-**
-*/
-#if defined(R_LINES_OFTEN) && !defined(TIMEDKLINES)
-error TIMEDKLINES must be defined for R_LINES_OFTEN to work (are you sure you need them?)
-#endif
-
-#if defined(TIMEDKLINES)
-# if (TIMEDKLINES + 0 < 60)
-#  error TIMEDKLINES must be bigger than 60 seconds
-# endif
-#endif
-
-/*
 ** You should not want to change this. ;)
 */
 #define	NOWRITEALARM	1
@@ -609,4 +750,20 @@
 ** Conformance of the internal resolver to RFC1123.
 */
 #define	RESTRICT_HOSTNAMES	1
+
+#if defined(DELAY_ACCEPT) && !defined(SPLIT_HANDLE)
+error DELAY_ACCEPT requires SPLIT_HANDLE defined.
+#endif
+
+# if (MAXCONNECTIONS <= 200)
+  #define CLCHNO 10
+# else
+  # if (MAXCONNECTIONS <= 1000)
+     #define CLCHNO 50
+  # else
+     #define CLCHNO 100
+  # endif
+# endif
+
+#define CLCHSEC 30
 
diff -Nur irc2.10.3p7/support/iauth.conf irc2.10.3p7+hemp2+DK+B5/support/iauth.conf
--- irc2.10.3p7/support/iauth.conf	Mon Jul  5 00:15:43 1999
+++ irc2.10.3p7+hemp2+DK+B5/support/iauth.conf	Tue May 11 15:25:05 2004
@@ -6,13 +6,27 @@
 
 # If iauth timeouts, then reject user
 notimeout
+
 # This makes the IRC server require that iauth performs the authentication
 # in order for a new user connection to be accepted
 required
 
 # Perform ident lookups
 module rfc931
+	timeout = 16
+# Check and reject hosts in named DNSBL
+#module dnsbl
+#	option = reject,log,list=klines.dnsbl.irc.pl
+#	timeout = 8
+#	reason = See www.irc.pl/proxy-klines
 
 # Check and reject open SOCKS proxies
-#module socks
-#	option = reject,paranoid
+module socks
+	option = reject,paranoid
+	timeout = 16
+#	reason = See www.irc.pl/proxy-socks
+
+module webproxy
+	option = log,reject,ports=3128;8080
+	timeout = 24
+#	reason = See www.irc.pl/proxy-web
diff -Nur irc2.10.3p7/support/tkconf.h.dist irc2.10.3p7+hemp2+DK+B5/support/tkconf.h.dist
--- irc2.10.3p7/support/tkconf.h.dist	Sun Feb 21 01:33:47 1999
+++ irc2.10.3p7+hemp2+DK+B5/support/tkconf.h.dist	Tue May 11 15:25:05 2004
@@ -28,8 +28,8 @@
 #undef TKSERV_DEBUG
 
 /* The name of the ircd config file backup (suffix after CPATH) */
-#define TKSERV_IRCD_CONFIG_BAK 	CPATH".tkserv"
+#define TKSERV_IRCD_CONFIG_BAK 	TKSERV_IRCD_CONF".tkserv"
 
 /* The name of the ircd temp config file (suffix after CPATH) */
-#define TKSERV_IRCD_CONFIG_TMP	CPATH".tmp"
+#define TKSERV_IRCD_CONFIG_TMP	TKSERV_IRCD_CONF".tmp"
 
