diff -urN irc2.10.3p7/common/common_def.h irc2.10.3p7+hemp2/common/common_def.h
--- irc2.10.3p7/common/common_def.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/common/common_def.h	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/common/match.c irc2.10.3p7+hemp2/common/match.c
--- irc2.10.3p7/common/match.c	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/common/match.c	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/common/msg_def.h irc2.10.3p7+hemp2/common/msg_def.h
--- irc2.10.3p7/common/msg_def.h	2004-03-09 17:22:51.000000000 +0900
+++ irc2.10.3p7+hemp2/common/msg_def.h	2004-03-09 17:53:06.000000000 +0900
@@ -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,11 @@
 #define	MSG_HASH     "HAZH"	/* HASH */
 #define	MSG_DNS      "DNS"	/* DNS  -> DNSS */
 #define	MSG_POST     "POST"
+#ifdef SERVER_MAP
+#define MSG_MAP      "MAP"	/* MAP */
+#endif
+#ifdef OPER_SET
+#define MSG_SET      "SET"	/* SET */
+#endif
 
 #define MAXPARA    15 
diff -urN irc2.10.3p7/common/numeric_def.h irc2.10.3p7+hemp2/common/numeric_def.h
--- irc2.10.3p7/common/numeric_def.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/common/numeric_def.h	2004-03-09 17:29:27.000000000 +0900
@@ -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.
@@ -232,6 +242,7 @@
 
 #define RPL_NOTOPIC          331
 #define RPL_TOPIC            332
+#define RPL_TOPICWHOTIME     333
 
 #define RPL_INVITING         341
 #define	RPL_SUMMONING        342
@@ -299,7 +310,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 +346,5 @@
 #define	RPL_TRACEEND         262
 #define	RPL_TRYAGAIN         263
 
+#define RPL_LOCALUSERS       265
+#define RPL_GLOBALUSERS      266
diff -urN irc2.10.3p7/common/parse.c irc2.10.3p7+hemp2/common/parse.c
--- irc2.10.3p7/common/parse.c	2004-03-09 17:46:34.000000000 +0900
+++ irc2.10.3p7+hemp2/common/parse.c	2004-03-09 17:53:06.000000000 +0900
@@ -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 -urN irc2.10.3p7/common/parse_ext.h irc2.10.3p7+hemp2/common/parse_ext.h
--- irc2.10.3p7/common/parse_ext.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/common/parse_ext.h	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/common/send.c irc2.10.3p7+hemp2/common/send.c
--- irc2.10.3p7/common/send.c	2004-03-09 17:22:01.000000000 +0900
+++ irc2.10.3p7+hemp2/common/send.c	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/common/struct_def.h irc2.10.3p7+hemp2/common/struct_def.h
--- irc2.10.3p7/common/struct_def.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/common/struct_def.h	2004-03-09 17:29:27.000000000 +0900
@@ -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
@@ -307,7 +335,6 @@
 				 CONF_SERVER_MASK)
 
 #define	IsIllegal(x)	((x)->status & CONF_ILLEGAL)
-
 typedef	struct	{
 	u_long	pi_id;
 	u_long	pi_seq;
@@ -345,7 +372,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 +395,8 @@
 	char	username[USERLEN+1];
 	char	host[HOSTLEN+1];
 	char	*server;
+	struct User *hnext;	
+	int 	hashv;		
 };
 
 struct	Server	{
@@ -382,6 +411,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 +422,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 +485,7 @@
 				  ** accepted.
 				  */
 	char	passwd[PASSWDLEN+1];
+	char	*reason;	/* internal quit reason */
 	char	exitc;
 };
 
@@ -531,6 +566,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 +608,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 +629,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 +737,16 @@
 				  x->prev->service->servp == x->serv)))
 
 typedef	struct	{
+#ifdef	EXTRA_STATISTICS
+	time_t	is_last_cnt_t;	/* timestamp for last count */
+	u_long	is_last_cnt;	/* last count */
+	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)
diff -urN irc2.10.3p7/common/support.c irc2.10.3p7+hemp2/common/support.c
--- irc2.10.3p7/common/support.c	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/common/support.c	2004-03-09 17:29:27.000000000 +0900
@@ -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,30 @@
 		sprintf(ver + strlen(ver), "%c%d", DEVLEVEL, dv);
 	if (pl)	/* patchlevel */
 		sprintf(ver + strlen(ver), "p%d", pl);
