Commit Diff


commit - 12db0bdc4fb2d4bf40d6961406400a248bac123c
commit + 47ca178a219d682c589b27e64ee1a4e936cc7bdc
blob - fbc51766fe7a1bf0fa3839aeb499f81a8f7af661
blob + d39fbd5177d5f57db24c45f21bea9648a634cf96
--- ChangeLog
+++ ChangeLog
@@ -12,6 +12,11 @@
 
 ngIRCd HEAD
 
+  - New configuration option "MaxNickLength" to specify the allowed maximum
+    length of user nick names. Note: must be unique in an IRC network!
+  - Enhanced the IRC+ protocol to support an enhanced "server handshake" and
+    enable server to recognice numeric 005 (ISUPPORT) and 376 (ENDOFMOTD).
+    See doc/Protocol.txt for details.
   - Re-added doc/SSL.txt to distribution -- got lost somewhere!?
   - Fixes the wrong logging output when nested servers are introduced
     to the network as well as the wrong output of the LINKS command.
@@ -713,4 +718,4 @@ ngIRCd 0.0.1, 31.12.2001
 
 
 -- 
-$Id: ChangeLog,v 1.328 2007/11/20 21:39:35 alex Exp $
+$Id: ChangeLog,v 1.329 2007/11/21 12:16:33 alex Exp $
blob - 2591b230dd7150d6b7f4ba11813b9db6bcbafda7
blob + a604926bd4e0e41ac28943b87727ee6f214d79a3
--- NEWS
+++ NEWS
@@ -12,6 +12,8 @@
 
 ngIRCd HEAD
 
+  - New configuration option "MaxNickLength" to specify the allowed maximum
+    length of user nick names. Note: must be unique in an IRC network!
   - Numeric 317: implemented "signon time" (displayed in WHOIS result).
   - Added new server configuration option "Passive" for "Server" blocks to
     disable automatic outgoing connections (similar to -p option to ngircd,
@@ -246,4 +248,4 @@ ngIRCd 0.0.1, 31.12.2001
 
 
 -- 
-$Id: NEWS,v 1.81 2007/10/14 14:17:32 alex Exp $
+$Id: NEWS,v 1.82 2007/11/21 12:16:33 alex Exp $
blob - 1ca7140d69505e665de32cd8dbc852fd2b81047f
blob + 1a032a79f5121ce9506b8f6a9d4227035cb8860f
--- contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj
+++ contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj
@@ -34,6 +34,7 @@
 		FA322D4D0CEF74B1001761B3 /* resolve.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322D0C0CEF74B1001761B3 /* resolve.c */; };
 		FA322DBE0CEF7766001761B3 /* tool.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322D330CEF74B1001761B3 /* tool.c */; };
 		FA322DC10CEF77CB001761B3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FA322DC00CEF77CB001761B3 /* libz.dylib */; };
