summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/flatpak-build.yml17
-rw-r--r--.github/workflows/msys-build.yml40
-rw-r--r--.github/workflows/ubuntu-build.yml10
-rw-r--r--.github/workflows/windows-build.yml14
-rw-r--r--.gitmodules3
-rw-r--r--data/icons/meson.build2
-rw-r--r--data/meson.build6
-rw-r--r--data/misc/io.github.Hexchat.appdata.xml.in29
-rw-r--r--data/misc/io.github.Hexchat.desktop.in.in2
-rw-r--r--data/misc/meson.build12
-rw-r--r--flatpak/Load-plugins-from-Flatpak-extensions.patch25
-rw-r--r--flatpak/io.github.Hexchat.json78
-rw-r--r--flatpak/python3-cffi.json19
m---------flatpak/shared-modules0
-rw-r--r--meson.build53
-rw-r--r--meson_options.txt37
-rw-r--r--plugins/checksum/meson.build1
-rw-r--r--plugins/exec/meson.build3
-rw-r--r--plugins/fishlim/fish.c58
-rw-r--r--plugins/fishlim/fish.h2
-rw-r--r--plugins/fishlim/fishlim.vcxproj4
-rw-r--r--plugins/fishlim/meson.build1
-rw-r--r--plugins/fishlim/plugin_hexchat.c6
-rw-r--r--plugins/fishlim/tests/meson.build11
-rw-r--r--plugins/fishlim/tests/mock-keystore.c (renamed from plugins/fishlim/tests/fake/keystore.c)16
-rw-r--r--plugins/fishlim/tests/old_version/fish.c155
-rw-r--r--plugins/fishlim/tests/old_version/fish.h37
-rw-r--r--plugins/fishlim/tests/old_version/meson.build4
-rw-r--r--plugins/fishlim/tests/tests.c178
-rw-r--r--plugins/fishlim/utils.c2
-rw-r--r--plugins/lua/lua.c8
-rw-r--r--plugins/perl/meson.build1
-rw-r--r--plugins/python/meson.build1
-rw-r--r--plugins/python/python.py2
-rw-r--r--plugins/sysinfo/meson.build1
-rw-r--r--plugins/upd/meson.build1
-rw-r--r--plugins/winamp/meson.build1
-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
-rw-r--r--win32/copy/copy.vcxproj4
-rw-r--r--win32/hexchat.props4
-rw-r--r--win32/installer/hexchat.iss.tt9
74 files changed, 1057 insertions, 758 deletions
diff --git a/.github/workflows/flatpak-build.yml b/.github/workflows/flatpak-build.yml
new file mode 100644
index 00000000..66cd890b
--- /dev/null
+++ b/.github/workflows/flatpak-build.yml
@@ -0,0 +1,17 @@
+name: Flatpak Build
+on: [push, pull_request]
+jobs:
+  flatpak_build:
+    runs-on: ubuntu-latest
+    container:
+      image: bilelmoussaoui/flatpak-github-actions:gnome-40
+      options: --privileged
+    steps:
+    - uses: actions/checkout@v2
+      with:
+        submodules: true
+
+    - uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@v3
+      with:
+        bundle: hexchat.flatpak
+        manifest-path: flatpak/io.github.Hexchat.json
diff --git a/.github/workflows/msys-build.yml b/.github/workflows/msys-build.yml
new file mode 100644
index 00000000..b7779da6
--- /dev/null
+++ b/.github/workflows/msys-build.yml
@@ -0,0 +1,40 @@
+name: MSYS2 Build
+on: [push, pull_request]
+
+jobs:
+  msys2_build:
+    runs-on: windows-latest
+    defaults:
+      run:
+        shell: msys2 {0}
+
+    steps:
+      - uses: actions/checkout@v2
+
+      - uses: msys2/setup-msys2@v2
+        with:
+          install: >-
+            mingw-w64-x86_64-gcc
+            mingw-w64-x86_64-pkg-config
+            mingw-w64-x86_64-python3-cffi
+            mingw-w64-x86_64-meson
+            mingw-w64-x86_64-gtk2
+            mingw-w64-x86_64-luajit
+            mingw-w64-x86_64-desktop-file-utils
+
+      - name: Configure
+        run: >-
+          meson build
+          -Dtext-frontend=true
+          -Ddbus=disabled
+          -Dwith-upd=false
+          -Dwith-perl=false
+
+      - name: Build
+        run: ninja -C build
+
+      - name: Test
+        run: ninja -C build test
+
+      - name: Install
+        run: ninja -C build install
diff --git a/.github/workflows/ubuntu-build.yml b/.github/workflows/ubuntu-build.yml
index f2d3ac8e..0e8deb34 100644
--- a/.github/workflows/ubuntu-build.yml
+++ b/.github/workflows/ubuntu-build.yml
@@ -1,21 +1,19 @@
 name: Ubuntu Build
 on: [push, pull_request]
 jobs:
-  build:
-    runs-on: ubuntu-18.04
+  ubuntu_build:
+    runs-on: ubuntu-20.04
 
     steps:
       - uses: actions/checkout@v2
-        with:
-          fetch-depth: 1
 
       - name: Install Dependencies
         run: |
           sudo apt-get update
-          sudo apt-get install -y meson libcanberra-dev libdbus-glib-1-dev libglib2.0-dev libgtk2.0-dev libluajit-5.1-dev libnotify-dev libpci-dev libperl-dev libproxy-dev libssl-dev python3-dev python3-cffi mono-devel desktop-file-utils
+          sudo apt-get install -y meson libcanberra-dev libdbus-glib-1-dev libglib2.0-dev libgtk2.0-dev libluajit-5.1-dev libpci-dev libperl-dev libssl-dev python3-dev python3-cffi mono-devel desktop-file-utils
 
       - name: Configure
-        run: meson build -Dwith-text=true -Dwith-theme-manager=true
+        run: meson build -Dtext=true -Dtheme-manager=true -Dauto_features=enabled
 
       - name: Build
         run: ninja -C build
diff --git a/.github/workflows/windows-build.yml b/.github/workflows/windows-build.yml
index f8a965f9..f1eddbbd 100644
--- a/.github/workflows/windows-build.yml
+++ b/.github/workflows/windows-build.yml
@@ -2,7 +2,7 @@ name: Windows Build
 on: [push, pull_request]
 
 jobs:
-  build:
+  windows_build:
     runs-on: windows-2019
     strategy:
       matrix:
@@ -17,8 +17,6 @@ jobs:
 
     steps:
       - uses: actions/checkout@v2
-        with:
-          fetch-depth: 1
 
       - name: Install Dependencies
         run: |
@@ -30,7 +28,7 @@ jobs:
           Invoke-WebRequest https://dl.hexchat.net/misc/idpsetup-1.5.1.exe -OutFile deps\idpsetup.exe
           & deps\idpsetup.exe /VERYSILENT
 
-          Invoke-WebRequest https://dl.hexchat.net/gtk/gtk-${{ matrix.platform }}-2018-08-29.7z -OutFile deps\gtk-${{ matrix.arch }}.7z
+          Invoke-WebRequest https://dl.hexchat.net/gtk/gtk-${{ matrix.platform }}-2018-08-29-openssl1.1.7z -OutFile deps\gtk-${{ matrix.arch }}.7z
           & 7z.exe x deps\gtk-${{ matrix.arch }}.7z -oC:\gtk-build\gtk
 
           Invoke-WebRequest https://dl.hexchat.net/gtk-win32/gendef-20111031.7z -OutFile deps\gendef.7z
@@ -63,12 +61,12 @@ jobs:
           move ..\hexchat-build .\
         shell: cmd
 
-      - uses: actions/upload-artifact@v2-preview
+      - uses: actions/upload-artifact@v2
         with:
-          name: Installer
+          name: Installer ${{ matrix.arch }}
           path: HexChat*.exe
 
-      - uses: actions/upload-artifact@v2-preview
+      - uses: actions/upload-artifact@v2
         with:
