Browse Source

Import upstream version 19.2~rc1

Alexander Barton 12 years ago
parent
commit
e13e33193f

+ 42 - 14
ChangeLog

@@ -9,14 +9,42 @@
                                -- ChangeLog --
                                -- ChangeLog --
 
 
 
 
+ngIRCd Release 19.2
+
+  ngIRCd 19.2~rc1 (2012-06-13)
+  - New configuration option "CloakHostModeX" to configure the hostname
+    that gets used for IRC clients which have user mode "+x" enabled.
+    Up to now, the name of the IRC server itself has been used for this,
+    which still is the default when "CloakHostModeX" isn't set.
+  - Correctly handle asynchronously re-established server links: a race
+    condition could let the daemon loose track of an already re-established
+    incoming server link while preparing its own outgoing connection.
+    Peers that both try to connect each other could have been affected.
+  - Log a debug message when SIGUSR2 is handled in debug mode.
+  - Only allow alphanumeric characters in user-supplied user names of
+    USER command and IDENT replies.
+  - Change wording of "TLS initialized" message to make it more consistent.
+  - Don't leak file descriptors on error path when creating "PID files".
+  - Add missing mode "r" to CHANMODES in 005 "ISUPPORT" numeric.
+  - Update doc/Modes.txt and doc/Platforms.txt documents.
+  - contrib/platformtest.sh: correctly detect Open64 C compiler and handle
+    "CC=xxx MAKE=yyy ./platformtest.sh" calling convention.
+  - Add instructions for setting up Atheme IRC services.
+  - Implement support for IRC capability handling, the new "CAP" command,
+    and capablity "multi-prefix" which allows both the NAME and	WHO command
+    handlers to return more than one "class prefix" to the client.
+  - Update Xcode project files: reference missing documentation files.
+  - Fix: Don't ignore "permission denied" errors when enabling chroot.
+  - FAQ: enhance description of chroot setup.
+
 ngIRCd Release 19.1 (2012-03-19)
 ngIRCd Release 19.1 (2012-03-19)
 
 
   - Fix gcc warning (v4.6.3), initialize "list" variable to NULL.
   - Fix gcc warning (v4.6.3), initialize "list" variable to NULL.
   - Fix typos: "recieved" -> "received", "Please not" -> "Please note",
   - Fix typos: "recieved" -> "received", "Please not" -> "Please note",
     and fix lintian(1) warning ""hyphen-used-as-minus-sign", too.
     and fix lintian(1) warning ""hyphen-used-as-minus-sign", too.
-  - Really include _all_ patchtes to build the Anope module into the
+  - Really include _all_ patches to build the Anope module into the
     distribution archive ... ooops!
     distribution archive ... ooops!
-  - getpid.sh: Fix testcase error for Debian using sbuild(1).
+  - getpid.sh: Fix test case error for Debian using sbuild(1).
   - Don't log "ngIRCd hello message" two times when starting up.
   - Don't log "ngIRCd hello message" two times when starting up.
 
 
 ngIRCd Release 19 (2012-02-29)
 ngIRCd Release 19 (2012-02-29)
@@ -28,7 +56,7 @@ ngIRCd Release 19 (2012-02-29)
   - Fix building ngIRCd with old gcc versions (e. g. 2.7.2).
   - Fix building ngIRCd with old gcc versions (e. g. 2.7.2).
   - Correctly re-open syslog logging after reading of configuration
   - Correctly re-open syslog logging after reading of configuration
     file: Syslog logging has been initialized before reading the
     file: Syslog logging has been initialized before reading the
-    configuraton, so ngIRCd always used the default facility and ignored
+    configuration, so ngIRCd always used the default facility and ignored
     the "SyslogFacility" configuration option ...
     the "SyslogFacility" configuration option ...
     Thanks to Patrik Schindler for reporting this issue!
     Thanks to Patrik Schindler for reporting this issue!
 
 
@@ -39,7 +67,7 @@ ngIRCd Release 19 (2012-02-29)
   - Log more information about server synchronization.
   - Log more information about server synchronization.
   - Update preliminary ngIRCd protocol module for Anope 1.9.6, which now
   - Update preliminary ngIRCd protocol module for Anope 1.9.6, which now
     is the only supported version.
     is the only supported version.
-  - New numeric RPL_WHOISHOST_MSG(378), which returns the DNS hostname
+  - New numeric RPL_WHOISHOST_MSG(378), which returns the DNS host name
     (if available) and the IP address of a client in the WHOIS reply.
     (if available) and the IP address of a client in the WHOIS reply.
     Only the user itself and local IRC operators get this numeric.
     Only the user itself and local IRC operators get this numeric.
   - Implement channel exception list (mode 'e'). This allows a channel
   - Implement channel exception list (mode 'e'). This allows a channel
@@ -85,7 +113,7 @@ ngIRCd Release 19 (2012-02-29)
     commands: this reduces the possibility of flooding channels with
     commands: this reduces the possibility of flooding channels with
     commands like "PRIVMSG/NOTICE #a,#n,#c,... :message" a little bit.
     commands like "PRIVMSG/NOTICE #a,#n,#c,... :message" a little bit.
     Problem noticed by Cahata, thanks!
     Problem noticed by Cahata, thanks!
-  - Display correct error message when "Server{UID|GID}" variabe in the
+  - Display correct error message when "Server{UID|GID}" variable in the
     configuration file is invalid (not a number and no existing user).
     configuration file is invalid (not a number and no existing user).
   - Update Copyright notices for 2012 :-)
   - Update Copyright notices for 2012 :-)
   - JOIN command: don't stop handling of channel lists when a single
   - JOIN command: don't stop handling of channel lists when a single
@@ -127,8 +155,8 @@ ngIRCd Release 19 (2012-02-29)
   - ./configure: Fix logic and quoting of poll() detection code: only use
   - ./configure: Fix logic and quoting of poll() detection code: only use
     poll() when poll.h exists as well.
     poll() when poll.h exists as well.
   - Suppress 'Can't create pre-defined channel: invalid name: ""' message.
   - Suppress 'Can't create pre-defined channel: invalid name: ""' message.
-  - whois-test: handle local hostname = "localhost.localdomain" using the
-    pattern "localhost*" for valid local hostnames.
+  - whois-test: handle local host name = "localhost.localdomain" using the
+    pattern "localhost*" for valid local host names.
   - sample-ngircd.conf: show correct default for "PAM" variable: The
   - sample-ngircd.conf: show correct default for "PAM" variable: The
     default of "PAM" is "yes" when ngIRCd has been configured to use it,
     default of "PAM" is "yes" when ngIRCd has been configured to use it,
     so show the correct default value in the sample configuration file.
     so show the correct default value in the sample configuration file.
@@ -242,8 +270,8 @@ ngIRCd Release 18 (2011-07-10)
     variable description.
     variable description.
   - Don't use "the.net" in sample-ngircd.conf, use "example.net".
   - Don't use "the.net" in sample-ngircd.conf, use "example.net".
   - Terminate incoming connections on HTTP commands "GET" and "POST".
   - Terminate incoming connections on HTTP commands "GET" and "POST".
-  - New configuration option "CloakHost": when set, this hostname is used for
-    every client instead of the real DNS hostname (or IP address).
+  - New configuration option "CloakHost": when set, this host name is used for
+    every client instead of the real DNS host name (or IP address).
   - New configuration option "CloakUserToNick": when enabled, ngIRCd sets
   - New configuration option "CloakUserToNick": when enabled, ngIRCd sets
     every clients' user name to their nick name and hides the user name
     every clients' user name to their nick name and hides the user name
     supplied by the IRC client.
     supplied by the IRC client.
@@ -348,7 +376,7 @@ ngIRCd Release 17 (2010-11-07)
   - configure script: correctly indent IPv6 yes/no summary output.
   - configure script: correctly indent IPv6 yes/no summary output.
   - Don't reset My_Connections[Idx].lastping when reading data, so the
   - Don't reset My_Connections[Idx].lastping when reading data, so the
     client lag debug-output is working again.
     client lag debug-output is working again.
-  - Implement user mode "x": hostname cloaking (closes: #102).
+  - Implement user mode "x": host name cloaking (closes: #102).
   - Make configure switch "--docdir" work (closes: #108).
   - Make configure switch "--docdir" work (closes: #108).
   - Reformat and update FAQ.txt a little bit.
   - Reformat and update FAQ.txt a little bit.
   - INSTALL: mention SSL, IPv6, and changed handling of MotdFile.
   - INSTALL: mention SSL, IPv6, and changed handling of MotdFile.
@@ -453,7 +481,7 @@ ngIRCd Release 14.1 (2009-05-05)
   - Allow ping timeout quit messages to show the timeout value.
   - Allow ping timeout quit messages to show the timeout value.
   - Fix error handling on compressed links.
   - Fix error handling on compressed links.
   - Fix server list announcement.
   - Fix server list announcement.
-  - Do not remove hostnames from info text.
+  - Do not remove host names from info text.
 
 
 ngIRCd Release 14 (2009-04-20)
 ngIRCd Release 14 (2009-04-20)
 
 
@@ -549,7 +577,7 @@ ngIRCd 0.12.0 (2008-05-13)
   - RPL_WHOREPLY messages generated by IRC_WHO didn't include flags (*,@,+).
   - RPL_WHOREPLY messages generated by IRC_WHO didn't include flags (*,@,+).
     (Dana Dahlstrom)
     (Dana Dahlstrom)
   - IRC_WHO now supports search patterns and will test this against user
   - IRC_WHO now supports search patterns and will test this against user
-    nickname/servername/hostname, etc. as required by RFC 2812, Section 3.6.1.
+    nickname/server name/host name, etc. as required by RFC 2812, Section 3.6.1.
     (reported by Dana Dahlstrom)
     (reported by Dana Dahlstrom)
   - Add test cases for "WHO" command. (Dana Dahlstrom)
   - Add test cases for "WHO" command. (Dana Dahlstrom)
   - Implement RFC 2812 handling of "0" argument to 'JOIN': must be treated
   - Implement RFC 2812 handling of "0" argument to 'JOIN': must be treated
@@ -572,7 +600,7 @@ ngIRCd 0.11.0 (2008-01-15)
     ngircd to crash [from HEAD]. (CVE-2008-0285)
     ngircd to crash [from HEAD]. (CVE-2008-0285)
   
   
   ngIRCd 0.11.0-pre1 (2008-01-02)
   ngIRCd 0.11.0-pre1 (2008-01-02)
-  - Use dotted-decimal IP address if hostname is >= 64.
+  - Use dotted-decimal IP address if host name is >= 64.
   - Add support for /STAT u (server uptime) command.
   - Add support for /STAT u (server uptime) command.
   - New [Server] configuration Option "Bind" allows to specify
   - New [Server] configuration Option "Bind" allows to specify
     the source IP address to use when connecting to remote server.
     the source IP address to use when connecting to remote server.
@@ -798,7 +826,7 @@ ngIRCd 0.8.0 (2004-06-26)
     original ircd exactly: the unnecessary but missing ":" before the last
     original ircd exactly: the unnecessary but missing ":" before the last
     parameter has been added.
     parameter has been added.
   - Fixed TRACE: don't output "Serv" lines for ourself; display more info.
   - Fixed TRACE: don't output "Serv" lines for ourself; display more info.
-  - Results of the resolver (hostnames and IDENT names) are discarded after
+  - Results of the resolver (host names and IDENT names) are discarded after
     the client is successfully registered with the server.
     the client is successfully registered with the server.
   - Better logging while establishing and shutting down connections.
   - Better logging while establishing and shutting down connections.
   - The type of service (TOS) of all sockets is set to "interactive" now.
   - The type of service (TOS) of all sockets is set to "interactive" now.

+ 26 - 1
INSTALL

@@ -93,7 +93,8 @@ automake ("configure") should be no problem.
 The normal installation procedure after getting (and expanding) the source
 The normal installation procedure after getting (and expanding) the source
 files (using a distribution archive or GIT) is as following:
 files (using a distribution archive or GIT) is as following:
 
 
-  1) ./autogen.sh	[only necessary when using GIT]
+  0) Satisfy prerequisites
+  1) ./autogen.sh  [only necessary when using GIT]
   2) ./configure
   2) ./configure
   3) make
   3) make
   4) make install
   4) make install
@@ -114,6 +115,30 @@ possible options will be installed there. You'll find its template in the
 doc/ directory: sample-ngircd.conf.
 doc/ directory: sample-ngircd.conf.
 
 
 
 
+0): Satisfy prerequisites
+
+When building from source, you'll need some other software to build ngIRCd:
+for example a working C compiler, make tool, GNU automake and autoconf (only
+when not using a distribution archive), and a few libraries depending on the
+features you want to compile in (like IDENT support, SSL, and PAM).
+
+If you are using one of the "big" operating systems or Linux distributions,
+you can use the following commands to install all the required packages to
+build the sources including all optional features and to run the test suite:
+
+* RedHat / Fedora based distributions:
+
+  yum install \
+    autoconf automake expect gcc glibc-devel gnutls-devel \
+    libident-devel make pam-devel tcp_wrappers-devel telnet zlib-devel
+
+* Debian / Ubuntu based distributions:
+
+  apt-get install \
+    autoconf automake build-essential expect libgnutls-dev \
+    libident-dev libpam-dev libwrap0-dev libz-dev telnet
+
+
 1): "autogen.sh"
 1): "autogen.sh"
 
 
 The first step, autogen.sh, is only necessary if the configure-script isn't
 The first step, autogen.sh, is only necessary if the configure-script isn't

+ 18 - 6
NEWS

@@ -9,9 +9,21 @@
                                   -- NEWS --
                                   -- NEWS --
 
 
 
 
+ngIRCd Release 19.2
+
+  ngIRCd 19.2~rc1 (2012-06-13)
+  - New configuration option "CloakHostModeX" to configure the hostname
+    that gets used for IRC clients which have user mode "+x" enabled.
+    Up to now, the name of the IRC server itself has been used for this,
+    which still is the default when "CloakHostModeX" isn't set.
+  - Add instructions for setting up Atheme IRC services.
+  - Implement support for IRC capability handling, the new "CAP" command,
+    and capablity "multi-prefix" which allows both the NAME and	WHO command
+    handlers to return more than one "class prefix" to the client.
+
 ngIRCd Release 19.1 (2012-03-19)
 ngIRCd Release 19.1 (2012-03-19)
 
 
-  - Really include _all_ patchtes to build the Anope module into the
+  - Really include _all_ patches to build the Anope module into the
     distribution archive ... ooops!
     distribution archive ... ooops!
 
 
 ngIRCd Release 19 (2012-02-29)
 ngIRCd Release 19 (2012-02-29)
@@ -19,7 +31,7 @@ ngIRCd Release 19 (2012-02-29)
   ngIRCd 19~rc1 (2012-02-12)
   ngIRCd 19~rc1 (2012-02-12)
   - Update preliminary ngIRCd protocol module for Anope 1.9.6, which now
   - Update preliminary ngIRCd protocol module for Anope 1.9.6, which now
     is the only supported version.
     is the only supported version.
-  - New numeric RPL_WHOISHOST_MSG(378), which returns the DNS hostname
+  - New numeric RPL_WHOISHOST_MSG(378), which returns the DNS host name
     (if available) and the IP address of a client in the WHOIS reply.
     (if available) and the IP address of a client in the WHOIS reply.
     Only the user itself and local IRC operators get this numeric.
     Only the user itself and local IRC operators get this numeric.
   - Implement channel exception list (mode 'e'). This allows a channel
   - Implement channel exception list (mode 'e'). This allows a channel
@@ -134,8 +146,8 @@ ngIRCd Release 18 (2011-07-10)
     (booleans, text strings, integer numbers) and add type information to each
     (booleans, text strings, integer numbers) and add type information to each
     variable description.
     variable description.
   - Terminate incoming connections on HTTP commands "GET" and "POST".
   - Terminate incoming connections on HTTP commands "GET" and "POST".
-  - New configuration option "CloakHost": when set, this hostname is used for
-    every client instead of the real DNS hostname (or IP address).
+  - New configuration option "CloakHost": when set, this host name is used for
+    every client instead of the real DNS host name (or IP address).
   - New configuration option "CloakUserToNick": when enabled, ngIRCd sets
   - New configuration option "CloakUserToNick": when enabled, ngIRCd sets
     every clients' user name to their nick name and hides the user name
     every clients' user name to their nick name and hides the user name
     supplied by the IRC client.
     supplied by the IRC client.
@@ -187,7 +199,7 @@ ngIRCd Release 17 (2010-11-07)
   - Enable the daemon to disable and enable "debug mode" on runtime using
   - Enable the daemon to disable and enable "debug mode" on runtime using
     signal SIGUSR1, when debug code is compiled in, not only on startup
     signal SIGUSR1, when debug code is compiled in, not only on startup
     using the command line parameters.
     using the command line parameters.
