summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorSoniEx2 <endermoneymod@gmail.com>2022-04-11 21:54:33 -0300
committerSoniEx2 <endermoneymod@gmail.com>2022-04-21 20:23:35 -0300
commit5f137d2c81878c41aa3b893fb56b1116bc27bc78 (patch)
tree2d6eadb2474e2d7b234b3dda9efd7559335adce7 /src
parente2cfba040e26927b94a4e311a0a61365a81a41b1 (diff)
parent133f62806441a5db1156653aa1f077d2e8deeb34 (diff)
Merge upstream changes
Diffstat (limited to 'src')
-rw-r--r--src/common/ctcp.c5
-rw-r--r--src/common/dbus/meson.build2
-rw-r--r--src/common/fe.h11
-rw-r--r--src/common/hexchat.c16
-rw-r--r--src/common/hexchat.h4
-rw-r--r--src/common/inbound.c12
-rw-r--r--src/common/meson.build16
-rw-r--r--src/common/modes.c9
-rw-r--r--src/common/notify.c7
-rw-r--r--src/common/outbound.c104
-rw-r--r--src/common/plugin-timer.c2
-rw-r--r--src/common/proto-irc.c111
-rw-r--r--src/common/proto-irc.h2
-rw-r--r--src/common/server.c36
-rw-r--r--src/common/servlist.c140
-rw-r--r--src/common/ssl.c21
-rw-r--r--src/common/ssl.h2
-rw-r--r--src/common/sysinfo/win32/backend.c6
-rw-r--r--src/common/text.c11
-rw-r--r--src/common/textevents.in36
-rw-r--r--src/common/util.c1
-rw-r--r--src/fe-gtk/fe-gtk.c53
-rw-r--r--src/fe-gtk/maingui.c27
-rw-r--r--src/fe-gtk/meson.build10
-rw-r--r--src/fe-gtk/notifications/notification-freedesktop.c148
-rw-r--r--src/fe-gtk/notifications/notification-libnotify.c81
-rw-r--r--src/fe-gtk/plugin-notification.c2
-rw-r--r--src/fe-gtk/servlistgui.c14
-rw-r--r--src/fe-gtk/setup.c2
-rw-r--r--src/fe-gtk/sexy-spell-entry.c20
-rw-r--r--src/fe-gtk/xtext.c17
-rw-r--r--src/fe-gtk/xtext.h22
-rw-r--r--src/fe-text/fe-text.c2
-rw-r--r--src/meson.build6
34 files changed, 571 insertions, 387 deletions
diff --git a/src/common/ctcp.c b/src/common/ctcp.c
index a8e1ea8d..f9c05440 100644
--- a/src/common/ctcp.c
+++ b/src/common/ctcp.c
@@ -94,9 +94,6 @@ ctcp_handle (session *sess, char *to, char *nick, char *ip,
 	char outbuf[1024];
 	int ctcp_offset = 2;
 
-	if (serv->have_idmsg && (word[4][1] == '+' || word[4][1] == '-') )
-			ctcp_offset = 3;
-
 	/* consider DCC to be different from other CTCPs */
 	if (!g_ascii_strncasecmp (msg, "DCC", 3))
 	{
@@ -129,7 +126,7 @@ ctcp_handle (session *sess, char *to, char *nick, char *ip,
 		if (ctcp_check (sess, nick, word, word_eol, word[4] + ctcp_offset))
 			goto generic;
 
-		inbound_action (sess, to, nick, ip, msg + 7, FALSE, id, tags_data);
+		inbound_action (sess, to, nick, ip, msg + 7, FALSE, tags_data->identified, tags_data);
 		return;
 	}
 
diff --git a/src/common/dbus/meson.build b/src/common/dbus/meson.build
index 69066be0..856bbe55 100644
--- a/src/common/dbus/meson.build
+++ b/src/common/dbus/meson.build
@@ -1,5 +1,5 @@
 dbus_deps = [
-  dependency('dbus-glib-1')
+  dbus_glib_dep
 ]
 
 dbus_sources = [
diff --git a/src/common/fe.h b/src/common/fe.h
index 6614055b..9da4e230 100644
--- a/src/common/fe.h
+++ b/src/common/fe.h
@@ -69,7 +69,16 @@ int fe_input_add (int sok, int flags, void *func, void *data);
 void fe_input_remove (int tag);
 void fe_idle_add (void *func, void *data);
 void fe_set_topic (struct session *sess, char *topic, char *stripped_topic);
-void fe_set_tab_color (struct session *sess, int col);
+typedef enum
+{
+	FE_COLOR_NONE = 0,
+	FE_COLOR_NEW_DATA = 1,
+	FE_COLOR_NEW_MSG = 2,
+	FE_COLOR_NEW_HILIGHT = 3,
+	FE_COLOR_FLAG_NOOVERRIDE = 8,
+} tabcolor;
+#define FE_COLOR_ALLFLAGS (FE_COLOR_FLAG_NOOVERRIDE)
+void fe_set_tab_color (struct session *sess, tabcolor col);
 void fe_flash_window (struct session *sess);
 void fe_update_mode_buttons (struct session *sess, char mode, char sign);
 void fe_update_channel_key (struct session *sess);
diff --git a/src/common/hexchat.c b/src/common/hexchat.c
index 9be2e56d..a2e88a0d 100644
--- a/src/common/hexchat.c
+++ b/src/common/hexchat.c
@@ -57,10 +57,6 @@
 #include <glib-object.h>			/* for g_type_init() */
 #endif
 
-#ifdef USE_LIBPROXY
-#include <proxy.h>
-#endif
-
 GSList *popup_list = 0;
 GSList *button_list = 0;
 GSList *dlgbutton_list = 0;
@@ -111,10 +107,6 @@ struct session *current_tab;
 struct session *current_sess = 0;
 struct hexchatprefs prefs;
 
-#ifdef USE_LIBPROXY
-pxProxyFactory *libproxy_factory;
-#endif
-
 /*
  * Update the priority queue of the "interesting sessions"
  * (sess_list_by_lastact).
@@ -1102,10 +1094,6 @@ main (int argc, char *argv[])
 	hexchat_remote ();
 #endif
 
-#ifdef USE_LIBPROXY
-	libproxy_factory = px_proxy_factory_new ();
-#endif
-
 #ifdef WIN32
 	coinit_result = CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);
 	if (SUCCEEDED (coinit_result))
@@ -1148,10 +1136,6 @@ main (int argc, char *argv[])
 	}
 #endif
 
-#ifdef USE_LIBPROXY
-	px_proxy_factory_free (libproxy_factory);
-#endif
-
 #ifdef WIN32
 	WSACleanup ();
 #endif
diff --git a/src/common/hexchat.h b/src/common/hexchat.h
index d8effa1f..43a5f43a 100644
--- a/src/common/hexchat.h
+++ b/src/common/hexchat.h
@@ -503,7 +503,7 @@ typedef struct server
 	char servername[128];			/* what the server says is its name */
 	char password[86];
 	char nick[NICKLEN];
-	char linebuf[2048];				/* RFC says 512 chars including \r\n */
+	char linebuf[8704];				/* RFC says 512 chars including \r\n, IRCv3 message tags add 8191, plus the NUL byte */
 	char *last_away_reason;
 	int pos;								/* current position in linebuf */
 	int nickcount;
@@ -567,7 +567,7 @@ typedef struct server
 	unsigned int have_awaynotify:1;
 	unsigned int have_uhnames:1;
 	unsigned int have_whox:1;		/* have undernet's WHOX features */
-	unsigned int have_idmsg:1;		/* freenode's IDENTIFY-MSG */
+	unsigned int have_idmsg:1;		/* cap solanum.chat/identify-msg */
 	unsigned int have_accnotify:1; /* cap account-notify */
 	unsigned int have_extjoin:1;	/* cap extended-join */
 	unsigned int have_account_tag:1;	/* cap account-tag */
diff --git a/src/common/inbound.c b/src/common/inbound.c
index 7175b2ae..3c505a57 100644
--- a/src/common/inbound.c
+++ b/src/common/inbound.c
@@ -107,7 +107,8 @@ find_session_from_nick (char *nick, server *serv)
 
 	if (serv->front_session)
 	{
-		if (userlist_find (serv->front_session, nick))
+		// If we are here for ChanServ, then it is usually a reply for the user
+		if (!g_ascii_strcasecmp(nick, "ChanServ") || userlist_find (serv->front_session, nick))
 			return serv->front_session;
 	}
 
@@ -189,7 +190,7 @@ inbound_privmsg (server *serv, char *from, char *ip, char *text, int id,
 
 		if (ip && ip[0])
 			set_topic (sess, ip, ip);
-		inbound_chanmsg (serv, NULL, NULL, from, text, FALSE, id, tags_data);
+		inbound_chanmsg (serv, NULL, NULL, from, text, FALSE, tags_data->identified, tags_data);
 		return;
 	}
 
@@ -1655,7 +1656,7 @@ inbound_toggle_caps (server *serv, const char *extensions_str, gboolean enable)
 	{
 		const char *extension = extensions[i];
 
-		if (!strcmp (extension, "identify-msg"))
+		if (!strcmp (extension, "solanum.chat/identify-msg"))
 			serv->have_idmsg = enable;
 		else if (!strcmp (extension, "multi-prefix"))
 			serv->have_namesx = enable;
@@ -1712,8 +1713,6 @@ inbound_cap_del (server *serv, char *nick, char *extensions,
 }
 
 static const char * const supported_caps[] = {
-	"identify-msg",
-
 	/* IRCv3.1 */
 	"multi-prefix",
 	"away-notify",
@@ -1736,6 +1735,9 @@ static const char * const supported_caps[] = {
 
 	/* Twitch */
 	"twitch.tv/membership",
+
+	/* Solanum */
+	"solanum.chat/identify-msg",
 };
 
 static int
diff --git a/src/common/meson.build b/src/common/meson.build
index 492227b2..84e2fca3 100644
--- a/src/common/meson.build
+++ b/src/common/meson.build
@@ -28,6 +28,7 @@ common_sysinfo_deps = []
 
 common_deps = [
   libgio_dep,
+  libcanberra_dep,
 ] + global_deps
 
 common_includes = [
@@ -46,7 +47,6 @@ if host_machine.system() == 'windows'
   ]
   common_sysinfo_deps += [
     cc.find_library('wbemuuid'), # sysinfo
-    cc.find_library('wbemcore'),
   ]
 
   common_sources += 'sysinfo/win32/backend.c'
@@ -72,26 +72,18 @@ textevents = custom_target('textevents',
 #   SIGACTION
 #   HAVE_GTK_MAC
 
-if get_option('with-ssl')
+if libssl_dep.found()
   common_sources += 'ssl.c'
   common_deps += libssl_dep
 endif
 
-if get_option('with-libproxy')
-  common_deps += dependency('libproxy-1.0')
-endif
-
-if get_option('with-libcanberra')
-  common_deps += dependency('libcanberra', version: '>= 0.22')
-endif
-
-if get_option('with-dbus')
+if dbus_glib_dep.found()
   subdir('dbus')
   common_deps += hexchat_dbus_dep
   common_includes += include_directories('dbus')
 endif
 
-if get_option('with-plugin')
+if get_option('plugin')
   common_deps += libgmodule_dep
   install_headers('hexchat-plugin.h')
 endif
diff --git a/src/common/modes.c b/src/common/modes.c
index 82b466cb..756f0858 100644
--- a/src/common/modes.c
+++ b/src/common/modes.c
@@ -67,8 +67,8 @@ send_channel_modes (session *sess, char *tbuf, char *word[], int wpos,
 	int usable_modes, orig_len, len, wlen, i, max;
 	server *serv = sess->server;
 
-	/* sanity check. IRC RFC says three per line. */
-	if (serv->modes_per_line < 3)
+	/* sanity check. IRC RFC says three per line but some servers may support less. */
+	if (serv->modes_per_line < 1)
 		serv->modes_per_line = 3;
 	if (modes_per_line < 1)
 		modes_per_line = serv->modes_per_line;
@@ -880,7 +880,7 @@ inbound_005 (server * serv, char *word[], const message_tags_data *tags_data)
 				g_free (serv->nick_prefixes);
 				g_free (serv->nick_modes);
 				serv->nick_prefixes = g_strdup (pre + 1);
-				serv->nick_modes = g_strdup (tokvalue);
+				serv->nick_modes = g_strdup (tokvalue + 1);
 			} else
 			{
 				/* bad! some ircds don't give us the modes. */
@@ -913,6 +913,9 @@ inbound_005 (server * serv, char *word[], const message_tags_data *tags_data)
 			{
 				server_set_encoding (serv, "UTF-8");
 			}
+		} else if (g_strcmp0 (tokname, "UTF8ONLY") == 0)
+		{
+			server_set_encoding (serv, "UTF-8");
 		} else if (g_strcmp0 (tokname, "NAMESX") == 0)
 		{
 									/* 12345678901234567 */
diff --git a/src/common/notify.c b/src/common/notify.c
index b5316c36..ef52889b 100644
--- a/src/common/notify.c
+++ b/src/common/notify.c
@@ -123,7 +123,11 @@ notify_save (void)
 {
 	int fh;
 	struct notify *notify;
-	GSList *list = notify_list;
+        // while reading the notify.conf file, elements are added by prepending to the
+        // list. reverse the list before writing to disk to keep the original
+        // order of the list
+        GSList *list = g_slist_copy(notify_list);
+        list = g_slist_reverse(list);
 
 	fh = hexchat_open_file ("notify.conf", O_TRUNC | O_WRONLY | O_CREAT, 0600, XOF_DOMODE);
 	if (fh != -1)
@@ -142,6 +146,7 @@ notify_save (void)
 		}
 		close (fh);
 	}
+        g_slist_free(list);
 }
 
 void
diff --git a/src/common/outbound.c b/src/common/outbound.c
index 614aad38..6f0241be 100644
--- a/src/common/outbound.c
+++ b/src/common/outbound.c
@@ -1579,9 +1579,26 @@ cmd_execw (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 		EMIT_SIGNAL (XP_TE_NOCHILD, sess, NULL, NULL, NULL, NULL, 0);
 		return FALSE;
 	}
-	len = strlen(word_eol[2]);
-	temp = g_strconcat (word_eol[2], "\n", NULL);
-	PrintText(sess, temp);
+	if (strcmp (word[2], "--") == 0)
+	{
+		len = strlen(word_eol[3]);
+		temp = g_strconcat (word_eol[3], "\n", NULL);
+		PrintText(sess, temp);
+	}
+	else
+	{
+		if (strcmp (word[2], "-q") == 0)
+		{
+			len = strlen(word_eol[3]);
+			temp = g_strconcat (word_eol[3], "\n", NULL);
+		}
+		else
+		{
+			len = strlen(word_eol[2]);
+			temp = g_strconcat (word_eol[2], "\n", NULL);
+			PrintText(sess, temp);
+		}
+	}
 	write(sess->running_exec->myfd, temp, len + 1);
 	g_free(temp);
 
@@ -2152,7 +2169,6 @@ cmd_gui (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 	{
 	case 0x058b836e: fe_ctrl_gui (sess, 8, 0); break; /* APPLY */
 	case 0xac1eee45: fe_ctrl_gui (sess, 7, 2); break; /* ATTACH */
-	case 0x05a72f63: fe_ctrl_gui (sess, 4, atoi (word[3])); break; /* COLOR */
 	case 0xb06a1793: fe_ctrl_gui (sess, 7, 1); break; /* DETACH */
 	case 0x05cfeff0: fe_ctrl_gui (sess, 3, 0); break; /* FLASH */
 	case 0x05d154d8: fe_ctrl_gui (sess, 2, 0); break; /* FOCUS */
@@ -2166,6 +2182,12 @@ cmd_gui (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 		else
 			return FALSE;
 		break;
+	case 0x05a72f63: /* COLOR */
+		if (!g_ascii_strcasecmp (word[4], "-NOOVERRIDE"))
+			fe_ctrl_gui (sess, 4, FE_COLOR_FLAG_NOOVERRIDE | atoi (word[3]));
+		else
+			fe_ctrl_gui (sess, 4, atoi (word[3]));
+		break;
 	default:
 		return FALSE;
 	}
@@ -3225,16 +3247,23 @@ cmd_reconnect (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 	else if (*word[2])
 	{
 		int offset = 0;
+
 #ifdef USE_OPENSSL
 		int use_ssl = FALSE;
-
-		if (strcmp (word[2], "-ssl") == 0)
+		int use_ssl_noverify = FALSE;
+		if (g_strcmp0 (word[2], "-ssl") == 0)
+		{
+			use_ssl = TRUE;
+			use_ssl_noverify = FALSE;
+			offset++;	/* args move up by 1 word */
+		} else if (g_strcmp0 (word[2], "-ssl-noverify") == 0)
 		{
 			use_ssl = TRUE;
+			use_ssl_noverify = TRUE;
 			offset++;	/* args move up by 1 word */
 		}
 		serv->use_ssl = use_ssl;
-		serv->accept_invalid_cert = TRUE;
+		serv->accept_invalid_cert = use_ssl_noverify;
 #endif
 
 		if (*word[4+offset])
@@ -3422,17 +3451,24 @@ cmd_server (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 	char *channel = NULL;
 	char *key = NULL;
 	int use_ssl = FALSE;
+	int use_ssl_noverify = FALSE;
 	int is_url = TRUE;
 	server *serv = sess->server;
 	ircnet *net = NULL;
 
 #ifdef USE_OPENSSL
 	/* BitchX uses -ssl, mIRC uses -e, let's support both */
-	if (strcmp (word[2], "-ssl") == 0 || strcmp (word[2], "-e") == 0)
+	if (g_strcmp0 (word[2], "-ssl") == 0 || g_strcmp0 (word[2], "-e") == 0)
 	{
 		use_ssl = TRUE;
 		offset++;	/* args move up by 1 word */
 	}
+	else if (g_strcmp0 (word[2], "-ssl-noverify") == 0)
+	{
+		use_ssl = TRUE;
+		use_ssl_noverify = TRUE;
+		offset++;	/* args move up by 1 word */
+	}
 #endif
 
 	if (!parse_irc_url (word[2 + offset], &server_name, &port, &channel, &key, &use_ssl))
@@ -3497,7 +3533,7 @@ cmd_server (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 
 #ifdef USE_OPENSSL
 	serv->use_ssl = use_ssl;
-	serv->accept_invalid_cert = TRUE;
+	serv->accept_invalid_cert = use_ssl_noverify;
 #endif
 
 	/* try to connect by Network name */
@@ -3528,7 +3564,7 @@ cmd_servchan (struct session *sess, char *tbuf, char *word[],
 	int offset = 0;
 
 #ifdef USE_OPENSSL
-	if (strcmp (word[2], "-ssl") == 0)
+	if (g_strcmp0 (word[2], "-ssl") == 0 || g_strcmp0 (word[2], "-ssl-noverify") == 0)
 		offset++;
 #endif
 
@@ -3863,34 +3899,6 @@ cmd_wallchop (struct session *sess, char *tbuf, char *word[],
 }
 
 static int
-cmd_wallchan (struct session *sess, char *tbuf, char *word[],
-				  char *word_eol[])
-{
-	GSList *list;
-
-	if (*word_eol[2])
-	{
-		list = sess_list;
-		while (list)
-		{
-			sess = list->data;
-			if (sess->type == SESS_CHANNEL)
-			{
-				message_tags_data no_tags = MESSAGE_TAGS_DATA_INIT;
-
-				inbound_chanmsg (sess->server, NULL, sess->channel,
-									  sess->server->nick, word_eol[2], TRUE, FALSE, 
-									  &no_tags);
-				sess->server->p_message (sess->server, sess->channel, word_eol[2]);
-			}
-			list = list->next;
-		}
-		return TRUE;
-	}
-	return FALSE;
-}
-
-static int
 cmd_hop (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 {
 	int i = 2;
@@ -3930,7 +3938,7 @@ cmd_voice (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 const struct commands xc_cmds[] = {
 	{"ADDBUTTON", cmd_addbutton, 0, 0, 1,
 	 N_("ADDBUTTON <name> <action>, adds a button under the user-list")},
-	{"ADDSERVER", cmd_addserver, 0, 0, 1, N_("ADDSERVER <NewNetwork> <newserver/6667>, adds a new network with a new server to the network list")},
+	{"ADDSERVER", cmd_addserver, 0, 0, 1, N_("ADDSERVER <NewNetwork> <hostname/port>, adds a new network with a new server to the network list")},
 	{"ALLCHAN", cmd_allchannels, 0, 0, 1,
 	 N_("ALLCHAN <cmd>, sends a command to all channels you're in")},
 	{"ALLCHANL", cmd_allchannelslocal, 0, 0, 1,
@@ -3986,7 +3994,7 @@ const struct commands xc_cmds[] = {
 	 N_("EXECKILL [-9], kills a running exec in the current session. If -9 is given the process is SIGKILL'ed")},
 #ifndef __EMX__
 	{"EXECSTOP", cmd_execs, 0, 0, 1, N_("EXECSTOP, sends the process SIGSTOP")},
-	{"EXECWRITE", cmd_execw, 0, 0, 1, N_("EXECWRITE, sends data to the processes stdin")},
+	{"EXECWRITE", cmd_execw, 0, 0, 1, N_("EXECWRITE [-q|--], sends data to the processes stdin; use -q flag to quiet/suppress output at text box; use -- flag to stop interpreting arguments as flags, needed if -q itself would occur as data")},
 #endif
 #endif
 #if 0
@@ -4001,8 +4009,9 @@ const struct commands xc_cmds[] = {
 	{"GETINT", cmd_getint, 0, 0, 1, "GETINT <default> <command> <prompt>"},
 	{"GETSTR", cmd_getstr, 0, 0, 1, "GETSTR <default> <command> <prompt>"},
 	{"GHOST", cmd_ghost, 1, 0, 1, N_("GHOST <nick> [password], Kills a ghosted nickname")},
-	{"GUI", cmd_gui, 0, 0, 1, "GUI [APPLY|ATTACH|DETACH|SHOW|HIDE|FOCUS|FLASH|ICONIFY|COLOR <n>]\n"
-									  "       GUI [MSGBOX <text>|MENU TOGGLE]"},
+	{"GUI", cmd_gui, 0, 0, 1, "GUI [APPLY|ATTACH|DETACH|SHOW|HIDE|FOCUS|FLASH|ICONIFY]\n"
+									  "       GUI [MSGBOX <text>|MENU TOGGLE]\n"
+									  "       GUI COLOR <n> [-NOOVERRIDE]"},
 	{"HELP", cmd_help, 0, 0, 1, 0},
 	{"HOP", cmd_hop, 1, 1, 1,
 	 N_("HOP <nick>, gives chanhalf-op status to the nick (needs chanop)")},
@@ -4077,7 +4086,7 @@ const struct commands xc_cmds[] = {
 	 N_("QUOTE <text>, sends the text in raw form to the server")},
 #ifdef USE_OPENSSL
 	{"RECONNECT", cmd_reconnect, 0, 0, 1,
-	 N_("RECONNECT [-ssl] [<host>] [<port>] [<password>], Can be called just as /RECONNECT to reconnect to the current server or with /RECONNECT ALL to reconnect to all the open servers")},
+	 N_("RECONNECT [-ssl|-ssl-noverify] [<host>] [<port>] [<password>], Can be called just as /RECONNECT to reconnect to the current server or with /RECONNECT ALL to reconnect to all the open servers")},
 #else
 	{"RECONNECT", cmd_reconnect, 0, 0, 1,
 	 N_("RECONNECT [<host>] [<port>] [<password>], Can be called just as /RECONNECT to reconnect to the current server or with /RECONNECT ALL to reconnect to all the open servers")},
@@ -4089,14 +4098,14 @@ const struct commands xc_cmds[] = {
 	{"SEND", cmd_send, 0, 0, 1, N_("SEND <nick> [<file>]")},
 #ifdef USE_OPENSSL
 	{"SERVCHAN", cmd_servchan, 0, 0, 1,
-	 N_("SERVCHAN [-ssl] <host> <port> <channel>, connects and joins a channel")},
+	 N_("SERVCHAN [-ssl|-ssl-noverify] <host> <port> <channel>, connects and joins a channel")},
 #else
 	{"SERVCHAN", cmd_servchan, 0, 0, 1,
 	 N_("SERVCHAN <host> <port> <channel>, connects and joins a channel")},
 #endif
 #ifdef USE_OPENSSL
 	{"SERVER", cmd_server, 0, 0, 1,
-	 N_("SERVER [-ssl] <host> [<port>] [<password>], connects to a server, the default port is 6667 for normal connections, and 6697 for ssl connections")},
+	 N_("SERVER [-ssl|-ssl-noverify] <host> [<port>] [<password>], connects to a server, the default port is 6667 for normal connections, and 6697 for ssl connections")},
 #else
 	{"SERVER", cmd_server, 0, 0, 1,
 	 N_("SERVER <host> [<port>] [<password>], connects to a server, the default port is 6667")},
@@ -4127,8 +4136,6 @@ const struct commands xc_cmds[] = {
 	{"USERLIST", cmd_userlist, 1, 1, 1, 0},
 	{"VOICE", cmd_voice, 1, 1, 1,
 	 N_("VOICE <nick>, gives voice status to someone (needs chanop)")},
-	{"WALLCHAN", cmd_wallchan, 1, 1, 1,
-	 N_("WALLCHAN <message>, writes the message to all channels")},
 	{"WALLCHOP", cmd_wallchop, 1, 1, 1,
 	 N_("WALLCHOP <message>, sends the message to all chanops on the current channel")},
 	{0, 0, 0, 0, 0, 0}
@@ -4420,6 +4427,9 @@ check_special_chars (char *cmd, int do_ascii) /* check for %X */
 				case 'I':
 					buf[i] = '\035';
 					break;
+				case 'S':
+					buf[i] = '\036';
+					break;
 				case 'C':
 					buf[i] = '\003';
 					break;
diff --git a/src/common/plugin-timer.c b/src/common/plugin-timer.c
index d0c82c28..17f11ce3 100644
--- a/src/common/plugin-timer.c
+++ b/src/common/plugin-timer.c
@@ -198,7 +198,7 @@ timer_cb (char *word[], char *word_eol[], void *userdata)
 		offset += 2;
 	}
 
-	timeout = atof (word[2 + offset]);
+	timeout = g_ascii_strtod (word[2 + offset], NULL);
 	command = word_eol[3 + offset];
 
 	if (timeout < 0.1 || timeout * 1000 > INT_MAX || !command[0])
diff --git a/src/common/proto-irc.c b/src/common/proto-irc.c
index c8e44b62..32cc47f2 100644
--- a/src/common/proto-irc.c
+++ b/src/common/proto-irc.c
@@ -460,6 +460,18 @@ channel_date (session *sess, char *chan, char *timestr,
 								  tags_data->timestamp);
 }
 
+static int
+trailing_index(const char *word_eol[])
+{
+	int param_index;
+	for (param_index = 3; param_index < PDIWORDS; ++param_index)
+	{
+		if (word_eol[param_index][0] == ':')
+			break;
+	}
+	return param_index;
+}
+
 static void
 process_numeric (session * sess, int n,
 					  char *word[], char *word_eol[], char *text,
@@ -491,22 +503,6 @@ process_numeric (session * sess, int n,
 
 		goto def;
 
-	case 4:	/* check the ircd type */
-		serv->use_listargs = FALSE;
-		serv->modes_per_line = 3;		/* default to IRC RFC */
-		if (strncmp (word[5], "bahamut", 7) == 0)				/* DALNet */
-		{
-			serv->use_listargs = TRUE;		/* use the /list args */
-		} else if (strncmp (word[5], "u2.10.", 6) == 0)		/* Undernet */
-		{
-			serv->use_listargs = TRUE;		/* use the /list args */
-			serv->modes_per_line = 6;		/* allow 6 modes per line */
-		} else if (strncmp (word[5], "glx2", 4) == 0)
-		{
-			serv->use_listargs = TRUE;		/* use the /list args */
-		}
-		goto def;
-
 	case 5:
 		inbound_005 (serv, word, tags_data);
 		goto def;
@@ -631,7 +627,7 @@ process_numeric (session * sess, int n,
 	case 320:	/* :is an identified user */
 		if (!serv->skip_next_whois)
 			EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_ID, whois_sess, word[4],
-										  word_eol[5] + 1, NULL, NULL, 0,
+										  word_eol[5][0] == ':' ? word_eol[5] + 1 : word_eol[5], NULL, NULL, 0,
 										  tags_data->timestamp);
 		break;
 
@@ -801,7 +797,7 @@ process_numeric (session * sess, int n,
 		break;
 
 	case 346:	/* +I-list entry */
-		if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], 346,
+		if (!inbound_banlist (sess, atol (STRIP_COLON (word, word_eol, 7)), word[4], word[5], word[6], 346,
 									 tags_data))
 			goto def;
 		break;
@@ -812,7 +808,7 @@ process_numeric (session * sess, int n,
 		break;
 
 	case 348:	/* +e-list entry */
-		if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], 348,
+		if (!inbound_banlist (sess, atol (STRIP_COLON (word, word_eol, 7)), word[4], word[5], word[6], 348,
 									 tags_data))
 			goto def;
 		break;
@@ -837,7 +833,7 @@ process_numeric (session * sess, int n,
 		break;
 
 	case 367: /* banlist entry */
-		if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], 367,
+		if (!inbound_banlist (sess, atol (STRIP_COLON (word, word_eol, 7)), word[4], word[5], word[6], 367,
 									 tags_data))
 			goto def;
 		break;
@@ -924,6 +920,14 @@ process_numeric (session * sess, int n,
 		notify_set_online (serv, word[4], tags_data);
 		break;
 
+	case 524: // ERR_HELPNOTFOUND
+	case 704: // RPL_HELPSTART
+	case 705: // RPL_HELPTXT
+	case 706: // RPL_ENDOFHELP
+		EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, sess, STRIP_COLON(word, word_eol, 5), NULL, NULL, NULL,
+									  0, tags_data->timestamp);
+		break;
+
 	case 728:	/* +q-list entry */
 		/* NOTE:  FREENODE returns these results inconsistent with e.g. +b */
 		/* Who else has imlemented MODE_QUIET, I wonder? */
@@ -1139,6 +1143,39 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
 										(word_eol[3][0] == ':') ? word_eol[3] + 1 : NULL,
 										tags_data);
 			return;
+
+		case WORDL('F','A','I','L'):
+			text = STRIP_COLON(word, word_eol, trailing_index(word_eol));
+			if (g_strcmp0(word[3], "*") == 0)
+			{
+				EMIT_SIGNAL_TIMESTAMP (XP_TE_FAIL, sess, word[4], text, NULL, NULL, NULL, tags_data->timestamp);
+			} else
+			{
+				EMIT_SIGNAL_TIMESTAMP (XP_TE_FAILCMD, sess, word[3], word[4], text, NULL, NULL, tags_data->timestamp);
+			}
+			return;
+
+		case WORDL('W','A','R','N'):
+			text = STRIP_COLON(word, word_eol, trailing_index(word_eol));
+			if (g_strcmp0(word[3], "*") == 0)
+			{
+				EMIT_SIGNAL_TIMESTAMP (XP_TE_WARN, sess, word[4], text, NULL, NULL, NULL, tags_data->timestamp);
+			} else
+			{
+				EMIT_SIGNAL_TIMESTAMP (XP_TE_WARNCMD, sess, word[3], word[4], text, NULL, NULL, tags_data->timestamp);
+			}
+			return;
+
+		case WORDL('N','O','T','E'):
+			text = STRIP_COLON(word, word_eol, trailing_index(word_eol));
+			if (g_strcmp0(word[3], "*") == 0)
+			{
+				EMIT_SIGNAL_TIMESTAMP (XP_TE_NOTE, sess, word[4], text, NULL, NULL, NULL, tags_data->timestamp);
+			} else
+			{
+				EMIT_SIGNAL_TIMESTAMP (XP_TE_NOTECMD, sess, word[3], word[4], text, NULL, NULL, tags_data->timestamp);
+			}
+			return;
 		}
 
 		goto garbage;
@@ -1189,8 +1226,6 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
 
 		case WORDL('N','O','T','I'):
 			{
-				int id = FALSE;								/* identified */
-
 				text = word_eol[4];
 				if (*text == ':')
 				{
@@ -1219,18 +1254,8 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
 				}
 #endif
 
-				if (serv->have_idmsg)
-				{
-					if (*text == '+')
-					{
-						id = TRUE;
-						text++;
-					} else if (*text == '-')
-						text++;
-				}
-
 				if (!ignore_check (word[1], IG_NOTI))
-					inbound_notice (serv, word[3], nick, text, ip, id, tags_data);
+					inbound_notice (serv, word[3], nick, text, ip, tags_data->identified, tags_data);
 			}
 			return;
 
@@ -1238,7 +1263,6 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
 			{
 				char *to = word[3];
 				int len;
-				int id = FALSE;	/* identified */
 				if (*to)
 				{
 					/* Handle limited channel messages, for now no special event */
@@ -1249,15 +1273,7 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
 					text = word_eol[4];
 					if (*text == ':')
 						text++;
-					if (serv->have_idmsg)
-					{
-						if (*text == '+')
-						{
-							id = TRUE;
-							text++;
-						} else if (*text == '-')
-							text++;
-					}
+
 					len = strlen (text);
 					if (text[0] == 1)	/* ctcp */
 					{
@@ -1289,7 +1305,7 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
 							}
 						}
 
-						ctcp_handle (sess, to, nick, ip, text, word, word_eol, id,
+						ctcp_handle (sess, to, nick, ip, text, word, word_eol, tags_data->identified,
 										 tags_data);
 
 						/* Note word will be invalid beyond this scope */
@@ -1300,13 +1316,13 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
 						{
 							if (ignore_check (word[1], IG_CHAN))
 								return;
-							inbound_chanmsg (serv, NULL, to, nick, text, FALSE, id,
+							inbound_chanmsg (serv, NULL, to, nick, text, FALSE, tags_data->identified,
 												  tags_data);
 						} else
 						{
 							if (ignore_check (word[1], IG_PRIV))
 								return;
-							inbound_privmsg (serv, nick, ip, text, id, tags_data);
+							inbound_privmsg (serv, nick, ip, text, tags_data->identified, tags_data);
 						}
 					}
 				}
@@ -1537,6 +1553,9 @@ handle_message_tags (server *serv, const char *tags_str,
 		if (serv->have_account_tag && !strcmp (key, "account"))
 			tags_data->account = g_strdup (value);
 
+		if (serv->have_idmsg && strcmp (key, "solanum.chat/identified"))
+			tags_data->identified = TRUE;
+
 		if (serv->have_server_time && !strcmp (key, "time"))
 			handle_message_tag_time (value, tags_data);
 	}
diff --git a/src/common/proto-irc.h b/src/common/proto-irc.h
index 0f72c644..6f52f1bc 100644
--- a/src/common/proto-irc.h
+++ b/src/common/proto-irc.h
@@ -26,6 +26,7 @@
 #define MESSAGE_TAGS_DATA_INIT			\
 	{									\
 		NULL, /* account name */		\
+		FALSE, /* identified to nick */ \
 		(time_t)0, /* timestamp */		\
 	}
 
@@ -38,6 +39,7 @@
 typedef struct 
 {
 	char *account;
+	gboolean identified;
 	time_t timestamp;
 } message_tags_data;
 
diff --git a/src/common/server.c b/src/common/server.c
index 5c645eb5..e14da237 100644
--- a/src/common/server.c
+++ b/src/common/server.c
@@ -61,10 +61,6 @@
 #include "ssl.h"
 #endif
 
-#ifdef USE_LIBPROXY
-#include <proxy.h>
-#endif
-
 #ifdef USE_OPENSSL
 /* local variables */
 static struct session *g_sess = NULL;
@@ -78,9 +74,15 @@ static void server_disconnect (session * sess, int sendquit, int err);
 static int server_cleanup (server * serv);
 static void server_connect (server *serv, char *hostname, int port, int no_login);
 
-#ifdef USE_LIBPROXY
-extern pxProxyFactory *libproxy_factory;
-#endif
+static void
+write_error (char *message, GError **error)
+{
+	if (error == NULL || *error == NULL) {
+		return;
+	}
+	g_printerr ("%s: %s\n", message, (*error)->message);
+	g_clear_error (error);
+}
 
 /* actually send to the socket. This might do a character translation or
    send via SSL. server/dcc both use this function. */
@@ -360,7 +362,7 @@ server_read (GIOChannel *source, GIOCondition condition, server *serv)
 				serv->linebuf[serv->pos] = lbuf[i];
 				if (serv->pos >= (sizeof (serv->linebuf) - 1))
 					fprintf (stderr,
-								"*** HEXCHAT WARNING: Buffer overflow - shit server!\n");
+								"*** HEXCHAT WARNING: Buffer overflow - non-compliant server!\n");
 				else
 					serv->pos++;
 			}
@@ -770,7 +772,7 @@ server_connect_success (server *serv)
 
 		/* it'll be a memory leak, if connection isn't terminated by
 		   server_cleanup() */
-		if ((err = _SSL_set_verify (serv->ctx, ssl_cb_verify, NULL)))
+		if ((err = _SSL_set_verify (serv->ctx, ssl_cb_verify)))
 		{
 			EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, err, NULL,
 							 NULL, NULL, 0);
@@ -1392,14 +1394,16 @@ server_child (server * serv)
 
 	if (!serv->dont_use_proxy) /* blocked in serverlist? */
 	{
-#ifdef USE_LIBPROXY
 		if (prefs.hex_net_proxy_type == 5)
 		{
 			char **proxy_list;
 			char *url, *proxy;
+			GProxyResolver *resolver;
+			GError *error = NULL;
 
+			resolver = g_proxy_resolver_get_default ();
 			url = g_strdup_printf ("irc://%s:%d", hostname, port);
-			proxy_list = px_proxy_factory_get_proxies (libproxy_factory, url);
+			proxy_list = g_proxy_resolver_lookup (resolver, url, NULL, &error);
 
 			if (proxy_list) {
 				/* can use only one */
@@ -1412,6 +1416,8 @@ server_child (server * serv)
 					proxy_type = 3;
 				else if (!strncmp (proxy, "socks", 5))
 					proxy_type = 2;
+			} else {
+				write_error ("Failed to lookup proxy", &error);
 			}
 
 			if (proxy_type) {
@@ -1426,7 +1432,7 @@ server_child (server * serv)
 			g_strfreev (proxy_list);
 			g_free (url);
 		}
-#endif
+
 		if (prefs.hex_net_proxy_host[0] &&
 			   prefs.hex_net_proxy_type > 0 &&
 			   prefs.hex_net_proxy_use != 2) /* proxy is NOT dcc-only */
@@ -1553,7 +1559,7 @@ server_connect (server *serv, char *hostname, int port, int no_login)
 	if (!hostname[0])
 		return;
 
-	if (port < 0)
+	if (port < 1 || port > 65535)
 	{
 		/* use default port for this server type */
 		port = 6667;
@@ -1561,8 +1567,8 @@ server_connect (server *serv, char *hostname, int port, int no_login)
 		if (serv->use_ssl)
 			port = 6697;
 #endif
+		g_debug ("Attempted to connect to invalid port, assuming default port %d", port);
 	}
-	port &= 0xffff;	/* wrap around */
 
 	if (serv->connected || serv->connecting || serv->recondelay_tag)
 		server_disconnect (sess, TRUE, -1);
@@ -1764,6 +1770,7 @@ server_set_defaults (server *serv)
 	serv->chanmodes = g_strdup ("beI,k,l");
 	serv->nick_prefixes = g_strdup ("@%+");
 	serv->nick_modes = g_strdup ("ohv");
+	serv->modes_per_line = 3; /* https://datatracker.ietf.org/doc/html/rfc1459#section-4.2.3.1 */
 	serv->sasl_mech = MECH_PLAIN;
 
 	if (!serv->encoding)
@@ -1772,6 +1779,7 @@ server_set_defaults (server *serv)
 	serv->nickcount = 1;
 	serv->end_of_motd = FALSE;
 	serv->sent_capend = FALSE;
+	serv->use_listargs = FALSE;
 	serv->is_away = FALSE;
 	serv->supports_watch = FALSE;
 	serv->supports_monitor = FALSE;
diff --git a/src/common/servlist.c b/src/common/servlist.c
index 79a5694b..160cc9e0 100644
--- a/src/common/servlist.c
+++ b/src/common/servlist.c
@@ -54,10 +54,6 @@ static const struct defaultserver def[] =
 	/* Invalid hostname in cert */
 	{0,			"irc.2600.net"},
 
-	{"AccessIRC",	0},
-	/* Self signed */
-	{0,			"irc.accessirc.net"},
-
 	{"ACN", 0, 0, 0, LOGIN_SASL, 0, TRUE},
 	{0,			"global.acn.gr"},
 
@@ -67,15 +63,11 @@ static const struct defaultserver def[] =
 	{"Aitvaras",	0},
 #ifdef USE_OPENSSL
 	{0,			"irc.data.lt/+6668"},
-	{0,			"irc.omnitel.net/+6668"},
-	{0,			"irc.ktu.lt/+6668"},
-	{0,			"irc.kis.lt/+6668"},
+	{0,			"irc.omicron.lt/+6668"},
 	{0,			"irc.vub.lt/+6668"},
 #endif
 	{0,			"irc.data.lt"},
-	{0,			"irc.omnitel.net"},
-	{0,			"irc.ktu.lt"},
-	{0,			"irc.kis.lt"},
+	{0,			"irc.omicron.lt"},
 	{0,			"irc.vub.lt"},
 
 	{"Anthrochat", 0, 0, 0, 0, 0, TRUE},
@@ -90,10 +82,6 @@ static const struct defaultserver def[] =
 	{"AzzurraNet",	0},
 	{0,			"irc.azzurra.org"},
 
-	{"BetaChat", 0, 0, 0, LOGIN_SASL},
-	{0,			"irc.betachat.net"},
-	{"BuddyIM", 0, 0, 0, LOGIN_SASL, 0, TRUE},
-	{0,			"irc.buddy.im"},
 	{"Canternet", 0, 0, 0, LOGIN_SASL, 0, TRUE},
 	{0,			"irc.canternet.org"},
 
@@ -103,19 +91,16 @@ static const struct defaultserver def[] =
 	{"ChatJunkies",	0},
 	{0,			"irc.chatjunkies.org"},
 
-	{"ChatNet",	0},
-	{0,			"irc.chatnet.org"},
+	{"chatpat", 0, 0, "CP1251", LOGIN_CUSTOM, "MSG NS IDENTIFY %p"},
+	{0,			"irc.unibg.net"},
+	{0,			"irc.chatpat.bg"},
 
 	{"ChatSpike", 0, 0, 0, LOGIN_SASL},
 	{0,			"irc.chatspike.net"},
 
-	{"ChattingAway", 0},
-	{0,			"irc.chattingaway.com"},
-
-	{"Criten", 0},
-	/* Self signed */
-	{0,			"irc.criten.net"},
-
+	{"DaIRC", 0},
+	{0,			"irc.dairc.net"},
+	
 	{"DALnet", 0, 0, 0, LOGIN_NICKSERV},
 	/* Self signed */
 	{0,			"us.dal.net"},
@@ -132,19 +117,20 @@ static const struct defaultserver def[] =
 
 	{"Dark-Tou-Net",	0},
 	{0,			"irc.d-t-net.de"},
-
-	{"DeltaAnime", 0},
-	{0,			"irc.deltaanime.net"},
+	
+	{"DigitalIRC", 0, 0, 0, LOGIN_SASL, 0, TRUE},
+	{0,			"irc.digitalirc.org"},
+	
+#ifdef USE_OPENSSL
+	{"DosersNET", 0, 0, 0, LOGIN_SASL, 0, TRUE},
+	{0,			"irc.dosers.net/+6697"},
+#endif
 
 	{"EFnet",	0},
 	{0,			"irc.choopa.net"},
-	{0,			"irc.paraphysics.net"},
 	{0,			"efnet.port80.se"},
 	{0,			"irc.underworld.no"},
-	{0,			"irc.inet.tele.dk"},
-
-	{"ElectroCode", 0, 0, 0, LOGIN_SASL, 0, TRUE},
-	{0,			"irc.electrocode.net"},
+	{0,			"efnet.deic.eu"},
 
 	{"EnterTheGame",	0},
 	{0,			"irc.enterthegame.com"},
@@ -166,20 +152,8 @@ static const struct defaultserver def[] =
 	/* Self signed */
 	{0,			"irc.fdfnet.net"},
 
-	{"freenode", 0, 0, 0, LOGIN_SASL, 0, TRUE},
-	{0,				"chat.freenode.net"},
-	/* irc. points to chat. but many users and urls still reference it */
-	{0,				"irc.freenode.net"},
-
-	{"GalaxyNet",	0},
-	{0,			"irc.galaxynet.org"},
-
 	{"GameSurge", 0},
 	{0,			"irc.gamesurge.net"},
-	
-	{"GeeksIRC", 0, 0, 0, LOGIN_SASL},
-	/* Self signed */
-	{0,			"irc.geeksirc.net"},
 
 	{"GeekShed", 0, 0, 0, 0, 0, TRUE},
 	{0,			"irc.geekshed.net"},
@@ -207,16 +181,15 @@ static const struct defaultserver def[] =
 	{"Hashmark",	0},
 	{0,			"irc.hashmark.net"},
 
-	{"IdleMonkeys", 0},
-	{0,			"irc.idlemonkeys.net"},
+	{"ICQ-Chat", 0, 0, 0, LOGIN_SASL, 0, TRUE},
+	{0,			"irc.icq-chat.com"},
 
-	{"IndirectIRC", 0, 0, 0, LOGIN_SASL},
-	/* Self signed */
-	{0,			"irc.indirectirc.com"},
-	
 	{"Interlinked", 0, 0, 0, LOGIN_SASL, 0, TRUE},
 	{0,			"irc.interlinked.me"},
 
+	{"Irc-Nerds", 0, 0, 0, LOGIN_SASL, 0, TRUE},
+	{0,			"irc.irc-nerds.net"},
+	
 	{"IRC4Fun", 0, 0, 0, LOGIN_SASL, 0, TRUE},
 	{0,				"irc.irc4fun.net"},
 
@@ -226,19 +199,16 @@ static const struct defaultserver def[] =
 	{"IRCNet",		0},
 	{0,				"open.ircnet.net"},
 
-	{"Irctoo.net",	0},
+	{"IRCtoo",	0},
 	{0,			"irc.irctoo.net"},
 
-	{"iZ-smart.net", 0, 0, "CP1252"},
-	{0,			"irc.iz-smart.net"},
-
-	{"KBFail", 0},
+	{"Keyboard-Failure", 0},
 	/* SSL is self-signed */
 	{0,			"irc.kbfail.net"},
 
-	{"Krstarica", 0},
-	{0,			"irc.krstarica.com"},
-
+	{"Libera.Chat", 0, 0, 0, LOGIN_SASL, 0, TRUE},
+	{0,			"irc.libera.chat"},
+	
 #ifdef USE_OPENSSL
 	{"LibertaCasa", 0, 0, 0, LOGIN_SASL, 0, TRUE},
 	{0,			"irc.liberta.casa"},
@@ -248,9 +218,6 @@ static const struct defaultserver def[] =
 	/* Self signed */
 	{0,			"irc.librairc.net"},
 
-	{"Libera.Chat", 0, 0, 0, LOGIN_SASL, 0, TRUE},
-	{0,			"irc.libera.chat"},
-
 #ifdef USE_OPENSSL
 	{"LinkNet",	0},
 	{0,			"irc.link-net.org/+7000"},
@@ -262,10 +229,6 @@ static const struct defaultserver def[] =
 	{"MIXXnet",		0},
 	{0,			"irc.mixxnet.net"},
 
-	{"ObsidianIRC",  0},
-	/* Self signed */
-	{0,      "irc.obsidianirc.net"}, 
-
 	{"Oceanius", 0, 0, 0, LOGIN_SASL},
 	/* Self signed */
 	{0,			"irc.oceanius.com"},
@@ -276,16 +239,16 @@ static const struct defaultserver def[] =
 	{"OtherNet",	0},
 	{0,			"irc.othernet.org"},
 
-	{"OzNet",	0},
+	{"OzOrg",	0},
 	{0,			"irc.oz.org"},
 
-	{"PIRC.PL",	0, 0, 0, 0, 0, TRUE},
+	{"PIK", 0},
+	{0,			"irc.krstarica.com"},
+
+	{"pirc.pl",	0, 0, 0, 0, 0, TRUE},
 	{0,			"irc.pirc.pl"},
-	
-	{"PonyChat", 0, 0, 0, LOGIN_SASL, 0, TRUE},
-	{0,			"irc.ponychat.net"},
 
-	{"PTNet.org",	0},
+	{"PTNet",	0},
 	{0,			"irc.ptnet.org"},
 	{0,			"uevora.ptnet.org"},
 	{0,			"claranet.ptnet.org"},
@@ -306,12 +269,6 @@ static const struct defaultserver def[] =
 	{0,			"irc.ru"},
 	{0,			"irc.lucky.net"},
 
-	{"SceneNet",	0},
-	{0,			"irc.scene.org"},
-
-	{"SeilEn.de", 0, 0, "CP1252"},
-	{0,			"irc.seilen.de"},
-
 	{"Serenity-IRC",	0},
 	{0,			"irc.serenity-irc.net"},
 
@@ -328,10 +285,6 @@ static const struct defaultserver def[] =
 	{"Sohbet.Net", 0, 0, "CP1254"},
 	{0,			"irc.sohbet.net"},
 
-	{"SolidIRC", 0},
-	/* Self signed */
-	{0,			"irc.solidirc.com"},
-
 	{"SorceryNet", 0, 0, 0, LOGIN_SASL},
 	/* Self signed */
 	{0,			"irc.sorcery.net"},
@@ -339,9 +292,6 @@ static const struct defaultserver def[] =
 	{"SpotChat", 0, 0, 0, LOGIN_SASL, 0, TRUE},
 	{0,			"irc.spotchat.org"},
 
-	{"StarChat", 0},
-	{0,			"irc.starchat.net"},
-
 	{"Station51", 0},
 	/* Self signed */
 	{0,			"irc.station51.net"},
@@ -363,6 +313,12 @@ static const struct defaultserver def[] =
 	{"tilde.chat", 0, 0, 0, LOGIN_SASL, 0, TRUE},
 	{0,			"irc.tilde.chat"},
 
+	{"TURLINet", 0, 0, 0, 0, 0, TRUE},
+	/* all servers use UTF-8 and valid certs */
+	{0,			"irc.servx.org"},
+	{0,			"i.valware.uk"},
+	
+	
 #ifdef USE_OPENSSL
 	{"TripSit", 0, 0, 0, LOGIN_SASL, 0, TRUE},
 	{0,			"irc.tripsit.me"},
@@ -370,27 +326,12 @@ static const struct defaultserver def[] =
 	{0,			"coconut.tripsit.me"},
 	{0,			"innsbruck.tripsit.me"},
 #endif	
-	
-	{"TURLINet", 0, 0, 0, 0, 0, TRUE},
-	/* Other servers use CP1251 and invalid certs */
-	{0,			"irc.servx.ru"},
 
 	{"UnderNet", 0, 0, 0, LOGIN_CUSTOM, "MSG x@channels.undernet.org login %u %p"},
 	{0,			"us.undernet.org"},
 
-	{"UniBG", 0, 0, "CP1251", LOGIN_CUSTOM, "MSG NS IDENTIFY %p"},
-	{0,			"irc.lirex.com"},
-	{0,			"irc.naturella.com"},
-	{0,			"irc.techno-link.com"},
-
-	{"Worldnet",		0},
-	{0,			"irc.worldnet.net"},
-
 	{"Xertion", 0, 0, 0, LOGIN_SASL, 0, TRUE},
 	{0,			"irc.xertion.org"},
-	
-	{"DeltaPool", 0, 0, 0, LOGIN_SASL, 0, TRUE},
-	{0,			"irc.deltapool.net"},
 
 	{0,0}
 };
@@ -947,6 +888,9 @@ servlist_net_add (char *name, char *comment, int prepend)
 	net = g_new0 (ircnet, 1);
 	net->name = g_strdup (name);
 	net->flags = FLAG_CYCLE | FLAG_USE_GLOBAL | FLAG_USE_PROXY;
+#ifdef USE_OPENSSL
+	net->flags |= FLAG_USE_SSL;
+#endif
 
 	if (prepend)
 		network_list = g_slist_prepend (network_list, net);
diff --git a/src/common/ssl.c b/src/common/ssl.c
index 0eb78bd7..e7f7e0a8 100644
--- a/src/common/ssl.c
+++ b/src/common/ssl.c
@@ -321,23 +321,22 @@ _SSL_socket (SSL_CTX *ctx, int sd)
 
 
 char *
-_SSL_set_verify (SSL_CTX *ctx, void *verify_callback, char *cacert)
+_SSL_set_verify (SSL_CTX *ctx, void *verify_callback)
 {
-	if (!SSL_CTX_set_default_verify_paths (ctx))
+#ifdef DEFAULT_CERT_FILE
+	if (!SSL_CTX_load_verify_locations (ctx, DEFAULT_CERT_FILE, NULL))
 	{
-		__SSL_fill_err_buf ("SSL_CTX_set_default_verify_paths");
+		__SSL_fill_err_buf ("SSL_CTX_load_verify_locations");
 		return (err_buf);
 	}
-/*
-	if (cacert)
+#else
+	if (!SSL_CTX_set_default_verify_paths (ctx))
 	{
-		if (!SSL_CTX_load_verify_locations (ctx, cacert, NULL))
-		{
-			__SSL_fill_err_buf ("SSL_CTX_load_verify_locations");
-			return (err_buf);
-		}
+		__SSL_fill_err_buf ("SSL_CTX_set_default_verify_paths");
+		return (err_buf);
 	}
-*/
+#endif
+
 	SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER, verify_callback);
 
 	return (NULL);
diff --git a/src/common/ssl.h b/src/common/ssl.h
index e722f831..bea2f440 100644
--- a/src/common/ssl.h
+++ b/src/common/ssl.h
@@ -45,7 +45,7 @@ SSL_CTX *_SSL_context_init (void (*info_cb_func));
 #define _SSL_context_free(a)	SSL_CTX_free(a);
 
 SSL *_SSL_socket (SSL_CTX *ctx, int sd);
-char *_SSL_set_verify (SSL_CTX *ctx, void *(verify_callback), char *cacert);
+char *_SSL_set_verify (SSL_CTX *ctx, void *(verify_callback));
 /*
     int SSL_connect(SSL *);
     int SSL_accept(SSL *);
diff --git a/src/common/sysinfo/win32/backend.c b/src/common/sysinfo/win32/backend.c
index 1d88b139..67a0fd2b 100644
--- a/src/common/sysinfo/win32/backend.c
+++ b/src/common/sysinfo/win32/backend.c
@@ -84,7 +84,8 @@ sysinfo_get_cpu_arch (void)
 
 	GetNativeSystemInfo (&si);
 
-	if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
+	if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
+		si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64)
 	{
 		return cpu_arch = 64;
 	}
@@ -106,7 +107,8 @@ sysinfo_get_build_arch (void)
 
 	GetSystemInfo (&si);
 
-	if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
+	if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
+		si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64)
 	{
 		return build_arch = 64;
 	}
diff --git a/src/common/text.c b/src/common/text.c
index b0a90e03..a77700fa 100644
--- a/src/common/text.c
+++ b/src/common/text.c
@@ -1512,6 +1512,17 @@ static char * const pevt_discon_help[] = {
 	N_("Error"),
 };
 
+static char * const pevt_stdrpl_help[] = {
+	N_("Error Code"),
+	N_("Error Message"),
+};
+
+static char * const pevt_stdrplcmd_help[] = {
+	N_("Command"),
+	N_("Error Code"),
+	N_("Error Message"),
+};
+
 #include "textevents.h"
 
 static void
diff --git a/src/common/textevents.in b/src/common/textevents.in
index 14bd4b06..19b0d497 100644
--- a/src/common/textevents.in
+++ b/src/common/textevents.in
@@ -436,6 +436,18 @@ pevt_discon_help
 %C20*%O$tDisconnected (%C20$1%O)
 1
 
+Fail
+XP_TE_FAIL
+pevt_stdrpl_help
+%C20*%O$t$2%O
+2
+
+Fail Command
+XP_TE_FAILCMD
+pevt_stdrplcmd_help
+%C20*%O$t$1: $3%O
+3
+
 Found IP
 XP_TE_FOUNDIP
 pevt_foundip_help
@@ -574,6 +586,18 @@ pevt_generic_none_help
 %C23*%O$tNo process is currently running
 0
 
+Note
+XP_TE_NOTE
+pevt_stdrpl_help
+%C22*%O$t$2%O
+2
+
+Note Command
+XP_TE_NOTECMD
+pevt_stdrplcmd_help
+%C22*%O$t$1: $3%O
+3
+
 Notice
 XP_TE_NOTICE
 pevt_notice_help
@@ -802,6 +826,18 @@ pevt_usersonchan_help
 %C22*%O$tUsers on %C22$1%C: %C24$2%O
 2
 
+Warn
+XP_TE_WARN
+pevt_stdrpl_help
+%C23*%O$t$2%O
+2
+
+Warn Command
+XP_TE_WARNCMD
+pevt_stdrplcmd_help
+%C23*%O$t$1: $3%O
+3
+
 WhoIs Authenticated
 XP_TE_WHOIS_AUTH
 pevt_whoisauth_help
diff --git a/src/common/util.c b/src/common/util.c
index 5b5fb23f..fa0783d4 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -329,6 +329,7 @@ strip_color2 (const char *src, int len, char *dst, int flags)
 			case '\026':			  /*ATTR_REVERSE: */
 			case '\002':			  /*ATTR_BOLD: */
 			case '\037':			  /*ATTR_UNDERLINE: */
+			case '\036':			  /*ATTR_STRIKETHROUGH: */
 			case '\035':			  /*ATTR_ITALICS: */
 				if (!(flags & STRIP_ATTRIB)) goto pass_char;
 				break;
diff --git a/src/fe-gtk/fe-gtk.c b/src/fe-gtk/fe-gtk.c
index ee3e847c..7eca0710 100644
--- a/src/fe-gtk/fe-gtk.c
+++ b/src/fe-gtk/fe-gtk.c
@@ -664,13 +664,13 @@ fe_print_text (struct session *sess, char *text, time_t stamp,
 		return;
 
 	if (sess == current_tab)
-		fe_set_tab_color (sess, 0);
+		fe_set_tab_color (sess, FE_COLOR_NONE);
 	else if (sess->tab_state & TAB_STATE_NEW_HILIGHT)
-		fe_set_tab_color (sess, 3);
+		fe_set_tab_color (sess, FE_COLOR_NEW_HILIGHT);
 	else if (sess->tab_state & TAB_STATE_NEW_MSG)
-		fe_set_tab_color (sess, 2);
+		fe_set_tab_color (sess, FE_COLOR_NEW_MSG);
 	else
-		fe_set_tab_color (sess, 1);
+		fe_set_tab_color (sess, FE_COLOR_NEW_DATA);
 }
 
 void
@@ -1054,6 +1054,46 @@ osx_show_uri (const char *url)
 
 #endif
 
+static inline char *
+escape_uri (const char *uri)
+{
+	return g_uri_escape_string(uri, G_URI_RESERVED_CHARS_GENERIC_DELIMITERS G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, FALSE);
+}
+
+static inline gboolean
+uri_contains_forbidden_characters (const char *uri)
+{
+	while (*uri)
+	{
+		/* This is not an exhaustive list, the full URI has segments that allow characters like "[]:" for example. */
+		if (strchr ("`<> ${}\"+", *uri) != NULL || (*uri & 0x80) /* non-ascii */)
+			return TRUE;
+		uri++;
+	}
+
+	return FALSE;
+}
+
+static char *
+maybe_escape_uri (const char *uri)
+{
+	/* The only way to know if a string has already been escaped or not
+	 * is by fulling parsing each segement but we can try some more simple heuristics. */
+
+	/* If we find characters that should clearly be escaped. */
+	if (uri_contains_forbidden_characters (uri))
+		return escape_uri (uri);
+
+	/* If it fails to be unescaped then it was not escaped. */
+	char *unescaped = g_uri_unescape_string (uri, NULL);
+	if (!unescaped)
+		return escape_uri (uri);
+	g_free (unescaped);
+
+	/* At this point it is probably safe to pass through as-is. */
+	return g_strdup (uri);
+}
+
 static void
 fe_open_url_inner (const char *url)
 {
@@ -1071,7 +1111,10 @@ fe_open_url_inner (const char *url)
 #elif defined(__APPLE__)
     osx_show_uri (url);
 #else
-	gtk_show_uri (NULL, url, GDK_CURRENT_TIME, NULL);
+	char *escaped_url = maybe_escape_uri (url);
+	g_debug ("Opening URL \"%s\" (%s)", escaped_url, url);
+	gtk_show_uri (NULL, escaped_url, GDK_CURRENT_TIME, NULL);
+	g_free (escaped_url);
 #endif
 }
 
diff --git a/src/fe-gtk/maingui.c b/src/fe-gtk/maingui.c
index 4e5baaa0..61f59856 100644
--- a/src/fe-gtk/maingui.c
+++ b/src/fe-gtk/maingui.c
@@ -175,20 +175,26 @@ fe_flash_window (session *sess)
 /* set a tab plain, red, light-red, or blue */
 
 void
-fe_set_tab_color (struct session *sess, int col)
+fe_set_tab_color (struct session *sess, tabcolor col)
 {
 	struct session *server_sess = sess->server->server_session;
+	int col_noflags = (col & ~FE_COLOR_ALLFLAGS);
+	int col_shouldoverride = !(col & FE_COLOR_FLAG_NOOVERRIDE);
+
 	if (sess->res->tab && sess->gui->is_tab && (col == 0 || sess != current_tab))
 	{
-		switch (col)
+		switch (col_noflags)
 		{
 		case 0:	/* no particular color (theme default) */
 			sess->tab_state = TAB_STATE_NONE;
 			chan_set_color (sess->res->tab, plain_list);
 			break;
 		case 1:	/* new data has been displayed (dark red) */
-			sess->tab_state = TAB_STATE_NEW_DATA;
-			chan_set_color (sess->res->tab, newdata_list);
+			if (col_shouldoverride || !((sess->tab_state & TAB_STATE_NEW_MSG)
+										|| (sess->tab_state & TAB_STATE_NEW_HILIGHT))) {
+				sess->tab_state = TAB_STATE_NEW_DATA;
+				chan_set_color (sess->res->tab, newdata_list);
+			}
 
 			if (chan_is_collapsed (sess->res->tab)
 				&& !((server_sess->tab_state & TAB_STATE_NEW_MSG)
@@ -201,8 +207,10 @@ fe_set_tab_color (struct session *sess, int col)
 
 			break;
 		case 2:	/* new message arrived in channel (light red) */
-			sess->tab_state = TAB_STATE_NEW_MSG;
-			chan_set_color (sess->res->tab, newmsg_list);
+			if (col_shouldoverride || !(sess->tab_state & TAB_STATE_NEW_HILIGHT)) {
+				sess->tab_state = TAB_STATE_NEW_MSG;
+				chan_set_color (sess->res->tab, newmsg_list);
+			}
 
 			if (chan_is_collapsed (sess->res->tab)
 				&& !(server_sess->tab_state & TAB_STATE_NEW_HILIGHT)
@@ -540,7 +548,7 @@ mg_focus (session *sess)
 	/* when called via mg_changui_new, is_tab might be true, but
 		sess->res->tab is still NULL. */
 	if (sess->res->tab)
-		fe_set_tab_color (sess, 0);
+		fe_set_tab_color (sess, FE_COLOR_NONE);
 }
 
 static int
@@ -1394,6 +1402,8 @@ mg_color_insert (GtkWidget *item, gpointer userdata)
 			text = "\037"; break;
 		case 102:
 			text = "\035"; break;
+		case 103:
+			text = "\036"; break;
 		default:
 			text = "\017"; break;
 		}
@@ -1447,7 +1457,8 @@ mg_create_color_menu (GtkWidget *menu, session *sess)
 	mg_markup_item (submenu, _("<b>Bold</b>"), 100);
 	mg_markup_item (submenu, _("<u>Underline</u>"), 101);
 	mg_markup_item (submenu, _("<i>Italic</i>"), 102);
-	mg_markup_item (submenu, _("Normal"), 103);
+	mg_markup_item (submenu, _("<s>Strikethrough</s>"), 103);
+	mg_markup_item (submenu, _("Normal"), 999);
 
 	subsubmenu = mg_submenu (submenu, _("Colors 0-7"));
 
diff --git a/src/fe-gtk/meson.build b/src/fe-gtk/meson.build
index 3dfc7427..d07514db 100644
--- a/src/fe-gtk/meson.build
+++ b/src/fe-gtk/meson.build
@@ -43,11 +43,7 @@ hexchat_gtk_cflags = []
 
 hexchat_gtk_ldflags = []
 
-if get_option('with-libnotify')
-  hexchat_gtk_sources += 'notifications/notification-libnotify.c'
-  hexchat_gtk_deps += dependency('libnotify')
-elif false # TODO HAVE_GTK_MAC
-elif host_machine.system() == 'windows'
+if host_machine.system() == 'windows'
   hexchat_gtk_sources += 'notifications/notification-windows.c'
 
   # TODO: mingw doesn't have these headers or libs
@@ -57,7 +53,7 @@ elif host_machine.system() == 'windows'
   #)
 
 else
-  hexchat_gtk_sources += 'notifications/notification-dummy.c'
+  hexchat_gtk_sources += 'notifications/notification-freedesktop.c'
 endif
 
 iso_codes = dependency('iso-codes', required: false)
@@ -69,7 +65,7 @@ if iso_codes.found()
                         join_paths(iso_codes_prefix, 'share/locale'))
 endif
 
-if get_option('with-plugin')
+if get_option('plugin')
   hexchat_gtk_sources += 'plugingui.c'
 endif
 
diff --git a/src/fe-gtk/notifications/notification-freedesktop.c b/src/fe-gtk/notifications/notification-freedesktop.c
new file mode 100644
index 00000000..a23284e5
--- /dev/null
+++ b/src/fe-gtk/notifications/notification-freedesktop.c
@@ -0,0 +1,148 @@
+/* HexChat
+ * Copyright (C) 2021 Patrick Griffis.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <gio/gio.h>
+
+static GDBusProxy *fdo_notifications;
+static gboolean strip_markup;
+
+static void
+on_notify_ready (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
+{
+    GError *error = NULL;
+    guint32 notification_id;
+    GVariant *response = g_dbus_proxy_call_finish (proxy, res, &error);
+    if (error)
+    {
+        g_info ("Failed to send notification: %s", error->message);
+        g_error_free (error);
+        return;
+    }
+
+    g_variant_get (response, "(u)", &notification_id);
+    g_info ("Notification sent. ID=%u", notification_id);
+
+    g_variant_unref (response);
+}
+
+void
+notification_backend_show (const char *title, const char *text)
+{
+    GVariantBuilder params;
+
+    g_assert (fdo_notifications);
+
+    if (strip_markup)
+        text = g_markup_escape_text (text, -1);
+
+    g_variant_builder_init (&params, G_VARIANT_TYPE ("(susssasa{sv}i)"));
+    g_variant_builder_add (&params, "s", "hexchat"); /* App name */
+    g_variant_builder_add (&params, "u", 0); /* ID, 0 means don't replace */
+    g_variant_builder_add (&params, "s", "io.github.Hexchat"); /* App icon */
+    g_variant_builder_add (&params, "s", title);
+    g_variant_builder_add (&params, "s", text);
+    g_variant_builder_add (&params, "as", NULL); /* Actions */
+
+    /* Hints */
+    g_variant_builder_open (&params, G_VARIANT_TYPE ("a{sv}"));
+    g_variant_builder_open (&params, G_VARIANT_TYPE ("{sv}"));
+    g_variant_builder_add (&params, "s", "desktop-entry");
+    g_variant_builder_add (&params, "v", g_variant_new_string ("io.github.Hexchat"));
+    g_variant_builder_close (&params);
+    g_variant_builder_close (&params);
+
+    g_variant_builder_add (&params, "i", -1); /* Expiration */
+
+    g_dbus_proxy_call (fdo_notifications,
+                       "Notify",
+                       g_variant_builder_end (&params),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       1000,
+                       NULL,
+                       (GAsyncReadyCallback)on_notify_ready,
+                       NULL);
+
+    if (strip_markup)
+        g_free ((char*)text);
+}
+
+int
+notification_backend_init (const char **error)
+{
+    GError *err = NULL;
+    GVariant *response;
+    char **capabilities;
+    guint i;
+
+    fdo_notifications = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+                                                       G_DBUS_PROXY_FLAGS_NONE,
+                                                       NULL,
+                                                       "org.freedesktop.Notifications",
+                                                       "/org/freedesktop/Notifications",
+                                                       "org.freedesktop.Notifications",
+                                                       NULL,
+                                                       &err);
+
+    if (err)
+        goto return_error;
+
+    response = g_dbus_proxy_call_sync (fdo_notifications,
+                                       "GetCapabilities",
+                                       NULL,
+                                       G_DBUS_CALL_FLAGS_NONE,
+                                       30,
+                                       NULL,
+                                       &err);
+
+    if (err)
+    {
+        g_clear_object (&fdo_notifications);
+        goto return_error;
+    }
+
+    g_variant_get (response, "(^a&s)", &capabilities);
+    for (i = 0; capabilities[i]; i++)
+    {
+        if (strcmp (capabilities[i], "body-markup") == 0)
+            strip_markup = TRUE;
+    }
+
+    g_free (capabilities);
+    g_variant_unref (response);
+    return 1;
+
+return_error:
+    *error = g_strdup (err->message);
+    g_error_free (err);
+    return 0;
+}
+
+void
+notification_backend_deinit (void)
+{
+    g_clear_object (&fdo_notifications);
+}
+
+int
+notification_backend_supported (void)
+{
+    return fdo_notifications != NULL;
+}
diff --git a/src/fe-gtk/notifications/notification-libnotify.c b/src/fe-gtk/notifications/notification-libnotify.c
deleted file mode 100644
index ee417396..00000000
--- a/src/fe-gtk/notifications/notification-libnotify.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/* HexChat
- * Copyright (C) 2015 Patrick Griffis.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "config.h"
-#include <glib.h>
-#include <libnotify/notify.h>
-
-#ifndef NOTIFY_CHECK_VERSION
-#define NOTIFY_CHECK_VERSION(x,y,z) 0
-#endif
-
-static gboolean strip_markup = FALSE;
-
-void
-notification_backend_show (const char *title, const char *text)
-{
-	NotifyNotification *notification;
-
-	if (strip_markup)
-		text = g_markup_escape_text (text, -1);
-
-#if NOTIFY_CHECK_VERSION(0,7,0)
-	notification = notify_notification_new (title, text, "hexchat");
-#else
-	notification = notify_notification_new (title, text, "hexchat", NULL);
-#endif
-#if NOTIFY_CHECK_VERSION(0,6,0)
-	notify_notification_set_hint (notification, "desktop-entry", g_variant_new_string ("io.github.Hexchat"));
-#else
-	notify_notification_set_hint_string (notification, "desktop-entry", "io.github.Hexchat");
-#endif
-
-	notify_notification_show (notification, NULL);
-
-	g_object_unref (notification);
-	if (strip_markup)
-		g_free ((char*)text);
-}
-
-int
-notification_backend_init (const char **error)
-{
-	GList* server_caps;
-
-	if (!notify_init (PACKAGE_NAME))
-		return 0;
-
-	server_caps = notify_get_server_caps ();
-	if (g_list_find_custom (server_caps, "body-markup", (GCompareFunc)g_strcmp0))
-		strip_markup = TRUE;
-	g_list_free_full (server_caps, g_free);
-
-	return 1;
-}
-
-void
-notification_backend_deinit (void)
-{
-	notify_uninit ();
-}
-
-int
-notification_backend_supported (void)
-{
-	return notify_is_initted ();
-}
diff --git a/src/fe-gtk/plugin-notification.c b/src/fe-gtk/plugin-notification.c
index 29478d7a..875b50f4 100644
--- a/src/fe-gtk/plugin-notification.c
+++ b/src/fe-gtk/plugin-notification.c
@@ -218,7 +218,7 @@ notification_plugin_init (hexchat_plugin *plugin_handle, char **plugin_name, cha
 	if (!notification_backend_init (&error))
 	{
 		if (error)
-			hexchat_printf(plugin_handle, "Failed loading notification plugin: %s\n", error);
+			g_debug("Failed loading notification plugin: %s\n", error);
 		return 0;
 	}
 
diff --git a/src/fe-gtk/servlistgui.c b/src/fe-gtk/servlistgui.c
index b22330ac..edcd4609 100644
--- a/src/fe-gtk/servlistgui.c
+++ b/src/fe-gtk/servlistgui.c
@@ -39,6 +39,12 @@
 #define SERVLIST_X_PADDING 4			/* horizontal paddig in the network editor */
 #define SERVLIST_Y_PADDING 0			/* vertical padding in the network editor */
 
+#ifdef USE_OPENSSL
+# define DEFAULT_SERVER "newserver/6697"
+#else
+# define DEFAULT_SERVER "newserver/6667"
+#endif
+
 /* servlistgui.c globals */
 static GtkWidget *serverlist_win = NULL;
 static GtkWidget *networks_tree;		/* network TreeView */
@@ -299,7 +305,7 @@ servlist_networks_populate_ (GtkWidget *treeview, GSList *netlist, gboolean favo
 	if (!netlist)
 	{
 		net = servlist_net_add (_("New Network"), "", FALSE);
-		servlist_server_add (net, "newserver/6667");
+		servlist_server_add (net, DEFAULT_SERVER);
 		netlist = network_list;
 	}
 	store = (GtkListStore *)gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
@@ -434,10 +440,10 @@ servlist_addserver (void)
 		return;
 
 	store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (edit_trees[SERVER_TREE])));
-	servlist_server_add (selected_net, "newserver/6667");
+	servlist_server_add (selected_net, DEFAULT_SERVER);
 
 	gtk_list_store_append (store, &iter);
-	gtk_list_store_set (store, &iter, 0, "newserver/6667", 1, TRUE, -1);
+	gtk_list_store_set (store, &iter, 0, DEFAULT_SERVER, 1, TRUE, -1);
 
 	/* select this server */
 	servlist_select_and_show (GTK_TREE_VIEW (edit_trees[SERVER_TREE]), &iter, store);
@@ -498,7 +504,7 @@ servlist_addnet_cb (GtkWidget *item, GtkTreeView *treeview)
 
 	net = servlist_net_add (_("New Network"), "", TRUE);
 	net->encoding = g_strdup (IRC_DEFAULT_CHARSET);
-	servlist_server_add (net, "newserver/6667");
+	servlist_server_add (net, DEFAULT_SERVER);
 
 	store = (GtkListStore *)gtk_tree_view_get_model (treeview);
 	gtk_list_store_prepend (store, &iter);
diff --git a/src/fe-gtk/setup.c b/src/fe-gtk/setup.c
index 3d003eef..a7e3a15c 100644
--- a/src/fe-gtk/setup.c
+++ b/src/fe-gtk/setup.c
@@ -614,9 +614,7 @@ static const char *const proxytypes[] =
 	N_("SOCKS4"),
 	N_("SOCKS5"),
 	N_("HTTP"),
-#ifdef USE_LIBPROXY
 	N_("Auto"),
-#endif
 	NULL
 };
 
diff --git a/src/fe-gtk/sexy-spell-entry.c b/src/fe-gtk/sexy-spell-entry.c
index dce19b82..04ff0f8a 100644
--- a/src/fe-gtk/sexy-spell-entry.c
+++ b/src/fe-gtk/sexy-spell-entry.c
@@ -390,6 +390,17 @@ insert_italic (SexySpellEntry *entry, guint start, gboolean toggle)
 }
 
 static void
+insert_strikethrough (SexySpellEntry *entry, guint start, gboolean toggle)
+{
+	PangoAttribute *sattr;
+
+	sattr  = pango_attr_strikethrough_new (!toggle);
+	sattr->start_index = start;
+	sattr->end_index = PANGO_ATTR_INDEX_TO_TEXT_END;
+	pango_attr_list_change (entry->priv->attr_list, sattr);
+}
+
+static void
 insert_color (SexySpellEntry *entry, guint start, int fgcolor, int bgcolor)
 {
 	PangoAttribute *fgattr;
@@ -429,6 +440,7 @@ insert_reset (SexySpellEntry *entry, guint start)
 	insert_bold (entry, start, TRUE);
 	insert_underline (entry, start, TRUE);
 	insert_italic (entry, start, TRUE);
+	insert_strikethrough (entry, start, TRUE);
 	insert_color (entry, start, -1, -1);
 }
 
@@ -918,6 +930,7 @@ check_attributes (SexySpellEntry *entry, const char *text, int len)
 	gboolean bold = FALSE;
 	gboolean italic = FALSE;
 	gboolean underline = FALSE;
+	gboolean strikethrough = FALSE;
 	int parsing_color = 0;
 	char fg_color[3];
 	char bg_color[3];
@@ -942,6 +955,12 @@ check_attributes (SexySpellEntry *entry, const char *text, int len)
 			italic = !italic;
 			goto check_color;
 
+		case ATTR_STRIKETHROUGH:
+			insert_hiddenchar (entry, i, i + 1);
+			insert_strikethrough (entry, i, strikethrough);
+			strikethrough = !strikethrough;
+			goto check_color;
+
 		case ATTR_UNDERLINE:
 			insert_hiddenchar (entry, i, i + 1);
 			insert_underline (entry, i, underline);
@@ -954,6 +973,7 @@ check_attributes (SexySpellEntry *entry, const char *text, int len)
 			bold = FALSE;
 			italic = FALSE;
 			underline = FALSE;
+			strikethrough = FALSE;
 			goto check_color;
 
 		case ATTR_HIDDEN:
diff --git a/src/fe-gtk/xtext.c b/src/fe-gtk/xtext.c
index 418bb4da..6a0fccba 100644
--- a/src/fe-gtk/xtext.c
+++ b/src/fe-gtk/xtext.c
@@ -433,6 +433,7 @@ gtk_xtext_init (GtkXText * xtext)
 	xtext->nc = 0;
 	xtext->pixel_offset = 0;
 	xtext->underline = FALSE;
+	xtext->strikethrough = FALSE;
 	xtext->hidden = FALSE;
 	xtext->font = NULL;
 	xtext->layout = NULL;
@@ -2451,6 +2452,7 @@ gtk_xtext_strip_color (unsigned char *text, int len, unsigned char *outbuf,
 			case ATTR_REVERSE:
 			case ATTR_BOLD:
 			case ATTR_UNDERLINE:
+			case ATTR_STRIKETHROUGH:
 			case ATTR_ITALICS:
 				xtext_do_chunk (&c);
 				if (*text == ATTR_RESET)
@@ -2627,6 +2629,13 @@ gtk_xtext_render_flush (GtkXText * xtext, int x, int y, unsigned char *str,
 		g_object_unref (pix);
 	}
 
+	if (xtext->strikethrough)
+	{
+		/* pango_attr_strikethrough_new does not render in the custom widget so we need to reinvent the wheel */
+		y = dest_y + (xtext->fontsize / 2);
+		gdk_draw_line (xtext->draw_buf, gc, dest_x, y, dest_x + str_width - 1, y);
+	}
+
 	if (xtext->underline)
 	{
 dounder:
@@ -2651,6 +2660,7 @@ gtk_xtext_reset (GtkXText * xtext, int mark, int attribs)
 	if (attribs)
 	{
 		xtext->underline = FALSE;
+		xtext->strikethrough = FALSE;
 		xtext->hidden = FALSE;
 	}
 	if (!mark)
@@ -2961,6 +2971,12 @@ gtk_xtext_render_str (GtkXText * xtext, int y, textentry * ent,
 				pstr += j + 1;
 				j = 0;
 				break;
+			case ATTR_STRIKETHROUGH:
+				RENDER_FLUSH;
+				xtext->strikethrough = !xtext->strikethrough;
+				pstr += j + 1;
+				j = 0;
+				break;
 			case ATTR_ITALICS:
 				RENDER_FLUSH;
 				*emphasis ^= EMPH_ITAL;
@@ -3191,6 +3207,7 @@ find_next_wrap (GtkXText * xtext, textentry * ent, unsigned char *str,
 			case ATTR_REVERSE:
 			case ATTR_BOLD:
 			case ATTR_UNDERLINE:
+			case ATTR_STRIKETHROUGH:
 			case ATTR_ITALICS:
 				if (*str == ATTR_RESET)
 					emphasis = 0;
diff --git a/src/fe-gtk/xtext.h b/src/fe-gtk/xtext.h
index 12d6f563..18d769fb 100644
--- a/src/fe-gtk/xtext.h
+++ b/src/fe-gtk/xtext.h
@@ -29,16 +29,17 @@
 #define GTK_IS_XTEXT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_XTEXT))
 #define GTK_XTEXT_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_XTEXT, GtkXTextClass))
 
-#define ATTR_BOLD			'\002'
-#define ATTR_COLOR		'\003'
-#define ATTR_BLINK		'\006'
-#define ATTR_BEEP			'\007'
-#define ATTR_HIDDEN		'\010'
-#define ATTR_ITALICS2	'\011'
-#define ATTR_RESET		'\017'
-#define ATTR_REVERSE		'\026'
-#define ATTR_ITALICS		'\035'
-#define ATTR_UNDERLINE	'\037'
+#define ATTR_BOLD				'\002'
+#define ATTR_COLOR			'\003'
+#define ATTR_BLINK			'\006'
+#define ATTR_BEEP				'\007'
+#define ATTR_HIDDEN			'\010'
+#define ATTR_ITALICS2		'\011'
+#define ATTR_RESET			'\017'
+#define ATTR_REVERSE			'\026'
+#define ATTR_ITALICS			'\035'
+#define ATTR_STRIKETHROUGH	'\036'
+#define ATTR_UNDERLINE		'\037'
 
 /* these match palette.h */
 #define XTEXT_MIRC_COLS 32
@@ -207,6 +208,7 @@ struct _GtkXText
 
 	/* current text states */
 	unsigned int underline:1;
+	unsigned int strikethrough:1;
 	unsigned int hidden:1;
 
 	/* text parsing states */
diff --git a/src/fe-text/fe-text.c b/src/fe-text/fe-text.c
index 1d411ddf..3673a81f 100644
--- a/src/fe-text/fe-text.c
+++ b/src/fe-text/fe-text.c
@@ -623,7 +623,7 @@ fe_cleanup (void)
 {
 }
 void
-fe_set_tab_color (struct session *sess, int col)
+fe_set_tab_color (struct session *sess, tabcolor col)
 {
 }
 void
diff --git a/src/meson.build b/src/meson.build
index ff2c8871..23453ec1 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -1,13 +1,13 @@
 subdir('common')
 
-if get_option('with-gtk')
+if get_option('gtk-frontend')
   subdir('fe-gtk')
 endif
 
-if get_option('with-text')
+if get_option('text-frontend')
   subdir('fe-text')
 endif
 
-if get_option('with-theme-manager')
+if get_option('theme-manager')
   subdir('htm')
 endif