+	strcat(ver,"+hemp2");
 	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 -urN irc2.10.3p7/common/support_ext.h irc2.10.3p7+hemp2/common/support_ext.h
--- irc2.10.3p7/common/support_ext.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/common/support_ext.h	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/iauth/a_conf.c irc2.10.3p7+hemp2/iauth/a_conf.c
--- irc2.10.3p7/iauth/a_conf.c	2004-03-09 17:22:01.000000000 +0900
+++ irc2.10.3p7+hemp2/iauth/a_conf.c	2004-03-09 17:29:27.000000000 +0900
@@ -26,6 +26,7 @@
 #define A_CONF_C
 #include "a_externs.h"
 #undef A_CONF_C
+#undef USE_DSM
 
 static aModule *Mlist[16];
 
@@ -87,6 +88,7 @@
 
 	Mlist[Mcnt++] = &Module_rfc931;
 	Mlist[Mcnt++] = &Module_socks;
+	Mlist[Mcnt++] = &Module_webproxy;
 	Mlist[Mcnt++] = &Module_pipe;
 	Mlist[Mcnt++] = &Module_lhex;
 	Mlist[Mcnt] = NULL;
@@ -248,6 +250,7 @@
 			(*last)->hostname = NULL;
 			(*last)->address = NULL;
 			(*last)->timeout = timeout;
+			(*last)->reason = NULL;
 			if (Mlist[i] == &Module_rfc931)
 				ident = *last;
 
@@ -291,6 +294,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;
diff -urN irc2.10.3p7/iauth/a_conf_def.h irc2.10.3p7+hemp2/iauth/a_conf_def.h
--- irc2.10.3p7/iauth/a_conf_def.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/iauth/a_conf_def.h	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/iauth/a_externs.h irc2.10.3p7+hemp2/iauth/a_externs.h
--- irc2.10.3p7/iauth/a_externs.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/iauth/a_externs.h	2004-03-09 17:29:27.000000000 +0900
@@ -30,5 +30,6 @@
 
 #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"
diff -urN irc2.10.3p7/iauth/a_log_def.h irc2.10.3p7+hemp2/iauth/a_log_def.h
--- irc2.10.3p7/iauth/a_log_def.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/iauth/a_log_def.h	2004-03-09 17:29:27.000000000 +0900
@@ -37,5 +37,7 @@
 #define	ALOG_DSOCKSC	0x040000	/* debug: module socks cache */
 #define	ALOG_DPIPE	0x080000	/* debug: module pipe */
 #define	ALOG_DLHEX	0x100000	/* debug: module pipe */
+#define	ALOG_DWEBPROXY 0x200000 /* debug: module webproxy */
+#define	ALOG_DWEBPROXYC 0x400000 /* debug: module webproxy */
 
-#define	ALOG_DALL	0x1F3700	/* any debug flag */
+#define	ALOG_DALL	0x7F3700	/* any debug flag */
diff -urN irc2.10.3p7/iauth/iauth.c irc2.10.3p7+hemp2/iauth/iauth.c
--- irc2.10.3p7/iauth/iauth.c	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/iauth/iauth.c	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/iauth/mod_socks.c irc2.10.3p7+hemp2/iauth/mod_socks.c
--- irc2.10.3p7/iauth/mod_socks.c	2004-03-09 17:22:26.000000000 +0900
+++ irc2.10.3p7+hemp2/iauth/mod_socks.c	2004-03-09 17:37:13.000000000 +0900
@@ -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 -urN irc2.10.3p7/iauth/mod_webproxy.c irc2.10.3p7+hemp2/iauth/mod_webproxy.c
--- irc2.10.3p7/iauth/mod_webproxy.c	1970-01-01 09:00:00.000000000 +0900
+++ irc2.10.3p7+hemp2/iauth/mod_webproxy.c	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/iauth/mod_webproxy_ext.h irc2.10.3p7+hemp2/iauth/mod_webproxy_ext.h
--- irc2.10.3p7/iauth/mod_webproxy_ext.h	1970-01-01 09:00:00.000000000 +0900
+++ irc2.10.3p7+hemp2/iauth/mod_webproxy_ext.h	2004-03-09 17:29:27.000000000 +0900
@@ -0,0 +1,3 @@
+#ifndef MOD_WEBPROXY_C
+extern aModule Module_webproxy;
+#endif /* MOD_WEBPROXY_C */
diff -urN irc2.10.3p7/ircd/channel.c irc2.10.3p7+hemp2/ircd/channel.c
--- irc2.10.3p7/ircd/channel.c	2004-03-09 17:22:51.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/channel.c	2004-03-09 17:53:06.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/channel_def.h irc2.10.3p7+hemp2/ircd/channel_def.h
--- irc2.10.3p7/ircd/channel_def.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/channel_def.h	2004-03-09 17:29:27.000000000 +0900
@@ -25,5 +25,3 @@
 #define NullChn	((aChannel *)0)
 
 #define ChannelExists(n)	(find_channel(n, NullChn) != NullChn)