+		FAE5CC2E0CF2308A007D69B6 /* numeric.c in Sources */ = {isa = PBXBuildFile; fileRef = FAE5CC2D0CF2308A007D69B6 /* numeric.c */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -198,6 +199,8 @@
 		FA322DB10CEF7565001761B3 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
 		FA322DBB0CEF773C001761B3 /* cvs-version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "cvs-version.h"; sourceTree = "<group>"; };
 		FA322DC00CEF77CB001761B3 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = /usr/lib/libz.dylib; sourceTree = "<absolute>"; };
+		FAE5CC2C0CF2308A007D69B6 /* numeric.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = numeric.h; sourceTree = "<group>"; };
+		FAE5CC2D0CF2308A007D69B6 /* numeric.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = numeric.c; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -309,6 +312,8 @@
 				FA322D050CEF74B1001761B3 /* messages.h */,
 				FA322D060CEF74B1001761B3 /* ngircd.c */,
 				FA322D070CEF74B1001761B3 /* ngircd.h */,
+				FAE5CC2D0CF2308A007D69B6 /* numeric.c */,
+				FAE5CC2C0CF2308A007D69B6 /* numeric.h */,
 				FA322D080CEF74B1001761B3 /* parse.c */,
 				FA322D090CEF74B1001761B3 /* parse.h */,
 				FA322D0A0CEF74B1001761B3 /* rendezvous.c */,
@@ -622,6 +627,7 @@
 				FA322D4C0CEF74B1001761B3 /* rendezvous.c in Sources */,
 				FA322D4D0CEF74B1001761B3 /* resolve.c in Sources */,
 				FA322DBE0CEF7766001761B3 /* tool.c in Sources */,
+				FAE5CC2E0CF2308A007D69B6 /* numeric.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
blob - 14da84757493db2da0cad65be464120f2cf3ac23
blob + c81143e335928e9a7b7acc249117ebc227525cad
--- doc/Protocol.txt
+++ doc/Protocol.txt
@@ -1,7 +1,7 @@
 
                      ngIRCd - Next Generation IRC Server
 
-                      (c)2001-2003 by Alexander Barton,
+                        (c)2001-2007 Alexander Barton,
                     alex@barton.de, http://www.barton.de/
 
                ngIRCd is free software and published under the
@@ -79,6 +79,9 @@ The following <serverflags> are defined at the moment:
      peer understands this flag, it will send "MODE +I" and "MODE +b"
      commands after the server link has been established.
 
+- H: The server supports the "enhanced server handshake", see section II.2
+     for a detailed description.
+
 - o: IRC operators are allowed to change channel- and channel-user-modes
      even if they aren't channel-operator of the affected channel.
 
@@ -90,8 +93,51 @@ The optional parameter <options> is used to propagate 
 defined in RFC 2813, section 4.1.1.
 
 
-II.2 Exchange channel-modes, topics, and persistent channels
+II.2 Enhanced Server Handshake
 
+The "enhanced server handshake" is used when both servers support this IRC+
+extension, which is indicated by the 'H' flag in the <serverflags> sent with
+the PASS command, see section II.1.
+
+It basically means, that after exchanging the PASS and SERVER commands the
+server is not registered in the network (as usual), but that IRC numerics
+are exchanged until the numeric 376 (ENDOFMOTD) is received. Afterwards the
+peer is registered in the network as with the regular IRC protocol.
+
+A server implementing the enhanced server handshake (and indicating this
+using 'H' in the <serverflags>) MUST ignore all unknown numerics to it
+silently.
+
+In addition, such a server should at least send the numeric 005 (ISUPPORT)
+to its peer, containing the following information. Syntax: <key>=<value>,
+one token per IRC parameter. If the server has to send more than 12 token
+it must send separate ISUPPORT numerics (this is a limitation of the IRC
+protocol which allows at max 15 arguments per command).
+
+ - NICKLEN: Maximum nickname length. Default: 9.
+ - CASEMAPPING: Case mapping used for nick- and channel name comparing.
+   Default: "ascii", the chars [a-z] are lowercase of [A-Z].
+ - PREFIX: List of channel modes a person can get and the respective prefix
+   a channel or nickname will get in case the person has it. The order of the
+   modes goes from most powerful to least powerful. Default: "(ov)@+"
+ - CHANTYPES: Supported channel prefixes. Default: "#".
+ - CHANMODES: List of channel modes for 4 types, separated by comma (","):
+   Mode that adds or removes a nick or address to a list, mode that changes
+   a setting (both have always has a parameter), mode that changes a setting
+   and only has a parameter when set, and mode that changes a setting and
+   never has a parameter. For example "bI,k,l,imnPst".
+ - CHANLIMIT: Maximum number of channels allowed to join by channel prefix,
+   for example "#:10".
+
+Please see <http://www.irc.org/tech_docs/005.html> for details.
+
+The information exchanged using ISUPPORT can be used to detect configuration
+incompatibilities (different maximum nick name length, for example) and
+therefore to disconnect the peer prior to registering it in the network.
+
+
+II.3 Exchange channel-modes, topics, and persistent channels
+
      Command: CHANINFO
   Parameters: <channel> +<modes> <key> <limit> [<topic>]
      Used by: servers only
@@ -115,4 +161,4 @@ channel mode). In this case <limit> should be "0".
 
 
 -- 
-$Id: Protocol.txt,v 1.13 2005/08/27 19:00:06 alex Exp $
+$Id: Protocol.txt,v 1.14 2007/11/21 12:16:35 alex Exp $
blob - e17b0e60690dd5b46a886985391acc7a083c3b9d
blob + 924f0595450939600f516516f97bf5b063bca401
--- doc/sample-ngircd.conf
+++ doc/sample-ngircd.conf
@@ -1,4 +1,4 @@
-# $Id: sample-ngircd.conf,v 1.41 2007/10/13 20:45:11 fw Exp $
+# $Id: sample-ngircd.conf,v 1.42 2007/11/21 12:16:35 alex Exp $
 
 #
 # This is a sample configuration file for the ngIRCd, which must be adepted
@@ -111,6 +111,11 @@
 	# Maximum number of channels a user can be member of (0: no limit):
 	;MaxJoins = 10
 
+	# Maximum length of an user nick name (Default: 9, as in RFC 2812).
+	# Please note that all servers in an IRC network MUST use the same
+	# maximum nick name length!
+	;MaxNickLength = 9
+
 [Operator]
 	# [Operator] sections are used to define IRC Operators. There may be
 	# more than one [Operator] block, one for each local operator.
blob - 8321900926d6218ec9ffb7ad34a3166a90f608dd
blob + 457a162caba1c71918304b67262f81ca0bfb8343
--- man/ngircd.conf.5.tmpl
+++ man/ngircd.conf.5.tmpl
@@ -1,5 +1,5 @@
 .\"
-.\" $Id: ngircd.conf.5.tmpl,v 1.5 2007/10/25 11:01:19 fw Exp $
+.\" $Id: ngircd.conf.5.tmpl,v 1.6 2007/11/21 12:16:36 alex Exp $
 .\"
 .TH ngircd.conf 5 "August 2005" ngircd "ngIRCd Manual"
 .SH NAME
@@ -170,6 +170,11 @@ the risk of denial of service attacks (DoS). Default: 
 \fBMaxJoins\fR
 Maximum number of channels a user can be member of (0: no limit).
 Default: 10.
+.TP
+\fBMaxNickLength\fR
+Maximum length of an user nick name (Default: 9, as in RFC 2812). Please
+note that all servers in an IRC network MUST use the same maximum nick name
+length!
 .SH [OPERATOR]
 .I [Operator]
 sections are used to define IRC Operators. There may be more than one
blob - 52bd1615bd4fc5b9400e43ec5f96c8ac7e25829f
blob + 46513a8a54da042e4b74fbc21ef165ed23c20b4c
--- src/ngircd/Makefile.am
+++ src/ngircd/Makefile.am
@@ -8,7 +8,7 @@
 # (at your option) any later version.
 # Please read the file COPYING, README and AUTHORS for more information.
 #
-# $Id: Makefile.am,v 1.49 2006/03/11 01:48:50 alex Exp $
+# $Id: Makefile.am,v 1.50 2007/11/21 12:16:36 alex Exp $
 #
 
 AUTOMAKE_OPTIONS = ../portab/ansi2knr
@@ -23,7 +23,7 @@ sbin_PROGRAMS = ngircd
 ngircd_SOURCES = ngircd.c array.c channel.c client.c conf.c conn.c conn-func.c \
 	conn-zip.c hash.c io.c irc.c irc-channel.c irc-info.c irc-login.c \
 	irc-mode.c irc-op.c irc-oper.c irc-server.c irc-write.c lists.c log.c \
-	match.c parse.c rendezvous.c resolve.c
+	match.c numeric.c parse.c rendezvous.c resolve.c
 
 ngircd_LDFLAGS = -L../portab -L../tool
 
@@ -32,7 +32,7 @@ ngircd_LDADD = -lngportab -lngtool
 noinst_HEADERS = ngircd.h array.h channel.h client.h conf.h conn.h conn-func.h \
 	conn-zip.h hash.h io.h irc.h irc-channel.h irc-info.h irc-login.h \
 	irc-mode.h irc-op.h irc-oper.h irc-server.h irc-write.h lists.h log.h \
-	match.h parse.h rendezvous.h resolve.h \
+	match.h numeric.h parse.h rendezvous.h resolve.h \
 	defines.h messages.h
 
 clean-local:
blob - 474ae4b6460c4be738b90e723065885ffa0a51ad
blob + c7d6427f939b72be30a05c2405ed20074cbbc3c7
--- src/ngircd/client.c
+++ src/ngircd/client.c
@@ -17,7 +17,7 @@
 
 #include "portab.h"
 
-static char UNUSED id[] = "$Id: client.c,v 1.96 2007/10/25 11:01:19 fw Exp $";
+static char UNUSED id[] = "$Id: client.c,v 1.97 2007/11/21 12:16:36 alex Exp $";
 
 #include "imp.h"
 #include <assert.h>
@@ -609,7 +609,8 @@ Client_ID( CLIENT *Client )
 	assert( Client != NULL );
 
 #ifdef DEBUG
-	if( Client->type == CLIENT_USER ) assert( strlen( Client->id ) < CLIENT_NICK_LEN );
+	if(Client->type == CLIENT_USER)
+		assert(strlen(Client->id) < Conf_MaxNickLength);
 #endif
 						   
 	if( Client->id[0] ) return Client->id;
@@ -952,7 +953,7 @@ Client_IsValidNick( const char *Nick )
 
 	if( Nick[0] == '#' ) return false;
 	if( strchr( goodchars, Nick[0] )) return false;
-	if( strlen( Nick ) >= CLIENT_NICK_LEN ) return false;
+	if( strlen( Nick ) >= Conf_MaxNickLength) return false;
 
 	ptr = Nick;
 	while( *ptr )
blob - c9643dad491d75c5abefb7af49a7431ef31f1991
blob + c55aaf53a775f8945706a73305d3157ed277b623
--- src/ngircd/conf.c
+++ src/ngircd/conf.c
@@ -14,7 +14,7 @@
 
 #include "portab.h"
 
-static char UNUSED id[] = "$Id: conf.c,v 1.101 2007/10/25 11:01:19 fw Exp $";
+static char UNUSED id[] = "$Id: conf.c,v 1.102 2007/11/21 12:16:36 alex Exp $";
 
 #include "imp.h"
 #include <assert.h>
@@ -208,7 +208,8 @@ Conf_Test( void )
 	printf( "  NoDNS = %s\n", Conf_NoDNS ? "yes" : "no");
 	printf( "  MaxConnections = %ld\n", Conf_MaxConnections);
 	printf( "  MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP);
-	printf( "  MaxJoins = %d\n\n", Conf_MaxJoins);
+	printf( "  MaxJoins = %d\n", Conf_MaxJoins>0 ? Conf_MaxJoins : -1);
+	printf( "  MaxNickLength = %u\n\n", Conf_MaxNickLength - 1);
 
 	for( i = 0; i < Conf_Oper_Count; i++ ) {
 		if( ! Conf_Oper[i].name[0] ) continue;
@@ -452,6 +453,7 @@ Set_Defaults( bool InitServers )
 	Conf_MaxConnections = 0;
 	Conf_MaxConnectionsIP = 5;
 	Conf_MaxJoins = 10;
+	Conf_MaxNickLength = CLIENT_NICK_LEN_DEFAULT;
 
 	/* Initialize server configuration structures */
 	if( InitServers ) for( i = 0; i < MAX_SERVERS; Init_Server_Struct( &Conf_Server[i++] ));
@@ -636,6 +638,27 @@ Check_ArgIsTrue( const char *Arg )
 
 	return false;
 } /* Check_ArgIsTrue */