-          name: Build
+          name: Build Files ${{ matrix.arch  }}
           path: hexchat-build
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..ff138137
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "flatpak/shared-modules"]
+	path = flatpak/shared-modules
+	url = https://github.com/flathub/shared-modules.git
diff --git a/data/icons/meson.build b/data/icons/meson.build
index d7926e83..710e0045 100644
--- a/data/icons/meson.build
+++ b/data/icons/meson.build
@@ -1,9 +1,11 @@
 icondir = join_paths(get_option('datadir'), 'icons/hicolor')
 install_data(
   'hexchat.png',
+  rename: 'io.github.Hexchat.png',
   install_dir: join_paths(icondir, '48x48/apps')
 )
 install_data(
   'hexchat.svg',
+  rename: 'io.github.Hexchat.svg',
   install_dir: join_paths(icondir, 'scalable/apps')
 )
diff --git a/data/meson.build b/data/meson.build
index b905c314..6c6b1a9c 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -1,11 +1,11 @@
-if get_option('with-plugin')
+if get_option('plugin')
   subdir('pkgconfig')
 endif
 
-if get_option('with-gtk')
+if get_option('gtk-frontend')
   subdir('icons')
   subdir('misc')
   subdir('man')
-elif get_option('with-theme-manager')
+elif get_option('theme-manager')
   subdir('misc')
 endif
diff --git a/data/misc/io.github.Hexchat.appdata.xml.in b/data/misc/io.github.Hexchat.appdata.xml.in
index 9b0bac72..9ee4343b 100644
--- a/data/misc/io.github.Hexchat.appdata.xml.in
+++ b/data/misc/io.github.Hexchat.appdata.xml.in
@@ -26,6 +26,35 @@
     <id>hexchat.desktop</id>
   </provides>
   <releases>
+    <release date="2022-02-12" version="2.16.1">
+      <description>
+        <p>This is a minor release with mostly bug-fixes:</p>
+        <ul>
+          <li>Add `-NOOVERRIDE` flag to the `GUI COLOR` command</li>
+          <li>Add `-q` (quiet) flag to the `EXECWRITE` command</li>
+          <li>Rename installed icon to match app-id (Fixes notification icon)</li>
+          <li>Fix escaping already escaped URLs when opening them</li>
+          <li>Fix Python scripts not being opened as UTF-8</li>
+          <li>Fix `TIMER` command supporting decimals regardless of locale</li>
+        </ul>
+      </description>
+    </release>
+    <release date="2021-10-01" version="2.16.0">
+      <description>
+        <p>This is a feature release:</p>
+        <ul>
+          <li>Add support for IRCv3 SETNAME, invite-notify, account-tag, standard replies, and UTF8ONLY</li>
+          <li>Add support for strikethrough formatting</li>
+          <li>Fix text clipping issues by respecting font line height</li>
+          <li>Fix URLs not being escaped when opened</li>
+          <li>Fix possible hang when showing notifications</li>
+          <li>Print ChanServ notices in the front tab by default</li>
+          <li>Update network list</li>
+          <li>python: Rewrite plugin improving memory usage and compatibility</li>
+          <li>fishlim: Add support for CBC and other improvements</li>
+        </ul>
+      </description>
+    </release>
     <release date="2019-12-20" version="2.14.3">
       <description>
         <p>This is a bug-fix release:</p>
diff --git a/data/misc/io.github.Hexchat.desktop.in.in b/data/misc/io.github.Hexchat.desktop.in.in
index 7bf6a9a8..5e00ce8f 100644
--- a/data/misc/io.github.Hexchat.desktop.in.in
+++ b/data/misc/io.github.Hexchat.desktop.in.in
@@ -4,7 +4,7 @@ GenericName=IRC Client
 Comment=Chat with other people online
 Keywords=IM;Chat;
 Exec=@exec_command@
-Icon=hexchat
+Icon=io.github.Hexchat
 Terminal=false
 Type=Application
 Categories=GTK;Network;IRCClient;
diff --git a/data/misc/meson.build b/data/misc/meson.build
index f7f1c27f..2abf3075 100644
--- a/data/misc/meson.build
+++ b/data/misc/meson.build
@@ -2,8 +2,8 @@ appdir = join_paths(get_option('datadir'), 'applications')
 metainfodir = join_paths(get_option('datadir'), 'metainfo')
 desktop_utils = find_program('desktop-file-validate', required: false)
 
-if get_option('with-gtk')
-  if get_option('with-appdata')
+if get_option('gtk-frontend')
+  if get_option('install-appdata')
     hexchat_appdata = i18n.merge_file(
       input: 'io.github.Hexchat.appdata.xml.in',
       output: 'io.github.Hexchat.appdata.xml',
@@ -21,7 +21,7 @@ if get_option('with-gtk')
   endif
 
   desktop_conf = configuration_data()
-  if get_option('with-dbus')
+  if dbus_glib_dep.found()
     desktop_conf.set('exec_command', 'hexchat --existing %U')
   else
     desktop_conf.set('exec_command', 'hexchat %U')
@@ -49,7 +49,7 @@ if get_option('with-gtk')
   endif
 endif
 
-if get_option('with-theme-manager')
+if get_option('theme-manager')
   htm_desktop = i18n.merge_file(
     input: 'io.github.Hexchat.ThemeManager.desktop.in',
     output: 'io.github.Hexchat.ThemeManager.desktop',
@@ -70,7 +70,7 @@ if get_option('with-theme-manager')
   )
 endif
 
-if get_option('with-plugin') and get_option('with-appdata')
+if get_option('plugin')
   plugin_metainfo = []
 
   # FIXME: These should all get translated somewhere
@@ -124,4 +124,4 @@ if get_option('with-plugin') and get_option('with-appdata')
       install_dir: get_option('install-plugin-metainfo') ? metainfodir : '',
     )
   endforeach
