6 Commits

58 changed files with 682 additions and 2114 deletions

View File

@@ -86,21 +86,11 @@ jobs:
cp -a /usr/lib/x86_64-linux-gnu/python3/dist-packages AppDir/usr/lib/x86_64-linux-gnu/python3/
fi
if [ -d "/usr/lib/x86_64-linux-gnu/perl-base" ]; then
install -d AppDir/usr/lib/x86_64-linux-gnu
cp -a /usr/lib/x86_64-linux-gnu/perl-base AppDir/usr/lib/x86_64-linux-gnu/
fi
if [ -d "/usr/lib/x86_64-linux-gnu/perl" ]; then
install -d AppDir/usr/lib/x86_64-linux-gnu
cp -a /usr/lib/x86_64-linux-gnu/perl AppDir/usr/lib/x86_64-linux-gnu/
fi
if [ -d "/usr/lib/x86_64-linux-gnu/perl5" ]; then
install -d AppDir/usr/lib/x86_64-linux-gnu
cp -a /usr/lib/x86_64-linux-gnu/perl5 AppDir/usr/lib/x86_64-linux-gnu/
fi
if [ -d "/usr/share/perl" ]; then
install -d AppDir/usr/share
cp -a /usr/share/perl AppDir/usr/share/
@@ -110,10 +100,6 @@ jobs:
install -d AppDir/usr/share
cp -a /usr/share/perl5 AppDir/usr/share/
fi
perl -MFile::Spec -e 'print "Build host File::Spec: $INC{\"File/Spec.pm\"}\n"'
find AppDir/usr -path '*/File/Spec.pm' -print -quit | grep -q .
if compgen -G '/usr/lib/x86_64-linux-gnu/libpython3*.so*' > /dev/null; then
install -d AppDir/usr/lib/x86_64-linux-gnu
cp -a /usr/lib/x86_64-linux-gnu/libpython3*.so* AppDir/usr/lib/x86_64-linux-gnu/
@@ -176,7 +162,7 @@ jobs:
APPDIR="${APPDIR:-$(dirname "$(readlink -f "$0")")}"
export PATH="$APPDIR/usr/bin:${PATH:-/usr/bin:/bin}"
export PATH="${PATH:-/usr/bin:/bin}:$APPDIR/usr/bin"
export LD_LIBRARY_PATH="$APPDIR/usr/lib:$APPDIR/usr/lib/x86_64-linux-gnu:${LD_LIBRARY_PATH:-}"
export XDG_DATA_DIRS="$APPDIR/usr/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
export GTK_EXE_PREFIX="$APPDIR/usr"
@@ -225,23 +211,6 @@ jobs:
unset GTK_MODULES
perl5lib_entries=""
for dir in \
"$APPDIR/usr/lib/x86_64-linux-gnu/perl-base" \
"$APPDIR/usr/lib/x86_64-linux-gnu/perl"/* \
"$APPDIR/usr/lib/x86_64-linux-gnu/perl5"/* \
"$APPDIR/usr/share/perl"/* \
"$APPDIR/usr/share/perl5"
do
if [ -d "$dir" ]; then
perl5lib_entries="${perl5lib_entries:+$perl5lib_entries:}$dir"
fi
done
if [ -n "$perl5lib_entries" ]; then
export PERL5LIB="$perl5lib_entries${PERL5LIB:+:$PERL5LIB}"
fi
export PYTHONHOME="$APPDIR/usr"
python_stdlib_dir="$(find "$APPDIR/usr/lib" -maxdepth 1 -type d -name 'python3.*' | head -n 1 || true)"
pythonpath_entries=""
@@ -287,12 +256,13 @@ jobs:
EOF
chmod +x AppRun
VERSION="$(git describe --tags --always)"
./linuxdeploy-x86_64.AppImage \
--appdir AppDir \
--desktop-file AppDir/usr/share/applications/net.zoite.Zoitechat.desktop \
--icon-file AppDir/usr/share/icons/hicolor/48x48/apps/net.zoite.Zoitechat.png \
--desktop-file AppDir/usr/share/applications/org.zoitechat.ZoiteChat.desktop \
--icon-file AppDir/usr/share/icons/hicolor/48x48/apps/org.zoitechat.ZoiteChat.png \
--custom-apprun ./AppRun \
--plugin gtk \
--output appimage

View File

@@ -33,7 +33,7 @@ jobs:
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
with:
bundle: zoitechat.flatpak
manifest-path: flatpak/net.zoite.Zoitechat.json
manifest-path: flatpak/org.zoitechat.ZoiteChat.json
cache: false
restore-cache: false

View File

@@ -1,11 +1,11 @@
icondir = join_paths(get_option('datadir'), 'icons/hicolor')
install_data(
'zoitechat.png',
rename: 'net.zoite.Zoitechat.png',
rename: 'org.zoitechat.ZoiteChat.png',
install_dir: join_paths(icondir, '48x48/apps')
)
install_data(
'zoitechat.svg',
rename: 'net.zoite.Zoitechat.svg',
rename: 'org.zoitechat.ZoiteChat.svg',
install_dir: join_paths(icondir, 'scalable/apps')
)

View File

@@ -6,8 +6,8 @@ desktop_utils = find_program('desktop-file-validate', required: false)
if get_option('gtk-frontend')
if get_option('install-appdata')
zoitechat_appdata = i18n.merge_file(
input: 'net.zoite.Zoitechat.appdata.xml.in',
output: 'net.zoite.Zoitechat.appdata.xml',
input: 'org.zoitechat.ZoiteChat.metainfo.xml.in',
output: 'org.zoitechat.ZoiteChat.metainfo.xml',
po_dir: '../../po',
install: true,
install_dir: metainfodir
@@ -15,7 +15,7 @@ if get_option('gtk-frontend')
appstreamcli = find_program('appstreamcli', required: false)
if appstreamcli.found()
test('Validate net.zoite.Zoitechat.appdata.xml', appstreamcli,
test('Validate org.zoitechat.ZoiteChat.metainfo.xml', appstreamcli,
args: ['validate', zoitechat_appdata]
)
endif
@@ -29,14 +29,14 @@ if get_option('gtk-frontend')
endif
desktop_file = configure_file(
input: 'net.zoite.Zoitechat.desktop.in.in',
output: 'net.zoite.Zoitechat.desktop.in',
input: 'org.zoitechat.ZoiteChat.desktop.in.in',
output: 'org.zoitechat.ZoiteChat.desktop.in',
configuration: desktop_conf
)
zoitechat_desktop = i18n.merge_file(
input: desktop_file,
output: 'net.zoite.Zoitechat.desktop',
output: 'org.zoitechat.ZoiteChat.desktop',
po_dir: '../../po',
type: 'desktop',
install: true,
@@ -44,7 +44,7 @@ if get_option('gtk-frontend')
)
if desktop_utils.found()
test('Validate net.zoite.Zoitechat.desktop', desktop_utils,
test('Validate org.zoitechat.ZoiteChat.desktop', desktop_utils,
args: [zoitechat_desktop]
)
endif
@@ -98,14 +98,14 @@ if get_option('plugin')
conf.set('LICENSE', metainfo[2])
plugin_appdata = configure_file(
input: 'net.zoite.Zoitechat.Plugin.metainfo.xml.in',
output: 'net.zoite.Zoitechat.Plugin.@0@.metainfo.xml'.format(name),
input: 'org.zoitechat.ZoiteChat.Plugin.metainfo.xml.in',
output: 'org.zoitechat.ZoiteChat.Plugin.@0@.metainfo.xml'.format(name),
configuration: conf,
install_dir: get_option('install-plugin-metainfo') ? metainfodir : '',
)
if appstreamcli.found()
test('Validate net.zoite.Zoitechat.Plugin.@0@.metainfo.xml'.format(name), appstreamcli,
test('Validate org.zoitechat.ZoiteChat.Plugin.@0@.metainfo.xml'.format(name), appstreamcli,
args: ['validate', plugin_appdata]
)
endif

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="addon">
<id>net.zoite.Zoitechat.Plugin.@NAME@</id>
<extends>net.zoite.Zoitechat</extends>
<id>org.zoitechat.ZoiteChat.Plugin.@NAME@</id>
<extends>org.zoitechat.ZoiteChat</extends>
<name>@NAME@ Plugin</name>
<summary>@SUMMARY@</summary>
<url type="homepage">https://zoitechat.org/</url>

View File

@@ -4,12 +4,12 @@ GenericName=IRC Client
Comment=Chat with other people online
Keywords=IM;Chat;
Exec=@exec_command@
Icon=net.zoite.Zoitechat
Icon=org.zoitechat.ZoiteChat
Terminal=false
Type=Application
Categories=GTK;Network;IRCClient;
StartupNotify=true
StartupWMClass=net.zoite.Zoitechat
StartupWMClass=org.zoitechat.ZoiteChat
X-GNOME-UsesNotifications=true
MimeType=x-scheme-handler/irc;x-scheme-handler/ircs;
Actions=SafeMode;

View File

@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>net.zoite.Zoitechat</id>
<id>org.zoitechat.ZoiteChat</id>
<name>ZoiteChat</name>
<launchable type="desktop-id">net.zoite.Zoitechat.desktop</launchable>
<launchable type="desktop-id">org.zoitechat.ZoiteChat.desktop</launchable>
<developer id="net.zoite">
<developer id="org.zoitechat">
<name translate="no">ZoiteChat</name>
</developer>
@@ -26,7 +26,7 @@
</screenshot>
</screenshots>
<provides>
<id>zoitechat.desktop</id>
<id>org.zoitechat.ZoiteChat.desktop</id>
</provides>
<releases>
<release date="2026-05-21" version="2.18.1">
@@ -339,7 +339,7 @@
<description>
<p>This is largely a bug fix release though it has some large behind the scenes changes:</p>
<ul>
<li>Rename data files to use *net.zoite.Zoitechat* name</li>
<li>Rename data files to use *org.zoitechat.ZoiteChat* name</li>
<li>Add option (irc_reconnect_rejoin) to disable auto-rejoin on reconnect</li>
<li>Add ability to set custom tray icon separate of app icon</li>
<li>Fix Enchant 2.0+ support</li>

View File

@@ -1,25 +1,17 @@
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/zoitechat/plugins", "*.so", plugin_auto_load_cb);
@@ -470,7 +470,14 @@
if (libdir && *libdir)
return libdir;
else
+ {
+ if (g_file_test ("/app/extensions/lib/zoitechat/plugins", G_FILE_TEST_IS_DIR))
+ {
+ return "/app/extensions/lib/zoitechat/plugins";
+ }
+
#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
return ZOITECHATLIBDIR;
+ }
}
void

View File

@@ -1,82 +0,0 @@
{
"app-id": "net.zoite.Zoitechat",
"branch": "master",
"runtime": "org.gnome.Platform",
"runtime-version": "49",
"sdk": "org.gnome.Sdk",
"command": "zoitechat",
"finish-args": [
"--share=ipc",
"--socket=wayland",
"--socket=fallback-x11",
"--share=network",
"--socket=pulseaudio",
"--filesystem=xdg-download",
"--filesystem=xdg-data/themes:ro",
"--filesystem=xdg-data/icons:ro",
"--filesystem=xdg-run/tray-icon:create",
"--env=GTK_CSD=1",
"--talk-name=org.freedesktop.Notifications",
"--talk-name=org.kde.StatusNotifierWatcher",
"--talk-name=com.canonical.AppMenu.Registrar",
"--talk-name=org.mpris.MediaPlayer2.*"
],
"add-extensions": {
"net.zoite.Zoitechat.Plugin": {
"version": "49",
"directory": "extensions",
"add-ld-path": "lib",
"merge-dirs": "lib/zoitechat/plugins",
"subdirectories": true,
"no-autodownload": true,
"autodelete": true
}
},
"modules": [
"shared-modules/lua5.4/lua-5.4.json",
"shared-modules/libcanberra/libcanberra.json",
"shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json",
"python3-cffi.json",
"perl.json",
{
"name": "lgi",
"buildsystem": "meson",
"sources": [
{
"type": "archive",
"url": "https://github.com/pavouk/lgi/archive/c9b8e4473c6421f2a215d8c06c0d94b86eb0b26a.tar.gz",
"sha256": "db67b2b7ee89fa566f783486d56be7203552a997bc55f35020b57dd2776b9943"
}
]
},
{
"name": "zoitechat",
"buildsystem": "meson",
"config-opts": [
"-Ddbus-service-use-appid=true",
"-Dwith-perl=perl",
"-Dwith-python=python3",
"-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"
}
]
}
]
}

View File

@@ -0,0 +1,127 @@
{
"app-id": "org.zoitechat.ZoiteChat",
"runtime": "org.gnome.Platform",
"runtime-version": "50",
"sdk": "org.gnome.Sdk",
"command": "zoitechat",
"finish-args": [
"--share=ipc",
"--socket=wayland",
"--socket=fallback-x11",
"--share=network",
"--socket=pulseaudio",
"--filesystem=xdg-download",
"--filesystem=xdg-run/tray-icon:create",
"--env=GTK_CSD=1",
"--talk-name=org.freedesktop.Notifications",
"--talk-name=org.kde.StatusNotifierWatcher",
"--talk-name=com.canonical.AppMenu.Registrar"
],
"add-extensions": {
"org.zoitechat.ZoiteChat.Plugin": {
"version": "50",
"directory": "extensions",
"add-ld-path": "lib",
"merge-dirs": "lib/zoitechat/plugins",
"subdirectories": true,
"no-autodownload": true,
"autodelete": true
}
},
"modules": [
"shared-modules/lua5.4/lua-5.4.json",
"shared-modules/libcanberra/libcanberra.json",
"shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json",
{
"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/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz",
"sha256": "491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz",
"sha256": "1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"
}
]
},
{
"name": "perl",
"buildsystem": "simple",
"build-options": {
"no-debuginfo": true
},
"build-commands": [
"./Configure -des -Dprefix=/app -Dvendorprefix=/app -Duseshrplib -Dman1dir=none -Dman3dir=none",
"make -j${FLATPAK_BUILDER_N_JOBS}",
"make install"
],
"cleanup": [
"/share/man",
"/lib/perl5/*/*/CORE/*.a"
],
"sources": [
{
"type": "archive",
"url": "https://www.cpan.org/src/5.0/perl-5.42.2.tar.xz",
"sha256": "0a585eeb9e363c0f80482ddb3571625250c2c86aeb408853e8ea50805cfb14bb"
}
]
},
{
"name": "lgi",
"buildsystem": "meson",
"sources": [
{
"type": "archive",
"url": "https://github.com/pavouk/lgi/archive/c9b8e4473c6421f2a215d8c06c0d94b86eb0b26a.tar.gz",
"sha256": "db67b2b7ee89fa566f783486d56be7203552a997bc55f35020b57dd2776b9943"
}
]
},
{
"name": "zoitechat",
"buildsystem": "meson",
"config-opts": [
"-Ddbus-service-use-appid=true",
"-Dwith-perl=perl",
"-Dwith-python=python3",
"-Dwith-lua=lua"
],
"build-options": {
"cflags": "-Wno-error=missing-include-dirs"
},
"cleanup": [
"/share/man"
],
"post-install": [
"install -d /app/extensions"
],
"sources": [
{
"type": "git",
"url": "https://github.com/ZoiteChat/zoitechat.git",
"tag": "zoitechat-2.18.1",
"commit": "479f1649efa0e5b166a7c7c9d86214b42ec9f794"
},
{
"type": "file",
"url": "https://publicsuffix.org/list/public_suffix_list.dat",
"sha256": "6f7f7d9e8c68447f1c74095a12574b7fee46b0cd759c518a659aee0615d8e118",
"dest": "src/common",
"dest-filename": "public_suffix_list.dat"
},
{
"type": "patch",
"path": "Load-plugins-from-Flatpak-extensions.patch"
}
]
}
]
}

View File

@@ -1,20 +0,0 @@
{
"name": "perl",
"buildsystem": "simple",
"build-commands": [
"./Configure -des -Dprefix=/app -Dvendorprefix=/app -Duseshrplib -Dman1dir=none -Dman3dir=none",
"make -j${FLATPAK_BUILDER_N_JOBS}",
"make install"
],
"cleanup": [
"/share/man",
"/lib/perl5/*/*/CORE/*.a"
],
"sources": [
{
"type": "archive",
"url": "https://www.cpan.org/src/5.0/perl-5.42.2.tar.xz",
"sha256": "0a585eeb9e363c0f80482ddb3571625250c2c86aeb408853e8ea50805cfb14bb"
}
]
}

View File

@@ -1,19 +0,0 @@
{
"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/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz",
"sha256": "491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz",
"sha256": "1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"
}
]
}

View File

@@ -19,7 +19,6 @@ libgmodule_dep = dependency('gmodule-2.0')
libcanberra_dep = dependency('libcanberra', version: '>= 0.22',
required: get_option('libcanberra'))
dbus_dep = dependency('gio-2.0', required: get_option('dbus'))
libsecret_dep = dependency('libsecret-1', required: false)
global_deps = []
if cc.get_id() == 'msvc'
@@ -41,7 +40,6 @@ config_h.set10('ENABLE_NLS', true)
config_h.set('USE_OPENSSL', libssl_dep.found())
config_h.set('USE_LIBCANBERRA', libcanberra_dep.found())
config_h.set('USE_DBUS', dbus_dep.found())
config_h.set('HAVE_LIBSECRET', libsecret_dep.found())
config_h.set('USE_PLUGIN', get_option('plugin'))
config_h.set('USE_GTK_FRONTEND', get_option('gtk-frontend'))

View File

@@ -91,13 +91,27 @@ static const signed char fish_unbase64[256] = {
#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
legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
default_provider = OSSL_PROVIDER_load(NULL, "default");
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;
}
@@ -115,6 +129,10 @@ void fish_deinit(void)
default_provider = NULL;
}
if (ossl_ctx) {
OSSL_LIB_CTX_free(ossl_ctx);
ossl_ctx = NULL;
}
#endif
}
@@ -260,9 +278,7 @@ char *fish_cipher(const char *plaintext, size_t plaintext_len, const char *key,
}
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
cipher = EVP_CIPHER_fetch(NULL, "BF-CBC", NULL);
if (!cipher)
cipher = (EVP_CIPHER *) EVP_bf_cbc();
cipher = EVP_CIPHER_fetch(ossl_ctx, "BF-CBC", NULL);
#else
cipher = (EVP_CIPHER *) EVP_bf_cbc();
#endif
@@ -270,9 +286,7 @@ char *fish_cipher(const char *plaintext, size_t plaintext_len, const char *key,
} else if (mode == EVP_CIPH_ECB_MODE) {
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
cipher = EVP_CIPHER_fetch(NULL, "BF-ECB", NULL);
if (!cipher)
cipher = (EVP_CIPHER *) EVP_bf_ecb();
cipher = EVP_CIPHER_fetch(ossl_ctx, "BF-ECB", NULL);
#else
cipher = (EVP_CIPHER *) EVP_bf_ecb();
#endif

View File

@@ -421,7 +421,7 @@ static int handle_keyx_notice(char *word[], char *word_eol[], void *userdata) {
zoitechat_commandf(ph, "quote NOTICE %s :DH1080_FINISH %s%s", sender, pub_key, (mode == FISH_CBC_MODE) ? " CBC" : "");
g_free(pub_key);
} else {
zoitechat_printf(ph, "Failed to generate keys");
zoitechat_print(ph, "Failed to generate keys");
goto cleanup;
}
} else if (!strcmp (dh_message, "DH1080_FINISH")) {
@@ -446,7 +446,7 @@ static int handle_keyx_notice(char *word[], char *word_eol[], void *userdata) {
zoitechat_printf(ph, "Stored new key for %s (%s)", sender, fish_modes[mode]);
g_free(secret_key);
} else {
zoitechat_printf(ph, "Failed to create secret key!");
zoitechat_print(ph, "Failed to create secret key!");
}
cleanup:
@@ -548,7 +548,7 @@ static int handle_keyx(char *word[], char *word_eol[], void *userdata) {
}
if ((query_ctx && ctx_type != 3) || (!query_ctx && !irc_is_query(target))) {
zoitechat_printf(ph, "You can only exchange keys with individuals");
zoitechat_print(ph, "You can only exchange keys with individuals");
return ZOITECHAT_EAT_ALL;
}
@@ -560,7 +560,7 @@ static int handle_keyx(char *word[], char *word_eol[], void *userdata) {
g_free(pub_key);
} else {
zoitechat_printf(ph, "Failed to generate keys");
zoitechat_print(ph, "Failed to generate keys");
}
return ZOITECHAT_EAT_ALL;
@@ -577,7 +577,7 @@ static int handle_crypt_topic(char *word[], char *word_eol[], void *userdata) {
GSList *encrypted_list;
if (!*topic) {
zoitechat_printf(ph, "%s", usage_topic);
zoitechat_print(ph, usage_topic);
return ZOITECHAT_EAT_ALL;
}
@@ -624,7 +624,7 @@ static int handle_crypt_notice(char *word[], char *word_eol[], void *userdata) {
GSList *encrypted_list, *encrypted_item;
if (!*target || !*notice) {
zoitechat_printf(ph, "%s", usage_notice);
zoitechat_print(ph, usage_notice);
return ZOITECHAT_EAT_ALL;
}
@@ -676,7 +676,7 @@ static int handle_crypt_msg(char *word[], char *word_eol[], void *userdata) {
GSList *encrypted_list, *encrypted_item;
if (!*target || !*message) {
zoitechat_printf(ph, "%s", usage_msg);
zoitechat_print(ph, usage_msg);
return ZOITECHAT_EAT_ALL;
}
@@ -805,15 +805,11 @@ int zoitechat_plugin_init(zoitechat_plugin *plugin_handle,
zoitechat_hook_server_attrs(ph, "TOPIC", ZOITECHAT_PRI_NORM, handle_incoming, NULL);
zoitechat_hook_server_attrs(ph, "332", ZOITECHAT_PRI_NORM, handle_incoming, NULL);
if (!fish_init()) {
zoitechat_printf(ph, "FiSHLiM failed to initialize crypto backend");
if (!fish_init())
return 0;
}
if (!dh1080_init()) {
zoitechat_printf(ph, "FiSHLiM failed to initialize DH1080");
if (!dh1080_init())
return 0;
}
pending_exchanges = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);

View File

@@ -31,19 +31,12 @@
<br />
ZoiteChat is a GTK3 IRC client based on HexChat, available for Windows and UNIX-like operating systems.
Features include HexChat-compatible Python, Perl and Lua scripting support, a plugin API,
multiple server/channel windows, spell checking, multiple authentication methods including SASL,
and customizable notifications.
ZoiteChat is an HexChat based IRC client for Windows and UNIX-like operating systems.
See [IRCHelp.org](http://irchelp.org) for information about IRC in general.
For more information on ZoiteChat please read our [documentation](https://docs.zoitechat.org/):
- [Downloads](https://zoitechat.org/download)
For more information on ZoiteChat:
- [Main Documentation](https://docs.zoitechat.org/) and [FAQ](https://docs.zoitechat.org/en/latest/faq.html)
- [Downloads](https://zoitechat.org/download.php)
- [Troubleshooting](troubleshooting.md)
---

View File

@@ -447,7 +447,6 @@ const struct prefs vars[] =
{"gui_tab_layout", P_OFFINT (hex_gui_tab_layout), TYPE_INT},
{"gui_tab_closebuttons", P_OFFINT (hex_gui_tab_closebuttons), TYPE_BOOL},
{"gui_tab_middleclose", P_OFFINT (hex_gui_tab_middleclose), TYPE_BOOL},
{"gui_mouse_scroll_speed", P_OFFINT (hex_gui_mouse_scroll_speed), TYPE_INT},
{"gui_tab_newtofront", P_OFFINT (hex_gui_tab_newtofront), TYPE_INT},
{"gui_tab_pos", P_OFFINT (hex_gui_tab_pos), TYPE_INT},
{"gui_tab_scrollchans", P_OFFINT (hex_gui_tab_scrollchans), TYPE_BOOL},
@@ -518,7 +517,6 @@ const struct prefs vars[] =
{"irc_conf_mode", P_OFFINT (hex_irc_conf_mode), TYPE_BOOL},
{"irc_extra_hilight", P_OFFSET (hex_irc_extra_hilight), TYPE_STR},
{"irc_hide_nickchange", P_OFFINT (hex_irc_hide_nickchange), TYPE_BOOL},
{"irc_hide_join_part_hostmask", P_OFFINT (hex_irc_hide_join_part_hostmask), TYPE_BOOL},
{"irc_hide_version", P_OFFINT (hex_irc_hide_version), TYPE_BOOL},
{"irc_hidehost", P_OFFINT (hex_irc_hidehost), TYPE_BOOL},
{"irc_id_ntext", P_OFFSET (hex_irc_id_ntext), TYPE_STR},
@@ -550,10 +548,6 @@ const struct prefs vars[] =
#endif
{"net_bind_host", P_OFFSET (hex_net_bind_host), TYPE_STR},
{"net_ping_timeout", P_OFFINT (hex_net_ping_timeout), TYPE_INT, zoitechat_reinit_timers},
{"net_lag_check", P_OFFINT (hex_net_lag_check), TYPE_INT, zoitechat_reinit_timers},
{"net_keepalive_idle", P_OFFINT (hex_net_keepalive_idle), TYPE_INT},
{"net_keepalive_interval", P_OFFINT (hex_net_keepalive_interval), TYPE_INT},
{"net_keepalive_count", P_OFFINT (hex_net_keepalive_count), TYPE_INT},
{"net_proxy_auth", P_OFFINT (hex_net_proxy_auth), TYPE_BOOL},
{"net_proxy_host", P_OFFSET (hex_net_proxy_host), TYPE_STR},
{"net_proxy_pass", P_OFFSET (hex_net_proxy_pass), TYPE_STR},
@@ -789,7 +783,6 @@ load_default_config(void)
prefs.hex_gui_tab_server = 1;
prefs.hex_gui_tab_sort = 1;
prefs.hex_gui_tab_scrollchans = 1;
prefs.hex_gui_mouse_scroll_speed = 10;
prefs.hex_gui_topicbar = 1;
prefs.hex_gui_transparency = 255;
prefs.hex_gui_tray = 1;
@@ -865,10 +858,6 @@ load_default_config(void)
prefs.hex_irc_ban_type = 1;
prefs.hex_irc_join_delay = 5;
prefs.hex_net_ping_timeout = 60;
prefs.hex_net_lag_check = 60;
prefs.hex_net_keepalive_idle = 60;
prefs.hex_net_keepalive_interval = 20;
prefs.hex_net_keepalive_count = 3;
prefs.hex_net_reconnect_delay = 10;
prefs.hex_notify_timeout = 15;
prefs.hex_text_max_indent = 256;

View File

@@ -32,7 +32,6 @@
<ClInclude Include="public_suffix_data.h" />
<ClInclude Include="server.h" />
<ClInclude Include="servlist.h" />
<ClInclude Include="secretstore.h" />
<ClInclude Include="ssl.h" />
<ClInclude Include="scram.h" />
<ClInclude Include="sysinfo\sysinfo.h" />
@@ -69,7 +68,6 @@
<ClCompile Include="proto-irc.c" />
<ClCompile Include="server.c" />
<ClCompile Include="servlist.c" />
<ClCompile Include="secretstore.c" />
<ClCompile Include="ssl.c" />
<ClCompile Include="scram.c" />
<ClCompile Include="sts.c" />

View File

@@ -74,9 +74,6 @@
<ClInclude Include="servlist.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="secretstore.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ssl.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -181,9 +178,6 @@
<ClCompile Include="servlist.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="secretstore.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ssl.c">
<Filter>Source Files</Filter>
</ClCompile>

View File

@@ -304,24 +304,29 @@ dcc_check_timeouts (void)
static int
dcc_lookup_proxy (char *host, struct sockaddr_in *addr)
{
struct hostent *h;
static char *cache_host = NULL;
static guint32 cache_addr;
/* too lazy to thread this, so we cache results */
if (cache_host)
{
if (strcmp (host, cache_host) == 0)
{
addr->sin_addr.s_addr = cache_addr;
memcpy (&addr->sin_addr, &cache_addr, 4);
return TRUE;
}
g_free (cache_host);
cache_host = NULL;
}
if (net_lookup_ipv4 (host, &addr->sin_addr.s_addr))
h = gethostbyname (host);
if (h != NULL && h->h_length == 4 && h->h_addr_list[0] != NULL)
{
cache_addr = addr->sin_addr.s_addr;
memcpy (&addr->sin_addr, h->h_addr_list[0], 4);
memcpy (&cache_addr, h->h_addr_list[0], 4);
cache_host = g_strdup (host);
/* cppcheck-suppress memleak */
return TRUE;
}
@@ -1609,14 +1614,25 @@ dcc_accept (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
}
guint32
dcc_get_my_address (session *sess)
dcc_get_my_address (session *sess) /* the address we'll tell the other person */
{
struct hostent *dns_query;
guint32 addr = 0;
if (prefs.hex_dcc_ip_from_server && sess->server->dcc_ip)
addr = sess->server->dcc_ip;
else if (prefs.hex_dcc_ip[0])
net_lookup_ipv4 ((const char *) prefs.hex_dcc_ip, &addr);
{
dns_query = gethostbyname ((const char *) prefs.hex_dcc_ip);
if (dns_query != NULL &&
dns_query->h_length == 4 &&
dns_query->h_addr_list[0] != NULL)
{
/*we're offered at least one IPv4 address: we take the first*/
addr = *((guint32*) dns_query->h_addr_list[0]);
}
}
return addr;
}