-  - Implement user mode "x": hostname cloaking (closes: #102).
+  - Implement user mode "x": host name cloaking (closes: #102).
   - Change MOTD file handling: ngIRCd now caches the contens of the MOTD
   - Change MOTD file handling: ngIRCd now caches the contens of the MOTD
     file, so the daemon now requires a HUP signal or REHASH command to
     file, so the daemon now requires a HUP signal or REHASH command to
     re-read the MOTD file when its content changed.
     re-read the MOTD file when its content changed.
@@ -292,7 +304,7 @@ ngIRCd 0.12.0 (2008-05-13)
   - Implemented IRC commands INFO, SUMMON (dummy), and USERS (dummy) and
   - Implemented IRC commands INFO, SUMMON (dummy), and USERS (dummy) and
     enhanced test suite to check these commands. (Dana Dahlstrom)
     enhanced test suite to check these commands. (Dana Dahlstrom)
   - IRC_WHO now supports search patterns and will test this against user
   - IRC_WHO now supports search patterns and will test this against user
-    nickname/servername/hostname, etc. as required by RFC 2812, Section 3.6.1.
+    nickname/server name/host name, etc. as required by RFC 2812, Section 3.6.1.
     (reported by Dana Dahlstrom)
     (reported by Dana Dahlstrom)
   - Implement RFC 2812 handling of "0" argument to 'JOIN': must be treated
   - Implement RFC 2812 handling of "0" argument to 'JOIN': must be treated
     as if the user had sent PART commands for all channels the user is a
     as if the user had sent PART commands for all channels the user is a

+ 10 - 10
configure

@@ -1,6 +1,6 @@
 #! /bin/sh
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.67 for ngircd 19.1.
+# Generated by GNU Autoconf 2.67 for ngircd 19.2~rc1.
 #
 #
 #
 #
 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -549,8 +549,8 @@ MAKEFLAGS=
 # Identity of this package.
 # Identity of this package.
 PACKAGE_NAME='ngircd'
 PACKAGE_NAME='ngircd'
 PACKAGE_TARNAME='ngircd'
 PACKAGE_TARNAME='ngircd'
-PACKAGE_VERSION='19.1'
-PACKAGE_STRING='ngircd 19.1'
+PACKAGE_VERSION='19.2~rc1'
+PACKAGE_STRING='ngircd 19.2~rc1'
 PACKAGE_BUGREPORT=''
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 PACKAGE_URL=''
 
 
@@ -1267,7 +1267,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
   cat <<_ACEOF
-\`configure' configures ngircd 19.1 to adapt to many kinds of systems.
+\`configure' configures ngircd 19.2~rc1 to adapt to many kinds of systems.
 
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
 
@@ -1338,7 +1338,7 @@ fi
 
 
 if test -n "$ac_init_help"; then
 if test -n "$ac_init_help"; then
   case $ac_init_help in
   case $ac_init_help in
-     short | recursive ) echo "Configuration of ngircd 19.1:";;
+     short | recursive ) echo "Configuration of ngircd 19.2~rc1:";;
    esac
    esac
   cat <<\_ACEOF
   cat <<\_ACEOF
 
 
@@ -1448,7 +1448,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
 if $ac_init_version; then
   cat <<\_ACEOF
   cat <<\_ACEOF
-ngircd configure 19.1
+ngircd configure 19.2~rc1
 generated by GNU Autoconf 2.67
 generated by GNU Autoconf 2.67
 
 
 Copyright (C) 2010 Free Software Foundation, Inc.
 Copyright (C) 2010 Free Software Foundation, Inc.
@@ -1924,7 +1924,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 running configure, to aid debugging if configure makes a mistake.
 
 
-It was created by ngircd $as_me 19.1, which was
+It was created by ngircd $as_me 19.2~rc1, which was
 generated by GNU Autoconf 2.67.  Invocation command line was
 generated by GNU Autoconf 2.67.  Invocation command line was
 
 
   $ $0 $@
   $ $0 $@
@@ -2850,7 +2850,7 @@ fi
 
 
 # Define the identity of the package.
 # Define the identity of the package.
  PACKAGE='ngircd'
  PACKAGE='ngircd'
- VERSION='19.1'
+ VERSION='19.2~rc1'
 
 
 
 
 cat >>confdefs.h <<_ACEOF
 cat >>confdefs.h <<_ACEOF
@@ -7475,7 +7475,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 # values after options handling.
 ac_log="
 ac_log="
-This file was extended by ngircd $as_me 19.1, which was
+This file was extended by ngircd $as_me 19.2~rc1, which was
 generated by GNU Autoconf 2.67.  Invocation command line was
 generated by GNU Autoconf 2.67.  Invocation command line was
 
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_FILES    = $CONFIG_FILES
@@ -7541,7 +7541,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
 ac_cs_version="\\
-ngircd config.status 19.1
+ngircd config.status 19.2~rc1
 configured by $0, generated by GNU Autoconf 2.67,
 configured by $0, generated by GNU Autoconf 2.67,
   with options \\"\$ac_cs_config\\"
   with options \\"\$ac_cs_config\\"
 
 

+ 6 - 0
contrib/Debian/changelog

@@ -1,3 +1,9 @@
+ngircd (19.2~rc1-0ab1) unstable; urgency=low
+
+  * New "upstream" release candidate 1 for ngIRC Release 19.2.
+
+ -- Alexander Barton <alex@barton.de>  Wed, 13 Jun 2012 10:59:34 +0200
+
 ngircd (19.1-0ab1) unstable; urgency=low
 ngircd (19.1-0ab1) unstable; urgency=low
 
 
   * New "upstream" release: ngIRCd 19.1.
   * New "upstream" release: ngIRCd 19.1.

+ 40 - 8
contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj

@@ -41,6 +41,9 @@
 		FAA3D27B0F139CDC00B2447E /* conn-ssl.c in Sources */ = {isa = PBXBuildFile; fileRef = FAA3D2790F139CDC00B2447E /* conn-ssl.c */; };
 		FAA3D27B0F139CDC00B2447E /* conn-ssl.c in Sources */ = {isa = PBXBuildFile; fileRef = FAA3D2790F139CDC00B2447E /* conn-ssl.c */; };
 		FAA97C57124A271400D5BBA9 /* sighandlers.c in Sources */ = {isa = PBXBuildFile; fileRef = FAA97C55124A271400D5BBA9 /* sighandlers.c */; };
 		FAA97C57124A271400D5BBA9 /* sighandlers.c in Sources */ = {isa = PBXBuildFile; fileRef = FAA97C55124A271400D5BBA9 /* sighandlers.c */; };
 		FAACD5F514A6099C006ED74F /* class.c in Sources */ = {isa = PBXBuildFile; fileRef = FAACD5F314A6099C006ED74F /* class.c */; };
 		FAACD5F514A6099C006ED74F /* class.c in Sources */ = {isa = PBXBuildFile; fileRef = FAACD5F314A6099C006ED74F /* class.c */; };
+		FAD5853215271AAB00328741 /* client-cap.c in Sources */ = {isa = PBXBuildFile; fileRef = FAD5853015271AAB00328741 /* client-cap.c */; };
+		FAD5853515271AB800328741 /* irc-cap.c in Sources */ = {isa = PBXBuildFile; fileRef = FAD5853315271AB800328741 /* irc-cap.c */; };
+		FAD5853815272C2600328741 /* login.c in Sources */ = {isa = PBXBuildFile; fileRef = FAD5853615272C2500328741 /* login.c */; };
 		FAE5CC2E0CF2308A007D69B6 /* numeric.c in Sources */ = {isa = PBXBuildFile; fileRef = FAE5CC2D0CF2308A007D69B6 /* numeric.c */; };
 		FAE5CC2E0CF2308A007D69B6 /* numeric.c in Sources */ = {isa = PBXBuildFile; fileRef = FAE5CC2D0CF2308A007D69B6 /* numeric.c */; };
 /* End PBXBuildFile section */
 /* End PBXBuildFile section */
 
 
@@ -231,6 +234,19 @@
 		FAA97C56124A271400D5BBA9 /* sighandlers.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = sighandlers.h; sourceTree = "<group>"; };
 		FAA97C56124A271400D5BBA9 /* sighandlers.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = sighandlers.h; sourceTree = "<group>"; };
 		FAACD5F314A6099C006ED74F /* class.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = class.c; sourceTree = "<group>"; };
 		FAACD5F314A6099C006ED74F /* class.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = class.c; sourceTree = "<group>"; };
 		FAACD5F414A6099C006ED74F /* class.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = class.h; sourceTree = "<group>"; };
 		FAACD5F414A6099C006ED74F /* class.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = class.h; sourceTree = "<group>"; };
+		FAD5852F15271A7800328741 /* Capabilities.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Capabilities.txt; sourceTree = "<group>"; };
+		FAD5853015271AAB00328741 /* client-cap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "client-cap.c"; sourceTree = "<group>"; };
+		FAD5853115271AAB00328741 /* client-cap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "client-cap.h"; sourceTree = "<group>"; };
+		FAD5853315271AB800328741 /* irc-cap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "irc-cap.c"; sourceTree = "<group>"; };
+		FAD5853415271AB800328741 /* irc-cap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "irc-cap.h"; sourceTree = "<group>"; };
+		FAD5853615272C2500328741 /* login.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = login.c; sourceTree = "<group>"; };
+		FAD5853715272C2500328741 /* login.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = login.h; sourceTree = "<group>"; };
+		FAE22BD215270EA300F1A5AB /* Bopm.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bopm.txt; sourceTree = "<group>"; };
+		FAE22BD415270EA300F1A5AB /* Contributing.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Contributing.txt; sourceTree = "<group>"; };
+		FAE22BD515270EB500F1A5AB /* HowToRelease.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = HowToRelease.txt; sourceTree = "<group>"; };
+		FAE22BD615270EB500F1A5AB /* Modes.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Modes.txt; sourceTree = "<group>"; };
+		FAE22BD715270EB500F1A5AB /* PAM.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = PAM.txt; sourceTree = "<group>"; };
+		FAE22BD815270EC400F1A5AB /* README-Interix.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "README-Interix.txt"; sourceTree = "<group>"; };
 		FAE5CC2C0CF2308A007D69B6 /* numeric.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = numeric.h; sourceTree = "<group>"; };
 		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>"; };
 		FAE5CC2D0CF2308A007D69B6 /* numeric.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = numeric.c; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 /* End PBXFileReference section */
@@ -298,8 +314,7 @@
 		FA322CD70CEF74B1001761B3 /* ngircd */ = {
 		FA322CD70CEF74B1001761B3 /* ngircd */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
-				FAA3D2790F139CDC00B2447E /* conn-ssl.c */,
-				FAA3D27A0F139CDC00B2447E /* conn-ssl.h */,
+				FA322D020CEF74B1001761B3 /* Makefile.am */,
 				FA322CD90CEF74B1001761B3 /* array.c */,
 				FA322CD90CEF74B1001761B3 /* array.c */,
 				FA322CDA0CEF74B1001761B3 /* array.h */,
 				FA322CDA0CEF74B1001761B3 /* array.h */,
 				FA322CDB0CEF74B1001761B3 /* channel.c */,
 				FA322CDB0CEF74B1001761B3 /* channel.c */,
@@ -308,6 +323,8 @@
 				FAACD5F414A6099C006ED74F /* class.h */,
 				FAACD5F414A6099C006ED74F /* class.h */,
 				FA322CDD0CEF74B1001761B3 /* client.c */,
 				FA322CDD0CEF74B1001761B3 /* client.c */,
 				FA322CDE0CEF74B1001761B3 /* client.h */,
 				FA322CDE0CEF74B1001761B3 /* client.h */,
+				FAD5853015271AAB00328741 /* client-cap.c */,
+				FAD5853115271AAB00328741 /* client-cap.h */,
 				FA322CDF0CEF74B1001761B3 /* conf.c */,
 				FA322CDF0CEF74B1001761B3 /* conf.c */,
 				FA322CE00CEF74B1001761B3 /* conf.h */,
 				FA322CE00CEF74B1001761B3 /* conf.h */,
 				FAA3D2780F139CDC00B2447E /* conf-ssl.h */,
 				FAA3D2780F139CDC00B2447E /* conf-ssl.h */,
@@ -317,11 +334,15 @@
 				FA322CE40CEF74B1001761B3 /* conn-zip.h */,
 				FA322CE40CEF74B1001761B3 /* conn-zip.h */,
 				FA322CE50CEF74B1001761B3 /* conn.c */,
 				FA322CE50CEF74B1001761B3 /* conn.c */,
 				FA322CE60CEF74B1001761B3 /* conn.h */,
 				FA322CE60CEF74B1001761B3 /* conn.h */,
+				FAA3D2790F139CDC00B2447E /* conn-ssl.c */,
+				FAA3D27A0F139CDC00B2447E /* conn-ssl.h */,
 				FA322CE70CEF74B1001761B3 /* defines.h */,
 				FA322CE70CEF74B1001761B3 /* defines.h */,
 				FA322CE80CEF74B1001761B3 /* hash.c */,
 				FA322CE80CEF74B1001761B3 /* hash.c */,
 				FA322CE90CEF74B1001761B3 /* hash.h */,
 				FA322CE90CEF74B1001761B3 /* hash.h */,
 				FA322CEA0CEF74B1001761B3 /* io.c */,
 				FA322CEA0CEF74B1001761B3 /* io.c */,
 				FA322CEB0CEF74B1001761B3 /* io.h */,
 				FA322CEB0CEF74B1001761B3 /* io.h */,
+				FAD5853315271AB800328741 /* irc-cap.c */,
+				FAD5853415271AB800328741 /* irc-cap.h */,
 				FA322CEC0CEF74B1001761B3 /* irc-channel.c */,
 				FA322CEC0CEF74B1001761B3 /* irc-channel.c */,
 				FA322CED0CEF74B1001761B3 /* irc-channel.h */,
 				FA322CED0CEF74B1001761B3 /* irc-channel.h */,
 				FA322CEE0CEF74B1001761B3 /* irc-info.c */,
 				FA322CEE0CEF74B1001761B3 /* irc-info.c */,
@@ -344,7 +365,8 @@
 				FA322CFF0CEF74B1001761B3 /* lists.h */,
 				FA322CFF0CEF74B1001761B3 /* lists.h */,
 				FA322D000CEF74B1001761B3 /* log.c */,
 				FA322D000CEF74B1001761B3 /* log.c */,
 				FA322D010CEF74B1001761B3 /* log.h */,
 				FA322D010CEF74B1001761B3 /* log.h */,
-				FA322D020CEF74B1001761B3 /* Makefile.am */,
+				FAD5853615272C2500328741 /* login.c */,
+				FAD5853715272C2500328741 /* login.h */,
 				FA322D030CEF74B1001761B3 /* match.c */,
 				FA322D030CEF74B1001761B3 /* match.c */,
 				FA322D040CEF74B1001761B3 /* match.h */,
 				FA322D040CEF74B1001761B3 /* match.h */,
 				FA322D050CEF74B1001761B3 /* messages.h */,
 				FA322D050CEF74B1001761B3 /* messages.h */,
@@ -563,18 +585,25 @@
 		FA322D970CEF752C001761B3 /* doc */ = {
 		FA322D970CEF752C001761B3 /* doc */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
-				FAA3D2800F139D1500B2447E /* Services.txt */,
-				FA407F380DB15AC700271AF1 /* GIT.txt */,
-				FA322D9A0CEF752C001761B3 /* FAQ.txt */,
 				FA322D9B0CEF752C001761B3 /* Makefile.am */,
 				FA322D9B0CEF752C001761B3 /* Makefile.am */,
+				FAE22BD215270EA300F1A5AB /* Bopm.txt */,
+				FAD5852F15271A7800328741 /* Capabilities.txt */,
+				FAE22BD415270EA300F1A5AB /* Contributing.txt */,
+				FA322D9A0CEF752C001761B3 /* FAQ.txt */,
+				FA407F380DB15AC700271AF1 /* GIT.txt */,
+				FAE22BD515270EB500F1A5AB /* HowToRelease.txt */,
+				FAE22BD615270EB500F1A5AB /* Modes.txt */,
+				FAE22BD715270EB500F1A5AB /* PAM.txt */,
 				FA322D9C0CEF752C001761B3 /* Platforms.txt */,
 				FA322D9C0CEF752C001761B3 /* Platforms.txt */,
 				FA322D9D0CEF752C001761B3 /* Protocol.txt */,
 				FA322D9D0CEF752C001761B3 /* Protocol.txt */,
 				FA322D9E0CEF752C001761B3 /* README-AUX.txt */,
 				FA322D9E0CEF752C001761B3 /* README-AUX.txt */,
 				FA322D9F0CEF752C001761B3 /* README-BeOS.txt */,
 				FA322D9F0CEF752C001761B3 /* README-BeOS.txt */,
+				FAE22BD815270EC400F1A5AB /* README-Interix.txt */,
 				FA322DA00CEF752C001761B3 /* RFC.txt */,
 				FA322DA00CEF752C001761B3 /* RFC.txt */,
+				FAA3D2800F139D1500B2447E /* Services.txt */,
+				FA322DA90CEF752C001761B3 /* SSL.txt */,
 				FA77849A133FB9FF00740057 /* sample-ngircd.conf.tmpl */,
 				FA77849A133FB9FF00740057 /* sample-ngircd.conf.tmpl */,
 				FA322DA20CEF752C001761B3 /* src */,
 				FA322DA20CEF752C001761B3 /* src */,
-				FA322DA90CEF752C001761B3 /* SSL.txt */,
 			);
 			);
 			name = doc;
 			name = doc;
 			path = ../../doc;
 			path = ../../doc;
@@ -653,7 +682,7 @@
 		08FB7793FE84155DC02AAC07 /* Project object */ = {
 		08FB7793FE84155DC02AAC07 /* Project object */ = {
 			isa = PBXProject;
 			isa = PBXProject;
 			attributes = {
 			attributes = {
-				LastUpgradeCheck = 0420;
+				LastUpgradeCheck = 0430;
 			};
 			};
 			buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "ngIRCd" */;
 			buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "ngIRCd" */;
 			compatibilityVersion = "Xcode 3.2";
 			compatibilityVersion = "Xcode 3.2";
@@ -718,6 +747,9 @@
 				FA2D564A11EA158B00D37A35 /* pam.c in Sources */,
 				FA2D564A11EA158B00D37A35 /* pam.c in Sources */,
 				FAA97C57124A271400D5BBA9 /* sighandlers.c in Sources */,
 				FAA97C57124A271400D5BBA9 /* sighandlers.c in Sources */,
 				FAACD5F514A6099C006ED74F /* class.c in Sources */,
 				FAACD5F514A6099C006ED74F /* class.c in Sources */,
+				FAD5853215271AAB00328741 /* client-cap.c in Sources */,
+				FAD5853515271AB800328741 /* irc-cap.c in Sources */,
+				FAD5853815272C2600328741 /* login.c in Sources */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		};

+ 1 - 1
contrib/ngircd.spec

@@ -1,5 +1,5 @@
 %define name    ngircd
 %define name    ngircd
-%define version 19.1
+%define version 19.2~rc1
 %define release 1
 %define release 1
 %define prefix  %{_prefix}
 %define prefix  %{_prefix}
 
 

+ 30 - 22
contrib/platformtest.sh

@@ -1,7 +1,7 @@
 #!/bin/sh
 #!/bin/sh
 #
 #
 # ngIRCd -- The Next Generation IRC Daemon
 # ngIRCd -- The Next Generation IRC Daemon
-# Copyright (c)2001-2010 Alexander Barton <alex@barton.de>
+# Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors
 #
 #
 # This program is free software; you can redistribute it and/or modify
 # 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
 # it under the terms of the GNU General Public License as published by
@@ -21,13 +21,16 @@ PLATFORM=
 COMPILER="unknown"
 COMPILER="unknown"
 VERSION="unknown"
 VERSION="unknown"
 DATE=`date "+%y-%m-%d"`
 DATE=`date "+%y-%m-%d"`
-
-CONFIGURE=
-MAKE=
-CHECK=
-RUN=
 COMMENT=
 COMMENT=
 
 
+R_CONFIGURE=
+R_MAKE=
+R_CHECK=
+R_RUN=
+
+[ -n "$MAKE" ] || MAKE="make"
+export MAKE CC
+
 while [ $# -gt 0 ]; do
 while [ $# -gt 0 ]; do
 	case "$1" in
 	case "$1" in
 		"-v")
 		"-v")
@@ -61,20 +64,20 @@ if [ -r ./configure ]; then
 	echo "$NAME: Running \"./configure\" script ..."
 	echo "$NAME: Running \"./configure\" script ..."
 	[ -n "$VERBOSE" ] && ./configure || ./configure >/dev/null
 	[ -n "$VERBOSE" ] && ./configure || ./configure >/dev/null
 	if [ $? -eq 0 -a -r ./Makefile ]; then
 	if [ $? -eq 0 -a -r ./Makefile ]; then
-		CONFIGURE=1
-		echo "$NAME: Running \"make\" ..."
-		[ -n "$VERBOSE" ] && make || make >/dev/null
+		R_CONFIGURE=1
+		echo "$NAME: Running \"$MAKE\" ..."
+		[ -n "$VERBOSE" ] && "$MAKE" || "$MAKE" >/dev/null
 		if [ $? -eq 0 -a -x src/ngircd/ngircd ]; then
 		if [ $? -eq 0 -a -x src/ngircd/ngircd ]; then
-			MAKE=1
-			echo "$NAME: Running \"make check\" ..."
-			[ -n "$VERBOSE" ] && make check || make check >/dev/null
+			R_MAKE=1
+			echo "$NAME: Running \"$MAKE check\" ..."
+			[ -n "$VERBOSE" ] && "$MAKE" check || "$MAKE" check >/dev/null
 			if [ $? -eq 0 ]; then
 			if [ $? -eq 0 ]; then
-				CHECK=1
-				RUN=$CHECK
+				R_CHECK=1
+				R_RUN=$R_CHECK
 			else
 			else
 				./src/ngircd/ngircd --help 2>/dev/null \
 				./src/ngircd/ngircd --help 2>/dev/null \
 				 | grep "^ngircd" >/dev/null
 				 | grep "^ngircd" >/dev/null
-				[ $? -eq 0 ] && RUN=1
+				[ $? -eq 0 ] && R_RUN=1
 			fi
 			fi
 		fi
 		fi
 	fi
 	fi
@@ -96,9 +99,14 @@ if [ -r "Makefile" ]; then
 	CC=$(grep "^CC = " Makefile | cut -d' ' -f3)
 	CC=$(grep "^CC = " Makefile | cut -d' ' -f3)
 	$CC --version 2>&1 | grep -i "GCC" >/dev/null
 	$CC --version 2>&1 | grep -i "GCC" >/dev/null
 	if [ $? -eq 0 ]; then
 	if [ $? -eq 0 ]; then
-		COMPILER=$($CC --version | head -1 \
-		  | cut -d')' -f2 | cut -d' ' -f2)
-		COMPILER="gcc $COMPILER"
+		$CC --version 2>&1 | grep -i "Open64" >/dev/null
+		if [ $? -eq 0 ]; then
+			COMPILER="Open64"
+		else
+			COMPILER=$($CC --version | head -1 \
+			  | cut -d')' -f2 | cut -d' ' -f2)
+			COMPILER="gcc $COMPILER"
+		fi
 	else
 	else
 		case "$CC" in
 		case "$CC" in
 		  gcc*)
 		  gcc*)
@@ -130,10 +138,10 @@ else
 	[ $? -eq 0 ] && COMMENT="(3)"
 	[ $? -eq 0 ] && COMMENT="(3)"
 fi
 fi
 
 
-[ -n "$CONFIGURE" ] && C="Y" || C="N"
-[ -n "$MAKE" ] && M="Y" || M="N"
-[ -n "$CHECK" ] && T="Y" || T="N"
-[ -n "$RUN" ] && R="Y" || R="N"
+[ -n "$R_CONFIGURE" ] && C="Y" || C="N"
+[ -n "$R_MAKE" ] && M="Y" || M="N"
+[ -n "$R_CHECK" ] && T="Y" || T="N"
+[ -n "$R_RUN" ] && R="Y" || R="N"
 [ -n "$COMMENT" ] && COMMENT=" $COMMENT"
 [ -n "$COMMENT" ] && COMMENT=" $COMMENT"
 
 
 echo
 echo

+ 23 - 0
doc/Capabilities.txt

@@ -0,0 +1,23 @@
+
+                     ngIRCd - Next Generation IRC Server
+                           http://ngircd.barton.de/
+
+               (c)2001-2012 Alexander Barton and Contributors.
+               ngIRCd is free software and published under the
+                   terms of the GNU General Public License.
+
+                            -- Capabilities.txt --
+
+
+This document lists and describes the "IRC capabilities" that ngIRCd supports
+and can be requested by a IRC/IRCv3 client that supports the "CAP" command.
+
+ngIRCd implements the "IRC Client Capabilities Extension" as described here:
+<http://www.leeh.co.uk/draft-mitchell-irc-capabilities-02.html>
+
+
+I. Supported Capabilities
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+None. At the moment, ngIRCd supports the "CAP" command and its sub-commands
+but offers no capabilities that could be requested by a client.

+ 11 - 3
doc/FAQ.txt

@@ -64,11 +64,19 @@ A: ngIRCd does not write its own log file. Instead, ngIRCd uses syslog(3).
 
 
 Q: I cannot connect to remote peers when I use the chroot option, the
 Q: I cannot connect to remote peers when I use the chroot option, the
    following is logged: "Can't resolve example.com: unknown error!".
    following is logged: "Can't resolve example.com: unknown error!".
+A: see next question blow ...
+
+Q: When running ngIRCd inside a chroot, no IP addresses can be translated
+   in DNS names, errors like "Name or service not known" are logged.
 A: On Linux/glibc with chroot enabled you need to put some libraries inside
 A: On Linux/glibc with chroot enabled you need to put some libraries inside
    the chroot as well, notably libnss_dns; maybe others. Unfortunately, even
    the chroot as well, notably libnss_dns; maybe others. Unfortunately, even
-   linking ngIRCd statically does not help this. The only known workaround
-   is to either disable chroot support or to link against dietlibc instead
-   of glibc. (tnx to Sebastian Siewior)
+   linking ngIRCd statically does not help this. So you can either copy
+   all the required files into the chroot directory:
+     $ mkdir -p ./chroot/etc ./chroot/lib
+     $ cp -a /etc/hosts /etc/resolv.conf /etc/nsswitch.conf ./chroot/etc/
+     $ cp -a /lib/libresolv* /lib/libnss_* ./chroot/lib/
+   Or you can try to link ngIRCd against an other C library (like dietlibc)
+   that doesn't depend on NSS modules and/or these files.
 
 
 Q: I have added an [Oper] section, how do i log on as IRC operator?
 Q: I have added an [Oper] section, how do i log on as IRC operator?
 A: You can use the /OPER command in your IRC client to become an IRC operator.
 A: You can use the /OPER command in your IRC client to become an IRC operator.

+ 17 - 4
doc/Makefile.am

@@ -1,6 +1,6 @@
 #
 #
 # ngIRCd -- The Next Generation IRC Daemon
 # ngIRCd -- The Next Generation IRC Daemon
-# Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors
+# Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors
 #
 #
 # This program is free software; you can redistribute it and/or modify
 # 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
 # it under the terms of the GNU General Public License as published by
@@ -16,9 +16,22 @@
 
 
 SUFFIXES = .tmpl
 SUFFIXES = .tmpl
 
 
-static_docs = Bopm.txt FAQ.txt GIT.txt HowToRelease.txt Modes.txt PAM.txt \
-	Platforms.txt Protocol.txt README-AUX.txt README-BeOS.txt \
-	README-Interix.txt RFC.txt SSL.txt Services.txt
+static_docs = \
+	Bopm.txt \
+	Capabilities.txt \
+	FAQ.txt \
+	GIT.txt \
+	HowToRelease.txt \
+	Modes.txt \
+	PAM.txt \
+	Platforms.txt \
+	Protocol.txt \
+	README-AUX.txt \
+	README-BeOS.txt \
+	README-Interix.txt \
+	RFC.txt \
+	Services.txt \
+	SSL.txt
 
 
 doc_templates = sample-ngircd.conf.tmpl
 doc_templates = sample-ngircd.conf.tmpl
 
 

+ 17 - 4
doc/Makefile.in

@@ -17,7 +17,7 @@
 
 
 #
 #
 # ngIRCd -- The Next Generation IRC Daemon
 # ngIRCd -- The Next Generation IRC Daemon
-# Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors
+# Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors
 #
 #
 # This program is free software; you can redistribute it and/or modify
 # 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
 # it under the terms of the GNU General Public License as published by
@@ -207,9 +207,22 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 top_srcdir = @top_srcdir@
 SUFFIXES = .tmpl
 SUFFIXES = .tmpl
-static_docs = Bopm.txt FAQ.txt GIT.txt HowToRelease.txt Modes.txt PAM.txt \
-	Platforms.txt Protocol.txt README-AUX.txt README-BeOS.txt \
-	README-Interix.txt RFC.txt SSL.txt Services.txt
+static_docs = \
+	Bopm.txt \
+	Capabilities.txt \
+	FAQ.txt \
+	GIT.txt \
+	HowToRelease.txt \
+	Modes.txt \
+	PAM.txt \
+	Platforms.txt \
+	Protocol.txt \
+	README-AUX.txt \
+	README-BeOS.txt \
+	README-Interix.txt \
+	RFC.txt \
+	Services.txt \
+	SSL.txt
 
 
 doc_templates = sample-ngircd.conf.tmpl
 doc_templates = sample-ngircd.conf.tmpl
 generated_docs = sample-ngircd.conf
 generated_docs = sample-ngircd.conf

+ 1 - 0
doc/Modes.txt

@@ -43,6 +43,7 @@ users to lists (e.g. "invite list", "ban list"), others have parameters
   mode	since	description
   mode	since	description
 
 
   b	0.5.0	Add/remove a host mask to the ban list.
   b	0.5.0	Add/remove a host mask to the ban list.
+  e	19	Add/remove a host mask to the exception list.
   i	0.5.0	Channel is "invite only".
   i	0.5.0	Channel is "invite only".
   I	0.5.0	Add/remove a host mask to the invite list.
   I	0.5.0	Add/remove a host mask to the invite list.
   k	0.6.0	Channel has a "key" (a password).
   k	0.6.0	Channel has a "key" (a password).

+ 5 - 2
doc/Platforms.txt

@@ -26,6 +26,8 @@ list can be updated. Thanks for your help!
 Platform                    Compiler     ngIRCd     Date     Tester C M T R See
 Platform                    Compiler     ngIRCd     Date     Tester C M T R See
 --------------------------- ------------ ---------- -------- ------ - - - - ---
 --------------------------- ------------ ---------- -------- ------ - - - - ---
 alpha/unknown/netbsd3.0     gcc 3.3.3    CVSHEAD    06-05-07 fw     Y Y Y Y (3)
 alpha/unknown/netbsd3.0     gcc 3.3.3    CVSHEAD    06-05-07 fw     Y Y Y Y (3)
+armv6l/unkn./linux-gnueabi  gcc 4.4.5    19.1       12-06-04 goetz  Y Y Y Y (5)
+armv7l/unkn./linux-gnueabi  gcc 4.4.3    19.1       12-04-29 goetz  Y Y Y Y (5)
 hppa/unknown/openbsd3.5     gcc 2.95.3   CVSHEAD    04-05-25 alex   Y Y Y Y
 hppa/unknown/openbsd3.5     gcc 2.95.3   CVSHEAD    04-05-25 alex   Y Y Y Y
 hppa1.1/unknown/linux-gnu   gcc 3.3.3    0.8.0      04-05-30 alex   Y Y Y Y
 hppa1.1/unknown/linux-gnu   gcc 3.3.3    0.8.0      04-05-30 alex   Y Y Y Y
 hppa2.0/unknown/linux-gnu   gcc 3.3.5    13~rc1     08-12-02 alex   Y Y Y Y
 hppa2.0/unknown/linux-gnu   gcc 3.3.5    13~rc1     08-12-02 alex   Y Y Y Y
@@ -35,7 +37,7 @@ i386/apple/darwin10.8.0     gcc 4.2.1    19         12-02-26 alex   Y Y Y Y (3)
 i386/apple/darwin11.3.0     gcc 4.2.1    19         12-02-26 alex   Y Y Y Y (3)
 i386/apple/darwin11.3.0     gcc 4.2.1    19         12-02-26 alex   Y Y Y Y (3)
 i386/pc/solaris2.9          gcc 3.2.2    CVSHEAD    04-02-24 alex   Y Y Y Y
 i386/pc/solaris2.9          gcc 3.2.2    CVSHEAD    04-02-24 alex   Y Y Y Y
 i386/pc/solaris2.11         gcc 3.4.3    19         12-02-26 alex   Y Y N Y (4)
 i386/pc/solaris2.11         gcc 3.4.3    19         12-02-26 alex   Y Y N Y (4)
-i386/pc/solaris2.11         gcc 4.2.3    18         11-08-17 goetz  Y Y Y Y (4)
+i386/pc/solaris2.11         gcc 4.2.3    19.1       12-05-29 goetz  Y Y Y Y (4)
 i386/unknown/freebsd5.2.1   gcc 3.3.3    0.8.0      04-05-30 alex   Y Y Y Y
 i386/unknown/freebsd5.2.1   gcc 3.3.3    0.8.0      04-05-30 alex   Y Y Y Y
 i386/unknown/freebsd6.2     gcc 3.4.6    19         12-02-26 alex   Y Y Y Y (3)
 i386/unknown/freebsd6.2     gcc 3.4.6    19         12-02-26 alex   Y Y Y Y (3)
 i386/unknown/freebsd7.3     gcc 4.2.1    19         12-02-26 alex   Y Y Y Y (3)
 i386/unknown/freebsd7.3     gcc 4.2.1    19         12-02-26 alex   Y Y Y Y (3)
@@ -49,6 +51,7 @@ i386/unknown/openbsd3.9     gcc 3.3.5    0.10.0-p1  06-08-30 alex   Y Y Y Y (3)
 i386/unknown/openbsd4.1     gcc 3.3.5    16         10-04-11 alex   Y Y Y Y (3)
 i386/unknown/openbsd4.1     gcc 3.3.5    16         10-04-11 alex   Y Y Y Y (3)
 i586/pc/interix3.5          gcc 3.3      19         12-02-29 alex   Y Y N Y
 i586/pc/interix3.5          gcc 3.3      19         12-02-29 alex   Y Y N Y
 i686/pc/cygwin              gcc 3.3.1    0.8.0      04-05-30 alex   Y Y N Y
 i686/pc/cygwin              gcc 3.3.1    0.8.0      04-05-30 alex   Y Y N Y
+i686/pc/linux-gnu           gcc 2.7.2    19.1       12-05-30 goetz  Y Y Y Y (1)
 i686/pc/linux-gnu           gcc 2.95.4   0.8.0      04-05-30 alex   Y Y Y Y (1)
 i686/pc/linux-gnu           gcc 2.95.4   0.8.0      04-05-30 alex   Y Y Y Y (1)
 i686/pc/linux-gnu           gcc 3.3.5    14.1       09-08-04 alex   Y Y Y Y (1)
 i686/pc/linux-gnu           gcc 3.3.5    14.1       09-08-04 alex   Y Y Y Y (1)
 i386/pc/linux-gnu           gcc 4.1.2    13~rc1     08-12-05 alex   Y Y Y Y (1)
 i386/pc/linux-gnu           gcc 4.1.2    13~rc1     08-12-05 alex   Y Y Y Y (1)
@@ -62,7 +65,7 @@ m88k/dg/dgux5.4R3.10        gcc 2.5.8    CVSHEAD    04-03-15 alex   Y Y ? ?
 mipsel/unknown/linux-gnu    gcc 4.1.2    18         11-07-05 goetz  Y Y N Y (1)
 mipsel/unknown/linux-gnu    gcc 4.1.2    18         11-07-05 goetz  Y Y N Y (1)
 mipsel/unknown/linux-gnu    gcc 4.4.5    18         11-07-30 goetz  Y Y Y Y (1)
 mipsel/unknown/linux-gnu    gcc 4.4.5    18         11-07-30 goetz  Y Y Y Y (1)
 powerpc/apple/darwin6.5     gcc 3.1      0.7.x-CVS  03-04-23 alex   Y Y Y Y
 powerpc/apple/darwin6.5     gcc 3.1      0.7.x-CVS  03-04-23 alex   Y Y Y Y
-powerpc/apple/darwin7.9.0   gcc 3.3      CVSHEAD    06-05-07 fw     Y Y Y Y (3)
+powerpc/apple/darwin7.9.0   gcc 3.3      19.1       12-05-22 goetz  Y Y Y Y (3)
 powerpc/apple/darwin8.11.0  gcc 4.0.1    18         11-07-02 goetz  Y Y Y Y (3)
 powerpc/apple/darwin8.11.0  gcc 4.0.1    18         11-07-02 goetz  Y Y Y Y (3)
 powerpc/unknown/linux-gnu   gcc 3.3.3    0.8.0      04-05-30 alex   Y Y Y Y
 powerpc/unknown/linux-gnu   gcc 3.3.3    0.8.0      04-05-30 alex   Y Y Y Y
 powerpc/unknown/openbsd3.6  gcc 2.95.3   0.10.0     06-10-08 alex   Y Y N Y
 powerpc/unknown/openbsd3.6  gcc 2.95.3   0.10.0     06-10-08 alex   Y Y N Y

+ 22 - 2
doc/Services.txt

@@ -14,8 +14,9 @@ But services acting as a "regular server" are supported, either using the IRC
 protocol defined in RFC 1459 or RFC 2812.
 protocol defined in RFC 1459 or RFC 2812.
 
 
 Support for Services has been tested using "IRC Services" version 5.x by
 Support for Services has been tested using "IRC Services" version 5.x by
-Andrew Church (<http://achurch.org/services/>), and a Anope 1.9 using a
-preliminary protocol module for ngIRCd (<http://www.anope.org/>).
+Andrew Church (<http://achurch.org/services/>), Anope 1.9 using a
+preliminary protocol module for ngIRCd (<http://www.anope.org/>), and
+Atheme 7.0.2 or later.
 
 
 This document describes setting up ngIRCd and these services.
 This document describes setting up ngIRCd and these services.
 
 
@@ -93,5 +94,24 @@ The documentation of IRC Services can be found here:
 <http://www.ircservices.za.net/docs/>
 <http://www.ircservices.za.net/docs/>
 
 
 
 
+Setting up Atheme 7.0.2 or later
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Atheme 7.0.2 or later may be used with ngIRCd using the "ngircd" protocol
+module.
+
+The following settings need to be in atheme.conf:
+
+loadmodule "modules/protocol/ngircd";
+
+uplink "server.irc.net" {
+	password = "123abc";
+	port = 6667;
+};
+
+The documentation of Atheme can be found in the doc/ directory of the
+Atheme source distribution.
+
+
 Please let us know if you are successfully using other IRC service packages or
 Please let us know if you are successfully using other IRC service packages or
 which problems you encounter, thanks!
 which problems you encounter, thanks!

+ 7 - 1
doc/sample-ngircd.conf.tmpl

@@ -127,7 +127,13 @@
 	# Set this hostname for every client instead of the real one.
 	# Set this hostname for every client instead of the real one.
 	# Please note: don't use the percentage sign ("%"), it is reserved for
 	# Please note: don't use the percentage sign ("%"), it is reserved for
 	# future extensions!
 	# future extensions!
-	;CloakHost = irc.example.net
+	;CloakHost = cloaked.host
+
+	# Use this hostname for hostname cloaking on clients that have the
+	# user mode "+x" set, instead of the name of the server.
+	# Please note: don't use the percentage sign ("%"), it is reserved for
+	# future extensions!
+	;CloakHostModeX = cloaked.user
 
 
 	# Set every clients' user name to their nick name
 	# Set every clients' user name to their nick name
 	;CloakUserToNick = yes
 	;CloakUserToNick = yes

+ 11 - 0
man/ngircd.conf.5.tmpl

@@ -220,6 +220,17 @@ don't change.
 Don't use the percentage sign ("%"), it is reserved for future extensions!
 Don't use the percentage sign ("%"), it is reserved for future extensions!
 .RE
 .RE
 .TP
 .TP
+\fBCloakHostModeX\fR (string)
+Use this hostname for hostname cloaking on clients that have the user mode
+"+x" set, instead of the name of the server. Default: empty, use the name
+of the server.
+.PP
+.RS
+.B Please note:
+.br
+Don't use the percentage sign ("%"), it is reserved for future extensions!
+.RE
+.TP
 \fBCloakUserToNick\fR (boolean)
 \fBCloakUserToNick\fR (boolean)
 Set every clients' user name to their nick name and hide the one supplied
 Set every clients' user name to their nick name and hide the one supplied
 by the IRC client. Default: no.
 by the IRC client. Default: no.

+ 74 - 11
src/ngircd/Makefile.am

@@ -1,6 +1,6 @@
 #
 #
 # ngIRCd -- The Next Generation IRC Daemon
 # ngIRCd -- The Next Generation IRC Daemon
-# Copyright (c)2001-2010 Alexander Barton (alex@barton.de)
+# Copyright (c)2001-2012 Alexander Barton (alex@barton.de)
 #
 #
 # This program is free software; you can redistribute it and/or modify
 # 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
 # it under the terms of the GNU General Public License as published by
@@ -18,21 +18,84 @@ LINTARGS = -weak -warnunixlib +unixlib -booltype BOOLEAN \
 
 
 sbin_PROGRAMS = ngircd
 sbin_PROGRAMS = ngircd
 
 
-ngircd_SOURCES = ngircd.c array.c channel.c class.c client.c conf.c conn.c \
-	conn-func.c conn-ssl.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 op.c numeric.c pam.c parse.c \
-	proc.c resolve.c sighandlers.c
+ngircd_SOURCES = \
+	ngircd.c \
+	array.c \
+	channel.c \
+	class.c \
+	client.c \
+	client-cap.c \
+	conf.c \
+	conn.c \
+	conn-func.c \
+	conn-ssl.c \
+	conn-zip.c \
+	hash.c \
+	io.c \
+	irc.c \
+	irc-cap.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 \
+	login.c \
+	match.c \
+	numeric.c \
+	op.c \
+	pam.c \
+	parse.c \
+	proc.c \
+	resolve.c \
+	sighandlers.c
 
 
 ngircd_LDFLAGS = -L../portab -L../tool -L../ipaddr
 ngircd_LDFLAGS = -L../portab -L../tool -L../ipaddr
 
 
 ngircd_LDADD = -lngportab -lngtool -lngipaddr
 ngircd_LDADD = -lngportab -lngtool -lngipaddr
 
 
-noinst_HEADERS = ngircd.h array.h channel.h class.h client.h conf.h \
-	conf-ssl.h conn.h conn-func.h conn-ssl.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 numeric.h \
-	op.h pam.h parse.h proc.h resolve.h sighandlers.h defines.h messages.h
+noinst_HEADERS = \
+	ngircd.h \
+	array.h \
+	channel.h \
+	class.h \
+	client.h \
+	client-cap.h \
+	conf.h \
+	conf-ssl.h \
+	conn.h \
+	conn-func.h \
+	conn-ssl.h \
+	conn-zip.h \
+	defines.h \
+	hash.h \
+	io.h \
+	irc.h \
+	irc-cap.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 \
+	login.h \
+	match.h \
+	messages.h \
+	numeric.h \
+	op.h \
+	pam.h \
+	parse.h \
+	proc.h \
+	resolve.h \
+	sighandlers.h
 
 
 clean-local:
 clean-local:
 	rm -f check-version check-help lint.out
 	rm -f check-version check-help lint.out

+ 98 - 23
src/ngircd/Makefile.in

@@ -17,7 +17,7 @@
 
 
 #
 #
 # ngIRCd -- The Next Generation IRC Daemon
 # ngIRCd -- The Next Generation IRC Daemon
-# Copyright (c)2001-2010 Alexander Barton (alex@barton.de)
+# Copyright (c)2001-2012 Alexander Barton (alex@barton.de)
 #
 #
 # This program is free software; you can redistribute it and/or modify
 # 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
 # it under the terms of the GNU General Public License as published by
@@ -64,15 +64,17 @@ am__installdirs = "$(DESTDIR)$(sbindir)"
 PROGRAMS = $(sbin_PROGRAMS)
 PROGRAMS = $(sbin_PROGRAMS)
 am_ngircd_OBJECTS = ngircd$U.$(OBJEXT) array$U.$(OBJEXT) \
 am_ngircd_OBJECTS = ngircd$U.$(OBJEXT) array$U.$(OBJEXT) \
 	channel$U.$(OBJEXT) class$U.$(OBJEXT) client$U.$(OBJEXT) \
 	channel$U.$(OBJEXT) class$U.$(OBJEXT) client$U.$(OBJEXT) \
-	conf$U.$(OBJEXT) conn$U.$(OBJEXT) conn-func$U.$(OBJEXT) \
-	conn-ssl$U.$(OBJEXT) conn-zip$U.$(OBJEXT) hash$U.$(OBJEXT) \
-	io$U.$(OBJEXT) irc$U.$(OBJEXT) irc-channel$U.$(OBJEXT) \
+	client-cap$U.$(OBJEXT) conf$U.$(OBJEXT) conn$U.$(OBJEXT) \
+	conn-func$U.$(OBJEXT) conn-ssl$U.$(OBJEXT) \
+	conn-zip$U.$(OBJEXT) hash$U.$(OBJEXT) io$U.$(OBJEXT) \
+	irc$U.$(OBJEXT) irc-cap$U.$(OBJEXT) irc-channel$U.$(OBJEXT) \
 	irc-info$U.$(OBJEXT) irc-login$U.$(OBJEXT) \
 	irc-info$U.$(OBJEXT) irc-login$U.$(OBJEXT) \
 	irc-mode$U.$(OBJEXT) irc-op$U.$(OBJEXT) irc-oper$U.$(OBJEXT) \
 	irc-mode$U.$(OBJEXT) irc-op$U.$(OBJEXT) irc-oper$U.$(OBJEXT) \
 	irc-server$U.$(OBJEXT) irc-write$U.$(OBJEXT) lists$U.$(OBJEXT) \
 	irc-server$U.$(OBJEXT) irc-write$U.$(OBJEXT) lists$U.$(OBJEXT) \
-	log$U.$(OBJEXT) match$U.$(OBJEXT) op$U.$(OBJEXT) \
-	numeric$U.$(OBJEXT) pam$U.$(OBJEXT) parse$U.$(OBJEXT) \
-	proc$U.$(OBJEXT) resolve$U.$(OBJEXT) sighandlers$U.$(OBJEXT)
+	log$U.$(OBJEXT) login$U.$(OBJEXT) match$U.$(OBJEXT) \
+	numeric$U.$(OBJEXT) op$U.$(OBJEXT) pam$U.$(OBJEXT) \
+	parse$U.$(OBJEXT) proc$U.$(OBJEXT) resolve$U.$(OBJEXT) \
+	sighandlers$U.$(OBJEXT)
 ngircd_OBJECTS = $(am_ngircd_OBJECTS)
 ngircd_OBJECTS = $(am_ngircd_OBJECTS)
 ngircd_DEPENDENCIES =
 ngircd_DEPENDENCIES =
 ngircd_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(ngircd_LDFLAGS) \
 ngircd_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(ngircd_LDFLAGS) \
@@ -212,19 +214,82 @@ INCLUDES = -I$(srcdir)/../portab -I$(srcdir)/../tool -I$(srcdir)/../ipaddr
 LINTARGS = -weak -warnunixlib +unixlib -booltype BOOLEAN \
 LINTARGS = -weak -warnunixlib +unixlib -booltype BOOLEAN \
  -varuse -retvalother -emptyret -unrecog
  -varuse -retvalother -emptyret -unrecog
 
 
-ngircd_SOURCES = ngircd.c array.c channel.c class.c client.c conf.c conn.c \
-	conn-func.c conn-ssl.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 op.c numeric.c pam.c parse.c \
-	proc.c resolve.c sighandlers.c
+ngircd_SOURCES = \
+	ngircd.c \
+	array.c \
+	channel.c \
+	class.c \
+	client.c \
+	client-cap.c \
+	conf.c \
+	conn.c \
+	conn-func.c \
+	conn-ssl.c \
+	conn-zip.c \
+	hash.c \
+	io.c \
+	irc.c \
+	irc-cap.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 \
+	login.c \
+	match.c \
+	numeric.c \
+	op.c \
+	pam.c \
+	parse.c \
+	proc.c \
+	resolve.c \
+	sighandlers.c
 
 
 ngircd_LDFLAGS = -L../portab -L../tool -L../ipaddr
 ngircd_LDFLAGS = -L../portab -L../tool -L../ipaddr
 ngircd_LDADD = -lngportab -lngtool -lngipaddr
 ngircd_LDADD = -lngportab -lngtool -lngipaddr
-noinst_HEADERS = ngircd.h array.h channel.h class.h client.h conf.h \
-	conf-ssl.h conn.h conn-func.h conn-ssl.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 numeric.h \
-	op.h pam.h parse.h proc.h resolve.h sighandlers.h defines.h messages.h
+noinst_HEADERS = \
+	ngircd.h \
+	array.h \
+	channel.h \
+	class.h \
+	client.h \
+	client-cap.h \
+	conf.h \
+	conf-ssl.h \
+	conn.h \
+	conn-func.h \
+	conn-ssl.h \
+	conn-zip.h \
+	defines.h \
+	hash.h \
+	io.h \
+	irc.h \
+	irc-cap.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 \
+	login.h \
+	match.h \
+	messages.h \
+	numeric.h \
+	op.h \
+	pam.h \
+	parse.h \
+	proc.h \
+	resolve.h \
+	sighandlers.h
 
 
 TESTS = check-version check-help
 TESTS = check-version check-help
 all: all-am
 all: all-am
@@ -317,6 +382,7 @@ mostlyclean-kr:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/channel$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/channel$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/class$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/class$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client-cap$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conn$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conn$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conn-func$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conn-func$U.Po@am__quote@
@@ -325,6 +391,7 @@ mostlyclean-kr:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc-cap$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc-channel$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc-channel$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc-info$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc-info$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc-login$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc-login$U.Po@am__quote@
@@ -335,6 +402,7 @@ mostlyclean-kr:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc-write$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc-write$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lists$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lists$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/login$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/match$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/match$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ngircd$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ngircd$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/numeric$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/numeric$U.Po@am__quote@
@@ -368,6 +436,8 @@ class_.c: class.c $(ANSI2KNR)
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/class.c; then echo $(srcdir)/class.c; else echo class.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/class.c; then echo $(srcdir)/class.c; else echo class.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 client_.c: client.c $(ANSI2KNR)
 client_.c: client.c $(ANSI2KNR)
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/client.c; then echo $(srcdir)/client.c; else echo client.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/client.c; then echo $(srcdir)/client.c; else echo client.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+client-cap_.c: client-cap.c $(ANSI2KNR)
+	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/client-cap.c; then echo $(srcdir)/client-cap.c; else echo client-cap.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 conf_.c: conf.c $(ANSI2KNR)
 conf_.c: conf.c $(ANSI2KNR)
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/conf.c; then echo $(srcdir)/conf.c; else echo conf.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/conf.c; then echo $(srcdir)/conf.c; else echo conf.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 conn_.c: conn.c $(ANSI2KNR)
 conn_.c: conn.c $(ANSI2KNR)
@@ -384,6 +454,8 @@ io_.c: io.c $(ANSI2KNR)
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/io.c; then echo $(srcdir)/io.c; else echo io.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/io.c; then echo $(srcdir)/io.c; else echo io.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 irc_.c: irc.c $(ANSI2KNR)
 irc_.c: irc.c $(ANSI2KNR)
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/irc.c; then echo $(srcdir)/irc.c; else echo irc.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/irc.c; then echo $(srcdir)/irc.c; else echo irc.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+irc-cap_.c: irc-cap.c $(ANSI2KNR)
+	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/irc-cap.c; then echo $(srcdir)/irc-cap.c; else echo irc-cap.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 irc-channel_.c: irc-channel.c $(ANSI2KNR)
 irc-channel_.c: irc-channel.c $(ANSI2KNR)
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/irc-channel.c; then echo $(srcdir)/irc-channel.c; else echo irc-channel.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/irc-channel.c; then echo $(srcdir)/irc-channel.c; else echo irc-channel.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 irc-info_.c: irc-info.c $(ANSI2KNR)
 irc-info_.c: irc-info.c $(ANSI2KNR)
@@ -404,6 +476,8 @@ lists_.c: lists.c $(ANSI2KNR)
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/lists.c; then echo $(srcdir)/lists.c; else echo lists.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/lists.c; then echo $(srcdir)/lists.c; else echo lists.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 log_.c: log.c $(ANSI2KNR)
 log_.c: log.c $(ANSI2KNR)
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/log.c; then echo $(srcdir)/log.c; else echo log.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/log.c; then echo $(srcdir)/log.c; else echo log.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+login_.c: login.c $(ANSI2KNR)
+	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/login.c; then echo $(srcdir)/login.c; else echo login.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 match_.c: match.c $(ANSI2KNR)
 match_.c: match.c $(ANSI2KNR)
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/match.c; then echo $(srcdir)/match.c; else echo match.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/match.c; then echo $(srcdir)/match.c; else echo match.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 ngircd_.c: ngircd.c $(ANSI2KNR)
 ngircd_.c: ngircd.c $(ANSI2KNR)
@@ -423,12 +497,13 @@ resolve_.c: resolve.c $(ANSI2KNR)
 sighandlers_.c: sighandlers.c $(ANSI2KNR)
 sighandlers_.c: sighandlers.c $(ANSI2KNR)
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/sighandlers.c; then echo $(srcdir)/sighandlers.c; else echo sighandlers.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/sighandlers.c; then echo $(srcdir)/sighandlers.c; else echo sighandlers.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 array_.$(OBJEXT) channel_.$(OBJEXT) class_.$(OBJEXT) client_.$(OBJEXT) \
 array_.$(OBJEXT) channel_.$(OBJEXT) class_.$(OBJEXT) client_.$(OBJEXT) \
-conf_.$(OBJEXT) conn_.$(OBJEXT) conn-func_.$(OBJEXT) \
-conn-ssl_.$(OBJEXT) conn-zip_.$(OBJEXT) hash_.$(OBJEXT) io_.$(OBJEXT) \
-irc_.$(OBJEXT) irc-channel_.$(OBJEXT) irc-info_.$(OBJEXT) \
-irc-login_.$(OBJEXT) irc-mode_.$(OBJEXT) irc-op_.$(OBJEXT) \
-irc-oper_.$(OBJEXT) irc-server_.$(OBJEXT) irc-write_.$(OBJEXT) \
-lists_.$(OBJEXT) log_.$(OBJEXT) match_.$(OBJEXT) ngircd_.$(OBJEXT) \
+client-cap_.$(OBJEXT) conf_.$(OBJEXT) conn_.$(OBJEXT) \
+conn-func_.$(OBJEXT) conn-ssl_.$(OBJEXT) conn-zip_.$(OBJEXT) \
+hash_.$(OBJEXT) io_.$(OBJEXT) irc_.$(OBJEXT) irc-cap_.$(OBJEXT) \
+irc-channel_.$(OBJEXT) irc-info_.$(OBJEXT) irc-login_.$(OBJEXT) \
+irc-mode_.$(OBJEXT) irc-op_.$(OBJEXT) irc-oper_.$(OBJEXT) \
+irc-server_.$(OBJEXT) irc-write_.$(OBJEXT) lists_.$(OBJEXT) \
+log_.$(OBJEXT) login_.$(OBJEXT) match_.$(OBJEXT) ngircd_.$(OBJEXT) \
 numeric_.$(OBJEXT) op_.$(OBJEXT) pam_.$(OBJEXT) parse_.$(OBJEXT) \
 numeric_.$(OBJEXT) op_.$(OBJEXT) pam_.$(OBJEXT) parse_.$(OBJEXT) \
 proc_.$(OBJEXT) resolve_.$(OBJEXT) sighandlers_.$(OBJEXT) : \
 proc_.$(OBJEXT) resolve_.$(OBJEXT) sighandlers_.$(OBJEXT) : \
 $(ANSI2KNR)
 $(ANSI2KNR)

+ 73 - 0
src/ngircd/client-cap.c

@@ -0,0 +1,73 @@
+/*
+ * ngIRCd -- The Next Generation IRC Daemon
+ * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * Please read the file COPYING, README and AUTHORS for more information.
+ */
+
+#define __client_cap_c__
+
+#include "portab.h"
+
+/**
+ * @file
+ * Functions to deal with IRC Capabilities
+ */
+
+#include "imp.h"
+#include <assert.h>
+
+#include "defines.h"
+#include "conn.h"
+#include "client.h"
+#include "log.h"
+
+#include "exp.h"
+#include "client-cap.h"
+
+GLOBAL int
+Client_Cap(CLIENT *Client)
+{
+	assert (Client != NULL);
+
+	return Client->capabilities;
+}
+
+GLOBAL void
+Client_CapSet(CLIENT *Client, int Cap)
+{
+	assert(Client != NULL);
+	assert(Cap >= 0);
+
+	Client->capabilities = Cap;
+	LogDebug("Set new capability of \"%s\" to %d.",
+		 Client_ID(Client), Client->capabilities);
+}
+
+GLOBAL void
+Client_CapAdd(CLIENT *Client, int Cap)
+{
+	assert(Client != NULL);
+	assert(Cap > 0);
+
+	Client->capabilities |= Cap;
+	LogDebug("Add capability %d, new capability of \"%s\" is %d.",
+		 Cap, Client_ID(Client), Client->capabilities);
+}
+
+GLOBAL void
+Client_CapDel(CLIENT *Client, int Cap)
+{
+	assert(Client != NULL);
+	assert(Cap > 0);
+
+	Client->capabilities &= ~Cap;
+	LogDebug("Delete capability %d, new capability of \"%s\" is %d.",
+		 Cap, Client_ID(Client), Client->capabilities);
+}
+
+/* -eof- */

+ 31 - 0
src/ngircd/client-cap.h

@@ -0,0 +1,31 @@
+/*
+ * ngIRCd -- The Next Generation IRC Daemon
+ * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * Please read the file COPYING, README and AUTHORS for more information.
+ */
+
+#ifndef __client_cap_h__
+#define __client_cap_h__
+
+/**
+ * @file
+ * Functions to deal with IRC Capabilities (header)
+ */
+
+#define CLIENT_CAP_PENDING 1		/* Capability negotiation pending */
+#define CLIENT_CAP_SUPPORTED 2		/* Client supports IRC capabilities */
+
+#define CLIENT_CAP_MULTI_PREFIX 4	/* multi-prefix */
+
+GLOBAL int Client_Cap PARAMS((CLIENT *Client));
+
+GLOBAL void Client_CapSet PARAMS((CLIENT *Client, int Cap));
+GLOBAL void Client_CapAdd PARAMS((CLIENT *Client, int Cap));
+GLOBAL void Client_CapDel PARAMS((CLIENT *Client, int Cap));
+
+#endif

+ 99 - 1
src/ngircd/client.c

@@ -37,6 +37,7 @@
 #include "ngircd.h"
 #include "ngircd.h"
 #include "channel.h"
 #include "channel.h"
 #include "conf.h"
 #include "conf.h"
+#include "conn-func.h"
 #include "hash.h"
 #include "hash.h"
 #include "irc-write.h"
 #include "irc-write.h"
 #include "log.h"
 #include "log.h"
@@ -69,6 +70,8 @@ static CLIENT *Init_New_Client PARAMS((CONN_ID Idx, CLIENT *Introducer,
 static void Destroy_UserOrService PARAMS((CLIENT *Client,const char *Txt, const char *FwdMsg,
 static void Destroy_UserOrService PARAMS((CLIENT *Client,const char *Txt, const char *FwdMsg,
 					bool SendQuit));
 					bool SendQuit));
 
 
+static void cb_introduceClient PARAMS((CLIENT *Client, CLIENT *Prefix,
+				       void *i));
 
 
 GLOBAL void
 GLOBAL void
 Client_Init( void )
 Client_Init( void )
@@ -822,7 +825,9 @@ Client_MaskCloaked(CLIENT *Client)
 	    return Client_Mask(Client);
 	    return Client_Mask(Client);
 
 
 	snprintf(Mask_Buffer, GETID_LEN, "%s!%s@%s",
 	snprintf(Mask_Buffer, GETID_LEN, "%s!%s@%s",
-		 Client->id, Client->user, Client_ID(Client->introducer));
+		 Client->id, Client->user,
+		 *Conf_CloakHostModeX ? Conf_CloakHostModeX
+				      : Client_ID(Client->introducer));
 	return Mask_Buffer;
 	return Mask_Buffer;
 } /* Client_MaskCloaked */
 } /* Client_MaskCloaked */
 
 
@@ -1142,6 +1147,46 @@ Client_Reject(CLIENT *Client, const char *Reason, bool InformClient)
 }
 }
 
 
 
 
+/**
+ * Introduce a new user or service client in the network.
+ *
+ * @param From Remote server introducing the client or NULL (local).
+ * @param Client New client.
+ * @param Type Type of the client (CLIENT_USER or CLIENT_SERVICE).
+ */
+GLOBAL void
+Client_Introduce(CLIENT *From, CLIENT *Client, int Type)
+{
+	/* Set client type (user or service) */
+	Client_SetType(Client, Type);
+
+	if (From) {
+		if (Conf_IsService(Conf_GetServer(Client_Conn(From)),
+				   Client_ID(Client)))
+			Client_SetType(Client, CLIENT_SERVICE);
+		LogDebug("%s \"%s\" (+%s) registered (via %s, on %s, %d hop%s).",
+			 Client_TypeText(Client), Client_Mask(Client),
+			 Client_Modes(Client), Client_ID(From),
+			 Client_ID(Client_Introducer(Client)),
+			 Client_Hops(Client), Client_Hops(Client) > 1 ? "s": "");
+	} else {
+		Log(LOG_NOTICE, "%s \"%s\" registered (connection %d).",
+		    Client_TypeText(Client), Client_Mask(Client),
+		    Client_Conn(Client));
+		Log_ServerNotice('c', "Client connecting: %s (%s@%s) [%s] - %s",
+			         Client_ID(Client), Client_User(Client),
+				 Client_Hostname(Client),
+				 Conn_IPA(Client_Conn(Client)),
+				 Client_TypeText(Client));
+	}
+
+	/* Inform other servers */
+	IRC_WriteStrServersPrefixFlag_CB(From,
+				From != NULL ? From : Client_ThisServer(),
+				'\0', cb_introduceClient, (void *)Client);
+} /* Client_Introduce */
+
+
 static unsigned long
 static unsigned long
 Count( CLIENT_TYPE Type )
 Count( CLIENT_TYPE Type )
 {
 {
@@ -1361,6 +1406,59 @@ Destroy_UserOrService(CLIENT *Client, const char *Txt, const char *FwdMsg, bool
 } /* Destroy_UserOrService */
 } /* Destroy_UserOrService */
 
 
 
 
+/**
+ * Introduce a new user or service client to a remote server.
+ *
+ * This function differentiates between RFC1459 and RFC2813 server links and
+ * generates the appropriate commands to register the new user or service.
+ *
+ * @param To		The remote server to inform.
+ * @param Prefix	Prefix for the generated commands.
+ * @param data		CLIENT structure of the new client.
+ */
+static void
+cb_introduceClient(CLIENT *To, CLIENT *Prefix, void *data)
+{
+	CLIENT *c = (CLIENT *)data;
+	CONN_ID conn;
+	char *modes, *user, *host;
+
+	modes = Client_Modes(c);
+	user = Client_User(c) ? Client_User(c) : "-";
+	host = Client_Hostname(c) ? Client_Hostname(c) : "-";
+
+	conn = Client_Conn(To);
+	if (Conn_Options(conn) & CONN_RFC1459) {
+		/* RFC 1459 mode: separate NICK and USER commands */
+		Conn_WriteStr(conn, "NICK %s :%d", Client_ID(c),
+			      Client_Hops(c) + 1);
+		Conn_WriteStr(conn, ":%s USER %s %s %s :%s",
+			      Client_ID(c), user, host,
+			      Client_ID(Client_Introducer(c)), Client_Info(c));
+		if (modes[0])
+			Conn_WriteStr(conn, ":%s MODE %s +%s",
+				      Client_ID(c), Client_ID(c), modes);
+	} else {
+		/* RFC 2813 mode: one combined NICK or SERVICE command */
+		if (Client_Type(c) == CLIENT_SERVICE
+		    && strchr(Client_Flags(To), 'S'))
+			IRC_WriteStrClientPrefix(To, Prefix,
+						 "SERVICE %s %d * +%s %d :%s",
+						 Client_Mask(c),
+						 Client_MyToken(Client_Introducer(c)),
+						 Client_Modes(c), Client_Hops(c) + 1,
+						 Client_Info(c));
+		else
+			IRC_WriteStrClientPrefix(To, Prefix,
+						 "NICK %s %d %s %s %d +%s :%s",
+						 Client_ID(c), Client_Hops(c) + 1,
+						 user, host,
+						 Client_MyToken(Client_Introducer(c)),
+						 modes, Client_Info(c));
+	}
+} /* cb_introduceClient */
+
+
 #ifdef DEBUG
 #ifdef DEBUG
 
 
 GLOBAL void
 GLOBAL void

+ 6 - 2
src/ngircd/client.h

@@ -1,6 +1,6 @@
 /*
 /*
  * ngIRCd -- The Next Generation IRC Daemon
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2008 Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2012 Alexander Barton (alex@barton.de)
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -29,12 +29,13 @@
 #ifndef STRICT_RFC
 #ifndef STRICT_RFC
 # define CLIENT_WAITAUTHPING 512	/* waiting for AUTH PONG from client */
 # define CLIENT_WAITAUTHPING 512	/* waiting for AUTH PONG from client */
 #endif
 #endif
+#define CLIENT_WAITCAPEND 1024		/* waiting for "CAP END" command */
 
 
 #define CLIENT_TYPE int
 #define CLIENT_TYPE int
 
 
 #include "defines.h"
 #include "defines.h"
 
 
-#if defined(__client_c__) | defined(S_SPLINT_S)
+#if defined(__client_c__) | defined(__client_cap_c__) | defined(S_SPLINT_S)
 
 
 typedef struct _CLIENT
 typedef struct _CLIENT
 {
 {
@@ -58,6 +59,7 @@ typedef struct _CLIENT
 	bool oper_by_me;		/* client is local IRC operator on this server? */
 	bool oper_by_me;		/* client is local IRC operator on this server? */
 	char away[CLIENT_AWAY_LEN];	/* AWAY text (valid if mode 'a' is set) */
 	char away[CLIENT_AWAY_LEN];	/* AWAY text (valid if mode 'a' is set) */
 	char flags[CLIENT_FLAGS_LEN];	/* flags of the client */
 	char flags[CLIENT_FLAGS_LEN];	/* flags of the client */
+	int capabilities;		/* enabled IRC capabilities */
 } CLIENT;
 } CLIENT;
 
 
 #else
 #else
@@ -165,6 +167,8 @@ GLOBAL const char *Client_TypeText PARAMS((CLIENT *Client));
 
 
 GLOBAL void Client_Reject PARAMS((CLIENT *Client, const char *Reason,
 GLOBAL void Client_Reject PARAMS((CLIENT *Client, const char *Reason,
 				  bool InformClient));
 				  bool InformClient));
+GLOBAL void Client_Introduce PARAMS((CLIENT *From, CLIENT *Client, int Type));
+
 
 
 #ifdef DEBUG
 #ifdef DEBUG
 GLOBAL void Client_DebugDump PARAMS((void));
 GLOBAL void Client_DebugDump PARAMS((void));

+ 17 - 1
src/ngircd/conf.c

@@ -1,6 +1,6 @@
 /*
 /*
  * ngIRCd -- The Next Generation IRC Daemon
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -358,6 +358,7 @@ Conf_Test( void )
 	printf("  AllowRemoteOper = %s\n", yesno_to_str(Conf_AllowRemoteOper));
 	printf("  AllowRemoteOper = %s\n", yesno_to_str(Conf_AllowRemoteOper));
 	printf("  ChrootDir = %s\n", Conf_Chroot);
 	printf("  ChrootDir = %s\n", Conf_Chroot);
 	printf("  CloakHost = %s\n", Conf_CloakHost);
 	printf("  CloakHost = %s\n", Conf_CloakHost);
+	printf("  CloakHostModeX = %s\n", Conf_CloakHostModeX);
 	printf("  CloakUserToNick = %s\n", yesno_to_str(Conf_CloakUserToNick));
 	printf("  CloakUserToNick = %s\n", yesno_to_str(Conf_CloakUserToNick));
 #ifdef WANT_IPV6
 #ifdef WANT_IPV6
 	printf("  ConnectIPv4 = %s\n", yesno_to_str(Conf_ConnectIPv6));
 	printf("  ConnectIPv4 = %s\n", yesno_to_str(Conf_ConnectIPv6));
@@ -492,6 +493,14 @@ Conf_SetServer( int ConfServer, CONN_ID Idx )
 	assert( ConfServer > NONE );
 	assert( ConfServer > NONE );
 	assert( Idx > NONE );
 	assert( Idx > NONE );
 
 
+	if (Conf_Server[ConfServer].conn_id > NONE &&
+	    Conf_Server[ConfServer].conn_id != Idx) {
+		Log(LOG_ALERT,
+			"Trying to update connection index for already registered server \"%s\": %d/%d - ignored.",
+			Conf_Server[ConfServer].name,
+			Conf_Server[ConfServer].conn_id, Idx);
+		return;
+	}
 	Conf_Server[ConfServer].conn_id = Idx;
 	Conf_Server[ConfServer].conn_id = Idx;
 }
 }
 
 
@@ -676,6 +685,7 @@ Set_Defaults(bool InitServers)
 #endif
 #endif
 	strlcpy(Conf_Chroot, CHROOT_DIR, sizeof(Conf_Chroot));
 	strlcpy(Conf_Chroot, CHROOT_DIR, sizeof(Conf_Chroot));
 	strcpy(Conf_CloakHost, "");
 	strcpy(Conf_CloakHost, "");
+	strcpy(Conf_CloakHostModeX, "");
 	Conf_CloakUserToNick = false;
 	Conf_CloakUserToNick = false;
 	Conf_ConnectIPv4 = true;
 	Conf_ConnectIPv4 = true;
 #ifdef WANT_IPV6
 #ifdef WANT_IPV6
@@ -1469,6 +1479,12 @@ Handle_OPTIONS(int Line, char *Var, char *Arg)
 			Config_Error_TooLong(Line, Var);
 			Config_Error_TooLong(Line, Var);
 		return;
 		return;
 	}
 	}
+	if (strcasecmp(Var, "CloakHostModeX") == 0) {
+		len = strlcpy(Conf_CloakHostModeX, Arg, sizeof(Conf_CloakHostModeX));
+		if (len >= sizeof(Conf_CloakHostModeX))
+			Config_Error_TooLong(Line, Var);
+		return;
+	}
 	if (strcasecmp(Var, "CloakUserToNick") == 0) {
 	if (strcasecmp(Var, "CloakUserToNick") == 0) {
 		Conf_CloakUserToNick = Check_ArgIsTrue(Arg);
 		Conf_CloakUserToNick = Check_ArgIsTrue(Arg);
 		return;
 		return;

+ 3 - 0
src/ngircd/conf.h

@@ -166,6 +166,9 @@ GLOBAL bool Conf_AllowRemoteOper;
 /** Cloaked hostname of the clients */
 /** Cloaked hostname of the clients */
 GLOBAL char Conf_CloakHost[CLIENT_ID_LEN];
 GLOBAL char Conf_CloakHost[CLIENT_ID_LEN];
 
 
+/** Cloaked hostname for clients that did +x */
+GLOBAL char Conf_CloakHostModeX[CLIENT_ID_LEN];
+
 /** Use nick name as user name? */
 /** Use nick name as user name? */
 GLOBAL bool Conf_CloakUserToNick;
 GLOBAL bool Conf_CloakUserToNick;
 
 

+ 5 - 4
src/ngircd/conn-ssl.c

@@ -549,17 +549,18 @@ ConnSSL_LogCertInfo( CONNECTION *c )
 
 
 	assert(ssl);
 	assert(ssl);
 
 
-	Log(LOG_INFO, "New %s connection using cipher %s on socket %d.",
-		SSL_get_version(ssl), SSL_get_cipher(ssl), c->sock);
+	Log(LOG_INFO, "Connection %d: initialized %s using cipher %s.",
+		c->sock, SSL_get_version(ssl), SSL_get_cipher(ssl));
 #endif
 #endif
 #ifdef HAVE_LIBGNUTLS
 #ifdef HAVE_LIBGNUTLS
 	gnutls_session_t sess = c->ssl_state.gnutls_session;
 	gnutls_session_t sess = c->ssl_state.gnutls_session;
 	gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
 	gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
 
 
-	Log(LOG_INFO, "New %s connection using cipher %s-%s on socket %d.",
+	Log(LOG_INFO, "Connection %d: initialized %s using cipher %s-%s.",
+	    c->sock,
 	    gnutls_protocol_get_name(gnutls_protocol_get_version(sess)),
 	    gnutls_protocol_get_name(gnutls_protocol_get_version(sess)),
 	    gnutls_cipher_get_name(cipher),
 	    gnutls_cipher_get_name(cipher),
-	    gnutls_mac_get_name(gnutls_mac_get(sess)), c->sock);
+	    gnutls_mac_get_name(gnutls_mac_get(sess)));
 #endif
 #endif
 }
 }
 
 

+ 34 - 6
src/ngircd/conn.c

@@ -1,6 +1,6 @@
 /*
 /*
  * ngIRCd -- The Next Generation IRC Daemon
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -1935,6 +1935,14 @@ New_Server( int Server , ng_ipaddr_t *dest)
 
 
 	assert( Server > NONE );
 	assert( Server > NONE );
 
 
+	/* Make sure that the remote server hasn't re-linked to this server
+	 * asynchronously on its own */
+	if (Conf_Server[Server].conn_id > NONE) {
+		Log(LOG_INFO,
+			"Connection to \"%s\" meanwhile re-established, aborting preparation.");
+		return;
+	}
+
 	if (!ng_ipaddr_tostr_r(dest, ip_str)) {
 	if (!ng_ipaddr_tostr_r(dest, ip_str)) {
 		Log(LOG_WARNING, "New_Server: Could not convert IP to string");
 		Log(LOG_WARNING, "New_Server: Could not convert IP to string");
 		return;
 		return;
@@ -2008,7 +2016,7 @@ New_Server( int Server , ng_ipaddr_t *dest)
 	Client_SetToken( c, TOKEN_OUTBOUND );
 	Client_SetToken( c, TOKEN_OUTBOUND );
 
 
 	/* Register connection */
 	/* Register connection */
-	Conf_Server[Server].conn_id = new_sock;
+	Conf_SetServer(Server, new_sock);
 	My_Connections[new_sock].sock = new_sock;
 	My_Connections[new_sock].sock = new_sock;
 	My_Connections[new_sock].addr = *dest;
 	My_Connections[new_sock].addr = *dest;
 	My_Connections[new_sock].client = c;
 	My_Connections[new_sock].client = c;
@@ -2174,6 +2182,7 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events )
 	char *identptr;
 	char *identptr;
 #ifdef IDENTAUTH
 #ifdef IDENTAUTH
 	char readbuf[HOST_LEN + 2 + CLIENT_USER_LEN];
 	char readbuf[HOST_LEN + 2 + CLIENT_USER_LEN];
+	char *ptr;
 #else
 #else
 	char readbuf[HOST_LEN + 1];
 	char readbuf[HOST_LEN + 1];
 #endif
 #endif
@@ -2226,11 +2235,30 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events )
 #ifdef IDENTAUTH
 #ifdef IDENTAUTH
 		++identptr;
 		++identptr;
 		if (*identptr) {
 		if (*identptr) {
-			Log(LOG_INFO, "IDENT lookup for connection %d: \"%s\".", i, identptr);
-			Client_SetUser(c, identptr, true);
-			if (Conf_NoticeAuth)
+			ptr = identptr;
+			while (*ptr) {
+				if ((*ptr < '0' || *ptr > '9') &&
+				    (*ptr < 'A' || *ptr > 'Z') &&
+				    (*ptr < 'a' || *ptr > 'z'))
+					break;
+				ptr++;
+			}
+			if (*ptr) {
+				/* Erroneous IDENT reply */
+				Log(LOG_NOTICE,
+				    "Got invalid IDENT reply for connection %d! Ignored.",
+				    i);
+			} else {
+				Log(LOG_INFO,
+				    "IDENT lookup for connection %d: \"%s\".",
+				    i, identptr);
+				Client_SetUser(c, identptr, true);
+			}
+			if (Conf_NoticeAuth) {
 				(void)Conn_WriteStr(i,
 				(void)Conn_WriteStr(i,
-					"NOTICE AUTH :*** Got ident response");
+					"NOTICE AUTH :*** Got %sident response",
+					*ptr ? "invalid " : "");
+			}
 		} else {
 		} else {
 			Log(LOG_INFO, "IDENT lookup for connection %d: no result.", i);
 			Log(LOG_INFO, "IDENT lookup for connection %d: no result.", i);
 			if (Conf_NoticeAuth && Conf_Ident)
 			if (Conf_NoticeAuth && Conf_Ident)

+ 1 - 1
src/ngircd/defines.h

@@ -161,7 +161,7 @@
 #define USERMODES "acCiorRswx"
 #define USERMODES "acCiorRswx"
 
 
 /** Supported channel modes. */
 /** Supported channel modes. */
-#define CHANMODES "beiIklmnoOPRstvz"
+#define CHANMODES "beiIklmnoOPrRstvz"
 
 
 /** Away message for users connected to linked servers. */
 /** Away message for users connected to linked servers. */
 #define DEFAULT_AWAY_MSG "Away"
 #define DEFAULT_AWAY_MSG "Away"

+ 291 - 0
src/ngircd/irc-cap.c

@@ -0,0 +1,291 @@
+/*
+ * ngIRCd -- The Next Generation IRC Daemon
+ * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * Please read the file COPYING, README and AUTHORS for more information.
+ */
+
+#include "portab.h"
+
+/**
+ * @file
+ * Handler for IRC capability ("CAP") commands
+ */
+
+#include "imp.h"
+#include <assert.h>
+#include <string.h>
+
+#include "defines.h"
+#include "conn.h"
+#include "channel.h"
+#include "client-cap.h"
+#include "irc-write.h"
+#include "log.h"
+#include "login.h"
+#include "messages.h"
+#include "parse.h"
+
+#include "exp.h"
+#include "irc-cap.h"
+
+bool Handle_CAP_LS PARAMS((CLIENT *Client, char *Arg));
+bool Handle_CAP_LIST PARAMS((CLIENT *Client, char *Arg));
+bool Handle_CAP_REQ PARAMS((CLIENT *Client, char *Arg));
+bool Handle_CAP_ACK PARAMS((CLIENT *Client, char *Arg));
+bool Handle_CAP_CLEAR PARAMS((CLIENT *Client));
+bool Handle_CAP_END PARAMS((CLIENT *Client));
+
+void Set_CAP_Negotiation PARAMS((CLIENT *Client));
+
+int Parse_CAP PARAMS((int Capabilities, char *Args));
+char *Get_CAP_String PARAMS((int Capabilities));
+
+/**
+ * Handler for the IRCv3 "CAP" command.
+ *
+ * @param Client The client from which this command has been received.
+ * @param Req Request structure with prefix and all parameters.
+ * @returns CONNECTED or DISCONNECTED.
+ */
+GLOBAL bool
+IRC_CAP(CLIENT *Client, REQUEST *Req)
+{
+	assert(Client != NULL);
+	assert(Req != NULL);
+
+	/* Bad number of prameters? */
+	if (Req->argc < 1 || Req->argc > 2)
+		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
+					  Client_ID(Client), Req->command);
+
+	LogDebug("Got \"%s %s\" command from \"%s\" ...",
+		 Req->command, Req->argv[0], Client_ID(Client));
+
+	if (Req->argc == 1) {
+		if (strcasecmp(Req->argv[0], "CLEAR") == 0)
+			return Handle_CAP_CLEAR(Client);
+		if (strcasecmp(Req->argv[0], "END") == 0)
+			return Handle_CAP_END(Client);
+	}
+	if (Req->argc >= 1 && Req->argc <= 2) {
+		if (strcasecmp(Req->argv[0], "LS") == 0)
+			return Handle_CAP_LS(Client, Req->argv[1]);
+		if (strcasecmp(Req->argv[0], "LIST") == 0)
+			return Handle_CAP_LIST(Client, Req->argv[1]);
+	}
+	if (Req->argc == 2) {
+		if (strcasecmp(Req->argv[0], "REQ") == 0)
+			return Handle_CAP_REQ(Client, Req->argv[1]);
+		if (strcasecmp(Req->argv[0], "ACK") == 0)
+			return Handle_CAP_ACK(Client, Req->argv[1]);
+	}
+
+	return IRC_WriteStrClient(Client, ERR_INVALIDCAP_MSG,
+				  Client_ID(Client), Req->argv[0]);
+}
+
+/**
+ * Handler for the "CAP LS" command.
+ *
+ * @param Client The client from which this command has been received.
+ * @param Arg Command argument or NULL.
+ * @returns CONNECTED or DISCONNECTED.
+ */
+bool
+Handle_CAP_LS(CLIENT *Client, UNUSED char *Arg)
+{
+	assert(Client != NULL);
+
+	Set_CAP_Negotiation(Client);
+
+	return IRC_WriteStrClient(Client,
+				  "CAP %s LS :multi-prefix",
+				  Client_ID(Client));
+}
+
+/**
+ * Handler for the "CAP LIST" command.
+ *
+ * @param Client The client from which this command has been received.
+ * @param Arg Command argument or NULL.
+ * @returns CONNECTED or DISCONNECTED.
+ */
+bool
+Handle_CAP_LIST(CLIENT *Client, UNUSED char *Arg)
+{
+	assert(Client != NULL);
+
+	return IRC_WriteStrClient(Client, "CAP %s LIST :%s", Client_ID(Client),
+				  Get_CAP_String(Client_Cap(Client)));
+}
+
+/**
+ * Handler for the "CAP REQ" command.
+ *
+ * @param Client The client from which this command has been received.
+ * @param Arg Command argument.
+ * @returns CONNECTED or DISCONNECTED.
+ */
+bool
+Handle_CAP_REQ(CLIENT *Client, char *Arg)
+{
+	int new_cap;
+
+	assert(Client != NULL);
+	assert(Arg != NULL);
+
+	Set_CAP_Negotiation(Client);
+
+	new_cap = Parse_CAP(Client_Cap(Client), Arg);
+
+	if (new_cap < 0)
+		return IRC_WriteStrClient(Client, "CAP %s NAK :%s",
+					  Client_ID(Client), Arg);
+
+	Client_CapSet(Client, new_cap);
+	return IRC_WriteStrClient(Client, "CAP %s ACK :%s",
+				  Client_ID(Client), Arg);
+}
+
+/**
+ * Handler for the "CAP ACK" command.
+ *
+ * @param Client The client from which this command has been received.
+ * @param Arg Command argument.
+ * @returns CONNECTED or DISCONNECTED.
+ */
+bool
+Handle_CAP_ACK(UNUSED CLIENT *Client, UNUSED char *Arg)
+{
+	assert(Client != NULL);
+	assert(Arg != NULL);
+
+	return CONNECTED;
+}
+
+/**
+ * Handler for the "CAP CLEAR" command.
+ *
+ * @param Client The client from which this command has been received.
+ * @returns CONNECTED or DISCONNECTED.
+ */
+bool
+Handle_CAP_CLEAR(CLIENT *Client)
+{
+	int cap_old;
+
+	assert(Client != NULL);
+
+	cap_old = Client_Cap(Client);
+	if (cap_old & CLIENT_CAP_MULTI_PREFIX)
+		Client_CapDel(Client, CLIENT_CAP_MULTI_PREFIX);
+
+	return IRC_WriteStrClient(Client, "CAP %s ACK :%s", Client_ID(Client),
+				  Get_CAP_String(cap_old));
+}
+
+/**
+ * Handler for the "CAP END" command.
+ *
+ * @param Client The client from which this command has been received.
+ * @returns CONNECTED or DISCONNECTED.
+ */
+bool
+Handle_CAP_END(CLIENT *Client)
+{
+	assert(Client != NULL);
+
+	if (Client_Type(Client) != CLIENT_USER) {
+		/* User is still logging in ... */
+		Client_CapDel(Client, CLIENT_CAP_PENDING);
+
+		if (Client_Type(Client) == CLIENT_WAITCAPEND) {
+			/* Only "CAP END" was missing: log in! */
+			return Login_User(Client);
+		}
+	}
+
+	return CONNECTED;
+}
+
+/**
+ * Set CAP negotiation status and mark client as "supports capabilities".
+ *
+ * @param Client The client to handle.
+ */
+void
+Set_CAP_Negotiation(CLIENT *Client)
+{
+	assert(Client != NULL);
+
+	if (Client_Type(Client) != CLIENT_USER)
+		Client_CapAdd(Client, CLIENT_CAP_PENDING);
+	Client_CapAdd(Client, CLIENT_CAP_SUPPORTED);
+}
+
+/**
+ * Parse capability string and return numeric flag value.
+ *
+ * @param Args The string containing space-separated capability names.
+ * @return Changed capability flags or 0 on error.
+ */
+int
+Parse_CAP(int Capabilities, char *Args)
+{
+	static char tmp[COMMAND_LEN];
+	char *ptr;
+
+	assert(Args != NULL);
+
+	strlcpy(tmp, Args, sizeof(tmp));
+
+	ptr = strtok(tmp, " ");
+	while (ptr) {
+		if (*ptr == '-') {
+			/* drop capabilities */
+			ptr++;
+			if (strcmp(ptr, "multi-prefix") == 0)
+				Capabilities &= ~CLIENT_CAP_MULTI_PREFIX;
+			else
+				return -1;
+		} else {
+			/* request capabilities */
+			if (strcmp(ptr, "multi-prefix") == 0)
+				Capabilities |= CLIENT_CAP_MULTI_PREFIX;
+			else
+				return -1;
+		}
+		ptr = strtok(NULL, " ");
+	}
+
+	return Capabilities;
+}
+
+/**
+ * Return textual representation of capability flags.
+ *
+ * Please note: this function returns a pointer to a global buffer and
+ * therefore isn't thread safe!
+ *
+ * @param Capabilities Capability flags (bitmask).
+ * @return Pointer to textual representation.
+ */
+char
+*Get_CAP_String(int Capabilities)
+{
+	static char txt[COMMAND_LEN];
+
+	txt[0] = '\0';
+
+	if (Capabilities & CLIENT_CAP_MULTI_PREFIX)
+		strlcat(txt, "multi-prefix ", sizeof(txt));
+
+	return txt;
+}
+
+/* -eof- */

+ 24 - 0
src/ngircd/irc-cap.h

@@ -0,0 +1,24 @@
+/*
+ * ngIRCd -- The Next Generation IRC Daemon
+ * Copyright (c)2001-2010 Alexander Barton (alex@barton.de).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * Please read the file COPYING, README and AUTHORS for more information.
+ */
+
+#ifndef __irc_cap_h__
+#define __irc_cap_h__
+
+/**
+ * @file
+ * Handler for IRC capability ("CAP") commands (header)
+ */
+
+GLOBAL bool IRC_CAP PARAMS((CLIENT *Client, REQUEST *Req));
+
+#endif
+
+/* -eof- */

+ 61 - 35
src/ngircd/irc-info.c

@@ -39,6 +39,7 @@
 #include "parse.h"
 #include "parse.h"
 #include "irc.h"
 #include "irc.h"
 #include "irc-write.h"
 #include "irc-write.h"
+#include "client-cap.h"
 
 
 #include "exp.h"
 #include "exp.h"
 #include "irc-info.h"
 #include "irc-info.h"
@@ -807,8 +808,16 @@ who_flags_status(const char *client_modes)
 
 
 
 
 static const char *
 static const char *
-who_flags_qualifier(const char *chan_user_modes)
+who_flags_qualifier(CLIENT *Client, const char *chan_user_modes)
 {
 {
+	assert(Client != NULL);
+
+	if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX) {
+		if (strchr(chan_user_modes, 'o') &&
+		    strchr(chan_user_modes, 'v'))
+			return "@+";
+	}
+
 	if (strchr(chan_user_modes, 'o'))
 	if (strchr(chan_user_modes, 'o'))
 		return "@";
 		return "@";
 	else if (strchr(chan_user_modes, 'v'))
 	else if (strchr(chan_user_modes, 'v'))
@@ -865,7 +874,7 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
 				strlcat(flags, "*", sizeof(flags));
 				strlcat(flags, "*", sizeof(flags));
 
 
 			chan_user_modes = Channel_UserModes(Chan, c);
 			chan_user_modes = Channel_UserModes(Chan, c);
-			strlcat(flags, who_flags_qualifier(chan_user_modes),
+			strlcat(flags, who_flags_qualifier(c, chan_user_modes),
 				sizeof(flags));
 				sizeof(flags));
 
 
 			if (!write_whoreply(Client, c, Channel_Name(Chan),
 			if (!write_whoreply(Client, c, Channel_Name(Chan),
@@ -1078,7 +1087,7 @@ IRC_WHOIS_SendReply(CLIENT *Client, CLIENT *from, CLIENT *c)
 		if (str[strlen(str) - 1] != ':')
 		if (str[strlen(str) - 1] != ':')
 			strlcat(str, " ", sizeof(str));
 			strlcat(str, " ", sizeof(str));
 
 
-		strlcat(str, who_flags_qualifier(Channel_UserModes(chan, c)),
+		strlcat(str, who_flags_qualifier(c, Channel_UserModes(chan, c)),
 						 sizeof(str));
 						 sizeof(str));
 		strlcat(str, Channel_Name(chan), sizeof(str));
 		strlcat(str, Channel_Name(chan), sizeof(str));
 
 
@@ -1524,60 +1533,77 @@ IRC_Show_MOTD( CLIENT *Client )
 } /* IRC_Show_MOTD */
 } /* IRC_Show_MOTD */
 
 
 
 
+/**
+ * Send NAMES reply for a specific client and channel.
+ *
+ * @param Client The client requesting the NAMES information.
+ * @param Chan The channel
+ * @return CONNECTED or DISCONNECTED.
+ */
 GLOBAL bool
 GLOBAL bool
-IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan )
+IRC_Send_NAMES(CLIENT * Client, CHANNEL * Chan)
 {
 {
 	bool is_visible, is_member;
 	bool is_visible, is_member;
 	char str[LINE_LEN + 1];
 	char str[LINE_LEN + 1];
 	CL2CHAN *cl2chan;
 	CL2CHAN *cl2chan;
 	CLIENT *cl;
 	CLIENT *cl;
 
 
-	assert( Client != NULL );
-	assert( Chan != NULL );
+	assert(Client != NULL);
+	assert(Chan != NULL);
 
 
-	if( Channel_IsMemberOf( Chan, Client )) is_member = true;
-	else is_member = false;
+	if (Channel_IsMemberOf(Chan, Client))
+		is_member = true;
+	else
+		is_member = false;
 
 
 	/* Do not print info on channel memberships to anyone that is not member? */
 	/* Do not print info on channel memberships to anyone that is not member? */
 	if (Conf_MorePrivacy && !is_member)
 	if (Conf_MorePrivacy && !is_member)
 		return CONNECTED;
 		return CONNECTED;
 
 
 	/* Secret channel? */
 	/* Secret channel? */
-	if( ! is_member && strchr( Channel_Modes( Chan ), 's' )) return CONNECTED;
+	if (!is_member && strchr(Channel_Modes(Chan), 's'))
+		return CONNECTED;
 
 
-	/* Alle Mitglieder suchen */
-	snprintf( str, sizeof( str ), RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
-	cl2chan = Channel_FirstMember( Chan );
-	while( cl2chan )
-	{
-		cl = Channel_GetClient( cl2chan );
+	snprintf(str, sizeof(str), RPL_NAMREPLY_MSG, Client_ID(Client), "=",
+		 Channel_Name(Chan));
+	cl2chan = Channel_FirstMember(Chan);
+	while (cl2chan) {
+		cl = Channel_GetClient(cl2chan);
 
 
-		if( strchr( Client_Modes( cl ), 'i' )) is_visible = false;
-		else is_visible = true;
+		if (strchr(Client_Modes(cl), 'i'))
+			is_visible = false;
+		else
+			is_visible = true;
 
 
-		if( is_member || is_visible )
-		{
-			/* Nick anhaengen */
-			if( str[strlen( str ) - 1] != ':' ) strlcat( str, " ", sizeof( str ));
-			if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strlcat( str, "@", sizeof( str ));
-			else if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strlcat( str, "+", sizeof( str ));
-			strlcat( str, Client_ID( cl ), sizeof( str ));
+		if (is_member || is_visible) {
+			if (str[strlen(str) - 1] != ':')
+				strlcat(str, " ", sizeof(str));
+			if (Client_Cap(cl) & CLIENT_CAP_MULTI_PREFIX) {
+				if (strchr(Channel_UserModes(Chan, cl), 'o') &&
+				    strchr(Channel_UserModes(Chan, cl), 'v'))
+					strlcat(str, "@+", sizeof(str));
+			} else {
+				if (strchr(Channel_UserModes(Chan, cl), 'o'))
+					strlcat(str, "@", sizeof(str));
+				else if (strchr(Channel_UserModes(Chan, cl), 'v'))
+					strlcat(str, "+", sizeof(str));
+			}
+			strlcat(str, Client_ID(cl), sizeof(str));
 
 
-			if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
-			{
-				/* Zeile wird zu lang: senden! */
-				if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
-				snprintf( str, sizeof( str ), RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
+			if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 4)) {
+				if (!IRC_WriteStrClient(Client, "%s", str))
+					return DISCONNECTED;
+				snprintf(str, sizeof(str), RPL_NAMREPLY_MSG,
+					 Client_ID(Client), "=",
+					 Channel_Name(Chan));
 			}
 			}
 		}
 		}
 
 
-		/* naechstes Mitglied suchen */
-		cl2chan = Channel_NextMember( Chan, cl2chan );
+		cl2chan = Channel_NextMember(Chan, cl2chan);
 	}
 	}
-	if( str[strlen( str ) - 1] != ':')
-	{
-		/* Es sind noch Daten da, die gesendet werden muessen */
-		if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
+	if (str[strlen(str) - 1] != ':') {
+		if (!IRC_WriteStrClient(Client, "%s", str))
+			return DISCONNECTED;
 	}
 	}
 
 
 	return CONNECTED;
 	return CONNECTED;

+ 20 - 309
src/ngircd/irc-login.c

@@ -18,22 +18,17 @@
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 #include <strings.h>
 #include <strings.h>
-#include <signal.h>
-#include <unistd.h>
 
 
-#include "ngircd.h"
 #include "conn-func.h"
 #include "conn-func.h"
 #include "class.h"
 #include "class.h"
 #include "conf.h"
 #include "conf.h"
 #include "channel.h"
 #include "channel.h"
-#include "io.h"
 #include "log.h"
 #include "log.h"
+#include "login.h"
 #include "messages.h"
 #include "messages.h"
-#include "pam.h"
 #include "parse.h"
 #include "parse.h"
 #include "irc.h"
 #include "irc.h"
 #include "irc-info.h"
 #include "irc-info.h"
@@ -42,18 +37,7 @@
 #include "exp.h"
 #include "exp.h"
 #include "irc-login.h"
 #include "irc-login.h"
 
 
-
-static bool Hello_User PARAMS(( CLIENT *Client ));
-static bool Hello_User_PostAuth PARAMS(( CLIENT *Client ));
 static void Kill_Nick PARAMS(( char *Nick, char *Reason ));
 static void Kill_Nick PARAMS(( char *Nick, char *Reason ));
-static void Introduce_Client PARAMS((CLIENT *To, CLIENT *Client, int Type));
-
-static void cb_introduceClient PARAMS((CLIENT *Client, CLIENT *Prefix,
-				       void *i));
-
-#ifdef PAM
-static void cb_Read_Auth_Result PARAMS((int r_fd, UNUSED short events));
-#endif
 
 
 /**
 /**
  * Handler for the IRC "PASS" command.
  * Handler for the IRC "PASS" command.
@@ -285,7 +269,7 @@ IRC_NICK( CLIENT *Client, REQUEST *Req )
 			/* If we received a valid USER command already then
 			/* If we received a valid USER command already then
 			 * register the new client! */
 			 * register the new client! */
 			if( Client_Type( Client ) == CLIENT_GOTUSER )
 			if( Client_Type( Client ) == CLIENT_GOTUSER )
-				return Hello_User( Client );
+				return Login_User( Client );
 			else
 			else
 				Client_SetType( Client, CLIENT_GOTNICK );
 				Client_SetType( Client, CLIENT_GOTNICK );
 		} else {
 		} else {
@@ -395,7 +379,7 @@ IRC_NICK( CLIENT *Client, REQUEST *Req )
 				 Client_Mask(c));
 				 Client_Mask(c));
 			Client_SetType(c, CLIENT_GOTNICK);
 			Client_SetType(c, CLIENT_GOTNICK);
 		} else
 		} else
-			Introduce_Client(Client, c, CLIENT_USER);
+			Client_Introduce(Client, c, CLIENT_USER);
 
 
 		return CONNECTED;
 		return CONNECTED;
 	}
 	}
@@ -416,9 +400,7 @@ GLOBAL bool
 IRC_USER(CLIENT * Client, REQUEST * Req)
 IRC_USER(CLIENT * Client, REQUEST * Req)
 {
 {
 	CLIENT *c;
 	CLIENT *c;
-#ifdef IDENTAUTH
 	char *ptr;
 	char *ptr;
-#endif
 
 
 	assert(Client != NULL);
 	assert(Client != NULL);
 	assert(Req != NULL);
 	assert(Req != NULL);
@@ -436,7 +418,19 @@ IRC_USER(CLIENT * Client, REQUEST * Req)
 						  Client_ID(Client),
 						  Client_ID(Client),
 						  Req->command);
 						  Req->command);
 
 
-		/* User name */
+		/* User name: only alphanumeric characters are allowed! */
+		ptr = Req->argv[0];
+		while (*ptr) {
+			if ((*ptr < '0' || *ptr > '9') &&
+			    (*ptr < 'A' || *ptr > 'Z') &&
+			    (*ptr < 'a' || *ptr > 'z')) {
+				Conn_Close(Client_Conn(Client), NULL,
+					   "Invalid user name", true);
+				return DISCONNECTED;
+			}
+			ptr++;
+		}
+
 #ifdef IDENTAUTH
 #ifdef IDENTAUTH
 		ptr = Client_User(Client);
 		ptr = Client_User(Client);
 		if (!ptr || !*ptr || *ptr == '~')
 		if (!ptr || !*ptr || *ptr == '~')
@@ -457,7 +451,7 @@ IRC_USER(CLIENT * Client, REQUEST * Req)
 		LogDebug("Connection %d: got valid USER command ...",
 		LogDebug("Connection %d: got valid USER command ...",
 		    Client_Conn(Client));
 		    Client_Conn(Client));
 		if (Client_Type(Client) == CLIENT_GOTNICK)
 		if (Client_Type(Client) == CLIENT_GOTNICK)
-			return Hello_User(Client);
+			return Login_User(Client);
 		else
 		else
 			Client_SetType(Client, CLIENT_GOTUSER);
 			Client_SetType(Client, CLIENT_GOTUSER);
 		return CONNECTED;
 		return CONNECTED;
@@ -487,7 +481,7 @@ IRC_USER(CLIENT * Client, REQUEST * Req)
 		/* RFC 1459 style user registration?
 		/* RFC 1459 style user registration?
 		 * Introduce client to network: */
 		 * Introduce client to network: */
 		if (Client_Type(c) == CLIENT_GOTNICK)
 		if (Client_Type(c) == CLIENT_GOTNICK)
-			Introduce_Client(Client, c, CLIENT_USER);
+			Client_Introduce(Client, c, CLIENT_USER);
 
 
 		return CONNECTED;
 		return CONNECTED;
 	} else if (Client_Type(Client) == CLIENT_USER) {
 	} else if (Client_Type(Client) == CLIENT_USER) {
@@ -601,7 +595,7 @@ IRC_SERVICE(CLIENT *Client, REQUEST *Req)
 		return CONNECTED;
 		return CONNECTED;
 	}
 	}
 
 
-	Introduce_Client(Client, c, CLIENT_SERVICE);
+	Client_Introduce(Client, c, CLIENT_SERVICE);
 	return CONNECTED;
 	return CONNECTED;
 } /* IRC_SERVICE */
 } /* IRC_SERVICE */
 
 
@@ -880,7 +874,7 @@ IRC_PONG(CLIENT *Client, REQUEST *Req)
 		if (auth_ping == atoi(Req->argv[0])) {
 		if (auth_ping == atoi(Req->argv[0])) {
 			Conn_SetAuthPing(conn, 0);
 			Conn_SetAuthPing(conn, 0);
 			if (Client_Type(Client) == CLIENT_WAITAUTHPING)
 			if (Client_Type(Client) == CLIENT_WAITAUTHPING)
-				Hello_User(Client);
+				Login_User(Client);
 		} else
 		} else
 			if (!IRC_WriteStrClient(Client,
 			if (!IRC_WriteStrClient(Client,
 					"To connect, type /QUOTE PONG %ld",
 					"To connect, type /QUOTE PONG %ld",
@@ -904,196 +898,6 @@ IRC_PONG(CLIENT *Client, REQUEST *Req)
 
 
 
 
 /**
 /**
- * Initiate client registration.
- *
- * This function is called after the daemon received the required NICK and
- * USER commands of a new client. If the daemon is compiled with support for
- * PAM, the authentication sub-processs is forked; otherwise the global server
- * password is checked.
- *
- * @param Client	The client logging in.
- * @returns		CONNECTED or DISCONNECTED.
- */
-static bool
-Hello_User(CLIENT * Client)
-{
-#ifdef PAM
-	int pipefd[2], result;
-	pid_t pid;
-#endif
-	CONN_ID conn;
-
-	assert(Client != NULL);
-	conn = Client_Conn(Client);
-
-#ifndef STRICT_RFC
-	if (Conf_AuthPing) {
-		/* Did we receive the "auth PONG" already? */
-		if (Conn_GetAuthPing(conn)) {
-			Client_SetType(Client, CLIENT_WAITAUTHPING);
-			LogDebug("Connection %d: Waiting for AUTH PONG ...", conn);
-			return CONNECTED;
-		}
-	}
-#endif
-
-#ifdef PAM
-	if (!Conf_PAM) {
-		/* Don't do any PAM authentication at all, instead emulate
-		 * the beahiour of the daemon compiled without PAM support:
-		 * because there can't be any "server password", all
-		 * passwords supplied are classified as "wrong". */
-		if(Client_Password(Client)[0] == '\0')
-			return Hello_User_PostAuth(Client);
-		Client_Reject(Client, "Non-empty password", false);
-		return DISCONNECTED;
-	}
-
-	if (Conf_PAMIsOptional && strcmp(Client_Password(Client), "") == 0) {
-		/* Clients are not required to send a password and to be PAM-
-		 * authenticated at all. If not, they won't become "identified"
-		 * and keep the "~" in their supplied user name.
-		 * Therefore it is sensible to either set Conf_PAMisOptional or
-		 * to enable IDENT lookups -- not both. */
-		return Hello_User_PostAuth(Client);
-	}
-
-	/* Fork child process for PAM authentication; and make sure that the
-	 * process timeout is set higher than the login timeout! */
-	pid = Proc_Fork(Conn_GetProcStat(conn), pipefd,
-			cb_Read_Auth_Result, Conf_PongTimeout + 1);
-	if (pid > 0) {
-		LogDebug("Authenticator for connection %d created (PID %d).",
-			 conn, pid);
-		return CONNECTED;
-	} else {
-		/* Sub process */
-		Log_Init_Subprocess("Auth");
-		Conn_CloseAllSockets(NONE);
-		result = PAM_Authenticate(Client);
-		if (write(pipefd[1], &result, sizeof(result)) != sizeof(result))
-			Log_Subprocess(LOG_ERR,
-				       "Failed to pipe result to parent!");
-		Log_Exit_Subprocess("Auth");
-		exit(0);
-	}
-#else
-	/* Check global server password ... */
-	if (strcmp(Client_Password(Client), Conf_ServerPwd) != 0) {
-		/* Bad password! */
-		Client_Reject(Client, "Bad server password", false);
-		return DISCONNECTED;
-	}
-	return Hello_User_PostAuth(Client);
-#endif
-}
-
-
-#ifdef PAM
-
-/**
- * Read result of the authenticatior sub-process from pipe
- *
- * @param r_fd		File descriptor of the pipe.
- * @param events	(ignored IO specification)
- */
-static void
-cb_Read_Auth_Result(int r_fd, UNUSED short events)
-{
-	CONN_ID conn;
-	CLIENT *client;
-	int result;
-	size_t len;
-	PROC_STAT *proc;
-
-	LogDebug("Auth: Got callback on fd %d, events %d", r_fd, events);
-	conn = Conn_GetFromProc(r_fd);
-	if (conn == NONE) {
-		/* Ops, none found? Probably the connection has already
-		 * been closed!? We'll ignore that ... */
-		io_close(r_fd);
-		LogDebug("Auth: Got callback for unknown connection!?");
-		return;
-	}
-	proc = Conn_GetProcStat(conn);
-	client = Conn_GetClient(conn);
-
-	/* Read result from pipe */
-	len = Proc_Read(proc, &result, sizeof(result));
-	Proc_Close(proc);
-	if (len == 0)
-		return;
-
-	if (len != sizeof(result)) {
-		Log(LOG_CRIT, "Auth: Got malformed result!");
-		Client_Reject(client, "Internal error", false);
-		return;
-	}
-
-	if (result == true) {
-		Client_SetUser(client, Client_OrigUser(client), true);
-		(void)Hello_User_PostAuth(client);
-	} else
-		Client_Reject(client, "Bad password", false);
-}
-
-#endif
-
-
-/**
- * Finish client registration.
- *
- * Introduce the new client to the network and send all "hello messages"
- * to it after authentication has been succeeded.
- *
- * @param Client	The client logging in.
- * @returns		CONNECTED or DISCONNECTED.
- */
-static bool
-Hello_User_PostAuth(CLIENT *Client)
-{
-	assert(Client != NULL);
-
-	if (Class_HandleServerBans(Client) != CONNECTED)
-		return DISCONNECTED;
-
-	Introduce_Client(NULL, Client, CLIENT_USER);
-
-	if (!IRC_WriteStrClient
-	    (Client, RPL_WELCOME_MSG, Client_ID(Client), Client_Mask(Client)))
-		return false;
-	if (!IRC_WriteStrClient
-	    (Client, RPL_YOURHOST_MSG, Client_ID(Client),
-	     Client_ID(Client_ThisServer()), PACKAGE_VERSION, TARGET_CPU,
-	     TARGET_VENDOR, TARGET_OS))
-		return false;
-	if (!IRC_WriteStrClient
-	    (Client, RPL_CREATED_MSG, Client_ID(Client), NGIRCd_StartStr))
-		return false;
-	if (!IRC_WriteStrClient
-	    (Client, RPL_MYINFO_MSG, Client_ID(Client),
-	     Client_ID(Client_ThisServer()), PACKAGE_VERSION, USERMODES,
-	     CHANMODES))
-		return false;
-
-	/* Features supported by this server (005 numeric, ISUPPORT),
-	 * see <http://www.irc.org/tech_docs/005.html> for details. */
-	if (!IRC_Send_ISUPPORT(Client))
-		return DISCONNECTED;
-
-	if (!IRC_Send_LUSERS(Client))
-		return DISCONNECTED;
-	if (!IRC_Show_MOTD(Client))
-		return DISCONNECTED;
-
-	/* Suspend the client for a second ... */
-	IRC_SetPenalty(Client, 1);
-
-	return CONNECTED;
-}
-
-
-/**
  * Kill all users with a specific nick name in the network.
  * Kill all users with a specific nick name in the network.
  *
  *
  * @param Nick		Nick name.
  * @param Nick		Nick name.
@@ -1119,97 +923,4 @@ Kill_Nick(char *Nick, char *Reason)
 } /* Kill_Nick */
 } /* Kill_Nick */
 
 
 
 
-/**
- * Introduce a new user or service client in the network.
- *
- * @param From		Remote server introducing the client or NULL (local).
- * @param Client	New client.
- * @param Type		Type of the client (CLIENT_USER or CLIENT_SERVICE).
- */
-static void
-Introduce_Client(CLIENT *From, CLIENT *Client, int Type)
-{
-	/* Set client type (user or service) */
-	Client_SetType(Client, Type);
-
-	if (From) {
-		if (Conf_IsService(Conf_GetServer(Client_Conn(From)),
-				   Client_ID(Client)))
-			Client_SetType(Client, CLIENT_SERVICE);
-		LogDebug("%s \"%s\" (+%s) registered (via %s, on %s, %d hop%s).",
-			 Client_TypeText(Client), Client_Mask(Client),
-			 Client_Modes(Client), Client_ID(From),
-			 Client_ID(Client_Introducer(Client)),
-			 Client_Hops(Client), Client_Hops(Client) > 1 ? "s": "");
-	} else {
-		Log(LOG_NOTICE, "%s \"%s\" registered (connection %d).",
-		    Client_TypeText(Client), Client_Mask(Client),
-		    Client_Conn(Client));
-		Log_ServerNotice('c', "Client connecting: %s (%s@%s) [%s] - %s",
-			         Client_ID(Client), Client_User(Client),
-				 Client_Hostname(Client),
-				 Conn_IPA(Client_Conn(Client)),
-				 Client_TypeText(Client));
-	}
-
-	/* Inform other servers */
-	IRC_WriteStrServersPrefixFlag_CB(From,
-				From != NULL ? From : Client_ThisServer(),
-				'\0', cb_introduceClient, (void *)Client);
-} /* Introduce_Client */
-
-
-/**
- * Introduce a new user or service client to a remote server.
- *
- * This function differentiates between RFC1459 and RFC2813 server links and
- * generates the appropriate commands to register the new user or service.
- *
- * @param To		The remote server to inform.
- * @param Prefix	Prefix for the generated commands.
- * @param data		CLIENT structure of the new client.
- */
-static void
-cb_introduceClient(CLIENT *To, CLIENT *Prefix, void *data)
-{
-	CLIENT *c = (CLIENT *)data;
-	CONN_ID conn;
-	char *modes, *user, *host;
-
-	modes = Client_Modes(c);
-	user = Client_User(c) ? Client_User(c) : "-";
-	host = Client_Hostname(c) ? Client_Hostname(c) : "-";
-
-	conn = Client_Conn(To);
-	if (Conn_Options(conn) & CONN_RFC1459) {
-		/* RFC 1459 mode: separate NICK and USER commands */
-		Conn_WriteStr(conn, "NICK %s :%d", Client_ID(c),
-			      Client_Hops(c) + 1);
-		Conn_WriteStr(conn, ":%s USER %s %s %s :%s",
-			      Client_ID(c), user, host,
-			      Client_ID(Client_Introducer(c)), Client_Info(c));
-		if (modes[0])
-			Conn_WriteStr(conn, ":%s MODE %s +%s",
-				      Client_ID(c), Client_ID(c), modes);
-	} else {
-		/* RFC 2813 mode: one combined NICK or SERVICE command */
-		if (Client_Type(c) == CLIENT_SERVICE
-		    && strchr(Client_Flags(To), 'S'))
-			IRC_WriteStrClientPrefix(To, Prefix,
-					 "SERVICE %s %d * +%s %d :%s",
-					 Client_Mask(c),
-					 Client_MyToken(Client_Introducer(c)),
-					 Client_Modes(c), Client_Hops(c) + 1,
-					 Client_Info(c));
-		else
-			IRC_WriteStrClientPrefix(To, Prefix,
-					 "NICK %s %d %s %s %d +%s :%s",
-					 Client_ID(c), Client_Hops(c) + 1,
-					 user, host,
-					 Client_MyToken(Client_Introducer(c)),
-					 modes, Client_Info(c));
-	}
-} /* cb_introduceClient */
-
-
 /* -eof- */
 /* -eof- */

+ 2 - 4
src/ngircd/lists.c

@@ -147,10 +147,8 @@ Lists_Add(struct list_head *h, const char *Mask, time_t ValidUntil,
 
 
 	strlcpy(newelem->mask, Mask, sizeof(newelem->mask));
 	strlcpy(newelem->mask, Mask, sizeof(newelem->mask));
 	if (Reason) {
 	if (Reason) {
-		newelem->reason = malloc(strlen(Reason) + 1);
-		if (newelem->reason)
-			strlcpy(newelem->reason, Reason, strlen(Reason) + 1);
-		else
+		newelem->reason = strdup(Reason);
+		if (!newelem->reason)
 			Log(LOG_EMERG,
 			Log(LOG_EMERG,
 			    "Can't allocate memory for new list reason text!");
 			    "Can't allocate memory for new list reason text!");
 	}
 	}

+ 243 - 0
src/ngircd/login.c

@@ -0,0 +1,243 @@
+/*
+ * ngIRCd -- The Next Generation IRC Daemon
+ * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * Please read the file COPYING, README and AUTHORS for more information.
+ */
+
+#include "portab.h"
+
+/**
+ * @file
+ * Functions to deal with client logins
+ */
+
+#include "imp.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "defines.h"
+#include "conn.h"
+#include "class.h"
+#include "client.h"
+#include "client-cap.h"
+#include "channel.h"
+#include "conf.h"
+#include "io.h"
+#include "parse.h"
+#include "log.h"
+#include "messages.h"
+#include "ngircd.h"
+#include "pam.h"
+#include "irc-info.h"
+#include "irc-write.h"
+
+#include "exp.h"
+#include "login.h"
+
+#ifdef PAM
+static void cb_Read_Auth_Result PARAMS((int r_fd, UNUSED short events));
+#endif
+
+/**
+ * Initiate client login.
+ *
+ * This function is called after the daemon received the required NICK and
+ * USER commands of a new client. If the daemon is compiled with support for
+ * PAM, the authentication sub-processs is forked; otherwise the global server
+ * password is checked.
+ *
+ * @param Client The client logging in.
+ * @returns CONNECTED or DISCONNECTED.
+ */
+GLOBAL bool
+Login_User(CLIENT * Client)
+{
+#ifdef PAM
+	int pipefd[2], result;
+	pid_t pid;
+#endif
+	CONN_ID conn;
+
+	assert(Client != NULL);
+	conn = Client_Conn(Client);
+
+#ifndef STRICT_RFC
+	if (Conf_AuthPing) {
+		/* Did we receive the "auth PONG" already? */
+		if (Conn_GetAuthPing(conn)) {
+			Client_SetType(Client, CLIENT_WAITAUTHPING);
+			LogDebug("Connection %d: Waiting for AUTH PONG ...", conn);
+			return CONNECTED;
+		}
+	}
+#endif
+
+	/* Still waiting for "CAP END" command? */
+	if (Client_Cap(Client) & CLIENT_CAP_PENDING) {
+		Client_SetType(Client, CLIENT_WAITCAPEND);
+		LogDebug("Connection %d: Waiting for CAP END ...", conn);
+		return CONNECTED;
+	}
+
+#ifdef PAM
+	if (!Conf_PAM) {
+		/* Don't do any PAM authentication at all, instead emulate
+		 * the beahiour of the daemon compiled without PAM support:
+		 * because there can't be any "server password", all
+		 * passwords supplied are classified as "wrong". */
+		if(Client_Password(Client)[0] == '\0')
+			return Login_User_PostAuth(Client);
+		Client_Reject(Client, "Non-empty password", false);
+		return DISCONNECTED;
+	}
+
+	if (Conf_PAMIsOptional && strcmp(Client_Password(Client), "") == 0) {
+		/* Clients are not required to send a password and to be PAM-
+		 * authenticated at all. If not, they won't become "identified"
+		 * and keep the "~" in their supplied user name.
+		 * Therefore it is sensible to either set Conf_PAMisOptional or
+		 * to enable IDENT lookups -- not both. */
+		return Login_User_PostAuth(Client);
+	}
+
+	/* Fork child process for PAM authentication; and make sure that the
+	 * process timeout is set higher than the login timeout! */
+	pid = Proc_Fork(Conn_GetProcStat(conn), pipefd,
+			cb_Read_Auth_Result, Conf_PongTimeout + 1);
+	if (pid > 0) {
+		LogDebug("Authenticator for connection %d created (PID %d).",
+			 conn, pid);
+		return CONNECTED;
+	} else {
+		/* Sub process */
+		Log_Init_Subprocess("Auth");
+		Conn_CloseAllSockets(NONE);
+		result = PAM_Authenticate(Client);
+		if (write(pipefd[1], &result, sizeof(result)) != sizeof(result))
+			Log_Subprocess(LOG_ERR,
+				       "Failed to pipe result to parent!");
+		Log_Exit_Subprocess("Auth");
+		exit(0);
+	}
+#else
+	/* Check global server password ... */
+	if (strcmp(Client_Password(Client), Conf_ServerPwd) != 0) {
+		/* Bad password! */
+		Client_Reject(Client, "Bad server password", false);
+		return DISCONNECTED;
+	}
+	return Login_User_PostAuth(Client);
+#endif
+}
+
+/**
+ * Finish client registration.
+ *
+ * Introduce the new client to the network and send all "hello messages"
+ * to it after authentication has been succeeded.
+ *
+ * @param Client The client logging in.
+ * @return CONNECTED or DISCONNECTED.
+ */
+GLOBAL bool
+Login_User_PostAuth(CLIENT *Client)
+{
+	assert(Client != NULL);
+
+	if (Class_HandleServerBans(Client) != CONNECTED)
+		return DISCONNECTED;
+
+	Client_Introduce(NULL, Client, CLIENT_USER);
+
+	if (!IRC_WriteStrClient
+	    (Client, RPL_WELCOME_MSG, Client_ID(Client), Client_Mask(Client)))
+		return false;
+	if (!IRC_WriteStrClient
+	    (Client, RPL_YOURHOST_MSG, Client_ID(Client),
+	     Client_ID(Client_ThisServer()), PACKAGE_VERSION, TARGET_CPU,
+	     TARGET_VENDOR, TARGET_OS))
+		return false;
+	if (!IRC_WriteStrClient
+	    (Client, RPL_CREATED_MSG, Client_ID(Client), NGIRCd_StartStr))
+		return false;
+	if (!IRC_WriteStrClient
+	    (Client, RPL_MYINFO_MSG, Client_ID(Client),
+	     Client_ID(Client_ThisServer()), PACKAGE_VERSION, USERMODES,
+	     CHANMODES))
+		return false;
+
+	/* Features supported by this server (005 numeric, ISUPPORT),
+	 * see <http://www.irc.org/tech_docs/005.html> for details. */
+	if (!IRC_Send_ISUPPORT(Client))
+		return DISCONNECTED;
+
+	if (!IRC_Send_LUSERS(Client))
+		return DISCONNECTED;
+	if (!IRC_Show_MOTD(Client))
+		return DISCONNECTED;
+
+	/* Suspend the client for a second ... */
+	IRC_SetPenalty(Client, 1);
+
+	return CONNECTED;
+}
+
+#ifdef PAM
+
+/**
+ * Read result of the authenticatior sub-process from pipe
+ *
+ * @param r_fd		File descriptor of the pipe.
+ * @param events	(ignored IO specification)
+ */
+static void
+cb_Read_Auth_Result(int r_fd, UNUSED short events)
+{
+	CONN_ID conn;
+	CLIENT *client;
+	int result;
+	size_t len;
+	PROC_STAT *proc;
+
+	LogDebug("Auth: Got callback on fd %d, events %d", r_fd, events);
+	conn = Conn_GetFromProc(r_fd);
+	if (conn == NONE) {
+		/* Ops, none found? Probably the connection has already
+		 * been closed!? We'll ignore that ... */
+		io_close(r_fd);
+		LogDebug("Auth: Got callback for unknown connection!?");
+		return;
+	}
+	proc = Conn_GetProcStat(conn);
+	client = Conn_GetClient(conn);
+
+	/* Read result from pipe */
+	len = Proc_Read(proc, &result, sizeof(result));
+	Proc_Close(proc);
+	if (len == 0)
+		return;
+
+	if (len != sizeof(result)) {
+		Log(LOG_CRIT, "Auth: Got malformed result!");
+		Client_Reject(client, "Internal error", false);
+		return;
+	}
+
+	if (result == true) {
+		Client_SetUser(client, Client_OrigUser(client), true);
+		(void)Login_User_PostAuth(client);
+	} else
+		Client_Reject(client, "Bad password", false);
+}
+
+#endif
+
+/* -eof- */

+ 25 - 0
src/ngircd/login.h

@@ -0,0 +1,25 @@
+/*
+ * ngIRCd -- The Next Generation IRC Daemon
+ * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * Please read the file COPYING, README and AUTHORS for more information.
+ */
+
+#ifndef __login_h__
+#define __login_h__
+
+/**
+ * @file
+ * Functions to deal with client logins (header)
+ */
+
+GLOBAL bool Login_User PARAMS((CLIENT * Client));
+GLOBAL bool Login_User_PostAuth PARAMS((CLIENT *Client));
+
+#endif
+
+/* -eof- */

+ 1 - 0
src/ngircd/messages.h

@@ -103,6 +103,7 @@
 #define ERR_TOOMANYCHANNELS_MSG		"405 %s %s :You have joined too many channels"
 #define ERR_TOOMANYCHANNELS_MSG		"405 %s %s :You have joined too many channels"
 #define ERR_WASNOSUCHNICK_MSG		"406 %s %s :There was no such nickname"
 #define ERR_WASNOSUCHNICK_MSG		"406 %s %s :There was no such nickname"
 #define ERR_NOORIGIN_MSG		"409 %s :No origin specified"
 #define ERR_NOORIGIN_MSG		"409 %s :No origin specified"
+#define ERR_INVALIDCAP_MSG		"410 %s %s :Invalid CAP subcommand"
 #define ERR_NORECIPIENT_MSG		"411 %s :No recipient given (%s)"
 #define ERR_NORECIPIENT_MSG		"411 %s :No recipient given (%s)"
 #define ERR_NOTEXTTOSEND_MSG		"412 %s :No text to send"
 #define ERR_NOTEXTTOSEND_MSG		"412 %s :No text to send"
 #define ERR_WILDTOPLEVEL		"414 %s :Wildcard in toplevel domain"
 #define ERR_WILDTOPLEVEL		"414 %s :Wildcard in toplevel domain"

+ 6 - 7
src/ngircd/ngircd.c

@@ -498,7 +498,8 @@ Pidfile_Create(pid_t pid)
 
 
 	len = snprintf(pidbuf, sizeof pidbuf, "%ld\n", (long)pid);
 	len = snprintf(pidbuf, sizeof pidbuf, "%ld\n", (long)pid);
 	if (len < 0 || len >= (int)sizeof pidbuf) {
 	if (len < 0 || len >= (int)sizeof pidbuf) {
-		Log( LOG_ERR, "Error converting pid");
+		Log(LOG_ERR, "Error converting pid");
+		close(pidfd);
 		return;
 		return;
 	}
 	}
 	
 	
@@ -642,12 +643,10 @@ NGIRCd_Init(bool NGIRCd_NoDaemon)
 		}
 		}
 
 
 		if (chroot(Conf_Chroot) != 0) {
 		if (chroot(Conf_Chroot) != 0) {
-			if (errno != EPERM) {
-				Log(LOG_ERR,
-				    "Can't change root directory to \"%s\": %s",
-				    Conf_Chroot, strerror(errno));
-				goto out;
-			}
+			Log(LOG_ERR,
+			    "Can't change root directory to \"%s\": %s",
+			    Conf_Chroot, strerror(errno));
+			goto out;
 		} else {
 		} else {
 			chrooted = true;
 			chrooted = true;
 			Log(LOG_INFO,
 			Log(LOG_INFO,

+ 2 - 0
src/ngircd/parse.c

@@ -36,6 +36,7 @@
 
 
 #include "imp.h"
 #include "imp.h"
 #include "irc.h"
 #include "irc.h"
+#include "irc-cap.h"
 #include "irc-channel.h"
 #include "irc-channel.h"
 #include "irc-info.h"
 #include "irc-info.h"
 #include "irc-login.h"
 #include "irc-login.h"
@@ -113,6 +114,7 @@ static COMMAND My_Commands[] =
 	{ "CHANINFO", IRC_CHANINFO, CLIENT_SERVER, 0, 0, 0 },
 	{ "CHANINFO", IRC_CHANINFO, CLIENT_SERVER, 0, 0, 0 },
 #endif
 #endif
 #ifndef STRICT_RFC
 #ifndef STRICT_RFC
+	{ "CAP", IRC_CAP, 0xFFFF, 0, 0, 0 },
 	{ "GET",  IRC_QUIT_HTTP, CLIENT_UNKNOWN, 0, 0, 0 },
 	{ "GET",  IRC_QUIT_HTTP, CLIENT_UNKNOWN, 0, 0, 0 },
 	{ "POST", IRC_QUIT_HTTP, CLIENT_UNKNOWN, 0, 0, 0 },
 	{ "POST", IRC_QUIT_HTTP, CLIENT_UNKNOWN, 0, 0, 0 },
 #endif
 #endif

+ 4 - 1
src/ngircd/sighandlers.c

@@ -218,8 +218,11 @@ Signal_Handler_BH(int Signal)
 		break;
 		break;
 #ifdef DEBUG
 #ifdef DEBUG
 	case SIGUSR2:
 	case SIGUSR2:
-		if (NGIRCd_Debug)
+		if (NGIRCd_Debug) {
+			Log(LOG_INFO|LOG_snotice,
+			    "Got SIGUSR2, dumping internal state ...");
 			Dump_State();
 			Dump_State();
+		}
 		break;
 		break;
 	default:
 	default:
 		Log(LOG_DEBUG, "Got signal %d! Ignored.", Signal);
 		Log(LOG_DEBUG, "Got signal %d! Ignored.", Signal);