+
+
+static unsigned int Handle_MaxNickLength(int Line, const char *Arg)
+{
+	unsigned new;
+
+	new = (unsigned) atoi(Arg) + 1;
+	if (new > CLIENT_NICK_LEN) {
+		Config_Error(LOG_WARNING,
+			     "%s, line %d: Value of \"MaxNickLength\" exceeds %u!",
+			     NGIRCd_ConfFile, Line, CLIENT_NICK_LEN - 1);
+		return CLIENT_NICK_LEN;
+	}
+	if (new < 2) {
+		Config_Error(LOG_WARNING,
+			     "%s, line %d: Value of \"MaxNickLength\" must be at least 1!",
+			     NGIRCd_ConfFile, Line);
+		return 2;
+	}
+	return new;
+} /* Handle_MaxNickLength */
 
 
 static void
@@ -827,6 +850,13 @@ Handle_GLOBAL( int Line, char *Var, char *Arg )
 		Conf_MaxJoins = atoi( Arg );
 		return;
 	}
+	if( strcasecmp( Var, "MaxNickLength" ) == 0 ) {
+		/* Maximum length of a nick name; must be same on all servers
+		 * within the IRC network! */
+		Conf_MaxNickLength = Handle_MaxNickLength(Line, Arg);
+		return;
+	}
+
 	if( strcasecmp( Var, "Listen" ) == 0 ) {
 		/* IP-Address to bind sockets */
 		len = strlcpy( Conf_ListenAddress, Arg, sizeof( Conf_ListenAddress ));
blob - ce09997c23ee8bffeb460c405a3791fa922b527c
blob + 371f94db64233155d2169f16093d93e5df470195
--- src/ngircd/conf.h
+++ src/ngircd/conf.h
@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
- * $Id: conf.h,v 1.44 2007/10/25 11:01:19 fw Exp $
+ * $Id: conf.h,v 1.45 2007/11/21 12:16:36 alex Exp $
  *
  * Configuration management (header)
  */
@@ -135,6 +135,8 @@ GLOBAL int Conf_MaxJoins;
 /* Maximum number of connections per IP address */
 GLOBAL int Conf_MaxConnectionsIP;
 
+/* Maximum length of a nick name */
+GLOBAL unsigned int Conf_MaxNickLength;
 
 GLOBAL void Conf_Init PARAMS((void));
 GLOBAL void Conf_Rehash PARAMS((void));
blob - 251a6997dd3c1e084525cc29ede57c8219735cc2
blob + cccf48b43e5f719d3a19146f995956e36fd6803e
--- src/ngircd/defines.h
+++ src/ngircd/defines.h
@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
- * $Id: defines.h,v 1.61 2007/08/02 10:14:26 fw Exp $
+ * $Id: defines.h,v 1.62 2007/11/21 12:16:36 alex Exp $
  */
 
 
@@ -47,8 +47,9 @@
 
 #define CLIENT_ID_LEN 64		/* Max. length of an IRC ID; see RFC
 					   RFC 2812 section 1.1 and 1.2.1 */
-#define CLIENT_NICK_LEN 10		/* Max. nick length, see. RFC 2812
-					   section 1.2.1 */
+#define CLIENT_NICK_LEN_DEFAULT 10	/* Default nick length, see. RFC 2812
+					 * section 1.2.1 */
+#define CLIENT_NICK_LEN 32		/* Maximum nick name length */
 #define CLIENT_PASS_LEN 21		/* Max. password length */
 #define CLIENT_USER_LEN 10		/* Max. length of user name ("login")
 					   see RFC 2812, section 1.2.1 */
@@ -81,7 +82,7 @@
 					   protocol, see doc/Protocol.txt */
 
 #ifdef IRCPLUS
-# define IRCPLUSFLAGS "CL"		/* Standard IRC+ flags */
+# define IRCPLUSFLAGS "CHL"		/* Standard IRC+ flags */
 #endif
 
 #define STARTUP_DELAY 1			/* Delay outgoing connections n seconds
blob - 4ed05b332b21f2506999886c564f02c70d00c2db
blob + 683f7d1b04b8a79f0f3ff04f2d94771c14270ee4
--- src/ngircd/irc-info.c
+++ src/ngircd/irc-info.c
@@ -14,7 +14,7 @@
 
 #include "portab.h"
 
-static char UNUSED id[] = "$Id: irc-info.c,v 1.39 2007/11/18 15:05:35 alex Exp $";
+static char UNUSED id[] = "$Id: irc-info.c,v 1.40 2007/11/21 12:16:36 alex Exp $";
 
 #include "imp.h"
 #include <assert.h>
@@ -1048,6 +1048,24 @@ IRC_Send_WHO( CLIENT *Client, CHANNEL *Chan, bool Only
 	}
 	return CONNECTED;
 } /* IRC_Send_WHO */