-
-#define	MAXMODEPARAMS	3
diff -urN irc2.10.3p7/ircd/channel_ext.h irc2.10.3p7+hemp2/ircd/channel_ext.h
--- irc2.10.3p7/ircd/channel_ext.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/channel_ext.h	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/hash.c irc2.10.3p7+hemp2/ircd/hash.c
--- irc2.10.3p7/ircd/hash.c	2004-03-09 17:22:01.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/hash.c	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/hash_def.h irc2.10.3p7+hemp2/ircd/hash_def.h
--- irc2.10.3p7/ircd/hash_def.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/hash_def.h	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/hash_ext.h irc2.10.3p7+hemp2/ircd/hash_ext.h
--- irc2.10.3p7/ircd/hash_ext.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/hash_ext.h	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/ircd.c irc2.10.3p7+hemp2/ircd/ircd.c
--- irc2.10.3p7/ircd/ircd.c	2004-05-10 13:25:26.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/ircd.c	2004-05-10 16:03:38.000000000 +0900
@@ -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,6 +354,147 @@
 			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, 1, &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
 
 
 static	time_t	check_pings(currenttime)
@@ -360,7 +512,6 @@
 		if (!(cptr = local[i]) || IsListening(cptr) || IsLog(cptr) ||
 		    IsHeld(cptr))
 			continue;
-
 		/*
 		 * K and R lines once per minute, max.  This is the max.
 		 * granularity in K-lines anyway (with time field).
@@ -371,7 +522,11 @@
 #endif /* TIMEDKLINES */
 			rehashed)
 		    {
-			if (IsPerson(cptr))
+			if (IsPerson(cptr)
+#ifdef ILINE_FLAGS
+			&& !IsKlineExempt(cptr)
+#endif
+					)
 			    {
 				kflag = find_kill(cptr, rehashed, &reason);
 #ifdef R_LINES_OFTEN
@@ -686,7 +841,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 +1071,7 @@
 		if (!find_me())
 			exit(-1);
 	    }
-
+	initialconf = 0;
 	dbuf_init();
 	setup_me(&me);
 	check_class();
@@ -990,7 +1147,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
@@ -1072,6 +1233,19 @@
 		rehashed = 0;
 	    }
 
+#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");
 	if (dorehash)
diff -urN irc2.10.3p7/ircd/ircd_ext.h irc2.10.3p7+hemp2/ircd/ircd_ext.h
--- irc2.10.3p7/ircd/ircd_ext.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/ircd_ext.h	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/list.c irc2.10.3p7+hemp2/ircd/list.c
--- irc2.10.3p7/ircd/list.c	2004-05-10 13:25:26.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/list.c	2004-05-10 16:03:38.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/list_ext.h irc2.10.3p7+hemp2/ircd/list_ext.h
--- irc2.10.3p7/ircd/list_ext.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/list_ext.h	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/res.c irc2.10.3p7+hemp2/ircd/res.c
--- irc2.10.3p7/ircd/res.c	2004-05-10 13:25:26.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/res.c	2004-05-10 16:03:38.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/s_auth.c irc2.10.3p7+hemp2/ircd/s_auth.c
--- irc2.10.3p7/ircd/s_auth.c	2004-03-09 17:22:01.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/s_auth.c	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/s_bsd.c irc2.10.3p7+hemp2/ircd/s_bsd.c
--- irc2.10.3p7/ircd/s_bsd.c	2004-05-10 13:25:26.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/s_bsd.c	2004-05-10 16:03:38.000000000 +0900
@@ -327,7 +327,6 @@
 #endif
 		if (inetport(cptr, aconf->host, aconf->name, aconf->port))
 			cptr->fd = -2;
