diff options
405 files changed, 12780 insertions, 18408 deletions
diff --git a/.gitignore b/.gitignore index 3a5fef871..244c938a5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *~ +*.pem *.swp /.config.cache @@ -11,8 +12,7 @@ /run /bin -/include/inspircd_config.h -/include/inspircd_version.h +/include/config.h /src/modules/m_geoip.cpp /src/modules/m_ldapauth.cpp @@ -22,6 +22,7 @@ /src/modules/m_pgsql.cpp /src/modules/m_regex_pcre.cpp /src/modules/m_regex_posix.cpp +/src/modules/m_regex_re2.cpp /src/modules/m_regex_stdlib.cpp /src/modules/m_regex_tre.cpp /src/modules/m_sqlite3.cpp @@ -33,35 +33,17 @@ BEGIN { use strict; use warnings FATAL => qw(all); -use Data::Dumper; -BEGIN { - $Data::Dumper::Sortkeys = 1; - $Data::Dumper::Useqq = 1; -}; - use File::Copy (); -use Socket; +use File::Spec::Functions qw(rel2abs); use Cwd; use Getopt::Long; -# Utility functions for our buildsystem -use make::utilities; use make::configure; -use make::gnutlscert; -use make::opensslcert; - -############################################################################################### -# -# NON-EDITABLE VARIABLES -# -############################################################################################### - -our ($opt_use_gnutls, $opt_rebuild, $opt_use_openssl, $opt_nointeractive, $opt_ports, - $opt_epoll, $opt_kqueue, $opt_noports, $opt_noepoll, $opt_nokqueue, - $opt_noipv6, $opt_maxbuf, $opt_disable_debug, $opt_freebsd_port, - $opt_system, $opt_uid); +use make::utilities; -our ($opt_cc, $opt_base_dir, $opt_config_dir, $opt_module_dir, $opt_binary_dir, $opt_data_dir, $opt_log_dir); +our ($opt_use_gnutls, $opt_use_openssl, $opt_nointeractive, $opt_socketengine, + $opt_system, $opt_uid, $opt_base_dir, $opt_config_dir, $opt_module_dir, $opt_binary_dir, + $opt_data_dir, $opt_log_dir); sub list_extras (); @@ -74,36 +56,23 @@ my @opt_disableextras; GetOptions ( 'enable-gnutls' => \$opt_use_gnutls, - 'rebuild' => \$opt_rebuild, 'system' => \$opt_system, 'uid=s' => \$opt_uid, 'enable-openssl' => \$opt_use_openssl, 'disable-interactive' => \$opt_nointeractive, - 'enable-ports' => \$opt_ports, - 'enable-epoll' => \$opt_epoll, - 'enable-kqueue' => \$opt_kqueue, - 'disable-ports' => \$opt_noports, - 'disable-epoll' => \$opt_noepoll, - 'disable-kqueue' => \$opt_nokqueue, - 'disable-ipv6' => \$opt_noipv6, - 'with-cc=s' => \$opt_cc, - 'with-maxbuf=i' => \$opt_maxbuf, - 'enable-freebsd-ports-openssl' => \$opt_freebsd_port, + 'socketengine=s' => \$opt_socketengine, 'prefix=s' => \$opt_base_dir, 'config-dir=s' => \$opt_config_dir, 'module-dir=s' => \$opt_module_dir, 'binary-dir=s' => \$opt_binary_dir, 'data-dir=s' => \$opt_data_dir, 'log-dir=s' => \$opt_log_dir, - 'disable-debuginfo' => sub { $opt_disable_debug = 1 }, - 'help' => sub { showhelp(); }, - 'update' => sub { update(); }, - 'clean' => sub { clean(); }, + 'help' => \&cmd_help, + 'update' => \&cmd_update, + 'clean' => \&cmd_clean, 'list-extras' => sub { list_extras; exit 0; }, # This, --enable-extras, and --disable-extras are for non-interactive managing. 'enable-extras=s@' => \@opt_enableextras, # ^ 'disable-extras=s@' => \@opt_disableextras, # ^ - 'generate-openssl-cert' => sub { make_openssl_cert(); exit(0); }, - 'generate-gnutls-cert' => sub { make_gnutls_cert(); exit(0); } ); if (scalar(@opt_enableextras) + scalar(@opt_disableextras) > 0) { @@ -125,30 +94,20 @@ our $interactive = !( (defined $opt_data_dir) || (defined $opt_log_dir) || (defined $opt_nointeractive) || - (defined $opt_cc) || - (defined $opt_noipv6) || - (defined $opt_kqueue) || - (defined $opt_epoll) || - (defined $opt_ports) || + (defined $opt_socketengine) || (defined $opt_use_openssl) || - (defined $opt_nokqueue) || - (defined $opt_noepoll) || - (defined $opt_noports) || - (defined $opt_maxbuf) || (defined $opt_system) || (defined $opt_uid) || - (defined $opt_use_gnutls) || - (defined $opt_freebsd_port) + (defined $opt_use_gnutls) ); -chomp(our $topdir = getcwd()); -our $this = resolve_directory($topdir); # PWD, Regardless. -our @modlist = (); # Declare for Module List.. -our %config = (); # Initiate Configuration Hash.. -our $cache_loaded = getcache(); -$config{ME} = resolve_directory($topdir); # Present Working Directory +our $topdir = getcwd(); +our %config = read_configure_cache(); + +print "Checking for cache from previous configure... "; +print %config ? "found\n" : "not found\n"; -$config{BASE_DIR} = $config{ME}."/run"; +$config{BASE_DIR} = $topdir."/run"; if (defined $opt_base_dir) { $config{BASE_DIR} = $opt_base_dir; @@ -158,20 +117,20 @@ if (defined $opt_base_dir) { if (defined $opt_system) { $config{UID} = $opt_uid || 'ircd'; - $config{CONFIG_DIR} = '/etc/inspircd'; - $config{MODULE_DIR} = '/usr/lib/inspircd'; - $config{BINARY_DIR} = '/usr/sbin/'; - $config{BUILD_DIR} = resolve_directory($config{ME}."/build"); # Build Directory - $config{DATA_DIR} = '/var/inspircd'; - $config{LOG_DIR} = '/var/log/inspircd'; + $config{CONFIG_DIR} = '/etc/inspircd'; + $config{MODULE_DIR} = '/usr/lib/inspircd'; + $config{BINARY_DIR} = '/usr/sbin/'; + $config{BUILD_DIR} = $topdir."/build"; + $config{DATA_DIR} = '/var/inspircd'; + $config{LOG_DIR} = '/var/log/inspircd'; } else { $config{UID} = $opt_uid || $<; - $config{CONFIG_DIR} = resolve_directory($config{BASE_DIR}."/conf"); # Configuration Directory - $config{MODULE_DIR} = resolve_directory($config{BASE_DIR}."/modules"); # Modules Directory - $config{BINARY_DIR} = resolve_directory($config{BASE_DIR}."/bin"); # Binary Directory - $config{BUILD_DIR} = resolve_directory($config{ME}."/build"); # Build Directory - $config{DATA_DIR} = resolve_directory($config{BASE_DIR}."/data"); # Data directory - $config{LOG_DIR} = resolve_directory($config{BASE_DIR}."/logs"); # Log directory + $config{CONFIG_DIR} = rel2abs($config{BASE_DIR}."/conf"); + $config{MODULE_DIR} = rel2abs($config{BASE_DIR}."/modules"); + $config{BINARY_DIR} = rel2abs($config{BASE_DIR}."/bin"); + $config{BUILD_DIR} = rel2abs($topdir."/build"); + $config{DATA_DIR} = rel2abs($config{BASE_DIR}."/data"); + $config{LOG_DIR} = rel2abs($config{BASE_DIR}."/logs"); } if (defined $opt_config_dir) { @@ -189,89 +148,37 @@ if (defined $opt_data_dir) { if (defined $opt_log_dir) { $config{LOG_DIR} = $opt_log_dir; } -chomp($config{HAS_GNUTLS} = `pkg-config --modversion gnutls 2>/dev/null`); # GNUTLS Version. - -if (defined $opt_freebsd_port) -{ - chomp($config{HAS_OPENSSL} = `pkg-config --modversion openssl 2>/dev/null`); - chomp($config{HAS_OPENSSL_PORT} = `pkg-config --modversion openssl 2>/dev/null`); - $config{USE_FREEBSD_BASE_SSL} = "n"; -} -else -{ - if ($^O eq "freebsd") - { - # default: use base ssl - chomp($config{HAS_OPENSSL} = `openssl version | cut -d ' ' -f 2`); # OpenSSL version, freebsd specific - chomp($config{HAS_OPENSSL_PORT} = `pkg-config --modversion openssl 2>/dev/null`); # Port version, may be different - } - else - { - chomp($config{HAS_OPENSSL} = `pkg-config --modversion openssl 2>/dev/null`); # Openssl version, others - $config{HAS_OPENSSL_PORT} = ""; - } -} +chomp($config{HAS_GNUTLS} = `pkg-config --modversion gnutls 2>/dev/null`); +chomp($config{HAS_OPENSSL} = `pkg-config --modversion openssl 2>/dev/null`); chomp(our $gnutls_ver = $config{HAS_GNUTLS}); chomp(our $openssl_ver = $config{HAS_OPENSSL}); -$config{USE_GNUTLS} = "n"; +$config{USE_GNUTLS} = 0; if (defined $opt_use_gnutls) { $config{USE_GNUTLS} = "y"; # Use gnutls. } -$config{USE_OPENSSL} = "n"; # Use openssl. +$config{USE_OPENSSL} = 0; # Use openssl. if (defined $opt_use_openssl) { $config{USE_OPENSSL} = "y"; } -if (!defined $opt_disable_debug) { - $config{OPTIMISATI} = "-g1"; # Optimisation Flag -} else { - $config{OPTIMISATI} = "-O2"; -} +$config{STARTSCRIPT} = $^O eq 'darwin' ? 'org.inspircd.plist' : 'inspircd'; -$config{HAS_STRLCPY} = "false"; # strlcpy Check. -$config{HAS_STDINT} = "false"; # stdint.h check -$config{USE_KQUEUE} = "y"; # kqueue enabled -if (defined $opt_nokqueue) { - $config{USE_KQUEUE} = "n"; -} -$config{USE_POLL} = "y"; # poll enabled -$config{USE_EPOLL} = "y"; # epoll enabled -if (defined $opt_noepoll) -{ - $config{USE_EPOLL} = "n"; +$config{CXX} = defined $ENV{CXX} && !system("$ENV{CXX} -v > /dev/null 2>&1") ? $ENV{CXX} : find_compiler(); +if ($config{CXX} eq "") { + print "A C++ compiler could not be detected on your system!\n"; + print "Set the CXX environment variable to the full path if this is incorrect.\n"; + exit 1; } -$config{USE_PORTS} = "y"; # epoll enabled -if (defined $opt_noports) -{ - $config{USE_PORTS} = "n"; -} -$config{_SOMAXCONN} = SOMAXCONN; # Max connections in accept queue -$config{OSNAME} = $^O; # Operating System Name -$config{IS_DARWIN} = "NO"; # Is OSX? -$config{STARTSCRIPT} = "inspircd"; # start script? -$config{DESTINATION} = "BASE"; # Is target path. -if ($config{OSNAME} =~ /darwin/i) -{ - $config{IS_DARWIN} = "YES"; - $config{STARTSCRIPT} = "org.inspircd.plist"; # start script for OSX. - $config{CC} = "xcrun clang++"; # C++ compiler for OSX. -} -else -{ - $config{CC} = "g++"; # C++ compiler -} -if (defined $opt_cc) -{ - $config{CC} = $opt_cc; + +our %cxx = get_compiler_info($config{CXX}); +if ($cxx{UNSUPPORTED}) { + print "Your C++ compiler is too old to build InspIRCd!\n"; + print "Reason: $cxx{REASON}\n"; + exit 1; } -our $exec = $config{CC} . " -dumpversion | cut -c 1"; -chomp($config{GCCVER} = `$exec`); # Major GCC Version -$exec = $config{CC} . " -dumpversion | cut -c 3"; -chomp($config{GCCMINOR} = `$exec`); -$config{MAXBUF} = "512"; # Max buffer size if ($config{HAS_OPENSSL} =~ /^([-[:digit:].]+)(?:[a-z])?(?:\-[a-z][0-9])?/) { $config{HAS_OPENSSL} = $1; @@ -279,156 +186,46 @@ if ($config{HAS_OPENSSL} =~ /^([-[:digit:].]+)(?:[a-z])?(?:\-[a-z][0-9])?/) { $config{HAS_OPENSSL} = ""; } -if (($config{GCCVER} eq "") || ($config{GCCMINOR} eq "")) { - if ($config{IS_DARWIN} eq "YES") { - print $config{CC} . " was not found! You require clang++ (the LLVM C++ compiler, part of the OSX developer tools) to build InspIRCd!\n"; - } else { - print $config{CC} . " was not found! You require g++ (the GNU C++ compiler, part of GCC) to build InspIRCd!\n"; - } - exit; -} - -# Get and Set some important vars.. -getmodules(); +$config{HAS_CLOCK_GETTIME} = run_test 'clock_gettime()', test_file($config{CXX}, 'clock_gettime.cpp', '-lrt'); +$config{HAS_EVENTFD} = run_test 'eventfd()', test_file($config{CXX}, 'eventfd.cpp'); -sub clean -{ - unlink(".config.cache"); +if ($config{HAS_EPOLL} = run_test 'epoll', test_header($config{CXX}, 'sys/epoll.h')) { + $config{SOCKETENGINE} ||= 'epoll'; } -our ($has_epoll, $has_ports, $has_kqueue) = (0, 0, 0); - -sub update -{ - eval { - chomp($topdir = getcwd()); - $this = resolve_directory($topdir); # PWD, Regardless. - getmodules(); - # Does the cache file exist? - if (!getcache()) { - # No, No it doesn't.. *BASH* - print "You have not run ./configure before. Please do this before trying to run the update script.\n"; - exit 0; - } else { - # We've Loaded the cache file and all our variables.. - print "Updating files...\n"; - if (defined($opt_disable_debug) && $opt_disable_debug == 1) - { - print "Disabling debug information (-g).\n"; - $config{OPTIMISATI} = ""; - } - $has_epoll = $config{HAS_EPOLL}; - $has_ports = $config{HAS_PORTS}; - $has_kqueue = $config{HAS_KQUEUE}; - writefiles(1); - makecache(); - print "Complete.\n"; - exit; - } - }; - if ($@) - { - print "Configure update failed: $@\n"; - } - exit; +if ($config{HAS_KQUEUE} = run_test 'kqueue', test_file($config{CXX}, 'kqueue.cpp')) { + $config{SOCKETENGINE} ||= 'kqueue'; } - -sub test_compile { - my $feature = shift; - my $fail = 0; - $fail ||= system "$config{CC} -o test_$feature make/check_$feature.cpp >/dev/null 2>&1"; - $fail ||= system "./test_$feature"; - unlink "test_$feature"; - return !$fail; +if ($config{HAS_PORTS} = run_test 'Solaris IOCP', test_header($config{CXX}, 'port.h')) { + $config{SOCKETENGINE} ||= 'ports'; } -print "Running non-interactive configure...\n" unless $interactive; -print "Checking for cache from previous configure... "; -print ($cache_loaded ? "found\n" : "not found\n"); -$config{SYSTEM} = lc $^O; -print "Checking operating system version... $config{SYSTEM}\n"; - -$exec = $config{CC} . " -dumpversion | cut -c 1"; -chomp($config{GCCVER} = `$exec`); # Major GCC Version -$exec = $config{CC} . " -dumpversion | cut -c 3"; -chomp($config{GCCMINOR} = `$exec`); - -printf "Checking if stdint.h exists... "; -$config{HAS_STDINT} = "true"; -our $fail = 0; -open(STDINT, "</usr/include/stdint.h") or $config{HAS_STDINT} = "false"; -if ($config{HAS_STDINT} eq "true") { - close(STDINT); +if ($config{HAS_POLL} = run_test 'poll', test_header($config{CXX}, 'poll.h')) { + $config{SOCKETENGINE} ||= 'poll'; } -print "yes\n" if $config{HAS_STDINT} eq "true"; -print "no\n" if $config{HAS_STDINT} eq "false"; - -printf "Checking if strlcpy exists... "; -# Perform the strlcpy() test.. -$config{HAS_STRLCPY} = "false"; -$fail = 0; -open(STRLCPY, "</usr/include/string.h") or $fail = 1; -if (!$fail) { - while (defined(my $line = <STRLCPY>)) { - chomp($line); - # try and find the delcaration of: - # size_t strlcpy(...) - if ($line =~ /size_t(\0x9|\s)+strlcpy/) { - $config{HAS_STRLCPY} = "true"; - } - } - close(STRLCPY); -} -print "yes\n" if $config{HAS_STRLCPY} eq "true"; -print "no\n" if $config{HAS_STRLCPY} eq "false"; - -printf "Checking if kqueue exists... "; -$has_kqueue = 0; -$fail = 0; -open(KQUEUE, "</usr/include/sys/event.h") or $fail = 1; -if (!$fail) { - while (defined(my $line = <KQUEUE>)) { - chomp($line); - # try and find the delcaration of: - # int kqueue(void); - if ($line =~ /int(\0x9|\s)+kqueue/) { - $has_kqueue = 1; + +# Select is available on all platforms +$config{HAS_SELECT} = 1; +$config{SOCKETENGINE} ||= "select"; + +if (defined $opt_socketengine) { + my $cfgkey = "HAS_" . uc $opt_socketengine; + if ($config{$cfgkey} && -f "src/socketengines/socketengine_$opt_socketengine.cpp") { + $config{SOCKETENGINE} = $opt_socketengine; + } else { + print "Unable to use a socket engine which is not supported on this platform ($opt_socketengine)!\n"; + print "Available socket engines are:"; + foreach (<src/socketengines/socketengine_*.cpp>) { + s/src\/socketengines\/socketengine_(\w+)\.cpp/$1/; + print " $1" if $config{"HAS_" . uc $1}; } + print "\n"; + exit 1; } - close(KQUEUE); } -print "yes\n" if $has_kqueue == 1; -print "no\n" if $has_kqueue == 0; - -printf "Checking for epoll support... "; -$has_epoll = test_compile('epoll'); -print $has_epoll ? "yes\n" : "no\n"; - -printf "Checking for eventfd support... "; -$config{HAS_EVENTFD} = test_compile('eventfd') ? 'true' : 'false'; -print $config{HAS_EVENTFD} eq 'true' ? "yes\n" : "no\n"; - -printf "Checking if Solaris I/O completion ports are available... "; -$has_ports = 0; -our $system = `uname -s`; -chomp ($system); -$has_ports = 1 if ($system eq "SunOS"); - -if ($has_ports) { - my $kernel = `uname -r`; - chomp($kernel); - if (($kernel !~ /^5\.1./)) { - $has_ports = 0; - } -} -print "yes\n" if $has_ports == 1; -print "no\n" if $has_ports == 0; - -$config{HAS_EPOLL} = $has_epoll; -$config{HAS_KQUEUE} = $has_kqueue; -printf "Checking for libgnutls... "; +print "Checking for libgnutls... "; if (defined($config{HAS_GNUTLS}) && (($config{HAS_GNUTLS}) || ($config{HAS_GNUTLS} eq "y"))) { if (defined($gnutls_ver) && ($gnutls_ver ne "")) { print "yes\n"; @@ -442,7 +239,7 @@ if (defined($config{HAS_GNUTLS}) && (($config{HAS_GNUTLS}) || ($config{HAS_GNUTL $config{HAS_GNUTLS} = "n"; } -printf "Checking for openssl... "; +print "Checking for openssl... "; if (defined($config{HAS_OPENSSL}) && (($config{HAS_OPENSSL}) || ($config{HAS_OPENSSL} eq "y"))) { if (defined($openssl_ver) && ($openssl_ver ne "")) { print "yes\n"; @@ -456,38 +253,14 @@ if (defined($config{HAS_OPENSSL}) && (($config{HAS_OPENSSL}) || ($config{HAS_OPE $config{HAS_OPENSSL} = "n"; } -printf "Checking if you are running an ancient, unsupported OS... "; -if ($config{OSNAME} =~ /FreeBSD/i) -{ - my $version = `uname -r`; - if ($version =~ /^4\./) - { - print "yes.\n"; - print "FreeBSD 4.x is no longer supported. By ANYONE.\n"; - print "To build, you will need to add the following to CXXFLAGS:\n"; - print "\t-L/usr/local/lib -lgnugetopt -DHAVE_DECL_GETOPT=1\n"; - } - else - { - print "no ($version)\n"; - } -} -else -{ - print "no ($config{OSNAME})\n"; -} - -################################################################################ -# BEGIN INTERACTIVE PART # -################################################################################ - -# Clear the Screen.. if ($interactive) { - print "\e[2J\e[0G\e[0d"; # J = Erase in Display, 2 = Entire Screen, (G, d) = Move cursor to (..,..) - my $wholeos = $^O; + # Clear the screen. + system 'tput', 'clear'; + + my $revision = get_revision(); + chomp(my $version = `sh src/version.sh`); - my $rev = getrevision(); # Display Introduction Message.. print <<"STOP" ; Welcome to the \e[1mInspIRCd\e[0m Configuration program! (\e[1minteractive mode\e[0m) @@ -501,143 +274,93 @@ Press \e[1m<RETURN>\e[0m to accept the default for any option, or enter a new value. Please note: You will \e[1mHAVE\e[0m to read the docs dir, otherwise you won't have a config file! -Your operating system is: \e[1;32m$config{OSNAME}\e[0m ($wholeos) -Your InspIRCd revision ID is \e[1;32mr$rev\e[0m +Your operating system is: \e[1;32m$^O\e[0m STOP - if ($rev eq "r0") { - print " (Non-SVN build)"; - } - print ".\n\n"; - - $config{CHANGE_COMPILER} = "n"; - print "I have detected the following compiler: \e[1;32m$config{CC}\e[0m (version \e[1;32m$config{GCCVER}.$config{GCCMINOR}\e[0m)\n"; - - while (($config{GCCVER} < 3) || ($config{GCCVER} eq "")) { - print "\e[1;32mIMPORTANT!\e[0m A GCC 2.x compiler has been detected, and -should NOT be used. You should probably specify a newer compiler.\n\n"; - yesno('CHANGE_COMPILER',"Do you want to change the compiler?"); - if ($config{CHANGE_COMPILER} =~ /y/i) { - print "What command do you want to use to invoke your compiler?\n"; - print "[\e[1;32m$config{CC}\e[0m] -> "; - chomp($config{CC} = <STDIN>); - if ($config{CC} eq "") { - $config{CC} = "g++"; - } - chomp(my $foo = `$config{CC} -dumpversion | cut -c 1`); - if ($foo ne "") { - chomp($config{GCCVER} = `$config{CC} -dumpversion | cut -c 1`); # we must redo these if we change compilers - chomp($config{GCCMINOR} = `$config{CC} -dumpversion | cut -c 3`); - print "Queried compiler: \e[1;32m$config{CC}\e[0m (version \e[1;32m$config{GCCVER}.$config{GCCMINOR}\e[0m)\n"; - if ($config{GCCVER} < 3) { - print "\e[1;32mGCC 2.x WILL NOT WORK!\e[0m. Let's try that again, shall we?\n"; - } - } - else { - print "\e[1;32mWARNING!\e[0m Could not execute the compiler you specified. You may want to try again.\n"; - } - } - } - - print "\n"; + print "Your InspIRCd version is: \e[1;32m"; + print $revision eq 'release' ? substr($version, 9) : substr($revision, 1); + print "\e[0m\n\n"; + print "The following compiler has been detected: \e[1;32m$cxx{NAME} $cxx{VERSION}\e[0m ($config{CXX})\n\n"; # Directory Settings.. my $tmpbase = $config{BASE_DIR}; - dir_check("do you wish to install the InspIRCd base", "BASE_DIR"); + $config{BASE_DIR} = prompt_dir(1, 'What directory do you wish to install the InspIRCd base?', $config{BASE_DIR}); if ($tmpbase ne $config{BASE_DIR}) { - $config{CONFIG_DIR} = resolve_directory($config{BASE_DIR}."/conf"); # Configuration Dir - $config{MODULE_DIR} = resolve_directory($config{BASE_DIR}."/modules"); # Modules Directory - $config{DATA_DIR} = resolve_directory($config{BASE_DIR}."/data"); # Data Directory - $config{LOG_DIR} = resolve_directory($config{BASE_DIR}."/logs"); # Log Directory - $config{BINARY_DIR} = resolve_directory($config{BASE_DIR}."/bin"); # Binary Directory + $config{CONFIG_DIR} = rel2abs($config{BASE_DIR}."/conf"); + $config{MODULE_DIR} = rel2abs($config{BASE_DIR}."/modules"); + $config{DATA_DIR} = rel2abs($config{BASE_DIR}."/data"); + $config{LOG_DIR} = rel2abs($config{BASE_DIR}."/logs"); + $config{BINARY_DIR} = rel2abs($config{BASE_DIR}."/bin"); } - dir_check("are the configuration files", "CONFIG_DIR"); - dir_check("are the modules to be compiled to", "MODULE_DIR"); - dir_check("is the IRCd binary to be placed", "BINARY_DIR"); - dir_check("are variable data files to be located in", "DATA_DIR"); - dir_check("are the logs to be stored in", "LOG_DIR"); - dir_check("do you want the build to take place", "BUILD_DIR"); - + $config{BINARY_DIR} = prompt_dir(1, 'In what directory should the InspIRCd binary be placed?', $config{BINARY_DIR}); + $config{CONFIG_DIR} = prompt_dir(1, 'In what directory are the configuration files to be stored?', $config{CONFIG_DIR}); + $config{DATA_DIR} = prompt_dir(1, 'In what directory are variable data files to be stored?', $config{DATA_DIR}); + $config{LOG_DIR} = prompt_dir(1, 'In what directory are log files to be stored?', $config{LOG_DIR}); + $config{MODULE_DIR} = prompt_dir(1, 'In what directory are the modules to be placed?', $config{MODULE_DIR}); + $config{BUILD_DIR} = prompt_dir(1, 'In what directory do you want the build to take place?', $config{BUILD_DIR}); + my $chose_hiperf = 0; - if ($has_kqueue) { - yesno('USE_KQUEUE',"You are running a BSD operating system, and kqueue\nwas detected. Would you like to enable kqueue support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable kqueue?"); - print "\n"; - if ($config{USE_KQUEUE} eq "y") { + if ($config{HAS_KQUEUE}) { + $config{USE_KQUEUE} = prompt_bool(1, 'Your operating system has support for the high performance kqueue socket engine. Would you like to enable it?', 1); + if ($config{USE_KQUEUE}) { + $config{SOCKETENGINE} = "kqueue"; $chose_hiperf = 1; } } - if ($has_epoll) { - yesno('USE_EPOLL',"You are running a Linux 2.6+ operating system, and epoll\nwas detected. Would you like to enable epoll support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable epoll?"); - print "\n"; - if ($config{USE_EPOLL} eq "y") { + if ($config{HAS_EPOLL}) { + $config{USE_EPOLL} = prompt_bool(1, 'Your operating system has support for the high performance epoll socket engine. Would you like to enable it?', 1); + if ($config{USE_EPOLL}) { + $config{SOCKETENGINE} = "epoll"; $chose_hiperf = 1; } } - if ($has_ports) { - yesno('USE_PORTS',"You are running Solaris 10.\nWould you like to enable I/O completion ports support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable support for I/O completion ports?"); - print "\n"; - if ($config{USE_PORTS} eq "y") { + if ($config{HAS_PORTS}) { + $config{USE_PORTS} = prompt_bool(1, 'Your operating system has support for the high performance IOCP socket engine. Would you like to enable it?', 1); + if ($config{USE_PORTS}) { + $config{SOCKETENGINE} = "ports"; $chose_hiperf = 1; } } - if (!$chose_hiperf) { - yesno('USE_POLL', "Would you like to use poll?\n This is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable poll?"); - if ($config{USE_POLL} ne "y") - { - print "No high-performance socket engines are available, or you chose\n"; - print "not to enable one. Defaulting to select() engine.\n\n"; + if (!$chose_hiperf && $config{HAS_POLL}) { + $config{USE_POLL} = prompt_bool(1, 'Your operating system has support for the mid performance poll socket engine. Would you like to enable it?', 1); + if ($config{USE_POLL}) { + $config{SOCKETENGINE} = "poll"; } } - - $config{USE_FREEBSD_BASE_SSL} = "n"; - $config{USE_FREEBSD_PORTS_SSL} = "n"; - if ($config{HAS_OPENSSL_PORT} ne "") + unless ($chose_hiperf || $config{USE_POLL}) { - $config{USE_FREEBSD_PORTS_SSL} = "y"; - print "I have detected the OpenSSL FreeBSD port installed on your system,\n"; - print "version \e[1;32m".$config{HAS_OPENSSL_PORT}."\e[0m. Your base system OpenSSL is version \e[1;32m".$openssl_ver."\e[0m.\n\n"; - yesno('USE_FREEBSD_PORTS_SSL', "Do you want to use the FreeBSD ports version?"); - print "\n"; - $config{USE_FREEBSD_BASE_SSL} = "y" if ($config{USE_FREEBSD_PORTS_SSL} eq "n"); - - if ($config{USE_FREEBSD_BASE_SSL} eq "n") - { - # update to port version - $openssl_ver = $config{HAS_OPENSSL_PORT}; - } + print "No high-performance socket engines are available, or you chose not to enable one. Defaulting to select() engine.\n\n"; + $config{SOCKETENGINE} = "select"; } - else - { - $config{USE_FREEBSD_BASE_SSL} = "y" if ($^O eq "freebsd"); - } - - $config{USE_SSL} = "n"; - $config{MODUPDATE} = 'n'; if ($config{HAS_GNUTLS} eq "y" || $config{HAS_OPENSSL} eq "y") { print "Detected GnuTLS version: \e[1;32m" . $gnutls_ver . "\e[0m\n"; print "Detected OpenSSL version: \e[1;32m" . $openssl_ver . "\e[0m\n\n"; - yesno('USE_SSL', "One or more SSL libraries detected. Would you like to enable SSL support?"); - if ($config{USE_SSL} eq "y") + $config{USE_SSL} = prompt_bool(1, 'One or more SSL libraries detected. Would you like to enable SSL support?', 1); + if ($config{USE_SSL}) { if ($config{HAS_GNUTLS} eq "y") { - yesno('USE_GNUTLS',"Would you like to enable SSL with m_ssl_gnutls? (recommended)"); - if ($config{USE_GNUTLS} eq "y") + $config{USE_GNUTLS} = prompt_bool(1, 'Would you like to enable SSL with m_ssl_gnutls (recommended)?', 1); + if ($config{USE_GNUTLS}) { - print "\nUsing GnuTLS SSL module.\n"; + print "Using GnuTLS SSL module.\n\n"; + unlink 'src/modules/m_ssl_gnutls.cpp' if -f 'src/modules/m_ssl_gnutls.cpp'; + symlink "extra/m_ssl_gnutls.cpp", "src/modules/m_ssl_gnutls.cpp" or print STDERR "Symlink failed: $!\n"; } } if ($config{HAS_OPENSSL} eq "y") { - yesno('USE_OPENSSL', "Would you like to enable SSL with m_ssl_openssl?"); - if ($config{USE_OPENSSL} eq "y") + $config{USE_OPENSSL} = prompt_bool(1, 'Would you like to enable SSL with m_ssl_openssl (recommended)?', 1); + if ($config{USE_OPENSSL}) { - print "\nUsing OpenSSL SSL module.\nYou will get better performance if you move to GnuTLS in the future.\n"; + print "Using OpenSSL SSL module.\n\n"; + unlink 'src/modules/m_ssl_openssl.cpp' if -f 'src/modules/m_ssl_openssl.cpp'; + symlink "extra/m_ssl_openssl.cpp", "src/modules/m_ssl_openssl.cpp" or print STDERR "Symlink failed: $!\n"; } } } @@ -647,377 +370,120 @@ should NOT be used. You should probably specify a newer compiler.\n\n"; print "\nCould not detect OpenSSL or GnuTLS. Make sure pkg-config is installed and\n"; print "is in your path.\n\n"; } - - yesno('MODUPDATE',"Would you like to check for updates to third-party modules?"); - print "\n"; - if ($config{MODUPDATE} eq "y") { - print "Checking for upgrades to extra and third party modules... "; - system "./modulemanager upgrade"; - } } # We are on a POSIX system, we can enable POSIX extras without asking symlink "extra/m_regex_posix.cpp", "src/modules/m_regex_posix.cpp"; -dumphash(); - -if (($config{USE_GNUTLS} eq "y") && ($config{HAS_GNUTLS} ne "y")) +if (($config{USE_GNUTLS}) && ($config{HAS_GNUTLS} ne "y")) { - print "Sorry, but i couldn't detect gnutls. Make sure gnutls-config is in your path.\n"; - exit(0); + print "Sorry, but i couldn't detect gnutls. Make sure pkg-config is in your path.\n"; + exit 1; } -if (($config{USE_OPENSSL} eq "y") && ($config{HAS_OPENSSL} ne "y")) +if (($config{USE_OPENSSL}) && ($config{HAS_OPENSSL} ne "y")) { - print "Sorry, but i couldn't detect openssl. Make sure openssl is in your path.\n"; - exit(0); + print "Sorry, but i couldn't detect openssl. Make sure pkg-config is in your path.\n"; + exit 1; } -our $failed = 0; -$config{CERTGEN} ||= 'y'; -yesno('CERTGEN',"Would you like generate SSL certificates now?") if ($interactive && ($config{USE_GNUTLS} eq "y" || $config{USE_OPENSSL} eq "y")); - -if ($config{USE_GNUTLS} eq "y") { - unless (-r "src/modules/m_ssl_gnutls.cpp") { - print "Symlinking src/modules/m_ssl_gnutls.cpp from extra/\n"; - symlink "extra/m_ssl_gnutls.cpp", "src/modules/m_ssl_gnutls.cpp" or print STDERR "Symlink failed: $!"; - } - if ($interactive && $config{CERTGEN} eq 'y') - { - unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") { - print "SSL Certificates Not found, Generating.. \n\n -************************************************************* -* Generating the Private Key may take some time, go grab a * -* Coffee. Even better, to generate some more entropy if it * -* is taking a while, open another console and type du / a * -* few times and get that HD going :) Then answer the * -* Questions which follow. If you are unsure, just hit enter * -*************************************************************\n\n"; - $failed = make_gnutls_cert(); - if ($failed) { - print "\n\e[1;32mCertificate generation failed!\e[0m\n\n"; - } else { +if ($config{USE_GNUTLS} || $config{USE_OPENSSL}) { + if (my $val = prompt_bool($interactive, 'Would you like to generate SSL certificates now?', $interactive)) { + unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem" && -r "$config{CONFIG_DIR}/dhparams.pem") { + unless (system './tools/genssl auto') { print "\nCertificate generation complete, copying to config directory... "; File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n"; File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n"; + File::Copy::move("dhparams.pem", "$config{CONFIG_DIR}/dhparams.pem") or print STDERR "Could not copy dhparams.pem!\n"; print "Done.\n\n"; } - } - else { - print "SSL Certificates found, skipping.\n\n"; - } - } - else - { - print "Skipping SSL certificate generation\nin non-interactive mode.\n\n"; - } -} - -if ($config{USE_OPENSSL} eq "y") { - unless (-r "src/modules/m_ssl_openssl.cpp") { - print "Symlinking src/modules/m_ssl_openssl.cpp from extra/\n"; - symlink "extra/m_ssl_openssl.cpp", "src/modules/m_ssl_openssl.cpp" or print STDERR "Symlink failed: $!"; - } - $failed = 0; - if ($interactive && $config{CERTGEN} eq 'y') - { - unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") { - print "SSL Certificates Not found, Generating.. \n\n -************************************************************* -* Generating the certificates may take some time, go grab a * -* coffee, or something. * -*************************************************************\n\n"; - make_openssl_cert(); - print "\nCertificate generation complete, copying to config directory... "; - File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n"; - File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n"; - File::Copy::move("dhparams.pem", "$config{CONFIG_DIR}/dhparams.pem") or print STDERR "Could not copy dhparams.pem!\n"; - print "Done.\n\n"; } else { print "SSL Certificates found, skipping.\n\n" } + } else { + print "Skipping SSL certificate generation in non-interactive mode.\n\n"; } - else - { - print "Skipping SSL certificate generation\nin non-interactive mode.\n\n"; - } -} -if (($config{USE_GNUTLS} eq "n") && ($config{USE_OPENSSL} eq "n")) { +} else { print "Skipping SSL Certificate generation, SSL support is not available.\n\n"; } -depcheck(); -writefiles(1); -makecache(); +print "Writing \e[1;32m.config.cache\e[0m ...\n"; +write_configure_cache(%config); +writefiles(); +dump_hash(); -print "\n\n"; +print "\n"; print "To build your server with these settings, please run '\e[1;32mmake\e[0m' now.\n"; -if (($config{USE_GNUTLS} eq "y") || ($config{USE_OPENSSL} eq "y")) { +if ($config{USE_GNUTLS} || $config{USE_OPENSSL}) { print "Please note: for \e[1;32mSSL support\e[0m you will need to load required\n"; print "modules in your config. This configure script has added those modules to the\n"; print "build process. For more info please refer to:\n"; print "\e[1;32mhttp://wiki.inspircd.org/Installation_From_Tarball\e[0m\n"; } -print "*** \e[1;32mRemember to edit your configuration files!!!\e[0m ***\n\n\n"; -if (($config{OSNAME} eq "OpenBSD") && ($config{CC} ne "eg++")) { - print "\e[1;32mWARNING!\e[0m You are running OpenBSD but you are using the base gcc package\nrather than eg++. This compile will most likely fail, but i'm letting you\ngo ahead with it anyway, just in case i'm wrong :-)\n"; -} - -if ($config{GCCVER} < "3") { - print <<FOO2; -\e[1;32mWARNING!\e[0m You are attempting to compile InspIRCd on GCC 2.x! -GCC 2.x series compilers only had partial (read as broken) C++ support, and -your compile will most likely fail horribly! If you have any problems, do NOT -report them to the bugtracker or forums without first upgrading your compiler -to a newer 3.x or 4.x (or whatever is available currently) version. -FOO2 -} - -################################################################################ -# HELPER FUNCTIONS # -################################################################################ -sub getcache { - # Retrieves the .config.cache file, and loads values into the main config hash. - open(CACHE, ".config.cache") or return 0; - while (<CACHE>) { - chomp; - # Ignore Blank lines, and comments.. - next if /^\s*$/; - next if /^\s*#/; - my ($key, $value) = split("=", $_, 2); - $value =~ /^\"(.*)\"$/; - # Do something with data here! - $config{$key} = $1; - } - close(CACHE); - return 1; -} - -sub makecache { - # Dump the contents of %config - print "Writing \e[1;32mcache file\e[0m for future ./configures ...\n"; - open(FILEHANDLE, ">.config.cache"); - foreach my $key (keys %config) { - print FILEHANDLE "$key=\"$config{$key}\"\n"; - } - close(FILEHANDLE); -} - -sub dir_check { - my ($desc, $hash_key) = @_; - my $complete = 0; - while (!$complete) { - print "In what directory $desc?\n"; - print "[\e[1;32m$config{$hash_key}\e[0m] -> "; - chomp(my $var = <STDIN>); - if ($var eq "") { - $var = $config{$hash_key}; - } - if ($var =~ /^\~\/(.+)$/) { - # Convert it to a full path.. - $var = resolve_directory($ENV{HOME} . "/" . $1); - } - elsif ((($config{OSNAME} =~ /MINGW32/i) and ($var !~ /^[A-Z]{1}:\\.*/)) and (substr($var,0,1) ne "/")) - { - # Assume relative Path was given.. fill in the rest. - $var = $this . "/$var"; - } - - $var = resolve_directory($var); - if (! -e $var) { - print "$var does not exist. Create it?\n[\e[1;32my\e[0m] "; - chomp(my $tmp = <STDIN>); - if (($tmp eq "") || ($tmp =~ /^y/i)) { - # Attempt to Create the Dir.. - my $chk = eval { - use File::Path (); - File::Path::mkpath($var, 0, 0777); - 1; - }; - unless (defined($chk) && -d $var) { - print "Unable to create directory. ($var)\n\n"; - # Restart Loop.. - next; - } - } else { - # They said they don't want to create, and we can't install there. - print "\n\n"; - next; - } - } else { - if (!is_dir($var)) { - # Target exists, but is not a directory. - print "File $var exists, but is not a directory.\n\n"; - next; - } - } - # Either Dir Exists, or was created fine. - $config{$hash_key} = $var; - $complete = 1; - print "\n"; - } -} - -our $SHARED = ""; - -my ($mliflags, $mfrules, $mobjs, $mfcount) = ("", "", "", 0); +print "*** \e[1;32mRemember to edit your configuration files!!!\e[0m ***\n\n"; sub writefiles { - my($writeheader) = @_; - # First File.. inspircd_config.h chomp(my $incos = `uname -n -s -r`); chomp(my $version = `sh src/version.sh`); - chomp(my $revision2 = getrevision()); + my $revision = get_revision(); my $branch = "InspIRCd-0.0"; if ($version =~ /^(InspIRCd-[0-9]+\.[0-9]+)\.[0-9]+/) { $branch = $1; } - if ($writeheader == 1) - { - print "Writing \e[1;32minspircd_config.h\e[0m\n"; - open(FILEHANDLE, ">include/inspircd_config.h.tmp"); - print FILEHANDLE <<EOF; + print "Writing \e[1;32mconfig.h\e[0m\n"; + open(FILEHANDLE, ">include/config.h.tmp"); + print FILEHANDLE <<EOF; /* Auto generated by configure, do not modify! */ -#ifndef __CONFIGURATION_AUTO__ -#define __CONFIGURATION_AUTO__ +#pragma once -/* this is for windows support. */ -#define CoreExport /**/ -#define DllExport /**/ +#define BRANCH "$branch" +#define VERSION "$version" +#define REVISION "$revision" +#define SYSTEM "$incos" #define CONFIG_PATH "$config{CONFIG_DIR}" #define DATA_PATH "$config{DATA_DIR}" #define LOG_PATH "$config{LOG_DIR}" #define MOD_PATH "$config{MODULE_DIR}" -#define SOMAXCONN_S "$config{_SOMAXCONN}" -#define ENTRYPOINT int main(int argc, char** argv) EOF -print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n"; - - if ($config{OSNAME} =~ /SunOS/i) { - print FILEHANDLE "#define IS_SOLARIS\n"; - } - if ($config{OSNAME} =~ /MINGW32/i) { - print FILEHANDLE "#define IS_MINGW\n"; - } - if ($config{GCCVER} >= 3) { - print FILEHANDLE "#define GCC3\n"; - } - if ($config{HAS_STRLCPY} eq "true") { - print FILEHANDLE "#define HAS_STRLCPY\n"; - } - if ($config{HAS_STDINT} eq "true") { - print FILEHANDLE "#define HAS_STDINT\n"; - } - if ($config{HAS_EVENTFD} eq 'true') { - print FILEHANDLE "#define HAS_EVENTFD\n"; - } - if ($config{OSNAME} !~ /DARWIN/i) { - print FILEHANDLE "#define HAS_CLOCK_GETTIME\n"; - } - my $use_hiperf = 0; - if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) { - print FILEHANDLE "#define USE_KQUEUE\n"; - $config{SOCKETENGINE} = "socketengine_kqueue"; - $use_hiperf = 1; - } - if (($has_epoll) && ($config{USE_EPOLL} eq "y")) { - print FILEHANDLE "#define USE_EPOLL\n"; - $config{SOCKETENGINE} = "socketengine_epoll"; - $use_hiperf = 1; - } - if (($has_ports) && ($config{USE_PORTS} eq "y")) { - print FILEHANDLE "#define USE_PORTS\n"; - $config{SOCKETENGINE} = "socketengine_ports"; - $use_hiperf = 1; - } - # user didn't choose either epoll or select for their OS. - # default them to USE_SELECT (ewwy puke puke) - if (!$use_hiperf) { - print "no hi-perf, " . $config{USE_POLL}; - if ($config{USE_POLL} eq "y") - { - print FILEHANDLE "#define USE_POLL\n"; - $config{SOCKETENGINE} = "socketengine_poll"; - } - else - { - print FILEHANDLE "#define USE_SELECT\n"; - $config{SOCKETENGINE} = "socketengine_select"; - } - } - print FILEHANDLE "\n#include \"threadengines/threadengine_pthread.h\"\n\n#endif\n"; - close(FILEHANDLE); - open(FILEHANDLE, ">include/inspircd_version.h.tmp"); - print FILEHANDLE <<EOF; -#define BRANCH "$branch" -#define VERSION "$version" -#define REVISION "$revision2" -#define SYSTEM "$incos" -EOF - close FILEHANDLE; - - for my $file (qw(include/inspircd_config.h include/inspircd_version.h)) { - my $diff = 0; - open my $fh1, $file or $diff = 1; - open my $fh2, $file.'.tmp' or die "Can't read $file.tmp that we just wrote: $!"; - while (!$diff) { - my $line1 = <$fh1>; - my $line2 = <$fh2>; - if (defined($line1) != defined($line2)) { - $diff = 1; - } elsif (!defined $line1) { - last; - } else { - $diff = ($line1 ne $line2); - } - } - if ($diff) { - unlink $file; - rename "$file.tmp", $file; - } else { - unlink "$file.tmp"; - } - } + if ($config{HAS_EVENTFD}) { + print FILEHANDLE "#define HAS_EVENTFD\n"; } + if ($config{HAS_CLOCK_GETTIME}) { + print FILEHANDLE "#define HAS_CLOCK_GETTIME\n"; + } + + print FILEHANDLE "\n#include \"threadengines/threadengine_pthread.h\"\n"; + close(FILEHANDLE); - # Write all .in files. - my $tmp = ""; - my $file = ""; - my $exe = "inspircd"; + unlink 'include/config.h'; + rename 'include/config.h.tmp', 'include/config.h'; # Do this once here, and cache it in the .*.inc files, # rather than attempting to read src/version.sh from # compiled code -- we might not have the source to hand. - # Fix for bug#177 by Brain. - - chomp($version = `sh ./src/version.sh`); - chomp(my $revision = getrevision()); - $version = "$version(r$revision)"; - - # We can actually parse any file starting with . and ending with .inc, - # but right now we only parse .inspircd.inc to form './inspircd' - prepare_dynamic_makefile(); my @dotfiles = qw(main.mk inspircd); - push @dotfiles, 'org.inspircd.plist' if $config{OSNAME} eq 'darwin'; + push @dotfiles, 'org.inspircd.plist' if $^O eq 'darwin'; foreach my $file (@dotfiles) { open(FILEHANDLE, "make/template/$file") or die "Can't open make/template/$file: $!"; $_ = join '', <FILEHANDLE>; close(FILEHANDLE); - $config{BUILD_DIR} ||= resolve_directory($config{ME}."/build"); + $config{BUILD_DIR} ||= rel2abs($topdir."/build"); + $config{COMPILER} = lc $cxx{NAME}; + $config{SYSTEM} = lc $^O; for my $var (qw( - CC SYSTEM BASE_DIR CONFIG_DIR MODULE_DIR BINARY_DIR BUILD_DIR DATA_DIR UID - STARTSCRIPT DESTINATION SOCKETENGINE + CXX COMPILER SYSTEM BASE_DIR CONFIG_DIR MODULE_DIR BINARY_DIR BUILD_DIR DATA_DIR UID + STARTSCRIPT SOCKETENGINE )) { s/\@$var\@/$config{$var}/g; } - s/\@EXECUTABLE\@/$exe/ if defined $exe; + s/\@VERSION\@/$version/ if defined $version; if ($file eq 'main.mk') { @@ -1027,6 +493,7 @@ EOF s/\@IFDEF (\S+)/ifdef $1/g; s/\@IFNDEF (\S+)/ifndef $1/g; s/\@IFEQ (\S+) (\S+)/ifeq ($1,$2)/g; + s/\@IFNEQ (\S+) (\S+)/ifneq ($1,$2)/g; s/\@ELSIFEQ (\S+) (\S+)/else ifeq ($1,$2)/g; s/\@ELSE/else/g; s/\@ENDIF/endif/g; @@ -1042,6 +509,7 @@ EOF s/\@IFDEF (\S+)/.if defined($1)/g; s/\@IFNDEF (\S+)/.if !defined($1)/g; s/\@IFEQ (\S+) (\S+)/.if $1 == $2/g; + s/\@IFNEQ (\S+) (\S+)/.if $1 != $2/g; s/\@ELSIFEQ (\S+) (\S+)/.elif $1 == $2/g; s/\@ELSE/.else/g; s/\@ENDIF/.endif/g; @@ -1060,34 +528,7 @@ EOF } } - chmod 0755, 'inspircd'; -} - -sub depcheck -{ - getmodules(); - for my $mod (@modlist) { - getcompilerflags("src/modules/m_$mod.cpp"); - getlinkerflags("src/modules/m_$mod.cpp"); - } -} - -sub prepare_dynamic_makefile -{ - my $i = 0; - - if (!$has_epoll) - { - $config{USE_EPOLL} = 0; - } - if (!$has_kqueue) - { - $config{USE_KQUEUE} = 0; - } - if (!$has_ports) - { - $config{USE_PORTS} = 0; - } + chmod 0750, 'inspircd'; } # Routine to list out the extra/ modules that have been enabled. @@ -1153,7 +594,7 @@ EXTRA: for my $extra (@extras) { for my $extra (keys(%extras)) { next unless $extras{$extra} =~ m/enabled/; # only process enabled extras. my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra); - my @deps = split / +/, getdependencies($abs_extra); + my @deps = split /\s+/, get_property($abs_extra, 'ModDep'); for my $dep (@deps) { if (exists($extras{$dep})) { my $ref = \$extras{$dep}; # Take reference. @@ -1200,10 +641,10 @@ sub enable_extras (@) { next; } # Get dependencies, and add them to be processed. - my @deps = split / +/, getdependencies($extrapath); + my @deps = split /\s+/, get_property($extrapath, 'ModDep'); for my $dep (@deps) { next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway. - if (!-e "src/modules/$dep") { + if (!-e "src/modules/$dep" && !-e "include/$dep") { if (-e "src/modules/extra/$dep") { print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n"; push @extras, $dep; @@ -1236,7 +677,7 @@ EXTRA: for my $extra (@extras) { } # Check if anything needs this. for my $file (@files) { - my @deps = split / +/, getdependencies("src/modules/extra/$file"); + my @deps = split /\s+/, get_property("src/modules/extra/$file", 'ModDep'); # File depends on this extra... if (scalar(grep { $_ eq $extra } @deps) > 0) { # And is both enabled and not about to be disabled. diff --git a/docs/conf/helpop-full.conf.example b/docs/conf/helpop-full.conf.example index 1b33004c4..bddb5846a 100644 --- a/docs/conf/helpop-full.conf.example +++ b/docs/conf/helpop-full.conf.example @@ -97,6 +97,11 @@ Removes a user from a channel you specify. You must be at least a channel halfoperator to remove a user. A removed user will part with a message stating they were removed from the channel and by whom."> +<helpop key="rmode" value="/RMODE [channel] [modeletter] {[pattern]} + +Removes listmodes from a channel. +E.g. /RMODE #Chan b m:* will remove all mute extbans."> + <helpop key="fpart" value="/FPART [channel] [nick] {[reason]} This behaves identically to /REMOVE, the only difference is that that @@ -804,15 +809,15 @@ Closes all unregistered connections to the local server."> v [nickname] Gives voice to [nickname], allowing them to speak while the channel is +m. - h [nickname] Gives halfop status to [nickname] (this mode can - be disabled). + h [nickname] Gives halfop status to [nickname] (requires + customprefix module). o [nickname] Gives op status to [nickname]. a [nickname] Gives protected status to [nickname], preventing them from them from being kicked (+q only, - requires chanprotect module). + requires customprefix module). q [nickname] Gives owner status to [nickname], preventing them from being kicked (Services or only, requires - chanprotect module). + customprefix module). b [hostmask] Bans [hostmask] from the channel. e [hostmask] Excepts [hostmask] from bans (requires @@ -869,6 +874,9 @@ Closes all unregistered connections to the local server."> module). D Delays join messages from users until they message the channel (requires delayjoin module). + E [~*][lines]:[sec]{[:difference]}{[:backlog]} Allows blocking of similiar messages. + Kicks as default, blocks with ~ and bans with * + The last two parameters are optional. F [changes]:[sec] Blocks nick changes when they equal or exceed the specified rate (requires nickflood module). G Censors messages to the channel based on the diff --git a/docs/conf/helpop.conf.example b/docs/conf/helpop.conf.example index 2cccc5a2c..2c5102fcc 100644 --- a/docs/conf/helpop.conf.example +++ b/docs/conf/helpop.conf.example @@ -117,15 +117,15 @@ LOCKSERV UNLOCKSERV JUMPSERVER"> v [nickname] Gives voice to [nickname], allowing them to speak while the channel is +m. - h [nickname] Gives halfop status to [nickname] (this mode can - be disabled). + h [nickname] Gives halfop status to [nickname] (requires + customprefix module). o [nickname] Gives op status to [nickname]. a [nickname] Gives protected status to [nickname], preventing them from them from being kicked (+q only, - requires chanprotect module). + requires customprefix module). q [nickname] Gives owner status to [nickname], preventing them from being kicked (Services or only, requires - chanprotect module). + customprefix module). b [hostmask] Bans [hostmask] from the channel. e [hostmask] Excepts [hostmask] from bans (requires @@ -181,6 +181,9 @@ LOCKSERV UNLOCKSERV JUMPSERVER"> module). D Delays join messages from users until they message the channel (requires delayjoin module). + E [~*][lines]:[sec]{[:difference]}{[:backlog]} Allows blocking of similiar messages. + Kicks as default, blocks with ~ and bans with * + The last two parameters are optional. F [changes]:[sec] Blocks nick changes when they equal or exceed the specified rate (requires nickflood module). G Censors messages to the channel based on the diff --git a/docs/conf/inspircd.conf.example b/docs/conf/inspircd.conf.example index 9512e17c4..8a498577a 100644 --- a/docs/conf/inspircd.conf.example +++ b/docs/conf/inspircd.conf.example @@ -38,6 +38,15 @@ # # ######################################################################## +#-#-#-#-#-#-#-#-#-# CONFIGURATION FORMAT #-#-#-#-#-#-#-#-#-#-#-#-#-#- +# # +# In order to maintain compatibility with older configuration files, # +# you can change the configuration parser to parse as it did in # +# previous releases. When using the "compat" format, you need to use # +# C++ escape sequences (e.g. \n) instead of XML ones (e.g. &nl;) and # +# can not use <define> to create macros. # +#<config format="compat"> + #-#-#-#-#-#-#-#-#-# INCLUDE CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-#-# # # # This optional tag allows you to include another config file # @@ -69,11 +78,6 @@ # # # Variables may be redefined and may reference other variables. # # Value expansion happens at the time the tag is read. # -# # -# Using variable definitions REQUIRES that the config format be # -# changed to "xml" from the default "compat" that uses escape # -# sequences such as "\"" and "\n", and does not support <define> # -<config format="xml"> <define name="bindip" value="1.2.2.3"> <define name="localips" value="&bindip;/24"> @@ -157,6 +161,17 @@ # for ssl to work. If you do not want this bind section to support ssl, # just remove or comment out this option. ssl="gnutls" + + # defer: When this is non-zero, connections will not be handed over to + # the daemon from the operating system before data is ready. + # In Linux, the value indicates the number of seconds we'll wait for a + # connection to come up with data. Don't set it too low! + # In BSD the value is ignored; only zero and non-zero is possible. + # Windows ignores this parameter completely. + # Note: This does not take effect on rehash. + # To change it on a running bind, you'll have to comment it out, + # rehash, comment it in and rehash again. + defer="0" > <bind address="" port="6660-6669" type="clients"> @@ -270,6 +285,10 @@ # maxconnwarn: Enable warnings when localmax or globalmax is hit (defaults to on) maxconnwarn="off" + # resolvehostnames: If disabled, no DNS lookups will be performed on connecting users + # in this class. This can save a lot of resources on very busy servers. + resolvehostnames="yes" + # usednsbl: Defines whether or not users in this class are subject to DNSBL. Default is yes. # This setting only has effect when m_dnsbl is loaded. #usednsbl="yes" @@ -375,6 +394,10 @@ # globalmax: Maximum global (network-wide) connections per IP. globalmax="3" + # resolvehostnames: If disabled, no DNS lookups will be performed on connecting users + # in this class. This can save a lot of resources on very busy servers. + resolvehostnames="yes" + # useident: Defines if users in this class must respond to a ident query or not. useident="no" @@ -415,11 +438,11 @@ # This file has all the information about oper classes, types and o:lines. # You *MUST* edit it. -<include file="conf/examples/opers.conf.example"> +<include file="examples/opers.conf.example"> # This file has all the information about server links and ulined servers. # You *MUST* edit it if you intend to link servers. -<include file="conf/examples/links.conf.example"> +<include file="examples/links.conf.example"> #-#-#-#-#-#-#-#-#-#- MISCELLANEOUS CONFIGURATION -#-#-#-#-#-#-#-#-#-# # # @@ -429,7 +452,7 @@ # motd - displayed on connect and when a user executes /MOTD # rules - displayed when the user executes /RULES # Modules can also define their own files -<files motd="conf/examples/motd.txt.example" rules="conf/examples/rules.txt.example"> +<files motd="examples/motd.txt.example" rules="examples/rules.txt.example"> # Example of an executable file include. Note this will be read on rehash, # not when the command is run. @@ -554,11 +577,6 @@ # the correct parameters are. syntaxhints="no" - # cyclehosts: If enabled, when a user gets a host set, it will cycle - # them in all their channels. If not, it will simply change their host - # without cycling them. - cyclehosts="yes" - # cyclehostsfromuser: If enabled, the source of the mode change for # cyclehosts will be the user who cycled. This can look nicer, but # triggers anti-takeover mechanisms of some obsolete bots. @@ -598,11 +616,11 @@ # defaultmodes: What modes are set on a empty channel when a user # joins it and it is unregistered. This is similar to Asuka's # autochanmodes. - defaultmodes="nt" + defaultmodes="not" - # moronbanner: This is the text that is sent to a user when they are + # xlinemessage: This is the text that is sent to a user when they are # banned from the server. - moronbanner="You're banned! Email haha@abuse.com with the ERROR line below for help." + xlinemessage="You're banned! Email irc@example.com with the ERROR line below for help." # exemptchanops: exemptions for channel access restrictions based on prefix. exemptchanops="nonick:v flood:o" @@ -613,12 +631,7 @@ # nosnoticestack: This prevents snotices from 'stacking' and giving you # the message saying '(last message repeated X times)'. Defaults to no. - nosnoticestack="no" - - # welcomenotice: When turned on, this sends a NOTICE to connecting users - # with the text Welcome to <networkname>! after successful registration. - # Defaults to yes. - welcomenotice="yes"> + nosnoticestack="no"> #-#-#-#-#-#-#-#-#-#-#-# PERFORMANCE CONFIGURATION #-#-#-#-#-#-#-#-#-#-# @@ -633,33 +646,37 @@ # in the accept queue. This is *NOT* the total maximum number of # connections per server. Some systems may only allow this to be up # to 5, while others (such as linux and *BSD) default to 128. + # Setting this above the limit imposed by your OS can have undesired + # effects. somaxconn="128" - # limitsomaxconn: By default, somaxconn (see above) is limited to a - # safe maximum value in the 2.0 branch for compatibility reasons. - # This setting can be used to disable this limit, forcing InspIRCd - # to use the value specifed above. - limitsomaxconn="true" - # softlimit: This optional feature allows a defined softlimit for # connections. If defined, it sets a soft max connections value. softlimit="12800" + # clonesonconnect: If this is set to false, we won't check for clones + # on initial connection, but only after the DNS check is done. + # This can be useful where your main class is more restrictive + # than some other class a user can be assigned after DNS lookup is complete. + # Turning this option off will make the server spend more time on users we may + # potentially not want. Normally this should be neglible, though. + # Default value is true + clonesonconnect="true" + # quietbursts: When syncing or splitting from a network, a server # can generate a lot of connect and quit messages to opers with # +C and +Q snomasks. Setting this to yes squelches those messages, # which makes it easier for opers, but degrades the functionality of # bots like BOPM during netsplits. - quietbursts="yes" - - # nouserdns: If enabled, no DNS lookups will be performed on - # connecting users. This can save a lot of resources on very busy servers. - nouserdns="no"> + quietbursts="yes"> #-#-#-#-#-#-#-#-#-#-#-# SECURITY CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-# # # <security + # allowcoreunload: If this value is set to yes, Opers will be able to + # unload core modules (e.g. cmd_privmsg.so). + allowcoreunload="no" # announceinvites: This option controls which members of the channel # receive an announcement when someone is INVITEd. Available values: @@ -708,8 +725,8 @@ # (Commands like /notice, /privmsg, /kick, etc) maxtargets="20" - # customversion: Displays a custom string when a user /version's - # the ircd. This may be set for security reasons or vanity reasons. + # customversion: A custom message to be displayed in the comments field + # of the VERSION command response. This does not hide the InspIRCd version. customversion="" # operspywhois: show opers (users/auspex) the +s channels a user is in. Values: @@ -786,6 +803,14 @@ # maxaway: Maximum length of an away message. maxaway="200"> +#-#-#-#-#-#-#-#-#-#-#-#-# PATHS CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-# +# # +# This configuration tag defines the location that InspIRCd stores # +# various types of files such as configuration files, log files and # +# modules. You will probably not need to change these from the values # +# set when InspIRCd was built unless you are using a binary package # +# where you do not have the ability to set build time configuration. # +#<path configdir="conf" datadir="data" logdir="logs" moduledir="modules"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Logging @@ -955,7 +980,7 @@ # provide almost all the features of InspIRCd. :) # # # # The default does nothing -- we include it for simplicity for you. # -<include file="conf/examples/modules.conf.example"> +<include file="examples/modules.conf.example"> # Here are some pre-built modules.conf files that closely match the # default configurations of some popular IRCd's. You still may want to @@ -967,10 +992,10 @@ # recommended that you make your own modules file based on modules.conf.example. # Settings similar to UnrealIRCd defaults. -#<include file="conf/examples/modules/unrealircd.conf.example"> +#<include file="examples/modules/unrealircd.conf.example"> # Settings similar to Charybdis IRCd defaults. -#<include file="conf/examples/modules/charybdis.conf.example"> +#<include file="examples/modules/charybdis.conf.example"> ######################################################################### diff --git a/docs/conf/links.conf.example b/docs/conf/links.conf.example index fc0fc3b5e..382455bcd 100644 --- a/docs/conf/links.conf.example +++ b/docs/conf/links.conf.example @@ -95,7 +95,7 @@ # Simple autoconnect block. This enables automatic connection of a server # Recommended setup is to have leaves connect to the hub, and have no # automatic connections started by the hub. -<autoconnect period="300" server="hub.penguin.org"> +<autoconnect period="10m" server="hub.penguin.org"> # Failover autoconnect block. If you have multiple hubs, or want your network # to automatically link even if the hub is down, you can specify multiple diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example index 54a667f34..d329ab522 100644 --- a/docs/conf/modules.conf.example +++ b/docs/conf/modules.conf.example @@ -314,7 +314,7 @@ # specify some censor tags. See also: # # http://wiki.inspircd.org/Modules/censor # # -#<include file="conf/examples/censor.conf.example"> +#<include file="examples/censor.conf.example"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # CGI:IRC module: Adds support for automatic host changing in CGI:IRC @@ -384,7 +384,8 @@ # This is the hard limit for 'X'. # If notice is set to yes, joining users will get a NOTICE before playback # telling them about the following lines being the pre-join history. -#<chanhistory maxlines="20" notice="yes"> +# If bots is set to yes, it will also send to users marked with +B +#<chanhistory maxlines="20" notice="yes" bots="yes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Channel logging module: used to send snotice output to channels, to @@ -418,32 +419,6 @@ #<module name="m_channelban.so"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# -# Chanprotect module: gives +q and +a channel modes -#<module name="m_chanprotect.so"> - -<chanprotect - # noservices: With this set to yes, when a user joins a empty channel, - # the server will set +q on them. If set to no, it will only set +o - # on them until they register the channel. - noservices="no" - - # qprefix: Prefix (symbol) to use for +q users. - qprefix="~" - - # aprefix: Prefix (symbol) to use for +a users. - aprefix="&" - - # deprotectself: If this value is set (true, yes or 1), it will allow - # +a and +q users to remove the +a and +q from themselves, otherwise, - # the status will have to be removed by services. - deprotectself="yes" - - # deprotectothers: If this value is set to yes, true, or 1, then any - # user with +q or +a may remove the +q or +a from other users. - deprotectothers="yes"> - - -#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Check module: gives /check # Check is useful for looking up information on channels, # users, IP addresses and hosts. @@ -494,7 +469,7 @@ # cloak prefix as shown below. The cloak key must be shared across # # the network for correct cloaking. # # # -# There are four methods of cloaking: # +# There are two methods of cloaking: # # # # half Cloak only the "unique" portion of a host; show # # the last 2 parts of the domain, /16 subnet of IPv4 # @@ -503,19 +478,8 @@ # full Cloak the users completely, using three slices for # # common CIDR bans (IPv4: /16, /24; IPv6: /48, /64) # # # -# These methods use a single key that can be any length of text. # +# The methods use a single key that can be any length of text. # # An optional prefix may be specified to mark cloaked hosts. # -# # -# The following methods are maintained for backwards compatibility; # -# they are slightly less secure, and always hide unresolved IPs # -# # -# compat-host InspIRCd 1.2-compatible host-based cloaking # -# compat-ip InspIRCd 1.2-compatible ip-always cloaking # -# # -# If you use a compat cloaking mode then you must specify key1, key2, # -# key3, key4; the values must be less than 0x80000000 and should be # -# picked at random. Prefix is mandatory, will default to network name # -# if not specified, and will always have a "-" appended. # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # #<cloak mode="half" @@ -619,7 +583,6 @@ #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Custom prefixes: allows for channel prefixes to be added. -# This replaces m_chanprotect and m_halfop. #<module name="m_customprefix.so"> # # name The name of the mode, must be unique from other modes @@ -770,7 +733,7 @@ # specfiy below the path to the filter.conf file, or define some # # <filter> tags. # # # -#<include file="conf/examples/filter.conf.example"> +#<include file="examples/filter.conf.example"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Gecosban: Implements extended ban r:, which stops anyone matching @@ -814,10 +777,6 @@ #<module name="m_globalload.so"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# -# Halfop module: Provides the +h (halfops) channel status mode. -#<module name="m_halfop.so"> - -#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # HELPOP module: Provides the /HELPOP command #<module name="m_helpop.so"> # @@ -827,7 +786,7 @@ # specify below the path to the helpop.conf file, or if you like to # # make a mess, define your helpop tags in this conf. # # # -#<include file="conf/examples/inspircd.helpop-full.example"> +#<include file="examples/inspircd.helpop-full.example"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # HIDECHANS module: Allows users to hide their channels list from non- @@ -860,6 +819,11 @@ #<hostchange mask="a@b.com" action="set" value="blah.blah.blah"> #<hostchange mask="localhost" ports="7000,7001,7005-7007" action="set" value="blahblah.foo"> +# hostcycle: If loaded, when a user gets a host or ident set, it will +# cycle them in all their channels. If not loaded it will simply change +# their host/ident without cycling them. +#<module name="m_hostcycle.so"> + #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # httpd module: Provides http server support for InspIRCd #<module name="m_httpd.so"> @@ -955,8 +919,6 @@ #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Anti-Auto-Rejoin: Adds support for prevention of auto-rejoin (+J) #<module name="m_kicknorejoin.so"> -# Set the maximum time that is accepted as a parameter for +J here. -#<kicknorejoin maxtime="1m"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Knock module: adds the /KNOCK command and +K channel mode @@ -1273,7 +1235,7 @@ # Read the comment above <connect:allowmotdcolors> in # # inspircd.conf.example for details. # # # -#<opermotd file="conf/examples/opermotd.txt.example" onoper="yes" processcolors="false"> +#<opermotd file="examples/opermotd.txt.example" onoper="yes" processcolors="false"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Override module: Adds support for oper override @@ -1428,6 +1390,12 @@ #<module name="m_regex_pcre.so"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# +# Regular Expression Provider for RE2 Regular Expressions. +# You need libre2 installed and in your include/library paths in order +# to compile and load this module. +#<module name="m_regex_re2.so"> + +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Regular Expression Provider for POSIX Regular Expressions. # You shouldn't need any additional libraries on a POSIX-compatible # system (i.e.: any Linux, BSD, but not Windows). You must have at @@ -1472,6 +1440,26 @@ #<module name="m_remove.so"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# +# A module to block, kick or ban upon similiar messages being uttered several times. +# Syntax [~*][lines]:[sec]{[:difference]}{[:matchlines]} +# ~ is to block, * is to ban, default is kick. +# lines - In mode 1 the amount of lines that has to match consecutively - In mode 2 the size of the backlog to keep for matching +# seconds - How old the message has to be before it's invalidated. +# distance - Edit distance, in percent, between two strings to trigger on. +# matchlines - When set, the function goes into mode 2. In this mode the function will trigger if this many of the last <lines> matches. +# +# As this module can be rather CPU-intensive, it comes with some options. +# maxbacklog - Maximum size that can be specified for backlog. 0 disables multiline matching. +# maxdistance - Max percentage of difference between two lines we'll allow to match. Set to 0 to disable edit-distance matching. +# maxlines - Max lines of backlog to match against. +# maxsecs - Maximum value of seconds a user can set. 0 to allow any. +# size - Maximum number of characters to check for, can be used to truncate messages +# before they are checked, resulting in less CPU usage. Increasing this beyond 512 +# doesn't have any effect, as the maximum length of a message on IRC cannot exceed that. +#<repeat maxbacklog="20" maxlines="20" maxdistance="50" maxsecs="0" size="512"> +#<module name="m_repeat.so"> + +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Restricted channels module: Allows only opers to create channels. # # You probably *DO NOT* want to load this module on a public network. @@ -1511,6 +1499,13 @@ # so that at least \s or [[:space:]] is available. #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# +# RMODE module: Adds the /RMODE command +# Allows channel mods to remove list modes en masse. +# Syntax: /rmode <channel> <mode> [pattern] +# E.g. '/rmode #Channel b m:*' will remove all mute-extbans on the channel. +#<module name="m_rmode.so"> + +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # SAJOIN module: Adds the /SAJOIN command # This module is oper-only. # To use, SAJOIN must be in one of your oper class blocks. diff --git a/docs/conf/modules/unrealircd.conf.example b/docs/conf/modules/unrealircd.conf.example index 65896808f..afd54359c 100644 --- a/docs/conf/modules/unrealircd.conf.example +++ b/docs/conf/modules/unrealircd.conf.example @@ -93,15 +93,6 @@ <module name="m_chanfilter.so"> <chanfilter hidemask="yes"> -<module name="m_chanprotect.so"> - -<chanprotect - noservices="no" - qprefix="~" - aprefix="&" - deprotectself="yes" - deprotectothers="yes"> - <module name="m_check.so"> <module name="m_chghost.so"> <hostname charmap="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_/0123456789"> diff --git a/docs/conf/opers.conf.example b/docs/conf/opers.conf.example index 6cd00a409..e7b65b675 100644 --- a/docs/conf/opers.conf.example +++ b/docs/conf/opers.conf.example @@ -24,6 +24,7 @@ # - servers/auspex: allows opers with this priv to see more detail about server information than normal users. # ACTIONS: # - users/mass-message: allows opers with this priv to PRIVMSG and NOTICE to a server mask (e.g. NOTICE $*) + # - users/samode-usermodes: allows opers with this priv to change the user modes of any other user using /SAMODE # - channels/high-join-limit: allows opers with this priv to join <channels:opers> total channels instead of <channels:users> total channels. # PERMISSIONS: # - users/flood/no-throttle: allows opers with this priv to send commands without being throttled (*NOTE) diff --git a/include/bancache.h b/include/bancache.h index a7aac7f17..7f51ca75e 100644 --- a/include/bancache.h +++ b/include/bancache.h @@ -18,8 +18,7 @@ */ -#ifndef BANCACHE_H -#define BANCACHE_H +#pragma once /** Stores a cached ban entry. * Each ban has one of these hashed in a hash_map to make for faster removal @@ -37,68 +36,50 @@ class CoreExport BanCacheHit /** Reason, shown as quit message */ std::string Reason; - /** IP to match against, no wildcards here (of course) - */ - std::string IP; /** Time that the ban expires at */ time_t Expiry; - BanCacheHit(const std::string &ip, const std::string &type, const std::string &reason) + BanCacheHit(const std::string &type, const std::string &reason, time_t seconds) + : Type(type), Reason(reason), Expiry(ServerInstance->Time() + seconds) { - this->Type = type; - this->Reason = reason; - this->IP = ip; - this->Expiry = ServerInstance->Time() + 86400; // a day. this might seem long, but entries will be removed as glines/etc expire. } - // overridden to allow custom time - BanCacheHit(const std::string &ip, const std::string &type, const std::string &reason, time_t seconds) - { - this->Type = type; - this->Reason = reason; - this->IP = ip; - this->Expiry = ServerInstance->Time() + seconds; - } + bool IsPositive() const { return (!Reason.empty()); } }; /* A container of ban cache items. * must be defined after class BanCacheHit. */ -typedef nspace::hash_map<std::string, BanCacheHit*, nspace::hash<std::string> > BanCacheHash; +typedef TR1NS::unordered_map<std::string, BanCacheHit*, TR1NS::hash<std::string> > BanCacheHash; /** A manager for ban cache, which allocates and deallocates and checks cached bans. */ class CoreExport BanCacheManager { - private: BanCacheHash* BanHash; + bool RemoveIfExpired(BanCacheHash::iterator& it); + public: /** Creates and adds a Ban Cache item. * @param ip The IP the item is for. * @param type The type of ban cache item. std::string. .empty() means it's a negative match (user is allowed freely). * @param reason The reason for the ban. Left .empty() if it's a negative match. + * @param seconds Number of seconds before nuking the bancache entry, the default is a day. This might seem long, but entries will be removed as glines/etc expire. */ - BanCacheHit *AddHit(const std::string &ip, const std::string &type, const std::string &reason); - - // Overridden to allow an optional number of seconds before expiry - BanCacheHit *AddHit(const std::string &ip, const std::string &type, const std::string &reason, time_t seconds); + BanCacheHit *AddHit(const std::string &ip, const std::string &type, const std::string &reason, time_t seconds = 0); BanCacheHit *GetHit(const std::string &ip); - bool RemoveHit(BanCacheHit *b); /** Removes all entries of a given type, either positive or negative. Returns the number of hits removed. * @param type The type of bancache entries to remove (e.g. 'G') * @param positive Remove either positive (true) or negative (false) hits. */ - unsigned int RemoveEntries(const std::string &type, bool positive); + void RemoveEntries(const std::string& type, bool positive); BanCacheManager() { this->BanHash = new BanCacheHash(); } ~BanCacheManager(); - void RehashCache(); }; - -#endif diff --git a/include/base.h b/include/base.h index 0a4456f3a..c6d361576 100644 --- a/include/base.h +++ b/include/base.h @@ -20,8 +20,7 @@ */ -#ifndef BASE_H -#define BASE_H +#pragma once #include <map> #include <deque> @@ -255,5 +254,3 @@ class CoreExport ServiceProvider : public classbase virtual ~ServiceProvider(); }; - -#endif diff --git a/include/builtinmodes.h b/include/builtinmodes.h new file mode 100644 index 000000000..b1e5c3ccd --- /dev/null +++ b/include/builtinmodes.h @@ -0,0 +1,191 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> + * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> + * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "mode.h" +#include "channels.h" +#include "listmode.h" + +/** Channel mode +b + */ +class ModeChannelBan : public ListModeBase +{ + public: + ModeChannelBan() + : ListModeBase(NULL, "ban", 'b', "End of channel ban list", 367, 368, true, "maxbans") + { + } +}; + +/** Channel mode +i + */ +class ModeChannelInviteOnly : public SimpleChannelModeHandler +{ + public: + ModeChannelInviteOnly() : SimpleChannelModeHandler(NULL, "inviteonly", 'i') + { + } +}; + +/** Channel mode +k + */ +class ModeChannelKey : public ModeHandler +{ + public: + ModeChannelKey(); + ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); +}; + +/** Channel mode +l + */ +class ModeChannelLimit : public ParamChannelModeHandler +{ + public: + ModeChannelLimit(); + bool ParamValidate(std::string& parameter); + bool ResolveModeConflict(std::string &their_param, const std::string &our_param, Channel* channel); +}; + +/** Channel mode +m + */ +class ModeChannelModerated : public SimpleChannelModeHandler +{ + public: + ModeChannelModerated() : SimpleChannelModeHandler(NULL, "moderated", 'm') + { + } +}; + +/** Channel mode +n + */ +class ModeChannelNoExternal : public SimpleChannelModeHandler +{ + public: + ModeChannelNoExternal() : SimpleChannelModeHandler(NULL, "noextmsg", 'n') + { + } +}; + +/** Channel mode +o + */ +class ModeChannelOp : public ModeHandler +{ + private: + public: + ModeChannelOp(); + ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); + unsigned int GetPrefixRank(); +}; + +/** Channel mode +p + */ +class ModeChannelPrivate : public SimpleChannelModeHandler +{ + public: + ModeChannelPrivate() : SimpleChannelModeHandler(NULL, "private", 'p') + { + } +}; + +/** Channel mode +s + */ +class ModeChannelSecret : public SimpleChannelModeHandler +{ + public: + ModeChannelSecret() : SimpleChannelModeHandler(NULL, "secret", 's') + { + } +}; + +/** Channel mode +t + */ +class ModeChannelTopicOps : public SimpleChannelModeHandler +{ + public: + ModeChannelTopicOps() : SimpleChannelModeHandler(NULL, "topiclock", 't') + { + } +}; + +/** Channel mode +v + */ +class ModeChannelVoice : public ModeHandler +{ + private: + public: + ModeChannelVoice(); + ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); + unsigned int GetPrefixRank(); +}; + +/** User mode +i + */ +class ModeUserInvisible : public SimpleUserModeHandler +{ + public: + ModeUserInvisible() : SimpleUserModeHandler(NULL, "invisible", 'i') + { + } +}; + +/** User mode +s + */ +class ModeUserServerNoticeMask : public ModeHandler +{ + /** Process a snomask modifier string, e.g. +abc-de + * @param user The target user + * @param input A sequence of notice mask characters + * @return The cleaned mode sequence which can be output, + * e.g. in the above example if masks c and e are not + * valid, this function will return +ab-d + */ + std::string ProcessNoticeMasks(User* user, const std::string& input); + + public: + ModeUserServerNoticeMask(); + ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); + void OnParameterMissing(User* user, User* dest, Channel* channel); + + /** Create a displayable mode string of the snomasks set on a given user + * @param user The user whose notice masks to format + * @return The notice mask character sequence + */ + std::string GetUserParameter(User* user); +}; + +/** User mode +o + */ +class ModeUserOperator : public ModeHandler +{ + public: + ModeUserOperator(); + ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); +}; + +/** User mode +w + */ +class ModeUserWallops : public SimpleUserModeHandler +{ + public: + ModeUserWallops() : SimpleUserModeHandler(NULL, "wallops", 'w') + { + } +}; diff --git a/include/caller.h b/include/caller.h index 64b37611f..c3a29e8c2 100644 --- a/include/caller.h +++ b/include/caller.h @@ -3,6 +3,7 @@ * * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> + * Copyright (C) 2012 Adam <Adam@anope.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public @@ -18,8 +19,79 @@ */ -#ifndef CALLER_H -#define CALLER_H +#pragma once + +#if defined HAS_CXX11_VARIADIC_TEMPLATES + +template<typename ReturnType, typename... Args> class CoreExport Handler : public classbase +{ + public: + virtual ~Handler() { } + virtual ReturnType Call(Args...) = 0; +}; + +template<typename ReturnType, typename... Args> class CoreExport Caller +{ + public: + Handler<ReturnType, Args...>* target; + + Caller(Handler<ReturnType, Args...>* initial) : target(initial) { } + virtual ~Caller() { } + + virtual ReturnType operator()(const Args&... params) + { + return this->target->Call(params...); + } +}; + +/* Below here is compat with the old API */ +#define HandlerBase0 Handler +#define HandlerBase1 Handler +#define HandlerBase2 Handler +#define HandlerBase3 Handler +#define HandlerBase4 Handler +#define HandlerBase5 Handler +#define HandlerBase6 Handler +#define HandlerBase7 Handler +#define HandlerBase8 Handler + +#define caller1 Caller +#define caller2 Caller +#define caller3 Caller +#define caller4 Caller +#define caller5 Caller +#define caller6 Caller +#define caller7 Caller +#define caller8 Caller + +#define DEFINE_HANDLER0(NAME, RETURN) \ + class CoreExport NAME : public Handler<RETURN> { public: NAME() { } virtual RETURN Call(); } + +#define DEFINE_HANDLER1(NAME, RETURN, V1) \ + class CoreExport NAME : public Handler<RETURN, V1> { public: NAME() { } virtual RETURN Call(V1); } + +#define DEFINE_HANDLER2(NAME, RETURN, V1, V2) \ + class CoreExport NAME : public Handler<RETURN, V1, V2> { public: NAME() { } virtual RETURN Call(V1, V2); } + +#define DEFINE_HANDLER3(NAME, RETURN, V1, V2, V3) \ + class CoreExport NAME : public Handler<RETURN, V1, V2, V3> { public: NAME() { } virtual RETURN Call(V1, V2, V3); } + +#define DEFINE_HANDLER4(NAME, RETURN, V1, V2, V3, V4) \ + class CoreExport NAME : public Handler<RETURN, V1, V2, V3, V4> { public: NAME() { } virtual RETURN Call(V1, V2, V3, V4); } + +#define DEFINE_HANDLER5(NAME, RETURN, V1, V2, V3, V4, V5) \ + class CoreExport NAME : public Handler<RETURN, V1, V2, V3, V4, V5> { public: NAME() { } virtual RETURN Call(V1, V2, V3, V4, V5); } + +#define DEFINE_HANDLER6(NAME, RETURN, V1, V2, V3, V4, V5, V6) \ + class CoreExport NAME : public Handler<RETURN, V1, V2, V3, V4, V5, V6> { public: NAME() { } virtual RETURN Call(V1, V2, V3, V4, V5, V6); } + +#define DEFINE_HANDLER7(NAME, RETURN, V1, V2, V3, V4, V5, V6, V7) \ + class CoreExport NAME : public Handler<RETURN, V1, V2, V3, V4, V5, V6, V7> { public: NAME() { } virtual RETURN Call(V1, V2, V3, V4, V5, V6, V7); } + +#define DEFINE_HANDLER8(NAME, RETURN, V1, V2, V3, V4, V5, V6, V7, V8) \ + class CoreExport NAME : public Handler<RETURN, V1, V2, V3, V4, V5, V6, V7, V8> { public: NAME() { } virtual RETURN Call(V1, V2, V3, V4, V5, V6, V7, V8); } + +#else /** The templates below can be auto generated by tools/create_templates.pl. * They are used to represent a functor with a given number of parameters and diff --git a/include/channels.h b/include/channels.h index dda53f69d..0c7a3a20c 100644 --- a/include/channels.h +++ b/include/channels.h @@ -20,8 +20,7 @@ */ -#ifndef CHANNELS_H -#define CHANNELS_H +#pragma once #include "membership.h" #include "mode.h" @@ -29,28 +28,6 @@ /** Holds an entry for a ban list, exemption list, or invite list. * This class contains a single element in a channel list, such as a banlist. */ -class HostItem -{ - public: - /** Time the item was added - */ - time_t set_time; - /** Who added the item - */ - std::string set_by; - /** The actual item data - */ - std::string data; - - HostItem() { /* stub */ } - virtual ~HostItem() { /* stub */ } -}; - -/** A subclass of HostItem designed to hold channel bans (+b) - */ -class BanItem : public HostItem -{ -}; /** Holds all relevent information for a channel. * This class represents a channel, and contains its name, modes, topic, topic set time, @@ -58,18 +35,10 @@ class BanItem : public HostItem */ class CoreExport Channel : public Extensible, public InviteBase { - /** Connect a Channel to a User - */ - static Channel* ForceChan(Channel* Ptr, User* user, const std::string &privs, bool bursting, bool created); - /** Set default modes for the channel on creation */ void SetDefaultModes(); - /** Maximum number of bans (cached) - */ - int maxbans; - /** Modes for the channel. * This is not a null terminated string! It is a bitset where * each item in it represents if a mode is set. For example @@ -83,12 +52,34 @@ class CoreExport Channel : public Extensible, public InviteBase */ CustomModeList custom_mode_params; + /** Remove the given membership from the channel's internal map of + * memberships and destroy the Membership object. + * This function does not remove the channel from User::chanlist. + * Since the parameter is an iterator to the target, the complexity + * of this function is constant. + * @param membiter The UserMembIter to remove, must be valid + */ + void DelUser(const UserMembIter& membiter); + public: /** Creates a channel record and initialises it with default values - * @throw Nothing at present. + * @param name The name of the channel + * @param ts The creation time of the channel + * @throw CoreException if this channel name is in use */ Channel(const std::string &name, time_t ts); + /** Checks whether the channel should be destroyed, and if yes, begins + * the teardown procedure. + * + * If there are users on the channel or a module vetoes the deletion + * (OnPreChannelDelete hook) then nothing else happens. + * Otherwise, first the OnChannelDelete event is fired, then the channel is + * removed from the channel list. All pending invites are destroyed and + * finally the channel is added to the cull list. + */ + void CheckDestroy(); + /** The channel's name. */ std::string name; @@ -116,16 +107,11 @@ class CoreExport Channel : public Extensible, public InviteBase */ std::string setby; /* 128 */ - /** The list of all bans set on the channel. - */ - BanList bans; - /** Sets or unsets a custom mode in the channels info * @param mode The mode character to set or unset * @param value True if you want to set the mode or false if you want to remove it */ void SetMode(ModeHandler* mode, bool value); - void SetMode(char mode,bool mode_on); /** Sets or unsets a custom mode in the channels info * @param mode The mode character to set or unset @@ -133,15 +119,14 @@ class CoreExport Channel : public Extensible, public InviteBase * If it is empty, the mode is unset; if it is nonempty, the mode is set. */ void SetModeParam(ModeHandler* mode, const std::string& parameter); - void SetModeParam(char mode, const std::string& parameter); /** Returns true if a mode is set on a channel * @param mode The mode character you wish to query * @return True if the custom mode is set, false if otherwise */ - inline bool IsModeSet(char mode) { return modes[mode-'A']; } inline bool IsModeSet(ModeHandler* mode) { return modes[mode->GetModeChar()-'A']; } - + bool IsModeSet(ModeHandler& mode) { return IsModeSet(&mode); } + bool IsModeSet(ChanModeReference& mode); /** Returns the parameter for a custom mode on a channel. * @param mode The mode character you wish to query @@ -153,24 +138,21 @@ class CoreExport Channel : public Extensible, public InviteBase * * @return The parameter for this mode is returned, or an empty string */ - std::string GetModeParameter(char mode); std::string GetModeParameter(ModeHandler* mode); + std::string GetModeParameter(ChanModeReference& mode); /** Sets the channel topic. - * @param u The user setting the topic - * @param t The topic to set it to. Non-const, as it may be modified by a hook. - * @param forceset If set to true then all access checks will be bypassed. + * @param user The user setting the topic. + * @param topic The topic to set it to. */ - int SetTopic(User *u, std::string &t, bool forceset = false); + void SetTopic(User* user, const std::string& topic); /** Obtain the channel "user counter" - * This returns the channel reference counter, which is initialized - * to 0 when the channel is created and incremented/decremented - * upon joins, parts quits and kicks. + * This returns the number of users on this channel * * @return The number of users on this channel */ - long GetUserCounter(); + long GetUserCounter() const { return userlist.size(); } /** Add a user pointer to the internal reference list * @param user The user to add @@ -196,7 +178,7 @@ class CoreExport Channel : public Extensible, public InviteBase * * @return This function returns pointer to a map of User pointers (CUList*). */ - const UserMembList* GetUsers(); + const UserMembList* GetUsers() const { return &userlist; } /** Returns true if the user given is on the given channel. * @param user The user to look for @@ -210,8 +192,9 @@ class CoreExport Channel : public Extensible, public InviteBase * @param src The source of the kick * @param user The user being kicked (must be on this channel) * @param reason The reason for the kick + * @param srcmemb The membership of the user who does the kick, can be NULL */ - void KickUser(User *src, User *user, const char* reason); + void KickUser(User* src, User* user, const std::string& reason, Membership* srcmemb = NULL); /** Part a user from this channel with the given reason. * If the reason field is NULL, no reason will be sent. @@ -220,16 +203,24 @@ class CoreExport Channel : public Extensible, public InviteBase */ void PartUser(User *user, std::string &reason); - /* Join a user to a channel. May be a channel that doesnt exist yet. + /** Join a local user to a channel, with or without permission checks. May be a channel that doesn't exist yet. * @param user The user to join to the channel. - * @param cn The channel name to join to. Does not have to exist. + * @param channame The channel name to join to. Does not have to exist. * @param key The key of the channel, if given * @param override If true, override all join restrictions such as +bkil * @return A pointer to the Channel the user was joined to. A new Channel may have * been created if the channel did not exist before the user was joined to it. - * If the user could not be joined to a channel, the return value may be NULL. + * If the user could not be joined to a channel, the return value is NULL. + */ + static Channel* JoinUser(LocalUser* user, std::string channame, bool override = false, const std::string& key = ""); + + /** Join a user to an existing channel, without doing any permission checks + * @param user The user to join to the channel + * @param privs Priviliges (prefix mode letters) to give to this user, may be NULL + * @param bursting True if this join is the result of a netburst (passed to modules in the OnUserJoin hook) + * @param created_by_local True if this channel was just created by a local user (passed to modules in the OnUserJoin hook) */ - static Channel* JoinUser(User *user, const char* cn, bool override, const char* key, bool bursting, time_t TS = 0); + void ForceJoin(User* user, const std::string* privs = NULL, bool bursting = false, bool created_by_local = false); /** Write to a channel, from a user, using va_args for text * @param user User whos details to prefix the line with @@ -301,28 +292,18 @@ class CoreExport Channel : public Extensible, public InviteBase /** Write a line of text that already includes the source */ void RawWriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const std::string& text); - /** Returns the maximum number of bans allowed to be set on this channel - * @return The maximum number of bans allowed - */ - long GetMaxBans(); - /** Return the channel's modes with parameters. * @param showkey If this is set to true, the actual key is shown, * otherwise it is replaced with '<KEY>' * @return The channel mode string */ - char* ChanModes(bool showkey); + const char* ChanModes(bool showkey); /** Spool the NAMES list for this channel to the given user * @param user The user to spool the NAMES list to */ void UserList(User *user); - /** Get the number of invisible users on this channel - * @return Number of invisible users - */ - int CountInvisible(); - /** Get a users prefix on this channel in a string. * @param user The user to look up * @return A character array containing the prefix string. @@ -357,13 +338,6 @@ class CoreExport Channel : public Extensible, public InviteBase */ unsigned int GetPrefixValue(User* user); - /** This method removes all prefix characters from a user. - * It will not inform the user or the channel of the removal of prefixes, - * and should be used when the user parts or quits. - * @param user The user to remove all prefixes from - */ - void RemoveAllPrefixes(User* user); - /** Add a prefix character to a user. * Only the core should call this method, usually from * within the mode parser or when the first user joins @@ -388,10 +362,23 @@ class CoreExport Channel : public Extensible, public InviteBase /** Get the status of an "action" type extban */ ModResult GetExtBanStatus(User *u, char type); - - /** Clears the cached max bans value - */ - void ResetMaxBans(); }; -#endif +inline bool Channel::HasUser(User* user) +{ + return (userlist.find(user) != userlist.end()); +} + +inline std::string Channel::GetModeParameter(ChanModeReference& mode) +{ + if (!mode) + return ""; + return GetModeParameter(*mode); +} + +inline bool Channel::IsModeSet(ChanModeReference& mode) +{ + if (!mode) + return false; + return IsModeSet(*mode); +} diff --git a/include/command_parse.h b/include/command_parse.h index f9e3a740c..6682bc4fb 100644 --- a/include/command_parse.h +++ b/include/command_parse.h @@ -20,8 +20,7 @@ */ -#ifndef COMMAND_PARSE_H -#define COMMAND_PARSE_H +#pragma once /** This class handles command management and parsing. * It allows you to add and remove commands from the map, @@ -31,18 +30,11 @@ class CoreExport CommandParser { private: - /** Process a parameter string into a list of items - * @param command_p The output list of items - * @param parameters The input string - * @return The number of parameters parsed into command_p - */ - int ProcessParameters(std::vector<std::string>& command_p, char* parameters); - /** Process a command from a user. * @param user The user to parse the command for * @param cmd The command string to process */ - bool ProcessCommand(LocalUser *user, std::string &cmd); + void ProcessCommand(LocalUser* user, std::string& cmd); public: /** Command list, a hash_map of command names to Command* @@ -71,44 +63,50 @@ class CoreExport CommandParser */ Command* GetHandler(const std::string &commandname); - /** This function returns true if a command is valid with the given number of parameters and user. - * @param commandname The command name to check - * @param pcnt The parameter count - * @param user The user to check against - * @return If the user given has permission to execute the command, and the parameter count is - * equal to or greater than the minimum number of parameters to the given command, then this - * function will return true, otherwise it will return false. - */ - bool IsValidCommand(const std::string &commandname, unsigned int pcnt, User * user); - - /** LoopCall is used to call a command classes handler repeatedly based on the contents of a comma seperated list. - * There are two overriden versions of this method, one of which takes two potential lists and the other takes one. - * We need a version which takes two potential lists for JOIN, because a JOIN may contain two lists of items at once, + /** LoopCall is used to call a command handler repeatedly based on the contents of a comma seperated list. + * There are two ways to call this method, either with one potential list or with two potential lists. + * We need to handle two potential lists for JOIN, because a JOIN may contain two lists of items at once: * the channel names and their keys as follows: * * JOIN \#chan1,\#chan2,\#chan3 key1,,key3 * - * Therefore, we need to deal with both lists concurrently. The first instance of this method does that by creating - * two instances of irc::commasepstream and reading them both together until the first runs out of tokens. - * The second version is much simpler and just has the one stream to read, and is used in NAMES, WHOIS, PRIVMSG etc. - * Both will only parse until they reach ServerInstance->Config->MaxTargets number of targets, to stop abuse via spam. + * Therefore, we need to deal with both lists concurrently. If there are two lists then the method reads + * them both together until the first runs out of tokens. + * With one list it is much simpler, and is used in NAMES, WHOIS, PRIVMSG etc. + * + * If there is only one list and there are duplicates in it, then the command handler is only called for + * unique items. Entries are compared using "irc comparision" (see irc::string). + * If the usemax parameter is true (the default) the function only parses until it reaches + * ServerInstance->Config->MaxTargets number of targets, to stop abuse via spam. + * + * The OnPostCommand hook is executed for each item after it has been processed by the handler, with the + * original line parameter being empty (to indicate that the command in that form was created by this function). + * This only applies if the user executing the command is local. + * + * If there are two lists and the second list runs out of tokens before the first list then parameters[extra] + * will be an EMPTY string when Handle() is called for the remaining tokens in the first list, even if it is + * in the middle of parameters[]! Moreover, empty tokens in the second list are allowed, and those will also + * result in the appropiate entry being empty in parameters[]. + * This is different than what command handlers usually expect; the command parser only allows an empty param + * as the last item in the vector. * * @param user The user who sent the command - * @param CommandObj the command object to call for each parameter in the list - * @param parameters Parameter list as an array of array of char (that's not a typo). + * @param handler The command handler to call for each parameter in the list + * @param parameters Parameter list as a vector of strings * @param splithere The first parameter index to split as a comma seperated list - * @param extra The second parameter index to split as a comma seperated list - * @param usemax Limit the command to MaxTargets targets - * @return This function will return 1 when there are no more parameters to process. When this occurs, its - * caller should return without doing anything, otherwise it should continue into its main section of code. + * @param extra The second parameter index to split as a comma seperated list, or -1 (the default) if there is only one list + * @param usemax True to limit the command to MaxTargets targets (default), or false to process all tokens + * @return This function returns true when it identified a list in the given parameter and finished calling the + * command handler for each entry on the list. When this occurs, the caller should return without doing anything, + * otherwise it should continue into its main section of code. */ - int LoopCall(User* user, Command* CommandObj, const std::vector<std::string>& parameters, unsigned int splithere, int extra = -1, bool usemax = true); + static bool LoopCall(User* user, Command* handler, const std::vector<std::string>& parameters, unsigned int splithere, int extra = -1, bool usemax = true); /** Take a raw input buffer from a recvq, and process it on behalf of a user. * @param buffer The buffer line to process * @param user The user to whom this line belongs */ - bool ProcessBuffer(std::string &buffer,LocalUser *user); + void ProcessBuffer(std::string &buffer,LocalUser *user); /** Add a new command to the commands hash * @param f The new Command to add to the list @@ -120,23 +118,23 @@ class CoreExport CommandParser */ void RemoveCommand(Command* x); - /** Translate nicknames in a string into UIDs, based on the TranslationType given. - * @param to The translation type to use for the process. - * @param source The input string - * @param dest The output string, it is safe to pass source and dest as the same variable only for translation type TR_TEXT. - * @return returns the number of substitutions made. Will always be 0 or 1 + /** Translate a single item based on the TranslationType given. + * @param to The translation type to use for the process + * @param item The input string + * @param dest The output string. The translation result will be appended to this string + * @param custom_translator Used to translate the parameter if the translation type is TR_CUSTOM, if NULL, TR_CUSTOM will act like TR_TEXT + * @param paramnumber The index of the parameter we are translating. */ - int TranslateUIDs(TranslateType to, const std::string &source, std::string &dest); + static void TranslateSingleParam(TranslateType to, const std::string& item, std::string& dest, CommandBase* custom_translator = NULL, unsigned int paramnumber = 0); /** Translate nicknames in a list of strings into UIDs, based on the TranslateTypes given. * @param to The translation types to use for the process. If this list is too short, TR_TEXT is assumed for the rest. * @param source The strings to translate - * @param dest The output string * @param prefix_final True if the final source argument should have a colon prepended (if it could contain a space) - * @param custom_translator Used to translate the parameter if the TR_CUSTOM type is found in to - * @return returns the number of substitutions made. + * @param custom_translator Used to translate the parameter if the translation type is TR_CUSTOM, if NULL, TR_CUSTOM will act like TR_TEXT + * @return dest The output string */ - int TranslateUIDs(const std::vector<TranslateType> to, const std::vector<std::string> &source, std::string &dest, bool prefix_final = false, Command* custom_translator = NULL); + static std::string TranslateUIDs(const std::vector<TranslateType>& to, const std::vector<std::string>& source, bool prefix_final = false, CommandBase* custom_translator = NULL); }; /** A lookup table of values for multiplier characters used by @@ -165,5 +163,3 @@ const int duration_multi[] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; - -#endif diff --git a/include/commands/cmd_whowas.h b/include/commands/cmd_whowas.h index d33354122..0a38b44f1 100644 --- a/include/commands/cmd_whowas.h +++ b/include/commands/cmd_whowas.h @@ -19,39 +19,13 @@ */ -#ifndef CMD_WHOWAS_H -#define CMD_WHOWAS_H -#include "modules.h" - -struct WhowasRequest : public Request -{ - /* list of available internal commands */ - enum Internals - { - WHOWAS_ADD = 1, - WHOWAS_STATS = 2, - WHOWAS_PRUNE = 3, - WHOWAS_MAINTAIN = 4 - }; - - const Internals type; - std::string value; - User* user; - - WhowasRequest(Module* src, Module* whowas, Internals Type) : Request(src, whowas, "WHOWAS"), type(Type) - {} -}; +#pragma once -/* Forward ref for timer */ -class WhoWasMaintainTimer; +#include "modules.h" /* Forward ref for typedefs */ class WhoWasGroup; -/** Timer that is used to maintain the whowas list, called once an hour - */ -extern WhoWasMaintainTimer* timer; - /** A group of users related by nickname */ typedef std::deque<WhoWasGroup*> whowas_set; @@ -72,15 +46,28 @@ typedef std::deque<std::pair<time_t,irc::string> > whowas_users_fifo; class CommandWhowas : public Command { private: - /** Whowas container, contains a map of vectors of users tracked by WHOWAS + /** Primary container, links nicknames tracked by WHOWAS to a list of records */ whowas_users whowas; - /** Whowas container, contains a map of time_t to users tracked by WHOWAS + /** List of nicknames in the order they were inserted into the map */ whowas_users_fifo whowas_fifo; public: + /** Max number of WhoWas entries per user. + */ + unsigned int GroupSize; + + /** Max number of cumulative user-entries in WhoWas. + * When max reached and added to, push out oldest entry FIFO style. + */ + unsigned int MaxGroups; + + /** Max seconds a user is kept in WhoWas before being pruned. + */ + unsigned int MaxKeep; + CommandWhowas(Module* parent); /** Handle command. * @param parameters The parameters to the comamnd @@ -91,8 +78,8 @@ class CommandWhowas : public Command CmdResult Handle(const std::vector<std::string>& parameters, User *user); void AddToWhoWas(User* user); std::string GetStats(); - void PruneWhoWas(time_t t); - void MaintainWhoWas(time_t t); + void Prune(); + void Maintain(); ~CommandWhowas(); }; @@ -123,19 +110,4 @@ class WhoWasGroup /** Initialize this WhoWasFroup with a user */ WhoWasGroup(User* user); - /** Destructor - */ - ~WhoWasGroup(); }; - -class WhoWasMaintainTimer : public Timer -{ - public: - WhoWasMaintainTimer(long interval) - : Timer(interval, ServerInstance->Time(), true) - { - } - virtual void Tick(time_t TIME); -}; - -#endif diff --git a/include/compat.h b/include/compat.h new file mode 100644 index 000000000..1cdad06c2 --- /dev/null +++ b/include/compat.h @@ -0,0 +1,116 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Peter Powell <petpow@saberuk.com> + * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> + * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +/** + * Some implementations of the C++11 standard library are incomplete so we use + * the implementation of the same types from C++ Technical Report 1 instead. + */ +#if defined _LIBCPP_VERSION || defined _WIN32 +# define TR1NS std +# include <unordered_map> +#else +# define TR1NS std::tr1 +# include <tr1/unordered_map> +#endif + +/** + * This macro enables the compile-time checking of printf format strings. This + * makes the compiler show a warning if the format of a printf arguments are + * incorrect. + */ +#if defined __clang__ || defined __GNUC__ +# define CUSTOM_PRINTF(stringpos, firstpos) __attribute__((format(printf, stringpos, firstpos))) +#else +# pragma message ("Warning! CUSTOM_PRINTF() does not work on your compiler!") +# define CUSTOM_PRINTF(stringpos, firstpos) +#endif + +/** + * These macros enable the use of the C++11 override control keywords in + * compilers which support them. + */ +#if __cplusplus >= 201103L +# define HAS_CXX11_FINAL_OVERRIDE +#elif defined __clang__ +# if __has_feature(cxx_override_control) +# define HAS_CXX11_FINAL_OVERRIDE +# endif +#elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) +# if defined __GXX_EXPERIMENTAL_CXX0X__ +# define HAS_CXX11_FINAL_OVERRIDE +# endif +#elif _MSC_VER >= 1700 +# define HAS_CXX11_FINAL_OVERRIDE +#endif + +#if defined HAS_CXX11_FINAL_OVERRIDE +# define CXX11_FINAL final +# define CXX11_OVERRIDE override +#else +# define CXX11_FINAL +# define CXX11_OVERRIDE +#endif + +/** + * These macros enable the detection of the C++11 variadic templates in + * compilers which support them. + */ +#if __cplusplus >= 201103L +# define HAS_CXX11_VARIADIC_TEMPLATES +#elif defined __clang__ +# if __has_feature(cxx_variadic_templates) +# define HAS_CXX11_VARIADIC_TEMPLATES +# endif +#elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) +# if defined __GXX_EXPERIMENTAL_CXX0X__ +# define HAS_CXX11_VARIADIC_TEMPLATES +# endif +#elif _MSC_FULL_VER >= 170051025 +# define HAS_CXX11_VARIADIC_TEMPLATES +#endif + +/** + * This macro allows methods to be marked as deprecated. To use this, wrap the + * method declaration in the header file with the macro. + */ +#if defined __clang__ || defined __GNUC__ +# define DEPRECATED_METHOD(function) function __attribute__((deprecated)) +#elif defined _MSC_VER +# define DEPRECATED_METHOD(function) __declspec(deprecated) function +#else +# pragma message ("Warning! DEPRECATED_METHOD() does not work on your compiler!") +# define DEPRECATED_METHOD(function) function +#endif + +/** + * Windows is very different to UNIX so we have to wrap certain features in + * order to build on Windows correctly. + */ +#if defined _WIN32 +# include "inspircd_win32wrapper.h" +#else +# include <unistd.h> +# define ENTRYPOINT int main(int argc, char** argv) +# define DllExport +# define CoreExport +#endif diff --git a/include/configparser.h b/include/configparser.h index 999d79e24..8292fdda5 100644 --- a/include/configparser.h +++ b/include/configparser.h @@ -17,6 +17,8 @@ */ +#pragma once + struct fpos { std::string filename; @@ -31,7 +33,7 @@ struct fpos enum ParseFlags { - FLAG_USE_XML = 1, + FLAG_USE_COMPAT = 1, FLAG_NO_EXEC = 2, FLAG_NO_INC = 4 }; @@ -76,5 +78,3 @@ struct FileWrapper } } }; - - diff --git a/include/configreader.h b/include/configreader.h index 09d4e619d..6786604b5 100644 --- a/include/configreader.h +++ b/include/configreader.h @@ -21,8 +21,7 @@ */ -#ifndef INSPIRCD_CONFIGREADER -#define INSPIRCD_CONFIGREADER +#pragma once #include <sstream> #include <string> @@ -45,12 +44,22 @@ class CoreExport ConfigTag : public refcountbase /** Get the value of an option, using def if it does not exist */ std::string getString(const std::string& key, const std::string& def = ""); /** Get the value of an option, using def if it does not exist */ - long getInt(const std::string& key, long def = 0); + long getInt(const std::string& key, long def = 0, long min = LONG_MIN, long max = LONG_MAX); /** Get the value of an option, using def if it does not exist */ double getFloat(const std::string& key, double def = 0); /** Get the value of an option, using def if it does not exist */ bool getBool(const std::string& key, bool def = false); + /** Get the value in seconds of a duration that is in the user-friendly "1h2m3s" format, + * using a default value if it does not exist or is out of bounds. + * @param key The config key name + * @param def Default value (optional) + * @param min Minimum acceptable value (optional) + * @param max Maximum acceptable value (optional) + * @return The duration in seconds + */ + long getDuration(const std::string& key, long def = 0, long min = LONG_MIN, long max = LONG_MAX); + /** Get the value of an option * @param key The option to get * @param value The location to store the value (unmodified if does not exist) @@ -59,6 +68,16 @@ class CoreExport ConfigTag : public refcountbase */ bool readString(const std::string& key, std::string& value, bool allow_newline = false); + /** Check for an out of range value. If the value falls outside the boundaries a warning is + * logged and the value is corrected (set to def). + * @param key The key name, used in the warning message + * @param res The value to verify and modify if needed + * @param def The default value, res will be set to this if (min <= res <= max) doesn't hold true + * @param min Minimum accepted value for res + * @param max Maximum accepted value for res + */ + void CheckRange(const std::string& key, long& res, long def, long min, long max); + std::string getTagLocation(); inline const std::vector<KeyVal>& getItems() const { return items; } @@ -94,14 +113,16 @@ class ServerLimits size_t MaxGecos; /** Maximum away message length */ size_t MaxAway; + /** Maximum line length */ + size_t MaxLine; /** Creating the class initialises it to the defaults * as in 1.1's ./configure script. Reading other values * from the config will change these values. */ - ServerLimits() : NickMax(31), ChanMax(64), MaxModes(20), IdentMax(12), MaxQuit(255), MaxTopic(307), MaxKick(255), MaxGecos(128), MaxAway(200) - { - } + ServerLimits() : NickMax(31), ChanMax(64), MaxModes(20), IdentMax(12), + MaxQuit(255), MaxTopic(307), MaxKick(255), MaxGecos(128), MaxAway(200), + MaxLine(512) { } }; struct CommandLineConf @@ -143,8 +164,6 @@ struct CommandLineConf /** Saved argv from startup */ char** argv; - - std::string startup_log; }; class CoreExport OperInfo : public refcountbase @@ -171,11 +190,6 @@ class CoreExport OperInfo : public refcountbase /** Get a configuration item, searching in the oper, type, and class blocks (in that order) */ std::string getConfig(const std::string& key); void init(); - - inline const char* NameStr() - { - return irc::Spacify(name.c_str()); - } }; /** This class holds the bulk of the runtime configuration for the ircd. @@ -190,6 +204,32 @@ class CoreExport ServerConfig void CrossCheckConnectBlocks(ServerConfig* current); public: + class ServerPaths + { + public: + /** Config path */ + std::string Config; + + /** Data path */ + std::string Data; + + /** Log path */ + std::string Log; + + /** Module path */ + std::string Module; + + ServerPaths() + : Config(CONFIG_PATH) + , Data(DATA_PATH) + , Log(LOG_PATH) + , Module(MOD_PATH) { } + + std::string PrependConfig(const std::string& fn) const { return ServerConfig::ExpandPath(Config, fn); } + std::string PrependData(const std::string& fn) const { return ServerConfig::ExpandPath(Data, fn); } + std::string PrependLog(const std::string& fn) const { return ServerConfig::ExpandPath(Log, fn); } + std::string PrependModule(const std::string& fn) const { return ServerConfig::ExpandPath(Module, fn); } + }; /** Get a configuration tag * @param tag The name of the tag to get @@ -226,6 +266,9 @@ class CoreExport ServerConfig */ ServerLimits Limits; + /** Locations of various types of file (config, module, etc). */ + ServerPaths Paths; + /** Configuration parsed from the command line. */ CommandLineConf cmdline; @@ -240,27 +283,14 @@ class CoreExport ServerConfig */ int c_ipv6_range; - /** Max number of WhoWas entries per user. - */ - int WhoWasGroupSize; - - /** Max number of cumulative user-entries in WhoWas. - * When max reached and added to, push out oldest entry FIFO style. - */ - int WhoWasMaxGroups; - - /** Max seconds a user is kept in WhoWas before being pruned. - */ - int WhoWasMaxKeep; - /** Holds the server name of the local server * as defined by the administrator. */ std::string ServerName; - /** Notice to give to users when they are Xlined + /** Notice to give to users when they are banned by an XLine */ - std::string MoronBanner; + std::string XLineMessage; /* Holds the network name the local server * belongs to. This is an arbitary field defined @@ -334,10 +364,6 @@ class CoreExport ServerConfig */ std::string FixedPart; - /** The DNS server to use for DNS queries - */ - std::string DNSServer; - /** Pretend disabled commands don't exist. */ bool DisabledDontExist; @@ -356,13 +382,6 @@ class CoreExport ServerConfig */ char DisabledCModes[64]; - /** The full path to the modules directory. - * This is either set at compile time, or - * overridden in the configuration file via - * the \<path> tag. - */ - std::string ModPath; - /** If set to true, then all opers on this server are * shown with a generic 'is an IRC operator' line rather * than the oper type. Oper types are still used internally. @@ -396,6 +415,13 @@ class CoreExport ServerConfig */ int MaxConn; + /** If we should check for clones during CheckClass() in AddUser() + * Setting this to false allows to not trigger on maxclones for users + * that may belong to another class after DNS-lookup is complete. + * It does, however, make the server spend more time on users we may potentially not want. + */ + bool CCOnConnect; + /** The soft limit value assigned to the irc server. * The IRC server will not allow more than this * number of local users. @@ -445,16 +471,6 @@ class CoreExport ServerConfig */ ClassVector Classes; - /** The 005 tokens of this server (ISUPPORT) - * populated/repopulated upon loading or unloading - * modules. - */ - std::string data005; - - /** isupport strings - */ - std::vector<std::string> isupport; - /** STATS characters in this list are available * only to operators. */ @@ -472,23 +488,10 @@ class CoreExport ServerConfig */ std::map<irc::string, bool> ulines; - /** Max banlist sizes for channels (the std::string is a glob) - */ - std::map<std::string, int> maxbans; - - /** If set to true, no user DNS lookups are to be performed - */ - bool NoUserDns; - /** If set to true, provide syntax hints for unknown commands */ bool SyntaxHints; - /** If set to true, users appear to quit then rejoin when their hosts change. - * This keeps clients synchronized properly. - */ - bool CycleHosts; - /** If set to true, the CycleHosts mode change will be sourced from the user, * rather than the server */ @@ -504,11 +507,14 @@ class CoreExport ServerConfig */ bool FullHostInTopic; - /** Oper block and type index. - * For anonymous oper blocks (type only), prefix with a space. + /** Oper blocks keyed by their name */ OperIndex oper_blocks; + /** Oper types keyed by their name + */ + OperIndex OperTypes; + /** Max channels per user */ unsigned int MaxChans; @@ -530,15 +536,7 @@ class CoreExport ServerConfig /** Get server ID as string with required leading zeroes */ - const std::string& GetSID(); - - /** Update the 005 vector - */ - void Update005(); - - /** Send the 005 numerics (ISUPPORT) to a user - */ - void Send005(User* user); + const std::string& GetSID() const { return sid; } /** Read the entire configuration into memory * and initialize this class. All other methods @@ -555,7 +553,7 @@ class CoreExport ServerConfig /** Returns true if the given string starts with a windows drive letter */ - bool StartsWithWindowsDriveLetter(const std::string &path); + static bool StartsWithWindowsDriveLetter(const std::string& path); bool ApplyDisabledCommands(const std::string& data); @@ -571,6 +569,18 @@ class CoreExport ServerConfig */ static bool FileExists(const char* file); + /** Expands a path fragment to a full path. + * @param base The base path to expand from + * @param fragment The path fragment to expand on top of base. + */ + static std::string ExpandPath(const std::string& base, const std::string& fragment); + + /** Escapes a value for storage in a configuration key. + * @param str The string to escape. + * @param xml Are we using the XML config format? + */ + static std::string Escape(const std::string& str, bool xml = true); + /** If this value is true, invites will bypass more than just +i */ bool InvBypassModes; @@ -578,11 +588,6 @@ class CoreExport ServerConfig /** If this value is true, snotices will not stack when repeats are sent */ bool NoSnoticeStack; - - /** If true, a "Welcome to <networkname>!" NOTICE will be sent to - * connecting users - */ - bool WelcomeNotice; }; /** The background thread for config reading, so that reading from executable includes @@ -609,5 +614,3 @@ class CoreExport ConfigReaderThread : public Thread void Finish(); bool IsDone() { return done; } }; - -#endif diff --git a/include/consolecolors.h b/include/consolecolors.h index f7ca1335e..9b7e0670a 100644 --- a/include/consolecolors.h +++ b/include/consolecolors.h @@ -14,8 +14,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef CONSOLECOLORS_H -#define CONSOLECOLORS_H + +#pragma once #include <ostream> @@ -96,5 +96,3 @@ inline std::ostream& con_reset(std::ostream &s) } #endif - -#endif diff --git a/include/ctables.h b/include/ctables.h index f9cd08cb3..747901459 100644 --- a/include/ctables.h +++ b/include/ctables.h @@ -21,8 +21,7 @@ */ -#ifndef CTABLES_H -#define CTABLES_H +#pragma once /** Used to indicate command success codes */ @@ -44,7 +43,6 @@ const char FLAG_SERVERONLY = 7; // technically anything nonzero below 'A' works */ enum TranslateType { - TR_END, /* End of known parameters, everything after this is TR_TEXT */ TR_TEXT, /* Raw text, leave as-is */ TR_NICK, /* Nickname, translate to UUID for server->server */ TR_CUSTOM /* Custom translation handled by EncodeParameter/DecodeParameter */ @@ -99,7 +97,7 @@ struct RouteDescriptor /** A structure that defines a command. Every command available * in InspIRCd must be defined as derived from Command. */ -class CoreExport Command : public ServiceProvider +class CoreExport CommandBase : public ServiceProvider { public: /** User flags needed to execute the command or 0 @@ -120,10 +118,6 @@ class CoreExport Command : public ServiceProvider */ unsigned long use_count; - /** used by /stats m - */ - unsigned long total_bytes; - /** True if the command is disabled to non-opers */ bool disabled; @@ -162,20 +156,13 @@ class CoreExport Command : public ServiceProvider * @param maxpara Maximum number of parameters this command may have - extra parameters * will be tossed into one last space-seperated param. */ - Command(Module* me, const std::string &cmd, int minpara = 0, int maxpara = 0) : + CommandBase(Module* me, const std::string &cmd, int minpara = 0, int maxpara = 0) : ServiceProvider(me, cmd, SERVICE_COMMAND), flags_needed(0), min_params(minpara), max_params(maxpara), - use_count(0), total_bytes(0), disabled(false), works_before_reg(false), allow_empty_last_param(true), + use_count(0), disabled(false), works_before_reg(false), allow_empty_last_param(true), Penalty(1) { } - /** Handle the command from a user. - * @param parameters The parameters for the command. - * @param user The user who issued the command. - * @return Return CMD_SUCCESS on success, or CMD_FAILURE on failure. - */ - virtual CmdResult Handle(const std::vector<std::string>& parameters, User* user) = 0; - virtual RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_LOCALONLY; @@ -224,7 +211,28 @@ class CoreExport Command : public ServiceProvider return works_before_reg; } - virtual ~Command(); + virtual ~CommandBase(); +}; + +class CoreExport Command : public CommandBase +{ + public: + Command(Module* me, const std::string& cmd, unsigned int minpara = 0, unsigned int maxpara = 0) + : CommandBase(me, cmd, minpara, maxpara) + { + } + + /** Handle the command from a user. + * @param parameters The parameters for the command. + * @param user The user who issued the command. + * @return Return CMD_SUCCESS on success, or CMD_FAILURE on failure. + */ + virtual CmdResult Handle(const std::vector<std::string>& parameters, User* user) = 0; + + /** Destructor + * Removes this command from the command parser + */ + ~Command(); }; class CoreExport SplitCommand : public Command @@ -252,5 +260,3 @@ class CoreExport SplitCommand : public Command translation.push_back(x5);translation.push_back(x6);translation.push_back(x7); #define TRANSLATE8(x1,x2,x3,x4,x5,x6,x7,x8) translation.push_back(x1);translation.push_back(x2);translation.push_back(x3);translation.push_back(x4);\ translation.push_back(x5);translation.push_back(x6);translation.push_back(x7);translation.push_back(x8); - -#endif diff --git a/include/cull_list.h b/include/cull_list.h index 75b08b7a3..ac64dced2 100644 --- a/include/cull_list.h +++ b/include/cull_list.h @@ -20,8 +20,7 @@ */ -#ifndef CULL_LIST_H -#define CULL_LIST_H +#pragma once /** * The CullList class is used to delete objects at the end of the main loop to @@ -58,6 +57,3 @@ class CoreExport ActionList void Run(); }; - -#endif - diff --git a/include/dns.h b/include/dns.h deleted file mode 100644 index 27c3c8848..000000000 --- a/include/dns.h +++ /dev/null @@ -1,443 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> - * Copyright (C) 2005-2008 Craig Edwards <craigedwards@brainbox.cc> - * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -/* -dns.h - dns library very very loosely based on -firedns, Copyright (C) 2002 Ian Gulliver - -This program is free software; you can redistribute it and/or modify -it under the terms of version 2 of the GNU General Public License as -published by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef DNS_H -#define DNS_H - -#include "socket.h" -#include "hashcomp.h" - -/** - * Result status, used internally - */ -class CoreExport DNSResult -{ - public: - /** Result ID - */ - int id; - /** Result body, a hostname or IP address - */ - std::string result; - /** Time-to-live value of the result - */ - unsigned long ttl; - /** The original request, a hostname or IP address - */ - std::string original; - - /** Build a DNS result. - * @param i The request ID - * @param res The request result, a hostname or IP - * @param timetolive The request time-to-live - * @param orig The original request, a hostname or IP - */ - DNSResult(int i, const std::string &res, unsigned long timetolive, const std::string &orig) : id(i), result(res), ttl(timetolive), original(orig) { } -}; - -/** - * Information on a completed lookup, used internally - */ -typedef std::pair<unsigned char*, std::string> DNSInfo; - -/** Cached item stored in the query cache. - */ -class CoreExport CachedQuery -{ - public: - /** The cached result data, an IP or hostname - */ - std::string data; - /** The time when the item is due to expire - */ - time_t expires; - - /** Build a cached query - * @param res The result data, an IP or hostname - * @param ttl The time-to-live value of the query result - */ - CachedQuery(const std::string &res, unsigned int ttl); - - /** Returns the number of seconds remaining before this - * cache item has expired and should be removed. - */ - int CalcTTLRemaining(); -}; - -/** DNS cache information. Holds IPs mapped to hostnames, and hostnames mapped to IPs. - */ -typedef nspace::hash_map<irc::string, CachedQuery, irc::hash> dnscache; - -/** - * Error types that class Resolver can emit to its error method. - */ -enum ResolverError -{ - RESOLVER_NOERROR = 0, - RESOLVER_NSDOWN = 1, - RESOLVER_NXDOMAIN = 2, - RESOLVER_BADIP = 3, - RESOLVER_TIMEOUT = 4, - RESOLVER_FORCEUNLOAD = 5 -}; - -/** - * Query and resource record types - */ -enum QueryType -{ - /** Uninitialized Query */ - DNS_QUERY_NONE = 0, - /** 'A' record: an ipv4 address */ - DNS_QUERY_A = 1, - /** 'CNAME' record: An alias */ - DNS_QUERY_CNAME = 5, - /** 'PTR' record: a hostname */ - DNS_QUERY_PTR = 12, - /** 'AAAA' record: an ipv6 address */ - DNS_QUERY_AAAA = 28, - - /** Force 'PTR' to use IPV4 scemantics */ - DNS_QUERY_PTR4 = 0xFFFD, - /** Force 'PTR' to use IPV6 scemantics */ - DNS_QUERY_PTR6 = 0xFFFE -}; - -/** - * Used internally to force PTR lookups to use a certain protocol scemantics, - * e.g. x.x.x.x.in-addr.arpa for v4, and *.ip6.arpa for v6. - */ -enum ForceProtocol -{ - /** Forced to use ipv4 */ - PROTOCOL_IPV4 = 0, - /** Forced to use ipv6 */ - PROTOCOL_IPV6 = 1 -}; - -/** - * The Resolver class is a high-level abstraction for resolving DNS entries. - * It can do forward and reverse IPv4 lookups, and where IPv6 is supported, will - * also be able to do those, transparent of protocols. Module developers must - * extend this class via inheritence, and then insert a pointer to their derived - * class into the core using Server::AddResolver(). Once you have done this, - * the class will be able to receive callbacks. There are two callbacks which - * can occur by calling virtual methods, one is a success situation, and the other - * an error situation. - */ -class CoreExport Resolver -{ - protected: - /** - * Pointer to creator module (if any, or NULL) - */ - ModuleRef Creator; - /** - * The input data, either a host or an IP address - */ - std::string input; - /** - * True if a forward lookup is being performed, false if otherwise - */ - QueryType querytype; - /** - * The DNS erver being used for lookups. If this is an empty string, - * the value of ServerConfig::DNSServer is used instead. - */ - std::string server; - /** - * The ID allocated to your lookup. This is a pseudo-random number - * between 0 and 65535, a value of -1 indicating a failure. - * The core uses this to route results to the correct objects. - */ - int myid; - - /** - * Cached result, if there is one - */ - CachedQuery *CQ; - - /** - * Time left before cache expiry - */ - int time_left; - - public: - /** - * Initiate DNS lookup. Your class should not attempt to delete or free these - * objects, as the core will do this for you. They must always be created upon - * the heap using new, as you cannot be sure at what time they will be deleted. - * Allocating them on the stack or attempting to delete them yourself could cause - * the object to go 'out of scope' and cause a segfault in the core if the result - * arrives at a later time. - * @param source The IP or hostname to resolve - * @param qt The query type to perform. Resolution of 'A', 'AAAA', 'PTR' and 'CNAME' records - * is supported. Use one of the QueryType enum values to initiate this type of - * lookup. Resolution of 'AAAA' ipv6 records is always supported, regardless of - * wether InspIRCd is built with ipv6 support. - * To look up reverse records, specify one of DNS_QUERY_PTR4 or DNS_QUERY_PTR6 depending - * on the type of address you are looking up. - * @param cached The constructor will set this boolean to true or false depending - * on whether the DNS lookup you are attempting is cached (and not expired) or not. - * If the value is cached, upon return this will be set to true, otherwise it will - * be set to false. You should pass this value to InspIRCd::AddResolver(), which - * will then influence the behaviour of the method and determine whether a cached - * or non-cached result is obtained. The value in this variable is always correct - * for the given request when the constructor exits. - * @param creator See the note below. - * @throw ModuleException This class may throw an instance of ModuleException, in the - * event a lookup could not be allocated, or a similar hard error occurs such as - * the network being down. This will also be thrown if an invalid IP address is - * passed when resolving a 'PTR' record. - * - * NOTE: If you are instantiating your DNS lookup from a module, you should set the - * value of creator to point at your Module class. This way if your module is unloaded - * whilst lookups are in progress, they can be safely removed and your module will not - * crash the server. - */ - Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator); - - /** - * The default destructor does nothing. - */ - virtual ~Resolver(); - - /** - * When your lookup completes, this method will be called. - * @param result The resulting DNS lookup, either an IP address or a hostname. - * @param ttl The time-to-live value of the result, in the instance of a cached - * result, this is the number of seconds remaining before refresh/expiry. - * @param cached True if the result is a cached result, false if it was requested - * from the DNS server. - */ - virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) = 0; - - /** - * If an error occurs (such as NXDOMAIN, no domain name found) then this method - * will be called. - * @param e A ResolverError enum containing the error type which has occured. - * @param errormessage The error text of the error that occured. - */ - virtual void OnError(ResolverError e, const std::string &errormessage); - - /** - * Returns the id value of this class. This is primarily used by the core - * to determine where in various tables to place a pointer to your class, but it - * is safe to call and use this method. - * As specified in RFC1035, each dns request has a 16 bit ID value, ranging - * from 0 to 65535. If there is an issue and the core cannot send your request, - * this method will return -1. - */ - int GetId(); - - /** - * Returns the creator module, or NULL - */ - Module* GetCreator(); - - /** - * If the result is a cached result, this triggers the objects - * OnLookupComplete. This is done because it is not safe to call - * the abstract virtual method from the constructor. - */ - void TriggerCachedResult(); -}; - -/** DNS is a singleton class used by the core to dispatch dns - * requests to the dns server, and route incoming dns replies - * back to Resolver objects, based upon the request ID. You - * should never use this class yourself. - */ -class CoreExport DNS : public EventHandler -{ - private: - - /** - * The maximum value of a dns request id, - * 16 bits wide, 0xFFFF. - */ - static const int MAX_REQUEST_ID = 0xFFFF; - - /** - * Currently cached items - */ - dnscache* cache; - - /** A timer which ticks every hour to remove expired - * items from the DNS cache. - */ - class CacheTimer* PruneTimer; - - /** - * Build a dns packet payload - */ - int MakePayload(const char* name, const QueryType rr, const unsigned short rr_class, unsigned char* payload); - - public: - - irc::sockets::sockaddrs myserver; - - /** - * Currently active Resolver classes - */ - Resolver* Classes[MAX_REQUEST_ID]; - - /** - * Requests that are currently 'in flight' - */ - DNSRequest* requests[MAX_REQUEST_ID]; - - /** - * The port number DNS requests are made on, - * and replies have as a source-port number. - */ - static const int QUERY_PORT = 53; - - /** - * Fill an rr (resource record) with data from input - */ - static void FillResourceRecord(ResourceRecord* rr, const unsigned char* input); - - /** - * Fill a header with data from input limited by a length - */ - static void FillHeader(DNSHeader *header, const unsigned char *input, const int length); - - /** - * Empty out a header into a data stream ready for transmission "on the wire" - */ - static void EmptyHeader(unsigned char *output, const DNSHeader *header, const int length); - - /** - * Start the lookup of an ipv4 from a hostname - */ - int GetIP(const char* name); - - /** - * Start lookup of a hostname from an ip, but - * force a specific protocol to be used for the lookup - * for example to perform an ipv6 reverse lookup. - */ - int GetNameForce(const char *ip, ForceProtocol fp); - - /** - * Start lookup of an ipv6 from a hostname - */ - int GetIP6(const char *name); - - /** - * Start lookup of a CNAME from another hostname - */ - int GetCName(const char* alias); - - /** - * Fetch the result string (an ip or host) - * and/or an error message to go with it. - */ - DNSResult GetResult(); - - /** - * Handle a SocketEngine read event - * Inherited from EventHandler - */ - void HandleEvent(EventType et, int errornum = 0); - - /** - * Add a Resolver* to the list of active classes - */ - bool AddResolverClass(Resolver* r); - - /** - * Add a query to the list to be sent - */ - DNSRequest* AddQuery(DNSHeader *header, int &id, const char* original); - - /** - * The constructor initialises the dns socket, - * and clears the request lists. - */ - DNS(); - - /** - * Re-initialize the DNS subsystem. - */ - void Rehash(); - - /** - * Destructor - */ - ~DNS(); - - /** - * Turn an in6_addr into a .ip6.arpa domain - */ - static void MakeIP6Int(char* query, const in6_addr *ip); - - /** - * Clean out all dns resolvers owned by a particular - * module, to make unloading a module safe if there - * are dns requests currently in progress. - */ - void CleanResolvers(Module* module); - - /** Return the cached value of an IP or hostname - * @param source An IP or hostname to find in the cache. - * @return A pointer to a CachedQuery if the item exists, - * otherwise NULL. - */ - CachedQuery* GetCache(const std::string &source); - - /** Delete a cached item from the DNS cache. - * @param source An IP or hostname to remove - */ - void DelCache(const std::string &source); - - /** Clear all items from the DNS cache immediately. - */ - int ClearCache(); - - /** Prune the DNS cache, e.g. remove all expired - * items and rehash the cache buckets, but leave - * items in the hash which are still valid. - */ - int PruneCache(); -}; - -#endif - diff --git a/include/dynamic.h b/include/dynamic.h index 5e66ddbb0..d42cf61bf 100644 --- a/include/dynamic.h +++ b/include/dynamic.h @@ -20,8 +20,7 @@ */ -#ifndef DLL_H -#define DLL_H +#pragma once /** The DLLManager class is able to load a module file by filename, * and locate its init_module symbol. @@ -65,6 +64,3 @@ class CoreExport DLLManager : public classbase /** Get detailed version information from the module file */ std::string GetVersion(); }; - -#endif - diff --git a/include/dynref.h b/include/dynref.h new file mode 100644 index 000000000..1d05b35a0 --- /dev/null +++ b/include/dynref.h @@ -0,0 +1,99 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> + * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "base.h" + +class CoreExport dynamic_reference_base : public interfacebase +{ + private: + std::string name; + void resolve(); + protected: + ServiceProvider* value; + public: + ModuleRef creator; + dynamic_reference_base(Module* Creator, const std::string& Name); + ~dynamic_reference_base(); + inline const std::string& GetProvider() { return name; } + void SetProvider(const std::string& newname); + void check(); + operator bool() { return (value != NULL); } + static void reset_all(); +}; + +inline void dynamic_reference_base::check() +{ + if (!value) + throw ModuleException("Dynamic reference to '" + name + "' failed to resolve"); +} + +template<typename T> +class dynamic_reference : public dynamic_reference_base +{ + public: + dynamic_reference(Module* Creator, const std::string& Name) + : dynamic_reference_base(Creator, Name) {} + + inline T* operator->() + { + check(); + return static_cast<T*>(value); + } + + T* operator*() + { + return operator->(); + } +}; + +template<typename T> +class dynamic_reference_nocheck : public dynamic_reference_base +{ + public: + dynamic_reference_nocheck(Module* Creator, const std::string& Name) + : dynamic_reference_base(Creator, Name) {} + + T* operator->() + { + return static_cast<T*>(value); + } + + T* operator*() + { + return operator->(); + } +}; + +class ModeHandler; +class ChanModeReference : public dynamic_reference_nocheck<ModeHandler> +{ + public: + ChanModeReference(Module* mod, const std::string& modename) + : dynamic_reference_nocheck<ModeHandler>(mod, "mode/" + modename) {} +}; + +class UserModeReference : public dynamic_reference_nocheck<ModeHandler> +{ + public: + UserModeReference(Module* mod, const std::string& modename) + : dynamic_reference_nocheck<ModeHandler>(mod, "umode/" + modename) {} +}; diff --git a/include/exitcodes.h b/include/exitcodes.h index d4890c94d..b1090d141 100644 --- a/include/exitcodes.h +++ b/include/exitcodes.h @@ -19,8 +19,7 @@ */ -#ifndef EXITCODE_H -#define EXITCODE_H +#pragma once /** Valid exit codes to be used with InspIRCd::Exit() */ @@ -28,30 +27,18 @@ enum ExitStatus { EXIT_STATUS_NOERROR = 0, /* No error */ EXIT_STATUS_DIE = 1, /* Operator issued DIE */ - EXIT_STATUS_FAILED_EXEC = 2, /* execv() failed */ - EXIT_STATUS_INTERNAL = 3, /* Internal error */ - EXIT_STATUS_CONFIG = 4, /* Config error */ - EXIT_STATUS_LOG = 5, /* Log file error */ - EXIT_STATUS_FORK = 6, /* fork() failed */ - EXIT_STATUS_ARGV = 7, /* Invalid program arguments */ - EXIT_STATUS_BIND = 8, /* Port binding failed on all ports */ - EXIT_STATUS_PID = 9, /* Couldn't write PID file */ - EXIT_STATUS_SOCKETENGINE = 10, /* Couldn't start socket engine */ - EXIT_STATUS_ROOT = 11, /* Refusing to start as root */ - EXIT_STATUS_DIETAG = 12, /* Found a die tag in the config file */ - EXIT_STATUS_MODULE = 13, /* Couldn't load a required module */ - EXIT_STATUS_CREATEPROCESS = 14, /* CreateProcess failed (windows) */ - EXIT_STATUS_SIGTERM = 15, /* Note: dont move this value. It corresponds with the value of #define SIGTERM. */ - EXIT_STATUS_BADHANDLER = 16, /* Bad command handler loaded */ - EXIT_STATUS_RSCH_FAILED = 17, /* Windows service specific failure, will name these later */ - EXIT_STATUS_UPDATESCM_FAILED = 18, /* Windows service specific failure, will name these later */ - EXIT_STATUS_CREATE_EVENT_FAILED = 19 /* Windows service specific failure, will name these later */ + EXIT_STATUS_CONFIG = 2, /* Config error */ + EXIT_STATUS_LOG = 3, /* Log file error */ + EXIT_STATUS_FORK = 4, /* fork() failed */ + EXIT_STATUS_ARGV = 5, /* Invalid program arguments */ + EXIT_STATUS_PID = 6, /* Couldn't write PID file */ + EXIT_STATUS_SOCKETENGINE = 7, /* Couldn't start socket engine */ + EXIT_STATUS_ROOT = 8, /* Refusing to start as root */ + EXIT_STATUS_MODULE = 9, /* Couldn't load a required module */ + EXIT_STATUS_SIGTERM = 10 /* Received SIGTERM */ }; /** Array that maps exit codes (ExitStatus types) to * human-readable strings to be shown on shutdown. */ extern const char * ExitCodes[]; - -#endif - diff --git a/include/extensible.h b/include/extensible.h index bcc4992bb..e062f66a5 100644 --- a/include/extensible.h +++ b/include/extensible.h @@ -17,8 +17,7 @@ */ -#ifndef EXTENSIBLE_H -#define EXTENSIBLE_H +#pragma once #include <stdint.h> @@ -190,5 +189,3 @@ class CoreExport StringExtItem : public ExtensionItem void unset(Extensible* container); void free(void* item); }; - -#endif diff --git a/include/filelogger.h b/include/filelogger.h index 22a94c934..ce571c3ae 100644 --- a/include/filelogger.h +++ b/include/filelogger.h @@ -18,27 +18,10 @@ */ -#ifndef FILELOGGER_H -#define FILELOGGER_H +#pragma once #include "logger.h" -/** Debug levels for use with InspIRCd::Log() - * */ -enum DebugLevel -{ - RAWIO = 5, - DEBUG = 10, - VERBOSE = 20, - DEFAULT = 30, - SPARSE = 40, - NONE = 50 -}; - - -/* Forward declaration -- required */ -class InspIRCd; - /** A logging class which logs to a streamed file. */ class CoreExport FileLogStream : public LogStream @@ -46,12 +29,9 @@ class CoreExport FileLogStream : public LogStream private: FileWriter *f; public: - FileLogStream(int loglevel, FileWriter *fw); + FileLogStream(LogLevel loglevel, FileWriter *fw); virtual ~FileLogStream(); - virtual void OnLog(int loglevel, const std::string &type, const std::string &msg); + virtual void OnLog(LogLevel loglevel, const std::string &type, const std::string &msg); }; - -#endif - diff --git a/include/hash_map.h b/include/hash_map.h deleted file mode 100644 index 1b43f0118..000000000 --- a/include/hash_map.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2009 Robin Burchell <robin+git@viroteck.net> - * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> - * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> - * Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#ifndef INSPIRCD_HASHMAP_H -#define INSPIRCD_HASHMAP_H - - /** Where hash_map is varies from compiler to compiler - * as it is not standard unless we have tr1. - * - * TODO: in 2.2 if we drop support for libstdc++ older than 3.4.7 and GCC older - * than 4.1 this can be cleaned up massively. - */ - #ifndef _WIN32 - #if __GLIBCXX__ > 20060309 - // GCC4+ has deprecated hash_map and uses tr1. But of course, uses a different include to MSVC. FOR FUCKS SAKE. - #include <tr1/unordered_map> - #define HAS_TR1_UNORDERED - #define HASHMAP_DEPRECATED - #else - #include <ext/hash_map> - /** Oddball linux namespace for hash_map */ - #define nspace __gnu_cxx - #define BEGIN_HASHMAP_NAMESPACE namespace nspace { - #define END_HASHMAP_NAMESPACE } - #endif - #else - #include <unordered_map> - #define HAS_TR1_UNORDERED - #define HASHMAP_DEPRECATED - #endif - - // tr1: restoring sanity to our headers. now if only compiler vendors could agree on a FUCKING INCLUDE FILE. - #ifdef HAS_TR1_UNORDERED - #define hash_map unordered_map - #define nspace std::tr1 - #define BEGIN_HASHMAP_NAMESPACE namespace std { namespace tr1 { - #define END_HASHMAP_NAMESPACE } } - #endif - -#endif diff --git a/include/hashcomp.h b/include/hashcomp.h index 78d7ee878..51570978a 100644 --- a/include/hashcomp.h +++ b/include/hashcomp.h @@ -22,8 +22,7 @@ */ -#ifndef HASHCOMP_H -#define HASHCOMP_H +#pragma once #include <cstring> #include <string> @@ -31,7 +30,7 @@ #include <deque> #include <map> #include <set> -#include "hash_map.h" +#include "inspircd.h" /******************************************************* * This file contains classes and templates that deal @@ -110,6 +109,11 @@ namespace irc bool operator()(const std::string& s1, const std::string& s2) const; }; + struct insensitive + { + size_t CoreExport operator()(const std::string &s) const; + }; + /** The irc_char_traits class is used for RFC-style comparison of strings. * This class is used to implement irc::string, a case-insensitive, RFC- * comparing string class. @@ -155,22 +159,13 @@ namespace irc static CoreExport const char* find(const char* s1, int n, char c); }; - /** Compose a hex string from raw data. - * @param raw The raw data to compose hex from - * @param rawsz The size of the raw data buffer - * @return The hex string. - */ - CoreExport std::string hex(const unsigned char *raw, size_t rawsz); - /** This typedef declares irc::string based upon irc_char_traits. */ typedef std::basic_string<char, irc_char_traits, std::allocator<char> > string; /** irc::stringjoiner joins string lists into a string, using - * the given seperator string. - * This class can join a vector of std::string, a deque of - * std::string, or a const char* const* array, using overloaded - * constructors. + * space as the separator. + * This class can join a vector of std::string. */ class CoreExport stringjoiner { @@ -182,34 +177,16 @@ namespace irc public: - /** Join elements of a vector, between (and including) begin and end - * @param seperator The string to seperate values with - * @param sequence One or more items to seperate - * @param begin The starting element in the sequence to be joined - * @param end The ending element in the sequence to be joined + /** Join all elements of a vector, in the resulting string + * each element will be seperated by a single space character. + * @param sequence Zero or more items to seperate */ - stringjoiner(const std::string &seperator, const std::vector<std::string> &sequence, int begin, int end); - - /** Join elements of a deque, between (and including) begin and end - * @param seperator The string to seperate values with - * @param sequence One or more items to seperate - * @param begin The starting element in the sequence to be joined - * @param end The ending element in the sequence to be joined - */ - stringjoiner(const std::string &seperator, const std::deque<std::string> &sequence, int begin, int end); - - /** Join elements of an array of char arrays, between (and including) begin and end - * @param seperator The string to seperate values with - * @param sequence One or more items to seperate - * @param begin The starting element in the sequence to be joined - * @param end The ending element in the sequence to be joined - */ - stringjoiner(const std::string &seperator, const char* const* sequence, int begin, int end); + stringjoiner(const std::vector<std::string>& sequence); /** Get the joined sequence - * @return A reference to the joined string + * @return A constant reference to the joined string */ - std::string& GetJoined(); + const std::string& GetJoined() const { return joined; } }; /** irc::modestacker stacks mode sequences into a list. @@ -281,80 +258,6 @@ namespace irc */ int GetStackedLine(std::vector<std::string> &result, int max_line_size = 360); - /** deprecated compatability interface - TODO remove */ - int GetStackedLine(std::deque<std::string> &result, int max_line_size = 360) { - std::vector<std::string> r; - int n = GetStackedLine(r, max_line_size); - result.clear(); - result.insert(result.end(), r.begin(), r.end()); - return n; - } - }; - - /** irc::tokenstream reads a string formatted as per RFC1459 and RFC2812. - * It will split the string into 'tokens' each containing one parameter - * from the string. - * For instance, if it is instantiated with the string: - * "PRIVMSG #test :foo bar baz qux" - * then each successive call to tokenstream::GetToken() will return - * "PRIVMSG", "#test", "foo bar baz qux", "". - * Note that if the whole string starts with a colon this is not taken - * to mean the string is all one parameter, and the first item in the - * list will be ":item". This is to allow for parsing 'source' fields - * from data. - */ - class CoreExport tokenstream - { - private: - - /** Original string - */ - std::string tokens; - - /** Last position of a seperator token - */ - std::string::iterator last_starting_position; - - /** Current string position - */ - std::string::iterator n; - - /** True if the last value was an ending value - */ - bool last_pushed; - public: - - /** Create a tokenstream and fill it with the provided data - */ - tokenstream(const std::string &source); - - /** Destructor - */ - ~tokenstream(); - - /** Fetch the next token from the stream as a std::string - * @param token The next token available, or an empty string if none remain - * @return True if tokens are left to be read, false if the last token was just retrieved. - */ - bool GetToken(std::string &token); - - /** Fetch the next token from the stream as an irc::string - * @param token The next token available, or an empty string if none remain - * @return True if tokens are left to be read, false if the last token was just retrieved. - */ - bool GetToken(irc::string &token); - - /** Fetch the next token from the stream as an integer - * @param token The next token available, or undefined if none remain - * @return True if tokens are left to be read, false if the last token was just retrieved. - */ - bool GetToken(int &token); - - /** Fetch the next token from the stream as a long integer - * @param token The next token available, or undefined if none remain - * @return True if tokens are left to be read, false if the last token was just retrieved. - */ - bool GetToken(long &token); }; /** irc::sepstream allows for splitting token seperated lists. @@ -364,43 +267,39 @@ namespace irc */ class CoreExport sepstream { - private: + protected: /** Original string. */ std::string tokens; - /** Last position of a seperator token + /** Separator value */ - std::string::iterator last_starting_position; + char sep; /** Current string position */ - std::string::iterator n; - /** Seperator value + size_t pos; + /** If set then GetToken() can return an empty string */ - char sep; + bool allow_empty; public: /** Create a sepstream and fill it with the provided data */ - sepstream(const std::string &source, char seperator); - - /** Destructor - */ - virtual ~sepstream(); + sepstream(const std::string &source, char separator, bool allowempty = false); /** Fetch the next token from the stream * @param token The next token from the stream is placed here * @return True if tokens still remain, false if there are none left */ - virtual bool GetToken(std::string &token); + bool GetToken(std::string& token); /** Fetch the entire remaining stream, without tokenizing * @return The remaining part of the stream */ - virtual const std::string GetRemaining(); + const std::string GetRemaining(); /** Returns true if the end of the stream has been reached * @return True if the end of the stream has been reached, otherwise false */ - virtual bool StreamEnd(); + bool StreamEnd(); }; /** A derived form of sepstream, which seperates on commas @@ -408,9 +307,9 @@ namespace irc class CoreExport commasepstream : public sepstream { public: - /** Initialize with comma seperator + /** Initialize with comma separator */ - commasepstream(const std::string &source) : sepstream(source, ',') + commasepstream(const std::string &source, bool allowempty = false) : sepstream(source, ',', allowempty) { } }; @@ -420,13 +319,57 @@ namespace irc class CoreExport spacesepstream : public sepstream { public: - /** Initialize with space seperator + /** Initialize with space separator */ - spacesepstream(const std::string &source) : sepstream(source, ' ') + spacesepstream(const std::string &source, bool allowempty = false) : sepstream(source, ' ', allowempty) { } }; + /** irc::tokenstream reads a string formatted as per RFC1459 and RFC2812. + * It will split the string into 'tokens' each containing one parameter + * from the string. + * For instance, if it is instantiated with the string: + * "PRIVMSG #test :foo bar baz qux" + * then each successive call to tokenstream::GetToken() will return + * "PRIVMSG", "#test", "foo bar baz qux", "". + * Note that if the whole string starts with a colon this is not taken + * to mean the string is all one parameter, and the first item in the + * list will be ":item". This is to allow for parsing 'source' fields + * from data. + */ + class CoreExport tokenstream : private spacesepstream + { + public: + /** Create a tokenstream and fill it with the provided data + */ + tokenstream(const std::string &source); + + /** Fetch the next token from the stream as a std::string + * @param token The next token available, or an empty string if none remain + * @return True if tokens are left to be read, false if the last token was just retrieved. + */ + bool GetToken(std::string &token); + + /** Fetch the next token from the stream as an irc::string + * @param token The next token available, or an empty string if none remain + * @return True if tokens are left to be read, false if the last token was just retrieved. + */ + bool GetToken(irc::string &token); + + /** Fetch the next token from the stream as an integer + * @param token The next token available, or undefined if none remain + * @return True if tokens are left to be read, false if the last token was just retrieved. + */ + bool GetToken(int &token); + + /** Fetch the next token from the stream as a long integer + * @param token The next token available, or undefined if none remain + * @return True if tokens are left to be read, false if the last token was just retrieved. + */ + bool GetToken(long &token); + }; + /** The portparser class seperates out a port range into integers. * A port range may be specified in the input string in the form * "6660,6661,6662-6669,7020". The end of the stream is indicated by @@ -481,12 +424,6 @@ namespace irc long GetToken(); }; - /** Turn _ characters in a string into spaces - * @param n String to translate - * @return The new value with _ translated to space. - */ - CoreExport const char* Spacify(const char* n); - struct hash { /** Hash an irc::string using RFC1459 case sensitivity rules @@ -590,72 +527,3 @@ inline std::string& trim(std::string &str) return str; } - -/** Hashing stuff is totally different on vc++'s hash_map implementation, so to save a buttload of - * \#ifdefs we'll just do it all at once. Except, of course, with TR1, when it's the same as GCC. - */ -BEGIN_HASHMAP_NAMESPACE - - /** Hashing function to hash irc::string - */ -#if defined(_WIN32) && !defined(HAS_TR1_UNORDERED) - template<> class CoreExport hash_compare<irc::string, std::less<irc::string> > - { - public: - enum { bucket_size = 4, min_buckets = 8 }; /* Got these numbers from the CRT source, if anyone wants to change them feel free. */ - - /** Compare two irc::string values for hashing in hash_map - */ - bool operator()(const irc::string & s1, const irc::string & s2) const - { - if(s1.length() != s2.length()) return true; - return (irc::irc_char_traits::compare(s1.c_str(), s2.c_str(), (size_t)s1.length()) < 0); - } - - /** Hash an irc::string value for hash_map - */ - size_t operator()(const irc::string & s) const; - }; - - template<> class CoreExport hash_compare<std::string, std::less<std::string> > - { - public: - enum { bucket_size = 4, min_buckets = 8 }; /* Again, from the CRT source */ - - /** Compare two std::string values for hashing in hash_map - */ - bool operator()(const std::string & s1, const std::string & s2) const - { - if(s1.length() != s2.length()) return true; - return (irc::irc_char_traits::compare(s1.c_str(), s2.c_str(), (size_t)s1.length()) < 0); - } - - /** Hash a std::string using RFC1459 case sensitivity rules - * @param s A string to hash - * @return The hash value - */ - size_t operator()(const std::string & s) const; - }; -#else - - /* XXX FIXME: Implement a hash function overriding std::string's that works with TR1! */ - -#ifdef HASHMAP_DEPRECATED - struct insensitive -#else - CoreExport template<> struct hash<std::string> -#endif - { - size_t CoreExport operator()(const std::string &s) const; - }; - -#endif - - /** Convert a string to lower case respecting RFC1459 - * @param n A string to lowercase - */ - void strlower(char *n); - -END_HASHMAP_NAMESPACE - -#endif diff --git a/include/inspircd.h b/include/inspircd.h index 86853a94f..694869423 100644 --- a/include/inspircd.h +++ b/include/inspircd.h @@ -23,57 +23,34 @@ */ -#ifndef INSPIRCD_H -#define INSPIRCD_H +#pragma once -#define _FILE_OFFSET_BITS 64 -#ifndef _LARGEFILE_SOURCE -#define _LARGEFILE_SOURCE -#endif - -#ifndef _WIN32 -#define DllExport -#define CoreExport -#else -#include "inspircd_win32wrapper.h" -/** Windows defines these already */ -#undef ERROR -#endif - -#ifdef __GNUC__ -#define CUSTOM_PRINTF(STRING, FIRST) __attribute__((format(printf, STRING, FIRST))) -#else -#define CUSTOM_PRINTF(STRING, FIRST) -#endif - -// Required system headers. -#include <ctime> -#include <cstdarg> -#include <algorithm> -#include <cmath> -#include <cstring> #include <climits> +#include <cmath> +#include <csignal> +#include <cstdarg> #include <cstdio> -#ifndef _WIN32 -#include <unistd.h> -#endif +#include <cstring> +#include <ctime> -#include <sstream> -#include <string> -#include <vector> -#include <list> +#include <algorithm> +#include <bitset> #include <deque> +#include <list> #include <map> -#include <bitset> #include <set> -#include <time.h> -#include "inspircd_config.h" -#include "inspircd_version.h" +#include <sstream> +#include <string> +#include <vector> + +#include "compat.h" #include "typedefs.h" -#include "consolecolors.h" CoreExport extern InspIRCd* ServerInstance; +#include "config.h" +#include "dynref.h" +#include "consolecolors.h" #include "caller.h" #include "cull_list.h" #include "extensible.h" @@ -98,43 +75,27 @@ CoreExport extern InspIRCd* ServerInstance; #include "inspstring.h" #include "protocol.h" -#ifndef PATH_MAX -#warning Potentially broken system, PATH_MAX undefined -#define PATH_MAX 4096 -#endif - -/** - * Used to define the maximum number of parameters a command may have. - */ -#define MAXPARAMETERS 127 - /** Returned by some functions to indicate failure. */ #define ERROR -1 -/** Support for librodent - - * see http://www.chatspike.net/index.php?z=64 - */ -#define ETIREDHAMSTERS EAGAIN - /** Template function to convert any input type to std::string */ template<typename T> inline std::string ConvNumeric(const T &in) { - if (in == 0) return "0"; - char res[MAXBUF]; - char* out = res; + if (in == 0) + return "0"; T quotient = in; - while (quotient) { - *out = "0123456789"[ std::abs( (long)quotient % 10 ) ]; - ++out; + std::string out; + while (quotient) + { + out += "0123456789"[ std::abs( (long)quotient % 10 ) ]; quotient /= 10; } if (in < 0) - *out++ = '-'; - *out = 0; - std::reverse(res,out); - return res; + out += '-'; + std::reverse(out.begin(), out.end()); + return out; } /** Template function to convert any input type to std::string @@ -259,17 +220,34 @@ class serverstats } }; -DEFINE_HANDLER2(IsNickHandler, bool, const char*, size_t); +/** This class manages the generation and transmission of ISUPPORT. */ +class CoreExport ISupportManager +{ +private: + /** The generated lines which are sent to clients. */ + std::vector<std::string> Lines; + +public: + /** (Re)build the ISUPPORT vector. */ + void Build(); + + /** Returns the std::vector of ISUPPORT lines. */ + const std::vector<std::string>& GetLines() + { + return this->Lines; + } + + /** Send the 005 numerics (ISUPPORT) to a user. */ + void SendTo(LocalUser* user); +}; + +DEFINE_HANDLER1(IsNickHandler, bool, const std::string&); DEFINE_HANDLER2(GenRandomHandler, void, char*, size_t); -DEFINE_HANDLER1(IsIdentHandler, bool, const char*); -DEFINE_HANDLER1(FloodQuitUserHandler, void, User*); -DEFINE_HANDLER2(IsChannelHandler, bool, const char*, size_t); -DEFINE_HANDLER1(IsSIDHandler, bool, const std::string&); +DEFINE_HANDLER1(IsIdentHandler, bool, const std::string&); +DEFINE_HANDLER1(IsChannelHandler, bool, const std::string&); DEFINE_HANDLER1(RehashHandler, void, const std::string&); DEFINE_HANDLER3(OnCheckExemptionHandler, ModResult, User*, Channel*, const std::string&); -class TestSuite; - /** The main class of the irc server. * This class contains instances of all the other classes in this software. * Amongst other things, it contains a ModeParser, a DNS object, a CommandParser @@ -279,10 +257,6 @@ class TestSuite; class CoreExport InspIRCd { private: - /** Holds the current UID. Used to generate the next one. - */ - char current_uid[UUID_LENGTH]; - /** Set up the signal handlers */ void SetSignals(); @@ -292,25 +266,6 @@ class CoreExport InspIRCd */ bool DaemonSeed(); - /** Iterate the list of BufferedSocket objects, removing ones which have timed out - * @param TIME the current time - */ - void DoSocketTimeouts(time_t TIME); - - /** Increments the current UID by one. - */ - void IncrementUID(int pos); - - /** Perform background user events such as PING checks - */ - void DoBackgroundUserStuff(); - - /** Returns true when all modules have done pre-registration checks on a user - * @param user The user to verify - * @return True if all modules have finished checking this user - */ - bool AllModulesReportReady(LocalUser* user); - /** The current time, updated in the mainloop */ struct timespec TIME; @@ -320,8 +275,15 @@ class CoreExport InspIRCd */ char ReadBuffer[65535]; + /** Check we aren't running as root, and exit if we are + * with exit code EXIT_STATUS_ROOT. + */ + void CheckRoot(); + public: + UIDGenerator UIDGen; + /** Global cull list, will be processed on next iteration */ CullList GlobalCulls; @@ -332,10 +294,8 @@ class CoreExport InspIRCd IsNickHandler HandleIsNick; IsIdentHandler HandleIsIdent; - FloodQuitUserHandler HandleFloodQuitUser; OnCheckExemptionHandler HandleOnCheckExemption; IsChannelHandler HandleIsChannel; - IsSIDHandler HandleIsSID; RehashHandler HandleRehash; GenRandomHandler HandleGenRandom; @@ -349,28 +309,12 @@ class CoreExport InspIRCd */ FakeUser* FakeClient; - /** Returns the next available UID for this server. - */ - std::string GetUID(); - - static const char LogHeader[]; - /** Find a user in the UUID hash * @param uid The UUID to find * @return A pointer to the user, or NULL if the user does not exist */ User* FindUUID(const std::string &uid); - /** Find a user in the UUID hash - * @param uid The UUID to find - * @return A pointer to the user, or NULL if the user does not exist - */ - User* FindUUID(const char *uid); - - /** Build the ISUPPORT string by triggering all modules On005Numeric events - */ - void BuildISupport(); - /** Time this ircd was booted */ time_t startup_time; @@ -428,10 +372,6 @@ class CoreExport InspIRCd */ SnomaskManager* SNO; - /** DNS class, provides resolver facilities to the core and modules - */ - DNS* Res; - /** Timer manager class, triggers Timer timer events */ TimerManager* Timers; @@ -454,19 +394,18 @@ class CoreExport InspIRCd /** Set to the current signal recieved */ - int s_signal; + static sig_atomic_t s_signal; /** Protocol interface, overridden by server protocol modules */ ProtocolInterface* PI; - /** Holds extensible for user nickforced - */ - LocalIntExt NICKForced; - /** Holds extensible for user operquit */ - LocalStringExt OperQuit; + StringExtItem OperQuit; + + /** Manages the generation and transmission of ISUPPORT. */ + ISupportManager ISupport; /** Get the current time * Because this only calls time() once every time around the mainloop, @@ -523,17 +462,6 @@ class CoreExport InspIRCd */ User* FindNick(const std::string &nick); - /** Find a user in the nick hash. - * If the user cant be found in the nick hash check the uuid hash - * @param nick The nickname to find - * @return A pointer to the user, or NULL if the user does not exist - */ - User* FindNick(const char* nick); - - /** Find a user in the nick hash ONLY - */ - User* FindNickOnly(const char* nick); - /** Find a user in the nick hash ONLY */ User* FindNickOnly(const std::string &nick); @@ -544,34 +472,16 @@ class CoreExport InspIRCd */ Channel* FindChan(const std::string &chan); - /** Find a channel in the channels hash - * @param chan The channel to find - * @return A pointer to the channel, or NULL if the channel does not exist - */ - Channel* FindChan(const char* chan); - - /** Check we aren't running as root, and exit if we are - * @return Depending on the configuration, this function may never return - */ - void CheckRoot(); - - /** Determine the right path for, and open, the logfile - * @param argv The argv passed to main() initially, used to calculate program path - * @param argc The argc passed to main() initially, used to calculate program path - * @return True if the log could be opened, false if otherwise - */ - bool OpenLog(char** argv, int argc); - /** Return true if a channel name is valid * @param chname A channel name to verify * @return True if the name is valid */ - caller2<bool, const char*, size_t> IsChannel; + caller1<bool, const std::string&> IsChannel; /** Return true if str looks like a server ID - * @param string to check against + * @param sid string to check against */ - caller1<bool, const std::string&> IsSID; + static bool IsSID(const std::string& sid); /** Rehash the local server */ @@ -600,10 +510,18 @@ class CoreExport InspIRCd */ static void QuickExit(int status); + /** Formats the input string with the specified arguments. + * @param formatString The string to format + * @param ... A variable number of format arguments. + * @return The formatted string + */ + static const char* Format(const char* formatString, ...) CUSTOM_PRINTF(1, 2); + static const char* Format(va_list &vaList, const char* formatString) CUSTOM_PRINTF(2, 0); + /** Return a count of channels on the network * @return The number of channels */ - long ChannelCount(); + long ChannelCount() const { return chanlist->size(); } /** Send an error notice to all local users, opered and unopered * @param s The error string to send @@ -614,56 +532,13 @@ class CoreExport InspIRCd * @param n A nickname to verify * @return True if the nick is valid */ - caller2<bool, const char*, size_t> IsNick; + caller1<bool, const std::string&> IsNick; /** Return true if an ident is valid * @param An ident to verify * @return True if the ident is valid */ - caller1<bool, const char*> IsIdent; - - /** Add a dns Resolver class to this server's active set - * @param r The resolver to add - * @param cached If this value is true, then the cache will - * be searched for the DNS result, immediately. If the value is - * false, then a request will be sent to the nameserver, and the - * result will not be immediately available. You should usually - * use the boolean value which you passed to the Resolver - * constructor, which Resolver will set appropriately depending - * on if cached results are available and haven't expired. It is - * however safe to force this value to false, forcing a remote DNS - * lookup, but not an update of the cache. - * @return True if the operation completed successfully. Note that - * if this method returns true, you should not attempt to access - * the resolver class you pass it after this call, as depending upon - * the request given, the object may be deleted! - */ - bool AddResolver(Resolver* r, bool cached); - - /** Add a command to this server's command parser - * @param f A Command command handler object to add - * @throw ModuleException Will throw ModuleExcption if the command already exists - */ - inline void AddCommand(Command *f) - { - Modules->AddService(*f); - } - - /** Send a modechange. - * The parameters provided are identical to that sent to the - * handler for class cmd_mode. - * @param parameters The mode parameters - * @param user The user to send error messages to - */ - void SendMode(const std::vector<std::string>& parameters, User *user); - - /** Send a modechange and route it to the network. - * The parameters provided are identical to that sent to the - * handler for class cmd_mode. - * @param parameters The mode parameters - * @param user The user to send error messages to - */ - void SendGlobalMode(const std::vector<std::string>& parameters, User *user); + caller1<bool, const std::string&> IsIdent; /** Match two strings using pattern matching, optionally, with a map * to check case against (may be NULL). If map is null, match will be case insensitive. @@ -671,8 +546,8 @@ class CoreExport InspIRCd * @param mask The glob pattern to match against. * @param map The character map to use when matching. */ - static bool Match(const std::string &str, const std::string &mask, unsigned const char *map = NULL); - static bool Match(const char *str, const char *mask, unsigned const char *map = NULL); + static bool Match(const std::string& str, const std::string& mask, unsigned const char* map = NULL); + static bool Match(const char* str, const char* mask, unsigned const char* map = NULL); /** Match two strings using pattern matching, optionally, with a map * to check case against (may be NULL). If map is null, match will be case insensitive. @@ -681,24 +556,15 @@ class CoreExport InspIRCd * @param mask The glob or CIDR pattern to match against. * @param map The character map to use when matching. */ - static bool MatchCIDR(const std::string &str, const std::string &mask, unsigned const char *map = NULL); - static bool MatchCIDR(const char *str, const char *mask, unsigned const char *map = NULL); - - /** Call the handler for a given command. - * @param commandname The command whos handler you wish to call - * @param parameters The mode parameters - * @param user The user to execute the command as - * @return True if the command handler was called successfully - */ - CmdResult CallCommandHandler(const std::string &commandname, const std::vector<std::string>& parameters, User* user); + static bool MatchCIDR(const std::string& str, const std::string& mask, unsigned const char* map = NULL); + static bool MatchCIDR(const char* str, const char* mask, unsigned const char* map = NULL); - /** Return true if the command is a module-implemented command and the given parameters are valid for it - * @param commandname The command name to check - * @param pcnt The parameter count - * @param user The user to test-execute the command as - * @return True if the command handler is a module command, and there are enough parameters and the user has permission to the command + /** Matches a hostname and IP against a space delimited list of hostmasks. + * @param masks The space delimited masks to match against. + * @param hostname The hostname to try and match. + * @param ipaddr The IP address to try and match. */ - bool IsValidModuleCommand(const std::string &commandname, int pcnt, User* user); + static bool MatchMask(const std::string& masks, const std::string& hostname, const std::string& ipaddr); /** Return true if the given parameter is a valid nick!user\@host mask * @param mask A nick!user\@host masak to match against @@ -746,7 +612,7 @@ class CoreExport InspIRCd * (one year, two weeks, three days, four hours, six minutes and five seconds) * @return The total number of seconds */ - long Duration(const std::string &str); + static unsigned long Duration(const std::string& str); /** Attempt to compare a password to a string from the config file. * This will be passed to handling modules which will compare the data @@ -774,7 +640,7 @@ class CoreExport InspIRCd /** Returns the full version string of this ircd * @return The version string */ - std::string GetVersionString(bool rawversion = false); + std::string GetVersionString(bool getFullVersion = false); /** Attempt to write the process id to a given file * @param filename The PID file to attempt to write to @@ -808,16 +674,6 @@ class CoreExport InspIRCd */ void SendWhoisLine(User* user, User* dest, int numeric, const char* format, ...) CUSTOM_PRINTF(5, 6); - /** Handle /WHOIS - */ - void DoWhois(User* user, User* dest,unsigned long signon, unsigned long idle, const char* nick); - - /** Quit a user for excess flood, and if they are not - * fully registered yet, temporarily zline their IP. - * @param current user to quit - */ - caller1<void, User*> FloodQuitUser; - /** Called to check whether a channel restriction mode applies to a user * @param User that is attempting some action * @param Channel that the action is being performed on @@ -825,31 +681,12 @@ class CoreExport InspIRCd */ caller3<ModResult, User*, Channel*, const std::string&> OnCheckExemption; - /** Restart the server. - * This function will not return. If an error occurs, - * it will throw an instance of CoreException. - * @param reason The restart reason to show to all clients - * @throw CoreException An instance of CoreException indicating the error from execv(). - */ - void Restart(const std::string &reason); - /** Prepare the ircd for restart or shutdown. * This function unloads all modules which can be unloaded, * closes all open sockets, and closes the logfile. */ void Cleanup(); - /** This copies the user and channel hash_maps into new hash maps. - * This frees memory used by the hash_map allocator (which it neglects - * to free, most of the time, using tons of ram) - */ - void RehashUsersAndChans(); - - /** Resets the cached max bans value on all channels. - * Called by rehash. - */ - void ResetMaxBans(); - /** Return a time_t as a human-readable string. */ std::string TimeString(time_t curtime); @@ -857,20 +694,13 @@ class CoreExport InspIRCd /** Begin execution of the server. * NOTE: this function NEVER returns. Internally, * it will repeatedly loop. - * @return The return value for this function is undefined. - */ - int Run(); - - /** Adds an extban char to the 005 token. */ - void AddExtBanChar(char c); + void Run(); char* GetReadBuffer() { return this->ReadBuffer; } - - friend class TestSuite; }; ENTRYPOINT; @@ -894,5 +724,3 @@ class CommandModule : public Module return Version(cmd.name, VF_VENDOR|VF_CORE); } }; - -#endif diff --git a/include/inspsocket.h b/include/inspsocket.h index c62c5a250..720489b77 100644 --- a/include/inspsocket.h +++ b/include/inspsocket.h @@ -21,11 +21,12 @@ */ -#ifndef INSPSOCKET_H -#define INSPSOCKET_H +#pragma once #include "timer.h" +class IOHook; + /** * States which a socket may be in */ @@ -93,7 +94,7 @@ class CoreExport SocketTimeout : public Timer /** Handle tick event */ - virtual void Tick(time_t now); + virtual bool Tick(time_t now); }; /** @@ -102,8 +103,9 @@ class CoreExport SocketTimeout : public Timer */ class CoreExport StreamSocket : public EventHandler { - /** Module that handles raw I/O for this socket, or NULL */ - reference<Module> IOHook; + /** The IOHook that handles raw I/O for this socket, or NULL */ + IOHook* iohook; + /** Private send queue. Note that individual strings may be shared */ std::deque<std::string> sendq; @@ -114,10 +116,10 @@ class CoreExport StreamSocket : public EventHandler protected: std::string recvq; public: - StreamSocket() : sendq_len(0) {} - inline Module* GetIOHook(); - inline void AddIOHook(Module* m); - inline void DelIOHook(); + StreamSocket() : iohook(NULL), sendq_len(0) {} + IOHook* GetIOHook() const; + void AddIOHook(IOHook* hook); + void DelIOHook(); /** Handle event from socket engine. * This will call OnDataReady if there is *new* data in recvq */ @@ -229,9 +231,6 @@ class CoreExport BufferedSocket : public StreamSocket BufferedSocketError BeginConnect(const std::string &ipaddr, int aport, unsigned long maxtime, const std::string &connectbindip); }; -#include "modules.h" - -inline Module* StreamSocket::GetIOHook() { return IOHook; } -inline void StreamSocket::AddIOHook(Module* m) { IOHook = m; } -inline void StreamSocket::DelIOHook() { IOHook = NULL; } -#endif +inline IOHook* StreamSocket::GetIOHook() const { return iohook; } +inline void StreamSocket::AddIOHook(IOHook* hook) { iohook = hook; } +inline void StreamSocket::DelIOHook() { iohook = NULL; } diff --git a/include/inspstring.h b/include/inspstring.h index a6ef5e552..ccc77da66 100644 --- a/include/inspstring.h +++ b/include/inspstring.h @@ -18,40 +18,38 @@ */ -#ifndef INSPSTRING_H -#define INSPSTRING_H +#pragma once -// This (inspircd_config) is needed as inspstring doesn't pull in the central header -#include "inspircd_config.h" +// This (config) is needed as inspstring doesn't pull in the central header +#include "config.h" #include <cstring> -//#include <cstddef> -#ifndef HAS_STRLCPY -/** strlcpy() implementation for systems that don't have it (linux) */ -CoreExport size_t strlcpy(char *dst, const char *src, size_t siz); -/** strlcat() implementation for systems that don't have it (linux) */ -CoreExport size_t strlcat(char *dst, const char *src, size_t siz); -#endif - -/** charlcat() will append one character to a string using the same - * safety scemantics as strlcat(). - * @param x The string to operate on - * @param y the character to append to the end of x - * @param z The maximum allowed length for z including null terminator - */ -CoreExport int charlcat(char* x,char y,int z); -/** charremove() will remove all instances of a character from a string - * @param mp The string to operate on - * @param remove The character to remove +/** Sets ret to the formated string. last is the last parameter before ..., and format is the format in printf-style */ +#define VAFORMAT(ret, last, format) \ + do { \ + va_list _vaList; \ + va_start(_vaList, last); \ + ret = InspIRCd::Format(_vaList, format); \ + va_end(_vaList); \ + } while (false); + +/** Compose a hex string from raw data. + * @param raw The raw data to compose hex from (can be NULL if rawsize is 0) + * @param rawsize The size of the raw data buffer + * @return The hex string */ -CoreExport bool charremove(char* mp, char remove); +CoreExport std::string BinToHex(const void* raw, size_t rawsize); -/** Binary to hexadecimal conversion */ -CoreExport std::string BinToHex(const std::string& data); /** Base64 encode */ CoreExport std::string BinToBase64(const std::string& data, const char* table = NULL, char pad = 0); /** Base64 decode */ CoreExport std::string Base64ToBin(const std::string& data, const char* table = NULL); -#endif - +/** Compose a hex string from the data in a std::string. + * @param data The data to compose hex from + * @return The hex string. + */ +inline std::string BinToHex(const std::string& data) +{ + return BinToHex(data.data(), data.size()); +} diff --git a/include/iohook.h b/include/iohook.h new file mode 100644 index 000000000..7c3a0faee --- /dev/null +++ b/include/iohook.h @@ -0,0 +1,79 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +class StreamSocket; + +class IOHook : public ServiceProvider +{ + public: + enum Type + { + IOH_UNKNOWN, + IOH_SSL + }; + + const Type type; + + IOHook(Module* mod, const std::string& Name, Type hooktype = IOH_UNKNOWN) + : ServiceProvider(mod, Name, SERVICE_IOHOOK), type(hooktype) { } + + /** Called immediately after any connection is accepted. This is intended for raw socket + * processing (e.g. modules which wrap the tcp connection within another library) and provides + * no information relating to a user record as the connection has not been assigned yet. + * There are no return values from this call as all modules get an opportunity if required to + * process the connection. + * @param sock The socket in question + * @param client The client IP address and port + * @param server The server IP address and port + */ + virtual void OnStreamSocketAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) = 0; + + /** + * Called when a hooked stream has data to write, or when the socket + * engine returns it as writable + * @param sock The socket in question + * @param sendq Data to send to the socket + * @return 1 if the sendq has been completely emptied, 0 if there is + * still data to send, and -1 if there was an error + */ + virtual int OnStreamSocketWrite(StreamSocket* sock, std::string& sendq) = 0; + + /** Called immediately before any socket is closed. When this event is called, shutdown() + * has not yet been called on the socket. + * @param sock The socket in question + */ + virtual void OnStreamSocketClose(StreamSocket* sock) = 0; + + /** Called immediately upon connection of an outbound BufferedSocket which has been hooked + * by a module. + * @param sock The socket in question + */ + virtual void OnStreamSocketConnect(StreamSocket* sock) = 0; + + /** + * Called when the stream socket has data to read + * @param sock The socket that is ready + * @param recvq The receive queue that new data should be appended to + * @return 1 if new data has been read, 0 if no new data is ready (but the + * socket is still connected), -1 if there was an error or close + */ + virtual int OnStreamSocketRead(StreamSocket* sock, std::string& recvq) = 0; +}; diff --git a/include/listmode.h b/include/listmode.h new file mode 100644 index 000000000..e27071eac --- /dev/null +++ b/include/listmode.h @@ -0,0 +1,218 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +/** The base class for list modes, should be inherited. + */ +class CoreExport ListModeBase : public ModeHandler +{ + public: + /** An item in a listmode's list + */ + struct ListItem + { + std::string setter; + std::string mask; + time_t time; + ListItem(const std::string& Mask, const std::string& Setter, time_t Time) + : setter(Setter), mask(Mask), time(Time) { } + }; + + /** Items stored in the channel's list + */ + typedef std::list<ListItem> ModeList; + + private: + class ChanData + { + public: + ModeList list; + int maxitems; + + ChanData() : maxitems(-1) { } + }; + + /** The number of items a listmode's list may contain + */ + struct ListLimit + { + std::string mask; + unsigned int limit; + ListLimit(const std::string& Mask, unsigned int Limit) : mask(Mask), limit(Limit) { } + bool operator==(const ListLimit& other) const { return (this->mask == other.mask && this->limit == other.limit); } + }; + + /** Max items per channel by name + */ + typedef std::vector<ListLimit> limitlist; + + /** Finds the limit of modes that can be placed on the given channel name according to the config + * @param channame The channel name to find the limit for + * @return The maximum number of modes of this type that we allow to be set on the given channel name + */ + unsigned int FindLimit(const std::string& channame); + + /** Returns the limit on the given channel for this mode. + * If the limit is cached then the cached value is returned, + * otherwise the limit is determined using FindLimit() and cached + * for later queries before it is returned + * @param channame The channel name to find the limit for + * @param cd The ChanData associated with channel channame + * @return The maximum number of modes of this type that we allow to be set on the given channel + */ + unsigned int GetLimitInternal(const std::string& channame, ChanData* cd); + + protected: + /** Numeric to use when outputting the list + */ + unsigned int listnumeric; + /** Numeric to indicate end of list + */ + unsigned int endoflistnumeric; + /** String to send for end of list + */ + std::string endofliststring; + /** Automatically tidy up entries + */ + bool tidy; + /** Config tag to check for max items per channel + */ + std::string configtag; + /** Limits on a per-channel basis read from the tag + * specified in ListModeBase::configtag + */ + limitlist chanlimits; + + /** Storage key + */ + SimpleExtItem<ChanData> extItem; + + public: + /** Constructor. + * @param Creator The creator of this class + * @param Name Mode name + * @param modechar Mode character + * @param eolstr End of list string + * @param lnum List numeric + * @param eolnum End of list numeric + * @param autotidy Automatically tidy list entries on add + * @param ctag Configuration tag to get limits from + */ + ListModeBase(Module* Creator, const std::string& Name, char modechar, const std::string &eolstr, unsigned int lnum, unsigned int eolnum, bool autotidy, const std::string &ctag = "banlist"); + + /** Get limit of this mode on a channel + * @param channel The channel to inspect + * @return Maximum number of modes of this type that can be placed on the given channel + */ + unsigned int GetLimit(Channel* channel); + + /** Retrieves the list of all modes set on the given channel + * @param channel Channel to get the list from + * @return A list with all modes of this type set on the given channel, can be NULL + */ + ModeList* GetList(Channel* channel); + + /** Display the list for this mode + * See mode.h + * @param user The user to send the list to + * @param channel The channel the user is requesting the list for + */ + virtual void DisplayList(User* user, Channel* channel); + + /** Tell a user that a list contains no elements. + * Sends 'eolnum' numeric with text 'eolstr', unless overridden (see constructor) + * @param user The user issuing the command + * @param channel The channel that has the empty list + * See mode.h + */ + virtual void DisplayEmptyList(User* user, Channel* channel); + + /** Remove all instances of the mode from a channel. + * Populates the given modestack with modes that remove every instance of + * this mode from the channel. + * See mode.h for more details. + * @param channel The channel to remove all instances of the mode from + * @param stack The mode stack to add the mode change to + */ + virtual void RemoveMode(Channel* channel, irc::modestacker& stack); + + /** Perform a rehash of this mode's configuration data + */ + virtual void DoRehash(); + + /** Populate the Implements list with the correct events for a List Mode + */ + virtual void DoImplements(Module* m); + + /** Handle the list mode. + * See mode.h + */ + virtual ModeAction OnModeChange(User* source, User*, Channel* channel, std::string ¶meter, bool adding); + + /** Syncronize channel item list with another server. + * See modules.h + * @param chan Channel to syncronize + * @param proto Protocol module pointer + * @param opaque Opaque connection handle + */ + virtual void DoSyncChannel(Channel* chan, Module* proto, void* opaque); + + /** Validate parameters. + * Overridden by implementing module. + * @param user Source user adding the parameter + * @param channel Channel the parameter is being added to + * @param parameter The actual parameter being added + * @return true if the parameter is valid + */ + virtual bool ValidateParam(User* user, Channel* channel, std::string& parameter); + + /** Tell the user the list is too long. + * Overridden by implementing module. + * @param source Source user adding the parameter + * @param channel Channel the parameter is being added to + * @param parameter The actual parameter being added + */ + virtual void TellListTooLong(User* source, Channel* channel, std::string& parameter); + + /** Tell the user an item is already on the list. + * Overridden by implementing module. + * @param source Source user adding the parameter + * @param channel Channel the parameter is being added to + * @param parameter The actual parameter being added + */ + virtual void TellAlreadyOnList(User* source, Channel* channel, std::string& parameter); + + /** Tell the user that the parameter is not in the list. + * Overridden by implementing module. + * @param source Source user removing the parameter + * @param channel Channel the parameter is being removed from + * @param parameter The actual parameter being removed + */ + virtual void TellNotSet(User* source, Channel* channel, std::string& parameter); +}; + +inline ListModeBase::ModeList* ListModeBase::GetList(Channel* channel) +{ + ChanData* cd = extItem.get(channel); + if (!cd) + return NULL; + + return &cd->list; +} diff --git a/include/logger.h b/include/logger.h index 0fa4bc7cd..2ea280be8 100644 --- a/include/logger.h +++ b/include/logger.h @@ -18,8 +18,18 @@ */ -#ifndef LOGGER_H -#define LOGGER_H +#pragma once + +/** Levels at which messages can be logged. */ +enum LogLevel +{ + LOG_RAWIO = 5, + LOG_DEBUG = 10, + LOG_VERBOSE = 20, + LOG_DEFAULT = 30, + LOG_SPARSE = 40, + LOG_NONE = 50 +}; /** Simple wrapper providing periodic flushing to a disk-backed file. */ @@ -77,9 +87,11 @@ class CoreExport FileWriter class CoreExport LogStream : public classbase { protected: - int loglvl; + LogLevel loglvl; public: - LogStream(int loglevel) : loglvl(loglevel) + static const char LogHeader[]; + + LogStream(LogLevel loglevel) : loglvl(loglevel) { } @@ -91,13 +103,13 @@ class CoreExport LogStream : public classbase /** Changes the loglevel for this LogStream on-the-fly. * This is needed for -nofork. But other LogStreams could use it to change loglevels. */ - void ChangeLevel(int lvl) { this->loglvl = lvl; } + void ChangeLevel(LogLevel lvl) { this->loglvl = lvl; } /** Called when there is stuff to log for this particular logstream. The derived class may take no action with it, or do what it * wants with the output, basically. loglevel and type are primarily for informational purposes (the level and type of the event triggered) * and msg is, of course, the actual message to log. */ - virtual void OnLog(int loglevel, const std::string &type, const std::string &msg) = 0; + virtual void OnLog(LogLevel loglevel, const std::string &type, const std::string &msg) = 0; }; typedef std::map<FileWriter*, int> FileLogMap; @@ -127,7 +139,6 @@ class CoreExport LogManager FileLogMap FileLogs; public: - LogManager(); ~LogManager(); @@ -199,17 +210,15 @@ class CoreExport LogManager /** Logs an event, sending it to all LogStreams registered for the type. * @param type Log message type (ex: "USERINPUT", "MODULE", ...) - * @param loglevel Log message level (DEBUG, VERBOSE, DEFAULT, SPARSE, NONE) + * @param loglevel Log message level (LOG_DEBUG, LOG_VERBOSE, LOG_DEFAULT, LOG_SPARSE, LOG_NONE) * @param msg The message to be logged (literal). */ - void Log(const std::string &type, int loglevel, const std::string &msg); + void Log(const std::string &type, LogLevel loglevel, const std::string &msg); /** Logs an event, sending it to all LogStreams registered for the type. * @param type Log message type (ex: "USERINPUT", "MODULE", ...) - * @param loglevel Log message level (DEBUG, VERBOSE, DEFAULT, SPARSE, NONE) + * @param loglevel Log message level (LOG_DEBUG, LOG_VERBOSE, LOG_DEFAULT, LOG_SPARSE, LOG_NONE) * @param fmt The format of the message to be logged. See your C manual on printf() for details. */ - void Log(const std::string &type, int loglevel, const char *fmt, ...) CUSTOM_PRINTF(4, 5); + void Log(const std::string &type, LogLevel loglevel, const char *fmt, ...) CUSTOM_PRINTF(4, 5); }; - -#endif diff --git a/include/membership.h b/include/membership.h index 436a9371c..5850e0ae0 100644 --- a/include/membership.h +++ b/include/membership.h @@ -17,8 +17,7 @@ */ -#ifndef MEMBERSHIP_H -#define MEMBERSHIP_H +#pragma once class CoreExport Membership : public Extensible { @@ -46,7 +45,7 @@ class CoreExport InviteBase friend class Invitation; }; -class Invitation : public classbase +class CoreExport Invitation : public classbase { Invitation(Channel* c, LocalUser* u, time_t timeout) : user(u), chan(c), expiry(timeout) {} @@ -59,5 +58,3 @@ class Invitation : public classbase static void Create(Channel* c, LocalUser* u, time_t timeout); static Invitation* Find(Channel* c, LocalUser* u, bool check_expired = true); }; - -#endif diff --git a/include/mode.h b/include/mode.h index 1dab442d4..9b8d07877 100644 --- a/include/mode.h +++ b/include/mode.h @@ -20,8 +20,7 @@ */ -#ifndef MODE_H -#define MODE_H +#pragma once #include "ctables.h" @@ -101,6 +100,13 @@ enum ParamSpec */ class CoreExport ModeHandler : public ServiceProvider { + /** + * Removes this prefix mode from all users on the given channel + * @param channel The channel which the server wants to remove your mode from + * @param stack The mode stack to add the mode change to + */ + void RemovePrefixMode(Channel* chan, irc::modestacker& stack); + protected: /** * The mode parameter translation type @@ -149,6 +155,11 @@ class CoreExport ModeHandler : public ServiceProvider */ int levelrequired; + /** The prefix rank of this mode, used to compare prefix + * modes + */ + unsigned int prefixrank; + public: /** * The constructor for ModeHandler initalizes the mode handler. @@ -166,7 +177,7 @@ class CoreExport ModeHandler : public ServiceProvider /** * Returns true if the mode is a list mode */ - bool IsListMode(); + bool IsListMode() const { return list; } /** * Mode prefix or 0. If this is defined, you should * also implement GetPrefixRank() to return an integer @@ -180,7 +191,7 @@ class CoreExport ModeHandler : public ServiceProvider * PrefixModeValue enum and Channel::GetPrefixValue() for * more information. */ - virtual unsigned int GetPrefixRank(); + unsigned int GetPrefixRank() const { return prefixrank; } /** * Returns the mode's type */ @@ -269,26 +280,23 @@ class CoreExport ModeHandler : public ServiceProvider virtual bool ResolveModeConflict(std::string &their_param, const std::string &our_param, Channel* channel); /** - * When a MODETYPE_USER mode handler is being removed, the server will call this method for every user on the server. - * Your mode handler should remove its user mode from the user by sending the appropriate server modes using - * InspIRCd::SendMode(). The default implementation of this method can remove simple modes which have no parameters, - * and can be used when your mode is of this type, otherwise you must implement a more advanced version of it to remove - * your mode properly from each user. + * When a MODETYPE_USER mode handler is being removed, the core will call this method for every user on the server. + * The usermode will be removed using the appropiate server mode using InspIRCd::SendMode(). * @param user The user which the server wants to remove your mode from - * @param stack The mode stack to add the mode change to */ - virtual void RemoveMode(User* user, irc::modestacker* stack = NULL); + void RemoveMode(User* user); /** * When a MODETYPE_CHANNEL mode handler is being removed, the server will call this method for every channel on the server. - * Your mode handler should remove its user mode from the channel by sending the appropriate server modes using - * InspIRCd::SendMode(). The default implementation of this method can remove simple modes which have no parameters, - * and can be used when your mode is of this type, otherwise you must implement a more advanced version of it to remove - * your mode properly from each channel. Note that in the case of listmodes, you should remove the entire list of items. + * The mode handler has to populate the given modestacker with mode changes that remove the mode from the channel. + * The default implementation of this method can remove all kinds of channel modes except listmodes. + * In the case of listmodes, the entire list of items must be added to the modestacker (which is handled by ListModeBase, + * so if you inherit from it or your mode can be removed by the default implementation then you do not have to implement + * this function). * @param channel The channel which the server wants to remove your mode from * @param stack The mode stack to add the mode change to */ - virtual void RemoveMode(Channel* channel, irc::modestacker* stack = NULL); + virtual void RemoveMode(Channel* channel, irc::modestacker& stack); inline unsigned int GetLevelRequired() const { return levelrequired; } }; @@ -339,11 +347,12 @@ class CoreExport ParamChannelModeHandler : public ModeHandler */ class CoreExport ModeWatcher : public classbase { - protected: + private: /** - * The mode letter this class is watching + * The mode name this class is watching */ - char mode; + const std::string mode; + /** * The mode type being watched (user or channel) */ @@ -354,17 +363,18 @@ class CoreExport ModeWatcher : public classbase /** * The constructor initializes the mode and the mode type */ - ModeWatcher(Module* creator, char modeletter, ModeType type); + ModeWatcher(Module* creator, const std::string& modename, ModeType type); /** * The default destructor does nothing. */ virtual ~ModeWatcher(); /** - * Get the mode character being watched - * @return The mode character being watched + * Get the mode name being watched + * @return The mode name being watched */ - char GetModeChar(); + const std::string& GetModeName() const { return mode; } + /** * Get the mode type being watched * @return The mode type being watched (user or channel) @@ -380,11 +390,10 @@ class CoreExport ModeWatcher : public classbase * If you alter the parameter you are given, the mode handler will see your atered version * when it handles the mode. * @param adding True if the mode is being added and false if it is being removed - * @param type The mode type, either MODETYPE_USER or MODETYPE_CHANNEL * @return True to allow the mode change to go ahead, false to abort it. If you abort the * change, the mode handler (and ModeWatcher::AfterMode()) will never see the mode change. */ - virtual bool BeforeMode(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, ModeType type); + virtual bool BeforeMode(User* source, User* dest, Channel* channel, std::string& parameter, bool adding); /** * After the mode character has been processed by the ModeHandler, this method will be called. * @param source The sender of the mode @@ -393,12 +402,11 @@ class CoreExport ModeWatcher : public classbase * @param parameter The parameter of the mode, if the mode is supposed to have a parameter. * You cannot alter the parameter here, as the mode handler has already processed it. * @param adding True if the mode is being added and false if it is being removed - * @param type The mode type, either MODETYPE_USER or MODETYPE_CHANNEL */ - virtual void AfterMode(User* source, User* dest, Channel* channel, const std::string ¶meter, bool adding, ModeType type); + virtual void AfterMode(User* source, User* dest, Channel* channel, const std::string& parameter, bool adding); }; -typedef std::vector<ModeWatcher*>::iterator ModeWatchIter; +typedef std::multimap<std::string, ModeWatcher*>::iterator ModeWatchIter; /** The mode parser handles routing of modes and handling of mode strings. * It marshalls, controls and maintains both ModeWatcher and ModeHandler classes, @@ -414,11 +422,11 @@ class CoreExport ModeParser * or a channel mode, so we have 256 of them not 64. */ ModeHandler* modehandlers[256]; - /** Mode watcher classes arranged in the same way as the - * mode handlers, except for instead of having 256 of them - * we have 256 lists of them. + + /** Mode watcher classes */ - std::vector<ModeWatcher*> modewatchers[256]; + std::multimap<std::string, ModeWatcher*> modewatchermap; + /** Displays the current modes of a channel or user. * Used by ModeParser::Process. */ @@ -433,6 +441,20 @@ class CoreExport ModeParser */ ModeAction TryMode(User* user, User* targu, Channel* targc, bool adding, unsigned char mode, std::string ¶m, bool SkipACL); + /** Returns a list of user or channel mode characters. + * Used for constructing the parts of the mode list in the 004 numeric. + * @param mt Controls whether to list user modes or channel modes + * @param needparam Return modes only if they require a parameter to be set + * @return The available mode letters that satisfy the given conditions + */ + std::string CreateModeList(ModeType mt, bool needparam = false); + + /** Recreate the cached mode list that is displayed in the 004 numeric + * in Cached004ModeList. + * Called when a mode handler is added or removed. + */ + void RecreateModeListFor004Numeric(); + /** The string representing the last set of modes to be parsed. * Use GetLastParse() to get this value, to be used for display purposes. */ @@ -444,17 +466,41 @@ class CoreExport ModeParser unsigned int seq; + /** Cached mode list for use in 004 numeric + */ + std::string Cached004ModeList; + public: + typedef unsigned int ModeProcessFlag; + enum ModeProcessFlags + { + /** If only this flag is specified, the mode change will be global + * and parameter modes will have their parameters explicitly set + * (not merged). This is the default. + */ + MODE_NONE = 0, + + /** If this flag is set then the parameters of non-listmodes will be + * merged according to their conflict resolution rules. + * Does not affect user modes, channel modes without a parameter and + * listmodes. + */ + MODE_MERGE = 1, + + /** If this flag is set then the mode change won't be handed over to + * the linking module to be sent to other servers, but will be processed + * locally and sent to local user(s) as usual. + */ + MODE_LOCALONLY = 2 + }; - /** The constructor initializes all the RFC basic modes by using ModeParserAddMode(). - */ ModeParser(); ~ModeParser(); - /** Used to check if user 'd' should be allowed to do operation 'MASK' on channel 'chan'. - * for example, should 'user A' be able to 'op' on 'channel B'. + /** Initialize all built-in modes */ - User* SanityChecks(User *user,const char *dest,Channel *chan,int status); + static void InitBuiltinModes(); + /** Tidy a banmask. This makes a banmask 'acceptable' if fields are left out. * E.g. * @@ -474,7 +520,7 @@ class CoreExport ModeParser * may be different to what you sent after it has been 'cleaned up' by the parser. * @return Last parsed string, as seen by users. */ - const std::string& GetLastParse(); + const std::string& GetLastParse() const { return LastParse; } const std::vector<std::string>& GetLastParseParams() { return LastParseParams; } const std::vector<TranslateType>& GetLastParseTranslate() { return LastParseTranslate; } /** Add a mode to the mode parser. @@ -496,9 +542,9 @@ class CoreExport ModeParser * triggered. See the documentation of class ModeWatcher for more * information. * @param mw The ModeWatcher you want to add - * @return True if the ModeWatcher was added correctly */ - bool AddModeWatcher(ModeWatcher* mw); + void AddModeWatcher(ModeWatcher* mw); + /** Delete a mode watcher. * A mode watcher is triggered before and after a mode handler is * triggered. See the documentation of class ModeWatcher for more @@ -510,12 +556,11 @@ class CoreExport ModeParser /** Process a set of mode changes from a server or user. * @param parameters The parameters of the mode change, in the format * they would be from a MODE command. - * @param user The user setting or removing the modes. When the modes are set - * by a server, an 'uninitialized' User is used, where *user\::nick == NULL - * and *user->server == NULL. - * @param merge Should the mode parameters be merged? + * @param user The source of the mode change, can be a server user. + * @param flags Optional flags controlling how the mode change is processed, + * defaults to MODE_NONE. */ - void Process(const std::vector<std::string>& parameters, User *user, bool merge = false); + void Process(const std::vector<std::string>& parameters, User* user, ModeProcessFlag flags = MODE_NONE); /** Find the mode handler for a given mode and type. * @param modeletter mode letter to search for @@ -531,20 +576,13 @@ class CoreExport ModeParser */ ModeHandler* FindPrefix(unsigned const char pfxletter); - /** Returns a list of mode characters which are usermodes. - * This is used in the 004 numeric when users connect. - */ - std::string UserModeList(); - - /** Returns a list of channel mode characters which are listmodes. - * This is used in the 004 numeric when users connect. + /** Returns a list of modes, space seperated by type: + * 1. User modes + * 2. Channel modes + * 3. Channel modes that require a parameter when set + * This is sent to users as the last part of the 004 numeric */ - std::string ChannelModeList(); - - /** Returns a list of channel mode characters which take parameters. - * This is used in the 004 numeric when users connect. - */ - std::string ParaModeList(); + const std::string& GetModeListFor004Numeric(); /** Generates a list of modes, comma seperated by type: * 1; Listmodes EXCEPT those with a prefix @@ -554,12 +592,13 @@ class CoreExport ModeParser */ std::string GiveModeList(ModeMasks m); - static bool PrefixComparison(ModeHandler* one, ModeHandler* two); - /** This returns the PREFIX=(ohv)@%+ section of the 005 numeric, or * just the "@%+" part if the parameter false */ std::string BuildPrefixes(bool lettersAndModes = true); }; -#endif +inline const std::string& ModeParser::GetModeListFor004Numeric() +{ + return Cached004ModeList; +} diff --git a/include/modes/cmode_b.h b/include/modes/cmode_b.h deleted file mode 100644 index afd5cd13b..000000000 --- a/include/modes/cmode_b.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "mode.h" -#include "channels.h" - -class InspIRCd; - -/** Channel mode +b - */ -class ModeChannelBan : public ModeHandler -{ - private: - BanItem b; - public: - ModeChannelBan(); - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); - std::string& AddBan(User *user,std::string& dest,Channel *chan,int status); - std::string& DelBan(User *user,std::string& dest,Channel *chan,int status); - void DisplayList(User* user, Channel* channel); - void DisplayEmptyList(User* user, Channel* channel); - void RemoveMode(User* user, irc::modestacker* stack = NULL); - void RemoveMode(Channel* channel, irc::modestacker* stack = NULL); -}; - diff --git a/include/modes/cmode_k.h b/include/modes/cmode_k.h deleted file mode 100644 index 000667f72..000000000 --- a/include/modes/cmode_k.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "mode.h" - -class InspIRCd; - -/** Channel mode +k - */ -class ModeChannelKey : public ModeHandler -{ - public: - ModeChannelKey(); - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); - void RemoveMode(Channel* channel, irc::modestacker* stack = NULL); - void RemoveMode(User* user, irc::modestacker* stack = NULL); -}; diff --git a/include/modes/cmode_l.h b/include/modes/cmode_l.h deleted file mode 100644 index 3018a0d67..000000000 --- a/include/modes/cmode_l.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "mode.h" - -/** Channel mode +l - */ -class ModeChannelLimit : public ParamChannelModeHandler -{ - public: - ModeChannelLimit(); - bool ParamValidate(std::string& parameter); - bool ResolveModeConflict(std::string &their_param, const std::string &our_param, Channel* channel); -}; diff --git a/include/modes/cmode_o.h b/include/modes/cmode_o.h deleted file mode 100644 index c5f1764c1..000000000 --- a/include/modes/cmode_o.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "mode.h" -#include "channels.h" - -class InspIRCd; - -/** Channel mode +o - */ -class ModeChannelOp : public ModeHandler -{ - private: - public: - ModeChannelOp(); - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); - unsigned int GetPrefixRank(); - void RemoveMode(Channel* channel, irc::modestacker* stack = NULL); - void RemoveMode(User* user, irc::modestacker* stack = NULL); -}; - diff --git a/include/modes/cmode_v.h b/include/modes/cmode_v.h deleted file mode 100644 index ab037f33f..000000000 --- a/include/modes/cmode_v.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "mode.h" -#include "channels.h" - -class InspIRCd; - -/** Channel mode +v - */ -class ModeChannelVoice : public ModeHandler -{ - private: - public: - ModeChannelVoice(); - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); - unsigned int GetPrefixRank(); - void RemoveMode(User* user, irc::modestacker* stack = NULL); - void RemoveMode(Channel* channel, irc::modestacker* stack = NULL); -}; - diff --git a/include/modes/simplemodes.h b/include/modes/simplemodes.h deleted file mode 100644 index 661bba400..000000000 --- a/include/modes/simplemodes.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> - * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "mode.h" - -/** Channel mode +i - */ -class ModeChannelInviteOnly : public SimpleChannelModeHandler -{ - public: - ModeChannelInviteOnly() : SimpleChannelModeHandler(NULL, "inviteonly", 'i') - { - } -}; - -/** Channel mode +m - */ -class ModeChannelModerated : public SimpleChannelModeHandler -{ - public: - ModeChannelModerated() : SimpleChannelModeHandler(NULL, "moderated", 'm') - { - } -}; - -/** Channel mode +n - */ -class ModeChannelNoExternal : public SimpleChannelModeHandler -{ - public: - ModeChannelNoExternal() : SimpleChannelModeHandler(NULL, "noextmsg", 'n') - { - } -}; - -/** Channel mode +p - */ -class ModeChannelPrivate : public SimpleChannelModeHandler -{ - public: - ModeChannelPrivate() : SimpleChannelModeHandler(NULL, "private", 'p') - { - } -}; - -/** Channel mode +s - */ -class ModeChannelSecret : public SimpleChannelModeHandler -{ - public: - ModeChannelSecret() : SimpleChannelModeHandler(NULL, "secret", 's') - { - } -}; - -/** Channel mode +t - */ -class ModeChannelTopicOps : public SimpleChannelModeHandler -{ - public: - ModeChannelTopicOps() : SimpleChannelModeHandler(NULL, "topiclock", 't') - { - } -}; - -/** User mode +i - */ -class ModeUserInvisible : public SimpleUserModeHandler -{ - public: - ModeUserInvisible() : SimpleUserModeHandler(NULL, "invisible", 'i') - { - } -}; - -/** User mode +w - */ -class ModeUserWallops : public SimpleUserModeHandler -{ - public: - ModeUserWallops() : SimpleUserModeHandler(NULL, "wallops", 'w') - { - } -}; diff --git a/include/modes/umode_s.h b/include/modes/umode_s.h deleted file mode 100644 index 8ac8fa31a..000000000 --- a/include/modes/umode_s.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> - * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "mode.h" - -class InspIRCd; - -/** User mode +n - */ -class ModeUserServerNoticeMask : public ModeHandler -{ - public: - ModeUserServerNoticeMask(); - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); - void OnParameterMissing(User* user, User* dest, Channel* channel); - std::string GetUserParameter(User* user); -}; diff --git a/include/modules.h b/include/modules.h index 00f2cbb62..d13ff58b0 100644 --- a/include/modules.h +++ b/include/modules.h @@ -23,8 +23,7 @@ */ -#ifndef MODULES_H -#define MODULES_H +#pragma once #include "dynamic.h" #include "base.h" @@ -35,7 +34,6 @@ #include <sstream> #include "timer.h" #include "mode.h" -#include "dns.h" /** Used to define a set of behavior bits for a module */ @@ -109,35 +107,33 @@ struct ModResult { /** InspIRCd major version. * 1.2 -> 102; 2.1 -> 201; 2.12 -> 212 */ -#define INSPIRCD_VERSION_MAJ 200 +#define INSPIRCD_VERSION_MAJ 202 /** InspIRCd API version. * If you change any API elements, increment this value. This counter should be * reset whenever the major version is changed. Modules can use these two values * and numerical comparisons in preprocessor macros if they wish to support * multiple versions of InspIRCd in one file. */ -#define INSPIRCD_VERSION_API 6 +#define INSPIRCD_VERSION_API 1 /** * This #define allows us to call a method in all * loaded modules in a readable simple way, e.g.: - * 'FOREACH_MOD(I_OnConnect,OnConnect(user));' + * 'FOREACH_MOD(OnConnect,(user));' */ #define FOREACH_MOD(y,x) do { \ - EventHandlerIter safei; \ - for (EventHandlerIter _i = ServerInstance->Modules->EventHandlers[y].begin(); _i != ServerInstance->Modules->EventHandlers[y].end(); ) \ + const IntModuleList& _handlers = ServerInstance->Modules->EventHandlers[I_ ## y]; \ + for (IntModuleList::const_reverse_iterator _i = _handlers.rbegin(), _next; _i != _handlers.rend(); _i = _next) \ { \ - safei = _i; \ - ++safei; \ + _next = _i+1; \ try \ { \ - (*_i)->x ; \ + (*_i)->y x ; \ } \ catch (CoreException& modexcept) \ { \ - ServerInstance->Logs->Log("MODULE",DEFAULT,"Exception caught: %s",modexcept.GetReason()); \ + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Exception caught: %s",modexcept.GetReason()); \ } \ - _i = safei; \ } \ } while (0); @@ -149,21 +145,19 @@ struct ModResult { */ #define DO_EACH_HOOK(n,v,args) \ do { \ - EventHandlerIter iter_ ## n = ServerInstance->Modules->EventHandlers[I_ ## n].begin(); \ - while (iter_ ## n != ServerInstance->Modules->EventHandlers[I_ ## n].end()) \ + const IntModuleList& _handlers = ServerInstance->Modules->EventHandlers[I_ ## n]; \ + for (IntModuleList::const_reverse_iterator _i = _handlers.rbegin(), _next; _i != _handlers.rend(); _i = _next) \ { \ - Module* mod_ ## n = *iter_ ## n; \ - iter_ ## n ++; \ + _next = _i+1; \ try \ { \ - v = (mod_ ## n)->n args; + v = (*_i)->n args; #define WHILE_EACH_HOOK(n) \ } \ catch (CoreException& except_ ## n) \ { \ - ServerInstance->Logs->Log("MODULE",DEFAULT,"Exception caught: %s", (except_ ## n).GetReason()); \ - (void) mod_ ## n; /* catch mismatched pairs */ \ + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Exception caught: %s", (except_ ## n).GetReason()); \ } \ } \ } while(0) @@ -212,41 +206,6 @@ class CoreExport Version virtual ~Version() {} }; -/** The Request class is a unicast message directed at a given module. - * When this class is properly instantiated it may be sent to a module - * using the Send() method, which will call the given module's OnRequest - * method with this class as its parameter. - */ -class CoreExport Request : public classbase -{ - public: - /** This should be a null-terminated string identifying the type of request, - * all modules should define this and use it to determine the nature of the - * request before they attempt to cast the Request in any way. - */ - const char* const id; - /** This is a pointer to the sender of the message, which can be used to - * directly trigger events, or to create a reply. - */ - ModuleRef source; - /** The single destination of the Request - */ - ModuleRef dest; - - /** Create a new Request - * This is for the 'new' way of defining a subclass - * of Request and defining it in a common header, - * passing an object of your Request subclass through - * as a Request* and using the ID string to determine - * what to cast it back to and the other end. - */ - Request(Module* src, Module* dst, const char* idstr); - /** Send the Request. - */ - void Send(); -}; - - /** The Event class is a unicast message directed at all modules. * When the class is properly instantiated it may be sent to all modules * using the Send() method, which will trigger the OnEvent method in @@ -282,38 +241,6 @@ class CoreExport DataProvider : public ServiceProvider : ServiceProvider(Creator, Name, SERVICE_DATA) {} }; -class CoreExport dynamic_reference_base : public interfacebase -{ - private: - std::string name; - protected: - DataProvider* value; - public: - ModuleRef creator; - dynamic_reference_base(Module* Creator, const std::string& Name); - ~dynamic_reference_base(); - inline void ClearCache() { value = NULL; } - inline const std::string& GetProvider() { return name; } - void SetProvider(const std::string& newname); - void lookup(); - operator bool(); - static void reset_all(); -}; - -template<typename T> -class dynamic_reference : public dynamic_reference_base -{ - public: - dynamic_reference(Module* Creator, const std::string& Name) - : dynamic_reference_base(Creator, Name) {} - inline T* operator->() - { - if (!value) - lookup(); - return static_cast<T*>(value); - } -}; - /** Priority types which can be used by Module::Prioritize() */ enum Priority { PRIORITY_FIRST, PRIORITY_LAST, PRIORITY_BEFORE, PRIORITY_AFTER }; @@ -325,16 +252,16 @@ enum Implementation I_BEGIN, I_OnUserConnect, I_OnUserQuit, I_OnUserDisconnect, I_OnUserJoin, I_OnUserPart, I_OnRehash, I_OnSendSnotice, I_OnUserPreJoin, I_OnUserPreKick, I_OnUserKick, I_OnOper, I_OnInfo, I_OnWhois, - I_OnUserPreInvite, I_OnUserInvite, I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserPreNick, - I_OnUserMessage, I_OnUserNotice, I_OnMode, I_OnGetServerDescription, I_OnSyncUser, - I_OnSyncChannel, I_OnDecodeMetaData, I_OnWallops, I_OnAcceptConnection, I_OnUserInit, + I_OnUserPreInvite, I_OnUserInvite, I_OnUserPreMessage, I_OnUserPreNick, + I_OnUserMessage, I_OnMode, I_OnGetServerDescription, I_OnSyncUser, + I_OnSyncChannel, I_OnDecodeMetaData, I_OnAcceptConnection, I_OnUserInit, I_OnChangeHost, I_OnChangeName, I_OnAddLine, I_OnDelLine, I_OnExpireLine, - I_OnUserPostNick, I_OnPreMode, I_On005Numeric, I_OnKill, I_OnRemoteKill, I_OnLoadModule, + I_OnUserPostNick, I_OnPreMode, I_On005Numeric, I_OnKill, I_OnLoadModule, I_OnUnloadModule, I_OnBackgroundTimer, I_OnPreCommand, I_OnCheckReady, I_OnCheckInvite, I_OnRawMode, I_OnCheckKey, I_OnCheckLimit, I_OnCheckBan, I_OnCheckChannelBan, I_OnExtBanCheck, I_OnStats, I_OnChangeLocalUserHost, I_OnPreTopicChange, - I_OnPostTopicChange, I_OnEvent, I_OnGlobalOper, I_OnPostConnect, I_OnAddBan, - I_OnDelBan, I_OnChangeLocalUserGECOS, I_OnUserRegister, I_OnChannelPreDelete, I_OnChannelDelete, + I_OnPostTopicChange, I_OnEvent, I_OnGlobalOper, I_OnPostConnect, + I_OnChangeLocalUserGECOS, I_OnUserRegister, I_OnChannelPreDelete, I_OnChannelDelete, I_OnPostOper, I_OnSyncNetwork, I_OnSetAway, I_OnPostCommand, I_OnPostJoin, I_OnWhoisLine, I_OnBuildNeighborList, I_OnGarbageCollect, I_OnSetConnectClass, I_OnText, I_OnPassCompare, I_OnRunTestSuite, I_OnNamesListItem, I_OnNumeric, I_OnHookIO, @@ -349,6 +276,11 @@ enum Implementation */ class CoreExport Module : public classbase, public usecountbase { + /** Detach an event from this module + * @param i Event type to detach + */ + void DetachEvent(Implementation i); + public: /** File that this module was loaded from */ @@ -514,7 +446,7 @@ class CoreExport Module : public classbase, public usecountbase * @param keygiven The key given to join the channel, or an empty string if none was provided * @return 1 To prevent the join, 0 to allow it. */ - virtual ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven); + virtual ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven); /** Called whenever a user is about to be kicked. * Returning a value of 1 from this function stops the process immediately, causing no @@ -611,30 +543,10 @@ class CoreExport Module : public classbase, public usecountbase * @param status The status being used, e.g. PRIVMSG @#chan has status== '@', 0 to send to everyone. * @param exempt_list A list of users not to send to. For channel messages, this will usually contain just the sender. * It will be ignored for private messages. + * @param msgtype The message type, MSG_PRIVMSG for PRIVMSGs, MSG_NOTICE for NOTICEs * @return 1 to deny the message, 0 to allow it */ - virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text,char status, CUList &exempt_list); - - /** Called whenever a user is about to NOTICE A user or a channel, before any processing is done. - * Returning any nonzero value from this function stops the process immediately, causing no - * output to be sent to the user by the core. If you do this you must produce your own numerics, - * notices etc. This is useful for modules which may want to filter or redirect messages. - * target_type can be one of TYPE_USER or TYPE_CHANNEL. If the target_type value is a user, - * you must cast dest to a User* otherwise you must cast it to a Channel*, this is the details - * of where the message is destined to be sent. - * You may alter the message text as you wish before relinquishing control to the next module - * in the chain, and if no other modules block the text this altered form of the text will be sent out - * to the user and possibly to other servers. - * @param user The user sending the message - * @param dest The target of the message (Channel* or User*) - * @param target_type The type of target (TYPE_USER or TYPE_CHANNEL) - * @param text Changeable text being sent by the user - * @param status The status being used, e.g. PRIVMSG @#chan has status== '@', 0 to send to everyone. - * @param exempt_list A list of users not to send to. For channel notices, this will usually contain just the sender. - * It will be ignored for private notices. - * @return 1 to deny the NOTICE, 0 to allow it - */ - virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text,char status, CUList &exempt_list); + virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text,char status, CUList &exempt_list, MessageType msgtype); /** Called when sending a message to all "neighbors" of a given user - * that is, all users that share a common channel. This is used in @@ -668,25 +580,14 @@ class CoreExport Module : public classbase, public usecountbase * @param text the text being sent by the user * @param status The status being used, e.g. PRIVMSG @#chan has status== '@', 0 to send to everyone. * @param exempt_list A list of users to not send to. + * @param msgtype The message type, MSG_PRIVMSG for PRIVMSGs, MSG_NOTICE for NOTICEs */ - virtual void OnUserMessage(User* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list); - - /** Called after any NOTICE sent from a user. - * The dest variable contains a User* if target_type is TYPE_USER and a Channel* - * if target_type is TYPE_CHANNEL. - * @param user The user sending the message - * @param dest The target of the message - * @param target_type The type of target (TYPE_USER or TYPE_CHANNEL) - * @param text the text being sent by the user - * @param status The status being used, e.g. NOTICE @#chan has status== '@', 0 to send to everyone. - * @param exempt_list A list of users to not send to. - */ - virtual void OnUserNotice(User* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list); + virtual void OnUserMessage(User* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list, MessageType msgtype); /** Called immediately before any NOTICE or PRIVMSG sent from a user, local or remote. * The dest variable contains a User* if target_type is TYPE_USER and a Channel* * if target_type is TYPE_CHANNEL. - * The difference between this event and OnUserPreNotice/OnUserPreMessage is that delivery is gauranteed, + * The difference between this event and OnUserPreMessage is that delivery is gauranteed, * the message has already been vetted. In the case of the other two methods, a later module may stop your * message. This also differs from OnUserMessage which occurs AFTER the message has been sent. * @param user The user sending the message @@ -699,16 +600,17 @@ class CoreExport Module : public classbase, public usecountbase virtual void OnText(User* user, void* dest, int target_type, const std::string &text, char status, CUList &exempt_list); /** Called after every MODE command sent from a user - * The dest variable contains a User* if target_type is TYPE_USER and a Channel* - * if target_type is TYPE_CHANNEL. The text variable contains the remainder of the - * mode string after the target, e.g. "+wsi" or "+ooo nick1 nick2 nick3". + * Either the usertarget or the chantarget variable contains the target of the modes, + * the actual target will have a non-NULL pointer. + * The modes vector contains the remainder of the mode string after the target, + * e.g.: "+wsi" or ["+ooo", "nick1", "nick2", "nick3"]. * @param user The user sending the MODEs - * @param dest The target of the modes (User* or Channel*) - * @param target_type The type of target (TYPE_USER or TYPE_CHANNEL) - * @param text The actual modes and their parameters if any + * @param usertarget The target user of the modes, NULL if the target is a channel + * @param chantarget The target channel of the modes, NULL if the target is a user + * @param modes The actual modes and their parameters if any * @param translate The translation types of the mode parameters */ - virtual void OnMode(User* user, void* dest, int target_type, const std::vector<std::string> &text, const std::vector<TranslateType> &translate); + virtual void OnMode(User* user, User* usertarget, Channel* chantarget, const std::vector<std::string>& modes, const std::vector<TranslateType>& translate); /** Allows modules to alter or create server descriptions * Whenever a module requires a server description, for example for display in @@ -741,8 +643,6 @@ class CoreExport Module : public classbase, public usecountbase * (see below). This function will be called for every user visible on your side * of the burst, allowing you to for example set modes, etc. * - * For a good example of how to use this function, please see src/modules/m_chanprotect.cpp - * * @param chan The channel being syncronized * @param proto A pointer to the module handling network protocol * @param opaque An opaque pointer set by the protocol module, should not be modified! @@ -775,9 +675,6 @@ class CoreExport Module : public classbase, public usecountbase * down the network link as a broadcast, without a module calling it having to know the format * of the MODE command before the actual mode string. * - * More documentation to follow soon. Please see src/modules/m_chanprotect.cpp for examples - * of how to use this function. - * * @param opaque An opaque pointer set by the protocol module, should not be modified! * @param target_type The type of item to decode data for, TYPE_USER or TYPE_CHANNEL * @param target The Channel* or User* that modes should be sent for @@ -801,12 +698,6 @@ class CoreExport Module : public classbase, public usecountbase */ virtual void ProtoSendMetaData(void* opaque, Extensible* target, const std::string &extname, const std::string &extdata); - /** Called after every WALLOPS command. - * @param user The user sending the WALLOPS - * @param text The content of the WALLOPS message - */ - virtual void OnWallops(User* user, const std::string &text); - /** Called whenever a user's hostname is changed. * This event triggers after the host has been set. * @param user The user whos host is being changed @@ -885,9 +776,9 @@ class CoreExport Module : public classbase, public usecountbase /** Called when a 005 numeric is about to be output. * The module should modify the 005 numeric if needed to indicate its features. - * @param output The 005 string to be modified if neccessary. - */ - virtual void On005Numeric(std::string &output); + * @param tokens The 005 map to be modified if neccessary. + */ + virtual void On005Numeric(std::map<std::string, std::string>& tokens); /** Called when a client is disconnected by KILL. * If a client is killed by a server, e.g. a nickname collision or protocol error, @@ -904,14 +795,6 @@ class CoreExport Module : public classbase, public usecountbase */ virtual ModResult OnKill(User* source, User* dest, const std::string &reason); - /** Called when an oper wants to disconnect a remote user via KILL - * @param source The user sending the KILL - * @param dest The user being killed - * @param reason The kill reason - * @param operreason The oper kill reason - */ - virtual void OnRemoteKill(User* source, User* dest, const std::string &reason, const std::string &operreason); - /** Called whenever a module is loaded. * mod will contain a pointer to the module, and string will contain its name, * for example m_widgets.so. This function is primary for dependency checking, @@ -976,7 +859,7 @@ class CoreExport Module : public classbase, public usecountbase * @param result The return code given by the command handler, one of CMD_SUCCESS or CMD_FAILURE * @param original_line The entire original line as passed to the parser from the user */ - virtual void OnPostCommand(const std::string &command, const std::vector<std::string>& parameters, LocalUser *user, CmdResult result, const std::string &original_line); + virtual void OnPostCommand(Command* command, const std::vector<std::string>& parameters, LocalUser* user, CmdResult result, const std::string& original_line); /** Called when a user is first connecting, prior to starting DNS lookups, checking initial * connect class, or accepting any commands. @@ -1128,12 +1011,6 @@ class CoreExport Module : public classbase, public usecountbase */ virtual void OnEvent(Event& event); - /** Called whenever a Request class is sent to your module by another module. - * The value of Request::id should be used to determine the type of request. - * @param request The Request class being received - */ - virtual void OnRequest(Request& request); - /** Called whenever a password check is to be made. Replaces the old OldOperCompare API. * The password field (from the config file) is in 'password' and is to be compared against * 'input'. This method allows for encryption of passwords (oper, connect:allow, die/restart, etc). @@ -1162,24 +1039,6 @@ class CoreExport Module : public classbase, public usecountbase */ virtual void OnPostConnect(User* user); - /** Called whenever a ban is added to a channel's list. - * Return a non-zero value to 'eat' the mode change and prevent the ban from being added. - * @param source The user adding the ban - * @param channel The channel the ban is being added to - * @param banmask The ban mask being added - * @return 1 to block the ban, 0 to continue as normal - */ - virtual ModResult OnAddBan(User* source, Channel* channel,const std::string &banmask); - - /** Called whenever a ban is removed from a channel's list. - * Return a non-zero value to 'eat' the mode change and prevent the ban from being removed. - * @param source The user deleting the ban - * @param channel The channel the ban is being deleted from - * @param banmask The ban mask being deleted - * @return 1 to block the unban, 0 to continue as normal - */ - virtual ModResult OnDelBan(User* source, Channel* channel,const std::string &banmask); - /** Called to install an I/O hook on an event handler * @param user The socket to possibly install the I/O hook on * @param via The port that the user connected on @@ -1195,48 +1054,6 @@ class CoreExport Module : public classbase, public usecountbase */ virtual ModResult OnAcceptConnection(int fd, ListenSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server); - /** Called immediately after any connection is accepted. This is intended for raw socket - * processing (e.g. modules which wrap the tcp connection within another library) and provides - * no information relating to a user record as the connection has not been assigned yet. - * There are no return values from this call as all modules get an opportunity if required to - * process the connection. - * @param sock The socket in question - * @param client The client IP address and port - * @param server The server IP address and port - */ - virtual void OnStreamSocketAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server); - - /** - * Called when a hooked stream has data to write, or when the socket - * engine returns it as writable - * @param sock The socket in question - * @param sendq Data to send to the socket - * @return 1 if the sendq has been completely emptied, 0 if there is - * still data to send, and -1 if there was an error - */ - virtual int OnStreamSocketWrite(StreamSocket* sock, std::string& sendq); - - /** Called immediately before any socket is closed. When this event is called, shutdown() - * has not yet been called on the socket. - * @param sock The socket in question - */ - virtual void OnStreamSocketClose(StreamSocket* sock); - - /** Called immediately upon connection of an outbound BufferedSocket which has been hooked - * by a module. - * @param sock The socket in question - */ - virtual void OnStreamSocketConnect(StreamSocket* sock); - - /** - * Called when the stream socket has data to read - * @param sock The socket that is ready - * @param recvq The receive queue that new data should be appended to - * @return 1 if new data has been read, 0 if no new data is ready (but the - * socket is still connected), -1 if there was an error or close - */ - virtual int OnStreamSocketRead(StreamSocket* sock, std::string& recvq); - /** Called whenever a user sets away or returns from being away. * The away message is available as a parameter, but should not be modified. * At this stage, it has already been copied into the user record. @@ -1301,171 +1118,42 @@ class CoreExport Module : public classbase, public usecountbase virtual void OnSetUserIP(LocalUser* user); }; - -#define CONF_NO_ERROR 0x000000 -#define CONF_NOT_A_NUMBER 0x000010 -#define CONF_INT_NEGATIVE 0x000080 -#define CONF_VALUE_NOT_FOUND 0x000100 -#define CONF_FILE_NOT_FOUND 0x000200 - - -/** Allows reading of values from configuration files - * This class allows a module to read from either the main configuration file (inspircd.conf) or from - * a module-specified configuration file. It may either be instantiated with one parameter or none. - * Constructing the class using one parameter allows you to specify a path to your own configuration - * file, otherwise, inspircd.conf is read. - */ -class CoreExport ConfigReader : public interfacebase -{ - protected: - /** Error code - */ - long error; - - public: - /** Default constructor. - * This constructor initialises the ConfigReader class to read the inspircd.conf file - * as specified when running ./configure. - */ - ConfigReader(); - /** Default destructor. - * This method destroys the ConfigReader class. - */ - ~ConfigReader(); - - /** Retrieves a value from the config file. - * This method retrieves a value from the config file. Where multiple copies of the tag - * exist in the config file, index indicates which of the values to retrieve. - */ - std::string ReadValue(const std::string &tag, const std::string &name, int index, bool allow_linefeeds = false); - /** Retrieves a value from the config file. - * This method retrieves a value from the config file. Where multiple copies of the tag - * exist in the config file, index indicates which of the values to retrieve. If the - * tag is not found the default value is returned instead. - */ - std::string ReadValue(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool allow_linefeeds = false); - - /** Retrieves a boolean value from the config file. - * This method retrieves a boolean value from the config file. Where multiple copies of the tag - * exist in the config file, index indicates which of the values to retrieve. The values "1", "yes" - * and "true" in the config file count as true to ReadFlag, and any other value counts as false. - */ - bool ReadFlag(const std::string &tag, const std::string &name, int index); - /** Retrieves a boolean value from the config file. - * This method retrieves a boolean value from the config file. Where multiple copies of the tag - * exist in the config file, index indicates which of the values to retrieve. The values "1", "yes" - * and "true" in the config file count as true to ReadFlag, and any other value counts as false. - * If the tag is not found, the default value is used instead. - */ - bool ReadFlag(const std::string &tag, const std::string &name, const std::string &default_value, int index); - - /** Retrieves an integer value from the config file. - * This method retrieves an integer value from the config file. Where multiple copies of the tag - * exist in the config file, index indicates which of the values to retrieve. Any invalid integer - * values in the tag will cause the objects error value to be set, and any call to GetError() will - * return CONF_INVALID_NUMBER to be returned. need_positive is set if the number must be non-negative. - * If a negative number is placed into a tag which is specified positive, 0 will be returned and GetError() - * will return CONF_INT_NEGATIVE. Note that need_positive is not suitable to get an unsigned int - you - * should cast the result to achieve that effect. - */ - int ReadInteger(const std::string &tag, const std::string &name, int index, bool need_positive); - /** Retrieves an integer value from the config file. - * This method retrieves an integer value from the config file. Where multiple copies of the tag - * exist in the config file, index indicates which of the values to retrieve. Any invalid integer - * values in the tag will cause the objects error value to be set, and any call to GetError() will - * return CONF_INVALID_NUMBER to be returned. needs_unsigned is set if the number must be unsigned. - * If a signed number is placed into a tag which is specified unsigned, 0 will be returned and GetError() - * will return CONF_NOT_UNSIGNED. If the tag is not found, the default value is used instead. - */ - int ReadInteger(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool need_positive); - - /** Returns the last error to occur. - * Valid errors can be found by looking in modules.h. Any nonzero value indicates an error condition. - * A call to GetError() resets the error flag back to 0. - */ - long GetError(); - - /** Counts the number of times a given tag appears in the config file. - * This method counts the number of times a tag appears in a config file, for use where - * there are several tags of the same kind, e.g. with opers and connect types. It can be - * used with the index value of ConfigReader::ReadValue to loop through all copies of a - * multiple instance tag. - */ - int Enumerate(const std::string &tag); -}; - - - -/** Caches a text file into memory and can be used to retrieve lines from it. - * This class contains methods for read-only manipulation of a text file in memory. - * Either use the constructor type with one parameter to load a file into memory - * at construction, or use the LoadFile method to load a file. - */ +/** Provides an easy method of reading a text file into memory. */ class CoreExport FileReader : public classbase { - /** The file contents + /** The lines of text in the file. */ - std::vector<std::string> fc; + std::vector<std::string> lines; /** Content size in bytes */ - unsigned long contentsize; - - /** Calculate content size in bytes - */ - void CalcSize(); + unsigned long totalSize; public: - /** Default constructor. - * This method does not load any file into memory, you must use the LoadFile method - * after constructing the class this way. - */ - FileReader(); - - /** Secondary constructor. - * This method initialises the class with a file loaded into it ready for GetLine and - * and other methods to be called. If the file could not be loaded, FileReader::FileSize - * returns 0. - */ - FileReader(const std::string &filename); - - /** Default destructor. - * This deletes the memory allocated to the file. + /** Initializes a new file reader. */ - ~FileReader(); + FileReader() : totalSize(0) { } - /** Used to load a file. - * This method loads a file into the class ready for GetLine and - * and other methods to be called. If the file could not be loaded, FileReader::FileSize - * returns 0. + /** Initializes a new file reader and reads the specified file. + * @param filename The file to read into memory. */ - void LoadFile(const std::string &filename); + FileReader(const std::string& filename); - /** Returns the whole content of the file as std::string + /** Loads a text file from disk. + * @param filename The file to read into memory. + * @throw CoreException The file can not be loaded. */ - std::string Contents(); + void Load(const std::string& filename); - /** Returns the entire size of the file as std::string + /** Retrieves the entire contents of the file cache as a single string. */ - unsigned long ContentSize(); + std::string GetString(); - /** Returns true if the file exists - * This function will return false if the file could not be opened. + /** Retrieves the entire contents of the file cache as a vector of strings. */ - bool Exists(); + const std::vector<std::string>& GetVector() { return lines; } - /** Retrieve one line from the file. - * This method retrieves one line from the text file. If an empty non-NULL string is returned, - * the index was out of bounds, or the line had no data on it. - */ - std::string GetLine(int x); - - /** Returns the size of the file in lines. - * This method returns the number of lines in the read file. If it is 0, no lines have been - * read into memory, either because the file is empty or it does not exist, or cannot be - * opened due to permission problems. - */ - int FileSize(); + unsigned long TotalSize() { return totalSize; } }; /** A list of modules @@ -1585,6 +1273,11 @@ class CoreExport ModuleManager */ void DetachAll(Module* mod); + /** Attach all events to a module (used on module load) + * @param mod Module to attach to all events + */ + void AttachAll(Module* mod); + /** Returns text describing the last module error * @return The last error message to occur */ @@ -1726,11 +1419,9 @@ struct AllModuleList { { \ return new y; \ } \ - extern "C" const char inspircd_src_version[] = VERSION " r" REVISION; + extern "C" const char inspircd_src_version[] = VERSION " " REVISION; #endif #define COMMAND_INIT(c) MODULE_INIT(CommandModule<c>) #endif - -#endif diff --git a/src/modules/account.h b/include/modules/account.h index ba671ba0b..c00b044e4 100644 --- a/src/modules/account.h +++ b/include/modules/account.h @@ -17,8 +17,7 @@ */ -#ifndef ACCOUNT_H -#define ACCOUNT_H +#pragma once #include <map> #include <string> @@ -40,5 +39,3 @@ inline AccountExtItem* GetAccountExtItem() { return static_cast<AccountExtItem*>(ServerInstance->Extensions.GetItem("accountname")); } - -#endif diff --git a/src/modules/m_cap.h b/include/modules/cap.h index 409671f48..2ed8df494 100644 --- a/src/modules/m_cap.h +++ b/include/modules/cap.h @@ -18,8 +18,7 @@ */ -#ifndef M_CAP_H -#define M_CAP_H +#pragma once class CapEvent : public Event { @@ -89,4 +88,3 @@ class GenericCap } }; -#endif diff --git a/include/modules/dns.h b/include/modules/dns.h new file mode 100644 index 000000000..65a1762b3 --- /dev/null +++ b/include/modules/dns.h @@ -0,0 +1,193 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Adam <Adam@anope.org> + * Copyright (C) 2003-2013 Anope Team <team@anope.org> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +namespace DNS +{ + /** Valid query types + */ + enum QueryType + { + /* Nothing */ + QUERY_NONE, + /* A simple A lookup */ + QUERY_A = 1, + /* A CNAME lookup */ + QUERY_CNAME = 5, + /* Reverse DNS lookup */ + QUERY_PTR = 12, + /* IPv6 AAAA lookup */ + QUERY_AAAA = 28 + }; + + /** Flags that can be AND'd into DNSPacket::flags to receive certain values + */ + enum + { + QUERYFLAGS_QR = 0x8000, + QUERYFLAGS_OPCODE = 0x7800, + QUERYFLAGS_AA = 0x400, + QUERYFLAGS_TC = 0x200, + QUERYFLAGS_RD = 0x100, + QUERYFLAGS_RA = 0x80, + QUERYFLAGS_Z = 0x70, + QUERYFLAGS_RCODE = 0xF + }; + + enum Error + { + ERROR_NONE, + ERROR_UNKNOWN, + ERROR_UNLOADED, + ERROR_TIMEDOUT, + ERROR_NOT_AN_ANSWER, + ERROR_NONSTANDARD_QUERY, + ERROR_FORMAT_ERROR, + ERROR_SERVER_FAILURE, + ERROR_DOMAIN_NOT_FOUND, + ERROR_NOT_IMPLEMENTED, + ERROR_REFUSED, + ERROR_NO_RECORDS, + ERROR_INVALIDTYPE + }; + + const int PORT = 53; + + /** + * The maximum value of a dns request id, + * 16 bits wide, 0xFFFF. + */ + const int MAX_REQUEST_ID = 0xFFFF; + + class Exception : public ModuleException + { + public: + Exception(const std::string& message) : ModuleException(message) { } + }; + + struct Question + { + std::string name; + QueryType type; + unsigned short qclass; + + Question() : type(QUERY_NONE), qclass(0) { } + Question(const std::string& n, QueryType t, unsigned short c = 1) : name(n), type(t), qclass(c) { } + inline bool operator==(const Question& other) const { return name == other.name && type == other.type && qclass == other.qclass; } + + struct hash + { + size_t operator()(const Question& question) const + { + return irc::insensitive()(question.name); + } + }; + }; + + struct ResourceRecord : Question + { + unsigned int ttl; + std::string rdata; + time_t created; + + ResourceRecord(const std::string& n, QueryType t, unsigned short c = 1) : Question(n, t, c), ttl(0), created(ServerInstance->Time()) { } + ResourceRecord(const Question& question) : Question(question), ttl(0), created(ServerInstance->Time()) { } + }; + + struct Query + { + std::vector<Question> questions; + std::vector<ResourceRecord> answers; + Error error; + bool cached; + + Query() : error(ERROR_NONE), cached(false) { } + Query(const Question& question) : error(ERROR_NONE), cached(false) { questions.push_back(question); } + }; + + class ReplySocket; + class Request; + + /** DNS manager + */ + class Manager : public DataProvider + { + public: + Manager(Module* mod) : DataProvider(mod, "DNS") { } + + virtual void Process(Request* req) = 0; + virtual void RemoveRequest(Request* req) = 0; + virtual std::string GetErrorStr(Error) = 0; + }; + + /** A DNS query. + */ + class Request : public Timer, public Question + { + protected: + Manager* const manager; + public: + /* Use result cache if available */ + bool use_cache; + /* Request id */ + unsigned short id; + /* Creator of this request */ + Module* const creator; + + Request(Manager* mgr, Module* mod, const std::string& addr, QueryType qt, bool usecache = true) + : Timer((ServerInstance->Config->dns_timeout ? ServerInstance->Config->dns_timeout : 5), ServerInstance->Time()) + , Question(addr, qt) + , manager(mgr) + , use_cache(usecache) + , id(0) + , creator(mod) + { + ServerInstance->Timers->AddTimer(this); + } + + virtual ~Request() + { + manager->RemoveRequest(this); + } + + /** Called when this request succeeds + * @param r The query sent back from the nameserver + */ + virtual void OnLookupComplete(const Query* req) = 0; + + /** Called when this request fails or times out. + * @param r The query sent back from the nameserver, check the error code. + */ + virtual void OnError(const Query* req) { } + + /** Used to time out the query, calls OnError and asks the TimerManager + * to delete this request + */ + bool Tick(time_t now) + { + Query rr(*this); + rr.error = ERROR_TIMEDOUT; + this->OnError(&rr); + return false; + } + }; + +} // namespace DNS + diff --git a/src/modules/hash.h b/include/modules/hash.h index f7bf85e20..da04c45ba 100644 --- a/src/modules/hash.h +++ b/include/modules/hash.h @@ -17,8 +17,7 @@ */ -#ifndef HASH_H -#define HASH_H +#pragma once #include "modules.h" @@ -40,20 +39,6 @@ class HashProvider : public DataProvider return BinToBase64(sum(data), NULL, 0); } - /** Allows the IVs for the hash to be specified. As the choice of initial IV is - * important for the security of a hash, this should not be used except to - * maintain backwards compatability. This also allows you to change the hex - * sequence from its default of "0123456789abcdef", which does not improve the - * strength of the output, but helps confuse those attempting to implement it. - * - * Example: - * \code - * unsigned int iv[] = { 0xFFFFFFFF, 0x00000000, 0xAAAAAAAA, 0xCCCCCCCC }; - * std::string result = Hash.sumIV(iv, "fedcba9876543210", "data"); - * \endcode - */ - virtual std::string sumIV(unsigned int* IV, const char* HexMap, const std::string &sdata) = 0; - /** HMAC algorithm, RFC 2104 */ std::string hmac(const std::string& key, const std::string& msg) { @@ -71,6 +56,3 @@ class HashProvider : public DataProvider return sum(hmac1); } }; - -#endif - diff --git a/src/modules/httpd.h b/include/modules/httpd.h index 56fd22da0..86234d53f 100644 --- a/src/modules/httpd.h +++ b/include/modules/httpd.h @@ -21,10 +21,9 @@ */ -#include "base.h" +#pragma once -#ifndef HTTPD_H -#define HTTPD_H +#include "base.h" #include <string> #include <sstream> @@ -178,30 +177,63 @@ class HTTPRequest : public Event } }; -/** You must return a HTTPDocument to the httpd module by using the Request class. - * When you initialize this class you may initialize it with all components required to - * form a valid HTTP response, including document data, headers, and a response code. +/** If you want to reply to HTTP requests, you must return a HTTPDocumentResponse to + * the httpd module via the HTTPdAPI. + * When you initialize this class you initialize it with all components required to + * form a valid HTTP response: the document data and a response code. + * You can add additional HTTP headers, if you want. */ -class HTTPDocumentResponse : public Request +class HTTPDocumentResponse { public: + /** Module that generated this reply + */ + Module* const module; + std::stringstream* document; - int responsecode; + unsigned int responsecode; + + /** Any extra headers to include with the defaults + */ HTTPHeaders headers; + HTTPRequest& src; - /** Initialize a HTTPRequest ready for sending to m_httpd.so. - * @param opaque The socket pointer you obtained from the HTTPRequest at an earlier time + /** Initialize a HTTPDocumentResponse ready for sending to the httpd module. + * @param mod A pointer to the module who responded to the request + * @param req The request you obtained from the HTTPRequest at an earlier time * @param doc A stringstream containing the document body * @param response A valid HTTP/1.0 or HTTP/1.1 response code. The response text will be determined for you * based upon the response code. - * @param extra Any extra headers to include with the defaults, seperated by carriage return and linefeed. */ - HTTPDocumentResponse(Module* me, HTTPRequest& req, std::stringstream* doc, int response) - : Request(me, req.source, "HTTP-DOC"), document(doc), responsecode(response), src(req) + HTTPDocumentResponse(Module* mod, HTTPRequest& req, std::stringstream* doc, unsigned int response) + : module(mod), document(doc), responsecode(response), src(req) { } }; -#endif +class HTTPdAPIBase : public DataProvider +{ + public: + HTTPdAPIBase(Module* parent) + : DataProvider(parent, "m_httpd_api") + { + } + + /** Answer an incoming HTTP request with the provided document + * @param response The response created by your module that will be sent to the client + */ + virtual void SendResponse(HTTPDocumentResponse& response) = 0; +}; +/** The API provided by the httpd module that allows other modules to respond to incoming + * HTTP requests + */ +class HTTPdAPI : public dynamic_reference<HTTPdAPIBase> +{ + public: + HTTPdAPI(Module* parent) + : dynamic_reference<HTTPdAPIBase>(parent, "m_httpd_api") + { + } +}; diff --git a/src/modules/m_regex.h b/include/modules/regex.h index 0233f938a..5ef00cdd0 100644 --- a/src/modules/m_regex.h +++ b/include/modules/regex.h @@ -18,26 +18,22 @@ */ -#ifndef M_REGEX_H -#define M_REGEX_H +#pragma once #include "inspircd.h" class Regex : public classbase { protected: - std::string regex_string; // The raw uncompiled regex string. + /** The uncompiled regex string. */ + std::string regex_string; // Constructor may as well be protected, as this class is abstract. - Regex(const std::string& rx) : regex_string(rx) - { - } + Regex(const std::string& rx) : regex_string(rx) { } public: - virtual ~Regex() - { - } + virtual ~Regex() { } virtual bool Matches(const std::string& text) = 0; @@ -50,9 +46,17 @@ public: class RegexFactory : public DataProvider { public: - RegexFactory(Module* Creator, const std::string& Name) : DataProvider(Creator, Name) {} + RegexFactory(Module* Creator, const std::string& Name) : DataProvider(Creator, Name) { } virtual Regex* Create(const std::string& expr) = 0; }; -#endif +class RegexException : public ModuleException +{ + public: + RegexException(const std::string& regex, const std::string& error) + : ModuleException("Error in regex '" + regex + "': " + error) { } + + RegexException(const std::string& regex, const std::string& error, int offset) + : ModuleException("Error in regex '" + regex + "' at offset " + ConvToStr(offset) + ": " + error) { } +}; diff --git a/src/modules/sasl.h b/include/modules/sasl.h index f67351104..321711a68 100644 --- a/src/modules/sasl.h +++ b/include/modules/sasl.h @@ -17,8 +17,7 @@ */ -#ifndef SASL_H -#define SASL_H +#pragma once class SASLFallback : public Event { @@ -30,5 +29,3 @@ class SASLFallback : public Event Send(); } }; - -#endif diff --git a/src/modules/spanningtree.h b/include/modules/spanningtree.h index 212f35ff3..99f4f9fc4 100644 --- a/src/modules/spanningtree.h +++ b/include/modules/spanningtree.h @@ -17,8 +17,7 @@ */ -#ifndef SPANNINGTREE_H -#define SPANNINGTREE_H +#pragma once struct AddServerEvent : public Event { @@ -39,5 +38,3 @@ struct DelServerEvent : public Event Send(); } }; - -#endif diff --git a/src/modules/sql.h b/include/modules/sql.h index 436cd1da8..a671cc95c 100644 --- a/src/modules/sql.h +++ b/include/modules/sql.h @@ -17,8 +17,7 @@ */ -#ifndef INSPIRCD_SQLAPI_3 -#define INSPIRCD_SQLAPI_3 +#pragma once /** Defines the error types which SQLerror may be set to */ @@ -183,5 +182,3 @@ class SQLProvider : public DataProvider userinfo["uuid"] = user->uuid; } }; - -#endif diff --git a/src/modules/ssl.h b/include/modules/ssl.h index 9deafb830..25076215a 100644 --- a/src/modules/ssl.h +++ b/include/modules/ssl.h @@ -18,11 +18,10 @@ */ -#ifndef SSL_H -#define SSL_H +#pragma once -#include <map> #include <string> +#include "iohook.h" /** ssl_cert is a class which abstracts SSL certificate * and key information. @@ -132,44 +131,110 @@ class ssl_cert : public refcountbase } }; -/** Get certificate from a socket (only useful with an SSL module) */ -struct SocketCertificateRequest : public Request +class SSLIOHook : public IOHook { - StreamSocket* const sock; - ssl_cert* cert; - - SocketCertificateRequest(StreamSocket* ss, Module* Me) - : Request(Me, ss->GetIOHook(), "GET_SSL_CERT"), sock(ss), cert(NULL) + public: + SSLIOHook(Module* mod, const std::string& Name) + : IOHook(mod, Name, IOHook::IOH_SSL) { - Send(); } - std::string GetFingerprint() + /** + * Get the client certificate from a socket + * @param sock The socket to get the certificate from, must be using this IOHook + * @return The SSL client certificate information + */ + virtual ssl_cert* GetCertificate(StreamSocket* sock) = 0; + + /** + * Get the fingerprint of a client certificate from a socket + * @param sock The socket to get the certificate fingerprint from, must be using this IOHook + * @return The fingerprint of the SSL client certificate sent by the peer, + * empty if no cert was sent + */ + std::string GetFingerprint(StreamSocket* sock) { + ssl_cert* cert = GetCertificate(sock); if (cert) return cert->GetFingerprint(); return ""; } }; -/** Get certificate from a user (requires m_sslinfo) */ -struct UserCertificateRequest : public Request +/** Helper functions for obtaining SSL client certificates and key fingerprints + * from StreamSockets + */ +class SSLClientCert { - User* const user; - ssl_cert* cert; + public: + /** + * Get the client certificate from a socket + * @param sock The socket to get the certificate from, the socket does not have to use SSL + * @return The SSL client certificate information, NULL if the peer is not using SSL + */ + static ssl_cert* GetCertificate(StreamSocket* sock) + { + IOHook* iohook = sock->GetIOHook(); + if ((!iohook) || (iohook->type != IOHook::IOH_SSL)) + return NULL; + + SSLIOHook* ssliohook = static_cast<SSLIOHook*>(iohook); + return ssliohook->GetCertificate(sock); + } + + /** + * Get the fingerprint of a client certificate from a socket + * @param sock The socket to get the certificate fingerprint from, the + * socket does not have to use SSL + * @return The key fingerprint from the SSL certificate sent by the peer, + * empty if no cert was sent or the peer is not using SSL + */ + static std::string GetFingerprint(StreamSocket* sock) + { + ssl_cert* cert = SSLClientCert::GetCertificate(sock); + if (cert) + return cert->GetFingerprint(); + return ""; + } +}; - UserCertificateRequest(User* u, Module* Me, Module* info = ServerInstance->Modules->Find("m_sslinfo.so")) - : Request(Me, info, "GET_USER_CERT"), user(u), cert(NULL) +class UserCertificateAPIBase : public DataProvider +{ + public: + UserCertificateAPIBase(Module* parent) + : DataProvider(parent, "m_sslinfo_api") { - Send(); } - std::string GetFingerprint() + /** Get the SSL certificate of a user + * @param user The user whose certificate to get, user may be remote + * @return The SSL certificate of the user or NULL if the user is not using SSL + */ + virtual ssl_cert* GetCertificate(User* user) = 0; + + /** Get the key fingerprint from a user's certificate + * @param user The user whose key fingerprint to get, user may be remote + * @return The key fingerprint from the user's SSL certificate or an empty string + * if the user is not using SSL or did not provide a client certificate + */ + std::string GetFingerprint(User* user) { + ssl_cert* cert = GetCertificate(user); if (cert) return cert->GetFingerprint(); return ""; } }; -#endif +/** API implemented by m_sslinfo that allows modules to retrive the SSL certificate + * information of local and remote users. It can also be used to find out whether a + * user is using SSL or not. + */ +class UserCertificateAPI : public dynamic_reference<UserCertificateAPIBase> +{ + public: + UserCertificateAPI(Module* parent) + : dynamic_reference<UserCertificateAPIBase>(parent, "m_sslinfo_api") + { + } +}; diff --git a/include/numerics.h b/include/numerics.h index 4fce4cb6d..997a71d3a 100644 --- a/include/numerics.h +++ b/include/numerics.h @@ -18,8 +18,7 @@ */ -#ifndef NUMERICS_H -#define NUMERICS_H +#pragma once /* * This file is aimed providing a string that is easier to use than using the numeric @@ -157,5 +156,3 @@ enum Numerics ERR_CANTLOADMODULE = 974, // insp-specific RPL_LOADEDMODULE = 975 // insp-specific }; - -#endif diff --git a/include/protocol.h b/include/protocol.h index aabb5b022..6af0ed21c 100644 --- a/include/protocol.h +++ b/include/protocol.h @@ -18,8 +18,7 @@ */ -#ifndef PROTOCOL_H -#define PROTOCOL_H +#pragma once #include "hashcomp.h" @@ -27,23 +26,22 @@ class User; typedef std::vector<std::string> parameterlist; -class ProtoServer +class ProtocolInterface { public: - std::string servername; - std::string parentname; - std::string gecos; - unsigned int usercount; - unsigned int opercount; - unsigned int latencyms; -}; + class ServerInfo + { + public: + std::string servername; + std::string parentname; + std::string gecos; + unsigned int usercount; + unsigned int opercount; + unsigned int latencyms; + }; -typedef std::list<ProtoServer> ProtoServerList; + typedef std::vector<ServerInfo> ServerList; -class ProtocolInterface -{ - public: - ProtocolInterface() { } virtual ~ProtocolInterface() { } /** Send an ENCAP message to one or more linked servers. @@ -69,27 +67,13 @@ class ProtocolInterface virtual void SendTopic(Channel* channel, std::string &topic) { } /** Send mode changes for an object. - * @param target The channel name or user to send mode changes for. + * @param source The source of the mode change + * @param usertarget The target user, NULL if the target is a channel + * @param chantarget The target channel, NULL if the target is a user * @param modedata The mode changes to send. * @param translate A list of translation types */ - virtual void SendMode(const std::string &target, const parameterlist &modedata, const std::vector<TranslateType> &translate) { } - - /** Convenience function, string wrapper around the above. - */ - virtual void SendModeStr(const std::string &target, const std::string &modeline) - { - irc::spacesepstream x(modeline); - parameterlist n; - std::vector<TranslateType> types; - std::string v; - while (x.GetToken(v)) - { - n.push_back(v); - types.push_back(TR_TEXT); - } - SendMode(target, n, types); - } + virtual void SendMode(User* source, User* usertarget, Channel* chantarget, const parameterlist& modedata, const std::vector<TranslateType>& translate) { } /** Send a notice to users with a given snomask. * @param snomask The snomask required for the message to be sent. @@ -107,34 +91,39 @@ class ProtocolInterface * @param target The channel to message. * @param status The status character (e.g. %) required to recieve. * @param text The message to send. + * @param type The message type (MSG_PRIVMSG or MSG_NOTICE) */ - virtual void SendChannelPrivmsg(Channel* target, char status, const std::string &text) { } + virtual void SendMessage(Channel* target, char status, const std::string& text, MessageType type = MSG_PRIVMSG) { } - /** Send a notice to a channel. - * @param target The channel to message. - * @param status The status character (e.g. %) required to recieve. + /** Send a message to a user. + * @param target The user to message. * @param text The message to send. + * @param type The message type (MSG_PRIVMSG or MSG_NOTICE) */ - virtual void SendChannelNotice(Channel* target, char status, const std::string &text) { } + virtual void SendMessage(User* target, const std::string& text, MessageType type = MSG_PRIVMSG) { } - /** Send a message to a user. - * @param target The user to message. + /** Send a notice to a channel. + * @param target The channel to message. + * @param status The status character (e.g. %) required to recieve. * @param text The message to send. */ - virtual void SendUserPrivmsg(User* target, const std::string &text) { } + void SendChannelNotice(Channel* target, char status, const std::string &text) + { + SendMessage(target, status, text, MSG_NOTICE); + } /** Send a notice to a user. * @param target The user to message. * @param text The message to send. */ - virtual void SendUserNotice(User* target, const std::string &text) { } + void SendUserNotice(User* target, const std::string &text) + { + SendMessage(target, text, MSG_NOTICE); + } /** Fill a list of servers and information about them. * @param sl The list of servers to fill. * XXX: document me properly, this is shit. */ - virtual void GetServerList(ProtoServerList &sl) { } + virtual void GetServerList(ServerList& sl) { } }; - -#endif - diff --git a/include/snomasks.h b/include/snomasks.h index 85ad26f71..df4faab47 100644 --- a/include/snomasks.h +++ b/include/snomasks.h @@ -20,31 +20,52 @@ */ -#ifndef SNOMASKS_H -#define SNOMASKS_H +#pragma once +class SnomaskManager; class Snomask { - public: + /** Description of this snomask, e.g.: OPER, ANNOUNCEMENT, XLINE + */ std::string Description; + + /** Information about the last sent message, + * used for sending "last message repeated X times" messages + */ std::string LastMessage; - int Count; - bool LastBlocked; char LastLetter; + unsigned int Count; + /** Log and send a message to all opers who have the given snomask set + * @param letter The target users of this message + * @param desc The description of this snomask, will be prepended to the message + * @param msg The message to send + */ + static void Send(char letter, const std::string& desc, const std::string& msg); + + public: /** Create a new Snomask */ - Snomask() : Count(0), LastBlocked(false), LastLetter(0) - { - } + Snomask(); /** Sends a message to all opers with this snomask. + * @param message The message to send + * @param remote If true the message will go to the uppercase variant of this snomask */ - void SendMessage(const std::string &message, char letter); + void SendMessage(const std::string& message, char letter); /** Sends out the (last message repeated N times) message */ void Flush(); + + /** Returns the description of this snomask + * @param letter The letter of this snomask. If uppercase, the description of the remote + * variant of this snomask will be returned (i.e.: "REMOTE" will be prepended to the description). + * @return The description of this snomask + */ + std::string GetDescription(char letter) const; + + friend class SnomaskManager; }; /** Snomask manager handles routing of SNOMASK (usermode +s) messages to opers. @@ -53,9 +74,9 @@ class Snomask */ class CoreExport SnomaskManager { - public: Snomask masks[26]; + public: /** Create a new SnomaskManager */ SnomaskManager(); @@ -95,7 +116,6 @@ class CoreExport SnomaskManager */ void WriteGlobalSno(char letter, const char* text, ...) CUSTOM_PRINTF(3, 4); - /** Called once per 5 seconds from the mainloop, this flushes any cached * snotices. The way the caching works is as follows: * Calls to WriteToSnoMask write to a cache, if the call is the same as it was @@ -105,6 +125,12 @@ class CoreExport SnomaskManager * is not particularly significant, in order to keep notices going out. */ void FlushSnotices(); -}; -#endif + /** Check whether a given character is an enabled (initialized) snomask. + * Valid snomask chars are lower- or uppercase letters and have a description. + * Snomasks are initialized with EnableSnomask(). + * @param ch The character to check + * @return True if the given char is allowed to be set via +s. + */ + bool IsSnomaskUsable(char ch) const; +}; diff --git a/include/socket.h b/include/socket.h index 5f6705124..3abbeef32 100644 --- a/include/socket.h +++ b/include/socket.h @@ -22,8 +22,7 @@ */ -#ifndef INSPIRCD_SOCKET_H -#define INSPIRCD_SOCKET_H +#pragma once #ifndef _WIN32 @@ -110,9 +109,6 @@ namespace irc */ CoreExport bool MatchCIDR(const std::string &address, const std::string &cidr_mask, bool match_with_username); - /** Return the size of the structure for syscall passing */ - inline int sa_size(const irc::sockets::sockaddrs& sa) { return sa.sa_size(); } - /** Convert an address-port pair into a binary sockaddr * @param addr The IP address, IPv4 or IPv6 * @param port The port, 0 for unspecified @@ -165,6 +161,3 @@ class CoreExport ListenSocket : public EventHandler */ void AcceptInternal(); }; - -#endif - diff --git a/include/socketengine.h b/include/socketengine.h index 37b7d6373..d97c0ea9f 100644 --- a/include/socketengine.h +++ b/include/socketengine.h @@ -20,13 +20,12 @@ */ -#ifndef SOCKETENGINE_H -#define SOCKETENGINE_H +#pragma once #include <vector> #include <string> #include <map> -#include "inspircd_config.h" +#include "config.h" #include "socket.h" #include "base.h" @@ -128,7 +127,7 @@ enum EventMask /** Add a trial write. During the next DispatchEvents invocation, this * will call HandleEvent with EVENT_WRITE unless writes are known to be * blocking. - * + * * This could be used to group several writes together into a single * send() syscall, or to ensure that writes are blocking when attempting * to use FD_WANT_FAST_WRITE. @@ -137,7 +136,7 @@ enum EventMask /** Assert that writes are known to block. This cancels FD_ADD_TRIAL_WRITE. * Reset by SE before running EVENT_WRITE */ - FD_WRITE_WILL_BLOCK = 0x8000, + FD_WRITE_WILL_BLOCK = 0x8000, /** Mask for trial read/trial write */ FD_TRIAL_NOTE_MASK = 0x5000 @@ -418,7 +417,7 @@ public: * @param buf The buffer in which the data that is sent is stored. * @param len The size of the buffer. * @param flags A flag value that controls the sending of the data. - * @param to The remote IP address and port. + * @param to The remote IP address and port. * @param tolen The size of the to parameter. * @return This method should return exactly the same values as the system call it emulates. */ @@ -518,6 +517,3 @@ inline bool SocketEngine::IgnoreError() } SocketEngine* CreateSocketEngine(); - -#endif - diff --git a/include/testsuite.h b/include/testsuite.h index f91e508c9..7f0b2236a 100644 --- a/include/testsuite.h +++ b/include/testsuite.h @@ -16,12 +16,10 @@ */ -#ifndef TESTSUITE_H -#define TESTSUITE_H +#pragma once class TestSuite { - bool RealGenerateUIDTests(); public: TestSuite(); ~TestSuite(); @@ -32,5 +30,3 @@ class TestSuite bool DoSpaceSepStreamTests(); bool DoGenerateUIDTests(); }; - -#endif diff --git a/include/threadengine.h b/include/threadengine.h index 4bf5a48f3..39f150566 100644 --- a/include/threadengine.h +++ b/include/threadengine.h @@ -18,13 +18,12 @@ */ -#ifndef THREADENGINE_H -#define THREADENGINE_H +#pragma once #include <vector> #include <string> #include <map> -#include "inspircd_config.h" +#include "config.h" #include "base.h" class ThreadData; @@ -172,6 +171,3 @@ class CoreExport SocketThread : public Thread */ virtual void OnNotify() = 0; }; - -#endif - diff --git a/include/threadengines/threadengine_pthread.h b/include/threadengines/threadengine_pthread.h index 5168ed238..253e8d223 100644 --- a/include/threadengines/threadengine_pthread.h +++ b/include/threadengines/threadengine_pthread.h @@ -18,8 +18,7 @@ */ -#ifndef THREADENGINE_PTHREAD_H -#define THREADENGINE_PTHREAD_H +#pragma once #include <pthread.h> #include "typedefs.h" @@ -153,6 +152,3 @@ class ThreadSignalData public: ThreadSignalSocket* sock; }; - - -#endif diff --git a/include/threadengines/threadengine_win32.h b/include/threadengines/threadengine_win32.h index f068ac707..59848bd44 100644 --- a/include/threadengines/threadengine_win32.h +++ b/include/threadengines/threadengine_win32.h @@ -18,10 +18,9 @@ */ -#ifndef THREADENGINE_WIN32_H -#define THREADENGINE_WIN32_H +#pragma once -#include "inspircd_config.h" +#include "config.h" #include "base.h" class Thread; @@ -152,6 +151,3 @@ class ThreadSignalData connFD = -1; } }; - -#endif - diff --git a/include/timer.h b/include/timer.h index 9bb7128b8..2887e2b52 100644 --- a/include/timer.h +++ b/include/timer.h @@ -19,8 +19,9 @@ */ -#ifndef INSPIRCD_TIMER_H -#define INSPIRCD_TIMER_H +#pragma once + +class Module; /** Timer class for one-second resolution timers * Timer provides a facility which allows module @@ -29,61 +30,69 @@ * resolution. To use Timer, inherit a class from * Timer, then insert your inherited class into the * queue using Server::AddTimer(). The Tick() method of - * your object (which you should override) will be called + * your object (which you have to override) will be called * at the given time. */ class CoreExport Timer { - private: /** The triggering time */ time_t trigger; + /** Number of seconds between triggers */ - long secs; + unsigned int secs; + /** True if this is a repeating timer */ bool repeat; + public: /** Default constructor, initializes the triggering time * @param secs_from_now The number of seconds from now to trigger the timer * @param now The time now * @param repeating Repeat this timer every secs_from_now seconds if set to true */ - Timer(long secs_from_now, time_t now, bool repeating = false) + Timer(unsigned int secs_from_now, time_t now, bool repeating = false) { trigger = now + secs_from_now; secs = secs_from_now; repeat = repeating; } - /** Default destructor, does nothing. + /** Default destructor, removes the timer from the timer manager */ - virtual ~Timer() { } + virtual ~Timer(); /** Retrieve the current triggering time */ - virtual time_t GetTimer() + time_t GetTrigger() const { return trigger; } /** Sets the trigger timeout to a new value + * This does not update the bookkeeping in TimerManager, use SetInterval() + * to change the interval between ticks while keeping TimerManager updated */ - virtual void SetTimer(time_t t) + void SetTrigger(time_t nexttrigger) { - trigger = t; + trigger = nexttrigger; } + /** Sets the interval between two ticks. + */ + void SetInterval(time_t interval); + /** Called when the timer ticks. * You should override this method with some useful code to * handle the tick event. */ - virtual void Tick(time_t TIME) = 0; + virtual bool Tick(time_t TIME) = 0; /** Returns true if this timer is set to repeat */ - bool GetRepeat() + bool GetRepeat() const { return repeat; } @@ -91,7 +100,7 @@ class CoreExport Timer /** Returns the interval (number of seconds between ticks) * of this timer object. */ - long GetSecs() + unsigned int GetInterval() const { return secs; } @@ -99,12 +108,6 @@ class CoreExport Timer /** Cancels the repeat state of a repeating timer. * If you call this method, then the next time your * timer ticks, it will be removed immediately after. - * You should use this method call to remove a recurring - * timer if you wish to do so within the timer's Tick - * event, as calling TimerManager::DelTimer() from within - * the Timer::Tick() method is dangerous and may - * cause a segmentation fault. Calling CancelRepeat() - * is safe in this case. */ void CancelRepeat() { @@ -112,6 +115,7 @@ class CoreExport Timer } }; +typedef std::multimap<time_t, Timer*> TimerMap; /** This class manages sets of Timers, and triggers them at their defined times. * This will ensure timers are not missed, as well as removing timers that have @@ -119,17 +123,11 @@ class CoreExport Timer */ class CoreExport TimerManager { - protected: /** A list of all pending timers */ - std::vector<Timer *> Timers; + TimerMap Timers; public: - /** Constructor - */ - TimerManager(); - ~TimerManager(); - /** Tick all pending Timers * @param TIME the current system time */ @@ -140,15 +138,8 @@ class CoreExport TimerManager */ void AddTimer(Timer *T); - /** Delete an Timer - * @param T an Timer derived class to delete + /** Remove a Timer + * @param T an Timer derived class to remove */ void DelTimer(Timer* T); - - /** Compares two timers - */ - static bool TimerComparison( Timer *one, Timer*two); }; - -#endif - diff --git a/include/typedefs.h b/include/typedefs.h index 06f704120..c38f89d4d 100644 --- a/include/typedefs.h +++ b/include/typedefs.h @@ -19,18 +19,13 @@ */ -#ifndef TYPEDEFS_H -#define TYPEDEFS_H +#pragma once class BanCacheManager; -class BanItem; class BufferedSocket; class Channel; class Command; -class ConfigReader; class ConfigTag; -class DNSHeader; -class DNSRequest; class Extensible; class FakeUser; class InspIRCd; @@ -45,24 +40,17 @@ class ServerConfig; class ServerLimits; class Thread; class User; -class UserResolver; class XLine; class XLineManager; class XLineFactory; struct ConnectClass; struct ModResult; -struct ResourceRecord; #include "hashcomp.h" #include "base.h" -#ifdef HASHMAP_DEPRECATED - typedef nspace::hash_map<std::string, User*, nspace::insensitive, irc::StrHashComp> user_hash; - typedef nspace::hash_map<std::string, Channel*, nspace::insensitive, irc::StrHashComp> chan_hash; -#else - typedef nspace::hash_map<std::string, User*, nspace::hash<std::string>, irc::StrHashComp> user_hash; - typedef nspace::hash_map<std::string, Channel*, nspace::hash<std::string>, irc::StrHashComp> chan_hash; -#endif +typedef TR1NS::unordered_map<std::string, User*, irc::insensitive, irc::StrHashComp> user_hash; +typedef TR1NS::unordered_map<std::string, Channel*, irc::insensitive, irc::StrHashComp> chan_hash; /** A list holding local users, this is the type of UserManager::local_users */ @@ -87,10 +75,6 @@ typedef std::set<Channel*> UserChanList; */ typedef UserChanList::iterator UCListIter; -/** Holds a complete ban list - */ -typedef std::vector<BanItem> BanList; - /** A list of custom modes parameters on a channel */ typedef std::map<char,std::string> CustomModeList; @@ -120,7 +104,7 @@ typedef std::map<std::string, file_cache> ConfigFileCache; /** A hash of commands used by the core */ -typedef nspace::hash_map<std::string,Command*> Commandtable; +typedef TR1NS::unordered_map<std::string, Command*> Commandtable; /** Membership list of a channel */ typedef std::map<User*, Membership*> UserMembList; @@ -159,7 +143,3 @@ typedef XLineContainer::iterator ContainerIter; /** An interator in an XLineLookup */ typedef XLineLookup::iterator LookupIter; - - -#endif - diff --git a/include/uid.h b/include/uid.h index 17061bdee..772c8a716 100644 --- a/include/uid.h +++ b/include/uid.h @@ -16,12 +16,44 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#pragma once -/** - * This is the maximum length of a UUID (unique user identifier). - * This length is set in compliance with TS6 protocol, and really should not be changed. Ever. - * It allows for a lot of clients as-is. -- w00t. - */ -#define UUID_LENGTH 10 +class TestSuite; + +class CoreExport UIDGenerator +{ + friend class TestSuite; + + /** Holds the current UID. Used to generate the next one. + */ + std::string current_uid; + + /** Increments the current UID by one. + */ + void IncrementUID(unsigned int pos); + + public: + /** + * This is the maximum length of a UUID (unique user identifier). + * This length is set in compliance with TS6 protocol, and really should not be changed. Ever. + * It allows for a lot of clients as-is. -- w00t. + */ + static const unsigned int UUID_LENGTH = 9; + + /** Initializes this UID generator with the given SID + * @param sid SID that conforms to InspIRCd::IsSID() + */ + void init(const std::string& sid); + /** Returns the next available UID for this server. + */ + std::string GetUID(); + /** Generates a pseudorandom SID based on a servername and a description + * Guaranteed to return the same if invoked with the same parameters + * @param servername The server name to use as seed + * @param serverdesc The server description to use as seed + * @return A valid SID + */ + static std::string GenerateSID(const std::string& servername, const std::string& serverdesc); +}; diff --git a/include/usermanager.h b/include/usermanager.h index ac8ae1cb3..c6745ace6 100644 --- a/include/usermanager.h +++ b/include/usermanager.h @@ -17,8 +17,7 @@ */ -#ifndef USERMANAGER_H -#define USERMANAGER_H +#pragma once #include <list> @@ -31,19 +30,16 @@ class CoreExport UserManager /** Map of local ip addresses for clone counting */ clonemap local_clones; + public: + /** Constructor, initializes variables and allocates the hashmaps + */ UserManager(); - ~UserManager() - { - for (user_hash::iterator i = clientlist->begin();i != clientlist->end();i++) - { - delete i->second; - } - clientlist->clear(); - delete clientlist; - delete uuidlist; - } + /** Destructor, destroys all users in clientlist and then deallocates + * the hashmaps + */ + ~UserManager(); /** Client list, a hash_map containing all clients, local and remote */ @@ -76,6 +72,22 @@ class CoreExport UserManager */ clonemap global_clones; + /** + * Reset the already_sent IDs so we don't wrap it around and drop a message + * Also removes all expired invites + */ + void GarbageCollect(); + + /** Perform background user events such as PING checks + */ + void DoBackgroundUserStuff(); + + /** Returns true when all modules have done pre-registration checks on a user + * @param user The user to verify + * @return True if all modules have finished checking this user + */ + bool AllModulesReportReady(LocalUser* user); + /** Add a client to the system. * This will create a new User, insert it into the user_hash, * initialize it as not yet registered, and add it to the socket engine. @@ -124,49 +136,34 @@ class CoreExport UserManager */ unsigned long LocalCloneCount(User *user); - /** Return a count of users, unknown and known connections - * @return The number of users - */ - unsigned int UserCount(); - - /** Return a count of fully registered connections only - * @return The number of registered users + /** Return a count of all global users, unknown and known connections + * @return The number of users on the network, including local unregistered users */ - unsigned int RegisteredUserCount(); + unsigned int UserCount() const { return this->clientlist->size(); } - /** Return a count of opered (umode +o) users only - * @return The number of opers + /** Return a count of fully registered connections on the network + * @return The number of registered users on the network */ - unsigned int OperCount(); + unsigned int RegisteredUserCount() { return this->clientlist->size() - this->UnregisteredUserCount(); } - /** Return a count of unregistered (before NICK/USER) users only - * @return The number of unregistered (unknown) connections + /** Return a count of opered (umode +o) users on the network + * @return The number of opers on the network */ - unsigned int UnregisteredUserCount(); + unsigned int OperCount() const { return this->all_opers.size(); } - /** Return a count of local users on this server only - * @return The number of local users + /** Return a count of local unregistered (before NICK/USER) users + * @return The number of local unregistered (unknown) connections */ - unsigned int LocalUserCount(); - - + unsigned int UnregisteredUserCount() const { return this->unregistered_count; } - - /** Number of users with a certain mode set on them + /** Return a count of local registered users + * @return The number of registered local users */ - int ModeCount(const char mode); + unsigned int LocalUserCount() const { return (this->local_count - this->UnregisteredUserCount()); } /** Send a server notice to all local users * @param text The text format string to send * @param ... The format arguments */ void ServerNoticeAll(const char* text, ...) CUSTOM_PRINTF(2, 3); - - /** Send a server message (PRIVMSG) to all local users - * @param text The text format string to send - * @param ... The format arguments - */ - void ServerPrivmsgAll(const char* text, ...) CUSTOM_PRINTF(2, 3); }; - -#endif diff --git a/include/users.h b/include/users.h index 88abfbcd1..aa11a2b82 100644 --- a/include/users.h +++ b/include/users.h @@ -22,12 +22,10 @@ */ -#ifndef USERS_H -#define USERS_H +#pragma once #include "socket.h" #include "inspsocket.h" -#include "dns.h" #include "mode.h" #include "membership.h" @@ -42,19 +40,6 @@ enum ClassTypes { CC_NAMED = 2 }; -/** RFC1459 channel modes - */ -enum UserModes { - /** +s: Server notice mask */ - UM_SNOMASK = 's' - 65, - /** +w: WALLOPS */ - UM_WALLOPS = 'w' - 65, - /** +i: Invisible */ - UM_INVISIBLE = 'i' - 65, - /** +o: Operator */ - UM_OPERATOR = 'o' - 65 -}; - /** Registration state of a user, e.g. * have they sent USER, NICK, PASS yet? */ @@ -146,6 +131,10 @@ struct CoreExport ConnectClass : public refcountbase */ unsigned long limit; + /** If set to true, no user DNS lookups are to be performed + */ + bool resolvehostnames; + /** Create a new connect class with no settings. */ ConnectClass(ConfigTag* tag, char type, const std::string& mask); @@ -250,6 +239,14 @@ class CoreExport User : public Extensible */ std::string cachedip; + /** The user's mode list. + * Much love to the STL for giving us an easy to use bitset, saving us RAM. + * if (modes[modeletter-65]) is set, then the mode is + * set, for example, to work out if mode +s is set, we check the field + * User::modes['s'-65] != 0. + */ + std::bitset<64> modes; + public: /** Hostname of connection. @@ -267,10 +264,6 @@ class CoreExport User : public Extensible */ time_t signon; - /** Time that the connection last sent a message, used to calculate idle time - */ - time_t idle_lastmsg; - /** Client address that the user is connected from. * Do not modify this value directly, use SetClientIP() to change it. * Port is not valid for remote users. @@ -302,18 +295,6 @@ class CoreExport User : public Extensible */ std::string fullname; - /** The user's mode list. - * NOT a null terminated string. - * Also NOT an array. - * Much love to the STL for giving us an easy to use bitset, saving us RAM. - * if (modes[modeletter-65]) is set, then the mode is - * set, for example, to work out if mode +s is set, we check the field - * User::modes['s'-65] != 0. - * The following RFC characters o, w, s, i have constants defined via an - * enum, such as UM_SERVERNOTICE and UM_OPETATOR. - */ - std::bitset<64> modes; - /** What snomasks are set on this user. * This functions the same as the above modes. */ @@ -333,7 +314,7 @@ class CoreExport User : public Extensible std::string awaymsg; /** Time the user last went away. - * This is ONLY RELIABLE if user IS_AWAY()! + * This is ONLY RELIABLE if user IsAway()! */ time_t awaytime; @@ -347,12 +328,6 @@ class CoreExport User : public Extensible */ unsigned int registered:3; - /** True when DNS lookups are completed. - * The UserResolver classes res_forward and res_reverse will - * set this value once they complete. - */ - unsigned int dns_done:1; - /** Whether or not to send an snotice about this user's quitting */ unsigned int quietquit:1; @@ -364,27 +339,13 @@ class CoreExport User : public Extensible */ unsigned int quitting:1; - /** Recursion fix: user is out of SendQ and will be quit as soon as possible. - * This can't be handled normally because QuitUser itself calls Write on other - * users, which could trigger their SendQ to overrun. - */ - unsigned int quitting_sendq:1; - - /** This is true if the user matched an exception (E:Line). It is used to save time on ban checks. - */ - unsigned int exempt:1; - - /** has the user responded to their previous ping? - */ - unsigned int lastping:1; - /** What type of user is this? */ const unsigned int usertype:2; /** Get client IP string from sockaddr, using static internal buffer * @return The IP string */ - const char* GetIPString(); + const std::string& GetIPString(); /** Get CIDR mask, using default range, for this user */ @@ -402,12 +363,6 @@ class CoreExport User : public Extensible */ User(const std::string &uid, const std::string& srv, int objtype); - /** Check if the user matches a G or K line, and disconnect them if they do. - * @param doZline True if ZLines should be checked (if IP has changed since initial connect) - * Returns true if the user matched a ban, false else. - */ - bool CheckLines(bool doZline = false); - /** Returns the full displayed host of the user * This member function returns the hostname of the user as seen by other users * on the server, in nick!ident\@host form. @@ -428,18 +383,17 @@ class CoreExport User : public Extensible */ void InvalidateCache(); - /** Create a displayable mode string for this users snomasks - * @return The notice mask character sequence + /** Returns whether this user is currently away or not. If true, + * further information can be found in User::awaymsg and User::awaytime + * @return True if the user is away, false otherwise */ - const char* FormatNoticeMasks(); + bool IsAway() const { return (!awaymsg.empty()); } - /** Process a snomask modifier string, e.g. +abc-de - * @param sm A sequence of notice mask characters - * @return The cleaned mode sequence which can be output, - * e.g. in the above example if masks c and e are not - * valid, this function will return +ab-d + /** Returns whether this user is an oper or not. If true, + * oper information can be obtained from User::oper + * @return True if the user is an oper, false otherwise */ - std::string ProcessNoticeMasks(const char *sm); + bool IsOper() const { return oper; } /** Returns true if a notice mask is set * @param sm A notice mask character to check @@ -447,12 +401,6 @@ class CoreExport User : public Extensible */ bool IsNoticeMaskSet(unsigned char sm); - /** Changed a specific notice mask value - * @param sm The server notice mask to change - * @param value An on/off value for this mask - */ - void SetNoticeMask(unsigned char sm, bool value); - /** Create a displayable mode string for this users umodes * @param showparameters The mode string */ @@ -463,12 +411,16 @@ class CoreExport User : public Extensible * @return True if the mode is set */ bool IsModeSet(unsigned char m); + bool IsModeSet(ModeHandler* mh); + bool IsModeSet(ModeHandler& mh) { return IsModeSet(&mh); } + bool IsModeSet(UserModeReference& moderef); /** Set a specific usermode to on or off * @param m The user mode * @param value On or off setting of the mode */ - void SetMode(unsigned char m, bool value); + void SetMode(ModeHandler* mh, bool value); + void SetMode(ModeHandler& mh, bool value) { SetMode(&mh, value); } /** Returns true or false for if a user can execute a privilaged oper command. * This is done by looking up their oper type from User::oper, then referencing @@ -497,12 +449,6 @@ class CoreExport User : public Extensible */ virtual bool HasModePermission(unsigned char mode, ModeType type); - /** Creates a wildcard host. - * Takes a buffer to use and fills the given buffer with the host in the format *!*\@hostname - * @return The wildcarded hostname in *!*\@host form - */ - char* MakeWildHost(); - /** Creates a usermask with real host. * Takes a buffer to use and fills the given buffer with the hostmask in the format user\@host * @return the usermask in the format user\@host @@ -515,10 +461,6 @@ class CoreExport User : public Extensible */ const std::string& MakeHostIP(); - /** Add the user to WHOWAS system - */ - void AddToWhoWas(); - /** Oper up the user using the given opertype. * This will also give the +o usermode. */ @@ -531,7 +473,7 @@ class CoreExport User : public Extensible * @param newnick The nickname to change to * @return True if the nickchange was successful. */ - inline bool ForceNickChange(const char* newnick) { return ChangeNick(newnick, true); } + bool ForceNickChange(const std::string& newnick) { return ChangeNick(newnick, true); } /** Oper down. * This will clear the +o usermode and unset the user's oper type @@ -563,6 +505,11 @@ class CoreExport User : public Extensible */ void WriteServ(const char* text, ...) CUSTOM_PRINTF(2, 3); + /** Sends a server notice to this user. + * @param text The contents of the message to send. + */ + void WriteNotice(const std::string& text); + void WriteNumeric(unsigned int numeric, const char* text, ...) CUSTOM_PRINTF(3, 4); void WriteNumeric(unsigned int numeric, const std::string &text); @@ -619,10 +566,10 @@ class CoreExport User : public Extensible void WriteCommonQuit(const std::string &normal_text, const std::string &oper_text); /** Dump text to a user target, splitting it appropriately to fit - * @param LinePrefix text to prefix each complete line with - * @param TextStream the text to send to the user + * @param linePrefix text to prefix each complete line with + * @param textStream the text to send to the user */ - void SendText(const std::string &LinePrefix, std::stringstream &TextStream); + void SendText(const std::string& linePrefix, std::stringstream& textStream); /** Write to the user, routing the line if the user is remote. */ @@ -638,32 +585,24 @@ class CoreExport User : public Extensible */ bool SharesChannelWith(User *other); - /** Send fake quit/join messages for host or ident cycle. - * Run this after the item in question has changed. - * You should not need to use this function, call ChangeDisplayedHost instead - * - * @param quitline The entire QUIT line, including the source using the old value - */ - void DoHostCycle(const std::string &quitline); - /** Change the displayed host of a user. * ALWAYS use this function, rather than writing User::dhost directly, * as this triggers module events allowing the change to be syncronized to - * remote servers. This will also emulate a QUIT and rejoin (where configured) - * before setting their host field. + * remote servers. * @param host The new hostname to set * @return True if the change succeeded, false if it didn't + * (a module vetoed the change). */ - bool ChangeDisplayedHost(const char* host); + bool ChangeDisplayedHost(const std::string& host); /** Change the ident (username) of a user. * ALWAYS use this function, rather than writing User::ident directly, - * as this correctly causes the user to seem to quit (where configured) - * before setting their ident field. + * as this triggers module events allowing the change to be syncronized to + * remote servers. * @param newident The new ident to set * @return True if the change succeeded, false if it didn't */ - bool ChangeIdent(const char* newident); + bool ChangeIdent(const std::string& newident); /** Change a users realname field. * ALWAYS use this function, rather than writing User::fullname directly, @@ -672,7 +611,7 @@ class CoreExport User : public Extensible * @param gecos The user's new realname * @return True if the change succeeded, false if otherwise */ - bool ChangeName(const char* gecos); + bool ChangeName(const std::string& gecos); /** Change a user's nick * @param newnick The new nick @@ -691,30 +630,11 @@ class CoreExport User : public Extensible */ void SendAll(const char* command, const char* text, ...) CUSTOM_PRINTF(3, 4); - /** Compile a channel list for this user. Used internally by WHOIS - * @param source The user to prepare the channel list for - * @param spy Whether to return the spy channel list rather than the normal one - * @return This user's channel list - */ - std::string ChannelList(User* source, bool spy); - - /** Split the channel list in cl which came from dest, and spool it to this user - * Used internally by WHOIS - * @param dest The user the original channel list came from - * @param cl The channel list as a string obtained from User::ChannelList() - */ - void SplitChanList(User* dest, const std::string &cl); - /** Remove this user from all channels they are on, and delete any that are now empty. * This is used by QUIT, and will not send part messages! */ void PurgeEmptyChannels(); - /** Get the connect class which this user belongs to. NULL for remote users. - * @return A pointer to this user's connect class. - */ - virtual ConnectClass* GetClass(); - /** Default destructor */ virtual ~User(); @@ -777,11 +697,14 @@ class CoreExport LocalUser : public User, public InviteBase */ reference<ConnectClass> MyClass; - ConnectClass* GetClass(); + /** Get the connect class which this user belongs to. + * @return A pointer to this user's connect class. + */ + ConnectClass* GetClass() const { return MyClass; } /** Call this method to find the matching \<connect> for a user, and to check them against it. */ - void CheckClass(); + void CheckClass(bool clone_count = true); /** Server address and port that this user is connected to. */ @@ -792,10 +715,28 @@ class CoreExport LocalUser : public User, public InviteBase */ int GetServerPort(); + /** Recursion fix: user is out of SendQ and will be quit as soon as possible. + * This can't be handled normally because QuitUser itself calls Write on other + * users, which could trigger their SendQ to overrun. + */ + unsigned int quitting_sendq:1; + + /** has the user responded to their previous ping? + */ + unsigned int lastping:1; + + /** This is true if the user matched an exception (E:Line). It is used to save time on ban checks. + */ + unsigned int exempt:1; + /** Used by PING checking code */ time_t nping; + /** Time that the connection last sent a message, used to calculate idle time + */ + time_t idle_lastmsg; + /** This value contains how far into the penalty threshold the user is. * This is used either to enable fake lag or for excess flood quits */ @@ -804,15 +745,11 @@ class CoreExport LocalUser : public User, public InviteBase static already_sent_t already_sent_id; already_sent_t already_sent; - /** Stored reverse lookup from res_forward. Should not be used after resolution. - */ - std::string stored_host; - - /** Starts a DNS lookup of the user's IP. - * This will cause two UserResolver classes to be instantiated. - * When complete, these objects set User::dns_done to true. + /** Check if the user matches a G or K line, and disconnect them if they do. + * @param doZline True if ZLines should be checked (if IP has changed since initial connect) + * Returns true if the user matched a ban, false else. */ - void StartDNSLookup(); + bool CheckLines(bool doZline = false); /** Use this method to fully connect a user. * This will send the message of the day, check G/K/E lines, etc. @@ -839,23 +776,18 @@ class CoreExport LocalUser : public User, public InviteBase InviteList& GetInviteList(); /** Returns true if a user is invited to a channel. - * @param channel A channel name to look up + * @param chan A channel to look up * @return True if the user is invited to the given channel */ - bool IsInvited(const irc::string &channel); - - /** Adds a channel to a users invite list (invites them to a channel) - * @param channel A channel name to add - * @param timeout When the invite should expire (0 == never) - */ - void InviteTo(const irc::string &channel, time_t timeout); + bool IsInvited(Channel* chan) { return (Invitation::Find(chan, this) != NULL); } /** Removes a channel from a users invite list. * This member function is called on successfully joining an invite only channel * to which the user has previously been invited, to clear the invitation. - * @param channel The channel to remove the invite to + * @param chan The channel to remove the invite to + * @return True if the user was invited to the channel and the invite was erased, false if the user wasn't invited */ - void RemoveInvite(const irc::string &channel); + bool RemoveInvite(Channel* chan); void RemoveExpiredInvites(); @@ -926,42 +858,22 @@ inline FakeUser* IS_SERVER(User* u) { return u->usertype == USERTYPE_SERVER ? static_cast<FakeUser*>(u) : NULL; } -/** Is an oper */ -#define IS_OPER(x) (x->oper) -/** Is away */ -#define IS_AWAY(x) (!x->awaymsg.empty()) -/** Derived from Resolver, and performs user forward/reverse lookups. - */ -class CoreExport UserResolver : public Resolver +inline bool User::IsModeSet(ModeHandler* mh) { - private: - /** UUID we are looking up */ - std::string uuid; - /** True if the lookup is forward, false if is a reverse lookup - */ - bool fwd; - public: - /** Create a resolver. - * @param user The user to begin lookup on - * @param to_resolve The IP or host to resolve - * @param qt The query type - * @param cache Modified by the constructor if the result was cached - */ - UserResolver(LocalUser* user, std::string to_resolve, QueryType qt, bool &cache); - - /** Called on successful lookup - * @param result Result string - * @param ttl Time to live for result - * @param cached True if the result was found in the cache - */ - void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached); + char m = mh->GetModeChar(); + return (modes[m-65]); +} - /** Called on failed lookup - * @param e Error code - * @param errormessage Error message string - */ - void OnError(ResolverError e, const std::string &errormessage); -}; +inline bool User::IsModeSet(UserModeReference& moderef) +{ + if (!moderef) + return false; + return IsModeSet(*moderef); +} -#endif +inline void User::SetMode(ModeHandler* mh, bool value) +{ + char m = mh->GetModeChar(); + modes[m-65] = value; +} diff --git a/include/xline.h b/include/xline.h index 2a49d8b80..5403a0933 100644 --- a/include/xline.h +++ b/include/xline.h @@ -20,8 +20,7 @@ */ -#ifndef XLINE_H -#define XLINE_H +#pragma once /** XLine is the base class for ban lines such as G lines and K lines. * Modules may derive from this, and their xlines will automatically be @@ -101,16 +100,16 @@ class CoreExport XLine : public classbase * line. Usually a line in the form 'expiring Xline blah, set by...' * see the DisplayExpiry methods of GLine, ELine etc. */ - virtual void DisplayExpiry() = 0; + virtual void DisplayExpiry(); /** Returns the displayable form of the pattern for this xline, * e.g. '*\@foo' or '*baz*'. This must always return the full pattern * in a form which can be used to construct an entire derived xline, * even if it is stored differently internally (e.g. GLine stores the * ident and host parts seperately but will still return ident\@host - * for its Displayable() method) + * for its Displayable() method). */ - virtual const char* Displayable() = 0; + virtual const std::string& Displayable() = 0; /** Called when the xline has just been added. */ @@ -177,9 +176,7 @@ class CoreExport KLine : public XLine virtual void Apply(User* u); - virtual void DisplayExpiry(); - - virtual const char* Displayable(); + virtual const std::string& Displayable(); virtual bool IsBurstable(); @@ -225,9 +222,7 @@ class CoreExport GLine : public XLine virtual void Apply(User* u); - virtual void DisplayExpiry(); - - virtual const char* Displayable(); + virtual const std::string& Displayable(); /** Ident mask (ident part only) */ @@ -269,11 +264,9 @@ class CoreExport ELine : public XLine virtual void Unset(); - virtual void DisplayExpiry(); - virtual void OnAdd(); - virtual const char* Displayable(); + virtual const std::string& Displayable(); /** Ident mask (ident part only) */ @@ -314,9 +307,7 @@ class CoreExport ZLine : public XLine virtual void Apply(User* u); - virtual void DisplayExpiry(); - - virtual const char* Displayable(); + virtual const std::string& Displayable(); /** IP mask (no ident part) */ @@ -351,9 +342,7 @@ class CoreExport QLine : public XLine virtual void Apply(User* u); - virtual void DisplayExpiry(); - - virtual const char* Displayable(); + virtual const std::string& Displayable(); /** Nickname mask */ @@ -537,4 +526,3 @@ class CoreExport XLineManager void InvokeStats(const std::string &type, int numeric, User* user, string_list &results); }; -#endif diff --git a/make/calcdep.pl b/make/calcdep.pl index 4a759a24a..26be367f5 100755 --- a/make/calcdep.pl +++ b/make/calcdep.pl @@ -78,7 +78,7 @@ END for my $file (<*.cpp>, <modes/*.cpp>, <socketengines/*.cpp>, "threadengines/threadengine_pthread.cpp") { my $out = find_output $file; dep_cpp $file, $out, 'gen-o'; - next if $file =~ m#^socketengines/# && $file ne "socketengines/$ENV{SOCKETENGINE}.cpp"; + next if $file =~ m#^socketengines/# && $file ne "socketengines/socketengine_$ENV{SOCKETENGINE}.cpp"; push @core_deps, $out; } @@ -148,7 +148,7 @@ END mkdir "$ENV{BUILDPATH}/obj/$1"; } dep_cpp $file, $out, 'gen-o'; - next if $file =~ m#^socketengines/# && $file ne "socketengines/$ENV{SOCKETENGINE}.cpp"; + next if $file =~ m#^socketengines/# && $file ne "socketengines/socketengine_$ENV{SOCKETENGINE}.cpp"; push @deps, $out; push @srcs, $file; } @@ -199,7 +199,7 @@ sub gendep($) { while (<$in>) { if (/^\s*#\s*include\s*"([^"]+)"/) { my $inc = $1; - next if $inc eq 'inspircd_version.h' && $f eq '../include/inspircd.h'; + next if $inc eq 'config.h' && $f eq '../include/inspircd.h'; my $found = 0; for my $loc ("$basedir/$inc", "../include/$inc") { next unless -e $loc; diff --git a/make/configure.pm b/make/configure.pm index 606483e98..286424080 100644 --- a/make/configure.pm +++ b/make/configure.pm @@ -21,291 +21,246 @@ # -package make::configure; +BEGIN { + require 5.8.0; +} -require 5.8.0; +package make::configure; use strict; use warnings FATAL => qw(all); +use Cwd; use Exporter 'import'; -use POSIX; + use make::utilities; -our @EXPORT = qw(promptnumeric dumphash is_dir getmodules getrevision getcompilerflags getlinkerflags getdependencies nopedantic resolve_directory yesno showhelp promptstring_s module_installed); - -my $no_git = 0; - -sub yesno { - my ($flag,$prompt) = @_; - print "$prompt [\e[1;32m$main::config{$flag}\e[0m] -> "; - chomp(my $tmp = <STDIN>); - if ($tmp eq "") { $tmp = $main::config{$flag} } - if (($tmp eq "") || ($tmp =~ /^y/i)) - { - $main::config{$flag} = "y"; - } - else - { - $main::config{$flag} = "n"; + +our @EXPORT = qw(cmd_clean cmd_help cmd_update + read_configure_cache write_configure_cache + get_compiler_info find_compiler + run_test test_file test_header + get_property get_revision + dump_hash); + +my $revision; + +sub __get_socketengines() { + my @socketengines; + foreach (<src/socketengines/socketengine_*.cpp>) { + s/src\/socketengines\/socketengine_(\w+)\.cpp/$1/; + push @socketengines, $1; } - return; + return @socketengines; } -sub resolve_directory -{ - my $ret = $_[0]; - eval - { - use File::Spec; - $ret = File::Spec->rel2abs($_[0]); - }; - return $ret; +sub cmd_clean { + unlink '.config.cache'; } -sub getrevision { - if ($no_git) - { - return "0"; - } - my $data = `git describe --tags 2>/dev/null`; - if ($data eq "") - { - $no_git = 1; - return '0'; +sub cmd_help { + my $PWD = getcwd(); + my $SELIST = join ', ', __get_socketengines(); + print <<EOH; +Usage: $0 [options] + +When no options are specified, configure runs in interactive mode and you must +specify any required values manually. If one or more options are specified, +non-interactive configuration is started and any omitted values are defaulted. + +PATH OPTIONS + + --system Automatically set up the installation paths + for system-wide installation. + --prefix=[dir] The root install directory. If this is set then + all subdirectories will be adjusted accordingly. + [$PWD/run] + --binary-dir=[dir] The location where the main server binary is + stored. + [$PWD/run/bin] + --config-dir=[dir] The location where the configuration files and + SSL certificates are stored. + [$PWD/run/conf] + --data-dir=[dir] The location where the data files, such as the + pid file, are stored. + [$PWD/run/data] + --log-dir=[dir] The location where the log files are stored. + [$PWD/run/logs] + --module-dir=[dir] The location where the loadable modules are + stored. + [$PWD/run/modules] + --build-dir=[dir] The location to store files in while building. + + +EXTRA MODULE OPTIONS + + --enable-extras=[extras] Enables a comma separated list of extra modules. + --disable-extras=[extras] Disables a comma separated list of extra modules. + --list-extras Shows the availability status of all extra + modules. + +MISC OPTIONS + + --clean Remove the configuration cache file and start + the interactive configuration wizard. + --disable-interactive Disables the interactive configuration wizard. + --help Show this message and exit. + --uid=[name] Sets the user to run InspIRCd as. + --socketengine=[name] Sets the socket engine to be used. Possible + values are $SELIST. + --update Updates the build environment. + + +FLAGS + + CXX=[name] Sets the C++ compiler to use when building the + server. If not specified then the build system + will search for c++, g++, clang++ or icpc. + +If you have any problems with configuring InspIRCd then visit our IRC channel +at irc.ChatSpike.net #InspIRCd. + +EOH + exit 0; +} + +sub cmd_update { + unless (-f '.config.cache') { + print "You have not run $0 before. Please do this before trying to update the build files.\n"; + exit 1; } - chomp $data; # remove \n - return $data; + print "Updating...\n"; + %main::config = read_configure_cache(); + %main::cxx = get_compiler_info($main::config{CXX}); + $main::topdir = getcwd(); + main::writefiles(); + print "Update complete!\n"; + exit 0; } -sub getcompilerflags { - my ($file) = @_; - open(FLAGS, $file) or return ""; - while (<FLAGS>) { - if ($_ =~ /^\/\* \$CompileFlags: (.+) \*\/$/) { - my $x = translate_functions($1, $file); - next if ($x eq ""); - close(FLAGS); - return $x; - } +sub read_configure_cache { + my %cfg = (); + open(CACHE, '.config.cache') or return %cfg; + while (my $line = <CACHE>) { + next if $line =~ /^\s*($|\#)/; + my ($key, $value) = ($line =~ /^(\S+)="(.*)"$/); + $cfg{$key} = $value; } - close(FLAGS); - return ""; + close(CACHE); + return %cfg; } -sub getlinkerflags { - my ($file) = @_; - open(FLAGS, $file) or return ""; - while (<FLAGS>) { - if ($_ =~ /^\/\* \$LinkerFlags: (.+) \*\/$/) { - my $x = translate_functions($1, $file); - next if ($x eq ""); - close(FLAGS); - return $x; - } +sub write_configure_cache(%) { + my %cfg = @_; + open(CACHE, ">.config.cache") or return 0; + while (my ($key, $value) = each %cfg) { + $value = "" unless defined $value; + print CACHE "$key=\"$value\"\n"; } - close(FLAGS); - return ""; + close(CACHE); + return 1; } -sub getdependencies { - my ($file) = @_; - open(FLAGS, $file) or return ""; - while (<FLAGS>) { - if ($_ =~ /^\/\* \$ModDep: (.+) \*\/$/) { - my $x = translate_functions($1, $file); - next if ($x eq ""); - close(FLAGS); - return $x; - } +sub get_compiler_info($) { + my $binary = shift; + my $version = `$binary -v 2>&1`; + if ($version =~ /(?:clang|llvm)\sversion\s(\d+\.\d+)/i) { + return ( + NAME => 'Clang', + VERSION => $1, + UNSUPPORTED => $1 lt '3.0', + REASON => 'Clang 2.9 and older do not have adequate C++ support.' + ); + } elsif ($version =~ /gcc\sversion\s(\d+\.\d+)/i) { + return ( + NAME => 'GCC', + VERSION => $1, + UNSUPPORTED => $1 lt '4.1', + REASON => 'GCC 4.0 and older do not have adequate C++ support.' + ); + } elsif ($version =~ /(?:icc|icpc)\sversion\s(\d+\.\d+).\d+\s\(gcc\sversion\s(\d+\.\d+).\d+/i) { + return ( + NAME => 'ICC', + VERSION => $1, + UNSUPPORTED => $2 lt '4.1', + REASON => "ICC $1 (GCC $2 compatibility mode) does not have adequate C++ support." + ); } - close(FLAGS); - return ""; + return ( + NAME => $binary, + VERSION => '0.0' + ); } -sub nopedantic { - my ($file) = @_; - open(FLAGS, $file) or return ""; - while (<FLAGS>) { - if ($_ =~ /^\/\* \$NoPedantic \*\/$/) { - my $x = translate_functions($_, $file); - next if ($x eq ""); - close(FLAGS); - return 1; +sub find_compiler { + foreach my $compiler ('c++', 'g++', 'clang++', 'icpc') { + return $compiler unless system "$compiler -v > /dev/null 2>&1"; + if ($^O eq 'Darwin') { + return $compiler unless system "xcrun $compiler -v > /dev/null 2>&1"; } } - close(FLAGS); - return 0; + return ""; } -sub getmodules -{ - my ($silent) = @_; - - my $i = 0; - - if (!$silent) - { - print "Detecting modules "; - } +sub run_test($$) { + my ($what, $result) = @_; + print "Checking whether $what is available... "; + print $result ? "yes\n" : "no\n"; + return $result; +} - opendir(DIRHANDLE, "src/modules") or die("WTF, missing src/modules!"); - foreach my $name (sort readdir(DIRHANDLE)) - { - if ($name =~ /^m_(.+)\.cpp$/) - { - my $mod = $1; - $main::modlist[$i++] = $mod; - if (!$silent) - { - print "."; - } - } - } - closedir(DIRHANDLE); +sub test_file($$;$) { + my ($cc, $file, $args) = @_; + my $status = 0; + $args ||= ''; + $status ||= system "$cc -o __test_$file make/test/$file $args >/dev/null 2>&1"; + $status ||= system "./__test_$file >/dev/null 2>&1"; + unlink "./__test_$file"; + return !$status; +} - if (!$silent) - { - print "\nOk, $i modules.\n"; - } +sub test_header($$;$) { + my ($cc, $header, $args) = @_; + $args ||= ''; + open(CC, "| $cc -E - $args >/dev/null 2>&1") or return 0; + print CC "#include <$header>"; + close(CC); + return !$?; } -sub promptnumeric($$) +sub get_property($$;$) { - my $continue = 0; - my ($prompt, $configitem) = @_; - while (!$continue) - { - print "Please enter the maximum $prompt?\n"; - print "[\e[1;32m$main::config{$configitem}\e[0m] -> "; - chomp(my $var = <STDIN>); - if ($var eq "") - { - $var = $main::config{$configitem}; - } - if ($var =~ /^\d+$/) { - # We don't care what the number is, set it and be on our way. - $main::config{$configitem} = $var; - $continue = 1; - print "\n"; - } else { - print "You must enter a number in this field. Please try again.\n\n"; + my ($file, $property, $default) = @_; + open(MODULE, $file) or return $default; + while (<MODULE>) { + if ($_ =~ /^\/\* \$(\S+): (.+) \*\/$/) { + next unless $1 eq $property; + close(MODULE); + return translate_functions($2, $file); } } + close(MODULE); + return defined $default ? $default : ''; } -sub module_installed($) -{ - my $module = shift; - eval("use $module;"); - return !$@; -} - -sub promptstring_s($$) -{ - my ($prompt,$default) = @_; - my $var; - print "$prompt\n"; - print "[\e[1;32m$default\e[0m] -> "; - chomp($var = <STDIN>); - $var = $default if $var eq ""; - print "\n"; - return $var; +sub get_revision { + return $revision if defined $revision; + chomp(my $tags = `git describe --tags 2>/dev/null`); + $revision = $tags || 'release'; + return $revision; } -sub dumphash() +sub dump_hash() { print "\n\e[1;32mPre-build configuration is complete!\e[0m\n\n"; print "\e[0mBase install path:\e[1;32m\t\t$main::config{BASE_DIR}\e[0m\n"; print "\e[0mConfig path:\e[1;32m\t\t\t$main::config{CONFIG_DIR}\e[0m\n"; + print "\e[0mData path:\e[1;32m\t\t\t$main::config{DATA_DIR}\e[0m\n"; + print "\e[0mLog path:\e[1;32m\t\t\t$main::config{LOG_DIR}\e[0m\n"; print "\e[0mModule path:\e[1;32m\t\t\t$main::config{MODULE_DIR}\e[0m\n"; - print "\e[0mGCC Version Found:\e[1;32m\t\t$main::config{GCCVER}.$main::config{GCCMINOR}\e[0m\n"; - print "\e[0mCompiler program:\e[1;32m\t\t$main::config{CC}\e[0m\n"; - print "\e[0mGnuTLS Support:\e[1;32m\t\t\t$main::config{USE_GNUTLS}\e[0m\n"; - print "\e[0mOpenSSL Support:\e[1;32m\t\t$main::config{USE_OPENSSL}\e[0m\n\n"; - print "\e[1;32mImportant note: The maximum length values are now configured in the\e[0m\n"; - print "\e[1;32m configuration file, not in ./configure! See the <limits>\e[0m\n"; - print "\e[1;32m tag in the configuration file for more information.\e[0m\n\n"; -} - -sub is_dir -{ - my ($path) = @_; - if (chdir($path)) - { - chdir($main::this); - return 1; - } - else - { - # Just in case.. - chdir($main::this); - return 0; - } -} - -sub showhelp -{ - chomp(my $PWD = `pwd`); - print <<EOH; -Usage: configure [options] - -*** NOTE: NON-INTERACTIVE CONFIGURE IS *NOT* SUPPORTED BY THE *** -*** INSPIRCD DEVELOPMENT TEAM. DO NOT ASK FOR HELP REGARDING *** -*** NON-INTERACTIVE CONFIGURE ON THE FORUMS OR ON IRC! *** - -Options: [defaults in brackets after descriptions] - -When no options are specified, interactive -configuration is started and you must specify -any required values manually. If one or more -options are specified, non-interactive configuration -is started, and any omitted values are defaulted. - -Arguments with a single \"-\" symbol, as in -InspIRCd 1.0.x, are also allowed. - - --disable-interactive Sets no options itself, but - will disable any interactive prompting. - --update Update makefiles and dependencies - --clean Remove .config.cache file and go interactive - --enable-gnutls Enable GnuTLS module [no] - --enable-openssl Enable OpenSSL module [no] - --enable-epoll Enable epoll() where supported [set] - --enable-kqueue Enable kqueue() where supported [set] - --disable-epoll Do not enable epoll(), fall back - to select() [not set] - --disable-kqueue Do not enable kqueue(), fall back - to select() [not set] - --disable-ipv6 Do not build IPv6 native InspIRCd [not set] - --with-cc=[filename] Use an alternative compiler to - build InspIRCd [g++] - --with-maxbuf=[n] Change the per message buffer size [512] - DO NOT ALTER THIS OPTION WITHOUT GOOD REASON - AS IT *WILL* BREAK CLIENTS!!! - --prefix=[directory] Base directory to install into (if defined, - can automatically define config, module, bin - and library dirs as subdirectories of prefix) - [$PWD] - --config-dir=[directory] Config file directory for config and SSL certs - [$PWD/conf] - --log-dir=[directory] Log file directory for logs - [$PWD/logs] - --data-dir=[directory] Data directory for variable data, such as the permchannel configuration and the XLine database - [$PWD/data] - --module-dir=[directory] Modules directory for loadable modules - [$PWD/modules] - --binary-dir=[directory] Binaries directory for core binary - [$PWD/bin] - --library-dir=[directory] Library directory for core libraries - [$PWD/lib] - --list-extras Show current status of extra modules - --enable-extras=[extras] Enable the specified list of extras - --disable-extras=[extras] Disable the specified list of extras - --help Show this help text and exit - -EOH - exit(0); + print "\e[0mCompiler:\e[1;32m\t\t\t$main::cxx{NAME} $main::cxx{VERSION}\e[0m\n"; + print "\e[0mSocket engine:\e[1;32m\t\t\t$main::config{SOCKETENGINE}\e[0m\n"; + print "\e[0mGnuTLS support:\e[1;32m\t\t\t$main::config{USE_GNUTLS}\e[0m\n"; + print "\e[0mOpenSSL support:\e[1;32m\t\t$main::config{USE_OPENSSL}\e[0m\n"; } 1; - diff --git a/make/gnutlscert.pm b/make/gnutlscert.pm deleted file mode 100644 index a67be0cfd..000000000 --- a/make/gnutlscert.pm +++ /dev/null @@ -1,147 +0,0 @@ -# -# InspIRCd -- Internet Relay Chat Daemon -# -# Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> -# Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> -# -# This file is part of InspIRCd. InspIRCd 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, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# - - -package make::gnutlscert; - -require 5.8.0; - -use strict; -use warnings FATAL => qw(all); - -use Exporter 'import'; -use make::configure; -our @EXPORT = qw(make_gnutls_cert); - - -sub make_gnutls_cert() -{ - open (FH, ">certtool.template"); - my $timestr = time(); - my $org = promptstring_s("Please enter the organization name", "My IRC Network"); - my $unit = promptstring_s("Please enter the unit Name", "Server Admins"); - my $state = promptstring_s("Please enter your state (two letter code)", "CA"); - my $country = promptstring_s("Please enter your country", "Oompa Loompa Land"); - my $commonname = promptstring_s("Please enter the certificate common name (hostname)", "irc.mynetwork.com"); - my $email = promptstring_s("Please enter a contact email address", "oompa\@loompa.com"); - print FH <<__END__; -# X.509 Certificate options -# -# DN options - -# The organization of the subject. -organization = "$org" - -# The organizational unit of the subject. -unit = "$unit" - -# The locality of the subject. -# locality = - -# The state of the certificate owner. -state = "$state" - -# The country of the subject. Two letter code. -country = $country - -# The common name of the certificate owner. -cn = "$commonname" - -# A user id of the certificate owner. -#uid = "clauper" - -# If the supported DN OIDs are not adequate you can set -# any OID here. -# For example set the X.520 Title and the X.520 Pseudonym -# by using OID and string pairs. -#dn_oid = "2.5.4.12" "Dr." "2.5.4.65" "jackal" - -# This is deprecated and should not be used in new -# certificates. -# pkcs9_email = "none\@none.org" - -# The serial number of the certificate -serial = $timestr - -# In how many days, counting from today, this certificate will expire. -expiration_days = 700 - -# X.509 v3 extensions - -# A dnsname in case of a WWW server. -#dns_name = "www.none.org" - -# An IP address in case of a server. -#ip_address = "192.168.1.1" - -# An email in case of a person -email = "$email" - -# An URL that has CRLs (certificate revocation lists) -# available. Needed in CA certificates. -#crl_dist_points = "http://www.getcrl.crl/getcrl/" - -# Whether this is a CA certificate or not -#ca - -# Whether this certificate will be used for a TLS client -tls_www_client - -# Whether this certificate will be used for a TLS server -tls_www_server - -# Whether this certificate will be used to sign data (needed -# in TLS DHE ciphersuites). -signing_key - -# Whether this certificate will be used to encrypt data (needed -# in TLS RSA ciphersuites). Note that it is prefered to use different -# keys for encryption and signing. -encryption_key - -# Whether this key will be used to sign other certificates. -cert_signing_key - -# Whether this key will be used to sign CRLs. -crl_signing_key - -# Whether this key will be used to sign code. -code_signing_key - -# Whether this key will be used to sign OCSP data. -ocsp_signing_key - -# Whether this key will be used for time stamping. -time_stamping_key -__END__ -close(FH); -my $certtool = "certtool"; -if (`uname -s` eq "Darwin\n") { - # On OS X the certtool binary name is different to prevent - # collisions with the system certtool from NSS. - $certtool = "gnutls-certtool"; -} -if ( (my $status = system("$certtool --generate-privkey --outfile key.pem")) ne 0) { return 1; } -if ( (my $status = system("$certtool --generate-self-signed --load-privkey key.pem --outfile cert.pem --template certtool.template")) ne 0) { return 1; } -unlink("certtool.template"); -return 0; -} - -1; - diff --git a/make/opensslcert.pm b/make/opensslcert.pm deleted file mode 100644 index fd7bd6998..000000000 --- a/make/opensslcert.pm +++ /dev/null @@ -1,61 +0,0 @@ -# -# InspIRCd -- Internet Relay Chat Daemon -# -# Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> -# Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> -# -# This file is part of InspIRCd. InspIRCd 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, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# - - -package make::opensslcert; - -require 5.8.0; - -use strict; -use warnings FATAL => qw(all); - -use Exporter 'import'; -use make::configure; -our @EXPORT = qw(make_openssl_cert); - - -sub make_openssl_cert() -{ - open (FH, ">openssl.template"); - my $org = promptstring_s("Please enter the organization name", "My IRC Network"); - my $unit = promptstring_s("Please enter the unit Name", "Server Admins"); - my $country = promptstring_s("Please enter your country (two letter code)", "US"); - my $state = promptstring_s("Please enter your state or locality name", "Alaska"); - my $city = promptstring_s("Please enter your city", "Factory Town"); - my $email = promptstring_s("Please enter a contact email address", "oompa\@loompa.com"); - my $commonname = promptstring_s("Please enter the common name (domain name) of the irc server", "example.inspircd.org"); - print FH <<__END__; -$country -$state -$city -$org -$unit -$commonname -$email -__END__ -close(FH); - -my $time = promptstring_s("Please enter the number of days that this certificate is valid for","365"); - -system("cat openssl.template | openssl req -x509 -nodes -newkey rsa:1024 -keyout key.pem -out cert.pem -days $time 2>/dev/null"); -system("openssl dhparam -out dhparams.pem 1024"); -unlink("openssl.template"); -} - -1; diff --git a/make/template/inspircd b/make/template/inspircd index 322ee2cd6..c14099323 100644 --- a/make/template/inspircd +++ b/make/template/inspircd @@ -29,11 +29,11 @@ my $binpath = "@BINARY_DIR@"; my $runpath = "@BASE_DIR@"; my $datadir = "@DATA_DIR@"; my $valgrindlogpath = "$basepath/valgrindlogs"; -my $executable = "@EXECUTABLE@"; +my $executable = "inspircd"; my $version = "@VERSION@"; my $uid = "@UID@"; -if ($< == 0 || $> == 0) { +if (!("--runasroot" ~~ @ARGV) && ($< == 0 || $> == 0)) { if ($uid !~ /^\d+$/) { # Named UID, look it up $uid = getpwnam $uid; diff --git a/make/template/main.mk b/make/template/main.mk index e55e36c0a..bdb4d9762 100644 --- a/make/template/main.mk +++ b/make/template/main.mk @@ -30,13 +30,13 @@ # -CC = @CC@ +CXX = @CXX@ +COMPILER = @COMPILER@ SYSTEM = @SYSTEM@ BUILDPATH = @BUILD_DIR@ SOCKETENGINE = @SOCKETENGINE@ -CXXFLAGS = -pipe -fPIC -DPIC -LDLIBS = -pthread -lstdc++ -LDFLAGS = +CORECXXFLAGS = -fPIC -pipe -Iinclude -Wall -Wextra -Wfatal-errors -Wno-unused-parameter -Wshadow +LDLIBS = -lstdc++ CORELDFLAGS = -rdynamic -L. $(LDFLAGS) PICLDFLAGS = -fPIC -shared -rdynamic $(LDFLAGS) BASE = "$(DESTDIR)@BASE_DIR@" @@ -46,16 +46,17 @@ DATPATH = "$(DESTDIR)@DATA_DIR@" BINPATH = "$(DESTDIR)@BINARY_DIR@" INSTALL = install INSTUID = @UID@ -INSTMODE_DIR = 0755 -INSTMODE_BIN = 0755 -INSTMODE_LIB = 0644 +INSTMODE_DIR = 0750 +INSTMODE_BIN = 0750 +INSTMODE_LIB = 0640 -@IFEQ $(CC) icc - CXXFLAGS += -Wshadow -@ELSE - CXXFLAGS += -pedantic -Woverloaded-virtual -Wshadow -Wformat=2 -Wmissing-format-attribute -Wall +@IFNEQ $(COMPILER) icc + CORECXXFLAGS += -pedantic -Woverloaded-virtual -Wshadow -Wformat=2 -Wmissing-format-attribute @ENDIF +@IFNEQ $(SYSTEM) darwin + LDLIBS += -pthread +@ENDIF @IFEQ $(SYSTEM) linux LDLIBS += -ldl -lrt @@ -70,19 +71,11 @@ INSTMODE_LIB = 0644 LDLIBS += -lsocket -lnsl -lrt -lresolv INSTALL = ginstall @ENDIF -@IFEQ $(SYSTEM) sunos - LDLIBS += -lsocket -lnsl -lrt -lresolv - INSTALL = ginstall -@ENDIF @IFEQ $(SYSTEM) darwin - CXXFLAGS += -DDARWIN -frtti LDLIBS += -ldl CORELDFLAGS = -dynamic -bind_at_load -L. $(LDFLAGS) PICLDFLAGS = -fPIC -shared -twolevel_namespace -undefined dynamic_lookup $(LDFLAGS) @ENDIF -@IFEQ $(SYSTEM) interix - CXXFLAGS += -D_ALL_SOURCE -I/usr/local/include -@ENDIF @IFNDEF D D=0 @@ -90,48 +83,50 @@ INSTMODE_LIB = 0644 DBGOK=0 @IFEQ $(D) 0 - CXXFLAGS += -O2 -@IFEQ $(CC) gcc - CXXFLAGS += -g1 + CORECXXFLAGS += -O2 +@IFEQ $(CXX) g++ + CORECXXFLAGS += -g1 @ENDIF HEADER = std-header DBGOK=1 @ENDIF @IFEQ $(D) 1 - CXXFLAGS += -O0 -g3 -Werror + CORECXXFLAGS += -O0 -g3 -Werror HEADER = debug-header DBGOK=1 @ENDIF @IFEQ $(D) 2 - CXXFLAGS += -O2 -g3 + CORECXXFLAGS += -O2 -g3 HEADER = debug-header DBGOK=1 @ENDIF FOOTER = finishmessage -CXXFLAGS += -Iinclude - @GNU_ONLY MAKEFLAGS += --no-print-directory @GNU_ONLY SOURCEPATH = $(shell /bin/pwd) @BSD_ONLY SOURCEPATH != /bin/pwd @IFDEF V - RUNCC = $(CC) - RUNLD = $(CC) + RUNCC = $(CXX) + RUNLD = $(CXX) VERBOSE = -v @ELSE @GNU_ONLY MAKEFLAGS += --silent @BSD_ONLY MAKE += -s - RUNCC = perl $(SOURCEPATH)/make/run-cc.pl $(CC) - RUNLD = perl $(SOURCEPATH)/make/run-cc.pl $(CC) + RUNCC = perl $(SOURCEPATH)/make/run-cc.pl $(CXX) + RUNLD = perl $(SOURCEPATH)/make/run-cc.pl $(CXX) @ENDIF @IFDEF PURE_STATIC - CXXFLAGS += -DPURE_STATIC + CORECXXFLAGS += -DPURE_STATIC @ENDIF -@DO_EXPORT RUNCC RUNLD CXXFLAGS LDLIBS PICLDFLAGS VERBOSE SOCKETENGINE CORELDFLAGS +# Add the users CXXFLAGS to the base ones to allow them to override +# things like -Wfatal-errors if they wish to. +CORECXXFLAGS += $(CXXFLAGS) + +@DO_EXPORT RUNCC RUNLD CORECXXFLAGS LDLIBS PICLDFLAGS VERBOSE SOCKETENGINE CORELDFLAGS @DO_EXPORT SOURCEPATH BUILDPATH PURE_STATIC SPLIT_CC # Default target @@ -230,6 +225,7 @@ install: target [ $(BUILDPATH)/modules/ -ef $(MODPATH) ] || $(INSTALL) -m $(INSTMODE_LIB) $(BUILDPATH)/modules/*.so $(MODPATH) @ENDIF -$(INSTALL) -m $(INSTMODE_BIN) @STARTSCRIPT@ $(BASE) 2>/dev/null + -$(INSTALL) -m $(INSTMODE_BIN) tools/genssl $(BINPATH)/inspircd-genssl 2>/dev/null -$(INSTALL) -m $(INSTMODE_LIB) tools/gdbargs $(BASE)/.gdbargs 2>/dev/null -$(INSTALL) -m $(INSTMODE_LIB) docs/conf/*.example $(CONPATH)/examples -$(INSTALL) -m $(INSTMODE_LIB) docs/conf/aliases/*.example $(CONPATH)/examples/aliases @@ -269,14 +265,11 @@ deinstall: -rm -f $(BASE)/.gdbargs -rm -f $(BASE)/org.inspircd.plist -squeakyclean: distclean - configureclean: rm -f .config.cache rm -f BSDmakefile rm -f GNUmakefile - rm -f include/inspircd_config.h - rm -f include/inspircd_version.h + rm -f include/config.h rm -f inspircd -rm -f org.inspircd.plist @@ -312,4 +305,4 @@ help: @echo ' deinstall Removes the files created by "make install"' @echo -.PHONY: all target debug debug-header mod-header mod-footer std-header finishmessage install clean deinstall squeakyclean configureclean help +.PHONY: all target debug debug-header mod-header mod-footer std-header finishmessage install clean deinstall configureclean help diff --git a/include/modes/umode_o.h b/make/test/clock_gettime.cpp index f9644a097..91d8cd412 100644 --- a/include/modes/umode_o.h +++ b/make/test/clock_gettime.cpp @@ -1,7 +1,6 @@ /* * InspIRCd -- Internet Relay Chat Daemon * - * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public @@ -17,15 +16,10 @@ */ -#include "mode.h" +#include <time.h> -class InspIRCd; - -/** User mode +o - */ -class ModeUserOperator : public ModeHandler -{ - public: - ModeUserOperator(); - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); -}; +int main() { + timespec time_spec; + clock_gettime(CLOCK_REALTIME, &time_spec); + return 0; +} diff --git a/make/check_eventfd.cpp b/make/test/eventfd.cpp index 980d04485..980d04485 100644 --- a/make/check_eventfd.cpp +++ b/make/test/eventfd.cpp diff --git a/make/check_epoll.cpp b/make/test/kqueue.cpp index 918d3907e..a8b9882cf 100644 --- a/make/check_epoll.cpp +++ b/make/test/kqueue.cpp @@ -16,9 +16,10 @@ */ -#include <sys/epoll.h> +#include <sys/types.h> +#include <sys/event.h> int main() { - int fd = epoll_create(1); + int fd = kqueue(); return (fd < 0); } diff --git a/make/unit-cc.pl b/make/unit-cc.pl index 7474365aa..5b0c50021 100755 --- a/make/unit-cc.pl +++ b/make/unit-cc.pl @@ -52,7 +52,7 @@ exit 1; sub do_static_find { my @flags; for my $file (@ARGV) { - push @flags, getlinkerflags($file); + push @flags, get_property($file, 'LinkerFlags'); } open F, '>', $out; print F join ' ', @flags; @@ -97,12 +97,10 @@ sub do_compile { my $libs = ''; my $binary = $ENV{RUNCC}; if ($do_compile) { - $flags = $ENV{CXXFLAGS}; - $flags =~ s/ -pedantic// if nopedantic($file); - $flags .= ' ' . getcompilerflags($file); + $flags = $ENV{CORECXXFLAGS} . ' ' . get_property($file, 'CompileFlags'); if ($file =~ m#(?:^|/)((?:m|cmd)_[^/. ]+)(?:\.cpp|/.*\.cpp)$#) { - $flags .= ' -DMODNAME='.$1.'.so'; + $flags .= ' -DMODNAME=\\"'.$1.'\\"'; } } else { $binary = $ENV{RUNLD}; @@ -110,7 +108,7 @@ sub do_compile { if ($do_link) { $flags = join ' ', $flags, $ENV{PICLDFLAGS}; - $libs = join ' ', getlinkerflags($file); + $libs = get_property($file, 'LinkerFlags'); } else { $flags .= ' -c'; } diff --git a/make/utilities.pm b/make/utilities.pm index 9281246fb..87aa46d6e 100644 --- a/make/utilities.pm +++ b/make/utilities.pm @@ -20,18 +20,22 @@ # -package make::utilities; +BEGIN { + require 5.8.0; +} -require 5.8.0; +package make::utilities; use strict; use warnings FATAL => qw(all); use Exporter 'import'; -use POSIX; -use Getopt::Long; use Fcntl; -our @EXPORT = qw(make_rpath pkgconfig_get_include_dirs pkgconfig_get_lib_dirs pkgconfig_check_version translate_functions promptstring); +use File::Path; +use File::Spec::Functions qw(rel2abs); +use Getopt::Long; + +our @EXPORT = qw(module_installed prompt_bool prompt_dir prompt_string make_rpath pkgconfig_get_include_dirs pkgconfig_get_lib_dirs pkgconfig_check_version translate_functions promptstring); # Parse the output of a *_config program, # such as pcre_config, take out the -L @@ -42,6 +46,47 @@ our @EXPORT = qw(make_rpath pkgconfig_get_include_dirs pkgconfig_get_lib_dirs pk my %already_added = (); my $if_skip_lines = 0; +sub module_installed($) +{ + my $module = shift; + eval("use $module;"); + return !$@; +} + +sub prompt_bool($$$) { + my ($interactive, $question, $default) = @_; + my $answer = prompt_string($interactive, $question, $default ? 'y' : 'n'); + return $answer =~ /y/i; +} + +sub prompt_dir($$$) { + my ($interactive, $question, $default) = @_; + my ($answer, $create) = (undef, 'y'); + do { + $answer = rel2abs(prompt_string($interactive, $question, $default)); + $create = prompt_bool($interactive && !-d $answer, "$answer does not exist. Create it?", 'y'); + my $mkpath = eval { + mkpath($answer, 0, 0750); + return 1; + }; + unless (defined $mkpath) { + print "Error: unable to create $answer!\n\n"; + $create = 0; + } + } while (!$create); + return $answer; +} + +sub prompt_string($$$) { + my ($interactive, $question, $default) = @_; + return $default unless $interactive; + print $question, "\n"; + print "[\e[1;32m$default\e[0m] => "; + chomp(my $answer = <STDIN>); + print "\n"; + return $answer ? $answer : $default; +} + sub promptstring($$$$$) { my ($prompt, $configitem, $default, $package, $commandlineswitch) = @_; @@ -108,15 +153,6 @@ sub pkgconfig_get_include_dirs($$$;$) { my ($packagename, $headername, $defaults, $module) = @_; - my $key = "default_includedir_$packagename"; - if (exists $main::config{$key}) - { - print "Locating include directory for package \e[1;32m$packagename\e[0m for module \e[1;32m$module\e[0m... "; - my $ret = $main::config{$key}; - print "\e[1;32m$ret\e[0m (cached)\n"; - return $ret; - } - extend_pkg_path(); print "Locating include directory for package \e[1;32m$packagename\e[0m for module \e[1;32m$module\e[0m... "; @@ -223,15 +259,6 @@ sub pkgconfig_get_lib_dirs($$$;$) { my ($packagename, $libname, $defaults, $module) = @_; - my $key = "default_libdir_$packagename"; - if (exists $main::config{$key}) - { - print "Locating library directory for package \e[1;32m$packagename\e[0m for module \e[1;32m$module\e[0m... "; - my $ret = $main::config{$key}; - print "\e[1;32m$ret\e[0m (cached)\n"; - return $ret; - } - extend_pkg_path(); print "Locating library directory for package \e[1;32m$packagename\e[0m for module \e[1;32m$module\e[0m... "; @@ -305,16 +332,6 @@ sub translate_functions($$) $module =~ /modules*\/(.+?)$/; $module = $1; - # This is only a cursory check, just designed to catch casual accidental use of backticks. - # There are pleanty of ways around it, but its not supposed to be for security, just checking - # that people are using the new configuration api as theyre supposed to and not just using - # backticks instead of eval(), being as eval has accountability. People wanting to get around - # the accountability will do so anyway. - if (($line =~ /`/) && ($line !~ /eval\(.+?`.+?\)/)) - { - die "Developers should no longer use backticks in configuration macros. Please use exec() and eval() macros instead. Offending line: $line (In module: $module)"; - } - if ($line =~ /ifuname\(\!"(\w+)"\)/) { my $uname = $1; diff --git a/modulemanager b/modulemanager index 7884654af..9e4670de8 100755 --- a/modulemanager +++ b/modulemanager @@ -22,8 +22,7 @@ use strict; use warnings FATAL => qw(all); -use make::configure; - +use make::utilities; if (!module_installed("LWP::Simple")) { @@ -35,10 +34,9 @@ if (!module_installed("Crypt::SSLeay") && !module_installed("IO::Socket::SSL")) die "Your system is missing the Crypt::SSLeay or IO::Socket::SSL Perl modules!"; } +use File::Basename; use LWP::Simple; -our @modlist; - my %installed; # $installed{name} = $version @@ -128,8 +126,6 @@ while (<SRC>) { } close SRC; -getmodules(1); - # determine core version `./src/version.sh` =~ /InspIRCd-([0-9.]+)/ or die "Cannot determine inspircd version"; $installed{core} = $1; @@ -153,9 +149,8 @@ $modules{core}{$1} = { }; # set up core module list -for my $modname (@modlist) { - my $mod = "m_$modname"; - my $modfile = "src/modules/$mod.cpp"; +for my $modname (<src/modules/m_*.cpp>) { + my $mod = basename($modname, '.cpp'); my $ver = getmodversion($mod) || '0.0'; $ver =~ s/\$Rev: (.*) \$/$1/; # for storing revision in SVN $installed{$mod} = $ver; diff --git a/src/bancache.cpp b/src/bancache.cpp index 52449e55e..4bb2fa82c 100644 --- a/src/bancache.cpp +++ b/src/bancache.cpp @@ -18,34 +18,16 @@ */ -/* $Core */ - #include "inspircd.h" #include "bancache.h" -BanCacheHit *BanCacheManager::AddHit(const std::string &ip, const std::string &type, const std::string &reason) -{ - BanCacheHit *b; - - if (this->BanHash->find(ip) != this->BanHash->end()) // can't have two cache entries on the same IP, sorry.. - return NULL; - - b = new BanCacheHit(ip, type, reason); - - this->BanHash->insert(std::make_pair(ip, b)); - return b; -} - BanCacheHit *BanCacheManager::AddHit(const std::string &ip, const std::string &type, const std::string &reason, time_t seconds) { - BanCacheHit *b; - - if (this->BanHash->find(ip) != this->BanHash->end()) // can't have two cache entries on the same IP, sorry.. + BanCacheHit*& b = (*BanHash)[ip]; + if (b != NULL) // can't have two cache entries on the same IP, sorry.. return NULL; - b = new BanCacheHit(ip, type, reason, seconds); - - this->BanHash->insert(std::make_pair(ip, b)); + b = new BanCacheHit(type, reason, (seconds ? seconds : 86400)); return b; } @@ -55,113 +37,60 @@ BanCacheHit *BanCacheManager::GetHit(const std::string &ip) if (i == this->BanHash->end()) return NULL; // free and safe - else - { - if (ServerInstance->Time() > i->second->Expiry) - { - ServerInstance->Logs->Log("BANCACHE", DEBUG, "Hit on " + ip + " is out of date, removing!"); - RemoveHit(i->second); - return NULL; // out of date - } - return i->second; // hit. - } + if (RemoveIfExpired(i)) + return NULL; // expired + + return i->second; // hit. } -bool BanCacheManager::RemoveHit(BanCacheHit *b) +bool BanCacheManager::RemoveIfExpired(BanCacheHash::iterator& it) { - BanCacheHash::iterator i; - - if (!b) - return false; // I don't think so. + if (ServerInstance->Time() < it->second->Expiry) + return false; - i = this->BanHash->find(b->IP); - - if (i == this->BanHash->end()) - { - // err.. - ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCacheManager::RemoveHit(): I got asked to remove a hit that wasn't in the hash(?)"); - } - else - { - this->BanHash->erase(i); - } - - delete b; + ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "Hit on " + it->first + " is out of date, removing!"); + delete it->second; + it = BanHash->erase(it); return true; } -unsigned int BanCacheManager::RemoveEntries(const std::string &type, bool positive) +void BanCacheManager::RemoveEntries(const std::string& type, bool positive) { - int removed = 0; - - BanCacheHash::iterator safei; - if (positive) - ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCacheManager::RemoveEntries(): Removing positive hits for " + type); + ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCacheManager::RemoveEntries(): Removing positive hits for " + type); else - ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCacheManager::RemoveEntries(): Removing negative hits for " + type); + ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCacheManager::RemoveEntries(): Removing all negative hits"); - for (BanCacheHash::iterator n = BanHash->begin(); n != BanHash->end(); ) + for (BanCacheHash::iterator i = BanHash->begin(); i != BanHash->end(); ) { - safei = n; - safei++; + if (RemoveIfExpired(i)) + continue; // updates the iterator if expired - BanCacheHit *b = n->second; + BanCacheHit* b = i->second; + bool remove = false; - /* Safe to delete items here through iterator 'n' */ - if (b->Type == type || !positive) // if removing negative hits, ignore type.. + if (positive) { - if ((positive && !b->Reason.empty()) || b->Reason.empty()) - { - /* we need to remove this one. */ - ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCacheManager::RemoveEntries(): Removing a hit on " + b->IP); - delete b; - BanHash->erase(n); // WORD TO THE WISE: don't use RemoveHit here, because we MUST remove the iterator in a safe way. - removed++; - } + // when removing positive hits, remove only if the type matches + remove = b->IsPositive() && (b->Type == type); + } + else + { + // when removing negative hits, remove all of them + remove = !b->IsPositive(); } - /* End of safe section */ - n = safei; - } - - - return removed; -} - -void BanCacheManager::RehashCache() -{ - BanCacheHash* NewHash = new BanCacheHash(); - - BanCacheHash::iterator safei; - for (BanCacheHash::iterator n = BanHash->begin(); n != BanHash->end(); ) - { - safei = n; - safei++; - - /* Safe to delete items here through iterator 'n' */ - BanCacheHit *b = n->second; - - if (ServerInstance->Time() > b->Expiry) + if (remove) { /* we need to remove this one. */ + ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCacheManager::RemoveEntries(): Removing a hit on " + i->first); delete b; - BanHash->erase(n); // WORD TO THE WISE: don't use RemoveHit here, because we MUST remove the iterator in a safe way. + i = BanHash->erase(i); } else - { - /* Actually inserts a std::pair */ - NewHash->insert(*n); - } - - /* End of safe section */ - - n = safei; + ++i; } - - delete BanHash; - BanHash = NewHash; } BanCacheManager::~BanCacheManager() diff --git a/src/base.cpp b/src/base.cpp index 66a3cb140..db8d9f3cf 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -28,13 +28,13 @@ classbase::classbase() { if (ServerInstance && ServerInstance->Logs) - ServerInstance->Logs->Log("CULLLIST", DEBUG, "classbase::+ @%p", (void*)this); + ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "classbase::+ @%p", (void*)this); } CullResult classbase::cull() { if (ServerInstance && ServerInstance->Logs) - ServerInstance->Logs->Log("CULLLIST", DEBUG, "classbase::-%s @%p", + ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "classbase::-%s @%p", typeid(*this).name(), (void*)this); return CullResult(); } @@ -42,7 +42,7 @@ CullResult classbase::cull() classbase::~classbase() { if (ServerInstance && ServerInstance->Logs) - ServerInstance->Logs->Log("CULLLIST", DEBUG, "classbase::~ @%p", (void*)this); + ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "classbase::~ @%p", (void*)this); } CullResult::CullResult() @@ -74,14 +74,14 @@ refcountbase::refcountbase() : refcount(0) refcountbase::~refcountbase() { if (refcount && ServerInstance && ServerInstance->Logs) - ServerInstance->Logs->Log("CULLLIST", DEBUG, "refcountbase::~ @%p with refcount %d", + ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "refcountbase::~ @%p with refcount %d", (void*)this, refcount); } usecountbase::~usecountbase() { if (usecount && ServerInstance && ServerInstance->Logs) - ServerInstance->Logs->Log("CULLLIST", DEBUG, "usecountbase::~ @%p with refcount %d", + ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "usecountbase::~ @%p with refcount %d", (void*)this, usecount); } @@ -198,8 +198,7 @@ CullResult Extensible::cull() Extensible::~Extensible() { if (!extensions.empty() && ServerInstance && ServerInstance->Logs) - ServerInstance->Logs->Log("CULLLIST", DEBUG, - "Extensible destructor called without cull @%p", (void*)this); + ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "Extensible destructor called without cull @%p", (void*)this); } LocalExtItem::LocalExtItem(const std::string& Key, Module* mod) : ExtensionItem(Key, mod) diff --git a/src/channels.cpp b/src/channels.cpp index 4f63654a5..afc569909 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -23,27 +23,27 @@ */ -/* $Core */ - #include "inspircd.h" +#include "listmode.h" #include <cstdarg> #include "mode.h" -Channel::Channel(const std::string &cname, time_t ts) +namespace { - if (!ServerInstance->chanlist->insert(std::make_pair(cname, this)).second) - throw CoreException("Cannot create duplicate channel " + cname); - - this->name = cname; - this->age = ts ? ts : ServerInstance->Time(); - - maxbans = topicset = 0; - modes.reset(); + ChanModeReference ban(NULL, "ban"); + ChanModeReference inviteonlymode(NULL, "inviteonly"); + ChanModeReference keymode(NULL, "key"); + ChanModeReference limitmode(NULL, "limit"); + ChanModeReference secretmode(NULL, "secret"); + ChanModeReference privatemode(NULL, "private"); + UserModeReference invisiblemode(NULL, "invisible"); } -void Channel::SetMode(char mode,bool mode_on) +Channel::Channel(const std::string &cname, time_t ts) + : name(cname), age(ts), topicset(0) { - modes[mode-65] = mode_on; + if (!ServerInstance->chanlist->insert(std::make_pair(cname, this)).second) + throw CoreException("Cannot create duplicate channel " + cname); } void Channel::SetMode(ModeHandler* mh, bool on) @@ -51,14 +51,12 @@ void Channel::SetMode(ModeHandler* mh, bool on) modes[mh->GetModeChar() - 65] = on; } -void Channel::SetModeParam(char mode, const std::string& parameter) +void Channel::SetModeParam(ModeHandler* mh, const std::string& parameter) { - CustomModeList::iterator n = custom_mode_params.find(mode); - // always erase, even if changing, so that the map gets the new value - if (n != custom_mode_params.end()) - custom_mode_params.erase(n); + char mode = mh->GetModeChar(); if (parameter.empty()) { + custom_mode_params.erase(mode); modes[mode-65] = false; } else @@ -68,19 +66,6 @@ void Channel::SetModeParam(char mode, const std::string& parameter) } } -void Channel::SetModeParam(ModeHandler* mode, const std::string& parameter) -{ - SetModeParam(mode->GetModeChar(), parameter); -} - -std::string Channel::GetModeParameter(char mode) -{ - CustomModeList::iterator n = custom_mode_params.find(mode); - if (n != custom_mode_params.end()) - return n->second; - return ""; -} - std::string Channel::GetModeParameter(ModeHandler* mode) { CustomModeList::iterator n = custom_mode_params.find(mode->GetModeChar()); @@ -89,96 +74,64 @@ std::string Channel::GetModeParameter(ModeHandler* mode) return ""; } -int Channel::SetTopic(User *u, std::string &ntopic, bool forceset) +void Channel::SetTopic(User* u, const std::string& ntopic) { - if (!u) - u = ServerInstance->FakeClient; - if (IS_LOCAL(u) && !forceset) - { - ModResult res; - FIRST_MOD_RESULT(OnPreTopicChange, res, (u,this,ntopic)); - - if (res == MOD_RES_DENY) - return CMD_FAILURE; - if (res != MOD_RES_ALLOW) - { - if (!this->HasUser(u)) - { - u->WriteNumeric(442, "%s %s :You're not on that channel!",u->nick.c_str(), this->name.c_str()); - return CMD_FAILURE; - } - if (IsModeSet('t') && !ServerInstance->OnCheckExemption(u,this,"topiclock").check(GetPrefixValue(u) >= HALFOP_VALUE)) - { - u->WriteNumeric(482, "%s %s :You do not have access to change the topic on this channel", u->nick.c_str(), this->name.c_str()); - return CMD_FAILURE; - } - } - } - this->topic.assign(ntopic, 0, ServerInstance->Config->Limits.MaxTopic); - if (u) - { - this->setby.assign(ServerInstance->Config->FullHostInTopic ? u->GetFullHost() : u->nick, 0, 128); - this->WriteChannel(u, "TOPIC %s :%s", this->name.c_str(), this->topic.c_str()); - } - else - { - this->setby.assign(ServerInstance->Config->ServerName); - this->WriteChannelWithServ(ServerInstance->Config->ServerName, "TOPIC %s :%s", this->name.c_str(), this->topic.c_str()); - } - + this->setby.assign(ServerInstance->Config->FullHostInTopic ? u->GetFullHost() : u->nick, 0, 128); + this->WriteChannel(u, "TOPIC %s :%s", this->name.c_str(), this->topic.c_str()); this->topicset = ServerInstance->Time(); - FOREACH_MOD(I_OnPostTopicChange,OnPostTopicChange(u, this, this->topic)); - - return CMD_SUCCESS; -} - -long Channel::GetUserCounter() -{ - return userlist.size(); + FOREACH_MOD(OnPostTopicChange, (u, this, this->topic)); } Membership* Channel::AddUser(User* user) { - Membership* memb = new Membership(user, this); - userlist[user] = memb; + Membership*& memb = userlist[user]; + if (memb) + return NULL; + + memb = new Membership(user, this); return memb; } void Channel::DelUser(User* user) { - UserMembIter a = userlist.find(user); + UserMembIter it = userlist.find(user); + if (it != userlist.end()) + DelUser(it); +} - if (a != userlist.end()) - { - a->second->cull(); - delete a->second; - userlist.erase(a); - } +void Channel::CheckDestroy() +{ + if (!userlist.empty()) + return; - if (userlist.empty()) - { - ModResult res; - FIRST_MOD_RESULT(OnChannelPreDelete, res, (this)); - if (res == MOD_RES_DENY) - return; - chan_hash::iterator iter = ServerInstance->chanlist->find(this->name); - /* kill the record */ - if (iter != ServerInstance->chanlist->end()) - { - FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this)); - ServerInstance->chanlist->erase(iter); - } + ModResult res; + FIRST_MOD_RESULT(OnChannelPreDelete, res, (this)); + if (res == MOD_RES_DENY) + return; - ClearInvites(); - ServerInstance->GlobalCulls.AddItem(this); + chan_hash::iterator iter = ServerInstance->chanlist->find(this->name); + /* kill the record */ + if (iter != ServerInstance->chanlist->end()) + { + FOREACH_MOD(OnChannelDelete, (this)); + ServerInstance->chanlist->erase(iter); } + + ClearInvites(); + ServerInstance->GlobalCulls.AddItem(this); } -bool Channel::HasUser(User* user) +void Channel::DelUser(const UserMembIter& membiter) { - return (userlist.find(user) != userlist.end()); + Membership* memb = membiter->second; + memb->cull(); + delete memb; + userlist.erase(membiter); + + // If this channel became empty then it should be removed + CheckDestroy(); } Membership* Channel::GetUser(User* user) @@ -189,14 +142,9 @@ Membership* Channel::GetUser(User* user) return i->second; } -const UserMembList* Channel::GetUsers() -{ - return &userlist; -} - void Channel::SetDefaultModes() { - ServerInstance->Logs->Log("CHANNELS", DEBUG, "SetDefaultModes %s", + ServerInstance->Logs->Log("CHANNELS", LOG_DEBUG, "SetDefaultModes %s", ServerInstance->Config->DefaultModes.c_str()); irc::spacesepstream list(ServerInstance->Config->DefaultModes); std::string modeseq; @@ -209,6 +157,9 @@ void Channel::SetDefaultModes() ModeHandler* mode = ServerInstance->Modes->FindMode(*n, MODETYPE_CHANNEL); if (mode) { + if (mode->GetPrefixRank()) + continue; + if (mode->GetNumParams(true)) list.GetToken(parameter); else @@ -223,14 +174,13 @@ void Channel::SetDefaultModes() * add a channel to a user, creating the record for it if needed and linking * it to the user record */ -Channel* Channel::JoinUser(User *user, const char* cn, bool override, const char* key, bool bursting, time_t TS) +Channel* Channel::JoinUser(LocalUser* user, std::string cname, bool override, const std::string& key) { - // Fix: unregistered users could be joined using /SAJOIN - if (!user || !cn || user->registered != REG_ALL) + if (user->registered != REG_ALL) + { + ServerInstance->Logs->Log("CHANNELS", LOG_DEBUG, "Attempted to join unregistered user " + user->uuid + " to channel " + cname); return NULL; - - std::string privs; - Channel *Ptr; + } /* * We don't restrict the number of channels that remote users or users that are override-joining may be in. @@ -238,13 +188,13 @@ Channel* Channel::JoinUser(User *user, const char* cn, bool override, const char * We restrict local operators to OperMaxChans channels. * This is a lot more logical than how it was formerly. -- w00t */ - if (IS_LOCAL(user) && !override) + if (!override) { if (user->HasPrivPermission("channels/high-join-limit")) { if (user->chans.size() >= ServerInstance->Config->OperMaxChans) { - user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cn); + user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cname.c_str()); return NULL; } } @@ -255,102 +205,99 @@ Channel* Channel::JoinUser(User *user, const char* cn, bool override, const char maxchans = ServerInstance->Config->MaxChans; if (user->chans.size() >= maxchans) { - user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cn); + user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cname.c_str()); return NULL; } } } - std::string cname; - cname.assign(std::string(cn), 0, ServerInstance->Config->Limits.ChanMax); - Ptr = ServerInstance->FindChan(cname); - bool created_by_local = false; + // Crop channel name if it's too long + if (cname.length() > ServerInstance->Config->Limits.ChanMax) + cname.resize(ServerInstance->Config->Limits.ChanMax); - if (!Ptr) + Channel* chan = ServerInstance->FindChan(cname); + bool created_by_local = (chan == NULL); // Flag that will be passed to modules in the OnUserJoin() hook later + std::string privs; // Prefix mode(letter)s to give to the joining user + + if (!chan) { - /* - * Fix: desync bug was here, don't set @ on remote users - spanningtree handles their permissions. bug #358. -- w00t - */ - if (!IS_LOCAL(user)) - { - if (!TS) - ServerInstance->Logs->Log("CHANNELS",DEBUG,"*** BUG *** Channel::JoinUser called for REMOTE user '%s' on channel '%s' but no TS given!", user->nick.c_str(), cn); - } - else - { - privs = "o"; - created_by_local = true; - } + privs = ServerInstance->Config->DefaultModes.substr(0, ServerInstance->Config->DefaultModes.find(' ')); - if (IS_LOCAL(user) && override == false) + if (override == false) { + // Ask the modules whether they're ok with the join, pass NULL as Channel* as the channel is yet to be created ModResult MOD_RESULT; - FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, NULL, cname.c_str(), privs, key ? key : "")); + FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, NULL, cname, privs, key)); if (MOD_RESULT == MOD_RES_DENY) - return NULL; + return NULL; // A module wasn't happy with the join, abort } - Ptr = new Channel(cname, TS); + chan = new Channel(cname, ServerInstance->Time()); + // Set the default modes on the channel (<options:defaultmodes>) + chan->SetDefaultModes(); } else { /* Already on the channel */ - if (Ptr->HasUser(user)) + if (chan->HasUser(user)) return NULL; - /* - * remote users are allowed us to bypass channel modes - * and bans (used by servers) - */ - if (IS_LOCAL(user) && override == false) + if (override == false) { ModResult MOD_RESULT; - FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, Ptr, cname.c_str(), privs, key ? key : "")); + FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, chan, cname, privs, key)); + + // A module explicitly denied the join and (hopefully) generated a message + // describing the situation, so we may stop here without sending anything if (MOD_RESULT == MOD_RES_DENY) - { return NULL; - } - else if (MOD_RESULT == MOD_RES_PASSTHRU) + + // If no module returned MOD_RES_DENY or MOD_RES_ALLOW (which is the case + // most of the time) then proceed to check channel modes +k, +i, +l and bans, + // in this order. + // If a module explicitly allowed the join (by returning MOD_RES_ALLOW), + // then this entire section is skipped + if (MOD_RESULT == MOD_RES_PASSTHRU) { - std::string ckey = Ptr->GetModeParameter('k'); - bool invited = IS_LOCAL(user)->IsInvited(Ptr->name.c_str()); + std::string ckey = chan->GetModeParameter(keymode); + bool invited = user->IsInvited(chan); bool can_bypass = ServerInstance->Config->InvBypassModes && invited; if (!ckey.empty()) { - FIRST_MOD_RESULT(OnCheckKey, MOD_RESULT, (user, Ptr, key ? key : "")); - if (!MOD_RESULT.check((key && ckey == key) || can_bypass)) + FIRST_MOD_RESULT(OnCheckKey, MOD_RESULT, (user, chan, key)); + if (!MOD_RESULT.check((ckey == key) || can_bypass)) { // If no key provided, or key is not the right one, and can't bypass +k (not invited or option not enabled) - user->WriteNumeric(ERR_BADCHANNELKEY, "%s %s :Cannot join channel (Incorrect channel key)",user->nick.c_str(), Ptr->name.c_str()); + user->WriteNumeric(ERR_BADCHANNELKEY, "%s %s :Cannot join channel (Incorrect channel key)",user->nick.c_str(), chan->name.c_str()); return NULL; } } - if (Ptr->IsModeSet('i')) + if (chan->IsModeSet(inviteonlymode)) { - FIRST_MOD_RESULT(OnCheckInvite, MOD_RESULT, (user, Ptr)); + FIRST_MOD_RESULT(OnCheckInvite, MOD_RESULT, (user, chan)); if (!MOD_RESULT.check(invited)) { - user->WriteNumeric(ERR_INVITEONLYCHAN, "%s %s :Cannot join channel (Invite only)",user->nick.c_str(), Ptr->name.c_str()); + user->WriteNumeric(ERR_INVITEONLYCHAN, "%s %s :Cannot join channel (Invite only)",user->nick.c_str(), chan->name.c_str()); return NULL; } } - std::string limit = Ptr->GetModeParameter('l'); + std::string limit = chan->GetModeParameter(limitmode); if (!limit.empty()) { - FIRST_MOD_RESULT(OnCheckLimit, MOD_RESULT, (user, Ptr)); - if (!MOD_RESULT.check((Ptr->GetUserCounter() < atol(limit.c_str()) || can_bypass))) + FIRST_MOD_RESULT(OnCheckLimit, MOD_RESULT, (user, chan)); + if (!MOD_RESULT.check((chan->GetUserCounter() < atol(limit.c_str()) || can_bypass))) { - user->WriteNumeric(ERR_CHANNELISFULL, "%s %s :Cannot join channel (Channel is full)",user->nick.c_str(), Ptr->name.c_str()); + user->WriteNumeric(ERR_CHANNELISFULL, "%s %s :Cannot join channel (Channel is full)",user->nick.c_str(), chan->name.c_str()); return NULL; } } - if (Ptr->IsBanned(user) && !can_bypass) + if (chan->IsBanned(user) && !can_bypass) { - user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s %s :Cannot join channel (You're banned)",user->nick.c_str(), Ptr->name.c_str()); + user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s %s :Cannot join channel (You're banned)",user->nick.c_str(), chan->name.c_str()); return NULL; } @@ -360,67 +307,77 @@ Channel* Channel::JoinUser(User *user, const char* cn, bool override, const char */ if (invited) { - IS_LOCAL(user)->RemoveInvite(Ptr->name.c_str()); + user->RemoveInvite(chan); } } } } - if (created_by_local) - { - /* As spotted by jilles, dont bother to set this on remote users */ - Ptr->SetDefaultModes(); - } - - return Channel::ForceChan(Ptr, user, privs, bursting, created_by_local); + // We figured that this join is allowed and also created the + // channel if it didn't exist before, now do the actual join + chan->ForceJoin(user, &privs, false, created_by_local); + return chan; } -Channel* Channel::ForceChan(Channel* Ptr, User* user, const std::string &privs, bool bursting, bool created) +void Channel::ForceJoin(User* user, const std::string* privs, bool bursting, bool created_by_local) { - std::string nick = user->nick; + if (IS_SERVER(user)) + { + ServerInstance->Logs->Log("CHANNELS", LOG_DEBUG, "Attempted to join server user " + user->uuid + " to channel " + this->name); + return; + } - Membership* memb = Ptr->AddUser(user); - user->chans.insert(Ptr); + Membership* memb = this->AddUser(user); + if (!memb) + return; // Already on the channel - for (std::string::const_iterator x = privs.begin(); x != privs.end(); x++) + user->chans.insert(this); + + if (privs) { - const char status = *x; - ModeHandler* mh = ServerInstance->Modes->FindMode(status, MODETYPE_CHANNEL); - if (mh) + // If the user was granted prefix modes (in the OnUserPreJoin hook, or he's a + // remote user and his own server set the modes), then set them internally now + for (std::string::const_iterator i = privs->begin(); i != privs->end(); ++i) { - /* Set, and make sure that the mode handler knows this mode was now set */ - Ptr->SetPrefix(user, mh->GetModeChar(), true); - mh->OnModeChange(ServerInstance->FakeClient, ServerInstance->FakeClient, Ptr, nick, true); + ModeHandler* mh = ServerInstance->Modes->FindMode(*i, MODETYPE_CHANNEL); + if (mh && mh->GetPrefixRank()) + { + std::string nick = user->nick; + /* Set, and make sure that the mode handler knows this mode was now set */ + this->SetPrefix(user, mh->GetModeChar(), true); + mh->OnModeChange(ServerInstance->FakeClient, ServerInstance->FakeClient, this, nick, true); + } } } + // Tell modules about this join, they have the chance now to populate except_list with users we won't send the JOIN (and possibly MODE) to CUList except_list; - FOREACH_MOD(I_OnUserJoin,OnUserJoin(memb, bursting, created, except_list)); + FOREACH_MOD(OnUserJoin, (memb, bursting, created_by_local, except_list)); - Ptr->WriteAllExcept(user, false, 0, except_list, "JOIN :%s", Ptr->name.c_str()); + this->WriteAllExcept(user, false, 0, except_list, "JOIN :%s", this->name.c_str()); /* Theyre not the first ones in here, make sure everyone else sees the modes we gave the user */ - if ((Ptr->GetUserCounter() > 1) && (!memb->modes.empty())) + if ((GetUserCounter() > 1) && (!memb->modes.empty())) { std::string ms = memb->modes; for(unsigned int i=0; i < memb->modes.length(); i++) ms.append(" ").append(user->nick); except_list.insert(user); - Ptr->WriteAllExcept(user, !ServerInstance->Config->CycleHostsFromUser, 0, except_list, "MODE %s +%s", Ptr->name.c_str(), ms.c_str()); + this->WriteAllExcept(user, !ServerInstance->Config->CycleHostsFromUser, 0, except_list, "MODE %s +%s", this->name.c_str(), ms.c_str()); } if (IS_LOCAL(user)) { - if (Ptr->topicset) + if (this->topicset) { - user->WriteNumeric(RPL_TOPIC, "%s %s :%s", user->nick.c_str(), Ptr->name.c_str(), Ptr->topic.c_str()); - user->WriteNumeric(RPL_TOPICTIME, "%s %s %s %lu", user->nick.c_str(), Ptr->name.c_str(), Ptr->setby.c_str(), (unsigned long)Ptr->topicset); + user->WriteNumeric(RPL_TOPIC, "%s %s :%s", user->nick.c_str(), this->name.c_str(), this->topic.c_str()); + user->WriteNumeric(RPL_TOPICTIME, "%s %s %s %lu", user->nick.c_str(), this->name.c_str(), this->setby.c_str(), (unsigned long)this->topicset); } - Ptr->UserList(user); + this->UserList(user); } - FOREACH_MOD(I_OnPostJoin,OnPostJoin(memb)); - return Ptr; + + FOREACH_MOD(OnPostJoin, (memb)); } bool Channel::IsBanned(User* user) @@ -431,10 +388,15 @@ bool Channel::IsBanned(User* user) if (result != MOD_RES_PASSTHRU) return (result == MOD_RES_DENY); - for (BanList::iterator i = this->bans.begin(); i != this->bans.end(); i++) + ListModeBase* banlm = static_cast<ListModeBase*>(*ban); + const ListModeBase::ModeList* bans = banlm->GetList(this); + if (bans) { - if (CheckBan(user, i->data)) - return true; + for (ListModeBase::ModeList::const_iterator it = bans->begin(); it != bans->end(); it++) + { + if (CheckBan(user, it->mask)) + return true; + } } return false; } @@ -454,10 +416,9 @@ bool Channel::CheckBan(User* user, const std::string& mask) if (at == std::string::npos) return false; - char tomatch[MAXBUF]; - snprintf(tomatch, MAXBUF, "%s!%s", user->nick.c_str(), user->ident.c_str()); + const std::string nickIdent = user->nick + "!" + user->ident; std::string prefix = mask.substr(0, at); - if (InspIRCd::Match(tomatch, prefix, NULL)) + if (InspIRCd::Match(nickIdent, prefix, NULL)) { std::string suffix = mask.substr(at + 1); if (InspIRCd::Match(user->host, suffix, NULL) || @@ -474,12 +435,15 @@ ModResult Channel::GetExtBanStatus(User *user, char type) FIRST_MOD_RESULT(OnExtBanCheck, rv, (user, this, type)); if (rv != MOD_RES_PASSTHRU) return rv; - for (BanList::iterator i = this->bans.begin(); i != this->bans.end(); i++) + + ListModeBase* banlm = static_cast<ListModeBase*>(*ban); + const ListModeBase::ModeList* bans = banlm->GetList(this); + if (bans) + { - if (i->data[0] == type && i->data[1] == ':') + for (ListModeBase::ModeList::const_iterator it = bans->begin(); it != bans->end(); ++it) { - std::string val = i->data.substr(2); - if (CheckBan(user, val)) + if (CheckBan(user, it->mask)) return MOD_RES_DENY; } } @@ -487,61 +451,54 @@ ModResult Channel::GetExtBanStatus(User *user, char type) } /* Channel::PartUser - * remove a channel from a users record, and return the number of users left. - * Therefore, if this function returns 0 the caller should delete the Channel. + * Remove a channel from a users record, remove the reference to the Membership object + * from the channel and destroy it. */ void Channel::PartUser(User *user, std::string &reason) { - if (!user) - return; + UserMembIter membiter = userlist.find(user); - Membership* memb = GetUser(user); - - if (memb) + if (membiter != userlist.end()) { + Membership* memb = membiter->second; CUList except_list; - FOREACH_MOD(I_OnUserPart,OnUserPart(memb, reason, except_list)); + FOREACH_MOD(OnUserPart, (memb, reason, except_list)); WriteAllExcept(user, false, 0, except_list, "PART %s%s%s", this->name.c_str(), reason.empty() ? "" : " :", reason.c_str()); + // Remove this channel from the user's chanlist user->chans.erase(this); - this->RemoveAllPrefixes(user); + // Remove the Membership from this channel's userlist and destroy it + this->DelUser(membiter); } - - this->DelUser(user); } -void Channel::KickUser(User *src, User *user, const char* reason) +void Channel::KickUser(User* src, User* victim, const std::string& reason, Membership* srcmemb) { - if (!src || !user || !reason) + UserMembIter victimiter = userlist.find(victim); + Membership* memb = ((victimiter != userlist.end()) ? victimiter->second : NULL); + + if (!memb) + { + src->WriteNumeric(ERR_USERNOTINCHANNEL, "%s %s %s :They are not on that channel",src->nick.c_str(), victim->nick.c_str(), this->name.c_str()); return; + } - Membership* memb = GetUser(user); + // Do the following checks only if the KICK is done by a local user; + // each server enforces its own rules. if (IS_LOCAL(src)) { - if (!memb) - { - src->WriteNumeric(ERR_USERNOTINCHANNEL, "%s %s %s :They are not on that channel",src->nick.c_str(), user->nick.c_str(), this->name.c_str()); - return; - } - if ((ServerInstance->ULine(user->server)) && (!ServerInstance->ULine(src->server))) - { - src->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only a u-line may kick a u-line from a channel.",src->nick.c_str(), this->name.c_str()); - return; - } - + // Modules are allowed to explicitly allow or deny kicks done by local users ModResult res; - if (ServerInstance->ULine(src->server)) - res = MOD_RES_ALLOW; - else - FIRST_MOD_RESULT(OnUserPreKick, res, (src,memb,reason)); - + FIRST_MOD_RESULT(OnUserPreKick, res, (src,memb,reason)); if (res == MOD_RES_DENY) return; if (res == MOD_RES_PASSTHRU) { - unsigned int them = this->GetPrefixValue(src); + if (!srcmemb) + srcmemb = GetUser(src); + unsigned int them = srcmemb ? srcmemb->getRank() : 0; unsigned int req = HALFOP_VALUE; for (std::string::size_type i = 0; i < memb->modes.length(); i++) { @@ -559,78 +516,48 @@ void Channel::KickUser(User *src, User *user, const char* reason) } } - if (memb) - { - CUList except_list; - FOREACH_MOD(I_OnUserKick,OnUserKick(src, memb, reason, except_list)); - - WriteAllExcept(src, false, 0, except_list, "KICK %s %s :%s", name.c_str(), user->nick.c_str(), reason); + CUList except_list; + FOREACH_MOD(OnUserKick, (src, memb, reason, except_list)); - user->chans.erase(this); - this->RemoveAllPrefixes(user); - } + WriteAllExcept(src, false, 0, except_list, "KICK %s %s :%s", name.c_str(), victim->nick.c_str(), reason.c_str()); - this->DelUser(user); + victim->chans.erase(this); + this->DelUser(victimiter); } void Channel::WriteChannel(User* user, const char* text, ...) { - char textbuffer[MAXBUF]; - va_list argsPtr; - - if (!user || !text) - return; - - va_start(argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - this->WriteChannel(user, std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + this->WriteChannel(user, textbuffer); } void Channel::WriteChannel(User* user, const std::string &text) { - char tb[MAXBUF]; - - if (!user) - return; - - snprintf(tb,MAXBUF,":%s %s", user->GetFullHost().c_str(), text.c_str()); - std::string out = tb; + const std::string message = ":" + user->GetFullHost() + " " + text; for (UserMembIter i = userlist.begin(); i != userlist.end(); i++) { if (IS_LOCAL(i->first)) - i->first->Write(out); + i->first->Write(message); } } void Channel::WriteChannelWithServ(const std::string& ServName, const char* text, ...) { - char textbuffer[MAXBUF]; - va_list argsPtr; - - if (!text) - return; - - va_start(argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - this->WriteChannelWithServ(ServName, std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + this->WriteChannelWithServ(ServName, textbuffer); } void Channel::WriteChannelWithServ(const std::string& ServName, const std::string &text) { - char tb[MAXBUF]; - - snprintf(tb,MAXBUF,":%s %s", ServName.empty() ? ServerInstance->Config->ServerName.c_str() : ServName.c_str(), text.c_str()); - std::string out = tb; + const std::string message = ":" + (ServName.empty() ? ServerInstance->Config->ServerName : ServName) + " " + text; for (UserMembIter i = userlist.begin(); i != userlist.end(); i++) { if (IS_LOCAL(i->first)) - i->first->Write(out); + i->first->Write(message); } } @@ -638,43 +565,23 @@ void Channel::WriteChannelWithServ(const std::string& ServName, const std::strin * for the sender (for privmsg etc) */ void Channel::WriteAllExceptSender(User* user, bool serversource, char status, const char* text, ...) { - char textbuffer[MAXBUF]; - va_list argsPtr; - - if (!text) - return; - - va_start(argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - this->WriteAllExceptSender(user, serversource, status, std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + this->WriteAllExceptSender(user, serversource, status, textbuffer); } void Channel::WriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const char* text, ...) { - char textbuffer[MAXBUF]; - va_list argsPtr; - - if (!text) - return; - - int offset = snprintf(textbuffer,MAXBUF,":%s ", serversource ? ServerInstance->Config->ServerName.c_str() : user->GetFullHost().c_str()); - - va_start(argsPtr, text); - vsnprintf(textbuffer + offset, MAXBUF - offset, text, argsPtr); - va_end(argsPtr); - - this->RawWriteAllExcept(user, serversource, status, except_list, std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + textbuffer = ":" + (serversource ? ServerInstance->Config->ServerName : user->GetFullHost()) + " " + textbuffer; + this->RawWriteAllExcept(user, serversource, status, except_list, textbuffer); } void Channel::WriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const std::string &text) { - char tb[MAXBUF]; - - snprintf(tb,MAXBUF,":%s %s", serversource ? ServerInstance->Config->ServerName.c_str() : user->GetFullHost().c_str(), text.c_str()); - - this->RawWriteAllExcept(user, serversource, status, except_list, std::string(tb)); + const std::string message = ":" + (serversource ? ServerInstance->Config->ServerName : user->GetFullHost()) + " " + text; + this->RawWriteAllExcept(user, serversource, status, except_list, message); } void Channel::RawWriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const std::string &out) @@ -706,59 +613,41 @@ void Channel::WriteAllExceptSender(User* user, bool serversource, char status, c this->WriteAllExcept(user, serversource, status, except_list, std::string(text)); } -/* - * return a count of the users on a specific channel accounting for - * invisible users who won't increase the count. e.g. for /LIST - */ -int Channel::CountInvisible() +const char* Channel::ChanModes(bool showkey) { - int count = 0; - for (UserMembIter i = userlist.begin(); i != userlist.end(); i++) - { - if (!i->first->quitting && !i->first->IsModeSet('i')) - count++; - } + static std::string scratch; + std::string sparam; - return count; -} - -char* Channel::ChanModes(bool showkey) -{ - static char scratch[MAXBUF]; - static char sparam[MAXBUF]; - char* offset = scratch; - std::string extparam; - - *scratch = '\0'; - *sparam = '\0'; + scratch.clear(); /* This was still iterating up to 190, Channel::modes is only 64 elements -- Om */ for(int n = 0; n < 64; n++) { if(this->modes[n]) { - *offset++ = n + 65; - extparam.clear(); + scratch.push_back(n + 65); + ModeHandler* mh = ServerInstance->Modes->FindMode(n+'A', MODETYPE_CHANNEL); + if (!mh) + continue; + if (n == 'k' - 65 && !showkey) { - extparam = "<key>"; + sparam += " <key>"; } else { - extparam = this->GetModeParameter(n + 65); - } - if (!extparam.empty()) - { - charlcat(sparam,' ',MAXBUF); - strlcat(sparam,extparam.c_str(),MAXBUF); + const std::string param = this->GetModeParameter(mh); + if (!param.empty()) + { + sparam += ' '; + sparam += param; + } } } } - /* Null terminate scratch */ - *offset = '\0'; - strlcat(scratch,sparam,MAXBUF); - return scratch; + scratch += sparam; + return scratch.c_str(); } /* compile a userlist of a channel into a string, each nick seperated by @@ -766,33 +655,33 @@ char* Channel::ChanModes(bool showkey) */ void Channel::UserList(User *user) { - char list[MAXBUF]; - size_t dlen, curlen; - - if (!IS_LOCAL(user)) - return; - - if (this->IsModeSet('s') && !this->HasUser(user) && !user->HasPrivPermission("channels/auspex")) + if (this->IsModeSet(secretmode) && !this->HasUser(user) && !user->HasPrivPermission("channels/auspex")) { user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), this->name.c_str()); return; } - dlen = curlen = snprintf(list,MAXBUF,"%s %c %s :", user->nick.c_str(), this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=', this->name.c_str()); + std::string list = user->nick; + list.push_back(' '); + list.push_back(this->IsModeSet(secretmode) ? '@' : this->IsModeSet(privatemode) ? '*' : '='); + list.push_back(' '); + list.append(this->name).append(" :"); + std::string::size_type pos = list.size(); - int numusers = 0; - char* ptr = list + dlen; + bool has_one = false; /* Improvement by Brain - this doesnt change in value, so why was it inside * the loop? */ bool has_user = this->HasUser(user); - for (UserMembIter i = userlist.begin(); i != userlist.end(); i++) + std::string prefixlist; + std::string nick; + for (UserMembIter i = userlist.begin(); i != userlist.end(); ++i) { if (i->first->quitting) continue; - if ((!has_user) && (i->first->IsModeSet('i'))) + if ((!has_user) && (i->first->IsModeSet(invisiblemode))) { /* * user is +i, and source not on the channel, does not show @@ -801,72 +690,39 @@ void Channel::UserList(User *user) continue; } - std::string prefixlist = this->GetPrefixChar(i->first); - std::string nick = i->first->nick; + prefixlist = this->GetPrefixChar(i->first); + nick = i->first->nick; - FOREACH_MOD(I_OnNamesListItem, OnNamesListItem(user, i->second, prefixlist, nick)); + FOREACH_MOD(OnNamesListItem, (user, i->second, prefixlist, nick)); /* Nick was nuked, a module wants us to skip it */ if (nick.empty()) continue; - size_t ptrlen = 0; - - if (curlen + prefixlist.length() + nick.length() + 1 > 480) + if (list.size() + prefixlist.length() + nick.length() + 1 > 480) { /* list overflowed into multiple numerics */ - user->WriteNumeric(RPL_NAMREPLY, std::string(list)); - - /* reset our lengths */ - dlen = curlen = snprintf(list,MAXBUF,"%s %c %s :", user->nick.c_str(), this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=', this->name.c_str()); - ptr = list + dlen; + user->WriteNumeric(RPL_NAMREPLY, list); - numusers = 0; + // Erase all nicks, keep the constant part + list.erase(pos); + has_one = false; } - ptrlen = snprintf(ptr, MAXBUF, "%s%s ", prefixlist.c_str(), nick.c_str()); - - curlen += ptrlen; - ptr += ptrlen; + list.append(prefixlist).append(nick).push_back(' '); - numusers++; + has_one = true; } /* if whats left in the list isnt empty, send it */ - if (numusers) + if (has_one) { - user->WriteNumeric(RPL_NAMREPLY, std::string(list)); + user->WriteNumeric(RPL_NAMREPLY, list); } user->WriteNumeric(RPL_ENDOFNAMES, "%s %s :End of /NAMES list.", user->nick.c_str(), this->name.c_str()); } -long Channel::GetMaxBans() -{ - /* Return the cached value if there is one */ - if (this->maxbans) - return this->maxbans; - - /* If there isnt one, we have to do some O(n) hax to find it the first time. (ick) */ - for (std::map<std::string,int>::iterator n = ServerInstance->Config->maxbans.begin(); n != ServerInstance->Config->maxbans.end(); n++) - { - if (InspIRCd::Match(this->name, n->first, NULL)) - { - this->maxbans = n->second; - return n->second; - } - } - - /* Screw it, just return the default of 64 */ - this->maxbans = 64; - return this->maxbans; -} - -void Channel::ResetMaxBans() -{ - this->maxbans = 0; -} - /* returns the status character for a given user on a channel, e.g. @ for op, * % for halfop etc. If the user has several modes set, the highest mode * the user has must be returned. @@ -962,22 +818,13 @@ bool Channel::SetPrefix(User* user, char prefix, bool adding) return adding; } -void Channel::RemoveAllPrefixes(User* user) -{ - UserMembIter m = userlist.find(user); - if (m != userlist.end()) - { - m->second->modes.clear(); - } -} - void Invitation::Create(Channel* c, LocalUser* u, time_t timeout) { if ((timeout != 0) && (ServerInstance->Time() >= timeout)) // Expired, don't bother return; - ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Create chan=%s user=%s", c->name.c_str(), u->uuid.c_str()); + ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Create chan=%s user=%s", c->name.c_str(), u->uuid.c_str()); Invitation* inv = Invitation::Find(c, u, false); if (inv) @@ -985,20 +832,20 @@ void Invitation::Create(Channel* c, LocalUser* u, time_t timeout) if ((inv->expiry == 0) || (inv->expiry > timeout)) return; inv->expiry = timeout; - ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Create changed expiry in existing invitation %p", (void*) inv); + ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Create changed expiry in existing invitation %p", (void*) inv); } else { inv = new Invitation(c, u, timeout); c->invites.push_back(inv); u->invites.push_back(inv); - ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Create created new invitation %p", (void*) inv); + ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Create created new invitation %p", (void*) inv); } } Invitation* Invitation::Find(Channel* c, LocalUser* u, bool check_expired) { - ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Find chan=%s user=%s check_expired=%d", c ? c->name.c_str() : "NULL", u ? u->uuid.c_str() : "NULL", check_expired); + ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Find chan=%s user=%s check_expired=%d", c ? c->name.c_str() : "NULL", u ? u->uuid.c_str() : "NULL", check_expired); if (!u || u->invites.empty()) return NULL; @@ -1013,7 +860,7 @@ Invitation* Invitation::Find(Channel* c, LocalUser* u, bool check_expired) { /* Expired invite, remove it. */ std::string expiration = ServerInstance->TimeString(inv->expiry); - ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Find ecountered expired entry: %p expired %s", (void*) inv, expiration.c_str()); + ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Find ecountered expired entry: %p expired %s", (void*) inv, expiration.c_str()); i = locallist.erase(i); inv->cull(); delete inv; @@ -1031,7 +878,7 @@ Invitation* Invitation::Find(Channel* c, LocalUser* u, bool check_expired) } locallist.swap(u->invites); - ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Find result=%p", (void*) result); + ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Find result=%p", (void*) result); return result; } @@ -1048,7 +895,7 @@ Invitation::~Invitation() void InviteBase::ClearInvites() { - ServerInstance->Logs->Log("INVITEBASE", DEBUG, "InviteBase::ClearInvites %p", (void*) this); + ServerInstance->Logs->Log("INVITEBASE", LOG_DEBUG, "InviteBase::ClearInvites %p", (void*) this); InviteList locallist; locallist.swap(invites); for (InviteList::const_iterator i = locallist.begin(); i != locallist.end(); ++i) diff --git a/src/cidr.cpp b/src/cidr.cpp index 54f7b83e9..f5ecaac5b 100644 --- a/src/cidr.cpp +++ b/src/cidr.cpp @@ -19,8 +19,6 @@ */ -/* $Core */ - #include "inspircd.h" /* Used when comparing CIDR masks for the modulus bits left over. diff --git a/src/command_parse.cpp b/src/command_parse.cpp index b05b34c9b..d1ae98729 100644 --- a/src/command_parse.cpp +++ b/src/command_parse.cpp @@ -44,91 +44,68 @@ int InspIRCd::PassCompare(Extensible* ex, const std::string &data, const std::st return (data != input); // this seems back to front, but returns 0 if they *match*, 1 else } -/* LoopCall is used to call a command classes handler repeatedly based on the contents of a comma seperated list. - * There are two overriden versions of this method, one of which takes two potential lists and the other takes one. - * We need a version which takes two potential lists for JOIN, because a JOIN may contain two lists of items at once, - * the channel names and their keys as follows: - * JOIN #chan1,#chan2,#chan3 key1,,key3 - * Therefore, we need to deal with both lists concurrently. The first instance of this method does that by creating - * two instances of irc::commasepstream and reading them both together until the first runs out of tokens. - * The second version is much simpler and just has the one stream to read, and is used in NAMES, WHOIS, PRIVMSG etc. - * Both will only parse until they reach ServerInstance->Config->MaxTargets number of targets, to stop abuse via spam. - */ -int CommandParser::LoopCall(User* user, Command* CommandObj, const std::vector<std::string>& parameters, unsigned int splithere, int extra, bool usemax) +bool CommandParser::LoopCall(User* user, Command* handler, const std::vector<std::string>& parameters, unsigned int splithere, int extra, bool usemax) { if (splithere >= parameters.size()) - return 0; - - if (extra >= (signed)parameters.size()) - extra = -1; + return false; - /* First check if we have more than one item in the list, if we don't we return zero here and the handler + /* First check if we have more than one item in the list, if we don't we return false here and the handler * which called us just carries on as it was. */ if (parameters[splithere].find(',') == std::string::npos) - return 0; + return false; /** Some lame ircds will weed out dupes using some shitty O(n^2) algorithm. * By using std::set (thanks for the idea w00t) we can cut this down a ton. * ...VOOODOOOO! + * + * Only check for duplicates if there is one list (allow them in JOIN). */ std::set<irc::string> dupes; + bool check_dupes = (extra < 0); - /* Create two lists, one for channel names, one for keys + /* Create two sepstreams, if we have only one list, then initialize the second sepstream with + * an empty string. The second parameter of the constructor of the sepstream tells whether + * or not to allow empty tokens. + * We allow empty keys, so "JOIN #a,#b ,bkey" will be interpreted as "JOIN #a", "JOIN #b bkey" */ irc::commasepstream items1(parameters[splithere]); - irc::commasepstream items2(extra >= 0 ? parameters[extra] : ""); - std::string extrastuff; + irc::commasepstream items2(extra >= 0 ? parameters[extra] : "", true); std::string item; unsigned int max = 0; + LocalUser* localuser = IS_LOCAL(user); - /* Attempt to iterate these lists and call the command objech - * which called us, for every parameter pair until there are - * no more left to parse. + /* Attempt to iterate these lists and call the command handler + * for every parameter or parameter pair until there are no more + * left to parse. */ while (items1.GetToken(item) && (!usemax || max++ < ServerInstance->Config->MaxTargets)) { - if (dupes.find(item.c_str()) == dupes.end()) + if ((!check_dupes) || (dupes.insert(item.c_str()).second)) { std::vector<std::string> new_parameters(parameters); - - if (!items2.GetToken(extrastuff)) - extrastuff.clear(); - new_parameters[splithere] = item; - if (extra >= 0) - new_parameters[extra] = extrastuff; - CommandObj->Handle(new_parameters, user); - - dupes.insert(item.c_str()); - } - } - return 1; -} - -bool CommandParser::IsValidCommand(const std::string &commandname, unsigned int pcnt, User * user) -{ - Commandtable::iterator n = cmdlist.find(commandname); - - if (n != cmdlist.end()) - { - if ((pcnt >= n->second->min_params)) - { - if (IS_LOCAL(user) && n->second->flags_needed) + if (extra >= 0) { - if (user->IsModeSet(n->second->flags_needed)) - { - return (user->HasPermission(commandname)); - } + // If we have two lists then get the next item from the second list. + // In case it runs out of elements then 'item' will be an empty string. + items2.GetToken(item); + new_parameters[extra] = item; } - else + + CmdResult result = handler->Handle(new_parameters, user); + if (localuser) { - return true; + // Run the OnPostCommand hook with the last parameter (original line) being empty + // to indicate that the command had more targets in its original form. + item.clear(); + FOREACH_MOD(OnPostCommand, (handler, new_parameters, localuser, result, item)); } } } - return false; + + return true; } Command* CommandParser::GetHandler(const std::string &commandname) @@ -181,7 +158,7 @@ CmdResult CommandParser::CallHandler(const std::string &commandname, const std:: return CMD_INVALID; } -bool CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) +void CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) { std::vector<std::string> command_p; irc::tokenstream tokens(cmd); @@ -196,29 +173,27 @@ bool CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) if (command[0] == ':') tokens.GetToken(command); - while (tokens.GetToken(token) && (command_p.size() <= MAXPARAMETERS)) + while (tokens.GetToken(token)) command_p.push_back(token); std::transform(command.begin(), command.end(), command.begin(), ::toupper); /* find the command, check it exists */ - Commandtable::iterator cm = cmdlist.find(command); + Command* handler = GetHandler(command); /* Modify the user's penalty regardless of whether or not the command exists */ - bool do_more = true; if (!user->HasPrivPermission("users/flood/no-throttle")) { // If it *doesn't* exist, give it a slightly heftier penalty than normal to deter flooding us crap - user->CommandFloodPenalty += cm != cmdlist.end() ? cm->second->Penalty * 1000 : 2000; + user->CommandFloodPenalty += handler ? handler->Penalty * 1000 : 2000; } - - if (cm == cmdlist.end()) + if (!handler) { ModResult MOD_RESULT; FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, command_p, user, false, cmd)); if (MOD_RESULT == MOD_RES_DENY) - return true; + return; /* * This double lookup is in case a module (abbreviation) wishes to change a command. @@ -227,17 +202,19 @@ bool CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) * Thanks dz for making me actually understand why this is necessary! * -- w00t */ - cm = cmdlist.find(command); - if (cm == cmdlist.end()) + handler = GetHandler(command); + if (!handler) { if (user->registered == REG_ALL) user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s %s :Unknown command",user->nick.c_str(),command.c_str()); ServerInstance->stats->statsUnknown++; - return true; + return; } } - if (cm->second->max_params && command_p.size() > cm->second->max_params) + // If we were given more parameters than max_params then append the excess parameter(s) + // to command_p[maxparams-1], i.e. to the last param that is still allowed + if (handler->max_params && command_p.size() > handler->max_params) { /* * command_p input (assuming max_params 1): @@ -246,32 +223,21 @@ bool CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) * a * test */ - std::string lparam; - /* - * The '-1' here is a clever trick, we'll go backwards throwing everything into a temporary param - * and then just toss that into the array. - * -- w00t - */ - while (command_p.size() > (cm->second->max_params - 1)) - { - // BE CAREFUL: .end() returns past the end of the vector, hence decrement. - std::vector<std::string>::iterator it = --command_p.end(); + // Iterator to the last parameter that will be kept + const std::vector<std::string>::iterator lastkeep = command_p.begin() + (handler->max_params - 1); + // Iterator to the first excess parameter + const std::vector<std::string>::iterator firstexcess = lastkeep + 1; - lparam.insert(0, " " + *(it)); - command_p.erase(it); // remove last element + // Append all excess parameter(s) to the last parameter, seperated by spaces + for (std::vector<std::string>::const_iterator i = firstexcess; i != command_p.end(); ++i) + { + lastkeep->push_back(' '); + lastkeep->append(*i); } - /* we now have (each iteration): - * ' test' - * ' a test' - * ' is a test' <-- final string - * ...now remove the ' ' at the start... - */ - lparam.erase(lparam.begin()); - - /* param is now 'is a test', which is exactly what we wanted! */ - command_p.push_back(lparam); + // Erase the excess parameter(s) + command_p.erase(firstexcess, command_p.end()); } /* @@ -281,26 +247,28 @@ bool CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) ModResult MOD_RESULT; FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, command_p, user, false, cmd)); if (MOD_RESULT == MOD_RES_DENY) - return true; + return; /* activity resets the ping pending timer */ user->nping = ServerInstance->Time() + user->MyClass->GetPingTime(); - if (cm->second->flags_needed) + if (handler->flags_needed) { - if (!user->IsModeSet(cm->second->flags_needed)) + if (!user->IsModeSet(handler->flags_needed)) { user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - You do not have the required operator privileges",user->nick.c_str()); - return do_more; + return; } + if (!user->HasPermission(command)) { user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to command %s", - user->nick.c_str(), user->oper->NameStr(), command.c_str()); - return do_more; + user->nick.c_str(), user->oper->name.c_str(), command.c_str()); + return; } } - if ((user->registered == REG_ALL) && (!IS_OPER(user)) && (cm->second->IsDisabled())) + + if ((user->registered == REG_ALL) && (!user->IsOper()) && (handler->IsDisabled())) { /* command is disabled! */ if (ServerInstance->Config->DisabledDontExist) @@ -315,42 +283,40 @@ bool CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) ServerInstance->SNO->WriteToSnoMask('t', "%s denied for %s (%s@%s)", command.c_str(), user->nick.c_str(), user->ident.c_str(), user->host.c_str()); - return do_more; + return; } - if ((!command_p.empty()) && (command_p.back().empty()) && (!cm->second->allow_empty_last_param)) + if ((!command_p.empty()) && (command_p.back().empty()) && (!handler->allow_empty_last_param)) command_p.pop_back(); - if (command_p.size() < cm->second->min_params) + if (command_p.size() < handler->min_params) { user->WriteNumeric(ERR_NEEDMOREPARAMS, "%s %s :Not enough parameters.", user->nick.c_str(), command.c_str()); - if ((ServerInstance->Config->SyntaxHints) && (user->registered == REG_ALL) && (cm->second->syntax.length())) - user->WriteNumeric(RPL_SYNTAX, "%s :SYNTAX %s %s", user->nick.c_str(), cm->second->name.c_str(), cm->second->syntax.c_str()); - return do_more; + if ((ServerInstance->Config->SyntaxHints) && (user->registered == REG_ALL) && (handler->syntax.length())) + user->WriteNumeric(RPL_SYNTAX, "%s :SYNTAX %s %s", user->nick.c_str(), handler->name.c_str(), handler->syntax.c_str()); + return; } - if ((user->registered != REG_ALL) && (!cm->second->WorksBeforeReg())) + + if ((user->registered != REG_ALL) && (!handler->WorksBeforeReg())) { user->WriteNumeric(ERR_NOTREGISTERED, "%s :You have not registered",command.c_str()); - return do_more; } else { /* passed all checks.. first, do the (ugly) stats counters. */ - cm->second->use_count++; - cm->second->total_bytes += cmd.length(); + handler->use_count++; /* module calls too */ FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, command_p, user, true, cmd)); if (MOD_RESULT == MOD_RES_DENY) - return do_more; + return; /* * WARNING: be careful, the user may be deleted soon */ - CmdResult result = cm->second->Handle(command_p, user); + CmdResult result = handler->Handle(command_p, user); - FOREACH_MOD(I_OnPostCommand,OnPostCommand(command, command_p, user, result,cmd)); - return do_more; + FOREACH_MOD(OnPostCommand, (handler, command_p, user, result, cmd)); } } @@ -361,19 +327,23 @@ void CommandParser::RemoveCommand(Command* x) cmdlist.erase(n); } +CommandBase::~CommandBase() +{ +} + Command::~Command() { ServerInstance->Parser->RemoveCommand(this); } -bool CommandParser::ProcessBuffer(std::string &buffer,LocalUser *user) +void CommandParser::ProcessBuffer(std::string &buffer,LocalUser *user) { if (!user || buffer.empty()) - return true; + return; - ServerInstance->Logs->Log("USERINPUT", RAWIO, "C[%s] I :%s %s", + ServerInstance->Logs->Log("USERINPUT", LOG_RAWIO, "C[%s] I :%s %s", user->uuid.c_str(), user->nick.c_str(), buffer.c_str()); - return ProcessCommand(user,buffer); + ProcessCommand(user,buffer); } bool CommandParser::AddCommand(Command *f) @@ -391,88 +361,64 @@ CommandParser::CommandParser() { } -int CommandParser::TranslateUIDs(const std::vector<TranslateType> to, const std::vector<std::string> &source, std::string &dest, bool prefix_final, Command* custom_translator) +std::string CommandParser::TranslateUIDs(const std::vector<TranslateType>& to, const std::vector<std::string>& source, bool prefix_final, CommandBase* custom_translator) { std::vector<TranslateType>::const_iterator types = to.begin(); - User* user = NULL; - unsigned int i; - int translations = 0; - dest.clear(); + std::string dest; - for(i=0; i < source.size(); i++) + for (unsigned int i = 0; i < source.size(); i++) { - TranslateType t; - std::string item = source[i]; - - if (types == to.end()) - t = TR_TEXT; - else + TranslateType t = TR_TEXT; + // They might supply less translation types than parameters, + // in that case pretend that all remaining types are TR_TEXT + if (types != to.end()) { t = *types; types++; } - if (prefix_final && i == source.size() - 1) - dest.append(":"); + bool last = (i == (source.size() - 1)); + if (prefix_final && last) + dest.push_back(':'); - switch (t) - { - case TR_NICK: - /* Translate single nickname */ - user = ServerInstance->FindNick(item); - if (user) - { - dest.append(user->uuid); - translations++; - } - else - dest.append(item); - break; - case TR_CUSTOM: - if (custom_translator) - custom_translator->EncodeParameter(item, i); - dest.append(item); - break; - case TR_END: - case TR_TEXT: - default: - /* Do nothing */ - dest.append(item); - break; - } - if (i != source.size() - 1) - dest.append(" "); + TranslateSingleParam(t, source[i], dest, custom_translator, i); + + if (!last) + dest.push_back(' '); } - return translations; + return dest; } -int CommandParser::TranslateUIDs(TranslateType to, const std::string &source, std::string &dest) +void CommandParser::TranslateSingleParam(TranslateType to, const std::string& item, std::string& dest, CommandBase* custom_translator, unsigned int paramnumber) { - User* user = NULL; - int translations = 0; - dest.clear(); - switch (to) { case TR_NICK: + { /* Translate single nickname */ - user = ServerInstance->FindNick(source); + User* user = ServerInstance->FindNick(item); if (user) + dest.append(user->uuid); + else + dest.append(item); + break; + } + case TR_CUSTOM: + { + if (custom_translator) { - dest = user->uuid; - translations++; + std::string translated = item; + custom_translator->EncodeParameter(translated, paramnumber); + dest.append(translated); + break; } - else - dest = source; - break; - case TR_END: + // If no custom translator was given, fall through + } case TR_TEXT: default: /* Do nothing */ - dest = source; + dest.append(item); break; } - - return translations; } diff --git a/src/commands.cpp b/src/commands.cpp index d805a1f65..f62f00340 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -21,8 +21,6 @@ */ -/* $Core */ - #include "inspircd.h" #include "xline.h" #include "command_parse.h" @@ -127,7 +125,7 @@ CmdResult SplitCommand::Handle(const std::vector<std::string>& parms, User* u) return HandleRemote(parms, IS_REMOTE(u)); if (IS_SERVER(u)) return HandleServer(parms, IS_SERVER(u)); - ServerInstance->Logs->Log("COMMAND", DEFAULT, "Unknown user type in command (uuid=%s)!", u->uuid.c_str()); + ServerInstance->Logs->Log("COMMAND", LOG_DEFAULT, "Unknown user type in command (uuid=%s)!", u->uuid.c_str()); return CMD_INVALID; } diff --git a/src/commands/cmd_away.cpp b/src/commands/cmd_away.cpp index fa3f7fae9..de0969af4 100644 --- a/src/commands/cmd_away.cpp +++ b/src/commands/cmd_away.cpp @@ -38,6 +38,10 @@ class CommandAway : public Command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(const std::vector<std::string>& parameters, User *user); + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) + { + return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST); + } }; /** Handle /AWAY diff --git a/src/commands/cmd_clearcache.cpp b/src/commands/cmd_clearcache.cpp deleted file mode 100644 index 5914f9a8f..000000000 --- a/src/commands/cmd_clearcache.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> - * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "inspircd.h" - -/** Handle /CLEARCACHE. These command handlers can be reloaded by the core, - * and handle basic RFC1459 commands. Commands within modules work - * the same way, however, they can be fully unloaded, where these - * may not. - */ -class CommandClearcache : public Command -{ - public: - /** Constructor for clearcache. - */ - CommandClearcache ( Module* parent) : Command(parent,"CLEARCACHE",0) { flags_needed = 'o'; } - /** Handle command. - * @param parameters The parameters to the comamnd - * @param pcnt The number of parameters passed to teh command - * @param user The user issuing the command - * @return A value from CmdResult to indicate command success or failure. - */ - CmdResult Handle(const std::vector<std::string>& parameters, User *user); -}; - -/** Handle /CLEARCACHE - */ -CmdResult CommandClearcache::Handle (const std::vector<std::string>& parameters, User *user) -{ - int n = ServerInstance->Res->ClearCache(); - user->WriteServ("NOTICE %s :*** Cleared DNS cache of %d items.", user->nick.c_str(), n); - return CMD_SUCCESS; -} - -COMMAND_INIT(CommandClearcache) diff --git a/src/commands/cmd_commands.cpp b/src/commands/cmd_commands.cpp index 36408b363..99acdfe96 100644 --- a/src/commands/cmd_commands.cpp +++ b/src/commands/cmd_commands.cpp @@ -53,12 +53,9 @@ CmdResult CommandCommands::Handle (const std::vector<std::string>&, User *user) continue; Module* src = i->second->creator; - char buffer[MAXBUF]; - snprintf(buffer, MAXBUF, ":%s %03d %s :%s %s %d %d", - ServerInstance->Config->ServerName.c_str(), RPL_COMMANDS, user->nick.c_str(), - i->second->name.c_str(), src->ModuleSourceFile.c_str(), - i->second->min_params, i->second->Penalty); - list.push_back(buffer); + list.push_back(InspIRCd::Format(":%s %03d %s :%s %s %d %d", ServerInstance->Config->ServerName.c_str(), + RPL_COMMANDS, user->nick.c_str(), i->second->name.c_str(), src->ModuleSourceFile.c_str(), + i->second->min_params, i->second->Penalty)); } sort(list.begin(), list.end()); for(unsigned int i=0; i < list.size(); i++) diff --git a/src/commands/cmd_die.cpp b/src/commands/cmd_die.cpp index 1d6640213..3ccc037b4 100644 --- a/src/commands/cmd_die.cpp +++ b/src/commands/cmd_die.cpp @@ -50,7 +50,7 @@ CmdResult CommandDie::Handle (const std::vector<std::string>& parameters, User * { { std::string diebuf = "*** DIE command from " + user->GetFullHost() + ". Terminating."; - ServerInstance->Logs->Log("COMMAND",SPARSE, diebuf); + ServerInstance->Logs->Log("COMMAND", LOG_SPARSE, diebuf); ServerInstance->SendError(diebuf); } @@ -58,7 +58,7 @@ CmdResult CommandDie::Handle (const std::vector<std::string>& parameters, User * } else { - ServerInstance->Logs->Log("COMMAND",SPARSE, "Failed /DIE command from %s", user->GetFullRealHost().c_str()); + ServerInstance->Logs->Log("COMMAND", LOG_SPARSE, "Failed /DIE command from %s", user->GetFullRealHost().c_str()); ServerInstance->SNO->WriteGlobalSno('a', "Failed DIE Command from %s.", user->GetFullRealHost().c_str()); return CMD_FAILURE; } diff --git a/src/commands/cmd_dns.cpp b/src/commands/cmd_dns.cpp new file mode 100644 index 000000000..2b7114128 --- /dev/null +++ b/src/commands/cmd_dns.cpp @@ -0,0 +1,842 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Adam <Adam@anope.org> + * Copyright (C) 2003-2013 Anope Team <team@anope.org> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "inspircd.h" +#include "modules/dns.h" +#include <iostream> +#include <fstream> + +#ifdef _WIN32 +#include <Iphlpapi.h> +#pragma comment(lib, "Iphlpapi.lib") +#endif + +using namespace DNS; + +/** A full packet sent or recieved to/from the nameserver + */ +class Packet : public Query +{ + void PackName(unsigned char* output, unsigned short output_size, unsigned short& pos, const std::string& name) + { + if (pos + name.length() + 2 > output_size) + throw Exception("Unable to pack name"); + + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: Packing name " + name); + + irc::sepstream sep(name, '.'); + std::string token; + + while (sep.GetToken(token)) + { + output[pos++] = token.length(); + memcpy(&output[pos], token.data(), token.length()); + pos += token.length(); + } + + output[pos++] = 0; + } + + std::string UnpackName(const unsigned char* input, unsigned short input_size, unsigned short& pos) + { + std::string name; + unsigned short pos_ptr = pos, lowest_ptr = input_size; + bool compressed = false; + + if (pos_ptr >= input_size) + throw Exception("Unable to unpack name - no input"); + + while (input[pos_ptr] > 0) + { + unsigned short offset = input[pos_ptr]; + + if (offset & POINTER) + { + if ((offset & POINTER) != POINTER) + throw Exception("Unable to unpack name - bogus compression header"); + if (pos_ptr + 1 >= input_size) + throw Exception("Unable to unpack name - bogus compression header"); + + /* Place pos at the second byte of the first (farthest) compression pointer */ + if (compressed == false) + { + ++pos; + compressed = true; + } + + pos_ptr = (offset & LABEL) << 8 | input[pos_ptr + 1]; + + /* Pointers can only go back */ + if (pos_ptr >= lowest_ptr) + throw Exception("Unable to unpack name - bogus compression pointer"); + lowest_ptr = pos_ptr; + } + else + { + if (pos_ptr + offset + 1 >= input_size) + throw Exception("Unable to unpack name - offset too large"); + if (!name.empty()) + name += "."; + for (unsigned i = 1; i <= offset; ++i) + name += input[pos_ptr + i]; + + pos_ptr += offset + 1; + if (compressed == false) + /* Move up pos */ + pos = pos_ptr; + } + } + + /* +1 pos either to one byte after the compression pointer or one byte after the ending \0 */ + ++pos; + + if (name.empty()) + throw Exception("Unable to unpack name - no name"); + + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: Unpack name " + name); + + return name; + } + + Question UnpackQuestion(const unsigned char* input, unsigned short input_size, unsigned short& pos) + { + Question question; + + question.name = this->UnpackName(input, input_size, pos); + + if (pos + 4 > input_size) + throw Exception("Unable to unpack question"); + + question.type = static_cast<QueryType>(input[pos] << 8 | input[pos + 1]); + pos += 2; + + question.qclass = input[pos] << 8 | input[pos + 1]; + pos += 2; + + return question; + } + + ResourceRecord UnpackResourceRecord(const unsigned char* input, unsigned short input_size, unsigned short& pos) + { + ResourceRecord record = static_cast<ResourceRecord>(this->UnpackQuestion(input, input_size, pos)); + + if (pos + 6 > input_size) + throw Exception("Unable to unpack resource record"); + + record.ttl = (input[pos] << 24) | (input[pos + 1] << 16) | (input[pos + 2] << 8) | input[pos + 3]; + pos += 4; + + //record.rdlength = input[pos] << 8 | input[pos + 1]; + pos += 2; + + switch (record.type) + { + case QUERY_A: + { + if (pos + 4 > input_size) + throw Exception("Unable to unpack resource record"); + + irc::sockets::sockaddrs addrs; + memset(&addrs, 0, sizeof(addrs)); + + addrs.in4.sin_family = AF_INET; + addrs.in4.sin_addr.s_addr = input[pos] | (input[pos + 1] << 8) | (input[pos + 2] << 16) | (input[pos + 3] << 24); + pos += 4; + + record.rdata = addrs.addr(); + break; + } + case QUERY_AAAA: + { + if (pos + 16 > input_size) + throw Exception("Unable to unpack resource record"); + + irc::sockets::sockaddrs addrs; + memset(&addrs, 0, sizeof(addrs)); + + addrs.in6.sin6_family = AF_INET6; + for (int j = 0; j < 16; ++j) + addrs.in6.sin6_addr.s6_addr[j] = input[pos + j]; + pos += 16; + + record.rdata = addrs.addr(); + + break; + } + case QUERY_CNAME: + case QUERY_PTR: + { + record.rdata = this->UnpackName(input, input_size, pos); + break; + } + default: + break; + } + + if (!record.name.empty() && !record.rdata.empty()) + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: " + record.name + " -> " + record.rdata); + + return record; + } + + public: + static const int POINTER = 0xC0; + static const int LABEL = 0x3F; + static const int HEADER_LENGTH = 12; + + /* ID for this packet */ + unsigned short id; + /* Flags on the packet */ + unsigned short flags; + + Packet() : id(0), flags(0) + { + } + + void Fill(const unsigned char* input, const unsigned short len) + { + if (len < HEADER_LENGTH) + throw Exception("Unable to fill packet"); + + unsigned short packet_pos = 0; + + this->id = (input[packet_pos] << 8) | input[packet_pos + 1]; + packet_pos += 2; + + if (this->id >= MAX_REQUEST_ID) + throw Exception("Query ID too large?"); + + this->flags = (input[packet_pos] << 8) | input[packet_pos + 1]; + packet_pos += 2; + + unsigned short qdcount = (input[packet_pos] << 8) | input[packet_pos + 1]; + packet_pos += 2; + + unsigned short ancount = (input[packet_pos] << 8) | input[packet_pos + 1]; + packet_pos += 2; + + unsigned short nscount = (input[packet_pos] << 8) | input[packet_pos + 1]; + packet_pos += 2; + + unsigned short arcount = (input[packet_pos] << 8) | input[packet_pos + 1]; + packet_pos += 2; + + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: qdcount: " + ConvToStr(qdcount) + " ancount: " + ConvToStr(ancount) + " nscount: " + ConvToStr(nscount) + " arcount: " + ConvToStr(arcount)); + + for (unsigned i = 0; i < qdcount; ++i) + this->questions.push_back(this->UnpackQuestion(input, len, packet_pos)); + + for (unsigned i = 0; i < ancount; ++i) + this->answers.push_back(this->UnpackResourceRecord(input, len, packet_pos)); + } + + unsigned short Pack(unsigned char* output, unsigned short output_size) + { + if (output_size < HEADER_LENGTH) + throw Exception("Unable to pack packet"); + + unsigned short pos = 0; + + output[pos++] = this->id >> 8; + output[pos++] = this->id & 0xFF; + output[pos++] = this->flags >> 8; + output[pos++] = this->flags & 0xFF; + output[pos++] = this->questions.size() >> 8; + output[pos++] = this->questions.size() & 0xFF; + output[pos++] = this->answers.size() >> 8; + output[pos++] = this->answers.size() & 0xFF; + output[pos++] = 0; + output[pos++] = 0; + output[pos++] = 0; + output[pos++] = 0; + + for (unsigned i = 0; i < this->questions.size(); ++i) + { + Question& q = this->questions[i]; + + if (q.type == QUERY_PTR) + { + irc::sockets::sockaddrs ip; + irc::sockets::aptosa(q.name, 0, ip); + + if (q.name.find(':') != std::string::npos) + { + static const char* const hex = "0123456789abcdef"; + char reverse_ip[128]; + unsigned reverse_ip_count = 0; + for (int j = 15; j >= 0; --j) + { + reverse_ip[reverse_ip_count++] = hex[ip.in6.sin6_addr.s6_addr[j] & 0xF]; + reverse_ip[reverse_ip_count++] = '.'; + reverse_ip[reverse_ip_count++] = hex[ip.in6.sin6_addr.s6_addr[j] >> 4]; + reverse_ip[reverse_ip_count++] = '.'; + } + reverse_ip[reverse_ip_count++] = 0; + + q.name = reverse_ip; + q.name += "ip6.arpa"; + } + else + { + unsigned long forward = ip.in4.sin_addr.s_addr; + ip.in4.sin_addr.s_addr = forward << 24 | (forward & 0xFF00) << 8 | (forward & 0xFF0000) >> 8 | forward >> 24; + + q.name = ip.addr() + ".in-addr.arpa"; + } + } + + this->PackName(output, output_size, pos, q.name); + + if (pos + 4 >= output_size) + throw Exception("Unable to pack packet"); + + short s = htons(q.type); + memcpy(&output[pos], &s, 2); + pos += 2; + + s = htons(q.qclass); + memcpy(&output[pos], &s, 2); + pos += 2; + } + + for (unsigned int i = 0; i < answers.size(); i++) + { + ResourceRecord& rr = answers[i]; + + this->PackName(output, output_size, pos, rr.name); + + if (pos + 8 >= output_size) + throw Exception("Unable to pack packet"); + + short s = htons(rr.type); + memcpy(&output[pos], &s, 2); + pos += 2; + + s = htons(rr.qclass); + memcpy(&output[pos], &s, 2); + pos += 2; + + long l = htonl(rr.ttl); + memcpy(&output[pos], &l, 4); + pos += 4; + + switch (rr.type) + { + case QUERY_A: + { + if (pos + 6 > output_size) + throw Exception("Unable to pack packet"); + + irc::sockets::sockaddrs a; + irc::sockets::aptosa(rr.rdata, 0, a); + + s = htons(4); + memcpy(&output[pos], &s, 2); + pos += 2; + + memcpy(&output[pos], &a.in4.sin_addr, 4); + pos += 4; + break; + } + case QUERY_AAAA: + { + if (pos + 18 > output_size) + throw Exception("Unable to pack packet"); + + irc::sockets::sockaddrs a; + irc::sockets::aptosa(rr.rdata, 0, a); + + s = htons(16); + memcpy(&output[pos], &s, 2); + pos += 2; + + memcpy(&output[pos], &a.in6.sin6_addr, 16); + pos += 16; + break; + } + case QUERY_CNAME: + case QUERY_PTR: + { + if (pos + 2 >= output_size) + throw Exception("Unable to pack packet"); + + unsigned short packet_pos_save = pos; + pos += 2; + + this->PackName(output, output_size, pos, rr.rdata); + + s = htons(pos - packet_pos_save - 2); + memcpy(&output[packet_pos_save], &s, 2); + break; + } + default: + break; + } + } + + return pos; + } +}; + +class MyManager : public Manager, public Timer, public EventHandler +{ + typedef TR1NS::unordered_map<Question, Query, Question::hash> cache_map; + cache_map cache; + + irc::sockets::sockaddrs myserver; + + static bool IsExpired(const Query& record, time_t now = ServerInstance->Time()) + { + const ResourceRecord& req = record.answers[0]; + return (req.created + static_cast<time_t>(req.ttl) < now); + } + + /** Check the DNS cache to see if request can be handled by a cached result + * @return true if a cached result was found. + */ + bool CheckCache(DNS::Request* req, const DNS::Question& question) + { + ServerInstance->Logs->Log("RESOLVER", LOG_SPARSE, "Resolver: cache: Checking cache for " + question.name); + + cache_map::iterator it = this->cache.find(question); + if (it == this->cache.end()) + return false; + + Query& record = it->second; + if (IsExpired(record)) + { + this->cache.erase(it); + return false; + } + + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: cache: Using cached result for " + question.name); + record.cached = true; + req->OnLookupComplete(&record); + return true; + } + + /** Add a record to the dns cache + * @param r The record + */ + void AddCache(Query& r) + { + const ResourceRecord& rr = r.answers[0]; + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: cache: added cache for " + rr.name + " -> " + rr.rdata + " ttl: " + ConvToStr(rr.ttl)); + this->cache[r.questions[0]] = r; + } + + public: + DNS::Request* requests[MAX_REQUEST_ID]; + + MyManager(Module* c) : Manager(c), Timer(3600, ServerInstance->Time(), true) + { + for (int i = 0; i < MAX_REQUEST_ID; ++i) + requests[i] = NULL; + ServerInstance->Timers->AddTimer(this); + } + + ~MyManager() + { + for (int i = 0; i < MAX_REQUEST_ID; ++i) + { + DNS::Request* request = requests[i]; + if (!request) + continue; + + Query rr(*request); + rr.error = ERROR_UNKNOWN; + request->OnError(&rr); + + delete request; + } + } + + void Process(DNS::Request* req) + { + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: Processing request to lookup " + req->name + " of type " + ConvToStr(req->type) + " to " + this->myserver.addr()); + + /* Create an id */ + unsigned int tries = 0; + do + { + req->id = ServerInstance->GenRandomInt(DNS::MAX_REQUEST_ID); + + if (++tries == DNS::MAX_REQUEST_ID*5) + { + // If we couldn't find an empty slot this many times, do a sequential scan as a last + // resort. If an empty slot is found that way, go on, otherwise throw an exception + req->id = 0; + for (int i = 1; i < DNS::MAX_REQUEST_ID; i++) + { + if (!this->requests[i]) + { + req->id = i; + break; + } + } + + if (req->id == 0) + throw Exception("DNS: All ids are in use"); + + break; + } + } + while (!req->id || this->requests[req->id]); + + this->requests[req->id] = req; + + Packet p; + p.flags = QUERYFLAGS_RD; + p.id = req->id; + p.questions.push_back(*req); + + unsigned char buffer[524]; + unsigned short len = p.Pack(buffer, sizeof(buffer)); + + /* Note that calling Pack() above can actually change the contents of p.questions[0].name, if the query is a PTR, + * to contain the value that would be in the DNS cache, which is why this is here. + */ + if (req->use_cache && this->CheckCache(req, p.questions[0])) + { + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: Using cached result"); + delete req; + return; + } + + if (ServerInstance->SE->SendTo(this, buffer, len, 0, &this->myserver.sa, this->myserver.sa_size()) != len) + throw Exception("DNS: Unable to send query"); + } + + void RemoveRequest(DNS::Request* req) + { + this->requests[req->id] = NULL; + } + + std::string GetErrorStr(Error e) + { + switch (e) + { + case ERROR_UNLOADED: + return "Module is unloading"; + case ERROR_TIMEDOUT: + return "Request timed out"; + case ERROR_NOT_AN_ANSWER: + case ERROR_NONSTANDARD_QUERY: + case ERROR_FORMAT_ERROR: + return "Malformed answer"; + case ERROR_SERVER_FAILURE: + case ERROR_NOT_IMPLEMENTED: + case ERROR_REFUSED: + case ERROR_INVALIDTYPE: + return "Nameserver failure"; + case ERROR_DOMAIN_NOT_FOUND: + case ERROR_NO_RECORDS: + return "Domain not found"; + case ERROR_NONE: + case ERROR_UNKNOWN: + default: + return "Unknown error"; + } + } + + void HandleEvent(EventType et, int) + { + if (et == EVENT_ERROR) + { + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: UDP socket got an error event"); + return; + } + + unsigned char buffer[524]; + irc::sockets::sockaddrs from; + socklen_t x = sizeof(from); + + int length = ServerInstance->SE->RecvFrom(this, buffer, sizeof(buffer), 0, &from.sa, &x); + + if (length < Packet::HEADER_LENGTH) + return; + + Packet recv_packet; + + try + { + recv_packet.Fill(buffer, length); + } + catch (Exception& ex) + { + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, std::string(ex.GetReason())); + return; + } + + if (myserver != from) + { + std::string server1 = from.str(); + std::string server2 = myserver.str(); + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: Got a result from the wrong server! Bad NAT or DNS forging attempt? '%s' != '%s'", + server1.c_str(), server2.c_str()); + return; + } + + DNS::Request* request = this->requests[recv_packet.id]; + if (request == NULL) + { + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: Received an answer for something we didn't request"); + return; + } + + if (recv_packet.flags & QUERYFLAGS_OPCODE) + { + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: Received a nonstandard query"); + ServerInstance->stats->statsDnsBad++; + recv_packet.error = ERROR_NONSTANDARD_QUERY; + request->OnError(&recv_packet); + } + else if (recv_packet.flags & QUERYFLAGS_RCODE) + { + Error error = ERROR_UNKNOWN; + + switch (recv_packet.flags & QUERYFLAGS_RCODE) + { + case 1: + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: format error"); + error = ERROR_FORMAT_ERROR; + break; + case 2: + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: server error"); + error = ERROR_SERVER_FAILURE; + break; + case 3: + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: domain not found"); + error = ERROR_DOMAIN_NOT_FOUND; + break; + case 4: + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: not implemented"); + error = ERROR_NOT_IMPLEMENTED; + break; + case 5: + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: refused"); + error = ERROR_REFUSED; + break; + default: + break; + } + + ServerInstance->stats->statsDnsBad++; + recv_packet.error = error; + request->OnError(&recv_packet); + } + else if (recv_packet.questions.empty() || recv_packet.answers.empty()) + { + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: No resource records returned"); + ServerInstance->stats->statsDnsBad++; + recv_packet.error = ERROR_NO_RECORDS; + request->OnError(&recv_packet); + } + else + { + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: Lookup complete for " + request->name); + ServerInstance->stats->statsDnsGood++; + request->OnLookupComplete(&recv_packet); + this->AddCache(recv_packet); + } + + ServerInstance->stats->statsDns++; + + /* Request's destructor removes it from the request map */ + delete request; + } + + bool Tick(time_t now) + { + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolver: cache: purging DNS cache"); + + for (cache_map::iterator it = this->cache.begin(); it != this->cache.end(); ) + { + const Query& query = it->second; + if (IsExpired(query, now)) + this->cache.erase(it++); + else + ++it; + } + return true; + } + + void Rehash(const std::string& dnsserver) + { + if (this->GetFd() > -1) + { + ServerInstance->SE->DelFd(this); + ServerInstance->SE->Shutdown(this, 2); + ServerInstance->SE->Close(this); + this->SetFd(-1); + + /* Remove expired entries from the cache */ + this->Tick(ServerInstance->Time()); + } + + irc::sockets::aptosa(dnsserver, DNS::PORT, myserver); + + /* Initialize mastersocket */ + int s = socket(myserver.sa.sa_family, SOCK_DGRAM, 0); + this->SetFd(s); + + /* Have we got a socket? */ + if (this->GetFd() != -1) + { + ServerInstance->SE->SetReuse(s); + ServerInstance->SE->NonBlocking(s); + + irc::sockets::sockaddrs bindto; + memset(&bindto, 0, sizeof(bindto)); + bindto.sa.sa_family = myserver.sa.sa_family; + + if (ServerInstance->SE->Bind(this->GetFd(), bindto) < 0) + { + /* Failed to bind */ + ServerInstance->Logs->Log("RESOLVER", LOG_SPARSE, "Resolver: Error binding dns socket - hostnames will NOT resolve"); + ServerInstance->SE->Close(this); + this->SetFd(-1); + } + else if (!ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE)) + { + ServerInstance->Logs->Log("RESOLVER", LOG_SPARSE, "Resolver: Internal error starting DNS - hostnames will NOT resolve."); + ServerInstance->SE->Close(this); + this->SetFd(-1); + } + } + else + { + ServerInstance->Logs->Log("RESOLVER", LOG_SPARSE, "Resolver: Error creating DNS socket - hostnames will NOT resolve"); + } + } +}; + +class ModuleDNS : public Module +{ + MyManager manager; + std::string DNSServer; + + void FindDNSServer() + { +#ifdef _WIN32 + // attempt to look up their nameserver from the system + ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "WARNING: <dns:server> not defined, attempting to find a working server in the system settings..."); + + PFIXED_INFO pFixedInfo; + DWORD dwBufferSize = sizeof(FIXED_INFO); + pFixedInfo = (PFIXED_INFO) HeapAlloc(GetProcessHeap(), 0, sizeof(FIXED_INFO)); + + if (pFixedInfo) + { + if (GetNetworkParams(pFixedInfo, &dwBufferSize) == ERROR_BUFFER_OVERFLOW) + { + HeapFree(GetProcessHeap(), 0, pFixedInfo); + pFixedInfo = (PFIXED_INFO) HeapAlloc(GetProcessHeap(), 0, dwBufferSize); + } + + if (pFixedInfo) + { + if (GetNetworkParams(pFixedInfo, &dwBufferSize) == NO_ERROR) + DNSServer = pFixedInfo->DnsServerList.IpAddress.String; + + HeapFree(GetProcessHeap(), 0, pFixedInfo); + } + + if (!DNSServer.empty()) + { + ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "<dns:server> set to '%s' as first active resolver in the system settings.", DNSServer.c_str()); + return; + } + } + + ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "No viable nameserver found! Defaulting to nameserver '127.0.0.1'!"); +#else + // attempt to look up their nameserver from /etc/resolv.conf + ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "WARNING: <dns:server> not defined, attempting to find working server in /etc/resolv.conf..."); + + std::ifstream resolv("/etc/resolv.conf"); + + while (resolv >> DNSServer) + { + if (DNSServer == "nameserver") + { + resolv >> DNSServer; + if (DNSServer.find_first_not_of("0123456789.") == std::string::npos) + { + ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "<dns:server> set to '%s' as first resolver in /etc/resolv.conf.",DNSServer.c_str()); + return; + } + } + } + + ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "/etc/resolv.conf contains no viable nameserver entries! Defaulting to nameserver '127.0.0.1'!"); +#endif + DNSServer = "127.0.0.1"; + } + + public: + ModuleDNS() : manager(this) + { + } + + void init() + { + ServerInstance->Modules->AddService(this->manager); + + this->OnRehash(NULL); + } + + void OnRehash(User* user) + { + std::string oldserver = DNSServer; + DNSServer = ServerInstance->Config->ConfValue("dns")->getString("server"); + if (DNSServer.empty()) + FindDNSServer(); + + if (oldserver != DNSServer) + this->manager.Rehash(DNSServer); + } + + void OnUnloadModule(Module* mod) + { + for (int i = 0; i < MAX_REQUEST_ID; ++i) + { + DNS::Request* req = this->manager.requests[i]; + if (!req) + continue; + + if (req->creator == mod) + { + Query rr(*req); + rr.error = ERROR_UNLOADED; + req->OnError(&rr); + + delete req; + } + } + } + + Version GetVersion() + { + return Version("DNS support", VF_CORE|VF_VENDOR); + } +}; + +MODULE_INIT(ModuleDNS) + diff --git a/src/commands/cmd_eline.cpp b/src/commands/cmd_eline.cpp index ca39f9061..67f67e9f0 100644 --- a/src/commands/cmd_eline.cpp +++ b/src/commands/cmd_eline.cpp @@ -60,17 +60,16 @@ CmdResult CommandEline::Handle (const std::vector<std::string>& parameters, User else ih = ServerInstance->XLines->IdentSplit(target); - if (ih.first.empty()) - { - user->WriteServ("NOTICE %s :*** Target not found", user->nick.c_str()); - return CMD_FAILURE; - } + if (ih.first.empty()) + { + user->WriteNotice("*** Target not found"); + return CMD_FAILURE; + } if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user)) return CMD_FAILURE; - long duration = ServerInstance->Duration(parameters[1].c_str()); - + unsigned long duration = InspIRCd::Duration(parameters[1]); ELine* el = new ELine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ih.first.c_str(), ih.second.c_str()); if (ServerInstance->XLines->AddLine(el, user)) { @@ -89,7 +88,7 @@ CmdResult CommandEline::Handle (const std::vector<std::string>& parameters, User else { delete el; - user->WriteServ("NOTICE %s :*** E-Line for %s already exists",user->nick.c_str(),target.c_str()); + user->WriteNotice("*** E-Line for " + target + " already exists"); } } else @@ -100,7 +99,7 @@ CmdResult CommandEline::Handle (const std::vector<std::string>& parameters, User } else { - user->WriteServ("NOTICE %s :*** E-Line %s not found in list, try /stats e.",user->nick.c_str(),target.c_str()); + user->WriteNotice("*** E-Line " + target + " not found in list, try /stats e"); } } diff --git a/src/commands/cmd_gline.cpp b/src/commands/cmd_gline.cpp index 6505b7464..bdb5c26b2 100644 --- a/src/commands/cmd_gline.cpp +++ b/src/commands/cmd_gline.cpp @@ -63,7 +63,7 @@ CmdResult CommandGline::Handle (const std::vector<std::string>& parameters, User if (ih.first.empty()) { - user->WriteServ("NOTICE %s :*** Target not found", user->nick.c_str()); + user->WriteNotice("*** Target not found"); return CMD_FAILURE; } @@ -72,11 +72,11 @@ CmdResult CommandGline::Handle (const std::vector<std::string>& parameters, User else if (target.find('!') != std::string::npos) { - user->WriteServ("NOTICE %s :*** G-Line cannot operate on nick!user@host masks",user->nick.c_str()); + user->WriteNotice("*** G-Line cannot operate on nick!user@host masks"); return CMD_FAILURE; } - long duration = ServerInstance->Duration(parameters[1].c_str()); + unsigned long duration = InspIRCd::Duration(parameters[1]); GLine* gl = new GLine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ih.first.c_str(), ih.second.c_str()); if (ServerInstance->XLines->AddLine(gl, user)) { @@ -97,7 +97,7 @@ CmdResult CommandGline::Handle (const std::vector<std::string>& parameters, User else { delete gl; - user->WriteServ("NOTICE %s :*** G-Line for %s already exists",user->nick.c_str(),target.c_str()); + user->WriteNotice("** G-Line for " + target + " already exists"); } } @@ -109,7 +109,7 @@ CmdResult CommandGline::Handle (const std::vector<std::string>& parameters, User } else { - user->WriteServ("NOTICE %s :*** G-line %s not found in list, try /stats g.",user->nick.c_str(),target.c_str()); + user->WriteNotice("*** G-Line " + target + " not found in list, try /stats g."); } } diff --git a/src/commands/cmd_hostname_lookup.cpp b/src/commands/cmd_hostname_lookup.cpp new file mode 100644 index 000000000..f352443d0 --- /dev/null +++ b/src/commands/cmd_hostname_lookup.cpp @@ -0,0 +1,239 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Adam <Adam@anope.org> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "inspircd.h" +#include "modules/dns.h" + +namespace +{ + LocalIntExt* dl; + LocalStringExt* ph; +} + +/** Derived from Resolver, and performs user forward/reverse lookups. + */ +class UserResolver : public DNS::Request +{ + /** UUID we are looking up */ + const std::string uuid; + + /** True if the lookup is forward, false if is a reverse lookup + */ + const bool fwd; + + public: + /** Create a resolver. + * @param mgr DNS Manager + * @param me this module + * @param user The user to begin lookup on + * @param to_resolve The IP or host to resolve + * @param qt The query type + */ + UserResolver(DNS::Manager* mgr, Module* me, LocalUser* user, const std::string& to_resolve, DNS::QueryType qt) + : DNS::Request(mgr, me, to_resolve, qt) + , uuid(user->uuid) + , fwd(qt == DNS::QUERY_A || qt == DNS::QUERY_AAAA) + { + } + + /** Called on successful lookup + * if a previous result has already come back. + * @param r The finished query + */ + void OnLookupComplete(const DNS::Query* r) + { + LocalUser* bound_user = (LocalUser*)ServerInstance->FindUUID(uuid); + if (!bound_user) + { + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Resolution finished for user '%s' who is gone", uuid.c_str()); + return; + } + + const DNS::ResourceRecord& ans_record = r->answers[0]; + + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "DNS result for %s: '%s' -> '%s'", uuid.c_str(), ans_record.name.c_str(), ans_record.rdata.c_str()); + + if (!fwd) + { + // first half of resolution is done. We now need to verify that the host matches. + ph->set(bound_user, ans_record.rdata); + + UserResolver* res_forward; + if (bound_user->client_sa.sa.sa_family == AF_INET6) + { + /* IPV6 forward lookup */ + res_forward = new UserResolver(this->manager, this->creator, bound_user, ans_record.rdata, DNS::QUERY_AAAA); + } + else + { + /* IPV4 lookup */ + res_forward = new UserResolver(this->manager, this->creator, bound_user, ans_record.rdata, DNS::QUERY_A); + } + try + { + this->manager->Process(res_forward); + } + catch (DNS::Exception& e) + { + delete res_forward; + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG, "Error in resolver: %s",e.GetReason()); + + bound_user->WriteNotice("*** There was an internal error resolving your host, using your IP address (" + bound_user->GetIPString() + ") instead."); + dl->set(bound_user, 0); + } + } + else + { + /* Both lookups completed */ + + irc::sockets::sockaddrs* user_ip = &bound_user->client_sa; + bool rev_match = false; + if (user_ip->sa.sa_family == AF_INET6) + { + struct in6_addr res_bin; + if (inet_pton(AF_INET6, ans_record.rdata.c_str(), &res_bin)) + { + rev_match = !memcmp(&user_ip->in6.sin6_addr, &res_bin, sizeof(res_bin)); + } + } + else + { + struct in_addr res_bin; + if (inet_pton(AF_INET, ans_record.rdata.c_str(), &res_bin)) + { + rev_match = !memcmp(&user_ip->in4.sin_addr, &res_bin, sizeof(res_bin)); + } + } + + dl->set(bound_user, 0); + + if (rev_match) + { + std::string* hostname = ph->get(bound_user); + + if (hostname == NULL) + { + ServerInstance->Logs->Log("RESOLVER", LOG_DEFAULT, "ERROR: User has no hostname attached when doing a forward lookup"); + bound_user->WriteNotice("*** There was an internal error resolving your host, using your IP address (" + bound_user->GetIPString() + ") instead."); + return; + } + else if (hostname->length() < 65) + { + /* Hostnames starting with : are not a good thing (tm) */ + if ((*hostname)[0] == ':') + hostname->insert(0, "0"); + + bound_user->WriteNotice("*** Found your hostname (" + *hostname + (r->cached ? ") -- cached" : ")")); + bound_user->host.assign(*hostname, 0, 64); + bound_user->dhost = bound_user->host; + + /* Invalidate cache */ + bound_user->InvalidateCache(); + } + else + { + bound_user->WriteNotice("*** Your hostname is longer than the maximum of 64 characters, using your IP address (" + bound_user->GetIPString() + ") instead."); + } + + ph->unset(bound_user); + } + else + { + bound_user->WriteNotice("*** Your hostname does not match up with your IP address. Sorry, using your IP address (" + bound_user->GetIPString() + ") instead."); + } + } + } + + /** Called on failed lookup + * @param query The errored query + */ + void OnError(const DNS::Query* query) + { + LocalUser* bound_user = (LocalUser*)ServerInstance->FindUUID(uuid); + if (bound_user) + { + bound_user->WriteNotice("*** Could not resolve your hostname: " + this->manager->GetErrorStr(query->error) + "; using your IP address (" + bound_user->GetIPString() + ") instead."); + dl->set(bound_user, 0); + ServerInstance->stats->statsDnsBad++; + } + } +}; + +class ModuleHostnameLookup : public Module +{ + LocalIntExt dnsLookup; + LocalStringExt ptrHosts; + dynamic_reference<DNS::Manager> DNS; + + public: + ModuleHostnameLookup() + : dnsLookup("dnsLookup", this) + , ptrHosts("ptrHosts", this) + , DNS(this, "DNS") + { + dl = &dnsLookup; + ph = &ptrHosts; + } + + void init() + { + ServerInstance->Modules->AddService(this->dnsLookup); + ServerInstance->Modules->AddService(this->ptrHosts); + } + + void OnUserInit(LocalUser *user) + { + if (!DNS || !user->MyClass->resolvehostnames) + { + user->WriteNotice("*** Skipping host resolution (disabled by server administrator)"); + return; + } + + user->WriteNotice("*** Looking up your hostname..."); + + UserResolver* res_reverse = new UserResolver(*this->DNS, this, user, user->GetIPString(), DNS::QUERY_PTR); + try + { + /* If both the reverse and forward queries are cached, the user will be able to pass DNS completely + * before Process() completes, which is why dnsLookup.set() is here, before Process() + */ + this->dnsLookup.set(user, 1); + this->DNS->Process(res_reverse); + } + catch (DNS::Exception& e) + { + this->dnsLookup.set(user, 0); + delete res_reverse; + ServerInstance->Logs->Log("USERS", LOG_DEBUG, "Error in resolver: %s", e.GetReason()); + ServerInstance->stats->statsDnsBad++; + } + } + + ModResult OnCheckReady(LocalUser* user) + { + return this->dnsLookup.get(user) ? MOD_RES_DENY : MOD_RES_PASSTHRU; + } + + Version GetVersion() + { + return Version("Provides support for DNS lookups on connecting clients", VF_CORE|VF_VENDOR); + } +}; + +MODULE_INIT(ModuleHostnameLookup) diff --git a/src/commands/cmd_info.cpp b/src/commands/cmd_info.cpp index 6e5f2a909..b3f146c30 100644 --- a/src/commands/cmd_info.cpp +++ b/src/commands/cmd_info.cpp @@ -100,7 +100,7 @@ CmdResult CommandInfo::Handle (const std::vector<std::string>& parameters, User int i=0; while (lines[i]) user->SendText(":%s %03d %s :%s", ServerInstance->Config->ServerName.c_str(), RPL_INFO, user->nick.c_str(), lines[i++]); - FOREACH_MOD(I_OnInfo,OnInfo(user)); + FOREACH_MOD(OnInfo, (user)); user->SendText(":%s %03d %s :End of /INFO list", ServerInstance->Config->ServerName.c_str(), RPL_ENDOFINFO, user->nick.c_str()); return CMD_SUCCESS; } diff --git a/src/commands/cmd_invite.cpp b/src/commands/cmd_invite.cpp index c69e6bd1b..2ed05c550 100644 --- a/src/commands/cmd_invite.cpp +++ b/src/commands/cmd_invite.cpp @@ -40,6 +40,10 @@ class CommandInvite : public Command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(const std::vector<std::string>& parameters, User *user); + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) + { + return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST); + } }; /** Handle /INVITE @@ -61,7 +65,7 @@ CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, Use if (parameters.size() == 3) { if (IS_LOCAL(user)) - timeout = ServerInstance->Time() + ServerInstance->Duration(parameters[2]); + timeout = ServerInstance->Time() + InspIRCd::Duration(parameters[1]); else timeout = ConvToInt(parameters[2]); } @@ -107,9 +111,14 @@ CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, Use } if (IS_LOCAL(u)) - IS_LOCAL(u)->InviteTo(c->name.c_str(), timeout); - u->WriteFrom(user,"INVITE %s :%s",u->nick.c_str(),c->name.c_str()); - user->WriteNumeric(RPL_INVITING, "%s %s %s",user->nick.c_str(),u->nick.c_str(),c->name.c_str()); + { + Invitation::Create(c, IS_LOCAL(u), timeout); + u->WriteFrom(user,"INVITE %s :%s",u->nick.c_str(),c->name.c_str()); + } + + if (IS_LOCAL(user)) + user->WriteNumeric(RPL_INVITING, "%s %s %s",user->nick.c_str(),u->nick.c_str(),c->name.c_str()); + if (ServerInstance->Config->AnnounceInvites != ServerConfig::INVITE_ANNOUNCE_NONE) { char prefix; @@ -134,7 +143,7 @@ CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, Use } c->WriteAllExceptSender(user, true, prefix, "NOTICE %s :*** %s invited %s into the channel", c->name.c_str(), user->nick.c_str(), u->nick.c_str()); } - FOREACH_MOD(I_OnUserInvite,OnUserInvite(user,u,c,timeout)); + FOREACH_MOD(OnUserInvite, (user,u,c,timeout)); } else if (IS_LOCAL(user)) { diff --git a/src/commands/cmd_join.cpp b/src/commands/cmd_join.cpp index 6124fcc1c..9e2678b5d 100644 --- a/src/commands/cmd_join.cpp +++ b/src/commands/cmd_join.cpp @@ -25,44 +25,50 @@ * the same way, however, they can be fully unloaded, where these * may not. */ -class CommandJoin : public Command +class CommandJoin : public SplitCommand { public: /** Constructor for join. */ - CommandJoin ( Module* parent) : Command(parent,"JOIN", 1, 2) { syntax = "<channel>{,<channel>} {<key>{,<key>}}"; Penalty = 2; } + CommandJoin(Module* parent) + : SplitCommand(parent, "JOIN", 1, 2) + { + syntax = "<channel>{,<channel>} {<key>{,<key>}}"; + Penalty = 2; + } + /** Handle command. * @param parameters The parameters to the comamnd * @param pcnt The number of parameters passed to teh command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ - CmdResult Handle(const std::vector<std::string>& parameters, User *user); + CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user); }; /** Handle /JOIN */ -CmdResult CommandJoin::Handle (const std::vector<std::string>& parameters, User *user) +CmdResult CommandJoin::HandleLocal(const std::vector<std::string>& parameters, LocalUser *user) { if (parameters.size() > 1) { - if (ServerInstance->Parser->LoopCall(user, this, parameters, 0, 1, false)) + if (CommandParser::LoopCall(user, this, parameters, 0, 1, false)) return CMD_SUCCESS; - if (ServerInstance->IsChannel(parameters[0].c_str(), ServerInstance->Config->Limits.ChanMax)) + if (ServerInstance->IsChannel(parameters[0])) { - Channel::JoinUser(user, parameters[0].c_str(), false, parameters[1].c_str(), false); + Channel::JoinUser(user, parameters[0], false, parameters[1]); return CMD_SUCCESS; } } else { - if (ServerInstance->Parser->LoopCall(user, this, parameters, 0, -1, false)) + if (CommandParser::LoopCall(user, this, parameters, 0, -1, false)) return CMD_SUCCESS; - if (ServerInstance->IsChannel(parameters[0].c_str(), ServerInstance->Config->Limits.ChanMax)) + if (ServerInstance->IsChannel(parameters[0])) { - Channel::JoinUser(user, parameters[0].c_str(), false, "", false); + Channel::JoinUser(user, parameters[0]); return CMD_SUCCESS; } } diff --git a/src/commands/cmd_kick.cpp b/src/commands/cmd_kick.cpp index 3c5fb0052..b59eec030 100644 --- a/src/commands/cmd_kick.cpp +++ b/src/commands/cmd_kick.cpp @@ -38,6 +38,10 @@ class CommandKick : public Command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(const std::vector<std::string>& parameters, User *user); + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) + { + return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST); + } }; /** Handle /KICK @@ -48,7 +52,7 @@ CmdResult CommandKick::Handle (const std::vector<std::string>& parameters, User Channel* c = ServerInstance->FindChan(parameters[0]); User* u; - if (ServerInstance->Parser->LoopCall(user, this, parameters, 1)) + if (CommandParser::LoopCall(user, this, parameters, 1)) return CMD_SUCCESS; if (IS_LOCAL(user)) @@ -62,10 +66,21 @@ CmdResult CommandKick::Handle (const std::vector<std::string>& parameters, User return CMD_FAILURE; } - if ((IS_LOCAL(user)) && (!c->HasUser(user)) && (!ServerInstance->ULine(user->server))) + Membership* srcmemb = NULL; + if (IS_LOCAL(user)) { - user->WriteServ( "442 %s %s :You're not on that channel!", user->nick.c_str(), parameters[0].c_str()); - return CMD_FAILURE; + srcmemb = c->GetUser(user); + if (!srcmemb) + { + user->WriteServ( "442 %s %s :You're not on that channel!", user->nick.c_str(), parameters[0].c_str()); + return CMD_FAILURE; + } + + if (ServerInstance->ULine(u->server)) + { + user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You may not kick a u-lined client", user->nick.c_str(), c->name.c_str()); + return CMD_FAILURE; + } } if (parameters.size() > 2) @@ -77,7 +92,7 @@ CmdResult CommandKick::Handle (const std::vector<std::string>& parameters, User reason.assign(user->nick, 0, ServerInstance->Config->Limits.MaxKick); } - c->KickUser(user, u, reason.c_str()); + c->KickUser(user, u, reason, srcmemb); return CMD_SUCCESS; } diff --git a/src/commands/cmd_kill.cpp b/src/commands/cmd_kill.cpp index 17c8a76a0..dddfe4291 100644 --- a/src/commands/cmd_kill.cpp +++ b/src/commands/cmd_kill.cpp @@ -28,13 +28,16 @@ */ class CommandKill : public Command { + std::string lastuuid; + std::string killreason; + public: /** Constructor for kill. */ CommandKill ( Module* parent) : Command(parent,"KILL",2,2) { flags_needed = 'o'; syntax = "<nickname> <reason>"; - TRANSLATE3(TR_NICK, TR_TEXT, TR_END); + TRANSLATE2(TR_CUSTOM, TR_CUSTOM); } /** Handle command. * @param parameters The parameters to the comamnd @@ -45,11 +48,21 @@ class CommandKill : public Command CmdResult Handle(const std::vector<std::string>& parameters, User *user); RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { - // local kills of remote users are routed via the OnRemoteKill hook - if (IS_LOCAL(user)) + // FindNick() doesn't work here because we quit the target user in Handle() which + // removes it from the nicklist, so we check lastuuid: if it's empty then this KILL + // was for a local user, otherwise it contains the uuid of the user who was killed. + if (lastuuid.empty()) return ROUTE_LOCALONLY; return ROUTE_BROADCAST; } + + void EncodeParameter(std::string& param, int index) + { + // Manually translate the nick -> uuid (see above), and also the reason (params[1]) + // because we decorate it if the oper is local and want remote servers to see the + // decorated reason not the original. + param = ((index == 0) ? lastuuid : killreason); + } }; /** Handle /KILL @@ -57,8 +70,12 @@ class CommandKill : public Command CmdResult CommandKill::Handle (const std::vector<std::string>& parameters, User *user) { /* Allow comma seperated lists of users for /KILL (thanks w00t) */ - if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) - return CMD_SUCCESS; + if (CommandParser::LoopCall(user, this, parameters, 0)) + { + // If we got a colon delimited list of nicks then the handler ran for each nick, + // and KILL commands were broadcast for remote targets. + return CMD_FAILURE; + } User *u = ServerInstance->FindNick(parameters[0]); if ((u) && (!IS_SERVER(u))) @@ -71,7 +88,6 @@ CmdResult CommandKill::Handle (const std::vector<std::string>& parameters, User * just gets processed and passed on, otherwise, if they are local, it gets prefixed. Makes sense :-) -- w00t */ - std::string killreason; if (IS_LOCAL(user)) { /* @@ -112,7 +128,7 @@ CmdResult CommandKill::Handle (const std::vector<std::string>& parameters, User { // remote kill ServerInstance->SNO->WriteToSnoMask('K', "Remote kill by %s: %s (%s)", user->nick.c_str(), u->GetFullRealHost().c_str(), parameters[1].c_str()); - FOREACH_MOD(I_OnRemoteKill, OnRemoteKill(user, u, killreason, killreason)); + this->lastuuid = u->uuid; } else { @@ -125,7 +141,7 @@ CmdResult CommandKill::Handle (const std::vector<std::string>& parameters, User ServerInstance->SNO->WriteGlobalSno('k',"Local Kill by %s: %s (%s)", user->nick.c_str(), u->GetFullRealHost().c_str(), parameters[1].c_str()); else ServerInstance->SNO->WriteToSnoMask('k',"Local Kill by %s: %s (%s)", user->nick.c_str(), u->GetFullRealHost().c_str(), parameters[1].c_str()); - ServerInstance->Logs->Log("KILL",DEFAULT,"LOCAL KILL: %s :%s!%s!%s (%s)", u->nick.c_str(), ServerInstance->Config->ServerName.c_str(), user->dhost.c_str(), user->nick.c_str(), parameters[1].c_str()); + ServerInstance->Logs->Log("KILL", LOG_DEFAULT, "LOCAL KILL: %s :%s!%s!%s (%s)", u->nick.c_str(), ServerInstance->Config->ServerName.c_str(), user->dhost.c_str(), user->nick.c_str(), parameters[1].c_str()); /* Bug #419, make sure this message can only occur once even in the case of multiple KILL messages crossing the network, and change to show * hidekillsserver as source if possible */ @@ -138,6 +154,8 @@ CmdResult CommandKill::Handle (const std::vector<std::string>& parameters, User ServerInstance->Config->HideKillsServer.empty() ? user->nick.c_str() : ServerInstance->Config->HideKillsServer.c_str(), parameters[1].c_str()); } + + this->lastuuid.clear(); } // send the quit out diff --git a/src/commands/cmd_kline.cpp b/src/commands/cmd_kline.cpp index ce3642f91..20afae2a9 100644 --- a/src/commands/cmd_kline.cpp +++ b/src/commands/cmd_kline.cpp @@ -63,7 +63,7 @@ CmdResult CommandKline::Handle (const std::vector<std::string>& parameters, User if (ih.first.empty()) { - user->WriteServ("NOTICE %s :*** Target not found", user->nick.c_str()); + user->WriteNotice("*** Target not found"); return CMD_FAILURE; } @@ -72,11 +72,11 @@ CmdResult CommandKline::Handle (const std::vector<std::string>& parameters, User if (target.find('!') != std::string::npos) { - user->WriteServ("NOTICE %s :*** K-Line cannot operate on nick!user@host masks",user->nick.c_str()); + user->WriteNotice("*** K-Line cannot operate on nick!user@host masks"); return CMD_FAILURE; } - long duration = ServerInstance->Duration(parameters[1].c_str()); + unsigned long duration = InspIRCd::Duration(parameters[1]); KLine* kl = new KLine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ih.first.c_str(), ih.second.c_str()); if (ServerInstance->XLines->AddLine(kl,user)) { @@ -97,7 +97,7 @@ CmdResult CommandKline::Handle (const std::vector<std::string>& parameters, User else { delete kl; - user->WriteServ("NOTICE %s :*** K-Line for %s already exists",user->nick.c_str(),target.c_str()); + user->WriteNotice("*** K-Line for " + target + " already exists"); } } else @@ -108,7 +108,7 @@ CmdResult CommandKline::Handle (const std::vector<std::string>& parameters, User } else { - user->WriteServ("NOTICE %s :*** K-Line %s not found in list, try /stats k.",user->nick.c_str(),target.c_str()); + user->WriteNotice("*** K-Line " + target + " not found in list, try /stats k."); } } diff --git a/src/commands/cmd_list.cpp b/src/commands/cmd_list.cpp index 2f417bc04..5962e2547 100644 --- a/src/commands/cmd_list.cpp +++ b/src/commands/cmd_list.cpp @@ -27,10 +27,20 @@ */ class CommandList : public Command { + ChanModeReference secretmode; + ChanModeReference privatemode; + public: /** Constructor for list. */ - CommandList ( Module* parent) : Command(parent,"LIST", 0, 0) { Penalty = 5; } + CommandList(Module* parent) + : Command(parent,"LIST", 0, 0) + , secretmode(creator, "secret") + , privatemode(creator, "private") + { + Penalty = 5; + } + /** Handle command. * @param parameters The parameters to the comamnd * @param pcnt The number of parameters passed to teh command @@ -82,14 +92,14 @@ CmdResult CommandList::Handle (const std::vector<std::string>& parameters, User // if the channel is not private/secret, OR the user is on the channel anyway bool n = (i->second->HasUser(user) || user->HasPrivPermission("channels/auspex")); - if (!n && i->second->IsModeSet('p')) + if (!n && i->second->IsModeSet(privatemode)) { /* Channel is +p and user is outside/not privileged */ user->WriteNumeric(322, "%s * %ld :",user->nick.c_str(), users); } else { - if (n || !i->second->IsModeSet('s')) + if (n || !i->second->IsModeSet(secretmode)) { /* User is in the channel/privileged, channel is not +s */ user->WriteNumeric(322, "%s %s %ld :[+%s] %s",user->nick.c_str(),i->second->name.c_str(),users,i->second->ChanModes(n),i->second->topic.c_str()); diff --git a/src/commands/cmd_lusers.cpp b/src/commands/cmd_lusers.cpp index 91a718090..06419733d 100644 --- a/src/commands/cmd_lusers.cpp +++ b/src/commands/cmd_lusers.cpp @@ -26,10 +26,10 @@ struct LusersCounters unsigned int max_global; unsigned int invisible; - LusersCounters() + LusersCounters(unsigned int inv) : max_local(ServerInstance->Users->LocalUserCount()) , max_global(ServerInstance->Users->RegisteredUserCount()) - , invisible(ServerInstance->Users->ModeCount('i')) + , invisible(inv) { } @@ -73,11 +73,11 @@ class CommandLusers : public Command CmdResult CommandLusers::Handle (const std::vector<std::string>&, User *user) { unsigned int n_users = ServerInstance->Users->RegisteredUserCount(); - ProtoServerList serverlist; + ProtocolInterface::ServerList serverlist; ServerInstance->PI->GetServerList(serverlist); unsigned int n_serv = serverlist.size(); unsigned int n_local_servs = 0; - for(ProtoServerList::iterator i = serverlist.begin(); i != serverlist.end(); ++i) + for (ProtocolInterface::ServerList::const_iterator i = serverlist.begin(); i != serverlist.end(); ++i) { if (i->parentname == ServerInstance->Config->ServerName) n_local_servs++; @@ -110,11 +110,11 @@ class InvisibleWatcher : public ModeWatcher unsigned int& invisible; public: InvisibleWatcher(Module* mod, unsigned int& Invisible) - : ModeWatcher(mod, 'i', MODETYPE_USER), invisible(Invisible) + : ModeWatcher(mod, "invisible", MODETYPE_USER), invisible(Invisible) { } - void AfterMode(User* source, User* dest, Channel* channel, const std::string& parameter, bool adding, ModeType type) + void AfterMode(User* source, User* dest, Channel* channel, const std::string& parameter, bool adding) { if (dest->registered != REG_ALL) return; @@ -128,34 +128,48 @@ public: class ModuleLusers : public Module { + UserModeReference invisiblemode; LusersCounters counters; CommandLusers cmd; InvisibleWatcher mw; + unsigned int CountInvisible() + { + unsigned int c = 0; + for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); ++i) + { + User* u = i->second; + if (u->IsModeSet(invisiblemode)) + c++; + } + return c; + } + public: ModuleLusers() - : cmd(this, counters), mw(this, counters.invisible) + : invisiblemode(this, "invisible") + , counters(CountInvisible()) + , cmd(this, counters) + , mw(this, counters.invisible) { } void init() { ServerInstance->Modules->AddService(cmd); - Implementation events[] = { I_OnPostConnect, I_OnUserQuit }; - ServerInstance->Modules->Attach(events, this, sizeof(events)/sizeof(Implementation)); ServerInstance->Modes->AddModeWatcher(&mw); } void OnPostConnect(User* user) { counters.UpdateMaxUsers(); - if (user->IsModeSet('i')) + if (user->IsModeSet(invisiblemode)) counters.invisible++; } void OnUserQuit(User* user, const std::string& message, const std::string& oper_message) { - if (user->IsModeSet('i')) + if (user->IsModeSet(invisiblemode)) counters.invisible--; } diff --git a/src/commands/cmd_map.cpp b/src/commands/cmd_map.cpp deleted file mode 100644 index 385a2c752..000000000 --- a/src/commands/cmd_map.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> - * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "inspircd.h" - -class CommandMap : public Command -{ - public: - /** Constructor for map. - */ - CommandMap ( Module* parent) : Command(parent,"MAP",0,0) { Penalty=2; } - /** Handle command. - * @param parameters The parameters to the comamnd - * @param pcnt The number of parameters passed to teh command - * @param user The user issuing the command - * @return A value from CmdResult to indicate command success or failure. - */ - CmdResult Handle(const std::vector<std::string>& parameters, User *user); -}; - -/** Handle /MAP - */ -CmdResult CommandMap::Handle (const std::vector<std::string>&, User *user) -{ - // as with /LUSERS this does nothing without a linking - // module to override its behaviour and display something - // better. - - if (IS_OPER(user)) - { - user->WriteNumeric(006, "%s :%s [%s]", user->nick.c_str(), ServerInstance->Config->ServerName.c_str(), ServerInstance->Config->GetSID().c_str()); - user->WriteNumeric(007, "%s :End of /MAP", user->nick.c_str()); - return CMD_SUCCESS; - } - user->WriteNumeric(006, "%s :%s",user->nick.c_str(),ServerInstance->Config->ServerName.c_str()); - user->WriteNumeric(007, "%s :End of /MAP",user->nick.c_str()); - - return CMD_SUCCESS; -} - -COMMAND_INIT(CommandMap) diff --git a/src/commands/cmd_mode.cpp b/src/commands/cmd_mode.cpp index 17e21b182..1a42835e5 100644 --- a/src/commands/cmd_mode.cpp +++ b/src/commands/cmd_mode.cpp @@ -38,6 +38,10 @@ class CommandMode : public Command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(const std::vector<std::string>& parameters, User *user); + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) + { + return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST); + } }; @@ -45,7 +49,7 @@ class CommandMode : public Command */ CmdResult CommandMode::Handle (const std::vector<std::string>& parameters, User *user) { - ServerInstance->Modes->Process(parameters, user, false); + ServerInstance->Modes->Process(parameters, user, (IS_LOCAL(user) ? ModeParser::MODE_NONE : ModeParser::MODE_LOCALONLY)); return CMD_SUCCESS; } diff --git a/src/commands/cmd_motd.cpp b/src/commands/cmd_motd.cpp index 8e227723e..b28e57b2f 100644 --- a/src/commands/cmd_motd.cpp +++ b/src/commands/cmd_motd.cpp @@ -54,8 +54,9 @@ CmdResult CommandMotd::Handle (const std::vector<std::string>& parameters, User return CMD_SUCCESS; ConfigTag* tag = NULL; - if (IS_LOCAL(user)) - tag = user->GetClass()->config; + LocalUser* localuser = IS_LOCAL(user); + if (localuser) + tag = localuser->GetClass()->config; std::string motd_name = tag->getString("motd", "motd"); ConfigFileCache::iterator motd = ServerInstance->Config->Files.find(motd_name); if (motd == ServerInstance->Config->Files.end()) diff --git a/src/commands/cmd_names.cpp b/src/commands/cmd_names.cpp index 0c06b636f..c74d18c23 100644 --- a/src/commands/cmd_names.cpp +++ b/src/commands/cmd_names.cpp @@ -27,10 +27,18 @@ */ class CommandNames : public Command { + ChanModeReference secretmode; + public: /** Constructor for names. */ - CommandNames ( Module* parent) : Command(parent,"NAMES",0,0) { syntax = "{<channel>{,<channel>}}"; } + CommandNames(Module* parent) + : Command(parent, "NAMES", 0, 0) + , secretmode(parent, "secret") + { + syntax = "{<channel>{,<channel>}}"; + } + /** Handle command. * @param parameters The parameters to the comamnd * @param pcnt The number of parameters passed to teh command @@ -52,13 +60,13 @@ CmdResult CommandNames::Handle (const std::vector<std::string>& parameters, User return CMD_SUCCESS; } - if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) + if (CommandParser::LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; c = ServerInstance->FindChan(parameters[0]); if (c) { - if ((c->IsModeSet('s')) && (!c->HasUser(user))) + if ((c->IsModeSet(secretmode)) && (!c->HasUser(user))) { user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), c->name.c_str()); return CMD_FAILURE; diff --git a/src/commands/cmd_nick.cpp b/src/commands/cmd_nick.cpp index a079e59d0..e58aab986 100644 --- a/src/commands/cmd_nick.cpp +++ b/src/commands/cmd_nick.cpp @@ -66,7 +66,7 @@ CmdResult CommandNick::Handle (const std::vector<std::string>& parameters, User { newnick = user->uuid; } - else if (!ServerInstance->IsNick(newnick.c_str(), ServerInstance->Config->Limits.NickMax)) + else if (!ServerInstance->IsNick(newnick)) { user->WriteNumeric(432, "%s %s :Erroneous Nickname", user->nick.c_str(),newnick.c_str()); return CMD_FAILURE; diff --git a/src/commands/cmd_notice.cpp b/src/commands/cmd_notice.cpp deleted file mode 100644 index d5ef7ba1d..000000000 --- a/src/commands/cmd_notice.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> - * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> - * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "inspircd.h" -/** Handle /NOTICE. These command handlers can be reloaded by the core, - * and handle basic RFC1459 commands. Commands within modules work - * the same way, however, they can be fully unloaded, where these - * may not. - */ -class CommandNotice : public Command -{ - public: - /** Constructor for notice. - */ - CommandNotice ( Module* parent) : Command(parent,"NOTICE",2,2) { syntax = "<target>{,<target>} <message>"; } - /** Handle command. - * @param parameters The parameters to the comamnd - * @param pcnt The number of parameters passed to teh command - * @param user The user issuing the command - * @return A value from CmdResult to indicate command success or failure. - */ - CmdResult Handle(const std::vector<std::string>& parameters, User *user); - - RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) - { - if (IS_LOCAL(user)) - // This is handled by the OnUserNotice hook to split the LoopCall pieces - return ROUTE_LOCALONLY; - else - return ROUTE_MESSAGE(parameters[0]); - } -}; - - -CmdResult CommandNotice::Handle (const std::vector<std::string>& parameters, User *user) -{ - User *dest; - Channel *chan; - - CUList exempt_list; - - user->idle_lastmsg = ServerInstance->Time(); - - if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) - return CMD_SUCCESS; - if (parameters[0][0] == '$') - { - if (!user->HasPrivPermission("users/mass-message")) - return CMD_SUCCESS; - - ModResult MOD_RESULT; - std::string temp = parameters[1]; - FIRST_MOD_RESULT(OnUserPreNotice, MOD_RESULT, (user, (void*)parameters[0].c_str(), TYPE_SERVER, temp, 0, exempt_list)); - if (MOD_RESULT == MOD_RES_DENY) - return CMD_FAILURE; - const char* text = temp.c_str(); - const char* servermask = (parameters[0].c_str()) + 1; - - FOREACH_MOD(I_OnText,OnText(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, exempt_list)); - if (InspIRCd::Match(ServerInstance->Config->ServerName,servermask, NULL)) - { - user->SendAll("NOTICE", "%s", text); - } - FOREACH_MOD(I_OnUserNotice,OnUserNotice(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, exempt_list)); - return CMD_SUCCESS; - } - char status = 0; - const char* target = parameters[0].c_str(); - - if (ServerInstance->Modes->FindPrefix(*target)) - { - status = *target; - target++; - } - if (*target == '#') - { - chan = ServerInstance->FindChan(target); - - exempt_list.insert(user); - - if (chan) - { - if (IS_LOCAL(user)) - { - if ((chan->IsModeSet('n')) && (!chan->HasUser(user))) - { - user->WriteNumeric(404, "%s %s :Cannot send to channel (no external messages)", user->nick.c_str(), chan->name.c_str()); - return CMD_FAILURE; - } - if ((chan->IsModeSet('m')) && (chan->GetPrefixValue(user) < VOICE_VALUE)) - { - user->WriteNumeric(404, "%s %s :Cannot send to channel (+m)", user->nick.c_str(), chan->name.c_str()); - return CMD_FAILURE; - } - - if (ServerInstance->Config->RestrictBannedUsers) - { - if (chan->IsBanned(user)) - { - user->WriteNumeric(404, "%s %s :Cannot send to channel (you're banned)", user->nick.c_str(), chan->name.c_str()); - return CMD_FAILURE; - } - } - } - ModResult MOD_RESULT; - - std::string temp = parameters[1]; - FIRST_MOD_RESULT(OnUserPreNotice, MOD_RESULT, (user,chan,TYPE_CHANNEL,temp,status, exempt_list)); - if (MOD_RESULT == MOD_RES_DENY) - return CMD_FAILURE; - - const char* text = temp.c_str(); - - if (temp.empty()) - { - user->WriteNumeric(412, "%s :No text to send", user->nick.c_str()); - return CMD_FAILURE; - } - - FOREACH_MOD(I_OnText,OnText(user,chan,TYPE_CHANNEL,text,status,exempt_list)); - - if (status) - { - if (ServerInstance->Config->UndernetMsgPrefix) - { - chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%c %s", status, chan->name.c_str(), status, text); - } - else - { - chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%s", status, chan->name.c_str(), text); - } - } - else - { - chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %s :%s", chan->name.c_str(), text); - } - - FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,chan,TYPE_CHANNEL,text,status,exempt_list)); - } - else - { - /* no such nick/channel */ - user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), target); - return CMD_FAILURE; - } - return CMD_SUCCESS; - } - - const char* destnick = parameters[0].c_str(); - - if (IS_LOCAL(user)) - { - const char* targetserver = strchr(destnick, '@'); - - if (targetserver) - { - std::string nickonly; - - nickonly.assign(destnick, 0, targetserver - destnick); - dest = ServerInstance->FindNickOnly(nickonly); - if (dest && strcasecmp(dest->server.c_str(), targetserver + 1)) - { - /* Incorrect server for user */ - user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); - return CMD_FAILURE; - } - } - else - dest = ServerInstance->FindNickOnly(destnick); - } - else - dest = ServerInstance->FindNick(destnick); - - if ((dest) && (dest->registered == REG_ALL)) - { - if (parameters[1].empty()) - { - user->WriteNumeric(412, "%s :No text to send", user->nick.c_str()); - return CMD_FAILURE; - } - - ModResult MOD_RESULT; - std::string temp = parameters[1]; - FIRST_MOD_RESULT(OnUserPreNotice, MOD_RESULT, (user,dest,TYPE_USER,temp,0,exempt_list)); - if (MOD_RESULT == MOD_RES_DENY) { - return CMD_FAILURE; - } - const char* text = temp.c_str(); - - FOREACH_MOD(I_OnText,OnText(user,dest,TYPE_USER,text,0,exempt_list)); - - if (IS_LOCAL(dest)) - { - // direct write, same server - user->WriteTo(dest, "NOTICE %s :%s", dest->nick.c_str(), text); - } - - FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,dest,TYPE_USER,text,0,exempt_list)); - } - else - { - /* no such nick/channel */ - user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); - return CMD_FAILURE; - } - - return CMD_SUCCESS; - -} - -COMMAND_INIT(CommandNotice) diff --git a/src/commands/cmd_oper.cpp b/src/commands/cmd_oper.cpp index 1a5e7e178..e1018f805 100644 --- a/src/commands/cmd_oper.cpp +++ b/src/commands/cmd_oper.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -bool OneOfMatches(const char* host, const char* ip, const char* hostlist); - /** Handle /OPER. These command handlers can be reloaded by the core, * and handle basic RFC1459 commands. Commands within modules work * the same way, however, they can be fully unloaded, where these @@ -43,30 +41,14 @@ class CommandOper : public SplitCommand CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser *user); }; -bool OneOfMatches(const char* host, const char* ip, const std::string& hostlist) -{ - std::stringstream hl(hostlist); - std::string xhost; - while (hl >> xhost) - { - if (InspIRCd::Match(host, xhost, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(ip, xhost, ascii_case_insensitive_map)) - { - return true; - } - } - return false; -} - CmdResult CommandOper::HandleLocal(const std::vector<std::string>& parameters, LocalUser *user) { - char TheHost[MAXBUF]; - char TheIP[MAXBUF]; bool match_login = false; bool match_pass = false; bool match_hosts = false; - snprintf(TheHost,MAXBUF,"%s@%s",user->ident.c_str(),user->host.c_str()); - snprintf(TheIP, MAXBUF,"%s@%s",user->ident.c_str(),user->GetIPString()); + const std::string userHost = user->ident + "@" + user->host; + const std::string userIP = user->ident + "@" + user->GetIPString(); OperIndex::iterator i = ServerInstance->Config->oper_blocks.find(parameters[0]); if (i != ServerInstance->Config->oper_blocks.end()) @@ -75,7 +57,7 @@ CmdResult CommandOper::HandleLocal(const std::vector<std::string>& parameters, L ConfigTag* tag = ifo->oper_block; match_login = true; match_pass = !ServerInstance->PassCompare(user, tag->getString("password"), parameters[1], tag->getString("hash")); - match_hosts = OneOfMatches(TheHost,TheIP,tag->getString("host")); + match_hosts = InspIRCd::MatchMask(tag->getString("host"), userHost, userIP); if (match_pass && match_hosts) { @@ -98,7 +80,7 @@ CmdResult CommandOper::HandleLocal(const std::vector<std::string>& parameters, L user->CommandFloodPenalty += 10000; ServerInstance->SNO->WriteGlobalSno('o', "WARNING! Failed oper attempt by %s using login '%s': The following fields do not match: %s", user->GetFullRealHost().c_str(), parameters[0].c_str(), fields.c_str()); - ServerInstance->Logs->Log("OPER",DEFAULT,"OPER: Failed oper attempt by %s using login '%s': The following fields did not match: %s", user->GetFullRealHost().c_str(), parameters[0].c_str(), fields.c_str()); + ServerInstance->Logs->Log("OPER", LOG_DEFAULT, "OPER: Failed oper attempt by %s using login '%s': The following fields did not match: %s", user->GetFullRealHost().c_str(), parameters[0].c_str(), fields.c_str()); return CMD_FAILURE; } diff --git a/src/commands/cmd_part.cpp b/src/commands/cmd_part.cpp index aadb42d90..adf9da727 100644 --- a/src/commands/cmd_part.cpp +++ b/src/commands/cmd_part.cpp @@ -38,6 +38,10 @@ class CommandPart : public Command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(const std::vector<std::string>& parameters, User *user); + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) + { + return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST); + } }; CmdResult CommandPart::Handle (const std::vector<std::string>& parameters, User *user) @@ -57,7 +61,7 @@ CmdResult CommandPart::Handle (const std::vector<std::string>& parameters, User reason = parameters[1]; } - if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) + if (CommandParser::LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; Channel* c = ServerInstance->FindChan(parameters[0]); diff --git a/src/commands/cmd_privmsg.cpp b/src/commands/cmd_privmsg.cpp index cefdd4800..ed98c771f 100644 --- a/src/commands/cmd_privmsg.cpp +++ b/src/commands/cmd_privmsg.cpp @@ -21,24 +21,31 @@ #include "inspircd.h" -/** Handle /PRIVMSG. These command handlers can be reloaded by the core, - * and handle basic RFC1459 commands. Commands within modules work - * the same way, however, they can be fully unloaded, where these - * may not. - */ -class CommandPrivmsg : public Command +namespace +{ + const char* MessageTypeString[] = { "PRIVMSG", "NOTICE" }; +} + +class MessageCommandBase : public Command { + ChanModeReference moderatedmode; + ChanModeReference noextmsgmode; + public: - /** Constructor for privmsg. - */ - CommandPrivmsg ( Module* parent) : Command(parent,"PRIVMSG",2,2) { syntax = "<target>{,<target>} <message>"; } + MessageCommandBase(Module* parent, MessageType mt) + : Command(parent, MessageTypeString[mt], 2, 2) + , moderatedmode(parent, "moderated") + , noextmsgmode(parent, "noextmsg") + { + syntax = "<target>{,<target>} <message>"; + } + /** Handle command. * @param parameters The parameters to the comamnd - * @param pcnt The number of parameters passed to teh command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ - CmdResult Handle(const std::vector<std::string>& parameters, User *user); + CmdResult HandleMessage(const std::vector<std::string>& parameters, User* user, MessageType mt); RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { @@ -50,15 +57,17 @@ class CommandPrivmsg : public Command } }; -CmdResult CommandPrivmsg::Handle (const std::vector<std::string>& parameters, User *user) +CmdResult MessageCommandBase::HandleMessage(const std::vector<std::string>& parameters, User* user, MessageType mt) { User *dest; Channel *chan; CUList except_list; - user->idle_lastmsg = ServerInstance->Time(); + LocalUser* localuser = IS_LOCAL(user); + if (localuser) + localuser->idle_lastmsg = ServerInstance->Time(); - if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) + if (CommandParser::LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; if (parameters[0][0] == '$') @@ -68,19 +77,19 @@ CmdResult CommandPrivmsg::Handle (const std::vector<std::string>& parameters, Us ModResult MOD_RESULT; std::string temp = parameters[1]; - FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, (void*)parameters[0].c_str(), TYPE_SERVER, temp, 0, except_list)); + FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, (void*)parameters[0].c_str(), TYPE_SERVER, temp, 0, except_list, mt)); if (MOD_RESULT == MOD_RES_DENY) return CMD_FAILURE; const char* text = temp.c_str(); const char* servermask = (parameters[0].c_str()) + 1; - FOREACH_MOD(I_OnText,OnText(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list)); + FOREACH_MOD(OnText, (user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list)); if (InspIRCd::Match(ServerInstance->Config->ServerName, servermask, NULL)) { - user->SendAll("PRIVMSG", "%s", text); + user->SendAll(MessageTypeString[mt], "%s", text); } - FOREACH_MOD(I_OnUserMessage,OnUserMessage(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list)); + FOREACH_MOD(OnUserMessage, (user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list, mt)); return CMD_SUCCESS; } char status = 0; @@ -99,15 +108,15 @@ CmdResult CommandPrivmsg::Handle (const std::vector<std::string>& parameters, Us if (chan) { - if (IS_LOCAL(user) && chan->GetPrefixValue(user) < VOICE_VALUE) + if (localuser && chan->GetPrefixValue(user) < VOICE_VALUE) { - if (chan->IsModeSet('n') && !chan->HasUser(user)) + if (chan->IsModeSet(noextmsgmode) && !chan->HasUser(user)) { user->WriteNumeric(404, "%s %s :Cannot send to channel (no external messages)", user->nick.c_str(), chan->name.c_str()); return CMD_FAILURE; } - if (chan->IsModeSet('m')) + if (chan->IsModeSet(moderatedmode)) { user->WriteNumeric(404, "%s %s :Cannot send to channel (+m)", user->nick.c_str(), chan->name.c_str()); return CMD_FAILURE; @@ -125,7 +134,7 @@ CmdResult CommandPrivmsg::Handle (const std::vector<std::string>& parameters, Us ModResult MOD_RESULT; std::string temp = parameters[1]; - FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user,chan,TYPE_CHANNEL,temp,status,except_list)); + FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, chan, TYPE_CHANNEL, temp, status, except_list, mt)); if (MOD_RESULT == MOD_RES_DENY) return CMD_FAILURE; @@ -138,25 +147,25 @@ CmdResult CommandPrivmsg::Handle (const std::vector<std::string>& parameters, Us return CMD_FAILURE; } - FOREACH_MOD(I_OnText,OnText(user,chan,TYPE_CHANNEL,text,status,except_list)); + FOREACH_MOD(OnText, (user,chan,TYPE_CHANNEL,text,status,except_list)); if (status) { if (ServerInstance->Config->UndernetMsgPrefix) { - chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%c %s", status, chan->name.c_str(), status, text); + chan->WriteAllExcept(user, false, status, except_list, "%s %c%s :%c %s", MessageTypeString[mt], status, chan->name.c_str(), status, text); } else { - chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%s", status, chan->name.c_str(), text); + chan->WriteAllExcept(user, false, status, except_list, "%s %c%s :%s", MessageTypeString[mt], status, chan->name.c_str(), text); } } else { - chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %s :%s", chan->name.c_str(), text); + chan->WriteAllExcept(user, false, status, except_list, "%s %s :%s", MessageTypeString[mt], chan->name.c_str(), text); } - FOREACH_MOD(I_OnUserMessage,OnUserMessage(user,chan,TYPE_CHANNEL,text,status,except_list)); + FOREACH_MOD(OnUserMessage, (user,chan, TYPE_CHANNEL, text, status, except_list, mt)); } else { @@ -169,7 +178,7 @@ CmdResult CommandPrivmsg::Handle (const std::vector<std::string>& parameters, Us const char* destnick = parameters[0].c_str(); - if (IS_LOCAL(user)) + if (localuser) { const char* targetserver = strchr(destnick, '@'); @@ -200,7 +209,7 @@ CmdResult CommandPrivmsg::Handle (const std::vector<std::string>& parameters, Us return CMD_FAILURE; } - if (IS_AWAY(dest)) + if ((dest->IsAway()) && (mt == MSG_PRIVMSG)) { /* auto respond with aweh msg */ user->WriteNumeric(301, "%s %s :%s", user->nick.c_str(), dest->nick.c_str(), dest->awaymsg.c_str()); @@ -209,21 +218,21 @@ CmdResult CommandPrivmsg::Handle (const std::vector<std::string>& parameters, Us ModResult MOD_RESULT; std::string temp = parameters[1]; - FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, dest, TYPE_USER, temp, 0, except_list)); + FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, dest, TYPE_USER, temp, 0, except_list, mt)); if (MOD_RESULT == MOD_RES_DENY) return CMD_FAILURE; const char* text = temp.c_str(); - FOREACH_MOD(I_OnText,OnText(user, dest, TYPE_USER, text, 0, except_list)); + FOREACH_MOD(OnText, (user, dest, TYPE_USER, text, 0, except_list)); if (IS_LOCAL(dest)) { // direct write, same server - user->WriteTo(dest, "PRIVMSG %s :%s", dest->nick.c_str(), text); + user->WriteTo(dest, "%s %s :%s", MessageTypeString[mt], dest->nick.c_str(), text); } - FOREACH_MOD(I_OnUserMessage,OnUserMessage(user, dest, TYPE_USER, text, 0, except_list)); + FOREACH_MOD(OnUserMessage, (user, dest, TYPE_USER, text, 0, except_list, mt)); } else { @@ -234,4 +243,42 @@ CmdResult CommandPrivmsg::Handle (const std::vector<std::string>& parameters, Us return CMD_SUCCESS; } -COMMAND_INIT(CommandPrivmsg) +template<MessageType MT> +class CommandMessage : public MessageCommandBase +{ + public: + CommandMessage(Module* parent) + : MessageCommandBase(parent, MT) + { + } + + CmdResult Handle(const std::vector<std::string>& parameters, User* user) + { + return HandleMessage(parameters, user, MT); + } +}; + +class ModuleCoreMessage : public Module +{ + CommandMessage<MSG_PRIVMSG> CommandPrivmsg; + CommandMessage<MSG_NOTICE> CommandNotice; + + public: + ModuleCoreMessage() + : CommandPrivmsg(this), CommandNotice(this) + { + } + + void init() + { + ServerInstance->Modules->AddService(CommandPrivmsg); + ServerInstance->Modules->AddService(CommandNotice); + } + + Version GetVersion() + { + return Version("PRIVMSG, NOTICE", VF_CORE|VF_VENDOR); + } +}; + +MODULE_INIT(ModuleCoreMessage) diff --git a/src/commands/cmd_qline.cpp b/src/commands/cmd_qline.cpp index 3118798e6..bfc9e4519 100644 --- a/src/commands/cmd_qline.cpp +++ b/src/commands/cmd_qline.cpp @@ -48,11 +48,11 @@ CmdResult CommandQline::Handle (const std::vector<std::string>& parameters, User if (parameters[0].find('@') != std::string::npos || parameters[0].find('!') != std::string::npos || parameters[0].find('.') != std::string::npos) { - user->WriteServ("NOTICE %s :*** A Q-Line only bans a nick pattern, not a nick!user@host pattern.",user->nick.c_str()); + user->WriteNotice("*** A Q-Line only bans a nick pattern, not a nick!user@host pattern."); return CMD_FAILURE; } - long duration = ServerInstance->Duration(parameters[1].c_str()); + unsigned long duration = InspIRCd::Duration(parameters[1]); QLine* ql = new QLine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), parameters[0].c_str()); if (ServerInstance->XLines->AddLine(ql,user)) { @@ -72,7 +72,7 @@ CmdResult CommandQline::Handle (const std::vector<std::string>& parameters, User else { delete ql; - user->WriteServ("NOTICE %s :*** Q-Line for %s already exists",user->nick.c_str(),parameters[0].c_str()); + user->WriteNotice("*** Q-Line for " + parameters[0] + " already exists"); } } else @@ -83,7 +83,7 @@ CmdResult CommandQline::Handle (const std::vector<std::string>& parameters, User } else { - user->WriteServ("NOTICE %s :*** Q-Line %s not found in list, try /stats q.",user->nick.c_str(),parameters[0].c_str()); + user->WriteNotice("*** Q-Line " + parameters[0] + " not found in list, try /stats q."); return CMD_FAILURE; } } diff --git a/src/commands/cmd_quit.cpp b/src/commands/cmd_quit.cpp index 6a6b447e5..61a88e2b5 100644 --- a/src/commands/cmd_quit.cpp +++ b/src/commands/cmd_quit.cpp @@ -38,6 +38,10 @@ class CommandQuit : public Command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(const std::vector<std::string>& parameters, User *user); + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) + { + return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST); + } }; diff --git a/src/commands/cmd_rehash.cpp b/src/commands/cmd_rehash.cpp index abf0b7876..3dc454036 100644 --- a/src/commands/cmd_rehash.cpp +++ b/src/commands/cmd_rehash.cpp @@ -45,7 +45,7 @@ CmdResult CommandRehash::Handle (const std::vector<std::string>& parameters, Use { std::string param = parameters.size() ? parameters[0] : ""; - FOREACH_MOD(I_OnPreRehash,OnPreRehash(user, param)); + FOREACH_MOD(OnPreRehash, (user, param)); if (param.empty()) { @@ -68,7 +68,7 @@ CmdResult CommandRehash::Handle (const std::vector<std::string>& parameters, Use if (param[0] == '-') param = param.substr(1); - FOREACH_MOD(I_OnModuleRehash,OnModuleRehash(user, param)); + FOREACH_MOD(OnModuleRehash, (user, param)); return CMD_SUCCESS; } @@ -88,8 +88,7 @@ CmdResult CommandRehash::Handle (const std::vector<std::string>& parameters, Use /* Don't do anything with the logs here -- logs are restarted * after the config thread has completed. */ - ServerInstance->RehashUsersAndChans(); - FOREACH_MOD(I_OnGarbageCollect, OnGarbageCollect()); + FOREACH_MOD(OnGarbageCollect, ()); ServerInstance->ConfigThread = new ConfigReaderThread(user->uuid); @@ -102,7 +101,7 @@ CmdResult CommandRehash::Handle (const std::vector<std::string>& parameters, Use * XXX, todo: we should find some way to kill runaway rehashes that are blocking, this is a major problem for unrealircd users */ if (IS_LOCAL(user)) - user->WriteServ("NOTICE %s :*** Could not rehash: A rehash is already in progress.", user->nick.c_str()); + user->WriteNotice("*** Could not rehash: A rehash is already in progress."); else ServerInstance->PI->SendUserNotice(user, "*** Could not rehash: A rehash is already in progress."); } diff --git a/src/commands/cmd_restart.cpp b/src/commands/cmd_restart.cpp index bdbcfed35..6711ada7d 100644 --- a/src/commands/cmd_restart.cpp +++ b/src/commands/cmd_restart.cpp @@ -39,7 +39,7 @@ class CommandRestart : public Command CmdResult CommandRestart::Handle (const std::vector<std::string>& parameters, User *user) { - ServerInstance->Logs->Log("COMMAND",DEFAULT,"Restart: %s",user->nick.c_str()); + ServerInstance->Logs->Log("COMMAND", LOG_DEFAULT, "Restart: %s",user->nick.c_str()); if (!ServerInstance->PassCompare(user, ServerInstance->Config->restartpass, parameters[0].c_str(), ServerInstance->Config->powerhash)) { ServerInstance->SNO->WriteGlobalSno('a', "RESTART command from %s, restarting server.", user->GetFullRealHost().c_str()); diff --git a/src/commands/cmd_rules.cpp b/src/commands/cmd_rules.cpp index 5d41aa4b8..76ee0061b 100644 --- a/src/commands/cmd_rules.cpp +++ b/src/commands/cmd_rules.cpp @@ -52,8 +52,9 @@ CmdResult CommandRules::Handle (const std::vector<std::string>& parameters, User return CMD_SUCCESS; ConfigTag* tag = NULL; - if (IS_LOCAL(user)) - tag = user->GetClass()->config; + LocalUser* localuser = IS_LOCAL(user); + if (localuser) + tag = localuser->GetClass()->config; std::string rules_name = tag->getString("rules", "rules"); ConfigFileCache::iterator rules = ServerInstance->Config->Files.find(rules_name); if (rules == ServerInstance->Config->Files.end()) diff --git a/src/commands/cmd_stats.cpp b/src/commands/cmd_stats.cpp index 898e89a7d..846af57db 100644 --- a/src/commands/cmd_stats.cpp +++ b/src/commands/cmd_stats.cpp @@ -21,7 +21,6 @@ #include "inspircd.h" #include "xline.h" -#include "commands/cmd_whowas.h" #ifdef _WIN32 #include <psapi.h> @@ -60,7 +59,7 @@ void CommandStats::DoStats(char statschar, User* user, string_list &results) std::string sn(ServerInstance->Config->ServerName); bool isPublic = ServerInstance->Config->UserStats.find(statschar) != std::string::npos; - bool isRemoteOper = IS_REMOTE(user) && IS_OPER(user); + bool isRemoteOper = IS_REMOTE(user) && (user->IsOper()); bool isLocalOperWithPrivs = IS_LOCAL(user) && user->HasPrivPermission("servers/auspex"); if (!isPublic && !isRemoteOper && !isLocalOperWithPrivs) @@ -167,8 +166,9 @@ void CommandStats::DoStats(char statschar, User* user, string_list &results) User* oper = *i; if (!ServerInstance->ULine(oper->server)) { + LocalUser* lu = IS_LOCAL(oper); results.push_back(sn+" 249 " + user->nick + " :" + oper->nick + " (" + oper->ident + "@" + oper->dhost + ") Idle: " + - (IS_LOCAL(oper) ? ConvToStr(ServerInstance->Time() - oper->idle_lastmsg) + " secs" : "unavailable")); + (lu ? ConvToStr(ServerInstance->Time() - lu->idle_lastmsg) + " secs" : "unavailable")); idx++; } } @@ -205,7 +205,7 @@ void CommandStats::DoStats(char statschar, User* user, string_list &results) if (i->second->use_count) { /* RPL_STATSCOMMANDS */ - results.push_back(sn+" 212 "+user->nick+" "+i->second->name+" "+ConvToStr(i->second->use_count)+" "+ConvToStr(i->second->total_bytes)); + results.push_back(sn+" 212 "+user->nick+" "+i->second->name+" "+ConvToStr(i->second->use_count)); } } break; @@ -217,18 +217,6 @@ void CommandStats::DoStats(char statschar, User* user, string_list &results) results.push_back(sn+" 249 "+user->nick+" :Channels: "+ConvToStr(ServerInstance->chanlist->size())); results.push_back(sn+" 249 "+user->nick+" :Commands: "+ConvToStr(ServerInstance->Parser->cmdlist.size())); - if (!ServerInstance->Config->WhoWasGroupSize == 0 && !ServerInstance->Config->WhoWasMaxGroups == 0) - { - Module* whowas = ServerInstance->Modules->Find("cmd_whowas.so"); - if (whowas) - { - WhowasRequest req(NULL, whowas, WhowasRequest::WHOWAS_STATS); - req.user = user; - req.Send(); - results.push_back(sn+" 249 "+user->nick+" :"+req.value); - } - } - float kbitpersec_in, kbitpersec_out, kbitpersec_total; char kbitpersec_in_s[30], kbitpersec_out_s[30], kbitpersec_total_s[30]; @@ -283,9 +271,9 @@ void CommandStats::DoStats(char statschar, User* user, string_list &results) } FILETIME CreationTime; - FILETIME ExitTime; - FILETIME KernelTime; - FILETIME UserTime; + FILETIME ExitTime; + FILETIME KernelTime; + FILETIME UserTime; LARGE_INTEGER ThisSample; if(GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime, &KernelTime, &UserTime) && QueryPerformanceCounter(&ThisSample)) @@ -295,7 +283,7 @@ void CommandStats::DoStats(char statschar, User* user, string_list &results) double n_eaten = (double)( ( (uint64_t)(KernelTime.dwHighDateTime - ServerInstance->stats->LastCPU.dwHighDateTime) << 32 ) + (uint64_t)(KernelTime.dwLowDateTime - ServerInstance->stats->LastCPU.dwLowDateTime) )/100000; double n_elapsed = (double)(ThisSample.QuadPart - ServerInstance->stats->LastSampled.QuadPart) / ServerInstance->stats->QPFrequency.QuadPart; double per = (n_eaten/n_elapsed); - + char percent[30]; snprintf(percent, 30, "%03.5f%%", per); @@ -313,15 +301,13 @@ void CommandStats::DoStats(char statschar, User* user, string_list &results) case 'T': { - char buffer[MAXBUF]; results.push_back(sn+" 249 "+user->nick+" :accepts "+ConvToStr(ServerInstance->stats->statsAccept)+" refused "+ConvToStr(ServerInstance->stats->statsRefused)); results.push_back(sn+" 249 "+user->nick+" :unknown commands "+ConvToStr(ServerInstance->stats->statsUnknown)); results.push_back(sn+" 249 "+user->nick+" :nick collisions "+ConvToStr(ServerInstance->stats->statsCollisions)); results.push_back(sn+" 249 "+user->nick+" :dns requests "+ConvToStr(ServerInstance->stats->statsDnsGood+ServerInstance->stats->statsDnsBad)+" succeeded "+ConvToStr(ServerInstance->stats->statsDnsGood)+" failed "+ConvToStr(ServerInstance->stats->statsDnsBad)); results.push_back(sn+" 249 "+user->nick+" :connection count "+ConvToStr(ServerInstance->stats->statsConnects)); - snprintf(buffer,MAXBUF," 249 %s :bytes sent %5.2fK recv %5.2fK", - user->nick.c_str(),ServerInstance->stats->statsSent / 1024.0,ServerInstance->stats->statsRecv / 1024.0); - results.push_back(sn+buffer); + results.push_back(InspIRCd::Format("%s 249 %s :bytes sent %5.2fK recv %5.2fK", sn.c_str(), user->nick.c_str(), + ServerInstance->stats->statsSent / 1024.0, ServerInstance->stats->statsRecv / 1024.0)); } break; @@ -339,11 +325,8 @@ void CommandStats::DoStats(char statschar, User* user, string_list &results) break; case 'O': { - for(OperIndex::iterator i = ServerInstance->Config->oper_blocks.begin(); i != ServerInstance->Config->oper_blocks.end(); i++) + for (OperIndex::const_iterator i = ServerInstance->Config->OperTypes.begin(); i != ServerInstance->Config->OperTypes.end(); ++i) { - // just the types, not the actual oper blocks... - if (i->first[0] != ' ') - continue; OperInfo* tag = i->second; tag->init(); std::string umodes; @@ -357,7 +340,7 @@ void CommandStats::DoStats(char statschar, User* user, string_list &results) if (mh && mh->NeedsOper() && tag->AllowedChanModes[c - 'A']) cmodes.push_back(c); } - results.push_back(sn+" 243 "+user->nick+" O "+tag->NameStr() + " " + umodes + " " + cmodes); + results.push_back(sn+" 243 "+user->nick+" O "+tag->name.c_str() + " " + umodes + " " + cmodes); } } break; @@ -394,15 +377,15 @@ void CommandStats::DoStats(char statschar, User* user, string_list &results) * Craig suggested this, and it seemed a good idea so in it went */ if (stime->tm_year > 70) { - char buffer[MAXBUF]; - snprintf(buffer,MAXBUF," 242 %s :Server up %d years, %d days, %.2d:%.2d:%.2d",user->nick.c_str(),(stime->tm_year-70),stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec); - results.push_back(sn+buffer); + results.push_back(InspIRCd::Format("%s 242 %s :Server up %d years, %d days, %.2d:%.2d:%.2d", + sn.c_str(), user->nick.c_str(), stime->tm_year - 70, stime->tm_yday, stime->tm_hour, + stime->tm_min, stime->tm_sec)); } else { - char buffer[MAXBUF]; - snprintf(buffer,MAXBUF," 242 %s :Server up %d days, %.2d:%.2d:%.2d",user->nick.c_str(),stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec); - results.push_back(sn+buffer); + results.push_back(InspIRCd::Format("%s 242 %s :Server up %d days, %.2d:%.2d:%.2d", + sn.c_str(), user->nick.c_str(), stime->tm_yday, stime->tm_hour, stime->tm_min, + stime->tm_sec)); } } break; diff --git a/src/commands/cmd_time.cpp b/src/commands/cmd_time.cpp index db452d381..8c516ac42 100644 --- a/src/commands/cmd_time.cpp +++ b/src/commands/cmd_time.cpp @@ -50,16 +50,13 @@ CmdResult CommandTime::Handle (const std::vector<std::string>& parameters, User { if (parameters.size() > 0 && parameters[0] != ServerInstance->Config->ServerName) return CMD_SUCCESS; - struct tm* timeinfo; - time_t local = ServerInstance->Time(); - - timeinfo = localtime(&local); - char tms[26]; - snprintf(tms,26,"%s",asctime(timeinfo)); - tms[24] = 0; + time_t local = ServerInstance->Time(); + struct tm* timeinfo = localtime(&local); + const std::string& humanTime = asctime(timeinfo); - user->SendText(":%s %03d %s %s :%s", ServerInstance->Config->ServerName.c_str(), RPL_TIME, user->nick.c_str(),ServerInstance->Config->ServerName.c_str(),tms); + user->SendText(":%s %03d %s %s :%s", ServerInstance->Config->ServerName.c_str(), RPL_TIME, user->nick.c_str(), + ServerInstance->Config->ServerName.c_str(), humanTime.c_str()); return CMD_SUCCESS; } diff --git a/src/commands/cmd_topic.cpp b/src/commands/cmd_topic.cpp index 412ca1c06..8f5979865 100644 --- a/src/commands/cmd_topic.cpp +++ b/src/commands/cmd_topic.cpp @@ -27,26 +27,35 @@ * the same way, however, they can be fully unloaded, where these * may not. */ -class CommandTopic : public Command +class CommandTopic : public SplitCommand { + ChanModeReference secretmode; + ChanModeReference topiclockmode; + public: /** Constructor for topic. */ - CommandTopic ( Module* parent) : Command(parent,"TOPIC",1, 2) { syntax = "<channel> [<topic>]"; Penalty = 2; } + CommandTopic(Module* parent) + : SplitCommand(parent, "TOPIC", 1, 2) + , secretmode(parent, "secret") + , topiclockmode(parent, "topiclock") + { + syntax = "<channel> [<topic>]"; + Penalty = 2; + } + /** Handle command. * @param parameters The parameters to the comamnd * @param pcnt The number of parameters passed to teh command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ - CmdResult Handle(const std::vector<std::string>& parameters, User *user); + CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user); }; -CmdResult CommandTopic::Handle (const std::vector<std::string>& parameters, User *user) +CmdResult CommandTopic::HandleLocal(const std::vector<std::string>& parameters, LocalUser* user) { - Channel* c; - - c = ServerInstance->FindChan(parameters[0]); + Channel* c = ServerInstance->FindChan(parameters[0]); if (!c) { user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); @@ -57,7 +66,7 @@ CmdResult CommandTopic::Handle (const std::vector<std::string>& parameters, User { if (c) { - if ((c->IsModeSet('s')) && (!c->HasUser(user))) + if ((c->IsModeSet(secretmode)) && (!c->HasUser(user))) { user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), c->name.c_str()); return CMD_FAILURE; @@ -75,12 +84,28 @@ CmdResult CommandTopic::Handle (const std::vector<std::string>& parameters, User } return CMD_SUCCESS; } - else if (parameters.size()>1) + + std::string t = parameters[1]; // needed, in case a module wants to change it + ModResult res; + FIRST_MOD_RESULT(OnPreTopicChange, res, (user,c,t)); + + if (res == MOD_RES_DENY) + return CMD_FAILURE; + if (res != MOD_RES_ALLOW) { - std::string t = parameters[1]; // needed, in case a module wants to change it - c->SetTopic(user, t); + if (!c->HasUser(user)) + { + user->WriteNumeric(442, "%s %s :You're not on that channel!", user->nick.c_str(), c->name.c_str()); + return CMD_FAILURE; + } + if (c->IsModeSet(topiclockmode) && !ServerInstance->OnCheckExemption(user, c, "topiclock").check(c->GetPrefixValue(user) >= HALFOP_VALUE)) + { + user->WriteNumeric(482, "%s %s :You do not have access to change the topic on this channel", user->nick.c_str(), c->name.c_str()); + return CMD_FAILURE; + } } + c->SetTopic(user, t); return CMD_SUCCESS; } diff --git a/src/commands/cmd_unloadmodule.cpp b/src/commands/cmd_unloadmodule.cpp index 6d0f5f41c..29f454987 100644 --- a/src/commands/cmd_unloadmodule.cpp +++ b/src/commands/cmd_unloadmodule.cpp @@ -42,12 +42,19 @@ class CommandUnloadmodule : public Command CmdResult CommandUnloadmodule::Handle (const std::vector<std::string>& parameters, User *user) { + if (!ServerInstance->Config->ConfValue("security")->getBool("allowcoreunload") && + InspIRCd::Match(parameters[0], "cmd_*.so", ascii_case_insensitive_map)) + { + user->WriteNumeric(972, "%s %s :You cannot unload core commands!", user->nick.c_str(), parameters[0].c_str()); + return CMD_FAILURE; + } + if (parameters[0] == "cmd_unloadmodule.so" || parameters[0] == "cmd_loadmodule.so") { user->WriteNumeric(972, "%s %s :You cannot unload module loading commands!", user->nick.c_str(), parameters[0].c_str()); return CMD_FAILURE; } - + Module* m = ServerInstance->Modules->Find(parameters[0]); if (m && ServerInstance->Modules->Unload(m)) { diff --git a/src/commands/cmd_user.cpp b/src/commands/cmd_user.cpp index 305d0847f..b4d86f07b 100644 --- a/src/commands/cmd_user.cpp +++ b/src/commands/cmd_user.cpp @@ -45,7 +45,7 @@ CmdResult CommandUser::HandleLocal(const std::vector<std::string>& parameters, L /* A user may only send the USER command once */ if (!(user->registered & REG_USER)) { - if (!ServerInstance->IsIdent(parameters[0].c_str())) + if (!ServerInstance->IsIdent(parameters[0])) { /* * RFC says we must use this numeric, so we do. Let's make it a little more nub friendly though. :) @@ -61,7 +61,7 @@ CmdResult CommandUser::HandleLocal(const std::vector<std::string>& parameters, L * ~ character, and +1 for null termination, therefore we can safely use up to * IDENTMAX here. */ - user->ChangeIdent(parameters[0].c_str()); + user->ChangeIdent(parameters[0]); user->fullname.assign(parameters[3].empty() ? "No info" : parameters[3], 0, ServerInstance->Config->Limits.MaxGecos); user->registered = (user->registered | REG_USER); } diff --git a/src/commands/cmd_userhost.cpp b/src/commands/cmd_userhost.cpp index 399de0b1a..933cbca04 100644 --- a/src/commands/cmd_userhost.cpp +++ b/src/commands/cmd_userhost.cpp @@ -54,12 +54,12 @@ CmdResult CommandUserhost::Handle (const std::vector<std::string>& parameters, U { retbuf = retbuf + u->nick; - if (IS_OPER(u)) + if (u->IsOper()) retbuf = retbuf + "*"; retbuf = retbuf + "="; - if (IS_AWAY(u)) + if (u->IsAway()) retbuf += "-"; else retbuf += "+"; diff --git a/src/commands/cmd_version.cpp b/src/commands/cmd_version.cpp index 7620197fd..9fdd9c838 100644 --- a/src/commands/cmd_version.cpp +++ b/src/commands/cmd_version.cpp @@ -42,9 +42,13 @@ class CommandVersion : public Command CmdResult CommandVersion::Handle (const std::vector<std::string>&, User *user) { - std::string version = ServerInstance->GetVersionString(IS_OPER(user)); + std::string version = ServerInstance->GetVersionString((user->IsOper())); user->WriteNumeric(RPL_VERSION, "%s :%s", user->nick.c_str(), version.c_str()); - ServerInstance->Config->Send005(user); + LocalUser *lu = IS_LOCAL(user); + if (lu != NULL) + { + ServerInstance->ISupport.SendTo(lu); + } return CMD_SUCCESS; } diff --git a/src/commands/cmd_wallops.cpp b/src/commands/cmd_wallops.cpp index 198997a95..e0e832ff7 100644 --- a/src/commands/cmd_wallops.cpp +++ b/src/commands/cmd_wallops.cpp @@ -27,10 +27,19 @@ */ class CommandWallops : public Command { + UserModeReference wallopsmode; + public: /** Constructor for wallops. */ - CommandWallops ( Module* parent) : Command(parent,"WALLOPS",1,1) { flags_needed = 'o'; syntax = "<any-text>"; } + CommandWallops(Module* parent) + : Command(parent, "WALLOPS", 1, 1) + , wallopsmode(parent, "wallops") + { + flags_needed = 'o'; + syntax = "<any-text>"; + } + /** Handle command. * @param parameters The parameters to the comamnd * @param pcnt The number of parameters passed to teh command @@ -38,6 +47,11 @@ class CommandWallops : public Command * @return A value from CmdResult to indicate command success or failure. */ CmdResult Handle(const std::vector<std::string>& parameters, User *user); + + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) + { + return ROUTE_BROADCAST; + } }; CmdResult CommandWallops::Handle (const std::vector<std::string>& parameters, User *user) @@ -48,11 +62,10 @@ CmdResult CommandWallops::Handle (const std::vector<std::string>& parameters, Us for (LocalUserList::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); i++) { User* t = *i; - if (t->IsModeSet('w')) + if (t->IsModeSet(wallopsmode)) user->WriteTo(t,wallop); } - FOREACH_MOD(I_OnWallops,OnWallops(user,parameters[0])); return CMD_SUCCESS; } diff --git a/src/commands/cmd_who.cpp b/src/commands/cmd_who.cpp index f8926b9f7..5e0e55b66 100644 --- a/src/commands/cmd_who.cpp +++ b/src/commands/cmd_who.cpp @@ -39,13 +39,34 @@ class CommandWho : public Command bool opt_local; bool opt_far; bool opt_time; + ChanModeReference secretmode; + ChanModeReference privatemode; + UserModeReference invisiblemode; + + Channel* get_first_visible_channel(User *u) + { + UCListIter i = u->chans.begin(); + while (i != u->chans.end()) + { + Channel* c = *i++; + if (!c->IsModeSet(secretmode)) + return c; + } + return NULL; + } public: /** Constructor for who. */ - CommandWho ( Module* parent) : Command(parent,"WHO", 1) { + CommandWho(Module* parent) + : Command(parent, "WHO", 1) + , secretmode(parent, "secret") + , privatemode(parent, "private") + , invisiblemode(parent, "invisible") + { syntax = "<server>|<nickname>|<channel>|<realname>|<host>|0 [ohurmMiaplf]"; } + void SendWhoLine(User* user, const std::vector<std::string>& parms, const std::string &initial, Channel* ch, User* u, std::vector<std::string> &whoresults); /** Handle command. * @param parameters The parameters to the comamnd @@ -57,19 +78,6 @@ class CommandWho : public Command bool whomatch(User* cuser, User* user, const char* matchtext); }; - -static Channel* get_first_visible_channel(User *u) -{ - UCListIter i = u->chans.begin(); - while (i != u->chans.end()) - { - Channel* c = *i++; - if (!c->IsModeSet('s')) - return c; - } - return NULL; -} - bool CommandWho::whomatch(User* cuser, User* user, const char* matchtext) { bool match = false; @@ -138,7 +146,7 @@ bool CommandWho::whomatch(User* cuser, User* user, const char* matchtext) match = InspIRCd::Match(user->awaymsg, matchtext); else if (opt_time) { - long seconds = ServerInstance->Duration(matchtext); + long seconds = InspIRCd::Duration(matchtext); // Okay, so time matching, we want all users connected `seconds' ago if (user->age >= ServerInstance->Time() - seconds) @@ -180,7 +188,7 @@ bool CommandWho::CanView(Channel* chan, User* user) if (user->HasPrivPermission("users/auspex")) return true; /* Cant see inside a +s or a +p channel unless we are a member (see above) */ - else if (!chan->IsModeSet('s') && !chan->IsModeSet('p')) + else if (!chan->IsModeSet(secretmode) && !chan->IsModeSet(privatemode)) return true; return false; @@ -197,11 +205,11 @@ void CommandWho::SendWhoLine(User* user, const std::vector<std::string>& parms, wholine.append(ServerInstance->Config->HideWhoisServer); else wholine.append(u->server); - + wholine.append(" " + u->nick + " "); /* away? */ - if (IS_AWAY(u)) + if (u->IsAway()) { wholine.append("G"); } @@ -211,7 +219,7 @@ void CommandWho::SendWhoLine(User* user, const std::vector<std::string>& parms, } /* oper? */ - if (IS_OPER(u)) + if (u->IsOper()) { wholine.push_back('*'); } @@ -221,7 +229,7 @@ void CommandWho::SendWhoLine(User* user, const std::vector<std::string>& parms, wholine.append(" :0 " + u->fullname); - FOREACH_MOD(I_OnSendWhoLine, OnSendWhoLine(user, parms, u, wholine)); + FOREACH_MOD(OnSendWhoLine, (user, parms, u, wholine)); if (!wholine.empty()) whoresults.push_back(wholine); @@ -249,33 +257,17 @@ CmdResult CommandWho::Handle (const std::vector<std::string>& parameters, User * opt_far = false; opt_time = false; - Channel *ch = NULL; std::vector<std::string> whoresults; std::string initial = "352 " + user->nick + " "; - char matchtext[MAXBUF]; - bool usingwildcards = false; - /* Change '0' into '*' so the wildcard matcher can grok it */ - if (parameters[0] == "0") - strlcpy(matchtext, "*", MAXBUF); - else - strlcpy(matchtext, parameters[0].c_str(), MAXBUF); + std::string matchtext = ((parameters[0] == "0") ? "*" : parameters[0]); - for (const char* check = matchtext; *check; check++) - { - if (*check == '*' || *check == '?' || *check == '.') - { - usingwildcards = true; - break; - } - } + // WHO flags count as a wildcard + bool usingwildcards = ((parameters.size() > 1) || (matchtext.find_first_of("*?.") != std::string::npos)); if (parameters.size() > 1) { - /* Fix for bug #444, WHO flags count as a wildcard */ - usingwildcards = true; - for (std::string::const_iterator iter = parameters[1].begin(); iter != parameters[1].end(); ++iter) { switch (*iter) @@ -325,7 +317,7 @@ CmdResult CommandWho::Handle (const std::vector<std::string>& parameters, User * /* who on a channel? */ - ch = ServerInstance->FindChan(matchtext); + Channel* ch = ServerInstance->FindChan(matchtext); if (ch) { @@ -342,11 +334,11 @@ CmdResult CommandWho::Handle (const std::vector<std::string>& parameters, User * if (user != i->first) { /* opers only, please */ - if (opt_viewopersonly && !IS_OPER(i->first)) + if (opt_viewopersonly && !i->first->IsOper()) continue; /* If we're not inside the channel, hide +i users */ - if (i->first->IsModeSet('i') && !inside && !user->HasPrivPermission("users/auspex")) + if (i->first->IsModeSet(invisiblemode) && !inside && !user->HasPrivPermission("users/auspex")) continue; } @@ -364,11 +356,11 @@ CmdResult CommandWho::Handle (const std::vector<std::string>& parameters, User * { User* oper = *i; - if (whomatch(user, oper, matchtext)) + if (whomatch(user, oper, matchtext.c_str())) { if (!user->SharesChannelWith(oper)) { - if (usingwildcards && (!oper->IsModeSet('i')) && (!user->HasPrivPermission("users/auspex"))) + if (usingwildcards && (!oper->IsModeSet(invisiblemode)) && (!user->HasPrivPermission("users/auspex"))) continue; } @@ -380,11 +372,11 @@ CmdResult CommandWho::Handle (const std::vector<std::string>& parameters, User * { for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++) { - if (whomatch(user, i->second, matchtext)) + if (whomatch(user, i->second, matchtext.c_str())) { if (!user->SharesChannelWith(i->second)) { - if (usingwildcards && (i->second->IsModeSet('i')) && (!user->HasPrivPermission("users/auspex"))) + if (usingwildcards && (i->second->IsModeSet(invisiblemode)) && (!user->HasPrivPermission("users/auspex"))) continue; } diff --git a/src/commands/cmd_whois.cpp b/src/commands/cmd_whois.cpp index ba2ad9c15..0df6b65f0 100644 --- a/src/commands/cmd_whois.cpp +++ b/src/commands/cmd_whois.cpp @@ -26,32 +26,191 @@ * the same way, however, they can be fully unloaded, where these * may not. */ -class CommandWhois : public Command +class CommandWhois : public SplitCommand { + ChanModeReference secretmode; + ChanModeReference privatemode; + UserModeReference snomaskmode; + + void SplitChanList(User* source, User* dest, const std::string& cl); + void DoWhois(User* user, User* dest, unsigned long signon, unsigned long idle); + std::string ChannelList(User* source, User* dest, bool spy); + public: /** Constructor for whois. */ - CommandWhois ( Module* parent) : Command(parent,"WHOIS",1) { Penalty = 2; syntax = "<nick>{,<nick>}"; } + CommandWhois(Module* parent) + : SplitCommand(parent, "WHOIS", 1) + , secretmode(parent, "secret") + , privatemode(parent, "private") + , snomaskmode(parent, "snomask") + { + Penalty = 2; + syntax = "<nick>{,<nick>}"; + } + /** Handle command. * @param parameters The parameters to the comamnd * @param pcnt The number of parameters passed to teh command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ - CmdResult Handle(const std::vector<std::string>& parameters, User *user); + CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user); + CmdResult HandleRemote(const std::vector<std::string>& parameters, RemoteUser* target); }; +std::string CommandWhois::ChannelList(User* source, User* dest, bool spy) +{ + std::string list; -CmdResult CommandWhois::Handle (const std::vector<std::string>& parameters, User *user) + for (UCListIter i = dest->chans.begin(); i != dest->chans.end(); i++) + { + Channel* c = *i; + /* If the target is the sender, neither +p nor +s is set, or + * the channel contains the user, it is not a spy channel + */ + if (spy != (source == dest || !(c->IsModeSet(privatemode) || c->IsModeSet(secretmode)) || c->HasUser(source))) + list.append(c->GetPrefixChar(dest)).append(c->name).append(" "); + } + + return list; +} + +void CommandWhois::SplitChanList(User* source, User* dest, const std::string& cl) +{ + std::string line; + std::ostringstream prefix; + std::string::size_type start, pos, length; + + prefix << source->nick << " " << dest->nick << " :"; + line = prefix.str(); + int namelen = ServerInstance->Config->ServerName.length() + 6; + + for (start = 0; (pos = cl.find(' ', start)) != std::string::npos; start = pos+1) + { + length = (pos == std::string::npos) ? cl.length() : pos; + + if (line.length() + namelen + length - start > 510) + { + ServerInstance->SendWhoisLine(source, dest, 319, "%s", line.c_str()); + line = prefix.str(); + } + + if(pos == std::string::npos) + { + line.append(cl.substr(start, length - start)); + break; + } + else + { + line.append(cl.substr(start, length - start + 1)); + } + } + + if (line.length() != prefix.str().length()) + { + ServerInstance->SendWhoisLine(source, dest, 319, "%s", line.c_str()); + } +} + +void CommandWhois::DoWhois(User* user, User* dest, unsigned long signon, unsigned long idle) +{ + ServerInstance->SendWhoisLine(user, dest, 311, "%s %s %s %s * :%s",user->nick.c_str(), dest->nick.c_str(), dest->ident.c_str(), dest->dhost.c_str(), dest->fullname.c_str()); + if (user == dest || user->HasPrivPermission("users/auspex")) + { + ServerInstance->SendWhoisLine(user, dest, 378, "%s %s :is connecting from %s@%s %s", user->nick.c_str(), dest->nick.c_str(), dest->ident.c_str(), dest->host.c_str(), dest->GetIPString().c_str()); + } + + std::string cl = ChannelList(user, dest, false); + const ServerConfig::OperSpyWhoisState state = user->HasPrivPermission("users/auspex") ? ServerInstance->Config->OperSpyWhois : ServerConfig::SPYWHOIS_NONE; + + if (state == ServerConfig::SPYWHOIS_SINGLEMSG) + cl.append(ChannelList(user, dest, true)); + + SplitChanList(user, dest, cl); + + if (state == ServerConfig::SPYWHOIS_SPLITMSG) + { + std::string scl = ChannelList(user, dest, true); + if (scl.length()) + { + ServerInstance->SendWhoisLine(user, dest, 336, "%s %s :is on private/secret channels:",user->nick.c_str(), dest->nick.c_str()); + SplitChanList(user, dest, scl); + } + } + if (user != dest && !ServerInstance->Config->HideWhoisServer.empty() && !user->HasPrivPermission("servers/auspex")) + { + ServerInstance->SendWhoisLine(user, dest, 312, "%s %s %s :%s",user->nick.c_str(), dest->nick.c_str(), ServerInstance->Config->HideWhoisServer.c_str(), ServerInstance->Config->Network.c_str()); + } + else + { + std::string serverdesc = ServerInstance->GetServerDescription(dest->server); + ServerInstance->SendWhoisLine(user, dest, 312, "%s %s %s :%s",user->nick.c_str(), dest->nick.c_str(), dest->server.c_str(), serverdesc.c_str()); + } + + if (dest->IsAway()) + { + ServerInstance->SendWhoisLine(user, dest, 301, "%s %s :%s",user->nick.c_str(), dest->nick.c_str(), dest->awaymsg.c_str()); + } + + if (dest->IsOper()) + { + if (ServerInstance->Config->GenericOper) + ServerInstance->SendWhoisLine(user, dest, 313, "%s %s :is an IRC operator",user->nick.c_str(), dest->nick.c_str()); + else + ServerInstance->SendWhoisLine(user, dest, 313, "%s %s :is %s %s on %s",user->nick.c_str(), dest->nick.c_str(), (strchr("AEIOUaeiou",dest->oper->name[0]) ? "an" : "a"),dest->oper->name.c_str(), ServerInstance->Config->Network.c_str()); + } + + if (user == dest || user->HasPrivPermission("users/auspex")) + { + if (dest->IsModeSet(snomaskmode)) + { + ServerInstance->SendWhoisLine(user, dest, 379, "%s %s :is using modes +%s %s", user->nick.c_str(), dest->nick.c_str(), dest->FormatModes(), snomaskmode->GetUserParameter(dest).c_str()); + } + else + { + ServerInstance->SendWhoisLine(user, dest, 379, "%s %s :is using modes +%s", user->nick.c_str(), dest->nick.c_str(), dest->FormatModes()); + } + } + + FOREACH_MOD(OnWhois, (user,dest)); + + /* + * We only send these if we've been provided them. That is, if hidewhois is turned off, and user is local, or + * if remote whois is queried, too. This is to keep the user hidden, and also since you can't reliably tell remote time. -- w00t + */ + if ((idle) || (signon)) + { + ServerInstance->SendWhoisLine(user, dest, 317, "%s %s %lu %lu :seconds idle, signon time",user->nick.c_str(), dest->nick.c_str(), idle, signon); + } + + ServerInstance->SendWhoisLine(user, dest, 318, "%s %s :End of /WHOIS list.",user->nick.c_str(), dest->nick.c_str()); +} + +CmdResult CommandWhois::HandleRemote(const std::vector<std::string>& parameters, RemoteUser* target) +{ + if (parameters.size() < 2) + return CMD_FAILURE; + + User* user = ServerInstance->FindUUID(parameters[0]); + if (!user) + return CMD_FAILURE; + + unsigned long idle = ConvToInt(parameters.back()); + DoWhois(user, target, target->signon, idle); + + return CMD_SUCCESS; +} + +CmdResult CommandWhois::HandleLocal(const std::vector<std::string>& parameters, LocalUser* user) { User *dest; int userindex = 0; unsigned long idle = 0, signon = 0; - if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) + if (CommandParser::LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; - /* * If 2 paramters are specified (/whois nick nick), ignore the first one like spanningtree * does, and use the second one, otherwise, use the only paramter. -- djGrrr @@ -59,10 +218,7 @@ CmdResult CommandWhois::Handle (const std::vector<std::string>& parameters, User if (parameters.size() > 1) userindex = 1; - if (IS_LOCAL(user)) - dest = ServerInstance->FindNickOnly(parameters[userindex]); - else - dest = ServerInstance->FindNick(parameters[userindex]); + dest = ServerInstance->FindNickOnly(parameters[userindex]); if ((dest) && (dest->registered == REG_ALL)) { @@ -74,13 +230,14 @@ CmdResult CommandWhois::Handle (const std::vector<std::string>& parameters, User * For remote users (/w remoteuser remoteuser), spanningtree will handle calling do_whois, so we can ignore this case. * Thanks to djGrrr for not being impatient while I have a crap day coding. :p -- w00t */ - if (IS_LOCAL(dest) && (ServerInstance->Config->HideWhoisServer.empty() || parameters.size() > 1)) + LocalUser* localuser = IS_LOCAL(dest); + if (localuser && (ServerInstance->Config->HideWhoisServer.empty() || parameters.size() > 1)) { - idle = abs((long)((dest->idle_lastmsg)-ServerInstance->Time())); + idle = abs((long)((localuser->idle_lastmsg)-ServerInstance->Time())); signon = dest->signon; } - ServerInstance->DoWhois(user,dest,signon,idle,parameters[userindex].c_str()); + DoWhois(user,dest,signon,idle); } else { @@ -93,6 +250,4 @@ CmdResult CommandWhois::Handle (const std::vector<std::string>& parameters, User return CMD_SUCCESS; } - - COMMAND_INIT(CommandWhois) diff --git a/src/commands/cmd_whowas.cpp b/src/commands/cmd_whowas.cpp index 3a6444b45..75d1ee8ff 100644 --- a/src/commands/cmd_whowas.cpp +++ b/src/commands/cmd_whowas.cpp @@ -23,20 +23,18 @@ #include "inspircd.h" #include "commands/cmd_whowas.h" -WhoWasMaintainTimer * timer; - -CommandWhowas::CommandWhowas( Module* parent) : Command(parent, "WHOWAS", 1) +CommandWhowas::CommandWhowas( Module* parent) + : Command(parent, "WHOWAS", 1) + , GroupSize(0), MaxGroups(0), MaxKeep(0) { syntax = "<nick>{,<nick>}"; Penalty = 2; - timer = new WhoWasMaintainTimer(3600); - ServerInstance->Timers->AddTimer(timer); } CmdResult CommandWhowas::Handle (const std::vector<std::string>& parameters, User* user) { /* if whowas disabled in config */ - if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0) + if (this->GroupSize == 0 || this->MaxGroups == 0) { user->WriteNumeric(421, "%s %s :This command has been disabled.",user->nick.c_str(),name.c_str()); return CMD_FAILURE; @@ -47,13 +45,11 @@ CmdResult CommandWhowas::Handle (const std::vector<std::string>& parameters, Use if (i == whowas.end()) { user->WriteNumeric(406, "%s %s :There was no such nickname",user->nick.c_str(),parameters[0].c_str()); - user->WriteNumeric(369, "%s %s :End of WHOWAS",user->nick.c_str(),parameters[0].c_str()); - return CMD_FAILURE; } else { whowas_set* grp = i->second; - if (grp->size()) + if (!grp->empty()) { for (whowas_set::iterator ux = grp->begin(); ux != grp->end(); ux++) { @@ -67,17 +63,13 @@ CmdResult CommandWhowas::Handle (const std::vector<std::string>& parameters, Use user->nick.c_str(), parameters[0].c_str(), u->host.c_str()); std::string signon = ServerInstance->TimeString(u->signon); - if (!ServerInstance->Config->HideWhoisServer.empty() && !user->HasPrivPermission("servers/auspex")) - user->WriteNumeric(312, "%s %s %s :%s",user->nick.c_str(),parameters[0].c_str(), ServerInstance->Config->HideWhoisServer.c_str(), signon.c_str()); - else - user->WriteNumeric(312, "%s %s %s :%s",user->nick.c_str(),parameters[0].c_str(), u->server.c_str(), signon.c_str()); + bool hide_server = (!ServerInstance->Config->HideWhoisServer.empty() && !user->HasPrivPermission("servers/auspex")); + user->WriteNumeric(312, "%s %s %s :%s",user->nick.c_str(), parameters[0].c_str(), (hide_server ? ServerInstance->Config->HideWhoisServer.c_str() : u->server.c_str()), signon.c_str()); } } else { user->WriteNumeric(406, "%s %s :There was no such nickname",user->nick.c_str(),parameters[0].c_str()); - user->WriteNumeric(369, "%s %s :End of WHOWAS",user->nick.c_str(),parameters[0].c_str()); - return CMD_FAILURE; } } @@ -89,15 +81,11 @@ std::string CommandWhowas::GetStats() { int whowas_size = 0; int whowas_bytes = 0; - whowas_users_fifo::iterator iter; - for (iter = whowas_fifo.begin(); iter != whowas_fifo.end(); iter++) + for (whowas_users::iterator i = whowas.begin(); i != whowas.end(); ++i) { - whowas_set* n = (whowas_set*)whowas.find(iter->second)->second; - if (n->size()) - { - whowas_size += n->size(); - whowas_bytes += (sizeof(whowas_set) + ( sizeof(WhoWasGroup) * n->size() ) ); - } + whowas_set* n = i->second; + whowas_size += n->size(); + whowas_bytes += (sizeof(whowas_set) + ( sizeof(WhoWasGroup) * n->size() ) ); } return "Whowas entries: " +ConvToStr(whowas_size)+" ("+ConvToStr(whowas_bytes)+" bytes)"; } @@ -105,97 +93,81 @@ std::string CommandWhowas::GetStats() void CommandWhowas::AddToWhoWas(User* user) { /* if whowas disabled */ - if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0) + if (this->GroupSize == 0 || this->MaxGroups == 0) { return; } - whowas_users::iterator iter = whowas.find(irc::string(user->nick.c_str())); + // Insert nick if it doesn't exist + // 'first' will point to the newly inserted element or to the existing element with an equivalent key + std::pair<whowas_users::iterator, bool> ret = whowas.insert(std::make_pair(irc::string(user->nick.c_str()), static_cast<whowas_set*>(NULL))); - if (iter == whowas.end()) + if (ret.second) // If inserted { + // This nick is new, create a list for it and add the first record to it whowas_set* n = new whowas_set; - WhoWasGroup *a = new WhoWasGroup(user); - n->push_back(a); - whowas[user->nick.c_str()] = n; - whowas_fifo.push_back(std::make_pair(ServerInstance->Time(),user->nick.c_str())); + n->push_back(new WhoWasGroup(user)); + ret.first->second = n; - if ((int)(whowas.size()) > ServerInstance->Config->WhoWasMaxGroups) + // Add this nick to the fifo too + whowas_fifo.push_back(std::make_pair(ServerInstance->Time(), ret.first->first)); + + if (whowas.size() > this->MaxGroups) { - whowas_users::iterator iter2 = whowas.find(whowas_fifo[0].second); - if (iter2 != whowas.end()) + // Too many nicks, remove the nick which was inserted the longest time ago from both the map and the fifo + whowas_users::iterator it = whowas.find(whowas_fifo.front().second); + if (it != whowas.end()) { - whowas_set* n2 = (whowas_set*)iter2->second; - - if (n2->size()) - { - while (n2->begin() != n2->end()) - { - WhoWasGroup *a2 = *(n2->begin()); - delete a2; - n2->pop_front(); - } - } - - delete n2; - whowas.erase(iter2); + whowas_set* set = it->second; + for (whowas_set::iterator i = set->begin(); i != set->end(); ++i) + delete *i; + + delete set; + whowas.erase(it); } whowas_fifo.pop_front(); } } else { - whowas_set* group = (whowas_set*)iter->second; - WhoWasGroup *a = new WhoWasGroup(user); - group->push_back(a); + // We've met this nick before, add a new record to the list + whowas_set* set = ret.first->second; + set->push_back(new WhoWasGroup(user)); - if ((int)(group->size()) > ServerInstance->Config->WhoWasGroupSize) + // If there are too many records for this nick, remove the oldest (front) + if (set->size() > this->GroupSize) { - WhoWasGroup *a2 = (WhoWasGroup*)*(group->begin()); - delete a2; - group->pop_front(); + delete set->front(); + set->pop_front(); } } } /* on rehash, refactor maps according to new conf values */ -void CommandWhowas::PruneWhoWas(time_t t) +void CommandWhowas::Prune() { - /* config values */ - int groupsize = ServerInstance->Config->WhoWasGroupSize; - int maxgroups = ServerInstance->Config->WhoWasMaxGroups; - int maxkeep = ServerInstance->Config->WhoWasMaxKeep; + time_t min = ServerInstance->Time() - this->MaxKeep; /* first cut the list to new size (maxgroups) and also prune entries that are timed out. */ - whowas_users::iterator iter; - int fifosize; - while ((fifosize = (int)whowas_fifo.size()) > 0) + while (!whowas_fifo.empty()) { - if (fifosize > maxgroups || whowas_fifo[0].first < t - maxkeep) + if ((whowas_fifo.size() > this->MaxGroups) || (whowas_fifo.front().first < min)) { - iter = whowas.find(whowas_fifo[0].second); + whowas_users::iterator iter = whowas.find(whowas_fifo.front().second); /* hopefully redundant integrity check, but added while debugging r6216 */ if (iter == whowas.end()) { /* this should never happen, if it does maps are corrupt */ - ServerInstance->Logs->Log("WHOWAS",DEFAULT, "BUG: Whowas maps got corrupted! (1)"); + ServerInstance->Logs->Log("WHOWAS", LOG_DEFAULT, "BUG: Whowas maps got corrupted! (1)"); return; } - whowas_set* n = (whowas_set*)iter->second; - - if (n->size()) - { - while (n->begin() != n->end()) - { - WhoWasGroup *a = *(n->begin()); - delete a; - n->pop_front(); - } - } + whowas_set* set = iter->second; + for (whowas_set::iterator i = set->begin(); i != set->end(); ++i) + delete *i; - delete n; + delete set; whowas.erase(iter); whowas_fifo.pop_front(); } @@ -204,86 +176,41 @@ void CommandWhowas::PruneWhoWas(time_t t) } /* Then cut the whowas sets to new size (groupsize) */ - fifosize = (int)whowas_fifo.size(); - for (int i = 0; i < fifosize; i++) + for (whowas_users::iterator i = whowas.begin(); i != whowas.end(); ++i) { - iter = whowas.find(whowas_fifo[0].second); - /* hopefully redundant integrity check, but added while debugging r6216 */ - if (iter == whowas.end()) + whowas_set* n = i->second; + while (n->size() > this->GroupSize) { - /* this should never happen, if it does maps are corrupt */ - ServerInstance->Logs->Log("WHOWAS",DEFAULT, "BUG: Whowas maps got corrupted! (2)"); - return; - } - whowas_set* n = (whowas_set*)iter->second; - if (n->size()) - { - int nickcount = n->size(); - while (n->begin() != n->end() && nickcount > groupsize) - { - WhoWasGroup *a = *(n->begin()); - delete a; - n->pop_front(); - nickcount--; - } + delete n->front(); + n->pop_front(); } } } /* call maintain once an hour to remove expired nicks */ -void CommandWhowas::MaintainWhoWas(time_t t) +void CommandWhowas::Maintain() { - for (whowas_users::iterator iter = whowas.begin(); iter != whowas.end(); iter++) + time_t min = ServerInstance->Time() - this->MaxKeep; + for (whowas_users::iterator i = whowas.begin(); i != whowas.end(); ++i) { - whowas_set* n = (whowas_set*)iter->second; - if (n->size()) + whowas_set* set = i->second; + while (!set->empty() && set->front()->signon < min) { - while ((n->begin() != n->end()) && ((*n->begin())->signon < t - ServerInstance->Config->WhoWasMaxKeep)) - { - WhoWasGroup *a = *(n->begin()); - delete a; - n->erase(n->begin()); - } + delete set->front(); + set->pop_front(); } } } CommandWhowas::~CommandWhowas() { - if (timer) + for (whowas_users::iterator i = whowas.begin(); i != whowas.end(); ++i) { - ServerInstance->Timers->DelTimer(timer); - } + whowas_set* set = i->second; + for (whowas_set::iterator j = set->begin(); j != set->end(); ++j) + delete *j; - whowas_users::iterator iter; - int fifosize; - while ((fifosize = (int)whowas_fifo.size()) > 0) - { - iter = whowas.find(whowas_fifo[0].second); - - /* hopefully redundant integrity check, but added while debugging r6216 */ - if (iter == whowas.end()) - { - /* this should never happen, if it does maps are corrupt */ - ServerInstance->Logs->Log("WHOWAS",DEFAULT, "BUG: Whowas maps got corrupted! (3)"); - return; - } - - whowas_set* n = (whowas_set*)iter->second; - - if (n->size()) - { - while (n->begin() != n->end()) - { - WhoWasGroup *a = *(n->begin()); - delete a; - n->pop_front(); - } - } - - delete n; - whowas.erase(iter); - whowas_fifo.pop_front(); + delete set; } } @@ -292,23 +219,10 @@ WhoWasGroup::WhoWasGroup(User* user) : host(user->host), dhost(user->dhost), ide { } -WhoWasGroup::~WhoWasGroup() -{ -} - -/* every hour, run this function which removes all entries older than Config->WhoWasMaxKeep */ -void WhoWasMaintainTimer::Tick(time_t) -{ - Module* whowas = ServerInstance->Modules->Find("cmd_whowas.so"); - if (whowas) - { - WhowasRequest(whowas, whowas, WhowasRequest::WHOWAS_MAINTAIN).Send(); - } -} - class ModuleWhoWas : public Module { CommandWhowas cmd; + public: ModuleWhoWas() : cmd(this) { @@ -317,31 +231,47 @@ class ModuleWhoWas : public Module void init() { ServerInstance->Modules->AddService(cmd); + OnRehash(NULL); } - void OnRequest(Request& request) + void OnGarbageCollect() { - WhowasRequest& req = static_cast<WhowasRequest&>(request); - switch (req.type) - { - case WhowasRequest::WHOWAS_ADD: - cmd.AddToWhoWas(req.user); - break; - case WhowasRequest::WHOWAS_STATS: - req.value = cmd.GetStats(); - break; - case WhowasRequest::WHOWAS_PRUNE: - cmd.PruneWhoWas(ServerInstance->Time()); - break; - case WhowasRequest::WHOWAS_MAINTAIN: - cmd.MaintainWhoWas(ServerInstance->Time()); - break; - } + // Remove all entries older than MaxKeep + cmd.Maintain(); + } + + void OnUserQuit(User* user, const std::string& message, const std::string& oper_message) + { + cmd.AddToWhoWas(user); + } + + ModResult OnStats(char symbol, User* user, string_list &results) + { + if (symbol == 'z') + results.push_back(ServerInstance->Config->ServerName+" 249 "+user->nick+" :"+cmd.GetStats()); + + return MOD_RES_PASSTHRU; + } + + void OnRehash(User* user) + { + ConfigTag* tag = ServerInstance->Config->ConfValue("whowas"); + unsigned int NewGroupSize = tag->getInt("groupsize", 10, 0, 10000); + unsigned int NewMaxGroups = tag->getInt("maxgroups", 10240, 0, 1000000); + unsigned int NewMaxKeep = tag->getDuration("maxkeep", 3600, 3600); + + if ((NewGroupSize == cmd.GroupSize) && (NewMaxGroups == cmd.MaxGroups) && (NewMaxKeep == cmd.MaxKeep)) + return; + + cmd.GroupSize = NewGroupSize; + cmd.MaxGroups = NewMaxGroups; + cmd.MaxKeep = NewMaxKeep; + cmd.Prune(); } Version GetVersion() { - return Version("WHOWAS Command", VF_VENDOR); + return Version("WHOWAS", VF_VENDOR); } }; diff --git a/src/commands/cmd_zline.cpp b/src/commands/cmd_zline.cpp index 91d9c6255..fdb156e0a 100644 --- a/src/commands/cmd_zline.cpp +++ b/src/commands/cmd_zline.cpp @@ -49,7 +49,7 @@ CmdResult CommandZline::Handle (const std::vector<std::string>& parameters, User { if (target.find('!') != std::string::npos) { - user->WriteServ("NOTICE %s :*** You cannot include a nickname in a zline, a zline must ban only an IP mask",user->nick.c_str()); + user->WriteNotice("*** You cannot include a nickname in a zline, a zline must ban only an IP mask"); return CMD_FAILURE; } @@ -72,8 +72,7 @@ CmdResult CommandZline::Handle (const std::vector<std::string>& parameters, User if (ServerInstance->IPMatchesEveryone(ipaddr,user)) return CMD_FAILURE; - long duration = ServerInstance->Duration(parameters[1].c_str()); - + unsigned long duration = InspIRCd::Duration(parameters[1]); ZLine* zl = new ZLine(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ipaddr); if (ServerInstance->XLines->AddLine(zl,user)) { @@ -93,7 +92,7 @@ CmdResult CommandZline::Handle (const std::vector<std::string>& parameters, User else { delete zl; - user->WriteServ("NOTICE %s :*** Z-Line for %s already exists",user->nick.c_str(),ipaddr); + user->WriteNotice("*** Z-Line for " + std::string(ipaddr) + " already exists"); } } else @@ -104,7 +103,7 @@ CmdResult CommandZline::Handle (const std::vector<std::string>& parameters, User } else { - user->WriteServ("NOTICE %s :*** Z-Line %s not found in list, try /stats Z.",user->nick.c_str(),target.c_str()); + user->WriteNotice("*** Z-Line " + target + " not found in list, try /stats Z."); return CMD_FAILURE; } } diff --git a/src/configparser.cpp b/src/configparser.cpp index 7d9eab651..0e2a86706 100644 --- a/src/configparser.cpp +++ b/src/configparser.cpp @@ -119,7 +119,7 @@ struct Parser while (1) { ch = next(); - if (ch == '&' && (flags & FLAG_USE_XML)) + if (ch == '&' && !(flags & FLAG_USE_COMPAT)) { std::string varname; while (1) @@ -141,7 +141,7 @@ struct Parser throw CoreException("Undefined XML entity reference '&" + varname + ";'"); value.append(var->second); } - else if (ch == '\\' && !(flags & FLAG_USE_XML)) + else if (ch == '\\' && (flags & FLAG_USE_COMPAT)) { int esc = next(); if (esc == 'n') @@ -183,7 +183,10 @@ struct Parser std::set<std::string> seen; tag = ConfigTag::create(name, current.filename, current.line, items); - while (kv(items, seen)); + while (kv(items, seen)) + { + // Do nothing here (silences a GCC warning). + } if (name == mandatory_tag) { @@ -211,7 +214,7 @@ struct Parser } else if (name == "define") { - if (!(flags & FLAG_USE_XML)) + if (flags & FLAG_USE_COMPAT) throw CoreException("<define> tags may only be used in XML-style config (add <config format=\"xml\">)"); std::string varname = tag->getString("name"); std::string value = tag->getString("value"); @@ -223,9 +226,9 @@ struct Parser { std::string format = tag->getString("format"); if (format == "xml") - flags |= FLAG_USE_XML; + flags &= ~FLAG_USE_COMPAT; else if (format == "compat") - flags &= ~FLAG_USE_XML; + flags |= FLAG_USE_COMPAT; else if (!format.empty()) throw CoreException("Unknown configuration format " + format); } @@ -320,14 +323,15 @@ void ParseStack::DoReadFile(const std::string& key, const std::string& name, int if (exec && (flags & FLAG_NO_EXEC)) throw CoreException("Invalid <execfiles> tag in file included with noexec=\"yes\""); - FileWrapper file(exec ? popen(name.c_str(), "r") : fopen(name.c_str(), "r"), exec); + std::string path = ServerInstance->Config->Paths.PrependConfig(name); + FileWrapper file(exec ? popen(name.c_str(), "r") : fopen(path.c_str(), "r"), exec); if (!file) - throw CoreException("Could not read \"" + name + "\" for \"" + key + "\" file"); + throw CoreException("Could not read \"" + path + "\" for \"" + key + "\" file"); file_cache& cache = FilesOutput[key]; cache.clear(); - char linebuf[MAXBUF*10]; + char linebuf[5120]; while (fgets(linebuf, sizeof(linebuf), file)) { size_t len = strlen(linebuf); @@ -342,23 +346,24 @@ void ParseStack::DoReadFile(const std::string& key, const std::string& name, int bool ParseStack::ParseFile(const std::string& name, int flags, const std::string& mandatory_tag) { - ServerInstance->Logs->Log("CONFIG", DEBUG, "Reading file %s", name.c_str()); + std::string path = ServerInstance->Config->Paths.PrependConfig(name); + ServerInstance->Logs->Log("CONFIG", LOG_DEBUG, "Reading file %s", path.c_str()); for (unsigned int t = 0; t < reading.size(); t++) { if (std::string(name) == reading[t]) { - throw CoreException("File " + name + " is included recursively (looped inclusion)"); + throw CoreException("File " + path + " is included recursively (looped inclusion)"); } } /* It's not already included, add it to the list of files we've loaded */ - FileWrapper file(fopen(name.c_str(), "r")); + FileWrapper file(fopen(path.c_str(), "r")); if (!file) - throw CoreException("Could not read \"" + name + "\" for include"); + throw CoreException("Could not read \"" + path + "\" for include"); - reading.push_back(name); - Parser p(*this, flags, file, name, mandatory_tag); + reading.push_back(path); + Parser p(*this, flags, file, path, mandatory_tag); bool ok = p.outer_parse(); reading.pop_back(); return ok; @@ -366,7 +371,7 @@ bool ParseStack::ParseFile(const std::string& name, int flags, const std::string bool ParseStack::ParseExec(const std::string& name, int flags, const std::string& mandatory_tag) { - ServerInstance->Logs->Log("CONFIG", DEBUG, "Reading executable %s", name.c_str()); + ServerInstance->Logs->Log("CONFIG", LOG_DEBUG, "Reading executable %s", name.c_str()); for (unsigned int t = 0; t < reading.size(); t++) { if (std::string(name) == reading[t]) @@ -399,7 +404,7 @@ bool ConfigTag::readString(const std::string& key, std::string& value, bool allo value = j->second; if (!allow_lf && (value.find('\n') != std::string::npos)) { - ServerInstance->Logs->Log("CONFIG",DEFAULT, "Value of <" + tag + ":" + key + "> at " + getTagLocation() + + ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Value of <" + tag + ":" + key + "> at " + getTagLocation() + " contains a linefeed, and linefeeds in this value are not permitted -- stripped to spaces."); for (std::string::iterator n = value.begin(); n != value.end(); n++) if (*n == '\n') @@ -417,7 +422,7 @@ std::string ConfigTag::getString(const std::string& key, const std::string& def) return res; } -long ConfigTag::getInt(const std::string &key, long def) +long ConfigTag::getInt(const std::string &key, long def, long min, long max) { std::string result; if(!readString(key, result)) @@ -431,18 +436,41 @@ long ConfigTag::getInt(const std::string &key, long def) switch (toupper(*res_tail)) { case 'K': - res= res* 1024; + res = res * 1024; break; case 'M': - res= res* 1024 * 1024; + res = res * 1024 * 1024; break; case 'G': - res= res* 1024 * 1024 * 1024; + res = res * 1024 * 1024 * 1024; break; } + + CheckRange(key, res, def, min, max); return res; } +void ConfigTag::CheckRange(const std::string& key, long& res, long def, long min, long max) +{ + if (res < min || res > max) + { + ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "WARNING: <%s:%s> value of %ld is not between %ld and %ld; set to %ld.", + tag.c_str(), key.c_str(), res, min, max, def); + res = def; + } +} + +long ConfigTag::getDuration(const std::string& key, long def, long min, long max) +{ + std::string duration; + if (!readString(key, duration)) + return def; + + long ret = InspIRCd::Duration(duration); + CheckRange(key, ret, def, min, max); + return ret; +} + double ConfigTag::getFloat(const std::string &key, double def) { std::string result; @@ -462,7 +490,7 @@ bool ConfigTag::getBool(const std::string &key, bool def) if (result == "no" || result == "false" || result == "0" || result == "off") return false; - ServerInstance->Logs->Log("CONFIG",DEFAULT, "Value of <" + tag + ":" + key + "> at " + getTagLocation() + + ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Value of <" + tag + ":" + key + "> at " + getTagLocation() + " is not valid, ignoring"); return def; } diff --git a/src/configreader.cpp b/src/configreader.cpp index e8707cc3e..957adc829 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -23,22 +23,16 @@ #include "inspircd.h" -#include <fstream> #include "xline.h" +#include "listmode.h" #include "exitcodes.h" -#include "commands/cmd_whowas.h" #include "configparser.h" #include <iostream> -#ifdef _WIN32 -#include <Iphlpapi.h> -#pragma comment(lib, "Iphlpapi.lib") -#endif ServerConfig::ServerConfig() { - WhoWasGroupSize = WhoWasMaxGroups = WhoWasMaxKeep = 0; - RawLog = NoUserDns = HideBans = HideSplits = UndernetMsgPrefix = false; - WildcardIPv6 = CycleHosts = InvBypassModes = true; + RawLog = HideBans = HideSplits = UndernetMsgPrefix = false; + WildcardIPv6 = InvBypassModes = true; dns_timeout = 5; MaxTargets = 20; NetBufferSize = 10240; @@ -50,60 +44,6 @@ ServerConfig::ServerConfig() c_ipv6_range = 128; } -void ServerConfig::Update005() -{ - std::stringstream out(data005); - std::vector<std::string> data; - std::string token; - while (out >> token) - data.push_back(token); - sort(data.begin(), data.end()); - - std::string line5; - isupport.clear(); - for(unsigned int i=0; i < data.size(); i++) - { - token = data[i]; - line5 = line5 + token + " "; - if (i % 13 == 12) - { - line5.append(":are supported by this server"); - isupport.push_back(line5); - line5.clear(); - } - } - if (!line5.empty()) - { - line5.append(":are supported by this server"); - isupport.push_back(line5); - } -} - -void ServerConfig::Send005(User* user) -{ - for (std::vector<std::string>::iterator line = ServerInstance->Config->isupport.begin(); line != ServerInstance->Config->isupport.end(); line++) - user->WriteNumeric(RPL_ISUPPORT, "%s %s", user->nick.c_str(), line->c_str()); -} - -template<typename T, typename V> -static void range(T& value, V min, V max, V def, const char* msg) -{ - if (value >= (T)min && value <= (T)max) - return; - ServerInstance->Logs->Log("CONFIG", DEFAULT, - "WARNING: %s value of %ld is not between %ld and %ld; set to %ld.", - msg, (long)value, (long)min, (long)max, (long)def); - value = def; -} - - -static void ValidIP(const std::string& ip, const std::string& key) -{ - irc::sockets::sockaddrs dummy; - if (!irc::sockets::aptosa(ip, 0, dummy)) - throw CoreException("The value of "+key+" is not an IP address"); -} - static void ValidHost(const std::string& p, const std::string& msg) { int num_dots = 0; @@ -145,64 +85,6 @@ bool ServerConfig::ApplyDisabledCommands(const std::string& data) return true; } -static void FindDNS(std::string& server) -{ - if (!server.empty()) - return; -#ifdef _WIN32 - // attempt to look up their nameserver from the system - ServerInstance->Logs->Log("CONFIG",DEFAULT,"WARNING: <dns:server> not defined, attempting to find a working server in the system settings..."); - - PFIXED_INFO pFixedInfo; - DWORD dwBufferSize = sizeof(FIXED_INFO); - pFixedInfo = (PFIXED_INFO) HeapAlloc(GetProcessHeap(), 0, sizeof(FIXED_INFO)); - - if(pFixedInfo) - { - if (GetNetworkParams(pFixedInfo, &dwBufferSize) == ERROR_BUFFER_OVERFLOW) { - HeapFree(GetProcessHeap(), 0, pFixedInfo); - pFixedInfo = (PFIXED_INFO) HeapAlloc(GetProcessHeap(), 0, dwBufferSize); - } - - if(pFixedInfo) { - if (GetNetworkParams(pFixedInfo, &dwBufferSize) == NO_ERROR) - server = pFixedInfo->DnsServerList.IpAddress.String; - - HeapFree(GetProcessHeap(), 0, pFixedInfo); - } - - if(!server.empty()) - { - ServerInstance->Logs->Log("CONFIG",DEFAULT,"<dns:server> set to '%s' as first active resolver in the system settings.", server.c_str()); - return; - } - } - - ServerInstance->Logs->Log("CONFIG",DEFAULT,"No viable nameserver found! Defaulting to nameserver '127.0.0.1'!"); -#else - // attempt to look up their nameserver from /etc/resolv.conf - ServerInstance->Logs->Log("CONFIG",DEFAULT,"WARNING: <dns:server> not defined, attempting to find working server in /etc/resolv.conf..."); - - std::ifstream resolv("/etc/resolv.conf"); - - while (resolv >> server) - { - if (server == "nameserver") - { - resolv >> server; - if (server.find_first_not_of("0123456789.") == std::string::npos) - { - ServerInstance->Logs->Log("CONFIG",DEFAULT,"<dns:server> set to '%s' as first resolver in /etc/resolv.conf.",server.c_str()); - return; - } - } - } - - ServerInstance->Logs->Log("CONFIG",DEFAULT,"/etc/resolv.conf contains no viable nameserver entries! Defaulting to nameserver '127.0.0.1'!"); -#endif - server = "127.0.0.1"; -} - static void ReadXLine(ServerConfig* conf, const std::string& tag, const std::string& key, XLineFactory* make) { ConfigTagList tags = conf->ConfTags(tag); @@ -241,13 +123,11 @@ void ServerConfig::CrossCheckOperClassType() std::string name = tag->getString("name"); if (name.empty()) throw CoreException("<type:name> is missing from tag at " + tag->getTagLocation()); - if (!ServerInstance->IsNick(name.c_str(), Limits.NickMax)) - throw CoreException("<type:name> is invalid (value '" + name + "')"); - if (oper_blocks.find(" " + name) != oper_blocks.end()) + if (OperTypes.find(name) != OperTypes.end()) throw CoreException("Duplicate type block with name " + name + " at " + tag->getTagLocation()); OperInfo* ifo = new OperInfo; - oper_blocks[" " + name] = ifo; + OperTypes[name] = ifo; ifo->name = name; ifo->type_block = tag; @@ -272,8 +152,8 @@ void ServerConfig::CrossCheckOperClassType() throw CoreException("<oper:name> missing from tag at " + tag->getTagLocation()); std::string type = tag->getString("type"); - OperIndex::iterator tblk = oper_blocks.find(" " + type); - if (tblk == oper_blocks.end()) + OperIndex::iterator tblk = OperTypes.find(type); + if (tblk == OperTypes.end()) throw CoreException("Oper block " + name + " has missing type " + type); if (oper_blocks.find(name) != oper_blocks.end()) throw CoreException("Duplicate oper block with name " + name + " at " + tag->getTagLocation()); @@ -419,6 +299,7 @@ void ServerConfig::CrossCheckConnectBlocks(ServerConfig* current) me->maxchans = tag->getInt("maxchans", me->maxchans); me->maxconnwarn = tag->getBool("maxconnwarn", me->maxconnwarn); me->limit = tag->getInt("limit", me->limit); + me->resolvehostnames = tag->getBool("resolvehostnames", me->resolvehostnames); ClassMap::iterator oldMask = oldBlocksByMask.find(typeMask); if (oldMask != oldBlocksByMask.end()) @@ -436,42 +317,30 @@ void ServerConfig::CrossCheckConnectBlocks(ServerConfig* current) /** Represents a deprecated configuration tag. */ -struct Deprecated +struct DeprecatedConfig { - /** Tag name - */ - const char* tag; - /** Tag value - */ - const char* value; - /** Reason for deprecation - */ - const char* reason; + /** Tag name. */ + std::string tag; + + /** Attribute key. */ + std::string key; + + /** Attribute value. */ + std::string value; + + /** Reason for deprecation. */ + std::string reason; }; -static const Deprecated ChangedConfig[] = { - {"options", "hidelinks", "has been moved to <security:hidelinks> as of 1.2a3"}, - {"options", "hidewhois", "has been moved to <security:hidewhois> as of 1.2a3"}, - {"options", "userstats", "has been moved to <security:userstats> as of 1.2a3"}, - {"options", "customversion", "has been moved to <security:customversion> as of 1.2a3"}, - {"options", "hidesplits", "has been moved to <security:hidesplits> as of 1.2a3"}, - {"options", "hidebans", "has been moved to <security:hidebans> as of 1.2a3"}, - {"options", "hidekills", "has been moved to <security:hidekills> as of 1.2a3"}, - {"options", "operspywhois", "has been moved to <security:operspywhois> as of 1.2a3"}, - {"options", "announceinvites", "has been moved to <security:announceinvites> as of 1.2a3"}, - {"options", "hidemodes", "has been moved to <security:hidemodes> as of 1.2a3"}, - {"options", "maxtargets", "has been moved to <security:maxtargets> as of 1.2a3"}, - {"options", "nouserdns", "has been moved to <performance:nouserdns> as of 1.2a3"}, - {"options", "maxwho", "has been moved to <performance:maxwho> as of 1.2a3"}, - {"options", "softlimit", "has been moved to <performance:softlimit> as of 1.2a3"}, - {"options", "somaxconn", "has been moved to <performance:somaxconn> as of 1.2a3"}, - {"options", "netbuffersize", "has been moved to <performance:netbuffersize> as of 1.2a3"}, - {"options", "maxwho", "has been moved to <performance:maxwho> as of 1.2a3"}, - {"options", "loglevel", "1.2+ does not use the loglevel value. Please define <log> tags instead."}, - {"die", "value", "you need to reread your config"}, - {"bind", "transport", "has been moved to <bind:ssl> as of 2.0a1"}, - {"link", "transport", "has been moved to <link:ssl> as of 2.0a1"}, - {"link", "autoconnect", "2.0+ does not use the autoconnect value. Please define <autoconnect> tags instead."}, +static const DeprecatedConfig ChangedConfig[] = { + { "bind", "transport", "", "has been moved to <bind:ssl> as of 2.0" }, + { "die", "value", "", "you need to reread your config" }, + { "link", "autoconnect", "", "2.0+ does not use this attribute - define <autoconnect> tags instead" }, + { "link", "transport", "", "has been moved to <link:ssl> as of 2.0" }, + { "module", "name", "m_chanprotect.so", "has been replaced with m_customprefix as of 2.2" }, + { "module", "name", "m_halfop.so", "has been replaced with m_customprefix as of 2.2" }, + { "options", "cyclehosts", "", "has been replaced with m_hostcycle as of 2.2" }, + { "performance", "nouserdns", "", "has been moved to <connect:resolvehostnames> as of 2.2" } }; void ServerConfig::Fill() @@ -480,19 +349,21 @@ void ServerConfig::Fill() ConfigTag* security = ConfValue("security"); if (sid.empty()) { - ServerName = ConfValue("server")->getString("name"); - sid = ConfValue("server")->getString("id"); + ServerName = ConfValue("server")->getString("name", "irc.example.com"); ValidHost(ServerName, "<server:name>"); - if (!sid.empty() && !ServerInstance->IsSID(sid)) + + sid = ConfValue("server")->getString("id"); + if (!sid.empty() && !InspIRCd::IsSID(sid)) throw CoreException(sid + " is not a valid server ID. A server ID must be 3 characters long, with the first character a digit and the next two characters a digit or letter."); } else { if (ServerName != ConfValue("server")->getString("name")) - throw CoreException("You must restart to change the server name or SID"); + throw CoreException("You must restart to change the server name"); + std::string nsid = ConfValue("server")->getString("id"); if (!nsid.empty() && nsid != sid) - throw CoreException("You must restart to change the server name or SID"); + throw CoreException("You must restart to change the server id"); } diepass = ConfValue("power")->getString("diepass"); restartpass = ConfValue("power")->getString("restartpass"); @@ -503,39 +374,34 @@ void ServerConfig::Fill() PrefixPart = options->getString("prefixpart"); SuffixPart = options->getString("suffixpart"); FixedPart = options->getString("fixedpart"); - SoftLimit = ConfValue("performance")->getInt("softlimit", ServerInstance->SE->GetMaxFds()); + SoftLimit = ConfValue("performance")->getInt("softlimit", ServerInstance->SE->GetMaxFds(), 10, ServerInstance->SE->GetMaxFds()); + CCOnConnect = ConfValue("performance")->getBool("clonesonconnect", true); MaxConn = ConfValue("performance")->getInt("somaxconn", SOMAXCONN); - MoronBanner = options->getString("moronbanner", "You're banned!"); + XLineMessage = options->getString("xlinemessage", options->getString("moronbanner", "You're banned!")); ServerDesc = ConfValue("server")->getString("description", "Configure Me"); Network = ConfValue("server")->getString("network", "Network"); AdminName = ConfValue("admin")->getString("name", ""); AdminEmail = ConfValue("admin")->getString("email", "null@example.com"); AdminNick = ConfValue("admin")->getString("nick", "admin"); - ModPath = ConfValue("path")->getString("moduledir", MOD_PATH); - NetBufferSize = ConfValue("performance")->getInt("netbuffersize", 10240); + NetBufferSize = ConfValue("performance")->getInt("netbuffersize", 10240, 1024, 65534); dns_timeout = ConfValue("dns")->getInt("timeout", 5); DisabledCommands = ConfValue("disabled")->getString("commands", ""); DisabledDontExist = ConfValue("disabled")->getBool("fakenonexistant"); UserStats = security->getString("userstats"); - CustomVersion = security->getString("customversion", Network + " IRCd"); + CustomVersion = security->getString("customversion"); HideSplits = security->getBool("hidesplits"); HideBans = security->getBool("hidebans"); HideWhoisServer = security->getString("hidewhois"); HideKillsServer = security->getString("hidekills"); RestrictBannedUsers = security->getBool("restrictbannedusers", true); GenericOper = security->getBool("genericoper"); - NoUserDns = ConfValue("performance")->getBool("nouserdns"); SyntaxHints = options->getBool("syntaxhints"); - CycleHosts = options->getBool("cyclehosts"); CycleHostsFromUser = options->getBool("cyclehostsfromuser"); UndernetMsgPrefix = options->getBool("ircumsgprefix"); FullHostInTopic = options->getBool("hostintopic"); - MaxTargets = security->getInt("maxtargets", 20); - DefaultModes = options->getString("defaultmodes", "nt"); + MaxTargets = security->getInt("maxtargets", 20, 1, 31); + DefaultModes = options->getString("defaultmodes", "not"); PID = ConfValue("pid")->getString("file"); - WhoWasGroupSize = ConfValue("whowas")->getInt("groupsize"); - WhoWasMaxGroups = ConfValue("whowas")->getInt("maxgroups"); - WhoWasMaxKeep = ServerInstance->Duration(ConfValue("whowas")->getString("maxkeep")); MaxChans = ConfValue("channels")->getInt("users", 20); OperMaxChans = ConfValue("channels")->getInt("opers", 60); c_ipv4_range = ConfValue("cidr")->getInt("ipv4clone", 32); @@ -549,20 +415,16 @@ void ServerConfig::Fill() Limits.MaxKick = ConfValue("limits")->getInt("maxkick", 255); Limits.MaxGecos = ConfValue("limits")->getInt("maxgecos", 128); Limits.MaxAway = ConfValue("limits")->getInt("maxaway", 200); + Limits.MaxLine = ConfValue("limits")->getInt("maxline", 512); + Paths.Config = ConfValue("path")->getString("configdir", CONFIG_PATH); + Paths.Data = ConfValue("path")->getString("datadir", DATA_PATH); + Paths.Log = ConfValue("path")->getString("logdir", LOG_PATH); + Paths.Module = ConfValue("path")->getString("moduledir", MOD_PATH); InvBypassModes = options->getBool("invitebypassmodes", true); NoSnoticeStack = options->getBool("nosnoticestack", false); - WelcomeNotice = options->getBool("welcomenotice", true); - range(SoftLimit, 10, ServerInstance->SE->GetMaxFds(), ServerInstance->SE->GetMaxFds(), "<performance:softlimit>"); - if (ConfValue("performance")->getBool("limitsomaxconn", true)) - range(MaxConn, 0, SOMAXCONN, SOMAXCONN, "<performance:somaxconn>"); - range(MaxTargets, 1, 31, 20, "<security:maxtargets>"); - range(NetBufferSize, 1024, 65534, 10240, "<performance:netbuffersize>"); - range(WhoWasGroupSize, 0, 10000, 10, "<whowas:groupsize>"); - range(WhoWasMaxGroups, 0, 1000000, 10240, "<whowas:maxgroups>"); - range(WhoWasMaxKeep, 3600, INT_MAX, 3600, "<whowas:maxkeep>"); - - ValidIP(DNSServer, "<dns:server>"); + if (Network.find(' ') != std::string::npos) + throw CoreException(Network + " is not a valid network name. A network name must not contain spaces."); std::string defbind = options->getString("defaultbind"); if (assign(defbind) == "ipv4") @@ -589,17 +451,11 @@ void ServerConfig::Fill() std::string server; if (!tag->readString("server", server)) throw CoreException("<uline> tag missing server at " + tag->getTagLocation()); - ulines[assign(server)] = tag->getBool("silent"); - } - tags = ConfTags("banlist"); - for(ConfigIter i = tags.first; i != tags.second; ++i) - { - ConfigTag* tag = i->second; - std::string chan; - if (!tag->readString("chan", chan)) - throw CoreException("<banlist> tag missing chan at " + tag->getTagLocation()); - maxbans[chan] = tag->getInt("limit"); + if (ServerName == server) + throw CoreException("Servers should not uline themselves (at " + tag->getTagLocation() + ")"); + + ulines[assign(server)] = tag->getBool("silent"); } ReadXLine(this, "badip", "ipmask", ServerInstance->XLines->GetFactory("Z")); @@ -667,11 +523,6 @@ void ServerConfig::Read() valid = false; errstr << err.GetReason(); } - if (valid) - { - DNSServer = ConfValue("dns")->getString("server"); - FindDNS(DNSServer); - } } void ServerConfig::Apply(ServerConfig* old, const std::string &useruid) @@ -690,16 +541,26 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid) /* The stuff in here may throw CoreException, be sure we're in a position to catch it. */ try { - for (int Index = 0; Index * sizeof(Deprecated) < sizeof(ChangedConfig); Index++) + for (int index = 0; index * sizeof(DeprecatedConfig) < sizeof(ChangedConfig); index++) { - std::string dummy; - ConfigTagList tags = ConfTags(ChangedConfig[Index].tag); + std::string value; + ConfigTagList tags = ConfTags(ChangedConfig[index].tag); for(ConfigIter i = tags.first; i != tags.second; ++i) { - if (i->second->readString(ChangedConfig[Index].value, dummy, true)) - errstr << "Your configuration contains a deprecated value: <" - << ChangedConfig[Index].tag << ":" << ChangedConfig[Index].value << "> - " << ChangedConfig[Index].reason - << " (at " << i->second->getTagLocation() << ")\n"; + if (i->second->readString(ChangedConfig[index].key, value, true) + && (ChangedConfig[index].value.empty() || value == ChangedConfig[index].value)) + { + errstr << "Your configuration contains a deprecated value: <" << ChangedConfig[index].tag; + if (ChangedConfig[index].value.empty()) + { + errstr << ':' << ChangedConfig[index].key; + } + else + { + errstr << ' ' << ChangedConfig[index].key << "=\"" << ChangedConfig[index].value << "\""; + } + errstr << "> - " << ChangedConfig[index].reason << " (at " << i->second->getTagLocation() << ")" << std::endl; + } } } @@ -721,6 +582,11 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid) if (valid) ServerInstance->WritePID(this->PID); + ConfigTagList binds = ConfTags("bind"); + if (binds.first == binds.second) + errstr << "Possible configuration error: you have not defined any <bind> blocks." << std::endl + << "You will need to do this if you want clients to be able to connect!" << std::endl; + if (old) { // On first run, ports are bound later on @@ -728,14 +594,14 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid) ServerInstance->BindPorts(pl); if (pl.size()) { - errstr << "Not all your client ports could be bound.\nThe following port(s) failed to bind:\n"; + errstr << "Not all your client ports could be bound." << std::endl + << "The following port(s) failed to bind:" << std::endl; int j = 1; for (FailedPortList::iterator i = pl.begin(); i != pl.end(); i++, j++) { - char buf[MAXBUF]; - snprintf(buf, MAXBUF, "%d. Address: %s Reason: %s\n", j, i->first.empty() ? "<all>" : i->first.c_str(), i->second.c_str()); - errstr << buf; + errstr << j << ".\tAddress: " << (i->first.empty() ? "<all>" : i->first.c_str()) << "\tReason: " + << i->second << std::endl; } } } @@ -743,7 +609,7 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid) User* user = useruid.empty() ? NULL : ServerInstance->FindNick(useruid); if (!valid) - ServerInstance->Logs->Log("CONFIG",DEFAULT, "There were errors in your configuration file:"); + ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "There were errors in your configuration file:"); while (errstr.good()) { @@ -807,10 +673,6 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid) void ServerConfig::ApplyModules(User* user) { - Module* whowas = ServerInstance->Modules->Find("cmd_whowas.so"); - if (whowas) - WhowasRequest(NULL, whowas, WhowasRequest::WHOWAS_PRUNE).Send(); - const std::vector<std::string> v = ServerInstance->Modules->GetAllModuleNames(0); std::vector<std::string> added_modules; std::set<std::string> removed_modules(v.begin(), v.end()); @@ -829,9 +691,6 @@ void ServerConfig::ApplyModules(User* user) } } - if (ConfValue("options")->getBool("allowhalfop") && removed_modules.erase("m_halfop.so") == 0) - added_modules.push_back("m_halfop.so"); - for (std::set<std::string>::iterator removing = removed_modules.begin(); removing != removed_modules.end(); removing++) { // Don't remove cmd_*.so, just remove m_*.so @@ -889,7 +748,7 @@ ConfigTag* ServerConfig::ConfValue(const std::string &tag) ConfigTag* rv = found.first->second; found.first++; if (found.first != found.second) - ServerInstance->Logs->Log("CONFIG",DEFAULT, "Multiple <" + tag + "> tags found; only first will be used " + ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Multiple <" + tag + "> tags found; only first will be used " "(first at " + rv->getTagLocation() + "; second at " + found.first->second->getTagLocation() + ")"); return rv; } @@ -908,14 +767,40 @@ bool ServerConfig::FileExists(const char* file) if ((sb.st_mode & S_IFDIR) > 0) return false; - FILE *input = fopen(file, "r"); - if (input == NULL) - return false; - else + return !access(file, F_OK); +} + +std::string ServerConfig::Escape(const std::string& str, bool xml) +{ + std::string escaped; + for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) { - fclose(input); - return true; + switch (*it) + { + case '"': + escaped += xml ? """ : "\""; + break; + case '&': + escaped += xml ? "&" : "&"; + break; + case '\\': + escaped += xml ? "\\" : "\\\\"; + break; + default: + escaped += *it; + break; + } } + return escaped; +} + +std::string ServerConfig::ExpandPath(const std::string& base, const std::string& fragment) +{ + // The fragment is an absolute path, don't modify it. + if (fragment[0] == '/' || ServerConfig::StartsWithWindowsDriveLetter(fragment)) + return fragment; + + return base + '/' + fragment; } const char* ServerConfig::CleanFilename(const char* name) @@ -925,11 +810,6 @@ const char* ServerConfig::CleanFilename(const char* name) return (p != name ? ++p : p); } -const std::string& ServerConfig::GetSID() -{ - return sid; -} - void ConfigReaderThread::Run() { Config->Read(); @@ -939,7 +819,7 @@ void ConfigReaderThread::Run() void ConfigReaderThread::Finish() { ServerConfig* old = ServerInstance->Config; - ServerInstance->Logs->Log("CONFIG",DEBUG,"Switching to new configuration..."); + ServerInstance->Logs->Log("CONFIG", LOG_DEBUG, "Switching to new configuration..."); ServerInstance->Config = this->Config; Config->Apply(old, TheUserUID); @@ -953,12 +833,12 @@ void ConfigReaderThread::Finish() */ ServerInstance->XLines->CheckELines(); ServerInstance->XLines->ApplyLines(); - ServerInstance->Res->Rehash(); - ServerInstance->ResetMaxBans(); + ChanModeReference ban(NULL, "ban"); + static_cast<ListModeBase*>(*ban)->DoRehash(); Config->ApplyDisabledCommands(Config->DisabledCommands); User* user = ServerInstance->FindNick(TheUserUID); - FOREACH_MOD(I_OnRehash, OnRehash(user)); - ServerInstance->BuildISupport(); + FOREACH_MOD(OnRehash, (user)); + ServerInstance->ISupport.Build(); ServerInstance->Logs->CloseLogs(); ServerInstance->Logs->OpenFileLogs(); diff --git a/src/cull_list.cpp b/src/cull_list.cpp index 956ed3494..5cbe3aef3 100644 --- a/src/cull_list.cpp +++ b/src/cull_list.cpp @@ -46,14 +46,14 @@ void CullList::Apply() classbase* c = list[i]; if (gone.insert(c).second) { - ServerInstance->Logs->Log("CULLLIST", DEBUG, "Deleting %s @%p", typeid(*c).name(), + ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "Deleting %s @%p", typeid(*c).name(), (void*)c); c->cull(); queue.push_back(c); } else { - ServerInstance->Logs->Log("CULLLIST",DEBUG, "WARNING: Object @%p culled twice!", + ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "WARNING: Object @%p culled twice!", (void*)c); } } @@ -65,7 +65,7 @@ void CullList::Apply() } if (list.size()) { - ServerInstance->Logs->Log("CULLLIST",DEBUG, "WARNING: Objects added to cull list in a destructor"); + ServerInstance->Logs->Log("CULLLIST", LOG_DEBUG, "WARNING: Objects added to cull list in a destructor"); Apply(); } } diff --git a/src/dns.cpp b/src/dns.cpp deleted file mode 100644 index 63bde0ecc..000000000 --- a/src/dns.cpp +++ /dev/null @@ -1,1110 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2012 William Pitcock <nenolod@dereferenced.org> - * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> - * Copyright (C) 2006, 2009 Robin Burchell <robin+git@viroteck.net> - * Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org> - * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> - * Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -/* $Core */ - -/* -dns.cpp - Nonblocking DNS functions. -Very very loosely based on the firedns library, -Copyright (C) 2002 Ian Gulliver. This file is no -longer anything like firedns, there are many major -differences between this code and the original. -Please do not assume that firedns works like this, -looks like this, walks like this or tastes like this. -*/ - -#ifndef _WIN32 -#include <sys/types.h> -#include <sys/socket.h> -#include <errno.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#else -#include "inspircd_win32wrapper.h" -#endif - -#include "inspircd.h" -#include "socketengine.h" -#include "configreader.h" -#include "socket.h" - -#define DN_COMP_BITMASK 0xC000 /* highest 6 bits in a DN label header */ - -/** Masks to mask off the responses we get from the DNSRequest methods - */ -enum QueryInfo -{ - ERROR_MASK = 0x10000 /* Result is an error */ -}; - -/** Flags which can be ORed into a request or reply for different meanings - */ -enum QueryFlags -{ - FLAGS_MASK_RD = 0x01, /* Recursive */ - FLAGS_MASK_TC = 0x02, - FLAGS_MASK_AA = 0x04, /* Authoritative */ - FLAGS_MASK_OPCODE = 0x78, - FLAGS_MASK_QR = 0x80, - FLAGS_MASK_RCODE = 0x0F, /* Request */ - FLAGS_MASK_Z = 0x70, - FLAGS_MASK_RA = 0x80 -}; - - -/** Represents a dns resource record (rr) - */ -struct ResourceRecord -{ - QueryType type; /* Record type */ - unsigned int rr_class; /* Record class */ - unsigned long ttl; /* Time to live */ - unsigned int rdlength; /* Record length */ -}; - -/** Represents a dns request/reply header, and its payload as opaque data. - */ -class DNSHeader -{ - public: - unsigned char id[2]; /* Request id */ - unsigned int flags1; /* Flags */ - unsigned int flags2; /* Flags */ - unsigned int qdcount; - unsigned int ancount; /* Answer count */ - unsigned int nscount; /* Nameserver count */ - unsigned int arcount; - unsigned char payload[512]; /* Packet payload */ -}; - -class DNSRequest -{ - public: - unsigned char id[2]; /* Request id */ - unsigned char* res; /* Result processing buffer */ - unsigned int rr_class; /* Request class */ - QueryType type; /* Request type */ - DNS* dnsobj; /* DNS caller (where we get our FD from) */ - unsigned long ttl; /* Time to live */ - std::string orig; /* Original requested name/ip */ - - DNSRequest(DNS* dns, int id, const std::string &original); - ~DNSRequest(); - DNSInfo ResultIsReady(DNSHeader &h, unsigned length); - int SendRequests(const DNSHeader *header, const int length, QueryType qt); -}; - -class CacheTimer : public Timer -{ - private: - DNS* dns; - public: - CacheTimer(DNS* thisdns) - : Timer(3600, ServerInstance->Time(), true), dns(thisdns) { } - - virtual void Tick(time_t) - { - dns->PruneCache(); - } -}; - -class RequestTimeout : public Timer -{ - DNSRequest* watch; - int watchid; - public: - RequestTimeout(unsigned long n, DNSRequest* watching, int id) : Timer(n, ServerInstance->Time()), watch(watching), watchid(id) - { - } - ~RequestTimeout() - { - if (ServerInstance->Res) - Tick(0); - } - - void Tick(time_t) - { - if (ServerInstance->Res->requests[watchid] == watch) - { - /* Still exists, whack it */ - if (ServerInstance->Res->Classes[watchid]) - { - ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out"); - delete ServerInstance->Res->Classes[watchid]; - ServerInstance->Res->Classes[watchid] = NULL; - } - ServerInstance->Res->requests[watchid] = NULL; - delete watch; - } - } -}; - -CachedQuery::CachedQuery(const std::string &res, unsigned int ttl) : data(res) -{ - expires = ServerInstance->Time() + ttl; -} - -int CachedQuery::CalcTTLRemaining() -{ - int n = expires - ServerInstance->Time(); - return (n < 0 ? 0 : n); -} - -/* Allocate the processing buffer */ -DNSRequest::DNSRequest(DNS* dns, int rid, const std::string &original) : dnsobj(dns) -{ - /* hardening against overflow here: make our work buffer twice the theoretical - * maximum size so that hostile input doesn't screw us over. - */ - res = new unsigned char[sizeof(DNSHeader) * 2]; - *res = 0; - orig = original; - RequestTimeout* RT = new RequestTimeout(ServerInstance->Config->dns_timeout ? ServerInstance->Config->dns_timeout : 5, this, rid); - ServerInstance->Timers->AddTimer(RT); /* The timer manager frees this */ -} - -/* Deallocate the processing buffer */ -DNSRequest::~DNSRequest() -{ - delete[] res; -} - -/** Fill a ResourceRecord class based on raw data input */ -inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input) -{ - rr->type = (QueryType)((input[0] << 8) + input[1]); - rr->rr_class = (input[2] << 8) + input[3]; - rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7]; - rr->rdlength = (input[8] << 8) + input[9]; -} - -/** Fill a DNSHeader class based on raw data input of a given length */ -inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length) -{ - header->id[0] = input[0]; - header->id[1] = input[1]; - header->flags1 = input[2]; - header->flags2 = input[3]; - header->qdcount = (input[4] << 8) + input[5]; - header->ancount = (input[6] << 8) + input[7]; - header->nscount = (input[8] << 8) + input[9]; - header->arcount = (input[10] << 8) + input[11]; - memcpy(header->payload,&input[12],length); -} - -/** Empty a DNSHeader class out into raw data, ready for transmission */ -inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length) -{ - output[0] = header->id[0]; - output[1] = header->id[1]; - output[2] = header->flags1; - output[3] = header->flags2; - output[4] = header->qdcount >> 8; - output[5] = header->qdcount & 0xFF; - output[6] = header->ancount >> 8; - output[7] = header->ancount & 0xFF; - output[8] = header->nscount >> 8; - output[9] = header->nscount & 0xFF; - output[10] = header->arcount >> 8; - output[11] = header->arcount & 0xFF; - memcpy(&output[12],header->payload,length); -} - -/** Send requests we have previously built down the UDP socket */ -int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt) -{ - ServerInstance->Logs->Log("RESOLVER", DEBUG,"DNSRequest::SendRequests"); - - unsigned char payload[sizeof(DNSHeader)]; - - this->rr_class = 1; - this->type = qt; - - DNS::EmptyHeader(payload,header,length); - - if (ServerInstance->SE->SendTo(dnsobj, payload, length + 12, 0, &(dnsobj->myserver.sa), sa_size(dnsobj->myserver)) != length+12) - return -1; - - ServerInstance->Logs->Log("RESOLVER",DEBUG,"Sent OK"); - return 0; -} - -/** Add a query with a predefined header, and allocate an ID for it. */ -DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original) -{ - /* Is the DNS connection down? */ - if (this->GetFd() == -1) - return NULL; - - /* Create an id */ - unsigned int tries = 0; - do { - id = ServerInstance->GenRandomInt(DNS::MAX_REQUEST_ID); - if (++tries == DNS::MAX_REQUEST_ID*5) - { - // If we couldn't find an empty slot this many times, do a sequential scan as a last - // resort. If an empty slot is found that way, go on, otherwise throw an exception - id = -1; - for (int i = 0; i < DNS::MAX_REQUEST_ID; i++) - { - if (!requests[i]) - { - id = i; - break; - } - } - - if (id == -1) - throw ModuleException("DNS: All ids are in use"); - - break; - } - } while (requests[id]); - - DNSRequest* req = new DNSRequest(this, id, original); - - header->id[0] = req->id[0] = id >> 8; - header->id[1] = req->id[1] = id & 0xFF; - header->flags1 = FLAGS_MASK_RD; - header->flags2 = 0; - header->qdcount = 1; - header->ancount = 0; - header->nscount = 0; - header->arcount = 0; - - /* At this point we already know the id doesnt exist, - * so there needs to be no second check for the ::end() - */ - requests[id] = req; - - /* According to the C++ spec, new never returns NULL. */ - return req; -} - -int DNS::ClearCache() -{ - /* This ensures the buckets are reset to sane levels */ - int rv = this->cache->size(); - delete this->cache; - this->cache = new dnscache(); - return rv; -} - -int DNS::PruneCache() -{ - int n = 0; - dnscache* newcache = new dnscache(); - for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++) - /* Dont include expired items (theres no point) */ - if (i->second.CalcTTLRemaining()) - newcache->insert(*i); - else - n++; - - delete this->cache; - this->cache = newcache; - return n; -} - -void DNS::Rehash() -{ - if (this->GetFd() > -1) - { - ServerInstance->SE->DelFd(this); - ServerInstance->SE->Shutdown(this, 2); - ServerInstance->SE->Close(this); - this->SetFd(-1); - - /* Rehash the cache */ - this->PruneCache(); - } - else - { - /* Create initial dns cache */ - this->cache = new dnscache(); - } - - irc::sockets::aptosa(ServerInstance->Config->DNSServer, DNS::QUERY_PORT, myserver); - - /* Initialize mastersocket */ - int s = socket(myserver.sa.sa_family, SOCK_DGRAM, 0); - this->SetFd(s); - - /* Have we got a socket and is it nonblocking? */ - if (this->GetFd() != -1) - { - ServerInstance->SE->SetReuse(s); - ServerInstance->SE->NonBlocking(s); - irc::sockets::sockaddrs bindto; - memset(&bindto, 0, sizeof(bindto)); - bindto.sa.sa_family = myserver.sa.sa_family; - if (ServerInstance->SE->Bind(this->GetFd(), bindto) < 0) - { - /* Failed to bind */ - ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error binding dns socket - hostnames will NOT resolve"); - ServerInstance->SE->Shutdown(this, 2); - ServerInstance->SE->Close(this); - this->SetFd(-1); - } - else if (!ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE)) - { - ServerInstance->Logs->Log("RESOLVER",SPARSE,"Internal error starting DNS - hostnames will NOT resolve."); - ServerInstance->SE->Shutdown(this, 2); - ServerInstance->SE->Close(this); - this->SetFd(-1); - } - } - else - { - ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error creating DNS socket - hostnames will NOT resolve"); - } -} - -/** Initialise the DNS UDP socket so that we can send requests */ -DNS::DNS() -{ - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::DNS"); - /* Clear the Resolver class table */ - memset(Classes,0,sizeof(Classes)); - - /* Clear the requests class table */ - memset(requests,0,sizeof(requests)); - - /* DNS::Rehash() sets this to a valid ptr - */ - this->cache = NULL; - - /* Again, DNS::Rehash() sets this to a - * valid value - */ - this->SetFd(-1); - - /* Actually read the settings - */ - this->Rehash(); - - this->PruneTimer = new CacheTimer(this); - - ServerInstance->Timers->AddTimer(this->PruneTimer); -} - -/** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */ -int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload) -{ - short payloadpos = 0; - const char* tempchr, *tempchr2 = name; - unsigned short length; - - /* split name up into labels, create query */ - while ((tempchr = strchr(tempchr2,'.')) != NULL) - { - length = tempchr - tempchr2; - if (payloadpos + length + 1 > 507) - return -1; - payload[payloadpos++] = length; - memcpy(&payload[payloadpos],tempchr2,length); - payloadpos += length; - tempchr2 = &tempchr[1]; - } - length = strlen(tempchr2); - if (length) - { - if (payloadpos + length + 2 > 507) - return -1; - payload[payloadpos++] = length; - memcpy(&payload[payloadpos],tempchr2,length); - payloadpos += length; - payload[payloadpos++] = 0; - } - if (payloadpos > 508) - return -1; - length = htons(rr); - memcpy(&payload[payloadpos],&length,2); - length = htons(rr_class); - memcpy(&payload[payloadpos + 2],&length,2); - return payloadpos + 4; -} - -/** Start lookup of an hostname to an IP address */ -int DNS::GetIP(const char *name) -{ - DNSHeader h; - int id; - int length; - - if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1) - return -1; - - DNSRequest* req = this->AddQuery(&h, id, name); - - if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1)) - return -1; - - return id; -} - -/** Start lookup of an hostname to an IPv6 address */ -int DNS::GetIP6(const char *name) -{ - DNSHeader h; - int id; - int length; - - if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1) - return -1; - - DNSRequest* req = this->AddQuery(&h, id, name); - - if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1)) - return -1; - - return id; -} - -/** Start lookup of a cname to another name */ -int DNS::GetCName(const char *alias) -{ - DNSHeader h; - int id; - int length; - - if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1) - return -1; - - DNSRequest* req = this->AddQuery(&h, id, alias); - - if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1)) - return -1; - - return id; -} - -/** Start lookup of an IP address to a hostname */ -int DNS::GetNameForce(const char *ip, ForceProtocol fp) -{ - char query[128]; - DNSHeader h; - int id; - int length; - - if (fp == PROTOCOL_IPV6) - { - in6_addr i; - if (inet_pton(AF_INET6, ip, &i) > 0) - { - DNS::MakeIP6Int(query, &i); - } - else - { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv6 bad format for '%s'", ip); - /* Invalid IP address */ - return -1; - } - } - else - { - in_addr i; - if (inet_aton(ip, &i)) - { - unsigned char* c = (unsigned char*)&i.s_addr; - sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]); - } - else - { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv4 bad format for '%s'", ip); - /* Invalid IP address */ - return -1; - } - } - - length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload); - if (length == -1) - { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't query '%s' using '%s' because it's too long", ip, query); - return -1; - } - - DNSRequest* req = this->AddQuery(&h, id, ip); - - if (!req) - { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't add query (resolver down?)"); - return -1; - } - - if (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1) - { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't send (firewall?)"); - return -1; - } - - return id; -} - -/** Build an ipv6 reverse domain from an in6_addr - */ -void DNS::MakeIP6Int(char* query, const in6_addr *ip) -{ - const char* hex = "0123456789abcdef"; - for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */ - { - if (index % 2) - /* low nibble */ - *query++ = hex[ip->s6_addr[index / 2] & 0x0F]; - else - /* high nibble */ - *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4]; - *query++ = '.'; /* Seperator */ - } - strcpy(query,"ip6.arpa"); /* Suffix the string */ -} - -/** Return the next id which is ready, and the result attached to it */ -DNSResult DNS::GetResult() -{ - /* Fetch dns query response and decide where it belongs */ - DNSHeader header; - DNSRequest *req; - unsigned char buffer[sizeof(DNSHeader)]; - irc::sockets::sockaddrs from; - memset(&from, 0, sizeof(from)); - socklen_t x = sizeof(from); - - int length = ServerInstance->SE->RecvFrom(this, (char*)buffer, sizeof(DNSHeader), 0, &from.sa, &x); - - /* Did we get the whole header? */ - if (length < 12) - { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"GetResult didn't get a full packet (len=%d)", length); - /* Nope - something screwed up. */ - return DNSResult(-1,"",0,""); - } - - /* Check wether the reply came from a different DNS - * server to the one we sent it to, or the source-port - * is not 53. - * A user could in theory still spoof dns packets anyway - * but this is less trivial than just sending garbage - * to the server, which is possible without this check. - * - * -- Thanks jilles for pointing this one out. - */ - if (from != myserver) - { - std::string server1 = from.str(); - std::string server2 = myserver.str(); - ServerInstance->Logs->Log("RESOLVER",DEBUG,"Got a result from the wrong server! Bad NAT or DNS forging attempt? '%s' != '%s'", - server1.c_str(), server2.c_str()); - return DNSResult(-1,"",0,""); - } - - /* Put the read header info into a header class */ - DNS::FillHeader(&header,buffer,length - 12); - - /* Get the id of this request. - * Its a 16 bit value stored in two char's, - * so we use logic shifts to create the value. - */ - unsigned long this_id = header.id[1] + (header.id[0] << 8); - - /* Do we have a pending request matching this id? */ - if (!requests[this_id]) - { - /* Somehow we got a DNS response for a request we never made... */ - ServerInstance->Logs->Log("RESOLVER",DEBUG,"Hmm, got a result that we didn't ask for (id=%lx). Ignoring.", this_id); - return DNSResult(-1,"",0,""); - } - else - { - /* Remove the query from the list of pending queries */ - req = requests[this_id]; - requests[this_id] = NULL; - } - - /* Inform the DNSRequest class that it has a result to be read. - * When its finished it will return a DNSInfo which is a pair of - * unsigned char* resource record data, and an error message. - */ - DNSInfo data = req->ResultIsReady(header, length); - std::string resultstr; - - /* Check if we got a result, if we didnt, its an error */ - if (data.first == NULL) - { - /* An error. - * Mask the ID with the value of ERROR_MASK, so that - * the dns_deal_with_classes() function knows that its - * an error response and needs to be treated uniquely. - * Put the error message in the second field. - */ - std::string ro = req->orig; - delete req; - return DNSResult(this_id | ERROR_MASK, data.second, 0, ro); - } - else - { - unsigned long ttl = req->ttl; - char formatted[128]; - - /* Forward lookups come back as binary data. We must format them into ascii */ - switch (req->type) - { - case DNS_QUERY_A: - snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]); - resultstr = formatted; - break; - - case DNS_QUERY_AAAA: - { - inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted)); - char* c = strstr(formatted,":0:"); - if (c != NULL) - { - memmove(c+1,c+2,strlen(c+2) + 1); - c += 2; - while (memcmp(c,"0:",2) == 0) - memmove(c,c+2,strlen(c+2) + 1); - if (memcmp(c,"0",2) == 0) - *c = 0; - if (memcmp(formatted,"0::",3) == 0) - memmove(formatted,formatted + 1, strlen(formatted + 1) + 1); - } - resultstr = formatted; - - /* Special case. Sending ::1 around between servers - * and to clients is dangerous, because the : on the - * start makes the client or server interpret the IP - * as the last parameter on the line with a value ":1". - */ - if (*formatted == ':') - resultstr.insert(0, "0"); - } - break; - - case DNS_QUERY_CNAME: - /* Identical handling to PTR */ - - case DNS_QUERY_PTR: - /* Reverse lookups just come back as char* */ - resultstr = std::string((const char*)data.first); - break; - - default: - break; - } - - /* Build the reply with the id and hostname/ip in it */ - std::string ro = req->orig; - delete req; - return DNSResult(this_id,resultstr,ttl,ro); - } -} - -/** A result is ready, process it */ -DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length) -{ - unsigned i = 0, o; - int q = 0; - int curanswer; - ResourceRecord rr; - unsigned short ptr; - - /* This is just to keep _FORTIFY_SOURCE happy */ - rr.type = DNS_QUERY_NONE; - rr.rdlength = 0; - rr.ttl = 1; /* GCC is a whiney bastard -- see the XXX below. */ - rr.rr_class = 0; /* Same for VC++ */ - - if (!(header.flags1 & FLAGS_MASK_QR)) - return std::make_pair((unsigned char*)NULL,"Not a query result"); - - if (header.flags1 & FLAGS_MASK_OPCODE) - return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet"); - - if (header.flags2 & FLAGS_MASK_RCODE) - return std::make_pair((unsigned char*)NULL,"Domain name not found"); - - if (header.ancount < 1) - return std::make_pair((unsigned char*)NULL,"No resource records returned"); - - /* Subtract the length of the header from the length of the packet */ - length -= 12; - - while ((unsigned int)q < header.qdcount && i < length) - { - if (header.payload[i] > 63) - { - i += 6; - q++; - } - else - { - if (header.payload[i] == 0) - { - q++; - i += 5; - } - else i += header.payload[i] + 1; - } - } - curanswer = 0; - while ((unsigned)curanswer < header.ancount) - { - q = 0; - while (q == 0 && i < length) - { - if (header.payload[i] > 63) - { - i += 2; - q = 1; - } - else - { - if (header.payload[i] == 0) - { - i++; - q = 1; - } - else i += header.payload[i] + 1; /* skip length and label */ - } - } - if (static_cast<int>(length - i) < 10) - return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply"); - - /* XXX: We actually initialise 'rr' here including its ttl field */ - DNS::FillResourceRecord(&rr,&header.payload[i]); - - i += 10; - ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver: rr.type is %d and this.type is %d rr.class %d this.class %d", rr.type, this->type, rr.rr_class, this->rr_class); - if (rr.type != this->type) - { - curanswer++; - i += rr.rdlength; - continue; - } - if (rr.rr_class != this->rr_class) - { - curanswer++; - i += rr.rdlength; - continue; - } - break; - } - if ((unsigned int)curanswer == header.ancount) - return std::make_pair((unsigned char*)NULL,"No A, AAAA or PTR type answers (" + ConvToStr(header.ancount) + " answers)"); - - if (i + rr.rdlength > (unsigned int)length) - return std::make_pair((unsigned char*)NULL,"Resource record larger than stated"); - - if (rr.rdlength > 1023) - return std::make_pair((unsigned char*)NULL,"Resource record too large"); - - this->ttl = rr.ttl; - - switch (rr.type) - { - /* - * CNAME and PTR are compressed. We need to decompress them. - */ - case DNS_QUERY_CNAME: - case DNS_QUERY_PTR: - { - unsigned short lowest_pos = length; - o = 0; - q = 0; - while (q == 0 && i < length && o + 256 < 1023) - { - /* DN label found (byte over 63) */ - if (header.payload[i] > 63) - { - memcpy(&ptr,&header.payload[i],2); - - i = ntohs(ptr); - - /* check that highest two bits are set. if not, we've been had */ - if ((i & DN_COMP_BITMASK) != DN_COMP_BITMASK) - return std::make_pair((unsigned char *) NULL, "DN label decompression header is bogus"); - - /* mask away the two highest bits. */ - i &= ~DN_COMP_BITMASK; - - /* and decrease length by 12 bytes. */ - i -= 12; - - if (i >= lowest_pos) - return std::make_pair((unsigned char *) NULL, "Invalid decompression pointer"); - lowest_pos = i; - } - else - { - if (header.payload[i] == 0) - { - q = 1; - } - else - { - res[o] = 0; - if (o != 0) - res[o++] = '.'; - - if (o + header.payload[i] > sizeof(DNSHeader)) - return std::make_pair((unsigned char *) NULL, "DN label decompression is impossible -- malformed/hostile packet?"); - - memcpy(&res[o], &header.payload[i + 1], header.payload[i]); - o += header.payload[i]; - i += header.payload[i] + 1; - } - } - } - res[o] = 0; - } - break; - case DNS_QUERY_AAAA: - if (rr.rdlength != sizeof(struct in6_addr)) - return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 16 bytes for an ipv6 entry -- malformed/hostile packet?"); - - memcpy(res,&header.payload[i],rr.rdlength); - res[rr.rdlength] = 0; - break; - case DNS_QUERY_A: - if (rr.rdlength != sizeof(struct in_addr)) - return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 4 bytes for an ipv4 entry -- malformed/hostile packet?"); - - memcpy(res,&header.payload[i],rr.rdlength); - res[rr.rdlength] = 0; - break; - default: - return std::make_pair((unsigned char *) NULL, "don't know how to handle undefined type (" + ConvToStr(rr.type) + ") -- rejecting"); - break; - } - return std::make_pair(res,"No error"); -} - -/** Close the master socket */ -DNS::~DNS() -{ - ServerInstance->SE->Shutdown(this, 2); - ServerInstance->SE->Close(this); - ServerInstance->Timers->DelTimer(this->PruneTimer); - if (cache) - delete cache; -} - -CachedQuery* DNS::GetCache(const std::string &source) -{ - dnscache::iterator x = cache->find(source.c_str()); - if (x != cache->end()) - return &(x->second); - else - return NULL; -} - -void DNS::DelCache(const std::string &source) -{ - cache->erase(source.c_str()); -} - -void Resolver::TriggerCachedResult() -{ - if (CQ) - OnLookupComplete(CQ->data, time_left, true); -} - -/** High level abstraction of dns used by application at large */ -Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator) : Creator(creator), input(source), querytype(qt) -{ - ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver::Resolver"); - cached = false; - - CQ = ServerInstance->Res->GetCache(source); - if (CQ) - { - time_left = CQ->CalcTTLRemaining(); - if (!time_left) - { - ServerInstance->Res->DelCache(source); - } - else - { - cached = true; - return; - } - } - - switch (querytype) - { - case DNS_QUERY_A: - this->myid = ServerInstance->Res->GetIP(source.c_str()); - break; - - case DNS_QUERY_PTR4: - querytype = DNS_QUERY_PTR; - this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4); - break; - - case DNS_QUERY_PTR6: - querytype = DNS_QUERY_PTR; - this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6); - break; - - case DNS_QUERY_AAAA: - this->myid = ServerInstance->Res->GetIP6(source.c_str()); - break; - - case DNS_QUERY_CNAME: - this->myid = ServerInstance->Res->GetCName(source.c_str()); - break; - - default: - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request with unknown query type %d", querytype); - this->myid = -1; - break; - } - if (this->myid == -1) - { - throw ModuleException("Resolver: Couldn't get an id to make a request"); - } - else - { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request id %d", this->myid); - } -} - -/** Called when an error occurs */ -void Resolver::OnError(ResolverError, const std::string&) -{ - /* Nothing in here */ -} - -/** Destroy a resolver */ -Resolver::~Resolver() -{ - /* Nothing here (yet) either */ -} - -/** Get the request id associated with this class */ -int Resolver::GetId() -{ - return this->myid; -} - -Module* Resolver::GetCreator() -{ - return this->Creator; -} - -/** Process a socket read event */ -void DNS::HandleEvent(EventType, int) -{ - /* Fetch the id and result of the next available packet */ - DNSResult res(0,"",0,""); - res.id = 0; - ServerInstance->Logs->Log("RESOLVER",DEBUG,"Handle DNS event"); - - res = this->GetResult(); - - ServerInstance->Logs->Log("RESOLVER",DEBUG,"Result id %d", res.id); - - /* Is there a usable request id? */ - if (res.id != -1) - { - /* Its an error reply */ - if (res.id & ERROR_MASK) - { - /* Mask off the error bit */ - res.id -= ERROR_MASK; - /* Marshall the error to the correct class */ - if (Classes[res.id]) - { - if (ServerInstance && ServerInstance->stats) - ServerInstance->stats->statsDnsBad++; - Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result); - delete Classes[res.id]; - Classes[res.id] = NULL; - } - return; - } - else - { - /* It is a non-error result, marshall the result to the correct class */ - if (Classes[res.id]) - { - if (ServerInstance && ServerInstance->stats) - ServerInstance->stats->statsDnsGood++; - - if (!this->GetCache(res.original.c_str())) - this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl))); - - Classes[res.id]->OnLookupComplete(res.result, res.ttl, false); - delete Classes[res.id]; - Classes[res.id] = NULL; - } - } - - if (ServerInstance && ServerInstance->stats) - ServerInstance->stats->statsDns++; - } -} - -/** Add a derived Resolver to the working set */ -bool DNS::AddResolverClass(Resolver* r) -{ - ServerInstance->Logs->Log("RESOLVER",DEBUG,"AddResolverClass 0x%08lx", (unsigned long)r); - /* Check the pointers validity and the id's validity */ - if ((r) && (r->GetId() > -1)) - { - /* Check the slot isnt already occupied - - * This should NEVER happen unless we have - * a severely broken DNS server somewhere - */ - if (!Classes[r->GetId()]) - { - /* Set up the pointer to the class */ - Classes[r->GetId()] = r; - return true; - } - } - - /* Pointer or id not valid, or duplicate id. - * Free the item and return - */ - delete r; - return false; -} - -void DNS::CleanResolvers(Module* module) -{ - for (int i = 0; i < MAX_REQUEST_ID; i++) - { - if (Classes[i]) - { - if (Classes[i]->GetCreator() == module) - { - Classes[i]->OnError(RESOLVER_FORCEUNLOAD, "Parent module is unloading"); - delete Classes[i]; - Classes[i] = NULL; - } - } - } -} diff --git a/src/filelogger.cpp b/src/filelogger.cpp index 0575256d0..fff0b37fa 100644 --- a/src/filelogger.cpp +++ b/src/filelogger.cpp @@ -19,15 +19,12 @@ */ -/* $Core */ - #include "inspircd.h" #include <fstream> #include "socketengine.h" #include "filelogger.h" -FileLogStream::FileLogStream(int loglevel, FileWriter *fw) - : LogStream(loglevel), f(fw) +FileLogStream::FileLogStream(LogLevel loglevel, FileWriter *fw) : LogStream(loglevel), f(fw) { ServerInstance->Logs->AddLoggerRef(f); } @@ -38,9 +35,9 @@ FileLogStream::~FileLogStream() ServerInstance->Logs->DelLoggerRef(f); } -void FileLogStream::OnLog(int loglevel, const std::string &type, const std::string &text) +void FileLogStream::OnLog(LogLevel loglevel, const std::string &type, const std::string &text) { - static char TIMESTR[26]; + static std::string TIMESTR; static time_t LAST = 0; if (loglevel < this->loglvl) @@ -53,11 +50,9 @@ void FileLogStream::OnLog(int loglevel, const std::string &type, const std::stri time_t local = ServerInstance->Time(); struct tm *timeinfo = localtime(&local); - strlcpy(TIMESTR,asctime(timeinfo),26); - TIMESTR[24] = ':'; + TIMESTR.assign(asctime(timeinfo), 24); LAST = ServerInstance->Time(); } - std::string out = std::string(TIMESTR) + " " + text.c_str() + "\n"; - this->f->WriteLogLine(out); + this->f->WriteLogLine(TIMESTR + " " + type + ": " + text + "\n"); } diff --git a/src/hashcomp.cpp b/src/hashcomp.cpp index 3fb7f84fb..4eb416406 100644 --- a/src/hashcomp.cpp +++ b/src/hashcomp.cpp @@ -20,11 +20,8 @@ */ -/* $Core */ - #include "inspircd.h" #include "hashcomp.h" -#include "hash_map.h" /****************************************************** * @@ -35,7 +32,7 @@ * scene spend a lot of time debating (arguing) about * the best way to write hash functions to hash irc * nicknames, channels etc. - * We are lucky as C++ developers as hash_map does + * We are lucky as C++ developers as unordered_map does * a lot of this for us. It does intellegent memory * requests, bucketing, search functions, insertion * and deletion etc. All we have to do is write some @@ -51,101 +48,109 @@ * ******************************************************/ -/** A mapping of uppercase to lowercase, including scandinavian - * 'oddities' as specified by RFC1459, e.g. { -> [, and | -> \ - */ -unsigned const char rfc_case_insensitive_map[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 0-19 */ - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, /* 20-39 */ - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, /* 40-59 */ - 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, /* 60-79 */ - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 94, 95, 96, 97, 98, 99, /* 80-99 */ - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, /* 100-119 */ - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, /* 120-139 */ - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, /* 140-159 */ - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, /* 160-179 */ - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, /* 180-199 */ - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, /* 200-219 */ - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, /* 220-239 */ - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 /* 240-255 */ -}; -/** Case insensitive map, ASCII rules. - * That is; - * [ != {, but A == a. +/** + * A case insensitive mapping of characters from upper case to lower case for + * the ASCII character set. */ unsigned const char ascii_case_insensitive_map[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 0-19 */ - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, /* 20-39 */ - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, /* 40-59 */ - 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, /* 60-79 */ - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, /* 80-99 */ - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, /* 100-119 */ - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, /* 120-139 */ - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, /* 140-159 */ - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, /* 160-179 */ - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, /* 180-199 */ - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, /* 200-219 */ - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, /* 220-239 */ - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 /* 240-255 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // 0-9 + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 10-19 + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, // 20-29 + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, // 30-39 + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, // 40-49 + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, // 50-59 + 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, // 60-69 + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 70-79 + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, // 80-89 + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, // 90-99 + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, // 100-109 + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, // 110-119 + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, // 120-129 + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, // 130-139 + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, // 140-149 + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, // 150-159 + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, // 160-169 + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, // 170-179 + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, // 180-189 + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, // 190-199 + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, // 200-209 + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, // 210-219 + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, // 220-229 + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // 230-249 + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, // 240-249 + 250, 251, 252, 253, 254, 255, // 250-255 }; -/** Case sensitive map. - * Can technically also be used for ASCII case sensitive comparisons, as [ != {, etc. + + +/** + * A case insensitive mapping of characters from upper case to lower case for + * the character set of RFC 1459. This is identical to ASCII with the small + * exception of {}| being considered to be the lower case equivalents of the + * characters []\ respectively. */ -unsigned const char rfc_case_sensitive_map[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 +unsigned const char rfc_case_insensitive_map[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // 0-9 + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 10-19 + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, // 20-29 + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, // 30-39 + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, // 40-49 + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, // 50-59 + 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, // 60-69 + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 70-79 + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, // 80-89 + 122, 123, 124, 125, 94, 95, 96, 97, 98, 99, // 90-99 + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, // 100-109 + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, // 110-119 + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, // 120-129 + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, // 130-139 + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, // 140-149 + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, // 150-159 + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, // 160-169 + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, // 170-179 + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, // 180-189 + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, // 190-199 + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, // 200-209 + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, // 210-219 + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, // 220-229 + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // 230-239 + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, // 240-249 + 250, 251, 252, 253, 254, 255, // 250-255 }; -/* convert a string to lowercase. Note following special circumstances - * taken from RFC 1459. Many "official" server branches still hold to this - * rule so i will too; - * - * Because of IRC's scandanavian origin, the characters {}| are - * considered to be the lower case equivalents of the characters []\, - * respectively. This is a critical issue when determining the - * equivalence of two nicknames. +/** + * A case sensitive mapping of characters from upper case to lower case for the + * character set of RFC 1459. This is identical to ASCII. */ -void nspace::strlower(char *n) -{ - if (n) - { - for (char* t = n; *t; t++) - *t = national_case_insensitive_map[(unsigned char)*t]; - } -} - -#ifdef HASHMAP_DEPRECATED - size_t CoreExport nspace::insensitive::operator()(const std::string &s) const -#else - size_t nspace::hash<std::string>::operator()(const std::string &s) const -#endif - -{ - /* XXX: NO DATA COPIES! :) - * The hash function here is practically - * a copy of the one in STL's hash_fun.h, - * only with *x replaced with national_case_insensitive_map[*x]. - * This avoids a copy to use hash<const char*> - */ - register size_t t = 0; - for (std::string::const_iterator x = s.begin(); x != s.end(); ++x) /* ++x not x++, as its faster */ - t = 5 * t + national_case_insensitive_map[(unsigned char)*x]; - return t; -} - +unsigned const char rfc_case_sensitive_map[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // 0-9 + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 10-19 + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, // 20-29 + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, // 30-39 + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, // 40-49 + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, // 50-59 + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, // 60-69 + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 70-79 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, // 80-89 + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, // 90-99 + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, // 100-109 + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, // 110-119 + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, // 120-129 + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, // 130-139 + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, // 140-149 + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, // 150-159 + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, // 160-169 + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, // 170-179 + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, // 180-189 + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, // 190-199 + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, // 200-209 + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, // 210-219 + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, // 220-229 + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // 230-239 + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, // 240-249 + 250, 251, 252, 253, 254, 255, // 250-255 +}; size_t CoreExport irc::hash::operator()(const irc::string &s) const { @@ -165,6 +170,20 @@ bool irc::StrHashComp::operator()(const std::string& s1, const std::string& s2) return (national_case_insensitive_map[*n1] == national_case_insensitive_map[*n2]); } +size_t irc::insensitive::operator()(const std::string &s) const +{ + /* XXX: NO DATA COPIES! :) + * The hash function here is practically + * a copy of the one in STL's hash_fun.h, + * only with *x replaced with national_case_insensitive_map[*x]. + * This avoids a copy to use hash<const char*> + */ + register size_t t = 0; + for (std::string::const_iterator x = s.begin(); x != s.end(); ++x) /* ++x not x++, as its faster */ + t = 5 * t + national_case_insensitive_map[(unsigned char)*x]; + return t; +} + /****************************************************** * * This is the implementation of our special irc::string @@ -217,60 +236,30 @@ const char* irc::irc_char_traits::find(const char* s1, int n, char c) return (n >= 0) ? s1 : NULL; } -irc::tokenstream::tokenstream(const std::string &source) : tokens(source), last_pushed(false) -{ - /* Record starting position and current position */ - last_starting_position = tokens.begin(); - n = tokens.begin(); -} - -irc::tokenstream::~tokenstream() +irc::tokenstream::tokenstream(const std::string &source) : spacesepstream(source) { } bool irc::tokenstream::GetToken(std::string &token) { - std::string::iterator lsp = last_starting_position; + bool first = !pos; - while (n != tokens.end()) - { - /** Skip multi space, converting " " into " " - */ - while ((n+1 != tokens.end()) && (*n == ' ') && (*(n+1) == ' ')) - n++; - - if ((last_pushed) && (*n == ':')) - { - /* If we find a token thats not the first and starts with :, - * this is the last token on the line - */ - std::string::iterator curr = ++n; - n = tokens.end(); - token = std::string(curr, tokens.end()); - return true; - } - - last_pushed = false; + if (!spacesepstream::GetToken(token)) + return false; - if ((*n == ' ') || (n+1 == tokens.end())) + /* This is the last parameter */ + if (token[0] == ':' && !first) + { + token = token.substr(1); + if (!StreamEnd()) { - /* If we find a space, or end of string, this is the end of a token. - */ - last_starting_position = n+1; - last_pushed = *n == ' '; - - std::string strip(lsp, n+1 == tokens.end() ? n+1 : n++); - while ((strip.length()) && (strip.find_last_of(' ') == strip.length() - 1)) - strip.erase(strip.end() - 1); - - token = strip; - return !token.empty(); + token += ' '; + token += GetRemaining(); } - - n++; + pos = tokens.length() + 1; } - token.clear(); - return false; + + return true; } bool irc::tokenstream::GetToken(irc::string &token) @@ -297,85 +286,50 @@ bool irc::tokenstream::GetToken(long &token) return returnval; } -irc::sepstream::sepstream(const std::string &source, char seperator) : tokens(source), sep(seperator) +irc::sepstream::sepstream(const std::string& source, char separator, bool allowempty) + : tokens(source), sep(separator), pos(0), allow_empty(allowempty) { - last_starting_position = tokens.begin(); - n = tokens.begin(); } bool irc::sepstream::GetToken(std::string &token) { - std::string::iterator lsp = last_starting_position; + if (this->StreamEnd()) + { + token.clear(); + return false; + } - while (n != tokens.end()) + if (!this->allow_empty) { - if ((*n == sep) || (n+1 == tokens.end())) + this->pos = this->tokens.find_first_not_of(this->sep, this->pos); + if (this->pos == std::string::npos) { - last_starting_position = n+1; - token = std::string(lsp, n+1 == tokens.end() ? n+1 : n++); - - while ((token.length()) && (token.find_last_of(sep) == token.length() - 1)) - token.erase(token.end() - 1); - - if (token.empty()) - n++; - - return n == tokens.end() ? false : true; + this->pos = this->tokens.length() + 1; + token.clear(); + return false; } - - n++; } - token.clear(); - return false; -} - -const std::string irc::sepstream::GetRemaining() -{ - return std::string(n, tokens.end()); -} + size_t p = this->tokens.find(this->sep, this->pos); + if (p == std::string::npos) + p = this->tokens.length(); -bool irc::sepstream::StreamEnd() -{ - return ((n + 1) == tokens.end()); -} + token = this->tokens.substr(this->pos, p - this->pos); + this->pos = p + 1; -irc::sepstream::~sepstream() -{ + return true; } -std::string irc::hex(const unsigned char *raw, size_t rawsz) +const std::string irc::sepstream::GetRemaining() { - if (!rawsz) - return ""; - - /* EWW! This used to be using sprintf, which is WAY inefficient. -Special */ - - const char *hex = "0123456789abcdef"; - static char hexbuf[MAXBUF]; - - size_t i, j; - for (i = 0, j = 0; j < rawsz; ++j) - { - hexbuf[i++] = hex[raw[j] / 16]; - hexbuf[i++] = hex[raw[j] % 16]; - } - hexbuf[i] = 0; - - return hexbuf; + return !this->StreamEnd() ? this->tokens.substr(this->pos) : ""; } -CoreExport const char* irc::Spacify(const char* n) +bool irc::sepstream::StreamEnd() { - static char x[MAXBUF]; - strlcpy(x,n,MAXBUF); - for (char* y = x; *y; y++) - if (*y == '_') - *y = ' '; - return x; + return this->pos > this->tokens.length(); } - irc::modestacker::modestacker(bool add) : adding(add) { sequence.clear(); @@ -441,39 +395,14 @@ int irc::modestacker::GetStackedLine(std::vector<std::string> &result, int max_l return n; } -irc::stringjoiner::stringjoiner(const std::string &seperator, const std::vector<std::string> &sequence, int begin, int end) -{ - if (end < begin) - return; // nothing to do here - - for (int v = begin; v < end; v++) - joined.append(sequence[v]).append(seperator); - joined.append(sequence[end]); -} - -irc::stringjoiner::stringjoiner(const std::string &seperator, const std::deque<std::string> &sequence, int begin, int end) +irc::stringjoiner::stringjoiner(const std::vector<std::string>& sequence) { - if (end < begin) - return; // nothing to do here - - for (int v = begin; v < end; v++) - joined.append(sequence[v]).append(seperator); - joined.append(sequence[end]); -} - -irc::stringjoiner::stringjoiner(const std::string &seperator, const char* const* sequence, int begin, int end) -{ - if (end < begin) + if (sequence.empty()) return; // nothing to do here - for (int v = begin; v < end; v++) - joined.append(sequence[v]).append(seperator); - joined.append(sequence[end]); -} - -std::string& irc::stringjoiner::GetJoined() -{ - return joined; + for (std::vector<std::string>::const_iterator i = sequence.begin(); i != sequence.end(); ++i) + joined.append(*i).push_back(' '); + joined.erase(joined.end()-1); } irc::portparser::portparser(const std::string &source, bool allow_overlapped) @@ -549,25 +478,3 @@ long irc::portparser::GetToken() return atoi(x.c_str()); } } - -/*const std::basic_string& SearchAndReplace(std::string& text, const std::string& pattern, const std::string& replace) -{ - std::string replacement; - if ((!pattern.empty()) && (!text.empty())) - { - for (std::string::size_type n = 0; n != text.length(); ++n) - { - if (text.length() >= pattern.length() && text.substr(n, pattern.length()) == pattern) - { - replacement.append(replace); - n = n + pattern.length() - 1; - } - else - { - replacement += text[n]; - } - } - } - text = replacement; - return text; -}*/ diff --git a/src/helperfuncs.cpp b/src/helperfuncs.cpp index 439320c1e..cfbd53c98 100644 --- a/src/helperfuncs.cpp +++ b/src/helperfuncs.cpp @@ -22,8 +22,6 @@ */ -/* $Core */ - #ifdef _WIN32 #define _CRT_RAND_S #include <stdlib.h> @@ -38,7 +36,7 @@ std::string InspIRCd::GetServerDescription(const std::string& servername) { std::string description; - FOREACH_MOD(I_OnGetServerDescription,OnGetServerDescription(servername,description)); + FOREACH_MOD(OnGetServerDescription, (servername,description)); if (!description.empty()) { @@ -66,19 +64,6 @@ User* InspIRCd::FindNick(const std::string &nick) return iter->second; } -User* InspIRCd::FindNick(const char* nick) -{ - if (isdigit(*nick)) - return FindUUID(nick); - - user_hash::iterator iter = this->Users->clientlist->find(nick); - - if (iter == this->Users->clientlist->end()) - return NULL; - - return iter->second; -} - User* InspIRCd::FindNickOnly(const std::string &nick) { user_hash::iterator iter = this->Users->clientlist->find(nick); @@ -89,16 +74,6 @@ User* InspIRCd::FindNickOnly(const std::string &nick) return iter->second; } -User* InspIRCd::FindNickOnly(const char* nick) -{ - user_hash::iterator iter = this->Users->clientlist->find(nick); - - if (iter == this->Users->clientlist->end()) - return NULL; - - return iter->second; -} - User *InspIRCd::FindUUID(const std::string &uid) { user_hash::iterator finduuid = this->Users->uuidlist->find(uid); @@ -108,23 +83,7 @@ User *InspIRCd::FindUUID(const std::string &uid) return finduuid->second; } - -User *InspIRCd::FindUUID(const char *uid) -{ - return FindUUID(std::string(uid)); -} - /* find a channel record by channel name and return a pointer to it */ -Channel* InspIRCd::FindChan(const char* chan) -{ - chan_hash::iterator iter = chanlist->find(chan); - - if (iter == chanlist->end()) - /* Couldn't find it */ - return NULL; - - return iter->second; -} Channel* InspIRCd::FindChan(const std::string &chan) { @@ -145,8 +104,8 @@ void InspIRCd::SendError(const std::string &s) User* u = *i; if (u->registered == REG_ALL) { - u->WriteServ("NOTICE %s :%s",u->nick.c_str(),s.c_str()); - } + u->WriteNotice(s); + } else { /* Unregistered connections receive ERROR, not a NOTICE */ @@ -155,12 +114,6 @@ void InspIRCd::SendError(const std::string &s) } } -/* return channel count */ -long InspIRCd::ChannelCount() -{ - return chanlist->size(); -} - bool InspIRCd::IsValidMask(const std::string &mask) { const char* dest = mask.c_str(); @@ -281,47 +234,35 @@ void InspIRCd::ProcessColors(file_cache& input) } /* true for valid channel name, false else */ -bool IsChannelHandler::Call(const char *chname, size_t max) +bool IsChannelHandler::Call(const std::string& chname) { - const char *c = chname + 1; + if (chname.empty() || chname.length() > ServerInstance->Config->Limits.ChanMax) + return false; - /* check for no name - don't check for !*chname, as if it is empty, it won't be '#'! */ - if (!chname || *chname != '#') - { + if (chname[0] != '#') return false; - } - while (*c) + for (std::string::const_iterator i = chname.begin()+1; i != chname.end(); ++i) { - switch (*c) + switch (*i) { case ' ': case ',': case 7: return false; } - - c++; - } - - size_t len = c - chname; - /* too long a name - note funky pointer arithmetic here. */ - if (len > max) - { - return false; } return true; } /* true for valid nickname, false else */ -bool IsNickHandler::Call(const char* n, size_t max) +bool IsNickHandler::Call(const std::string& n) { - if (!n || !*n) + if (n.empty() || n.length() > ServerInstance->Config->Limits.NickMax) return false; - unsigned int p = 0; - for (const char* i = n; *i; i++, p++) + for (std::string::const_iterator i = n.begin(); i != n.end(); ++i) { if ((*i >= 'A') && (*i <= '}')) { @@ -329,7 +270,7 @@ bool IsNickHandler::Call(const char* n, size_t max) continue; } - if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i > n)) + if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i != n.begin())) { /* "0"-"9", "-" can occur anywhere BUT the first char of a nickname */ continue; @@ -339,17 +280,16 @@ bool IsNickHandler::Call(const char* n, size_t max) return false; } - /* too long? or not */ - return (p <= max); + return true; } /* return true for good ident, false else */ -bool IsIdentHandler::Call(const char* n) +bool IsIdentHandler::Call(const std::string& n) { - if (!n || !*n) + if (n.empty()) return false; - for (const char* i = n; *i; i++) + for (std::string::const_iterator i = n.begin(); i != n.end(); ++i) { if ((*i >= 'A') && (*i <= '}')) { @@ -367,7 +307,7 @@ bool IsIdentHandler::Call(const char* n) return true; } -bool IsSIDHandler::Call(const std::string &str) +bool InspIRCd::IsSID(const std::string &str) { /* Returns true if the string given is exactly 3 characters long, * starts with a digit, and the other two characters are A-Z or digits @@ -377,35 +317,13 @@ bool IsSIDHandler::Call(const std::string &str) ((str[2] >= 'A' && str[2] <= 'Z') || isdigit(str[2]))); } -/* open the proper logfile */ -bool InspIRCd::OpenLog(char**, int) -{ - if (!Config->cmdline.writelog) return true; // Skip opening default log if -nolog - - if (Config->cmdline.startup_log.empty()) - Config->cmdline.startup_log = LOG_PATH "/startup.log"; - FILE* startup = fopen(Config->cmdline.startup_log.c_str(), "a+"); - - if (!startup) - { - return false; - } - - FileWriter* fw = new FileWriter(startup); - FileLogStream *f = new FileLogStream((Config->cmdline.forcedebug ? DEBUG : DEFAULT), fw); - - this->Logs->AddLogType("*", f, true); - - return true; -} - void InspIRCd::CheckRoot() { #ifndef _WIN32 if (geteuid() == 0) { std::cout << "ERROR: You are running an irc server as root! DO NOT DO THIS!" << std::endl << std::endl; - this->Logs->Log("STARTUP",DEFAULT,"Can't start as root"); + this->Logs->Log("STARTUP", LOG_DEFAULT, "Can't start as root"); Exit(EXIT_STATUS_ROOT); } #endif @@ -424,19 +342,15 @@ void InspIRCd::SendWhoisLine(User* user, User* dest, int numeric, const std::str void InspIRCd::SendWhoisLine(User* user, User* dest, int numeric, const char* format, ...) { - char textbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, format); - vsnprintf(textbuffer, MAXBUF, format, argsPtr); - va_end(argsPtr); - - this->SendWhoisLine(user, dest, numeric, std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, format, format) + this->SendWhoisLine(user, dest, numeric, textbuffer); } /** Refactored by Brain, Jun 2009. Much faster with some clever O(1) array * lookups and pointer maths. */ -long InspIRCd::Duration(const std::string &str) +unsigned long InspIRCd::Duration(const std::string &str) { unsigned char multiplier = 0; long total = 0; @@ -476,6 +390,34 @@ long InspIRCd::Duration(const std::string &str) return total + subtotal; } +const char* InspIRCd::Format(va_list &vaList, const char* formatString) +{ + static std::vector<char> formatBuffer(1024); + + while (true) + { + va_list dst; + va_copy(dst, vaList); + + int vsnret = vsnprintf(&formatBuffer[0], formatBuffer.size(), formatString, dst); + if (vsnret > 0 && static_cast<unsigned>(vsnret) < formatBuffer.size()) + { + return &formatBuffer[0]; + } + + formatBuffer.resize(formatBuffer.size() * 2); + } + + throw CoreException(); +} + +const char* InspIRCd::Format(const char* formatString, ...) +{ + const char* ret; + VAFORMAT(ret, formatString, formatString); + return ret; +} + bool InspIRCd::ULine(const std::string& sserver) { if (sserver.empty()) @@ -517,26 +459,6 @@ std::string InspIRCd::TimeString(time_t curtime) return std::string(asctime(timeinfo),24); } -// You should only pass a single character to this. -void InspIRCd::AddExtBanChar(char c) -{ - std::string &tok = Config->data005; - std::string::size_type ebpos = tok.find(" EXTBAN=,"); - - if (ebpos == std::string::npos) - { - tok.append(" EXTBAN=,"); - tok.push_back(c); - } - else - { - ebpos += 9; - while (isalpha(tok[ebpos]) && tok[ebpos] < c) - ebpos++; - tok.insert(ebpos, 1, c); - } -} - std::string InspIRCd::GenRandomStr(int length, bool printable) { char* buf = new char[length]; diff --git a/src/inspircd.cpp b/src/inspircd.cpp index 9516449a0..2171e2a9f 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -26,9 +26,7 @@ */ -/* $Core */ #include "inspircd.h" -#include "inspircd_version.h" #include <signal.h> #ifndef _WIN32 @@ -63,7 +61,6 @@ #include "testsuite.h" InspIRCd* ServerInstance = NULL; -int* mysig = NULL; /** Seperate from the other casemap tables so that code *can* still exclusively rely on RFC casemapping * if it must. @@ -79,26 +76,17 @@ unsigned const char *national_case_insensitive_map = rfc_case_insensitive_map; */ const char* ExitCodes[] = { - "No error", /* 0 */ - "DIE command", /* 1 */ - "execv() failed", /* 2 */ - "Internal error", /* 3 */ - "Config file error", /* 4 */ - "Logfile error", /* 5 */ - "POSIX fork failed", /* 6 */ - "Bad commandline parameters", /* 7 */ - "No ports could be bound", /* 8 */ - "Can't write PID file", /* 9 */ - "SocketEngine could not initialize", /* 10 */ - "Refusing to start up as root", /* 11 */ - "Found a <die> tag!", /* 12 */ - "Couldn't load module on startup", /* 13 */ - "Could not create windows forked process", /* 14 */ - "Received SIGTERM", /* 15 */ - "Bad command handler loaded", /* 16 */ - "RegisterServiceCtrlHandler failed", /* 17 */ - "UpdateSCMStatus failed", /* 18 */ - "CreateEvent failed" /* 19 */ + "No error", // 0 + "DIE command", // 1 + "Config file error", // 2 + "Logfile error", // 3 + "POSIX fork failed", // 4 + "Bad commandline parameters", // 5 + "Can't write PID file", // 6 + "SocketEngine could not initialize", // 7 + "Refusing to start up as root", // 8 + "Couldn't load module on startup", // 9 + "Received SIGTERM" // 10 }; template<typename T> static void DeleteZero(T*&n) @@ -110,9 +98,9 @@ template<typename T> static void DeleteZero(T*&n) void InspIRCd::Cleanup() { + // Close all listening sockets for (unsigned int i = 0; i < ports.size(); i++) { - /* This calls the constructor and closes the listening socket */ ports[i]->cull(); delete ports[i]; } @@ -133,8 +121,6 @@ void InspIRCd::Cleanup() /* Must be deleted before modes as it decrements modelines */ if (FakeClient) FakeClient->cull(); - if (Res) - Res->cull(); DeleteZero(this->FakeClient); DeleteZero(this->Users); DeleteZero(this->Modes); @@ -145,87 +131,15 @@ void InspIRCd::Cleanup() DeleteZero(this->BanCache); DeleteZero(this->SNO); DeleteZero(this->Config); - DeleteZero(this->Res); DeleteZero(this->chanlist); DeleteZero(this->PI); DeleteZero(this->Threads); DeleteZero(this->Timers); DeleteZero(this->SE); - /* Close logging */ - this->Logs->CloseLogs(); + Logs->CloseLogs(); DeleteZero(this->Logs); } -void InspIRCd::Restart(const std::string &reason) -{ - /* SendError flushes each client's queue, - * regardless of writeability state - */ - this->SendError(reason); - - /* Figure out our filename (if theyve renamed it, we're boned) */ - std::string me; - - char** argv = Config->cmdline.argv; - -#ifdef _WIN32 - char module[MAX_PATH]; - if (GetModuleFileNameA(NULL, module, MAX_PATH)) - me = module; -#else - me = argv[0]; -#endif - - this->Cleanup(); - - if (execv(me.c_str(), argv) == -1) - { - /* Will raise a SIGABRT if not trapped */ - throw CoreException(std::string("Failed to execv()! error: ") + strerror(errno)); - } -} - -void InspIRCd::ResetMaxBans() -{ - for (chan_hash::const_iterator i = chanlist->begin(); i != chanlist->end(); i++) - i->second->ResetMaxBans(); -} - -/** Because hash_map doesn't free its buckets when we delete items, we occasionally - * recreate the hash to free them up. - * We do this by copying the entries from the old hash to a new hash, causing all - * empty buckets to be weeded out of the hash. - * Since this is quite expensive, it's not done very often. - */ -void InspIRCd::RehashUsersAndChans() -{ - user_hash* old_users = Users->clientlist; - Users->clientlist = new user_hash; - for (user_hash::const_iterator n = old_users->begin(); n != old_users->end(); n++) - Users->clientlist->insert(*n); - delete old_users; - - user_hash* old_uuid = Users->uuidlist; - Users->uuidlist = new user_hash; - for (user_hash::const_iterator n = old_uuid->begin(); n != old_uuid->end(); n++) - Users->uuidlist->insert(*n); - delete old_uuid; - - chan_hash* old_chans = chanlist; - chanlist = new chan_hash; - for (chan_hash::const_iterator n = old_chans->begin(); n != old_chans->end(); n++) - chanlist->insert(*n); - delete old_chans; - - // Reset the already_sent IDs so we don't wrap it around and drop a message - LocalUser::already_sent_id = 0; - for (LocalUserList::const_iterator i = Users->local_users.begin(); i != Users->local_users.end(); i++) - { - (**i).already_sent = 0; - (**i).RemoveExpiredInvites(); - } -} - void InspIRCd::SetSignals() { #ifndef _WIN32 @@ -252,8 +166,8 @@ bool InspIRCd::DaemonSeed() #else signal(SIGTERM, InspIRCd::QuickExit); - int childpid; - if ((childpid = fork ()) < 0) + int childpid = fork(); + if (childpid < 0) return false; else if (childpid > 0) { @@ -276,13 +190,13 @@ bool InspIRCd::DaemonSeed() rlimit rl; if (getrlimit(RLIMIT_CORE, &rl) == -1) { - this->Logs->Log("STARTUP",DEFAULT,"Failed to getrlimit()!"); + this->Logs->Log("STARTUP", LOG_DEFAULT, "Failed to getrlimit()!"); return false; } rl.rlim_cur = rl.rlim_max; if (setrlimit(RLIMIT_CORE, &rl) == -1) - this->Logs->Log("STARTUP",DEFAULT,"setrlimit() failed, cannot increase coredump size."); + this->Logs->Log("STARTUP", LOG_DEFAULT, "setrlimit() failed, cannot increase coredump size."); return true; #endif @@ -293,7 +207,7 @@ void InspIRCd::WritePID(const std::string &filename) #ifndef _WIN32 std::string fname(filename); if (fname.empty()) - fname = DATA_PATH "/inspircd.pid"; + fname = ServerInstance->Config->Paths.PrependData("inspircd.pid"); std::ofstream outfile(fname.c_str()); if (outfile.is_open()) { @@ -303,7 +217,7 @@ void InspIRCd::WritePID(const std::string &filename) else { std::cout << "Failed to write PID-file '" << fname << "', exiting." << std::endl; - this->Logs->Log("STARTUP",DEFAULT,"Failed to write PID-file '%s', exiting.",fname.c_str()); + this->Logs->Log("STARTUP", LOG_DEFAULT, "Failed to write PID-file '%s', exiting.",fname.c_str()); Exit(EXIT_STATUS_PID); } #endif @@ -317,26 +231,21 @@ InspIRCd::InspIRCd(int argc, char** argv) : * THIS MUST MATCH THE ORDER OF DECLARATION OF THE FUNCTORS, e.g. the methods * themselves within the class. */ - NICKForced("NICKForced", NULL), - OperQuit("OperQuit", NULL), + OperQuit("operquit", NULL), GenRandom(&HandleGenRandom), IsChannel(&HandleIsChannel), - IsSID(&HandleIsSID), Rehash(&HandleRehash), IsNick(&HandleIsNick), IsIdent(&HandleIsIdent), - FloodQuitUser(&HandleFloodQuitUser), OnCheckExemption(&HandleOnCheckExemption) { ServerInstance = this; - Extensions.Register(&NICKForced); Extensions.Register(&OperQuit); FailedPortList pl; int do_version = 0, do_nofork = 0, do_debug = 0, do_nolog = 0, do_root = 0, do_testsuite = 0; /* flag variables */ - int c = 0; // Initialize so that if we exit before proper initialization they're not deleted this->Logs = 0; @@ -353,7 +262,6 @@ InspIRCd::InspIRCd(int argc, char** argv) : this->Parser = 0; this->XLines = 0; this->Modes = 0; - this->Res = 0; this->ConfigThread = NULL; this->FakeClient = NULL; @@ -370,19 +278,16 @@ InspIRCd::InspIRCd(int argc, char** argv) : /* Default implementation does nothing */ this->PI = new ProtocolInterface; - this->s_signal = 0; - // Create base manager classes early, so nothing breaks this->Users = new UserManager; - this->Users->clientlist = new user_hash(); - this->Users->uuidlist = new user_hash(); this->chanlist = new chan_hash(); this->Config = new ServerConfig; this->SNO = new SnomaskManager; this->BanCache = new BanCacheManager; this->Modules = new ModuleManager(); + dynamic_reference_base::reset_all(); this->stats = new serverstats(); this->Timers = new TimerManager; this->Parser = new CommandParser; @@ -414,7 +319,6 @@ InspIRCd::InspIRCd(int argc, char** argv) : struct option longopts[] = { { "nofork", no_argument, &do_nofork, 1 }, - { "logfile", required_argument, NULL, 'f' }, { "config", required_argument, NULL, 'c' }, { "debug", no_argument, &do_debug, 1 }, { "nolog", no_argument, &do_nolog, 1 }, @@ -424,15 +328,12 @@ InspIRCd::InspIRCd(int argc, char** argv) : { 0, 0, 0, 0 } }; + int c; int index; - while ((c = getopt_long(argc, argv, ":c:f:", longopts, &index)) != -1) + while ((c = getopt_long(argc, argv, ":c:", longopts, &index)) != -1) { switch (c) { - case 'f': - /* Log filename was set */ - Config->cmdline.startup_log = optarg; - break; case 'c': /* Config filename was set */ ConfigFileName = optarg; @@ -445,8 +346,8 @@ InspIRCd::InspIRCd(int argc, char** argv) : default: /* Fall through to handle other weird values too */ std::cout << "Unknown parameter '" << argv[optind-1] << "'" << std::endl; - std::cout << "Usage: " << argv[0] << " [--nofork] [--nolog] [--debug] [--logfile <filename>] " << std::endl << - std::string(static_cast<int>(8+strlen(argv[0])), ' ') << "[--runasroot] [--version] [--config <config>] [--testsuite]" << std::endl; + std::cout << "Usage: " << argv[0] << " [--nofork] [--nolog] [--debug] [--config <config>]" << std::endl << + std::string(static_cast<int>(8+strlen(argv[0])), ' ') << "[--runasroot] [--version] [--testsuite]" << std::endl; Exit(EXIT_STATUS_ARGV); break; } @@ -457,7 +358,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : if (do_version) { - std::cout << std::endl << VERSION << " r" << REVISION << std::endl; + std::cout << std::endl << VERSION << " " << REVISION << std::endl; Exit(EXIT_STATUS_NOERROR); } @@ -476,14 +377,9 @@ InspIRCd::InspIRCd(int argc, char** argv) : if (do_debug) { FileWriter* fw = new FileWriter(stdout); - FileLogStream* fls = new FileLogStream(RAWIO, fw); + FileLogStream* fls = new FileLogStream(LOG_RAWIO, fw); Logs->AddLogTypes("*", fls, true); } - else if (!this->OpenLog(argv, argc)) - { - std::cout << "ERROR: Could not open initial logfile " << Config->cmdline.startup_log << ": " << strerror(errno) << std::endl << std::endl; - Exit(EXIT_STATUS_LOG); - } if (!ServerConfig::FileExists(ConfigFileName.c_str())) { @@ -500,7 +396,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : #endif { std::cout << "ERROR: Cannot open config file: " << ConfigFileName << std::endl << "Exiting..." << std::endl; - this->Logs->Log("STARTUP",DEFAULT,"Unable to open config file %s", ConfigFileName.c_str()); + this->Logs->Log("STARTUP", LOG_DEFAULT, "Unable to open config file %s", ConfigFileName.c_str()); Exit(EXIT_STATUS_CONFIG); } } @@ -509,7 +405,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : std::cout << con_green << "(C) InspIRCd Development Team." << con_reset << std::endl << std::endl; std::cout << "Developers:" << std::endl; std::cout << con_green << "\tBrain, FrostyCoolSlug, w00t, Om, Special, peavey" << std::endl; - std::cout << "\taquanight, psychon, dz, danieldg, jackmcbarn" << std::endl;
+ std::cout << "\taquanight, psychon, dz, danieldg, jackmcbarn" << std::endl; std::cout << "\tAttila" << con_reset << std::endl << std::endl; std::cout << "Others:\t\t\t" << con_green << "See /INFO Output" << con_reset << std::endl; @@ -520,14 +416,14 @@ InspIRCd::InspIRCd(int argc, char** argv) : this->CheckRoot(); else { - std::cout << "* WARNING * WARNING * WARNING * WARNING * WARNING *" << std::endl
- << "YOU ARE RUNNING INSPIRCD AS ROOT. THIS IS UNSUPPORTED" << std::endl
- << "AND IF YOU ARE HACKED, CRACKED, SPINDLED OR MUTILATED" << std::endl
- << "OR ANYTHING ELSE UNEXPECTED HAPPENS TO YOU OR YOUR" << std::endl
- << "SERVER, THEN IT IS YOUR OWN FAULT. IF YOU DID NOT MEAN" << std::endl
- << "TO START INSPIRCD AS ROOT, HIT CTRL+C NOW AND RESTART" << std::endl
- << "THE PROGRAM AS A NORMAL USER. YOU HAVE BEEN WARNED!" << std::endl << std::endl
- << "InspIRCd starting in 20 seconds, ctrl+c to abort..." << std::endl;
+ std::cout << "* WARNING * WARNING * WARNING * WARNING * WARNING *" << std::endl + << "YOU ARE RUNNING INSPIRCD AS ROOT. THIS IS UNSUPPORTED" << std::endl + << "AND IF YOU ARE HACKED, CRACKED, SPINDLED OR MUTILATED" << std::endl + << "OR ANYTHING ELSE UNEXPECTED HAPPENS TO YOU OR YOUR" << std::endl + << "SERVER, THEN IT IS YOUR OWN FAULT. IF YOU DID NOT MEAN" << std::endl + << "TO START INSPIRCD AS ROOT, HIT CTRL+C NOW AND RESTART" << std::endl + << "THE PROGRAM AS A NORMAL USER. YOU HAVE BEEN WARNED!" << std::endl << std::endl + << "InspIRCd starting in 20 seconds, ctrl+c to abort..." << std::endl; sleep(20); } #endif @@ -539,47 +435,32 @@ InspIRCd::InspIRCd(int argc, char** argv) : if (!this->DaemonSeed()) { std::cout << "ERROR: could not go into daemon mode. Shutting down." << std::endl; - Logs->Log("STARTUP", DEFAULT, "ERROR: could not go into daemon mode. Shutting down."); + Logs->Log("STARTUP", LOG_DEFAULT, "ERROR: could not go into daemon mode. Shutting down."); Exit(EXIT_STATUS_FORK); } } SE->RecoverFromFork(); - /* During startup we don't actually initialize this - * in the thread engine. + /* During startup we read the configuration now, not in + * a seperate thread */ this->Config->Read(); this->Config->Apply(NULL, ""); Logs->OpenFileLogs(); + ModeParser::InitBuiltinModes(); - this->Res = new DNS(); - - /* - * Initialise SID/UID. - * For an explanation as to exactly how this works, and why it works this way, see GetUID(). - * -- w00t - */ + // If we don't have a SID, generate one based on the server name and the server description if (Config->sid.empty()) - { - // Generate one - unsigned int sid = 0; - char sidstr[4]; - - for (const char* x = Config->ServerName.c_str(); *x; ++x) - sid = 5 * sid + *x; - for (const char* y = Config->ServerDesc.c_str(); *y; ++y) - sid = 5 * sid + *y; - sprintf(sidstr, "%03d", sid % 1000); + Config->sid = UIDGenerator::GenerateSID(Config->ServerName, Config->ServerDesc); - Config->sid = sidstr; - } + // Initialize the UID generator with our sid + this->UIDGen.init(Config->sid); - /* set up fake client again this time with the correct uid */ + // Create the server user for this server this->FakeClient = new FakeUser(Config->sid, Config->ServerName); - // Get XLine to do it's thing. - this->XLines->CheckELines(); + // This is needed as all new XLines are marked pending until ApplyLines() is called this->XLines->ApplyLines(); int bounditems = BindPorts(pl); @@ -588,8 +469,8 @@ InspIRCd::InspIRCd(int argc, char** argv) : this->Modules->LoadAll(); - /* Just in case no modules were loaded - fix for bug #101 */ - this->BuildISupport(); + // Build ISupport as ModuleManager::LoadAll() does not do it + this->ISupport.Build(); Config->ApplyDisabledCommands(Config->DisabledCommands); if (!pl.empty()) @@ -614,7 +495,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : if (kill(getppid(), SIGTERM) == -1) { std::cout << "Error killing parent process: " << strerror(errno) << std::endl; - Logs->Log("STARTUP", DEFAULT, "Error killing parent process: %s",strerror(errno)); + Logs->Log("STARTUP", LOG_DEFAULT, "Error killing parent process: %s",strerror(errno)); } } @@ -637,16 +518,16 @@ InspIRCd::InspIRCd(int argc, char** argv) : fclose(stdout); if (dup2(fd, STDIN_FILENO) < 0) - Logs->Log("STARTUP", DEFAULT, "Failed to dup /dev/null to stdin."); + Logs->Log("STARTUP", LOG_DEFAULT, "Failed to dup /dev/null to stdin."); if (dup2(fd, STDOUT_FILENO) < 0) - Logs->Log("STARTUP", DEFAULT, "Failed to dup /dev/null to stdout."); + Logs->Log("STARTUP", LOG_DEFAULT, "Failed to dup /dev/null to stdout."); if (dup2(fd, STDERR_FILENO) < 0) - Logs->Log("STARTUP", DEFAULT, "Failed to dup /dev/null to stderr."); + Logs->Log("STARTUP", LOG_DEFAULT, "Failed to dup /dev/null to stderr."); close(fd); } else { - Logs->Log("STARTUP", DEFAULT,"Keeping pseudo-tty open as we are running in the foreground."); + Logs->Log("STARTUP", LOG_DEFAULT, "Keeping pseudo-tty open as we are running in the foreground."); } #else /* Set win32 service as running, if we are running as a service */ @@ -661,7 +542,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : QueryPerformanceFrequency(&stats->QPFrequency); #endif - Logs->Log("STARTUP", DEFAULT, "Startup complete as '%s'[%s], %d max open sockets", Config->ServerName.c_str(),Config->GetSID().c_str(), SE->GetMaxFds()); + Logs->Log("STARTUP", LOG_DEFAULT, "Startup complete as '%s'[%s], %d max open sockets", Config->ServerName.c_str(),Config->GetSID().c_str(), SE->GetMaxFds()); #ifndef _WIN32 std::string SetUser = Config->ConfValue("security")->getString("runasuser"); @@ -675,7 +556,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : if (ret == -1) { - this->Logs->Log("SETGROUPS", DEFAULT, "setgroups() failed (wtf?): %s", strerror(errno)); + this->Logs->Log("STARTUP", LOG_DEFAULT, "setgroups() failed (wtf?): %s", strerror(errno)); this->QuickExit(0); } @@ -687,7 +568,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : if (!g) { - this->Logs->Log("SETGUID", DEFAULT, "getgrnam() failed (bad user?): %s", strerror(errno)); + this->Logs->Log("STARTUP", LOG_DEFAULT, "getgrnam() failed (bad user?): %s", strerror(errno)); this->QuickExit(0); } @@ -695,7 +576,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : if (ret == -1) { - this->Logs->Log("SETGUID", DEFAULT, "setgid() failed (bad user?): %s", strerror(errno)); + this->Logs->Log("STARTUP", LOG_DEFAULT, "setgid() failed (bad user?): %s", strerror(errno)); this->QuickExit(0); } } @@ -710,7 +591,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : if (!u) { - this->Logs->Log("SETGUID", DEFAULT, "getpwnam() failed (bad user?): %s", strerror(errno)); + this->Logs->Log("STARTUP", LOG_DEFAULT, "getpwnam() failed (bad user?): %s", strerror(errno)); this->QuickExit(0); } @@ -718,7 +599,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : if (ret == -1) { - this->Logs->Log("SETGUID", DEFAULT, "setuid() failed (bad user?): %s", strerror(errno)); + this->Logs->Log("STARTUP", LOG_DEFAULT, "setuid() failed (bad user?): %s", strerror(errno)); this->QuickExit(0); } } @@ -747,14 +628,14 @@ void InspIRCd::UpdateTime() #endif } -int InspIRCd::Run() +void InspIRCd::Run() { /* See if we're supposed to be running the test suite rather than entering the mainloop */ if (Config->cmdline.TestSuite) { TestSuite* ts = new TestSuite; delete ts; - Exit(0); + return; } UpdateTime(); @@ -770,7 +651,7 @@ int InspIRCd::Run() if (this->ConfigThread && this->ConfigThread->IsDone()) { /* Rehash has completed */ - this->Logs->Log("CONFIG",DEBUG,"Detected ConfigThread exiting, tidying up..."); + this->Logs->Log("CONFIG", LOG_DEBUG, "Detected ConfigThread exiting, tidying up..."); this->ConfigThread->Finish(); @@ -814,21 +695,21 @@ int InspIRCd::Run() { SNO->WriteToSnoMask('d', "\002EH?!\002 -- Time is jumping FORWARDS! Clock skipped %lu secs.", (unsigned long)TIME.tv_sec - OLDTIME); } -
+ OLDTIME = TIME.tv_sec; if ((TIME.tv_sec % 3600) == 0) { - this->RehashUsersAndChans(); - FOREACH_MOD(I_OnGarbageCollect, OnGarbageCollect()); + Users->GarbageCollect(); + FOREACH_MOD(OnGarbageCollect, ()); } Timers->TickTimers(TIME.tv_sec); - this->DoBackgroundUserStuff(); + Users->DoBackgroundUserStuff(); if ((TIME.tv_sec % 5) == 0) { - FOREACH_MOD(I_OnBackgroundTimer,OnBackgroundTimer(TIME.tv_sec)); + FOREACH_MOD(OnBackgroundTimer, (TIME.tv_sec)); SNO->FlushSnotices(); } } @@ -847,36 +728,19 @@ int InspIRCd::Run() GlobalCulls.Apply(); AtomicActions.Run(); - if (this->s_signal) + if (s_signal) { this->SignalHandler(s_signal); - this->s_signal = 0; + s_signal = 0; } } - - return 0; } -/**********************************************************************************/ - -/** - * An ircd in five lines! bwahahaha. ahahahahaha. ahahah *cough*. - */ - -/* this returns true when all modules are satisfied that the user should be allowed onto the irc server - * (until this returns true, a user will block in the waiting state, waiting to connect up to the - * registration timeout maximum seconds) - */ -bool InspIRCd::AllModulesReportReady(LocalUser* user) -{ - ModResult res; - FIRST_MOD_RESULT(OnCheckReady, res, (user)); - return (res == MOD_RES_PASSTHRU); -} +sig_atomic_t InspIRCd::s_signal = 0; void InspIRCd::SetSignal(int signal) { - *mysig = signal; + s_signal = signal; } /* On posix systems, the flow of the program starts right here, with @@ -888,7 +752,6 @@ void InspIRCd::SetSignal(int signal) ENTRYPOINT { new InspIRCd(argc, argv); - mysig = &ServerInstance->s_signal; ServerInstance->Run(); delete ServerInstance; return 0; diff --git a/src/inspsocket.cpp b/src/inspsocket.cpp index 356904f74..d7a25785d 100644 --- a/src/inspsocket.cpp +++ b/src/inspsocket.cpp @@ -26,6 +26,7 @@ #include "socket.h" #include "inspstring.h" #include "socketengine.h" +#include "iohook.h" #ifndef DISABLE_WRITEV #include <sys/uio.h> @@ -66,7 +67,7 @@ BufferedSocketError BufferedSocket::BeginConnect(const std::string &ipaddr, int irc::sockets::sockaddrs addr, bind; if (!irc::sockets::aptosa(ipaddr, aport, addr)) { - ServerInstance->Logs->Log("SOCKET", DEBUG, "BUG: Hostname passed to BufferedSocket, rather than an IP address!"); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "BUG: Hostname passed to BufferedSocket, rather than an IP address!"); return I_ERR_CONNECT; } @@ -98,7 +99,7 @@ BufferedSocketError BufferedSocket::BeginConnect(const irc::sockets::sockaddrs& ServerInstance->SE->NonBlocking(fd); - if (ServerInstance->SE->Connect(this, &dest.sa, sa_size(dest)) == -1) + if (ServerInstance->SE->Connect(this, &dest.sa, dest.sa_size()) == -1) { if (errno != EINPROGRESS) return I_ERR_CONNECT; @@ -112,7 +113,7 @@ BufferedSocketError BufferedSocket::BeginConnect(const irc::sockets::sockaddrs& this->Timeout = new SocketTimeout(this->GetFd(), this, timeout, ServerInstance->Time()); ServerInstance->Timers->AddTimer(this->Timeout); - ServerInstance->Logs->Log("SOCKET", DEBUG,"BufferedSocket::DoConnect success"); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "BufferedSocket::DoConnect success"); return I_ERR_NONE; } @@ -122,18 +123,18 @@ void StreamSocket::Close() { // final chance, dump as much of the sendq as we can DoWrite(); - if (IOHook) + if (GetIOHook()) { try { - IOHook->OnStreamSocketClose(this); + GetIOHook()->OnStreamSocketClose(this); } catch (CoreException& modexcept) { - ServerInstance->Logs->Log("SOCKET", DEFAULT,"%s threw an exception: %s", + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); } - IOHook = NULL; + DelIOHook(); } ServerInstance->SE->Shutdown(this, 2); ServerInstance->SE->DelFd(this); @@ -161,16 +162,16 @@ bool StreamSocket::GetNextLine(std::string& line, char delim) void StreamSocket::DoRead() { - if (IOHook) + if (GetIOHook()) { int rv = -1; try { - rv = IOHook->OnStreamSocketRead(this, recvq); + rv = GetIOHook()->OnStreamSocketRead(this, recvq); } catch (CoreException& modexcept) { - ServerInstance->Logs->Log("SOCKET", DEFAULT, "%s threw an exception: %s", + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); return; } @@ -225,12 +226,12 @@ void StreamSocket::DoWrite() return; if (!error.empty() || fd < 0 || fd == INT_MAX) { - ServerInstance->Logs->Log("SOCKET", DEBUG, "DoWrite on errored or closed socket"); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DoWrite on errored or closed socket"); return; } #ifndef DISABLE_WRITEV - if (IOHook) + if (GetIOHook()) #endif { int rv = -1; @@ -258,9 +259,9 @@ void StreamSocket::DoWrite() } std::string& front = sendq.front(); int itemlen = front.length(); - if (IOHook) + if (GetIOHook()) { - rv = IOHook->OnStreamSocketWrite(this, front); + rv = GetIOHook()->OnStreamSocketWrite(this, front); if (rv > 0) { // consumed the entire string, and is ready for more @@ -319,7 +320,7 @@ void StreamSocket::DoWrite() } catch (CoreException& modexcept) { - ServerInstance->Logs->Log("SOCKET", DEBUG,"%s threw an exception: %s", + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); } } @@ -421,7 +422,7 @@ void StreamSocket::WriteData(const std::string &data) { if (fd < 0) { - ServerInstance->Logs->Log("SOCKET", DEBUG, "Attempt to write data to dead socket: %s", + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Attempt to write data to dead socket: %s", data.c_str()); return; } @@ -433,12 +434,12 @@ void StreamSocket::WriteData(const std::string &data) ServerInstance->SE->ChangeEventMask(this, FD_ADD_TRIAL_WRITE); } -void SocketTimeout::Tick(time_t) +bool SocketTimeout::Tick(time_t) { - ServerInstance->Logs->Log("SOCKET", DEBUG,"SocketTimeout::Tick"); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "SocketTimeout::Tick"); if (ServerInstance->SE->GetRef(this->sfd) != this->sock) - return; + return false; if (this->sock->state == I_CONNECTING) { @@ -454,6 +455,7 @@ void SocketTimeout::Tick(time_t) } this->sock->Timeout = NULL; + return false; } void BufferedSocket::OnConnected() { } @@ -478,8 +480,8 @@ BufferedSocket::~BufferedSocket() this->Close(); if (Timeout) { - ServerInstance->Timers->DelTimer(Timeout); - Timeout = NULL; + // The timer is removed from the TimerManager in Timer::~Timer() + delete Timeout; } } @@ -530,13 +532,13 @@ void StreamSocket::HandleEvent(EventType et, int errornum) } catch (CoreException& ex) { - ServerInstance->Logs->Log("SOCKET", DEFAULT, "Caught exception in socket processing on FD %d - '%s'", + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "Caught exception in socket processing on FD %d - '%s'", fd, ex.GetReason()); SetError(ex.GetReason()); } if (!error.empty()) { - ServerInstance->Logs->Log("SOCKET", DEBUG, "Error on FD %d - '%s'", fd, error.c_str()); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Error on FD %d - '%s'", fd, error.c_str()); OnError(errcode); } } diff --git a/src/inspstring.cpp b/src/inspstring.cpp index 534b7ce00..7fa4762c5 100644 --- a/src/inspstring.cpp +++ b/src/inspstring.cpp @@ -21,140 +21,18 @@ #include "inspircd.h" -/* - * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef HAS_STRLCPY -CoreExport size_t strlcat(char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz, dlen; - - while (n-- != 0 && *d != '\0') - d++; - - dlen = d - dst; - n = siz - dlen; - - if (n == 0) - return(dlen + strlen(s)); - - while (*s != '\0') - { - if (n != 1) - { - *d++ = *s; - n--; - } - - s++; - } - - *d = '\0'; - return(dlen + (s - src)); /* count does not include NUL */ -} - -CoreExport size_t strlcpy(char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0 && --n != 0) - { - do - { - if ((*d++ = *s++) == 0) - break; - } while (--n != 0); - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) - { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++); - } - - return(s - src - 1); /* count does not include NUL */ -} -#endif - -CoreExport int charlcat(char* x,char y,int z) -{ - char* x__n = x; - int v = 0; - - while(*x__n++) - v++; - - if (v < z - 1) - { - *--x__n = y; - *++x__n = 0; - } - - return v; -} - -CoreExport bool charremove(char* mp, char remove) -{ - char* mptr = mp; - bool shift_down = false; - - while (*mptr) - { - if (*mptr == remove) - shift_down = true; - - if (shift_down) - *mptr = *(mptr+1); - - mptr++; - } - - return shift_down; -} - static const char hextable[] = "0123456789abcdef"; -std::string BinToHex(const std::string& data) +std::string BinToHex(const void* raw, size_t l) { - int l = data.length(); + const char* data = static_cast<const char*>(raw); std::string rv; rv.reserve(l * 2); - for(int i=0; i < l; i++) + for (size_t i = 0; i < l; i++) { unsigned char c = data[i]; - rv.append(1, hextable[c >> 4]); - rv.append(1, hextable[c & 0xF]); + rv.push_back(hextable[c >> 4]); + rv.push_back(hextable[c & 0xF]); } return rv; } diff --git a/src/listensocket.cpp b/src/listensocket.cpp index ae11c3b48..ca518c59e 100644 --- a/src/listensocket.cpp +++ b/src/listensocket.cpp @@ -22,6 +22,10 @@ #include "socket.h" #include "socketengine.h" +#ifndef _WIN32 +#include <netinet/tcp.h> +#endif + ListenSocket::ListenSocket(ConfigTag* tag, const irc::sockets::sockaddrs& bind_to) : bind_tag(tag) { @@ -56,6 +60,19 @@ ListenSocket::ListenSocket(ConfigTag* tag, const irc::sockets::sockaddrs& bind_t if (rv >= 0) rv = ServerInstance->SE->Listen(this->fd, ServerInstance->Config->MaxConn); + int timeout = tag->getInt("defer", 0); + if (timeout && !rv) + { +#if defined TCP_DEFER_ACCEPT + setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, sizeof(timeout)); +#elif defined SO_ACCEPTFILTER + struct accept_filter_arg afa; + memset(&afa, 0, sizeof(afa)); + strcpy(afa.af_name, "dataready"); + setsockopt(fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)); +#endif + } + if (rv < 0) { int errstore = errno; @@ -76,10 +93,10 @@ ListenSocket::~ListenSocket() if (this->GetFd() > -1) { ServerInstance->SE->DelFd(this); - ServerInstance->Logs->Log("SOCKET", DEBUG,"Shut down listener on fd %d", this->fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Shut down listener on fd %d", this->fd); ServerInstance->SE->Shutdown(this, 2); if (ServerInstance->SE->Close(this) != 0) - ServerInstance->Logs->Log("SOCKET", DEBUG,"Failed to cancel listener: %s", strerror(errno)); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Failed to cancel listener: %s", strerror(errno)); this->fd = -1; } } @@ -93,7 +110,7 @@ void ListenSocket::AcceptInternal() socklen_t length = sizeof(client); int incomingSockfd = ServerInstance->SE->Accept(this, &client.sa, &length); - ServerInstance->Logs->Log("SOCKET",DEBUG,"HandleEvent for Listensocket %s nfd=%d", bind_desc.c_str(), incomingSockfd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "HandleEvent for Listensocket %s nfd=%d", bind_desc.c_str(), incomingSockfd); if (incomingSockfd < 0) { ServerInstance->stats->statsRefused++; @@ -103,7 +120,7 @@ void ListenSocket::AcceptInternal() socklen_t sz = sizeof(server); if (getsockname(incomingSockfd, &server.sa, &sz)) { - ServerInstance->Logs->Log("SOCKET", DEBUG, "Can't get peername: %s", strerror(errno)); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Can't get peername: %s", strerror(errno)); irc::sockets::aptosa(bind_addr, bind_port, server); } @@ -119,7 +136,7 @@ void ListenSocket::AcceptInternal() */ if (incomingSockfd >= ServerInstance->SE->GetMaxFds()) { - ServerInstance->Logs->Log("SOCKET", DEBUG, "Server is full"); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Server is full"); ServerInstance->SE->Shutdown(incomingSockfd, 2); ServerInstance->SE->Close(incomingSockfd); ServerInstance->stats->statsRefused++; @@ -176,7 +193,7 @@ void ListenSocket::AcceptInternal() else { ServerInstance->stats->statsRefused++; - ServerInstance->Logs->Log("SOCKET",DEFAULT,"Refusing connection on %s - %s", + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "Refusing connection on %s - %s", bind_desc.c_str(), res == MOD_RES_DENY ? "Connection refused by module" : "Module for this port not found"); ServerInstance->SE->Close(incomingSockfd); } @@ -187,10 +204,10 @@ void ListenSocket::HandleEvent(EventType e, int err) switch (e) { case EVENT_ERROR: - ServerInstance->Logs->Log("SOCKET",DEFAULT,"ListenSocket::HandleEvent() received a socket engine error event! well shit! '%s'", strerror(err)); + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ListenSocket::HandleEvent() received a socket engine error event! well shit! '%s'", strerror(err)); break; case EVENT_WRITE: - ServerInstance->Logs->Log("SOCKET",DEBUG,"*** BUG *** ListenSocket::HandleEvent() got a WRITE event!!!"); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "*** BUG *** ListenSocket::HandleEvent() got a WRITE event!!!"); break; case EVENT_READ: this->AcceptInternal(); diff --git a/src/listmode.cpp b/src/listmode.cpp new file mode 100644 index 000000000..fb76beab2 --- /dev/null +++ b/src/listmode.cpp @@ -0,0 +1,251 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "inspircd.h" +#include "listmode.h" + +ListModeBase::ListModeBase(Module* Creator, const std::string& Name, char modechar, const std::string &eolstr, unsigned int lnum, unsigned int eolnum, bool autotidy, const std::string &ctag) + : ModeHandler(Creator, Name, modechar, PARAM_ALWAYS, MODETYPE_CHANNEL), + listnumeric(lnum), endoflistnumeric(eolnum), endofliststring(eolstr), tidy(autotidy), + configtag(ctag), extItem("listbase_mode_" + name + "_list", Creator) +{ + list = true; +} + +void ListModeBase::DisplayList(User* user, Channel* channel) +{ + ChanData* cd = extItem.get(channel); + if (cd) + { + for (ModeList::reverse_iterator it = cd->list.rbegin(); it != cd->list.rend(); ++it) + { + user->WriteNumeric(listnumeric, "%s %s %s %s %lu", user->nick.c_str(), channel->name.c_str(), it->mask.c_str(), (!it->setter.empty() ? it->setter.c_str() : ServerInstance->Config->ServerName.c_str()), (unsigned long) it->time); + } + } + user->WriteNumeric(endoflistnumeric, "%s %s :%s", user->nick.c_str(), channel->name.c_str(), endofliststring.c_str()); +} + +void ListModeBase::DisplayEmptyList(User* user, Channel* channel) +{ + user->WriteNumeric(endoflistnumeric, "%s %s :%s", user->nick.c_str(), channel->name.c_str(), endofliststring.c_str()); +} + +void ListModeBase::RemoveMode(Channel* channel, irc::modestacker& stack) +{ + ChanData* cd = extItem.get(channel); + if (cd) + { + for (ModeList::iterator it = cd->list.begin(); it != cd->list.end(); it++) + { + stack.Push(this->GetModeChar(), it->mask); + } + } +} + +void ListModeBase::DoRehash() +{ + ConfigTagList tags = ServerInstance->Config->ConfTags(configtag); + + limitlist oldlimits = chanlimits; + chanlimits.clear(); + + for (ConfigIter i = tags.first; i != tags.second; i++) + { + // For each <banlist> tag + ConfigTag* c = i->second; + ListLimit limit(c->getString("chan"), c->getInt("limit")); + + if (limit.mask.size() && limit.limit > 0) + chanlimits.push_back(limit); + } + + if (chanlimits.empty()) + chanlimits.push_back(ListLimit("*", 64)); + + // Most of the time our settings are unchanged, so we can avoid iterating the chanlist + if (oldlimits == chanlimits) + return; + + for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); ++i) + { + ChanData* cd = extItem.get(i->second); + if (cd) + cd->maxitems = -1; + } +} + +void ListModeBase::DoImplements(Module* m) +{ + ServerInstance->Modules->AddService(extItem); + this->DoRehash(); +} + +unsigned int ListModeBase::FindLimit(const std::string& channame) +{ + for (limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); ++it) + { + if (InspIRCd::Match(channame, it->mask)) + { + // We have a pattern matching the channel + return it->limit; + } + } + return 64; +} + +unsigned int ListModeBase::GetLimitInternal(const std::string& channame, ChanData* cd) +{ + if (cd->maxitems < 0) + cd->maxitems = FindLimit(channame); + return cd->maxitems; +} + +unsigned int ListModeBase::GetLimit(Channel* channel) +{ + ChanData* cd = extItem.get(channel); + if (!cd) // just find the limit + return FindLimit(channel->name); + + return GetLimitInternal(channel->name, cd); +} + +ModeAction ListModeBase::OnModeChange(User* source, User*, Channel* channel, std::string ¶meter, bool adding) +{ + // Try and grab the list + ChanData* cd = extItem.get(channel); + + if (adding) + { + if (tidy) + ModeParser::CleanMask(parameter); + + if (parameter.length() > 250) + return MODEACTION_DENY; + + // If there was no list + if (!cd) + { + // Make one + cd = new ChanData; + extItem.set(channel, cd); + } + + // Check if the item already exists in the list + for (ModeList::iterator it = cd->list.begin(); it != cd->list.end(); it++) + { + if (parameter == it->mask) + { + /* Give a subclass a chance to error about this */ + TellAlreadyOnList(source, channel, parameter); + + // it does, deny the change + return MODEACTION_DENY; + } + } + + if ((IS_LOCAL(source)) && (cd->list.size() >= GetLimitInternal(channel->name, cd))) + { + /* List is full, give subclass a chance to send a custom message */ + TellListTooLong(source, channel, parameter); + parameter.clear(); + return MODEACTION_DENY; + } + + /* Ok, it *could* be allowed, now give someone subclassing us + * a chance to validate the parameter. + * The param is passed by reference, so they can both modify it + * and tell us if we allow it or not. + * + * eg, the subclass could: + * 1) allow + * 2) 'fix' parameter and then allow + * 3) deny + */ + if (ValidateParam(source, channel, parameter)) + { + // And now add the mask onto the list... + cd->list.push_back(ListItem(parameter, source->nick, ServerInstance->Time())); + return MODEACTION_ALLOW; + } + else + { + /* If they deny it they have the job of giving an error message */ + return MODEACTION_DENY; + } + } + else + { + // We're taking the mode off + if (cd) + { + for (ModeList::iterator it = cd->list.begin(); it != cd->list.end(); ++it) + { + if (parameter == it->mask) + { + cd->list.erase(it); + return MODEACTION_ALLOW; + } + } + } + + /* Tried to remove something that wasn't set */ + TellNotSet(source, channel, parameter); + parameter.clear(); + return MODEACTION_DENY; + } +} + +void ListModeBase::DoSyncChannel(Channel* chan, Module* proto, void* opaque) +{ + ChanData* cd = extItem.get(chan); + if (!cd) + return; + + irc::modestacker modestack(true); + std::vector<std::string> stackresult; + std::vector<TranslateType> types; + types.push_back(TR_TEXT); + + for (ModeList::iterator it = cd->list.begin(); it != cd->list.end(); it++) + modestack.Push(mode, it->mask); + + while (modestack.GetStackedLine(stackresult)) + { + types.assign(stackresult.size(), this->GetTranslateType()); + proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, stackresult, types); + stackresult.clear(); + } +} + +bool ListModeBase::ValidateParam(User*, Channel*, std::string&) +{ + return true; +} + +void ListModeBase::TellListTooLong(User* source, Channel* channel, std::string& parameter) +{ + source->WriteNumeric(478, "%s %s %s :Channel ban list is full", source->nick.c_str(), channel->name.c_str(), parameter.c_str()); +} + +void ListModeBase::TellAlreadyOnList(User*, Channel*, std::string&) +{ +} + +void ListModeBase::TellNotSet(User*, Channel*, std::string&) +{ +} diff --git a/src/logger.cpp b/src/logger.cpp index 89b2be019..61ac517c7 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -21,7 +21,6 @@ #include "inspircd.h" - #include "filelogger.h" /* @@ -51,9 +50,13 @@ * */ +const char LogStream::LogHeader[] = + "Log started for " VERSION " (" REVISION ", " MODULE_INIT_STR ")" + " - compiled on " SYSTEM; + LogManager::LogManager() + : Logging(false) { - Logging = false; } LogManager::~LogManager() @@ -82,41 +85,41 @@ void LogManager::OpenFileLogs() } std::string type = tag->getString("type"); std::string level = tag->getString("level"); - int loglevel = DEFAULT; + LogLevel loglevel = LOG_DEFAULT; if (level == "rawio") { - loglevel = RAWIO; + loglevel = LOG_RAWIO; ServerInstance->Config->RawLog = true; } else if (level == "debug") { - loglevel = DEBUG; + loglevel = LOG_DEBUG; } else if (level == "verbose") { - loglevel = VERBOSE; + loglevel = LOG_VERBOSE; } else if (level == "default") { - loglevel = DEFAULT; + loglevel = LOG_DEFAULT; } else if (level == "sparse") { - loglevel = SPARSE; + loglevel = LOG_SPARSE; } else if (level == "none") { - loglevel = NONE; + loglevel = LOG_NONE; } FileWriter* fw; - std::string target = tag->getString("target"); + std::string target = ServerInstance->Config->Paths.PrependLog(tag->getString("target")); std::map<std::string, FileWriter*>::iterator fwi = logmap.find(target); if (fwi == logmap.end()) { - char realtarget[MAXBUF]; + char realtarget[256]; time_t time = ServerInstance->Time(); struct tm *mytime = gmtime(&time); - strftime(realtarget, MAXBUF, target.c_str(), mytime); + strftime(realtarget, sizeof(realtarget), target.c_str(), mytime); FILE* f = fopen(realtarget, "a"); fw = new FileWriter(f); logmap.insert(std::make_pair(target, fw)); @@ -126,7 +129,7 @@ void LogManager::OpenFileLogs() fw = fwi->second; } FileLogStream* fls = new FileLogStream(loglevel, fw); - fls->OnLog(SPARSE, "HEADER", InspIRCd::LogHeader); + fls->OnLog(LOG_SPARSE, "HEADER", LogStream::LogHeader); AddLogTypes(type, fls, true); } } @@ -135,13 +138,16 @@ void LogManager::CloseLogs() { if (ServerInstance->Config && ServerInstance->Config->cmdline.forcedebug) return; - std::map<std::string, std::vector<LogStream*> >().swap(LogStreams); /* Clear it */ - std::map<LogStream*, std::vector<std::string> >().swap(GlobalLogStreams); /* Clear it */ + + LogStreams.clear(); + GlobalLogStreams.clear(); + for (std::map<LogStream*, int>::iterator i = AllLogStreams.begin(); i != AllLogStreams.end(); ++i) { delete i->first; } - std::map<LogStream*, int>().swap(AllLogStreams); /* And clear it */ + + AllLogStreams.clear(); } void LogManager::AddLogTypes(const std::string &types, LogStream* l, bool autoclose) @@ -187,36 +193,13 @@ void LogManager::AddLogTypes(const std::string &types, LogStream* l, bool autocl bool LogManager::AddLogType(const std::string &type, LogStream *l, bool autoclose) { - std::map<std::string, std::vector<LogStream *> >::iterator i = LogStreams.find(type); - - if (i != LogStreams.end()) - { - i->second.push_back(l); - } - else - { - std::vector<LogStream *> v; - v.push_back(l); - LogStreams[type] = v; - } + LogStreams[type].push_back(l); if (type == "*") - { GlobalLogStreams.insert(std::make_pair(l, std::vector<std::string>())); - } if (autoclose) - { - std::map<LogStream*, int>::iterator ai = AllLogStreams.find(l); - if (ai == AllLogStreams.end()) - { - AllLogStreams.insert(std::make_pair(l, 1)); - } - else - { - ++ai->second; - } - } + AllLogStreams[l]++; return true; } @@ -228,21 +211,18 @@ void LogManager::DelLogStream(LogStream* l) std::vector<LogStream*>::iterator it; while ((it = std::find(i->second.begin(), i->second.end(), l)) != i->second.end()) { - if (it == i->second.end()) - continue; i->second.erase(it); } } - std::map<LogStream *, std::vector<std::string> >::iterator gi = GlobalLogStreams.find(l); - if (gi != GlobalLogStreams.end()) - { - GlobalLogStreams.erase(gi); - } + + GlobalLogStreams.erase(l); + std::map<LogStream*, int>::iterator ai = AllLogStreams.begin(); if (ai == AllLogStreams.end()) { return; /* Done. */ } + delete ai->first; AllLogStreams.erase(ai); } @@ -252,8 +232,7 @@ bool LogManager::DelLogType(const std::string &type, LogStream *l) std::map<std::string, std::vector<LogStream *> >::iterator i = LogStreams.find(type); if (type == "*") { - std::map<LogStream *, std::vector<std::string> >::iterator gi = GlobalLogStreams.find(l); - if (gi != GlobalLogStreams.end()) GlobalLogStreams.erase(gi); + GlobalLogStreams.erase(l); } if (i != LogStreams.end()) @@ -293,24 +272,17 @@ bool LogManager::DelLogType(const std::string &type, LogStream *l) return true; } -void LogManager::Log(const std::string &type, int loglevel, const char *fmt, ...) +void LogManager::Log(const std::string &type, LogLevel loglevel, const char *fmt, ...) { if (Logging) - { return; - } - - va_list a; - static char buf[65536]; - - va_start(a, fmt); - vsnprintf(buf, 65536, fmt, a); - va_end(a); - this->Log(type, loglevel, std::string(buf)); + std::string buf; + VAFORMAT(buf, fmt, fmt); + this->Log(type, loglevel, buf); } -void LogManager::Log(const std::string &type, int loglevel, const std::string &msg) +void LogManager::Log(const std::string &type, LogLevel loglevel, const std::string &msg) { if (Logging) { @@ -354,8 +326,8 @@ void FileWriter::WriteLogLine(const std::string &line) // XXX: For now, just return. Don't throw an exception. It'd be nice to find out if this is happening, but I'm terrified of breaking so close to final release. -- w00t // throw CoreException("FileWriter::WriteLogLine called with a closed logfile"); - fprintf(log,"%s",line.c_str()); - if (writeops++ % 20) + fputs(line.c_str(), log); + if (++writeops % 20 == 0) { fflush(log); } diff --git a/src/mode.cpp b/src/mode.cpp index e2b0c2f68..15f5c0d60 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -24,35 +24,12 @@ #include "inspircd.h" - -/* +s (secret) */ -/* +p (private) */ -/* +m (moderated) */ -/* +t (only (half) ops can change topic) */ -/* +n (no external messages) */ -/* +i (invite only) */ -/* +w (see wallops) */ -/* +i (invisible) */ -#include "modes/simplemodes.h" -/* +b (bans) */ -#include "modes/cmode_b.h" -/* +k (keyed channel) */ -#include "modes/cmode_k.h" -/* +l (channel user limit) */ -#include "modes/cmode_l.h" -/* +o (channel op) */ -#include "modes/cmode_o.h" -/* +v (channel voice) */ -#include "modes/cmode_v.h" -/* +o (operator) */ -#include "modes/umode_o.h" -/* +s (server notice masks) */ -#include "modes/umode_s.h" +#include "builtinmodes.h" ModeHandler::ModeHandler(Module* Creator, const std::string& Name, char modeletter, ParamSpec Params, ModeType type) : ServiceProvider(Creator, Name, SERVICE_MODE), m_paramtype(TR_TEXT), parameters_taken(Params), mode(modeletter), prefix(0), oper(false), - list(false), m_type(type), levelrequired(HALFOP_VALUE) + list(false), m_type(type), levelrequired(HALFOP_VALUE), prefixrank(0) { } @@ -67,16 +44,6 @@ ModeHandler::~ModeHandler() { } -bool ModeHandler::IsListMode() -{ - return list; -} - -unsigned int ModeHandler::GetPrefixRank() -{ - return 0; -} - int ModeHandler::GetNumParams(bool adding) { switch (parameters_taken) @@ -127,7 +94,7 @@ ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel { /* We're either trying to add a mode we already have or remove a mode we don't have, deny. */ - if (dest->IsModeSet(this->GetModeChar()) == adding) + if (dest->IsModeSet(this) == adding) return MODEACTION_DENY; /* adding will be either true or false, depending on if we @@ -136,7 +103,7 @@ ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel aren't removing a mode we don't have, we don't have to do any other checks here to see if it's true or false, just add or remove the mode */ - dest->SetMode(this->GetModeChar(), adding); + dest->SetMode(this, adding); return MODEACTION_ALLOW; } @@ -146,7 +113,7 @@ ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Chan { /* We're either trying to add a mode we already have or remove a mode we don't have, deny. */ - if (channel->IsModeSet(this->GetModeChar()) == adding) + if (channel->IsModeSet(this) == adding) return MODEACTION_DENY; /* adding will be either true or false, depending on if we @@ -155,7 +122,7 @@ ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Chan aren't removing a mode we don't have, we don't have to do any other checks here to see if it's true or false, just add or remove the mode */ - channel->SetMode(this->GetModeChar(), adding); + channel->SetMode(this, adding); return MODEACTION_ALLOW; } @@ -167,10 +134,6 @@ ModeAction ParamChannelModeHandler::OnModeChange(User* source, User* dest, Chann std::string now = channel->GetModeParameter(this); if (parameter == now) return MODEACTION_DENY; - if (adding) - channel->SetModeParam(this, parameter); - else - channel->SetModeParam(this, ""); return MODEACTION_ALLOW; } @@ -179,8 +142,8 @@ bool ParamChannelModeHandler::ParamValidate(std::string& parameter) return true; } -ModeWatcher::ModeWatcher(Module* Creator, char modeletter, ModeType type) - : mode(modeletter), m_type(type), creator(Creator) +ModeWatcher::ModeWatcher(Module* Creator, const std::string& modename, ModeType type) + : mode(modename), m_type(type), creator(Creator) { } @@ -188,39 +151,18 @@ ModeWatcher::~ModeWatcher() { } -char ModeWatcher::GetModeChar() -{ - return mode; -} - ModeType ModeWatcher::GetModeType() { return m_type; } -bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType) +bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool) { return true; } -void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType) -{ -} - -User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int) +void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool) { - User *d; - if ((!user) || (!dest) || (!chan) || (!*dest)) - { - return NULL; - } - d = ServerInstance->FindNick(dest); - if (!d) - { - user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest); - return NULL; - } - return d; } void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text) @@ -238,8 +180,11 @@ void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targ { /* Display user's current mode string */ user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes()); - if (IS_OPER(targetuser)) - user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks()); + if ((targetuser->IsOper())) + { + ModeHandler* snomask = FindMode('s', MODETYPE_USER); + user->WriteNumeric(RPL_SNOMASKIS, "%s %s :Server notice mask", targetuser->nick.c_str(), snomask->GetUserParameter(user).c_str()); + } return; } else @@ -254,7 +199,6 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool std::string ¶meter, bool SkipACL) { ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER; - unsigned char mask = chan ? MASK_CHANNEL : MASK_USER; ModeHandler *mh = FindMode(modechar, type); int pcnt = mh->GetNumParams(adding); @@ -308,18 +252,23 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool } } - unsigned char handler_id = (modechar - 'A') | mask; - - for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++) + // Ask mode watchers whether this mode change is OK + std::pair<ModeWatchIter, ModeWatchIter> itpair = modewatchermap.equal_range(mh->name); + for (ModeWatchIter i = itpair.first; i != itpair.second; ++i) { - if ((*watchers)->BeforeMode(user, targetuser, chan, parameter, adding, type) == false) - return MODEACTION_DENY; - /* A module whacked the parameter completely, and there was one. abort. */ - if (pcnt && parameter.empty()) - return MODEACTION_DENY; + ModeWatcher* mw = i->second; + if (mw->GetModeType() == type) + { + if (!mw->BeforeMode(user, targetuser, chan, parameter, adding)) + return MODEACTION_DENY; + + // A module whacked the parameter completely, and there was one. Abort. + if (pcnt && parameter.empty()) + return MODEACTION_DENY; + } } - if (IS_LOCAL(user) && !IS_OPER(user)) + if (IS_LOCAL(user) && !user->IsOper()) { char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes; if (disabled[modechar - 'A']) @@ -333,10 +282,10 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type)) { /* It's an oper only mode, and they don't have access to it. */ - if (IS_OPER(user)) + if (user->IsOper()) { user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c", - user->nick.c_str(), user->oper->NameStr(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar); + user->nick.c_str(), user->oper->name.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar); } else { @@ -370,13 +319,21 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool if (ma != MODEACTION_ALLOW) return ma; - for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++) - (*watchers)->AfterMode(user, targetuser, chan, parameter, adding, type); + if ((!mh->IsListMode()) && (mh->GetNumParams(true)) && (chan)) + chan->SetModeParam(mh, (adding ? parameter : "")); + + itpair = modewatchermap.equal_range(mh->name); + for (ModeWatchIter i = itpair.first; i != itpair.second; ++i) + { + ModeWatcher* mw = i->second; + if (mw->GetModeType() == type) + mw->AfterMode(user, targetuser, chan, parameter, adding); + } return MODEACTION_ALLOW; } -void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool merge) +void ModeParser::Process(const std::vector<std::string>& parameters, User* user, ModeProcessFlag flags) { std::string target = parameters[0]; Channel* targetchannel = ServerInstance->FindChan(target); @@ -456,9 +413,9 @@ void ModeParser::Process(const std::vector<std::string>& parameters, User *user, /* Make sure the user isn't trying to slip in an invalid parameter */ if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos)) continue; - if (merge && targetchannel && targetchannel->IsModeSet(modechar) && !mh->IsListMode()) + if ((flags & MODE_MERGE) && targetchannel && targetchannel->IsModeSet(mh) && !mh->IsListMode()) { - std::string ours = targetchannel->GetModeParameter(modechar); + std::string ours = targetchannel->GetModeParameter(mh); if (!mh->ResolveModeConflict(parameter, ours, targetchannel)) /* we won the mode merge, don't apply this mode */ continue; @@ -510,16 +467,15 @@ void ModeParser::Process(const std::vector<std::string>& parameters, User *user, LastParse.append(output_mode); LastParse.append(output_parameters.str()); + if (!(flags & MODE_LOCALONLY)) + ServerInstance->PI->SendMode(user, targetuser, targetchannel, LastParseParams, LastParseTranslate); + if (targetchannel) - { - targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str()); - FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate)); - } + targetchannel->WriteChannel(user, "MODE " + LastParse); else - { - targetuser->WriteFrom(user, "MODE %s", LastParse.c_str()); - FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate)); - } + targetuser->WriteFrom(user, "MODE " + LastParse); + + FOREACH_MOD(OnMode, (user, targetuser, targetchannel, LastParseParams, LastParseTranslate)); } else if (targetchannel && parameters.size() == 2) { @@ -566,15 +522,24 @@ void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_s display = false; } - unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL; - - for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++) + // Ask mode watchers whether it's OK to show the list + std::pair<ModeWatchIter, ModeWatchIter> itpair = modewatchermap.equal_range(mh->name); + for (ModeWatchIter i = itpair.first; i != itpair.second; ++i) { - std::string dummyparam; + ModeWatcher* mw = i->second; + if (mw->GetModeType() == MODETYPE_CHANNEL) + { + std::string dummyparam; - if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL))) - display = false; + if (!mw->BeforeMode(user, NULL, chan, dummyparam, true)) + { + // A mode watcher doesn't want us to show the list + display = false; + break; + } + } } + if (display) mh->DisplayList(user, chan); else @@ -582,11 +547,6 @@ void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_s } } -const std::string& ModeParser::GetLastParse() -{ - return LastParse; -} - void ModeParser::CleanMask(std::string &mask) { std::string::size_type pos_of_pling = mask.find_first_of('!'); @@ -652,6 +612,7 @@ bool ModeParser::AddMode(ModeHandler* mh) return false; modehandlers[pos] = mh; + RecreateModeListFor004Numeric(); return true; } @@ -688,12 +649,23 @@ bool ModeParser::DelMode(ModeHandler* mh) // The channel may not be in the hash after RemoveMode(), see m_permchannels Channel* chan = i->second; ++i; - mh->RemoveMode(chan); + + irc::modestacker stack(false); + mh->RemoveMode(chan, stack); + + std::vector<std::string> stackresult; + stackresult.push_back(chan->name); + while (stack.GetStackedLine(stackresult)) + { + this->Process(stackresult, ServerInstance->FakeClient, MODE_LOCALONLY); + stackresult.erase(stackresult.begin() + 1, stackresult.end()); + } } break; } modehandlers[pos] = NULL; + RecreateModeListFor004Numeric(); return true; } @@ -712,52 +684,25 @@ ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt) return modehandlers[pos]; } -std::string ModeParser::UserModeList() +std::string ModeParser::CreateModeList(ModeType mt, bool needparam) { - char modestr[256]; - int pointer = 0; + std::string modestr; + unsigned char mask = ((mt == MODETYPE_CHANNEL) ? MASK_CHANNEL : MASK_USER); for (unsigned char mode = 'A'; mode <= 'z'; mode++) { - unsigned char pos = (mode-65) | MASK_USER; + unsigned char pos = (mode-65) | mask; - if (modehandlers[pos]) - modestr[pointer++] = mode; + if ((modehandlers[pos]) && ((!needparam) || (modehandlers[pos]->GetNumParams(true)))) + modestr.push_back(mode); } - modestr[pointer++] = 0; - return modestr; -} - -std::string ModeParser::ChannelModeList() -{ - char modestr[256]; - int pointer = 0; - - for (unsigned char mode = 'A'; mode <= 'z'; mode++) - { - unsigned char pos = (mode-65) | MASK_CHANNEL; - if (modehandlers[pos]) - modestr[pointer++] = mode; - } - modestr[pointer++] = 0; return modestr; } -std::string ModeParser::ParaModeList() +void ModeParser::RecreateModeListFor004Numeric() { - char modestr[256]; - int pointer = 0; - - for (unsigned char mode = 'A'; mode <= 'z'; mode++) - { - unsigned char pos = (mode-65) | MASK_CHANNEL; - - if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true))) - modestr[pointer++] = mode; - } - modestr[pointer++] = 0; - return modestr; + Cached004ModeList = CreateModeList(MODETYPE_USER) + " " + CreateModeList(MODETYPE_CHANNEL) + " " + CreateModeList(MODETYPE_CHANNEL, true); } ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter) @@ -847,91 +792,62 @@ std::string ModeParser::BuildPrefixes(bool lettersAndModes) return lettersAndModes ? "(" + mprefixes + ")" + mletters : mletters; } -bool ModeParser::AddModeWatcher(ModeWatcher* mw) +void ModeParser::AddModeWatcher(ModeWatcher* mw) { - unsigned char mask = 0; - unsigned char pos = 0; - - if (!mw) - return false; - - if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z')) - return false; - - mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL; - pos = (mw->GetModeChar()-65) | mask; - - modewatchers[pos].push_back(mw); - - return true; + modewatchermap.insert(std::make_pair(mw->GetModeName(), mw)); } bool ModeParser::DelModeWatcher(ModeWatcher* mw) { - unsigned char mask = 0; - unsigned char pos = 0; - - if (!mw) - return false; - - if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z')) - return false; - - mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL; - pos = (mw->GetModeChar()-65) | mask; - - ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw); - - if (a == modewatchers[pos].end()) + std::pair<ModeWatchIter, ModeWatchIter> itpair = modewatchermap.equal_range(mw->GetModeName()); + for (ModeWatchIter i = itpair.first; i != itpair.second; ++i) { - return false; + if (i->second == mw) + { + modewatchermap.erase(i); + return true; + } } - modewatchers[pos].erase(a); - - return true; + return false; } -/** This default implementation can remove simple user modes - */ -void ModeHandler::RemoveMode(User* user, irc::modestacker* stack) +void ModeHandler::RemoveMode(User* user) { + // Remove the mode if it's set on the user if (user->IsModeSet(this->GetModeChar())) { - if (stack) - { - stack->Push(this->GetModeChar()); - } - else - { - std::vector<std::string> parameters; - parameters.push_back(user->nick); - parameters.push_back("-"); - parameters[1].push_back(this->GetModeChar()); - ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient); - } + std::vector<std::string> parameters; + parameters.push_back(user->nick); + parameters.push_back("-"); + parameters[1].push_back(this->GetModeChar()); + ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient, ModeParser::MODE_LOCALONLY); } } -/** This default implementation can remove simple channel modes - * (no parameters) - */ -void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack) +void ModeHandler::RemoveMode(Channel* channel, irc::modestacker& stack) { - if (channel->IsModeSet(this->GetModeChar())) + if (this->GetPrefixRank()) { - if (stack) - { - stack->Push(this->GetModeChar()); - } + RemovePrefixMode(channel, stack); + } + else if (channel->IsModeSet(this)) + { + if (this->GetNumParams(false)) + // Removing this mode requires a parameter + stack.Push(this->GetModeChar(), channel->GetModeParameter(this)); else - { - std::vector<std::string> parameters; - parameters.push_back(channel->name); - parameters.push_back("-"); - parameters[1].push_back(this->GetModeChar()); - ServerInstance->SendMode(parameters, ServerInstance->FakeClient); - } + stack.Push(this->GetModeChar()); + } +} + +void ModeHandler::RemovePrefixMode(Channel* chan, irc::modestacker& stack) +{ + const UserMembList* userlist = chan->GetUsers(); + for (UserMembCIter i = userlist->begin(); i != userlist->end(); ++i) + { + if (i->second->hasMode(this->GetModeChar())) + stack.Push(this->GetModeChar(), i->first->nick); } } @@ -956,40 +872,29 @@ struct builtin_modes ModeUserOperator uo; ModeUserServerNoticeMask us; - void init(ModeParser* modes) - { - modes->AddMode(&s); - modes->AddMode(&p); - modes->AddMode(&m); - modes->AddMode(&t); - modes->AddMode(&n); - modes->AddMode(&i); - modes->AddMode(&k); - modes->AddMode(&l); - modes->AddMode(&b); - modes->AddMode(&o); - modes->AddMode(&v); - modes->AddMode(&uw); - modes->AddMode(&ui); - modes->AddMode(&uo); - modes->AddMode(&us); + void init() + { + ServiceProvider* modes[] = { &s, &p, &m, &t, &n, &i, &k, &l, &b, &o, &v, + &uw, &ui, &uo, &us }; + ServerInstance->Modules->AddServices(modes, sizeof(modes)/sizeof(ServiceProvider*)); } }; static builtin_modes static_modes; +void ModeParser::InitBuiltinModes() +{ + static_modes.init(); + static_modes.b.DoRehash(); +} + ModeParser::ModeParser() { /* Clear mode handler list */ memset(modehandlers, 0, sizeof(modehandlers)); - /* Last parse string */ - LastParse.clear(); - seq = 0; memset(&sent, 0, sizeof(sent)); - - static_modes.init(this); } ModeParser::~ModeParser() diff --git a/src/modes/cmode_b.cpp b/src/modes/cmode_b.cpp deleted file mode 100644 index 09df05100..000000000 --- a/src/modes/cmode_b.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> - * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "inspircd.h" -#include <string> -#include <vector> -#include "inspircd_config.h" -#include "configreader.h" -#include "hash_map.h" -#include "mode.h" -#include "channels.h" -#include "users.h" -#include "modules.h" -#include "inspstring.h" -#include "hashcomp.h" -#include "modes/cmode_b.h" - -ModeChannelBan::ModeChannelBan() : ModeHandler(NULL, "ban", 'b', PARAM_ALWAYS, MODETYPE_CHANNEL) -{ - list = true; -} - -ModeAction ModeChannelBan::OnModeChange(User* source, User*, Channel* channel, std::string ¶meter, bool adding) -{ - int status = channel->GetPrefixValue(source); - /* Call the correct method depending on wether we're adding or removing the mode */ - if (adding) - { - this->AddBan(source, parameter, channel, status); - } - else - { - this->DelBan(source, parameter, channel, status); - } - /* If the method above 'ate' the parameter by reducing it to an empty string, then - * it won't matter wether we return ALLOW or DENY here, as an empty string overrides - * the return value and is always MODEACTION_DENY if the mode is supposed to have - * a parameter. - */ - return MODEACTION_ALLOW; -} - -void ModeChannelBan::RemoveMode(Channel* channel, irc::modestacker* stack) -{ - BanList copy; - - for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++) - { - copy.push_back(*i); - } - - for (BanList::iterator i = copy.begin(); i != copy.end(); i++) - { - if (stack) - { - stack->Push(this->GetModeChar(), i->data); - } - else - { - std::vector<std::string> parameters; parameters.push_back(channel->name); parameters.push_back("-b"); parameters.push_back(i->data); - ServerInstance->SendMode(parameters, ServerInstance->FakeClient); - } - } -} - -void ModeChannelBan::RemoveMode(User*, irc::modestacker* stack) -{ -} - -void ModeChannelBan::DisplayList(User* user, Channel* channel) -{ - /* Display the channel banlist */ - for (BanList::reverse_iterator i = channel->bans.rbegin(); i != channel->bans.rend(); ++i) - { - user->WriteServ("367 %s %s %s %s %lu",user->nick.c_str(), channel->name.c_str(), i->data.c_str(), i->set_by.c_str(), (unsigned long)i->set_time); - } - user->WriteServ("368 %s %s :End of channel ban list",user->nick.c_str(), channel->name.c_str()); - return; -} - -void ModeChannelBan::DisplayEmptyList(User* user, Channel* channel) -{ - user->WriteServ("368 %s %s :End of channel ban list",user->nick.c_str(), channel->name.c_str()); -} - -std::string& ModeChannelBan::AddBan(User *user, std::string &dest, Channel *chan, int) -{ - if ((!user) || (!chan)) - { - ServerInstance->Logs->Log("MODE",DEFAULT,"*** BUG *** AddBan was given an invalid parameter"); - dest.clear(); - return dest; - } - - /* Attempt to tidy the mask */ - ModeParser::CleanMask(dest); - /* If the mask was invalid, we exit */ - if (dest.empty() || dest.length() > 250) - return dest; - - long maxbans = chan->GetMaxBans(); - if (IS_LOCAL(user) && ((unsigned)chan->bans.size() >= (unsigned)maxbans)) - { - user->WriteServ("478 %s %s :Channel ban list for %s is full (maximum entries for this channel is %ld)",user->nick.c_str(), chan->name.c_str(), chan->name.c_str(), maxbans); - dest.clear(); - return dest; - } - - ModResult MOD_RESULT; - FIRST_MOD_RESULT(OnAddBan, MOD_RESULT, (user,chan,dest)); - if (MOD_RESULT == MOD_RES_DENY) - { - dest.clear(); - return dest; - } - - for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++) - { - if (i->data == dest) - { - /* dont allow a user to set the same ban twice */ - dest.clear(); - return dest; - } - } - - b.set_time = ServerInstance->Time(); - b.data.assign(dest, 0, MAXBUF); - b.set_by.assign(user->nick, 0, 64); - chan->bans.push_back(b); - return dest; -} - -std::string& ModeChannelBan::DelBan(User *user, std::string& dest, Channel *chan, int) -{ - if ((!user) || (!chan)) - { - ServerInstance->Logs->Log("MODE",DEFAULT,"*** BUG *** TakeBan was given an invalid parameter"); - dest.clear(); - return dest; - } - - for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++) - { - if (!strcasecmp(i->data.c_str(), dest.c_str())) - { - ModResult MOD_RESULT; - FIRST_MOD_RESULT(OnDelBan, MOD_RESULT, (user, chan, dest)); - if (MOD_RESULT == MOD_RES_DENY) - { - dest.clear(); - return dest; - } - chan->bans.erase(i); - return dest; - } - } - dest.clear(); - return dest; -} - diff --git a/src/modes/cmode_k.cpp b/src/modes/cmode_k.cpp index 400333fce..e56b26ff1 100644 --- a/src/modes/cmode_k.cpp +++ b/src/modes/cmode_k.cpp @@ -24,76 +24,34 @@ #include "mode.h" #include "channels.h" #include "users.h" -#include "modes/cmode_k.h" +#include "builtinmodes.h" ModeChannelKey::ModeChannelKey() : ModeHandler(NULL, "key", 'k', PARAM_ALWAYS, MODETYPE_CHANNEL) { } -void ModeChannelKey::RemoveMode(Channel* channel, irc::modestacker* stack) -{ - /** +k needs a parameter when being removed, - * so we have a special-case RemoveMode here for it - */ - - if (channel->IsModeSet('k')) - { - if (stack) - { - stack->Push('k', channel->GetModeParameter('k')); - } - else - { - std::vector<std::string> parameters; - parameters.push_back(channel->name); - parameters.push_back("-k"); - parameters.push_back(channel->GetModeParameter('k')); - ServerInstance->SendMode(parameters, ServerInstance->FakeClient); - } - } -} - -void ModeChannelKey::RemoveMode(User*, irc::modestacker* stack) -{ -} - ModeAction ModeChannelKey::OnModeChange(User* source, User*, Channel* channel, std::string ¶meter, bool adding) { - bool exists = channel->IsModeSet('k'); + bool exists = channel->IsModeSet(this); if (IS_LOCAL(source)) { if (exists == adding) return MODEACTION_DENY; - if (exists && (parameter != channel->GetModeParameter('k'))) + if (exists && (parameter != channel->GetModeParameter(this))) { /* Key is currently set and the correct key wasnt given */ return MODEACTION_DENY; } } else { - if (exists && adding && parameter == channel->GetModeParameter('k')) + if (exists && adding && parameter == channel->GetModeParameter(this)) { /* no-op, don't show */ return MODEACTION_DENY; } } - /* invalid keys */ - if (!parameter.length()) - return MODEACTION_DENY; - - if (parameter.rfind(' ') != std::string::npos) - return MODEACTION_DENY; - if (adding) - { - std::string ckey; - ckey.assign(parameter, 0, 32); - parameter = ckey; - channel->SetModeParam('k', parameter); - } - else - { - channel->SetModeParam('k', ""); - } + parameter = parameter.substr(0, 32); + return MODEACTION_ALLOW; } diff --git a/src/modes/cmode_l.cpp b/src/modes/cmode_l.cpp index 001d058bb..f057a75e6 100644 --- a/src/modes/cmode_l.cpp +++ b/src/modes/cmode_l.cpp @@ -23,7 +23,7 @@ #include "mode.h" #include "channels.h" #include "users.h" -#include "modes/cmode_l.h" +#include "builtinmodes.h" ModeChannelLimit::ModeChannelLimit() : ParamChannelModeHandler(NULL, "limit", 'l') { diff --git a/src/modes/cmode_o.cpp b/src/modes/cmode_o.cpp index 0a13b39ce..d500f23b1 100644 --- a/src/modes/cmode_o.cpp +++ b/src/modes/cmode_o.cpp @@ -26,7 +26,7 @@ #include "channels.h" #include "users.h" #include "modules.h" -#include "modes/cmode_o.h" +#include "builtinmodes.h" ModeChannelOp::ModeChannelOp() : ModeHandler(NULL, "op", 'o', PARAM_ALWAYS, MODETYPE_CHANNEL) { @@ -34,34 +34,7 @@ ModeChannelOp::ModeChannelOp() : ModeHandler(NULL, "op", 'o', PARAM_ALWAYS, MODE prefix = '@'; levelrequired = OP_VALUE; m_paramtype = TR_NICK; -} - -unsigned int ModeChannelOp::GetPrefixRank() -{ - return OP_VALUE; -} - -void ModeChannelOp::RemoveMode(Channel* channel, irc::modestacker* stack) -{ - const UserMembList* clist = channel->GetUsers(); - - for (UserMembCIter i = clist->begin(); i != clist->end(); i++) - { - if (stack) - stack->Push(this->GetModeChar(), i->first->nick); - else - { - std::vector<std::string> parameters; - parameters.push_back(channel->name); - parameters.push_back("-o"); - parameters.push_back(i->first->nick); - ServerInstance->SendMode(parameters, ServerInstance->FakeClient); - } - } -} - -void ModeChannelOp::RemoveMode(User*, irc::modestacker* stack) -{ + prefixrank = OP_VALUE; } ModeAction ModeChannelOp::OnModeChange(User* source, User*, Channel* channel, std::string ¶meter, bool adding) diff --git a/src/modes/cmode_v.cpp b/src/modes/cmode_v.cpp index 4a00f60f1..fe62c407f 100644 --- a/src/modes/cmode_v.cpp +++ b/src/modes/cmode_v.cpp @@ -26,7 +26,7 @@ #include "channels.h" #include "users.h" #include "modules.h" -#include "modes/cmode_v.h" +#include "builtinmodes.h" ModeChannelVoice::ModeChannelVoice() : ModeHandler(NULL, "voice", 'v', PARAM_ALWAYS, MODETYPE_CHANNEL) { @@ -34,34 +34,7 @@ ModeChannelVoice::ModeChannelVoice() : ModeHandler(NULL, "voice", 'v', PARAM_ALW prefix = '+'; levelrequired = HALFOP_VALUE; m_paramtype = TR_NICK; -} - -unsigned int ModeChannelVoice::GetPrefixRank() -{ - return VOICE_VALUE; -} - -void ModeChannelVoice::RemoveMode(Channel* channel, irc::modestacker* stack) -{ - const UserMembList* clist = channel->GetUsers(); - - for (UserMembCIter i = clist->begin(); i != clist->end(); i++) - { - if (stack) - stack->Push(this->GetModeChar(), i->first->nick); - else - { - std::vector<std::string> parameters; - parameters.push_back(channel->name); - parameters.push_back("-v"); - parameters.push_back(i->first->nick); - ServerInstance->SendMode(parameters, ServerInstance->FakeClient); - } - } -} - -void ModeChannelVoice::RemoveMode(User*, irc::modestacker* stack) -{ + prefixrank = VOICE_VALUE; } ModeAction ModeChannelVoice::OnModeChange(User* source, User*, Channel* channel, std::string ¶meter, bool adding) diff --git a/src/modes/umode_o.cpp b/src/modes/umode_o.cpp index a5f590ba0..45b99b1d6 100644 --- a/src/modes/umode_o.cpp +++ b/src/modes/umode_o.cpp @@ -22,7 +22,7 @@ #include "mode.h" #include "channels.h" #include "users.h" -#include "modes/umode_o.h" +#include "builtinmodes.h" ModeUserOperator::ModeUserOperator() : ModeHandler(NULL, "oper", 'o', PARAM_NONE, MODETYPE_USER) { @@ -32,7 +32,7 @@ ModeUserOperator::ModeUserOperator() : ModeHandler(NULL, "oper", 'o', PARAM_NONE ModeAction ModeUserOperator::OnModeChange(User* source, User* dest, Channel*, std::string&, bool adding) { /* Only opers can execute this class at all */ - if (!ServerInstance->ULine(source->server) && !IS_OPER(source)) + if (!ServerInstance->ULine(source->server) && !source->IsOper()) return MODEACTION_DENY; /* Not even opers can GIVE the +o mode, only take it away */ diff --git a/src/modes/umode_s.cpp b/src/modes/umode_s.cpp index 1b782ae85..d06ef64cb 100644 --- a/src/modes/umode_s.cpp +++ b/src/modes/umode_s.cpp @@ -23,7 +23,7 @@ #include "mode.h" #include "channels.h" #include "users.h" -#include "modes/umode_s.h" +#include "builtinmodes.h" ModeUserServerNoticeMask::ModeUserServerNoticeMask() : ModeHandler(NULL, "snomask", 's', PARAM_SETONLY, MODETYPE_USER) { @@ -32,41 +32,116 @@ ModeUserServerNoticeMask::ModeUserServerNoticeMask() : ModeHandler(NULL, "snomas ModeAction ModeUserServerNoticeMask::OnModeChange(User* source, User* dest, Channel*, std::string ¶meter, bool adding) { - /* Set the array fields */ if (adding) { - /* Fix for bug #310 reported by Smartys */ - if (!dest->modes[UM_SNOMASK]) - dest->snomasks.reset(); - - dest->modes[UM_SNOMASK] = true; - parameter = dest->ProcessNoticeMasks(parameter.c_str()); + dest->SetMode(this, true); + // Process the parameter (remove chars we don't understand, remove redundant chars, etc.) + parameter = ProcessNoticeMasks(dest, parameter); return MODEACTION_ALLOW; } else { - if (dest->modes[UM_SNOMASK] != false) + if (dest->IsModeSet(this)) { - dest->modes[UM_SNOMASK] = false; + dest->SetMode(this, false); + dest->snomasks.reset(); return MODEACTION_ALLOW; } } - /* Allow the change */ + // Mode not set and trying to unset, deny return MODEACTION_DENY; } std::string ModeUserServerNoticeMask::GetUserParameter(User* user) { - std::string masks = user->FormatNoticeMasks(); - if (masks.length()) - masks = "+" + masks; - return masks; + std::string ret; + if (!user->IsModeSet(this)) + return ret; + + ret.push_back('+'); + for (unsigned char n = 0; n < 64; n++) + { + if (user->snomasks[n]) + ret.push_back(n + 'A'); + } + return ret; } void ModeUserServerNoticeMask::OnParameterMissing(User* user, User* dest, Channel* channel) { - user->WriteServ("NOTICE %s :*** The user mode +s requires a parameter (server notice mask). Please provide a parameter, e.g. '+s +*'.", - user->nick.c_str()); + user->WriteNotice("*** The user mode +s requires a parameter (server notice mask). Please provide a parameter, e.g. '+s +*'."); } +std::string ModeUserServerNoticeMask::ProcessNoticeMasks(User* user, const std::string& input) +{ + bool adding = true; + std::bitset<64> curr = user->snomasks; + + for (std::string::const_iterator i = input.begin(); i != input.end(); ++i) + { + switch (*i) + { + case '+': + adding = true; + break; + case '-': + adding = false; + break; + case '*': + for (size_t j = 0; j < 64; j++) + { + if (ServerInstance->SNO->IsSnomaskUsable(j+'A')) + curr[j] = adding; + } + break; + default: + // For local users check whether the given snomask is valid and enabled - IsSnomaskUsable() tests both. + // For remote users accept what we were told, unless the snomask char is not a letter. + if (IS_LOCAL(user)) + { + if (!ServerInstance->SNO->IsSnomaskUsable(*i)) + { + user->WriteNumeric(ERR_UNKNOWNSNOMASK, "%s %c :is unknown snomask char to me", user->nick.c_str(), *i); + continue; + } + } + else if (!(((*i >= 'a') && (*i <= 'z')) || ((*i >= 'A') && (*i <= 'Z')))) + continue; + + size_t index = ((*i) - 'A'); + curr[index] = adding; + break; + } + } + + std::string plus = "+"; + std::string minus = "-"; + + // Apply changes and construct two strings consisting of the newly added and the removed snomask chars + for (size_t i = 0; i < 64; i++) + { + bool isset = curr[i]; + if (user->snomasks[i] != isset) + { + user->snomasks[i] = isset; + std::string& appendhere = (isset ? plus : minus); + appendhere.push_back(i+'A'); + } + } + + // Create the final string that will be shown to the user and sent to servers + // Form: "+ABc-de" + std::string output; + if (plus.length() > 1) + output = plus; + + if (minus.length() > 1) + output += minus; + + // Unset the snomask usermode itself if every snomask was unset + if (user->snomasks.none()) + user->SetMode(this, false); + + return output; +} diff --git a/src/modmanager_dynamic.cpp b/src/modmanager_dynamic.cpp index 7dae49a18..750a1c448 100644 --- a/src/modmanager_dynamic.cpp +++ b/src/modmanager_dynamic.cpp @@ -22,7 +22,6 @@ #include "socket.h" #include "socketengine.h" #include "command_parse.h" -#include "dns.h" #include "exitcodes.h" #include <iostream> @@ -38,25 +37,24 @@ bool ModuleManager::Load(const std::string& filename, bool defer) if (filename.find('/') != std::string::npos) return false; - char modfile[MAXBUF]; - snprintf(modfile,MAXBUF,"%s/%s",ServerInstance->Config->ModPath.c_str(),filename.c_str()); + const std::string moduleFile = ServerInstance->Config->Paths.PrependModule(filename); - if (!ServerConfig::FileExists(modfile)) + if (!ServerConfig::FileExists(moduleFile.c_str())) { LastModuleError = "Module file could not be found: " + filename; - ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); return false; } if (Modules.find(filename) != Modules.end()) { LastModuleError = "Module " + filename + " is already loaded, cannot load a module twice!"; - ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); return false; } Module* newmod = NULL; - DLLManager* newhandle = new DLLManager(modfile); + DLLManager* newhandle = new DLLManager(moduleFile.c_str()); try { @@ -71,22 +69,23 @@ bool ModuleManager::Load(const std::string& filename, bool defer) std::string version = newhandle->GetVersion(); if (defer) { - ServerInstance->Logs->Log("MODULE", DEFAULT,"New module introduced: %s (Module version %s)", + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "New module introduced: %s (Module version %s)", filename.c_str(), version.c_str()); } else { + AttachAll(newmod); newmod->init(); Version v = newmod->GetVersion(); - ServerInstance->Logs->Log("MODULE", DEFAULT,"New module introduced: %s (Module version %s)%s", + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "New module introduced: %s (Module version %s)%s", filename.c_str(), version.c_str(), (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]")); } } else { LastModuleError = "Unable to load " + filename + ": " + newhandle->LastError(); - ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); delete newhandle; return false; } @@ -102,7 +101,7 @@ bool ModuleManager::Load(const std::string& filename, bool defer) else delete newhandle; LastModuleError = "Unable to load " + filename + ": " + modexcept.GetReason(); - ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); return false; } @@ -110,7 +109,7 @@ bool ModuleManager::Load(const std::string& filename, bool defer) if (defer) return true; - FOREACH_MOD(I_OnLoadModule,OnLoadModule(newmod)); + FOREACH_MOD(OnLoadModule, (newmod)); /* We give every module a chance to re-prioritize when we introduce a new one, * not just the one thats loading, as the new module could affect the preference * of others @@ -124,10 +123,10 @@ bool ModuleManager::Load(const std::string& filename, bool defer) if (prioritizationState == PRIO_STATE_LAST) break; if (tries == 19) - ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected while loading " + filename); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Hook priority dependency loop detected while loading " + filename); } - ServerInstance->BuildISupport(); + ServerInstance->ISupport.Build(); return true; } @@ -191,7 +190,7 @@ void ModuleManager::LoadAll() std::cout << std::endl << "Loading core commands"; fflush(stdout); - DIR* library = opendir(ServerInstance->Config->ModPath.c_str()); + DIR* library = opendir(ServerInstance->Config->Paths.Module.c_str()); if (library) { dirent* entry = NULL; @@ -204,7 +203,7 @@ void ModuleManager::LoadAll() if (!Load(entry->d_name, true)) { - ServerInstance->Logs->Log("MODULE", DEFAULT, this->LastError()); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, this->LastError()); std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << this->LastError() << std::endl << std::endl; ServerInstance->Exit(EXIT_STATUS_MODULE); } @@ -223,7 +222,7 @@ void ModuleManager::LoadAll() if (!this->Load(name, true)) { - ServerInstance->Logs->Log("MODULE", DEFAULT, this->LastError()); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, this->LastError()); std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << this->LastError() << std::endl << std::endl; ServerInstance->Exit(EXIT_STATUS_MODULE); } @@ -234,13 +233,14 @@ void ModuleManager::LoadAll() Module* mod = i->second; try { - ServerInstance->Logs->Log("MODULE", DEBUG, "Initializing %s", i->first.c_str()); + ServerInstance->Logs->Log("MODULE", LOG_DEBUG, "Initializing %s", i->first.c_str()); + AttachAll(mod); mod->init(); } catch (CoreException& modexcept) { LastModuleError = "Unable to initialize " + mod->ModuleSourceFile + ": " + modexcept.GetReason(); - ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << LastModuleError << std::endl << std::endl; ServerInstance->Exit(EXIT_STATUS_MODULE); } @@ -260,7 +260,7 @@ void ModuleManager::LoadAll() break; if (tries == 19) { - ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected"); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Hook priority dependency loop detected"); ServerInstance->Exit(EXIT_STATUS_MODULE); } } diff --git a/src/modmanager_static.cpp b/src/modmanager_static.cpp index 8f532ee80..321bf520d 100644 --- a/src/modmanager_static.cpp +++ b/src/modmanager_static.cpp @@ -58,7 +58,7 @@ class AllModule : public Module { Command* c = (*i)(this); cmds.push_back(c); - ServerInstance->AddCommand(c); + ServerInstance->Modules->AddService(*c); } } catch (...) @@ -97,11 +97,12 @@ bool ModuleManager::Load(const std::string& name, bool defer) Modules[name] = mod; if (defer) { - ServerInstance->Logs->Log("MODULE", DEFAULT,"New module introduced: %s", name.c_str()); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "New module introduced: %s", name.c_str()); return true; } else { + AttachAll(mod); mod->init(); } } @@ -109,10 +110,10 @@ bool ModuleManager::Load(const std::string& name, bool defer) { if (mod) DoSafeUnload(mod); - ServerInstance->Logs->Log("MODULE", DEFAULT, "Unable to load " + name + ": " + modexcept.GetReason()); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Unable to load " + name + ": " + modexcept.GetReason()); return false; } - FOREACH_MOD(I_OnLoadModule,OnLoadModule(mod)); + FOREACH_MOD(OnLoadModule, (mod)); /* We give every module a chance to re-prioritize when we introduce a new one, * not just the one thats loading, as the new module could affect the preference * of others @@ -126,10 +127,10 @@ bool ModuleManager::Load(const std::string& name, bool defer) if (prioritizationState == PRIO_STATE_LAST) break; if (tries == 19) - ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected while loading " + name); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Hook priority dependency loop detected while loading " + name); } - ServerInstance->BuildISupport(); + ServerInstance->ISupport.Build(); return true; } @@ -185,6 +186,7 @@ void ModuleManager::LoadAll() Load("cmd_all", true); Load("cmd_whowas.so", true); Load("cmd_lusers.so", true); + Load("cmd_privmsg.so", true); ConfigTagList tags = ServerInstance->Config->ConfTags("module"); for(ConfigIter i = tags.first; i != tags.second; ++i) @@ -195,7 +197,7 @@ void ModuleManager::LoadAll() if (!this->Load(name, true)) { - ServerInstance->Logs->Log("MODULE", DEFAULT, this->LastError()); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, this->LastError()); std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << this->LastError() << std::endl << std::endl; ServerInstance->Exit(EXIT_STATUS_MODULE); } @@ -204,14 +206,15 @@ void ModuleManager::LoadAll() for(std::map<std::string, Module*>::iterator i = Modules.begin(); i != Modules.end(); i++) { Module* mod = i->second; - try + try { + AttachAll(mod); mod->init(); } catch (CoreException& modexcept) { LastModuleError = "Unable to initialize " + mod->ModuleSourceFile + ": " + modexcept.GetReason(); - ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << LastModuleError << std::endl << std::endl; ServerInstance->Exit(EXIT_STATUS_MODULE); } @@ -231,7 +234,7 @@ void ModuleManager::LoadAll() break; if (tries == 19) { - ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected"); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Hook priority dependency loop detected"); ServerInstance->Exit(EXIT_STATUS_MODULE); } } diff --git a/src/modules.cpp b/src/modules.cpp index d25e145e3..47c994088 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -24,12 +24,12 @@ */ +#include <fstream> #include "inspircd.h" #include "xline.h" #include "socket.h" #include "socketengine.h" #include "command_parse.h" -#include "dns.h" #include "exitcodes.h" #ifndef _WIN32 @@ -37,13 +37,15 @@ #endif static std::vector<dynamic_reference_base*>* dynrefs = NULL; +static bool dynref_init_complete = false; void dynamic_reference_base::reset_all() { + dynref_init_complete = true; if (!dynrefs) return; for(unsigned int i = 0; i < dynrefs->size(); i++) - (*dynrefs)[i]->ClearCache(); + (*dynrefs)[i]->resolve(); } // Version is a simple class for holding a modules version number @@ -56,22 +58,11 @@ Version::Version(const std::string &desc, int flags, const std::string& linkdata { } -Request::Request(Module* src, Module* dst, const char* idstr) -: id(idstr), source(src), dest(dst) -{ -} - -void Request::Send() -{ - if (dest) - dest->OnRequest(*this); -} - Event::Event(Module* src, const std::string &eventid) : source(src), id(eventid) { } void Event::Send() { - FOREACH_MOD(I_OnEvent,OnEvent(*this)); + FOREACH_MOD(OnEvent, (*this)); } // These declarations define the behavours of the base class Module (which does nothing at all) @@ -85,98 +76,91 @@ Module::~Module() { } -ModResult Module::OnSendSnotice(char &snomask, std::string &type, const std::string &message) { return MOD_RES_PASSTHRU; } -void Module::OnUserConnect(LocalUser*) { } -void Module::OnUserQuit(User*, const std::string&, const std::string&) { } -void Module::OnUserDisconnect(LocalUser*) { } -void Module::OnUserJoin(Membership*, bool, bool, CUList&) { } -void Module::OnPostJoin(Membership*) { } -void Module::OnUserPart(Membership*, std::string&, CUList&) { } -void Module::OnPreRehash(User*, const std::string&) { } -void Module::OnModuleRehash(User*, const std::string&) { } -void Module::OnRehash(User*) { } -ModResult Module::OnUserPreJoin(User*, Channel*, const char*, std::string&, const std::string&) { return MOD_RES_PASSTHRU; } -void Module::OnMode(User*, void*, int, const std::vector<std::string>&, const std::vector<TranslateType>&) { } -void Module::OnOper(User*, const std::string&) { } -void Module::OnPostOper(User*, const std::string&, const std::string &) { } -void Module::OnInfo(User*) { } -void Module::OnWhois(User*, User*) { } -ModResult Module::OnUserPreInvite(User*, User*, Channel*, time_t) { return MOD_RES_PASSTHRU; } -ModResult Module::OnUserPreMessage(User*, void*, int, std::string&, char, CUList&) { return MOD_RES_PASSTHRU; } -ModResult Module::OnUserPreNotice(User*, void*, int, std::string&, char, CUList&) { return MOD_RES_PASSTHRU; } -ModResult Module::OnUserPreNick(User*, const std::string&) { return MOD_RES_PASSTHRU; } -void Module::OnUserPostNick(User*, const std::string&) { } -ModResult Module::OnPreMode(User*, User*, Channel*, const std::vector<std::string>&) { return MOD_RES_PASSTHRU; } -void Module::On005Numeric(std::string&) { } -ModResult Module::OnKill(User*, User*, const std::string&) { return MOD_RES_PASSTHRU; } -void Module::OnLoadModule(Module*) { } -void Module::OnUnloadModule(Module*) { } -void Module::OnBackgroundTimer(time_t) { } -ModResult Module::OnPreCommand(std::string&, std::vector<std::string>&, LocalUser*, bool, const std::string&) { return MOD_RES_PASSTHRU; } -void Module::OnPostCommand(const std::string&, const std::vector<std::string>&, LocalUser*, CmdResult, const std::string&) { } -void Module::OnUserInit(LocalUser*) { } -ModResult Module::OnCheckReady(LocalUser*) { return MOD_RES_PASSTHRU; } -ModResult Module::OnUserRegister(LocalUser*) { return MOD_RES_PASSTHRU; } -ModResult Module::OnUserPreKick(User*, Membership*, const std::string&) { return MOD_RES_PASSTHRU; } -void Module::OnUserKick(User*, Membership*, const std::string&, CUList&) { } -ModResult Module::OnRawMode(User*, Channel*, const char, const std::string &, bool, int) { return MOD_RES_PASSTHRU; } -ModResult Module::OnCheckInvite(User*, Channel*) { return MOD_RES_PASSTHRU; } -ModResult Module::OnCheckKey(User*, Channel*, const std::string&) { return MOD_RES_PASSTHRU; } -ModResult Module::OnCheckLimit(User*, Channel*) { return MOD_RES_PASSTHRU; } -ModResult Module::OnCheckChannelBan(User*, Channel*) { return MOD_RES_PASSTHRU; } -ModResult Module::OnCheckBan(User*, Channel*, const std::string&) { return MOD_RES_PASSTHRU; } -ModResult Module::OnExtBanCheck(User*, Channel*, char) { return MOD_RES_PASSTHRU; } -ModResult Module::OnStats(char, User*, string_list&) { return MOD_RES_PASSTHRU; } -ModResult Module::OnChangeLocalUserHost(LocalUser*, const std::string&) { return MOD_RES_PASSTHRU; } -ModResult Module::OnChangeLocalUserGECOS(LocalUser*, const std::string&) { return MOD_RES_PASSTHRU; } -ModResult Module::OnPreTopicChange(User*, Channel*, const std::string&) { return MOD_RES_PASSTHRU; } -void Module::OnEvent(Event&) { } -void Module::OnRequest(Request&) { } -ModResult Module::OnPassCompare(Extensible* ex, const std::string &password, const std::string &input, const std::string& hashtype) { return MOD_RES_PASSTHRU; } -void Module::OnGlobalOper(User*) { } -void Module::OnPostConnect(User*) { } -ModResult Module::OnAddBan(User*, Channel*, const std::string &) { return MOD_RES_PASSTHRU; } -ModResult Module::OnDelBan(User*, Channel*, const std::string &) { return MOD_RES_PASSTHRU; } -void Module::OnStreamSocketAccept(StreamSocket*, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) { } -int Module::OnStreamSocketWrite(StreamSocket*, std::string&) { return -1; } -void Module::OnStreamSocketClose(StreamSocket*) { } -void Module::OnStreamSocketConnect(StreamSocket*) { } -int Module::OnStreamSocketRead(StreamSocket*, std::string&) { return -1; } -void Module::OnUserMessage(User*, void*, int, const std::string&, char, const CUList&) { } -void Module::OnUserNotice(User*, void*, int, const std::string&, char, const CUList&) { } -void Module::OnRemoteKill(User*, User*, const std::string&, const std::string&) { } -void Module::OnUserInvite(User*, User*, Channel*, time_t) { } -void Module::OnPostTopicChange(User*, Channel*, const std::string&) { } -void Module::OnGetServerDescription(const std::string&, std::string&) { } -void Module::OnSyncUser(User*, Module*, void*) { } -void Module::OnSyncChannel(Channel*, Module*, void*) { } -void Module::OnSyncNetwork(Module*, void*) { } +void Module::DetachEvent(Implementation i) +{ + ServerInstance->Modules->Detach(i, this); +} + +ModResult Module::OnSendSnotice(char &snomask, std::string &type, const std::string &message) { DetachEvent(I_OnSendSnotice); return MOD_RES_PASSTHRU; } +void Module::OnUserConnect(LocalUser*) { DetachEvent(I_OnUserConnect); } +void Module::OnUserQuit(User*, const std::string&, const std::string&) { DetachEvent(I_OnUserQuit); } +void Module::OnUserDisconnect(LocalUser*) { DetachEvent(I_OnUserDisconnect); } +void Module::OnUserJoin(Membership*, bool, bool, CUList&) { DetachEvent(I_OnUserJoin); } +void Module::OnPostJoin(Membership*) { DetachEvent(I_OnPostJoin); } +void Module::OnUserPart(Membership*, std::string&, CUList&) { DetachEvent(I_OnUserPart); } +void Module::OnPreRehash(User*, const std::string&) { DetachEvent(I_OnPreRehash); } +void Module::OnModuleRehash(User*, const std::string&) { DetachEvent(I_OnModuleRehash); } +void Module::OnRehash(User*) { DetachEvent(I_OnRehash); } +ModResult Module::OnUserPreJoin(LocalUser*, Channel*, const std::string&, std::string&, const std::string&) { DetachEvent(I_OnUserPreJoin); return MOD_RES_PASSTHRU; } +void Module::OnMode(User*, User*, Channel*, const std::vector<std::string>&, const std::vector<TranslateType>&) { DetachEvent(I_OnMode); } +void Module::OnOper(User*, const std::string&) { DetachEvent(I_OnOper); } +void Module::OnPostOper(User*, const std::string&, const std::string &) { DetachEvent(I_OnPostOper); } +void Module::OnInfo(User*) { DetachEvent(I_OnInfo); } +void Module::OnWhois(User*, User*) { DetachEvent(I_OnWhois); } +ModResult Module::OnUserPreInvite(User*, User*, Channel*, time_t) { DetachEvent(I_OnUserPreInvite); return MOD_RES_PASSTHRU; } +ModResult Module::OnUserPreMessage(User*, void*, int, std::string&, char, CUList&, MessageType) { DetachEvent(I_OnUserPreMessage); return MOD_RES_PASSTHRU; } +ModResult Module::OnUserPreNick(User*, const std::string&) { DetachEvent(I_OnUserPreNick); return MOD_RES_PASSTHRU; } +void Module::OnUserPostNick(User*, const std::string&) { DetachEvent(I_OnUserPostNick); } +ModResult Module::OnPreMode(User*, User*, Channel*, const std::vector<std::string>&) { DetachEvent(I_OnPreMode); return MOD_RES_PASSTHRU; } +void Module::On005Numeric(std::map<std::string, std::string>&) { DetachEvent(I_On005Numeric); } +ModResult Module::OnKill(User*, User*, const std::string&) { DetachEvent(I_OnKill); return MOD_RES_PASSTHRU; } +void Module::OnLoadModule(Module*) { DetachEvent(I_OnLoadModule); } +void Module::OnUnloadModule(Module*) { DetachEvent(I_OnUnloadModule); } +void Module::OnBackgroundTimer(time_t) { DetachEvent(I_OnBackgroundTimer); } +ModResult Module::OnPreCommand(std::string&, std::vector<std::string>&, LocalUser*, bool, const std::string&) { DetachEvent(I_OnPreCommand); return MOD_RES_PASSTHRU; } +void Module::OnPostCommand(Command*, const std::vector<std::string>&, LocalUser*, CmdResult, const std::string&) { DetachEvent(I_OnPostCommand); } +void Module::OnUserInit(LocalUser*) { DetachEvent(I_OnUserInit); } +ModResult Module::OnCheckReady(LocalUser*) { DetachEvent(I_OnCheckReady); return MOD_RES_PASSTHRU; } +ModResult Module::OnUserRegister(LocalUser*) { DetachEvent(I_OnUserRegister); return MOD_RES_PASSTHRU; } +ModResult Module::OnUserPreKick(User*, Membership*, const std::string&) { DetachEvent(I_OnUserPreKick); return MOD_RES_PASSTHRU; } +void Module::OnUserKick(User*, Membership*, const std::string&, CUList&) { DetachEvent(I_OnUserKick); } +ModResult Module::OnRawMode(User*, Channel*, const char, const std::string &, bool, int) { DetachEvent(I_OnRawMode); return MOD_RES_PASSTHRU; } +ModResult Module::OnCheckInvite(User*, Channel*) { DetachEvent(I_OnCheckInvite); return MOD_RES_PASSTHRU; } +ModResult Module::OnCheckKey(User*, Channel*, const std::string&) { DetachEvent(I_OnCheckKey); return MOD_RES_PASSTHRU; } +ModResult Module::OnCheckLimit(User*, Channel*) { DetachEvent(I_OnCheckLimit); return MOD_RES_PASSTHRU; } +ModResult Module::OnCheckChannelBan(User*, Channel*) { DetachEvent(I_OnCheckChannelBan); return MOD_RES_PASSTHRU; } +ModResult Module::OnCheckBan(User*, Channel*, const std::string&) { DetachEvent(I_OnCheckBan); return MOD_RES_PASSTHRU; } +ModResult Module::OnExtBanCheck(User*, Channel*, char) { DetachEvent(I_OnExtBanCheck); return MOD_RES_PASSTHRU; } +ModResult Module::OnStats(char, User*, string_list&) { DetachEvent(I_OnStats); return MOD_RES_PASSTHRU; } +ModResult Module::OnChangeLocalUserHost(LocalUser*, const std::string&) { DetachEvent(I_OnChangeLocalUserHost); return MOD_RES_PASSTHRU; } +ModResult Module::OnChangeLocalUserGECOS(LocalUser*, const std::string&) { DetachEvent(I_OnChangeLocalUserGECOS); return MOD_RES_PASSTHRU; } +ModResult Module::OnPreTopicChange(User*, Channel*, const std::string&) { DetachEvent(I_OnPreTopicChange); return MOD_RES_PASSTHRU; } +void Module::OnEvent(Event&) { DetachEvent(I_OnEvent); } +ModResult Module::OnPassCompare(Extensible* ex, const std::string &password, const std::string &input, const std::string& hashtype) { DetachEvent(I_OnPassCompare); return MOD_RES_PASSTHRU; } +void Module::OnGlobalOper(User*) { DetachEvent(I_OnGlobalOper); } +void Module::OnPostConnect(User*) { DetachEvent(I_OnPostConnect); } +void Module::OnUserMessage(User*, void*, int, const std::string&, char, const CUList&, MessageType) { DetachEvent(I_OnUserMessage); } +void Module::OnUserInvite(User*, User*, Channel*, time_t) { DetachEvent(I_OnUserInvite); } +void Module::OnPostTopicChange(User*, Channel*, const std::string&) { DetachEvent(I_OnPostTopicChange); } +void Module::OnGetServerDescription(const std::string&, std::string&) { DetachEvent(I_OnGetServerDescription); } +void Module::OnSyncUser(User*, Module*, void*) { DetachEvent(I_OnSyncUser); } +void Module::OnSyncChannel(Channel*, Module*, void*) { DetachEvent(I_OnSyncChannel); } +void Module::OnSyncNetwork(Module*, void*) { DetachEvent(I_OnSyncNetwork); } void Module::ProtoSendMode(void*, TargetTypeFlags, void*, const std::vector<std::string>&, const std::vector<TranslateType>&) { } -void Module::OnDecodeMetaData(Extensible*, const std::string&, const std::string&) { } +void Module::OnDecodeMetaData(Extensible*, const std::string&, const std::string&) { DetachEvent(I_OnDecodeMetaData); } void Module::ProtoSendMetaData(void*, Extensible*, const std::string&, const std::string&) { } -void Module::OnWallops(User*, const std::string&) { } -void Module::OnChangeHost(User*, const std::string&) { } -void Module::OnChangeName(User*, const std::string&) { } -void Module::OnChangeIdent(User*, const std::string&) { } -void Module::OnAddLine(User*, XLine*) { } -void Module::OnDelLine(User*, XLine*) { } -void Module::OnExpireLine(XLine*) { } +void Module::OnChangeHost(User*, const std::string&) { DetachEvent(I_OnChangeHost); } +void Module::OnChangeName(User*, const std::string&) { DetachEvent(I_OnChangeName); } +void Module::OnChangeIdent(User*, const std::string&) { DetachEvent(I_OnChangeIdent); } +void Module::OnAddLine(User*, XLine*) { DetachEvent(I_OnAddLine); } +void Module::OnDelLine(User*, XLine*) { DetachEvent(I_OnDelLine); } +void Module::OnExpireLine(XLine*) { DetachEvent(I_OnExpireLine); } void Module::OnCleanup(int, void*) { } -ModResult Module::OnChannelPreDelete(Channel*) { return MOD_RES_PASSTHRU; } -void Module::OnChannelDelete(Channel*) { } -ModResult Module::OnSetAway(User*, const std::string &) { return MOD_RES_PASSTHRU; } -ModResult Module::OnWhoisLine(User*, User*, int&, std::string&) { return MOD_RES_PASSTHRU; } -void Module::OnBuildNeighborList(User*, UserChanList&, std::map<User*,bool>&) { } -void Module::OnGarbageCollect() { } -ModResult Module::OnSetConnectClass(LocalUser* user, ConnectClass* myclass) { return MOD_RES_PASSTHRU; } -void Module::OnText(User*, void*, int, const std::string&, char, CUList&) { } -void Module::OnRunTestSuite() { } -void Module::OnNamesListItem(User*, Membership*, std::string&, std::string&) { } -ModResult Module::OnNumeric(User*, unsigned int, const std::string&) { return MOD_RES_PASSTHRU; } -void Module::OnHookIO(StreamSocket*, ListenSocket*) { } -ModResult Module::OnAcceptConnection(int, ListenSocket*, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) { return MOD_RES_PASSTHRU; } -void Module::OnSendWhoLine(User*, const std::vector<std::string>&, User*, std::string&) { } -void Module::OnSetUserIP(LocalUser*) { } +ModResult Module::OnChannelPreDelete(Channel*) { DetachEvent(I_OnChannelPreDelete); return MOD_RES_PASSTHRU; } +void Module::OnChannelDelete(Channel*) { DetachEvent(I_OnChannelDelete); } +ModResult Module::OnSetAway(User*, const std::string &) { DetachEvent(I_OnSetAway); return MOD_RES_PASSTHRU; } +ModResult Module::OnWhoisLine(User*, User*, int&, std::string&) { DetachEvent(I_OnWhoisLine); return MOD_RES_PASSTHRU; } +void Module::OnBuildNeighborList(User*, UserChanList&, std::map<User*,bool>&) { DetachEvent(I_OnBuildNeighborList); } +void Module::OnGarbageCollect() { DetachEvent(I_OnGarbageCollect); } +ModResult Module::OnSetConnectClass(LocalUser* user, ConnectClass* myclass) { DetachEvent(I_OnSetConnectClass); return MOD_RES_PASSTHRU; } +void Module::OnText(User*, void*, int, const std::string&, char, CUList&) { DetachEvent(I_OnText); } +void Module::OnRunTestSuite() { DetachEvent(I_OnRunTestSuite); } +void Module::OnNamesListItem(User*, Membership*, std::string&, std::string&) { DetachEvent(I_OnNamesListItem); } +ModResult Module::OnNumeric(User*, unsigned int, const std::string&) { DetachEvent(I_OnNumeric); return MOD_RES_PASSTHRU; } +void Module::OnHookIO(StreamSocket*, ListenSocket*) { DetachEvent(I_OnHookIO); } +ModResult Module::OnAcceptConnection(int, ListenSocket*, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) { DetachEvent(I_OnAcceptConnection); return MOD_RES_PASSTHRU; } +void Module::OnSendWhoLine(User*, const std::vector<std::string>&, User*, std::string&) { DetachEvent(I_OnSendWhoLine); } +void Module::OnSetUserIP(LocalUser*) { DetachEvent(I_OnSetUserIP); } ModuleManager::ModuleManager() : ModCount(0) { @@ -212,6 +196,12 @@ void ModuleManager::Attach(Implementation* i, Module* mod, size_t sz) Attach(i[n], mod); } +void ModuleManager::AttachAll(Module* mod) +{ + for (size_t i = I_BEGIN + 1; i != I_END; ++i) + Attach((Implementation)i, mod); +} + void ModuleManager::DetachAll(Module* mod) { for (size_t n = I_BEGIN + 1; n != I_END; ++n) @@ -254,22 +244,25 @@ bool ModuleManager::SetPriority(Module* mod, Implementation i, Priority s, Modul return false; found_src: + // The modules registered for a hook are called in reverse order (to allow for easier removal + // of list entries while looping), meaning that the Priority given to us has the exact opposite effect + // on the list, e.g.: PRIORITY_BEFORE will actually put 'mod' after 'which', etc. size_t swap_pos = my_pos; switch (s) { - case PRIORITY_FIRST: + case PRIORITY_LAST: if (prioritizationState != PRIO_STATE_FIRST) return true; else swap_pos = 0; break; - case PRIORITY_LAST: + case PRIORITY_FIRST: if (prioritizationState != PRIO_STATE_FIRST) return true; else swap_pos = EventHandlers[i].size() - 1; break; - case PRIORITY_AFTER: + case PRIORITY_BEFORE: { /* Find the latest possible position, only searching AFTER our position */ for (size_t x = EventHandlers[i].size() - 1; x > my_pos; --x) @@ -284,7 +277,7 @@ found_src: return true; } /* Place this module before a set of other modules */ - case PRIORITY_BEFORE: + case PRIORITY_AFTER: { for (size_t x = 0; x < my_pos; ++x) { @@ -331,13 +324,13 @@ bool ModuleManager::CanUnload(Module* mod) if ((modfind == Modules.end()) || (modfind->second != mod) || (mod->dying)) { LastModuleError = "Module " + mod->ModuleSourceFile + " is not loaded, cannot unload it!"; - ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); return false; } if (mod->GetVersion().Flags & VF_STATIC) { LastModuleError = "Module " + mod->ModuleSourceFile + " not unloadable (marked static)"; - ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); return false; } @@ -347,6 +340,11 @@ bool ModuleManager::CanUnload(Module* mod) void ModuleManager::DoSafeUnload(Module* mod) { + // First, notify all modules that a module is about to be unloaded, so in case + // they pass execution to the soon to be unloaded module, it will happen now, + // i.e. before we unregister the services of the module being unloaded + FOREACH_MOD(OnUnloadModule, (mod)); + std::map<std::string, Module*>::iterator modfind = Modules.find(mod->ModuleSourceFile); std::vector<reference<ExtensionItem> > items; @@ -370,10 +368,10 @@ void ModuleManager::DoSafeUnload(Module* mod) ModeHandler* mh; mh = ServerInstance->Modes->FindMode(m, MODETYPE_USER); if (mh && mh->creator == mod) - ServerInstance->Modes->DelMode(mh); + this->DelService(*mh); mh = ServerInstance->Modes->FindMode(m, MODETYPE_CHANNEL); if (mh && mh->creator == mod) - ServerInstance->Modes->DelMode(mh); + this->DelService(*mh); } for(std::multimap<std::string, ServiceProvider*>::iterator i = DataProviders.begin(); i != DataProviders.end(); ) { @@ -384,19 +382,14 @@ void ModuleManager::DoSafeUnload(Module* mod) dynamic_reference_base::reset_all(); - /* Tidy up any dangling resolvers */ - ServerInstance->Res->CleanResolvers(mod); - - FOREACH_MOD(I_OnUnloadModule,OnUnloadModule(mod)); - DetachAll(mod); Modules.erase(modfind); ServerInstance->GlobalCulls.AddItem(mod); - ServerInstance->Logs->Log("MODULE", DEFAULT,"Module %s unloaded",mod->ModuleSourceFile.c_str()); + ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Module %s unloaded",mod->ModuleSourceFile.c_str()); this->ModCount--; - ServerInstance->BuildISupport(); + ServerInstance->ISupport.Build(); } void ModuleManager::UnloadAll() @@ -427,16 +420,6 @@ std::string& ModuleManager::LastError() return LastModuleError; } -CmdResult InspIRCd::CallCommandHandler(const std::string &commandname, const std::vector<std::string>& parameters, User* user) -{ - return this->Parser->CallHandler(commandname, parameters, user); -} - -bool InspIRCd::IsValidModuleCommand(const std::string &commandname, int pcnt, User* user) -{ - return this->Parser->IsValidCommand(commandname, pcnt, user); -} - void ModuleManager::AddService(ServiceProvider& item) { switch (item.service) @@ -446,9 +429,14 @@ void ModuleManager::AddService(ServiceProvider& item) throw ModuleException("Command "+std::string(item.name)+" already exists."); return; case SERVICE_MODE: - if (!ServerInstance->Modes->AddMode(static_cast<ModeHandler*>(&item))) + { + ModeHandler* mh = static_cast<ModeHandler*>(&item); + if (!ServerInstance->Modes->AddMode(mh)) throw ModuleException("Mode "+std::string(item.name)+" already exists."); + DataProviders.insert(std::make_pair((mh->GetModeType() == MODETYPE_CHANNEL ? "mode/" : "umode/") + item.name, &item)); + dynamic_reference_base::reset_all(); return; + } case SERVICE_METADATA: if (!ServerInstance->Extensions.Register(static_cast<ExtensionItem*>(&item))) throw ModuleException("Extension " + std::string(item.name) + " already exists."); @@ -456,6 +444,9 @@ void ModuleManager::AddService(ServiceProvider& item) case SERVICE_DATA: case SERVICE_IOHOOK: { + if ((item.name.substr(0, 5) == "mode/") || (item.name.substr(0, 6) == "umode/")) + throw ModuleException("The \"mode/\" and the \"umode\" service name prefixes are reserved."); + DataProviders.insert(std::make_pair(item.name, &item)); std::string::size_type slash = item.name.find('/'); if (slash != std::string::npos) @@ -463,6 +454,7 @@ void ModuleManager::AddService(ServiceProvider& item) DataProviders.insert(std::make_pair(item.name.substr(0, slash), &item)); DataProviders.insert(std::make_pair(item.name.substr(slash + 1), &item)); } + dynamic_reference_base::reset_all(); return; } default: @@ -477,7 +469,7 @@ void ModuleManager::DelService(ServiceProvider& item) case SERVICE_MODE: if (!ServerInstance->Modes->DelMode(static_cast<ModeHandler*>(&item))) throw ModuleException("Mode "+std::string(item.name)+" does not exist."); - return; + // Fall through case SERVICE_DATA: case SERVICE_IOHOOK: { @@ -519,6 +511,8 @@ dynamic_reference_base::dynamic_reference_base(Module* Creator, const std::strin if (!dynrefs) dynrefs = new std::vector<dynamic_reference_base*>; dynrefs->push_back(this); + if (dynref_init_complete) + resolve(); } dynamic_reference_base::~dynamic_reference_base() @@ -544,49 +538,16 @@ dynamic_reference_base::~dynamic_reference_base() void dynamic_reference_base::SetProvider(const std::string& newname) { name = newname; - ClearCache(); -} - -void dynamic_reference_base::lookup() -{ - if (!*this) - throw ModuleException("Dynamic reference to '" + name + "' failed to resolve"); + resolve(); } -dynamic_reference_base::operator bool() +void dynamic_reference_base::resolve() { - if (!value) - { - std::multimap<std::string, ServiceProvider*>::iterator i = ServerInstance->Modules->DataProviders.find(name); - if (i != ServerInstance->Modules->DataProviders.end()) - value = static_cast<DataProvider*>(i->second); - } - return (value != NULL); -} - -void InspIRCd::SendMode(const std::vector<std::string>& parameters, User *user) -{ - this->Modes->Process(parameters, user); -} - - -void InspIRCd::SendGlobalMode(const std::vector<std::string>& parameters, User *user) -{ - Modes->Process(parameters, user); - if (!Modes->GetLastParse().empty()) - this->PI->SendMode(parameters[0], Modes->GetLastParseParams(), Modes->GetLastParseTranslate()); -} - -bool InspIRCd::AddResolver(Resolver* r, bool cached) -{ - if (!cached) - return this->Res->AddResolverClass(r); + std::multimap<std::string, ServiceProvider*>::iterator i = ServerInstance->Modules->DataProviders.find(name); + if (i != ServerInstance->Modules->DataProviders.end()) + value = static_cast<DataProvider*>(i->second); else - { - r->TriggerCachedResult(); - delete r; - return true; - } + value = NULL; } Module* ModuleManager::Find(const std::string &name) @@ -608,169 +569,46 @@ const std::vector<std::string> ModuleManager::GetAllModuleNames(int filter) return retval; } -ConfigReader::ConfigReader() -{ - this->error = 0; - ServerInstance->Logs->Log("MODULE", DEBUG, "ConfigReader is deprecated in 2.0; " - "use ServerInstance->Config->ConfValue(\"key\") or ->ConfTags(\"key\") instead"); -} - - -ConfigReader::~ConfigReader() +FileReader::FileReader(const std::string& filename) { + Load(filename); } -static ConfigTag* SlowGetTag(const std::string &tag, int index) +void FileReader::Load(const std::string& filename) { - ConfigTagList tags = ServerInstance->Config->ConfTags(tag); - while (tags.first != tags.second) + // If the file is stored in the file cache then we used that version instead. + std::string realName = ServerInstance->Config->Paths.PrependConfig(filename); + ConfigFileCache::iterator it = ServerInstance->Config->Files.find(realName); + if (it != ServerInstance->Config->Files.end()) { - if (!index) - return tags.first->second; - tags.first++; - index--; + this->lines = it->second; } - return NULL; -} - -std::string ConfigReader::ReadValue(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool allow_linefeeds) -{ - std::string result = default_value; - if (!SlowGetTag(tag, index)->readString(name, result, allow_linefeeds)) - { - this->error = CONF_VALUE_NOT_FOUND; - } - return result; -} - -std::string ConfigReader::ReadValue(const std::string &tag, const std::string &name, int index, bool allow_linefeeds) -{ - return ReadValue(tag, name, "", index, allow_linefeeds); -} - -bool ConfigReader::ReadFlag(const std::string &tag, const std::string &name, const std::string &default_value, int index) -{ - bool def = (default_value == "yes"); - return SlowGetTag(tag, index)->getBool(name, def); -} - -bool ConfigReader::ReadFlag(const std::string &tag, const std::string &name, int index) -{ - return ReadFlag(tag, name, "", index); -} - - -int ConfigReader::ReadInteger(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool need_positive) -{ - int v = atoi(default_value.c_str()); - int result = SlowGetTag(tag, index)->getInt(name, v); - - if ((need_positive) && (result < 0)) + else { - this->error = CONF_INT_NEGATIVE; - return 0; - } + lines.clear(); - return result; -} - -int ConfigReader::ReadInteger(const std::string &tag, const std::string &name, int index, bool need_positive) -{ - return ReadInteger(tag, name, "", index, need_positive); -} + std::ifstream stream(realName.c_str()); + if (!stream.is_open()) + throw CoreException(filename + " does not exist or is not readable!"); -long ConfigReader::GetError() -{ - long olderr = this->error; - this->error = 0; - return olderr; -} - -int ConfigReader::Enumerate(const std::string &tag) -{ - ServerInstance->Logs->Log("MODULE", DEBUG, "Module is using ConfigReader::Enumerate on %s; this is slow!", - tag.c_str()); - int i=0; - while (SlowGetTag(tag, i)) i++; - return i; -} - -FileReader::FileReader(const std::string &filename) -{ - LoadFile(filename); -} - -FileReader::FileReader() -{ -} + std::string line; + while (std::getline(stream, line)) + { + lines.push_back(line); + totalSize += line.size() + 2; + } -std::string FileReader::Contents() -{ - std::string x; - for (file_cache::iterator a = this->fc.begin(); a != this->fc.end(); a++) - { - x.append(*a); - x.append("\r\n"); + stream.close(); } - return x; } -unsigned long FileReader::ContentSize() +std::string FileReader::GetString() { - return this->contentsize; -} - -void FileReader::CalcSize() -{ - unsigned long n = 0; - for (file_cache::iterator a = this->fc.begin(); a != this->fc.end(); a++) - n += (a->length() + 2); - this->contentsize = n; -} - -void FileReader::LoadFile(const std::string &filename) -{ - std::map<std::string, file_cache>::iterator file = ServerInstance->Config->Files.find(filename); - if (file != ServerInstance->Config->Files.end()) + std::string buffer; + for (file_cache::iterator it = this->lines.begin(); it != this->lines.end(); ++it) { - this->fc = file->second; + buffer.append(*it); + buffer.append("\r\n"); } - else - { - fc.clear(); - FILE* f = fopen(filename.c_str(), "r"); - if (!f) - return; - char linebuf[MAXBUF*10]; - while (fgets(linebuf, sizeof(linebuf), f)) - { - int len = strlen(linebuf); - if (len) - fc.push_back(std::string(linebuf, len - 1)); - } - fclose(f); - } - CalcSize(); -} - - -FileReader::~FileReader() -{ -} - -bool FileReader::Exists() -{ - return (!(fc.size() == 0)); -} - -std::string FileReader::GetLine(int x) -{ - if ((x<0) || ((unsigned)x>=fc.size())) - return ""; - return fc[x]; -} - -int FileReader::FileSize() -{ - return fc.size(); + return buffer; } diff --git a/src/modules/extra/m_geoip.cpp b/src/modules/extra/m_geoip.cpp index a36c39bc8..50df9fc26 100644 --- a/src/modules/extra/m_geoip.cpp +++ b/src/modules/extra/m_geoip.cpp @@ -27,7 +27,6 @@ # pragma comment(lib, "GeoIP.lib") #endif -/* $ModDesc: Provides a way to restrict users by country using GeoIP lookup */ /* $LinkerFlags: -lGeoIP */ class ModuleGeoIP : public Module @@ -37,7 +36,7 @@ class ModuleGeoIP : public Module std::string* SetExt(LocalUser* user) { - const char* c = GeoIP_country_code_by_addr(gi, user->GetIPString()); + const char* c = GeoIP_country_code_by_addr(gi, user->GetIPString().c_str()); if (!c) c = "UNK"; @@ -51,15 +50,13 @@ class ModuleGeoIP : public Module { } - void init() + void init() CXX11_OVERRIDE { gi = GeoIP_new(GEOIP_STANDARD); if (gi == NULL) throw ModuleException("Unable to initialize geoip, are you missing GeoIP.dat?"); ServerInstance->Modules->AddService(ext); - Implementation eventlist[] = { I_OnSetConnectClass, I_OnStats }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); for (LocalUserList::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); ++i) { @@ -77,12 +74,12 @@ class ModuleGeoIP : public Module GeoIP_delete(gi); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides a way to assign users to connect classes by country using GeoIP lookup", VF_VENDOR); } - ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) + ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE { std::string* cc = ext.get(user); if (!cc) @@ -99,7 +96,7 @@ class ModuleGeoIP : public Module return MOD_RES_DENY; } - ModResult OnStats(char symbol, User* user, string_list &out) + ModResult OnStats(char symbol, User* user, string_list &out) CXX11_OVERRIDE { if (symbol != 'G') return MOD_RES_PASSTHRU; @@ -129,4 +126,3 @@ class ModuleGeoIP : public Module }; MODULE_INIT(ModuleGeoIP) - diff --git a/src/modules/extra/m_ldapauth.cpp b/src/modules/extra/m_ldapauth.cpp index 5b3f1e7cc..517a6d395 100644 --- a/src/modules/extra/m_ldapauth.cpp +++ b/src/modules/extra/m_ldapauth.cpp @@ -35,7 +35,6 @@ # pragma comment(lib, "lber.lib") #endif -/* $ModDesc: Allow/Deny connections based upon answer from LDAP server */ /* $LinkerFlags: -lldap */ struct RAIILDAPString @@ -119,12 +118,10 @@ public: conn = NULL; } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(ldapAuthed); ServerInstance->Modules->AddService(ldapVhost); - Implementation eventlist[] = { I_OnCheckReady, I_OnRehash,I_OnUserRegister, I_OnUserConnect }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); } @@ -134,7 +131,7 @@ public: ldap_unbind_ext(conn, NULL, NULL); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("ldapauth"); whitelistedcidrs.clear(); @@ -212,7 +209,7 @@ public: std::string> &replacements) { std::string result; - result.reserve(MAXBUF); + result.reserve(text.length()); for (unsigned int i = 0; i < text.length(); ++i) { char c = text[i]; @@ -234,7 +231,7 @@ public: return result; } - virtual void OnUserConnect(LocalUser *user) + void OnUserConnect(LocalUser *user) CXX11_OVERRIDE { std::string* cc = ldapVhost.get(user); if (cc) @@ -244,7 +241,7 @@ public: } } - ModResult OnUserRegister(LocalUser* user) + ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE { if ((!allowpattern.empty()) && (InspIRCd::Match(user->nick,allowpattern))) { @@ -378,7 +375,7 @@ public: attr_value.bv_val = const_cast<char*>(val.c_str()); attr_value.bv_len = val.length(); - ServerInstance->Logs->Log("m_ldapauth", DEBUG, "LDAP compare: %s=%s", attr.c_str(), val.c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "LDAP compare: %s=%s", attr.c_str(), val.c_str()); authed = (ldap_compare_ext_s(conn, DN, attr.c_str(), &attr_value, NULL, NULL) == LDAP_COMPARE_TRUE); @@ -421,16 +418,15 @@ public: return true; } - ModResult OnCheckReady(LocalUser* user) + ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE { return ldapAuthed.get(user) ? MOD_RES_PASSTHRU : MOD_RES_DENY; } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Allow/Deny connections based upon answer from LDAP server", VF_VENDOR); } - }; MODULE_INIT(ModuleLDAPAuth) diff --git a/src/modules/extra/m_ldapoper.cpp b/src/modules/extra/m_ldapoper.cpp index 53896878c..af7b48d07 100644 --- a/src/modules/extra/m_ldapoper.cpp +++ b/src/modules/extra/m_ldapoper.cpp @@ -32,24 +32,8 @@ # pragma comment(lib, "lber.lib") #endif -/* $ModDesc: Adds the ability to authenticate opers via LDAP */ /* $LinkerFlags: -lldap */ -// Duplicated code, also found in cmd_oper and m_sqloper -static bool OneOfMatches(const char* host, const char* ip, const std::string& hostlist) -{ - std::stringstream hl(hostlist); - std::string xhost; - while (hl >> xhost) - { - if (InspIRCd::Match(host, xhost, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(ip, xhost, ascii_case_insensitive_map)) - { - return true; - } - } - return false; -} - struct RAIILDAPString { char *str; @@ -97,7 +81,7 @@ class ModuleLDAPAuth : public Module std::string acceptedhosts = tag->getString("host"); std::string hostname = user->ident + "@" + user->host; - if (!OneOfMatches(hostname.c_str(), user->GetIPString(), acceptedhosts)) + if (!InspIRCd::MatchMask(acceptedhosts, hostname, user->GetIPString())) return false; if (!LookupOper(opername, inputpass)) @@ -113,20 +97,18 @@ public: { } - void init() + void init() CXX11_OVERRIDE { - Implementation eventlist[] = { I_OnRehash, I_OnPreCommand }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); } - virtual ~ModuleLDAPAuth() + ~ModuleLDAPAuth() { if (conn) ldap_unbind_ext(conn, NULL, NULL); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("ldapoper"); @@ -168,7 +150,7 @@ public: return true; } - ModResult OnPreCommand(std::string& command, std::vector<std::string>& parameters, LocalUser* user, bool validated, const std::string& original_line) + ModResult OnPreCommand(std::string& command, std::vector<std::string>& parameters, LocalUser* user, bool validated, const std::string& original_line) CXX11_OVERRIDE { if (validated && command == "OPER" && parameters.size() >= 2) { @@ -245,7 +227,7 @@ public: } } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Adds the ability to authenticate opers via LDAP", VF_VENDOR); } diff --git a/src/modules/extra/m_mssql.cpp b/src/modules/extra/m_mssql.cpp index 598f9aac9..e6bac038c 100644 --- a/src/modules/extra/m_mssql.cpp +++ b/src/modules/extra/m_mssql.cpp @@ -30,10 +30,8 @@ #include "m_sqlv2.h" -/* $ModDesc: MsSQL provider */ /* $CompileFlags: exec("grep VERSION_NO /usr/include/tdsver.h 2>/dev/null | perl -e 'print "-D_TDSVER=".((<> =~ /freetds v(\d+\.\d+)/i) ? $1*100 : 0);'") */ /* $LinkerFlags: -ltds */ -/* $ModDep: m_sqlv2.h */ class SQLConn; class MsSQLResult; @@ -64,8 +62,8 @@ class QueryThread : public SocketThread public: QueryThread(ModuleMsSQL* mod) : Parent(mod) { } ~QueryThread() { } - virtual void Run(); - virtual void OnNotify(); + void Run(); + void OnNotify(); }; class MsSQLResult : public SQLresult @@ -88,10 +86,6 @@ class MsSQLResult : public SQLresult { } - ~MsSQLResult() - { - } - void AddRow(int colsnum, char **dat, char **colname) { colnames.clear(); @@ -111,17 +105,17 @@ class MsSQLResult : public SQLresult rows++; } - virtual int Rows() + int Rows() { return rows; } - virtual int Cols() + int Cols() { return cols; } - virtual std::string ColName(int column) + std::string ColName(int column) { if (column < (int)colnames.size()) { @@ -134,7 +128,7 @@ class MsSQLResult : public SQLresult return ""; } - virtual int ColNum(const std::string &column) + int ColNum(const std::string &column) { for (unsigned int i = 0; i < colnames.size(); i++) { @@ -145,7 +139,7 @@ class MsSQLResult : public SQLresult return 0; } - virtual SQLfield GetValue(int row, int column) + SQLfield GetValue(int row, int column) { if ((row >= 0) && (row < rows) && (column >= 0) && (column < Cols())) { @@ -158,7 +152,7 @@ class MsSQLResult : public SQLresult return SQLfield("",true); } - virtual SQLfieldList& GetRow() + SQLfieldList& GetRow() { if (currentrow < rows) return fieldlists[currentrow]; @@ -166,7 +160,7 @@ class MsSQLResult : public SQLresult return emptyfieldlist; } - virtual SQLfieldMap& GetRowMap() + SQLfieldMap& GetRowMap() { /* In an effort to reduce overhead we don't actually allocate the map * until the first time it's needed...so... @@ -192,7 +186,7 @@ class MsSQLResult : public SQLresult return *fieldmap; } - virtual SQLfieldList* GetRowPtr() + SQLfieldList* GetRowPtr() { fieldlist = new SQLfieldList(); @@ -207,7 +201,7 @@ class MsSQLResult : public SQLresult return fieldlist; } - virtual SQLfieldMap* GetRowMapPtr() + SQLfieldMap* GetRowMapPtr() { fieldmap = new SQLfieldMap(); @@ -223,12 +217,12 @@ class MsSQLResult : public SQLresult return fieldmap; } - virtual void Free(SQLfieldMap* fm) + void Free(SQLfieldMap* fm) { delete fm; } - virtual void Free(SQLfieldList* fl) + void Free(SQLfieldList* fl) { delete fl; } @@ -258,7 +252,7 @@ class SQLConn : public classbase if (tds_process_simple_query(sock) != TDS_SUCCEED) { LoggingMutex->Lock(); - ServerInstance->Logs->Log("m_mssql",DEFAULT, "WARNING: Could not select database " + host.name + " for DB with id: " + host.id); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not select database " + host.name + " for DB with id: " + host.id); LoggingMutex->Unlock(); CloseDB(); } @@ -266,7 +260,7 @@ class SQLConn : public classbase else { LoggingMutex->Lock(); - ServerInstance->Logs->Log("m_mssql",DEFAULT, "WARNING: Could not select database " + host.name + " for DB with id: " + host.id); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not select database " + host.name + " for DB with id: " + host.id); LoggingMutex->Unlock(); CloseDB(); } @@ -274,7 +268,7 @@ class SQLConn : public classbase else { LoggingMutex->Lock(); - ServerInstance->Logs->Log("m_mssql",DEFAULT, "WARNING: Could not connect to DB with id: " + host.id); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not connect to DB with id: " + host.id); LoggingMutex->Unlock(); CloseDB(); } @@ -433,7 +427,7 @@ class SQLConn : public classbase char* msquery = strdup(req->query.q.data()); LoggingMutex->Lock(); - ServerInstance->Logs->Log("m_mssql",DEBUG,"doing Query: %s",msquery); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "doing Query: %s",msquery); LoggingMutex->Unlock(); if (tds_submit_query(sock, msquery) != TDS_SUCCEED) { @@ -449,8 +443,8 @@ class SQLConn : public classbase int tds_res; while (tds_process_tokens(sock, &tds_res, NULL, TDS_TOKEN_RESULTS) == TDS_SUCCEED) { - //ServerInstance->Logs->Log("m_mssql",DEBUG,"<******> result type: %d", tds_res); - //ServerInstance->Logs->Log("m_mssql",DEBUG,"AFFECTED ROWS: %d", sock->rows_affected); + //ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "<******> result type: %d", tds_res); + //ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "AFFECTED ROWS: %d", sock->rows_affected); switch (tds_res) { case TDS_ROWFMT_RESULT: @@ -476,8 +470,8 @@ class SQLConn : public classbase if (sock->res_info->row_count > 0) { int cols = sock->res_info->num_cols; - char** name = new char*[MAXBUF]; - char** data = new char*[MAXBUF]; + char** name = new char*[512]; + char** data = new char*[512]; for (int j=0; j<cols; j++) { TDSCOLUMN* col = sock->current_results->columns[j]; @@ -516,7 +510,7 @@ class SQLConn : public classbase { SQLConn* sc = (SQLConn*)pContext->parent; LoggingMutex->Lock(); - ServerInstance->Logs->Log("m_mssql", DEBUG, "Message for DB with id: %s -> %s", sc->host.id.c_str(), pMessage->message); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Message for DB with id: %s -> %s", sc->host.id.c_str(), pMessage->message); LoggingMutex->Unlock(); return 0; } @@ -525,7 +519,7 @@ class SQLConn : public classbase { SQLConn* sc = (SQLConn*)pContext->parent; LoggingMutex->Lock(); - ServerInstance->Logs->Log("m_mssql", DEFAULT, "Error for DB with id: %s -> %s", sc->host.id.c_str(), pMessage->message); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Error for DB with id: %s -> %s", sc->host.id.c_str(), pMessage->message); LoggingMutex->Unlock(); return 0; } @@ -657,18 +651,16 @@ class ModuleMsSQL : public Module queryDispatcher = new QueryThread(this); } - void init() + void init() CXX11_OVERRIDE { ReadConf(); ServerInstance->Threads->Start(queryDispatcher); - Implementation eventlist[] = { I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); ServerInstance->Modules->AddService(sqlserv); } - virtual ~ModuleMsSQL() + ~ModuleMsSQL() { queryDispatcher->join(); delete queryDispatcher; @@ -753,7 +745,7 @@ class ModuleMsSQL : public Module if (HasHost(hi)) { LoggingMutex->Lock(); - ServerInstance->Logs->Log("m_mssql",DEFAULT, "WARNING: A MsSQL connection with id: %s already exists. Aborting database open attempt.", hi.id.c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: A MsSQL connection with id: %s already exists. Aborting database open attempt.", hi.id.c_str()); LoggingMutex->Unlock(); return; } @@ -787,14 +779,14 @@ class ModuleMsSQL : public Module connections.clear(); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { queryDispatcher->LockQueue(); ReadConf(); queryDispatcher->UnlockQueueWakeup(); } - void OnRequest(Request& request) + void OnRequest(Request& request) CXX11_OVERRIDE { if(strcmp(SQLREQID, request.id) == 0) { @@ -825,7 +817,7 @@ class ModuleMsSQL : public Module return ++currid; } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("MsSQL provider", VF_VENDOR); } diff --git a/src/modules/extra/m_mysql.cpp b/src/modules/extra/m_mysql.cpp index 22cf5f3f4..2d20a82ab 100644 --- a/src/modules/extra/m_mysql.cpp +++ b/src/modules/extra/m_mysql.cpp @@ -25,7 +25,7 @@ #include "inspircd.h" #include <mysql.h> -#include "sql.h" +#include "modules/sql.h" #ifdef _WIN32 # pragma comment(lib, "mysqlclient.lib") @@ -35,7 +35,6 @@ /* VERSION 3 API: With nonblocking (threaded) requests */ -/* $ModDesc: SQL Service Provider module for all other m_sql* modules */ /* $CompileFlags: exec("mysql_config --include") */ /* $LinkerFlags: exec("mysql_config --libs_r") rpath("mysql_config --libs_r") */ @@ -107,11 +106,11 @@ class ModuleSQL : public Module ConnMap connections; // main thread only ModuleSQL(); - void init(); + void init() CXX11_OVERRIDE; ~ModuleSQL(); - void OnRehash(User* user); - void OnUnloadModule(Module* mod); - Version GetVersion(); + void OnRehash(User* user) CXX11_OVERRIDE; + void OnUnloadModule(Module* mod) CXX11_OVERRIDE; + Version GetVersion() CXX11_OVERRIDE; }; class DispatcherThread : public SocketThread @@ -121,8 +120,8 @@ class DispatcherThread : public SocketThread public: DispatcherThread(ModuleSQL* CreatorModule) : Parent(CreatorModule) { } ~DispatcherThread() { } - virtual void Run(); - virtual void OnNotify(); + void Run(); + void OnNotify(); }; #if !defined(MYSQL_VERSION_ID) || MYSQL_VERSION_ID<32224 @@ -188,21 +187,17 @@ class MySQLresult : public SQLResult } - ~MySQLresult() - { - } - - virtual int Rows() + int Rows() { return rows; } - virtual void GetCols(std::vector<std::string>& result) + void GetCols(std::vector<std::string>& result) { result.assign(colnames.begin(), colnames.end()); } - virtual SQLEntry GetValue(int row, int column) + SQLEntry GetValue(int row, int column) { if ((row >= 0) && (row < rows) && (column >= 0) && (column < (int)fieldlists[row].size())) { @@ -211,7 +206,7 @@ class MySQLresult : public SQLResult return SQLEntry(); } - virtual bool GetRow(SQLEntries& result) + bool GetRow(SQLEntries& result) { if (currentrow < rows) { @@ -387,9 +382,6 @@ void ModuleSQL::init() Dispatcher = new DispatcherThread(this); ServerInstance->Threads->Start(Dispatcher); - Implementation eventlist[] = { I_OnRehash, I_OnUnloadModule }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - OnRehash(NULL); } diff --git a/src/modules/extra/m_pgsql.cpp b/src/modules/extra/m_pgsql.cpp index ac247548a..2300c9d5b 100644 --- a/src/modules/extra/m_pgsql.cpp +++ b/src/modules/extra/m_pgsql.cpp @@ -26,9 +26,8 @@ #include <cstdlib> #include <sstream> #include <libpq-fe.h> -#include "sql.h" +#include "modules/sql.h" -/* $ModDesc: PostgreSQL Service Provider module for all other m_sql* modules, uses v2 of the SQL API */ /* $CompileFlags: -Iexec("pg_config --includedir") eval("my $s = `pg_config --version`;$s =~ /^.*?(\d+)\.(\d+)\.(\d+).*?$/;my $v = hex(sprintf("0x%02x%02x%02x", $1, $2, $3));print "-DPGSQL_HAS_ESCAPECONN" if(($v >= 0x080104) || ($v >= 0x07030F && $v < 0x070400) || ($v >= 0x07040D && $v < 0x080000) || ($v >= 0x080008 && $v < 0x080100));") */ /* $LinkerFlags: -Lexec("pg_config --libdir") -lpq */ @@ -62,7 +61,7 @@ class ReconnectTimer : public Timer ReconnectTimer(ModulePgSQL* m) : Timer(5, ServerInstance->Time(), false), mod(m) { } - virtual void Tick(time_t TIME); + bool Tick(time_t TIME); }; struct QueueItem @@ -97,12 +96,12 @@ class PgSQLresult : public SQLResult PQclear(res); } - virtual int Rows() + int Rows() { return rows; } - virtual void GetCols(std::vector<std::string>& result) + void GetCols(std::vector<std::string>& result) { result.resize(PQnfields(res)); for(unsigned int i=0; i < result.size(); i++) @@ -111,7 +110,7 @@ class PgSQLresult : public SQLResult } } - virtual SQLEntry GetValue(int row, int column) + SQLEntry GetValue(int row, int column) { char* v = PQgetvalue(res, row, column); if (!v || PQgetisnull(res, row, column)) @@ -120,7 +119,7 @@ class PgSQLresult : public SQLResult return SQLEntry(std::string(v, PQgetlength(res, row, column))); } - virtual bool GetRow(SQLEntries& result) + bool GetRow(SQLEntries& result) { if (currentrow >= PQntuples(res)) return false; @@ -152,7 +151,7 @@ class SQLConn : public SQLProvider, public EventHandler { if (!DoConnect()) { - ServerInstance->Logs->Log("m_pgsql",DEFAULT, "WARNING: Could not connect to database " + tag->getString("id")); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not connect to database " + tag->getString("id")); DelayReconnect(); } } @@ -180,7 +179,7 @@ class SQLConn : public SQLProvider, public EventHandler } } - virtual void HandleEvent(EventType et, int errornum) + void HandleEvent(EventType et, int errornum) { switch (et) { @@ -244,7 +243,7 @@ class SQLConn : public SQLProvider, public EventHandler if (!ServerInstance->SE->AddFd(this, FD_WANT_NO_WRITE | FD_WANT_NO_READ)) { - ServerInstance->Logs->Log("m_pgsql",DEBUG, "BUG: Couldn't add pgsql socket to socket engine"); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Couldn't add pgsql socket to socket engine"); return false; } @@ -417,7 +416,7 @@ restart: int error; size_t escapedsize = PQescapeStringConn(sql, &buffer[0], parm.data(), parm.length(), &error); if (error) - ServerInstance->Logs->Log("m_pgsql", DEBUG, "BUG: Apparently PQescapeStringConn() failed"); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Apparently PQescapeStringConn() failed"); #else size_t escapedsize = PQescapeString(&buffer[0], parm.data(), parm.length()); #endif @@ -452,7 +451,7 @@ restart: int error; size_t escapedsize = PQescapeStringConn(sql, &buffer[0], parm.data(), parm.length(), &error); if (error) - ServerInstance->Logs->Log("m_pgsql", DEBUG, "BUG: Apparently PQescapeStringConn() failed"); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Apparently PQescapeStringConn() failed"); #else size_t escapedsize = PQescapeString(&buffer[0], parm.data(), parm.length()); #endif @@ -505,25 +504,22 @@ class ModulePgSQL : public Module ReconnectTimer* retimer; ModulePgSQL() + : retimer(NULL) { } - void init() + void init() CXX11_OVERRIDE { ReadConf(); - - Implementation eventlist[] = { I_OnUnloadModule, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual ~ModulePgSQL() + ~ModulePgSQL() { - if (retimer) - ServerInstance->Timers->DelTimer(retimer); + delete retimer; ClearAllConnections(); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ReadConf(); } @@ -564,7 +560,7 @@ class ModulePgSQL : public Module connections.clear(); } - void OnUnloadModule(Module* mod) + void OnUnloadModule(Module* mod) CXX11_OVERRIDE { SQLerror err(SQL_BAD_DBID); for(ConnMap::iterator i = connections.begin(); i != connections.end(); i++) @@ -592,16 +588,17 @@ class ModulePgSQL : public Module } } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("PostgreSQL Service Provider module for all other m_sql* modules, uses v2 of the SQL API", VF_VENDOR); } }; -void ReconnectTimer::Tick(time_t time) +bool ReconnectTimer::Tick(time_t time) { mod->retimer = NULL; mod->ReadConf(); + return false; } void SQLConn::DelayReconnect() diff --git a/src/modules/extra/m_regex_pcre.cpp b/src/modules/extra/m_regex_pcre.cpp index cba234c8c..91c2d1404 100644 --- a/src/modules/extra/m_regex_pcre.cpp +++ b/src/modules/extra/m_regex_pcre.cpp @@ -20,10 +20,8 @@ #include "inspircd.h" #include <pcre.h> -#include "m_regex.h" +#include "modules/regex.h" -/* $ModDesc: Regex Provider Module for PCRE */ -/* $ModDep: m_regex.h */ /* $CompileFlags: exec("pcre-config --cflags") */ /* $LinkerFlags: exec("pcre-config --libs") rpath("pcre-config --libs") -lpcre */ @@ -31,21 +29,11 @@ # pragma comment(lib, "libpcre.lib") #endif -class PCREException : public ModuleException -{ -public: - PCREException(const std::string& rx, const std::string& error, int erroffset) - : ModuleException("Error in regex " + rx + " at offset " + ConvToStr(erroffset) + ": " + error) - { - } -}; - class PCRERegex : public Regex { -private: pcre* regex; -public: + public: PCRERegex(const std::string& rx) : Regex(rx) { const char* error; @@ -53,24 +41,19 @@ public: regex = pcre_compile(rx.c_str(), 0, &error, &erroffset, NULL); if (!regex) { - ServerInstance->Logs->Log("REGEX", DEBUG, "pcre_compile failed: /%s/ [%d] %s", rx.c_str(), erroffset, error); - throw PCREException(rx, error, erroffset); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "pcre_compile failed: /%s/ [%d] %s", rx.c_str(), erroffset, error); + throw RegexException(rx, error, erroffset); } } - virtual ~PCRERegex() + ~PCRERegex() { pcre_free(regex); } - virtual bool Matches(const std::string& text) + bool Matches(const std::string& text) CXX11_OVERRIDE { - if (pcre_exec(regex, NULL, text.c_str(), text.length(), 0, 0, NULL, 0) > -1) - { - // Bang. :D - return true; - } - return false; + return (pcre_exec(regex, NULL, text.c_str(), text.length(), 0, 0, NULL, 0) >= 0); } }; @@ -78,7 +61,7 @@ class PCREFactory : public RegexFactory { public: PCREFactory(Module* m) : RegexFactory(m, "regex/pcre") {} - Regex* Create(const std::string& expr) + Regex* Create(const std::string& expr) CXX11_OVERRIDE { return new PCRERegex(expr); } @@ -86,13 +69,14 @@ class PCREFactory : public RegexFactory class ModuleRegexPCRE : public Module { -public: + public: PCREFactory ref; - ModuleRegexPCRE() : ref(this) { + ModuleRegexPCRE() : ref(this) + { ServerInstance->Modules->AddService(ref); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Regex Provider Module for PCRE", VF_VENDOR); } diff --git a/src/modules/extra/m_regex_posix.cpp b/src/modules/extra/m_regex_posix.cpp index b3afd60c8..935cdbf92 100644 --- a/src/modules/extra/m_regex_posix.cpp +++ b/src/modules/extra/m_regex_posix.cpp @@ -19,28 +19,15 @@ #include "inspircd.h" -#include "m_regex.h" +#include "modules/regex.h" #include <sys/types.h> #include <regex.h> -/* $ModDesc: Regex Provider Module for POSIX Regular Expressions */ -/* $ModDep: m_regex.h */ - -class POSIXRegexException : public ModuleException -{ -public: - POSIXRegexException(const std::string& rx, const std::string& error) - : ModuleException("Error in regex " + rx + ": " + error) - { - } -}; - class POSIXRegex : public Regex { -private: regex_t regbuf; -public: + public: POSIXRegex(const std::string& rx, bool extended) : Regex(rx) { int flags = (extended ? REG_EXTENDED : 0) | REG_NOSUB; @@ -58,23 +45,18 @@ public: error = errbuf; delete[] errbuf; regfree(®buf); - throw POSIXRegexException(rx, error); + throw RegexException(rx, error); } } - virtual ~POSIXRegex() + ~POSIXRegex() { regfree(®buf); } - virtual bool Matches(const std::string& text) + bool Matches(const std::string& text) CXX11_OVERRIDE { - if (regexec(®buf, text.c_str(), 0, NULL, 0) == 0) - { - // Bang. :D - return true; - } - return false; + return (regexec(®buf, text.c_str(), 0, NULL, 0) == 0); } }; @@ -83,7 +65,7 @@ class PosixFactory : public RegexFactory public: bool extended; PosixFactory(Module* m) : RegexFactory(m, "regex/posix") {} - Regex* Create(const std::string& expr) + Regex* Create(const std::string& expr) CXX11_OVERRIDE { return new POSIXRegex(expr, extended); } @@ -92,20 +74,20 @@ class PosixFactory : public RegexFactory class ModuleRegexPOSIX : public Module { PosixFactory ref; -public: - ModuleRegexPOSIX() : ref(this) { + + public: + ModuleRegexPOSIX() : ref(this) + { ServerInstance->Modules->AddService(ref); - Implementation eventlist[] = { I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Regex Provider Module for POSIX Regular Expressions", VF_VENDOR); } - void OnRehash(User* u) + void OnRehash(User* u) CXX11_OVERRIDE { ref.extended = ServerInstance->Config->ConfValue("posix")->getBool("extended"); } diff --git a/src/modules/extra/m_regex_re2.cpp b/src/modules/extra/m_regex_re2.cpp new file mode 100644 index 000000000..2525b70ab --- /dev/null +++ b/src/modules/extra/m_regex_re2.cpp @@ -0,0 +1,78 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Peter Powell <petpow@saberuk.com> + * Copyright (C) 2012 ChrisTX <chris@rev-crew.info> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#if defined __GNUC__ +# pragma GCC diagnostic ignored "-Wshadow" +#endif + +#include "inspircd.h" +#include "modules/regex.h" +#include <re2/re2.h> + + +/* $CompileFlags: -std=c++11 */ +/* $LinkerFlags: -lre2 */ + +class RE2Regex : public Regex +{ + RE2 regexcl; + + public: + RE2Regex(const std::string& rx) : Regex(rx), regexcl(rx, RE2::Quiet) + { + if (!regexcl.ok()) + { + throw RegexException(rx, regexcl.error()); + } + } + + bool Matches(const std::string& text) CXX11_OVERRIDE + { + return RE2::FullMatch(text, regexcl); + } +}; + +class RE2Factory : public RegexFactory +{ + public: + RE2Factory(Module* m) : RegexFactory(m, "regex/re2") { } + Regex* Create(const std::string& expr) CXX11_OVERRIDE + { + return new RE2Regex(expr); + } +}; + +class ModuleRegexRE2 : public Module +{ + RE2Factory ref; + + public: + ModuleRegexRE2() : ref(this) + { + ServerInstance->Modules->AddService(ref); + } + + Version GetVersion() CXX11_OVERRIDE + { + return Version("Regex Provider Module for RE2", VF_VENDOR); + } +}; + +MODULE_INIT(ModuleRegexRE2) diff --git a/src/modules/extra/m_regex_stdlib.cpp b/src/modules/extra/m_regex_stdlib.cpp index 204728b65..5ec358d58 100644 --- a/src/modules/extra/m_regex_stdlib.cpp +++ b/src/modules/extra/m_regex_stdlib.cpp @@ -15,32 +15,18 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - + #include "inspircd.h" -#include "m_regex.h" +#include "modules/regex.h" #include <regex> -/* $ModDesc: Regex Provider Module for std::regex Regular Expressions */ -/* $ModConfig: <stdregex type="ecmascript"> - * Specify the Regular Expression engine to use here. Valid settings are - * bre, ere, awk, grep, egrep, ecmascript (default if not specified)*/ /* $CompileFlags: -std=c++11 */ -/* $ModDep: m_regex.h */ - -class StdRegexException : public ModuleException -{ -public: - StdRegexException(const std::string& rx, const std::string& error) - : ModuleException(std::string("Error in regex ") + rx + ": " + error) - { - } -}; class StdRegex : public Regex { -private: std::regex regexcl; -public: + + public: StdRegex(const std::string& rx, std::regex::flag_type fltype) : Regex(rx) { try{ @@ -48,11 +34,11 @@ public: } catch(std::regex_error rxerr) { - throw StdRegexException(rx, rxerr.what()); + throw RegexException(rx, rxerr.what()); } } - - virtual bool Matches(const std::string& text) + + bool Matches(const std::string& text) CXX11_OVERRIDE { return std::regex_search(text, regexcl); } @@ -63,7 +49,7 @@ class StdRegexFactory : public RegexFactory public: std::regex::flag_type regextype; StdRegexFactory(Module* m) : RegexFactory(m, "regex/stdregex") {} - Regex* Create(const std::string& expr) + Regex* Create(const std::string& expr) CXX11_OVERRIDE { return new StdRegex(expr, regextype); } @@ -73,23 +59,22 @@ class ModuleRegexStd : public Module { public: StdRegexFactory ref; - ModuleRegexStd() : ref(this) { + ModuleRegexStd() : ref(this) + { ServerInstance->Modules->AddService(ref); - Implementation eventlist[] = { I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Regex Provider Module for std::regex", VF_VENDOR); } - - void OnRehash(User* u) + + void OnRehash(User* u) CXX11_OVERRIDE { ConfigTag* Conf = ServerInstance->Config->ConfValue("stdregex"); std::string regextype = Conf->getString("type", "ecmascript"); - + if(regextype == "bre") ref.regextype = std::regex::basic; else if(regextype == "ere") diff --git a/src/modules/extra/m_regex_tre.cpp b/src/modules/extra/m_regex_tre.cpp index 4b9eab472..92f2ad990 100644 --- a/src/modules/extra/m_regex_tre.cpp +++ b/src/modules/extra/m_regex_tre.cpp @@ -19,27 +19,15 @@ #include "inspircd.h" -#include "m_regex.h" +#include "modules/regex.h" #include <sys/types.h> #include <tre/regex.h> -/* $ModDesc: Regex Provider Module for TRE Regular Expressions */ /* $CompileFlags: pkgconfincludes("tre","tre/regex.h","") */ /* $LinkerFlags: pkgconflibs("tre","/libtre.so","-ltre") rpath("pkg-config --libs tre") */ -/* $ModDep: m_regex.h */ - -class TRERegexException : public ModuleException -{ -public: - TRERegexException(const std::string& rx, const std::string& error) - : ModuleException("Error in regex " + rx + ": " + error) - { - } -}; class TRERegex : public Regex { -private: regex_t regbuf; public: @@ -60,30 +48,26 @@ public: error = errbuf; delete[] errbuf; regfree(®buf); - throw TRERegexException(rx, error); + throw RegexException(rx, error); } } - virtual ~TRERegex() + ~TRERegex() { regfree(®buf); } - virtual bool Matches(const std::string& text) + bool Matches(const std::string& text) CXX11_OVERRIDE { - if (regexec(®buf, text.c_str(), 0, NULL, 0) == 0) - { - // Bang. :D - return true; - } - return false; + return (regexec(®buf, text.c_str(), 0, NULL, 0) == 0); } }; -class TREFactory : public RegexFactory { +class TREFactory : public RegexFactory +{ public: TREFactory(Module* m) : RegexFactory(m, "regex/tre") {} - Regex* Create(const std::string& expr) + Regex* Create(const std::string& expr) CXX11_OVERRIDE { return new TRERegex(expr); } @@ -92,18 +76,16 @@ class TREFactory : public RegexFactory { class ModuleRegexTRE : public Module { TREFactory trf; -public: - ModuleRegexTRE() : trf(this) { - ServerInstance->Modules->AddService(trf); - } - Version GetVersion() + public: + ModuleRegexTRE() : trf(this) { - return Version("Regex Provider Module for TRE Regular Expressions", VF_VENDOR); + ServerInstance->Modules->AddService(trf); } - ~ModuleRegexTRE() + Version GetVersion() CXX11_OVERRIDE { + return Version("Regex Provider Module for TRE Regular Expressions", VF_VENDOR); } }; diff --git a/src/modules/extra/m_sqlite3.cpp b/src/modules/extra/m_sqlite3.cpp index 7f6a53359..54a2788eb 100644 --- a/src/modules/extra/m_sqlite3.cpp +++ b/src/modules/extra/m_sqlite3.cpp @@ -22,16 +22,14 @@ #include "inspircd.h" #include <sqlite3.h> -#include "sql.h" +#include "modules/sql.h" #ifdef _WIN32 # pragma comment(lib, "sqlite3.lib") #endif -/* $ModDesc: sqlite3 provider */ -/* $CompileFlags: pkgconfversion("sqlite3","3.3") pkgconfincludes("sqlite3","/sqlite3.h","") */ +/* $CompileFlags: pkgconfversion("sqlite3","3.3") pkgconfincludes("sqlite3","/sqlite3.h","") -Wno-pedantic */ /* $LinkerFlags: pkgconflibs("sqlite3","/libsqlite3.so","-lsqlite3") */ -/* $NoPedantic */ class SQLConn; typedef std::map<std::string, SQLConn*> ConnMap; @@ -48,16 +46,12 @@ class SQLite3Result : public SQLResult { } - ~SQLite3Result() - { - } - - virtual int Rows() + int Rows() { return rows; } - virtual bool GetRow(SQLEntries& result) + bool GetRow(SQLEntries& result) { if (currentrow < rows) { @@ -72,7 +66,7 @@ class SQLite3Result : public SQLResult } } - virtual void GetCols(std::vector<std::string>& result) + void GetCols(std::vector<std::string>& result) { result.assign(columns.begin(), columns.end()); } @@ -80,7 +74,6 @@ class SQLite3Result : public SQLResult class SQLConn : public SQLProvider { - private: sqlite3* conn; reference<ConfigTag> config; @@ -90,7 +83,7 @@ class SQLConn : public SQLProvider std::string host = tag->getString("hostname"); if (sqlite3_open_v2(host.c_str(), &conn, SQLITE_OPEN_READWRITE, 0) != SQLITE_OK) { - ServerInstance->Logs->Log("m_sqlite3",DEFAULT, "WARNING: Could not open DB with id: " + tag->getString("id")); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not open DB with id: " + tag->getString("id")); conn = NULL; } } @@ -149,13 +142,13 @@ class SQLConn : public SQLProvider sqlite3_finalize(stmt); } - virtual void submit(SQLQuery* query, const std::string& q) + void submit(SQLQuery* query, const std::string& q) { Query(query, q); delete query; } - virtual void submit(SQLQuery* query, const std::string& q, const ParamL& p) + void submit(SQLQuery* query, const std::string& q, const ParamL& p) { std::string res; unsigned int param = 0; @@ -176,7 +169,7 @@ class SQLConn : public SQLProvider submit(query, res); } - virtual void submit(SQLQuery* query, const std::string& q, const ParamM& p) + void submit(SQLQuery* query, const std::string& q, const ParamM& p) { std::string res; for(std::string::size_type i = 0; i < q.length(); i++) @@ -206,23 +199,15 @@ class SQLConn : public SQLProvider class ModuleSQLite3 : public Module { - private: ConnMap conns; public: - ModuleSQLite3() - { - } - - void init() + void init() CXX11_OVERRIDE { ReadConf(); - - Implementation eventlist[] = { I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual ~ModuleSQLite3() + ~ModuleSQLite3() { ClearConns(); } @@ -252,12 +237,12 @@ class ModuleSQLite3 : public Module } } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ReadConf(); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("sqlite3 provider", VF_VENDOR); } diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp index 1f1297ef9..53fc38ec0 100644 --- a/src/modules/extra/m_ssl_gnutls.cpp +++ b/src/modules/extra/m_ssl_gnutls.cpp @@ -25,8 +25,13 @@ #include <gcrypt.h> #include <gnutls/gnutls.h> #include <gnutls/x509.h> -#include "ssl.h" -#include "m_cap.h" +#include "modules/ssl.h" +#include "modules/cap.h" + +#if ((GNUTLS_VERSION_MAJOR > 2) || (GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR > 9) || (GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR == 9 && GNUTLS_VERSION_PATCH >= 8)) +#define GNUTLS_HAS_MAC_GET_ID +#include <gnutls/crypto.h> +#endif #ifdef _WIN32 # pragma comment(lib, "libgnutls.lib") @@ -39,10 +44,8 @@ # pragma comment(lib, "gdi32.lib") #endif -/* $ModDesc: Provides SSL support for clients */ -/* $CompileFlags: pkgconfincludes("gnutls","/gnutls/gnutls.h","") exec("libgcrypt-config --cflags") */ +/* $CompileFlags: pkgconfincludes("gnutls","/gnutls/gnutls.h","") exec("libgcrypt-config --cflags") -Wno-pedantic */ /* $LinkerFlags: rpath("pkg-config --libs gnutls") pkgconflibs("gnutls","/libgnutls.so","-lgnutls") exec("libgcrypt-config --libs") */ -/* $NoPedantic */ #ifndef GNUTLS_VERSION_MAJOR #define GNUTLS_VERSION_MAJOR LIBGNUTLS_VERSION_MAJOR @@ -106,77 +109,188 @@ public: issl_session() : socket(NULL), sess(NULL) {} }; -class CommandStartTLS : public SplitCommand +class GnuTLSIOHook : public SSLIOHook { - public: - bool enabled; - CommandStartTLS (Module* mod) : SplitCommand(mod, "STARTTLS") + private: + void InitSession(StreamSocket* user, bool me_server) { - enabled = true; - works_before_reg = true; + issl_session* session = &sessions[user->GetFd()]; + + gnutls_init(&session->sess, me_server ? GNUTLS_SERVER : GNUTLS_CLIENT); + session->socket = user; + + #ifdef GNUTLS_NEW_PRIO_API + gnutls_priority_set(session->sess, priority); + #else + gnutls_set_default_priority(session->sess); + #endif + gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred); + gnutls_dh_set_prime_bits(session->sess, dh_bits); + gnutls_transport_set_ptr(session->sess, reinterpret_cast<gnutls_transport_ptr_t>(session)); + gnutls_transport_set_push_function(session->sess, gnutls_push_wrapper); + gnutls_transport_set_pull_function(session->sess, gnutls_pull_wrapper); + + if (me_server) + gnutls_certificate_server_set_request(session->sess, GNUTLS_CERT_REQUEST); // Request client certificate if any. + + Handshake(session, user); } - CmdResult HandleLocal(const std::vector<std::string> ¶meters, LocalUser *user) + void CloseSession(issl_session* session) { - if (!enabled) + if (session->sess) { - user->WriteNumeric(691, "%s :STARTTLS is not enabled", user->nick.c_str()); - return CMD_FAILURE; + gnutls_bye(session->sess, GNUTLS_SHUT_WR); + gnutls_deinit(session->sess); } + session->socket = NULL; + session->sess = NULL; + session->cert = NULL; + session->status = ISSL_NONE; + } - if (user->registered == REG_ALL) - { - user->WriteNumeric(691, "%s :STARTTLS is not permitted after client registration is complete", user->nick.c_str()); - } - else + bool Handshake(issl_session* session, StreamSocket* user) + { + int ret = gnutls_handshake(session->sess); + + if (ret < 0) { - if (!user->eh.GetIOHook()) + if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) { - user->WriteNumeric(670, "%s :STARTTLS successful, go ahead with TLS handshake", user->nick.c_str()); - /* We need to flush the write buffer prior to adding the IOHook, - * otherwise we'll be sending this line inside the SSL session - which - * won't start its handshake until the client gets this line. Currently, - * we assume the write will not block here; this is usually safe, as - * STARTTLS is sent very early on in the registration phase, where the - * user hasn't built up much sendq. Handling a blocked write here would - * be very annoying. - */ - user->eh.DoWrite(); - user->eh.AddIOHook(creator); - creator->OnStreamSocketAccept(&user->eh, NULL, NULL); + // Handshake needs resuming later, read() or write() would have blocked. + + if(gnutls_record_get_direction(session->sess) == 0) + { + // gnutls_handshake() wants to read() again. + session->status = ISSL_HANDSHAKING_READ; + ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); + } + else + { + // gnutls_handshake() wants to write() again. + session->status = ISSL_HANDSHAKING_WRITE; + ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE); + } } else - user->WriteNumeric(691, "%s :STARTTLS failure", user->nick.c_str()); + { + user->SetError("Handshake Failed - " + std::string(gnutls_strerror(ret))); + CloseSession(session); + session->status = ISSL_CLOSING; + } + + return false; } + else + { + // Change the seesion state + session->status = ISSL_HANDSHAKEN; - return CMD_FAILURE; + VerifyCertificate(session,user); + + // Finish writing, if any left + ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE); + + return true; + } } -}; -class ModuleSSLGnuTLS : public Module -{ - issl_session* sessions; + void VerifyCertificate(issl_session* session, StreamSocket* user) + { + if (!session->sess || !user) + return; - gnutls_certificate_credentials_t x509_cred; - gnutls_dh_params_t dh_params; - gnutls_digest_algorithm_t hash; - #ifdef GNUTLS_NEW_PRIO_API - gnutls_priority_t priority; - #endif + unsigned int status; + const gnutls_datum_t* cert_list; + int ret; + unsigned int cert_list_size; + gnutls_x509_crt_t cert; + char str[512]; + unsigned char digest[512]; + size_t digest_size = sizeof(digest); + size_t name_size = sizeof(str); + ssl_cert* certinfo = new ssl_cert; + session->cert = certinfo; - std::string sslports; - int dh_bits; + /* This verification function uses the trusted CAs in the credentials + * structure. So you must have installed one or more CA certificates. + */ + ret = gnutls_certificate_verify_peers2(session->sess, &status); - bool cred_alloc; - bool dh_alloc; + if (ret < 0) + { + certinfo->error = std::string(gnutls_strerror(ret)); + return; + } - RandGen randhandler; - CommandStartTLS starttls; + certinfo->invalid = (status & GNUTLS_CERT_INVALID); + certinfo->unknownsigner = (status & GNUTLS_CERT_SIGNER_NOT_FOUND); + certinfo->revoked = (status & GNUTLS_CERT_REVOKED); + certinfo->trusted = !(status & GNUTLS_CERT_SIGNER_NOT_CA); - GenericCap capHandler; - ServiceProvider iohook; + /* Up to here the process is the same for X.509 certificates and + * OpenPGP keys. From now on X.509 certificates are assumed. This can + * be easily extended to work with openpgp keys as well. + */ + if (gnutls_certificate_type_get(session->sess) != GNUTLS_CRT_X509) + { + certinfo->error = "No X509 keys sent"; + return; + } + + ret = gnutls_x509_crt_init(&cert); + if (ret < 0) + { + certinfo->error = gnutls_strerror(ret); + return; + } + + cert_list_size = 0; + cert_list = gnutls_certificate_get_peers(session->sess, &cert_list_size); + if (cert_list == NULL) + { + certinfo->error = "No certificate was found"; + goto info_done_dealloc; + } + + /* This is not a real world example, since we only check the first + * certificate in the given chain. + */ + + ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); + if (ret < 0) + { + certinfo->error = gnutls_strerror(ret); + goto info_done_dealloc; + } + + gnutls_x509_crt_get_dn(cert, str, &name_size); + certinfo->dn = str; + + gnutls_x509_crt_get_issuer_dn(cert, str, &name_size); + certinfo->issuer = str; + + if ((ret = gnutls_x509_crt_get_fingerprint(cert, hash, digest, &digest_size)) < 0) + { + certinfo->error = gnutls_strerror(ret); + } + else + { + certinfo->fingerprint = BinToHex(digest, digest_size); + } + + /* Beware here we do not check for errors. + */ + if ((gnutls_x509_crt_get_expiration_time(cert) < ServerInstance->Time()) || (gnutls_x509_crt_get_activation_time(cert) > ServerInstance->Time())) + { + certinfo->error = "Not activated, or expired certificate"; + } + +info_done_dealloc: + gnutls_x509_crt_deinit(cert); + } - inline static const char* UnknownIfNULL(const char* str) + static const char* UnknownIfNULL(const char* str) { return str ? str : "UNKNOWN"; } @@ -246,27 +360,271 @@ class ModuleSSLGnuTLS : public Module } public: + issl_session* sessions; + gnutls_certificate_credentials_t x509_cred; + + gnutls_digest_algorithm_t hash; + #ifdef GNUTLS_NEW_PRIO_API + gnutls_priority_t priority; + #endif + int dh_bits; + + GnuTLSIOHook(Module* parent) + : SSLIOHook(parent, "ssl/gnutls") + { + sessions = new issl_session[ServerInstance->SE->GetMaxFds()]; + } + + ~GnuTLSIOHook() + { + delete[] sessions; + } + + void OnStreamSocketAccept(StreamSocket* user, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE + { + issl_session* session = &sessions[user->GetFd()]; + + /* For STARTTLS: Don't try and init a session on a socket that already has a session */ + if (session->sess) + return; + + InitSession(user, true); + } + + void OnStreamSocketConnect(StreamSocket* user) CXX11_OVERRIDE + { + InitSession(user, false); + } + + void OnStreamSocketClose(StreamSocket* user) CXX11_OVERRIDE + { + CloseSession(&sessions[user->GetFd()]); + } + + int OnStreamSocketRead(StreamSocket* user, std::string& recvq) CXX11_OVERRIDE + { + issl_session* session = &sessions[user->GetFd()]; + + if (!session->sess) + { + CloseSession(session); + user->SetError("No SSL session"); + return -1; + } + + if (session->status == ISSL_HANDSHAKING_READ || session->status == ISSL_HANDSHAKING_WRITE) + { + // The handshake isn't finished, try to finish it. + + if(!Handshake(session, user)) + { + if (session->status != ISSL_CLOSING) + return 0; + return -1; + } + } + + // If we resumed the handshake then session->status will be ISSL_HANDSHAKEN. + + if (session->status == ISSL_HANDSHAKEN) + { + char* buffer = ServerInstance->GetReadBuffer(); + size_t bufsiz = ServerInstance->Config->NetBufferSize; + int ret = gnutls_record_recv(session->sess, buffer, bufsiz); + if (ret > 0) + { + recvq.append(buffer, ret); + return 1; + } + else if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) + { + return 0; + } + else if (ret == 0) + { + user->SetError("Connection closed"); + CloseSession(session); + return -1; + } + else + { + user->SetError(gnutls_strerror(ret)); + CloseSession(session); + return -1; + } + } + else if (session->status == ISSL_CLOSING) + return -1; + + return 0; + } + + int OnStreamSocketWrite(StreamSocket* user, std::string& sendq) CXX11_OVERRIDE + { + issl_session* session = &sessions[user->GetFd()]; + + if (!session->sess) + { + CloseSession(session); + user->SetError("No SSL session"); + return -1; + } + + if (session->status == ISSL_HANDSHAKING_WRITE || session->status == ISSL_HANDSHAKING_READ) + { + // The handshake isn't finished, try to finish it. + Handshake(session, user); + if (session->status != ISSL_CLOSING) + return 0; + return -1; + } + + int ret = 0; + + if (session->status == ISSL_HANDSHAKEN) + { + ret = gnutls_record_send(session->sess, sendq.data(), sendq.length()); + + if (ret == (int)sendq.length()) + { + ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_WRITE); + return 1; + } + else if (ret > 0) + { + sendq = sendq.substr(ret); + ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE); + return 0; + } + else if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED || ret == 0) + { + ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE); + return 0; + } + else // (ret < 0) + { + user->SetError(gnutls_strerror(ret)); + CloseSession(session); + return -1; + } + } + + return 0; + } + + ssl_cert* GetCertificate(StreamSocket* sock) CXX11_OVERRIDE + { + int fd = sock->GetFd(); + issl_session* session = &sessions[fd]; + return session->cert; + } + + void TellCiphersAndFingerprint(LocalUser* user) + { + const gnutls_session_t& sess = sessions[user->eh.GetFd()].sess; + if (sess) + { + std::string text = "*** You are connected using SSL cipher '"; + + text += UnknownIfNULL(gnutls_kx_get_name(gnutls_kx_get(sess))); + text.append("-").append(UnknownIfNULL(gnutls_cipher_get_name(gnutls_cipher_get(sess)))).append("-"); + text.append(UnknownIfNULL(gnutls_mac_get_name(gnutls_mac_get(sess)))).append("'"); + + ssl_cert* cert = sessions[user->eh.GetFd()].cert; + if (!cert->fingerprint.empty()) + text += " and your SSL fingerprint is " + cert->fingerprint; + + user->WriteNotice(text); + } + } +}; + +class CommandStartTLS : public SplitCommand +{ + IOHook& hook; + + public: + bool enabled; + CommandStartTLS(Module* mod, IOHook& Hook) + : SplitCommand(mod, "STARTTLS") + , hook(Hook) + { + enabled = true; + works_before_reg = true; + } + + CmdResult HandleLocal(const std::vector<std::string> ¶meters, LocalUser *user) + { + if (!enabled) + { + user->WriteNumeric(691, "%s :STARTTLS is not enabled", user->nick.c_str()); + return CMD_FAILURE; + } + + if (user->registered == REG_ALL) + { + user->WriteNumeric(691, "%s :STARTTLS is not permitted after client registration is complete", user->nick.c_str()); + } + else + { + if (!user->eh.GetIOHook()) + { + user->WriteNumeric(670, "%s :STARTTLS successful, go ahead with TLS handshake", user->nick.c_str()); + /* We need to flush the write buffer prior to adding the IOHook, + * otherwise we'll be sending this line inside the SSL session - which + * won't start its handshake until the client gets this line. Currently, + * we assume the write will not block here; this is usually safe, as + * STARTTLS is sent very early on in the registration phase, where the + * user hasn't built up much sendq. Handling a blocked write here would + * be very annoying. + */ + user->eh.DoWrite(); + user->eh.AddIOHook(&hook); + hook.OnStreamSocketAccept(&user->eh, NULL, NULL); + } + else + user->WriteNumeric(691, "%s :STARTTLS failure", user->nick.c_str()); + } + + return CMD_FAILURE; + } +}; +class ModuleSSLGnuTLS : public Module +{ + GnuTLSIOHook iohook; + + gnutls_dh_params_t dh_params; + + std::string sslports; + + bool cred_alloc; + bool dh_alloc; + + RandGen randhandler; + CommandStartTLS starttls; + + GenericCap capHandler; + + public: ModuleSSLGnuTLS() - : starttls(this), capHandler(this, "tls"), iohook(this, "ssl/gnutls", SERVICE_IOHOOK) + : iohook(this), starttls(this, iohook), capHandler(this, "tls") { gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); - sessions = new issl_session[ServerInstance->SE->GetMaxFds()]; - gnutls_global_init(); // This must be called once in the program gnutls_x509_privkey_init(&x509_key); #ifdef GNUTLS_NEW_PRIO_API // Init this here so it's always initialized, avoids an extra boolean - gnutls_priority_init(&priority, "NORMAL", NULL); + gnutls_priority_init(&iohook.priority, "NORMAL", NULL); #endif cred_alloc = false; dh_alloc = false; } - void init() + void init() CXX11_OVERRIDE { // Needs the flag as it ignores a plain /rehash OnModuleRehash(NULL,"ssl"); @@ -274,16 +632,13 @@ class ModuleSSLGnuTLS : public Module ServerInstance->GenRandom = &randhandler; // Void return, guess we assume success - gnutls_certificate_set_dh_params(x509_cred, dh_params); - Implementation eventlist[] = { I_On005Numeric, I_OnRehash, I_OnModuleRehash, I_OnUserConnect, - I_OnEvent, I_OnHookIO }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); + gnutls_certificate_set_dh_params(iohook.x509_cred, dh_params); ServerInstance->Modules->AddService(iohook); ServerInstance->Modules->AddService(starttls); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { sslports.clear(); @@ -303,7 +658,7 @@ class ModuleSSLGnuTLS : public Module continue; const std::string& portid = port->bind_desc; - ServerInstance->Logs->Log("m_ssl_gnutls", DEFAULT, "m_ssl_gnutls.so: Enabling SSL for port %s", portid.c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Enabling SSL for port %s", portid.c_str()); if (port->bind_tag->getString("type", "clients") == "clients" && port->bind_addr != "127.0.0.1") { @@ -323,7 +678,7 @@ class ModuleSSLGnuTLS : public Module } } - void OnModuleRehash(User* user, const std::string ¶m) + void OnModuleRehash(User* user, const std::string ¶m) CXX11_OVERRIDE { if(param != "ssl") return; @@ -336,11 +691,11 @@ class ModuleSSLGnuTLS : public Module ConfigTag* Conf = ServerInstance->Config->ConfValue("gnutls"); - cafile = Conf->getString("cafile", CONFIG_PATH "/ca.pem"); - crlfile = Conf->getString("crlfile", CONFIG_PATH "/crl.pem"); - certfile = Conf->getString("certfile", CONFIG_PATH "/cert.pem"); - keyfile = Conf->getString("keyfile", CONFIG_PATH "/key.pem"); - dh_bits = Conf->getInt("dhbits"); + cafile = ServerInstance->Config->Paths.PrependConfig(Conf->getString("cafile", "ca.pem")); + crlfile = ServerInstance->Config->Paths.PrependConfig(Conf->getString("crlfile", "crl.pem")); + certfile = ServerInstance->Config->Paths.PrependConfig(Conf->getString("certfile", "cert.pem")); + keyfile = ServerInstance->Config->Paths.PrependConfig(Conf->getString("keyfile", "key.pem")); + int dh_bits = Conf->getInt("dhbits"); std::string hashname = Conf->getString("hash", "md5"); // The GnuTLS manual states that the gnutls_set_default_priority() @@ -353,13 +708,30 @@ class ModuleSSLGnuTLS : public Module if((dh_bits != 768) && (dh_bits != 1024) && (dh_bits != 2048) && (dh_bits != 3072) && (dh_bits != 4096)) dh_bits = 1024; + iohook.dh_bits = dh_bits; + + // As older versions of gnutls can't do this, let's disable it where needed. +#ifdef GNUTLS_HAS_MAC_GET_ID + // As gnutls_digest_algorithm_t and gnutls_mac_algorithm_t are mapped 1:1, we can do this + // There is no gnutls_dig_get_id() at the moment, but it may come later + iohook.hash = (gnutls_digest_algorithm_t)gnutls_mac_get_id(hashname.c_str()); + if (iohook.hash == GNUTLS_DIG_UNKNOWN) + throw ModuleException("Unknown hash type " + hashname); + + // Check if the user is walking around with their head in the ass, + // giving us something that is a valid MAC but not digest + gnutls_hash_hd_t is_digest; + if (gnutls_hash_init(&is_digest, iohook.hash) < 0) + throw ModuleException("Unknown hash type " + hashname); + gnutls_hash_deinit(is_digest, NULL); +#else if (hashname == "md5") - hash = GNUTLS_DIG_MD5; + iohook.hash = GNUTLS_DIG_MD5; else if (hashname == "sha1") - hash = GNUTLS_DIG_SHA1; + iohook.hash = GNUTLS_DIG_SHA1; else throw ModuleException("Unknown hash type " + hashname); - +#endif int ret; @@ -373,32 +745,32 @@ class ModuleSSLGnuTLS : public Module if (cred_alloc) { // Deallocate the old credentials - gnutls_certificate_free_credentials(x509_cred); + gnutls_certificate_free_credentials(iohook.x509_cred); for(unsigned int i=0; i < x509_certs.size(); i++) gnutls_x509_crt_deinit(x509_certs[i]); x509_certs.clear(); } - ret = gnutls_certificate_allocate_credentials(&x509_cred); + ret = gnutls_certificate_allocate_credentials(&iohook.x509_cred); cred_alloc = (ret >= 0); if (!cred_alloc) - ServerInstance->Logs->Log("m_ssl_gnutls",DEBUG, "m_ssl_gnutls.so: Failed to allocate certificate credentials: %s", gnutls_strerror(ret)); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Failed to allocate certificate credentials: %s", gnutls_strerror(ret)); - if((ret =gnutls_certificate_set_x509_trust_file(x509_cred, cafile.c_str(), GNUTLS_X509_FMT_PEM)) < 0) - ServerInstance->Logs->Log("m_ssl_gnutls",DEBUG, "m_ssl_gnutls.so: Failed to set X.509 trust file '%s': %s", cafile.c_str(), gnutls_strerror(ret)); + if((ret =gnutls_certificate_set_x509_trust_file(iohook.x509_cred, cafile.c_str(), GNUTLS_X509_FMT_PEM)) < 0) + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Failed to set X.509 trust file '%s': %s", cafile.c_str(), gnutls_strerror(ret)); - if((ret = gnutls_certificate_set_x509_crl_file (x509_cred, crlfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0) - ServerInstance->Logs->Log("m_ssl_gnutls",DEBUG, "m_ssl_gnutls.so: Failed to set X.509 CRL file '%s': %s", crlfile.c_str(), gnutls_strerror(ret)); + if((ret = gnutls_certificate_set_x509_crl_file (iohook.x509_cred, crlfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0) + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Failed to set X.509 CRL file '%s': %s", crlfile.c_str(), gnutls_strerror(ret)); FileReader reader; - reader.LoadFile(certfile); - std::string cert_string = reader.Contents(); + reader.Load(certfile); + std::string cert_string = reader.GetString(); gnutls_datum_t cert_datum = { (unsigned char*)cert_string.data(), static_cast<unsigned int>(cert_string.length()) }; - reader.LoadFile(keyfile); - std::string key_string = reader.Contents(); + reader.Load(keyfile); + std::string key_string = reader.GetString(); gnutls_datum_t key_datum = { (unsigned char*)key_string.data(), static_cast<unsigned int>(key_string.length()) }; // If this fails, no SSL port will work. At all. So, do the smart thing - throw a ModuleException @@ -423,40 +795,40 @@ class ModuleSSLGnuTLS : public Module if((ret = gnutls_x509_privkey_import(x509_key, &key_datum, GNUTLS_X509_FMT_PEM)) < 0) throw ModuleException("Unable to load GnuTLS server private key (" + keyfile + "): " + std::string(gnutls_strerror(ret))); - if((ret = gnutls_certificate_set_x509_key(x509_cred, &x509_certs[0], certcount, x509_key)) < 0) + if((ret = gnutls_certificate_set_x509_key(iohook.x509_cred, &x509_certs[0], certcount, x509_key)) < 0) throw ModuleException("Unable to set GnuTLS cert/key pair: " + std::string(gnutls_strerror(ret))); #ifdef GNUTLS_NEW_PRIO_API // It's safe to call this every time as we cannot have this uninitialized, see constructor and below. - gnutls_priority_deinit(priority); + gnutls_priority_deinit(iohook.priority); // Try to set the priorities for ciphers, kex methods etc. to the user supplied string // If the user did not supply anything then the string is already set to "NORMAL" const char* priocstr = priorities.c_str(); const char* prioerror; - if ((ret = gnutls_priority_init(&priority, priocstr, &prioerror)) < 0) + if ((ret = gnutls_priority_init(&iohook.priority, priocstr, &prioerror)) < 0) { // gnutls did not understand the user supplied string, log and fall back to the default priorities - ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to set priorities to \"%s\": %s Syntax error at position %u, falling back to default (NORMAL)", priorities.c_str(), gnutls_strerror(ret), (unsigned int) (prioerror - priocstr)); - gnutls_priority_init(&priority, "NORMAL", NULL); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Failed to set priorities to \"%s\": %s Syntax error at position %u, falling back to default (NORMAL)", priorities.c_str(), gnutls_strerror(ret), (unsigned int) (prioerror - priocstr)); + gnutls_priority_init(&iohook.priority, "NORMAL", NULL); } #else if (priorities != "NORMAL") - ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: You've set <gnutls:priority> to a value other than the default, but this is only supported with GnuTLS v2.1.7 or newer. Your GnuTLS version is older than that so the option will have no effect."); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "You've set <gnutls:priority> to a value other than the default, but this is only supported with GnuTLS v2.1.7 or newer. Your GnuTLS version is older than that so the option will have no effect."); #endif #if(GNUTLS_VERSION_MAJOR < 2 || ( GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR < 12 ) ) - gnutls_certificate_client_set_retrieve_function (x509_cred, cert_callback); + gnutls_certificate_client_set_retrieve_function (iohook.x509_cred, cert_callback); #else - gnutls_certificate_set_retrieve_function (x509_cred, cert_callback); + gnutls_certificate_set_retrieve_function (iohook.x509_cred, cert_callback); #endif ret = gnutls_dh_params_init(&dh_params); dh_alloc = (ret >= 0); if (!dh_alloc) { - ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to initialise DH parameters: %s", gnutls_strerror(ret)); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Failed to initialise DH parameters: %s", gnutls_strerror(ret)); return; } @@ -464,14 +836,14 @@ class ModuleSSLGnuTLS : public Module if (!dhfile.empty()) { // Try to load DH params from file - reader.LoadFile(dhfile); - std::string dhstring = reader.Contents(); + reader.Load(dhfile); + std::string dhstring = reader.GetString(); gnutls_datum_t dh_datum = { (unsigned char*)dhstring.data(), static_cast<unsigned int>(dhstring.length()) }; if ((ret = gnutls_dh_params_import_pkcs3(dh_params, &dh_datum, GNUTLS_X509_FMT_PEM)) < 0) { // File unreadable or GnuTLS was unhappy with the contents, generate the DH primes now - ServerInstance->Logs->Log("m_ssl_gnutls", DEFAULT, "m_ssl_gnutls.so: Generating DH parameters because I failed to load them from file '%s': %s", dhfile.c_str(), gnutls_strerror(ret)); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Generating DH parameters because I failed to load them from file '%s': %s", dhfile.c_str(), gnutls_strerror(ret)); GenerateDHParams(); } } @@ -493,8 +865,8 @@ class ModuleSSLGnuTLS : public Module int ret; - if((ret = gnutls_dh_params_generate2(dh_params, dh_bits)) < 0) - ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to generate DH parameters (%d bits): %s", dh_bits, gnutls_strerror(ret)); + if((ret = gnutls_dh_params_generate2(dh_params, iohook.dh_bits)) < 0) + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Failed to generate DH parameters (%d bits): %s", iohook.dh_bits, gnutls_strerror(ret)); } ~ModuleSSLGnuTLS() @@ -504,26 +876,25 @@ class ModuleSSLGnuTLS : public Module gnutls_x509_privkey_deinit(x509_key); #ifdef GNUTLS_NEW_PRIO_API - gnutls_priority_deinit(priority); + gnutls_priority_deinit(iohook.priority); #endif if (dh_alloc) gnutls_dh_params_deinit(dh_params); if (cred_alloc) - gnutls_certificate_free_credentials(x509_cred); + gnutls_certificate_free_credentials(iohook.x509_cred); gnutls_global_deinit(); - delete[] sessions; ServerInstance->GenRandom = &ServerInstance->HandleGenRandom; } - void OnCleanup(int target_type, void* item) + void OnCleanup(int target_type, void* item) CXX11_OVERRIDE { if(target_type == TYPE_USER) { LocalUser* user = IS_LOCAL(static_cast<User*>(item)); - if (user && user->eh.GetIOHook() == this) + if (user && user->eh.GetIOHook() == &iohook) { // User is using SSL, they're a local user, and they're using one of *our* SSL ports. // Potentially there could be multiple SSL modules loaded at once on different ports. @@ -532,373 +903,35 @@ class ModuleSSLGnuTLS : public Module } } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides SSL support for clients", VF_VENDOR); } - - void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { if (!sslports.empty()) - output.append(" SSL=" + sslports); + tokens["SSL"] = sslports; if (starttls.enabled) - output.append(" STARTTLS"); + tokens["STARTTLS"]; } - void OnHookIO(StreamSocket* user, ListenSocket* lsb) + void OnHookIO(StreamSocket* user, ListenSocket* lsb) CXX11_OVERRIDE { if (!user->GetIOHook() && lsb->bind_tag->getString("ssl") == "gnutls") { /* Hook the user with our module */ - user->AddIOHook(this); - } - } - - void OnRequest(Request& request) - { - if (strcmp("GET_SSL_CERT", request.id) == 0) - { - SocketCertificateRequest& req = static_cast<SocketCertificateRequest&>(request); - int fd = req.sock->GetFd(); - issl_session* session = &sessions[fd]; - - req.cert = session->cert; - } - } - - void InitSession(StreamSocket* user, bool me_server) - { - issl_session* session = &sessions[user->GetFd()]; - - gnutls_init(&session->sess, me_server ? GNUTLS_SERVER : GNUTLS_CLIENT); - session->socket = user; - - #ifdef GNUTLS_NEW_PRIO_API - gnutls_priority_set(session->sess, priority); - #else - gnutls_set_default_priority(session->sess); - #endif - gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred); - gnutls_dh_set_prime_bits(session->sess, dh_bits); - gnutls_transport_set_ptr(session->sess, reinterpret_cast<gnutls_transport_ptr_t>(session)); - gnutls_transport_set_push_function(session->sess, gnutls_push_wrapper); - gnutls_transport_set_pull_function(session->sess, gnutls_pull_wrapper); - - if (me_server) - gnutls_certificate_server_set_request(session->sess, GNUTLS_CERT_REQUEST); // Request client certificate if any. - - Handshake(session, user); - } - - void OnStreamSocketAccept(StreamSocket* user, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) - { - issl_session* session = &sessions[user->GetFd()]; - - /* For STARTTLS: Don't try and init a session on a socket that already has a session */ - if (session->sess) - return; - - InitSession(user, true); - } - - void OnStreamSocketConnect(StreamSocket* user) - { - InitSession(user, false); - } - - void OnStreamSocketClose(StreamSocket* user) - { - CloseSession(&sessions[user->GetFd()]); - } - - int OnStreamSocketRead(StreamSocket* user, std::string& recvq) - { - issl_session* session = &sessions[user->GetFd()]; - - if (!session->sess) - { - CloseSession(session); - user->SetError("No SSL session"); - return -1; - } - - if (session->status == ISSL_HANDSHAKING_READ || session->status == ISSL_HANDSHAKING_WRITE) - { - // The handshake isn't finished, try to finish it. - - if(!Handshake(session, user)) - { - if (session->status != ISSL_CLOSING) - return 0; - return -1; - } - } - - // If we resumed the handshake then session->status will be ISSL_HANDSHAKEN. - - if (session->status == ISSL_HANDSHAKEN) - { - char* buffer = ServerInstance->GetReadBuffer(); - size_t bufsiz = ServerInstance->Config->NetBufferSize; - int ret = gnutls_record_recv(session->sess, buffer, bufsiz); - if (ret > 0) - { - recvq.append(buffer, ret); - return 1; - } - else if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) - { - return 0; - } - else if (ret == 0) - { - user->SetError("Connection closed"); - CloseSession(session); - return -1; - } - else - { - user->SetError(gnutls_strerror(ret)); - CloseSession(session); - return -1; - } - } - else if (session->status == ISSL_CLOSING) - return -1; - - return 0; - } - - int OnStreamSocketWrite(StreamSocket* user, std::string& sendq) - { - issl_session* session = &sessions[user->GetFd()]; - - if (!session->sess) - { - CloseSession(session); - user->SetError("No SSL session"); - return -1; - } - - if (session->status == ISSL_HANDSHAKING_WRITE || session->status == ISSL_HANDSHAKING_READ) - { - // The handshake isn't finished, try to finish it. - Handshake(session, user); - if (session->status != ISSL_CLOSING) - return 0; - return -1; - } - - int ret = 0; - - if (session->status == ISSL_HANDSHAKEN) - { - ret = gnutls_record_send(session->sess, sendq.data(), sendq.length()); - - if (ret == (int)sendq.length()) - { - ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_WRITE); - return 1; - } - else if (ret > 0) - { - sendq = sendq.substr(ret); - ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE); - return 0; - } - else if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED || ret == 0) - { - ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE); - return 0; - } - else // (ret < 0) - { - user->SetError(gnutls_strerror(ret)); - CloseSession(session); - return -1; - } - } - - return 0; - } - - bool Handshake(issl_session* session, StreamSocket* user) - { - int ret = gnutls_handshake(session->sess); - - if (ret < 0) - { - if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) - { - // Handshake needs resuming later, read() or write() would have blocked. - - if(gnutls_record_get_direction(session->sess) == 0) - { - // gnutls_handshake() wants to read() again. - session->status = ISSL_HANDSHAKING_READ; - ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); - } - else - { - // gnutls_handshake() wants to write() again. - session->status = ISSL_HANDSHAKING_WRITE; - ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE); - } - } - else - { - user->SetError("Handshake Failed - " + std::string(gnutls_strerror(ret))); - CloseSession(session); - session->status = ISSL_CLOSING; - } - - return false; - } - else - { - // Change the seesion state - session->status = ISSL_HANDSHAKEN; - - VerifyCertificate(session,user); - - // Finish writing, if any left - ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE); - - return true; - } - } - - void OnUserConnect(LocalUser* user) - { - if (user->eh.GetIOHook() == this) - { - if (sessions[user->eh.GetFd()].sess) - { - const gnutls_session_t& sess = sessions[user->eh.GetFd()].sess; - std::string cipher = UnknownIfNULL(gnutls_kx_get_name(gnutls_kx_get(sess))); - cipher.append("-").append(UnknownIfNULL(gnutls_cipher_get_name(gnutls_cipher_get(sess)))).append("-"); - cipher.append(UnknownIfNULL(gnutls_mac_get_name(gnutls_mac_get(sess)))); - - ssl_cert* cert = sessions[user->eh.GetFd()].cert; - if (cert->fingerprint.empty()) - user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick.c_str(), cipher.c_str()); - else - user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"" - " and your SSL fingerprint is %s", user->nick.c_str(), cipher.c_str(), cert->fingerprint.c_str()); - } - } - } - - void CloseSession(issl_session* session) - { - if (session->sess) - { - gnutls_bye(session->sess, GNUTLS_SHUT_WR); - gnutls_deinit(session->sess); + user->AddIOHook(&iohook); } - session->socket = NULL; - session->sess = NULL; - session->cert = NULL; - session->status = ISSL_NONE; } - void VerifyCertificate(issl_session* session, StreamSocket* user) + void OnUserConnect(LocalUser* user) CXX11_OVERRIDE { - if (!session->sess || !user) - return; - - unsigned int status; - const gnutls_datum_t* cert_list; - int ret; - unsigned int cert_list_size; - gnutls_x509_crt_t cert; - char name[MAXBUF]; - unsigned char digest[MAXBUF]; - size_t digest_size = sizeof(digest); - size_t name_size = sizeof(name); - ssl_cert* certinfo = new ssl_cert; - session->cert = certinfo; - - /* This verification function uses the trusted CAs in the credentials - * structure. So you must have installed one or more CA certificates. - */ - ret = gnutls_certificate_verify_peers2(session->sess, &status); - - if (ret < 0) - { - certinfo->error = std::string(gnutls_strerror(ret)); - return; - } - - certinfo->invalid = (status & GNUTLS_CERT_INVALID); - certinfo->unknownsigner = (status & GNUTLS_CERT_SIGNER_NOT_FOUND); - certinfo->revoked = (status & GNUTLS_CERT_REVOKED); - certinfo->trusted = !(status & GNUTLS_CERT_SIGNER_NOT_CA); - - /* Up to here the process is the same for X.509 certificates and - * OpenPGP keys. From now on X.509 certificates are assumed. This can - * be easily extended to work with openpgp keys as well. - */ - if (gnutls_certificate_type_get(session->sess) != GNUTLS_CRT_X509) - { - certinfo->error = "No X509 keys sent"; - return; - } - - ret = gnutls_x509_crt_init(&cert); - if (ret < 0) - { - certinfo->error = gnutls_strerror(ret); - return; - } - - cert_list_size = 0; - cert_list = gnutls_certificate_get_peers(session->sess, &cert_list_size); - if (cert_list == NULL) - { - certinfo->error = "No certificate was found"; - goto info_done_dealloc; - } - - /* This is not a real world example, since we only check the first - * certificate in the given chain. - */ - - ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); - if (ret < 0) - { - certinfo->error = gnutls_strerror(ret); - goto info_done_dealloc; - } - - gnutls_x509_crt_get_dn(cert, name, &name_size); - certinfo->dn = name; - - gnutls_x509_crt_get_issuer_dn(cert, name, &name_size); - certinfo->issuer = name; - - if ((ret = gnutls_x509_crt_get_fingerprint(cert, hash, digest, &digest_size)) < 0) - { - certinfo->error = gnutls_strerror(ret); - } - else - { - certinfo->fingerprint = irc::hex(digest, digest_size); - } - - /* Beware here we do not check for errors. - */ - if ((gnutls_x509_crt_get_expiration_time(cert) < ServerInstance->Time()) || (gnutls_x509_crt_get_activation_time(cert) > ServerInstance->Time())) - { - certinfo->error = "Not activated, or expired certificate"; - } - -info_done_dealloc: - gnutls_x509_crt_deinit(cert); + if (user->eh.GetIOHook() == &iohook) + iohook.TellCiphersAndFingerprint(user); } - void OnEvent(Event& ev) + void OnEvent(Event& ev) CXX11_OVERRIDE { if (starttls.enabled) capHandler.HandleEvent(ev); diff --git a/src/modules/extra/m_ssl_openssl.cpp b/src/modules/extra/m_ssl_openssl.cpp index 7b7de023c..29c3568ef 100644 --- a/src/modules/extra/m_ssl_openssl.cpp +++ b/src/modules/extra/m_ssl_openssl.cpp @@ -29,11 +29,12 @@ # define __AVAILABILITYMACROS__ # define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER #endif - + #include "inspircd.h" +#include "iohook.h" #include <openssl/ssl.h> #include <openssl/err.h> -#include "ssl.h" +#include "modules/ssl.h" #ifdef _WIN32 # pragma comment(lib, "libcrypto.lib") @@ -47,14 +48,8 @@ # define MAX_DESCRIPTORS 10000 #endif -/* $ModDesc: Provides SSL support for clients */ - -/* $LinkerFlags: if("USE_FREEBSD_BASE_SSL") -lssl -lcrypto */ -/* $CompileFlags: if(!"USE_FREEBSD_BASE_SSL") pkgconfversion("openssl","0.9.7") pkgconfincludes("openssl","/openssl/ssl.h","") */ -/* $LinkerFlags: if(!"USE_FREEBSD_BASE_SSL") rpath("pkg-config --libs openssl") pkgconflibs("openssl","/libssl.so","-lssl -lcrypto -ldl") */ - -/* $NoPedantic */ - +/* $CompileFlags: pkgconfversion("openssl","0.9.7") pkgconfincludes("openssl","/openssl/ssl.h","") -Wno-pedantic */ +/* $LinkerFlags: rpath("pkg-config --libs openssl") pkgconflibs("openssl","/libssl.so","-lssl -lcrypto") */ enum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_OPEN }; @@ -100,234 +95,144 @@ static int OnVerify(int preverify_ok, X509_STORE_CTX *ctx) return 1; } -class ModuleSSLOpenSSL : public Module +class OpenSSLIOHook : public SSLIOHook { - issl_session* sessions; - - SSL_CTX* ctx; - SSL_CTX* clictx; - - std::string sslports; - bool use_sha; - - ServiceProvider iohook; - public: - - ModuleSSLOpenSSL() : iohook(this, "ssl/openssl", SERVICE_IOHOOK) + private: + bool Handshake(StreamSocket* user, issl_session* session) { - sessions = new issl_session[ServerInstance->SE->GetMaxFds()]; + int ret; - /* Global SSL library initialization*/ - SSL_library_init(); - SSL_load_error_strings(); + if (session->outbound) + ret = SSL_connect(session->sess); + else + ret = SSL_accept(session->sess); - /* Build our SSL contexts: - * NOTE: OpenSSL makes us have two contexts, one for servers and one for clients. ICK. - */ - ctx = SSL_CTX_new( SSLv23_server_method() ); - clictx = SSL_CTX_new( SSLv23_client_method() ); + if (ret < 0) + { + int err = SSL_get_error(session->sess, ret); - SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - SSL_CTX_set_mode(clictx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + if (err == SSL_ERROR_WANT_READ) + { + ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); + session->status = ISSL_HANDSHAKING; + return true; + } + else if (err == SSL_ERROR_WANT_WRITE) + { + ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE); + session->status = ISSL_HANDSHAKING; + return true; + } + else + { + CloseSession(session); + } - SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify); - SSL_CTX_set_verify(clictx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify); - } + return false; + } + else if (ret > 0) + { + // Handshake complete. + VerifyCertificate(session, user); - void init() - { - // Needs the flag as it ignores a plain /rehash - OnModuleRehash(NULL,"ssl"); - Implementation eventlist[] = { I_On005Numeric, I_OnRehash, I_OnModuleRehash, I_OnHookIO, I_OnUserConnect }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - ServerInstance->Modules->AddService(iohook); - } + session->status = ISSL_OPEN; - void OnHookIO(StreamSocket* user, ListenSocket* lsb) - { - if (!user->GetIOHook() && lsb->bind_tag->getString("ssl") == "openssl") + ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE); + + return true; + } + else if (ret == 0) { - /* Hook the user with our module */ - user->AddIOHook(this); + CloseSession(session); + return true; } + + return true; } - void OnRehash(User* user) + void CloseSession(issl_session* session) { - sslports.clear(); - - ConfigTag* Conf = ServerInstance->Config->ConfValue("openssl"); - - if (Conf->getBool("showports", true)) + if (session->sess) { - sslports = Conf->getString("advertisedports"); - if (!sslports.empty()) - return; - - for (size_t i = 0; i < ServerInstance->ports.size(); i++) - { - ListenSocket* port = ServerInstance->ports[i]; - if (port->bind_tag->getString("ssl") != "openssl") - continue; - - const std::string& portid = port->bind_desc; - ServerInstance->Logs->Log("m_ssl_openssl", DEFAULT, "m_ssl_openssl.so: Enabling SSL for port %s", portid.c_str()); - - if (port->bind_tag->getString("type", "clients") == "clients" && port->bind_addr != "127.0.0.1") - { - /* - * Found an SSL port for clients that is not bound to 127.0.0.1 and handled by us, display - * the IP:port in ISUPPORT. - * - * We used to advertise all ports seperated by a ';' char that matched the above criteria, - * but this resulted in too long ISUPPORT lines if there were lots of ports to be displayed. - * To solve this by default we now only display the first IP:port found and let the user - * configure the exact value for the 005 token, if necessary. - */ - sslports = portid; - break; - } - } + SSL_shutdown(session->sess); + SSL_free(session->sess); } + + session->sess = NULL; + session->status = ISSL_NONE; + errno = EIO; } - void OnModuleRehash(User* user, const std::string ¶m) + void VerifyCertificate(issl_session* session, StreamSocket* user) { - if (param != "ssl") + if (!session->sess || !user) return; - std::string keyfile; - std::string certfile; - std::string cafile; - std::string dhfile; - OnRehash(user); - - ConfigTag* conf = ServerInstance->Config->ConfValue("openssl"); - - cafile = conf->getString("cafile", CONFIG_PATH "/ca.pem"); - certfile = conf->getString("certfile", CONFIG_PATH "/cert.pem"); - keyfile = conf->getString("keyfile", CONFIG_PATH "/key.pem"); - dhfile = conf->getString("dhfile", CONFIG_PATH "/dhparams.pem"); - std::string hash = conf->getString("hash", "md5"); - if (hash != "sha1" && hash != "md5") - throw ModuleException("Unknown hash type " + hash); - use_sha = (hash == "sha1"); + X509* cert; + ssl_cert* certinfo = new ssl_cert; + session->cert = certinfo; + unsigned int n; + unsigned char md[EVP_MAX_MD_SIZE]; - std::string ciphers = conf->getString("ciphers", ""); + cert = SSL_get_peer_certificate((SSL*)session->sess); - if (!ciphers.empty()) + if (!cert) { - if ((!SSL_CTX_set_cipher_list(ctx, ciphers.c_str())) || (!SSL_CTX_set_cipher_list(clictx, ciphers.c_str()))) - { - ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't set cipher list to %s.", ciphers.c_str()); - ERR_print_errors_cb(error_callback, this); - } + certinfo->error = "Could not get peer certificate: "+std::string(get_error()); + return; } - /* Load our keys and certificates - * NOTE: OpenSSL's error logging API sucks, don't blame us for this clusterfuck. - */ - if ((!SSL_CTX_use_certificate_chain_file(ctx, certfile.c_str())) || (!SSL_CTX_use_certificate_chain_file(clictx, certfile.c_str()))) - { - ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't read certificate file %s. %s", certfile.c_str(), strerror(errno)); - ERR_print_errors_cb(error_callback, this); - } + certinfo->invalid = (SSL_get_verify_result(session->sess) != X509_V_OK); - if (((!SSL_CTX_use_PrivateKey_file(ctx, keyfile.c_str(), SSL_FILETYPE_PEM))) || (!SSL_CTX_use_PrivateKey_file(clictx, keyfile.c_str(), SSL_FILETYPE_PEM))) + if (!SelfSigned) { - ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't read key file %s. %s", keyfile.c_str(), strerror(errno)); - ERR_print_errors_cb(error_callback, this); + certinfo->unknownsigner = false; + certinfo->trusted = true; } - - /* Load the CAs we trust*/ - if (((!SSL_CTX_load_verify_locations(ctx, cafile.c_str(), 0))) || (!SSL_CTX_load_verify_locations(clictx, cafile.c_str(), 0))) + else { - ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't read CA list from %s. This is only a problem if you want to verify client certificates, otherwise it's safe to ignore this message. Error: %s", cafile.c_str(), strerror(errno)); - ERR_print_errors_cb(error_callback, this); + certinfo->unknownsigner = true; + certinfo->trusted = false; } - FILE* dhpfile = fopen(dhfile.c_str(), "r"); - DH* ret; + certinfo->dn = X509_NAME_oneline(X509_get_subject_name(cert),0,0); + certinfo->issuer = X509_NAME_oneline(X509_get_issuer_name(cert),0,0); - if (dhpfile == NULL) + if (!X509_digest(cert, digest, md, &n)) { - ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so Couldn't open DH file %s: %s", dhfile.c_str(), strerror(errno)); - throw ModuleException("Couldn't open DH file " + dhfile + ": " + strerror(errno)); + certinfo->error = "Out of memory generating fingerprint"; } else { - ret = PEM_read_DHparams(dhpfile, NULL, NULL, NULL); - if ((SSL_CTX_set_tmp_dh(ctx, ret) < 0) || (SSL_CTX_set_tmp_dh(clictx, ret) < 0)) - { - ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Couldn't set DH parameters %s. SSL errors follow:", dhfile.c_str()); - ERR_print_errors_cb(error_callback, this); - } + certinfo->fingerprint = BinToHex(md, n); } - fclose(dhpfile); - } - - void On005Numeric(std::string &output) - { - if (!sslports.empty()) - output.append(" SSL=" + sslports); - } - - ~ModuleSSLOpenSSL() - { - SSL_CTX_free(ctx); - SSL_CTX_free(clictx); - delete[] sessions; - } - - void OnUserConnect(LocalUser* user) - { - if (user->eh.GetIOHook() == this) + if ((ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(cert), ServerInstance->Time()) == -1) || (ASN1_UTCTIME_cmp_time_t(X509_get_notBefore(cert), ServerInstance->Time()) == 0)) { - if (sessions[user->eh.GetFd()].sess) - { - if (!sessions[user->eh.GetFd()].cert->fingerprint.empty()) - user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"" - " and your SSL fingerprint is %s", user->nick.c_str(), SSL_get_cipher(sessions[user->eh.GetFd()].sess), sessions[user->eh.GetFd()].cert->fingerprint.c_str()); - else - user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick.c_str(), SSL_get_cipher(sessions[user->eh.GetFd()].sess)); - } + certinfo->error = "Not activated, or expired certificate"; } - } - - void OnCleanup(int target_type, void* item) - { - if (target_type == TYPE_USER) - { - LocalUser* user = IS_LOCAL((User*)item); - if (user && user->eh.GetIOHook() == this) - { - // User is using SSL, they're a local user, and they're using one of *our* SSL ports. - // Potentially there could be multiple SSL modules loaded at once on different ports. - ServerInstance->Users->QuitUser(user, "SSL module unloading"); - } - } + X509_free(cert); } - Version GetVersion() + public: + issl_session* sessions; + SSL_CTX* ctx; + SSL_CTX* clictx; + const EVP_MD *digest; + + OpenSSLIOHook(Module* mod) + : SSLIOHook(mod, "ssl/openssl") { - return Version("Provides SSL support for clients", VF_VENDOR); + sessions = new issl_session[ServerInstance->SE->GetMaxFds()]; } - void OnRequest(Request& request) + ~OpenSSLIOHook() { - if (strcmp("GET_SSL_CERT", request.id) == 0) - { - SocketCertificateRequest& req = static_cast<SocketCertificateRequest&>(request); - int fd = req.sock->GetFd(); - issl_session* session = &sessions[fd]; - - req.cert = session->cert; - } + delete[] sessions; } - void OnStreamSocketAccept(StreamSocket* user, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) + void OnStreamSocketAccept(StreamSocket* user, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE { int fd = user->GetFd(); @@ -343,14 +248,14 @@ class ModuleSSLOpenSSL : public Module if (SSL_set_fd(session->sess, fd) == 0) { - ServerInstance->Logs->Log("m_ssl_openssl",DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Can't set fd with SSL_set_fd: %d", fd); return; } Handshake(user, session); } - void OnStreamSocketConnect(StreamSocket* user) + void OnStreamSocketConnect(StreamSocket* user) CXX11_OVERRIDE { int fd = user->GetFd(); /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */ @@ -368,14 +273,14 @@ class ModuleSSLOpenSSL : public Module if (SSL_set_fd(session->sess, fd) == 0) { - ServerInstance->Logs->Log("m_ssl_openssl",DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Can't set fd with SSL_set_fd: %d", fd); return; } Handshake(user, session); } - void OnStreamSocketClose(StreamSocket* user) + void OnStreamSocketClose(StreamSocket* user) CXX11_OVERRIDE { int fd = user->GetFd(); /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */ @@ -385,7 +290,7 @@ class ModuleSSLOpenSSL : public Module CloseSession(&sessions[fd]); } - int OnStreamSocketRead(StreamSocket* user, std::string& recvq) + int OnStreamSocketRead(StreamSocket* user, std::string& recvq) CXX11_OVERRIDE { int fd = user->GetFd(); /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */ @@ -459,7 +364,7 @@ class ModuleSSLOpenSSL : public Module return 0; } - int OnStreamSocketWrite(StreamSocket* user, std::string& buffer) + int OnStreamSocketWrite(StreamSocket* user, std::string& buffer) CXX11_OVERRIDE { int fd = user->GetFd(); @@ -528,128 +433,230 @@ class ModuleSSLOpenSSL : public Module return 0; } - bool Handshake(StreamSocket* user, issl_session* session) + ssl_cert* GetCertificate(StreamSocket* sock) CXX11_OVERRIDE { - int ret; - - if (session->outbound) - ret = SSL_connect(session->sess); - else - ret = SSL_accept(session->sess); + int fd = sock->GetFd(); + issl_session* session = &sessions[fd]; + return session->cert; + } - if (ret < 0) + void TellCiphersAndFingerprint(LocalUser* user) + { + issl_session& s = sessions[user->eh.GetFd()]; + if (s.sess) { - int err = SSL_get_error(session->sess, ret); - - if (err == SSL_ERROR_WANT_READ) - { - ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); - session->status = ISSL_HANDSHAKING; - return true; - } - else if (err == SSL_ERROR_WANT_WRITE) - { - ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE); - session->status = ISSL_HANDSHAKING; - return true; - } - else - { - CloseSession(session); - } + std::string text = "*** You are connected using SSL cipher '" + std::string(SSL_get_cipher(s.sess)) + "'"; + const std::string& fingerprint = s.cert->fingerprint; + if (!fingerprint.empty()) + text += " and your SSL fingerprint is " + fingerprint; - return false; + user->WriteNotice(text); } - else if (ret > 0) - { - // Handshake complete. - VerifyCertificate(session, user); + } +}; - session->status = ISSL_OPEN; +class ModuleSSLOpenSSL : public Module +{ + std::string sslports; + OpenSSLIOHook iohook; - ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE); + public: + ModuleSSLOpenSSL() : iohook(this) + { + /* Global SSL library initialization*/ + SSL_library_init(); + SSL_load_error_strings(); - return true; - } - else if (ret == 0) - { - CloseSession(session); - return true; - } + /* Build our SSL contexts: + * NOTE: OpenSSL makes us have two contexts, one for servers and one for clients. ICK. + */ + iohook.ctx = SSL_CTX_new( SSLv23_server_method() ); + iohook.clictx = SSL_CTX_new( SSLv23_client_method() ); - return true; + SSL_CTX_set_mode(iohook.ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_set_mode(iohook.clictx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + + SSL_CTX_set_verify(iohook.ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify); + SSL_CTX_set_verify(iohook.clictx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify); } - void CloseSession(issl_session* session) + ~ModuleSSLOpenSSL() { - if (session->sess) + SSL_CTX_free(iohook.ctx); + SSL_CTX_free(iohook.clictx); + } + + void init() CXX11_OVERRIDE + { + // Needs the flag as it ignores a plain /rehash + OnModuleRehash(NULL,"ssl"); + ServerInstance->Modules->AddService(iohook); + } + + void OnHookIO(StreamSocket* user, ListenSocket* lsb) CXX11_OVERRIDE + { + if (!user->GetIOHook() && lsb->bind_tag->getString("ssl") == "openssl") { - SSL_shutdown(session->sess); - SSL_free(session->sess); + /* Hook the user with our module */ + user->AddIOHook(&iohook); } + } - session->sess = NULL; - session->status = ISSL_NONE; - errno = EIO; + void OnRehash(User* user) CXX11_OVERRIDE + { + sslports.clear(); + + ConfigTag* Conf = ServerInstance->Config->ConfValue("openssl"); + + if (Conf->getBool("showports", true)) + { + sslports = Conf->getString("advertisedports"); + if (!sslports.empty()) + return; + + for (size_t i = 0; i < ServerInstance->ports.size(); i++) + { + ListenSocket* port = ServerInstance->ports[i]; + if (port->bind_tag->getString("ssl") != "openssl") + continue; + + const std::string& portid = port->bind_desc; + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Enabling SSL for port %s", portid.c_str()); + + if (port->bind_tag->getString("type", "clients") == "clients" && port->bind_addr != "127.0.0.1") + { + /* + * Found an SSL port for clients that is not bound to 127.0.0.1 and handled by us, display + * the IP:port in ISUPPORT. + * + * We used to advertise all ports seperated by a ';' char that matched the above criteria, + * but this resulted in too long ISUPPORT lines if there were lots of ports to be displayed. + * To solve this by default we now only display the first IP:port found and let the user + * configure the exact value for the 005 token, if necessary. + */ + sslports = portid; + break; + } + } + } } - void VerifyCertificate(issl_session* session, StreamSocket* user) + void OnModuleRehash(User* user, const std::string ¶m) CXX11_OVERRIDE { - if (!session->sess || !user) + if (param != "ssl") return; - X509* cert; - ssl_cert* certinfo = new ssl_cert; - session->cert = certinfo; - unsigned int n; - unsigned char md[EVP_MAX_MD_SIZE]; - const EVP_MD *digest = use_sha ? EVP_sha1() : EVP_md5(); + std::string keyfile; + std::string certfile; + std::string cafile; + std::string dhfile; + OnRehash(user); - cert = SSL_get_peer_certificate((SSL*)session->sess); + ConfigTag* conf = ServerInstance->Config->ConfValue("openssl"); - if (!cert) + cafile = ServerInstance->Config->Paths.PrependConfig(conf->getString("cafile", "ca.pem")); + certfile = ServerInstance->Config->Paths.PrependConfig(conf->getString("certfile", "cert.pem")); + keyfile = ServerInstance->Config->Paths.PrependConfig(conf->getString("keyfile", "key.pem")); + dhfile = ServerInstance->Config->Paths.PrependConfig(conf->getString("dhfile", "dhparams.pem")); + std::string hash = conf->getString("hash", "md5"); + + iohook.digest = EVP_get_digestbyname(hash.c_str()); + if (iohook.digest == NULL) + throw ModuleException("Unknown hash type " + hash); + + std::string ciphers = conf->getString("ciphers", ""); + + SSL_CTX* ctx = iohook.ctx; + SSL_CTX* clictx = iohook.clictx; + + if (!ciphers.empty()) { - certinfo->error = "Could not get peer certificate: "+std::string(get_error()); - return; + if ((!SSL_CTX_set_cipher_list(ctx, ciphers.c_str())) || (!SSL_CTX_set_cipher_list(clictx, ciphers.c_str()))) + { + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Can't set cipher list to %s.", ciphers.c_str()); + ERR_print_errors_cb(error_callback, this); + } } - certinfo->invalid = (SSL_get_verify_result(session->sess) != X509_V_OK); + /* Load our keys and certificates + * NOTE: OpenSSL's error logging API sucks, don't blame us for this clusterfuck. + */ + if ((!SSL_CTX_use_certificate_chain_file(ctx, certfile.c_str())) || (!SSL_CTX_use_certificate_chain_file(clictx, certfile.c_str()))) + { + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Can't read certificate file %s. %s", certfile.c_str(), strerror(errno)); + ERR_print_errors_cb(error_callback, this); + } - if (!SelfSigned) + if (((!SSL_CTX_use_PrivateKey_file(ctx, keyfile.c_str(), SSL_FILETYPE_PEM))) || (!SSL_CTX_use_PrivateKey_file(clictx, keyfile.c_str(), SSL_FILETYPE_PEM))) { - certinfo->unknownsigner = false; - certinfo->trusted = true; + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Can't read key file %s. %s", keyfile.c_str(), strerror(errno)); + ERR_print_errors_cb(error_callback, this); } - else + + /* Load the CAs we trust*/ + if (((!SSL_CTX_load_verify_locations(ctx, cafile.c_str(), 0))) || (!SSL_CTX_load_verify_locations(clictx, cafile.c_str(), 0))) { - certinfo->unknownsigner = true; - certinfo->trusted = false; + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Can't read CA list from %s. This is only a problem if you want to verify client certificates, otherwise it's safe to ignore this message. Error: %s", cafile.c_str(), strerror(errno)); + ERR_print_errors_cb(error_callback, this); } - certinfo->dn = X509_NAME_oneline(X509_get_subject_name(cert),0,0); - certinfo->issuer = X509_NAME_oneline(X509_get_issuer_name(cert),0,0); + FILE* dhpfile = fopen(dhfile.c_str(), "r"); + DH* ret; - if (!X509_digest(cert, digest, md, &n)) + if (dhpfile == NULL) { - certinfo->error = "Out of memory generating fingerprint"; + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Couldn't open DH file %s: %s", dhfile.c_str(), strerror(errno)); + throw ModuleException("Couldn't open DH file " + dhfile + ": " + strerror(errno)); } else { - certinfo->fingerprint = irc::hex(md, n); + ret = PEM_read_DHparams(dhpfile, NULL, NULL, NULL); + if ((SSL_CTX_set_tmp_dh(ctx, ret) < 0) || (SSL_CTX_set_tmp_dh(clictx, ret) < 0)) + { + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Couldn't set DH parameters %s. SSL errors follow:", dhfile.c_str()); + ERR_print_errors_cb(error_callback, this); + } } - if ((ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(cert), ServerInstance->Time()) == -1) || (ASN1_UTCTIME_cmp_time_t(X509_get_notBefore(cert), ServerInstance->Time()) == 0)) + fclose(dhpfile); + } + + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE + { + if (!sslports.empty()) + tokens["SSL"] = sslports; + } + + void OnUserConnect(LocalUser* user) CXX11_OVERRIDE + { + if (user->eh.GetIOHook() == &iohook) + iohook.TellCiphersAndFingerprint(user); + } + + void OnCleanup(int target_type, void* item) CXX11_OVERRIDE + { + if (target_type == TYPE_USER) { - certinfo->error = "Not activated, or expired certificate"; + LocalUser* user = IS_LOCAL((User*)item); + + if (user && user->eh.GetIOHook() == &iohook) + { + // User is using SSL, they're a local user, and they're using one of *our* SSL ports. + // Potentially there could be multiple SSL modules loaded at once on different ports. + ServerInstance->Users->QuitUser(user, "SSL module unloading"); + } } + } - X509_free(cert); + Version GetVersion() CXX11_OVERRIDE + { + return Version("Provides SSL support for clients", VF_VENDOR); } }; static int error_callback(const char *str, size_t len, void *u) { - ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "SSL error: " + std::string(str, len - 1)); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "SSL error: " + std::string(str, len - 1)); // // XXX: Remove this line, it causes valgrind warnings... diff --git a/src/modules/m_abbreviation.cpp b/src/modules/m_abbreviation.cpp index a744f55f6..32878614d 100644 --- a/src/modules/m_abbreviation.cpp +++ b/src/modules/m_abbreviation.cpp @@ -19,27 +19,20 @@ #include "inspircd.h" -/* $ModDesc: Provides the ability to abbreviate commands a-la BBC BASIC keywords. */ - class ModuleAbbreviation : public Module { public: - void init() - { - ServerInstance->Modules->Attach(I_OnPreCommand, this); - } - void Prioritize() { ServerInstance->Modules->SetPriority(this, I_OnPreCommand, PRIORITY_FIRST); } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides the ability to abbreviate commands a-la BBC BASIC keywords.",VF_VENDOR); } - virtual ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) + ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE { /* Command is already validated, has a length of 0, or last character is not a . */ if (validated || command.empty() || *command.rbegin() != '.') diff --git a/src/modules/m_alias.cpp b/src/modules/m_alias.cpp index 25f071bab..4d942854c 100644 --- a/src/modules/m_alias.cpp +++ b/src/modules/m_alias.cpp @@ -22,8 +22,6 @@ #include "inspircd.h" -/* $ModDesc: Provides aliases of commands. */ - /** An alias definition */ class Alias @@ -59,20 +57,19 @@ class Alias class ModuleAlias : public Module { - private: - char fprefix; /* We cant use a map, there may be multiple aliases with the same name. * We can, however, use a fancy invention: the multimap. Maps a key to one or more values. * -- w00t - */ + */ std::multimap<irc::string, Alias> Aliases; /* whether or not +B users are allowed to use fantasy commands */ bool AllowBots; + UserModeReference botmode; - virtual void ReadAliases() + void ReadAliases() { ConfigTag* fantasy = ServerInstance->Config->ConfValue("fantasy"); AllowBots = fantasy->getBool("allowbots", false); @@ -100,19 +97,17 @@ class ModuleAlias : public Module } public: - - void init() + ModuleAlias() + : botmode(this, "bot") { - ReadAliases(); - Implementation eventlist[] = { I_OnPreCommand, I_OnRehash, I_OnUserMessage }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual ~ModuleAlias() + void init() CXX11_OVERRIDE { + ReadAliases(); } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides aliases of commands.", VF_VENDOR); } @@ -142,7 +137,7 @@ class ModuleAlias : public Module return word; } - virtual ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) + ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE { std::multimap<irc::string, Alias>::iterator i, upperbound; @@ -182,9 +177,9 @@ class ModuleAlias : public Module return MOD_RES_PASSTHRU; } - virtual void OnUserMessage(User *user, void *dest, int target_type, const std::string &text, char status, const CUList &exempt_list) + void OnUserMessage(User *user, void *dest, int target_type, const std::string &text, char status, const CUList &exempt_list, MessageType msgtype) CXX11_OVERRIDE { - if (target_type != TYPE_CHANNEL) + if ((target_type != TYPE_CHANNEL) || (msgtype != MSG_PRIVMSG)) { return; } @@ -196,7 +191,7 @@ class ModuleAlias : public Module } /* Stop here if the user is +B and allowbot is set to no. */ - if (!AllowBots && user->IsModeSet('B')) + if (!AllowBots && user->IsModeSet(botmode)) { return; } @@ -270,7 +265,7 @@ class ModuleAlias : public Module } } - if ((a->OperOnly) && (!IS_OPER(user))) + if ((a->OperOnly) && (!user->IsOper())) return 0; if (!a->RequiredNick.empty()) @@ -316,7 +311,7 @@ class ModuleAlias : public Module void DoCommand(const std::string& newline, User* user, Channel *chan, const std::string &original_line) { std::string result; - result.reserve(MAXBUF); + result.reserve(newline.length()); for (unsigned int i = 0; i < newline.length(); i++) { char c = newline[i]; @@ -367,19 +362,19 @@ class ModuleAlias : public Module std::string command, token; ss.GetToken(command); - while (ss.GetToken(token) && (pars.size() <= MAXPARAMETERS)) + while (ss.GetToken(token)) { pars.push_back(token); } ServerInstance->Parser->CallHandler(command, pars, user); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ReadAliases(); } - virtual void Prioritize() + void Prioritize() { // Prioritise after spanningtree so that channel aliases show the alias before the effects. Module* linkmod = ServerInstance->Modules->Find("m_spanningtree.so"); diff --git a/src/modules/m_allowinvite.cpp b/src/modules/m_allowinvite.cpp index 08a5f542a..a33bee832 100644 --- a/src/modules/m_allowinvite.cpp +++ b/src/modules/m_allowinvite.cpp @@ -19,8 +19,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for channel mode +A, allowing /invite freely on a channel and extban A to deny specific users it */ - class AllowInvite : public SimpleChannelModeHandler { public: @@ -36,19 +34,17 @@ class ModuleAllowInvite : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(ni); - Implementation eventlist[] = { I_OnUserPreInvite, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - ServerInstance->AddExtBanChar('A'); + tokens["EXTBAN"].push_back('A'); } - virtual ModResult OnUserPreInvite(User* user,User* dest,Channel* channel, time_t timeout) + ModResult OnUserPreInvite(User* user,User* dest,Channel* channel, time_t timeout) CXX11_OVERRIDE { if (IS_LOCAL(user)) { @@ -59,7 +55,7 @@ class ModuleAllowInvite : public Module user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You are banned from using INVITE", user->nick.c_str(), channel->name.c_str()); return res; } - if (channel->IsModeSet('A') || res == MOD_RES_ALLOW) + if (channel->IsModeSet(ni) || res == MOD_RES_ALLOW) { // Explicitly allow /invite return MOD_RES_ALLOW; @@ -69,11 +65,7 @@ class ModuleAllowInvite : public Module return MOD_RES_PASSTHRU; } - virtual ~ModuleAllowInvite() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for channel mode +A, allowing /invite freely on a channel and extban A to deny specific users it",VF_VENDOR); } diff --git a/src/modules/m_alltime.cpp b/src/modules/m_alltime.cpp index 38ae4b254..dac3a4c8e 100644 --- a/src/modules/m_alltime.cpp +++ b/src/modules/m_alltime.cpp @@ -21,15 +21,12 @@ #include "inspircd.h" -/* $ModDesc: Display timestamps from all servers connected to the network */ - class CommandAlltime : public Command { public: CommandAlltime(Module* Creator) : Command(Creator, "ALLTIME", 0) { flags_needed = 'o'; - translation.push_back(TR_END); } CmdResult Handle(const std::vector<std::string> ¶meters, User *user) @@ -52,7 +49,6 @@ class CommandAlltime : public Command } }; - class Modulealltime : public Module { CommandAlltime mycommand; @@ -62,16 +58,12 @@ class Modulealltime : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(mycommand); } - virtual ~Modulealltime() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Display timestamps from all servers connected to the network", VF_OPTCOMMON | VF_VENDOR); } diff --git a/src/modules/m_auditorium.cpp b/src/modules/m_auditorium.cpp index c3e31c583..af828c130 100644 --- a/src/modules/m_auditorium.cpp +++ b/src/modules/m_auditorium.cpp @@ -22,8 +22,6 @@ #include "inspircd.h" -/* $ModDesc: Allows for auditorium channels (+u) where nobody can see others joining and parting or the nick list */ - class AuditoriumMode : public ModeHandler { public: @@ -43,34 +41,24 @@ class AuditoriumMode : public ModeHandler class ModuleAuditorium : public Module { - private: AuditoriumMode aum; bool OpsVisible; bool OpsCanSee; bool OperCanSee; + public: ModuleAuditorium() : aum(this) { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(aum); OnRehash(NULL); - - Implementation eventlist[] = { - I_OnUserJoin, I_OnUserPart, I_OnUserKick, - I_OnBuildNeighborList, I_OnNamesListItem, I_OnSendWhoLine, - I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - ~ModuleAuditorium() - { } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("auditorium"); OpsVisible = tag->getBool("opvisible"); @@ -78,7 +66,7 @@ class ModuleAuditorium : public Module OperCanSee = tag->getBool("opercansee", true); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Allows for auditorium channels (+u) where nobody can see others joining and parting or the nick list", VF_VENDOR); } @@ -112,7 +100,7 @@ class ModuleAuditorium : public Module return false; } - void OnNamesListItem(User* issuer, Membership* memb, std::string &prefixes, std::string &nick) + void OnNamesListItem(User* issuer, Membership* memb, std::string &prefixes, std::string &nick) CXX11_OVERRIDE { // Some module already hid this from being displayed, don't bother if (nick.empty()) @@ -141,22 +129,22 @@ class ModuleAuditorium : public Module } } - void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) + void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) CXX11_OVERRIDE { BuildExcept(memb, excepts); } - void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts) + void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts) CXX11_OVERRIDE { BuildExcept(memb, excepts); } - void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) + void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) CXX11_OVERRIDE { BuildExcept(memb, excepts); } - void OnBuildNeighborList(User* source, UserChanList &include, std::map<User*,bool> &exception) + void OnBuildNeighborList(User* source, UserChanList &include, std::map<User*,bool> &exception) CXX11_OVERRIDE { UCListIter i = include.begin(); while (i != include.end()) @@ -177,7 +165,7 @@ class ModuleAuditorium : public Module } } - void OnSendWhoLine(User* source, const std::vector<std::string>& params, User* user, std::string& line) + void OnSendWhoLine(User* source, const std::vector<std::string>& params, User* user, std::string& line) CXX11_OVERRIDE { Channel* channel = ServerInstance->FindChan(params[0]); if (!channel) diff --git a/src/modules/m_autoop.cpp b/src/modules/m_autoop.cpp index 07dca6929..6bc5f464c 100644 --- a/src/modules/m_autoop.cpp +++ b/src/modules/m_autoop.cpp @@ -19,9 +19,7 @@ #include "inspircd.h" -#include "u_listmode.h" - -/* $ModDesc: Provides support for the +w channel mode, autoop list */ +#include "listmode.h" /** Handles +w channel mode */ @@ -82,32 +80,29 @@ class ModuleAutoOp : public Module { AutoOpList mh; -public: + public: ModuleAutoOp() : mh(this) { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(mh); mh.DoImplements(this); - - Implementation list[] = { I_OnPostJoin, }; - ServerInstance->Modules->Attach(list, this, sizeof(list)/sizeof(Implementation)); } - void OnPostJoin(Membership *memb) + void OnPostJoin(Membership *memb) CXX11_OVERRIDE { if (!IS_LOCAL(memb->user)) return; - modelist* list = mh.extItem.get(memb->chan); + ListModeBase::ModeList* list = mh.GetList(memb->chan); if (list) { std::string modeline("+"); std::vector<std::string> modechange; modechange.push_back(memb->chan->name); - for (modelist::iterator it = list->begin(); it != list->end(); it++) + for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++) { std::string::size_type colon = it->mask.find(':'); if (colon == std::string::npos) @@ -123,21 +118,21 @@ public: for(std::string::size_type i = modeline.length(); i > 1; --i) // we use "i > 1" instead of "i" so we skip the + modechange.push_back(memb->user->nick); if(modechange.size() >= 3) - ServerInstance->SendGlobalMode(modechange, ServerInstance->FakeClient); + ServerInstance->Modes->Process(modechange, ServerInstance->FakeClient); } } - void OnSyncChannel(Channel* chan, Module* proto, void* opaque) + void OnSyncChannel(Channel* chan, Module* proto, void* opaque) CXX11_OVERRIDE { mh.DoSyncChannel(chan, proto, opaque); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { mh.DoRehash(); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for the +w channel mode", VF_VENDOR); } diff --git a/src/modules/m_banexception.cpp b/src/modules/m_banexception.cpp index 1811f743d..e142af0de 100644 --- a/src/modules/m_banexception.cpp +++ b/src/modules/m_banexception.cpp @@ -22,10 +22,7 @@ #include "inspircd.h" -#include "u_listmode.h" - -/* $ModDesc: Provides support for the +e channel mode */ -/* $ModDep: ../../include/u_listmode.h */ +#include "listmode.h" /* Written by Om<om@inspircd.org>, April 2005. */ /* Rewritten to use the listmode utility by Om, December 2005 */ @@ -49,35 +46,33 @@ class ModuleBanException : public Module { BanException be; -public: + public: ModuleBanException() : be(this) { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(be); be.DoImplements(this); - Implementation list[] = { I_OnRehash, I_On005Numeric, I_OnExtBanCheck, I_OnCheckChannelBan }; - ServerInstance->Modules->Attach(list, this, sizeof(list)/sizeof(Implementation)); } - void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - output.append(" EXCEPTS=e"); + tokens["EXCEPTS"] = "e"; } - ModResult OnExtBanCheck(User *user, Channel *chan, char type) + ModResult OnExtBanCheck(User *user, Channel *chan, char type) CXX11_OVERRIDE { if (chan != NULL) { - modelist *list = be.extItem.get(chan); + ListModeBase::ModeList *list = be.GetList(chan); if (!list) return MOD_RES_PASSTHRU; - for (modelist::iterator it = list->begin(); it != list->end(); it++) + for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++) { if (it->mask[0] != type || it->mask[1] != ':') continue; @@ -93,11 +88,11 @@ public: return MOD_RES_PASSTHRU; } - ModResult OnCheckChannelBan(User* user, Channel* chan) + ModResult OnCheckChannelBan(User* user, Channel* chan) CXX11_OVERRIDE { if (chan) { - modelist *list = be.extItem.get(chan); + ListModeBase::ModeList *list = be.GetList(chan); if (!list) { @@ -105,7 +100,7 @@ public: return MOD_RES_PASSTHRU; } - for (modelist::iterator it = list->begin(); it != list->end(); it++) + for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++) { if (chan->CheckBan(user, it->mask)) { @@ -117,17 +112,17 @@ public: return MOD_RES_PASSTHRU; } - void OnSyncChannel(Channel* chan, Module* proto, void* opaque) + void OnSyncChannel(Channel* chan, Module* proto, void* opaque) CXX11_OVERRIDE { be.DoSyncChannel(chan, proto, opaque); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { be.DoRehash(); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for the +e channel mode", VF_VENDOR); } diff --git a/src/modules/m_banredirect.cpp b/src/modules/m_banredirect.cpp index ee52a5cfb..73d8270d1 100644 --- a/src/modules/m_banredirect.cpp +++ b/src/modules/m_banredirect.cpp @@ -23,9 +23,7 @@ #include "inspircd.h" -#include "u_listmode.h" - -/* $ModDesc: Allows an extended ban (+b) syntax redirecting banned users to another channel */ +#include "listmode.h" /* Originally written by Om, January 2009 */ @@ -43,18 +41,20 @@ class BanRedirectEntry }; typedef std::vector<BanRedirectEntry> BanRedirectList; -typedef std::deque<std::string> StringDeque; class BanRedirect : public ModeWatcher { + ChanModeReference ban; public: SimpleExtItem<BanRedirectList> extItem; - BanRedirect(Module* parent) : ModeWatcher(parent, 'b', MODETYPE_CHANNEL), - extItem("banredirect", parent) + BanRedirect(Module* parent) + : ModeWatcher(parent, "ban", MODETYPE_CHANNEL) + , ban(parent, "ban") + , extItem("banredirect", parent) { } - bool BeforeMode(User* source, User* dest, Channel* channel, std::string ¶m, bool adding, ModeType type) + bool BeforeMode(User* source, User* dest, Channel* channel, std::string ¶m, bool adding) { /* nick!ident@host -> nick!ident@host * nick!ident@host#chan -> nick!ident@host#chan @@ -63,21 +63,23 @@ class BanRedirect : public ModeWatcher * nick#chan -> nick!*@*#chan */ - if(channel && (type == MODETYPE_CHANNEL) && param.length()) + if ((channel) && !param.empty()) { BanRedirectList* redirects; std::string mask[4]; enum { NICK, IDENT, HOST, CHAN } current = NICK; std::string::iterator start_pos = param.begin(); - long maxbans = channel->GetMaxBans(); if (param.length() >= 2 && param[1] == ':') return true; - if(adding && (channel->bans.size() > static_cast<unsigned>(maxbans))) + ListModeBase* banlm = static_cast<ListModeBase*>(*ban); + unsigned int maxbans = banlm->GetLimit(channel); + ListModeBase::ModeList* list = banlm->GetList(channel); + if ((list) && (adding) && (maxbans <= list->size())) { - source->WriteNumeric(478, "%s %s :Channel ban list for %s is full (maximum entries for this channel is %ld)", source->nick.c_str(), channel->name.c_str(), channel->name.c_str(), maxbans); + source->WriteNumeric(478, "%s %s :Channel ban list for %s is full (maximum entries for this channel is %u)", source->nick.c_str(), channel->name.c_str(), channel->name.c_str(), maxbans); return false; } @@ -86,23 +88,25 @@ class BanRedirect : public ModeWatcher switch(*curr) { case '!': + if (current != NICK) + break; mask[current].assign(start_pos, curr); current = IDENT; start_pos = curr+1; break; case '@': + if (current != IDENT) + break; mask[current].assign(start_pos, curr); current = HOST; start_pos = curr+1; break; case '#': - /* bug #921: don't barf when redirecting to ## channels */ - if (current != CHAN) - { - mask[current].assign(start_pos, curr); - current = CHAN; - start_pos = curr; - } + if (current == CHAN) + break; + mask[current].assign(start_pos, curr); + current = CHAN; + start_pos = curr; break; } } @@ -133,7 +137,7 @@ class BanRedirect : public ModeWatcher { if (adding && IS_LOCAL(source)) { - if (!ServerInstance->IsChannel(mask[CHAN].c_str(), ServerInstance->Config->Limits.ChanMax)) + if (!ServerInstance->IsChannel(mask[CHAN])) { source->WriteNumeric(403, "%s %s :Invalid channel name in redirection (%s)", source->nick.c_str(), channel->name.c_str(), mask[CHAN].c_str()); return false; @@ -213,26 +217,25 @@ class ModuleBanRedirect : public Module { BanRedirect re; bool nofollow; + ChanModeReference limitmode; + ChanModeReference redirectmode; public: ModuleBanRedirect() - : re(this) + : re(this) + , nofollow(false) + , limitmode(this, "limit") + , redirectmode(this, "redirect") { - nofollow = false; } - - void init() + void init() CXX11_OVERRIDE { - if(!ServerInstance->Modes->AddModeWatcher(&re)) - throw ModuleException("Could not add mode watcher"); - + ServerInstance->Modes->AddModeWatcher(&re); ServerInstance->Modules->AddService(re.extItem); - Implementation list[] = { I_OnUserPreJoin }; - ServerInstance->Modules->Attach(list, this, sizeof(list)/sizeof(Implementation)); } - virtual void OnCleanup(int target_type, void* item) + void OnCleanup(int target_type, void* item) CXX11_OVERRIDE { if(target_type == TYPE_CHANNEL) { @@ -242,9 +245,6 @@ class ModuleBanRedirect : public Module if(redirects) { irc::modestacker modestack(false); - StringDeque stackresult; - std::vector<std::string> mode_junk; - mode_junk.push_back(chan->name); for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++) { @@ -257,17 +257,18 @@ class ModuleBanRedirect : public Module modestack.Push('b', i->banmask); } - while(modestack.GetStackedLine(stackresult)) + std::vector<std::string> stackresult; + stackresult.push_back(chan->name); + while (modestack.GetStackedLine(stackresult)) { - mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end()); - ServerInstance->SendMode(mode_junk, ServerInstance->FakeClient); - mode_junk.erase(mode_junk.begin() + 1, mode_junk.end()); + ServerInstance->Modes->Process(stackresult, ServerInstance->FakeClient, ModeParser::MODE_LOCALONLY); + stackresult.erase(stackresult.begin() + 1, stackresult.end()); } } } } - virtual ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven) + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { if (chan) { @@ -311,9 +312,9 @@ class ModuleBanRedirect : public Module std::string destlimit; if (destchan) - destlimit = destchan->GetModeParameter('l'); + destlimit = destchan->GetModeParameter(limitmode); - if(destchan && ServerInstance->Modules->Find("m_redirect.so") && destchan->IsModeSet('L') && !destlimit.empty() && (destchan->GetUserCounter() >= atoi(destlimit.c_str()))) + if(destchan && destchan->IsModeSet(redirectmode) && !destlimit.empty() && (destchan->GetUserCounter() >= atoi(destlimit.c_str()))) { user->WriteNumeric(474, "%s %s :Cannot join channel (You are banned)", user->nick.c_str(), chan->name.c_str()); return MOD_RES_DENY; @@ -323,7 +324,7 @@ class ModuleBanRedirect : public Module user->WriteNumeric(474, "%s %s :Cannot join channel (You are banned)", user->nick.c_str(), chan->name.c_str()); user->WriteNumeric(470, "%s %s %s :You are banned from this channel, so you are automatically transfered to the redirected channel.", user->nick.c_str(), chan->name.c_str(), redir->targetchan.c_str()); nofollow = true; - Channel::JoinUser(user, redir->targetchan.c_str(), false, "", false, ServerInstance->Time()); + Channel::JoinUser(user, redir->targetchan); nofollow = false; return MOD_RES_DENY; } @@ -334,14 +335,14 @@ class ModuleBanRedirect : public Module return MOD_RES_PASSTHRU; } - virtual ~ModuleBanRedirect() + ~ModuleBanRedirect() { /* XXX is this the best place to do this? */ if (!ServerInstance->Modes->DelModeWatcher(&re)) - ServerInstance->Logs->Log("m_banredirect.so", DEBUG, "Failed to delete modewatcher!"); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Failed to delete modewatcher!"); } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Allows an extended ban (+b) syntax redirecting banned users to another channel", VF_COMMON|VF_VENDOR); } diff --git a/src/modules/m_blockamsg.cpp b/src/modules/m_blockamsg.cpp index be861447f..b71247d71 100644 --- a/src/modules/m_blockamsg.cpp +++ b/src/modules/m_blockamsg.cpp @@ -23,8 +23,6 @@ #include "inspircd.h" -/* $ModDesc: Attempt to block /amsg, at least some of the irritating mIRC scripts. */ - enum BlockAction { IBLOCK_KILL, IBLOCK_KILLOPERS, IBLOCK_NOTICE, IBLOCK_NOTICEOPERS, IBLOCK_SILENT }; /* IBLOCK_NOTICE - Send a notice to the user informing them of what happened. * IBLOCK_NOTICEOPERS - Send a notice to the user informing them and send an oper notice. @@ -37,7 +35,7 @@ enum BlockAction { IBLOCK_KILL, IBLOCK_KILLOPERS, IBLOCK_NOTICE, IBLOCK_NOTICEOP */ class BlockedMessage { -public: + public: std::string message; irc::string target; time_t sent; @@ -59,24 +57,18 @@ class ModuleBlockAmsg : public Module { } - void init() + void init() CXX11_OVERRIDE { this->OnRehash(NULL); ServerInstance->Modules->AddService(blockamsg); - Implementation eventlist[] = { I_OnRehash, I_OnPreCommand }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - virtual ~ModuleBlockAmsg() - { } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Attempt to block /amsg, at least some of the irritating mIRC scripts.",VF_VENDOR); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("blockamsg"); ForgetDelay = tag->getInt("delay", -1); @@ -94,7 +86,7 @@ class ModuleBlockAmsg : public Module action = IBLOCK_KILLOPERS; } - virtual ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) + ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE { // Don't do anything with unregistered users if (user->registered != REG_ALL) @@ -169,5 +161,4 @@ class ModuleBlockAmsg : public Module } }; - MODULE_INIT(ModuleBlockAmsg) diff --git a/src/modules/m_blockcaps.cpp b/src/modules/m_blockcaps.cpp index 200693699..f80c6d16d 100644 --- a/src/modules/m_blockcaps.cpp +++ b/src/modules/m_blockcaps.cpp @@ -22,8 +22,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support to block all-CAPS channel messages and notices */ - /** Handles the +B channel mode */ @@ -39,31 +37,29 @@ class ModuleBlockCAPS : public Module int percent; unsigned int minlen; char capsmap[256]; -public: +public: ModuleBlockCAPS() : bc(this) { } - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); ServerInstance->Modules->AddService(bc); - Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_OnRehash, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - ServerInstance->AddExtBanChar('B'); + tokens["EXTBAN"].push_back('B'); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ReadConf(); } - virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { if (target_type == TYPE_CHANNEL) { @@ -76,7 +72,7 @@ public: if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; - if (!c->GetExtBanStatus(user, 'B').check(!c->IsModeSet('B'))) + if (!c->GetExtBanStatus(user, 'B').check(!c->IsModeSet(bc))) { int caps = 0; const char* actstr = "\1ACTION "; @@ -105,37 +101,18 @@ public: return MOD_RES_PASSTHRU; } - virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreMessage(user,dest,target_type,text,status,exempt_list); - } - void ReadConf() { ConfigTag* tag = ServerInstance->Config->ConfValue("blockcaps"); - percent = tag->getInt("percent", 100); - minlen = tag->getInt("minlen", 1); + percent = tag->getInt("percent", 100, 1, 100); + minlen = tag->getInt("minlen", 1, 1, ServerInstance->Config->Limits.MaxLine); std::string hmap = tag->getString("capsmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); memset(capsmap, 0, sizeof(capsmap)); for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++) capsmap[(unsigned char)*n] = 1; - if (percent < 1 || percent > 100) - { - ServerInstance->Logs->Log("CONFIG",DEFAULT, "<blockcaps:percent> out of range, setting to default of 100."); - percent = 100; - } - if (minlen < 1 || minlen > MAXBUF-1) - { - ServerInstance->Logs->Log("CONFIG",DEFAULT, "<blockcaps:minlen> out of range, setting to default of 1."); - minlen = 1; - } - } - - virtual ~ModuleBlockCAPS() - { } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support to block all-CAPS channel messages and notices", VF_VENDOR); } diff --git a/src/modules/m_blockcolor.cpp b/src/modules/m_blockcolor.cpp index 3cc01b4c0..6e04e53da 100644 --- a/src/modules/m_blockcolor.cpp +++ b/src/modules/m_blockcolor.cpp @@ -23,8 +23,6 @@ #include "inspircd.h" -/* $ModDesc: Provides channel mode +c to block color */ - /** Handles the +c channel mode */ class BlockColor : public SimpleChannelModeHandler @@ -42,19 +40,17 @@ class ModuleBlockColor : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(bc); - Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - ServerInstance->AddExtBanChar('c'); + tokens["EXTBAN"].push_back('c'); } - virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user))) { @@ -64,7 +60,7 @@ class ModuleBlockColor : public Module if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; - if (!c->GetExtBanStatus(user, 'c').check(!c->IsModeSet('c'))) + if (!c->GetExtBanStatus(user, 'c').check(!c->IsModeSet(bc))) { for (std::string::iterator i = text.begin(); i != text.end(); i++) { @@ -86,16 +82,7 @@ class ModuleBlockColor : public Module return MOD_RES_PASSTHRU; } - virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreMessage(user,dest,target_type,text,status,exempt_list); - } - - virtual ~ModuleBlockColor() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +c to block color",VF_VENDOR); } diff --git a/src/modules/m_botmode.cpp b/src/modules/m_botmode.cpp index b29c58240..7c2794789 100644 --- a/src/modules/m_botmode.cpp +++ b/src/modules/m_botmode.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides user mode +B to mark the user as a bot */ - /** Handles user mode +B */ class BotMode : public SimpleUserModeHandler @@ -40,31 +38,23 @@ class ModuleBotMode : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(bm); - Implementation eventlist[] = { I_OnWhois }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - virtual ~ModuleBotMode() - { } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides user mode +B to mark the user as a bot",VF_VENDOR); } - virtual void OnWhois(User* src, User* dst) + void OnWhois(User* src, User* dst) CXX11_OVERRIDE { - if (dst->IsModeSet('B')) + if (dst->IsModeSet(bm)) { ServerInstance->SendWhoisLine(src, dst, 335, src->nick+" "+dst->nick+" :is a bot on "+ServerInstance->Config->Network); } } - }; - MODULE_INIT(ModuleBotMode) diff --git a/src/modules/m_callerid.cpp b/src/modules/m_callerid.cpp index 37787b525..3d2394fb1 100644 --- a/src/modules/m_callerid.cpp +++ b/src/modules/m_callerid.cpp @@ -22,8 +22,6 @@ #include "inspircd.h" -/* $ModDesc: Implementation of callerid, usermode +g, /accept */ - class callerid_data { public: @@ -62,12 +60,20 @@ struct CallerIDExtInfo : public ExtensionItem std::string serialize(SerializeFormat format, const Extensible* container, void* item) const { - callerid_data* dat = static_cast<callerid_data*>(item); - return dat->ToString(format); + std::string ret; + if (format != FORMAT_NETWORK) + { + callerid_data* dat = static_cast<callerid_data*>(item); + ret = dat->ToString(format); + } + return ret; } void unserialize(SerializeFormat format, Extensible* container, const std::string& value) { + if (format == FORMAT_NETWORK) + return; + callerid_data* dat = new callerid_data; irc::commasepstream s(value); std::string tok; @@ -76,9 +82,6 @@ struct CallerIDExtInfo : public ExtensionItem while (s.GetToken(tok)) { - if (tok.empty()) - continue; - User *u = ServerInstance->FindNick(tok); if ((u) && (u->registered == REG_ALL) && (!u->quitting) && (!IS_SERVER(u))) { @@ -117,7 +120,7 @@ struct CallerIDExtInfo : public ExtensionItem if (!targ) { - ServerInstance->Logs->Log("m_callerid", DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (1)"); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (1)"); continue; // shouldn't happen, but oh well. } @@ -125,7 +128,7 @@ struct CallerIDExtInfo : public ExtensionItem if (it2 != targ->wholistsme.end()) targ->wholistsme.erase(it2); else - ServerInstance->Logs->Log("m_callerid", DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (2)"); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (2)"); } delete dat; } @@ -139,6 +142,23 @@ public: class CommandAccept : public Command { + /** Pair: first is the target, second is true to add, false to remove + */ + typedef std::pair<User*, bool> ACCEPTAction; + + ACCEPTAction GetTargetAndAction(std::string& tok) + { + bool remove = (tok[0] == '-'); + if ((remove) || (tok[0] == '+')) + tok.erase(tok.begin()); + + User* target = ServerInstance->FindNick(tok); + if ((!target) || (target->registered != REG_ALL) || (target->quitting) || (IS_SERVER(target))) + target = NULL; + + return std::make_pair(target, !remove); + } + public: CallerIDExtInfo extInfo; unsigned int maxaccepts; @@ -147,39 +167,21 @@ public: { allow_empty_last_param = false; syntax = "{[+|-]<nicks>}|*}"; - TRANSLATE2(TR_CUSTOM, TR_END); + TRANSLATE1(TR_CUSTOM); } - virtual void EncodeParameter(std::string& parameter, int index) + void EncodeParameter(std::string& parameter, int index) { - if (index != 0) + // Send lists as-is (part of 2.0 compat) + if (parameter.find(',') != std::string::npos) return; - std::string out; - irc::commasepstream nicks(parameter); - std::string tok; - while (nicks.GetToken(tok)) - { - if (tok == "*") - { - continue; // Drop list requests, since remote servers ignore them anyway. - } - if (!out.empty()) - out.append(","); - bool dash = false; - if (tok[0] == '-') - { - dash = true; - tok.erase(0, 1); // Remove the dash. - } - User* u = ServerInstance->FindNick(tok); - if ((!u) || (u->registered != REG_ALL) || (u->quitting) || (IS_SERVER(u))) - continue; - if (dash) - out.append("-"); - out.append(u->uuid); - } - parameter = out; + // Convert a [+|-]<nick> into a [-]<uuid> + ACCEPTAction action = GetTargetAndAction(parameter); + if (!action.first) + return; + + parameter = (action.second ? "" : "-") + action.first->uuid; } /** Will take any number of nicks (up to MaxTargets), which can be seperated by commas. @@ -189,43 +191,58 @@ public: */ CmdResult Handle(const std::vector<std::string> ¶meters, User* user) { - if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) + if (CommandParser::LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; + /* Even if callerid mode is not set, we let them manage their ACCEPT list so that if they go +g they can * have a list already setup. */ - std::string tok = parameters[0]; - - if (tok == "*") + if (parameters[0] == "*") { - if (IS_LOCAL(user)) - ListAccept(user); + ListAccept(user); return CMD_SUCCESS; } - else if (tok[0] == '-') + + std::string tok = parameters[0]; + ACCEPTAction action = GetTargetAndAction(tok); + if (!action.first) { - User* whotoremove = ServerInstance->FindNick(tok.substr(1)); - if (whotoremove) - return (RemoveAccept(user, whotoremove) ? CMD_SUCCESS : CMD_FAILURE); - else - return CMD_FAILURE; + user->WriteNumeric(401, "%s %s :No such nick/channel", user->nick.c_str(), tok.c_str()); + return CMD_FAILURE; } + + if ((!IS_LOCAL(user)) && (!IS_LOCAL(action.first))) + // Neither source nor target is local, forward the command to the server of target + return CMD_SUCCESS; + + // The second item in the pair is true if the first char is a '+' (or nothing), false if it's a '-' + if (action.second) + return (AddAccept(user, action.first) ? CMD_SUCCESS : CMD_FAILURE); else - { - User* whotoadd = ServerInstance->FindNick(tok[0] == '+' ? tok.substr(1) : tok); - if ((whotoadd) && (whotoadd->registered == REG_ALL) && (!whotoadd->quitting) && (!IS_SERVER(whotoadd))) - return (AddAccept(user, whotoadd) ? CMD_SUCCESS : CMD_FAILURE); - else - { - user->WriteNumeric(401, "%s %s :No such nick/channel", user->nick.c_str(), tok.c_str()); - return CMD_FAILURE; - } - } + return (RemoveAccept(user, action.first) ? CMD_SUCCESS : CMD_FAILURE); } RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { - return ROUTE_BROADCAST; + // There is a list in parameters[0] in two cases: + // Either when the source is remote, this happens because 2.0 servers send comma seperated uuid lists, + // we don't split those but broadcast them, as before. + // + // Or if the source is local then LoopCall() runs OnPostCommand() after each entry in the list, + // meaning the linking module has sent an ACCEPT already for each entry in the list to the + // appropiate server and the ACCEPT with the list of nicks (this) doesn't need to be sent anywhere. + if ((!IS_LOCAL(user)) && (parameters[0].find(',') != std::string::npos)) + return ROUTE_BROADCAST; + + // Find the target + std::string targetstring = parameters[0]; + ACCEPTAction action = GetTargetAndAction(targetstring); + if (!action.first) + // Target is a "*" or source is local and the target is a list of nicks + return ROUTE_LOCALONLY; + + // Route to the server of the target + return ROUTE_UNICAST(action.first->server); } void ListAccept(User* user) @@ -258,7 +275,7 @@ public: callerid_data *targ = extInfo.get(whotoadd, true); targ->wholistsme.push_back(dat); - user->WriteServ("NOTICE %s :%s is now on your accept list", user->nick.c_str(), whotoadd->nick.c_str()); + user->WriteNotice(whotoadd->nick + " is now on your accept list"); return true; } @@ -285,7 +302,7 @@ public: if (!dat2) { // How the fuck is this possible. - ServerInstance->Logs->Log("m_callerid", DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (3)"); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (3)"); return false; } @@ -294,17 +311,16 @@ public: // Found me! dat2->wholistsme.erase(it); else - ServerInstance->Logs->Log("m_callerid", DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (4)"); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (4)"); - user->WriteServ("NOTICE %s :%s is no longer on your accept list", user->nick.c_str(), whotoremove->nick.c_str()); + user->WriteNotice(whotoremove->nick + " is no longer on your accept list"); return true; } }; class ModuleCallerID : public Module { -private: CommandAccept cmd; User_g myumode; @@ -334,7 +350,7 @@ private: if (it2 != dat->accepting.end()) dat->accepting.erase(it2); else - ServerInstance->Logs->Log("m_callerid", DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (5)"); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (5)"); } userdata->wholistsme.clear(); @@ -345,38 +361,31 @@ public: { } - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); ServerInstance->Modules->AddService(myumode); ServerInstance->Modules->AddService(cmd); ServerInstance->Modules->AddService(cmd.extInfo); - - Implementation eventlist[] = { I_OnRehash, I_OnUserPostNick, I_OnUserQuit, I_On005Numeric, I_OnUserPreNotice, I_OnUserPreMessage }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual ~ModuleCallerID() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Implementation of callerid, usermode +g, /accept", VF_COMMON | VF_VENDOR); } - virtual void On005Numeric(std::string& output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - output += " CALLERID=g"; + tokens["CALLERID"] = "g"; } ModResult PreText(User* user, User* dest, std::string& text) { - if (!dest->IsModeSet('g') || (user == dest)) + if (!dest->IsModeSet(myumode) || (user == dest)) return MOD_RES_PASSTHRU; - if (operoverride && IS_OPER(user)) + if (operoverride && user->IsOper()) return MOD_RES_PASSTHRU; callerid_data* dat = cmd.extInfo.get(dest, true); @@ -399,15 +408,7 @@ public: return MOD_RES_PASSTHRU; } - virtual ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList &exempt_list) - { - if (IS_LOCAL(user) && target_type == TYPE_USER) - return PreText(user, (User*)dest, text); - - return MOD_RES_PASSTHRU; - } - - virtual ModResult OnUserPreNotice(User* user, void* dest, int target_type, std::string& text, char status, CUList &exempt_list) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { if (IS_LOCAL(user) && target_type == TYPE_USER) return PreText(user, (User*)dest, text); @@ -415,18 +416,18 @@ public: return MOD_RES_PASSTHRU; } - void OnUserPostNick(User* user, const std::string& oldnick) + void OnUserPostNick(User* user, const std::string& oldnick) CXX11_OVERRIDE { if (!tracknick) RemoveFromAllAccepts(user); } - void OnUserQuit(User* user, const std::string& message, const std::string& oper_message) + void OnUserQuit(User* user, const std::string& message, const std::string& oper_message) CXX11_OVERRIDE { RemoveFromAllAccepts(user); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("callerid"); cmd.maxaccepts = tag->getInt("maxaccepts", 16); @@ -437,5 +438,3 @@ public: }; MODULE_INIT(ModuleCallerID) - - diff --git a/src/modules/m_cap.cpp b/src/modules/m_cap.cpp index e9f4dae90..35c24fd23 100644 --- a/src/modules/m_cap.cpp +++ b/src/modules/m_cap.cpp @@ -19,9 +19,7 @@ #include "inspircd.h" -#include "m_cap.h" - -/* $ModDesc: Provides the CAP negotiation mechanism seen in ratbox-derived ircds */ +#include "modules/cap.h" /* CAP LS @@ -74,13 +72,13 @@ class CommandCAP : public Command if (Data.ack.size() > 0) { - std::string AckResult = irc::stringjoiner(" ", Data.ack, 0, Data.ack.size() - 1).GetJoined(); + std::string AckResult = irc::stringjoiner(Data.ack).GetJoined(); user->WriteServ("CAP %s ACK :%s", user->nick.c_str(), AckResult.c_str()); } if (Data.wanted.size() > 0) { - std::string NakResult = irc::stringjoiner(" ", Data.wanted, 0, Data.wanted.size() - 1).GetJoined(); + std::string NakResult = irc::stringjoiner(Data.wanted).GetJoined(); user->WriteServ("CAP %s NAK :%s", user->nick.c_str(), NakResult.c_str()); } } @@ -95,10 +93,7 @@ class CommandCAP : public Command reghold.set(user, 1); Data.Send(); - std::string Result; - if (Data.wanted.size() > 0) - Result = irc::stringjoiner(" ", Data.wanted, 0, Data.wanted.size() - 1).GetJoined(); - + std::string Result = irc::stringjoiner(Data.wanted).GetJoined(); user->WriteServ("CAP %s %s :%s", user->nick.c_str(), subcommand.c_str(), Result.c_str()); } else if (subcommand == "CLEAR") @@ -108,9 +103,7 @@ class CommandCAP : public Command reghold.set(user, 1); Data.Send(); - std::string Result; - if (!Data.ack.empty()) - Result = irc::stringjoiner(" ", Data.ack, 0, Data.ack.size() - 1).GetJoined(); + std::string Result = irc::stringjoiner(Data.ack).GetJoined(); user->WriteServ("CAP %s ACK :%s", user->nick.c_str(), Result.c_str()); } else @@ -132,16 +125,13 @@ class ModuleCAP : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); ServerInstance->Modules->AddService(cmd.reghold); - - Implementation eventlist[] = { I_OnCheckReady }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - ModResult OnCheckReady(LocalUser* user) + ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE { /* Users in CAP state get held until CAP END */ if (cmd.reghold.get(user)) @@ -150,15 +140,10 @@ class ModuleCAP : public Module return MOD_RES_PASSTHRU; } - ~ModuleCAP() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Client CAP extension support", VF_VENDOR); } }; MODULE_INIT(ModuleCAP) - diff --git a/src/modules/m_cban.cpp b/src/modules/m_cban.cpp index fb78e41b2..39a5d6266 100644 --- a/src/modules/m_cban.cpp +++ b/src/modules/m_cban.cpp @@ -23,25 +23,22 @@ #include "inspircd.h" #include "xline.h" -/* $ModDesc: Gives /cban, aka C:lines. Think Q:lines, for channels. */ - /** Holds a CBAN item */ class CBan : public XLine { -public: +private: + std::string displaytext; irc::string matchtext; +public: CBan(time_t s_time, long d, const std::string& src, const std::string& re, const std::string& ch) : XLine(s_time, d, src, re, "CBAN") { + this->displaytext = ch; this->matchtext = ch.c_str(); } - ~CBan() - { - } - // XXX I shouldn't have to define this bool Matches(User *u) { @@ -55,15 +52,9 @@ public: return false; } - void DisplayExpiry() + const std::string& Displayable() { - ServerInstance->SNO->WriteToSnoMask('x',"Removing expired CBan %s (set by %s %ld seconds ago)", - this->matchtext.c_str(), this->source.c_str(), (long int)(ServerInstance->Time() - this->set_time)); - } - - const char* Displayable() - { - return matchtext.c_str(); + return displaytext; } }; @@ -95,7 +86,6 @@ class CommandCBan : public Command CommandCBan(Module* Creator) : Command(Creator, "CBAN", 1, 3) { flags_needed = 'o'; this->syntax = "<channel> [<duration> :<reason>]"; - TRANSLATE4(TR_TEXT,TR_TEXT,TR_TEXT,TR_END); } CmdResult Handle(const std::vector<std::string> ¶meters, User *user) @@ -111,14 +101,14 @@ class CommandCBan : public Command } else { - user->WriteServ("NOTICE %s :*** CBan %s not found in list, try /stats C.",user->nick.c_str(),parameters[0].c_str()); + user->WriteNotice("*** CBan " + parameters[0] + " not found in list, try /stats C."); return CMD_FAILURE; } } else { // Adding - XXX todo make this respect <insane> tag perhaps.. - long duration = ServerInstance->Duration(parameters[1]); + unsigned long duration = InspIRCd::Duration(parameters[1]); const char *reason = (parameters.size() > 2) ? parameters[2].c_str() : "No reason supplied"; CBan* r = new CBan(ServerInstance->Time(), duration, user->nick.c_str(), reason, parameters[0].c_str()); @@ -138,7 +128,7 @@ class CommandCBan : public Command else { delete r; - user->WriteServ("NOTICE %s :*** CBan for %s already exists", user->nick.c_str(), parameters[0].c_str()); + user->WriteNotice("*** CBan for " + parameters[0] + " already exists"); return CMD_FAILURE; } } @@ -164,22 +154,20 @@ class ModuleCBan : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->XLines->RegisterFactory(&f); ServerInstance->Modules->AddService(mycommand); - Implementation eventlist[] = { I_OnUserPreJoin, I_OnStats }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual ~ModuleCBan() + ~ModuleCBan() { ServerInstance->XLines->DelAll("CBAN"); ServerInstance->XLines->UnregisterFactory(&f); } - virtual ModResult OnStats(char symbol, User* user, string_list &out) + ModResult OnStats(char symbol, User* user, string_list &out) CXX11_OVERRIDE { if (symbol != 'C') return MOD_RES_PASSTHRU; @@ -188,27 +176,26 @@ class ModuleCBan : public Module return MOD_RES_DENY; } - virtual ModResult OnUserPreJoin(User *user, Channel *chan, const char *cname, std::string &privs, const std::string &keygiven) + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { XLine *rl = ServerInstance->XLines->MatchesLine("CBAN", cname); if (rl) { // Channel is banned. - user->WriteServ( "384 %s %s :Cannot join channel, CBANed (%s)", user->nick.c_str(), cname, rl->reason.c_str()); + user->WriteServ( "384 %s %s :Cannot join channel, CBANed (%s)", user->nick.c_str(), cname.c_str(), rl->reason.c_str()); ServerInstance->SNO->WriteGlobalSno('a', "%s tried to join %s which is CBANed (%s)", - user->nick.c_str(), cname, rl->reason.c_str()); + user->nick.c_str(), cname.c_str(), rl->reason.c_str()); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Gives /cban, aka C:lines. Think Q:lines, for channels.", VF_COMMON | VF_VENDOR); } }; MODULE_INIT(ModuleCBan) - diff --git a/src/modules/m_censor.cpp b/src/modules/m_censor.cpp index 50c8e22a7..747c16d83 100644 --- a/src/modules/m_censor.cpp +++ b/src/modules/m_censor.cpp @@ -20,8 +20,6 @@ */ -/* $ModDesc: Provides user and channel +G mode */ - #define _CRT_SECURE_NO_DEPRECATE #define _SCL_SECURE_NO_DEPRECATE @@ -55,24 +53,17 @@ class ModuleCensor : public Module public: ModuleCensor() : cu(this), cc(this) { } - void init() + void init() CXX11_OVERRIDE { /* Read the configuration file on startup. */ OnRehash(NULL); ServerInstance->Modules->AddService(cu); ServerInstance->Modules->AddService(cc); - Implementation eventlist[] = { I_OnRehash, I_OnUserPreMessage, I_OnUserPreNotice }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - - virtual ~ModuleCensor() - { } // format of a config entry is <badword text="shit" replace="poo"> - virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; @@ -80,11 +71,11 @@ class ModuleCensor : public Module bool active = false; if (target_type == TYPE_USER) - active = ((User*)dest)->IsModeSet('G'); + active = ((User*)dest)->IsModeSet(cu); else if (target_type == TYPE_CHANNEL) { - active = ((Channel*)dest)->IsModeSet('G'); Channel* c = (Channel*)dest; + active = c->IsModeSet(cc); ModResult res = ServerInstance->OnCheckExemption(user,c,"censor"); if (res == MOD_RES_ALLOW) @@ -112,12 +103,7 @@ class ModuleCensor : public Module return MOD_RES_PASSTHRU; } - virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreMessage(user,dest,target_type,text,status,exempt_list); - } - - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { /* * reload our config file on rehash - we must destroy and re-allocate the classes @@ -136,7 +122,7 @@ class ModuleCensor : public Module } } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides user and channel +G mode",VF_VENDOR); } diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp index ccbaaae32..2352fa217 100644 --- a/src/modules/m_cgiirc.cpp +++ b/src/modules/m_cgiirc.cpp @@ -25,8 +25,7 @@ #include "inspircd.h" #include "xline.h" - -/* $ModDesc: Change user's hosts connecting from known CGI:IRC hosts */ +#include "modules/dns.h" enum CGItype { PASS, IDENT, PASSFIRST, IDENTFIRST, WEBIRC }; @@ -116,39 +115,44 @@ class CommandWebirc : public Command /** Resolver for CGI:IRC hostnames encoded in ident/GECOS */ -class CGIResolver : public Resolver +class CGIResolver : public DNS::Request { std::string typ; std::string theiruid; LocalIntExt& waiting; bool notify; public: - CGIResolver(Module* me, bool NotifyOpers, const std::string &source, LocalUser* u, - const std::string &type, bool &cached, LocalIntExt& ext) - : Resolver(source, DNS_QUERY_PTR4, cached, me), typ(type), theiruid(u->uuid), + CGIResolver(DNS::Manager *mgr, Module* me, bool NotifyOpers, const std::string &source, LocalUser* u, + const std::string &ttype, LocalIntExt& ext) + : DNS::Request(mgr, me, source, DNS::QUERY_PTR), typ(ttype), theiruid(u->uuid), waiting(ext), notify(NotifyOpers) { } - virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) + void OnLookupComplete(const DNS::Query *r) CXX11_OVERRIDE { /* Check the user still exists */ User* them = ServerInstance->FindUUID(theiruid); if ((them) && (!them->quitting)) { - if (notify) - ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", them->nick.c_str(), them->host.c_str(), result.c_str(), typ.c_str()); + LocalUser* lu = IS_LOCAL(them); + if (!lu) + return; - if (result.length() > 64) + const DNS::ResourceRecord &ans_record = r->answers[0]; + if (ans_record.rdata.empty() || ans_record.rdata.length() > 64) return; - them->host = result; - them->dhost = result; + + if (notify) + ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", them->nick.c_str(), them->host.c_str(), ans_record.rdata.c_str(), typ.c_str()); + + them->host = them->dhost = ans_record.rdata; them->InvalidateCache(); - them->CheckLines(true); + lu->CheckLines(true); } } - virtual void OnError(ResolverError e, const std::string &errormessage) + void OnError(const DNS::Query *r) CXX11_OVERRIDE { if (!notify) return; @@ -160,7 +164,7 @@ class CGIResolver : public Resolver } } - virtual ~CGIResolver() + ~CGIResolver() { User* them = ServerInstance->FindUUID(theiruid); if (!them) @@ -175,6 +179,7 @@ class ModuleCgiIRC : public Module { CommandWebirc cmd; LocalIntExt waiting; + dynamic_reference<DNS::Manager> DNS; static void RecheckClass(LocalUser* user) { @@ -199,40 +204,44 @@ class ModuleCgiIRC : public Module user->host = user->dhost = user->GetIPString(); user->InvalidateCache(); RecheckClass(user); + // Don't create the resolver if the core couldn't put the user in a connect class or when dns is disabled - if (user->quitting || ServerInstance->Config->NoUserDns) + if (user->quitting || !DNS || !user->MyClass->resolvehostnames) return; + CGIResolver* r = new CGIResolver(*this->DNS, this, cmd.notify, newip, user, (was_pass ? "PASS" : "IDENT"), waiting); try { - bool cached; - CGIResolver* r = new CGIResolver(this, cmd.notify, newip, user, (was_pass ? "PASS" : "IDENT"), cached, waiting); waiting.set(user, waiting.get(user) + 1); - ServerInstance->AddResolver(r, cached); + this->DNS->Process(r); } - catch (...) + catch (DNS::Exception &ex) { + int count = waiting.get(user); + if (count) + waiting.set(user, count - 1); + delete r; if (cmd.notify) - ServerInstance->SNO->WriteToSnoMask('a', "Connecting user %s detected as using CGI:IRC (%s), but I could not resolve their hostname!", user->nick.c_str(), user->host.c_str()); + ServerInstance->SNO->WriteToSnoMask('a', "Connecting user %s detected as using CGI:IRC (%s), but I could not resolve their hostname; %s", user->nick.c_str(), user->host.c_str(), ex.GetReason()); } } public: - ModuleCgiIRC() : cmd(this), waiting("cgiirc-delay", this) + ModuleCgiIRC() + : cmd(this) + , waiting("cgiirc-delay", this) + , DNS(this, "DNS") { } - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); ServiceProvider* providerlist[] = { &cmd, &cmd.realhost, &cmd.realip, &cmd.webirc_hostname, &cmd.webirc_ip, &waiting }; ServerInstance->Modules->AddServices(providerlist, sizeof(providerlist)/sizeof(ServiceProvider*)); - - Implementation eventlist[] = { I_OnRehash, I_OnUserRegister, I_OnCheckReady }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { cmd.Hosts.clear(); @@ -251,7 +260,7 @@ public: { if (type == "webirc" && password.empty()) { - ServerInstance->Logs->Log("CONFIG",DEFAULT, "m_cgiirc: Missing password in config: %s", hostmask.c_str()); + ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "m_cgiirc: Missing password in config: %s", hostmask.c_str()); } else { @@ -267,7 +276,7 @@ public: else { cgitype = PASS; - ServerInstance->Logs->Log("CONFIG",DEFAULT, "m_cgiirc.so: Invalid <cgihost:type> value in config: %s, setting it to \"pass\"", type.c_str()); + ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Invalid <cgihost:type> value in config: %s, setting it to \"pass\"", type.c_str()); } cmd.Hosts.push_back(CGIhost(hostmask, cgitype, password)); @@ -275,13 +284,13 @@ public: } else { - ServerInstance->Logs->Log("CONFIG",DEFAULT, "m_cgiirc.so: Invalid <cgihost:mask> value in config: %s", hostmask.c_str()); + ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Invalid <cgihost:mask> value in config: %s", hostmask.c_str()); continue; } } } - ModResult OnCheckReady(LocalUser *user) + ModResult OnCheckReady(LocalUser *user) CXX11_OVERRIDE { if (waiting.get(user)) return MOD_RES_DENY; @@ -309,7 +318,7 @@ public: return MOD_RES_PASSTHRU; } - ModResult OnUserRegister(LocalUser* user) + ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE { for(CGIHostlist::iterator iter = cmd.Hosts.begin(); iter != cmd.Hosts.end(); iter++) { @@ -406,7 +415,7 @@ public: return true; } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Change user's hosts connecting from known CGI:IRC hosts",VF_VENDOR); } diff --git a/src/modules/m_chancreate.cpp b/src/modules/m_chancreate.cpp index 997a92648..6cf4af235 100644 --- a/src/modules/m_chancreate.cpp +++ b/src/modules/m_chancreate.cpp @@ -21,26 +21,20 @@ #include "inspircd.h" -/* $ModDesc: Provides snomasks 'j' and 'J', to which notices about newly created channels are sent */ - class ModuleChanCreate : public Module { - private: public: - void init() + void init() CXX11_OVERRIDE { ServerInstance->SNO->EnableSnomask('j', "CHANCREATE"); - Implementation eventlist[] = { I_OnUserJoin }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides snomasks 'j' and 'J', to which notices about newly created channels are sent",VF_VENDOR); } - - void OnUserJoin(Membership* memb, bool sync, bool created, CUList& except) + void OnUserJoin(Membership* memb, bool sync, bool created, CUList& except) CXX11_OVERRIDE { if ((created) && (IS_LOCAL(memb->user))) { diff --git a/src/modules/m_chanfilter.cpp b/src/modules/m_chanfilter.cpp index 651e659b5..38ee14e60 100644 --- a/src/modules/m_chanfilter.cpp +++ b/src/modules/m_chanfilter.cpp @@ -23,13 +23,11 @@ */ -/* $ModDesc: Provides channel-specific censor lists (like mode +G but varies from channel to channel) */ - #define _CRT_SECURE_NO_DEPRECATE #define _SCL_SECURE_NO_DEPRECATE #include "inspircd.h" -#include "u_listmode.h" +#include "listmode.h" /** Handles channel mode +g */ @@ -38,7 +36,7 @@ class ChanFilter : public ListModeBase public: ChanFilter(Module* Creator) : ListModeBase(Creator, "filter", 'g', "End of channel spamfilter list", 941, 940, false, "chanfilter") { } - virtual bool ValidateParam(User* user, Channel* chan, std::string &word) + bool ValidateParam(User* user, Channel* chan, std::string &word) { if ((word.length() > 35) || (word.empty())) { @@ -49,18 +47,17 @@ class ChanFilter : public ListModeBase return true; } - virtual bool TellListTooLong(User* user, Channel* chan, std::string &word) + void TellListTooLong(User* user, Channel* chan, std::string &word) { user->WriteNumeric(939, "%s %s %s :Channel spamfilter list is full", user->nick.c_str(), chan->name.c_str(), word.c_str()); - return true; } - virtual void TellAlreadyOnList(User* user, Channel* chan, std::string &word) + void TellAlreadyOnList(User* user, Channel* chan, std::string &word) { user->WriteNumeric(937, "%s %s :The word %s is already on the spamfilter list",user->nick.c_str(), chan->name.c_str(), word.c_str()); } - virtual void TellNotSet(User* user, Channel* chan, std::string &word) + void TellNotSet(User* user, Channel* chan, std::string &word) { user->WriteNumeric(938, "%s %s :No such spamfilter word is set",user->nick.c_str(), chan->name.c_str()); } @@ -78,35 +75,33 @@ class ModuleChanFilter : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cf); cf.DoImplements(this); - Implementation eventlist[] = { I_OnRehash, I_OnUserPreMessage, I_OnUserPreNotice, I_OnSyncChannel }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { hidemask = ServerInstance->Config->ConfValue("chanfilter")->getBool("hidemask"); cf.DoRehash(); } - virtual ModResult ProcessMessages(User* user,Channel* chan,std::string &text) + ModResult ProcessMessages(User* user,Channel* chan,std::string &text) { ModResult res = ServerInstance->OnCheckExemption(user,chan,"filter"); if (!IS_LOCAL(user) || res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; - modelist* list = cf.extItem.get(chan); + ListModeBase::ModeList* list = cf.GetList(chan); if (list) { - for (modelist::iterator i = list->begin(); i != list->end(); i++) + for (ListModeBase::ModeList::iterator i = list->begin(); i != list->end(); i++) { if (InspIRCd::Match(text, i->mask)) { @@ -122,7 +117,7 @@ class ModuleChanFilter : public Module return MOD_RES_PASSTHRU; } - virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { if (target_type == TYPE_CHANNEL) { @@ -131,24 +126,15 @@ class ModuleChanFilter : public Module return MOD_RES_PASSTHRU; } - virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreMessage(user,dest,target_type,text,status,exempt_list); - } - - virtual void OnSyncChannel(Channel* chan, Module* proto, void* opaque) + void OnSyncChannel(Channel* chan, Module* proto, void* opaque) CXX11_OVERRIDE { cf.DoSyncChannel(chan, proto, opaque); } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel-specific censor lists (like mode +G but varies from channel to channel)", VF_VENDOR); } - - virtual ~ModuleChanFilter() - { - } }; MODULE_INIT(ModuleChanFilter) diff --git a/src/modules/m_chanhistory.cpp b/src/modules/m_chanhistory.cpp index e48e67fe5..f1f9ed614 100644 --- a/src/modules/m_chanhistory.cpp +++ b/src/modules/m_chanhistory.cpp @@ -19,8 +19,6 @@ #include "inspircd.h" -/* $ModDesc: Provides channel history for a given number of lines */ - struct HistoryItem { time_t ts; @@ -70,7 +68,7 @@ class HistoryMode : public ModeHandler return MODEACTION_DENY; unsigned int len = ConvToInt(parameter.substr(0, colon)); - int time = ServerInstance->Duration(duration); + int time = InspIRCd::Duration(duration); if (len == 0 || time < 0) return MODEACTION_DENY; if (len > maxlines && IS_LOCAL(source)) @@ -94,14 +92,12 @@ class HistoryMode : public ModeHandler { ext.set(channel, new HistoryList(len, time)); } - channel->SetModeParam('H', parameter); } else { - if (!channel->IsModeSet('H')) + if (!channel->IsModeSet(this)) return MODEACTION_DENY; ext.unset(channel); - channel->SetModeParam('H', ""); } return MODEACTION_ALLOW; } @@ -111,51 +107,53 @@ class ModuleChanHistory : public Module { HistoryMode m; bool sendnotice; + UserModeReference botmode; + bool dobots; public: - ModuleChanHistory() : m(this) + ModuleChanHistory() : m(this), botmode(this, "bot") { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(m); ServerInstance->Modules->AddService(m.ext); - Implementation eventlist[] = { I_OnPostJoin, I_OnUserMessage, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); } - void OnRehash(User*) + void OnRehash(User*) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("chanhistory"); m.maxlines = tag->getInt("maxlines", 50); sendnotice = tag->getBool("notice", true); + dobots = tag->getBool("bots", true); } - void OnUserMessage(User* user,void* dest,int target_type, const std::string &text, char status, const CUList&) + void OnUserMessage(User* user, void* dest, int target_type, const std::string &text, char status, const CUList&, MessageType msgtype) CXX11_OVERRIDE { - if (target_type == TYPE_CHANNEL && status == 0) + if ((target_type == TYPE_CHANNEL) && (status == 0) && (msgtype == MSG_PRIVMSG)) { Channel* c = (Channel*)dest; HistoryList* list = m.ext.get(c); if (list) { - char buf[MAXBUF]; - snprintf(buf, MAXBUF, ":%s PRIVMSG %s :%s", - user->GetFullHost().c_str(), c->name.c_str(), text.c_str()); - list->lines.push_back(HistoryItem(buf)); + const std::string line = ":" + user->GetFullHost() + " PRIVMSG " + c->name + " :" + text; + list->lines.push_back(HistoryItem(line)); if (list->lines.size() > list->maxlen) list->lines.pop_front(); } } } - void OnPostJoin(Membership* memb) + void OnPostJoin(Membership* memb) CXX11_OVERRIDE { if (IS_REMOTE(memb->user)) return; + if (memb->user->IsModeSet(botmode) && !dobots) + return; + HistoryList* list = m.ext.get(memb->chan); if (!list) return; @@ -165,8 +163,7 @@ class ModuleChanHistory : public Module if (sendnotice) { - memb->user->WriteServ("NOTICE %s :Replaying up to %d lines of pre-join history spanning up to %d seconds", - memb->chan->name.c_str(), list->maxlen, list->maxtime); + memb->user->WriteNotice("Replaying up to " + ConvToStr(list->maxlen) + " lines of pre-join history spanning up to " + ConvToStr(list->maxtime) + " seconds"); } for(std::deque<HistoryItem>::iterator i = list->lines.begin(); i != list->lines.end(); ++i) @@ -176,7 +173,7 @@ class ModuleChanHistory : public Module } } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel history replayed on join", VF_VENDOR); } diff --git a/src/modules/m_chanlog.cpp b/src/modules/m_chanlog.cpp index 6dbc0e7a8..dc5750ba6 100644 --- a/src/modules/m_chanlog.cpp +++ b/src/modules/m_chanlog.cpp @@ -20,11 +20,8 @@ #include "inspircd.h" -/* $ModDesc: Logs snomask output to channel(s). */ - class ModuleChanLog : public Module { - private: /* * Multimap so people can redirect a snomask to multiple channels. */ @@ -32,19 +29,12 @@ class ModuleChanLog : public Module ChanLogTargets logstreams; public: - void init() + void init() CXX11_OVERRIDE { - Implementation eventlist[] = { I_OnRehash, I_OnSendSnotice }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - OnRehash(NULL); } - virtual ~ModuleChanLog() - { - } - - virtual void OnRehash(User *user) + void OnRehash(User *user) CXX11_OVERRIDE { std::string snomasks; std::string channel; @@ -59,100 +49,44 @@ class ModuleChanLog : public Module if (channel.empty() || snomasks.empty()) { - ServerInstance->Logs->Log("m_chanlog", DEFAULT, "Malformed chanlog tag, ignoring"); + ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Malformed chanlog tag, ignoring"); continue; } for (std::string::const_iterator it = snomasks.begin(); it != snomasks.end(); it++) { logstreams.insert(std::make_pair(*it, channel)); - ServerInstance->Logs->Log("m_chanlog", DEFAULT, "Logging %c to %s", *it, channel.c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Logging %c to %s", *it, channel.c_str()); } } } - virtual ModResult OnSendSnotice(char &sno, std::string &desc, const std::string &msg) + ModResult OnSendSnotice(char &sno, std::string &desc, const std::string &msg) CXX11_OVERRIDE { std::pair<ChanLogTargets::const_iterator, ChanLogTargets::const_iterator> itpair = logstreams.equal_range(sno); if (itpair.first == itpair.second) return MOD_RES_PASSTHRU; - char buf[MAXBUF]; - snprintf(buf, MAXBUF, "\2%s\2: %s", desc.c_str(), msg.c_str()); + const std::string snotice = "\2" + desc + "\2: " + msg; for (ChanLogTargets::const_iterator it = itpair.first; it != itpair.second; ++it) { Channel *c = ServerInstance->FindChan(it->second); if (c) { - c->WriteChannelWithServ(ServerInstance->Config->ServerName, "PRIVMSG %s :%s", c->name.c_str(), buf); - ServerInstance->PI->SendChannelPrivmsg(c, 0, buf); + c->WriteChannelWithServ(ServerInstance->Config->ServerName, "PRIVMSG %s :%s", c->name.c_str(), snotice.c_str()); + ServerInstance->PI->SendMessage(c, 0, snotice); } } return MOD_RES_PASSTHRU; } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Logs snomask output to channel(s).", VF_VENDOR); } }; - MODULE_INIT(ModuleChanLog) - - - - - - - - - -/* - * This is for the "old" chanlog module which intercepted messages going to the logfile.. - * I don't consider it all that useful, and it's quite dangerous if setup incorrectly, so - * this is defined out but left intact in case someone wants to develop it further someday. - * - * -- w00t (aug 23rd, 2008) - */ -#define OLD_CHANLOG 0 - -#if OLD_CHANLOG -class ChannelLogStream : public LogStream -{ - private: - std::string channel; - - public: - ChannelLogStream(int loglevel, const std::string &chan) : LogStream(loglevel), channel(chan) - { - } - - virtual void OnLog(int loglevel, const std::string &type, const std::string &msg) - { - Channel *c = ServerInstance->FindChan(channel); - static bool Logging = false; - - if (loglevel < this->loglvl) - return; - - if (Logging) - return; - - if (c) - { - Logging = true; // this avoids (rare chance) loops with logging server IO on networks - char buf[MAXBUF]; - snprintf(buf, MAXBUF, "\2%s\2: %s", type.c_str(), msg.c_str()); - - c->WriteChannelWithServ(ServerInstance->Config->ServerName, "PRIVMSG %s :%s", c->name.c_str(), buf); - ServerInstance->PI->SendChannelPrivmsg(c, 0, buf); - Logging = false; - } - } -}; -#endif - diff --git a/src/modules/m_channames.cpp b/src/modules/m_channames.cpp index b5f5853e7..fcb2ef6d7 100644 --- a/src/modules/m_channames.cpp +++ b/src/modules/m_channames.cpp @@ -19,51 +19,49 @@ #include "inspircd.h" -/* $ModDesc: Implements config tags which allow changing characters allowed in channel names */ - static std::bitset<256> allowedmap; -class NewIsChannelHandler : public HandlerBase2<bool, const char*, size_t> +class NewIsChannelHandler : public HandlerBase1<bool, const std::string&> { public: NewIsChannelHandler() { } - virtual ~NewIsChannelHandler() { } - virtual bool Call(const char*, size_t); + ~NewIsChannelHandler() { } + bool Call(const std::string&); }; -bool NewIsChannelHandler::Call(const char* c, size_t max) +bool NewIsChannelHandler::Call(const std::string& channame) { - /* check for no name - don't check for !*chname, as if it is empty, it won't be '#'! */ - if (!c || *c++ != '#') + if (channame.empty() || channame.length() > ServerInstance->Config->Limits.ChanMax || channame[0] != '#') + return false; + + for (std::string::const_iterator c = channame.begin(); c != channame.end(); ++c) + { + unsigned int i = *c & 0xFF; + if (!allowedmap[i]) return false; + } - while (*c && --max) - { - unsigned int i = *c++ & 0xFF; - if (!allowedmap[i]) - return false; - } - // a name of exactly max length will have max = 1 here; the null does not trigger --max - return max; + return true; } class ModuleChannelNames : public Module { - private: NewIsChannelHandler myhandler; - caller2<bool, const char*, size_t> rememberer; + caller1<bool, const std::string&> rememberer; bool badchan; + ChanModeReference permchannelmode; public: - ModuleChannelNames() : rememberer(ServerInstance->IsChannel), badchan(false) + ModuleChannelNames() + : rememberer(ServerInstance->IsChannel) + , badchan(false) + , permchannelmode(this, "permanent") { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->IsChannel = &myhandler; - Implementation eventlist[] = { I_OnRehash, I_OnUserKick }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); } @@ -73,20 +71,20 @@ class ModuleChannelNames : public Module std::vector<Channel*> chanvec; for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); ++i) { - if (!ServerInstance->IsChannel(i->second->name.c_str(), MAXBUF)) + if (!ServerInstance->IsChannel(i->second->name)) chanvec.push_back(i->second); } std::vector<Channel*>::reverse_iterator c2 = chanvec.rbegin(); while (c2 != chanvec.rend()) { Channel* c = *c2++; - if (c->IsModeSet('P') && c->GetUserCounter()) + if (c->IsModeSet(permchannelmode) && c->GetUserCounter()) { std::vector<std::string> modes; modes.push_back(c->name); - modes.push_back("-P"); + modes.push_back(std::string("-") + permchannelmode->GetModeChar()); - ServerInstance->SendGlobalMode(modes, ServerInstance->FakeClient); + ServerInstance->Modes->Process(modes, ServerInstance->FakeClient); } const UserMembList* users = c->GetUsers(); for(UserMembCIter j = users->begin(); j != users->end(); ) @@ -104,7 +102,7 @@ class ModuleChannelNames : public Module badchan = false; } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("channames"); std::string denyToken = tag->getString("denyrange"); @@ -128,7 +126,7 @@ class ModuleChannelNames : public Module ValidateChans(); } - virtual void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& except_list) + void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& except_list) CXX11_OVERRIDE { if (badchan) { @@ -139,13 +137,13 @@ class ModuleChannelNames : public Module } } - virtual ~ModuleChannelNames() + ~ModuleChannelNames() { ServerInstance->IsChannel = rememberer; ValidateChans(); } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Implements config tags which allow changing characters allowed in channel names", VF_VENDOR); } diff --git a/src/modules/m_channelban.cpp b/src/modules/m_channelban.cpp index 6eec486ea..3260c0fa4 100644 --- a/src/modules/m_channelban.cpp +++ b/src/modules/m_channelban.cpp @@ -20,28 +20,15 @@ #include "inspircd.h" -/* $ModDesc: Implements extban +b j: - matching channel bans */ - class ModuleBadChannelExtban : public Module { - private: public: - void init() - { - Implementation eventlist[] = { I_OnCheckBan, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - ~ModuleBadChannelExtban() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Extban 'j' - channel status/join ban", VF_OPTCOMMON|VF_VENDOR); } - ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) + ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) CXX11_OVERRIDE { if ((mask.length() > 2) && (mask[0] == 'j') && (mask[1] == ':')) { @@ -71,12 +58,10 @@ class ModuleBadChannelExtban : public Module return MOD_RES_PASSTHRU; } - void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - ServerInstance->AddExtBanChar('j'); + tokens["EXTBAN"].push_back('j'); } }; - MODULE_INIT(ModuleBadChannelExtban) - diff --git a/src/modules/m_chanprotect.cpp b/src/modules/m_chanprotect.cpp deleted file mode 100644 index affd0c8d6..000000000 --- a/src/modules/m_chanprotect.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> - * Copyright (C) 2006-2009 Robin Burchell <robin+git@viroteck.net> - * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> - * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> - * Copyright (C) 2004-2008 Craig Edwards <craigedwards@brainbox.cc> - * Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net> - * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "inspircd.h" - -/* $ModDesc: Provides channel modes +a and +q */ - -#define PROTECT_VALUE 40000 -#define FOUNDER_VALUE 50000 - -struct ChanProtectSettings -{ - bool DeprivSelf; - bool DeprivOthers; - bool FirstInGetsFounder; - bool booting; - ChanProtectSettings() : booting(true) {} -}; - -static ChanProtectSettings settings; - -/** Handles basic operation of +qa channel modes - */ -class FounderProtectBase -{ - private: - const std::string type; - const char mode; - const int list; - const int end; - public: - FounderProtectBase(char Mode, const std::string &mtype, int l, int e) : - type(mtype), mode(Mode), list(l), end(e) - { - } - - void RemoveMode(Channel* channel, irc::modestacker* stack) - { - const UserMembList* cl = channel->GetUsers(); - std::vector<std::string> mode_junk; - mode_junk.push_back(channel->name); - irc::modestacker modestack(false); - std::deque<std::string> stackresult; - - for (UserMembCIter i = cl->begin(); i != cl->end(); i++) - { - if (i->second->hasMode(mode)) - { - if (stack) - stack->Push(mode, i->first->nick); - else - modestack.Push(mode, i->first->nick); - } - } - - if (stack) - return; - - while (modestack.GetStackedLine(stackresult)) - { - mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end()); - ServerInstance->SendMode(mode_junk, ServerInstance->FakeClient); - mode_junk.erase(mode_junk.begin() + 1, mode_junk.end()); - } - } - - void DisplayList(User* user, Channel* channel) - { - const UserMembList* cl = channel->GetUsers(); - for (UserMembCIter i = cl->begin(); i != cl->end(); ++i) - { - if (i->second->hasMode(mode)) - { - user->WriteServ("%d %s %s %s", list, user->nick.c_str(), channel->name.c_str(), i->first->nick.c_str()); - } - } - user->WriteServ("%d %s %s :End of channel %s list", end, user->nick.c_str(), channel->name.c_str(), type.c_str()); - } - - bool CanRemoveOthers(User* u1, Channel* c) - { - Membership* m1 = c->GetUser(u1); - return (settings.DeprivOthers && m1 && m1->hasMode(mode)); - } -}; - -/** Abstraction of FounderProtectBase for channel mode +q - */ -class ChanFounder : public ModeHandler, public FounderProtectBase -{ - public: - ChanFounder(Module* Creator) - : ModeHandler(Creator, "founder", 'q', PARAM_ALWAYS, MODETYPE_CHANNEL), - FounderProtectBase('q', "founder", 386, 387) - { - ModeHandler::list = true; - levelrequired = FOUNDER_VALUE; - m_paramtype = TR_NICK; - } - - void setPrefix(int pfx) - { - prefix = pfx; - } - - unsigned int GetPrefixRank() - { - return FOUNDER_VALUE; - } - - void RemoveMode(Channel* channel, irc::modestacker* stack) - { - FounderProtectBase::RemoveMode(channel, stack); - } - - void RemoveMode(User* user, irc::modestacker* stack) - { - } - - ModResult AccessCheck(User* source, Channel* channel, std::string ¶meter, bool adding) - { - User* theuser = ServerInstance->FindNick(parameter); - // remove own privs? - if (source == theuser && !adding && settings.DeprivSelf) - return MOD_RES_ALLOW; - - if (!adding && FounderProtectBase::CanRemoveOthers(source, channel)) - { - return MOD_RES_PASSTHRU; - } - else - { - source->WriteNumeric(468, "%s %s :Only servers may set channel mode +q", source->nick.c_str(), channel->name.c_str()); - return MOD_RES_DENY; - } - } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - return MODEACTION_ALLOW; - } - - void DisplayList(User* user, Channel* channel) - { - FounderProtectBase::DisplayList(user,channel); - } -}; - -/** Abstraction of FounderProtectBase for channel mode +a - */ -class ChanProtect : public ModeHandler, public FounderProtectBase -{ - public: - ChanProtect(Module* Creator) - : ModeHandler(Creator, "admin", 'a', PARAM_ALWAYS, MODETYPE_CHANNEL), - FounderProtectBase('a',"protected user", 388, 389) - { - ModeHandler::list = true; - levelrequired = PROTECT_VALUE; - m_paramtype = TR_NICK; - } - - void setPrefix(int pfx) - { - prefix = pfx; - } - - - unsigned int GetPrefixRank() - { - return PROTECT_VALUE; - } - - void RemoveMode(Channel* channel, irc::modestacker* stack) - { - FounderProtectBase::RemoveMode(channel, stack); - } - - void RemoveMode(User* user, irc::modestacker* stack) - { - } - - ModResult AccessCheck(User* source, Channel* channel, std::string ¶meter, bool adding) - { - User* theuser = ServerInstance->FindNick(parameter); - // source has +q - if (channel->GetPrefixValue(source) > PROTECT_VALUE) - return MOD_RES_ALLOW; - - // removing own privs? - if (source == theuser && !adding && settings.DeprivSelf) - return MOD_RES_ALLOW; - - if (!adding && FounderProtectBase::CanRemoveOthers(source, channel)) - { - return MOD_RES_PASSTHRU; - } - else - { - source->WriteNumeric(482, "%s %s :You are not a channel founder", source->nick.c_str(), channel->name.c_str()); - return MOD_RES_DENY; - } - } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - return MODEACTION_ALLOW; - } - - void DisplayList(User* user, Channel* channel) - { - FounderProtectBase::DisplayList(user, channel); - } - -}; - -class ModuleChanProtect : public Module -{ - ChanProtect cp; - ChanFounder cf; - public: - ModuleChanProtect() : cp(this), cf(this) - { - } - - void init() - { - /* Load config stuff */ - LoadSettings(); - settings.booting = false; - - ServerInstance->Modules->AddService(cf); - ServerInstance->Modules->AddService(cp); - - Implementation eventlist[] = { I_OnUserPreJoin }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - void LoadSettings() - { - ConfigTag* tag = ServerInstance->Config->ConfValue("chanprotect"); - - settings.FirstInGetsFounder = tag->getBool("noservices"); - - std::string qpre = tag->getString("qprefix"); - char QPrefix = qpre.empty() ? 0 : qpre[0]; - - std::string apre = tag->getString("aprefix"); - char APrefix = apre.empty() ? 0 : apre[0]; - - if ((APrefix && QPrefix) && APrefix == QPrefix) - throw ModuleException("What the smeg, why are both your +q and +a prefixes the same character?"); - - if (settings.booting) - { - if (APrefix && ServerInstance->Modes->FindPrefix(APrefix) && ServerInstance->Modes->FindPrefix(APrefix) != &cp) - throw ModuleException("Looks like the +a prefix you picked for m_chanprotect is already in use. Pick another."); - - if (QPrefix && ServerInstance->Modes->FindPrefix(QPrefix) && ServerInstance->Modes->FindPrefix(QPrefix) != &cf) - throw ModuleException("Looks like the +q prefix you picked for m_chanprotect is already in use. Pick another."); - - cp.setPrefix(APrefix); - cf.setPrefix(QPrefix); - } - settings.DeprivSelf = tag->getBool("deprotectself", true); - settings.DeprivOthers = tag->getBool("deprotectothers", true); - } - - ModResult OnUserPreJoin(User *user, Channel *chan, const char *cname, std::string &privs, const std::string &keygiven) - { - // if the user is the first user into the channel, mark them as the founder, but only if - // the config option for it is set - - if (settings.FirstInGetsFounder && !chan) - privs += 'q'; - - return MOD_RES_PASSTHRU; - } - - Version GetVersion() - { - return Version("Founder and Protect modes (+qa)", VF_VENDOR); - } -}; - -MODULE_INIT(ModuleChanProtect) diff --git a/src/modules/m_check.cpp b/src/modules/m_check.cpp index 07276445f..258352979 100644 --- a/src/modules/m_check.cpp +++ b/src/modules/m_check.cpp @@ -20,16 +20,32 @@ */ -/* $ModDesc: Provides the /CHECK command to retrieve information on a user, channel, hostname or IP address */ - #include "inspircd.h" +#include "listmode.h" /** Handle /CHECK */ class CommandCheck : public Command { + ChanModeReference ban; + UserModeReference snomaskmode; + + std::string GetSnomasks(User* user) + { + std::string ret; + if (snomaskmode) + ret = snomaskmode->GetUserParameter(user); + + if (ret.empty()) + ret = "+"; + return ret; + } + public: - CommandCheck(Module* parent) : Command(parent,"CHECK", 1) + CommandCheck(Module* parent) + : Command(parent,"CHECK", 1) + , ban(parent, "ban") + , snomaskmode(parent, "snomask") { flags_needed = 'o'; syntax = "<nickname>|<ip>|<hostmask>|<channel> <server>"; } @@ -90,26 +106,26 @@ class CommandCheck : public Command user->SendText(checkstr + " realnuh " + targuser->GetFullRealHost()); user->SendText(checkstr + " realname " + targuser->fullname); user->SendText(checkstr + " modes +" + targuser->FormatModes()); - user->SendText(checkstr + " snomasks +" + targuser->FormatNoticeMasks()); + user->SendText(checkstr + " snomasks " + GetSnomasks(targuser)); user->SendText(checkstr + " server " + targuser->server); user->SendText(checkstr + " uid " + targuser->uuid); user->SendText(checkstr + " signon " + timestring(targuser->signon)); user->SendText(checkstr + " nickts " + timestring(targuser->age)); if (loctarg) - user->SendText(checkstr + " lastmsg " + timestring(targuser->idle_lastmsg)); + user->SendText(checkstr + " lastmsg " + timestring(loctarg->idle_lastmsg)); - if (IS_AWAY(targuser)) + if (targuser->IsAway()) { /* user is away */ user->SendText(checkstr + " awaytime " + timestring(targuser->awaytime)); user->SendText(checkstr + " awaymsg " + targuser->awaymsg); } - if (IS_OPER(targuser)) + if (targuser->IsOper()) { OperInfo* oper = targuser->oper; /* user is an oper of type ____ */ - user->SendText(checkstr + " opertype " + oper->NameStr()); + user->SendText(checkstr + " opertype " + oper->name); if (loctarg) { std::string umodes; @@ -190,27 +206,21 @@ class CommandCheck : public Command /* note that unlike /names, we do NOT check +i vs in the channel */ for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++) { - char tmpbuf[MAXBUF]; /* - * Unlike Asuka, I define a clone as coming from the same host. --w00t - */ - snprintf(tmpbuf, MAXBUF, "%-3lu %s%s (%s@%s) %s ", ServerInstance->Users->GlobalCloneCount(i->first), targchan->GetAllPrefixChars(i->first), i->first->nick.c_str(), i->first->ident.c_str(), i->first->dhost.c_str(), i->first->fullname.c_str()); - user->SendText(checkstr + " member " + tmpbuf); + * Unlike Asuka, I define a clone as coming from the same host. --w00t + */ + user->SendText("%s member %-3lu %s%s (%s@%s) %s ", + checkstr.c_str(), ServerInstance->Users->GlobalCloneCount(i->first), + targchan->GetAllPrefixChars(i->first), i->first->nick.c_str(), + i->first->ident.c_str(), i->first->dhost.c_str(), i->first->fullname.c_str()); } - irc::modestacker modestack(true); - for(BanList::iterator b = targchan->bans.begin(); b != targchan->bans.end(); ++b) - { - modestack.Push('b', b->data); - } - std::vector<std::string> stackresult; - std::vector<TranslateType> dummy; - while (modestack.GetStackedLine(stackresult)) - { - creator->ProtoSendMode(user, TYPE_CHANNEL, targchan, stackresult, dummy); - stackresult.clear(); - } - FOREACH_MOD(I_OnSyncChannel,OnSyncChannel(targchan,creator,user)); + // We know that the mode handler for bans is in the core and is derived from ListModeBase + ListModeBase* banlm = static_cast<ListModeBase*>(*ban); + banlm->DoSyncChannel(targchan, creator, user); + + // Show other listmodes as well + FOREACH_MOD(OnSyncChannel, (targchan,creator,user)); dumpExt(user, checkstr, targchan); } else @@ -250,25 +260,19 @@ class CommandCheck : public Command } }; - class ModuleCheck : public Module { - private: CommandCheck mycommand; public: ModuleCheck() : mycommand(this) { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(mycommand); } - ~ModuleCheck() - { - } - void ProtoSendMode(void* uv, TargetTypeFlags, void*, const std::vector<std::string>& result, const std::vector<TranslateType>&) { User* user = (User*)uv; @@ -285,7 +289,7 @@ class ModuleCheck : public Module user->SendText(checkstr); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("CHECK command, view user, channel, IP address or hostname information", VF_VENDOR|VF_OPTCOMMON); } diff --git a/src/modules/m_chghost.cpp b/src/modules/m_chghost.cpp index 08f7f76fa..664508301 100644 --- a/src/modules/m_chghost.cpp +++ b/src/modules/m_chghost.cpp @@ -21,13 +21,10 @@ #include "inspircd.h" -/* $ModDesc: Provides support for the CHGHOST command */ - /** Handle /CHGHOST */ class CommandChghost : public Command { - private: char* hostmap; public: CommandChghost(Module* Creator, char* hmap) : Command(Creator,"CHGHOST", 2), hostmap(hmap) @@ -35,7 +32,7 @@ class CommandChghost : public Command allow_empty_last_param = false; flags_needed = 'o'; syntax = "<nick> <newhost>"; - TRANSLATE3(TR_NICK, TR_TEXT, TR_END); + TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle(const std::vector<std::string> ¶meters, User *user) @@ -44,7 +41,7 @@ class CommandChghost : public Command if (parameters[1].length() > 63) { - user->WriteServ("NOTICE %s :*** CHGHOST: Host too long", user->nick.c_str()); + user->WriteNotice("*** CHGHOST: Host too long"); return CMD_FAILURE; } @@ -52,7 +49,7 @@ class CommandChghost : public Command { if (!hostmap[(unsigned char)*x]) { - user->WriteServ("NOTICE "+user->nick+" :*** CHGHOST: Invalid characters in hostname"); + user->WriteNotice("*** CHGHOST: Invalid characters in hostname"); return CMD_FAILURE; } } @@ -67,7 +64,7 @@ class CommandChghost : public Command if (IS_LOCAL(dest)) { - if ((dest->ChangeDisplayedHost(parameters[1].c_str())) && (!ServerInstance->ULine(user->server))) + if ((dest->ChangeDisplayedHost(parameters[1])) && (!ServerInstance->ULine(user->server))) { // fix by brain - ulines set hosts silently ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used CHGHOST to make the displayed host of "+dest->nick+" become "+dest->dhost); @@ -91,20 +88,19 @@ class ModuleChgHost : public Module { CommandChghost cmd; char hostmap[256]; + public: ModuleChgHost() : cmd(this, hostmap) { } - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); ServerInstance->Modules->AddService(cmd); - Implementation eventlist[] = { I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { std::string hmap = ServerInstance->Config->ConfValue("hostname")->getString("charmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789"); @@ -113,15 +109,10 @@ class ModuleChgHost : public Module hostmap[(unsigned char)*n] = 1; } - ~ModuleChgHost() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for the CHGHOST command", VF_OPTCOMMON | VF_VENDOR); } - }; MODULE_INIT(ModuleChgHost) diff --git a/src/modules/m_chgident.cpp b/src/modules/m_chgident.cpp index 2112e45a3..b9de3e45b 100644 --- a/src/modules/m_chgident.cpp +++ b/src/modules/m_chgident.cpp @@ -22,8 +22,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for the CHGIDENT command */ - /** Handle /CHGIDENT */ class CommandChgident : public Command @@ -34,7 +32,7 @@ class CommandChgident : public Command allow_empty_last_param = false; flags_needed = 'o'; syntax = "<nick> <newident>"; - TRANSLATE3(TR_NICK, TR_TEXT, TR_END); + TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle(const std::vector<std::string> ¶meters, User *user) @@ -49,19 +47,19 @@ class CommandChgident : public Command if (parameters[1].length() > ServerInstance->Config->Limits.IdentMax) { - user->WriteServ("NOTICE %s :*** CHGIDENT: Ident is too long", user->nick.c_str()); + user->WriteNotice("*** CHGIDENT: Ident is too long"); return CMD_FAILURE; } - if (!ServerInstance->IsIdent(parameters[1].c_str())) + if (!ServerInstance->IsIdent(parameters[1])) { - user->WriteServ("NOTICE %s :*** CHGIDENT: Invalid characters in ident", user->nick.c_str()); + user->WriteNotice("*** CHGIDENT: Invalid characters in ident"); return CMD_FAILURE; } if (IS_LOCAL(dest)) { - dest->ChangeIdent(parameters[1].c_str()); + dest->ChangeIdent(parameters[1]); if (!ServerInstance->ULine(user->server)) ServerInstance->SNO->WriteGlobalSno('a', "%s used CHGIDENT to change %s's ident to '%s'", user->nick.c_str(), dest->nick.c_str(), dest->ident.c_str()); @@ -79,7 +77,6 @@ class CommandChgident : public Command } }; - class ModuleChgIdent : public Module { CommandChgident cmd; @@ -89,16 +86,12 @@ public: { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleChgIdent() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for the CHGIDENT command", VF_OPTCOMMON | VF_VENDOR); } @@ -106,4 +99,3 @@ public: }; MODULE_INIT(ModuleChgIdent) - diff --git a/src/modules/m_chgname.cpp b/src/modules/m_chgname.cpp index 73ae3d487..efcce1590 100644 --- a/src/modules/m_chgname.cpp +++ b/src/modules/m_chgname.cpp @@ -20,8 +20,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for the CHGNAME command */ - /** Handle /CHGNAME */ class CommandChgname : public Command @@ -32,7 +30,7 @@ class CommandChgname : public Command allow_empty_last_param = false; flags_needed = 'o'; syntax = "<nick> <newname>"; - TRANSLATE3(TR_NICK, TR_TEXT, TR_END); + TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle(const std::vector<std::string> ¶meters, User *user) @@ -47,19 +45,19 @@ class CommandChgname : public Command if (parameters[1].empty()) { - user->WriteServ("NOTICE %s :*** CHGNAME: GECOS must be specified", user->nick.c_str()); + user->WriteNotice("*** CHGNAME: GECOS must be specified"); return CMD_FAILURE; } if (parameters[1].length() > ServerInstance->Config->Limits.MaxGecos) { - user->WriteServ("NOTICE %s :*** CHGNAME: GECOS too long", user->nick.c_str()); + user->WriteNotice("*** CHGNAME: GECOS too long"); return CMD_FAILURE; } if (IS_LOCAL(dest)) { - dest->ChangeName(parameters[1].c_str()); + dest->ChangeName(parameters[1]); ServerInstance->SNO->WriteGlobalSno('a', "%s used CHGNAME to change %s's GECOS to '%s'", user->nick.c_str(), dest->nick.c_str(), dest->fullname.c_str()); } @@ -75,7 +73,6 @@ class CommandChgname : public Command } }; - class ModuleChgName : public Module { CommandChgname cmd; @@ -85,16 +82,12 @@ public: { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleChgName() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for the CHGNAME command", VF_OPTCOMMON | VF_VENDOR); } diff --git a/src/modules/m_cloaking.cpp b/src/modules/m_cloaking.cpp index 105d68833..4e203d14c 100644 --- a/src/modules/m_cloaking.cpp +++ b/src/modules/m_cloaking.cpp @@ -24,16 +24,10 @@ #include "inspircd.h" -#include "hash.h" - -/* $ModDesc: Provides masking of user hostnames */ +#include "modules/hash.h" enum CloakMode { - /** 1.2-compatible host-based cloak */ - MODE_COMPAT_HOST, - /** 1.2-compatible IP-only cloak */ - MODE_COMPAT_IPONLY, /** 2.0 cloak of "half" of the hostname plus the full IP hash */ MODE_HALF_CLOAK, /** 2.0 cloak of IP hash, split at 2 common CIDR range points */ @@ -49,7 +43,6 @@ class CloakUser : public ModeHandler { public: LocalStringExt ext; - std::string debounce_uid; time_t debounce_ts; int debounce_count; @@ -70,7 +63,7 @@ class CloakUser : public ModeHandler */ if (!user) { - dest->SetMode('x',adding); + dest->SetMode(this, adding); return MODEACTION_ALLOW; } @@ -87,7 +80,7 @@ class CloakUser : public ModeHandler debounce_ts = ServerInstance->Time(); } - if (adding == user->IsModeSet('x')) + if (adding == user->IsModeSet(this)) return MODEACTION_DENY; /* don't allow this user to spam modechanges */ @@ -107,7 +100,7 @@ class CloakUser : public ModeHandler if (cloak) { user->ChangeDisplayedHost(cloak->c_str()); - user->SetMode('x',true); + user->SetMode(this, true); return MODEACTION_ALLOW; } else @@ -118,12 +111,11 @@ class CloakUser : public ModeHandler /* User is removing the mode, so restore their real host * and make it match the displayed one. */ - user->SetMode('x',false); + user->SetMode(this, false); user->ChangeDisplayedHost(user->host.c_str()); return MODEACTION_ALLOW; } } - }; class CommandCloak : public Command @@ -147,7 +139,6 @@ class ModuleCloaking : public Module std::string prefix; std::string suffix; std::string key; - unsigned int compatkey[4]; const char* xtab[4]; dynamic_reference<HashProvider> Hash; @@ -155,16 +146,13 @@ class ModuleCloaking : public Module { } - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); ServerInstance->Modules->AddService(cu); ServerInstance->Modules->AddService(ck); ServerInstance->Modules->AddService(cu.ext); - - Implementation eventlist[] = { I_OnRehash, I_OnCheckBan, I_OnUserConnect, I_OnChangeHost }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } /** This function takes a domain name string and returns just the last two domain parts, @@ -224,63 +212,6 @@ class ModuleCloaking : public Module return rv; } - std::string CompatCloak4(const char* ip) - { - irc::sepstream seps(ip, '.'); - std::string octet[4]; - int i[4]; - - for (int j = 0; j < 4; j++) - { - seps.GetToken(octet[j]); - i[j] = atoi(octet[j].c_str()); - } - - octet[3] = octet[0] + "." + octet[1] + "." + octet[2] + "." + octet[3]; - octet[2] = octet[0] + "." + octet[1] + "." + octet[2]; - octet[1] = octet[0] + "." + octet[1]; - - /* Reset the Hash module and send it our IV */ - - std::string rv; - - /* Send the Hash module a different hex table for each octet group's Hash sum */ - for (int k = 0; k < 4; k++) - { - rv.append(Hash->sumIV(compatkey, xtab[(compatkey[k]+i[k]) % 4], octet[k]).substr(0,6)); - if (k < 3) - rv.append("."); - } - /* Stick them all together */ - return rv; - } - - std::string CompatCloak6(const char* ip) - { - std::vector<std::string> hashies; - std::string item; - int rounds = 0; - - /* Reset the Hash module and send it our IV */ - - for (const char* input = ip; *input; input++) - { - item += *input; - if (item.length() > 7) - { - hashies.push_back(Hash->sumIV(compatkey, xtab[(compatkey[0]+rounds) % 4], item).substr(0,8)); - item.clear(); - } - rounds++; - } - if (!item.empty()) - { - hashies.push_back(Hash->sumIV(compatkey, xtab[(compatkey[0]+rounds) % 4], item).substr(0,8)); - } - /* Stick them all together */ - return irc::stringjoiner(":", hashies, 0, hashies.size() - 1).GetJoined(); - } - std::string SegmentIP(const irc::sockets::sockaddrs& ip, bool full) { std::string bindata; @@ -348,7 +279,7 @@ class ModuleCloaking : public Module return rv; } - ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask) + ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask) CXX11_OVERRIDE { LocalUser* lu = IS_LOCAL(user); if (!lu) @@ -359,9 +290,8 @@ class ModuleCloaking : public Module /* Check if they have a cloaked host, but are not using it */ if (cloak && *cloak != user->dhost) { - char cmask[MAXBUF]; - snprintf(cmask, MAXBUF, "%s!%s@%s", user->nick.c_str(), user->ident.c_str(), cloak->c_str()); - if (InspIRCd::Match(cmask,mask)) + const std::string cloakMask = user->nick + "!" + user->ident + "@" + *cloak; + if (InspIRCd::Match(cloakMask, mask)) return MOD_RES_DENY; } return MOD_RES_PASSTHRU; @@ -375,32 +305,22 @@ class ModuleCloaking : public Module // this unsets umode +x on every host change. If we are actually doing a +x // mode change, we will call SetMode back to true AFTER the host change is done. - void OnChangeHost(User* u, const std::string& host) + void OnChangeHost(User* u, const std::string& host) CXX11_OVERRIDE { - if(u->IsModeSet('x')) + if (u->IsModeSet(cu)) { - u->SetMode('x', false); - u->WriteServ("MODE %s -x", u->nick.c_str()); + u->SetMode(cu, false); + u->WriteServ("MODE %s -%c", u->nick.c_str(), cu.GetModeChar()); } } - ~ModuleCloaking() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { std::string testcloak = "broken"; if (Hash) { switch (mode) { - case MODE_COMPAT_HOST: - testcloak = prefix + "-" + Hash->sumIV(compatkey, xtab[0], "*").substr(0,10); - break; - case MODE_COMPAT_IPONLY: - testcloak = Hash->sumIV(compatkey, xtab[0], "*").substr(0,10); - break; case MODE_HALF_CLOAK: testcloak = prefix + SegmentCloak("*", 3, 8) + suffix; break; @@ -411,82 +331,23 @@ class ModuleCloaking : public Module return Version("Provides masking of user hostnames", VF_COMMON|VF_VENDOR, testcloak); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("cloak"); prefix = tag->getString("prefix"); suffix = tag->getString("suffix", ".IP"); std::string modestr = tag->getString("mode"); - if (modestr == "compat-host") - mode = MODE_COMPAT_HOST; - else if (modestr == "compat-ip") - mode = MODE_COMPAT_IPONLY; - else if (modestr == "half") + if (modestr == "half") mode = MODE_HALF_CLOAK; else if (modestr == "full") mode = MODE_OPAQUE; else - throw ModuleException("Bad value for <cloak:mode>; must be one of compat-host, compat-ip, half, full"); - - if (mode == MODE_COMPAT_HOST || mode == MODE_COMPAT_IPONLY) - { - bool lowercase = tag->getBool("lowercase"); - - /* These are *not* using the need_positive parameter of ReadInteger - - * that will limit the valid values to only the positive values in a - * signed int. Instead, accept any value that fits into an int and - * cast it to an unsigned int. That will, a bit oddly, give us the full - * spectrum of an unsigned integer. - Special - * - * We must limit the keys or else we get different results on - * amd64/x86 boxes. - psychon */ - const unsigned int limit = 0x80000000; - compatkey[0] = (unsigned int) tag->getInt("key1"); - compatkey[1] = (unsigned int) tag->getInt("key2"); - compatkey[2] = (unsigned int) tag->getInt("key3"); - compatkey[3] = (unsigned int) tag->getInt("key4"); - - if (!lowercase) - { - xtab[0] = "F92E45D871BCA630"; - xtab[1] = "A1B9D80C72E653F4"; - xtab[2] = "1ABC078934DEF562"; - xtab[3] = "ABCDEF5678901234"; - } - else - { - xtab[0] = "f92e45d871bca630"; - xtab[1] = "a1b9d80c72e653f4"; - xtab[2] = "1abc078934def562"; - xtab[3] = "abcdef5678901234"; - } + throw ModuleException("Bad value for <cloak:mode>; must be half or full"); - if (prefix.empty()) - prefix = ServerInstance->Config->Network; - - if (!compatkey[0] || !compatkey[1] || !compatkey[2] || !compatkey[3] || - compatkey[0] >= limit || compatkey[1] >= limit || compatkey[2] >= limit || compatkey[3] >= limit) - { - std::string detail; - if (!compatkey[0] || compatkey[0] >= limit) - detail = "<cloak:key1> is not valid, it may be set to a too high/low value, or it may not exist."; - else if (!compatkey[1] || compatkey[1] >= limit) - detail = "<cloak:key2> is not valid, it may be set to a too high/low value, or it may not exist."; - else if (!compatkey[2] || compatkey[2] >= limit) - detail = "<cloak:key3> is not valid, it may be set to a too high/low value, or it may not exist."; - else if (!compatkey[3] || compatkey[3] >= limit) - detail = "<cloak:key4> is not valid, it may be set to a too high/low value, or it may not exist."; - - throw ModuleException("You have not defined cloak keys for m_cloaking!!! THIS IS INSECURE AND SHOULD BE CHECKED! - " + detail); - } - } - else - { - key = tag->getString("key"); - if (key.empty() || key == "secret") - throw ModuleException("You have not defined cloak keys for m_cloaking. Define <cloak:key> as a network-wide secret."); - } + key = tag->getString("key"); + if (key.empty() || key == "secret") + throw ModuleException("You have not defined cloak keys for m_cloaking. Define <cloak:key> as a network-wide secret."); } std::string GenCloak(const irc::sockets::sockaddrs& ip, const std::string& ipstr, const std::string& host) @@ -495,29 +356,6 @@ class ModuleCloaking : public Module switch (mode) { - case MODE_COMPAT_HOST: - { - if (ipstr != host) - { - std::string tail = LastTwoDomainParts(host); - - // xtab is not used here due to a bug in 1.2 cloaking - chost = prefix + "-" + Hash->sumIV(compatkey, "0123456789abcdef", host).substr(0,8) + tail; - - /* Fix by brain - if the cloaked host is > the max length of a host (64 bytes - * according to the DNS RFC) then they get cloaked as an IP. - */ - if (chost.length() <= 64) - break; - } - // fall through to IP cloak - } - case MODE_COMPAT_IPONLY: - if (ip.sa.sa_family == AF_INET6) - chost = CompatCloak6(ipstr.c_str()); - else - chost = CompatCloak4(ipstr.c_str()); - break; case MODE_HALF_CLOAK: { if (ipstr != host) @@ -533,7 +371,7 @@ class ModuleCloaking : public Module return chost; } - void OnUserConnect(LocalUser* dest) + void OnUserConnect(LocalUser* dest) CXX11_OVERRIDE { std::string* cloak = cu.ext.get(dest); if (cloak) @@ -554,7 +392,7 @@ CmdResult CommandCloak::Handle(const std::vector<std::string> ¶meters, User else cloak = mod->GenCloak(sa, "", parameters[0]); - user->WriteServ("NOTICE %s :*** Cloak for %s is %s", user->nick.c_str(), parameters[0].c_str(), cloak.c_str()); + user->WriteNotice("*** Cloak for " + parameters[0] + " is " + cloak); return CMD_SUCCESS; } diff --git a/src/modules/m_clones.cpp b/src/modules/m_clones.cpp index 92b1bda78..ecdea5be0 100644 --- a/src/modules/m_clones.cpp +++ b/src/modules/m_clones.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides the /CLONES command to retrieve information on clones. */ - /** Handle /CLONES */ class CommandClones : public Command @@ -63,31 +61,23 @@ class CommandClones : public Command } }; - class ModuleClones : public Module { - private: CommandClones cmd; public: ModuleClones() : cmd(this) { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleClones() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides the /CLONES command to retrieve information on clones.", VF_VENDOR); } - - }; MODULE_INIT(ModuleClones) diff --git a/src/modules/m_close.cpp b/src/modules/m_close.cpp index 8b0ea3417..806a88640 100644 --- a/src/modules/m_close.cpp +++ b/src/modules/m_close.cpp @@ -20,8 +20,6 @@ #include "inspircd.h" -/* $ModDesc: Provides /CLOSE functionality */ - /** Handle /CLOSE */ class CommandClose : public Command @@ -50,13 +48,14 @@ class CommandClose : public Command int total = 0; for (std::map<std::string,int>::iterator ci = closed.begin(); ci != closed.end(); ci++) { - src->WriteServ("NOTICE %s :*** Closed %d unknown connection%s from [%s]",src->nick.c_str(),(*ci).second,((*ci).second>1)?"s":"",(*ci).first.c_str()); - total += (*ci).second; + src->WriteNotice("*** Closed " + ConvToStr(ci->second) + " unknown " + (ci->second == 1 ? "connection" : "connections") + + " from [" + ci->first + "]"); + total += ci->second; } if (total) - src->WriteServ("NOTICE %s :*** %i unknown connection%s closed",src->nick.c_str(),total,(total>1)?"s":""); + src->WriteNotice("*** " + ConvToStr(total) + " unknown " + (total == 1 ? "connection" : "connections") + " closed"); else - src->WriteServ("NOTICE %s :*** No unknown connections found",src->nick.c_str()); + src->WriteNotice("*** No unknown connections found"); return CMD_SUCCESS; } @@ -71,16 +70,12 @@ class ModuleClose : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleClose() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides /CLOSE functionality", VF_VENDOR); } diff --git a/src/modules/m_commonchans.cpp b/src/modules/m_commonchans.cpp index afa17add4..5871f5f9d 100644 --- a/src/modules/m_commonchans.cpp +++ b/src/modules/m_commonchans.cpp @@ -19,8 +19,6 @@ #include "inspircd.h" -/* $ModDesc: Adds user mode +c, which if set, users must be on a common channel with you to private message you */ - /** Handles user mode +c */ class PrivacyMode : public SimpleUserModeHandler @@ -37,28 +35,22 @@ class ModulePrivacyMode : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(pm); - Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - virtual ~ModulePrivacyMode() - { } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Adds user mode +c, which if set, users must be on a common channel with you to private message you", VF_VENDOR); } - virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { if (target_type == TYPE_USER) { User* t = (User*)dest; - if (!IS_OPER(user) && (t->IsModeSet('c')) && (!ServerInstance->ULine(user->server)) && !user->SharesChannelWith(t)) + if (!user->IsOper() && (t->IsModeSet(pm)) && (!ServerInstance->ULine(user->server)) && !user->SharesChannelWith(t)) { user->WriteNumeric(ERR_CANTSENDTOUSER, "%s %s :You are not permitted to send private messages to this user (+c set)", user->nick.c_str(), t->nick.c_str()); return MOD_RES_DENY; @@ -66,12 +58,6 @@ class ModulePrivacyMode : public Module } return MOD_RES_PASSTHRU; } - - virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreMessage(user, dest, target_type, text, status, exempt_list); - } }; - MODULE_INIT(ModulePrivacyMode) diff --git a/src/modules/m_conn_join.cpp b/src/modules/m_conn_join.cpp index 6b13ab1aa..fdcf82dcc 100644 --- a/src/modules/m_conn_join.cpp +++ b/src/modules/m_conn_join.cpp @@ -22,45 +22,37 @@ #include "inspircd.h" -/* $ModDesc: Forces users to join the specified channel(s) on connect */ - class ModuleConnJoin : public Module { public: - void init() - { - Implementation eventlist[] = { I_OnPostConnect }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - void Prioritize() { ServerInstance->Modules->SetPriority(this, I_OnPostConnect, PRIORITY_LAST); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Forces users to join the specified channel(s) on connect", VF_VENDOR); } - void OnPostConnect(User* user) + void OnPostConnect(User* user) CXX11_OVERRIDE { - if (!IS_LOCAL(user)) + LocalUser* localuser = IS_LOCAL(user); + if (!localuser) return; std::string chanlist = ServerInstance->Config->ConfValue("autojoin")->getString("channel"); - chanlist = user->GetClass()->config->getString("autojoin", chanlist); + chanlist = localuser->GetClass()->config->getString("autojoin", chanlist); irc::commasepstream chans(chanlist); std::string chan; while (chans.GetToken(chan)) { - if (ServerInstance->IsChannel(chan.c_str(), ServerInstance->Config->Limits.ChanMax)) - Channel::JoinUser(user, chan.c_str(), false, "", false, ServerInstance->Time()); + if (ServerInstance->IsChannel(chan)) + Channel::JoinUser(localuser, chan); } } }; - MODULE_INIT(ModuleConnJoin) diff --git a/src/modules/m_conn_umodes.cpp b/src/modules/m_conn_umodes.cpp index a21462ddf..1e3ea1a49 100644 --- a/src/modules/m_conn_umodes.cpp +++ b/src/modules/m_conn_umodes.cpp @@ -22,32 +22,21 @@ #include "inspircd.h" -/* $ModDesc: Sets (and unsets) modes on users when they connect */ - class ModuleModesOnConnect : public Module { public: - void init() - { - ServerInstance->Modules->Attach(I_OnUserConnect, this); - } - void Prioritize() { // for things like +x on connect, important, otherwise we have to resort to config order (bleh) -- w00t ServerInstance->Modules->SetPriority(this, I_OnUserConnect, PRIORITY_FIRST); } - virtual ~ModuleModesOnConnect() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Sets (and unsets) modes on users when they connect", VF_VENDOR); } - virtual void OnUserConnect(LocalUser* user) + void OnUserConnect(LocalUser* user) CXX11_OVERRIDE { // Backup and zero out the disabled usermodes, so that we can override them here. char save[64]; @@ -62,26 +51,14 @@ class ModuleModesOnConnect : public Module std::string buf; std::stringstream ss(ThisModes); - std::vector<std::string> tokens; - - // split ThisUserModes into modes and mode params - while (ss >> buf) - tokens.push_back(buf); - std::vector<std::string> modes; modes.push_back(user->nick); - modes.push_back(tokens[0]); - if (tokens.size() > 1) - { - // process mode params - for (unsigned int k = 1; k < tokens.size(); k++) - { - modes.push_back(tokens[k]); - } - } + // split ThisUserModes into modes and mode params + while (ss >> buf) + modes.push_back(buf); - ServerInstance->Parser->CallHandler("MODE", modes, user); + ServerInstance->Modes->Process(modes, user); } memcpy(ServerInstance->Config->DisabledUModes, save, 64); diff --git a/src/modules/m_conn_waitpong.cpp b/src/modules/m_conn_waitpong.cpp index 1d48220a6..c15205df3 100644 --- a/src/modules/m_conn_waitpong.cpp +++ b/src/modules/m_conn_waitpong.cpp @@ -24,8 +24,6 @@ #include "inspircd.h" -/* $ModDesc: Forces connecting clients to send a PONG message back to the server before they can complete their connection */ - class ModuleWaitPong : public Module { bool sendsnotice; @@ -38,35 +36,33 @@ class ModuleWaitPong : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(ext); OnRehash(NULL); - Implementation eventlist[] = { I_OnUserRegister, I_OnCheckReady, I_OnPreCommand, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("waitpong"); sendsnotice = tag->getBool("sendsnotice", true); killonbadreply = tag->getBool("killonbadreply", true); } - ModResult OnUserRegister(LocalUser* user) + ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE { std::string pingrpl = ServerInstance->GenRandomStr(10); user->Write("PING :%s", pingrpl.c_str()); if(sendsnotice) - user->WriteServ("NOTICE %s :*** If you are having problems connecting due to ping timeouts, please type /quote PONG %s or /raw PONG %s now.", user->nick.c_str(), pingrpl.c_str(), pingrpl.c_str()); + user->WriteNotice("*** If you are having problems connecting due to ping timeouts, please type /quote PONG " + pingrpl + " or /raw PONG " + pingrpl + " now."); ext.set(user, pingrpl); return MOD_RES_PASSTHRU; } - ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser* user, bool validated, const std::string &original_line) + ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser* user, bool validated, const std::string &original_line) CXX11_OVERRIDE { if (command == "PONG") { @@ -90,20 +86,15 @@ class ModuleWaitPong : public Module return MOD_RES_PASSTHRU; } - ModResult OnCheckReady(LocalUser* user) + ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE { return ext.get(user) ? MOD_RES_DENY : MOD_RES_PASSTHRU; } - ~ModuleWaitPong() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Require pong prior to registration", VF_VENDOR); } - }; MODULE_INIT(ModuleWaitPong) diff --git a/src/modules/m_connectban.cpp b/src/modules/m_connectban.cpp index 26120add9..227373a36 100644 --- a/src/modules/m_connectban.cpp +++ b/src/modules/m_connectban.cpp @@ -20,55 +20,36 @@ #include "inspircd.h" #include "xline.h" -/* $ModDesc: Throttles the connections of IP ranges who try to connect flood. */ - class ModuleConnectBan : public Module { - private: clonemap connects; unsigned int threshold; unsigned int banduration; unsigned int ipv4_cidr; unsigned int ipv6_cidr; + public: - void init() + void init() CXX11_OVERRIDE { - Implementation eventlist[] = { I_OnSetUserIP, I_OnGarbageCollect, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); } - virtual ~ModuleConnectBan() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Throttles the connections of IP ranges who try to connect flood.", VF_VENDOR); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("connectban"); - ipv4_cidr = tag->getInt("ipv4cidr", 32); - if (ipv4_cidr == 0) - ipv4_cidr = 32; - - ipv6_cidr = tag->getInt("ipv6cidr", 128); - if (ipv6_cidr == 0) - ipv6_cidr = 128; - - threshold = tag->getInt("threshold", 10); - if (threshold == 0) - threshold = 10; - - banduration = ServerInstance->Duration(tag->getString("duration", "10m")); - if (banduration == 0) - banduration = 10*60; + ipv4_cidr = tag->getInt("ipv4cidr", 32, 1, 32); + ipv6_cidr = tag->getInt("ipv6cidr", 128, 1, 128); + threshold = tag->getInt("threshold", 10, 1); + banduration = tag->getDuration("duration", 10*60, 1); } - virtual void OnSetUserIP(LocalUser* u) + void OnSetUserIP(LocalUser* u) CXX11_OVERRIDE { if (u->exempt) return; @@ -117,9 +98,9 @@ class ModuleConnectBan : public Module } } - virtual void OnGarbageCollect() + void OnGarbageCollect() { - ServerInstance->Logs->Log("m_connectban",DEBUG, "Clearing map."); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Clearing map."); connects.clear(); } }; diff --git a/src/modules/m_connflood.cpp b/src/modules/m_connflood.cpp index f77691e32..23b570bf6 100644 --- a/src/modules/m_connflood.cpp +++ b/src/modules/m_connflood.cpp @@ -21,11 +21,8 @@ #include "inspircd.h" -/* $ModDesc: Connection throttle */ - class ModuleConnFlood : public Module { -private: int seconds, timeout, boot_wait; unsigned int conns; unsigned int maxconns; @@ -39,14 +36,12 @@ public: { } - void init() + void init() CXX11_OVERRIDE { InitConf(); - Implementation eventlist[] = { I_OnRehash, I_OnUserRegister }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Connection throttle", VF_VENDOR); } @@ -67,7 +62,7 @@ public: first = ServerInstance->Time(); } - virtual ModResult OnUserRegister(LocalUser* user) + ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE { if (user->exempt) return MOD_RES_PASSTHRU; @@ -115,7 +110,7 @@ public: return MOD_RES_PASSTHRU; } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { InitConf(); } diff --git a/src/modules/m_customprefix.cpp b/src/modules/m_customprefix.cpp index dfc60e082..bda11e8b3 100644 --- a/src/modules/m_customprefix.cpp +++ b/src/modules/m_customprefix.cpp @@ -19,14 +19,12 @@ #include "inspircd.h" -/* $ModDesc: Allows custom prefix modes to be created. */ - class CustomPrefixMode : public ModeHandler { public: reference<ConfigTag> tag; - int rank; bool depriv; + CustomPrefixMode(Module* parent, ConfigTag* Tag) : ModeHandler(parent, Tag->getString("name"), 0, PARAM_ALWAYS, MODETYPE_CHANNEL), tag(Tag) { @@ -36,16 +34,11 @@ class CustomPrefixMode : public ModeHandler prefix = v.c_str()[0]; v = tag->getString("letter"); mode = v.c_str()[0]; - rank = tag->getInt("rank"); - levelrequired = tag->getInt("ranktoset", rank); + prefixrank = tag->getInt("rank"); + levelrequired = tag->getInt("ranktoset", prefixrank); depriv = tag->getBool("depriv", true); } - unsigned int GetPrefixRank() - { - return rank; - } - ModResult AccessCheck(User* src, Channel*, std::string& value, bool adding) { if (!adding && src->nick == value && depriv) @@ -53,40 +46,6 @@ class CustomPrefixMode : public ModeHandler return MOD_RES_PASSTHRU; } - void RemoveMode(Channel* channel, irc::modestacker* stack) - { - const UserMembList* cl = channel->GetUsers(); - std::vector<std::string> mode_junk; - mode_junk.push_back(channel->name); - irc::modestacker modestack(false); - std::deque<std::string> stackresult; - - for (UserMembCIter i = cl->begin(); i != cl->end(); i++) - { - if (i->second->hasMode(mode)) - { - if (stack) - stack->Push(this->GetModeChar(), i->first->nick); - else - modestack.Push(this->GetModeChar(), i->first->nick); - } - } - - if (stack) - return; - - while (modestack.GetStackedLine(stackresult)) - { - mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end()); - ServerInstance->SendMode(mode_junk, ServerInstance->FakeClient); - mode_junk.erase(mode_junk.begin() + 1, mode_junk.end()); - } - } - - void RemoveMode(User* user, irc::modestacker* stack) - { - } - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { return MODEACTION_ALLOW; @@ -97,11 +56,7 @@ class ModuleCustomPrefix : public Module { std::vector<CustomPrefixMode*> modes; public: - ModuleCustomPrefix() - { - } - - void init() + void init() CXX11_OVERRIDE { ConfigTagList tags = ServerInstance->Config->ConfTags("customprefix"); while (tags.first != tags.second) @@ -110,7 +65,7 @@ class ModuleCustomPrefix : public Module tags.first++; CustomPrefixMode* mh = new CustomPrefixMode(this, tag); modes.push_back(mh); - if (mh->rank <= 0) + if (mh->GetPrefixRank() == 0) throw ModuleException("Rank must be specified for prefix at " + tag->getTagLocation()); if (!isalpha(mh->GetModeChar())) throw ModuleException("Mode must be a letter for prefix at " + tag->getTagLocation()); @@ -131,7 +86,7 @@ class ModuleCustomPrefix : public Module delete *i; } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides custom prefix channel modes", VF_VENDOR); } diff --git a/src/modules/m_customtitle.cpp b/src/modules/m_customtitle.cpp index c65645bc9..5a3a925a3 100644 --- a/src/modules/m_customtitle.cpp +++ b/src/modules/m_customtitle.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides the TITLE command which allows setting of CUSTOM WHOIS TITLE line */ - /** Handle /TITLE */ class CommandTitle : public Command @@ -35,27 +33,10 @@ class CommandTitle : public Command syntax = "<user> <password>"; } - bool OneOfMatches(const char* host, const char* ip, const char* hostlist) - { - std::stringstream hl(hostlist); - std::string xhost; - while (hl >> xhost) - { - if (InspIRCd::Match(host, xhost, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(ip, xhost, ascii_case_insensitive_map)) - { - return true; - } - } - return false; - } - CmdResult Handle(const std::vector<std::string> ¶meters, User* user) { - char TheHost[MAXBUF]; - char TheIP[MAXBUF]; - - snprintf(TheHost,MAXBUF,"%s@%s",user->ident.c_str(), user->host.c_str()); - snprintf(TheIP, MAXBUF,"%s@%s",user->ident.c_str(), user->GetIPString()); + const std::string userHost = user->ident + "@" + user->host; + const std::string userIP = user->ident + "@" + user->GetIPString(); ConfigTagList tags = ServerInstance->Config->ConfTags("title"); for (ConfigIter i = tags.first; i != tags.second; ++i) @@ -67,7 +48,8 @@ class CommandTitle : public Command std::string title = i->second->getString("title"); std::string vhost = i->second->getString("vhost"); - if (Name == parameters[0] && !ServerInstance->PassCompare(user, pass, parameters[1], hash) && OneOfMatches(TheHost,TheIP,host.c_str()) && !title.empty()) + if (Name == parameters[0] && !ServerInstance->PassCompare(user, pass, parameters[1], hash) && + InspIRCd::MatchMask(host, userHost, userIP) && !title.empty()) { ctitle.set(user, title); @@ -76,13 +58,13 @@ class CommandTitle : public Command if (!vhost.empty()) user->ChangeDisplayedHost(vhost.c_str()); - user->WriteServ("NOTICE %s :Custom title set to '%s'",user->nick.c_str(), title.c_str()); + user->WriteNotice("Custom title set to '" + title + "'"); return CMD_SUCCESS; } } - user->WriteServ("NOTICE %s :Invalid title credentials",user->nick.c_str()); + user->WriteNotice("Invalid title credentials"); return CMD_SUCCESS; } @@ -97,15 +79,14 @@ class ModuleCustomTitle : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); ServerInstance->Modules->AddService(cmd.ctitle); - ServerInstance->Modules->Attach(I_OnWhoisLine, this); } // :kenny.chatspike.net 320 Brain Azhrarn :is getting paid to play games. - ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text) + ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text) CXX11_OVERRIDE { /* We use this and not OnWhois because this triggers for remote, too */ if (numeric == 312) @@ -121,11 +102,7 @@ class ModuleCustomTitle : public Module return MOD_RES_PASSTHRU; } - ~ModuleCustomTitle() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Custom Title for users", VF_OPTCOMMON | VF_VENDOR); } diff --git a/src/modules/m_cycle.cpp b/src/modules/m_cycle.cpp index 383e7b5a2..61deaf58b 100644 --- a/src/modules/m_cycle.cpp +++ b/src/modules/m_cycle.cpp @@ -20,20 +20,18 @@ #include "inspircd.h" -/* $ModDesc: Provides command CYCLE, acts as a server-side HOP command to part and rejoin a channel. */ - /** Handle /CYCLE */ -class CommandCycle : public Command +class CommandCycle : public SplitCommand { public: - CommandCycle(Module* Creator) : Command(Creator,"CYCLE", 1) + CommandCycle(Module* Creator) + : SplitCommand(Creator, "CYCLE", 1) { Penalty = 3; syntax = "<channel> :[reason]"; - TRANSLATE3(TR_TEXT, TR_TEXT, TR_END); } - CmdResult Handle (const std::vector<std::string> ¶meters, User *user) + CmdResult HandleLocal(const std::vector<std::string> ¶meters, LocalUser* user) { Channel* channel = ServerInstance->FindChan(parameters[0]); std::string reason = ConvToStr("Cycling"); @@ -60,13 +58,12 @@ class CommandCycle : public Command if (channel->GetPrefixValue(user) < VOICE_VALUE && channel->IsBanned(user)) { /* banned, boned. drop the message. */ - user->WriteServ("NOTICE "+user->nick+" :*** You may not cycle, as you are banned on channel " + channel->name); + user->WriteNotice("*** You may not cycle, as you are banned on channel " + channel->name); return CMD_FAILURE; } channel->PartUser(user, reason); - - Channel::JoinUser(user, parameters[0].c_str(), true, "", false, ServerInstance->Time()); + Channel::JoinUser(user, parameters[0], true); } return CMD_SUCCESS; @@ -84,26 +81,22 @@ class CommandCycle : public Command class ModuleCycle : public Module { CommandCycle cmd; + public: ModuleCycle() : cmd(this) { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleCycle() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides command CYCLE, acts as a server-side HOP command to part and rejoin a channel.", VF_VENDOR); } - }; MODULE_INIT(ModuleCycle) diff --git a/src/modules/m_dccallow.cpp b/src/modules/m_dccallow.cpp index de7b6b7bf..d65537537 100644 --- a/src/modules/m_dccallow.cpp +++ b/src/modules/m_dccallow.cpp @@ -25,8 +25,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for the /DCCALLOW command */ - class BannedFileList { public: @@ -152,10 +150,10 @@ class CommandDccallow : public Command std::string mask = target->nick+"!"+target->ident+"@"+target->dhost; std::string default_length = ServerInstance->Config->ConfValue("dccallow")->getString("length"); - long length; + unsigned long length; if (parameters.size() < 2) { - length = ServerInstance->Duration(default_length); + length = InspIRCd::Duration(default_length); } else if (!atoi(parameters[1].c_str())) { @@ -163,7 +161,7 @@ class CommandDccallow : public Command } else { - length = ServerInstance->Duration(parameters[1]); + length = InspIRCd::Duration(parameters[1]); } if (!ServerInstance->IsValidMask(mask)) @@ -247,30 +245,28 @@ class CommandDccallow : public Command class ModuleDCCAllow : public Module { CommandDccallow cmd; - public: + public: ModuleDCCAllow() : cmd(this) { ext = NULL; } - void init() + void init() CXX11_OVERRIDE { ext = new SimpleExtItem<dccallowlist>("dccallow", this); ServerInstance->Modules->AddService(*ext); ServerInstance->Modules->AddService(cmd); ReadFileConf(); - Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserQuit, I_OnUserPostNick, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ReadFileConf(); } - virtual void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message) + void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message) CXX11_OVERRIDE { dccallowlist* udl = ext->get(user); @@ -287,17 +283,12 @@ class ModuleDCCAllow : public Module RemoveNick(user); } - virtual void OnUserPostNick(User* user, const std::string &oldnick) + void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE { RemoveNick(user); } - virtual ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreNotice(user, dest, target_type, text, status, exempt_list); - } - - virtual ModResult OnUserPreNotice(User* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; @@ -365,16 +356,16 @@ class ModuleDCCAllow : public Module if ((!found) && (defaultaction == "allow")) return MOD_RES_PASSTHRU; - user->WriteServ("NOTICE %s :The user %s is not accepting DCC SENDs from you. Your file %s was not sent.", user->nick.c_str(), u->nick.c_str(), filename.c_str()); - u->WriteServ("NOTICE %s :%s (%s@%s) attempted to send you a file named %s, which was blocked.", u->nick.c_str(), user->nick.c_str(), user->ident.c_str(), user->dhost.c_str(), filename.c_str()); - u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick.c_str(), user->nick.c_str()); + user->WriteNotice("The user " + u->nick + " is not accepting DCC SENDs from you. Your file " + filename + " was not sent."); + u->WriteNotice(user->nick + " (" + user->ident + "@" + user->dhost + ") attempted to send you a file named " + filename + ", which was blocked."); + u->WriteNotice("If you trust " + user->nick + " and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system."); return MOD_RES_DENY; } else if ((type == "CHAT") && (blockchat)) { - user->WriteServ("NOTICE %s :The user %s is not accepting DCC CHAT requests from you.", user->nick.c_str(), u->nick.c_str()); - u->WriteServ("NOTICE %s :%s (%s@%s) attempted to initiate a DCC CHAT session, which was blocked.", u->nick.c_str(), user->nick.c_str(), user->ident.c_str(), user->dhost.c_str()); - u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick.c_str(), user->nick.c_str()); + user->WriteNotice("The user " + u->nick + " is not accepting DCC CHAT requests from you."); + u->WriteNotice(user->nick + " (" + user->ident + "@" + user->dhost + ") attempted to initiate a DCC CHAT session, which was blocked."); + u->WriteNotice("If you trust " + user->nick + " and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system."); return MOD_RES_DENY; } } @@ -432,7 +423,7 @@ class ModuleDCCAllow : public Module if (i->nickname == user->nick) { - u->WriteServ("NOTICE %s :%s left the network or changed their nickname and has been removed from your DCCALLOW list", u->nick.c_str(), i->nickname.c_str()); + u->WriteNotice(i->nickname + " left the network or changed their nickname and has been removed from your DCCALLOW list"); u->WriteNumeric(995, "%s %s :Removed %s from your DCCALLOW list", u->nick.c_str(), u->nick.c_str(), i->nickname.c_str()); dl->erase(i); break; @@ -475,12 +466,12 @@ class ModuleDCCAllow : public Module } } - virtual ~ModuleDCCAllow() + ~ModuleDCCAllow() { delete ext; } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for the /DCCALLOW command", VF_COMMON | VF_VENDOR); } diff --git a/src/modules/m_deaf.cpp b/src/modules/m_deaf.cpp index 43b24cfae..2e07aea41 100644 --- a/src/modules/m_deaf.cpp +++ b/src/modules/m_deaf.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides usermode +d to block channel messages and channel notices */ - /** User mode +d - filter out channel messages and channel notices */ class User_d : public ModeHandler @@ -32,31 +30,20 @@ class User_d : public ModeHandler ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { + if (adding == dest->IsModeSet(this)) + return MODEACTION_DENY; + if (adding) - { - if (!dest->IsModeSet('d')) - { - dest->WriteServ("NOTICE %s :*** You have enabled usermode +d, deaf mode. This mode means you WILL NOT receive any messages from any channels you are in. If you did NOT mean to do this, use /mode %s -d.", dest->nick.c_str(), dest->nick.c_str()); - dest->SetMode('d',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('d')) - { - dest->SetMode('d',false); - return MODEACTION_ALLOW; - } - } - return MODEACTION_DENY; + dest->WriteNotice("*** You have enabled usermode +d, deaf mode. This mode means you WILL NOT receive any messages from any channels you are in. If you did NOT mean to do this, use /mode " + dest->nick + " -d."); + + dest->SetMode(this, adding); + return MODEACTION_ALLOW; } }; class ModuleDeaf : public Module { User_d m1; - std::string deaf_bypasschars; std::string deaf_bypasschars_uline; @@ -66,47 +53,33 @@ class ModuleDeaf : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(m1); OnRehash(NULL); - Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("deaf"); deaf_bypasschars = tag->getString("bypasschars"); deaf_bypasschars_uline = tag->getString("bypasscharsuline"); } - virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - if (target_type == TYPE_CHANNEL) - { - Channel* chan = (Channel*)dest; - if (chan) - this->BuildDeafList(MSG_NOTICE, chan, user, status, text, exempt_list); - } - - return MOD_RES_PASSTHRU; - } - - virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { if (target_type == TYPE_CHANNEL) { Channel* chan = (Channel*)dest; if (chan) - this->BuildDeafList(MSG_PRIVMSG, chan, user, status, text, exempt_list); + this->BuildDeafList(msgtype, chan, user, status, text, exempt_list); } return MOD_RES_PASSTHRU; } - virtual void BuildDeafList(MessageType message_type, Channel* chan, User* sender, char status, const std::string &text, CUList &exempt_list) + void BuildDeafList(MessageType message_type, Channel* chan, User* sender, char status, const std::string &text, CUList &exempt_list) { const UserMembList *ulist = chan->GetUsers(); bool is_a_uline; @@ -137,7 +110,7 @@ class ModuleDeaf : public Module for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++) { /* not +d ? */ - if (!i->first->IsModeSet('d')) + if (!i->first->IsModeSet(m1)) continue; /* deliver message */ /* matched both U-line only and regular bypasses */ if (is_bypasschar && is_bypasschar_uline) @@ -159,15 +132,10 @@ class ModuleDeaf : public Module } } - virtual ~ModuleDeaf() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides usermode +d to block channel messages and channel notices", VF_VENDOR); } - }; MODULE_INIT(ModuleDeaf) diff --git a/src/modules/m_delayjoin.cpp b/src/modules/m_delayjoin.cpp index a9a92e67a..444cbbc39 100644 --- a/src/modules/m_delayjoin.cpp +++ b/src/modules/m_delayjoin.cpp @@ -20,14 +20,11 @@ */ -/* $ModDesc: Allows for delay-join channels (+D) where users don't appear to join until they speak */ - #include "inspircd.h" #include <stdarg.h> class DelayJoinMode : public ModeHandler { - private: CUList empty; public: DelayJoinMode(Module* Parent) : ModeHandler(Parent, "delayjoin", 'D', PARAM_NONE, MODETYPE_CHANNEL) @@ -47,29 +44,26 @@ class ModuleDelayJoin : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(djm); ServerInstance->Modules->AddService(unjoined); - Implementation eventlist[] = { I_OnUserJoin, I_OnUserPart, I_OnUserKick, I_OnBuildNeighborList, I_OnNamesListItem, I_OnText, I_OnRawMode }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - ~ModuleDelayJoin(); - Version GetVersion(); - void OnNamesListItem(User* issuer, Membership*, std::string &prefixes, std::string &nick); - void OnUserJoin(Membership*, bool, bool, CUList&); + Version GetVersion() CXX11_OVERRIDE; + void OnNamesListItem(User* issuer, Membership*, std::string &prefixes, std::string &nick) CXX11_OVERRIDE; + void OnUserJoin(Membership*, bool, bool, CUList&) CXX11_OVERRIDE; void CleanUser(User* user); - void OnUserPart(Membership*, std::string &partmessage, CUList&); - void OnUserKick(User* source, Membership*, const std::string &reason, CUList&); - void OnBuildNeighborList(User* source, UserChanList &include, std::map<User*,bool> &exception); - void OnText(User* user, void* dest, int target_type, const std::string &text, char status, CUList &exempt_list); - ModResult OnRawMode(User* user, Channel* channel, const char mode, const std::string ¶m, bool adding, int pcnt); + void OnUserPart(Membership*, std::string &partmessage, CUList&) CXX11_OVERRIDE; + void OnUserKick(User* source, Membership*, const std::string &reason, CUList&) CXX11_OVERRIDE; + void OnBuildNeighborList(User* source, UserChanList &include, std::map<User*,bool> &exception) CXX11_OVERRIDE; + void OnText(User* user, void* dest, int target_type, const std::string &text, char status, CUList &exempt_list) CXX11_OVERRIDE; + ModResult OnRawMode(User* user, Channel* channel, const char mode, const std::string ¶m, bool adding, int pcnt) CXX11_OVERRIDE; }; ModeAction DelayJoinMode::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { /* no change */ - if (channel->IsModeSet('D') == adding) + if (channel->IsModeSet(this) == adding) return MODEACTION_DENY; if (!adding) @@ -82,14 +76,10 @@ ModeAction DelayJoinMode::OnModeChange(User* source, User* dest, Channel* channe for (UserMembCIter n = names->begin(); n != names->end(); ++n) creator->OnText(n->first, channel, TYPE_CHANNEL, "", 0, empty); } - channel->SetMode('D', adding); + channel->SetMode(this, adding); return MODEACTION_ALLOW; } -ModuleDelayJoin::~ModuleDelayJoin() -{ -} - Version ModuleDelayJoin::GetVersion() { return Version("Allows for delay-join channels (+D) where users don't appear to join until they speak", VF_VENDOR); @@ -119,7 +109,7 @@ static void populate(CUList& except, Membership* memb) void ModuleDelayJoin::OnUserJoin(Membership* memb, bool sync, bool created, CUList& except) { - if (memb->chan->IsModeSet('D')) + if (memb->chan->IsModeSet(djm)) { unjoined.set(memb, 1); populate(except, memb); diff --git a/src/modules/m_delaymsg.cpp b/src/modules/m_delaymsg.cpp index cfc06866a..1e16647f3 100644 --- a/src/modules/m_delaymsg.cpp +++ b/src/modules/m_delaymsg.cpp @@ -19,8 +19,6 @@ #include "inspircd.h" -/* $ModDesc: Provides channelmode +d <int>, to deny messages to a channel until <int> seconds. */ - class DelayMsgMode : public ModeHandler { public: @@ -41,30 +39,27 @@ class DelayMsgMode : public ModeHandler class ModuleDelayMsg : public Module { - private: DelayMsgMode djm; public: ModuleDelayMsg() : djm(this) { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(djm); ServerInstance->Modules->AddService(djm.jointime); - Implementation eventlist[] = { I_OnUserJoin, I_OnUserPreMessage}; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - Version GetVersion(); - void OnUserJoin(Membership* memb, bool sync, bool created, CUList&); - ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list); + Version GetVersion() CXX11_OVERRIDE; + void OnUserJoin(Membership* memb, bool sync, bool created, CUList&) CXX11_OVERRIDE; + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE; }; ModeAction DelayMsgMode::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { if (adding) { - if ((channel->IsModeSet('d')) && (channel->GetModeParameter('d') == parameter)) + if ((channel->IsModeSet(this)) && (channel->GetModeParameter(this) == parameter)) return MODEACTION_DENY; /* Setting a new limit, sanity check */ @@ -78,7 +73,7 @@ ModeAction DelayMsgMode::OnModeChange(User* source, User* dest, Channel* channel } else { - if (!channel->IsModeSet('d')) + if (!channel->IsModeSet(this)) return MODEACTION_DENY; /* @@ -88,7 +83,6 @@ ModeAction DelayMsgMode::OnModeChange(User* source, User* dest, Channel* channel for (UserMembCIter n = names->begin(); n != names->end(); ++n) jointime.set(n->second, 0); } - channel->SetModeParam('d', adding ? parameter : ""); return MODEACTION_ALLOW; } @@ -99,19 +93,19 @@ Version ModuleDelayMsg::GetVersion() void ModuleDelayMsg::OnUserJoin(Membership* memb, bool sync, bool created, CUList&) { - if ((IS_LOCAL(memb->user)) && (memb->chan->IsModeSet('d'))) + if ((IS_LOCAL(memb->user)) && (memb->chan->IsModeSet(djm))) { djm.jointime.set(memb, ServerInstance->Time()); } } -ModResult ModuleDelayMsg::OnUserPreMessage(User* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list) +ModResult ModuleDelayMsg::OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) { /* Server origin */ if ((!user) || (!IS_LOCAL(user))) return MOD_RES_PASSTHRU; - if (target_type != TYPE_CHANNEL) + if ((target_type != TYPE_CHANNEL) || (msgtype != MSG_PRIVMSG)) return MOD_RES_PASSTHRU; Channel* channel = (Channel*) dest; @@ -125,7 +119,7 @@ ModResult ModuleDelayMsg::OnUserPreMessage(User* user, void* dest, int target_ty if (ts == 0) return MOD_RES_PASSTHRU; - std::string len = channel->GetModeParameter('d'); + std::string len = channel->GetModeParameter(&djm); if (ts + atoi(len.c_str()) > ServerInstance->Time()) { @@ -145,4 +139,3 @@ ModResult ModuleDelayMsg::OnUserPreMessage(User* user, void* dest, int target_ty } MODULE_INIT(ModuleDelayMsg) - diff --git a/src/modules/m_denychans.cpp b/src/modules/m_denychans.cpp index e774e92c8..237447ac7 100644 --- a/src/modules/m_denychans.cpp +++ b/src/modules/m_denychans.cpp @@ -22,18 +22,17 @@ #include "inspircd.h" -/* $ModDesc: Implements config tags which allow blocking of joins to channels */ - class ModuleDenyChannels : public Module { + ChanModeReference redirectmode; + public: - void init() + ModuleDenyChannels() + : redirectmode(this, "redirect") { - Implementation eventlist[] = { I_OnUserPreJoin, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { /* check for redirect validity and loops/chains */ ConfigTagList tags = ServerInstance->Config->ConfTags("badchan"); @@ -45,10 +44,10 @@ class ModuleDenyChannels : public Module if (!redirect.empty()) { - if (!ServerInstance->IsChannel(redirect.c_str(), ServerInstance->Config->Limits.ChanMax)) + if (!ServerInstance->IsChannel(redirect)) { if (user) - user->WriteServ("NOTICE %s :Invalid badchan redirect '%s'", user->nick.c_str(), redirect.c_str()); + user->WriteNotice("Invalid badchan redirect '" + redirect + "'"); throw ModuleException("Invalid badchan redirect, not a channel"); } @@ -68,7 +67,7 @@ class ModuleDenyChannels : public Module { /* <badchan:redirect> is a badchan */ if (user) - user->WriteServ("NOTICE %s :Badchan %s redirects to badchan %s", user->nick.c_str(), name.c_str(), redirect.c_str()); + user->WriteNotice("Badchan " + name + " redirects to badchan " + redirect); throw ModuleException("Badchan redirect loop"); } } @@ -77,24 +76,20 @@ class ModuleDenyChannels : public Module } } - virtual ~ModuleDenyChannels() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Implements config tags which allow blocking of joins to channels", VF_VENDOR); } - virtual ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven) + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { ConfigTagList tags = ServerInstance->Config->ConfTags("badchan"); for (ConfigIter j = tags.first; j != tags.second; ++j) { if (InspIRCd::Match(cname, j->second->getString("name"))) { - if (IS_OPER(user) && j->second->getBool("allowopers")) + if (user->IsOper() && j->second->getBool("allowopers")) { return MOD_RES_PASSTHRU; } @@ -112,19 +107,19 @@ class ModuleDenyChannels : public Module } } - if (ServerInstance->IsChannel(redirect.c_str(), ServerInstance->Config->Limits.ChanMax)) + if (ServerInstance->IsChannel(redirect)) { /* simple way to avoid potential loops: don't redirect to +L channels */ Channel *newchan = ServerInstance->FindChan(redirect); - if ((!newchan) || (!(newchan->IsModeSet('L')))) + if ((!newchan) || (!newchan->IsModeSet(redirectmode))) { - user->WriteNumeric(926, "%s %s :Channel %s is forbidden, redirecting to %s: %s",user->nick.c_str(),cname,cname,redirect.c_str(), reason.c_str()); - Channel::JoinUser(user,redirect.c_str(),false,"",false,ServerInstance->Time()); + user->WriteNumeric(926, "%s %s :Channel %s is forbidden, redirecting to %s: %s",user->nick.c_str(),cname.c_str(),cname.c_str(),redirect.c_str(), reason.c_str()); + Channel::JoinUser(user, redirect); return MOD_RES_DENY; } } - user->WriteNumeric(926, "%s %s :Channel %s is forbidden: %s",user->nick.c_str(),cname,cname,reason.c_str()); + user->WriteNumeric(926, "%s %s :Channel %s is forbidden: %s",user->nick.c_str(),cname.c_str(),cname.c_str(),reason.c_str()); return MOD_RES_DENY; } } diff --git a/src/modules/m_devoice.cpp b/src/modules/m_devoice.cpp index 2b5de2bd6..e16a87336 100644 --- a/src/modules/m_devoice.cpp +++ b/src/modules/m_devoice.cpp @@ -24,8 +24,6 @@ * Syntax: /DEVOICE <#chan> */ -/* $ModDesc: Provides voiced users with the ability to devoice themselves. */ - #include "inspircd.h" /** Handle /DEVOICE @@ -36,24 +34,17 @@ class CommandDevoice : public Command CommandDevoice(Module* Creator) : Command(Creator,"DEVOICE", 1) { syntax = "<channel>"; - TRANSLATE2(TR_TEXT, TR_END); } CmdResult Handle (const std::vector<std::string> ¶meters, User *user) { - Channel* c = ServerInstance->FindChan(parameters[0]); - if (c && c->HasUser(user)) - { - std::vector<std::string> modes; - modes.push_back(parameters[0]); - modes.push_back("-v"); - modes.push_back(user->nick); - - ServerInstance->SendGlobalMode(modes, ServerInstance->FakeClient); - return CMD_SUCCESS; - } + std::vector<std::string> modes; + modes.push_back(parameters[0]); + modes.push_back("-v"); + modes.push_back(user->nick); - return CMD_FAILURE; + ServerInstance->Modes->Process(modes, ServerInstance->FakeClient); + return CMD_SUCCESS; } }; @@ -65,16 +56,12 @@ class ModuleDeVoice : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleDeVoice() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides voiced users with the ability to devoice themselves.", VF_VENDOR); } diff --git a/src/modules/m_dnsbl.cpp b/src/modules/m_dnsbl.cpp index 3a9360380..3c9d64d49 100644 --- a/src/modules/m_dnsbl.cpp +++ b/src/modules/m_dnsbl.cpp @@ -23,8 +23,7 @@ #include "inspircd.h" #include "xline.h" - -/* $ModDesc: Provides handling of DNS blacklists */ +#include "modules/dns.h" /* Class holding data for a single entry */ class DNSBLConfEntry : public refcountbase @@ -40,13 +39,12 @@ class DNSBLConfEntry : public refcountbase unsigned char records[256]; unsigned long stats_hits, stats_misses; DNSBLConfEntry(): type(A_BITMASK),duration(86400),bitmask(0),stats_hits(0), stats_misses(0) {} - ~DNSBLConfEntry() { } }; /** Resolver for CGI:IRC hostnames encoded in ident/GECOS */ -class DNSBLResolver : public Resolver +class DNSBLResolver : public DNS::Request { std::string theiruid; LocalStringExt& nameExt; @@ -55,161 +53,158 @@ class DNSBLResolver : public Resolver public: - DNSBLResolver(Module *me, LocalStringExt& match, LocalIntExt& ctr, const std::string &hostname, LocalUser* u, reference<DNSBLConfEntry> conf, bool &cached) - : Resolver(hostname, DNS_QUERY_A, cached, me), theiruid(u->uuid), nameExt(match), countExt(ctr), ConfEntry(conf) + DNSBLResolver(DNS::Manager *mgr, Module *me, LocalStringExt& match, LocalIntExt& ctr, const std::string &hostname, LocalUser* u, reference<DNSBLConfEntry> conf) + : DNS::Request(mgr, me, hostname, DNS::QUERY_A, true), theiruid(u->uuid), nameExt(match), countExt(ctr), ConfEntry(conf) { } /* Note: This may be called multiple times for multiple A record results */ - virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) + void OnLookupComplete(const DNS::Query *r) CXX11_OVERRIDE { /* Check the user still exists */ LocalUser* them = (LocalUser*)ServerInstance->FindUUID(theiruid); - if (them) + if (!them) + return; + + const DNS::ResourceRecord &ans_record = r->answers[0]; + + int i = countExt.get(them); + if (i) + countExt.set(them, i - 1); + + // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d + + unsigned int bitmask = 0, record = 0; + bool match = false; + in_addr resultip; + + inet_aton(ans_record.rdata.c_str(), &resultip); + + switch (ConfEntry->type) + { + case DNSBLConfEntry::A_BITMASK: + bitmask = resultip.s_addr >> 24; /* Last octet (network byte order) */ + bitmask &= ConfEntry->bitmask; + match = (bitmask != 0); + break; + case DNSBLConfEntry::A_RECORD: + record = resultip.s_addr >> 24; /* Last octet */ + match = (ConfEntry->records[record] == 1); + break; + } + + if (match) { - int i = countExt.get(them); - if (i) - countExt.set(them, i - 1); - // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d - if(result.length()) + std::string reason = ConfEntry->reason; + std::string::size_type x = reason.find("%ip%"); + while (x != std::string::npos) { - unsigned int bitmask = 0, record = 0; - bool match = false; - in_addr resultip; + reason.erase(x, 4); + reason.insert(x, them->GetIPString()); + x = reason.find("%ip%"); + } - inet_aton(result.c_str(), &resultip); + ConfEntry->stats_hits++; - switch (ConfEntry->type) + switch (ConfEntry->banaction) + { + case DNSBLConfEntry::I_KILL: { - case DNSBLConfEntry::A_BITMASK: - bitmask = resultip.s_addr >> 24; /* Last octet (network byte order) */ - bitmask &= ConfEntry->bitmask; - match = (bitmask != 0); - break; - case DNSBLConfEntry::A_RECORD: - record = resultip.s_addr >> 24; /* Last octet */ - match = (ConfEntry->records[record] == 1); + ServerInstance->Users->QuitUser(them, "Killed (" + reason + ")"); break; } - - if (match) + case DNSBLConfEntry::I_MARK: { - std::string reason = ConfEntry->reason; - std::string::size_type x = reason.find("%ip%"); - while (x != std::string::npos) + if (!ConfEntry->ident.empty()) { - reason.erase(x, 4); - reason.insert(x, them->GetIPString()); - x = reason.find("%ip%"); + them->WriteServ("304 " + them->nick + " :Your ident has been set to " + ConfEntry->ident + " because you matched " + reason); + them->ChangeIdent(ConfEntry->ident); } - ConfEntry->stats_hits++; - - switch (ConfEntry->banaction) + if (!ConfEntry->host.empty()) { - case DNSBLConfEntry::I_KILL: - { - ServerInstance->Users->QuitUser(them, "Killed (" + reason + ")"); - break; - } - case DNSBLConfEntry::I_MARK: - { - if (!ConfEntry->ident.empty()) - { - them->WriteServ("304 " + them->nick + " :Your ident has been set to " + ConfEntry->ident + " because you matched " + reason); - them->ChangeIdent(ConfEntry->ident.c_str()); - } - - if (!ConfEntry->host.empty()) - { - them->WriteServ("304 " + them->nick + " :Your host has been set to " + ConfEntry->host + " because you matched " + reason); - them->ChangeDisplayedHost(ConfEntry->host.c_str()); - } - - nameExt.set(them, ConfEntry->name); - break; - } - case DNSBLConfEntry::I_KLINE: - { - KLine* kl = new KLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(), - "*", them->GetIPString()); - if (ServerInstance->XLines->AddLine(kl,NULL)) - { - std::string timestr = ServerInstance->TimeString(kl->expiry); - ServerInstance->SNO->WriteGlobalSno('x',"K:line added due to DNSBL match on *@%s to expire on %s: %s", - them->GetIPString(), timestr.c_str(), reason.c_str()); - ServerInstance->XLines->ApplyLines(); - } - else - delete kl; - break; - } - case DNSBLConfEntry::I_GLINE: - { - GLine* gl = new GLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(), - "*", them->GetIPString()); - if (ServerInstance->XLines->AddLine(gl,NULL)) - { - std::string timestr = ServerInstance->TimeString(gl->expiry); - ServerInstance->SNO->WriteGlobalSno('x',"G:line added due to DNSBL match on *@%s to expire on %s: %s", - them->GetIPString(), timestr.c_str(), reason.c_str()); - ServerInstance->XLines->ApplyLines(); - } - else - delete gl; - break; - } - case DNSBLConfEntry::I_ZLINE: - { - ZLine* zl = new ZLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(), - them->GetIPString()); - if (ServerInstance->XLines->AddLine(zl,NULL)) - { - std::string timestr = ServerInstance->TimeString(zl->expiry); - ServerInstance->SNO->WriteGlobalSno('x',"Z:line added due to DNSBL match on *@%s to expire on %s: %s", - them->GetIPString(), timestr.c_str(), reason.c_str()); - ServerInstance->XLines->ApplyLines(); - } - else - delete zl; - break; - } - case DNSBLConfEntry::I_UNKNOWN: - { - break; - } - break; + them->WriteServ("304 " + them->nick + " :Your host has been set to " + ConfEntry->host + " because you matched " + reason); + them->ChangeDisplayedHost(ConfEntry->host); } - ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s%s detected as being on a DNS blacklist (%s) with result %d", them->nick.empty() ? "<unknown>" : "", them->GetFullRealHost().c_str(), ConfEntry->domain.c_str(), (ConfEntry->type==DNSBLConfEntry::A_BITMASK) ? bitmask : record); + nameExt.set(them, ConfEntry->name); + break; + } + case DNSBLConfEntry::I_KLINE: + { + KLine* kl = new KLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(), + "*", them->GetIPString()); + if (ServerInstance->XLines->AddLine(kl,NULL)) + { + std::string timestr = ServerInstance->TimeString(kl->expiry); + ServerInstance->SNO->WriteGlobalSno('x',"K:line added due to DNSBL match on *@%s to expire on %s: %s", + them->GetIPString().c_str(), timestr.c_str(), reason.c_str()); + ServerInstance->XLines->ApplyLines(); + } + else + delete kl; + break; + } + case DNSBLConfEntry::I_GLINE: + { + GLine* gl = new GLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(), + "*", them->GetIPString()); + if (ServerInstance->XLines->AddLine(gl,NULL)) + { + std::string timestr = ServerInstance->TimeString(gl->expiry); + ServerInstance->SNO->WriteGlobalSno('x',"G:line added due to DNSBL match on *@%s to expire on %s: %s", + them->GetIPString().c_str(), timestr.c_str(), reason.c_str()); + ServerInstance->XLines->ApplyLines(); + } + else + delete gl; + break; } - else - ConfEntry->stats_misses++; + case DNSBLConfEntry::I_ZLINE: + { + ZLine* zl = new ZLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(), + them->GetIPString()); + if (ServerInstance->XLines->AddLine(zl,NULL)) + { + std::string timestr = ServerInstance->TimeString(zl->expiry); + ServerInstance->SNO->WriteGlobalSno('x',"Z:line added due to DNSBL match on *@%s to expire on %s: %s", + them->GetIPString().c_str(), timestr.c_str(), reason.c_str()); + ServerInstance->XLines->ApplyLines(); + } + else + delete zl; + break; + } + case DNSBLConfEntry::I_UNKNOWN: + default: + break; } - else - ConfEntry->stats_misses++; + + ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s%s detected as being on a DNS blacklist (%s) with result %d", them->nick.empty() ? "<unknown>" : "", them->GetFullRealHost().c_str(), ConfEntry->domain.c_str(), (ConfEntry->type==DNSBLConfEntry::A_BITMASK) ? bitmask : record); } + else + ConfEntry->stats_misses++; } - virtual void OnError(ResolverError e, const std::string &errormessage) + void OnError(const DNS::Query *q) CXX11_OVERRIDE { LocalUser* them = (LocalUser*)ServerInstance->FindUUID(theiruid); - if (them) - { - int i = countExt.get(them); - if (i) - countExt.set(them, i - 1); - } - } + if (!them) + return; - virtual ~DNSBLResolver() - { + int i = countExt.get(them); + if (i) + countExt.set(them, i - 1); + + if (q->error == DNS::ERROR_NO_RECORDS || q->error == DNS::ERROR_DOMAIN_NOT_FOUND) + ConfEntry->stats_misses++; } }; class ModuleDNSBL : public Module { std::vector<reference<DNSBLConfEntry> > DNSBLConfEntries; + dynamic_reference<DNS::Manager> DNS; LocalStringExt nameExt; LocalIntExt countExt; @@ -232,18 +227,16 @@ class ModuleDNSBL : public Module return DNSBLConfEntry::I_UNKNOWN; } public: - ModuleDNSBL() : nameExt("dnsbl_match", this), countExt("dnsbl_pending", this) { } + ModuleDNSBL() : DNS(this, "DNS"), nameExt("dnsbl_match", this), countExt("dnsbl_pending", this) { } - void init() + void init() CXX11_OVERRIDE { ReadConf(); ServerInstance->Modules->AddService(nameExt); ServerInstance->Modules->AddService(countExt); - Implementation eventlist[] = { I_OnRehash, I_OnSetUserIP, I_OnStats, I_OnSetConnectClass, I_OnCheckReady }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides handling of DNS blacklists", VF_VENDOR); } @@ -282,7 +275,7 @@ class ModuleDNSBL : public Module } e->banaction = str2banaction(tag->getString("action")); - e->duration = ServerInstance->Duration(tag->getString("duration", "60")); + e->duration = tag->getDuration("duration", 60, 1); /* Use portparser for record replies */ @@ -307,11 +300,6 @@ class ModuleDNSBL : public Module std::string location = tag->getTagLocation(); ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): Invalid banaction", location.c_str()); } - else if (e->duration <= 0) - { - std::string location = tag->getTagLocation(); - ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): Invalid duration", location.c_str()); - } else { if (e->reason.empty()) @@ -327,14 +315,14 @@ class ModuleDNSBL : public Module } } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ReadConf(); } - void OnSetUserIP(LocalUser* user) + void OnSetUserIP(LocalUser* user) CXX11_OVERRIDE { - if ((user->exempt) || (user->client_sa.sa.sa_family != AF_INET)) + if ((user->exempt) || (user->client_sa.sa.sa_family != AF_INET) || !DNS) return; if (user->MyClass) @@ -343,40 +331,42 @@ class ModuleDNSBL : public Module return; } else - ServerInstance->Logs->Log("m_dnsbl", DEBUG, "User has no connect class in OnSetUserIP"); - - unsigned char a, b, c, d; - char reversedipbuf[128]; - std::string reversedip; + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User has no connect class in OnSetUserIP"); - d = (unsigned char) (user->client_sa.in4.sin_addr.s_addr >> 24) & 0xFF; - c = (unsigned char) (user->client_sa.in4.sin_addr.s_addr >> 16) & 0xFF; - b = (unsigned char) (user->client_sa.in4.sin_addr.s_addr >> 8) & 0xFF; - a = (unsigned char) user->client_sa.in4.sin_addr.s_addr & 0xFF; + unsigned int a, b, c, d; + d = (unsigned int) (user->client_sa.in4.sin_addr.s_addr >> 24) & 0xFF; + c = (unsigned int) (user->client_sa.in4.sin_addr.s_addr >> 16) & 0xFF; + b = (unsigned int) (user->client_sa.in4.sin_addr.s_addr >> 8) & 0xFF; + a = (unsigned int) user->client_sa.in4.sin_addr.s_addr & 0xFF; - snprintf(reversedipbuf, 128, "%d.%d.%d.%d", d, c, b, a); - reversedip = std::string(reversedipbuf); + const std::string reversedip = ConvToStr(d) + "." + ConvToStr(c) + "." + ConvToStr(b) + "." + ConvToStr(a); countExt.set(user, DNSBLConfEntries.size()); // For each DNSBL, we will run through this lookup - unsigned int i = 0; - while (i < DNSBLConfEntries.size()) + for (unsigned i = 0; i < DNSBLConfEntries.size(); ++i) { // Fill hostname with a dnsbl style host (d.c.b.a.domain.tld) std::string hostname = reversedip + "." + DNSBLConfEntries[i]->domain; /* now we'd need to fire off lookups for `hostname'. */ - bool cached; - DNSBLResolver *r = new DNSBLResolver(this, nameExt, countExt, hostname, user, DNSBLConfEntries[i], cached); - ServerInstance->AddResolver(r, cached); + DNSBLResolver *r = new DNSBLResolver(*this->DNS, this, nameExt, countExt, hostname, user, DNSBLConfEntries[i]); + try + { + this->DNS->Process(r); + } + catch (DNS::Exception &ex) + { + delete r; + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, std::string(ex.GetReason())); + } + if (user->quitting) break; - i++; } } - ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) + ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE { std::string dnsbl; if (!myclass->config->readString("dnsbl", dnsbl)) @@ -387,15 +377,15 @@ class ModuleDNSBL : public Module return MOD_RES_PASSTHRU; return MOD_RES_DENY; } - - ModResult OnCheckReady(LocalUser *user) + + ModResult OnCheckReady(LocalUser *user) CXX11_OVERRIDE { if (countExt.get(user)) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } - ModResult OnStats(char symbol, User* user, string_list &results) + ModResult OnStats(char symbol, User* user, string_list &results) CXX11_OVERRIDE { if (symbol != 'd') return MOD_RES_PASSTHRU; diff --git a/src/modules/m_exemptchanops.cpp b/src/modules/m_exemptchanops.cpp index 9fac8e7ad..a74658bcd 100644 --- a/src/modules/m_exemptchanops.cpp +++ b/src/modules/m_exemptchanops.cpp @@ -18,9 +18,7 @@ #include "inspircd.h" -#include "u_listmode.h" - -/* $ModDesc: Provides the ability to allow channel operators to be exempt from certain modes. */ +#include "listmode.h" /** Handles channel mode +X */ @@ -41,10 +39,9 @@ class ExemptChanOps : public ListModeBase return true; } - bool TellListTooLong(User* user, Channel* chan, std::string &word) + void TellListTooLong(User* user, Channel* chan, std::string &word) { user->WriteNumeric(959, "%s %s %s :Channel exemptchanops list is full", user->nick.c_str(), chan->name.c_str(), word.c_str()); - return true; } void TellAlreadyOnList(User* user, Channel* chan, std::string &word) @@ -63,7 +60,7 @@ class ExemptHandler : public HandlerBase3<ModResult, User*, Channel*, const std: public: ExemptChanOps ec; ExemptHandler(Module* me) : ec(me) {} - + ModeHandler* FindMode(const std::string& mid) { if (mid.length() == 1) @@ -82,11 +79,11 @@ class ExemptHandler : public HandlerBase3<ModResult, User*, Channel*, const std: unsigned int mypfx = chan->GetPrefixValue(user); std::string minmode; - modelist* list = ec.extItem.get(chan); + ListModeBase::ModeList* list = ec.GetList(chan); if (list) { - for (modelist::iterator i = list->begin(); i != list->end(); ++i) + for (ListModeBase::ModeList::iterator i = list->begin(); i != list->end(); ++i) { std::string::size_type pos = (*i).mask.find(':'); if (pos == std::string::npos) @@ -112,16 +109,13 @@ class ModuleExemptChanOps : public Module ExemptHandler eh; public: - ModuleExemptChanOps() : eh(this) { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(eh.ec); - Implementation eventlist[] = { I_OnRehash, I_OnSyncChannel }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); ServerInstance->OnCheckExemption = &eh; OnRehash(NULL); @@ -132,17 +126,17 @@ class ModuleExemptChanOps : public Module ServerInstance->OnCheckExemption = &ServerInstance->HandleOnCheckExemption; } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides the ability to allow channel operators to be exempt from certain modes.",VF_VENDOR); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { eh.ec.DoRehash(); } - void OnSyncChannel(Channel* chan, Module* proto, void* opaque) + void OnSyncChannel(Channel* chan, Module* proto, void* opaque) CXX11_OVERRIDE { eh.ec.DoSyncChannel(chan, proto, opaque); } diff --git a/src/modules/m_filter.cpp b/src/modules/m_filter.cpp index 4090f5600..d60dd7942 100644 --- a/src/modules/m_filter.cpp +++ b/src/modules/m_filter.cpp @@ -22,9 +22,7 @@ #include "inspircd.h" #include "xline.h" -#include "m_regex.h" - -/* $ModDesc: Text (spam) filtering */ +#include "modules/regex.h" class ModuleFilter; @@ -179,22 +177,21 @@ class ModuleFilter : public Module std::set<std::string> exemptfromfilter; // List of channel names excluded from filtering. ModuleFilter(); - void init(); + void init() CXX11_OVERRIDE; CullResult cull(); - ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list); + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE; FilterResult* FilterMatch(User* user, const std::string &text, int flags); bool DeleteFilter(const std::string &freeform); std::pair<bool, std::string> AddFilter(const std::string &freeform, FilterAction type, const std::string &reason, long duration, const std::string &flags); - ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list); - void OnRehash(User* user); - Version GetVersion(); + void OnRehash(User* user) CXX11_OVERRIDE; + Version GetVersion() CXX11_OVERRIDE; std::string EncodeFilter(FilterResult* filter); FilterResult DecodeFilter(const std::string &data); - void OnSyncNetwork(Module* proto, void* opaque); - void OnDecodeMetaData(Extensible* target, const std::string &extname, const std::string &extdata); - ModResult OnStats(char symbol, User* user, string_list &results); - ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line); - void OnUnloadModule(Module* mod); + void OnSyncNetwork(Module* proto, void* opaque) CXX11_OVERRIDE; + void OnDecodeMetaData(Extensible* target, const std::string &extname, const std::string &extdata) CXX11_OVERRIDE; + ModResult OnStats(char symbol, User* user, string_list &results) CXX11_OVERRIDE; + ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE; + void OnUnloadModule(Module* mod) CXX11_OVERRIDE; bool AppliesToMe(User* user, FilterResult* filter, int flags); void ReadFilters(); static bool StringToFilterAction(const std::string& str, FilterAction& fa); @@ -209,13 +206,13 @@ CmdResult CommandFilter::Handle(const std::vector<std::string> ¶meters, User Module *me = creator; if (static_cast<ModuleFilter *>(me)->DeleteFilter(parameters[0])) { - user->WriteServ("NOTICE %s :*** Removed filter '%s'", user->nick.c_str(), parameters[0].c_str()); + user->WriteNotice("*** Removed filter '" + parameters[0] + "'"); ServerInstance->SNO->WriteToSnoMask(IS_LOCAL(user) ? 'a' : 'A', "FILTER: "+user->nick+" removed filter '"+parameters[0]+"'"); return CMD_SUCCESS; } else { - user->WriteServ("NOTICE %s :*** Filter '%s' not found in list, try /stats s.", user->nick.c_str(), parameters[0].c_str()); + user->WriteNotice("*** Filter '" + parameters[0] + "' not found in list, try /stats s."); return CMD_FAILURE; } } @@ -232,7 +229,7 @@ CmdResult CommandFilter::Handle(const std::vector<std::string> ¶meters, User if (!ModuleFilter::StringToFilterAction(parameters[1], type)) { - user->WriteServ("NOTICE %s :*** Invalid filter type '%s'. Supported types are 'gline', 'none', 'block', 'silent' and 'kill'.", user->nick.c_str(), parameters[1].c_str()); + user->WriteNotice("*** Invalid filter type '" + parameters[1] + "'. Supported types are 'gline', 'none', 'block', 'silent' and 'kill'."); return CMD_FAILURE; } @@ -240,12 +237,12 @@ CmdResult CommandFilter::Handle(const std::vector<std::string> ¶meters, User { if (parameters.size() >= 5) { - duration = ServerInstance->Duration(parameters[3]); + duration = InspIRCd::Duration(parameters[3]); reasonindex = 4; } else { - user->WriteServ("NOTICE %s :*** Not enough parameters: When setting a gline type filter, a gline duration must be specified as the third parameter.", user->nick.c_str()); + user->WriteNotice("*** Not enough parameters: When setting a gline type filter, a gline duration must be specified as the third parameter."); return CMD_FAILURE; } } @@ -258,9 +255,9 @@ CmdResult CommandFilter::Handle(const std::vector<std::string> ¶meters, User std::pair<bool, std::string> result = static_cast<ModuleFilter *>(me)->AddFilter(freeform, type, parameters[reasonindex], duration, flags); if (result.first) { - user->WriteServ("NOTICE %s :*** Added filter '%s', type '%s'%s%s, flags '%s', reason: '%s'", user->nick.c_str(), freeform.c_str(), - parameters[1].c_str(), (duration ? ", duration " : ""), (duration ? parameters[3].c_str() : ""), - flags.c_str(), parameters[reasonindex].c_str()); + user->WriteNotice("*** Added filter '" + freeform + "', type '" + parameters[1] + "'" + + (duration ? ", duration " + parameters[3] : "") + ", flags '" + flags + "', reason: '" + + parameters[reasonindex] + "'"); ServerInstance->SNO->WriteToSnoMask(IS_LOCAL(user) ? 'a' : 'A', "FILTER: "+user->nick+" added filter '"+freeform+"', type '"+parameters[1]+"', "+(duration ? "duration "+parameters[3]+", " : "")+"flags '"+flags+"', reason: "+parameters[reasonindex]); @@ -268,13 +265,13 @@ CmdResult CommandFilter::Handle(const std::vector<std::string> ¶meters, User } else { - user->WriteServ("NOTICE %s :*** Filter '%s' could not be added: %s", user->nick.c_str(), freeform.c_str(), result.second.c_str()); + user->WriteNotice("*** Filter '" + freeform + "' could not be added: " + result.second); return CMD_FAILURE; } } else { - user->WriteServ("NOTICE %s :*** Not enough parameters.", user->nick.c_str()); + user->WriteNotice("*** Not enough parameters."); return CMD_FAILURE; } @@ -283,7 +280,7 @@ CmdResult CommandFilter::Handle(const std::vector<std::string> ¶meters, User bool ModuleFilter::AppliesToMe(User* user, FilterResult* filter, int iflags) { - if ((filter->flag_no_opers) && IS_OPER(user)) + if ((filter->flag_no_opers) && user->IsOper()) return false; if ((iflags & FLAG_PRIVMSG) && (!filter->flag_privmsg)) return false; @@ -304,8 +301,6 @@ ModuleFilter::ModuleFilter() void ModuleFilter::init() { ServerInstance->Modules->AddService(filtcommand); - Implementation eventlist[] = { I_OnPreCommand, I_OnStats, I_OnSyncNetwork, I_OnDecodeMetaData, I_OnUserPreMessage, I_OnUserPreNotice, I_OnRehash, I_OnUnloadModule }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); } @@ -323,23 +318,13 @@ void ModuleFilter::FreeFilters() filters.clear(); } -ModResult ModuleFilter::OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) -{ - if (!IS_LOCAL(user)) - return MOD_RES_PASSTHRU; - - flags = FLAG_PRIVMSG; - return OnUserPreNotice(user,dest,target_type,text,status,exempt_list); -} - -ModResult ModuleFilter::OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) +ModResult ModuleFilter::OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) { /* Leave ulines alone */ if ((ServerInstance->ULine(user->server)) || (!IS_LOCAL(user))) return MOD_RES_PASSTHRU; - if (!flags) - flags = FLAG_NOTICE; + flags = (msgtype == MSG_PRIVMSG) ? FLAG_PRIVMSG : FLAG_NOTICE; FilterResult* f = this->FilterMatch(user, text, flags); if (f) @@ -364,14 +349,14 @@ ModResult ModuleFilter::OnUserPreNotice(User* user,void* dest,int target_type, s if (target_type == TYPE_CHANNEL) user->WriteNumeric(404, "%s %s :Message to channel blocked and opers notified (%s)",user->nick.c_str(), target.c_str(), f->reason.c_str()); else - user->WriteServ("NOTICE "+user->nick+" :Your message to "+target+" was blocked and opers notified: "+f->reason); + user->WriteNotice("Your message to "+target+" was blocked and opers notified: "+f->reason); } else if (f->action == FA_SILENT) { if (target_type == TYPE_CHANNEL) user->WriteNumeric(404, "%s %s :Message to channel blocked (%s)",user->nick.c_str(), target.c_str(), f->reason.c_str()); else - user->WriteServ("NOTICE "+user->nick+" :Your message to "+target+" was blocked: "+f->reason); + user->WriteNotice("Your message to "+target+" was blocked: "+f->reason); } else if (f->action == FA_KILL) { @@ -388,7 +373,7 @@ ModResult ModuleFilter::OnUserPreNotice(User* user,void* dest,int target_type, s delete gl; } - ServerInstance->Logs->Log("FILTER",DEFAULT,"FILTER: "+ user->nick + " had their message filtered, target was " + target + ": " + f->reason + " Action: " + ModuleFilter::FilterActionToString(f->action)); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, user->nick + " had their message filtered, target was " + target + ": " + f->reason + " Action: " + ModuleFilter::FilterActionToString(f->action)); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; @@ -446,7 +431,7 @@ ModResult ModuleFilter::OnPreCommand(std::string &command, std::vector<std::stri /* Are they parting, if so, kill is applicable */ if ((parting) && (f->action == FA_KILL)) { - user->WriteServ("NOTICE %s :*** Your PART message was filtered: %s", user->nick.c_str(), f->reason.c_str()); + user->WriteNotice("*** Your PART message was filtered: " + f->reason); ServerInstance->Users->QuitUser(user, "Filtered: " + f->reason); } if (f->action == FA_GLINE) @@ -573,7 +558,7 @@ void ModuleFilter::OnDecodeMetaData(Extensible* target, const std::string &extna } catch (ModuleException& e) { - ServerInstance->Logs->Log("m_filter", DEBUG, "Error when unserializing filter: " + std::string(e.GetReason())); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Error when unserializing filter: " + std::string(e.GetReason())); } } } @@ -605,13 +590,8 @@ FilterResult* ModuleFilter::FilterMatch(User* user, const std::string &text, int InspIRCd::StripColor(stripped_text); } - //ServerInstance->Logs->Log("m_filter", DEBUG, "Match '%s' against '%s'", text.c_str(), index->freeform.c_str()); if (index->regex->Matches(filter->flag_strip_color ? stripped_text : text)) - { - //ServerInstance->Logs->Log("m_filter", DEBUG, "MATCH"); return &*index; - } - //ServerInstance->Logs->Log("m_filter", DEBUG, "NO MATCH"); } return NULL; } @@ -646,7 +626,7 @@ std::pair<bool, std::string> ModuleFilter::AddFilter(const std::string &freeform } catch (ModuleException &e) { - ServerInstance->Logs->Log("m_filter", DEFAULT, "Error in regular expression '%s': %s", freeform.c_str(), e.GetReason()); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Error in regular expression '%s': %s", freeform.c_str(), e.GetReason()); return std::make_pair(false, e.GetReason()); } return std::make_pair(true, ""); @@ -695,7 +675,7 @@ void ModuleFilter::ReadFilters() std::string reason = i->second->getString("reason"); std::string action = i->second->getString("action"); std::string flgs = i->second->getString("flags"); - long gline_time = ServerInstance->Duration(i->second->getString("duration")); + unsigned long gline_time = i->second->getDuration("duration", 10*60, 1); if (flgs.empty()) flgs = "*"; @@ -706,11 +686,11 @@ void ModuleFilter::ReadFilters() try { filters.push_back(ImplFilter(this, reason, fa, gline_time, pattern, flgs)); - ServerInstance->Logs->Log("m_filter", DEFAULT, "Regular expression %s loaded.", pattern.c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Regular expression %s loaded.", pattern.c_str()); } catch (ModuleException &e) { - ServerInstance->Logs->Log("m_filter", DEFAULT, "Error in regular expression '%s': %s", pattern.c_str(), e.GetReason()); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Error in regular expression '%s': %s", pattern.c_str(), e.GetReason()); } } } diff --git a/src/modules/m_gecosban.cpp b/src/modules/m_gecosban.cpp index 1497c1b87..a15f19418 100644 --- a/src/modules/m_gecosban.cpp +++ b/src/modules/m_gecosban.cpp @@ -19,27 +19,15 @@ #include "inspircd.h" -/* $ModDesc: Implements extban +b r: - realname (gecos) bans */ - class ModuleGecosBan : public Module { public: - void init() - { - Implementation eventlist[] = { I_OnCheckBan, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - ~ModuleGecosBan() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Extban 'r' - realname (gecos) ban", VF_OPTCOMMON|VF_VENDOR); } - ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) + ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) CXX11_OVERRIDE { if ((mask.length() > 2) && (mask[0] == 'r') && (mask[1] == ':')) { @@ -49,9 +37,9 @@ class ModuleGecosBan : public Module return MOD_RES_PASSTHRU; } - void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - ServerInstance->AddExtBanChar('r'); + tokens["EXTBAN"].push_back('r'); } }; diff --git a/src/modules/m_globalload.cpp b/src/modules/m_globalload.cpp index 22286b950..2c936d5ea 100644 --- a/src/modules/m_globalload.cpp +++ b/src/modules/m_globalload.cpp @@ -22,8 +22,6 @@ */ -/* $ModDesc: Allows global loading of a module. */ - #include "inspircd.h" /** Handle /GLOADMODULE @@ -35,7 +33,6 @@ class CommandGloadmodule : public Command { flags_needed = 'o'; syntax = "<modulename> [servermask]"; - TRANSLATE3(TR_TEXT, TR_TEXT, TR_END); } CmdResult Handle (const std::vector<std::string> ¶meters, User *user) @@ -79,6 +76,13 @@ class CommandGunloadmodule : public Command CmdResult Handle (const std::vector<std::string> ¶meters, User *user) { + if (!ServerInstance->Config->ConfValue("security")->getBool("allowcoreunload") && + InspIRCd::Match(parameters[0], "cmd_*.so", ascii_case_insensitive_map)) + { + user->WriteNumeric(972, "%s %s :You cannot unload core commands!", user->nick.c_str(), parameters[0].c_str()); + return CMD_FAILURE; + } + std::string servername = parameters.size() > 1 ? parameters[1] : "*"; if (InspIRCd::Match(ServerInstance->Config->ServerName.c_str(), servername)) @@ -180,22 +184,17 @@ class ModuleGlobalLoad : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd1); ServerInstance->Modules->AddService(cmd2); ServerInstance->Modules->AddService(cmd3); } - ~ModuleGlobalLoad() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Allows global loading of a module.", VF_COMMON | VF_VENDOR); } }; MODULE_INIT(ModuleGlobalLoad) - diff --git a/src/modules/m_globops.cpp b/src/modules/m_globops.cpp index 85d84252b..d74534ca1 100644 --- a/src/modules/m_globops.cpp +++ b/src/modules/m_globops.cpp @@ -23,8 +23,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for GLOBOPS and snomask +g */ - /** Handle /GLOBOPS */ class CommandGlobops : public Command @@ -33,7 +31,6 @@ class CommandGlobops : public Command CommandGlobops(Module* Creator) : Command(Creator,"GLOBOPS", 1,1) { flags_needed = 'o'; syntax = "<any-text>"; - TRANSLATE2(TR_TEXT, TR_END); } CmdResult Handle (const std::vector<std::string> ¶meters, User *user) @@ -49,17 +46,16 @@ class ModuleGlobops : public Module public: ModuleGlobops() : cmd(this) {} - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); ServerInstance->SNO->EnableSnomask('g',"GLOBOPS"); } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for GLOBOPS and snomask +g", VF_VENDOR); } - }; MODULE_INIT(ModuleGlobops) diff --git a/src/modules/m_halfop.cpp b/src/modules/m_halfop.cpp deleted file mode 100644 index 3194fcde8..000000000 --- a/src/modules/m_halfop.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -/* $ModDesc: Channel half-operator mode provider */ - -#include "inspircd.h" - -class ModeChannelHalfOp : public ModeHandler -{ - public: - ModeChannelHalfOp(Module* parent); - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); - unsigned int GetPrefixRank(); - void RemoveMode(Channel* channel, irc::modestacker* stack = NULL); - void RemoveMode(User* user, irc::modestacker* stack = NULL); - - ModResult AccessCheck(User* src, Channel*, std::string& value, bool adding) - { - if (!adding && src->nick == value) - return MOD_RES_ALLOW; - return MOD_RES_PASSTHRU; - } -}; - -ModeChannelHalfOp::ModeChannelHalfOp(Module* parent) : ModeHandler(parent, "halfop", 'h', PARAM_ALWAYS, MODETYPE_CHANNEL) -{ - list = true; - prefix = '%'; - levelrequired = OP_VALUE; - m_paramtype = TR_NICK; -} - -unsigned int ModeChannelHalfOp::GetPrefixRank() -{ - return HALFOP_VALUE; -} - -void ModeChannelHalfOp::RemoveMode(Channel* channel, irc::modestacker* stack) -{ - const UserMembList* clist = channel->GetUsers(); - - for (UserMembCIter i = clist->begin(); i != clist->end(); i++) - { - if (stack) - { - stack->Push(this->GetModeChar(), i->first->nick); - } - else - { - std::vector<std::string> parameters; - parameters.push_back(channel->name); - parameters.push_back("-h"); - parameters.push_back(i->first->nick); - ServerInstance->SendMode(parameters, ServerInstance->FakeClient); - } - } - -} - -void ModeChannelHalfOp::RemoveMode(User*, irc::modestacker* stack) -{ -} - -ModeAction ModeChannelHalfOp::OnModeChange(User* source, User*, Channel* channel, std::string ¶meter, bool adding) -{ - return MODEACTION_ALLOW; -} - -class ModuleHalfop : public Module -{ - ModeChannelHalfOp mh; - public: - ModuleHalfop() : mh(this) - { - } - - void init() - { - ServerInstance->Modules->AddService(mh); - } - - Version GetVersion() - { - return Version("Channel half-operator mode provider", VF_VENDOR); - } -}; - -MODULE_INIT(ModuleHalfop) diff --git a/src/modules/m_helpop.cpp b/src/modules/m_helpop.cpp index 92abcd76f..7d7e9663a 100644 --- a/src/modules/m_helpop.cpp +++ b/src/modules/m_helpop.cpp @@ -21,8 +21,6 @@ */ -/* $ModDesc: Provides the /HELPOP command for useful information */ - #include "inspircd.h" static std::map<irc::string, std::string> helpop_map; @@ -98,7 +96,6 @@ class CommandHelpop : public Command class ModuleHelpop : public Module { - private: std::string h_file; CommandHelpop cmd; Helpop ho; @@ -109,13 +106,11 @@ class ModuleHelpop : public Module { } - void init() + void init() CXX11_OVERRIDE { ReadConfig(); ServerInstance->Modules->AddService(ho); ServerInstance->Modules->AddService(cmd); - Implementation eventlist[] = { I_OnRehash, I_OnWhois }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } void ReadConfig() @@ -151,20 +146,20 @@ class ModuleHelpop : public Module } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ReadConfig(); } - void OnWhois(User* src, User* dst) + void OnWhois(User* src, User* dst) CXX11_OVERRIDE { - if (dst->IsModeSet('h')) + if (dst->IsModeSet(ho)) { ServerInstance->SendWhoisLine(src, dst, 310, src->nick+" "+dst->nick+" :is available for help."); } } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides the /HELPOP command for useful information", VF_VENDOR); } diff --git a/src/modules/m_hidechans.cpp b/src/modules/m_hidechans.cpp index 008c62208..1bf87bd14 100644 --- a/src/modules/m_hidechans.cpp +++ b/src/modules/m_hidechans.cpp @@ -20,8 +20,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for hiding channels with user mode +I */ - /** Handles user mode +I */ class HideChans : public SimpleUserModeHandler @@ -39,29 +37,23 @@ class ModuleHideChans : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(hm); - Implementation eventlist[] = { I_OnWhoisLine, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); } - virtual ~ModuleHideChans() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for hiding channels with user mode +I", VF_VENDOR); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { AffectsOpers = ServerInstance->Config->ConfValue("hidechans")->getBool("affectsopers"); } - ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text) + ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text) CXX11_OVERRIDE { /* always show to self */ if (user == dest) @@ -72,7 +64,7 @@ class ModuleHideChans : public Module return MOD_RES_PASSTHRU; /* don't touch if -I */ - if (!dest->IsModeSet('I')) + if (!dest->IsModeSet(hm)) return MOD_RES_PASSTHRU; /* if it affects opers, we don't care if they are opered */ @@ -88,5 +80,4 @@ class ModuleHideChans : public Module } }; - MODULE_INIT(ModuleHideChans) diff --git a/src/modules/m_hideoper.cpp b/src/modules/m_hideoper.cpp index fbab9685f..ded6f6791 100644 --- a/src/modules/m_hideoper.cpp +++ b/src/modules/m_hideoper.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for hiding oper status with user mode +H */ - /** Handles user mode +H */ class HideOper : public SimpleUserModeHandler @@ -43,24 +41,17 @@ class ModuleHideOper : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(hm); - Implementation eventlist[] = { I_OnWhoisLine, I_OnSendWhoLine }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - - virtual ~ModuleHideOper() - { } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for hiding oper status with user mode +H", VF_VENDOR); } - ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text) + ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text) CXX11_OVERRIDE { /* Dont display numeric 313 (RPL_WHOISOPER) if they have +H set and the * person doing the WHOIS is not an oper @@ -68,7 +59,7 @@ class ModuleHideOper : public Module if (numeric != 313) return MOD_RES_PASSTHRU; - if (!dest->IsModeSet('H')) + if (!dest->IsModeSet(hm)) return MOD_RES_PASSTHRU; if (!user->HasPrivPermission("users/auspex")) @@ -77,9 +68,9 @@ class ModuleHideOper : public Module return MOD_RES_PASSTHRU; } - void OnSendWhoLine(User* source, const std::vector<std::string>& params, User* user, std::string& line) + void OnSendWhoLine(User* source, const std::vector<std::string>& params, User* user, std::string& line) CXX11_OVERRIDE { - if (user->IsModeSet('H') && !source->HasPrivPermission("users/auspex")) + if (user->IsModeSet(hm) && !source->HasPrivPermission("users/auspex")) { // hide the "*" that marks the user as an oper from the /WHO line std::string::size_type pos = line.find("*"); @@ -92,5 +83,4 @@ class ModuleHideOper : public Module } }; - MODULE_INIT(ModuleHideOper) diff --git a/src/modules/m_hostchange.cpp b/src/modules/m_hostchange.cpp index 7433fccd3..74c58b22a 100644 --- a/src/modules/m_hostchange.cpp +++ b/src/modules/m_hostchange.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides masking of user hostnames in a different way to m_cloaking */ - /** Holds information on a host set by m_hostchange */ class Host @@ -47,21 +45,18 @@ typedef std::vector<std::pair<std::string, Host> > hostchanges_t; class ModuleHostChange : public Module { - private: hostchanges_t hostchanges; std::string MySuffix; std::string MyPrefix; std::string MySeparator; public: - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); - Implementation eventlist[] = { I_OnRehash, I_OnUserConnect }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* host = ServerInstance->Config->ConfValue("host"); MySuffix = host->getString("suffix"); @@ -97,14 +92,14 @@ class ModuleHostChange : public Module } } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { // returns the version number of the module to be // listed in /MODULES return Version("Provides masking of user hostnames in a different way to m_cloaking", VF_VENDOR); } - virtual void OnUserConnect(LocalUser* user) + void OnUserConnect(LocalUser* user) CXX11_OVERRIDE { for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++) { @@ -160,9 +155,9 @@ class ModuleHostChange : public Module } if (!newhost.empty()) { - user->WriteServ("NOTICE "+user->nick+" :Setting your virtual host: " + newhost); + user->WriteNotice("Setting your virtual host: " + newhost); if (!user->ChangeDisplayedHost(newhost.c_str())) - user->WriteServ("NOTICE "+user->nick+" :Could not set your virtual host: " + newhost); + user->WriteNotice("Could not set your virtual host: " + newhost); return; } } diff --git a/src/modules/m_hostcycle.cpp b/src/modules/m_hostcycle.cpp new file mode 100644 index 000000000..79b4169ec --- /dev/null +++ b/src/modules/m_hostcycle.cpp @@ -0,0 +1,114 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> + * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "inspircd.h" + +class ModuleHostCycle : public Module +{ + /** Send fake quit/join/mode messages for host or ident cycle. + */ + static void DoHostCycle(User* user, const std::string& newident, const std::string& newhost, const char* quitmsg) + { + // GetFullHost() returns the original data at the time this function is called + const std::string quitline = ":" + user->GetFullHost() + " QUIT :" + quitmsg; + + already_sent_t silent_id = ++LocalUser::already_sent_id; + already_sent_t seen_id = ++LocalUser::already_sent_id; + + UserChanList include_chans(user->chans); + std::map<User*,bool> exceptions; + + FOREACH_MOD(OnBuildNeighborList, (user, include_chans, exceptions)); + + for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i) + { + LocalUser* u = IS_LOCAL(i->first); + if (u && !u->quitting) + { + if (i->second) + { + u->already_sent = seen_id; + u->Write(quitline); + } + else + { + u->already_sent = silent_id; + } + } + } + + std::string newfullhost = user->nick + "!" + newident + "@" + newhost; + + for (UCListIter i = include_chans.begin(); i != include_chans.end(); ++i) + { + Channel* c = *i; + Membership* memb = c->GetUser(user); + const std::string joinline = ":" + newfullhost + " JOIN " + c->name; + std::string modeline; + + if (!memb->modes.empty()) + { + modeline = ":" + (ServerInstance->Config->CycleHostsFromUser ? newfullhost : ServerInstance->Config->ServerName) + + " MODE " + c->name + " +" + memb->modes; + + for (size_t j = 0; j < memb->modes.length(); j++) + modeline.append(" ").append(user->nick); + } + + const UserMembList* ulist = c->GetUsers(); + for (UserMembList::const_iterator j = ulist->begin(); j != ulist->end(); ++j) + { + LocalUser* u = IS_LOCAL(j->first); + if (u == NULL || u == user) + continue; + if (u->already_sent == silent_id) + continue; + + if (u->already_sent != seen_id) + { + u->Write(quitline); + u->already_sent = seen_id; + } + + u->Write(joinline); + if (!memb->modes.empty()) + u->Write(modeline); + } + } + } + + public: + void OnChangeIdent(User* user, const std::string& newident) CXX11_OVERRIDE + { + DoHostCycle(user, newident, user->dhost, "Changing ident"); + } + + void OnChangeHost(User* user, const std::string& newhost) CXX11_OVERRIDE + { + DoHostCycle(user, user->ident, newhost, "Changing host"); + } + + Version GetVersion() CXX11_OVERRIDE + { + return Version("Cycles users in all their channels when their host or ident changes", VF_VENDOR); + } +}; + +MODULE_INIT(ModuleHostCycle) diff --git a/src/modules/m_httpd.cpp b/src/modules/m_httpd.cpp index 37f715a8d..9a5722c6a 100644 --- a/src/modules/m_httpd.cpp +++ b/src/modules/m_httpd.cpp @@ -23,10 +23,8 @@ #include "inspircd.h" -#include "httpd.h" - -/* $ModDesc: Provides HTTP serving facilities to modules */ -/* $ModDep: httpd.h */ +#include "iohook.h" +#include "modules/httpd.h" class ModuleHttpServer; @@ -58,18 +56,17 @@ class HttpServerSocket : public BufferedSocket std::string http_version; public: - HttpServerSocket(int newfd, const std::string& IP, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) : BufferedSocket(newfd), ip(IP), postsize(0) { InternalState = HTTP_SERVE_WAIT_REQUEST; - FOREACH_MOD(I_OnHookIO, OnHookIO(this, via)); + FOREACH_MOD(OnHookIO, (this, via)); if (GetIOHook()) GetIOHook()->OnStreamSocketAccept(this, client, server); } - virtual void OnError(BufferedSocketError) + void OnError(BufferedSocketError) CXX11_OVERRIDE { ServerInstance->GlobalCulls.AddItem(this); } @@ -217,7 +214,7 @@ class HttpServerSocket : public BufferedSocket if (reqbuffer.length() >= 8192) { - ServerInstance->Logs->Log("m_httpd",DEBUG, "m_httpd dropped connection due to an oversized request buffer"); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "m_httpd dropped connection due to an oversized request buffer"); reqbuffer.clear(); SetError("Buffer"); } @@ -331,27 +328,39 @@ class HttpServerSocket : public BufferedSocket } }; -class ModuleHttpServer : public Module +class HTTPdAPIImpl : public HTTPdAPIBase { - std::vector<HttpServerSocket *> httpsocks; public: - - void init() + HTTPdAPIImpl(Module* parent) + : HTTPdAPIBase(parent) { - HttpModule = this; - ServerInstance->Modules->Attach(I_OnAcceptConnection, this); } - void OnRequest(Request& request) + void SendResponse(HTTPDocumentResponse& resp) CXX11_OVERRIDE { - if (strcmp(request.id, "HTTP-DOC") != 0) - return; - HTTPDocumentResponse& resp = static_cast<HTTPDocumentResponse&>(request); claimed = true; resp.src.sock->Page(resp.document, resp.responsecode, &resp.headers); } +}; - ModResult OnAcceptConnection(int nfd, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) +class ModuleHttpServer : public Module +{ + std::vector<HttpServerSocket *> httpsocks; + HTTPdAPIImpl APIImpl; + + public: + ModuleHttpServer() + : APIImpl(this) + { + } + + void init() CXX11_OVERRIDE + { + HttpModule = this; + ServerInstance->Modules->AddService(APIImpl); + } + + ModResult OnAcceptConnection(int nfd, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE { if (from->bind_tag->getString("type") != "httpd") return MOD_RES_PASSTHRU; @@ -362,8 +371,7 @@ class ModuleHttpServer : public Module return MOD_RES_ALLOW; } - - virtual ~ModuleHttpServer() + ~ModuleHttpServer() { for (size_t i = 0; i < httpsocks.size(); i++) { @@ -372,7 +380,7 @@ class ModuleHttpServer : public Module } } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides HTTP serving facilities to modules", VF_VENDOR); } diff --git a/src/modules/m_httpd_acl.cpp b/src/modules/m_httpd_acl.cpp index c25cabc0a..272316440 100644 --- a/src/modules/m_httpd_acl.cpp +++ b/src/modules/m_httpd_acl.cpp @@ -19,11 +19,9 @@ #include "inspircd.h" -#include "httpd.h" +#include "modules/httpd.h" #include "protocol.h" -/* $ModDesc: Provides access control lists (passwording of resources, ip restrictions etc) to m_httpd.so dependent modules */ - class HTTPACL { public: @@ -37,17 +35,19 @@ class HTTPACL const std::string &set_whitelist, const std::string &set_blacklist) : path(set_path), username(set_username), password(set_password), whitelist(set_whitelist), blacklist(set_blacklist) { } - - ~HTTPACL() { } }; class ModuleHTTPAccessList : public Module { - std::string stylesheet; std::vector<HTTPACL> acl_list; + HTTPdAPI API; public: + ModuleHTTPAccessList() + : API(this) + { + } void OnRehash(User* user) { @@ -86,37 +86,35 @@ class ModuleHTTPAccessList : public Module } } - ServerInstance->Logs->Log("m_httpd_acl", DEBUG, "Read ACL: path=%s pass=%s whitelist=%s blacklist=%s", path.c_str(), + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Read ACL: path=%s pass=%s whitelist=%s blacklist=%s", path.c_str(), password.c_str(), whitelist.c_str(), blacklist.c_str()); acl_list.push_back(HTTPACL(path, username, password, whitelist, blacklist)); } } - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); - Implementation eventlist[] = { I_OnEvent, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } void BlockAccess(HTTPRequest* http, int returnval, const std::string &extraheaderkey = "", const std::string &extraheaderval="") { - ServerInstance->Logs->Log("m_httpd_acl", DEBUG, "BlockAccess (%d)", returnval); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BlockAccess (%d)", returnval); std::stringstream data("Access to this resource is denied by an access control list. Please contact your IRC administrator."); HTTPDocumentResponse response(this, *http, &data, returnval); - response.headers.SetHeader("X-Powered-By", "m_httpd_acl.so"); + response.headers.SetHeader("X-Powered-By", MODNAME); if (!extraheaderkey.empty()) response.headers.SetHeader(extraheaderkey, extraheaderval); - response.Send(); + API->SendResponse(response); } - void OnEvent(Event& event) + void OnEvent(Event& event) CXX11_OVERRIDE { if (event.id == "httpd_acl") { - ServerInstance->Logs->Log("m_http_stats", DEBUG,"Handling httpd acl event"); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling httpd acl event"); HTTPRequest* http = (HTTPRequest*)&event; for (std::vector<HTTPACL>::const_iterator this_acl = acl_list.begin(); this_acl != acl_list.end(); ++this_acl) @@ -133,7 +131,7 @@ class ModuleHTTPAccessList : public Module { if (InspIRCd::Match(http->GetIP(), entry, ascii_case_insensitive_map)) { - ServerInstance->Logs->Log("m_httpd_acl", DEBUG, "Denying access to blacklisted resource %s (matched by pattern %s) from ip %s (matched by entry %s)", + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Denying access to blacklisted resource %s (matched by pattern %s) from ip %s (matched by entry %s)", http->GetURI().c_str(), this_acl->path.c_str(), http->GetIP().c_str(), entry.c_str()); BlockAccess(http, 403); return; @@ -155,7 +153,7 @@ class ModuleHTTPAccessList : public Module if (!allow_access) { - ServerInstance->Logs->Log("m_httpd_acl", DEBUG, "Denying access to whitelisted resource %s (matched by pattern %s) from ip %s (Not in whitelist)", + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Denying access to whitelisted resource %s (matched by pattern %s) from ip %s (Not in whitelist)", http->GetURI().c_str(), this_acl->path.c_str(), http->GetIP().c_str()); BlockAccess(http, 403); return; @@ -164,7 +162,7 @@ class ModuleHTTPAccessList : public Module if (!this_acl->password.empty() && !this_acl->username.empty()) { /* Password auth, first look to see if we have a basic authentication header */ - ServerInstance->Logs->Log("m_httpd_acl", DEBUG, "Checking HTTP auth password for resource %s (matched by pattern %s) from ip %s, against username %s", + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Checking HTTP auth password for resource %s (matched by pattern %s) from ip %s, against username %s", http->GetURI().c_str(), this_acl->path.c_str(), http->GetIP().c_str(), this_acl->username.c_str()); if (http->headers->IsSet("Authorization")) @@ -183,7 +181,7 @@ class ModuleHTTPAccessList : public Module sep.GetToken(base64); std::string userpass = Base64ToBin(base64); - ServerInstance->Logs->Log("m_httpd_acl", DEBUG, "HTTP authorization: %s (%s)", userpass.c_str(), base64.c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "HTTP authorization: %s (%s)", userpass.c_str(), base64.c_str()); irc::sepstream userpasspair(userpass, ':'); if (userpasspair.GetToken(user)) @@ -193,7 +191,7 @@ class ModuleHTTPAccessList : public Module /* Access granted if username and password are correct */ if (user == this_acl->username && pass == this_acl->password) { - ServerInstance->Logs->Log("m_httpd_acl", DEBUG, "HTTP authorization: password and username match"); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "HTTP authorization: password and username match"); return; } else @@ -222,11 +220,7 @@ class ModuleHTTPAccessList : public Module } } - virtual ~ModuleHTTPAccessList() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides access control lists (passwording of resources, ip restrictions etc) to m_httpd.so dependent modules", VF_VENDOR); } diff --git a/src/modules/m_httpd_config.cpp b/src/modules/m_httpd_config.cpp index 62314cd7e..8333d9f9c 100644 --- a/src/modules/m_httpd_config.cpp +++ b/src/modules/m_httpd_config.cpp @@ -19,18 +19,17 @@ #include "inspircd.h" -#include "httpd.h" +#include "modules/httpd.h" #include "protocol.h" -/* $ModDesc: Allows for the server configuration to be viewed over HTTP via m_httpd.so */ - class ModuleHttpConfig : public Module { + HTTPdAPI API; + public: - void init() + ModuleHttpConfig() + : API(this) { - Implementation eventlist[] = { I_OnEvent }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } std::string Sanitize(const std::string &str) @@ -67,13 +66,13 @@ class ModuleHttpConfig : public Module return ret; } - void OnEvent(Event& event) + void OnEvent(Event& event) CXX11_OVERRIDE { std::stringstream data(""); if (event.id == "httpd_url") { - ServerInstance->Logs->Log("m_http_stats", DEBUG,"Handling httpd event"); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling httpd event"); HTTPRequest* http = (HTTPRequest*)&event; if ((http->GetURI() == "/config") || (http->GetURI() == "/config/")) @@ -95,18 +94,14 @@ class ModuleHttpConfig : public Module data << "</body></html>"; /* Send the document back to m_httpd */ HTTPDocumentResponse response(this, *http, &data, 200); - response.headers.SetHeader("X-Powered-By", "m_httpd_config.so"); + response.headers.SetHeader("X-Powered-By", MODNAME); response.headers.SetHeader("Content-Type", "text/html"); - response.Send(); + API->SendResponse(response); } } } - virtual ~ModuleHttpConfig() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Allows for the server configuration to be viewed over HTTP via m_httpd.so", VF_VENDOR); } diff --git a/src/modules/m_httpd_stats.cpp b/src/modules/m_httpd_stats.cpp index 547d6032f..022d91f1e 100644 --- a/src/modules/m_httpd_stats.cpp +++ b/src/modules/m_httpd_stats.cpp @@ -22,22 +22,19 @@ #include "inspircd.h" -#include "httpd.h" +#include "modules/httpd.h" #include "xline.h" #include "protocol.h" -/* $ModDesc: Provides statistics over HTTP via m_httpd.so */ - class ModuleHttpStats : public Module { static std::map<char, char const*> const &entities; + HTTPdAPI API; public: - - void init() + ModuleHttpStats() + : API(this) { - Implementation eventlist[] = { I_OnEvent }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } std::string Sanitize(const std::string &str) @@ -55,8 +52,7 @@ class ModuleHttpStats : public Module ret += it->second; ret += ';'; } - else if (*x == 0x9 || *x == 0xA || *x == 0xD || - (*x >= 0x20 && *x <= 0xD7FF) || (*x >= 0xE000 && *x <= 0x10FFFF)) + else if (*x == 0x9 || *x == 0xA || *x == 0xD || *x >= 0x20) { // The XML specification defines the following characters as valid inside an XML document: // Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] @@ -92,13 +88,13 @@ class ModuleHttpStats : public Module data << "</metadata>"; } - void OnEvent(Event& event) + void OnEvent(Event& event) CXX11_OVERRIDE { std::stringstream data(""); if (event.id == "httpd_url") { - ServerInstance->Logs->Log("m_http_stats", DEBUG,"Handling httpd event"); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling httpd event"); HTTPRequest* http = (HTTPRequest*)&event; if ((http->GetURI() == "/stats") || (http->GetURI() == "/stats/")) @@ -120,7 +116,13 @@ class ModuleHttpStats : public Module stime = gmtime(&server_uptime); data << "<uptime><days>" << stime->tm_yday << "</days><hours>" << stime->tm_hour << "</hours><mins>" << stime->tm_min << "</mins><secs>" << stime->tm_sec << "</secs><boot_time_t>" << ServerInstance->startup_time << "</boot_time_t></uptime>"; - data << "<isupport>" << Sanitize(ServerInstance->Config->data005) << "</isupport></general><xlines>"; + data << "<isupport>"; + const std::vector<std::string>& isupport = ServerInstance->ISupport.GetLines(); + for (std::vector<std::string>::const_iterator it = isupport.begin(); it != isupport.end(); it++) + { + data << Sanitize(*it) << std::endl; + } + data << "</isupport></general><xlines>"; std::vector<std::string> xltypes = ServerInstance->XLines->GetAllTypes(); for (std::vector<std::string>::iterator it = xltypes.begin(); it != xltypes.end(); ++it) { @@ -188,10 +190,10 @@ class ModuleHttpStats : public Module data << "<nickname>" << u->nick << "</nickname><uuid>" << u->uuid << "</uuid><realhost>" << u->host << "</realhost><displayhost>" << u->dhost << "</displayhost><gecos>" << Sanitize(u->fullname) << "</gecos><server>" << u->server << "</server>"; - if (IS_AWAY(u)) + if (u->IsAway()) data << "<away>" << Sanitize(u->awaymsg) << "</away><awaytime>" << u->awaytime << "</awaytime>"; - if (IS_OPER(u)) - data << "<opertype>" << Sanitize(u->oper->NameStr()) << "</opertype>"; + if (u->IsOper()) + data << "<opertype>" << Sanitize(u->oper->name) << "</opertype>"; data << "<modes>" << u->FormatModes() << "</modes><ident>" << Sanitize(u->ident) << "</ident>"; LocalUser* lu = IS_LOCAL(u); if (lu) @@ -206,10 +208,10 @@ class ModuleHttpStats : public Module data << "</userlist><serverlist>"; - ProtoServerList sl; + ProtocolInterface::ServerList sl; ServerInstance->PI->GetServerList(sl); - for (ProtoServerList::iterator b = sl.begin(); b != sl.end(); ++b) + for (ProtocolInterface::ServerList::const_iterator b = sl.begin(); b != sl.end(); ++b) { data << "<server>"; data << "<servername>" << b->servername << "</servername>"; @@ -226,18 +228,14 @@ class ModuleHttpStats : public Module /* Send the document back to m_httpd */ HTTPDocumentResponse response(this, *http, &data, 200); - response.headers.SetHeader("X-Powered-By", "m_httpd_stats.so"); + response.headers.SetHeader("X-Powered-By", MODNAME); response.headers.SetHeader("Content-Type", "text/xml"); - response.Send(); + API->SendResponse(response); } } } - virtual ~ModuleHttpStats() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides statistics over HTTP via m_httpd.so", VF_VENDOR); } diff --git a/src/modules/m_ident.cpp b/src/modules/m_ident.cpp index 6099e7c14..bbd66530e 100644 --- a/src/modules/m_ident.cpp +++ b/src/modules/m_ident.cpp @@ -24,8 +24,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for RFC1413 ident lookups */ - /* -------------------------------------------------------------- * Note that this is the third incarnation of m_ident. The first * two attempts were pretty crashy, mainly due to the fact we tried @@ -142,9 +140,9 @@ class IdentRequestSocket : public EventHandler } } - virtual void OnConnected() + void OnConnected() { - ServerInstance->Logs->Log("m_ident",DEBUG,"OnConnected()"); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "OnConnected()"); ServerInstance->SE->ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); char req[32]; @@ -165,7 +163,7 @@ class IdentRequestSocket : public EventHandler done = true; } - virtual void HandleEvent(EventType et, int errornum = 0) + void HandleEvent(EventType et, int errornum = 0) { switch (et) { @@ -179,7 +177,7 @@ class IdentRequestSocket : public EventHandler break; case EVENT_ERROR: /* fd error event, ohshi- */ - ServerInstance->Logs->Log("m_ident",DEBUG,"EVENT_ERROR"); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "EVENT_ERROR"); /* We *must* Close() here immediately or we get a * huge storm of EVENT_ERROR events! */ @@ -196,7 +194,7 @@ class IdentRequestSocket : public EventHandler */ if (GetFd() > -1) { - ServerInstance->Logs->Log("m_ident",DEBUG,"Close ident socket %d", GetFd()); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Close ident socket %d", GetFd()); ServerInstance->SE->DelFd(this); ServerInstance->SE->Close(GetFd()); this->SetFd(-1); @@ -213,8 +211,8 @@ class IdentRequestSocket : public EventHandler /* We don't really need to buffer for incomplete replies here, since IDENT replies are * extremely short - there is *no* sane reason it'd be in more than one packet */ - char ibuf[MAXBUF]; - int recvresult = ServerInstance->SE->Recv(this, ibuf, MAXBUF-1, 0); + char ibuf[256]; + int recvresult = ServerInstance->SE->Recv(this, ibuf, sizeof(ibuf)-1, 0); /* Close (but don't delete from memory) our socket * and flag as done since the ident lookup has finished @@ -228,7 +226,7 @@ class IdentRequestSocket : public EventHandler if (recvresult < 3) return; - ServerInstance->Logs->Log("m_ident",DEBUG,"ReadResponse()"); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "ReadResponse()"); /* Truncate at the first null character, but first make sure * there is at least one null char (at the end of the buffer). @@ -260,7 +258,7 @@ class IdentRequestSocket : public EventHandler * we're done. */ result += *i; - if (!ServerInstance->IsIdent(result.c_str())) + if (!ServerInstance->IsIdent(result)) { result.erase(result.end()-1); break; @@ -278,40 +276,31 @@ class ModuleIdent : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(ext); OnRehash(NULL); - Implementation eventlist[] = { - I_OnRehash, I_OnUserInit, I_OnCheckReady, - I_OnUserDisconnect, I_OnSetConnectClass - }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - ~ModuleIdent() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for RFC1413 ident lookups", VF_VENDOR); } - virtual void OnRehash(User *user) + void OnRehash(User *user) CXX11_OVERRIDE { RequestTimeout = ServerInstance->Config->ConfValue("ident")->getInt("timeout", 5); if (!RequestTimeout) RequestTimeout = 5; } - void OnUserInit(LocalUser *user) + void OnUserInit(LocalUser *user) CXX11_OVERRIDE { ConfigTag* tag = user->MyClass->config; if (!tag->getBool("useident", true)) return; - user->WriteServ("NOTICE Auth :*** Looking up your ident..."); + user->WriteNotice("*** Looking up your ident..."); try { @@ -320,7 +309,7 @@ class ModuleIdent : public Module } catch (ModuleException &e) { - ServerInstance->Logs->Log("m_ident",DEBUG,"Ident exception: %s", e.GetReason()); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Ident exception: %s", e.GetReason()); } } @@ -328,17 +317,12 @@ class ModuleIdent : public Module * creating a Timer object and especially better than creating a * Timer per ident lookup! */ - virtual ModResult OnCheckReady(LocalUser *user) + ModResult OnCheckReady(LocalUser *user) CXX11_OVERRIDE { /* Does user have an ident socket attached at all? */ IdentRequestSocket *isock = ext.get(user); if (!isock) - { - ServerInstance->Logs->Log("m_ident",DEBUG, "No ident socket :("); return MOD_RES_PASSTHRU; - } - - ServerInstance->Logs->Log("m_ident",DEBUG, "Has ident_socket"); time_t compare = isock->age; compare += RequestTimeout; @@ -347,28 +331,24 @@ class ModuleIdent : public Module if (ServerInstance->Time() >= compare) { /* Ident timeout */ - user->WriteServ("NOTICE Auth :*** Ident request timed out."); - ServerInstance->Logs->Log("m_ident",DEBUG, "Timeout"); + user->WriteNotice("*** Ident request timed out."); } else if (!isock->HasResult()) { // time still good, no result yet... hold the registration - ServerInstance->Logs->Log("m_ident",DEBUG, "No result yet"); return MOD_RES_DENY; } - ServerInstance->Logs->Log("m_ident",DEBUG, "Yay, result!"); - /* wooo, got a result (it will be good, or bad) */ if (isock->result.empty()) { user->ident.insert(0, 1, '~'); - user->WriteServ("NOTICE Auth :*** Could not find your ident, using %s instead.", user->ident.c_str()); + user->WriteNotice("*** Could not find your ident, using " + user->ident + " instead."); } else { user->ident = isock->result; - user->WriteServ("NOTICE Auth :*** Found your ident, '%s'", user->ident.c_str()); + user->WriteNotice("*** Found your ident, '" + user->ident + "'"); } user->InvalidateCache(); @@ -377,14 +357,14 @@ class ModuleIdent : public Module return MOD_RES_PASSTHRU; } - ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) + ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE { if (myclass->config->getBool("requireident") && user->ident[0] == '~') return MOD_RES_DENY; return MOD_RES_PASSTHRU; } - virtual void OnCleanup(int target_type, void *item) + void OnCleanup(int target_type, void *item) CXX11_OVERRIDE { /* Module unloading, tidy up users */ if (target_type == TYPE_USER) @@ -395,7 +375,7 @@ class ModuleIdent : public Module } } - virtual void OnUserDisconnect(LocalUser *user) + void OnUserDisconnect(LocalUser *user) CXX11_OVERRIDE { /* User disconnect (generic socket detatch event) */ IdentRequestSocket *isock = ext.get(user); @@ -408,4 +388,3 @@ class ModuleIdent : public Module }; MODULE_INIT(ModuleIdent) - diff --git a/src/modules/m_inviteexception.cpp b/src/modules/m_inviteexception.cpp index 747a3b30a..700df27fb 100644 --- a/src/modules/m_inviteexception.cpp +++ b/src/modules/m_inviteexception.cpp @@ -22,10 +22,7 @@ #include "inspircd.h" -#include "u_listmode.h" - -/* $ModDesc: Provides support for the +I channel mode */ -/* $ModDep: ../../include/u_listmode.h */ +#include "listmode.h" /* * Written by Om <om@inspircd.org>, April 2005. @@ -54,27 +51,25 @@ public: { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(ie); OnRehash(NULL); ie.DoImplements(this); - Implementation eventlist[] = { I_On005Numeric, I_OnCheckInvite, I_OnCheckKey, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - output.append(" INVEX=I"); + tokens["INVEX"] = "I"; } - ModResult OnCheckInvite(User* user, Channel* chan) + ModResult OnCheckInvite(User* user, Channel* chan) CXX11_OVERRIDE { - modelist* list = ie.extItem.get(chan); + ListModeBase::ModeList* list = ie.GetList(chan); if (list) { - for (modelist::iterator it = list->begin(); it != list->end(); it++) + for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++) { if (chan->CheckBan(user, it->mask)) { @@ -86,25 +81,25 @@ public: return MOD_RES_PASSTHRU; } - ModResult OnCheckKey(User* user, Channel* chan, const std::string& key) + ModResult OnCheckKey(User* user, Channel* chan, const std::string& key) CXX11_OVERRIDE { if (invite_bypass_key) return OnCheckInvite(user, chan); return MOD_RES_PASSTHRU; } - void OnSyncChannel(Channel* chan, Module* proto, void* opaque) + void OnSyncChannel(Channel* chan, Module* proto, void* opaque) CXX11_OVERRIDE { ie.DoSyncChannel(chan, proto, opaque); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { invite_bypass_key = ServerInstance->Config->ConfValue("inviteexception")->getBool("bypasskey", true); ie.DoRehash(); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for the +I channel mode", VF_VENDOR); } diff --git a/src/modules/m_ircv3.cpp b/src/modules/m_ircv3.cpp index da42d823d..f46ae97b4 100644 --- a/src/modules/m_ircv3.cpp +++ b/src/modules/m_ircv3.cpp @@ -16,11 +16,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* $ModDesc: Provides support for extended-join, away-notify and account-notify CAP capabilities */ - #include "inspircd.h" -#include "account.h" -#include "m_cap.h" +#include "modules/account.h" +#include "modules/cap.h" class ModuleIRCv3 : public Module { @@ -38,7 +36,7 @@ class ModuleIRCv3 : public Module UserChanList chans(user->chans); std::map<User*, bool> exceptions; - FOREACH_MOD(I_OnBuildNeighborList, OnBuildNeighborList(user, chans, exceptions)); + FOREACH_MOD(OnBuildNeighborList, (user, chans, exceptions)); // Send it to all local users who were explicitly marked as neighbours by modules and have the required ext for (std::map<User*, bool>::const_iterator i = exceptions.begin(); i != exceptions.end(); ++i) @@ -78,22 +76,20 @@ class ModuleIRCv3 : public Module { } - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); - Implementation eventlist[] = { I_OnUserJoin, I_OnPostJoin, I_OnSetAway, I_OnEvent, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* conf = ServerInstance->Config->ConfValue("ircv3"); - accountnotify = conf->getBool("accountnotify", conf->getBool("accoutnotify", true)); + accountnotify = conf->getBool("accountnotify", true); awaynotify = conf->getBool("awaynotify", true); extendedjoin = conf->getBool("extendedjoin", true); } - void OnEvent(Event& ev) + void OnEvent(Event& ev) CXX11_OVERRIDE { if (awaynotify) cap_awaynotify.HandleEvent(ev); @@ -122,10 +118,10 @@ class ModuleIRCv3 : public Module } } - void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) + void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) CXX11_OVERRIDE { // Remember who is not going to see the JOIN because of other modules - if ((awaynotify) && (IS_AWAY(memb->user))) + if ((awaynotify) && (memb->user->IsAway())) last_excepts = excepts; if (!extendedjoin) @@ -195,7 +191,7 @@ class ModuleIRCv3 : public Module } } - ModResult OnSetAway(User* user, const std::string &awaymsg) + ModResult OnSetAway(User* user, const std::string &awaymsg) CXX11_OVERRIDE { if (awaynotify) { @@ -210,9 +206,9 @@ class ModuleIRCv3 : public Module return MOD_RES_PASSTHRU; } - void OnPostJoin(Membership *memb) + void OnPostJoin(Membership *memb) CXX11_OVERRIDE { - if ((!awaynotify) || (!IS_AWAY(memb->user))) + if ((!awaynotify) || (!memb->user->IsAway())) return; std::string line = ":" + memb->user->GetFullHost() + " AWAY :" + memb->user->awaymsg; @@ -236,7 +232,7 @@ class ModuleIRCv3 : public Module ServerInstance->Modules->SetPriority(this, I_OnUserJoin, PRIORITY_LAST); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for extended-join, away-notify and account-notify CAP capabilities", VF_VENDOR); } diff --git a/src/modules/m_joinflood.cpp b/src/modules/m_joinflood.cpp index 0c68da1fb..efb277f81 100644 --- a/src/modules/m_joinflood.cpp +++ b/src/modules/m_joinflood.cpp @@ -23,35 +23,32 @@ #include "inspircd.h" -/* $ModDesc: Provides channel mode +j (join flood protection) */ - /** Holds settings and state associated with channel mode +j */ class joinfloodsettings { public: - int secs; - int joins; + unsigned int secs; + unsigned int joins; time_t reset; time_t unlocktime; - int counter; - bool locked; + unsigned int counter; - joinfloodsettings(int b, int c) : secs(b), joins(c) + joinfloodsettings(unsigned int b, unsigned int c) + : secs(b), joins(c), unlocktime(0), counter(0) { reset = ServerInstance->Time() + secs; - counter = 0; - locked = false; - }; + } void addjoin() { - counter++; if (ServerInstance->Time() > reset) { - counter = 0; + counter = 1; reset = ServerInstance->Time() + secs; } + else + counter++; } bool shouldlock() @@ -66,27 +63,21 @@ class joinfloodsettings bool islocked() { - if (locked) - { - if (ServerInstance->Time() > unlocktime) - { - locked = false; - return false; - } - else - { - return true; - } - } - return false; + if (ServerInstance->Time() > unlocktime) + unlocktime = 0; + + return (unlocktime != 0); } void lock() { - locked = true; unlocktime = ServerInstance->Time() + 60; } + bool operator==(const joinfloodsettings& other) const + { + return ((this->secs == other.secs) && (this->joins == other.joins)); + } }; /** Handles channel mode +j @@ -102,85 +93,41 @@ class JoinFlood : public ModeHandler { if (adding) { - char ndata[MAXBUF]; - char* data = ndata; - strlcpy(ndata,parameter.c_str(),MAXBUF); - char* joins = data; - char* secs = NULL; - while (*data) + std::string::size_type colon = parameter.find(':'); + if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) { - if (*data == ':') - { - *data = 0; - data++; - secs = data; - break; - } - else data++; + source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str()); + return MODEACTION_DENY; } - if (secs) - { - /* Set up the flood parameters for this channel */ - int njoins = atoi(joins); - int nsecs = atoi(secs); - if ((njoins<1) || (nsecs<1)) - { - source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str()); - parameter.clear(); - return MODEACTION_DENY; - } - else - { - joinfloodsettings* f = ext.get(channel); - if (!f) - { - parameter = ConvToStr(njoins) + ":" +ConvToStr(nsecs); - f = new joinfloodsettings(nsecs, njoins); - ext.set(channel, f); - channel->SetModeParam('j', parameter); - return MODEACTION_ALLOW; - } - else - { - std::string cur_param = channel->GetModeParameter('j'); - parameter = ConvToStr(njoins) + ":" +ConvToStr(nsecs); - if (cur_param == parameter) - { - // mode params match - return MODEACTION_DENY; - } - else - { - // new mode param, replace old with new - if ((nsecs > 0) && (njoins > 0)) - { - f = new joinfloodsettings(nsecs, njoins); - ext.set(channel, f); - channel->SetModeParam('j', parameter); - return MODEACTION_ALLOW; - } - else - { - return MODEACTION_DENY; - } - } - } - } - } - else + /* Set up the flood parameters for this channel */ + unsigned int njoins = ConvToInt(parameter.substr(0, colon)); + unsigned int nsecs = ConvToInt(parameter.substr(colon+1)); + if ((njoins<1) || (nsecs<1)) { source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str()); return MODEACTION_DENY; } + + joinfloodsettings jfs(nsecs, njoins); + joinfloodsettings* f = ext.get(channel); + if ((f) && (*f == jfs)) + // mode params match + return MODEACTION_DENY; + + ext.set(channel, jfs); + parameter = ConvToStr(njoins) + ":" + ConvToStr(nsecs); + return MODEACTION_ALLOW; } else { + if (!channel->IsModeSet(this)) + return MODEACTION_DENY; + joinfloodsettings* f = ext.get(channel); if (f) { ext.unset(channel); - channel->SetModeParam('j', ""); return MODEACTION_ALLOW; } } @@ -190,25 +137,21 @@ class JoinFlood : public ModeHandler class ModuleJoinFlood : public Module { - JoinFlood jf; public: - ModuleJoinFlood() : jf(this) { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(jf); ServerInstance->Modules->AddService(jf.ext); - Implementation eventlist[] = { I_OnUserPreJoin, I_OnUserJoin }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven) + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { if (chan) { @@ -222,7 +165,7 @@ class ModuleJoinFlood : public Module return MOD_RES_PASSTHRU; } - void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) + void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) CXX11_OVERRIDE { /* We arent interested in JOIN events caused by a network burst */ if (sync) @@ -243,11 +186,7 @@ class ModuleJoinFlood : public Module } } - ~ModuleJoinFlood() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +j (join flood protection)", VF_VENDOR); } diff --git a/src/modules/m_jumpserver.cpp b/src/modules/m_jumpserver.cpp index dce8f0bd5..81022a907 100644 --- a/src/modules/m_jumpserver.cpp +++ b/src/modules/m_jumpserver.cpp @@ -20,8 +20,7 @@ #include "inspircd.h" - -/* $ModDesc: Provides support for the RPL_REDIR numeric and the /JUMPSERVER command. */ +#include "modules/ssl.h" /** Handle /JUMPSERVER */ @@ -32,11 +31,14 @@ class CommandJumpserver : public Command std::string redirect_to; std::string reason; int port; + int sslport; CommandJumpserver(Module* Creator) : Command(Creator, "JUMPSERVER", 0, 4) { - flags_needed = 'o'; syntax = "[<server> <port> <+/-an> <reason>]"; + flags_needed = 'o'; + syntax = "[<server> <port>[:<sslport>] <+/-an> <reason>]"; port = 0; + sslport = 0; redirect_new_users = false; } @@ -53,11 +55,12 @@ class CommandJumpserver : public Command if (!parameters.size()) { if (port) - user->WriteServ("NOTICE %s :*** Disabled jumpserver (previously set to '%s:%d')", user->nick.c_str(), redirect_to.c_str(), port); + user->WriteNotice("*** Disabled jumpserver (previously set to '" + redirect_to + ":" + ConvToStr(port) + "')"); else - user->WriteServ("NOTICE %s :*** Jumpserver was not enabled.", user->nick.c_str()); + user->WriteNotice("*** Jumpserver was not enabled."); port = 0; + sslport = 0; redirect_to.clear(); return CMD_SUCCESS; } @@ -84,15 +87,21 @@ class CommandJumpserver : public Command redirect_new_users = direction; break; default: - user->WriteServ("NOTICE %s :*** Invalid JUMPSERVER flag: %c", user->nick.c_str(), *n); + user->WriteNotice("*** Invalid JUMPSERVER flag: " + ConvToStr(*n)); return CMD_FAILURE; break; } } - if (!atoi(parameters[1].c_str())) + size_t delimpos = parameters[1].find(':'); + port = ConvToInt(parameters[1].substr(0, delimpos ? delimpos : std::string::npos)); + sslport = (delimpos == std::string::npos ? 0 : ConvToInt(parameters[1].substr(delimpos + 1))); + + if (parameters[1].find_first_not_of("0123456789:") != std::string::npos + || parameters[1].rfind(':') != delimpos + || port > 65535 || sslport > 65535) { - user->WriteServ("NOTICE %s :*** Invalid port number", user->nick.c_str()); + user->WriteNotice("*** Invalid port number"); return CMD_FAILURE; } @@ -101,10 +110,10 @@ class CommandJumpserver : public Command /* Redirect everyone but the oper sending the command */ for (LocalUserList::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); ++i) { - User* t = *i; - if (!IS_OPER(t)) + LocalUser* t = *i; + if (!t->IsOper()) { - t->WriteNumeric(10, "%s %s %s :Please use this Server/Port instead", t->nick.c_str(), parameters[0].c_str(), parameters[1].c_str()); + t->WriteNumeric(10, "%s %s %d :Please use this Server/Port instead", t->nick.c_str(), parameters[0].c_str(), GetPort(t)); ServerInstance->Users->QuitUser(t, reason); n_done++; } @@ -116,24 +125,24 @@ class CommandJumpserver : public Command } if (redirect_new_users) - { redirect_to = parameters[0]; - port = atoi(parameters[1].c_str()); - } - user->WriteServ("NOTICE %s :*** Set jumpserver to server '%s' port '%s', flags '+%s%s'%s%s%s: %s", user->nick.c_str(), parameters[0].c_str(), parameters[1].c_str(), - redirect_all_immediately ? "a" : "", - redirect_new_users ? "n" : "", - n_done ? " (" : "", - n_done ? n_done_s.c_str() : "", - n_done ? " user(s) redirected)" : "", - reason.c_str()); + user->WriteNotice("*** Set jumpserver to server '" + parameters[0] + "' port '" + (port ? ConvToStr(port) : "Auto") + ", SSL " + (sslport ? ConvToStr(sslport) : "Auto") + "', flags '+" + + (redirect_all_immediately ? "a" : "") + (redirect_new_users ? "n'" : "'") + + (n_done ? " (" + n_done_s + "user(s) redirected): " : ": ") + reason); } return CMD_SUCCESS; } -}; + int GetPort(LocalUser* user) + { + int p = (SSLClientCert::GetCertificate(&user->eh) ? sslport : port); + if (p == 0) + p = user->GetServerPort(); + return p; + } +}; class ModuleJumpServer : public Module { @@ -143,40 +152,34 @@ class ModuleJumpServer : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(js); - Implementation eventlist[] = { I_OnUserRegister, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - virtual ~ModuleJumpServer() - { } - virtual ModResult OnUserRegister(LocalUser* user) + ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE { - if (js.port && js.redirect_new_users) + if (js.redirect_new_users) { + int port = js.GetPort(user); user->WriteNumeric(10, "%s %s %d :Please use this Server/Port instead", - user->nick.c_str(), js.redirect_to.c_str(), js.port); + user->nick.c_str(), js.redirect_to.c_str(), port); ServerInstance->Users->QuitUser(user, js.reason); return MOD_RES_PASSTHRU; } return MOD_RES_PASSTHRU; } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { // Emergency way to unlock if (!user) js.redirect_new_users = false; } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for the RPL_REDIR numeric and the /JUMPSERVER command.", VF_VENDOR); } - }; MODULE_INIT(ModuleJumpServer) diff --git a/src/modules/m_kicknorejoin.cpp b/src/modules/m_kicknorejoin.cpp index a914f3869..bb04610de 100644 --- a/src/modules/m_kicknorejoin.cpp +++ b/src/modules/m_kicknorejoin.cpp @@ -25,16 +25,14 @@ #include "inspircd.h" -/* $ModDesc: Provides channel mode +J (delay rejoin after kick) */ - typedef std::map<std::string, time_t> delaylist; /** Handles channel mode +J */ class KickRejoin : public ModeHandler { + static const unsigned int max = 60; public: - unsigned int max; SimpleExtItem<delaylist> ext; KickRejoin(Module* Creator) : ModeHandler(Creator, "kicknorejoin", 'J', PARAM_SETONLY, MODETYPE_CHANNEL) @@ -42,7 +40,7 @@ class KickRejoin : public ModeHandler { } - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) + ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE { if (adding) { @@ -56,7 +54,6 @@ class KickRejoin : public ModeHandler v = max; parameter = ConvToStr(v); - channel->SetModeParam(this, parameter); } else { @@ -64,7 +61,6 @@ class KickRejoin : public ModeHandler return MODEACTION_DENY; ext.unset(channel); - channel->SetModeParam(this, ""); } return MODEACTION_ALLOW; } @@ -75,29 +71,18 @@ class ModuleKickNoRejoin : public Module KickRejoin kr; public: - ModuleKickNoRejoin() : kr(this) { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(kr); ServerInstance->Modules->AddService(kr.ext); - Implementation eventlist[] = { I_OnUserPreJoin, I_OnUserKick, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - OnRehash(NULL); - } - - void OnRehash(User* user) - { - kr.max = ServerInstance->Duration(ServerInstance->Config->ConfValue("kicknorejoin")->getString("maxtime")); - if (!kr.max) - kr.max = 30*60; } - ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven) + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { if (chan) { @@ -131,7 +116,7 @@ public: return MOD_RES_PASSTHRU; } - void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) + void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) CXX11_OVERRIDE { if (memb->chan->IsModeSet(&kr) && (IS_LOCAL(memb->user)) && (source != memb->user)) { @@ -145,15 +130,10 @@ public: } } - ~ModuleKickNoRejoin() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Channel mode to delay rejoin after kick", VF_VENDOR); } }; - MODULE_INIT(ModuleKickNoRejoin) diff --git a/src/modules/m_knock.cpp b/src/modules/m_knock.cpp index 8d2aa4543..96ea66d7b 100644 --- a/src/modules/m_knock.cpp +++ b/src/modules/m_knock.cpp @@ -21,20 +21,23 @@ #include "inspircd.h" -/* $ModDesc: Provides support for /KNOCK and channel mode +K */ - /** Handles the /KNOCK command */ class CommandKnock : public Command { + SimpleChannelModeHandler& noknockmode; + ChanModeReference inviteonlymode; + public: bool sendnotice; bool sendnumeric; - CommandKnock(Module* Creator) : Command(Creator,"KNOCK", 2, 2) + CommandKnock(Module* Creator, SimpleChannelModeHandler& Noknockmode) + : Command(Creator,"KNOCK", 2, 2) + , noknockmode(Noknockmode) + , inviteonlymode(Creator, "inviteonly") { syntax = "<channel> <reason>"; Penalty = 5; - TRANSLATE3(TR_TEXT, TR_TEXT, TR_END); } CmdResult Handle (const std::vector<std::string> ¶meters, User *user) @@ -52,13 +55,13 @@ class CommandKnock : public Command return CMD_FAILURE; } - if (c->IsModeSet('K')) + if (c->IsModeSet(noknockmode)) { user->WriteNumeric(480, "%s :Can't KNOCK on %s, +K is set.",user->nick.c_str(), c->name.c_str()); return CMD_FAILURE; } - if (!c->IsModeSet('i')) + if (!c->IsModeSet(inviteonlymode)) { user->WriteNumeric(480, "%s :Can't KNOCK on %s, channel is not invite only so knocking is pointless!",user->nick.c_str(), c->name.c_str()); return CMD_FAILURE; @@ -70,7 +73,7 @@ class CommandKnock : public Command if (sendnumeric) c->WriteChannelWithServ(ServerInstance->Config->ServerName, "710 %s %s %s :is KNOCKing: %s", c->name.c_str(), c->name.c_str(), user->GetFullHost().c_str(), parameters[1].c_str()); - user->WriteServ("NOTICE %s :KNOCKing on %s", user->nick.c_str(), c->name.c_str()); + user->WriteNotice("KNOCKing on " + c->name); return CMD_SUCCESS; } @@ -80,33 +83,27 @@ class CommandKnock : public Command } }; -/** Handles channel mode +K - */ -class Knock : public SimpleChannelModeHandler -{ - public: - Knock(Module* Creator) : SimpleChannelModeHandler(Creator, "noknock", 'K') { } -}; - class ModuleKnock : public Module { + SimpleChannelModeHandler kn; CommandKnock cmd; - Knock kn; + public: - ModuleKnock() : cmd(this), kn(this) + ModuleKnock() + : kn(this, "noknock", 'K') + , cmd(this, kn) { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(kn); ServerInstance->Modules->AddService(cmd); - ServerInstance->Modules->Attach(I_OnRehash, this); OnRehash(NULL); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { std::string knocknotify = ServerInstance->Config->ConfValue("knock")->getString("notify"); irc::string notify(knocknotify.c_str()); @@ -128,7 +125,7 @@ class ModuleKnock : public Module } } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for /KNOCK and channel mode +K", VF_OPTCOMMON | VF_VENDOR); } diff --git a/src/modules/m_lockserv.cpp b/src/modules/m_lockserv.cpp index 4983ae16a..8fae86e1e 100644 --- a/src/modules/m_lockserv.cpp +++ b/src/modules/m_lockserv.cpp @@ -20,18 +20,16 @@ #include "inspircd.h" -/* $ModDesc: Allows locking of the server to stop all incoming connections till unlocked again */ - /** Adds numerics * 988 <nick> <servername> :Closed for new connections * 989 <nick> <servername> :Open for new connections -*/ - + */ class CommandLockserv : public Command { bool& locked; -public: + + public: CommandLockserv(Module* Creator, bool& lock) : Command(Creator, "LOCKSERV", 0), locked(lock) { flags_needed = 'o'; @@ -41,7 +39,7 @@ public: { if (locked) { - user->WriteServ("NOTICE %s :The server is already locked.", user->nick.c_str()); + user->WriteNotice("The server is already locked."); return CMD_FAILURE; } @@ -54,10 +52,9 @@ public: class CommandUnlockserv : public Command { -private: bool& locked; -public: + public: CommandUnlockserv(Module* Creator, bool &lock) : Command(Creator, "UNLOCKSERV", 0), locked(lock) { flags_needed = 'o'; @@ -67,7 +64,7 @@ public: { if (!locked) { - user->WriteServ("NOTICE %s :The server isn't locked.", user->nick.c_str()); + user->WriteNotice("The server isn't locked."); return CMD_FAILURE; } @@ -80,37 +77,29 @@ public: class ModuleLockserv : public Module { -private: bool locked; CommandLockserv lockcommand; CommandUnlockserv unlockcommand; -public: + public: ModuleLockserv() : lockcommand(this, locked), unlockcommand(this, locked) { } - void init() + void init() CXX11_OVERRIDE { locked = false; ServerInstance->Modules->AddService(lockcommand); ServerInstance->Modules->AddService(unlockcommand); - Implementation eventlist[] = { I_OnUserRegister, I_OnRehash, I_OnCheckReady }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual ~ModuleLockserv() - { - } - - - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { // Emergency way to unlock if (!user) locked = false; } - virtual ModResult OnUserRegister(LocalUser* user) + ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE { if (locked) { @@ -120,12 +109,12 @@ public: return MOD_RES_PASSTHRU; } - virtual ModResult OnCheckReady(LocalUser* user) + ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE { return locked ? MOD_RES_DENY : MOD_RES_PASSTHRU; } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Allows locking of the server to stop all incoming connections until unlocked again", VF_VENDOR); } diff --git a/src/modules/m_maphide.cpp b/src/modules/m_maphide.cpp index 546e342ae..21072c1fc 100644 --- a/src/modules/m_maphide.cpp +++ b/src/modules/m_maphide.cpp @@ -19,44 +19,35 @@ #include "inspircd.h" -/* $ModDesc: Hide /MAP and /LINKS in the same form as ircu (mostly useless) */ - class ModuleMapHide : public Module { std::string url; public: - void init() + void init() CXX11_OVERRIDE { - Implementation eventlist[] = { I_OnPreCommand, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { url = ServerInstance->Config->ConfValue("security")->getString("maphide"); } - ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) + ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE { - if (validated && !IS_OPER(user) && !url.empty() && (command == "MAP" || command == "LINKS")) + if (validated && !user->IsOper() && !url.empty() && (command == "MAP" || command == "LINKS")) { - user->WriteServ("NOTICE %s :/%s has been disabled; visit %s", user->nick.c_str(), command.c_str(), url.c_str()); + user->WriteNotice("/" + command + " has been disabled; visit " + url); return MOD_RES_DENY; } else return MOD_RES_PASSTHRU; } - virtual ~ModuleMapHide() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Hide /MAP and /LINKS in the same form as ircu (mostly useless)", VF_VENDOR); } }; MODULE_INIT(ModuleMapHide) - diff --git a/src/modules/m_md5.cpp b/src/modules/m_md5.cpp index 14ccf16a8..dd72fe9ea 100644 --- a/src/modules/m_md5.cpp +++ b/src/modules/m_md5.cpp @@ -21,13 +21,8 @@ */ -/* $ModDesc: Allows for MD5 encrypted oper passwords */ - #include "inspircd.h" -#ifdef HAS_STDINT -#include <stdint.h> -#endif -#include "hash.h" +#include "modules/hash.h" /* The four core functions - F1 is optimized somewhat */ #define F1(x, y, z) (z ^ (x & (y ^ z))) @@ -39,10 +34,6 @@ #define MD5STEP(f,w,x,y,z,in,s) \ (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x) -#ifndef HAS_STDINT -typedef unsigned int uint32_t; -#endif - typedef uint32_t word32; /* NOT unsigned long. We don't support 16 bit platforms, anyway. */ typedef unsigned char byte; @@ -275,13 +266,6 @@ class MD5Provider : public HashProvider return std::string(res, 16); } - std::string sumIV(unsigned int* IV, const char* HexMap, const std::string &sdata) - { - char res[33]; - GenHash(sdata.data(), res, HexMap, IV, sdata.length()); - return res; - } - MD5Provider(Module* parent) : HashProvider(parent, "hash/md5", 16, 64) {} }; @@ -294,7 +278,7 @@ class ModuleMD5 : public Module ServerInstance->Modules->AddService(md5); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Implements MD5 hashing",VF_VENDOR); } diff --git a/src/modules/m_messageflood.cpp b/src/modules/m_messageflood.cpp index 9ff17924d..ef7bf9d52 100644 --- a/src/modules/m_messageflood.cpp +++ b/src/modules/m_messageflood.cpp @@ -25,8 +25,6 @@ #include "inspircd.h" -/* $ModDesc: Provides channel mode +f (message flood protection) */ - /** Holds flood settings and state for mode +f */ class floodsettings @@ -102,16 +100,14 @@ class MsgFlood : public ModeHandler ext.set(channel, new floodsettings(ban, nsecs, nlines)); parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" + ConvToStr(nsecs); - channel->SetModeParam('f', parameter); return MODEACTION_ALLOW; } else { - if (!channel->IsModeSet('f')) + if (!channel->IsModeSet(this)) return MODEACTION_DENY; ext.unset(channel); - channel->SetModeParam('f', ""); return MODEACTION_ALLOW; } } @@ -128,17 +124,15 @@ class ModuleMsgFlood : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(mf); ServerInstance->Modules->AddService(mf.ext); - Implementation eventlist[] = { I_OnUserPreNotice, I_OnUserPreMessage }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } ModResult ProcessMessages(User* user,Channel* dest, const std::string &text) { - if ((!IS_LOCAL(user)) || !dest->IsModeSet('f')) + if ((!IS_LOCAL(user)) || !dest->IsModeSet(mf)) return MOD_RES_PASSTHRU; if (ServerInstance->OnCheckExemption(user,dest,"flood") == MOD_RES_ALLOW) @@ -156,14 +150,14 @@ class ModuleMsgFlood : public Module std::vector<std::string> parameters; parameters.push_back(dest->name); parameters.push_back("+b"); - parameters.push_back(user->MakeWildHost()); - ServerInstance->SendGlobalMode(parameters, ServerInstance->FakeClient); + parameters.push_back("*!*@" + user->dhost); + ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient); } - char kickmessage[MAXBUF]; - snprintf(kickmessage, MAXBUF, "Channel flood triggered (limit is %u lines in %u secs)", f->lines, f->secs); + const std::string kickMessage = "Channel flood triggered (limit is " + ConvToStr(f->lines) + + " in " + ConvToStr(f->secs) + " secs)"; - dest->KickUser(ServerInstance->FakeClient, user, kickmessage); + dest->KickUser(ServerInstance->FakeClient, user, kickMessage); return MOD_RES_DENY; } @@ -172,15 +166,7 @@ class ModuleMsgFlood : public Module return MOD_RES_PASSTHRU; } - ModResult OnUserPreMessage(User *user, void *dest, int target_type, std::string &text, char status, CUList &exempt_list) - { - if (target_type == TYPE_CHANNEL) - return ProcessMessages(user,(Channel*)dest,text); - - return MOD_RES_PASSTHRU; - } - - ModResult OnUserPreNotice(User *user, void *dest, int target_type, std::string &text, char status, CUList &exempt_list) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { if (target_type == TYPE_CHANNEL) return ProcessMessages(user,(Channel*)dest,text); @@ -192,10 +178,9 @@ class ModuleMsgFlood : public Module { // we want to be after all modules that might deny the message (e.g. m_muteban, m_noctcp, m_blockcolor, etc.) ServerInstance->Modules->SetPriority(this, I_OnUserPreMessage, PRIORITY_LAST); - ServerInstance->Modules->SetPriority(this, I_OnUserPreNotice, PRIORITY_LAST); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +f (message flood protection)", VF_VENDOR); } diff --git a/src/modules/m_mlock.cpp b/src/modules/m_mlock.cpp index 719701d02..abcd79667 100644 --- a/src/modules/m_mlock.cpp +++ b/src/modules/m_mlock.cpp @@ -17,25 +17,21 @@ */ -/* $ModDesc: Implements the ability to have server-side MLOCK enforcement. */ - #include "inspircd.h" class ModuleMLock : public Module { -private: StringExtItem mlock; public: ModuleMLock() : mlock("mlock", this) {}; - void init() + void init() CXX11_OVERRIDE { - ServerInstance->Modules->Attach(I_OnPreMode, this); ServerInstance->Modules->AddService(this->mlock); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Implements the ability to have server-side MLOCK enforcement.", VF_VENDOR); } @@ -45,7 +41,7 @@ public: ServerInstance->Modules->SetPriority(this, I_OnPreMode, PRIORITY_FIRST); } - ModResult OnPreMode(User* source, User* dest, Channel* channel, const std::vector<std::string>& parameters) + ModResult OnPreMode(User* source, User* dest, Channel* channel, const std::vector<std::string>& parameters) CXX11_OVERRIDE { if (!channel) return MOD_RES_PASSTHRU; @@ -67,7 +63,6 @@ public: return MOD_RES_PASSTHRU; } - }; MODULE_INIT(ModuleMLock) diff --git a/src/modules/m_muteban.cpp b/src/modules/m_muteban.cpp index 767af2901..06ede1f54 100644 --- a/src/modules/m_muteban.cpp +++ b/src/modules/m_muteban.cpp @@ -20,28 +20,15 @@ #include "inspircd.h" -/* $ModDesc: Implements extban +b m: - mute bans */ - class ModuleQuietBan : public Module { - private: public: - void init() - { - Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - virtual ~ModuleQuietBan() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Implements extban +b m: - mute bans",VF_OPTCOMMON|VF_VENDOR); } - virtual ModResult OnUserPreMessage(User *user, void *dest, int target_type, std::string &text, char status, CUList &exempt_list) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { if (!IS_LOCAL(user) || target_type != TYPE_CHANNEL) return MOD_RES_PASSTHRU; @@ -56,17 +43,10 @@ class ModuleQuietBan : public Module return MOD_RES_PASSTHRU; } - virtual ModResult OnUserPreNotice(User *user, void *dest, int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreMessage(user, dest, target_type, text, status, exempt_list); - } - - virtual void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - ServerInstance->AddExtBanChar('m'); + tokens["EXTBAN"].push_back('m'); } }; - MODULE_INIT(ModuleQuietBan) - diff --git a/src/modules/m_namedmodes.cpp b/src/modules/m_namedmodes.cpp index 4db1f70b9..8647cebb4 100644 --- a/src/modules/m_namedmodes.cpp +++ b/src/modules/m_namedmodes.cpp @@ -17,8 +17,6 @@ */ -/* $ModDesc: Provides the ability to manipulate modes via long names. */ - #include "inspircd.h" static void DisplayList(User* user, Channel* channel) @@ -29,15 +27,14 @@ static void DisplayList(User* user, Channel* channel) ModeHandler* mh = ServerInstance->Modes->FindMode(letter, MODETYPE_CHANNEL); if (!mh || mh->IsListMode()) continue; - if (!channel->IsModeSet(letter)) + if (!channel->IsModeSet(mh)) continue; items << " +" << mh->name; if (mh->GetNumParams(true)) - items << " " << channel->GetModeParameter(letter); + items << " " << channel->GetModeParameter(mh); } - char pfx[MAXBUF]; - snprintf(pfx, MAXBUF, ":%s 961 %s %s", ServerInstance->Config->ServerName.c_str(), user->nick.c_str(), channel->name.c_str()); - user->SendText(std::string(pfx), items); + const std::string line = ":" + ServerInstance->Config->ServerName + " 961 " + user->nick + " " + channel->name; + user->SendText(line, items); user->WriteNumeric(960, "%s %s :End of mode list", user->nick.c_str(), channel->name.c_str()); } @@ -83,7 +80,7 @@ class CommandProp : public Command } } } - ServerInstance->SendGlobalMode(modes, src); + ServerInstance->Modes->Process(modes, src); return CMD_SUCCESS; } }; @@ -106,16 +103,13 @@ class ModuleNamedModes : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); ServerInstance->Modules->AddService(dummyZ); - - Implementation eventlist[] = { I_OnPreMode }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides the ability to manipulate modes via long names.",VF_VENDOR); } @@ -125,7 +119,7 @@ class ModuleNamedModes : public Module ServerInstance->Modules->SetPriority(this, I_OnPreMode, PRIORITY_FIRST); } - ModResult OnPreMode(User* source, User* dest, Channel* channel, const std::vector<std::string>& parameters) + ModResult OnPreMode(User* source, User* dest, Channel* channel, const std::vector<std::string>& parameters) CXX11_OVERRIDE { if (!channel) return MOD_RES_PASSTHRU; @@ -197,7 +191,7 @@ class ModuleNamedModes : public Module } } newparms[1] = modelist; - ServerInstance->Modes->Process(newparms, source, false); + ServerInstance->Modes->Process(newparms, source); return MOD_RES_DENY; } }; diff --git a/src/modules/m_namesx.cpp b/src/modules/m_namesx.cpp index 82d311773..afbf7a8e2 100644 --- a/src/modules/m_namesx.cpp +++ b/src/modules/m_namesx.cpp @@ -21,40 +21,27 @@ #include "inspircd.h" -#include "m_cap.h" - -/* $ModDesc: Provides the NAMESX (CAP multi-prefix) capability. */ +#include "modules/cap.h" class ModuleNamesX : public Module { - public: GenericCap cap; + public: ModuleNamesX() : cap(this, "multi-prefix") { } - void init() - { - Implementation eventlist[] = { I_OnPreCommand, I_OnNamesListItem, I_On005Numeric, I_OnEvent, I_OnSendWhoLine }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - - ~ModuleNamesX() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides the NAMESX (CAP multi-prefix) capability.",VF_VENDOR); } - void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - output.append(" NAMESX"); + tokens["NAMESX"]; } - ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) + ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE { /* We don't actually create a proper command handler class for PROTOCTL, * because other modules might want to have PROTOCTL hooks too. @@ -72,7 +59,7 @@ class ModuleNamesX : public Module return MOD_RES_PASSTHRU; } - void OnNamesListItem(User* issuer, Membership* memb, std::string &prefixes, std::string &nick) + void OnNamesListItem(User* issuer, Membership* memb, std::string &prefixes, std::string &nick) CXX11_OVERRIDE { if (!cap.ext.get(issuer)) return; @@ -84,7 +71,7 @@ class ModuleNamesX : public Module prefixes = memb->chan->GetAllPrefixChars(memb->user); } - void OnSendWhoLine(User* source, const std::vector<std::string>& params, User* user, std::string& line) + void OnSendWhoLine(User* source, const std::vector<std::string>& params, User* user, std::string& line) CXX11_OVERRIDE { if (!cap.ext.get(source)) return; @@ -122,7 +109,7 @@ class ModuleNamesX : public Module line.insert(pos, prefixes); } - void OnEvent(Event& ev) + void OnEvent(Event& ev) CXX11_OVERRIDE { cap.HandleEvent(ev); } diff --git a/src/modules/m_nationalchars.cpp b/src/modules/m_nationalchars.cpp index b43b6e2b6..99e525398 100644 --- a/src/modules/m_nationalchars.cpp +++ b/src/modules/m_nationalchars.cpp @@ -29,14 +29,12 @@ #include "caller.h" #include <fstream> -/* $ModDesc: Provides an ability to have non-RFC1459 nicks & support for national CASEMAPPING */ - -class lwbNickHandler : public HandlerBase2<bool, const char*, size_t> +class lwbNickHandler : public HandlerBase1<bool, const std::string&> { public: lwbNickHandler() { } - virtual ~lwbNickHandler() { } - virtual bool Call(const char*, size_t); + ~lwbNickHandler() { } + bool Call(const std::string&); }; /*,m_reverse_additionalUp[256];*/ @@ -71,11 +69,12 @@ char utf8size(unsigned char * mb) /* Conditions added */ -bool lwbNickHandler::Call(const char* n, size_t max) +bool lwbNickHandler::Call(const std::string& nick) { - if (!n || !*n) + if (nick.empty()) return false; + const char* n = nick.c_str(); unsigned int p = 0; for (const char* i = n; *i; i++, p++) { @@ -215,17 +214,16 @@ bool lwbNickHandler::Call(const char* n, size_t max) } /* too long? or not -- pointer arithmetic rocks */ - return (p < max); + return (p < ServerInstance->Config->Limits.NickMax); } class ModuleNationalChars : public Module { - private: lwbNickHandler myhandler; std::string charset, casemapping; unsigned char m_additional[256], m_additionalUp[256], m_lower[256], m_upper[256]; - caller2<bool, const char*, size_t> rememberer; + caller1<bool, const std::string&> rememberer; bool forcequit; const unsigned char * lowermap_rememberer; @@ -235,26 +233,22 @@ class ModuleNationalChars : public Module { } - void init() + void init() CXX11_OVERRIDE { memcpy(m_lower, rfc_case_insensitive_map, 256); national_case_insensitive_map = m_lower; ServerInstance->IsNick = &myhandler; - Implementation eventlist[] = { I_OnRehash, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); } - virtual void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - std::string tmp(casemapping); - tmp.insert(0, "CASEMAPPING="); - SearchAndReplace(output, std::string("CASEMAPPING=rfc1459"), tmp); + tokens["CASEMAPPING"] = casemapping; } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("nationalchars"); charset = tag->getString("file"); @@ -276,19 +270,19 @@ class ModuleNationalChars : public Module { /* Fix by Brain: Dont quit UID users */ User* n = *iter; - if (!isdigit(n->nick[0]) && !ServerInstance->IsNick(n->nick.c_str(), ServerInstance->Config->Limits.NickMax)) + if (!isdigit(n->nick[0]) && !ServerInstance->IsNick(n->nick)) ServerInstance->Users->QuitUser(n, message); } } - virtual ~ModuleNationalChars() + ~ModuleNationalChars() { ServerInstance->IsNick = rememberer; national_case_insensitive_map = lowermap_rememberer; CheckForceQuit("National characters module unloaded"); } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides an ability to have non-RFC1459 nicks & support for national CASEMAPPING", VF_VENDOR | VF_COMMON, charset); } @@ -304,10 +298,10 @@ class ModuleNationalChars : public Module /*so Bynets Unreal distribution stuff*/ void loadtables(std::string filename, unsigned char ** tables, unsigned char cnt, char faillimit) { - std::ifstream ifs(filename.c_str()); + std::ifstream ifs(ServerInstance->Config->Paths.PrependConfig(filename).c_str()); if (ifs.fail()) { - ServerInstance->Logs->Log("m_nationalchars",DEFAULT,"loadtables() called for missing file: %s", filename.c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "loadtables() called for missing file: %s", filename.c_str()); return; } @@ -322,7 +316,7 @@ class ModuleNationalChars : public Module { if (loadtable(ifs, tables[n], 255) && (n < faillimit)) { - ServerInstance->Logs->Log("m_nationalchars",DEFAULT,"loadtables() called for illegal file: %s (line %d)", filename.c_str(), n+1); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "loadtables() called for illegal file: %s (line %d)", filename.c_str(), n+1); return; } } diff --git a/src/modules/m_nickflood.cpp b/src/modules/m_nickflood.cpp index 04d7c8b5e..66e7ca520 100644 --- a/src/modules/m_nickflood.cpp +++ b/src/modules/m_nickflood.cpp @@ -20,8 +20,6 @@ #include "inspircd.h" -/* $ModDesc: Provides channel mode +F (nick flood protection) */ - /** Holds settings and state associated with channel mode +F */ class nickfloodsettings @@ -115,16 +113,14 @@ class NickFlood : public ModeHandler ext.set(channel, new nickfloodsettings(nsecs, nnicks)); parameter = ConvToStr(nnicks) + ":" + ConvToStr(nsecs); - channel->SetModeParam('F', parameter); return MODEACTION_ALLOW; } else { - if (!channel->IsModeSet('F')) + if (!channel->IsModeSet(this)) return MODEACTION_DENY; ext.unset(channel); - channel->SetModeParam('F', ""); return MODEACTION_ALLOW; } } @@ -135,25 +131,19 @@ class ModuleNickFlood : public Module NickFlood nf; public: - ModuleNickFlood() : nf(this) { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(nf); ServerInstance->Modules->AddService(nf.ext); - Implementation eventlist[] = { I_OnUserPreNick, I_OnUserPostNick }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - ModResult OnUserPreNick(User* user, const std::string &newnick) + ModResult OnUserPreNick(User* user, const std::string &newnick) CXX11_OVERRIDE { - if (ServerInstance->NICKForced.get(user)) /* Allow forced nick changes */ - return MOD_RES_PASSTHRU; - for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++) { Channel *channel = *i; @@ -188,7 +178,7 @@ class ModuleNickFlood : public Module /* * XXX: HACK: We do the increment on the *POST* event here (instead of all together) because we have no way of knowing whether other modules would block a nickchange. */ - void OnUserPostNick(User* user, const std::string &oldnick) + void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE { if (isdigit(user->nick[0])) /* allow switches to UID */ return; @@ -214,11 +204,7 @@ class ModuleNickFlood : public Module } } - ~ModuleNickFlood() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Channel mode F - nick flood protection", VF_VENDOR); } diff --git a/src/modules/m_nicklock.cpp b/src/modules/m_nicklock.cpp index 4f5e5941c..6c4101bc5 100644 --- a/src/modules/m_nicklock.cpp +++ b/src/modules/m_nicklock.cpp @@ -22,8 +22,6 @@ #include "inspircd.h" -/* $ModDesc: Provides the NICKLOCK command, allows an oper to change a users nick and lock them to it until they quit */ - /** Handle /NICKLOCK */ class CommandNicklock : public Command @@ -35,7 +33,7 @@ class CommandNicklock : public Command { flags_needed = 'o'; syntax = "<oldnick> <newnick>"; - TRANSLATE3(TR_NICK, TR_TEXT, TR_END); + TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle(const std::vector<std::string>& parameters, User *user) @@ -44,16 +42,16 @@ class CommandNicklock : public Command if ((!target) || (target->registered != REG_ALL)) { - user->WriteServ("NOTICE %s :*** No such nickname: '%s'", user->nick.c_str(), parameters[0].c_str()); + user->WriteNotice("*** No such nickname: '" + parameters[0] + "'"); return CMD_FAILURE; } /* Do local sanity checks and bails */ if (IS_LOCAL(user)) { - if (!ServerInstance->IsNick(parameters[1].c_str(), ServerInstance->Config->Limits.NickMax)) + if (!ServerInstance->IsNick(parameters[1])) { - user->WriteServ("NOTICE %s :*** Invalid nickname '%s'", user->nick.c_str(), parameters[1].c_str()); + user->WriteNotice("*** Invalid nickname '" + parameters[1] + "'"); return CMD_FAILURE; } @@ -66,7 +64,7 @@ class CommandNicklock : public Command locked.set(target, 1); std::string oldnick = target->nick; - if (target->ForceNickChange(parameters[1].c_str())) + if (target->ForceNickChange(parameters[1])) ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used NICKLOCK to change and hold "+oldnick+" to "+parameters[1]); else { @@ -98,7 +96,7 @@ class CommandNickunlock : public Command { flags_needed = 'o'; syntax = "<locked-nick>"; - TRANSLATE2(TR_NICK, TR_END); + TRANSLATE1(TR_NICK); } CmdResult Handle (const std::vector<std::string>& parameters, User *user) @@ -107,7 +105,7 @@ class CommandNickunlock : public Command if (!target) { - user->WriteServ("NOTICE %s :*** No such nickname: '%s'", user->nick.c_str(), parameters[0].c_str()); + user->WriteNotice("*** No such nickname: '" + parameters[0] + "'"); return CMD_FAILURE; } @@ -139,7 +137,6 @@ class CommandNickunlock : public Command } }; - class ModuleNickLock : public Module { LocalIntExt locked; @@ -151,31 +148,23 @@ class ModuleNickLock : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd1); ServerInstance->Modules->AddService(cmd2); ServerInstance->Modules->AddService(locked); - ServerInstance->Modules->Attach(I_OnUserPreNick, this); } - ~ModuleNickLock() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides the NICKLOCK command, allows an oper to change a users nick and lock them to it until they quit", VF_OPTCOMMON | VF_VENDOR); } - ModResult OnUserPreNick(User* user, const std::string &newnick) + ModResult OnUserPreNick(User* user, const std::string &newnick) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; - if (ServerInstance->NICKForced.get(user)) /* Allow forced nick changes */ - return MOD_RES_PASSTHRU; - if (locked.get(user)) { user->WriteNumeric(447, "%s :You cannot change your nickname (your nick is locked)",user->nick.c_str()); diff --git a/src/modules/m_noctcp.cpp b/src/modules/m_noctcp.cpp index 1dd6fe34a..d791dca36 100644 --- a/src/modules/m_noctcp.cpp +++ b/src/modules/m_noctcp.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides channel mode +C to block CTCPs */ - class NoCTCP : public SimpleChannelModeHandler { public: @@ -31,38 +29,25 @@ class NoCTCP : public SimpleChannelModeHandler class ModuleNoCTCP : public Module { - NoCTCP nc; public: - ModuleNoCTCP() : nc(this) { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(nc); - Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual ~ModuleNoCTCP() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +C to block CTCPs", VF_VENDOR); } - virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreNotice(user,dest,target_type,text,status,exempt_list); - } - - virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user))) { @@ -74,7 +59,7 @@ class ModuleNoCTCP : public Module if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; - if (!c->GetExtBanStatus(user, 'C').check(!c->IsModeSet('C'))) + if (!c->GetExtBanStatus(user, 'C').check(!c->IsModeSet(nc))) { user->WriteNumeric(ERR_NOCTCPALLOWED, "%s %s :Can't send CTCP to channel (+C set)",user->nick.c_str(), c->name.c_str()); return MOD_RES_DENY; @@ -83,9 +68,9 @@ class ModuleNoCTCP : public Module return MOD_RES_PASSTHRU; } - virtual void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - ServerInstance->AddExtBanChar('C'); + tokens["EXTBAN"].push_back('C'); } }; diff --git a/src/modules/m_nokicks.cpp b/src/modules/m_nokicks.cpp index 1f58a2e08..5e58f002c 100644 --- a/src/modules/m_nokicks.cpp +++ b/src/modules/m_nokicks.cpp @@ -22,8 +22,6 @@ #include "inspircd.h" -/* $ModDesc: Provides channel mode +Q to prevent kicks on the channel. */ - class NoKicks : public SimpleChannelModeHandler { public: @@ -40,21 +38,19 @@ class ModuleNoKicks : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(nk); - Implementation eventlist[] = { I_OnUserPreKick, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - ServerInstance->AddExtBanChar('Q'); + tokens["EXTBAN"].push_back('Q'); } - ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason) + ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason) CXX11_OVERRIDE { - if (!memb->chan->GetExtBanStatus(source, 'Q').check(!memb->chan->IsModeSet('Q'))) + if (!memb->chan->GetExtBanStatus(source, 'Q').check(!memb->chan->IsModeSet(nk))) { // Can't kick with Q in place, not even opers with override, and founders source->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Can't kick user %s from channel (+Q set)",source->nick.c_str(), memb->chan->name.c_str(), memb->user->nick.c_str()); @@ -63,15 +59,10 @@ class ModuleNoKicks : public Module return MOD_RES_PASSTHRU; } - ~ModuleNoKicks() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +Q to prevent kicks on the channel.", VF_VENDOR); } }; - MODULE_INIT(ModuleNoKicks) diff --git a/src/modules/m_nonicks.cpp b/src/modules/m_nonicks.cpp index 672a48f8d..4078e54a4 100644 --- a/src/modules/m_nonicks.cpp +++ b/src/modules/m_nonicks.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for channel mode +N & extban +b N: which prevents nick changes on channel */ - class NoNicks : public SimpleChannelModeHandler { public: @@ -38,38 +36,27 @@ class ModuleNoNickChange : public Module { } - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); ServerInstance->Modules->AddService(nn); - Implementation eventlist[] = { I_OnUserPreNick, I_On005Numeric, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - virtual ~ModuleNoNickChange() - { } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for channel mode +N & extban +b N: which prevents nick changes on channel", VF_VENDOR); } - - virtual void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - ServerInstance->AddExtBanChar('N'); + tokens["EXTBAN"].push_back('N'); } - virtual ModResult OnUserPreNick(User* user, const std::string &newnick) + ModResult OnUserPreNick(User* user, const std::string &newnick) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; - // Allow forced nick changes. - if (ServerInstance->NICKForced.get(user)) - return MOD_RES_PASSTHRU; - for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++) { Channel* curr = *i; @@ -79,10 +66,10 @@ class ModuleNoNickChange : public Module if (res == MOD_RES_ALLOW) continue; - if (override && IS_OPER(user)) + if (override && user->IsOper()) continue; - if (!curr->GetExtBanStatus(user, 'N').check(!curr->IsModeSet('N'))) + if (!curr->GetExtBanStatus(user, 'N').check(!curr->IsModeSet(nn))) { user->WriteNumeric(ERR_CANTCHANGENICK, "%s :Can't change nickname while on %s (+N is set)", user->nick.c_str(), curr->name.c_str()); @@ -93,7 +80,7 @@ class ModuleNoNickChange : public Module return MOD_RES_PASSTHRU; } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { override = ServerInstance->Config->ConfValue("nonicks")->getBool("operoverride", false); } diff --git a/src/modules/m_nonotice.cpp b/src/modules/m_nonotice.cpp index c5b9f3a1c..cf8da5f55 100644 --- a/src/modules/m_nonotice.cpp +++ b/src/modules/m_nonotice.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides channel mode +T to block notices to the channel */ - class NoNotice : public SimpleChannelModeHandler { public: @@ -39,25 +37,23 @@ class ModuleNoNotice : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(nt); - Implementation eventlist[] = { I_OnUserPreNotice, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - ServerInstance->AddExtBanChar('T'); + tokens["EXTBAN"].push_back('T'); } - virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { ModResult res; - if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user))) + if ((msgtype == MSG_NOTICE) && (target_type == TYPE_CHANNEL) && (IS_LOCAL(user))) { Channel* c = (Channel*)dest; - if (!c->GetExtBanStatus(user, 'T').check(!c->IsModeSet('T'))) + if (!c->GetExtBanStatus(user, 'T').check(!c->IsModeSet(nt))) { res = ServerInstance->OnCheckExemption(user,c,"nonotice"); if (res == MOD_RES_ALLOW) @@ -72,11 +68,7 @@ class ModuleNoNotice : public Module return MOD_RES_PASSTHRU; } - virtual ~ModuleNoNotice() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +T to block notices to the channel", VF_VENDOR); } diff --git a/src/modules/m_nopartmsg.cpp b/src/modules/m_nopartmsg.cpp index ad3413101..7aeb66920 100644 --- a/src/modules/m_nopartmsg.cpp +++ b/src/modules/m_nopartmsg.cpp @@ -19,45 +19,27 @@ #include "inspircd.h" -/* $ModDesc: Implements extban +b p: - part message bans */ - class ModulePartMsgBan : public Module { - private: public: - void init() - { - Implementation eventlist[] = { I_OnUserPart, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - virtual ~ModulePartMsgBan() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Implements extban +b p: - part message bans", VF_OPTCOMMON|VF_VENDOR); } - - virtual void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts) + void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts) CXX11_OVERRIDE { if (!IS_LOCAL(memb->user)) return; if (memb->chan->GetExtBanStatus(memb->user, 'p') == MOD_RES_DENY) partmessage.clear(); - - return; } - virtual void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - ServerInstance->AddExtBanChar('p'); + tokens["EXTBAN"].push_back('p'); } }; - MODULE_INIT(ModulePartMsgBan) - diff --git a/src/modules/m_ojoin.cpp b/src/modules/m_ojoin.cpp index 8f8d3ca90..b0c206ab3 100644 --- a/src/modules/m_ojoin.cpp +++ b/src/modules/m_ojoin.cpp @@ -1,6 +1,7 @@ /* * InspIRCd -- Internet Relay Chat Daemon * + * Copyright (C) 2009 Taros <taros34@hotmail.com> * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can @@ -16,57 +17,38 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -/* - * Written for InspIRCd-1.2 by Taros on the Tel'Laerad M&D Team - * <http://tellaerad.net> - */ - #include "inspircd.h" -/* $ModConfig: <ojoin prefix="!" notice="yes" op="yes"> - * Specify the prefix that +Y will grant here, it should be unused. - * Leave prefix empty if you do not wish +Y to grant a prefix - * If notice is set to on, upon ojoin, the server will notice - * the channel saying that the oper is joining on network business - * If op is set to on, it will give them +o along with +Y */ -/* $ModDesc: Provides the /ojoin command, which joins a user to a channel on network business, and gives them +Y, which makes them immune to kick / deop and so on. */ -/* $ModAuthor: Taros */ -/* $ModAuthorMail: taros34@hotmail.com */ - -/* A note: This will not protect against kicks from services, - * ulines, or operoverride. */ - #define NETWORK_VALUE 9000000 -char NPrefix; -bool notice; -bool op; - /** Handle /OJOIN */ -class CommandOjoin : public Command +class CommandOjoin : public SplitCommand { public: bool active; - CommandOjoin(Module* parent) : Command(parent,"OJOIN", 1) + bool notice; + bool op; + ModeHandler* npmh; + CommandOjoin(Module* parent) : + SplitCommand(parent, "OJOIN", 1) { flags_needed = 'o'; Penalty = 0; syntax = "<channel>"; active = false; - TRANSLATE3(TR_NICK, TR_TEXT, TR_END); } - CmdResult Handle (const std::vector<std::string>& parameters, User *user) + CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user) { // Make sure the channel name is allowable. - if (!ServerInstance->IsChannel(parameters[0].c_str(), ServerInstance->Config->Limits.ChanMax)) + if (!ServerInstance->IsChannel(parameters[0])) { - user->WriteServ("NOTICE "+user->nick+" :*** Invalid characters in channel name or name too long"); + user->WriteNotice("*** Invalid characters in channel name or name too long"); return CMD_FAILURE; } active = true; - Channel* channel = Channel::JoinUser(user, parameters[0].c_str(), false, "", false); + // override is false because we want OnUserPreJoin to run + Channel* channel = Channel::JoinUser(user, parameters[0], false); active = false; if (channel) @@ -87,11 +69,14 @@ class CommandOjoin : public Command // they're already in the channel std::vector<std::string> modes; modes.push_back(parameters[0]); - modes.push_back(op ? "+Yo" : "+Y"); - modes.push_back(user->nick); + modes.push_back(std::string("+") + npmh->GetModeChar()); if (op) + { + modes[1].push_back('o'); modes.push_back(user->nick); - ServerInstance->SendGlobalMode(modes, ServerInstance->FakeClient); + } + modes.push_back(user->nick); + ServerInstance->Modes->Process(modes, ServerInstance->FakeClient); } return CMD_SUCCESS; } @@ -102,51 +87,14 @@ class CommandOjoin : public Command class NetworkPrefix : public ModeHandler { public: - NetworkPrefix(Module* parent) : ModeHandler(parent, "official-join", 'Y', PARAM_ALWAYS, MODETYPE_CHANNEL) + NetworkPrefix(Module* parent, char NPrefix) + : ModeHandler(parent, "official-join", 'Y', PARAM_ALWAYS, MODETYPE_CHANNEL) { list = true; prefix = NPrefix; levelrequired = INT_MAX; m_paramtype = TR_NICK; - } - - void RemoveMode(Channel* channel, irc::modestacker* stack) - { - const UserMembList* cl = channel->GetUsers(); - std::vector<std::string> mode_junk; - mode_junk.push_back(channel->name); - irc::modestacker modestack(false); - std::deque<std::string> stackresult; - - for (UserMembCIter i = cl->begin(); i != cl->end(); i++) - { - if (i->second->hasMode('Y')) - { - if (stack) - stack->Push(this->GetModeChar(), i->first->nick); - else - modestack.Push(this->GetModeChar(), i->first->nick); - } - } - - if (stack) - return; - - while (modestack.GetStackedLine(stackresult)) - { - mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end()); - ServerInstance->SendMode(mode_junk, ServerInstance->FakeClient); - mode_junk.erase(mode_junk.begin() + 1, mode_junk.end()); - } - } - - unsigned int GetPrefixRank() - { - return NETWORK_VALUE; - } - - void RemoveMode(User* user, irc::modestacker* stack) - { + prefixrank = NETWORK_VALUE; } ModResult AccessCheck(User* source, Channel* channel, std::string ¶meter, bool adding) @@ -178,27 +126,30 @@ class ModuleOjoin : public Module { } - void init() + void init() CXX11_OVERRIDE { /* Load config stuff */ OnRehash(NULL); + std::string npre = ServerInstance->Config->ConfValue("ojoin")->getString("prefix"); + char NPrefix = npre.empty() ? 0 : npre[0]; + if (NPrefix && ServerInstance->Modes->FindPrefix(NPrefix)) + throw ModuleException("Looks like the prefix you picked for m_ojoin is already in use. Pick another."); + /* Initialise module variables */ - np = new NetworkPrefix(this); + np = new NetworkPrefix(this, NPrefix); + mycommand.npmh = np; ServerInstance->Modules->AddService(*np); ServerInstance->Modules->AddService(mycommand); - - Implementation eventlist[] = { I_OnUserPreJoin, I_OnUserPreKick, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - ModResult OnUserPreJoin(User *user, Channel *chan, const char *cname, std::string &privs, const std::string &keygiven) + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { if (mycommand.active) { - privs += 'Y'; - if (op) + privs += np->GetModeChar(); + if (mycommand.op) privs += 'o'; return MOD_RES_ALLOW; } @@ -206,28 +157,17 @@ class ModuleOjoin : public Module return MOD_RES_PASSTHRU; } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* Conf = ServerInstance->Config->ConfValue("ojoin"); - - if (!np) - { - // This is done on module load only - std::string npre = Conf->getString("prefix"); - NPrefix = npre.empty() ? 0 : npre[0]; - - if (NPrefix && ServerInstance->Modes->FindPrefix(NPrefix)) - throw ModuleException("Looks like the +Y prefix you picked for m_ojoin is already in use. Pick another."); - } - - notice = Conf->getBool("notice", true); - op = Conf->getBool("op", true); + mycommand.notice = Conf->getBool("notice", true); + mycommand.op = Conf->getBool("op", true); } - ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason) + ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason) CXX11_OVERRIDE { // Don't do anything if they're not +Y - if (!memb->hasMode('Y')) + if (!memb->hasMode(np->GetModeChar())) return MOD_RES_PASSTHRU; // Let them do whatever they want to themselves. @@ -248,11 +188,10 @@ class ModuleOjoin : public Module ServerInstance->Modules->SetPriority(this, I_OnUserPreJoin, PRIORITY_FIRST); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Network Business Join", VF_VENDOR); } }; MODULE_INIT(ModuleOjoin) - diff --git a/src/modules/m_operchans.cpp b/src/modules/m_operchans.cpp index ca948d95b..73ef130b9 100644 --- a/src/modules/m_operchans.cpp +++ b/src/modules/m_operchans.cpp @@ -22,8 +22,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for oper-only chans via the +O channel mode */ - class OperChans : public SimpleChannelModeHandler { public: @@ -42,16 +40,14 @@ class ModuleOperChans : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(oc); - Implementation eventlist[] = { I_OnCheckBan, I_On005Numeric, I_OnUserPreJoin }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven) + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { - if (chan && chan->IsModeSet('O') && !IS_OPER(user)) + if (chan && chan->IsModeSet(oc) && !user->IsOper()) { user->WriteNumeric(ERR_CANTJOINOPERSONLY, "%s %s :Only IRC operators may join %s (+O is set)", user->nick.c_str(), chan->name.c_str(), chan->name.c_str()); @@ -60,26 +56,22 @@ class ModuleOperChans : public Module return MOD_RES_PASSTHRU; } - ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) + ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) CXX11_OVERRIDE { if ((mask.length() > 2) && (mask[0] == 'O') && (mask[1] == ':')) { - if (IS_OPER(user) && InspIRCd::Match(user->oper->name, mask.substr(2))) + if (user->IsOper() && InspIRCd::Match(user->oper->name, mask.substr(2))) return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } - void On005Numeric(std::string &output) - { - ServerInstance->AddExtBanChar('O'); - } - - ~ModuleOperChans() + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { + tokens["EXTBAN"].push_back('O'); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for oper-only chans via the +O channel mode and 'O' extban", VF_VENDOR); } diff --git a/src/modules/m_operjoin.cpp b/src/modules/m_operjoin.cpp index bd77384a6..80bb73ad4 100644 --- a/src/modules/m_operjoin.cpp +++ b/src/modules/m_operjoin.cpp @@ -24,11 +24,8 @@ #include "inspircd.h" -/* $ModDesc: Forces opers to join the specified channel(s) on oper-up */ - class ModuleOperjoin : public Module { - private: std::string operChan; std::vector<std::string> operChans; bool override; @@ -53,15 +50,13 @@ class ModuleOperjoin : public Module } public: - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); - Implementation eventlist[] = { I_OnPostOper, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("operjoin"); @@ -72,34 +67,31 @@ class ModuleOperjoin : public Module tokenize(operChan,operChans); } - virtual ~ModuleOperjoin() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Forces opers to join the specified channel(s) on oper-up", VF_VENDOR); } - virtual void OnPostOper(User* user, const std::string &opertype, const std::string &opername) + void OnPostOper(User* user, const std::string &opertype, const std::string &opername) CXX11_OVERRIDE { - if (!IS_LOCAL(user)) + LocalUser* localuser = IS_LOCAL(user); + if (!localuser) return; - for(std::vector<std::string>::iterator it = operChans.begin(); it != operChans.end(); it++) - if (ServerInstance->IsChannel(it->c_str(), ServerInstance->Config->Limits.ChanMax)) - Channel::JoinUser(user, it->c_str(), override, "", false, ServerInstance->Time()); + for (std::vector<std::string>::const_iterator i = operChans.begin(); i != operChans.end(); ++i) + if (ServerInstance->IsChannel(*i)) + Channel::JoinUser(localuser, *i, override); - std::string chanList = IS_OPER(user)->getConfig("autojoin"); + std::string chanList = localuser->oper->getConfig("autojoin"); if (!chanList.empty()) { std::vector<std::string> typechans; tokenize(chanList, typechans); for (std::vector<std::string>::const_iterator it = typechans.begin(); it != typechans.end(); ++it) { - if (ServerInstance->IsChannel(it->c_str(), ServerInstance->Config->Limits.ChanMax)) + if (ServerInstance->IsChannel(*it)) { - Channel::JoinUser(user, it->c_str(), override, "", false, ServerInstance->Time()); + Channel::JoinUser(localuser, *it, override); } } } diff --git a/src/modules/m_operlevels.cpp b/src/modules/m_operlevels.cpp index 569defd49..cacedd62d 100644 --- a/src/modules/m_operlevels.cpp +++ b/src/modules/m_operlevels.cpp @@ -20,27 +20,20 @@ */ -/* $ModDesc: Gives each oper type a 'level', cannot kill opers 'above' your level. */ - #include "inspircd.h" class ModuleOperLevels : public Module { public: - void init() - { - ServerInstance->Modules->Attach(I_OnKill, this); - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Gives each oper type a 'level', cannot kill opers 'above' your level.", VF_VENDOR); } - virtual ModResult OnKill(User* source, User* dest, const std::string &reason) + ModResult OnKill(User* source, User* dest, const std::string &reason) CXX11_OVERRIDE { // oper killing an oper? - if (IS_OPER(dest) && IS_OPER(source)) + if (dest->IsOper() && source->IsOper()) { std::string level = dest->oper->getConfig("level"); long dest_level = atol(level.c_str()); @@ -50,7 +43,7 @@ class ModuleOperLevels : public Module if (dest_level > source_level) { if (IS_LOCAL(source)) ServerInstance->SNO->WriteGlobalSno('a', "Oper %s (level %ld) attempted to /kill a higher oper: %s (level %ld): Reason: %s",source->nick.c_str(),source_level,dest->nick.c_str(),dest_level,reason.c_str()); - dest->WriteServ("NOTICE %s :*** Oper %s attempted to /kill you!",dest->nick.c_str(),source->nick.c_str()); + dest->WriteNotice("*** Oper " + source->nick + " attempted to /kill you!"); source->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper %s is a higher level than you",source->nick.c_str(),dest->nick.c_str()); return MOD_RES_DENY; } @@ -60,4 +53,3 @@ class ModuleOperLevels : public Module }; MODULE_INIT(ModuleOperLevels) - diff --git a/src/modules/m_operlog.cpp b/src/modules/m_operlog.cpp index edb9109e8..42a0e4ecf 100644 --- a/src/modules/m_operlog.cpp +++ b/src/modules/m_operlog.cpp @@ -21,51 +21,41 @@ #include "inspircd.h" -/* $ModDesc: A module which logs all oper commands to the ircd log at default loglevel. */ - class ModuleOperLog : public Module { bool tosnomask; public: - void init() + void init() CXX11_OVERRIDE { - Implementation eventlist[] = { I_OnPreCommand, I_On005Numeric, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); ServerInstance->SNO->EnableSnomask('r', "OPERLOG"); OnRehash(NULL); } - virtual ~ModuleOperLog() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("A module which logs all oper commands to the ircd log at default loglevel.", VF_VENDOR); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { tosnomask = ServerInstance->Config->ConfValue("operlog")->getBool("tosnomask", false); } - virtual ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) + ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE { /* If the command doesnt appear to be valid, we dont want to mess with it. */ if (!validated) return MOD_RES_PASSTHRU; - if ((IS_OPER(user)) && (IS_LOCAL(user)) && (user->HasPermission(command))) + if ((user->IsOper()) && (IS_LOCAL(user)) && (user->HasPermission(command))) { Command* thiscommand = ServerInstance->Parser->GetHandler(command); if ((thiscommand) && (thiscommand->flags_needed == 'o')) { - std::string line; - if (!parameters.empty()) - line = irc::stringjoiner(" ", parameters, 0, parameters.size() - 1).GetJoined(); + std::string line = irc::stringjoiner(parameters).GetJoined(); std::string msg = "[" + user->GetFullRealHost() + "] " + command + " " + line; - ServerInstance->Logs->Log("m_operlog", DEFAULT, "OPERLOG: " + msg); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "OPERLOG: " + msg); if (tosnomask) ServerInstance->SNO->WriteGlobalSno('r', msg); } @@ -74,12 +64,11 @@ class ModuleOperLog : public Module return MOD_RES_PASSTHRU; } - virtual void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - output.append(" OPERLOG"); + tokens["OPERLOG"]; } }; - MODULE_INIT(ModuleOperLog) diff --git a/src/modules/m_opermodes.cpp b/src/modules/m_opermodes.cpp index 8b49f685e..7ab54cedf 100644 --- a/src/modules/m_opermodes.cpp +++ b/src/modules/m_opermodes.cpp @@ -22,26 +22,15 @@ #include "inspircd.h" -/* $ModDesc: Sets (and unsets) modes on opers when they oper up */ - class ModuleModesOnOper : public Module { public: - void init() - { - ServerInstance->Modules->Attach(I_OnPostOper, this); - } - - virtual ~ModuleModesOnOper() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Sets (and unsets) modes on opers when they oper up", VF_VENDOR); } - virtual void OnPostOper(User* user, const std::string &opertype, const std::string &opername) + void OnPostOper(User* user, const std::string &opertype, const std::string &opername) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return; @@ -71,7 +60,7 @@ class ModuleModesOnOper : public Module while (ss >> buf) modes.push_back(buf); - ServerInstance->SendMode(modes, u); + ServerInstance->Modes->Process(modes, u); } }; diff --git a/src/modules/m_opermotd.cpp b/src/modules/m_opermotd.cpp index 989f97689..1be81e641 100644 --- a/src/modules/m_opermotd.cpp +++ b/src/modules/m_opermotd.cpp @@ -22,8 +22,6 @@ #include "inspircd.h" -/* $ModDesc: Shows a message to opers after oper-up, adds /opermotd */ - /** Handle /OPERMOTD */ class CommandOpermotd : public Command @@ -82,34 +80,38 @@ class ModuleOpermotd : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); OnRehash(NULL); - Implementation eventlist[] = { I_OnRehash, I_OnOper }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Shows a message to opers after oper-up, adds /opermotd", VF_VENDOR | VF_OPTCOMMON); } - virtual void OnOper(User* user, const std::string &opertype) + void OnOper(User* user, const std::string &opertype) CXX11_OVERRIDE { if (onoper && IS_LOCAL(user)) cmd.ShowOperMOTD(user); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { cmd.opermotd.clear(); ConfigTag* conf = ServerInstance->Config->ConfValue("opermotd"); onoper = conf->getBool("onoper", true); - FileReader f(conf->getString("file", "opermotd")); - for (int i=0, filesize = f.FileSize(); i < filesize; i++) - cmd.opermotd.push_back(f.GetLine(i)); + try + { + FileReader reader(conf->getString("file", "opermotd")); + cmd.opermotd = reader.GetVector(); + } + catch (CoreException&) + { + // Nothing happens here as we do the error handling in ShowOperMOTD. + } if (conf->getBool("processcolors")) InspIRCd::ProcessColors(cmd.opermotd); diff --git a/src/modules/m_operprefix.cpp b/src/modules/m_operprefix.cpp index 25937cd6e..43346a4d0 100644 --- a/src/modules/m_operprefix.cpp +++ b/src/modules/m_operprefix.cpp @@ -22,8 +22,6 @@ * Originally by Chernov-Phoenix Alexey (Phoenix@RusNet) mailto:phoenix /email address separator/ pravmail.ru */ -/* $ModDesc: Gives opers cmode +y which provides a staff prefix. */ - #include "inspircd.h" #define OPERPREFIX_VALUE 1000000 @@ -38,11 +36,7 @@ class OperPrefixMode : public ModeHandler prefix = pfx.empty() ? '!' : pfx[0]; levelrequired = OPERPREFIX_VALUE; m_paramtype = TR_NICK; - } - - unsigned int GetPrefixRank() - { - return OPERPREFIX_VALUE; + prefixrank = OPERPREFIX_VALUE; } ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) @@ -64,48 +58,40 @@ class ModuleOperPrefixMode; class HideOperWatcher : public ModeWatcher { ModuleOperPrefixMode* parentmod; + public: - HideOperWatcher(ModuleOperPrefixMode* parent) : ModeWatcher((Module*) parent, 'H', MODETYPE_USER), parentmod(parent) {} - void AfterMode(User* source, User* dest, Channel* channel, const std::string ¶meter, bool adding, ModeType type); + HideOperWatcher(ModuleOperPrefixMode* parent); + void AfterMode(User* source, User* dest, Channel* channel, const std::string ¶meter, bool adding); }; class ModuleOperPrefixMode : public Module { - private: OperPrefixMode opm; - bool mw_added; HideOperWatcher hideoperwatcher; + UserModeReference hideopermode; + public: ModuleOperPrefixMode() - : opm(this), mw_added(false), hideoperwatcher(this) + : opm(this), hideoperwatcher(this) + , hideopermode(this, "hideoper") { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(opm); - Implementation eventlist[] = { I_OnUserPreJoin, I_OnPostOper, I_OnLoadModule, I_OnUnloadModule }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - /* To give clients a chance to learn about the new prefix we don't give +y to opers * right now. That means if the module was loaded after opers have joined channels * they need to rejoin them in order to get the oper prefix. */ - if (ServerInstance->Modules->Find("m_hideoper.so")) - mw_added = ServerInstance->Modes->AddModeWatcher(&hideoperwatcher); + ServerInstance->Modes->AddModeWatcher(&hideoperwatcher); } - ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string& privs, const std::string& keygiven) + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { - /* The user may have the +H umode on himself, but +H does not necessarily correspond - * to the +H of m_hideoper. - * However we only add the modewatcher when m_hideoper is loaded, so these - * conditions (mw_added and the user being +H) together mean the user is a hidden oper. - */ - - if (IS_OPER(user) && (!mw_added || !user->IsModeSet('H'))) + if ((user->IsOper()) && (!user->IsModeSet(hideopermode))) privs.push_back('y'); return MOD_RES_PASSTHRU; } @@ -114,40 +100,29 @@ class ModuleOperPrefixMode : public Module { std::vector<std::string> modechange; modechange.push_back(""); - modechange.push_back(add ? "+y" : "-y"); + modechange.push_back(add ? "+" : "-"); + modechange[1].push_back(opm.GetModeChar()); modechange.push_back(user->nick); for (UCListIter v = user->chans.begin(); v != user->chans.end(); v++) { modechange[0] = (*v)->name; - ServerInstance->SendGlobalMode(modechange, ServerInstance->FakeClient); + ServerInstance->Modes->Process(modechange, ServerInstance->FakeClient); } } - void OnPostOper(User* user, const std::string& opername, const std::string& opertype) + void OnPostOper(User* user, const std::string& opername, const std::string& opertype) CXX11_OVERRIDE { - if (IS_LOCAL(user) && (!mw_added || !user->IsModeSet('H'))) + if (IS_LOCAL(user) && (!user->IsModeSet(hideopermode))) SetOperPrefix(user, true); } - void OnLoadModule(Module* mod) - { - if ((!mw_added) && (mod->ModuleSourceFile == "m_hideoper.so")) - mw_added = ServerInstance->Modes->AddModeWatcher(&hideoperwatcher); - } - - void OnUnloadModule(Module* mod) - { - if ((mw_added) && (mod->ModuleSourceFile == "m_hideoper.so") && (ServerInstance->Modes->DelModeWatcher(&hideoperwatcher))) - mw_added = false; - } ~ModuleOperPrefixMode() { - if (mw_added) - ServerInstance->Modes->DelModeWatcher(&hideoperwatcher); + ServerInstance->Modes->DelModeWatcher(&hideoperwatcher); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Gives opers cmode +y which provides a staff prefix.", VF_VENDOR); } @@ -160,7 +135,13 @@ class ModuleOperPrefixMode : public Module } }; -void HideOperWatcher::AfterMode(User* source, User* dest, Channel* channel, const std::string& parameter, bool adding, ModeType type) +HideOperWatcher::HideOperWatcher(ModuleOperPrefixMode* parent) + : ModeWatcher(parent, "hideoper", MODETYPE_USER) + , parentmod(parent) +{ +} + +void HideOperWatcher::AfterMode(User* source, User* dest, Channel* channel, const std::string& parameter, bool adding) { if (IS_LOCAL(dest)) parentmod->SetOperPrefix(dest, !adding); diff --git a/src/modules/m_override.cpp b/src/modules/m_override.cpp index 1d9447fc4..e342e7dab 100644 --- a/src/modules/m_override.cpp +++ b/src/modules/m_override.cpp @@ -26,25 +26,32 @@ #include "inspircd.h" -/* $ModDesc: Provides support for allowing opers to override certain things. */ - class ModuleOverride : public Module { bool RequireKey; bool NoisyOverride; + ChanModeReference topiclock; + ChanModeReference inviteonly; + ChanModeReference key; + ChanModeReference limit; public: + ModuleOverride() + : topiclock(this, "topiclock") + , inviteonly(this, "inviteonly") + , key(this, "key") + , limit(this, "limit") + { + } - void init() + void init() CXX11_OVERRIDE { // read our config options (main config file) OnRehash(NULL); ServerInstance->SNO->EnableSnomask('v', "OVERRIDE"); - Implementation eventlist[] = { I_OnRehash, I_OnPreMode, I_On005Numeric, I_OnUserPreJoin, I_OnUserPreKick, I_OnPreTopicChange }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { // re-read our config options on a rehash ConfigTag* tag = ServerInstance->Config->ConfValue("override"); @@ -52,9 +59,9 @@ class ModuleOverride : public Module RequireKey = tag->getBool("requirekey"); } - void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - output.append(" OVERRIDE"); + tokens["OVERRIDE"]; } bool CanOverride(User* source, const char* token) @@ -66,11 +73,11 @@ class ModuleOverride : public Module } - ModResult OnPreTopicChange(User *source, Channel *channel, const std::string &topic) + ModResult OnPreTopicChange(User *source, Channel *channel, const std::string &topic) CXX11_OVERRIDE { - if (IS_LOCAL(source) && IS_OPER(source) && CanOverride(source, "TOPIC")) + if (IS_LOCAL(source) && source->IsOper() && CanOverride(source, "TOPIC")) { - if (!channel->HasUser(source) || (channel->IsModeSet('t') && channel->GetPrefixValue(source) < HALFOP_VALUE)) + if (!channel->HasUser(source) || (channel->IsModeSet(topiclock) && channel->GetPrefixValue(source) < HALFOP_VALUE)) { ServerInstance->SNO->WriteGlobalSno('v',source->nick+" used oper override to change a topic on "+channel->name); } @@ -82,9 +89,9 @@ class ModuleOverride : public Module return MOD_RES_PASSTHRU; } - ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason) + ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason) CXX11_OVERRIDE { - if (IS_OPER(source) && CanOverride(source,"KICK")) + if (source->IsOper() && CanOverride(source,"KICK")) { // If the kicker's status is less than the target's, or the kicker's status is less than or equal to voice if ((memb->chan->GetPrefixValue(source) < memb->getRank()) || (memb->chan->GetPrefixValue(source) <= VOICE_VALUE)) @@ -96,11 +103,11 @@ class ModuleOverride : public Module return MOD_RES_PASSTHRU; } - ModResult OnPreMode(User* source,User* dest,Channel* channel, const std::vector<std::string>& parameters) + ModResult OnPreMode(User* source,User* dest,Channel* channel, const std::vector<std::string>& parameters) CXX11_OVERRIDE { if (!source || !channel) return MOD_RES_PASSTHRU; - if (!IS_OPER(source) || !IS_LOCAL(source)) + if (!source->IsOper() || !IS_LOCAL(source)) return MOD_RES_PASSTHRU; unsigned int mode = channel->GetPrefixValue(source); @@ -116,58 +123,57 @@ class ModuleOverride : public Module return MOD_RES_PASSTHRU; } - ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven) + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { - if (IS_LOCAL(user) && IS_OPER(user)) + if (user->IsOper()) { if (chan) { - if (chan->IsModeSet('i') && (CanOverride(user,"INVITE"))) + if (chan->IsModeSet(inviteonly) && (CanOverride(user,"INVITE"))) { - irc::string x(chan->name.c_str()); - if (!IS_LOCAL(user)->IsInvited(x)) + if (!IS_LOCAL(user)->IsInvited(chan)) { if (RequireKey && keygiven != "override") { // Can't join normally -- must use a special key to bypass restrictions - user->WriteServ("NOTICE %s :*** You may not join normally. You must join with a key of 'override' to oper override.", user->nick.c_str()); + user->WriteNotice("*** You may not join normally. You must join with a key of 'override' to oper override."); return MOD_RES_PASSTHRU; } if (NoisyOverride) - chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper override to bypass invite-only", cname, user->nick.c_str()); - ServerInstance->SNO->WriteGlobalSno('v', user->nick+" used oper override to bypass +i on "+std::string(cname)); + chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper override to bypass invite-only", cname.c_str(), user->nick.c_str()); + ServerInstance->SNO->WriteGlobalSno('v', user->nick+" used oper override to bypass +i on " + cname); } return MOD_RES_ALLOW; } - if (chan->IsModeSet('k') && (CanOverride(user,"KEY")) && keygiven != chan->GetModeParameter('k')) + if (chan->IsModeSet(key) && (CanOverride(user,"KEY")) && keygiven != chan->GetModeParameter(key)) { if (RequireKey && keygiven != "override") { // Can't join normally -- must use a special key to bypass restrictions - user->WriteServ("NOTICE %s :*** You may not join normally. You must join with a key of 'override' to oper override.", user->nick.c_str()); + user->WriteNotice("*** You may not join normally. You must join with a key of 'override' to oper override."); return MOD_RES_PASSTHRU; } if (NoisyOverride) - chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper override to bypass the channel key", cname, user->nick.c_str()); - ServerInstance->SNO->WriteGlobalSno('v', user->nick+" used oper override to bypass +k on "+std::string(cname)); + chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper override to bypass the channel key", cname.c_str(), user->nick.c_str()); + ServerInstance->SNO->WriteGlobalSno('v', user->nick+" used oper override to bypass +k on " + cname); return MOD_RES_ALLOW; } - if (chan->IsModeSet('l') && (chan->GetUserCounter() >= ConvToInt(chan->GetModeParameter('l'))) && (CanOverride(user,"LIMIT"))) + if (chan->IsModeSet(limit) && (chan->GetUserCounter() >= ConvToInt(chan->GetModeParameter(limit))) && (CanOverride(user,"LIMIT"))) { if (RequireKey && keygiven != "override") { // Can't join normally -- must use a special key to bypass restrictions - user->WriteServ("NOTICE %s :*** You may not join normally. You must join with a key of 'override' to oper override.", user->nick.c_str()); + user->WriteNotice("*** You may not join normally. You must join with a key of 'override' to oper override."); return MOD_RES_PASSTHRU; } if (NoisyOverride) - chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper override to bypass the channel limit", cname, user->nick.c_str()); - ServerInstance->SNO->WriteGlobalSno('v', user->nick+" used oper override to bypass +l on "+std::string(cname)); + chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper override to bypass the channel limit", cname.c_str(), user->nick.c_str()); + ServerInstance->SNO->WriteGlobalSno('v', user->nick+" used oper override to bypass +l on " + cname); return MOD_RES_ALLOW; } @@ -176,13 +182,13 @@ class ModuleOverride : public Module if (RequireKey && keygiven != "override") { // Can't join normally -- must use a special key to bypass restrictions - user->WriteServ("NOTICE %s :*** You may not join normally. You must join with a key of 'override' to oper override.", user->nick.c_str()); + user->WriteNotice("*** You may not join normally. You must join with a key of 'override' to oper override."); return MOD_RES_PASSTHRU; } if (NoisyOverride) - chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper override to bypass channel ban", cname, user->nick.c_str()); - ServerInstance->SNO->WriteGlobalSno('v',"%s used oper override to bypass channel ban on %s", user->nick.c_str(), cname); + chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper override to bypass channel ban", cname.c_str(), user->nick.c_str()); + ServerInstance->SNO->WriteGlobalSno('v',"%s used oper override to bypass channel ban on %s", user->nick.c_str(), cname.c_str()); return MOD_RES_ALLOW; } } @@ -190,7 +196,7 @@ class ModuleOverride : public Module return MOD_RES_PASSTHRU; } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for allowing opers to override certain things",VF_VENDOR); } diff --git a/src/modules/m_passforward.cpp b/src/modules/m_passforward.cpp index c04b306b1..7f3cb6421 100644 --- a/src/modules/m_passforward.cpp +++ b/src/modules/m_passforward.cpp @@ -17,29 +17,24 @@ */ -/* $ModDesc: Forwards a password users can send on connect (for example for NickServ identification). */ - #include "inspircd.h" class ModulePassForward : public Module { - private: std::string nickrequired, forwardmsg, forwardcmd; public: - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); - Implementation eventlist[] = { I_OnPostConnect, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Sends server password to NickServ", VF_VENDOR); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("passforward"); nickrequired = tag->getString("nick", "NickServ"); @@ -82,7 +77,7 @@ class ModulePassForward : public Module } } - virtual void OnPostConnect(User* ruser) + void OnPostConnect(User* ruser) CXX11_OVERRIDE { LocalUser* user = IS_LOCAL(ruser); if (!user || user->password.empty()) diff --git a/src/modules/m_password_hash.cpp b/src/modules/m_password_hash.cpp index 98462780b..4f7d9e449 100644 --- a/src/modules/m_password_hash.cpp +++ b/src/modules/m_password_hash.cpp @@ -18,10 +18,8 @@ */ -/* $ModDesc: Allows for hashed oper passwords */ - #include "inspircd.h" -#include "hash.h" +#include "modules/hash.h" /* Handle /MKPASSWD */ @@ -42,15 +40,14 @@ class CommandMkpasswd : public Command HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + type); if (!hp) { - user->WriteServ("NOTICE %s :Unknown hash type", user->nick.c_str()); + user->WriteNotice("Unknown hash type"); return; } std::string salt = ServerInstance->GenRandomStr(6, false); std::string target = hp->hmac(salt, stuff); std::string str = BinToBase64(salt) + "$" + BinToBase64(target, NULL, 0); - user->WriteServ("NOTICE %s :%s hashed password for %s is %s", - user->nick.c_str(), algo.c_str(), stuff.c_str(), str.c_str()); + user->WriteNotice(algo + " hashed password for " + stuff + " is " + str); return; } HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + algo); @@ -58,12 +55,11 @@ class CommandMkpasswd : public Command { /* Now attempt to generate a hash */ std::string hexsum = hp->hexsum(stuff); - user->WriteServ("NOTICE %s :%s hashed password for %s is %s", - user->nick.c_str(), algo.c_str(), stuff.c_str(), hexsum.c_str()); + user->WriteNotice(algo + " hashed password for " + stuff + " is " + hexsum); } else { - user->WriteServ("NOTICE %s :Unknown hash type", user->nick.c_str()); + user->WriteNotice("Unknown hash type"); } } @@ -84,17 +80,15 @@ class ModuleOperHash : public Module { } - void init() + void init() CXX11_OVERRIDE { /* Read the config file first */ OnRehash(NULL); ServerInstance->Modules->AddService(cmd); - Implementation eventlist[] = { I_OnPassCompare }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual ModResult OnPassCompare(Extensible* ex, const std::string &data, const std::string &input, const std::string &hashtype) + ModResult OnPassCompare(Extensible* ex, const std::string &data, const std::string &input, const std::string &hashtype) CXX11_OVERRIDE { if (hashtype.substr(0,5) == "hmac-") { @@ -132,7 +126,7 @@ class ModuleOperHash : public Module return MOD_RES_PASSTHRU; } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Allows for hashed oper passwords",VF_VENDOR); } diff --git a/src/modules/m_permchannels.cpp b/src/modules/m_permchannels.cpp index 0a7dc8ed9..a19a184e0 100644 --- a/src/modules/m_permchannels.cpp +++ b/src/modules/m_permchannels.cpp @@ -19,8 +19,9 @@ #include "inspircd.h" +#include "listmode.h" +#include <fstream> -/* $ModDesc: Provides support for channel mode +P to provide permanent channels */ struct ListModeData { @@ -28,40 +29,61 @@ struct ListModeData std::string params; }; -// Not in a class due to circular dependancy hell. -static std::string permchannelsconf; -static bool WriteDatabase(Module* mod, bool save_listmodes) +/** Handles the +P channel mode + */ +class PermChannel : public ModeHandler { - FILE *f; - - if (permchannelsconf.empty()) + public: + PermChannel(Module* Creator) + : ModeHandler(Creator, "permanent", 'P', PARAM_NONE, MODETYPE_CHANNEL) { - // Fake success. - return true; + oper = true; } - std::string tempname = permchannelsconf + ".tmp"; + ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) + { + if (adding == channel->IsModeSet(this)) + return MODEACTION_DENY; + + channel->SetMode(this, adding); + if (!adding) + channel->CheckDestroy(); + + return MODEACTION_ALLOW; + } +}; +// Not in a class due to circular dependancy hell. +static std::string permchannelsconf; +static bool WriteDatabase(PermChannel& permchanmode, Module* mod, bool save_listmodes) +{ + ChanModeReference ban(mod, "ban"); /* * We need to perform an atomic write so as not to fuck things up. - * So, let's write to a temporary file, flush and sync the FD, then rename the file.. - * -- w00t + * So, let's write to a temporary file, flush it, then rename the file.. + * -- w00t */ - f = fopen(tempname.c_str(), "w"); - if (!f) + + // If the user has not specified a configuration file then we don't write one. + if (permchannelsconf.empty()) + return true; + + std::string permchannelsnewconf = permchannelsconf + ".tmp"; + std::ofstream stream(permchannelsnewconf.c_str()); + if (!stream.is_open()) { - ServerInstance->Logs->Log("m_permchannels",DEFAULT, "permchannels: Cannot create database! %s (%d)", strerror(errno), errno); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot create database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot create new db: %s (%d)", strerror(errno), errno); return false; } + + stream << "# This file is automatically generated by m_permchannels. Any changes will be overwritten." << std::endl + << "<config format=\"xml\">" << std::endl; - fputs("# Permchannels DB\n# This file is autogenerated; any changes will be overwritten!\n<config format=\"compat\">\n", f); - // Now, let's write. - std::string line; for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++) { Channel* chan = i->second; - if (!chan->IsModeSet('P')) + if (!chan->IsModeSet(permchanmode)) continue; std::string chanmodes = chan->ChanModes(true); @@ -70,18 +92,13 @@ static bool WriteDatabase(Module* mod, bool save_listmodes) ListModeData lm; // Bans are managed by the core, so we have to process them separately - lm.modes = std::string(chan->bans.size(), 'b'); - for (BanList::const_iterator j = chan->bans.begin(); j != chan->bans.end(); ++j) - { - lm.params += j->data; - lm.params += ' '; - } + static_cast<ListModeBase*>(*ban)->DoSyncChannel(chan, mod, &lm); // All other listmodes are managed by modules, so we need to ask them (call their // OnSyncChannel() handler) to give our ProtoSendMode() a list of modes that are // set on the channel. The ListModeData struct is passed as an opaque pointer // that will be passed back to us by the module handling the mode. - FOREACH_MOD(I_OnSyncChannel, OnSyncChannel(chan, mod, &lm)); + FOREACH_MOD(OnSyncChannel, (chan, mod, &lm)); if (!lm.modes.empty()) { @@ -102,71 +119,35 @@ static bool WriteDatabase(Module* mod, bool save_listmodes) } } - std::string chants = ConvToStr(chan->age); - std::string topicts = ConvToStr(chan->topicset); - const char* items[] = - { - "<permchannels channel=", - chan->name.c_str(), - " ts=", - chants.c_str(), - " topic=", - chan->topic.c_str(), - " topicts=", - topicts.c_str(), - " topicsetby=", - chan->setby.c_str(), - " modes=", - chanmodes.c_str(), - ">\n" - }; - - line.clear(); - int item = 0, ipos = 0; - while (item < 13) - { - char c = items[item][ipos++]; - if (c == 0) - { - // end of this string; hop to next string, insert a quote - item++; - ipos = 0; - c = '"'; - } - else if (c == '\\' || c == '"') - { - line += '\\'; - } - line += c; - } - - // Erase last '"' - line.erase(line.end()-1); - fputs(line.c_str(), f); + stream << "<permchannels channel=\"" << ServerConfig::Escape(chan->name) + << "\" ts=\"" << chan->age + << "\" topic=\"" << ServerConfig::Escape(chan->topic) + << "\" topicts=\"" << chan->topicset + << "\" topicsetby=\"" << ServerConfig::Escape(chan->setby) + << "\" modes=\"" << ServerConfig::Escape(chanmodes) + << "\">" << std::endl; } - int write_error = 0; - write_error = ferror(f); - write_error |= fclose(f); - if (write_error) + if (stream.fail()) { - ServerInstance->Logs->Log("m_permchannels",DEFAULT, "permchannels: Cannot write to new database! %s (%d)", strerror(errno), errno); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot write to new database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot write to new db: %s (%d)", strerror(errno), errno); return false; } + stream.close(); #ifdef _WIN32 if (remove(permchannelsconf.c_str())) { - ServerInstance->Logs->Log("m_permchannels",DEFAULT, "permchannels: Cannot remove old database! %s (%d)", strerror(errno), errno); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot remove old database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot remove old database: %s (%d)", strerror(errno), errno); return false; } #endif // Use rename to move temporary to new db - this is guarenteed not to fuck up, even in case of a crash. - if (rename(tempname.c_str(), permchannelsconf.c_str()) < 0) + if (rename(permchannelsnewconf.c_str(), permchannelsconf.c_str()) < 0) { - ServerInstance->Logs->Log("m_permchannels",DEFAULT, "permchannels: Cannot move new to old database! %s (%d)", strerror(errno), errno); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot move new to old database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot replace old with new db: %s (%d)", strerror(errno), errno); return false; } @@ -174,42 +155,6 @@ static bool WriteDatabase(Module* mod, bool save_listmodes) return true; } - - -/** Handles the +P channel mode - */ -class PermChannel : public ModeHandler -{ - public: - PermChannel(Module* Creator) : ModeHandler(Creator, "permanent", 'P', PARAM_NONE, MODETYPE_CHANNEL) { oper = true; } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!channel->IsModeSet('P')) - { - channel->SetMode('P',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('P')) - { - channel->SetMode(this,false); - if (channel->GetUserCounter() == 0) - { - channel->DelUser(ServerInstance->FakeClient); - } - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } -}; - class ModulePermanentChannels : public Module { PermChannel p; @@ -221,11 +166,9 @@ public: { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(p); - Implementation eventlist[] = { I_OnChannelPreDelete, I_OnPostTopicChange, I_OnRawMode, I_OnRehash, I_OnBackgroundTimer }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); } @@ -245,7 +188,7 @@ public: { chan_hash::iterator at = iter; iter++; - FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(c)); + FOREACH_MOD(OnChannelDelete, (c)); ServerInstance->chanlist->erase(at); ServerInstance->GlobalCulls.AddItem(c); } @@ -256,7 +199,7 @@ public: return Module::cull(); } - virtual void OnRehash(User *user) + void OnRehash(User *user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("permchanneldb"); permchannelsconf = tag->getString("filename"); @@ -274,12 +217,11 @@ public: { ConfigTag* tag = i->second; std::string channel = tag->getString("channel"); - std::string topic = tag->getString("topic"); std::string modes = tag->getString("modes"); if ((channel.empty()) || (channel.length() > ServerInstance->Config->Limits.ChanMax)) { - ServerInstance->Logs->Log("m_permchannels", DEFAULT, "Ignoring permchannels tag with empty or too long channel name (\"" + channel + "\")"); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring permchannels tag with empty or too long channel name (\"" + channel + "\")"); continue; } @@ -287,19 +229,23 @@ public: if (!c) { - time_t TS = tag->getInt("ts"); - c = new Channel(channel, ((TS > 0) ? TS : ServerInstance->Time())); + time_t TS = tag->getInt("ts", ServerInstance->Time(), 1); + c = new Channel(channel, TS); - c->SetTopic(NULL, topic, true); - c->setby = tag->getString("topicsetby"); - if (c->setby.empty()) - c->setby = ServerInstance->Config->ServerName; unsigned int topicset = tag->getInt("topicts"); - // SetTopic() sets the topic TS to now, if there was no topicts saved then don't overwrite that with a 0 - if (topicset > 0) + c->topic = tag->getString("topic"); + + if ((topicset != 0) || (!c->topic.empty())) + { + if (topicset == 0) + topicset = ServerInstance->Time(); c->topicset = topicset; + c->setby = tag->getString("topicsetby"); + if (c->setby.empty()) + c->setby = ServerInstance->Config->ServerName; + } - ServerInstance->Logs->Log("m_permchannels", DEBUG, "Added %s with topic %s", channel.c_str(), topic.c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Added %s with topic %s", channel.c_str(), c->topic.c_str()); if (modes.empty()) continue; @@ -328,24 +274,24 @@ public: } } - virtual ModResult OnRawMode(User* user, Channel* chan, const char mode, const std::string ¶m, bool adding, int pcnt) + ModResult OnRawMode(User* user, Channel* chan, const char mode, const std::string ¶m, bool adding, int pcnt) CXX11_OVERRIDE { - if (chan && (chan->IsModeSet('P') || mode == 'P')) + if (chan && (chan->IsModeSet(p) || mode == p.GetModeChar())) dirty = true; return MOD_RES_PASSTHRU; } - virtual void OnPostTopicChange(User*, Channel *c, const std::string&) + void OnPostTopicChange(User*, Channel *c, const std::string&) CXX11_OVERRIDE { - if (c->IsModeSet('P')) + if (c->IsModeSet(p)) dirty = true; } - void OnBackgroundTimer(time_t) + void OnBackgroundTimer(time_t) CXX11_OVERRIDE { if (dirty) - WriteDatabase(this, save_listmodes); + WriteDatabase(p, this, save_listmodes); dirty = false; } @@ -366,7 +312,7 @@ public: // Load only when there are no linked servers - we set the TS of the channels we // create to the current time, this can lead to desync because spanningtree has // no way of knowing what we do - ProtoServerList serverlist; + ProtocolInterface::ServerList serverlist; ServerInstance->PI->GetServerList(serverlist); if (serverlist.size() < 2) { @@ -376,7 +322,7 @@ public: } catch (CoreException& e) { - ServerInstance->Logs->Log("m_permchannels", DEFAULT, "Error loading permchannels database: " + std::string(e.GetReason())); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Error loading permchannels database: " + std::string(e.GetReason())); } } } @@ -400,14 +346,14 @@ public: } } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for channel mode +P to provide permanent channels",VF_VENDOR); } - virtual ModResult OnChannelPreDelete(Channel *c) + ModResult OnChannelPreDelete(Channel *c) CXX11_OVERRIDE { - if (c->IsModeSet('P')) + if (c->IsModeSet(p)) return MOD_RES_DENY; return MOD_RES_PASSTHRU; diff --git a/src/modules/m_randquote.cpp b/src/modules/m_randquote.cpp index 668eea0e5..1bb28583e 100644 --- a/src/modules/m_randquote.cpp +++ b/src/modules/m_randquote.cpp @@ -21,80 +21,37 @@ */ -/* $ModDesc: Provides random quotes on connect. */ - #include "inspircd.h" -static FileReader *quotes = NULL; - -std::string prefix; -std::string suffix; - -/** Handle /RANDQUOTE - */ -class CommandRandquote : public Command -{ - public: - CommandRandquote(Module* Creator) : Command(Creator,"RANDQUOTE", 0) - { - } - - CmdResult Handle (const std::vector<std::string>& parameters, User *user) - { - int fsize = quotes->FileSize(); - if (fsize) - { - std::string str = quotes->GetLine(ServerInstance->GenRandomInt(fsize)); - if (!str.empty()) - user->WriteServ("NOTICE %s :%s%s%s",user->nick.c_str(),prefix.c_str(),str.c_str(),suffix.c_str()); - } - - return CMD_SUCCESS; - } -}; - class ModuleRandQuote : public Module { private: - CommandRandquote cmd; - public: - ModuleRandQuote() - : cmd(this) - { - } + std::string prefix; + std::string suffix; + std::vector<std::string> quotes; - void init() + public: + void init() CXX11_OVERRIDE { ConfigTag* conf = ServerInstance->Config->ConfValue("randquote"); - - std::string q_file = conf->getString("file","quotes"); prefix = conf->getString("prefix"); suffix = conf->getString("suffix"); - - quotes = new FileReader(q_file); - if (!quotes->Exists()) - { - throw ModuleException("m_randquote: QuoteFile not Found!! Please check your config - module will not function."); - } - ServerInstance->Modules->AddService(cmd); - Implementation eventlist[] = { I_OnUserConnect }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); + FileReader reader(conf->getString("file", "quotes")); + quotes = reader.GetVector(); } - - virtual ~ModuleRandQuote() + void OnUserConnect(LocalUser* user) CXX11_OVERRIDE { - delete quotes; - } - - virtual Version GetVersion() - { - return Version("Provides random quotes on connect.",VF_VENDOR); + if (!quotes.empty()) + { + unsigned long random = ServerInstance->GenRandomInt(quotes.size()); + user->WriteNotice(prefix + quotes[random] + suffix); + } } - virtual void OnUserConnect(LocalUser* user) + Version GetVersion() CXX11_OVERRIDE { - cmd.Handle(std::vector<std::string>(), user); + return Version("Provides random quotes on connect.", VF_VENDOR); } }; diff --git a/src/modules/m_redirect.cpp b/src/modules/m_redirect.cpp index 26d6b162b..89097ade4 100644 --- a/src/modules/m_redirect.cpp +++ b/src/modules/m_redirect.cpp @@ -24,8 +24,6 @@ #include "inspircd.h" -/* $ModDesc: Provides channel mode +L (limit redirection) and usermode +L (no forced redirection) */ - /** Handle channel mode +L */ class Redirect : public ModeHandler @@ -39,7 +37,7 @@ class Redirect : public ModeHandler { if (IS_LOCAL(source)) { - if (!ServerInstance->IsChannel(parameter.c_str(), ServerInstance->Config->Limits.ChanMax)) + if (!ServerInstance->IsChannel(parameter)) { source->WriteNumeric(403, "%s %s :Invalid channel name", source->nick.c_str(), parameter.c_str()); parameter.clear(); @@ -47,7 +45,7 @@ class Redirect : public ModeHandler } } - if (IS_LOCAL(source) && !IS_OPER(source)) + if (IS_LOCAL(source) && !source->IsOper()) { Channel* c = ServerInstance->FindChan(parameter); if (!c) @@ -64,20 +62,18 @@ class Redirect : public ModeHandler } } - if (channel->GetModeParameter('L') == parameter) + if (channel->GetModeParameter(this) == parameter) return MODEACTION_DENY; /* * We used to do some checking for circular +L here, but there is no real need for this any more especially as we * now catch +L looping in PreJoin. Remove it, since O(n) logic makes me sad, and we catch it anyway. :) -- w00t */ - channel->SetModeParam('L', parameter); return MODEACTION_ALLOW; } else { - if (channel->IsModeSet('L')) + if (channel->IsModeSet(this)) { - channel->SetModeParam('L', ""); return MODEACTION_ALLOW; } } @@ -97,19 +93,20 @@ class AntiRedirect : public SimpleUserModeHandler class ModuleRedirect : public Module { - Redirect re; AntiRedirect re_u; + ChanModeReference limitmode; bool UseUsermode; public: - ModuleRedirect() - : re(this), re_u(this) + : re(this) + , re_u(this) + , limitmode(this, "limit") { } - void init() + void init() CXX11_OVERRIDE { /* Setting this here so it isn't changable by rehasing the config later. */ UseUsermode = ServerInstance->Config->ConfValue("redirect")->getBool("antiredirect"); @@ -121,46 +118,41 @@ class ModuleRedirect : public Module if (UseUsermode) { /* Log noting that this breaks compatability. */ - ServerInstance->Logs->Log("m_redirect", DEFAULT, "REDIRECT: Enabled usermode +L. This breaks linking with servers that do not have this enabled. This is disabled by default in the 2.0 branch but will be enabled in the next version."); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "REDIRECT: Enabled usermode +L. This breaks linking with servers that do not have this enabled. This is disabled by default in the 2.0 branch but will be enabled in the next version."); /* Try to add the usermode */ ServerInstance->Modules->AddService(re_u); } - - Implementation eventlist[] = { I_OnUserPreJoin }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven) + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { if (chan) { - if (chan->IsModeSet('L') && chan->IsModeSet('l')) + if (chan->IsModeSet(re) && chan->IsModeSet(limitmode)) { - if (chan->GetUserCounter() >= ConvToInt(chan->GetModeParameter('l'))) + if (chan->GetUserCounter() >= ConvToInt(chan->GetModeParameter(limitmode))) { - std::string channel = chan->GetModeParameter('L'); + std::string channel = chan->GetModeParameter(&re); /* sometimes broken ulines can make circular or chained +L, avoid this */ - Channel* destchan = NULL; - destchan = ServerInstance->FindChan(channel); - if (destchan && destchan->IsModeSet('L')) + Channel* destchan = ServerInstance->FindChan(channel); + if (destchan && destchan->IsModeSet(re)) { - user->WriteNumeric(470, "%s %s * :You may not join this channel. A redirect is set, but you may not be redirected as it is a circular loop.", user->nick.c_str(), cname); + user->WriteNumeric(470, "%s %s * :You may not join this channel. A redirect is set, but you may not be redirected as it is a circular loop.", user->nick.c_str(), cname.c_str()); return MOD_RES_DENY; } /* We check the bool value here to make sure we have it enabled, if we don't then usermode +L might be assigned to something else. */ - if (UseUsermode && user->IsModeSet('L')) + if (UseUsermode && user->IsModeSet(re_u)) { - user->WriteNumeric(470, "%s %s %s :Force redirection stopped.", - user->nick.c_str(), cname, channel.c_str()); + user->WriteNumeric(470, "%s %s %s :Force redirection stopped.", user->nick.c_str(), cname.c_str(), channel.c_str()); return MOD_RES_DENY; } else { - user->WriteNumeric(470, "%s %s %s :You may not join this channel, so you are automatically being transferred to the redirect channel.", user->nick.c_str(), cname, channel.c_str()); - Channel::JoinUser(user, channel.c_str(), false, "", false, ServerInstance->Time()); + user->WriteNumeric(470, "%s %s %s :You may not join this channel, so you are automatically being transferred to the redirect channel.", user->nick.c_str(), cname.c_str(), channel.c_str()); + Channel::JoinUser(user, channel); return MOD_RES_DENY; } } @@ -169,11 +161,7 @@ class ModuleRedirect : public Module return MOD_RES_PASSTHRU; } - virtual ~ModuleRedirect() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +L (limit redirection) and user mode +L (no forced redirection)", VF_VENDOR); } diff --git a/src/modules/m_regex_glob.cpp b/src/modules/m_regex_glob.cpp index 44d1a5898..eb7cf4ece 100644 --- a/src/modules/m_regex_glob.cpp +++ b/src/modules/m_regex_glob.cpp @@ -18,11 +18,9 @@ */ -#include "m_regex.h" +#include "modules/regex.h" #include "inspircd.h" -/* $ModDesc: Regex module using plain wildcard matching. */ - class GlobRegex : public Regex { public: @@ -30,11 +28,7 @@ public: { } - virtual ~GlobRegex() - { - } - - virtual bool Matches(const std::string& text) + bool Matches(const std::string& text) CXX11_OVERRIDE { return InspIRCd::Match(text, this->regex_string); } @@ -43,7 +37,7 @@ public: class GlobFactory : public RegexFactory { public: - Regex* Create(const std::string& expr) + Regex* Create(const std::string& expr) CXX11_OVERRIDE { return new GlobRegex(expr); } @@ -59,7 +53,7 @@ public: ServerInstance->Modules->AddService(gf); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Regex module using plain wildcard matching.", VF_VENDOR); } diff --git a/src/modules/m_regonlycreate.cpp b/src/modules/m_regonlycreate.cpp index 61f94c0bd..b6f7c2c4f 100644 --- a/src/modules/m_regonlycreate.cpp +++ b/src/modules/m_regonlycreate.cpp @@ -21,28 +21,27 @@ #include "inspircd.h" -#include "account.h" - -/* $ModDesc: Prevents users whose nicks are not registered from creating new channels */ +#include "modules/account.h" class ModuleRegOnlyCreate : public Module { + UserModeReference regusermode; + public: - void init() + ModuleRegOnlyCreate() + : regusermode(this, "u_registered") { - Implementation eventlist[] = { I_OnUserPreJoin }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven) + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { if (chan) return MOD_RES_PASSTHRU; - if (IS_OPER(user)) + if (user->IsOper()) return MOD_RES_PASSTHRU; - if (user->IsModeSet('r')) + if (user->IsModeSet(regusermode)) return MOD_RES_PASSTHRU; const AccountExtItem* ext = GetAccountExtItem(); @@ -50,15 +49,11 @@ class ModuleRegOnlyCreate : public Module return MOD_RES_PASSTHRU; // XXX. there may be a better numeric for this.. - user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have a registered nickname to create a new channel", user->nick.c_str(), cname); + user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have a registered nickname to create a new channel", user->nick.c_str(), cname.c_str()); return MOD_RES_DENY; } - ~ModuleRegOnlyCreate() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Prevents users whose nicks are not registered from creating new channels", VF_VENDOR); } diff --git a/src/modules/m_remove.cpp b/src/modules/m_remove.cpp index 86f50ad62..43f7065b5 100644 --- a/src/modules/m_remove.cpp +++ b/src/modules/m_remove.cpp @@ -24,8 +24,6 @@ #include "inspircd.h" -/* $ModDesc: Provides a /remove command, this is mostly an alternative to /kick, except makes users appear to have parted the channel */ - /* * This module supports the use of the +q and +a usermodes, but should work without them too. * Usage of the command is restricted to +hoaq, and you cannot remove a user with a "higher" level than yourself. @@ -36,12 +34,14 @@ */ class RemoveBase : public Command { - private: bool& supportnokicks; + ChanModeReference& nokicksmode; public: - RemoveBase(Module* Creator, bool& snk, const char* cmdn) - : Command(Creator, cmdn, 2, 3), supportnokicks(snk) + RemoveBase(Module* Creator, bool& snk, ChanModeReference& nkm, const char* cmdn) + : Command(Creator, cmdn, 2, 3) + , supportnokicks(snk) + , nokicksmode(nkm) { } @@ -50,9 +50,6 @@ class RemoveBase : public Command User* target; Channel* channel; std::string reason; - std::string protectkey; - std::string founderkey; - bool hasnokicks; /* Set these to the parameters needed, the new version of this module switches it's parameters around * supplying a new command with the new order while keeping the old /remove with the older order. @@ -84,8 +81,6 @@ class RemoveBase : public Command int ulevel = channel->GetPrefixValue(user); int tlevel = channel->GetPrefixValue(target); - hasnokicks = (ServerInstance->Modules->Find("m_nokicks.so") && channel->IsModeSet('Q')); - if (ServerInstance->ULine(target->server)) { user->WriteNumeric(482, "%s %s :Only a u-line may remove a u-line from a channel.", user->nick.c_str(), channame.c_str()); @@ -93,7 +88,7 @@ class RemoveBase : public Command } /* We support the +Q channel mode via. the m_nokicks module, if the module is loaded and the mode is set then disallow the /remove */ - if ((!IS_LOCAL(user)) || (!supportnokicks || !hasnokicks)) + if ((!IS_LOCAL(user)) || (!supportnokicks) || (!channel->IsModeSet(nokicksmode))) { /* We'll let everyone remove their level and below, eg: * ops can remove ops, halfops, voices, and those with no mode (no moders actually are set to 1) @@ -118,7 +113,7 @@ class RemoveBase : public Command reason = "Removed by " + user->nick + ": " + reasonparam; channel->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s removed %s from the channel", channel->name.c_str(), user->nick.c_str(), target->nick.c_str()); - target->WriteServ("NOTICE %s :*** %s removed you from %s with the message: %s", target->nick.c_str(), user->nick.c_str(), channel->name.c_str(), reasonparam.c_str()); + target->WriteNotice("*** " + user->nick + " removed you from " + channel->name + " with the message: " + reasonparam); channel->PartUser(target, reason); } @@ -131,13 +126,13 @@ class RemoveBase : public Command else { /* m_nokicks.so was loaded and +Q was set, block! */ - user->WriteServ( "484 %s %s :Can't remove user %s from channel (+Q set)", user->nick.c_str(), channel->name.c_str(), target->nick.c_str()); + user->WriteServ( "484 %s %s :Can't remove user %s from channel (nokicks mode is set)", user->nick.c_str(), channel->name.c_str(), target->nick.c_str()); return CMD_FAILURE; } return CMD_SUCCESS; } - virtual RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) = 0; + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) = 0; }; /** Handle /REMOVE @@ -145,11 +140,11 @@ class RemoveBase : public Command class CommandRemove : public RemoveBase { public: - CommandRemove(Module* Creator, bool& snk) - : RemoveBase(Creator, snk, "REMOVE") + CommandRemove(Module* Creator, bool& snk, ChanModeReference& nkm) + : RemoveBase(Creator, snk, nkm, "REMOVE") { syntax = "<nick> <channel> [<reason>]"; - TRANSLATE4(TR_NICK, TR_TEXT, TR_TEXT, TR_END); + TRANSLATE3(TR_NICK, TR_TEXT, TR_TEXT); } CmdResult Handle (const std::vector<std::string>& parameters, User *user) @@ -171,11 +166,11 @@ class CommandRemove : public RemoveBase class CommandFpart : public RemoveBase { public: - CommandFpart(Module* Creator, bool& snk) - : RemoveBase(Creator, snk, "FPART") + CommandFpart(Module* Creator, bool& snk, ChanModeReference& nkm) + : RemoveBase(Creator, snk, nkm, "FPART") { syntax = "<channel> <nick> [<reason>]"; - TRANSLATE4(TR_TEXT, TR_NICK, TR_TEXT, TR_END); + TRANSLATE3(TR_TEXT, TR_NICK, TR_TEXT); } CmdResult Handle (const std::vector<std::string>& parameters, User *user) @@ -194,44 +189,40 @@ class CommandFpart : public RemoveBase class ModuleRemove : public Module { + ChanModeReference nokicksmode; CommandRemove cmd1; CommandFpart cmd2; bool supportnokicks; - public: - ModuleRemove() : cmd1(this, supportnokicks), cmd2(this, supportnokicks) + ModuleRemove() + : nokicksmode(this, "nokick") + , cmd1(this, supportnokicks, nokicksmode) + , cmd2(this, supportnokicks, nokicksmode) { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd1); ServerInstance->Modules->AddService(cmd2); OnRehash(NULL); - Implementation eventlist[] = { I_On005Numeric, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - output.append(" REMOVE"); + tokens["REMOVE"]; } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { supportnokicks = ServerInstance->Config->ConfValue("remove")->getBool("supportnokicks"); } - virtual ~ModuleRemove() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides a /remove command, this is mostly an alternative to /kick, except makes users appear to have parted the channel", VF_OPTCOMMON | VF_VENDOR); } - }; MODULE_INIT(ModuleRemove) diff --git a/src/modules/m_repeat.cpp b/src/modules/m_repeat.cpp new file mode 100644 index 000000000..4591d8ad2 --- /dev/null +++ b/src/modules/m_repeat.cpp @@ -0,0 +1,413 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Daniel Vassdal <shutter@canternet.org> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "inspircd.h" + +#ifdef _WIN32 +// windows.h defines this +#undef min +#endif + +class RepeatMode : public ModeHandler +{ + private: + struct RepeatItem + { + time_t ts; + std::string line; + RepeatItem(time_t TS, const std::string& Line) : ts(TS), line(Line) { } + }; + + typedef std::deque<RepeatItem> RepeatItemList; + + struct MemberInfo + { + RepeatItemList ItemList; + unsigned int Counter; + MemberInfo() : Counter(0) {} + }; + + struct ModuleSettings + { + unsigned int MaxLines; + unsigned int MaxSecs; + unsigned int MaxBacklog; + unsigned int MaxDiff; + unsigned int MaxMessageSize; + ModuleSettings() : MaxLines(0), MaxSecs(0), MaxBacklog(0), MaxDiff() { } + }; + + std::vector<unsigned int> mx[2]; + ModuleSettings ms; + + bool CompareLines(const std::string& message, const std::string& historyline, unsigned int trigger) + { + if (message == historyline) + return true; + else if (trigger) + return (Levenshtein(message, historyline) <= trigger); + + return false; + } + + unsigned int Levenshtein(const std::string& s1, const std::string& s2) + { + unsigned int l1 = s1.size(); + unsigned int l2 = s2.size(); + + for (unsigned int i = 0; i < l2; i++) + mx[0][i] = i; + for (unsigned int i = 0; i < l1; i++) + { + mx[1][0] = i + 1; + for (unsigned int j = 0; j < l2; j++) + mx[1][j + 1] = std::min(std::min(mx[1][j] + 1, mx[0][j + 1] + 1), mx[0][j] + ((s1[i] == s2[j]) ? 0 : 1)); + + mx[0].swap(mx[1]); + } + return mx[0][l2]; + } + + public: + enum RepeatAction + { + ACT_KICK, + ACT_BLOCK, + ACT_BAN + }; + + class ChannelSettings + { + public: + RepeatAction Action; + unsigned int Backlog; + unsigned int Lines; + unsigned int Diff; + unsigned int Seconds; + + std::string serialize() + { + std::string ret = ((Action == ACT_BAN) ? "*" : (Action == ACT_BLOCK ? "~" : "")) + ConvToStr(Lines) + ":" + ConvToStr(Seconds); + if (Diff) + { + ret += ":" + ConvToStr(Diff); + if (Backlog) + ret += ":" + ConvToStr(Backlog); + } + return ret; + } + }; + + SimpleExtItem<MemberInfo> MemberInfoExt; + SimpleExtItem<ChannelSettings> ChanSet; + + RepeatMode(Module* Creator) + : ModeHandler(Creator, "repeat", 'E', PARAM_SETONLY, MODETYPE_CHANNEL) + , MemberInfoExt("repeat_memb", Creator) + , ChanSet("repeat", Creator) + { + } + + ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) + { + if (!adding) + { + if (!channel->IsModeSet(this)) + return MODEACTION_DENY; + + // Unset the per-membership extension when the mode is removed + const UserMembList* users = channel->GetUsers(); + for (UserMembCIter i = users->begin(); i != users->end(); ++i) + MemberInfoExt.unset(i->second); + + ChanSet.unset(channel); + return MODEACTION_ALLOW; + } + + if (channel->GetModeParameter(this) == parameter) + return MODEACTION_DENY; + + ChannelSettings settings; + if (!ParseSettings(source, parameter, settings)) + { + source->WriteNotice("*** Invalid syntax. Syntax is {[~*]}[lines]:[time]{:[difference]}{:[backlog]}"); + return MODEACTION_DENY; + } + + if ((settings.Backlog > 0) && (settings.Lines > settings.Backlog)) + { + source->WriteNotice("*** You can't set needed lines higher than backlog"); + return MODEACTION_DENY; + } + + LocalUser* localsource = IS_LOCAL(source); + if ((localsource) && (!ValidateSettings(localsource, settings))) + return MODEACTION_DENY; + + ChanSet.set(channel, settings); + + return MODEACTION_ALLOW; + } + + bool MatchLine(Membership* memb, ChannelSettings* rs, std::string message) + { + // If the message is larger than whatever size it's set to, + // let's pretend it isn't. If the first 512 (def. setting) match, it's probably spam. + if (message.size() > ms.MaxMessageSize) + message.erase(ms.MaxMessageSize); + + MemberInfo* rp = MemberInfoExt.get(memb); + if (!rp) + { + rp = new MemberInfo; + MemberInfoExt.set(memb, rp); + } + + unsigned int matches = 0; + if (!rs->Backlog) + matches = rp->Counter; + + RepeatItemList& items = rp->ItemList; + const unsigned int trigger = (message.size() * rs->Diff / 100); + const time_t now = ServerInstance->Time(); + + std::transform(message.begin(), message.end(), message.begin(), ::tolower); + + for (std::deque<RepeatItem>::iterator it = items.begin(); it != items.end(); ++it) + { + if (it->ts < now) + { + items.erase(it, items.end()); + matches = 0; + break; + } + + if (CompareLines(message, it->line, trigger)) + { + if (++matches >= rs->Lines) + { + if (rs->Action != ACT_BLOCK) + rp->Counter = 0; + return true; + } + } + else if ((ms.MaxBacklog == 0) || (rs->Backlog == 0)) + { + matches = 0; + items.clear(); + break; + } + } + + unsigned int max_items = (rs->Backlog ? rs->Backlog : 1); + if (items.size() >= max_items) + items.pop_back(); + + items.push_front(RepeatItem(now + rs->Seconds, message)); + rp->Counter = matches; + return false; + } + + void Resize(size_t size) + { + size_t newsize = size+1; + if (newsize <= mx[0].size()) + return; + ms.MaxMessageSize = size; + mx[0].resize(newsize); + mx[1].resize(newsize); + } + + void ReadConfig() + { + ConfigTag* conf = ServerInstance->Config->ConfValue("repeat"); + ms.MaxLines = conf->getInt("maxlines", 20); + ms.MaxBacklog = conf->getInt("maxbacklog", 20); + ms.MaxSecs = conf->getInt("maxsecs", 0); + + ms.MaxDiff = conf->getInt("maxdistance", 50); + if (ms.MaxDiff > 100) + ms.MaxDiff = 100; + + unsigned int newsize = conf->getInt("size", 512); + if (newsize > ServerInstance->Config->Limits.MaxLine) + newsize = ServerInstance->Config->Limits.MaxLine; + Resize(newsize); + } + + std::string GetModuleSettings() const + { + return ConvToStr(ms.MaxLines) + ":" + ConvToStr(ms.MaxSecs) + ":" + ConvToStr(ms.MaxDiff) + ":" + ConvToStr(ms.MaxBacklog); + } + + private: + bool ParseSettings(User* source, std::string& parameter, ChannelSettings& settings) + { + irc::sepstream stream(parameter, ':'); + std::string item; + if (!stream.GetToken(item)) + // Required parameter missing + return false; + + if ((item[0] == '*') || (item[0] == '~')) + { + settings.Action = ((item[0] == '*') ? ACT_BAN : ACT_BLOCK); + item.erase(item.begin()); + } + else + settings.Action = ACT_KICK; + + if ((settings.Lines = ConvToInt(item)) == 0) + return false; + + if ((!stream.GetToken(item)) || ((settings.Seconds = InspIRCd::Duration(item)) == 0)) + // Required parameter missing + return false; + + // The diff and backlog parameters are optional + settings.Diff = settings.Backlog = 0; + if (stream.GetToken(item)) + { + // There is a diff parameter, see if it's valid (> 0) + if ((settings.Diff = ConvToInt(item)) == 0) + return false; + + if (stream.GetToken(item)) + { + // There is a backlog parameter, see if it's valid + if ((settings.Backlog = ConvToInt(item)) == 0) + return false; + + // If there are still tokens, then it's invalid because we allow only 4 + if (stream.GetToken(item)) + return false; + } + } + + parameter = settings.serialize(); + return true; + } + + bool ValidateSettings(LocalUser* source, const ChannelSettings& settings) + { + if (settings.Backlog && !ms.MaxBacklog) + { + source->WriteNotice("*** The server administrator has disabled backlog matching"); + return false; + } + + if (settings.Diff) + { + if (settings.Diff > ms.MaxDiff) + { + if (ms.MaxDiff == 0) + source->WriteNotice("*** The server administrator has disabled matching on edit distance"); + else + source->WriteNotice("*** The distance you specified is too great. Maximum allowed is " + ConvToStr(ms.MaxDiff)); + return false; + } + + if (ms.MaxLines && settings.Lines > ms.MaxLines) + { + source->WriteNotice("*** The line number you specified is too great. Maximum allowed is " + ConvToStr(ms.MaxLines)); + return false; + } + + if (ms.MaxSecs && settings.Seconds > ms.MaxSecs) + { + source->WriteNotice("*** The seconds you specified is too great. Maximum allowed is " + ConvToStr(ms.MaxSecs)); + return false; + } + } + + return true; + } +}; + +class RepeatModule : public Module +{ + RepeatMode rm; + + public: + RepeatModule() : rm(this) {} + + void init() CXX11_OVERRIDE + { + ServerInstance->Modules->AddService(rm); + ServerInstance->Modules->AddService(rm.ChanSet); + ServerInstance->Modules->AddService(rm.MemberInfoExt); + rm.ReadConfig(); + } + + void OnRehash(User* user) CXX11_OVERRIDE + { + rm.ReadConfig(); + } + + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE + { + if (target_type != TYPE_CHANNEL || !IS_LOCAL(user)) + return MOD_RES_PASSTHRU; + + Membership* memb = ((Channel*)dest)->GetUser(user); + if (!memb || !memb->chan->IsModeSet(&rm)) + return MOD_RES_PASSTHRU; + + if (ServerInstance->OnCheckExemption(user, memb->chan, "repeat") == MOD_RES_ALLOW) + return MOD_RES_PASSTHRU; + + RepeatMode::ChannelSettings* settings = rm.ChanSet.get(memb->chan); + if (!settings) + return MOD_RES_PASSTHRU; + + if (rm.MatchLine(memb, settings, text)) + { + if (settings->Action == RepeatMode::ACT_BLOCK) + { + user->WriteNotice("*** This line is too similiar to one of your last lines."); + return MOD_RES_DENY; + } + + if (settings->Action == RepeatMode::ACT_BAN) + { + std::vector<std::string> parameters; + parameters.push_back(memb->chan->name); + parameters.push_back("+b"); + parameters.push_back("*!*@" + user->dhost); + ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient); + } + + memb->chan->KickUser(ServerInstance->FakeClient, user, "Repeat flood"); + return MOD_RES_DENY; + } + return MOD_RES_PASSTHRU; + } + + void Prioritize() CXX11_OVERRIDE + { + ServerInstance->Modules->SetPriority(this, I_OnUserPreMessage, PRIORITY_LAST); + } + + Version GetVersion() CXX11_OVERRIDE + { + return Version("Provides the +E channel mode - for blocking of similiar messages", VF_COMMON|VF_VENDOR, rm.GetModuleSettings()); + } +}; + +MODULE_INIT(RepeatModule) diff --git a/src/modules/m_restrictchans.cpp b/src/modules/m_restrictchans.cpp index c76b0e79f..21686add3 100644 --- a/src/modules/m_restrictchans.cpp +++ b/src/modules/m_restrictchans.cpp @@ -22,8 +22,6 @@ #include "inspircd.h" -/* $ModDesc: Only opers may create new channels if this module is loaded */ - class ModuleRestrictChans : public Module { std::set<irc::string> allowchans; @@ -41,43 +39,34 @@ class ModuleRestrictChans : public Module } public: - void init() + void init() CXX11_OVERRIDE { ReadConfig(); - Implementation eventlist[] = { I_OnUserPreJoin, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ReadConfig(); } - - virtual ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven) + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { - irc::string x = cname; - if (!IS_LOCAL(user)) - return MOD_RES_PASSTHRU; + irc::string x(cname.c_str()); // channel does not yet exist (record is null, about to be created IF we were to allow it) if (!chan) { // user is not an oper and its not in the allow list - if ((!IS_OPER(user)) && (allowchans.find(x) == allowchans.end())) + if ((!user->IsOper()) && (allowchans.find(x) == allowchans.end())) { - user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s %s :Only IRC operators may create new channels",user->nick.c_str(),cname); + user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s %s :Only IRC operators may create new channels",user->nick.c_str(),cname.c_str()); return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; } - virtual ~ModuleRestrictChans() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Only opers may create new channels if this module is loaded",VF_VENDOR); } diff --git a/src/modules/m_restrictmsg.cpp b/src/modules/m_restrictmsg.cpp index e814f3b16..5fae46d83 100644 --- a/src/modules/m_restrictmsg.cpp +++ b/src/modules/m_restrictmsg.cpp @@ -21,22 +21,10 @@ #include "inspircd.h" -/* $ModDesc: Forbids users from messaging each other. Users may still message opers and opers may message other opers. */ - - class ModuleRestrictMsg : public Module { - public: - - void init() - { - Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - - virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { if ((target_type == TYPE_USER) && (IS_LOCAL(user))) { @@ -46,7 +34,7 @@ class ModuleRestrictMsg : public Module // (1) the sender is opered // (2) the recipient is opered // anything else, blocked. - if (IS_OPER(u) || IS_OPER(user)) + if (u->IsOper() || user->IsOper()) { return MOD_RES_PASSTHRU; } @@ -58,16 +46,7 @@ class ModuleRestrictMsg : public Module return MOD_RES_PASSTHRU; } - virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return this->OnUserPreMessage(user,dest,target_type,text,status,exempt_list); - } - - virtual ~ModuleRestrictMsg() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Forbids users from messaging each other. Users may still message opers and opers may message other opers.",VF_VENDOR); } diff --git a/src/modules/m_ripemd160.cpp b/src/modules/m_ripemd160.cpp index 6ceb4b481..183b75452 100644 --- a/src/modules/m_ripemd160.cpp +++ b/src/modules/m_ripemd160.cpp @@ -56,25 +56,15 @@ */ -/* $ModDesc: Allows for RIPEMD-160 encrypted oper passwords */ - /* macro definitions */ #include "inspircd.h" -#ifdef HAS_STDINT -#include <stdint.h> -#endif -#include "hash.h" +#include "modules/hash.h" #define RMDsize 160 -#ifndef HAS_STDINT -typedef unsigned char byte; -typedef unsigned int dword; -#else -typedef uint8_t byte; -typedef uint32_t dword; -#endif +typedef uint8_t byte; +typedef uint32_t dword; /* collect four bytes into one word: */ #define BYTES_TO_DWORD(strptr) \ @@ -164,7 +154,6 @@ class RIProv : public HashProvider { if (key) { - ServerInstance->Logs->Log("m_ripemd160.so", DEBUG, "initialize with custom mdbuf"); MDbuf[0] = key[0]; MDbuf[1] = key[1]; MDbuf[2] = key[2]; @@ -173,7 +162,6 @@ class RIProv : public HashProvider } else { - ServerInstance->Logs->Log("m_ripemd160.so", DEBUG, "initialize with default mdbuf"); MDbuf[0] = 0x67452301UL; MDbuf[1] = 0xefcdab89UL; MDbuf[2] = 0x98badcfeUL; @@ -414,7 +402,6 @@ class RIProv : public HashProvider byte *RMD(byte *message, dword length, unsigned int* key) { - ServerInstance->Logs->Log("m_ripemd160", DEBUG, "RMD: '%s' length=%u", (const char*)message, length); dword MDbuf[RMDsize/32]; /* contains (A, B, C, D(E)) */ static byte hashcode[RMDsize/8]; /* for final hash-value */ dword X[16]; /* current 16-word chunk */ @@ -451,11 +438,6 @@ public: return std::string(rv, RMDsize / 8); } - std::string sumIV(unsigned int* IV, const char* HexMap, const std::string &sdata) - { - return ""; - } - RIProv(Module* m) : HashProvider(m, "hash/ripemd160", 20, 64) {} }; @@ -468,12 +450,10 @@ class ModuleRIPEMD160 : public Module ServerInstance->Modules->AddService(mr); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides RIPEMD-160 hashing", VF_VENDOR); } - }; MODULE_INIT(ModuleRIPEMD160) - diff --git a/src/modules/m_rline.cpp b/src/modules/m_rline.cpp index d1ab5d9ba..7a65947d3 100644 --- a/src/modules/m_rline.cpp +++ b/src/modules/m_rline.cpp @@ -20,10 +20,8 @@ */ -/* $ModDesc: RLINE: Regexp user banning. */ - #include "inspircd.h" -#include "m_regex.h" +#include "modules/regex.h" #include "xline.h" static bool ZlineOnMatch = false; @@ -60,7 +58,8 @@ class RLine : public XLine bool Matches(User *u) { - if (u->exempt) + LocalUser* lu = IS_LOCAL(u); + if (lu && lu->exempt) return false; std::string compare = u->nick + "!" + u->ident + "@" + u->host + " " + u->fullname; @@ -90,15 +89,9 @@ class RLine : public XLine DefaultApply(u, "R", false); } - void DisplayExpiry() + const std::string& Displayable() { - ServerInstance->SNO->WriteToSnoMask('x',"Removing expired R-line %s (set by %s %ld seconds ago)", - this->matchtext.c_str(), this->source.c_str(), (long int)(ServerInstance->Time() - this->set_time)); - } - - const char* Displayable() - { - return matchtext.c_str(); + return matchtext; } std::string matchtext; @@ -116,7 +109,7 @@ class RLineFactory : public XLineFactory RLineFactory(dynamic_reference<RegexFactory>& rx) : XLineFactory("R"), rxfactory(rx) { } - + /** Generate a RLine */ XLine* Generate(time_t set_time, long duration, std::string source, std::string reason, std::string xline_specific_mask) @@ -129,10 +122,6 @@ class RLineFactory : public XLineFactory return new RLine(set_time, duration, source, reason, xline_specific_mask, rxfactory); } - - ~RLineFactory() - { - } }; /** Handle /RLINE @@ -156,7 +145,7 @@ class CommandRLine : public Command { // Adding - XXX todo make this respect <insane> tag perhaps.. - long duration = ServerInstance->Duration(parameters[1]); + unsigned long duration = InspIRCd::Duration(parameters[1]); XLine *r = NULL; try @@ -188,7 +177,7 @@ class CommandRLine : public Command else { delete r; - user->WriteServ("NOTICE %s :*** R-Line for %s already exists", user->nick.c_str(), parameters[0].c_str()); + user->WriteNotice("*** R-Line for " + parameters[0] + " already exists"); } } } @@ -200,7 +189,7 @@ class CommandRLine : public Command } else { - user->WriteServ("NOTICE %s :*** R-Line %s not found in list, try /stats R.",user->nick.c_str(),parameters[0].c_str()); + user->WriteNotice("*** R-Line " + parameters[0] + " not found in list, try /stats R."); } } @@ -218,7 +207,6 @@ class CommandRLine : public Command class ModuleRLine : public Module { - private: dynamic_reference<RegexFactory> rxfactory; RLineFactory f; CommandRLine r; @@ -233,29 +221,26 @@ class ModuleRLine : public Module { } - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); ServerInstance->Modules->AddService(r); ServerInstance->XLines->RegisterFactory(&f); - - Implementation eventlist[] = { I_OnUserRegister, I_OnRehash, I_OnUserPostNick, I_OnStats, I_OnBackgroundTimer, I_OnUnloadModule }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual ~ModuleRLine() + ~ModuleRLine() { ServerInstance->XLines->DelAll("R"); ServerInstance->XLines->UnregisterFactory(&f); } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("RLINE: Regexp user banning.", VF_COMMON | VF_VENDOR, rxfactory ? rxfactory->name : ""); } - ModResult OnUserRegister(LocalUser* user) + ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE { // Apply lines on user connect XLine *rl = ServerInstance->XLines->MatchesLine("R", user); @@ -269,7 +254,7 @@ class ModuleRLine : public Module return MOD_RES_PASSTHRU; } - virtual void OnRehash(User *user) + void OnRehash(User *user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("rline"); @@ -302,7 +287,7 @@ class ModuleRLine : public Module initing = false; } - virtual ModResult OnStats(char symbol, User* user, string_list &results) + ModResult OnStats(char symbol, User* user, string_list &results) CXX11_OVERRIDE { if (symbol != 'R') return MOD_RES_PASSTHRU; @@ -311,7 +296,7 @@ class ModuleRLine : public Module return MOD_RES_DENY; } - virtual void OnUserPostNick(User *user, const std::string &oldnick) + void OnUserPostNick(User *user, const std::string &oldnick) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return; @@ -328,7 +313,7 @@ class ModuleRLine : public Module } } - virtual void OnBackgroundTimer(time_t curtime) + void OnBackgroundTimer(time_t curtime) CXX11_OVERRIDE { if (added_zline) { @@ -337,7 +322,7 @@ class ModuleRLine : public Module } } - void OnUnloadModule(Module* mod) + void OnUnloadModule(Module* mod) CXX11_OVERRIDE { // If the regex engine became unavailable or has changed, remove all rlines if (!rxfactory) diff --git a/src/modules/m_rmode.cpp b/src/modules/m_rmode.cpp new file mode 100644 index 000000000..542df70a5 --- /dev/null +++ b/src/modules/m_rmode.cpp @@ -0,0 +1,127 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Daniel Vassdal <shutter@canternet.org> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "inspircd.h" +#include "listmode.h" + +/** Handle /RMODE + */ +class CommandRMode : public Command +{ + public: + CommandRMode(Module* Creator) : Command(Creator,"RMODE", 2, 3) + { + allow_empty_last_param = false; + syntax = "<channel> <mode> [pattern]"; + } + + CmdResult Handle(const std::vector<std::string> ¶meters, User *user) + { + ModeHandler* mh; + Channel* chan = ServerInstance->FindChan(parameters[0]); + char modeletter = parameters[1][0]; + + if (chan == NULL) + { + user->WriteNotice("The channel " + parameters[0] + " does not exist."); + return CMD_FAILURE; + } + + mh = ServerInstance->Modes->FindMode(modeletter, MODETYPE_CHANNEL); + if (mh == NULL || parameters[1].size() > 1) + { + user->WriteNotice(parameters[1] + " is not a valid channel mode."); + return CMD_FAILURE; + } + + if (chan->GetPrefixValue(user) < mh->GetLevelRequired()) + { + user->WriteNotice("You do not have access to unset " + ConvToStr(modeletter) + " on " + chan->name + "."); + return CMD_FAILURE; + } + + unsigned int prefixrank; + char prefixchar; + std::string pattern = parameters.size() > 2 ? parameters[2] : "*"; + ListModeBase* lm; + ListModeBase::ModeList* ml; + irc::modestacker modestack(false); + + if (!mh->IsListMode()) + { + if (chan->IsModeSet(mh)) + modestack.Push(modeletter); + } + else if (((prefixrank = mh->GetPrefixRank()) && (prefixchar = mh->GetPrefix()))) + { + // As user prefix modes don't have a GetList() method, let's iterate through the channel's users. + for (UserMembIter it = chan->userlist.begin(); it != chan->userlist.end(); ++it) + { + if (!InspIRCd::Match(it->first->nick, pattern)) + continue; + if (((strchr(chan->GetAllPrefixChars(user), prefixchar)) != NULL) && !(it->first == user && prefixrank > VOICE_VALUE)) + modestack.Push(modeletter, it->first->nick); + } + } + else if (((lm = dynamic_cast<ListModeBase*>(mh)) != NULL) && ((ml = lm->GetList(chan)) != NULL)) + { + for (ListModeBase::ModeList::iterator it = ml->begin(); it != ml->end(); ++it) + { + if (!InspIRCd::Match(it->mask, pattern)) + continue; + modestack.Push(modeletter, it->mask); + } + } + else + { + user->WriteNotice("Could not remove channel mode " + ConvToStr(modeletter)); + return CMD_FAILURE; + } + + parameterlist stackresult; + stackresult.push_back(chan->name); + while (modestack.GetStackedLine(stackresult)) + { + ServerInstance->Modes->Process(stackresult, user); + stackresult.erase(stackresult.begin() + 1, stackresult.end()); + } + + return CMD_SUCCESS; + } +}; + +class ModuleRMode : public Module +{ + CommandRMode cmd; + + public: + ModuleRMode() : cmd(this) { } + + void init() CXX11_OVERRIDE + { + ServerInstance->Modules->AddService(cmd); + } + + Version GetVersion() CXX11_OVERRIDE + { + return Version("Allows glob-based removal of list modes", VF_VENDOR); + } +}; + +MODULE_INIT(ModuleRMode) diff --git a/src/modules/m_sajoin.cpp b/src/modules/m_sajoin.cpp index 932b564fa..9cc6a72d2 100644 --- a/src/modules/m_sajoin.cpp +++ b/src/modules/m_sajoin.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides command SAJOIN to allow opers to force-join users to channels */ - /** Handle /SAJOIN */ class CommandSajoin : public Command @@ -32,7 +30,7 @@ class CommandSajoin : public Command { allow_empty_last_param = false; flags_needed = 'o'; Penalty = 0; syntax = "<nick> <channel>"; - TRANSLATE3(TR_NICK, TR_TEXT, TR_END); + TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle (const std::vector<std::string>& parameters, User *user) @@ -45,22 +43,21 @@ class CommandSajoin : public Command user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Cannot use an SA command on a u-lined client",user->nick.c_str()); return CMD_FAILURE; } - if (IS_LOCAL(user) && !ServerInstance->IsChannel(parameters[1].c_str(), ServerInstance->Config->Limits.ChanMax)) + if (IS_LOCAL(user) && !ServerInstance->IsChannel(parameters[1])) { /* we didn't need to check this for each character ;) */ - user->WriteServ("NOTICE "+user->nick+" :*** Invalid characters in channel name or name too long"); + user->WriteNotice("*** Invalid characters in channel name or name too long"); return CMD_FAILURE; } - /* For local users, we send the JoinUser which may create a channel and set its TS. + /* For local users, we call Channel::JoinUser which may create a channel and set its TS. * For non-local users, we just return CMD_SUCCESS, knowing this will propagate it where it needs to be - * and then that server will generate the users JOIN or FJOIN instead. + * and then that server will handle the command. */ - if (IS_LOCAL(dest)) + LocalUser* localuser = IS_LOCAL(dest); + if (localuser) { - Channel::JoinUser(dest, parameters[1].c_str(), true, "", false, ServerInstance->Time()); - /* Fix for dotslasher and w00t - if the join didnt succeed, return CMD_FAILURE so that it doesnt propagate */ - Channel* n = ServerInstance->FindChan(parameters[1]); + Channel* n = Channel::JoinUser(localuser, parameters[1], true); if (n) { if (n->HasUser(dest)) @@ -70,13 +67,13 @@ class CommandSajoin : public Command } else { - user->WriteServ("NOTICE "+user->nick+" :*** Could not join "+dest->nick+" to "+parameters[1]+" (User is probably banned, or blocking modes)"); + user->WriteNotice("*** Could not join "+dest->nick+" to "+parameters[1]+" (User is probably banned, or blocking modes)"); return CMD_FAILURE; } } else { - user->WriteServ("NOTICE "+user->nick+" :*** Could not join "+dest->nick+" to "+parameters[1]); + user->WriteNotice("*** Could not join "+dest->nick+" to "+parameters[1]); return CMD_FAILURE; } } @@ -88,7 +85,7 @@ class CommandSajoin : public Command } else { - user->WriteServ("NOTICE "+user->nick+" :*** No such nickname "+parameters[0]); + user->WriteNotice("*** No such nickname "+parameters[0]); return CMD_FAILURE; } } @@ -111,20 +108,15 @@ class ModuleSajoin : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleSajoin() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides command SAJOIN to allow opers to force-join users to channels", VF_OPTCOMMON | VF_VENDOR); } - }; MODULE_INIT(ModuleSajoin) diff --git a/src/modules/m_sakick.cpp b/src/modules/m_sakick.cpp index 7dfcd8904..e7dd86d6f 100644 --- a/src/modules/m_sakick.cpp +++ b/src/modules/m_sakick.cpp @@ -20,8 +20,6 @@ #include "inspircd.h" -/* $ModDesc: Provides a SAKICK command */ - /** Handle /SAKICK */ class CommandSakick : public Command @@ -30,7 +28,7 @@ class CommandSakick : public Command CommandSakick(Module* Creator) : Command(Creator,"SAKICK", 2, 3) { flags_needed = 'o'; Penalty = 0; syntax = "<channel> <nick> [reason]"; - TRANSLATE4(TR_TEXT, TR_NICK, TR_TEXT, TR_END); + TRANSLATE3(TR_TEXT, TR_NICK, TR_TEXT); } CmdResult Handle (const std::vector<std::string>& parameters, User *user) @@ -68,7 +66,7 @@ class CommandSakick : public Command if (n && n->HasUser(dest)) { /* Sort-of-bug: If the command was issued remotely, this message won't be sent */ - user->WriteServ("NOTICE %s :*** Unable to kick %s from %s", user->nick.c_str(), dest->nick.c_str(), parameters[0].c_str()); + user->WriteNotice("*** Unable to kick " + dest->nick + " from " + parameters[0]); return CMD_FAILURE; } } @@ -83,7 +81,7 @@ class CommandSakick : public Command } else { - user->WriteServ("NOTICE %s :*** Invalid nickname or channel", user->nick.c_str()); + user->WriteNotice("*** Invalid nickname or channel"); } return CMD_FAILURE; @@ -107,21 +105,15 @@ class ModuleSakick : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleSakick() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides a SAKICK command", VF_OPTCOMMON|VF_VENDOR); } - }; MODULE_INIT(ModuleSakick) - diff --git a/src/modules/m_samode.cpp b/src/modules/m_samode.cpp index 9b71992a6..a549f89a7 100644 --- a/src/modules/m_samode.cpp +++ b/src/modules/m_samode.cpp @@ -20,8 +20,6 @@ */ -/* $ModDesc: Provides command SAMODE to allow opers to change modes on channels and users */ - #include "inspircd.h" /** Handle /SAMODE @@ -39,8 +37,14 @@ class CommandSamode : public Command CmdResult Handle (const std::vector<std::string>& parameters, User *user) { + User* target = ServerInstance->FindNick(parameters[0]); + if ((target) && (target != user)) + { + if (!user->HasPrivPermission("users/samode-usermodes", true)) + return CMD_FAILURE; + } this->active = true; - ServerInstance->Parser->CallHandler("MODE", parameters, user); + ServerInstance->Modes->Process(parameters, user); if (ServerInstance->Modes->GetLastParse().length()) ServerInstance->SNO->WriteGlobalSno('a', user->nick + " used SAMODE: " +ServerInstance->Modes->GetLastParse()); this->active = false; @@ -57,22 +61,17 @@ class ModuleSaMode : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); - ServerInstance->Modules->Attach(I_OnPreMode, this); - } - - ~ModuleSaMode() - { } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides command SAMODE to allow opers to change modes on channels and users", VF_VENDOR); } - ModResult OnPreMode(User* source,User* dest,Channel* channel, const std::vector<std::string>& parameters) + ModResult OnPreMode(User* source,User* dest,Channel* channel, const std::vector<std::string>& parameters) CXX11_OVERRIDE { if (cmd.active) return MOD_RES_ALLOW; diff --git a/src/modules/m_sanick.cpp b/src/modules/m_sanick.cpp index 4e4be77ae..82e8508dd 100644 --- a/src/modules/m_sanick.cpp +++ b/src/modules/m_sanick.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for SANICK command */ - /** Handle /SANICK */ class CommandSanick : public Command @@ -32,7 +30,7 @@ class CommandSanick : public Command { allow_empty_last_param = false; flags_needed = 'o'; Penalty = 0; syntax = "<nick> <new-nick>"; - TRANSLATE3(TR_NICK, TR_TEXT, TR_END); + TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle (const std::vector<std::string>& parameters, User *user) @@ -50,13 +48,13 @@ class CommandSanick : public Command if ((!target) || (target->registered != REG_ALL)) { - user->WriteServ("NOTICE %s :*** No such nickname: '%s'", user->nick.c_str(), parameters[0].c_str()); + user->WriteNotice("*** No such nickname: '" + parameters[0] + "'"); return CMD_FAILURE; } - if (!ServerInstance->IsNick(parameters[1].c_str(), ServerInstance->Config->Limits.NickMax)) + if (!ServerInstance->IsNick(parameters[1])) { - user->WriteServ("NOTICE %s :*** Invalid nickname '%s'", user->nick.c_str(), parameters[1].c_str()); + user->WriteNotice("*** Invalid nickname '" + parameters[1] + "'"); return CMD_FAILURE; } } @@ -98,20 +96,16 @@ class ModuleSanick : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleSanick() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for SANICK command", VF_OPTCOMMON | VF_VENDOR); } - }; MODULE_INIT(ModuleSanick) + diff --git a/src/modules/m_sapart.cpp b/src/modules/m_sapart.cpp index 89256e0e4..c6137c561 100644 --- a/src/modules/m_sapart.cpp +++ b/src/modules/m_sapart.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides command SAPART to force-part users from a channel. */ - /** Handle /SAPART */ class CommandSapart : public Command @@ -31,7 +29,7 @@ class CommandSapart : public Command CommandSapart(Module* Creator) : Command(Creator,"SAPART", 2, 3) { flags_needed = 'o'; Penalty = 0; syntax = "<nick> <channel> [reason]"; - TRANSLATE4(TR_NICK, TR_TEXT, TR_TEXT, TR_END); + TRANSLATE3(TR_NICK, TR_TEXT, TR_TEXT); } CmdResult Handle (const std::vector<std::string>& parameters, User *user) @@ -74,7 +72,7 @@ class CommandSapart : public Command } else { - user->WriteServ("NOTICE %s :*** Unable to make %s part %s",user->nick.c_str(), dest->nick.c_str(), parameters[1].c_str()); + user->WriteNotice("*** Unable to make " + dest->nick + " part " + parameters[1]); return CMD_FAILURE; } } @@ -84,7 +82,7 @@ class CommandSapart : public Command } else { - user->WriteServ("NOTICE %s :*** Invalid nickname or channel", user->nick.c_str()); + user->WriteNotice("*** Invalid nickname or channel"); } return CMD_FAILURE; @@ -109,21 +107,15 @@ class ModuleSapart : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleSapart() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides command SAPART to force-part users from a channel.", VF_OPTCOMMON | VF_VENDOR); } - }; MODULE_INIT(ModuleSapart) - diff --git a/src/modules/m_saquit.cpp b/src/modules/m_saquit.cpp index 3b7bdc824..8525a94fe 100644 --- a/src/modules/m_saquit.cpp +++ b/src/modules/m_saquit.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for an SAQUIT command, exits user with a reason */ - /** Handle /SAQUIT */ class CommandSaquit : public Command @@ -31,7 +29,7 @@ class CommandSaquit : public Command CommandSaquit(Module* Creator) : Command(Creator, "SAQUIT", 2, 2) { flags_needed = 'o'; Penalty = 0; syntax = "<nick> <reason>"; - TRANSLATE3(TR_NICK, TR_TEXT, TR_END); + TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle (const std::vector<std::string>& parameters, User *user) @@ -48,7 +46,7 @@ class CommandSaquit : public Command // Pass the command on, so the client's server can quit it properly. if (!IS_LOCAL(dest)) return CMD_SUCCESS; - + ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SAQUIT to make "+dest->nick+" quit with a reason of "+parameters[1]); ServerInstance->Users->QuitUser(dest, parameters[1]); @@ -56,7 +54,7 @@ class CommandSaquit : public Command } else { - user->WriteServ("NOTICE %s :*** Invalid nickname '%s'", user->nick.c_str(), parameters[0].c_str()); + user->WriteNotice("*** Invalid nickname '" + parameters[0] + "'"); return CMD_FAILURE; } } @@ -79,20 +77,16 @@ class ModuleSaquit : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleSaquit() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for an SAQUIT command, exits user with a reason", VF_OPTCOMMON | VF_VENDOR); } - }; MODULE_INIT(ModuleSaquit) + diff --git a/src/modules/m_sasl.cpp b/src/modules/m_sasl.cpp index b67111987..8b6d4ed85 100644 --- a/src/modules/m_sasl.cpp +++ b/src/modules/m_sasl.cpp @@ -19,12 +19,10 @@ #include "inspircd.h" -#include "m_cap.h" -#include "account.h" -#include "sasl.h" -#include "ssl.h" - -/* $ModDesc: Provides support for IRC Authentication Layer (aka: atheme SASL) via AUTHENTICATE. */ +#include "modules/cap.h" +#include "modules/account.h" +#include "modules/sasl.h" +#include "modules/ssl.h" enum SaslState { SASL_INIT, SASL_COMM, SASL_DONE }; enum SaslResult { SASL_OK, SASL_FAIL, SASL_ABORT }; @@ -63,10 +61,10 @@ class SaslAuthenticator params.push_back("S"); params.push_back(method); - if (method == "EXTERNAL" && IS_LOCAL(user_)) + LocalUser* localuser = IS_LOCAL(user); + if (method == "EXTERNAL" && localuser) { - SocketCertificateRequest req(&((LocalUser*)user_)->eh, ServerInstance->Modules->Find("m_sasl.so")); - std::string fp = req.GetFingerprint(); + std::string fp = SSLClientCert::GetFingerprint(&localuser->eh); if (fp.size()) params.push_back(fp); @@ -112,7 +110,7 @@ class SaslAuthenticator case SASL_DONE: break; default: - ServerInstance->Logs->Log("m_sasl", DEFAULT, "WTF: SaslState is not a known state (%d)", this->state); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WTF: SaslState is not a known state (%d)", this->state); break; } @@ -220,7 +218,7 @@ class CommandSASL : public Command User* target = ServerInstance->FindNick(parameters[1]); if ((!target) || (IS_SERVER(target))) { - ServerInstance->Logs->Log("m_sasl", DEBUG,"User not found in sasl ENCAP event: %s", parameters[1].c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User not found in sasl ENCAP event: %s", parameters[1].c_str()); return CMD_FAILURE; } @@ -249,31 +247,30 @@ class ModuleSASL : public Module GenericCap cap; CommandAuthenticate auth; CommandSASL sasl; + public: ModuleSASL() : authExt("sasl_auth", this), cap(this, "sasl"), auth(this, authExt, cap), sasl(this, authExt) { } - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); - Implementation eventlist[] = { I_OnEvent, I_OnUserRegister, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); ServiceProvider* providelist[] = { &auth, &sasl, &authExt }; ServerInstance->Modules->AddServices(providelist, 3); if (!ServerInstance->Modules->Find("m_services_account.so") || !ServerInstance->Modules->Find("m_cap.so")) - ServerInstance->Logs->Log("m_sasl", DEFAULT, "WARNING: m_services_account.so and m_cap.so are not loaded! m_sasl.so will NOT function correctly until these two modules are loaded!"); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: m_services_account.so and m_cap.so are not loaded! m_sasl.so will NOT function correctly until these two modules are loaded!"); } - void OnRehash(User*) + void OnRehash(User*) CXX11_OVERRIDE { sasl_target = ServerInstance->Config->ConfValue("sasl")->getString("target", "*"); } - ModResult OnUserRegister(LocalUser *user) + ModResult OnUserRegister(LocalUser *user) CXX11_OVERRIDE { SaslAuthenticator *sasl_ = authExt.get(user); if (sasl_) @@ -285,12 +282,12 @@ class ModuleSASL : public Module return MOD_RES_PASSTHRU; } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for IRC Authentication Layer (aka: atheme SASL) via AUTHENTICATE.",VF_VENDOR); } - void OnEvent(Event &ev) + void OnEvent(Event &ev) CXX11_OVERRIDE { cap.HandleEvent(ev); } diff --git a/src/modules/m_satopic.cpp b/src/modules/m_satopic.cpp index ae1c19d91..053f13789 100644 --- a/src/modules/m_satopic.cpp +++ b/src/modules/m_satopic.cpp @@ -17,8 +17,6 @@ */ -/* $ModDesc: Provides a SATOPIC command */ - #include "inspircd.h" /** Handle /SATOPIC @@ -40,10 +38,8 @@ class CommandSATopic : public Command if(target) { - std::string newTopic = parameters[1]; - - // 3rd parameter overrides access checks - target->SetTopic(user, newTopic, true); + const std::string& newTopic = parameters[1]; + target->SetTopic(user, newTopic); ServerInstance->SNO->WriteGlobalSno('a', user->nick + " used SATOPIC on " + target->name + ", new topic: " + newTopic); return CMD_SUCCESS; @@ -65,16 +61,12 @@ class ModuleSATopic : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleSATopic() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides a SATOPIC command", VF_VENDOR); } diff --git a/src/modules/m_securelist.cpp b/src/modules/m_securelist.cpp index 6013d1fd7..cfafd4f05 100644 --- a/src/modules/m_securelist.cpp +++ b/src/modules/m_securelist.cpp @@ -21,31 +21,23 @@ #include "inspircd.h" -/* $ModDesc: Disallows /LIST for recently connected clients to hinder spam bots */ - class ModuleSecureList : public Module { - private: std::vector<std::string> allowlist; time_t WaitTime; + public: - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); - Implementation eventlist[] = { I_OnRehash, I_OnPreCommand, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - virtual ~ModuleSecureList() - { } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Disallows /LIST for recently connected clients to hinder spam bots", VF_VENDOR); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { allowlist.clear(); @@ -61,13 +53,13 @@ class ModuleSecureList : public Module * OnPreCommand() * Intercept the LIST command. */ - virtual ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) + ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE { /* If the command doesnt appear to be valid, we dont want to mess with it. */ if (!validated) return MOD_RES_PASSTHRU; - if ((command == "LIST") && (ServerInstance->Time() < (user->signon+WaitTime)) && (!IS_OPER(user))) + if ((command == "LIST") && (ServerInstance->Time() < (user->signon+WaitTime)) && (!user->IsOper())) { /* Normally wouldnt be allowed here, are they exempt? */ for (std::vector<std::string>::iterator x = allowlist.begin(); x != allowlist.end(); x++) @@ -75,7 +67,7 @@ class ModuleSecureList : public Module return MOD_RES_PASSTHRU; /* Not exempt, BOOK EM DANNO! */ - user->WriteServ("NOTICE %s :*** You cannot list within the first %lu seconds of connecting. Please try again later.",user->nick.c_str(), (unsigned long) WaitTime); + user->WriteNotice("*** You cannot list within the first " + ConvToStr(WaitTime) + " seconds of connecting. Please try again later."); /* Some crap clients (read: mIRC, various java chat applets) muck up if they don't * receive these numerics whenever they send LIST, so give them an empty LIST to mull over. */ @@ -86,9 +78,9 @@ class ModuleSecureList : public Module return MOD_RES_PASSTHRU; } - virtual void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - output.append(" SECURELIST"); + tokens["SECURELIST"]; } }; diff --git a/src/modules/m_seenicks.cpp b/src/modules/m_seenicks.cpp index 95872b5b2..bff3516f1 100644 --- a/src/modules/m_seenicks.cpp +++ b/src/modules/m_seenicks.cpp @@ -21,24 +21,20 @@ #include "inspircd.h" -/* $ModDesc: Provides support for seeing local and remote nickchanges via snomasks 'n' and 'N'. */ - class ModuleSeeNicks : public Module { public: - void init() + void init() CXX11_OVERRIDE { ServerInstance->SNO->EnableSnomask('n',"NICK"); - Implementation eventlist[] = { I_OnUserPostNick }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for seeing local and remote nickchanges via snomasks", VF_VENDOR); } - virtual void OnUserPostNick(User* user, const std::string &oldnick) + void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE { ServerInstance->SNO->WriteToSnoMask(IS_LOCAL(user) ? 'n' : 'N',"User %s changed their nickname to %s", oldnick.c_str(), user->nick.c_str()); } diff --git a/src/modules/m_serverban.cpp b/src/modules/m_serverban.cpp index cf77ae9ba..87fe08670 100644 --- a/src/modules/m_serverban.cpp +++ b/src/modules/m_serverban.cpp @@ -19,28 +19,15 @@ #include "inspircd.h" -/* $ModDesc: Implements extban +b s: - server name bans */ - class ModuleServerBan : public Module { - private: public: - void init() - { - Implementation eventlist[] = { I_OnCheckBan, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - ~ModuleServerBan() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Extban 's' - server ban",VF_OPTCOMMON|VF_VENDOR); } - ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) + ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) CXX11_OVERRIDE { if ((mask.length() > 2) && (mask[0] == 's') && (mask[1] == ':')) { @@ -50,12 +37,10 @@ class ModuleServerBan : public Module return MOD_RES_PASSTHRU; } - void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - ServerInstance->AddExtBanChar('s'); + tokens["EXTBAN"].push_back('s'); } }; - MODULE_INIT(ModuleServerBan) - diff --git a/src/modules/m_services_account.cpp b/src/modules/m_services_account.cpp index cb3f089c6..4f2125a97 100644 --- a/src/modules/m_services_account.cpp +++ b/src/modules/m_services_account.cpp @@ -22,10 +22,8 @@ */ -/* $ModDesc: Provides support for ircu-style services accounts, including chmode +R, etc. */ - #include "inspircd.h" -#include "account.h" +#include "modules/account.h" /** Channel mode +r - mark a channel as identified */ @@ -40,9 +38,9 @@ class Channel_r : public ModeHandler if (!IS_LOCAL(source)) { // Only change the mode if it's not redundant - if ((adding != channel->IsModeSet('r'))) + if ((adding != channel->IsModeSet(this))) { - channel->SetMode('r',adding); + channel->SetMode(this, adding); return MODEACTION_ALLOW; } } @@ -66,9 +64,9 @@ class User_r : public ModeHandler { if (!IS_LOCAL(source)) { - if ((adding != dest->IsModeSet('r'))) + if ((adding != dest->IsModeSet(this))) { - dest->SetMode('r',adding); + dest->SetMode(this, adding); return MODEACTION_ALLOW; } } @@ -118,24 +116,20 @@ class ModuleServicesAccount : public Module { } - void init() + void init() CXX11_OVERRIDE { ServiceProvider* providerlist[] = { &m1, &m2, &m3, &m4, &m5, &accountname }; ServerInstance->Modules->AddServices(providerlist, sizeof(providerlist)/sizeof(ServiceProvider*)); - Implementation eventlist[] = { I_OnWhois, I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserPreJoin, I_OnCheckBan, - I_OnDecodeMetaData, I_On005Numeric, I_OnUserPostNick, I_OnSetConnectClass }; - - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - void On005Numeric(std::string &t) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - ServerInstance->AddExtBanChar('R'); - ServerInstance->AddExtBanChar('U'); + tokens["EXTBAN"].push_back('R'); + tokens["EXTBAN"].push_back('U'); } /* <- :twisted.oscnet.org 330 w00t2 w00t2 w00t :is logged in as */ - void OnWhois(User* source, User* dest) + void OnWhois(User* source, User* dest) CXX11_OVERRIDE { std::string *account = accountname.get(dest); @@ -144,26 +138,26 @@ class ModuleServicesAccount : public Module ServerInstance->SendWhoisLine(source, dest, 330, "%s %s %s :is logged in as", source->nick.c_str(), dest->nick.c_str(), account->c_str()); } - if (dest->IsModeSet('r')) + if (dest->IsModeSet(m5)) { /* user is registered */ ServerInstance->SendWhoisLine(source, dest, 307, "%s %s :is a registered nick", source->nick.c_str(), dest->nick.c_str()); } } - void OnUserPostNick(User* user, const std::string &oldnick) + void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE { /* On nickchange, if they have +r, remove it */ - if (user->IsModeSet('r') && assign(user->nick) != oldnick) + if (user->IsModeSet(m5) && assign(user->nick) != oldnick) { std::vector<std::string> modechange; modechange.push_back(user->nick); modechange.push_back("-r"); - ServerInstance->SendMode(modechange, ServerInstance->FakeClient); + ServerInstance->Modes->Process(modechange, ServerInstance->FakeClient, ModeParser::MODE_LOCALONLY); } } - ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; @@ -176,7 +170,7 @@ class ModuleServicesAccount : public Module Channel* c = (Channel*)dest; ModResult res = ServerInstance->OnCheckExemption(user,c,"regmoderated"); - if (c->IsModeSet('M') && !is_registered && res != MOD_RES_ALLOW) + if (c->IsModeSet(m2) && !is_registered && res != MOD_RES_ALLOW) { // user messaging a +M channel and is not registered user->WriteNumeric(477, user->nick+" "+c->name+" :You need to be identified to a registered account to message this channel"); @@ -187,7 +181,7 @@ class ModuleServicesAccount : public Module { User* u = (User*)dest; - if (u->IsModeSet('R') && !is_registered) + if (u->IsModeSet(m3) && !is_registered) { // user messaging a +R user and is not registered user->WriteNumeric(477, ""+ user->nick +" "+ u->nick +" :You need to be identified to a registered account to message this user"); @@ -197,7 +191,7 @@ class ModuleServicesAccount : public Module return MOD_RES_PASSTHRU; } - ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask) + ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask) CXX11_OVERRIDE { static bool checking = false; if (checking) @@ -234,22 +228,14 @@ class ModuleServicesAccount : public Module return MOD_RES_PASSTHRU; } - ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreMessage(user, dest, target_type, text, status, exempt_list); - } - - ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven) + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { - if (!IS_LOCAL(user)) - return MOD_RES_PASSTHRU; - std::string *account = accountname.get(user); bool is_registered = account && !account->empty(); if (chan) { - if (chan->IsModeSet('R')) + if (chan->IsModeSet(m1)) { if (!is_registered) { @@ -269,7 +255,7 @@ class ModuleServicesAccount : public Module // In our case we're only sending a single string around, so we just construct a std::string. // Some modules will probably get much more complex and format more detailed structs and classes // in a textual way for sending over the link. - void OnDecodeMetaData(Extensible* target, const std::string &extname, const std::string &extdata) + void OnDecodeMetaData(Extensible* target, const std::string &extname, const std::string &extdata) CXX11_OVERRIDE { User* dest = dynamic_cast<User*>(target); // check if its our metadata key, and its associated with a user @@ -293,17 +279,18 @@ class ModuleServicesAccount : public Module } } - ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) + ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE { if (myclass->config->getBool("requireaccount") && !accountname.get(user)) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for ircu-style services accounts, including chmode +R, etc.",VF_OPTCOMMON|VF_VENDOR); } }; MODULE_INIT(ModuleServicesAccount) + diff --git a/src/modules/m_servprotect.cpp b/src/modules/m_servprotect.cpp index b4f2b5bbd..2b550408c 100644 --- a/src/modules/m_servprotect.cpp +++ b/src/modules/m_servprotect.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides usermode +k to protect services from kicks, kills and mode changes. */ - /** Handles user mode +k */ class ServProtectMode : public ModeHandler @@ -53,32 +51,25 @@ class ModuleServProtectMode : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(bm); - Implementation eventlist[] = { I_OnWhois, I_OnKill, I_OnWhoisLine, I_OnRawMode, I_OnUserPreKick }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - - ~ModuleServProtectMode() - { } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides usermode +k to protect services from kicks, kills, and mode changes.", VF_VENDOR); } - void OnWhois(User* src, User* dst) + void OnWhois(User* user, User* dest) CXX11_OVERRIDE { - if (dst->IsModeSet('k')) + if (dest->IsModeSet(bm)) { - ServerInstance->SendWhoisLine(src, dst, 310, src->nick+" "+dst->nick+" :is an "+ServerInstance->Config->Network+" Service"); + ServerInstance->SendWhoisLine(user, dest, 310, user->nick+" "+dest->nick+" :is a Network Service on "+ServerInstance->Config->Network); } } - ModResult OnRawMode(User* user, Channel* chan, const char mode, const std::string ¶m, bool adding, int pcnt) + ModResult OnRawMode(User* user, Channel* chan, const char mode, const std::string ¶m, bool adding, int pcnt) CXX11_OVERRIDE { /* Check that the mode is not a server mode, it is being removed, the user making the change is local, there is a parameter, * and the user making the change is not a uline @@ -95,7 +86,7 @@ class ModuleServProtectMode : public Module * This includes any prefix permission mode, even those registered in other modules, e.g. +qaohv. Using ::ModeString() * here means that the number of modes is restricted to only modes the user has, limiting it to as short a loop as possible. */ - if (u->IsModeSet('k') && memb && memb->modes.find(mode) != std::string::npos) + if (u->IsModeSet(bm) && memb && memb->modes.find(mode) != std::string::npos) { /* BZZZT, Denied! */ user->WriteNumeric(482, "%s %s :You are not permitted to remove privileges from %s services", user->nick.c_str(), chan->name.c_str(), ServerInstance->Config->Network.c_str()); @@ -107,12 +98,12 @@ class ModuleServProtectMode : public Module return MOD_RES_PASSTHRU; } - ModResult OnKill(User* src, User* dst, const std::string &reason) + ModResult OnKill(User* src, User* dst, const std::string &reason) CXX11_OVERRIDE { if (src == NULL) return MOD_RES_PASSTHRU; - if (dst->IsModeSet('k')) + if (dst->IsModeSet(bm)) { src->WriteNumeric(485, "%s :You are not permitted to kill %s services!", src->nick.c_str(), ServerInstance->Config->Network.c_str()); ServerInstance->SNO->WriteGlobalSno('a', src->nick+" tried to kill service "+dst->nick+" ("+reason+")"); @@ -121,9 +112,9 @@ class ModuleServProtectMode : public Module return MOD_RES_PASSTHRU; } - ModResult OnUserPreKick(User *src, Membership* memb, const std::string &reason) + ModResult OnUserPreKick(User *src, Membership* memb, const std::string &reason) CXX11_OVERRIDE { - if (memb->user->IsModeSet('k')) + if (memb->user->IsModeSet(bm)) { src->WriteNumeric(484, "%s %s :You are not permitted to kick services", src->nick.c_str(), memb->chan->name.c_str()); @@ -133,9 +124,9 @@ class ModuleServProtectMode : public Module return MOD_RES_PASSTHRU; } - ModResult OnWhoisLine(User* src, User* dst, int &numeric, std::string &text) + ModResult OnWhoisLine(User* src, User* dst, int &numeric, std::string &text) CXX11_OVERRIDE { - return ((src != dst) && (numeric == 319) && dst->IsModeSet('k')) ? MOD_RES_DENY : MOD_RES_PASSTHRU; + return ((src != dst) && (numeric == 319) && dst->IsModeSet(bm)) ? MOD_RES_DENY : MOD_RES_PASSTHRU; } }; diff --git a/src/modules/m_sethost.cpp b/src/modules/m_sethost.cpp index 2ef0c0548..fb9fd7f1f 100644 --- a/src/modules/m_sethost.cpp +++ b/src/modules/m_sethost.cpp @@ -21,20 +21,17 @@ #include "inspircd.h" -/* $ModDesc: Provides support for the SETHOST command */ - /** Handle /SETHOST */ class CommandSethost : public Command { - private: char* hostmap; + public: CommandSethost(Module* Creator, char* hmap) : Command(Creator,"SETHOST", 1), hostmap(hmap) { allow_empty_last_param = false; flags_needed = 'o'; syntax = "<new-hostname>"; - TRANSLATE2(TR_TEXT, TR_END); } CmdResult Handle (const std::vector<std::string>& parameters, User *user) @@ -44,18 +41,18 @@ class CommandSethost : public Command { if (!hostmap[(const unsigned char)*x]) { - user->WriteServ("NOTICE "+user->nick+" :*** SETHOST: Invalid characters in hostname"); + user->WriteNotice("*** SETHOST: Invalid characters in hostname"); return CMD_FAILURE; } } if (len > 64) { - user->WriteServ("NOTICE %s :*** SETHOST: Host too long",user->nick.c_str()); + user->WriteNotice("*** SETHOST: Host too long"); return CMD_FAILURE; } - if (user->ChangeDisplayedHost(parameters[0].c_str())) + if (user->ChangeDisplayedHost(parameters[0])) { ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SETHOST to change their displayed host to "+user->dhost); return CMD_SUCCESS; @@ -70,21 +67,20 @@ class ModuleSetHost : public Module { CommandSethost cmd; char hostmap[256]; + public: ModuleSetHost() : cmd(this, hostmap) { } - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); ServerInstance->Modules->AddService(cmd); - Implementation eventlist[] = { I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { std::string hmap = ServerInstance->Config->ConfValue("hostname")->getString("charmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789"); @@ -93,15 +89,10 @@ class ModuleSetHost : public Module hostmap[(unsigned char)*n] = 1; } - virtual ~ModuleSetHost() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for the SETHOST command", VF_VENDOR); } - }; MODULE_INIT(ModuleSetHost) diff --git a/src/modules/m_setident.cpp b/src/modules/m_setident.cpp index f63be1381..024421347 100644 --- a/src/modules/m_setident.cpp +++ b/src/modules/m_setident.cpp @@ -22,8 +22,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for the SETIDENT command */ - /** Handle /SETIDENT */ class CommandSetident : public Command @@ -33,31 +31,29 @@ class CommandSetident : public Command { allow_empty_last_param = false; flags_needed = 'o'; syntax = "<new-ident>"; - TRANSLATE2(TR_TEXT, TR_END); } CmdResult Handle(const std::vector<std::string>& parameters, User *user) { if (parameters[0].size() > ServerInstance->Config->Limits.IdentMax) { - user->WriteServ("NOTICE %s :*** SETIDENT: Ident is too long", user->nick.c_str()); + user->WriteNotice("*** SETIDENT: Ident is too long"); return CMD_FAILURE; } - if (!ServerInstance->IsIdent(parameters[0].c_str())) + if (!ServerInstance->IsIdent(parameters[0])) { - user->WriteServ("NOTICE %s :*** SETIDENT: Invalid characters in ident", user->nick.c_str()); + user->WriteNotice("*** SETIDENT: Invalid characters in ident"); return CMD_FAILURE; } - user->ChangeIdent(parameters[0].c_str()); + user->ChangeIdent(parameters[0]); ServerInstance->SNO->WriteGlobalSno('a', "%s used SETIDENT to change their ident to '%s'", user->nick.c_str(), user->ident.c_str()); return CMD_SUCCESS; } }; - class ModuleSetIdent : public Module { CommandSetident cmd; @@ -67,21 +63,15 @@ class ModuleSetIdent : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleSetIdent() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for the SETIDENT command", VF_VENDOR); } - }; - MODULE_INIT(ModuleSetIdent) diff --git a/src/modules/m_setidle.cpp b/src/modules/m_setidle.cpp index fdb29d14f..e246b801f 100644 --- a/src/modules/m_setidle.cpp +++ b/src/modules/m_setidle.cpp @@ -21,22 +21,19 @@ #include "inspircd.h" -/* $ModDesc: Allows opers to set their idle time */ - /** Handle /SETIDLE */ -class CommandSetidle : public Command +class CommandSetidle : public SplitCommand { public: - CommandSetidle(Module* Creator) : Command(Creator,"SETIDLE", 1) + CommandSetidle(Module* Creator) : SplitCommand(Creator,"SETIDLE", 1) { flags_needed = 'o'; syntax = "<duration>"; - TRANSLATE2(TR_TEXT, TR_END); } - CmdResult Handle (const std::vector<std::string>& parameters, User *user) + CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user) { - time_t idle = ServerInstance->Duration(parameters[0]); + int idle = InspIRCd::Duration(parameters[0]); if (idle < 1) { user->WriteNumeric(948, "%s :Invalid idle time.",user->nick.c_str()); @@ -63,16 +60,12 @@ class ModuleSetIdle : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleSetIdle() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Allows opers to set their idle time", VF_VENDOR); } diff --git a/src/modules/m_setname.cpp b/src/modules/m_setname.cpp index d0610853b..4c9d6ae53 100644 --- a/src/modules/m_setname.cpp +++ b/src/modules/m_setname.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for the SETNAME command */ - class CommandSetname : public Command @@ -32,18 +30,17 @@ class CommandSetname : public Command { allow_empty_last_param = false; syntax = "<new-gecos>"; - TRANSLATE2(TR_TEXT, TR_END); } CmdResult Handle (const std::vector<std::string>& parameters, User *user) { if (parameters[0].size() > ServerInstance->Config->Limits.MaxGecos) { - user->WriteServ("NOTICE %s :*** SETNAME: GECOS too long", user->nick.c_str()); + user->WriteNotice("*** SETNAME: GECOS too long"); return CMD_FAILURE; } - if (user->ChangeName(parameters[0].c_str())) + if (user->ChangeName(parameters[0])) { ServerInstance->SNO->WriteGlobalSno('a', "%s used SETNAME to change their GECOS to '%s'", user->nick.c_str(), parameters[0].c_str()); } @@ -62,16 +59,12 @@ class ModuleSetName : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleSetName() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for the SETNAME command", VF_VENDOR); } diff --git a/src/modules/m_sha256.cpp b/src/modules/m_sha256.cpp index 86970968a..82ac8c160 100644 --- a/src/modules/m_sha256.cpp +++ b/src/modules/m_sha256.cpp @@ -56,17 +56,8 @@ * SUCH DAMAGE. */ -/* $ModDesc: Allows for SHA-256 encrypted oper passwords */ - #include "inspircd.h" -#ifdef HAS_STDINT -#include <stdint.h> -#endif -#include "hash.h" - -#ifndef HAS_STDINT -typedef unsigned int uint32_t; -#endif +#include "modules/hash.h" #define SHA256_DIGEST_SIZE (256 / 8) #define SHA256_BLOCK_SIZE (512 / 8) @@ -263,11 +254,6 @@ class HashSHA256 : public HashProvider return std::string((char*)bytes, SHA256_DIGEST_SIZE); } - std::string sumIV(unsigned int* IV, const char* HexMap, const std::string &sdata) - { - return ""; - } - HashSHA256(Module* parent) : HashProvider(parent, "hash/sha256", 32, 64) {} }; @@ -280,7 +266,7 @@ class ModuleSHA256 : public Module ServerInstance->Modules->AddService(sha); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Implements SHA-256 hashing", VF_VENDOR); } diff --git a/src/modules/m_showwhois.cpp b/src/modules/m_showwhois.cpp index 434d1b07f..bf3028c12 100644 --- a/src/modules/m_showwhois.cpp +++ b/src/modules/m_showwhois.cpp @@ -23,8 +23,6 @@ #include "inspircd.h" -/* $ModDesc: Allows opers to set +W to see when a user uses WHOIS on them */ - /** Handle user mode +W */ class SeeWhois : public SimpleUserModeHandler @@ -46,9 +44,9 @@ class WhoisNoticeCmd : public Command void HandleFast(User* dest, User* src) { - dest->WriteServ("NOTICE %s :*** %s (%s@%s) did a /whois on you", - dest->nick.c_str(), src->nick.c_str(), src->ident.c_str(), - dest->HasPrivPermission("users/auspex") ? src->host.c_str() : src->dhost.c_str()); + dest->WriteNotice("*** " + src->nick + " (" + src->ident + "@" + + (dest->HasPrivPermission("users/auspex") ? src->host : src->dhost) + + ") did a /whois on you"); } CmdResult Handle(const std::vector<std::string> ¶meters, User *user) @@ -79,7 +77,7 @@ class ModuleShowwhois : public Module { } - void init() + void init() CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("showwhois"); @@ -89,8 +87,6 @@ class ModuleShowwhois : public Module sw = new SeeWhois(this, OpersOnly); ServerInstance->Modules->AddService(*sw); ServerInstance->Modules->AddService(cmd); - Implementation eventlist[] = { I_OnWhois }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } ~ModuleShowwhois() @@ -98,17 +94,17 @@ class ModuleShowwhois : public Module delete sw; } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Allows opers to set +W to see when a user uses WHOIS on them",VF_OPTCOMMON|VF_VENDOR); } - void OnWhois(User* source, User* dest) + void OnWhois(User* source, User* dest) CXX11_OVERRIDE { - if (!dest->IsModeSet('W') || source == dest) + if (!dest->IsModeSet(*sw) || source == dest) return; - if (!ShowWhoisFromOpers && IS_OPER(source)) + if (!ShowWhoisFromOpers && source->IsOper()) return; if (IS_LOCAL(dest)) @@ -125,7 +121,7 @@ class ModuleShowwhois : public Module ServerInstance->PI->SendEncapsulatedData(params); } } - }; MODULE_INIT(ModuleShowwhois) + diff --git a/src/modules/m_shun.cpp b/src/modules/m_shun.cpp index 8bf4d30e7..dbc1812c7 100644 --- a/src/modules/m_shun.cpp +++ b/src/modules/m_shun.cpp @@ -23,8 +23,6 @@ #include "inspircd.h" #include "xline.h" -/* $ModDesc: Provides the /SHUN command, which stops a user from executing all except configured commands. */ - class Shun : public XLine { public: @@ -36,14 +34,11 @@ public: { } - ~Shun() - { - } - bool Matches(User *u) { // E: overrides shun - if (u->exempt) + LocalUser* lu = IS_LOCAL(u); + if (lu && lu->exempt) return false; if (InspIRCd::Match(u->GetFullHost(), matchtext) || InspIRCd::Match(u->GetFullRealHost(), matchtext) || InspIRCd::Match(u->nick+"!"+u->ident+"@"+u->GetIPString(), matchtext)) @@ -59,15 +54,9 @@ public: return false; } - void DisplayExpiry() + const std::string& Displayable() { - ServerInstance->SNO->WriteToSnoMask('x',"Removing expired shun %s (set by %s %ld seconds ago)", - this->matchtext.c_str(), this->source.c_str(), (long int)(ServerInstance->Time() - this->set_time)); - } - - const char* Displayable() - { - return matchtext.c_str(); + return matchtext; } }; @@ -107,7 +96,7 @@ class CommandShun : public Command /* 'time' is a human-readable timestring, like 2d3h2s. */ std::string target = parameters[0]; - + User *find = ServerInstance->FindNick(target); if ((find) && (find->registered == REG_ALL)) target = std::string("*!*@") + find->GetIPString(); @@ -120,18 +109,18 @@ class CommandShun : public Command } else { - user->WriteServ("NOTICE %s :*** Shun %s not found in list, try /stats H.",user->nick.c_str(),target.c_str()); + user->WriteNotice("*** Shun " + target + " not found in list, try /stats H."); return CMD_FAILURE; } } else { // Adding - XXX todo make this respect <insane> tag perhaps.. - long duration; + unsigned long duration; std::string expr; if (parameters.size() > 2) { - duration = ServerInstance->Duration(parameters[1]); + duration = InspIRCd::Duration(parameters[1]); expr = parameters[2]; } else @@ -159,7 +148,7 @@ class CommandShun : public Command else { delete r; - user->WriteServ("NOTICE %s :*** Shun for %s already exists", user->nick.c_str(), target.c_str()); + user->WriteNotice("*** Shun for " + target + " already exists"); return CMD_FAILURE; } } @@ -188,17 +177,15 @@ class ModuleShun : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->XLines->RegisterFactory(&f); ServerInstance->Modules->AddService(cmd); - Implementation eventlist[] = { I_OnStats, I_OnPreCommand, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); } - virtual ~ModuleShun() + ~ModuleShun() { ServerInstance->XLines->DelAll("SHUN"); ServerInstance->XLines->UnregisterFactory(&f); @@ -210,7 +197,7 @@ class ModuleShun : public Module ServerInstance->Modules->SetPriority(this, I_OnPreCommand, PRIORITY_BEFORE, &alias); } - virtual ModResult OnStats(char symbol, User* user, string_list& out) + ModResult OnStats(char symbol, User* user, string_list& out) CXX11_OVERRIDE { if (symbol != 'H') return MOD_RES_PASSTHRU; @@ -219,7 +206,7 @@ class ModuleShun : public Module return MOD_RES_DENY; } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("shun"); std::string cmds = tag->getString("enabledcommands"); @@ -242,7 +229,7 @@ class ModuleShun : public Module affectopers = tag->getBool("affectopers", false); } - virtual ModResult OnPreCommand(std::string &command, std::vector<std::string>& parameters, LocalUser* user, bool validated, const std::string &original_line) + ModResult OnPreCommand(std::string &command, std::vector<std::string>& parameters, LocalUser* user, bool validated, const std::string &original_line) CXX11_OVERRIDE { if (validated) return MOD_RES_PASSTHRU; @@ -253,7 +240,7 @@ class ModuleShun : public Module return MOD_RES_PASSTHRU; } - if (!affectopers && IS_OPER(user)) + if (!affectopers && user->IsOper()) { /* Don't do anything if the user is an operator and affectopers isn't set */ return MOD_RES_PASSTHRU; @@ -264,7 +251,7 @@ class ModuleShun : public Module if (i == ShunEnabledCommands.end()) { if (NotifyOfShun) - user->WriteServ("NOTICE %s :*** Command %s not processed, as you have been blocked from issuing commands (SHUN)", user->nick.c_str(), command.c_str()); + user->WriteNotice("*** Command " + command + " not processed, as you have been blocked from issuing commands (SHUN)"); return MOD_RES_DENY; } @@ -283,11 +270,10 @@ class ModuleShun : public Module return MOD_RES_PASSTHRU; } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides the /SHUN command, which stops a user from executing all except configured commands.",VF_VENDOR|VF_COMMON); } }; MODULE_INIT(ModuleShun) - diff --git a/src/modules/m_silence.cpp b/src/modules/m_silence.cpp index 817c8ffcf..b6cb897e7 100644 --- a/src/modules/m_silence.cpp +++ b/src/modules/m_silence.cpp @@ -23,8 +23,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for the /SILENCE command */ - /* Improved drop-in replacement for the /SILENCE command * syntax: /SILENCE [+|-]<mask> <p|c|i|n|t|a|x> as in <privatemessage|channelmessage|invites|privatenotice|channelnotice|all|exclude> * @@ -66,7 +64,7 @@ class CommandSVSSilence : public Command CommandSVSSilence(Module* Creator) : Command(Creator,"SVSSILENCE", 2) { syntax = "<target> {[+|-]<mask> <p|c|i|n|t|a|x>}"; - TRANSLATE4(TR_NICK, TR_TEXT, TR_TEXT, TR_END); /* we watch for a nick. not a UID. */ + TRANSLATE3(TR_NICK, TR_TEXT, TR_TEXT); } CmdResult Handle (const std::vector<std::string>& parameters, User *user) @@ -112,7 +110,6 @@ class CommandSilence : public Command { allow_empty_last_param = false; syntax = "{[+|-]<mask> <p|c|i|n|t|a|x>}"; - TRANSLATE3(TR_TEXT, TR_TEXT, TR_END); } CmdResult Handle (const std::vector<std::string>& parameters, User *user) @@ -149,7 +146,7 @@ class CommandSilence : public Command if (pattern == 0) { - user->WriteServ("NOTICE %s :Bad SILENCE pattern",user->nick.c_str()); + user->WriteNotice("Bad SILENCE pattern"); return CMD_INVALID; } @@ -302,28 +299,25 @@ class ModuleSilence : public Module { } - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); ServerInstance->Modules->AddService(cmdsilence); ServerInstance->Modules->AddService(cmdsvssilence); ServerInstance->Modules->AddService(cmdsilence.ext); - - Implementation eventlist[] = { I_OnRehash, I_On005Numeric, I_OnUserPreNotice, I_OnUserPreMessage, I_OnUserPreInvite }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { maxsilence = ServerInstance->Config->ConfValue("showwhois")->getInt("maxentries", 32); if (!maxsilence) maxsilence = 32; } - void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - // we don't really have a limit... - output = output + " ESILENCE SILENCE=" + ConvToStr(maxsilence); + tokens["ESILENCE"]; + tokens["SILENCE"] = ConvToStr(maxsilence); } void OnBuildExemptList(MessageType message_type, Channel* chan, User* sender, char status, CUList &exempt_list, const std::string &text) @@ -343,34 +337,24 @@ class ModuleSilence : public Module } } - ModResult PreText(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list, int silence_type) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { if (target_type == TYPE_USER && IS_LOCAL(((User*)dest))) { - return MatchPattern((User*)dest, user, silence_type); + return MatchPattern((User*)dest, user, ((msgtype == MSG_PRIVMSG) ? SILENCE_PRIVATE : SILENCE_NOTICE)); } else if (target_type == TYPE_CHANNEL) { Channel* chan = (Channel*)dest; if (chan) { - this->OnBuildExemptList((silence_type == SILENCE_PRIVATE ? MSG_PRIVMSG : MSG_NOTICE), chan, user, status, exempt_list, ""); + this->OnBuildExemptList(msgtype, chan, user, status, exempt_list, ""); } } return MOD_RES_PASSTHRU; } - ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_PRIVATE); - } - - ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_NOTICE); - } - - ModResult OnUserPreInvite(User* source,User* dest,Channel* channel, time_t timeout) + ModResult OnUserPreInvite(User* source,User* dest,Channel* channel, time_t timeout) CXX11_OVERRIDE { return MatchPattern(dest, source, SILENCE_INVITE); } @@ -393,11 +377,7 @@ class ModuleSilence : public Module return MOD_RES_PASSTHRU; } - ~ModuleSilence() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for the /SILENCE command", VF_OPTCOMMON | VF_VENDOR); } diff --git a/src/modules/m_spanningtree/addline.cpp b/src/modules/m_spanningtree/addline.cpp index 7ee1a7ef1..d06317674 100644 --- a/src/modules/m_spanningtree/addline.cpp +++ b/src/modules/m_spanningtree/addline.cpp @@ -20,51 +20,32 @@ #include "inspircd.h" #include "xline.h" -#include "treesocket.h" #include "treeserver.h" #include "utils.h" +#include "commands.h" -/* $ModDep: m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */ - -bool TreeSocket::AddLine(const std::string &prefix, parameterlist ¶ms) +CmdResult CommandAddLine::Handle(User* usr, std::vector<std::string>& params) { - if (params.size() < 6) - { - std::string servername = MyRoot->GetName(); - ServerInstance->SNO->WriteToSnoMask('d', "%s sent me a malformed ADDLINE", servername.c_str()); - return true; - } - XLineFactory* xlf = ServerInstance->XLines->GetFactory(params[0]); - - std::string setter = "<unknown>"; - User* usr = ServerInstance->FindNick(prefix); - if (usr) - setter = usr->nick; - else - { - TreeServer* t = Utils->FindServer(prefix); - if (t) - setter = t->GetName(); - } + const std::string& setter = usr->nick; if (!xlf) { ServerInstance->SNO->WriteToSnoMask('d',"%s sent me an unknown ADDLINE type (%s).",setter.c_str(),params[0].c_str()); - return true; + return CMD_FAILURE; } XLine* xl = NULL; try { - xl = xlf->Generate(ServerInstance->Time(), atoi(params[4].c_str()), params[2], params[5], params[1]); + xl = xlf->Generate(ServerInstance->Time(), ConvToInt(params[4]), params[2], params[5], params[1]); } catch (ModuleException &e) { ServerInstance->SNO->WriteToSnoMask('d',"Unable to ADDLINE type %s from %s: %s", params[0].c_str(), setter.c_str(), e.GetReason()); - return true; + return CMD_FAILURE; } - xl->SetCreateTime(atoi(params[3].c_str())); + xl->SetCreateTime(ConvToInt(params[3])); if (ServerInstance->XLines->AddLine(xl, NULL)) { if (xl->duration) @@ -78,20 +59,29 @@ bool TreeSocket::AddLine(const std::string &prefix, parameterlist ¶ms) ServerInstance->SNO->WriteToSnoMask('X',"%s added permanent %s%s on %s: %s",setter.c_str(),params[0].c_str(),params[0].length() == 1 ? "-line" : "", params[1].c_str(),params[5].c_str()); } - params[5] = ":" + params[5]; - User* u = ServerInstance->FindNick(prefix); - Utils->DoOneToAllButSender(prefix, "ADDLINE", params, u ? u->server : prefix); - TreeServer *remoteserver = Utils->FindServer(u ? u->server : prefix); + TreeServer* remoteserver = Utils->FindServer(usr->server); if (!remoteserver->bursting) { ServerInstance->XLines->ApplyLines(); } + return CMD_SUCCESS; } else + { delete xl; - - return true; + return CMD_FAILURE; + } } +CommandAddLine::Builder::Builder(XLine* xline, User* user) + : CmdBuilder(user, "ADDLINE") +{ + push(xline->type); + push(xline->Displayable()); + push(xline->source); + push_int(xline->set_time); + push_int(xline->duration); + push_last(xline->reason); +} diff --git a/src/modules/m_spanningtree/away.cpp b/src/modules/m_spanningtree/away.cpp index ed97c48cd..9c4ec5783 100644 --- a/src/modules/m_spanningtree/away.cpp +++ b/src/modules/m_spanningtree/away.cpp @@ -21,32 +21,38 @@ #include "main.h" #include "utils.h" -#include "treeserver.h" -#include "treesocket.h" +#include "commands.h" -bool TreeSocket::Away(const std::string &prefix, parameterlist ¶ms) +CmdResult CommandAway::HandleRemote(RemoteUser* u, std::vector<std::string>& params) { - User* u = ServerInstance->FindNick(prefix); - if ((!u) || (IS_SERVER(u))) - return true; if (params.size()) { - FOREACH_MOD(I_OnSetAway, OnSetAway(u, params[params.size() - 1])); + FOREACH_MOD(OnSetAway, (u, params[params.size() - 1])); if (params.size() > 1) - u->awaytime = atoi(params[0].c_str()); + u->awaytime = ConvToInt(params[0]); else u->awaytime = ServerInstance->Time(); u->awaymsg = params[params.size() - 1]; - - params[params.size() - 1] = ":" + params[params.size() - 1]; } else { - FOREACH_MOD(I_OnSetAway, OnSetAway(u, "")); + FOREACH_MOD(OnSetAway, (u, "")); u->awaymsg.clear(); } - Utils->DoOneToAllButSender(prefix,"AWAY",params,u->server); - return true; + return CMD_SUCCESS; +} + +CommandAway::Builder::Builder(User* user) + : CmdBuilder(user, "AWAY") +{ + push_int(user->awaytime).push_last(user->awaymsg); +} + +CommandAway::Builder::Builder(User* user, const std::string& msg) + : CmdBuilder(user, "AWAY") +{ + if (!msg.empty()) + push_int(ServerInstance->Time()).push_last(msg); } diff --git a/src/modules/m_spanningtree/cachetimer.cpp b/src/modules/m_spanningtree/cachetimer.cpp deleted file mode 100644 index be438651d..000000000 --- a/src/modules/m_spanningtree/cachetimer.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "inspircd.h" -#include "socket.h" -#include "xline.h" - -#include "cachetimer.h" -#include "main.h" -#include "utils.h" -#include "treeserver.h" -#include "link.h" -#include "treesocket.h" - -/* $ModDep: m_spanningtree/cachetimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */ - -CacheRefreshTimer::CacheRefreshTimer(SpanningTreeUtilities *Util) : Timer(3600, ServerInstance->Time(), true), Utils(Util) -{ -} - -void CacheRefreshTimer::Tick(time_t TIME) -{ - Utils->RefreshIPCache(); -} - diff --git a/src/modules/m_spanningtree/cachetimer.h b/src/modules/m_spanningtree/cachetimer.h index bad1b7419..89933cc4b 100644 --- a/src/modules/m_spanningtree/cachetimer.h +++ b/src/modules/m_spanningtree/cachetimer.h @@ -17,13 +17,7 @@ */ -#ifndef M_SPANNINGTREE_CACHETIMER_H -#define M_SPANNINGTREE_CACHETIMER_H - -#include "timer.h" - -class ModuleSpanningTree; -class SpanningTreeUtilities; +#pragma once /** Create a timer which recurs every second, we inherit from Timer. * Timer is only one-shot however, so at the end of each Tick() we simply @@ -31,11 +25,7 @@ class SpanningTreeUtilities; */ class CacheRefreshTimer : public Timer { - private: - SpanningTreeUtilities *Utils; public: - CacheRefreshTimer(SpanningTreeUtilities* Util); - virtual void Tick(time_t TIME); + CacheRefreshTimer(); + bool Tick(time_t TIME); }; - -#endif diff --git a/src/modules/m_spanningtree/capab.cpp b/src/modules/m_spanningtree/capab.cpp index 62afe5974..1ca5b982c 100644 --- a/src/modules/m_spanningtree/capab.cpp +++ b/src/modules/m_spanningtree/capab.cpp @@ -20,9 +20,7 @@ #include "inspircd.h" -#include "xline.h" -#include "treesocket.h" #include "treeserver.h" #include "utils.h" #include "link.h" @@ -32,25 +30,19 @@ std::string TreeSocket::MyModules(int filter) { std::vector<std::string> modlist = ServerInstance->Modules->GetAllModuleNames(filter); - if (filter == VF_COMMON && proto_version != ProtocolVersion) - CompatAddModules(modlist); - std::string capabilities; sort(modlist.begin(),modlist.end()); for (std::vector<std::string>::const_iterator i = modlist.begin(); i != modlist.end(); ++i) { if (i != modlist.begin()) - capabilities.push_back(proto_version > 1201 ? ' ' : ','); + capabilities.push_back(' '); capabilities.append(*i); Module* m = ServerInstance->Modules->Find(*i); - if (m && proto_version > 1201) + Version v = m->GetVersion(); + if (!v.link_data.empty()) { - Version v = m->GetVersion(); - if (!v.link_data.empty()) - { - capabilities.push_back('='); - capabilities.append(v.link_data); - } + capabilities.push_back('='); + capabilities.append(v.link_data); } } return capabilities; @@ -74,7 +66,7 @@ static std::string BuildModeList(ModeType type) } } sort(modes.begin(), modes.end()); - irc::stringjoiner line(" ", modes, 0, modes.size() - 1); + irc::stringjoiner line(modes); return line.GetJoined(); } @@ -90,7 +82,7 @@ void TreeSocket::SendCapabilities(int phase) if (phase < 2) return; - char sep = proto_version > 1201 ? ' ' : ','; + const char sep = ' '; irc::sepstream modulelist(MyModules(VF_COMMON), sep); irc::sepstream optmodulelist(MyModules(VF_OPTCOMMON), sep); /* Send module names, split at 509 length */ @@ -139,8 +131,10 @@ void TreeSocket::SendCapabilities(int phase) SetOurChallenge(ServerInstance->GenRandomStr(20)); extra = " CHALLENGE=" + this->GetOurChallenge(); } - if (proto_version < 1202) - extra += ServerInstance->Modes->FindMode('h', MODETYPE_CHANNEL) ? " HALFOP=1" : " HALFOP=0"; + + // 2.0 needs this key + if (proto_version == 1202) + extra.append(" PROTOCOL="+ConvToStr(ProtocolVersion)); this->WriteLine("CAPAB CAPABILITIES " /* Preprocessor does this one. */ ":NICKMAX="+ConvToStr(ServerInstance->Config->Limits.NickMax)+ @@ -152,12 +146,11 @@ void TreeSocket::SendCapabilities(int phase) " MAXKICK="+ConvToStr(ServerInstance->Config->Limits.MaxKick)+ " MAXGECOS="+ConvToStr(ServerInstance->Config->Limits.MaxGecos)+ " MAXAWAY="+ConvToStr(ServerInstance->Config->Limits.MaxAway)+ - " IP6SUPPORT=1"+ - " PROTOCOL="+ConvToStr(ProtocolVersion)+extra+ + extra+ " PREFIX="+ServerInstance->Modes->BuildPrefixes()+ " CHANMODES="+ServerInstance->Modes->GiveModeList(MASK_CHANNEL)+ - " USERMODES="+ServerInstance->Modes->GiveModeList(MASK_USER)+ - " SVSPART=1"); + " USERMODES="+ServerInstance->Modes->GiveModeList(MASK_USER) + ); this->WriteLine("CAPAB END"); } @@ -202,7 +195,23 @@ bool TreeSocket::Capab(const parameterlist ¶ms) capab->OptModuleList.clear(); capab->CapKeys.clear(); if (params.size() > 1) - proto_version = atoi(params[1].c_str()); + proto_version = ConvToInt(params[1]); + + if (proto_version < MinCompatProtocol) + { + SendError("CAPAB negotiation failed: Server is using protocol version " + (proto_version ? ConvToStr(proto_version) : "1201 or older") + + " which is too old to link with this server (version " + ConvToStr(ProtocolVersion) + + (ProtocolVersion != MinCompatProtocol ? ", links with " + ConvToStr(MinCompatProtocol) + " and above)" : ")")); + return false; + } + + // Special case, may be removed in the future + if (proto_version == 1203 || proto_version == 1204) + { + SendError("CAPAB negotiation failed: InspIRCd 2.1 beta is not supported"); + return false; + } + SendCapabilities(2); } else if (params[0] == "END") @@ -212,7 +221,7 @@ bool TreeSocket::Capab(const parameterlist ¶ms) if ((this->capab->ModuleList != this->MyModules(VF_COMMON)) && (this->capab->ModuleList.length())) { std::string diffIneed, diffUneed; - ListDifference(this->capab->ModuleList, this->MyModules(VF_COMMON), proto_version > 1201 ? ' ' : ',', diffIneed, diffUneed); + ListDifference(this->capab->ModuleList, this->MyModules(VF_COMMON), ' ', diffIneed, diffUneed); if (diffIneed.length() || diffUneed.length()) { reason = "Modules incorrectly matched on these servers."; @@ -250,21 +259,6 @@ bool TreeSocket::Capab(const parameterlist ¶ms) } } - if (this->capab->CapKeys.find("PROTOCOL") == this->capab->CapKeys.end()) - { - reason = "Protocol version not specified"; - } - else - { - proto_version = atoi(capab->CapKeys.find("PROTOCOL")->second.c_str()); - if (proto_version < MinCompatProtocol) - { - reason = "Server is using protocol version " + ConvToStr(proto_version) + - " which is too old to link with this server (version " + ConvToStr(ProtocolVersion) - + (ProtocolVersion != MinCompatProtocol ? ", links with " + ConvToStr(MinCompatProtocol) + " and above)" : ")"); - } - } - if(this->capab->CapKeys.find("PREFIX") != this->capab->CapKeys.end() && this->capab->CapKeys.find("PREFIX")->second != ServerInstance->Modes->BuildPrefixes()) reason = "One or more of the prefixes on the remote server are invalid on this server."; @@ -348,7 +342,7 @@ bool TreeSocket::Capab(const parameterlist ¶ms) } else { - capab->ModuleList.push_back(proto_version > 1201 ? ' ' : ','); + capab->ModuleList.push_back(' '); capab->ModuleList.append(params[1]); } } diff --git a/src/modules/m_spanningtree/commandbuilder.h b/src/modules/m_spanningtree/commandbuilder.h new file mode 100644 index 000000000..07f7c94d0 --- /dev/null +++ b/src/modules/m_spanningtree/commandbuilder.h @@ -0,0 +1,139 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "utils.h" + +class TreeServer; + +class CmdBuilder +{ + std::string content; + + public: + CmdBuilder(const char* cmd) + : content(1, ':') + { + content.append(ServerInstance->Config->GetSID()); + push(cmd); + } + + CmdBuilder(const std::string& src, const char* cmd) + : content(1, ':') + { + content.append(src); + push(cmd); + } + + CmdBuilder(User* src, const char* cmd) + : content(1, ':') + { + content.append(src->uuid); + push(cmd); + } + + CmdBuilder& push_raw(const std::string& str) + { + content.append(str); + return *this; + } + + CmdBuilder& push_raw(const char* str) + { + content.append(str); + return *this; + } + + CmdBuilder& push_raw(char c) + { + content.push_back(c); + return *this; + } + + CmdBuilder& push(const std::string& str) + { + content.push_back(' '); + content.append(str); + return *this; + } + + CmdBuilder& push(const char* str) + { + content.push_back(' '); + content.append(str); + return *this; + } + + CmdBuilder& push(char c) + { + content.push_back(' '); + content.push_back(c); + return *this; + } + + template <typename T> + CmdBuilder& push_int(T i) + { + content.push_back(' '); + content.append(ConvToStr(i)); + return *this; + } + + CmdBuilder& push_last(const std::string& str) + { + content.push_back(' '); + content.push_back(':'); + content.append(str); + return *this; + } + + template<typename T> + CmdBuilder& insert(const T& cont) + { + for (typename T::const_iterator i = cont.begin(); i != cont.end(); ++i) + push(*i); + return *this; + } + + void push_back(const std::string& str) { push(str); } + + const std::string& str() const { return content; } + operator const std::string&() const { return str(); } + + void Broadcast() const + { + Utils->DoOneToMany(*this); + } + + void Forward(TreeServer* omit) const + { + Utils->DoOneToAllButSender(*this, omit); + } + + bool Unicast(const std::string& target) const + { + return Utils->DoOneToOne(*this, target); + } + + bool Unicast(User* target) const + { + return Unicast(target->server); + } +}; diff --git a/src/modules/m_spanningtree/commands.h b/src/modules/m_spanningtree/commands.h index 3b5b499c1..f15708a9a 100644 --- a/src/modules/m_spanningtree/commands.h +++ b/src/modules/m_spanningtree/commands.h @@ -17,119 +17,315 @@ */ -#ifndef M_SPANNINGTREE_COMMANDS_H -#define M_SPANNINGTREE_COMMANDS_H +#pragma once #include "main.h" +#include "commandbuilder.h" /** Handle /RCONNECT */ class CommandRConnect : public Command { - SpanningTreeUtilities* Utils; /* Utility class */ public: - CommandRConnect (Module* Callback, SpanningTreeUtilities* Util); - CmdResult Handle (const std::vector<std::string>& parameters, User *user); - RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters); + CommandRConnect(Module* Creator); + CmdResult Handle(const std::vector<std::string>& parameters, User* user); + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters); }; class CommandRSQuit : public Command { - SpanningTreeUtilities* Utils; /* Utility class */ public: - CommandRSQuit(Module* Callback, SpanningTreeUtilities* Util); - CmdResult Handle (const std::vector<std::string>& parameters, User *user); - RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters); - void NoticeUser(User* user, const std::string &msg); + CommandRSQuit(Module* Creator); + CmdResult Handle(const std::vector<std::string>& parameters, User* user); + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters); }; -class CommandSVSJoin : public Command +class CommandMap : public Command { + /** Show MAP output to a user (recursive) + */ + void ShowMap(TreeServer* Current, User* user, int depth, int &line, char* names, int &maxnamew, char* stats); + + /** Returns oper-specific MAP information + */ + std::string MapOperInfo(TreeServer* Current); + public: - CommandSVSJoin(Module* Creator) : Command(Creator, "SVSJOIN", 2) { flags_needed = FLAG_SERVERONLY; } - CmdResult Handle (const std::vector<std::string>& parameters, User *user); + CommandMap(Module* Creator); + CmdResult Handle(const std::vector<std::string>& parameters, User* user); RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters); }; -class CommandSVSPart : public Command + +class CommandSVSJoin : public ServerCommand { public: - CommandSVSPart(Module* Creator) : Command(Creator, "SVSPART", 2) { flags_needed = FLAG_SERVERONLY; } - CmdResult Handle (const std::vector<std::string>& parameters, User *user); + CommandSVSJoin(Module* Creator) : ServerCommand(Creator, "SVSJOIN", 2) { } + CmdResult Handle(User* user, std::vector<std::string>& params); RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters); }; -class CommandSVSNick : public Command + +class CommandSVSPart : public ServerCommand { public: - CommandSVSNick(Module* Creator) : Command(Creator, "SVSNICK", 3) { flags_needed = FLAG_SERVERONLY; } - CmdResult Handle (const std::vector<std::string>& parameters, User *user); + CommandSVSPart(Module* Creator) : ServerCommand(Creator, "SVSPART", 2) { } + CmdResult Handle(User* user, std::vector<std::string>& params); RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters); }; -class CommandMetadata : public Command + +class CommandSVSNick : public ServerCommand { public: - CommandMetadata(Module* Creator) : Command(Creator, "METADATA", 2) { flags_needed = FLAG_SERVERONLY; } - CmdResult Handle (const std::vector<std::string>& parameters, User *user); - RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; } + CommandSVSNick(Module* Creator) : ServerCommand(Creator, "SVSNICK", 3) { } + CmdResult Handle(User* user, std::vector<std::string>& params); + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters); }; -class CommandUID : public Command + +class CommandMetadata : public ServerCommand { public: - CommandUID(Module* Creator) : Command(Creator, "UID", 10) { flags_needed = FLAG_SERVERONLY; } - CmdResult Handle (const std::vector<std::string>& parameters, User *user); - RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; } + CommandMetadata(Module* Creator) : ServerCommand(Creator, "METADATA", 2) { } + CmdResult Handle(User* user, std::vector<std::string>& params); + + class Builder : public CmdBuilder + { + public: + Builder(User* user, const std::string& key, const std::string& val); + Builder(Channel* chan, const std::string& key, const std::string& val); + Builder(const std::string& key, const std::string& val); + }; }; -class CommandOpertype : public Command + +class CommandUID : public ServerOnlyServerCommand<CommandUID> { public: - CommandOpertype(Module* Creator) : Command(Creator, "OPERTYPE", 1) { flags_needed = FLAG_SERVERONLY; } - CmdResult Handle (const std::vector<std::string>& parameters, User *user); - RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; } + CommandUID(Module* Creator) : ServerOnlyServerCommand<CommandUID>(Creator, "UID", 10) { } + CmdResult HandleServer(TreeServer* server, std::vector<std::string>& params); + + class Builder : public CmdBuilder + { + public: + Builder(User* user); + }; }; -class CommandFJoin : public Command + +class CommandOpertype : public UserOnlyServerCommand<CommandOpertype> { public: - CommandFJoin(Module* Creator) : Command(Creator, "FJOIN", 3) { flags_needed = FLAG_SERVERONLY; } - CmdResult Handle (const std::vector<std::string>& parameters, User *user); - RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; } + CommandOpertype(Module* Creator) : UserOnlyServerCommand<CommandOpertype>(Creator, "OPERTYPE", 1) { } + CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& params); + + class Builder : public CmdBuilder + { + public: + Builder(User* user); + }; +}; + +class TreeSocket; +class CommandFJoin : public ServerCommand +{ /** Remove all modes from a channel, including statusmodes (+qaovh etc), simplemodes, parameter modes. * This does not update the timestamp of the target channel, this must be done seperately. */ - void RemoveStatus(User* source, parameterlist ¶ms); + static void RemoveStatus(Channel* c); + static void ApplyModeStack(User* srcuser, Channel* c, irc::modestacker& stack); + bool ProcessModeUUIDPair(const std::string& item, TreeSocket* src_socket, Channel* chan, irc::modestacker* modestack); + public: + CommandFJoin(Module* Creator) : ServerCommand(Creator, "FJOIN", 3) { } + CmdResult Handle(User* user, std::vector<std::string>& params); +}; + +class CommandFMode : public ServerCommand +{ + public: + CommandFMode(Module* Creator) : ServerCommand(Creator, "FMODE", 3) { } + CmdResult Handle(User* user, std::vector<std::string>& params); +}; + +class CommandFTopic : public ServerCommand +{ + public: + CommandFTopic(Module* Creator) : ServerCommand(Creator, "FTOPIC", 4, 5) { } + CmdResult Handle(User* user, std::vector<std::string>& params); + + class Builder : public CmdBuilder + { + public: + Builder(Channel* chan); + Builder(User* user, Channel* chan); + }; +}; + +class CommandFHost : public UserOnlyServerCommand<CommandFHost> +{ + public: + CommandFHost(Module* Creator) : UserOnlyServerCommand<CommandFHost>(Creator, "FHOST", 1) { } + CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& params); +}; + +class CommandFIdent : public UserOnlyServerCommand<CommandFIdent> +{ + public: + CommandFIdent(Module* Creator) : UserOnlyServerCommand<CommandFIdent>(Creator, "FIDENT", 1) { } + CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& params); +}; + +class CommandFName : public UserOnlyServerCommand<CommandFName> +{ + public: + CommandFName(Module* Creator) : UserOnlyServerCommand<CommandFName>(Creator, "FNAME", 1) { } + CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& params); }; -class CommandFMode : public Command + +class CommandIJoin : public UserOnlyServerCommand<CommandIJoin> { public: - CommandFMode(Module* Creator) : Command(Creator, "FMODE", 3) { flags_needed = FLAG_SERVERONLY; } - CmdResult Handle (const std::vector<std::string>& parameters, User *user); - RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; } + CommandIJoin(Module* Creator) : UserOnlyServerCommand<CommandIJoin>(Creator, "IJOIN", 1) { } + CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& params); }; -class CommandFTopic : public Command + +class CommandResync : public ServerOnlyServerCommand<CommandResync> { public: - CommandFTopic(Module* Creator) : Command(Creator, "FTOPIC", 4) { flags_needed = FLAG_SERVERONLY; } - CmdResult Handle (const std::vector<std::string>& parameters, User *user); - RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; } + CommandResync(Module* Creator) : ServerOnlyServerCommand<CommandResync>(Creator, "RESYNC", 1) { } + CmdResult HandleServer(TreeServer* server, std::vector<std::string>& parameters); }; -class CommandFHost : public Command + +class CommandAway : public UserOnlyServerCommand<CommandAway> { public: - CommandFHost(Module* Creator) : Command(Creator, "FHOST", 1) { flags_needed = FLAG_SERVERONLY; } - CmdResult Handle (const std::vector<std::string>& parameters, User *user); - RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; } + CommandAway(Module* Creator) : UserOnlyServerCommand<CommandAway>(Creator, "AWAY", 0, 2) { } + CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& parameters); + + class Builder : public CmdBuilder + { + public: + Builder(User* user); + Builder(User* user, const std::string& msg); + }; }; -class CommandFIdent : public Command + +class XLine; +class CommandAddLine : public ServerCommand { public: - CommandFIdent(Module* Creator) : Command(Creator, "FIDENT", 1) { flags_needed = FLAG_SERVERONLY; } - CmdResult Handle (const std::vector<std::string>& parameters, User *user); - RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; } + CommandAddLine(Module* Creator) : ServerCommand(Creator, "ADDLINE", 6, 6) { } + CmdResult Handle(User* user, std::vector<std::string>& parameters); + + class Builder : public CmdBuilder + { + public: + Builder(XLine* xline, User* user = ServerInstance->FakeClient); + }; }; -class CommandFName : public Command + +class CommandDelLine : public ServerCommand { public: - CommandFName(Module* Creator) : Command(Creator, "FNAME", 1) { flags_needed = FLAG_SERVERONLY; } - CmdResult Handle (const std::vector<std::string>& parameters, User *user); - RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; } + CommandDelLine(Module* Creator) : ServerCommand(Creator, "DELLINE", 2, 2) { } + CmdResult Handle(User* user, std::vector<std::string>& parameters); +}; + +class CommandEncap : public ServerCommand +{ + public: + CommandEncap(Module* Creator) : ServerCommand(Creator, "ENCAP", 2) { } + CmdResult Handle(User* user, std::vector<std::string>& parameters); + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters); +}; + +class CommandIdle : public UserOnlyServerCommand<CommandIdle> +{ + public: + CommandIdle(Module* Creator) : UserOnlyServerCommand<CommandIdle>(Creator, "IDLE", 1) { } + CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& parameters); + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_UNICAST(parameters[0]); } +}; + +class CommandNick : public UserOnlyServerCommand<CommandNick> +{ + public: + CommandNick(Module* Creator) : UserOnlyServerCommand<CommandNick>(Creator, "NICK", 2) { } + CmdResult HandleRemote(RemoteUser* user, std::vector<std::string>& parameters); +}; + +class CommandPing : public ServerCommand +{ + public: + CommandPing(Module* Creator) : ServerCommand(Creator, "PING", 1) { } + CmdResult Handle(User* user, std::vector<std::string>& parameters); + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_UNICAST(parameters[0]); } +}; + +class CommandPong : public ServerOnlyServerCommand<CommandPong> +{ + public: + CommandPong(Module* Creator) : ServerOnlyServerCommand<CommandPong>(Creator, "PONG", 1) { } + CmdResult HandleServer(TreeServer* server, std::vector<std::string>& parameters); + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_UNICAST(parameters[0]); } +}; + +class CommandPush : public ServerCommand +{ + public: + CommandPush(Module* Creator) : ServerCommand(Creator, "PUSH", 2) { } + CmdResult Handle(User* user, std::vector<std::string>& parameters); + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_UNICAST(parameters[0]); } +}; + +class CommandSave : public ServerCommand +{ + public: + CommandSave(Module* Creator) : ServerCommand(Creator, "SAVE", 2) { } + CmdResult Handle(User* user, std::vector<std::string>& parameters); +}; + +class CommandServer : public ServerOnlyServerCommand<CommandServer> +{ + public: + CommandServer(Module* Creator) : ServerOnlyServerCommand<CommandServer>(Creator, "SERVER", 5) { } + CmdResult HandleServer(TreeServer* server, std::vector<std::string>& parameters); + + class Builder : public CmdBuilder + { + public: + Builder(TreeServer* server); + }; +}; + +class CommandSQuit : public ServerOnlyServerCommand<CommandSQuit> +{ + public: + CommandSQuit(Module* Creator) : ServerOnlyServerCommand<CommandSQuit>(Creator, "SQUIT", 2) { } + CmdResult HandleServer(TreeServer* server, std::vector<std::string>& parameters); +}; + +class CommandSNONotice : public ServerCommand +{ + public: + CommandSNONotice(Module* Creator) : ServerCommand(Creator, "SNONOTICE", 2) { } + CmdResult Handle(User* user, std::vector<std::string>& parameters); +}; + +class CommandVersion : public ServerOnlyServerCommand<CommandVersion> +{ + public: + CommandVersion(Module* Creator) : ServerOnlyServerCommand<CommandVersion>(Creator, "VERSION", 1) { } + CmdResult HandleServer(TreeServer* server, std::vector<std::string>& parameters); +}; + +class CommandBurst : public ServerOnlyServerCommand<CommandBurst> +{ + public: + CommandBurst(Module* Creator) : ServerOnlyServerCommand<CommandBurst>(Creator, "BURST") { } + CmdResult HandleServer(TreeServer* server, std::vector<std::string>& parameters); +}; + +class CommandEndBurst : public ServerOnlyServerCommand<CommandEndBurst> +{ + public: + CommandEndBurst(Module* Creator) : ServerOnlyServerCommand<CommandEndBurst>(Creator, "ENDBURST") { } + CmdResult HandleServer(TreeServer* server, std::vector<std::string>& parameters); }; class SpanningTreeCommands @@ -137,6 +333,7 @@ class SpanningTreeCommands public: CommandRConnect rconnect; CommandRSQuit rsquit; + CommandMap map; CommandSVSJoin svsjoin; CommandSVSPart svspart; CommandSVSNick svsnick; @@ -144,12 +341,28 @@ class SpanningTreeCommands CommandUID uid; CommandOpertype opertype; CommandFJoin fjoin; + CommandIJoin ijoin; + CommandResync resync; CommandFMode fmode; CommandFTopic ftopic; CommandFHost fhost; CommandFIdent fident; CommandFName fname; + CommandAway away; + CommandAddLine addline; + CommandDelLine delline; + CommandEncap encap; + CommandIdle idle; + CommandNick nick; + CommandPing ping; + CommandPong pong; + CommandPush push; + CommandSave save; + CommandServer server; + CommandSQuit squit; + CommandSNONotice snonotice; + CommandVersion version; + CommandBurst burst; + CommandEndBurst endburst; SpanningTreeCommands(ModuleSpanningTree* module); }; - -#endif diff --git a/src/modules/m_spanningtree/compat.cpp b/src/modules/m_spanningtree/compat.cpp index ec0cdb036..02e11c849 100644 --- a/src/modules/m_spanningtree/compat.cpp +++ b/src/modules/m_spanningtree/compat.cpp @@ -20,177 +20,272 @@ #include "inspircd.h" #include "main.h" #include "treesocket.h" +#include "treeserver.h" -static const char* const forge_common_1201[] = { - "m_allowinvite.so", - "m_alltime.so", - "m_auditorium.so", - "m_banexception.so", - "m_blockcaps.so", - "m_blockcolor.so", - "m_botmode.so", - "m_censor.so", - "m_chanfilter.so", - "m_chanhistory.so", - "m_channelban.so", - "m_chanprotect.so", - "m_chghost.so", - "m_chgname.so", - "m_commonchans.so", - "m_customtitle.so", - "m_deaf.so", - "m_delayjoin.so", - "m_delaymsg.so", - "m_exemptchanops.so", - "m_gecosban.so", - "m_globops.so", - "m_helpop.so", - "m_hidechans.so", - "m_hideoper.so", - "m_invisible.so", - "m_inviteexception.so", - "m_joinflood.so", - "m_kicknorejoin.so", - "m_knock.so", - "m_messageflood.so", - "m_muteban.so", - "m_nickflood.so", - "m_nicklock.so", - "m_noctcp.so", - "m_nokicks.so", - "m_nonicks.so", - "m_nonotice.so", - "m_nopartmsg.so", - "m_ojoin.so", - "m_operprefix.so", - "m_permchannels.so", - "m_redirect.so", - "m_regex_glob.so", - "m_regex_pcre.so", - "m_regex_posix.so", - "m_regex_tre.so", - "m_remove.so", - "m_sajoin.so", - "m_sakick.so", - "m_sanick.so", - "m_sapart.so", - "m_saquit.so", - "m_serverban.so", - "m_services_account.so", - "m_servprotect.so", - "m_setident.so", - "m_showwhois.so", - "m_silence.so", - "m_sslmodes.so", - "m_stripcolor.so", - "m_swhois.so", - "m_uninvite.so", - "m_watch.so" -}; - -static std::string wide_newline("\r\n"); static std::string newline("\n"); -void TreeSocket::CompatAddModules(std::vector<std::string>& modlist) -{ - if (proto_version < 1202) - { - // you MUST have chgident loaded in order to be able to translate FIDENT - modlist.push_back("m_chgident.so"); - for(int i=0; i * sizeof(char*) < sizeof(forge_common_1201); i++) - { - if (ServerInstance->Modules->Find(forge_common_1201[i])) - modlist.push_back(forge_common_1201[i]); - } - // module was merged - if (ServerInstance->Modules->Find("m_operchans.so")) - { - modlist.push_back("m_operchans.so"); - modlist.push_back("m_operinvex.so"); - } - } -} - -void TreeSocket::WriteLine(std::string line) +void TreeSocket::WriteLine(const std::string& original_line) { if (LinkState == CONNECTED) { - if (line[0] != ':') + if (original_line.c_str()[0] != ':') { - ServerInstance->Logs->Log("m_spanningtree", DEFAULT, "Sending line without server prefix!"); - line = ":" + ServerInstance->Config->GetSID() + " " + line; + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Sending line without server prefix!"); + WriteLine(":" + ServerInstance->Config->GetSID() + " " + original_line); + return; } if (proto_version != ProtocolVersion) { + std::string line = original_line; std::string::size_type a = line.find(' '); std::string::size_type b = line.find(' ', a + 1); std::string command = line.substr(a + 1, b-a-1); // now try to find a translation entry // TODO a more efficient lookup method will be needed later - if (proto_version < 1202 && command == "FIDENT") - { - ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Rewriting FIDENT for 1201-protocol server"); - line = ":" + ServerInstance->Config->GetSID() + " CHGIDENT " + line.substr(1,a-1) + line.substr(b); - } - else if (proto_version < 1202 && command == "SAVE") + if (proto_version < 1205) { - ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Rewriting SAVE for 1201-protocol server"); - std::string::size_type c = line.find(' ', b + 1); - std::string uid = line.substr(b, c - b); - line = ":" + ServerInstance->Config->GetSID() + " SVSNICK" + uid + line.substr(b); - } - else if (proto_version < 1202 && command == "AWAY") - { - if (b != std::string::npos) + if (command == "IJOIN") { - ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Stripping AWAY timestamp for 1201-protocol server"); + // Convert + // :<uid> IJOIN <chan> [<ts> [<flags>]] + // to + // :<sid> FJOIN <chan> <ts> + [<flags>],<uuid> std::string::size_type c = line.find(' ', b + 1); - line.erase(b,c-b); + if (c == std::string::npos) + { + // No TS or modes in the command + // :22DAAAAAB IJOIN #chan + const std::string channame = line.substr(b+1, c-b-1); + Channel* chan = ServerInstance->FindChan(channame); + if (!chan) + return; + + line.push_back(' '); + line.append(ConvToStr(chan->age)); + line.append(" + ,"); + } + else + { + std::string::size_type d = line.find(' ', c + 1); + if (d == std::string::npos) + { + // TS present, no modes + // :22DAAAAAC IJOIN #chan 12345 + line.append(" + ,"); + } + else + { + // Both TS and modes are present + // :22DAAAAAC IJOIN #chan 12345 ov + std::string::size_type e = line.find(' ', d + 1); + if (e != std::string::npos) + line.erase(e); + + line.insert(d, " +"); + line.push_back(','); + } + } + + // Move the uuid to the end and replace the I with an F + line.append(line.substr(1, 9)); + line.erase(4, 6); + line[5] = 'F'; } - } - else if (proto_version < 1202 && command == "ENCAP") - { - // :src ENCAP target command [args...] - // A B C D - // Therefore B and C cannot be npos in a valid command - if (b == std::string::npos) - return; - std::string::size_type c = line.find(' ', b + 1); - if (c == std::string::npos) + else if (command == "RESYNC") return; - std::string::size_type d = line.find(' ', c + 1); - std::string subcmd = line.substr(c + 1, d - c - 1); + else if (command == "METADATA") + { + // Drop TS for channel METADATA, translate METADATA operquit into an OPERQUIT command + // :sid METADATA #target TS extname ... + // A B C D + if (b == std::string::npos) + return; + + std::string::size_type c = line.find(' ', b + 1); + if (c == std::string::npos) + return; - if (subcmd == "CHGIDENT" && d != std::string::npos) + std::string::size_type d = line.find(' ', c + 1); + if (d == std::string::npos) + return; + + if (line[b + 1] == '#') + { + // We're sending channel metadata + line.erase(c, d-c); + } + else if (line.substr(c, d-c) == " operquit") + { + // ":22D METADATA 22DAAAAAX operquit :message" -> ":22DAAAAAX OPERQUIT :message" + line = ":" + line.substr(b+1, c-b) + "OPERQUIT" + line.substr(d); + } + } + else if (command == "FTOPIC") { - std::string::size_type e = line.find(' ', d + 1); - if (e == std::string::npos) - return; // not valid - std::string target = line.substr(d + 1, e - d - 1); + // Drop channel TS for FTOPIC + // :sid FTOPIC #target TS TopicTS setter :newtopic + // A B C D E F + // :uid FTOPIC #target TS TopicTS :newtopic + // A B C D E + if (b == std::string::npos) + return; + + std::string::size_type c = line.find(' ', b + 1); + if (c == std::string::npos) + return; + + std::string::size_type d = line.find(' ', c + 1); + if (d == std::string::npos) + return; - ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Forging acceptance of CHGIDENT from 1201-protocol server"); - recvq.insert(0, ":" + target + " FIDENT " + line.substr(e) + "\n"); + std::string::size_type e = line.find(' ', d + 1); + if (line[e+1] == ':') + { + line.erase(c, e-c); + line.erase(a+1, 1); + } + else + line.erase(c, d-c); } + else if ((command == "PING") || (command == "PONG")) + { + // :22D PING 20D + if (line.length() < 13) + return; - Command* thiscmd = ServerInstance->Parser->GetHandler(subcmd); - if (thiscmd && subcmd != "WHOISNOTICE") + // Insert the source SID (and a space) between the command and the first parameter + line.insert(10, line.substr(1, 4)); + } + else if (command == "OPERTYPE") { - Version ver = thiscmd->creator->GetVersion(); - if (ver.Flags & VF_OPTCOMMON) + std::string::size_type colon = line.find(':', b); + if (colon != std::string::npos) { - ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Removing ENCAP on '%s' for 1201-protocol server", - subcmd.c_str()); - line.erase(a, c-a); + for (std::string::iterator i = line.begin()+colon; i != line.end(); ++i) + { + if (*i == ' ') + *i = '_'; + } + line.erase(colon, 1); } } } + ServerInstance->Logs->Log(MODNAME, LOG_RAWIO, "S[%d] O %s", this->GetFd(), line.c_str()); + this->WriteData(line); + this->WriteData(newline); + return; } } - ServerInstance->Logs->Log("m_spanningtree", RAWIO, "S[%d] O %s", this->GetFd(), line.c_str()); - this->WriteData(line); - if (proto_version < 1202) - this->WriteData(wide_newline); - else - this->WriteData(newline); + ServerInstance->Logs->Log(MODNAME, LOG_RAWIO, "S[%d] O %s", this->GetFd(), original_line.c_str()); + this->WriteData(original_line); + this->WriteData(newline); +} + +namespace +{ + bool InsertCurrentChannelTS(std::vector<std::string>& params) + { + Channel* chan = ServerInstance->FindChan(params[0]); + if (!chan) + return false; + + // Insert the current TS of the channel between the first and the second parameters + params.insert(params.begin()+1, ConvToStr(chan->age)); + return true; + } +} + +bool TreeSocket::PreProcessOldProtocolMessage(User*& who, std::string& cmd, std::vector<std::string>& params) +{ + if ((cmd == "METADATA") && (params.size() >= 3) && (params[0][0] == '#')) + { + // :20D METADATA #channel extname :extdata + return InsertCurrentChannelTS(params); + } + else if ((cmd == "FTOPIC") && (params.size() >= 4)) + { + // :20D FTOPIC #channel 100 Attila :topic text + return InsertCurrentChannelTS(params); + } + else if ((cmd == "PING") || (cmd == "PONG")) + { + if (params.size() == 1) + { + // If it's a PING with 1 parameter, reply with a PONG now, if it's a PONG with 1 parameter (weird), do nothing + if (cmd[1] == 'I') + this->WriteData(":" + ServerInstance->Config->GetSID() + " PONG " + params[0] + newline); + + // Don't process this message further + return false; + } + + // :20D PING 20D 22D + // :20D PONG 20D 22D + // Drop the first parameter + params.erase(params.begin()); + + // If the target is a server name, translate it to a SID + if (!InspIRCd::IsSID(params[0])) + { + TreeServer* server = Utils->FindServer(params[0]); + if (!server) + { + // We've no idea what this is, log and stop processing + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Received a " + cmd + " with an unknown target: \"" + params[0] + "\", command dropped"); + return false; + } + + params[0] = server->GetID(); + } + } + else if ((cmd == "GLINE") || (cmd == "KLINE") || (cmd == "ELINE") || (cmd == "ZLINE") || (cmd == "QLINE")) + { + // Fix undocumented protocol usage: translate GLINE, ZLINE, etc. into ADDLINE or DELLINE + if ((params.size() != 1) && (params.size() != 3)) + return false; + + parameterlist p; + p.push_back(cmd.substr(0, 1)); + p.push_back(params[0]); + + if (params.size() == 3) + { + cmd = "ADDLINE"; + p.push_back(who->nick); + p.push_back(ConvToStr(ServerInstance->Time())); + p.push_back(ConvToStr(InspIRCd::Duration(params[1]))); + p.push_back(params[2]); + } + else + cmd = "DELLINE"; + + params.swap(p); + } + else if (cmd == "SVSMODE") + { + cmd = "MODE"; + } + else if (cmd == "OPERQUIT") + { + // Translate OPERQUIT into METADATA + if (params.empty()) + return false; + + cmd = "METADATA"; + params.insert(params.begin(), who->uuid); + params.insert(params.begin()+1, "operquit"); + who = MyRoot->ServerUser; + } + else if ((cmd == "TOPIC") && (params.size() >= 2)) + { + // :20DAAAAAC TOPIC #chan :new topic + cmd = "FTOPIC"; + if (!InsertCurrentChannelTS(params)) + return false; + + params.insert(params.begin()+2, ConvToStr(ServerInstance->Time())); + } + + return true; // Passthru } diff --git a/src/modules/m_spanningtree/delline.cpp b/src/modules/m_spanningtree/delline.cpp index 540ca5079..c4ed1691b 100644 --- a/src/modules/m_spanningtree/delline.cpp +++ b/src/modules/m_spanningtree/delline.cpp @@ -20,38 +20,19 @@ #include "inspircd.h" #include "xline.h" -#include "treesocket.h" -#include "treeserver.h" -#include "utils.h" +#include "commands.h" -/* $ModDep: m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */ - - -bool TreeSocket::DelLine(const std::string &prefix, parameterlist ¶ms) +CmdResult CommandDelLine::Handle(User* user, std::vector<std::string>& params) { - if (params.size() < 2) - return true; - - std::string setter = "<unknown>"; - - User* user = ServerInstance->FindNick(prefix); - if (user) - setter = user->nick; - else - { - TreeServer* t = Utils->FindServer(prefix); - if (t) - setter = t->GetName(); - } - + const std::string& setter = user->nick; /* NOTE: No check needed on 'user', this function safely handles NULL */ if (ServerInstance->XLines->DelLine(params[1].c_str(), params[0], user)) { ServerInstance->SNO->WriteToSnoMask('X',"%s removed %s%s on %s", setter.c_str(), params[0].c_str(), params[0].length() == 1 ? "-line" : "", params[1].c_str()); - Utils->DoOneToAllButSender(prefix,"DELLINE", params, prefix); + return CMD_SUCCESS; } - return true; + return CMD_FAILURE; } diff --git a/src/modules/m_spanningtree/encap.cpp b/src/modules/m_spanningtree/encap.cpp index dabfc086b..12ab2b664 100644 --- a/src/modules/m_spanningtree/encap.cpp +++ b/src/modules/m_spanningtree/encap.cpp @@ -18,32 +18,24 @@ #include "inspircd.h" -#include "xline.h" -#include "treesocket.h" -#include "treeserver.h" -#include "utils.h" +#include "commands.h" /** ENCAP */ -void TreeSocket::Encap(User* who, parameterlist ¶ms) +CmdResult CommandEncap::Handle(User* user, std::vector<std::string>& params) { - if (params.size() > 1) + if (ServerInstance->Config->GetSID() == params[0] || InspIRCd::Match(ServerInstance->Config->ServerName, params[0])) { - if (ServerInstance->Config->GetSID() == params[0] || InspIRCd::Match(ServerInstance->Config->ServerName, params[0])) - { - parameterlist plist(params.begin() + 2, params.end()); - ServerInstance->Parser->CallHandler(params[1], plist, who); - // discard return value, ENCAP shall succeed even if the command does not exist - } - - params[params.size() - 1] = ":" + params[params.size() - 1]; - - if (params[0].find_first_of("*?") != std::string::npos) - { - Utils->DoOneToAllButSender(who->uuid, "ENCAP", params, who->server); - } - else - Utils->DoOneToOne(who->uuid, "ENCAP", params, params[0]); + parameterlist plist(params.begin() + 2, params.end()); + ServerInstance->Parser->CallHandler(params[1], plist, user); + // Discard return value, ENCAP shall succeed even if the command does not exist } + return CMD_SUCCESS; } +RouteDescriptor CommandEncap::GetRouting(User* user, const std::vector<std::string>& params) +{ + if (params[0].find_first_of("*?") != std::string::npos) + return ROUTE_BROADCAST; + return ROUTE_UNICAST(params[0]); +} diff --git a/src/modules/m_spanningtree/fjoin.cpp b/src/modules/m_spanningtree/fjoin.cpp index ee18c8e87..0fb446877 100644 --- a/src/modules/m_spanningtree/fjoin.cpp +++ b/src/modules/m_spanningtree/fjoin.cpp @@ -26,10 +26,9 @@ #include "treesocket.h" /** FJOIN, almost identical to TS6 SJOIN, except for nicklist handling. */ -CmdResult CommandFJoin::Handle(const std::vector<std::string>& params, User *srcuser) +CmdResult CommandFJoin::Handle(User* srcuser, std::vector<std::string>& params) { - SpanningTreeUtilities* Utils = ((ModuleSpanningTree*)(Module*)creator)->Utils; - /* 1.1 FJOIN works as follows: + /* 1.1+ FJOIN works as follows: * * Each FJOIN is sent along with a timestamp, and the side with the lowest * timestamp 'wins'. From this point on we will refer to this side as the @@ -54,71 +53,75 @@ CmdResult CommandFJoin::Handle(const std::vector<std::string>& params, User *src * The winning side on the other hand will ignore all user modes from the * losing side, so only its own modes get applied. Life is simple for those * who succeed at internets. :-) + * + * Syntax: + * :<sid> FJOIN <chan> <TS> <modes> :[[modes,]<uuid> [[modes,]<uuid> ... ]] + * The last parameter is a list consisting of zero or more (modelist, uuid) + * pairs (permanent channels may have zero users). The mode list for each + * user is a concatenation of the mode letters the user has on the channel + * (e.g.: "ov" if the user is opped and voiced). The order of the mode letters + * are not important but if a server ecounters an unknown mode letter, it will + * drop the link to avoid desync. + * + * InspIRCd 2.0 and older required a comma before the uuid even if the user + * had no prefix modes on the channel, InspIRCd 2.2 and later does not require + * a comma in this case anymore. + * */ - irc::modestacker modestack(true); /* Modes to apply from the users in the user list */ - User* who = NULL; /* User we are currently checking */ - std::string channel = params[0]; /* Channel name, as a string */ - time_t TS = atoi(params[1].c_str()); /* Timestamp given to us for remote side */ - irc::tokenstream users((params.size() > 3) ? params[params.size() - 1] : ""); /* users from the user list */ - bool apply_other_sides_modes = true; /* True if we are accepting the other side's modes */ - Channel* chan = ServerInstance->FindChan(channel); /* The channel we're sending joins to */ - bool created = !chan; /* True if the channel doesnt exist here yet */ - std::string item; /* One item in the list of nicks */ - - TreeSocket* src_socket = Utils->FindServer(srcuser->server)->GetRoute()->GetSocket(); - + time_t TS = ConvToInt(params[1]); if (!TS) { - ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"*** BUG? *** TS of 0 sent to FJOIN. Are some services authors smoking craq, or is it 1970 again?. Dropped."); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "*** BUG? *** TS of 0 sent to FJOIN. Are some services authors smoking craq, or is it 1970 again?. Dropped."); ServerInstance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FJOIN with a TS of zero. Total craq. Command was dropped.", srcuser->server.c_str()); return CMD_INVALID; } - if (created) + const std::string& channel = params[0]; + Channel* chan = ServerInstance->FindChan(channel); + bool apply_other_sides_modes = true; + + if (!chan) { chan = new Channel(channel, TS); - ServerInstance->SNO->WriteToSnoMask('d', "Creation FJOIN received for %s, timestamp: %lu", chan->name.c_str(), (unsigned long)TS); } else { time_t ourTS = chan->age; - if (TS != ourTS) + { ServerInstance->SNO->WriteToSnoMask('d', "Merge FJOIN received for %s, ourTS: %lu, TS: %lu, difference: %lu", chan->name.c_str(), (unsigned long)ourTS, (unsigned long)TS, (unsigned long)(ourTS - TS)); - /* If our TS is less than theirs, we dont accept their modes */ - if (ourTS < TS) - { - ServerInstance->SNO->WriteToSnoMask('d', "NOT Applying modes from other side"); - apply_other_sides_modes = false; - } - else if (ourTS > TS) - { - /* Our TS greater than theirs, clear all our modes from the channel, accept theirs. */ - ServerInstance->SNO->WriteToSnoMask('d', "Removing our modes, accepting remote"); - parameterlist param_list; - if (Utils->AnnounceTSChange) - chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :TS for %s changed from %lu to %lu", chan->name.c_str(), channel.c_str(), (unsigned long) ourTS, (unsigned long) TS); - // while the name is equal in case-insensitive compare, it might differ in case; use the remote version - chan->name = channel; - chan->age = TS; - chan->ClearInvites(); - param_list.push_back(channel); - this->RemoveStatus(ServerInstance->FakeClient, param_list); - - // XXX: If the channel does not exist in the chan hash at this point, create it so the remote modes can be applied on it. - // This happens to 0-user permanent channels on the losing side, because those are removed (from the chan hash, then - // deleted later) as soon as the permchan mode is removed from them. - if (ServerInstance->FindChan(channel) == NULL) + /* If our TS is less than theirs, we dont accept their modes */ + if (ourTS < TS) { - chan = new Channel(channel, TS); + apply_other_sides_modes = false; + } + else if (ourTS > TS) + { + /* Our TS greater than theirs, clear all our modes from the channel, accept theirs. */ + if (Utils->AnnounceTSChange) + chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :TS for %s changed from %lu to %lu", chan->name.c_str(), channel.c_str(), (unsigned long) ourTS, (unsigned long) TS); + + // while the name is equal in case-insensitive compare, it might differ in case; use the remote version + chan->name = channel; + chan->age = TS; + chan->ClearInvites(); + + CommandFJoin::RemoveStatus(chan); + + // XXX: If the channel does not exist in the chan hash at this point, create it so the remote modes can be applied on it. + // This happens to 0-user permanent channels on the losing side, because those are removed (from the chan hash, then + // deleted later) as soon as the permchan mode is removed from them. + if (ServerInstance->FindChan(channel) == NULL) + { + chan = new Channel(channel, TS); + } } } - // The silent case here is ourTS == TS, we don't need to remove modes here, just to merge them later on. } - /* First up, apply their modes if they won the TS war */ + /* First up, apply their channel modes if they won the TS war */ if (apply_other_sides_modes) { // Need to use a modestacker here due to maxmodes @@ -148,109 +151,100 @@ CmdResult CommandFJoin::Handle(const std::vector<std::string>& params, User *src while (stack.GetStackedLine(modelist)) { - ServerInstance->Modes->Process(modelist, srcuser, true); + ServerInstance->Modes->Process(modelist, srcuser, ModeParser::MODE_LOCALONLY | ModeParser::MODE_MERGE); modelist.erase(modelist.begin() + 1, modelist.end()); } - - ServerInstance->Modes->Process(modelist, srcuser, true); } - /* Now, process every 'modes,nick' pair */ + irc::modestacker modestack(true); + TreeSocket* src_socket = Utils->FindServer(srcuser->server)->GetSocket(); + + /* Now, process every 'modes,uuid' pair */ + irc::tokenstream users(*params.rbegin()); + std::string item; + irc::modestacker* modestackptr = (apply_other_sides_modes ? &modestack : NULL); while (users.GetToken(item)) { - const char* usr = item.c_str(); - if (usr && *usr) - { - const char* unparsedmodes = usr; - std::string modes; - - - /* Iterate through all modes for this user and check they are valid. */ - while ((*unparsedmodes) && (*unparsedmodes != ',')) - { - ModeHandler *mh = ServerInstance->Modes->FindMode(*unparsedmodes, MODETYPE_CHANNEL); - if (!mh) - { - ServerInstance->Logs->Log("m_spanningtree", SPARSE, "Unrecognised mode %c, dropping link", *unparsedmodes); - return CMD_INVALID; - } - - modes += *unparsedmodes; - usr++; - unparsedmodes++; - } + if (!ProcessModeUUIDPair(item, src_socket, chan, modestackptr)) + return CMD_INVALID; + } - /* Advance past the comma, to the nick */ - usr++; + /* Flush mode stacker if we lost the FJOIN or had equal TS */ + if (apply_other_sides_modes) + CommandFJoin::ApplyModeStack(srcuser, chan, modestack); - /* Check the user actually exists */ - who = ServerInstance->FindUUID(usr); - if (who) - { - /* Check that the user's 'direction' is correct */ - TreeServer* route_back_again = Utils->BestRouteTo(who->server); - if ((!route_back_again) || (route_back_again->GetSocket() != src_socket)) - continue; + return CMD_SUCCESS; +} - /* Add any modes this user had to the mode stack */ - for (std::string::iterator x = modes.begin(); x != modes.end(); ++x) - modestack.Push(*x, who->nick); +bool CommandFJoin::ProcessModeUUIDPair(const std::string& item, TreeSocket* src_socket, Channel* chan, irc::modestacker* modestack) +{ + std::string::size_type comma = item.find(','); - Channel::JoinUser(who, channel.c_str(), true, "", route_back_again->bursting, TS); - } - else - { - ServerInstance->Logs->Log("m_spanningtree",SPARSE, "Ignored nonexistant user %s in fjoin to %s (probably quit?)", usr, channel.c_str()); - continue; - } - } + // Comma not required anymore if the user has no modes + std::string uuid = ((comma == std::string::npos) ? item : item.substr(comma+1)); + User* who = ServerInstance->FindUUID(uuid); + if (!who) + { + // Probably KILLed, ignore + return true; } - /* Flush mode stacker if we lost the FJOIN or had equal TS */ - if (apply_other_sides_modes) + /* Check that the user's 'direction' is correct */ + TreeServer* route_back_again = Utils->BestRouteTo(who->server); + if ((!route_back_again) || (route_back_again->GetSocket() != src_socket)) { - parameterlist stackresult; - stackresult.push_back(channel); + return true; + } - while (modestack.GetStackedLine(stackresult)) + /* Check if the user received at least one mode */ + if ((modestack) && (comma > 0) && (comma != std::string::npos)) + { + /* Iterate through the modes and see if they are valid here, if so, apply */ + std::string::const_iterator commait = item.begin()+comma; + for (std::string::const_iterator i = item.begin(); i != commait; ++i) { - ServerInstance->SendMode(stackresult, srcuser); - stackresult.erase(stackresult.begin() + 1, stackresult.end()); + if (!ServerInstance->Modes->FindMode(*i, MODETYPE_CHANNEL)) + { + ServerInstance->SNO->WriteToSnoMask('d', "Unrecognised mode '%c' for a user in FJOIN, dropping link", *i); + return false; + } + + /* Add any modes this user had to the mode stack */ + modestack->Push(*i, who->nick); } } - return CMD_SUCCESS; + + chan->ForceJoin(who, NULL, route_back_again->bursting); + return true; } -void CommandFJoin::RemoveStatus(User* srcuser, parameterlist ¶ms) +void CommandFJoin::RemoveStatus(Channel* c) { - if (params.size() < 1) - return; - - Channel* c = ServerInstance->FindChan(params[0]); + irc::modestacker stack(false); - if (c) + for (char modeletter = 'A'; modeletter <= 'z'; ++modeletter) { - irc::modestacker stack(false); - parameterlist stackresult; - stackresult.push_back(c->name); + ModeHandler* mh = ServerInstance->Modes->FindMode(modeletter, MODETYPE_CHANNEL); + + /* Passing a pointer to a modestacker here causes the mode to be put onto the mode stack, + * rather than applied immediately. Module unloads require this to be done immediately, + * for this function we require tidyness instead. Fixes bug #493 + */ + if (mh) + mh->RemoveMode(c, stack); + } - for (char modeletter = 'A'; modeletter <= 'z'; ++modeletter) - { - ModeHandler* mh = ServerInstance->Modes->FindMode(modeletter, MODETYPE_CHANNEL); + ApplyModeStack(ServerInstance->FakeClient, c, stack); +} - /* Passing a pointer to a modestacker here causes the mode to be put onto the mode stack, - * rather than applied immediately. Module unloads require this to be done immediately, - * for this function we require tidyness instead. Fixes bug #493 - */ - if (mh) - mh->RemoveMode(c, &stack); - } +void CommandFJoin::ApplyModeStack(User* srcuser, Channel* c, irc::modestacker& stack) +{ + parameterlist stackresult; + stackresult.push_back(c->name); - while (stack.GetStackedLine(stackresult)) - { - ServerInstance->SendMode(stackresult, srcuser); - stackresult.erase(stackresult.begin() + 1, stackresult.end()); - } + while (stack.GetStackedLine(stackresult)) + { + ServerInstance->Modes->Process(stackresult, srcuser, ModeParser::MODE_LOCALONLY); + stackresult.erase(stackresult.begin() + 1, stackresult.end()); } } - diff --git a/src/modules/m_spanningtree/fmode.cpp b/src/modules/m_spanningtree/fmode.cpp index c1e452db6..16af5ccc0 100644 --- a/src/modules/m_spanningtree/fmode.cpp +++ b/src/modules/m_spanningtree/fmode.cpp @@ -21,73 +21,59 @@ #include "inspircd.h" #include "commands.h" -#include "treesocket.h" -#include "treeserver.h" -#include "utils.h" - /** FMODE command - server mode with timestamp checks */ -CmdResult CommandFMode::Handle(const std::vector<std::string>& params, User *who) +CmdResult CommandFMode::Handle(User* who, std::vector<std::string>& params) { - std::string sourceserv = who->server; - - std::vector<std::string> modelist; - time_t TS = 0; - for (unsigned int q = 0; (q < params.size()) && (q < 64); q++) + time_t TS = ConvToInt(params[1]); + if (!TS) { - if (q == 1) - { - /* The timestamp is in this position. - * We don't want to pass that up to the - * server->client protocol! - */ - TS = atoi(params[q].c_str()); - } - else - { - /* Everything else is fine to append to the modelist */ - modelist.push_back(params[q]); - } - + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "*** BUG? *** TS of 0 sent to FMODE. Are some services authors smoking craq, or is it 1970 again?. Dropping link."); + ServerInstance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FMODE with a TS of zero. Total craq, dropping link.", who->server.c_str()); + return CMD_INVALID; } - /* Extract the TS value of the object, either User or Channel */ - User* dst = ServerInstance->FindNick(params[0]); - Channel* chan = NULL; - time_t ourTS = 0; - if (dst) + /* Extract the TS value of the object, either User or Channel */ + time_t ourTS; + if (params[0][0] == '#') { - ourTS = dst->age; + Channel* chan = ServerInstance->FindChan(params[0]); + if (!chan) + /* Oops, channel doesn't exist! */ + return CMD_FAILURE; + + ourTS = chan->age; } else { - chan = ServerInstance->FindChan(params[0]); - if (chan) - { - ourTS = chan->age; - } - else - /* Oops, channel doesnt exist! */ + User* user = ServerInstance->FindUUID(params[0]); + if (!user) return CMD_FAILURE; - } - if (!TS) - { - ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"*** BUG? *** TS of 0 sent to FMODE. Are some services authors smoking craq, or is it 1970 again?. Dropped."); - ServerInstance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FMODE with a TS of zero. Total craq. Mode was dropped.", sourceserv.c_str()); - return CMD_INVALID; + if (IS_SERVER(user)) + return CMD_INVALID; + + ourTS = user->age; } - /* TS is equal or less: Merge the mode changes into ours and pass on. + /* If the TS is greater than ours, we drop the mode and don't pass it anywhere. */ - if (TS <= ourTS) - { - bool merge = (TS == ourTS) && IS_SERVER(who); - ServerInstance->Modes->Process(modelist, who, merge); - return CMD_SUCCESS; - } - /* If the TS is greater than ours, we drop the mode and dont pass it anywhere. + if (TS > ourTS) + return CMD_FAILURE; + + /* TS is equal or less: Merge the mode changes into ours and pass on. */ - return CMD_FAILURE; + std::vector<std::string> modelist; + modelist.reserve(params.size()-1); + /* Insert everything into modelist except the TS (params[1]) */ + modelist.push_back(params[0]); + modelist.insert(modelist.end(), params.begin()+2, params.end()); + + ModeParser::ModeProcessFlag flags = ModeParser::MODE_LOCALONLY; + if ((TS == ourTS) && IS_SERVER(who)) + flags |= ModeParser::MODE_MERGE; + + ServerInstance->Modes->Process(modelist, who, flags); + return CMD_SUCCESS; } diff --git a/src/modules/m_spanningtree/ftopic.cpp b/src/modules/m_spanningtree/ftopic.cpp index d559c6ae5..bd15489a2 100644 --- a/src/modules/m_spanningtree/ftopic.cpp +++ b/src/modules/m_spanningtree/ftopic.cpp @@ -21,31 +21,88 @@ #include "inspircd.h" #include "commands.h" -#include "treesocket.h" -#include "treeserver.h" -#include "utils.h" - /** FTOPIC command */ -CmdResult CommandFTopic::Handle(const std::vector<std::string>& params, User *user) +CmdResult CommandFTopic::Handle(User* user, std::vector<std::string>& params) { - time_t ts = atoi(params[1].c_str()); Channel* c = ServerInstance->FindChan(params[0]); - if (c) + if (!c) + return CMD_FAILURE; + + time_t ChanTS = ConvToInt(params[1]); + if (!ChanTS) + return CMD_INVALID; + + if (c->age < ChanTS) + // Our channel TS is older, nothing to do + return CMD_FAILURE; + + time_t ts = ConvToInt(params[2]); + if (!ts) + return CMD_INVALID; + + // Channel::topicset is initialized to 0 on channel creation, so their ts will always win if we never had a topic + if (ts < c->topicset) + return CMD_FAILURE; + + // The topic text is always the last parameter + const std::string& newtopic = params.back(); + + // If there is a setter in the message use that, otherwise use the message source + const std::string& setter = ((params.size() > 4) ? params[3] : (ServerInstance->Config->FullHostInTopic ? user->GetFullHost() : user->nick)); + + /* + * If the topics were updated at the exact same second, accept + * the remote only when it's "bigger" than ours as defined by + * string comparision, so non-empty topics always overridde + * empty topics if their timestamps are equal + * + * Similarly, if the topic texts are equal too, keep one topic + * setter and discard the other + */ + if (ts == c->topicset) + { + // Discard if their topic text is "smaller" + if (c->topic > newtopic) + return CMD_FAILURE; + + // If the texts are equal in addition to the timestamps, decide which setter to keep + if ((c->topic == newtopic) && (c->setby >= setter)) + return CMD_FAILURE; + } + + if (c->topic != newtopic) { - if ((ts >= c->topicset) || (c->topic.empty())) - { - if (c->topic != params[3]) - { - // Update topic only when it differs from current topic - c->topic.assign(params[3], 0, ServerInstance->Config->Limits.MaxTopic); - c->WriteChannel(user, "TOPIC %s :%s", c->name.c_str(), c->topic.c_str()); - } - - // Always update setter and settime. - c->setby.assign(params[2], 0, 127); - c->topicset = ts; - } + // Update topic only when it differs from current topic + c->topic.assign(newtopic, 0, ServerInstance->Config->Limits.MaxTopic); + c->WriteChannel(user, "TOPIC %s :%s", c->name.c_str(), c->topic.c_str()); } + + // Update setter and settime + c->setby.assign(setter, 0, 128); + c->topicset = ts; + + FOREACH_MOD(OnPostTopicChange, (user, c, c->topic)); + return CMD_SUCCESS; } +// Used when bursting and in reply to RESYNC, contains topic setter as the 4th parameter +CommandFTopic::Builder::Builder(Channel* chan) + : CmdBuilder("FTOPIC") +{ + push(chan->name); + push_int(chan->age); + push_int(chan->topicset); + push(chan->setby); + push_last(chan->topic); +} + +// Used when changing the topic, the setter is the message source +CommandFTopic::Builder::Builder(User* user, Channel* chan) + : CmdBuilder(user, "FTOPIC") +{ + push(chan->name); + push_int(chan->age); + push_int(chan->topicset); + push_last(chan->topic); +} diff --git a/src/modules/m_spanningtree/hmac.cpp b/src/modules/m_spanningtree/hmac.cpp index d990e1fbf..d79f13567 100644 --- a/src/modules/m_spanningtree/hmac.cpp +++ b/src/modules/m_spanningtree/hmac.cpp @@ -19,18 +19,12 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" -#include "../hash.h" -#include "../ssl.h" -#include "socketengine.h" +#include "modules/hash.h" +#include "modules/ssl.h" #include "main.h" -#include "utils.h" -#include "treeserver.h" #include "link.h" #include "treesocket.h" -#include "resolvers.h" const std::string& TreeSocket::GetOurChallenge() { @@ -62,39 +56,10 @@ std::string TreeSocket::MakePass(const std::string &password, const std::string */ HashProvider* sha256 = ServerInstance->Modules->FindDataService<HashProvider>("hash/sha256"); if (Utils->ChallengeResponse && sha256 && !challenge.empty()) - { - if (proto_version < 1202) - { - /* This is how HMAC is done in InspIRCd 1.2: - * - * sha256( (pass xor 0x5c) + sha256((pass xor 0x36) + m) ) - * - * 5c and 36 were chosen as part of the HMAC standard, because they - * flip the bits in a way likely to strengthen the function. - */ - std::string hmac1, hmac2; + return "AUTH:" + BinToBase64(sha256->hmac(password, challenge)); - for (size_t n = 0; n < password.length(); n++) - { - hmac1.push_back(static_cast<char>(password[n] ^ 0x5C)); - hmac2.push_back(static_cast<char>(password[n] ^ 0x36)); - } - - hmac2.append(challenge); - hmac2 = sha256->hexsum(hmac2); - - std::string hmac = hmac1 + hmac2; - hmac = sha256->hexsum(hmac); - - return "HMAC-SHA256:"+ hmac; - } - else - { - return "AUTH:" + BinToBase64(sha256->hmac(password, challenge)); - } - } - else if (!challenge.empty() && !sha256) - ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Not authenticating to server using SHA256/HMAC because we don't have m_sha256 loaded!"); + if (!challenge.empty() && !sha256) + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Not authenticating to server using SHA256/HMAC because we don't have m_sha256 loaded!"); return password; } @@ -104,16 +69,6 @@ bool TreeSocket::ComparePass(const Link& link, const std::string &theirs) capab->auth_fingerprint = !link.Fingerprint.empty(); capab->auth_challenge = !capab->ourchallenge.empty() && !capab->theirchallenge.empty(); - std::string fp; - if (GetIOHook()) - { - SocketCertificateRequest req(this, Utils->Creator); - if (req.cert) - { - fp = req.cert->GetFingerprint(); - } - } - if (capab->auth_challenge) { std::string our_hmac = MakePass(link.RecvPass, capab->ourchallenge); @@ -129,6 +84,7 @@ bool TreeSocket::ComparePass(const Link& link, const std::string &theirs) return false; } + std::string fp = SSLClientCert::GetFingerprint(this); if (capab->auth_fingerprint) { /* Require fingerprint to exist and match */ diff --git a/src/modules/m_spanningtree/idle.cpp b/src/modules/m_spanningtree/idle.cpp index 8bc0cd2bb..d7c0cdf1b 100644 --- a/src/modules/m_spanningtree/idle.cpp +++ b/src/modules/m_spanningtree/idle.cpp @@ -18,67 +18,53 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" -#include "socketengine.h" - -#include "main.h" #include "utils.h" -#include "treeserver.h" -#include "treesocket.h" +#include "commands.h" -bool TreeSocket::Whois(const std::string &prefix, parameterlist ¶ms) +CmdResult CommandIdle::HandleRemote(RemoteUser* issuer, std::vector<std::string>& params) { - if (params.size() < 1) - return true; - User* u = ServerInstance->FindNick(prefix); - if (u) + /** + * There are two forms of IDLE: request and reply. Requests have one parameter, + * replies have more than one. + * + * If this is a request, 'issuer' did a /whois and its server wants to learn the + * idle time of the user in params[0]. + * + * If this is a reply, params[0] is the user who did the whois and params.back() is + * the number of seconds 'issuer' has been idle. + */ + + User* target = ServerInstance->FindUUID(params[0]); + if ((!target) || (IS_SERVER(target))) + return CMD_FAILURE; + + LocalUser* localtarget = IS_LOCAL(target); + if (!localtarget) { - // an incoming request - if (params.size() == 1) - { - User* x = ServerInstance->FindNick(params[0]); - if ((x) && (IS_LOCAL(x))) - { - long idle = abs((long)((x->idle_lastmsg) - ServerInstance->Time())); - parameterlist par; - par.push_back(prefix); - par.push_back(ConvToStr(x->signon)); - par.push_back(ConvToStr(idle)); - // ours, we're done, pass it BACK - Utils->DoOneToOne(params[0], "IDLE", par, u->server); - } - else - { - // not ours pass it on - if (x) - Utils->DoOneToOne(prefix, "IDLE", params, x->server); - } - } - else if (params.size() == 3) - { - std::string who_did_the_whois = params[0]; - User* who_to_send_to = ServerInstance->FindNick(who_did_the_whois); - if ((who_to_send_to) && (IS_LOCAL(who_to_send_to))) - { - // an incoming reply to a whois we sent out - std::string nick_whoised = prefix; - unsigned long signon = atoi(params[1].c_str()); - unsigned long idle = atoi(params[2].c_str()); - if ((who_to_send_to) && (IS_LOCAL(who_to_send_to))) - { - ServerInstance->DoWhois(who_to_send_to, u, signon, idle, nick_whoised.c_str()); - } - } - else - { - // not ours, pass it on - if (who_to_send_to) - Utils->DoOneToOne(prefix, "IDLE", params, who_to_send_to->server); - } - } + // Forward to target's server + return CMD_SUCCESS; } - return true; -} + if (params.size() >= 2) + { + ServerInstance->Parser->CallHandler("WHOIS", params, issuer); + } + else + { + // A server is asking us the idle time of our user + unsigned int idle; + if (localtarget->idle_lastmsg >= ServerInstance->Time()) + // Possible case when our clock ticked backwards + idle = 0; + else + idle = ((unsigned int) (ServerInstance->Time() - localtarget->idle_lastmsg)); + + CmdBuilder reply(params[0], "IDLE"); + reply.push_back(issuer->uuid); + reply.push_back(ConvToStr(target->signon)); + reply.push_back(ConvToStr(idle)); + reply.Unicast(issuer); + } + return CMD_SUCCESS; +} diff --git a/src/modules/m_spanningtree/ijoin.cpp b/src/modules/m_spanningtree/ijoin.cpp new file mode 100644 index 000000000..a579848c8 --- /dev/null +++ b/src/modules/m_spanningtree/ijoin.cpp @@ -0,0 +1,84 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2012-2013 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "inspircd.h" +#include "commands.h" +#include "utils.h" +#include "treeserver.h" +#include "treesocket.h" + +CmdResult CommandIJoin::HandleRemote(RemoteUser* user, std::vector<std::string>& params) +{ + Channel* chan = ServerInstance->FindChan(params[0]); + if (!chan) + { + // Desync detected, recover + // Ignore the join and send RESYNC, this will result in the remote server sending all channel data to us + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Received IJOIN for non-existant channel: " + params[0]); + + CmdBuilder("RESYNC").push(params[0]).Unicast(user); + + return CMD_FAILURE; + } + + bool apply_modes; + if (params.size() > 1) + { + time_t RemoteTS = ConvToInt(params[1]); + if (!RemoteTS) + { + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Invalid TS in IJOIN: " + params[1]); + return CMD_INVALID; + } + + if (RemoteTS < chan->age) + { + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Attempted to lower TS via IJOIN. Channel=" + params[0] + " RemoteTS=" + params[1] + " LocalTS=" + ConvToStr(chan->age)); + return CMD_INVALID; + } + apply_modes = ((params.size() > 2) && (RemoteTS == chan->age)); + } + else + apply_modes = false; + + chan->ForceJoin(user, apply_modes ? ¶ms[2] : NULL); + return CMD_SUCCESS; +} + +CmdResult CommandResync::HandleServer(TreeServer* server, std::vector<std::string>& params) +{ + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Resyncing " + params[0]); + Channel* chan = ServerInstance->FindChan(params[0]); + if (!chan) + { + // This can happen for a number of reasons, safe to ignore + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Channel does not exist"); + return CMD_FAILURE; + } + + if (!server->IsLocal()) + { + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Received RESYNC with a source that is not directly connected: " + server->GetID()); + return CMD_INVALID; + } + + // Send all known information about the channel + server->GetSocket()->SyncChannel(chan); + return CMD_SUCCESS; +} diff --git a/src/modules/m_spanningtree/link.h b/src/modules/m_spanningtree/link.h index 797f108d8..b318c9bf2 100644 --- a/src/modules/m_spanningtree/link.h +++ b/src/modules/m_spanningtree/link.h @@ -18,8 +18,7 @@ */ -#ifndef M_SPANNINGTREE_LINK_H -#define M_SPANNINGTREE_LINK_H +#pragma once class Link : public refcountbase { @@ -51,5 +50,3 @@ class Autoconnect : public refcountbase int position; Autoconnect(ConfigTag* Tag) : tag(Tag) {} }; - -#endif diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp index ce1792a02..9ece3c03d 100644 --- a/src/modules/m_spanningtree/main.cpp +++ b/src/modules/m_spanningtree/main.cpp @@ -21,13 +21,11 @@ */ -/* $ModDesc: Provides a spanning tree server link protocol */ - #include "inspircd.h" #include "socket.h" #include "xline.h" +#include "iohook.h" -#include "cachetimer.h" #include "resolvers.h" #include "main.h" #include "utils.h" @@ -38,56 +36,39 @@ #include "protocolinterface.h" ModuleSpanningTree::ModuleSpanningTree() + : commands(NULL), DNS(this, "DNS") { - Utils = new SpanningTreeUtilities(this); - commands = new SpanningTreeCommands(this); - RefreshTimer = NULL; } SpanningTreeCommands::SpanningTreeCommands(ModuleSpanningTree* module) - : rconnect(module, module->Utils), rsquit(module, module->Utils), + : rconnect(module), rsquit(module), map(module), svsjoin(module), svspart(module), svsnick(module), metadata(module), - uid(module), opertype(module), fjoin(module), fmode(module), ftopic(module), - fhost(module), fident(module), fname(module) + uid(module), opertype(module), fjoin(module), ijoin(module), resync(module), + fmode(module), ftopic(module), fhost(module), fident(module), fname(module), + away(module), addline(module), delline(module), encap(module), idle(module), + nick(module), ping(module), pong(module), push(module), save(module), + server(module), squit(module), snonotice(module), version(module), + burst(module), endburst(module) { } void ModuleSpanningTree::init() { + ServerInstance->SNO->EnableSnomask('l', "LINK"); + + Utils = new SpanningTreeUtilities(this); + Utils->TreeRoot = new TreeServer; + commands = new SpanningTreeCommands(this); ServerInstance->Modules->AddService(commands->rconnect); ServerInstance->Modules->AddService(commands->rsquit); - ServerInstance->Modules->AddService(commands->svsjoin); - ServerInstance->Modules->AddService(commands->svspart); - ServerInstance->Modules->AddService(commands->svsnick); - ServerInstance->Modules->AddService(commands->metadata); - ServerInstance->Modules->AddService(commands->uid); - ServerInstance->Modules->AddService(commands->opertype); - ServerInstance->Modules->AddService(commands->fjoin); - ServerInstance->Modules->AddService(commands->fmode); - ServerInstance->Modules->AddService(commands->ftopic); - ServerInstance->Modules->AddService(commands->fhost); - ServerInstance->Modules->AddService(commands->fident); - ServerInstance->Modules->AddService(commands->fname); - RefreshTimer = new CacheRefreshTimer(Utils); - ServerInstance->Timers->AddTimer(RefreshTimer); - - Implementation eventlist[] = - { - I_OnPreCommand, I_OnGetServerDescription, I_OnUserInvite, I_OnPostTopicChange, - I_OnWallops, I_OnUserNotice, I_OnUserMessage, I_OnBackgroundTimer, I_OnUserJoin, - I_OnChangeHost, I_OnChangeName, I_OnChangeIdent, I_OnUserPart, I_OnUnloadModule, - I_OnUserQuit, I_OnUserPostNick, I_OnUserKick, I_OnRemoteKill, I_OnRehash, I_OnPreRehash, - I_OnOper, I_OnAddLine, I_OnDelLine, I_OnMode, I_OnLoadModule, I_OnStats, - I_OnSetAway, I_OnPostCommand, I_OnUserConnect, I_OnAcceptConnection - }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); + ServerInstance->Modules->AddService(commands->map); delete ServerInstance->PI; - ServerInstance->PI = new SpanningTreeProtocolInterface(Utils); + ServerInstance->PI = new SpanningTreeProtocolInterface; loopCall = false; // update our local user count - Utils->TreeRoot->SetUserCount(ServerInstance->Users->local_users.size()); + Utils->TreeRoot->UserCount = ServerInstance->Users->local_users.size(); } void ModuleSpanningTree::ShowLinks(TreeServer* Current, User* user, int hops) @@ -97,44 +78,40 @@ void ModuleSpanningTree::ShowLinks(TreeServer* Current, User* user, int hops) { Parent = Current->GetParent()->GetName(); } - for (unsigned int q = 0; q < Current->ChildCount(); q++) + + const TreeServer::ChildServers& children = Current->GetChildren(); + for (TreeServer::ChildServers::const_iterator i = children.begin(); i != children.end(); ++i) { - if ((Current->GetChild(q)->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName())))) + TreeServer* server = *i; + if ((server->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(server->GetName())))) { - if (IS_OPER(user)) + if (user->IsOper()) { - ShowLinks(Current->GetChild(q),user,hops+1); + ShowLinks(server, user, hops+1); } } else { - ShowLinks(Current->GetChild(q),user,hops+1); + ShowLinks(server, user, hops+1); } } /* Don't display the line if its a uline, hide ulines is on, and the user isnt an oper */ - if ((Utils->HideULines) && (ServerInstance->ULine(Current->GetName())) && (!IS_OPER(user))) + if ((Utils->HideULines) && (ServerInstance->ULine(Current->GetName())) && (!user->IsOper())) return; /* Or if the server is hidden and they're not an oper */ - else if ((Current->Hidden) && (!IS_OPER(user))) + else if ((Current->Hidden) && (!user->IsOper())) return; - std::string servername = Current->GetName(); - user->WriteNumeric(364, "%s %s %s :%d %s", user->nick.c_str(), servername.c_str(), - (Utils->FlatLinks && (!IS_OPER(user))) ? ServerInstance->Config->ServerName.c_str() : Parent.c_str(), - (Utils->FlatLinks && (!IS_OPER(user))) ? 0 : hops, + user->WriteNumeric(364, "%s %s %s :%d %s", user->nick.c_str(), Current->GetName().c_str(), + (Utils->FlatLinks && (!user->IsOper())) ? ServerInstance->Config->ServerName.c_str() : Parent.c_str(), + (Utils->FlatLinks && (!user->IsOper())) ? 0 : hops, Current->GetDesc().c_str()); } -int ModuleSpanningTree::CountServs() -{ - return Utils->serverlist.size(); -} - void ModuleSpanningTree::HandleLinks(const std::vector<std::string>& parameters, User* user) { ShowLinks(Utils->TreeRoot,user,0); user->WriteNumeric(365, "%s * :End of /LINKS list.",user->nick.c_str()); - return; } std::string ModuleSpanningTree::TimeToStr(time_t secs) @@ -164,62 +141,53 @@ restart: { TreeServer *s = i->second; - if (s->GetSocket() && s->GetSocket()->GetLinkState() == DYING) + // Skip myself + if (s->IsRoot()) + continue; + + if (s->GetSocket()->GetLinkState() == DYING) { s->GetSocket()->Close(); goto restart; } - // Fix for bug #792, do not ping servers that are not connected yet! - // Remote servers have Socket == NULL and local connected servers have - // Socket->LinkState == CONNECTED - if (s->GetSocket() && s->GetSocket()->GetLinkState() != CONNECTED) + // Do not ping servers that are not fully connected yet! + // Servers which are connected to us have IsLocal() == true and if they're fully connected + // then Socket->LinkState == CONNECTED. Servers that are linked to another server are always fully connected. + if (s->IsLocal() && s->GetSocket()->GetLinkState() != CONNECTED) continue; // Now do PING checks on all servers - TreeServer *mts = Utils->BestRouteTo(s->GetID()); - - if (mts) + // Only ping if this server needs one + if (curtime >= s->NextPingTime()) { - // Only ping if this server needs one - if (curtime >= s->NextPingTime()) + // And if they answered the last + if (s->AnsweredLastPing()) { - // And if they answered the last - if (s->AnsweredLastPing()) - { - // They did, send a ping to them - s->SetNextPingTime(curtime + Utils->PingFreq); - TreeSocket *tsock = mts->GetSocket(); - - // ... if we can find a proper route to them - if (tsock) - { - tsock->WriteLine(":" + ServerInstance->Config->GetSID() + " PING " + - ServerInstance->Config->GetSID() + " " + s->GetID()); - s->LastPingMsec = ts; - } - } - else + // They did, send a ping to them + s->SetNextPingTime(curtime + Utils->PingFreq); + s->GetSocket()->WriteLine(":" + ServerInstance->Config->GetSID() + " PING " + s->GetID()); + s->LastPingMsec = ts; + } + else + { + // They didn't answer the last ping, if they are locally connected, get rid of them. + if (s->IsLocal()) { - // They didn't answer the last ping, if they are locally connected, get rid of them. - TreeSocket *sock = s->GetSocket(); - if (sock) - { - sock->SendError("Ping timeout"); - sock->Close(); - goto restart; - } + TreeSocket* sock = s->GetSocket(); + sock->SendError("Ping timeout"); + sock->Close(); + goto restart; } } + } - // If warn on ping enabled and not warned and the difference is sufficient and they didn't answer the last ping... - if ((Utils->PingWarnTime) && (!s->Warned) && (curtime >= s->NextPingTime() - (Utils->PingFreq - Utils->PingWarnTime)) && (!s->AnsweredLastPing())) - { - /* The server hasnt responded, send a warning to opers */ - std::string servername = s->GetName(); - ServerInstance->SNO->WriteToSnoMask('l',"Server \002%s\002 has not responded to PING for %d seconds, high latency.", servername.c_str(), Utils->PingWarnTime); - s->Warned = true; - } + // If warn on ping enabled and not warned and the difference is sufficient and they didn't answer the last ping... + if ((Utils->PingWarnTime) && (!s->Warned) && (curtime >= s->NextPingTime() - (Utils->PingFreq - Utils->PingWarnTime)) && (!s->AnsweredLastPing())) + { + /* The server hasnt responded, send a warning to opers */ + ServerInstance->SNO->WriteToSnoMask('l',"Server \002%s\002 has not responded to PING for %d seconds, high latency.", s->GetName().c_str(), Utils->PingWarnTime); + s->Warned = true; } } } @@ -271,7 +239,7 @@ void ModuleSpanningTree::ConnectServer(Link* x, Autoconnect* y) return; } - QueryType start_type = DNS_QUERY_AAAA; + DNS::QueryType start_type = DNS::QUERY_AAAA; if (strchr(x->IPAddr.c_str(),':')) { in6_addr n; @@ -289,7 +257,7 @@ void ModuleSpanningTree::ConnectServer(Link* x, Autoconnect* y) if (ipvalid) { /* Gave a hook, but it wasnt one we know */ - TreeSocket* newsocket = new TreeSocket(Utils, x, y, x->IPAddr); + TreeSocket* newsocket = new TreeSocket(x, y, x->IPAddr); if (newsocket->GetFd() > -1) { /* Handled automatically on success */ @@ -301,16 +269,20 @@ void ModuleSpanningTree::ConnectServer(Link* x, Autoconnect* y) ServerInstance->GlobalCulls.AddItem(newsocket); } } + else if (!DNS) + { + ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: Hostname given and m_dns.so is not loaded, unable to resolve.", x->Name.c_str()); + } else { + ServernameResolver* snr = new ServernameResolver(*DNS, x->IPAddr, x, start_type, y); try { - bool cached = false; - ServernameResolver* snr = new ServernameResolver(Utils, x->IPAddr, x, cached, start_type, y); - ServerInstance->AddResolver(snr, cached); + DNS->Process(snr); } - catch (ModuleException& e) + catch (DNS::Exception& e) { + delete snr; ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(), e.GetReason()); ConnectServer(y, false); } @@ -359,12 +331,13 @@ ModResult ModuleSpanningTree::HandleVersion(const std::vector<std::string>& para TreeServer* found = Utils->FindServerMask(parameters[0]); if (found) { - std::string Version = found->GetVersion(); - user->WriteNumeric(351, "%s :%s",user->nick.c_str(),Version.c_str()); if (found == Utils->TreeRoot) { - ServerInstance->Config->Send005(user); + // Pass to default VERSION handler. + return MOD_RES_PASSTHRU; } + std::string Version = found->GetVersion(); + user->WriteNumeric(351, "%s :%s",user->nick.c_str(),Version.c_str()); } else { @@ -377,15 +350,11 @@ ModResult ModuleSpanningTree::HandleVersion(const std::vector<std::string>& para */ void ModuleSpanningTree::RemoteMessage(User* user, const char* format, ...) { - char text[MAXBUF]; - va_list argsPtr; - - va_start(argsPtr, format); - vsnprintf(text, MAXBUF, format, argsPtr); - va_end(argsPtr); + std::string text; + VAFORMAT(text, format, format); if (IS_LOCAL(user)) - user->WriteServ("NOTICE %s :%s", user->nick.c_str(), text); + user->WriteNotice(text); else ServerInstance->PI->SendUserNotice(user, text); } @@ -412,8 +381,7 @@ ModResult ModuleSpanningTree::HandleConnect(const std::vector<std::string>& para } else { - std::string servername = CheckDupe->GetParent()->GetName(); - RemoteMessage(user, "*** CONNECT: Server \002%s\002 already exists on the network and is connected via \002%s\002", x->Name.c_str(), servername.c_str()); + RemoteMessage(user, "*** CONNECT: Server \002%s\002 already exists on the network and is connected via \002%s\002", x->Name.c_str(), CheckDupe->GetParent()->GetName().c_str()); return MOD_RES_DENY; } } @@ -422,6 +390,11 @@ ModResult ModuleSpanningTree::HandleConnect(const std::vector<std::string>& para return MOD_RES_DENY; } +void ModuleSpanningTree::On005Numeric(std::map<std::string, std::string>& tokens) +{ + tokens["MAP"]; +} + void ModuleSpanningTree::OnGetServerDescription(const std::string &servername,std::string &description) { TreeServer* s = Utils->FindServer(servername); @@ -435,11 +408,11 @@ void ModuleSpanningTree::OnUserInvite(User* source,User* dest,Channel* channel, { if (IS_LOCAL(source)) { - parameterlist params; + CmdBuilder params(source, "INVITE"); params.push_back(dest->uuid); params.push_back(channel->name); params.push_back(ConvToStr(expiry)); - Utils->DoOneToMany(source->uuid,"INVITE",params); + params.Broadcast(); } } @@ -449,123 +422,37 @@ void ModuleSpanningTree::OnPostTopicChange(User* user, Channel* chan, const std: if (!IS_LOCAL(user)) return; - parameterlist params; - params.push_back(chan->name); - params.push_back(":"+topic); - Utils->DoOneToMany(user->uuid,"TOPIC",params); + CommandFTopic::Builder(user, chan).Broadcast(); } -void ModuleSpanningTree::OnWallops(User* user, const std::string &text) +void ModuleSpanningTree::OnUserMessage(User* user, void* dest, int target_type, const std::string& text, char status, const CUList& exempt_list, MessageType msgtype) { - if (IS_LOCAL(user)) - { - parameterlist params; - params.push_back(":"+text); - Utils->DoOneToMany(user->uuid,"WALLOPS",params); - } -} - -void ModuleSpanningTree::OnUserNotice(User* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list) -{ - /* Server origin */ - if (user == NULL) - return; - - if (target_type == TYPE_USER) - { - User* d = (User*)dest; - if (!IS_LOCAL(d) && IS_LOCAL(user)) - { - parameterlist params; - params.push_back(d->uuid); - params.push_back(":"+text); - Utils->DoOneToOne(user->uuid,"NOTICE",params,d->server); - } - } - else if (target_type == TYPE_CHANNEL) - { - if (IS_LOCAL(user)) - { - Channel *c = (Channel*)dest; - if (c) - { - std::string cname = c->name; - if (status) - cname = status + cname; - TreeServerList list; - Utils->GetListOfServersForChannel(c,list,status,exempt_list); - for (TreeServerList::iterator i = list.begin(); i != list.end(); i++) - { - TreeSocket* Sock = i->second->GetSocket(); - if (Sock) - Sock->WriteLine(":"+std::string(user->uuid)+" NOTICE "+cname+" :"+text); - } - } - } - } - else if (target_type == TYPE_SERVER) - { - if (IS_LOCAL(user)) - { - char* target = (char*)dest; - parameterlist par; - par.push_back(target); - par.push_back(":"+text); - Utils->DoOneToMany(user->uuid,"NOTICE",par); - } - } -} - -void ModuleSpanningTree::OnUserMessage(User* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list) -{ - /* Server origin */ - if (user == NULL) + if (!IS_LOCAL(user)) return; + const char* message_type = (msgtype == MSG_PRIVMSG ? "PRIVMSG" : "NOTICE"); if (target_type == TYPE_USER) { - // route private messages which are targetted at clients only to the server - // which needs to receive them - User* d = (User*)dest; - if (!IS_LOCAL(d) && (IS_LOCAL(user))) + User* d = (User*) dest; + if (!IS_LOCAL(d)) { - parameterlist params; + CmdBuilder params(user, message_type); params.push_back(d->uuid); - params.push_back(":"+text); - Utils->DoOneToOne(user->uuid,"PRIVMSG",params,d->server); + params.push_last(text); + params.Unicast(d); } } else if (target_type == TYPE_CHANNEL) { - if (IS_LOCAL(user)) - { - Channel *c = (Channel*)dest; - if (c) - { - std::string cname = c->name; - if (status) - cname = status + cname; - TreeServerList list; - Utils->GetListOfServersForChannel(c,list,status,exempt_list); - for (TreeServerList::iterator i = list.begin(); i != list.end(); i++) - { - TreeSocket* Sock = i->second->GetSocket(); - if (Sock) - Sock->WriteLine(":"+std::string(user->uuid)+" PRIVMSG "+cname+" :"+text); - } - } - } + Utils->SendChannelMessage(user->uuid, (Channel*)dest, text, status, exempt_list, message_type); } else if (target_type == TYPE_SERVER) { - if (IS_LOCAL(user)) - { - char* target = (char*)dest; - parameterlist par; - par.push_back(target); - par.push_back(":"+text); - Utils->DoOneToMany(user->uuid,"PRIVMSG",par); - } + char* target = (char*) dest; + CmdBuilder par(user, message_type); + par.push_back(target); + par.push_last(text); + par.Broadcast(); } } @@ -581,25 +468,10 @@ void ModuleSpanningTree::OnUserConnect(LocalUser* user) if (user->quitting) return; - parameterlist params; - params.push_back(user->uuid); - params.push_back(ConvToStr(user->age)); - params.push_back(user->nick); - params.push_back(user->host); - params.push_back(user->dhost); - params.push_back(user->ident); - params.push_back(user->GetIPString()); - params.push_back(ConvToStr(user->signon)); - params.push_back("+"+std::string(user->FormatModes(true))); - params.push_back(":"+user->fullname); - Utils->DoOneToMany(ServerInstance->Config->GetSID(), "UID", params); + CommandUID::Builder(user).Broadcast(); - if (IS_OPER(user)) - { - params.clear(); - params.push_back(user->oper->name); - Utils->DoOneToMany(user->uuid,"OPERTYPE",params); - } + if (user->IsOper()) + CommandOpertype::Builder(user).Broadcast(); for(Extensible::ExtensibleStore::const_iterator i = user->GetExtList().begin(); i != user->GetExtList().end(); i++) { @@ -609,23 +481,34 @@ void ModuleSpanningTree::OnUserConnect(LocalUser* user) ServerInstance->PI->SendMetaData(user, item->name, value); } - Utils->TreeRoot->SetUserCount(1); // increment by 1 + Utils->TreeRoot->UserCount++; } -void ModuleSpanningTree::OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) +void ModuleSpanningTree::OnUserJoin(Membership* memb, bool sync, bool created_by_local, CUList& excepts) { // Only do this for local users - if (IS_LOCAL(memb->user)) + if (!IS_LOCAL(memb->user)) + return; + + if (created_by_local) { - parameterlist params; - // set up their permissions and the channel TS with FJOIN. - // All users are FJOINed now, because a module may specify - // new joining permissions for the user. + CmdBuilder params("FJOIN"); params.push_back(memb->chan->name); params.push_back(ConvToStr(memb->chan->age)); - params.push_back(std::string("+") + memb->chan->ChanModes(true)); - params.push_back(memb->modes+","+memb->user->uuid); - Utils->DoOneToMany(ServerInstance->Config->GetSID(),"FJOIN",params); + params.push_raw(" +").push_raw(memb->chan->ChanModes(true)); + params.push(memb->modes).push_raw(',').push_raw(memb->user->uuid); + params.Broadcast(); + } + else + { + CmdBuilder params(memb->user, "IJOIN"); + params.push_back(memb->chan->name); + if (!memb->modes.empty()) + { + params.push_back(ConvToStr(memb->chan->age)); + params.push_back(memb->modes); + } + params.Broadcast(); } } @@ -634,9 +517,7 @@ void ModuleSpanningTree::OnChangeHost(User* user, const std::string &newhost) if (user->registered != REG_ALL || !IS_LOCAL(user)) return; - parameterlist params; - params.push_back(newhost); - Utils->DoOneToMany(user->uuid,"FHOST",params); + CmdBuilder(user, "FHOST").push(newhost).Broadcast(); } void ModuleSpanningTree::OnChangeName(User* user, const std::string &gecos) @@ -644,9 +525,7 @@ void ModuleSpanningTree::OnChangeName(User* user, const std::string &gecos) if (user->registered != REG_ALL || !IS_LOCAL(user)) return; - parameterlist params; - params.push_back(gecos); - Utils->DoOneToMany(user->uuid,"FNAME",params); + CmdBuilder(user, "FNAME").push(gecos).Broadcast(); } void ModuleSpanningTree::OnChangeIdent(User* user, const std::string &ident) @@ -654,20 +533,18 @@ void ModuleSpanningTree::OnChangeIdent(User* user, const std::string &ident) if ((user->registered != REG_ALL) || (!IS_LOCAL(user))) return; - parameterlist params; - params.push_back(ident); - Utils->DoOneToMany(user->uuid,"FIDENT",params); + CmdBuilder(user, "FIDENT").push(ident).Broadcast(); } void ModuleSpanningTree::OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts) { if (IS_LOCAL(memb->user)) { - parameterlist params; + CmdBuilder params(memb->user, "PART"); params.push_back(memb->chan->name); if (!partmessage.empty()) - params.push_back(":"+partmessage); - Utils->DoOneToMany(memb->user->uuid,"PART",params); + params.push_last(partmessage); + params.Broadcast(); } } @@ -675,23 +552,17 @@ void ModuleSpanningTree::OnUserQuit(User* user, const std::string &reason, const { if ((IS_LOCAL(user)) && (user->registered == REG_ALL)) { - parameterlist params; - if (oper_message != reason) - { - params.push_back(":"+oper_message); - Utils->DoOneToMany(user->uuid,"OPERQUIT",params); - } - params.clear(); - params.push_back(":"+reason); - Utils->DoOneToMany(user->uuid,"QUIT",params); + ServerInstance->PI->SendMetaData(user, "operquit", oper_message); + + CmdBuilder(user, "QUIT").push_last(reason).Broadcast(); } // Regardless, We need to modify the user Counts.. TreeServer* SourceServer = Utils->FindServer(user->server); if (SourceServer) { - SourceServer->SetUserCount(-1); // decrement by 1 + SourceServer->UserCount--; } } @@ -699,7 +570,7 @@ void ModuleSpanningTree::OnUserPostNick(User* user, const std::string &oldnick) { if (IS_LOCAL(user)) { - parameterlist params; + CmdBuilder params(user, "NICK"); params.push_back(user->nick); /** IMPORTANT: We don't update the TS if the oldnick is just a case change of the newnick! @@ -708,46 +579,27 @@ void ModuleSpanningTree::OnUserPostNick(User* user, const std::string &oldnick) user->age = ServerInstance->Time(); params.push_back(ConvToStr(user->age)); - Utils->DoOneToMany(user->uuid,"NICK",params); + params.Broadcast(); } else if (!loopCall && user->nick == user->uuid) { - parameterlist params; + CmdBuilder params("SAVE"); params.push_back(user->uuid); params.push_back(ConvToStr(user->age)); - Utils->DoOneToMany(ServerInstance->Config->GetSID(),"SAVE",params); + params.Broadcast(); } } void ModuleSpanningTree::OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) { - parameterlist params; + if ((!IS_LOCAL(source) || source != ServerInstance->FakeClient)) + return; + + CmdBuilder params(source, "KICK"); params.push_back(memb->chan->name); params.push_back(memb->user->uuid); - params.push_back(":"+reason); - if (IS_LOCAL(source)) - { - Utils->DoOneToMany(source->uuid,"KICK",params); - } - else if (source == ServerInstance->FakeClient) - { - Utils->DoOneToMany(ServerInstance->Config->GetSID(),"KICK",params); - } -} - -void ModuleSpanningTree::OnRemoteKill(User* source, User* dest, const std::string &reason, const std::string &operreason) -{ - if (!IS_LOCAL(source)) - return; // Only start routing if we're origin. - - ServerInstance->OperQuit.set(dest, operreason); - parameterlist params; - params.push_back(":"+operreason); - Utils->DoOneToMany(dest->uuid,"OPERQUIT",params); - params.clear(); - params.push_back(dest->uuid); - params.push_back(":"+reason); - Utils->DoOneToMany(source->uuid,"KILL",params); + params.push_last(reason); + params.Broadcast(); } void ModuleSpanningTree::OnPreRehash(User* user, const std::string ¶meter) @@ -755,14 +607,14 @@ void ModuleSpanningTree::OnPreRehash(User* user, const std::string ¶meter) if (loopCall) return; // Don't generate a REHASH here if we're in the middle of processing a message that generated this one - ServerInstance->Logs->Log("remoterehash", DEBUG, "called with param %s", parameter.c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "OnPreRehash called with param %s", parameter.c_str()); // Send out to other servers if (!parameter.empty() && parameter[0] != '-') { - parameterlist params; + CmdBuilder params((user ? user->uuid : ServerInstance->Config->GetSID()), "REHASH"); params.push_back(parameter); - Utils->DoOneToAllButSender(user ? user->uuid : ServerInstance->Config->GetSID(), "REHASH", params, user ? user->server : ServerInstance->Config->ServerName); + params.Forward(user ? Utils->BestRouteTo(user->server) : NULL); } } @@ -802,14 +654,16 @@ void ModuleSpanningTree::OnLoadModule(Module* mod) void ModuleSpanningTree::OnUnloadModule(Module* mod) { + if (!Utils) + return; ServerInstance->PI->SendMetaData(NULL, "modules", "-" + mod->ModuleSourceFile); - unsigned int items = Utils->TreeRoot->ChildCount(); - for(unsigned int x = 0; x < items; x++) + // Close all connections which use an IO hook provided by this module + const TreeServer::ChildServers& list = Utils->TreeRoot->GetChildren(); + for (TreeServer::ChildServers::const_iterator i = list.begin(); i != list.end(); ++i) { - TreeServer* srv = Utils->TreeRoot->GetChild(x); - TreeSocket* sock = srv->GetSocket(); - if (sock && sock->GetIOHook() == mod) + TreeSocket* sock = (*i)->GetSocket(); + if (sock && sock->GetIOHook() && sock->GetIOHook()->creator == mod) { sock->SendError("SSL module unloaded"); sock->Close(); @@ -819,7 +673,7 @@ void ModuleSpanningTree::OnUnloadModule(Module* mod) for (SpanningTreeUtilities::TimeoutList::const_iterator i = Utils->timeoutlist.begin(); i != Utils->timeoutlist.end(); ++i) { TreeSocket* sock = i->first; - if (sock->GetIOHook() == mod) + if (sock->GetIOHook() && sock->GetIOHook()->creator == mod) sock->Close(); } } @@ -831,96 +685,38 @@ void ModuleSpanningTree::OnOper(User* user, const std::string &opertype) { if (user->registered != REG_ALL || !IS_LOCAL(user)) return; - parameterlist params; - params.push_back(opertype); - Utils->DoOneToMany(user->uuid,"OPERTYPE",params); + CommandOpertype::Builder(user).Broadcast(); } void ModuleSpanningTree::OnAddLine(User* user, XLine *x) { - if (!x->IsBurstable() || loopCall) + if (!x->IsBurstable() || loopCall || (user && !IS_LOCAL(user))) return; - parameterlist params; - params.push_back(x->type); - params.push_back(x->Displayable()); - params.push_back(ServerInstance->Config->ServerName); - params.push_back(ConvToStr(x->set_time)); - params.push_back(ConvToStr(x->duration)); - params.push_back(":" + x->reason); - if (!user) - { - /* Server-set lines */ - Utils->DoOneToMany(ServerInstance->Config->GetSID(), "ADDLINE", params); - } - else if (IS_LOCAL(user)) - { - /* User-set lines */ - Utils->DoOneToMany(user->uuid, "ADDLINE", params); - } + user = ServerInstance->FakeClient; + + CommandAddLine::Builder(x, user).Broadcast(); } void ModuleSpanningTree::OnDelLine(User* user, XLine *x) { - if (!x->IsBurstable() || loopCall) + if (!x->IsBurstable() || loopCall || (user && !IS_LOCAL(user))) return; - parameterlist params; - params.push_back(x->type); - params.push_back(x->Displayable()); - if (!user) - { - /* Server-unset lines */ - Utils->DoOneToMany(ServerInstance->Config->GetSID(), "DELLINE", params); - } - else if (IS_LOCAL(user)) - { - /* User-unset lines */ - Utils->DoOneToMany(user->uuid, "DELLINE", params); - } -} + user = ServerInstance->FakeClient; -void ModuleSpanningTree::OnMode(User* user, void* dest, int target_type, const parameterlist &text, const std::vector<TranslateType> &translate) -{ - if ((IS_LOCAL(user)) && (user->registered == REG_ALL)) - { - parameterlist params; - std::string output_text; - - ServerInstance->Parser->TranslateUIDs(translate, text, output_text); - - if (target_type == TYPE_USER) - { - User* u = (User*)dest; - params.push_back(u->uuid); - params.push_back(output_text); - Utils->DoOneToMany(user->uuid, "MODE", params); - } - else - { - Channel* c = (Channel*)dest; - params.push_back(c->name); - params.push_back(ConvToStr(c->age)); - params.push_back(output_text); - Utils->DoOneToMany(user->uuid, "FMODE", params); - } - } + CmdBuilder params(user, "DELLINE"); + params.push_back(x->type); + params.push_back(x->Displayable()); + params.Broadcast(); } ModResult ModuleSpanningTree::OnSetAway(User* user, const std::string &awaymsg) { if (IS_LOCAL(user)) - { - parameterlist params; - if (!awaymsg.empty()) - { - params.push_back(ConvToStr(user->awaytime)); - params.push_back(":" + awaymsg); - } - Utils->DoOneToMany(user->uuid, "AWAY", params); - } + CommandAway::Builder(user, awaymsg).Broadcast(); return MOD_RES_PASSTHRU; } @@ -928,9 +724,7 @@ ModResult ModuleSpanningTree::OnSetAway(User* user, const std::string &awaymsg) void ModuleSpanningTree::ProtoSendMode(void* opaque, TargetTypeFlags target_type, void* target, const parameterlist &modeline, const std::vector<TranslateType> &translate) { TreeSocket* s = (TreeSocket*)opaque; - std::string output_text; - - ServerInstance->Parser->TranslateUIDs(translate, modeline, output_text); + std::string output_text = CommandParser::TranslateUIDs(translate, modeline); if (target) { @@ -955,15 +749,15 @@ void ModuleSpanningTree::ProtoSendMetaData(void* opaque, Extensible* target, con if (u) s->WriteLine(":"+ServerInstance->Config->GetSID()+" METADATA "+u->uuid+" "+extname+" :"+extdata); else if (c) - s->WriteLine(":"+ServerInstance->Config->GetSID()+" METADATA "+c->name+" "+extname+" :"+extdata); + s->WriteLine(":"+ServerInstance->Config->GetSID()+" METADATA "+c->name+" "+ConvToStr(c->age)+" "+extname+" :"+extdata); else if (!target) s->WriteLine(":"+ServerInstance->Config->GetSID()+" METADATA * "+extname+" :"+extdata); } CullResult ModuleSpanningTree::cull() { - Utils->cull(); - ServerInstance->Timers->DelTimer(RefreshTimer); + if (Utils) + Utils->cull(); return this->Module::cull(); } diff --git a/src/modules/m_spanningtree/main.h b/src/modules/m_spanningtree/main.h index ae6e2e602..f03a36db2 100644 --- a/src/modules/m_spanningtree/main.h +++ b/src/modules/m_spanningtree/main.h @@ -21,11 +21,11 @@ */ -#ifndef M_SPANNINGTREE_MAIN_H -#define M_SPANNINGTREE_MAIN_H +#pragma once #include "inspircd.h" -#include <stdarg.h> +#include "modules/dns.h" +#include "servercommand.h" /** If you make a change which breaks the protocol, increment this. * If you completely change the protocol, completely change the number. @@ -36,8 +36,8 @@ * Failure to document your protocol changes will result in a painfully * painful death by pain. You have been warned. */ -const long ProtocolVersion = 1202; -const long MinCompatProtocol = 1201; +const long ProtocolVersion = 1205; +const long MinCompatProtocol = 1202; /** Forward declarations */ @@ -55,9 +55,10 @@ class ModuleSpanningTree : public Module SpanningTreeCommands* commands; public: - SpanningTreeUtilities* Utils; + dynamic_reference<DNS::Manager> DNS; + + ServerCommandManager CmdManager; - CacheRefreshTimer *RefreshTimer; /** Set to true if inside a spanningtree call, to prevent sending * xlines and other things back to their source */ @@ -66,28 +67,16 @@ class ModuleSpanningTree : public Module /** Constructor */ ModuleSpanningTree(); - void init(); + void init() CXX11_OVERRIDE; /** Shows /LINKS */ void ShowLinks(TreeServer* Current, User* user, int hops); - /** Counts local and remote servers - */ - int CountServs(); - /** Handle LINKS command */ void HandleLinks(const std::vector<std::string>& parameters, User* user); - /** Show MAP output to a user (recursive) - */ - void ShowMap(TreeServer* Current, User* user, int depth, int &line, char* names, int &maxnamew, char* stats); - - /** Handle MAP command - */ - bool HandleMap(const std::vector<std::string>& parameters, User* user); - /** Handle SQUIT */ ModResult HandleSquit(const std::vector<std::string>& parameters, User* user); @@ -128,55 +117,46 @@ class ModuleSpanningTree : public Module */ void RemoteMessage(User* user, const char* format, ...) CUSTOM_PRINTF(3, 4); - /** Returns oper-specific MAP information - */ - const std::string MapOperInfo(TreeServer* Current); - /** Display a time as a human readable string */ - std::string TimeToStr(time_t secs); + static std::string TimeToStr(time_t secs); /** ** *** MODULE EVENTS *** **/ - ModResult OnPreCommand(std::string &command, std::vector<std::string>& parameters, LocalUser *user, bool validated, const std::string &original_line); - void OnPostCommand(const std::string &command, const std::vector<std::string>& parameters, LocalUser *user, CmdResult result, const std::string &original_line); - void OnGetServerDescription(const std::string &servername,std::string &description); - void OnUserConnect(LocalUser* source); - void OnUserInvite(User* source,User* dest,Channel* channel, time_t); - void OnPostTopicChange(User* user, Channel* chan, const std::string &topic); - void OnWallops(User* user, const std::string &text); - void OnUserNotice(User* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list); - void OnUserMessage(User* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list); - void OnBackgroundTimer(time_t curtime); - void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts); - void OnChangeHost(User* user, const std::string &newhost); - void OnChangeName(User* user, const std::string &gecos); - void OnChangeIdent(User* user, const std::string &ident); - void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts); - void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message); - void OnUserPostNick(User* user, const std::string &oldnick); - void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts); - void OnRemoteKill(User* source, User* dest, const std::string &reason, const std::string &operreason); - void OnPreRehash(User* user, const std::string ¶meter); - void OnRehash(User* user); - void OnOper(User* user, const std::string &opertype); + ModResult OnPreCommand(std::string &command, std::vector<std::string>& parameters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE; + void OnPostCommand(Command*, const std::vector<std::string>& parameters, LocalUser* user, CmdResult result, const std::string& original_line) CXX11_OVERRIDE; + void OnGetServerDescription(const std::string &servername,std::string &description) CXX11_OVERRIDE; + void OnUserConnect(LocalUser* source) CXX11_OVERRIDE; + void OnUserInvite(User* source,User* dest,Channel* channel, time_t) CXX11_OVERRIDE; + void OnPostTopicChange(User* user, Channel* chan, const std::string &topic) CXX11_OVERRIDE; + void OnUserMessage(User* user, void* dest, int target_type, const std::string& text, char status, const CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE; + void OnBackgroundTimer(time_t curtime) CXX11_OVERRIDE; + void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) CXX11_OVERRIDE; + void OnChangeHost(User* user, const std::string &newhost) CXX11_OVERRIDE; + void OnChangeName(User* user, const std::string &gecos) CXX11_OVERRIDE; + void OnChangeIdent(User* user, const std::string &ident) CXX11_OVERRIDE; + void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts) CXX11_OVERRIDE; + void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message) CXX11_OVERRIDE; + void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE; + void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) CXX11_OVERRIDE; + void OnPreRehash(User* user, const std::string ¶meter) CXX11_OVERRIDE; + void OnRehash(User* user) CXX11_OVERRIDE; + void OnOper(User* user, const std::string &opertype) CXX11_OVERRIDE; void OnLine(User* source, const std::string &host, bool adding, char linetype, long duration, const std::string &reason); - void OnAddLine(User *u, XLine *x); - void OnDelLine(User *u, XLine *x); - void OnMode(User* user, void* dest, int target_type, const std::vector<std::string> &text, const std::vector<TranslateType> &translate); - ModResult OnStats(char statschar, User* user, string_list &results); - ModResult OnSetAway(User* user, const std::string &awaymsg); + void OnAddLine(User *u, XLine *x) CXX11_OVERRIDE; + void OnDelLine(User *u, XLine *x) CXX11_OVERRIDE; + ModResult OnStats(char statschar, User* user, string_list &results) CXX11_OVERRIDE; + ModResult OnSetAway(User* user, const std::string &awaymsg) CXX11_OVERRIDE; void ProtoSendMode(void* opaque, TargetTypeFlags target_type, void* target, const std::vector<std::string> &modeline, const std::vector<TranslateType> &translate); void ProtoSendMetaData(void* opaque, Extensible* target, const std::string &extname, const std::string &extdata); - void OnLoadModule(Module* mod); - void OnUnloadModule(Module* mod); - ModResult OnAcceptConnection(int newsock, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server); + void OnLoadModule(Module* mod) CXX11_OVERRIDE; + void OnUnloadModule(Module* mod) CXX11_OVERRIDE; + ModResult OnAcceptConnection(int newsock, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE; + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE; CullResult cull(); ~ModuleSpanningTree(); - Version GetVersion(); + Version GetVersion() CXX11_OVERRIDE; void Prioritize(); }; - -#endif diff --git a/src/modules/m_spanningtree/metadata.cpp b/src/modules/m_spanningtree/metadata.cpp index a584f8fa8..5dea7ffae 100644 --- a/src/modules/m_spanningtree/metadata.cpp +++ b/src/modules/m_spanningtree/metadata.cpp @@ -21,39 +21,79 @@ #include "inspircd.h" #include "commands.h" -#include "treesocket.h" -#include "treeserver.h" -#include "utils.h" - -CmdResult CommandMetadata::Handle(const std::vector<std::string>& params, User *srcuser) +CmdResult CommandMetadata::Handle(User* srcuser, std::vector<std::string>& params) { - std::string value = params.size() < 3 ? "" : params[2]; - ExtensionItem* item = ServerInstance->Extensions.GetItem(params[1]); if (params[0] == "*") { - FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(NULL,params[1],value)); + std::string value = params.size() < 3 ? "" : params[2]; + FOREACH_MOD(OnDecodeMetaData, (NULL,params[1],value)); + return CMD_SUCCESS; } - else if (*(params[0].c_str()) == '#') + + if (params[0][0] == '#') { + // Channel METADATA has an additional parameter: the channel TS + // :22D METADATA #channel 12345 extname :extdata + if (params.size() < 3) + return CMD_INVALID; + Channel* c = ServerInstance->FindChan(params[0]); - if (c) - { - if (item) - item->unserialize(FORMAT_NETWORK, c, value); - FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(c,params[1],value)); - } + if (!c) + return CMD_FAILURE; + + time_t ChanTS = ConvToInt(params[1]); + if (!ChanTS) + return CMD_INVALID; + + if (c->age < ChanTS) + // Their TS is newer than ours, discard this command and do not propagate + return CMD_FAILURE; + + std::string value = params.size() < 4 ? "" : params[3]; + + ExtensionItem* item = ServerInstance->Extensions.GetItem(params[2]); + if (item) + item->unserialize(FORMAT_NETWORK, c, value); + FOREACH_MOD(OnDecodeMetaData, (c,params[2],value)); } - else if (*(params[0].c_str()) != '#') + else { User* u = ServerInstance->FindUUID(params[0]); if ((u) && (!IS_SERVER(u))) { + ExtensionItem* item = ServerInstance->Extensions.GetItem(params[1]); + std::string value = params.size() < 3 ? "" : params[2]; + if (item) item->unserialize(FORMAT_NETWORK, u, value); - FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(u,params[1],value)); + FOREACH_MOD(OnDecodeMetaData, (u,params[1],value)); } } return CMD_SUCCESS; } +CommandMetadata::Builder::Builder(User* user, const std::string& key, const std::string& val) + : CmdBuilder("METADATA") +{ + push(user->uuid); + push(key); + push_last(val); +} + +CommandMetadata::Builder::Builder(Channel* chan, const std::string& key, const std::string& val) + : CmdBuilder("METADATA") +{ + push(chan->name); + push_int(chan->age); + push(key); + push_last(val); +} + +CommandMetadata::Builder::Builder(const std::string& key, const std::string& val) + : CmdBuilder("METADATA") +{ + push("*"); + push(key); + push_last(val); +} diff --git a/src/modules/m_spanningtree/misccommands.cpp b/src/modules/m_spanningtree/misccommands.cpp new file mode 100644 index 000000000..5b04c73bc --- /dev/null +++ b/src/modules/m_spanningtree/misccommands.cpp @@ -0,0 +1,48 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> + * Copyright (C) 2007-2008, 2012 Robin Burchell <robin+git@viroteck.net> + * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> + * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> + * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> + * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> + * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "inspircd.h" + +#include "main.h" +#include "commands.h" +#include "treeserver.h" + +CmdResult CommandSNONotice::Handle(User* user, std::vector<std::string>& params) +{ + ServerInstance->SNO->WriteToSnoMask(params[0][0], "From " + user->nick + ": " + params[1]); + return CMD_SUCCESS; +} + +CmdResult CommandBurst::HandleServer(TreeServer* server, std::vector<std::string>& params) +{ + server->bursting = true; + return CMD_SUCCESS; +} + +CmdResult CommandEndBurst::HandleServer(TreeServer* server, std::vector<std::string>& params) +{ + server->FinishBurst(); + return CMD_SUCCESS; +} diff --git a/src/modules/m_spanningtree/netburst.cpp b/src/modules/m_spanningtree/netburst.cpp index d508c092d..d4669442a 100644 --- a/src/modules/m_spanningtree/netburst.cpp +++ b/src/modules/m_spanningtree/netburst.cpp @@ -21,11 +21,12 @@ #include "inspircd.h" #include "xline.h" +#include "listmode.h" #include "treesocket.h" #include "treeserver.h" -#include "utils.h" #include "main.h" +#include "commands.h" /** This function is called when we want to send a netburst to a local * server. There is a set order we must do this, because for example @@ -34,9 +35,8 @@ */ void TreeSocket::DoBurst(TreeServer* s) { - std::string servername = s->GetName(); ServerInstance->SNO->WriteToSnoMask('l',"Bursting to \2%s\2 (Authentication: %s%s).", - servername.c_str(), + s->GetName().c_str(), capab->auth_fingerprint ? "SSL Fingerprint and " : "", capab->auth_challenge ? "challenge-response" : "plaintext password"); this->CleanNegotiationInfo(); @@ -44,42 +44,38 @@ void TreeSocket::DoBurst(TreeServer* s) /* send our version string */ this->WriteLine(":" + ServerInstance->Config->GetSID() + " VERSION :"+ServerInstance->GetVersionString()); /* Send server tree */ - this->SendServers(Utils->TreeRoot,s,1); + this->SendServers(Utils->TreeRoot, s); /* Send users and their oper status */ this->SendUsers(); - /* Send everything else (channel modes, xlines etc) */ - this->SendChannelModes(); + + for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); ++i) + SyncChannel(i->second); + this->SendXLines(); - FOREACH_MOD(I_OnSyncNetwork,OnSyncNetwork(Utils->Creator,(void*)this)); + FOREACH_MOD(OnSyncNetwork, (Utils->Creator,(void*)this)); this->WriteLine(":" + ServerInstance->Config->GetSID() + " ENDBURST"); ServerInstance->SNO->WriteToSnoMask('l',"Finished bursting to \2"+ s->GetName()+"\2."); } -/** Recursively send the server tree with distances as hops. +/** Recursively send the server tree. * This is used during network burst to inform the other server * (and any of ITS servers too) of what servers we know about. * If at any point any of these servers already exist on the other - * end, our connection may be terminated. The hopcounts given - * by this function are relative, this doesn't matter so long as - * they are all >1, as all the remote servers re-calculate them - * to be relative too, with themselves as hop 0. + * end, our connection may be terminated. + * The hopcount parameter (3rd) is deprecated, and is always 0. */ -void TreeSocket::SendServers(TreeServer* Current, TreeServer* s, int hops) +void TreeSocket::SendServers(TreeServer* Current, TreeServer* s) { - char command[MAXBUF]; - for (unsigned int q = 0; q < Current->ChildCount(); q++) + const TreeServer::ChildServers& children = Current->GetChildren(); + for (TreeServer::ChildServers::const_iterator i = children.begin(); i != children.end(); ++i) { - TreeServer* recursive_server = Current->GetChild(q); + TreeServer* recursive_server = *i; if (recursive_server != s) { - std::string recursive_servername = recursive_server->GetName(); - snprintf(command, MAXBUF, ":%s SERVER %s * %d %s :%s", Current->GetID().c_str(), recursive_servername.c_str(), hops, - recursive_server->GetID().c_str(), - recursive_server->GetDesc().c_str()); - this->WriteLine(command); - this->WriteLine(":"+recursive_server->GetID()+" VERSION :"+recursive_server->GetVersion()); + this->WriteLine(CommandServer::Builder(recursive_server)); + this->WriteLine(":" + recursive_server->GetID() + " VERSION :" + recursive_server->GetVersion()); /* down to next level */ - this->SendServers(recursive_server, s, hops+1); + this->SendServers(recursive_server, s); } } } @@ -87,101 +83,46 @@ void TreeSocket::SendServers(TreeServer* Current, TreeServer* s, int hops) /** Send one or more FJOINs for a channel of users. * If the length of a single line is more than 480-NICKMAX * in length, it is split over multiple lines. + * Send one or more FMODEs for a channel with the + * channel bans, if there's any. */ void TreeSocket::SendFJoins(Channel* c) { - std::string buffer; - char list[MAXBUF]; - - size_t curlen, headlen; - curlen = headlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu +%s :", - ServerInstance->Config->GetSID().c_str(), c->name.c_str(), (unsigned long)c->age, c->ChanModes(true)); - int numusers = 0; - char* ptr = list + curlen; - bool looped_once = false; + std::string line(":"); + line.append(ServerInstance->Config->GetSID()).append(" FJOIN ").append(c->name).append(1, ' ').append(ConvToStr(c->age)).append(" +"); + std::string::size_type erase_from = line.length(); + line.append(c->ChanModes(true)).append(" :"); const UserMembList *ulist = c->GetUsers(); - std::string modes; - std::string params; - - for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++) - { - size_t ptrlen = 0; - std::string modestr = i->second->modes; - - if ((curlen + modestr.length() + i->first->uuid.length() + 4) > 480) - { - // remove the final space - if (ptr[-1] == ' ') - ptr[-1] = '\0'; - buffer.append(list).append("\r\n"); - curlen = headlen; - ptr = list + headlen; - numusers = 0; - } - - ptrlen = snprintf(ptr, MAXBUF-curlen, "%s,%s ", modestr.c_str(), i->first->uuid.c_str()); - - looped_once = true; - - curlen += ptrlen; - ptr += ptrlen; - numusers++; - } - - // Okay, permanent channels will (of course) need this \r\n anyway, numusers check is if there - // actually were people in the channel (looped_once == true) - if (!looped_once || numusers > 0) - { - // remove the final space - if (ptr[-1] == ' ') - ptr[-1] = '\0'; - buffer.append(list).append("\r\n"); - } - - int linesize = 1; - for (BanList::iterator b = c->bans.begin(); b != c->bans.end(); b++) + for (UserMembCIter i = ulist->begin(); i != ulist->end(); ++i) { - int size = b->data.length() + 2; - int currsize = linesize + size; - if (currsize <= 350) + const std::string& modestr = i->second->modes; + if ((line.length() + modestr.length() + UIDGenerator::UUID_LENGTH + 2) > 480) { - modes.append("b"); - params.append(" ").append(b->data); - linesize += size; - } - if ((modes.length() >= ServerInstance->Config->Limits.MaxModes) || (currsize > 350)) - { - /* Wrap at MAXMODES */ - buffer.append(":").append(ServerInstance->Config->GetSID()).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params).append("\r\n"); - modes.clear(); - params.clear(); - linesize = 1; + this->WriteLine(line); + line.erase(erase_from); + line.append(" :"); } + line.append(modestr).append(1, ',').append(i->first->uuid).push_back(' '); } + this->WriteLine(line); - /* Only send these if there are any */ - if (!modes.empty()) - buffer.append(":").append(ServerInstance->Config->GetSID()).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params); - - this->WriteLine(buffer); + ChanModeReference ban(NULL, "ban"); + static_cast<ListModeBase*>(*ban)->DoSyncChannel(c, Utils->Creator, this); } /** Send all XLines we know about */ void TreeSocket::SendXLines() { - char data[MAXBUF]; - std::string n = ServerInstance->Config->GetSID(); - const char* sn = n.c_str(); - std::vector<std::string> types = ServerInstance->XLines->GetAllTypes(); - time_t current = ServerInstance->Time(); - for (std::vector<std::string>::iterator it = types.begin(); it != types.end(); ++it) + for (std::vector<std::string>::const_iterator it = types.begin(); it != types.end(); ++it) { + /* Expired lines are removed in XLineManager::GetAll() */ XLineLookup* lookup = ServerInstance->XLines->GetAll(*it); + /* lookup cannot be NULL in this case but a check won't hurt */ if (lookup) { for (LookupIter i = lookup->begin(); i != lookup->end(); ++i) @@ -192,96 +133,60 @@ void TreeSocket::SendXLines() if (!i->second->IsBurstable()) break; - /* If it's expired, don't bother to burst it - */ - if (i->second->duration && current > i->second->expiry) - continue; - - snprintf(data,MAXBUF,":%s ADDLINE %s %s %s %lu %lu :%s",sn, it->c_str(), i->second->Displayable(), - i->second->source.c_str(), - (unsigned long)i->second->set_time, - (unsigned long)i->second->duration, - i->second->reason.c_str()); - this->WriteLine(data); + this->WriteLine(CommandAddLine::Builder(i->second)); } } } } /** Send channel topic, modes and metadata */ -void TreeSocket::SendChannelModes() +void TreeSocket::SyncChannel(Channel* chan) { - char data[MAXBUF]; - std::string n = ServerInstance->Config->GetSID(); - const char* sn = n.c_str(); + SendFJoins(chan); - for (chan_hash::iterator c = ServerInstance->chanlist->begin(); c != ServerInstance->chanlist->end(); c++) - { - SendFJoins(c->second); - if (!c->second->topic.empty()) - { - snprintf(data,MAXBUF,":%s FTOPIC %s %lu %s :%s", sn, c->second->name.c_str(), (unsigned long)c->second->topicset, c->second->setby.c_str(), c->second->topic.c_str()); - this->WriteLine(data); - } + // If the topic was ever set, send it, even if it's empty now + // because a new empty topic should override an old non-empty topic + if (chan->topicset != 0) + this->WriteLine(CommandFTopic::Builder(chan)); - for(Extensible::ExtensibleStore::const_iterator i = c->second->GetExtList().begin(); i != c->second->GetExtList().end(); i++) - { - ExtensionItem* item = i->first; - std::string value = item->serialize(FORMAT_NETWORK, c->second, i->second); - if (!value.empty()) - Utils->Creator->ProtoSendMetaData(this, c->second, item->name, value); - } - - FOREACH_MOD(I_OnSyncChannel,OnSyncChannel(c->second,Utils->Creator,this)); + for (Extensible::ExtensibleStore::const_iterator i = chan->GetExtList().begin(); i != chan->GetExtList().end(); i++) + { + ExtensionItem* item = i->first; + std::string value = item->serialize(FORMAT_NETWORK, chan, i->second); + if (!value.empty()) + Utils->Creator->ProtoSendMetaData(this, chan, item->name, value); } + + FOREACH_MOD(OnSyncChannel, (chan, Utils->Creator, this)); } /** send all users and their oper state/modes */ void TreeSocket::SendUsers() { - char data[MAXBUF]; for (user_hash::iterator u = ServerInstance->Users->clientlist->begin(); u != ServerInstance->Users->clientlist->end(); u++) { - if (u->second->registered == REG_ALL) - { - TreeServer* theirserver = Utils->FindServer(u->second->server); - if (theirserver) - { - snprintf(data,MAXBUF,":%s UID %s %lu %s %s %s %s %s %lu +%s :%s", - theirserver->GetID().c_str(), /* Prefix: SID */ - u->second->uuid.c_str(), /* 0: UUID */ - (unsigned long)u->second->age, /* 1: TS */ - u->second->nick.c_str(), /* 2: Nick */ - u->second->host.c_str(), /* 3: Displayed Host */ - u->second->dhost.c_str(), /* 4: Real host */ - u->second->ident.c_str(), /* 5: Ident */ - u->second->GetIPString(), /* 6: IP string */ - (unsigned long)u->second->signon, /* 7: Signon time for WHOWAS */ - u->second->FormatModes(true), /* 8...n: Modes and params */ - u->second->fullname.c_str()); /* size-1: GECOS */ - this->WriteLine(data); - if (IS_OPER(u->second)) - { - snprintf(data,MAXBUF,":%s OPERTYPE %s", u->second->uuid.c_str(), u->second->oper->name.c_str()); - this->WriteLine(data); - } - if (IS_AWAY(u->second)) - { - snprintf(data,MAXBUF,":%s AWAY %ld :%s", u->second->uuid.c_str(), (long)u->second->awaytime, u->second->awaymsg.c_str()); - this->WriteLine(data); - } - } + User* user = u->second; + if (user->registered != REG_ALL) + continue; - for(Extensible::ExtensibleStore::const_iterator i = u->second->GetExtList().begin(); i != u->second->GetExtList().end(); i++) - { - ExtensionItem* item = i->first; - std::string value = item->serialize(FORMAT_NETWORK, u->second, i->second); - if (!value.empty()) - Utils->Creator->ProtoSendMetaData(this, u->second, item->name, value); - } + this->WriteLine(CommandUID::Builder(user)); + + if (user->IsOper()) + this->WriteLine(CommandOpertype::Builder(user)); - FOREACH_MOD(I_OnSyncUser,OnSyncUser(u->second,Utils->Creator,this)); + if (user->IsAway()) + this->WriteLine(CommandAway::Builder(user)); + + const Extensible::ExtensibleStore& exts = user->GetExtList(); + for (Extensible::ExtensibleStore::const_iterator i = exts.begin(); i != exts.end(); ++i) + { + ExtensionItem* item = i->first; + std::string value = item->serialize(FORMAT_NETWORK, u->second, i->second); + if (!value.empty()) + Utils->Creator->ProtoSendMetaData(this, u->second, item->name, value); } + + FOREACH_MOD(OnSyncUser, (user, Utils->Creator, this)); } } diff --git a/src/modules/m_spanningtree/nick.cpp b/src/modules/m_spanningtree/nick.cpp new file mode 100644 index 000000000..7ace9cc73 --- /dev/null +++ b/src/modules/m_spanningtree/nick.cpp @@ -0,0 +1,61 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> + * Copyright (C) 2007-2008, 2012 Robin Burchell <robin+git@viroteck.net> + * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> + * Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> + * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com> + * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> + * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "inspircd.h" + +#include "main.h" +#include "utils.h" +#include "commands.h" + +CmdResult CommandNick::HandleRemote(RemoteUser* user, std::vector<std::string>& params) +{ + if ((isdigit(params[0][0])) && (params[0] != user->uuid)) + return CMD_INVALID; + + /* Update timestamp on user when they change nicks */ + user->age = ConvToInt(params[1]); + + /* + * On nick messages, check that the nick doesn't already exist here. + * If it does, perform collision logic. + */ + User* x = ServerInstance->FindNickOnly(params[0]); + if ((x) && (x != user)) + { + /* x is local, who is remote */ + int collideret = Utils->DoCollision(x, Utils->FindServer(user->server), user->age, user->ident, user->GetIPString(), user->uuid); + if (collideret != 1) + { + /* + * Remote client lost, or both lost, parsing or passing on this + * nickchange would be pointless, as the incoming client's server will + * soon receive SAVE to change its nick to its UID. :) -- w00t + */ + return CMD_FAILURE; + } + } + user->ForceNickChange(params[0]); + return CMD_SUCCESS; +} diff --git a/src/modules/m_spanningtree/nickcollide.cpp b/src/modules/m_spanningtree/nickcollide.cpp index 38d59affb..edc1ac6ff 100644 --- a/src/modules/m_spanningtree/nickcollide.cpp +++ b/src/modules/m_spanningtree/nickcollide.cpp @@ -19,14 +19,11 @@ #include "inspircd.h" -#include "xline.h" #include "treesocket.h" #include "treeserver.h" #include "utils.h" - -/* $ModDep: m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */ - +#include "commandbuilder.h" /* * Yes, this function looks a little ugly. @@ -34,7 +31,7 @@ * Returns 1 if colliding local client, 2 if colliding remote, 3 if colliding both. * Sends SAVEs as appropriate and forces nickchanges too. */ -int TreeSocket::DoCollision(User *u, time_t remotets, const std::string &remoteident, const std::string &remoteip, const std::string &remoteuid) +int SpanningTreeUtilities::DoCollision(User* u, TreeServer* server, time_t remotets, const std::string& remoteident, const std::string& remoteip, const std::string& remoteuid) { /* * Under old protocol rules, we would have had to kill both clients. @@ -109,12 +106,12 @@ int TreeSocket::DoCollision(User *u, time_t remotets, const std::string &remotei * Local-side nick needs to change. Just in case we are hub, and * this "local" nick is actually behind us, send an SAVE out. */ - parameterlist params; + CmdBuilder params("SAVE"); params.push_back(u->uuid); params.push_back(ConvToStr(u->age)); - Utils->DoOneToMany(ServerInstance->Config->GetSID(),"SAVE",params); + params.Broadcast(); - u->ForceNickChange(u->uuid.c_str()); + u->ForceNickChange(u->uuid); if (!bChangeRemote) return 1; @@ -127,12 +124,13 @@ int TreeSocket::DoCollision(User *u, time_t remotets, const std::string &remotei * the UID or halt the propagation of the nick change command, * so other servers don't need to see the SAVE */ - WriteLine(":"+ServerInstance->Config->GetSID()+" SAVE "+remoteuid+" "+ ConvToStr(remotets)); + TreeSocket* sock = server->GetSocket(); + sock->WriteLine(":"+ServerInstance->Config->GetSID()+" SAVE "+remoteuid+" "+ ConvToStr(remotets)); if (remote) { /* nick change collide. Force change their nick. */ - remote->ForceNickChange(remoteuid.c_str()); + remote->ForceNickChange(remoteuid); } if (!bChangeLocal) diff --git a/src/modules/m_spanningtree/operquit.cpp b/src/modules/m_spanningtree/operquit.cpp deleted file mode 100644 index af2e04ebc..000000000 --- a/src/modules/m_spanningtree/operquit.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "inspircd.h" -#include "xline.h" - -#include "treesocket.h" -#include "treeserver.h" -#include "utils.h" - -/* $ModDep: m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */ - - -bool TreeSocket::OperQuit(const std::string &prefix, parameterlist ¶ms) -{ - if (params.size() < 1) - return true; - - User* u = ServerInstance->FindUUID(prefix); - - if ((u) && (!IS_SERVER(u))) - { - ServerInstance->OperQuit.set(u, params[0]); - params[0] = ":" + params[0]; - Utils->DoOneToAllButSender(prefix,"OPERQUIT",params,prefix); - } - return true; -} - diff --git a/src/modules/m_spanningtree/opertype.cpp b/src/modules/m_spanningtree/opertype.cpp index 97a4de8c2..6e5d473aa 100644 --- a/src/modules/m_spanningtree/opertype.cpp +++ b/src/modules/m_spanningtree/opertype.cpp @@ -26,15 +26,17 @@ /** Because the core won't let users or even SERVERS set +o, * we use the OPERTYPE command to do this. */ -CmdResult CommandOpertype::Handle(const std::vector<std::string>& params, User *u) +CmdResult CommandOpertype::HandleRemote(RemoteUser* u, std::vector<std::string>& params) { - SpanningTreeUtilities* Utils = ((ModuleSpanningTree*)(Module*)creator)->Utils; - std::string opertype = params[0]; - if (!IS_OPER(u)) + const std::string& opertype = params[0]; + if (!u->IsOper()) ServerInstance->Users->all_opers.push_back(u); - u->modes[UM_OPERATOR] = 1; - OperIndex::iterator iter = ServerInstance->Config->oper_blocks.find(" " + opertype); - if (iter != ServerInstance->Config->oper_blocks.end()) + + ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER); + u->SetMode(opermh, true); + + OperIndex::iterator iter = ServerInstance->Config->OperTypes.find(opertype); + if (iter != ServerInstance->Config->OperTypes.end()) u->oper = iter->second; else { @@ -53,7 +55,12 @@ CmdResult CommandOpertype::Handle(const std::vector<std::string>& params, User * return CMD_SUCCESS; } - ServerInstance->SNO->WriteToSnoMask('O',"From %s: User %s (%s@%s) is now an IRC operator of type %s",u->server.c_str(), u->nick.c_str(),u->ident.c_str(), u->host.c_str(), irc::Spacify(opertype.c_str())); + ServerInstance->SNO->WriteToSnoMask('O',"From %s: User %s (%s@%s) is now an IRC operator of type %s",u->server.c_str(), u->nick.c_str(),u->ident.c_str(), u->host.c_str(), opertype.c_str()); return CMD_SUCCESS; } +CommandOpertype::Builder::Builder(User* user) + : CmdBuilder(user, "OPERTYPE") +{ + push_last(user->oper->name); +} diff --git a/src/modules/m_spanningtree/override_map.cpp b/src/modules/m_spanningtree/override_map.cpp index 04fa4bcab..b5da11280 100644 --- a/src/modules/m_spanningtree/override_map.cpp +++ b/src/modules/m_spanningtree/override_map.cpp @@ -19,26 +19,28 @@ */ -/* $ModDesc: Provides a spanning tree server link protocol */ - #include "inspircd.h" #include "main.h" #include "utils.h" #include "treeserver.h" -#include "treesocket.h" +#include "commands.h" -/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */ +CommandMap::CommandMap(Module* Creator) + : Command(Creator, "MAP", 0, 1) +{ + Penalty = 2; +} -const std::string ModuleSpanningTree::MapOperInfo(TreeServer* Current) +std::string CommandMap::MapOperInfo(TreeServer* Current) { time_t secs_up = ServerInstance->Time() - Current->age; - return " [Up: " + TimeToStr(secs_up) + (Current->rtt == 0 ? "]" : " Lag: " + ConvToStr(Current->rtt) + "ms]"); + return " [Up: " + ModuleSpanningTree::TimeToStr(secs_up) + (Current->rtt == 0 ? "]" : " Lag: " + ConvToStr(Current->rtt) + "ms]"); } -void ModuleSpanningTree::ShowMap(TreeServer* Current, User* user, int depth, int &line, char* names, int &maxnamew, char* stats) +void CommandMap::ShowMap(TreeServer* Current, User* user, int depth, int &line, char* names, int &maxnamew, char* stats) { - ServerInstance->Logs->Log("map",DEBUG,"ShowMap depth %d on line %d", depth, line); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "ShowMap depth %d on line %d", depth, line); float percent; if (ServerInstance->Users->clientlist->size() == 0) @@ -48,38 +50,39 @@ void ModuleSpanningTree::ShowMap(TreeServer* Current, User* user, int depth, int } else { - percent = Current->GetUserCount() * 100.0 / ServerInstance->Users->clientlist->size(); + percent = Current->UserCount * 100.0 / ServerInstance->Users->clientlist->size(); } - const std::string operdata = IS_OPER(user) ? MapOperInfo(Current) : ""; + const std::string operdata = user->IsOper() ? MapOperInfo(Current) : ""; char* myname = names + 100 * line; char* mystat = stats + 50 * line; memset(myname, ' ', depth); int w = depth; - std::string servername = Current->GetName(); - if (IS_OPER(user)) + if (user->IsOper()) { - w += snprintf(myname + depth, 99 - depth, "%s (%s)", servername.c_str(), Current->GetID().c_str()); + w += snprintf(myname + depth, 99 - depth, "%s (%s)", Current->GetName().c_str(), Current->GetID().c_str()); } else { - w += snprintf(myname + depth, 99 - depth, "%s", servername.c_str()); + w += snprintf(myname + depth, 99 - depth, "%s", Current->GetName().c_str()); } memset(myname + w, ' ', 100 - w); if (w > maxnamew) maxnamew = w; - snprintf(mystat, 49, "%5d [%5.2f%%]%s", Current->GetUserCount(), percent, operdata.c_str()); + snprintf(mystat, 49, "%5d [%5.2f%%]%s", Current->UserCount, percent, operdata.c_str()); line++; - if (IS_OPER(user) || !Utils->FlatLinks) + if (user->IsOper() || !Utils->FlatLinks) depth = depth + 2; - for (unsigned int q = 0; q < Current->ChildCount(); q++) + + const TreeServer::ChildServers& servers = Current->GetChildren(); + for (TreeServer::ChildServers::const_iterator i = servers.begin(); i != servers.end(); ++i) { - TreeServer* child = Current->GetChild(q); - if (!IS_OPER(user)) { + TreeServer* child = *i; + if (!user->IsOper()) { if (child->Hidden) continue; if ((Utils->HideULines) && (ServerInstance->ULine(child->GetName()))) @@ -98,38 +101,27 @@ void ModuleSpanningTree::ShowMap(TreeServer* Current, User* user, int depth, int // and divisons, we instead render the map onto a backplane of characters // (a character matrix), then draw the branches as a series of "L" shapes // from the nodes. This is not only friendlier on CPU it uses less stack. -bool ModuleSpanningTree::HandleMap(const std::vector<std::string>& parameters, User* user) +CmdResult CommandMap::Handle(const std::vector<std::string>& parameters, User* user) { if (parameters.size() > 0) { /* Remote MAP, the server is within the 1st parameter */ TreeServer* s = Utils->FindServerMask(parameters[0]); - bool ret = false; if (!s) { user->WriteNumeric(ERR_NOSUCHSERVER, "%s %s :No such server", user->nick.c_str(), parameters[0].c_str()); - ret = true; + return CMD_FAILURE; } - else if (s && s != Utils->TreeRoot) - { - parameterlist params; - params.push_back(parameters[0]); - params[0] = s->GetName(); - Utils->DoOneToOne(user->uuid, "MAP", params, s->GetName()); - ret = true; - } - - // Don't return if s == Utils->TreeRoot (us) - if (ret) - return true; + if (!s->IsRoot()) + return CMD_SUCCESS; } // These arrays represent a virtual screen which we will // "scratch" draw to, as the console device of an irc // client does not provide for a proper terminal. int totusers = ServerInstance->Users->clientlist->size(); - int totservers = this->CountServs(); + int totservers = Utils->serverlist.size(); int maxnamew = 0; int line = 0; char* names = new char[totservers * 100]; @@ -174,7 +166,6 @@ bool ModuleSpanningTree::HandleMap(const std::vector<std::string>& parameters, U float avg_users = totusers * 1.0 / line; - ServerInstance->Logs->Log("map",DEBUG,"local"); for (int t = 0; t < line; t++) { // terminate the string at maxnamew characters @@ -191,6 +182,12 @@ bool ModuleSpanningTree::HandleMap(const std::vector<std::string>& parameters, U delete[] names; delete[] stats; - return true; + return CMD_SUCCESS; } +RouteDescriptor CommandMap::GetRouting(User* user, const std::vector<std::string>& parameters) +{ + if (!parameters.empty()) + return ROUTE_UNICAST(parameters[0]); + return ROUTE_LOCALONLY; +} diff --git a/src/modules/m_spanningtree/override_squit.cpp b/src/modules/m_spanningtree/override_squit.cpp index 7d01c8149..d3caa7bc8 100644 --- a/src/modules/m_spanningtree/override_squit.cpp +++ b/src/modules/m_spanningtree/override_squit.cpp @@ -17,33 +17,28 @@ */ -/* $ModDesc: Provides a spanning tree server link protocol */ - #include "inspircd.h" #include "socket.h" -#include "xline.h" #include "main.h" #include "utils.h" #include "treeserver.h" #include "treesocket.h" -/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */ - ModResult ModuleSpanningTree::HandleSquit(const std::vector<std::string>& parameters, User* user) { TreeServer* s = Utils->FindServerMask(parameters[0]); if (s) { - if (s == Utils->TreeRoot) + if (s->IsRoot()) { - user->WriteServ("NOTICE %s :*** SQUIT: Foolish mortal, you cannot make a server SQUIT itself! (%s matches local server name)",user->nick.c_str(),parameters[0].c_str()); + user->WriteNotice("*** SQUIT: Foolish mortal, you cannot make a server SQUIT itself! (" + parameters[0] + " matches local server name)"); return MOD_RES_DENY; } TreeSocket* sock = s->GetSocket(); - if (sock) + if (s->IsLocal()) { ServerInstance->SNO->WriteToSnoMask('l',"SQUIT: Server \002%s\002 removed from network by %s",parameters[0].c_str(),user->nick.c_str()); sock->Squit(s,"Server quit by " + user->GetFullRealHost()); @@ -52,12 +47,12 @@ ModResult ModuleSpanningTree::HandleSquit(const std::vector<std::string>& parame } else { - user->WriteServ("NOTICE %s :*** SQUIT may not be used to remove remote servers. Please use RSQUIT instead.",user->nick.c_str()); + user->WriteNotice("*** SQUIT may not be used to remove remote servers. Please use RSQUIT instead."); } } else { - user->WriteServ("NOTICE %s :*** SQUIT: The server \002%s\002 does not exist on the network.",user->nick.c_str(),parameters[0].c_str()); + user->WriteNotice("*** SQUIT: The server \002" + parameters[0] + "\002 does not exist on the network."); } return MOD_RES_DENY; } diff --git a/src/modules/m_spanningtree/override_stats.cpp b/src/modules/m_spanningtree/override_stats.cpp index 688661b80..9762ecf4e 100644 --- a/src/modules/m_spanningtree/override_stats.cpp +++ b/src/modules/m_spanningtree/override_stats.cpp @@ -18,16 +18,11 @@ */ -/* $ModDesc: Provides a spanning tree server link protocol */ - #include "inspircd.h" -#include "socket.h" #include "main.h" #include "utils.h" -#include "treeserver.h" #include "link.h" -#include "treesocket.h" ModResult ModuleSpanningTree::OnStats(char statschar, User* user, string_list &results) { diff --git a/src/modules/m_spanningtree/override_whois.cpp b/src/modules/m_spanningtree/override_whois.cpp index ad8c6a6ef..cb21f84b5 100644 --- a/src/modules/m_spanningtree/override_whois.cpp +++ b/src/modules/m_spanningtree/override_whois.cpp @@ -16,19 +16,10 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -/* $ModDesc: Provides a spanning tree server link protocol */ - #include "inspircd.h" -#include "socket.h" -#include "xline.h" #include "main.h" -#include "utils.h" -#include "treeserver.h" -#include "treesocket.h" - -/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */ +#include "commandbuilder.h" ModResult ModuleSpanningTree::HandleRemoteWhois(const std::vector<std::string>& parameters, User* user) { @@ -37,9 +28,7 @@ ModResult ModuleSpanningTree::HandleRemoteWhois(const std::vector<std::string>& User* remote = ServerInstance->FindNickOnly(parameters[1]); if (remote && !IS_LOCAL(remote)) { - parameterlist params; - params.push_back(remote->uuid); - Utils->DoOneToOne(user->uuid,"IDLE",params,remote->server); + CmdBuilder(user, "IDLE").push(remote->uuid).Unicast(remote); return MOD_RES_DENY; } else if (!remote) diff --git a/src/modules/m_spanningtree/ping.cpp b/src/modules/m_spanningtree/ping.cpp index aec680b23..6d8893acf 100644 --- a/src/modules/m_spanningtree/ping.cpp +++ b/src/modules/m_spanningtree/ping.cpp @@ -18,44 +18,26 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" -#include "socketengine.h" -#include "main.h" #include "utils.h" #include "treeserver.h" -#include "treesocket.h" - -/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */ +#include "commands.h" +#include "utils.h" -bool TreeSocket::LocalPing(const std::string &prefix, parameterlist ¶ms) +CmdResult CommandPing::Handle(User* user, std::vector<std::string>& params) { - if (params.size() < 1) - return true; - if (params.size() == 1) + if (params[0] == ServerInstance->Config->GetSID()) { - std::string stufftobounce = params[0]; - this->WriteLine(":"+ServerInstance->Config->GetSID()+" PONG "+stufftobounce); - return true; - } - else - { - std::string forwardto = params[1]; - if (forwardto == ServerInstance->Config->ServerName || forwardto == ServerInstance->Config->GetSID()) - { - // this is a ping for us, send back PONG to the requesting server - params[1] = params[0]; - params[0] = forwardto; - Utils->DoOneToOne(ServerInstance->Config->GetSID(),"PONG",params,params[1]); - } - else - { - // not for us, pass it on :) - Utils->DoOneToOne(prefix,"PING",params,forwardto); - } - return true; + // PING for us, reply with a PONG + CmdBuilder reply("PONG"); + reply.push_back(user->uuid); + if (params.size() >= 2) + // If there is a second parameter, append it + reply.push_back(params[1]); + + reply.Unicast(user); } + return CMD_SUCCESS; } diff --git a/src/modules/m_spanningtree/pong.cpp b/src/modules/m_spanningtree/pong.cpp index 5966d05d9..ce1715874 100644 --- a/src/modules/m_spanningtree/pong.cpp +++ b/src/modules/m_spanningtree/pong.cpp @@ -18,65 +18,27 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" -#include "socketengine.h" -#include "main.h" #include "utils.h" #include "treeserver.h" -#include "treesocket.h" - -/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */ +#include "commands.h" +#include "utils.h" -bool TreeSocket::LocalPong(const std::string &prefix, parameterlist ¶ms) +CmdResult CommandPong::HandleServer(TreeServer* server, std::vector<std::string>& params) { - if (params.size() < 1) - return true; - - if (params.size() == 1) + if (server->bursting) { - TreeServer* ServerSource = Utils->FindServer(prefix); - if (ServerSource) - { - ServerSource->SetPingFlag(); - long ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000); - ServerSource->rtt = ts - ServerSource->LastPingMsec; - } + ServerInstance->SNO->WriteGlobalSno('l', "Server \002%s\002 has not finished burst, forcing end of burst (send ENDBURST!)", server->GetName().c_str()); + server->FinishBurst(); } - else - { - std::string forwardto = params[1]; - if (forwardto == ServerInstance->Config->GetSID() || forwardto == ServerInstance->Config->ServerName) - { - /* - * this is a PONG for us - * if the prefix is a user, check theyre local, and if they are, - * dump the PONG reply back to their fd. If its a server, do nowt. - * Services might want to send these s->s, but we dont need to yet. - */ - User* u = ServerInstance->FindNick(prefix); - if (u) - { - u->WriteServ("PONG %s %s",params[0].c_str(),params[1].c_str()); - } - TreeServer *ServerSource = Utils->FindServer(params[0]); - - if (ServerSource) - { - long ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000); - ServerSource->rtt = ts - ServerSource->LastPingMsec; - ServerSource->SetPingFlag(); - } - } - else - { - // not for us, pass it on :) - Utils->DoOneToOne(prefix,"PONG",params,forwardto); - } + if (params[0] == ServerInstance->Config->GetSID()) + { + // PONG for us + long ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000); + server->rtt = ts - server->LastPingMsec; + server->SetPingFlag(); } - - return true; + return CMD_SUCCESS; } diff --git a/src/modules/m_spanningtree/postcommand.cpp b/src/modules/m_spanningtree/postcommand.cpp index 471bbfcb9..57fbca6bc 100644 --- a/src/modules/m_spanningtree/postcommand.cpp +++ b/src/modules/m_spanningtree/postcommand.cpp @@ -17,69 +17,45 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -/* $ModDesc: Provides a spanning tree server link protocol */ - #include "inspircd.h" -#include "socket.h" -#include "xline.h" #include "main.h" #include "utils.h" #include "treeserver.h" -#include "treesocket.h" +#include "commandbuilder.h" -/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */ - -void ModuleSpanningTree::OnPostCommand(const std::string &command, const std::vector<std::string>& parameters, LocalUser *user, CmdResult result, const std::string &original_line) +void ModuleSpanningTree::OnPostCommand(Command* command, const std::vector<std::string>& parameters, LocalUser* user, CmdResult result, const std::string& original_line) { if (result == CMD_SUCCESS) Utils->RouteCommand(NULL, command, parameters, user); } -void SpanningTreeUtilities::RouteCommand(TreeServer* origin, const std::string &command, const parameterlist& parameters, User *user) +void SpanningTreeUtilities::RouteCommand(TreeServer* origin, CommandBase* thiscmd, const parameterlist& parameters, User* user) { - if (!ServerInstance->Parser->IsValidCommand(command, parameters.size(), user)) - return; - - /* We know it's non-null because IsValidCommand returned true */ - Command* thiscmd = ServerInstance->Parser->GetHandler(command); - + const std::string& command = thiscmd->name; RouteDescriptor routing = thiscmd->GetRouting(user, parameters); - - std::string sent_cmd = command; - parameterlist params; - if (routing.type == ROUTE_TYPE_LOCALONLY) - { - /* Broadcast when it's a core command with the default route descriptor and the source is a - * remote user or a remote server - */ + return; - Version ver = thiscmd->creator->GetVersion(); - if ((!(ver.Flags & VF_CORE)) || (IS_LOCAL(user)) || (IS_SERVER(user) == ServerInstance->FakeClient)) - return; + const bool encap = ((routing.type == ROUTE_TYPE_OPT_BCAST) || (routing.type == ROUTE_TYPE_OPT_UCAST)); + CmdBuilder params(user, encap ? "ENCAP" : command.c_str()); - routing = ROUTE_BROADCAST; - } - else if (routing.type == ROUTE_TYPE_OPT_BCAST) + if (routing.type == ROUTE_TYPE_OPT_BCAST) { - params.push_back("*"); + params.push('*'); params.push_back(command); - sent_cmd = "ENCAP"; } else if (routing.type == ROUTE_TYPE_OPT_UCAST) { TreeServer* sdest = FindServer(routing.serverdest); if (!sdest) { - ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Trying to route ENCAP to nonexistant server %s", + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Trying to route ENCAP to nonexistant server %s", routing.serverdest.c_str()); return; } params.push_back(sdest->GetID()); params.push_back(command); - sent_cmd = "ENCAP"; } else { @@ -88,14 +64,13 @@ void SpanningTreeUtilities::RouteCommand(TreeServer* origin, const std::string & if (!(ver.Flags & (VF_COMMON | VF_CORE)) && srcmodule != Creator) { - ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Routed command %s from non-VF_COMMON module %s", + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Routed command %s from non-VF_COMMON module %s", command.c_str(), srcmodule->ModuleSourceFile.c_str()); return; } } - std::string output_text; - ServerInstance->Parser->TranslateUIDs(thiscmd->translation, parameters, output_text, true, thiscmd); + std::string output_text = CommandParser::TranslateUIDs(thiscmd->translation, parameters, true, thiscmd); params.push_back(output_text); @@ -113,27 +88,13 @@ void SpanningTreeUtilities::RouteCommand(TreeServer* origin, const std::string & Channel* c = ServerInstance->FindChan(dest); if (!c) return; - TreeServerList list; // TODO OnBuildExemptList hook was here - GetListOfServersForChannel(c,list,pfx, CUList()); - std::string data = ":" + user->uuid + " " + sent_cmd; - for (unsigned int x = 0; x < params.size(); x++) - data += " " + params[x]; - for (TreeServerList::iterator i = list.begin(); i != list.end(); i++) - { - TreeSocket* Sock = i->second->GetSocket(); - if (origin && origin->GetSocket() == Sock) - continue; - if (Sock) - Sock->WriteLine(data); - } + CUList exempts; + SendChannelMessage(user->uuid, c, parameters[1], pfx, exempts, command.c_str(), origin ? origin->GetSocket() : NULL); } else if (dest[0] == '$') { - if (origin) - DoOneToAllButSender(user->uuid, sent_cmd, params, origin->GetName()); - else - DoOneToMany(user->uuid, sent_cmd, params); + params.Forward(origin); } else { @@ -145,20 +106,17 @@ void SpanningTreeUtilities::RouteCommand(TreeServer* origin, const std::string & if (tsd == origin) // huh? no routing stuff around in a circle, please. return; - DoOneToOne(user->uuid, sent_cmd, params, d->server); + params.Unicast(d); } } else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST) { - if (origin) - DoOneToAllButSender(user->uuid, sent_cmd, params, origin->GetName()); - else - DoOneToMany(user->uuid, sent_cmd, params); + params.Forward(origin); } else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST) { if (origin && routing.serverdest == origin->GetName()) return; - DoOneToOne(user->uuid, sent_cmd, params, routing.serverdest); + params.Unicast(routing.serverdest); } } diff --git a/src/modules/m_spanningtree/precommand.cpp b/src/modules/m_spanningtree/precommand.cpp index b331571ca..29b6ae642 100644 --- a/src/modules/m_spanningtree/precommand.cpp +++ b/src/modules/m_spanningtree/precommand.cpp @@ -18,18 +18,9 @@ */ -/* $ModDesc: Provides a spanning tree server link protocol */ - #include "inspircd.h" -#include "socket.h" -#include "xline.h" #include "main.h" -#include "utils.h" -#include "treeserver.h" -#include "treesocket.h" - -/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */ ModResult ModuleSpanningTree::OnPreCommand(std::string &command, std::vector<std::string>& parameters, LocalUser *user, bool validated, const std::string &original_line) { @@ -45,10 +36,6 @@ ModResult ModuleSpanningTree::OnPreCommand(std::string &command, std::vector<std { return this->HandleSquit(parameters,user); } - else if (command == "MAP") - { - return this->HandleMap(parameters,user) ? MOD_RES_DENY : MOD_RES_PASSTHRU; - } else if (command == "LINKS") { this->HandleLinks(parameters,user); @@ -64,8 +51,7 @@ ModResult ModuleSpanningTree::OnPreCommand(std::string &command, std::vector<std } else if ((command == "VERSION") && (parameters.size() > 0)) { - this->HandleVersion(parameters,user); - return MOD_RES_DENY; + return this->HandleVersion(parameters,user); } return MOD_RES_PASSTHRU; } diff --git a/src/modules/m_spanningtree/protocolinterface.cpp b/src/modules/m_spanningtree/protocolinterface.cpp index 3ab5dae9d..013dfac1b 100644 --- a/src/modules/m_spanningtree/protocolinterface.cpp +++ b/src/modules/m_spanningtree/protocolinterface.cpp @@ -19,27 +19,25 @@ #include "inspircd.h" -#include "main.h" #include "utils.h" #include "treeserver.h" -#include "treesocket.h" #include "protocolinterface.h" +#include "commands.h" /* * For documentation on this class, see include/protocol.h. */ -void SpanningTreeProtocolInterface::GetServerList(ProtoServerList &sl) +void SpanningTreeProtocolInterface::GetServerList(ServerList& sl) { - sl.clear(); for (server_hash::iterator i = Utils->serverlist.begin(); i != Utils->serverlist.end(); i++) { - ProtoServer ps; + ServerInfo ps; ps.servername = i->second->GetName(); TreeServer* s = i->second->GetParent(); ps.parentname = s ? s->GetName() : ""; - ps.usercount = i->second->GetUserCount(); - ps.opercount = i->second->GetOperCount(); + ps.usercount = i->second->UserCount; + ps.opercount = i->second->OperCount; ps.gecos = i->second->GetDesc(); ps.latencyms = i->second->rtt; sl.push_back(ps); @@ -48,132 +46,76 @@ void SpanningTreeProtocolInterface::GetServerList(ProtoServerList &sl) bool SpanningTreeProtocolInterface::SendEncapsulatedData(const parameterlist &encap) { + CmdBuilder params("ENCAP"); + params.insert(encap); if (encap[0].find_first_of("*?") != std::string::npos) { - Utils->DoOneToMany(ServerInstance->Config->GetSID(), "ENCAP", encap); + params.Broadcast(); return true; } - return Utils->DoOneToOne(ServerInstance->Config->GetSID(), "ENCAP", encap, encap[0]); + return params.Unicast(encap[0]); } void SpanningTreeProtocolInterface::SendMetaData(Extensible* target, const std::string &key, const std::string &data) { - parameterlist params; - User* u = dynamic_cast<User*>(target); Channel* c = dynamic_cast<Channel*>(target); if (u) - params.push_back(u->uuid); + CommandMetadata::Builder(u, key, data).Broadcast(); else if (c) - params.push_back(c->name); + CommandMetadata::Builder(c, key, data).Broadcast(); else - params.push_back("*"); - - params.push_back(key); - params.push_back(":" + data); - - Utils->DoOneToMany(ServerInstance->Config->GetSID(),"METADATA",params); + CommandMetadata::Builder(key, data).Broadcast(); } void SpanningTreeProtocolInterface::SendTopic(Channel* channel, std::string &topic) { - parameterlist params; - - params.push_back(channel->name); - params.push_back(ConvToStr(ServerInstance->Time())); - params.push_back(ServerInstance->Config->ServerName); - params.push_back(":" + topic); - - Utils->DoOneToMany(ServerInstance->Config->GetSID(),"FTOPIC", params); + CommandFTopic::Builder(ServerInstance->FakeClient, channel).Broadcast(); } -void SpanningTreeProtocolInterface::SendMode(const std::string &target, const parameterlist &modedata, const std::vector<TranslateType> &translate) +void SpanningTreeProtocolInterface::SendMode(User* source, User* u, Channel* c, const std::vector<std::string>& modedata, const std::vector<TranslateType>& translate) { - if (modedata.empty()) - return; - - std::string outdata; - ServerInstance->Parser->TranslateUIDs(translate, modedata, outdata); - - std::string uidtarget; - ServerInstance->Parser->TranslateUIDs(TR_NICK, target, uidtarget); - - parameterlist outlist; - outlist.push_back(uidtarget); - outlist.push_back(outdata); - - User* a = ServerInstance->FindNick(uidtarget); - if (a) + if (u) { - Utils->DoOneToMany(ServerInstance->Config->GetSID(),"MODE",outlist); - return; + if (u->registered != REG_ALL) + return; + + CmdBuilder params(source, "MODE"); + params.push_back(u->uuid); + params.insert(modedata); + params.Broadcast(); } else { - Channel* c = ServerInstance->FindChan(target); - if (c) - { - outlist.insert(outlist.begin() + 1, ConvToStr(c->age)); - Utils->DoOneToMany(ServerInstance->Config->GetSID(),"FMODE",outlist); - } + CmdBuilder params(source, "FMODE"); + params.push_back(c->name); + params.push_back(ConvToStr(c->age)); + params.push_back(CommandParser::TranslateUIDs(translate, modedata)); + params.Broadcast(); } } void SpanningTreeProtocolInterface::SendSNONotice(const std::string &snomask, const std::string &text) { - parameterlist p; - p.push_back(snomask); - p.push_back(":" + text); - Utils->DoOneToMany(ServerInstance->Config->GetSID(), "SNONOTICE", p); + CmdBuilder("SNONOTICE").push(snomask).push_last(text).Broadcast(); } void SpanningTreeProtocolInterface::PushToClient(User* target, const std::string &rawline) { - parameterlist p; - p.push_back(target->uuid); - p.push_back(":" + rawline); - Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PUSH", p, target->server); + CmdBuilder("PUSH").push(target->uuid).push_last(rawline).Unicast(target); } -void SpanningTreeProtocolInterface::SendChannel(Channel* target, char status, const std::string &text) +void SpanningTreeProtocolInterface::SendMessage(Channel* target, char status, const std::string& text, MessageType msgtype) { - std::string cname = target->name; - if (status) - cname = status + cname; - TreeServerList list; + const char* cmd = (msgtype == MSG_PRIVMSG ? "PRIVMSG" : "NOTICE"); CUList exempt_list; - Utils->GetListOfServersForChannel(target,list,status,exempt_list); - for (TreeServerList::iterator i = list.begin(); i != list.end(); i++) - { - TreeSocket* Sock = i->second->GetSocket(); - if (Sock) - Sock->WriteLine(text); - } -} - - -void SpanningTreeProtocolInterface::SendChannelPrivmsg(Channel* target, char status, const std::string &text) -{ - SendChannel(target, status, ":" + ServerInstance->Config->GetSID()+" PRIVMSG "+target->name+" :"+text); -} - -void SpanningTreeProtocolInterface::SendChannelNotice(Channel* target, char status, const std::string &text) -{ - SendChannel(target, status, ":" + ServerInstance->Config->GetSID()+" NOTICE "+target->name+" :"+text); -} - -void SpanningTreeProtocolInterface::SendUserPrivmsg(User* target, const std::string &text) -{ - parameterlist p; - p.push_back(target->uuid); - p.push_back(":" + text); - Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PRIVMSG", p, target->server); + Utils->SendChannelMessage(ServerInstance->Config->GetSID(), target, text, status, exempt_list, cmd); } -void SpanningTreeProtocolInterface::SendUserNotice(User* target, const std::string &text) +void SpanningTreeProtocolInterface::SendMessage(User* target, const std::string& text, MessageType msgtype) { - parameterlist p; + CmdBuilder p(msgtype == MSG_PRIVMSG ? "PRIVMSG" : "NOTICE"); p.push_back(target->uuid); - p.push_back(":" + text); - Utils->DoOneToOne(ServerInstance->Config->GetSID(), "NOTICE", p, target->server); + p.push_last(text); + p.Unicast(target); } diff --git a/src/modules/m_spanningtree/protocolinterface.h b/src/modules/m_spanningtree/protocolinterface.h index 297366893..b48e45425 100644 --- a/src/modules/m_spanningtree/protocolinterface.h +++ b/src/modules/m_spanningtree/protocolinterface.h @@ -17,32 +17,18 @@ */ -#ifndef M_SPANNINGTREE_PROTOCOLINTERFACE_H -#define M_SPANNINGTREE_PROTOCOLINTERFACE_H - -class SpanningTreeUtilities; -class ModuleSpanningTree; +#pragma once class SpanningTreeProtocolInterface : public ProtocolInterface { - SpanningTreeUtilities* Utils; - void SendChannel(Channel* target, char status, const std::string &text); public: - SpanningTreeProtocolInterface(SpanningTreeUtilities* util) : Utils(util) { } - virtual ~SpanningTreeProtocolInterface() { } - - virtual bool SendEncapsulatedData(const parameterlist &encap); - virtual void SendMetaData(Extensible* target, const std::string &key, const std::string &data); - virtual void SendTopic(Channel* channel, std::string &topic); - virtual void SendMode(const std::string &target, const parameterlist &modedata, const std::vector<TranslateType> &types); - virtual void SendSNONotice(const std::string &snomask, const std::string &text); - virtual void PushToClient(User* target, const std::string &rawline); - virtual void SendChannelPrivmsg(Channel* target, char status, const std::string &text); - virtual void SendChannelNotice(Channel* target, char status, const std::string &text); - virtual void SendUserPrivmsg(User* target, const std::string &text); - virtual void SendUserNotice(User* target, const std::string &text); - virtual void GetServerList(ProtoServerList &sl); + bool SendEncapsulatedData(const parameterlist &encap); + void SendMetaData(Extensible* target, const std::string &key, const std::string &data); + void SendTopic(Channel* channel, std::string &topic); + void SendMode(User* source, User* usertarget, Channel* chantarget, const parameterlist& modedata, const std::vector<TranslateType>& types); + void SendSNONotice(const std::string &snomask, const std::string &text); + void PushToClient(User* target, const std::string &rawline); + void SendMessage(Channel* target, char status, const std::string& text, MessageType msgtype); + void SendMessage(User* target, const std::string& text, MessageType msgtype); + void GetServerList(ServerList& sl); }; - -#endif - diff --git a/src/modules/m_spanningtree/push.cpp b/src/modules/m_spanningtree/push.cpp index b791376ea..a265e0d2e 100644 --- a/src/modules/m_spanningtree/push.cpp +++ b/src/modules/m_spanningtree/push.cpp @@ -18,34 +18,19 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" -#include "socketengine.h" -#include "main.h" #include "utils.h" -#include "treeserver.h" -#include "treesocket.h" +#include "commands.h" -/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */ - -bool TreeSocket::Push(const std::string &prefix, parameterlist ¶ms) +CmdResult CommandPush::Handle(User* user, std::vector<std::string>& params) { - if (params.size() < 2) - return true; User* u = ServerInstance->FindNick(params[0]); if (!u) - return true; + return CMD_FAILURE; if (IS_LOCAL(u)) { u->Write(params[1]); } - else - { - // continue the raw onwards - params[1] = ":" + params[1]; - Utils->DoOneToOne(prefix,"PUSH",params,u->server); - } - return true; + return CMD_SUCCESS; } diff --git a/src/modules/m_spanningtree/rconnect.cpp b/src/modules/m_spanningtree/rconnect.cpp index d4254cac6..c5d3a5b52 100644 --- a/src/modules/m_spanningtree/rconnect.cpp +++ b/src/modules/m_spanningtree/rconnect.cpp @@ -19,19 +19,13 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" -#include "resolvers.h" #include "main.h" #include "utils.h" -#include "treeserver.h" -#include "link.h" -#include "treesocket.h" #include "commands.h" -CommandRConnect::CommandRConnect (Module* Creator, SpanningTreeUtilities* Util) - : Command(Creator, "RCONNECT", 2), Utils(Util) +CommandRConnect::CommandRConnect (Module* Creator) + : Command(Creator, "RCONNECT", 2) { flags_needed = 'o'; syntax = "<remote-server-mask> <target-server-mask>"; @@ -39,14 +33,11 @@ CommandRConnect::CommandRConnect (Module* Creator, SpanningTreeUtilities* Util) CmdResult CommandRConnect::Handle (const std::vector<std::string>& parameters, User *user) { - if (IS_LOCAL(user)) + /* First see if the server which is being asked to connect to another server in fact exists */ + if (!Utils->FindServerMask(parameters[0])) { - if (!Utils->FindServerMask(parameters[0])) - { - user->WriteServ("NOTICE %s :*** RCONNECT: Server \002%s\002 isn't connected to the network!", user->nick.c_str(), parameters[0].c_str()); - return CMD_FAILURE; - } - user->WriteServ("NOTICE %s :*** RCONNECT: Sending remote connect to \002%s\002 to connect server \002%s\002.",user->nick.c_str(),parameters[0].c_str(),parameters[1].c_str()); + ((ModuleSpanningTree*)(Module*)creator)->RemoteMessage(user, "*** RCONNECT: Server \002%s\002 isn't connected to the network!", parameters[0].c_str()); + return CMD_FAILURE; } /* Is this aimed at our server? */ @@ -58,6 +49,21 @@ CmdResult CommandRConnect::Handle (const std::vector<std::string>& parameters, U para.push_back(parameters[1]); ((ModuleSpanningTree*)(Module*)creator)->HandleConnect(para, user); } + else + { + /* It's not aimed at our server, but if the request originates from our user + * acknowledge that we sent the request. + * + * It's possible that we're asking a server for something that makes no sense + * (e.g. connect to itself or to an already connected server), but we don't check + * for those conditions here, as ModuleSpanningTree::HandleConnect() (which will run + * on the target) does all the checking and error reporting. + */ + if (IS_LOCAL(user)) + { + user->WriteNotice("*** RCONNECT: Sending remote connect to \002 " + parameters[0] + "\002 to connect server \002" + parameters[1] + "\002."); + } + } return CMD_SUCCESS; } diff --git a/src/modules/m_spanningtree/resolvers.cpp b/src/modules/m_spanningtree/resolvers.cpp index d7c4c5227..80e8aeb0e 100644 --- a/src/modules/m_spanningtree/resolvers.cpp +++ b/src/modules/m_spanningtree/resolvers.cpp @@ -19,9 +19,8 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" +#include "cachetimer.h" #include "resolvers.h" #include "main.h" #include "utils.h" @@ -29,21 +28,22 @@ #include "link.h" #include "treesocket.h" -/* $ModDep: m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */ - /** This class is used to resolve server hostnames during /connect and autoconnect. * As of 1.1, the resolver system is seperated out from BufferedSocket, so we must do this * resolver step first ourselves if we need it. This is totally nonblocking, and will * callback to OnLookupComplete or OnError when completed. Once it has completed we * will have an IP address which we can then use to continue our connection. */ -ServernameResolver::ServernameResolver(SpanningTreeUtilities* Util, const std::string &hostname, Link* x, bool &cached, QueryType qt, Autoconnect* myac) - : Resolver(hostname, qt, cached, Util->Creator), Utils(Util), query(qt), host(hostname), MyLink(x), myautoconnect(myac) +ServernameResolver::ServernameResolver(DNS::Manager* mgr, const std::string& hostname, Link* x, DNS::QueryType qt, Autoconnect* myac) + : DNS::Request(mgr, Utils->Creator, hostname, qt) + , query(qt), host(hostname), MyLink(x), myautoconnect(myac) { } -void ServernameResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) +void ServernameResolver::OnLookupComplete(const DNS::Query *r) { + const DNS::ResourceRecord &ans_record = r->answers[0]; + /* Initiate the connection, now that we have an IP to use. * Passing a hostname directly to BufferedSocket causes it to * just bail and set its FD to -1. @@ -51,7 +51,7 @@ void ServernameResolver::OnLookupComplete(const std::string &result, unsigned in TreeServer* CheckDupe = Utils->FindServer(MyLink->Name.c_str()); if (!CheckDupe) /* Check that nobody tried to connect it successfully while we were resolving */ { - TreeSocket* newsocket = new TreeSocket(Utils, MyLink, myautoconnect, result); + TreeSocket* newsocket = new TreeSocket(MyLink, myautoconnect, ans_record.rdata); if (newsocket->GetFd() > -1) { /* We're all OK */ @@ -66,47 +66,74 @@ void ServernameResolver::OnLookupComplete(const std::string &result, unsigned in } } -void ServernameResolver::OnError(ResolverError e, const std::string &errormessage) +void ServernameResolver::OnError(const DNS::Query *r) { /* Ooops! */ - if (query == DNS_QUERY_AAAA) + if (query == DNS::QUERY_AAAA) { - bool cached = false; - ServernameResolver* snr = new ServernameResolver(Utils, host, MyLink, cached, DNS_QUERY_A, myautoconnect); - ServerInstance->AddResolver(snr, cached); - return; + ServernameResolver* snr = new ServernameResolver(this->manager, host, MyLink, DNS::QUERY_A, myautoconnect); + try + { + this->manager->Process(snr); + return; + } + catch (DNS::Exception &) + { + delete snr; + } } - ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: Unable to resolve hostname - %s", MyLink->Name.c_str(), errormessage.c_str() ); + + ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: Unable to resolve hostname - %s", MyLink->Name.c_str(), this->manager->GetErrorStr(r->error).c_str()); Utils->Creator->ConnectServer(myautoconnect, false); } -SecurityIPResolver::SecurityIPResolver(Module* me, SpanningTreeUtilities* U, const std::string &hostname, Link* x, bool &cached, QueryType qt) - : Resolver(hostname, qt, cached, me), MyLink(x), Utils(U), mine(me), host(hostname), query(qt) +SecurityIPResolver::SecurityIPResolver(Module* me, DNS::Manager* mgr, const std::string& hostname, Link* x, DNS::QueryType qt) + : DNS::Request(mgr, me, hostname, qt) + , MyLink(x), mine(me), host(hostname), query(qt) { } -void SecurityIPResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) +void SecurityIPResolver::OnLookupComplete(const DNS::Query *r) { + const DNS::ResourceRecord &ans_record = r->answers[0]; + for (std::vector<reference<Link> >::iterator i = Utils->LinkBlocks.begin(); i != Utils->LinkBlocks.end(); ++i) { Link* L = *i; if (L->IPAddr == host) { - Utils->ValidIPs.push_back(result); + Utils->ValidIPs.push_back(ans_record.rdata); break; } } } -void SecurityIPResolver::OnError(ResolverError e, const std::string &errormessage) +void SecurityIPResolver::OnError(const DNS::Query *r) { - if (query == DNS_QUERY_AAAA) + if (query == DNS::QUERY_AAAA) { - bool cached = false; - SecurityIPResolver* res = new SecurityIPResolver(mine, Utils, host, MyLink, cached, DNS_QUERY_A); - ServerInstance->AddResolver(res, cached); - return; + SecurityIPResolver* res = new SecurityIPResolver(mine, this->manager, host, MyLink, DNS::QUERY_A); + try + { + this->manager->Process(res); + return; + } + catch (DNS::Exception &) + { + delete res; + } } - ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Could not resolve IP associated with Link '%s': %s", - MyLink->Name.c_str(),errormessage.c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Could not resolve IP associated with Link '%s': %s", + MyLink->Name.c_str(), this->manager->GetErrorStr(r->error).c_str()); +} + +CacheRefreshTimer::CacheRefreshTimer() + : Timer(3600, ServerInstance->Time(), true) +{ +} + +bool CacheRefreshTimer::Tick(time_t TIME) +{ + Utils->RefreshIPCache(); + return true; } diff --git a/src/modules/m_spanningtree/resolvers.h b/src/modules/m_spanningtree/resolvers.h index 65b9e7249..782ac86ef 100644 --- a/src/modules/m_spanningtree/resolvers.h +++ b/src/modules/m_spanningtree/resolvers.h @@ -18,30 +18,27 @@ */ -#ifndef M_SPANNINGTREE_RESOLVERS_H -#define M_SPANNINGTREE_RESOLVERS_H +#pragma once -#include "socket.h" #include "inspircd.h" -#include "xline.h" +#include "modules/dns.h" #include "utils.h" #include "link.h" /** Handle resolving of server IPs for the cache */ -class SecurityIPResolver : public Resolver +class SecurityIPResolver : public DNS::Request { private: reference<Link> MyLink; - SpanningTreeUtilities* Utils; Module* mine; std::string host; - QueryType query; + DNS::QueryType query; public: - SecurityIPResolver(Module* me, SpanningTreeUtilities* U, const std::string &hostname, Link* x, bool &cached, QueryType qt); - void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached); - void OnError(ResolverError e, const std::string &errormessage); + SecurityIPResolver(Module* me, DNS::Manager* mgr, const std::string& hostname, Link* x, DNS::QueryType qt); + void OnLookupComplete(const DNS::Query *r) CXX11_OVERRIDE; + void OnError(const DNS::Query *q) CXX11_OVERRIDE; }; /** This class is used to resolve server hostnames during /connect and autoconnect. @@ -50,18 +47,15 @@ class SecurityIPResolver : public Resolver * callback to OnLookupComplete or OnError when completed. Once it has completed we * will have an IP address which we can then use to continue our connection. */ -class ServernameResolver : public Resolver +class ServernameResolver : public DNS::Request { private: - SpanningTreeUtilities* Utils; - QueryType query; + DNS::QueryType query; std::string host; reference<Link> MyLink; reference<Autoconnect> myautoconnect; public: - ServernameResolver(SpanningTreeUtilities* Util, const std::string &hostname, Link* x, bool &cached, QueryType qt, Autoconnect* myac); - void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached); - void OnError(ResolverError e, const std::string &errormessage); + ServernameResolver(DNS::Manager* mgr, const std::string& hostname, Link* x, DNS::QueryType qt, Autoconnect* myac); + void OnLookupComplete(const DNS::Query *r) CXX11_OVERRIDE; + void OnError(const DNS::Query *q) CXX11_OVERRIDE; }; - -#endif diff --git a/src/modules/m_spanningtree/rsquit.cpp b/src/modules/m_spanningtree/rsquit.cpp index 027ae02ab..3b7468491 100644 --- a/src/modules/m_spanningtree/rsquit.cpp +++ b/src/modules/m_spanningtree/rsquit.cpp @@ -19,17 +19,13 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" -#include "main.h" #include "utils.h" #include "treeserver.h" -#include "treesocket.h" #include "commands.h" -CommandRSQuit::CommandRSQuit (Module* Creator, SpanningTreeUtilities* Util) - : Command(Creator, "RSQUIT", 1), Utils(Util) +CommandRSQuit::CommandRSQuit(Module* Creator) + : Command(Creator, "RSQUIT", 1) { flags_needed = 'o'; syntax = "<target-server-mask> [reason]"; @@ -38,34 +34,28 @@ CommandRSQuit::CommandRSQuit (Module* Creator, SpanningTreeUtilities* Util) CmdResult CommandRSQuit::Handle (const std::vector<std::string>& parameters, User *user) { TreeServer *server_target; // Server to squit - TreeServer *server_linked; // Server target is linked to server_target = Utils->FindServerMask(parameters[0]); if (!server_target) { - user->WriteServ("NOTICE %s :*** RSQUIT: Server \002%s\002 isn't connected to the network!", user->nick.c_str(), parameters[0].c_str()); + ((ModuleSpanningTree*)(Module*)creator)->RemoteMessage(user, "*** RSQUIT: Server \002%s\002 isn't connected to the network!", parameters[0].c_str()); return CMD_FAILURE; } - if (server_target == Utils->TreeRoot) + if (server_target->IsRoot()) { - NoticeUser(user, "*** RSQUIT: Foolish mortal, you cannot make a server SQUIT itself! ("+parameters[0]+" matches local server name)"); + ((ModuleSpanningTree*)(Module*)creator)->RemoteMessage(user, "*** RSQUIT: Foolish mortal, you cannot make a server SQUIT itself! (%s matches local server name)", parameters[0].c_str()); return CMD_FAILURE; } - server_linked = server_target->GetParent(); - - if (server_linked == Utils->TreeRoot) + if (server_target->IsLocal()) { // We have been asked to remove server_target. TreeSocket* sock = server_target->GetSocket(); - if (sock) - { - const char *reason = parameters.size() == 2 ? parameters[1].c_str() : "No reason"; - ServerInstance->SNO->WriteToSnoMask('l',"RSQUIT: Server \002%s\002 removed from network by %s (%s)", parameters[0].c_str(), user->nick.c_str(), reason); - sock->Squit(server_target, "Server quit by " + user->GetFullRealHost() + " (" + reason + ")"); - sock->Close(); - } + const char* reason = parameters.size() == 2 ? parameters[1].c_str() : "No reason"; + ServerInstance->SNO->WriteToSnoMask('l',"RSQUIT: Server \002%s\002 removed from network by %s (%s)", parameters[0].c_str(), user->nick.c_str(), reason); + sock->Squit(server_target, "Server quit by " + user->GetFullRealHost() + " (" + reason + ")"); + sock->Close(); } return CMD_SUCCESS; @@ -75,20 +65,3 @@ RouteDescriptor CommandRSQuit::GetRouting(User* user, const std::vector<std::str { return ROUTE_UNICAST(parameters[0]); } - -// XXX use protocol interface instead of rolling our own :) -void CommandRSQuit::NoticeUser(User* user, const std::string &msg) -{ - if (IS_LOCAL(user)) - { - user->WriteServ("NOTICE %s :%s",user->nick.c_str(),msg.c_str()); - } - else - { - parameterlist params; - params.push_back(user->nick); - params.push_back("NOTICE "+ConvToStr(user->nick)+" :"+msg); - Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PUSH", params, user->server); - } -} - diff --git a/src/modules/m_spanningtree/save.cpp b/src/modules/m_spanningtree/save.cpp index 92999b422..8f0eced73 100644 --- a/src/modules/m_spanningtree/save.cpp +++ b/src/modules/m_spanningtree/save.cpp @@ -18,38 +18,30 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" -#include "socketengine.h" -#include "main.h" #include "utils.h" -#include "treeserver.h" #include "treesocket.h" - -/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */ +#include "commands.h" /** * SAVE command - force nick change to UID on timestamp match */ -bool TreeSocket::ForceNick(const std::string &prefix, parameterlist ¶ms) +CmdResult CommandSave::Handle(User* user, std::vector<std::string>& params) { - if (params.size() < 2) - return true; - User* u = ServerInstance->FindNick(params[0]); + if ((!u) || (IS_SERVER(u))) + return CMD_FAILURE; + time_t ts = atol(params[1].c_str()); - if ((u) && (!IS_SERVER(u)) && (u->age == ts)) + if (u->age == ts) { - Utils->DoOneToAllButSender(prefix,"SAVE",params,prefix); - - if (!u->ForceNickChange(u->uuid.c_str())) + if (!u->ForceNickChange(u->uuid)) { ServerInstance->Users->QuitUser(u, "Nickname collision"); } } - return true; + return CMD_SUCCESS; } diff --git a/src/modules/m_spanningtree/server.cpp b/src/modules/m_spanningtree/server.cpp index 05441da0c..69cae001c 100644 --- a/src/modules/m_spanningtree/server.cpp +++ b/src/modules/m_spanningtree/server.cpp @@ -19,72 +19,55 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" -#include "socketengine.h" #include "main.h" #include "utils.h" #include "link.h" #include "treeserver.h" #include "treesocket.h" - -/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h m_spanningtree/link.h */ +#include "commands.h" /* * Some server somewhere in the network introducing another server. * -- w */ -bool TreeSocket::RemoteServer(const std::string &prefix, parameterlist ¶ms) +CmdResult CommandServer::HandleServer(TreeServer* ParentOfThis, std::vector<std::string>& params) { - if (params.size() < 5) - { - SendError("Protocol error - Not enough parameters for SERVER command"); - return false; - } - std::string servername = params[0]; // password is not used for a remote server // hopcount is not used (ever) std::string sid = params[3]; std::string description = params[4]; - TreeServer* ParentOfThis = Utils->FindServer(prefix); + TreeSocket* socket = ParentOfThis->GetSocket(); - if (!ParentOfThis) + if (!InspIRCd::IsSID(sid)) { - this->SendError("Protocol error - Introduced remote server from unknown server "+prefix); - return false; - } - if (!ServerInstance->IsSID(sid)) - { - this->SendError("Invalid format server ID: "+sid+"!"); - return false; + socket->SendError("Invalid format server ID: "+sid+"!"); + return CMD_FAILURE; } TreeServer* CheckDupe = Utils->FindServer(servername); if (CheckDupe) { - this->SendError("Server "+servername+" already exists!"); + socket->SendError("Server "+servername+" already exists!"); ServerInstance->SNO->WriteToSnoMask('L', "Server \2"+CheckDupe->GetName()+"\2 being introduced from \2" + ParentOfThis->GetName() + "\2 denied, already exists. Closing link with " + ParentOfThis->GetName()); - return false; + return CMD_FAILURE; } CheckDupe = Utils->FindServer(sid); if (CheckDupe) { - this->SendError("Server ID "+sid+" already exists! You may want to specify the server ID for the server manually with <server:id> so they do not conflict."); + socket->SendError("Server ID "+sid+" already exists! You may want to specify the server ID for the server manually with <server:id> so they do not conflict."); ServerInstance->SNO->WriteToSnoMask('L', "Server \2"+servername+"\2 being introduced from \2" + ParentOfThis->GetName() + "\2 denied, server ID already exists on the network. Closing link with " + ParentOfThis->GetName()); - return false; + return CMD_FAILURE; } Link* lnk = Utils->FindLink(servername); - TreeServer *Node = new TreeServer(Utils, servername, description, sid, ParentOfThis,NULL, lnk ? lnk->Hidden : false); + TreeServer* Node = new TreeServer(servername, description, sid, ParentOfThis, ParentOfThis->GetSocket(), lnk ? lnk->Hidden : false); ParentOfThis->AddChild(Node); - params[4] = ":" + params[4]; - Utils->DoOneToAllButSender(prefix,"SERVER",params,prefix); ServerInstance->SNO->WriteToSnoMask('L', "Server \002"+ParentOfThis->GetName()+"\002 introduced server \002"+servername+"\002 ("+description+")"); - return true; + return CMD_SUCCESS; } @@ -105,17 +88,9 @@ bool TreeSocket::Outbound_Reply_Server(parameterlist ¶ms) std::string password = params[1]; std::string sid = params[3]; std::string description = params[4]; - int hops = atoi(params[2].c_str()); this->SendCapabilities(2); - if (hops) - { - this->SendError("Server too far away for authentication"); - ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication"); - return false; - } - if (!ServerInstance->IsSID(sid)) { this->SendError("Invalid format server ID: "+sid+"!"); @@ -163,15 +138,12 @@ bool TreeSocket::Outbound_Reply_Server(parameterlist ¶ms) Utils->timeoutlist.erase(this); linkID = sname; - MyRoot = new TreeServer(Utils, sname, description, sid, Utils->TreeRoot, this, x->Hidden); + MyRoot = new TreeServer(sname, description, sid, Utils->TreeRoot, this, x->Hidden); Utils->TreeRoot->AddChild(MyRoot); this->DoBurst(MyRoot); - params[4] = ":" + params[4]; - - /* IMPORTANT: Take password/hmac hash OUT of here before we broadcast the introduction! */ - params[1] = "*"; - Utils->DoOneToAllButSender(ServerInstance->Config->GetSID(),"SERVER",params,sname); + // This will send a * in place of the password/hmac + CommandServer::Builder(MyRoot).Forward(MyRoot); return true; } @@ -194,7 +166,7 @@ bool TreeSocket::CheckDuplicate(const std::string& sname, const std::string& sid } /* Check for fully initialized instances of the server by id */ - ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Looking for dupe SID %s", sid.c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Looking for dupe SID %s", sid.c_str()); CheckDupe = Utils->FindServerID(sid); if (CheckDupe) @@ -225,17 +197,9 @@ bool TreeSocket::Inbound_Server(parameterlist ¶ms) std::string password = params[1]; std::string sid = params[3]; std::string description = params[4]; - int hops = atoi(params[2].c_str()); this->SendCapabilities(2); - if (hops) - { - this->SendError("Server too far away for authentication"); - ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication"); - return false; - } - if (!ServerInstance->IsSID(sid)) { this->SendError("Invalid format server ID: "+sid+"!"); @@ -281,3 +245,11 @@ bool TreeSocket::Inbound_Server(parameterlist ¶ms) return false; } +CommandServer::Builder::Builder(TreeServer* server) + : CmdBuilder(server->GetParent()->GetID(), "SERVER") +{ + push(server->GetName()); + push_raw(" * 0 "); + push_raw(server->GetID()); + push_last(server->GetDesc()); +} diff --git a/src/modules/m_spanningtree/servercommand.cpp b/src/modules/m_spanningtree/servercommand.cpp new file mode 100644 index 000000000..fe5a38a9e --- /dev/null +++ b/src/modules/m_spanningtree/servercommand.cpp @@ -0,0 +1,48 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "inspircd.h" +#include "main.h" +#include "servercommand.h" + +ServerCommand::ServerCommand(Module* Creator, const std::string& Name, unsigned int MinParams, unsigned int MaxParams) + : CommandBase(Creator, Name, MinParams, MaxParams) +{ + ModuleSpanningTree* st = static_cast<ModuleSpanningTree*>(Creator); + st->CmdManager.AddCommand(this); +} + +RouteDescriptor ServerCommand::GetRouting(User* user, const std::vector<std::string>& parameters) +{ + // Broadcast server-to-server commands unless overridden + return ROUTE_BROADCAST; +} + +ServerCommand* ServerCommandManager::GetHandler(const std::string& command) const +{ + ServerCommandMap::const_iterator it = commands.find(command); + if (it != commands.end()) + return it->second; + return NULL; +} + +bool ServerCommandManager::AddCommand(ServerCommand* cmd) +{ + return commands.insert(std::make_pair(cmd->name, cmd)).second; +} diff --git a/src/modules/m_spanningtree/servercommand.h b/src/modules/m_spanningtree/servercommand.h new file mode 100644 index 000000000..2bd77fc84 --- /dev/null +++ b/src/modules/m_spanningtree/servercommand.h @@ -0,0 +1,83 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2013 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd 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, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "utils.h" + +class TreeServer; + +/** Base class for server-to-server commands that may have a (remote) user source or server source. + */ +class ServerCommand : public CommandBase +{ + public: + ServerCommand(Module* Creator, const std::string& Name, unsigned int MinPara = 0, unsigned int MaxPara = 0); + + virtual CmdResult Handle(User* user, std::vector<std::string>& parameters) = 0; + virtual RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters); +}; + +/** Base class for server-to-server command handlers which are only valid if their source is a user. + * When a server sends a command of this type and the source is a server (sid), the link is aborted. + */ +template <class T> +class UserOnlyServerCommand : public ServerCommand +{ + public: + UserOnlyServerCommand(Module* Creator, const std::string& Name, unsigned int MinPara = 0, unsigned int MaxPara = 0) + : ServerCommand(Creator, Name, MinPara, MaxPara) { } + + CmdResult Handle(User* user, std::vector<std::string>& parameters) + { + RemoteUser* remoteuser = IS_REMOTE(user); + if (!remoteuser) + return CMD_INVALID; + return static_cast<T*>(this)->HandleRemote(remoteuser, parameters); + } +}; + +/** Base class for server-to-server command handlers which are only valid if their source is a server. + * When a server sends a command of this type and the source is a user (uuid), the link is aborted. + */ +template <class T> +class ServerOnlyServerCommand : public ServerCommand +{ + public: + ServerOnlyServerCommand(Module* Creator, const std::string& Name, unsigned int MinPara = 0, unsigned int MaxPara = 0) + : ServerCommand(Creator, Name, MinPara, MaxPara) { } + + CmdResult Handle(User* user, std::vector<std::string>& parameters) + { + if (!IS_SERVER(user)) + return CMD_INVALID; + TreeServer* server = Utils->FindServer(user->server); + return static_cast<T*>(this)->HandleServer(server, parameters); + } +}; + +class ServerCommandManager +{ + typedef TR1NS::unordered_map<std::string, ServerCommand*> ServerCommandMap; + ServerCommandMap commands; + + public: + ServerCommand* GetHandler(const std::string& command) const; + bool AddCommand(ServerCommand* cmd); +}; diff --git a/src/modules/m_spanningtree/svsjoin.cpp b/src/modules/m_spanningtree/svsjoin.cpp index 416502369..552e08dd3 100644 --- a/src/modules/m_spanningtree/svsjoin.cpp +++ b/src/modules/m_spanningtree/svsjoin.cpp @@ -19,19 +19,13 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" -#include "socketengine.h" -#include "main.h" -#include "utils.h" -#include "treeserver.h" #include "commands.h" -CmdResult CommandSVSJoin::Handle(const std::vector<std::string>& parameters, User *user) +CmdResult CommandSVSJoin::Handle(User* user, std::vector<std::string>& parameters) { // Check for valid channel name - if (!ServerInstance->IsChannel(parameters[1].c_str(), ServerInstance->Config->Limits.ChanMax)) + if (!ServerInstance->IsChannel(parameters[1])) return CMD_FAILURE; // Check target exists @@ -40,8 +34,9 @@ CmdResult CommandSVSJoin::Handle(const std::vector<std::string>& parameters, Use return CMD_FAILURE; /* only join if it's local, otherwise just pass it on! */ - if (IS_LOCAL(u)) - Channel::JoinUser(u, parameters[1].c_str(), false, "", false, ServerInstance->Time()); + LocalUser* localuser = IS_LOCAL(u); + if (localuser) + Channel::JoinUser(localuser, parameters[1]); return CMD_SUCCESS; } diff --git a/src/modules/m_spanningtree/svsnick.cpp b/src/modules/m_spanningtree/svsnick.cpp index 79dc27ea3..a504afbd7 100644 --- a/src/modules/m_spanningtree/svsnick.cpp +++ b/src/modules/m_spanningtree/svsnick.cpp @@ -20,11 +20,9 @@ #include "inspircd.h" -#include "main.h" -#include "utils.h" #include "commands.h" -CmdResult CommandSVSNick::Handle(const std::vector<std::string>& parameters, User *user) +CmdResult CommandSVSNick::Handle(User* user, std::vector<std::string>& parameters) { User* u = ServerInstance->FindNick(parameters[0]); @@ -34,17 +32,17 @@ CmdResult CommandSVSNick::Handle(const std::vector<std::string>& parameters, Use if (isdigit(nick[0])) nick = u->uuid; - if (!u->ForceNickChange(nick.c_str())) + if (!u->ForceNickChange(nick)) { /* buh. UID them */ - if (!u->ForceNickChange(u->uuid.c_str())) + if (!u->ForceNickChange(u->uuid)) { ServerInstance->Users->QuitUser(u, "Nickname collision"); return CMD_SUCCESS; } } - u->age = atoi(parameters[2].c_str()); + u->age = ConvToInt(parameters[2]); } return CMD_SUCCESS; diff --git a/src/modules/m_spanningtree/svspart.cpp b/src/modules/m_spanningtree/svspart.cpp index 3bdf13b25..f86afa367 100644 --- a/src/modules/m_spanningtree/svspart.cpp +++ b/src/modules/m_spanningtree/svspart.cpp @@ -19,16 +19,10 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" -#include "socketengine.h" -#include "main.h" -#include "utils.h" -#include "treeserver.h" #include "commands.h" -CmdResult CommandSVSPart::Handle(const std::vector<std::string>& parameters, User *user) +CmdResult CommandSVSPart::Handle(User* user, std::vector<std::string>& parameters) { User* u = ServerInstance->FindUUID(parameters[0]); if (!u) diff --git a/src/modules/m_spanningtree/treeserver.cpp b/src/modules/m_spanningtree/treeserver.cpp index 493b05ebf..8af3e777d 100644 --- a/src/modules/m_spanningtree/treeserver.cpp +++ b/src/modules/m_spanningtree/treeserver.cpp @@ -21,56 +21,39 @@ #include "inspircd.h" -#include "socket.h" #include "xline.h" #include "main.h" -#include "../spanningtree.h" +#include "modules/spanningtree.h" #include "utils.h" #include "treeserver.h" -/* $ModDep: m_spanningtree/utils.h m_spanningtree/treeserver.h */ - /** We use this constructor only to create the 'root' item, Utils->TreeRoot, which * represents our own server. Therefore, it has no route, no parent, and * no socket associated with it. Its version string is our own local version. */ -TreeServer::TreeServer(SpanningTreeUtilities* Util, std::string Name, std::string Desc, const std::string &id) - : ServerName(Name.c_str()), ServerDesc(Desc), Utils(Util), ServerUser(ServerInstance->FakeClient) +TreeServer::TreeServer() + : Parent(NULL), Route(NULL), ServerName(ServerInstance->Config->ServerName), ServerDesc(ServerInstance->Config->ServerDesc) + , VersionString(ServerInstance->GetVersionString()), Socket(NULL), sid(ServerInstance->Config->GetSID()), ServerUser(ServerInstance->FakeClient) + , age(ServerInstance->Time()), Warned(false), bursting(false), UserCount(0), OperCount(0), rtt(0), StartBurst(0), Hidden(false) { - age = ServerInstance->Time(); - bursting = false; - Parent = NULL; - VersionString.clear(); - ServerUserCount = ServerOperCount = 0; - VersionString = ServerInstance->GetVersionString(); - Route = NULL; - Socket = NULL; /* Fix by brain */ - StartBurst = rtt = 0; - Warned = Hidden = false; AddHashEntry(); - SetID(id); } /** When we create a new server, we call this constructor to initialize it. * This constructor initializes the server's Route and Parent, and sets up * its ping counters so that it will be pinged one minute from now. */ -TreeServer::TreeServer(SpanningTreeUtilities* Util, std::string Name, std::string Desc, const std::string &id, TreeServer* Above, TreeSocket* Sock, bool Hide) - : Parent(Above), ServerName(Name.c_str()), ServerDesc(Desc), Socket(Sock), Utils(Util), ServerUser(new FakeUser(id, Name)), Hidden(Hide) +TreeServer::TreeServer(const std::string& Name, const std::string& Desc, const std::string& id, TreeServer* Above, TreeSocket* Sock, bool Hide) + : Parent(Above), ServerName(Name), ServerDesc(Desc), Socket(Sock), sid(id), ServerUser(new FakeUser(id, Name)) + , age(ServerInstance->Time()), Warned(false), bursting(true), UserCount(0), OperCount(0), rtt(0), Hidden(Hide) { - age = ServerInstance->Time(); - bursting = true; - VersionString.clear(); - ServerUserCount = ServerOperCount = 0; SetNextPingTime(ServerInstance->Time() + Utils->PingFreq); SetPingFlag(); - Warned = false; - rtt = 0; long ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000); this->StartBurst = ts; - ServerInstance->Logs->Log("m_spanningtree",DEBUG, "Started bursting at time %lu", ts); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Server %s started bursting at time %lu", sid.c_str(), ts); /* find the 'route' for this server (e.g. the one directly connected * to the local server, which we can use to reach it) @@ -124,8 +107,6 @@ TreeServer::TreeServer(SpanningTreeUtilities* Util, std::string Name, std::strin */ this->AddHashEntry(); - - SetID(id); } const std::string& TreeServer::GetID() @@ -138,9 +119,9 @@ void TreeServer::FinishBurstInternal() this->bursting = false; SetNextPingTime(ServerInstance->Time() + Utils->PingFreq); SetPingFlag(); - for(unsigned int q=0; q < ChildCount(); q++) + for (ChildServers::const_iterator i = Children.begin(); i != Children.end(); ++i) { - TreeServer* child = GetChild(q); + TreeServer* child = *i; child->FinishBurstInternal(); } } @@ -153,14 +134,7 @@ void TreeServer::FinishBurst() unsigned long bursttime = ts - this->StartBurst; ServerInstance->SNO->WriteToSnoMask(Parent == Utils->TreeRoot ? 'l' : 'L', "Received end of netburst from \2%s\2 (burst time: %lu %s)", ServerName.c_str(), (bursttime > 10000 ? bursttime / 1000 : bursttime), (bursttime > 10000 ? "secs" : "msecs")); - AddServerEvent(Utils->Creator, ServerName.c_str()); -} - -void TreeServer::SetID(const std::string &id) -{ - ServerInstance->Logs->Log("m_spanningtree",DEBUG, "Setting SID to " + id); - sid = id; - Utils->sidlist[sid] = this; + AddServerEvent(Utils->Creator, ServerName); } int TreeServer::QuitUsers(const std::string &reason) @@ -179,7 +153,7 @@ int TreeServer::QuitUsers(const std::string &reason) User* a = (User*)*n; if (!IS_LOCAL(a)) { - if (this->Utils->quiet_bursts) + if (Utils->quiet_bursts) a->quietquit = true; if (ServerInstance->Config->HideSplits) @@ -197,20 +171,8 @@ int TreeServer::QuitUsers(const std::string &reason) */ void TreeServer::AddHashEntry() { - server_hash::iterator iter = Utils->serverlist.find(this->ServerName.c_str()); - if (iter == Utils->serverlist.end()) - Utils->serverlist[this->ServerName.c_str()] = this; -} - -/** This method removes the reference to this object - * from the hash_map which is used for linear searches. - * It is only called by the default destructor. - */ -void TreeServer::DelHashEntry() -{ - server_hash::iterator iter = Utils->serverlist.find(this->ServerName.c_str()); - if (iter != Utils->serverlist.end()) - Utils->serverlist.erase(iter); + Utils->serverlist[ServerName] = this; + Utils->sidlist[sid] = this; } /** These accessors etc should be pretty self- @@ -221,11 +183,6 @@ TreeServer* TreeServer::GetRoute() return Route; } -std::string TreeServer::GetName() -{ - return ServerName.c_str(); -} - const std::string& TreeServer::GetDesc() { return ServerDesc; @@ -257,26 +214,6 @@ void TreeServer::SetPingFlag() LastPingWasGood = true; } -unsigned int TreeServer::GetUserCount() -{ - return ServerUserCount; -} - -void TreeServer::SetUserCount(int diff) -{ - ServerUserCount += diff; -} - -void TreeServer::SetOperCount(int diff) -{ - ServerOperCount += diff; -} - -unsigned int TreeServer::GetOperCount() -{ - return ServerOperCount; -} - TreeSocket* TreeServer::GetSocket() { return Socket; @@ -292,28 +229,6 @@ void TreeServer::SetVersion(const std::string &Version) VersionString = Version; } -unsigned int TreeServer::ChildCount() -{ - return Children.size(); -} - -TreeServer* TreeServer::GetChild(unsigned int n) -{ - if (n < Children.size()) - { - /* Make sure they cant request - * an out-of-range object. After - * all we know what these programmer - * types are like *grin*. - */ - return Children[n]; - } - else - { - return NULL; - } -} - void TreeServer::AddChild(TreeServer* Child) { Children.push_back(Child); @@ -334,13 +249,13 @@ bool TreeServer::DelChild(TreeServer* Child) * This is used during netsplits to automatically tidy up the * server tree. It is slow, we don't use it for much else. */ -bool TreeServer::Tidy() +void TreeServer::Tidy() { while (1) { std::vector<TreeServer*>::iterator a = Children.begin(); if (a == Children.end()) - return true; + return; TreeServer* s = *a; s->Tidy(); s->cull(); @@ -351,7 +266,7 @@ bool TreeServer::Tidy() CullResult TreeServer::cull() { - if (ServerUser != ServerInstance->FakeClient) + if (!IsRoot()) ServerUser->cull(); return classbase::cull(); } @@ -359,11 +274,9 @@ CullResult TreeServer::cull() TreeServer::~TreeServer() { /* We'd better tidy up after ourselves, eh? */ - this->DelHashEntry(); - if (ServerUser != ServerInstance->FakeClient) + if (!IsRoot()) delete ServerUser; - server_hash::iterator iter = Utils->sidlist.find(GetID()); - if (iter != Utils->sidlist.end()) - Utils->sidlist.erase(iter); + Utils->sidlist.erase(sid); + Utils->serverlist.erase(ServerName); } diff --git a/src/modules/m_spanningtree/treeserver.h b/src/modules/m_spanningtree/treeserver.h index 60b6d1def..8178c87fa 100644 --- a/src/modules/m_spanningtree/treeserver.h +++ b/src/modules/m_spanningtree/treeserver.h @@ -19,8 +19,7 @@ */ -#ifndef M_SPANNINGTREE_TREESERVER_H -#define M_SPANNINGTREE_TREESERVER_H +#pragma once #include "treesocket.h" @@ -43,65 +42,61 @@ class TreeServer : public classbase TreeServer* Parent; /* Parent entry */ TreeServer* Route; /* Route entry */ std::vector<TreeServer*> Children; /* List of child objects */ - irc::string ServerName; /* Server's name */ + std::string ServerName; /* Server's name */ std::string ServerDesc; /* Server's description */ std::string VersionString; /* Version string or empty string */ - unsigned int ServerUserCount; /* How many users are on this server? [note: doesn't care about +i] */ - unsigned int ServerOperCount; /* How many opers are on this server? */ - TreeSocket* Socket; /* For directly connected servers this points at the socket object */ + TreeSocket* Socket; /* Socket used to communicate with this server */ time_t NextPing; /* After this time, the server should be PINGed*/ bool LastPingWasGood; /* True if the server responded to the last PING with a PONG */ - SpanningTreeUtilities* Utils; /* Utility class */ std::string sid; /* Server ID */ - /** Set server ID - * @param id Server ID - * @throws CoreException on duplicate ID + /** This method is used to add this TreeServer to the + * hash maps. It is only called by the constructors. */ - void SetID(const std::string &id); + void AddHashEntry(); public: + typedef std::vector<TreeServer*> ChildServers; FakeUser* const ServerUser; /* User representing this server */ - time_t age; + const time_t age; bool Warned; /* True if we've warned opers about high latency on this server */ bool bursting; /* whether or not this server is bursting */ + unsigned int UserCount; /* How many users are on this server? [note: doesn't care about +i] */ + unsigned int OperCount; /* How many opers are on this server? */ + /** We use this constructor only to create the 'root' item, Utils->TreeRoot, which * represents our own server. Therefore, it has no route, no parent, and * no socket associated with it. Its version string is our own local version. */ - TreeServer(SpanningTreeUtilities* Util, std::string Name, std::string Desc, const std::string &id); + TreeServer(); /** When we create a new server, we call this constructor to initialize it. * This constructor initializes the server's Route and Parent, and sets up * its ping counters so that it will be pinged one minute from now. */ - TreeServer(SpanningTreeUtilities* Util, std::string Name, std::string Desc, const std::string &id, TreeServer* Above, TreeSocket* Sock, bool Hide); + TreeServer(const std::string& Name, const std::string& Desc, const std::string& id, TreeServer* Above, TreeSocket* Sock, bool Hide); int QuitUsers(const std::string &reason); - /** This method is used to add the structure to the - * hash_map for linear searches. It is only called - * by the constructors. - */ - void AddHashEntry(); - - /** This method removes the reference to this object - * from the hash_map which is used for linear searches. - * It is only called by the default destructor. - */ - void DelHashEntry(); - /** Get route. * The 'route' is defined as the locally- * connected server which can be used to reach this server. */ TreeServer* GetRoute(); + /** Returns true if this server is the tree root (i.e.: us) + */ + bool IsRoot() const { return (this->Parent == NULL); } + + /** Returns true if this server is locally connected + */ + bool IsLocal() const { return (this->Route == this); } + /** Get server name */ - std::string GetName(); + const std::string& GetName() const { return ServerName; } /** Get server description (GECOS) */ @@ -143,22 +138,6 @@ class TreeServer : public classbase */ void SetPingFlag(); - /** Get the number of users on this server. - */ - unsigned int GetUserCount(); - - /** Increment or decrement the user count by diff. - */ - void SetUserCount(int diff); - - /** Gets the numbers of opers on this server. - */ - unsigned int GetOperCount(); - - /** Increment or decrement the oper count by diff. - */ - void SetOperCount(int diff); - /** Get the TreeSocket pointer for local servers. * For remote servers, this returns NULL. */ @@ -173,13 +152,9 @@ class TreeServer : public classbase */ void SetVersion(const std::string &Version); - /** Return number of child servers - */ - unsigned int ChildCount(); - - /** Return a child server indexed 0..n + /** Return all child servers */ - TreeServer* GetChild(unsigned int n); + const ChildServers& GetChildren() const { return Children; } /** Add a child server */ @@ -193,7 +168,7 @@ class TreeServer : public classbase * This is used during netsplits to automatically tidy up the * server tree. It is slow, we don't use it for much else. */ - bool Tidy(); + void Tidy(); /** Get server ID */ @@ -206,9 +181,10 @@ class TreeServer : public classbase void FinishBurstInternal(); CullResult cull(); + /** Destructor + * Removes the reference to this object from the + * hash maps. */ ~TreeServer(); }; - -#endif diff --git a/src/modules/m_spanningtree/treesocket.h b/src/modules/m_spanningtree/treesocket.h index d8445572b..6d79711cc 100644 --- a/src/modules/m_spanningtree/treesocket.h +++ b/src/modules/m_spanningtree/treesocket.h @@ -20,12 +20,9 @@ */ -#ifndef M_SPANNINGTREE_TREESOCKET_H -#define M_SPANNINGTREE_TREESOCKET_H +#pragma once -#include "socket.h" #include "inspircd.h" -#include "xline.h" #include "utils.h" @@ -92,7 +89,6 @@ struct CapabData */ class TreeSocket : public BufferedSocket { - SpanningTreeUtilities* Utils; /* Utility class */ std::string linkID; /* Description for this link */ ServerState LinkState; /* Link state */ CapabData* capab; /* Link setup data (held until burst is sent) */ @@ -107,20 +103,20 @@ class TreeSocket : public BufferedSocket bool CheckDuplicate(const std::string& servername, const std::string& sid); public: - time_t age; + const time_t age; /** Because most of the I/O gubbins are encapsulated within * BufferedSocket, we just call the superclass constructor for * most of the action, and append a few of our own values * to it. */ - TreeSocket(SpanningTreeUtilities* Util, Link* link, Autoconnect* myac, const std::string& ipaddr); + TreeSocket(Link* link, Autoconnect* myac, const std::string& ipaddr); /** When a listening socket gives us a new file descriptor, * we must associate it with a socket without creating a new * connection. This constructor is used for this purpose. */ - TreeSocket(SpanningTreeUtilities* Util, int newfd, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server); + TreeSocket(int newfd, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server); /** Get link state */ @@ -166,11 +162,11 @@ class TreeSocket : public BufferedSocket * to server docs on the inspircd.org site, the other side * will then send back its own server string. */ - virtual void OnConnected(); + void OnConnected(); /** Handle socket error event */ - virtual void OnError(BufferedSocketError e); + void OnError(BufferedSocketError e) CXX11_OVERRIDE; /** Sends an error to the remote server, and displays it locally to show * that it was sent. @@ -180,13 +176,8 @@ class TreeSocket : public BufferedSocket /** Recursively send the server tree with distances as hops. * This is used during network burst to inform the other server * (and any of ITS servers too) of what servers we know about. - * If at any point any of these servers already exist on the other - * end, our connection may be terminated. The hopcounts given - * by this function are relative, this doesn't matter so long as - * they are all >1, as all the remote servers re-calculate them - * to be relative too, with themselves as hop 0. */ - void SendServers(TreeServer* Current, TreeServer* s, int hops); + void SendServers(TreeServer* Current, TreeServer* s); /** Returns module list as a string, filtered by filter * @param filter a module version bitmask, such as VF_COMMON or VF_OPTCOMMON @@ -197,9 +188,6 @@ class TreeSocket : public BufferedSocket */ void SendCapabilities(int phase); - /** Add modules to VF_COMMON list for backwards compatability */ - void CompatAddModules(std::vector<std::string>& modlist); - /* Isolate and return the elements that are different between two lists */ void ListDifference(const std::string &one, const std::string &two, char sep, std::string& mleft, std::string& mright); @@ -220,9 +208,6 @@ class TreeSocket : public BufferedSocket */ void Squit(TreeServer* Current, const std::string &reason); - /* Used on nick collision ... XXX ugly function HACK */ - int DoCollision(User *u, time_t remotets, const std::string &remoteident, const std::string &remoteip, const std::string &remoteuid); - /** Send one or more FJOINs for a channel of users. * If the length of a single line is more than 480-NICKMAX * in length, it is split over multiple lines. @@ -232,8 +217,8 @@ class TreeSocket : public BufferedSocket /** Send G, Q, Z and E lines */ void SendXLines(); - /** Send channel modes and topics */ - void SendChannelModes(); + /** Send all known information about a channel */ + void SyncChannel(Channel* chan); /** send all users and their oper state/modes */ void SendUsers(); @@ -252,57 +237,11 @@ class TreeSocket : public BufferedSocket /** Send one or more complete lines down the socket */ - void WriteLine(std::string line); + void WriteLine(const std::string& line); /** Handle ERROR command */ void Error(parameterlist ¶ms); - /** Remote AWAY */ - bool Away(const std::string &prefix, parameterlist ¶ms); - - /** SAVE to resolve nick collisions without killing */ - bool ForceNick(const std::string &prefix, parameterlist ¶ms); - - /** ENCAP command - */ - void Encap(User* who, parameterlist ¶ms); - - /** OPERQUIT command - */ - bool OperQuit(const std::string &prefix, parameterlist ¶ms); - - /** PONG - */ - bool LocalPong(const std::string &prefix, parameterlist ¶ms); - - /** VERSION - */ - bool ServerVersion(const std::string &prefix, parameterlist ¶ms); - - /** ADDLINE - */ - bool AddLine(const std::string &prefix, parameterlist ¶ms); - - /** DELLINE - */ - bool DelLine(const std::string &prefix, parameterlist ¶ms); - - /** WHOIS - */ - bool Whois(const std::string &prefix, parameterlist ¶ms); - - /** PUSH - */ - bool Push(const std::string &prefix, parameterlist ¶ms); - - /** PING - */ - bool LocalPing(const std::string &prefix, parameterlist ¶ms); - - /** <- (remote) <- SERVER - */ - bool RemoteServer(const std::string &prefix, parameterlist ¶ms); - /** (local) -> SERVER */ bool Outbound_Reply_Server(parameterlist ¶ms); @@ -323,15 +262,16 @@ class TreeSocket : public BufferedSocket /** Handle socket timeout from connect() */ - virtual void OnTimeout(); + void OnTimeout(); /** Handle server quit on close */ - virtual void Close(); + void Close(); /** Returns true if this server was introduced to the rest of the network */ bool Introduced(); -}; - -#endif + /** Fixes messages coming from old servers so the new command handlers understand them + */ + bool PreProcessOldProtocolMessage(User*& who, std::string& cmd, std::vector<std::string>& params); +}; diff --git a/src/modules/m_spanningtree/treesocket1.cpp b/src/modules/m_spanningtree/treesocket1.cpp index cb2c93548..dc9bb5331 100644 --- a/src/modules/m_spanningtree/treesocket1.cpp +++ b/src/modules/m_spanningtree/treesocket1.cpp @@ -21,36 +21,29 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" -#include "socketengine.h" +#include "iohook.h" #include "main.h" -#include "../spanningtree.h" +#include "modules/spanningtree.h" #include "utils.h" #include "treeserver.h" #include "link.h" #include "treesocket.h" -#include "resolvers.h" +#include "commands.h" /** Because most of the I/O gubbins are encapsulated within * BufferedSocket, we just call the superclass constructor for * most of the action, and append a few of our own values * to it. */ -TreeSocket::TreeSocket(SpanningTreeUtilities* Util, Link* link, Autoconnect* myac, const std::string& ipaddr) - : Utils(Util) +TreeSocket::TreeSocket(Link* link, Autoconnect* myac, const std::string& ipaddr) + : linkID(assign(link->Name)), LinkState(CONNECTING), MyRoot(NULL), proto_version(0), ConnectionFailureShown(false) + , age(ServerInstance->Time()) { - age = ServerInstance->Time(); - linkID = assign(link->Name); capab = new CapabData; capab->link = link; capab->ac = myac; capab->capab_phase = 0; - MyRoot = NULL; - proto_version = 0; - ConnectionFailureShown = false; - LinkState = CONNECTING; if (!link->Hook.empty()) { ServiceProvider* prov = ServerInstance->Modules->FindService(SERVICE_IOHOOK, link->Hook); @@ -59,7 +52,7 @@ TreeSocket::TreeSocket(SpanningTreeUtilities* Util, Link* link, Autoconnect* mya SetError("Could not find hook '" + link->Hook + "' for connection to " + linkID); return; } - AddIOHook(prov->creator); + AddIOHook(static_cast<IOHook*>(prov)); } DoConnect(ipaddr, link->Port, link->Timeout, link->Bind); Utils->timeoutlist[this] = std::pair<std::string, int>(linkID, link->Timeout); @@ -70,19 +63,15 @@ TreeSocket::TreeSocket(SpanningTreeUtilities* Util, Link* link, Autoconnect* mya * we must associate it with a socket without creating a new * connection. This constructor is used for this purpose. */ -TreeSocket::TreeSocket(SpanningTreeUtilities* Util, int newfd, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) - : BufferedSocket(newfd), Utils(Util) +TreeSocket::TreeSocket(int newfd, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) + : BufferedSocket(newfd) + , linkID("inbound from " + client->addr()), LinkState(WAIT_AUTH_1), MyRoot(NULL), proto_version(0) + , ConnectionFailureShown(false), age(ServerInstance->Time()) { capab = new CapabData; capab->capab_phase = 0; - MyRoot = NULL; - age = ServerInstance->Time(); - LinkState = WAIT_AUTH_1; - proto_version = 0; - ConnectionFailureShown = false; - linkID = "inbound from " + client->addr(); - - FOREACH_MOD(I_OnHookIO, OnHookIO(this, via)); + + FOREACH_MOD(OnHookIO, (this, via)); if (GetIOHook()) GetIOHook()->OnStreamSocketAccept(this, client, server); SendCapabilities(1); @@ -114,8 +103,7 @@ CullResult TreeSocket::cull() TreeSocket::~TreeSocket() { - if (capab) - delete capab; + delete capab; } /** When an outbound connection finishes connecting, we receive @@ -157,16 +145,15 @@ void TreeSocket::SendError(const std::string &errormessage) */ void TreeSocket::SquitServer(std::string &from, TreeServer* Current, int& num_lost_servers, int& num_lost_users) { - std::string servername = Current->GetName(); - ServerInstance->Logs->Log("m_spanningtree",DEBUG,"SquitServer for %s from %s", - servername.c_str(), from.c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "SquitServer for %s from %s", Current->GetName().c_str(), from.c_str()); /* recursively squit the servers attached to 'Current'. * We're going backwards so we don't remove users * while we still need them ;) */ - for (unsigned int q = 0; q < Current->ChildCount(); q++) + const TreeServer::ChildServers& children = Current->GetChildren(); + for (TreeServer::ChildServers::const_iterator i = children.begin(); i != children.end(); ++i) { - TreeServer* recursive_server = Current->GetChild(q); + TreeServer* recursive_server = *i; this->SquitServer(from,recursive_server, num_lost_servers, num_lost_users); } /* Now we've whacked the kids, whack self */ @@ -182,22 +169,21 @@ void TreeSocket::Squit(TreeServer* Current, const std::string &reason) { bool LocalSquit = false; - if ((Current) && (Current != Utils->TreeRoot)) + if (!Current->IsRoot()) { DelServerEvent(Utils->Creator, Current->GetName()); - if (!Current->GetSocket() || Current->GetSocket()->Introduced()) - { - parameterlist params; - params.push_back(Current->GetID()); - params.push_back(":"+reason); - Utils->DoOneToAllButSender(Current->GetParent()->GetID(),"SQUIT",params,Current->GetID()); - } - - if (Current->GetParent() == Utils->TreeRoot) + if (Current->IsLocal()) { ServerInstance->SNO->WriteGlobalSno('l', "Server \002"+Current->GetName()+"\002 split: "+reason); LocalSquit = true; + if (Current->GetSocket()->Introduced()) + { + CmdBuilder params("SQUIT"); + params.push_back(Current->GetID()); + params.push_last(reason); + params.Broadcast(); + } } else { @@ -219,8 +205,20 @@ void TreeSocket::Squit(TreeServer* Current, const std::string &reason) Close(); } } - else - ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Squit from unknown server"); +} + +CmdResult CommandSQuit::HandleServer(TreeServer* server, std::vector<std::string>& params) +{ + TreeServer* quitting = Utils->FindServer(params[0]); + if (!quitting) + { + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Squit from unknown server"); + return CMD_FAILURE; + } + + TreeSocket* sock = server->GetSocket(); + sock->Squit(quitting, params[1]); + return CMD_SUCCESS; } /** This function is called when we receive data from a remote diff --git a/src/modules/m_spanningtree/treesocket2.cpp b/src/modules/m_spanningtree/treesocket2.cpp index 5007fe921..8d14ff5ff 100644 --- a/src/modules/m_spanningtree/treesocket2.cpp +++ b/src/modules/m_spanningtree/treesocket2.cpp @@ -23,16 +23,13 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" -#include "socketengine.h" #include "main.h" #include "utils.h" #include "treeserver.h" -#include "link.h" #include "treesocket.h" #include "resolvers.h" +#include "commands.h" /* Handle ERROR command */ void TreeSocket::Error(parameterlist ¶ms) @@ -47,7 +44,7 @@ void TreeSocket::Split(const std::string& line, std::string& prefix, std::string if (!tokens.GetToken(prefix)) return; - + if (prefix[0] == ':') { prefix = prefix.substr(1); @@ -84,7 +81,7 @@ void TreeSocket::ProcessLine(std::string &line) std::string command; parameterlist params; - ServerInstance->Logs->Log("m_spanningtree", RAWIO, "S[%d] I %s", this->GetFd(), line.c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_RAWIO, "S[%d] I %s", this->GetFd(), line.c_str()); Split(line, prefix, command, params); @@ -151,7 +148,7 @@ void TreeSocket::ProcessLine(std::string &line) { if (params.size()) { - time_t them = atoi(params[0].c_str()); + time_t them = ConvToInt(params[0]); time_t delta = them - ServerInstance->Time(); if ((delta < -600) || (delta > 600)) { @@ -176,20 +173,14 @@ void TreeSocket::ProcessLine(std::string &line) linkID = capab->name; - MyRoot = new TreeServer(Utils, capab->name, capab->description, capab->sid, Utils->TreeRoot, this, capab->hidden); + MyRoot = new TreeServer(capab->name, capab->description, capab->sid, Utils->TreeRoot, this, capab->hidden); Utils->TreeRoot->AddChild(MyRoot); MyRoot->bursting = true; this->DoBurst(MyRoot); - parameterlist sparams; - sparams.push_back(MyRoot->GetName()); - sparams.push_back("*"); - sparams.push_back("0"); - sparams.push_back(MyRoot->GetID()); - sparams.push_back(":" + MyRoot->GetDesc()); - Utils->DoOneToAllButSender(ServerInstance->Config->GetSID(), "SERVER", sparams, MyRoot->GetName()); - Utils->DoOneToAllButSender(MyRoot->GetID(), "BURST", params, MyRoot->GetName()); + CommandServer::Builder(MyRoot).Forward(MyRoot); + CmdBuilder(MyRoot->GetID(), "BURST").insert(params).Forward(MyRoot); } else if (command == "ERROR") { @@ -257,7 +248,7 @@ void TreeSocket::ProcessConnectedLine(std::string& prefix, std::string& command, * crossing the users QUIT further upstream from the server. Thanks jilles! */ - if ((prefix.length() == UUID_LENGTH-1) && (isdigit(prefix[0])) && + if ((prefix.length() == UIDGenerator::UUID_LENGTH) && (isdigit(prefix[0])) && ((command == "FMODE") || (command == "MODE") || (command == "KICK") || (command == "TOPIC") || (command == "KILL") || (command == "ADDLINE") || (command == "DELLINE"))) { /* Special case, we cannot drop these commands as they've been committed already on a @@ -271,7 +262,7 @@ void TreeSocket::ProcessConnectedLine(std::string& prefix, std::string& command, } else { - ServerInstance->Logs->Log("m_spanningtree", DEBUG, "Command '%s' from unknown prefix '%s'! Dropping entire command.", + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Command '%s' from unknown prefix '%s'! Dropping entire command.", command.c_str(), prefix.c_str()); return; } @@ -302,210 +293,68 @@ void TreeSocket::ProcessConnectedLine(std::string& prefix, std::string& command, if ((!route_back_again) || (route_back_again->GetSocket() != this)) { if (route_back_again) - ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Protocol violation: Fake direction '%s' from connection '%s'", + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Protocol violation: Fake direction '%s' from connection '%s'", prefix.c_str(),linkID.c_str()); return; } - /* - * First up, check for any malformed commands (e.g. MODE without a timestamp) - * and rewrite commands where necessary (SVSMODE -> MODE for services). -- w - */ - if (command == "SVSMODE") // This isn't in an "else if" so we still force FMODE for changes on channels. - command = "MODE"; - - // TODO move all this into Commands - if (command == "MAP") - { - Utils->Creator->HandleMap(params, who); - } - else if (command == "SERVER") - { - this->RemoteServer(prefix,params); - } - else if (command == "ERROR") - { - this->Error(params); - } - else if (command == "AWAY") - { - this->Away(prefix,params); - } - else if (command == "PING") - { - this->LocalPing(prefix,params); - } - else if (command == "PONG") - { - TreeServer *s = Utils->FindServer(prefix); - if (s && s->bursting) - { - ServerInstance->SNO->WriteGlobalSno('l',"Server \002%s\002 has not finished burst, forcing end of burst (send ENDBURST!)", prefix.c_str()); - s->FinishBurst(); - } - this->LocalPong(prefix,params); - } - else if (command == "VERSION") - { - this->ServerVersion(prefix,params); - } - else if (command == "ADDLINE") - { - this->AddLine(prefix,params); - } - else if (command == "DELLINE") - { - this->DelLine(prefix,params); - } - else if (command == "SAVE") - { - this->ForceNick(prefix,params); - } - else if (command == "OPERQUIT") - { - this->OperQuit(prefix,params); - } - else if (command == "IDLE") - { - this->Whois(prefix,params); - } - else if (command == "PUSH") - { - this->Push(prefix,params); - } - else if (command == "SQUIT") - { - if (params.size() == 2) - { - this->Squit(Utils->FindServer(params[0]),params[1]); - } - } - else if (command == "SNONOTICE") - { - if (params.size() >= 2) - { - ServerInstance->SNO->WriteToSnoMask(params[0][0], "From " + who->nick + ": "+ params[1]); - params[1] = ":" + params[1]; - Utils->DoOneToAllButSender(prefix, command, params, prefix); - } - } - else if (command == "BURST") - { - // Set prefix server as bursting - TreeServer* ServerSource = Utils->FindServer(prefix); - if (!ServerSource) - { - ServerInstance->SNO->WriteGlobalSno('l', "WTF: Got BURST from a non-server(?): %s", prefix.c_str()); - return; - } - - ServerSource->bursting = true; - Utils->DoOneToAllButSender(prefix, command, params, prefix); - } - else if (command == "ENDBURST") + // Translate commands coming from servers using an older protocol + if (proto_version < ProtocolVersion) { - TreeServer* ServerSource = Utils->FindServer(prefix); - if (!ServerSource) - { - ServerInstance->SNO->WriteGlobalSno('l', "WTF: Got ENDBURST from a non-server(?): %s", prefix.c_str()); + if (!PreProcessOldProtocolMessage(who, command, params)) return; - } - - ServerSource->FinishBurst(); - Utils->DoOneToAllButSender(prefix, command, params, prefix); - } - else if (command == "ENCAP") - { - this->Encap(who, params); } - else if (command == "NICK") - { - if (params.size() != 2) - { - SendError("Protocol violation: Wrong number of parameters for NICK message"); - return; - } - - if (IS_SERVER(who)) - { - SendError("Protocol violation: Server changing nick"); - return; - } - - if ((isdigit(params[0][0])) && (params[0] != who->uuid)) - { - SendError("Protocol violation: User changing nick to an invalid UID - " + params[0]); - return; - } - /* Update timestamp on user when they change nicks */ - who->age = atoi(params[1].c_str()); - - /* - * On nick messages, check that the nick doesnt already exist here. - * If it does, perform collision logic. - */ - User* x = ServerInstance->FindNickOnly(params[0]); - if ((x) && (x != who)) - { - int collideret = 0; - /* x is local, who is remote */ - collideret = this->DoCollision(x, who->age, who->ident, who->GetIPString(), who->uuid); - if (collideret != 1) - { - /* - * Remote client lost, or both lost, parsing or passing on this - * nickchange would be pointless, as the incoming client's server will - * soon recieve SVSNICK to change its nick to its UID. :) -- w00t - */ - return; - } - } - who->ForceNickChange(params[0].c_str()); - Utils->RouteCommand(route_back_again, command, params, who); - } - else + ServerCommand* scmd = Utils->Creator->CmdManager.GetHandler(command); + CommandBase* cmdbase = scmd; + Command* cmd; + if (!scmd) { - Command* cmd = ServerInstance->Parser->GetHandler(command); - + // Not a special server-to-server command + cmd = ServerInstance->Parser->GetHandler(command); if (!cmd) { - irc::stringjoiner pmlist(" ", params, 0, params.size() - 1); - ServerInstance->Logs->Log("m_spanningtree", SPARSE, "Unrecognised S2S command :%s %s %s", + irc::stringjoiner pmlist(params); + ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "Unrecognised S2S command :%s %s %s", who->uuid.c_str(), command.c_str(), pmlist.GetJoined().c_str()); SendError("Unrecognised command '" + command + "' -- possibly loaded mismatched modules"); return; } + cmdbase = cmd; + } - if (params.size() < cmd->min_params) - { - irc::stringjoiner pmlist(" ", params, 0, params.size() - 1); - ServerInstance->Logs->Log("m_spanningtree", SPARSE, "Insufficient parameters for S2S command :%s %s %s", - who->uuid.c_str(), command.c_str(), pmlist.GetJoined().c_str()); - SendError("Insufficient parameters for command '" + command + "'"); - return; - } + if (params.size() < cmdbase->min_params) + { + irc::stringjoiner pmlist(params); + ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "Insufficient parameters for S2S command :%s %s %s", + who->uuid.c_str(), command.c_str(), pmlist.GetJoined().c_str()); + SendError("Insufficient parameters for command '" + command + "'"); + return; + } - if ((!params.empty()) && (params.back().empty()) && (!cmd->allow_empty_last_param)) - { - // the last param is empty and the command handler doesn't allow that, check if there will be enough params if we drop the last - if (params.size()-1 < cmd->min_params) - return; - params.pop_back(); - } + if ((!params.empty()) && (params.back().empty()) && (!cmdbase->allow_empty_last_param)) + { + // the last param is empty and the command handler doesn't allow that, check if there will be enough params if we drop the last + if (params.size()-1 < cmdbase->min_params) + return; + params.pop_back(); + } - CmdResult res = cmd->Handle(params, who); + CmdResult res; + if (scmd) + res = scmd->Handle(who, params); + else + res = cmd->Handle(params, who); - if (res == CMD_INVALID) - { - irc::stringjoiner pmlist(" ", params, 0, params.size() - 1); - ServerInstance->Logs->Log("m_spanningtree", SPARSE, "Error handling S2S command :%s %s %s", - who->uuid.c_str(), command.c_str(), pmlist.GetJoined().c_str()); - SendError("Error handling '" + command + "' -- possibly loaded mismatched modules"); - } - else if (res == CMD_SUCCESS) - Utils->RouteCommand(route_back_again, command, params, who); + if (res == CMD_INVALID) + { + irc::stringjoiner pmlist(params); + ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "Error handling S2S command :%s %s %s", + who->uuid.c_str(), command.c_str(), pmlist.GetJoined().c_str()); + SendError("Error handling '" + command + "' -- possibly loaded mismatched modules"); } + else if (res == CMD_SUCCESS) + Utils->RouteCommand(route_back_again, cmdbase, params, who); } void TreeSocket::OnTimeout() @@ -534,7 +383,7 @@ void TreeSocket::Close() time_t server_uptime = ServerInstance->Time() - this->age; if (server_uptime) { - std::string timestr = Utils->Creator->TimeToStr(server_uptime); + std::string timestr = ModuleSpanningTree::TimeToStr(server_uptime); ServerInstance->SNO->WriteGlobalSno('l', "Connection to '\2%s\2' was established for %s", linkID.c_str(), timestr.c_str()); } } diff --git a/src/modules/m_spanningtree/uid.cpp b/src/modules/m_spanningtree/uid.cpp index f33cb038d..82d78124a 100644 --- a/src/modules/m_spanningtree/uid.cpp +++ b/src/modules/m_spanningtree/uid.cpp @@ -23,14 +23,10 @@ #include "commands.h" #include "utils.h" -#include "link.h" -#include "treesocket.h" #include "treeserver.h" -#include "resolvers.h" -CmdResult CommandUID::Handle(const parameterlist ¶ms, User* serversrc) +CmdResult CommandUID::HandleServer(TreeServer* remoteserver, std::vector<std::string>& params) { - SpanningTreeUtilities* Utils = ((ModuleSpanningTree*)(Module*)creator)->Utils; /** Do we have enough parameters: * 0 1 2 3 4 5 6 7 8 9 (n-1) * UID uuid age nick host dhost ident ip.string signon +modes (modepara) :gecos @@ -38,14 +34,10 @@ CmdResult CommandUID::Handle(const parameterlist ¶ms, User* serversrc) time_t age_t = ConvToInt(params[1]); time_t signon = ConvToInt(params[7]); std::string empty; - std::string modestr(params[8]); + const std::string& modestr = params[8]; - TreeServer* remoteserver = Utils->FindServer(serversrc->server); - - if (!remoteserver) - return CMD_INVALID; /* Is this a valid UID, and not misrouted? */ - if (params[0].length() != 9 || params[0].substr(0,3) != serversrc->uuid) + if (params[0].length() != UIDGenerator::UUID_LENGTH || params[0].substr(0, 3) != remoteserver->GetID()) return CMD_INVALID; /* Check parameters for validity before introducing the client, discovered by dmb */ if (!age_t) @@ -54,7 +46,6 @@ CmdResult CommandUID::Handle(const parameterlist ¶ms, User* serversrc) return CMD_INVALID; if (modestr[0] != '+') return CMD_INVALID; - TreeSocket* sock = remoteserver->GetRoute()->GetSocket(); /* check for collision */ user_hash::iterator iter = ServerInstance->Users->clientlist->find(params[2]); @@ -64,17 +55,13 @@ CmdResult CommandUID::Handle(const parameterlist ¶ms, User* serversrc) /* * Nick collision. */ - int collide = sock->DoCollision(iter->second, age_t, params[5], params[6], params[0]); - ServerInstance->Logs->Log("m_spanningtree",DEBUG,"*** Collision on %s, collide=%d", params[2].c_str(), collide); + int collide = Utils->DoCollision(iter->second, remoteserver, age_t, params[5], params[6], params[0]); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "*** Collision on %s, collide=%d", params[2].c_str(), collide); if (collide != 1) { - /* remote client lost, make sure we change their nick for the hash too - * - * This alters the line that will be sent to other servers, which - * commands normally shouldn't do; hence the required const_cast. - */ - const_cast<parameterlist&>(params)[2] = params[0]; + // Remote client lost, make sure we change their nick for the hash too + params[2] = params[0]; } } @@ -88,7 +75,7 @@ CmdResult CommandUID::Handle(const parameterlist ¶ms, User* serversrc) } catch (...) { - ServerInstance->Logs->Log("m_spanningtree", DEFAULT, "Duplicate UUID %s in client introduction", params[0].c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Duplicate UUID %s in client introduction", params[0].c_str()); return CMD_INVALID; } (*(ServerInstance->Users->clientlist))[params[2]] = _new; @@ -101,49 +88,47 @@ CmdResult CommandUID::Handle(const parameterlist ¶ms, User* serversrc) _new->signon = signon; _new->age = age_t; - /* we need to remove the + from the modestring, so we can do our stuff */ - std::string::size_type pos_after_plus = modestr.find_first_not_of('+'); - if (pos_after_plus != std::string::npos) - modestr = modestr.substr(pos_after_plus); - unsigned int paramptr = 9; - for (std::string::iterator v = modestr.begin(); v != modestr.end(); v++) + + for (std::string::const_iterator v = modestr.begin(); v != modestr.end(); ++v) { - /* For each mode thats set, increase counter */ + // Accept more '+' chars, for now + if (*v == '+') + continue; + + /* For each mode thats set, find the mode handler and set it on the new user */ ModeHandler* mh = ServerInstance->Modes->FindMode(*v, MODETYPE_USER); + if (!mh) + { + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Unrecognised mode '%c' for a user in UID, dropping link", *v); + return CMD_INVALID; + } - if (mh) + if (mh->GetNumParams(true)) { - if (mh->GetNumParams(true)) - { - if (paramptr >= params.size() - 1) - return CMD_INVALID; - std::string mp = params[paramptr++]; - /* IMPORTANT NOTE: - * All modes are assumed to succeed here as they are being set by a remote server. - * Modes CANNOT FAIL here. If they DO fail, then the failure is ignored. This is important - * to note as all but one modules currently cannot ever fail in this situation, except for - * m_servprotect which specifically works this way to prevent the mode being set ANYWHERE - * but here, at client introduction. You may safely assume this behaviour is standard and - * will not change in future versions if you want to make use of this protective behaviour - * yourself. - */ - mh->OnModeChange(_new, _new, NULL, mp, true); - } - else - mh->OnModeChange(_new, _new, NULL, empty, true); - _new->SetMode(*v, true); + if (paramptr >= params.size() - 1) + return CMD_INVALID; + std::string mp = params[paramptr++]; + /* IMPORTANT NOTE: + * All modes are assumed to succeed here as they are being set by a remote server. + * Modes CANNOT FAIL here. If they DO fail, then the failure is ignored. This is important + * to note as all but one modules currently cannot ever fail in this situation, except for + * m_servprotect which specifically works this way to prevent the mode being set ANYWHERE + * but here, at client introduction. You may safely assume this behaviour is standard and + * will not change in future versions if you want to make use of this protective behaviour + * yourself. + */ + mh->OnModeChange(_new, _new, NULL, mp, true); } + else + mh->OnModeChange(_new, _new, NULL, empty, true); + _new->SetMode(mh, true); } - /* now we've done with modes processing, put the + back for remote servers */ - if (modestr[0] != '+') - modestr = "+" + modestr; - _new->SetClientIP(params[6].c_str()); ServerInstance->Users->AddGlobalClone(_new); - remoteserver->SetUserCount(1); // increment by 1 + remoteserver->UserCount++; bool dosend = true; @@ -151,34 +136,42 @@ CmdResult CommandUID::Handle(const parameterlist ¶ms, User* serversrc) dosend = false; if (dosend) - ServerInstance->SNO->WriteToSnoMask('C',"Client connecting at %s: %s (%s) [%s]", _new->server.c_str(), _new->GetFullRealHost().c_str(), _new->GetIPString(), _new->fullname.c_str()); + ServerInstance->SNO->WriteToSnoMask('C',"Client connecting at %s: %s (%s) [%s]", _new->server.c_str(), _new->GetFullRealHost().c_str(), _new->GetIPString().c_str(), _new->fullname.c_str()); - FOREACH_MOD(I_OnPostConnect,OnPostConnect(_new)); + FOREACH_MOD(OnPostConnect, (_new)); return CMD_SUCCESS; } -CmdResult CommandFHost::Handle(const parameterlist ¶ms, User* src) +CmdResult CommandFHost::HandleRemote(RemoteUser* src, std::vector<std::string>& params) { - if (IS_SERVER(src)) - return CMD_FAILURE; - src->ChangeDisplayedHost(params[0].c_str()); + src->ChangeDisplayedHost(params[0]); return CMD_SUCCESS; } -CmdResult CommandFIdent::Handle(const parameterlist ¶ms, User* src) +CmdResult CommandFIdent::HandleRemote(RemoteUser* src, std::vector<std::string>& params) { - if (IS_SERVER(src)) - return CMD_FAILURE; - src->ChangeIdent(params[0].c_str()); + src->ChangeIdent(params[0]); return CMD_SUCCESS; } -CmdResult CommandFName::Handle(const parameterlist ¶ms, User* src) +CmdResult CommandFName::HandleRemote(RemoteUser* src, std::vector<std::string>& params) { - if (IS_SERVER(src)) - return CMD_FAILURE; - src->ChangeName(params[0].c_str()); + src->ChangeName(params[0]); return CMD_SUCCESS; } +CommandUID::Builder::Builder(User* user) + : CmdBuilder(user->uuid.substr(0, 3), "UID") +{ + push(user->uuid); + push_int(user->age); + push(user->nick); + push(user->host); + push(user->dhost); + push(user->ident); + push(user->GetIPString()); + push_int(user->signon); + push('+').push_raw(user->FormatModes(true)); + push_last(user->fullname); +} diff --git a/src/modules/m_spanningtree/utils.cpp b/src/modules/m_spanningtree/utils.cpp index 1879d7111..40db1339c 100644 --- a/src/modules/m_spanningtree/utils.cpp +++ b/src/modules/m_spanningtree/utils.cpp @@ -21,16 +21,15 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" -#include "socketengine.h" #include "main.h" #include "utils.h" #include "treeserver.h" -#include "link.h" #include "treesocket.h" #include "resolvers.h" +#include "commandbuilder.h" + +SpanningTreeUtilities* Utils = NULL; /* Create server sockets off a listener. */ ModResult ModuleSpanningTree::OnAcceptConnection(int newsock, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) @@ -45,7 +44,7 @@ ModResult ModuleSpanningTree::OnAcceptConnection(int newsock, ListenSocket* from if (*i == "*" || *i == incomingip || irc::sockets::cidr_mask(*i).match(*client)) { /* we don't need to do anything with the pointer, creating it stores it in the necessary places */ - new TreeSocket(Utils, newsock, from, client, server); + new TreeSocket(newsock, from, client, server); return MOD_RES_ALLOW; } } @@ -61,10 +60,10 @@ ModResult ModuleSpanningTree::OnAcceptConnection(int newsock, ListenSocket* from */ TreeServer* SpanningTreeUtilities::FindServer(const std::string &ServerName) { - if (ServerInstance->IsSID(ServerName)) + if (InspIRCd::IsSID(ServerName)) return this->FindServerID(ServerName); - server_hash::iterator iter = serverlist.find(ServerName.c_str()); + server_hash::iterator iter = serverlist.find(ServerName); if (iter != serverlist.end()) { return iter->second; @@ -83,8 +82,6 @@ TreeServer* SpanningTreeUtilities::FindServer(const std::string &ServerName) */ TreeServer* SpanningTreeUtilities::BestRouteTo(const std::string &ServerName) { - if (ServerName.c_str() == TreeRoot->GetName() || ServerName == ServerInstance->Config->GetSID()) - return NULL; TreeServer* Found = FindServer(ServerName); if (Found) { @@ -130,24 +127,21 @@ TreeServer* SpanningTreeUtilities::FindServerID(const std::string &id) return NULL; } -SpanningTreeUtilities::SpanningTreeUtilities(ModuleSpanningTree* C) : Creator(C) +SpanningTreeUtilities::SpanningTreeUtilities(ModuleSpanningTree* C) + : Creator(C), TreeRoot(NULL) { - ServerInstance->Logs->Log("m_spanningtree",DEBUG,"***** Using SID for hash: %s *****", ServerInstance->Config->GetSID().c_str()); + ServerInstance->Timers->AddTimer(&RefreshTimer); - this->TreeRoot = new TreeServer(this, ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc, ServerInstance->Config->GetSID()); this->ReadConfiguration(); } CullResult SpanningTreeUtilities::cull() { - while (TreeRoot->ChildCount()) + const TreeServer::ChildServers& children = TreeRoot->GetChildren(); + while (!children.empty()) { - TreeServer* child_server = TreeRoot->GetChild(0); - if (child_server) - { - TreeSocket* sock = child_server->GetSocket(); - sock->Close(); - } + TreeSocket* sock = children.front()->GetSocket(); + sock->Close(); } for(std::map<TreeSocket*, std::pair<std::string, int> >::iterator i = timeoutlist.begin(); i != timeoutlist.end(); ++i) @@ -165,14 +159,8 @@ SpanningTreeUtilities::~SpanningTreeUtilities() delete TreeRoot; } -void SpanningTreeUtilities::AddThisServer(TreeServer* server, TreeServerList &list) -{ - if (list.find(server) == list.end()) - list[server] = server; -} - /* returns a list of DIRECT servernames for a specific channel */ -void SpanningTreeUtilities::GetListOfServersForChannel(Channel* c, TreeServerList &list, char status, const CUList &exempt_list) +void SpanningTreeUtilities::GetListOfServersForChannel(Channel* c, TreeSocketSet& list, char status, const CUList& exempt_list) { unsigned int minrank = 0; if (status) @@ -196,84 +184,36 @@ void SpanningTreeUtilities::GetListOfServersForChannel(Channel* c, TreeServerLis { TreeServer* best = this->BestRouteTo(i->first->server); if (best) - AddThisServer(best,list); + list.insert(best->GetSocket()); } } return; } -bool SpanningTreeUtilities::DoOneToAllButSender(const std::string &prefix, const std::string &command, const parameterlist ¶ms, const std::string& omit) +void SpanningTreeUtilities::DoOneToAllButSender(const CmdBuilder& params, TreeServer* omitroute) { - TreeServer* omitroute = this->BestRouteTo(omit); - std::string FullLine = ":" + prefix + " " + command; - unsigned int words = params.size(); - for (unsigned int x = 0; x < words; x++) - { - FullLine = FullLine + " " + params[x]; - } - unsigned int items = this->TreeRoot->ChildCount(); - for (unsigned int x = 0; x < items; x++) - { - TreeServer* Route = this->TreeRoot->GetChild(x); - // Send the line IF: - // The route has a socket (its a direct connection) - // The route isnt the one to be omitted - // The route isnt the path to the one to be omitted - if ((Route) && (Route->GetSocket()) && (Route->GetName() != omit) && (omitroute != Route)) - { - TreeSocket* Sock = Route->GetSocket(); - if (Sock) - Sock->WriteLine(FullLine); - } - } - return true; -} + const std::string& FullLine = params.str(); -bool SpanningTreeUtilities::DoOneToMany(const std::string &prefix, const std::string &command, const parameterlist ¶ms) -{ - std::string FullLine = ":" + prefix + " " + command; - unsigned int words = params.size(); - for (unsigned int x = 0; x < words; x++) - { - FullLine = FullLine + " " + params[x]; - } - unsigned int items = this->TreeRoot->ChildCount(); - for (unsigned int x = 0; x < items; x++) + const TreeServer::ChildServers& children = TreeRoot->GetChildren(); + for (TreeServer::ChildServers::const_iterator i = children.begin(); i != children.end(); ++i) { - TreeServer* Route = this->TreeRoot->GetChild(x); - if (Route && Route->GetSocket()) + TreeServer* Route = *i; + // Send the line if the route isn't the path to the one to be omitted + if (Route != omitroute) { - TreeSocket* Sock = Route->GetSocket(); - if (Sock) - Sock->WriteLine(FullLine); + Route->GetSocket()->WriteLine(FullLine); } } - return true; } -bool SpanningTreeUtilities::DoOneToOne(const std::string &prefix, const std::string &command, const parameterlist ¶ms, const std::string& target) +bool SpanningTreeUtilities::DoOneToOne(const CmdBuilder& params, const std::string& target) { TreeServer* Route = this->BestRouteTo(target); - if (Route) - { - std::string FullLine = ":" + prefix + " " + command; - unsigned int words = params.size(); - for (unsigned int x = 0; x < words; x++) - { - FullLine = FullLine + " " + params[x]; - } - if (Route && Route->GetSocket()) - { - TreeSocket* Sock = Route->GetSocket(); - if (Sock) - Sock->WriteLine(FullLine); - } - return true; - } - else - { + if (!Route) return false; - } + + Route->GetSocket()->WriteLine(params); + return true; } void SpanningTreeUtilities::RefreshIPCache() @@ -284,7 +224,7 @@ void SpanningTreeUtilities::RefreshIPCache() Link* L = *i; if (!L->Port) { - ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"m_spanningtree: Ignoring a link block without a port."); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring a link block without a port."); /* Invalid link block */ continue; } @@ -296,16 +236,16 @@ void SpanningTreeUtilities::RefreshIPCache() bool ipvalid = irc::sockets::aptosa(L->IPAddr, L->Port, dummy); if ((L->IPAddr == "*") || (ipvalid)) ValidIPs.push_back(L->IPAddr); - else + else if (this->Creator->DNS) { + SecurityIPResolver* sr = new SecurityIPResolver(Creator, *this->Creator->DNS, L->IPAddr, L, DNS::QUERY_AAAA); try { - bool cached = false; - SecurityIPResolver* sr = new SecurityIPResolver(Creator, this, L->IPAddr, L, cached, DNS_QUERY_AAAA); - ServerInstance->AddResolver(sr, cached); + this->Creator->DNS->Process(sr); } - catch (...) + catch (DNS::Exception &) { + delete sr; } } } @@ -346,7 +286,7 @@ void SpanningTreeUtilities::ReadConfiguration() L->RecvPass = tag->getString("recvpass", tag->getString("password")); L->Fingerprint = tag->getString("fingerprint"); L->HiddenFromStats = tag->getBool("statshidden"); - L->Timeout = tag->getInt("timeout", 30); + L->Timeout = tag->getDuration("timeout", 30); L->Hook = tag->getString("ssl"); L->Bind = tag->getString("bind"); L->Hidden = tag->getBool("hidden"); @@ -375,11 +315,11 @@ void SpanningTreeUtilities::ReadConfiguration() if (L->IPAddr.empty()) { L->IPAddr = "*"; - ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Configuration warning: Link block '" + assign(L->Name) + "' has no IP defined! This will allow any IP to connect as this server, and MAY not be what you want."); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Configuration warning: Link block '" + assign(L->Name) + "' has no IP defined! This will allow any IP to connect as this server, and MAY not be what you want."); } if (!L->Port) - ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Configuration warning: Link block '" + assign(L->Name) + "' has no port defined, you will not be able to /connect it."); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Configuration warning: Link block '" + assign(L->Name) + "' has no port defined, you will not be able to /connect it."); L->Fingerprint.erase(std::remove(L->Fingerprint.begin(), L->Fingerprint.end(), ':'), L->Fingerprint.end()); LinkBlocks.push_back(L); @@ -390,7 +330,7 @@ void SpanningTreeUtilities::ReadConfiguration() { ConfigTag* tag = i->second; reference<Autoconnect> A = new Autoconnect(tag); - A->Period = tag->getInt("period"); + A->Period = tag->getDuration("period", 60, 1); A->NextConnectTime = ServerInstance->Time() + A->Period; A->position = -1; irc::spacesepstream ss(tag->getString("server")); @@ -400,11 +340,6 @@ void SpanningTreeUtilities::ReadConfiguration() A->servers.push_back(server); } - if (A->Period <= 0) - { - throw ModuleException("Invalid configuration for autoconnect, period not a positive integer!"); - } - if (A->servers.empty()) { throw ModuleException("Invalid configuration for autoconnect, server cannot be empty!"); @@ -428,3 +363,20 @@ Link* SpanningTreeUtilities::FindLink(const std::string& name) } return NULL; } + +void SpanningTreeUtilities::SendChannelMessage(const std::string& prefix, Channel* target, const std::string& text, char status, const CUList& exempt_list, const char* message_type, TreeSocket* omit) +{ + CmdBuilder msg(prefix, message_type); + if (status == 0) + status = ' '; + msg.push(status).push_raw(target->name).push_last(text); + + TreeSocketSet list; + this->GetListOfServersForChannel(target, list, status, exempt_list); + for (TreeSocketSet::iterator i = list.begin(); i != list.end(); ++i) + { + TreeSocket* Sock = *i; + if (Sock != omit) + Sock->WriteLine(msg); + } +} diff --git a/src/modules/m_spanningtree/utils.h b/src/modules/m_spanningtree/utils.h index a0543b6bd..164bed1ca 100644 --- a/src/modules/m_spanningtree/utils.h +++ b/src/modules/m_spanningtree/utils.h @@ -20,10 +20,10 @@ */ -#ifndef M_SPANNINGTREE_UTILS_H -#define M_SPANNINGTREE_UTILS_H +#pragma once #include "inspircd.h" +#include "cachetimer.h" /* Foward declarations */ class TreeServer; @@ -32,24 +32,24 @@ class Link; class Autoconnect; class ModuleSpanningTree; class SpanningTreeUtilities; +class CmdBuilder; + +extern SpanningTreeUtilities* Utils; /* This hash_map holds the hash equivalent of the server * tree, used for rapid linear lookups. */ -#ifdef HASHMAP_DEPRECATED - typedef nspace::hash_map<std::string, TreeServer*, nspace::insensitive, irc::StrHashComp> server_hash; -#else - typedef nspace::hash_map<std::string, TreeServer*, nspace::hash<std::string>, irc::StrHashComp> server_hash; -#endif - -typedef std::map<TreeServer*,TreeServer*> TreeServerList; +typedef TR1NS::unordered_map<std::string, TreeServer*, irc::insensitive, irc::StrHashComp> server_hash; /** Contains helper functions and variables for this module, * and keeps them out of the global namespace */ class SpanningTreeUtilities : public classbase { + CacheRefreshTimer RefreshTimer; + public: + typedef std::set<TreeSocket*> TreeSocketSet; typedef std::map<TreeSocket*, std::pair<std::string, int> > TimeoutList; /** Creator module @@ -124,31 +124,31 @@ class SpanningTreeUtilities : public classbase */ ~SpanningTreeUtilities(); - void RouteCommand(TreeServer*, const std::string&, const parameterlist&, User*); + void RouteCommand(TreeServer* origin, CommandBase* cmd, const parameterlist& parameters, User* user); /** Send a message from this server to one other local or remote */ - bool DoOneToOne(const std::string &prefix, const std::string &command, const parameterlist ¶ms, const std::string& target); + bool DoOneToOne(const CmdBuilder& params, const std::string& target); /** Send a message from this server to all but one other, local or remote */ - bool DoOneToAllButSender(const std::string &prefix, const std::string &command, const parameterlist ¶ms, const std::string& omit); + void DoOneToAllButSender(const CmdBuilder& params, TreeServer* omit); /** Send a message from this server to all others */ - bool DoOneToMany(const std::string &prefix, const std::string &command, const parameterlist ¶ms); + void DoOneToMany(const CmdBuilder& params); /** Read the spanningtree module's tags from the config file */ void ReadConfiguration(); - /** Add a server to the server list for GetListOfServersForChannel + /** Handle nick collision */ - void AddThisServer(TreeServer* server, TreeServerList &list); + int DoCollision(User* u, TreeServer* server, time_t remotets, const std::string& remoteident, const std::string& remoteip, const std::string& remoteuid); /** Compile a list of servers which contain members of channel c */ - void GetListOfServersForChannel(Channel* c, TreeServerList &list, char status, const CUList &exempt_list); + void GetListOfServersForChannel(Channel* c, TreeSocketSet& list, char status, const CUList& exempt_list); /** Find a server by name */ @@ -173,6 +173,13 @@ class SpanningTreeUtilities : public classbase /** Refresh the IP cache used for allowing inbound connections */ void RefreshIPCache(); + + /** Sends a PRIVMSG or a NOTICE to a channel obeying an exempt list and an optional prefix + */ + void SendChannelMessage(const std::string& prefix, Channel* target, const std::string& text, char status, const CUList& exempt_list, const char* message_type, TreeSocket* omit = NULL); }; -#endif +inline void SpanningTreeUtilities::DoOneToMany(const CmdBuilder& params) +{ + DoOneToAllButSender(params, NULL); +} diff --git a/src/modules/m_spanningtree/version.cpp b/src/modules/m_spanningtree/version.cpp index e08d13e6e..b63fc259c 100644 --- a/src/modules/m_spanningtree/version.cpp +++ b/src/modules/m_spanningtree/version.cpp @@ -18,30 +18,15 @@ #include "inspircd.h" -#include "socket.h" -#include "xline.h" -#include "socketengine.h" #include "main.h" #include "utils.h" #include "treeserver.h" -#include "treesocket.h" +#include "commands.h" -/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/treesocket.h */ - -bool TreeSocket::ServerVersion(const std::string &prefix, parameterlist ¶ms) +CmdResult CommandVersion::HandleServer(TreeServer* server, std::vector<std::string>& params) { - if (params.size() < 1) - return true; - - TreeServer* ServerSource = Utils->FindServer(prefix); - - if (ServerSource) - { - ServerSource->SetVersion(params[0]); - } - params[0] = ":" + params[0]; - Utils->DoOneToAllButSender(prefix,"VERSION",params,prefix); - return true; + server->SetVersion(params[0]); + return CMD_SUCCESS; } diff --git a/src/modules/m_sqlauth.cpp b/src/modules/m_sqlauth.cpp index df97145be..ba969e54d 100644 --- a/src/modules/m_sqlauth.cpp +++ b/src/modules/m_sqlauth.cpp @@ -18,10 +18,8 @@ #include "inspircd.h" -#include "sql.h" -#include "hash.h" - -/* $ModDesc: Allow/Deny connections based upon an arbitrary SQL table */ +#include "modules/sql.h" +#include "modules/hash.h" enum AuthState { AUTH_STATE_NONE = 0, @@ -39,8 +37,8 @@ class AuthQuery : public SQLQuery : SQLQuery(me), uid(u), pendingExt(e), verbose(v) { } - - void OnResult(SQLResult& res) + + void OnResult(SQLResult& res) CXX11_OVERRIDE { User* user = ServerInstance->FindNick(uid); if (!user) @@ -57,7 +55,7 @@ class AuthQuery : public SQLQuery } } - void OnError(SQLerror& error) + void OnError(SQLerror& error) CXX11_OVERRIDE { User* user = ServerInstance->FindNick(uid); if (!user) @@ -83,15 +81,13 @@ class ModuleSQLAuth : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(pendingExt); OnRehash(NULL); - Implementation eventlist[] = { I_OnCheckReady, I_OnRehash, I_OnUserRegister }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* conf = ServerInstance->Config->ConfValue("sqlauth"); std::string dbid = conf->getString("dbid"); @@ -105,7 +101,7 @@ class ModuleSQLAuth : public Module verbose = conf->getBool("verbose"); } - ModResult OnUserRegister(LocalUser* user) + ModResult OnUserRegister(LocalUser* user) CXX11_OVERRIDE { // Note this is their initial (unresolved) connect block ConfigTag* tag = user->MyClass->config; @@ -144,7 +140,7 @@ class ModuleSQLAuth : public Module return MOD_RES_PASSTHRU; } - ModResult OnCheckReady(LocalUser* user) + ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE { switch (pendingExt.get(user)) { @@ -159,7 +155,7 @@ class ModuleSQLAuth : public Module return MOD_RES_PASSTHRU; } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Allow/Deny connections based upon an arbitrary SQL table", VF_VENDOR); } diff --git a/src/modules/m_sqloper.cpp b/src/modules/m_sqloper.cpp index ae581cc4b..295f4aa94 100644 --- a/src/modules/m_sqloper.cpp +++ b/src/modules/m_sqloper.cpp @@ -18,24 +18,8 @@ #include "inspircd.h" -#include "sql.h" -#include "hash.h" - -/* $ModDesc: Allows storage of oper credentials in an SQL table */ - -static bool OneOfMatches(const char* host, const char* ip, const std::string& hostlist) -{ - std::stringstream hl(hostlist); - std::string xhost; - while (hl >> xhost) - { - if (InspIRCd::Match(host, xhost, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(ip, xhost, ascii_case_insensitive_map)) - { - return true; - } - } - return false; -} +#include "modules/sql.h" +#include "modules/hash.h" class OpMeQuery : public SQLQuery { @@ -46,9 +30,9 @@ class OpMeQuery : public SQLQuery { } - void OnResult(SQLResult& res) + void OnResult(SQLResult& res) CXX11_OVERRIDE { - ServerInstance->Logs->Log("m_sqloper",DEBUG, "SQLOPER: result for %s", uid.c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "result for %s", uid.c_str()); User* user = ServerInstance->FindNick(uid); if (!user) return; @@ -57,30 +41,17 @@ class OpMeQuery : public SQLQuery SQLEntries row; while (res.GetRow(row)) { -#if 0 - parameterlist cols; - res.GetCols(cols); - - std::vector<KeyVal>* items; - reference<ConfigTag> tag = ConfigTag::create("oper", "<m_sqloper>", 0, items); - for(unsigned int i=0; i < cols.size(); i++) - { - if (!row[i].nul) - items->insert(std::make_pair(cols[i], row[i])); - } -#else if (OperUser(user, row[0], row[1])) return; -#endif } - ServerInstance->Logs->Log("m_sqloper",DEBUG, "SQLOPER: no matches for %s (checked %d rows)", uid.c_str(), res.Rows()); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "no matches for %s (checked %d rows)", uid.c_str(), res.Rows()); // nobody succeeded... fall back to OPER fallback(); } - void OnError(SQLerror& error) + void OnError(SQLerror& error) CXX11_OVERRIDE { - ServerInstance->Logs->Log("m_sqloper",DEFAULT, "SQLOPER: query failed (%s)", error.Str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "query failed (%s)", error.Str()); fallback(); } @@ -101,16 +72,16 @@ class OpMeQuery : public SQLQuery } else { - ServerInstance->Logs->Log("m_sqloper",SPARSE, "BUG: WHAT?! Why do we have no OPER command?!"); + ServerInstance->Logs->Log(MODNAME, LOG_SPARSE, "BUG: WHAT?! Why do we have no OPER command?!"); } } bool OperUser(User* user, const std::string &pattern, const std::string &type) { - OperIndex::iterator iter = ServerInstance->Config->oper_blocks.find(" " + type); - if (iter == ServerInstance->Config->oper_blocks.end()) + OperIndex::iterator iter = ServerInstance->Config->OperTypes.find(type); + if (iter == ServerInstance->Config->OperTypes.end()) { - ServerInstance->Logs->Log("m_sqloper",DEFAULT, "SQLOPER: bad type '%s' in returned row for oper %s", type.c_str(), username.c_str()); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "bad type '%s' in returned row for oper %s", type.c_str(), username.c_str()); return false; } OperInfo* ifo = iter->second; @@ -119,7 +90,7 @@ class OpMeQuery : public SQLQuery hostname.append("@").append(user->host); - if (OneOfMatches(hostname.c_str(), user->GetIPString(), pattern)) + if (InspIRCd::MatchMask(pattern, hostname, user->GetIPString())) { /* Opertype and host match, looks like this is it. */ @@ -140,15 +111,12 @@ class ModuleSQLOper : public Module public: ModuleSQLOper() : SQL(this, "SQL") {} - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); - - Implementation eventlist[] = { I_OnRehash, I_OnPreCommand }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { ConfigTag* tag = ServerInstance->Config->ConfValue("sqloper"); @@ -162,7 +130,7 @@ public: query = tag->getString("query", "SELECT hostname as host, type FROM ircd_opers WHERE username='$username' AND password='$password'"); } - ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) + ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE { if (validated && command == "OPER" && parameters.size() >= 2) { @@ -172,7 +140,7 @@ public: /* Query is in progress, it will re-invoke OPER if needed */ return MOD_RES_DENY; } - ServerInstance->Logs->Log("m_sqloper",DEFAULT, "SQLOPER: database not present"); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "database not present"); } return MOD_RES_PASSTHRU; } @@ -189,11 +157,10 @@ public: SQL->submit(new OpMeQuery(this, user->uuid, username, password), query, userinfo); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Allows storage of oper credentials in an SQL table", VF_VENDOR); } - }; MODULE_INIT(ModuleSQLOper) diff --git a/src/modules/m_sslinfo.cpp b/src/modules/m_sslinfo.cpp index 2bfe0e1c4..c6fb2165c 100644 --- a/src/modules/m_sslinfo.cpp +++ b/src/modules/m_sslinfo.cpp @@ -18,9 +18,7 @@ #include "inspircd.h" -#include "ssl.h" - -/* $ModDesc: Provides SSL metadata, including /WHOIS information and /SSLINFO command */ +#include "modules/ssl.h" class SSLCertExt : public ExtensionItem { public: @@ -97,82 +95,83 @@ class CommandSSLInfo : public Command return CMD_FAILURE; } bool operonlyfp = ServerInstance->Config->ConfValue("sslinfo")->getBool("operonly"); - if (operonlyfp && !IS_OPER(user) && target != user) + if (operonlyfp && !user->IsOper() && target != user) { - user->WriteServ("NOTICE %s :*** You cannot view SSL certificate information for other users", user->nick.c_str()); + user->WriteNotice("*** You cannot view SSL certificate information for other users"); return CMD_FAILURE; } ssl_cert* cert = CertExt.get(target); if (!cert) { - user->WriteServ("NOTICE %s :*** No SSL certificate for this user", user->nick.c_str()); + user->WriteNotice("*** No SSL certificate for this user"); } else if (cert->GetError().length()) { - user->WriteServ("NOTICE %s :*** No SSL certificate information for this user (%s).", user->nick.c_str(), cert->GetError().c_str()); + user->WriteNotice("*** No SSL certificate information for this user (" + cert->GetError() + ")."); } else { - user->WriteServ("NOTICE %s :*** Distinguished Name: %s", user->nick.c_str(), cert->GetDN().c_str()); - user->WriteServ("NOTICE %s :*** Issuer: %s", user->nick.c_str(), cert->GetIssuer().c_str()); - user->WriteServ("NOTICE %s :*** Key Fingerprint: %s", user->nick.c_str(), cert->GetFingerprint().c_str()); + user->WriteNotice("*** Distinguished Name: " + cert->GetDN()); + user->WriteNotice("*** Issuer: " + cert->GetIssuer()); + user->WriteNotice("*** Key Fingerprint: " + cert->GetFingerprint()); } return CMD_SUCCESS; } }; +class UserCertificateAPIImpl : public UserCertificateAPIBase +{ + SSLCertExt& ext; + + public: + UserCertificateAPIImpl(Module* mod, SSLCertExt& certext) + : UserCertificateAPIBase(mod), ext(certext) + { + } + + ssl_cert* GetCertificate(User* user) CXX11_OVERRIDE + { + return ext.get(user); + } +}; + class ModuleSSLInfo : public Module { CommandSSLInfo cmd; + UserCertificateAPIImpl APIImpl; public: - ModuleSSLInfo() : cmd(this) + ModuleSSLInfo() + : cmd(this), APIImpl(this, cmd.CertExt) { } - void init() + void init() CXX11_OVERRIDE { + ServerInstance->Modules->AddService(APIImpl); ServerInstance->Modules->AddService(cmd); - ServerInstance->Modules->AddService(cmd.CertExt); - - Implementation eventlist[] = { I_OnWhois, I_OnPreCommand, I_OnSetConnectClass, I_OnUserConnect, I_OnPostConnect }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("SSL Certificate Utilities", VF_VENDOR); } - void OnWhois(User* source, User* dest) + void OnWhois(User* source, User* dest) CXX11_OVERRIDE { ssl_cert* cert = cmd.CertExt.get(dest); if (cert) { ServerInstance->SendWhoisLine(source, dest, 671, "%s %s :is using a secure connection", source->nick.c_str(), dest->nick.c_str()); bool operonlyfp = ServerInstance->Config->ConfValue("sslinfo")->getBool("operonly"); - if ((!operonlyfp || source == dest || IS_OPER(source)) && !cert->fingerprint.empty()) + if ((!operonlyfp || source == dest || source->IsOper()) && !cert->fingerprint.empty()) ServerInstance->SendWhoisLine(source, dest, 276, "%s %s :has client certificate fingerprint %s", source->nick.c_str(), dest->nick.c_str(), cert->fingerprint.c_str()); } } - bool OneOfMatches(const char* host, const char* ip, const char* hostlist) - { - std::stringstream hl(hostlist); - std::string xhost; - while (hl >> xhost) - { - if (InspIRCd::Match(host, xhost, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(ip, xhost, ascii_case_insensitive_map)) - { - return true; - } - } - return false; - } - - ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) + ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE { if ((command == "OPER") && (validated)) { @@ -203,15 +202,14 @@ class ModuleSSLInfo : public Module return MOD_RES_PASSTHRU; } - void OnUserConnect(LocalUser* user) + void OnUserConnect(LocalUser* user) CXX11_OVERRIDE { - SocketCertificateRequest req(&user->eh, this); - if (!req.cert) - return; - cmd.CertExt.set(user, req.cert); + ssl_cert* cert = SSLClientCert::GetCertificate(&user->eh); + if (cert) + cmd.CertExt.set(user, cert); } - void OnPostConnect(User* user) + void OnPostConnect(User* user) CXX11_OVERRIDE { ssl_cert *cert = cmd.CertExt.get(user); if (!cert || cert->fingerprint.empty()) @@ -226,33 +224,23 @@ class ModuleSSLInfo : public Module } } - ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) + ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE { - SocketCertificateRequest req(&user->eh, this); + ssl_cert* cert = SSLClientCert::GetCertificate(&user->eh); bool ok = true; if (myclass->config->getString("requiressl") == "trusted") { - ok = (req.cert && req.cert->IsCAVerified()); + ok = (cert && cert->IsCAVerified()); } else if (myclass->config->getBool("requiressl")) { - ok = (req.cert != NULL); + ok = (cert != NULL); } if (!ok) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } - - void OnRequest(Request& request) - { - if (strcmp("GET_USER_CERT", request.id) == 0) - { - UserCertificateRequest& req = static_cast<UserCertificateRequest&>(request); - req.cert = cmd.CertExt.get(req.user); - } - } }; MODULE_INIT(ModuleSSLInfo) - diff --git a/src/modules/m_sslmodes.cpp b/src/modules/m_sslmodes.cpp index c81c74207..191ca10f1 100644 --- a/src/modules/m_sslmodes.cpp +++ b/src/modules/m_sslmodes.cpp @@ -22,38 +22,44 @@ #include "inspircd.h" -#include "ssl.h" - -/* $ModDesc: Provides channel mode +z to allow for Secure/SSL only channels */ +#include "modules/ssl.h" /** Handle channel mode +z */ class SSLMode : public ModeHandler { public: - SSLMode(Module* Creator) : ModeHandler(Creator, "sslonly", 'z', PARAM_NONE, MODETYPE_CHANNEL) { } + UserCertificateAPI API; + + SSLMode(Module* Creator) + : ModeHandler(Creator, "sslonly", 'z', PARAM_NONE, MODETYPE_CHANNEL) + , API(Creator) + { + } ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { if (adding) { - if (!channel->IsModeSet('z')) + if (!channel->IsModeSet(this)) { if (IS_LOCAL(source)) { + if (!API) + return MODEACTION_DENY; + const UserMembList* userlist = channel->GetUsers(); for(UserMembCIter i = userlist->begin(); i != userlist->end(); i++) { - UserCertificateRequest req(i->first, creator); - req.Send(); - if(!req.cert && !ServerInstance->ULine(i->first->server)) + ssl_cert* cert = API->GetCertificate(i->first); + if (!cert && !ServerInstance->ULine(i->first->server)) { source->WriteNumeric(ERR_ALLMUSTSSL, "%s %s :all members of the channel must be connected via SSL", source->nick.c_str(), channel->name.c_str()); return MODEACTION_DENY; } } } - channel->SetMode('z',true); + channel->SetMode(this, true); return MODEACTION_ALLOW; } else @@ -63,9 +69,9 @@ class SSLMode : public ModeHandler } else { - if (channel->IsModeSet('z')) + if (channel->IsModeSet(this)) { - channel->SetMode('z',false); + channel->SetMode(this, false); return MODEACTION_ALLOW; } @@ -85,20 +91,20 @@ class ModuleSSLModes : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(sslm); - Implementation eventlist[] = { I_OnUserPreJoin, I_OnCheckBan, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven) + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { - if(chan && chan->IsModeSet('z')) + if(chan && chan->IsModeSet(sslm)) { - UserCertificateRequest req(user, this); - req.Send(); - if (req.cert) + if (!sslm.API) + return MOD_RES_DENY; + + ssl_cert* cert = sslm.API->GetCertificate(user); + if (cert) { // Let them in return MOD_RES_PASSTHRU; @@ -106,7 +112,7 @@ class ModuleSSLModes : public Module else { // Deny - user->WriteServ( "489 %s %s :Cannot join channel; SSL users only (+z)", user->nick.c_str(), cname); + user->WriteServ( "489 %s %s :Cannot join channel; SSL users only (+z)", user->nick.c_str(), cname.c_str()); return MOD_RES_DENY; } } @@ -114,33 +120,29 @@ class ModuleSSLModes : public Module return MOD_RES_PASSTHRU; } - ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) + ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) CXX11_OVERRIDE { if ((mask.length() > 2) && (mask[0] == 'z') && (mask[1] == ':')) { - UserCertificateRequest req(user, this); - req.Send(); - if (req.cert && InspIRCd::Match(req.cert->GetFingerprint(), mask.substr(2))) + if (!sslm.API) + return MOD_RES_DENY; + + ssl_cert* cert = sslm.API->GetCertificate(user); + if (cert && InspIRCd::Match(cert->GetFingerprint(), mask.substr(2))) return MOD_RES_DENY; } return MOD_RES_PASSTHRU; } - ~ModuleSSLModes() + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { + tokens["EXTBAN"].push_back('z'); } - void On005Numeric(std::string &output) - { - ServerInstance->AddExtBanChar('z'); - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel mode +z to allow for Secure/SSL only channels", VF_VENDOR); } }; - MODULE_INIT(ModuleSSLModes) - diff --git a/src/modules/m_stripcolor.cpp b/src/modules/m_stripcolor.cpp index f1504edaf..b50c22297 100644 --- a/src/modules/m_stripcolor.cpp +++ b/src/modules/m_stripcolor.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides channel +S mode (strip ansi color) */ - /** Handles channel mode +S */ class ChannelStripColor : public SimpleChannelModeHandler @@ -50,24 +48,18 @@ class ModuleStripColor : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(usc); ServerInstance->Modules->AddService(csc); - Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - virtual ~ModuleStripColor() - { } - virtual void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - ServerInstance->AddExtBanChar('S'); + tokens["EXTBAN"].push_back('S'); } - virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) + ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; @@ -76,7 +68,7 @@ class ModuleStripColor : public Module if (target_type == TYPE_USER) { User* t = (User*)dest; - active = t->IsModeSet('S'); + active = t->IsModeSet(usc); } else if (target_type == TYPE_CHANNEL) { @@ -86,7 +78,7 @@ class ModuleStripColor : public Module if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; - active = !t->GetExtBanStatus(user, 'S').check(!t->IsModeSet('S')); + active = !t->GetExtBanStatus(user, 'S').check(!t->IsModeSet(csc)); } if (active) @@ -97,12 +89,7 @@ class ModuleStripColor : public Module return MOD_RES_PASSTHRU; } - virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) - { - return OnUserPreMessage(user,dest,target_type,text,status,exempt_list); - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides channel +S mode (strip ansi color)", VF_VENDOR); } diff --git a/src/modules/m_svshold.cpp b/src/modules/m_svshold.cpp index d8176043e..fc1eb5381 100644 --- a/src/modules/m_svshold.cpp +++ b/src/modules/m_svshold.cpp @@ -23,23 +23,17 @@ #include "inspircd.h" #include "xline.h" -/* $ModDesc: Implements SVSHOLD. Like Q:Lines, but can only be added/removed by Services. */ - /** Holds a SVSHold item */ class SVSHold : public XLine { public: - irc::string nickname; + std::string nickname; SVSHold(time_t s_time, long d, const std::string& src, const std::string& re, const std::string& nick) : XLine(s_time, d, src, re, "SVSHOLD") { - this->nickname = nick.c_str(); - } - - ~SVSHold() - { + this->nickname = nick; } bool Matches(User *u) @@ -51,20 +45,12 @@ public: bool Matches(const std::string &s) { - if (nickname == s) - return true; - return false; - } - - void DisplayExpiry() - { - ServerInstance->SNO->WriteToSnoMask('x',"Removing expired SVSHOLD %s (set by %s %ld seconds ago)", - this->nickname.c_str(), this->source.c_str(), (long int)(ServerInstance->Time() - this->set_time)); + return InspIRCd::Match(s, nickname); } - const char* Displayable() + const std::string& Displayable() { - return nickname.c_str(); + return nickname; } }; @@ -96,7 +82,6 @@ class CommandSvshold : public Command CommandSvshold(Module* Creator) : Command(Creator, "SVSHOLD", 1) { flags_needed = 'o'; this->syntax = "<nickname> [<duration> :<reason>]"; - TRANSLATE4(TR_TEXT, TR_TEXT, TR_TEXT, TR_END); } CmdResult Handle(const std::vector<std::string> ¶meters, User *user) @@ -118,7 +103,7 @@ class CommandSvshold : public Command } else { - user->WriteServ("NOTICE %s :*** SVSHOLD %s not found in list, try /stats S.",user->nick.c_str(),parameters[0].c_str()); + user->WriteNotice("*** SVSHOLD " + parameters[0] + " not found in list, try /stats S."); } } else @@ -126,8 +111,7 @@ class CommandSvshold : public Command if (parameters.size() < 3) return CMD_FAILURE; - // Adding - XXX todo make this respect <insane> tag perhaps.. - long duration = ServerInstance->Duration(parameters[1]); + unsigned long duration = InspIRCd::Duration(parameters[1]); SVSHold* r = new SVSHold(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), parameters[0].c_str()); if (ServerInstance->XLines->AddLine(r, user)) @@ -170,15 +154,13 @@ class ModuleSVSHold : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->XLines->RegisterFactory(&s); ServerInstance->Modules->AddService(cmd); - Implementation eventlist[] = { I_OnUserPreNick, I_OnStats }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual ModResult OnStats(char symbol, User* user, string_list &out) + ModResult OnStats(char symbol, User* user, string_list &out) CXX11_OVERRIDE { if(symbol != 'S') return MOD_RES_PASSTHRU; @@ -187,7 +169,7 @@ class ModuleSVSHold : public Module return MOD_RES_DENY; } - virtual ModResult OnUserPreNick(User *user, const std::string &newnick) + ModResult OnUserPreNick(User *user, const std::string &newnick) CXX11_OVERRIDE { XLine *rl = ServerInstance->XLines->MatchesLine("SVSHOLD", newnick); @@ -200,13 +182,13 @@ class ModuleSVSHold : public Module return MOD_RES_PASSTHRU; } - virtual ~ModuleSVSHold() + ~ModuleSVSHold() { ServerInstance->XLines->DelAll("SVSHOLD"); ServerInstance->XLines->UnregisterFactory(&s); } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Implements SVSHOLD. Like Q:Lines, but can only be added/removed by Services.", VF_COMMON | VF_VENDOR); } diff --git a/src/modules/m_swhois.cpp b/src/modules/m_swhois.cpp index 742781747..c2659f6aa 100644 --- a/src/modules/m_swhois.cpp +++ b/src/modules/m_swhois.cpp @@ -25,8 +25,6 @@ #include "inspircd.h" -/* $ModDesc: Provides the SWHOIS command which allows setting of arbitrary WHOIS lines */ - /** Handle /SWHOIS */ class CommandSwhois : public Command @@ -36,7 +34,7 @@ class CommandSwhois : public Command CommandSwhois(Module* Creator) : Command(Creator,"SWHOIS", 2,2), swhois("swhois", Creator) { flags_needed = 'o'; syntax = "<nick> :<swhois>"; - TRANSLATE3(TR_NICK, TR_TEXT, TR_END); + TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle(const std::vector<std::string> ¶meters, User* user) @@ -90,16 +88,14 @@ class ModuleSWhois : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); ServerInstance->Modules->AddService(cmd.swhois); - Implementation eventlist[] = { I_OnWhoisLine, I_OnPostOper }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } // :kenny.chatspike.net 320 Brain Azhrarn :is getting paid to play games. - ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text) + ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text) CXX11_OVERRIDE { /* We use this and not OnWhois because this triggers for remote, too */ if (numeric == 312) @@ -116,7 +112,7 @@ class ModuleSWhois : public Module return MOD_RES_PASSTHRU; } - void OnPostOper(User* user, const std::string &opertype, const std::string &opername) + void OnPostOper(User* user, const std::string &opertype, const std::string &opername) CXX11_OVERRIDE { if (!IS_LOCAL(user)) return; @@ -130,11 +126,7 @@ class ModuleSWhois : public Module ServerInstance->PI->SendMetaData(user, "swhois", swhois); } - ~ModuleSWhois() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides the SWHOIS command which allows setting of arbitrary WHOIS lines", VF_OPTCOMMON | VF_VENDOR); } diff --git a/src/modules/m_testnet.cpp b/src/modules/m_testnet.cpp index 401766d8a..4e99abd32 100644 --- a/src/modules/m_testnet.cpp +++ b/src/modules/m_testnet.cpp @@ -17,167 +17,8 @@ */ -/* $ModDesc: Provides a module for testing the server while linked in a network */ - #include "inspircd.h" -struct vtbase -{ - virtual void isok(const char* name, int impl, Module* basemod, std::vector<std::string>& allmods) = 0; - virtual ~vtbase() {} -}; - -template<typename T> struct vtable : public vtbase -{ - union u { - T function; - struct v { - size_t delta; - size_t vtoff; - } v; - } u; - vtable(T t) { - u.function = t; - } - /** member function pointer dereference from vtable; depends on the GCC 4.4 ABI (x86_64) */ - template<typename E> void* read(E* obj) - { - if (u.v.delta & 1) - { - uint8_t* optr = reinterpret_cast<uint8_t*>(obj); - optr += u.v.vtoff; - uint8_t* vptr = *reinterpret_cast<uint8_t**>(optr); - vptr += u.v.delta - 1; - return *reinterpret_cast<void**>(vptr); - } - else - return reinterpret_cast<void*>(u.v.delta); - } - void isok(const char* name, int impl, Module* basemod, std::vector<std::string>& allmods) - { - void* base = read(basemod); - for(unsigned int i=0; i < allmods.size(); ++i) - { - Module* mod = ServerInstance->Modules->Find(allmods[i]); - void* fptr = read(mod); - for(EventHandlerIter j = ServerInstance->Modules->EventHandlers[impl].begin(); - j != ServerInstance->Modules->EventHandlers[impl].end(); j++) - { - if (mod == *j) - { - if (fptr == base) - { - ServerInstance->SNO->WriteToSnoMask('a', "Module %s implements %s but uses default function", - mod->ModuleSourceFile.c_str(), name); - } - goto done; - } - } - if (fptr != base) - { - ServerInstance->SNO->WriteToSnoMask('a', "Module %s does not implement %s but overrides function", - mod->ModuleSourceFile.c_str(), name); - } - done:; - } - } -}; - -template<typename T> vtbase* vtinit(T t) -{ - return new vtable<T>(t); -} - -static void checkall(Module* noimpl) -{ - std::vector<std::string> allmods = ServerInstance->Modules->GetAllModuleNames(0); -#define CHK(name) do { \ - vtbase* vt = vtinit(&Module::name); \ - vt->isok(#name, I_ ## name, noimpl, allmods); \ - delete vt; \ -} while (0) - CHK(OnUserConnect); - CHK(OnUserQuit); - CHK(OnUserDisconnect); - CHK(OnUserJoin); - CHK(OnUserPart); - CHK(OnRehash); - CHK(OnSendSnotice); - CHK(OnUserPreJoin); - CHK(OnUserPreKick); - CHK(OnUserKick); - CHK(OnOper); - CHK(OnInfo); - CHK(OnWhois); - CHK(OnUserPreInvite); - CHK(OnUserInvite); - CHK(OnUserPreMessage); - CHK(OnUserPreNotice); - CHK(OnUserPreNick); - CHK(OnUserMessage); - CHK(OnUserNotice); - CHK(OnMode); - CHK(OnGetServerDescription); - CHK(OnSyncUser); - CHK(OnSyncChannel); - CHK(OnDecodeMetaData); - CHK(OnWallops); - CHK(OnAcceptConnection); - CHK(OnChangeHost); - CHK(OnChangeName); - CHK(OnAddLine); - CHK(OnDelLine); - CHK(OnExpireLine); - CHK(OnUserPostNick); - CHK(OnPreMode); - CHK(On005Numeric); - CHK(OnKill); - CHK(OnRemoteKill); - CHK(OnLoadModule); - CHK(OnUnloadModule); - CHK(OnBackgroundTimer); - CHK(OnPreCommand); - CHK(OnCheckReady); - CHK(OnCheckInvite); - CHK(OnRawMode); - CHK(OnCheckKey); - CHK(OnCheckLimit); - CHK(OnCheckBan); - CHK(OnCheckChannelBan); - CHK(OnExtBanCheck); - CHK(OnStats); - CHK(OnChangeLocalUserHost); - CHK(OnPreTopicChange); - CHK(OnPostTopicChange); - CHK(OnEvent); - CHK(OnGlobalOper); - CHK(OnPostConnect); - CHK(OnAddBan); - CHK(OnDelBan); - CHK(OnChangeLocalUserGECOS); - CHK(OnUserRegister); - CHK(OnChannelPreDelete); - CHK(OnChannelDelete); - CHK(OnPostOper); - CHK(OnSyncNetwork); - CHK(OnSetAway); - CHK(OnPostCommand); - CHK(OnPostJoin); - CHK(OnWhoisLine); - CHK(OnBuildNeighborList); - CHK(OnGarbageCollect); - CHK(OnText); - CHK(OnPassCompare); - CHK(OnRunTestSuite); - CHK(OnNamesListItem); - CHK(OnNumeric); - CHK(OnHookIO); - CHK(OnPreRehash); - CHK(OnModuleRehash); - CHK(OnSendWhoLine); - CHK(OnChangeIdent); -} - class CommandTest : public Command { public: @@ -199,11 +40,6 @@ class CommandTest : public Command { IS_LOCAL(user)->CommandFloodPenalty += atoi(parameters[1].c_str()); } - else if (parameters[0] == "check") - { - checkall(creator); - ServerInstance->SNO->WriteToSnoMask('a', "Module check complete"); - } return CMD_SUCCESS; } }; @@ -216,18 +52,17 @@ class ModuleTest : public Module { } - void init() + void init() CXX11_OVERRIDE { if (!strstr(ServerInstance->Config->ServerName.c_str(), ".test")) throw ModuleException("Don't load modules without reading their descriptions!"); ServerInstance->Modules->AddService(cmd); } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides a module for testing the server while linked in a network", VF_VENDOR|VF_OPTCOMMON); } }; MODULE_INIT(ModuleTest) - diff --git a/src/modules/m_timedbans.cpp b/src/modules/m_timedbans.cpp index 497ac2569..29691b338 100644 --- a/src/modules/m_timedbans.cpp +++ b/src/modules/m_timedbans.cpp @@ -20,8 +20,6 @@ */ -/* $ModDesc: Adds timed bans */ - #include "inspircd.h" /** Holds a timed ban @@ -45,7 +43,6 @@ class CommandTban : public Command CommandTban(Module* Creator) : Command(Creator,"TBAN", 3) { syntax = "<channel> <duration> <banmask>"; - TRANSLATE4(TR_TEXT, TR_TEXT, TR_TEXT, TR_END); } CmdResult Handle (const std::vector<std::string> ¶meters, User *user) @@ -62,15 +59,15 @@ class CommandTban : public Command user->WriteNumeric(482, "%s %s :You do not have permission to set bans on this channel", user->nick.c_str(), channel->name.c_str()); return CMD_FAILURE; - } + } TimedBan T; std::string channelname = parameters[0]; - long duration = ServerInstance->Duration(parameters[1]); + unsigned long duration = InspIRCd::Duration(parameters[1]); unsigned long expire = duration + ServerInstance->Time(); if (duration < 1) { - user->WriteServ("NOTICE "+user->nick+" :Invalid ban time"); + user->WriteNotice("Invalid ban time"); return CMD_FAILURE; } std::string mask = parameters[2]; @@ -80,20 +77,17 @@ class CommandTban : public Command bool isextban = ((mask.size() > 2) && (mask[1] == ':')); if (!isextban && !ServerInstance->IsValidMask(mask)) mask.append("!*@*"); - if ((mask.length() > 250) || (!ServerInstance->IsValidMask(mask) && !isextban)) + + setban.push_back(mask); + // Pass the user (instead of ServerInstance->FakeClient) to ModeHandler::Process() to + // make it so that the user sets the mode themselves + ServerInstance->Modes->Process(setban, user); + if (ServerInstance->Modes->GetLastParse().empty()) { - user->WriteServ("NOTICE "+user->nick+" :Invalid ban mask"); + user->WriteNotice("Invalid ban mask"); return CMD_FAILURE; } - setban.push_back(mask); - // use CallHandler to make it so that the user sets the mode - // themselves - ServerInstance->Parser->CallHandler("MODE",setban,user); - for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++) - if (!strcasecmp(i->data.c_str(), mask.c_str())) - goto found; - return CMD_FAILURE; -found: + CUList tmp; T.channel = channelname; T.mask = mask; @@ -114,27 +108,22 @@ found: } }; -class ModuleTimedBans : public Module +class BanWatcher : public ModeWatcher { - CommandTban cmd; public: - ModuleTimedBans() - : cmd(this) + BanWatcher(Module* parent) + : ModeWatcher(parent, "ban", MODETYPE_CHANNEL) { } - void init() + void AfterMode(User* source, User* dest, Channel* chan, const std::string& banmask, bool adding) { - ServerInstance->Modules->AddService(cmd); - Implementation eventlist[] = { I_OnDelBan, I_OnBackgroundTimer }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } + if (adding) + return; - virtual ModResult OnDelBan(User* source, Channel* chan, const std::string &banmask) - { irc::string listitem = banmask.c_str(); irc::string thischan = chan->name.c_str(); - for (timedbans::iterator i = TimedBanList.begin(); i != TimedBanList.end(); i++) + for (timedbans::iterator i = TimedBanList.begin(); i != TimedBanList.end(); ++i) { irc::string target = i->mask.c_str(); irc::string tchan = i->channel.c_str(); @@ -144,10 +133,33 @@ class ModuleTimedBans : public Module break; } } - return MOD_RES_PASSTHRU; + } +}; + +class ModuleTimedBans : public Module +{ + CommandTban cmd; + BanWatcher banwatcher; + + public: + ModuleTimedBans() + : cmd(this) + , banwatcher(this) + { } - virtual void OnBackgroundTimer(time_t curtime) + void init() CXX11_OVERRIDE + { + ServerInstance->Modules->AddService(cmd); + ServerInstance->Modes->AddModeWatcher(&banwatcher); + } + + ~ModuleTimedBans() + { + ServerInstance->Modes->DelModeWatcher(&banwatcher); + } + + void OnBackgroundTimer(time_t curtime) CXX11_OVERRIDE { timedbans expired; for (timedbans::iterator i = TimedBanList.begin(); i != TimedBanList.end();) @@ -178,16 +190,15 @@ class ModuleTimedBans : public Module cr->WriteAllExcept(ServerInstance->FakeClient, true, '@', empty, "NOTICE %s :%s", cr->name.c_str(), expiry.c_str()); ServerInstance->PI->SendChannelNotice(cr, '@', expiry); - ServerInstance->SendGlobalMode(setban, ServerInstance->FakeClient); + ServerInstance->Modes->Process(setban, ServerInstance->FakeClient); } } } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Adds timed bans", VF_COMMON | VF_VENDOR); } }; MODULE_INIT(ModuleTimedBans) - diff --git a/src/modules/m_tline.cpp b/src/modules/m_tline.cpp index b4e7e5a99..bf1476bb5 100644 --- a/src/modules/m_tline.cpp +++ b/src/modules/m_tline.cpp @@ -20,8 +20,6 @@ #include "inspircd.h" -/* $ModDesc: Provides /tline command used to test who a mask matches */ - /** Handle /TLINE */ class CommandTline : public Command @@ -75,20 +73,15 @@ class ModuleTLine : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleTLine() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides /tline command used to test who a mask matches", VF_VENDOR); } }; MODULE_INIT(ModuleTLine) - diff --git a/src/modules/m_topiclock.cpp b/src/modules/m_topiclock.cpp index 3e8a846e7..760283c95 100644 --- a/src/modules/m_topiclock.cpp +++ b/src/modules/m_topiclock.cpp @@ -16,8 +16,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* $ModDesc: Implements server-side topic locks and the server-to-server command SVSTOPIC */ - #include "inspircd.h" class CommandSVSTOPIC : public Command @@ -47,7 +45,7 @@ class CommandSVSTOPIC : public Command time_t topicts = ConvToInt(parameters[1]); if (!topicts) { - ServerInstance->Logs->Log("m_topiclock", DEFAULT, "Received SVSTOPIC with a 0 topicts, dropped."); + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Received SVSTOPIC with a 0 topicts, dropped."); return CMD_INVALID; } @@ -96,7 +94,7 @@ class FlagExtItem : public ExtensionItem { } - virtual ~FlagExtItem() + ~FlagExtItem() { } @@ -151,14 +149,13 @@ class ModuleTopicLock : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); ServerInstance->Modules->AddService(topiclock); - ServerInstance->Modules->Attach(I_OnPreTopicChange, this); } - ModResult OnPreTopicChange(User* user, Channel* chan, const std::string &topic) + ModResult OnPreTopicChange(User* user, Channel* chan, const std::string &topic) CXX11_OVERRIDE { // Only fired for local users currently, but added a check anyway if ((IS_LOCAL(user)) && (topiclock.get(chan))) @@ -170,7 +167,7 @@ class ModuleTopicLock : public Module return MOD_RES_PASSTHRU; } - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Implements server-side topic locks and the server-to-server command SVSTOPIC", VF_COMMON | VF_VENDOR); } diff --git a/src/modules/m_uhnames.cpp b/src/modules/m_uhnames.cpp index 2cd090f97..2534afb97 100644 --- a/src/modules/m_uhnames.cpp +++ b/src/modules/m_uhnames.cpp @@ -20,9 +20,7 @@ #include "inspircd.h" -#include "m_cap.h" - -/* $ModDesc: Provides the UHNAMES facility. */ +#include "modules/cap.h" class ModuleUHNames : public Module { @@ -33,27 +31,17 @@ class ModuleUHNames : public Module { } - void init() - { - Implementation eventlist[] = { I_OnEvent, I_OnPreCommand, I_OnNamesListItem, I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - ~ModuleUHNames() - { - } - - Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides the UHNAMES facility.",VF_VENDOR); } - void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - output.append(" UHNAMES"); + tokens["UHNAMES"]; } - ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) + ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) CXX11_OVERRIDE { /* We don't actually create a proper command handler class for PROTOCTL, * because other modules might want to have PROTOCTL hooks too. @@ -71,7 +59,7 @@ class ModuleUHNames : public Module return MOD_RES_PASSTHRU; } - void OnNamesListItem(User* issuer, Membership* memb, std::string &prefixes, std::string &nick) + void OnNamesListItem(User* issuer, Membership* memb, std::string &prefixes, std::string &nick) CXX11_OVERRIDE { if (!cap.ext.get(issuer)) return; @@ -82,7 +70,7 @@ class ModuleUHNames : public Module nick = memb->user->GetFullHost(); } - void OnEvent(Event& ev) + void OnEvent(Event& ev) CXX11_OVERRIDE { cap.HandleEvent(ev); } diff --git a/src/modules/m_uninvite.cpp b/src/modules/m_uninvite.cpp index 10fd7c7b6..3ee23c95a 100644 --- a/src/modules/m_uninvite.cpp +++ b/src/modules/m_uninvite.cpp @@ -20,8 +20,6 @@ */ -/* $ModDesc: Provides the UNINVITE command which lets users un-invite other users from channels (!) */ - #include "inspircd.h" /** Handle /UNINVITE @@ -32,7 +30,7 @@ class CommandUninvite : public Command CommandUninvite(Module* Creator) : Command(Creator,"UNINVITE", 2) { syntax = "<nick> <channel>"; - TRANSLATE3(TR_NICK, TR_TEXT, TR_END); + TRANSLATE2(TR_NICK, TR_TEXT); } CmdResult Handle (const std::vector<std::string> ¶meters, User *user) @@ -70,15 +68,13 @@ class CommandUninvite : public Command LocalUser* lu = IS_LOCAL(u); if (lu) { - irc::string xname(c->name.c_str()); - if (!lu->IsInvited(xname)) + if (!lu->RemoveInvite(c)) { user->SendText(":%s 505 %s %s %s :Is not invited to channel %s", user->server.c_str(), user->nick.c_str(), u->nick.c_str(), c->name.c_str(), c->name.c_str()); return CMD_FAILURE; } user->SendText(":%s 494 %s %s %s :Uninvited", user->server.c_str(), user->nick.c_str(), c->name.c_str(), u->nick.c_str()); - lu->RemoveInvite(xname); lu->WriteNumeric(493, "%s :You were uninvited from %s by %s", u->nick.c_str(), c->name.c_str(), user->nick.c_str()); std::string msg = "*** " + user->nick + " uninvited " + u->nick + "."; @@ -106,20 +102,15 @@ class ModuleUninvite : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleUninvite() - { - } - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides the UNINVITE command which lets users un-invite other users from channels", VF_VENDOR | VF_OPTCOMMON); } }; MODULE_INIT(ModuleUninvite) - diff --git a/src/modules/m_userip.cpp b/src/modules/m_userip.cpp index 5ea84c04a..79e69ec5e 100644 --- a/src/modules/m_userip.cpp +++ b/src/modules/m_userip.cpp @@ -21,8 +21,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for USERIP command */ - /** Handle /USERIP */ class CommandUserip : public Command @@ -61,8 +59,8 @@ class CommandUserip : public Command continue; } - retbuf = retbuf + u->nick + (IS_OPER(u) ? "*" : "") + "="; - if (IS_AWAY(u)) + retbuf = retbuf + u->nick + (u->IsOper() ? "*" : "") + "="; + if (u->IsAway()) retbuf += "-"; else retbuf += "+"; @@ -87,28 +85,20 @@ class ModuleUserIP : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); - Implementation eventlist[] = { I_On005Numeric }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - } - - virtual void On005Numeric(std::string &output) - { - output = output + " USERIP"; } - virtual ~ModuleUserIP() + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { + tokens["USERIP"]; } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for USERIP command",VF_VENDOR); } - }; MODULE_INIT(ModuleUserIP) - diff --git a/src/modules/m_vhost.cpp b/src/modules/m_vhost.cpp index 31c504af8..e938da297 100644 --- a/src/modules/m_vhost.cpp +++ b/src/modules/m_vhost.cpp @@ -22,8 +22,6 @@ #include "inspircd.h" -/* $ModDesc: Provides masking of user hostnames via traditional /VHOST command */ - /** Handle /VHOST */ class CommandVhost : public Command @@ -49,21 +47,20 @@ class CommandVhost : public Command { if (!mask.empty()) { - user->WriteServ("NOTICE "+user->nick+" :Setting your VHost: " + mask); + user->WriteNotice("Setting your VHost: " + mask); user->ChangeDisplayedHost(mask.c_str()); return CMD_SUCCESS; } } } - user->WriteServ("NOTICE "+user->nick+" :Invalid username or password."); + user->WriteNotice("Invalid username or password."); return CMD_FAILURE; } }; class ModuleVHost : public Module { - private: CommandVhost cmd; public: @@ -71,22 +68,15 @@ class ModuleVHost : public Module { } - void init() + void init() CXX11_OVERRIDE { ServerInstance->Modules->AddService(cmd); } - virtual ~ModuleVHost() - { - } - - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides masking of user hostnames via traditional /VHOST command",VF_VENDOR); } - }; MODULE_INIT(ModuleVHost) - diff --git a/src/modules/m_watch.cpp b/src/modules/m_watch.cpp index ec38edc31..94f53c164 100644 --- a/src/modules/m_watch.cpp +++ b/src/modules/m_watch.cpp @@ -22,8 +22,6 @@ #include "inspircd.h" -/* $ModDesc: Provides support for the /WATCH command */ - /* * Okay, it's nice that this was documented and all, but I at least understood very little @@ -92,12 +90,7 @@ * of users using WATCH. */ -/* - * Before you start screaming, this definition is only used here, so moving it to a header is pointless. - * Yes, it's horrid. Blame cl for being different. -- w00t - */ - -typedef nspace::hash_map<irc::string, std::deque<User*>, irc::hash> watchentries; +typedef TR1NS::unordered_map<irc::string, std::deque<User*>, irc::hash> watchentries; typedef std::map<irc::string, std::string> watchlist; /* Who's watching each nickname. @@ -112,7 +105,7 @@ class CommandSVSWatch : public Command CommandSVSWatch(Module* Creator) : Command(Creator,"SVSWATCH", 2) { syntax = "<target> [C|L|S]|[+|-<nick>]"; - TRANSLATE3(TR_NICK, TR_TEXT, TR_END); /* we watch for a nick. not a UID. */ + TRANSLATE2(TR_NICK, TR_TEXT); /* we watch for a nick. not a UID. */ } CmdResult Handle (const std::vector<std::string> ¶meters, User *user) @@ -151,7 +144,7 @@ class CommandWatch : public Command CmdResult remove_watch(User* user, const char* nick) { // removing an item from the list - if (!ServerInstance->IsNick(nick, ServerInstance->Config->Limits.NickMax)) + if (!ServerInstance->IsNick(nick)) { user->WriteNumeric(942, "%s %s :Invalid nickname", user->nick.c_str(), nick); return CMD_FAILURE; @@ -201,7 +194,7 @@ class CommandWatch : public Command CmdResult add_watch(User* user, const char* nick) { - if (!ServerInstance->IsNick(nick, ServerInstance->Config->Limits.NickMax)) + if (!ServerInstance->IsNick(nick)) { user->WriteNumeric(942, "%s %s :Invalid nickname",user->nick.c_str(),nick); return CMD_FAILURE; @@ -242,7 +235,7 @@ class CommandWatch : public Command { (*wl)[nick] = std::string(target->ident).append(" ").append(target->dhost).append(" ").append(ConvToStr(target->age)); user->WriteNumeric(604, "%s %s %s :is online",user->nick.c_str(), nick, (*wl)[nick].c_str()); - if (IS_AWAY(target)) + if (target->IsAway()) { user->WriteNumeric(609, "%s %s %s %s %lu :is away", user->nick.c_str(), target->nick.c_str(), target->ident.c_str(), target->dhost.c_str(), (unsigned long) target->awaytime); } @@ -260,7 +253,6 @@ class CommandWatch : public Command CommandWatch(Module* parent, unsigned int &maxwatch) : Command(parent,"WATCH", 0), MAX_WATCH(maxwatch), ext("watchlist", parent) { syntax = "[C|L|S]|[+|-<nick>]"; - TRANSLATE2(TR_TEXT, TR_END); /* we watch for a nick. not a UID. */ } CmdResult Handle (const std::vector<std::string> ¶meters, User *user) @@ -320,7 +312,7 @@ class CommandWatch : public Command { user->WriteNumeric(604, "%s %s %s :is online", user->nick.c_str(), q->first.c_str(), q->second.c_str()); User *targ = ServerInstance->FindNick(q->first.c_str()); - if (IS_AWAY(targ)) + if (targ->IsAway()) { user->WriteNumeric(609, "%s %s %s %s %lu :is away", user->nick.c_str(), targ->nick.c_str(), targ->ident.c_str(), targ->dhost.c_str(), (unsigned long) targ->awaytime); } @@ -382,24 +374,22 @@ class Modulewatch : public Module whos_watching_me = new watchentries(); } - void init() + void init() CXX11_OVERRIDE { OnRehash(NULL); ServerInstance->Modules->AddService(cmdw); ServerInstance->Modules->AddService(sw); ServerInstance->Modules->AddService(cmdw.ext); - Implementation eventlist[] = { I_OnRehash, I_OnGarbageCollect, I_OnUserQuit, I_OnPostConnect, I_OnUserPostNick, I_On005Numeric, I_OnSetAway }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - virtual void OnRehash(User* user) + void OnRehash(User* user) CXX11_OVERRIDE { maxwatch = ServerInstance->Config->ConfValue("watch")->getInt("maxentries", 32); if (!maxwatch) maxwatch = 32; } - virtual ModResult OnSetAway(User *user, const std::string &awaymsg) + ModResult OnSetAway(User *user, const std::string &awaymsg) CXX11_OVERRIDE { std::string numeric; int inum; @@ -427,7 +417,7 @@ class Modulewatch : public Module return MOD_RES_PASSTHRU; } - virtual void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message) + void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message) CXX11_OVERRIDE { watchentries::iterator x = whos_watching_me->find(user->nick.c_str()); if (x != whos_watching_me->end()) @@ -467,7 +457,7 @@ class Modulewatch : public Module } } - virtual void OnGarbageCollect() + void OnGarbageCollect() { watchentries* old_watch = whos_watching_me; whos_watching_me = new watchentries(); @@ -478,7 +468,7 @@ class Modulewatch : public Module delete old_watch; } - virtual void OnPostConnect(User* user) + void OnPostConnect(User* user) CXX11_OVERRIDE { watchentries::iterator x = whos_watching_me->find(user->nick.c_str()); if (x != whos_watching_me->end()) @@ -495,7 +485,7 @@ class Modulewatch : public Module } } - virtual void OnUserPostNick(User* user, const std::string &oldnick) + void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE { watchentries::iterator new_offline = whos_watching_me->find(oldnick.c_str()); watchentries::iterator new_online = whos_watching_me->find(user->nick.c_str()); @@ -527,22 +517,20 @@ class Modulewatch : public Module } } - virtual void On005Numeric(std::string &output) + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE { - // we don't really have a limit... - output = output + " WATCH=" + ConvToStr(maxwatch); + tokens["WATCH"] = ConvToStr(maxwatch); } - virtual ~Modulewatch() + ~Modulewatch() { delete whos_watching_me; } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides support for the /WATCH command", VF_OPTCOMMON | VF_VENDOR); } }; MODULE_INIT(Modulewatch) - diff --git a/src/modules/m_xline_db.cpp b/src/modules/m_xline_db.cpp index 5e83478c3..63eb6d3ee 100644 --- a/src/modules/m_xline_db.cpp +++ b/src/modules/m_xline_db.cpp @@ -20,17 +20,14 @@ #include "inspircd.h" #include "xline.h" - -/* $ModConfig: <xlinedb filename="data/xline.db"> - * Specify the filename for the xline database here*/ -/* $ModDesc: Keeps a dynamic log of all XLines created, and stores them in a seperate conf file (xline.db). */ +#include <fstream> class ModuleXLineDB : public Module { bool dirty; std::string xlinedbpath; public: - void init() + void init() CXX11_OVERRIDE { /* Load the configuration * Note: @@ -39,26 +36,20 @@ class ModuleXLineDB : public Module * ...and so is discarding all current in-memory XLines for the ones in the database. */ ConfigTag* Conf = ServerInstance->Config->ConfValue("xlinedb"); - xlinedbpath = Conf->getString("filename", DATA_PATH "/xline.db"); + xlinedbpath = ServerInstance->Config->Paths.PrependData(Conf->getString("filename", "xline.db")); // Read xlines before attaching to events ReadDatabase(); - Implementation eventlist[] = { I_OnAddLine, I_OnDelLine, I_OnExpireLine, I_OnBackgroundTimer }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); dirty = false; } - virtual ~ModuleXLineDB() - { - } - /** Called whenever an xline is added by a local user. * This method is triggered after the line is added. * @param source The sender of the line or NULL for local server * @param line The xline being added */ - void OnAddLine(User* source, XLine* line) + void OnAddLine(User* source, XLine* line) CXX11_OVERRIDE { dirty = true; } @@ -68,17 +59,17 @@ class ModuleXLineDB : public Module * @param source The user removing the line or NULL for local server * @param line the line being deleted */ - void OnDelLine(User* source, XLine* line) + void OnDelLine(User* source, XLine* line) CXX11_OVERRIDE { dirty = true; } - void OnExpireLine(XLine *line) + void OnExpireLine(XLine *line) CXX11_OVERRIDE { dirty = true; } - void OnBackgroundTimer(time_t now) + void OnBackgroundTimer(time_t now) CXX11_OVERRIDE { if (dirty) { @@ -89,25 +80,23 @@ class ModuleXLineDB : public Module bool WriteDatabase() { - FILE *f; - /* * We need to perform an atomic write so as not to fuck things up. - * So, let's write to a temporary file, flush and sync the FD, then rename the file.. + * So, let's write to a temporary file, flush it, then rename the file.. * Technically, that means that this can block, but I have *never* seen that. - * -- w00t + * -- w00t */ - ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Opening temporary database"); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Opening temporary database"); std::string xlinenewdbpath = xlinedbpath + ".new"; - f = fopen(xlinenewdbpath.c_str(), "w"); - if (!f) + std::ofstream stream(xlinenewdbpath.c_str()); + if (!stream.is_open()) { - ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Cannot create database! %s (%d)", strerror(errno), errno); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot create database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot create new db: %s (%d)", strerror(errno), errno); return false; } - ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Opened. Writing.."); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Opened. Writing.."); /* * Now, much as I hate writing semi-unportable formats, additional @@ -116,7 +105,7 @@ class ModuleXLineDB : public Module * semblance of backwards compatibility for reading on startup.. * -- w00t */ - fprintf(f, "VERSION 1\n"); + stream << "VERSION 1" << std::endl; // Now, let's write. std::vector<std::string> types = ServerInstance->XLines->GetAllTypes(); @@ -129,27 +118,26 @@ class ModuleXLineDB : public Module for (LookupIter i = lookup->begin(); i != lookup->end(); ++i) { XLine* line = i->second; - fprintf(f, "LINE %s %s %s %lu %lu :%s\n", line->type.c_str(), line->Displayable(), - ServerInstance->Config->ServerName.c_str(), (unsigned long)line->set_time, (unsigned long)line->duration, line->reason.c_str()); + stream << "LINE " << line->type << " " << line->Displayable() << " " + << ServerInstance->Config->ServerName << " " << line->set_time << " " + << line->duration << " " << line->reason << std::endl; } } - ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Finished writing XLines. Checking for error.."); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Finished writing XLines. Checking for error.."); - int write_error = 0; - write_error = ferror(f); - write_error |= fclose(f); - if (write_error) + if (stream.fail()) { - ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Cannot write to new database! %s (%d)", strerror(errno), errno); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot write to new database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot write to new db: %s (%d)", strerror(errno), errno); return false; } + stream.close(); #ifdef _WIN32 if (remove(xlinedbpath.c_str())) { - ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Cannot remove old database! %s (%d)", strerror(errno), errno); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot remove old database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot remove old database: %s (%d)", strerror(errno), errno); return false; } @@ -157,7 +145,7 @@ class ModuleXLineDB : public Module // Use rename to move temporary to new db - this is guarenteed not to fuck up, even in case of a crash. if (rename(xlinenewdbpath.c_str(), xlinedbpath.c_str()) < 0) { - ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Cannot move new to old database! %s (%d)", strerror(errno), errno); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot move new to old database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot replace old with new db: %s (%d)", strerror(errno), errno); return false; } @@ -167,42 +155,23 @@ class ModuleXLineDB : public Module bool ReadDatabase() { - FILE *f; - char linebuf[MAXBUF]; + // If the xline database doesn't exist then we don't need to load it. + if (!ServerConfig::FileExists(xlinedbpath.c_str())) + return true; - f = fopen(xlinedbpath.c_str(), "r"); - if (!f) + std::ifstream stream(xlinedbpath.c_str()); + if (!stream.is_open()) { - if (errno == ENOENT) - { - /* xline.db doesn't exist, fake good return value (we don't care about this) */ - return true; - } - else - { - /* this might be slightly more problematic. */ - ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Cannot read database! %s (%d)", strerror(errno), errno); - ServerInstance->SNO->WriteToSnoMask('a', "database: cannot read db: %s (%d)", strerror(errno), errno); - return false; - } + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot read database! %s (%d)", strerror(errno), errno); + ServerInstance->SNO->WriteToSnoMask('a', "database: cannot read db: %s (%d)", strerror(errno), errno); + return false; } - - while (fgets(linebuf, MAXBUF, f)) + + std::string line; + while (std::getline(stream, line)) { - char *c = linebuf; - - while (c && *c) - { - if (*c == '\n') - { - *c = '\0'; - } - - c++; - } - // Inspired by the command parser. :) - irc::tokenstream tokens(linebuf); + irc::tokenstream tokens(line); int items = 0; std::string command_p[7]; std::string tmp; @@ -213,18 +182,14 @@ class ModuleXLineDB : public Module items++; } - ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Processing %s", linebuf); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Processing %s", line.c_str()); if (command_p[0] == "VERSION") { - if (command_p[1] == "1") - { - ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Reading db version %s", command_p[1].c_str()); - } - else + if (command_p[1] != "1") { - fclose(f); - ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: I got database version %s - I don't understand it", command_p[1].c_str()); + stream.close(); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "I got database version %s - I don't understand it", command_p[1].c_str()); ServerInstance->SNO->WriteToSnoMask('a', "database: I got a database version (%s) I don't understand", command_p[1].c_str()); return false; } @@ -251,18 +216,14 @@ class ModuleXLineDB : public Module delete xl; } } - - fclose(f); + stream.close(); return true; } - - - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Keeps a dynamic log of all XLines created, and stores them in a separate conf file (xline.db).", VF_VENDOR); } }; MODULE_INIT(ModuleXLineDB) - diff --git a/src/modules/u_listmode.h b/src/modules/u_listmode.h deleted file mode 100644 index 0f5903e53..000000000 --- a/src/modules/u_listmode.h +++ /dev/null @@ -1,423 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#ifndef INSPIRCD_LISTMODE_PROVIDER -#define INSPIRCD_LISTMODE_PROVIDER - -/** Get the time as a string - */ -inline std::string stringtime() -{ - std::ostringstream TIME; - TIME << ServerInstance->Time(); - return TIME.str(); -} - -/** An item in a listmode's list - */ -class ListItem -{ -public: - std::string nick; - std::string mask; - std::string time; -}; - -/** The number of items a listmode's list may contain - */ -class ListLimit -{ -public: - std::string mask; - unsigned int limit; -}; - -/** Items stored in the channel's list - */ -typedef std::list<ListItem> modelist; -/** Max items per channel by name - */ -typedef std::list<ListLimit> limitlist; - -/** The base class for list modes, should be inherited. - */ -class ListModeBase : public ModeHandler -{ - protected: - /** Numeric to use when outputting the list - */ - unsigned int listnumeric; - /** Numeric to indicate end of list - */ - unsigned int endoflistnumeric; - /** String to send for end of list - */ - std::string endofliststring; - /** Automatically tidy up entries - */ - bool tidy; - /** Config tag to check for max items per channel - */ - std::string configtag; - /** Limits on a per-channel basis read from the tag - * specified in ListModeBase::configtag - */ - limitlist chanlimits; - - public: - /** Storage key - */ - SimpleExtItem<modelist> extItem; - - /** Constructor. - * @param Instance The creator of this class - * @param modechar Mode character - * @param eolstr End of list string - * @pram lnum List numeric - * @param eolnum End of list numeric - * @param autotidy Automatically tidy list entries on add - * @param ctag Configuration tag to get limits from - */ - ListModeBase(Module* Creator, const std::string& Name, char modechar, const std::string &eolstr, unsigned int lnum, unsigned int eolnum, bool autotidy, const std::string &ctag = "banlist") - : ModeHandler(Creator, Name, modechar, PARAM_ALWAYS, MODETYPE_CHANNEL), - listnumeric(lnum), endoflistnumeric(eolnum), endofliststring(eolstr), tidy(autotidy), - configtag(ctag), extItem("listbase_mode_" + name + "_list", Creator) - { - list = true; - } - - /** See mode.h - */ - std::pair<bool,std::string> ModeSet(User*, User*, Channel* channel, const std::string ¶meter) - { - modelist* el = extItem.get(channel); - if (el) - { - for (modelist::iterator it = el->begin(); it != el->end(); it++) - { - if(parameter == it->mask) - { - return std::make_pair(true, parameter); - } - } - } - return std::make_pair(false, parameter); - } - - /** Display the list for this mode - * @param user The user to send the list to - * @param channel The channel the user is requesting the list for - */ - virtual void DisplayList(User* user, Channel* channel) - { - modelist* el = extItem.get(channel); - if (el) - { - for (modelist::reverse_iterator it = el->rbegin(); it != el->rend(); ++it) - { - user->WriteNumeric(listnumeric, "%s %s %s %s %s", user->nick.c_str(), channel->name.c_str(), it->mask.c_str(), (it->nick.length() ? it->nick.c_str() : ServerInstance->Config->ServerName.c_str()), it->time.c_str()); - } - } - user->WriteNumeric(endoflistnumeric, "%s %s :%s", user->nick.c_str(), channel->name.c_str(), endofliststring.c_str()); - } - - virtual void DisplayEmptyList(User* user, Channel* channel) - { - user->WriteNumeric(endoflistnumeric, "%s %s :%s", user->nick.c_str(), channel->name.c_str(), endofliststring.c_str()); - } - - /** Remove all instances of the mode from a channel. - * See mode.h - * @param channel The channel to remove all instances of the mode from - */ - virtual void RemoveMode(Channel* channel, irc::modestacker* stack) - { - modelist* el = extItem.get(channel); - if (el) - { - irc::modestacker modestack(false); - - for (modelist::iterator it = el->begin(); it != el->end(); it++) - { - if (stack) - stack->Push(this->GetModeChar(), it->mask); - else - modestack.Push(this->GetModeChar(), it->mask); - } - - if (stack) - return; - - std::vector<std::string> stackresult; - stackresult.push_back(channel->name); - while (modestack.GetStackedLine(stackresult)) - { - ServerInstance->SendMode(stackresult, ServerInstance->FakeClient); - stackresult.clear(); - stackresult.push_back(channel->name); - } - } - } - - /** See mode.h - */ - virtual void RemoveMode(User*, irc::modestacker* stack) - { - /* Listmodes dont get set on users */ - } - - /** Perform a rehash of this mode's configuration data - */ - virtual void DoRehash() - { - ConfigTagList tags = ServerInstance->Config->ConfTags(configtag); - - chanlimits.clear(); - - for (ConfigIter i = tags.first; i != tags.second; i++) - { - // For each <banlist> tag - ConfigTag* c = i->second; - ListLimit limit; - limit.mask = c->getString("chan"); - limit.limit = c->getInt("limit"); - - if (limit.mask.size() && limit.limit > 0) - chanlimits.push_back(limit); - } - if (chanlimits.empty()) - { - ListLimit limit; - limit.mask = "*"; - limit.limit = 64; - chanlimits.push_back(limit); - } - } - - /** Populate the Implements list with the correct events for a List Mode - */ - virtual void DoImplements(Module* m) - { - ServerInstance->Modules->AddService(extItem); - this->DoRehash(); - Implementation eventlist[] = { I_OnSyncChannel, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, m, sizeof(eventlist)/sizeof(Implementation)); - } - - /** Handle the list mode. - * See mode.h - */ - virtual ModeAction OnModeChange(User* source, User*, Channel* channel, std::string ¶meter, bool adding) - { - // Try and grab the list - modelist* el = extItem.get(channel); - - if (adding) - { - if (tidy) - ModeParser::CleanMask(parameter); - - if (parameter.length() > 250) - return MODEACTION_DENY; - - // If there was no list - if (!el) - { - // Make one - el = new modelist; - extItem.set(channel, el); - } - - // Check if the item already exists in the list - for (modelist::iterator it = el->begin(); it != el->end(); it++) - { - if (parameter == it->mask) - { - /* Give a subclass a chance to error about this */ - TellAlreadyOnList(source, channel, parameter); - - // it does, deny the change - return MODEACTION_DENY; - } - } - - unsigned int maxsize = 0; - - for (limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); it++) - { - if (InspIRCd::Match(channel->name, it->mask)) - { - // We have a pattern matching the channel... - maxsize = el->size(); - if (!IS_LOCAL(source) || (maxsize < it->limit)) - { - /* Ok, it *could* be allowed, now give someone subclassing us - * a chance to validate the parameter. - * The param is passed by reference, so they can both modify it - * and tell us if we allow it or not. - * - * eg, the subclass could: - * 1) allow - * 2) 'fix' parameter and then allow - * 3) deny - */ - if (ValidateParam(source, channel, parameter)) - { - // And now add the mask onto the list... - ListItem e; - e.mask = parameter; - e.nick = source->nick; - e.time = stringtime(); - - el->push_back(e); - return MODEACTION_ALLOW; - } - else - { - /* If they deny it they have the job of giving an error message */ - return MODEACTION_DENY; - } - } - } - } - - /* List is full, give subclass a chance to send a custom message */ - if (!TellListTooLong(source, channel, parameter)) - { - source->WriteNumeric(478, "%s %s %s :Channel ban/ignore list is full", source->nick.c_str(), channel->name.c_str(), parameter.c_str()); - } - - parameter.clear(); - return MODEACTION_DENY; - } - else - { - // We're taking the mode off - if (el) - { - for (modelist::iterator it = el->begin(); it != el->end(); it++) - { - if (parameter == it->mask) - { - el->erase(it); - if (el->empty()) - { - extItem.unset(channel); - } - return MODEACTION_ALLOW; - } - } - /* Tried to remove something that wasn't set */ - TellNotSet(source, channel, parameter); - parameter.clear(); - return MODEACTION_DENY; - } - else - { - /* Hmm, taking an exception off a non-existant list, DIE */ - TellNotSet(source, channel, parameter); - parameter.clear(); - return MODEACTION_DENY; - } - } - return MODEACTION_DENY; - } - - /** Syncronize channel item list with another server. - * See modules.h - * @param chan Channel to syncronize - * @param proto Protocol module pointer - * @param opaque Opaque connection handle - */ - virtual void DoSyncChannel(Channel* chan, Module* proto, void* opaque) - { - modelist* mlist = extItem.get(chan); - irc::modestacker modestack(true); - std::vector<std::string> stackresult; - std::vector<TranslateType> types; - types.push_back(TR_TEXT); - if (mlist) - { - for (modelist::iterator it = mlist->begin(); it != mlist->end(); it++) - { - modestack.Push(std::string(1, mode)[0], it->mask); - } - } - while (modestack.GetStackedLine(stackresult)) - { - types.assign(stackresult.size(), this->GetTranslateType()); - proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, stackresult, types); - stackresult.clear(); - } - } - - /** Clean up module on unload - * @param target_type Type of target to clean - * @param item Item to clean - */ - virtual void DoCleanup(int, void*) - { - } - - /** Validate parameters. - * Overridden by implementing module. - * @param source Source user adding the parameter - * @param channel Channel the parameter is being added to - * @param parameter The actual parameter being added - * @return true if the parameter is valid - */ - virtual bool ValidateParam(User*, Channel*, std::string&) - { - return true; - } - - /** Tell the user the list is too long. - * Overridden by implementing module. - * @param source Source user adding the parameter - * @param channel Channel the parameter is being added to - * @param parameter The actual parameter being added - * @return Ignored - */ - virtual bool TellListTooLong(User*, Channel*, std::string&) - { - return false; - } - - /** Tell the user an item is already on the list. - * Overridden by implementing module. - * @param source Source user adding the parameter - * @param channel Channel the parameter is being added to - * @param parameter The actual parameter being added - */ - virtual void TellAlreadyOnList(User*, Channel*, std::string&) - { - } - - /** Tell the user that the parameter is not in the list. - * Overridden by implementing module. - * @param source Source user removing the parameter - * @param channel Channel the parameter is being removed from - * @param parameter The actual parameter being removed - */ - virtual void TellNotSet(User*, Channel*, std::string&) - { - } -}; - -#endif diff --git a/src/server.cpp b/src/server.cpp index 4741f942d..97b4058c0 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -23,7 +23,6 @@ #include <signal.h> #include "exitcodes.h" #include "inspircd.h" -#include "inspircd_version.h" void InspIRCd::SignalHandler(int signal) { @@ -37,7 +36,7 @@ void InspIRCd::SignalHandler(int signal) else if (signal == SIGTERM) #endif { - Exit(signal); + Exit(EXIT_STATUS_SIGTERM); } } @@ -59,8 +58,7 @@ void InspIRCd::Exit(int status) void RehashHandler::Call(const std::string &reason) { ServerInstance->SNO->WriteToSnoMask('a', "Rehashing config file %s %s",ServerConfig::CleanFilename(ServerInstance->ConfigFileName.c_str()), reason.c_str()); - ServerInstance->RehashUsersAndChans(); - FOREACH_MOD(I_OnGarbageCollect, OnGarbageCollect()); + FOREACH_MOD(OnGarbageCollect, ()); if (!ServerInstance->ConfigThread) { ServerInstance->ConfigThread = new ConfigReaderThread(""); @@ -68,36 +66,28 @@ void RehashHandler::Call(const std::string &reason) } } -std::string InspIRCd::GetVersionString(bool operstring) +std::string InspIRCd::GetVersionString(bool getFullVersion) { - char versiondata[MAXBUF]; - if (operstring) - { - std::string sename = SE->GetName(); - snprintf(versiondata,MAXBUF,"%s %s :%s [%s,%s,%s]",VERSION, Config->ServerName.c_str(), SYSTEM,REVISION, sename.c_str(), Config->sid.c_str()); - } - else - snprintf(versiondata,MAXBUF,"%s %s :%s",BRANCH,Config->ServerName.c_str(),Config->CustomVersion.c_str()); - return versiondata; + if (getFullVersion) + return VERSION " " + Config->ServerName + " :" SYSTEM " [" REVISION "," + SE->GetName() + "," + Config->sid + "]"; + return BRANCH " " + Config->ServerName + " :" + Config->CustomVersion; } -const char InspIRCd::LogHeader[] = - "Log started for " VERSION " (" REVISION ", " MODULE_INIT_STR ")" - " - compiled on " SYSTEM; - -void InspIRCd::BuildISupport() +std::string UIDGenerator::GenerateSID(const std::string& servername, const std::string& serverdesc) { - // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it... - std::stringstream v; - v << "WALLCHOPS WALLVOICES MODES=" << Config->Limits.MaxModes << " CHANTYPES=# PREFIX=" << this->Modes->BuildPrefixes() << " MAP MAXCHANNELS=" << Config->MaxChans << " MAXBANS=60 VBANLIST NICKLEN=" << Config->Limits.NickMax; - v << " CASEMAPPING=rfc1459 STATUSMSG=" << Modes->BuildPrefixes(false) << " CHARSET=ascii TOPICLEN=" << Config->Limits.MaxTopic << " KICKLEN=" << Config->Limits.MaxKick << " MAXTARGETS=" << Config->MaxTargets; - v << " AWAYLEN=" << Config->Limits.MaxAway << " CHANMODES=" << this->Modes->GiveModeList(MASK_CHANNEL) << " FNC NETWORK=" << Config->Network << " MAXPARA=32 ELIST=MU" << " CHANNELLEN=" << Config->Limits.ChanMax; - Config->data005 = v.str(); - FOREACH_MOD(I_On005Numeric,On005Numeric(Config->data005)); - Config->Update005(); + unsigned int sid = 0; + + for (std::string::const_iterator i = servername.begin(); i != servername.end(); ++i) + sid = 5 * sid + *i; + for (std::string::const_iterator i = serverdesc.begin(); i != serverdesc.end(); ++i) + sid = 5 * sid + *i; + + std::string sidstr = ConvToStr(sid % 1000); + sidstr.insert(0, 3 - sidstr.length(), '0'); + return sidstr; } -void InspIRCd::IncrementUID(int pos) +void UIDGenerator::IncrementUID(unsigned int pos) { /* * Okay. The rules for generating a UID go like this... @@ -106,85 +96,141 @@ void InspIRCd::IncrementUID(int pos) * A again, in an iterative fashion.. so.. * AAA9 -> AABA, and so on. -- w00t */ - if ((pos == 3) && (current_uid[3] == '9')) + + // If we hit Z, wrap around to 0. + if (current_uid[pos] == 'Z') + { + current_uid[pos] = '0'; + } + else if (current_uid[pos] == '9') { - // At pos 3, if we hit '9', we've run out of available UIDs, and need to reset to AAA..AAA. - for (int i = 3; i < UUID_LENGTH-1; i++) + /* + * Or, if we hit 9, wrap around to pos = 'A' and (pos - 1)++, + * e.g. A9 -> BA -> BB .. + */ + current_uid[pos] = 'A'; + if (pos == 3) { - current_uid[i] = 'A'; + // At pos 3, if we hit '9', we've run out of available UIDs, and reset to AAA..AAA. + return; } + this->IncrementUID(pos - 1); } else { - // If we hit Z, wrap around to 0. - if (current_uid[pos] == 'Z') - { - current_uid[pos] = '0'; - } - else if (current_uid[pos] == '9') - { - /* - * Or, if we hit 9, wrap around to pos = 'A' and (pos - 1)++, - * e.g. A9 -> BA -> BB .. - */ - current_uid[pos] = 'A'; - this->IncrementUID(pos - 1); - } - else - { - // Anything else, nobody gives a shit. Just increment. - current_uid[pos]++; - } + // Anything else, nobody gives a shit. Just increment. + current_uid[pos]++; } } -/* - * Retrieve the next valid UUID that is free for this server. - */ -std::string InspIRCd::GetUID() +void UIDGenerator::init(const std::string& sid) { - static bool inited = false; - /* - * If we're setting up, copy SID into the first three digits, 9's to the rest, null term at the end + * Copy SID into the first three digits, 9's to the rest, null term at the end * Why 9? Well, we increment before we find, otherwise we have an unnecessary copy, and I want UID to start at AAA..AA * and not AA..AB. So by initialising to 99999, we force it to rollover to AAAAA on the first IncrementUID call. * Kind of silly, but I like how it looks. * -- w */ - if (!inited) - { - inited = true; - current_uid[0] = Config->sid[0]; - current_uid[1] = Config->sid[1]; - current_uid[2] = Config->sid[2]; - for (int i = 3; i < (UUID_LENGTH - 1); i++) - current_uid[i] = '9'; - - // Null terminator. Important. - current_uid[UUID_LENGTH - 1] = '\0'; - } + current_uid.resize(UUID_LENGTH, '9'); + current_uid[0] = sid[0]; + current_uid[1] = sid[1]; + current_uid[2] = sid[2]; +} +/* + * Retrieve the next valid UUID that is free for this server. + */ +std::string UIDGenerator::GetUID() +{ while (1) { // Add one to the last UID - this->IncrementUID(UUID_LENGTH - 2); + this->IncrementUID(UUID_LENGTH - 1); - if (this->FindUUID(current_uid)) - { - /* - * It's in use. We need to try the loop again. - */ - continue; - } + if (!ServerInstance->FindUUID(current_uid)) + break; - return current_uid; + /* + * It's in use. We need to try the loop again. + */ } - /* not reached. */ - return ""; + return current_uid; } +void ISupportManager::Build() +{ + /** + * This is currently the neatest way we can build the initial ISUPPORT map. In + * the future we can use an initializer list here. + */ + std::map<std::string, std::string> tokens; + + tokens["AWAYLEN"] = ConvToStr(ServerInstance->Config->Limits.MaxAway); + tokens["CASEMAPPING"] = "rfc1459"; + tokens["CHANMODES"] = ServerInstance->Modes->GiveModeList(MASK_CHANNEL); + tokens["CHANNELLEN"] = ConvToStr(ServerInstance->Config->Limits.ChanMax); + tokens["CHANTYPES"] = "#"; + tokens["CHARSET"] = "ascii"; + tokens["ELIST"] = "MU"; + tokens["KICKLEN"] = ConvToStr(ServerInstance->Config->Limits.MaxKick); + tokens["MAXBANS"] = "64"; // TODO: make this a config setting. + tokens["MAXCHANNELS"] = ConvToStr(ServerInstance->Config->MaxChans); + tokens["MAXTARGETS"] = ConvToStr(ServerInstance->Config->MaxTargets); + tokens["MODES"] = ConvToStr(ServerInstance->Config->Limits.MaxModes); + tokens["NETWORK"] = ServerInstance->Config->Network; + tokens["NICKLEN"] = ConvToStr(ServerInstance->Config->Limits.NickMax); + tokens["PREFIX"] = ServerInstance->Modes->BuildPrefixes(); + tokens["STATUSMSG"] = ServerInstance->Modes->BuildPrefixes(false); + tokens["TOPICLEN"] = ConvToStr(ServerInstance->Config->Limits.MaxTopic); + + tokens["FNC"] = tokens["VBANLIST"] = + tokens["WALLCHOPS"] = tokens["WALLVOICES"]; + + // Modules can add new tokens and also edit or remove existing tokens + FOREACH_MOD(On005Numeric, (tokens)); + + // EXTBAN is a special case as we need to sort it and prepend a comma. + std::map<std::string, std::string>::iterator extban = tokens.find("EXTBAN"); + if (extban != tokens.end()) + { + sort(extban->second.begin(), extban->second.end()); + extban->second.insert(0, ","); + } + + // Transform the map into a list of lines, ready to be sent to clients + std::vector<std::string>& lines = this->Lines; + std::string line; + unsigned int token_count = 0; + lines.clear(); + + for (std::map<std::string, std::string>::const_iterator it = tokens.begin(); it != tokens.end(); ++it) + { + line.append(it->first); + + // If this token has a value then append a '=' char after the name and then the value itself + if (!it->second.empty()) + line.append(1, '=').append(it->second); + // Always append a space, even if it's the last token because all lines will be suffixed + line.push_back(' '); + token_count++; + if (token_count % 13 == 12 || it == --tokens.end()) + { + // Reached maximum number of tokens for this line or the current token + // is the last one; finalize the line and store it for later use + line.append(":are supported by this server"); + lines.push_back(line); + line.clear(); + } + } +} + +void ISupportManager::SendTo(LocalUser* user) +{ + for (std::vector<std::string>::const_iterator i = this->Lines.begin(); i != this->Lines.end(); ++i) + user->WriteNumeric(RPL_ISUPPORT, "%s %s", user->nick.c_str(), i->c_str()); +} diff --git a/src/snomasks.cpp b/src/snomasks.cpp index 4b9c9d86b..d7cb64f26 100644 --- a/src/snomasks.cpp +++ b/src/snomasks.cpp @@ -52,26 +52,16 @@ void SnomaskManager::WriteGlobalSno(char letter, const std::string& text) void SnomaskManager::WriteToSnoMask(char letter, const char* text, ...) { - char textbuffer[MAXBUF]; - va_list argsPtr; - - va_start(argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - this->WriteToSnoMask(letter, std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + this->WriteToSnoMask(letter, textbuffer); } void SnomaskManager::WriteGlobalSno(char letter, const char* text, ...) { - char textbuffer[MAXBUF]; - va_list argsPtr; - - va_start(argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - this->WriteGlobalSno(letter, std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + this->WriteGlobalSno(letter, textbuffer); } SnomaskManager::SnomaskManager() @@ -79,54 +69,42 @@ SnomaskManager::SnomaskManager() EnableSnomask('c',"CONNECT"); /* Local connect notices */ EnableSnomask('q',"QUIT"); /* Local quit notices */ EnableSnomask('k',"KILL"); /* Kill notices */ - EnableSnomask('l',"LINK"); /* Linking notices */ EnableSnomask('o',"OPER"); /* Oper up/down notices */ EnableSnomask('a',"ANNOUNCEMENT"); /* formerly WriteOpers() - generic notices to all opers */ EnableSnomask('d',"DEBUG"); /* Debug notices */ EnableSnomask('x',"XLINE"); /* Xline notice (g/z/q/k/e) */ EnableSnomask('t',"STATS"); /* Local or remote stats request */ - EnableSnomask('f',"FLOOD"); /* Flooding notices */ } -/*************************************************************************************/ +bool SnomaskManager::IsSnomaskUsable(char ch) const +{ + return ((isalpha(ch)) && (!masks[tolower(ch) - 'a'].Description.empty())); +} -void Snomask::SendMessage(const std::string &message, char mysnomask) +Snomask::Snomask() + : Count(0) { - if (ServerInstance->Config->NoSnoticeStack || message != LastMessage || mysnomask != LastLetter) +} + +void Snomask::SendMessage(const std::string& message, char letter) +{ + if ((!ServerInstance->Config->NoSnoticeStack) && (message == LastMessage) && (letter == LastLetter)) { - this->Flush(); - LastMessage = message; - LastLetter = mysnomask; - - std::string desc = Description; - if (desc.empty()) - desc = std::string("SNO-") + (char)tolower(mysnomask); - if (isupper(mysnomask)) - desc = "REMOTE" + desc; - ModResult MOD_RESULT; - ServerInstance->Logs->Log("snomask", DEFAULT, "%s: %s", desc.c_str(), message.c_str()); - - FIRST_MOD_RESULT(OnSendSnotice, MOD_RESULT, (mysnomask, desc, message)); - - LastBlocked = (MOD_RESULT == MOD_RES_DENY); - - if (!LastBlocked) - { - /* Only opers can receive snotices, so we iterate the oper list */ - std::list<User*>::iterator i = ServerInstance->Users->all_opers.begin(); - - while (i != ServerInstance->Users->all_opers.end()) - { - User* a = *i; - if (IS_LOCAL(a) && a->IsModeSet('s') && a->IsNoticeMaskSet(mysnomask) && !a->quitting) - { - a->WriteServ("NOTICE %s :*** %s: %s", a->nick.c_str(), desc.c_str(), message.c_str()); - } - - i++; - } - } + Count++; + return; } + + this->Flush(); + + std::string desc = GetDescription(letter); + ModResult MOD_RESULT; + FIRST_MOD_RESULT(OnSendSnotice, MOD_RESULT, (letter, desc, message)); + if (MOD_RESULT == MOD_RES_DENY) + return; + + Snomask::Send(letter, desc, message); + LastMessage = message; + LastLetter = letter; Count++; } @@ -134,36 +112,44 @@ void Snomask::Flush() { if (Count > 1) { - std::string desc = Description; - if (desc.empty()) - desc = std::string("SNO-") + (char)tolower(LastLetter); - if (isupper(LastLetter)) - desc = "REMOTE" + desc; - std::string mesg = "(last message repeated "+ConvToStr(Count)+" times)"; - - ServerInstance->Logs->Log("snomask", DEFAULT, "%s: %s", desc.c_str(), mesg.c_str()); - - FOREACH_MOD(I_OnSendSnotice, OnSendSnotice(LastLetter, desc, mesg)); - - if (!LastBlocked) - { - /* Only opers can receive snotices, so we iterate the oper list */ - std::list<User*>::iterator i = ServerInstance->Users->all_opers.begin(); - - while (i != ServerInstance->Users->all_opers.end()) - { - User* a = *i; - if (IS_LOCAL(a) && a->IsModeSet('s') && a->IsNoticeMaskSet(LastLetter) && !a->quitting) - { - a->WriteServ("NOTICE %s :*** %s: %s", a->nick.c_str(), desc.c_str(), mesg.c_str()); - } - - i++; - } - } + std::string desc = GetDescription(LastLetter); + std::string msg = "(last message repeated " + ConvToStr(Count) + " times)"; + FOREACH_MOD(OnSendSnotice, (LastLetter, desc, msg)); + Snomask::Send(LastLetter, desc, msg); } + LastMessage.clear(); - LastBlocked = false; Count = 0; } + +void Snomask::Send(char letter, const std::string& desc, const std::string& msg) +{ + std::string log = desc; + log.append(": ").append(msg); + ServerInstance->Logs->Log("snomask", LOG_DEFAULT, log); + + std::string finalmsg = "*** "; + finalmsg.append(log); + /* Only opers can receive snotices, so we iterate the oper list */ + const std::list<User*>& opers = ServerInstance->Users->all_opers; + for (std::list<User*>::const_iterator i = opers.begin(); i != opers.end(); ++i) + { + User* user = *i; + // IsNoticeMaskSet() returns false for opers who aren't +s, no need to check for it seperately + if (IS_LOCAL(user) && user->IsNoticeMaskSet(letter)) + user->WriteNotice(finalmsg); + } +} + +std::string Snomask::GetDescription(char letter) const +{ + std::string ret; + if (isupper(letter)) + ret = "REMOTE"; + if (!Description.empty()) + ret += Description; + else + ret += std::string("SNO-") + (char)tolower(letter); + return ret; +} diff --git a/src/socket.cpp b/src/socket.cpp index 6fc7b13f8..9ec7544f2 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -58,19 +58,19 @@ bool InspIRCd::BindSocket(int sockfd, int port, const char* addr, bool dolisten) { if (SE->Listen(sockfd, Config->MaxConn) == -1) { - this->Logs->Log("SOCKET",DEFAULT,"ERROR in listen(): %s",strerror(errno)); + this->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR in listen(): %s",strerror(errno)); return false; } else { - this->Logs->Log("SOCKET",DEBUG,"New socket binding for %d with listen: %s:%d", sockfd, addr, port); + this->Logs->Log("SOCKET", LOG_DEBUG, "New socket binding for %d with listen: %s:%d", sockfd, addr, port); SE->NonBlocking(sockfd); return true; } } else { - this->Logs->Log("SOCKET",DEBUG,"New socket binding for %d without listen: %s:%d", sockfd, addr, port); + this->Logs->Log("SOCKET", LOG_DEBUG, "New socket binding for %d without listen: %s:%d", sockfd, addr, port); return true; } } @@ -89,7 +89,7 @@ int InspIRCd::BindPorts(FailedPortList &failed_ports) std::string Addr = tag->getString("address"); if (strncasecmp(Addr.c_str(), "::ffff:", 7) == 0) - this->Logs->Log("SOCKET",DEFAULT, "Using 4in6 (::ffff:) isn't recommended. You should bind IPv4 addresses directly instead."); + this->Logs->Log("SOCKET", LOG_DEFAULT, "Using 4in6 (::ffff:) isn't recommended. You should bind IPv4 addresses directly instead."); irc::portparser portrange(porttag, false); int portno = -1; @@ -136,11 +136,11 @@ int InspIRCd::BindPorts(FailedPortList &failed_ports) n++; if (n == ports.end()) { - this->Logs->Log("SOCKET",DEFAULT,"Port bindings slipped out of vector, aborting close!"); + this->Logs->Log("SOCKET", LOG_DEFAULT, "Port bindings slipped out of vector, aborting close!"); break; } - this->Logs->Log("SOCKET",DEFAULT, "Port binding %s was removed from the config file, closing.", + this->Logs->Log("SOCKET", LOG_DEFAULT, "Port binding %s was removed from the config file, closing.", (**n).bind_desc.c_str()); delete *n; @@ -221,24 +221,22 @@ static const char all_zero[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; std::string irc::sockets::sockaddrs::str() const { - char buffer[MAXBUF]; if (sa.sa_family == AF_INET) { - const uint8_t* bits = reinterpret_cast<const uint8_t*>(&in4.sin_addr); - sprintf(buffer, "%d.%d.%d.%d:%u", bits[0], bits[1], bits[2], bits[3], ntohs(in4.sin_port)); + char ipaddr[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &in4.sin_addr, ipaddr, sizeof(ipaddr)); + return InspIRCd::Format("%s:%u", ipaddr, ntohs(in4.sin_port)); } - else if (sa.sa_family == AF_INET6) + + if (sa.sa_family == AF_INET6) { - buffer[0] = '['; - if (!inet_ntop(AF_INET6, &in6.sin6_addr, buffer+1, MAXBUF - 10)) - return "<unknown>"; // should never happen, buffer is large enough - int len = strlen(buffer); - // no need for snprintf, buffer has at least 9 chars left, max short len = 5 - sprintf(buffer + len, "]:%u", ntohs(in6.sin6_port)); + char ipaddr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &in6.sin6_addr, ipaddr, sizeof(ipaddr)); + return InspIRCd::Format("[%s]:%u", ipaddr, ntohs(in6.sin6_port)); } - else - return "<unknown>"; - return std::string(buffer); + + // This should never happen. + return "<unknown>"; } int irc::sockets::sockaddrs::sa_size() const diff --git a/src/socketengine.cpp b/src/socketengine.cpp index 8af598b06..219d154f2 100644 --- a/src/socketengine.cpp +++ b/src/socketengine.cpp @@ -60,7 +60,7 @@ void SocketEngine::ChangeEventMask(EventHandler* eh, int change) new_m &= ~FD_WANT_READ_MASK; if (change & FD_WANT_WRITE_MASK) new_m &= ~FD_WANT_WRITE_MASK; - + // if adding a trial read/write, insert it into the set if (change & FD_TRIAL_NOTE_MASK && !(old_m & FD_TRIAL_NOTE_MASK)) trials.insert(eh->GetFd()); diff --git a/src/socketengines/socketengine_epoll.cpp b/src/socketengines/socketengine_epoll.cpp index 6913076a2..099f793a1 100644 --- a/src/socketengines/socketengine_epoll.cpp +++ b/src/socketengines/socketengine_epoll.cpp @@ -61,7 +61,7 @@ EPollEngine::EPollEngine() } else { - ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets!"); + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR: Can't determine maximum number of open sockets!"); std::cout << "ERROR: Can't determine maximum number of open sockets!" << std::endl; ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE); } @@ -71,8 +71,8 @@ EPollEngine::EPollEngine() if (EngineHandle == -1) { - ServerInstance->Logs->Log("SOCKET",DEFAULT, "ERROR: Could not initialize socket engine: %s", strerror(errno)); - ServerInstance->Logs->Log("SOCKET",DEFAULT, "ERROR: Your kernel probably does not have the proper features. This is a fatal error, exiting now."); + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR: Could not initialize socket engine: %s", strerror(errno)); + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR: Your kernel probably does not have the proper features. This is a fatal error, exiting now."); std::cout << "ERROR: Could not initialize epoll socket engine: " << strerror(errno) << std::endl; std::cout << "ERROR: Your kernel probably does not have the proper features. This is a fatal error, exiting now." << std::endl; ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE); @@ -119,13 +119,13 @@ bool EPollEngine::AddFd(EventHandler* eh, int event_mask) int fd = eh->GetFd(); if ((fd < 0) || (fd > GetMaxFds() - 1)) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"AddFd out of range: (fd: %d, max: %d)", fd, GetMaxFds()); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "AddFd out of range: (fd: %d, max: %d)", fd, GetMaxFds()); return false; } if (ref[fd]) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"Attempt to add duplicate fd: %d", fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Attempt to add duplicate fd: %d", fd); return false; } @@ -136,11 +136,11 @@ bool EPollEngine::AddFd(EventHandler* eh, int event_mask) int i = epoll_ctl(EngineHandle, EPOLL_CTL_ADD, fd, &ev); if (i < 0) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"Error adding fd: %d to socketengine: %s", fd, strerror(errno)); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Error adding fd: %d to socketengine: %s", fd, strerror(errno)); return false; } - ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd); ref[fd] = eh; SocketEngine::SetEventMask(eh, event_mask); @@ -168,7 +168,7 @@ void EPollEngine::DelFd(EventHandler* eh) int fd = eh->GetFd(); if ((fd < 0) || (fd > GetMaxFds() - 1)) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"DelFd out of range: (fd: %d, max: %d)", fd, GetMaxFds()); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DelFd out of range: (fd: %d, max: %d)", fd, GetMaxFds()); return; } @@ -179,12 +179,12 @@ void EPollEngine::DelFd(EventHandler* eh) if (i < 0) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"epoll_ctl can't remove socket: %s", strerror(errno)); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "epoll_ctl can't remove socket: %s", strerror(errno)); } ref[fd] = NULL; - ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d", fd); CurrentSetSize--; } @@ -202,7 +202,7 @@ int EPollEngine::DispatchEvents() EventHandler* eh = ref[events[j].data.fd]; if (!eh) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"Got event on unknown fd: %d", events[j].data.fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Got event on unknown fd: %d", events[j].data.fd); epoll_ctl(EngineHandle, EPOLL_CTL_DEL, events[j].data.fd, &events[j]); continue; } diff --git a/src/socketengines/socketengine_kqueue.cpp b/src/socketengines/socketengine_kqueue.cpp index 8694a0bdd..99ac51499 100644 --- a/src/socketengines/socketengine_kqueue.cpp +++ b/src/socketengines/socketengine_kqueue.cpp @@ -72,7 +72,7 @@ KQueueEngine::KQueueEngine() sysctl(mib, 2, &MAX_DESCRIPTORS, &len, NULL, 0); if (MAX_DESCRIPTORS <= 0) { - ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets!"); + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR: Can't determine maximum number of open sockets!"); std::cout << "ERROR: Can't determine maximum number of open sockets!" << std::endl; ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE); } @@ -93,8 +93,8 @@ void KQueueEngine::RecoverFromFork() EngineHandle = kqueue(); if (EngineHandle == -1) { - ServerInstance->Logs->Log("SOCKET",DEFAULT, "ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features."); - ServerInstance->Logs->Log("SOCKET",DEFAULT, "ERROR: this is a fatal error, exiting now."); + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features."); + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR: this is a fatal error, exiting now."); std::cout << "ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features." << std::endl; std::cout << "ERROR: this is a fatal error, exiting now." << std::endl; ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE); @@ -126,7 +126,7 @@ bool KQueueEngine::AddFd(EventHandler* eh, int event_mask) int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL); if (i == -1) { - ServerInstance->Logs->Log("SOCKET",DEFAULT,"Failed to add fd: %d %s", + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "Failed to add fd: %d %s", fd, strerror(errno)); return false; } @@ -136,7 +136,7 @@ bool KQueueEngine::AddFd(EventHandler* eh, int event_mask) OnSetEvent(eh, 0, event_mask); CurrentSetSize++; - ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd); return true; } @@ -146,7 +146,7 @@ void KQueueEngine::DelFd(EventHandler* eh) if ((fd < 0) || (fd > GetMaxFds() - 1)) { - ServerInstance->Logs->Log("SOCKET",DEFAULT,"DelFd() on invalid fd: %d", fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "DelFd() on invalid fd: %d", fd); return; } @@ -163,14 +163,14 @@ void KQueueEngine::DelFd(EventHandler* eh) if (j < 0) { - ServerInstance->Logs->Log("SOCKET",DEFAULT,"Failed to remove fd: %d %s", + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "Failed to remove fd: %d %s", fd, strerror(errno)); } CurrentSetSize--; ref[fd] = NULL; - ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d", fd); } void KQueueEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask) @@ -182,7 +182,7 @@ void KQueueEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask) EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_ADD, 0, 0, NULL); int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL); if (i < 0) { - ServerInstance->Logs->Log("SOCKET",DEFAULT,"Failed to mark for writing: %d %s", + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "Failed to mark for writing: %d %s", eh->GetFd(), strerror(errno)); } } @@ -193,7 +193,7 @@ void KQueueEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask) EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL); int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL); if (i < 0) { - ServerInstance->Logs->Log("SOCKET",DEFAULT,"Failed to mark for writing: %d %s", + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "Failed to mark for writing: %d %s", eh->GetFd(), strerror(errno)); } } @@ -204,7 +204,7 @@ void KQueueEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask) EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, NULL); int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL); if (i < 0) { - ServerInstance->Logs->Log("SOCKET",DEFAULT,"Failed to mark for writing: %d %s", + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "Failed to mark for writing: %d %s", eh->GetFd(), strerror(errno)); } } diff --git a/src/socketengines/socketengine_poll.cpp b/src/socketengines/socketengine_poll.cpp index ea7780686..493b22630 100644 --- a/src/socketengines/socketengine_poll.cpp +++ b/src/socketengines/socketengine_poll.cpp @@ -20,9 +20,6 @@ */ -#include "inspircd.h" -#include "exitcodes.h" - #ifndef SOCKETENGINE_POLL #define SOCKETENGINE_POLL @@ -30,7 +27,7 @@ #include <vector> #include <string> #include <map> -#include "inspircd_config.h" +#include "exitcodes.h" #include "inspircd.h" #include "socketengine.h" @@ -86,7 +83,7 @@ PollEngine::PollEngine() } else { - ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets: %s", strerror(errno)); + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR: Can't determine maximum number of open sockets: %s", strerror(errno)); std::cout << "ERROR: Can't determine maximum number of open sockets: " << strerror(errno) << std::endl; ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE); } @@ -120,13 +117,13 @@ bool PollEngine::AddFd(EventHandler* eh, int event_mask) int fd = eh->GetFd(); if ((fd < 0) || (fd > GetMaxFds() - 1)) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"AddFd out of range: (fd: %d, max: %d)", fd, GetMaxFds()); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "AddFd out of range: (fd: %d, max: %d)", fd, GetMaxFds()); return false; } if (fd_mappings.find(fd) != fd_mappings.end()) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"Attempt to add duplicate fd: %d", fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Attempt to add duplicate fd: %d", fd); return false; } @@ -137,7 +134,7 @@ bool PollEngine::AddFd(EventHandler* eh, int event_mask) events[index].fd = fd; events[index].events = mask_to_poll(event_mask); - ServerInstance->Logs->Log("SOCKET", DEBUG,"New file descriptor: %d (%d; index %d)", fd, events[fd].events, index); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d (%d; index %d)", fd, events[fd].events, index); SocketEngine::SetEventMask(eh, event_mask); CurrentSetSize++; return true; @@ -156,7 +153,7 @@ void PollEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask) std::map<int, unsigned int>::iterator it = fd_mappings.find(eh->GetFd()); if (it == fd_mappings.end()) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"SetEvents() on unknown fd: %d", eh->GetFd()); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "SetEvents() on unknown fd: %d", eh->GetFd()); return; } @@ -168,14 +165,14 @@ void PollEngine::DelFd(EventHandler* eh) int fd = eh->GetFd(); if ((fd < 0) || (fd > MAX_DESCRIPTORS)) { - ServerInstance->Logs->Log("SOCKET", DEBUG, "DelFd out of range: (fd: %d, max: %d)", fd, GetMaxFds()); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DelFd out of range: (fd: %d, max: %d)", fd, GetMaxFds()); return; } std::map<int, unsigned int>::iterator it = fd_mappings.find(fd); if (it == fd_mappings.end()) { - ServerInstance->Logs->Log("SOCKET",DEBUG,"DelFd() on unknown fd: %d", fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DelFd() on unknown fd: %d", fd); return; } @@ -206,7 +203,7 @@ void PollEngine::DelFd(EventHandler* eh) CurrentSetSize--; - ServerInstance->Logs->Log("SOCKET", DEBUG, "Remove file descriptor: %d (index: %d) " + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d (index: %d) " "(Filled gap with: %d (index: %d))", fd, index, last_fd, last_index); } @@ -255,7 +252,7 @@ int PollEngine::DispatchEvents() // whoops, deleted out from under us continue; } - + if (events[index].revents & POLLOUT) { int mask = eh->GetEventMask(); diff --git a/src/socketengines/socketengine_ports.cpp b/src/socketengines/socketengine_ports.cpp index f7c547d45..ba4e8f2d7 100644 --- a/src/socketengines/socketengine_ports.cpp +++ b/src/socketengines/socketengine_ports.cpp @@ -32,7 +32,6 @@ #include <vector> #include <string> #include <map> -#include "inspircd_config.h" #include "inspircd.h" #include "socketengine.h" #include <port.h> @@ -75,7 +74,7 @@ PortsEngine::PortsEngine() } else { - ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets!"); + ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "ERROR: Can't determine maximum number of open sockets!"); std::cout << "ERROR: Can't determine maximum number of open sockets!" << std::endl; ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE); } @@ -83,8 +82,8 @@ PortsEngine::PortsEngine() if (EngineHandle == -1) { - ServerInstance->Logs->Log("SOCKET",SPARSE,"ERROR: Could not initialize socket engine: %s", strerror(errno)); - ServerInstance->Logs->Log("SOCKET",SPARSE,"ERROR: This is a fatal error, exiting now."); + ServerInstance->Logs->Log("SOCKET", LOG_SPARSE, "ERROR: Could not initialize socket engine: %s", strerror(errno)); + ServerInstance->Logs->Log("SOCKET", LOG_SPARSE, "ERROR: This is a fatal error, exiting now."); std::cout << "ERROR: Could not initialize socket engine: " << strerror(errno) << std::endl; std::cout << "ERROR: This is a fatal error, exiting now." << std::endl; ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE); @@ -126,7 +125,7 @@ bool PortsEngine::AddFd(EventHandler* eh, int event_mask) SocketEngine::SetEventMask(eh, event_mask); port_associate(EngineHandle, PORT_SOURCE_FD, fd, mask_to_events(event_mask), eh); - ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd); CurrentSetSize++; return true; } @@ -148,7 +147,7 @@ void PortsEngine::DelFd(EventHandler* eh) CurrentSetSize--; ref[fd] = NULL; - ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d", fd); } int PortsEngine::DispatchEvents() diff --git a/src/socketengines/socketengine_select.cpp b/src/socketengines/socketengine_select.cpp index c21b200c2..f995b5472 100644 --- a/src/socketengines/socketengine_select.cpp +++ b/src/socketengines/socketengine_select.cpp @@ -18,8 +18,6 @@ */ -#include "inspircd_config.h" - #include "inspircd.h" #include "socketengine.h" @@ -86,7 +84,7 @@ bool SelectEngine::AddFd(EventHandler* eh, int event_mask) CurrentSetSize++; - ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd); return true; } @@ -106,7 +104,7 @@ void SelectEngine::DelFd(EventHandler* eh) if (fd == MaxFD) --MaxFD; - ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d", fd); } void SelectEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask) diff --git a/src/testsuite.cpp b/src/testsuite.cpp index 58b72ee3e..b27f6e18c 100644 --- a/src/testsuite.cpp +++ b/src/testsuite.cpp @@ -19,8 +19,6 @@ */ -/* $Core */ - #include "inspircd.h" #include "testsuite.h" #include "threadengine.h" @@ -76,7 +74,7 @@ TestSuite::TestSuite() switch (choice) { case '1': - FOREACH_MOD(I_OnRunTestSuite, OnRunTestSuite()); + FOREACH_MOD(OnRunTestSuite, ()); break; case '2': std::cout << "Enter module filename to load: "; @@ -331,36 +329,25 @@ bool TestSuite::DoThreadTests() bool TestSuite::DoGenerateUIDTests() { - bool success = RealGenerateUIDTests(); - - // Reset the UID generation state so running the tests multiple times won't mess things up - for (unsigned int i = 0; i < 3; i++) - ServerInstance->current_uid[i] = ServerInstance->Config->sid[i]; - for (unsigned int i = 3; i < UUID_LENGTH-1; i++) - ServerInstance->current_uid[i] = '9'; - - ServerInstance->current_uid[UUID_LENGTH-1] = '\0'; + const unsigned int UUID_LENGTH = UIDGenerator::UUID_LENGTH; + UIDGenerator uidgen; + uidgen.init(ServerInstance->Config->GetSID()); + std::string first_uid = uidgen.GetUID(); - return success; -} - -bool TestSuite::RealGenerateUIDTests() -{ - std::string first_uid = ServerInstance->GetUID(); - if (first_uid.length() != UUID_LENGTH-1) + if (first_uid.length() != UUID_LENGTH) { std::cout << "GENERATEUID: Generated UID is " << first_uid.length() << " characters long instead of " << UUID_LENGTH-1 << std::endl; return false; } - if (ServerInstance->current_uid[UUID_LENGTH-1] != '\0') + if (uidgen.current_uid.c_str()[UUID_LENGTH] != '\0') { std::cout << "GENERATEUID: The null terminator is missing from the end of current_uid" << std::endl; return false; } // The correct UID when generating one for the first time is ...AAAAAA - std::string correct_uid = ServerInstance->Config->sid + std::string(UUID_LENGTH - 4, 'A'); + std::string correct_uid = ServerInstance->Config->sid + std::string(UUID_LENGTH - 3, 'A'); if (first_uid != correct_uid) { std::cout << "GENERATEUID: Generated an invalid first UID: " << first_uid << " instead of " << correct_uid << std::endl; @@ -368,16 +355,16 @@ bool TestSuite::RealGenerateUIDTests() } // Set current_uid to be ...Z99999 - ServerInstance->current_uid[3] = 'Z'; - for (unsigned int i = 4; i < UUID_LENGTH-1; i++) - ServerInstance->current_uid[i] = '9'; + uidgen.current_uid[3] = 'Z'; + for (unsigned int i = 4; i < UUID_LENGTH; i++) + uidgen.current_uid[i] = '9'; // Store the UID we'll be incrementing so we can display what's wrong later if necessary - std::string before_increment(ServerInstance->current_uid); - std::string generated_uid = ServerInstance->GetUID(); + std::string before_increment(uidgen.current_uid); + std::string generated_uid = uidgen.GetUID(); // Correct UID after incrementing ...Z99999 is ...0AAAAA - correct_uid = ServerInstance->Config->sid + "0" + std::string(UUID_LENGTH - 5, 'A'); + correct_uid = ServerInstance->Config->sid + "0" + std::string(UUID_LENGTH - 4, 'A'); if (generated_uid != correct_uid) { @@ -386,11 +373,11 @@ bool TestSuite::RealGenerateUIDTests() } // Set current_uid to be ...999999 to see if it rolls over correctly - for (unsigned int i = 3; i < UUID_LENGTH-1; i++) - ServerInstance->current_uid[i] = '9'; + for (unsigned int i = 3; i < UUID_LENGTH; i++) + uidgen.current_uid[i] = '9'; - before_increment.assign(ServerInstance->current_uid); - generated_uid = ServerInstance->GetUID(); + before_increment.assign(uidgen.current_uid); + generated_uid = uidgen.GetUID(); // Correct UID after rolling over is the first UID we've generated (...AAAAAA) if (generated_uid != first_uid) diff --git a/src/threadengine.cpp b/src/threadengine.cpp index 8f1895c0f..8e1bac470 100644 --- a/src/threadengine.cpp +++ b/src/threadengine.cpp @@ -17,12 +17,6 @@ */ -/* $Core */ - -/********* DEFAULTS **********/ -/* $ExtraSources: threadengines/threadengine_pthread.cpp */ -/* $ExtraObjects: threadengine_pthread.o */ - #include "inspircd.h" #include "threadengine.h" diff --git a/src/timer.cpp b/src/timer.cpp index a1ee0b488..f541c7eb1 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -20,60 +20,57 @@ */ -/* $Core */ - #include "inspircd.h" #include "timer.h" -TimerManager::TimerManager() +void Timer::SetInterval(time_t newinterval) { + ServerInstance->Timers->DelTimer(this); + secs = newinterval; + SetTrigger(ServerInstance->Time() + newinterval); + ServerInstance->Timers->AddTimer(this); } -TimerManager::~TimerManager() +Timer::~Timer() { - for(std::vector<Timer *>::iterator i = Timers.begin(); i != Timers.end(); i++) - delete *i; + ServerInstance->Timers->DelTimer(this); } void TimerManager::TickTimers(time_t TIME) { - while ((Timers.size()) && (TIME > (*Timers.begin())->GetTimer())) + for (TimerMap::iterator i = Timers.begin(); i != Timers.end(); ) { - std::vector<Timer *>::iterator i = Timers.begin(); - Timer *t = (*i); + Timer* t = i->second; + if (t->GetTrigger() > TIME) + break; - // Probable fix: move vector manipulation to *before* we modify the vector. - Timers.erase(i); + Timers.erase(i++); - t->Tick(TIME); - if (t->GetRepeat()) + if (!t->Tick(TIME)) + delete t; + else if (t->GetRepeat()) { - t->SetTimer(TIME + t->GetSecs()); + t->SetTrigger(TIME + t->GetInterval()); AddTimer(t); } - else - delete t; } } -void TimerManager::DelTimer(Timer* T) +void TimerManager::DelTimer(Timer* t) { - std::vector<Timer *>::iterator i = std::find(Timers.begin(), Timers.end(), T); + std::pair<TimerMap::iterator, TimerMap::iterator> itpair = Timers.equal_range(t->GetTrigger()); - if (i != Timers.end()) + for (TimerMap::iterator i = itpair.first; i != itpair.second; ++i) { - delete (*i); - Timers.erase(i); + if (i->second == t) + { + Timers.erase(i); + break; + } } } -void TimerManager::AddTimer(Timer* T) -{ - Timers.push_back(T); - sort(Timers.begin(), Timers.end(), TimerManager::TimerComparison); -} - -bool TimerManager::TimerComparison( Timer *one, Timer *two) +void TimerManager::AddTimer(Timer* t) { - return (one->GetTimer()) < (two->GetTimer()); + Timers.insert(std::make_pair(t->GetTrigger(), t)); } diff --git a/src/user_resolver.cpp b/src/user_resolver.cpp deleted file mode 100644 index f18fc9a03..000000000 --- a/src/user_resolver.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> - * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "inspircd.h" -UserResolver::UserResolver(LocalUser* user, std::string to_resolve, QueryType qt, bool &cache) : - Resolver(to_resolve, qt, cache, NULL), uuid(user->uuid) -{ - this->fwd = (qt == DNS_QUERY_A || qt == DNS_QUERY_AAAA); -} - -void UserResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) -{ - UserResolver *res_forward; // for forward-resolution - LocalUser* bound_user = (LocalUser*)ServerInstance->FindUUID(uuid); - if (!bound_user) - { - ServerInstance->Logs->Log("RESOLVER", DEBUG, "Resolution finished for user '%s' who is gone", uuid.c_str()); - return; - } - - ServerInstance->Logs->Log("RESOLVER", DEBUG, "DNS result for %s: '%s' -> '%s'", uuid.c_str(), input.c_str(), result.c_str()); - - if (!fwd) - { - // first half of resolution is done. We now need to verify that the host matches. - bound_user->stored_host = result; - try - { - /* Check we didnt time out */ - if (bound_user->registered != REG_ALL) - { - bool lcached = false; - if (bound_user->client_sa.sa.sa_family == AF_INET6) - { - /* IPV6 forward lookup */ - res_forward = new UserResolver(bound_user, result, DNS_QUERY_AAAA, lcached); - } - else - { - /* IPV4 lookup */ - res_forward = new UserResolver(bound_user, result, DNS_QUERY_A, lcached); - } - ServerInstance->AddResolver(res_forward, lcached); - } - } - catch (CoreException& e) - { - ServerInstance->Logs->Log("RESOLVER", DEBUG,"Error in resolver: %s",e.GetReason()); - } - } - else - { - /* Both lookups completed */ - - irc::sockets::sockaddrs* user_ip = &bound_user->client_sa; - bool rev_match = false; - if (user_ip->sa.sa_family == AF_INET6) - { - struct in6_addr res_bin; - if (inet_pton(AF_INET6, result.c_str(), &res_bin)) - { - rev_match = !memcmp(&user_ip->in6.sin6_addr, &res_bin, sizeof(res_bin)); - } - } - else - { - struct in_addr res_bin; - if (inet_pton(AF_INET, result.c_str(), &res_bin)) - { - rev_match = !memcmp(&user_ip->in4.sin_addr, &res_bin, sizeof(res_bin)); - } - } - - if (rev_match) - { - std::string hostname = bound_user->stored_host; - if (hostname.length() < 65) - { - /* Check we didnt time out */ - if ((bound_user->registered != REG_ALL) && (!bound_user->dns_done)) - { - /* Hostnames starting with : are not a good thing (tm) */ - if (hostname[0] == ':') - hostname.insert(0, "0"); - - bound_user->WriteServ("NOTICE Auth :*** Found your hostname (%s)%s", hostname.c_str(), (cached ? " -- cached" : "")); - bound_user->dns_done = true; - bound_user->dhost.assign(hostname, 0, 64); - bound_user->host.assign(hostname, 0, 64); - /* Invalidate cache */ - bound_user->InvalidateCache(); - } - } - else - { - if (!bound_user->dns_done) - { - bound_user->WriteServ("NOTICE Auth :*** Your hostname is longer than the maximum of 64 characters, using your IP address (%s) instead.", bound_user->GetIPString()); - bound_user->dns_done = true; - } - } - } - else - { - if (!bound_user->dns_done) - { - bound_user->WriteServ("NOTICE Auth :*** Your hostname does not match up with your IP address. Sorry, using your IP address (%s) instead.", bound_user->GetIPString()); - bound_user->dns_done = true; - } - } - - // Save some memory by freeing this up; it's never used again in the user's lifetime. - bound_user->stored_host.resize(0); - } -} - -void UserResolver::OnError(ResolverError e, const std::string &errormessage) -{ - LocalUser* bound_user = (LocalUser*)ServerInstance->FindUUID(uuid); - if (bound_user) - { - bound_user->WriteServ("NOTICE Auth :*** Could not resolve your hostname: %s; using your IP address (%s) instead.", errormessage.c_str(), bound_user->GetIPString()); - bound_user->dns_done = true; - bound_user->stored_host.resize(0); - ServerInstance->stats->statsDnsBad++; - } -} diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 076277a33..538feaade 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -23,12 +23,26 @@ #include "inspircd.h" #include "xline.h" #include "bancache.h" +#include "iohook.h" UserManager::UserManager() - : unregistered_count(0), local_count(0) + : clientlist(new user_hash) + , uuidlist(new user_hash) + , unregistered_count(0), local_count(0) { } +UserManager::~UserManager() +{ + for (user_hash::iterator i = clientlist->begin(); i != clientlist->end(); ++i) + { + delete i->second; + } + + delete clientlist; + delete uuidlist; +} + /* add a client connection to the sockets list */ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) { @@ -42,14 +56,14 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs } catch (...) { - ServerInstance->Logs->Log("USERS", DEFAULT,"*** WTF *** Duplicated UUID! -- Crack smoking monkeys have been unleashed."); + ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "*** WTF *** Duplicated UUID! -- Crack smoking monkeys have been unleashed."); ServerInstance->SNO->WriteToSnoMask('a', "WARNING *** Duplicate UUID allocated!"); return; } UserIOHandler* eh = &New->eh; /* Give each of the modules an attempt to hook the user for I/O */ - FOREACH_MOD(I_OnHookIO, OnHookIO(eh, via)); + FOREACH_MOD(OnHookIO, (eh, via)); if (eh->GetIOHook()) { @@ -59,11 +73,11 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs } catch (CoreException& modexcept) { - ServerInstance->Logs->Log("SOCKET", DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); + ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); } } - ServerInstance->Logs->Log("USERS", DEBUG,"New user fd: %d", socket); + ServerInstance->Logs->Log("USERS", LOG_DEBUG, "New user fd: %d", socket); this->unregistered_count++; @@ -98,7 +112,7 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs * Check connect class settings and initialise settings into User. * This will be done again after DNS resolution. -- w00t */ - New->CheckClass(); + New->CheckClass(ServerInstance->Config->CCOnConnect); if (New->quitting) return; @@ -114,15 +128,15 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs if (!b->Type.empty() && !New->exempt) { /* user banned */ - ServerInstance->Logs->Log("BANCACHE", DEBUG, std::string("BanCache: Positive hit for ") + New->GetIPString()); - if (!ServerInstance->Config->MoronBanner.empty()) - New->WriteServ("NOTICE %s :*** %s", New->nick.c_str(), ServerInstance->Config->MoronBanner.c_str()); + ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Positive hit for " + New->GetIPString()); + if (!ServerInstance->Config->XLineMessage.empty()) + New->WriteNotice("*** " + ServerInstance->Config->XLineMessage); this->QuitUser(New, b->Reason); return; } else { - ServerInstance->Logs->Log("BANCACHE", DEBUG, std::string("BanCache: Negative hit for ") + New->GetIPString()); + ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Negative hit for " + New->GetIPString()); } } else @@ -141,51 +155,37 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs if (!ServerInstance->SE->AddFd(eh, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE)) { - ServerInstance->Logs->Log("USERS", DEBUG,"Internal error on new connection"); + ServerInstance->Logs->Log("USERS", LOG_DEBUG, "Internal error on new connection"); this->QuitUser(New, "Internal error handling connection"); } - /* NOTE: even if dns lookups are *off*, we still need to display this. - * BOPM and other stuff requires it. - */ - New->WriteServ("NOTICE Auth :*** Looking up your hostname..."); if (ServerInstance->Config->RawLog) - New->WriteServ("NOTICE Auth :*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded."); + New->WriteNotice("*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded."); - FOREACH_MOD(I_OnSetUserIP,OnSetUserIP(New)); + FOREACH_MOD(OnSetUserIP, (New)); if (New->quitting) return; - FOREACH_MOD(I_OnUserInit,OnUserInit(New)); - - if (ServerInstance->Config->NoUserDns) - { - New->WriteServ("NOTICE %s :*** Skipping host resolution (disabled by server administrator)", New->nick.c_str()); - New->dns_done = true; - } - else - { - New->StartDNSLookup(); - } + FOREACH_MOD(OnUserInit, (New)); } void UserManager::QuitUser(User *user, const std::string &quitreason, const char* operreason) { if (user->quitting) { - ServerInstance->Logs->Log("USERS", DEFAULT, "ERROR: Tried to quit quitting user: " + user->nick); + ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Tried to quit quitting user: " + user->nick); return; } if (IS_SERVER(user)) { - ServerInstance->Logs->Log("USERS", DEFAULT, "ERROR: Tried to quit server user: " + user->nick); + ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Tried to quit server user: " + user->nick); return; } user->quitting = true; - ServerInstance->Logs->Log("USERS", DEBUG, "QuitUser: %s=%s '%s'", user->uuid.c_str(), user->nick.c_str(), quitreason.c_str()); + ServerInstance->Logs->Log("USERS", LOG_DEBUG, "QuitUser: %s=%s '%s'", user->uuid.c_str(), user->nick.c_str(), quitreason.c_str()); user->Write("ERROR :Closing link: (%s@%s) [%s]", user->ident.c_str(), user->host.c_str(), *operreason ? operreason : quitreason.c_str()); std::string reason; @@ -200,7 +200,7 @@ void UserManager::QuitUser(User *user, const std::string &quitreason, const char if (user->registered == REG_ALL) { - FOREACH_MOD(I_OnUserQuit,OnUserQuit(user, reason, oper_reason)); + FOREACH_MOD(OnUserQuit, (user, reason, oper_reason)); user->WriteCommonQuit(reason, oper_reason); } @@ -211,7 +211,7 @@ void UserManager::QuitUser(User *user, const std::string &quitreason, const char if (IS_LOCAL(user)) { LocalUser* lu = IS_LOCAL(user); - FOREACH_MOD(I_OnUserDisconnect,OnUserDisconnect(lu)); + FOREACH_MOD(OnUserDisconnect, (lu)); lu->eh.Close(); } @@ -226,7 +226,7 @@ void UserManager::QuitUser(User *user, const std::string &quitreason, const char if (!user->quietquit) { ServerInstance->SNO->WriteToSnoMask('q',"Client exiting: %s (%s) [%s]", - user->GetFullRealHost().c_str(), user->GetIPString(), oper_reason.c_str()); + user->GetFullRealHost().c_str(), user->GetIPString().c_str(), oper_reason.c_str()); } } else @@ -234,10 +234,9 @@ void UserManager::QuitUser(User *user, const std::string &quitreason, const char if ((!ServerInstance->SilentULine(user->server)) && (!user->quietquit)) { ServerInstance->SNO->WriteToSnoMask('Q',"Client exiting on server %s: %s (%s) [%s]", - user->server.c_str(), user->GetFullRealHost().c_str(), user->GetIPString(), oper_reason.c_str()); + user->server.c_str(), user->GetFullRealHost().c_str(), user->GetIPString().c_str(), oper_reason.c_str()); } } - user->AddToWhoWas(); } user_hash::iterator iter = this->clientlist->find(user->nick); @@ -245,12 +244,11 @@ void UserManager::QuitUser(User *user, const std::string &quitreason, const char if (iter != this->clientlist->end()) this->clientlist->erase(iter); else - ServerInstance->Logs->Log("USERS", DEFAULT, "ERROR: Nick not found in clientlist, cannot remove: " + user->nick); + ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Nick not found in clientlist, cannot remove: " + user->nick); ServerInstance->Users->uuidlist->erase(user->uuid); } - void UserManager::AddLocalClone(User *user) { local_clones[user->GetCIDRMask()]++; @@ -305,94 +303,37 @@ unsigned long UserManager::LocalCloneCount(User *user) return 0; } -/* this function counts all users connected, wether they are registered or NOT. */ -unsigned int UserManager::UserCount() -{ - /* - * XXX: Todo: - * As part of this restructuring, move clientlist/etc fields into usermanager. - * -- w00t - */ - return this->clientlist->size(); -} - -/* this counts only registered users, so that the percentages in /MAP don't mess up */ -unsigned int UserManager::RegisteredUserCount() -{ - return this->clientlist->size() - this->UnregisteredUserCount(); -} - -/* return how many users are opered */ -unsigned int UserManager::OperCount() -{ - return this->all_opers.size(); -} - -/* return how many users are unregistered */ -unsigned int UserManager::UnregisteredUserCount() -{ - return this->unregistered_count; -} - -/* return how many local registered users there are */ -unsigned int UserManager::LocalUserCount() -{ - /* Doesnt count unregistered clients */ - return (this->local_count - this->UnregisteredUserCount()); -} - void UserManager::ServerNoticeAll(const char* text, ...) { - if (!text) - return; - - char textbuffer[MAXBUF]; - char formatbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - snprintf(formatbuffer,MAXBUF,"NOTICE $%s :%s", ServerInstance->Config->ServerName.c_str(), textbuffer); + std::string message; + VAFORMAT(message, text, text); + message = "NOTICE $" + ServerInstance->Config->ServerName + " :" + message; for (LocalUserList::const_iterator i = local_users.begin(); i != local_users.end(); i++) { User* t = *i; - t->WriteServ(std::string(formatbuffer)); + t->WriteServ(message); } } -void UserManager::ServerPrivmsgAll(const char* text, ...) +void UserManager::GarbageCollect() { - if (!text) - return; - - char textbuffer[MAXBUF]; - char formatbuffer[MAXBUF]; - va_list argsPtr; - va_start (argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - snprintf(formatbuffer,MAXBUF,"PRIVMSG $%s :%s", ServerInstance->Config->ServerName.c_str(), textbuffer); - - for (LocalUserList::const_iterator i = local_users.begin(); i != local_users.end(); i++) + // Reset the already_sent IDs so we don't wrap it around and drop a message + LocalUser::already_sent_id = 0; + for (LocalUserList::const_iterator i = this->local_users.begin(); i != this->local_users.end(); i++) { - User* t = *i; - t->WriteServ(std::string(formatbuffer)); + (**i).already_sent = 0; + (**i).RemoveExpiredInvites(); } } - -/* return how many users have a given mode e.g. 'a' */ -int UserManager::ModeCount(const char mode) +/* this returns true when all modules are satisfied that the user should be allowed onto the irc server + * (until this returns true, a user will block in the waiting state, waiting to connect up to the + * registration timeout maximum seconds) + */ +bool UserManager::AllModulesReportReady(LocalUser* user) { - int c = 0; - for(user_hash::iterator i = clientlist->begin(); i != clientlist->end(); ++i) - { - User* u = i->second; - if (u->modes[mode-65]) - c++; - } - return c; + ModResult res; + FIRST_MOD_RESULT(OnCheckReady, res, (user)); + return (res == MOD_RES_PASSTHRU); } diff --git a/src/userprocess.cpp b/src/userprocess.cpp index 9cc2e7df7..fe55fb3f7 100644 --- a/src/userprocess.cpp +++ b/src/userprocess.cpp @@ -21,46 +21,24 @@ */ -/* $Core */ - #include "inspircd.h" #include "xline.h" #include "socketengine.h" #include "command_parse.h" -void FloodQuitUserHandler::Call(User* current) -{ - ServerInstance->Logs->Log("USERS",DEFAULT,"Excess flood from: %s@%s", current->ident.c_str(), current->host.c_str()); - ServerInstance->SNO->WriteToSnoMask('f',"Excess flood from: %s%s%s@%s", - current->registered == REG_ALL ? current->nick.c_str() : "", - current->registered == REG_ALL ? "!" : "", current->ident.c_str(), current->host.c_str()); - ServerInstance->Users->QuitUser(current, "Excess flood"); - - if (current->registered != REG_ALL) - { - ZLine* zl = new ZLine(ServerInstance->Time(), 0, ServerInstance->Config->ServerName, "Flood from unregistered connection", current->GetIPString()); - if (ServerInstance->XLines->AddLine(zl,NULL)) - ServerInstance->XLines->ApplyLines(); - else - delete zl; - } -} - /** * This function is called once a second from the mainloop. * It is intended to do background checking on all the user structs, e.g. * stuff like ping checks, registration timeouts, etc. */ -void InspIRCd::DoBackgroundUserStuff() +void UserManager::DoBackgroundUserStuff() { /* * loop over all local users.. */ - LocalUserList::reverse_iterator count2 = this->Users->local_users.rbegin(); - while (count2 != this->Users->local_users.rend()) + for (LocalUserList::iterator i = local_users.begin(); i != local_users.end(); ++i) { - LocalUser *curr = *count2; - count2++; + LocalUser* curr = *i; if (curr->quitting) continue; @@ -78,27 +56,24 @@ void InspIRCd::DoBackgroundUserStuff() switch (curr->registered) { case REG_ALL: - if (Time() > curr->nping) + if (ServerInstance->Time() > curr->nping) { // This user didn't answer the last ping, remove them if (!curr->lastping) { - time_t time = this->Time() - (curr->nping - curr->MyClass->GetPingTime()); - char message[MAXBUF]; - snprintf(message, MAXBUF, "Ping timeout: %ld second%s", (long)time, time > 1 ? "s" : ""); - curr->lastping = 1; - curr->nping = Time() + curr->MyClass->GetPingTime(); - this->Users->QuitUser(curr, message); + time_t time = ServerInstance->Time() - (curr->nping - curr->MyClass->GetPingTime()); + const std::string message = "Ping timeout: " + ConvToStr(time) + (time == 1 ? " seconds" : " second"); + this->QuitUser(curr, message); continue; } - curr->Write("PING :%s",this->Config->ServerName.c_str()); + curr->Write("PING :" + ServerInstance->Config->ServerName); curr->lastping = 0; - curr->nping = Time() +curr->MyClass->GetPingTime(); + curr->nping = ServerInstance->Time() + curr->MyClass->GetPingTime(); } break; case REG_NICKUSER: - if (AllModulesReportReady(curr) && curr->dns_done) + if (AllModulesReportReady(curr)) { /* User has sent NICK/USER, modules are okay, DNS finished. */ curr->FullConnect(); @@ -107,15 +82,14 @@ void InspIRCd::DoBackgroundUserStuff() break; } - if (curr->registered != REG_ALL && (Time() > (curr->age + curr->MyClass->GetRegTimeout()))) + if (curr->registered != REG_ALL && (ServerInstance->Time() > (curr->age + curr->MyClass->GetRegTimeout()))) { /* * registration timeout -- didnt send USER/NICK/HOST * in the time specified in their connection class. */ - this->Users->QuitUser(curr, "Registration timeout"); + this->QuitUser(curr, "Registration timeout"); continue; } } } - diff --git a/src/users.cpp b/src/users.cpp index 18a356ef8..0383aaaa4 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -28,108 +28,9 @@ #include "socketengine.h" #include "xline.h" #include "bancache.h" -#include "commands/cmd_whowas.h" already_sent_t LocalUser::already_sent_id = 0; -std::string User::ProcessNoticeMasks(const char *sm) -{ - bool adding = true, oldadding = false; - const char *c = sm; - std::string output; - - while (c && *c) - { - switch (*c) - { - case '+': - adding = true; - break; - case '-': - adding = false; - break; - case '*': - for (unsigned char d = 'a'; d <= 'z'; d++) - { - if (!ServerInstance->SNO->masks[d - 'a'].Description.empty()) - { - if ((!IsNoticeMaskSet(d) && adding) || (IsNoticeMaskSet(d) && !adding)) - { - if ((oldadding != adding) || (!output.length())) - output += (adding ? '+' : '-'); - - this->SetNoticeMask(d, adding); - - output += d; - } - oldadding = adding; - char u = toupper(d); - if ((!IsNoticeMaskSet(u) && adding) || (IsNoticeMaskSet(u) && !adding)) - { - if ((oldadding != adding) || (!output.length())) - output += (adding ? '+' : '-'); - - this->SetNoticeMask(u, adding); - - output += u; - } - oldadding = adding; - } - } - break; - default: - if (isalpha(*c)) - { - if ((!IsNoticeMaskSet(*c) && adding) || (IsNoticeMaskSet(*c) && !adding)) - { - if ((oldadding != adding) || (!output.length())) - output += (adding ? '+' : '-'); - - this->SetNoticeMask(*c, adding); - - output += *c; - oldadding = adding; - } - } - else - this->WriteNumeric(ERR_UNKNOWNSNOMASK, "%s %c :is unknown snomask char to me", this->nick.c_str(), *c); - - break; - } - - c++; - } - - std::string s = this->FormatNoticeMasks(); - if (s.length() == 0) - { - this->modes[UM_SNOMASK] = false; - } - - return output; -} - -void LocalUser::StartDNSLookup() -{ - try - { - bool cached = false; - const char* sip = this->GetIPString(); - UserResolver *res_reverse; - - QueryType resolvtype = this->client_sa.sa.sa_family == AF_INET6 ? DNS_QUERY_PTR6 : DNS_QUERY_PTR4; - res_reverse = new UserResolver(this, sip, resolvtype, cached); - - ServerInstance->AddResolver(res_reverse, cached); - } - catch (CoreException& e) - { - ServerInstance->Logs->Log("USERS", DEBUG,"Error in resolver: %s",e.GetReason()); - dns_done = true; - ServerInstance->stats->statsDnsBad++; - } -} - bool User::IsNoticeMaskSet(unsigned char sm) { if (!isalpha(sm)) @@ -137,28 +38,6 @@ bool User::IsNoticeMaskSet(unsigned char sm) return (snomasks[sm-65]); } -void User::SetNoticeMask(unsigned char sm, bool value) -{ - if (!isalpha(sm)) - return; - snomasks[sm-65] = value; -} - -const char* User::FormatNoticeMasks() -{ - static char data[MAXBUF]; - int offset = 0; - - for (int n = 0; n < 64; n++) - { - if (snomasks[n]) - data[offset++] = n+65; - } - - data[offset] = 0; - return data; -} - bool User::IsModeSet(unsigned char m) { if (!isalpha(m)) @@ -166,24 +45,17 @@ bool User::IsModeSet(unsigned char m) return (modes[m-65]); } -void User::SetMode(unsigned char m, bool value) -{ - if (!isalpha(m)) - return; - modes[m-65] = value; -} - const char* User::FormatModes(bool showparameters) { - static char data[MAXBUF]; + static std::string data; std::string params; - int offset = 0; + data.clear(); for (unsigned char n = 0; n < 64; n++) { if (modes[n]) { - data[offset++] = n + 65; + data.push_back(n + 65); ModeHandler* mh = ServerInstance->Modes->FindMode(n + 65, MODETYPE_USER); if (showparameters && mh && mh->GetNumParams(true)) { @@ -193,36 +65,33 @@ const char* User::FormatModes(bool showparameters) } } } - data[offset] = 0; - strlcat(data, params.c_str(), MAXBUF); - return data; + data += params; + return data.c_str(); } User::User(const std::string &uid, const std::string& sid, int type) : uuid(uid), server(sid), usertype(type) { age = ServerInstance->Time(); - signon = idle_lastmsg = 0; + signon = 0; registered = 0; - quietquit = quitting = exempt = dns_done = false; - quitting_sendq = false; + quietquit = quitting = false; client_sa.sa.sa_family = AF_UNSPEC; - ServerInstance->Logs->Log("USERS", DEBUG, "New UUID for user: %s", uuid.c_str()); + ServerInstance->Logs->Log("USERS", LOG_DEBUG, "New UUID for user: %s", uuid.c_str()); - user_hash::iterator finduuid = ServerInstance->Users->uuidlist->find(uuid); - if (finduuid == ServerInstance->Users->uuidlist->end()) - (*ServerInstance->Users->uuidlist)[uuid] = this; - else + if (!ServerInstance->Users->uuidlist->insert(std::make_pair(uuid, this)).second) throw CoreException("Duplicate UUID "+std::string(uuid)+" in User constructor"); } LocalUser::LocalUser(int myfd, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* servaddr) - : User(ServerInstance->GetUID(), ServerInstance->Config->ServerName, USERTYPE_LOCAL), eh(this), + : User(ServerInstance->UIDGen.GetUID(), ServerInstance->Config->ServerName, USERTYPE_LOCAL), eh(this), localuseriter(ServerInstance->Users->local_users.end()), bytes_in(0), bytes_out(0), cmds_in(0), cmds_out(0), nping(0), CommandFloodPenalty(0), already_sent(0) { + exempt = quitting_sendq = false; + idle_lastmsg = 0; ident = "unknown"; lastping = 0; eh.SetFd(myfd); @@ -234,7 +103,7 @@ LocalUser::LocalUser(int myfd, irc::sockets::sockaddrs* client, irc::sockets::so User::~User() { if (ServerInstance->Users->uuidlist->find(uuid) != ServerInstance->Users->uuidlist->end()) - ServerInstance->Logs->Log("USERS", DEFAULT, "User destructor for %s called without cull", uuid.c_str()); + ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "User destructor for %s called without cull", uuid.c_str()); } const std::string& User::MakeHost() @@ -242,18 +111,8 @@ const std::string& User::MakeHost() if (!this->cached_makehost.empty()) return this->cached_makehost; - char nhost[MAXBUF]; - /* This is much faster than snprintf */ - char* t = nhost; - for(const char* n = ident.c_str(); *n; n++) - *t++ = *n; - *t++ = '@'; - for(const char* n = host.c_str(); *n; n++) - *t++ = *n; - *t = 0; - - this->cached_makehost.assign(nhost); - + // XXX: Is there really a need to cache this? + this->cached_makehost = ident + "@" + host; return this->cached_makehost; } @@ -262,18 +121,8 @@ const std::string& User::MakeHostIP() if (!this->cached_hostip.empty()) return this->cached_hostip; - char ihost[MAXBUF]; - /* This is much faster than snprintf */ - char* t = ihost; - for(const char* n = ident.c_str(); *n; n++) - *t++ = *n; - *t++ = '@'; - for(const char* n = this->GetIPString(); *n; n++) - *t++ = *n; - *t = 0; - - this->cached_hostip = ihost; - + // XXX: Is there really a need to cache this? + this->cached_hostip = ident + "@" + this->GetIPString(); return this->cached_hostip; } @@ -282,91 +131,37 @@ const std::string& User::GetFullHost() if (!this->cached_fullhost.empty()) return this->cached_fullhost; - char result[MAXBUF]; - char* t = result; - for(const char* n = nick.c_str(); *n; n++) - *t++ = *n; - *t++ = '!'; - for(const char* n = ident.c_str(); *n; n++) - *t++ = *n; - *t++ = '@'; - for(const char* n = dhost.c_str(); *n; n++) - *t++ = *n; - *t = 0; - - this->cached_fullhost = result; - + // XXX: Is there really a need to cache this? + this->cached_fullhost = nick + "!" + ident + "@" + dhost; return this->cached_fullhost; } -char* User::MakeWildHost() -{ - static char nresult[MAXBUF]; - char* t = nresult; - *t++ = '*'; *t++ = '!'; - *t++ = '*'; *t++ = '@'; - for(const char* n = dhost.c_str(); *n; n++) - *t++ = *n; - *t = 0; - return nresult; -} - const std::string& User::GetFullRealHost() { if (!this->cached_fullrealhost.empty()) return this->cached_fullrealhost; - char fresult[MAXBUF]; - char* t = fresult; - for(const char* n = nick.c_str(); *n; n++) - *t++ = *n; - *t++ = '!'; - for(const char* n = ident.c_str(); *n; n++) - *t++ = *n; - *t++ = '@'; - for(const char* n = host.c_str(); *n; n++) - *t++ = *n; - *t = 0; - - this->cached_fullrealhost = fresult; - + // XXX: Is there really a need to cache this? + this->cached_fullrealhost = nick + "!" + ident + "@" + host; return this->cached_fullrealhost; } -bool LocalUser::IsInvited(const irc::string &channel) -{ - Channel* chan = ServerInstance->FindChan(channel.c_str()); - if (!chan) - return false; - - return (Invitation::Find(chan, this) != NULL); -} - InviteList& LocalUser::GetInviteList() { RemoveExpiredInvites(); return invites; } -void LocalUser::InviteTo(const irc::string &channel, time_t invtimeout) +bool LocalUser::RemoveInvite(Channel* chan) { - Channel* chan = ServerInstance->FindChan(channel.c_str()); - if (chan) - Invitation::Create(chan, this, invtimeout); -} - -void LocalUser::RemoveInvite(const irc::string &channel) -{ - Channel* chan = ServerInstance->FindChan(channel.c_str()); - if (chan) + Invitation* inv = Invitation::Find(chan, this); + if (inv) { - Invitation* inv = Invitation::Find(chan, this); - if (inv) - { - inv->cull(); - delete inv; - } + inv->cull(); + delete inv; + return true; } + return false; } void LocalUser::RemoveExpiredInvites() @@ -381,7 +176,7 @@ bool User::HasModePermission(unsigned char, ModeType) bool LocalUser::HasModePermission(unsigned char mode, ModeType type) { - if (!IS_OPER(this)) + if (!this->IsOper()) return false; if (mode < 'A' || mode > ('A' + 64)) return false; @@ -404,7 +199,7 @@ bool User::HasPermission(const std::string&) bool LocalUser::HasPermission(const std::string &command) { // are they even an oper at all? - if (!IS_OPER(this)) + if (!this->IsOper()) { return false; } @@ -424,10 +219,10 @@ bool User::HasPrivPermission(const std::string &privstr, bool noisy) bool LocalUser::HasPrivPermission(const std::string &privstr, bool noisy) { - if (!IS_OPER(this)) + if (!this->IsOper()) { if (noisy) - this->WriteServ("NOTICE %s :You are not an oper", this->nick.c_str()); + this->WriteNotice("You are not an oper"); return false; } @@ -441,7 +236,8 @@ bool LocalUser::HasPrivPermission(const std::string &privstr, bool noisy) } if (noisy) - this->WriteServ("NOTICE %s :Oper type %s does not have access to priv %s", this->nick.c_str(), oper->NameStr(), privstr.c_str()); + this->WriteNotice("Oper type " + oper->name + " does not have access to priv " + privstr); + return false; } @@ -467,7 +263,7 @@ void UserIOHandler::OnDataReady() while (user->CommandFloodPenalty < penaltymax && getSendQSize() < sendqmax) { std::string line; - line.reserve(MAXBUF); + line.reserve(ServerInstance->Config->Limits.MaxLine); std::string::size_type qpos = 0; while (qpos < recvq.length()) { @@ -482,7 +278,7 @@ void UserIOHandler::OnDataReady() case '\n': goto eol_found; } - if (line.length() < MAXBUF - 2) + if (line.length() < ServerInstance->Config->Limits.MaxLine - 2) line.push_back(c); } // if we got here, the recvq ran out before we found a newline @@ -550,7 +346,7 @@ CullResult LocalUser::cull() ServerInstance->Users->local_users.erase(localuseriter); } else - ServerInstance->Logs->Log("USERS", DEFAULT, "ERROR: LocalUserIter does not point to a valid entry for " + this->nick); + ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: LocalUserIter does not point to a valid entry for " + this->nick); ClearInvites(); eh.cull(); @@ -561,20 +357,21 @@ CullResult FakeUser::cull() { // Fake users don't quit, they just get culled. quitting = true; - ServerInstance->Users->clientlist->erase(nick); + // Fake users are not inserted into UserManager::clientlist, they're only in the uuidlist ServerInstance->Users->uuidlist->erase(uuid); return User::cull(); } void User::Oper(OperInfo* info) { - if (this->IsModeSet('o')) + ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER); + if (this->IsModeSet(opermh)) this->UnOper(); - this->modes[UM_OPERATOR] = 1; + this->SetMode(opermh, true); this->oper = info; this->WriteServ("MODE %s :+o", this->nick.c_str()); - FOREACH_MOD(I_OnOper, OnOper(this, info->name)); + FOREACH_MOD(OnOper, (this, info->name)); std::string opername; if (info->oper_block) @@ -592,17 +389,17 @@ void User::Oper(OperInfo* info) } ServerInstance->SNO->WriteToSnoMask('o',"%s (%s@%s) is now an IRC operator of type %s (using oper '%s')", - nick.c_str(), ident.c_str(), host.c_str(), oper->NameStr(), opername.c_str()); - this->WriteNumeric(381, "%s :You are now %s %s", nick.c_str(), strchr("aeiouAEIOU", oper->name[0]) ? "an" : "a", oper->NameStr()); + nick.c_str(), ident.c_str(), host.c_str(), oper->name.c_str(), opername.c_str()); + this->WriteNumeric(381, "%s :You are now %s %s", nick.c_str(), strchr("aeiouAEIOU", oper->name[0]) ? "an" : "a", oper->name.c_str()); - ServerInstance->Logs->Log("OPER", DEFAULT, "%s opered as type: %s", GetFullRealHost().c_str(), oper->NameStr()); + ServerInstance->Logs->Log("OPER", LOG_DEFAULT, "%s opered as type: %s", GetFullRealHost().c_str(), oper->name.c_str()); ServerInstance->Users->all_opers.push_back(this); // Expand permissions from config for faster lookup if (IS_LOCAL(this)) oper->init(); - FOREACH_MOD(I_OnPostOper,OnPostOper(this, oper->name, opername)); + FOREACH_MOD(OnPostOper, (this, oper->name, opername)); } void OperInfo::init() @@ -660,7 +457,7 @@ void OperInfo::init() void User::UnOper() { - if (!IS_OPER(this)) + if (!this->IsOper()) return; /* @@ -686,30 +483,19 @@ void User::UnOper() parameters.push_back(this->nick); parameters.push_back(moderemove); - ServerInstance->Parser->CallHandler("MODE", parameters, this); + ServerInstance->Modes->Process(parameters, this); /* remove the user from the oper list. Will remove multiple entries as a safeguard against bug #404 */ ServerInstance->Users->all_opers.remove(this); - this->modes[UM_OPERATOR] = 0; -} - -/* adds or updates an entry in the whowas list */ -void User::AddToWhoWas() -{ - Module* whowas = ServerInstance->Modules->Find("cmd_whowas.so"); - if (whowas) - { - WhowasRequest req(NULL, whowas, WhowasRequest::WHOWAS_ADD); - req.user = this; - req.Send(); - } + ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER); + this->SetMode(opermh, false); } /* * Check class restrictions */ -void LocalUser::CheckClass() +void LocalUser::CheckClass(bool clone_count) { ConnectClass* a = this->MyClass; @@ -723,25 +509,28 @@ void LocalUser::CheckClass() ServerInstance->Users->QuitUser(this, a->config->getString("reason", "Unauthorised connection")); return; } - else if ((a->GetMaxLocal()) && (ServerInstance->Users->LocalCloneCount(this) > a->GetMaxLocal())) - { - ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (local)"); - if (a->maxconnwarn) - ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a->GetMaxLocal(), this->GetIPString()); - return; - } - else if ((a->GetMaxGlobal()) && (ServerInstance->Users->GlobalCloneCount(this) > a->GetMaxGlobal())) + else if (clone_count) { - ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (global)"); - if (a->maxconnwarn) - ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s", a->GetMaxGlobal(), this->GetIPString()); - return; + if ((a->GetMaxLocal()) && (ServerInstance->Users->LocalCloneCount(this) > a->GetMaxLocal())) + { + ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (local)"); + if (a->maxconnwarn) + ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a->GetMaxLocal(), this->GetIPString().c_str()); + return; + } + else if ((a->GetMaxGlobal()) && (ServerInstance->Users->GlobalCloneCount(this) > a->GetMaxGlobal())) + { + ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (global)"); + if (a->maxconnwarn) + ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s", a->GetMaxGlobal(), this->GetIPString().c_str()); + return; + } } this->nping = ServerInstance->Time() + a->GetPingTime() + ServerInstance->Config->dns_timeout; } -bool User::CheckLines(bool doZline) +bool LocalUser::CheckLines(bool doZline) { const char* check[] = { "G" , "K", (doZline) ? "Z" : NULL, NULL }; @@ -781,18 +570,14 @@ void LocalUser::FullConnect() if (quitting) return; - if (ServerInstance->Config->WelcomeNotice) - this->WriteServ("NOTICE Auth :Welcome to \002%s\002!",ServerInstance->Config->Network.c_str()); this->WriteNumeric(RPL_WELCOME, "%s :Welcome to the %s IRC Network %s",this->nick.c_str(), ServerInstance->Config->Network.c_str(), GetFullRealHost().c_str()); this->WriteNumeric(RPL_YOURHOSTIS, "%s :Your host is %s, running version %s",this->nick.c_str(),ServerInstance->Config->ServerName.c_str(),BRANCH); this->WriteNumeric(RPL_SERVERCREATED, "%s :This server was created %s %s", this->nick.c_str(), __TIME__, __DATE__); - std::string umlist = ServerInstance->Modes->UserModeList(); - std::string cmlist = ServerInstance->Modes->ChannelModeList(); - std::string pmlist = ServerInstance->Modes->ParaModeList(); - this->WriteNumeric(RPL_SERVERVERSION, "%s %s %s %s %s %s", this->nick.c_str(), ServerInstance->Config->ServerName.c_str(), BRANCH, umlist.c_str(), cmlist.c_str(), pmlist.c_str()); + const std::string& modelist = ServerInstance->Modes->GetModeListFor004Numeric(); + this->WriteNumeric(RPL_SERVERVERSION, "%s %s %s %s", this->nick.c_str(), ServerInstance->Config->ServerName.c_str(), BRANCH, modelist.c_str()); - ServerInstance->Config->Send005(this); + ServerInstance->ISupport.SendTo(this); this->WriteNumeric(RPL_YOURUUID, "%s %s :your unique ID", this->nick.c_str(), this->uuid.c_str()); /* Now registered */ @@ -801,14 +586,14 @@ void LocalUser::FullConnect() /* Trigger MOTD and LUSERS output, give modules a chance too */ ModResult MOD_RESULT; - std::string command("MOTD"); + std::string command("LUSERS"); std::vector<std::string> parameters; FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, this, true, command)); if (!MOD_RESULT) ServerInstance->Parser->CallHandler(command, parameters, this); MOD_RESULT = MOD_RES_PASSTHRU; - command = "LUSERS"; + command = "MOTD"; FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, this, true, command)); if (!MOD_RESULT) ServerInstance->Parser->CallHandler(command, parameters, this); @@ -820,15 +605,15 @@ void LocalUser::FullConnect() * We don't set REG_ALL until triggering OnUserConnect, so some module events don't spew out stuff * for a user that doesn't exist yet. */ - FOREACH_MOD(I_OnUserConnect,OnUserConnect(this)); + FOREACH_MOD(OnUserConnect, (this)); this->registered = REG_ALL; - FOREACH_MOD(I_OnPostConnect,OnPostConnect(this)); + FOREACH_MOD(OnPostConnect, (this)); ServerInstance->SNO->WriteToSnoMask('c',"Client connecting on port %d (class %s): %s (%s) [%s]", - this->GetServerPort(), this->MyClass->name.c_str(), GetFullRealHost().c_str(), this->GetIPString(), this->fullname.c_str()); - ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCache: Adding NEGATIVE hit for %s", this->GetIPString()); + this->GetServerPort(), this->MyClass->name.c_str(), GetFullRealHost().c_str(), this->GetIPString().c_str(), this->fullname.c_str()); + ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Adding NEGATIVE hit for " + this->GetIPString()); ServerInstance->BanCache->AddHit(this->GetIPString(), "", ""); // reset the flood penalty (which could have been raised due to things like auto +x) CommandFloodPenalty = 0; @@ -847,21 +632,20 @@ bool User::ChangeNick(const std::string& newnick, bool force) { if (quitting) { - ServerInstance->Logs->Log("USERS", DEFAULT, "ERROR: Attempted to change nick of a quitting user: " + this->nick); + ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Attempted to change nick of a quitting user: " + this->nick); return false; } - ModResult MOD_RESULT; - - if (force) - ServerInstance->NICKForced.set(this, 1); - FIRST_MOD_RESULT(OnUserPreNick, MOD_RESULT, (this, newnick)); - ServerInstance->NICKForced.set(this, 0); - - if (MOD_RESULT == MOD_RES_DENY) + if (!force) { - ServerInstance->stats->statsCollisions++; - return false; + ModResult MOD_RESULT; + FIRST_MOD_RESULT(OnUserPreNick, MOD_RESULT, (this, newnick)); + + if (MOD_RESULT == MOD_RES_DENY) + { + ServerInstance->stats->statsCollisions++; + return false; + } } if (assign(newnick) == assign(nick)) @@ -953,7 +737,7 @@ bool User::ChangeNick(const std::string& newnick, bool force) (*(ServerInstance->Users->clientlist))[newnick] = this; if (registered == REG_ALL) - FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(this,oldnick)); + FOREACH_MOD(OnUserPostNick, (this,oldnick)); return true; } @@ -970,18 +754,18 @@ int LocalUser::GetServerPort() return 0; } -const char* User::GetIPString() +const std::string& User::GetIPString() { int port; if (cachedip.empty()) { irc::sockets::satoap(client_sa, cachedip, port); /* IP addresses starting with a : on irc are a Bad Thing (tm) */ - if (cachedip.c_str()[0] == ':') + if (cachedip[0] == ':') cachedip.insert(0,1,'0'); } - return cachedip.c_str(); + return cachedip; } irc::sockets::cidr_mask User::GetCIDRMask() @@ -1032,7 +816,7 @@ void LocalUser::SetClientIP(const irc::sockets::sockaddrs& sa, bool recheck_elin if (recheck_eline) this->exempt = (ServerInstance->XLines->MatchesLine("E", this) != NULL); - FOREACH_MOD(I_OnSetUserIP,OnSetUserIP(this)); + FOREACH_MOD(OnSetUserIP, (this)); } } @@ -1051,15 +835,15 @@ void LocalUser::Write(const std::string& text) if (!ServerInstance->SE->BoundsCheckFd(&eh)) return; - if (text.length() > MAXBUF - 2) + if (text.length() > ServerInstance->Config->Limits.MaxLine - 2) { // this should happen rarely or never. Crop the string at 512 and try again. - std::string try_again = text.substr(0, MAXBUF - 2); + std::string try_again = text.substr(0, ServerInstance->Config->Limits.MaxLine - 2); Write(try_again); return; } - ServerInstance->Logs->Log("USEROUTPUT", RAWIO, "C[%s] O %s", uuid.c_str(), text.c_str()); + ServerInstance->Logs->Log("USEROUTPUT", LOG_RAWIO, "C[%s] O %s", uuid.c_str(), text.c_str()); eh.AddWriteBuf(text); eh.AddWriteBuf(wide_newline); @@ -1073,14 +857,9 @@ void LocalUser::Write(const std::string& text) */ void LocalUser::Write(const char *text, ...) { - va_list argsPtr; - char textbuffer[MAXBUF]; - - va_start(argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - this->Write(std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + this->Write(textbuffer); } void User::WriteServ(const std::string& text) @@ -1093,50 +872,41 @@ void User::WriteServ(const std::string& text) */ void User::WriteServ(const char* text, ...) { - va_list argsPtr; - char textbuffer[MAXBUF]; - - va_start(argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - this->WriteServ(std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + this->WriteServ(textbuffer); } +void User::WriteNotice(const std::string& text) +{ + this->WriteServ("NOTICE " + (this->registered == REG_ALL ? this->nick : "*") + " :" + text); +} void User::WriteNumeric(unsigned int numeric, const char* text, ...) { - va_list argsPtr; - char textbuffer[MAXBUF]; - - va_start(argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - this->WriteNumeric(numeric, std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + this->WriteNumeric(numeric, textbuffer); } void User::WriteNumeric(unsigned int numeric, const std::string &text) { - char textbuffer[MAXBUF]; ModResult MOD_RESULT; FIRST_MOD_RESULT(OnNumeric, MOD_RESULT, (this, numeric, text)); if (MOD_RESULT == MOD_RES_DENY) return; - - snprintf(textbuffer,MAXBUF,":%s %03u %s",ServerInstance->Config->ServerName.c_str(), numeric, text.c_str()); - this->Write(std::string(textbuffer)); + + const std::string message = InspIRCd::Format(":%s %03u %s", ServerInstance->Config->ServerName.c_str(), + numeric, text.c_str()); + this->Write(message); } void User::WriteFrom(User *user, const std::string &text) { - char tb[MAXBUF]; - - snprintf(tb,MAXBUF,":%s %s",user->GetFullHost().c_str(),text.c_str()); - - this->Write(std::string(tb)); + const std::string message = ":" + user->GetFullHost() + " " + text; + this->Write(message); } @@ -1144,14 +914,9 @@ void User::WriteFrom(User *user, const std::string &text) void User::WriteFrom(User *user, const char* text, ...) { - va_list argsPtr; - char textbuffer[MAXBUF]; - - va_start(argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - this->WriteFrom(user, std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + this->WriteFrom(user, textbuffer); } @@ -1159,14 +924,9 @@ void User::WriteFrom(User *user, const char* text, ...) void User::WriteTo(User *dest, const char *data, ...) { - char textbuffer[MAXBUF]; - va_list argsPtr; - - va_start(argsPtr, data); - vsnprintf(textbuffer, MAXBUF, data, argsPtr); - va_end(argsPtr); - - this->WriteTo(dest, std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, data, data); + this->WriteTo(dest, textbuffer); } void User::WriteTo(User *dest, const std::string &data) @@ -1176,36 +936,24 @@ void User::WriteTo(User *dest, const std::string &data) void User::WriteCommon(const char* text, ...) { - char textbuffer[MAXBUF]; - va_list argsPtr; - if (this->registered != REG_ALL || quitting) return; - int len = snprintf(textbuffer,MAXBUF,":%s ",this->GetFullHost().c_str()); - - va_start(argsPtr, text); - vsnprintf(textbuffer + len, MAXBUF - len, text, argsPtr); - va_end(argsPtr); - - this->WriteCommonRaw(std::string(textbuffer), true); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + textbuffer = ":" + this->GetFullHost() + " " + textbuffer; + this->WriteCommonRaw(textbuffer, true); } void User::WriteCommonExcept(const char* text, ...) { - char textbuffer[MAXBUF]; - va_list argsPtr; - if (this->registered != REG_ALL || quitting) return; - int len = snprintf(textbuffer,MAXBUF,":%s ",this->GetFullHost().c_str()); - - va_start(argsPtr, text); - vsnprintf(textbuffer + len, MAXBUF - len, text, argsPtr); - va_end(argsPtr); - - this->WriteCommonRaw(std::string(textbuffer), false); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + textbuffer = ":" + this->GetFullHost() + " " + textbuffer; + this->WriteCommonRaw(textbuffer, false); } void User::WriteCommonRaw(const std::string &line, bool include_self) @@ -1220,7 +968,7 @@ void User::WriteCommonRaw(const std::string &line, bool include_self) exceptions[this] = include_self; - FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions)); + FOREACH_MOD(OnBuildNeighborList, (this, include_c, exceptions)); for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i) { @@ -1250,23 +998,18 @@ void User::WriteCommonRaw(const std::string &line, bool include_self) void User::WriteCommonQuit(const std::string &normal_text, const std::string &oper_text) { - char tb1[MAXBUF]; - char tb2[MAXBUF]; - if (this->registered != REG_ALL) return; already_sent_t uniq_id = ++LocalUser::already_sent_id; - snprintf(tb1,MAXBUF,":%s QUIT :%s",this->GetFullHost().c_str(),normal_text.c_str()); - snprintf(tb2,MAXBUF,":%s QUIT :%s",this->GetFullHost().c_str(),oper_text.c_str()); - std::string out1 = tb1; - std::string out2 = tb2; + const std::string normalMessage = ":" + this->GetFullHost() + " QUIT :" + normal_text; + const std::string operMessage = ":" + this->GetFullHost() + " QUIT :" + oper_text; UserChanList include_c(chans); std::map<User*,bool> exceptions; - FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions)); + FOREACH_MOD(OnBuildNeighborList, (this, include_c, exceptions)); for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i) { @@ -1275,7 +1018,7 @@ void User::WriteCommonQuit(const std::string &normal_text, const std::string &op { u->already_sent = uniq_id; if (i->second) - u->Write(IS_OPER(u) ? out2 : out1); + u->Write(u->IsOper() ? operMessage : normalMessage); } } for (UCListIter v = include_c.begin(); v != include_c.end(); ++v) @@ -1287,7 +1030,7 @@ void User::WriteCommonQuit(const std::string &normal_text, const std::string &op if (u && !u->quitting && (u->already_sent != uniq_id)) { u->already_sent = uniq_id; - u->Write(IS_OPER(u) ? out2 : out1); + u->Write(u->IsOper() ? operMessage : normalMessage); } } } @@ -1309,38 +1052,26 @@ void FakeUser::SendText(const std::string& line) void User::SendText(const char *text, ...) { - va_list argsPtr; - char line[MAXBUF]; - - va_start(argsPtr, text); - vsnprintf(line, MAXBUF, text, argsPtr); - va_end(argsPtr); - - SendText(std::string(line)); + std::string line; + VAFORMAT(line, text, text); + SendText(line); } -void User::SendText(const std::string &LinePrefix, std::stringstream &TextStream) +void User::SendText(const std::string& linePrefix, std::stringstream& textStream) { - char line[MAXBUF]; - int start_pos = LinePrefix.length(); - int pos = start_pos; - memcpy(line, LinePrefix.data(), pos); - std::string Word; - while (TextStream >> Word) + std::string line; + std::string word; + while (textStream >> word) { - int len = Word.length(); - if (pos + len + 12 > MAXBUF) + size_t lineLength = linePrefix.length() + line.length() + word.length() + 3; // "\s\n\r" + if (lineLength > ServerInstance->Config->Limits.MaxLine) { - line[pos] = '\0'; - SendText(std::string(line)); - pos = start_pos; + SendText(linePrefix + line); + line.clear(); } - line[pos] = ' '; - memcpy(line + pos + 1, Word.data(), len); - pos += len + 1; + line += " " + word; } - line[pos] = '\0'; - SendText(std::string(line)); + SendText(linePrefix + line); } /* return 0 or 1 depending if users u and u2 share one or more common channels @@ -1372,7 +1103,7 @@ bool User::SharesChannelWith(User *other) return false; } -bool User::ChangeName(const char* gecos) +bool User::ChangeName(const std::string& gecos) { if (!this->fullname.compare(gecos)) return true; @@ -1383,83 +1114,14 @@ bool User::ChangeName(const char* gecos) FIRST_MOD_RESULT(OnChangeLocalUserGECOS, MOD_RESULT, (IS_LOCAL(this),gecos)); if (MOD_RESULT == MOD_RES_DENY) return false; - FOREACH_MOD(I_OnChangeName,OnChangeName(this,gecos)); + FOREACH_MOD(OnChangeName, (this,gecos)); } this->fullname.assign(gecos, 0, ServerInstance->Config->Limits.MaxGecos); return true; } -void User::DoHostCycle(const std::string &quitline) -{ - char buffer[MAXBUF]; - - if (!ServerInstance->Config->CycleHosts) - return; - - already_sent_t silent_id = ++LocalUser::already_sent_id; - already_sent_t seen_id = ++LocalUser::already_sent_id; - - UserChanList include_c(chans); - std::map<User*,bool> exceptions; - - FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions)); - - for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i) - { - LocalUser* u = IS_LOCAL(i->first); - if (u && !u->quitting) - { - if (i->second) - { - u->already_sent = seen_id; - u->Write(quitline); - } - else - { - u->already_sent = silent_id; - } - } - } - for (UCListIter v = include_c.begin(); v != include_c.end(); ++v) - { - Channel* c = *v; - snprintf(buffer, MAXBUF, ":%s JOIN %s", GetFullHost().c_str(), c->name.c_str()); - std::string joinline(buffer); - Membership* memb = c->GetUser(this); - std::string modeline = memb->modes; - if (modeline.length() > 0) - { - for(unsigned int i=0; i < memb->modes.length(); i++) - modeline.append(" ").append(nick); - snprintf(buffer, MAXBUF, ":%s MODE %s +%s", - ServerInstance->Config->CycleHostsFromUser ? GetFullHost().c_str() : ServerInstance->Config->ServerName.c_str(), - c->name.c_str(), modeline.c_str()); - modeline = buffer; - } - - const UserMembList *ulist = c->GetUsers(); - for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++) - { - LocalUser* u = IS_LOCAL(i->first); - if (u == NULL || u == this) - continue; - if (u->already_sent == silent_id) - continue; - - if (u->already_sent != seen_id) - { - u->Write(quitline); - u->already_sent = seen_id; - } - u->Write(joinline); - if (modeline.length() > 0) - u->Write(modeline); - } - } -} - -bool User::ChangeDisplayedHost(const char* shost) +bool User::ChangeDisplayedHost(const std::string& shost) { if (dhost == shost) return true; @@ -1472,113 +1134,40 @@ bool User::ChangeDisplayedHost(const char* shost) return false; } - FOREACH_MOD(I_OnChangeHost, OnChangeHost(this,shost)); - - std::string quitstr = ":" + GetFullHost() + " QUIT :Changing host"; + FOREACH_MOD(OnChangeHost, (this,shost)); - /* Fix by Om: User::dhost is 65 long, this was truncating some long hosts */ this->dhost.assign(shost, 0, 64); - this->InvalidateCache(); - this->DoHostCycle(quitstr); - if (IS_LOCAL(this)) this->WriteNumeric(RPL_YOURDISPLAYEDHOST, "%s %s :is now your displayed host",this->nick.c_str(),this->dhost.c_str()); return true; } -bool User::ChangeIdent(const char* newident) +bool User::ChangeIdent(const std::string& newident) { if (this->ident == newident) return true; - FOREACH_MOD(I_OnChangeIdent, OnChangeIdent(this,newident)); - - std::string quitstr = ":" + GetFullHost() + " QUIT :Changing ident"; + FOREACH_MOD(OnChangeIdent, (this,newident)); this->ident.assign(newident, 0, ServerInstance->Config->Limits.IdentMax); - this->InvalidateCache(); - this->DoHostCycle(quitstr); - return true; } void User::SendAll(const char* command, const char* text, ...) { - char textbuffer[MAXBUF]; - char formatbuffer[MAXBUF]; - va_list argsPtr; - - va_start(argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - snprintf(formatbuffer,MAXBUF,":%s %s $* :%s", this->GetFullHost().c_str(), command, textbuffer); - std::string fmt = formatbuffer; + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + const std::string message = ":" + this->GetFullHost() + " " + command + " $* :" + textbuffer; for (LocalUserList::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); i++) { if ((*i)->registered == REG_ALL) - (*i)->Write(fmt); - } -} - - -std::string User::ChannelList(User* source, bool spy) -{ - std::string list; - - for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++) - { - Channel* c = *i; - /* If the target is the sender, neither +p nor +s is set, or - * the channel contains the user, it is not a spy channel - */ - if (spy != (source == this || !(c->IsModeSet('p') || c->IsModeSet('s')) || c->HasUser(source))) - list.append(c->GetPrefixChar(this)).append(c->name).append(" "); - } - - return list; -} - -void User::SplitChanList(User* dest, const std::string &cl) -{ - std::string line; - std::ostringstream prefix; - std::string::size_type start, pos, length; - - prefix << this->nick << " " << dest->nick << " :"; - line = prefix.str(); - int namelen = ServerInstance->Config->ServerName.length() + 6; - - for (start = 0; (pos = cl.find(' ', start)) != std::string::npos; start = pos+1) - { - length = (pos == std::string::npos) ? cl.length() : pos; - - if (line.length() + namelen + length - start > 510) - { - ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str()); - line = prefix.str(); - } - - if(pos == std::string::npos) - { - line.append(cl.substr(start, length - start)); - break; - } - else - { - line.append(cl.substr(start, length - start + 1)); - } - } - - if (line.length() != prefix.str().length()) - { - ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str()); + (*i)->Write(message); } } @@ -1593,7 +1182,7 @@ void LocalUser::SetClass(const std::string &explicit_name) { ConnectClass *found = NULL; - ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Setting connect class for UID %s", this->uuid.c_str()); + ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Setting connect class for UID %s", this->uuid.c_str()); if (!explicit_name.empty()) { @@ -1603,7 +1192,7 @@ void LocalUser::SetClass(const std::string &explicit_name) if (explicit_name == c->name) { - ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Explicitly set to %s", explicit_name.c_str()); + ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Explicitly set to %s", explicit_name.c_str()); found = c; } } @@ -1613,7 +1202,7 @@ void LocalUser::SetClass(const std::string &explicit_name) for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++) { ConnectClass* c = *i; - ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Checking %s", c->GetName().c_str()); + ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Checking %s", c->GetName().c_str()); ModResult MOD_RESULT; FIRST_MOD_RESULT(OnSetConnectClass, MOD_RESULT, (this,c)); @@ -1621,7 +1210,7 @@ void LocalUser::SetClass(const std::string &explicit_name) continue; if (MOD_RESULT == MOD_RES_ALLOW) { - ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Class forced by module to %s", c->GetName().c_str()); + ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Class forced by module to %s", c->GetName().c_str()); found = c; break; } @@ -1637,7 +1226,7 @@ void LocalUser::SetClass(const std::string &explicit_name) if (!InspIRCd::MatchCIDR(this->GetIPString(), c->GetHost(), NULL) && !InspIRCd::MatchCIDR(this->host, c->GetHost(), NULL)) { - ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "No host match (for %s)", c->GetHost().c_str()); + ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "No host match (for %s)", c->GetHost().c_str()); continue; } @@ -1647,7 +1236,7 @@ void LocalUser::SetClass(const std::string &explicit_name) */ if (c->limit && (c->GetReferenceCount() >= c->limit)) { - ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "OOPS: Connect class limit (%lu) hit, denying", c->limit); + ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "OOPS: Connect class limit (%lu) hit, denying", c->limit); continue; } @@ -1655,7 +1244,7 @@ void LocalUser::SetClass(const std::string &explicit_name) int port = c->config->getInt("port"); if (port) { - ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Requires port (%d)", port); + ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Requires port (%d)", port); /* and our port doesn't match, fail. */ if (this->GetServerPort() != port) @@ -1666,7 +1255,7 @@ void LocalUser::SetClass(const std::string &explicit_name) { if (ServerInstance->PassCompare(this, c->config->getString("password"), password, c->config->getString("hash"))) { - ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Bad password, skipping"); + ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Bad password, skipping"); continue; } } @@ -1686,21 +1275,6 @@ void LocalUser::SetClass(const std::string &explicit_name) } } -/* looks up a users password for their connection class (<ALLOW>/<DENY> tags) - * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves, - * then their ip will be taken as 'priority' anyway, so for example, - * <connect allow="127.0.0.1"> will match joe!bloggs@localhost - */ -ConnectClass* LocalUser::GetClass() -{ - return MyClass; -} - -ConnectClass* User::GetClass() -{ - return NULL; -} - void User::PurgeEmptyChannels() { // firstly decrement the count on each channel @@ -1730,7 +1304,8 @@ const std::string& FakeUser::GetFullRealHost() ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask) : config(tag), type(t), fakelag(true), name("unnamed"), registration_timeout(0), host(mask), pingtime(0), softsendqmax(0), hardsendqmax(0), recvqmax(0), - penaltythreshold(0), commandrate(0), maxlocal(0), maxglobal(0), maxconnwarn(true), maxchans(0), limit(0) + penaltythreshold(0), commandrate(0), maxlocal(0), maxglobal(0), maxconnwarn(true), maxchans(0), + limit(0), resolvehostnames(true) { } @@ -1740,7 +1315,7 @@ ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask, cons softsendqmax(parent.softsendqmax), hardsendqmax(parent.hardsendqmax), recvqmax(parent.recvqmax), penaltythreshold(parent.penaltythreshold), commandrate(parent.commandrate), maxlocal(parent.maxlocal), maxglobal(parent.maxglobal), maxconnwarn(parent.maxconnwarn), maxchans(parent.maxchans), - limit(parent.limit) + limit(parent.limit), resolvehostnames(parent.resolvehostnames) { } @@ -1763,4 +1338,5 @@ void ConnectClass::Update(const ConnectClass* src) maxconnwarn = src->maxconnwarn; maxchans = src->maxchans; limit = src->limit; + resolvehostnames = src->resolvehostnames; } diff --git a/src/version.sh b/src/version.sh index 99d0d81d6..d307082f4 100755 --- a/src/version.sh +++ b/src/version.sh @@ -1,2 +1,2 @@ #!/bin/sh -echo "InspIRCd-2.0.14" +echo "InspIRCd-2.2.0+pre" diff --git a/src/whois.cpp b/src/whois.cpp deleted file mode 100644 index bec9c7ea9..000000000 --- a/src/whois.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> - * - * This file is part of InspIRCd. InspIRCd 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, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "inspircd.h" - -void InspIRCd::DoWhois(User* user, User* dest,unsigned long signon, unsigned long idle, const char* nick) -{ - this->SendWhoisLine(user, dest, 311, "%s %s %s %s * :%s",user->nick.c_str(), dest->nick.c_str(), dest->ident.c_str(), dest->dhost.c_str(), dest->fullname.c_str()); - if (user == dest || user->HasPrivPermission("users/auspex")) - { - this->SendWhoisLine(user, dest, 378, "%s %s :is connecting from %s@%s %s", user->nick.c_str(), dest->nick.c_str(), dest->ident.c_str(), dest->host.c_str(), dest->GetIPString()); - } - - std::string cl = dest->ChannelList(user, false); - const ServerConfig::OperSpyWhoisState state = user->HasPrivPermission("users/auspex") ? ServerInstance->Config->OperSpyWhois : ServerConfig::SPYWHOIS_NONE; - - if (state == ServerConfig::SPYWHOIS_SINGLEMSG) - cl.append(dest->ChannelList(user, true)); - - user->SplitChanList(dest,cl); - - if (state == ServerConfig::SPYWHOIS_SPLITMSG) - { - std::string scl = dest->ChannelList(user, true); - if (scl.length()) - { - SendWhoisLine(user, dest, 336, "%s %s :is on private/secret channels:",user->nick.c_str(), dest->nick.c_str()); - user->SplitChanList(dest,scl); - } - } - if (user != dest && !this->Config->HideWhoisServer.empty() && !user->HasPrivPermission("servers/auspex")) - { - this->SendWhoisLine(user, dest, 312, "%s %s %s :%s",user->nick.c_str(), dest->nick.c_str(), this->Config->HideWhoisServer.c_str(), this->Config->Network.c_str()); - } - else - { - std::string serverdesc = GetServerDescription(dest->server); - this->SendWhoisLine(user, dest, 312, "%s %s %s :%s",user->nick.c_str(), dest->nick.c_str(), dest->server.c_str(), serverdesc.c_str()); - } - - if (IS_AWAY(dest)) - { - this->SendWhoisLine(user, dest, 301, "%s %s :%s",user->nick.c_str(), dest->nick.c_str(), dest->awaymsg.c_str()); - } - - if (IS_OPER(dest)) - { - if (this->Config->GenericOper) - this->SendWhoisLine(user, dest, 313, "%s %s :is an IRC operator",user->nick.c_str(), dest->nick.c_str()); - else - this->SendWhoisLine(user, dest, 313, "%s %s :is %s %s on %s",user->nick.c_str(), dest->nick.c_str(), (strchr("AEIOUaeiou",dest->oper->name[0]) ? "an" : "a"),dest->oper->NameStr(), this->Config->Network.c_str()); - } - - if (user == dest || user->HasPrivPermission("users/auspex")) - { - if (dest->IsModeSet('s') != 0) - { - this->SendWhoisLine(user, dest, 379, "%s %s :is using modes +%s +%s", user->nick.c_str(), dest->nick.c_str(), dest->FormatModes(), dest->FormatNoticeMasks()); - } - else - { - this->SendWhoisLine(user, dest, 379, "%s %s :is using modes +%s", user->nick.c_str(), dest->nick.c_str(), dest->FormatModes()); - } - } - - FOREACH_MOD(I_OnWhois,OnWhois(user,dest)); - - /* - * We only send these if we've been provided them. That is, if hidewhois is turned off, and user is local, or - * if remote whois is queried, too. This is to keep the user hidden, and also since you can't reliably tell remote time. -- w00t - */ - if ((idle) || (signon)) - { - this->SendWhoisLine(user, dest, 317, "%s %s %lu %lu :seconds idle, signon time",user->nick.c_str(), dest->nick.c_str(), idle, signon); - } - - this->SendWhoisLine(user, dest, 318, "%s %s :End of /WHOIS list.",user->nick.c_str(), dest->nick.c_str()); -} - - - diff --git a/src/wildcard.cpp b/src/wildcard.cpp index eb9151293..b62fd8a61 100644 --- a/src/wildcard.cpp +++ b/src/wildcard.cpp @@ -19,15 +19,14 @@ */ -/* $Core */ - #include "inspircd.h" #include "hashcomp.h" #include "inspstring.h" -static bool match_internal(const unsigned char *str, const unsigned char *mask, unsigned const char *map) +static bool MatchInternal(const unsigned char* str, const unsigned char* mask, unsigned const char* map) { - unsigned char *cp = NULL, *mp = NULL; + unsigned char* cp = NULL; + unsigned char* mp = NULL; unsigned char* string = (unsigned char*)str; unsigned char* wild = (unsigned char*)mask; @@ -74,46 +73,53 @@ static bool match_internal(const unsigned char *str, const unsigned char *mask, return !*wild; } -/******************************************************************** - * Below here is all wrappers around match_internal - ********************************************************************/ +// Below here is all wrappers around MatchInternal -CoreExport bool InspIRCd::Match(const std::string &str, const std::string &mask, unsigned const char *map) +bool InspIRCd::Match(const std::string& str, const std::string& mask, unsigned const char* map) { if (!map) map = national_case_insensitive_map; - return match_internal((const unsigned char *)str.c_str(), (const unsigned char *)mask.c_str(), map); + return MatchInternal((const unsigned char*)str.c_str(), (const unsigned char*)mask.c_str(), map); } -CoreExport bool InspIRCd::Match(const char *str, const char *mask, unsigned const char *map) +bool InspIRCd::Match(const char* str, const char* mask, unsigned const char* map) { if (!map) map = national_case_insensitive_map; - return match_internal((const unsigned char *)str, (const unsigned char *)mask, map); + + return MatchInternal((const unsigned char*)str, (const unsigned char*)mask, map); } -CoreExport bool InspIRCd::MatchCIDR(const std::string &str, const std::string &mask, unsigned const char *map) +bool InspIRCd::MatchCIDR(const std::string& str, const std::string& mask, unsigned const char* map) { if (irc::sockets::MatchCIDR(str, mask, true)) return true; - if (!map) - map = national_case_insensitive_map; - // Fall back to regular match return InspIRCd::Match(str, mask, map); } -CoreExport bool InspIRCd::MatchCIDR(const char *str, const char *mask, unsigned const char *map) +bool InspIRCd::MatchCIDR(const char* str, const char* mask, unsigned const char* map) { if (irc::sockets::MatchCIDR(str, mask, true)) return true; - if (!map) - map = national_case_insensitive_map; - // Fall back to regular match return InspIRCd::Match(str, mask, map); } +bool InspIRCd::MatchMask(const std::string& masks, const std::string& hostname, const std::string& ipaddr) +{ + std::stringstream masklist(masks); + std::string mask; + while (masklist >> mask) + { + if (InspIRCd::Match(hostname, mask, ascii_case_insensitive_map) || + InspIRCd::MatchCIDR(ipaddr, mask, ascii_case_insensitive_map)) + { + return true; + } + } + return false; +} diff --git a/src/xline.cpp b/src/xline.cpp index 66d24f439..bc8e596bd 100644 --- a/src/xline.cpp +++ b/src/xline.cpp @@ -158,7 +158,7 @@ void XLineManager::CheckELines() for (LocalUserList::const_iterator u2 = ServerInstance->Users->local_users.begin(); u2 != ServerInstance->Users->local_users.end(); u2++) { - User* u = (User*)(*u2); + LocalUser* u = *u2; /* This uses safe iteration to ensure that if a line expires here, it doenst trash the iterator */ LookupIter safei; @@ -259,7 +259,7 @@ bool XLineManager::AddLine(XLine* line, User* user) ContainerIter x = lookup_lines.find(line->type); if (x != lookup_lines.end()) { - LookupIter i = x->second.find(line->Displayable()); + LookupIter i = x->second.find(line->Displayable().c_str()); if (i != x->second.end()) { // XLine propagation bug was here, if the line to be added already exists and @@ -281,10 +281,10 @@ bool XLineManager::AddLine(XLine* line, User* user) if (xlf->AutoApplyToUserList(line)) pending_lines.push_back(line); - lookup_lines[line->type][line->Displayable()] = line; + lookup_lines[line->type][line->Displayable().c_str()] = line; line->OnAdd(); - FOREACH_MOD(I_OnAddLine,OnAddLine(user, line)); + FOREACH_MOD(OnAddLine, (user, line)); return true; } @@ -308,7 +308,7 @@ bool XLineManager::DelLine(const char* hostmask, const std::string &type, User* ServerInstance->BanCache->RemoveEntries(y->second->type, true); - FOREACH_MOD(I_OnDelLine,OnDelLine(user, y->second)); + FOREACH_MOD(OnDelLine, (user, y->second)); y->second->Unset(); @@ -328,7 +328,7 @@ void ELine::Unset() /* remove exempt from everyone and force recheck after deleting eline */ for (LocalUserList::const_iterator u2 = ServerInstance->Users->local_users.begin(); u2 != ServerInstance->Users->local_users.end(); u2++) { - User* u = (User*)(*u2); + LocalUser* u = *u2; u->exempt = false; } @@ -409,7 +409,7 @@ XLine* XLineManager::MatchesLine(const std::string &type, const std::string &pat // removes lines that have expired void XLineManager::ExpireLine(ContainerIter container, LookupIter item) { - FOREACH_MOD(I_OnExpireLine, OnExpireLine(item->second)); + FOREACH_MOD(OnExpireLine, (item->second)); item->second->DisplayExpiry(); item->second->Unset(); @@ -433,7 +433,7 @@ void XLineManager::ApplyLines() LocalUserList::reverse_iterator u2 = ServerInstance->Users->local_users.rbegin(); while (u2 != ServerInstance->Users->local_users.rend()) { - User* u = *u2++; + LocalUser* u = *u2++; // Don't ban people who are exempt. if (u->exempt) @@ -531,30 +531,28 @@ bool XLine::IsBurstable() void XLine::DefaultApply(User* u, const std::string &line, bool bancache) { - char sreason[MAXBUF]; - snprintf(sreason, MAXBUF, "%s-Lined: %s", line.c_str(), this->reason.c_str()); - if (!ServerInstance->Config->MoronBanner.empty()) - u->WriteServ("NOTICE %s :*** %s", u->nick.c_str(), ServerInstance->Config->MoronBanner.c_str()); + const std::string banReason = line + "-Lined: " + reason; + + if (!ServerInstance->Config->XLineMessage.empty()) + u->WriteNotice("*** " + ServerInstance->Config->XLineMessage); if (ServerInstance->Config->HideBans) - ServerInstance->Users->QuitUser(u, line + "-Lined", sreason); + ServerInstance->Users->QuitUser(u, line + "-Lined", banReason.c_str()); else - ServerInstance->Users->QuitUser(u, sreason); + ServerInstance->Users->QuitUser(u, banReason); if (bancache) { - ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCache: Adding positive hit (" + line + ") for " + u->GetIPString()); - if (this->duration > 0) - ServerInstance->BanCache->AddHit(u->GetIPString(), this->type, line + "-Lined: " + this->reason, this->duration); - else - ServerInstance->BanCache->AddHit(u->GetIPString(), this->type, line + "-Lined: " + this->reason); + ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Adding positive hit (" + line + ") for " + u->GetIPString()); + ServerInstance->BanCache->AddHit(u->GetIPString(), this->type, line + "-Lined: " + this->reason, this->duration); } } bool KLine::Matches(User *u) { - if (u->exempt) + LocalUser* lu = IS_LOCAL(u); + if (lu && lu->exempt) return false; if (InspIRCd::Match(u->ident, this->identmask, ascii_case_insensitive_map)) @@ -576,7 +574,8 @@ void KLine::Apply(User* u) bool GLine::Matches(User *u) { - if (u->exempt) + LocalUser* lu = IS_LOCAL(u); + if (lu && lu->exempt) return false; if (InspIRCd::Match(u->ident, this->identmask, ascii_case_insensitive_map)) @@ -598,7 +597,8 @@ void GLine::Apply(User* u) bool ELine::Matches(User *u) { - if (u->exempt) + LocalUser* lu = IS_LOCAL(u); + if (lu && lu->exempt) return false; if (InspIRCd::Match(u->ident, this->identmask, ascii_case_insensitive_map)) @@ -615,7 +615,8 @@ bool ELine::Matches(User *u) bool ZLine::Matches(User *u) { - if (u->exempt) + LocalUser* lu = IS_LOCAL(u); + if (lu && lu->exempt) return false; if (InspIRCd::MatchCIDR(u->GetIPString(), this->ipaddr)) @@ -641,7 +642,7 @@ bool QLine::Matches(User *u) void QLine::Apply(User* u) { /* Force to uuid on apply of qline, no need to disconnect any more :) */ - u->ForceNickChange(u->uuid.c_str()); + u->ForceNickChange(u->uuid); } @@ -681,65 +682,42 @@ void ELine::OnAdd() /* When adding one eline, only check the one eline */ for (LocalUserList::const_iterator u2 = ServerInstance->Users->local_users.begin(); u2 != ServerInstance->Users->local_users.end(); u2++) { - User* u = (User*)(*u2); + LocalUser* u = *u2; if (this->Matches(u)) u->exempt = true; } } -void ELine::DisplayExpiry() -{ - ServerInstance->SNO->WriteToSnoMask('x',"Removing expired E-Line %s@%s (set by %s %ld seconds ago)", - identmask.c_str(),hostmask.c_str(),source.c_str(),(long)(ServerInstance->Time() - this->set_time)); -} - -void QLine::DisplayExpiry() -{ - ServerInstance->SNO->WriteToSnoMask('x',"Removing expired Q-Line %s (set by %s %ld seconds ago)", - nick.c_str(),source.c_str(),(long)(ServerInstance->Time() - this->set_time)); -} - -void ZLine::DisplayExpiry() -{ - ServerInstance->SNO->WriteToSnoMask('x',"Removing expired Z-Line %s (set by %s %ld seconds ago)", - ipaddr.c_str(),source.c_str(),(long)(ServerInstance->Time() - this->set_time)); -} - -void KLine::DisplayExpiry() -{ - ServerInstance->SNO->WriteToSnoMask('x',"Removing expired K-Line %s@%s (set by %s %ld seconds ago)", - identmask.c_str(),hostmask.c_str(),source.c_str(),(long)(ServerInstance->Time() - this->set_time)); -} - -void GLine::DisplayExpiry() +void XLine::DisplayExpiry() { - ServerInstance->SNO->WriteToSnoMask('x',"Removing expired G-Line %s@%s (set by %s %ld seconds ago)", - identmask.c_str(),hostmask.c_str(),source.c_str(),(long)(ServerInstance->Time() - this->set_time)); + bool onechar = (type.length() == 1); + ServerInstance->SNO->WriteToSnoMask('x', "Removing expired %s%s %s (set by %s %ld seconds ago)", + type.c_str(), (onechar ? "-Line" : ""), Displayable().c_str(), source.c_str(), (long)(ServerInstance->Time() - set_time)); } -const char* ELine::Displayable() +const std::string& ELine::Displayable() { - return matchtext.c_str(); + return matchtext; } -const char* KLine::Displayable() +const std::string& KLine::Displayable() { - return matchtext.c_str(); + return matchtext; } -const char* GLine::Displayable() +const std::string& GLine::Displayable() { - return matchtext.c_str(); + return matchtext; } -const char* ZLine::Displayable() +const std::string& ZLine::Displayable() { - return ipaddr.c_str(); + return ipaddr; } -const char* QLine::Displayable() +const std::string& QLine::Displayable() { - return nick.c_str(); + return nick; } bool KLine::IsBurstable() diff --git a/tools/create_templates.pl b/tools/create_templates.pl deleted file mode 100755 index dfdaa29d1..000000000 --- a/tools/create_templates.pl +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/perl - -# -# InspIRCd -- Internet Relay Chat Daemon -# -# Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> -# -# This file is part of InspIRCd. InspIRCd 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, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# - - -use strict; -use warnings; - -my $maxparams = shift; - -die "You must supply a number of parameters to generate headers allowing for!" unless(defined $maxparams); -die "You must request a non-negative parameter limit!" unless($maxparams >= 0); - -print STDERR "Generating headerfile for a maximium of $maxparams parameters\n"; - -# First generate the HanderBase family - -my @templatetypes = ('ReturnType'); -for(my $i = 0; $i <= $maxparams; $i++) -{ - push @templatetypes, "Param" . $i if($i > 0); - print "template <typename " . join(', typename ', @templatetypes) . "> class CoreExport HandlerBase" . $i . "\n"; - print "{\n"; - print " public:\n"; - print " virtual ReturnType Call(" . join(', ', @templatetypes[1..$#templatetypes]) . ") = 0;\n"; - print " virtual ~HandlerBase" . $i . "() { }\n"; - print "};\n\n"; -} - -# And now the caller family - -print "template <typename HandlerType> class CoreExport caller\n"; -print "{\n"; -print " public:\n"; -print " HandlerType* target;\n\n"; -print " caller(HandlerType* initial)\n"; -print " : target(initial)\n"; -print " { }\n\n"; -print " virtual ~caller() { }\n\n"; -print " caller& operator=(HandlerType* newtarget)\n"; -print " {\n"; -print " target = newtarget;\n"; -print " return *this;\n"; -print " }\n"; -print "};\n\n"; - - - - -@templatetypes = ('ReturnType'); -for(my $i = 0; $i <= $maxparams; $i++) -{ - push @templatetypes, "Param" . $i if($i > 0); - - my $handlertype = "HandlerBase" . $i . "<" . join(', ', @templatetypes) . ">"; - my @templatetypepairs = map { $_ . " " . lc($_) } @templatetypes; - my @lctemplatetypes = map(lc, @templatetypes); - - print "template <typename " . join(', typename ', @templatetypes) . "> class CoreExport caller" . $i . " : public caller< " . $handlertype . " >\n"; - print "{\n"; - print " public:\n"; - print " caller" . $i . "(" . $handlertype . "* initial)\n"; - print " : caller< " . $handlertype. " >::caller(initial)\n"; - print " { }\n\n"; - print " virtual ReturnType operator() (" . join(', ', @templatetypepairs[1..$#templatetypepairs]) . ")\n"; - print " {\n"; - print " return this->target->Call(" . join(', ', @lctemplatetypes[1..$#lctemplatetypes]) . ");\n"; - print " }\n"; - print "};\n\n"; -} - diff --git a/tools/genssl b/tools/genssl new file mode 100755 index 000000000..26f4f76c5 --- /dev/null +++ b/tools/genssl @@ -0,0 +1,135 @@ +#!/usr/bin/env perl +# +# InspIRCd -- Internet Relay Chat Daemon +# +# Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> +# Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> +# Copyright (C) 2013 Peter Powell <petpow@saberuk.com> +# +# This file is part of InspIRCd. InspIRCd 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, version 2. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + + +BEGIN { + require 5.8.0; +} + +use strict; +use warnings FATAL => qw(all); + +use File::Temp(); + +# IMPORTANT: This script has to be able to run by itself so that it can be used +# by binary distributions where the make/utilities.pm module will not +# be available! + +sub prompt($$) { + my ($question, $default) = @_; + print "$question\n"; + print "[$default] => "; + chomp(my $answer = <STDIN>); + print "\n"; + return $answer ? $answer : $default; +} + +if ($#ARGV != 0 || $ARGV[0] !~ /^(?:auto|gnutls|openssl)$/i) { + print "Syntax: genssl <auto|gnutls|openssl>\n"; + exit 1; +} + +# On OS X the GnuTLS certtool is prefixed to avoid collision with the system certtool. +my $certtool = $^O eq 'darwin' ? 'gnutls-certtool' : 'certtool'; + +# Check whether the user has the required tools installed. +my $has_gnutls = !system "$certtool --version >/dev/null 2>&1"; +my $has_openssl = !system 'openssl version >/dev/null 2>&1'; + +# The framework the user has specified. +my $tool = lc $ARGV[0]; + +# If the user has not explicitly specified a framework then detect one. +if ($tool eq 'auto') { + if ($has_gnutls) { + $tool = 'gnutls'; + } elsif ($has_openssl) { + $tool = 'openssl'; + } else { + print STDERR "SSL generation failed: could not find $certtool or openssl in the PATH!\n"; + exit 1; + } +} elsif ($tool eq 'gnutls' && !$has_gnutls) { + print STDERR "SSL generation failed: could not find '$certtool' in the PATH!\n"; + exit 1; +} elsif ($tool eq 'openssl' && !$has_openssl) { + print STDERR "SSL generation failed: could not find 'openssl' in the PATH!\n"; + exit 1; +} + +# Harvest information needed to generate the certificate. +my $common_name = prompt('What is the hostname of your server?', 'irc.example.com'); +my $email = prompt('What email address can you be contacted at?', 'example@example.com'); +my $unit = prompt('What is the name of your unit?', 'Server Admins'); +my $organization = prompt('What is the name of your organization?', 'Example IRC Network'); +my $city = prompt('What city are you located in?', 'Example City'); +my $state = prompt('What state are you located in?', 'Example State'); +my $country = prompt('What is the ISO 3166-1 code for the country you are located in?', 'XZ'); +my $days = prompt('How many days do you want your certificate to be valid for?', '365'); + +# Contains the exit code of openssl/gnutls-certtool. +my $status = 0; + +if ($tool eq 'gnutls') { + my $tmp = new File::Temp(); + print $tmp <<__GNUTLS_END__; +cn = "$common_name" +email = "$email" +unit = "$unit" +organization = "$organization" +locality = "$city" +state = "$state" +country = "$country" +expiration_days = $days +tls_www_client +tls_www_server +signing_key +encryption_key +cert_signing_key +crl_signing_key +code_signing_key +ocsp_signing_key +time_stamping_key +__GNUTLS_END__ + close($tmp); + $status ||= system "$certtool --generate-privkey --outfile key.pem"; + $status ||= system "$certtool --generate-self-signed --load-privkey key.pem --outfile cert.pem --template $tmp"; + $status ||= system "$certtool --generate-dh-params --bits 2048 --outfile dhparams.pem"; +} elsif ($tool eq 'openssl') { + my $tmp = new File::Temp(); + print $tmp <<__OPENSSL_END__; +$country +$state +$city +$organization +$unit +$common_name +$email +__OPENSSL_END__ + close($tmp); + $status ||= system "cat $tmp | openssl req -x509 -nodes -newkey rsa:2048 -keyout key.pem -out cert.pem -days $days 2>/dev/null"; + $status ||= system 'openssl dhparam -out dhparams.pem 2048'; +} + +if ($status) { + print STDERR "SSL generation failed: $tool exited with a non-zero status!\n"; + exit 1; +} diff --git a/win/.gitignore b/win/.gitignore index f53ca0701..4b875ca61 100644 --- a/win/.gitignore +++ b/win/.gitignore @@ -1,3 +1,2 @@ -inspircd_version.h
-inspircd_config.h
+config.h
inspircd.rc
diff --git a/win/CMakeLists.txt b/win/CMakeLists.txt index e6a854d99..a9c58bcfc 100644 --- a/win/CMakeLists.txt +++ b/win/CMakeLists.txt @@ -12,6 +12,9 @@ set(EXTRA_LIBS "" CACHE PATH "Extra library paths") set(INSPIRCD_BASE "${CMAKE_CURRENT_SOURCE_DIR}/../") +# Build with multiple processes +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") + # Use our own NSIS template set(CMAKE_MODULE_PATH "${INSPIRCD_BASE}/win") @@ -56,8 +59,7 @@ if(MSVC) endif(MSVC) configure_file("${INSPIRCD_BASE}/win/inspircd.rc.cmake" "${INSPIRCD_BASE}/win/inspircd.rc") -configure_file("${INSPIRCD_BASE}/win/inspircd_version.h.cmake" "${INSPIRCD_BASE}/win/inspircd_version.h") -configure_file("${INSPIRCD_BASE}/win/inspircd_config.h.cmake" "${INSPIRCD_BASE}/win/inspircd_config.h") +configure_file("${INSPIRCD_BASE}/win/config.h.cmake" "${INSPIRCD_BASE}/win/config.h") add_executable(inspircd ${INSPIRCD_SOURCES} "${INSPIRCD_BASE}/win/inspircd.rc") target_link_libraries(inspircd win32_memory) diff --git a/win/inspircd_config.h.cmake b/win/config.h.cmake index f98cd391e..081163fab 100644 --- a/win/inspircd_config.h.cmake +++ b/win/config.h.cmake @@ -1,13 +1,14 @@ -#ifndef INSPIRCD_CONFIG_H
-#define INSPIRCD_CONFIG_H
+#pragma once
+
+#define BRANCH "@MAJOR_VERSION@.@MINOR_VERSION@"
+#define VERSION "@FULL_VERSION@"
+#define REVISION "release"
+#define SYSTEM "@CMAKE_SYSTEM@"
#define CONFIG_PATH "@CONF_PATH@"
#define MOD_PATH "@MODULE_PATH@"
#define DATA_PATH "@DATA_PATH@"
#define LOG_PATH "@LOG_PATH@"
-#define MAXBUF 514
#include "inspircd_win32wrapper.h"
#include "threadengines/threadengine_win32.h"
-
-#endif
\ No newline at end of file diff --git a/win/inspircd_memory_functions.cpp b/win/inspircd_memory_functions.cpp index 398708317..2093bf3a8 100644 --- a/win/inspircd_memory_functions.cpp +++ b/win/inspircd_memory_functions.cpp @@ -16,6 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + #include <windows.h> #include <exception> #include <new> diff --git a/win/inspircd_version.h.cmake b/win/inspircd_version.h.cmake deleted file mode 100644 index 1aec12b24..000000000 --- a/win/inspircd_version.h.cmake +++ /dev/null @@ -1,4 +0,0 @@ -#define BRANCH "@MAJOR_VERSION@.@MINOR_VERSION@"
-#define VERSION "@FULL_VERSION@"
-#define REVISION "0"
-#define SYSTEM "@CMAKE_SYSTEM@"
\ No newline at end of file diff --git a/win/inspircd_win32wrapper.cpp b/win/inspircd_win32wrapper.cpp index 048baf38b..eba18dca3 100644 --- a/win/inspircd_win32wrapper.cpp +++ b/win/inspircd_win32wrapper.cpp @@ -22,6 +22,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + #include "inspircd_win32wrapper.h" #include "inspircd.h" #include "configreader.h" @@ -85,7 +86,7 @@ CoreExport int insp_inet_pton(int af, const char *src, void *dst) } return 1; } - + return 0; } @@ -163,7 +164,7 @@ int getopt_long(int ___argc, char *const *___argv, const char *__shortopts, cons // optind++; // Trash this next argument, we won't be needing it. par = ___argv[optind-1]; } - } + } // increment the argument for next time // optind++; @@ -189,9 +190,9 @@ int getopt_long(int ___argc, char *const *___argv, const char *__shortopts, cons { if (__longopts[i].val == -1 || par == 0) return 1; - + return __longopts[i].val; - } + } break; } } diff --git a/win/inspircd_win32wrapper.h b/win/inspircd_win32wrapper.h index 75404ef8b..a7f2b4354 100644 --- a/win/inspircd_win32wrapper.h +++ b/win/inspircd_win32wrapper.h @@ -19,13 +19,11 @@ */ +#pragma once + /* Windows Port Wrapper Functions/Definitions By Burlex */ - -#ifndef INSPIRCD_WIN32WRAPPER_H -#define INSPIRCD_WIN32WRAPPER_H - /* * Starting with PSAPI version 2 for Windows 7 and Windows Server 2008 R2, this function is defined as K32GetProcessMemoryInfo in Psapi.h and exported * in Kernel32.lib and Kernel32.dll. However, you should always call this function as GetProcessMemoryInfo. To ensure correct resolution of symbols @@ -45,9 +43,6 @@ #define VC_EXTRALEAN #define WIN32_LEAN_AND_MEAN -/* They just have to be *different*, don't they. */ -#define PATH_MAX MAX_PATH - /* Macros for exporting symbols - dependant on what is being compiled */ #ifdef DLL_BUILD @@ -73,6 +68,15 @@ #include <sys/stat.h> #include <direct.h> #include <process.h> +#include <io.h> + +#define F_OK 0 /* test for existence of file */ +#define X_OK (1<<0) /* test for execute or search permission */ +#define W_OK (1<<1) /* test for write permission */ +#define R_OK (1<<2) /* test for read permission */ + +/* Windows defines this already. */ +#undef ERROR /* strcasecmp is not defined on windows by default */ #define strcasecmp _stricmp @@ -92,6 +96,10 @@ CoreExport const char * insp_inet_ntop(int af, const void * src, char * dst, soc #define snprintf _snprintf #define vsnprintf _vsnprintf +#ifndef va_copy +#define va_copy(dest, src) (dest = src) +#endif + /* Unix-style sleep (argument is in seconds) */ __inline void sleep(int seconds) { Sleep(seconds * 1000); } @@ -99,6 +107,9 @@ __inline void sleep(int seconds) { Sleep(seconds * 1000); } #define popen _popen #define pclose _pclose +/* _access */ +#define access _access + /* IPV4 only convert string to address struct */ __inline int inet_aton(const char *cp, struct in_addr *addr) { @@ -201,5 +212,5 @@ private: DWORD dwErrorCode; }; -#endif - +// Same value as EXIT_STATUS_FORK (EXIT_STATUS_FORK is unused on Windows) +#define EXIT_STATUS_SERVICE 4 diff --git a/win/modules/CMakeLists.txt b/win/modules/CMakeLists.txt index 5778d944a..386d3600d 100644 --- a/win/modules/CMakeLists.txt +++ b/win/modules/CMakeLists.txt @@ -8,9 +8,15 @@ list(SORT INSPIRCD_MODULES) add_definitions("-DDLL_BUILD")
foreach(MODULE_NAME ${INSPIRCD_MODULES})
- string(REGEX REPLACE "^.*[/\\](.*).cpp$" "\\1.so" SO_NAME ${MODULE_NAME})
+ string(REGEX REPLACE "^.*[/\\](.*).cpp$" "\\1" BASE_NAME ${MODULE_NAME})
+ set(SO_NAME "${BASE_NAME}.so")
add_library(${SO_NAME} MODULE ${MODULE_NAME})
- set_target_properties(${SO_NAME} PROPERTIES PREFIX "" SUFFIX "")
+ set_target_properties(${SO_NAME} PROPERTIES
+ PREFIX ""
+ SUFFIX ""
+ COMPILE_DEFINITIONS "MODNAME=\"${BASE_NAME}\""
+ )
+
target_link_libraries(${SO_NAME} inspircd)
add_dependencies(${SO_NAME} inspircd)
if(MSVC)
@@ -24,7 +30,12 @@ file(GLOB INSPIRCD_MODULES_SPANNINGTREE RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${ list(SORT INSPIRCD_MODULES_SPANNINGTREE)
add_library(m_spanningtree.so MODULE ${INSPIRCD_MODULES_SPANNINGTREE})
-set_target_properties(m_spanningtree.so PROPERTIES PREFIX "" SUFFIX "")
+set_target_properties(m_spanningtree.so PROPERTIES
+ PREFIX ""
+ SUFFIX ""
+ COMPILE_DEFINITIONS "MODNAME=\"m_spanningtree\""
+)
+
target_link_libraries(m_spanningtree.so inspircd)
add_dependencies(m_spanningtree.so inspircd)
if(MSVC)
diff --git a/win/win32service.cpp b/win/win32service.cpp index c34e9957d..448829a1d 100644 --- a/win/win32service.cpp +++ b/win/win32service.cpp @@ -17,7 +17,7 @@ */ -#include "inspircd_config.h" +#include "config.h" #include "inspircd.h" #include "exitcodes.h" #include <windows.h> @@ -280,7 +280,7 @@ int main(int argc, char* argv[]) } else { - return EXIT_STATUS_INTERNAL; + return EXIT_STATUS_SERVICE; } } return 0; diff --git a/win/win32service.h b/win/win32service.h index e4500be13..d8177eabc 100644 --- a/win/win32service.h +++ b/win/win32service.h @@ -15,7 +15,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + #pragma once + #ifdef _WIN32 /* Hook for win32service.cpp to exit properly with the service specific error code */ |