+
+
+/**
+ * Send the ISUPPORT numeric (005).
+ * This numeric indicates the features that are supported by this server.
+ * See <http://www.irc.org/tech_docs/005.html> for details.
+ */
+GLOBAL bool
+IRC_Send_ISUPPORT PARAMS((CLIENT * Client))
+{
+	if (!IRC_WriteStrClient(Client, RPL_ISUPPORT1_MSG, Client_ID(Client),
+				Conf_MaxJoins))
+		return DISCONNECTED;
+	return IRC_WriteStrClient(Client, RPL_ISUPPORT2_MSG, Client_ID(Client),
+				  CHANNEL_NAME_LEN - 1, Conf_MaxNickLength - 1,
+				  COMMAND_LEN - 23, CLIENT_AWAY_LEN - 1,
+				  COMMAND_LEN - 113);
+} /* IRC_Send_ISUPPORT */
 
 
 /* -eof- */
blob - 24181e375e7c0396860ff68ff3ef8bb4866deb3d
blob + 41e3953d1cd5ffab5988acbf099f70d748409154
--- src/ngircd/irc-info.h
+++ src/ngircd/irc-info.h
@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
- * $Id: irc-info.h,v 1.3 2005/03/19 18:43:48 fw Exp $
+ * $Id: irc-info.h,v 1.4 2007/11/21 12:16:36 alex Exp $
  *
  * IRC info commands (header)
  */