-
 	if (cptr->fd >= 0)
 	    {
 		cptr->confs = make_link();
@@ -341,7 +340,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 +1384,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 +1657,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 +1715,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 +2630,8 @@
 int	*lenp;
 {
 	static	struct	SOCKADDR_IN	server;
+	struct SOCKADDR_IN outip;
+	
 	Reg	struct	hostent	*hp;
 	aClient	*acptr;
 	int	i;
@@ -2599,7 +2651,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 +2681,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 -urN irc2.10.3p7/ircd/s_bsd_ext.h irc2.10.3p7+hemp2/ircd/s_bsd_ext.h
--- irc2.10.3p7/ircd/s_bsd_ext.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/s_bsd_ext.h	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/s_conf.c irc2.10.3p7+hemp2/ircd/s_conf.c
--- irc2.10.3p7/ircd/s_conf.c	2004-05-10 13:25:26.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/s_conf.c	2004-05-10 16:03:38.000000000 +0900
@@ -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)))
@@ -851,12 +899,11 @@
 		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
@@ -1190,7 +1237,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 +1316,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 +1463,10 @@
 				MyFree(tmp2);
 				tmp2 = NULL;
 			    }
+			if (tmp3)
+			{
+				DupString(aconf->source_ip, tmp3);
+			}
 				
 		    }
 		/*
diff -urN irc2.10.3p7/ircd/s_debug.c irc2.10.3p7+hemp2/ircd/s_debug.c
--- irc2.10.3p7/ircd/s_debug.c	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/s_debug.c	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/s_err.c irc2.10.3p7+hemp2/ircd/s_err.c
--- irc2.10.3p7/ircd/s_err.c	2004-03-09 17:22:01.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/s_err.c	2004-03-09 17:29:27.000000000 +0900
@@ -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 },
@@ -183,7 +207,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 +227,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 +279,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 +326,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 +371,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 -urN irc2.10.3p7/ircd/s_misc.c irc2.10.3p7+hemp2/ircd/s_misc.c
--- irc2.10.3p7/ircd/s_misc.c	2004-05-10 13:25:26.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/s_misc.c	2004-05-10 16:03:38.000000000 +0900
@@ -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)
 		    {
@@ -408,16 +417,30 @@
 				istat.is_myservice--;
 			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)
+#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 +527,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 +563,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 +627,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 +663,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 +807,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 +866,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 +948,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 +1024,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 +1238,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
@@ -996,3 +1302,325 @@
 	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 =='#') || (*user == IRCDCONF_DELIMITER))
+			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] == '#') || (kline_reason[i] == IRCDCONF_DELIMITER))
+		    {
+			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;
+		    }
+
+		sprintf(buffer, "K%c%s%c%s%c%s%c\n\n", IRCDCONF_DELIMITER, host, IRCDCONF_DELIMITER, kline_reason,
+			IRCDCONF_DELIMITER, user, IRCDCONF_DELIMITER);
+
+		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 -urN irc2.10.3p7/ircd/s_misc_ext.h irc2.10.3p7+hemp2/ircd/s_misc_ext.h
--- irc2.10.3p7/ircd/s_misc_ext.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/s_misc_ext.h	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/s_numeric.c irc2.10.3p7+hemp2/ircd/s_numeric.c
--- irc2.10.3p7/ircd/s_numeric.c	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/s_numeric.c	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/s_serv.c irc2.10.3p7+hemp2/ircd/s_serv.c
--- irc2.10.3p7/ircd/s_serv.c	2004-05-10 13:25:26.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/s_serv.c	2004-05-10 16:03:38.000000000 +0900
@@ -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");
@@ -1304,7 +1379,6 @@
 		{ CONF_DENY,		  RPL_STATSDLINE, 'D'},
 		{ 0, 0, 0}
 	};
-
 static	void	report_configured_links(sptr, to, mask)
 aClient *sptr;
 char	*to;
@@ -1312,6 +1386,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 +1397,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 +1493,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;
@@ -1410,6 +1678,10 @@
 			}
 			/* else fallthrough */
                 default:
