ngIRCd: Patch ngIRCd 0.11.1 to version 0.12.0-pre1. Alexander Barton (25): Remove entry about ngircd failing on Linux 2.4: Document NoDNS configuration option. Updated Debian changelog [from 0.10.x; 0.11.x] Updated ChangeLog to reflect changes in 0.10.x and 0.11.x branches. Updated NEWS to reflect ChangeLog. Implemented IRC commands INFO, USERS (dummy), and SUMMON (dummy). Removed the SQUIT test for now, actually we don't support it yet. Added new test files to Xcode project. Install a LaunchDaemon script to start/stop ngIRCd on Mac OS X. LaunchDaemon plist for Mac OS X/Darwin launchd. Updated ChangeLog to include 0.11.1. Fix #include's: search log.h locally, include string.h. Moved .cvsignore files to .gitignore Include Mac OS X Xcode project in distribution archives. Include Mac OS X Xcode project in distribution archives. (Part 2) Added "portabtest" binary to .gitignore file in src/portabtest/. Updated Xcode project file. GIT should ignore user preferences files inside Xcode projects. Enable more compiler warnings when using Xcode. Fixed "xcode" make target (used to build ngIRCd with Mac OS X Xcode) Added make target "testsuite" Updated copyright notice to read "2001-2008". Updated NEWS and ChangeLog for upcoming 0.12.0-pre1 release. ngIRCd 0.12.0-pre1 Don't include doc/CVS.txt in distribution archive, use doc/GIT.txt now! Dana Dahlstrom (4): Implement RFC 2812 handling of "0" argument to JOIN Remove duplicate Channel_FirstChannelOf(). Don't send trailing space in MODE messages Include flags in RPL_WHOREPLY messages. Florian Westphal (25): IRC_PART could reference invalid memory. [Parser]: Fix minor sparse warnings This adds support for sending NOTICEs to a channel. Fix wrong strncpy usage if CVSDATE defined Don't use Client_Type after command has been processed. Updated NEWS to reflect ChangeLog. Make Channel_Part name and reason parameters 'const'. Make IRC_WHO also search username/servername/hostname. IRC_JOIN cleanups. Channel_Mode cleanups IPv6 support. Do not exit unconditionally if config file cannot be opened io.c: try to cut down the number of ifdefs. io.c: fix select FD_SETSIZE check when using epoll as io backend io.c: kill select FD_SETSIZE sanity check in io_library_init. Fix client.c sparse warnings. Convert CVS commands to their git equivalents. Channel_Mode: Unify Add_Invite and Add_Ban handler Constify Lists_MakeMask argument and return type. Channel_Mode: Unify Del_Invite and Del_Ban handler Channel_Mode: unify 'b' and 'I' switch/case handling. Channel_Mode: check return type of Invite/Ban Add/Del function Channel_Mode: Re-indent switch. Channel_Mode: change order of if (set) and if (client) check. Channel_Mode: Remove duplicate code. Rolf Eike Beer (1): Fix sending of JOINs between servers. .cvsignore | 7 - .gitignore | 17 + ChangeLog | 31 +- Makefile.am | 12 +- NEWS | 16 +- configure.in | 22 +- contrib/.cvsignore | 2 - contrib/Debian/.cvsignore | 2 - contrib/Debian/changelog | 12 +- 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 | 2 +- doc/src/.cvsignore | 3 - doc/src/.gitignore | 1 + man/.cvsignore | 4 - man/.gitignore | 2 + src/.cvsignore | 5 - src/.gitignore | 3 + src/Makefile.am | 4 +- src/ipaddr/Makefile.am | 14 + src/ipaddr/ng_ipaddr.c | 170 +++++ src/ipaddr/ng_ipaddr.h | 115 +++ src/ngircd/.cvsignore | 8 - src/ngircd/.gitignore | 5 + src/ngircd/Makefile.am | 8 +- src/ngircd/channel.c | 86 ++- src/ngircd/channel.h | 9 +- src/ngircd/client.c | 6 +- src/ngircd/conf.c | 30 +- src/ngircd/conf.h | 15 +- src/ngircd/conn-func.c | 5 +- src/ngircd/conn.c | 294 +++++--- src/ngircd/conn.h | 6 +- src/ngircd/io.c | 913 +++++++++++------------ src/ngircd/irc-channel.c | 328 +++++---- src/ngircd/irc-info.c | 378 +++++++--- src/ngircd/irc-info.h | 6 +- src/ngircd/irc-login.c | 2 +- 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 | 20 +- src/ngircd/parse.c | 220 +++--- src/ngircd/parse.h | 10 +- src/ngircd/resolve.c | 414 +++++++--- 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 | 3 +- src/testsuite/who-test.e | 162 ++++ src/tool/.cvsignore | 3 - src/tool/tool.c | 21 +- src/tool/tool.h | 4 +- 73 files changed, 2712 insertions(+), 1724 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..8457e8d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,13 +10,32 @@ -- ChangeLog -- +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) @@ -742,4 +761,4 @@ ngIRCd 0.0.1, 31.12.2001 -- -$Id: ChangeLog,v 1.332.2.10 2008/02/26 19:22:06 alex Exp $ +$Id: ChangeLog,v 1.345 2008/03/18 20:12:47 fw 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..7c98a72 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,20 @@ -- NEWS -- +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 +265,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/configure.in b/configure.in index c4d9546..cf5fc85 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-pre1) 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..880a509 100644 --- a/contrib/Debian/changelog +++ b/contrib/Debian/changelog @@ -1,14 +1,8 @@ -ngircd (0.11.1-0ab1) unstable; urgency=low +ngircd (0.12.0-0ab0-pre1) unstable; urgency=low - * New "upstream" release 0.11.1. + * Prereloease of upcoming new "upstrem" release 0.12.0-pre1. - -- Alexander Barton Tue, 26 Feb 2008 20:24:55 +0100 - -ngircd (0.11.0-0ab1) unstable; urgency=low - - * New "upstream" release 0.11.0. - - -- Alexander Barton Tue, 15 Jan 2008 21:43:46 +0100 + -- 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..315ff3b 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-pre1 %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..13014d3 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 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/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..bbfb5a7 --- /dev/null +++ b/src/ipaddr/ng_ipaddr.c @@ -0,0 +1,170 @@ +/* + * 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 + +#include + +#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..1e198b0 --- /dev/null +++ b/src/ipaddr/ng_ipaddr.h @@ -0,0 +1,115 @@ +/* + * Functions for AF_ agnostic ipv4/ipv6 handling. + * + * (c) 2008 Florian Westphal , public domain. + */ + +#ifndef NG_IPADDR_HDR +#define NG_IPADDR_HDR +#include "portab.h" + +#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/.cvsignore deleted file mode 100644 index 9407c0b..0000000 --- a/src/ngircd/.cvsignore +++ /dev/null @@ -1,8 +0,0 @@ -Makefile -Makefile.in -.deps -check-help -check-version -cvs-version.h -cvs-version.new -ngircd diff --git a/src/ngircd/.gitignore b/src/ngircd/.gitignore new file mode 100644 index 0000000..e02dd40 --- /dev/null +++ b/src/ngircd/.gitignore @@ -0,0 +1,5 @@ +check-help +check-version +cvs-version.h +cvs-version.new +ngircd diff --git a/src/ngircd/Makefile.am b/src/ngircd/Makefile.am index 46513a8..cfa45e1 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 \ diff --git a/src/ngircd/channel.c b/src/ngircd/channel.c index 3341cb4..35922c2 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 )); @@ -202,7 +202,7 @@ Channel_Join( CLIENT *Client, char *Name ) 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; @@ -388,7 +388,7 @@ Channel_Next( CHANNEL *Chan ) GLOBAL CHANNEL * -Channel_Search( char *Name ) +Channel_Search( const char *Name ) { /* Channel-Struktur suchen */ @@ -695,38 +695,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 +829,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 +903,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..0f66862 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,21 +134,21 @@ 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 */ @@ -163,9 +163,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 @@ -460,8 +459,8 @@ Set_Defaults( bool InitServers ) } /* Set_Defaults */ -static void -Read_Config( void ) +static bool +Read_Config( bool ngircd_starting ) { /* Read configuration file. */ @@ -476,10 +475,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 +629,7 @@ Read_Config( void ) exit( 1 ); } } + return true; } /* Read_Config */ @@ -938,7 +942,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\"", @@ -1213,7 +1217,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..d505f33 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,12 @@ GLOBAL bool Conf_OperCanMode; /* Disable all DNS functions? */ GLOBAL bool Conf_NoDNS; +/* don't listen for incoming ipv6 connections, even if OS supports it? */ +GLOBAL bool Conf_NoListenIpv6; + +/* don't connect to remote systems unsign ipv6? */ +GLOBAL bool Conf_NoConnectIpv6; + /* 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 +148,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..9e31e4e 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,18 @@ 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_NoListenIpv6) + created = ports_initlisteners(&Conf_ListenPorts, AF_INET6, cb_listen); +#endif + created += ports_initlisteners(&Conf_ListenPorts, AF_INET, cb_listen); return created; } /* Conn_InitListeners */ @@ -327,68 +348,75 @@ 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; +#if defined(IPV6_V6ONLY) && defined(WANT_IPV6) + int on = 1; - InitSinaddr(addr, Port); - - 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; } + af = ng_ipaddr_af(&addr); + + set_v6_only(af, sock); + if( ! Init_Socket( sock )) return -1; - if (bind(sock, (struct sockaddr *)&addr, (socklen_t)sizeof(addr)) != 0) { + if (bind(sock, (struct sockaddr *)&addr, ng_ipaddr_salen(&addr)) != 0) { Log( LOG_CRIT, "Can't bind socket (port %d) : %s!", Port, strerror( errno )); close( sock ); return -1; @@ -407,8 +435,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 +741,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 +769,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 +811,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 +840,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 +848,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 +972,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 +996,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 +1013,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 +1034,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 +1081,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 +1095,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 +1158,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 +1418,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; + } - new_sock = socket( PF_INET, SOCK_STREAM, 0 ); - if ( new_sock < 0 ) { + Log( LOG_INFO, "Establishing connection to \"%s\", %s, port %d ... ", + Conf_Server[Server].host, ip_str, Conf_Server[Server].port ); + + 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 +1476,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 +1490,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 +1569,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 +1588,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 +1708,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..5577057 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; diff --git a/src/ngircd/irc-info.c b/src/ngircd/irc-info.c index 4e51d75..87ed2ad 100644 --- a/src/ngircd/irc-info.c +++ b/src/ngircd/irc-info.c @@ -14,7 +14,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: irc-info.c,v 1.41.2.1 2008/02/26 12:06:57 fw Exp $"; +static char UNUSED id[] = "$Id: irc-info.c,v 1.44 2008/02/17 13:26:42 alex Exp $"; #include "imp.h" #include @@ -35,6 +35,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 +85,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 +534,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,6 +624,18 @@ 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 ) { @@ -592,12 +683,102 @@ IRC_VERSION( CLIENT *Client, REQUEST *Req ) } /* 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 CONNECTED; + + 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 +786,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 +1261,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..1f7038e 100644 --- a/src/ngircd/irc-login.c +++ b/src/ngircd/irc-login.c @@ -14,7 +14,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: irc-login.c,v 1.54.2.1 2008/02/05 11:48:37 fw Exp $"; +static char UNUSED id[] = "$Id: irc-login.c,v 1.55 2008/02/05 11:46:55 fw Exp $"; #include "imp.h" #include 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..5b872fc 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 @@ -397,7 +395,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 )); @@ -427,15 +430,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 +556,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..a128694 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,20 +35,16 @@ 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 )); -#endif static pid_t Resolver_fork(int *pipefds) @@ -82,7 +78,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 +88,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 +142,331 @@ 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 const 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 + }; + 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..5b1fbe3 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 @@ -9,6 +9,7 @@ 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