diff options
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)", ¬ification_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 (¶ms, G_VARIANT_TYPE ("(susssasa{sv}i)")); + g_variant_builder_add (¶ms, "s", "hexchat"); /* App name */ + g_variant_builder_add (¶ms, "u", 0); /* ID, 0 means don't replace */ + g_variant_builder_add (¶ms, "s", "io.github.Hexchat"); /* App icon */ + g_variant_builder_add (¶ms, "s", title); + g_variant_builder_add (¶ms, "s", text); + g_variant_builder_add (¶ms, "as", NULL); /* Actions */ + + /* Hints */ + g_variant_builder_open (¶ms, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_open (¶ms, G_VARIANT_TYPE ("{sv}")); + g_variant_builder_add (¶ms, "s", "desktop-entry"); + g_variant_builder_add (¶ms, "v", g_variant_new_string ("io.github.Hexchat")); + g_variant_builder_close (¶ms); + g_variant_builder_close (¶ms); + + g_variant_builder_add (¶ms, "i", -1); /* Expiration */ + + g_dbus_proxy_call (fdo_notifications, + "Notify", + g_variant_builder_end (¶ms), + 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 |