+#ifdef NO_OPER_TRYAGAIN
+		if (IsOper(sptr))
+			break;
+#endif
 		if (check_link(cptr))
 		    {
 			sendto_one(sptr, rpl_str(RPL_TRYAGAIN, parv[0]),
@@ -1430,14 +1702,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 +1750,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 +1775,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),
@@ -1540,8 +1845,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 +1893,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 +2016,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 +2158,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 +2201,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 +2378,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 +2433,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;
-	}
-
-	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]++;
-	}
+	char *name;
+	int class;
 
-	/* 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 +2685,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 +2809,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 +3205,7 @@
     return -1;
 }
 
+#ifndef DELAY_ACCEPT
 static void report_listeners(aClient *sptr, char *to)
 {
 	aConfItem *tmp;
@@ -2518,3 +3221,4 @@
 		}
 	}
 }
+#endif
diff -urN irc2.10.3p7/ircd/s_serv_ext.h irc2.10.3p7+hemp2/ircd/s_serv_ext.h
--- irc2.10.3p7/ircd/s_serv_ext.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/s_serv_ext.h	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/s_service.c irc2.10.3p7+hemp2/ircd/s_service.c
--- irc2.10.3p7/ircd/s_service.c	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/s_service.c	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/ircd/s_user.c irc2.10.3p7+hemp2/ircd/s_user.c
--- irc2.10.3p7/ircd/s_user.c	2004-03-09 17:22:51.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/s_user.c	2004-03-09 17:53:06.000000000 +0900
@@ -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
 		 */
+#ifdef ILINE_FLAGS
+		if (!IsKlineExempt(sptr) && find_kill(sptr, 1, &reason))
+
+#else
 		if (find_kill(sptr, 1, &reason))
+#endif
 		    {
 			/*char buf[100];*/
 
@@ -582,6 +648,21 @@
 			return exit_client(cptr, sptr, &me , "R-lined");
 		    }
 #endif
