diff --git a/Config b/Config
@@ -88,6 +88,19 @@ fi
if [ "x$INSTALLCURL" = "x1" ]; then
extras/curlinstall "$PRIVATELIBDIR" || exit 1
fi
+# At least do SOME parallel compiling by default, IF:
+# - the MAKE environment variable is not set
+# - the MAKEFLAGS environment variable is not set
+# - we are using GNU Make
+if [ "x$MAKE" = "x" ]; then
+ if [ "x$MAKEFLAGS" = "x" ]; then
+ if make --version 2>&1|grep -q "GNU Make"; then
+ echo "Running with 4 concurrent build processes by default (make -j4)."
+ export MAKE='make -j4'
+ fi
+ fi
+fi
+
echo $CONF
$CONF || exit 1
cd "$UNREALCWD"
@@ -313,7 +326,7 @@ echo "We will now ask you a number of questions. You can just press ENTER to acc
echo ""
# This needs to be updated each release so auto-upgrading works for settings, modules, etc!!:
-UNREALRELEASES="unrealircd-5.0.3.1 unrealircd-5.0.3 unrealircd-5.0.2 unrealircd-5.0.1 unrealircd-5.0.0 unrealircd-5.0.0-rc2 unrealircd-5.0.0-rc1"
+UNREALRELEASES="unrealircd-5.0.4 unrealircd-5.0.3.1 unrealircd-5.0.3 unrealircd-5.0.2 unrealircd-5.0.1 unrealircd-5.0.0 unrealircd-5.0.0-rc2 unrealircd-5.0.0-rc1"
if [ -f "config.settings" ]; then
. ./config.settings
else
@@ -479,7 +492,7 @@ while [ -z "$TEST" ] ; do
echo ""
echo "Do you want to enable remote includes?"
echo "This allows stuff like this in your configuration file:"
- echo "include \"http://www.somesite.org/files/opers.conf\";"
+ echo "include \"https://www.somesite.org/files/opers.conf\";"
echo $n "[$TEST] -> $c"
read cc
if [ -z "$cc" ] ; then
diff --git a/Makefile.windows b/Makefile.windows
@@ -290,7 +290,10 @@ DLL_FILES=SRC/MODULES/CLOAK.DLL \
SRC/MODULES/USERHOST-TAG.DLL \
SRC/MODULES/REQUIRE-MODULE.DLL \
SRC/MODULES/IDENT_LOOKUP.DLL \
- SRC/MODULES/HISTORY.DLL
+ SRC/MODULES/HISTORY.DLL \
+ SRC/MODULES/TARGETFLOODPROT.DLL \
+ SRC/MODULES/TYPING-INDICATOR.DLL \
+ SRC/MODULES/CLIENTTAGDENY.DLL
ALL: CONF UNREALSVC.EXE UnrealIRCd.exe MODULES
@@ -1081,4 +1084,13 @@ src/modules/ident_lookup.dll: src/modules/ident_lookup.c $(INCLUDES)
src/modules/history.dll: src/modules/history.c $(INCLUDES)
$(CC) $(MODCFLAGS) /Fosrc/modules/ /Fesrc/modules/ src/modules/history.c $(MODLFLAGS)
+src/modules/targetfloodprot.dll: src/modules/targetfloodprot.c $(INCLUDES)
+ $(CC) $(MODCFLAGS) /Fosrc/modules/ /Fesrc/modules/ src/modules/targetfloodprot.c $(MODLFLAGS)
+
+src/modules/typing-indicator.dll: src/modules/typing-indicator.c $(INCLUDES)
+ $(CC) $(MODCFLAGS) /Fosrc/modules/ /Fesrc/modules/ src/modules/typing-indicator.c $(MODLFLAGS)
+
+src/modules/clienttagdeny.dll: src/modules/clienttagdeny.c $(INCLUDES)
+ $(CC) $(MODCFLAGS) /Fosrc/modules/ /Fesrc/modules/ src/modules/clienttagdeny.c $(MODLFLAGS)
+
dummy:
diff --git a/configure b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for unrealircd 5.0.4.
+# Generated by GNU Autoconf 2.69 for unrealircd 5.0.5.
#
# Report bugs to <https://bugs.unrealircd.org/>.
#
@@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='unrealircd'
PACKAGE_TARNAME='unrealircd'
-PACKAGE_VERSION='5.0.4'
-PACKAGE_STRING='unrealircd 5.0.4'
+PACKAGE_VERSION='5.0.5'
+PACKAGE_STRING='unrealircd 5.0.5'
PACKAGE_BUGREPORT='https://bugs.unrealircd.org/'
PACKAGE_URL='https://unrealircd.org/'
@@ -1325,7 +1325,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures unrealircd 5.0.4 to adapt to many kinds of systems.
+\`configure' configures unrealircd 5.0.5 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1391,7 +1391,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of unrealircd 5.0.4:";;
+ short | recursive ) echo "Configuration of unrealircd 5.0.5:";;
esac
cat <<\_ACEOF
@@ -1544,7 +1544,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-unrealircd configure 5.0.4
+unrealircd configure 5.0.5
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1913,7 +1913,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by unrealircd $as_me 5.0.4, which was
+It was created by unrealircd $as_me 5.0.5, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2321,7 +2321,7 @@ _ACEOF
# Minor version number (e.g.: Z in X.Y.Z)
-UNREAL_VERSION_MINOR="4"
+UNREAL_VERSION_MINOR="5"
cat >>confdefs.h <<_ACEOF
#define UNREAL_VERSION_MINOR $UNREAL_VERSION_MINOR
@@ -4078,6 +4078,104 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ # Added in UnrealIRCd 5.0.5 (default on Ubuntu 19.10)
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fstack-clash-protection" >&5
+$as_echo_n "checking whether C compiler accepts -fstack-clash-protection... " >&6; }
+if ${ax_cv_check_cflags__Werror___fstack_clash_protection+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_check_save_flags=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -fstack-clash-protection"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ax_cv_check_cflags__Werror___fstack_clash_protection=yes
+else
+ ax_cv_check_cflags__Werror___fstack_clash_protection=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$ax_check_save_flags
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror___fstack_clash_protection" >&5
+$as_echo "$ax_cv_check_cflags__Werror___fstack_clash_protection" >&6; }
+if test x"$ax_cv_check_cflags__Werror___fstack_clash_protection" = xyes; then :
+ HARDEN_CFLAGS="$HARDEN_CFLAGS -fstack-clash-protection"
+else
+ :
+fi
+
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ # Control Flow Enforcement (ROP hardening) - requires CPU hardware support
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fcf-protection" >&5
+$as_echo_n "checking whether C compiler accepts -fcf-protection... " >&6; }
+if ${ax_cv_check_cflags__Werror___fcf_protection+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_check_save_flags=$CFLAGS
+ CFLAGS="$CFLAGS -Werror -fcf-protection"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ax_cv_check_cflags__Werror___fcf_protection=yes
+else
+ ax_cv_check_cflags__Werror___fcf_protection=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$ax_check_save_flags
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror___fcf_protection" >&5
+$as_echo "$ax_cv_check_cflags__Werror___fcf_protection" >&6; }
+if test x"$ax_cv_check_cflags__Werror___fcf_protection" = xyes; then :
+ HARDEN_CFLAGS="$HARDEN_CFLAGS -fcf-protection"
+else
+ :
+fi
+
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
# At the link step, we might want -pie (GCC) or -Wl,-pie (Clang on OS X)
#
# The linker checks also compile code, so we need to include -fPIE as well.
@@ -6783,12 +6881,12 @@ if test -n "$PCRE2_CFLAGS"; then
pkg_cv_PCRE2_CFLAGS="$PCRE2_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpcre2-8 >= 10.00\""; } >&5
- ($PKG_CONFIG --exists --print-errors "libpcre2-8 >= 10.00") 2>&5
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpcre2-8 >= 10.34\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libpcre2-8 >= 10.34") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_PCRE2_CFLAGS=`$PKG_CONFIG --cflags "libpcre2-8 >= 10.00" 2>/dev/null`
+ pkg_cv_PCRE2_CFLAGS=`$PKG_CONFIG --cflags "libpcre2-8 >= 10.34" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -6800,12 +6898,12 @@ if test -n "$PCRE2_LIBS"; then
pkg_cv_PCRE2_LIBS="$PCRE2_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpcre2-8 >= 10.00\""; } >&5
- ($PKG_CONFIG --exists --print-errors "libpcre2-8 >= 10.00") 2>&5
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpcre2-8 >= 10.34\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libpcre2-8 >= 10.34") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_PCRE2_LIBS=`$PKG_CONFIG --libs "libpcre2-8 >= 10.00" 2>/dev/null`
+ pkg_cv_PCRE2_LIBS=`$PKG_CONFIG --libs "libpcre2-8 >= 10.34" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -6826,9 +6924,9 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- PCRE2_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpcre2-8 >= 10.00" 2>&1`
+ PCRE2_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpcre2-8 >= 10.34" 2>&1`
else
- PCRE2_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpcre2-8 >= 10.00" 2>&1`
+ PCRE2_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpcre2-8 >= 10.34" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$PCRE2_PKG_ERRORS" >&5
@@ -6852,7 +6950,7 @@ fi
if test "$has_system_pcre2" = "no"; then :
-pcre2_version="10.33"
+pcre2_version="10.34"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: extracting PCRE2 regex library" >&5
$as_echo "extracting PCRE2 regex library" >&6; }
cur_dir=`pwd`
@@ -6869,7 +6967,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: configuring PCRE2 regex library" >&5
$as_echo "configuring PCRE2 regex library" >&6; }
cd pcre2-$pcre2_version
-./configure --enable-jit --enable-shared --disable-unicode --prefix=$cur_dir/extras/pcre2 --libdir=$PRIVATELIBDIR || exit 1
+./configure --enable-jit --enable-shared --prefix=$cur_dir/extras/pcre2 --libdir=$PRIVATELIBDIR || exit 1
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: compiling PCRE2 regex library" >&5
$as_echo "compiling PCRE2 regex library" >&6; }
$ac_cv_prog_MAKER || exit 1
@@ -7089,7 +7187,7 @@ fi
if test "$has_system_cares" = "no"; then :
-cares_version="1.15.0"
+cares_version="1.16.0"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: extracting c-ares resolver library" >&5
$as_echo "extracting c-ares resolver library" >&6; }
cur_dir=`pwd`
@@ -8300,7 +8398,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by unrealircd $as_me 5.0.4, which was
+This file was extended by unrealircd $as_me 5.0.5, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -8363,7 +8461,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-unrealircd config.status 5.0.4
+unrealircd config.status 5.0.5
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
@@ -7,7 +7,7 @@ dnl src/windows/unrealinst.iss
dnl doc/Config.header
dnl src/version.c.SH
-AC_INIT([unrealircd], [5.0.4], [https://bugs.unrealircd.org/], [], [https://unrealircd.org/])
+AC_INIT([unrealircd], [5.0.5], [https://bugs.unrealircd.org/], [], [https://unrealircd.org/])
AC_CONFIG_SRCDIR([src/ircd.c])
AC_CONFIG_HEADER([include/setup.h])
AC_CONFIG_AUX_DIR([autoconf])
@@ -34,7 +34,7 @@ UNREAL_VERSION_MAJOR=["0"]
AC_DEFINE_UNQUOTED([UNREAL_VERSION_MAJOR], [$UNREAL_VERSION_MAJOR], [Major version number (e.g.: Y for X.Y.Z)])
# Minor version number (e.g.: Z in X.Y.Z)
-UNREAL_VERSION_MINOR=["4"]
+UNREAL_VERSION_MINOR=["5"]
AC_DEFINE_UNQUOTED([UNREAL_VERSION_MINOR], [$UNREAL_VERSION_MINOR], [Minor version number (e.g.: Z for X.Y.Z)])
# The version suffix such as a beta marker or release candidate
@@ -129,6 +129,12 @@ AS_IF([test x"$hardening" != x"no"], [
check_cc_flag([--param ssp-buffer-size=1], [HARDEN_CFLAGS="$HARDEN_CFLAGS --param ssp-buffer-size=1"],
[], [-fstack-protector-all])])])
+ # Added in UnrealIRCd 5.0.5 (default on Ubuntu 19.10)
+ check_cc_flag([-fstack-clash-protection], [HARDEN_CFLAGS="$HARDEN_CFLAGS -fstack-clash-protection"])
+
+ # Control Flow Enforcement (ROP hardening) - requires CPU hardware support
+ check_cc_flag([-fcf-protection], [HARDEN_CFLAGS="$HARDEN_CFLAGS -fcf-protection"])
+
# At the link step, we might want -pie (GCC) or -Wl,-pie (Clang on OS X)
#
# The linker checks also compile code, so we need to include -fPIE as well.
@@ -531,12 +537,12 @@ export PATH_SEPARATOR
dnl Use system pcre2 when available, unless --without-system-pcre2.
has_system_pcre2="no"
AS_IF([test "x$with_system_pcre2" = "xyes"],[
-PKG_CHECK_MODULES([PCRE2], libpcre2-8 >= 10.00,[has_system_pcre2=yes
+PKG_CHECK_MODULES([PCRE2], libpcre2-8 >= 10.34,[has_system_pcre2=yes
AS_IF([test "x$PRIVATELIBDIR" != "x"], [rm -f "$PRIVATELIBDIR/"libpcre2*])],[has_system_pcre2=no])])
AS_IF([test "$has_system_pcre2" = "no"], [
dnl REMEMBER TO CHANGE WITH A NEW PCRE2 RELEASE!
-pcre2_version="10.33"
+pcre2_version="10.34"
AC_MSG_RESULT(extracting PCRE2 regex library)
cur_dir=`pwd`
cd extras
@@ -553,7 +559,7 @@ else
fi
AC_MSG_RESULT(configuring PCRE2 regex library)
cd pcre2-$pcre2_version
-./configure --enable-jit --enable-shared --disable-unicode --prefix=$cur_dir/extras/pcre2 --libdir=$PRIVATELIBDIR || exit 1
+./configure --enable-jit --enable-shared --prefix=$cur_dir/extras/pcre2 --libdir=$PRIVATELIBDIR || exit 1
AC_MSG_RESULT(compiling PCRE2 regex library)
$ac_cv_prog_MAKER || exit 1
AC_MSG_RESULT(installing PCRE2 regex library)
@@ -627,7 +633,7 @@ AS_IF([test "$has_system_cares" = "no"], [
dnl REMEMBER TO CHANGE WITH A NEW C-ARES RELEASE!
dnl NOTE: when changing this here, ALSO change it in extras/curlinstall
dnl and in the comment in this file around line 400!
-cares_version="1.15.0"
+cares_version="1.16.0"
AC_MSG_RESULT(extracting c-ares resolver library)
cur_dir=`pwd`
cd extras
diff --git a/doc/Config.header b/doc/Config.header
@@ -7,7 +7,7 @@
\___/|_| |_|_| \___|\__,_|_|\___/\_| \_| \____/\__,_|
Configuration Program
- for UnrealIRCd 5.0.4
+ for UnrealIRCd 5.0.5
This program will help you to compile your IRC server, and ask you
questions regarding the compile-time settings of it during the process.
diff --git a/doc/RELEASE-NOTES.md b/doc/RELEASE-NOTES.md
@@ -1,6 +1,82 @@
-UnrealIRCd 5.0.4 Release Notes
+UnrealIRCd 5.0.5 Release Notes
===============================
+This release mainly focuses on new features, while also fixing a few bugs.
+
+Fixes:
+* [except ban { }](https://www.unrealircd.org/docs/Except_ban_block)
+ without 'type' was not exempting from gline.
+* Channel mode ```+L #forward``` and ```+k key```: should forward
+ on wrong key, but was also redirecting on correct key.
+* Crash on 32-bit machines in tkldb (on start or rehash)
+* Crash when saving channeldb when a parameter channel mode is combined
+ with ```+P``` and that module was loaded after channeldb. This may
+ happen if you use 3rd party modules that add parameter channel modes.
+
+Enhancements:
+* [Spamfilter](https://www.unrealircd.org/docs/Spamfilter) is now UTF8-aware.
+ This means, among other things:
+ * Case insensitive matches work better. For example, with extended
+ Latin, a spamfilter on ```ę``` now also matches ```Ę```.
+ * Other PCRE2 features such as [\p](https://www.pcre.org/current/doc/html/pcre2syntax.html#SEC5)
+ are now available. For example you can now set a spamfilter with the regex
+ ```\p{Arabic}``` to block all Arabic script, or ```\p{Cyrillic}``` to
+ block all Cyrillic script (such as Russian).
+ Please do use these new tools with care. Blocking an entire language
+ or script is quite a drastic measure.
+ * These new features require the PCRE2 10.34 regex library. If you
+ have a lower version on your system then UnrealIRCd will fall back
+ to using the UnrealIRCd-shipped-library version 10.34. The only
+ downside to that is that compiling during ```./Config``` may take
+ a little longer than usual.
+* [antimixedutf8](https://www.unrealircd.org/docs/Set_block#set::antimixedutf8)
+ has been improved to detect CJK and other scripts and this will now
+ catch more mixed UTF8 spam. Note that, if you previously manually
+ set the score very tight (much lower than the default of 10) then you
+ may have to increase it a bit, or not, depending on your network.
+* Support for IRCv3 [+typing clienttag](https://ircv3.net/specs/client-tags/typing.html),
+ which adds "user is typing" support to channels and PM (if the client
+ supports it).
+* New flood countermeasure,
+ [set::anti-flood::target-flood](https://www.unrealircd.org/docs/Set_block#set%3A%3Aanti-flood%3A%3Atarget-flood),
+ which limits flooding to channels and users. This is only meant as a
+ filter for high rate floods. You are still encouraged to use
+ [channel mode +f](https://www.unrealircd.org/docs/Anti-flood_features#Channel_mode_f)
+ in channels which give you more customized and fine-grained options
+ to deal with low- and medium-rate floods.
+* If a chanop /INVITEs someone, it will now override ban forwards
+ such as ```+b ~f:#forward:*!*@*```.
+
+Changes:
+* We now do parallel builds by default (```make -j4```) within ./Config,
+ unless the ```$MAKE``` or ```$MAKEFLAGS``` environment variable is set.
+* [set::restrict-commands](https://www.unrealircd.org/docs/Set_block#set%3A%3Arestrict-commands):
+ * The ```disable``` option is now removed as it is implied. In other words: if
+ you want to disable a command, then simply don't use ```connect-delay```.
+ * You can now have a block without ```connect-delay``` but still make
+ users bypass the restriction with ```exempt-identified``` and/or
+ ```exempt-reputation-score```. Previously this was not possible.
+* We now give an error when an IRCOp tries to place an *LINE that already
+ exists. (Previously we sometimes replaced the existing *LINE and other
+ times we did not)
+* Add Polish HELPOP (help.pl.conf)
+
+Module coders / Developers:
+* Breaking API change in ```HOOKTYPE_CAN_SEND_TO_USER``` and
+ ```HOOKTYPE_CAN_SEND_TO_CHANNEL```: the final argument has changed
+ from ```int notice``` to ```SendType sendtype```, which is an
+ enum, since we now have 3 message options (PRIVMSG, NOTICE, TAGMSG).
+
+Upgrading from UnrealIRCd 4?
+-----------------------------
+
+Are you upgrading from UnrealIRCd 4.x to UnrealIRCd 5?
+Then check out the *UnrealIRCd 5* release notes [further down](#unrealircd-5). At the
+very least, check out [Upgrading from 4.x](https://www.unrealircd.org/docs/Upgrading_from_4.x).
+
+UnrealIRCd 5.0.4
+------------------
+
This new 5.0.4 version fixes quite a number of bugs. It contains only two small feature improvements.
Fixes:
@@ -35,13 +111,6 @@ Changes:
[set::plaintext-policy::oper-message](https://www.unrealircd.org/docs/Set_block#set::plaintext-policy).
* The French HELPOP text was updated.
-Upgrading from UnrealIRCd 4?
------------------------------
-
-Are you upgrading from UnrealIRCd 4.x to UnrealIRCd 5?
-Then check out the *UnrealIRCd 5* release notes [further down](#unrealircd-5). At the
-very least, check out [Upgrading from 4.x](https://www.unrealircd.org/docs/Upgrading_from_4.x).
-
UnrealIRCd 5.0.3.1
-------------------
This fixes a crash issue after REHASH in 5.0.3.
diff --git a/doc/conf/modules.conf b/doc/conf/modules.conf
@@ -156,8 +156,10 @@ loadmodule "extbans/textban"; /* +b ~T */
loadmodule "extbans/timedban"; /* +b ~t */
// IRCv3 Extensions
+loadmodule "account-notify";
loadmodule "account-tag";
loadmodule "batch";
+loadmodule "clienttagdeny";
loadmodule "echo-message";
loadmodule "labeled-response";
loadmodule "link-security";
@@ -166,6 +168,7 @@ loadmodule "message-tags";
loadmodule "plaintext-policy";
loadmodule "server-time";
loadmodule "sts";
+loadmodule "typing-indicator";
// Other
loadmodule "antimixedutf8";
@@ -180,6 +183,7 @@ loadmodule "history_backend_mem";
#loadmodule "history_backend_null";
loadmodule "ident_lookup";
loadmodule "jointhrottle";
+#loadmodule "targetfloodprot";
loadmodule "tkldb";
loadmodule "tls_antidos";
loadmodule "userhost-tag";
diff --git a/doc/conf/modules.sources.list b/doc/conf/modules.sources.list
@@ -1 +1 @@
-https://modules.unrealircd.org/modules.list
+https://modules.unrealircd.org/modules.list
+\ No newline at end of file
diff --git a/doc/conf/opers.conf b/doc/conf/opers.conf
@@ -101,7 +101,7 @@ operclass netadmin {
permissions {
chat { notice { global; } }
client { set; }
- immune { join-flood; max-conncurrent-conversionations; maxchannelsperuser; nick-flood; server-ban { spamfilter; } }
+ immune { join-flood; max-conncurrent-conversionations; maxchannelsperuser; nick-flood; server-ban { spamfilter; }; target-flood; }
kill;
channel { operonly; override; see; }
route;
diff --git a/doc/conf/tls/curl-ca-bundle.crt b/doc/conf/tls/curl-ca-bundle.crt
@@ -1,7 +1,7 @@
##
## Bundle of CA Root Certificates
##
-## Certificate data from Mozilla as of: Wed Oct 16 03:12:09 2019 GMT
+## Certificate data from Mozilla as of: Wed Jan 1 04:12:10 2020 GMT
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
@@ -14,7 +14,7 @@
## Just configure this file as the SSLCACertificateFile.
##
## Conversion done with mk-ca-bundle.pl version 1.27.
-## SHA256: c979c6f35714a0fedb17d9e5ba37adecbbc91a8faf4186b4e23d6f9ca44fd6cb
+## SHA256: f3bdcd74612952da8476a9d4147f50b29ad0710b7dd95b4c8690500209986d70
##
@@ -3430,3 +3430,37 @@ hcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB
60PZ2Pierc+xYw5F9KBaLJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fq
dBb9HxEGmpv0
-----END CERTIFICATE-----
+
+Entrust Root Certification Authority - G4
+=========================================
+-----BEGIN CERTIFICATE-----
+MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAwgb4xCzAJBgNV
+BAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3Qu
+bmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1
+dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1
+dGhvcml0eSAtIEc0MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYT
+AlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0
+L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhv
+cml0eSAtIEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3D
+umSXbcr3DbVZwbPLqGgZ2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV
+3imz/f3ET+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j5pds
+8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAMC1rlLAHGVK/XqsEQ
+e9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73TDtTUXm6Hnmo9RR3RXRv06QqsYJn7
+ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNXwbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5X
+xNMhIWNlUpEbsZmOeX7m640A2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV
+7rtNOzK+mndmnqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8
+dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwlN4y6mACXi0mW
+Hv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNjc0kCAwEAAaNCMEAwDwYDVR0T
+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9n
+MA0GCSqGSIb3DQEBCwUAA4ICAQAS5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4Q
+jbRaZIxowLByQzTSGwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht
+7LGrhFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/B7NTeLUK
+YvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uIAeV8KEsD+UmDfLJ/fOPt
+jqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbwH5Lk6rWS02FREAutp9lfx1/cH6NcjKF+
+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKW
+RGhXxNUzzxkvFMSUHHuk2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjA
+JOgc47OlIQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk5F6G
++TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuYn/PIjhs4ViFqUZPT
+kcpG2om3PVODLAgfi49T3f+sHw==
+-----END CERTIFICATE-----
diff --git a/doc/conf/unrealircd.remote.conf b/doc/conf/unrealircd.remote.conf
@@ -16,6 +16,11 @@ class servers { pingfreq 120; maxclients 10; sendq 1M; connfreq 30; }
allow { ip *; class clients; maxperip 2; }
+#require authentication {
+# mask *@*;
+# reason "8,4 E N T E R T H E V O I D ";
+#}
+
listen { ip *; port 6667; options { clientsonly; } }
listen { ip *; port 6697; options { clientsonly; tls; } }
listen { ip *; port REDACTED; options { serversonly; tls; } }
@@ -90,12 +95,12 @@ set {
level-on-join "op";
restrict-channelmodes "CnLpPs";
restrict-commands {
- channel-message { connect-delay 60; exempt-identified yes; exempt-reputation-score 24; }
- invite { connect-delay 3600; exempt-identified yes; exempt-reputation-score 24; }
- join { connect-delay 60; exempt-identified yes; exempt-reputation-score 24; }
- list { connect-delay 120; exempt-identified yes; exempt-reputation-score 24; }
- private-message { connect-delay 300; exempt-identified yes; exempt-reputation-score 24; }
- private-notice { connect-delay 3600; exempt-identified yes; exempt-reputation-score 24; }
+ channel-message { connect-delay 60; exempt-identified yes; exempt-reputation-score 100; }
+ invite { connect-delay 3600; exempt-identified yes; exempt-reputation-score 100; }
+ join { connect-delay 60; exempt-identified yes; exempt-reputation-score 100; }
+ list { connect-delay 120; exempt-identified yes; exempt-reputation-score 100; }
+ private-message { connect-delay 300; exempt-identified yes; exempt-reputation-score 100; }
+ private-notice { connect-delay 3600; exempt-identified yes; exempt-reputation-score 100; }
}
auto-join "#superbowl";
oper-auto-join "#help";
@@ -132,24 +137,37 @@ set {
user-message "4WARNING: You are using an outdated SSL/TLS protocol or cipher";
oper-message "Network operators must connect using an up-to-date SSL/TLS protocol or cipher";
}
+ #handshake-timeout 60s; # Enable for authprompt
anti-flood {
- away-flood 3:300;
+ away-flood 3:300;
connect-flood 3:300;
- invite-flood 3:300;
- join-flood 3:300;
- knock-flood 3:300;
- max-concurrent-conversations { users 5; new-user-every 60s; }
- nick-flood 3:300;
+ invite-flood 3:300;
+ join-flood 3:300;
+ knock-flood 3:300;
+ nick-flood 3:300;
+ max-concurrent-conversations {
+ users 5;
+ new-user-every 60s;
+ }
+ #target-flood {
+ # channel-privmsg 45:5;
+ # channel-notice 15:5;
+ # channel-tagmsg 15:5;
+ # private-privmsg 30:5;
+ # private-notice 10:5;
+ # private-tagmsg 10:5;
+ #}
unknown-flood-amount 2048;
unknown-flood-bantime 1h;
}
- default-bantime 1d;
+ default-bantime 30d;
+ modef-default-unsettime 5;
spamfilter {
ban-time 1d;
ban-reason "8,4 E N T E R T H E V O I D ";
except "#anythinggoes";
}
- max-targets-per-command { kick 1; part 1; privmsg 1; }
+ max-targets-per-command { kick 1; notice 1; part 1; privmsg 1; }
hide-ban-reason yes;
reject-message {
gline "8,4 E N T E R T H E V O I D ";
@@ -163,8 +181,13 @@ set {
score 10;
ban-action block;
ban-reason "8,4 E N T E R T H E V O I D ";
- ban-time 1h;
}
+ #authentication-prompt {
+ # enabled yes;
+ # message "The server requires clients from this IP address to authenticate with a registered nickname and password.";
+ # message "Please reconnect using SASL, or authenticate now by typing: /QUOTE AUTH nick:password";
+ # fail-message "Authentication failed";
+ #}
connthrottle {
known-users { minimum-reputation-score 24; sasl-bypass yes; }
new-users { local-throttle 20:60; global-throttle 30:60; }
@@ -176,7 +199,7 @@ set {
max-storage-per-channel { lines 100; time 1d; }
}
}
- manual-ban-target ip;
+ hide-idle-time { policy always; }
}
hideserver {
diff --git a/extras/build-tests/nix/run-tests b/extras/build-tests/nix/run-tests
@@ -23,8 +23,15 @@ fi
git clone -q https://github.com/unrealircd/unrealircd-tests.git
cd unrealircd-tests
-# Run the test framework, testing both services:
+# FreeBSD has various issues with the tests from us and others,
+# better set a flag to keep it simple:
+FREEBSD=0
if uname -a|grep -q FreeBSD; then
+ FREEBSD=1
+fi
+
+# Run the test framework, testing both services:
+if [ "$FREEBSD" = 1 ]; then
# FreeBSD runs without services since they fail mysteriously:
./run -services none || exit 1
else
@@ -34,7 +41,8 @@ else
fi
# Do cipherscan test at the end
-if [[ "$OSTYPE" != "freebsd"* ]]; then
+# Has problems on non-Linux-64-bit, so we skip there:
+if [ "$FREEBSD" = 0 -a "$HOSTNAME" != "ub18-ia32" ]; then
sleep 2
cd ../extras/tests/tls
./tls-tests
diff --git a/extras/build-tests/windows/compilecmd/vs2019.bat b/extras/build-tests/windows/compilecmd/vs2019.bat
@@ -3,7 +3,7 @@ rem Build command for Visual Studio 2019
nmake -f makefile.windows ^
LIBRESSL_INC_DIR="c:\projects\unrealircd-5-libs\libressl\include" ^
LIBRESSL_LIB_DIR="c:\projects\unrealircd-5-libs\libressl\lib" ^
-SSLLIB="crypto-45.lib ssl-47.lib" ^
+SSLLIB="crypto-46.lib ssl-48.lib" ^
USE_REMOTEINC=1 ^
LIBCURL_INC_DIR="c:\projects\unrealircd-5-libs\curl\include" ^
LIBCURL_LIB_DIR="c:\projects\unrealircd-5-libs\curl\builds\libcurl-vc-x64-release-dll-ssl-dll-cares-dll-ipv6-obj-lib" ^
diff --git a/extras/c-ares.tar.gz b/extras/c-ares.tar.gz
Binary files differ.
diff --git a/extras/curlinstall b/extras/curlinstall
@@ -4,7 +4,7 @@ OUTF="curl-latest.tar.gz"
OUTD="curl-latest"
ARESPATH="`pwd`/extras/c-ares"
UNREALDIR="`pwd`"
-CARESVERSION="1.15.0"
+CARESVERSION="1.16.0"
LIBDIR="$1"
if [ "x$1" = "x" ]; then
diff --git a/extras/doxygen/Doxyfile b/extras/doxygen/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = "UnrealIRCd"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 5.0.4
+PROJECT_NUMBER = 5.0.5
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/extras/pcre2.tar.gz b/extras/pcre2.tar.gz
Binary files differ.
diff --git a/include/h.h b/include/h.h
@@ -174,7 +174,6 @@ extern void set_snomask(Client *client, char *snomask);
extern char *get_snomask_string(Client *client);
extern int check_tkls(Client *cptr);
/* for services */
-extern void del_invite(Client *, Channel *);
extern void send_user_joins(Client *, Client *);
extern int valid_channelname(const char *);
extern int valid_server_name(char *name);
@@ -623,6 +622,8 @@ extern char *spamfilter_inttostring_long(int v);
extern Channel *get_channel(Client *cptr, char *chname, int flag);
extern MODVAR char backupbuf[];
extern void add_invite(Client *, Client *, Channel *, MessageTag *);
+extern void del_invite(Client *, Channel *);
+extern int is_invited(Client *client, Channel *channel);
extern void channel_modes(Client *cptr, char *mbuf, char *pbuf, size_t mbuf_size, size_t pbuf_size, Channel *channel);
extern MODVAR char modebuf[BUFSIZE], parabuf[BUFSIZE];
extern int op_can_override(char *acl, Client *client,Channel *channel,void* extra);
@@ -884,6 +885,7 @@ extern char *certificate_name(SSL *ssl);
extern void start_of_normal_client_handshake(Client *acptr);
extern void clicap_pre_rehash(void);
extern void clicap_post_rehash(void);
+extern void unload_all_unused_mtag_handlers(void);
extern void send_cap_notify(int add, char *token);
extern void sendbufto_one(Client *to, char *msg, unsigned int quick);
extern MODVAR int current_serial;
@@ -970,3 +972,5 @@ extern void link_generator(void);
extern void update_throttling_timer_settings(void);
extern int hide_idle_time(Client *client, Client *target);
extern void lost_server_link(Client *serv, FORMAT_STRING(const char *fmt), ...);
+extern char *sendtype_to_cmd(SendType sendtype);
+extern MODVAR MessageTagHandler *mtaghandlers;
diff --git a/include/modules.h b/include/modules.h
@@ -901,7 +901,7 @@ extern void SavePersistentIntX(ModuleInfo *modinfo, char *varshortname, int var)
#define SavePersistentInt(modinfo, var) SavePersistentIntX(modinfo, #var, var)
extern int LoadPersistentLongX(ModuleInfo *modinfo, char *varshortname, long *var);
-#define LoadPersistentLong(modinfo, var) LoadPersistentIntX(modinfo, #var, &var)
+#define LoadPersistentLong(modinfo, var) LoadPersistentLongX(modinfo, #var, &var)
extern void SavePersistentLongX(ModuleInfo *modinfo, char *varshortname, long var);
#define SavePersistentLong(modinfo, var) SavePersistentLongX(modinfo, #var, var)
@@ -1009,6 +1009,7 @@ extern void SavePersistentLongX(ModuleInfo *modinfo, char *varshortname, long va
#define HOOKTYPE_CAN_SEND_TO_USER 105
#define HOOKTYPE_SERVER_SYNC 106
#define HOOKTYPE_ACCOUNT_LOGIN 107
+#define HOOKTYPE_CLOSE_CONNECTION 108
/* Adding a new hook here?
* 1) Add the #define HOOKTYPE_.... with a new number
@@ -1042,12 +1043,12 @@ char *hooktype_pre_local_kick(Client *client, Client *victim, Channel *channel,
int hooktype_can_kick(Client *client, Client *victim, Channel *channel, char *comment, long client_flags, long victim_flags, char **error);
int hooktype_local_kick(Client *client, Client *victim, Channel *channel, MessageTag *mtags, char *comment);
int hooktype_remote_kick(Client *client, Client *victim, Channel *channel, MessageTag *mtags, char *comment);
-char *hooktype_pre_usermsg(Client *client, Client *to, char *text, int notice);
-int hooktype_usermsg(Client *client, Client *to, MessageTag *mtags, char *text, int notice);
-int hooktype_can_send_to_channel(Client *client, Channel *channel, Membership *member, char **text, char **errmsg, int notice);
-int hooktype_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, int notice);
-int hooktype_pre_chanmsg(Client *client, Channel *channel, MessageTag *mtags, char *text, int notice);
-int hooktype_chanmsg(Client *client, Channel *channel, int sendflags, int prefix, char *target, MessageTag *mtags, char *text, int notice);
+char *hooktype_pre_usermsg(Client *client, Client *to, char *text, SendType sendtype);
+int hooktype_usermsg(Client *client, Client *to, MessageTag *mtags, char *text, SendType sendtype);
+int hooktype_can_send_to_channel(Client *client, Channel *channel, Membership *member, char **text, char **errmsg, SendType sendtype);
+int hooktype_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype);
+int hooktype_pre_chanmsg(Client *client, Channel *channel, MessageTag *mtags, char *text, SendType sendtype);
+int hooktype_chanmsg(Client *client, Channel *channel, int sendflags, int prefix, char *target, MessageTag *mtags, char *text, SendType sendtype);
char *hooktype_pre_local_topic(Client *client, Channel *channel, char *topic);
int hooktype_local_topic(Client *client, Channel *channel, char *topic);
int hooktype_topic(Client *client, Channel *channel, MessageTag *mtags, char *topic);
@@ -1084,7 +1085,7 @@ int hooktype_tkl_add(Client *client, TKL *tkl);
int hooktype_tkl_del(Client *client, TKL *tkl);
int hooktype_log(int flags, char *timebuf, char *buf);
int hooktype_local_spamfilter(Client *acptr, char *str, char *str_in, int type, char *target, TKL *tkl);
-int hooktype_silenced(Client *client, Client *to, int notice);
+int hooktype_silenced(Client *client, Client *to, SendType sendtype);
int hooktype_rawpacket_in(Client *client, char *readbuf, int *length);
int hooktype_packet(Client *from, Client *to, Client *intended_to, char **msg, int *length);
int hooktype_handshake(Client *client);
@@ -1121,6 +1122,7 @@ int hooktype_is_handshake_finished(Client *acptr);
char *hooktype_pre_local_quit_chan(Client *client, Channel *channel, char *comment);
int hooktype_ident_lookup(Client *acptr);
int hooktype_account_login(Client *client, MessageTag *mtags);
+int hooktype_close_connection(Client *client);
#ifdef GCC_TYPECHECKING
#define ValidateHook(validatefunc, func) __builtin_types_compatible_p(__typeof__(func), __typeof__(validatefunc))
@@ -1229,7 +1231,8 @@ _UNREAL_ERROR(_hook_error_incompatible, "Incompatible hook function. Check argum
((hooktype == HOOKTYPE_PRE_LOCAL_QUIT_CHAN) && !ValidateHook(hooktype_pre_local_quit_chan, func)) || \
((hooktype == HOOKTYPE_IDENT_LOOKUP) && !ValidateHook(hooktype_ident_lookup, func)) || \
((hooktype == HOOKTYPE_CONFIGRUN_EX) && !ValidateHook(hooktype_configrun_ex, func)) || \
- ((hooktype == HOOKTYPE_ACCOUNT_LOGIN) && !ValidateHook(hooktype_account_login, func)) ) \
+ ((hooktype == HOOKTYPE_ACCOUNT_LOGIN) && !ValidateHook(hooktype_account_login, func)) || \
+ ((hooktype == HOOKTYPE_CLOSE_CONNECTION) && !ValidateHook(hooktype_close_connection, func)) ) \
_hook_error_incompatible();
#endif /* GCC_TYPECHECKING */
diff --git a/include/struct.h b/include/struct.h
@@ -140,6 +140,12 @@ typedef enum OperClassEntryType { OPERCLASSENTRY_ALLOW=1, OPERCLASSENTRY_DENY=2}
typedef enum OperPermission { OPER_ALLOW=1, OPER_DENY=0} OperPermission;
+typedef enum SendType {
+ SEND_TYPE_PRIVMSG = 0,
+ SEND_TYPE_NOTICE = 1,
+ SEND_TYPE_TAGMSG = 2
+} SendType;
+
struct OperClassValidator;
typedef struct OperClassValidator OperClassValidator;
typedef struct OperClassACLPath OperClassACLPath;
@@ -338,6 +344,8 @@ typedef enum ClientStatus {
#define PROTO_MTAGS 0x010000 /* Support message tags and big buffers */
/* For client capabilities: */
+#define CAP_INVERT 1L
+
/** HasCapabilityFast() checks for a token if you know exactly which bit to check */
#define HasCapabilityFast(cptr, val) ((cptr)->local->caps & (val))
/** HasCapability() checks for a token by name and is slightly slower */
diff --git a/include/windows/setup.h b/include/windows/setup.h
@@ -63,7 +63,7 @@
#define UNREAL_VERSION_MAJOR 0
/* Minor version number (e.g.: 1 for Unreal3.2.1) */
-#define UNREAL_VERSION_MINOR 4
+#define UNREAL_VERSION_MINOR 5
/* Version suffix such as a beta marker or release candidate marker. (e.g.:
-rcX for unrealircd-3.2.9-rcX) */
diff --git a/src/api-clicap.c b/src/api-clicap.c
@@ -98,10 +98,11 @@ void ClearCapability(Client *client, const char *token)
long clicap_allocate_cap(void)
{
- long v = 1;
+ long v;
ClientCapability *clicap;
- for (v=1; v < 2147483648; v = v * 2)
+ /* The first bit (v=1) is used by the "invert" marker */
+ for (v=2; v < LONG_MAX; v = v * 2)
{
unsigned char found = 0;
for (clicap = clicaps; clicap; clicap = clicap->next)
diff --git a/src/api-moddata.c b/src/api-moddata.c
@@ -125,7 +125,6 @@ void moddata_free_local_client(Client *client)
memset(client->moddata, 0, sizeof(client->moddata));
}
-// FIXME: this is never called
void moddata_free_channel(Channel *channel)
{
ModDataInfo *md;
diff --git a/src/channel.c b/src/channel.c
@@ -1031,6 +1031,20 @@ void del_invite(Client *client, Channel *channel)
}
}
+/** Is the user 'client' invited to channel 'channel' by a chanop?
+ * @param client The client who was invited
+ * @param channel The channel to which the person was invited
+ */
+int is_invited(Client *client, Channel *channel)
+{
+ Link *lp;
+
+ for (lp = client->user->invited; lp; lp = lp->next)
+ if (lp->value.channel == channel)
+ return 1;
+ return 0;
+}
+
/** Subtract one user from channel i. Free the channel if it became empty.
* @param channel The channel
* @returns 1 if the channel was freed, 0 if the channel still exists.
@@ -1057,6 +1071,8 @@ int sub1_from_channel(Channel *channel)
* But first we will destroy all kinds of references and lists...
*/
+ moddata_free_channel(channel);
+
while ((lp = channel->invites))
del_invite(lp->value.client, channel);
diff --git a/src/conf.c b/src/conf.c
@@ -1746,6 +1746,8 @@ void config_setdefaultsettings(Configuration *i)
i->manual_ban_target = BAN_TARGET_HOST;
i->hide_idle_time = HIDE_IDLE_TIME_OPER_USERMODE;
+
+ i->who_limit = 100;
}
static void make_default_logblock(void)
@@ -2133,6 +2135,7 @@ int init_conf(char *rootconf, int rehash)
postconf();
config_status("Configuration loaded.");
clicap_post_rehash();
+ unload_all_unused_mtag_handlers();
return 0;
}
@@ -8335,16 +8338,20 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
}
continue; /* required here, due to checknull directly below */
}
- CheckNull(cepp);
if (!strcmp(cepp->ce_varname, "unknown-flood-bantime"))
{
+ CheckNull(cepp);
CheckDuplicate(cepp, anti_flood_unknown_flood_bantime, "anti-flood::unknown-flood-bantime");
}
- else if (!strcmp(cepp->ce_varname, "unknown-flood-amount")) {
+ else if (!strcmp(cepp->ce_varname, "unknown-flood-amount"))
+ {
+ CheckNull(cepp);
CheckDuplicate(cepp, anti_flood_unknown_flood_amount, "anti-flood::unknown-flood-amount");
}
- else if (!strcmp(cepp->ce_varname, "away-count")) {
+ else if (!strcmp(cepp->ce_varname, "away-count"))
+ {
int temp = atol(cepp->ce_vardata);
+ CheckNull(cepp);
CheckDuplicate(cepp, anti_flood_away_count, "anti-flood::away-count");
if (temp < 1 || temp > 255)
{
@@ -8353,7 +8360,9 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
errors++;
}
}
- else if (!strcmp(cepp->ce_varname, "away-period")) {
+ else if (!strcmp(cepp->ce_varname, "away-period"))
+ {
+ CheckNull(cepp);
int temp = config_checkval(cepp->ce_vardata, CFG_TIME);
CheckDuplicate(cepp, anti_flood_away_period, "anti-flood::away-period");
if (temp < 10)
@@ -8366,6 +8375,7 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
else if (!strcmp(cepp->ce_varname, "away-flood"))
{
int cnt, period;
+ CheckNull(cepp);
if (settings.has_anti_flood_away_period)
{
config_warn("%s:%d: set::anti-flood::away-flood overrides set::anti-flood::away-period",
@@ -8392,6 +8402,7 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
else if (!strcmp(cepp->ce_varname, "nick-flood"))
{
int cnt, period;
+ CheckNull(cepp);
CheckDuplicate(cepp, anti_flood_nick_flood, "anti-flood::nick-flood");
if (!config_parse_flood(cepp->ce_vardata, &cnt, &period) ||
(cnt < 1) || (cnt > 255) || (period < 5))
@@ -8405,6 +8416,7 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
else if (!strcmp(cepp->ce_varname, "invite-flood"))
{
int cnt, period;
+ CheckNull(cepp);
CheckDuplicate(cepp, anti_flood_invite_flood, "anti-flood::invite-flood");
if (!config_parse_flood(cepp->ce_vardata, &cnt, &period) ||
(cnt < 1) || (cnt > 255) || (period < 5))
@@ -8418,6 +8430,7 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
else if (!strcmp(cepp->ce_varname, "knock-flood"))
{
int cnt, period;
+ CheckNull(cepp);
CheckDuplicate(cepp, anti_flood_knock_flood, "anti-flood::knock-flood");
if (!config_parse_flood(cepp->ce_vardata, &cnt, &period) ||
(cnt < 1) || (cnt > 255) || (period < 5))
@@ -8431,6 +8444,7 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
else if (!strcmp(cepp->ce_varname, "connect-flood"))
{
int cnt, period;
+ CheckNull(cepp);
CheckDuplicate(cepp, anti_flood_connect_flood, "anti-flood::connect-flood");
if (!config_parse_flood(cepp->ce_vardata, &cnt, &period) ||
(cnt < 1) || (cnt > 255) || (period < 1) || (period > 3600))
diff --git a/src/crule.c b/src/crule.c
@@ -306,7 +306,7 @@ int crule_gettoken(int *next_tokp, char **ruleptr)
void crule_getword(char *word, int *wordlenp, int maxlen, char **ruleptr)
{
- char *word_ptr;
+ char *word_ptr, c;
word_ptr = word;
/* Both - and : can appear in hostnames so they must not be
@@ -315,8 +315,16 @@ void crule_getword(char *word, int *wordlenp, int maxlen, char **ruleptr)
while ((isalnum(**ruleptr)) || (**ruleptr == '*') ||
(**ruleptr == '?') || (**ruleptr == '.') || (**ruleptr == '-') ||
(**ruleptr == ':'))
- *word_ptr++ = *(*ruleptr)++;
- *word_ptr = '\0';
+ {
+ c = *(*ruleptr)++;
+ if (maxlen > 1) /* >1 instead of >0 so we (possibly) still have room for NUL */
+ {
+ *word_ptr++ = c;
+ maxlen--;
+ }
+ }
+ if (maxlen)
+ *word_ptr = '\0';
*wordlenp = word_ptr - word;
}
diff --git a/src/match.c b/src/match.c
@@ -405,7 +405,7 @@ Match *unreal_create_match(MatchType type, char *str, char **error)
int options = 0;
char buf2[512];
- options = PCRE2_CASELESS|PCRE2_NEVER_UTF|PCRE2_NEVER_UCP;
+ options = PCRE2_CASELESS|PCRE2_MATCH_INVALID_UTF;
m->ext.pcre2_expr = pcre2_compile(str, PCRE2_ZERO_TERMINATED, options, &errorcode, &erroroffset, NULL);
if (m->ext.pcre2_expr == NULL)
diff --git a/src/misc.c b/src/misc.c
@@ -1912,3 +1912,15 @@ void freemultiline(MultiLine *l)
safe_free(l);
}
}
+
+/** Convert a sendtype to a command string */
+char *sendtype_to_cmd(SendType sendtype)
+{
+ if (sendtype == SEND_TYPE_PRIVMSG)
+ return "PRIVMSG";
+ if (sendtype == SEND_TYPE_NOTICE)
+ return "NOTICE";
+ if (sendtype == SEND_TYPE_TAGMSG)
+ return "TAGMSG";
+ return NULL;
+}
diff --git a/src/modules/Makefile.in b/src/modules/Makefile.in
@@ -71,7 +71,9 @@ R_MODULES= \
account-tag.so labeled-response.so link-security.so \
message-ids.so plaintext-policy.so server-time.so sts.so \
echo-message.so userip-tag.so userhost-tag.so \
- ident_lookup.so history.so
+ typing-indicator.so \
+ ident_lookup.so history.so \
+ targetfloodprot.so clienttagdeny.so
MODULES=cloak.so $(R_MODULES)
MODULEFLAGS=@MODULEFLAGS@
@@ -610,6 +612,10 @@ userhost-tag.so: userhost-tag.c $(INCLUDES)
$(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
-o userhost-tag.so userhost-tag.c
+typing-indicator.so: typing-indicator.c $(INCLUDES)
+ $(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
+ -o typing-indicator.so typing-indicator.c
+
require-module.so: require-module.c $(INCLUDES)
$(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
-o require-module.so require-module.c
@@ -626,6 +632,14 @@ history.so: history.c $(INCLUDES)
$(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
-o history.so history.c
+targetfloodprot.so: targetfloodprot.c $(INCLUDES)
+ $(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
+ -o targetfloodprot.so targetfloodprot.c
+
+clienttagdeny.so: clienttagdeny.c $(INCLUDES)
+ $(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
+ -o clienttagdeny.so clienttagdeny.c
+
#############################################################################
# capabilities
#############################################################################
diff --git a/src/modules/antimixedutf8.c b/src/modules/antimixedutf8.c
@@ -66,6 +66,10 @@ int antimixedutf8_config_run(ConfigFile *, ConfigEntry *, int);
#define SCRIPT_UNDEFINED 0
#define SCRIPT_LATIN 1
#define SCRIPT_CYRILLIC 2
+#define SCRIPT_CJK 3
+#define SCRIPT_HANGUL 4
+#define SCRIPT_CANADIAN 5
+#define SCRIPT_TELUGU 6
/**** the detection algorithm follows first, the module/config code is at the end ****/
@@ -95,6 +99,24 @@ int detect_script(const char *t)
else if ((t[0] == 0xd3) && (t[1] >= 0x80) && (t[1] <= 0xbf))
return SCRIPT_CYRILLIC;
+ if((t[0] == 0xe4) && (t[1] >= 0xb8) && (t[1] <= 0xbf))
+ return SCRIPT_CJK;
+ else if ((t[0] >= 0xe5) && (t[0] <= 0xe9) && (t[1] >= 0x80) && (t[1] <= 0xbf))
+ return SCRIPT_CJK;
+
+ if((t[0] == 0xea) && (t[1] >= 0xb0) && (t[1] <= 0xbf))
+ return SCRIPT_HANGUL;
+ else if ((t[0] >= 0xeb) && (t[0] <= 0xec) && (t[1] >= 0x80) && (t[1] <= 0xbf))
+ return SCRIPT_HANGUL;
+ else if ((t[0] == 0xed) && (t[1] >= 0x80) && (t[1] <= 0x9f))
+ return SCRIPT_HANGUL;
+
+ if((t[0] == 0xe1) && (t[1] >= 0x90) && (t[1] <= 0x99))
+ return SCRIPT_CANADIAN;
+
+ if((t[0] == 0xe0) && (t[1] >= 0xb0) && (t[1] <= 0xb1))
+ return SCRIPT_TELUGU;
+
if ((t[0] >= 'a') && (t[0] <= 'z'))
return SCRIPT_LATIN;
if ((t[0] >= 'A') && (t[0] <= 'Z'))
diff --git a/src/modules/chanmodes/censor.c b/src/modules/chanmodes/censor.c
@@ -20,7 +20,7 @@ Cmode_t EXTMODE_CENSOR = 0L;
#define IsCensored(x) ((x)->mode.extmode & EXTMODE_CENSOR)
-int censor_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice);
+int censor_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype);
char *censor_pre_local_part(Client *client, Channel *channel, char *text);
char *censor_pre_local_quit(Client *client, char *text);
@@ -253,7 +253,7 @@ char *stripbadwords_channel(char *str, int *blocked)
return stripbadwords(str, conf_badword_channel, blocked);
}
-int censor_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice)
+int censor_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype)
{
int blocked;
Hook *h;
diff --git a/src/modules/chanmodes/delayjoin.c b/src/modules/chanmodes/delayjoin.c
@@ -30,7 +30,7 @@ int moded_part(Client *client, Channel *channel, MessageTag *mtags, char *commen
int deny_all(Client *client, Channel *channel, char mode, char *para, int checkt, int what);
int moded_chanmode(Client *client, Channel *channel,
MessageTag *mtags, char *modebuf, char *parabuf, time_t sendts, int samode);
-int moded_prechanmsg(Client *client, Channel *channel, MessageTag *mtags, char *text, int notice);
+int moded_prechanmsg(Client *client, Channel *channel, MessageTag *mtags, char *text, SendType sendtype);
char *moded_serialize(ModData *m);
void moded_unserialize(char *str, ModData *m);
@@ -367,7 +367,7 @@ int moded_chanmode(Client *client, Channel *channel, MessageTag *recv_mtags, cha
return 0;
}
-int moded_prechanmsg(Client *client, Channel *channel, MessageTag *mtags, char *text, int notice)
+int moded_prechanmsg(Client *client, Channel *channel, MessageTag *mtags, char *text, SendType sendtype)
{
if ((channel_is_delayed(channel) || channel_is_post_delayed(channel)) && (moded_user_invisible(client, channel)))
clear_user_invisible_announce(channel, client, mtags);
diff --git a/src/modules/chanmodes/floodprot.c b/src/modules/chanmodes/floodprot.c
@@ -117,8 +117,8 @@ int cmodef_sjoin_check(Channel *channel, void *ourx, void *theirx);
int floodprot_join(Client *client, Channel *channel, MessageTag *mtags, char *parv[]);
EVENT(modef_event);
int cmodef_channel_destroy(Channel *channel, int *should_destroy);
-int floodprot_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice);
-int floodprot_post_chanmsg(Client *client, Channel *channel, int sendflags, int prefix, char *target, MessageTag *mtags, char *text, int notice);
+int floodprot_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype);
+int floodprot_post_chanmsg(Client *client, Channel *channel, int sendflags, int prefix, char *target, MessageTag *mtags, char *text, SendType sendtype);
int floodprot_knock(Client *client, Channel *channel, MessageTag *mtags, char *comment);
int floodprot_nickchange(Client *client, char *oldnick);
int floodprot_chanmode_del(Channel *channel, int m);
@@ -623,10 +623,11 @@ void *cmodef_put_param(void *fld_in, char *param)
/* if new 'per xxx seconds' is smaller than current 'per' then reset timers/counters (t, c) */
if (v < fld->per)
{
- for (v=0; v < NUMFLD; v++)
+ int i;
+ for (i=0; i < NUMFLD; i++)
{
- fld->timer[v] = 0;
- fld->counter[v] = 0;
+ fld->timer[i] = 0;
+ fld->counter[i] = 0;
}
}
fld->per = v;
@@ -939,7 +940,7 @@ char *channel_modef_string(ChannelFloodProtection *x, char *retbuf)
return retbuf;
}
-int floodprot_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice)
+int floodprot_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype)
{
Membership *mb;
ChannelFloodProtection *chp;
@@ -952,6 +953,8 @@ int floodprot_can_send_to_channel(Client *client, Channel *channel, Membership *
if (!MyUser(client))
return HOOK_CONTINUE;
+ if (sendtype == SEND_TYPE_TAGMSG)
+ return 0; // TODO: some TAGMSG specific limit? (1 of 2)
if (ValidatePermissionsForPath("channel:override:flood",client,NULL,channel,NULL) || !IsFloodLimit(channel) || is_skochanop(client, channel))
return HOOK_CONTINUE;
@@ -1061,11 +1064,14 @@ int floodprot_can_send_to_channel(Client *client, Channel *channel, Membership *
return HOOK_CONTINUE;
}
-int floodprot_post_chanmsg(Client *client, Channel *channel, int sendflags, int prefix, char *target, MessageTag *mtags, char *text, int notice)
+int floodprot_post_chanmsg(Client *client, Channel *channel, int sendflags, int prefix, char *target, MessageTag *mtags, char *text, SendType sendtype)
{
if (!IsFloodLimit(channel) || is_skochanop(client, channel) || IsULine(client))
return 0;
+ if (sendtype == SEND_TYPE_TAGMSG)
+ return 0; // TODO: some TAGMSG specific limit? (2 of 2)
+
/* HINT: don't be so stupid to reorder the items in the if's below.. you'll break things -- Syzop. */
if (do_floodprot(channel, FLD_MSG) && MyUser(client))
diff --git a/src/modules/chanmodes/history.c b/src/modules/chanmodes/history.c
@@ -47,7 +47,7 @@ void history_chanmode_free_param(void *r);
void *history_chanmode_dup_struct(void *r_in);
int history_chanmode_sjoin_check(Channel *channel, void *ourx, void *theirx);
int history_channel_destroy(Channel *channel, int *should_destroy);
-int history_chanmsg(Client *client, Channel *channel, int sendflags, int prefix, char *target, MessageTag *mtags, char *text, int notice);
+int history_chanmsg(Client *client, Channel *channel, int sendflags, int prefix, char *target, MessageTag *mtags, char *text, SendType sendtype);
int history_join(Client *client, Channel *channel, MessageTag *mtags, char *parv[]);
MOD_TEST()
@@ -490,7 +490,7 @@ int history_channel_destroy(Channel *channel, int *should_destroy)
return 0;
}
-int history_chanmsg(Client *client, Channel *channel, int sendflags, int prefix, char *target, MessageTag *mtags, char *text, int notice)
+int history_chanmsg(Client *client, Channel *channel, int sendflags, int prefix, char *target, MessageTag *mtags, char *text, SendType sendtype)
{
char buf[512];
char source[64];
@@ -503,6 +503,10 @@ int history_chanmsg(Client *client, Channel *channel, int sendflags, int prefix,
if ((*text == '\001') && strncmp(text+1, "ACTION", 6))
return 0;
+ /* Filter out TAGMSG */
+ if (sendtype == SEND_TYPE_TAGMSG)
+ return 0;
+
/* Lazy: if any prefix is addressed (eg: @#channel) then don't record it.
* This so we don't have to check privileges during history playback etc.
*/
@@ -516,7 +520,7 @@ int history_chanmsg(Client *client, Channel *channel, int sendflags, int prefix,
snprintf(buf, sizeof(buf), ":%s %s %s :%s",
source,
- notice ? "NOTICE" : "PRIVMSG",
+ sendtype_to_cmd(sendtype),
channel->chname,
text);
diff --git a/src/modules/chanmodes/link.c b/src/modules/chanmodes/link.c
@@ -357,39 +357,43 @@ int link_pre_localjoin_cb(Client *client, Channel *channel, char *parv[])
if (IsULine(client) || find_membership_link(client->user->channel, channel))
return HOOK_CONTINUE;
- // Extbans take precedence over +L #channel and other restrictions
- for(ban = channel->banlist; ban; ban = ban->next)
+ // Extbans take precedence over +L #channel and other restrictions,
+ // only /INVITE from chanop bypasses:
+ if (!is_invited(client, channel))
{
- if (!strncmp(ban->banstr, "~f:", 3))
+ for(ban = channel->banlist; ban; ban = ban->next)
{
- strlcpy(bantmp, ban->banstr + 3, sizeof(bantmp));
- } else
- if (!strncmp(ban->banstr, "~t:", 3))
- {
- /* A timed ban, but is it for us? Need to parse a little:
- * ~t:dddd:~f:...
- */
- char *p = strchr(ban->banstr + 3, ':');
- if (p && !strncmp(p, ":~f:", 4))
+ if (!strncmp(ban->banstr, "~f:", 3))
+ {
+ strlcpy(bantmp, ban->banstr + 3, sizeof(bantmp));
+ } else
+ if (!strncmp(ban->banstr, "~t:", 3))
+ {
+ /* A timed ban, but is it for us? Need to parse a little:
+ * ~t:dddd:~f:...
+ */
+ char *p = strchr(ban->banstr + 3, ':');
+ if (p && !strncmp(p, ":~f:", 4))
+ {
+ strlcpy(bantmp, p + 4, sizeof(bantmp));
+ } else {
+ /* Not for us - some other ~t ban */
+ continue;
+ }
+ } else
{
- strlcpy(bantmp, p + 4, sizeof(bantmp));
- } else {
- /* Not for us - some other ~t ban */
+ /* Not for us */
continue;
}
- } else
- {
- /* Not for us */
- continue;
+ banchan = bantmp;
+ banmask = strchr(bantmp, ':');
+ if (!banmask || !banmask[1])
+ continue;
+ *banmask++ = '\0';
+
+ if (ban_check_mask(client, channel, banmask, BANCHK_JOIN, NULL, NULL, 0))
+ return link_doforward(client, channel, banchan, LINKTYPE_BAN);
}
- banchan = bantmp;
- banmask = strchr(bantmp, ':');
- if (!banmask || !banmask[1])
- continue;
- *banmask++ = '\0';
-
- if (ban_check_mask(client, channel, banmask, BANCHK_JOIN, NULL, NULL, 0))
- return link_doforward(client, channel, banchan, LINKTYPE_BAN);
}
// Either +L is not set, or it is set but the parameter isn't stored somehow
@@ -397,7 +401,7 @@ int link_pre_localjoin_cb(Client *client, Channel *channel, char *parv[])
return HOOK_CONTINUE;
// can_join() actually returns 0 if we *can* join a channel, so we don't need to bother checking any further conditions
- if (!(canjoin = can_join(client, channel, NULL, parv)))
+ if (!(canjoin = can_join(client, channel, parv[2], parv)))
return HOOK_CONTINUE;
// Oper only channel
diff --git a/src/modules/chanmodes/nocolor.c b/src/modules/chanmodes/nocolor.c
@@ -34,7 +34,7 @@ Cmode_t EXTCMODE_NOCOLOR;
#define IsNoColor(channel) (channel->mode.extmode & EXTCMODE_NOCOLOR)
-int nocolor_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice);
+int nocolor_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype);
char *nocolor_prelocalpart(Client *client, Channel *channel, char *comment);
char *nocolor_prelocalquit(Client *client, char *comment);
@@ -85,7 +85,7 @@ static int IsUsingColor(char *s)
return 0;
}
-int nocolor_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice)
+int nocolor_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype)
{
Hook *h;
int i;
diff --git a/src/modules/chanmodes/noctcp.c b/src/modules/chanmodes/noctcp.c
@@ -34,7 +34,7 @@ Cmode_t EXTCMODE_NOCTCP;
#define IsNoCTCP(channel) (channel->mode.extmode & EXTCMODE_NOCTCP)
-int noctcp_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice);
+int noctcp_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype);
MOD_TEST()
{
@@ -78,7 +78,7 @@ static int IsACTCP(char *s)
return 0;
}
-int noctcp_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice)
+int noctcp_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype)
{
if (IsNoCTCP(channel) && IsACTCP(*msg))
{
diff --git a/src/modules/chanmodes/nonotice.c b/src/modules/chanmodes/nonotice.c
@@ -32,7 +32,7 @@ Cmode_t EXTCMODE_NONOTICE;
#define IsNoNotice(channel) (channel->mode.extmode & EXTCMODE_NONOTICE)
-int nonotice_check_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice);
+int nonotice_check_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype);
MOD_TEST()
{
@@ -65,13 +65,14 @@ MOD_UNLOAD()
return MOD_SUCCESS;
}
-int nonotice_check_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice)
+int nonotice_check_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype)
{
Hook *h;
int i;
- if (notice && IsNoNotice(channel) &&
- (!lp || !(lp->flags & (CHFL_CHANOP | CHFL_CHANOWNER | CHFL_CHANADMIN))))
+ if ((sendtype == SEND_TYPE_NOTICE) &&
+ IsNoNotice(channel) &&
+ (!lp || !(lp->flags & (CHFL_CHANOP | CHFL_CHANOWNER | CHFL_CHANADMIN))))
{
for (h = Hooks[HOOKTYPE_CAN_BYPASS_CHANNEL_MESSAGE_RESTRICTION]; h; h = h->next)
{
diff --git a/src/modules/chanmodes/regonlyspeak.c b/src/modules/chanmodes/regonlyspeak.c
@@ -34,7 +34,7 @@ static char errMsg[2048];
#define IsRegOnlySpeak(channel) (channel->mode.extmode & EXTCMODE_REGONLYSPEAK)
-int regonlyspeak_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice);
+int regonlyspeak_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype);
char *regonlyspeak_part_message (Client *client, Channel *channel, char *comment);
MOD_TEST()
@@ -81,7 +81,7 @@ char *regonlyspeak_part_message (Client *client, Channel *channel, char *comment
return comment;
}
-int regonlyspeak_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice)
+int regonlyspeak_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype)
{
Hook *h;
int i;
diff --git a/src/modules/chanmodes/secureonly.c b/src/modules/chanmodes/secureonly.c
@@ -140,11 +140,10 @@ int secureonly_check_join(Client *client, Channel *channel, char *key, char *par
/* if the channel is +z we still allow an ircop to bypass it
* if they are invited.
*/
- for (lp = client->user->invited; lp; lp = lp->next)
- if (lp->value.channel == channel)
- return HOOK_CONTINUE;
+ if (is_invited(client, channel))
+ return HOOK_CONTINUE;
}
- return (ERR_SECUREONLYCHAN);
+ return ERR_SECUREONLYCHAN;
}
return 0;
}
diff --git a/src/modules/chanmodes/stripcolor.c b/src/modules/chanmodes/stripcolor.c
@@ -34,7 +34,7 @@ Cmode_t EXTCMODE_STRIPCOLOR;
#define IsStripColor(channel) (channel->mode.extmode & EXTCMODE_STRIPCOLOR)
-int stripcolor_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice);
+int stripcolor_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype);
char *stripcolor_prelocalpart(Client *client, Channel *channel, char *comment);
char *stripcolor_prelocalquit(Client *client, char *comment);
@@ -73,7 +73,7 @@ MOD_UNLOAD()
return MOD_SUCCESS;
}
-int stripcolor_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice)
+int stripcolor_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype)
{
Hook *h;
int i;
diff --git a/src/modules/channeldb.c b/src/modules/channeldb.c
@@ -67,7 +67,7 @@ struct cfgstruct {
};
static struct cfgstruct cfg;
-static int channeldb_loaded = 0;
+static long channeldb_next_event = 0;
MOD_TEST()
{
@@ -80,7 +80,7 @@ MOD_INIT()
{
MARK_AS_OFFICIAL_MODULE(modinfo);
- LoadPersistentInt(modinfo, channeldb_loaded);
+ LoadPersistentLong(modinfo, channeldb_next_event);
setcfg();
@@ -90,7 +90,7 @@ MOD_INIT()
MOD_LOAD()
{
- if (!channeldb_loaded)
+ if (!channeldb_next_event)
{
/* If this is the first time that our module is loaded, then read the database. */
if (!read_channeldb())
@@ -102,9 +102,9 @@ MOD_LOAD()
else
config_warn("[channeldb] Failed to rename database from %s to %s: %s", cfg.database, fname, strerror(errno));
}
- channeldb_loaded = 1;
+ channeldb_next_event = TStime() + CHANNELDB_SAVE_EVERY;
}
- EventAdd(modinfo->handle, "channeldb_write_channeldb", write_channeldb_evt, NULL, CHANNELDB_SAVE_EVERY*1000, 0);
+ EventAdd(modinfo->handle, "channeldb_write_channeldb", write_channeldb_evt, NULL, 1000, 0);
if (ModuleGetError(modinfo->handle) != MODERR_NOERROR)
{
config_error("A critical error occurred when loading module %s: %s", MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle));
@@ -115,9 +115,8 @@ MOD_LOAD()
MOD_UNLOAD()
{
- write_channeldb();
freecfg();
- SavePersistentInt(modinfo, channeldb_loaded);
+ SavePersistentLong(modinfo, channeldb_next_event);
return MOD_SUCCESS;
}
@@ -191,6 +190,9 @@ int channeldb_configrun(ConfigFile *cf, ConfigEntry *ce, int type)
EVENT(write_channeldb_evt)
{
+ if (channeldb_next_event > TStime())
+ return;
+ channeldb_next_event = TStime() + CHANNELDB_SAVE_EVERY;
write_channeldb();
}
diff --git a/src/modules/clienttagdeny.c b/src/modules/clienttagdeny.c
@@ -0,0 +1,77 @@
+/*
+ * IRC - Internet Relay Chat, src/modules/echo-message.c
+ * (C) 2020 k4be for The UnrealIRCd Team
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "unrealircd.h"
+
+char *ct_isupport_param(void);
+int tags_rehash_complete(void);
+
+Module *module;
+
+ModuleHeader MOD_HEADER = {
+ "clienttagdeny",
+ "5.0",
+ "Informs clients about supported client tags",
+ "k4be",
+ "unrealircd-5",
+};
+
+MOD_INIT(){
+ MARK_AS_OFFICIAL_MODULE(modinfo);
+
+ return MOD_SUCCESS;
+}
+
+MOD_LOAD(){
+ module = modinfo->handle;
+ ISupportAdd(module, "CLIENTTAGDENY", ct_isupport_param());
+ HookAdd(module, HOOKTYPE_REHASH_COMPLETE, 0, tags_rehash_complete);
+
+ return MOD_SUCCESS;
+}
+
+MOD_UNLOAD(){
+ return MOD_SUCCESS;
+}
+
+#define BUFLEN 500
+
+char *ct_isupport_param(void){
+ static char buf[BUFLEN];
+ MessageTagHandler *m;
+
+ strlcpy(buf, "*", sizeof(buf));
+
+ for (m = mtaghandlers; m; m = m->next) {
+ if(!m->unloaded && m->name[0] == '+'){
+ strlcat(buf, ",-", sizeof(buf));
+ strlcat(buf, m->name+1, sizeof(buf));
+ }
+ }
+ return buf;
+}
+
+int tags_rehash_complete(void){
+ ISupportSet(module, "CLIENTTAGDENY", ct_isupport_param());
+ return HOOK_CONTINUE;
+}
+
diff --git a/src/modules/dccdeny.c b/src/modules/dccdeny.c
@@ -44,8 +44,8 @@ int dccdeny_stats(Client *client, char *para);
CMD_FUNC(cmd_dccdeny);
CMD_FUNC(cmd_undccdeny);
CMD_FUNC(cmd_svsfline);
-int dccdeny_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, int notice);
-int dccdeny_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice);
+int dccdeny_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype);
+int dccdeny_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype);
int dccdeny_server_sync(Client *client);
static ConfigItem_deny_dcc *dcc_isforbidden(Client *client, char *filename);
static ConfigItem_deny_dcc *dcc_isdiscouraged(Client *client, char *filename);
@@ -489,7 +489,7 @@ int dccdeny_server_sync(Client *client)
}
/** Check if a DCC should be blocked (user-to-user) */
-int dccdeny_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, int notice)
+int dccdeny_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype)
{
if (**text == '\001')
{
@@ -507,7 +507,7 @@ int dccdeny_can_send_to_user(Client *client, Client *target, char **text, char *
}
/** Check if a DCC should be blocked (user-to-channel, unusual) */
-int dccdeny_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice)
+int dccdeny_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype)
{
static char errbuf[512];
@@ -517,7 +517,7 @@ int dccdeny_can_send_to_channel(Client *client, Channel *channel, Membership *lp
char *filename = get_dcc_filename(*msg);
if (filename && !can_dcc(client, channel->chname, NULL, filename, &err))
{
- if (!IsDead(client) && !notice)
+ if (!IsDead(client) && (sendtype != SEND_TYPE_NOTICE))
{
strlcpy(errbuf, err, sizeof(errbuf));
*errmsg = errbuf;
diff --git a/src/modules/echo-message.c b/src/modules/echo-message.c
@@ -35,8 +35,8 @@ ModuleHeader MOD_HEADER
long CAP_ECHO_MESSAGE = 0L;
/* Forward declarations */
-int em_chanmsg(Client *client, Channel *channel, int sendflags, int prefix, char *target, MessageTag *mtags, char *text, int notice);
-int em_usermsg(Client *client, Client *to, MessageTag *mtags, char *text, int notice);
+int em_chanmsg(Client *client, Channel *channel, int sendflags, int prefix, char *target, MessageTag *mtags, char *text, SendType sendtype);
+int em_usermsg(Client *client, Client *to, MessageTag *mtags, char *text, SendType sendtype);
MOD_INIT()
{
@@ -64,28 +64,44 @@ MOD_UNLOAD()
return MOD_SUCCESS;
}
-int em_chanmsg(Client *client, Channel *channel, int sendflags, int prefix, char *target, MessageTag *mtags, char *text, int notice)
+int em_chanmsg(Client *client, Channel *channel, int sendflags, int prefix, char *target, MessageTag *mtags, char *text, SendType sendtype)
{
if (MyUser(client) && HasCapabilityFast(client, CAP_ECHO_MESSAGE))
{
- sendto_prefix_one(client, client, mtags, ":%s %s %s :%s",
- client->name,
- notice ? "NOTICE" : "PRIVMSG",
- target,
- text);
+ if (sendtype != SEND_TYPE_TAGMSG)
+ {
+ sendto_prefix_one(client, client, mtags, ":%s %s %s :%s",
+ client->name,
+ sendtype_to_cmd(sendtype),
+ target,
+ text);
+ } else {
+ sendto_prefix_one(client, client, mtags, ":%s %s %s",
+ client->name,
+ sendtype_to_cmd(sendtype),
+ target);
+ }
}
return 0;
}
-int em_usermsg(Client *client, Client *to, MessageTag *mtags, char *text, int notice)
+int em_usermsg(Client *client, Client *to, MessageTag *mtags, char *text, SendType sendtype)
{
if (MyUser(client) && HasCapabilityFast(client, CAP_ECHO_MESSAGE))
{
- sendto_prefix_one(client, client, mtags, ":%s %s %s :%s",
- client->name,
- notice ? "NOTICE" : "PRIVMSG",
- to->name,
- text);
+ if (sendtype != SEND_TYPE_TAGMSG)
+ {
+ sendto_prefix_one(client, client, mtags, ":%s %s %s :%s",
+ client->name,
+ sendtype_to_cmd(sendtype),
+ to->name,
+ text);
+ } else {
+ sendto_prefix_one(client, client, mtags, ":%s %s %s",
+ client->name,
+ sendtype_to_cmd(sendtype),
+ to->name);
+ }
}
return 0;
}
diff --git a/src/modules/join.c b/src/modules/join.c
@@ -113,9 +113,8 @@ int _can_join(Client *client, Channel *channel, char *key, char *parv[])
if (banned && j == HOOK_DENY)
return (ERR_BANNEDFROMCHAN);
- for (lp = client->user->invited; lp; lp = lp->next)
- if (lp->value.channel == channel)
- return 0;
+ if (is_invited(client, channel))
+ return 0; /* allowed */
if (channel->users >= channel->mode.limit)
{
@@ -515,20 +514,12 @@ void _do_join(Client *client, int parc, char *parv[])
!strcasecmp(name, SPAMFILTER_VIRUSCHAN) &&
!ValidatePermissionsForPath("immune:server-ban:viruschan",client,NULL,NULL,NULL) && !spamf_ugly_vchanoverride)
{
- int invited = 0;
- Link *lp;
Channel *channel = find_channel(name, NULL);
- if (channel)
+ if (!channel || !is_invited(client, channel))
{
- for (lp = client->user->invited; lp; lp = lp->next)
- if (lp->value.channel == channel)
- invited = 1;
- }
- if (!invited)
- {
- sendnotice(client, "*** Cannot join '%s' because it's the virus-help-channel which is "
- "reserved for infected users only", name);
+ sendnotice(client, "*** Cannot join '%s' because it's the virus-help-channel "
+ "which is reserved for infected users only", name);
continue;
}
}
@@ -549,7 +540,17 @@ void _do_join(Client *client, int parc, char *parv[])
Hook *h;
for (h = Hooks[HOOKTYPE_PRE_LOCAL_JOIN]; h; h = h->next)
{
- i = (*(h->func.intfunc))(client,channel,parv);
+ /* Note: this is just a hack not to break the ABI but still be
+ * able to fix https://bugs.unrealircd.org/view.php?id=5644
+ * In the future we should just drop the parv/parx argument
+ * and use key as an argument instead.
+ */
+ char *parx[4];
+ parx[0] = NULL;
+ parx[1] = name;
+ parx[2] = key;
+ parx[3] = NULL;
+ i = (*(h->func.intfunc))(client,channel,parx);
if (i == HOOK_DENY || i == HOOK_ALLOW)
break;
}
diff --git a/src/modules/labeled-response.c b/src/modules/labeled-response.c
@@ -45,6 +45,7 @@ struct LabeledResponseContext {
/* Forward declarations */
int lr_pre_command(Client *from, MessageTag *mtags, char *buf);
int lr_post_command(Client *from, MessageTag *mtags, char *buf);
+int lr_close_connection(Client *client);
int lr_packet(Client *from, Client *to, Client *intended_to, char **msg, int *len);
void *_labeled_response_save_context(void);
void _labeled_response_set_context(void *ctx);
@@ -94,6 +95,7 @@ MOD_INIT()
HookAdd(modinfo->handle, HOOKTYPE_PRE_COMMAND, 2000000000, lr_pre_command);
HookAdd(modinfo->handle, HOOKTYPE_POST_COMMAND, -2000000000, lr_post_command);
+ HookAdd(modinfo->handle, HOOKTYPE_CLOSE_CONNECTION, 2000000000, lr_close_connection);
HookAdd(modinfo->handle, HOOKTYPE_PACKET, 0, lr_packet);
return MOD_SUCCESS;
@@ -179,11 +181,12 @@ int lr_post_command(Client *from, MessageTag *mtags, char *buf)
if (currentcmd.responses == 0)
{
- /* Note: we blindly send recv_mtags back here,
- * which is OK now, but may not be OK later.
- */
+ MessageTag *m = safe_alloc(sizeof(MessageTag));
+ safe_strdup(m->name, "label");
+ safe_strdup(m->value, currentcmd.label);
memset(¤tcmd, 0, sizeof(currentcmd));
- sendto_one(from, mtags, ":%s ACK", me.name);
+ sendto_one(from, m, ":%s ACK", me.name);
+ free_message_tags(m);
goto done;
} else
if (currentcmd.responses == 1)
@@ -219,6 +222,13 @@ done:
return 0;
}
+int lr_close_connection(Client *client)
+{
+ /* Flush all data before closing connection */
+ lr_post_command(client, NULL, NULL);
+ return 0;
+}
+
/** Helper function for lr_packet() to skip the message tags prefix,
* and possibly @batch as well.
*/
diff --git a/src/modules/message-tags.c b/src/modules/message-tags.c
@@ -34,7 +34,6 @@ ModuleHeader MOD_HEADER
long CAP_MESSAGE_TAGS = 0L;
char *_mtags_to_string(MessageTag *m, Client *client);
void _parse_message_tags(Client *client, char **str, MessageTag **mtag_list);
-CMD_FUNC(cmd_tagmsg);
MOD_TEST()
{
@@ -55,7 +54,6 @@ MOD_INIT()
memset(&cap, 0, sizeof(cap));
cap.name = "message-tags";
ClientCapabilityAdd(modinfo->handle, &cap, &CAP_MESSAGE_TAGS);
- CommandAdd(modinfo->handle, "TAGMSG", cmd_tagmsg, 1, CMD_USER);
return MOD_SUCCESS;
}
@@ -296,11 +294,3 @@ char *_mtags_to_string(MessageTag *m, Client *client)
return buf;
}
-
-/* Dummy handler for TAGMSG.
- * We do not permit user tags, so implementing a real TAGMSG makes no sense.
- * By having a dummy command we avoid clients from getting "Unknown command".
- */
-CMD_FUNC(cmd_tagmsg)
-{
-}
diff --git a/src/modules/message.c b/src/modules/message.c
@@ -20,20 +20,19 @@
#include "unrealircd.h"
+/* Forward declarations */
char *_StripColors(unsigned char *text);
char *_StripControlCodes(unsigned char *text);
-
int ban_version(Client *client, char *text);
-
CMD_FUNC(cmd_private);
CMD_FUNC(cmd_notice);
-void cmd_message(Client *client, MessageTag *recv_mtags, int parc, char *parv[], int notice);
-int _can_send_to_channel(Client *client, Channel *channel, char **msgtext, char **errmsg, int notice);
-int can_send_to_user(Client *client, Client *target, char **msgtext, char **errmsg, int notice);
+CMD_FUNC(cmd_tagmsg);
+void cmd_message(Client *client, MessageTag *recv_mtags, int parc, char *parv[], SendType sendtype);
+int _can_send_to_channel(Client *client, Channel *channel, char **msgtext, char **errmsg, SendType sendtype);
+int can_send_to_user(Client *client, Client *target, char **msgtext, char **errmsg, SendType sendtype);
-/* Place includes here */
-#define MSG_PRIVATE "PRIVMSG" /* PRIV */
-#define MSG_NOTICE "NOTICE" /* NOTI */
+/* Variables */
+long CAP_MESSAGE_TAGS = 0; /**< Looked up at MOD_LOAD, may stay 0 if message-tags support is absent */
ModuleHeader MOD_HEADER
= {
@@ -56,8 +55,9 @@ MOD_TEST()
/* This is called on module init, before Server Ready */
MOD_INIT()
{
- CommandAdd(modinfo->handle, MSG_PRIVATE, cmd_private, 2, CMD_USER|CMD_SERVER|CMD_RESETIDLE|CMD_VIRUS);
- CommandAdd(modinfo->handle, MSG_NOTICE, cmd_notice, 2, CMD_USER|CMD_SERVER);
+ CommandAdd(modinfo->handle, "PRIVMSG", cmd_private, 2, CMD_USER|CMD_SERVER|CMD_RESETIDLE|CMD_VIRUS);
+ CommandAdd(modinfo->handle, "NOTICE", cmd_notice, 2, CMD_USER|CMD_SERVER);
+ CommandAdd(modinfo->handle, "TAGMSG", cmd_tagmsg, 1, CMD_USER|CMD_SERVER);
MARK_AS_OFFICIAL_MODULE(modinfo);
return MOD_SUCCESS;
}
@@ -65,6 +65,8 @@ MOD_INIT()
/* Is first run when server is 100% ready */
MOD_LOAD()
{
+ CAP_MESSAGE_TAGS = ClientCapabilityBit("message-tags");
+
return MOD_SUCCESS;
}
@@ -79,11 +81,11 @@ MOD_UNLOAD()
/** Check if PRIVMSG's are permitted from a person to another person.
* client: source client
* target: target client
- * notice: 1 if notice, 0 if privmsg
+ * sendtype: One of SEND_TYPE_*
* text: Pointer to a pointer to a text [in, out]
* cmd: Pointer to a pointer which contains the command to use [in, out]
*/
-int can_send_to_user(Client *client, Client *target, char **msgtext, char **errmsg, int notice)
+int can_send_to_user(Client *client, Client *target, char **msgtext, char **errmsg, SendType sendtype)
{
int ret;
Hook *h;
@@ -109,19 +111,19 @@ int can_send_to_user(Client *client, Client *target, char **msgtext, char **errm
if (is_silenced(client, target))
{
- RunHook3(HOOKTYPE_SILENCED, client, target, notice);
+ RunHook3(HOOKTYPE_SILENCED, client, target, sendtype);
/* Silently discarded, no error message */
return 0;
}
// Possible FIXME: make match_spamfilter also use errmsg, or via a wrapper? or use same numeric?
- if (MyUser(client) && match_spamfilter(client, *msgtext, (notice ? SPAMF_USERNOTICE : SPAMF_USERMSG), target->name, 0, NULL))
+ if (MyUser(client) && match_spamfilter(client, *msgtext, (sendtype == SEND_TYPE_NOTICE ? SPAMF_USERNOTICE : SPAMF_USERMSG), target->name, 0, NULL))
return 0;
n = HOOK_CONTINUE;
for (h = Hooks[HOOKTYPE_CAN_SEND_TO_USER]; h; h = h->next)
{
- n = (*(h->func.intfunc))(client, target, msgtext, errmsg, notice);
+ n = (*(h->func.intfunc))(client, target, msgtext, errmsg, sendtype);
if (n == HOOK_DENY)
{
if (!*errmsg)
@@ -132,13 +134,14 @@ int can_send_to_user(Client *client, Client *target, char **msgtext, char **errm
return 0;
}
if (!*msgtext || !**msgtext)
- return 0;
+ {
+ if (sendtype != SEND_TYPE_TAGMSG)
+ return 0;
+ else
+ *msgtext = "";
+ }
}
- /* This may happen, if nothing is left to send anymore (don't send empty messages) */
- if (!*msgtext || !**msgtext)
- return 0;
-
return 1;
}
@@ -249,18 +252,19 @@ int can_send_to_prefix(Client *client, Channel *channel, int prefix)
return 1;
}
-/*
-** cmd_message (used in cmd_private() and cmd_notice())
-** the general function to deliver MSG's between users/channels
-**
-** parv[1] = receiver list
-** parv[2] = message text
-**
-** massive cleanup
-** rev argv 6/91
-**
-*/
-void cmd_message(Client *client, MessageTag *recv_mtags, int parc, char *parv[], int notice)
+int has_client_mtags(MessageTag *mtags)
+{
+ MessageTag *m;
+
+ for (m = mtags; m; m = m->next)
+ if (*m->name == '+')
+ return 1;
+ return 0;
+}
+
+/* General message handler to users and channels. Used by PRIVMSG, NOTICE, etc.
+ */
+void cmd_message(Client *client, MessageTag *recv_mtags, int parc, char *parv[], SendType sendtype)
{
Client *target;
Channel *channel;
@@ -269,7 +273,7 @@ void cmd_message(Client *client, MessageTag *recv_mtags, int parc, char *parv[],
char pfixchan[CHANNELLEN + 4];
int ret;
int ntargets = 0;
- char *cmd = notice ? "NOTICE" : "PRIVMSG";
+ char *cmd = sendtype_to_cmd(sendtype);
int maxtargets = max_targets_for_command(cmd);
Hook *h;
MessageTag *mtags;
@@ -287,7 +291,7 @@ void cmd_message(Client *client, MessageTag *recv_mtags, int parc, char *parv[],
return;
}
- if (parc < 3 || *parv[2] == '\0')
+ if ((sendtype != SEND_TYPE_TAGMSG) && (parc < 3 || *parv[2] == '\0'))
{
sendnumeric(client, ERR_NOTEXTTOSEND);
return;
@@ -303,6 +307,7 @@ void cmd_message(Client *client, MessageTag *recv_mtags, int parc, char *parv[],
sendnumeric(client, ERR_TOOMANYTARGETS, targetstr, maxtargets, cmd);
break;
}
+
/* The nicks "ircd" and "irc" are special (and reserved) */
if (!strcasecmp(targetstr, "ircd") && MyUser(client))
return;
@@ -352,7 +357,7 @@ void cmd_message(Client *client, MessageTag *recv_mtags, int parc, char *parv[],
errmsg = NULL;
if (MyUser(client) && !IsULine(client))
{
- if (!can_send_to_channel(client, channel, &text, &errmsg, notice))
+ if (!can_send_to_channel(client, channel, &text, &errmsg, sendtype))
{
/* Send the error message, but only if:
* 1) The user has not been killed
@@ -360,7 +365,7 @@ void cmd_message(Client *client, MessageTag *recv_mtags, int parc, char *parv[],
*/
if (IsDead(client))
return;
- if (!IsDead(client) && !notice && errmsg)
+ if (!IsDead(client) && (sendtype != SEND_TYPE_NOTICE) && errmsg)
sendnumeric(client, ERR_CANNOTSENDTOCHAN, channel->chname, errmsg, p2);
continue; /* skip delivery to this target */
}
@@ -374,12 +379,12 @@ void cmd_message(Client *client, MessageTag *recv_mtags, int parc, char *parv[],
if ((*parv[2] == '\001') && strncmp(&parv[2][1], "ACTION ", 7))
sendflags |= SKIP_CTCP;
- if (MyUser(client) && match_spamfilter(client, text, notice ? SPAMF_CHANNOTICE : SPAMF_CHANMSG, channel->chname, 0, NULL))
+ if (MyUser(client) && match_spamfilter(client, text, (sendtype == SEND_TYPE_NOTICE ? SPAMF_CHANNOTICE : SPAMF_CHANMSG), channel->chname, 0, NULL))
return;
new_message(client, recv_mtags, &mtags);
- RunHook5(HOOKTYPE_PRE_CHANMSG, client, channel, mtags, text, notice);
+ RunHook5(HOOKTYPE_PRE_CHANMSG, client, channel, mtags, text, sendtype);
if (!text)
{
@@ -387,12 +392,31 @@ void cmd_message(Client *client, MessageTag *recv_mtags, int parc, char *parv[],
continue;
}
- sendto_channel(channel, client, client->direction,
- prefix, 0, sendflags, mtags,
- notice ? ":%s NOTICE %s :%s" : ":%s PRIVMSG %s :%s",
- client->name, targetstr, text);
+ if (sendtype != SEND_TYPE_TAGMSG)
+ {
+ /* PRIVMSG or NOTICE */
+ sendto_channel(channel, client, client->direction,
+ prefix, 0, sendflags, mtags,
+ ":%s %s %s :%s",
+ client->name, cmd, targetstr, text);
+ } else {
+ /* TAGMSG:
+ * Only send if the message includes any user message tags
+ * and if the 'message-tags' module is loaded.
+ * Do not allow empty and useless TAGMSG.
+ */
+ if (!CAP_MESSAGE_TAGS || !has_client_mtags(mtags))
+ {
+ free_message_tags(mtags);
+ continue;
+ }
+ sendto_channel(channel, client, client->direction,
+ prefix, CAP_MESSAGE_TAGS, sendflags, mtags,
+ ":%s TAGMSG %s",
+ client->name, targetstr);
+ }
- RunHook8(HOOKTYPE_CHANMSG, client, channel, sendflags, prefix, targetstr, mtags, text, notice);
+ RunHook8(HOOKTYPE_CHANMSG, client, channel, sendflags, prefix, targetstr, mtags, text, sendtype);
free_message_tags(mtags);
@@ -436,12 +460,12 @@ void cmd_message(Client *client, MessageTag *recv_mtags, int parc, char *parv[],
{
char *errmsg = NULL;
text = parv[2];
- if (!can_send_to_user(client, target, &text, &errmsg, notice))
+ if (!can_send_to_user(client, target, &text, &errmsg, sendtype))
{
/* Message is discarded */
if (IsDead(client))
return;
- if (!notice && errmsg)
+ if ((sendtype != SEND_TYPE_NOTICE) && errmsg)
sendnumeric(client, ERR_CANTSENDTOUSER, target->name, errmsg);
} else
{
@@ -449,23 +473,43 @@ void cmd_message(Client *client, MessageTag *recv_mtags, int parc, char *parv[],
MessageTag *mtags = NULL;
/* Inform sender that recipient is away, if this is so */
- if (!notice && MyConnect(client) && target->user && target->user->away)
+ if ((sendtype == SEND_TYPE_PRIVMSG) && MyConnect(client) && target->user && target->user->away)
sendnumeric(client, RPL_AWAY, target->name, target->user->away);
new_message(client, recv_mtags, &mtags);
+ if ((sendtype == SEND_TYPE_TAGMSG) && !has_client_mtags(mtags))
+ {
+ free_message_tags(mtags);
+ continue;
+ }
labeled_response_inhibit = 1;
if (MyUser(target))
{
/* Deliver to end-user */
- sendto_prefix_one(target, client, mtags, ":%s %s %s :%s",
- client->name, cmd, target->name, text);
+ if (sendtype == SEND_TYPE_TAGMSG)
+ {
+ if (HasCapability(target, "message-tags"))
+ {
+ sendto_prefix_one(target, client, mtags, ":%s %s %s",
+ client->name, cmd, target->name);
+ }
+ } else {
+ sendto_prefix_one(target, client, mtags, ":%s %s %s :%s",
+ client->name, cmd, target->name, text);
+ }
} else {
/* Send to another server */
- sendto_prefix_one(target, client, mtags, ":%s %s %s :%s",
- client->id, cmd, target->id, text);
+ if (sendtype == SEND_TYPE_TAGMSG)
+ {
+ sendto_prefix_one(target, client, mtags, ":%s %s %s",
+ client->id, cmd, target->id);
+ } else {
+ sendto_prefix_one(target, client, mtags, ":%s %s %s :%s",
+ client->id, cmd, target->id, text);
+ }
}
labeled_response_inhibit = 0;
- RunHook5(HOOKTYPE_USERMSG, client, target, mtags, text, notice);
+ RunHook5(HOOKTYPE_USERMSG, client, target, mtags, text, sendtype);
free_message_tags(mtags);
continue;
}
@@ -496,7 +540,7 @@ void cmd_message(Client *client, MessageTag *recv_mtags, int parc, char *parv[],
*/
CMD_FUNC(cmd_private)
{
- cmd_message(client, recv_mtags, parc, parv, 0);
+ cmd_message(client, recv_mtags, parc, parv, SEND_TYPE_PRIVMSG);
}
/*
@@ -506,7 +550,19 @@ CMD_FUNC(cmd_private)
*/
CMD_FUNC(cmd_notice)
{
- cmd_message(client, recv_mtags, parc, parv, 1);
+ cmd_message(client, recv_mtags, parc, parv, SEND_TYPE_NOTICE);
+}
+
+/*
+** cmd_tagmsg
+** parv[1] = receiver list
+*/
+CMD_FUNC(cmd_tagmsg)
+{
+ /* compatibility hack */
+ parv[2] = "";
+ parv[3] = NULL;
+ cmd_message(client, recv_mtags, parc, parv, SEND_TYPE_TAGMSG);
}
/* Taken from xchat by Peter Zelezny
@@ -707,13 +763,13 @@ int ban_version(Client *client, char *text)
/** Can user send a message to this channel?
* @param client The client
* @param channel The channel
- * @param msgtext The message to send (MAY be changed, even if user is allowed to send)
- * @param errmsg The error message (will be filled in)
- * @param notice If it's a NOTICE then this is set to 1. Set to 0 for PRIVMSG.
+ * @param msgtext The message to send (MAY be changed, even if user is allowed to send)
+ * @param errmsg The error message (will be filled in)
+ * @param sendtype One of SEND_TYPE_*
* @returns Returns 1 if the user is allowed to send, otherwise 0.
* (note that this behavior was reversed in UnrealIRCd versions <5.x.
*/
-int _can_send_to_channel(Client *client, Channel *channel, char **msgtext, char **errmsg, int notice)
+int _can_send_to_channel(Client *client, Channel *channel, char **msgtext, char **errmsg, SendType sendtype)
{
Membership *lp;
int member, i = 0;
@@ -769,7 +825,7 @@ int _can_send_to_channel(Client *client, Channel *channel, char **msgtext, char
/* Modules can plug in as well */
for (h = Hooks[HOOKTYPE_CAN_SEND_TO_CHANNEL]; h; h = h->next)
{
- i = (*(h->func.intfunc))(client, channel, lp, msgtext, errmsg, notice);
+ i = (*(h->func.intfunc))(client, channel, lp, msgtext, errmsg, sendtype);
if (i != HOOK_CONTINUE)
{
if (!*errmsg)
@@ -780,7 +836,12 @@ int _can_send_to_channel(Client *client, Channel *channel, char **msgtext, char
break;
}
if (!*msgtext || !**msgtext)
- return 0;
+ {
+ if (sendtype != SEND_TYPE_TAGMSG)
+ return 0;
+ else
+ *msgtext = "";
+ }
}
if (i != HOOK_CONTINUE)
@@ -794,9 +855,6 @@ int _can_send_to_channel(Client *client, Channel *channel, char **msgtext, char
*errmsg = NULL;
return 0;
}
- if (!*msgtext || !**msgtext)
- return 0;
-
/* Now we are going to check bans */
diff --git a/src/modules/names.c b/src/modules/names.c
@@ -183,7 +183,8 @@ CMD_FUNC(cmd_names)
*/
for (; *s; s++)
buf[idx++] = *s;
- buf[idx++] = ' ';
+ if (cm->next)
+ buf[idx++] = ' ';
buf[idx] = '\0';
flag = 1;
if (mlen + idx + bufLen > BUFSIZE - 7)
diff --git a/src/modules/nocodes.c b/src/modules/nocodes.c
@@ -29,7 +29,7 @@ ModuleHeader MOD_HEADER
"unrealircd-5",
};
-int nocodes_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice);
+int nocodes_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype);
MOD_INIT()
{
@@ -57,7 +57,7 @@ static int has_controlcodes(char *p)
return 0;
}
-int nocodes_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice)
+int nocodes_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype)
{
static char retbuf[4096];
Hook *h;
diff --git a/src/modules/restrict-commands.c b/src/modules/restrict-commands.c
@@ -38,7 +38,6 @@ struct RestrictedCommand {
int exempt_identified;
int exempt_reputation_score;
int exempt_webirc;
- int disable;
};
typedef struct {
@@ -52,9 +51,9 @@ RestrictedCommand *find_restrictions_bycmd(char *cmd);
RestrictedCommand *find_restrictions_byconftag(char *conftag);
int rcmd_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
int rcmd_configrun(ConfigFile *cf, ConfigEntry *ce, int type);
-int rcmd_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice);
-int rcmd_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, int notice);
-int rcmd_block_message(Client *client, char *text, int notice, char **errmsg, char *display, char *conftag);
+int rcmd_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype);
+int rcmd_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype);
+int rcmd_block_message(Client *client, char *text, SendType sendtype, char **errmsg, char *display, char *conftag);
CMD_OVERRIDE_FUNC(rcmd_override);
// Globals
@@ -145,12 +144,8 @@ RestrictedCommand *find_restrictions_byconftag(char *conftag) {
int rcmd_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
{
int errors = 0;
+ int warn_disable = 0;
ConfigEntry *cep, *cep2;
- RestrictedCommand *rcmd;
- long connect_delay;
- int exempt_reputation_score;
- int exempt_webirc;
- int has_restriction;
// We are only interested in set::restrict-commands
if (type != CONFIG_SET)
@@ -161,12 +156,18 @@ int rcmd_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
{
- has_restriction = 0;
for (cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next)
{
if (!strcmp(cep2->ce_varname, "disable"))
{
- has_restriction = 1;
+ config_warn("%s:%i: set::restrict-commands::%s: the 'disable' option has been removed.",
+ cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, cep->ce_varname);
+ if (!warn_disable)
+ {
+ config_warn("Simply remove 'disable yes;' from the configuration file and "
+ "it will have the same effect without it (will disable the command).");
+ warn_disable = 1;
+ }
continue;
}
@@ -179,9 +180,8 @@ int rcmd_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
if (!strcmp(cep2->ce_varname, "connect-delay"))
{
- has_restriction = 1;
- connect_delay = config_checkval(cep2->ce_vardata, CFG_TIME);
- if (connect_delay < 10 || connect_delay > 3600)
+ long v = config_checkval(cep2->ce_vardata, CFG_TIME);
+ if ((v < 10) || (v > 3600))
{
config_error("%s:%i: set::restrict-commands::%s::connect-delay should be in range 10-3600", cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, cep->ce_varname);
errors++;
@@ -197,8 +197,8 @@ int rcmd_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
if (!strcmp(cep2->ce_varname, "exempt-reputation-score"))
{
- exempt_reputation_score = atoi(cep2->ce_vardata);
- if (exempt_reputation_score <= 0)
+ int v = atoi(cep2->ce_vardata);
+ if (v <= 0)
{
config_error("%s:%i: set::restrict-commands::%s::exempt-reputation-score must be greater than 0", cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, cep->ce_varname);
errors++;
@@ -209,12 +209,6 @@ int rcmd_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
config_error("%s:%i: unknown directive set::restrict-commands::%s::%s", cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, cep->ce_varname, cep2->ce_varname);
errors++;
}
-
- if (!has_restriction)
- {
- config_error("%s:%i: no restrictions were set for set::restrict-commands::%s (either 'connect-delay' or 'disable' is required)", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname);
- errors++;
- }
}
*errs = errors;
@@ -292,12 +286,6 @@ int rcmd_configrun(ConfigFile *cf, ConfigEntry *ce, int type)
rcmd->exempt_reputation_score = atoi(cep2->ce_vardata);
continue;
}
-
- if (!strcmp(cep2->ce_varname, "disable"))
- {
- rcmd->disable = cep2->ce_vardata ? config_checkval(cep2->ce_vardata, CFG_YESNO) : 1;
- break; // Using break instead of continue since 'disable' takes precedence anyways
- }
}
AddListItem(rcmd, RestrictedCommandList);
}
@@ -315,32 +303,32 @@ int rcmd_canbypass(Client *client, RestrictedCommand *rcmd)
return 1;
if (rcmd->exempt_reputation_score > 0 && (GetReputation(client) >= rcmd->exempt_reputation_score))
return 1;
- if (client->local && (TStime() - client->local->firsttime < rcmd->connect_delay))
- return 0;
- return 1; // Default to yes so we don't drop too many commands
+ if (rcmd->connect_delay && client->local && (TStime() - client->local->firsttime >= rcmd->connect_delay))
+ return 1;
+ return 0;
}
-int rcmd_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, int notice)
+int rcmd_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype)
{
- if (rcmd_block_message(client, *msg, notice, errmsg, "channel", (notice ? "channel-notice" : "channel-message")))
+ if (rcmd_block_message(client, *msg, sendtype, errmsg, "channel", (sendtype == SEND_TYPE_NOTICE ? "channel-notice" : "channel-message")))
return HOOK_DENY;
return HOOK_CONTINUE;
}
-int rcmd_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, int notice)
+int rcmd_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype)
{
// Need a few extra exceptions for user messages only =]
if ((client == target) || IsULine(target))
return HOOK_CONTINUE; /* bypass/exempt */
- if (rcmd_block_message(client, *text, notice, errmsg, "user", (notice ? "private-notice" : "private-message")))
+ if (rcmd_block_message(client, *text, sendtype, errmsg, "user", (sendtype == SEND_TYPE_NOTICE ? "private-notice" : "private-message")))
return HOOK_DENY;
return HOOK_CONTINUE;
}
-int rcmd_block_message(Client *client, char *text, int notice, char **errmsg, char *display, char *conftag)
+int rcmd_block_message(Client *client, char *text, SendType sendtype, char **errmsg, char *display, char *conftag)
{
RestrictedCommand *rcmd;
static char errbuf[256];
@@ -350,24 +338,21 @@ int rcmd_block_message(Client *client, char *text, int notice, char **errmsg, ch
return 0;
rcmd = find_restrictions_byconftag(conftag);
- if (rcmd)
+ if (rcmd && !rcmd_canbypass(client, rcmd))
{
- if (rcmd->disable)
+ int notice = (sendtype == SEND_TYPE_NOTICE ? 1 : 0); // temporary hack FIXME !!!
+ if (rcmd->connect_delay)
{
ircsnprintf(errbuf, sizeof(errbuf),
- "Sending of %ss to %ss been disabled by the network administrators",
- (notice ? "notice" : "message"), display);
- *errmsg = errbuf;
- return 1;
- }
- if (!rcmd_canbypass(client, rcmd))
- {
+ "You cannot send %ss to %ss until you've been connected for %ld seconds or more",
+ (notice ? "notice" : "message"), display, rcmd->connect_delay);
+ } else {
ircsnprintf(errbuf, sizeof(errbuf),
- "You cannot send %ss to %ss until you've been connected for %ld seconds or more",
- (notice ? "notice" : "message"), display, rcmd->connect_delay);
- *errmsg = errbuf;
- return 1;
+ "Sending of %ss to %ss been disabled by the network administrators",
+ (notice ? "notice" : "message"), display);
}
+ *errmsg = errbuf;
+ return 1;
}
// No restrictions apply, process command as normal =]
@@ -385,22 +370,19 @@ CMD_OVERRIDE_FUNC(rcmd_override)
}
rcmd = find_restrictions_bycmd(ovr->command->cmd);
- if (rcmd)
+ if (rcmd && !rcmd_canbypass(client, rcmd))
{
- if (rcmd->disable)
- {
- sendnumericfmt(client, ERR_UNKNOWNCOMMAND,
- "%s :This command is disabled by the network administrator",
- ovr->command->cmd);
- return;
- }
- if (!rcmd_canbypass(client, rcmd))
+ if (rcmd->connect_delay)
{
sendnumericfmt(client, ERR_UNKNOWNCOMMAND,
"%s :You must be connected for at least %ld seconds before you can use this command",
ovr->command->cmd, rcmd->connect_delay);
- return;
+ } else {
+ sendnumericfmt(client, ERR_UNKNOWNCOMMAND,
+ "%s :This command is disabled by the network administrator",
+ ovr->command->cmd);
}
+ return;
}
// No restrictions apply, process command as normal =]
diff --git a/src/modules/sajoin.c b/src/modules/sajoin.c
@@ -275,12 +275,14 @@ CMD_FUNC(cmd_sajoin)
strlcat(jbuf, ",", sizeof jbuf);
strlcat(jbuf, name, sizeof jbuf);
}
+
if (did_anything)
{
if (!sjmode)
{
//sendnotice(target, "*** You were forced to join %s", jbuf);
sendto_umode_global(UMODE_OPER, "%s used SAJOIN to make %s join %s", client->name, target->name, jbuf);
+ /* Logging function added by XeRXeS */
ircd_log(LOG_SACMDS,"SAJOIN: %s used SAJOIN to make %s join %s",
client->name, target->name, jbuf);
}
diff --git a/src/modules/sapart.c b/src/modules/sapart.c
@@ -161,7 +161,7 @@ CMD_FUNC(cmd_sapart)
parv[2] = comment ? commentx : NULL; // comment
if (comment)
{
- //sendnotice(target, "*** You were forced to part %s (%s)", parv[1], commentx);
+ sendnotice(target, "*** You were forced to part %s (%s)", parv[1], commentx);
sendto_umode_global(UMODE_OPER, "%s used SAPART to make %s part %s (%s)",
client->name, target->name, parv[1], comment);
ircd_log(LOG_SACMDS,"SAPART: %s used SAPART to make %s part %s (%s)",
@@ -169,7 +169,7 @@ CMD_FUNC(cmd_sapart)
}
else
{
- //sendnotice(target, "*** You were forced to part %s", parv[1]);
+ sendnotice(target, "*** You were forced to part %s", parv[1]);
sendto_umode_global(UMODE_OPER, "%s used SAPART to make %s part %s",
client->name, target->name, parv[1]);
ircd_log(LOG_SACMDS,"SAPART: %s used SAPART to make %s part %s",
diff --git a/src/modules/svsnick.c b/src/modules/svsnick.c
@@ -95,7 +95,7 @@ CMD_FUNC(cmd_svsnick)
/* no 'recv_mtags' here, we do not inherit from SVSNICK but generate a new NICK event */
new_message(acptr, NULL, &mtags);
- sendto_local_common_channels(acptr, NULL, 0, mtags, ":%s NICK :%s", acptr->name, parv[2]);
+ sendto_local_common_channels(acptr, acptr, 0, mtags, ":%s NICK :%s", acptr->name, parv[2]);
sendto_one(acptr, mtags, ":%s NICK :%s", acptr->name, parv[2]);
sendto_server(NULL, 0, 0, mtags, ":%s NICK %s :%ld", acptr->id, parv[2], atol(parv[3]));
free_message_tags(mtags);
diff --git a/src/modules/targetfloodprot.c b/src/modules/targetfloodprot.c
@@ -0,0 +1,315 @@
+/* Target flood protection
+ * (C)Copyright 2020 Bram Matthys and the UnrealIRCd team
+ * License: GPLv2
+ */
+
+#include "unrealircd.h"
+
+ModuleHeader MOD_HEADER
+ = {
+ "targetfloodprot",
+ "5.0",
+ "Target flood protection (set::anti-flood::target-flood)",
+ "UnrealIRCd Team",
+ "unrealircd-5",
+ };
+
+#define TFP_PRIVMSG 0
+#define TFP_NOTICE 1
+#define TFP_TAGMSG 2
+#define TFP_MAX 3
+
+typedef struct TargetFlood TargetFlood;
+struct TargetFlood {
+ unsigned short cnt[TFP_MAX];
+ time_t t[TFP_MAX];
+};
+
+typedef struct TargetFloodConfig TargetFloodConfig;
+struct TargetFloodConfig {
+ int cnt[TFP_MAX];
+ int t[TFP_MAX];
+};
+
+/* Forward declarations */
+int targetfloodprot_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
+int targetfloodprot_config_run(ConfigFile *cf, ConfigEntry *ce, int type);
+void targetfloodprot_mdata_free(ModData *m);
+int targetfloodprot_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype);
+int targetfloodprot_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype);
+
+/* Global variables */
+ModDataInfo *targetfloodprot_client_md = NULL;
+ModDataInfo *targetfloodprot_channel_md = NULL;
+TargetFloodConfig *channelcfg = NULL;
+TargetFloodConfig *privatecfg = NULL;
+
+MOD_TEST()
+{
+ HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, targetfloodprot_config_test);
+ return MOD_SUCCESS;
+}
+
+/** Allocate config and set default configuration */
+void targetfloodprot_defaults(void)
+{
+ channelcfg = safe_alloc(sizeof(TargetFloodConfig));
+ privatecfg = safe_alloc(sizeof(TargetFloodConfig));
+
+ /* set::anti-flood::target-flood::channel-privmsg */
+ channelcfg->cnt[TFP_PRIVMSG] = 45;
+ channelcfg->t[TFP_PRIVMSG] = 5;
+ /* set::anti-flood::target-flood::channel-notice */
+ channelcfg->cnt[TFP_NOTICE] = 15;
+ channelcfg->t[TFP_NOTICE] = 5;
+ /* set::anti-flood::target-flood::channel-tagmsg */
+ channelcfg->cnt[TFP_TAGMSG] = 15;
+ channelcfg->t[TFP_TAGMSG] = 5;
+
+ /* set::anti-flood::target-flood::private-privmsg */
+ privatecfg->cnt[TFP_PRIVMSG] = 30;
+ privatecfg->t[TFP_PRIVMSG] = 5;
+ /* set::anti-flood::target-flood::private-notice */
+ privatecfg->cnt[TFP_NOTICE] = 10;
+ privatecfg->t[TFP_NOTICE] = 5;
+ /* set::anti-flood::target-flood::private-tagmsg */
+ privatecfg->cnt[TFP_TAGMSG] = 10;
+ privatecfg->t[TFP_TAGMSG] = 5;
+}
+
+MOD_INIT()
+{
+ ModDataInfo mreq;
+
+ MARK_AS_OFFICIAL_MODULE(modinfo);
+
+ HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, targetfloodprot_config_run);
+ HookAdd(modinfo->handle, HOOKTYPE_CAN_SEND_TO_CHANNEL, 0, targetfloodprot_can_send_to_channel);
+ HookAdd(modinfo->handle, HOOKTYPE_CAN_SEND_TO_USER, 0, targetfloodprot_can_send_to_user);
+
+ memset(&mreq, 0, sizeof(mreq));
+ mreq.name = "targetfloodprot";
+ mreq.serialize = NULL;
+ mreq.unserialize = NULL;
+ mreq.free = targetfloodprot_mdata_free;
+ mreq.sync = 0;
+ mreq.type = MODDATATYPE_LOCAL_CLIENT;
+ targetfloodprot_client_md = ModDataAdd(modinfo->handle, mreq);
+
+ memset(&mreq, 0, sizeof(mreq));
+ mreq.name = "targetfloodprot";
+ mreq.serialize = NULL;
+ mreq.unserialize = NULL;
+ mreq.free = targetfloodprot_mdata_free;
+ mreq.sync = 0;
+ mreq.type = MODDATATYPE_CHANNEL;
+ targetfloodprot_channel_md = ModDataAdd(modinfo->handle, mreq);
+
+ targetfloodprot_defaults();
+
+ return MOD_SUCCESS;
+}
+
+MOD_LOAD()
+{
+ return MOD_SUCCESS;
+}
+
+MOD_UNLOAD()
+{
+ return MOD_SUCCESS;
+}
+
+#ifndef CheckNull
+ #define CheckNull(x) if ((!(x)->ce_vardata) || (!(*((x)->ce_vardata)))) { config_error("%s:%i: missing parameter", (x)->ce_fileptr->cf_filename, (x)->ce_varlinenum); errors++; continue; }
+#endif
+
+int targetfloodprot_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
+{
+ int errors = 0;
+ ConfigEntry *cep;
+
+ if (type != CONFIG_SET_ANTI_FLOOD)
+ return 0;
+
+ /* We are only interrested in set::anti-flood::target-flood.. */
+ if (!ce || !ce->ce_varname || strcmp(ce->ce_varname, "target-flood"))
+ return 0;
+
+ for (cep = ce->ce_entries; cep; cep = cep->ce_next)
+ {
+ CheckNull(cep);
+
+ if (!strcmp(cep->ce_varname, "channel-privmsg") ||
+ !strcmp(cep->ce_varname, "channel-notice") ||
+ !strcmp(cep->ce_varname, "channel-tagmsg") ||
+ !strcmp(cep->ce_varname, "private-privmsg") ||
+ !strcmp(cep->ce_varname, "private-notice") ||
+ !strcmp(cep->ce_varname, "private-tagmsg"))
+ {
+ int cnt = 0, period = 0;
+
+ if (!config_parse_flood(cep->ce_vardata, &cnt, &period) ||
+ (cnt < 1) || (cnt > 10000) || (period < 1) || (period > 120))
+ {
+ config_error("%s:%i: set::anti-flood::target-flood::%s error. "
+ "Syntax is '<count>:<period>' (eg 5:60). "
+ "Count must be 1-10000 and period must be 1-120.",
+ cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
+ cep->ce_varname);
+ errors++;
+ }
+ } else
+ {
+ config_error("%s:%i: unknown directive set::anti-flood::target-flood:%s",
+ cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname);
+ errors++;
+ continue;
+ }
+ }
+
+ *errs = errors;
+ return errors ? -1 : 1;
+}
+
+int targetfloodprot_config_run(ConfigFile *cf, ConfigEntry *ce, int type)
+{
+ ConfigEntry *cep, *cepp;
+
+ if (type != CONFIG_SET_ANTI_FLOOD)
+ return 0;
+
+ /* We are only interrested in set::anti-flood::target-flood.. */
+ if (!ce || !ce->ce_varname || strcmp(ce->ce_varname, "target-flood"))
+ return 0;
+
+ for (cep = ce->ce_entries; cep; cep = cep->ce_next)
+ {
+ if (!strcmp(cep->ce_varname, "channel-privmsg"))
+ config_parse_flood(cep->ce_vardata, &channelcfg->cnt[TFP_PRIVMSG], &channelcfg->t[TFP_PRIVMSG]);
+ else if (!strcmp(cep->ce_varname, "channel-notice"))
+ config_parse_flood(cep->ce_vardata, &channelcfg->cnt[TFP_NOTICE], &channelcfg->t[TFP_NOTICE]);
+ else if (!strcmp(cep->ce_varname, "channel-tagmsg"))
+ config_parse_flood(cep->ce_vardata, &channelcfg->cnt[TFP_TAGMSG], &channelcfg->t[TFP_TAGMSG]);
+ else if (!strcmp(cep->ce_varname, "private-privmsg"))
+ config_parse_flood(cep->ce_vardata, &privatecfg->cnt[TFP_PRIVMSG], &privatecfg->t[TFP_PRIVMSG]);
+ else if (!strcmp(cep->ce_varname, "private-notice"))
+ config_parse_flood(cep->ce_vardata, &privatecfg->cnt[TFP_NOTICE], &privatecfg->t[TFP_NOTICE]);
+ else if (!strcmp(cep->ce_varname, "private-tagmsg"))
+ config_parse_flood(cep->ce_vardata, &privatecfg->cnt[TFP_TAGMSG], &privatecfg->t[TFP_TAGMSG]);
+ }
+
+ return 1;
+}
+
+/** UnrealIRCd internals: free object. */
+void targetfloodprot_mdata_free(ModData *m)
+{
+ /* we don't have any members to free, so this is easy */
+ safe_free(m->ptr);
+}
+
+int sendtypetowhat(SendType sendtype)
+{
+ if (sendtype == SEND_TYPE_PRIVMSG)
+ return 0;
+ if (sendtype == SEND_TYPE_NOTICE)
+ return 1;
+ if (sendtype == SEND_TYPE_TAGMSG)
+ return 2;
+#ifdef DEBUGMODE
+ ircd_log(LOG_ERROR, "sendtypetowhat() for unknown value %d", (int)sendtype);
+ abort();
+#endif
+ return 0; /* otherwise, default to privmsg i guess */
+}
+
+int targetfloodprot_can_send_to_channel(Client *client, Channel *channel, Membership *lp, char **msg, char **errmsg, SendType sendtype)
+{
+ TargetFlood *flood;
+ static char errbuf[256];
+ int what;
+
+ /* This is redundant, right? */
+ if (!MyUser(client))
+ return HOOK_CONTINUE;
+
+ /* Really, only IRCOps override */
+ if (IsOper(client) && ValidatePermissionsForPath("immune:target-flood",client,NULL,channel,NULL))
+ return HOOK_CONTINUE;
+
+ what = sendtypetowhat(sendtype);
+
+ if (moddata_channel(channel, targetfloodprot_channel_md).ptr == NULL)
+ {
+ /* Alloc a new entry if it doesn't exist yet */
+ moddata_channel(channel, targetfloodprot_channel_md).ptr = safe_alloc(sizeof(TargetFlood));
+ }
+
+ flood = (TargetFlood *)moddata_channel(channel, targetfloodprot_channel_md).ptr;
+
+ if ((TStime() - flood->t[what]) >= channelcfg->t[what])
+ {
+ /* Reset due to moving into a new time slot */
+ flood->t[what] = TStime();
+ flood->cnt[what] = 1;
+ return HOOK_CONTINUE; /* forget about it.. */
+ }
+
+ if (flood->cnt[what] >= channelcfg->cnt[what])
+ {
+ /* Flood detected */
+ snprintf(errbuf, sizeof(errbuf), "Channel is being flooded. Message not delivered.");
+ *errmsg = errbuf;
+ return HOOK_DENY;
+ }
+
+ flood->cnt[what]++;
+ return HOOK_CONTINUE;
+}
+
+int targetfloodprot_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype)
+{
+ TargetFlood *flood;
+ static char errbuf[256];
+ int what;
+
+ /* Check if it is our TARGET ('target'), so yeah
+ * be aware that 'client' may be remote client in all the code that follows!
+ */
+ if (!MyUser(target))
+ return HOOK_CONTINUE;
+
+ /* Really, only IRCOps override */
+ if (IsOper(client) && ValidatePermissionsForPath("immune:target-flood",client,target,NULL,NULL))
+ return HOOK_CONTINUE;
+
+ what = sendtypetowhat(sendtype);
+
+ if (moddata_local_client(target, targetfloodprot_client_md).ptr == NULL)
+ {
+ /* Alloc a new entry if it doesn't exist yet */
+ moddata_local_client(target, targetfloodprot_client_md).ptr = safe_alloc(sizeof(TargetFlood));
+ }
+
+ flood = (TargetFlood *)moddata_local_client(target, targetfloodprot_client_md).ptr;
+
+ if ((TStime() - flood->t[what]) >= privatecfg->t[what])
+ {
+ /* Reset due to moving into a new time slot */
+ flood->t[what] = TStime();
+ flood->cnt[what] = 1;
+ return HOOK_CONTINUE; /* forget about it.. */
+ }
+
+ if (flood->cnt[what] >= privatecfg->cnt[what])
+ {
+ /* Flood detected */
+ snprintf(errbuf, sizeof(errbuf), "User is being flooded. Message not delivered.");
+ *errmsg = errbuf;
+ return HOOK_DENY;
+ }
+
+ flood->cnt[what]++;
+ return HOOK_CONTINUE;
+}
diff --git a/src/modules/tkl.c b/src/modules/tkl.c
@@ -115,6 +115,7 @@ struct TKLTypeTable
* IMPORTANT IF YOU ARE ADDING A NEW TYPE TO THIS TABLE:
* - also update eline_syntax()
* - also check if eline_type_requires_ip() needs to be updated
+ * - update help.conf (HELPOP ELINE)
* - more?
*/
TKLTypeTable tkl_types[] = {
@@ -868,7 +869,7 @@ int tkl_config_run_except(ConfigFile *cf, ConfigEntry *ce, int configtype)
{
/* Default setting if no 'type' is specified: */
if (!strcmp(ce->ce_vardata, "ban"))
- strlcpy(bantypes, "kgzZs", sizeof(bantypes));
+ strlcpy(bantypes, "kGzZs", sizeof(bantypes));
else if (!strcmp(ce->ce_vardata, "throttle"))
strlcpy(bantypes, "c", sizeof(bantypes));
else if (!strcmp(ce->ce_vardata, "blacklist"))
@@ -1208,6 +1209,22 @@ int ban_too_broad(char *usermask, char *hostmask)
return 1;
}
+/** Ugly function, only meant to be called by cmd_tkl_line() */
+static int xline_exists(char *type, char *usermask, char *hostmask)
+{
+ char *umask = usermask;
+ int softban = 0;
+ int tpe = tkl_chartotype(type[0]);
+
+ if (*umask == '%')
+ {
+ umask++;
+ softban = 1;
+ }
+
+ return find_tkl_serverban(tpe, umask, hostmask, softban) ? 1 : 0;
+}
+
/** Intermediate layer between user functions such as KLINE/GLINE
* and the TKL layer (cmd_tkl).
* This allows us doing some syntax checking and other helpful
@@ -1434,6 +1451,13 @@ void cmd_tkl_line(Client *client, int parc, char *parv[], char *type)
return;
}
+ /* Some stupid checking */
+ if (xline_exists(type, usermask, hostmask))
+ {
+ sendnotice(client, "ERROR: Ban for %s@%s already exists.", usermask, hostmask);
+ return;
+ }
+
/* call the tkl layer .. */
cmd_tkl(&me, NULL, 9, tkllayer);
}
diff --git a/src/modules/tkldb.c b/src/modules/tkldb.c
@@ -402,9 +402,10 @@ int read_tkldb(void)
FILE *fd;
TKL *tkl = NULL;
uint32_t magic = 0;
+ uint32_t version;
uint64_t cnt;
uint64_t tklcount = 0;
- uint32_t version;
+ uint64_t v;
int added_cnt = 0;
char c;
char *str;
@@ -483,8 +484,10 @@ int read_tkldb(void)
/* Read the common types (same for all TKLs) */
R_SAFE(read_str(fd, &tkl->set_by));
- R_SAFE(read_int64(fd, &tkl->set_at));
- R_SAFE(read_int64(fd, &tkl->expire_at));
+ R_SAFE(read_int64(fd, &v));
+ tkl->set_at = v;
+ R_SAFE(read_int64(fd, &v));
+ tkl->expire_at = v;
/* Save some CPU... if it's already expired then don't bother adding */
if (tkl->expire_at != 0 && tkl->expire_at <= TStime())
@@ -645,7 +648,8 @@ int read_tkldb(void)
}
R_SAFE(read_str(fd, &tkl->ptr.spamfilter->tkl_reason));
- R_SAFE(read_int64(fd, &tkl->ptr.spamfilter->tkl_duration));
+ R_SAFE(read_int64(fd, &v));
+ tkl->ptr.spamfilter->tkl_duration = v;
if (find_tkl_spamfilter(tkl->type, tkl->ptr.spamfilter->match->str,
tkl->ptr.spamfilter->action,
diff --git a/src/modules/typing-indicator.c b/src/modules/typing-indicator.c
@@ -0,0 +1,105 @@
+/*
+ * IRC - Internet Relay Chat, src/modules/typing-indicator.c
+ * (C) 2020 Syzop & The UnrealIRCd Team
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "unrealircd.h"
+
+ModuleHeader MOD_HEADER
+ = {
+ "typing-indicator",
+ "5.0",
+ "+typing client tag",
+ "UnrealIRCd Team",
+ "unrealircd-5",
+ };
+
+int ti_mtag_is_ok(Client *client, char *name, char *value);
+void mtag_add_ti(Client *client, MessageTag *recv_mtags, MessageTag **mtag_list, char *signature);
+
+MOD_INIT()
+{
+ MessageTagHandlerInfo mtag;
+
+ MARK_AS_OFFICIAL_MODULE(modinfo);
+
+ memset(&mtag, 0, sizeof(mtag));
+ mtag.name = "+typing";
+ mtag.is_ok = ti_mtag_is_ok;
+ mtag.flags = MTAG_HANDLER_FLAGS_NO_CAP_NEEDED;
+ MessageTagHandlerAdd(modinfo->handle, &mtag);
+
+ memset(&mtag, 0, sizeof(mtag));
+ mtag.name = "+draft/typing";
+ mtag.is_ok = ti_mtag_is_ok;
+ mtag.flags = MTAG_HANDLER_FLAGS_NO_CAP_NEEDED;
+ MessageTagHandlerAdd(modinfo->handle, &mtag);
+
+ HookAddVoid(modinfo->handle, HOOKTYPE_NEW_MESSAGE, 0, mtag_add_ti);
+
+ return MOD_SUCCESS;
+}
+
+MOD_LOAD()
+{
+ return MOD_SUCCESS;
+}
+
+MOD_UNLOAD()
+{
+ return MOD_SUCCESS;
+}
+
+/** This function verifies if the client sending the mtag is permitted to do so.
+ */
+int ti_mtag_is_ok(Client *client, char *name, char *value)
+{
+ /* Require a non-empty parameter */
+ if (BadPtr(value))
+ return 0;
+
+ /* These are the only valid values: */
+ if (!strcmp(value, "active") || !strcmp(value, "paused") || !strcmp(value, "done"))
+ return 1;
+
+ /* All the rest is considered illegal */
+ return 0;
+}
+
+void mtag_add_ti(Client *client, MessageTag *recv_mtags, MessageTag **mtag_list, char *signature)
+{
+ MessageTag *m;
+
+ if (IsUser(client))
+ {
+ m = find_mtag(recv_mtags, "+typing");
+ if (m)
+ {
+ m = duplicate_mtag(m);
+ AddListItem(m, *mtag_list);
+ }
+ m = find_mtag(recv_mtags, "+draft/typing");
+ if (m)
+ {
+ m = duplicate_mtag(m);
+ AddListItem(m, *mtag_list);
+ }
+ }
+}
diff --git a/src/modules/usermodes/censor.c b/src/modules/usermodes/censor.c
@@ -20,7 +20,7 @@ long UMODE_CENSOR = 0L;
#define IsCensored(x) (x->umodes & UMODE_CENSOR)
-int censor_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, int notice);
+int censor_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype);
int censor_config_test(ConfigFile *, ConfigEntry *, int, int *);
int censor_config_run(ConfigFile *, ConfigEntry *, int);
@@ -237,7 +237,7 @@ char *stripbadwords_message(char *str, int *blocked)
return stripbadwords(str, conf_badword_message, blocked);
}
-int censor_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, int notice)
+int censor_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype)
{
int blocked = 0;
diff --git a/src/modules/usermodes/noctcp.c b/src/modules/usermodes/noctcp.c
@@ -34,7 +34,7 @@ long UMODE_NOCTCP = 0L;
#define IsNoCTCP(client) (client->umodes & UMODE_NOCTCP)
-int noctcp_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, int notice);
+int noctcp_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype);
MOD_TEST()
{
@@ -74,9 +74,10 @@ static int IsACTCP(char *s)
return 0;
}
-int noctcp_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, int notice)
+int noctcp_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype)
{
- if (MyUser(client) && !notice && IsNoCTCP(target) && !IsOper(client) && IsACTCP(*text))
+ if (MyUser(client) && (sendtype == SEND_TYPE_PRIVMSG) &&
+ IsNoCTCP(target) && !IsOper(client) && IsACTCP(*text))
{
*errmsg = "User does not accept CTCPs";
return HOOK_DENY;
diff --git a/src/modules/usermodes/privdeaf.c b/src/modules/usermodes/privdeaf.c
@@ -17,7 +17,7 @@ ModuleHeader MOD_HEADER
static long UMODE_PRIVDEAF = 0;
static Umode *UmodePrivdeaf = NULL;
-int privdeaf_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, int notice);
+int privdeaf_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype);
MOD_INIT()
{
@@ -47,7 +47,7 @@ MOD_UNLOAD()
return MOD_SUCCESS;
}
-int privdeaf_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, int notice)
+int privdeaf_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype)
{
if ((target->umodes & UMODE_PRIVDEAF) && !IsOper(client) &&
!IsULine(client) && !IsServer(client) && (client != target))
diff --git a/src/modules/usermodes/regonlymsg.c b/src/modules/usermodes/regonlymsg.c
@@ -35,7 +35,7 @@ ModuleHeader MOD_HEADER
long UMODE_REGONLYMSG = 0L;
/* Forward declarations */
-int regonlymsg_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, int notice);
+int regonlymsg_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype);
MOD_INIT()
{
@@ -57,7 +57,7 @@ MOD_UNLOAD()
return MOD_SUCCESS;
}
-int regonlymsg_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, int notice)
+int regonlymsg_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype)
{
if (IsRegOnlyMsg(target) && !IsServer(client) && !IsULine(client) && !IsLoggedIn(client))
{
diff --git a/src/modules/usermodes/secureonlymsg.c b/src/modules/usermodes/secureonlymsg.c
@@ -36,7 +36,7 @@ ModuleHeader MOD_HEADER
long UMODE_SECUREONLYMSG = 0L;
/* Forward declarations */
-int secureonlymsg_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, int notice);
+int secureonlymsg_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype);
MOD_INIT()
{
@@ -58,7 +58,7 @@ MOD_UNLOAD()
return MOD_SUCCESS;
}
-int secureonlymsg_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, int notice)
+int secureonlymsg_can_send_to_user(Client *client, Client *target, char **text, char **errmsg, SendType sendtype)
{
if (IsSecureOnlyMsg(target) && !IsServer(client) && !IsULine(client) && !IsSecureConnect(client))
{
diff --git a/src/modules/whox.c b/src/modules/whox.c
@@ -560,7 +560,7 @@ static void who_common_channel(Client *client, Channel *channel,
static void who_global(Client *client, char *mask, int operspy, struct who_format *fmt)
{
Client *acptr;
- int maxmatches = WHOLIMIT ? WHOLIMIT : 100;
+ int maxmatches = IsOper(client) ? INT_MAX : WHOLIMIT;
/* first, list all matching INvisible clients on common channels
* if this is not an operspy who
diff --git a/src/send.c b/src/send.c
@@ -422,7 +422,7 @@ void sendto_channel(Channel *channel, Client *from, Client *skip,
continue;
good:
/* Now deal with 'clicap' (if non-zero) */
- if (clicap && MyUser(acptr) && !HasCapabilityFast(acptr, clicap))
+ if (clicap && MyUser(acptr) && ((clicap & CAP_INVERT) ? HasCapabilityFast(acptr, clicap) : !HasCapabilityFast(acptr, clicap)))
continue;
if (MyUser(acptr))
@@ -558,7 +558,7 @@ void sendto_local_common_channels(Client *user, Client *skip, long clicap, Messa
if (acptr->local->serial == current_serial)
continue; /* message already sent to this client */
- if (clicap && !HasCapabilityFast(acptr, clicap))
+ if (clicap && ((clicap & CAP_INVERT) ? HasCapabilityFast(acptr, clicap) : !HasCapabilityFast(acptr, clicap)))
continue; /* client does not have the specified capability */
if (acptr == skip)
diff --git a/src/socket.c b/src/socket.c
@@ -616,6 +616,7 @@ void completed_connection(int fd, int revents, void *data)
*/
void close_connection(Client *client)
{
+ RunHook(HOOKTYPE_CLOSE_CONNECTION, client);
/* This function must make MyConnect(client) == FALSE,
* and set client->direction == NULL.
*/
diff --git a/src/user.c b/src/user.c
@@ -124,7 +124,7 @@ long set_usermode(char *umode)
/** Convert a target pointer to an 8 bit hash, used for target limiting. */
unsigned char hash_target(void *target)
{
- unsigned long long v = (unsigned long long)target;
+ uintptr_t v = (uintptr_t)target;
/* ircu does >> 16 and 8 but since our sizeof(Client) is
* towards 512 (and hence the alignment), that bit is useless.
* So we do >> 17 and 9.
@@ -552,6 +552,7 @@ void set_targmax_defaults(void)
/* Set the defaults */
setmaxtargets("PRIVMSG", 4);
setmaxtargets("NOTICE", 1);
+ setmaxtargets("TAGMSG", 1);
setmaxtargets("NAMES", 1); // >1 is not supported
setmaxtargets("WHOIS", 1);
setmaxtargets("WHOWAS", 1); // >1 is not supported
diff --git a/src/version.c.SH b/src/version.c.SH
@@ -4,7 +4,7 @@ echo "Extracting src/version.c..."
#id=`grep '$Id: Changes,v' ../Changes`
#id=`echo $id |sed 's/.* Changes\,v \(.*\) .* Exp .*/\1/'`
-id="5.0.4"
+id="5.0.5"
echo "$id"
if test -r version.c
diff --git a/src/windows/UnrealIRCd.exe.manifest b/src/windows/UnrealIRCd.exe.manifest
@@ -3,7 +3,7 @@
<assemblyIdentity
processorArchitecture="amd64"
name="UnrealIRCd.UnrealIRCd.5"
- version="5.0.4.0"
+ version="5.0.5.0"
type="win32"
/>
<description>Internet Relay Chat Daemon</description>
diff --git a/src/windows/unrealinst.iss b/src/windows/unrealinst.iss
@@ -6,7 +6,7 @@
[Setup]
AppName=UnrealIRCd 5
-AppVerName=UnrealIRCd 5.0.4
+AppVerName=UnrealIRCd 5.0.5
AppPublisher=UnrealIRCd Team
AppPublisherURL=https://www.unrealircd.org
AppSupportURL=https://www.unrealircd.org
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |