unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

commit c1971584d315660d9bdace1cf2b95a31c0eed282
parent 6ba3937b99cd586933d03a3752822365355d24f5
Author: acidvegas <acid.vegas@acid.vegas>
Date: Thu, 16 Jul 2020 18:06:52 -0400

Updated to 5.0.6

Diffstat:
MConfig | 2+-
Mconfigure | 40++++++++++++++++++++--------------------
Mconfigure.ac | 10+++++-----
Mdoc/Config.header | 2+-
Mdoc/RELEASE-NOTES.md | 72++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Mextras/doxygen/Doxyfile | 2+-
Mextras/pcre2.tar.gz | 0
Minclude/windows/setup.h | 2+-
Msrc/conf.c | 6++++++
Msrc/match.c | 2+-
Msrc/modules/chanmodes/history.c | 8+++++++-
Msrc/modules/cloak.c | 6++++++
Msrc/modules/history.c | 1+
Msrc/modules/history_backend_mem.c | 8+++++++-
Msrc/modules/labeled-response.c | 47++++++++++++++++++++++++++++++++---------------
Msrc/modules/nick.c | 3+++
Msrc/modules/sajoin.c | 4++--
Msrc/modules/sasl.c | 36+++++++++++++++++++++++++-----------
Msrc/modules/svsmode.c | 7-------
Msrc/modules/tkl.c | 2+-
Msrc/modules/usermodes/bot.c | 1+
Msrc/modules/websocket.c | 4++--
Msrc/send.c | 2+-
Msrc/tls.c | 2+-
Msrc/version.c.SH | 2+-
Msrc/windows/UnrealIRCd.exe.manifest | 2+-
Msrc/windows/unrealinst.iss | 2+-

27 files changed, 176 insertions(+), 99 deletions(-)

diff --git a/Config b/Config
@@ -326,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.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"
+UNREALRELEASES="unrealircd-5.0.5.1 unrealircd-5.0.5 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
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.5.
+# Generated by GNU Autoconf 2.69 for unrealircd 5.0.6.
 #
 # 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.5'
-PACKAGE_STRING='unrealircd 5.0.5'
+PACKAGE_VERSION='5.0.6'
+PACKAGE_STRING='unrealircd 5.0.6'
 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.5 to adapt to many kinds of systems.
+\`configure' configures unrealircd 5.0.6 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.5:";;
+     short | recursive ) echo "Configuration of unrealircd 5.0.6:";;
    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.5
+unrealircd configure 5.0.6
 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.5, which was
+It was created by unrealircd $as_me 5.0.6, 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="5"
+UNREAL_VERSION_MINOR="6"
 
 cat >>confdefs.h <<_ACEOF
 #define UNREAL_VERSION_MINOR $UNREAL_VERSION_MINOR
@@ -6881,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.34\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "libpcre2-8 >= 10.34") 2>&5
+    { { $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
   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.34" 2>/dev/null`
+  pkg_cv_PCRE2_CFLAGS=`$PKG_CONFIG --cflags "libpcre2-8 >= 10.00" 2>/dev/null`
 		      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
