ngIRCd: Patch to upgrade ngIRCd 0.11.1 to version 0.12.0. .cvsignore | 7 - .gitignore | 17 + ChangeLog | 47 +- INSTALL | 10 +- Makefile.am | 12 +- NEWS | 20 +- README | 10 +- configure.in | 22 +- contrib/.cvsignore | 2 - contrib/Debian/.cvsignore | 2 - contrib/Debian/changelog | 18 +- contrib/MacOSX/.cvsignore | 2 - contrib/MacOSX/.gitignore | 1 + contrib/MacOSX/Makefile.am | 35 +- contrib/MacOSX/config.h | 2 +- contrib/MacOSX/de.barton.ngircd.plist.tmpl | 19 + contrib/MacOSX/ngIRCd.xcodeproj/.gitignore | 2 + contrib/MacOSX/ngIRCd.xcodeproj/Makefile.am | 17 + contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj | 66 +- contrib/ngircd.spec | 2 +- doc/.cvsignore | 2 - doc/CVS.txt | 57 -- doc/FAQ.txt | 2 +- doc/GIT.txt | 45 ++ doc/Makefile.am | 6 +- doc/sample-ngircd.conf | 11 +- doc/src/.cvsignore | 3 - doc/src/.gitignore | 1 + man/.cvsignore | 4 - man/.gitignore | 2 + man/ngircd.conf.5.tmpl | 18 + src/.cvsignore | 5 - src/.gitignore | 3 + src/Makefile.am | 4 +- src/ipaddr/Makefile.am | 14 + src/ipaddr/ng_ipaddr.c | 167 +++++ src/ipaddr/ng_ipaddr.h | 118 +++ src/ngircd/{.cvsignore => .gitignore} | 3 - src/ngircd/Makefile.am | 27 +- src/ngircd/channel.c | 119 ++- src/ngircd/channel.h | 9 +- src/ngircd/client.c | 6 +- src/ngircd/conf.c | 96 ++- src/ngircd/conf.h | 24 +- src/ngircd/conn-func.c | 5 +- src/ngircd/conn.c | 303 +++++--- src/ngircd/conn.h | 6 +- src/ngircd/io.c | 913 +++++++++++------------ src/ngircd/irc-channel.c | 357 +++++---- src/ngircd/irc-info.c | 400 +++++++---- src/ngircd/irc-info.h | 6 +- src/ngircd/irc-login.c | 82 +-- src/ngircd/irc-mode.c | 628 +++++++--------- src/ngircd/irc.c | 12 +- src/ngircd/lists.c | 6 +- src/ngircd/lists.h | 4 +- src/ngircd/messages.h | 6 +- src/ngircd/ngircd.c | 30 +- src/ngircd/parse.c | 220 +++--- src/ngircd/parse.h | 10 +- src/ngircd/resolve.c | 424 ++++++++--- src/ngircd/resolve.h | 6 +- src/portab/.cvsignore | 4 - src/portab/.gitignore | 1 + src/testsuite/.cvsignore | 7 - src/testsuite/.gitignore | 10 + src/testsuite/Makefile.am | 16 +- src/testsuite/channel-test.e | 32 +- src/testsuite/misc-test.e | 44 ++ src/testsuite/mode-test.e | 2 +- src/testsuite/ngircd-test.conf | 5 +- src/testsuite/who-test.e | 162 ++++ src/tool/.cvsignore | 3 - src/tool/tool.c | 21 +- src/tool/tool.h | 4 +- 75 files changed, 2942 insertions(+), 1846 deletions(-) diff --git a/.cvsignore b/.cvsignore deleted file mode 100644 index fb24d37..0000000 --- a/.cvsignore +++ /dev/null @@ -1,7 +0,0 @@ -Makefile -Makefile.in -aclocal.m4 -autom4te.cache -config.log -config.status -configure diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9c344a9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +Makefile +Makefile.in +aclocal.m4 +ansi2knr.1 +ansi2knr.c +ansi2knr.h +autom4te.cache +config.log +config.status +configure +configure.lineno +depcomp +install-sh +missing +.deps +*.a +*.o diff --git a/ChangeLog b/ChangeLog index 0ab91f7..09ad689 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,13 +10,46 @@ -- ChangeLog -- +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] + - 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) @@ -739,7 +772,3 @@ ngIRCd 0.0.2, 06.01.2002 ngIRCd 0.0.1, 31.12.2001 - erste oeffentliche Version von ngIRCd als "public preview" :-) - - --- -$Id: ChangeLog,v 1.332.2.10 2008/02/26 19:22:06 alex Exp $ diff --git a/INSTALL b/INSTALL index 227c462..60e7b5e 100644 --- a/INSTALL +++ b/INSTALL @@ -51,9 +51,9 @@ on modern UNIX-like systems that are supported by GNU autoconf and GNU automake ("configure") should be no problem. 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 3) make 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 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. @@ -244,7 +244,3 @@ These parameters could be passed to the ngIRCd: Use "--help" to see a short help text describing all available parameters the server understands, with "--version" the ngIRCd shows its version number. In both cases the server exits after the output. - - --- -$Id: INSTALL,v 1.26 2007/04/08 11:39:08 alex Exp $ diff --git a/Makefile.am b/Makefile.am index 790f0df..d678f17 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ # # 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 # it under the terms of the GNU General Public License as published by @@ -8,8 +8,6 @@ # (at your option) any later version. # 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 @@ -24,6 +22,9 @@ maintainer-clean-local: rm -f mkinstalldirs missing depcomp install-sh rm -f config.log debian +testsuite: + make -C src/testsuite check + lint: make -C src/ngircd lint @@ -31,9 +32,10 @@ srcdoc: make -C doc srcdoc 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 ) - xcodebuild -project contrib/MacOSX/ngIRCd.xcode -alltargets \ + xcodebuild -project contrib/MacOSX/ngIRCd.xcodeproj -alltargets \ -buildstyle Development rpm: distcheck diff --git a/NEWS b/NEWS index 7c4ef98..47def92 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,24 @@ -- NEWS -- +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. @@ -251,4 +269,4 @@ ngIRCd 0.0.1, 31.12.2001 -- -$Id: NEWS,v 1.83.2.4 2008/02/26 19:22:07 alex Exp $ +$Id: NEWS,v 1.88 2008/02/26 22:05:42 fw Exp $ diff --git a/README b/README index f01e6d6..2eff7bc 100644 --- a/README +++ b/README @@ -67,9 +67,9 @@ the newest information about the ngIRCd and the most recent ("stable") releases there. 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 @@ -85,7 +85,3 @@ There you can read about known bugs and limitations, too. If you have critics, patches or something else, please feel free to post a mail to the ngIRCd mailing list: (please see for details). - - --- -$Id: README,v 1.25 2007/10/04 15:18:48 alex Exp $ diff --git a/configure.in b/configure.in index c4d9546..0d1fe7f 100644 --- a/configure.in +++ b/configure.in @@ -8,13 +8,11 @@ # (at your option) any later version. # Please read the file COPYING, README and AUTHORS for more information. # -# $Id: configure.in,v 1.125.2.4 2008/02/26 19:37:34 alex Exp $ -# # -- Initialisation -- AC_PREREQ(2.50) -AC_INIT(ngircd, 0.11.1) +AC_INIT(ngircd, 0.12.0) AC_CONFIG_SRCDIR(src/ngircd/ngircd.c) AC_CANONICAL_TARGET 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([TCPWRAP], [Define if TCP wrappers 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([IDENTAUTH], [Define if the server should do IDENT requests]) @@ -426,6 +425,19 @@ if test "$x_ircplus_on" = "yes"; then AC_DEFINE(IRCPLUS, 1) 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"? x_sniffer_on=no; x_debug_on=no @@ -477,6 +489,7 @@ AC_OUTPUT([ \ doc/src/Makefile \ src/Makefile \ src/portab/Makefile \ + src/ipaddr/Makefile \ src/tool/Makefile \ src/ngircd/Makefile \ src/testsuite/Makefile \ @@ -484,6 +497,7 @@ AC_OUTPUT([ \ contrib/Makefile \ contrib/Debian/Makefile \ contrib/MacOSX/Makefile \ + contrib/MacOSX/ngIRCd.xcodeproj/Makefile \ ]) type dpkg >/dev/null 2>&1 @@ -572,6 +586,8 @@ test "$x_identauth_on" = "yes" \ echo $ECHO_N " I/O backend: $ECHO_C" echo "\"$x_io_backend\"" +echo $ECHO_N " IPv6 protocol: $ECHO_C" +echo "$x_ipv6_on" echo # -eof- diff --git a/contrib/.cvsignore b/contrib/.cvsignore deleted file mode 100644 index 282522d..0000000 --- a/contrib/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -Makefile -Makefile.in diff --git a/contrib/Debian/.cvsignore b/contrib/Debian/.cvsignore deleted file mode 100644 index 282522d..0000000 --- a/contrib/Debian/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -Makefile -Makefile.in diff --git a/contrib/Debian/changelog b/contrib/Debian/changelog index 47012af..9895de7 100644 --- a/contrib/Debian/changelog +++ b/contrib/Debian/changelog @@ -1,14 +1,20 @@ -ngircd (0.11.1-0ab1) unstable; urgency=low +ngircd (0.12.0-0ab0-pre3) unstable; urgency=low - * New "upstream" release 0.11.1. + * New "upstream" release ngIRCd 0.12.0. - -- Alexander Barton Tue, 26 Feb 2008 20:24:55 +0100 + -- Alexander Barton Tue, 13 May 2008 12:30:31 +0200 -ngircd (0.11.0-0ab1) unstable; urgency=low +ngircd (0.12.0-0ab0-pre2) unstable; urgency=low - * New "upstream" release 0.11.0. + * Second prereloease of upcoming new "upstrem" release 0.12.0-pre1. - -- Alexander Barton Tue, 15 Jan 2008 21:43:46 +0100 + -- Alexander Barton 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 Sun, 20 Apr 2008 15:43:34 +0200 ngircd (0.11.0-0ab0-pre2) unstable; urgency=low diff --git a/contrib/MacOSX/.cvsignore b/contrib/MacOSX/.cvsignore deleted file mode 100644 index 282522d..0000000 --- a/contrib/MacOSX/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -Makefile -Makefile.in diff --git a/contrib/MacOSX/.gitignore b/contrib/MacOSX/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/contrib/MacOSX/.gitignore @@ -0,0 +1 @@ +build diff --git a/contrib/MacOSX/Makefile.am b/contrib/MacOSX/Makefile.am index d26499e..306e41f 100644 --- a/contrib/MacOSX/Makefile.am +++ b/contrib/MacOSX/Makefile.am @@ -1,6 +1,6 @@ # # ngIRCd -- The Next Generation IRC Daemon -# Copyright (c)2001-2004 Alexander Barton +# Copyright (c)2001-2008 Alexander Barton # # 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 @@ -8,9 +8,40 @@ # (at your option) any later version. # 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: rm -rf build diff --git a/contrib/MacOSX/config.h b/contrib/MacOSX/config.h index 04b7ceb..8882e46 100644 --- a/contrib/MacOSX/config.h +++ b/contrib/MacOSX/config.h @@ -89,4 +89,4 @@ #define HAVE_DNSSERVICEREGISTRATIONCREATE 1 #endif -/* -eof- */ \ No newline at end of file +/* -eof- */ diff --git a/contrib/MacOSX/de.barton.ngircd.plist.tmpl b/contrib/MacOSX/de.barton.ngircd.plist.tmpl new file mode 100644 index 0000000..f54333d --- /dev/null +++ b/contrib/MacOSX/de.barton.ngircd.plist.tmpl @@ -0,0 +1,19 @@ + + + + + Disabled + + KeepAlive + + Label + de.barton.ngIRCd + ProgramArguments + + :SBINDIR:/ngircd + --nodaemon + + RunAtLoad + + + diff --git a/contrib/MacOSX/ngIRCd.xcodeproj/.gitignore b/contrib/MacOSX/ngIRCd.xcodeproj/.gitignore new file mode 100644 index 0000000..d82a5e4 --- /dev/null +++ b/contrib/MacOSX/ngIRCd.xcodeproj/.gitignore @@ -0,0 +1,2 @@ +*.mode1v3 +*.pbxuser diff --git a/contrib/MacOSX/ngIRCd.xcodeproj/Makefile.am b/contrib/MacOSX/ngIRCd.xcodeproj/Makefile.am new file mode 100644 index 0000000..84e66d2 --- /dev/null +++ b/contrib/MacOSX/ngIRCd.xcodeproj/Makefile.am @@ -0,0 +1,17 @@ +# +# ngIRCd -- The Next Generation IRC Daemon +# Copyright (c)2001-2008 Alexander Barton +# +# 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- diff --git a/contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj b/contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj index 1a032a7..f557738 100644 --- a/contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj +++ b/contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj @@ -34,6 +34,7 @@ FA322D4D0CEF74B1001761B3 /* resolve.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322D0C0CEF74B1001761B3 /* resolve.c */; }; FA322DBE0CEF7766001761B3 /* tool.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322D330CEF74B1001761B3 /* tool.c */; }; FA322DC10CEF77CB001761B3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FA322DC00CEF77CB001761B3 /* libz.dylib */; }; + 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 */ @@ -50,10 +51,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + FA1A6BBC0D6857BB00AA8F71 /* misc-test.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "misc-test.e"; sourceTree = ""; }; + FA1A6BBD0D6857D900AA8F71 /* who-test.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "who-test.e"; sourceTree = ""; }; FA322BBA0CEF72E4001761B3 /* ngIRCd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ngIRCd; sourceTree = BUILT_PRODUCTS_DIR; }; - FA322CD50CEF74B1001761B3 /* .cvsignore */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = .cvsignore; sourceTree = ""; }; FA322CD60CEF74B1001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; - FA322CD80CEF74B1001761B3 /* .cvsignore */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = .cvsignore; sourceTree = ""; }; FA322CD90CEF74B1001761B3 /* array.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = array.c; sourceTree = ""; }; FA322CDA0CEF74B1001761B3 /* array.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = array.h; sourceTree = ""; }; FA322CDB0CEF74B1001761B3 /* channel.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = channel.c; sourceTree = ""; }; @@ -107,7 +108,6 @@ FA322D0B0CEF74B1001761B3 /* rendezvous.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = rendezvous.h; sourceTree = ""; }; FA322D0C0CEF74B1001761B3 /* resolve.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = resolve.c; sourceTree = ""; }; FA322D0D0CEF74B1001761B3 /* resolve.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = resolve.h; sourceTree = ""; }; - FA322D0F0CEF74B1001761B3 /* .cvsignore */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = .cvsignore; sourceTree = ""; }; FA322D100CEF74B1001761B3 /* ansi2knr.1 */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.man; path = ansi2knr.1; sourceTree = ""; }; FA322D110CEF74B1001761B3 /* ansi2knr.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = ansi2knr.c; sourceTree = ""; }; FA322D120CEF74B1001761B3 /* exp.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = exp.h; sourceTree = ""; }; @@ -119,7 +119,6 @@ FA322D180CEF74B1001761B3 /* strdup.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = strdup.c; sourceTree = ""; }; FA322D190CEF74B1001761B3 /* strlcpy.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = strlcpy.c; sourceTree = ""; }; FA322D1A0CEF74B1001761B3 /* vsnprintf.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = vsnprintf.c; sourceTree = ""; }; - FA322D1C0CEF74B1001761B3 /* .cvsignore */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = .cvsignore; sourceTree = ""; }; FA322D1D0CEF74B1001761B3 /* channel-test.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "channel-test.e"; sourceTree = ""; }; FA322D1E0CEF74B1001761B3 /* check-idle.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "check-idle.e"; sourceTree = ""; }; FA322D1F0CEF74B1001761B3 /* connect-test.e */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "connect-test.e"; sourceTree = ""; }; @@ -137,7 +136,6 @@ FA322D2B0CEF74B1001761B3 /* test-loop.sh */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; path = "test-loop.sh"; sourceTree = ""; }; FA322D2C0CEF74B1001761B3 /* tests.sh */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; path = tests.sh; sourceTree = ""; }; FA322D2D0CEF74B1001761B3 /* wait-tests.sh */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; path = "wait-tests.sh"; sourceTree = ""; }; - FA322D2F0CEF74B1001761B3 /* .cvsignore */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = .cvsignore; sourceTree = ""; }; FA322D300CEF74B1001761B3 /* ansi2knr.1 */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.man; path = ansi2knr.1; sourceTree = ""; }; FA322D310CEF74B1001761B3 /* ansi2knr.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = ansi2knr.c; sourceTree = ""; }; FA322D320CEF74B1001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; @@ -154,8 +152,6 @@ 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; }; - FA322D670CEF7523001761B3 /* .cvsignore */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = .cvsignore; sourceTree = ""; }; - FA322D690CEF7523001761B3 /* .cvsignore */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = .cvsignore; sourceTree = ""; }; FA322D6A0CEF7523001761B3 /* changelog */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = changelog; sourceTree = ""; }; FA322D6B0CEF7523001761B3 /* compat */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = compat; sourceTree = ""; }; FA322D6C0CEF7523001761B3 /* control */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = control; sourceTree = ""; }; @@ -165,7 +161,6 @@ FA322D700CEF7523001761B3 /* ngircd.init */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; path = ngircd.init; sourceTree = ""; }; FA322D710CEF7523001761B3 /* ngircd.postinst */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.script.sh; path = ngircd.postinst; sourceTree = ""; }; FA322D720CEF7523001761B3 /* rules */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = rules; sourceTree = ""; }; - FA322D740CEF7523001761B3 /* .cvsignore */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = .cvsignore; sourceTree = ""; }; FA322D8D0CEF7523001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; FA322D8E0CEF7523001761B3 /* ngIRCd.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = ngIRCd.xcodeproj; sourceTree = ""; }; FA322D910CEF7523001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; @@ -174,8 +169,6 @@ FA322D940CEF7523001761B3 /* ngircd.spec */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = ngircd.spec; sourceTree = ""; }; FA322D950CEF7523001761B3 /* README */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = README; sourceTree = ""; }; FA322D960CEF7523001761B3 /* systrace.policy */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = systrace.policy; sourceTree = ""; }; - FA322D980CEF752C001761B3 /* .cvsignore */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = .cvsignore; sourceTree = ""; }; - FA322D990CEF752C001761B3 /* CVS.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = CVS.txt; sourceTree = ""; }; FA322D9A0CEF752C001761B3 /* FAQ.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = FAQ.txt; sourceTree = ""; }; FA322D9B0CEF752C001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; FA322D9C0CEF752C001761B3 /* Platforms.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Platforms.txt; sourceTree = ""; }; @@ -184,7 +177,6 @@ FA322D9F0CEF752C001761B3 /* README-BeOS.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "README-BeOS.txt"; sourceTree = ""; }; FA322DA00CEF752C001761B3 /* RFC.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = RFC.txt; sourceTree = ""; }; FA322DA10CEF752C001761B3 /* sample-ngircd.conf */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = "sample-ngircd.conf"; sourceTree = ""; }; - FA322DA30CEF752C001761B3 /* .cvsignore */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = .cvsignore; sourceTree = ""; }; FA322DA40CEF752C001761B3 /* Doxyfile */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Doxyfile; sourceTree = ""; }; FA322DA50CEF752C001761B3 /* footer.inc.html */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.html; path = footer.inc.html; sourceTree = ""; }; FA322DA60CEF752C001761B3 /* header.inc.html */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.html; path = header.inc.html; sourceTree = ""; }; @@ -192,13 +184,16 @@ FA322DA80CEF752C001761B3 /* ngircd-doc.css */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.css; path = "ngircd-doc.css"; sourceTree = ""; }; FA322DA90CEF752C001761B3 /* SSL.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = SSL.txt; sourceTree = ""; }; FA322DAA0CEF752C001761B3 /* Zeroconf.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Zeroconf.txt; sourceTree = ""; }; - FA322DAC0CEF7538001761B3 /* .cvsignore */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = .cvsignore; sourceTree = ""; }; FA322DAD0CEF7538001761B3 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; FA322DAE0CEF7538001761B3 /* ngircd.8.tmpl */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = ngircd.8.tmpl; sourceTree = ""; }; FA322DAF0CEF7538001761B3 /* ngircd.conf.5.tmpl */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = ngircd.conf.5.tmpl; sourceTree = ""; }; FA322DB10CEF7565001761B3 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; FA322DBB0CEF773C001761B3 /* cvs-version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "cvs-version.h"; sourceTree = ""; }; FA322DC00CEF77CB001761B3 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = /usr/lib/libz.dylib; sourceTree = ""; }; + FA407F2B0DB159F400271AF1 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; name = Makefile.am; path = ipaddr/Makefile.am; sourceTree = ""; }; + FA407F2C0DB159F400271AF1 /* ng_ipaddr.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = ng_ipaddr.c; path = ipaddr/ng_ipaddr.c; sourceTree = ""; }; + FA407F2D0DB159F400271AF1 /* ng_ipaddr.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = ng_ipaddr.h; path = ipaddr/ng_ipaddr.h; sourceTree = ""; }; + FA407F380DB15AC700271AF1 /* GIT.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; path = GIT.txt; sourceTree = ""; }; FAE5CC2C0CF2308A007D69B6 /* numeric.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = numeric.h; sourceTree = ""; }; FAE5CC2D0CF2308A007D69B6 /* numeric.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = numeric.c; sourceTree = ""; }; /* End PBXFileReference section */ @@ -251,10 +246,10 @@ isa = PBXGroup; children = ( FA322CD70CEF74B1001761B3 /* ngircd */, + FA407F270DB1598D00271AF1 /* ipaddr */, FA322D0E0CEF74B1001761B3 /* portab */, FA322D1B0CEF74B1001761B3 /* testsuite */, FA322D2E0CEF74B1001761B3 /* tool */, - FA322CD50CEF74B1001761B3 /* .cvsignore */, FA322CD60CEF74B1001761B3 /* Makefile.am */, ); name = src; @@ -264,7 +259,6 @@ FA322CD70CEF74B1001761B3 /* ngircd */ = { isa = PBXGroup; children = ( - FA322CD80CEF74B1001761B3 /* .cvsignore */, FA322CD90CEF74B1001761B3 /* array.c */, FA322CDA0CEF74B1001761B3 /* array.h */, FA322CDB0CEF74B1001761B3 /* channel.c */, @@ -327,7 +321,6 @@ FA322D0E0CEF74B1001761B3 /* portab */ = { isa = PBXGroup; children = ( - FA322D0F0CEF74B1001761B3 /* .cvsignore */, FA322D100CEF74B1001761B3 /* ansi2knr.1 */, FA322D110CEF74B1001761B3 /* ansi2knr.c */, FA322D120CEF74B1001761B3 /* exp.h */, @@ -346,13 +339,13 @@ FA322D1B0CEF74B1001761B3 /* testsuite */ = { isa = PBXGroup; children = ( - FA322D1C0CEF74B1001761B3 /* .cvsignore */, 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 */, @@ -364,6 +357,7 @@ FA322D2B0CEF74B1001761B3 /* test-loop.sh */, FA322D2C0CEF74B1001761B3 /* tests.sh */, FA322D2D0CEF74B1001761B3 /* wait-tests.sh */, + FA1A6BBD0D6857D900AA8F71 /* who-test.e */, ); path = testsuite; sourceTree = ""; @@ -371,7 +365,6 @@ FA322D2E0CEF74B1001761B3 /* tool */ = { isa = PBXGroup; children = ( - FA322D2F0CEF74B1001761B3 /* .cvsignore */, FA322D300CEF74B1001761B3 /* ansi2knr.1 */, FA322D310CEF74B1001761B3 /* ansi2knr.c */, FA322D320CEF74B1001761B3 /* Makefile.am */, @@ -384,7 +377,6 @@ FA322D660CEF7523001761B3 /* contrib */ = { isa = PBXGroup; children = ( - FA322D670CEF7523001761B3 /* .cvsignore */, FA322D680CEF7523001761B3 /* Debian */, FA322D730CEF7523001761B3 /* MacOSX */, FA322D910CEF7523001761B3 /* Makefile.am */, @@ -401,7 +393,6 @@ FA322D680CEF7523001761B3 /* Debian */ = { isa = PBXGroup; children = ( - FA322D690CEF7523001761B3 /* .cvsignore */, FA322D6A0CEF7523001761B3 /* changelog */, FA322D6B0CEF7523001761B3 /* compat */, FA322D6C0CEF7523001761B3 /* control */, @@ -418,7 +409,6 @@ FA322D730CEF7523001761B3 /* MacOSX */ = { isa = PBXGroup; children = ( - FA322D740CEF7523001761B3 /* .cvsignore */, FA322D750CEF7523001761B3 /* build */, FA322D8D0CEF7523001761B3 /* Makefile.am */, FA322D8E0CEF7523001761B3 /* ngIRCd.xcodeproj */, @@ -509,8 +499,7 @@ FA322D970CEF752C001761B3 /* doc */ = { isa = PBXGroup; children = ( - FA322D980CEF752C001761B3 /* .cvsignore */, - FA322D990CEF752C001761B3 /* CVS.txt */, + FA407F380DB15AC700271AF1 /* GIT.txt */, FA322D9A0CEF752C001761B3 /* FAQ.txt */, FA322D9B0CEF752C001761B3 /* Makefile.am */, FA322D9C0CEF752C001761B3 /* Platforms.txt */, @@ -530,7 +519,6 @@ FA322DA20CEF752C001761B3 /* src */ = { isa = PBXGroup; children = ( - FA322DA30CEF752C001761B3 /* .cvsignore */, FA322DA40CEF752C001761B3 /* Doxyfile */, FA322DA50CEF752C001761B3 /* footer.inc.html */, FA322DA60CEF752C001761B3 /* header.inc.html */, @@ -543,7 +531,6 @@ FA322DAB0CEF7538001761B3 /* man */ = { isa = PBXGroup; children = ( - FA322DAC0CEF7538001761B3 /* .cvsignore */, FA322DAD0CEF7538001761B3 /* Makefile.am */, FA322DAE0CEF7538001761B3 /* ngircd.8.tmpl */, FA322DAF0CEF7538001761B3 /* ngircd.conf.5.tmpl */, @@ -552,6 +539,16 @@ path = ../../man; sourceTree = SOURCE_ROOT; }; + FA407F270DB1598D00271AF1 /* ipaddr */ = { + isa = PBXGroup; + children = ( + FA407F2B0DB159F400271AF1 /* Makefile.am */, + FA407F2C0DB159F400271AF1 /* ng_ipaddr.c */, + FA407F2D0DB159F400271AF1 /* ng_ipaddr.h */, + ); + name = ipaddr; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -628,6 +625,7 @@ FA322D4D0CEF74B1001761B3 /* resolve.c in Sources */, FA322DBE0CEF7766001761B3 /* tool.c in Sources */, FAE5CC2E0CF2308A007D69B6 /* numeric.c in Sources */, + FA407F2E0DB159F400271AF1 /* ng_ipaddr.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -637,8 +635,24 @@ 1DEB928708733DD80010E9CD /* Default */ = { isa = XCBuildConfiguration; buildSettings = { - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_MODEL_TUNING = G5; + 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; }; diff --git a/contrib/ngircd.spec b/contrib/ngircd.spec index 80308d3..2a98612 100644 --- a/contrib/ngircd.spec +++ b/contrib/ngircd.spec @@ -1,5 +1,5 @@ %define name ngircd -%define version 0.11.1 +%define version 0.12.0 %define release 1 %define prefix %{_prefix} diff --git a/doc/.cvsignore b/doc/.cvsignore deleted file mode 100644 index 282522d..0000000 --- a/doc/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -Makefile -Makefile.in diff --git a/doc/CVS.txt b/doc/CVS.txt deleted file mode 100644 index 814d807..0000000 --- a/doc/CVS.txt +++ /dev/null @@ -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 [] - -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, . - - --- -$Id: CVS.txt,v 1.9 2006/08/03 14:37:29 alex Exp $ diff --git a/doc/FAQ.txt b/doc/FAQ.txt index 4c8cccb..edd73ae 100644 --- a/doc/FAQ.txt +++ b/doc/FAQ.txt @@ -76,4 +76,4 @@ A: Please file a bug report at ! -- -$Id: FAQ.txt,v 1.11.4.1 2008/01/02 22:36:48 fw Exp $ +$Id: FAQ.txt,v 1.12 2008/01/02 22:47:58 alex Exp $ diff --git a/doc/GIT.txt b/doc/GIT.txt new file mode 100644 index 0000000..c42696d --- /dev/null +++ b/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, . + + +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, . + diff --git a/doc/Makefile.am b/doc/Makefile.am index 501fdec..394c89b 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,6 +1,6 @@ # # ngIRCd -- The Next Generation IRC Daemon -# Copyright (c)2001-2007 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 # der GNU General Public License (GPL), wie von der Free Software Foundation @@ -9,12 +9,10 @@ # Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste # der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS. # -# $Id: Makefile.am,v 1.22 2007/11/20 21:39:35 alex Exp $ -# SUBDIRS = src -EXTRA_DIST = CVS.txt FAQ.txt Protocol.txt Platforms.txt README-AUX.txt \ +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: diff --git a/doc/sample-ngircd.conf b/doc/sample-ngircd.conf index d0f559c..9f107a8 100644 --- a/doc/sample-ngircd.conf +++ b/doc/sample-ngircd.conf @@ -1,4 +1,4 @@ -# $Id: sample-ngircd.conf,v 1.43.2.1 2008/01/07 23:10:28 alex 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 @@ -103,6 +103,15 @@ # Don't do any DNS lookups when a client connects to the server. ;NoDNS = no + # allow both ipv4 and ipv6 clients to connect by opening both + # ipv4 and ipv6 sockets + ;ListenIPv6 = yes + ;ListenIPv4 = yes + + # 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 # to accept (0: unlimited): ;MaxConnections = 0 diff --git a/doc/src/.cvsignore b/doc/src/.cvsignore deleted file mode 100644 index 5508282..0000000 --- a/doc/src/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -Makefile -Makefile.in -html diff --git a/doc/src/.gitignore b/doc/src/.gitignore new file mode 100644 index 0000000..1936cc1 --- /dev/null +++ b/doc/src/.gitignore @@ -0,0 +1 @@ +html diff --git a/man/.cvsignore b/man/.cvsignore deleted file mode 100644 index 7d83154..0000000 --- a/man/.cvsignore +++ /dev/null @@ -1,4 +0,0 @@ -Makefile -Makefile.in -ngircd.8 -ngircd.conf.5 diff --git a/man/.gitignore b/man/.gitignore new file mode 100644 index 0000000..af7d6f1 --- /dev/null +++ b/man/.gitignore @@ -0,0 +1,2 @@ +ngircd.8 +ngircd.conf.5 diff --git a/man/ngircd.conf.5.tmpl b/man/ngircd.conf.5.tmpl index 3a6b7d5..cd5922a 100644 --- a/man/ngircd.conf.5.tmpl +++ b/man/ngircd.conf.5.tmpl @@ -158,6 +158,24 @@ If you configure ngircd to connect to other servers, ngircd may still perform a DNS lookup if required. Default: No. .TP +\fBListenIPv4\fR +Set this to no if you do not want ngircd to accept clients using the standard internet protocol, ipv4. +This allows use of ngircd in ipv6-only setups. +Default: Yes. +.TP +\fBListenIPv6\fR +Set this to no if you do not want ngircd to accept clients using the new internet protocol, ipv6. +Default: Yes. +.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 \fBMaxConnections\fR Maximum number of simultaneous connection the server is allowed to accept (0: unlimited). Default: 0. diff --git a/src/.cvsignore b/src/.cvsignore deleted file mode 100644 index 2fe57d0..0000000 --- a/src/.cvsignore +++ /dev/null @@ -1,5 +0,0 @@ -Makefile -Makefile.in -config.h -config.h.in -stamp-h1 diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..a9cca37 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,3 @@ +config.h +config.h.in +stamp-h1 diff --git a/src/Makefile.am b/src/Makefile.am index 24929f3..e04ebe1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,10 +8,10 @@ # (at your option) any later version. # 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: rm -f Makefile Makefile.in config.h config.h.in stamp-h.in diff --git a/src/ipaddr/Makefile.am b/src/ipaddr/Makefile.am new file mode 100644 index 0000000..fcbb7cf --- /dev/null +++ b/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- diff --git a/src/ipaddr/ng_ipaddr.c b/src/ipaddr/ng_ipaddr.c new file mode 100644 index 0000000..3b0595d --- /dev/null +++ b/src/ipaddr/ng_ipaddr.c @@ -0,0 +1,167 @@ +/* + * Functions for AF_ agnostic ipv4/ipv6 handling. + * + * (c) 2008 Florian Westphal , public domain. + */ + +#include "portab.h" + +#include +#include +#include + +#ifdef HAVE_GETADDRINFO +#include +#include +#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 = { +#ifndef WANT_IPV6 /* only accept v4 addresses */ + .ai_family = AF_INET, +#endif + .ai_flags = AI_NUMERICHOST + }; + + if (ip_str == NULL) + hints.ai_flags |= AI_PASSIVE; + + /* 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 */ + if (ip_str == NULL) + ip_str = "0.0.0.0"; + 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- */ diff --git a/src/ipaddr/ng_ipaddr.h b/src/ipaddr/ng_ipaddr.h new file mode 100644 index 0000000..3bc075e --- /dev/null +++ b/src/ipaddr/ng_ipaddr.h @@ -0,0 +1,118 @@ +/* + * Functions for AF_ agnostic ipv4/ipv6 handling. + * + * (c) 2008 Florian Westphal , public domain. + */ + +#ifndef NG_IPADDR_HDR +#define NG_IPADDR_HDR +#include "portab.h" + +#include +#include + +#ifdef HAVE_ARPA_INET_H +# include +#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 + * if ip_str is NULL it is treated as 0.0.0.0/[::] + * @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- */ diff --git a/src/ngircd/.cvsignore b/src/ngircd/.gitignore similarity index 69% rename from src/ngircd/.cvsignore rename to src/ngircd/.gitignore index 9407c0b..e02dd40 100644 --- a/src/ngircd/.cvsignore +++ b/src/ngircd/.gitignore @@ -1,6 +1,3 @@ -Makefile -Makefile.in -.deps check-help check-version cvs-version.h diff --git a/src/ngircd/Makefile.am b/src/ngircd/Makefile.am index 46513a8..1a5119f 100644 --- a/src/ngircd/Makefile.am +++ b/src/ngircd/Makefile.am @@ -8,12 +8,12 @@ # (at your option) any later version. # Please read the file COPYING, README and AUTHORS for more information. # -# $Id: Makefile.am,v 1.50 2007/11/21 12:16:36 alex Exp $ +# $Id: Makefile.am,v 1.51 2008/02/26 22:04:17 fw Exp $ # 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 \ -varuse -retvalother -emptyret -unrecog @@ -25,9 +25,9 @@ ngircd_SOURCES = ngircd.c array.c channel.c client.c conf.c conn.c conn-func.c \ irc-mode.c irc-op.c irc-oper.c irc-server.c irc-write.c lists.c log.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 \ conn-zip.h hash.h io.h irc.h irc-channel.h irc-info.h irc-login.h \ @@ -36,7 +36,7 @@ noinst_HEADERS = ngircd.h array.h channel.h client.h conf.h conn.h conn-func.h \ defines.h messages.h clean-local: - rm -f check-version check-help lint.out cvs-version.* + rm -f check-version check-help lint.out maintainer-clean-local: rm -f Makefile Makefile.in @@ -77,23 +77,6 @@ lint: || echo "Result: no warnings found."; \ 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 # -eof- diff --git a/src/ngircd/channel.c b/src/ngircd/channel.c index 3341cb4..32f911a 100644 --- a/src/ngircd/channel.c +++ b/src/ngircd/channel.c @@ -17,7 +17,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: channel.c,v 1.63 2007/06/11 20:06:46 fw Exp $"; +static char UNUSED id[] = "$Id: channel.c,v 1.65 2008/02/05 16:31:35 fw Exp $"; #include "imp.h" #include @@ -56,7 +56,7 @@ static CL2CHAN *My_Cl2Chan; static CL2CHAN *Get_Cl2Chan 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_Next_Cl2Chan PARAMS(( CL2CHAN *Start, CLIENT *Client, CHANNEL *Chan )); static bool Delete_Channel PARAMS(( CHANNEL *Chan )); @@ -201,25 +201,38 @@ Channel_Join( CLIENT *Client, char *Name ) } /* 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 -Channel_Part( CLIENT *Client, CLIENT *Origin, char *Name, char *Reason ) +Channel_Part(CLIENT * Client, CLIENT * Origin, const char *Name, const char *Reason) { 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; } - /* 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 */ @@ -388,7 +401,7 @@ Channel_Next( CHANNEL *Chan ) GLOBAL CHANNEL * -Channel_Search( char *Name ) +Channel_Search( const char *Name ) { /* Channel-Struktur suchen */ @@ -695,38 +708,66 @@ Channel_SetMaxUsers(CHANNEL *Chan, unsigned long Count) } /* 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; - if( Channel_IsMemberOf( Chan, From )) - { + + if (Channel_IsMemberOf(Chan, From)) { 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 * @@ -801,7 +842,7 @@ Add_Client( CHANNEL *Chan, CLIENT *Client ) 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; 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 ); } - + return true; } /* Remove_Client */ diff --git a/src/ngircd/channel.h b/src/ngircd/channel.h index 023a41e..8bf526b 100644 --- a/src/ngircd/channel.h +++ b/src/ngircd/channel.h @@ -8,7 +8,7 @@ * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. * - * $Id: channel.h,v 1.33 2006/12/07 22:23:39 fw Exp $ + * $Id: channel.h,v 1.35 2008/02/05 16:31:35 fw Exp $ * * Channel management (header) */ @@ -64,7 +64,7 @@ GLOBAL void Channel_InitPredefined PARAMS(( void )); GLOBAL void Channel_Exit PARAMS(( void )); 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 )); @@ -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_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_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_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 )); diff --git a/src/ngircd/client.c b/src/ngircd/client.c index c7d6427..24b24c7 100644 --- a/src/ngircd/client.c +++ b/src/ngircd/client.c @@ -17,7 +17,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: client.c,v 1.97 2007/11/21 12:16:36 alex Exp $"; +static char UNUSED id[] = "$Id: client.c,v 1.98 2008/04/04 19:30:01 fw Exp $"; #include "imp.h" #include @@ -55,6 +55,7 @@ static char GetID_Buffer[GETID_LEN]; static WHOWAS My_Whowas[MAX_WHOWAS]; static int Last_Whowas = -1; +static long Max_Users, My_Max_Users; 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)); -long Max_Users = 0, My_Max_Users = 0; - - GLOBAL void Client_Init( void ) { diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c index 7ca5567..c5a621f 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -14,7 +14,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: conf.c,v 1.103 2007/11/23 16:26:04 fw Exp $"; +static char UNUSED id[] = "$Id: conf.c,v 1.105 2008/03/18 20:12:47 fw Exp $"; #include "imp.h" #include @@ -57,7 +57,7 @@ static int New_Server_Idx; static void Set_Defaults PARAMS(( bool InitServers )); -static void Read_Config PARAMS(( void )); +static bool Read_Config PARAMS(( bool ngircd_starting )); static void Validate_Config PARAMS(( bool TestOnly, bool Rehash )); static void Handle_GLOBAL PARAMS(( int Line, char *Var, char *Arg )); @@ -134,24 +134,33 @@ ports_parse(array *a, int Line, char *Arg) GLOBAL void Conf_Init( void ) { - Set_Defaults( true ); - Read_Config( ); + Read_Config( true ); Validate_Config(false, false); } /* Config_Init */ -GLOBAL void +GLOBAL bool Conf_Rehash( void ) { - Set_Defaults( false ); - Read_Config( ); + if (!Read_Config(false)) + return false; Validate_Config(false, true); /* Update CLIENT structure of local server */ Client_SetInfo(Client_ThisServer(), Conf_ServerInfo); + return true; } /* Config_Rehash */ +static const char* +yesno_to_str(int boolean_value) +{ + if (boolean_value) + return "yes"; + return "no"; +} + + GLOBAL int Conf_Test( void ) { @@ -163,9 +172,8 @@ Conf_Test( void ) char *topic; Use_Log = false; - Set_Defaults( true ); - Read_Config( ); + Read_Config( true ); Validate_Config(true, false); /* If stdin and stdout ("you can read our nice message and we can @@ -202,10 +210,17 @@ Conf_Test( void ) printf( " PingTimeout = %d\n", Conf_PingTimeout ); printf( " PongTimeout = %d\n", Conf_PongTimeout ); 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( " NoDNS = %s\n", Conf_NoDNS ? "yes" : "no"); + 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 + printf(" ListenIPv6 = %s\n", yesno_to_str(Conf_ListenIPv6)); + printf(" ListenIPv4 = %s\n", yesno_to_str(Conf_ListenIPv4)); + 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); @@ -450,6 +465,11 @@ Set_Defaults( bool InitServers ) Conf_PredefChannelsOnly = false; Conf_OperServerMode = false; + Conf_ConnectIPv4 = true; + Conf_ListenIPv4 = true; + Conf_ConnectIPv6 = true; + Conf_ListenIPv6 = true; + Conf_MaxConnections = 0; Conf_MaxConnectionsIP = 5; Conf_MaxJoins = 10; @@ -460,8 +480,8 @@ Set_Defaults( bool InitServers ) } /* Set_Defaults */ -static void -Read_Config( void ) +static bool +Read_Config( bool ngircd_starting ) { /* Read configuration file. */ @@ -476,10 +496,14 @@ Read_Config( void ) /* No configuration file found! */ Config_Error( LOG_ALERT, "Can't read configuration \"%s\": %s", NGIRCd_ConfFile, strerror( errno )); + if (!ngircd_starting) + return false; Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME ); exit( 1 ); } + Set_Defaults( ngircd_starting ); + Config_Error( LOG_INFO, "Reading configuration from \"%s\" ...", NGIRCd_ConfFile ); /* Clean up server configuration structure: mark all already @@ -626,6 +650,7 @@ Read_Config( void ) exit( 1 ); } } + return true; } /* Read_Config */ @@ -813,6 +838,33 @@ Handle_GLOBAL( int Line, char *Var, char *Arg ) 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 ) { + /* listen on ipv6 sockets, if available? */ + Conf_ListenIPv6 = Check_ArgIsTrue( Arg ); + return; + } + if( strcasecmp( Var, "ListenIPv4" ) == 0 ) { + /* + * listen on ipv4 sockets, if available? + * this allows "ipv6-only" setups. + */ + Conf_ListenIPv4 = Check_ArgIsTrue( Arg ); + 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 ) { /* Are IRC operators allowed to use MODE in channels they aren't Op in? */ Conf_OperCanMode = Check_ArgIsTrue( Arg ); @@ -938,7 +990,7 @@ Handle_SERVER( int Line, char *Var, char *Arg ) return; } if (strcasecmp(Var, "Bind") == 0) { - if (ngt_IPStrToBin(Arg, &New_Server.bind_addr)) + 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\"", @@ -1134,6 +1186,16 @@ Validate_Config(bool Configtest, bool Rehash) "No administrative information configured but required by RFC!"); } +#ifdef WANT_IPV6 + if (!Conf_ListenIPv4 && !Conf_ListenIPv6) + Config_Error(LOG_ALERT, + "Both \"ListenIPv4\" and \"ListenIPv6\" are set to 'no'; no network protocol available!"); + + if (!Conf_ConnectIPv4 && !Conf_ConnectIPv6) + Config_Error(LOG_ALERT, + "Both \"ConnectIPv4\" and \"ConnectIPv6\" are set to 'no'; ngircd will fail to connect to other irc servers"); +#endif + #ifdef DEBUG servers = servers_once = 0; for (i = 0; i < MAX_SERVERS; i++) { @@ -1213,7 +1275,7 @@ Init_Server_Struct( CONF_SERVER *Server ) Resolve_Init(&Server->res_stat); Server->conn_id = NONE; - Server->bind_addr.s_addr = htonl(INADDR_ANY); + memset(&Server->bind_addr, 0, sizeof(&Server->bind_addr)); } /* Init_Server_Struct */ diff --git a/src/ngircd/conf.h b/src/ngircd/conf.h index 5ae7f5d..3bc2066 100644 --- a/src/ngircd/conf.h +++ b/src/ngircd/conf.h @@ -8,7 +8,7 @@ * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. * - * $Id: conf.h,v 1.47 2007/11/23 16:28:37 fw Exp $ + * $Id: conf.h,v 1.49 2008/03/18 20:12:47 fw Exp $ * * Configuration management (header) */ @@ -22,6 +22,8 @@ #include "defines.h" #include "array.h" #include "portab.h" +#include "tool.h" +#include "ng_ipaddr.h" typedef struct _Conf_Oper { @@ -42,7 +44,8 @@ typedef struct _Conf_Server RES_STAT res_stat; /* Status of the resolver */ int flags; /* Flags */ CONN_ID conn_id; /* ID of server connection or NONE */ - struct in_addr bind_addr; /* source address to use for outgoing connections */ + 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; typedef struct _Conf_Channel @@ -121,6 +124,21 @@ GLOBAL bool Conf_OperCanMode; /* Disable all DNS functions? */ GLOBAL bool Conf_NoDNS; +/* listen for incoming ipv6 connections if OS supports it (default: yes)? */ +GLOBAL bool Conf_ListenIPv6; + +/* listen for incoming ipv4 connections if OS supports it (default: yes)? */ +GLOBAL bool Conf_ListenIPv4; + +/* + * 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, * ircd2 will ignore the command. This enables a workaround: * It masks the command as coming from the server */ @@ -139,7 +157,7 @@ GLOBAL int Conf_MaxConnectionsIP; GLOBAL unsigned int Conf_MaxNickLength; 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 void Conf_UnsetServer PARAMS(( CONN_ID Idx )); diff --git a/src/ngircd/conn-func.c b/src/ngircd/conn-func.c index 92da142..2f15786 100644 --- a/src/ngircd/conn-func.c +++ b/src/ngircd/conn-func.c @@ -16,11 +16,12 @@ #include "portab.h" -static char UNUSED id[] = "$Id: conn-func.c,v 1.11 2007/10/04 15:03:56 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 -#include +#include +#include "log.h" #include "conn.h" #include "client.h" diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 6042db2..df65fc0 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -17,7 +17,7 @@ #include "portab.h" #include "io.h" -static char UNUSED id[] = "$Id: conn.c,v 1.220 2007/12/13 01:30:16 fw Exp $"; +static char UNUSED id[] = "$Id: conn.c,v 1.221 2008/02/26 22:04:17 fw Exp $"; #include "imp.h" #include @@ -86,10 +86,9 @@ static void Check_Connections PARAMS(( void )); static void Check_Servers PARAMS(( void )); static void Init_Conn_Struct PARAMS(( CONN_ID Idx )); static bool Init_Socket PARAMS(( int Sock )); -static void New_Server PARAMS(( int Server, struct in_addr *dest)); +static void New_Server PARAMS(( int Server, ng_ipaddr_t *dest )); 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(( int af, const UINT16 Port )); static array My_Listeners; static array My_ConnArray; @@ -144,10 +143,28 @@ cb_connserver(int sock, UNUSED short what) Conf_Server[Conf_GetServer(idx)].port, idx, strerror(err)); + res = Conf_GetServer(idx); + assert(res >= 0); + 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; } + 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 ); server_login(idx); } @@ -255,7 +272,7 @@ Conn_Exit( void ) static unsigned int -ports_initlisteners(array *a, void (*func)(int,short)) +ports_initlisteners(array *a, int af, void (*func)(int,short)) { unsigned int created = 0; size_t len; @@ -265,7 +282,7 @@ ports_initlisteners(array *a, void (*func)(int,short)) len = array_length(a, sizeof (UINT16)); port = array_start(a); while(len--) { - fd = NewListener( *port ); + fd = NewListener(af, *port); if (fd < 0) { port++; continue; @@ -290,14 +307,19 @@ Conn_InitListeners( void ) { /* Initialize ports on which the server should accept connections */ - unsigned int created; + unsigned int created = 0; if (!io_library_init(CONNECTION_POOL)) { Log(LOG_EMERG, "Cannot initialize IO routines: %s", strerror(errno)); return -1; } - created = ports_initlisteners(&Conf_ListenPorts, cb_listen); +#ifdef WANT_IPV6 + if (Conf_ListenIPv6) + created = ports_initlisteners(&Conf_ListenPorts, AF_INET6, cb_listen); +#endif + if (Conf_ListenIPv4) + created += ports_initlisteners(&Conf_ListenPorts, AF_INET, cb_listen); return created; } /* Conn_InitListeners */ @@ -327,70 +349,79 @@ Conn_ExitListeners( void ) } /* Conn_ExitListeners */ -static void -InitSinaddr(struct sockaddr_in *addr, UINT16 Port) +static bool +InitSinaddrListenAddr(int af, ng_ipaddr_t *addr, UINT16 Port) { - struct in_addr inaddr; - - memset(addr, 0, sizeof(*addr)); - memset( &inaddr, 0, sizeof(inaddr)); - - addr->sin_family = AF_INET; - addr->sin_port = htons(Port); - inaddr.s_addr = htonl(INADDR_ANY); - addr->sin_addr = inaddr; + bool ret; + const char *listen_addrstr = NULL; +#ifdef WANT_IPV6 + if (af == AF_INET) + listen_addrstr = "0.0.0.0"; +#else + (void)af; +#endif + if (Conf_ListenAddress[0]) /* overrides V4/V6 atm */ + listen_addrstr = Conf_ListenAddress; + + ret = ng_ipaddr_init(addr, listen_addrstr, Port); + if (!ret) { + if (!listen_addrstr) + 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 bool -InitSinaddrListenAddr(struct sockaddr_in *addr, UINT16 Port) +static void +set_v6_only(int af, int sock) { - struct in_addr inaddr; - - InitSinaddr(addr, Port); +#if defined(IPV6_V6ONLY) && defined(WANT_IPV6) + int on = 1; - if (!Conf_ListenAddress[0]) - return true; - - if (!ngt_IPStrToBin(Conf_ListenAddress, &inaddr)) { - Log( LOG_CRIT, "Can't bind to %s:%u: can't convert ip address \"%s\"", - Conf_ListenAddress, Port, Conf_ListenAddress); - return false; - } + if (af != AF_INET6) + return; - addr->sin_addr = inaddr; - return true; + 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 */ static int -NewListener( const UINT16 Port ) +NewListener(int af, const UINT16 Port) { /* Create new listening socket on specified port */ - - struct sockaddr_in addr; + ng_ipaddr_t addr; int sock; #ifdef ZEROCONF char name[CLIENT_ID_LEN], *info; #endif + if (!InitSinaddrListenAddr(af, &addr, Port)) + return -1; - InitSinaddrListenAddr(&addr, Port); - - addr.sin_family = AF_INET; - addr.sin_port = htons( Port ); - - sock = socket( PF_INET, SOCK_STREAM, 0); + sock = socket(ng_ipaddr_af(&addr), SOCK_STREAM, 0); if( sock < 0 ) { Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno )); return -1; } - if( ! Init_Socket( sock )) return -1; + af = ng_ipaddr_af(&addr); - 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 ); + set_v6_only(af, 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; } @@ -407,8 +438,12 @@ NewListener( const UINT16 Port ) 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 ); +#ifdef WANT_IPV6 + if (af == AF_INET6) + Log(LOG_INFO, "Now listening on [%s]:%d (socket %d).", ng_ipaddr_tostr(&addr), Port, sock); + else +#endif + Log(LOG_INFO, "Now listening on %s:%d (socket %d).", ng_ipaddr_tostr(&addr), Port, sock); #ifdef ZEROCONF /* Get best server description text */ @@ -709,6 +744,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient ) CLIENT *c; char *txt; double in_k, out_k; + UINT16 port; #ifdef ZLIB double in_z_k, out_z_k; int in_p, out_p; @@ -736,9 +772,9 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient ) if (! txt) txt = "Reason unknown"; + port = ng_ipaddr_getport(&My_Connections[Idx].addr); 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 */ c = Conn_GetClient( Idx ); @@ -778,7 +814,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient ) Log(LOG_CRIT, "Error closing connection %d (socket %d) with %s:%d - %s! (ignored)", 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: */ @@ -807,8 +843,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient ) out_p = (int)(( out_k * 100 ) / out_z_k ); Log(LOG_INFO, "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); } else @@ -816,8 +851,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient ) { Log(LOG_INFO, "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); } @@ -941,6 +975,22 @@ Handle_Write( CONN_ID Idx ) 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 ) { /* Neue Client-Verbindung von Listen-Socket annehmen und @@ -949,14 +999,16 @@ New_Connection( int Sock ) #ifdef TCPWRAP struct request_info req; #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; CLIENT *c; long cnt; assert( Sock > NONE ); /* 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, (socklen_t *)&new_sock_len); if (new_sock < 0) { @@ -964,14 +1016,18 @@ New_Connection( int Sock ) 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 /* Validate socket using TCP Wrappers */ request_init( &req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock, RQ_CLIENT_SIN, &new_addr, NULL ); 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" ); close( new_sock ); return -1; @@ -981,13 +1037,12 @@ New_Connection( int Sock ) /* Socket initialisieren */ if (!Init_Socket( new_sock )) return -1; - + /* 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! */ - 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!" ); close( new_sock ); return -1; @@ -1029,7 +1084,7 @@ New_Connection( int Sock ) 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 ) { Log(LOG_ALERT, "Can't accept connection: can't create client structure!"); Simple_Message(new_sock, "ERROR :Internal error"); @@ -1043,13 +1098,12 @@ New_Connection( int Sock ) My_Connections[new_sock].client = c; 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 */ - 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); if (!Conf_NoDNS) Resolve_Addr(&My_Connections[new_sock].res_stat, &new_addr, @@ -1107,10 +1161,10 @@ Read_Request( CONN_ID Idx ) len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf)); 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, "Socket closed!", "Client closed connection", false); @@ -1367,37 +1421,44 @@ Check_Servers( void ) static void -New_Server( int Server , struct in_addr *dest) +New_Server( int Server , ng_ipaddr_t *dest) { /* Establish new server link */ - struct sockaddr_in local_addr; - struct sockaddr_in new_addr; - int res, new_sock; + char ip_str[NG_INET_ADDRSTRLEN]; + int af_dest, res, new_sock; CLIENT *c; assert( Server > NONE ); - memset(&new_addr, 0, sizeof( new_addr )); - new_addr.sin_family = AF_INET; - new_addr.sin_addr = *dest; - new_addr.sin_port = htons( Conf_Server[Server].port ); + if (!ng_ipaddr_tostr_r(dest, ip_str)) { + Log(LOG_WARNING, "New_Server: Could not convert IP to string"); + return; + } + + 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 ) { + 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: %s!", strerror( errno )); return; } - if( ! Init_Socket( new_sock )) return; - - /* if we fail to bind, just continue and let connect() pick a source address */ - InitSinaddr(&local_addr, 0); - local_addr.sin_addr = Conf_Server[Server].bind_addr; - if (bind(new_sock, (struct sockaddr *)&local_addr, (socklen_t)sizeof(local_addr))) - Log(LOG_WARNING, "Can't bind socket to %s: %s!", inet_ntoa(Conf_Server[Server].bind_addr), strerror( errno )); + 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 )) { Log( LOG_CRIT, "Can't connect socket: %s!", strerror( errno )); close( new_sock ); @@ -1418,8 +1479,9 @@ New_Server( int Server , struct in_addr *dest) 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!" ); close( new_sock ); return; @@ -1431,7 +1493,7 @@ New_Server( int Server , struct in_addr *dest) /* Register connection */ Conf_Server[Server].conn_id = 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; strlcpy( My_Connections[new_sock].host, Conf_Server[Server].host, sizeof(My_Connections[new_sock].host )); @@ -1510,8 +1572,9 @@ cb_Connect_to_Server(int fd, UNUSED short events) /* Read result of resolver sub-process from pipe and start connection */ int i; size_t len; - struct in_addr dest_addr; - 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); @@ -1528,23 +1591,28 @@ cb_Connect_to_Server(int fd, UNUSED short events) } /* 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) return; - readbuf[len] = '\0'; - LogDebug("Got result from resolver: \"%s\" (%u bytes read).", readbuf, len); + assert((len % sizeof(ng_ipaddr_t)) == 0); - if (!ngt_IPStrToBin(readbuf, &dest_addr)) { - Log(LOG_ERR, "Can't connect to \"%s\": can't convert ip address %s!", - Conf_Server[i].host, readbuf); - return; - } + LogDebug("Got result from resolver: %u structs (%u bytes).", len/sizeof(ng_ipaddr_t), len); - Log( LOG_INFO, "Establishing connection to \"%s\", %s, port %d ... ", - Conf_Server[i].host, readbuf, Conf_Server[i].port ); + 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() */ - New_Server(i, &dest_addr); + New_Server(i, dest_addrs); } /* cb_Read_Forward_Lookup */ @@ -1643,19 +1711,6 @@ Simple_Message( int Sock, const char *Msg ) } /* 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 * Conn_GetClient( CONN_ID Idx ) { diff --git a/src/ngircd/conn.h b/src/ngircd/conn.h index 626a6e9..3bb76ab 100644 --- a/src/ngircd/conn.h +++ b/src/ngircd/conn.h @@ -8,7 +8,7 @@ * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. * - * $Id: conn.h,v 1.45 2007/10/04 15:03:56 alex Exp $ + * $Id: conn.h,v 1.46 2008/02/26 22:04:17 fw Exp $ * * Connection management (header) */ @@ -38,6 +38,8 @@ typedef int CONN_ID; #include "defines.h" #include "resolve.h" #include "array.h" +#include "tool.h" +#include "ng_ipaddr.h" #ifdef ZLIB #include @@ -54,7 +56,7 @@ typedef struct _ZipData typedef struct _Connection { int sock; /* Socket handle */ - struct sockaddr_in addr; /* Client address */ + ng_ipaddr_t addr; /* Client address */ RES_STAT res_stat; /* Status of resolver process */ char host[HOST_LEN]; /* Hostname */ array rbuf; /* Read buffer */ diff --git a/src/ngircd/io.c b/src/ngircd/io.c index d40b485..18a29aa 100644 --- a/src/ngircd/io.c +++ b/src/ngircd/io.c @@ -12,7 +12,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: io.c,v 1.28 2008/01/02 10:29:51 fw Exp $"; +static char UNUSED id[] = "$Id: io.c,v 1.31 2008/04/03 20:56:44 fw Exp $"; #include #include @@ -110,7 +110,11 @@ static bool io_event_change_devpoll(int fd, short what); static fd_set readers; static fd_set writers; -static int select_maxfd; /* the select() interface sucks badly */ +/* + * this is the first argument for select(), i.e. + * the largest fd registered, plus one. + */ +static int select_maxfd; static int io_dispatch_select(struct timeval *tv); #ifndef IO_USE_EPOLL @@ -122,6 +126,15 @@ static array io_events; static void io_docallback PARAMS((int fd, short what)); +#ifdef DEBUG_IO +static void io_debug(const char *s, int fd, int what) +{ + Log(LOG_DEBUG, "%s: %d, %d\n", s, fd, what); +} +#else +static inline void io_debug(const char UNUSED *s,int UNUSED a, int UNUSED b) {/*NOTHING*/} +#endif + static io_event * io_event_get(int fd) { @@ -138,6 +151,72 @@ io_event_get(int fd) #ifdef IO_USE_DEVPOLL +static int +io_dispatch_devpoll(struct timeval *tv) +{ + struct dvpoll dvp; + time_t sec = tv->tv_sec * 1000; + int i, total, ret, timeout = tv->tv_usec + sec; + short what; + struct pollfd p[100]; + + if (timeout < 0) + timeout = 1000; + + total = 0; + do { + dvp.dp_timeout = timeout; + dvp.dp_nfds = 100; + dvp.dp_fds = p; + ret = ioctl(io_masterfd, DP_POLL, &dvp); + total += ret; + if (ret <= 0) + return total; + for (i=0; i < ret ; i++) { + what = 0; + if (p[i].revents & (POLLIN|POLLPRI)) + what = IO_WANTREAD; + + if (p[i].revents & POLLOUT) + what |= IO_WANTWRITE; + + if (p[i].revents && !what) { + /* other flag is set, probably POLLERR */ + what = IO_ERROR; + } + io_docallback(p[i].fd, what); + } + } while (ret == 100); + + return total; +} + + +static bool +io_event_change_devpoll(int fd, short what) +{ + struct pollfd p; + + p.events = 0; + + if (what & IO_WANTREAD) + p.events = POLLIN | POLLPRI; + if (what & IO_WANTWRITE) + p.events |= POLLOUT; + + p.fd = fd; + return write(io_masterfd, &p, sizeof p) == (ssize_t)sizeof p; +} + +static void +io_close_devpoll(int fd) +{ + struct pollfd p; + p.events = POLLREMOVE; + p.fd = fd; + write(io_masterfd, &p, sizeof p); +} + static void io_library_init_devpoll(unsigned int eventsize) { @@ -147,10 +226,92 @@ io_library_init_devpoll(unsigned int eventsize) Log(LOG_INFO, "IO subsystem: /dev/poll (initial maxfd %u, masterfd %d).", eventsize, io_masterfd); } +#else +static inline void io_close_devpoll(int UNUSED x) {/* NOTHING */} +static inline void io_library_init_devpoll(unsigned int UNUSED ev) {/*NOTHING*/} #endif #ifdef IO_USE_POLL +static int +io_dispatch_poll(struct timeval *tv) +{ + time_t sec = tv->tv_sec * 1000; + int i, ret, timeout = tv->tv_usec + sec; + int fds_ready; + short what; + struct pollfd *p = array_start(&pollfds); + + if (timeout < 0) + timeout = 1000; + + ret = poll(p, poll_maxfd + 1, timeout); + if (ret <= 0) + return ret; + + fds_ready = ret; + for (i=0; i <= poll_maxfd; i++) { + what = 0; + if (p[i].revents & (POLLIN|POLLPRI)) + what = IO_WANTREAD; + + if (p[i].revents & POLLOUT) + what |= IO_WANTWRITE; + + if (p[i].revents && !what) { + /* other flag is set, probably POLLERR */ + what = IO_ERROR; + } + if (what) { + fds_ready--; + io_docallback(i, what); + } + if (fds_ready <= 0) + break; + } + + return ret; +} + +static bool +io_event_change_poll(int fd, short what) +{ + struct pollfd *p; + short events = 0; + + if (what & IO_WANTREAD) + events = POLLIN | POLLPRI; + if (what & IO_WANTWRITE) + events |= POLLOUT; + + p = array_alloc(&pollfds, sizeof *p, fd); + if (p) { + p->events = events; + p->fd = fd; + if (fd > poll_maxfd) + poll_maxfd = fd; + } + return p != NULL; +} + +static void +io_close_poll(int fd) +{ + struct pollfd *p; + p = array_get(&pollfds, sizeof *p, fd); + if (!p) return; + + p->fd = -1; + if (fd == poll_maxfd) { + while (poll_maxfd > 0) { + --poll_maxfd; + p = array_get(&pollfds, sizeof *p, poll_maxfd); + if (p && p->fd >= 0) + break; + } + } +} + static void io_library_init_poll(unsigned int eventsize) { @@ -169,13 +330,52 @@ io_library_init_poll(unsigned int eventsize) library_initialized = true; } } +#else +static inline void io_close_poll(int UNUSED x) {/* NOTHING */} +static inline void io_library_init_poll(unsigned int UNUSED ev) {/*NOTHING*/} #endif #ifdef IO_USE_SELECT +static int +io_dispatch_select(struct timeval *tv) +{ + fd_set readers_tmp = readers; + fd_set writers_tmp = writers; + short what; + int ret, i; + int fds_ready; + ret = select(select_maxfd + 1, &readers_tmp, &writers_tmp, NULL, tv); + if (ret <= 0) + return ret; + + fds_ready = ret; + + for (i = 0; i <= select_maxfd; i++) { + what = 0; + if (FD_ISSET(i, &readers_tmp)) { + what = IO_WANTREAD; + fds_ready--; + } + + if (FD_ISSET(i, &writers_tmp)) { + what |= IO_WANTWRITE; + fds_ready--; + } + if (what) + io_docallback(i, what); + if (fds_ready <= 0) + break; + } + + return ret; +} + static void io_library_init_select(unsigned int eventsize) { + if (library_initialized) + return; Log(LOG_INFO, "IO subsystem: select (initial maxfd %u).", eventsize); FD_ZERO(&readers); @@ -188,13 +388,93 @@ io_library_init_select(unsigned int eventsize) Conf_MaxConnections = FD_SETSIZE - 1; } +#else + Log(LOG_WARNING, + "FD_SETSIZE undefined, don't know how many descriptors select() can handle on your platform ..."); #endif /* FD_SETSIZE */ library_initialized = true; } + +static void +io_close_select(int fd) +{ + io_event *i; + + if (io_masterfd >= 0) /* Are we using epoll()? */ + return; + + FD_CLR(fd, &writers); + FD_CLR(fd, &readers); + + i = io_event_get(fd); + if (!i) return; + + if (fd == select_maxfd) { + while (select_maxfd>0) { + --select_maxfd; /* find largest fd */ + i = io_event_get(select_maxfd); + if (i && i->callback) break; + } + } +} +#else +static inline void io_library_init_select(int UNUSED x) {/* NOTHING */} +static inline void io_close_select(int UNUSED x) {/* NOTHING */} #endif /* SELECT */ #ifdef IO_USE_EPOLL +static bool +io_event_change_epoll(int fd, short what, const int action) +{ + struct epoll_event ev = { 0, {0} }; + ev.data.fd = fd; + + if (what & IO_WANTREAD) + ev.events = EPOLLIN | EPOLLPRI; + if (what & IO_WANTWRITE) + ev.events |= EPOLLOUT; + + return epoll_ctl(io_masterfd, action, fd, &ev) == 0; +} + +static int +io_dispatch_epoll(struct timeval *tv) +{ + time_t sec = tv->tv_sec * 1000; + int i, total = 0, ret, timeout = tv->tv_usec + sec; + struct epoll_event epoll_ev[100]; + short type; + + if (timeout < 0) + timeout = 1000; + + do { + ret = epoll_wait(io_masterfd, epoll_ev, 100, timeout); + total += ret; + if (ret <= 0) + return total; + + for (i = 0; i < ret; i++) { + type = 0; + if (epoll_ev[i].events & (EPOLLERR | EPOLLHUP)) + type = IO_ERROR; + + if (epoll_ev[i].events & (EPOLLIN | EPOLLPRI)) + type |= IO_WANTREAD; + + if (epoll_ev[i].events & EPOLLOUT) + type |= IO_WANTWRITE; + + io_docallback(epoll_ev[i].data.fd, type); + } + + timeout = 0; + } while (ret == 100); + + return total; +} + static void io_library_init_epoll(unsigned int eventsize) { @@ -207,12 +487,127 @@ io_library_init_epoll(unsigned int eventsize) Log(LOG_INFO, "IO subsystem: epoll (hint size %d, initial maxfd %u, masterfd %d).", ecreate_hint, eventsize, io_masterfd); + return; } -} +#ifdef IO_USE_SELECT + Log(LOG_INFO, "Can't initialize epoll() IO interface, falling back to select() ..."); #endif +} +#else +static inline void io_library_init_epoll(unsigned int UNUSED ev) {/* NOTHING */} +#endif /* IO_USE_EPOLL */ #ifdef IO_USE_KQUEUE +static bool +io_event_kqueue_commit_cache(void) +{ + struct kevent *events; + bool ret; + int len = (int) array_length(&io_evcache, sizeof (struct kevent)); + + if (!len) /* nothing to do */ + return true; + + assert(len>0); + + if (len < 0) { + array_free(&io_evcache); + return false; + } + + events = array_start(&io_evcache); + + assert(events != NULL); + + ret = kevent(io_masterfd, events, len, NULL, 0, NULL) == 0; + if (ret) + array_trunc(&io_evcache); + return ret; +} + +static bool +io_event_change_kqueue(int fd, short what, const int action) +{ + struct kevent kev; + bool ret = true; + + if (what & IO_WANTREAD) { + EV_SET(&kev, fd, EVFILT_READ, action, 0, 0, 0); + ret = array_catb(&io_evcache, (char*) &kev, sizeof (kev)); + if (!ret) + ret = kevent(io_masterfd, &kev,1, NULL, 0, NULL) == 0; + } + + if (ret && (what & IO_WANTWRITE)) { + EV_SET(&kev, fd, EVFILT_WRITE, action, 0, 0, 0); + ret = array_catb(&io_evcache, (char*) &kev, sizeof (kev)); + if (!ret) + ret = kevent(io_masterfd, &kev, 1, NULL, 0, NULL) == 0; + } + + if (array_length(&io_evcache, sizeof kev) >= 100) + io_event_kqueue_commit_cache(); + return ret; +} + +static int +io_dispatch_kqueue(struct timeval *tv) +{ + int i, total = 0, ret; + struct kevent kev[100]; + struct kevent *newevents; + struct timespec ts; + int newevents_len; + ts.tv_sec = tv->tv_sec; + ts.tv_nsec = tv->tv_usec * 1000; + + do { + newevents_len = (int) array_length(&io_evcache, sizeof (struct kevent)); + newevents = (newevents_len > 0) ? array_start(&io_evcache) : NULL; + assert(newevents_len >= 0); + + ret = kevent(io_masterfd, newevents, newevents_len, kev, 100, &ts); + if (newevents && ret != -1) + array_trunc(&io_evcache); + + total += ret; + if (ret <= 0) + return total; + + for (i = 0; i < ret; i++) { + io_debug("dispatch_kqueue: fd, kev.flags", (int)kev[i].ident, kev[i].flags); + if (kev[i].flags & (EV_EOF|EV_ERROR)) { + if (kev[i].flags & EV_ERROR) + Log(LOG_ERR, "kevent fd %d: EV_ERROR (%s)", + (int)kev[i].ident, strerror((int)kev[i].data)); + io_docallback((int)kev[i].ident, IO_ERROR); + continue; + } + + switch (kev[i].filter) { + case EVFILT_READ: + io_docallback((int)kev[i].ident, IO_WANTREAD); + break; + case EVFILT_WRITE: + io_docallback((int)kev[i].ident, IO_WANTWRITE); + break; + default: + LogDebug("Unknown kev.filter number %d for fd %d", + kev[i].filter, kev[i].ident); + /* Fall through */ + case EV_ERROR: + io_docallback((int)kev[i].ident, IO_ERROR); + break; + } + } + ts.tv_sec = 0; + ts.tv_nsec = 0; + } while (ret == 100); + + return total; +} + static void io_library_init_kqueue(unsigned int eventsize) { @@ -224,6 +619,8 @@ io_library_init_kqueue(unsigned int eventsize) if (io_masterfd >= 0) library_initialized = true; } +#else +static inline void io_library_init_kqueue(unsigned int UNUSED ev) {/* NOTHING */} #endif @@ -232,37 +629,16 @@ io_library_init(unsigned int eventsize) { if (library_initialized) return true; -#ifdef IO_USE_SELECT -#ifndef FD_SETSIZE - Log(LOG_WARNING, - "FD_SETSIZE undefined, don't know how many descriptors select() can handle on your platform ..."); -#else - if (eventsize >= FD_SETSIZE) - eventsize = FD_SETSIZE - 1; -#endif /* FD_SETSIZE */ -#endif /* IO_USE_SELECT */ + if ((eventsize > 0) && !array_alloc(&io_events, sizeof(io_event), (size_t)eventsize)) eventsize = 0; -#ifdef IO_USE_EPOLL + io_library_init_epoll(eventsize); -#ifdef IO_USE_SELECT - if (io_masterfd < 0) - Log(LOG_INFO, "Can't initialize epoll() IO interface, falling back to select() ..."); -#endif -#endif -#ifdef IO_USE_KQUEUE io_library_init_kqueue(eventsize); -#endif -#ifdef IO_USE_DEVPOLL io_library_init_devpoll(eventsize); -#endif -#ifdef IO_USE_POLL io_library_init_poll(eventsize); -#endif -#ifdef IO_USE_SELECT - if (! library_initialized) - io_library_init_select(eventsize); -#endif + io_library_init_select(eventsize); + return library_initialized; } @@ -274,14 +650,12 @@ io_library_shutdown(void) FD_ZERO(&readers); FD_ZERO(&writers); #endif -#ifdef IO_USE_EPOLL +#if defined(IO_USE_EPOLL) || defined(IO_USE_KQUEUE) || defined(IO_USE_DEVPOLL) if (io_masterfd >= 0) close(io_masterfd); io_masterfd = -1; #endif #ifdef IO_USE_KQUEUE - close(io_masterfd); - io_masterfd = -1; array_free(&io_evcache); #endif library_initialized = false; @@ -300,31 +674,10 @@ io_event_setcb(int fd, void (*cbfunc) (int, short)) } -bool -io_event_create(int fd, short what, void (*cbfunc) (int, short)) +static bool +backend_create_ev(int fd, short what) { bool ret; - io_event *i; - - assert(fd >= 0); -#if defined(IO_USE_SELECT) && defined(FD_SETSIZE) - if (fd >= FD_SETSIZE) { - Log(LOG_ERR, - "fd %d exceeds FD_SETSIZE (%u) (select can't handle more file descriptors)", - fd, FD_SETSIZE); - return false; - } -#endif - i = (io_event *) array_alloc(&io_events, sizeof(io_event), (size_t) fd); - if (!i) { - Log(LOG_WARNING, - "array_alloc failed: could not allocate space for %d io_event structures", - fd); - return false; - } - - i->callback = cbfunc; - i->what = 0; #ifdef IO_USE_DEVPOLL ret = io_event_change_devpoll(fd, what); #endif @@ -341,126 +694,42 @@ io_event_create(int fd, short what, void (*cbfunc) (int, short)) if (io_masterfd < 0) ret = io_event_add(fd, what); #endif - if (ret) i->what = what; return ret; } -#ifdef IO_USE_DEVPOLL -static bool -io_event_change_devpoll(int fd, short what) -{ - struct pollfd p; - - p.events = 0; - - if (what & IO_WANTREAD) - p.events = POLLIN | POLLPRI; - if (what & IO_WANTWRITE) - p.events |= POLLOUT; - - p.fd = fd; - return write(io_masterfd, &p, sizeof p) == (ssize_t)sizeof p; -} -#endif - - - -#ifdef IO_USE_POLL -static bool -io_event_change_poll(int fd, short what) +bool +io_event_create(int fd, short what, void (*cbfunc) (int, short)) { - struct pollfd *p; - short events = 0; - - if (what & IO_WANTREAD) - events = POLLIN | POLLPRI; - if (what & IO_WANTWRITE) - events |= POLLOUT; + bool ret; + io_event *i; - p = array_alloc(&pollfds, sizeof *p, fd); - if (p) { - p->events = events; - p->fd = fd; - if (fd > poll_maxfd) - poll_maxfd = fd; + assert(fd >= 0); +#if defined(IO_USE_SELECT) && defined(FD_SETSIZE) + if (io_masterfd < 0 && fd >= FD_SETSIZE) { + Log(LOG_ERR, + "fd %d exceeds FD_SETSIZE (%u) (select can't handle more file descriptors)", + fd, FD_SETSIZE); + return false; } - return p != NULL; -} -#endif - -#ifdef IO_USE_EPOLL -static bool -io_event_change_epoll(int fd, short what, const int action) -{ - struct epoll_event ev = { 0, {0} }; - ev.data.fd = fd; - - if (what & IO_WANTREAD) - ev.events = EPOLLIN | EPOLLPRI; - if (what & IO_WANTWRITE) - ev.events |= EPOLLOUT; - - return epoll_ctl(io_masterfd, action, fd, &ev) == 0; -} #endif - -#ifdef IO_USE_KQUEUE -static bool -io_event_kqueue_commit_cache(void) -{ - struct kevent *events; - bool ret; - int len = (int) array_length(&io_evcache, sizeof (struct kevent)); - - if (!len) /* nothing to do */ - return true; - - assert(len>0); - - if (len < 0) { - array_free(&io_evcache); + i = (io_event *) array_alloc(&io_events, sizeof(io_event), (size_t) fd); + if (!i) { + Log(LOG_WARNING, + "array_alloc failed: could not allocate space for %d io_event structures", + fd); return false; } - events = array_start(&io_evcache); - - assert(events != NULL); - - ret = kevent(io_masterfd, events, len, NULL, 0, NULL) == 0; + i->callback = cbfunc; + i->what = 0; + ret = backend_create_ev(fd, what); if (ret) - array_trunc(&io_evcache); + i->what = what; return ret; } -static bool -io_event_change_kqueue(int fd, short what, const int action) -{ - struct kevent kev; - bool ret = true; - - if (what & IO_WANTREAD) { - EV_SET(&kev, fd, EVFILT_READ, action, 0, 0, 0); - ret = array_catb(&io_evcache, (char*) &kev, sizeof (kev)); - if (!ret) - ret = kevent(io_masterfd, &kev,1, NULL, 0, NULL) == 0; - } - - if (ret && (what & IO_WANTWRITE)) { - EV_SET(&kev, fd, EVFILT_WRITE, action, 0, 0, 0); - ret = array_catb(&io_evcache, (char*) &kev, sizeof (kev)); - if (!ret) - ret = kevent(io_masterfd, &kev, 1, NULL, 0, NULL) == 0; - } - - if (array_length(&io_evcache, sizeof kev) >= 100) - io_event_kqueue_commit_cache(); - return ret; -} -#endif - - bool io_event_add(int fd, short what) { @@ -470,15 +739,14 @@ io_event_add(int fd, short what) if ((i->what & what) == what) /* event type is already registered */ return true; -#ifdef DEBUG_IO - Log(LOG_DEBUG, "io_event_add(): fd %d, what %d.", fd, what); -#endif + + io_debug("io_event_add: fd, what", fd, what); + i->what |= what; #ifdef IO_USE_EPOLL if (io_masterfd >= 0) return io_event_change_epoll(fd, i->what, EPOLL_CTL_MOD); #endif - #ifdef IO_USE_KQUEUE return io_event_change_kqueue(fd, what, EV_ADD | EV_ENABLE); #endif @@ -499,6 +767,7 @@ io_event_add(int fd, short what) return true; #endif + return false; } @@ -508,7 +777,6 @@ io_setnonblock(int fd) int flags = fcntl(fd, F_GETFL); if (flags == -1) return false; - #ifndef O_NONBLOCK #define O_NONBLOCK O_NDELAY #endif @@ -518,80 +786,6 @@ io_setnonblock(int fd) } -#ifdef IO_USE_DEVPOLL -static void -io_close_devpoll(int fd) -{ - struct pollfd p; - p.events = POLLREMOVE; - p.fd = fd; - write(io_masterfd, &p, sizeof p); -} -#else -static inline void -io_close_devpoll(int UNUSED x) -{ - /* NOTHING */ -} -#endif - - - -#ifdef IO_USE_POLL -static void -io_close_poll(int fd) -{ - struct pollfd *p; - p = array_get(&pollfds, sizeof *p, fd); - if (!p) return; - - p->fd = -1; - if (fd == poll_maxfd) { - while (poll_maxfd > 0) { - --poll_maxfd; - p = array_get(&pollfds, sizeof *p, poll_maxfd); - if (p && p->fd >= 0) - break; - } - } -} -#else -static inline void io_close_poll(int UNUSED x) { /* NOTHING */ } -#endif - - -#ifdef IO_USE_SELECT -static void -io_close_select(int fd) -{ - io_event *i; - - if (io_masterfd >= 0) /* Are we using epoll()? */ - return; - - FD_CLR(fd, &writers); - FD_CLR(fd, &readers); - - i = io_event_get(fd); - if (!i) return; - - if (fd == select_maxfd) { - while (select_maxfd>0) { - --select_maxfd; /* find largest fd */ - i = io_event_get(select_maxfd); - if (i && i->callback) break; - } - } -} -#else -static inline void -io_close_select(int UNUSED x) -{ - /* NOTHING */ -} -#endif - - bool io_close(int fd) { @@ -610,11 +804,9 @@ io_close(int fd) io_event_kqueue_commit_cache(); } #endif - io_close_devpoll(fd); io_close_poll(fd); io_close_select(fd); - #ifdef IO_USE_EPOLL io_event_change_epoll(fd, 0, EPOLL_CTL_DEL); #endif @@ -630,16 +822,14 @@ bool io_event_del(int fd, short what) { io_event *i = io_event_get(fd); -#ifdef DEBUG_IO - Log(LOG_DEBUG, "io_event_del(): trying to delete eventtype %d on fd %d", what, fd); -#endif + + io_debug("io_event_del: trying to delete eventtype; fd, what", fd, what); if (!i) return false; if (!(i->what & what)) /* event is already disabled */ return true; i->what &= ~what; - #ifdef IO_USE_DEVPOLL return io_event_change_devpoll(fd, i->what); #endif @@ -650,7 +840,6 @@ io_event_del(int fd, short what) if (io_masterfd >= 0) return io_event_change_epoll(fd, i->what, EPOLL_CTL_MOD); #endif - #ifdef IO_USE_KQUEUE return io_event_change_kqueue(fd, what, EV_DISABLE); #endif @@ -660,237 +849,12 @@ io_event_del(int fd, short what) if (what & IO_WANTREAD) FD_CLR(fd, &readers); - return true; #endif + return false; } -#ifdef IO_USE_SELECT -static int -io_dispatch_select(struct timeval *tv) -{ - fd_set readers_tmp = readers; - fd_set writers_tmp = writers; - short what; - int ret, i; - int fds_ready; - ret = select(select_maxfd + 1, &readers_tmp, &writers_tmp, NULL, tv); - if (ret <= 0) - return ret; - - fds_ready = ret; - - for (i = 0; i <= select_maxfd; i++) { - what = 0; - if (FD_ISSET(i, &readers_tmp)) { - what = IO_WANTREAD; - fds_ready--; - } - - if (FD_ISSET(i, &writers_tmp)) { - what |= IO_WANTWRITE; - fds_ready--; - } - if (what) - io_docallback(i, what); - if (fds_ready <= 0) - break; - } - - return ret; -} -#endif - - -#ifdef IO_USE_DEVPOLL -static int -io_dispatch_devpoll(struct timeval *tv) -{ - struct dvpoll dvp; - time_t sec = tv->tv_sec * 1000; - int i, total, ret, timeout = tv->tv_usec + sec; - short what; - struct pollfd p[100]; - - if (timeout < 0) - timeout = 1000; - - total = 0; - do { - dvp.dp_timeout = timeout; - dvp.dp_nfds = 100; - dvp.dp_fds = p; - ret = ioctl(io_masterfd, DP_POLL, &dvp); - total += ret; - if (ret <= 0) - return total; - for (i=0; i < ret ; i++) { - what = 0; - if (p[i].revents & (POLLIN|POLLPRI)) - what = IO_WANTREAD; - - if (p[i].revents & POLLOUT) - what |= IO_WANTWRITE; - - if (p[i].revents && !what) { - /* other flag is set, probably POLLERR */ - what = IO_ERROR; - } - io_docallback(p[i].fd, what); - } - } while (ret == 100); - - return total; -} -#endif - - -#ifdef IO_USE_POLL -static int -io_dispatch_poll(struct timeval *tv) -{ - time_t sec = tv->tv_sec * 1000; - int i, ret, timeout = tv->tv_usec + sec; - int fds_ready; - short what; - struct pollfd *p = array_start(&pollfds); - - if (timeout < 0) - timeout = 1000; - - ret = poll(p, poll_maxfd + 1, timeout); - if (ret <= 0) - return ret; - - fds_ready = ret; - for (i=0; i <= poll_maxfd; i++) { - what = 0; - if (p[i].revents & (POLLIN|POLLPRI)) - what = IO_WANTREAD; - - if (p[i].revents & POLLOUT) - what |= IO_WANTWRITE; - - if (p[i].revents && !what) { - /* other flag is set, probably POLLERR */ - what = IO_ERROR; - } - if (what) { - fds_ready--; - io_docallback(i, what); - } - if (fds_ready <= 0) - break; - } - - return ret; -} -#endif - - -#ifdef IO_USE_EPOLL -static int -io_dispatch_epoll(struct timeval *tv) -{ - time_t sec = tv->tv_sec * 1000; - int i, total = 0, ret, timeout = tv->tv_usec + sec; - struct epoll_event epoll_ev[100]; - short type; - - if (timeout < 0) - timeout = 1000; - - do { - ret = epoll_wait(io_masterfd, epoll_ev, 100, timeout); - total += ret; - if (ret <= 0) - return total; - - for (i = 0; i < ret; i++) { - type = 0; - if (epoll_ev[i].events & (EPOLLERR | EPOLLHUP)) - type = IO_ERROR; - - if (epoll_ev[i].events & (EPOLLIN | EPOLLPRI)) - type |= IO_WANTREAD; - - if (epoll_ev[i].events & EPOLLOUT) - type |= IO_WANTWRITE; - - io_docallback(epoll_ev[i].data.fd, type); - } - - timeout = 0; - } while (ret == 100); - - return total; -} -#endif - - -#ifdef IO_USE_KQUEUE -static int -io_dispatch_kqueue(struct timeval *tv) -{ - int i, total = 0, ret; - struct kevent kev[100]; - struct kevent *newevents; - struct timespec ts; - int newevents_len; - ts.tv_sec = tv->tv_sec; - ts.tv_nsec = tv->tv_usec * 1000; - - do { - newevents_len = (int) array_length(&io_evcache, sizeof (struct kevent)); - newevents = (newevents_len > 0) ? array_start(&io_evcache) : NULL; - assert(newevents_len >= 0); - - ret = kevent(io_masterfd, newevents, newevents_len, kev, 100, &ts); - if (newevents && ret != -1) - array_trunc(&io_evcache); - - total += ret; - if (ret <= 0) - return total; - - for (i = 0; i < ret; i++) { -#ifdef DEBUG_IO - LogDebug("fd %d, kev.flags: %x", (int)kev[i].ident, kev[i].flags); -#endif - if (kev[i].flags & (EV_EOF|EV_ERROR)) { - if (kev[i].flags & EV_ERROR) - Log(LOG_ERR, "kevent fd %d: EV_ERROR (%s)", - (int)kev[i].ident, strerror((int)kev[i].data)); - io_docallback((int)kev[i].ident, IO_ERROR); - continue; - } - - switch (kev[i].filter) { - case EVFILT_READ: - io_docallback((int)kev[i].ident, IO_WANTREAD); - break; - case EVFILT_WRITE: - io_docallback((int)kev[i].ident, IO_WANTWRITE); - break; - default: - LogDebug("Unknown kev.filter number %d for fd %d", - kev[i].filter, kev[i].ident); - /* Fall through */ - case EV_ERROR: - io_docallback((int)kev[i].ident, IO_ERROR); - break; - } - } - ts.tv_sec = 0; - ts.tv_nsec = 0; - } while (ret == 100); - - return total; -} -#endif - - int io_dispatch(struct timeval *tv) { @@ -910,6 +874,7 @@ io_dispatch(struct timeval *tv) #ifdef IO_USE_POLL return io_dispatch_poll(tv); #endif + return -1; } @@ -917,11 +882,9 @@ io_dispatch(struct timeval *tv) static void io_docallback(int fd, short what) { - io_event *i; -#ifdef DEBUG_IO - Log(LOG_DEBUG, "doing callback for fd %d, what %d", fd, what); -#endif - i = io_event_get(fd); + io_event *i = io_event_get(fd); + + io_debug("io_docallback; fd, what", fd, what); if (i->callback) { /* callback might be NULL if a previous callback function called io_close on this fd */ diff --git a/src/ngircd/irc-channel.c b/src/ngircd/irc-channel.c index 139f506..c678cee 100644 --- a/src/ngircd/irc-channel.c +++ b/src/ngircd/irc-channel.c @@ -14,7 +14,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: irc-channel.c,v 1.40.2.2 2008/02/26 12:07:41 fw Exp $"; +static char UNUSED id[] = "$Id: irc-channel.c,v 1.45 2008/02/24 18:57:38 fw Exp $"; #include "imp.h" #include @@ -40,14 +40,147 @@ static char UNUSED id[] = "$Id: irc-channel.c,v 1.40.2.2 2008/02/26 12:07:41 fw #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 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; CHANNEL *chan; - + assert( Client != NULL ); assert( Req != NULL ); @@ -57,186 +190,83 @@ IRC_JOIN( CLIENT *Client, REQUEST *Req ) Client_ID(Client), Req->command); /* 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? */ if (Req->argc > 1) { key = Req->argv[1]; key_ptr = strchr(key, ','); if (key_ptr) *key_ptr = '\0'; - } - else + } else { key = key_ptr = NULL; - + } channame = Req->argv[0]; channame_ptr = strchr(channame, ','); if (channame_ptr) *channame_ptr = '\0'; - /* Channel-Namen durchgehen */ - while (channame) - { - chan = NULL; flags = NULL; + while (channame) { + flags = NULL; + /* Did the server include channel-user-modes? */ if (Client_Type(Client) == CLIENT_SERVER) { - flags = strchr( channame, 0x7 ); - if( flags ) { + flags = strchr(channame, 0x7); + if (flags) { *flags = '\0'; flags++; } } - /* 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; + 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? */ - if( Client_Type( Client ) == CLIENT_USER ) - { + if (Client_Type(Client) == CLIENT_USER) { /* 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"; - } 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 * client is invited or not, but we have to make sure * that the "one shot" entries (generated by INVITE * commands) in this list become deleted when a user * joins a channel this way. */ - chan = Channel_Search( channame ); - if( chan != NULL ) (void)Lists_Check(Channel_GetListInvites(chan), target); + if (chan) (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 ) chan = Channel_Search( channame ); - assert( chan != NULL ); + /* Join channel (and create channel if it doesn't exist) */ + if (!Channel_Join(target, channame)) + break; - /* Modes setzen (wenn vorhanden) */ - while( flags && *flags ) - { - Channel_UserModeAdd( chan, target, *flags ); - flags++; - } - - /* 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'; - - /* An andere Server weiterleiten */ - IRC_WriteStrServersPrefix( Client, target, "JOIN :%s%s", channame, modes ); - - /* 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 )); - } + join_set_channelmodes(chan, target, flags); - 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 - } + join_forward(Client, target, chan, channame); - /* 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? */ channame = channame_ptr; @@ -256,29 +286,36 @@ IRC_JOIN( CLIENT *Client, REQUEST *Req ) } /* IRC_JOIN */ +/** + * Handler for the IRC "PART" command. + */ GLOBAL bool -IRC_PART( CLIENT *Client, REQUEST *Req ) +IRC_PART(CLIENT * Client, REQUEST * Req) { CLIENT *target; char *chan; - assert( Client != NULL ); - assert( Req != NULL ); + assert(Client != NULL); + assert(Req != NULL); if (Req->argc < 1 || Req->argc > 2) return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, - Client_ID(Client), Req->command); + 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 ); + /* 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); - /* Channel-Namen durchgehen */ + /* 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)); - + Channel_Part(target, Client, chan, + Req->argc > 1 ? Req->argv[1] : Client_ID(target)); chan = strtok(NULL, ","); } return CONNECTED; diff --git a/src/ngircd/irc-info.c b/src/ngircd/irc-info.c index 4e51d75..a3661f5 100644 --- a/src/ngircd/irc-info.c +++ b/src/ngircd/irc-info.c @@ -1,6 +1,6 @@ /* * 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 * it under the terms of the GNU General Public License as published by @@ -14,8 +14,6 @@ #include "portab.h" -static char UNUSED id[] = "$Id: irc-info.c,v 1.41.2.1 2008/02/26 12:06:57 fw Exp $"; - #include "imp.h" #include #include @@ -25,7 +23,6 @@ static char UNUSED id[] = "$Id: irc-info.c,v 1.41.2.1 2008/02/26 12:06:57 fw Exp #include #include "ngircd.h" -#include "cvs-version.h" #include "conn-func.h" #include "conn-zip.h" #include "client.h" @@ -35,6 +32,7 @@ static char UNUSED id[] = "$Id: irc-info.c,v 1.41.2.1 2008/02/26 12:06:57 fw Exp #include "defines.h" #include "log.h" #include "messages.h" +#include "match.h" #include "tool.h" #include "parse.h" #include "irc-write.h" @@ -84,6 +82,71 @@ IRC_ADMIN(CLIENT *Client, REQUEST *Req ) } /* 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 IRC_ISON( CLIENT *Client, REQUEST *Req ) { @@ -468,6 +531,19 @@ IRC_STATS( CLIENT *Client, REQUEST *Req ) } /* 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 IRC_TIME( CLIENT *Client, REQUEST *Req ) { @@ -545,13 +621,22 @@ IRC_USERHOST( CLIENT *Client, REQUEST *Req ) } /* 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 IRC_VERSION( CLIENT *Client, REQUEST *Req ) { CLIENT *target, *prefix; -#ifdef CVSDATE - char ver[12], vertxt[30]; -#endif assert( Client != NULL ); assert( Req != NULL ); @@ -578,26 +663,110 @@ IRC_VERSION( CLIENT *Client, REQUEST *Req ) 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 */ +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 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; CHANNEL *chan, *cn; CLIENT *c; @@ -605,82 +774,102 @@ IRC_WHO( CLIENT *Client, REQUEST *Req ) 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 ); + if (Req->argc > 2) + return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); 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 - 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 } - 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 */ - if (strchr(Client_Modes( c ), 'a')) - strcpy(flags, "G"); /* away */ - else - 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 */ @@ -1060,55 +1249,6 @@ IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan ) } /* IRC_Send_NAMES */ -GLOBAL bool -IRC_Send_WHO( CLIENT *Client, CHANNEL *Chan, bool OnlyOps ) -{ - 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 ) { - if (strchr(Client_Modes( c ), 'a')) - strcpy(flags, "G"); /* away */ - else - 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 */ - /** * Send the ISUPPORT numeric (005). diff --git a/src/ngircd/irc-info.h b/src/ngircd/irc-info.h index 41e3953..faef75a 100644 --- a/src/ngircd/irc-info.h +++ b/src/ngircd/irc-info.h @@ -8,7 +8,7 @@ * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. * - * $Id: irc-info.h,v 1.4 2007/11/21 12:16:36 alex Exp $ + * $Id: irc-info.h,v 1.6 2008/02/17 13:26:42 alex Exp $ * * IRC info commands (header) */ @@ -19,14 +19,17 @@ 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_LINKS 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_NAMES 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_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_WHO PARAMS(( CLIENT *Client, REQUEST *Req )); GLOBAL bool IRC_WHOIS PARAMS(( CLIENT *Client, REQUEST *Req )); @@ -35,7 +38,6 @@ GLOBAL bool IRC_WHOWAS PARAMS(( CLIENT *Client, REQUEST *Req )); GLOBAL bool IRC_Send_LUSERS PARAMS(( CLIENT *Client )); GLOBAL bool IRC_Send_NAMES PARAMS(( CLIENT *Client, CHANNEL *Chan )); GLOBAL bool IRC_Show_MOTD PARAMS(( CLIENT *Client )); -GLOBAL bool IRC_Send_WHO PARAMS(( CLIENT *Client, CHANNEL *Chan, bool OnlyOps )); GLOBAL bool IRC_Send_ISUPPORT PARAMS(( CLIENT *Client )); diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c index 7c83805..dd43619 100644 --- a/src/ngircd/irc-login.c +++ b/src/ngircd/irc-login.c @@ -1,6 +1,6 @@ /* * 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 * it under the terms of the GNU General Public License as published by @@ -14,8 +14,6 @@ #include "portab.h" -static char UNUSED id[] = "$Id: irc-login.c,v 1.54.2.1 2008/02/05 11:48:37 fw Exp $"; - #include "imp.h" #include #include @@ -35,7 +33,6 @@ static char UNUSED id[] = "$Id: irc-login.c,v 1.54.2.1 2008/02/05 11:48:37 fw Ex #include "irc.h" #include "irc-info.h" #include "irc-write.h" -#include "cvs-version.h" #include "exp.h" #include "irc-login.h" @@ -507,7 +504,7 @@ IRC_PING(CLIENT *Client, REQUEST *Req) Client_ID(from), Client_ID(Client)); #else /* 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", Client_ID(from), Req->argv[0]); #endif @@ -573,61 +570,60 @@ IRC_PONG(CLIENT *Client, REQUEST *Req) 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 ... */ - if( strcmp( Client_Password( Client ), Conf_ServerPwd ) != 0 ) - { + if (strcmp(Client_Password(Client), Conf_ServerPwd) != 0) { /* 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; } - 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 */ - 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 )); - memmove( ver + 4, ver + 5, 2 ); - memmove( 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), * see for details. */ - if (! IRC_Send_ISUPPORT(Client)) + if (!IRC_Send_ISUPPORT(Client)) 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 ... */ - IRC_SetPenalty( Client, 1 ); + IRC_SetPenalty(Client, 1); return CONNECTED; } /* Hello_User */ diff --git a/src/ngircd/irc-mode.c b/src/ngircd/irc-mode.c index af02462..3786e39 100644 --- a/src/ngircd/irc-mode.c +++ b/src/ngircd/irc-mode.c @@ -14,8 +14,6 @@ #include "portab.h" -static char UNUSED id[] = "$Id: irc-mode.c,v 1.50.2.1 2008/02/16 11:26:12 fw Exp $"; - #include "imp.h" #include #include @@ -41,13 +39,10 @@ static char UNUSED id[] = "$Id: irc-mode.c,v 1.50.2.1 2008/02/16 11:26:12 fw Exp 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 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 @@ -243,122 +238,139 @@ client_exit: 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 ) { /* Handle channel and channel-user modes */ 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; CLIENT *client; long l; size_t len; /* 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? */ - if( Client_Type( Client ) == CLIENT_USER ) - { + if (Client_Type(Client) == CLIENT_USER) { /* 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 */ - if( Client_OperByMe( Origin )) { + if (Client_OperByMe(Origin)) { 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_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? */ 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 */ - if( set ) strcpy( the_modes, "+" ); - else strcpy( the_modes, "-" ); + strcpy(the_modes, set ? "+" : "-"); the_args[0] = '\0'; x[1] = '\0'; 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 */ - 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; - 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? */ @@ -368,241 +380,194 @@ Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ) x[0] = '\0'; argadd[0] = '\0'; 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 ); + 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; - - 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++; + } + 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_NEEDMOREPARAMS_MSG, Client_ID( Origin ), Req->command ); + 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; - - case 'P': /* Persistent channel */ + } + if (arg_arg > mode_arg) { 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] ); + 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? */ - if( ! x[0] ) continue; + if (!x[0]) + continue; /* 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; } - if( set ) - { - /* Set mode */ - if( client ) - { - /* Channel-User-Mode */ - if( Channel_UserModeAdd( Channel, client, x[0] )) - { - 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 )); - } + 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, " ", 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_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? */ - if( argadd[0] ) - { - 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: - /* Are there changed modes? */ - if( the_modes[1] ) - { + if (the_modes[1]) { /* Clean up mode string */ - len = strlen( the_modes ) - 1; - if(( the_modes[len] == '+' ) || ( the_modes[len] == '-' )) the_modes[len] = '\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 */ - 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 */ - 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; } /* Channel_Mode */ @@ -635,85 +600,64 @@ IRC_AWAY( CLIENT *Client, REQUEST *Req ) static bool -Add_Invite( 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 ret; assert( Client != NULL ); assert( Channel != NULL ); assert( Pattern != NULL ); + assert(what == 'I' || what == 'b'); - mask = Lists_MakeMask( Pattern ); + mask = Lists_MakeMask(Pattern); - already = Lists_CheckDupeMask(Channel_GetListInvites(Channel), mask ); + 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 ) -{ - char *mask; - bool already; - - assert( Client != NULL ); - assert( Channel != NULL ); - assert( Pattern != NULL ); - - mask = Lists_MakeMask( Pattern ); - - already = Lists_CheckDupeMask(Channel_GetListBans(Channel), mask ); - 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; } - if ( already && ( Client_Type( Prefix ) == CLIENT_SERVER )) + if (already && (Client_Type(Prefix) == CLIENT_SERVER)) 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 -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( Channel != NULL ); assert( Pattern != NULL ); + assert(what == 'I' || what == 'b'); 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 ); -} /* Del_Ban */ +} 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 */ diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c index 3fb8423..86f5852 100644 --- a/src/ngircd/irc.c +++ b/src/ngircd/irc.c @@ -14,7 +14,7 @@ #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 @@ -170,6 +170,7 @@ GLOBAL bool IRC_NOTICE( CLIENT *Client, REQUEST *Req ) { CLIENT *to, *from; + CHANNEL *chan; assert( Client != NULL ); assert( Req != NULL ); @@ -189,7 +190,14 @@ IRC_NOTICE( CLIENT *Client, REQUEST *Req ) /* Okay, Ziel ist ein User */ 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 */ diff --git a/src/ngircd/lists.c b/src/ngircd/lists.c index 6a70d08..94069d4 100644 --- a/src/ngircd/lists.c +++ b/src/ngircd/lists.c @@ -14,8 +14,6 @@ #include "portab.h" -static char UNUSED id[] = "$Id: lists.c,v 1.21 2007/01/29 21:13:26 fw Exp $"; - #include "imp.h" #include @@ -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 * mask is only valid until the next call to Lists_MakeMask(), diff --git a/src/ngircd/lists.h b/src/ngircd/lists.h index 420f775..6458e78 100644 --- a/src/ngircd/lists.h +++ b/src/ngircd/lists.h @@ -8,8 +8,6 @@ * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. * - * $Id: lists.h,v 1.13 2006/12/07 17:57:20 fw Exp $ - * * 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 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 )); #endif diff --git a/src/ngircd/messages.h b/src/ngircd/messages.h index ccf9aa0..4f01ac5 100644 --- a/src/ngircd/messages.h +++ b/src/ngircd/messages.h @@ -8,7 +8,7 @@ * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. * - * $Id: messages.h,v 1.74 2007/12/11 11:29:44 fw Exp $ + * $Id: messages.h,v 1.75 2008/02/17 13:26:42 alex Exp $ * * IRC numerics (Header) */ @@ -77,6 +77,8 @@ #define RPL_BANLIST_MSG "367 %s %s %s" #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_INFO_MSG "371 %s :%s" +#define RPL_ENDOFINFO_MSG "374 %s :End of INFO list" #define RPL_MOTD_MSG "372 %s :- %s" #define RPL_MOTDSTART_MSG "375 %s :- %s message of the day" #define RPL_ENDOFMOTD_MSG "376 %s :End of MOTD command" @@ -100,6 +102,8 @@ #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_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_NOTREGISTEREDSERVER_MSG "451 %s :Connection not registered as server link" #define ERR_NEEDMOREPARAMS_MSG "461 %s %s :Syntax error" diff --git a/src/ngircd/ngircd.c b/src/ngircd/ngircd.c index d2a6d7e..626b8b2 100644 --- a/src/ngircd/ngircd.c +++ b/src/ngircd/ngircd.c @@ -1,6 +1,6 @@ /* * 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 * it under the terms of the GNU General Public License as published by @@ -12,8 +12,6 @@ #include "portab.h" -static char UNUSED id[] = "$Id: ngircd.c,v 1.117 2007/11/21 12:16:36 alex Exp $"; - /** * @file * The main program, including the C function main() which is called @@ -42,7 +40,6 @@ static char UNUSED id[] = "$Id: ngircd.c,v 1.117 2007/11/21 12:16:36 alex Exp $" #include "client.h" #include "channel.h" #include "conf.h" -#include "cvs-version.h" #include "lists.h" #include "log.h" #include "parse.h" @@ -397,7 +394,12 @@ Fill_Version( void ) strlcat( NGIRCd_VersionAddition, "IRCPLUS", sizeof NGIRCd_VersionAddition ); #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] ) strlcat( NGIRCd_VersionAddition, "-", sizeof( NGIRCd_VersionAddition )); @@ -407,12 +409,9 @@ Fill_Version( void ) strlcat( NGIRCd_VersionAddition, "/", 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 */ /** @@ -427,15 +426,16 @@ NGIRCd_Rehash( void ) Log( LOG_NOTICE|LOG_snotice, "Re-reading configuration NOW!" ); NGIRCd_SignalRehash = false; - /* Close down all listening sockets */ - Conn_ExitListeners( ); - /* Remember old server name and nick name length */ strlcpy( old_name, Conf_ServerName, sizeof old_name ); old_nicklen = Conf_MaxNickLength; /* Re-read configuration ... */ - Conf_Rehash( ); + if (!Conf_Rehash( )) + return; + + /* Close down all listening sockets */ + Conn_ExitListeners( ); /* Recover old server name and nick name length: these values can't * be changed during run-time */ @@ -552,7 +552,7 @@ static void Show_Version( void ) { puts( NGIRCd_Version ); - puts( "Copyright (c)2001-2007 Alexander Barton () and Contributors." ); + puts( "Copyright (c)2001-2008 Alexander Barton () and Contributors." ); puts( "Homepage: \n" ); 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." ); diff --git a/src/ngircd/parse.c b/src/ngircd/parse.c index f77d5b0..5cfeaaa 100644 --- a/src/ngircd/parse.c +++ b/src/ngircd/parse.c @@ -12,7 +12,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: parse.c,v 1.69.2.1 2008/02/05 13:11:20 fw Exp $"; +static char UNUSED id[] = "$Id: parse.c,v 1.72 2008/02/17 13:26:42 alex Exp $"; /** * @file @@ -52,8 +52,13 @@ static char UNUSED id[] = "$Id: parse.c,v 1.69.2.1 2008/02/05 13:11:20 fw Exp $" #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 }, { "AWAY", IRC_AWAY, CLIENT_USER, 0, 0, 0 }, @@ -62,6 +67,7 @@ COMMAND My_Commands[] = { "DISCONNECT", IRC_DISCONNECT, CLIENT_USER, 0, 0, 0 }, { "ERROR", IRC_ERROR, 0xFFFF, 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 }, { "ISON", IRC_ISON, CLIENT_USER, 0, 0, 0 }, { "JOIN", IRC_JOIN, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, @@ -88,11 +94,13 @@ COMMAND My_Commands[] = { "SERVER", IRC_SERVER, 0xFFFF, 0, 0, 0 }, { "SQUIT", IRC_SQUIT, 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 }, { "TOPIC", IRC_TOPIC, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "TRACE", IRC_TRACE, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "USER", IRC_USER, 0xFFFF, 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 }, { "WALLOPS", IRC_WALLOPS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "WHO", IRC_WHO, CLIENT_USER, 0, 0, 0 }, @@ -104,14 +112,6 @@ COMMAND My_Commands[] = { NULL, NULL, 0x0, 0, 0, 0 } /* Ende-Marke */ }; -NUMERIC My_Numerics[] = -{ - { 005, IRC_Num_ISUPPORT }, - { 376, IRC_Num_ENDOFMOTD }, - { 0, NULL } /* end marker */ -}; - - static void Init_Request PARAMS(( REQUEST *Req )); static bool Validate_Prefix PARAMS(( CONN_ID Idx, REQUEST *Req, bool *Closed )); @@ -120,6 +120,7 @@ static bool Validate_Args PARAMS(( CONN_ID Idx, REQUEST *Req, bool *Closed )); 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". @@ -347,18 +348,84 @@ Validate_Args( UNUSED CONN_ID Idx, UNUSED REQUEST *Req, bool *Closed ) } /* 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 Handle_Request( CONN_ID Idx, REQUEST *Req ) { /* Client-Request verarbeiten. Bei einem schwerwiegenden Fehler * 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; - NUMERIC *num; - int i, client_type; assert( Idx >= 0 ); assert( Req != NULL ); @@ -368,110 +435,43 @@ Handle_Request( CONN_ID Idx, REQUEST *Req ) assert( client != NULL ); /* Numeric? */ - if ((Client_Type(client) == CLIENT_SERVER || - Client_Type(client) == CLIENT_UNKNOWNSERVER) - && strlen(Req->command) == 3 && atoi(Req->command) > 1) { - /* Command is a status code ("numeric") from an other server */ - - /* Determine target */ - if (Req->argc > 0) - target = Client_Search( Req->argv[0] ); - else - target = NULL; - if (!target) { - /* 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 */ - i = atoi(Req->command); - - num = My_Numerics; - while (num->numeric > 0) { - if (i != num->numeric) { - num++; - continue; - } - result = (num->function)(client, Req); - return result; - } - - LogDebug("Ignored status code %s from \"%s\".", - Req->command, Client_ID(client)); - return true; - } - - /* 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 ); - } + 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; - client_type = Client_Type(client); - while( cmd->name ) - { + while (cmd->name) { /* Befehl suchen */ - if( strcasecmp( Req->command, cmd->name ) != 0 ) - { - cmd++; continue; + if (strcasecmp(Req->command, cmd->name) != 0) { + cmd++; + continue; } - if( client_type & 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_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 - { - /* 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; - + /* 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, Req->argc == 1 ? "parameter" : "parameters", Req->prefix ? "" : " no" ); @@ -480,10 +480,8 @@ Handle_Request( CONN_ID Idx, REQUEST *Req ) result = IRC_WriteStrClient(client, ERR_UNKNOWNCOMMAND_MSG, Client_ID(client), Req->command); Conn_SetPenalty(Idx, 1); - return result; } - - return true; + return result; } /* Handle_Request */ diff --git a/src/ngircd/parse.h b/src/ngircd/parse.h index e7a0087..a3f764e 100644 --- a/src/ngircd/parse.h +++ b/src/ngircd/parse.h @@ -8,7 +8,7 @@ * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. * - * $Id: parse.h,v 1.12 2007/11/21 12:16:36 alex Exp $ + * $Id: parse.h,v 1.13 2008/01/13 16:12:49 fw Exp $ * * IRC command parser and validator (header) */ @@ -38,18 +38,10 @@ typedef struct _COMMAND } COMMAND; -typedef struct _NUMERIC -{ - int numeric; /* numeric */ - bool (*function) PARAMS(( CLIENT *Client, REQUEST *Request )); -} NUMERIC; - - GLOBAL bool Parse_Request PARAMS((CONN_ID Idx, char *Request )); GLOBAL COMMAND *Parse_GetCommandStruct PARAMS(( void )); - #endif diff --git a/src/ngircd/resolve.c b/src/ngircd/resolve.c index 1bd7e29..041c156 100644 --- a/src/ngircd/resolve.c +++ b/src/ngircd/resolve.c @@ -14,7 +14,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: resolve.c,v 1.28 2008/01/02 11:03:29 fw Exp $"; +static char UNUSED id[] = "$Id: resolve.c,v 1.29 2008/02/26 22:04:17 fw Exp $"; #include "imp.h" #include @@ -35,19 +35,19 @@ static char UNUSED id[] = "$Id: resolve.c,v 1.28 2008/01/02 11:03:29 fw Exp $"; #include "conn.h" #include "defines.h" #include "log.h" -#include "tool.h" #include "exp.h" #include "resolve.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 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 static pid_t @@ -82,7 +82,7 @@ Resolver_fork(int *pipefds) * Resolve IP (asynchronous!). */ 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)) { int pipefd[2]; @@ -92,9 +92,8 @@ Resolve_Addr(RES_STAT * s, struct sockaddr_in *Addr, int identsock, pid = Resolver_fork(pipefd); 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->resolver_fd = pipefd[0]; 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[CLIENT_HOST_LEN]; - char ipstr[CLIENT_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 char *res; + + assert(identsock >= 0); + +#ifdef DEBUG + Log_Resolver(LOG_DEBUG, "Doing IDENT lookup on socket %d ...", identsock); #endif - array_init(&resolved_addr); - /* Resolve IP address */ + if (identsock < 0) + return; + res = ident_id( identsock, 10 ); #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 - h = gethostbyaddr( (char *)&Addr->sin_addr, sizeof( Addr->sin_addr ), AF_INET ); - if (!h || strlen(h->h_name) >= sizeof(hostname)) { -#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 - 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 { - 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 - 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 - 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 - (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 - 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 -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; + 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 { -#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 - 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 - /* 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 + /* Write result into pipe to parent */ + ArrayWrite(w_fd, &IpAddrs); + + array_free(&IpAddrs); +} /* Do_ResolveName */ static bool diff --git a/src/ngircd/resolve.h b/src/ngircd/resolve.h index ad8ebad..9fd16be 100644 --- a/src/ngircd/resolve.h +++ b/src/ngircd/resolve.h @@ -8,7 +8,7 @@ * (at your option) any later version. * 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) */ @@ -18,6 +18,8 @@ #define __resolve_h__ #include "array.h" +#include "tool.h" +#include "ng_ipaddr.h" #include /* This struct must not be accessed directly */ @@ -30,7 +32,7 @@ typedef struct _Res_Stat { #define Resolve_Getfd(x) ((x)->resolver_fd) #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 size_t Resolve_Read PARAMS(( RES_STAT *s, void *buf, size_t buflen)); GLOBAL void Resolve_Init PARAMS(( RES_STAT *s)); diff --git a/src/portab/.cvsignore b/src/portab/.cvsignore deleted file mode 100644 index 14b48af..0000000 --- a/src/portab/.cvsignore +++ /dev/null @@ -1,4 +0,0 @@ -Makefile -Makefile.in -.deps -portabtest diff --git a/src/portab/.gitignore b/src/portab/.gitignore new file mode 100644 index 0000000..839a69f --- /dev/null +++ b/src/portab/.gitignore @@ -0,0 +1 @@ +portabtest diff --git a/src/testsuite/.cvsignore b/src/testsuite/.cvsignore deleted file mode 100644 index 312c190..0000000 --- a/src/testsuite/.cvsignore +++ /dev/null @@ -1,7 +0,0 @@ -Makefile -Makefile.in -T-ngircd -logs -ngircd-test.log -ngircd-test.motd -tests diff --git a/src/testsuite/.gitignore b/src/testsuite/.gitignore new file mode 100644 index 0000000..611b082 --- /dev/null +++ b/src/testsuite/.gitignore @@ -0,0 +1,10 @@ +T-ngircd +channel-test +connect-test +misc-test +mode-test +who-test +ngircd-test.log +ngircd-test.motd +logs +tests diff --git a/src/testsuite/Makefile.am b/src/testsuite/Makefile.am index d02e4e1..6512aaa 100644 --- a/src/testsuite/Makefile.am +++ b/src/testsuite/Makefile.am @@ -9,7 +9,7 @@ # Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste # der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS. # -# $Id: Makefile.am,v 1.15 2007/11/18 15:07:16 alex Exp $ +# $Id: Makefile.am,v 1.18 2008/02/17 13:26:42 alex Exp $ # AUTOMAKE_OPTIONS = ../portab/ansi2knr @@ -20,8 +20,8 @@ EXTRA_DIST = \ README functions.inc getpid.sh \ start-server.sh stop-server.sh tests.sh stress-server.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 all: @@ -47,6 +47,14 @@ channel-test: tests.sh rm -f 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 rm -f mode-test ln -s $(srcdir)/tests.sh mode-test @@ -54,7 +62,9 @@ mode-test: tests.sh TESTS = start-server.sh \ connect-test \ channel-test \ + misc-test \ mode-test \ + who-test \ stress-server.sh \ stop-server.sh diff --git a/src/testsuite/channel-test.e b/src/testsuite/channel-test.e index 240abf6..16c67ad 100644 --- a/src/testsuite/channel-test.e +++ b/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 expect { @@ -69,6 +69,36 @@ expect { "@* 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" expect { timeout { exit 1 } diff --git a/src/testsuite/misc-test.e b/src/testsuite/misc-test.e new file mode 100644 index 0000000..4b88379 --- /dev/null +++ b/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- diff --git a/src/testsuite/mode-test.e b/src/testsuite/mode-test.e index 8aa4925..260cd03 100644 --- a/src/testsuite/mode-test.e +++ b/src/testsuite/mode-test.e @@ -1,4 +1,4 @@ -# $Id: mode-test.e,v 1.6.8.1 2008/02/16 11:26:13 fw Exp $ +# $Id: mode-test.e,v 1.7 2008/02/16 11:27:49 fw Exp $ spawn telnet localhost 6789 expect { diff --git a/src/testsuite/ngircd-test.conf b/src/testsuite/ngircd-test.conf index 3f0ffe9..0bec96d 100644 --- a/src/testsuite/ngircd-test.conf +++ b/src/testsuite/ngircd-test.conf @@ -1,4 +1,4 @@ -# $Id: ngircd-test.conf,v 1.5 2007/11/18 15:07:16 alex Exp $ +# $Id: ngircd-test.conf,v 1.6 2008/02/17 00:00:13 fw Exp $ [Global] Name = ngircd.test.server @@ -7,8 +7,7 @@ MotdFile = ngircd-test.motd AdminEMail = admin@irc.server MaxConnectionsIP = 0 - ServerUID = 1 - ServerGID = 1 + OperCanUseMode = yes [Operator] Name = TestOp diff --git a/src/testsuite/who-test.e b/src/testsuite/who-test.e new file mode 100644 index 0000000..c54a190 --- /dev/null +++ b/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- diff --git a/src/tool/.cvsignore b/src/tool/.cvsignore deleted file mode 100644 index 051d1bd..0000000 --- a/src/tool/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -Makefile -Makefile.in -.deps diff --git a/src/tool/tool.c b/src/tool/tool.c index 52d7be8..1e72377 100644 --- a/src/tool/tool.c +++ b/src/tool/tool.c @@ -14,7 +14,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: tool.c,v 1.8 2007/11/25 18:42:38 fw Exp $"; +static char UNUSED id[] = "$Id: tool.c,v 1.9 2008/02/26 22:04:18 fw Exp $"; #include "imp.h" #include @@ -106,23 +106,4 @@ ngt_TrimLastChr( char *String, const char Chr) if( String[len] == Chr ) String[len] = '\0'; } /* ngt_TrimLastChr */ - -GLOBAL bool -ngt_IPStrToBin(const char *ip_str, struct in_addr *inaddr) -{ - /* AF is always AF_INET for now */ -#ifdef HAVE_INET_ATON - if (inet_aton(ip_str, inaddr) == 0) - return false; -#else - inaddr->s_addr = inet_addr(ip_str); - if (inaddr->s_addr == (unsigned)-1) - return false; -#endif - return true; -} - - - - /* -eof- */ diff --git a/src/tool/tool.h b/src/tool/tool.h index 7ce3e2c..9bb7983 100644 --- a/src/tool/tool.h +++ b/src/tool/tool.h @@ -8,7 +8,7 @@ * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. * - * $Id: tool.h,v 1.5 2007/11/25 18:42:38 fw Exp $ + * $Id: tool.h,v 1.6 2008/02/26 22:04:18 fw Exp $ * * Tool functions (Header) */ @@ -29,8 +29,6 @@ GLOBAL void ngt_TrimLastChr PARAMS((char *String, const char Chr )); GLOBAL void ngt_TrimStr PARAMS((char *String )); GLOBAL char *ngt_LowerStr PARAMS((char *String )); - -GLOBAL bool ngt_IPStrToBin PARAMS((const char *ip_str, struct in_addr *inaddr)); #endif