-endif
\ No newline at end of file
+endif
diff --git a/flatpak/Load-plugins-from-Flatpak-extensions.patch b/flatpak/Load-plugins-from-Flatpak-extensions.patch
new file mode 100644
index 00000000..e93e864c
--- /dev/null
+++ b/flatpak/Load-plugins-from-Flatpak-extensions.patch
@@ -0,0 +1,25 @@
+From 918503d57c6740d20be68a6717158673a2a8b25f Mon Sep 17 00:00:00 2001
+From: Patrick Griffis <tingping@tingping.se>
+Date: Sat, 17 Mar 2018 05:57:49 -0400
+Subject: [PATCH] Support loading Flatpak extensions
+
+---
+ src/common/plugin.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/common/plugin.c b/src/common/plugin.c
+index 3ad3c558..6addf962 100644
+--- a/src/common/plugin.c
++++ b/src/common/plugin.c
+@@ -450,6 +450,8 @@ plugin_auto_load (session *sess)
+ 	lib_dir = plugin_get_libdir ();
+ 	sub_dir = g_build_filename (get_xdir (), "addons", NULL);
+ 
++	for_files ("/app/extensions/lib/hexchat/plugins", "*.so", plugin_auto_load_cb);
++
+ #ifdef WIN32
+ 	/* a long list of bundled plugins that should be loaded automatically,
+ 	 * user plugins should go to <config>, leave Program Files alone! */
+-- 
+2.14.3
+
diff --git a/flatpak/io.github.Hexchat.json b/flatpak/io.github.Hexchat.json
new file mode 100644
index 00000000..94cfb6c8
--- /dev/null
+++ b/flatpak/io.github.Hexchat.json
@@ -0,0 +1,78 @@
+{
+  "app-id": "io.github.Hexchat",
+  "branch": "stable",
+  "runtime": "org.gnome.Platform",
+  "runtime-version": "40",
+  "sdk": "org.gnome.Sdk",
+  "command": "hexchat",
+  "finish-args": [
+    "--share=ipc",
+    "--socket=x11",
+    "--share=network",
+    "--socket=pulseaudio",
+    "--filesystem=xdg-download",
+
+    "--talk-name=org.freedesktop.Notifications",
+
+    "--talk-name=org.mpris.MediaPlayer2.*"
+  ],
+  "add-extensions": {
+    "io.github.Hexchat.Plugin": {
+      "version": "20.08",
+      "directory": "extensions",
+      "add-ld-path": "lib",
+      "merge-dirs": "lib/hexchat/plugins",
+      "subdirectories": true,
+      "no-autodownload": true,
+      "autodelete": true
+    }
+  },
+  "modules": [
+    "shared-modules/gtk2/gtk2.json",
+    "shared-modules/gtk2/gtk2-common-themes.json",
+    "shared-modules/dbus-glib/dbus-glib.json",
+    "shared-modules/lua5.3/lua-5.3.5.json",
+    "shared-modules/libcanberra/libcanberra.json",
+    "python3-cffi.json",
+    {
+      "name": "lgi",
+      "buildsystem": "meson",
+      "sources": [
+        {
+          "type": "git",
+          "url": "https://github.com/pavouk/lgi.git",
+          "commit": "95418635aa8151a516d43166227ea2b9d4c4403f"
+        }
+      ]
+    },
+    {
+      "name": "hexchat",
+      "buildsystem": "meson",
+      "config-opts": [
+        "--buildtype=release",
+        "-Ddbus-service-use-appid=true",
+        "-Dwith-perl=false",
+        "-Dwith-lua=lua"
+      ],
+      "build-options": {
+        "cflags": "-Wno-error=missing-include-dirs"
+      },
+      "cleanup": [
+        "/share/man"
+      ],
+      "post-install": [
+        "install -d /app/extensions"
+      ],
+      "sources": [
+        {
+          "type": "dir",
+          "path": ".."
+        },
+        {
+          "type": "patch",
+          "path": "Load-plugins-from-Flatpak-extensions.patch"
+        }
+      ]
+    }
+  ]
+}
diff --git a/flatpak/python3-cffi.json b/flatpak/python3-cffi.json
new file mode 100644
index 00000000..171a384a
--- /dev/null
+++ b/flatpak/python3-cffi.json
@@ -0,0 +1,19 @@
+{
+    "name": "python3-cffi",
+    "buildsystem": "simple",
+    "build-commands": [
+        "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"cffi\" --no-build-isolation"
+    ],
+    "sources": [
+        {
+            "type": "file",
+            "url": "https://files.pythonhosted.org/packages/0f/86/e19659527668d70be91d0369aeaa055b4eb396b0f387a4f92293a20035bd/pycparser-2.20.tar.gz",
+            "sha256": "2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"
+        },
+        {
+            "type": "file",
+            "url": "https://files.pythonhosted.org/packages/a8/20/025f59f929bbcaa579704f443a438135918484fffaacfaddba776b374563/cffi-1.14.5.tar.gz",
+            "sha256": "fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/flatpak/shared-modules b/flatpak/shared-modules
new file mode 160000
+Subproject 2c2f8fef2e926ff03158c0b3341526cce1b405a
diff --git a/meson.build b/meson.build
index 9b33574b..8b0bd404 100644
--- a/meson.build
+++ b/meson.build
@@ -1,6 +1,6 @@
 project('hexchat', 'c',
-  version: '2.14.3',
-  meson_version: '>= 0.40.0',
+  version: '2.16.1',
+  meson_version: '>= 0.47.0',
   default_options: [
     'c_std=gnu89',
     'buildtype=debugoptimized',
@@ -15,12 +15,17 @@ cc = meson.get_compiler('c')
 
 libgio_dep = dependency('gio-2.0', version: '>= 2.34.0')
 libgmodule_dep = dependency('gmodule-2.0')
+
+libcanberra_dep = dependency('libcanberra', version: '>= 0.22',
+                             required: get_option('libcanberra'))
+dbus_glib_dep = dependency('dbus-glib-1', required: get_option('dbus'))
+
 global_deps = []
 if cc.get_id() == 'msvc'
-  libssl_dep = cc.find_library('libeay32')
+  libssl_dep = cc.find_library('libssl')
 else
   libssl_dep = dependency('openssl', version: '>= 0.9.8',
-                          required: get_option('with-ssl'))
+                          required: get_option('tls'))
 endif
 
 config_h = configuration_data()
@@ -29,14 +34,14 @@ config_h.set_quoted('PACKAGE_NAME', meson.project_name())
 config_h.set_quoted('GETTEXT_PACKAGE', 'hexchat')
 config_h.set_quoted('LOCALEDIR', join_paths(get_option('prefix'),
                                  get_option('datadir'), 'locale'))
+config_h.set_quoted('G_LOG_DOMAIN', 'hexchat')
 config_h.set10('ENABLE_NLS', true)
 
 # Optional features
-config_h.set('USE_OPENSSL', get_option('with-ssl'))
-config_h.set('USE_LIBPROXY', get_option('with-libproxy'))
-config_h.set('USE_LIBCANBERRA', get_option('with-libcanberra'))
-config_h.set('USE_DBUS', get_option('with-dbus'))
-config_h.set('USE_PLUGIN', get_option('with-plugin'))
+config_h.set('USE_OPENSSL', libssl_dep.found())
+config_h.set('USE_LIBCANBERRA', libcanberra_dep.found())
+config_h.set('USE_DBUS', dbus_glib_dep.found())
+config_h.set('USE_PLUGIN', get_option('plugin'))
 
 config_h.set('G_DISABLE_SINGLE_INCLUDES', true)
 config_h.set('GTK_DISABLE_DEPRECATED', true)
@@ -153,7 +158,7 @@ endforeach
 add_project_link_arguments(global_ldflags, language: 'c')
 
 subdir('src')
-if get_option('with-plugin')
+if get_option('plugin')
   subdir('plugins')
 endif
 if cc.get_id() != 'msvc'
@@ -161,6 +166,32 @@ if cc.get_id() != 'msvc'
   subdir('po') # FIXME: build xgettext
 
   meson.add_install_script('meson_post_install.py',
-    '@0@'.format(get_option('with-theme-manager'))
+    '@0@'.format(get_option('theme-manager'))
   )
 endif
+
+if meson.version().version_compare('>= 0.53.0')
+  summary({
+    'prefix': get_option('prefix'),
+    'bindir': get_option('bindir'),
+    'libdir': get_option('libdir'),
+    'datadir': get_option('datadir'),
+  }, section: 'Directories')
+
+  summary({
+    'TLS (openssl)': libssl_dep.found(),
+    'Plugin Support': get_option('plugin'),
+    'DBus Support': dbus_glib_dep.found(),
+    'libcanberra': libcanberra_dep.found(),
+  }, section: 'Features')
+
+  summary({
+    'Lua': get_option('with-lua'),
+    'Python': get_option('with-python'),
+    'Perl': get_option('with-perl'),
+    'Perl Legacy API': get_option('with-perl-legacy-api'),
+    'FiSH': get_option('with-fishlim'),
+    'Sysinfo': get_option('with-sysinfo'),
+    'DCC Checksum': get_option('with-checksum'),
+  }, section: 'Plugins')
+endif
diff --git a/meson_options.txt b/meson_options.txt
index 100a5ee7..c2ca54a2 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,36 +1,38 @@
-option('with-gtk', type: 'boolean',
+# Applications
+option('gtk-frontend', type: 'boolean',
   description: 'Main graphical interface'
 )
-option('with-text', type: 'boolean', value: false,
+option('text-frontend', type: 'boolean', value: false,
   description: 'Text interface (not generally useful)'
 )
-option('with-ssl', type: 'boolean',
+option('theme-manager', type: 'boolean', value: false,
+  description: 'Utility to help manage themes, requires mono/.net'
+)
+
+# Features
+option('tls', type: 'feature', value: 'enabled',
   description: 'Support for TLS connections, requires openssl'
 )
-option('with-plugin', type: 'boolean',
+option('plugin', type: 'boolean',
   description: 'Support for loadable plugins'
 )
-option('with-dbus', type: 'boolean',
+option('dbus', type: 'feature', value: 'auto',
   description: 'Support used for single-instance and scripting interface, Unix only'
 )
-option('with-libproxy', type: 'boolean',
-  description: 'Support for getting proxy information, Unix only'
-)
-option('with-libnotify', type: 'boolean',
-  description: 'Support for freedesktop notifications, Unix only'
-)
-option('with-libcanberra', type: 'boolean',
+option('libcanberra', type: 'feature', value: 'auto',
   description: 'Support for sound alerts, Unix only'
 )
-option('with-theme-manager', type: 'boolean', value: false,
-  description: 'Utility to help manage themes, requires mono/.net'
-)
+
+# Install options
 option('dbus-service-use-appid', type: 'boolean', value: false,
   description: 'Rename dbus service to match app-id, required for Flatpak'
 )
-option('with-appdata', type: 'boolean',
+option('install-appdata', type: 'boolean',
   description: 'Install appdata files for app stores'
 )
+option('install-plugin-metainfo', type: 'boolean', value: false,
+  description: 'Installs metainfo files for enabled plugins, useful when distros create split packages'
+)
 
 # Plugins
 option('with-checksum', type: 'boolean',
@@ -60,9 +62,6 @@ option('with-upd', type: 'boolean',
 option('with-winamp', type: 'boolean',
   description: 'Winamp plugin, Windows only'
 )
-option('install-plugin-metainfo', type: 'boolean', value: false,
-  description: 'Installs metainfo files for enabled plugins, useful when distros create split packages'
-)
 option('with-perl-legacy-api', type: 'boolean', value: false,
   description: 'Enables the legacy IRC perl module for compatibility with old scripts'
 )
diff --git a/plugins/checksum/meson.build b/plugins/checksum/meson.build
index 25835457..e3008f75 100644
--- a/plugins/checksum/meson.build
+++ b/plugins/checksum/meson.build
@@ -3,4 +3,5 @@ shared_module('checksum', 'checksum.c',
   install: true,
   install_dir: plugindir,
   name_prefix: '',
+  vs_module_defs: 'checksum.def',
 )
diff --git a/plugins/exec/meson.build b/plugins/exec/meson.build
index 3f9e8a32..782814da 100644
--- a/plugins/exec/meson.build
+++ b/plugins/exec/meson.build
@@ -1,5 +1,6 @@
 shared_module('exec', 'exec.c',
   dependencies: hexchat_plugin_dep,
   install: true,
-  install_dir: plugindir
+  install_dir: plugindir,
+  vs_module_defs: 'exec.def',
 )
diff --git a/plugins/fishlim/fish.c b/plugins/fishlim/fish.c
index c2c2b9da..5a27e4cb 100644
--- a/plugins/fishlim/fish.c
+++ b/plugins/fishlim/fish.c
@@ -87,6 +87,54 @@ static const signed char fish_unbase64[256] = {
     dest |= (uint8_t)*((source)++); \
 } while (0);
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/provider.h>
+static OSSL_PROVIDER *legacy_provider;
+static OSSL_PROVIDER *default_provider;
+static OSSL_LIB_CTX* *ossl_ctx;
+#endif
+
+int fish_init(void)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+    ossl_ctx = OSSL_LIB_CTX_new();
+    if (!ossl_ctx)
+        return 0;
+
+    legacy_provider = OSSL_PROVIDER_load(ossl_ctx, "legacy");
+    if (!legacy_provider) {
+        fish_deinit();
+        return 0;
+    }
+
+    default_provider = OSSL_PROVIDER_load(ossl_ctx, "default");
+    if (!default_provider) {
+        fish_deinit();
+        return 0;
+    }
+#endif
+    return 1;
+}
+
+void fish_deinit(void)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+    if (legacy_provider) {
+        OSSL_PROVIDER_unload(legacy_provider);
+        legacy_provider = NULL;
+    }
+
+    if (default_provider) {
+        OSSL_PROVIDER_unload(default_provider);
+        default_provider = NULL;
+    }
+
+    if (ossl_ctx) {
+        OSSL_LIB_CTX_free(ossl_ctx);
+        ossl_ctx = NULL;
+    }
+#endif
+}
 
 /**
  * Encode ECB FiSH Base64
@@ -228,9 +276,19 @@ char *fish_cipher(const char *plaintext, size_t plaintext_len, const char *key,
             plaintext_len -= 8;
         }
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+        cipher = EVP_CIPHER_fetch(ossl_ctx, "BF-CBC", NULL);
+#else
         cipher = (EVP_CIPHER *) EVP_bf_cbc();
+#endif
+
     } else if (mode == EVP_CIPH_ECB_MODE) {
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+        cipher = EVP_CIPHER_fetch(ossl_ctx, "BF-ECB", NULL);
+#else
         cipher = (EVP_CIPHER *) EVP_bf_ecb();
+#endif
     }
 
     /* Zero Padding */
diff --git a/plugins/fishlim/fish.h b/plugins/fishlim/fish.h
index 6a2e911c..75829061 100644
--- a/plugins/fishlim/fish.h
+++ b/plugins/fishlim/fish.h
@@ -35,6 +35,8 @@ enum fish_mode {
   FISH_CBC_MODE = 0x2
 };
 
+int fish_init(void);
+void fish_deinit(void);
 char *fish_base64_encode(const char *message, size_t message_len);
 char *fish_base64_decode(const char *message, size_t *final_len);
 char *fish_encrypt(const char *key, size_t keylen, const char *message, size_t message_len, enum fish_mode mode);
diff --git a/plugins/fishlim/fishlim.vcxproj b/plugins/fishlim/fishlim.vcxproj
index 579c2436..3661e1e6 100644
--- a/plugins/fishlim/fishlim.vcxproj
+++ b/plugins/fishlim/fishlim.vcxproj
@@ -29,7 +29,7 @@
   </PropertyGroup>

   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

     <ClCompile>

-      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;FISHLIM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;FISHLIM_EXPORTS;HAVE_DH_SET0_PQG;HAVE_DH_GET0_KEY;HAVE_DH_SET0_KEY;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);..\..\src\common;$(HexChatLib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

     </ClCompile>

     <Link>

@@ -40,7 +40,7 @@
   </ItemDefinitionGroup>

   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

     <ClCompile>

-      <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;FISHLIM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;FISHLIM_EXPORTS;HAVE_DH_SET0_PQG;HAVE_DH_GET0_KEY;HAVE_DH_SET0_KEY;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);..\..\src\common;$(HexChatLib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

     </ClCompile>

     <Link>

diff --git a/plugins/fishlim/meson.build b/plugins/fishlim/meson.build
index 65ccc9ea..232c9a33 100644
--- a/plugins/fishlim/meson.build
+++ b/plugins/fishlim/meson.build
@@ -19,4 +19,5 @@ shared_module('fishlim', fishlim_sources,
   install: true,
   install_dir: plugindir,
   name_prefix: '',
+  vs_module_defs: 'fishlim.def',
 )
diff --git a/plugins/fishlim/plugin_hexchat.c b/plugins/fishlim/plugin_hexchat.c
index 83286e28..a8b127f2 100644
--- a/plugins/fishlim/plugin_hexchat.c
+++ b/plugins/fishlim/plugin_hexchat.c
@@ -418,8 +418,6 @@ static int handle_keyx_notice(char *word[], char *word_eol[], void *userdata) {
         g_assert(hexchat_set_context(ph, query_ctx) == 1);
 
     dh_message++; /* : prefix */
-    if (*dh_message == '+' || *dh_message == '-')
-        dh_message++; /* identify-msg */
 
     if (g_strcmp0 (word[6], "CBC") == 0)
         mode = FISH_CBC_MODE;
@@ -817,6 +815,9 @@ int hexchat_plugin_init(hexchat_plugin *plugin_handle,
     hexchat_hook_server_attrs(ph, "TOPIC", HEXCHAT_PRI_NORM, handle_incoming, NULL);
     hexchat_hook_server_attrs(ph, "332", HEXCHAT_PRI_NORM, handle_incoming, NULL);
 
+    if (!fish_init())
+        return 0;
+
     if (!dh1080_init())
         return 0;
 
@@ -830,6 +831,7 @@ int hexchat_plugin_init(hexchat_plugin *plugin_handle,
 int hexchat_plugin_deinit(void) {
     g_clear_pointer(&pending_exchanges, g_hash_table_destroy);
     dh1080_deinit();
+    fish_deinit();
 
     hexchat_printf(ph, "%s plugin unloaded\n", plugin_name);
     return 1;
diff --git a/plugins/fishlim/tests/meson.build b/plugins/fishlim/tests/meson.build
index 3b75018e..1a0394a3 100644
--- a/plugins/fishlim/tests/meson.build
+++ b/plugins/fishlim/tests/meson.build
@@ -1,17 +1,16 @@
-subdir('old_version')
-
 fishlim_test_sources = [
   'tests.c',
-  'fake/keystore.c',
+  'mock-keystore.c',
   '../fish.c',
   '../utils.c',
 ]
 
 fishlim_tests = executable('fishlim_tests', fishlim_test_sources,
-  dependencies: [libgio_dep, libssl_dep],
-  link_with : fishlim_old_lib
+  dependencies: [libgio_dep, libssl_dep, hexchat_plugin_dep],
+  include_directories: include_directories('..'),
 )
 
 test('Fishlim Tests', fishlim_tests,
-  timeout: 90
+  protocol: 'tap',
+  timeout: 600,
 )
diff --git a/plugins/fishlim/tests/fake/keystore.c b/plugins/fishlim/tests/mock-keystore.c
index 854f38dc..57a98847 100644
--- a/plugins/fishlim/tests/fake/keystore.c
+++ b/plugins/fishlim/tests/mock-keystore.c
@@ -1,5 +1,4 @@
 /*
-
   Copyright (c) 2010 Samuel Lidén Borell <samuel@kodafritt.se>
 
   Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -22,26 +21,31 @@
 
 */
 
-#include "../../fish.h"
-
+#include "fish.h"
 
 /**
  * Extracts a key from the key store file.
  */
-char *keystore_get_key(const char *nick, enum fish_mode *mode) {
+char *
+keystore_get_key(const char *nick, enum fish_mode *mode)
+{
     return NULL;
 }
 
 /**
  * Sets a key in the key store file.
  */
-gboolean keystore_store_key(const char *nick, const char *key, enum fish_mode mode) {
+gboolean
+keystore_store_key(const char *nick, const char *key, enum fish_mode mode)
+{
     return TRUE;
 }
 
 /**
  * Deletes a nick from the key store.
  */
-gboolean keystore_delete_nick(const char *nick) {
+gboolean
+keystore_delete_nick(const char *nick)
+{
     return TRUE;
 }
diff --git a/plugins/fishlim/tests/old_version/fish.c b/plugins/fishlim/tests/old_version/fish.c
deleted file mode 100644
index 99601398..00000000
--- a/plugins/fishlim/tests/old_version/fish.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
-
-  Copyright (c) 2010 Samuel Lidén Borell <samuel@kodafritt.se>
-
-  Permission is hereby granted, free of charge, to any person obtaining a copy
-  of this software and associated documentation files (the "Software"), to deal
-  in the Software without restriction, including without limitation the rights
-  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the Software is
-  furnished to do so, subject to the following conditions:
-
-  The above copyright notice and this permission notice shall be included in
-  all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-  THE SOFTWARE.
-
-*/
-
-#ifdef __APPLE__
-#define __AVAILABILITYMACROS__
-#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <openssl/blowfish.h>
-
-#include "fish.h"
-
-#define IB 64
-static const char fish_base64[64] = "./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
-static const signed char fish_unbase64[256] = {
-    IB,IB,IB,IB,IB,IB,IB,IB,  IB,IB,IB,IB,IB,IB,IB,IB,
-    IB,IB,IB,IB,IB,IB,IB,IB,  IB,IB,IB,IB,IB,IB,IB,IB,
-/*      !  "  #  $  %  &  '  (    )  *  +  ,  -  .  / */
-    IB,IB,IB,IB,IB,IB,IB,IB,  IB,IB,IB,IB,IB,IB, 0, 1,
-/*   0  1  2  3  4  5  6  7    8  9  :  ;  <  =  >  ? */
-     2, 3, 4, 5, 6, 7, 8, 9,  10,11,IB,IB,IB,IB,IB,IB,
-/*   @  A  B  C  D  E  F  G    H  I  J  K  L  M  N  O */
-    IB,38,39,40,41,42,43,44,  45,46,47,48,49,50,51,52,
-/*   P  Q  R  S  T  U  V  W    X  Y  Z  [  \  ]  ^  _*/
-    53,54,55,56,57,58,59,60,  61,62,63,IB,IB,IB,IB,IB,
-/*   `  a  b  c  d  e  f  g    h  i  j  k  l  m  n  o */
-    IB,12,13,14,15,16,17,18,  19,20,21,22,23,24,25,26,
-/*   p  q  r  s  t  u  v  w    x  y  z  {  |  }  ~  <del> */
-    27,28,29,30,31,32,33,34,  35,36,37,IB,IB,IB,IB,IB,
-};
-
-#define GET_BYTES(dest, source) do { \
-    *((dest)++) = ((source) >> 24) & 0xFF; \
-    *((dest)++) = ((source) >> 16) & 0xFF; \
-    *((dest)++) = ((source) >> 8) & 0xFF; \
-    *((dest)++) = (source) & 0xFF; \
-} while (0);
-
-
-char *__old_fish_encrypt(const char *key, size_t keylen, const char *message) {
-    BF_KEY bfkey;
-    size_t messagelen;
-    size_t i;
-    int j;
-    char *encrypted;
-    char *end;
-    unsigned char bit;
-    unsigned char word;
-    unsigned char d;
-    BF_set_key(&bfkey, keylen, (const unsigned char*)key);
-    
-    messagelen = strlen(message);
-    if (messagelen == 0) return NULL;
-    encrypted = g_malloc(((messagelen - 1) / 8) * 12 + 12 + 1); /* each 8-byte block becomes 12 bytes */
-    end = encrypted;
-     
-    while (*message) {
-        /* Read 8 bytes (a Blowfish block) */
-        BF_LONG binary[2] = { 0, 0 };
-        unsigned char c;
-        for (i = 0; i < 8; i++) {
-            c = message[i];
-            binary[i >> 2] |= c << 8*(3 - (i&3));
-            if (c == '\0') break;
-        }
-        message += 8;
-        
-        /* Encrypt block */
-        BF_encrypt(binary, &bfkey);
-        
-        /* Emit FiSH-BASE64 */
-        bit = 0;
-        word = 1;
-        for (j = 0; j < 12; j++) {
-            d = fish_base64[(binary[word] >> bit) & 63];
-            *(end++) = d;
-            bit += 6;
-            if (j == 5) {
-                bit = 0;
-                word = 0;
-            }
-        }
-        
-        /* Stop if a null terminator was found */
-        if (c == '\0') break;
-    }
-    *end = '\0';
-    return encrypted;
-}
-
-
-char *__old_fish_decrypt(const char *key, size_t keylen, const char *data) {
-    BF_KEY bfkey;
-    size_t i;
-    char *decrypted;
-    char *end;
-    unsigned char bit;
-    unsigned char word;
-    unsigned char d;
-    BF_set_key(&bfkey, keylen, (const unsigned char*)key);
-    
-    decrypted = g_malloc(strlen(data) + 1);
-    end = decrypted;
-    
-    while (*data) {
-        /* Convert from FiSH-BASE64 */
-        BF_LONG binary[2] = { 0, 0 };
-        bit = 0;
-        word = 1;
-        for (i = 0; i < 12; i++) {
-            d = fish_unbase64[(const unsigned char)*(data++)];
-            if (d == IB) goto decrypt_end;
-            binary[word] |= (unsigned long)d << bit;
-            bit += 6;
-            if (i == 5) {
-                bit = 0;
-                word = 0;
-            }
-        }
-        
-        /* Decrypt block */
-        BF_decrypt(binary, &bfkey);
-        
-        /* Copy to buffer */
-        GET_BYTES(end, binary[0]);
-        GET_BYTES(end, binary[1]);
-    }
-    
-  decrypt_end:
-    *end = '\0';
-    return decrypted;
-}
\ No newline at end of file
diff --git a/plugins/fishlim/tests/old_version/fish.h b/plugins/fishlim/tests/old_version/fish.h
deleted file mode 100644
index 7037782b..00000000
--- a/plugins/fishlim/tests/old_version/fish.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-
-  Copyright (c) 2010 Samuel Lidén Borell <samuel@kodafritt.se>
-
-  Permission is hereby granted, free of charge, to any person obtaining a copy
-  of this software and associated documentation files (the "Software"), to deal
-  in the Software without restriction, including without limitation the rights
-  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the Software is
-  furnished to do so, subject to the following conditions:
-
-  The above copyright notice and this permission notice shall be included in
-  all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-  THE SOFTWARE.
-
-*/
-
-#ifndef FISH_OLD_H
-#define FISH_OLD_H
-
-#include <stddef.h>
-
-#include <glib.h>
-
-char *__old_fish_encrypt(const char *key, size_t keylen, const char *message);
-char *__old_fish_decrypt(const char *key, size_t keylen, const char *data);
-
-#endif
-
-
diff --git a/plugins/fishlim/tests/old_version/meson.build b/plugins/fishlim/tests/old_version/meson.build
deleted file mode 100644
index 54647d71..00000000
--- a/plugins/fishlim/tests/old_version/meson.build
+++ /dev/null
@@ -1,4 +0,0 @@
-fishlim_old_lib = shared_library('fishlim_old_lib',
-  ['fish.c'],
-  dependencies: [libgio_dep, libssl_dep],
-)
diff --git a/plugins/fishlim/tests/tests.c b/plugins/fishlim/tests/tests.c
index bb841c5e..12b10d1d 100644
--- a/plugins/fishlim/tests/tests.c
+++ b/plugins/fishlim/tests/tests.c
@@ -1,5 +1,4 @@
 /*
-
   Copyright (c) 2020 <bakasura@protonmail.ch>
 
   Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -22,22 +21,20 @@
 
 */
 
-#ifndef PLUGIN_HEXCHAT_FISHLIM_TEST_H
-#define PLUGIN_HEXCHAT_FISHLIM_TEST_H
-
-// Libs
+#include <string.h>
 #include <glib.h>
-// Project Libs
-#include "../fish.h"
-#include "../utils.h"
-#include "old_version/fish.h"
+
+#include "fish.h"
+#include "utils.h"
 
 /**
  * Auxiliary function: Generate a random string
  * @param out Preallocated string to fill
  * @param len Size of bytes to fill
  */
-void random_string(char *out, size_t len) {
+static void
+random_string(char *out, size_t len)
+{
     GRand *rand = NULL;
     int i = 0;
 
@@ -51,13 +48,14 @@ void random_string(char *out, size_t len) {
     g_rand_free(rand);
 }
 
-
 /**
- * Check encrypt and decrypt in ECB mode and compare with old implementation
+ * Check encrypt and decrypt in ECB mode
  */
-void __ecb(void) {
-    char *bo64 = NULL, *b64 = NULL;
-    char *deo = NULL, *de = NULL;
+static void
+test_ecb(void)
+{
+    char *b64 = NULL;
+    char *de = NULL;
     int key_len, message_len = 0;
     char key[57];
     char message[1000];
@@ -71,36 +69,20 @@ void __ecb(void) {
             random_string(message, message_len);
 
             /* Encrypt */
-            bo64 = __old_fish_encrypt(key, key_len, message);
-            g_assert_nonnull(bo64);
             b64 = fish_encrypt(key, key_len, message, message_len, FISH_ECB_MODE);
             g_assert_nonnull(b64);
-            g_assert_cmpuint(g_strcmp0(b64, bo64), == , 0);
 
             /* Decrypt */
             /* Linear */
-            deo = __old_fish_decrypt(key, key_len, bo64);
             de = fish_decrypt_str(key, key_len, b64, FISH_ECB_MODE);
-            g_assert_nonnull(deo);
-            g_assert_nonnull(de);
-            g_assert_cmpuint(g_strcmp0(de, message), == , 0);
-            g_assert_cmpuint(g_strcmp0(deo, message), == , 0);
-            g_assert_cmpuint(g_strcmp0(de, deo), == , 0);
-            g_free(deo);
+			g_assert_cmpstr (de, ==, message);
             g_free(de);
+	
             /* Mixed */
-            deo = __old_fish_decrypt(key, key_len, b64);
-            de = fish_decrypt_str(key, key_len, bo64, FISH_ECB_MODE);
-            g_assert_nonnull(deo);
-            g_assert_nonnull(de);
-            g_assert_cmpuint(g_strcmp0(de, message), == , 0);
-            g_assert_cmpuint(g_strcmp0(deo, message), == , 0);
-            g_assert_cmpuint(g_strcmp0(de, deo), == , 0);
-            g_free(deo);
+            de = fish_decrypt_str(key, key_len, b64, FISH_ECB_MODE);
+			g_assert_cmpstr (de, ==, message);
             g_free(de);
 
-            /* Free */
-            g_free(bo64);
             g_free(b64);
         }
     }
@@ -109,7 +91,9 @@ void __ecb(void) {
 /**
  * Check encrypt and decrypt in CBC mode
  */
-void __cbc(void) {
+static void
+test_cbc(void)
+{
     char *b64 = NULL;
     char *de = NULL;
     int key_len, message_len = 0;
@@ -131,11 +115,9 @@ void __cbc(void) {
             /* Decrypt */
             /* Linear */
             de = fish_decrypt_str(key, key_len, b64, FISH_CBC_MODE);
-            g_assert_nonnull(de);
-            g_assert_cmpuint(g_strcmp0(de, message), == , 0);
+            g_assert_cmpstr (de, ==, message);
             g_free(de);
 
-            /* Free */
             g_free(b64);
         }
     }
@@ -144,48 +126,49 @@ void __cbc(void) {
 /**
  * Check the calculation of final length from an encoded string in Base64
  */
-void __base64_len(void) {
+static void
+test_base64_len (void)
+{
     char *b64 = NULL;
-    int i, message_len = 0;
     char message[1000];
+    int message_end = sizeof (message) - 1;
 
-    for (i = 0; i < 10; ++i) {
+    random_string(message, message_end);
 
-        for (message_len = 1; message_len < 1000; ++message_len) {
-            random_string(message, message_len);
-            b64 = g_base64_encode((const unsigned char *) message, message_len);
-            g_assert_nonnull(b64);
-            g_assert_cmpuint(strlen(b64), == , base64_len(message_len));
-            g_free(b64);
-        }
+    for (; message_end >= 0; --message_end) {
+        message[message_end] = '\0'; /* Truncate instead of generating new strings */
+        b64 = g_base64_encode((const unsigned char *) message, message_end);
+        g_assert_nonnull(b64);
+        g_assert_cmpuint(strlen(b64), == , base64_len(message_end));
+        g_free(b64);
     }
 }
 
 /**
  * Check the calculation of final length from an encoded string in BlowcryptBase64
  */
-void __base64_fish_len(void) {
+static void
+test_base64_fish_len (void)
+{
     char *b64 = NULL;
-    int i, message_len = 0;
+    int message_len = 0;
     char message[1000];
 
-    for (i = 0; i < 10; ++i) {
-
-        for (message_len = 1; message_len < 1000; ++message_len) {
-            random_string(message, message_len);
-            b64 = fish_base64_encode(message, message_len);
-            g_assert_nonnull(b64);
-            g_assert_cmpuint(strlen(b64), == , base64_fish_len(message_len));
-            g_free(b64);
-        }
+    for (message_len = 1; message_len < 1000; ++message_len) {
+        random_string(message, message_len);
+        b64 = fish_base64_encode(message, message_len);
+        g_assert_nonnull(b64);
+        g_assert_cmpuint(strlen(b64), == , base64_fish_len(message_len));
+        g_free(b64);
     }
 }
 
-
 /**
  * Check the calculation of final length from an encrypted string in ECB mode
  */
-void __base64_ecb_len(void) {
+static void
+test_base64_ecb_len(void)
+{
     char *b64 = NULL;
     int key_len, message_len = 0;
     char key[57];
@@ -209,7 +192,9 @@ void __base64_ecb_len(void) {
 /**
  * Check the calculation of final length from an encrypted string in CBC mode
  */
-void __base64_cbc_len(void) {
+static void
+test_base64_cbc_len(void)
+{
     char *b64 = NULL;
     int key_len, message_len = 0;
     char key[57];
@@ -233,7 +218,9 @@ void __base64_cbc_len(void) {
 /**
  * Check the calculation of length limit for a plaintext in each encryption mode
  */
-void __max_text_command_len(void) {
+static void
+test_max_text_command_len(void)
+{
     int max_encoded_len, plaintext_len;
     enum fish_mode mode;
 
@@ -248,50 +235,51 @@ void __max_text_command_len(void) {
 /**
  * Check the calculation of length limit for a plaintext in each encryption mode
  */
-void __foreach_utf8_data_chunks(void) {
+static void
+test_foreach_utf8_data_chunks(void)
+{
     GRand *rand = NULL;
     GString *chunks = NULL;
-    int tests, max_chunks_len, chunks_len;
+    int  max_chunks_len, chunks_len;
     char ascii_message[1001];
     char *data_chunk = NULL;
 
     rand = g_rand_new();
+    max_chunks_len = g_rand_int_range(rand, 2, 301);
+    random_string(ascii_message, 1000);
 
-    for (tests = 0; tests < 1000; ++tests) {
-
-        max_chunks_len = g_rand_int_range(rand, 2, 301);
-        random_string(ascii_message, 1000);
+    data_chunk = ascii_message;
 
-        data_chunk = ascii_message;
+    chunks = g_string_new(NULL);
 
-        chunks = g_string_new(NULL);
-
-        while (foreach_utf8_data_chunks(data_chunk, max_chunks_len, &chunks_len)) {
-            g_string_append(chunks, g_strndup(data_chunk, chunks_len));
-            /* Next chunk */
-            data_chunk += chunks_len;
-        }
-        /* Check data loss */
-        g_assert_cmpstr(chunks->str, == , ascii_message);
-        g_string_free(chunks, TRUE);
+    while (foreach_utf8_data_chunks(data_chunk, max_chunks_len, &chunks_len)) {
+        g_string_append(chunks, g_strndup(data_chunk, chunks_len));
+        /* Next chunk */
+        data_chunk += chunks_len;
     }
-}
+    /* Check data loss */
+    g_assert_cmpstr(chunks->str, == , ascii_message);
 
+    g_string_free(chunks, TRUE);
+    g_rand_free (rand);
+}
 
-int main(int argc, char *argv[]) {
+int
+main(int argc, char *argv[]) {
 
     g_test_init(&argc, &argv, NULL);
 
-    g_test_add_func("/fishlim/__ecb", __ecb);
-    g_test_add_func("/fishlim/__cbc", __ecb);
-    g_test_add_func("/fishlim/__base64_len", __base64_len);
-    g_test_add_func("/fishlim/__base64_fish_len", __base64_fish_len);
-    g_test_add_func("/fishlim/__base64_ecb_len", __base64_ecb_len);
-    g_test_add_func("/fishlim/__base64_cbc_len", __base64_cbc_len);
-    g_test_add_func("/fishlim/__max_text_command_len", __max_text_command_len);
-    g_test_add_func("/fishlim/__foreach_utf8_data_chunks", __foreach_utf8_data_chunks);
-
-    return g_test_run();
+    g_test_add_func("/fishlim/ecb", test_ecb);
+    g_test_add_func("/fishlim/cbc", test_cbc);
+    g_test_add_func("/fishlim/base64_len", test_base64_len);
+    g_test_add_func("/fishlim/base64_fish_len", test_base64_fish_len);
+    g_test_add_func("/fishlim/base64_ecb_len", test_base64_ecb_len);
+    g_test_add_func("/fishlim/base64_cbc_len", test_base64_cbc_len);
+    g_test_add_func("/fishlim/max_text_command_len", test_max_text_command_len);
+    g_test_add_func("/fishlim/foreach_utf8_data_chunks", test_foreach_utf8_data_chunks);
+
+    fish_init();
+    int ret = g_test_run();
+    fish_deinit();
+    return ret;
 }
-
-#endif //PLUGIN_HEXCHAT_FISHLIM_TEST_H
\ No newline at end of file
diff --git a/plugins/fishlim/utils.c b/plugins/fishlim/utils.c
index 4052995a..17ed4c2e 100644
--- a/plugins/fishlim/utils.c
+++ b/plugins/fishlim/utils.c
@@ -22,6 +22,8 @@
 
 */
 
+#include <string.h>
+
 #include "utils.h"
 #include "fish.h"
 
diff --git a/plugins/lua/lua.c b/plugins/lua/lua.c
index d1370eaf..f8f051f4 100644
--- a/plugins/lua/lua.c
+++ b/plugins/lua/lua.c
@@ -957,16 +957,21 @@ static int api_hexchat_pluginprefs_meta_pairs(lua_State *L)
 	hexchat_plugin *h;
 
 	if(!script->name)
+
 		return luaL_error(L, "cannot use hexchat.pluginprefs before registering with hexchat.register");
 
 	dest = lua_newuserdata(L, 4096);
+
 	h = script->handle;
 	if(!hexchat_pluginpref_list(h, dest))
 		strcpy(dest, "");
 	lua_pushlightuserdata(L, dest);
 	lua_pushlightuserdata(L, dest);
 	lua_pushcclosure(L, api_hexchat_pluginprefs_meta_pairs_closure, 2);
-	return 1;
+	lua_insert(L, -2); // Return the userdata (second return value from pairs),
+						// even though it's not used by the closure (first return
+						// value from pairs), so that Lua knows not to GC it.
+	return 2;
 }
 
 static int api_attrs_meta_index(lua_State *L)
@@ -1764,4 +1769,3 @@ G_MODULE_EXPORT int hexchat_plugin_deinit(hexchat_plugin *plugin_handle)
 	g_clear_pointer(&expand_buffer, g_free);
 	return 1;
 }
-
diff --git a/plugins/perl/meson.build b/plugins/perl/meson.build
index 06ffd54b..ebcf35bb 100644
--- a/plugins/perl/meson.build
+++ b/plugins/perl/meson.build
@@ -88,4 +88,5 @@ shared_module('perl',
   install_dir: plugindir,
   install_rpath: perl_rpath,
   name_prefix: '',
+  vs_module_defs: 'perl.def',
 )
diff --git a/plugins/python/meson.build b/plugins/python/meson.build
index 5fd7ec2f..1e9b41ad 100644
--- a/plugins/python/meson.build
+++ b/plugins/python/meson.build
@@ -28,4 +28,5 @@ shared_module('python', python3_source,
   install: true,
   install_dir: plugindir,
   name_prefix: '',
+  vs_module_defs: 'python.def'
 )
diff --git a/plugins/python/python.py b/plugins/python/python.py
index 7bd327e3..1adcde98 100644
--- a/plugins/python/python.py
+++ b/plugins/python/python.py
@@ -146,7 +146,7 @@ class Plugin:
     def loadfile(self, filename):
         try:
             self.filename = filename
-            with open(filename) as f:
+            with open(filename, encoding='utf-8') as f:
                 data = f.read()
             compiled = compile_file(data, filename)
             exec(compiled, self.globals)
diff --git a/plugins/sysinfo/meson.build b/plugins/sysinfo/meson.build
index 7e2cdb6c..08f08c2c 100644
--- a/plugins/sysinfo/meson.build
+++ b/plugins/sysinfo/meson.build
@@ -57,4 +57,5 @@ shared_module('sysinfo', sysinfo_sources,
   install: true,
   install_dir: plugindir,
   name_prefix: '',
+  vs_module_defs: 'sysinfo.def',
 )
diff --git a/plugins/upd/meson.build b/plugins/upd/meson.build
index 7ab9d830..68217b31 100644
--- a/plugins/upd/meson.build
+++ b/plugins/upd/meson.build
@@ -5,4 +5,5 @@ shared_module('upd', 'upd.c',
   install: true,
   install_dir: plugindir,
   name_prefix: '',
+  vs_module_defs: 'upd.def',
 )
diff --git a/plugins/winamp/meson.build b/plugins/winamp/meson.build
index b07e7071..8d298651 100644
--- a/plugins/winamp/meson.build
+++ b/plugins/winamp/meson.build
@@ -3,4 +3,5 @@ shared_module('winamp', 'winamp.c',
   install: true,
   install_dir: plugindir,
   name_prefix: '',
+  vs_module_defs: 'winamp.def',
 )
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
diff --git a/win32/copy/copy.vcxproj b/win32/copy/copy.vcxproj
index b26d7e28..2fc7437b 100644
--- a/win32/copy/copy.vcxproj
+++ b/win32/copy/copy.vcxproj
@@ -40,7 +40,8 @@
     <None Include="$(DepsRoot)\bin\gthread-2.0-0.dll" />

     <None Include="$(DepsRoot)\bin\gtk-win32-2.0.dll" />

     <None Include="$(DepsRoot)\bin\iconv.dll" />

-    <None Include="$(DepsRoot)\bin\libeay32.dll" />

+    <None Include="$(DepsRoot)\bin\libcrypto*.dll" />

+    <None Include="$(DepsRoot)\bin\libssl*.dll" />

     <None Include="$(DepsRoot)\bin\libenchant.dll" />

     <None Include="$(DepsRoot)\bin\ffi-7.dll" />

     <None Include="$(DepsRoot)\bin\intl.dll" />

@@ -50,7 +51,6 @@
     <None Include="$(DepsRoot)\bin\pangocairo-1.0-0.dll" />

     <None Include="$(DepsRoot)\bin\pangoft2-1.0-0.dll" />

     <None Include="$(DepsRoot)\bin\pangowin32-1.0-0.dll" />

-    <None Include="$(DepsRoot)\bin\ssleay32.dll" />

     <None Include="$(DepsRoot)\bin\zlib1.dll" />

     <None Include="$(WinSparklePath)\WinSparkle.dll" />

     <None Include="$(HexChatBin)thememan.exe" />

diff --git a/win32/hexchat.props b/win32/hexchat.props
index f40c794a..038873b1 100644
--- a/win32/hexchat.props
+++ b/win32/hexchat.props
@@ -15,7 +15,7 @@
 

 		<!-- G_DISABLE_DEPRECATED is unfeasible due to g_completion_* -->

 		<!-- must be buildable with GSEAL_ENABLE in the future, xtext, setup, and chanview-tabs stand in the way -->

-		<OwnFlags>GTK_DISABLE_DEPRECATED;GDK_PIXBUF_DISABLE_DEPRECATED;G_DISABLE_SINGLE_INCLUDES;GDK_PIXBUF_DISABLE_SINGLE_INCLUDES;GTK_DISABLE_SINGLE_INCLUDES;HAVE_STRTOULL;strtoull=_strtoui64;strcasecmp=stricmp;strncasecmp=strnicmp;__inline__=__inline</OwnFlags>

+		<OwnFlags>GTK_DISABLE_DEPRECATED;GDK_PIXBUF_DISABLE_DEPRECATED;G_DISABLE_SINGLE_INCLUDES;GDK_PIXBUF_DISABLE_SINGLE_INCLUDES;GTK_DISABLE_SINGLE_INCLUDES;HAVE_X509_GET_SIGNATURE_NID;HAVE_SSL_CTX_GET_SSL_METHOD;DEFAULT_CERT_FILE="cert.pem";HAVE_STRTOULL;strtoull=_strtoui64;strcasecmp=stricmp;strncasecmp=strnicmp;__inline__=__inline</OwnFlags>

 		<!-- FIXME: Add ability to use debug builds -->

 		<DepsRoot>$(YourDepsPath)\$(PlatformName)\release</DepsRoot>

 		<GendefPath>$(YourGendefPath)</GendefPath>

@@ -33,7 +33,7 @@
 		<LuaLib>lua51</LuaLib>

 		<Glib>$(DepsRoot)\include\glib-2.0;$(DepsRoot)\lib\glib-2.0\include;$(DepsRoot)\include\libxml2</Glib>

 		<Gtk>$(DepsRoot)\include\gtk-2.0;$(DepsRoot)\lib\gtk-2.0\include;$(DepsRoot)\include\atk-1.0;$(DepsRoot)\include\cairo;$(DepsRoot)\include\pango-1.0;$(DepsRoot)\include\gdk-pixbuf-2.0</Gtk>

-		<DepLibs>gtk-win32-2.0.lib;gdk-win32-2.0.lib;atk-1.0.lib;gio-2.0.lib;gdk_pixbuf-2.0.lib;pangowin32-1.0.lib;pangocairo-1.0.lib;pango-1.0.lib;cairo.lib;gobject-2.0.lib;gmodule-2.0.lib;glib-2.0.lib;intl.lib;libxml2.lib;libeay32.lib;ssleay32.lib;wininet.lib;winmm.lib;ws2_32.lib</DepLibs>

+		<DepLibs>gtk-win32-2.0.lib;gdk-win32-2.0.lib;atk-1.0.lib;gio-2.0.lib;gdk_pixbuf-2.0.lib;pangowin32-1.0.lib;pangocairo-1.0.lib;pango-1.0.lib;cairo.lib;gobject-2.0.lib;gmodule-2.0.lib;glib-2.0.lib;intl.lib;libxml2.lib;libcrypto.lib;libssl.lib;ssleay32.lib;wininet.lib;winmm.lib;ws2_32.lib</DepLibs>

 		<DataDir>$(SolutionDir)..\data\\</DataDir>

 		<HexChatBuild>$(SolutionDir)..\..\hexchat-build</HexChatBuild>

 		<HexChatBin>$(HexChatBuild)\$(PlatformName)\bin\</HexChatBin>

diff --git a/win32/installer/hexchat.iss.tt b/win32/installer/hexchat.iss.tt
index be985384..1671988d 100644
--- a/win32/installer/hexchat.iss.tt
+++ b/win32/installer/hexchat.iss.tt
@@ -138,7 +138,13 @@ Source: "gspawn-win32-helper-console.exe"; DestDir: "{app}"; Flags: ignoreversio
 Source: "gthread-2.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
 Source: "gtk-win32-2.0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
 Source: "iconv.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
-Source: "libeay32.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
+#if APPARCH == "x64"
+Source: "libcrypto-1_1-x64.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
+Source: "libssl-1_1-x64.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
+#else
+Source: "libcrypto-1_1.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
+Source: "libssl-1_1.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
+#endif
 Source: "libenchant.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
 Source: "ffi-7.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
 Source: "intl.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
@@ -148,7 +154,6 @@ Source: "pango-1.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: l
 Source: "pangocairo-1.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
 Source: "pangoft2-1.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
 Source: "pangowin32-1.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
-Source: "ssleay32.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
 Source: "zlib1.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
 
 Source: "plugins\hcnotifications-winrt.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: libs