@@ -36,6 +36,7 @@ GLOBAL bool IRC_Send_LUSERS PARAMS(( CLIENT *Client ))
 GLOBAL bool IRC_Send_NAMES PARAMS(( CLIENT *Client, CHANNEL *Chan ));
 GLOBAL bool IRC_Show_MOTD PARAMS(( CLIENT *Client ));
 GLOBAL bool IRC_Send_WHO PARAMS(( CLIENT *Client, CHANNEL *Chan, bool OnlyOps ));
+GLOBAL bool IRC_Send_ISUPPORT PARAMS(( CLIENT *Client ));
 
 
 #endif
blob - caa78a1f3822993c3e9190d7a1c15d8e0e149e3b
blob + a095ddc00bbf45ca73b6ac553fbaff73e806756c
--- src/ngircd/irc-login.c
+++ src/ngircd/irc-login.c
@@ -14,7 +14,7 @@
 
 #include "portab.h"
 
-static char UNUSED id[] = "$Id: irc-login.c,v 1.53 2006/10/03 10:28:38 alex Exp $";
+static char UNUSED id[] = "$Id: irc-login.c,v 1.54 2007/11/21 12:16:36 alex Exp $";
 
 #include "imp.h"
 #include <assert.h>
@@ -618,12 +618,7 @@ Hello_User( CLIENT *Client )
 
 	/* Features supported by this server (005 numeric, ISUPPORT),
 	 * see <http://www.irc.org/tech_docs/005.html> for details. */
-	if (! IRC_WriteStrClient(Client, RPL_ISUPPORT1_MSG, Client_ID(Client),
-			Conf_MaxJoins))
-		return DISCONNECTED;
-	if (! IRC_WriteStrClient(Client, RPL_ISUPPORT2_MSG, Client_ID(Client),
-			CHANNEL_NAME_LEN-1, CLIENT_NICK_LEN-1, COMMAND_LEN-23,
-			CLIENT_AWAY_LEN-1, COMMAND_LEN-113))
+	if (! IRC_Send_ISUPPORT(Client))
 		return DISCONNECTED;
 
 	Client_SetType( Client, CLIENT_USER );
blob - 3fc0e2dc1e84f2032e1ad0aa4f1c70cc82b14e93
blob + d342ffab754f463ce423f842c41f56e9f37c192c
--- src/ngircd/irc-server.c
+++ src/ngircd/irc-server.c
@@ -14,7 +14,7 @@
 
 #include "portab.h"
 
-static char UNUSED id[] = "$Id: irc-server.c,v 1.45 2007/11/20 20:02:41 alex Exp $";
+static char UNUSED id[] = "$Id: irc-server.c,v 1.46 2007/11/21 12:16:36 alex Exp $";
 
 #include "imp.h"
 #include <assert.h>
@@ -35,54 +35,14 @@ static char UNUSED id[] = "$Id: irc-server.c,v 1.45 20
 #include "log.h"
 #include "messages.h"
 #include "parse.h"
+#include "numeric.h"
 #include "ngircd.h"
+#include "irc-info.h"
 
 #include "exp.h"
 #include "irc-server.h"
 
 
-#ifdef IRCPLUS
-static bool
-Synchronize_Lists( CLIENT *Client )
-{
-	CHANNEL *c;
-	struct list_head *head;
-	struct list_elem *elem;
-
-	assert( Client != NULL );
-
-	c = Channel_First();
-
-	while (c) {
-		head = Channel_GetListBans(c);
-
-		elem = Lists_GetFirst(head);
-		while (elem) {
-			if( ! IRC_WriteStrClient( Client, "MODE %s +b %s",
-					Channel_Name(c), Lists_GetMask(elem)))
-			{
-				return false;
-			}
-			elem = Lists_GetNext(elem);
-		}
-
-		head = Channel_GetListInvites(c);
-		elem = Lists_GetFirst(head);
-		while (elem) {
-			if( ! IRC_WriteStrClient( Client, "MODE %s +I %s",
-					Channel_Name( c ), Lists_GetMask(elem)))
-			{
-				return false;
-			}
-			elem = Lists_GetNext(elem);
-		}
-		c = Channel_Next(c);
-	}
-	return true;
-}
-#endif
-
-
 /**
  * Handler for the IRC command "SERVER".
  * See RFC 2813 section 4.1.2.
@@ -90,12 +50,10 @@ Synchronize_Lists( CLIENT *Client )
 GLOBAL bool
 IRC_SERVER( CLIENT *Client, REQUEST *Req )
 {
-	char str[LINE_LEN], *ptr, *modes, *topic;
-	CLIENT *from, *c, *cl;
-	CL2CHAN *cl2chan;
-	int max_hops, i;
-	CHANNEL *chan;
+	char str[LINE_LEN], *ptr;
+	CLIENT *from, *c;
 	bool ok;
+	int i;
 	CONN_ID con;
 	
 	assert( Client != NULL );
@@ -164,11 +122,11 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req )
 			Client_SetToken( Client, atoi( Req->argv[1] ));
 		}
 
-		Log( LOG_NOTICE|LOG_snotice, "Server \"%s\" registered (connection %d, 1 hop - direct link).", Client_ID( Client ), con );
+		/* Mark this connection as belonging to an configured server */
+		Conf_SetServer(i, con);
+		
+		Client_SetType(Client, CLIENT_UNKNOWNSERVER);
 