View File

@@ -38,7 +38,6 @@
#include "ignore.h"
#include "fe.h"
#include "modes.h"
#include "network.h"
#include "notify.h"
#include "outbound.h"
#include "inbound.h"
@@ -1477,13 +1476,14 @@ inbound_uback (server *serv, const message_tags_data *tags_data)
void
inbound_foundip (session *sess, char *ip, const message_tags_data *tags_data)
{
struct in_addr addr;
struct hostent *HostAddr;
if (net_lookup_ipv4 (ip, &addr.s_addr))
HostAddr = gethostbyname (ip);
if (HostAddr)
{
sess->server->dcc_ip = addr.s_addr;
sess->server->dcc_ip = ((struct in_addr *) HostAddr->h_addr_list[0])->s_addr;
EMIT_SIGNAL_TIMESTAMP (XP_TE_FOUNDIP, sess->server->server_session,
inet_ntoa (addr),
inet_ntoa (*((struct in_addr *) HostAddr->h_addr_list[0])),
NULL, NULL, NULL, 0, tags_data->timestamp);
}
}

View File

@@ -27,8 +27,6 @@ common_sources = [
'util.c'
]
secretstore_sources = files('secretstore.c')
common_sysinfo_deps = []
libarchive_dep = dependency('libarchive', required: host_machine.system() != 'windows')
@@ -40,9 +38,6 @@ common_deps = [
if libarchive_dep.found()
common_deps += libarchive_dep
endif
if libsecret_dep.found()
common_deps += libsecret_dep
endif
common_includes = [
config_h_include,
@@ -132,7 +127,7 @@ if get_option('plugin')
endif
zoitechat_common = static_library('zoitechatcommon',
sources: [textevents, public_suffix_data] + marshal + common_sources + secretstore_sources,
sources: [textevents, public_suffix_data] + marshal + common_sources,
include_directories: config_h_include,
dependencies: common_deps + common_sysinfo_deps,
c_args: common_cflags,

View File

@@ -34,9 +34,6 @@
#ifndef WIN32
#include <unistd.h>
#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif
#endif
#define WANTSOCKET
@@ -46,9 +43,6 @@
#define NETWORK_PRIVATE
#include "network.h"
#include "zoitechat.h"
extern struct zoitechatprefs prefs;
#define RAND_INT(n) ((int)(rand() / (RAND_MAX + 1.0) * (n)))
@@ -64,27 +58,6 @@ net_set_socket_options (int sok)
setsockopt (sok, SOL_SOCKET, SO_REUSEADDR, (char *) &sw, sizeof (sw));
sw = 1;
setsockopt (sok, SOL_SOCKET, SO_KEEPALIVE, (char *) &sw, sizeof (sw));
#ifdef TCP_KEEPIDLE
{
int keepidle = prefs.hex_net_keepalive_idle;
if (keepidle > 0)
setsockopt (sok, IPPROTO_TCP, TCP_KEEPIDLE, (char *) &keepidle, sizeof (keepidle));
}
#endif
#ifdef TCP_KEEPINTVL
{
int keepintvl = prefs.hex_net_keepalive_interval;
if (keepintvl > 0)
setsockopt (sok, IPPROTO_TCP, TCP_KEEPINTVL, (char *) &keepintvl, sizeof (keepintvl));
}
#endif
#ifdef TCP_KEEPCNT
{
int keepcnt = prefs.hex_net_keepalive_count;
if (keepcnt > 0)
setsockopt (sok, IPPROTO_TCP, TCP_KEEPCNT, (char *) &keepcnt, sizeof (keepcnt));
}
#endif
}
char *
@@ -96,30 +69,6 @@ net_ip (uint32_t addr)
return inet_ntoa (ia);
}
int
net_lookup_ipv4 (const char *hostname, uint32_t *addr)
{
struct addrinfo hints;
struct addrinfo *res;
struct sockaddr_in *sin;
int ret;
memset (&hints, 0, sizeof (hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_ADDRCONFIG;
ret = getaddrinfo (hostname, NULL, &hints, &res);
if (ret != 0)
return FALSE;
sin = (struct sockaddr_in *) res->ai_addr;
*addr = sin->sin_addr.s_addr;
freeaddrinfo (res);
return TRUE;
}
void
net_store_destroy (netstore * ns)
{

View File

@@ -39,7 +39,6 @@ int net_connect (netstore *ns, int sok4, int sok6, int *sok_return);
char *net_resolve (netstore *ns, char *hostname, int port, char **real_host);
void net_bind (netstore *tobindto, int sok4, int sok6);
char *net_ip (uint32_t addr);
int net_lookup_ipv4 (const char *hostname, uint32_t *addr);
void net_sockets (int *sok4, int *sok6);
#endif

View File

@@ -3462,45 +3462,28 @@ cmd_server (struct session *sess, char *tbuf, char *word[], char *word_eol[])
int use_ssl = FALSE;
#endif
int is_url = TRUE;
int no_proxy = FALSE;
server *serv = sess->server;
ircnet *net = NULL;
while (TRUE)
{
#ifdef USE_OPENSSL
if (g_strcmp0 (word[2 + offset], "-ssl") == 0 || g_strcmp0 (word[2 + offset], "-e") == 0)
{
use_ssl = TRUE;
use_ssl_noverify = FALSE;
offset++;
}
else if (g_strcmp0 (word[2 + offset], "-ssl-noverify") == 0)
{
use_ssl = TRUE;
use_ssl_noverify = TRUE;
offset++;
}
else if (g_strcmp0 (word[2 + offset], "-insecure") == 0)
{
use_ssl = FALSE;
use_ssl_noverify = FALSE;
offset++;
}
else
#endif
if (g_strcmp0 (word[2 + offset], "-noproxy") == 0)
{
no_proxy = TRUE;
offset++;
}
else
{
break;
}
/* BitchX uses -ssl, mIRC uses -e, let's support both */
if (g_strcmp0 (word[2], "-ssl") == 0 || g_strcmp0 (word[2], "-e") == 0)
{
use_ssl = TRUE;
offset++; /* args move up by 1 word */
}
serv->dont_use_proxy = no_proxy;
else if (g_strcmp0 (word[2], "-ssl-noverify") == 0)
{
use_ssl = TRUE;
use_ssl_noverify = TRUE;
offset++; /* args move up by 1 word */
}
else if (g_strcmp0 (word[2], "-insecure") == 0)
{
use_ssl = FALSE;
offset++; /* args move up by 1 word */
}
#endif
if (!parse_irc_url (word[2 + offset], &server_name, &port, &channel, &key, &use_ssl))
{
@@ -3601,18 +3584,10 @@ cmd_servchan (struct session *sess, char *tbuf, char *word[],
{
int offset = 0;
while (TRUE)
{
#ifdef USE_OPENSSL
if (g_strcmp0 (word[2 + offset], "-ssl") == 0 || g_strcmp0 (word[2 + offset], "-ssl-noverify") == 0 || g_strcmp0 (word[2 + offset], "-insecure") == 0)
offset++;
else
if (g_strcmp0 (word[2], "-ssl") == 0 || g_strcmp0 (word[2], "-ssl-noverify") == 0 || g_strcmp0 (word[2], "-insecure") == 0)
offset++;
#endif
if (g_strcmp0 (word[2 + offset], "-noproxy") == 0)
offset++;
else
break;
}
if (*word[4 + offset])
{
@@ -4144,17 +4119,17 @@ 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 [-noproxy] [-insecure|-ssl|-ssl-noverify] <host> <port> <channel>, connects and joins a channel using ssl unless otherwise specified")},
N_("SERVCHAN [-insecure|-ssl|-ssl-noverify] <host> <port> <channel>, connects and joins a channel using ssl unless otherwise specified")},
#else
{"SERVCHAN", cmd_servchan, 0, 0, 1,
N_("SERVCHAN [-noproxy] <host> <port> <channel>, connects and joins a channel")},
N_("SERVCHAN <host> <port> <channel>, connects and joins a channel")},
#endif
#ifdef USE_OPENSSL
{"SERVER", cmd_server, 0, 0, 1,
N_("SERVER [-noproxy] [-insecure|-ssl|-ssl-noverify] <host> [<port>] [<password>], connects to a server using ssl unless otherwise specified, the default port is 6697 for ssl connections and 6667 for insecure connections")},
N_("SERVER [-insecure|-ssl|-ssl-noverify] <host> [<port>] [<password>], connects to a server using ssl unless otherwise specified, the default port is 6697 for ssl connections and 6667 for insecure connections")},
#else
{"SERVER", cmd_server, 0, 0, 1,
N_("SERVER [-noproxy] <host> [<port>] [<password>], connects to a server, the default port is 6667")},
N_("SERVER <host> [<port>] [<password>], connects to a server, the default port is 6667")},
#endif
{"SET", cmd_set, 0, 0, 1, N_("SET [-e] [-off|-on] [-quiet] <variable> [<value>]")},
{"SETCURSOR", cmd_setcursor, 0, 0, 1, N_("SETCURSOR [-|+]<position>, reposition the cursor in the inputbox")},

View File

@@ -1213,6 +1213,8 @@ zoitechat_get_info (zoitechat_plugin *ph, const char *id)
case 0x4889ba9b: /* password */
case 0x438fdf9: /* nickserv */
if (sess->server->network)
return ((ircnet *)sess->server->network)->pass;
return NULL;
case 0xca022f43: /* server */

View File

@@ -1,173 +0,0 @@
#include "zoitechat.h"
#include "cfgfiles.h"
#include "secretstore.h"
#include <string.h>
#ifdef WIN32
#include <windows.h>
#include <wincred.h>
#endif
#ifdef HAVE_LIBSECRET
#include <libsecret/secret.h>
#endif
static char *secretstore_target (const char *network_name)
{
return g_strdup_printf ("zoitechat/network/%s", network_name ? network_name : "default");
}
int secretstore_is_keyring_available (void)
{
#ifdef WIN32
return TRUE;
#elif defined(HAVE_LIBSECRET)
return TRUE;
#else
return FALSE;
#endif
}
char *secretstore_get_network_password (const char *network_name)
{
char *target;
target = secretstore_target (network_name);
#ifdef WIN32
{
PCREDENTIALA cred = NULL;
char *ret = NULL;
if (CredReadA (target, CRED_TYPE_GENERIC, 0, &cred))
{
ret = g_strndup ((const char *) cred->CredentialBlob, cred->CredentialBlobSize);
CredFree (cred);
}
g_free (target);
return ret;
}
#elif defined(HAVE_LIBSECRET)
{
static const SecretSchema schema = {
"net.zoite.ZoiteChat.Network", SECRET_SCHEMA_NONE,
{
{ "network", SECRET_SCHEMA_ATTRIBUTE_STRING },
{ NULL, 0 },
}
};
char *ret = secret_password_lookup_sync (&schema, NULL, NULL, "network", target, NULL);
g_free (target);
return ret;
}
#else
g_free (target);
return NULL;
#endif
}
int secretstore_set_network_password (const char *network_name, const char *password)
{
char *target;
target = secretstore_target (network_name);
#ifdef WIN32
{
CREDENTIALA cred;
memset (&cred, 0, sizeof (cred));
cred.Type = CRED_TYPE_GENERIC;
cred.TargetName = target;
cred.CredentialBlobSize = (DWORD) strlen (password);
cred.CredentialBlob = (LPBYTE) password;
cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
cred.UserName = "zoitechat";
if (!CredWriteA (&cred, 0))
{
g_free (target);
return FALSE;
}
g_free (target);
return TRUE;
}
#elif defined(HAVE_LIBSECRET)
{
static const SecretSchema schema = {
"net.zoite.ZoiteChat.Network", SECRET_SCHEMA_NONE,
{
{ "network", SECRET_SCHEMA_ATTRIBUTE_STRING },
{ NULL, 0 },
}
};
gboolean ok = secret_password_store_sync (&schema, SECRET_COLLECTION_DEFAULT,
"ZoiteChat network password", password, NULL, NULL, "network", target, NULL);
g_free (target);
return ok;
}
#else
g_free (target);
return FALSE;
#endif
}
int secretstore_delete_network_password (const char *network_name)
{
char *target;
target = secretstore_target (network_name);
#ifdef WIN32
{
gboolean ok = CredDeleteA (target, CRED_TYPE_GENERIC, 0);
g_free (target);
return ok;
}
#elif defined(HAVE_LIBSECRET)
{
static const SecretSchema schema = {
"net.zoite.ZoiteChat.Network", SECRET_SCHEMA_NONE,
{
{ "network", SECRET_SCHEMA_ATTRIBUTE_STRING },
{ NULL, 0 },
}
};
gboolean ok = secret_password_clear_sync (&schema, NULL, NULL, "network", target, NULL);
g_free (target);
return ok;
}
#else
g_free (target);
return FALSE;
#endif
}
int secretstore_require_unlock (const char *network_name)
{
#ifdef WIN32
return TRUE;
#elif defined(HAVE_LIBSECRET)
{
static const SecretSchema schema = {
"net.zoite.ZoiteChat.Network", SECRET_SCHEMA_NONE,
{
{ "network", SECRET_SCHEMA_ATTRIBUTE_STRING },
{ NULL, 0 },
}
};
char *target;
char *password;
GError *error = NULL;
target = secretstore_target (network_name);
password = secret_password_lookup_sync (&schema, NULL, &error, "network", target, NULL);
g_free (target);
if (password)
{
memset (password, 0, strlen (password));
g_free (password);
return TRUE;
}
if (error)
{
g_error_free (error);
return FALSE;
}
return TRUE;
}
#else
return TRUE;
#endif
}

View File

@@ -1,10 +0,0 @@
#ifndef ZOITECHAT_SECRETSTORE_H
#define ZOITECHAT_SECRETSTORE_H
char *secretstore_get_network_password (const char *network_name);
int secretstore_set_network_password (const char *network_name, const char *password);
int secretstore_delete_network_password (const char *network_name);
int secretstore_is_keyring_available (void);
int secretstore_require_unlock (const char *network_name);
#endif

View File

@@ -522,7 +522,7 @@ ssl_cb_verify (int ok, X509_STORE_CTX * ctx)
X509 *current_cert = X509_STORE_CTX_get_current_cert (ctx);
if (!current_cert)
return ok;
return TRUE;
X509_NAME_oneline (X509_get_subject_name (current_cert),
subject, sizeof (subject));
@@ -534,21 +534,13 @@ ssl_cb_verify (int ok, X509_STORE_CTX * ctx)
g_snprintf (buf, sizeof (buf), "* Issuer: %s", issuer);
EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
if (!ok)
{
int err = X509_STORE_CTX_get_error (ctx);
g_snprintf (buf, sizeof (buf), "* Verify E: %s (%d)",
X509_verify_cert_error_string (err), err);
EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
}
return ok;
return TRUE;
}
static int
ssl_do_connect (server * serv)
{
char buf[256];
char buf[256]; // ERR_error_string() MUST have this size
g_sess = serv->server_session;
@@ -567,10 +559,9 @@ ssl_do_connect (server * serv)
if (SSL_connect (serv->ssl) <= 0)
{
char err_buf[128];
int err, ssl_err;
int err;
g_sess = NULL;
ssl_err = SSL_get_error (serv->ssl, -1);
if ((err = ERR_get_error ()) > 0)
{
ERR_error_string (err, err_buf);
@@ -580,8 +571,6 @@ ssl_do_connect (server * serv)
if (ERR_GET_REASON (err) == SSL_R_WRONG_VERSION_NUMBER)
PrintText (serv->server_session, _("Are you sure this is a SSL capable server and port?\n"));
else if (ssl_err == SSL_ERROR_SSL)
EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, "* TLS handshake rejected by protocol/certificate/cipher policy", NULL, NULL, NULL, 0);
server_cleanup (serv);
@@ -660,13 +649,29 @@ ssl_do_connect (server * serv)
int hostname_err;
if ((hostname_err = _SSL_check_hostname(cert, serv->hostname)) != 0)
{
g_snprintf (buf, sizeof (buf), "* Verify E: Failed to validate hostname (%d)",
hostname_err);
EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL, 0);
goto conn_fail;
g_snprintf (buf, sizeof (buf), "* Verify E: Failed to validate hostname? (%d)%s",
hostname_err, serv->accept_invalid_cert ? " -- Ignored" : "");
if (serv->accept_invalid_cert)
EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL, 0);
else
goto conn_fail;
}
break;
}
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
case X509_V_ERR_CERT_HAS_EXPIRED:
if (serv->accept_invalid_cert)
{
g_snprintf (buf, sizeof (buf), "* Verify E: %s.? (%d) -- Ignored",
X509_verify_cert_error_string (verify_error),
verify_error);
EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
NULL, 0);
break;
}
default:
g_snprintf (buf, sizeof (buf), "%s.? (%d)",
X509_verify_cert_error_string (verify_error),
@@ -876,7 +881,7 @@ server_read_child (GIOChannel *source, GIOCondition condition, server *serv)
if (prefs.hex_net_auto_reconnectonfail)
auto_reconnect (serv, FALSE, -1);
break;
case '3': /* resolver finished */
case '3': /* gethostbyname finished */
waitline2 (source, host, sizeof host);
waitline2 (source, ip, sizeof ip);
waitline2 (source, outbuf, sizeof outbuf);
@@ -927,7 +932,7 @@ server_read_child (GIOChannel *source, GIOCondition condition, server *serv)
waitline2 (source, tbuf, sizeof tbuf);
prefs.local_ip = inet_addr (tbuf);
break;
case '7': /* prefs.hex_net_bind_host resolve failed */
case '7': /* gethostbyname (prefs.hex_net_bind_host) failed */
sprintf (outbuf,
_("Cannot resolve hostname %s\nCheck your IP Settings!\n"),
prefs.hex_net_bind_host);

View File

@@ -33,152 +33,9 @@
#include "text.h"
#include "util.h" /* token_foreach */
#include "zoitechatc.h"
#include "secretstore.h"
#include "servlist.h"
#ifdef USE_OPENSSL
#include <openssl/evp.h>
#include <openssl/rand.h>
#endif
char *
servlist_password_encrypt_for_storage (const char *pass)
{
gchar *material;
unsigned char salt[16];
unsigned char iv[16];
unsigned char key[32];
unsigned char *ciphertext;
int outlen1;
int outlen2;
int inlen;
int cipherlen;
EVP_CIPHER_CTX *ctx;
char *b64;
char *ret;
if (!pass || !*pass)
return NULL;
#ifdef USE_OPENSSL
if (RAND_bytes (salt, sizeof (salt)) != 1 || RAND_bytes (iv, sizeof (iv)) != 1)
return NULL;
material = g_strdup_printf ("%s|%s", g_get_user_name (), get_xdir ());
if (!PKCS5_PBKDF2_HMAC (material, -1, salt, sizeof (salt), 300000, EVP_sha256 (), sizeof (key), key))
{
g_free (material);
return NULL;
}
g_free (material);
inlen = (int) strlen (pass);
ciphertext = g_malloc (inlen + EVP_MAX_BLOCK_LENGTH);
ctx = EVP_CIPHER_CTX_new ();
if (!ctx)
{
memset (key, 0, sizeof (key));
g_free (ciphertext);
return NULL;
}
if (EVP_EncryptInit_ex (ctx, EVP_aes_256_cbc (), NULL, key, iv) != 1 ||
EVP_EncryptUpdate (ctx, ciphertext, &outlen1, (const unsigned char *) pass, inlen) != 1 ||
EVP_EncryptFinal_ex (ctx, ciphertext + outlen1, &outlen2) != 1)
{
EVP_CIPHER_CTX_free (ctx);
memset (key, 0, sizeof (key));
g_free (ciphertext);
return NULL;
}
EVP_CIPHER_CTX_free (ctx);
cipherlen = outlen1 + outlen2;
{
gsize payload_len = sizeof (salt) + sizeof (iv) + (gsize) cipherlen;
unsigned char *payload = g_malloc (payload_len);
memcpy (payload, salt, sizeof (salt));
memcpy (payload + sizeof (salt), iv, sizeof (iv));
memcpy (payload + sizeof (salt) + sizeof (iv), ciphertext, cipherlen);
b64 = g_base64_encode (payload, payload_len);
memset (payload, 0, payload_len);
g_free (payload);
}
memset (key, 0, sizeof (key));
memset (ciphertext, 0, inlen + EVP_MAX_BLOCK_LENGTH);
g_free (ciphertext);
#else
b64 = g_base64_encode ((const guchar *) pass, strlen (pass));
#endif
ret = g_strdup_printf ("enc:%s", b64);
g_free (b64);
return ret;
}
gboolean
servlist_password_is_encrypted (const char *pass)
{
return pass && g_str_has_prefix (pass, "enc:");
}
char *
servlist_password_decrypt_for_storage (const char *enc)
{
guchar *raw;
gsize len;
char *ret;
if (!enc || !*enc)
return NULL;
if (!g_str_has_prefix (enc, "enc:"))
return g_strdup (enc);
raw = g_base64_decode (enc + 4, &len);
#ifdef USE_OPENSSL
if (len <= 32)
{
g_free (raw);
return NULL;
}
{
unsigned char *salt = raw;
unsigned char *iv = raw + 16;
unsigned char *ciphertext = raw + 32;
int cipherlen = (int) (len - 32);
unsigned char key[32];
gchar *material = g_strdup_printf ("%s|%s", g_get_user_name (), get_xdir ());
unsigned char *plaintext = g_malloc ((gsize) cipherlen + 1);
int outlen1;
int outlen2;
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
if (!ctx || !PKCS5_PBKDF2_HMAC (material, -1, salt, 16, 300000, EVP_sha256 (), sizeof (key), key))
{
g_free (material);
if (ctx)
EVP_CIPHER_CTX_free (ctx);
g_free (plaintext);
g_free (raw);
return NULL;
}
g_free (material);
if (EVP_DecryptInit_ex (ctx, EVP_aes_256_cbc (), NULL, key, iv) != 1 ||
EVP_DecryptUpdate (ctx, plaintext, &outlen1, ciphertext, cipherlen) != 1 ||
EVP_DecryptFinal_ex (ctx, plaintext + outlen1, &outlen2) != 1)
{
EVP_CIPHER_CTX_free (ctx);
memset (key, 0, sizeof (key));
memset (plaintext, 0, (gsize) cipherlen + 1);
g_free (plaintext);
g_free (raw);
return NULL;
}
EVP_CIPHER_CTX_free (ctx);
memset (key, 0, sizeof (key));
plaintext[outlen1 + outlen2] = 0;
ret = g_strdup ((const char *) plaintext);
memset (plaintext, 0, (gsize) cipherlen + 1);
g_free (plaintext);
}
#else
ret = g_strndup ((const char *) raw, len);
#endif
g_free (raw);
return ret;
}
struct defaultserver
{
@@ -487,29 +344,10 @@ servlist_connect (session *sess, ircnet *net, gboolean join)
}
serv->password[0] = 0;
if ((net->flags & FLAG_USE_KEYRING) && net->name)
if (net->pass)
{
char *stored_pass = secretstore_get_network_password (net->name);
if (stored_pass && *stored_pass)
{
safe_strcpy (serv->password, stored_pass, sizeof (serv->password));
}
if (stored_pass)
{
memset (stored_pass, 0, strlen (stored_pass));
g_free (stored_pass);
}
}
else if (net->pass)
{
char *plain = servlist_password_decrypt_for_storage (net->pass);
if (plain && *plain)
safe_strcpy (serv->password, plain, sizeof (serv->password));
if (plain)
{
memset (plain, 0, strlen (plain));
g_free (plain);
}
safe_strcpy (serv->password, net->pass, sizeof (serv->password));
}
if (net->flags & FLAG_USE_GLOBAL)
@@ -1144,6 +982,24 @@ servlist_load (void)
*
* Should be removed at some point.
*/
case 'A':
if (!net->pass)
{
net->pass = g_strdup (buf + 2);
if (!net->logintype)
{
net->logintype = LOGIN_SASL;
}
}
case 'B':
if (!net->pass)
{
net->pass = g_strdup (buf + 2);
if (!net->logintype)
{
net->logintype = LOGIN_NICKSERV;
}
}
}
}
if (buf[0] == 'N')

View File

@@ -62,8 +62,7 @@ extern GSList *network_list;
#define FLAG_USE_PROXY 16
#define FLAG_ALLOW_INVALID 32
#define FLAG_FAVORITE 64
#define FLAG_USE_KEYRING 128
#define FLAG_COUNT 8
#define FLAG_COUNT 7
/* Login methods. Use server password by default - if we had a NickServ password, it'd be set to 2 already by servlist_load() */
#define LOGIN_DEFAULT_REAL LOGIN_PASS /* this is to set the default login method for unknown servers */
@@ -125,8 +124,5 @@ favchannel *servlist_favchan_copy (favchannel *fav);
GSList *servlist_favchan_listadd (GSList *chanlist, char *channel, char *key);
gboolean joinlist_is_in_list (server *serv, char *channel);
char *servlist_password_encrypt_for_storage (const char *pass);
char *servlist_password_decrypt_for_storage (const char *pass);
gboolean servlist_password_is_encrypted (const char *pass);
#endif

View File

@@ -86,17 +86,15 @@ _SSL_context_init (void (*info_cb_func))
SSLeay_add_ssl_algorithms ();
SSL_load_error_strings ();
ctx = SSL_CTX_new (TLS_client_method ());
ctx = SSL_CTX_new (SSLv23_client_method ());
SSL_CTX_set_session_cache_mode (ctx, SSL_SESS_CACHE_BOTH);
SSL_CTX_set_timeout (ctx, 300);
SSL_CTX_set_options (ctx, SSL_OP_NO_COMPRESSION
SSL_CTX_set_options (ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3
|SSL_OP_NO_COMPRESSION
|SSL_OP_SINGLE_DH_USE|SSL_OP_SINGLE_ECDH_USE
|SSL_OP_NO_TICKET
|SSL_OP_NO_RENEGOTIATION);
SSL_CTX_set_min_proto_version (ctx, TLS1_2_VERSION);
SSL_CTX_set_cipher_list (ctx, "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!DSS");
SSL_CTX_set_ciphersuites (ctx, "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256");
|SSL_OP_CIPHER_SERVER_PREFERENCE);
#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined (OPENSSL_NO_COMP) /* workaround for OpenSSL 0.9.8 */
sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
@@ -313,7 +311,7 @@ _SSL_socket (SSL_CTX *ctx, int sd)
#else
method = SSL_CTX_get_ssl_method (ctx);
#endif
if (method == TLS_client_method())
if (method == SSLv23_client_method())
SSL_set_connect_state (ssl);
else
SSL_set_accept_state(ssl);

View File

@@ -1809,97 +1809,12 @@ format_event (session *sess, int index, char **args, char *o, gsize sizeofo, uns
o[0] = 0;
}
static char *
text_event_without_hostmask_format (const char *format, int host_arg)
{
char token[3];
const char *arg;
const char *open;
const char *close;
const char *start;
char *out;
gsize prefix_len;
g_snprintf (token, sizeof (token), "$%d", host_arg);
arg = strstr (format, token);
if (!arg)
return NULL;
open = arg;
while (open > format && *open != '(' && *open != '\n')
open--;
close = arg + strlen (token);
while (*close && *close != ')' && *close != '\n')
close++;
if (*open != '(' || *close != ')')
return NULL;
start = open;
if (start > format && start[-1] == ' ')
start--;
prefix_len = start - format;
out = g_malloc (prefix_len + strlen (close + 1) + 1);
memcpy (out, format, prefix_len);
strcpy (out + prefix_len, close + 1);
return out;
}
static void
display_event_string (session *sess, int event, char **args, char *format,
unsigned int stripcolor_args, time_t timestamp)
{
char *compiled;
char *saved;
char o[4096];
int max_arg;
if (pevt_build_string (format, &compiled, &max_arg) != 0)
return;
saved = pntevts[event];
pntevts[event] = compiled;
format_event (sess, event, args, o, sizeof (o), stripcolor_args);
pntevts[event] = saved;
g_free (compiled);
if (o[0])
PrintTextTimeStamp (sess, o, timestamp);
}
static void
display_event (session *sess, int event, char **args,
unsigned int stripcolor_args, time_t timestamp)
{
char o[4096];
char *format;
char *host;
int host_arg;
if (prefs.hex_irc_hide_join_part_hostmask &&
(event == XP_TE_JOIN || event == XP_TE_PART || event == XP_TE_PARTREASON))
{
host_arg = event == XP_TE_JOIN ? 3 : 2;
format = text_event_without_hostmask_format (pntevts_text[event], host_arg);
if (format)
{
display_event_string (sess, event, args, format, stripcolor_args, timestamp);
g_free (format);
return;
}
host = args[host_arg];
args[host_arg] = "";
format_event (sess, event, args, o, sizeof (o), stripcolor_args);
args[host_arg] = host;
}
else
{
format_event (sess, event, args, o, sizeof (o), stripcolor_args);
}
format_event (sess, event, args, o, sizeof (o), stripcolor_args);
if (o[0])
PrintTextTimeStamp (sess, o, timestamp);
}

View File

@@ -379,7 +379,6 @@ lag_check (void)
char tbuf[128];
time_t now = time (0);
time_t lag;
time_t ping_age;
tim = make_ping_time ();
@@ -389,7 +388,7 @@ lag_check (void)
if (serv->connected && serv->end_of_motd)
{
lag = now - serv->ping_recv;
if (serv->lag_sent && prefs.hex_net_ping_timeout != 0 && lag > prefs.hex_net_ping_timeout && lag > 0)
if (prefs.hex_net_ping_timeout != 0 && lag > prefs.hex_net_ping_timeout && lag > 0)
{
sprintf (tbuf, "%" G_GINT64_FORMAT, (gint64) lag);
EMIT_SIGNAL (XP_TE_PINGTIMEOUT, serv->server_session, tbuf, NULL,
@@ -399,11 +398,11 @@ lag_check (void)
}
else
{
ping_age = now - serv->ping_recv;
if (!serv->lag_sent && prefs.hex_net_lag_check > 0 && ping_age >= prefs.hex_net_lag_check)
g_snprintf (tbuf, sizeof (tbuf), "LAG%lu", tim);
serv->p_ping (serv, "", tbuf);
if (!serv->lag_sent)
{
g_snprintf (tbuf, sizeof (tbuf), "LAG%lu", tim);
serv->p_ping (serv, "", tbuf);
serv->lag_sent = tim;
fe_set_lag (serv, -1);
}
@@ -526,7 +525,7 @@ zoitechat_reinit_timers (void)
if ((prefs.hex_net_ping_timeout != 0 || prefs.hex_gui_lagometer)
&& lag_check_tag == 0)
{
lag_check_tag = fe_timeout_add_seconds (1, zoitechat_lag_check, NULL);
lag_check_tag = fe_timeout_add_seconds (30, zoitechat_lag_check, NULL);
}
else if ((!prefs.hex_net_ping_timeout && !prefs.hex_gui_lagometer)
&& lag_check_tag != 0)

View File

@@ -188,7 +188,6 @@ struct zoitechatprefs
unsigned int hex_irc_conf_mode;
unsigned int hex_irc_hidehost;
unsigned int hex_irc_hide_nickchange;
unsigned int hex_irc_hide_join_part_hostmask;
unsigned int hex_irc_hide_version;
unsigned int hex_irc_invisible;
unsigned int hex_irc_logging;
@@ -268,7 +267,6 @@ struct zoitechatprefs
int hex_gui_tab_layout;
int hex_gui_tab_closebuttons;
int hex_gui_tab_middleclose;
int hex_gui_mouse_scroll_speed;
int hex_gui_tab_newtofront;
int hex_gui_tab_pos;
int hex_gui_tab_small;
@@ -291,10 +289,6 @@ struct zoitechatprefs
int hex_irc_join_delay;
int hex_irc_notice_pos;
int hex_net_ping_timeout;
int hex_net_lag_check;
int hex_net_keepalive_idle;
int hex_net_keepalive_interval;
int hex_net_keepalive_count;
int hex_net_proxy_port;
int hex_net_proxy_type; /* 0=disabled, 1=wingate 2=socks4, 3=socks5, 4=http */
int hex_net_proxy_use; /* 0=all 1=IRC_ONLY 2=DCC_ONLY */

View File

@@ -305,14 +305,12 @@ static gboolean
tab_scroll_cb (GtkWidget *widget, GdkEventScroll *event, gpointer cv)
{
int direction = cv_scroll_direction (event);
int i;
if (prefs.hex_gui_tab_scrollchans)
{
if (direction != 0)
{
for (i = 0; i < cv_scroll_step_count (); i++)
mg_switch_page (1, direction);
mg_switch_page (1, direction);
return TRUE;
}
}
@@ -320,14 +318,12 @@ tab_scroll_cb (GtkWidget *widget, GdkEventScroll *event, gpointer cv)
{
if (direction < 0)
{
for (i = 0; i < cv_scroll_step_count (); i++)
tab_scroll_left_up_clicked (widget, cv);
tab_scroll_left_up_clicked (widget, cv);
return TRUE;
}
else if (direction > 0)
{
for (i = 0; i < cv_scroll_step_count (); i++)
tab_scroll_right_down_clicked (widget, cv);
tab_scroll_right_down_clicked (widget, cv);
return TRUE;
}
}

View File

@@ -112,11 +112,9 @@ cv_tree_scroll_event_cb (GtkWidget *widget, GdkEventScroll *event, gpointer user
if (prefs.hex_gui_tab_scrollchans)
{
int direction = cv_scroll_direction (event);
int i;
if (direction != 0)
for (i = 0; i < cv_scroll_step_count (); i++)
mg_switch_page (1, direction);
mg_switch_page (1, direction);
return direction != 0;
}

View File

@@ -126,15 +126,6 @@ cv_scroll_direction (GdkEventScroll *event)
}
}
static int
cv_scroll_step_count (void)
{
int speed = prefs.hex_gui_mouse_scroll_speed;
if (speed < 1)
speed = 1;
return (speed + 9) / 10;
}
/* ======= TABS ======= */

View File

@@ -320,7 +320,7 @@ fe_args (int argc, char *argv[])
GError *error = NULL;
GOptionContext *context;
char *buffer;
const char *desktop_id = "net.zoite.Zoitechat";
const char *desktop_id = "org.zoitechat.ZoiteChat";
#ifdef WIN32
char *base_path = NULL;
char *locale_path = NULL;

View File

@@ -60,7 +60,6 @@
#define ICON_FKEYS_DELETE "edit-delete"
#define ICON_FKEYS_CANCEL "dialog-cancel"
#define ICON_FKEYS_SAVE "document-save"
#define ICON_FKEYS_RESET "edit-undo"
static void replace_handle (GtkWidget * wid);
void key_check_replace_on_change (GtkEditable *editable, gpointer data);
@@ -81,7 +80,7 @@ void key_action_tab_clean (void);
*/
/* Remember that the *number* of actions is this *plus* 1 --AGL */
#define KEY_MAX_ACTIONS 16
#define KEY_MAX_ACTIONS 14
struct key_binding
{
@@ -106,10 +105,7 @@ struct gcomp_data
};
static int key_load_kbs (void);
static int key_load_kbs_from_buffer (char *ibuf, off_t size, GSList **out_list);
static int key_save_kbs (void);
static void key_dialog_load (GtkListStore *store);
static void key_dialog_reset (GtkWidget *wid, gpointer userdata);
static int key_action_handle_command (GtkWidget * wid, GdkEventKey * evt,
char *d1, char *d2,
struct session *sess);
@@ -146,13 +142,6 @@ static int key_action_move_tab_family_right (GtkWidget * wid, GdkEventKey * evt,
static int key_action_put_history (GtkWidget * wid, GdkEventKey * evt,
char *d1, char *d2,
struct session *sess);
static int key_action_menu_shortcut (GtkWidget * wid, GdkEventKey * evt,
char *d1, char *d2,
struct session *sess);
static int key_action_reopen_closed_tab (GtkWidget * wid, GdkEventKey * evt,
char *d1, char *d2,
struct session *sess);
static GSList *keybind_list = NULL;
@@ -271,7 +260,7 @@ static const struct key_action key_actions[KEY_MAX_ACTIONS + 1] = {
{key_action_handle_command, "Run Command",
N_("The \002Run Command\002 action runs the data in Data 1 as if it had been typed into the entry box where you pressed the key sequence. Thus it can contain text (which will be sent to the channel/person), commands or user commands. Escapes in Data 1 are interpreted (for example \002\\n\002, \002\\r\002, \002\\t\002, \002\\xNN\002 and \002\\\\\002), so it is possible to run more than one command by using newlines.")},
{key_action_page_switch, "Change Page",
N_("The \002Change Page\002 command switches between pages in the notebook. Set Data 1 to the page number, channel name, network/channel, or auto. If Data 2 is set to anything then numeric switches are relative to the current position. Auto switches to the page with the most recent and important activity (queries first, then channels with hilight, channels with dialogue, channels with other data)")},
N_("The \002Change Page\002 command switches between pages in the notebook. Set Data 1 to the page you want to switch to. If Data 2 is set to anything then the switch will be relative to the current position. Set Data 1 to auto to switch to the page with the most recent and important activity (queries first, then channels with hilight, channels with dialogue, channels with other data)")},
{key_action_insert, "Insert in Buffer",
N_("The \002Insert in Buffer\002 command will insert the contents of Data 1 into the entry where the key sequence was pressed at the current cursor position. Escapes in Data 1 are interpreted (for example \002\\n\002, \002\\r\002, \002\\t\002, \002\\xNN\002 and \002\\\\\002).")},
{key_action_scroll_page, "Scroll Page",
@@ -298,10 +287,6 @@ static const struct key_action key_actions[KEY_MAX_ACTIONS + 1] = {
N_("This command moves the current tab family to the right")},
{key_action_put_history, "Push input line into history",
N_("Push input line into history but doesn't send to server")},
{key_action_menu_shortcut, "Menu Shortcut",
N_("Runs one of the built-in menu shortcuts. Set Data 1 to: network-list, new-server-tab, new-server-window, close, quit, menu-toggle, user-list-toggle, fullscreen-toggle, away-toggle, reset-marker, move-marker, copy-selection, search-text, search-next, search-previous or contents.")},
{key_action_reopen_closed_tab, "Reopen Closed Tab",
N_("Reopens the most recently closed channel tab")},
};
#define default_kb_cfg \
@@ -344,86 +329,7 @@ static const struct key_action key_actions[KEY_MAX_ACTIONS + 1] = {
"ACCEL=<Alt>Right\nMove front tab right\nD1!\nD2!\n\n"\
"ACCEL=<Primary><Shift>Page_Up\nMove tab family left\nD1!\nD2!\n\n"\
"ACCEL=<Primary><Shift>Page_Down\nMove tab family right\nD1!\nD2!\n\n"\
"ACCEL=<Primary>s\nMenu Shortcut\nD1:network-list\nD2!\n\n"\
"ACCEL=<Primary>t\nMenu Shortcut\nD1:new-server-tab\nD2!\n\n"\
"ACCEL=<Primary>n\nMenu Shortcut\nD1:new-server-window\nD2!\n\n"\
"ACCEL=<Primary>w\nMenu Shortcut\nD1:close\nD2!\n\n"\
"ACCEL=<Primary>q\nMenu Shortcut\nD1:quit\nD2!\n\n"\
"ACCEL=<Primary>F9\nMenu Shortcut\nD1:menu-toggle\nD2!\n\n"\
"ACCEL=F7\nMenu Shortcut\nD1:user-list-toggle\nD2!\n\n"\
"ACCEL=F11\nMenu Shortcut\nD1:fullscreen-toggle\nD2!\n\n"\
"ACCEL=<Alt>a\nMenu Shortcut\nD1:away-toggle\nD2!\n\n"\
"ACCEL=<Primary>m\nMenu Shortcut\nD1:reset-marker\nD2!\n\n"\
"ACCEL=<Primary><Shift>M\nMenu Shortcut\nD1:move-marker\nD2!\n\n"\
"ACCEL=<Primary><Shift>C\nMenu Shortcut\nD1:copy-selection\nD2!\n\n"\
"ACCEL=<Primary>f\nMenu Shortcut\nD1:search-text\nD2!\n\n"\
"ACCEL=<Primary>g\nMenu Shortcut\nD1:search-next\nD2!\n\n"\
"ACCEL=<Primary><Shift>G\nMenu Shortcut\nD1:search-previous\nD2!\n\n"\
"ACCEL=F1\nMenu Shortcut\nD1:contents\nD2!\n\n"\
"ACCEL=<Primary><Shift>T\nReopen Closed Tab\nD1!\nD2!\n\n"
static gboolean
key_builtin_data_match (char *line, char *data)
{
if (line[2] == '!')
return data == NULL || data[0] == 0;
if (line[2] == ':')
return !strcmp (&line[3], data ? data : "");
return FALSE;
}
static gboolean
key_binding_is_builtin (struct key_binding *kb)
{
char *buf, *ibuf;
char *action;
int pnt = 0;
int state = 0;
gboolean match = FALSE;
gboolean d1_match = FALSE;
off_t size;
if (kb->action < 0 || kb->action > KEY_MAX_ACTIONS)
return FALSE;
action = key_actions[kb->action].name;
ibuf = g_strdup (default_kb_cfg);
size = strlen (default_kb_cfg);
while (buf_get_line (ibuf, &buf, &pnt, size))
{
if (strlen (buf) == 0)
continue;
switch (state)
{
case 0:
state = 1;
break;
case 1:
match = !strcmp (buf, action);
state = 2;
break;
case 2:
d1_match = match && key_builtin_data_match (buf, kb->data1);
state = 3;
break;
case 3:
if (d1_match && key_builtin_data_match (buf, kb->data2))
{
g_free (ibuf);
return TRUE;
}
state = 0;
break;
}
}
g_free (ibuf);
return FALSE;
}
"ACCEL=F9\nRun Command\nD1:/GUI MENU TOGGLE\nD2!\n\n"
void
key_init ()
@@ -537,6 +443,28 @@ key_handle_key_press (GtkWidget *wid, GdkEventKey *evt, session *sess)
if (!list)
return FALSE;
current_sess = sess;
if ((evt->state & GDK_CONTROL_MASK) &&
!(evt->state & (GDK_MOD1_MASK | GDK_META_MASK)))
{
if (!(evt->state & GDK_SHIFT_MASK) &&
(evt->keyval == GDK_KEY_w || evt->keyval == GDK_KEY_W))
{
if (sess->type == SESS_CHANNEL)
{
fe_close_window (sess);
g_signal_stop_emission_by_name (G_OBJECT (wid), "key-press-event");
return 1;
}
}
if ((evt->state & GDK_SHIFT_MASK) &&
(evt->keyval == GDK_KEY_t || evt->keyval == GDK_KEY_T))
{
mg_reopen_closed_channel_tab ();
g_signal_stop_emission_by_name (G_OBJECT (wid), "key-press-event");
return 1;
}
}
if (plugin_emit_keypress (sess, evt->state, evt->keyval, gdk_keyval_to_unicode (evt->keyval)))
return 1;
@@ -580,31 +508,6 @@ key_handle_key_press (GtkWidget *wid, GdkEventKey *evt, session *sess)
return 0;
}
gboolean
key_get_menu_accel (const char *name, guint *keyval, GdkModifierType *mod)
{
struct key_binding *kb;
GSList *list;
if (!name)
return FALSE;
list = keybind_list;
while (list)
{
kb = (struct key_binding*)list->data;
if (kb->action >= 0 && kb->action <= KEY_MAX_ACTIONS && kb->keyval != 0 && !strcmp (key_actions[kb->action].name, "Menu Shortcut") && kb->data1 && !strcmp (kb->data1, name))
{
*keyval = kb->keyval;
*mod = kb->mod;
return TRUE;
}
list = g_slist_next (list);
}
return FALSE;
}
/* ***** GUI code here ******************* */
@@ -615,7 +518,6 @@ enum
ACTION_COLUMN,
D1_COLUMN,
D2_COLUMN,
CUSTOM_COLUMN,
N_COLUMNS
};
@@ -740,32 +642,16 @@ key_dialog_keypress (GtkWidget *wid, GdkEventKey *evt, gpointer userdata)
if (handled)
{
gboolean custom1, custom2;
sel = gtk_tree_view_get_selection (view);
if (!gtk_tree_selection_get_selected (sel, &store, &iter1))
return FALSE;
gtk_tree_selection_get_selected (sel, &store, &iter1);
path = gtk_tree_model_get_path (store, &iter1);
if (delta == 1)
gtk_tree_path_next (path);
else if (!gtk_tree_path_prev (path))
{
gtk_tree_path_free (path);
return FALSE;
}
if (!gtk_tree_model_get_iter (store, &iter2, path))
{
gtk_tree_path_free (path);
return FALSE;
}
else
gtk_tree_path_prev (path);
gtk_tree_model_get_iter (store, &iter2, path);
gtk_tree_path_free (path);
gtk_tree_model_get (store, &iter1, CUSTOM_COLUMN, &custom1, -1);
gtk_tree_model_get (store, &iter2, CUSTOM_COLUMN, &custom2, -1);
if (custom1 && custom2)
gtk_list_store_swap (GTK_LIST_STORE (store), &iter1, &iter2);
gtk_list_store_swap (GTK_LIST_STORE (store), &iter1, &iter2);
}
return handled;
@@ -777,23 +663,14 @@ key_dialog_selection_changed (GtkTreeSelection *sel, gpointer userdata)
GtkTreeModel *model;
GtkTreeIter iter;
GtkXText *xtext;
GtkWidget *delete_button;
char *actiontext;
gboolean custom;
int action;
delete_button = g_object_get_data (G_OBJECT (key_dialog), "delete_button");
if (!gtk_tree_selection_get_selected (sel, &model, &iter) || model == NULL)
{
if (delete_button)
gtk_widget_set_sensitive (delete_button, FALSE);
return;
}
xtext = GTK_XTEXT (g_object_get_data (G_OBJECT (key_dialog), "xtext"));
gtk_tree_model_get (model, &iter, ACTION_COLUMN, &actiontext, CUSTOM_COLUMN, &custom, -1);
if (delete_button)
gtk_widget_set_sensitive (delete_button, custom);
gtk_tree_model_get (model, &iter, ACTION_COLUMN, &actiontext, -1);
if (actiontext)
{
@@ -868,10 +745,7 @@ key_dialog_save (GtkWidget *wid, gpointer userdata)
}
if (key_save_kbs () == 0)
{
menu_update_quit_accel ();
key_dialog_close (wid, NULL);
}
}
static void
@@ -884,7 +758,6 @@ key_dialog_add (GtkWidget *wid, gpointer userdata)
GtkTreePath *path;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, CUSTOM_COLUMN, TRUE, -1);
/* make sure the new row is visible and selected */
path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
@@ -894,134 +767,6 @@ key_dialog_add (GtkWidget *wid, gpointer userdata)
gtk_tree_path_free (path);
}
static char *
key_binding_signature (const char *action, const char *data1, const char *data2)
{
return g_strdup_printf ("%s\\n%s\\n%s", action ? action : "", data1 ? data1 : "", data2 ? data2 : "");
}
static int
key_dialog_reset_count (GHashTable *table, const char *key)
{
return GPOINTER_TO_INT (g_hash_table_lookup (table, key));
}
static void
key_dialog_reset_increment (GHashTable *table, char *key)
{
g_hash_table_replace (table, key, GINT_TO_POINTER (key_dialog_reset_count (table, key) + 1));
}
static void
key_dialog_reset (GtkWidget *wid, gpointer userdata)
{
GtkListStore *store = GTK_LIST_STORE (get_store ());
GtkListStore *custom_store;
GtkTreeIter iter, custom_iter;
GtkWidget *delete_button;
GHashTable *default_counts, *seen_counts;
GSList *list = NULL, *old_list, *default_iter;
struct key_binding *kb;
gboolean custom, keep;
char *key, *accel, *action, *data1, *data2, *signature;
if (key_load_kbs_from_buffer (g_strdup (default_kb_cfg), strlen (default_kb_cfg), &list) != 0)
return;
default_counts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
seen_counts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
for (default_iter = list; default_iter; default_iter = g_slist_next (default_iter))
{
kb = default_iter->data;
signature = key_binding_signature (key_actions[kb->action].name, kb->data1, kb->data2);
key_dialog_reset_increment (default_counts, signature);
}
custom_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
{
do
{
gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
KEY_COLUMN, &key,
ACCEL_COLUMN, &accel,
ACTION_COLUMN, &action,
D1_COLUMN, &data1,
D2_COLUMN, &data2,
CUSTOM_COLUMN, &custom,
-1);
signature = key_binding_signature (action, data1, data2);
keep = custom || key_dialog_reset_count (seen_counts, signature) >= key_dialog_reset_count (default_counts, signature);
if (!custom)
key_dialog_reset_increment (seen_counts, g_strdup (signature));
if (keep)
{
gtk_list_store_append (custom_store, &custom_iter);
gtk_list_store_set (custom_store, &custom_iter,
KEY_COLUMN, key,
ACCEL_COLUMN, accel,
ACTION_COLUMN, action,
D1_COLUMN, data1,
D2_COLUMN, data2,
CUSTOM_COLUMN, TRUE,
-1);
}
g_free (signature);
g_free (key);
g_free (accel);
g_free (action);
g_free (data1);
g_free (data2);
}
while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
}
old_list = keybind_list;
keybind_list = list;
gtk_list_store_clear (store);
key_dialog_load (store);
keybind_list = old_list;
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (custom_store), &iter))
{
do
{
gtk_tree_model_get (GTK_TREE_MODEL (custom_store), &iter,
KEY_COLUMN, &key,
ACCEL_COLUMN, &accel,
ACTION_COLUMN, &action,
D1_COLUMN, &data1,
D2_COLUMN, &data2,
-1);
gtk_list_store_append (store, &custom_iter);
gtk_list_store_set (store, &custom_iter,
KEY_COLUMN, key,
ACCEL_COLUMN, accel,
ACTION_COLUMN, action,
D1_COLUMN, data1,
D2_COLUMN, data2,
CUSTOM_COLUMN, TRUE,
-1);
g_free (key);
g_free (accel);
g_free (action);
g_free (data1);
g_free (data2);
}
while (gtk_tree_model_iter_next (GTK_TREE_MODEL (custom_store), &iter));
}
delete_button = g_object_get_data (G_OBJECT (key_dialog), "delete_button");
if (delete_button)
gtk_widget_set_sensitive (delete_button, FALSE);
g_hash_table_destroy (default_counts);
g_hash_table_destroy (seen_counts);
g_object_unref (custom_store);
g_slist_free_full (list, key_free);
}
static void
key_dialog_delete (GtkWidget *wid, gpointer userdata)
{
@@ -1029,14 +774,9 @@ key_dialog_delete (GtkWidget *wid, gpointer userdata)
GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
GtkTreeIter iter;
GtkTreePath *path;
gboolean custom;
if (gtkutil_treeview_get_selected (view, &iter, -1))
{
gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, CUSTOM_COLUMN, &custom, -1);
if (!custom)
return;
/* delete this row, select next one */
if (gtk_list_store_remove (store, &iter))
{
@@ -1063,13 +803,13 @@ key_dialog_treeview_new (GtkWidget *box)
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN);
store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
G_TYPE_STRING, G_TYPE_STRING);
g_return_val_if_fail (store != NULL, NULL);
view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (view), TRUE);
gtk_tree_view_set_enable_search (GTK_TREE_VIEW (view), FALSE);
gtk_tree_view_set_reorderable (GTK_TREE_VIEW (view), FALSE);
gtk_tree_view_set_reorderable (GTK_TREE_VIEW (view), TRUE);
g_signal_connect (G_OBJECT (view), "key-press-event",
G_CALLBACK (key_dialog_keypress), NULL);
@@ -1139,8 +879,7 @@ key_dialog_treeview_new (GtkWidget *box)
G_CALLBACK (key_dialog_combo_changed), combostore);
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view), ACTION_COLUMN,
"Action", render,
"text", ACTION_COLUMN,
"editable", CUSTOM_COLUMN,
"text", ACTION_COLUMN,
NULL);
render = gtk_cell_renderer_text_new ();
@@ -1151,7 +890,6 @@ key_dialog_treeview_new (GtkWidget *box)
GTK_TREE_VIEW (view), D1_COLUMN,
"Data1", render,
"text", D1_COLUMN,
"editable", CUSTOM_COLUMN,
NULL);
render = gtk_cell_renderer_text_new ();
@@ -1162,7 +900,6 @@ key_dialog_treeview_new (GtkWidget *box)
GTK_TREE_VIEW (view), D2_COLUMN,
"Data2", render,
"text", D2_COLUMN,
"editable", CUSTOM_COLUMN,
NULL);
col = gtk_tree_view_get_column (GTK_TREE_VIEW (view), KEY_COLUMN);
@@ -1208,8 +945,7 @@ key_dialog_load (GtkListStore *store)
ACCEL_COLUMN, accel_text,
ACTION_COLUMN, key_actions[kb->action].name,
D1_COLUMN, kb->data1,
D2_COLUMN, kb->data2,
CUSTOM_COLUMN, !key_binding_is_builtin (kb), -1);
D2_COLUMN, kb->data2, -1);
g_free (accel_text);
g_free (label_text);
@@ -1222,7 +958,7 @@ void
key_dialog_show ()
{
GtkWidget *vbox, *box;
GtkWidget *view, *xtext, *delete_button;
GtkWidget *view, *xtext;
GtkListStore *store;
XTextColor xtext_palette[XTEXT_COLS];
char buf[128];
@@ -1256,12 +992,8 @@ key_dialog_show ()
gtkutil_button (box, ICON_FKEYS_NEW, NULL, key_dialog_add,
NULL, _("Add"));
delete_button = gtkutil_button (box, ICON_FKEYS_DELETE, NULL, key_dialog_delete,
gtkutil_button (box, ICON_FKEYS_DELETE, NULL, key_dialog_delete,
NULL, _("Delete"));
g_object_set_data (G_OBJECT (key_dialog), "delete_button", delete_button);
gtk_widget_set_sensitive (delete_button, FALSE);
gtkutil_button (box, ICON_FKEYS_RESET, NULL, key_dialog_reset,
NULL, _("Reset"));
gtkutil_button (box, ICON_FKEYS_CANCEL, NULL, key_dialog_close,
NULL, _("Cancel"));
gtkutil_button (box, ICON_FKEYS_SAVE, NULL, key_dialog_save,
@@ -1369,14 +1101,41 @@ key_load_kbs_helper_mod (char *buf, GdkModifierType *out)
}
static int
key_load_kbs_from_buffer (char *ibuf, off_t size, GSList **out_list)
key_load_kbs (void)
{
char *buf;
char *buf, *ibuf;
struct stat st;
struct key_binding *kb = NULL;
int len, state = 0, pnt = 0;
int fd, len, state = 0, pnt = 0;
guint keyval;
GdkModifierType mod = 0;
GSList *list = NULL;
off_t size;
fd = zoitechat_open_file ("keybindings.conf", O_RDONLY, 0, 0);
if (fd < 0)
{
ibuf = g_strdup (default_kb_cfg);
size = strlen (default_kb_cfg);
}
else
{
if (fstat (fd, &st) != 0)
{
close (fd);
return 1;
}
ibuf = g_malloc(st.st_size);
read (fd, ibuf, st.st_size);
size = st.st_size;
close (fd);
}
if (keybind_list)
{
g_slist_free_full (keybind_list, key_free);
keybind_list = NULL;
}
while (buf_get_line (ibuf, &buf, &pnt, size))
{
@@ -1390,12 +1149,14 @@ key_load_kbs_from_buffer (char *ibuf, off_t size, GSList **out_list)
case KBSTATE_MOD:
kb = g_new0 (struct key_binding, 1);
/* New format */
if (strncmp (buf, "ACCEL=", 6) == 0)
{
buf += 6;
gtk_accelerator_parse (buf, &keyval, &mod);
kb->keyval = keyval;
kb->mod = key_modifier_get_valid (mod);
@@ -1418,8 +1179,6 @@ key_load_kbs_from_buffer (char *ibuf, off_t size, GSList **out_list)
if (keyval == 0)
{
g_free (ibuf);
key_free (kb);
g_slist_free_full (list, key_free);
return 2;
}
@@ -1436,8 +1195,6 @@ key_load_kbs_from_buffer (char *ibuf, off_t size, GSList **out_list)
if (kb->action == KEY_MAX_ACTIONS + 1)
{
g_free (ibuf);
key_free (kb);
g_slist_free_full (list, key_free);
return 3;
}
@@ -1455,8 +1212,6 @@ key_load_kbs_from_buffer (char *ibuf, off_t size, GSList **out_list)
if (buf[0] != 'D')
{
g_free (ibuf);
key_free (kb);
g_slist_free_full (list, key_free);
return 4;
}
@@ -1477,6 +1232,7 @@ key_load_kbs_from_buffer (char *ibuf, off_t size, GSList **out_list)
if (buf[2] == ':')
{
len = strlen (buf);
/* Add one for the NULL, subtract 3 for the "Dx:" */
len++;
len -= 3;
if (state == KBSTATE_DT1)
@@ -1499,8 +1255,7 @@ key_load_kbs_from_buffer (char *ibuf, off_t size, GSList **out_list)
continue;
} else
{
list = g_slist_append (list, kb);
kb = NULL;
keybind_list = g_slist_append (keybind_list, kb);
state = KBSTATE_MOD;
}
@@ -1509,56 +1264,14 @@ key_load_kbs_from_buffer (char *ibuf, off_t size, GSList **out_list)
}
}
g_free (ibuf);
*out_list = list;
return 0;
corrupt_file:
g_free (ibuf);
key_free (kb);
g_slist_free_full (list, key_free);
g_free (kb);
return 5;
}
static int
key_load_kbs (void)
{
char *ibuf;
struct stat st;
int fd, result;
off_t size;
GSList *list = NULL;
fd = zoitechat_open_file ("keybindings.conf", O_RDONLY, 0, 0);
if (fd < 0)
{
ibuf = g_strdup (default_kb_cfg);
size = strlen (default_kb_cfg);
}
else
{
if (fstat (fd, &st) != 0)
{
close (fd);
return 1;
}
ibuf = g_malloc(st.st_size);
read (fd, ibuf, st.st_size);
size = st.st_size;
close (fd);
}
result = key_load_kbs_from_buffer (ibuf, size, &list);
if (result != 0)
return result;
if (keybind_list)
g_slist_free_full (keybind_list, key_free);
keybind_list = list;
return 0;
}
static int
key_action_handle_command (GtkWidget * wid, GdkEventKey * evt, char *d1,
char *d2, struct session *sess)
@@ -1576,24 +1289,6 @@ key_action_handle_command (GtkWidget * wid, GdkEventKey * evt, char *d1,
return 0;
}
static int
key_action_menu_shortcut (GtkWidget * wid, GdkEventKey * evt, char *d1,
char *d2, struct session *sess)
{
if (menu_key_action (d1, evt->keyval, evt->state))
return 2;
return 0;
}
static int
key_action_reopen_closed_tab (GtkWidget * wid, GdkEventKey * evt, char *d1,
char *d2, struct session *sess)
{
mg_reopen_closed_channel_tab ();
return 2;
}
/*
* Check if the given session is inside the main window. This predicate
* is passed to lastact_getfirst() as a way to filter out detached sessions.
@@ -1612,9 +1307,6 @@ key_action_page_switch (GtkWidget * wid, GdkEventKey * evt, char *d1,
char *d2, struct session *sess)
{
session *newsess;
char *network;
char *channel;
char *slash;
int len, i, num;
if (!d1)
@@ -1626,13 +1318,21 @@ key_action_page_switch (GtkWidget * wid, GdkEventKey * evt, char *d1,
if (g_ascii_strcasecmp(d1, "auto") == 0)
{
/* Auto switch makes no sense in detached sessions */
if (!sess->gui->is_tab)
return 1;
/* Obtain a session with recent activity */
newsess = lastact_getfirst(session_check_is_tab);
if (newsess)
{
/*
* Only sessions in the current window should be considered (i.e.
* we don't want to move the focus on a different window). This
* call could, in theory, do this, but we checked before that
* newsess->gui->is_tab and sess->gui->is_tab.
*/
mg_bring_tofront_sess(newsess);
return 0;
}
@@ -1646,27 +1346,8 @@ key_action_page_switch (GtkWidget * wid, GdkEventKey * evt, char *d1,
{
if (i == 0 && (d1[i] == '+' || d1[i] == '-'))
continue;
network = NULL;
channel = d1;
slash = strchr (d1, '/');
if (slash && slash[1])
{
network = g_strndup (d1, slash - d1);
channel = slash + 1;
}
newsess = plugin_find_context (network, channel, sess->server);
g_free (network);
if (newsess && newsess->gui)
{
mg_bring_tofront_sess(newsess);
return 0;
}
return 1;
else
return 1;
}
}

View File

@@ -35,6 +35,5 @@ int key_handle_key_press (GtkWidget * wid, GdkEventKey * evt, session *sess);
int key_action_insert (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2,
session *sess);
void key_check_replace_on_change (GtkEditable *editable, gpointer data);
gboolean key_get_menu_accel (const char *name, guint *keyval, GdkModifierType *mod);
#endif

View File

@@ -272,6 +272,13 @@ gtkutil_apply_palette (GtkWidget *widget, const GdkRGBA *bg, const GdkRGBA *fg,
theme_manager_apply_palette_widget (widget, bg, fg, font_desc);
}
static void
gtkutil_file_req_destroy (GtkWidget * wid, struct file_req *freq)
{
freq->callback (freq->userdata, NULL);
g_free (freq);
}
static void
gtkutil_check_file (char *filename, struct file_req *freq)
{
@@ -383,6 +390,26 @@ gtkutil_file_req_done_chooser (GtkFileChooser *fs, struct file_req *freq)
}
static void
gtkutil_file_req_done (GtkWidget * wid, struct file_req *freq)
{
gtkutil_file_req_done_chooser (GTK_FILE_CHOOSER (freq->dialog), freq);
gtk_widget_destroy (freq->dialog);
}
static void
gtkutil_file_req_response (GtkWidget *dialog, gint res, struct file_req *freq)
{
if (res == GTK_RESPONSE_ACCEPT)
{
gtkutil_file_req_done (dialog, freq);
return;
}
gtk_widget_destroy (dialog);
}
#ifdef WIN32
static gboolean
gtkutil_native_dialog_unref_idle (gpointer native)
{
@@ -396,16 +423,27 @@ gtkutil_native_file_req_response (GtkNativeDialog *dialog, gint res, struct file
if (res == GTK_RESPONSE_ACCEPT)
gtkutil_file_req_done_chooser (GTK_FILE_CHOOSER (dialog), freq);
/* Match gtk dialog flow by always sending NULL to indicate completion. */
freq->callback (freq->userdata, NULL);
g_free (freq);
/*
* Defer unref until idle to avoid disposing the native chooser while
* still in the button-release signal stack on Windows.
*/
g_idle_add (gtkutil_native_dialog_unref_idle, dialog);
}
#endif
void
gtkutil_file_req (GtkWindow *parent, const char *title, void *callback, void *userdata, char *filter, char *extensions,
int flags)
{
struct file_req *freq;
GtkWidget *dialog;
GtkFileFilter *filefilter;
char *token;
char *tokenbuffer;
const char *xdir;
GtkWindow *effective_parent = parent;
@@ -415,6 +453,7 @@ gtkutil_file_req (GtkWindow *parent, const char *title, void *callback, void *us
xdir = get_xdir ();
#ifdef WIN32
{
GtkFileChooserNative *native = gtk_file_chooser_native_new (
title,
@@ -490,7 +529,107 @@ gtkutil_file_req (GtkWindow *parent, const char *title, void *callback, void *us
gtk_native_dialog_show (GTK_NATIVE_DIALOG (native));
return;
}
#endif
if (flags & FRF_WRITE)
{
dialog = gtk_file_chooser_dialog_new (title, NULL,
GTK_FILE_CHOOSER_ACTION_SAVE,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Save"), GTK_RESPONSE_ACCEPT,
NULL);
if (!(flags & FRF_NOASKOVERWRITE))
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
}
else
dialog = gtk_file_chooser_dialog_new (title, NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Open"), GTK_RESPONSE_ACCEPT,
NULL);
theme_manager_attach_window (dialog);
if (filter && filter[0] && (flags & FRF_FILTERISINITIAL))
{
if (flags & FRF_WRITE)
{
char temp[1024];
path_part (filter, temp, sizeof (temp));
if (temp[0] && g_file_test (temp, G_FILE_TEST_IS_DIR))
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), temp);
else if (xdir && xdir[0] && g_file_test (xdir, G_FILE_TEST_IS_DIR))
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), xdir);
gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), file_part (filter));
}
else
{
if (g_file_test (filter, G_FILE_TEST_IS_DIR))
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), filter);
else if (xdir && xdir[0] && g_file_test (xdir, G_FILE_TEST_IS_DIR))
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), xdir);
}
}
else if (!(flags & FRF_RECENTLYUSED))
{
if (xdir && xdir[0] && g_file_test (xdir, G_FILE_TEST_IS_DIR))
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), xdir);
}
if (flags & FRF_MULTIPLE)
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
if (flags & FRF_CHOOSEFOLDER)
gtk_file_chooser_set_action (GTK_FILE_CHOOSER (dialog), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
if ((flags & FRF_EXTENSIONS || flags & FRF_MIMETYPES) && extensions != NULL)
{
filefilter = gtk_file_filter_new ();
tokenbuffer = g_strdup (extensions);
token = strtok (tokenbuffer, ";");
while (token != NULL)
{
if (flags & FRF_EXTENSIONS)
gtk_file_filter_add_pattern (filefilter, token);
else
gtk_file_filter_add_mime_type (filefilter, token);
token = strtok (NULL, ";");
}
g_free (tokenbuffer);
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filefilter);
}
if (xdir && xdir[0] && g_file_test (xdir, G_FILE_TEST_IS_DIR))
{
GError *shortcut_error = NULL;
gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog), xdir, &shortcut_error);
if (shortcut_error)
g_error_free (shortcut_error);
}
freq = g_new (struct file_req, 1);
freq->dialog = dialog;
freq->flags = flags;
freq->callback = callback;
freq->userdata = userdata;
g_signal_connect (G_OBJECT (dialog), "response",
G_CALLBACK (gtkutil_file_req_response), freq);
g_signal_connect (G_OBJECT (dialog), "destroy",
G_CALLBACK (gtkutil_file_req_destroy), (gpointer) freq);
if (effective_parent)
gtk_window_set_transient_for (GTK_WINDOW (dialog), effective_parent);
if (flags & FRF_MODAL)
{
g_assert (effective_parent);
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
}
gtk_widget_show (dialog);
}
static gboolean