@@ -6898,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.34\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "libpcre2-8 >= 10.34") 2>&5
+    { { $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
   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.34" 2>/dev/null`
+  pkg_cv_PCRE2_LIBS=`$PKG_CONFIG --libs "libpcre2-8 >= 10.00" 2>/dev/null`
 		      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
@@ -6924,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.34" 2>&1`
+	        PCRE2_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpcre2-8 >= 10.00" 2>&1`
         else
-	        PCRE2_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpcre2-8 >= 10.34" 2>&1`
+	        PCRE2_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpcre2-8 >= 10.00" 2>&1`
         fi
 	# Put the nasty error message in config.log where it belongs
 	echo "$PCRE2_PKG_ERRORS" >&5
@@ -6950,7 +6950,7 @@ fi
 
 if test "$has_system_pcre2" = "no"; then :
 
-pcre2_version="10.34"
+pcre2_version="10.33"
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: extracting PCRE2 regex library" >&5
 $as_echo "extracting PCRE2 regex library" >&6; }
 cur_dir=`pwd`
@@ -6967,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 --prefix=$cur_dir/extras/pcre2 --libdir=$PRIVATELIBDIR || exit 1
+./configure --enable-jit --enable-shared --disable-unicode --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
@@ -8398,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.5, which was
+This file was extended by unrealircd $as_me 5.0.6, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -8461,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.5
+unrealircd config.status 5.0.6
 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.5], [https://bugs.unrealircd.org/], [], [https://unrealircd.org/])
+AC_INIT([unrealircd], [5.0.6], [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=["5"]
+UNREAL_VERSION_MINOR=["6"]
 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
@@ -537,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.34,[has_system_pcre2=yes
+PKG_CHECK_MODULES([PCRE2], libpcre2-8 >= 10.00,[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.34"
+pcre2_version="10.33"
 AC_MSG_RESULT(extracting PCRE2 regex library)
 cur_dir=`pwd`
 cd extras
@@ -559,7 +559,7 @@ else
 fi
 AC_MSG_RESULT(configuring PCRE2 regex library)
 cd pcre2-$pcre2_version
-./configure --enable-jit --enable-shared --prefix=$cur_dir/extras/pcre2 --libdir=$PRIVATELIBDIR || exit 1
+./configure --enable-jit --enable-shared --disable-unicode --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)
diff --git a/doc/Config.header b/doc/Config.header
@@ -7,7 +7,7 @@
  \___/|_| |_|_|  \___|\__,_|_|\___/\_| \_| \____/\__,_|
 
                                Configuration Program
-                                for UnrealIRCd 5.0.5
+                                for UnrealIRCd 5.0.6
                                     
 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,7 +1,53 @@
-UnrealIRCd 5.0.5 Release Notes
+UnrealIRCd 5.0.6 Release Notes
 ===============================
 
-This release mainly focuses on new features, while also fixing a few bugs.
+UnrealIRCd 5.0.6 is a small maintenance release for the stable 5.x series.
+For existing 5.x users there is probably little reason to upgrade.
+
+Enhancements:
+* Spanish help conf was added (conf/help/help.es.conf)
+
+Fixes:
+* History playback on join was not obeying the limits from
+  [set::history::channel::playback-on-join](https://www.unrealircd.org/docs/Set_block#set::history).
+  Note that if you want to see more lines, there is the ```HISTORY```
+  command. For more information on the different ways to retrieve history, see
+  [Channel History](https://www.unrealircd.org/docs/Channel_history)
+* [Spamfilter](https://www.unrealircd.org/docs/Spamfilter) with the
+  ['tempshun' action](https://www.unrealircd.org/docs/Actions) was letting
+  the message through.
+* In very specific circumstances a ```REHASH -tls``` would cause outgoing
+  linking to fail with the error "called a function you should not call".
+* Crash if empty [set::cloak-method](https://www.unrealircd.org/docs/Set_block#set::cloak-method)
+* Issues with labeled-response on websockets (partial fix)
+
+Module coders / Developers:
+* In ```RPL_ISUPPORT``` we now announce ```BOT=B``` to indicate the user mode and
+  ```WHO``` status flag for bots.
+* ```HOOKTYPE_ACCOUNT_LOGIN``` is called for remote users too now (also on server syncs)
+* Send ```RPL_LOGGEDOUT``` when logging out of services account
+* Fix double batch in message tags when using both labeled-response
+  and the ```HISTORY``` command
+
+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.5.1
+-------------------
+
+5.0.5.1 reverts the previously introduced UTF8 Spamfilter support.
+Unfortunately we had to do this, due to a bug in the PCRE2 regex library
+that caused a freeze / infinite loop with certain regexes and text.
+
+UnrealIRCd 5.0.5
+-----------------
+
+This 5.0.5 release mainly focuses on new features, while also fixing a few bugs.
 
 Fixes:
 * [except ban { }](https://www.unrealircd.org/docs/Except_ban_block)
@@ -14,21 +60,6 @@ Fixes:
   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
@@ -67,13 +98,6 @@ Module coders / Developers:
   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
 ------------------
 
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.5
+PROJECT_NUMBER         = 5.0.6
 
 # 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/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 5
+#define UNREAL_VERSION_MINOR 6
 
 /* Version suffix such as a beta marker or release candidate marker. (e.g.:
    -rcX for unrealircd-3.2.9-rcX) */
diff --git a/src/conf.c b/src/conf.c
@@ -7975,6 +7975,12 @@ int	_test_set(ConfigFile *conf, ConfigEntry *ce)
 		else if (!strcmp(cep->ce_varname, "who-limit")) {
 			CheckNull(cep);
 			CheckDuplicate(cep, who_limit, "who-limit");
+			if (!config_checkval(cep->ce_vardata,CFG_SIZE))
+			{
+				config_error("%s:%i: set::who-limit: value must be at least 1",
+					cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
+				errors++;
+			}
 		}
 		else if (!strcmp(cep->ce_varname, "maxbans")) {
 			CheckNull(cep);
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_MATCH_INVALID_UTF;
+		options = PCRE2_CASELESS|PCRE2_NEVER_UTF|PCRE2_NEVER_UCP;
 		
 		m->ext.pcre2_expr = pcre2_compile(str, PCRE2_ZERO_TERMINATED, options, &errorcode, &erroroffset, NULL);
 		if (m->ext.pcre2_expr == NULL)
diff --git a/src/modules/chanmodes/history.c b/src/modules/chanmodes/history.c
@@ -535,7 +535,13 @@ int history_join(Client *client, Channel *channel, MessageTag *mtags, char *parv
 		return 0;
 
 	if (MyUser(client))
-		history_request(client, channel->chname, NULL);
+	{
+		HistoryFilter filter;
+		memset(&filter, 0, sizeof(filter));
+		filter.last_lines = cfg.playback_on_join.lines;
+		filter.last_seconds = cfg.playback_on_join.time;
+		history_request(client, channel->chname, &filter);
+	}
 
 	return 0;
 }
diff --git a/src/modules/cloak.c b/src/modules/cloak.c
@@ -128,6 +128,12 @@ int cloak_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
 		if (!ce || !ce->ce_varname || strcmp(ce->ce_varname, "cloak-method"))
 			return 0;
 
+		if (!ce->ce_vardata)
+		{
+			config_error("%s:%i: set::cloak-method: no method specified. The only supported methods are: 'ip' and 'host'",
+				ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
+			errors++;
+		} else
 		if (strcmp(ce->ce_vardata, "ip") && strcmp(ce->ce_vardata, "host"))
 		{
 			config_error("%s:%i: set::cloak-method: unknown method '%s'. The only supported methods are: 'ip' and 'host'",
diff --git a/src/modules/history.c b/src/modules/history.c
@@ -120,6 +120,7 @@ CMD_FUNC(cmd_history)
 		return;
 	}
 
+	memset(&filter, 0, sizeof(filter));
 	filter.last_lines = lines;
 	history_request(client, channel->chname, &filter);
 }
diff --git a/src/modules/history_backend_mem.c b/src/modules/history_backend_mem.c
@@ -311,7 +311,13 @@ int hbm_history_request(Client *client, char *object, HistoryFilter *filter)
 		sendto_one(client, NULL, ":%s BATCH +%s chathistory %s", me.name, batch, object);
 	}
 
-	redline = TStime() - h->max_time;
+	/* Decide on red line, under this the history is too old.
+	 * Filter can be more strict than history object (but not the other way around):
+	 */
+	if (filter && filter->last_seconds && (filter->last_seconds < h->max_time))
+		redline = TStime() - filter->last_seconds;
+	else
+		redline = TStime() - h->max_time;
 
 	/* Once the filter API expands, the following will change too.
 	 * For now, this is sufficient, since requests are only about lines:
diff --git a/src/modules/labeled-response.c b/src/modules/labeled-response.c
@@ -93,10 +93,10 @@ MOD_INIT()
 	mtag.clicap_handler = c;
 	MessageTagHandlerAdd(modinfo->handle, &mtag);
 
-	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);
+	HookAdd(modinfo->handle, HOOKTYPE_PRE_COMMAND, -1000000000, lr_pre_command);
+	HookAdd(modinfo->handle, HOOKTYPE_POST_COMMAND, 1000000000, lr_post_command);
+	HookAdd(modinfo->handle, HOOKTYPE_CLOSE_CONNECTION, 1000000000, lr_close_connection);
+	HookAdd(modinfo->handle, HOOKTYPE_PACKET, 1000000000, lr_packet);
 
 	return MOD_SUCCESS;
 }
@@ -277,17 +277,34 @@ int lr_packet(Client *from, Client *to, Client *intended_to, char **msg, int *le
 				char *batchstr = gen_start_batch();
 				int more_tags_one = currentcmd.firstbuf[0] == '@';
 				int more_tags_two = **msg == '@';
-				snprintf(packet, sizeof(packet),
-				         "%s\r\n"
-				         "@batch=%s%s%s\r\n"
-				         "@batch=%s%s%s",
-				         batchstr,
-				         currentcmd.batch,
-				         more_tags_one ? ";" : " ",
-				         more_tags_one ? currentcmd.firstbuf+1 : currentcmd.firstbuf,
-				         currentcmd.batch,
-				         more_tags_two ? ";" : " ",
-				         more_tags_two ? *msg+1 : *msg);
+
+				if (!strncmp(*msg, "@batch", 6))
+				{
+					/* Special case: current message (*msg) already contains a batch */
+					snprintf(packet, sizeof(packet),
+						 "%s\r\n"
+						 "@batch=%s%s%s\r\n"
+						 "%s",
+						 batchstr,
+						 currentcmd.batch,
+						 more_tags_one ? ";" : " ",
+						 more_tags_one ? currentcmd.firstbuf+1 : currentcmd.firstbuf,
+						 *msg);
+				} else
+				{
+					/* Regular case: current message (*msg) contains no batch yet, add one.. */
+					snprintf(packet, sizeof(packet),
+						 "%s\r\n"
+						 "@batch=%s%s%s\r\n"
+						 "@batch=%s%s%s",
+						 batchstr,
+						 currentcmd.batch,
+						 more_tags_one ? ";" : " ",
+						 more_tags_one ? currentcmd.firstbuf+1 : currentcmd.firstbuf,
+						 currentcmd.batch,
+						 more_tags_two ? ";" : " ",
+						 more_tags_two ? *msg+1 : *msg);
+				}
 				*msg = packet;
 				*len = strlen(*msg);
 			} else {
diff --git a/src/modules/nick.c b/src/modules/nick.c
@@ -682,6 +682,9 @@ nickkill2done:
 	if (!IsULine(serv) && IsSynched(serv))
 		sendto_fconnectnotice(client, 0, NULL);
 
+	if (client->user->svid[0] != '0')
+		user_account_login(recv_mtags, client);
+
 	RunHook(HOOKTYPE_REMOTE_CONNECT, client);
 }
 
diff --git a/src/modules/sajoin.c b/src/modules/sajoin.c
@@ -280,7 +280,7 @@ CMD_FUNC(cmd_sajoin)
 		{
 			if (!sjmode)
 			{
-				//sendnotice(target, "*** You were forced to join %s", jbuf);
+				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",
@@ -288,7 +288,7 @@ CMD_FUNC(cmd_sajoin)
 			}
 			else
 			{
-				//sendnotice(target, "*** You were forced to join %s with '%c'", jbuf, sjmode);
+				sendnotice(target, "*** You were forced to join %s with '%c'", jbuf, sjmode);
 				sendto_umode_global(UMODE_OPER, "%s used SAJOIN to make %s join %c%s", client->name, target->name, sjmode, jbuf);
 				ircd_log(LOG_SACMDS,"SAJOIN: %s used SAJOIN to make %s join %c%s",
 					client->name, target->name, sjmode, jbuf);
diff --git a/src/modules/sasl.c b/src/modules/sasl.c
@@ -37,6 +37,7 @@ char *saslmechlist_serialize(ModData *m);
 void saslmechlist_unserialize(char *str, ModData *m);
 char *sasl_capability_parameter(Client *client);
 int sasl_server_synced(Client *client);
+int sasl_account_login(Client *client, MessageTag *mtags);
 EVENT(sasl_timeout);
 
 /* Macros */
@@ -64,6 +65,29 @@ long CAP_SASL = 0L;
  * IRC.
  */
 
+int sasl_account_login(Client *client, MessageTag *mtags)
+{
+	if (!MyConnect(client))
+		return 0;
+	/* Notify user */
+	if (client->user->svid[0] != '0')
+	{
+		sendnumeric(client, RPL_LOGGEDIN,
+			BadPtr(client->name) ? "*" : client->name,
+			BadPtr(client->user->username) ? "*" : client->user->username,
+			BadPtr(client->user->realhost) ? "*" : client->user->realhost,
+			client->user->svid, client->user->svid);
+	}
+	else
+	{
+		sendnumeric(client, RPL_LOGGEDOUT,
+			BadPtr(client->name) ? "*" : client->name,
+			BadPtr(client->user->username) ? "*" : client->user->username,
+			BadPtr(client->user->realhost) ? "*" : client->user->realhost);
+	}
+	return 0;
+}
+
 /*
  * SVSLOGIN message
  *
@@ -93,17 +117,6 @@ CMD_FUNC(cmd_svslogin)
 			make_user(target);
 
 		strlcpy(target->user->svid, parv[3], sizeof(target->user->svid));
-
-		if (MyConnect(target))
-		{
-			/* Notify user */
-			sendnumeric(target, RPL_LOGGEDIN,
-				   BadPtr(target->name) ? "*" : target->name,
-				   BadPtr(target->user->username) ? "*" : target->user->username,
-				   BadPtr(target->user->realhost) ? "*" : target->user->realhost,
-				   target->user->svid, target->user->svid);
-		}
-
 		user_account_login(recv_mtags, target);
 	} else {
 		/* It is perfectly normal for target to be NULL as this
@@ -366,6 +379,7 @@ MOD_INIT()
 	HookAdd(modinfo->handle, HOOKTYPE_LOCAL_QUIT, 0, sasl_quit);
 	HookAdd(modinfo->handle, HOOKTYPE_SERVER_QUIT, 0, sasl_server_quit);
 	HookAdd(modinfo->handle, HOOKTYPE_SERVER_SYNCED, 0, sasl_server_synced);
+	HookAdd(modinfo->handle, HOOKTYPE_ACCOUNT_LOGIN, 0, sasl_account_login);
 
 	memset(&cap, 0, sizeof(cap));
 	cap.name = "sasl";
diff --git a/src/modules/svsmode.c b/src/modules/svsmode.c
@@ -407,13 +407,6 @@ void do_svsmode(Client *client, MessageTag *recv_mtags, int parc, char *parv[], 
 				if (parv[3])
 				{
 					strlcpy(target->user->svid, parv[3], sizeof(target->user->svid));
-					if(MyConnect(target))
-						/* Notify user */
-						sendnumeric(target, RPL_LOGGEDIN,
-							   BadPtr(target->name) ? "*" : target->name,
-							   BadPtr(target->user->username) ? "*" : target->user->username,
-							   BadPtr(target->user->realhost) ? "*" : target->user->realhost,
-							   target->user->svid, target->user->svid);
 					user_account_login(recv_mtags, target);
 				}
 				else
diff --git a/src/modules/tkl.c b/src/modules/tkl.c
@@ -4391,7 +4391,7 @@ int _place_host_ban(Client *client, BanAction action, char *reason, long duratio
 				client->user ? client->user->realhost : GetIP(client),
 				reason);
 			SetShunned(client);
-			break;
+			return 1;
 		case BAN_ACT_GZLINE:
 		case BAN_ACT_GLINE:
 		case BAN_ACT_SOFT_GLINE:
diff --git a/src/modules/usermodes/bot.c b/src/modules/usermodes/bot.c
@@ -47,6 +47,7 @@ MOD_TEST()
 MOD_INIT()
 {
 	UmodeAdd(modinfo->handle, 'B', UMODE_GLOBAL, 0, NULL, &UMODE_BOT);
+	ISupportAdd(modinfo->handle, "BOT", "B");
 	
 	HookAdd(modinfo->handle, HOOKTYPE_WHOIS, 0, bot_whois);
 	HookAdd(modinfo->handle, HOOKTYPE_WHO_STATUS, 0, bot_who_status);
diff --git a/src/modules/websocket.c b/src/modules/websocket.c
@@ -78,8 +78,8 @@ MOD_INIT()
 	MARK_AS_OFFICIAL_MODULE(modinfo);
 
 	HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN_EX, 0, websocket_config_run_ex);
-	HookAdd(modinfo->handle, HOOKTYPE_PACKET, 0, websocket_packet_out);
-	HookAdd(modinfo->handle, HOOKTYPE_RAWPACKET_IN, 0, websocket_packet_in);
+	HookAdd(modinfo->handle, HOOKTYPE_PACKET, INT_MAX, websocket_packet_out);
+	HookAdd(modinfo->handle, HOOKTYPE_RAWPACKET_IN, INT_MIN, websocket_packet_in);
 
 	memset(&mreq, 0, sizeof(mreq));
 	mreq.name = "websocket";
diff --git a/src/send.c b/src/send.c
@@ -993,7 +993,7 @@ void sendto_connectnotice(Client *newuser, int disconnect, char *comment)
 
 		*secure = '\0';
 		if (IsSecure(newuser))
-			snprintf(secure, sizeof(secure), " [secure %s]", SSL_get_cipher(newuser->local->ssl));
+			snprintf(secure, sizeof(secure), " [secure %s]", tls_get_cipher(newuser->local->ssl));
 
 		ircsnprintf(connect, sizeof(connect),
 		    "*** Client connecting: %s (%s@%s) [%s] {%s}%s", newuser->name,
diff --git a/src/tls.c b/src/tls.c
@@ -625,7 +625,7 @@ void reinit_ssl(Client *client)
 	{
 		if (link->tls_options)
 		{
-			tmp = init_ctx(link->tls_options, 1);
+			tmp = init_ctx(link->tls_options, 0);
 			if (!tmp)
 			{
 				config_error("SSL Reload partially failed. link::outgoing::tls-options error in link %s { }, see above",
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.5"
+id="5.0.6"
 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.5.0"
+    version="5.0.6.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.5
+AppVerName=UnrealIRCd 5.0.6
 AppPublisher=UnrealIRCd Team
 AppPublisherURL=https://www.unrealircd.org
 AppSupportURL=https://www.unrealircd.org