-		Client_SetType( Client, CLIENT_SERVER );
-		Conf_SetServer( i, con );
-
 #ifdef ZLIB
 		/* Kompression initialisieren, wenn erforderlich */
 		if( strchr( Client_Flags( Client ), 'Z' ))
@@ -182,145 +140,23 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req )
 		}
 #endif
 
-		/* maximalen Hop Count ermitteln */
-		max_hops = 0;
-		c = Client_First( );
-		while( c )
-		{
-			if( Client_Hops( c ) > max_hops ) max_hops = Client_Hops( c );
-			c = Client_Next( c );
-		}
-		
-		/* Alle bisherigen Server dem neuen Server bekannt machen,
-		 * die bisherigen Server ueber den neuen informierenn */
-		for( i = 0; i < ( max_hops + 1 ); i++ )
-		{
-			c = Client_First( );
-			while( c )
-			{
-				if(( Client_Type( c ) == CLIENT_SERVER ) && ( c != Client ) && ( c != Client_ThisServer( )) && ( Client_Hops( c ) == i ))
-				{
-					if( Client_Conn( c ) > NONE )
-					{
-						/* Dem gefundenen Server gleich den neuen
-						 * Server bekannt machen */
-						if( ! IRC_WriteStrClient( c, "SERVER %s %d %d :%s", Client_ID( Client ), Client_Hops( Client ) + 1, Client_MyToken( Client ), Client_Info( Client ))) return DISCONNECTED;
-					}
-					
-					/* Inform the new server about this one */
-					if (! IRC_WriteStrClientPrefix(Client,
-							Client_Hops(c) == 1 ? Client_ThisServer() : Client_TopServer(c),
-							"SERVER %s %d %d :%s",
-							Client_ID(c), Client_Hops(c) + 1,
-							Client_MyToken(c), Client_Info(c)))
-						return DISCONNECTED;
-				}
-				c = Client_Next( c );
-			}
-		}
-
-		/* alle User dem neuen Server bekannt machen */
-		c = Client_First( );
-		while( c )
-		{
-			if( Client_Type( c ) == CLIENT_USER )
-			{
-				/* User an neuen Server melden */
-				if( ! IRC_WriteStrClient( Client, "NICK %s %d %s %s %d +%s :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_User( c ), Client_Hostname( c ), Client_MyToken( Client_Introducer( c )), Client_Modes( c ), Client_Info( c ))) return DISCONNECTED;
-			}
-			c = Client_Next( c );
-		}
-
-		/* Channels dem neuen Server bekannt machen */
-		chan = Channel_First( );
-		while( chan )
-		{
 #ifdef IRCPLUS
-			/* Send CHANINFO if the peer supports it */
-			if( strchr( Client_Flags( Client ), 'C' ))
-			{
-#ifdef DEBUG
-				Log( LOG_DEBUG, "Sending CHANINFO commands ..." );
+		if (strchr(Client_Flags(Client), 'H')) {
+			LogDebug("Peer supports IRC+ extended server handshake ...");
+			if (!IRC_Send_ISUPPORT(Client))
+				return DISCONNECTED;
+			return IRC_WriteStrClient(Client, RPL_ENDOFMOTD_MSG,
+						  Client_ID(Client));
+		} else {
 #endif
-				modes = Channel_Modes( chan );
-				topic = Channel_Topic( chan );
-
-				if( *modes || *topic )
-				{
-					/* send CHANINFO */
-					if(( ! strchr( Channel_Modes( chan ), 'k' )) && ( ! strchr( Channel_Modes( chan ), 'l' )) && ( ! *topic ))
-					{
-						/* "CHANINFO <chan> +<modes>" */
-						if( ! IRC_WriteStrClient( Client, "CHANINFO %s +%s", Channel_Name( chan ), modes )) return DISCONNECTED;
-					}
-					else if(( ! strchr( Channel_Modes( chan ), 'k' )) && ( ! strchr( Channel_Modes( chan ), 'l' )))
-					{
-						/* "CHANINFO <chan> +<modes> :<topic>" */
-						if( ! IRC_WriteStrClient( Client, "CHANINFO %s +%s :%s", Channel_Name( chan ), modes, topic )) return DISCONNECTED;
-					}
-					else
-					{
-						/* "CHANINFO <chan> +<modes> <key> <limit> :<topic>" */
-						if( ! IRC_WriteStrClient( Client, "CHANINFO %s +%s %s %lu :%s",
-							Channel_Name( chan ), modes,
-							strchr( Channel_Modes( chan ), 'k' ) ? Channel_Key( chan ) : "*",
-							strchr( Channel_Modes( chan ), 'l' ) ? Channel_MaxUsers( chan ) : 0, topic ))
-						{
-							return DISCONNECTED;
-						}
-					}
-				}
-			}
-#endif
-
-			/* alle Member suchen */
-			cl2chan = Channel_FirstMember( chan );
-			snprintf( str, sizeof( str ), "NJOIN %s :", Channel_Name( chan ));
-			while( cl2chan )
-			{
-				cl = Channel_GetClient( cl2chan );
-				assert( cl != NULL );
-
-				/* Nick, ggf. mit Modes, anhaengen */
-				if( str[strlen( str ) - 1] != ':' ) strlcat( str, ",", sizeof( str ));
-				if( strchr( Channel_UserModes( chan, cl ), 'v' )) strlcat( str, "+", sizeof( str ));
-				if( strchr( Channel_UserModes( chan, cl ), 'o' )) strlcat( str, "@", sizeof( str ));
-				strlcat( str, Client_ID( cl ), sizeof( str ));
-
-				if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 8 ))
-				{
-					/* Zeile senden */
-					if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
-					snprintf( str, sizeof( str ), "NJOIN %s :", Channel_Name( chan ));
-				}
-				
-				cl2chan = Channel_NextMember( chan, cl2chan );
-			}
-
-			/* noch Daten da? */
-			if( str[strlen( str ) - 1] != ':')
-			{
-				/* Ja; Also senden ... */
-				if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
-			}
-
-			/* Get next channel ... */
-			chan = Channel_Next(chan);
-		}
-
+			if (Conf_MaxNickLength != CLIENT_NICK_LEN_DEFAULT)
+				Log(LOG_CRIT,
+				    "Attention: this server uses a non-standard nick length, but the peer doesn't support the IRC+ extended server handshake!");
 #ifdef IRCPLUS
-		if (strchr(Client_Flags(Client), 'L')) {
-#ifdef DEBUG
-			Log(LOG_DEBUG,
-			    "Synchronizing INVITE- and BAN-lists ...");
-#endif
-			/* Synchronize INVITE- and BAN-lists */
-			if (!Synchronize_Lists(Client))
-				return DISCONNECTED;
 		}
 #endif
 
-		return CONNECTED;
+		return IRC_Num_ENDOFMOTD(Client, Req);
 	}
 	else if( Client_Type( Client ) == CLIENT_SERVER )
 	{
@@ -364,8 +200,9 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req )
 		IRC_WriteStrServersPrefix( Client, from, "SERVER %s %d %d :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_MyToken( c ), Client_Info( c ));
 
 		return CONNECTED;
-	}
-	else return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
+	} else
+		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
+					  Client_ID(Client), Req->command);
 } /* IRC_SERVER */
 
 
blob - 6322b25368f74f1c849c3b44e1c128147ae128ef
blob + 9940d79117f98b5a9fc2ab2880f8aa7124678c0d
--- src/ngircd/irc-server.h
+++ src/ngircd/irc-server.h
@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
- * $Id: irc-server.h,v 1.5 2005/03/19 18:43:49 fw Exp $
+ * $Id: irc-server.h,v 1.6 2007/11/21 12:16:36 alex Exp $
  *
  * IRC commands for server links (header)
  */
@@ -22,7 +22,9 @@ GLOBAL bool IRC_SERVER PARAMS((CLIENT *Client, REQUEST
 GLOBAL bool IRC_NJOIN PARAMS((CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_SQUIT PARAMS((CLIENT *Client, REQUEST *Req ));
 
+GLOBAL bool IRC_ENDOFMOTD_Server PARAMS((CLIENT *Client));
 
+
 #endif
 
 
blob - 1eb68b4c94f824950e6b239a5641bff22dbc8ae6
blob + d2a6d7ea8faae860f0df893edef82969acf80a3b
--- src/ngircd/ngircd.c
+++ src/ngircd/ngircd.c
@@ -12,7 +12,7 @@
 
 #include "portab.h"
 
-static char UNUSED id[] = "$Id: ngircd.c,v 1.116 2007/11/15 01:03:01 fw Exp $";
+static char UNUSED id[] = "$Id: ngircd.c,v 1.117 2007/11/21 12:16:36 alex Exp $";
 
 /**
  * @file
@@ -422,6 +422,7 @@ GLOBAL void
 NGIRCd_Rehash( void )
 {
 	char old_name[CLIENT_ID_LEN];
+	unsigned old_nicklen;
 
 	Log( LOG_NOTICE|LOG_snotice, "Re-reading configuration NOW!" );
 	NGIRCd_SignalRehash = false;
@@ -429,18 +430,23 @@ NGIRCd_Rehash( void )
 	/* Close down all listening sockets */
 	Conn_ExitListeners( );
 
-	/* Remember old server name */
+	/* Remember old server name and nick name length */
 	strlcpy( old_name, Conf_ServerName, sizeof old_name );
+	old_nicklen = Conf_MaxNickLength;
 
 	/* Re-read configuration ... */
 	Conf_Rehash( );
 
-	/* Recover old server name: it can't be changed during run-time */
-	if( strcmp( old_name, Conf_ServerName ) != 0 )
-	{
-		strlcpy( Conf_ServerName, old_name, sizeof Conf_ServerName );
-		Log( LOG_ERR, "Can't change \"ServerName\" on runtime! Ignored new name." );
+	/* Recover old server name and nick name length: these values can't
+	 * be changed during run-time */
+	if (strcmp(old_name, Conf_ServerName) != 0 ) {
+		strlcpy(Conf_ServerName, old_name, sizeof Conf_ServerName);
+		Log(LOG_ERR, "Can't change \"ServerName\" on runtime! Ignored new name.");
 	}
+	if (old_nicklen != Conf_MaxNickLength) {
+		Conf_MaxNickLength = old_nicklen;
+		Log(LOG_ERR, "Can't change \"MaxNickLength\" on runtime! Ignored new value.");
+	}
 
 	/* Create new pre-defined channels */
 	Channel_InitPredefined( );
blob - b5e64a331ffd0a2c57b503e0d0ca2097d84747ec
blob + 5109169b72a068b8ff4655adda8bcb6637c093b1
--- src/ngircd/parse.c
+++ src/ngircd/parse.c
@@ -12,7 +12,7 @@
 
 #include "portab.h"
 
-static char UNUSED id[] = "$Id: parse.c,v 1.68 2007/08/02 10:14:26 fw Exp $";
+static char UNUSED id[] = "$Id: parse.c,v 1.69 2007/11/21 12:16:36 alex Exp $";
 
 /**
  * @file
@@ -48,6 +48,7 @@ static char UNUSED id[] = "$Id: parse.c,v 1.68 2007/08
 #include "irc-oper.h"
 #include "irc-server.h"
 #include "irc-write.h"
+#include "numeric.h"
 
 #include "exp.h"
 
@@ -101,6 +102,13 @@ COMMAND My_Commands[] =
 	{ "CHANINFO", IRC_CHANINFO, CLIENT_SERVER, 0, 0, 0 },
 #endif
 	{ NULL, NULL, 0x0, 0, 0, 0 } /* Ende-Marke */
+};
+
+NUMERIC My_Numerics[] =
+{
+	{ 005, IRC_Num_ISUPPORT },
+	{ 376, IRC_Num_ENDOFMOTD },
+	{ 0, NULL } /* end marker */
 };
 
 
@@ -349,6 +357,7 @@ Handle_Request( CONN_ID Idx, REQUEST *Req )
 	char str[LINE_LEN];
 	bool result;
 	COMMAND *cmd;
+	NUMERIC *num;
 	int i;
 
 	assert( Idx >= 0 );
@@ -358,25 +367,45 @@ Handle_Request( CONN_ID Idx, REQUEST *Req )
 	client = Conn_GetClient( Idx );
 	assert( client != NULL );
 
-	/* Statuscode? */
-	if(( Client_Type( client ) == CLIENT_SERVER ) && ( strlen( Req->command ) == 3 ) && ( atoi( Req->command ) > 100 ))
-	{
-		/* Command is a status code from an other server */
+	/* Numeric? */
+	if ((Client_Type(client) == CLIENT_SERVER ||
+	     Client_Type(client) == CLIENT_UNKNOWNSERVER)
+	    && strlen(Req->command) == 3 && atoi(Req->command) > 1) {
+		/* Command is a status code ("numeric") from an other server */
 
 		/* Determine target */
-		if( Req->argc > 0 ) target = Client_Search( Req->argv[0] );
-		else target = NULL;
-		if( ! target )
-		{
+		if (Req->argc > 0)
+			target = Client_Search( Req->argv[0] );
+		else
+			target = NULL;
+		if (!target) {
 			/* Status code without target!? */
-			if( Req->argc > 0 ) Log( LOG_WARNING, "Unknown target for status code %s: \"%s\"", Req->command, Req->argv[0] );
-			else Log( LOG_WARNING, "Unknown target for status code %s!", Req->command );
+			if (Req->argc > 0)
+				Log(LOG_WARNING,
+				    "Unknown target for status code %s: \"%s\"",
+				    Req->command, Req->argv[0]);
+			else
+				Log(LOG_WARNING,
+				    "Unknown target for status code %s!",
+				    Req->command);
 			return true;
 		}
-		if( target == Client_ThisServer( ))
-		{
-			/* This server is the target, ignore it */
-			Log( LOG_DEBUG, "Ignored status code %s from \"%s\".", Req->command, Client_ID( client ));
+		if (target == Client_ThisServer()) {
+			/* This server is the target of the numeric */
+			i = atoi(Req->command);
+
+			num = My_Numerics;
+			while (num->numeric > 0) {
+				if (i != num->numeric) {
+					num++;
+					continue;
+				}
+				result = (num->function)(client, Req);
+				return result;
+			}
+			
+			LogDebug("Ignored status code %s from \"%s\".",
+				 Req->command, Client_ID(client));
 			return true;
 		}
 
blob - b095666601ba7018284055dc8698232de88c9d4c
blob + e7a00879b5b826f7bef0dd4d604314fc0114ca09
--- src/ngircd/parse.h
+++ src/ngircd/parse.h
@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
- * $Id: parse.h,v 1.11 2005/03/19 18:43:49 fw Exp $
+ * $Id: parse.h,v 1.12 2007/11/21 12:16:36 alex Exp $
  *
  * IRC command parser and validator (header)
  */
@@ -33,11 +33,18 @@ typedef struct _COMMAND
 	char *name;			/* command name */
 	bool (*function) PARAMS(( CLIENT *Client, REQUEST *Request ));
 	CLIENT_TYPE type;		/* valid client types (bit mask) */
-	long lcount, rcount;	/* number of local and remote calls */
-	long bytes;		/* number of bytes created */
+	long lcount, rcount;		/* number of local and remote calls */
+	long bytes;			/* number of bytes created */
 } COMMAND;
 
 
+typedef struct _NUMERIC
+{
+	int numeric;			/* numeric */
+	bool (*function) PARAMS(( CLIENT *Client, REQUEST *Request ));
+} NUMERIC;
+
+
 GLOBAL bool Parse_Request PARAMS((CONN_ID Idx, char *Request ));
 
 GLOBAL COMMAND *Parse_GetCommandStruct PARAMS(( void ));