Browse Source

Import upstream version 0.12.1

Alexander Barton 16 years ago
parent
commit
85ea944066
100 changed files with 6865 additions and 2282 deletions
  1. 9 3
      AUTHORS
  2. 97 5
      ChangeLog
  3. 4 7
      INSTALL
  4. 7 5
      Makefile.am
  5. 7 5
      Makefile.in
  6. 43 2
      NEWS
  7. 7 8
      README
  8. 141 11
      configure
  9. 20 4
      configure.in
  10. 33 9
      contrib/Debian/changelog
  11. 1 1
      contrib/Debian/ngircd.init
  12. 12 5
      contrib/Debian/ngircd.postinst
  13. 33 2
      contrib/MacOSX/Makefile.am
  14. 220 34
      contrib/MacOSX/Makefile.in
  15. 92 0
      contrib/MacOSX/config.h
  16. 0 0
      contrib/MacOSX/cvs-version.h
  17. 19 0
      contrib/MacOSX/de.barton.ngircd.plist.tmpl
  18. 17 0
      contrib/MacOSX/ngIRCd.xcodeproj/Makefile.am
  19. 308 0
      contrib/MacOSX/ngIRCd.xcodeproj/Makefile.in
  20. 697 0
      contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj
  21. 1 1
      contrib/ngircd.spec
  22. 0 56
      doc/CVS.txt
  23. 1 10
      doc/FAQ.txt
  24. 45 0
      doc/GIT.txt
  25. 3 5
      doc/Makefile.am
  26. 3 5
      doc/Makefile.in
  27. 1 1
      doc/Platforms.txt
  28. 49 3
      doc/Protocol.txt
  29. 58 0
      doc/SSL.txt
  30. 1 1
      doc/Zeroconf.txt
  31. 37 8
      doc/sample-ngircd.conf
  32. 1 1
      doc/src/Makefile.am
  33. 1 1
      doc/src/Makefile.in
  34. 15 2
      man/Makefile.am
  35. 14 2
      man/Makefile.in
  36. 8 7
      man/ngircd.8
  37. 69 27
      man/ngircd.conf.5
  38. 2 2
      src/Makefile.am
  39. 2 2
      src/Makefile.in
  40. 9 0
      src/config.h.in
  41. 14 0
      src/ipaddr/Makefile.am
  42. 414 0
      src/ipaddr/Makefile.in
  43. 36 0
      src/ipaddr/ansi2knr.1
  44. 739 0
      src/ipaddr/ansi2knr.c
  45. 167 0
      src/ipaddr/ng_ipaddr.c
  46. 117 0
      src/ipaddr/ng_ipaddr.h
  47. 7 24
      src/ngircd/Makefile.am
  48. 14 28
      src/ngircd/Makefile.in
  49. 4 4
      src/ngircd/array.c
  50. 81 40
      src/ngircd/channel.c
  51. 5 4
      src/ngircd/channel.h
  52. 9 9
      src/ngircd/client.c
  53. 1 1
      src/ngircd/client.h
  54. 217 36
      src/ngircd/conf.c
  55. 22 4
      src/ngircd/conf.h
  56. 13 2
      src/ngircd/conn-func.c
  57. 2 1
      src/ngircd/conn-func.h
  58. 1 1
      src/ngircd/conn-zip.c
  59. 240 158
      src/ngircd/conn.c
  60. 6 3
      src/ngircd/conn.h
  61. 6 5
      src/ngircd/defines.h
  62. 1 1
      src/ngircd/hash.c
  63. 1 1
      src/ngircd/hash.h
  64. 486 513
      src/ngircd/io.c
  65. 1 1
      src/ngircd/io.h
  66. 206 179
      src/ngircd/irc-channel.c
  67. 389 165
      src/ngircd/irc-info.c
  68. 5 2
      src/ngircd/irc-info.h
  69. 39 48
      src/ngircd/irc-login.c
  70. 289 343
      src/ngircd/irc-mode.c
  71. 1 1
      src/ngircd/irc-op.c
  72. 63 5
      src/ngircd/irc-oper.c
  73. 2 1
      src/ngircd/irc-oper.h
  74. 25 185
      src/ngircd/irc-server.c
  75. 3 1
      src/ngircd/irc-server.h
  76. 1 1
      src/ngircd/irc-write.c
  77. 10 2
      src/ngircd/irc.c
  78. 2 4
      src/ngircd/lists.c
  79. 1 3
      src/ngircd/lists.h
  80. 1 1
      src/ngircd/log.c
  81. 1 1
      src/ngircd/log.h
  82. 1 1
      src/ngircd/match.c
  83. 1 1
      src/ngircd/match.h
  84. 7 2
      src/ngircd/messages.h
  85. 49 38
      src/ngircd/ngircd.c
  86. 334 0
      src/ngircd/numeric.c
  87. 24 0
      src/ngircd/numeric.h
  88. 136 87
      src/ngircd/parse.c
  89. 3 4
      src/ngircd/parse.h
  90. 302 122
      src/ngircd/resolve.c
  91. 4 2
      src/ngircd/resolve.h
  92. 16 3
      src/testsuite/Makefile.am
  93. 16 3
      src/testsuite/Makefile.in
  94. 31 1
      src/testsuite/channel-test.e
  95. 1 1
      src/testsuite/getpid.sh
  96. 44 0
      src/testsuite/misc-test.e
  97. 3 3
      src/testsuite/mode-test.e
  98. 2 1
      src/testsuite/ngircd-test.conf
  99. 162 0
      src/testsuite/who-test.e
  100. 0 0
      src/tool/tool.c

+ 9 - 3
AUTHORS

@@ -1,7 +1,7 @@
 
 
                      ngIRCd - Next Generation IRC Server
                      ngIRCd - Next Generation IRC Server
 
 
-                        (c)2001-2005 Alexander Barton,
+                        (c)2001-2007 Alexander Barton,
                     alex@barton.de, http://www.barton.de/
                     alex@barton.de, http://www.barton.de/
 
 
                ngIRCd is free software and published under the
                ngIRCd is free software and published under the
@@ -10,9 +10,16 @@
                        -- AUTHORS and CONTRIBUTORS --
                        -- AUTHORS and CONTRIBUTORS --
 
 
 
 
+Note: If you have critics, patches or something else, please feel free to
+post a mail to the ngIRCd mailing list: <ngircd-ml@arthur.ath.cx> (please see
+<http://ngircd.barton.de/#ml> for details). Don't mail the contributors
+directly, if possible!
+
+
 Main Authors
 Main Authors
 ~~~~~~~~~~~~
 ~~~~~~~~~~~~
 Alexander Barton, <alex@barton.de> (alex)
 Alexander Barton, <alex@barton.de> (alex)
+Florian Westphal, <westphal@foo.fh-furtwangen.de> (fw)
 
 
 
 
 Contributors
 Contributors
@@ -21,7 +28,6 @@ Goetz Hoffart, <goetz@hoffart.de> (goetz)
 Ilja Osthoff, <i.osthoff@gmx.net> (ilja)
 Ilja Osthoff, <i.osthoff@gmx.net> (ilja)
 Benjamin Pineau, <ben@zouh.org>
 Benjamin Pineau, <ben@zouh.org>
 Sean Reifschneider, <jafo-rpms@tummy.com>
 Sean Reifschneider, <jafo-rpms@tummy.com>
-Florian Westphal, <westphal@foo.fh-furtwangen.de> (fw)
 
 
 
 
 Code snippets
 Code snippets
@@ -32,4 +38,4 @@ Andrew Tridgell & Martin Pool: strl{cpy|cat}()-functions
 
 
 
 
 -- 
 -- 
-$Id: AUTHORS,v 1.11 2005/03/19 14:24:52 alex Exp $
+$Id: AUTHORS,v 1.13 2007/10/04 15:18:48 alex Exp $

+ 97 - 5
ChangeLog

@@ -1,7 +1,7 @@
 
 
                      ngIRCd - Next Generation IRC Server
                      ngIRCd - Next Generation IRC Server
 
 
-                        (c)2001-2007 Alexander Barton,
+                        (c)2001-2008 Alexander Barton,
                     alex@barton.de, http://www.barton.de/
                     alex@barton.de, http://www.barton.de/
 
 
                ngIRCd is free software and published under the
                ngIRCd is free software and published under the
@@ -10,7 +10,102 @@
                                -- ChangeLog --
                                -- ChangeLog --
 
 
 
 
-ngIRCd 0.10.3 (2007-07-31)
+ngIRCd 0.12.1 (2008-07-09)
+
+  - Allow mixed line terminations (CR+LF/CR/LF) in non-RFC-compliant mode
+  - Don't allow stray \r or \n in command parameters
+  - --configtest: return non-zero exit code if there are errors
+  - Update ngIRCd manual pages
+  - Add option aliases -V (for --version) and -h (for --help).
+  - Fix 'no-ipv6' compile error.
+  - Make Listen parameter a comma-seperated list of addresses. This also
+    obsoletes ListenIPv4 and ListenIPv6 options. If Listen is unset, it
+    is treated as Listen="::,0.0.0.0".
+    Note: ListenIPv4 and ListenIPv6 options are still recognized,
+    but ngircd will print a warning if they are used in the config file.
+
+ngIRCd 0.12.0 (2008-05-13)
+
+  - Fix Bug: 85: "WHO #SecretChannel" that user is not a member of now returns
+    proper RPL_ENDOFWHO_MSG instead of nothing. (Ali Shemiran)
+  - Fix complie on FreeBSD 5.4 and AIX.
+  - If bind() fails, also print ip address and not just the port number.
+
+  ngIRCd 0.12.0-pre2 (2008-04-29)
+  - IPv6: Add config options to disabe ipv4/ipv6 support.
+  - Don't include doc/CVS.txt in distribution archive, use doc/GIT.txt now!
+  - Documentation: get rid of some more references to CVS, switch to GIT.
+  - Get rid of cvs-version.* and CVSDATE definition.
+  - Report ERR_NOTONCHANNEL when trying to part a channel one is not member of.
+  - Testsuite: remove erroneous ConfUID setting in config file.
+
+  ngIRCd 0.12.0-pre1 (2008-04-20)
+  - Include Mac OS X Xcode project in distribution archives.
+  - Do not exit on SIGHUP or /REHASH if the config file cannot opened.
+  - Add IPv6 support.
+  - Install a LaunchDaemon script to start/stop ngIRCd on Mac OS X.
+  - Implemented IRC commands INFO, SUMMON (dummy), and USERS (dummy) and
+    enhanced test suite to check these commands. (Dana Dahlstrom)
+  - RPL_WHOREPLY messages generated by IRC_WHO didn't include flags (*,@,+).
+    (Dana Dahlstrom)
+  - 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.
+    (reported by Dana Dahlstrom)
+  - Add test cases for "WHO" command. (Dana Dahlstrom)
+  - 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
+    member of. (Dana Dahlstrom)
+  - Allow NOTICEs to be sent to a channel. (Fabian Schlager)
+
+ngIRCd 0.11.1 (2008-02-26)
+
+  - Fix sending of JOIN commands between servers when remote server appended
+    mode flags. (Rolf Eike Beer) [from HEAD]
+  - Send "G" instead of "H" flag in WHO replies. (reported by Dana Dahlstrom)
+  - Under some circumstances ngIRCd issued channel MODE message with a
+    trailing space. (Dana Dahlstrom) [from HEAD]
+
+ngIRCd 0.11.0 (2008-01-15)
+
+  ngIRCd 0.11.0-pre2 (2008-01-07)
+  - SECURITY: IRC_PART could reference invalid memory, causing
+    ngircd to crash [from HEAD].
+  
+  ngIRCd 0.11.0-pre1 (2008-01-02)
+  - Use dotted-decimal IP address if hostname is >= 64.
+  - Add support for /STAT u (server uptime) command.
+  - New [Server] configuration Option "Bind" allows to specify
+    the source ip adress to use when connecting to remote server.
+  - New configuration option "MaxNickLength" to specify the allowed maximum
+    length of user nick names. Note: must be unique in an IRC network!
+  - Enhanced the IRC+ protocol to support an enhanced "server handshake" and
+    enable server to recognice numeric 005 (ISUPPORT) and 376 (ENDOFMOTD).
+    See doc/Protocol.txt for details.
+  - Re-added doc/SSL.txt to distribution -- got lost somewhere!?
+  - Fixes the wrong logging output when nested servers are introduced
+    to the network as well as the wrong output of the LINKS command.
+  - Update Mac OS X Xcode project file for Xcode 3.
+  - Adjust test suite to be usable on HP/UX 11.11 :-)
+  - Fix code to compile using K&R C compiler and ansi2kr again.
+  - New config option NoDNS: Disables DNS lookups when clients connect.
+  - Fixed propagation of channel mode 'P' on server links.
+  - Numeric 317: implemented "signon time" (displayed in WHOIS result).
+  - Fixed code that prevented GCC 2.95 to compile ngIRCd.
+  - Adjust path names in manual pages according to "./configure" settings.
+  - Added new server configuration option "Passive" for "Server" blocks to
+    disable automatic outgoing connections (similar to -p option to ngircd,
+    but only for the specified server). (Tassilo Schweyer)
+  - Don't connect to a server if a connection to another server within the
+    same group is already in progress.
+  - Added support for the WALLOPS command. Usage is restricted to IRC
+    operators.
+
+ngIRCd 0.10.4 (2008-01-07)
+
+  - SECURITY: IRC_PART could reference invalid memory, causing
+    ngircd to crash [from HEAD].
+  
+ngIRCd 0.10.3 (2007-08-01)
 
 
   - SECURITY: Fixed a severe bug in handling JOIN commands, which could
   - SECURITY: Fixed a severe bug in handling JOIN commands, which could
     cause the server to crash. Thanks to Sebastian Vesper, <net@veoson.net>.
     cause the server to crash. Thanks to Sebastian Vesper, <net@veoson.net>.
@@ -691,7 +786,3 @@ ngIRCd 0.0.2, 06.01.2002
 ngIRCd 0.0.1, 31.12.2001
 ngIRCd 0.0.1, 31.12.2001
 
 
   - erste oeffentliche Version von ngIRCd als "public preview" :-)
   - erste oeffentliche Version von ngIRCd als "public preview" :-)
-
-
-$Id: ChangeLog,v 1.302.2.19 2007/07/31 19:33:51 alex Exp $

+ 4 - 7
INSTALL

@@ -1,7 +1,7 @@
 
 
                      ngIRCd - Next Generation IRC Server
                      ngIRCd - Next Generation IRC Server
 
 
-                      (c)2001-2006 by Alexander Barton,
+                        (c)2001-2007 Alexander Barton,
                     alex@barton.de, http://www.barton.de/
                     alex@barton.de, http://www.barton.de/
 
 
                ngIRCd is free software and published under the
                ngIRCd is free software and published under the
@@ -51,9 +51,9 @@ on modern UNIX-like systems that are supported by GNU autoconf and GNU
 automake ("configure") should be no problem.
 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 CVS) is as following:
+files (using a distribution archive or GIT) is as following:
 
 
-  1) ./autogen.sh	[only necessary when using CVS]
+  1) ./autogen.sh	[only necessary when using GIT]
   2) ./configure
   2) ./configure
   3) make
   3) make
   4) make install
   4) make install
@@ -77,7 +77,7 @@ doc/ directory: sample-ngircd.conf.
 
 
 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
 already generated. This never happens in official ("stable") releases in
 already generated. This never happens in official ("stable") releases in
-tar.gz-archives, but when using CVS.
+tar.gz-archives, but when using GIT.
 
 
 This step is therefore only interesting for developers.
 This step is therefore only interesting for developers.
 
 
@@ -244,7 +244,3 @@ These parameters could be passed to the ngIRCd:
 Use "--help" to see a short help text describing all available parameters
 Use "--help" to see a short help text describing all available parameters
 the server understands, with "--version" the ngIRCd shows its version
 the server understands, with "--version" the ngIRCd shows its version
 number. In both cases the server exits after the output.
 number. In both cases the server exits after the output.
-
-
-$Id: INSTALL,v 1.23.2.2 2007/04/03 22:08:50 fw Exp $

+ 7 - 5
Makefile.am

@@ -1,6 +1,6 @@
 #
 #
 # ngIRCd -- The Next Generation IRC Daemon
 # ngIRCd -- The Next Generation IRC Daemon
-# Copyright (c)2001-2003 by Alexander Barton (alex@barton.de)
+# Copyright (c)2001-2008 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
@@ -8,8 +8,6 @@
 # (at your option) any later version.
 # (at your option) any later version.
 # Please read the file COPYING, README and AUTHORS for more information.
 # Please read the file COPYING, README and AUTHORS for more information.
 #
 #
-# $Id: Makefile.am,v 1.17 2005/07/22 21:01:52 alex Exp $
-#
 
 
 AUTOMAKE_OPTIONS = gnu
 AUTOMAKE_OPTIONS = gnu
 
 
@@ -24,6 +22,9 @@ maintainer-clean-local:
 	rm -f mkinstalldirs missing depcomp install-sh
 	rm -f mkinstalldirs missing depcomp install-sh
 	rm -f config.log debian
 	rm -f config.log debian
 
 
+testsuite:
+	make -C src/testsuite check
+
 lint:
 lint:
 	make -C src/ngircd lint
 	make -C src/ngircd lint
 
 
@@ -31,9 +32,10 @@ srcdoc:
 	make -C doc srcdoc
 	make -C doc srcdoc
 
 
 xcode:
 xcode:
-	@xcodebuild -project contrib/MacOSX/ngIRCd.xcode -list >/dev/null 2>&1 \
+	@xcodebuild -project contrib/MacOSX/ngIRCd.xcodeproj -list \
+	 >/dev/null 2>&1 \
 	 || ( echo; echo "Error: \"xcodebuild\" not found!"; echo; exit 1 )
 	 || ( echo; echo "Error: \"xcodebuild\" not found!"; echo; exit 1 )
-	xcodebuild -project contrib/MacOSX/ngIRCd.xcode -alltargets \
+	xcodebuild -project contrib/MacOSX/ngIRCd.xcodeproj -alltargets \
 	 -buildstyle Development
 	 -buildstyle Development
 
 
 rpm: distcheck
 rpm: distcheck

+ 7 - 5
Makefile.in

@@ -16,7 +16,7 @@
 
 
 #
 #
 # ngIRCd -- The Next Generation IRC Daemon
 # ngIRCd -- The Next Generation IRC Daemon
-# Copyright (c)2001-2003 by Alexander Barton (alex@barton.de)
+# Copyright (c)2001-2008 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
@@ -24,8 +24,6 @@
 # (at your option) any later version.
 # (at your option) any later version.
 # Please read the file COPYING, README and AUTHORS for more information.
 # Please read the file COPYING, README and AUTHORS for more information.
 #
 #
-# $Id: Makefile.am,v 1.17 2005/07/22 21:01:52 alex Exp $
-#
 srcdir = @srcdir@
 srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_srcdir = @top_srcdir@
 VPATH = @srcdir@
 VPATH = @srcdir@
@@ -590,6 +588,9 @@ maintainer-clean-local:
 	rm -f mkinstalldirs missing depcomp install-sh
 	rm -f mkinstalldirs missing depcomp install-sh
 	rm -f config.log debian
 	rm -f config.log debian
 
 
+testsuite:
+	make -C src/testsuite check
+
 lint:
 lint:
 	make -C src/ngircd lint
 	make -C src/ngircd lint
 
 
@@ -597,9 +598,10 @@ srcdoc:
 	make -C doc srcdoc
 	make -C doc srcdoc
 
 
 xcode:
 xcode:
-	@xcodebuild -project contrib/MacOSX/ngIRCd.xcode -list >/dev/null 2>&1 \
+	@xcodebuild -project contrib/MacOSX/ngIRCd.xcodeproj -list \
+	 >/dev/null 2>&1 \
 	 || ( echo; echo "Error: \"xcodebuild\" not found!"; echo; exit 1 )
 	 || ( echo; echo "Error: \"xcodebuild\" not found!"; echo; exit 1 )
-	xcodebuild -project contrib/MacOSX/ngIRCd.xcode -alltargets \
+	xcodebuild -project contrib/MacOSX/ngIRCd.xcodeproj -alltargets \
 	 -buildstyle Development
 	 -buildstyle Development
 
 
 rpm: distcheck
 rpm: distcheck

+ 43 - 2
NEWS

@@ -1,7 +1,7 @@
 
 
                      ngIRCd - Next Generation IRC Server
                      ngIRCd - Next Generation IRC Server
 
 
-                        (c)2001-2007 Alexander Barton,
+                        (c)2001-2008 Alexander Barton,
                     alex@barton.de, http://www.barton.de/
                     alex@barton.de, http://www.barton.de/
 
 
                ngIRCd is free software and published under the
                ngIRCd is free software and published under the
@@ -10,6 +10,47 @@
                                   -- NEWS --
                                   -- NEWS --
 
 
 
 
+ngIRCd 0.12.1 (2008-07-09)
+
+  - Add option aliases -V (for --version) and -h (for --help).
+  - Make Listen parameter a comma-seperated list of addresses. This also
+    obsoletes ListenIPv4 and ListenIPv6 options. If Listen is unset, it
+    is treated as Listen="::,0.0.0.0".
+    Note: ListenIPv4 and ListenIPv6 options are still recognized,
+    but ngircd will print a warning if they are used in the config file.
+
+ngIRCd 0.12.0 (2008-05-13)
+
+  ngIRCd 0.12.0-pre2 (2008-04-29)
+  - IPv6: Add config options to disabe ipv4/ipv6 support.
+
+  ngIRCd 0.12.0-pre1 (2008-04-20)
+  - Add IPv6 support.
+  - Install a LaunchDaemon script to start/stop ngIRCd on Mac OS X.
+  - Implemented IRC commands INFO, SUMMON (dummy), and USERS (dummy) and
+    enhanced test suite to check these commands. (Dana Dahlstrom)
+  - 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.
+    (reported by Dana Dahlstrom)
+  - 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
+    member of. (Dana Dahlstrom)
+  - Allow NOTICEs to be sent to a channel. (Fabian Schlager)
+
+ngIRCd 0.11.0 (2008-01-15)
+
+  - Add support for /STAT u (server uptime) command.
+  - New [Server] configuration Option "Bind" allows to specify
+    the source ip adress to use when connecting to remote server.
+  - New configuration option "MaxNickLength" to specify the allowed maximum
+    length of user nick names. Note: must be unique in an IRC network!
+  - Numeric 317: implemented "signon time" (displayed in WHOIS result).
+  - Added new server configuration option "Passive" for "Server" blocks to
+    disable automatic outgoing connections (similar to -p option to ngircd,
+    but only for the specified server). (Tassilo Schweyer)
+  - Added support for the WALLOPS command. Usage is restricted to IRC
+    operators.
+
 ngIRCd 0.10.2 (2007-06-08)
 ngIRCd 0.10.2 (2007-06-08)
 
 
   - Predefined channel configuration now allows specification of channel key
   - Predefined channel configuration now allows specification of channel key
@@ -237,4 +278,4 @@ ngIRCd 0.0.1, 31.12.2001
 
 
 
 
 -- 
 -- 
-$Id: NEWS,v 1.75.2.7 2007/06/08 09:05:23 alex Exp $
+$Id: NEWS,v 1.88 2008/02/26 22:05:42 fw Exp $

+ 7 - 8
README

@@ -37,7 +37,8 @@ Implemented IRC-commands are:
 ADMIN, AWAY, CHANINFO, CONNECT, DIE, DISCONNECT, ERROR, HELP, INVITE, ISON,
 ADMIN, AWAY, CHANINFO, CONNECT, DIE, DISCONNECT, ERROR, HELP, INVITE, ISON,
 JOIN, KICK, KILL, LINKS, LIST, LUSERS, MODE, MOTD, NAMES, NICK, NJOIN, NOTICE,
 JOIN, KICK, KILL, LINKS, LIST, LUSERS, MODE, MOTD, NAMES, NICK, NJOIN, NOTICE,
 OPER, PART, PASS, PING, PONG, PRIVMSG, QUIT, REHASH, RESTART, SERVER, SQUIT,
 OPER, PART, PASS, PING, PONG, PRIVMSG, QUIT, REHASH, RESTART, SERVER, SQUIT,
-STATS, TIME, TOPIC, TRACE, USER, USERHOST, VERSION, WHO, WHOIS, WHOWAS.
+STATS, TIME, TOPIC, TRACE, USER, USERHOST, VERSION, WALLOPS, WHO, WHOIS,
+WHOWAS.
 
 
 
 
 III. Features (or: why use ngIRCd?)
 III. Features (or: why use ngIRCd?)
@@ -66,9 +67,9 @@ the newest information about the ngIRCd and the most recent ("stable")
 releases there.
 releases there.
 
 
 If you are interested in the latest development versions (which are not
 If you are interested in the latest development versions (which are not
-always stable), then please read the section "CVS" on the homepage and
-the file "doc/CVS.txt" which describes the use of CVS, the "Concurrent
-Versioning System".
+always stable), then please read the section about "GIT" on the homepage and
+the file "doc/GIT.txt" which describes the use of GIT, the version control
+system used by ngIRCd (homepage: http://git.or.cz/).
 
 
 
 
 VI. Bugs
 VI. Bugs
@@ -82,8 +83,5 @@ them at the following URL:
 There you can read about known bugs and limitations, too.
 There you can read about known bugs and limitations, too.
 
 
 If you have critics, patches or something else, please feel free to post a
 If you have critics, patches or something else, please feel free to post a
-mail to <alex@barton.de>.
-
-
-$Id: README,v 1.21.2.2 2007/05/05 20:25:20 alex Exp $
+mail to the ngIRCd mailing list: <ngircd-ml@arthur.ath.cx> (please see
+<http://ngircd.barton.de/#ml> for details).

+ 141 - 11
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.59 for ngircd 0.10.3.
+# Generated by GNU Autoconf 2.59 for ngircd 0.12.1.
 #
 #
 # Copyright (C) 2003 Free Software Foundation, Inc.
 # Copyright (C) 2003 Free Software Foundation, Inc.
 # This configure script is free software; the Free Software Foundation
 # This configure script is free software; the Free Software Foundation
@@ -267,8 +267,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 # Identity of this package.
 PACKAGE_NAME='ngircd'
 PACKAGE_NAME='ngircd'
 PACKAGE_TARNAME='ngircd'
 PACKAGE_TARNAME='ngircd'
-PACKAGE_VERSION='0.10.3'
-PACKAGE_STRING='ngircd 0.10.3'
+PACKAGE_VERSION='0.12.1'
+PACKAGE_STRING='ngircd 0.12.1'
 PACKAGE_BUGREPORT=''
 PACKAGE_BUGREPORT=''
 
 
 ac_unique_file="src/ngircd/ngircd.c"
 ac_unique_file="src/ngircd/ngircd.c"
@@ -778,7 +778,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 0.10.3 to adapt to many kinds of systems.
+\`configure' configures ngircd 0.12.1 to adapt to many kinds of systems.
 
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
 
@@ -845,7 +845,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 0.10.3:";;
+     short | recursive ) echo "Configuration of ngircd 0.12.1:";;
    esac
    esac
   cat <<\_ACEOF
   cat <<\_ACEOF
 
 
@@ -855,6 +855,7 @@ Optional Features:
   --disable-dependency-tracking  speeds up one-time build
   --disable-dependency-tracking  speeds up one-time build
   --enable-dependency-tracking   do not reject slow dependency extractors
   --enable-dependency-tracking   do not reject slow dependency extractors
   --disable-ircplus       disable IRC+ protocol
   --disable-ircplus       disable IRC+ protocol
+  --enable-ipv6           enable IPv6 protocol support
   --enable-sniffer        enable IRC traffic sniffer (enables debug mode)
   --enable-sniffer        enable IRC traffic sniffer (enables debug mode)
   --enable-debug          show additional debug output
   --enable-debug          show additional debug output
   --enable-strict-rfc     strict RFC conformance -- may break clients!
   --enable-strict-rfc     strict RFC conformance -- may break clients!
@@ -980,7 +981,7 @@ fi
 test -n "$ac_init_help" && exit 0
 test -n "$ac_init_help" && exit 0
 if $ac_init_version; then
 if $ac_init_version; then
   cat <<\_ACEOF
   cat <<\_ACEOF
-ngircd configure 0.10.3
+ngircd configure 0.12.1
 generated by GNU Autoconf 2.59
 generated by GNU Autoconf 2.59
 
 
 Copyright (C) 2003 Free Software Foundation, Inc.
 Copyright (C) 2003 Free Software Foundation, Inc.
@@ -994,7 +995,7 @@ cat >&5 <<_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 0.10.3, which was
+It was created by ngircd $as_me 0.12.1, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
 
   $ $0 $@
   $ $0 $@
@@ -1720,7 +1721,7 @@ fi
 
 
 # Define the identity of the package.
 # Define the identity of the package.
  PACKAGE='ngircd'
  PACKAGE='ngircd'
- VERSION='0.10.3'
+ VERSION='0.12.1'
 
 
 
 
 cat >>confdefs.h <<_ACEOF
 cat >>confdefs.h <<_ACEOF
@@ -1883,6 +1884,8 @@ am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
 
 
 
 
 
 
+
+
 # -- C Compiler --
 # -- C Compiler --
 
 
 ac_ext=c
 ac_ext=c
@@ -9650,6 +9653,129 @@ _ACEOF
 
 
 fi
 fi
 
 
+# enable support for IPv6?
+x_ipv6_on=no
+# Check whether --enable-ipv6 or --disable-ipv6 was given.
+if test "${enable_ipv6+set}" = set; then
+  enableval="$enable_ipv6"
+  if test "$enableval" = "yes"; then x_ipv6_on=yes; fi
+
+fi;
+if test "$x_ipv6_on" = "yes"; then
+
+
+for ac_func in  \
+		getaddrinfo getnameinfo \
+
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  { { echo "$as_me:$LINENO: error: required function missing for IPv6 support!" >&5
+echo "$as_me: error: required function missing for IPv6 support!" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+done
+
+	cat >>confdefs.h <<\_ACEOF
+#define WANT_IPV6 1
+_ACEOF
+
+fi
+
 # compile in IRC "sniffer"?
 # compile in IRC "sniffer"?
 
 
 x_sniffer_on=no; x_debug_on=no
 x_sniffer_on=no; x_debug_on=no
@@ -9719,7 +9845,7 @@ test -n "$CFLAGS_END" && CFLAGS="$CFLAGS $CFLAGS_END"
 
 
 # -- Generate files --
 # -- Generate files --
 
 
-                                                                                                                        ac_config_files="$ac_config_files Makefile doc/Makefile doc/src/Makefile src/Makefile src/portab/Makefile src/tool/Makefile src/ngircd/Makefile src/testsuite/Makefile man/Makefile contrib/Makefile contrib/Debian/Makefile contrib/MacOSX/Makefile"
+                                                                                                                                            ac_config_files="$ac_config_files Makefile doc/Makefile doc/src/Makefile src/Makefile src/portab/Makefile src/ipaddr/Makefile src/tool/Makefile src/ngircd/Makefile src/testsuite/Makefile man/Makefile contrib/Makefile contrib/Debian/Makefile contrib/MacOSX/Makefile contrib/MacOSX/ngIRCd.xcodeproj/Makefile"
 cat >confcache <<\_ACEOF
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
 # tests run on this system so they can be shared between configure
@@ -10096,7 +10222,7 @@ _ASBOX
 } >&5
 } >&5
 cat >&5 <<_CSEOF
 cat >&5 <<_CSEOF
 
 
-This file was extended by ngircd $as_me 0.10.3, which was
+This file was extended by ngircd $as_me 0.12.1, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_FILES    = $CONFIG_FILES
@@ -10159,7 +10285,7 @@ _ACEOF
 
 
 cat >>$CONFIG_STATUS <<_ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
 ac_cs_version="\\
-ngircd config.status 0.10.3
+ngircd config.status 0.12.1
 configured by $0, generated by GNU Autoconf 2.59,
 configured by $0, generated by GNU Autoconf 2.59,
   with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
   with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
 
 
@@ -10274,6 +10400,7 @@ do
   "doc/src/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/src/Makefile" ;;
   "doc/src/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/src/Makefile" ;;
   "src/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
   "src/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
   "src/portab/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/portab/Makefile" ;;
   "src/portab/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/portab/Makefile" ;;
+  "src/ipaddr/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/ipaddr/Makefile" ;;
   "src/tool/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/tool/Makefile" ;;
   "src/tool/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/tool/Makefile" ;;
   "src/ngircd/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/ngircd/Makefile" ;;
   "src/ngircd/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/ngircd/Makefile" ;;
   "src/testsuite/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/testsuite/Makefile" ;;
   "src/testsuite/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/testsuite/Makefile" ;;
@@ -10281,6 +10408,7 @@ do
   "contrib/Makefile" ) CONFIG_FILES="$CONFIG_FILES contrib/Makefile" ;;
   "contrib/Makefile" ) CONFIG_FILES="$CONFIG_FILES contrib/Makefile" ;;
   "contrib/Debian/Makefile" ) CONFIG_FILES="$CONFIG_FILES contrib/Debian/Makefile" ;;
   "contrib/Debian/Makefile" ) CONFIG_FILES="$CONFIG_FILES contrib/Debian/Makefile" ;;
   "contrib/MacOSX/Makefile" ) CONFIG_FILES="$CONFIG_FILES contrib/MacOSX/Makefile" ;;
   "contrib/MacOSX/Makefile" ) CONFIG_FILES="$CONFIG_FILES contrib/MacOSX/Makefile" ;;
+  "contrib/MacOSX/ngIRCd.xcodeproj/Makefile" ) CONFIG_FILES="$CONFIG_FILES contrib/MacOSX/ngIRCd.xcodeproj/Makefile" ;;
   "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
   "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
   "src/config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;;
   "src/config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;;
   *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
   *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
@@ -11230,6 +11358,8 @@ test "$x_identauth_on" = "yes" \
 echo $ECHO_N "        I/O backend: $ECHO_C"
 echo $ECHO_N "        I/O backend: $ECHO_C"
 	echo "\"$x_io_backend\""
 	echo "\"$x_io_backend\""
 
 
+echo $ECHO_N "      IPv6 protocol: $ECHO_C"
+echo "$x_ipv6_on"
 echo
 echo
 
 
 # -eof-
 # -eof-

+ 20 - 4
configure.in

@@ -1,6 +1,6 @@
 #
 #
 # ngIRCd -- The Next Generation IRC Daemon
 # ngIRCd -- The Next Generation IRC Daemon
-# Copyright (c)2001-2007 Alexander Barton <alex@barton.de>
+# Copyright (c)2001-2008 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
@@ -8,13 +8,11 @@
 # (at your option) any later version.
 # (at your option) any later version.
 # Please read the file COPYING, README and AUTHORS for more information.
 # Please read the file COPYING, README and AUTHORS for more information.
 #
 #
-# $Id: configure.in,v 1.118.2.13 2007/07/31 19:07:59 alex Exp $
-#
 
 
 # -- Initialisation --
 # -- Initialisation --
 
 
 AC_PREREQ(2.50)
 AC_PREREQ(2.50)
-AC_INIT(ngircd, 0.10.3)
+AC_INIT(ngircd, 0.12.1)
 AC_CONFIG_SRCDIR(src/ngircd/ngircd.c)
 AC_CONFIG_SRCDIR(src/ngircd/ngircd.c)
 AC_CANONICAL_TARGET
 AC_CANONICAL_TARGET
 AM_INIT_AUTOMAKE(1.6)
 AM_INIT_AUTOMAKE(1.6)
@@ -30,6 +28,7 @@ AH_TEMPLATE([SYSLOG], [Define if syslog should be used for logging])
 AH_TEMPLATE([ZLIB], [Define if zlib compression should be enabled])
 AH_TEMPLATE([ZLIB], [Define if zlib compression should be enabled])
 AH_TEMPLATE([TCPWRAP], [Define if TCP wrappers should be used])
 AH_TEMPLATE([TCPWRAP], [Define if TCP wrappers should be used])
 AH_TEMPLATE([IRCPLUS], [Define if IRC+ protocol should be used])
 AH_TEMPLATE([IRCPLUS], [Define if IRC+ protocol should be used])
+AH_TEMPLATE([WANT_IPV6], [Define if IPV6 protocol should be enabled])
 AH_TEMPLATE([ZEROCONF], [Define if support for Zeroconf should be included])
 AH_TEMPLATE([ZEROCONF], [Define if support for Zeroconf should be included])
 AH_TEMPLATE([IDENTAUTH], [Define if the server should do IDENT requests])
 AH_TEMPLATE([IDENTAUTH], [Define if the server should do IDENT requests])
 
 
@@ -426,6 +425,19 @@ if test "$x_ircplus_on" = "yes"; then
 	AC_DEFINE(IRCPLUS, 1)
 	AC_DEFINE(IRCPLUS, 1)
 fi
 fi
 
 
+# enable support for IPv6?
+x_ipv6_on=no
+AC_ARG_ENABLE(ipv6,
+	[  --enable-ipv6           enable IPv6 protocol support],
+	if test "$enableval" = "yes"; then x_ipv6_on=yes; fi
+)
+if test "$x_ipv6_on" = "yes"; then
+	AC_CHECK_FUNCS([ \
+		getaddrinfo getnameinfo \
+		],,AC_MSG_ERROR([required function missing for IPv6 support!]))
+	AC_DEFINE(WANT_IPV6, 1)
+fi
+
 # compile in IRC "sniffer"?
 # compile in IRC "sniffer"?
 
 
 x_sniffer_on=no; x_debug_on=no
 x_sniffer_on=no; x_debug_on=no
@@ -477,6 +489,7 @@ AC_OUTPUT([ \
 	doc/src/Makefile \
 	doc/src/Makefile \
 	src/Makefile \
 	src/Makefile \
 	src/portab/Makefile \
 	src/portab/Makefile \
+	src/ipaddr/Makefile \
 	src/tool/Makefile \
 	src/tool/Makefile \
 	src/ngircd/Makefile \
 	src/ngircd/Makefile \
 	src/testsuite/Makefile \
 	src/testsuite/Makefile \
@@ -484,6 +497,7 @@ AC_OUTPUT([ \
 	contrib/Makefile \
 	contrib/Makefile \
 	contrib/Debian/Makefile \
 	contrib/Debian/Makefile \
 	contrib/MacOSX/Makefile \
 	contrib/MacOSX/Makefile \
+	contrib/MacOSX/ngIRCd.xcodeproj/Makefile \
 ])
 ])
 
 
 type dpkg >/dev/null 2>&1
 type dpkg >/dev/null 2>&1
@@ -572,6 +586,8 @@ test "$x_identauth_on" = "yes" \
 echo $ECHO_N "        I/O backend: $ECHO_C"
 echo $ECHO_N "        I/O backend: $ECHO_C"
 	echo "\"$x_io_backend\""
 	echo "\"$x_io_backend\""
 
 
+echo $ECHO_N "      IPv6 protocol: $ECHO_C"
+echo "$x_ipv6_on"
 echo
 echo
 
 
 # -eof-
 # -eof-

+ 33 - 9
contrib/Debian/changelog

@@ -1,20 +1,44 @@
-ngircd (0.10.3-0ab1) unstable; urgency=high
+ngircd (0.12.1-0ab1) unstable; urgency=low
 
 
-  * New "upstream" release: 0.10.3 - fixing a security bug.
+  * New "upstream" release ngIRCd 0.12.1.
 
 
- -- Alexander Barton <alex@barton.de>  Tue, 31 Jul 2007 21:02:52 +0200
+ -- Alexander Barton <alex@barton.de>  Wed,  9 Jul 2008 11:27:00 +0200
 
 
-ngircd (0.10.2-0ab1) unstable; urgency=low
+ngircd (0.12.0-0ab1) unstable; urgency=low
 
 
-  * New "upstream" release: 0.10.2
+  * New "upstream" release ngIRCd 0.12.0.
 
 
- -- Alexander Barton <alex@barton.de>  Fri,  8 Jun 2007 10:49:36 +0200
+ -- Alexander Barton <alex@barton.de>  Tue, 13 May 2008 12:30:31 +0200
 
 
-ngircd (0.10.1-0ab1) unstable; urgency=low
+ngircd (0.12.0-0ab0-pre2) unstable; urgency=low
 
 
-  * New "upstream" release: 0.10.1
+  * Second prerelease of upcoming new "upstrem" release 0.12.0-pre1.
 
 
- -- Alexander Barton <alex@barton.de>  Sun, 17 Dec 2006 14:52:06 +0100
+ -- Alexander Barton <alex@barton.de>  Tue, 29 Apr 2008 23:06:14 +0200
+
+ngircd (0.12.0-0ab0-pre1) unstable; urgency=low
+
+  * Prereloease of upcoming new "upstrem" release 0.12.0-pre1.
+
+ -- Alexander Barton <alex@barton.de>  Sun, 20 Apr 2008 15:43:34 +0200
+
+ngircd (0.11.0-0ab0-pre2) unstable; urgency=low
+
+  * Second prerelease of upcoming new "upstream release".
+
+ -- Alexander Barton <alex@barton.de>  Mon,  7 Jan 2008 15:32:42 +0100
+
+ngircd (0.11.0-0ab0-pre1) unstable; urgency=low
+
+  * Prerelease of upcoming new "upstream release".
+
+ -- Alexander Barton <alex@barton.de>  Wed,  2 Jan 2008 21:33:15 +0100
+
+ngircd (0.10.4-0ab1) unstable; urgency=high
+
+  * New "upstream" release: 0.10.4 - fixing a security bug.
+
+ -- Alexander Barton <alex@barton.de>  Mon,  7 Jan 2008 22:04:44 +0100
 
 
 ngircd (0.10.0-0ab1) unstable; urgency=low
 ngircd (0.10.0-0ab1) unstable; urgency=low
 
 

+ 1 - 1
contrib/Debian/ngircd.init

@@ -2,7 +2,7 @@
 #
 #
 # ngIRCd start and stop script for Debian-based systems
 # ngIRCd start and stop script for Debian-based systems
 #
 #
-# $Id: ngircd.init,v 1.6.2.1 2007/04/03 22:08:50 fw Exp $
+# $Id: ngircd.init,v 1.7 2006/12/26 14:43:46 alex Exp $
 #
 #
 
 
 ### BEGIN INIT INFO
 ### BEGIN INIT INFO

+ 12 - 5
contrib/Debian/ngircd.postinst

@@ -1,13 +1,20 @@
 #!/bin/sh
 #!/bin/sh
 #
 #
 # Debian post-installation script
 # Debian post-installation script
-# $Id: ngircd.postinst,v 1.1 2003/12/31 17:20:11 alex Exp $
+# $Id: ngircd.postinst,v 1.2 2006/12/26 14:44:40 alex Exp $
 #
 #
 
 
-if [ -f /etc/ngircd/ngircd.conf ]; then
-	# make sure that configuration file is not world readable
-	chmod o= /etc/ngircd/ngircd.conf
-fi
+set -e
+
+case "$1" in
+	configure)
+		if [ -f /etc/ngircd/ngircd.conf ]; then
+			# make sure that the configuration file is not
+			# world-readable, it contains passwords!
+			chmod o= /etc/ngircd/ngircd.conf
+		fi
+		;;
+esac
 
 
 #DEBHELPER#
 #DEBHELPER#
 
 

+ 33 - 2
contrib/MacOSX/Makefile.am

@@ -1,6 +1,6 @@
 #
 #
 # ngIRCd -- The Next Generation IRC Daemon
 # ngIRCd -- The Next Generation IRC Daemon
-# Copyright (c)2001-2004 Alexander Barton <alex@barton.de>
+# Copyright (c)2001-2008 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
@@ -8,9 +8,40 @@
 # (at your option) any later version.
 # (at your option) any later version.
 # Please read the file COPYING, README and AUTHORS for more information.
 # Please read the file COPYING, README and AUTHORS for more information.
 #
 #
-# $Id: Makefile.am,v 1.2 2004/05/11 00:34:26 alex Exp $
+# $Id: Makefile.am,v 1.3 2008/02/17 15:31:15 alex Exp $
 #
 #
 
 
+SUBDIRS = ngIRCd.xcodeproj
+
+EXTRA_DIST = de.barton.ngircd.plist.tmpl config.h cvs-version.h
+
+SUFFIXES = .tmpl .
+
+.tmpl:
+	sed \
+	    -e s@:SBINDIR:@${sbindir}@ \
+	    <$< >$@
+
+install-data-local:
+	[ `uname -s` != "Darwin" ] || make install-sys-darwin
+
+install-sys-darwin:
+	@if [ `id -u` -eq 0 ]; then \
+	  make install-sys-darwin-root; \
+	else \
+	  echo; \
+	  echo " ** NOTE: Not installing with root privileges, so the LaunchDaemon script"; \
+	  echo " ** \"/Library/LaunchDaemons/de.barton.ngircd.plist\" can't be installed/updated!"; \
+	  echo; \
+	fi
+
+install-sys-darwin-root: de.barton.ngircd.plist
+	install -c -m 644 -b -o root -g wheel de.barton.ngircd.plist /Library/LaunchDaemons/de.barton.ngircd.plist
+	@echo
+	@echo " ** \"/Library/LaunchDaemons/de.barton.ngircd.plist\" has been installed,"
+	@echo " ** but is disabled. Use launchctl(8) to enable/run ngIRCd on Darwin/Mac OS X."
+	@echo
+
 clean-local:
 clean-local:
 	rm -rf build
 	rm -rf build
 
 

+ 220 - 34
contrib/MacOSX/Makefile.in

@@ -16,7 +16,7 @@
 
 
 #
 #
 # ngIRCd -- The Next Generation IRC Daemon
 # ngIRCd -- The Next Generation IRC Daemon
-# Copyright (c)2001-2004 Alexander Barton <alex@barton.de>
+# Copyright (c)2001-2008 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
@@ -24,7 +24,7 @@
 # (at your option) any later version.
 # (at your option) any later version.
 # Please read the file COPYING, README and AUTHORS for more information.
 # Please read the file COPYING, README and AUTHORS for more information.
 #
 #
-# $Id: Makefile.am,v 1.2 2004/05/11 00:34:26 alex Exp $
+# $Id: Makefile.am,v 1.3 2008/02/17 15:31:15 alex Exp $
 #
 #
 srcdir = @srcdir@
 srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_srcdir = @top_srcdir@
@@ -60,6 +60,15 @@ CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_FILES =
 SOURCES =
 SOURCES =
 DIST_SOURCES =
 DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+	html-recursive info-recursive install-data-recursive \
+	install-exec-recursive install-info-recursive \
+	install-recursive installcheck-recursive installdirs-recursive \
+	pdf-recursive ps-recursive uninstall-info-recursive \
+	uninstall-recursive
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ACLOCAL = @ACLOCAL@
 AMDEP_FALSE = @AMDEP_FALSE@
 AMDEP_FALSE = @AMDEP_FALSE@
@@ -148,9 +157,13 @@ target_alias = @target_alias@
 target_cpu = @target_cpu@
 target_cpu = @target_cpu@
 target_os = @target_os@
 target_os = @target_os@
 target_vendor = @target_vendor@
 target_vendor = @target_vendor@
-all: all-am
+SUBDIRS = ngIRCd.xcodeproj
+EXTRA_DIST = de.barton.ngircd.plist.tmpl config.h cvs-version.h
+SUFFIXES = .tmpl .
+all: all-recursive
 
 
 .SUFFIXES:
 .SUFFIXES:
+.SUFFIXES: .tmpl .
 $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	@for dep in $?; do \
 	@for dep in $?; do \
 	  case '$(am__configure_deps)' in \
 	  case '$(am__configure_deps)' in \
@@ -181,12 +194,138 @@ $(top_srcdir)/configure:  $(am__configure_deps)
 $(ACLOCAL_M4):  $(am__aclocal_m4_deps)
 $(ACLOCAL_M4):  $(am__aclocal_m4_deps)
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 uninstall-info-am:
 uninstall-info-am:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+	@failcom='exit 1'; \
+	for f in x $$MAKEFLAGS; do \
+	  case $$f in \
+	    *=* | --[!k]*);; \
+	    *k*) failcom='fail=yes';; \
+	  esac; \
+	done; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+	@failcom='exit 1'; \
+	for f in x $$MAKEFLAGS; do \
+	  case $$f in \
+	    *=* | --[!k]*);; \
+	    *k*) failcom='fail=yes';; \
+	  esac; \
+	done; \
+	dot_seen=no; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	rev=''; for subdir in $$list; do \
+	  if test "$$subdir" = "."; then :; else \
+	    rev="$$subdir $$rev"; \
+	  fi; \
+	done; \
+	rev="$$rev ."; \
+	target=`echo $@ | sed s/-recursive//`; \
+	for subdir in $$rev; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done && test -z "$$fail"
+tags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+	done
+ctags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
 tags: TAGS
 tags: TAGS
-TAGS:
 
 
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
 ctags: CTAGS
 ctags: CTAGS
-CTAGS:
-
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 
 
 distdir: $(DISTFILES)
 distdir: $(DISTFILES)
 	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
 	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
@@ -215,19 +354,35 @@ distdir: $(DISTFILES)
 	    || exit 1; \
 	    || exit 1; \
 	  fi; \
 	  fi; \
 	done
 	done
+	list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test -d "$(distdir)/$$subdir" \
+	    || $(mkdir_p) "$(distdir)/$$subdir" \
+	    || exit 1; \
+	    distdir=`$(am__cd) $(distdir) && pwd`; \
+	    top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+	    (cd $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$top_distdir" \
+	        distdir="$$distdir/$$subdir" \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
 check-am: all-am
 check-am: all-am
-check: check-am
+check: check-recursive
 all-am: Makefile
 all-am: Makefile
-installdirs:
-install: install-am
-install-exec: install-exec-am
-install-data: install-data-am
-uninstall: uninstall-am
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
 
 
 install-am: all-am
 install-am: all-am
 	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
 	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
 
 
-installcheck: installcheck-am
+installcheck: installcheck-recursive
 install-strip:
 install-strip:
 	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
 	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
 	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
 	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
@@ -243,62 +398,93 @@ distclean-generic:
 maintainer-clean-generic:
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
 	@echo "This command is intended for maintainers to use"
 	@echo "it deletes files that may require special tools to rebuild."
 	@echo "it deletes files that may require special tools to rebuild."
-clean: clean-am
+clean: clean-recursive
 
 
 clean-am: clean-generic clean-local mostlyclean-am
 clean-am: clean-generic clean-local mostlyclean-am
 
 
-distclean: distclean-am
+distclean: distclean-recursive
 	-rm -f Makefile
 	-rm -f Makefile
-distclean-am: clean-am distclean-generic
+distclean-am: clean-am distclean-generic distclean-tags
 
 
-dvi: dvi-am
+dvi: dvi-recursive
 
 
 dvi-am:
 dvi-am:
 
 
-html: html-am
+html: html-recursive
 
 
-info: info-am
+info: info-recursive
 
 
 info-am:
 info-am:
 
 
-install-data-am:
+install-data-am: install-data-local
 
 
 install-exec-am:
 install-exec-am:
 
 
-install-info: install-info-am
+install-info: install-info-recursive
 
 
 install-man:
 install-man:
 
 
 installcheck-am:
 installcheck-am:
 
 
-maintainer-clean: maintainer-clean-am
+maintainer-clean: maintainer-clean-recursive
 	-rm -f Makefile
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic \
 maintainer-clean-am: distclean-am maintainer-clean-generic \
 	maintainer-clean-local
 	maintainer-clean-local
 
 
-mostlyclean: mostlyclean-am
+mostlyclean: mostlyclean-recursive
 
 
 mostlyclean-am: mostlyclean-generic
 mostlyclean-am: mostlyclean-generic
 
 
-pdf: pdf-am
+pdf: pdf-recursive
 
 
 pdf-am:
 pdf-am:
 
 
-ps: ps-am
+ps: ps-recursive
 
 
 ps-am:
 ps-am:
 
 
 uninstall-am: uninstall-info-am
 uninstall-am: uninstall-info-am
 
 
-.PHONY: all all-am check check-am clean clean-generic clean-local \
-	distclean distclean-generic distdir dvi dvi-am html html-am \
-	info info-am install install-am install-data install-data-am \
-	install-exec install-exec-am install-info install-info-am \
-	install-man install-strip installcheck installcheck-am \
-	installdirs maintainer-clean maintainer-clean-generic \
-	maintainer-clean-local mostlyclean mostlyclean-generic pdf \
-	pdf-am ps ps-am uninstall uninstall-am uninstall-info-am
-
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \
+	clean clean-generic clean-local clean-recursive ctags \
+	ctags-recursive distclean distclean-generic \
+	distclean-recursive distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-data-local install-exec \
+	install-exec-am install-info install-info-am install-man \
+	install-strip installcheck installcheck-am installdirs \
+	installdirs-am maintainer-clean maintainer-clean-generic \
+	maintainer-clean-local maintainer-clean-recursive mostlyclean \
+	mostlyclean-generic mostlyclean-recursive pdf pdf-am ps ps-am \
+	tags tags-recursive uninstall uninstall-am uninstall-info-am
+
+
+.tmpl:
+	sed \
+	    -e s@:SBINDIR:@${sbindir}@ \
+	    <$< >$@
+
+install-data-local:
+	[ `uname -s` != "Darwin" ] || make install-sys-darwin
+
+install-sys-darwin:
+	@if [ `id -u` -eq 0 ]; then \
+	  make install-sys-darwin-root; \
+	else \
+	  echo; \
+	  echo " ** NOTE: Not installing with root privileges, so the LaunchDaemon script"; \
+	  echo " ** \"/Library/LaunchDaemons/de.barton.ngircd.plist\" can't be installed/updated!"; \
+	  echo; \
+	fi
+
+install-sys-darwin-root: de.barton.ngircd.plist
+	install -c -m 644 -b -o root -g wheel de.barton.ngircd.plist /Library/LaunchDaemons/de.barton.ngircd.plist
+	@echo
+	@echo " ** \"/Library/LaunchDaemons/de.barton.ngircd.plist\" has been installed,"
+	@echo " ** but is disabled. Use launchctl(8) to enable/run ngIRCd on Darwin/Mac OS X."
+	@echo
 
 
 clean-local:
 clean-local:
 	rm -rf build
 	rm -rf build

+ 92 - 0
contrib/MacOSX/config.h

@@ -0,0 +1,92 @@
+/*
+ * ngIRCd -- The Next Generation IRC Daemon
+ * Copyright (c)2001-2007 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.
+ *
+ * $Id: config.h,v 1.1 2007/11/19 22:11:36 alex Exp $
+ *
+ * Static configuration file for Mac OS X Xcode project
+ */
+
+#define PACKAGE_NAME "ngircd"
+#define VERSION "??"
+#define SYSCONFDIR "/etc/ngircd"
+
+/* -- Build options -- */
+
+/* Define if debug-mode should be enabled */
+#define DEBUG 1
+
+/* Define if the server should do IDENT requests */
+/*#define IDENTAUTH 1*/
+
+/* Define if IRC+ protocol should be used */
+#define IRCPLUS 1
+
+/* Define if IRC sniffer should be enabled */
+/*#define SNIFFER 1*/
+
+/* Define if syslog should be used for logging */
+#define SYSLOG 1
+
+/* Define if TCP wrappers should be used */
+/*#define TCPWRAP 1*/
+
+/* Define if support for Zeroconf should be included */
+/*#define ZEROCONF 1*/
+
+/* Define if zlib compression should be enabled */
+#define ZLIB 1
+
+/* -- Supported features -- */
+
+/* Define if SSP C support is enabled. */
+#define ENABLE_SSP_CC 1
+
+/* Define to 1 if the C compiler supports function prototypes. */
+#define PROTOTYPES 1
+/* Define like PROTOTYPES; this can be used by system headers. */
+#define __PROTOTYPES 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+/* Define to 1 if you have the <stddef.h> header file. */
+#define HAVE_STDDEF_H 1
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the `kqueue' function. */
+#define HAVE_KQUEUE 1
+/* Define to 1 if you have the `inet_ntoa' function. */
+#define HAVE_INET_NTOA 1
+/* Define to 1 if you have the `snprintf' function. */
+#define HAVE_SNPRINTF 1
+/* Define to 1 if you have the `strlcat' function. */
+#define HAVE_STRLCAT 1
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+/* Define to 1 if you have the `vsnprintf' function. */
+#define HAVE_VSNPRINTF 1
+
+/* Define if socklen_t exists */
+#define HAVE_socklen_t 1
+
+#ifdef ZEROCONF
+/* Define to 1 if you have the <DNSServiceDiscovery/DNSServiceDiscovery.h> header file. */
+#define HAVE_DNSSERVICEDISCOVERY_DNSSERVICEDISCOVERY_H 1
+/* Define to 1 if you have the `DNSServiceRegistrationCreate' function. */
+#define HAVE_DNSSERVICEREGISTRATIONCREATE 1
+#endif
+
+/* -eof- */

+ 0 - 0
contrib/MacOSX/cvs-version.h


+ 19 - 0
contrib/MacOSX/de.barton.ngircd.plist.tmpl

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>Disabled</key>
+	<true/>
+	<key>KeepAlive</key>
+	<true/>
+	<key>Label</key>
+	<string>de.barton.ngIRCd</string>
+	<key>ProgramArguments</key>
+	<array>
+		<string>:SBINDIR:/ngircd</string>
+		<string>--nodaemon</string>
+	</array>
+	<key>RunAtLoad</key>
+	<true/>
+</dict>
+</plist>

+ 17 - 0
contrib/MacOSX/ngIRCd.xcodeproj/Makefile.am

@@ -0,0 +1,17 @@
+#
+# ngIRCd -- The Next Generation IRC Daemon
+# Copyright (c)2001-2008 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.
+#
+
+EXTRA_DIST = project.pbxproj
+
+maintainer-clean-local:
+	rm -f Makefile Makefile.in
+
+# -eof-

+ 308 - 0
contrib/MacOSX/ngIRCd.xcodeproj/Makefile.in

@@ -0,0 +1,308 @@
+# Makefile.in generated by automake 1.9.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# ngIRCd -- The Next Generation IRC Daemon
+# Copyright (c)2001-2008 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.
+#
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = contrib/MacOSX/ngIRCd.xcodeproj
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/src/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+U = @U@
+VERSION = @VERSION@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+EXTRA_DIST = project.pbxproj
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  contrib/MacOSX/ngIRCd.xcodeproj/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  contrib/MacOSX/ngIRCd.xcodeproj/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+uninstall-info-am:
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic \
+	maintainer-clean-local
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: all all-am check check-am clean clean-generic distclean \
+	distclean-generic distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-exec \
+	install-exec-am install-info install-info-am install-man \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic \
+	maintainer-clean-local mostlyclean mostlyclean-generic pdf \
+	pdf-am ps ps-am uninstall uninstall-am uninstall-info-am
+
+
+maintainer-clean-local:
+	rm -f Makefile Makefile.in
+
+# -eof-
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

+ 697 - 0
contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj

@@ -0,0 +1,697 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 44;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		FA322D350CEF74B1001761B3 /* array.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CD90CEF74B1001761B3 /* array.c */; };
+		FA322D360CEF74B1001761B3 /* channel.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CDB0CEF74B1001761B3 /* channel.c */; };
+		FA322D370CEF74B1001761B3 /* client.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CDD0CEF74B1001761B3 /* client.c */; };
+		FA322D380CEF74B1001761B3 /* conf.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CDF0CEF74B1001761B3 /* conf.c */; };
+		FA322D390CEF74B1001761B3 /* conn-func.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CE10CEF74B1001761B3 /* conn-func.c */; };
+		FA322D3A0CEF74B1001761B3 /* conn-zip.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CE30CEF74B1001761B3 /* conn-zip.c */; };
+		FA322D3B0CEF74B1001761B3 /* conn.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CE50CEF74B1001761B3 /* conn.c */; };
+		FA322D3C0CEF74B1001761B3 /* hash.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CE80CEF74B1001761B3 /* hash.c */; };
+		FA322D3D0CEF74B1001761B3 /* io.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CEA0CEF74B1001761B3 /* io.c */; };
+		FA322D3E0CEF74B1001761B3 /* irc-channel.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CEC0CEF74B1001761B3 /* irc-channel.c */; };
+		FA322D3F0CEF74B1001761B3 /* irc-info.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CEE0CEF74B1001761B3 /* irc-info.c */; };
+		FA322D400CEF74B1001761B3 /* irc-login.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CF00CEF74B1001761B3 /* irc-login.c */; };
+		FA322D410CEF74B1001761B3 /* irc-mode.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CF20CEF74B1001761B3 /* irc-mode.c */; };
+		FA322D420CEF74B1001761B3 /* irc-op.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CF40CEF74B1001761B3 /* irc-op.c */; };
+		FA322D430CEF74B1001761B3 /* irc-oper.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CF60CEF74B1001761B3 /* irc-oper.c */; };
+		FA322D440CEF74B1001761B3 /* irc-server.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CF80CEF74B1001761B3 /* irc-server.c */; };
+		FA322D450CEF74B1001761B3 /* irc-write.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CFA0CEF74B1001761B3 /* irc-write.c */; };
+		FA322D460CEF74B1001761B3 /* irc.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CFC0CEF74B1001761B3 /* irc.c */; };
+		FA322D470CEF74B1001761B3 /* lists.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322CFE0CEF74B1001761B3 /* lists.c */; };
+		FA322D480CEF74B1001761B3 /* log.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322D000CEF74B1001761B3 /* log.c */; };
+		FA322D490CEF74B1001761B3 /* match.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322D030CEF74B1001761B3 /* match.c */; };
+		FA322D4A0CEF74B1001761B3 /* ngircd.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322D060CEF74B1001761B3 /* ngircd.c */; };
+		FA322D4B0CEF74B1001761B3 /* parse.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322D080CEF74B1001761B3 /* parse.c */; };
+		FA322D4C0CEF74B1001761B3 /* rendezvous.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322D0A0CEF74B1001761B3 /* rendezvous.c */; };
+		FA322D4D0CEF74B1001761B3 /* resolve.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322D0C0CEF74B1001761B3 /* resolve.c */; };
+		FA322DBE0CEF7766001761B3 /* tool.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322D330CEF74B1001761B3 /* tool.c */; };
+		FA322DC10CEF77CB001761B3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FA322DC00CEF77CB001761B3 /* libz.dylib */; };
+		FA407F2E0DB159F400271AF1 /* ng_ipaddr.c in Sources */ = {isa = PBXBuildFile; fileRef = FA407F2C0DB159F400271AF1 /* ng_ipaddr.c */; };
+		FAE5CC2E0CF2308A007D69B6 /* numeric.c in Sources */ = {isa = PBXBuildFile; fileRef = FAE5CC2D0CF2308A007D69B6 /* numeric.c */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		8DD76FAF0486AB0100D96B5E /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 8;
+			dstPath = /usr/share/man/man1/;
+			dstSubfolderSpec = 0;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 1;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		FA1A6BBC0D6857BB00AA8F71 /* misc-test.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "misc-test.e"; sourceTree = "<group>"; };
+		FA1A6BBD0D6857D900AA8F71 /* who-test.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "who-test.e"; sourceTree = "<group>"; };
+		FA322BBA0CEF72E4001761B3 /* ngIRCd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ngIRCd; sourceTree = BUILT_PRODUCTS_DIR; };
+		FA322CD60CEF74B1001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = "<group>"; };
+		FA322CD90CEF74B1001761B3 /* array.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = array.c; sourceTree = "<group>"; };
+		FA322CDA0CEF74B1001761B3 /* array.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = array.h; sourceTree = "<group>"; };
+		FA322CDB0CEF74B1001761B3 /* channel.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = channel.c; sourceTree = "<group>"; };
+		FA322CDC0CEF74B1001761B3 /* channel.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = channel.h; sourceTree = "<group>"; };
+		FA322CDD0CEF74B1001761B3 /* client.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = client.c; sourceTree = "<group>"; };
+		FA322CDE0CEF74B1001761B3 /* client.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = client.h; sourceTree = "<group>"; };
+		FA322CDF0CEF74B1001761B3 /* conf.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = conf.c; sourceTree = "<group>"; };
+		FA322CE00CEF74B1001761B3 /* conf.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = conf.h; sourceTree = "<group>"; };
+		FA322CE10CEF74B1001761B3 /* conn-func.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = "conn-func.c"; sourceTree = "<group>"; };
+		FA322CE20CEF74B1001761B3 /* conn-func.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = "conn-func.h"; sourceTree = "<group>"; };
+		FA322CE30CEF74B1001761B3 /* conn-zip.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = "conn-zip.c"; sourceTree = "<group>"; };
+		FA322CE40CEF74B1001761B3 /* conn-zip.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = "conn-zip.h"; sourceTree = "<group>"; };
+		FA322CE50CEF74B1001761B3 /* conn.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = conn.c; sourceTree = "<group>"; };
+		FA322CE60CEF74B1001761B3 /* conn.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = conn.h; sourceTree = "<group>"; };
+		FA322CE70CEF74B1001761B3 /* defines.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = defines.h; sourceTree = "<group>"; };
+		FA322CE80CEF74B1001761B3 /* hash.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = hash.c; sourceTree = "<group>"; };
+		FA322CE90CEF74B1001761B3 /* hash.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = hash.h; sourceTree = "<group>"; };
+		FA322CEA0CEF74B1001761B3 /* io.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = io.c; sourceTree = "<group>"; };
+		FA322CEB0CEF74B1001761B3 /* io.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = io.h; sourceTree = "<group>"; };
+		FA322CEC0CEF74B1001761B3 /* irc-channel.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = "irc-channel.c"; sourceTree = "<group>"; };
+		FA322CED0CEF74B1001761B3 /* irc-channel.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = "irc-channel.h"; sourceTree = "<group>"; };
+		FA322CEE0CEF74B1001761B3 /* irc-info.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = "irc-info.c"; sourceTree = "<group>"; };
+		FA322CEF0CEF74B1001761B3 /* irc-info.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = "irc-info.h"; sourceTree = "<group>"; };
+		FA322CF00CEF74B1001761B3 /* irc-login.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = "irc-login.c"; sourceTree = "<group>"; };
+		FA322CF10CEF74B1001761B3 /* irc-login.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = "irc-login.h"; sourceTree = "<group>"; };
+		FA322CF20CEF74B1001761B3 /* irc-mode.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = "irc-mode.c"; sourceTree = "<group>"; };
+		FA322CF30CEF74B1001761B3 /* irc-mode.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = "irc-mode.h"; sourceTree = "<group>"; };
+		FA322CF40CEF74B1001761B3 /* irc-op.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = "irc-op.c"; sourceTree = "<group>"; };
+		FA322CF50CEF74B1001761B3 /* irc-op.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = "irc-op.h"; sourceTree = "<group>"; };
+		FA322CF60CEF74B1001761B3 /* irc-oper.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = "irc-oper.c"; sourceTree = "<group>"; };
+		FA322CF70CEF74B1001761B3 /* irc-oper.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = "irc-oper.h"; sourceTree = "<group>"; };
+		FA322CF80CEF74B1001761B3 /* irc-server.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = "irc-server.c"; sourceTree = "<group>"; };
+		FA322CF90CEF74B1001761B3 /* irc-server.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = "irc-server.h"; sourceTree = "<group>"; };
+		FA322CFA0CEF74B1001761B3 /* irc-write.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = "irc-write.c"; sourceTree = "<group>"; };
+		FA322CFB0CEF74B1001761B3 /* irc-write.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = "irc-write.h"; sourceTree = "<group>"; };
+		FA322CFC0CEF74B1001761B3 /* irc.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = irc.c; sourceTree = "<group>"; };
+		FA322CFD0CEF74B1001761B3 /* irc.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = irc.h; sourceTree = "<group>"; };
+		FA322CFE0CEF74B1001761B3 /* lists.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = lists.c; sourceTree = "<group>"; };
+		FA322CFF0CEF74B1001761B3 /* lists.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = lists.h; sourceTree = "<group>"; };
+		FA322D000CEF74B1001761B3 /* log.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = log.c; sourceTree = "<group>"; };
+		FA322D010CEF74B1001761B3 /* log.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = log.h; sourceTree = "<group>"; };
+		FA322D020CEF74B1001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = "<group>"; };
+		FA322D030CEF74B1001761B3 /* match.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = match.c; sourceTree = "<group>"; };
+		FA322D040CEF74B1001761B3 /* match.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = match.h; sourceTree = "<group>"; };
+		FA322D050CEF74B1001761B3 /* messages.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = messages.h; sourceTree = "<group>"; };
+		FA322D060CEF74B1001761B3 /* ngircd.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = ngircd.c; sourceTree = "<group>"; };
+		FA322D070CEF74B1001761B3 /* ngircd.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = ngircd.h; sourceTree = "<group>"; };
+		FA322D080CEF74B1001761B3 /* parse.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = parse.c; sourceTree = "<group>"; };
+		FA322D090CEF74B1001761B3 /* parse.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = parse.h; sourceTree = "<group>"; };
+		FA322D0A0CEF74B1001761B3 /* rendezvous.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = rendezvous.c; sourceTree = "<group>"; };
+		FA322D0B0CEF74B1001761B3 /* rendezvous.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = rendezvous.h; sourceTree = "<group>"; };
+		FA322D0C0CEF74B1001761B3 /* resolve.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = resolve.c; sourceTree = "<group>"; };
+		FA322D0D0CEF74B1001761B3 /* resolve.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = resolve.h; sourceTree = "<group>"; };
+		FA322D100CEF74B1001761B3 /* ansi2knr.1 */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.man; path = ansi2knr.1; sourceTree = "<group>"; };
+		FA322D110CEF74B1001761B3 /* ansi2knr.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = ansi2knr.c; sourceTree = "<group>"; };
+		FA322D120CEF74B1001761B3 /* exp.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = exp.h; sourceTree = "<group>"; };
+		FA322D130CEF74B1001761B3 /* imp.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = imp.h; sourceTree = "<group>"; };
+		FA322D140CEF74B1001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = "<group>"; };
+		FA322D150CEF74B1001761B3 /* portab.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = portab.h; sourceTree = "<group>"; };
+		FA322D160CEF74B1001761B3 /* portabtest.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = portabtest.c; sourceTree = "<group>"; };
+		FA322D170CEF74B1001761B3 /* splint.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = splint.h; sourceTree = "<group>"; };
+		FA322D180CEF74B1001761B3 /* strdup.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = strdup.c; sourceTree = "<group>"; };
+		FA322D190CEF74B1001761B3 /* strlcpy.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = strlcpy.c; sourceTree = "<group>"; };
+		FA322D1A0CEF74B1001761B3 /* vsnprintf.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = vsnprintf.c; sourceTree = "<group>"; };
+		FA322D1D0CEF74B1001761B3 /* channel-test.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "channel-test.e"; sourceTree = "<group>"; };
+		FA322D1E0CEF74B1001761B3 /* check-idle.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "check-idle.e"; sourceTree = "<group>"; };
+		FA322D1F0CEF74B1001761B3 /* connect-test.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "connect-test.e"; sourceTree = "<group>"; };
+		FA322D200CEF74B1001761B3 /* functions.inc */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.pascal; path = functions.inc; sourceTree = "<group>"; };
+		FA322D210CEF74B1001761B3 /* getpid.sh */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; path = getpid.sh; sourceTree = "<group>"; };
+		FA322D220CEF74B1001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = "<group>"; };
+		FA322D230CEF74B1001761B3 /* mode-test.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "mode-test.e"; sourceTree = "<group>"; };
+		FA322D240CEF74B1001761B3 /* ngircd-test.conf */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "ngircd-test.conf"; sourceTree = "<group>"; };
+		FA322D250CEF74B1001761B3 /* README */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+		FA322D260CEF74B1001761B3 /* start-server.sh */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; path = "start-server.sh"; sourceTree = "<group>"; };
+		FA322D270CEF74B1001761B3 /* stop-server.sh */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; path = "stop-server.sh"; sourceTree = "<group>"; };
+		FA322D280CEF74B1001761B3 /* stress-A.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "stress-A.e"; sourceTree = "<group>"; };
+		FA322D290CEF74B1001761B3 /* stress-B.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "stress-B.e"; sourceTree = "<group>"; };
+		FA322D2A0CEF74B1001761B3 /* stress-server.sh */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; path = "stress-server.sh"; sourceTree = "<group>"; };
+		FA322D2B0CEF74B1001761B3 /* test-loop.sh */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; path = "test-loop.sh"; sourceTree = "<group>"; };
+		FA322D2C0CEF74B1001761B3 /* tests.sh */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; path = tests.sh; sourceTree = "<group>"; };
+		FA322D2D0CEF74B1001761B3 /* wait-tests.sh */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; path = "wait-tests.sh"; sourceTree = "<group>"; };
+		FA322D300CEF74B1001761B3 /* ansi2knr.1 */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.man; path = ansi2knr.1; sourceTree = "<group>"; };
+		FA322D310CEF74B1001761B3 /* ansi2knr.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = ansi2knr.c; sourceTree = "<group>"; };
+		FA322D320CEF74B1001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = "<group>"; };
+		FA322D330CEF74B1001761B3 /* tool.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = tool.c; sourceTree = "<group>"; };
+		FA322D340CEF74B1001761B3 /* tool.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = tool.h; sourceTree = "<group>"; };
+		FA322D5A0CEF750F001761B3 /* AUTHORS */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; name = AUTHORS; path = ../../AUTHORS; sourceTree = SOURCE_ROOT; };
+		FA322D5B0CEF750F001761B3 /* autogen.sh */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; name = autogen.sh; path = ../../autogen.sh; sourceTree = SOURCE_ROOT; };
+		FA322D5C0CEF750F001761B3 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; name = ChangeLog; path = ../../ChangeLog; sourceTree = SOURCE_ROOT; };
+		FA322D5E0CEF750F001761B3 /* config.guess */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; name = config.guess; path = ../../config.guess; sourceTree = SOURCE_ROOT; };
+		FA322D5F0CEF750F001761B3 /* config.sub */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; name = config.sub; path = ../../config.sub; sourceTree = SOURCE_ROOT; };
+		FA322D600CEF750F001761B3 /* configure.in */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; name = configure.in; path = ../../configure.in; sourceTree = SOURCE_ROOT; };
+		FA322D610CEF750F001761B3 /* COPYING */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; name = COPYING; path = ../../COPYING; sourceTree = SOURCE_ROOT; };
+		FA322D620CEF750F001761B3 /* INSTALL */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; name = INSTALL; path = ../../INSTALL; sourceTree = SOURCE_ROOT; };
+		FA322D630CEF750F001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; name = Makefile.am; path = ../../Makefile.am; sourceTree = SOURCE_ROOT; };
+		FA322D640CEF750F001761B3 /* NEWS */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; name = NEWS; path = ../../NEWS; sourceTree = SOURCE_ROOT; };
+		FA322D650CEF750F001761B3 /* README */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; name = README; path = ../../README; sourceTree = SOURCE_ROOT; };
+		FA322D6A0CEF7523001761B3 /* changelog */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = changelog; sourceTree = "<group>"; };
+		FA322D6B0CEF7523001761B3 /* compat */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = compat; sourceTree = "<group>"; };
+		FA322D6C0CEF7523001761B3 /* control */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = control; sourceTree = "<group>"; };
+		FA322D6D0CEF7523001761B3 /* copyright */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = copyright; sourceTree = "<group>"; };
+		FA322D6E0CEF7523001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = "<group>"; };
+		FA322D6F0CEF7523001761B3 /* ngircd.default */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = ngircd.default; sourceTree = "<group>"; };
+		FA322D700CEF7523001761B3 /* ngircd.init */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; path = ngircd.init; sourceTree = "<group>"; };
+		FA322D710CEF7523001761B3 /* ngircd.postinst */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; path = ngircd.postinst; sourceTree = "<group>"; };
+		FA322D720CEF7523001761B3 /* rules */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = rules; sourceTree = "<group>"; };
+		FA322D8D0CEF7523001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = "<group>"; };
+		FA322D8E0CEF7523001761B3 /* ngIRCd.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = ngIRCd.xcodeproj; sourceTree = "<group>"; };
+		FA322D910CEF7523001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = "<group>"; };
+		FA322D920CEF7523001761B3 /* ngindent */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = ngindent; sourceTree = "<group>"; };
+		FA322D930CEF7523001761B3 /* ngircd.sh */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; path = ngircd.sh; sourceTree = "<group>"; };
+		FA322D940CEF7523001761B3 /* ngircd.spec */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = ngircd.spec; sourceTree = "<group>"; };
+		FA322D950CEF7523001761B3 /* README */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+		FA322D960CEF7523001761B3 /* systrace.policy */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = systrace.policy; sourceTree = "<group>"; };
+		FA322D9A0CEF752C001761B3 /* FAQ.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = FAQ.txt; sourceTree = "<group>"; };
+		FA322D9B0CEF752C001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = "<group>"; };
+		FA322D9C0CEF752C001761B3 /* Platforms.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Platforms.txt; sourceTree = "<group>"; };
+		FA322D9D0CEF752C001761B3 /* Protocol.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Protocol.txt; sourceTree = "<group>"; };
+		FA322D9E0CEF752C001761B3 /* README-AUX.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "README-AUX.txt"; sourceTree = "<group>"; };
+		FA322D9F0CEF752C001761B3 /* README-BeOS.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "README-BeOS.txt"; sourceTree = "<group>"; };
+		FA322DA00CEF752C001761B3 /* RFC.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = RFC.txt; sourceTree = "<group>"; };
+		FA322DA10CEF752C001761B3 /* sample-ngircd.conf */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "sample-ngircd.conf"; sourceTree = "<group>"; };
+		FA322DA40CEF752C001761B3 /* Doxyfile */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Doxyfile; sourceTree = "<group>"; };
+		FA322DA50CEF752C001761B3 /* footer.inc.html */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.html; path = footer.inc.html; sourceTree = "<group>"; };
+		FA322DA60CEF752C001761B3 /* header.inc.html */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.html; path = header.inc.html; sourceTree = "<group>"; };
+		FA322DA70CEF752C001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = "<group>"; };
+		FA322DA80CEF752C001761B3 /* ngircd-doc.css */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.css; path = "ngircd-doc.css"; sourceTree = "<group>"; };
+		FA322DA90CEF752C001761B3 /* SSL.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = SSL.txt; sourceTree = "<group>"; };
+		FA322DAA0CEF752C001761B3 /* Zeroconf.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Zeroconf.txt; sourceTree = "<group>"; };
+		FA322DAD0CEF7538001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = "<group>"; };
+		FA322DAE0CEF7538001761B3 /* ngircd.8.tmpl */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = ngircd.8.tmpl; sourceTree = "<group>"; };
+		FA322DAF0CEF7538001761B3 /* ngircd.conf.5.tmpl */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = ngircd.conf.5.tmpl; sourceTree = "<group>"; };
+		FA322DB10CEF7565001761B3 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
+		FA322DBB0CEF773C001761B3 /* cvs-version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "cvs-version.h"; sourceTree = "<group>"; };
+		FA322DC00CEF77CB001761B3 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = /usr/lib/libz.dylib; sourceTree = "<absolute>"; };
+		FA407F2B0DB159F400271AF1 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; name = Makefile.am; path = ipaddr/Makefile.am; sourceTree = "<group>"; };
+		FA407F2C0DB159F400271AF1 /* ng_ipaddr.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = ng_ipaddr.c; path = ipaddr/ng_ipaddr.c; sourceTree = "<group>"; };
+		FA407F2D0DB159F400271AF1 /* ng_ipaddr.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = ng_ipaddr.h; path = ipaddr/ng_ipaddr.h; sourceTree = "<group>"; };
+		FA407F380DB15AC700271AF1 /* GIT.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = GIT.txt; 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>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		8DD76FAD0486AB0100D96B5E /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				FA322DC10CEF77CB001761B3 /* libz.dylib in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		08FB7794FE84155DC02AAC07 /* ngIRCd */ = {
+			isa = PBXGroup;
+			children = (
+				FA322D970CEF752C001761B3 /* doc */,
+				FA322D660CEF7523001761B3 /* contrib */,
+				FA322DAB0CEF7538001761B3 /* man */,
+				FA322CD40CEF74B0001761B3 /* src */,
+				FA322D5A0CEF750F001761B3 /* AUTHORS */,
+				FA322D610CEF750F001761B3 /* COPYING */,
+				FA322D620CEF750F001761B3 /* INSTALL */,
+				FA322D640CEF750F001761B3 /* NEWS */,
+				FA322D650CEF750F001761B3 /* README */,
+				FA322D5B0CEF750F001761B3 /* autogen.sh */,
+				FA322D5C0CEF750F001761B3 /* ChangeLog */,
+				FA322D5E0CEF750F001761B3 /* config.guess */,
+				FA322D5F0CEF750F001761B3 /* config.sub */,
+				FA322D600CEF750F001761B3 /* configure.in */,
+				FA322D630CEF750F001761B3 /* Makefile.am */,
+				1AB674ADFE9D54B511CA2CBB /* Products */,
+				FA322DC00CEF77CB001761B3 /* libz.dylib */,
+			);
+			name = ngIRCd;
+			sourceTree = "<group>";
+		};
+		1AB674ADFE9D54B511CA2CBB /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				FA322BBA0CEF72E4001761B3 /* ngIRCd */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		FA322CD40CEF74B0001761B3 /* src */ = {
+			isa = PBXGroup;
+			children = (
+				FA322CD70CEF74B1001761B3 /* ngircd */,
+				FA407F270DB1598D00271AF1 /* ipaddr */,
+				FA322D0E0CEF74B1001761B3 /* portab */,
+				FA322D1B0CEF74B1001761B3 /* testsuite */,
+				FA322D2E0CEF74B1001761B3 /* tool */,
+				FA322CD60CEF74B1001761B3 /* Makefile.am */,
+			);
+			name = src;
+			path = ../../src;
+			sourceTree = SOURCE_ROOT;
+		};
+		FA322CD70CEF74B1001761B3 /* ngircd */ = {
+			isa = PBXGroup;
+			children = (
+				FA322CD90CEF74B1001761B3 /* array.c */,
+				FA322CDA0CEF74B1001761B3 /* array.h */,
+				FA322CDB0CEF74B1001761B3 /* channel.c */,
+				FA322CDC0CEF74B1001761B3 /* channel.h */,
+				FA322CDD0CEF74B1001761B3 /* client.c */,
+				FA322CDE0CEF74B1001761B3 /* client.h */,
+				FA322CDF0CEF74B1001761B3 /* conf.c */,
+				FA322CE00CEF74B1001761B3 /* conf.h */,
+				FA322CE10CEF74B1001761B3 /* conn-func.c */,
+				FA322CE20CEF74B1001761B3 /* conn-func.h */,
+				FA322CE30CEF74B1001761B3 /* conn-zip.c */,
+				FA322CE40CEF74B1001761B3 /* conn-zip.h */,
+				FA322CE50CEF74B1001761B3 /* conn.c */,
+				FA322CE60CEF74B1001761B3 /* conn.h */,
+				FA322CE70CEF74B1001761B3 /* defines.h */,
+				FA322CE80CEF74B1001761B3 /* hash.c */,
+				FA322CE90CEF74B1001761B3 /* hash.h */,
+				FA322CEA0CEF74B1001761B3 /* io.c */,
+				FA322CEB0CEF74B1001761B3 /* io.h */,
+				FA322CEC0CEF74B1001761B3 /* irc-channel.c */,
+				FA322CED0CEF74B1001761B3 /* irc-channel.h */,
+				FA322CEE0CEF74B1001761B3 /* irc-info.c */,
+				FA322CEF0CEF74B1001761B3 /* irc-info.h */,
+				FA322CF00CEF74B1001761B3 /* irc-login.c */,
+				FA322CF10CEF74B1001761B3 /* irc-login.h */,
+				FA322CF20CEF74B1001761B3 /* irc-mode.c */,
+				FA322CF30CEF74B1001761B3 /* irc-mode.h */,
+				FA322CF40CEF74B1001761B3 /* irc-op.c */,
+				FA322CF50CEF74B1001761B3 /* irc-op.h */,
+				FA322CF60CEF74B1001761B3 /* irc-oper.c */,
+				FA322CF70CEF74B1001761B3 /* irc-oper.h */,
+				FA322CF80CEF74B1001761B3 /* irc-server.c */,
+				FA322CF90CEF74B1001761B3 /* irc-server.h */,
+				FA322CFA0CEF74B1001761B3 /* irc-write.c */,
+				FA322CFB0CEF74B1001761B3 /* irc-write.h */,
+				FA322CFC0CEF74B1001761B3 /* irc.c */,
+				FA322CFD0CEF74B1001761B3 /* irc.h */,
+				FA322CFE0CEF74B1001761B3 /* lists.c */,
+				FA322CFF0CEF74B1001761B3 /* lists.h */,
+				FA322D000CEF74B1001761B3 /* log.c */,
+				FA322D010CEF74B1001761B3 /* log.h */,
+				FA322D020CEF74B1001761B3 /* Makefile.am */,
+				FA322D030CEF74B1001761B3 /* match.c */,
+				FA322D040CEF74B1001761B3 /* match.h */,
+				FA322D050CEF74B1001761B3 /* messages.h */,
+				FA322D060CEF74B1001761B3 /* ngircd.c */,
+				FA322D070CEF74B1001761B3 /* ngircd.h */,
+				FAE5CC2D0CF2308A007D69B6 /* numeric.c */,
+				FAE5CC2C0CF2308A007D69B6 /* numeric.h */,
+				FA322D080CEF74B1001761B3 /* parse.c */,
+				FA322D090CEF74B1001761B3 /* parse.h */,
+				FA322D0A0CEF74B1001761B3 /* rendezvous.c */,
+				FA322D0B0CEF74B1001761B3 /* rendezvous.h */,
+				FA322D0C0CEF74B1001761B3 /* resolve.c */,
+				FA322D0D0CEF74B1001761B3 /* resolve.h */,
+			);
+			path = ngircd;
+			sourceTree = "<group>";
+		};
+		FA322D0E0CEF74B1001761B3 /* portab */ = {
+			isa = PBXGroup;
+			children = (
+				FA322D100CEF74B1001761B3 /* ansi2knr.1 */,
+				FA322D110CEF74B1001761B3 /* ansi2knr.c */,
+				FA322D120CEF74B1001761B3 /* exp.h */,
+				FA322D130CEF74B1001761B3 /* imp.h */,
+				FA322D140CEF74B1001761B3 /* Makefile.am */,
+				FA322D150CEF74B1001761B3 /* portab.h */,
+				FA322D160CEF74B1001761B3 /* portabtest.c */,
+				FA322D170CEF74B1001761B3 /* splint.h */,
+				FA322D180CEF74B1001761B3 /* strdup.c */,
+				FA322D190CEF74B1001761B3 /* strlcpy.c */,
+				FA322D1A0CEF74B1001761B3 /* vsnprintf.c */,
+			);
+			path = portab;
+			sourceTree = "<group>";
+		};
+		FA322D1B0CEF74B1001761B3 /* testsuite */ = {
+			isa = PBXGroup;
+			children = (
+				FA322D1D0CEF74B1001761B3 /* channel-test.e */,
+				FA322D1E0CEF74B1001761B3 /* check-idle.e */,
+				FA322D1F0CEF74B1001761B3 /* connect-test.e */,
+				FA322D200CEF74B1001761B3 /* functions.inc */,
+				FA322D210CEF74B1001761B3 /* getpid.sh */,
+				FA322D220CEF74B1001761B3 /* Makefile.am */,
+				FA1A6BBC0D6857BB00AA8F71 /* misc-test.e */,
+				FA322D230CEF74B1001761B3 /* mode-test.e */,
+				FA322D240CEF74B1001761B3 /* ngircd-test.conf */,
+				FA322D250CEF74B1001761B3 /* README */,
+				FA322D260CEF74B1001761B3 /* start-server.sh */,
+				FA322D270CEF74B1001761B3 /* stop-server.sh */,
+				FA322D280CEF74B1001761B3 /* stress-A.e */,
+				FA322D290CEF74B1001761B3 /* stress-B.e */,
+				FA322D2A0CEF74B1001761B3 /* stress-server.sh */,
+				FA322D2B0CEF74B1001761B3 /* test-loop.sh */,
+				FA322D2C0CEF74B1001761B3 /* tests.sh */,
+				FA322D2D0CEF74B1001761B3 /* wait-tests.sh */,
+				FA1A6BBD0D6857D900AA8F71 /* who-test.e */,
+			);
+			path = testsuite;
+			sourceTree = "<group>";
+		};
+		FA322D2E0CEF74B1001761B3 /* tool */ = {
+			isa = PBXGroup;
+			children = (
+				FA322D300CEF74B1001761B3 /* ansi2knr.1 */,
+				FA322D310CEF74B1001761B3 /* ansi2knr.c */,
+				FA322D320CEF74B1001761B3 /* Makefile.am */,
+				FA322D330CEF74B1001761B3 /* tool.c */,
+				FA322D340CEF74B1001761B3 /* tool.h */,
+			);
+			path = tool;
+			sourceTree = "<group>";
+		};
+		FA322D660CEF7523001761B3 /* contrib */ = {
+			isa = PBXGroup;
+			children = (
+				FA322D680CEF7523001761B3 /* Debian */,
+				FA322D730CEF7523001761B3 /* MacOSX */,
+				FA322D910CEF7523001761B3 /* Makefile.am */,
+				FA322D920CEF7523001761B3 /* ngindent */,
+				FA322D930CEF7523001761B3 /* ngircd.sh */,
+				FA322D940CEF7523001761B3 /* ngircd.spec */,
+				FA322D950CEF7523001761B3 /* README */,
+				FA322D960CEF7523001761B3 /* systrace.policy */,
+			);
+			name = contrib;
+			path = ..;
+			sourceTree = SOURCE_ROOT;
+		};
+		FA322D680CEF7523001761B3 /* Debian */ = {
+			isa = PBXGroup;
+			children = (
+				FA322D6A0CEF7523001761B3 /* changelog */,
+				FA322D6B0CEF7523001761B3 /* compat */,
+				FA322D6C0CEF7523001761B3 /* control */,
+				FA322D6D0CEF7523001761B3 /* copyright */,
+				FA322D6E0CEF7523001761B3 /* Makefile.am */,
+				FA322D6F0CEF7523001761B3 /* ngircd.default */,
+				FA322D700CEF7523001761B3 /* ngircd.init */,
+				FA322D710CEF7523001761B3 /* ngircd.postinst */,
+				FA322D720CEF7523001761B3 /* rules */,
+			);
+			path = Debian;
+			sourceTree = "<group>";
+		};
+		FA322D730CEF7523001761B3 /* MacOSX */ = {
+			isa = PBXGroup;
+			children = (
+				FA322D750CEF7523001761B3 /* build */,
+				FA322D8D0CEF7523001761B3 /* Makefile.am */,
+				FA322D8E0CEF7523001761B3 /* ngIRCd.xcodeproj */,
+				FA322DB10CEF7565001761B3 /* config.h */,
+				FA322DBB0CEF773C001761B3 /* cvs-version.h */,
+			);
+			path = MacOSX;
+			sourceTree = "<group>";
+		};
+		FA322D750CEF7523001761B3 /* build */ = {
+			isa = PBXGroup;
+			children = (
+				FA322D760CEF7523001761B3 /* ngIRCd.build */,
+			);
+			path = build;
+			sourceTree = "<group>";
+		};
+		FA322D760CEF7523001761B3 /* ngIRCd.build */ = {
+			isa = PBXGroup;
+			children = (
+				FA322D770CEF7523001761B3 /* Default */,
+				FA322D7F0CEF7523001761B3 /* ngIRCd.pbxindex */,
+			);
+			path = ngIRCd.build;
+			sourceTree = "<group>";
+		};
+		FA322D770CEF7523001761B3 /* Default */ = {
+			isa = PBXGroup;
+			children = (
+				FA322D780CEF7523001761B3 /* ngIRCd.build */,
+			);
+			path = Default;
+			sourceTree = "<group>";
+		};
+		FA322D780CEF7523001761B3 /* ngIRCd.build */ = {
+			isa = PBXGroup;
+			children = (
+				FA322D7A0CEF7523001761B3 /* Objects-normal */,
+			);
+			path = ngIRCd.build;
+			sourceTree = "<group>";
+		};
+		FA322D7A0CEF7523001761B3 /* Objects-normal */ = {
+			isa = PBXGroup;
+			children = (
+				FA322D7B0CEF7523001761B3 /* i386 */,
+				FA322D7D0CEF7523001761B3 /* ppc */,
+			);
+			path = "Objects-normal";
+			sourceTree = "<group>";
+		};
+		FA322D7B0CEF7523001761B3 /* i386 */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			path = i386;
+			sourceTree = "<group>";
+		};
+		FA322D7D0CEF7523001761B3 /* ppc */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			path = ppc;
+			sourceTree = "<group>";
+		};
+		FA322D7F0CEF7523001761B3 /* ngIRCd.pbxindex */ = {
+			isa = PBXGroup;
+			children = (
+				FA322D880CEF7523001761B3 /* strings.pbxstrings */,
+			);
+			path = ngIRCd.pbxindex;
+			sourceTree = "<group>";
+		};
+		FA322D880CEF7523001761B3 /* strings.pbxstrings */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			path = strings.pbxstrings;
+			sourceTree = "<group>";
+		};
+		FA322D8F0CEF7523001761B3 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		FA322D970CEF752C001761B3 /* doc */ = {
+			isa = PBXGroup;
+			children = (
+				FA407F380DB15AC700271AF1 /* GIT.txt */,
+				FA322D9A0CEF752C001761B3 /* FAQ.txt */,
+				FA322D9B0CEF752C001761B3 /* Makefile.am */,
+				FA322D9C0CEF752C001761B3 /* Platforms.txt */,
+				FA322D9D0CEF752C001761B3 /* Protocol.txt */,
+				FA322D9E0CEF752C001761B3 /* README-AUX.txt */,
+				FA322D9F0CEF752C001761B3 /* README-BeOS.txt */,
+				FA322DA00CEF752C001761B3 /* RFC.txt */,
+				FA322DA10CEF752C001761B3 /* sample-ngircd.conf */,
+				FA322DA20CEF752C001761B3 /* src */,
+				FA322DA90CEF752C001761B3 /* SSL.txt */,
+				FA322DAA0CEF752C001761B3 /* Zeroconf.txt */,
+			);
+			name = doc;
+			path = ../../doc;
+			sourceTree = SOURCE_ROOT;
+		};
+		FA322DA20CEF752C001761B3 /* src */ = {
+			isa = PBXGroup;
+			children = (
+				FA322DA40CEF752C001761B3 /* Doxyfile */,
+				FA322DA50CEF752C001761B3 /* footer.inc.html */,
+				FA322DA60CEF752C001761B3 /* header.inc.html */,
+				FA322DA70CEF752C001761B3 /* Makefile.am */,
+				FA322DA80CEF752C001761B3 /* ngircd-doc.css */,
+			);
+			path = src;
+			sourceTree = "<group>";
+		};
+		FA322DAB0CEF7538001761B3 /* man */ = {
+			isa = PBXGroup;
+			children = (
+				FA322DAD0CEF7538001761B3 /* Makefile.am */,
+				FA322DAE0CEF7538001761B3 /* ngircd.8.tmpl */,
+				FA322DAF0CEF7538001761B3 /* ngircd.conf.5.tmpl */,
+			);
+			name = man;
+			path = ../../man;
+			sourceTree = SOURCE_ROOT;
+		};
+		FA407F270DB1598D00271AF1 /* ipaddr */ = {
+			isa = PBXGroup;
+			children = (
+				FA407F2B0DB159F400271AF1 /* Makefile.am */,
+				FA407F2C0DB159F400271AF1 /* ng_ipaddr.c */,
+				FA407F2D0DB159F400271AF1 /* ng_ipaddr.h */,
+			);
+			name = ipaddr;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		8DD76FA90486AB0100D96B5E /* ngIRCd */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "ngIRCd" */;
+			buildPhases = (
+				8DD76FAB0486AB0100D96B5E /* Sources */,
+				8DD76FAD0486AB0100D96B5E /* Frameworks */,
+				8DD76FAF0486AB0100D96B5E /* CopyFiles */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = ngIRCd;
+			productInstallPath = "$(HOME)/bin";
+			productName = ngIRCd;
+			productReference = FA322BBA0CEF72E4001761B3 /* ngIRCd */;
+			productType = "com.apple.product-type.tool";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		08FB7793FE84155DC02AAC07 /* Project object */ = {
+			isa = PBXProject;
+			buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "ngIRCd" */;
+			compatibilityVersion = "Xcode 3.0";
+			hasScannedForEncodings = 1;
+			mainGroup = 08FB7794FE84155DC02AAC07 /* ngIRCd */;
+			projectDirPath = "";
+			projectReferences = (
+				{
+					ProductGroup = FA322D8F0CEF7523001761B3 /* Products */;
+					ProjectRef = FA322D8E0CEF7523001761B3 /* ngIRCd.xcodeproj */;
+				},
+			);
+			projectRoot = "";
+			targets = (
+				8DD76FA90486AB0100D96B5E /* ngIRCd */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+		8DD76FAB0486AB0100D96B5E /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				FA322D350CEF74B1001761B3 /* array.c in Sources */,
+				FA322D360CEF74B1001761B3 /* channel.c in Sources */,
+				FA322D370CEF74B1001761B3 /* client.c in Sources */,
+				FA322D380CEF74B1001761B3 /* conf.c in Sources */,
+				FA322D390CEF74B1001761B3 /* conn-func.c in Sources */,
+				FA322D3A0CEF74B1001761B3 /* conn-zip.c in Sources */,
+				FA322D3B0CEF74B1001761B3 /* conn.c in Sources */,
+				FA322D3C0CEF74B1001761B3 /* hash.c in Sources */,
+				FA322D3D0CEF74B1001761B3 /* io.c in Sources */,
+				FA322D3E0CEF74B1001761B3 /* irc-channel.c in Sources */,
+				FA322D3F0CEF74B1001761B3 /* irc-info.c in Sources */,
+				FA322D400CEF74B1001761B3 /* irc-login.c in Sources */,
+				FA322D410CEF74B1001761B3 /* irc-mode.c in Sources */,
+				FA322D420CEF74B1001761B3 /* irc-op.c in Sources */,
+				FA322D430CEF74B1001761B3 /* irc-oper.c in Sources */,
+				FA322D440CEF74B1001761B3 /* irc-server.c in Sources */,
+				FA322D450CEF74B1001761B3 /* irc-write.c in Sources */,
+				FA322D460CEF74B1001761B3 /* irc.c in Sources */,
+				FA322D470CEF74B1001761B3 /* lists.c in Sources */,
+				FA322D480CEF74B1001761B3 /* log.c in Sources */,
+				FA322D490CEF74B1001761B3 /* match.c in Sources */,
+				FA322D4A0CEF74B1001761B3 /* ngircd.c in Sources */,
+				FA322D4B0CEF74B1001761B3 /* parse.c in Sources */,
+				FA322D4C0CEF74B1001761B3 /* rendezvous.c in Sources */,
+				FA322D4D0CEF74B1001761B3 /* resolve.c in Sources */,
+				FA322DBE0CEF7766001761B3 /* tool.c in Sources */,
+				FAE5CC2E0CF2308A007D69B6 /* numeric.c in Sources */,
+				FA407F2E0DB159F400271AF1 /* ng_ipaddr.c in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		1DEB928708733DD80010E9CD /* Default */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+				GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
+				GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
+				GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+				GCC_WARN_MISSING_PARENTHESES = YES;
+				GCC_WARN_PEDANTIC = YES;
+				GCC_WARN_SHADOW = YES;
+				GCC_WARN_SIGN_COMPARE = YES;
+				GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
+				GCC_WARN_UNKNOWN_PRAGMAS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_LABEL = YES;
+				GCC_WARN_UNUSED_PARAMETER = YES;
+				GCC_WARN_UNUSED_VALUE = YES;
+				INSTALL_PATH = /usr/local/bin;
+				PRODUCT_NAME = ngIRCd;
+			};
+			name = Default;
+		};
+		1DEB928B08733DD80010E9CD /* Default */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = (
+					ppc,
+					i386,
+				);
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				PREBINDING = NO;
+				SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk";
+			};
+			name = Default;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "ngIRCd" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				1DEB928708733DD80010E9CD /* Default */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Default;
+		};
+		1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "ngIRCd" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				1DEB928B08733DD80010E9CD /* Default */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Default;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}

+ 1 - 1
contrib/ngircd.spec

@@ -1,5 +1,5 @@
 %define name    ngircd
 %define name    ngircd
-%define version 0.10.3
+%define version 0.12.1
 %define release 1
 %define release 1
 %define prefix  %{_prefix}
 %define prefix  %{_prefix}
 
 

+ 0 - 56
doc/CVS.txt

@@ -1,57 +0,0 @@
-
-                     ngIRCd - Next Generation IRC Server
-
-                        (c)2001-2006 Alexander Barton,
-                    alex@barton.de, http://www.barton.de/
-
-               ngIRCd is free software and published under the
-                   terms of the GNU General Public License.
-
-                                 -- CVS.txt --
-
-
-The source code of ngIRCd is maintained using the "Concurrent Versions
-System" (CVS). Thereby several developers can work with the source tree at
-the same time.
-
-
-I. Anonymous read-only Access
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-To access the source tree anonymously in read-only mode, follow these steps:
-
-Login to the CVS server:
-
- $ cvs -d:pserver:anonymous@ngircd.barton.de:/srv/cvs/ngircd login
-
-Use "anonymous" as user name and no password (just hit Return). Now you can
-check out the sources:
-
- $ cvs -d:pserver:anonymous@ngircd.barton.de:/srv/cvs/ngircd checkout ngircd
-
-Thereby a new folder "ngircd" will be created containing all the individual
-source files. (Substitute the last "ngircd" with "website" to check out all
-the files of the homepage of ngIRCd.)
-
-The newly created folder ("ngircd" or "website") is the "working folder", all
-CVS commands will be executed from within this folder in the future.
-
-Please note: When checking out a fresh copy of ngIRCd from CVS, the
-configure script doesn't exist; you have to run the autogen.sh shell script
-(which is included in the source tree) to generate it. This requires you to
-have GNU automake and GNU autoconf installed on your system.
-
-Updating the CVS tree:
-
- $ cvs update -d -P [<filename>]
-
-You can update a single file or the complete source tree.
-
-
-II. Write Access
-~~~~~~~~~~~~~~~~
-If you want to contribute a couple of patches and write access to the CVS
-repository would be handy, please contact Alex Barton, <alex@barton.de>.
-
-
-$Id: CVS.txt,v 1.8.2.1 2006/08/02 09:04:20 alex Exp $

+ 1 - 10
doc/FAQ.txt

@@ -62,15 +62,6 @@ A: On Linux/glibc with chroot enabled you need to put some libraries inside
    is to either disable chroot support or to link against dietlibc instead
    is to either disable chroot support or to link against dietlibc instead
    of glibc. (tnx to Sebastian Siewior)
    of glibc. (tnx to Sebastian Siewior)
 
 
-Q: I am running Linux and ngircd dies on startup with the follwing errors:
-   IO subsystem: epoll (hint size 100, initial maxfd 100, masterfd -1).
-   Cannot initialize IO routines: Function not implemented
-   Server isn't listening on a single port!
-   ngircd exiting due to fatal errors!
-A: epoll is only supported on 2.6 Linux kernels. Either use a 2.6 kernel, or
-   re-run configure with the --without-epoll parameter. After configure
-   completed, you should see select() being listed as IO backend:
-   '(I/O backend: "select()"').
 
 
 IV. Bugs!?
 IV. Bugs!?
 ~~~~~~~~~~
 ~~~~~~~~~~
@@ -85,4 +76,4 @@ A: Please file a bug report at <http://ngircd.barton.de/bugzilla/index.cgi>!
 
 
 
 
 -- 
 -- 
-$Id: FAQ.txt,v 1.11 2005/12/09 21:14:56 fw Exp $
+$Id: FAQ.txt,v 1.12 2008/01/02 22:47:58 alex Exp $

+ 45 - 0
doc/GIT.txt

@@ -0,0 +1,45 @@
+                     ngIRCd - Next Generation IRC Server
+
+                                 -- GIT.txt --
+
+The source code of ngIRCd is maintained using git, the stupid content
+tracker.
+
+I. Getting the source code
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+To access the source tree anonymously, run:
+
+ $ git clone git://ngircd.barton.de/ngircd.git
+
+Thereby a new folder "ngircd" will be created containing all the individual
+source files.
+
+The newly created directory ("ngircd") is the "working directory", all
+git commands will be executed from within this directory in the future.
+
+Please note: When checking out a fresh copy of ngIRCd using git, the
+configure script doesn't exist; you have to run the autogen.sh shell script
+(which is included in the source tree) to generate it. This requires you to
+have GNU automake and GNU autoconf installed on your system.
+
+To update the git tree:
+
+ $ git pull
+
+This retrieves all changes and merges them into the current branch.
+
+II. Contributing
+~~~~~~~~~~~~~~~~
+
+Patches should be sent to the ngircd mailing list. List homepage:
+http://arthur.barton.de/mailman/listinfo/ngircd-ml
+
+If you do not want to send them to the list, you can also mail them
+to Alex Barton, <alex@barton.de>.
+
+
+III. Write Access
+~~~~~~~~~~~~~~~~~
+If you want to contribute a couple of patches and write access to the git
+repository would be handy, please contact Alex Barton, <alex@barton.de>.
+

+ 3 - 5
doc/Makefile.am

@@ -1,6 +1,6 @@
 #
 #
 # ngIRCd -- The Next Generation IRC Daemon
 # ngIRCd -- The Next Generation IRC Daemon
-# Copyright (c)2001-2003 by Alexander Barton (alex@barton.de)
+# Copyright (c)2001-2008 by Alexander Barton (alex@barton.de)
 #
 #
 # Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen
 # Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen
 # der GNU General Public License (GPL), wie von der Free Software Foundation
 # der GNU General Public License (GPL), wie von der Free Software Foundation
@@ -9,13 +9,11 @@
 # Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
 # Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
 # der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
 # der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
 #
 #
-# $Id: Makefile.am,v 1.21 2005/11/29 20:59:57 alex Exp $
-#
 
 
 SUBDIRS = src
 SUBDIRS = src
 
 
-EXTRA_DIST = CVS.txt FAQ.txt Protocol.txt Platforms.txt README-AUX.txt \
-	README-BeOS.txt RFC.txt Zeroconf.txt  sample-ngircd.conf
+EXTRA_DIST = FAQ.txt GIT.txt Protocol.txt Platforms.txt README-AUX.txt \
+	README-BeOS.txt RFC.txt SSL.txt Zeroconf.txt sample-ngircd.conf
 
 
 maintainer-clean-local:
 maintainer-clean-local:
 	rm -f Makefile Makefile.in
 	rm -f Makefile Makefile.in

+ 3 - 5
doc/Makefile.in

@@ -16,7 +16,7 @@
 
 
 #
 #
 # ngIRCd -- The Next Generation IRC Daemon
 # ngIRCd -- The Next Generation IRC Daemon
-# Copyright (c)2001-2003 by Alexander Barton (alex@barton.de)
+# Copyright (c)2001-2008 by Alexander Barton (alex@barton.de)
 #
 #
 # Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen
 # Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen
 # der GNU General Public License (GPL), wie von der Free Software Foundation
 # der GNU General Public License (GPL), wie von der Free Software Foundation
@@ -25,8 +25,6 @@
 # Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
 # Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
 # der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
 # der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
 #
 #
-# $Id: Makefile.am,v 1.21 2005/11/29 20:59:57 alex Exp $
-#
 srcdir = @srcdir@
 srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_srcdir = @top_srcdir@
 VPATH = @srcdir@
 VPATH = @srcdir@
@@ -159,8 +157,8 @@ target_cpu = @target_cpu@
 target_os = @target_os@
 target_os = @target_os@
 target_vendor = @target_vendor@
 target_vendor = @target_vendor@
 SUBDIRS = src
 SUBDIRS = src
-EXTRA_DIST = CVS.txt FAQ.txt Protocol.txt Platforms.txt README-AUX.txt \
-	README-BeOS.txt RFC.txt Zeroconf.txt  sample-ngircd.conf
+EXTRA_DIST = FAQ.txt GIT.txt Protocol.txt Platforms.txt README-AUX.txt \
+	README-BeOS.txt RFC.txt SSL.txt Zeroconf.txt sample-ngircd.conf
 
 
 docdir = $(datadir)/doc/$(PACKAGE)
 docdir = $(datadir)/doc/$(PACKAGE)
 documents = $(EXTRA_DIST) ../AUTHORS ../COPYING ../ChangeLog ../INSTALL \
 documents = $(EXTRA_DIST) ../AUTHORS ../COPYING ../ChangeLog ../INSTALL \

+ 1 - 1
doc/Platforms.txt

@@ -74,4 +74,4 @@ Notes
 (3) Using the kqueue() IO interface.
 (3) Using the kqueue() IO interface.
 
 
 -- 
 -- 
-$Id: Platforms.txt,v 1.14.2.2 2007/04/03 22:08:51 fw Exp $
+$Id: Platforms.txt,v 1.18 2006/10/08 14:09:16 alex Exp $

+ 49 - 3
doc/Protocol.txt

@@ -1,7 +1,7 @@
 
 
                      ngIRCd - Next Generation IRC Server
                      ngIRCd - Next Generation IRC Server
 
 
-                      (c)2001-2003 by Alexander Barton,
+                        (c)2001-2007 Alexander Barton,
                     alex@barton.de, http://www.barton.de/
                     alex@barton.de, http://www.barton.de/
 
 
                ngIRCd is free software and published under the
                ngIRCd is free software and published under the
@@ -79,6 +79,9 @@ The following <serverflags> are defined at the moment:
      peer understands this flag, it will send "MODE +I" and "MODE +b"
      peer understands this flag, it will send "MODE +I" and "MODE +b"
      commands after the server link has been established.
      commands after the server link has been established.
 
 
+- H: The server supports the "enhanced server handshake", see section II.2
+     for a detailed description.
+
 - o: IRC operators are allowed to change channel- and channel-user-modes
 - o: IRC operators are allowed to change channel- and channel-user-modes
      even if they aren't channel-operator of the affected channel.
      even if they aren't channel-operator of the affected channel.
 
 
@@ -90,7 +93,50 @@ The optional parameter <options> is used to propagate server options as
 defined in RFC 2813, section 4.1.1.
 defined in RFC 2813, section 4.1.1.
 
 
 
 
-II.2 Exchange channel-modes, topics, and persistent channels
+II.2 Enhanced Server Handshake
+
+The "enhanced server handshake" is used when both servers support this IRC+
+extension, which is indicated by the 'H' flag in the <serverflags> sent with
+the PASS command, see section II.1.
+
+It basically means, that after exchanging the PASS and SERVER commands the
+server is not registered in the network (as usual), but that IRC numerics
+are exchanged until the numeric 376 (ENDOFMOTD) is received. Afterwards the
+peer is registered in the network as with the regular IRC protocol.
+
+A server implementing the enhanced server handshake (and indicating this
+using 'H' in the <serverflags>) MUST ignore all unknown numerics to it
+silently.
+
+In addition, such a server should at least send the numeric 005 (ISUPPORT)
+to its peer, containing the following information. Syntax: <key>=<value>,
+one token per IRC parameter. If the server has to send more than 12 token
+it must send separate ISUPPORT numerics (this is a limitation of the IRC
+protocol which allows at max 15 arguments per command).
+
+ - NICKLEN: Maximum nickname length. Default: 9.
+ - CASEMAPPING: Case mapping used for nick- and channel name comparing.
+   Default: "ascii", the chars [a-z] are lowercase of [A-Z].
+ - PREFIX: List of channel modes a person can get and the respective prefix
+   a channel or nickname will get in case the person has it. The order of the
+   modes goes from most powerful to least powerful. Default: "(ov)@+"
+ - CHANTYPES: Supported channel prefixes. Default: "#".
+ - CHANMODES: List of channel modes for 4 types, separated by comma (","):
+   Mode that adds or removes a nick or address to a list, mode that changes
+   a setting (both have always has a parameter), mode that changes a setting
+   and only has a parameter when set, and mode that changes a setting and
+   never has a parameter. For example "bI,k,l,imnPst".
+ - CHANLIMIT: Maximum number of channels allowed to join by channel prefix,
+   for example "#:10".
+
+Please see <http://www.irc.org/tech_docs/005.html> for details.
+
+The information exchanged using ISUPPORT can be used to detect configuration
+incompatibilities (different maximum nick name length, for example) and
+therefore to disconnect the peer prior to registering it in the network.
+
+
+II.3 Exchange channel-modes, topics, and persistent channels
 
 
      Command: CHANINFO
      Command: CHANINFO
   Parameters: <channel> +<modes> <key> <limit> [<topic>]
   Parameters: <channel> +<modes> <key> <limit> [<topic>]
@@ -115,4 +161,4 @@ channel mode). In this case <limit> should be "0".
 
 
 
 
 -- 
 -- 
-$Id: Protocol.txt,v 1.13 2005/08/27 19:00:06 alex Exp $
+$Id: Protocol.txt,v 1.14 2007/11/21 12:16:35 alex Exp $

+ 58 - 0
doc/SSL.txt

@@ -0,0 +1,58 @@
+
+                     ngIRCd - Next Generation IRC Server
+
+                      (c)2001-2004 by Alexander Barton,
+                    alex@barton.de, http://www.barton.de/
+
+               ngIRCd is free software and published under the
+                   terms of the GNU General Public License.
+
+                                 -- SSL.txt --
+
+
+ngIRCd actually doesn't support secure connections for client-server or
+server-server links using SSL, the Secure Socket Layer, by itself. But you can
+use the stunnel(8) command to make this work.
+
+  <http://stunnel.mirt.net/>
+  <http://www.stunnel.org/>
+
+Stefan Sperling (stefan at binarchy dot net) mailed me the following text as a
+short "how-to", thanks Stefan!
+
+
+=== snip ===
+    ! This guide applies to stunnel 4.x !
+
+    Put this in your stunnel.conf:
+
+        [ircs]
+        accept = 6667
+        connect = 6668
+
+    This makes stunnel listen for incoming connections
+    on port 6667 and forward decrypted data to port 6668.
+    We call the connection 'ircs'. Stunnel will use this
+    name when logging connection attempts via syslog.
+    You can also use the name in /etc/hosts.{allow,deny}
+    if you run tcp-wrappers.
+
+    To make sure ngircd is listening on the port where
+    the decrypted data arrives, set
+
+        Ports = 6668
+
+    in your ngircd.conf.
+
+    Start stunnel and restart ngircd.
+
+    That's it.
+    Don't forget to activate ssl support in your irc client ;)
+=== snip ===
+
+
+Probably ngIRCd will include support for SSL in the future ...
+
+
+-- 
+$Id: SSL.txt,v 1.2 2004/12/27 01:11:40 alex Exp $

+ 1 - 1
doc/Zeroconf.txt

@@ -37,4 +37,4 @@ Links:
 
 
 
 
 -- 
 -- 
-$Id: Zeroconf.txt,v 1.1.2.1 2006/08/02 09:04:20 alex Exp $
+$Id: Zeroconf.txt,v 1.2 2006/08/03 14:37:29 alex Exp $

+ 37 - 8
doc/sample-ngircd.conf

@@ -1,4 +1,4 @@
-# $Id: sample-ngircd.conf,v 1.37.2.2 2007/04/03 22:08:51 fw Exp $
+# $Id: sample-ngircd.conf,v 1.44 2008/01/07 23:02:29 alex Exp $
 
 
 #
 #
 # This is a sample configuration file for the ngIRCd, which must be adepted
 # This is a sample configuration file for the ngIRCd, which must be adepted
@@ -6,6 +6,10 @@
 #
 #
 # Comments are started with "#" or ";".
 # Comments are started with "#" or ";".
 #
 #
+# A lot of configuration options in this file start with a ";". You have
+# to remove the ";" in front of each variable to actually set a value!
+# The disabled variables are shown with example values for completeness.
+#
 # Use "ngircd --configtest" (see manual page ngircd(8)) to validate that the
 # Use "ngircd --configtest" (see manual page ngircd(8)) to validate that the
 # server interprets the configuration file as expected!
 # server interprets the configuration file as expected!
 #
 #
@@ -36,9 +40,11 @@
 	# one port, separated with ",". (Default: 6667)
 	# one port, separated with ",". (Default: 6667)
 	;Ports = 6667, 6668, 6669
 	;Ports = 6667, 6668, 6669
 
 
-	# IP address on which the server should listen. (Default: empty,
-	# so the server listens on all IP addresses of the system)
-	;Listen = 1.2.3.4
+	# comma seperated list of IP addresses on which the server should
+	# listen. Default values are:
+	# "0.0.0.0" or (if compiled with IPv6 support) "::,0.0.0.0"
+	# so the server listens on all IP addresses of the system by default.
+	;Listen = 127.0.0.1,192.168.0.1
 
 
 	# Text file with the "message of the day" (MOTD). This message will
 	# Text file with the "message of the day" (MOTD). This message will
 	# be shown to all users connecting to the server:
 	# be shown to all users connecting to the server:
@@ -96,17 +102,29 @@
 	# Allow Pre-Defined Channels only (see Section [Channels])
 	# Allow Pre-Defined Channels only (see Section [Channels])
 	;PredefChannelsOnly = no
 	;PredefChannelsOnly = no
 
 
+	# Don't do any DNS lookups when a client connects to the server.
+	;NoDNS = no
+
+	# try to connect to other irc servers using ipv4 and ipv6, if possible
+	;ConnectIPv6 = yes
+	;ConnectIPv4 = yes
+
 	# Maximum number of simultaneous connection the server is allowed
 	# Maximum number of simultaneous connection the server is allowed
-	# to accept (<=0: unlimited):
-	;MaxConnections = -1
+	# to accept (0: unlimited):
+	;MaxConnections = 0
 
 
 	# Maximum number of simultaneous connections from a single IP address
 	# Maximum number of simultaneous connections from a single IP address
-	# the server will accept (<=0: unlimited):
+	# the server will accept (0: unlimited):
 	;MaxConnectionsIP = 5
 	;MaxConnectionsIP = 5
 
 
-	# Maximum number of channels a user can be member of (<=0: no limit):
+	# Maximum number of channels a user can be member of (0: no limit):
 	;MaxJoins = 10
 	;MaxJoins = 10
 
 
+	# Maximum length of an user nick name (Default: 9, as in RFC 2812).
+	# Please note that all servers in an IRC network MUST use the same
+	# maximum nick name length!
+	;MaxNickLength = 9
+
 [Operator]
 [Operator]
 	# [Operator] sections are used to define IRC Operators. There may be
 	# [Operator] sections are used to define IRC Operators. There may be
 	# more than one [Operator] block, one for each local operator.
 	# more than one [Operator] block, one for each local operator.
@@ -145,6 +163,10 @@
 	# this server should establish the connection).
 	# this server should establish the connection).
 	;Host = connect-to-host.the.net
 	;Host = connect-to-host.the.net
 
 
+	# IP address to use as _source_ address for the connection. if unspecified,
+	# ngircd will let the operating system pick an address.
+	;Bind = 10.0.0.1
+
 	# Port of the server to which the ngIRCd should connect. If you
 	# Port of the server to which the ngIRCd should connect. If you
 	# assign no port the ngIRCd waits for incoming connections.
 	# assign no port the ngIRCd waits for incoming connections.
 	;Port = 6667
 	;Port = 6667
@@ -160,6 +182,13 @@
 	# Group of this server (optional)
 	# Group of this server (optional)
 	;Group = 123
 	;Group = 123
 
 
+	# Set the "Passive" option to "yes" if you don't want this ngIRCd to
+	# connect to the configured peer (same as leaving the "Port" variable
+	# empty). The advantage of this option is that you can actually configure
+	# a port an use the IRC command CONNECT more easily to manually connect
+	# this specific server later.
+	;Passive = no
+
 [Server]
 [Server]
 	# More [Server] sections, if you like ...
 	# More [Server] sections, if you like ...
 
 

+ 1 - 1
doc/src/Makefile.am

@@ -8,7 +8,7 @@
 # (at your option) any later version.
 # (at your option) any later version.
 # Please read the file COPYING, README and AUTHORS for more information.
 # Please read the file COPYING, README and AUTHORS for more information.
 #
 #
-# $Id: Makefile.am,v 1.2.2.1 2007/04/03 22:08:52 fw Exp $
+# $Id: Makefile.am,v 1.3 2006/12/28 14:04:28 alex Exp $
 #
 #
 
 
 maintainer-clean-local:
 maintainer-clean-local:

+ 1 - 1
doc/src/Makefile.in

@@ -24,7 +24,7 @@
 # (at your option) any later version.
 # (at your option) any later version.
 # Please read the file COPYING, README and AUTHORS for more information.
 # Please read the file COPYING, README and AUTHORS for more information.
 #
 #
-# $Id: Makefile.am,v 1.2.2.1 2007/04/03 22:08:52 fw Exp $
+# $Id: Makefile.am,v 1.3 2006/12/28 14:04:28 alex Exp $
 #
 #
 srcdir = @srcdir@
 srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_srcdir = @top_srcdir@

+ 15 - 2
man/Makefile.am

@@ -9,12 +9,25 @@
 # Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
 # Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
 # der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
 # der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
 #
 #
-# $Id: Makefile.am,v 1.5 2002/04/04 13:02:41 alex Exp $
+# $Id: Makefile.am,v 1.6 2006/12/25 16:13:26 alex Exp $
 #
 #
 
 
+TEMPLATE_MANS = ngircd.conf.5.tmpl ngircd.8.tmpl
+
+SUFFIXES = .tmpl .
+
+.tmpl:
+	sed \
+	    -e s@:SBINDIR:@${sbindir}@ \
+	    -e s@:BINDIR:@${bindir}@ \
+	    -e s@:ETCDIR:@${sysconfdir}@ \
+	    <$< >$@
+
 man_MANS = ngircd.conf.5 ngircd.8
 man_MANS = ngircd.conf.5 ngircd.8
 
 
-EXTRA_DIST = $(man_MANS)
+CLEANFILES = $(man_MANS)
+
+EXTRA_DIST = $(TEMPLATE_MANS)
 
 
 maintainer-clean-local:
 maintainer-clean-local:
 	rm -f Makefile Makefile.in
 	rm -f Makefile Makefile.in

+ 14 - 2
man/Makefile.in

@@ -25,7 +25,7 @@
 # Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
 # Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
 # der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
 # der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
 #
 #
-# $Id: Makefile.am,v 1.5 2002/04/04 13:02:41 alex Exp $
+# $Id: Makefile.am,v 1.6 2006/12/25 16:13:26 alex Exp $
 #
 #
 srcdir = @srcdir@
 srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_srcdir = @top_srcdir@
@@ -154,11 +154,15 @@ target_alias = @target_alias@
 target_cpu = @target_cpu@
 target_cpu = @target_cpu@
 target_os = @target_os@
 target_os = @target_os@
 target_vendor = @target_vendor@
 target_vendor = @target_vendor@
+TEMPLATE_MANS = ngircd.conf.5.tmpl ngircd.8.tmpl
+SUFFIXES = .tmpl .
 man_MANS = ngircd.conf.5 ngircd.8
 man_MANS = ngircd.conf.5 ngircd.8
-EXTRA_DIST = $(man_MANS)
+CLEANFILES = $(man_MANS)
+EXTRA_DIST = $(TEMPLATE_MANS)
 all: all-am
 all: all-am
 
 
 .SUFFIXES:
 .SUFFIXES:
+.SUFFIXES: .tmpl .
 $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	@for dep in $?; do \
 	@for dep in $?; do \
 	  case '$(am__configure_deps)' in \
 	  case '$(am__configure_deps)' in \
@@ -337,6 +341,7 @@ install-strip:
 mostlyclean-generic:
 mostlyclean-generic:
 
 
 clean-generic:
 clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
 
 
 distclean-generic:
 distclean-generic:
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
@@ -404,6 +409,13 @@ uninstall-man: uninstall-man5 uninstall-man8
 	uninstall-info-am uninstall-man uninstall-man5 uninstall-man8
 	uninstall-info-am uninstall-man uninstall-man5 uninstall-man8
 
 
 
 
+.tmpl:
+	sed \
+	    -e s@:SBINDIR:@${sbindir}@ \
+	    -e s@:BINDIR:@${bindir}@ \
+	    -e s@:ETCDIR:@${sysconfdir}@ \
+	    <$< >$@
+
 maintainer-clean-local:
 maintainer-clean-local:
 	rm -f Makefile Makefile.in
 	rm -f Makefile Makefile.in
 
 

+ 8 - 7
man/ngircd.8

@@ -1,7 +1,7 @@
 .\"
 .\"
-.\" $Id: ngircd.8,v 1.11 2005/08/12 13:20:54 alex Exp $
+.\" $Id: ngircd.8.tmpl,v 1.2 2007/11/15 01:03:29 fw Exp $
 .\"
 .\"
-.TH ngircd 8 "August 2005" ngircd "ngIRCd Manual"
+.TH ngircd 8 "May 2008" ngircd "ngIRCd Manual"
 .SH NAME
 .SH NAME
 ngIRCd \- the next generation IRC daemon
 ngIRCd \- the next generation IRC daemon
 .SH SYNOPSIS
 .SH SYNOPSIS
@@ -23,7 +23,8 @@ Linux, Mac OS X, NetBSD, OpenBSD, Solaris, and Windows with Cygwin.
 .PP
 .PP
 As ngIRCd relies on UNIX standards and uses GNU automake and GNU autoconf
 As ngIRCd relies on UNIX standards and uses GNU automake and GNU autoconf
 there are good chances that it also supports other UNIX-based operating
 there are good chances that it also supports other UNIX-based operating
-systems as well.
+systems as well. By default, ngIRCd writes diagnostic and informational messages using
+the syslog mechanism.
 .SH OPTIONS
 .SH OPTIONS
 The default behaviour of
 The default behaviour of
 .BR ngircd
 .BR ngircd
@@ -49,17 +50,17 @@ CONNECT later on as IRC Operator to link this ngIRCd to other servers.
 \fB\-t\fR, \fB\-\-configtest\fR
 \fB\-t\fR, \fB\-\-configtest\fR
 Read, validate and display the configuration; then exit.
 Read, validate and display the configuration; then exit.
 .TP
 .TP
-\fB\-\-version\fR
+\fB\-V\fR, \fB\-\-version\fR
 Output version information and exit.
 Output version information and exit.
 .TP
 .TP
-\fB\-\-help\fR
+\fB\-h\fR, \fB\-\-help\fR
 Display a brief help text and exit.
 Display a brief help text and exit.
 .SH FILES
 .SH FILES
-.I /usr/local/etc/ngircd.conf
+.I :ETCDIR:/ngircd.conf
 .RS
 .RS
 The system wide default configuration file.
 The system wide default configuration file.
 .RE
 .RE
-.I /usr/local/etc/ngircd.motd
+.I :ETCDIR:/ngircd.motd
 .RS
 .RS
 Default "message of the day" (MOTD).
 Default "message of the day" (MOTD).
 .RE
 .RE

+ 69 - 27
man/ngircd.conf.5

@@ -1,11 +1,11 @@
 .\"
 .\"
-.\" $Id: ngircd.conf.5,v 1.20.2.1 2006/12/11 22:08:14 fw Exp $
+.\" $Id: ngircd.conf.5.tmpl,v 1.7 2007/11/23 16:26:03 fw Exp $
 .\"
 .\"
-.TH ngircd.conf 5 "August 2005" ngircd "ngIRCd Manual"
+.TH ngircd.conf 5 "May 2008" ngircd "ngIRCd Manual"
 .SH NAME
 .SH NAME
 ngircd.conf \- configuration file of ngIRCd
 ngircd.conf \- configuration file of ngIRCd
 .SH SYNOPSIS
 .SH SYNOPSIS
-.B /usr/local/etc/ngircd.conf
+.B :ETCDIR:/ngircd.conf
 .SH DESCRIPTION
 .SH DESCRIPTION
 .BR ngircd.conf
 .BR ngircd.conf
 is the configuration file of the
 is the configuration file of the
@@ -26,19 +26,20 @@ Sections contain parameters of the form
 .RE
 .RE
 .PP
 .PP
 Empty lines and any line beginning with a semicolon (';') or a hash ('#')
 Empty lines and any line beginning with a semicolon (';') or a hash ('#')
-character is treated as a comment and will be ignored.
+character are treated as a comment and will be ignored. Leading and trailing
+whitespaces are trimmed before any processing takes place.
 .PP
 .PP
-The file format is line-based - that means, each newline-terminated line
-represents either a comment, a section name or a parameter.
+The file format is line-based - that means, each non-empty newline-terminated
+line represents either a comment, a section name, or a parameter.
 .PP
 .PP
 Section and parameter names are not case sensitive.
 Section and parameter names are not case sensitive.
 .SH "SECTION OVERVIEW"
 .SH "SECTION OVERVIEW"
 The file can contain blocks of four types: [Global], [Operator], [Server],
 The file can contain blocks of four types: [Global], [Operator], [Server],
 and [Channel].
 and [Channel].
 .PP
 .PP
-In the
+The main configuration of the server is stored in the
 .I [Global]
 .I [Global]
-section, there is the main configuration like the server name and the
+section, like the server name, administrative information and the
 ports on which the server should be listening. IRC operators of this
 ports on which the server should be listening. IRC operators of this
 server are defined in
 server are defined in
 .I [Operator]
 .I [Operator]
@@ -57,7 +58,7 @@ section is used to define the server main configuration, like the server
 name and the ports on which the server should be listening.
 name and the ports on which the server should be listening.
 .TP
 .TP
 \fBName\fR
 \fBName\fR
-Server name in the IRC network
+Server name in the IRC network, must contain at least one dot (".").
 .TP
 .TP
 \fBInfo\fR
 \fBInfo\fR
 Info text of the server. This will be shown by WHOIS and LINKS requests for
 Info text of the server. This will be shown by WHOIS and LINKS requests for
@@ -72,8 +73,10 @@ Ports on which the server should listen. There may be more than one port,
 separated with ','. Default: 6667.
 separated with ','. Default: 6667.
 .TP
 .TP
 \fBListen\fR
 \fBListen\fR
-The IP address on which the server should listen. Default is empty, so
-the server listens on all configured IP addresses and interfaces.
+A comma seperated list of IP address on which the server should listen.
+If unset, the defaults value is "0.0.0.0", or, if ngircd was compiled
+with IPv6 support, "::,0.0.0.0", so the server listens on all configured
+IP addresses and interfaces by default.
 .TP
 .TP
 \fBMotdFile\fR
 \fBMotdFile\fR
 Text file with the "message of the day" (MOTD). This message will be shown
 Text file with the "message of the day" (MOTD). This message will be shown
@@ -81,7 +84,8 @@ to all users connecting to the server.
 .TP
 .TP
 \fBMotdPhrase\fR
 \fBMotdPhrase\fR
 A simple Phrase (<256 chars) if you don't want to use a MOTD file.
 A simple Phrase (<256 chars) if you don't want to use a MOTD file.
-If it is set no MotdFile will be read at all.
+If it is set no MotdFile will be read at all which can be handy if the
+daemon should run inside a chroot directory.
 .TP
 .TP
 \fBServerUID\fR
 \fBServerUID\fR
 User ID under which the server should run; you can use the name of the user
 User ID under which the server should run; you can use the name of the user
@@ -150,19 +154,40 @@ by non-chanops as if they were coming from the server. Default: no.
 If enabled, no new channels can be created. Useful if
 If enabled, no new channels can be created. Useful if
 you do not want to have channels other than those defined in
 you do not want to have channels other than those defined in
 the config file.
 the config file.
+Default: No.
+.TP
+\fBNoDNS\fR
+If enabled, ngircd will not make DNS lookups when clients connect.
+If you configure ngircd to connect to other servers, ngircd may still
+perform a DNS lookup if required.
+Default: No.
+.TP
+\fBConnectIPv4\fR
+Set this to no if you do not want ngircd to connect to other irc servers using ipv4.
+This allows use of ngircd in ipv6-only setups.
+Default: Yes.
+.TP
+\fBConnectIPv6\fR
+Set this to no if you do not want ngircd to connect to other irc servers using ipv6.
+Default: Yes.
 .TP
 .TP
 \fBMaxConnections\fR
 \fBMaxConnections\fR
 Maximum number of simultaneous connection the server is allowed to accept
 Maximum number of simultaneous connection the server is allowed to accept
-(<=0: unlimited). Default: -1.
+(0: unlimited). Default: 0.
 .TP
 .TP
 \fBMaxConnectionsIP\fR
 \fBMaxConnectionsIP\fR
 Maximum number of simultaneous connections from a single IP address that
 Maximum number of simultaneous connections from a single IP address that
-the server will accept (<=0: unlimited). This configuration options lowers
+the server will accept (0: unlimited). This configuration options lowers
 the risk of denial of service attacks (DoS). Default: 5.
 the risk of denial of service attacks (DoS). Default: 5.
 .TP
 .TP
 \fBMaxJoins\fR
 \fBMaxJoins\fR
-Maximum number of channels a user can be member of (<=0: no limit).
+Maximum number of channels a user can be member of (0: no limit).
 Default: 10.
 Default: 10.
+.TP
+\fBMaxNickLength\fR
+Maximum length of an user nick name (Default: 9, as in RFC 2812). Please
+note that all servers in an IRC network MUST use the same maximum nick name
+length!
 .SH [OPERATOR]
 .SH [OPERATOR]
 .I [Operator]
 .I [Operator]
 sections are used to define IRC Operators. There may be more than one
 sections are used to define IRC Operators. There may be more than one
@@ -182,27 +207,34 @@ Example: nick!ident@*.example.com
 Other servers are configured in
 Other servers are configured in
 .I [Server]
 .I [Server]
 sections. If you configure a port for the connection, then this ngIRCd
 sections. If you configure a port for the connection, then this ngIRCd
-tries to connect to to the other server on the given port; if not, it waits
-for the other server to connect.
+tries to connect to to the other server on the given port (active);
+if not, it waits for the other server to connect (passive).
 .PP
 .PP
-The ngIRCd allows "server groups": You can assign an "ID" to every server
-with which you want this ngIRCd to link. If a server of a group won't
-answer, the ngIRCd tries to connect to the next server in the given group.
-But ngIRCd never tries to connect to two servers with the same group ID.
+ngIRCd supports "server groups": You can assign an "ID" to every server
+with which you want this ngIRCd to link, and the daemon ensures that at
+any given time only one direct link exists to servers with the same ID.
+So if a server of a group won't answer, ngIRCd tries to connect to the next
+server in the given group (="with the same ID"), but never tries to connect
+to more than one server of this group simultaneously.
 .PP
 .PP
 There may be more than one
 There may be more than one
 .I [Server]
 .I [Server]
 block.
 block.
 .TP
 .TP
 \fBName\fR
 \fBName\fR
-IRC name of the server
+IRC name of the remote server.
 .TP
 .TP
 \fBHost\fR
 \fBHost\fR
-Internet host name of the peer
+Internet host name (or IP address) of the peer.
+.TP
+\fBBind\fR
+IP address to use as source IP for the outgoing connection. Default ist
+to let the operating system decide.
 .TP
 .TP
 \fBPort\fR
 \fBPort\fR
-Port of the server to which the ngIRCd should connect. If you assign no port
-the ngIRCd waits for incoming connections.
+Port of the remote server to which ngIRCd should connect (active).
+If no port is assigned to a configured server, the daemon only waits for
+incoming connections (passive).
 .TP
 .TP
 \fBMyPassword\fR
 \fBMyPassword\fR
 Own password for this connection. This password has to be configured as
 Own password for this connection. This password has to be configured as
@@ -214,6 +246,10 @@ Foreign password for this connection. This password has to be configured as
 .TP
 .TP
 \fBGroup\fR
 \fBGroup\fR
 Group of this server (optional).
 Group of this server (optional).
+.TP
+\fBPassive\fR
+Disable automatic connection even if port value is specified. Default: false.
+You can use the IRC Operator command CONNECT later on to create the link.
 .SH [CHANNEL]
 .SH [CHANNEL]
 Pre-defined channels can be configured in
 Pre-defined channels can be configured in
 .I [Channel]
 .I [Channel]
@@ -228,13 +264,19 @@ There may be more than one
 block.
 block.
 .TP
 .TP
 \fBName\fR
 \fBName\fR
-Name of the channel
+Name of the channel, including channel prefix ("#").
 .TP
 .TP
 \fBTopic\fR
 \fBTopic\fR
-Topic for this channel
+Topic for this channel.
 .TP
 .TP
 \fBModes\fR
 \fBModes\fR
 Initial channel modes.
 Initial channel modes.
+.TP
+\fBKey\fR
+Sets initial channel key (only relevant if mode k is set).
+.TP
+\fBMaxUsers\fR
+Set maximum user limit for this channel (only relevant if mode l is set).
 .SH HINTS
 .SH HINTS
 It's wise to use "ngircd --configtest" to validate the configuration file
 It's wise to use "ngircd --configtest" to validate the configuration file
 after changing it. See
 after changing it. See

+ 2 - 2
src/Makefile.am

@@ -8,10 +8,10 @@
 # (at your option) any later version.
 # (at your option) any later version.
 # Please read the file COPYING, README and AUTHORS for more information.
 # Please read the file COPYING, README and AUTHORS for more information.
 #
 #
-# $Id: Makefile.am,v 1.7 2005/07/22 21:01:03 alex Exp $
+# $Id: Makefile.am,v 1.8 2008/02/26 22:04:15 fw Exp $
 #
 #
 
 
-SUBDIRS = portab tool ngircd testsuite
+SUBDIRS = portab tool ipaddr ngircd testsuite
 
 
 maintainer-clean-local:
 maintainer-clean-local:
 	rm -f Makefile Makefile.in config.h config.h.in stamp-h.in
 	rm -f Makefile Makefile.in config.h config.h.in stamp-h.in

+ 2 - 2
src/Makefile.in

@@ -24,7 +24,7 @@
 # (at your option) any later version.
 # (at your option) any later version.
 # Please read the file COPYING, README and AUTHORS for more information.
 # Please read the file COPYING, README and AUTHORS for more information.
 #
 #
-# $Id: Makefile.am,v 1.7 2005/07/22 21:01:03 alex Exp $
+# $Id: Makefile.am,v 1.8 2008/02/26 22:04:15 fw Exp $
 #
 #
 srcdir = @srcdir@
 srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_srcdir = @top_srcdir@
@@ -158,7 +158,7 @@ target_alias = @target_alias@
 target_cpu = @target_cpu@
 target_cpu = @target_cpu@
 target_os = @target_os@
 target_os = @target_os@
 target_vendor = @target_vendor@
 target_vendor = @target_vendor@
-SUBDIRS = portab tool ngircd testsuite
+SUBDIRS = portab tool ipaddr ngircd testsuite
 all: config.h
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-recursive
 	$(MAKE) $(AM_MAKEFLAGS) all-recursive
 
 

+ 9 - 0
src/config.h.in

@@ -37,6 +37,9 @@
 /* Define to 1 if you have the `fork' function. */
 /* Define to 1 if you have the `fork' function. */
 #undef HAVE_FORK
 #undef HAVE_FORK
 
 
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
 /* Define to 1 if you have the `gethostbyaddr' function. */
 /* Define to 1 if you have the `gethostbyaddr' function. */
 #undef HAVE_GETHOSTBYADDR
 #undef HAVE_GETHOSTBYADDR
 
 
@@ -46,6 +49,9 @@
 /* Define to 1 if you have the `gethostname' function. */
 /* Define to 1 if you have the `gethostname' function. */
 #undef HAVE_GETHOSTNAME
 #undef HAVE_GETHOSTNAME
 
 
+/* Define to 1 if you have the `getnameinfo' function. */
+#undef HAVE_GETNAMEINFO
+
 /* Define to 1 if you have the <ident.h> header file. */
 /* Define to 1 if you have the <ident.h> header file. */
 #undef HAVE_IDENT_H
 #undef HAVE_IDENT_H
 
 
@@ -304,6 +310,9 @@
 /* Version number of package */
 /* Version number of package */
 #undef VERSION
 #undef VERSION
 
 
+/* Define if IPV6 protocol should be enabled */
+#undef WANT_IPV6
+
 /* Define if support for Zeroconf should be included */
 /* Define if support for Zeroconf should be included */
 #undef ZEROCONF
 #undef ZEROCONF
 
 

+ 14 - 0
src/ipaddr/Makefile.am

@@ -0,0 +1,14 @@
+AUTOMAKE_OPTIONS = ansi2knr
+
+INCLUDES = -I$(srcdir)/../portab
+
+noinst_LIBRARIES = libngipaddr.a
+
+libngipaddr_a_SOURCES = ng_ipaddr.c
+
+noinst_HEADERS = ng_ipaddr.h
+
+maintainer-clean-local:
+	rm -f Makefile Makefile.in
+
+# -eof-

+ 414 - 0
src/ipaddr/Makefile.in

@@ -0,0 +1,414 @@
+# Makefile.in generated by automake 1.9.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+SOURCES = $(libngipaddr_a_SOURCES)
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+ANSI2KNR = @ANSI2KNR@
+subdir = src/ipaddr
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+	$(srcdir)/Makefile.in ansi2knr.1 ansi2knr.c
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/src/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+AR = ar
+ARFLAGS = cru
+libngipaddr_a_AR = $(AR) $(ARFLAGS)
+libngipaddr_a_LIBADD =
+am_libngipaddr_a_OBJECTS = ng_ipaddr$U.$(OBJEXT)
+libngipaddr_a_OBJECTS = $(am_libngipaddr_a_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/src
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libngipaddr_a_SOURCES)
+DIST_SOURCES = $(libngipaddr_a_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+U = @U@
+VERSION = @VERSION@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+AUTOMAKE_OPTIONS = ansi2knr
+INCLUDES = -I$(srcdir)/../portab
+noinst_LIBRARIES = libngipaddr.a
+libngipaddr_a_SOURCES = ng_ipaddr.c
+noinst_HEADERS = ng_ipaddr.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  src/ipaddr/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  src/ipaddr/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libngipaddr.a: $(libngipaddr_a_OBJECTS) $(libngipaddr_a_DEPENDENCIES) 
+	-rm -f libngipaddr.a
+	$(libngipaddr_a_AR) libngipaddr.a $(libngipaddr_a_OBJECTS) $(libngipaddr_a_LIBADD)
+	$(RANLIB) libngipaddr.a
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+ansi2knr: ansi2knr.$(OBJEXT)
+	$(LINK) ansi2knr.$(OBJEXT) $(LIBS)
+ansi2knr.$(OBJEXT): $(CONFIG_HEADER)
+
+clean-krextra:
+	-rm -f ansi2knr
+
+mostlyclean-kr:
+	-test "$U" = "" || rm -f *_.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ng_ipaddr$U.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+ng_ipaddr_.c: ng_ipaddr.c $(ANSI2KNR)
+	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ng_ipaddr.c; then echo $(srcdir)/ng_ipaddr.c; else echo ng_ipaddr.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+ng_ipaddr_.$(OBJEXT) : $(ANSI2KNR)
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(ANSI2KNR) $(LIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-krextra clean-noinstLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic \
+	maintainer-clean-local
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic mostlyclean-kr
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-krextra clean-noinstLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-exec install-exec-am \
+	install-info install-info-am install-man install-strip \
+	installcheck installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic maintainer-clean-local mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-kr pdf \
+	pdf-am ps ps-am tags uninstall uninstall-am uninstall-info-am
+
+
+maintainer-clean-local:
+	rm -f Makefile Makefile.in
+
+# -eof-
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

+ 36 - 0
src/ipaddr/ansi2knr.1

@@ -0,0 +1,36 @@
+.TH ANSI2KNR 1 "19 Jan 1996"
+.SH NAME
+ansi2knr \- convert ANSI C to Kernighan & Ritchie C
+.SH SYNOPSIS
+.I ansi2knr
+[--varargs] input_file [output_file]
+.SH DESCRIPTION
+If no output_file is supplied, output goes to stdout.
+.br
+There are no error messages.
+.sp
+.I ansi2knr
+recognizes function definitions by seeing a non-keyword identifier at the left
+margin, followed by a left parenthesis, with a right parenthesis as the last
+character on the line, and with a left brace as the first token on the
+following line (ignoring possible intervening comments).  It will recognize a
+multi-line header provided that no intervening line ends with a left or right
+brace or a semicolon.  These algorithms ignore whitespace and comments, except
+that the function name must be the first thing on the line.
+.sp
+The following constructs will confuse it:
+.br
+     - Any other construct that starts at the left margin and follows the
+above syntax (such as a macro or function call).
+.br
+     - Some macros that tinker with the syntax of the function header.
+.sp
+The --varargs switch is obsolete, and is recognized only for
+backwards compatibility.  The present version of
+.I ansi2knr
+will always attempt to convert a ... argument to va_alist and va_dcl.
+.SH AUTHOR
+L. Peter Deutsch <ghost@aladdin.com> wrote the original ansi2knr and
+continues to maintain the current version; most of the code in the current
+version is his work.  ansi2knr also includes contributions by Francois
+Pinard <pinard@iro.umontreal.ca> and Jim Avera <jima@netcom.com>.

+ 739 - 0
src/ipaddr/ansi2knr.c

@@ -0,0 +1,739 @@
+/* Copyright (C) 1989, 2000 Aladdin Enterprises.  All rights reserved. */
+
+/*$Id: ansi2knr.c,v 1.3 2000/04/13 03:41:48 lpd Exp $*/
+/* Convert ANSI C function definitions to K&R ("traditional C") syntax */
+
+/*
+ansi2knr is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY.  No author or distributor accepts responsibility to anyone for the
+consequences of using it or for whether it serves any particular purpose or
+works at all, unless he says so in writing.  Refer to the GNU General Public
+License (the "GPL") for full details.
+
+Everyone is granted permission to copy, modify and redistribute ansi2knr,
+but only under the conditions described in the GPL.  A copy of this license
+is supposed to have been given to you along with ansi2knr so you can know
+your rights and responsibilities.  It should be in a file named COPYLEFT,
+or, if there is no file named COPYLEFT, a file named COPYING.  Among other
+things, the copyright notice and this notice must be preserved on all
+copies.
+
+We explicitly state here what we believe is already implied by the GPL: if
+the ansi2knr program is distributed as a separate set of sources and a
+separate executable file which are aggregated on a storage medium together
+with another program, this in itself does not bring the other program under
+the GPL, nor does the mere fact that such a program or the procedures for
+constructing it invoke the ansi2knr executable bring any other part of the
+program under the GPL.
+*/
+
+/*
+ * Usage:
+	ansi2knr [--filename FILENAME] [INPUT_FILE [OUTPUT_FILE]]
+ * --filename provides the file name for the #line directive in the output,
+ * overriding input_file (if present).
+ * If no input_file is supplied, input is read from stdin.
+ * If no output_file is supplied, output goes to stdout.
+ * There are no error messages.
+ *
+ * ansi2knr recognizes function definitions by seeing a non-keyword
+ * identifier at the left margin, followed by a left parenthesis, with a
+ * right parenthesis as the last character on the line, and with a left
+ * brace as the first token on the following line (ignoring possible
+ * intervening comments and/or preprocessor directives), except that a line
+ * consisting of only
+ *	identifier1(identifier2)
+ * will not be considered a function definition unless identifier2 is
+ * the word "void", and a line consisting of
+ *	identifier1(identifier2, <<arbitrary>>)
+ * will not be considered a function definition.
+ * ansi2knr will recognize a multi-line header provided that no intervening
+ * line ends with a left or right brace or a semicolon.  These algorithms
+ * ignore whitespace, comments, and preprocessor directives, except that
+ * the function name must be the first thing on the line.  The following
+ * constructs will confuse it:
+ *	- Any other construct that starts at the left margin and
+ *	    follows the above syntax (such as a macro or function call).
+ *	- Some macros that tinker with the syntax of function headers.
+ */
+
+/*
+ * The original and principal author of ansi2knr is L. Peter Deutsch
+ * <ghost@aladdin.com>.  Other authors are noted in the change history
+ * that follows (in reverse chronological order):
+
+	lpd 2000-04-12 backs out Eggert's changes because of bugs:
+	- concatlits didn't declare the type of its bufend argument;
+	- concatlits didn't recognize when it was inside a comment;
+	- scanstring could scan backward past the beginning of the string; when
+	- the check for \ + newline in scanstring was unnecessary.
+
+	2000-03-05  Paul Eggert  <eggert@twinsun.com>
+
+	Add support for concatenated string literals.
+	* ansi2knr.c (concatlits): New decl.
+	(main): Invoke concatlits to concatenate string literals.
+	(scanstring): Handle backslash-newline correctly.  Work with
+	character constants.  Fix bug when scanning backwards through
+	backslash-quote.  Check for unterminated strings.
+	(convert1): Parse character constants, too.
+	(appendline, concatlits): New functions.
+	* ansi2knr.1: Document this.
+
+	lpd 1999-08-17 added code to allow preprocessor directives
+		wherever comments are allowed
+	lpd 1999-04-12 added minor fixes from Pavel Roskin
+		<pavel_roskin@geocities.com> for clean compilation with
+		gcc -W -Wall
+	lpd 1999-03-22 added hack to recognize lines consisting of
+		identifier1(identifier2, xxx) as *not* being procedures
+	lpd 1999-02-03 made indentation of preprocessor commands consistent
+	lpd 1999-01-28 fixed two bugs: a '/' in an argument list caused an
+		endless loop; quoted strings within an argument list
+		confused the parser
+	lpd 1999-01-24 added a check for write errors on the output,
+		suggested by Jim Meyering <meyering@ascend.com>
+	lpd 1998-11-09 added further hack to recognize identifier(void)
+		as being a procedure
+	lpd 1998-10-23 added hack to recognize lines consisting of
+		identifier1(identifier2) as *not* being procedures
+	lpd 1997-12-08 made input_file optional; only closes input and/or
+		output file if not stdin or stdout respectively; prints
+		usage message on stderr rather than stdout; adds
+		--filename switch (changes suggested by
+		<ceder@lysator.liu.se>)
+	lpd 1996-01-21 added code to cope with not HAVE_CONFIG_H and with
+		compilers that don't understand void, as suggested by
+		Tom Lane
+	lpd 1996-01-15 changed to require that the first non-comment token
+		on the line following a function header be a left brace,
+		to reduce sensitivity to macros, as suggested by Tom Lane
+		<tgl@sss.pgh.pa.us>
+	lpd 1995-06-22 removed #ifndefs whose sole purpose was to define
+		undefined preprocessor symbols as 0; changed all #ifdefs
+		for configuration symbols to #ifs
+	lpd 1995-04-05 changed copyright notice to make it clear that
+		including ansi2knr in a program does not bring the entire
+		program under the GPL
+	lpd 1994-12-18 added conditionals for systems where ctype macros
+		don't handle 8-bit characters properly, suggested by
+		Francois Pinard <pinard@iro.umontreal.ca>;
+		removed --varargs switch (this is now the default)
+	lpd 1994-10-10 removed CONFIG_BROKETS conditional
+	lpd 1994-07-16 added some conditionals to help GNU `configure',
+		suggested by Francois Pinard <pinard@iro.umontreal.ca>;
+		properly erase prototype args in function parameters,
+		contributed by Jim Avera <jima@netcom.com>;
+		correct error in writeblanks (it shouldn't erase EOLs)
+	lpd 1989-xx-xx original version
+ */
+
+/* Most of the conditionals here are to make ansi2knr work with */
+/* or without the GNU configure machinery. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#if HAVE_CONFIG_H
+
+/*
+   For properly autoconfiguring ansi2knr, use AC_CONFIG_HEADER(config.h).
+   This will define HAVE_CONFIG_H and so, activate the following lines.
+ */
+
+# if STDC_HEADERS || HAVE_STRING_H
+#  include <string.h>
+# else
+#  include <strings.h>
+# endif
+
+#else /* not HAVE_CONFIG_H */
+
+/* Otherwise do it the hard way */
+
+# ifdef BSD
+#  include <strings.h>
+# else
+#  ifdef VMS
+    extern int strlen(), strncmp();
+#  else
+#   include <string.h>
+#  endif
+# endif
+
+#endif /* not HAVE_CONFIG_H */
+
+#if STDC_HEADERS
+# include <stdlib.h>
+#else
+/*
+   malloc and free should be declared in stdlib.h,
+   but if you've got a K&R compiler, they probably aren't.
+ */
+# ifdef MSDOS
+#  include <malloc.h>
+# else
+#  ifdef VMS
+     extern char *malloc();
+     extern void free();
+#  else
+     extern char *malloc();
+     extern int free();
+#  endif
+# endif
+
+#endif
+
+/* Define NULL (for *very* old compilers). */
+#ifndef NULL
+# define NULL (0)
+#endif
+
+/*
+ * The ctype macros don't always handle 8-bit characters correctly.
+ * Compensate for this here.
+ */
+#ifdef isascii
+# undef HAVE_ISASCII		/* just in case */
+# define HAVE_ISASCII 1
+#else
+#endif
+#if STDC_HEADERS || !HAVE_ISASCII
+# define is_ascii(c) 1
+#else
+# define is_ascii(c) isascii(c)
+#endif
+
+#define is_space(c) (is_ascii(c) && isspace(c))
+#define is_alpha(c) (is_ascii(c) && isalpha(c))
+#define is_alnum(c) (is_ascii(c) && isalnum(c))
+
+/* Scanning macros */
+#define isidchar(ch) (is_alnum(ch) || (ch) == '_')
+#define isidfirstchar(ch) (is_alpha(ch) || (ch) == '_')
+
+/* Forward references */
+char *ppdirforward();
+char *ppdirbackward();
+char *skipspace();
+char *scanstring();
+int writeblanks();
+int test1();
+int convert1();
+
+/* The main program */
+int
+main(argc, argv)
+    int argc;
+    char *argv[];
+{	FILE *in = stdin;
+	FILE *out = stdout;
+	char *filename = 0;
+	char *program_name = argv[0];
+	char *output_name = 0;
+#define bufsize 5000			/* arbitrary size */
+	char *buf;
+	char *line;
+	char *more;
+	char *usage =
+	  "Usage: ansi2knr [--filename FILENAME] [INPUT_FILE [OUTPUT_FILE]]\n";
+	/*
+	 * In previous versions, ansi2knr recognized a --varargs switch.
+	 * If this switch was supplied, ansi2knr would attempt to convert
+	 * a ... argument to va_alist and va_dcl; if this switch was not
+	 * supplied, ansi2knr would simply drop any such arguments.
+	 * Now, ansi2knr always does this conversion, and we only
+	 * check for this switch for backward compatibility.
+	 */
+	int convert_varargs = 1;
+	int output_error;
+
+	while ( argc > 1 && argv[1][0] == '-' ) {
+	  if ( !strcmp(argv[1], "--varargs") ) {
+	    convert_varargs = 1;
+	    argc--;
+	    argv++;
+	    continue;
+	  }
+	  if ( !strcmp(argv[1], "--filename") && argc > 2 ) {
+	    filename = argv[2];
+	    argc -= 2;
+	    argv += 2;
+	    continue;
+	  }
+	  fprintf(stderr, "%s: Unrecognized switch: %s\n", program_name,
+		  argv[1]);
+	  fprintf(stderr, usage);
+	  exit(1);
+	}
+	switch ( argc )
+	   {
+	default:
+		fprintf(stderr, usage);
+		exit(0);
+	case 3:
+		output_name = argv[2];
+		out = fopen(output_name, "w");
+		if ( out == NULL ) {
+		  fprintf(stderr, "%s: Cannot open output file %s\n",
+			  program_name, output_name);
+		  exit(1);
+		}
+		/* falls through */
+	case 2:
+		in = fopen(argv[1], "r");
+		if ( in == NULL ) {
+		  fprintf(stderr, "%s: Cannot open input file %s\n",
+			  program_name, argv[1]);
+		  exit(1);
+		}
+		if ( filename == 0 )
+		  filename = argv[1];
+		/* falls through */
+	case 1:
+		break;
+	   }
+	if ( filename )
+	  fprintf(out, "#line 1 \"%s\"\n", filename);
+	buf = malloc(bufsize);
+	if ( buf == NULL )
+	   {
+		fprintf(stderr, "Unable to allocate read buffer!\n");
+		exit(1);
+	   }
+	line = buf;
+	while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL )
+	   {
+test:		line += strlen(line);
+		switch ( test1(buf) )
+		   {
+		case 2:			/* a function header */
+			convert1(buf, out, 1, convert_varargs);
+			break;
+		case 1:			/* a function */
+			/* Check for a { at the start of the next line. */
+			more = ++line;
+f:			if ( line >= buf + (bufsize - 1) ) /* overflow check */
+			  goto wl;
+			if ( fgets(line, (unsigned)(buf + bufsize - line), in) == NULL )
+			  goto wl;
+			switch ( *skipspace(ppdirforward(more), 1) )
+			  {
+			  case '{':
+			    /* Definitely a function header. */
+			    convert1(buf, out, 0, convert_varargs);
+			    fputs(more, out);
+			    break;
+			  case 0:
+			    /* The next line was blank or a comment: */
+			    /* keep scanning for a non-comment. */
+			    line += strlen(line);
+			    goto f;
+			  default:
+			    /* buf isn't a function header, but */
+			    /* more might be. */
+			    fputs(buf, out);
+			    strcpy(buf, more);
+			    line = buf;
+			    goto test;
+			  }
+			break;
+		case -1:		/* maybe the start of a function */
+			if ( line != buf + (bufsize - 1) ) /* overflow check */
+			  continue;
+			/* falls through */
+		default:		/* not a function */
+wl:			fputs(buf, out);
+			break;
+		   }
+		line = buf;
+	   }
+	if ( line != buf )
+	  fputs(buf, out);
+	free(buf);
+	if ( output_name ) {
+	  output_error = ferror(out);
+	  output_error |= fclose(out);
+	} else {		/* out == stdout */
+	  fflush(out);
+	  output_error = ferror(out);
+	}
+	if ( output_error ) {
+	  fprintf(stderr, "%s: error writing to %s\n", program_name,
+		  (output_name ? output_name : "stdout"));
+	  exit(1);
+	}
+	if ( in != stdin )
+	  fclose(in);
+	return 0;
+}
+
+/*
+ * Skip forward or backward over one or more preprocessor directives.
+ */
+char *
+ppdirforward(p)
+    char *p;
+{
+    for (; *p == '#'; ++p) {
+	for (; *p != '\r' && *p != '\n'; ++p)
+	    if (*p == 0)
+		return p;
+	if (*p == '\r' && p[1] == '\n')
+	    ++p;
+    }
+    return p;
+}
+char *
+ppdirbackward(p, limit)
+    char *p;
+    char *limit;
+{
+    char *np = p;
+
+    for (;; p = --np) {
+	if (*np == '\n' && np[-1] == '\r')
+	    --np;
+	for (; np > limit && np[-1] != '\r' && np[-1] != '\n'; --np)
+	    if (np[-1] == 0)
+		return np;
+	if (*np != '#')
+	    return p;
+    }
+}
+
+/*
+ * Skip over whitespace, comments, and preprocessor directives,
+ * in either direction.
+ */
+char *
+skipspace(p, dir)
+    char *p;
+    int dir;			/* 1 for forward, -1 for backward */
+{
+    for ( ; ; ) {
+	while ( is_space(*p) )
+	    p += dir;
+	if ( !(*p == '/' && p[dir] == '*') )
+	    break;
+	p += dir;  p += dir;
+	while ( !(*p == '*' && p[dir] == '/') ) {
+	    if ( *p == 0 )
+		return p;	/* multi-line comment?? */
+	    p += dir;
+	}
+	p += dir;  p += dir;
+    }
+    return p;
+}
+
+/* Scan over a quoted string, in either direction. */
+char *
+scanstring(p, dir)
+    char *p;
+    int dir;
+{
+    for (p += dir; ; p += dir)
+	if (*p == '"' && p[-dir] != '\\')
+	    return p + dir;
+}
+
+/*
+ * Write blanks over part of a string.
+ * Don't overwrite end-of-line characters.
+ */
+int
+writeblanks(start, end)
+    char *start;
+    char *end;
+{	char *p;
+	for ( p = start; p < end; p++ )
+	  if ( *p != '\r' && *p != '\n' )
+	    *p = ' ';
+	return 0;
+}
+
+/*
+ * Test whether the string in buf is a function definition.
+ * The string may contain and/or end with a newline.
+ * Return as follows:
+ *	0 - definitely not a function definition;
+ *	1 - definitely a function definition;
+ *	2 - definitely a function prototype (NOT USED);
+ *	-1 - may be the beginning of a function definition,
+ *		append another line and look again.
+ * The reason we don't attempt to convert function prototypes is that
+ * Ghostscript's declaration-generating macros look too much like
+ * prototypes, and confuse the algorithms.
+ */
+int
+test1(buf)
+    char *buf;
+{	char *p = buf;
+	char *bend;
+	char *endfn;
+	int contin;
+
+	if ( !isidfirstchar(*p) )
+	  return 0;		/* no name at left margin */
+	bend = skipspace(ppdirbackward(buf + strlen(buf) - 1, buf), -1);
+	switch ( *bend )
+	   {
+	   case ';': contin = 0 /*2*/; break;
+	   case ')': contin = 1; break;
+	   case '{': return 0;		/* not a function */
+	   case '}': return 0;		/* not a function */
+	   default: contin = -1;
+	   }
+	while ( isidchar(*p) )
+	  p++;
+	endfn = p;
+	p = skipspace(p, 1);
+	if ( *p++ != '(' )
+	  return 0;		/* not a function */
+	p = skipspace(p, 1);
+	if ( *p == ')' )
+	  return 0;		/* no parameters */
+	/* Check that the apparent function name isn't a keyword. */
+	/* We only need to check for keywords that could be followed */
+	/* by a left parenthesis (which, unfortunately, is most of them). */
+	   {	static char *words[] =
+		   {	"asm", "auto", "case", "char", "const", "double",
+			"extern", "float", "for", "if", "int", "long",
+			"register", "return", "short", "signed", "sizeof",
+			"static", "switch", "typedef", "unsigned",
+			"void", "volatile", "while", 0
+		   };
+		char **key = words;
+		char *kp;
+		unsigned len = endfn - buf;
+
+		while ( (kp = *key) != 0 )
+		   {	if ( strlen(kp) == len && !strncmp(kp, buf, len) )
+			  return 0;	/* name is a keyword */
+			key++;
+		   }
+	   }
+	   {
+	       char *id = p;
+	       int len;
+	       /*
+		* Check for identifier1(identifier2) and not
+		* identifier1(void), or identifier1(identifier2, xxxx).
+		*/
+
+	       while ( isidchar(*p) )
+		   p++;
+	       len = p - id;
+	       p = skipspace(p, 1);
+	       if (*p == ',' ||
+		   (*p == ')' && (len != 4 || strncmp(id, "void", 4)))
+		   )
+		   return 0;	/* not a function */
+	   }
+	/*
+	 * If the last significant character was a ), we need to count
+	 * parentheses, because it might be part of a formal parameter
+	 * that is a procedure.
+	 */
+	if (contin > 0) {
+	    int level = 0;
+
+	    for (p = skipspace(buf, 1); *p; p = skipspace(p + 1, 1))
+		level += (*p == '(' ? 1 : *p == ')' ? -1 : 0);
+	    if (level > 0)
+		contin = -1;
+	}
+	return contin;
+}
+
+/* Convert a recognized function definition or header to K&R syntax. */
+int
+convert1(buf, out, header, convert_varargs)
+    char *buf;
+    FILE *out;
+    int header;			/* Boolean */
+    int convert_varargs;	/* Boolean */
+{	char *endfn;
+	char *p;
+	/*
+	 * The breaks table contains pointers to the beginning and end
+	 * of each argument.
+	 */
+	char **breaks;
+	unsigned num_breaks = 2;	/* for testing */
+	char **btop;
+	char **bp;
+	char **ap;
+	char *vararg = 0;
+
+	/* Pre-ANSI implementations don't agree on whether strchr */
+	/* is called strchr or index, so we open-code it here. */
+	for ( endfn = buf; *(endfn++) != '('; )
+	  ;
+top:	p = endfn;
+	breaks = (char **)malloc(sizeof(char *) * num_breaks * 2);
+	if ( breaks == NULL )
+	   {	/* Couldn't allocate break table, give up */
+		fprintf(stderr, "Unable to allocate break table!\n");
+		fputs(buf, out);
+		return -1;
+	   }
+	btop = breaks + num_breaks * 2 - 2;
+	bp = breaks;
+	/* Parse the argument list */
+	do
+	   {	int level = 0;
+		char *lp = NULL;
+		char *rp = NULL;
+		char *end = NULL;
+
+		if ( bp >= btop )
+		   {	/* Filled up break table. */
+			/* Allocate a bigger one and start over. */
+			free((char *)breaks);
+			num_breaks <<= 1;
+			goto top;
+		   }
+		*bp++ = p;
+		/* Find the end of the argument */
+		for ( ; end == NULL; p++ )
+		   {	switch(*p)
+			   {
+			   case ',':
+				if ( !level ) end = p;
+				break;
+			   case '(':
+				if ( !level ) lp = p;
+				level++;
+				break;
+			   case ')':
+				if ( --level < 0 ) end = p;
+				else rp = p;
+				break;
+			   case '/':
+				if (p[1] == '*')
+				    p = skipspace(p, 1) - 1;
+				break;
+			   case '"':
+			       p = scanstring(p, 1) - 1;
+			       break;
+			   default:
+				;
+			   }
+		   }
+		/* Erase any embedded prototype parameters. */
+		if ( lp && rp )
+		  writeblanks(lp + 1, rp);
+		p--;			/* back up over terminator */
+		/* Find the name being declared. */
+		/* This is complicated because of procedure and */
+		/* array modifiers. */
+		for ( ; ; )
+		   {	p = skipspace(p - 1, -1);
+			switch ( *p )
+			   {
+			   case ']':	/* skip array dimension(s) */
+			   case ')':	/* skip procedure args OR name */
+			   {	int level = 1;
+				while ( level )
+				 switch ( *--p )
+				   {
+				   case ']': case ')':
+				       level++;
+				       break;
+				   case '[': case '(':
+				       level--;
+				       break;
+				   case '/':
+				       if (p > buf && p[-1] == '*')
+					   p = skipspace(p, -1) + 1;
+				       break;
+				   case '"':
+				       p = scanstring(p, -1) + 1;
+				       break;
+				   default: ;
+				   }
+			   }
+				if ( *p == '(' && *skipspace(p + 1, 1) == '*' )
+				   {	/* We found the name being declared */
+					while ( !isidfirstchar(*p) )
+					  p = skipspace(p, 1) + 1;
+					goto found;
+				   }
+				break;
+			   default:
+				goto found;
+			   }
+		   }
+found:		if ( *p == '.' && p[-1] == '.' && p[-2] == '.' )
+		  {	if ( convert_varargs )
+			  {	*bp++ = "va_alist";
+				vararg = p-2;
+			  }
+			else
+			  {	p++;
+				if ( bp == breaks + 1 )	/* sole argument */
+				  writeblanks(breaks[0], p);
+				else
+				  writeblanks(bp[-1] - 1, p);
+				bp--;
+			  }
+		   }
+		else
+		   {	while ( isidchar(*p) ) p--;
+			*bp++ = p+1;
+		   }
+		p = end;
+	   }
+	while ( *p++ == ',' );
+	*bp = p;
+	/* Make a special check for 'void' arglist */
+	if ( bp == breaks+2 )
+	   {	p = skipspace(breaks[0], 1);
+		if ( !strncmp(p, "void", 4) )
+		   {	p = skipspace(p+4, 1);
+			if ( p == breaks[2] - 1 )
+			   {	bp = breaks;	/* yup, pretend arglist is empty */
+				writeblanks(breaks[0], p + 1);
+			   }
+		   }
+	   }
+	/* Put out the function name and left parenthesis. */
+	p = buf;
+	while ( p != endfn ) putc(*p, out), p++;
+	/* Put out the declaration. */
+	if ( header )
+	  {	fputs(");", out);
+		for ( p = breaks[0]; *p; p++ )
+		  if ( *p == '\r' || *p == '\n' )
+		    putc(*p, out);
+	  }
+	else
+	  {	for ( ap = breaks+1; ap < bp; ap += 2 )
+		  {	p = *ap;
+			while ( isidchar(*p) )
+			  putc(*p, out), p++;
+			if ( ap < bp - 1 )
+			  fputs(", ", out);
+		  }
+		fputs(")  ", out);
+		/* Put out the argument declarations */
+		for ( ap = breaks+2; ap <= bp; ap += 2 )
+		  (*ap)[-1] = ';';
+		if ( vararg != 0 )
+		  {	*vararg = 0;
+			fputs(breaks[0], out);		/* any prior args */
+			fputs("va_dcl", out);		/* the final arg */
+			fputs(bp[0], out);
+		  }
+		else
+		  fputs(breaks[0], out);
+	  }
+	free((char *)breaks);
+	return 0;
+}

+ 167 - 0
src/ipaddr/ng_ipaddr.c

@@ -0,0 +1,167 @@
+/*
+ * Functions for AF_ agnostic ipv4/ipv6 handling.
+ *
+ * (c) 2008 Florian Westphal <fw@strlen.de>, public domain.
+ */
+
+#include "portab.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_GETADDRINFO
+#include <netdb.h>
+#include <sys/types.h>
+#endif
+
+#include "ng_ipaddr.h"
+
+GLOBAL bool
+ng_ipaddr_init(ng_ipaddr_t *addr, const char *ip_str, UINT16 port)
+{
+#ifdef HAVE_GETADDRINFO
+	int ret;
+	char portstr[64];
+	struct addrinfo *res0;
+	struct addrinfo hints;
+
+	assert(ip_str);
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_flags = AI_NUMERICHOST;
+
+	/* some getaddrinfo implementations require that ai_socktype is set. */
+	hints.ai_socktype = SOCK_STREAM;
+
+	/* silly, but ngircd stores UINT16 in server config, not string */
+	snprintf(portstr, sizeof(portstr), "%u", (unsigned int) port);
+
+	ret = getaddrinfo(ip_str, portstr, &hints, &res0);
+	assert(ret == 0);
+	if (ret != 0)
+		return false;
+
+	assert(sizeof(*addr) >= res0->ai_addrlen);
+	if (sizeof(*addr) >= res0->ai_addrlen)
+		memcpy(addr, res0->ai_addr, res0->ai_addrlen);
+	else
+		ret = -1;
+	freeaddrinfo(res0);
+	return ret == 0;
+#else /* HAVE_GETADDRINFO */
+	assert(ip_str);
+	addr->sin4.sin_family = AF_INET;
+# ifdef HAVE_INET_ATON
+	if (inet_aton(ip_str, &addr->sin4.sin_addr) == 0)
+		return false;
+# else
+	addr->sin4.sin_addr.s_addr = inet_addr(ip_str);
+	if (addr->sin4.sin_addr.s_addr == (unsigned) -1)
+		return false;
+# endif
+	ng_ipaddr_setport(addr, port);
+	return true;
+#endif /* HAVE_GETADDRINFO */
+}
+
+
+GLOBAL void
+ng_ipaddr_setport(ng_ipaddr_t *a, UINT16 port)
+{
+#ifdef WANT_IPV6
+	int af;
+
+	assert(a != NULL);
+
+	af = a->sa.sa_family;
+
+	assert(af == AF_INET || af == AF_INET6);
+
+	switch (af) {
+	case AF_INET:
+		a->sin4.sin_port = htons(port);
+		break;
+	case AF_INET6:
+		a->sin6.sin6_port = htons(port);
+		break;
+	}
+#else /* WANT_IPV6 */
+	assert(a != NULL);
+	assert(a->sin4.sin_family == AF_INET);
+	a->sin4.sin_port = htons(port);
+#endif /* WANT_IPV6 */
+}
+
+
+
+GLOBAL bool
+ng_ipaddr_ipequal(const ng_ipaddr_t *a, const ng_ipaddr_t *b)
+{
+	assert(a != NULL);
+	assert(b != NULL);
+#ifdef WANT_IPV6
+	if (a->sa.sa_family != b->sa.sa_family)
+		return false;
+	assert(ng_ipaddr_salen(a) == ng_ipaddr_salen(b));
+	switch (a->sa.sa_family) {
+	case AF_INET6:
+		return IN6_ARE_ADDR_EQUAL(&a->sin6.sin6_addr, &b->sin6.sin6_addr);
+	case AF_INET:
+		return memcmp(&a->sin4.sin_addr, &b->sin4.sin_addr, sizeof(a->sin4.sin_addr)) == 0;
+	}
+	return false;
+#else
+	assert(a->sin4.sin_family == AF_INET);
+	assert(b->sin4.sin_family == AF_INET);
+	return memcmp(&a->sin4.sin_addr, &b->sin4.sin_addr, sizeof(a->sin4.sin_addr)) == 0;
+#endif
+}
+
+
+#ifdef WANT_IPV6
+GLOBAL const char *
+ng_ipaddr_tostr(const ng_ipaddr_t *addr)
+{
+	static char strbuf[NG_INET_ADDRSTRLEN];
+
+	strbuf[0] = 0;
+
+	ng_ipaddr_tostr_r(addr, strbuf);
+	return strbuf;
+}
+
+
+/* str must be at least NG_INET_ADDRSTRLEN bytes long */
+GLOBAL bool
+ng_ipaddr_tostr_r(const ng_ipaddr_t *addr, char *str)
+{
+#ifdef HAVE_GETNAMEINFO
+	const struct sockaddr *sa = (const struct sockaddr *) addr;
+	int ret;
+
+	*str = 0;
+
+	ret = getnameinfo(sa, ng_ipaddr_salen(addr),
+			str, NG_INET_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
+	/*
+	 * avoid leading ':'.
+	 * causes mis-interpretation of client host in e.g. /WHOIS
+	 */
+	if (*str == ':') {
+		char tmp[NG_INET_ADDRSTRLEN] = "0";
+		ret = getnameinfo(sa, ng_ipaddr_salen(addr),
+				tmp+1, sizeof(tmp) -1, NULL, 0, NI_NUMERICHOST);
+		if (ret == 0)
+			strlcpy(str, tmp, NG_INET_ADDRSTRLEN);
+	}
+	assert (ret == 0);
+	return ret == 0;
+#else
+	abort(); /* WANT_IPV6 depends on HAVE_GETNAMEINFO */
+#endif
+}
+
+#endif /* WANT_IPV6 */
+
+/* -eof- */

+ 117 - 0
src/ipaddr/ng_ipaddr.h

@@ -0,0 +1,117 @@
+/*
+ * Functions for AF_ agnostic ipv4/ipv6 handling.
+ *
+ * (c) 2008 Florian Westphal <fw@strlen.de>, public domain.
+ */
+
+#ifndef NG_IPADDR_HDR
+#define NG_IPADDR_HDR
+#include "portab.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#else
+# define PF_INET AF_INET
+#endif
+
+
+#ifdef WANT_IPV6
+#define NG_INET_ADDRSTRLEN	INET6_ADDRSTRLEN
+#else
+#define NG_INET_ADDRSTRLEN	16
+#endif
+
+
+#ifdef WANT_IPV6
+typedef union {
+	struct sockaddr sa;
+	struct sockaddr_in sin4;
+	struct sockaddr_in6 sin6;
+} ng_ipaddr_t;
+#else
+/* assume compiler can't deal with typedef struct {... */
+struct NG_IP_ADDR_DONTUSE {
+	struct sockaddr_in sin4;
+};
+typedef struct NG_IP_ADDR_DONTUSE ng_ipaddr_t;
+#endif
+
+
+static inline int
+ng_ipaddr_af(const ng_ipaddr_t *a)
+{
+#ifdef WANT_IPV6
+	return a->sa.sa_family;
+#else
+	assert(a->sin4.sin_family == 0 || a->sin4.sin_family == AF_INET);
+	return a->sin4.sin_family;
+#endif
+}
+
+
+static inline socklen_t
+ng_ipaddr_salen(const ng_ipaddr_t *a)
+{
+#ifdef WANT_IPV6
+	assert(a->sa.sa_family == AF_INET || a->sa.sa_family == AF_INET6);
+	if (a->sa.sa_family == AF_INET6)
+		return sizeof(a->sin6);
+#endif
+	assert(a->sin4.sin_family == AF_INET);
+	return sizeof(a->sin4);
+}
+
+
+static inline UINT16
+ng_ipaddr_getport(const ng_ipaddr_t *a)
+{
+#ifdef WANT_IPV6
+	int af = a->sa.sa_family;
+
+	assert(af == AF_INET || af == AF_INET6);
+
+	if (af == AF_INET6)
+		return ntohs(a->sin6.sin6_port);
+#endif /* WANT_IPV6 */
+	assert(a->sin4.sin_family == AF_INET);
+	return ntohs(a->sin4.sin_port);
+}
+
+/*
+ * init a ng_ipaddr_t object.
+ * @param addr: pointer to ng_ipaddr_t to initialize.
+ * @param ip_str: ip address in dotted-decimal (ipv4) or hexadecimal (ipv6) notation
+ * @param port: transport layer port number to use.
+ */
+GLOBAL bool ng_ipaddr_init PARAMS((ng_ipaddr_t *addr, const char *ip_str, UINT16 port));
+
+/* set sin4/sin6_port, depending on a->sa_family */
+GLOBAL void ng_ipaddr_setport PARAMS((ng_ipaddr_t *a, UINT16 port));
+
+/* return true if a and b have the same IP address. If a and b have different AF, return false. */
+GLOBAL bool ng_ipaddr_ipequal PARAMS((const ng_ipaddr_t *a, const ng_ipaddr_t *b));
+
+
+#ifdef WANT_IPV6
+/* convert struct sockaddr to string, returns pointer to static buffer */
+GLOBAL const char *ng_ipaddr_tostr PARAMS((const ng_ipaddr_t *addr));
+
+/* convert struct sockaddr to string. dest must be NG_INET_ADDRSTRLEN bytes long */
+GLOBAL bool ng_ipaddr_tostr_r PARAMS((const ng_ipaddr_t *addr, char *dest));
+#else
+static inline const char *
+ng_ipaddr_tostr(const ng_ipaddr_t *addr) { return inet_ntoa(addr->sin4.sin_addr); }
+
+static inline bool
+ng_ipaddr_tostr_r(const ng_ipaddr_t *addr, char *d)
+{
+	strlcpy(d, inet_ntoa(addr->sin4.sin_addr), NG_INET_ADDRSTRLEN);
+	return true;
+}
+#endif
+#endif
+
+/* -eof- */

+ 7 - 24
src/ngircd/Makefile.am

@@ -8,12 +8,12 @@
 # (at your option) any later version.
 # (at your option) any later version.
 # Please read the file COPYING, README and AUTHORS for more information.
 # Please read the file COPYING, README and AUTHORS for more information.
 #
 #
-# $Id: Makefile.am,v 1.49 2006/03/11 01:48:50 alex Exp $
+# $Id: Makefile.am,v 1.51 2008/02/26 22:04:17 fw Exp $
 #
 #
 
 
 AUTOMAKE_OPTIONS = ../portab/ansi2knr
 AUTOMAKE_OPTIONS = ../portab/ansi2knr
 
 
-INCLUDES = -I$(srcdir)/../portab -I$(srcdir)/../tool
+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
@@ -23,20 +23,20 @@ sbin_PROGRAMS = ngircd
 ngircd_SOURCES = ngircd.c array.c channel.c client.c conf.c conn.c conn-func.c \
 ngircd_SOURCES = ngircd.c array.c channel.c client.c conf.c conn.c conn-func.c \
 	conn-zip.c hash.c io.c irc.c irc-channel.c irc-info.c irc-login.c \
 	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 \
 	irc-mode.c irc-op.c irc-oper.c irc-server.c irc-write.c lists.c log.c \
-	match.c parse.c rendezvous.c resolve.c
+	match.c numeric.c parse.c rendezvous.c resolve.c
 
 
-ngircd_LDFLAGS = -L../portab -L../tool
+ngircd_LDFLAGS = -L../portab -L../tool -L../ipaddr
 
 
-ngircd_LDADD = -lngportab -lngtool
+ngircd_LDADD = -lngportab -lngtool -lngipaddr
 
 
 noinst_HEADERS = ngircd.h array.h channel.h client.h conf.h conn.h conn-func.h \
 noinst_HEADERS = ngircd.h array.h channel.h client.h conf.h conn.h conn-func.h \
 	conn-zip.h hash.h io.h irc.h irc-channel.h irc-info.h irc-login.h \
 	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 \
 	irc-mode.h irc-op.h irc-oper.h irc-server.h irc-write.h lists.h log.h \
-	match.h parse.h rendezvous.h resolve.h \
+	match.h numeric.h parse.h rendezvous.h resolve.h \
 	defines.h messages.h
 	defines.h messages.h
 
 
 clean-local:
 clean-local:
-	rm -f check-version check-help lint.out cvs-version.*
+	rm -f check-version check-help lint.out
 
 
 maintainer-clean-local:
 maintainer-clean-local:
 	rm -f Makefile Makefile.in
 	rm -f Makefile Makefile.in
@@ -77,23 +77,6 @@ lint:
 	 || echo "Result: no warnings found."; \
 	 || echo "Result: no warnings found."; \
 	echo; [ $$warnings -gt 0 ] && exit 1
 	echo; [ $$warnings -gt 0 ] && exit 1
 
 
-ngircd.c: cvs-version.h
-
-irc-login.c: cvs-version.h
-
-irc-info.c: cvs-version.h
-
-cvs-version.h: cvs-date
-
-cvs-date:
-	grep VERSION ../config.h | grep "CVS" \
-	 && echo "#define CVSDATE \"$$( grep "\$$Id" $(srcdir)/*.c \
-	    | $(AWK) "{ print \$$9 }" | sort | tail -1 \
-	    | sed -e "s/\//-/g" )\"" > cvs-version.new \
-	 || echo "" > cvs-version.new
-	diff cvs-version.h cvs-version.new 2>/dev/null \
-	 || cp cvs-version.new cvs-version.h
-
 TESTS = check-version check-help
 TESTS = check-version check-help
 
 
 # -eof-
 # -eof-

+ 14 - 28
src/ngircd/Makefile.in

@@ -24,7 +24,7 @@
 # (at your option) any later version.
 # (at your option) any later version.
 # Please read the file COPYING, README and AUTHORS for more information.
 # Please read the file COPYING, README and AUTHORS for more information.
 #
 #
-# $Id: Makefile.am,v 1.49 2006/03/11 01:48:50 alex Exp $
+# $Id: Makefile.am,v 1.51 2008/02/26 22:04:17 fw Exp $
 #
 #
 
 
 
 
@@ -76,8 +76,8 @@ am_ngircd_OBJECTS = ngircd$U.$(OBJEXT) array$U.$(OBJEXT) \
 	irc-login$U.$(OBJEXT) irc-mode$U.$(OBJEXT) irc-op$U.$(OBJEXT) \
 	irc-login$U.$(OBJEXT) irc-mode$U.$(OBJEXT) irc-op$U.$(OBJEXT) \
 	irc-oper$U.$(OBJEXT) irc-server$U.$(OBJEXT) \
 	irc-oper$U.$(OBJEXT) irc-server$U.$(OBJEXT) \
 	irc-write$U.$(OBJEXT) lists$U.$(OBJEXT) log$U.$(OBJEXT) \
 	irc-write$U.$(OBJEXT) lists$U.$(OBJEXT) log$U.$(OBJEXT) \
-	match$U.$(OBJEXT) parse$U.$(OBJEXT) rendezvous$U.$(OBJEXT) \
-	resolve$U.$(OBJEXT)
+	match$U.$(OBJEXT) numeric$U.$(OBJEXT) parse$U.$(OBJEXT) \
+	rendezvous$U.$(OBJEXT) resolve$U.$(OBJEXT)
 ngircd_OBJECTS = $(am_ngircd_OBJECTS)
 ngircd_OBJECTS = $(am_ngircd_OBJECTS)
 ngircd_DEPENDENCIES =
 ngircd_DEPENDENCIES =
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/src
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/src
@@ -181,21 +181,21 @@ target_cpu = @target_cpu@
 target_os = @target_os@
 target_os = @target_os@
 target_vendor = @target_vendor@
 target_vendor = @target_vendor@
 AUTOMAKE_OPTIONS = ../portab/ansi2knr
 AUTOMAKE_OPTIONS = ../portab/ansi2knr
-INCLUDES = -I$(srcdir)/../portab -I$(srcdir)/../tool
+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 client.c conf.c conn.c conn-func.c \
 ngircd_SOURCES = ngircd.c array.c channel.c client.c conf.c conn.c conn-func.c \
 	conn-zip.c hash.c io.c irc.c irc-channel.c irc-info.c irc-login.c \
 	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 \
 	irc-mode.c irc-op.c irc-oper.c irc-server.c irc-write.c lists.c log.c \
-	match.c parse.c rendezvous.c resolve.c
+	match.c numeric.c parse.c rendezvous.c resolve.c
 
 
-ngircd_LDFLAGS = -L../portab -L../tool
-ngircd_LDADD = -lngportab -lngtool
+ngircd_LDFLAGS = -L../portab -L../tool -L../ipaddr
+ngircd_LDADD = -lngportab -lngtool -lngipaddr
 noinst_HEADERS = ngircd.h array.h channel.h client.h conf.h conn.h conn-func.h \
 noinst_HEADERS = ngircd.h array.h channel.h client.h conf.h conn.h conn-func.h \
 	conn-zip.h hash.h io.h irc.h irc-channel.h irc-info.h irc-login.h \
 	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 \
 	irc-mode.h irc-op.h irc-oper.h irc-server.h irc-write.h lists.h log.h \
-	match.h parse.h rendezvous.h resolve.h \
+	match.h numeric.h parse.h rendezvous.h resolve.h \
 	defines.h messages.h
 	defines.h messages.h
 
 
 TESTS = check-version check-help
 TESTS = check-version check-help
@@ -292,6 +292,7 @@ mostlyclean-kr:
 @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)/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)/parse$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rendezvous$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rendezvous$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolve$U.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolve$U.Po@am__quote@
@@ -353,6 +354,8 @@ 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)
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ngircd.c; then echo $(srcdir)/ngircd.c; else echo ngircd.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ngircd.c; then echo $(srcdir)/ngircd.c; else echo ngircd.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+numeric_.c: numeric.c $(ANSI2KNR)
+	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/numeric.c; then echo $(srcdir)/numeric.c; else echo numeric.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 parse_.c: parse.c $(ANSI2KNR)
 parse_.c: parse.c $(ANSI2KNR)
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/parse.c; then echo $(srcdir)/parse.c; else echo parse.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/parse.c; then echo $(srcdir)/parse.c; else echo parse.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
 rendezvous_.c: rendezvous.c $(ANSI2KNR)
 rendezvous_.c: rendezvous.c $(ANSI2KNR)
@@ -365,8 +368,8 @@ hash_.$(OBJEXT) io_.$(OBJEXT) irc_.$(OBJEXT) irc-channel_.$(OBJEXT) \
 irc-info_.$(OBJEXT) irc-login_.$(OBJEXT) irc-mode_.$(OBJEXT) \
 irc-info_.$(OBJEXT) irc-login_.$(OBJEXT) irc-mode_.$(OBJEXT) \
 irc-op_.$(OBJEXT) irc-oper_.$(OBJEXT) irc-server_.$(OBJEXT) \
 irc-op_.$(OBJEXT) irc-oper_.$(OBJEXT) irc-server_.$(OBJEXT) \
 irc-write_.$(OBJEXT) lists_.$(OBJEXT) log_.$(OBJEXT) match_.$(OBJEXT) \
 irc-write_.$(OBJEXT) lists_.$(OBJEXT) log_.$(OBJEXT) match_.$(OBJEXT) \
-ngircd_.$(OBJEXT) parse_.$(OBJEXT) rendezvous_.$(OBJEXT) \
-resolve_.$(OBJEXT) : $(ANSI2KNR)
+ngircd_.$(OBJEXT) numeric_.$(OBJEXT) parse_.$(OBJEXT) \
+rendezvous_.$(OBJEXT) resolve_.$(OBJEXT) : $(ANSI2KNR)
 uninstall-info-am:
 uninstall-info-am:
 
 
 ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
 ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
@@ -614,7 +617,7 @@ uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS
 
 
 
 
 clean-local:
 clean-local:
-	rm -f check-version check-help lint.out cvs-version.*
+	rm -f check-version check-help lint.out
 
 
 maintainer-clean-local:
 maintainer-clean-local:
 	rm -f Makefile Makefile.in
 	rm -f Makefile Makefile.in
@@ -655,23 +658,6 @@ lint:
 	 || echo "Result: no warnings found."; \
 	 || echo "Result: no warnings found."; \
 	echo; [ $$warnings -gt 0 ] && exit 1
 	echo; [ $$warnings -gt 0 ] && exit 1
 
 
-ngircd.c: cvs-version.h
-
-irc-login.c: cvs-version.h
-
-irc-info.c: cvs-version.h
-
-cvs-version.h: cvs-date
-
-cvs-date:
-	grep VERSION ../config.h | grep "CVS" \
-	 && echo "#define CVSDATE \"$$( grep "\$$Id" $(srcdir)/*.c \
-	    | $(AWK) "{ print \$$9 }" | sort | tail -1 \
-	    | sed -e "s/\//-/g" )\"" > cvs-version.new \
-	 || echo "" > cvs-version.new
-	diff cvs-version.h cvs-version.new 2>/dev/null \
-	 || cp cvs-version.new cvs-version.h
-
 # -eof-
 # -eof-
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 # Otherwise a system limit (for SysV at least) may be exceeded.

+ 4 - 4
src/ngircd/array.c

@@ -12,7 +12,7 @@
 
 
 #include "array.h"
 #include "array.h"
 
 
-static char UNUSED id[] = "$Id: array.c,v 1.11.2.3 2007/04/03 22:08:52 fw Exp $";
+static char UNUSED id[] = "$Id: array.c,v 1.15 2007/11/18 15:05:35 alex Exp $";
 
 
 #include <assert.h>
 #include <assert.h>
 
 
@@ -28,9 +28,9 @@ static char UNUSED id[] = "$Id: array.c,v 1.11.2.3 2007/04/03 22:08:52 fw Exp $"
 
 
 #define array_UNUSABLE(x)	( !(x)->mem || (0 == (x)->allocated) )
 #define array_UNUSABLE(x)	( !(x)->mem || (0 == (x)->allocated) )
 
 
-#define ALIGN_32U(x)            (((x)+31U  ) & ~(31U))
-#define ALIGN_1024U(x)          (((x)+1023U) & ~(1023U))
-#define ALIGN_4096U(x)          (((x)+4095U) & ~(4095U))
+#define ALIGN_32U(x)            (((x)+(unsigned)31  ) & ~((unsigned)31))
+#define ALIGN_1024U(x)          (((x)+(unsigned)1023) & ~((unsigned)1023))
+#define ALIGN_4096U(x)          (((x)+(unsigned)4095) & ~((unsigned)4095))
 
 
 
 
 static bool
 static bool

+ 81 - 40
src/ngircd/channel.c

@@ -17,7 +17,7 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: channel.c,v 1.56.2.3 2007/04/03 22:08:52 fw Exp $";
+static char UNUSED id[] = "$Id: channel.c,v 1.65 2008/02/05 16:31:35 fw Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>
@@ -56,7 +56,7 @@ static CL2CHAN *My_Cl2Chan;
 
 
 static CL2CHAN *Get_Cl2Chan PARAMS(( CHANNEL *Chan, CLIENT *Client ));
 static CL2CHAN *Get_Cl2Chan PARAMS(( CHANNEL *Chan, CLIENT *Client ));
 static CL2CHAN *Add_Client PARAMS(( CHANNEL *Chan, CLIENT *Client ));
 static CL2CHAN *Add_Client PARAMS(( CHANNEL *Chan, CLIENT *Client ));
-static bool Remove_Client PARAMS(( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, char *Reason, bool InformServer ));
+static bool Remove_Client PARAMS(( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const char *Reason, bool InformServer ));
 static CL2CHAN *Get_First_Cl2Chan PARAMS(( CLIENT *Client, CHANNEL *Chan ));
 static CL2CHAN *Get_First_Cl2Chan PARAMS(( CLIENT *Client, CHANNEL *Chan ));
 static CL2CHAN *Get_Next_Cl2Chan PARAMS(( CL2CHAN *Start, CLIENT *Client, CHANNEL *Chan ));
 static CL2CHAN *Get_Next_Cl2Chan PARAMS(( CL2CHAN *Start, CLIENT *Client, CHANNEL *Chan ));
 static bool Delete_Channel PARAMS(( CHANNEL *Chan ));
 static bool Delete_Channel PARAMS(( CHANNEL *Chan ));
@@ -201,25 +201,38 @@ Channel_Join( CLIENT *Client, char *Name )
 } /* Channel_Join */
 } /* Channel_Join */
 
 
 
 
+/**
+ * Remove client from channel.
+ * This function lets a client lead a channel. First, the function checks
+ * if the channel exists and the client is a member of it and sends out
+ * appropriate error messages if not. The real work is done by the function
+ * Remove_Client().
+ */
 GLOBAL bool
 GLOBAL bool
-Channel_Part( CLIENT *Client, CLIENT *Origin, char *Name, char *Reason )
+Channel_Part(CLIENT * Client, CLIENT * Origin, const char *Name, const char *Reason)
 {
 {
 	CHANNEL *chan;
 	CHANNEL *chan;
 
 
-	assert( Client != NULL );
-	assert( Name != NULL );
-	assert( Reason != NULL );
+	assert(Client != NULL);
+	assert(Name != NULL);
+	assert(Reason != NULL);
 
 
-	chan = Channel_Search( Name );
-	if(( ! chan ) || ( ! Get_Cl2Chan( chan, Client )))
-	{
-		IRC_WriteStrClient( Client, ERR_NOSUCHCHANNEL_MSG, Client_ID( Client ), Name );
+	chan = Channel_Search(Name);
+	if (!chan) {
+		IRC_WriteStrClient(Client, ERR_NOSUCHCHANNEL_MSG,
+				   Client_ID(Client), Name);
+		return false;
+	}
+	if (!Get_Cl2Chan(chan, Client)) {
+		IRC_WriteStrClient(Client, ERR_NOTONCHANNEL_MSG,
+				   Client_ID(Client), Name);
 		return false;
 		return false;
 	}
 	}
 
 
-	/* User aus Channel entfernen */
-	if( ! Remove_Client( REMOVE_PART, chan, Client, Origin, Reason, true)) return false;
-	else return true;
+	if (!Remove_Client(REMOVE_PART, chan, Client, Origin, Reason, true))
+		return false;
+	else
+		return true;
 } /* Channel_Part */
 } /* Channel_Part */
 
 
 
 
@@ -388,7 +401,7 @@ Channel_Next( CHANNEL *Chan )
 
 
 
 
 GLOBAL CHANNEL *
 GLOBAL CHANNEL *
-Channel_Search( char *Name )
+Channel_Search( const char *Name )
 {
 {
 	/* Channel-Struktur suchen */
 	/* Channel-Struktur suchen */
 	
 	
@@ -602,7 +615,7 @@ Channel_IsMemberOf( CHANNEL *Chan, CLIENT *Client )
 
 
 	assert( Chan != NULL );
 	assert( Chan != NULL );
 	assert( Client != NULL );
 	assert( Client != NULL );
-	return Get_Cl2Chan(Chan, Client);
+	return Get_Cl2Chan(Chan, Client) != NULL;
 } /* Channel_IsMemberOf */
 } /* Channel_IsMemberOf */
 
 
 
 
@@ -695,38 +708,66 @@ Channel_SetMaxUsers(CHANNEL *Chan, unsigned long Count)
 } /* Channel_SetMaxUsers */
 } /* Channel_SetMaxUsers */
 
 
 
 
-GLOBAL bool
-Channel_Write( CHANNEL *Chan, CLIENT *From, CLIENT *Client, char *Text )
+static bool
+Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From)
 {
 {
-	bool is_member, has_voice, is_op, ok;
+	bool is_member, has_voice, is_op;
 
 
-	/* Okay, target is a channel */
 	is_member = has_voice = is_op = false;
 	is_member = has_voice = is_op = false;
-	if( Channel_IsMemberOf( Chan, From ))
-	{
+
+	if (Channel_IsMemberOf(Chan, From)) {
 		is_member = true;
 		is_member = true;
-		if( strchr( Channel_UserModes( Chan, From ), 'v' )) has_voice = true;
-		if( strchr( Channel_UserModes( Chan, From ), 'o' )) is_op = true;
+		if (strchr(Channel_UserModes(Chan, From), 'v'))
+			has_voice = true;
+		if (strchr(Channel_UserModes(Chan, From), 'o'))
+			is_op = true;
 	}
 	}
 
 
-	/* Is the client allowed to write to channel? */
-	ok = true;
-	if( strchr( Channel_Modes( Chan ), 'n' ) && ( ! is_member )) ok = false;
-	if( strchr( Channel_Modes( Chan ), 'm' ) && ( ! is_op ) && ( ! has_voice )) ok = false;
+	/*
+	 * Is the client allowed to write to channel?
+	 *
+	 * If channel mode n set: non-members cannot send to channel.
+	 * If channel mode m set: need voice.
+	 */
+	if (strchr(Channel_Modes(Chan), 'n') && !is_member)
+		return false;
 
 
-	/* Is the client banned? */
-	if( Lists_Check(&Chan->list_bans, From))
-	{
-		/* Client is banned, but is he channel operator or has voice? */
-		if(( ! has_voice ) && ( ! is_op )) ok = false;
-	}
+	if (is_op || has_voice)
+		return true;
+
+	if (strchr(Channel_Modes(Chan), 'm'))
+		return false;
+
+	return !Lists_Check(&Chan->list_bans, From);
+}
 
 
-	if( ! ok ) return IRC_WriteStrClient( From, ERR_CANNOTSENDTOCHAN_MSG, Client_ID( From ), Channel_Name( Chan ));
 
 
-	/* Send text */
-	if( Client_Conn( From ) > NONE ) Conn_UpdateIdle( Client_Conn( From ));
-	return IRC_WriteStrChannelPrefix( Client, Chan, From, true, "PRIVMSG %s :%s", Channel_Name( Chan ), Text );
-} /* Channel_Write */
+GLOBAL bool
+Channel_Write(CHANNEL *Chan, CLIENT *From, CLIENT *Client, const char *Text)
+{
+	if (!Can_Send_To_Channel(Chan, From))
+		return IRC_WriteStrClient(From, ERR_CANNOTSENDTOCHAN_MSG, Client_ID(From), Channel_Name(Chan));
+
+	if (Client_Conn(From) > NONE)
+		Conn_UpdateIdle(Client_Conn(From));
+
+	return IRC_WriteStrChannelPrefix(Client, Chan, From, true,
+			"PRIVMSG %s :%s", Channel_Name(Chan), Text);
+}
+
+
+GLOBAL bool
+Channel_Notice(CHANNEL *Chan, CLIENT *From, CLIENT *Client, const char *Text)
+{
+	if (!Can_Send_To_Channel(Chan, From))
+		return true; /* no error, see RFC 2812 */
+
+	if (Client_Conn(From) > NONE)
+		Conn_UpdateIdle(Client_Conn(From));
+
+	return IRC_WriteStrChannelPrefix(Client, Chan, From, true,
+			"NOTICE %s :%s", Channel_Name(Chan), Text);
+}
 
 
 
 
 GLOBAL CHANNEL *
 GLOBAL CHANNEL *
@@ -801,7 +842,7 @@ Add_Client( CHANNEL *Chan, CLIENT *Client )
 
 
 
 
 static bool
 static bool
-Remove_Client( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, char *Reason, bool InformServer )
+Remove_Client( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const char *Reason, bool InformServer )
 {
 {
 	CL2CHAN *cl2chan, *last_cl2chan;
 	CL2CHAN *cl2chan, *last_cl2chan;
 	CHANNEL *c;
 	CHANNEL *c;
@@ -875,7 +916,7 @@ Remove_Client( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, char *Re
 	{
 	{
 		if( ! Get_First_Cl2Chan( NULL, Chan )) Delete_Channel( Chan );
 		if( ! Get_First_Cl2Chan( NULL, Chan )) Delete_Channel( Chan );
 	}
 	}
-		
+
 	return true;
 	return true;
 } /* Remove_Client */
 } /* Remove_Client */
 
 

+ 5 - 4
src/ngircd/channel.h

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: channel.h,v 1.29.2.2 2007/04/03 20:23:31 fw Exp $
+ * $Id: channel.h,v 1.35 2008/02/05 16:31:35 fw Exp $
  *
  *
  * Channel management (header)
  * Channel management (header)
  */
  */
@@ -64,7 +64,7 @@ GLOBAL void Channel_InitPredefined PARAMS((  void ));
 GLOBAL void Channel_Exit PARAMS(( void ));
 GLOBAL void Channel_Exit PARAMS(( void ));
 
 
 GLOBAL bool Channel_Join PARAMS(( CLIENT *Client, char *Name ));
 GLOBAL bool Channel_Join PARAMS(( CLIENT *Client, char *Name ));
-GLOBAL bool Channel_Part PARAMS(( CLIENT *Client, CLIENT *Origin, char *Name, char *Reason ));
+GLOBAL bool Channel_Part PARAMS(( CLIENT *Client, CLIENT *Origin, const char *Name, const char *Reason ));
 
 
 GLOBAL void Channel_Quit PARAMS(( CLIENT *Client, char *Reason ));
 GLOBAL void Channel_Quit PARAMS(( CLIENT *Client, char *Reason ));
 
 
@@ -85,7 +85,7 @@ GLOBAL void Channel_SetModes PARAMS(( CHANNEL *Chan, char *Modes ));
 GLOBAL void Channel_SetKey PARAMS(( CHANNEL *Chan, char *Key ));
 GLOBAL void Channel_SetKey PARAMS(( CHANNEL *Chan, char *Key ));
 GLOBAL void Channel_SetMaxUsers PARAMS(( CHANNEL *Chan, unsigned long Count ));
 GLOBAL void Channel_SetMaxUsers PARAMS(( CHANNEL *Chan, unsigned long Count ));
 
 
-GLOBAL CHANNEL *Channel_Search PARAMS(( char *Name ));
+GLOBAL CHANNEL *Channel_Search PARAMS(( const char *Name ));
 
 
 GLOBAL CHANNEL *Channel_First PARAMS(( void ));
 GLOBAL CHANNEL *Channel_First PARAMS(( void ));
 GLOBAL CHANNEL *Channel_Next PARAMS(( CHANNEL *Chan ));
 GLOBAL CHANNEL *Channel_Next PARAMS(( CHANNEL *Chan ));
@@ -109,7 +109,8 @@ GLOBAL char *Channel_UserModes PARAMS(( CHANNEL *Chan, CLIENT *Client ));
 
 
 GLOBAL bool Channel_IsMemberOf PARAMS(( CHANNEL *Chan, CLIENT *Client ));
 GLOBAL bool Channel_IsMemberOf PARAMS(( CHANNEL *Chan, CLIENT *Client ));
 
 
-GLOBAL bool Channel_Write PARAMS(( CHANNEL *Chan, CLIENT *From, CLIENT *Client, char *Text ));
+GLOBAL bool Channel_Write PARAMS(( CHANNEL *Chan, CLIENT *From, CLIENT *Client, const char *Text ));
+GLOBAL bool Channel_Notice PARAMS(( CHANNEL *Chan, CLIENT *From, CLIENT *Client, const char *Text));
 
 
 GLOBAL CHANNEL *Channel_Create PARAMS(( char *Name ));
 GLOBAL CHANNEL *Channel_Create PARAMS(( char *Name ));
 
 

+ 9 - 9
src/ngircd/client.c

@@ -17,7 +17,7 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: client.c,v 1.91.2.2 2007/04/03 22:08:52 fw Exp $";
+static char UNUSED id[] = "$Id: client.c,v 1.98 2008/04/04 19:30:01 fw Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>
@@ -55,6 +55,7 @@ static char GetID_Buffer[GETID_LEN];
 
 
 static WHOWAS My_Whowas[MAX_WHOWAS];
 static WHOWAS My_Whowas[MAX_WHOWAS];
 static int Last_Whowas = -1;
 static int Last_Whowas = -1;
+static long Max_Users, My_Max_Users;
 
 
 
 
 static unsigned long Count PARAMS(( CLIENT_TYPE Type ));
 static unsigned long Count PARAMS(( CLIENT_TYPE Type ));
@@ -69,9 +70,6 @@ static CLIENT *Init_New_Client PARAMS((CONN_ID Idx, CLIENT *Introducer,
  char *Info, int Hops, int Token, char *Modes, bool Idented));
  char *Info, int Hops, int Token, char *Modes, bool Idented));
 
 
 
 
-long Max_Users = 0, My_Max_Users = 0;
-
-
 GLOBAL void
 GLOBAL void
 Client_Init( void )
 Client_Init( void )
 {
 {
@@ -94,9 +92,10 @@ Client_Init( void )
 	This_Server->hops = 0;
 	This_Server->hops = 0;
 
 
 	gethostname( This_Server->host, CLIENT_HOST_LEN );
 	gethostname( This_Server->host, CLIENT_HOST_LEN );
-	h = gethostbyname( This_Server->host );
-	if( h ) strlcpy( This_Server->host, h->h_name, sizeof( This_Server->host ));
-
+	if (!Conf_NoDNS) {
+		h = gethostbyname( This_Server->host );
+		if (h) strlcpy(This_Server->host, h->h_name, sizeof(This_Server->host));
+	}
 	Client_SetID( This_Server, Conf_ServerName );
 	Client_SetID( This_Server, Conf_ServerName );
 	Client_SetInfo( This_Server, Conf_ServerInfo );
 	Client_SetInfo( This_Server, Conf_ServerInfo );
 
 
@@ -608,7 +607,8 @@ Client_ID( CLIENT *Client )
 	assert( Client != NULL );
 	assert( Client != NULL );
 
 
 #ifdef DEBUG
 #ifdef DEBUG
-	if( Client->type == CLIENT_USER ) assert( strlen( Client->id ) < CLIENT_NICK_LEN );
+	if(Client->type == CLIENT_USER)
+		assert(strlen(Client->id) < Conf_MaxNickLength);
 #endif
 #endif
 						   
 						   
 	if( Client->id[0] ) return Client->id;
 	if( Client->id[0] ) return Client->id;
@@ -951,7 +951,7 @@ Client_IsValidNick( const char *Nick )
 
 
 	if( Nick[0] == '#' ) return false;
 	if( Nick[0] == '#' ) return false;
 	if( strchr( goodchars, Nick[0] )) return false;
 	if( strchr( goodchars, Nick[0] )) return false;
-	if( strlen( Nick ) >= CLIENT_NICK_LEN ) return false;
+	if( strlen( Nick ) >= Conf_MaxNickLength) return false;
 
 
 	ptr = Nick;
 	ptr = Nick;
 	while( *ptr )
 	while( *ptr )

+ 1 - 1
src/ngircd/client.h

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: client.h,v 1.42.2.3 2007/04/03 22:08:52 fw Exp $
+ * $Id: client.h,v 1.46 2007/01/23 16:07:19 alex Exp $
  *
  *
  * Client management (header)
  * Client management (header)
  */
  */

+ 217 - 36
src/ngircd/conf.c

@@ -14,7 +14,7 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: conf.c,v 1.92.2.4 2007/04/03 22:08:52 fw Exp $";
+static char UNUSED id[] = "$Id: conf.c,v 1.105 2008/03/18 20:12:47 fw Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>
@@ -56,9 +56,21 @@ static CONF_SERVER New_Server;
 static int New_Server_Idx;
 static int New_Server_Idx;
 
 
 
 
+#ifdef WANT_IPV6
+/*
+ * these options appeared in ngircd 0.12; they are here
+ * for backwards compatibility. They should be removed
+ * in the future. Instead of setting these options,
+ * the "Listen" option should be set accordingly.
+ */
+static bool Conf_ListenIPv6;
+static bool Conf_ListenIPv4;
+#endif
+
+
 static void Set_Defaults PARAMS(( bool InitServers ));
 static void Set_Defaults PARAMS(( bool InitServers ));
-static void Read_Config PARAMS(( void ));
-static void Validate_Config PARAMS(( bool TestOnly, bool Rehash ));
+static bool Read_Config PARAMS(( bool ngircd_starting ));
+static bool Validate_Config PARAMS(( bool TestOnly, bool Rehash ));
 
 
 static void Handle_GLOBAL PARAMS(( int Line, char *Var, char *Arg ));
 static void Handle_GLOBAL PARAMS(( int Line, char *Var, char *Arg ));
 static void Handle_OPERATOR PARAMS(( int Line, char *Var, char *Arg ));
 static void Handle_OPERATOR PARAMS(( int Line, char *Var, char *Arg ));
@@ -134,24 +146,33 @@ ports_parse(array *a, int Line, char *Arg)
 GLOBAL void
 GLOBAL void
 Conf_Init( void )
 Conf_Init( void )
 {
 {
-	Set_Defaults( true );
-	Read_Config( );
+	Read_Config( true );
 	Validate_Config(false, false);
 	Validate_Config(false, false);
 } /* Config_Init */
 } /* Config_Init */
 
 
 
 
-GLOBAL void
+GLOBAL bool
 Conf_Rehash( void )
 Conf_Rehash( void )
 {
 {
-	Set_Defaults( false );
-	Read_Config( );
+	if (!Read_Config(false))
+		return false;
 	Validate_Config(false, true);
 	Validate_Config(false, true);
 
 
 	/* Update CLIENT structure of local server */
 	/* Update CLIENT structure of local server */
 	Client_SetInfo(Client_ThisServer(), Conf_ServerInfo);
 	Client_SetInfo(Client_ThisServer(), Conf_ServerInfo);
+	return true;
 } /* Config_Rehash */
 } /* Config_Rehash */
 
 
 
 
+static const char*
+yesno_to_str(int boolean_value)
+{
+	if (boolean_value)
+		return "yes";
+	return "no";
+}
+
+
 GLOBAL int
 GLOBAL int
 Conf_Test( void )
 Conf_Test( void )
 {
 {
@@ -161,12 +182,14 @@ Conf_Test( void )
 	struct group *grp;
 	struct group *grp;
 	unsigned int i;
 	unsigned int i;
 	char *topic;
 	char *topic;
+	bool config_valid;
 
 
 	Use_Log = false;
 	Use_Log = false;
-	Set_Defaults( true );
 
 
-	Read_Config( );
-	Validate_Config(true, false);
+	if (! Read_Config(true))
+		return 1;
+
+	config_valid = Validate_Config(true, false);
 
 
 	/* If stdin and stdout ("you can read our nice message and we can
 	/* If stdin and stdout ("you can read our nice message and we can
 	 * read in your keypress") are valid tty's, wait for a key: */
 	 * read in your keypress") are valid tty's, wait for a key: */
@@ -191,8 +214,7 @@ Conf_Test( void )
 	fputs("  Ports = ", stdout);
 	fputs("  Ports = ", stdout);
 
 
 	ports_puts(&Conf_ListenPorts);
 	ports_puts(&Conf_ListenPorts);
-
-	printf( "  Listen = %s\n", Conf_ListenAddress );
+	printf("  Listen = %s\n", Conf_ListenAddress);
 	pwd = getpwuid( Conf_UID );
 	pwd = getpwuid( Conf_UID );
 	if( pwd ) printf( "  ServerUID = %s\n", pwd->pw_name );
 	if( pwd ) printf( "  ServerUID = %s\n", pwd->pw_name );
 	else printf( "  ServerUID = %ld\n", (long)Conf_UID );
 	else printf( "  ServerUID = %ld\n", (long)Conf_UID );
@@ -202,12 +224,24 @@ Conf_Test( void )
 	printf( "  PingTimeout = %d\n", Conf_PingTimeout );
 	printf( "  PingTimeout = %d\n", Conf_PingTimeout );
 	printf( "  PongTimeout = %d\n", Conf_PongTimeout );
 	printf( "  PongTimeout = %d\n", Conf_PongTimeout );
 	printf( "  ConnectRetry = %d\n", Conf_ConnectRetry );
 	printf( "  ConnectRetry = %d\n", Conf_ConnectRetry );
-	printf( "  OperCanUseMode = %s\n", Conf_OperCanMode == true ? "yes" : "no" );
-	printf( "  OperServerMode = %s\n", Conf_OperServerMode == true? "yes" : "no" );
-	printf( "  PredefChannelsOnly = %s\n", Conf_PredefChannelsOnly == true ? "yes" : "no" );
-	printf( "  MaxConnections = %ld\n", Conf_MaxConnections>0 ? Conf_MaxConnections : -1);
-	printf( "  MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP>0 ? Conf_MaxConnectionsIP : -1);
-	printf( "  MaxJoins = %d\n\n", Conf_MaxJoins>0 ? Conf_MaxJoins : -1);
+	printf( "  OperCanUseMode = %s\n", yesno_to_str(Conf_OperCanMode));
+	printf( "  OperServerMode = %s\n", yesno_to_str(Conf_OperServerMode));
+	printf( "  PredefChannelsOnly = %s\n", yesno_to_str(Conf_PredefChannelsOnly));
+	printf( "  NoDNS = %s\n", yesno_to_str(Conf_NoDNS));
+
+#ifdef WANT_IPV6
+	/* both are deprecated, only mention them if their default value changed. */
+	if (!Conf_ListenIPv6)
+		puts("  ListenIPv6 = no");
+	if (!Conf_ListenIPv4)
+		puts("  ListenIPv4 = no");
+	printf("  ConnectIPv4 = %s\n", yesno_to_str(Conf_ConnectIPv6));
+	printf("  ConnectIPv6 = %s\n", yesno_to_str(Conf_ConnectIPv4));
+#endif
+	printf( "  MaxConnections = %ld\n", Conf_MaxConnections);
+	printf( "  MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP);
+	printf( "  MaxJoins = %d\n", Conf_MaxJoins>0 ? Conf_MaxJoins : -1);
+	printf( "  MaxNickLength = %u\n\n", Conf_MaxNickLength - 1);
 
 
 	for( i = 0; i < Conf_Oper_Count; i++ ) {
 	for( i = 0; i < Conf_Oper_Count; i++ ) {
 		if( ! Conf_Oper[i].name[0] ) continue;
 		if( ! Conf_Oper[i].name[0] ) continue;
@@ -230,7 +264,8 @@ Conf_Test( void )
 		printf( "  Port = %u\n", (unsigned int)Conf_Server[i].port );
 		printf( "  Port = %u\n", (unsigned int)Conf_Server[i].port );
 		printf( "  MyPassword = %s\n", Conf_Server[i].pwd_in );
 		printf( "  MyPassword = %s\n", Conf_Server[i].pwd_in );
 		printf( "  PeerPassword = %s\n", Conf_Server[i].pwd_out );
 		printf( "  PeerPassword = %s\n", Conf_Server[i].pwd_out );
-		printf( "  Group = %d\n\n", Conf_Server[i].group );
+		printf( "  Group = %d\n", Conf_Server[i].group );
+		printf( "  Passive = %s\n\n", Conf_Server[i].flags & CONF_SFLAG_DISABLED ? "yes" : "no");
 	}
 	}
 
 
 	for( i = 0; i < Conf_Channel_Count; i++ ) {
 	for( i = 0; i < Conf_Channel_Count; i++ ) {
@@ -247,7 +282,7 @@ Conf_Test( void )
 		printf( "  Topic = %s\n\n", topic ? topic : "");
 		printf( "  Topic = %s\n\n", topic ? topic : "");
 	}
 	}
 
 
-	return 0;
+	return (config_valid ? 0 : 1);
 } /* Conf_Test */
 } /* Conf_Test */
 
 
 
 
@@ -337,6 +372,24 @@ Conf_EnableServer( char *Name, UINT16 Port )
 
 
 
 
 GLOBAL bool
 GLOBAL bool
+Conf_EnablePassiveServer(const char *Name)
+{
+	/* Enable specified server */
+	int i;
+
+	assert( Name != NULL );
+	for (i = 0; i < MAX_SERVERS; i++) {
+		if ((strcasecmp( Conf_Server[i].name, Name ) == 0) && (Conf_Server[i].port > 0)) {
+			/* BINGO! Enable server */
+			Conf_Server[i].flags &= ~CONF_SFLAG_DISABLED;
+			return true;
+		}
+	}
+	return false;
+} /* Conf_EnablePassiveServer */
+
+
+GLOBAL bool
 Conf_DisableServer( char *Name )
 Conf_DisableServer( char *Name )
 {
 {
 	/* Enable specified server and adjust port */
 	/* Enable specified server and adjust port */
@@ -412,8 +465,8 @@ Set_Defaults( bool InitServers )
 
 
 	strlcpy( Conf_PidFile, PID_FILE, sizeof( Conf_PidFile ));
 	strlcpy( Conf_PidFile, PID_FILE, sizeof( Conf_PidFile ));
 
 
-	strcpy( Conf_ListenAddress, "" );
-
+	free(Conf_ListenAddress);
+	Conf_ListenAddress = NULL;
 	Conf_UID = Conf_GID = 0;
 	Conf_UID = Conf_GID = 0;
 
 
 	Conf_PingTimeout = 120;
 	Conf_PingTimeout = 120;
@@ -425,20 +478,28 @@ Set_Defaults( bool InitServers )
 	Conf_Channel_Count = 0;
 	Conf_Channel_Count = 0;
 
 
 	Conf_OperCanMode = false;
 	Conf_OperCanMode = false;
+	Conf_NoDNS = false;
 	Conf_PredefChannelsOnly = false;
 	Conf_PredefChannelsOnly = false;
 	Conf_OperServerMode = false;
 	Conf_OperServerMode = false;
 
 
-	Conf_MaxConnections = -1;
+	Conf_ConnectIPv4 = true;
+	Conf_ConnectIPv6 = true;
+#ifdef WANT_IPV6
+	Conf_ListenIPv4 = true;
+	Conf_ListenIPv6 = true;
+#endif
+	Conf_MaxConnections = 0;
 	Conf_MaxConnectionsIP = 5;
 	Conf_MaxConnectionsIP = 5;
 	Conf_MaxJoins = 10;
 	Conf_MaxJoins = 10;
+	Conf_MaxNickLength = CLIENT_NICK_LEN_DEFAULT;
 
 
 	/* Initialize server configuration structures */
 	/* Initialize server configuration structures */
 	if( InitServers ) for( i = 0; i < MAX_SERVERS; Init_Server_Struct( &Conf_Server[i++] ));
 	if( InitServers ) for( i = 0; i < MAX_SERVERS; Init_Server_Struct( &Conf_Server[i++] ));
 } /* Set_Defaults */
 } /* Set_Defaults */
 
 
 
 
-static void
-Read_Config( void )
+static bool
+Read_Config( bool ngircd_starting )
 {
 {
 	/* Read configuration file. */
 	/* Read configuration file. */
 
 
@@ -453,10 +514,14 @@ Read_Config( void )
 		/* No configuration file found! */
 		/* No configuration file found! */
 		Config_Error( LOG_ALERT, "Can't read configuration \"%s\": %s",
 		Config_Error( LOG_ALERT, "Can't read configuration \"%s\": %s",
 					NGIRCd_ConfFile, strerror( errno ));
 					NGIRCd_ConfFile, strerror( errno ));
+		if (!ngircd_starting)
+			return false;
 		Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
 		Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
 		exit( 1 );
 		exit( 1 );
 	}
 	}
 
 
+	Set_Defaults( ngircd_starting );
+
 	Config_Error( LOG_INFO, "Reading configuration from \"%s\" ...", NGIRCd_ConfFile );
 	Config_Error( LOG_INFO, "Reading configuration from \"%s\" ...", NGIRCd_ConfFile );
 
 
 	/* Clean up server configuration structure: mark all already
 	/* Clean up server configuration structure: mark all already
@@ -603,6 +668,24 @@ Read_Config( void )
 			exit( 1 );
 			exit( 1 );
 		}
 		}
 	}
 	}
+
+	if (!Conf_ListenAddress) {
+		/* no Listen addresses configured, use default */
+#ifdef WANT_IPV6
+		/* Conf_ListenIPv6/4 should no longer be used */
+		if (Conf_ListenIPv6 && Conf_ListenIPv4)
+			Conf_ListenAddress = strdup_warn("::,0.0.0.0");
+		else if (Conf_ListenIPv6)
+			Conf_ListenAddress = strdup_warn("::");
+		else
+#endif
+		Conf_ListenAddress = strdup_warn("0.0.0.0");
+	}
+	if (!Conf_ListenAddress) {
+		Config_Error(LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME);
+		exit(1);
+	}
+	return true;
 } /* Read_Config */
 } /* Read_Config */
 
 
 
 
@@ -617,6 +700,27 @@ Check_ArgIsTrue( const char *Arg )
 } /* Check_ArgIsTrue */
 } /* Check_ArgIsTrue */
 
 
 
 
+static unsigned int Handle_MaxNickLength(int Line, const char *Arg)
+{
+	unsigned new;
+
+	new = (unsigned) atoi(Arg) + 1;
+	if (new > CLIENT_NICK_LEN) {
+		Config_Error(LOG_WARNING,
+			     "%s, line %d: Value of \"MaxNickLength\" exceeds %u!",
+			     NGIRCd_ConfFile, Line, CLIENT_NICK_LEN - 1);
+		return CLIENT_NICK_LEN;
+	}
+	if (new < 2) {
+		Config_Error(LOG_WARNING,
+			     "%s, line %d: Value of \"MaxNickLength\" must be at least 1!",
+			     NGIRCd_ConfFile, Line);
+		return 2;
+	}
+	return new;
+} /* Handle_MaxNickLength */
+
+
 static void
 static void
 Handle_GLOBAL( int Line, char *Var, char *Arg )
 Handle_GLOBAL( int Line, char *Var, char *Arg )
 {
 {
@@ -764,6 +868,46 @@ Handle_GLOBAL( int Line, char *Var, char *Arg )
 		Conf_PredefChannelsOnly = Check_ArgIsTrue( Arg );
 		Conf_PredefChannelsOnly = Check_ArgIsTrue( Arg );
 		return;
 		return;
 	}
 	}
+	if( strcasecmp( Var, "NoDNS" ) == 0 ) {
+		/* don't do reverse dns lookups when clients connect? */
+		Conf_NoDNS = Check_ArgIsTrue( Arg );
+		return;
+	}
+#ifdef WANT_IPV6
+	/* the default setting for all the WANT_IPV6 special options is 'true' */
+	if (strcasecmp(Var, "ListenIPv6") == 0) { /* DEPRECATED, option appeared in 0.12.0 */
+		/*
+		 * listen on ipv6 sockets, if available?
+		 * Deprecated use "Listen = 0.0.0.0" (or, rather, do not list "::")
+		 */
+		Conf_ListenIPv6 = Check_ArgIsTrue( Arg );
+		Config_Error(LOG_WARNING, "%s, line %d: %s=%s is deprecated, %sinclude '::' in \"Listen =\" option instead",
+				NGIRCd_ConfFile, Line, Var, yesno_to_str(Conf_ListenIPv6), Conf_ListenIPv6 ? " ":"do not ");
+		return;
+	}
+	if (strcasecmp(Var, "ListenIPv4") == 0) { /* DEPRECATED, option appeared in 0.12.0 */
+		/*
+		 * listen on ipv4 sockets, if available?
+		 * this allows "ipv6-only" setups
+		 * Deprecated use "Listen = ::" (or, rather, do not list "0.0.0.0")
+		 */
+		Conf_ListenIPv4 = Check_ArgIsTrue( Arg );
+		Config_Error(LOG_WARNING, "%s, line %d: %s=%s is deprecated, %sinclude '0.0.0.0' in \"Listen =\" option instead",
+				NGIRCd_ConfFile, Line, Var, yesno_to_str(Conf_ListenIPv4), Conf_ListenIPv4 ? " ":"do not ");
+		return;
+	}
+	if( strcasecmp( Var, "ConnectIPv6" ) == 0 ) {
+		/* connect to other hosts using ipv6, if they have an AAAA record? */
+		Conf_ConnectIPv6 = Check_ArgIsTrue( Arg );
+		return;
+	}
+	if( strcasecmp( Var, "ConnectIPv4" ) == 0 ) {
+		/* connect to other hosts using ipv4.
+		 * again, this can be used for ipv6-only setups */
+		Conf_ConnectIPv4 = Check_ArgIsTrue( Arg );
+		return;
+	}
+#endif
 	if( strcasecmp( Var, "OperCanUseMode" ) == 0 ) {
 	if( strcasecmp( Var, "OperCanUseMode" ) == 0 ) {
 		/* Are IRC operators allowed to use MODE in channels they aren't Op in? */
 		/* Are IRC operators allowed to use MODE in channels they aren't Op in? */
 		Conf_OperCanMode = Check_ArgIsTrue( Arg );
 		Conf_OperCanMode = Check_ArgIsTrue( Arg );
@@ -775,7 +919,7 @@ Handle_GLOBAL( int Line, char *Var, char *Arg )
 		return;
 		return;
 	}
 	}
 	if( strcasecmp( Var, "MaxConnections" ) == 0 ) {
 	if( strcasecmp( Var, "MaxConnections" ) == 0 ) {
-		/* Maximum number of connections. Values <= 0 are equal to "no limit". */
+		/* Maximum number of connections. 0 -> "no limit". */
 #ifdef HAVE_ISDIGIT
 #ifdef HAVE_ISDIGIT
 		if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var);
 		if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var);
 		else
 		else
@@ -784,7 +928,7 @@ Handle_GLOBAL( int Line, char *Var, char *Arg )
 		return;
 		return;
 	}
 	}
 	if( strcasecmp( Var, "MaxConnectionsIP" ) == 0 ) {
 	if( strcasecmp( Var, "MaxConnectionsIP" ) == 0 ) {
-		/* Maximum number of simultaneous connections from one IP. Values <= 0 -> "no limit" */
+		/* Maximum number of simultaneous connections from one IP. 0 -> "no limit" */
 #ifdef HAVE_ISDIGIT
 #ifdef HAVE_ISDIGIT
 		if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
 		if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
 		else
 		else
@@ -793,7 +937,7 @@ Handle_GLOBAL( int Line, char *Var, char *Arg )
 		return;
 		return;
 	}
 	}
 	if( strcasecmp( Var, "MaxJoins" ) == 0 ) {
 	if( strcasecmp( Var, "MaxJoins" ) == 0 ) {
-		/* Maximum number of channels a user can join. Values <= 0 are equal to "no limit". */
+		/* Maximum number of channels a user can join. 0 -> "no limit". */
 #ifdef HAVE_ISDIGIT
 #ifdef HAVE_ISDIGIT
 		if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
 		if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
 		else
 		else
@@ -801,16 +945,33 @@ Handle_GLOBAL( int Line, char *Var, char *Arg )
 		Conf_MaxJoins = atoi( Arg );
 		Conf_MaxJoins = atoi( Arg );
 		return;
 		return;
 	}
 	}
+	if( strcasecmp( Var, "MaxNickLength" ) == 0 ) {
+		/* Maximum length of a nick name; must be same on all servers
+		 * within the IRC network! */
+		Conf_MaxNickLength = Handle_MaxNickLength(Line, Arg);
+		return;
+	}
+
 	if( strcasecmp( Var, "Listen" ) == 0 ) {
 	if( strcasecmp( Var, "Listen" ) == 0 ) {
 		/* IP-Address to bind sockets */
 		/* IP-Address to bind sockets */
-		len = strlcpy( Conf_ListenAddress, Arg, sizeof( Conf_ListenAddress ));
-		if (len >= sizeof( Conf_ListenAddress ))
-			Config_Error_TooLong( Line, Var );
+		if (Conf_ListenAddress) {
+			Config_Error(LOG_ERR, "Multiple Listen= options, ignoring: %s", Arg);
+			return;
+		}
+		Conf_ListenAddress = strdup_warn(Arg);
+		/*
+		 * if allocation fails, we're in trouble:
+		 * we cannot ignore the error -- otherwise ngircd
+		 * would listen on all interfaces.
+		 */
+		if (!Conf_ListenAddress) {
+			Config_Error(LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME);
+			exit(1);
+		}
 		return;
 		return;
 	}
 	}
-
-	Config_Error( LOG_ERR, "%s, line %d (section \"Global\"): Unknown variable \"%s\"!",
-								NGIRCd_ConfFile, Line, Var );
+	Config_Error(LOG_ERR, "%s, line %d (section \"Global\"): Unknown variable \"%s\"!",
+								NGIRCd_ConfFile, Line, Var);
 } /* Handle_GLOBAL */
 } /* Handle_GLOBAL */
 
 
 
 
@@ -881,6 +1042,14 @@ Handle_SERVER( int Line, char *Var, char *Arg )
 			Config_Error_TooLong( Line, Var );
 			Config_Error_TooLong( Line, Var );
 		return;
 		return;
 	}
 	}
+	if (strcasecmp(Var, "Bind") == 0) {
+		if (ng_ipaddr_init(&New_Server.bind_addr, Arg, 0))
+			return;
+
+		Config_Error(LOG_ERR, "%s, line %d (section \"Server\"): Can't parse IP address \"%s\"",
+				NGIRCd_ConfFile, Line, Arg);
+		return;
+	}
 	if( strcasecmp( Var, "MyPassword" ) == 0 ) {
 	if( strcasecmp( Var, "MyPassword" ) == 0 ) {
 		/* Password of this server which is sent to the peer */
 		/* Password of this server which is sent to the peer */
 		if (*Arg == ':') {
 		if (*Arg == ':') {
@@ -920,6 +1089,11 @@ Handle_SERVER( int Line, char *Var, char *Arg )
 		New_Server.group = atoi( Arg );
 		New_Server.group = atoi( Arg );
 		return;
 		return;
 	}
 	}
+	if( strcasecmp( Var, "Passive" ) == 0 ) {
+		if (Check_ArgIsTrue(Arg))
+			New_Server.flags |= CONF_SFLAG_DISABLED;
+		return;
+	}
 	
 	
 	Config_Error( LOG_ERR, "%s, line %d (section \"Server\"): Unknown variable \"%s\"!",
 	Config_Error( LOG_ERR, "%s, line %d (section \"Server\"): Unknown variable \"%s\"!",
 								NGIRCd_ConfFile, Line, Var );
 								NGIRCd_ConfFile, Line, Var );
@@ -993,7 +1167,7 @@ Handle_CHANNEL( int Line, char *Var, char *Arg )
 } /* Handle_CHANNEL */
 } /* Handle_CHANNEL */
 
 
 
 
-static void
+static bool
 Validate_Config(bool Configtest, bool Rehash)
 Validate_Config(bool Configtest, bool Rehash)
 {
 {
 	/* Validate configuration settings. */
 	/* Validate configuration settings. */
@@ -1001,6 +1175,7 @@ Validate_Config(bool Configtest, bool Rehash)
 #ifdef DEBUG
 #ifdef DEBUG
 	int i, servers, servers_once;
 	int i, servers, servers_once;
 #endif
 #endif
+	bool config_valid = true;
 	char *ptr;
 	char *ptr;
 
 
 	/* Validate configured server name, see RFC 2812 section 2.3.1 */
 	/* Validate configured server name, see RFC 2812 section 2.3.1 */
@@ -1019,6 +1194,7 @@ Validate_Config(bool Configtest, bool Rehash)
 
 
 	if (!Conf_ServerName[0]) {
 	if (!Conf_ServerName[0]) {
 		/* No server name configured! */
 		/* No server name configured! */
+		config_valid = false;
 		Config_Error(LOG_ALERT,
 		Config_Error(LOG_ALERT,
 			     "No (valid) server name configured in \"%s\" (section 'Global': 'Name')!",
 			     "No (valid) server name configured in \"%s\" (section 'Global': 'Name')!",
 			     NGIRCd_ConfFile);
 			     NGIRCd_ConfFile);
@@ -1032,6 +1208,7 @@ Validate_Config(bool Configtest, bool Rehash)
 
 
 	if (Conf_ServerName[0] && !strchr(Conf_ServerName, '.')) {
 	if (Conf_ServerName[0] && !strchr(Conf_ServerName, '.')) {
 		/* No dot in server name! */
 		/* No dot in server name! */
+		config_valid = false;
 		Config_Error(LOG_ALERT,
 		Config_Error(LOG_ALERT,
 			     "Invalid server name configured in \"%s\" (section 'Global': 'Name'): Dot missing!",
 			     "Invalid server name configured in \"%s\" (section 'Global': 'Name'): Dot missing!",
 			     NGIRCd_ConfFile);
 			     NGIRCd_ConfFile);
@@ -1046,6 +1223,7 @@ Validate_Config(bool Configtest, bool Rehash)
 #ifdef STRICT_RFC
 #ifdef STRICT_RFC
 	if (!Conf_ServerAdminMail[0]) {
 	if (!Conf_ServerAdminMail[0]) {
 		/* No administrative contact configured! */
 		/* No administrative contact configured! */
+		config_valid = false;
 		Config_Error(LOG_ALERT,
 		Config_Error(LOG_ALERT,
 			     "No administrator email address configured in \"%s\" ('AdminEMail')!",
 			     "No administrator email address configured in \"%s\" ('AdminEMail')!",
 			     NGIRCd_ConfFile);
 			     NGIRCd_ConfFile);
@@ -1078,6 +1256,8 @@ Validate_Config(bool Configtest, bool Rehash)
 	    "Configuration: Operators=%d, Servers=%d[%d], Channels=%d",
 	    "Configuration: Operators=%d, Servers=%d[%d], Channels=%d",
 	    Conf_Oper_Count, servers, servers_once, Conf_Channel_Count);
 	    Conf_Oper_Count, servers, servers_once, Conf_Channel_Count);
 #endif
 #endif
+
+	return config_valid;
 } /* Validate_Config */
 } /* Validate_Config */
 
 
 
 
@@ -1144,6 +1324,7 @@ Init_Server_Struct( CONF_SERVER *Server )
 
 
 	Resolve_Init(&Server->res_stat);
 	Resolve_Init(&Server->res_stat);
 	Server->conn_id = NONE;
 	Server->conn_id = NONE;
+	memset(&Server->bind_addr, 0, sizeof(&Server->bind_addr));
 } /* Init_Server_Struct */
 } /* Init_Server_Struct */
 
 
 
 

+ 22 - 4
src/ngircd/conf.h

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: conf.h,v 1.40.2.2 2007/04/03 22:08:52 fw Exp $
+ * $Id: conf.h,v 1.49 2008/03/18 20:12:47 fw Exp $
  *
  *
  * Configuration management (header)
  * Configuration management (header)
  */
  */
@@ -22,6 +22,8 @@
 #include "defines.h"
 #include "defines.h"
 #include "array.h"
 #include "array.h"
 #include "portab.h"
 #include "portab.h"
+#include "tool.h"
+#include "ng_ipaddr.h"
 
 
 typedef struct _Conf_Oper
 typedef struct _Conf_Oper
 {
 {
@@ -33,7 +35,6 @@ typedef struct _Conf_Oper
 typedef struct _Conf_Server
 typedef struct _Conf_Server
 {
 {
 	char host[HOST_LEN];		/* Hostname */
 	char host[HOST_LEN];		/* Hostname */
-	char ip[16];			/* IP address (Resolver) */
 	char name[CLIENT_ID_LEN];	/* IRC-Client-ID */
 	char name[CLIENT_ID_LEN];	/* IRC-Client-ID */
 	char pwd_in[CLIENT_PASS_LEN];	/* Password which must be received */
 	char pwd_in[CLIENT_PASS_LEN];	/* Password which must be received */
 	char pwd_out[CLIENT_PASS_LEN];	/* Password to send to peer */
 	char pwd_out[CLIENT_PASS_LEN];	/* Password to send to peer */
@@ -43,6 +44,8 @@ typedef struct _Conf_Server
 	RES_STAT res_stat;		/* Status of the resolver */
 	RES_STAT res_stat;		/* Status of the resolver */
 	int flags;			/* Flags */
 	int flags;			/* Flags */
 	CONN_ID conn_id;		/* ID of server connection or NONE */
 	CONN_ID conn_id;		/* ID of server connection or NONE */
+	ng_ipaddr_t bind_addr;		/* source address to use for outgoing connections */
+	ng_ipaddr_t dst_addr[2];	/* list of addresses to connect to */
 } CONF_SERVER;
 } CONF_SERVER;
 
 
 typedef struct _Conf_Channel
 typedef struct _Conf_Channel
@@ -83,7 +86,7 @@ GLOBAL char Conf_MotdPhrase[LINE_LEN];
 GLOBAL array Conf_ListenPorts;
 GLOBAL array Conf_ListenPorts;
 
 
 /* Address to which the socket should be bound or empty (=all) */
 /* Address to which the socket should be bound or empty (=all) */
-GLOBAL char Conf_ListenAddress[16];
+GLOBAL char *Conf_ListenAddress;
 
 
 /* User and group ID the server should run with */
 /* User and group ID the server should run with */
 GLOBAL uid_t Conf_UID;
 GLOBAL uid_t Conf_UID;
@@ -118,6 +121,18 @@ GLOBAL bool Conf_PredefChannelsOnly;
 /* Are IRC operators allowed to always use MODE? */
 /* Are IRC operators allowed to always use MODE? */
 GLOBAL bool Conf_OperCanMode;
 GLOBAL bool Conf_OperCanMode;
 
 
+/* Disable all DNS functions? */
+GLOBAL bool Conf_NoDNS;
+
+/*
+ * try to connect to remote systems using the ipv6 protocol,
+ * if they have an ipv6 address? (default yes)
+ */
+GLOBAL bool Conf_ConnectIPv6;
+
+/* same as above, but for ipv4 hosts, default: yes  */
+GLOBAL bool Conf_ConnectIPv4;
+
 /* If an IRC op gives chanop privileges without being a chanop,
 /* If an IRC op gives chanop privileges without being a chanop,
  * ircd2 will ignore the command. This enables a workaround:
  * ircd2 will ignore the command. This enables a workaround:
  * It masks the command as coming from the server */
  * It masks the command as coming from the server */
@@ -132,9 +147,11 @@ GLOBAL int Conf_MaxJoins;
 /* Maximum number of connections per IP address */
 /* Maximum number of connections per IP address */
 GLOBAL int Conf_MaxConnectionsIP;
 GLOBAL int Conf_MaxConnectionsIP;
 
 
+/* Maximum length of a nick name */
+GLOBAL unsigned int Conf_MaxNickLength;
 
 
 GLOBAL void Conf_Init PARAMS((void));
 GLOBAL void Conf_Init PARAMS((void));
-GLOBAL void Conf_Rehash PARAMS((void));
+GLOBAL bool Conf_Rehash PARAMS((void));
 GLOBAL int Conf_Test PARAMS((void));
 GLOBAL int Conf_Test PARAMS((void));
 
 
 GLOBAL void Conf_UnsetServer PARAMS(( CONN_ID Idx ));
 GLOBAL void Conf_UnsetServer PARAMS(( CONN_ID Idx ));
@@ -142,6 +159,7 @@ GLOBAL void Conf_SetServer PARAMS(( int ConfServer, CONN_ID Idx ));
 GLOBAL int Conf_GetServer PARAMS(( CONN_ID Idx ));
 GLOBAL int Conf_GetServer PARAMS(( CONN_ID Idx ));
 
 
 GLOBAL bool Conf_EnableServer PARAMS(( char *Name, UINT16 Port ));
 GLOBAL bool Conf_EnableServer PARAMS(( char *Name, UINT16 Port ));
+GLOBAL bool Conf_EnablePassiveServer PARAMS((const char *Name));
 GLOBAL bool Conf_DisableServer PARAMS(( char *Name ));
 GLOBAL bool Conf_DisableServer PARAMS(( char *Name ));
 GLOBAL bool Conf_AddServer PARAMS(( char *Name, UINT16 Port, char *Host, char *MyPwd, char *PeerPwd ));
 GLOBAL bool Conf_AddServer PARAMS(( char *Name, UINT16 Port, char *Host, char *MyPwd, char *PeerPwd ));
 
 

+ 13 - 2
src/ngircd/conn-func.c

@@ -16,11 +16,12 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: conn-func.c,v 1.10 2006/05/10 21:24:01 alex Exp $";
+static char UNUSED id[] = "$Id: conn-func.c,v 1.12 2008/03/11 14:05:27 alex Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>
-#include <log.h>
+#include <string.h>
+#include "log.h"
 
 
 #include "conn.h"
 #include "conn.h"
 #include "client.h"
 #include "client.h"
@@ -39,6 +40,16 @@ Conn_UpdateIdle( CONN_ID Idx )
 }
 }
 
 
 
 
+/*
+ * Get signon time of a connection.
+ */
+GLOBAL time_t
+Conn_GetSignon(CONN_ID Idx)
+{
+	assert(Idx > NONE);
+	return My_Connections[Idx].signon;
+}
+
 GLOBAL time_t
 GLOBAL time_t
 Conn_GetIdle( CONN_ID Idx )
 Conn_GetIdle( CONN_ID Idx )
 {
 {

+ 2 - 1
src/ngircd/conn-func.h

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: conn-func.h,v 1.5.2.1 2007/04/03 22:08:52 fw Exp $
+ * $Id: conn-func.h,v 1.7 2007/10/04 15:03:56 alex Exp $
  *
  *
  * Connection management: Global functions (header)
  * Connection management: Global functions (header)
  */
  */
@@ -27,6 +27,7 @@
 
 
 
 
 GLOBAL void Conn_UpdateIdle PARAMS(( CONN_ID Idx ));
 GLOBAL void Conn_UpdateIdle PARAMS(( CONN_ID Idx ));
+GLOBAL time_t Conn_GetSignon PARAMS((CONN_ID Idx));
 GLOBAL time_t Conn_GetIdle PARAMS(( CONN_ID Idx ));
 GLOBAL time_t Conn_GetIdle PARAMS(( CONN_ID Idx ));
 GLOBAL time_t Conn_LastPing PARAMS(( CONN_ID Idx ));
 GLOBAL time_t Conn_LastPing PARAMS(( CONN_ID Idx ));
 GLOBAL time_t Conn_StartTime PARAMS(( CONN_ID Idx ));
 GLOBAL time_t Conn_StartTime PARAMS(( CONN_ID Idx ));

+ 1 - 1
src/ngircd/conn-zip.c

@@ -22,7 +22,7 @@
 /* enable more zlib related debug messages: */
 /* enable more zlib related debug messages: */
 /* #define DEBUG_ZLIB */
 /* #define DEBUG_ZLIB */
 
 
-static char UNUSED id[] = "$Id: conn-zip.c,v 1.11.2.1 2007/05/18 22:11:19 alex Exp $";
+static char UNUSED id[] = "$Id: conn-zip.c,v 1.16 2007/05/17 23:34:24 alex Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>

+ 240 - 158
src/ngircd/conn.c

@@ -17,7 +17,7 @@
 #include "portab.h"
 #include "portab.h"
 #include "io.h"
 #include "io.h"
 
 
-static char UNUSED id[] = "$Id: conn.c,v 1.198.2.6 2007/05/18 22:11:19 alex Exp $";
+static char UNUSED id[] = "$Id: conn.c,v 1.221 2008/02/26 22:04:17 fw Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>
@@ -41,12 +41,6 @@ static char UNUSED id[] = "$Id: conn.c,v 1.198.2.6 2007/05/18 22:11:19 alex Exp
 # include <netinet/ip.h>
 # include <netinet/ip.h>
 #endif
 #endif
 
 
-#ifdef HAVE_ARPA_INET_H
-# include <arpa/inet.h>
-#else
-# define PF_INET AF_INET
-#endif
-
 #ifdef HAVE_STDINT_H
 #ifdef HAVE_STDINT_H
 # include <stdint.h>			/* e.g. for Mac OS X */
 # include <stdint.h>			/* e.g. for Mac OS X */
 #endif
 #endif
@@ -92,10 +86,9 @@ static void Check_Connections PARAMS(( void ));
 static void Check_Servers PARAMS(( void ));
 static void Check_Servers PARAMS(( void ));
 static void Init_Conn_Struct PARAMS(( CONN_ID Idx ));
 static void Init_Conn_Struct PARAMS(( CONN_ID Idx ));
 static bool Init_Socket PARAMS(( int Sock ));
 static bool Init_Socket PARAMS(( int Sock ));
-static void New_Server PARAMS(( int Server ));
+static void New_Server PARAMS(( int Server, ng_ipaddr_t *dest ));
 static void Simple_Message PARAMS(( int Sock, const char *Msg ));
 static void Simple_Message PARAMS(( int Sock, const char *Msg ));
-static int Count_Connections PARAMS(( struct sockaddr_in addr ));
-static int NewListener PARAMS(( const UINT16 Port ));
+static int NewListener PARAMS(( const char *listen_addr, UINT16 Port ));
 
 
 static array My_Listeners;
 static array My_Listeners;
 static array My_ConnArray;
 static array My_ConnArray;
@@ -150,10 +143,28 @@ cb_connserver(int sock, UNUSED short what)
  			    Conf_Server[Conf_GetServer(idx)].port,
  			    Conf_Server[Conf_GetServer(idx)].port,
  			    idx, strerror(err));
  			    idx, strerror(err));
 
 
+		res = Conf_GetServer(idx);
+		assert(res >= 0);
+
 		Conn_Close(idx, "Can't connect!", NULL, false);
 		Conn_Close(idx, "Can't connect!", NULL, false);
+
+		if (res < 0)
+			return;
+		if (ng_ipaddr_af(&Conf_Server[res].dst_addr[0])) {
+			/* more addresses to try... */
+			New_Server(res, &Conf_Server[res].dst_addr[0]);
+			/* connection to dst_addr[0] in progress, remove this address... */
+			Conf_Server[res].dst_addr[0] = Conf_Server[res].dst_addr[1];
+
+			memset(&Conf_Server[res].dst_addr[1], 0, sizeof(&Conf_Server[res].dst_addr[1]));
+		}
 		return;
 		return;
 	}
 	}
 
 
+	res = Conf_GetServer(idx);
+	assert(res >= 0);
+	if (res >= 0) /* connect succeeded, remove all additional addresses */
+		memset(&Conf_Server[res].dst_addr, 0, sizeof(&Conf_Server[res].dst_addr));
 	Conn_OPTION_DEL( &My_Connections[idx], CONN_ISCONNECTING );
 	Conn_OPTION_DEL( &My_Connections[idx], CONN_ISCONNECTING );
 	server_login(idx);
 	server_login(idx);
 }
 }
@@ -260,25 +271,25 @@ Conn_Exit( void )
 } /* Conn_Exit */
 } /* Conn_Exit */
 
 
 
 
-static int
-ports_initlisteners(array *a, void (*func)(int,short))
+static unsigned int
+ports_initlisteners(array *a, const char *listen_addr, void (*func)(int,short))
 {
 {
-	int created = 0;
+	unsigned int created = 0;
 	size_t len;
 	size_t len;
 	int fd;
 	int fd;
 	UINT16 *port;
 	UINT16 *port;
 
 
 	len = array_length(a, sizeof (UINT16));
 	len = array_length(a, sizeof (UINT16));
 	port = array_start(a);
 	port = array_start(a);
-	while(len--) {
-		fd = NewListener( *port );
+	while (len--) {
+		fd = NewListener(listen_addr, *port);
 		if (fd < 0) {
 		if (fd < 0) {
 			port++;
 			port++;
 			continue;
 			continue;
 		}
 		}
 		if (!io_event_create( fd, IO_WANTREAD, func )) {
 		if (!io_event_create( fd, IO_WANTREAD, func )) {
 			Log( LOG_ERR, "io_event_create(): Could not add listening fd %d (port %u): %s!",
 			Log( LOG_ERR, "io_event_create(): Could not add listening fd %d (port %u): %s!",
-							fd, (unsigned int) *port, strerror(errno));
+						fd, (unsigned int) *port, strerror(errno));
 			close(fd);
 			close(fd);
 			port++;
 			port++;
 			continue;
 			continue;
@@ -286,25 +297,47 @@ ports_initlisteners(array *a, void (*func)(int,short))
 		created++;
 		created++;
 		port++;
 		port++;
 	}
 	}
-
 	return created;
 	return created;
 }
 }
 
 
 
 
-GLOBAL int
+GLOBAL unsigned int
 Conn_InitListeners( void )
 Conn_InitListeners( void )
 {
 {
 	/* Initialize ports on which the server should accept connections */
 	/* Initialize ports on which the server should accept connections */
-
-	int created;
+	unsigned int created = 0;
+	char *copy, *listen_addr;
 
 
 	if (!io_library_init(CONNECTION_POOL)) {
 	if (!io_library_init(CONNECTION_POOL)) {
 		Log(LOG_EMERG, "Cannot initialize IO routines: %s", strerror(errno));
 		Log(LOG_EMERG, "Cannot initialize IO routines: %s", strerror(errno));
 		return -1;
 		return -1;
 	}
 	}
 
 
-	created = ports_initlisteners(&Conf_ListenPorts, cb_listen);
+	assert(Conf_ListenAddress);
+
+	/* can't use Conf_ListenAddress directly, see below */
+	copy = strdup(Conf_ListenAddress);
+	if (!copy) {
+		Log(LOG_CRIT, "Cannot copy %s: %s", Conf_ListenAddress, strerror(errno));
+		return 0;
+	}
+	listen_addr = strtok(copy, ",");
+
+	while (listen_addr) {
+		ngt_TrimStr(listen_addr);
+		if (*listen_addr)
+			created += ports_initlisteners(&Conf_ListenPorts, listen_addr, cb_listen);
 
 
+		listen_addr = strtok(NULL, ",");
+	}
+
+	/*
+	 * can't free() Conf_ListenAddress here. On /REHASH, if the config file
+	 * cannot be re-loaded, we'd end up with a NULL Conf_ListenAddress.
+	 * Instead, free() takes place in conf.c, before the config file
+	 * is being parsed.
+	 */
+	free(copy);
 	return created;
 	return created;
 } /* Conn_InitListeners */
 } /* Conn_InitListeners */
 
 
@@ -333,52 +366,68 @@ Conn_ExitListeners( void )
 } /* Conn_ExitListeners */
 } /* Conn_ExitListeners */
 
 
 
 
+static bool
+InitSinaddrListenAddr(ng_ipaddr_t *addr, const char *listen_addrstr, UINT16 Port)
+{
+	bool ret;
+
+	ret = ng_ipaddr_init(addr, listen_addrstr, Port);
+	if (!ret) {
+		assert(listen_addrstr);
+		Log(LOG_CRIT, "Can't bind to [%s]:%u: can't convert ip address \"%s\"",
+						listen_addrstr, Port, listen_addrstr);
+	}
+	return ret;
+}
+
+
+static void
+set_v6_only(int af, int sock)
+{
+#if defined(IPV6_V6ONLY) && defined(WANT_IPV6)
+	int on = 1;
+
+	if (af != AF_INET6)
+		return;
+
+	if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)))
+		Log(LOG_ERR, "Could not set IPV6_V6ONLY: %s", strerror(errno));
+#else
+	(void)af;
+	(void)sock;
+#endif
+}
+
+
 /* return new listening port file descriptor or -1 on failure */
 /* return new listening port file descriptor or -1 on failure */
 static int
 static int
-NewListener( const UINT16 Port )
+NewListener(const char *listen_addr, UINT16 Port)
 {
 {
 	/* Create new listening socket on specified port */
 	/* Create new listening socket on specified port */
-
-	struct sockaddr_in addr;
-	struct in_addr inaddr;
-	int sock;
+	ng_ipaddr_t addr;
+	int sock, af;
 #ifdef ZEROCONF
 #ifdef ZEROCONF
 	char name[CLIENT_ID_LEN], *info;
 	char name[CLIENT_ID_LEN], *info;
 #endif
 #endif
+	if (!InitSinaddrListenAddr(&addr, listen_addr, Port))
+		return -1;
 
 
-	/* Server-"Listen"-Socket initialisieren */
-	memset( &addr, 0, sizeof( addr ));
-	memset( &inaddr, 0, sizeof( inaddr ));
-	addr.sin_family = (sa_family_t)AF_INET;
-	addr.sin_port = htons( Port );
-	if( Conf_ListenAddress[0] )
-	{
-#ifdef HAVE_INET_ATON
-		if( inet_aton( Conf_ListenAddress, &inaddr ) == 0 )
-#else
-		inaddr.s_addr = inet_addr( Conf_ListenAddress );
-		if( inaddr.s_addr == (unsigned)-1 )
-#endif
-		{
-			Log( LOG_CRIT, "Can't listen on %s:%u: can't convert ip address %s!",
-					Conf_ListenAddress, Port, Conf_ListenAddress );
-			return -1;
-		}
-	}
-	else inaddr.s_addr = htonl( INADDR_ANY );
-	addr.sin_addr = inaddr;
-
-	sock = socket( PF_INET, SOCK_STREAM, 0);
+	af = ng_ipaddr_af(&addr);
+	sock = socket(af, SOCK_STREAM, 0);
 	if( sock < 0 ) {
 	if( sock < 0 ) {
-		Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno ));
+		Log(LOG_CRIT, "Can't create socket (af %d) : %s!", af, strerror(errno));
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if( ! Init_Socket( sock )) return -1;
+	set_v6_only(af, sock);
 
 
-	if (bind(sock, (struct sockaddr *)&addr, (socklen_t)sizeof(addr)) != 0) {
-		Log( LOG_CRIT, "Can't bind socket (port %d) : %s!", Port, strerror( errno ));
-		close( sock );
+	if (!Init_Socket(sock))
+		return -1;
+
+	if (bind(sock, (struct sockaddr *)&addr, ng_ipaddr_salen(&addr)) != 0) {
+		Log(LOG_CRIT, "Can't bind socket to address %s:%d - %s",
+			ng_ipaddr_tostr(&addr), Port, strerror(errno));
+		close(sock);
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -395,8 +444,7 @@ NewListener( const UINT16 Port )
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if( Conf_ListenAddress[0]) Log( LOG_INFO, "Now listening on %s:%d (socket %d).", Conf_ListenAddress, Port, sock );
-	else Log( LOG_INFO, "Now listening on 0.0.0.0:%d (socket %d).", Port, sock );
+	Log(LOG_INFO, "Now listening on [%s]:%d (socket %d).", ng_ipaddr_tostr(&addr), Port, sock);
 
 
 #ifdef ZEROCONF
 #ifdef ZEROCONF
 	/* Get best server description text */
 	/* Get best server description text */
@@ -697,6 +745,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
 	CLIENT *c;
 	CLIENT *c;
 	char *txt;
 	char *txt;
 	double in_k, out_k;
 	double in_k, out_k;
+	UINT16 port;
 #ifdef ZLIB
 #ifdef ZLIB
 	double in_z_k, out_z_k;
 	double in_z_k, out_z_k;
 	int in_p, out_p;
 	int in_p, out_p;
@@ -724,9 +773,9 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
 	if (! txt)
 	if (! txt)
 		txt = "Reason unknown";
 		txt = "Reason unknown";
 
 
+	port = ng_ipaddr_getport(&My_Connections[Idx].addr);
 	Log(LOG_INFO, "Shutting down connection %d (%s) with %s:%d ...", Idx,
 	Log(LOG_INFO, "Shutting down connection %d (%s) with %s:%d ...", Idx,
-	    LogMsg ? LogMsg : FwdMsg, My_Connections[Idx].host,
-	    ntohs(My_Connections[Idx].addr.sin_port));
+	    LogMsg ? LogMsg : FwdMsg, My_Connections[Idx].host, port);
 
 
 	/* Search client, if any */
 	/* Search client, if any */
 	c = Conn_GetClient( Idx );
 	c = Conn_GetClient( Idx );
@@ -766,7 +815,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
 		Log(LOG_CRIT,
 		Log(LOG_CRIT,
 		    "Error closing connection %d (socket %d) with %s:%d - %s! (ignored)",
 		    "Error closing connection %d (socket %d) with %s:%d - %s! (ignored)",
 		    Idx, My_Connections[Idx].sock, My_Connections[Idx].host,
 		    Idx, My_Connections[Idx].sock, My_Connections[Idx].host,
-		    ntohs(My_Connections[Idx].addr.sin_port), strerror(errno));
+		    port, strerror(errno));
 	}
 	}
 
 
 	/* Mark socket as invalid: */
 	/* Mark socket as invalid: */
@@ -795,8 +844,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
 		out_p = (int)(( out_k * 100 ) / out_z_k );
 		out_p = (int)(( out_k * 100 ) / out_z_k );
 		Log(LOG_INFO,
 		Log(LOG_INFO,
 		    "Connection %d with %s:%d closed (in: %.1fk/%.1fk/%d%%, out: %.1fk/%.1fk/%d%%).",
 		    "Connection %d with %s:%d closed (in: %.1fk/%.1fk/%d%%, out: %.1fk/%.1fk/%d%%).",
-		    Idx, My_Connections[Idx].host,
-		    ntohs(My_Connections[Idx].addr.sin_port),
+		    Idx, My_Connections[Idx].host, port,
 		    in_k, in_z_k, in_p, out_k, out_z_k, out_p);
 		    in_k, in_z_k, in_p, out_k, out_z_k, out_p);
 	}
 	}
 	else
 	else
@@ -804,8 +852,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
 	{
 	{
 		Log(LOG_INFO,
 		Log(LOG_INFO,
 		    "Connection %d with %s:%d closed (in: %.1fk, out: %.1fk).",
 		    "Connection %d with %s:%d closed (in: %.1fk, out: %.1fk).",
-		    Idx, My_Connections[Idx].host,
-		    ntohs(My_Connections[Idx].addr.sin_port),
+		    Idx, My_Connections[Idx].host, port,
 		    in_k, out_k);
 		    in_k, out_k);
 	}
 	}
 
 
@@ -929,6 +976,22 @@ Handle_Write( CONN_ID Idx )
 
 
 
 
 static int
 static int
+Count_Connections(ng_ipaddr_t *a)
+{
+	int i, cnt;
+
+	cnt = 0;
+	for (i = 0; i < Pool_Size; i++) {
+		if (My_Connections[i].sock <= NONE)
+			continue;
+		if (ng_ipaddr_ipequal(&My_Connections[i].addr, a))
+			cnt++;
+	}
+	return cnt;
+} /* Count_Connections */
+
+
+static int
 New_Connection( int Sock )
 New_Connection( int Sock )
 {
 {
 	/* Neue Client-Verbindung von Listen-Socket annehmen und
 	/* Neue Client-Verbindung von Listen-Socket annehmen und
@@ -937,14 +1000,16 @@ New_Connection( int Sock )
 #ifdef TCPWRAP
 #ifdef TCPWRAP
 	struct request_info req;
 	struct request_info req;
 #endif
 #endif
-	struct sockaddr_in new_addr;
+	ng_ipaddr_t new_addr;
+	char ip_str[NG_INET_ADDRSTRLEN];
 	int new_sock, new_sock_len, new_Pool_Size;
 	int new_sock, new_sock_len, new_Pool_Size;
 	CLIENT *c;
 	CLIENT *c;
 	long cnt;
 	long cnt;
 
 
 	assert( Sock > NONE );
 	assert( Sock > NONE );
 	/* Connection auf Listen-Socket annehmen */
 	/* Connection auf Listen-Socket annehmen */
-	new_sock_len = (int)sizeof new_addr;
+	new_sock_len = (int)sizeof(new_addr);
+
 	new_sock = accept(Sock, (struct sockaddr *)&new_addr,
 	new_sock = accept(Sock, (struct sockaddr *)&new_addr,
 			  (socklen_t *)&new_sock_len);
 			  (socklen_t *)&new_sock_len);
 	if (new_sock < 0) {
 	if (new_sock < 0) {
@@ -952,14 +1017,18 @@ New_Connection( int Sock )
 		return -1;
 		return -1;
 	}
 	}
 
 
+	if (!ng_ipaddr_tostr_r(&new_addr, ip_str)) {
+		Log(LOG_CRIT, "fd %d: Can't convert IP address!", new_sock);
+		Simple_Message(new_sock, "ERROR :Internal Server Error");
+		close(new_sock);
+	}
+
 #ifdef TCPWRAP
 #ifdef TCPWRAP
 	/* Validate socket using TCP Wrappers */
 	/* Validate socket using TCP Wrappers */
 	request_init( &req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock, RQ_CLIENT_SIN, &new_addr, NULL );
 	request_init( &req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock, RQ_CLIENT_SIN, &new_addr, NULL );
 	fromhost(&req);
 	fromhost(&req);
-	if( ! hosts_access( &req ))
-	{
-		/* Access denied! */
-		Log( deny_severity, "Refused connection from %s (by TCP Wrappers)!", inet_ntoa( new_addr.sin_addr ));
+	if (!hosts_access(&req)) {
+		Log (deny_severity, "Refused connection from %s (by TCP Wrappers)!", ip_str);
 		Simple_Message( new_sock, "ERROR :Connection refused" );
 		Simple_Message( new_sock, "ERROR :Connection refused" );
 		close( new_sock );
 		close( new_sock );
 		return -1;
 		return -1;
@@ -969,13 +1038,12 @@ New_Connection( int Sock )
 	/* Socket initialisieren */
 	/* Socket initialisieren */
 	if (!Init_Socket( new_sock ))
 	if (!Init_Socket( new_sock ))
 		return -1;
 		return -1;
-	
+
 	/* Check IP-based connection limit */
 	/* Check IP-based connection limit */
-	cnt = Count_Connections( new_addr );
-	if(( Conf_MaxConnectionsIP > 0 ) && ( cnt >= Conf_MaxConnectionsIP ))
-	{
+	cnt = Count_Connections(&new_addr);
+	if ((Conf_MaxConnectionsIP > 0) && (cnt >= Conf_MaxConnectionsIP)) {
 		/* Access denied, too many connections from this IP address! */
 		/* Access denied, too many connections from this IP address! */
-		Log( LOG_ERR, "Refused connection from %s: too may connections (%ld) from this IP address!", inet_ntoa( new_addr.sin_addr ), cnt);
+		Log( LOG_ERR, "Refused connection from %s: too may connections (%ld) from this IP address!", ip_str, cnt);
 		Simple_Message( new_sock, "ERROR :Connection refused, too many connections from your IP address!" );
 		Simple_Message( new_sock, "ERROR :Connection refused, too many connections from your IP address!" );
 		close( new_sock );
 		close( new_sock );
 		return -1;
 		return -1;
@@ -1017,7 +1085,7 @@ New_Connection( int Sock )
 		return -1;
 		return -1;
 	}
 	}
 
 
-	c = Client_NewLocal( new_sock, inet_ntoa( new_addr.sin_addr ), CLIENT_UNKNOWN, false );
+	c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWN, false );
 	if( ! c ) {
 	if( ! c ) {
 		Log(LOG_ALERT, "Can't accept connection: can't create client structure!");
 		Log(LOG_ALERT, "Can't accept connection: can't create client structure!");
 		Simple_Message(new_sock, "ERROR :Internal error");
 		Simple_Message(new_sock, "ERROR :Internal error");
@@ -1031,19 +1099,18 @@ New_Connection( int Sock )
 	My_Connections[new_sock].client = c;
 	My_Connections[new_sock].client = c;
 
 
 	Log( LOG_INFO, "Accepted connection %d from %s:%d on socket %d.", new_sock,
 	Log( LOG_INFO, "Accepted connection %d from %s:%d on socket %d.", new_sock,
-			inet_ntoa( new_addr.sin_addr ), ntohs( new_addr.sin_port), Sock );
+			ip_str, ng_ipaddr_getport(&new_addr), Sock);
 
 
 	/* Hostnamen ermitteln */
 	/* Hostnamen ermitteln */
-	strlcpy( My_Connections[new_sock].host, inet_ntoa( new_addr.sin_addr ),
-						sizeof( My_Connections[new_sock].host ));
+	strlcpy(My_Connections[new_sock].host, ip_str, sizeof(My_Connections[new_sock].host));
 
 
-	Client_SetHostname( c, My_Connections[new_sock].host );
+	Client_SetHostname(c, My_Connections[new_sock].host);
 
 
-	Resolve_Addr(&My_Connections[new_sock].res_stat, &new_addr,
-		My_Connections[new_sock].sock, cb_Read_Resolver_Result);
+	if (!Conf_NoDNS)
+		Resolve_Addr(&My_Connections[new_sock].res_stat, &new_addr,
+			My_Connections[new_sock].sock, cb_Read_Resolver_Result);
 
 
-	/* Penalty-Zeit setzen */
-	Conn_SetPenalty( new_sock, 4 );
+	Conn_SetPenalty(new_sock, 4);
 	return new_sock;
 	return new_sock;
 } /* New_Connection */
 } /* New_Connection */
 
 
@@ -1095,10 +1162,10 @@ Read_Request( CONN_ID Idx )
 
 
 	len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf));
 	len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf));
 	if (len == 0) {
 	if (len == 0) {
-		Log(LOG_INFO, "%s:%d (%s) is closing the connection ...",
-		    My_Connections[Idx].host,
-		    ntohs(My_Connections[Idx].addr.sin_port),
-		    inet_ntoa( My_Connections[Idx].addr.sin_addr));
+		Log(LOG_INFO, "%s:%u (%s) is closing the connection ...",
+				My_Connections[Idx].host,
+				(unsigned int) ng_ipaddr_getport(&My_Connections[Idx].addr),
+				ng_ipaddr_tostr(&My_Connections[Idx].addr));
 		Conn_Close(Idx,
 		Conn_Close(Idx,
 			   "Socket closed!", "Client closed connection",
 			   "Socket closed!", "Client closed connection",
 			   false);
 			   false);
@@ -1160,7 +1227,7 @@ Handle_Buffer( CONN_ID Idx )
 	/* Handle Data in Connections Read-Buffer.
 	/* Handle Data in Connections Read-Buffer.
 	 * Return true if a reuqest was handled, false otherwise (also returned on errors). */
 	 * Return true if a reuqest was handled, false otherwise (also returned on errors). */
 #ifndef STRICT_RFC
 #ifndef STRICT_RFC
-	char *ptr1, *ptr2;
+	char *ptr1, *ptr2, *first_eol;
 #endif
 #endif
 	char *ptr;
 	char *ptr;
 	size_t len, delta;
 	size_t len, delta;
@@ -1188,19 +1255,32 @@ Handle_Buffer( CONN_ID Idx )
 			return false;
 			return false;
 
 
 		/* A Complete Request end with CR+LF, see RFC 2812. */
 		/* A Complete Request end with CR+LF, see RFC 2812. */
+		delta = 2;
 		ptr = strstr( array_start(&My_Connections[Idx].rbuf), "\r\n" );
 		ptr = strstr( array_start(&My_Connections[Idx].rbuf), "\r\n" );
 
 
-		if( ptr ) delta = 2; /* complete request */
 #ifndef STRICT_RFC
 #ifndef STRICT_RFC
-		else {
-			/* Check for non-RFC-compliant request (only CR or LF)? Unfortunately,
-			 * there are quite a few clients that do this (incl. "mIRC" :-( */
-			ptr1 = strchr( array_start(&My_Connections[Idx].rbuf), '\r' );
-			ptr2 = strchr( array_start(&My_Connections[Idx].rbuf), '\n' );
+		/* Check for non-RFC-compliant request (only CR or LF)?
+		 * Unfortunately, there are quite a few clients out there
+		 * that do this -- e. g. mIRC, BitchX, and Trillian :-( */
+		ptr1 = strchr(array_start(&My_Connections[Idx].rbuf), '\r');
+		ptr2 = strchr(array_start(&My_Connections[Idx].rbuf), '\n');
+		if (ptr) {
+			/* Check if there is a single CR or LF _before_ the
+			 * corerct CR+LF line terminator:  */
+			first_eol = ptr1 < ptr2 ? ptr1 : ptr2;
+			if (first_eol < ptr) {
+				/* Single CR or LF before CR+LF found */
+				ptr = first_eol;
+				delta = 1;
+			}
+		} else if (ptr1 || ptr2) {
+			/* No CR+LF terminated command found, but single
+			 * CR or LF found ... */
+			if (ptr1 && ptr2)
+				ptr = ptr1 < ptr2 ? ptr1 : ptr2;
+			else
+				ptr = ptr1 ? ptr1 : ptr2;
 			delta = 1;
 			delta = 1;
-			if( ptr1 && ptr2 ) ptr = ptr1 > ptr2 ? ptr2 : ptr1;
-			else if( ptr1 ) ptr = ptr1;
-			else if( ptr2 ) ptr = ptr2;
 		}
 		}
 #endif
 #endif
 
 
@@ -1333,7 +1413,7 @@ Check_Servers( void )
 		if( Conf_Server[i].group > NONE ) {
 		if( Conf_Server[i].group > NONE ) {
 			for (n = 0; n < MAX_SERVERS; n++) {
 			for (n = 0; n < MAX_SERVERS; n++) {
 				if (n == i) continue;
 				if (n == i) continue;
-				if ((Conf_Server[n].conn_id > NONE) &&
+				if ((Conf_Server[n].conn_id != NONE) &&
 					(Conf_Server[n].group == Conf_Server[i].group))
 					(Conf_Server[n].group == Conf_Server[i].group))
 						break;
 						break;
 			}
 			}
@@ -1347,6 +1427,7 @@ Check_Servers( void )
 
 
 		/* Okay, try to connect now */
 		/* Okay, try to connect now */
 		Conf_Server[i].lasttry = time_now;
 		Conf_Server[i].lasttry = time_now;
+		Conf_Server[i].conn_id = SERVER_WAIT;
 		assert(Resolve_Getfd(&Conf_Server[i].res_stat) < 0);
 		assert(Resolve_Getfd(&Conf_Server[i].res_stat) < 0);
 		Resolve_Name(&Conf_Server[i].res_stat, Conf_Server[i].host, cb_Connect_to_Server);
 		Resolve_Name(&Conf_Server[i].res_stat, Conf_Server[i].host, cb_Connect_to_Server);
 	}
 	}
@@ -1354,54 +1435,50 @@ Check_Servers( void )
 
 
 
 
 static void
 static void
-New_Server( int Server )
+New_Server( int Server , ng_ipaddr_t *dest)
 {
 {
 	/* Establish new server link */
 	/* Establish new server link */
-
-	struct sockaddr_in new_addr;
-	struct in_addr inaddr;
-	int res, new_sock;
+	char ip_str[NG_INET_ADDRSTRLEN];
+	int af_dest, res, new_sock;
 	CLIENT *c;
 	CLIENT *c;
 
 
 	assert( Server > NONE );
 	assert( Server > NONE );
 
 
-	Log( LOG_INFO, "Establishing connection to \"%s\", %s, port %d ... ", Conf_Server[Server].host,
-							Conf_Server[Server].ip, Conf_Server[Server].port );
-
-#ifdef HAVE_INET_ATON
-	if( inet_aton( Conf_Server[Server].ip, &inaddr ) == 0 )
-#else
-	memset( &inaddr, 0, sizeof( inaddr ));
-	inaddr.s_addr = inet_addr( Conf_Server[Server].ip );
-	if( inaddr.s_addr == (unsigned)-1 )
-#endif
-	{
-		Log( LOG_ERR, "Can't connect to \"%s\": can't convert ip address %s!",
-				Conf_Server[Server].host, Conf_Server[Server].ip );
+	if (!ng_ipaddr_tostr_r(dest, ip_str)) {
+		Log(LOG_WARNING, "New_Server: Could not convert IP to string");
 		return;
 		return;
 	}
 	}
 
 
-	memset( &new_addr, 0, sizeof( new_addr ));
-	new_addr.sin_family = (sa_family_t)AF_INET;
-	new_addr.sin_addr = inaddr;
-	new_addr.sin_port = htons( Conf_Server[Server].port );
+	Log( LOG_INFO, "Establishing connection to \"%s\", %s, port %d ... ",
+			Conf_Server[Server].host, ip_str, Conf_Server[Server].port );
 
 
-	new_sock = socket( PF_INET, SOCK_STREAM, 0 );
-	if ( new_sock < 0 ) {
-		Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno ));
+	af_dest = ng_ipaddr_af(dest);
+	new_sock = socket(af_dest, SOCK_STREAM, 0);
+	if (new_sock < 0) {
+		Log( LOG_CRIT, "Can't create socket (af %d) : %s!", af_dest, strerror( errno ));
 		return;
 		return;
 	}
 	}
 
 
-	if( ! Init_Socket( new_sock )) return;
+	if (!Init_Socket(new_sock))
+		return;
 
 
-	res = connect(new_sock, (struct sockaddr *)&new_addr,
-			(socklen_t)sizeof(new_addr));
+	/* is a bind address configured? */
+	res = ng_ipaddr_af(&Conf_Server[Server].bind_addr);
+	/* if yes, bind now. If it fails, warn and let connect() pick a source address */
+	if (res && bind(new_sock, (struct sockaddr *) &Conf_Server[Server].bind_addr,
+				ng_ipaddr_salen(&Conf_Server[Server].bind_addr)))
+	{
+		ng_ipaddr_tostr_r(&Conf_Server[Server].bind_addr, ip_str);
+		Log(LOG_WARNING, "Can't bind socket to %s: %s!", ip_str, strerror(errno));
+	}
+	ng_ipaddr_setport(dest, Conf_Server[Server].port);
+	res = connect(new_sock, (struct sockaddr *) dest, ng_ipaddr_salen(dest));
 	if(( res != 0 ) && ( errno != EINPROGRESS )) {
 	if(( res != 0 ) && ( errno != EINPROGRESS )) {
 		Log( LOG_CRIT, "Can't connect socket: %s!", strerror( errno ));
 		Log( LOG_CRIT, "Can't connect socket: %s!", strerror( errno ));
 		close( new_sock );
 		close( new_sock );
 		return;
 		return;
 	}
 	}
-	
+
 	if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), (size_t)new_sock)) {
 	if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), (size_t)new_sock)) {
 		Log(LOG_ALERT,
 		Log(LOG_ALERT,
 		    "Cannot allocate memory for server connection (socket %d)",
 		    "Cannot allocate memory for server connection (socket %d)",
@@ -1416,8 +1493,9 @@ New_Server( int Server )
 
 
 	Init_Conn_Struct(new_sock);
 	Init_Conn_Struct(new_sock);
 
 
-	c = Client_NewLocal( new_sock, inet_ntoa( new_addr.sin_addr ), CLIENT_UNKNOWNSERVER, false );
-	if( ! c ) {
+	ng_ipaddr_tostr_r(dest, ip_str);
+	c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWNSERVER, false);
+	if (!c) {
 		Log( LOG_ALERT, "Can't establish connection: can't create client structure!" );
 		Log( LOG_ALERT, "Can't establish connection: can't create client structure!" );
 		close( new_sock );
 		close( new_sock );
 		return;
 		return;
@@ -1429,7 +1507,7 @@ New_Server( int Server )
 	/* Register connection */
 	/* Register connection */
 	Conf_Server[Server].conn_id = new_sock;
 	Conf_Server[Server].conn_id = new_sock;
 	My_Connections[new_sock].sock = new_sock;
 	My_Connections[new_sock].sock = new_sock;
-	My_Connections[new_sock].addr = new_addr;
+	My_Connections[new_sock].addr = *dest;
 	My_Connections[new_sock].client = c;
 	My_Connections[new_sock].client = c;
 	strlcpy( My_Connections[new_sock].host, Conf_Server[Server].host,
 	strlcpy( My_Connections[new_sock].host, Conf_Server[Server].host,
 				sizeof(My_Connections[new_sock].host ));
 				sizeof(My_Connections[new_sock].host ));
@@ -1448,14 +1526,17 @@ New_Server( int Server )
 } /* New_Server */
 } /* New_Server */
 
 
 
 
+/**
+ * Initialize connection structure.
+ */
 static void
 static void
-Init_Conn_Struct( CONN_ID Idx )
+Init_Conn_Struct(CONN_ID Idx)
 {
 {
-	time_t now = time( NULL );
-	/* Connection-Struktur initialisieren */
+	time_t now = time(NULL);
 
 
-	memset( &My_Connections[Idx], 0, sizeof ( CONNECTION ));
+	memset(&My_Connections[Idx], 0, sizeof(CONNECTION));
 	My_Connections[Idx].sock = -1;
 	My_Connections[Idx].sock = -1;
+	My_Connections[Idx].signon = now;
 	My_Connections[Idx].lastdata = now;
 	My_Connections[Idx].lastdata = now;
 	My_Connections[Idx].lastprivmsg = now;
 	My_Connections[Idx].lastprivmsg = now;
 	Resolve_Init(&My_Connections[Idx].res_stat);
 	Resolve_Init(&My_Connections[Idx].res_stat);
@@ -1505,7 +1586,9 @@ cb_Connect_to_Server(int fd, UNUSED short events)
 	/* Read result of resolver sub-process from pipe and start connection */
 	/* Read result of resolver sub-process from pipe and start connection */
 	int i;
 	int i;
 	size_t len;
 	size_t len;
-	char readbuf[HOST_LEN + 1];
+	ng_ipaddr_t dest_addrs[4];	/* we can handle at most 3; but we read up to
+					   four so we can log the 'more than we can handle'
+					   condition */
 
 
 	LogDebug("Resolver: Got forward lookup callback on fd %d, events %d", fd, events);
 	LogDebug("Resolver: Got forward lookup callback on fd %d, events %d", fd, events);
 
 
@@ -1513,7 +1596,7 @@ cb_Connect_to_Server(int fd, UNUSED short events)
 		  if (Resolve_Getfd(&Conf_Server[i].res_stat) == fd )
 		  if (Resolve_Getfd(&Conf_Server[i].res_stat) == fd )
 			  break;
 			  break;
 	}
 	}
-	
+
 	if( i >= MAX_SERVERS) {
 	if( i >= MAX_SERVERS) {
 		/* Ops, no matching server found?! */
 		/* Ops, no matching server found?! */
 		io_close( fd );
 		io_close( fd );
@@ -1522,16 +1605,28 @@ cb_Connect_to_Server(int fd, UNUSED short events)
 	}
 	}
 
 
 	/* Read result from pipe */
 	/* Read result from pipe */
-	len = Resolve_Read(&Conf_Server[i].res_stat, readbuf, sizeof readbuf -1);
+	len = Resolve_Read(&Conf_Server[i].res_stat, dest_addrs, sizeof(dest_addrs));
 	if (len == 0)
 	if (len == 0)
 		return;
 		return;
-	
-	readbuf[len] = '\0';
-	LogDebug("Got result from resolver: \"%s\" (%u bytes read).", readbuf, len);
-	strlcpy( Conf_Server[i].ip, readbuf, sizeof( Conf_Server[i].ip ));
 
 
+	assert((len % sizeof(ng_ipaddr_t)) == 0);
+
+	LogDebug("Got result from resolver: %u structs (%u bytes).", len/sizeof(ng_ipaddr_t), len);
+
+	memset(&Conf_Server[i].dst_addr, 0, sizeof(&Conf_Server[i].dst_addr));
+	if (len > sizeof(ng_ipaddr_t)) {
+		/* more than one address for this hostname, remember them
+		 * in case first address is unreachable/not available */
+		len -= sizeof(ng_ipaddr_t);
+		if (len > sizeof(&Conf_Server[i].dst_addr)) {
+			len = sizeof(&Conf_Server[i].dst_addr);
+			Log(LOG_NOTICE, "Notice: Resolver returned more IP Addresses for host than we can handle,"
+					" additional addresses dropped");
+		}
+		memcpy(&Conf_Server[i].dst_addr, &dest_addrs[1], len);
+	}
 	/* connect() */
 	/* connect() */
-	New_Server(i);
+	New_Server(i, dest_addrs);
 } /* cb_Read_Forward_Lookup */
 } /* cb_Read_Forward_Lookup */
 
 
 
 
@@ -1598,10 +1693,10 @@ 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 %ld: \"%s\".", i, identptr);
-			Client_SetUser( c, identptr, true );
+			Log(LOG_INFO, "IDENT lookup for connection %d: \"%s\".", i, identptr);
+			Client_SetUser(c, identptr, true);
 		} else {
 		} else {
-			Log( LOG_INFO, "IDENT lookup for connection %ld: no result.", i );
+			Log(LOG_INFO, "IDENT lookup for connection %d: no result.", i);
 		}
 		}
 #endif
 #endif
 	}
 	}
@@ -1630,19 +1725,6 @@ Simple_Message( int Sock, const char *Msg )
 } /* Simple_Error */
 } /* Simple_Error */
 
 
 
 
-static int
-Count_Connections( struct sockaddr_in addr_in )
-{
-	int i, cnt;
-	
-	cnt = 0;
-	for( i = 0; i < Pool_Size; i++ ) {
-		if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].addr.sin_addr.s_addr == addr_in.sin_addr.s_addr )) cnt++;
-	}
-	return cnt;
-} /* Count_Connections */
-
-
 GLOBAL CLIENT *
 GLOBAL CLIENT *
 Conn_GetClient( CONN_ID Idx ) 
 Conn_GetClient( CONN_ID Idx ) 
 {
 {

+ 6 - 3
src/ngircd/conn.h

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: conn.h,v 1.42.2.1 2007/05/09 13:21:38 fw Exp $
+ * $Id: conn.h,v 1.46 2008/02/26 22:04:17 fw Exp $
  *
  *
  * Connection management (header)
  * Connection management (header)
  */
  */
@@ -38,6 +38,8 @@ typedef int CONN_ID;
 #include "defines.h"
 #include "defines.h"
 #include "resolve.h"
 #include "resolve.h"
 #include "array.h"
 #include "array.h"
+#include "tool.h"
+#include "ng_ipaddr.h"
 
 
 #ifdef ZLIB
 #ifdef ZLIB
 #include <zlib.h>
 #include <zlib.h>
@@ -54,11 +56,12 @@ typedef struct _ZipData
 typedef struct _Connection
 typedef struct _Connection
 {
 {
 	int sock;			/* Socket handle */
 	int sock;			/* Socket handle */
-	struct sockaddr_in addr;	/* Client address */
+	ng_ipaddr_t addr;		/* Client address */
 	RES_STAT res_stat;		/* Status of resolver process */
 	RES_STAT res_stat;		/* Status of resolver process */
 	char host[HOST_LEN];		/* Hostname */
 	char host[HOST_LEN];		/* Hostname */
 	array rbuf;			/* Read buffer */
 	array rbuf;			/* Read buffer */
 	array wbuf;			/* Write buffer */
 	array wbuf;			/* Write buffer */
+	time_t signon;			/* Signon ("connect") time */
 	time_t lastdata;		/* Last activity */
 	time_t lastdata;		/* Last activity */
 	time_t lastping;		/* Last PING */
 	time_t lastping;		/* Last PING */
 	time_t lastprivmsg;		/* Last PRIVMSG */
 	time_t lastprivmsg;		/* Last PRIVMSG */
@@ -83,7 +86,7 @@ GLOBAL long WCounter;
 GLOBAL void Conn_Init PARAMS((void ));
 GLOBAL void Conn_Init PARAMS((void ));
 GLOBAL void Conn_Exit PARAMS(( void ));
 GLOBAL void Conn_Exit PARAMS(( void ));
 
 
-GLOBAL int Conn_InitListeners PARAMS(( void ));
+GLOBAL unsigned int Conn_InitListeners PARAMS(( void ));
 GLOBAL void Conn_ExitListeners PARAMS(( void ));
 GLOBAL void Conn_ExitListeners PARAMS(( void ));
 
 
 GLOBAL void Conn_Handler PARAMS(( void ));
 GLOBAL void Conn_Handler PARAMS(( void ));

+ 6 - 5
src/ngircd/defines.h

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: defines.h,v 1.58.2.1 2007/05/18 22:11:19 alex Exp $
+ * $Id: defines.h,v 1.62 2007/11/21 12:16:36 alex Exp $
  */
  */
 
 
 
 
@@ -47,14 +47,15 @@
 
 
 #define CLIENT_ID_LEN 64		/* Max. length of an IRC ID; see RFC
 #define CLIENT_ID_LEN 64		/* Max. length of an IRC ID; see RFC
 					   RFC 2812 section 1.1 and 1.2.1 */
 					   RFC 2812 section 1.1 and 1.2.1 */
-#define CLIENT_NICK_LEN 10		/* Max. nick length, see. RFC 2812
-					   section 1.2.1 */
+#define CLIENT_NICK_LEN_DEFAULT 10	/* Default nick length, see. RFC 2812
+					 * section 1.2.1 */
+#define CLIENT_NICK_LEN 32		/* Maximum nick name length */
 #define CLIENT_PASS_LEN 21		/* Max. password length */
 #define CLIENT_PASS_LEN 21		/* Max. password length */
 #define CLIENT_USER_LEN 10		/* Max. length of user name ("login")
 #define CLIENT_USER_LEN 10		/* Max. length of user name ("login")
 					   see RFC 2812, section 1.2.1 */
 					   see RFC 2812, section 1.2.1 */
 #define CLIENT_NAME_LEN 32		/* Max. length of "real names" */
 #define CLIENT_NAME_LEN 32		/* Max. length of "real names" */
 #define CLIENT_HOST_LEN 64		/* Max. host name length */
 #define CLIENT_HOST_LEN 64		/* Max. host name length */
-#define CLIENT_MODE_LEN 8		/* Max. lenth of all client modes */
+#define CLIENT_MODE_LEN 9		/* Max. lenth of all client modes */
 #define CLIENT_INFO_LEN 64		/* Max. length of server info texts */
 #define CLIENT_INFO_LEN 64		/* Max. length of server info texts */
 #define CLIENT_AWAY_LEN 128		/* Max. length of away messages */
 #define CLIENT_AWAY_LEN 128		/* Max. length of away messages */
 #define CLIENT_FLAGS_LEN 100		/* Max. length of client flags */
 #define CLIENT_FLAGS_LEN 100		/* Max. length of client flags */
@@ -81,7 +82,7 @@
 					   protocol, see doc/Protocol.txt */
 					   protocol, see doc/Protocol.txt */
 
 
 #ifdef IRCPLUS
 #ifdef IRCPLUS
-# define IRCPLUSFLAGS "CL"		/* Standard IRC+ flags */
+# define IRCPLUSFLAGS "CHL"		/* Standard IRC+ flags */
 #endif
 #endif
 
 
 #define STARTUP_DELAY 1			/* Delay outgoing connections n seconds
 #define STARTUP_DELAY 1			/* Delay outgoing connections n seconds

+ 1 - 1
src/ngircd/hash.c

@@ -14,7 +14,7 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: hash.c,v 1.12.2.1 2006/12/02 13:18:22 fw Exp $";
+static char UNUSED id[] = "$Id: hash.c,v 1.13 2006/10/06 21:23:47 fw Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>

+ 1 - 1
src/ngircd/hash.h

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: hash.h,v 1.5.4.1 2006/12/02 13:18:22 fw Exp $
+ * $Id: hash.h,v 1.6 2006/10/06 21:23:47 fw Exp $
  *
  *
  * Hash calculation (header)
  * Hash calculation (header)
  */
  */

File diff suppressed because it is too large
+ 486 - 513
src/ngircd/io.c


+ 1 - 1
src/ngircd/io.h

@@ -7,7 +7,7 @@
  *
  *
  * I/O abstraction interface header
  * I/O abstraction interface header
  *
  *
- * $Id: io.h,v 1.3.2.1 2007/04/03 22:08:52 fw Exp $
+ * $Id: io.h,v 1.4 2006/12/25 22:53:52 alex Exp $
  */
  */
 
 
 #ifndef io_H_included
 #ifndef io_H_included

+ 206 - 179
src/ngircd/irc-channel.c

@@ -14,7 +14,7 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: irc-channel.c,v 1.35.2.4 2007/07/31 18:54:30 alex Exp $";
+static char UNUSED id[] = "$Id: irc-channel.c,v 1.45 2008/02/24 18:57:38 fw Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>
@@ -40,14 +40,147 @@ static char UNUSED id[] = "$Id: irc-channel.c,v 1.35.2.4 2007/07/31 18:54:30 ale
 #include "irc-channel.h"
 #include "irc-channel.h"
 
 
 
 
+/*
+ * RFC 2812, (3.2.1 Join message Command):
+ *  Note that this message
+ *  accepts a special argument ("0"), which is a special request to leave all
+ *  channels the user is currently a member of. The server will process this
+ *  message as if the user had sent a PART command (See Section 3.2.2) for
+ *  each channel he is a member of.
+ */
+static bool
+part_from_all_channels(CLIENT* client, CLIENT *target)
+{
+	CL2CHAN *cl2chan;
+	CHANNEL *chan;
+
+	while ((cl2chan = Channel_FirstChannelOf(target))) {
+		chan = Channel_GetChannel(cl2chan);
+		assert( chan != NULL );
+		Channel_Part(target, client, Channel_Name(chan), Client_ID(target));
+	}
+	return CONNECTED;
+}
+
+
+static bool
+join_allowed(CLIENT *Client, CLIENT *target, CHANNEL *chan,
+			const char *channame, const char *key)
+{
+	bool is_invited, is_banned;
+	const char *channel_modes;
+
+	is_banned = Lists_Check(Channel_GetListBans(chan), target);
+	is_invited = Lists_Check(Channel_GetListInvites(chan), target);
+
+	if (is_banned && !is_invited) {
+		IRC_WriteStrClient(Client, ERR_BANNEDFROMCHAN_MSG, Client_ID(Client), channame);
+		return false;
+	}
+
+	channel_modes = Channel_Modes(chan);
+	if ((strchr(channel_modes, 'i')) && !is_invited) {
+		/* Channel is "invite-only" (and Client wasn't invited) */
+		IRC_WriteStrClient(Client, ERR_INVITEONLYCHAN_MSG, Client_ID(Client), channame);
+		return false;
+	}
+
+	/* Is the channel protected by a key? */
+	if (strchr(channel_modes, 'k') &&
+		strcmp(Channel_Key(chan), key ? key : ""))
+	{
+		IRC_WriteStrClient(Client, ERR_BADCHANNELKEY_MSG, Client_ID(Client), channame);
+		return false;
+	}
+	/* Are there already too many members? */
+	if ((strchr(channel_modes, 'l')) && (Channel_MaxUsers(chan) <= Channel_MemberCount(chan))) {
+		IRC_WriteStrClient(Client, ERR_CHANNELISFULL_MSG, Client_ID(Client), channame);
+		return false;
+	}
+	return true;
+}
+
+
+static void
+join_set_channelmodes(CHANNEL *chan, CLIENT *target, const char *flags)
+{
+	if (flags) {
+		while (*flags) {
+			Channel_UserModeAdd(chan, target, *flags);
+			flags++;
+		}
+	}
+
+	/* If channel persistent and client is ircop: make client chanop */
+	if (strchr(Channel_Modes(chan), 'P') && strchr(Client_Modes(target), 'o'))
+		Channel_UserModeAdd(chan, target, 'o');
+}
+
+
+static void
+join_forward(CLIENT *Client, CLIENT *target, CHANNEL *chan,
+					const char *channame)
+{
+	char modes[8];
+
+	strlcpy(&modes[1], Channel_UserModes(chan, target), sizeof(modes) - 1);
+
+	if (modes[1])
+		modes[0] = 0x7;
+	else
+		modes[0] = '\0';
+	/* forward to other servers */
+	IRC_WriteStrServersPrefix(Client, target, "JOIN :%s%s", channame, modes);
+
+	/* tell users in this channel about the new client */
+	IRC_WriteStrChannelPrefix(Client, chan, target, false, "JOIN :%s", channame);
+	if (modes[1])
+		IRC_WriteStrChannelPrefix(Client, chan, target, false, "MODE %s +%s %s",
+						channame, &modes[1], Client_ID(target));
+}
+
+
+static bool
+join_send_topic(CLIENT *Client, CLIENT *target, CHANNEL *chan,
+					const char *channame)
+{
+	const char *topic;
+
+	if (Client_Type(Client) != CLIENT_USER)
+		return true;
+	/* acknowledge join */
+	if (!IRC_WriteStrClientPrefix(Client, target, "JOIN :%s", channame))
+		return false;
+
+	/* Send topic to client, if any */
+	topic = Channel_Topic(chan);
+	assert(topic != NULL);
+	if (*topic) {
+		if (!IRC_WriteStrClient(Client, RPL_TOPIC_MSG,
+			Client_ID(Client), channame, topic))
+				return false;
+#ifndef STRICT_RFC
+		if (!IRC_WriteStrClient(Client, RPL_TOPICSETBY_MSG,
+			Client_ID(Client), channame,
+			Channel_TopicWho(chan),
+			Channel_TopicTime(chan)))
+				return false;
+#endif
+	}
+	/* send list of channel members to client */
+	if (!IRC_Send_NAMES(Client, chan))
+		return false;
+	return IRC_WriteStrClient(Client, RPL_ENDOFNAMES_MSG, Client_ID(Client), Channel_Name(chan));
+}
+
+
 GLOBAL bool
 GLOBAL bool
 IRC_JOIN( CLIENT *Client, REQUEST *Req )
 IRC_JOIN( CLIENT *Client, REQUEST *Req )
 {
 {
-	char *channame, *channame_ptr, *key, *key_ptr, *flags, *topic, modes[8];
-	bool is_new_chan, is_invited, is_banned;
+	char *channame, *channame_ptr, *key, *key_ptr, *flags;
 	CLIENT *target;
 	CLIENT *target;
 	CHANNEL *chan;
 	CHANNEL *chan;
-	
+
 	assert( Client != NULL );
 	assert( Client != NULL );
 	assert( Req != NULL );
 	assert( Req != NULL );
 
 
@@ -57,190 +190,83 @@ IRC_JOIN( CLIENT *Client, REQUEST *Req )
 					  Client_ID(Client), Req->command);
 					  Client_ID(Client), Req->command);
 
 
 	/* Who is the sender? */
 	/* Who is the sender? */
-	if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
-	else target = Client;
-	if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
+	if (Client_Type(Client) == CLIENT_SERVER)
+		target = Client_Search(Req->prefix);
+	else
+		target = Client;
+
+	if (!target)
+		return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID(Client), Req->prefix);
+
+	/* Is argument "0"? */
+	if (Req->argc == 1 && !strncmp("0", Req->argv[0], 2))
+		return part_from_all_channels(Client, target);
 
 
 	/* Are channel keys given? */
 	/* Are channel keys given? */
 	if (Req->argc > 1) {
 	if (Req->argc > 1) {
 		key = Req->argv[1];
 		key = Req->argv[1];
 		key_ptr = strchr(key, ',');
 		key_ptr = strchr(key, ',');
 		if (key_ptr) *key_ptr = '\0';
 		if (key_ptr) *key_ptr = '\0';
-	}
-	else
+	} else {
 		key = key_ptr = NULL;
 		key = key_ptr = NULL;
-
+	}
 	channame = Req->argv[0];
 	channame = Req->argv[0];
 	channame_ptr = strchr(channame, ',');
 	channame_ptr = strchr(channame, ',');
 	if (channame_ptr) *channame_ptr = '\0';
 	if (channame_ptr) *channame_ptr = '\0';
 
 
-	/* Channel-Namen durchgehen */
-	while (channame)
-	{
-		chan = NULL; flags = NULL;
-
-		/* wird der Channel neu angelegt? */
-		if( Channel_Search( channame )) {
-			is_new_chan = false;
-		} else {
-			if (Conf_PredefChannelsOnly) { /* this server does not allow creation of channels */
-				IRC_WriteStrClient( Client, ERR_BANNEDFROMCHAN_MSG, Client_ID( Client ), channame );
-				/* Try next name, if any */
-				channame = strchr(channame, ',');
-				continue;
-			}
-			is_new_chan = true;
-		}
+	while (channame) {
+		flags = NULL;
 
 
-		/* Hat ein Server Channel-User-Modes uebergeben? */
-		if( Client_Type( Client ) == CLIENT_SERVER )
-		{
-			/* Channel-Flags extrahieren */
-			flags = strchr( channame, 0x7 );
-			if( flags )
-			{
+		/* Did the server include channel-user-modes? */
+		if (Client_Type(Client) == CLIENT_SERVER) {
+			flags = strchr(channame, 0x7);
+			if (flags) {
 				*flags = '\0';
 				*flags = '\0';
 				flags++;
 				flags++;
 			}
 			}
 		}
 		}
 
 
+		chan = Channel_Search(channame);
+		if (!chan && Conf_PredefChannelsOnly) {
+			 /* channel must be created, but server does not allow this */
+			IRC_WriteStrClient(Client, ERR_BANNEDFROMCHAN_MSG, Client_ID(Client), channame);
+			break;
+		}
+
 		/* Local client? */
 		/* Local client? */
-		if( Client_Type( Client ) == CLIENT_USER )
-		{
+		if (Client_Type(Client) == CLIENT_USER) {
 			/* Test if the user has reached his maximum channel count */
 			/* Test if the user has reached his maximum channel count */
-			if(( Conf_MaxJoins > 0 ) && ( Channel_CountForUser( Client ) >= Conf_MaxJoins ))
-				return IRC_WriteStrClient( Client, ERR_TOOMANYCHANNELS_MSG,
-							Client_ID( Client ), channame );
-
-			/* Existiert der Channel bereits, oder wird er im Moment neu erzeugt? */
-			if( is_new_chan )
-			{
-				/* Erster User im Channel: Operator-Flag setzen */
+			if ((Conf_MaxJoins > 0) && (Channel_CountForUser(Client) >= Conf_MaxJoins))
+				return IRC_WriteStrClient(Client, ERR_TOOMANYCHANNELS_MSG,
+							Client_ID(Client), channame);
+			if (!chan) /* New Channel: first user will be channel operator */
 				flags = "o";
 				flags = "o";
-			}
 			else
 			else
-			{
-				/* Existierenden Channel suchen */
-				chan = Channel_Search( channame );
-				assert( chan != NULL );
-
-				is_banned = Lists_Check(Channel_GetListBans(chan), target );
-				is_invited = Lists_Check(Channel_GetListInvites(chan), target );
-
-				/* Testen, ob Client gebanned ist */
-				if(( is_banned == true) &&  ( is_invited == false ))
-				{
-					/* Client ist gebanned (und nicht invited): */
-					IRC_WriteStrClient( Client, ERR_BANNEDFROMCHAN_MSG, Client_ID( Client ), channame );
-
-					/* Try next name, if any */
-					channame = strchr(channame, ',');
-					continue;
-				}
-
-				/* Ist der Channel "invite-only"? */
-				if(( strchr( Channel_Modes( chan ), 'i' )) && ( is_invited == false ))
-				{
-					/* Channel ist "invite-only" und Client wurde nicht invited: */
-					IRC_WriteStrClient( Client, ERR_INVITEONLYCHAN_MSG, Client_ID( Client ), channame );
-
-					/* Try next name, if any */
-					channame = strchr(channame, ',');
-					continue;
-				}
-
-				/* Is the channel protected by a key? */
-				if(( strchr( Channel_Modes( chan ), 'k' )) && ( strcmp( Channel_Key( chan ), key ? key : "" ) != 0 ))
-				{
-					/* Bad channel key! */
-					IRC_WriteStrClient( Client, ERR_BADCHANNELKEY_MSG, Client_ID( Client ), channame );
-
-					/* Try next name, if any */
-					channame = strchr(channame, ',');
-					continue;
-				}
-
-				/* Are there already too many members? */
-				if(( strchr( Channel_Modes( chan ), 'l' )) && ( Channel_MaxUsers( chan ) <= Channel_MemberCount( chan )))
-				{
-					/* Bad channel key! */
-					IRC_WriteStrClient( Client, ERR_CHANNELISFULL_MSG, Client_ID( Client ), channame );
-
-					/* Try next name, if any */
-					channame = strchr(channame, ',');
-					continue;
-				}
-			}
-		}
-		else
-		{
+				if (!join_allowed(Client, target, chan, channame, key))
+					break;
+		} else {
 			/* Remote server: we don't need to know whether the
 			/* Remote server: we don't need to know whether the
 			 * client is invited or not, but we have to make sure
 			 * client is invited or not, but we have to make sure
 			 * that the "one shot" entries (generated by INVITE
 			 * that the "one shot" entries (generated by INVITE
 			 * commands) in this list become deleted when a user
 			 * commands) in this list become deleted when a user
 			 * joins a channel this way. */
 			 * joins a channel this way. */
-			chan = Channel_Search( channame );
-			if( chan != NULL ) (void)Lists_Check(Channel_GetListInvites(chan), target);
-		}
-
-		/* Channel joinen (und ggf. anlegen) */
-		if( ! Channel_Join( target, channame ))
-		{
-			/* naechsten Namen ermitteln */
-			channame = strchr(channame, ',');
-			continue;
+			if (chan) (void)Lists_Check(Channel_GetListInvites(chan), target);
 		}
 		}
-		if( ! chan ) chan = Channel_Search( channame );
-		assert( chan != NULL );
 
 
-		/* Modes setzen (wenn vorhanden) */
-		while( flags && *flags )
-		{
-			Channel_UserModeAdd( chan, target, *flags );
-			flags++;
-		}
+		/* Join channel (and create channel if it doesn't exist) */
+		if (!Channel_Join(target, channame))
+			break;
 
 
-		/* Wenn persistenter Channel und IRC-Operator: zum Channel-OP machen */
-		if(( strchr( Channel_Modes( chan ), 'P' )) && ( strchr( Client_Modes( target ), 'o' ))) Channel_UserModeAdd( chan, target, 'o' );
+		if (!chan) /* channel is new; it has been created above */
+			chan = Channel_Search(channame);
+		assert(chan != NULL);
 
 
-		/* Muessen Modes an andere Server gemeldet werden? */
-		strlcpy( &modes[1], Channel_UserModes( chan, target ), sizeof( modes ) - 1 );
-		if( modes[1] ) modes[0] = 0x7;
-		else modes[0] = '\0';
+		join_set_channelmodes(chan, target, flags);
 
 
-		/* An andere Server weiterleiten */
-		IRC_WriteStrServersPrefix( Client, target, "JOIN :%s%s", channame, modes );
+		join_forward(Client, target, chan, channame);
 
 
-		/* im Channel bekannt machen */
-		IRC_WriteStrChannelPrefix( Client, chan, target, false, "JOIN :%s", channame );
-		if( modes[1] )
-		{
-			/* Modes im Channel bekannt machen */
-			IRC_WriteStrChannelPrefix( Client, chan, target, false, "MODE %s +%s %s", channame, &modes[1], Client_ID( target ));
-		}
-
-		if( Client_Type( Client ) == CLIENT_USER )
-		{
-			/* an Client bestaetigen */
-			IRC_WriteStrClientPrefix( Client, target, "JOIN :%s", channame );
-
-			/* Send topic to client, if any */
-			topic = Channel_Topic(chan);
-			if (*topic) {
-				IRC_WriteStrClient(Client, RPL_TOPIC_MSG,
-					Client_ID(Client), channame, topic);
-#ifndef STRICT_RFC
-				IRC_WriteStrClient(Client, RPL_TOPICSETBY_MSG,
-					Client_ID(Client), channame,
-					Channel_TopicWho(chan),
-					Channel_TopicTime(chan));
-#endif
-			}
-
-			/* Mitglieder an Client Melden */
-			IRC_Send_NAMES( Client, chan );
-			IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), Channel_Name( chan ));
-		}
+		if (!join_send_topic(Client, target, chan, channame))
+			break; /* write error */
 
 
 		/* next channel? */
 		/* next channel? */
 		channame = channame_ptr;
 		channame = channame_ptr;
@@ -260,36 +286,37 @@ IRC_JOIN( CLIENT *Client, REQUEST *Req )
 } /* IRC_JOIN */
 } /* IRC_JOIN */
 
 
 
 
+/**
+ * Handler for the IRC "PART" command.
+ */
 GLOBAL bool
 GLOBAL bool
-IRC_PART( CLIENT *Client, REQUEST *Req )
+IRC_PART(CLIENT * Client, REQUEST * Req)
 {
 {
 	CLIENT *target;
 	CLIENT *target;
 	char *chan;
 	char *chan;
 
 
-	assert( Client != NULL );
-	assert( Req != NULL );
-
-	/* Falsche Anzahl Parameter? */
-	if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
-
-	/* Wer ist der Absender? */
-	if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
-	else target = Client;
-	if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
+	assert(Client != NULL);
+	assert(Req != NULL);
 
 
-	/* Channel-Namen durchgehen */
-	chan = strtok( Req->argv[0], "," );
-	while( chan )
-	{
-		if( ! Channel_Part( target, Client, chan, Req->argc > 1 ? Req->argv[1] : Client_ID( target )))
-		{
-			/* naechsten Namen ermitteln */
-			chan = strtok( NULL, "," );
-			continue;
-		}
+	if (Req->argc < 1 || Req->argc > 2)
+		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
+					  Client_ID(Client), Req->command);
 
 
-		/* naechsten Namen ermitteln */
-		chan = strtok( NULL, "," );
+	/* Get the sender */
+	if (Client_Type(Client) == CLIENT_SERVER)
+		target = Client_Search(Req->prefix);
+	else
+		target = Client;
+	if (!target)
+		return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
+					  Client_ID(Client), Req->prefix);
+
+	/* Loop over all the given channel names */
+	chan = strtok(Req->argv[0], ",");
+	while (chan) {
+		Channel_Part(target, Client, chan,
+			     Req->argc > 1 ? Req->argv[1] : Client_ID(target));
+		chan = strtok(NULL, ",");
 	}
 	}
 	return CONNECTED;
 	return CONNECTED;
 } /* IRC_PART */
 } /* IRC_PART */

+ 389 - 165
src/ngircd/irc-info.c

@@ -1,6 +1,6 @@
 /*
 /*
  * ngIRCd -- The Next Generation IRC Daemon
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2005 Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2008 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
@@ -14,8 +14,6 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: irc-info.c,v 1.33.2.2 2006/12/02 14:26:53 fw Exp $";
-
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>
 #include <errno.h>
 #include <errno.h>
@@ -25,7 +23,6 @@ static char UNUSED id[] = "$Id: irc-info.c,v 1.33.2.2 2006/12/02 14:26:53 fw Exp
 #include <strings.h>
 #include <strings.h>
 
 
 #include "ngircd.h"
 #include "ngircd.h"
-#include "cvs-version.h"
 #include "conn-func.h"
 #include "conn-func.h"
 #include "conn-zip.h"
 #include "conn-zip.h"
 #include "client.h"
 #include "client.h"
@@ -35,6 +32,7 @@ static char UNUSED id[] = "$Id: irc-info.c,v 1.33.2.2 2006/12/02 14:26:53 fw Exp
 #include "defines.h"
 #include "defines.h"
 #include "log.h"
 #include "log.h"
 #include "messages.h"
 #include "messages.h"
+#include "match.h"
 #include "tool.h"
 #include "tool.h"
 #include "parse.h"
 #include "parse.h"
 #include "irc-write.h"
 #include "irc-write.h"
@@ -84,6 +82,71 @@ IRC_ADMIN(CLIENT *Client, REQUEST *Req )
 } /* IRC_ADMIN */
 } /* IRC_ADMIN */
 
 
 
 
+/**
+ * Handler for the IRC command "INFO".
+ * See RFC 2812 section 3.4.10.
+ */
+GLOBAL bool
+IRC_INFO(CLIENT * Client, REQUEST * Req)
+{
+	CLIENT *target, *prefix;
+	char msg[510];
+
+	assert(Client != NULL);
+	assert(Req != NULL);
+
+	/* Wrong number of parameters? */
+	if (Req->argc > 1)
+		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
+					  Client_ID(Client), Req->command);
+
+	/* Determine prefix */
+	if (Client_Type(Client) == CLIENT_SERVER)
+		prefix = Client_Search(Req->prefix);
+	else
+		prefix = Client;
+	if (!prefix)
+		return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
+					  Client_ID(Client), Req->prefix);
+
+	/* Look for a target */
+	if (Req->argc > 0)
+		target = Client_Search(Req->argv[0]);
+	else
+		target = Client_ThisServer();
+	
+	/* Make sure that the target is a server */
+	if (target && Client_Type(target) != CLIENT_SERVER)
+		target = Client_Introducer(target);
+
+	if (!target)
+		return IRC_WriteStrClient(prefix, ERR_NOSUCHSERVER_MSG,
+					  Client_ID(prefix), Req->argv[0]);
+
+	/* Pass on to another server? */
+	if (target != Client_ThisServer()) {
+		IRC_WriteStrClientPrefix(target, prefix, "INFO %s",
+					 Req->argv[0]);
+		return CONNECTED;
+	}
+
+	if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix),
+				NGIRCd_Version))
+		return DISCONNECTED;
+	
+	strlcpy(msg, "Server has been started ", sizeof(msg));
+	strlcat(msg, NGIRCd_StartStr, sizeof(msg));
+	if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), msg))
+		return DISCONNECTED;
+
+	if (!IRC_WriteStrClient(Client, RPL_ENDOFINFO_MSG, Client_ID(prefix)))
+		return DISCONNECTED;
+
+	IRC_SetPenalty(Client, 2);
+	return CONNECTED;
+} /* IRC_INFO */
+
+
 GLOBAL bool
 GLOBAL bool
 IRC_ISON( CLIENT *Client, REQUEST *Req )
 IRC_ISON( CLIENT *Client, REQUEST *Req )
 {
 {
@@ -335,6 +398,41 @@ IRC_NAMES( CLIENT *Client, REQUEST *Req )
 } /* IRC_NAMES */
 } /* IRC_NAMES */
 
 
 
 
+static unsigned int
+t_diff(time_t *t, const time_t div)
+{
+	time_t diff, remain;
+
+	diff = *t / div;
+
+	remain = diff * div;
+	*t -= remain;
+
+	return diff;
+}
+
+
+static unsigned int
+uptime_days(time_t *now)
+{
+	return t_diff(now, 60 * 60 * 24);
+}
+
+
+static unsigned int
+uptime_hrs(time_t *now)
+{
+	return t_diff(now, 60 * 60);
+}
+
+
+static unsigned int
+uptime_mins(time_t *now)
+{
+	 return t_diff(now, 60);
+}
+
+
 GLOBAL bool
 GLOBAL bool
 IRC_STATS( CLIENT *Client, REQUEST *Req )
 IRC_STATS( CLIENT *Client, REQUEST *Req )
 {
 {
@@ -342,78 +440,110 @@ IRC_STATS( CLIENT *Client, REQUEST *Req )
 	CONN_ID con;
 	CONN_ID con;
 	char query;
 	char query;
 	COMMAND *cmd;
 	COMMAND *cmd;
+	time_t time_now;
+	unsigned int days, hrs, mins;
 
 
 	assert( Client != NULL );
 	assert( Client != NULL );
 	assert( Req != NULL );
 	assert( Req != NULL );
 
 
 	/* Falsche Anzahl Parameter? */
 	/* Falsche Anzahl Parameter? */
-	if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
+	if (Req->argc > 2)
+		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command);
 
 
 	/* From aus Prefix ermitteln */
 	/* From aus Prefix ermitteln */
-	if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
-	else from = Client;
-	if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
+	if (Client_Type(Client) == CLIENT_SERVER)
+		from = Client_Search(Req->prefix);
+	else
+		from = Client;
 
 
-	if( Req->argc == 2 )
-	{
+	if (! from)
+		return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix);
+
+	if (Req->argc == 2) {
 		/* an anderen Server forwarden */
 		/* an anderen Server forwarden */
 		target = Client_Search( Req->argv[1] );
 		target = Client_Search( Req->argv[1] );
-		if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
+		if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER ))
+			return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
 
 
-		if( target != Client_ThisServer( ))
-		{
+		if( target != Client_ThisServer()) {
 			/* Ok, anderer Server ist das Ziel: forwarden */
 			/* Ok, anderer Server ist das Ziel: forwarden */
 			return IRC_WriteStrClientPrefix( target, from, "STATS %s %s", Req->argv[0], Req->argv[1] );
 			return IRC_WriteStrClientPrefix( target, from, "STATS %s %s", Req->argv[0], Req->argv[1] );
 		}
 		}
 	}
 	}
 
 
-	if( Req->argc > 0 ) query = Req->argv[0][0] ? Req->argv[0][0] : '*';
-	else query = '*';
+	if (Req->argc > 0)
+		query = Req->argv[0][0] ? Req->argv[0][0] : '*';
+	else
+		query = '*';
 
 
-	switch ( query )
-	{
+	switch (query) {
 		case 'l':	/* Links */
 		case 'l':	/* Links */
 		case 'L':
 		case 'L':
-			con = Conn_First( );
-			while( con != NONE )
-			{
-				cl = Conn_GetClient( con );
-				if( cl && (( Client_Type( cl ) == CLIENT_SERVER ) || ( cl == Client )))
-				{
+			time_now = time(NULL);
+			for (con = Conn_First(); con != NONE ;con = Conn_Next(con)) {
+				cl = Conn_GetClient(con);
+				if (!cl)
+					continue;
+				if ((Client_Type(cl) == CLIENT_SERVER) || (cl == Client)) {
 					/* Server link or our own connection */
 					/* Server link or our own connection */
 #ifdef ZLIB
 #ifdef ZLIB
-					if( Conn_Options( con ) & CONN_ZIP )
-					{
-						if( ! IRC_WriteStrClient( from, RPL_STATSLINKINFOZIP_MSG, Client_ID( from ), Client_Mask( cl ), Conn_SendQ( con ), Conn_SendMsg( con ), Zip_SendBytes( con ), Conn_SendBytes( con ), Conn_RecvMsg( con ), Zip_RecvBytes( con ), Conn_RecvBytes( con ), (long)( time( NULL ) - Conn_StartTime( con )))) return DISCONNECTED;
+					if (Conn_Options(con) & CONN_ZIP) {
+						if (!IRC_WriteStrClient(from, RPL_STATSLINKINFOZIP_MSG,
+							Client_ID(from), Client_Mask(cl), Conn_SendQ(con),
+							Conn_SendMsg(con), Zip_SendBytes(con), Conn_SendBytes(con),
+							Conn_RecvMsg(con), Zip_RecvBytes(con), Conn_RecvBytes(con), (long)(time_now - Conn_StartTime(con))))
+								return DISCONNECTED;
+						continue;
 					}
 					}
-					else
 #endif
 #endif
-					{
-						if( ! IRC_WriteStrClient( from, RPL_STATSLINKINFO_MSG, Client_ID( from ), Client_Mask( cl ), Conn_SendQ( con ), Conn_SendMsg( con ), Conn_SendBytes( con ), Conn_RecvMsg( con ), Conn_RecvBytes( con ), (long)( time( NULL ) - Conn_StartTime( con )))) return DISCONNECTED;
-					}
+					if (!IRC_WriteStrClient(from, RPL_STATSLINKINFO_MSG, Client_ID(from),
+						Client_Mask(cl), Conn_SendQ(con), Conn_SendMsg(con), Conn_SendBytes(con),
+						Conn_RecvMsg(con), Conn_RecvBytes(con), (long)(time_now - Conn_StartTime(con))))
+							return DISCONNECTED;
 				}
 				}
-				con = Conn_Next( con );
 			}
 			}
 			break;
 			break;
-		case 'm':	/* IRC-Befehle */
+		case 'm':	/* IRC-Commands */
 		case 'M':
 		case 'M':
 			cmd = Parse_GetCommandStruct( );
 			cmd = Parse_GetCommandStruct( );
-			while( cmd->name )
-			{
-				if( cmd->lcount > 0 || cmd->rcount > 0 )
-				{
-					if( ! IRC_WriteStrClient( from, RPL_STATSCOMMANDS_MSG, Client_ID( from ), cmd->name, cmd->lcount, cmd->bytes, cmd->rcount )) return DISCONNECTED;
-				}
-				cmd++;
+			for (; cmd->name ; cmd++) {
+				if (cmd->lcount == 0 && cmd->rcount == 0)
+					continue;
+				if (!IRC_WriteStrClient(from, RPL_STATSCOMMANDS_MSG, Client_ID(from),
+						cmd->name, cmd->lcount, cmd->bytes, cmd->rcount))
+							return DISCONNECTED;
 			}
 			}
 			break;
 			break;
+		case 'u':	/* server uptime */
+		case 'U':
+			time_now = time(NULL) - NGIRCd_Start;
+			days = uptime_days(&time_now);
+			hrs = uptime_hrs(&time_now);
+			mins = uptime_mins(&time_now);
+			if (!IRC_WriteStrClient(from, RPL_STATSUPTIME, Client_ID(from),
+					days, hrs, mins, (unsigned int) time_now))
+						return DISCONNECTED;
+			break;
 	}
 	}
 
 
-	IRC_SetPenalty( from, 2 );
-	return IRC_WriteStrClient( from, RPL_ENDOFSTATS_MSG, Client_ID( from ), query );
+	IRC_SetPenalty(from, 2);
+	return IRC_WriteStrClient(from, RPL_ENDOFSTATS_MSG, Client_ID(from), query);
 } /* IRC_STATS */
 } /* IRC_STATS */
 
 
 
 
+/**
+ * Handler for the IRC command "SUMMON".
+ * See RFC 2812 section 4.5. ngIRCd doesn't implement this functionality and
+ * therefore answers with ERR_SUMMONDISABLED.
+ */
+GLOBAL bool
+IRC_SUMMON(CLIENT * Client, REQUEST * Req)
+{
+	return IRC_WriteStrClient(Client, ERR_SUMMONDISABLED_MSG,
+				  Client_ID(Client), Req->command);
+} /* IRC_SUMMON */
+
+
 GLOBAL bool
 GLOBAL bool
 IRC_TIME( CLIENT *Client, REQUEST *Req )
 IRC_TIME( CLIENT *Client, REQUEST *Req )
 {
 {
@@ -491,13 +621,22 @@ IRC_USERHOST( CLIENT *Client, REQUEST *Req )
 } /* IRC_USERHOST */
 } /* IRC_USERHOST */
 
 
 
 
+/**
+ * Handler for the IRC command "USERS".
+ * See RFC 2812 section 4.6. As suggested there the command is disabled.
+ */
+GLOBAL bool
+IRC_USERS(CLIENT * Client, REQUEST * Req)
+{
+	return IRC_WriteStrClient(Client, ERR_USERSDISABLED_MSG,
+				  Client_ID(Client), Req->command);
+} /* IRC_USERS */
+
+
 GLOBAL bool
 GLOBAL bool
 IRC_VERSION( CLIENT *Client, REQUEST *Req )
 IRC_VERSION( CLIENT *Client, REQUEST *Req )
 {
 {
 	CLIENT *target, *prefix;
 	CLIENT *target, *prefix;
-#ifdef CVSDATE
-	char ver[12], vertxt[30];
-#endif
 
 
 	assert( Client != NULL );
 	assert( Client != NULL );
 	assert( Req != NULL );
 	assert( Req != NULL );
@@ -524,26 +663,110 @@ IRC_VERSION( CLIENT *Client, REQUEST *Req )
 		return CONNECTED;
 		return CONNECTED;
 	}
 	}
 
 
-	/* mit Versionsinfo antworten */
-	IRC_SetPenalty( Client, 1 );
-#ifdef CVSDATE
-	strlcpy( ver, CVSDATE, sizeof( ver ));
-	strncpy( ver + 4, ver + 5, 2 );
-	strncpy( ver + 6, ver + 8, 3 );
-	snprintf( vertxt, sizeof( vertxt ), "%s(%s)", PACKAGE_VERSION, ver );
-	return IRC_WriteStrClient( Client, RPL_VERSION_MSG, Client_ID( prefix ), PACKAGE_NAME, vertxt, NGIRCd_DebugLevel, Conf_ServerName, NGIRCd_VersionAddition );
-#else
-	return IRC_WriteStrClient( Client, RPL_VERSION_MSG, Client_ID( prefix ), PACKAGE_NAME, PACKAGE_VERSION, NGIRCd_DebugLevel, Conf_ServerName, NGIRCd_VersionAddition );
-#endif
+	/* send version information */
+	IRC_SetPenalty(Client, 1);
+	return IRC_WriteStrClient(Client, RPL_VERSION_MSG, Client_ID(prefix),
+				  PACKAGE_NAME, PACKAGE_VERSION,
+				  NGIRCd_DebugLevel, Conf_ServerName,
+				  NGIRCd_VersionAddition);
 } /* IRC_VERSION */
 } /* IRC_VERSION */
 
 
 
 
+static bool
+write_whoreply(CLIENT *Client, CLIENT *c, const char *channelname, const char *flags)
+{
+	return IRC_WriteStrClient(Client, RPL_WHOREPLY_MSG, Client_ID(Client), channelname,
+			Client_User(c), Client_Hostname(c), Client_ID(Client_Introducer(c)), Client_ID(c),
+			flags, Client_Hops(c), Client_Info(c));
+}
+
+
+static const char *
+who_flags_status(const char *client_modes)
+{
+	if (strchr(client_modes, 'a'))
+		return "G"; /* away */
+	return "H";
+}
+
+
+static const char *
+who_flags_qualifier(const char *chan_user_modes)
+{
+	if (strchr(chan_user_modes, 'o'))
+		return "@";
+	else if (strchr(chan_user_modes, 'v'))
+		return "+";
+	return "";
+}
+
+
+static bool
+IRC_Send_WHO(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
+{
+	bool is_visible, is_member, is_ircop;
+	CL2CHAN *cl2chan;
+	const char *client_modes;
+	const char *chan_user_modes;
+	char flags[8];
+	CLIENT *c;
+
+	assert( Client != NULL );
+	assert( Chan != NULL );
+
+	is_member = Channel_IsMemberOf(Chan, Client);
+
+	/* Secret channel? */
+	if (!is_member && strchr(Channel_Modes(Chan), 's'))
+		return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), Channel_Name(Chan));
+
+	cl2chan = Channel_FirstMember(Chan);
+	for (; cl2chan ; cl2chan = Channel_NextMember(Chan, cl2chan)) {
+		c = Channel_GetClient(cl2chan);
+
+		client_modes = Client_Modes(c);
+		is_ircop = strchr(client_modes, 'o') != NULL;
+		if (OnlyOps && !is_ircop)
+			continue;
+
+		is_visible = strchr(client_modes, 'i') == NULL;
+		if (is_member || is_visible) {
+			strcpy(flags, who_flags_status(client_modes));
+			if (is_ircop)
+				strlcat(flags, "*", sizeof(flags));
+
+			chan_user_modes = Channel_UserModes(Chan, c);
+			strlcat(flags, who_flags_qualifier(chan_user_modes), sizeof(flags));
+
+			if (!write_whoreply(Client, c, Channel_Name(Chan), flags))
+				return DISCONNECTED;
+		}
+	}
+	return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), Channel_Name(Chan));
+} /* IRC_Send_WHO */
+
+
+
+static bool
+MatchCaseInsensitive(const char *pattern, const char *searchme)
+{
+	char haystack[COMMAND_LEN];
+
+	strlcpy(haystack, searchme, sizeof(haystack));
+
+	ngt_LowerStr(haystack);
+
+	return Match(pattern, haystack);
+}
+
+
 GLOBAL bool
 GLOBAL bool
 IRC_WHO( CLIENT *Client, REQUEST *Req )
 IRC_WHO( CLIENT *Client, REQUEST *Req )
 {
 {
-	bool ok, only_ops;
-	char flags[8];
-	const char *ptr;
+	bool only_ops, have_arg, client_match;
+	const char *channelname, *client_modes, *chan_user_modes;
+	char pattern[COMMAND_LEN];
+	char flags[4];
 	CL2CHAN *cl2chan;
 	CL2CHAN *cl2chan;
 	CHANNEL *chan, *cn;
 	CHANNEL *chan, *cn;
 	CLIENT *c;
 	CLIENT *c;
@@ -551,78 +774,102 @@ IRC_WHO( CLIENT *Client, REQUEST *Req )
 	assert( Client != NULL );
 	assert( Client != NULL );
 	assert( Req != NULL );
 	assert( Req != NULL );
 
 
-	/* Falsche Anzahl Parameter? */
-	if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
+	if (Req->argc > 2)
+		return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
 
 
 	only_ops = false;
 	only_ops = false;
-	chan = NULL;
+	have_arg = false;
 
 
-	if( Req->argc == 2 )
-	{
-		/* Nur OPs anzeigen? */
-		if( strcmp( Req->argv[1], "o" ) == 0 ) only_ops = true;
+	if (Req->argc == 2) {
+		if (strcmp(Req->argv[1], "o") == 0)
+			only_ops = true;
 #ifdef STRICT_RFC
 #ifdef STRICT_RFC
-		else return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
+		else return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command);
 #endif
 #endif
 	}
 	}
 
 
-	if( Req->argc >= 1 )
-	{
-		/* wurde ein Channel oder Nick-Mask angegeben? */
-		chan = Channel_Search( Req->argv[0] );
+	IRC_SetPenalty(Client, 1);
+	if (Req->argc >= 1) { /* Channel or Mask. */
+		chan = Channel_Search(Req->argv[0]);
+		if (chan)
+			return IRC_Send_WHO(Client, chan, only_ops);
+		if (strcmp(Req->argv[0], "0") != 0) { /* RFC stupidity, same as no arguments */
+			have_arg = true;
+			strlcpy(pattern, Req->argv[0], sizeof(pattern));
+			ngt_LowerStr(pattern);
+			IRC_SetPenalty(Client, 3);
+		}
 	}
 	}
 
 
-	if( chan )
-	{
-		/* User eines Channels ausgeben */
-		if( ! IRC_Send_WHO( Client, chan, only_ops )) return DISCONNECTED;
-	}
+	for (c = Client_First(); c != NULL; c = Client_Next(c)) {
+		if (Client_Type(c) != CLIENT_USER)
+			continue;
+		 /*
+		  * RFC 2812, 3.6.1:
+		  * In the absence of the parameter, all visible (users who aren't
+		  * invisible (user mode +i) and who don't have a common channel
+		  * with the requesting client) are listed.
+		  *
+		  * The same result can be achieved by using a [sic] of "0"
+		  * or any wildcard which will end up matching every visible user.
+		  *
+		  * The [sic] passed to WHO is matched against users' host, server, real name and
+		  * nickname if the channel cannot be found.
+		  */
+		client_modes = Client_Modes(c);
+		if (strchr(client_modes, 'i'))
+			continue;
+
+		if (only_ops && !strchr(client_modes, 'o'))
+			continue;
+
+		if (have_arg) { /* match pattern against user host/server/name/nick */
+			client_match = MatchCaseInsensitive(pattern, Client_Hostname(c)); /* user's host */
+			if (!client_match)
+				client_match = MatchCaseInsensitive(pattern, Client_ID(Client_Introducer(c))); /* server */
+			if (!client_match)
+				client_match = Match(Req->argv[0], Client_Info(c)); /* realname */
+			if (!client_match)
+				client_match = MatchCaseInsensitive(pattern, Client_ID(c)); /* nick name */
+
+			if (!client_match) /* This isn't the client you're looking for */
+				continue;
+		}
 
 
-	c = Client_First( );
-	while( c )
-	{
-		if(( Client_Type( c ) == CLIENT_USER ) && ( ! strchr( Client_Modes( c ), 'i' )))
-		{
-			ok = false;
-			if( Req->argc == 0 ) ok = true;
-			else
-			{
-				if( strcasecmp( Req->argv[0], Client_ID( c )) == 0 ) ok = true;
-				else if( strcmp( Req->argv[0], "0" ) == 0 ) ok = true;
-			}
+		strcpy(flags, who_flags_status(client_modes));
 
 
-			if( ok && (( ! only_ops ) || ( strchr( Client_Modes( c ), 'o' ))))
-			{
-				/* Get flags */
-				strcpy( flags, "H" );
-				if( strchr( Client_Modes( c ), 'o' )) strlcat( flags, "*", sizeof( flags ));
-
-				/* Search suitable channel */
-				cl2chan = Channel_FirstChannelOf( c );
-				while( cl2chan )
-				{
-					cn = Channel_GetChannel( cl2chan );
-					if( Channel_IsMemberOf( cn, Client ) ||
-					    ! strchr( Channel_Modes( cn ), 's' ))
-					{
-						ptr = Channel_Name( cn );
-						break;
-					}
-					cl2chan = Channel_NextChannelOf( c, cl2chan );
-				}
-				if( ! cl2chan ) ptr = "*";
+		if (strchr(client_modes, 'o')) /* this client is an operator */
+			strlcat(flags, "*", sizeof(flags));
 
 
-				if( ! IRC_WriteStrClient( Client, RPL_WHOREPLY_MSG, Client_ID( Client ), ptr, Client_User( c ), Client_Hostname( c ), Client_ID( Client_Introducer( c )), Client_ID( c ), flags, Client_Hops( c ), Client_Info( c ))) return DISCONNECTED;
+		/* Search suitable channel */
+		cl2chan = Channel_FirstChannelOf(c);
+		while (cl2chan) {
+			cn = Channel_GetChannel(cl2chan);
+			if (Channel_IsMemberOf(cn, Client) ||
+				    !strchr(Channel_Modes(cn), 's'))
+			{
+				channelname = Channel_Name(cn);
+				break;
 			}
 			}
+			cl2chan = Channel_NextChannelOf(c, cl2chan);
 		}
 		}
-
-		/* naechster Client */
-		c = Client_Next( c );
+		if (cl2chan) {
+			chan = Channel_GetChannel(cl2chan);
+			chan_user_modes = Channel_UserModes(chan, c);
+			strlcat(flags, who_flags_qualifier(chan_user_modes), sizeof(flags));
+		} else
+			channelname = "*";
+
+		if (!write_whoreply(Client, c, channelname, flags))
+			return DISCONNECTED;
 	}
 	}
 
 
-	if( chan ) return IRC_WriteStrClient( Client, RPL_ENDOFWHO_MSG, Client_ID( Client ), Channel_Name( chan ));
-	else if( Req->argc == 0 ) return IRC_WriteStrClient( Client, RPL_ENDOFWHO_MSG, Client_ID( Client ), "*" );
-	else return IRC_WriteStrClient( Client, RPL_ENDOFWHO_MSG, Client_ID( Client ), Req->argv[0] );
+	if (Req->argc > 0)
+		channelname = Req->argv[0];
+	else
+		channelname = "*";
+
+	return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), channelname);
 } /* IRC_WHO */
 } /* IRC_WHO */
 
 
 
 
@@ -707,10 +954,13 @@ IRC_WHOIS( CLIENT *Client, REQUEST *Req )
 		if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
 		if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
 	}
 	}
 
 
-	/* Idle (only local clients) */
-	if( Client_Conn( c ) > NONE )
-	{
-		if( ! IRC_WriteStrClient( from, RPL_WHOISIDLE_MSG, Client_ID( from ), Client_ID( c ), Conn_GetIdle( Client_Conn ( c )))) return DISCONNECTED;
+	/* Idle and signon time (local clients only!) */
+	if (Client_Conn(c) > NONE ) {
+		if (! IRC_WriteStrClient(from, RPL_WHOISIDLE_MSG,
+			Client_ID(from), Client_ID(c),
+			(unsigned long)Conn_GetIdle(Client_Conn(c)),
+			(unsigned long)Conn_GetSignon(Client_Conn(c))))
+				return DISCONNECTED;
 	}
 	}
 
 
 	/* Away? */
 	/* Away? */
@@ -882,18 +1132,21 @@ IRC_Send_LUSERS( CLIENT *Client )
 } /* IRC_Send_LUSERS */
 } /* IRC_Send_LUSERS */
 
 
 
 
-static bool Show_MOTD_Start(CLIENT *Client)
+static bool
+Show_MOTD_Start(CLIENT *Client)
 {
 {
 	return IRC_WriteStrClient(Client, RPL_MOTDSTART_MSG,
 	return IRC_WriteStrClient(Client, RPL_MOTDSTART_MSG,
 		Client_ID( Client ), Client_ID( Client_ThisServer( )));
 		Client_ID( Client ), Client_ID( Client_ThisServer( )));
 }
 }
 
 
-static bool Show_MOTD_Sendline(CLIENT *Client, const char *msg)
+static bool
+Show_MOTD_Sendline(CLIENT *Client, const char *msg)
 {
 {
 	return IRC_WriteStrClient(Client, RPL_MOTD_MSG, Client_ID( Client ), msg);
 	return IRC_WriteStrClient(Client, RPL_MOTD_MSG, Client_ID( Client ), msg);
 }
 }
 
 
-static bool Show_MOTD_End(CLIENT *Client)
+static bool
+Show_MOTD_End(CLIENT *Client)
 {
 {
 	return IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ));
 	return IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ));
 }
 }
@@ -996,52 +1249,23 @@ IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan )
 } /* IRC_Send_NAMES */
 } /* IRC_Send_NAMES */
 
 
 
 
+
+/**
+ * Send the ISUPPORT numeric (005).
+ * This numeric indicates the features that are supported by this server.
+ * See <http://www.irc.org/tech_docs/005.html> for details.
+ */
 GLOBAL bool
 GLOBAL bool
-IRC_Send_WHO( CLIENT *Client, CHANNEL *Chan, bool OnlyOps )
+IRC_Send_ISUPPORT PARAMS((CLIENT * Client))
 {
 {
-	bool is_visible, is_member;
-	CL2CHAN *cl2chan;
-	char flags[8];
-	CLIENT *c;
-
-	assert( Client != NULL );
-	assert( Chan != NULL );
-
-	if( Channel_IsMemberOf( Chan, Client )) is_member = true;
-	else is_member = false;
-
-	/* Secret channel? */
-	if( ! is_member && strchr( Channel_Modes( Chan ), 's' )) return CONNECTED;
-
-	/* Alle Mitglieder suchen */
-	cl2chan = Channel_FirstMember( Chan );
-	while( cl2chan )
-	{
-		c = Channel_GetClient( cl2chan );
-
-		if( strchr( Client_Modes( c ), 'i' )) is_visible = false;
-		else is_visible = true;
-
-		if( is_member || is_visible )
-		{
-			/* Flags zusammenbasteln */
-			strcpy( flags, "H" );
-			if( strchr( Client_Modes( c ), 'o' )) strlcat( flags, "*", sizeof( flags ));
-			if( strchr( Channel_UserModes( Chan, c ), 'o' )) strlcat( flags, "@", sizeof( flags ));
-			else if( strchr( Channel_UserModes( Chan, c ), 'v' )) strlcat( flags, "+", sizeof( flags ));
-
-			/* ausgeben */
-			if(( ! OnlyOps ) || ( strchr( Client_Modes( c ), 'o' )))
-			{
-				if( ! IRC_WriteStrClient( Client, RPL_WHOREPLY_MSG, Client_ID( Client ), Channel_Name( Chan ), Client_User( c ), Client_Hostname( c ), Client_ID( Client_Introducer( c )), Client_ID( c ), flags, Client_Hops( c ), Client_Info( c ))) return DISCONNECTED;
-			}
-		}
-
-		/* naechstes Mitglied suchen */
-		cl2chan = Channel_NextMember( Chan, cl2chan );
-	}
-	return CONNECTED;
-} /* IRC_Send_WHO */
+	if (!IRC_WriteStrClient(Client, RPL_ISUPPORT1_MSG, Client_ID(Client),
+				Conf_MaxJoins))
+		return DISCONNECTED;
+	return IRC_WriteStrClient(Client, RPL_ISUPPORT2_MSG, Client_ID(Client),
+				  CHANNEL_NAME_LEN - 1, Conf_MaxNickLength - 1,
+				  COMMAND_LEN - 23, CLIENT_AWAY_LEN - 1,
+				  COMMAND_LEN - 113);
+} /* IRC_Send_ISUPPORT */
 
 
 
 
 /* -eof- */
 /* -eof- */

+ 5 - 2
src/ngircd/irc-info.h

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: irc-info.h,v 1.3 2005/03/19 18:43:48 fw Exp $
+ * $Id: irc-info.h,v 1.6 2008/02/17 13:26:42 alex Exp $
  *
  *
  * IRC info commands (header)
  * IRC info commands (header)
  */
  */
@@ -19,14 +19,17 @@
 
 
 
 
 GLOBAL bool IRC_ADMIN PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_ADMIN PARAMS(( CLIENT *Client, REQUEST *Req ));
+GLOBAL bool IRC_INFO PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_ISON PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_ISON PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_LINKS PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_LINKS PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_LUSERS PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_LUSERS PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_MOTD PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_MOTD PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_NAMES PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_NAMES PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_STATS PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_STATS PARAMS(( CLIENT *Client, REQUEST *Req ));
+GLOBAL bool IRC_SUMMON PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_TIME PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_TIME PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_USERHOST PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_USERHOST PARAMS(( CLIENT *Client, REQUEST *Req ));
+GLOBAL bool IRC_USERS PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_VERSION PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_VERSION PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_WHO PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_WHO PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_WHOIS PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_WHOIS PARAMS(( CLIENT *Client, REQUEST *Req ));
@@ -35,7 +38,7 @@ GLOBAL bool IRC_WHOWAS PARAMS(( CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_Send_LUSERS PARAMS(( CLIENT *Client ));
 GLOBAL bool IRC_Send_LUSERS PARAMS(( CLIENT *Client ));
 GLOBAL bool IRC_Send_NAMES PARAMS(( CLIENT *Client, CHANNEL *Chan ));
 GLOBAL bool IRC_Send_NAMES PARAMS(( CLIENT *Client, CHANNEL *Chan ));
 GLOBAL bool IRC_Show_MOTD PARAMS(( CLIENT *Client ));
 GLOBAL bool IRC_Show_MOTD PARAMS(( CLIENT *Client ));
-GLOBAL bool IRC_Send_WHO PARAMS(( CLIENT *Client, CHANNEL *Chan, bool OnlyOps ));
+GLOBAL bool IRC_Send_ISUPPORT PARAMS(( CLIENT *Client ));
 
 
 
 
 #endif
 #endif

+ 39 - 48
src/ngircd/irc-login.c

@@ -1,6 +1,6 @@
 /*
 /*
  * ngIRCd -- The Next Generation IRC Daemon
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2008 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
@@ -14,8 +14,6 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: irc-login.c,v 1.49.2.2 2006/12/02 14:26:53 fw Exp $";
-
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>
 #include <stdio.h>
 #include <stdio.h>
@@ -35,7 +33,6 @@ static char UNUSED id[] = "$Id: irc-login.c,v 1.49.2.2 2006/12/02 14:26:53 fw Ex
 #include "irc.h"
 #include "irc.h"
 #include "irc-info.h"
 #include "irc-info.h"
 #include "irc-write.h"
 #include "irc-write.h"
-#include "cvs-version.h"
 
 
 #include "exp.h"
 #include "exp.h"
 #include "irc-login.h"
 #include "irc-login.h"
@@ -507,7 +504,7 @@ IRC_PING(CLIENT *Client, REQUEST *Req)
 		Client_ID(from), Client_ID(Client));
 		Client_ID(from), Client_ID(Client));
 #else
 #else
 	/* Some clients depend on the argument being returned in the PONG
 	/* Some clients depend on the argument being returned in the PONG
-         * reply (not mentioned in any RFC, though) */
+	 * reply (not mentioned in any RFC, though) */
 	return IRC_WriteStrClient(Client, "PONG %s :%s",
 	return IRC_WriteStrClient(Client, "PONG %s :%s",
 		Client_ID(from), Req->argv[0]);
 		Client_ID(from), Req->argv[0]);
 #endif
 #endif
@@ -573,66 +570,60 @@ IRC_PONG(CLIENT *Client, REQUEST *Req)
 
 
 
 
 static bool
 static bool
-Hello_User( CLIENT *Client )
+Hello_User(CLIENT * Client)
 {
 {
-#ifdef CVSDATE
-	char ver[12], vertxt[30];
-#endif
-
-	assert( Client != NULL );
+	assert(Client != NULL);
 
 
 	/* Check password ... */
 	/* Check password ... */
-	if( strcmp( Client_Password( Client ), Conf_ServerPwd ) != 0 )
-	{
+	if (strcmp(Client_Password(Client), Conf_ServerPwd) != 0) {
 		/* Bad password! */
 		/* Bad password! */
-		Log( LOG_ERR, "User \"%s\" rejected (connection %d): Bad password!", Client_Mask( Client ), Client_Conn( Client ));
-		Conn_Close( Client_Conn( Client ), NULL, "Bad password", true);
+		Log(LOG_ERR,
+		    "User \"%s\" rejected (connection %d): Bad password!",
+		    Client_Mask(Client), Client_Conn(Client));
+		Conn_Close(Client_Conn(Client), NULL, "Bad password", true);
 		return DISCONNECTED;
 		return DISCONNECTED;
 	}
 	}
 
 
-	Log( LOG_NOTICE, "User \"%s\" registered (connection %d).", Client_Mask( Client ), Client_Conn( Client ));
+	Log(LOG_NOTICE, "User \"%s\" registered (connection %d).",
+	    Client_Mask(Client), Client_Conn(Client));
 
 
 	/* Inform other servers */
 	/* Inform other servers */
-	IRC_WriteStrServers( NULL, "NICK %s 1 %s %s 1 +%s :%s", Client_ID( Client ), Client_User( Client ), Client_Hostname( Client ), Client_Modes( Client ), Client_Info( Client ));
-
-	/* Welcome :-) */
-	if( ! IRC_WriteStrClient( Client, RPL_WELCOME_MSG, Client_ID( Client ), Client_Mask( Client ))) return false;
-
-	/* Version and system type */
-#ifdef CVSDATE
-	strlcpy( ver, CVSDATE, sizeof( ver ));
-	strncpy( ver + 4, ver + 5, 2 );
-	strncpy( ver + 6, ver + 8, 3 );
-	snprintf( vertxt, sizeof( vertxt ), "%s(%s)", PACKAGE_VERSION, ver );
-	if( ! IRC_WriteStrClient( Client, RPL_YOURHOST_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )), vertxt, TARGET_CPU, TARGET_VENDOR, TARGET_OS )) return false;
-#else
-	if( ! IRC_WriteStrClient( Client, RPL_YOURHOST_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )), PACKAGE_VERSION, TARGET_CPU, TARGET_VENDOR, TARGET_OS )) return false;
-#endif
-
-	if( ! IRC_WriteStrClient( Client, RPL_CREATED_MSG, Client_ID( Client ), NGIRCd_StartStr )) return false;
-#ifdef CVSDATE
-	if( ! IRC_WriteStrClient( Client, RPL_MYINFO_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )), vertxt, USERMODES, CHANMODES )) return false;	
-#else
-	if( ! IRC_WriteStrClient( Client, RPL_MYINFO_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )), PACKAGE_VERSION, USERMODES, CHANMODES )) return false;
-#endif
+	IRC_WriteStrServers(NULL, "NICK %s 1 %s %s 1 +%s :%s",
+			    Client_ID(Client), Client_User(Client),
+			    Client_Hostname(Client), Client_Modes(Client),
+			    Client_Info(Client));
+
+	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),
 	/* Features supported by this server (005 numeric, ISUPPORT),
 	 * see <http://www.irc.org/tech_docs/005.html> for details. */
 	 * see <http://www.irc.org/tech_docs/005.html> for details. */
-	if (! IRC_WriteStrClient(Client, RPL_ISUPPORT1_MSG, Client_ID(Client),
-			Conf_MaxJoins))
-		return DISCONNECTED;
-	if (! IRC_WriteStrClient(Client, RPL_ISUPPORT2_MSG, Client_ID(Client),
-			CHANNEL_NAME_LEN-1, CLIENT_NICK_LEN-1, COMMAND_LEN-23,
-			CLIENT_AWAY_LEN-1, COMMAND_LEN-113))
+	if (!IRC_Send_ISUPPORT(Client))
 		return DISCONNECTED;
 		return DISCONNECTED;
 
 
-	Client_SetType( Client, CLIENT_USER );
+	Client_SetType(Client, CLIENT_USER);
 
 
-	if( ! IRC_Send_LUSERS( Client )) return DISCONNECTED;
-	if( ! IRC_Show_MOTD( Client )) return DISCONNECTED;
+	if (!IRC_Send_LUSERS(Client))
+		return DISCONNECTED;
+	if (!IRC_Show_MOTD(Client))
+		return DISCONNECTED;
 
 
 	/* Suspend the client for a second ... */
 	/* Suspend the client for a second ... */
-	IRC_SetPenalty( Client, 1 );
+	IRC_SetPenalty(Client, 1);
 
 
 	return CONNECTED;
 	return CONNECTED;
 } /* Hello_User */
 } /* Hello_User */

+ 289 - 343
src/ngircd/irc-mode.c

@@ -14,8 +14,6 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: irc-mode.c,v 1.45.2.2 2007/04/03 20:23:31 fw Exp $";
-
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>
 #include <stdio.h>
 #include <stdio.h>
@@ -41,13 +39,10 @@ static char UNUSED id[] = "$Id: irc-mode.c,v 1.45.2.2 2007/04/03 20:23:31 fw Exp
 static bool Client_Mode PARAMS(( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target ));
 static bool Client_Mode PARAMS(( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target ));
 static bool Channel_Mode PARAMS(( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ));
 static bool Channel_Mode PARAMS(( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ));
 
 
-static bool Add_Invite PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Pattern ));
-static bool Add_Ban PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Pattern ));
-
-static bool Del_Invite PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Pattern ));
-static bool Del_Ban PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Pattern ));
+static bool Add_Ban_Invite PARAMS((int what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, const char *Pattern));
+static bool Del_Ban_Invite PARAMS((int what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, const char *Pattern));
 
 
-static bool Send_ListChange PARAMS(( char *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Mask ));
+static bool Send_ListChange PARAMS(( char *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, const char *Mask ));
 
 
 
 
 GLOBAL bool
 GLOBAL bool
@@ -164,6 +159,7 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
 		{
 		{
 			case 'i': /* Invisible */
 			case 'i': /* Invisible */
 			case 's': /* Server messages */
 			case 's': /* Server messages */
+			case 'w': /* Wallops messages */
 				x[0] = *mode_ptr;
 				x[0] = *mode_ptr;
 				break;
 				break;
 
 
@@ -242,122 +238,139 @@ client_exit:
 
 
 
 
 static bool
 static bool
+Channel_Mode_Answer_Request(CLIENT *Origin, CHANNEL *Channel)
+{
+	char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], argadd[CLIENT_PASS_LEN];
+	const char *mode_ptr;
+
+	/* Member or not? -- That's the question! */
+	if (!Channel_IsMemberOf(Channel, Origin))
+		return IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
+			Client_ID(Origin), Channel_Name(Channel), Channel_Modes(Channel));
+
+	/* The sender is a member: generate extended reply */
+	strlcpy(the_modes, Channel_Modes(Channel), sizeof(the_modes));
+	mode_ptr = the_modes;
+	the_args[0] = '\0';
+
+	while(*mode_ptr) {
+		switch(*mode_ptr) {
+		case 'l':
+			snprintf(argadd, sizeof(argadd), " %lu", Channel_MaxUsers(Channel));
+			strlcat(the_args, argadd, sizeof(the_args));
+			break;
+		case 'k':
+			strlcat(the_args, " ", sizeof(the_args));
+			strlcat(the_args, Channel_Key(Channel), sizeof(the_args));
+			break;
+		}
+		mode_ptr++;
+	}
+	if (the_args[0])
+		strlcat(the_modes, the_args, sizeof(the_modes));
+
+	return IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
+		Client_ID(Origin), Channel_Name(Channel), the_modes);
+}
+
+
+static bool
 Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel )
 Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel )
 {
 {
 	/* Handle channel and channel-user modes */
 	/* Handle channel and channel-user modes */
 
 
 	char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2], argadd[CLIENT_PASS_LEN], *mode_ptr;
 	char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2], argadd[CLIENT_PASS_LEN], *mode_ptr;
-	bool ok, set, modeok = false, skiponce, use_servermode = false;
+	bool ok, set, modeok = true, skiponce, use_servermode = false, retval;
 	int mode_arg, arg_arg;
 	int mode_arg, arg_arg;
 	CLIENT *client;
 	CLIENT *client;
 	long l;
 	long l;
 	size_t len;
 	size_t len;
 
 
 	/* Mode request: let's answer it :-) */
 	/* Mode request: let's answer it :-) */
-	if( Req->argc == 1 )
-	{
-		/* Member or not? -- That's the question! */
-		if( ! Channel_IsMemberOf( Channel, Origin )) return IRC_WriteStrClient( Origin, RPL_CHANNELMODEIS_MSG, Client_ID( Origin ), Channel_Name( Channel ), Channel_Modes( Channel ));
-
-		/* The sender is a member: generate extended reply */
-		strlcpy( the_modes, Channel_Modes( Channel ), sizeof( the_modes ));
-		mode_ptr = the_modes;
-		the_args[0] = '\0';
-		while( *mode_ptr )
-		{
-			switch( *mode_ptr )
-			{
-				case 'l':
-					snprintf( argadd, sizeof( argadd ), " %lu", Channel_MaxUsers( Channel ));
-					strlcat( the_args, argadd, sizeof( the_args ));
-					break;
-				case 'k':
-					strlcat( the_args, " ", sizeof( the_args ));
-					strlcat( the_args, Channel_Key( Channel ), sizeof( the_args ));
-					break;
-			}
-			mode_ptr++;
-		}
-		if( the_args[0] ) strlcat( the_modes, the_args, sizeof( the_modes ));
-
-		return IRC_WriteStrClient( Origin, RPL_CHANNELMODEIS_MSG, Client_ID( Origin ), Channel_Name( Channel ), the_modes );
-	}
+	if (Req->argc <= 1)
+		return Channel_Mode_Answer_Request(Origin, Channel);
 
 
 	/* Is the user allowed to change modes? */
 	/* Is the user allowed to change modes? */
-	if( Client_Type( Client ) == CLIENT_USER )
-	{
+	if (Client_Type(Client) == CLIENT_USER) {
 		/* Is the originating user on that channel? */
 		/* Is the originating user on that channel? */
-		if( ! Channel_IsMemberOf( Channel, Origin )) return IRC_WriteStrClient( Origin, ERR_NOTONCHANNEL_MSG, Client_ID( Origin ), Channel_Name( Channel ));
-
-		/* Is he channel operator? */
-		if( strchr( Channel_UserModes( Channel, Origin ), 'o' )) modeok = true;
-		else if( Conf_OperCanMode )
-		{
+		if (!Channel_IsMemberOf(Channel, Origin))
+			return IRC_WriteStrClient(Origin, ERR_NOTONCHANNEL_MSG,
+				Client_ID(Origin), Channel_Name(Channel));
+		modeok = false;
+		/* channel operator? */
+		if (strchr(Channel_UserModes(Channel, Origin), 'o'))
+			modeok = true;
+		else if(Conf_OperCanMode) {
 			/* IRC-Operators can use MODE as well */
 			/* IRC-Operators can use MODE as well */
-			if( Client_OperByMe( Origin )) {
+			if (Client_OperByMe(Origin)) {
 				modeok = true;
 				modeok = true;
-				if ( Conf_OperServerMode ) use_servermode = true; /* Change Origin to Server */
+				if (Conf_OperServerMode)
+					use_servermode = true; /* Change Origin to Server */
 			}
 			}
 		}
 		}
 	}
 	}
-	else modeok = true;
 
 
 	mode_arg = 1;
 	mode_arg = 1;
 	mode_ptr = Req->argv[mode_arg];
 	mode_ptr = Req->argv[mode_arg];
-	if( Req->argc > mode_arg + 1 ) arg_arg = mode_arg + 1;
-	else arg_arg = -1;
+	if (Req->argc > mode_arg + 1)
+		arg_arg = mode_arg + 1;
+	else
+		arg_arg = -1;
 
 
 	/* Initial state: set or unset modes? */
 	/* Initial state: set or unset modes? */
 	skiponce = false;
 	skiponce = false;
-	if( *mode_ptr == '-' ) set = false;
-	else if( *mode_ptr == '+' ) set = true;
-	else set = skiponce = true;
+	switch (*mode_ptr) {
+	case '-': set = false; break;
+	case '+': set = true; break;
+	default:
+		set = true;
+		skiponce = true;
+	}
 
 
 	/* Prepare reply string */
 	/* Prepare reply string */
-	if( set ) strcpy( the_modes, "+" );
-	else strcpy( the_modes, "-" );
-	strcpy( the_args, " " );
+	strcpy(the_modes, set ? "+" : "-");
+	the_args[0] = '\0';
 
 
 	x[1] = '\0';
 	x[1] = '\0';
 	ok = CONNECTED;
 	ok = CONNECTED;
-	while( mode_ptr )
-	{
-		if( ! skiponce ) mode_ptr++;
-		if( ! *mode_ptr )
-		{
+	while (mode_ptr) {
+		if (! skiponce)
+			mode_ptr++;
+		if (!*mode_ptr) {
 			/* Try next argument if there's any */
 			/* Try next argument if there's any */
-			if( arg_arg > mode_arg ) mode_arg = arg_arg;
-			else mode_arg++;
-			if( mode_arg < Req->argc ) mode_ptr = Req->argv[mode_arg];
-			else break;
-			if( Req->argc > mode_arg + 1 ) arg_arg = mode_arg + 1;
-			else arg_arg = -1;
+			if (arg_arg > mode_arg)
+				mode_arg = arg_arg;
+			else
+				mode_arg++;
+
+			if (mode_arg >= Req->argc)
+				break;
+			mode_ptr = Req->argv[mode_arg];
+
+			if (Req->argc > mode_arg + 1)
+				arg_arg = mode_arg + 1;
+			else
+				arg_arg = -1;
 		}
 		}
 		skiponce = false;
 		skiponce = false;
 
 
-		switch( *mode_ptr )
-		{
-			case '+':
-			case '-':
-				if((( *mode_ptr == '+' ) && ( ! set )) || (( *mode_ptr == '-' ) && ( set )))
-				{
-					/* Action modifier ("+"/"-") must be changed ... */
-					len = strlen( the_modes ) - 1;
-					if(( the_modes[len] == '+' ) || ( the_modes[len] == '-' ))
-					{
-						/* Adjust last action modifier in result */
-						the_modes[len] = *mode_ptr;
-					}
-					else
-					{
-						/* Append modifier character to result string */
-						x[0] = *mode_ptr;
-						strlcat( the_modes, x, sizeof( the_modes ));
-					}
-					if( *mode_ptr == '+' ) set = true;
-					else set = false;
+		switch (*mode_ptr) {
+		case '+':
+		case '-':
+			if (((*mode_ptr == '+') && !set) || ((*mode_ptr == '-') && set)) {
+				/* Action modifier ("+"/"-") must be changed ... */
+				len = strlen( the_modes ) - 1;
+				if ((the_modes[len] == '+') || (the_modes[len] == '-')) {
+					/* Adjust last action modifier in result */
+					the_modes[len] = *mode_ptr;
+				} else {
+					/* Append modifier character to result string */
+					x[0] = *mode_ptr;
+					strlcat(the_modes, x, sizeof(the_modes));
 				}
 				}
-				continue;
+				set = *mode_ptr == '+';
+			}
+			continue;
 		}
 		}
 
 
 		/* Are there arguments left? */
 		/* Are there arguments left? */
@@ -367,240 +380,194 @@ Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel )
 		x[0] = '\0';
 		x[0] = '\0';
 		argadd[0] = '\0';
 		argadd[0] = '\0';
 		client = NULL;
 		client = NULL;
-		switch( *mode_ptr )
-		{
-			/* --- Channel modes --- */
-
-			case 'i': /* Invite only */
-			case 'm': /* Moderated */
-			case 'n': /* Only members can write */
-			case 's': /* Secret channel */
-			case 't': /* Topic locked */
-				if( modeok ) x[0] = *mode_ptr;
-				else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
-				break;
-
-			case 'k': /* Channel key */
-				if( ! set )
-				{
-					if( modeok ) x[0] = *mode_ptr;
-					else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
-					break;
-				}
-				if( arg_arg > mode_arg )
-				{
-					if( modeok )
-					{
-						Channel_ModeDel( Channel, 'k' );
-						Channel_SetKey( Channel, Req->argv[arg_arg] );
-						strlcpy( argadd, Channel_Key( Channel ), sizeof( argadd ));
-						x[0] = *mode_ptr;
-					}
-					else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
-					Req->argv[arg_arg][0] = '\0';
-					arg_arg++;
-				}
-				else ok = IRC_WriteStrClient( Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID( Origin ), Req->command );
-				break;
-
-			case 'l': /* Member limit */
-				if( ! set )
-				{
-					if( modeok ) x[0] = *mode_ptr;
-					else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
-					break;
-				}
-				if( arg_arg > mode_arg )
-				{
-					if( modeok )
-					{
-						l = atol( Req->argv[arg_arg] );
-						if( l > 0 && l < 0xFFFF )
-						{
-							Channel_ModeDel( Channel, 'l' );
-							Channel_SetMaxUsers( Channel, l );
-							snprintf( argadd, sizeof( argadd ), "%ld", l );
-							x[0] = *mode_ptr;
-						}
-					}
-					else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
-					Req->argv[arg_arg][0] = '\0';
-					arg_arg++;
-				}
-				else ok = IRC_WriteStrClient( Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID( Origin ), Req->command );
+		switch (*mode_ptr) {
+		/* --- Channel modes --- */
+		case 'i': /* Invite only */
+		case 'm': /* Moderated */
+		case 'n': /* Only members can write */
+		case 's': /* Secret channel */
+		case 't': /* Topic locked */
+			if (modeok)
+				x[0] = *mode_ptr;
+			else
+				ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel));
+			break;
+		case 'k': /* Channel key */
+			if (! set) {
+				if (modeok)
+					x[0] = *mode_ptr;
+				else
+					ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel));
 				break;
 				break;
-
-			case 'P': /* Persistent channel */
-				if( modeok )
-				{
-					if( set && ( ! Client_OperByMe( Client )))
-					{
-						/* Only IRC operators are allowed to set P mode */
-						ok = IRC_WriteStrClient( Origin, ERR_NOPRIVILEGES_MSG, Client_ID( Origin ));
-					}
-					else x[0] = 'P';
+			}
+			if (arg_arg > mode_arg) {
+				if (modeok) {
+					Channel_ModeDel(Channel, 'k');
+					Channel_SetKey(Channel, Req->argv[arg_arg]);
+					strlcpy(argadd, Channel_Key(Channel), sizeof(argadd));
+					x[0] = *mode_ptr;
+				} else {
+					ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel));
 				}
 				}
-				else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
+				Req->argv[arg_arg][0] = '\0';
+				arg_arg++;
+			} else {
+				ok = IRC_WriteStrClient(Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID(Origin), Req->command);
+			}
+			break;
+		case 'l': /* Member limit */
+			if (!set) {
+				if (modeok)
+					x[0] = *mode_ptr;
+				else
+					ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel));
 				break;
 				break;
-
-			/* --- Channel user modes --- */
-
-			case 'o': /* Channel operator */
-			case 'v': /* Voice */
-				if( arg_arg > mode_arg )
-				{
-					if( modeok )
-					{
-						client = Client_Search( Req->argv[arg_arg] );
-						if( client ) x[0] = *mode_ptr;
-						else ok = IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[arg_arg] );
+			}
+			if (arg_arg > mode_arg) {
+				if (modeok) {
+					l = atol(Req->argv[arg_arg]);
+					if (l > 0 && l < 0xFFFF) {
+						Channel_ModeDel(Channel, 'l');
+						Channel_SetMaxUsers(Channel, l);
+						snprintf(argadd, sizeof(argadd), "%ld", l);
+						x[0] = *mode_ptr;
 					}
 					}
-					else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
-					Req->argv[arg_arg][0] = '\0';
-					arg_arg++;
+				} else {
+					ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel));
 				}
 				}
-				else ok = IRC_WriteStrClient( Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID( Origin ), Req->command );
-				break;
-
-			/* --- Channel lists --- */
-
-			case 'I': /* Invite lists */
-				if( arg_arg > mode_arg )
-				{
-					/* modify list */
-					if( modeok )
-					{
-						if( set ) Add_Invite( Origin, Client, Channel, Req->argv[arg_arg] );
-						else Del_Invite( Origin, Client, Channel, Req->argv[arg_arg] );
-					}
-					else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
-					Req->argv[arg_arg][0] = '\0';
-					arg_arg++;
+				Req->argv[arg_arg][0] = '\0';
+				arg_arg++;
+			} else {
+				ok = IRC_WriteStrClient(Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID(Origin), Req->command);
+			}
+			break;
+		case 'P': /* Persistent channel */
+			if (modeok) {
+				/* Only IRC operators are allowed to
+				 * set the 'P' channel mode! */
+				if (set && !(Client_OperByMe(Client) || Client_Type(Client) == CLIENT_SERVER))
+					ok = IRC_WriteStrClient(Origin, ERR_NOPRIVILEGES_MSG, Client_ID(Origin));
+				else
+						x[0] = 'P';
+			} else
+				ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel));
+			break;
+		/* --- Channel user modes --- */
+		case 'o': /* Channel operator */
+		case 'v': /* Voice */
+			if (arg_arg > mode_arg) {
+				if (modeok) {
+					client = Client_Search(Req->argv[arg_arg]);
+					if (client)
+						x[0] = *mode_ptr;
+					else
+						ok = IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID(Client), Req->argv[arg_arg]);
+				} else {
+					ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID(Origin), Channel_Name(Channel));
 				}
 				}
-				else Channel_ShowInvites( Origin, Channel );
-				break;
-
-			case 'b': /* Ban lists */
-				if( arg_arg > mode_arg )
-				{
-					/* modify list */
-					if( modeok )
-					{
-						if( set ) Add_Ban( Origin, Client, Channel, Req->argv[arg_arg] );
-						else Del_Ban( Origin, Client, Channel, Req->argv[arg_arg] );
-					}
-					else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
-					Req->argv[arg_arg][0] = '\0';
-					arg_arg++;
+				Req->argv[arg_arg][0] = '\0';
+				arg_arg++;
+			} else {
+				ok = IRC_WriteStrClient(Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID(Origin), Req->command);
+			}
+			break;
+		/* --- Channel lists --- */
+		case 'I': /* Invite lists */
+		case 'b': /* Ban lists */
+			if (arg_arg > mode_arg) {
+				/* modify list */
+				if (modeok) {
+					ok = set ? Add_Ban_Invite(*mode_ptr, Origin, Client, Channel, Req->argv[arg_arg])
+						 : Del_Ban_Invite(*mode_ptr, Origin, Client, Channel, Req->argv[arg_arg]);
+				} else {
+					ok = IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG,
+							Client_ID(Origin), Channel_Name(Channel));
 				}
 				}
-				else Channel_ShowBans( Origin, Channel );
-				break;
-
-			default:
-				Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\" on %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Origin ), Channel_Name( Channel ));
-				if( Client_Type( Client ) != CLIENT_SERVER ) ok = IRC_WriteStrClient( Origin, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Origin ), set ? '+' : '-', *mode_ptr );
-				x[0] = '\0';
-				goto chan_exit;
-		}
-		if( ! ok ) break;
+				Req->argv[arg_arg][0] = '\0';
+				arg_arg++;
+			} else {
+				if (*mode_ptr == 'I')
+					Channel_ShowInvites(Origin, Channel);
+				else
+					Channel_ShowBans(Origin, Channel);
+			}
+			break;
+		default:
+			Log(LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\" on %s!?",
+				set ? '+' : '-', *mode_ptr, Client_ID(Origin), Channel_Name(Channel));
+			if (Client_Type(Client) != CLIENT_SERVER)
+				ok = IRC_WriteStrClient(Origin, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID(Origin), set ? '+' : '-', *mode_ptr);
+			x[0] = '\0';
+			goto chan_exit;
+		} /* switch() */
+
+		if (!ok)
+			break;
 
 
 		/* Is there a valid mode change? */
 		/* Is there a valid mode change? */
-		if( ! x[0] ) continue;
+		if (!x[0])
+			continue;
 
 
 		/* Validate target client */
 		/* Validate target client */
-		if( client && ( ! Channel_IsMemberOf( Channel, client )))
-		{
-			if( ! IRC_WriteStrClient( Origin, ERR_USERNOTINCHANNEL_MSG, Client_ID( Origin ), Client_ID( client ), Channel_Name( Channel ))) break;
+		if (client && (!Channel_IsMemberOf(Channel, client))) {
+			if (!IRC_WriteStrClient(Origin, ERR_USERNOTINCHANNEL_MSG,
+				Client_ID(Origin), Client_ID(client), Channel_Name(Channel)))
+					break;
+
 			continue;
 			continue;
 		}
 		}
 
 
-		if( set )
-		{
-			/* Set mode */
-			if( client )
-			{
-				/* Channel-User-Mode */
-				if( Channel_UserModeAdd( Channel, client, x[0] ))
-				{
-					strlcat( the_args, Client_ID( client ), sizeof( the_args ));
-					strlcat( the_args, " ", sizeof( the_args ));
-					strlcat( the_modes, x, sizeof( the_modes ));
-					Log( LOG_DEBUG, "User \"%s\": Mode change on %s, now \"%s\"", Client_Mask( client ), Channel_Name( Channel ), Channel_UserModes( Channel, client ));
-				}
+		if (client) {
+			/* Channel-User-Mode */
+			retval = set ? Channel_UserModeAdd(Channel, client, x[0]) : Channel_UserModeDel(Channel, client, x[0]);
+			if (retval) {
+				strlcat(the_args, " ", sizeof(the_args));
+				strlcat(the_args, Client_ID(client), sizeof(the_args));
+				strlcat(the_modes, x, sizeof(the_modes));
+				Log(LOG_DEBUG, "User \"%s\": Mode change on %s, now \"%s\"",
+					Client_Mask(client), Channel_Name(Channel), Channel_UserModes(Channel, client));
 			}
 			}
-			else
-			{
-				/* Channel-Mode */
-				if( Channel_ModeAdd( Channel, x[0] ))
-				{
-					strlcat( the_modes, x, sizeof( the_modes ));
-					Log( LOG_DEBUG, "Channel %s: Mode change, now \"%s\".", Channel_Name( Channel ), Channel_Modes( Channel ));
-				}
-			}
-		}
-		else
-		{
-			/* Unset mode */
-			if( client )
-			{
-				/* Channel-User-Mode */
-				if( Channel_UserModeDel( Channel, client, x[0] ))
-				{
-					strlcat( the_args, Client_ID( client ), sizeof( the_args ));
-					strlcat( the_args, " ", sizeof( the_args ));
-					strlcat( the_modes, x, sizeof( the_modes ));
-					Log( LOG_DEBUG, "User \"%s\": Mode change on %s, now \"%s\"", Client_Mask( client ), Channel_Name( Channel ), Channel_UserModes( Channel, client ));
-				}
-			}
-			else
-			{
-				/* Channel-Mode */
-				if( Channel_ModeDel( Channel, x[0] ))
-				{
-					strlcat( the_modes, x, sizeof( the_modes ));
-					Log( LOG_DEBUG, "Channel %s: Mode change, now \"%s\".", Channel_Name( Channel ), Channel_Modes( Channel ));
-				}
+		} else {
+			/* Channel-Mode */
+			retval = set ? Channel_ModeAdd(Channel, x[0]) : Channel_ModeDel(Channel, x[0]);
+			if (retval) {
+				strlcat(the_modes, x, sizeof(the_modes));
+				Log(LOG_DEBUG, "Channel %s: Mode change, now \"%s\".", Channel_Name(Channel), Channel_Modes(Channel));
 			}
 			}
 		}
 		}
 
 
 		/* Are there additional arguments to add? */
 		/* Are there additional arguments to add? */
-		if( argadd[0] )
-		{
-			len = strlen( the_args ) - 1;
-			if( the_args[len] != ' ' ) strlcat( the_args, " ", sizeof( the_args ));
-			strlcat( the_args, argadd, sizeof( the_args ));
+		if (argadd[0]) {
+			strlcat(the_args, " ", sizeof(the_args));
+			strlcat(the_args, argadd, sizeof(the_args));
 		}
 		}
 	}
 	}
 chan_exit:
 chan_exit:
-
 	/* Are there changed modes? */
 	/* Are there changed modes? */
-	if( the_modes[1] )
-	{
+	if (the_modes[1]) {
 		/* Clean up mode string */
 		/* Clean up mode string */
-		len = strlen( the_modes ) - 1;
-		if(( the_modes[len] == '+' ) || ( the_modes[len] == '-' )) the_modes[len] = '\0';
-
-		/* Clean up argument string if there are none */
-		if( ! the_args[1] ) the_args[0] = '\0';
+		len = strlen(the_modes) - 1;
+		if ((the_modes[len] == '+') || (the_modes[len] == '-'))
+			the_modes[len] = '\0';
 
 
-		if( Client_Type( Client ) == CLIENT_SERVER )
-		{
+		if (Client_Type(Client) == CLIENT_SERVER) {
 			/* Forward mode changes to channel users and other servers */
 			/* Forward mode changes to channel users and other servers */
-			IRC_WriteStrServersPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
-			IRC_WriteStrChannelPrefix( Client, Channel, Origin, false, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
-		}
-		else
-		{
-			if ( use_servermode ) Origin = Client_ThisServer();
-
+			IRC_WriteStrServersPrefix(Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args);
+			IRC_WriteStrChannelPrefix(Client, Channel, Origin, false, "MODE %s %s%s", Channel_Name(Channel), the_modes, the_args);
+		} else {
+			if (use_servermode)
+				Origin = Client_ThisServer();
 			/* Send reply to client and inform other servers and channel users */
 			/* Send reply to client and inform other servers and channel users */
-			ok = IRC_WriteStrClientPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
-			IRC_WriteStrServersPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
-			IRC_WriteStrChannelPrefix( Client, Channel, Origin, false, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
+			ok = IRC_WriteStrClientPrefix(Client, Origin, "MODE %s %s%s",
+					Channel_Name(Channel), the_modes, the_args);
+			IRC_WriteStrServersPrefix(Client, Origin, "MODE %s %s%s",
+					Channel_Name(Channel), the_modes, the_args);
+			IRC_WriteStrChannelPrefix(Client, Channel, Origin, false, "MODE %s %s%s",
+						Channel_Name(Channel), the_modes, the_args);
 		}
 		}
 	}
 	}
 
 
-	IRC_SetPenalty( Client, 1 );
+	IRC_SetPenalty(Client, 1);
 	return CONNECTED;
 	return CONNECTED;
 } /* Channel_Mode */
 } /* Channel_Mode */
 
 
@@ -633,85 +600,64 @@ IRC_AWAY( CLIENT *Client, REQUEST *Req )
 
 
 
 
 static bool
 static bool
-Add_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Pattern )
-{
-	char *mask;
-	bool already;
-
-	assert( Client != NULL );
-	assert( Channel != NULL );
-	assert( Pattern != NULL );
-
-	mask = Lists_MakeMask( Pattern );
-
-	already = Lists_CheckDupeMask(Channel_GetListInvites(Channel), mask );
-	if (!already) {
-		if( ! Channel_AddInvite(Channel, mask, false ))
-			return CONNECTED;
-	}
-	if ( already && ( Client_Type( Prefix ) == CLIENT_SERVER ))
-		return CONNECTED;
-
-	return Send_ListChange( "+I", Prefix, Client, Channel, mask );
-} /* Add_Invite */
-
-
-static bool
-Add_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Pattern )
+Add_Ban_Invite(int what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, const char *Pattern)
 {
 {
-	char *mask;
+	const char *mask;
 	bool already;
 	bool already;
+	bool ret;
 
 
 	assert( Client != NULL );
 	assert( Client != NULL );
 	assert( Channel != NULL );
 	assert( Channel != NULL );
 	assert( Pattern != NULL );
 	assert( Pattern != NULL );
+	assert(what == 'I' || what == 'b');
 
 
-	mask = Lists_MakeMask( Pattern );
+	mask = Lists_MakeMask(Pattern);
 
 
-	already = Lists_CheckDupeMask(Channel_GetListBans(Channel), mask );
+	already = Lists_CheckDupeMask(Channel_GetListInvites(Channel), mask);
 	if (!already) {
 	if (!already) {
-		if( ! Channel_AddBan(Channel, mask))
+		if (what == 'I')
+			ret = Channel_AddInvite(Channel, mask, false);
+		else
+			ret = Channel_AddBan(Channel, mask);
+		if (!ret)
 			return CONNECTED;
 			return CONNECTED;
 	}
 	}
-	if ( already && ( Client_Type( Prefix ) == CLIENT_SERVER ))
+	if (already && (Client_Type(Prefix) == CLIENT_SERVER))
 		return CONNECTED;
 		return CONNECTED;
 
 
-	return Send_ListChange( "+b", Prefix, Client, Channel, mask );
-} /* Add_Ban */
+	if (what == 'I')
+		return Send_ListChange("+I", Prefix, Client, Channel, mask);
+	return Send_ListChange("+b", Prefix, Client, Channel, mask);
+}
 
 
 
 
 static bool
 static bool
-Del_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Pattern )
+Del_Ban_Invite(int what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, const char *Pattern)
 {
 {
-	char *mask;
+	const char *mask;
+	struct list_head *list;
 
 
 	assert( Client != NULL );
 	assert( Client != NULL );
 	assert( Channel != NULL );
 	assert( Channel != NULL );
 	assert( Pattern != NULL );
 	assert( Pattern != NULL );
+	assert(what == 'I' || what == 'b');
 
 
 	mask = Lists_MakeMask( Pattern );
 	mask = Lists_MakeMask( Pattern );
-	Lists_Del(Channel_GetListInvites(Channel), mask);
-	return Send_ListChange( "-I", Prefix, Client, Channel, mask );
-} /* Del_Invite */
-
-
-static bool
-Del_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Pattern )
-{
-	char *mask;
 
 
-	assert( Client != NULL );
-	assert( Channel != NULL );
-	assert( Pattern != NULL );
+	if (what == 'I')
+		list = Channel_GetListInvites(Channel);
+	else
+		list = Channel_GetListBans(Channel);
 
 
-	mask = Lists_MakeMask( Pattern );
-	Lists_Del(Channel_GetListBans(Channel), mask);
+	Lists_Del(list, mask);
+	if (what == 'I')
+		return Send_ListChange( "-I", Prefix, Client, Channel, mask );
 	return Send_ListChange( "-b", Prefix, Client, Channel, mask );
 	return Send_ListChange( "-b", Prefix, Client, Channel, mask );
-} /* Del_Ban */
+}
 
 
 
 
 static bool
 static bool
-Send_ListChange( char *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Mask )
+Send_ListChange( char *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, const char *Mask )
 {
 {
 	/* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
 	/* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
 
 

+ 1 - 1
src/ngircd/irc-op.c

@@ -14,7 +14,7 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: irc-op.c,v 1.15.4.2 2007/04/03 20:23:31 fw Exp $";
+static char UNUSED id[] = "$Id: irc-op.c,v 1.17 2006/12/07 17:57:20 fw Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>

+ 63 - 5
src/ngircd/irc-oper.c

@@ -14,7 +14,7 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: irc-oper.c,v 1.27 2006/07/23 15:43:18 alex Exp $";
+static char UNUSED id[] = "$Id: irc-oper.c,v 1.29 2007/08/02 10:14:26 fw Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>
@@ -191,12 +191,12 @@ IRC_CONNECT(CLIENT * Client, REQUEST * Req)
 					  Client_ID(Client));
 					  Client_ID(Client));
 
 
 	/* Bad number of parameters? */
 	/* Bad number of parameters? */
-	if ((Req->argc != 2) && (Req->argc != 5))
+	if ((Req->argc != 1) && (Req->argc != 2) && (Req->argc != 5))
 		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
 		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
 					  Client_ID(Client), Req->command);
 					  Client_ID(Client), Req->command);
 
 
 	/* Invalid port number? */
 	/* Invalid port number? */
-	if (atoi(Req->argv[1]) < 1)
+	if ((Req->argc > 1) && atoi(Req->argv[1]) < 1)
 		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
 		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
 					  Client_ID(Client), Req->command);
 					  Client_ID(Client), Req->command);
 
 
@@ -204,14 +204,22 @@ IRC_CONNECT(CLIENT * Client, REQUEST * Req)
 	    "Got CONNECT command from \"%s\" for \"%s\".", Client_Mask(Client),
 	    "Got CONNECT command from \"%s\" for \"%s\".", Client_Mask(Client),
 	    Req->argv[0]);
 	    Req->argv[0]);
 
 
-	if (Req->argc == 2) {
+	switch (Req->argc) {
+	case 1:
+		if (!Conf_EnablePassiveServer(Req->argv[0]))
+			return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG,
+						  Client_ID(Client),
+						  Req->argv[0]);
+	break;
+	case 2:
 		/* Connect configured server */
 		/* Connect configured server */
 		if (!Conf_EnableServer
 		if (!Conf_EnableServer
 		    (Req->argv[0], (UINT16) atoi(Req->argv[1])))
 		    (Req->argv[0], (UINT16) atoi(Req->argv[1])))
 			return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG,
 			return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG,
 						  Client_ID(Client),
 						  Client_ID(Client),
 						  Req->argv[0]);
 						  Req->argv[0]);
-	} else {
+	break;
+	default:
 		/* Add server */
 		/* Add server */
 		if (!Conf_AddServer
 		if (!Conf_AddServer
 		    (Req->argv[0], (UINT16) atoi(Req->argv[1]), Req->argv[2],
 		    (Req->argv[0], (UINT16) atoi(Req->argv[1]), Req->argv[2],
@@ -255,4 +263,54 @@ IRC_DISCONNECT(CLIENT *Client, REQUEST *Req )
 } /* IRC_CONNECT */
 } /* IRC_CONNECT */
 
 
 
 
+GLOBAL bool
+IRC_WALLOPS( CLIENT *Client, REQUEST *Req )
+{
+	CLIENT *to, *from;
+	int client_type;
+
+	assert( Client != NULL );
+	assert( Req != NULL );
+
+	if (Req->argc != 1)
+		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command);
+
+	client_type = Client_Type(Client);
+	switch (client_type) {
+	case CLIENT_USER:
+		if (!Client_OperByMe(Client))
+			return IRC_WriteStrClient(Client, ERR_NOPRIVILEGES_MSG, Client_ID(Client));
+		from = Client;
+		break;
+	case CLIENT_SERVER:
+		from = Client_Search(Req->prefix);
+		break;
+	default:
+		return CONNECTED;
+	}
+
+	if (!from)
+		return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID(Client), Req->prefix);
+
+	for (to=Client_First(); to != NULL; to=Client_Next(to)) {
+		if (Client_Conn(to) < 0) /* no local connection or WALLOPS origin */
+			continue;
+
+		client_type = Client_Type(to);
+		switch (client_type) {
+		case CLIENT_USER:
+			if (Client_HasMode(to, 'w'))
+				IRC_WriteStrClientPrefix(to, from, "WALLOPS :%s", Req->argv[0]);
+			break;
+		case CLIENT_SERVER:
+			if (to != Client)
+				IRC_WriteStrClientPrefix(to, from, "WALLOPS :%s", Req->argv[0]);
+			break;
+		}
+	}
+	return CONNECTED;
+}
+
+
+
 /* -eof- */
 /* -eof- */

+ 2 - 1
src/ngircd/irc-oper.h

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: irc-oper.h,v 1.11 2005/03/19 18:43:48 fw Exp $
+ * $Id: irc-oper.h,v 1.12 2007/08/02 10:14:26 fw Exp $
  *
  *
  * IRC operator commands (header)
  * IRC operator commands (header)
  */
  */
@@ -24,6 +24,7 @@ GLOBAL bool IRC_REHASH PARAMS((CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_RESTART PARAMS((CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_RESTART PARAMS((CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_CONNECT PARAMS((CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_CONNECT PARAMS((CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_DISCONNECT PARAMS((CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_DISCONNECT PARAMS((CLIENT *Client, REQUEST *Req ));
+GLOBAL bool IRC_WALLOPS PARAMS(( CLIENT *Client, REQUEST *Req ));
 
 
 
 
 #endif
 #endif

+ 25 - 185
src/ngircd/irc-server.c

@@ -1,6 +1,6 @@
 /*
 /*
  * ngIRCd -- The Next Generation IRC Daemon
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2006 Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2007 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
@@ -14,7 +14,7 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: irc-server.c,v 1.39.2.3 2007/04/03 20:23:31 fw Exp $";
+static char UNUSED id[] = "$Id: irc-server.c,v 1.46 2007/11/21 12:16:36 alex Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>
@@ -35,56 +35,14 @@ static char UNUSED id[] = "$Id: irc-server.c,v 1.39.2.3 2007/04/03 20:23:31 fw E
 #include "log.h"
 #include "log.h"
 #include "messages.h"
 #include "messages.h"
 #include "parse.h"
 #include "parse.h"
+#include "numeric.h"
 #include "ngircd.h"
 #include "ngircd.h"
+#include "irc-info.h"
 
 
 #include "exp.h"
 #include "exp.h"
 #include "irc-server.h"
 #include "irc-server.h"
 
 
 
 
-#ifdef IRCPLUS
-static bool
-Synchronize_Lists( CLIENT *Client )
-{
-	CHANNEL *c;
-	struct list_head *head;
-	struct list_elem *elem;
-
-	assert( Client != NULL );
-
-	c = Channel_First();
-
-	while (c) {
-		head = Channel_GetListBans(c);
-
-		elem = Lists_GetFirst(head);
-		while (elem) {
-			if( ! IRC_WriteStrClient( Client, "MODE %s +b %s",
-					Channel_Name(c), Lists_GetMask(elem)))
-			{
-				return false;
-			}
-			elem = Lists_GetNext(elem);
-		}
-
-		head = Channel_GetListInvites(c);
-		elem = Lists_GetFirst(head);
-		while (elem) {
-			if( ! IRC_WriteStrClient( Client, "MODE %s +I %s",
-					Channel_Name( c ), Lists_GetMask(elem)))
-			{
-				return false;
-			}
-			elem = Lists_GetNext(elem);
-		}
-		c = Channel_Next(c);
-	}
-	return true;
-}
-#endif
-
-
-
-
 /**
 /**
  * Handler for the IRC command "SERVER".
  * Handler for the IRC command "SERVER".
  * See RFC 2813 section 4.1.2.
  * See RFC 2813 section 4.1.2.
@@ -92,12 +50,10 @@ Synchronize_Lists( CLIENT *Client )
 GLOBAL bool
 GLOBAL bool
 IRC_SERVER( CLIENT *Client, REQUEST *Req )
 IRC_SERVER( CLIENT *Client, REQUEST *Req )
 {
 {
-	char str[LINE_LEN], *ptr, *modes, *topic;
-	CLIENT *from, *c, *cl;
-	CL2CHAN *cl2chan;
-	int max_hops, i;
-	CHANNEL *chan;
+	char str[LINE_LEN], *ptr;
+	CLIENT *from, *c;
 	bool ok;
 	bool ok;
+	int i;
 	CONN_ID con;
 	CONN_ID con;
 	
 	
 	assert( Client != NULL );
 	assert( Client != NULL );
@@ -166,10 +122,10 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req )
 			Client_SetToken( Client, atoi( Req->argv[1] ));
 			Client_SetToken( Client, atoi( Req->argv[1] ));
 		}
 		}
 
 
-		Log( LOG_NOTICE|LOG_snotice, "Server \"%s\" registered (connection %d, 1 hop - direct link).", Client_ID( Client ), con );
-
-		Client_SetType( Client, CLIENT_SERVER );
-		Conf_SetServer( i, con );
+		/* Mark this connection as belonging to an configured server */
+		Conf_SetServer(i, con);
+		
+		Client_SetType(Client, CLIENT_UNKNOWNSERVER);
 
 
 #ifdef ZLIB
 #ifdef ZLIB
 		/* Kompression initialisieren, wenn erforderlich */
 		/* Kompression initialisieren, wenn erforderlich */
@@ -184,140 +140,23 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req )
 		}
 		}
 #endif
 #endif
 
 
-		/* maximalen Hop Count ermitteln */
-		max_hops = 0;
-		c = Client_First( );
-		while( c )
-		{
-			if( Client_Hops( c ) > max_hops ) max_hops = Client_Hops( c );
-			c = Client_Next( c );
-		}
-		
-		/* Alle bisherigen Server dem neuen Server bekannt machen,
-		 * die bisherigen Server ueber den neuen informierenn */
-		for( i = 0; i < ( max_hops + 1 ); i++ )
-		{
-			c = Client_First( );
-			while( c )
-			{
-				if(( Client_Type( c ) == CLIENT_SERVER ) && ( c != Client ) && ( c != Client_ThisServer( )) && ( Client_Hops( c ) == i ))
-				{
-					if( Client_Conn( c ) > NONE )
-					{
-						/* Dem gefundenen Server gleich den neuen
-						 * Server bekannt machen */
-						if( ! IRC_WriteStrClient( c, "SERVER %s %d %d :%s", Client_ID( Client ), Client_Hops( Client ) + 1, Client_MyToken( Client ), Client_Info( Client ))) return DISCONNECTED;
-					}
-					
-					/* Den neuen Server ueber den alten informieren */
-					if( ! IRC_WriteStrClientPrefix( Client, Client_Hops( c ) == 1 ? Client_ThisServer( ) : Client_Introducer( c ), "SERVER %s %d %d :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_MyToken( c ), Client_Info( c ))) return DISCONNECTED;
-				}
-				c = Client_Next( c );
-			}
-		}
-
-		/* alle User dem neuen Server bekannt machen */
-		c = Client_First( );
-		while( c )
-		{
-			if( Client_Type( c ) == CLIENT_USER )
-			{
-				/* User an neuen Server melden */
-				if( ! IRC_WriteStrClient( Client, "NICK %s %d %s %s %d +%s :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_User( c ), Client_Hostname( c ), Client_MyToken( Client_Introducer( c )), Client_Modes( c ), Client_Info( c ))) return DISCONNECTED;
-			}
-			c = Client_Next( c );
-		}
-
-		/* Channels dem neuen Server bekannt machen */
-		chan = Channel_First( );
-		while( chan )
-		{
 #ifdef IRCPLUS
 #ifdef IRCPLUS
-			/* Send CHANINFO if the peer supports it */
-			if( strchr( Client_Flags( Client ), 'C' ))
-			{
-#ifdef DEBUG
-				Log( LOG_DEBUG, "Sending CHANINFO commands ..." );
-#endif
-				modes = Channel_Modes( chan );
-				topic = Channel_Topic( chan );
-
-				if( *modes || *topic )
-				{
-					/* send CHANINFO */
-					if(( ! strchr( Channel_Modes( chan ), 'k' )) && ( ! strchr( Channel_Modes( chan ), 'l' )) && ( ! *topic ))
-					{
-						/* "CHANINFO <chan> +<modes>" */
-						if( ! IRC_WriteStrClient( Client, "CHANINFO %s +%s", Channel_Name( chan ), modes )) return DISCONNECTED;
-					}
-					else if(( ! strchr( Channel_Modes( chan ), 'k' )) && ( ! strchr( Channel_Modes( chan ), 'l' )))
-					{
-						/* "CHANINFO <chan> +<modes> :<topic>" */
-						if( ! IRC_WriteStrClient( Client, "CHANINFO %s +%s :%s", Channel_Name( chan ), modes, topic )) return DISCONNECTED;
-					}
-					else
-					{
-						/* "CHANINFO <chan> +<modes> <key> <limit> :<topic>" */
-						if( ! IRC_WriteStrClient( Client, "CHANINFO %s +%s %s %lu :%s",
-							Channel_Name( chan ), modes,
-							strchr( Channel_Modes( chan ), 'k' ) ? Channel_Key( chan ) : "*",
-							strchr( Channel_Modes( chan ), 'l' ) ? Channel_MaxUsers( chan ) : 0UL, topic ))
-						{
-							return DISCONNECTED;
-						}
-					}
-				}
-			}
+		if (strchr(Client_Flags(Client), 'H')) {
+			LogDebug("Peer supports IRC+ extended server handshake ...");
+			if (!IRC_Send_ISUPPORT(Client))
+				return DISCONNECTED;
+			return IRC_WriteStrClient(Client, RPL_ENDOFMOTD_MSG,
+						  Client_ID(Client));
+		} else {
 #endif
 #endif
-
-			/* alle Member suchen */
-			cl2chan = Channel_FirstMember( chan );
-			snprintf( str, sizeof( str ), "NJOIN %s :", Channel_Name( chan ));
-			while( cl2chan )
-			{
-				cl = Channel_GetClient( cl2chan );
-				assert( cl != NULL );
-
-				/* Nick, ggf. mit Modes, anhaengen */
-				if( str[strlen( str ) - 1] != ':' ) strlcat( str, ",", sizeof( str ));
-				if( strchr( Channel_UserModes( chan, cl ), 'v' )) strlcat( str, "+", sizeof( str ));
-				if( strchr( Channel_UserModes( chan, cl ), 'o' )) strlcat( str, "@", sizeof( str ));
-				strlcat( str, Client_ID( cl ), sizeof( str ));
-
-				if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 8 ))
-				{
-					/* Zeile senden */
-					if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
-					snprintf( str, sizeof( str ), "NJOIN %s :", Channel_Name( chan ));
-				}
-				
-				cl2chan = Channel_NextMember( chan, cl2chan );
-			}
-
-			/* noch Daten da? */
-			if( str[strlen( str ) - 1] != ':')
-			{
-				/* Ja; Also senden ... */
-				if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
-			}
-
-			/* Get next channel ... */
-			chan = Channel_Next(chan);
-		}
-
+			if (Conf_MaxNickLength != CLIENT_NICK_LEN_DEFAULT)
+				Log(LOG_CRIT,
+				    "Attention: this server uses a non-standard nick length, but the peer doesn't support the IRC+ extended server handshake!");
 #ifdef IRCPLUS
 #ifdef IRCPLUS
-		if (strchr(Client_Flags(Client), 'L')) {
-#ifdef DEBUG
-			Log(LOG_DEBUG,
-			    "Synchronizing INVITE- and BAN-lists ...");
-#endif
-			/* Synchronize INVITE- and BAN-lists */
-			if (!Synchronize_Lists(Client))
-				return DISCONNECTED;
 		}
 		}
 #endif
 #endif
 
 
-		return CONNECTED;
+		return IRC_Num_ENDOFMOTD(Client, Req);
 	}
 	}
 	else if( Client_Type( Client ) == CLIENT_SERVER )
 	else if( Client_Type( Client ) == CLIENT_SERVER )
 	{
 	{
@@ -361,8 +200,9 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req )
 		IRC_WriteStrServersPrefix( Client, from, "SERVER %s %d %d :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_MyToken( c ), Client_Info( c ));
 		IRC_WriteStrServersPrefix( Client, from, "SERVER %s %d %d :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_MyToken( c ), Client_Info( c ));
 
 
 		return CONNECTED;
 		return CONNECTED;
-	}
-	else return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
+	} else
+		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
+					  Client_ID(Client), Req->command);
 } /* IRC_SERVER */
 } /* IRC_SERVER */
 
 
 
 

+ 3 - 1
src/ngircd/irc-server.h

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: irc-server.h,v 1.5 2005/03/19 18:43:49 fw Exp $
+ * $Id: irc-server.h,v 1.6 2007/11/21 12:16:36 alex Exp $
  *
  *
  * IRC commands for server links (header)
  * IRC commands for server links (header)
  */
  */
@@ -22,6 +22,8 @@ GLOBAL bool IRC_SERVER PARAMS((CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_NJOIN PARAMS((CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_NJOIN PARAMS((CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_SQUIT PARAMS((CLIENT *Client, REQUEST *Req ));
 GLOBAL bool IRC_SQUIT PARAMS((CLIENT *Client, REQUEST *Req ));
 
 
+GLOBAL bool IRC_ENDOFMOTD_Server PARAMS((CLIENT *Client));
+
 
 
 #endif
 #endif
 
 

+ 1 - 1
src/ngircd/irc-write.c

@@ -14,7 +14,7 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: irc-write.c,v 1.20.2.1 2006/12/02 13:06:50 fw Exp $";
+static char UNUSED id[] = "$Id: irc-write.c,v 1.21 2006/08/12 11:56:24 fw Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>

+ 10 - 2
src/ngircd/irc.c

@@ -14,7 +14,7 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: irc.c,v 1.131 2006/07/23 14:55:40 alex Exp $";
+static char UNUSED id[] = "$Id: irc.c,v 1.132 2008/01/15 22:28:14 fw Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>
@@ -170,6 +170,7 @@ GLOBAL bool
 IRC_NOTICE( CLIENT *Client, REQUEST *Req )
 IRC_NOTICE( CLIENT *Client, REQUEST *Req )
 {
 {
 	CLIENT *to, *from;
 	CLIENT *to, *from;
+	CHANNEL *chan;
 
 
 	assert( Client != NULL );
 	assert( Client != NULL );
 	assert( Req != NULL );
 	assert( Req != NULL );
@@ -189,7 +190,14 @@ IRC_NOTICE( CLIENT *Client, REQUEST *Req )
 		/* Okay, Ziel ist ein User */
 		/* Okay, Ziel ist ein User */
 		return IRC_WriteStrClientPrefix( to, from, "NOTICE %s :%s", Client_ID( to ), Req->argv[1] );
 		return IRC_WriteStrClientPrefix( to, from, "NOTICE %s :%s", Client_ID( to ), Req->argv[1] );
 	}
 	}
-	else return CONNECTED;
+	else
+	{
+		chan = Channel_Search(Req->argv[0]);
+		if (chan)
+			return Channel_Notice(chan, from, Client, Req->argv[1]);
+	}
+
+	return CONNECTED;
 } /* IRC_NOTICE */
 } /* IRC_NOTICE */
 
 
 
 

+ 2 - 4
src/ngircd/lists.c

@@ -14,8 +14,6 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: lists.c,v 1.18.2.3 2007/04/03 22:08:52 fw Exp $";
-
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>
 
 
@@ -162,8 +160,8 @@ Lists_CheckDupeMask(const struct list_head *h, const char *Mask )
 }
 }
 
 
 
 
-GLOBAL char *
-Lists_MakeMask( char *Pattern )
+GLOBAL const char *
+Lists_MakeMask(const char *Pattern)
 {
 {
 	/* This function generats a valid IRC mask of "any" string. This
 	/* This function generats a valid IRC mask of "any" string. This
 	 * mask is only valid until the next call to Lists_MakeMask(),
 	 * mask is only valid until the next call to Lists_MakeMask(),

+ 1 - 3
src/ngircd/lists.h

@@ -8,8 +8,6 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: lists.h,v 1.12.4.1 2007/04/03 20:23:31 fw Exp $
- *
  * Management of IRC lists: ban, invite, ... (header)
  * Management of IRC lists: ban, invite, ... (header)
  */
  */
 
 
@@ -39,7 +37,7 @@ GLOBAL bool Lists_AlreadyRegistered PARAMS(( const struct list_head *head, const
 
 
 GLOBAL void Lists_Free PARAMS(( struct list_head *head ));
 GLOBAL void Lists_Free PARAMS(( struct list_head *head ));
 
 
-GLOBAL char *Lists_MakeMask PARAMS(( char *Pattern ));
+GLOBAL const char *Lists_MakeMask PARAMS((const char *Pattern));
 GLOBAL const char *Lists_GetMask PARAMS(( const struct list_elem *e ));
 GLOBAL const char *Lists_GetMask PARAMS(( const struct list_elem *e ));
 
 
 #endif
 #endif

+ 1 - 1
src/ngircd/log.c

@@ -14,7 +14,7 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: log.c,v 1.61.2.1 2006/12/02 13:02:07 fw Exp $";
+static char UNUSED id[] = "$Id: log.c,v 1.62 2006/08/05 09:16:21 fw Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>

+ 1 - 1
src/ngircd/log.h

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: log.h,v 1.19.2.1 2006/12/02 13:02:07 fw Exp $
+ * $Id: log.h,v 1.20 2006/08/05 09:16:21 fw Exp $
  *
  *
  * Logging functions (header)
  * Logging functions (header)
  */
  */

+ 1 - 1
src/ngircd/match.c

@@ -14,7 +14,7 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: match.c,v 1.4.2.1 2006/12/02 13:01:11 fw Exp $";
+static char UNUSED id[] = "$Id: match.c,v 1.5 2006/10/06 21:23:47 fw Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>

+ 1 - 1
src/ngircd/match.h

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: match.h,v 1.3.4.1 2006/12/02 13:01:11 fw Exp $
+ * $Id: match.h,v 1.4 2006/10/06 21:23:47 fw Exp $
  *
  *
  * Wildcard pattern matching (header)
  * Wildcard pattern matching (header)
  */
  */

+ 7 - 2
src/ngircd/messages.h

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: messages.h,v 1.67.2.2 2006/12/02 14:26:53 fw Exp $
+ * $Id: messages.h,v 1.75 2008/02/17 13:26:42 alex Exp $
  *
  *
  * IRC numerics (Header)
  * IRC numerics (Header)
  */
  */
@@ -32,6 +32,7 @@
 #define RPL_STATSCOMMANDS_MSG		"212 %s %s %ld %ld %ld"
 #define RPL_STATSCOMMANDS_MSG		"212 %s %s %ld %ld %ld"
 #define RPL_ENDOFSTATS_MSG		"219 %s %c :End of STATS report"
 #define RPL_ENDOFSTATS_MSG		"219 %s %c :End of STATS report"
 #define RPL_UMODEIS_MSG			"221 %s +%s"
 #define RPL_UMODEIS_MSG			"221 %s +%s"
+#define RPL_STATSUPTIME			"242 %s :Server Up %u days %u:%02u:%02u"
 #define RPL_LUSERCLIENT_MSG		"251 %s :There are %ld users and %ld services on %ld servers"
 #define RPL_LUSERCLIENT_MSG		"251 %s :There are %ld users and %ld services on %ld servers"
 #define RPL_LUSEROP_MSG			"252 %s %lu :operator(s) online"
 #define RPL_LUSEROP_MSG			"252 %s %lu :operator(s) online"
 #define RPL_LUSERUNKNOWN_MSG		"253 %s %lu :unknown connection(s)"
 #define RPL_LUSERUNKNOWN_MSG		"253 %s %lu :unknown connection(s)"
@@ -55,7 +56,7 @@
 #define RPL_WHOISOPERATOR_MSG		"313 %s %s :is an IRC operator"
 #define RPL_WHOISOPERATOR_MSG		"313 %s %s :is an IRC operator"
 #define RPL_WHOWASUSER_MSG		"314 %s %s %s %s * :%s"
 #define RPL_WHOWASUSER_MSG		"314 %s %s %s %s * :%s"
 #define RPL_ENDOFWHO_MSG		"315 %s %s :End of WHO list"
 #define RPL_ENDOFWHO_MSG		"315 %s %s :End of WHO list"
-#define RPL_WHOISIDLE_MSG		"317 %s %s %ld :seconds idle"
+#define RPL_WHOISIDLE_MSG		"317 %s %s %lu %lu :seconds idle, signon time"
 #define RPL_ENDOFWHOIS_MSG		"318 %s %s :End of WHOIS list"
 #define RPL_ENDOFWHOIS_MSG		"318 %s %s :End of WHOIS list"
 #define RPL_WHOISCHANNELS_MSG		"319 %s %s :"
 #define RPL_WHOISCHANNELS_MSG		"319 %s %s :"
 #define RPL_LIST_MSG			"322 %s %s %ld :%s"
 #define RPL_LIST_MSG			"322 %s %s %ld :%s"
@@ -76,6 +77,8 @@
 #define RPL_BANLIST_MSG			"367 %s %s %s"
 #define RPL_BANLIST_MSG			"367 %s %s %s"
 #define RPL_ENDOFBANLIST_MSG		"368 %s %s :End of channel ban list"
 #define RPL_ENDOFBANLIST_MSG		"368 %s %s :End of channel ban list"
 #define RPL_ENDOFWHOWAS_MSG		"369 %s %s :End of WHOWAS list"
 #define RPL_ENDOFWHOWAS_MSG		"369 %s %s :End of WHOWAS list"
+#define RPL_INFO_MSG    		"371 %s :%s"
+#define RPL_ENDOFINFO_MSG    		"374 %s :End of INFO list"
 #define RPL_MOTD_MSG			"372 %s :- %s"
 #define RPL_MOTD_MSG			"372 %s :- %s"
 #define RPL_MOTDSTART_MSG		"375 %s :- %s message of the day"
 #define RPL_MOTDSTART_MSG		"375 %s :- %s message of the day"
 #define RPL_ENDOFMOTD_MSG		"376 %s :End of MOTD command"
 #define RPL_ENDOFMOTD_MSG		"376 %s :End of MOTD command"
@@ -99,6 +102,8 @@
 #define ERR_USERNOTINCHANNEL_MSG	"441 %s %s %s :They aren't on that channel"
 #define ERR_USERNOTINCHANNEL_MSG	"441 %s %s %s :They aren't on that channel"
 #define ERR_NOTONCHANNEL_MSG		"442 %s %s :You are not on that channel"
 #define ERR_NOTONCHANNEL_MSG		"442 %s %s :You are not on that channel"
 #define ERR_USERONCHANNEL_MSG		"443 %s %s %s :is already on channel"
 #define ERR_USERONCHANNEL_MSG		"443 %s %s %s :is already on channel"
+#define ERR_SUMMONDISABLED_MSG		"445 %s %s :SUMMON has been disabled"
+#define ERR_USERSDISABLED_MSG		"446 %s %s :USERS has been disabled"
 #define ERR_NOTREGISTERED_MSG		"451 %s :Connection not registered"
 #define ERR_NOTREGISTERED_MSG		"451 %s :Connection not registered"
 #define ERR_NOTREGISTEREDSERVER_MSG	"451 %s :Connection not registered as server link"
 #define ERR_NOTREGISTEREDSERVER_MSG	"451 %s :Connection not registered as server link"
 #define ERR_NEEDMOREPARAMS_MSG		"461 %s %s :Syntax error"
 #define ERR_NEEDMOREPARAMS_MSG		"461 %s %s :Syntax error"

+ 49 - 38
src/ngircd/ngircd.c

@@ -1,6 +1,6 @@
 /*
 /*
  * ngIRCd -- The Next Generation IRC Daemon
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2007 Alexander Barton (alex@barton.de).
+ * Copyright (c)2001-2008 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
@@ -12,8 +12,6 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: ngircd.c,v 1.113.2.2 2007/05/05 20:25:47 alex Exp $";
-
 /**
 /**
  * @file
  * @file
  * The main program, including the C function main() which is called
  * The main program, including the C function main() which is called
@@ -42,7 +40,6 @@ static char UNUSED id[] = "$Id: ngircd.c,v 1.113.2.2 2007/05/05 20:25:47 alex Ex
 #include "client.h"
 #include "client.h"
 #include "channel.h"
 #include "channel.h"
 #include "conf.h"
 #include "conf.h"
-#include "cvs-version.h"
 #include "lists.h"
 #include "lists.h"
 #include "log.h"
 #include "log.h"
 #include "parse.h"
 #include "parse.h"
@@ -169,14 +166,12 @@ main( int argc, const char *argv[] )
 			{
 			{
 				ok = false;
 				ok = false;
 #ifdef DEBUG
 #ifdef DEBUG
-				if( argv[i][n] == 'd' )
-				{
+				if (argv[i][n] == 'd') {
 					NGIRCd_Debug = true;
 					NGIRCd_Debug = true;
 					ok = true;
 					ok = true;
 				}
 				}
 #endif
 #endif
-				if( argv[i][n] == 'f' )
-				{
+				if (argv[i][n] == 'f') {
 					if(( ! argv[i][n + 1] ) && ( i + 1 < argc ))
 					if(( ! argv[i][n + 1] ) && ( i + 1 < argc ))
 					{
 					{
 						/* Ok, next character is a blank */
 						/* Ok, next character is a blank */
@@ -188,31 +183,38 @@ main( int argc, const char *argv[] )
 						ok = true;
 						ok = true;
 					}
 					}
 				}
 				}
-				if( argv[i][n] == 'n' )
-				{
+
+				if (argv[i][n] == 'h') {
+					Show_Version();
+					puts(""); Show_Help(); puts("");
+					exit(1);
+				}
+
+				if (argv[i][n] == 'n') {
 					NGIRCd_NoDaemon = true;
 					NGIRCd_NoDaemon = true;
 					ok = true;
 					ok = true;
 				}
 				}
-				if( argv[i][n] == 'p' )
-				{
+				if (argv[i][n] == 'p') {
 					NGIRCd_Passive = true;
 					NGIRCd_Passive = true;
 					ok = true;
 					ok = true;
 				}
 				}
 #ifdef SNIFFER
 #ifdef SNIFFER
-				if( argv[i][n] == 's' )
-				{
+				if (argv[i][n] == 's') {
 					NGIRCd_Sniffer = true;
 					NGIRCd_Sniffer = true;
 					ok = true;
 					ok = true;
 				}
 				}
 #endif
 #endif
-				if( argv[i][n] == 't' )
-				{
+				if (argv[i][n] == 't') {
 					configtest = true;
 					configtest = true;
 					ok = true;
 					ok = true;
 				}
 				}
 
 
-				if( ! ok )
-				{
+				if (argv[i][n] == 'V') {
+					Show_Version();
+					exit(1);
+				}
+
+				if (! ok) {
 					printf( "%s: invalid option \"-%c\"!\n", PACKAGE_NAME, argv[i][n] );
 					printf( "%s: invalid option \"-%c\"!\n", PACKAGE_NAME, argv[i][n] );
 					printf( "Try \"%s --help\" for more information.\n", PACKAGE_NAME );
 					printf( "Try \"%s --help\" for more information.\n", PACKAGE_NAME );
 					exit( 1 );
 					exit( 1 );
@@ -397,7 +399,12 @@ Fill_Version( void )
 
 
 	strlcat( NGIRCd_VersionAddition, "IRCPLUS", sizeof NGIRCd_VersionAddition );
 	strlcat( NGIRCd_VersionAddition, "IRCPLUS", sizeof NGIRCd_VersionAddition );
 #endif
 #endif
+#ifdef WANT_IPV6
+	if (NGIRCd_VersionAddition[0])
+		strlcat(NGIRCd_VersionAddition, "+", sizeof(NGIRCd_VersionAddition));
 
 
+	strlcat(NGIRCd_VersionAddition, "IPv6", sizeof(NGIRCd_VersionAddition));
+#endif
 	if( NGIRCd_VersionAddition[0] )
 	if( NGIRCd_VersionAddition[0] )
 		strlcat( NGIRCd_VersionAddition, "-", sizeof( NGIRCd_VersionAddition ));
 		strlcat( NGIRCd_VersionAddition, "-", sizeof( NGIRCd_VersionAddition ));
 
 
@@ -407,12 +414,9 @@ Fill_Version( void )
 	strlcat( NGIRCd_VersionAddition, "/", sizeof( NGIRCd_VersionAddition ));
 	strlcat( NGIRCd_VersionAddition, "/", sizeof( NGIRCd_VersionAddition ));
 	strlcat( NGIRCd_VersionAddition, TARGET_OS, sizeof( NGIRCd_VersionAddition ));
 	strlcat( NGIRCd_VersionAddition, TARGET_OS, sizeof( NGIRCd_VersionAddition ));
 
 
-#ifdef CVSDATE
-	snprintf( NGIRCd_Version, sizeof NGIRCd_Version,"%s %s(%s)-%s", PACKAGE_NAME, PACKAGE_VERSION, CVSDATE, NGIRCd_VersionAddition);
-#else
-	snprintf( NGIRCd_Version, sizeof NGIRCd_Version, "%s %s-%s", PACKAGE_NAME, PACKAGE_VERSION, NGIRCd_VersionAddition);
-#endif
-} /* Fill_Version */
+	snprintf(NGIRCd_Version, sizeof NGIRCd_Version, "%s %s-%s",
+		 PACKAGE_NAME, PACKAGE_VERSION, NGIRCd_VersionAddition);
+	} /* Fill_Version */
 
 
 
 
 /**
 /**
@@ -422,24 +426,31 @@ GLOBAL void
 NGIRCd_Rehash( void )
 NGIRCd_Rehash( void )
 {
 {
 	char old_name[CLIENT_ID_LEN];
 	char old_name[CLIENT_ID_LEN];
+	unsigned old_nicklen;
 
 
 	Log( LOG_NOTICE|LOG_snotice, "Re-reading configuration NOW!" );
 	Log( LOG_NOTICE|LOG_snotice, "Re-reading configuration NOW!" );
 	NGIRCd_SignalRehash = false;
 	NGIRCd_SignalRehash = false;
 
 
-	/* Close down all listening sockets */
-	Conn_ExitListeners( );
-
-	/* Remember old server name */
+	/* Remember old server name and nick name length */
 	strlcpy( old_name, Conf_ServerName, sizeof old_name );
 	strlcpy( old_name, Conf_ServerName, sizeof old_name );
+	old_nicklen = Conf_MaxNickLength;
 
 
 	/* Re-read configuration ... */
 	/* Re-read configuration ... */
-	Conf_Rehash( );
+	if (!Conf_Rehash( ))
+		return;
 
 
-	/* Recover old server name: it can't be changed during run-time */
-	if( strcmp( old_name, Conf_ServerName ) != 0 )
-	{
-		strlcpy( Conf_ServerName, old_name, sizeof Conf_ServerName );
-		Log( LOG_ERR, "Can't change \"ServerName\" on runtime! Ignored new name." );
+	/* Close down all listening sockets */
+	Conn_ExitListeners( );
+
+	/* Recover old server name and nick name length: these values can't
+	 * be changed during run-time */
+	if (strcmp(old_name, Conf_ServerName) != 0 ) {
+		strlcpy(Conf_ServerName, old_name, sizeof Conf_ServerName);
+		Log(LOG_ERR, "Can't change \"ServerName\" on runtime! Ignored new name.");
+	}
+	if (old_nicklen != Conf_MaxNickLength) {
+		Conf_MaxNickLength = old_nicklen;
+		Log(LOG_ERR, "Can't change \"MaxNickLength\" on runtime! Ignored new value.");
 	}
 	}
 
 
 	/* Create new pre-defined channels */
 	/* Create new pre-defined channels */
@@ -546,7 +557,7 @@ static void
 Show_Version( void )
 Show_Version( void )
 {
 {
 	puts( NGIRCd_Version );
 	puts( NGIRCd_Version );
-	puts( "Copyright (c)2001-2007 Alexander Barton (<alex@barton.de>) and Contributors." );
+	puts( "Copyright (c)2001-2008 Alexander Barton (<alex@barton.de>) and Contributors." );
 	puts( "Homepage: <http://ngircd.barton.de/>\n" );
 	puts( "Homepage: <http://ngircd.barton.de/>\n" );
 	puts( "This is free software; see the source for copying conditions. There is NO" );
 	puts( "This is free software; see the source for copying conditions. There is NO" );
 	puts( "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." );
 	puts( "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." );
@@ -571,8 +582,8 @@ Show_Help( void )
 	puts( "  -s, --sniffer      enable network sniffer and display all IRC traffic" );
 	puts( "  -s, --sniffer      enable network sniffer and display all IRC traffic" );
 #endif
 #endif
 	puts( "  -t, --configtest   read, validate and display configuration; then exit" );
 	puts( "  -t, --configtest   read, validate and display configuration; then exit" );
- 	puts( "      --version      output version information and exit" );
-	puts( "      --help         display this help and exit" );
+	puts( "  -V, --version      output version information and exit" );
+	puts( "  -h, --help         display this help and exit" );
 } /* Show_Help */
 } /* Show_Help */
 
 
 
 
@@ -797,7 +808,7 @@ NGIRCd_Init( bool NGIRCd_NoDaemon )
 			if( chdir( pwd->pw_dir ) == 0 ) 
 			if( chdir( pwd->pw_dir ) == 0 ) 
 				Log( LOG_DEBUG, "Changed working directory to \"%s\" ...", pwd->pw_dir );
 				Log( LOG_DEBUG, "Changed working directory to \"%s\" ...", pwd->pw_dir );
 			else 
 			else 
-				Log( LOG_ERR, "Can't change working directory to \"%s\": %s",
+				Log( LOG_INFO, "Notice: Can't change working directory to \"%s\": %s",
 								pwd->pw_dir, strerror( errno ));
 								pwd->pw_dir, strerror( errno ));
 		}
 		}
 	} else {
 	} else {

+ 334 - 0
src/ngircd/numeric.c

@@ -0,0 +1,334 @@
+/*
+ * ngIRCd -- The Next Generation IRC Daemon
+ * Copyright (c)2001-2007 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.
+ *
+ * Handlers for IRC numerics sent to the server
+ */
+
+#include "portab.h"
+
+static char UNUSED id[] = "$Id: numeric.c,v 1.1 2007/11/21 12:20:32 alex Exp $";
+
+#include "imp.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "defines.h"
+#include "resolve.h"
+#include "conn.h"
+#include "conf.h"
+#include "conn.h"
+#include "client.h"
+#include "channel.h"
+#include "irc-write.h"
+#include "lists.h"
+#include "log.h"
+#include "messages.h"
+#include "parse.h"
+
+#include "exp.h"
+#include "numeric.h"
+
+
+/**
+ * Announce new server in the network
+ * @param Client New server
+ * @param Server Existing server in the network
+ */
+static bool
+Announce_Server(CLIENT * Client, CLIENT * Server)
+{
+	CLIENT *c;
+
+	if (Client_Conn(Server) > NONE) {
+		/* Announce the new server to the one already registered
+		 * which is directly connected to the local server */
+		if (!IRC_WriteStrClient
+		    (Server, "SERVER %s %d %d :%s", Client_ID(Client),
+		     Client_Hops(Client) + 1, Client_MyToken(Client),
+		     Client_Info(Client)))
+			return DISCONNECTED;
+	}
+
+	if (Client_Hops(Server) == 1)
+		c = Client_ThisServer();
+	else
+		c = Client_Introducer(Server);
+
+	/* Inform new server about the one already registered in the network */
+	return IRC_WriteStrClientPrefix(Client, c, "SERVER %s %d %d :%s",
+		Client_ID(Server), Client_Hops(Server) + 1,
+		Client_MyToken(Server), Client_Info(Server));
+} /* Announce_Server */
+
+
+/**
+ * Announce existing user to a new server
+ * @param Client New server
+ * @param User Existing user in the network
+ */
+static bool
+Announce_User(CLIENT * Client, CLIENT * User)
+{
+	return IRC_WriteStrClient(Client, "NICK %s %d %s %s %d +%s :%s",
+		Client_ID(User), Client_Hops(User) + 1, Client_User(User),
+		Client_Hostname(User), Client_MyToken(Client_Introducer(User)),
+		Client_Modes(User), Client_Info(User));
+} /* Announce_User */
+
+
+#ifdef IRCPLUS
+
+/**
+ * Synchronize invite and ban lists between servers
+ * @param Client New server
+ */
+static bool
+Synchronize_Lists(CLIENT * Client)
+{
+	CHANNEL *c;
+	struct list_head *head;
+	struct list_elem *elem;
+
+	assert(Client != NULL);
+
+	c = Channel_First();
+	while (c) {
+		/* ban list */
+		head = Channel_GetListBans(c);
+		elem = Lists_GetFirst(head);
+		while (elem) {
+			if (!IRC_WriteStrClient(Client, "MODE %s +b %s",
+						Channel_Name(c),
+						Lists_GetMask(elem))) {
+				return DISCONNECTED;
+			}
+			elem = Lists_GetNext(elem);
+		}
+
+		/* invite list */
+		head = Channel_GetListInvites(c);
+		elem = Lists_GetFirst(head);
+		while (elem) {
+			if (!IRC_WriteStrClient(Client, "MODE %s +I %s",
+						Channel_Name(c),
+						Lists_GetMask(elem))) {
+				return DISCONNECTED;
+			}
+			elem = Lists_GetNext(elem);
+		}
+
+		c = Channel_Next(c);
+	}
+	return CONNECTED;
+}
+
+
+/**
+ * Send CHANINFO commands to a new server (inform it about existing channels).
+ * @param Client New server
+ * @param Chan Channel
+ */
+static bool
+Send_CHANINFO(CLIENT * Client, CHANNEL * Chan)
+{
+	char *modes, *topic;
+	bool has_k, has_l;
+	
+#ifdef DEBUG
+	Log(LOG_DEBUG, "Sending CHANINFO commands ...");
+#endif
+	
+	modes = Channel_Modes(Chan);
+	topic = Channel_Topic(Chan);
+	
+	if (!*modes && !*topic)
+		return CONNECTED;
+	
+	has_k = strchr(modes, 'k') != NULL;
+	has_l = strchr(modes, 'l') != NULL;
+	
+	/* send CHANINFO */
+	if (!has_k && !has_l) {
+		if (!*topic) {
+			/* "CHANINFO <chan> +<modes>" */
+			return IRC_WriteStrClient(Client, "CHANINFO %s +%s",
+						  Channel_Name(Chan), modes);
+		}
+		/* "CHANINFO <chan> +<modes> :<topic>" */
+		return IRC_WriteStrClient(Client, "CHANINFO %s +%s :%s",
+					  Channel_Name(Chan), modes, topic);
+	}
+	/* "CHANINFO <chan> +<modes> <key> <limit> :<topic>" */
+	return IRC_WriteStrClient(Client, "CHANINFO %s +%s %s %lu :%s",
+				  Channel_Name(Chan), modes,
+				  has_k ? Channel_Key(Chan) : "*",
+				  has_l ? Channel_MaxUsers(Chan) : 0, topic);
+} /* Send_CHANINFO */
+
+#endif /* IRCPLUS */
+
+
+/**
+ * Handle ENDOFMOTD (376) numeric and login remote server.
+ * The peer is either an IRC server (no IRC+ protocol), or we got the
+ * ENDOFMOTD numeric from an IRC+ server. We have to register the new server.
+ */
+GLOBAL bool
+IRC_Num_ENDOFMOTD(CLIENT * Client, UNUSED REQUEST * Req)
+{
+	char str[LINE_LEN];
+	int max_hops, i;
+	CLIENT *c, *cl;
+	CHANNEL *chan;
+	CL2CHAN *cl2chan;
+
+	Client_SetType(Client, CLIENT_SERVER);
+
+	Log(LOG_NOTICE | LOG_snotice,
+	    "Server \"%s\" registered (connection %d, 1 hop - direct link).",
+	    Client_ID(Client), Client_Conn(Client));
+
+	/* Get highest hop count */
+	max_hops = 0;
+	c = Client_First();
+	while (c) {
+		if (Client_Hops(c) > max_hops)
+			max_hops = Client_Hops(c);
+		c = Client_Next(c);
+	}
+
+	/* Inform the new server about all other servers, and announce the
+	 * new server to all the already registered ones. Important: we have
+	 * to do this "in order" and can't introduce servers of which the
+	 * "toplevel server" isn't known already. */
+	for (i = 0; i < (max_hops + 1); i++) {
+		for (c = Client_First(); c != NULL; c = Client_Next(c)) {
+			if (Client_Type(c) != CLIENT_SERVER)
+				continue;	/* not a server */
+			if (Client_Hops(c) != i)
+				continue;	/* not actual "nesting level" */
+			if (c == Client || c == Client_ThisServer())
+				continue;	/* that's us or the peer! */
+
+			if (!Announce_Server(Client, c))
+				return DISCONNECTED;
+		}
+	}
+
+	/* Announce all the users to the new server */
+	c = Client_First();
+	while (c) {
+		if (Client_Type(c) == CLIENT_USER) {
+			if (!Announce_User(Client, c))
+				return DISCONNECTED;
+		}
+		c = Client_Next(c);
+	}
+
+	/* Announce all channels to the new server */
+	chan = Channel_First();
+	while (chan) {
+#ifdef IRCPLUS
+		/* Send CHANINFO if the peer supports it */
+		if (strchr(Client_Flags(Client), 'C')) {
+			if (!Send_CHANINFO(Client, chan))
+				return DISCONNECTED;
+		}
+#endif
+
+		/* Get all the members of this channel */
+		cl2chan = Channel_FirstMember(chan);
+		snprintf(str, sizeof(str), "NJOIN %s :", Channel_Name(chan));
+		while (cl2chan) {
+			cl = Channel_GetClient(cl2chan);
+			assert(cl != NULL);
+
+			/* Nick name, with modes (if applicable) */
+			if (str[strlen(str) - 1] != ':')
+				strlcat(str, ",", sizeof(str));
+			if (strchr(Channel_UserModes(chan, cl), 'v'))
+				strlcat(str, "+", sizeof(str));
+			if (strchr(Channel_UserModes(chan, cl), 'o'))
+				strlcat(str, "@", sizeof(str));
+			strlcat(str, Client_ID(cl), sizeof(str));
+
+			/* Send the data if the buffer is "full" */
+			if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 8)) {
+				if (!IRC_WriteStrClient(Client, "%s", str))
+					return DISCONNECTED;
+				snprintf(str, sizeof(str), "NJOIN %s :",
+					 Channel_Name(chan));
+			}
+
+			cl2chan = Channel_NextMember(chan, cl2chan);
+		}
+
+		/* Data left in the buffer? */
+		if (str[strlen(str) - 1] != ':') {
+			/* Yes, send it ... */
+			if (!IRC_WriteStrClient(Client, "%s", str))
+				return DISCONNECTED;
+		}
+
+		/* Get next channel ... */
+		chan = Channel_Next(chan);
+	}
+
+#ifdef IRCPLUS
+	if (strchr(Client_Flags(Client), 'L')) {
+		LogDebug("Synchronizing INVITE- and BAN-lists ...");
+		if (!Synchronize_Lists(Client))
+			return DISCONNECTED;
+	}
+#endif
+
+	return CONNECTED;
+} /* IRC_Num_ENDOFMOTD */
+
+
+/**
+ * Handle ISUPPORT (005) numeric.
+ */
+GLOBAL bool
+IRC_Num_ISUPPORT(CLIENT * Client, REQUEST * Req)
+{
+	int i;
+	char *key, *value;
+
+	for (i = 1; i < Req->argc - 1; i++) {
+		key = Req->argv[i];
+		value = strchr(key, '=');
+		if (value)
+			*value++ = '\0';
+		else
+			value = "";
+
+		if (strcmp("NICKLEN", key) == 0) {
+			if ((unsigned int)atol(value) == Conf_MaxNickLength - 1)
+				continue;
+
+			/* Nick name length settings are different! */
+			Log(LOG_ERR,
+			    "Peer uses incompatible nick name length (%d/%d)! Disconnecting ...",
+			    Conf_MaxNickLength - 1, atoi(value));
+			Conn_Close(Client_Conn(Client),
+				   "Incompatible nick name length",
+				   NULL, false);
+			return DISCONNECTED;
+		}
+	}
+
+	return CONNECTED;
+} /* IRC_Num_ISUPPORT */
+
+
+/* -eof- */

+ 24 - 0
src/ngircd/numeric.h

@@ -0,0 +1,24 @@
+/*
+ * ngIRCd -- The Next Generation IRC Daemon
+ * Copyright (c)2001-2007 by 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.
+ *
+ * $Id: numeric.h,v 1.1 2007/11/21 12:20:32 alex Exp $
+ *
+ * Handlers for IRC numerics sent to the server (header)
+ */
+
+#ifndef __numeric_h__
+#define __numeric_h__
+
+GLOBAL bool IRC_Num_ENDOFMOTD PARAMS((CLIENT *Client, UNUSED REQUEST *Req));
+GLOBAL bool IRC_Num_ISUPPORT PARAMS((CLIENT *Client, REQUEST *Req));
+
+#endif
+
+/* -eof- */

+ 136 - 87
src/ngircd/parse.c

@@ -1,6 +1,6 @@
 /*
 /*
  * ngIRCd -- The Next Generation IRC Daemon
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2008 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
@@ -9,11 +9,8 @@
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  */
  */
 
 
-
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: parse.c,v 1.67 2006/04/23 10:37:27 fw Exp $";
-
 /**
 /**
  * @file
  * @file
  * IRC command parser and validator.
  * IRC command parser and validator.
@@ -48,11 +45,17 @@ static char UNUSED id[] = "$Id: parse.c,v 1.67 2006/04/23 10:37:27 fw Exp $";
 #include "irc-oper.h"
 #include "irc-oper.h"
 #include "irc-server.h"
 #include "irc-server.h"
 #include "irc-write.h"
 #include "irc-write.h"
+#include "numeric.h"
 
 
 #include "exp.h"
 #include "exp.h"
 
 
+struct _NUMERIC {
+	int numeric;
+	bool (*function) PARAMS(( CLIENT *Client, REQUEST *Request ));
+};
+
 
 
-COMMAND My_Commands[] =
+static COMMAND My_Commands[] =
 {
 {
 	{ "ADMIN", IRC_ADMIN, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "ADMIN", IRC_ADMIN, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "AWAY", IRC_AWAY, CLIENT_USER, 0, 0, 0 },
 	{ "AWAY", IRC_AWAY, CLIENT_USER, 0, 0, 0 },
@@ -61,6 +64,7 @@ COMMAND My_Commands[] =
 	{ "DISCONNECT", IRC_DISCONNECT, CLIENT_USER, 0, 0, 0 },
 	{ "DISCONNECT", IRC_DISCONNECT, CLIENT_USER, 0, 0, 0 },
 	{ "ERROR", IRC_ERROR, 0xFFFF, 0, 0, 0 },
 	{ "ERROR", IRC_ERROR, 0xFFFF, 0, 0, 0 },
 	{ "HELP", IRC_HELP, CLIENT_USER, 0, 0, 0 },
 	{ "HELP", IRC_HELP, CLIENT_USER, 0, 0, 0 },
+	{ "INFO", IRC_INFO, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "INVITE", IRC_INVITE, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "INVITE", IRC_INVITE, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "ISON", IRC_ISON, CLIENT_USER, 0, 0, 0 },
 	{ "ISON", IRC_ISON, CLIENT_USER, 0, 0, 0 },
 	{ "JOIN", IRC_JOIN, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "JOIN", IRC_JOIN, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
@@ -87,12 +91,15 @@ COMMAND My_Commands[] =
 	{ "SERVER", IRC_SERVER, 0xFFFF, 0, 0, 0 },
 	{ "SERVER", IRC_SERVER, 0xFFFF, 0, 0, 0 },
 	{ "SQUIT", IRC_SQUIT, CLIENT_SERVER, 0, 0, 0 },
 	{ "SQUIT", IRC_SQUIT, CLIENT_SERVER, 0, 0, 0 },
 	{ "STATS", IRC_STATS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "STATS", IRC_STATS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
+	{ "SUMMON", IRC_SUMMON, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "TIME", IRC_TIME, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "TIME", IRC_TIME, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "TOPIC", IRC_TOPIC, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "TOPIC", IRC_TOPIC, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "TRACE", IRC_TRACE, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "TRACE", IRC_TRACE, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "USER", IRC_USER, 0xFFFF, 0, 0, 0 },
 	{ "USER", IRC_USER, 0xFFFF, 0, 0, 0 },
 	{ "USERHOST", IRC_USERHOST, CLIENT_USER, 0, 0, 0 },
 	{ "USERHOST", IRC_USERHOST, CLIENT_USER, 0, 0, 0 },
+	{ "USERS", IRC_USERS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "VERSION", IRC_VERSION, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "VERSION", IRC_VERSION, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
+	{ "WALLOPS", IRC_WALLOPS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "WHO", IRC_WHO, CLIENT_USER, 0, 0, 0 },
 	{ "WHO", IRC_WHO, CLIENT_USER, 0, 0, 0 },
 	{ "WHOIS", IRC_WHOIS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "WHOIS", IRC_WHOIS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "WHOWAS", IRC_WHOWAS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "WHOWAS", IRC_WHOWAS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
@@ -102,7 +109,6 @@ COMMAND My_Commands[] =
 	{ NULL, NULL, 0x0, 0, 0, 0 } /* Ende-Marke */
 	{ NULL, NULL, 0x0, 0, 0, 0 } /* Ende-Marke */
 };
 };
 
 
-
 static void Init_Request PARAMS(( REQUEST *Req ));
 static void Init_Request PARAMS(( REQUEST *Req ));
 
 
 static bool Validate_Prefix PARAMS(( CONN_ID Idx, REQUEST *Req, bool *Closed ));
 static bool Validate_Prefix PARAMS(( CONN_ID Idx, REQUEST *Req, bool *Closed ));
@@ -111,6 +117,7 @@ static bool Validate_Args PARAMS(( CONN_ID Idx, REQUEST *Req, bool *Closed ));
 
 
 static bool Handle_Request PARAMS(( CONN_ID Idx, REQUEST *Req ));
 static bool Handle_Request PARAMS(( CONN_ID Idx, REQUEST *Req ));
 
 
+#define ARRAY_SIZE(x)	(sizeof(x)/sizeof((x)[0]))
 
 
 /**
 /**
  * Return the pointer to the global "IRC command structure".
  * Return the pointer to the global "IRC command structure".
@@ -328,27 +335,117 @@ Validate_Command( UNUSED CONN_ID Idx, UNUSED REQUEST *Req, bool *Closed )
 
 
 
 
 static bool
 static bool
-Validate_Args( UNUSED CONN_ID Idx, UNUSED REQUEST *Req, bool *Closed )
+Validate_Args(CONN_ID Idx, REQUEST *Req, bool *Closed)
 {
 {
+#ifdef STRICT_RFC
+	int i;
+#endif
+
 	assert( Idx >= 0 );
 	assert( Idx >= 0 );
 	assert( Req != NULL );
 	assert( Req != NULL );
 	*Closed = false;
 	*Closed = false;
 
 
+#ifdef STRICT_RFC
+	/* CR and LF are never allowed in command parameters.
+	 * But since we do accept lines terminated only with CR or LF in
+	 * "non-RFC-compliant mode" (besides the correct CR+LF combination),
+	 * this check can only trigger in "strict RFC" mode; therefore we
+	 * optimize it away otherwise ... */
+	for (i = 0; i < Req->argc; i++) {
+		if (strchr(Req->argv[i], '\r') || strchr(Req->argv[i], '\n')) {
+			Log(LOG_ERR,
+			    "Invalid character(s) in parameter (connection %d, command %s)!?",
+			    Idx, Req->command);
+			if (!Conn_WriteStr(Idx,
+					   "ERROR :Invalid character(s) in parameter!"))
+				*Closed = true;
+			return false;
+		}
+	}
+#endif
+
 	return true;
 	return true;
 } /* Validate_Args */
 } /* Validate_Args */
 
 
 
 
+/* Command is a status code ("numeric") from another server */
+static bool
+Handle_Numeric(CLIENT *client, REQUEST *Req)
+{
+	static const struct _NUMERIC Numerics[] = {
+		{ 005, IRC_Num_ISUPPORT },
+		{ 376, IRC_Num_ENDOFMOTD }
+	};
+	int i, num;
+	char str[LINE_LEN];
+	CLIENT *prefix, *target = NULL;
+
+	/* Determine target */
+	if (Req->argc > 0)
+		target = Client_Search(Req->argv[0]);
+
+	if (!target) {
+		/* Status code without target!? */
+		if (Req->argc > 0)
+			Log(LOG_WARNING,
+			    "Unknown target for status code %s: \"%s\"",
+			    Req->command, Req->argv[0]);
+		else
+			Log(LOG_WARNING,
+			    "Unknown target for status code %s!",
+			    Req->command);
+		return true;
+	}
+	if (target == Client_ThisServer()) {
+		/* This server is the target of the numeric */
+		num = atoi(Req->command);
+
+		for (i = 0; i < (int) ARRAY_SIZE(Numerics); i++) {
+			if (num == Numerics[i].numeric)
+				return Numerics[i].function(client, Req);
+		}
+
+		LogDebug("Ignored status code %s from \"%s\".",
+			 Req->command, Client_ID(client));
+		return true;
+	}
+
+	/* Determine source */
+	if (! Req->prefix[0]) {
+		/* Oops, no prefix!? */
+		Log(LOG_WARNING, "Got status code %s from \"%s\" without prefix!?",
+						Req->command, Client_ID(client));
+		return true;
+	}
+
+	prefix = Client_Search(Req->prefix);
+	if (! prefix) { /* Oops, unknown prefix!? */
+		Log(LOG_WARNING, "Got status code %s from unknown source: \"%s\"", Req->command, Req->prefix);
+		return true;
+	}
+
+	/* Forward status code */
+	strlcpy(str, Req->command, sizeof(str));
+	for (i = 0; i < Req->argc; i++) {
+		if (i < Req->argc - 1)
+			strlcat(str, " ", sizeof(str));
+		else
+			strlcat(str, " :", sizeof(str));
+		strlcat(str, Req->argv[i], sizeof(str));
+	}
+	return IRC_WriteStrClientPrefix(target, prefix, "%s", str);
+}
+
+
 static bool
 static bool
 Handle_Request( CONN_ID Idx, REQUEST *Req )
 Handle_Request( CONN_ID Idx, REQUEST *Req )
 {
 {
 	/* Client-Request verarbeiten. Bei einem schwerwiegenden Fehler
 	/* Client-Request verarbeiten. Bei einem schwerwiegenden Fehler
 	 * wird die Verbindung geschlossen und false geliefert. */
 	 * wird die Verbindung geschlossen und false geliefert. */
-
-	CLIENT *client, *target, *prefix;
-	char str[LINE_LEN];
-	bool result;
+	CLIENT *client;
+	bool result = true;
+	int client_type;
 	COMMAND *cmd;
 	COMMAND *cmd;
-	int i;
 
 
 	assert( Idx >= 0 );
 	assert( Idx >= 0 );
 	assert( Req != NULL );
 	assert( Req != NULL );
@@ -357,90 +454,44 @@ Handle_Request( CONN_ID Idx, REQUEST *Req )
 	client = Conn_GetClient( Idx );
 	client = Conn_GetClient( Idx );
 	assert( client != NULL );
 	assert( client != NULL );
 
 
-	/* Statuscode? */
-	if(( Client_Type( client ) == CLIENT_SERVER ) && ( strlen( Req->command ) == 3 ) && ( atoi( Req->command ) > 100 ))
-	{
-		/* Command is a status code from an other server */
-
-		/* Determine target */
-		if( Req->argc > 0 ) target = Client_Search( Req->argv[0] );
-		else target = NULL;
-		if( ! target )
-		{
-			/* Status code without target!? */
-			if( Req->argc > 0 ) Log( LOG_WARNING, "Unknown target for status code %s: \"%s\"", Req->command, Req->argv[0] );
-			else Log( LOG_WARNING, "Unknown target for status code %s!", Req->command );
-			return true;
-		}
-		if( target == Client_ThisServer( ))
-		{
-			/* This server is the target, ignore it */
-			Log( LOG_DEBUG, "Ignored status code %s from \"%s\".", Req->command, Client_ID( client ));
-			return true;
-		}
-
-		/* Determine source */
-		if( ! Req->prefix[0] )
-		{
-			/* Oops, no prefix!? */
-			Log( LOG_WARNING, "Got status code %s from \"%s\" without prefix!?", Req->command, Client_ID( client ));
-			return true;
-		}
-		else prefix = Client_Search( Req->prefix );
-		if( ! prefix )
-		{
-			/* Oops, unknown prefix!? */
-			Log( LOG_WARNING, "Got status code %s from unknown source: \"%s\"", Req->command, Req->prefix );
-			return true;
-		}
-
-		/* Forward status code */
-		strlcpy( str, Req->command, sizeof( str ));
-		for( i = 0; i < Req->argc; i++ )
-		{
-			if( i < Req->argc - 1 ) strlcat( str, " ", sizeof( str ));
-			else strlcat( str, " :", sizeof( str ));
-			strlcat( str, Req->argv[i], sizeof( str ));
-		}
-		return IRC_WriteStrClientPrefix( target, prefix, "%s", str );
-	}
+	/* Numeric? */
+	client_type = Client_Type(client);
+	if ((client_type == CLIENT_SERVER ||
+	     client_type == CLIENT_UNKNOWNSERVER)
+	    && strlen(Req->command) == 3 && atoi(Req->command) > 1)
+		return Handle_Numeric(client, Req);
 
 
 	cmd = My_Commands;
 	cmd = My_Commands;
-	while( cmd->name )
-	{
+	while (cmd->name) {
 		/* Befehl suchen */
 		/* Befehl suchen */
-		if( strcasecmp( Req->command, cmd->name ) != 0 )
-		{
-			cmd++; continue;
+		if (strcasecmp(Req->command, cmd->name) != 0) {
+			cmd++;
+			continue;
 		}
 		}
 
 
-		if( Client_Type( client ) & cmd->type )
-		{
-			/* Command is allowed for this client: call it and count produced bytes */
-			Conn_ResetWCounter( );
-			result = (cmd->function)( client, Req );
-			cmd->bytes += Conn_WCounter( );
+		if (!(client_type & cmd->type))
+			return IRC_WriteStrClient(client, ERR_NOTREGISTERED_MSG, Client_ID(client));
 
 
-			/* Adjust counters */
-			if( Client_Type( client ) != CLIENT_SERVER ) cmd->lcount++;
-			else cmd->rcount++;
+		/* Command is allowed for this client: call it and count produced bytes */
+		Conn_ResetWCounter();
+		result = (cmd->function)(client, Req);
+		cmd->bytes += Conn_WCounter();
 
 
-			return result;
-		}
+		/* Adjust counters */
+		if (client_type != CLIENT_SERVER)
+			cmd->lcount++;
 		else
 		else
-		{
-			/* Befehl ist fuer diesen Client-Typ nicht erlaubt! */
-			return IRC_WriteStrClient( client, ERR_NOTREGISTERED_MSG, Client_ID( client ));
-		}
+			cmd->rcount++;
+		return result;
 	}
 	}
 
 
-	if( Client_Type( client ) != CLIENT_USER &&
-	    Client_Type( client ) != CLIENT_SERVER &&
-	    Client_Type( client ) != CLIENT_SERVICE )
+	if (client_type != CLIENT_USER &&
+	    client_type != CLIENT_SERVER &&
+	    client_type != CLIENT_SERVICE )
 		return true;
 		return true;
-	
+
 	/* Unknown command and registered connection: generate error: */
 	/* Unknown command and registered connection: generate error: */
-	Log( LOG_DEBUG, "Connection %d: Unknown command \"%s\", %d %s,%s prefix.",
+	LogDebug("Connection %d: Unknown command \"%s\", %d %s,%s prefix.",
 			Client_Conn( client ), Req->command, Req->argc,
 			Client_Conn( client ), Req->command, Req->argc,
 			Req->argc == 1 ? "parameter" : "parameters",
 			Req->argc == 1 ? "parameter" : "parameters",
 			Req->prefix ? "" : " no" );
 			Req->prefix ? "" : " no" );
@@ -449,10 +500,8 @@ Handle_Request( CONN_ID Idx, REQUEST *Req )
 		result = IRC_WriteStrClient(client, ERR_UNKNOWNCOMMAND_MSG,
 		result = IRC_WriteStrClient(client, ERR_UNKNOWNCOMMAND_MSG,
 				Client_ID(client), Req->command);
 				Client_ID(client), Req->command);
 		Conn_SetPenalty(Idx, 1);
 		Conn_SetPenalty(Idx, 1);
-		return result;
 	}
 	}
-
-	return true;
+	return result;
 } /* Handle_Request */
 } /* Handle_Request */
 
 
 
 

+ 3 - 4
src/ngircd/parse.h

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: parse.h,v 1.11 2005/03/19 18:43:49 fw Exp $
+ * $Id: parse.h,v 1.13 2008/01/13 16:12:49 fw Exp $
  *
  *
  * IRC command parser and validator (header)
  * IRC command parser and validator (header)
  */
  */
@@ -33,8 +33,8 @@ typedef struct _COMMAND
 	char *name;			/* command name */
 	char *name;			/* command name */
 	bool (*function) PARAMS(( CLIENT *Client, REQUEST *Request ));
 	bool (*function) PARAMS(( CLIENT *Client, REQUEST *Request ));
 	CLIENT_TYPE type;		/* valid client types (bit mask) */
 	CLIENT_TYPE type;		/* valid client types (bit mask) */
-	long lcount, rcount;	/* number of local and remote calls */
-	long bytes;		/* number of bytes created */
+	long lcount, rcount;		/* number of local and remote calls */
+	long bytes;			/* number of bytes created */
 } COMMAND;
 } COMMAND;
 
 
 
 
@@ -42,7 +42,6 @@ GLOBAL bool Parse_Request PARAMS((CONN_ID Idx, char *Request ));
 
 
 GLOBAL COMMAND *Parse_GetCommandStruct PARAMS(( void ));
 GLOBAL COMMAND *Parse_GetCommandStruct PARAMS(( void ));
 
 
-
 #endif
 #endif
 
 
 
 

+ 302 - 122
src/ngircd/resolve.c

@@ -14,7 +14,7 @@
 
 
 #include "portab.h"
 #include "portab.h"
 
 
-static char UNUSED id[] = "$Id: resolve.c,v 1.24.2.2 2006/12/17 22:59:56 fw Exp $";
+static char UNUSED id[] = "$Id: resolve.c,v 1.29 2008/02/26 22:04:17 fw Exp $";
 
 
 #include "imp.h"
 #include "imp.h"
 #include <assert.h>
 #include <assert.h>
@@ -24,7 +24,6 @@ static char UNUSED id[] = "$Id: resolve.c,v 1.24.2.2 2006/12/17 22:59:56 fw Exp
 #include <unistd.h>
 #include <unistd.h>
 #include <sys/socket.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/in.h>
-#include <arpa/inet.h>
 #include <netdb.h>
 #include <netdb.h>
 
 
 #ifdef IDENTAUTH
 #ifdef IDENTAUTH
@@ -42,12 +41,13 @@ static char UNUSED id[] = "$Id: resolve.c,v 1.24.2.2 2006/12/17 22:59:56 fw Exp
 #include "io.h"
 #include "io.h"
 
 
 
 
-static void Do_ResolveAddr PARAMS(( struct sockaddr_in *Addr, int Sock, int w_fd ));
+static void Do_ResolveAddr PARAMS(( const ng_ipaddr_t *Addr, int Sock, int w_fd ));
 static void Do_ResolveName PARAMS(( const char *Host, int w_fd ));
 static void Do_ResolveName PARAMS(( const char *Host, int w_fd ));
 static bool register_callback PARAMS((RES_STAT *s, void (*cbfunc)(int, short)));
 static bool register_callback PARAMS((RES_STAT *s, void (*cbfunc)(int, short)));
 
 
-#ifdef h_errno
-static char *Get_Error PARAMS(( int H_Error ));
+#ifdef WANT_IPV6
+extern bool Conf_ConnectIPv4;
+extern bool Conf_ConnectIPv6;
 #endif
 #endif
 
 
 static pid_t
 static pid_t
@@ -82,7 +82,7 @@ Resolver_fork(int *pipefds)
  * Resolve IP (asynchronous!).
  * Resolve IP (asynchronous!).
  */
  */
 GLOBAL bool
 GLOBAL bool
-Resolve_Addr(RES_STAT * s, struct sockaddr_in *Addr, int identsock,
+Resolve_Addr(RES_STAT * s, const ng_ipaddr_t *Addr, int identsock,
 	     void (*cbfunc) (int, short))
 	     void (*cbfunc) (int, short))
 {
 {
 	int pipefd[2];
 	int pipefd[2];
@@ -92,9 +92,8 @@ Resolve_Addr(RES_STAT * s, struct sockaddr_in *Addr, int identsock,
 
 
 	pid = Resolver_fork(pipefd);
 	pid = Resolver_fork(pipefd);
 	if (pid > 0) {
 	if (pid > 0) {
-#ifdef DEBUG
-		Log( LOG_DEBUG, "Resolver for %s created (PID %d).", inet_ntoa( Addr->sin_addr ), pid );
-#endif
+		Log(LOG_DEBUG, "Resolver for %s created (PID %d).", ng_ipaddr_tostr(Addr), pid);
+
 		s->pid = pid;
 		s->pid = pid;
 		s->resolver_fd = pipefd[0];
 		s->resolver_fd = pipefd[0];
 		return register_callback(s, cbfunc);
 		return register_callback(s, cbfunc);
@@ -147,158 +146,339 @@ Resolve_Init(RES_STAT *s)
 }
 }
 
 
 
 
-static void
-Do_ResolveAddr( struct sockaddr_in *Addr, int identsock, int w_fd )
+#ifndef WANT_IPV6
+#ifdef h_errno
+static char *
+Get_Error( int H_Error )
 {
 {
-	/* Resolver sub-process: resolve IP address and write result into
-	 * pipe to parent. */
+	/* Get error message for H_Error */
+	switch( H_Error ) {
+	case HOST_NOT_FOUND:
+		return "host not found";
+	case NO_DATA:
+		return "name valid but no IP address defined";
+	case NO_RECOVERY:
+		return "name server error";
+	case TRY_AGAIN:
+		return "name server temporary not available";
+	}
+	return "unknown error";
+}
+#endif /* h_errno */
+#endif /* WANT_IPV6 */
 
 
-	char hostname[HOST_LEN];
-	char ipstr[HOST_LEN];
-	struct hostent *h;
-	size_t len;
-	struct in_addr *addr;
-	char *ntoaptr;
-	array resolved_addr;
+
+/* Do "IDENT" (aka "AUTH") lookup and append result to resolved_addr array */
+static void
+Do_IdentQuery(int identsock, array *resolved_addr)
+{
 #ifdef IDENTAUTH
 #ifdef IDENTAUTH
 	char *res;
 	char *res;
+
+	assert(identsock >= 0);
+
+#ifdef DEBUG
+	Log_Resolver(LOG_DEBUG, "Doing IDENT lookup on socket %d ...", identsock);
 #endif
 #endif
-	array_init(&resolved_addr);
-	/* Resolve IP address */
+	if (identsock < 0)
+		return;
+	res = ident_id( identsock, 10 );
 #ifdef DEBUG
 #ifdef DEBUG
-	Log_Resolver( LOG_DEBUG, "Now resolving %s ...", inet_ntoa( Addr->sin_addr ));
+	Log_Resolver(LOG_DEBUG, "Ok, IDENT lookup on socket %d done: \"%s\"",
+						identsock, res ? res : "(NULL)" );
 #endif
 #endif
-	h = gethostbyaddr( (char *)&Addr->sin_addr, sizeof( Addr->sin_addr ), AF_INET );
-	if (!h) {
-#ifdef h_errno
-		Log_Resolver( LOG_WARNING, "Can't resolve address \"%s\": %s!", inet_ntoa( Addr->sin_addr ), Get_Error( h_errno ));
+	if (!res) /* no result */
+		return;
+	if (!array_cats(resolved_addr, res))
+		Log_Resolver(LOG_WARNING, "Resolver: Cannot copy IDENT result: %s!", strerror(errno));
+
+	free(res);
+#else
+	(void) identsock;
+	(void) resolved_addr;
+#endif
+}
+
+
+/**
+ * perform reverse DNS lookup and put result string into resbuf.
+ * If no hostname could be obtained, this function stores the string representation of
+ * the IP address in resbuf and returns false.
+ * @param IpAddr ip address to resolve
+ * @param resbuf result buffer to store DNS name/string representation of ip address
+ * @reslen size of result buffer (must be >= NGT_INET_ADDRSTRLEN)
+ * @return true if reverse lookup successful, false otherwise
+ */
+static bool
+ReverseLookup(const ng_ipaddr_t *IpAddr, char *resbuf, size_t reslen)
+{
+	char tmp_ip_str[NG_INET_ADDRSTRLEN];
+	const char *errmsg;
+#ifdef HAVE_GETNAMEINFO
+	static const char funcname[]="getnameinfo";
+	int res;
+
+	*resbuf = 0;
+
+	res = getnameinfo((struct sockaddr *) IpAddr, ng_ipaddr_salen(IpAddr),
+				resbuf, reslen, NULL, 0, NI_NAMEREQD);
+	if (res == 0)
+		return true;
+
+	if (res == EAI_SYSTEM)
+		errmsg = strerror(errno);
+	else
+		errmsg = gai_strerror(res);
 #else
 #else
-		Log_Resolver( LOG_WARNING, "Can't resolve address \"%s\"!", inet_ntoa( Addr->sin_addr ));
-#endif	
-		strlcpy( hostname, inet_ntoa( Addr->sin_addr ), sizeof( hostname ));
+	const struct sockaddr_in *Addr = (const struct sockaddr_in *) IpAddr;
+	struct hostent *h;
+	static const char funcname[]="gethostbyaddr";
+
+	h = gethostbyaddr((char *)&Addr->sin_addr, sizeof(Addr->sin_addr), AF_INET);
+	if (h) {
+		if (strlcpy(resbuf, h->h_name, reslen) < reslen)
+			return true;
+		errmsg = "hostname too long";
 	} else {
 	} else {
- 		strlcpy( hostname, h->h_name, sizeof( hostname ));
-
-		h = gethostbyname( hostname );
-		if ( h ) {
-			if (memcmp(h->h_addr, &Addr->sin_addr, sizeof (struct in_addr))) {
-				addr = (struct in_addr*) h->h_addr;
-				strlcpy(ipstr, inet_ntoa(*addr), sizeof ipstr); 
-				ntoaptr = inet_ntoa( Addr->sin_addr );
-				Log(LOG_WARNING,"Possible forgery: %s resolved to %s (which is at ip %s!)",
-										ntoaptr, hostname, ipstr);
-				strlcpy( hostname, ntoaptr, sizeof hostname);
-			}
-		} else {
-			ntoaptr = inet_ntoa( Addr->sin_addr );
-			Log(LOG_WARNING, "Possible forgery: %s resolved to %s (which has no ip address)",
-											ntoaptr, hostname);
-			strlcpy( hostname, ntoaptr, sizeof hostname);
-		}
+# ifdef h_errno
+		errmsg = Get_Error(h_errno);
+# else
+		errmsg = "unknown error";
+# endif /* h_errno */
 	}
 	}
-	Log_Resolver( LOG_DEBUG, "Ok, translated %s to \"%s\".", inet_ntoa( Addr->sin_addr ), hostname );
+#endif	/* HAVE_GETNAMEINFO */
 
 
-	len = strlen( hostname ); 
-	hostname[len] = '\n'; len++;
-	if (!array_copyb(&resolved_addr, hostname, len )) {
-		Log_Resolver( LOG_CRIT, "Resolver: Can't copy resolved name: %s!", strerror( errno ));
-		close( w_fd );
-		return;
-	}
+	assert(errmsg);
+	assert(reslen >= NG_INET_ADDRSTRLEN);
+	ng_ipaddr_tostr_r(IpAddr, tmp_ip_str);
 
 
-#ifdef IDENTAUTH
-	assert(identsock >= 0);
-	if (identsock >= 0) {
-		/* Do "IDENT" (aka "AUTH") lookup and append result to resolved_addr array */
-#ifdef DEBUG
-		Log_Resolver( LOG_DEBUG, "Doing IDENT lookup on socket %d ...", identsock );
+	Log_Resolver(LOG_WARNING, "%s: Can't resolve address \"%s\": %s",
+				funcname, tmp_ip_str, errmsg);
+	strlcpy(resbuf, tmp_ip_str, reslen);
+	return false;
+}
+
+
+/**
+ * perform DNS lookup of given host name and fill IpAddr with a list of
+ * ip addresses associated with that name.
+ * ip addresses found are stored in the "array *IpAddr" argument (type ng_ipaddr_t)
+ * @param hostname The domain name to look up.
+ * @param IpAddr pointer to empty and initialized array to store results
+ * @return true if lookup successful, false if domain name not found
+ */
+static bool
+ForwardLookup(const char *hostname, array *IpAddr)
+{
+	ng_ipaddr_t addr;
+#ifdef HAVE_GETADDRINFO
+	int res;
+	struct addrinfo *a, *ai_results;
+	static struct addrinfo hints = {
+#ifndef WANT_IPV6
+		.ai_family = AF_INET,
 #endif
 #endif
-		res = ident_id( identsock, 10 );
-#ifdef DEBUG
-		Log_Resolver(LOG_DEBUG, "Ok, IDENT lookup on socket %d done: \"%s\"",
-							identsock, res ? res : "(NULL)" );
+#ifdef AI_ADDRCONFIG	/* glibc has this, but not e.g. netbsd 4.0 */
+		.ai_flags = AI_ADDRCONFIG,
 #endif
 #endif
-		if (res && !array_cats(&resolved_addr, res)) {
-			Log_Resolver(LOG_WARNING, "Resolver: Cannot copy IDENT result: %s!", strerror(errno));
-			/* omit ident and return hostname only */ 
-		}
+		.ai_socktype = SOCK_STREAM,
+		.ai_protocol = IPPROTO_TCP
+	};
+#ifdef WANT_IPV6
+	assert(Conf_ConnectIPv6 || Conf_ConnectIPv4);
+
+	if (!Conf_ConnectIPv6)
+		hints.ai_family = AF_INET;
+	if (!Conf_ConnectIPv4)
+		hints.ai_family = AF_INET6;
+#endif
+	res = getaddrinfo(hostname, NULL, &hints, &ai_results);
+	switch (res) {
+	case 0:	break;
+	case EAI_SYSTEM:
+		Log_Resolver(LOG_WARNING, "Can't resolve \"%s\": %s", hostname, strerror(errno));
+		return false;
+	default:
+		Log_Resolver(LOG_WARNING, "Can't resolve \"%s\": %s", hostname, gai_strerror(res));
+		return false;
+	}
 
 
-		if (res) free(res);
+	for (a = ai_results; a != NULL; a = a->ai_next) {
+		assert(a->ai_addrlen <= sizeof(addr));
+
+		if (a->ai_addrlen > sizeof(addr))
+			continue;
+
+		memcpy(&addr, a->ai_addr, a->ai_addrlen);
+
+		if (!array_catb(IpAddr, (char *)&addr, sizeof(addr)))
+			break;
 	}
 	}
+
+	freeaddrinfo(ai_results);
+	return a == NULL;
 #else
 #else
-	(void)identsock;
+	struct hostent *h = gethostbyname(hostname);
+
+	if (!h) {
+#ifdef h_errno
+		Log_Resolver(LOG_WARNING, "Can't resolve \"%s\": %s", hostname, Get_Error(h_errno));
+#else
+		Log_Resolver(LOG_WARNING, "Can't resolve \"%s\"", hostname);
 #endif
 #endif
-	len = array_bytes(&resolved_addr);
-	if( (size_t)write( w_fd, array_start(&resolved_addr), len) != len )
-		Log_Resolver( LOG_CRIT, "Resolver: Can't write result to parent: %s!", strerror( errno ));
+		return false;
+	}
+	memset(&addr, 0, sizeof(addr));
 
 
-	close(w_fd);
-	array_free(&resolved_addr);
-} /* Do_ResolveAddr */
+	addr.sin4.sin_family = AF_INET;
+	memcpy(&addr.sin4.sin_addr, h->h_addr, sizeof(struct in_addr));
+
+	return array_copyb(IpAddr, (char *)&addr, sizeof(addr));
+#endif /* HAVE_GETADDRINFO */
+}
+
+
+static bool
+Addr_in_list(const array *resolved_addr, const ng_ipaddr_t *Addr)
+{
+	char tmp_ip_str[NG_INET_ADDRSTRLEN];
+	const ng_ipaddr_t *tmpAddrs = array_start(resolved_addr);
+	size_t len = array_length(resolved_addr, sizeof(*tmpAddrs));
+
+	assert(len > 0);
+	assert(tmpAddrs);
+
+	while (len > 0) {
+		if (ng_ipaddr_ipequal(Addr, tmpAddrs))
+			return true;
+		tmpAddrs++;
+		len--;
+	}
+	/* failed; print list of addresses */
+	ng_ipaddr_tostr_r(Addr, tmp_ip_str);
+	len = array_length(resolved_addr, sizeof(*tmpAddrs));
+	tmpAddrs = array_start(resolved_addr);
+
+	while (len > 0) {
+		Log_Resolver(LOG_WARNING, "Address mismatch: %s != %s",
+			tmp_ip_str, ng_ipaddr_tostr(tmpAddrs));
+		tmpAddrs++;
+		len--;
+	}
+
+	return false;
+}
 
 
 
 
 static void
 static void
-Do_ResolveName( const char *Host, int w_fd )
+Log_Forgery_NoIP(const char *ip, const char *host)
 {
 {
-	/* Resolver sub-process: resolve name and write result into pipe
-	 * to parent. */
+	Log_Resolver(LOG_WARNING, "Possible forgery: %s resolved to %s "
+		"(which has no ip address)", ip, host);
+}
 
 
-	char ip[16];
-	struct hostent *h;
-	struct in_addr *addr;
+static void
+Log_Forgery_WrongIP(const char *ip, const char *host)
+{
+	Log_Resolver(LOG_WARNING,"Possible forgery: %s resolved to %s "
+		"(which points to different address)", ip, host);
+}
+
+
+static void
+ArrayWrite(int fd, const array *a)
+{
+	size_t len = array_bytes(a);
+	const char *data = array_start(a);
+
+	assert(data);
+
+	if( (size_t)write(fd, data, len) != len )
+		Log_Resolver( LOG_CRIT, "Resolver: Can't write to parent: %s!",
+							strerror(errno));
+}
+
+
+static void
+Do_ResolveAddr(const ng_ipaddr_t *Addr, int identsock, int w_fd)
+{
+	/* Resolver sub-process: resolve IP address and write result into
+	 * pipe to parent. */
+	char hostname[CLIENT_HOST_LEN];
+	char tmp_ip_str[NG_INET_ADDRSTRLEN];
 	size_t len;
 	size_t len;
+	array resolved_addr;
 
 
-	Log_Resolver( LOG_DEBUG, "Now resolving \"%s\" ...", Host );
+	array_init(&resolved_addr);
+	ng_ipaddr_tostr_r(Addr, tmp_ip_str);
+#ifdef DEBUG
+	Log_Resolver(LOG_DEBUG, "Now resolving %s ...", tmp_ip_str);
+#endif
+	if (!ReverseLookup(Addr, hostname, sizeof(hostname)))
+		goto dns_done;
 
 
-	/* Resolve hostname */
-	h = gethostbyname( Host );
-	if( h ) {
-		addr = (struct in_addr *)h->h_addr;
-		strlcpy( ip, inet_ntoa( *addr ), sizeof( ip ));
+	if (ForwardLookup(hostname, &resolved_addr)) {
+		if (!Addr_in_list(&resolved_addr, Addr)) {
+			Log_Forgery_WrongIP(tmp_ip_str, hostname);
+			strlcpy(hostname, tmp_ip_str, sizeof(hostname));
+		}
 	} else {
 	} else {
-#ifdef h_errno
-		Log_Resolver( LOG_WARNING, "Can't resolve \"%s\": %s!", Host, Get_Error( h_errno ));
-#else
-		Log_Resolver( LOG_WARNING, "Can't resolve \"%s\"!", Host );
-#endif
-		close(w_fd);
-		return;
+		Log_Forgery_NoIP(tmp_ip_str, hostname);
+		strlcpy(hostname, tmp_ip_str, sizeof(hostname));
 	}
 	}
 #ifdef DEBUG
 #ifdef DEBUG
-	Log_Resolver( LOG_DEBUG, "Ok, translated \"%s\" to %s.", Host, ip );
+	Log_Resolver(LOG_DEBUG, "Ok, translated %s to \"%s\".", tmp_ip_str, hostname);
 #endif
 #endif
-	/* Write result into pipe to parent */
-	len = strlen( ip );
-	if ((size_t)write( w_fd, ip, len ) != len) {
-		Log_Resolver( LOG_CRIT, "Resolver: Can't write to parent: %s!", strerror( errno ));
-		close( w_fd );
+ dns_done:
+	len = strlen(hostname);
+	hostname[len] = '\n';
+	if (!array_copyb(&resolved_addr, hostname, ++len)) {
+		Log_Resolver(LOG_CRIT, "Resolver: Can't copy resolved name: %s!", strerror(errno));
+		array_free(&resolved_addr);
+		return;
 	}
 	}
-} /* Do_ResolveName */
 
 
+	Do_IdentQuery(identsock, &resolved_addr);
 
 
-#ifdef h_errno
+	ArrayWrite(w_fd, &resolved_addr);
 
 
-static char *
-Get_Error( int H_Error )
+	array_free(&resolved_addr);
+} /* Do_ResolveAddr */
+
+
+static void
+Do_ResolveName( const char *Host, int w_fd )
 {
 {
-	/* Get error message for H_Error */
+	/* Resolver sub-process: resolve name and write result into pipe
+	 * to parent. */
+	array IpAddrs;
+#ifdef DEBUG
+	ng_ipaddr_t *addr;
+	size_t len;
+#endif
+	Log_Resolver(LOG_DEBUG, "Now resolving \"%s\" ...", Host);
 
 
-	switch( H_Error )
-	{
-		case HOST_NOT_FOUND:
-			return "host not found";
-		case NO_DATA:
-			return "name valid but no IP address defined";
-		case NO_RECOVERY:
-			return "name server error";
-		case TRY_AGAIN:
-			return "name server temporary not available";
-		default:
-			return "unknown error";
+	array_init(&IpAddrs);
+	/* Resolve hostname */
+	if (!ForwardLookup(Host, &IpAddrs)) {
+		close(w_fd);
+		return;
+	}
+#ifdef DEBUG
+	len = array_length(&IpAddrs, sizeof(*addr));
+	assert(len > 0);
+	addr = array_start(&IpAddrs);
+	assert(addr);
+	for (; len > 0; --len,addr++) {
+		Log_Resolver(LOG_DEBUG, "translated \"%s\" to %s.",
+					Host, ng_ipaddr_tostr(addr));
 	}
 	}
-} /* Get_Error */
-
 #endif
 #endif
+	/* Write result into pipe to parent */
+	ArrayWrite(w_fd, &IpAddrs);
+
+	array_free(&IpAddrs);
+} /* Do_ResolveName */
 
 
 
 
 static bool
 static bool

+ 4 - 2
src/ngircd/resolve.h

@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
  *
- * $Id: resolve.h,v 1.13 2006/05/10 21:24:02 alex Exp $
+ * $Id: resolve.h,v 1.14 2008/02/26 22:04:17 fw Exp $
  *
  *
  * Asynchronous resolver (header)
  * Asynchronous resolver (header)
  */
  */
@@ -18,6 +18,8 @@
 #define __resolve_h__
 #define __resolve_h__
 
 
 #include "array.h"
 #include "array.h"
+#include "tool.h"
+#include "ng_ipaddr.h"
 #include <netinet/in.h>
 #include <netinet/in.h>
 
 
 /* This struct must not be accessed directly */
 /* This struct must not be accessed directly */
@@ -30,7 +32,7 @@ typedef struct _Res_Stat {
 #define Resolve_Getfd(x)		((x)->resolver_fd)
 #define Resolve_Getfd(x)		((x)->resolver_fd)
 #define Resolve_INPROGRESS(x)		((x)->resolver_fd >= 0)
 #define Resolve_INPROGRESS(x)		((x)->resolver_fd >= 0)
 
 
-GLOBAL bool Resolve_Addr PARAMS(( RES_STAT *s, struct sockaddr_in *Addr, int identsock, void (*cbfunc)(int, short)));
+GLOBAL bool Resolve_Addr PARAMS(( RES_STAT *s, const ng_ipaddr_t *Addr, int identsock, void (*cbfunc)(int, short)));
 GLOBAL bool Resolve_Name PARAMS(( RES_STAT *s, const char *Host, void (*cbfunc)(int, short) ));
 GLOBAL bool Resolve_Name PARAMS(( RES_STAT *s, const char *Host, void (*cbfunc)(int, short) ));
 GLOBAL size_t Resolve_Read PARAMS(( RES_STAT *s, void *buf, size_t buflen));
 GLOBAL size_t Resolve_Read PARAMS(( RES_STAT *s, void *buf, size_t buflen));
 GLOBAL void Resolve_Init PARAMS(( RES_STAT *s));
 GLOBAL void Resolve_Init PARAMS(( RES_STAT *s));

+ 16 - 3
src/testsuite/Makefile.am

@@ -9,7 +9,7 @@
 # Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
 # Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
 # der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
 # der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
 #
 #
-# $Id: Makefile.am,v 1.14 2004/09/08 09:40:51 alex Exp $
+# $Id: Makefile.am,v 1.18 2008/02/17 13:26:42 alex Exp $
 #
 #
 
 
 AUTOMAKE_OPTIONS = ../portab/ansi2knr
 AUTOMAKE_OPTIONS = ../portab/ansi2knr
@@ -20,8 +20,8 @@ EXTRA_DIST = \
 	README functions.inc getpid.sh \
 	README functions.inc getpid.sh \
 	start-server.sh stop-server.sh tests.sh stress-server.sh \
 	start-server.sh stop-server.sh tests.sh stress-server.sh \
 	test-loop.sh wait-tests.sh \
 	test-loop.sh wait-tests.sh \
-	connect-test.e channel-test.e mode-test.e \
-	stress-A.e stress-B.e check-idle.e \
+	channel-test.e connect-test.e check-idle.e misc-test.e mode-test.e \
+	who-test.e stress-A.e stress-B.e \
 	ngircd-test.conf
 	ngircd-test.conf
 
 
 all:
 all:
@@ -40,18 +40,31 @@ ngircd-TEST-Binary:
 	[ -f getpid.sh ] || ln -s $(srcdir)/getpid.sh .
 	[ -f getpid.sh ] || ln -s $(srcdir)/getpid.sh .
 
 
 connect-test: tests.sh
 connect-test: tests.sh
+	rm -f connect-test
 	ln -s $(srcdir)/tests.sh connect-test
 	ln -s $(srcdir)/tests.sh connect-test
 
 
 channel-test: tests.sh
 channel-test: tests.sh
+	rm -f channel-test
 	ln -s $(srcdir)/tests.sh channel-test
 	ln -s $(srcdir)/tests.sh channel-test
 
 
+who-test: tests.sh
+	rm -f who-test
+	ln -s $(srcdir)/tests.sh who-test
+
+misc-test: tests.sh
+	rm -f misc-test
+	ln -s $(srcdir)/tests.sh misc-test
+
 mode-test: tests.sh
 mode-test: tests.sh
+	rm -f mode-test
 	ln -s $(srcdir)/tests.sh mode-test
 	ln -s $(srcdir)/tests.sh mode-test
 
 
 TESTS = start-server.sh \
 TESTS = start-server.sh \
 	connect-test \
 	connect-test \
 	channel-test \
 	channel-test \
+	misc-test \
 	mode-test \
 	mode-test \
+	who-test \
 	stress-server.sh \
 	stress-server.sh \
 	stop-server.sh
 	stop-server.sh
 
 

+ 16 - 3
src/testsuite/Makefile.in

@@ -25,7 +25,7 @@
 # Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
 # Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
 # der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
 # der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
 #
 #
-# $Id: Makefile.am,v 1.14 2004/09/08 09:40:51 alex Exp $
+# $Id: Makefile.am,v 1.18 2008/02/17 13:26:42 alex Exp $
 #
 #
 srcdir = @srcdir@
 srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_srcdir = @top_srcdir@
@@ -155,15 +155,17 @@ EXTRA_DIST = \
 	README functions.inc getpid.sh \
 	README functions.inc getpid.sh \
 	start-server.sh stop-server.sh tests.sh stress-server.sh \
 	start-server.sh stop-server.sh tests.sh stress-server.sh \
 	test-loop.sh wait-tests.sh \
 	test-loop.sh wait-tests.sh \
-	connect-test.e channel-test.e mode-test.e \
-	stress-A.e stress-B.e check-idle.e \
+	channel-test.e connect-test.e check-idle.e misc-test.e mode-test.e \
+	who-test.e stress-A.e stress-B.e \
 	ngircd-test.conf
 	ngircd-test.conf
 
 
 check_SCRIPTS = ngircd-TEST-Binary tests.sh
 check_SCRIPTS = ngircd-TEST-Binary tests.sh
 TESTS = start-server.sh \
 TESTS = start-server.sh \
 	connect-test \
 	connect-test \
 	channel-test \
 	channel-test \
+	misc-test \
 	mode-test \
 	mode-test \
+	who-test \
 	stress-server.sh \
 	stress-server.sh \
 	stop-server.sh
 	stop-server.sh
 
 
@@ -409,12 +411,23 @@ ngircd-TEST-Binary:
 	[ -f getpid.sh ] || ln -s $(srcdir)/getpid.sh .
 	[ -f getpid.sh ] || ln -s $(srcdir)/getpid.sh .
 
 
 connect-test: tests.sh
 connect-test: tests.sh
+	rm -f connect-test
 	ln -s $(srcdir)/tests.sh connect-test
 	ln -s $(srcdir)/tests.sh connect-test
 
 
 channel-test: tests.sh
 channel-test: tests.sh
+	rm -f channel-test
 	ln -s $(srcdir)/tests.sh channel-test
 	ln -s $(srcdir)/tests.sh channel-test
 
 
+who-test: tests.sh
+	rm -f who-test
+	ln -s $(srcdir)/tests.sh who-test
+
+misc-test: tests.sh
+	rm -f misc-test
+	ln -s $(srcdir)/tests.sh misc-test
+
 mode-test: tests.sh
 mode-test: tests.sh
+	rm -f mode-test
 	ln -s $(srcdir)/tests.sh mode-test
 	ln -s $(srcdir)/tests.sh mode-test
 
 
 # -eof-
 # -eof-

+ 31 - 1
src/testsuite/channel-test.e

@@ -1,4 +1,4 @@
-# $Id: channel-test.e,v 1.3 2003/12/27 13:01:12 alex Exp $
+# $Id: channel-test.e,v 1.4 2008/02/05 13:31:51 fw Exp $
 
 
 spawn telnet localhost 6789
 spawn telnet localhost 6789
 expect {
 expect {
@@ -69,6 +69,36 @@ expect {
 	"@* PART #channel :nick"
 	"@* PART #channel :nick"
 }
 }
 
 
+send "join #channel\r"
+expect {
+	timeout { exit 1 }
+	"@* JOIN :#channel"
+}
+expect {
+	timeout { exit 1 }
+	"366"
+}
+
+send "join #channel2\r"
+expect {
+	timeout { exit 1 }
+	"@* JOIN :#channel2"
+}
+expect {
+	timeout { exit 1 }
+	"366"
+}
+
+send "join 0\r"
+expect {
+	timeout { exit 1 }
+	"@* PART #channel2 :nick"
+}
+expect {
+	timeout { exit 1 }
+	"@* PART #channel :nick"
+}
+
 send "quit\r"
 send "quit\r"
 expect {
 expect {
 	timeout { exit 1 }
 	timeout { exit 1 }

+ 1 - 1
src/testsuite/getpid.sh

@@ -1,6 +1,6 @@
 #!/bin/sh
 #!/bin/sh
 # ngIRCd Test Suite
 # ngIRCd Test Suite
-# $Id: getpid.sh,v 1.4.6.1 2006/12/17 13:49:49 alex Exp $
+# $Id: getpid.sh,v 1.5 2006/08/05 00:15:28 alex Exp $
 
 
 # did we get a name?
 # did we get a name?
 [ $# -ne 1 ] && exit 1
 [ $# -ne 1 ] && exit 1

+ 44 - 0
src/testsuite/misc-test.e

@@ -0,0 +1,44 @@
+# $Id: misc-test.e,v 1.2 2008/02/17 13:51:00 alex Exp $
+
+spawn telnet localhost 6789
+expect {
+	timeout { exit 1 }
+	"Connected"
+}
+
+send "nick nick\r"
+send "user user . . :User\r"
+expect {
+	timeout { exit 1 }
+	"376"
+}
+
+send "summon\r"
+expect {
+	timeout { exit 1 }
+	"445"
+}
+
+send "users\r"
+expect {
+	timeout { exit 1 }
+	"446"
+}
+
+send "info\r"
+expect {
+	timeout { exit 1 }
+	"371"
+}
+expect {
+	timeout { exit 1 }
+	"374"
+}
+
+send "quit\r"
+expect {
+	timeout { exit 1 }
+	"ERROR"
+}
+
+# -eof-

+ 3 - 3
src/testsuite/mode-test.e

@@ -1,4 +1,4 @@
-# $Id: mode-test.e,v 1.6 2004/03/10 20:40:06 alex Exp $
+# $Id: mode-test.e,v 1.7 2008/02/16 11:27:49 fw Exp $
 
 
 spawn telnet localhost 6789
 spawn telnet localhost 6789
 expect {
 expect {
@@ -72,7 +72,7 @@ expect {
 send "mode #channel +v nick\r"
 send "mode #channel +v nick\r"
 expect {
 expect {
 	timeout { exit 1 }
 	timeout { exit 1 }
-	"@* MODE #channel +v nick"
+	"@* MODE #channel +v nick\r"
 }
 }
 
 
 send "mode #channel +I nick1\r"
 send "mode #channel +I nick1\r"
@@ -96,7 +96,7 @@ expect {
 send "mode #channel -vo nick nick\r"
 send "mode #channel -vo nick nick\r"
 expect {
 expect {
 	timeout { exit 1 }
 	timeout { exit 1 }
-	"@* MODE #channel -vo nick nick"
+	"@* MODE #channel -vo nick nick\r"
 }
 }
 
 
 send "quit\r"
 send "quit\r"

+ 2 - 1
src/testsuite/ngircd-test.conf

@@ -1,4 +1,4 @@
-# $Id: ngircd-test.conf,v 1.4 2003/11/05 23:31:43 alex Exp $
+# $Id: ngircd-test.conf,v 1.6 2008/02/17 00:00:13 fw Exp $
 
 
 [Global]
 [Global]
 	Name = ngircd.test.server
 	Name = ngircd.test.server
@@ -7,6 +7,7 @@
 	MotdFile = ngircd-test.motd
 	MotdFile = ngircd-test.motd
 	AdminEMail = admin@irc.server
 	AdminEMail = admin@irc.server
 	MaxConnectionsIP = 0
 	MaxConnectionsIP = 0
+	OperCanUseMode = yes
 
 
 [Operator]
 [Operator]
 	Name = TestOp
 	Name = TestOp

+ 162 - 0
src/testsuite/who-test.e

@@ -0,0 +1,162 @@
+spawn telnet localhost 6789
+expect {
+	timeout { exit 1 }
+	"Connected"
+}
+
+send "nick nick\r"
+send "user user . . :Real Name\r"
+expect {
+	timeout { exit 1 }
+	"376"
+}
+
+send "who\r"
+expect {
+	timeout { exit 1 }
+	":ngircd.test.server 352 nick \* ~user localhost ngircd.test.server nick H :0 Real Name"
+}
+
+send "join #channel\r"
+expect {
+	timeout { exit 1 }
+	"@* JOIN :#channel"
+}
+
+send "who 0\r"
+expect {
+	timeout { exit 1 }
+	":ngircd.test.server 352 nick #channel ~user localhost ngircd.test.server nick H@ :0 Real Name"
+}
+
+send "away :testing\r"
+expect {
+	timeout { exit 1 }
+	"306 nick"
+}
+
+send "who *\r"
+expect {
+	timeout { exit 1 }
+	":ngircd.test.server 352 nick #channel ~user localhost ngircd.test.server nick G@ :0 Real Name"
+}
+
+send "mode #channel +v nick\r"
+expect {
+	timeout { exit 1 }
+	"@* MODE #channel +v nick\r"
+}
+
+send "who localhost\r"
+expect {
+	timeout { exit 1 }
+	":ngircd.test.server 352 nick #channel ~user localhost ngircd.test.server nick G@ :0 Real Name"
+}
+
+send "mode #channel -o nick\r"
+expect {
+	timeout { exit 1 }
+	"@* MODE #channel -o nick\r"
+}
+
+send "who ngircd.test.server\r"
+expect {
+	timeout { exit 1 }
+	":ngircd.test.server 352 nick #channel ~user localhost ngircd.test.server nick G+ :0 Real Name"
+}
+
+send "part #channel\r"
+expect {
+	timeout { exit 1 }
+	"@* PART #channel :nick"
+}
+
+send "who Real?Name\r"
+expect {
+	timeout { exit 1 }
+	":ngircd.test.server 352 nick \* ~user localhost ngircd.test.server nick G :0 Real Name"
+}
+
+send "oper TestOp 123\r"
+expect {
+	timeout { exit 1 }
+	"MODE nick :+o"
+}
+expect {
+	timeout { exit 1 }
+	"381 nick"
+}
+
+send "who 0 o\r"
+expect {
+	timeout { exit 1 }
+	":ngircd.test.server 352 nick \* ~user localhost ngircd.test.server nick G* :0 Real Name"
+}
+
+send "away\r"
+expect {
+	timeout { exit 1 }
+	"305 nick"
+}
+
+send "who *cal*ho??\r"
+expect {
+	timeout { exit 1 }
+	":ngircd.test.server 352 nick \* ~user localhost ngircd.test.server nick H* :0 Real Name"
+}
+
+send "join #opers\r"
+expect {
+	timeout { exit 1 }
+	"@* JOIN :#opers"
+}
+
+send "who #opers\r"
+expect {
+	timeout { exit 1 }
+	":ngircd.test.server 352 nick #opers ~user localhost ngircd.test.server nick H*@ :0 Real Name"
+}
+
+send "mode #opers -o nick\r"
+expect {
+	timeout { exit 1 }
+	"@* MODE #opers -o nick\r"
+}
+
+send "who *.server\r"
+expect {
+	timeout { exit 1 }
+	":ngircd.test.server 352 nick #opers ~user localhost ngircd.test.server nick H* :0 Real Name"
+}
+
+send "mode #opers +v nick\r"
+expect {
+	timeout { exit 1 }
+	"@* MODE #opers +v nick\r"
+}
+
+send "who Real*me\r"
+expect {
+	timeout { exit 1 }
+	":ngircd.test.server 352 nick #opers ~user localhost ngircd.test.server nick H*+ :0 Real Name"
+}
+
+send "mode #opers +s\r"
+expect {
+	timeout { exit 1 }
+	"@* MODE #opers +s\r"
+}
+
+send "who n?c?\r"
+expect {
+	timeout { exit 1 }
+	":ngircd.test.server 352 nick \* ~user localhost ngircd.test.server nick H* :0 Real Name"
+}
+
+send "quit\r"
+expect {
+	timeout { exit 1 }
+	"Connection closed"
+}
+
+# -eof-

+ 0 - 0
src/tool/tool.c


Some files were not shown because too many files changed in this diff