View File

@@ -872,10 +872,6 @@ fe_set_title (session *sess)
static void
mg_topicbar_update_height (GtkWidget *topic);
static void
mg_topicbar_queue_relayout (GtkWidget *topic);
static void
mg_queue_window_relayout (GtkWidget *window);
static session *
mg_session_from_window (GtkWidget *wid)
@@ -895,57 +891,6 @@ mg_session_from_window (GtkWidget *wid)
return current_sess;
}
static gboolean
mg_window_relayout_idle_cb (gpointer userdata)
{
GtkWidget *window = GTK_WIDGET (userdata);
session *sess;
g_object_set_data (G_OBJECT (window), "mg-window-relayout-source", NULL);
sess = mg_session_from_window (window);
if (sess && sess->gui)
{
if (GTK_IS_WIDGET (sess->gui->topic_entry))
mg_topicbar_queue_relayout (sess->gui->topic_entry);
if (GTK_IS_XTEXT (sess->gui->xtext))
{
gtk_xtext_refresh (GTK_XTEXT (sess->gui->xtext));
gtk_widget_queue_resize (sess->gui->xtext);
gtk_widget_queue_draw (sess->gui->xtext);
}
if (GTK_IS_WIDGET (sess->gui->window))
{
gtk_widget_queue_resize (sess->gui->window);
gtk_widget_queue_draw (sess->gui->window);
}
}
g_object_unref (window);
return G_SOURCE_REMOVE;
}
static void
mg_queue_window_relayout (GtkWidget *window)
{
guint source_id;
if (!window || !GTK_IS_WIDGET (window))
return;
if (g_object_get_data (G_OBJECT (window), "mg-window-relayout-source") != NULL)
return;
source_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
mg_window_relayout_idle_cb,
g_object_ref (window),
NULL);
g_object_set_data (G_OBJECT (window), "mg-window-relayout-source",
GUINT_TO_POINTER (source_id));
}
static gboolean
mg_windowstate_cb (GtkWindow *wid, GdkEventWindowState *event, gpointer userdata)
{
@@ -994,18 +939,24 @@ mg_windowstate_cb (GtkWindow *wid, GdkEventWindowState *event, gpointer userdata
}
sess = mg_session_from_window (GTK_WIDGET (wid));
if (sess && sess->gui && GTK_IS_WIDGET (sess->gui->topic_entry))
{
mg_topicbar_update_height (sess->gui->topic_entry);
gtk_widget_queue_draw (sess->gui->topic_entry);
}
if (sess && sess->gui && GTK_IS_XTEXT (sess->gui->xtext))
{
gtk_xtext_refresh (GTK_XTEXT (sess->gui->xtext));
gtk_widget_queue_draw (sess->gui->xtext);
}
if (sess && sess->gui && GTK_IS_WIDGET (sess->gui->window))
mg_queue_window_relayout (sess->gui->window);
else
mg_queue_window_relayout (GTK_WIDGET (wid));
gtk_widget_queue_draw (sess->gui->window);
if (current_sess && current_sess->gui)
menu_set_fullscreen (current_sess->gui, prefs.hex_gui_win_fullscreen);
#ifdef G_OS_WIN32
if (event->changed_mask &
(GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN))
mg_win32_allow_autohide_taskbar (wid, event);
mg_win32_allow_autohide_taskbar (wid, event);
#endif
return FALSE;
@@ -1099,10 +1050,21 @@ mg_configure_cb (GtkWidget *wid, GdkEventConfigure *event, session *sess)
}
target_sess = mg_session_from_window (wid);
if (target_sess && target_sess->gui && GTK_IS_WIDGET (target_sess->gui->window))
mg_queue_window_relayout (target_sess->gui->window);
else
mg_queue_window_relayout (wid);
if (target_sess && target_sess->gui)
{
if (GTK_IS_WIDGET (target_sess->gui->topic_entry))
{
mg_topicbar_update_height (target_sess->gui->topic_entry);
gtk_widget_queue_draw (target_sess->gui->topic_entry);
}
if (GTK_IS_XTEXT (target_sess->gui->xtext))
{
gtk_xtext_refresh (GTK_XTEXT (target_sess->gui->xtext));
gtk_widget_queue_draw (target_sess->gui->xtext);
}
if (GTK_IS_WIDGET (target_sess->gui->window))
gtk_widget_queue_draw (target_sess->gui->window);
}
return FALSE;
}
@@ -2743,6 +2705,7 @@ mg_changui_destroy (session *sess)
/* it fixes: Gdk-CRITICAL **: gdk_colormap_get_screen: */
/* assertion `GDK_IS_COLORMAP (cmap)' failed */
ret = sess->gui->window;
g_free (sess->gui);
sess->gui = NULL;
}
return ret;
@@ -2764,17 +2727,13 @@ mg_link_irctab (session *sess, int focus)
return;
}
session_gui *old_gui;
mg_unpopulate (sess);
old_gui = sess->gui;
win = mg_changui_destroy (sess);
mg_changui_new (sess, sess->res, 1, focus);
/* the buffer is now attached to a different widget */
((xtext_buffer *)sess->res->buffer)->xtext = (GtkXText *)sess->gui->xtext;
if (win)
gtk_widget_destroy (win);
g_free (old_gui);
}
void
@@ -3149,51 +3108,33 @@ mg_create_dialogbuttons (GtkWidget *box)
static void
mg_topicbar_update_height (GtkWidget *topic)
{
GtkWidget *parent;
GtkWidget *grandparent;
GtkWidget *scroller;
GtkTextBuffer *buffer;
GtkTextIter start;
GtkTextIter end;
GtkTextView *view;
PangoLayout *layout;
char *text;
int width;
int line_height;
int line_count;
int target_height;
int margin_left;
int margin_right;
int margin_top;
int margin_bottom;
int old_height;
PangoContext *context;
PangoFontMetrics *metrics;
if (!topic || !GTK_IS_TEXT_VIEW (topic))
return;
view = GTK_TEXT_VIEW (topic);
parent = gtk_widget_get_parent (topic);
grandparent = parent ? gtk_widget_get_parent (parent) : NULL;
scroller = gtk_widget_get_parent (topic);
margin_left = gtk_text_view_get_left_margin (view);
margin_right = gtk_text_view_get_right_margin (view);
margin_top = gtk_text_view_get_top_margin (view);
margin_bottom = gtk_text_view_get_bottom_margin (view);
buffer = gtk_text_view_get_buffer (view);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (topic));
gtk_text_buffer_get_bounds (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
layout = gtk_widget_create_pango_layout (topic, text && text[0] ? text : " ");
g_free (text);
width = gtk_widget_get_allocated_width (topic);
if (width <= 1 && parent)
width = gtk_widget_get_allocated_width (parent);
width -= margin_left + margin_right;
if (width < 1)
width = 1;
pango_layout_set_width (layout, width * PANGO_SCALE);
width = gtk_widget_get_allocated_width (topic) - 8;
if (width > 0)
pango_layout_set_width (layout, width * PANGO_SCALE);
pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
context = gtk_widget_get_pango_context (topic);
@@ -3205,95 +3146,44 @@ mg_topicbar_update_height (GtkWidget *topic)
pango_font_metrics_unref (metrics);
if (line_height <= 0)
line_height = 16;
line_count = pango_layout_get_line_count (layout);
if (line_count <= 0)
line_count = 1;
target_height = line_height * line_count;
if (target_height < line_height)
target_height = line_height;
target_height = (line_height * line_count) + margin_top + margin_bottom;
if (target_height < line_height + margin_top + margin_bottom)
target_height = line_height + margin_top + margin_bottom;
old_height = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (topic),
"mg-topicbar-target-height"));
if (old_height != target_height)
gtk_widget_set_size_request (topic, -1, target_height);
if (scroller && GTK_IS_SCROLLED_WINDOW (scroller))
{
g_object_set_data (G_OBJECT (topic), "mg-topicbar-target-height",
GINT_TO_POINTER (target_height));
gtk_widget_set_size_request (topic, -1, target_height);
if (parent && GTK_IS_SCROLLED_WINDOW (parent))
{
gtk_scrolled_window_set_max_content_height (GTK_SCROLLED_WINDOW (parent), -1);
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (parent), -1);
gtk_scrolled_window_set_max_content_height (GTK_SCROLLED_WINDOW (parent), target_height);
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (parent), target_height);
gtk_widget_set_size_request (parent, -1, target_height);
}
gtk_scrolled_window_set_max_content_height (GTK_SCROLLED_WINDOW (scroller), -1);
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (scroller), -1);
gtk_scrolled_window_set_max_content_height (GTK_SCROLLED_WINDOW (scroller), target_height);
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (scroller), target_height);
gtk_widget_set_size_request (scroller, -1, target_height);
gtk_widget_queue_resize (scroller);
}
else
{
gtk_widget_queue_resize (topic);
}
gtk_widget_queue_resize (topic);
if (parent)
gtk_widget_queue_resize (parent);
if (grandparent)
gtk_widget_queue_resize (grandparent);
gtk_widget_queue_draw (topic);
g_object_unref (layout);
}
static gboolean
mg_topicbar_relayout_idle_cb (gpointer userdata)
{
GtkWidget *topic = GTK_WIDGET (userdata);
g_object_set_data (G_OBJECT (topic), "mg-topicbar-relayout-source", NULL);
mg_topicbar_update_height (topic);
g_object_unref (topic);
return G_SOURCE_REMOVE;
}
static void
mg_topicbar_queue_relayout (GtkWidget *topic)
{
guint source_id;
if (!topic || !GTK_IS_TEXT_VIEW (topic))
return;
if (g_object_get_data (G_OBJECT (topic), "mg-topicbar-relayout-source") != NULL)
return;
source_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
mg_topicbar_relayout_idle_cb,
g_object_ref (topic),
NULL);
g_object_set_data (G_OBJECT (topic), "mg-topicbar-relayout-source",
GUINT_TO_POINTER (source_id));
}
static void
mg_topicbar_buffer_changed_cb (GtkTextBuffer *buffer, gpointer userdata)
{
(void) buffer;
mg_topicbar_queue_relayout (GTK_WIDGET (userdata));
mg_topicbar_update_height (GTK_WIDGET (userdata));
}
static void
mg_topicbar_size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation, gpointer userdata)
{
int old_width;
(void) allocation;
(void) userdata;
old_width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
"mg-topicbar-allocated-width"));
if (allocation->width == old_width)
return;
g_object_set_data (G_OBJECT (widget), "mg-topicbar-allocated-width",
GINT_TO_POINTER (allocation->width));
mg_topicbar_queue_relayout (widget);
mg_topicbar_update_height (widget);
}
void
@@ -3578,7 +3468,7 @@ mg_create_infoframe (GtkWidget *box)
frame = gtk_frame_new (0);
gtk_frame_set_shadow_type ((GtkFrame*)frame, GTK_SHADOW_OUT);
gtk_box_pack_start (GTK_BOX (box), frame, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (box), frame, FALSE, TRUE, 0);
hbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0);
gtk_container_add (GTK_CONTAINER (frame), hbox);
@@ -3599,7 +3489,7 @@ mg_create_meters (session_gui *gui, GtkWidget *parent_box)
if ((prefs.hex_gui_lagometer & 2) || (prefs.hex_gui_throttlemeter & 2))
{
infbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, TRUE, 0);
infbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0);
gtk_box_pack_start (GTK_BOX (box), infbox, 0, 0, 0);
}