+
+#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 +710,70 @@
 				   (*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 ((istat.is_m_users % 1000) == 0)
+			sendto_flag(SCH_NOTICE,
+			"New highest global client connection:  %d",
+			istat.is_m_users);
+	}
+	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 ((istat.is_m_myclnt % 10) == 0)
+				sendto_flag(SCH_NOTICE,
+				"New highest local client connection:  %d",
+				istat.is_m_myclnt);
+		}
+		/*
+		**  Small cludge to try and warn of some fast clonebots.
+		*/
+		if ((istat.is_myclnt % 10) == 0) {
+			if (istat.is_myclnt > istat.is_last_cnt) {
+				if (istat.is_last_cnt_t == 0)
+					istat.is_last_cnt_t = me.since;
+
+				sendto_flag(SCH_NOTICE,
+				"Local increase from %d to %d clients in %d second%s",
+				(istat.is_myclnt - 10),istat.is_myclnt,
+				(timeofday - istat.is_last_cnt_t),
+				((timeofday - istat.is_last_cnt_t == 1) ? ""
+				: "s"));
+			}
+			istat.is_last_cnt_t = timeofday;
+			istat.is_last_cnt = 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 +783,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 +823,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 +1206,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 +1566,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 +1574,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 +1693,7 @@
 	for (p = NULL, mask = strtoken(&p, parv[1], ",");
 	    mask && penalty <= MAXPENALTY;
 		mask = strtoken(&p, NULL, ","))
-	{ 
+	{
 		channame = NULL;
 		penalty += 1;
 
@@ -1523,12 +1705,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 +1784,7 @@
 				** All nice chances lost above. 
 				** We must hog our server with that.
 				*/
+				
 				who_find(sptr, mask, oper);
 				penalty += MAXPENALTY;
 			}
@@ -1695,7 +1877,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 +2522,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 +2719,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 +3093,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 +3110,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 +3120,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 +3130,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 -urN irc2.10.3p7/ircd/version.c.SH.in irc2.10.3p7+hemp2/ircd/version.c.SH.in
--- irc2.10.3p7/ircd/version.c.SH.in	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/version.c.SH.in	2004-03-09 17:53:06.000000000 +0900
@@ -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 2003121203.",
+	"See http://jv.irc.cz/irc/ for more information about this patch.",
 	0,
     };
 !SUB!THIS!
diff -urN irc2.10.3p7/ircd/version_ext.h irc2.10.3p7+hemp2/ircd/version_ext.h
--- irc2.10.3p7/ircd/version_ext.h	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/ircd/version_ext.h	2004-03-09 17:29:27.000000000 +0900
@@ -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 -urN irc2.10.3p7/support/Makefile.in irc2.10.3p7+hemp2/support/Makefile.in
--- irc2.10.3p7/support/Makefile.in	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/support/Makefile.in	2004-03-09 17:29:27.000000000 +0900
@@ -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
 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
@@ -464,6 +467,9 @@
 mod_socks.o: ../iauth/mod_socks.c config.h setup.h
 	$(CC) $(A_CFLAGS) -c -o $@ ../iauth/mod_socks.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 -urN irc2.10.3p7/support/config.h.dist irc2.10.3p7+hemp2/support/config.h.dist
--- irc2.10.3p7/support/config.h.dist	2004-05-10 13:25:26.000000000 +0900
+++ irc2.10.3p7+hemp2/support/config.h.dist	2004-05-10 16:03:38.000000000 +0900
@@ -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	1024
 
 /* MAXIMUM LINKS
  *
@@ -323,7 +323,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	8000
 
 /* Remote query flood protection. */
 #define	CHREPLLEN	8192
@@ -339,6 +339,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,
@@ -389,6 +390,175 @@
  */
 #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
+ */
+#define 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].
+ */
+
+#undef FAILED_OPERLOG
+#undef 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 10
+
+/* 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  10
+#define SPLIT_USERS 15000
+
+/* 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
+ */
+#define KLINE_FILE IRCDCONF_PATH
+
+/* undef if you don't want to have Denied connection  because of open proxy */
+#define IAUTH_VERBOSE_REJECTS
+
+/* end of +jv patch */
+
 /*   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 +573,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 512
 
 /* define DEBUGMODE to enable debugging mode.*/
 #undef	DEBUGMODE
 
+/* log ircname to logfile */
+#define LOG_IRCNAME
 /*
  * Time interval to wait and if no messages have been received, then check for
  * PINGFREQUENCY and CONNECTFREQUENCY 
@@ -484,7 +656,7 @@
 /*
  * Max number of channels a user is allowed to join.
  */
-#define MAXCHANNELSPERUSER  10	/* Recommended value: 10 */
+#define MAXCHANNELSPERUSER  20	/* Recommended value: 10 */
 
 /*
  * USE_IAUTH makes ircd use the iauth program for authentication.
@@ -519,6 +691,7 @@
 /* #undef	NO_IDENT */
 /* #undef	NO_PREFIX */
 
+
 /* ------------------------- END CONFIGURATION SECTION -------------------- */
 #ifndef ENABLE_SUMMON
 #  undef LEAST_IDLE
@@ -610,3 +783,7 @@
 */
 #define	RESTRICT_HOSTNAMES	1
 
+#if defined(DELAY_ACCEPT) && !defined(SPLIT_HANDLE)
+error DELAY_ACCEPT requires SPLIT_HANDLE defined.
+#endif
+
diff -urN irc2.10.3p7/support/iauth.conf irc2.10.3p7+hemp2/support/iauth.conf
--- irc2.10.3p7/support/iauth.conf	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/support/iauth.conf	2004-03-09 17:29:27.000000000 +0900
@@ -14,5 +14,10 @@
 module rfc931
 
 # Check and reject open SOCKS proxies
-#module socks
-#	option = reject,paranoid
+module socks
+	option = reject,paranoid
+	timeout = 5
+
+module webproxy
+	option = log,reject,ports=3128;8080
+	timeout = 10
diff -urN irc2.10.3p7/support/tkconf.h.dist irc2.10.3p7+hemp2/support/tkconf.h.dist
--- irc2.10.3p7/support/tkconf.h.dist	2004-03-09 17:21:33.000000000 +0900
+++ irc2.10.3p7+hemp2/support/tkconf.h.dist	2004-03-09 17:29:27.000000000 +0900
@@ -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"
 