View File

@@ -1755,6 +1755,44 @@ menu_change_layout (void)
}
}
void
menu_update_quit_accel (void)
{
GSList *list;
list = sess_list;
while (list)
{
session *sess = list->data;
session_gui *gui = sess->gui;
GtkWidget *item;
GtkAccelGroup *accel_group;
int enabled;
list = list->next;
if (!gui)
continue;
item = gui->menu_item[MENU_ID_QUIT];
if (!item)
continue;
enabled = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "zc-ctrlq-enabled"));
if (enabled == (int)prefs.hex_gui_ctrlq_quit)
continue;
accel_group = g_object_get_data (G_OBJECT (item), "zc-quit-accel-group");
if (!accel_group)
continue;
if (prefs.hex_gui_ctrlq_quit)
gtk_widget_add_accelerator (item, "activate", accel_group, GDK_KEY_q, STATE_CTRL, GTK_ACCEL_VISIBLE);
else
gtk_widget_remove_accelerator (item, accel_group, GDK_KEY_q, STATE_CTRL);
g_object_set_data (G_OBJECT (item), "zc-ctrlq-enabled", GINT_TO_POINTER (prefs.hex_gui_ctrlq_quit));
}
}
static void
menu_layout_cb (GtkWidget *item, gpointer none)
{
@@ -1901,13 +1939,13 @@ menu_about (GtkWidget *wid, gpointer sess)
static struct mymenu mymenu[] = {
{N_("_ZoiteChat"), 0, 0, M_NEWMENU, MENU_ID_ZOITECHAT, 0, 1},
{N_("Network Li_st"), menu_open_server_list, 0, M_MENUITEM, 0, 0, 1},
{N_("Network Li_st"), menu_open_server_list, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_s},
{0, 0, 0, M_SEP, 0, 0, 0},
{N_("_New"), 0, 0, M_MENUSUB, 0, 0, 1},
{N_("Server Tab"), menu_newserver_tab, 0, M_MENUITEM, 0, 0, 1},
{N_("Server Tab"), menu_newserver_tab, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_t},
{N_("Channel Tab"), menu_newchannel_tab, 0, M_MENUITEM, 0, 0, 1},
{N_("Server Window"), menu_newserver_window, 0, M_MENUITEM, 0, 0, 1},
{N_("Server Window"), menu_newserver_window, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_n},
{N_("Channel Window"), menu_newchannel_window, 0, M_MENUITEM, 0, 0, 1},
{0, 0, 0, M_END, 0, 0, 0},
{0, 0, 0, M_SEP, 0, 0, 0},
@@ -1919,13 +1957,13 @@ static struct mymenu mymenu[] = {
#define CLOSE_OFFSET (13)
{0, menu_close, 0, M_MENUITEM, 0, 0, 1},
{0, 0, 0, M_SEP, 0, 0, 0},
{N_("_Quit"), menu_quit, 0, M_MENUITEM, MENU_ID_QUIT, 0, 1}, /* 15 */
{N_("_Quit"), menu_quit, 0, M_MENUITEM, MENU_ID_QUIT, 0, 1, GDK_KEY_q}, /* 15 */
{N_("_View"), 0, 0, M_NEWMENU, 0, 0, 1},
#define MENUBAR_OFFSET (17)
{N_("_Menu Bar"), menu_bar_toggle_cb, 0, M_MENUTOG, MENU_ID_MENUBAR, 0, 1},
{N_("_Menu Bar"), menu_bar_toggle_cb, 0, M_MENUTOG, MENU_ID_MENUBAR, 0, 1, GDK_KEY_F9},
{N_("_Topic Bar"), menu_topicbar_toggle, 0, M_MENUTOG, MENU_ID_TOPICBAR, 0, 1},
{N_("_User List"), menu_userlist_toggle, 0, M_MENUTOG, MENU_ID_USERLIST, 0, 1},
{N_("_User List"), menu_userlist_toggle, 0, M_MENUTOG, MENU_ID_USERLIST, 0, 1, GDK_KEY_F7},
{N_("U_ser List Buttons"), menu_ulbuttons_toggle, 0, M_MENUTOG, MENU_ID_ULBUTTONS, 0, 1},
{N_("M_ode Buttons"), menu_cmbuttons_toggle, 0, M_MENUTOG, MENU_ID_MODEBUTTONS, 0, 1},
{0, 0, 0, M_SEP, 0, 0, 0},
@@ -1942,7 +1980,7 @@ static struct mymenu mymenu[] = {
{N_("Both"), menu_metres_both, 0, M_MENURADIO, 0, 0, 1},
{0, 0, 0, M_END, 0, 0, 0}, /* 32 */
{ 0, 0, 0, M_SEP, 0, 0, 0 },
{N_ ("_Fullscreen"), menu_fullscreen_toggle, 0, M_MENUTOG, MENU_ID_FULLSCREEN, 0, 1},
{N_ ("_Fullscreen"), menu_fullscreen_toggle, 0, M_MENUTOG, MENU_ID_FULLSCREEN, 0, 1, GDK_KEY_F11},
{N_("_Server"), 0, 0, M_NEWMENU, 0, 0, 1},
{N_("_Disconnect"), menu_disconnect, 0, M_MENUITEM, MENU_ID_DISCONNECT, 0, 1},
@@ -1951,7 +1989,7 @@ static struct mymenu mymenu[] = {
{N_("Channel _List"), menu_chanlist, 0, M_MENUITEM, 0, 0, 1},
{0, 0, 0, M_SEP, 0, 0, 0},
#define AWAY_OFFSET (41)
{N_("Marked _Away"), menu_away_toggle, 0, M_MENUITEM, MENU_ID_AWAY, 0, 1},
{N_("Marked _Away"), menu_away_toggle, 0, M_MENUITEM, MENU_ID_AWAY, 0, 1, GDK_KEY_a},
{N_("_Usermenu"), 0, 0, M_NEWMENU, MENU_ID_USERMENU, 0, 1}, /* 40 */
@@ -1979,191 +2017,25 @@ static struct mymenu mymenu[] = {
{N_("_Raw Log"), menu_rawlog, 0, M_MENUITEM, 0, 0, 1}, /* 61 */
{N_("_URL Grabber"), url_opengui, 0, M_MENUITEM, 0, 0, 1},
{0, 0, 0, M_SEP, 0, 0, 0},
{N_("Reset Marker Line"), menu_resetmarker, 0, M_MENUITEM, 0, 0, 1},
{N_("Move to Marker Line"), menu_movetomarker, 0, M_MENUITEM, 0, 0, 1},
{N_("_Copy Selection"), menu_copy_selection, 0, M_MENUITEM, 0, 0, 1},
{N_("Reset Marker Line"), menu_resetmarker, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_m},
{N_("Move to Marker Line"), menu_movetomarker, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_M},
{N_("_Copy Selection"), menu_copy_selection, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_C},
{N_("C_lear Text"), menu_flushbuffer, 0, M_MENUITEM, 0, 0, 1},
{N_("Save Text" ELLIPSIS), menu_savebuffer, 0, M_MENUITEM, 0, 0, 1},
#define SEARCH_OFFSET (70)
{N_("Search"), 0, 0, M_MENUSUB, 0, 0, 1},
{N_("Search Text" ELLIPSIS), menu_search, 0, M_MENUITEM, 0, 0, 1},
{N_("Search Next" ), menu_search_next, 0, M_MENUITEM, 0, 0, 1},
{N_("Search Previous" ), menu_search_prev, 0, M_MENUITEM, 0, 0, 1},
{N_("Search Text" ELLIPSIS), menu_search, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_f},
{N_("Search Next" ), menu_search_next, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_g},
{N_("Search Previous" ), menu_search_prev, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_G},
{0, 0, 0, M_END, 0, 0, 0},
{N_("_Help"), 0, 0, M_NEWMENU, 0, 0, 1}, /* 74 */
{N_("_Contents"), menu_docs, 0, M_MENUITEM, 0, 0, 1},
{N_("_Contents"), menu_docs, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_F1},
{N_("_About"), menu_about, 0, M_MENUITEM, 0, 0, 1},
{0, 0, 0, M_END, 0, 0, 0},
};
static const char *
menu_get_key_action_name (int index)
{
switch (index)
{
case 1:
return "network-list";
case 4:
return "new-server-tab";
case 6:
return "new-server-window";
case CLOSE_OFFSET:
return "close";
case 15:
return "quit";
case MENUBAR_OFFSET:
return "menu-toggle";
case MENUBAR_OFFSET + 2:
return "user-list-toggle";
case 34:
return "fullscreen-toggle";
case AWAY_OFFSET:
return "away-toggle";
case 65:
return "reset-marker";
case 66:
return "move-marker";
case 67:
return "copy-selection";
case SEARCH_OFFSET + 1:
return "search-text";
case SEARCH_OFFSET + 2:
return "search-next";
case SEARCH_OFFSET + 3:
return "search-previous";
case 75:
return "contents";
}
return NULL;
}
static void
menu_add_keybinding_accel (GtkWidget *item, GtkAccelGroup *accel_group, const char *name)
{
guint keyval;
GdkModifierType mod;
if (!accel_group || !key_get_menu_accel (name, &keyval, &mod))
return;
if (!strcmp (name, "quit") && !prefs.hex_gui_ctrlq_quit && keyval == GDK_KEY_q && mod == STATE_CTRL)
return;
gtk_widget_add_accelerator (item, "activate", accel_group, keyval, mod, GTK_ACCEL_VISIBLE);
g_object_set_data (G_OBJECT (item), "zc-key-accel-key", GUINT_TO_POINTER (keyval));
g_object_set_data (G_OBJECT (item), "zc-key-accel-mod", GUINT_TO_POINTER (mod));
}
static void
menu_refresh_keybinding_accels (GtkWidget *widget, gpointer data)
{
GtkAccelGroup *accel_group = data;
const char *name;
guint keyval;
GdkModifierType mod;
GtkWidget *submenu;
GList *children, *list;
if (GTK_IS_MENU_ITEM (widget))
{
keyval = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "zc-key-accel-key"));
mod = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "zc-key-accel-mod"));
if (keyval != 0)
{
gtk_widget_remove_accelerator (widget, accel_group, keyval, mod);
g_object_set_data (G_OBJECT (widget), "zc-key-accel-key", NULL);
g_object_set_data (G_OBJECT (widget), "zc-key-accel-mod", NULL);
}
name = g_object_get_data (G_OBJECT (widget), "zc-key-action");
menu_add_keybinding_accel (widget, accel_group, name);
submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
if (submenu)
menu_refresh_keybinding_accels (submenu, data);
}
if (GTK_IS_CONTAINER (widget))
{
children = gtk_container_get_children (GTK_CONTAINER (widget));
for (list = children; list; list = g_list_next (list))
menu_refresh_keybinding_accels (list->data, data);
g_list_free (children);
}
}
void
menu_update_quit_accel (void)
{
session *sess;
GSList *list;
GtkAccelGroup *accel_group;
list = sess_list;
while (list)
{
sess = list->data;
if (sess && sess->gui && sess->gui->menu)
{
accel_group = g_object_get_data (G_OBJECT (sess->gui->menu), "accel");
if (accel_group)
menu_refresh_keybinding_accels (sess->gui->menu, accel_group);
}
list = g_slist_next (list);
}
}
gboolean
menu_key_action (const char *name, guint keyval, GdkModifierType state)
{
if (!name)
return FALSE;
if (!strcmp (name, "network-list"))
menu_open_server_list (NULL, NULL);
else if (!strcmp (name, "new-server-tab"))
menu_newserver_tab (NULL, NULL);
else if (!strcmp (name, "new-server-window"))
menu_newserver_window (NULL, NULL);
else if (!strcmp (name, "close"))
menu_close (NULL, NULL);
else if (!strcmp (name, "quit"))
{
if (!prefs.hex_gui_ctrlq_quit && keyval == GDK_KEY_q && (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)) == STATE_CTRL)
return FALSE;
menu_quit (NULL, NULL);
}
else if (!strcmp (name, "menu-toggle"))
menu_bar_toggle_cb ();
else if (!strcmp (name, "user-list-toggle"))
menu_userlist_toggle (NULL, NULL);
else if (!strcmp (name, "fullscreen-toggle"))
menu_fullscreen_toggle (NULL, NULL);
else if (!strcmp (name, "away-toggle"))
menu_away_toggle (NULL, NULL);
else if (!strcmp (name, "reset-marker"))
menu_resetmarker (NULL, NULL);
else if (!strcmp (name, "move-marker"))
menu_movetomarker (NULL, NULL);
else if (!strcmp (name, "copy-selection"))
menu_copy_selection (NULL, NULL);
else if (!strcmp (name, "search-text"))
menu_search ();
else if (!strcmp (name, "search-next"))
menu_search_next (NULL);
else if (!strcmp (name, "search-previous"))
menu_search_prev (NULL);
else if (!strcmp (name, "contents"))
menu_docs (NULL, NULL);
else
return FALSE;
return TRUE;
}
void
menu_set_away (session_gui *gui, int away)
{
@@ -2769,8 +2641,6 @@ menu_create_main (void *accel_group, int bar, int away, int toplevel,
case M_MENUITEM:
item = gtk_menu_item_new_with_mnemonic (_(mymenu[i].text));
normalitem:
g_object_set_data (G_OBJECT (item), "zc-key-action", (gpointer) menu_get_key_action_name (i));
menu_add_keybinding_accel (item, accel_group, menu_get_key_action_name (i));
if (mymenu[i].key != 0 && !(mymenu[i].id == MENU_ID_QUIT && !prefs.hex_gui_ctrlq_quit))
gtk_widget_add_accelerator (item, "activate", accel_group,
mymenu[i].key,
@@ -2799,8 +2669,6 @@ normalitem:
case M_MENUTOG:
item = gtk_check_menu_item_new_with_mnemonic (_(mymenu[i].text));
togitem:
g_object_set_data (G_OBJECT (item), "zc-key-action", (gpointer) menu_get_key_action_name (i));
menu_add_keybinding_accel (item, accel_group, menu_get_key_action_name (i));
/* must avoid callback for Radio buttons */
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), mymenu[i].state);
/*gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),

View File

@@ -39,7 +39,6 @@ void menu_bar_toggle (void);
void menu_add_plugin_items (GtkWidget *menu, char *root, char *target);
void menu_change_layout (void);
void menu_update_quit_accel (void);
gboolean menu_key_action (const char *name, guint keyval, GdkModifierType state);
void menu_set_away (session_gui *gui, int away);
void menu_set_fullscreen (session_gui *gui, int fullscreen);

View File

@@ -56,7 +56,7 @@ notification_backend_show (const char *title, const char *text)
g_variant_builder_init (&params, G_VARIANT_TYPE ("(susssasa{sv}i)"));
g_variant_builder_add (&params, "s", "zoitechat"); /* App name */
g_variant_builder_add (&params, "u", 0); /* ID, 0 means don't replace */
g_variant_builder_add (&params, "s", "net.zoite.Zoitechat"); /* App icon */
g_variant_builder_add (&params, "s", "org.zoitechat.ZoiteChat"); /* App icon */
g_variant_builder_add (&params, "s", title);
g_variant_builder_add (&params, "s", text);
g_variant_builder_add (&params, "as", NULL); /* Actions */
@@ -65,7 +65,7 @@ notification_backend_show (const char *title, const char *text)
g_variant_builder_open (&params, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_open (&params, G_VARIANT_TYPE ("{sv}"));
g_variant_builder_add (&params, "s", "desktop-entry");
g_variant_builder_add (&params, "v", g_variant_new_string ("net.zoite.Zoitechat"));
g_variant_builder_add (&params, "v", g_variant_new_string ("org.zoitechat.ZoiteChat"));
g_variant_builder_close (&params);
g_variant_builder_close (&params);

View File

@@ -80,7 +80,7 @@ typedef GIcon *TrayIcon;
typedef GIcon *TrayCustomIcon;
#define tray_icon_free(i) g_object_unref(i)
#define ICON_NORMAL_NAME "net.zoite.Zoitechat"
#define ICON_NORMAL_NAME "org.zoitechat.ZoiteChat"
#define ICON_MSG_NAME "mail-unread"
#define ICON_HILIGHT_NAME "dialog-warning"
#define ICON_FILE_NAME "folder-download"

View File

@@ -29,7 +29,6 @@
#include "../common/servlist.h"
#include "../common/cfgfiles.h"
#include "../common/fe.h"
#include "../common/secretstore.h"
#include "../common/util.h"
#include "fe-gtk.h"
@@ -86,12 +85,6 @@ static GtkWidget *edit_entry_nick2;
static GtkWidget *edit_entry_user;
static GtkWidget *edit_entry_real;
static GtkWidget *edit_entry_pass;
static GtkWidget *edit_check_show_pass;
static GtkWidget *edit_check_use_keyring;
static GtkWidget *edit_button_encrypt_pass;
static GtkWidget *edit_button_import_pass;
static int edit_pass_changed;
static char *edit_loaded_password;
static GtkWidget *edit_label_nick;
static GtkWidget *edit_label_nick2;
static GtkWidget *edit_label_real;
@@ -110,168 +103,6 @@ static session *servlist_sess;
static void servlist_network_row_cb (GtkTreeSelection *sel, gpointer user_data);
static GtkWidget *servlist_open_edit (GtkWidget *parent, ircnet *net);
static void servlist_password_changed_cb (GtkEditable *editable, gpointer userdata);
static void
servlist_update_password_tools (ircnet *net)
{
gboolean has_local;
gboolean use_keyring;
if (!edit_button_encrypt_pass || !edit_button_import_pass)
return;
use_keyring = net && (net->flags & FLAG_USE_KEYRING);
has_local = net && net->pass && *net->pass && !use_keyring && !edit_pass_changed;
gtk_widget_set_sensitive (edit_button_encrypt_pass, has_local && !servlist_password_is_encrypted (net->pass));
gtk_widget_set_sensitive (edit_button_import_pass, has_local);
}
static void
servlist_entry_set_text_silent (GtkWidget *entry, const char *text)
{
g_signal_handlers_block_by_func (G_OBJECT (entry), G_CALLBACK (servlist_password_changed_cb), NULL);
gtk_entry_set_text (GTK_ENTRY (entry), text);
g_signal_handlers_unblock_by_func (G_OBJECT (entry), G_CALLBACK (servlist_password_changed_cb), NULL);
}
static char *
servlist_display_password (ircnet *net)
{
if (!net)
return NULL;
if (edit_pass_changed)
return g_strdup (gtk_entry_get_text (GTK_ENTRY (edit_entry_pass)));
if (edit_loaded_password)
return g_strdup (edit_loaded_password);
if (net->flags & FLAG_USE_KEYRING)
return secretstore_get_network_password (net->name);
return servlist_password_decrypt_for_storage (net->pass);
}
static void
servlist_toggle_show_password_cb (GtkToggleButton *toggle, gpointer userdata)
{
if (gtk_toggle_button_get_active (toggle))
{
char *password = servlist_display_password (selected_net);
if (password)
{
if (edit_loaded_password)
{
memset (edit_loaded_password, 0, strlen (edit_loaded_password));
g_free (edit_loaded_password);
}
edit_loaded_password = g_strdup (password);
servlist_entry_set_text_silent (userdata, password);
memset (password, 0, strlen (password));
g_free (password);
}
gtk_entry_set_visibility (GTK_ENTRY (userdata), TRUE);
}
else
{
gtk_entry_set_visibility (GTK_ENTRY (userdata), FALSE);
if (edit_loaded_password && !edit_pass_changed)
servlist_entry_set_text_silent (userdata, "***");
}
}
static void
servlist_toggle_keyring_cb (GtkToggleButton *toggle, gpointer userdata)
{
servlist_update_password_tools (selected_net);
}
static void
servlist_password_changed_cb (GtkEditable *editable, gpointer userdata)
{
edit_pass_changed = 1;
if (edit_loaded_password && strcmp (gtk_entry_get_text (GTK_ENTRY (editable)), "***"))
{
memset (edit_loaded_password, 0, strlen (edit_loaded_password));
g_free (edit_loaded_password);
edit_loaded_password = NULL;
}
servlist_update_password_tools (selected_net);
}
static void
servlist_encrypt_password_cb (GtkWidget *button, gpointer userdata)
{
ircnet *net = userdata;
char *plain;
char *enc;
if (!net || (net->flags & FLAG_USE_KEYRING) || !net->pass || servlist_password_is_encrypted (net->pass))
return;
plain = servlist_password_decrypt_for_storage (net->pass);
if (!plain || !*plain)
{
if (plain)
{
memset (plain, 0, strlen (plain));
g_free (plain);
}
return;
}
enc = servlist_password_encrypt_for_storage (plain);
memset (plain, 0, strlen (plain));
g_free (plain);
if (!enc)
{
fe_message (_("Could not encrypt this password."), FE_MSG_WARN);
return;
}
g_free (net->pass);
net->pass = enc;
servlist_save ();
servlist_update_password_tools (net);
}
static void
servlist_import_password_cb (GtkWidget *button, gpointer userdata)
{
ircnet *net = userdata;
char *plain;
if (!net || !net->name || (net->flags & FLAG_USE_KEYRING) || !net->pass || !*net->pass)
return;
plain = servlist_password_decrypt_for_storage (net->pass);
if (!plain || !*plain)
{
if (plain)
{
memset (plain, 0, strlen (plain));
g_free (plain);
}
return;
}
if (!secretstore_set_network_password (net->name, plain))
{
memset (plain, 0, strlen (plain));
g_free (plain);
fe_message (_("Could not move this password into the system keyring."), FE_MSG_WARN);
return;
}
memset (plain, 0, strlen (plain));
g_free (plain);
g_free (net->pass);
net->pass = NULL;
net->flags |= FLAG_USE_KEYRING;
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (edit_check_use_keyring), TRUE);
servlist_entry_set_text_silent (edit_entry_pass, "***");
edit_pass_changed = 0;
servlist_save ();
servlist_update_password_tools (net);
}
static char *
servlist_get_cert_file (ircnet *net)
@@ -1247,79 +1078,14 @@ servlist_update_from_entry (char **str, GtkWidget *entry)
*str = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
}
static char *
servlist_edit_current_password (ircnet *net)
{
if (!net)
return NULL;
if (net->flags & FLAG_USE_KEYRING)
return secretstore_get_network_password (net->name);
return servlist_password_decrypt_for_storage (net->pass);
}
static void
servlist_edit_update (ircnet *net)
{
gboolean use_keyring;
gboolean keyring_changed;
char *password = NULL;
servlist_update_from_entry (&net->nick, edit_entry_nick);
servlist_update_from_entry (&net->nick2, edit_entry_nick2);
servlist_update_from_entry (&net->user, edit_entry_user);
servlist_update_from_entry (&net->real, edit_entry_real);
if (net && net->name)
{
use_keyring = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (edit_check_use_keyring));
keyring_changed = !!(net->flags & FLAG_USE_KEYRING) != !!use_keyring;
if (!edit_pass_changed && !keyring_changed)
return;
if (edit_pass_changed)
password = g_strdup (gtk_entry_get_text (GTK_ENTRY (edit_entry_pass)));
else
password = servlist_edit_current_password (net);
if (use_keyring)
{
if (password && *password)
{
if (!secretstore_set_network_password (net->name, password))
{
fe_message (_("No system keyring is available. ZoiteChat can save this password using local encrypted fallback storage, but it is less protected than your desktop keyring."), FE_MSG_WARN);
memset (password, 0, strlen (password));
g_free (password);
return;
}
}
else
secretstore_delete_network_password (net->name);
net->flags |= FLAG_USE_KEYRING;
g_free (net->pass);
net->pass = NULL;
}
else
{
char *enc = NULL;
if (password && *password)
{
enc = servlist_password_encrypt_for_storage (password);
if (!enc)
{
fe_message (_("Could not encrypt this password."), FE_MSG_WARN);
memset (password, 0, strlen (password));
g_free (password);
return;
}
}
secretstore_delete_network_password (net->name);
net->flags &= ~FLAG_USE_KEYRING;
g_free (net->pass);
net->pass = enc;
}
if (password)
{
memset (password, 0, strlen (password));
g_free (password);
}
}
servlist_update_from_entry (&net->pass, edit_entry_pass);
}
static void
@@ -1327,19 +1093,9 @@ servlist_edit_close_cb (GtkWidget *button, gpointer userdata)
{
if (selected_net)
servlist_edit_update (selected_net);
if (edit_loaded_password)
{
memset (edit_loaded_password, 0, strlen (edit_loaded_password));
g_free (edit_loaded_password);
edit_loaded_password = NULL;
}
gtk_widget_destroy (edit_win);
edit_win = NULL;
edit_entry_pass = NULL;
edit_check_show_pass = NULL;
edit_button_encrypt_pass = NULL;
edit_button_import_pass = NULL;
}
static gint
@@ -1370,10 +1126,6 @@ servlist_edit_cb (GtkWidget *but, gpointer none)
{
if (!servlist_has_selection (GTK_TREE_VIEW (networks_tree)))
return;
if (!selected_net || !selected_net->name)
return;
if ((selected_net->flags & FLAG_USE_KEYRING) && !secretstore_require_unlock (selected_net->name))
return;
edit_win = servlist_open_edit (serverlist_win, selected_net);
gtkutil_set_icon (edit_win);
@@ -2565,7 +2317,7 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
/* Checkboxes and entries */
table3 = gtkutil_grid_new (17, 2, FALSE);
table3 = gtkutil_grid_new (14, 2, FALSE);
gtk_box_pack_start (GTK_BOX (vbox5), table3, FALSE, FALSE, 0);
gtk_grid_set_row_spacing (GTK_GRID (table3), 2);
gtk_grid_set_column_spacing (GTK_GRID (table3), 8);
@@ -2584,97 +2336,38 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
#endif
servlist_create_check (1, net->flags & FLAG_USE_GLOBAL, table3, 5, 0, _("Use global user information"));
edit_check_use_keyring = gtk_check_button_new_with_mnemonic (_("Use system keyring"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (edit_check_use_keyring), net->flags & FLAG_USE_KEYRING);
servlist_table_attach (table3, edit_check_use_keyring, 0, 2, 6, 7,
FALSE, FALSE,
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
g_signal_connect (G_OBJECT (edit_check_use_keyring), "toggled",
G_CALLBACK (servlist_toggle_keyring_cb), NULL);
edit_entry_nick = servlist_create_entry (table3, _("_Nick name:"), 7, net->nick, &edit_label_nick, 0);
edit_entry_nick2 = servlist_create_entry (table3, _("Second choice:"), 8, net->nick2, &edit_label_nick2, 0);
edit_entry_real = servlist_create_entry (table3, _("Rea_l name:"), 9, net->real, &edit_label_real, 0);
edit_entry_user = servlist_create_entry (table3, _("_User name:"), 10, net->user, &edit_label_user, 0);
edit_entry_nick = servlist_create_entry (table3, _("_Nick name:"), 6, net->nick, &edit_label_nick, 0);
edit_entry_nick2 = servlist_create_entry (table3, _("Second choice:"), 7, net->nick2, &edit_label_nick2, 0);
edit_entry_real = servlist_create_entry (table3, _("Rea_l name:"), 8, net->real, &edit_label_real, 0);
edit_entry_user = servlist_create_entry (table3, _("_User name:"), 9, net->user, &edit_label_user, 0);
label_logintype = gtk_label_new (_("Login method:"));
servlist_table_attach (table3, label_logintype, 0, 1, 11, 12,
servlist_table_attach (table3, label_logintype, 0, 1, 10, 11,
FALSE, FALSE,
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
gtk_widget_set_halign (label_logintype, GTK_ALIGN_START);
gtk_widget_set_valign (label_logintype, GTK_ALIGN_CENTER);
combobox_logintypes = servlist_create_logintypecombo (notebook);
servlist_table_attach (table3, combobox_logintypes, 1, 2, 11, 12,
servlist_table_attach (table3, combobox_logintypes, 1, 2, 10, 11,
FALSE, FALSE,
SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_FILL,
4, 2);
edit_entry_pass = servlist_create_entry (table3, _("Password:"), 12, NULL, 0, _("Password used for login. If in doubt, leave blank."));
if (edit_loaded_password)
{
memset (edit_loaded_password, 0, strlen (edit_loaded_password));
g_free (edit_loaded_password);
edit_loaded_password = NULL;
}
edit_pass_changed = 0;
g_signal_connect (G_OBJECT (edit_entry_pass), "changed",
G_CALLBACK (servlist_password_changed_cb), NULL);
if (net->flags & FLAG_USE_KEYRING)
{
char *stored = secretstore_get_network_password (net->name);
if (stored && *stored)
{
edit_loaded_password = g_strdup (stored);
servlist_entry_set_text_silent (edit_entry_pass, "***");
}
if (stored)
{
memset (stored, 0, strlen (stored));
g_free (stored);
}
}
else if (net->pass && *net->pass)
{
servlist_entry_set_text_silent (edit_entry_pass, "***");
}
edit_pass_changed = 0;
edit_entry_pass = servlist_create_entry (table3, _("Password:"), 11, net->pass, 0, _("Password used for login. If in doubt, leave blank."));
gtk_entry_set_visibility (GTK_ENTRY (edit_entry_pass), FALSE);
if (selected_net && selected_net->logintype == LOGIN_SASLEXTERNAL)
gtk_widget_set_sensitive (edit_entry_pass, FALSE);
edit_check_show_pass = gtk_check_button_new_with_mnemonic (_("Show password"));
servlist_table_attach (table3, edit_check_show_pass, 0, 2, 13, 14,
FALSE, FALSE,
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
4, 2);
g_signal_connect (G_OBJECT (edit_check_show_pass), "toggled",
G_CALLBACK (servlist_toggle_show_password_cb), edit_entry_pass);
edit_button_encrypt_pass = gtk_button_new_with_mnemonic (_("Encrypt saved password"));
servlist_table_attach (table3, edit_button_encrypt_pass, 0, 1, 14, 15,
FALSE, FALSE,
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
g_signal_connect (G_OBJECT (edit_button_encrypt_pass), "clicked",
G_CALLBACK (servlist_encrypt_password_cb), net);
edit_button_import_pass = gtk_button_new_with_mnemonic (_("Move password to keyring"));
servlist_table_attach (table3, edit_button_import_pass, 1, 2, 14, 15,
FALSE, FALSE,
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
4, 2);
g_signal_connect (G_OBJECT (edit_button_import_pass), "clicked",
G_CALLBACK (servlist_import_password_cb), net);
label34 = gtk_label_new (_("Character set:"));
servlist_table_attach (table3, label34, 0, 1, 15, 16,
servlist_table_attach (table3, label34, 0, 1, 12, 13,
FALSE, FALSE,
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
gtk_widget_set_halign (label34, GTK_ALIGN_START);
gtk_widget_set_valign (label34, GTK_ALIGN_CENTER);
comboboxentry_charset = servlist_create_charsetcombo ();
servlist_table_attach (table3, comboboxentry_charset, 1, 2, 15, 16,
servlist_table_attach (table3, comboboxentry_charset, 1, 2, 12, 13,
FALSE, FALSE,
SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_FILL,
4, 2);
@@ -2700,7 +2393,7 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
G_CALLBACK (servlist_delete_client_cert_cb), net);
gtk_box_pack_start (GTK_BOX (hbox_cert_buttons), edit_button_cert_delete, FALSE, FALSE, 0);
servlist_table_attach (table3, hbox_cert_buttons, 0, 2, 16, 17,
servlist_table_attach (table3, hbox_cert_buttons, 0, 2, 13, 14,
FALSE, FALSE,
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
@@ -2724,8 +2417,6 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
{
servlist_toggle_global_user (FALSE);
}
servlist_toggle_keyring_cb (GTK_TOGGLE_BUTTON (edit_check_use_keyring), NULL);
servlist_update_password_tools (net);
gtk_widget_grab_focus (button10);
gtk_widget_grab_default (button10);

View File

@@ -193,7 +193,6 @@ static const setting appearance_advanced_settings[] =
{ST_HEADER, N_("Advanced"),0,0,0},
{ST_EFILE, N_ ("Background image:"), P_OFFSETNL (hex_text_background), 0, 0, sizeof prefs.hex_text_background},
{ST_HSCALE, N_("Window opacity:"), P_OFFINTNL(hex_gui_transparency),0,0,0},
{ST_HSCALE, N_("Mouse wheel scroll speed (Slower ← → Faster):"), P_OFFINTNL(hex_gui_mouse_scroll_speed), 0, 0, 100},
{ST_END, 0, 0, 0, 0, 0}
};
@@ -546,7 +545,6 @@ static const setting general_settings[] =
{ST_TOGGLE, N_("WHOIS on notify"), P_OFFINTNL(hex_notify_whois_online), N_("Sends a /WHOIS when a user comes online in your notify list."), 0, 0},
{ST_TOGGLE, N_("Hide join and part messages"), P_OFFINTNL(hex_irc_conf_mode), N_("Hide channel join/part messages by default."), 0, 0},
{ST_TOGGLE, N_("Hide nick change messages"), P_OFFINTNL(hex_irc_hide_nickchange), 0, 0, 0},
{ST_TOGGLE, N_("Hide hostmasks in join and part messages"), P_OFFINTNL(hex_irc_hide_join_part_hostmask), 0, 0, 0},
{ST_TOGGLE, N_("Enable Ctrl+Q to quit"), P_OFFINTNL(hex_gui_ctrlq_quit), 0, 0, 0},
{ST_END, 0, 0, 0, 0, 0}
@@ -584,7 +582,6 @@ static const setting advanced_settings[] =
{ST_TOGGLE, N_("Display lists in compact mode"), P_OFFINTNL(hex_gui_compact), N_("Use less spacing between user list/channel tree rows."), 0, 0},
{ST_TOGGLE, N_("Use server time if supported"), P_OFFINTNL(hex_irc_cap_server_time), N_("Display timestamps obtained from server if it supports the time-server extension."), 0, 0},
{ST_TOGGLE, N_("Automatically reconnect to servers on disconnect"), P_OFFINTNL(hex_net_auto_reconnect), 0, 0, 1},
{ST_NUMBER, N_("Lag check interval:"), P_OFFINTNL(hex_net_lag_check), 0, (const char **)N_("seconds."), 9999},
{ST_NUMBER, N_("Auto reconnect delay:"), P_OFFINTNL(hex_net_reconnect_delay), 0, 0, 9999},
{ST_NUMBER, N_("Auto join delay:"), P_OFFINTNL(hex_irc_join_delay), 0, 0, 9999},
{ST_MENU, N_("Ban Type:"), P_OFFINTNL(hex_irc_ban_type), N_("Attempt to use this banmask when banning or quieting. (requires irc_who_join)"), bantypemenu, 0},
@@ -658,11 +655,6 @@ static const setting network_settings[] =
{ST_MENU, N_("Type:"), P_OFFINTNL(hex_net_proxy_type), 0, proxytypes, 0},
{ST_MENU, N_("Use proxy for:"), P_OFFINTNL(hex_net_proxy_use), 0, proxyuse, 0},
{ST_HEADER, N_("Connection Health"), 0, 0, 0, 0},
{ST_NUMBER, N_("TCP keepalive idle:"), P_OFFINTNL(hex_net_keepalive_idle), 0, (const char **)N_("seconds."), 7200},
{ST_NUMBER, N_("TCP keepalive interval:"), P_OFFINTNL(hex_net_keepalive_interval), 0, (const char **)N_("seconds."), 600},
{ST_NUMBER, N_("TCP keepalive probes:"), P_OFFINTNL(hex_net_keepalive_count), 0, 0, 20},
{ST_HEADER, N_("Proxy Authentication"), 0, 0, 0, 0},
{ST_TOGGLE, N_("Use authentication (HTTP or SOCKS5 only)"), P_OFFINTNL(hex_net_proxy_auth), 0, 0, 0},
{ST_ENTRY, N_("Username:"), P_OFFSETNL(hex_net_proxy_user), 0, 0, sizeof prefs.hex_net_proxy_user},

View File

@@ -107,23 +107,12 @@ theme_manager_reset_mode_colors (unsigned int mode, gboolean *palette_changed)
*palette_changed = FALSE;
}
void
theme_runtime_clear_gtk_mapped_custom_tokens (void)
{
}
gboolean
theme_manager_save_preferences (void)
{
return TRUE;
}
void
theme_manager_apply_to_window (GtkWidget *window)
{
(void)window;
}
void
theme_manager_dispatch_changed (ThemeChangedReason reasons)
{

View File

@@ -88,15 +88,9 @@ theme_application_apply_toplevel_theme (gboolean dark)
gboolean
theme_application_apply_mode (unsigned int mode, gboolean *palette_changed)
{
static gboolean runtime_loaded = FALSE;
gboolean dark;
if (!runtime_loaded)
{
theme_runtime_load ();
runtime_loaded = TRUE;
}
theme_runtime_load ();
dark = theme_runtime_apply_mode (mode, palette_changed);
theme_application_apply_toplevel_theme (dark);

View File

@@ -35,7 +35,6 @@
#include "theme-gtk3.h"
#include "theme-manager.h"
#include "theme-preferences.h"
#include "theme-runtime.h"
extern void load_text_events (void);
@@ -1418,56 +1417,17 @@ theme_preferences_gtk3_sync_remove_state (theme_preferences_ui *ui)
gtk_widget_set_sensitive (ui->gtk3_remove, source == ZOITECHAT_GTK3_THEME_SOURCE_USER);
}
static void
theme_preferences_gtk3_sync_runtime_palette (theme_preferences_ui *ui)
{
ThemeWidgetStyleValues style_values;
GtkWidget *style_source = NULL;
if (ui && ui->parent)
style_source = GTK_WIDGET (ui->parent);
else if (ui && ui->gtk3_combo)
style_source = ui->gtk3_combo;
theme_runtime_clear_gtk_mapped_custom_tokens ();
theme_get_widget_style_values_for_widget (style_source, &style_values);
theme_preferences_staged_set_color (THEME_TOKEN_TEXT_FOREGROUND,
&style_values.foreground,
NULL,
TRUE);
theme_preferences_staged_set_color (THEME_TOKEN_TEXT_BACKGROUND,
&style_values.background,
NULL,
TRUE);
theme_preferences_staged_set_color (THEME_TOKEN_SELECTION_FOREGROUND,
&style_values.selection_foreground,
NULL,
TRUE);
theme_preferences_staged_set_color (THEME_TOKEN_SELECTION_BACKGROUND,
&style_values.selection_background,
NULL,
TRUE);
}
static gboolean
theme_preferences_gtk3_apply_and_refresh (theme_preferences_ui *ui, GError **error)
theme_preferences_gtk3_apply_and_refresh (GError **error)
{
if (!theme_gtk3_apply_current (error))
return FALSE;
if (ui && ui->parent)
theme_manager_apply_to_window (GTK_WIDGET (ui->parent));
theme_preferences_gtk3_sync_runtime_palette (ui);
theme_manager_dispatch_changed (THEME_CHANGED_REASON_THEME_PACK |
THEME_CHANGED_REASON_PALETTE |
THEME_CHANGED_REASON_WIDGET_STYLE |
THEME_CHANGED_REASON_USERLIST |
THEME_CHANGED_REASON_MODE);
return TRUE;
if (!theme_gtk3_apply_current (error))
return FALSE;
theme_manager_dispatch_changed (THEME_CHANGED_REASON_THEME_PACK |
THEME_CHANGED_REASON_PALETTE |
THEME_CHANGED_REASON_WIDGET_STYLE |
THEME_CHANGED_REASON_USERLIST |
THEME_CHANGED_REASON_MODE);
return TRUE;
}
static void
@@ -1503,7 +1463,7 @@ theme_preferences_gtk3_changed_cb (GtkComboBox *combo, gpointer user_data)
ui->setup_prefs->hex_gui_gtk3_variant = prefs.hex_gui_gtk3_variant;
}
if (selection_changed && !theme_preferences_gtk3_apply_and_refresh (ui, &error))
if (selection_changed && !theme_preferences_gtk3_apply_and_refresh (&error))
{
theme_preferences_show_message (ui, GTK_MESSAGE_ERROR,
error ? error->message : _("Failed to apply GTK3 theme."));
@@ -1592,7 +1552,7 @@ theme_preferences_populate_gtk3 (theme_preferences_ui *ui)
g_free (final_id);
}
if (should_apply && !theme_preferences_gtk3_apply_and_refresh (ui, &error))
if (should_apply && !theme_preferences_gtk3_apply_and_refresh (&error))
{
theme_preferences_show_message (ui, GTK_MESSAGE_ERROR,
error ? error->message : _("Failed to apply GTK3 theme."));

View File

@@ -410,20 +410,6 @@ theme_runtime_reset_mode_colors (gboolean dark_mode)
dark_mode_active = FALSE;
}
void
theme_runtime_clear_gtk_mapped_custom_tokens (void)
{
light_custom_tokens[THEME_TOKEN_TEXT_FOREGROUND] = FALSE;
light_custom_tokens[THEME_TOKEN_TEXT_BACKGROUND] = FALSE;
light_custom_tokens[THEME_TOKEN_SELECTION_FOREGROUND] = FALSE;
light_custom_tokens[THEME_TOKEN_SELECTION_BACKGROUND] = FALSE;
dark_custom_tokens[THEME_TOKEN_TEXT_FOREGROUND] = FALSE;
dark_custom_tokens[THEME_TOKEN_TEXT_BACKGROUND] = FALSE;
dark_custom_tokens[THEME_TOKEN_SELECTION_FOREGROUND] = FALSE;
dark_custom_tokens[THEME_TOKEN_SELECTION_BACKGROUND] = FALSE;
}
void
theme_runtime_load (void)
{

View File

@@ -47,7 +47,6 @@ gboolean theme_runtime_apply_dark_mode (gboolean enable);
void theme_runtime_user_set_color (ThemeSemanticToken token, const GdkRGBA *col);
void theme_runtime_dark_set_color (ThemeSemanticToken token, const GdkRGBA *col);
void theme_runtime_reset_mode_colors (gboolean dark_mode);
void theme_runtime_clear_gtk_mapped_custom_tokens (void);
gboolean theme_runtime_get_color (ThemeSemanticToken token, GdkRGBA *out_rgba);
gboolean theme_runtime_mode_has_user_colors (gboolean dark_mode);
void theme_runtime_get_widget_style_values (ThemeWidgetStyleValues *out_values);

View File

@@ -2300,12 +2300,6 @@ gtk_xtext_leave_notify (GtkWidget * widget, GdkEventCrossing * event)
xtext->hilight_ent = NULL;
}
if (xtext->tooltip_stamp_set)
{
gtk_widget_set_tooltip_text (widget, NULL);
xtext->tooltip_stamp_set = FALSE;
}
return FALSE;
}
@@ -2472,7 +2466,7 @@ gtk_xtext_motion_notify (GtkWidget * widget, GdkEventMotion * event)
}
if (xtext->urlcheck_function == NULL)
goto tooltip_check;
return FALSE;
word_type = gtk_xtext_get_word_adjust (xtext, x, y, &word_ent, &offset, &len);
if (word_type > 0)
@@ -2510,46 +2504,6 @@ gtk_xtext_motion_notify (GtkWidget * widget, GdkEventMotion * event)
return FALSE;
}
tooltip_check:
if (xtext->buffer->time_stamp && xtext->buffer->indent > 0 && x >= 0 && x < xtext->stamp_width)
{
textentry *ent = gtk_xtext_find_char (xtext, x, y, NULL, NULL);
if (ent && (!xtext->tooltip_stamp_set || xtext->tooltip_stamp != ent->stamp))
{
char tooltip[96];
strftime_utf8 (tooltip, sizeof (tooltip), "%Y-%m-%d", ent->stamp);
gtk_widget_set_tooltip_text (widget, tooltip);
xtext->tooltip_stamp = ent->stamp;
xtext->tooltip_stamp_set = TRUE;
}
if (ent)
return FALSE;
}
else if (!xtext->buffer->time_stamp && x >= xtext->buffer->indent)
{
textentry *ent = gtk_xtext_find_char (xtext, x, y, NULL, NULL);
if (ent && ent->stamp && (!xtext->tooltip_stamp_set || xtext->tooltip_stamp != ent->stamp))
{
char tooltip[128];
char date[64];
char *stamp_text;
strftime_utf8 (date, sizeof (date), "%Y-%m-%d", ent->stamp);
xtext_get_stamp_str (ent->stamp, &stamp_text);
g_snprintf (tooltip, sizeof (tooltip), "%s %s", date, stamp_text);
gtk_widget_set_tooltip_text (widget, tooltip);
g_free (stamp_text);
xtext->tooltip_stamp = ent->stamp;
xtext->tooltip_stamp_set = TRUE;
}
if (ent)
return FALSE;
}
else if (xtext->tooltip_stamp_set)
{
gtk_widget_set_tooltip_text (widget, NULL);
xtext->tooltip_stamp_set = FALSE;
}
gtk_xtext_leave_notify (widget, NULL);
return FALSE;
@@ -2984,41 +2938,19 @@ gtk_xtext_scroll (GtkWidget *widget, GdkEventScroll *event)
{
GtkXText *xtext = GTK_XTEXT (widget);
gfloat new_value;
gfloat step;
gdouble dx;
gdouble dy;
int direction = 0;
int speed = prefs.hex_gui_mouse_scroll_speed;
if (speed < 1)
speed = 1;
step = (xtext_adj_get_page_increment (xtext->adj) * speed) / 100.0f;
if (event->direction == GDK_SCROLL_SMOOTH &&
gdk_event_get_scroll_deltas ((GdkEvent *)event, &dx, &dy))
{
if (dy > 0)
direction = 1;
else if (dy < 0)
direction = -1;
}
else if (event->direction == GDK_SCROLL_UP)
direction = -1;
else if (event->direction == GDK_SCROLL_DOWN)
direction = 1;
if (direction < 0)
if (event->direction == GDK_SCROLL_UP) /* mouse wheel pageUp */
{
new_value = xtext_adj_get_value (xtext->adj) -
step;
(xtext_adj_get_page_increment (xtext->adj) / 10);
if (new_value < xtext_adj_get_lower (xtext->adj))
new_value = xtext_adj_get_lower (xtext->adj);
xtext_adj_set_value (xtext->adj, new_value);
}
else if (direction > 0)
else if (event->direction == GDK_SCROLL_DOWN) /* mouse wheel pageDn */
{
new_value = xtext_adj_get_value (xtext->adj) +
step;
(xtext_adj_get_page_increment (xtext->adj) / 10);
if (new_value > (xtext_adj_get_upper (xtext->adj) -
xtext_adj_get_page_size (xtext->adj)))
new_value = xtext_adj_get_upper (xtext->adj) -
@@ -3026,7 +2958,7 @@ gtk_xtext_scroll (GtkWidget *widget, GdkEventScroll *event)
xtext_adj_set_value (xtext->adj, new_value);
}
return direction != 0;
return FALSE;
}
static void

View File

@@ -190,8 +190,6 @@ struct _GtkXText
textentry *hilight_ent;
int hilight_start;
int hilight_end;
time_t tooltip_stamp;
unsigned int tooltip_stamp_set:1;
guint16 fontwidth[128]; /* each char's width, only the ASCII ones */

View File

@@ -128,7 +128,7 @@
<ArchiveDefs Condition="'$(ArchiveLib)'=='archive_static.lib' or '$(ArchiveLib)'=='libarchive_static.lib'">LIBARCHIVE_STATIC</ArchiveDefs>
<DepLibs>$(Gtk3Lib);$(Gdk3Lib);wininet.lib;winmm.lib;ws2_32.lib;advapi32.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;$(IntlLib);$(IconvLib);$(ZlibLib);$(Xml2Lib);$(JpegLib);$(PngLib);$(ArchiveLib);$(OpenSslLibs)</DepLibs>
<DepLibs>$(Gtk3Lib);$(Gdk3Lib);wininet.lib;winmm.lib;ws2_32.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;$(IntlLib);$(IconvLib);$(ZlibLib);$(Xml2Lib);$(JpegLib);$(PngLib);$(ArchiveLib);$(OpenSslLibs)</DepLibs>
<DataDir>$(SolutionDir)..\data\\</DataDir>
<ZoiteChatBuild>$(SolutionDir)..\..\zoitechat-build</ZoiteChatBuild>