mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-06-17 03:59:24 +00:00
Compare commits
7 Commits
bb08b19c0d
...
fishlim-ma
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ded7ef830 | |||
| adb18b7ce3 | |||
| b09af655e7 | |||
|
|
72132d5e88 | ||
|
|
4167c4db78 | ||
| 3e1f6b9137 | |||
| d1707d3c72 |
@@ -26,7 +26,7 @@
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;FISHLIM_EXPORTS;HAVE_DH_SET0_PQG;HAVE_DH_GET0_KEY;HAVE_DH_SET0_KEY;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(OpenSslInclude);$(Glib);..\..\src\common;$(ZoiteChatLib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(OpenSslInclude);$(Glib);$(Gtk);..\..\src\common;$(ZoiteChatLib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<ModuleDefinitionFile>fishlim.def</ModuleDefinitionFile>
|
||||
|
||||
@@ -194,6 +194,18 @@ static gboolean keyfile_save_to_file (GKeyFile *keyfile, char *filename) {
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
gchar **keystore_get_targets(gsize *length) {
|
||||
GKeyFile *keyfile;
|
||||
gchar **groups;
|
||||
|
||||
keyfile = getConfigFile();
|
||||
groups = g_key_file_get_groups(keyfile, length);
|
||||
g_key_file_free(keyfile);
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the key store file to disk.
|
||||
*/
|
||||
@@ -217,6 +229,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
/**
|
||||
* Sets a key in the key store file.
|
||||
*/
|
||||
|
||||
gboolean keystore_store_key(const char *nick, const char *key, enum fish_mode mode) {
|
||||
const char *password;
|
||||
char *encrypted;
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
char *keystore_get_key(const char *nick, enum fish_mode *mode);
|
||||
gboolean keystore_store_key(const char *nick, const char *key, enum fish_mode mode);
|
||||
gboolean keystore_delete_nick(const char *nick);
|
||||
gchar **keystore_get_targets(gsize *length);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ fishlim_sources = [
|
||||
]
|
||||
|
||||
shared_module('fishlim', fishlim_sources,
|
||||
dependencies: [libgio_dep, zoitechat_plugin_dep, libssl_dep],
|
||||
dependencies: [libgio_dep, gtk_dep, zoitechat_plugin_dep, libssl_dep],
|
||||
c_args: ['-DOPENSSL_API_COMPAT=0x10100000L'],
|
||||
install: true,
|
||||
install_dir: plugindir,
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "zoitechat-plugin.h"
|
||||
@@ -44,7 +45,7 @@ static const char plugin_version[] = "1.0.0";
|
||||
|
||||
static const char usage_setkey[] = "Usage: SETKEY [<nick or #channel>] [<mode>:]<password>, sets the key for a channel or nick. Modes: ECB, CBC";
|
||||
static const char usage_delkey[] = "Usage: DELKEY [<nick or #channel>], deletes the key for a channel or nick";
|
||||
static const char usage_keyx[] = "Usage: KEYX [<nick>], performs DH1080 key-exchange with <nick>";
|
||||
static const char usage_keyx[] = "Usage: KEYX [<nick>] [ECB|CBC], performs DH1080 key-exchange with <nick>";
|
||||
static const char usage_topic[] = "Usage: TOPIC+ <topic>, sets a new encrypted topic for the current channel";
|
||||
static const char usage_notice[] = "Usage: NOTICE+ <nick or #channel> <notice>";
|
||||
static const char usage_msg[] = "Usage: MSG+ <nick or #channel> <message>";
|
||||
@@ -52,6 +53,13 @@ static const char usage_msg[] = "Usage: MSG+ <nick or #channel> <message>";
|
||||
|
||||
static zoitechat_plugin *ph;
|
||||
static GHashTable *pending_exchanges;
|
||||
static GtkWidget *fishlim_dialog;
|
||||
static GtkWidget *fishlim_target_entry;
|
||||
static GtkWidget *fishlim_key_entry;
|
||||
static GtkWidget *fishlim_mode_combo;
|
||||
static GtkWidget *fishlim_status_label;
|
||||
static GtkListStore *fishlim_store;
|
||||
static GtkWidget *fishlim_view;
|
||||
|
||||
|
||||
/**
|
||||
@@ -455,6 +463,314 @@ cleanup:
|
||||
return ZOITECHAT_EAT_ALL;
|
||||
}
|
||||
|
||||
|
||||
static const char *fishlim_gui_target(void) {
|
||||
const char *target;
|
||||
|
||||
target = gtk_entry_get_text(GTK_ENTRY(fishlim_target_entry));
|
||||
if (target && *target)
|
||||
return target;
|
||||
|
||||
return zoitechat_get_info(ph, "channel");
|
||||
}
|
||||
|
||||
static void fishlim_gui_refresh(void) {
|
||||
GtkTreeIter iter;
|
||||
gchar **targets;
|
||||
gsize length, i;
|
||||
const char *target;
|
||||
char *key;
|
||||
enum fish_mode mode;
|
||||
|
||||
if (!fishlim_dialog)
|
||||
return;
|
||||
|
||||
gtk_list_store_clear(fishlim_store);
|
||||
targets = keystore_get_targets(&length);
|
||||
|
||||
for (i = 0; targets && i < length; i++) {
|
||||
key = keystore_get_key(targets[i], &mode);
|
||||
gtk_list_store_append(fishlim_store, &iter);
|
||||
gtk_list_store_set(fishlim_store, &iter, 0, targets[i], 1, fish_modes[mode], 2, key ? "Stored" : "Unreadable", -1);
|
||||
g_free(key);
|
||||
}
|
||||
|
||||
g_strfreev(targets);
|
||||
|
||||
target = fishlim_gui_target();
|
||||
key = target ? keystore_get_key(target, &mode) : NULL;
|
||||
|
||||
if (key) {
|
||||
char *text = g_strdup_printf("Key stored for %s (%s)", target, fish_modes[mode]);
|
||||
gtk_label_set_text(GTK_LABEL(fishlim_status_label), text);
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(fishlim_mode_combo), mode == FISH_CBC_MODE ? 1 : 0);
|
||||
g_free(text);
|
||||
g_free(key);
|
||||
} else if (target && *target) {
|
||||
char *text = g_strdup_printf("No key for %s", target);
|
||||
gtk_label_set_text(GTK_LABEL(fishlim_status_label), text);
|
||||
g_free(text);
|
||||
} else {
|
||||
gtk_label_set_text(GTK_LABEL(fishlim_status_label), "No target selected");
|
||||
}
|
||||
}
|
||||
|
||||
static void fishlim_gui_refresh_cb(GtkWidget *widget, gpointer data) {
|
||||
fishlim_gui_refresh();
|
||||
}
|
||||
|
||||
static void fishlim_gui_send_channel_key(const char *channel, const char *mode, const char *key) {
|
||||
GtkWidget *dialog, *content, *entry, *label;
|
||||
char **users;
|
||||
int i;
|
||||
|
||||
if (!channel || !*channel || irc_is_query(channel))
|
||||
return;
|
||||
|
||||
dialog = gtk_dialog_new_with_buttons("Share Channel Key", GTK_WINDOW(fishlim_dialog), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, "_Skip", GTK_RESPONSE_CANCEL, "_Send", GTK_RESPONSE_OK, NULL);
|
||||
content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
||||
label = gtk_label_new("Send this channel key to users by private message. Enter users separated by commas.");
|
||||
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
|
||||
gtk_box_pack_start(GTK_BOX(content), label, FALSE, FALSE, 6);
|
||||
entry = gtk_entry_new();
|
||||
gtk_entry_set_placeholder_text(GTK_ENTRY(entry), "nick1, nick2, nick3");
|
||||
gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
|
||||
gtk_box_pack_start(GTK_BOX(content), entry, FALSE, FALSE, 6);
|
||||
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
|
||||
gtk_widget_show_all(dialog);
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
|
||||
users = g_strsplit(gtk_entry_get_text(GTK_ENTRY(entry)), ",", -1);
|
||||
for (i = 0; users && users[i]; i++) {
|
||||
char *user = g_strstrip(users[i]);
|
||||
if (*user)
|
||||
zoitechat_commandf(ph, "msg %s Encrypted chat invite: join %s, open FiSHLiM Key Manager, add channel %s with %s key: %s. Key exchange is for private messages only.", user, channel, channel, mode, key);
|
||||
}
|
||||
g_strfreev(users);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
static void fishlim_gui_set(GtkWidget *widget, gpointer data) {
|
||||
const char *target = fishlim_gui_target();
|
||||
const char *key = gtk_entry_get_text(GTK_ENTRY(fishlim_key_entry));
|
||||
const char *mode = gtk_combo_box_get_active(GTK_COMBO_BOX(fishlim_mode_combo)) == 1 ? "CBC" : "ECB";
|
||||
|
||||
if (!target || !*target || !key || !*key) {
|
||||
zoitechat_printf(ph, "%s\n", usage_setkey);
|
||||
return;
|
||||
}
|
||||
|
||||
zoitechat_commandf(ph, "SETKEY %s %s:%s", target, mode, key);
|
||||
fishlim_gui_send_channel_key(target, mode, key);
|
||||
gtk_entry_set_text(GTK_ENTRY(fishlim_key_entry), "");
|
||||
fishlim_gui_refresh();
|
||||
}
|
||||
|
||||
static gboolean fishlim_gui_confirm_delete(const char *target) {
|
||||
GtkWidget *dialog;
|
||||
char *message;
|
||||
gboolean confirmed;
|
||||
|
||||
message = g_strdup_printf("Delete the key for %s?", target);
|
||||
dialog = gtk_message_dialog_new(GTK_WINDOW(fishlim_dialog), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, "%s", message);
|
||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "This cannot be undone.");
|
||||
gtk_dialog_add_buttons(GTK_DIALOG(dialog), "_Cancel", GTK_RESPONSE_CANCEL, "_Delete", GTK_RESPONSE_ACCEPT, NULL);
|
||||
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
|
||||
confirmed = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT;
|
||||
gtk_widget_destroy(dialog);
|
||||
g_free(message);
|
||||
return confirmed;
|
||||
}
|
||||
|
||||
static char *fishlim_gui_selected_target(void) {
|
||||
GtkTreeSelection *selection;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
char *target = NULL;
|
||||
|
||||
if (!fishlim_view)
|
||||
return NULL;
|
||||
|
||||
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(fishlim_view));
|
||||
if (gtk_tree_selection_get_selected(selection, &model, &iter))
|
||||
gtk_tree_model_get(model, &iter, 0, &target, -1);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
static void fishlim_gui_delete(GtkWidget *widget, gpointer data) {
|
||||
char *selected = fishlim_gui_selected_target();
|
||||
const char *target = selected ? selected : fishlim_gui_target();
|
||||
|
||||
if (!target || !*target) {
|
||||
zoitechat_printf(ph, "%s\n", usage_delkey);
|
||||
g_free(selected);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fishlim_gui_confirm_delete(target)) {
|
||||
zoitechat_commandf(ph, "DELKEY %s", target);
|
||||
fishlim_gui_refresh();
|
||||
}
|
||||
|
||||
g_free(selected);
|
||||
}
|
||||
|
||||
static char *fishlim_gui_prompt_target(const char *title, const char *initial) {
|
||||
GtkWidget *dialog, *content, *entry;
|
||||
char *target = NULL;
|
||||
|
||||
dialog = gtk_dialog_new_with_buttons(title, GTK_WINDOW(fishlim_dialog), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, "_Cancel", GTK_RESPONSE_CANCEL, "_OK", GTK_RESPONSE_OK, NULL);
|
||||
content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
||||
entry = gtk_entry_new();
|
||||
if (initial && *initial)
|
||||
gtk_entry_set_text(GTK_ENTRY(entry), initial);
|
||||
gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
|
||||
gtk_box_pack_start(GTK_BOX(content), gtk_label_new("Private message user"), FALSE, FALSE, 6);
|
||||
gtk_box_pack_start(GTK_BOX(content), entry, FALSE, FALSE, 6);
|
||||
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
|
||||
gtk_widget_show_all(dialog);
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
|
||||
const char *text = gtk_entry_get_text(GTK_ENTRY(entry));
|
||||
if (text && *text)
|
||||
target = g_strdup(text);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
return target;
|
||||
}
|
||||
|
||||
static void fishlim_gui_keyx(GtkWidget *widget, gpointer data) {
|
||||
char *target;
|
||||
const char *initial = fishlim_gui_target();
|
||||
const char *mode = gtk_combo_box_get_active(GTK_COMBO_BOX(fishlim_mode_combo)) == 1 ? "CBC" : "ECB";
|
||||
|
||||
if (!initial || !*initial || !irc_is_query(initial))
|
||||
initial = NULL;
|
||||
|
||||
target = fishlim_gui_prompt_target("Key Exchange", initial);
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
zoitechat_commandf(ph, "KEYX %s %s", target, mode);
|
||||
g_free(target);
|
||||
}
|
||||
|
||||
static void fishlim_gui_row_activated(GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *column, gpointer data) {
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(tree);
|
||||
GtkTreeIter iter;
|
||||
char *target;
|
||||
|
||||
if (!gtk_tree_model_get_iter(model, &iter, path))
|
||||
return;
|
||||
|
||||
gtk_tree_model_get(model, &iter, 0, &target, -1);
|
||||
gtk_entry_set_text(GTK_ENTRY(fishlim_target_entry), target);
|
||||
g_free(target);
|
||||
fishlim_gui_refresh();
|
||||
}
|
||||
|
||||
static void fishlim_gui_destroy(GtkWidget *widget, gpointer data) {
|
||||
fishlim_dialog = NULL;
|
||||
fishlim_target_entry = NULL;
|
||||
fishlim_key_entry = NULL;
|
||||
fishlim_mode_combo = NULL;
|
||||
fishlim_status_label = NULL;
|
||||
fishlim_store = NULL;
|
||||
fishlim_view = NULL;
|
||||
}
|
||||
|
||||
static int handle_fishlim(char *word[], char *word_eol[], void *userdata) {
|
||||
GtkWidget *content, *grid, *view, *scroll, *buttons, *button;
|
||||
GtkCellRenderer *renderer;
|
||||
const char *target;
|
||||
|
||||
target = *word_eol[2] ? word_eol[2] : zoitechat_get_info(ph, "channel");
|
||||
|
||||
if (fishlim_dialog) {
|
||||
if (target)
|
||||
gtk_entry_set_text(GTK_ENTRY(fishlim_target_entry), target);
|
||||
gtk_window_present(GTK_WINDOW(fishlim_dialog));
|
||||
return ZOITECHAT_EAT_ZOITECHAT;
|
||||
}
|
||||
|
||||
fishlim_dialog = gtk_dialog_new_with_buttons("FiSHLiM Key Manager", NULL, GTK_DIALOG_DESTROY_WITH_PARENT, "_Close", GTK_RESPONSE_CLOSE, NULL);
|
||||
gtk_window_set_default_size(GTK_WINDOW(fishlim_dialog), 520, 360);
|
||||
g_signal_connect(fishlim_dialog, "response", G_CALLBACK(gtk_widget_destroy), NULL);
|
||||
g_signal_connect(fishlim_dialog, "destroy", G_CALLBACK(fishlim_gui_destroy), NULL);
|
||||
|
||||
content = gtk_dialog_get_content_area(GTK_DIALOG(fishlim_dialog));
|
||||
grid = gtk_grid_new();
|
||||
gtk_grid_set_row_spacing(GTK_GRID(grid), 8);
|
||||
gtk_grid_set_column_spacing(GTK_GRID(grid), 8);
|
||||
gtk_container_set_border_width(GTK_CONTAINER(grid), 12);
|
||||
gtk_box_pack_start(GTK_BOX(content), grid, TRUE, TRUE, 0);
|
||||
|
||||
fishlim_target_entry = gtk_entry_new();
|
||||
if (target)
|
||||
gtk_entry_set_text(GTK_ENTRY(fishlim_target_entry), target);
|
||||
gtk_grid_attach(GTK_GRID(grid), gtk_label_new("Target nick or channel"), 0, 0, 1, 1);
|
||||
gtk_grid_attach(GTK_GRID(grid), fishlim_target_entry, 1, 0, 2, 1);
|
||||
|
||||
fishlim_mode_combo = gtk_combo_box_text_new();
|
||||
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(fishlim_mode_combo), "ECB");
|
||||
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(fishlim_mode_combo), "CBC");
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(fishlim_mode_combo), 1);
|
||||
gtk_grid_attach(GTK_GRID(grid), gtk_label_new("Mode"), 0, 1, 1, 1);
|
||||
gtk_grid_attach(GTK_GRID(grid), fishlim_mode_combo, 1, 1, 2, 1);
|
||||
gtk_grid_attach(GTK_GRID(grid), gtk_label_new("CBC may not work with older clients. Key exchange is private-message only."), 1, 2, 2, 1);
|
||||
|
||||
fishlim_key_entry = gtk_entry_new();
|
||||
gtk_entry_set_visibility(GTK_ENTRY(fishlim_key_entry), FALSE);
|
||||
gtk_grid_attach(GTK_GRID(grid), gtk_label_new("Key"), 0, 3, 1, 1);
|
||||
gtk_grid_attach(GTK_GRID(grid), fishlim_key_entry, 1, 3, 2, 1);
|
||||
|
||||
buttons = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_button_box_set_layout(GTK_BUTTON_BOX(buttons), GTK_BUTTONBOX_END);
|
||||
gtk_grid_attach(GTK_GRID(grid), buttons, 0, 4, 3, 1);
|
||||
|
||||
button = gtk_button_new_with_label("Set Key");
|
||||
g_signal_connect(button, "clicked", G_CALLBACK(fishlim_gui_set), NULL);
|
||||
gtk_container_add(GTK_CONTAINER(buttons), button);
|
||||
|
||||
button = gtk_button_new_with_label("Delete Key");
|
||||
g_signal_connect(button, "clicked", G_CALLBACK(fishlim_gui_delete), NULL);
|
||||
gtk_container_add(GTK_CONTAINER(buttons), button);
|
||||
|
||||
button = gtk_button_new_with_label("Private Message Key Exchange");
|
||||
g_signal_connect(button, "clicked", G_CALLBACK(fishlim_gui_keyx), NULL);
|
||||
gtk_container_add(GTK_CONTAINER(buttons), button);
|
||||
|
||||
fishlim_status_label = gtk_label_new(NULL);
|
||||
gtk_label_set_xalign(GTK_LABEL(fishlim_status_label), 0.0);
|
||||
gtk_grid_attach(GTK_GRID(grid), fishlim_status_label, 0, 5, 3, 1);
|
||||
|
||||
fishlim_store = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
|
||||
view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(fishlim_store));
|
||||
fishlim_view = view;
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, "Target", renderer, "text", 0, NULL);
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, "Mode", renderer, "text", 1, NULL);
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, "Status", renderer, "text", 2, NULL);
|
||||
g_signal_connect(view, "row-activated", G_CALLBACK(fishlim_gui_row_activated), NULL);
|
||||
|
||||
scroll = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_widget_set_vexpand(scroll, TRUE);
|
||||
gtk_container_add(GTK_CONTAINER(scroll), view);
|
||||
gtk_grid_attach(GTK_GRID(grid), scroll, 0, 6, 3, 1);
|
||||
|
||||
g_signal_connect(fishlim_target_entry, "changed", G_CALLBACK(fishlim_gui_refresh_cb), NULL);
|
||||
fishlim_gui_refresh();
|
||||
|
||||
gtk_widget_show_all(fishlim_dialog);
|
||||
return ZOITECHAT_EAT_ZOITECHAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command handler for /setkey
|
||||
*/
|
||||
@@ -490,6 +806,8 @@ static int handle_setkey(char *word[], char *word_eol[], void *userdata) {
|
||||
/* Set password */
|
||||
if (keystore_store_key(nick, key, mode)) {
|
||||
zoitechat_printf(ph, "Stored key for %s (%s)\n", nick, fish_modes[mode]);
|
||||
if (mode == FISH_CBC_MODE)
|
||||
zoitechat_printf(ph, "Warning: CBC may not work with older clients.\n");
|
||||
} else {
|
||||
zoitechat_printf(ph, "\00305Failed to store key in addon_fishlim.conf\n");
|
||||
}
|
||||
@@ -533,8 +851,18 @@ static int handle_keyx(char *word[], char *word_eol[], void *userdata) {
|
||||
const char *target = word[2];
|
||||
zoitechat_context *query_ctx = NULL;
|
||||
char *pub_key, *priv_key;
|
||||
enum fish_mode mode = FISH_CBC_MODE;
|
||||
int ctx_type;
|
||||
|
||||
if (*word[3]) {
|
||||
if (g_ascii_strcasecmp(word[3], "ECB") == 0)
|
||||
mode = FISH_ECB_MODE;
|
||||
else if (g_ascii_strcasecmp(word[3], "CBC") != 0) {
|
||||
zoitechat_printf(ph, "%s", usage_keyx);
|
||||
return ZOITECHAT_EAT_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
if (*target)
|
||||
query_ctx = find_context_on_network(target);
|
||||
else {
|
||||
@@ -555,8 +883,10 @@ static int handle_keyx(char *word[], char *word_eol[], void *userdata) {
|
||||
if (dh1080_generate_key(&priv_key, &pub_key)) {
|
||||
g_hash_table_replace (pending_exchanges, g_ascii_strdown(target, -1), priv_key);
|
||||
|
||||
zoitechat_commandf(ph, "quote NOTICE %s :DH1080_INIT %s CBC", target, pub_key);
|
||||
zoitechat_printf(ph, "Sent public key to %s (CBC), waiting for reply...", target);
|
||||
zoitechat_commandf(ph, "quote NOTICE %s :DH1080_INIT %s%s", target, pub_key, (mode == FISH_CBC_MODE) ? " CBC" : "");
|
||||
zoitechat_printf(ph, "Sent public key to %s (%s), waiting for reply...", target, fish_modes[mode]);
|
||||
if (mode == FISH_CBC_MODE)
|
||||
zoitechat_printf(ph, "Warning: CBC may not work with older clients.");
|
||||
|
||||
g_free(pub_key);
|
||||
} else {
|
||||
@@ -789,6 +1119,7 @@ int zoitechat_plugin_init(zoitechat_plugin *plugin_handle,
|
||||
*version = plugin_version;
|
||||
|
||||
/* Register commands */
|
||||
zoitechat_hook_command(ph, "FISHLIM", ZOITECHAT_PRI_NORM, handle_fishlim, "Usage: FISHLIM, opens the FiSHLiM key manager", NULL);
|
||||
zoitechat_hook_command(ph, "SETKEY", ZOITECHAT_PRI_NORM, handle_setkey, usage_setkey, NULL);
|
||||
zoitechat_hook_command(ph, "DELKEY", ZOITECHAT_PRI_NORM, handle_delkey, usage_delkey, NULL);
|
||||
zoitechat_hook_command(ph, "KEYX", ZOITECHAT_PRI_NORM, handle_keyx, usage_keyx, NULL);
|
||||
@@ -817,12 +1148,19 @@ int zoitechat_plugin_init(zoitechat_plugin *plugin_handle,
|
||||
|
||||
pending_exchanges = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
|
||||
|
||||
zoitechat_command(ph, "MENU ADD \"Window/FiSHLiM Key Manager\" \"FISHLIM\"");
|
||||
zoitechat_command(ph, "MENU ADD \"$NICK/FiSHLiM Key Manager\" \"FISHLIM %s\"");
|
||||
|
||||
zoitechat_printf(ph, "%s plugin loaded\n", plugin_name);
|
||||
/* Return success */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int zoitechat_plugin_deinit(void) {
|
||||
zoitechat_command(ph, "MENU DEL \"Window/FiSHLiM Key Manager\"");
|
||||
zoitechat_command(ph, "MENU DEL \"$NICK/FiSHLiM Key Manager\"");
|
||||
if (fishlim_dialog)
|
||||
gtk_widget_destroy(fishlim_dialog);
|
||||
g_clear_pointer(&pending_exchanges, g_hash_table_destroy);
|
||||
dh1080_deinit();
|
||||
fish_deinit();
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
#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);
|
||||
@@ -105,7 +106,10 @@ 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);
|
||||
@@ -890,6 +894,134 @@ 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)
|
||||
{
|
||||
@@ -1128,6 +1260,8 @@ key_dialog_show ()
|
||||
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,
|
||||
@@ -1235,41 +1369,14 @@ key_load_kbs_helper_mod (char *buf, GdkModifierType *out)
|
||||
}
|
||||
|
||||
static int
|
||||
key_load_kbs (void)
|
||||
key_load_kbs_from_buffer (char *ibuf, off_t size, GSList **out_list)
|
||||
{
|
||||
char *buf, *ibuf;
|
||||
struct stat st;
|
||||
char *buf;
|
||||
struct key_binding *kb = NULL;
|
||||
int fd, len, state = 0, pnt = 0;
|
||||
int len, state = 0, pnt = 0;
|
||||
guint keyval;
|
||||
GdkModifierType mod = 0;
|
||||
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;
|
||||
}
|
||||
GSList *list = NULL;
|
||||
|
||||
while (buf_get_line (ibuf, &buf, &pnt, size))
|
||||
{
|
||||
@@ -1283,14 +1390,12 @@ key_load_kbs (void)
|
||||
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);
|
||||
|
||||
@@ -1313,6 +1418,8 @@ key_load_kbs (void)
|
||||
if (keyval == 0)
|
||||
{
|
||||
g_free (ibuf);
|
||||
key_free (kb);
|
||||
g_slist_free_full (list, key_free);
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -1329,6 +1436,8 @@ key_load_kbs (void)
|
||||
if (kb->action == KEY_MAX_ACTIONS + 1)
|
||||
{
|
||||
g_free (ibuf);
|
||||
key_free (kb);
|
||||
g_slist_free_full (list, key_free);
|
||||
return 3;
|
||||
}
|
||||
|
||||
@@ -1346,6 +1455,8 @@ key_load_kbs (void)
|
||||
if (buf[0] != 'D')
|
||||
{
|
||||
g_free (ibuf);
|
||||
key_free (kb);
|
||||
g_slist_free_full (list, key_free);
|
||||
return 4;
|
||||
}
|
||||
|
||||
@@ -1366,7 +1477,6 @@ key_load_kbs (void)
|
||||
if (buf[2] == ':')
|
||||
{
|
||||
len = strlen (buf);
|
||||
/* Add one for the NULL, subtract 3 for the "Dx:" */
|
||||
len++;
|
||||
len -= 3;
|
||||
if (state == KBSTATE_DT1)
|
||||
@@ -1389,7 +1499,8 @@ key_load_kbs (void)
|
||||
continue;
|
||||
} else
|
||||
{
|
||||
keybind_list = g_slist_append (keybind_list, kb);
|
||||
list = g_slist_append (list, kb);
|
||||
kb = NULL;
|
||||
|
||||
state = KBSTATE_MOD;
|
||||
}
|
||||
@@ -1398,14 +1509,56 @@ key_load_kbs (void)
|
||||
}
|
||||
}
|
||||
g_free (ibuf);
|
||||
*out_list = list;
|
||||
return 0;
|
||||
|
||||
corrupt_file:
|
||||
g_free (ibuf);
|
||||
g_free (kb);
|
||||
key_free (kb);
|
||||
g_slist_free_full (list, key_free);
|
||||
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)
|
||||
|
||||
@@ -855,6 +855,7 @@ tray_toggle_visibility (gboolean force_hide)
|
||||
static int maximized;
|
||||
static int fullscreen;
|
||||
GtkWindow *win;
|
||||
WinStatus status;
|
||||
|
||||
if (!tray_backend_active)
|
||||
return FALSE;
|
||||
@@ -870,7 +871,9 @@ tray_toggle_visibility (gboolean force_hide)
|
||||
if (!win)
|
||||
return FALSE;
|
||||
|
||||
if (force_hide || gtk_widget_get_visible (GTK_WIDGET (win)))
|
||||
status = tray_get_window_status ();
|
||||
|
||||
if (force_hide || status != WS_HIDDEN)
|
||||
{
|
||||
if (prefs.hex_gui_tray_away)
|
||||
zoitechat_command (ph, "ALLSERV AWAY");
|
||||
@@ -890,8 +893,8 @@ tray_toggle_visibility (gboolean force_hide)
|
||||
gtk_window_maximize (win);
|
||||
if (fullscreen)
|
||||
gtk_window_fullscreen (win);
|
||||
gtk_widget_show (GTK_WIDGET (win));
|
||||
gtk_window_deiconify (win);
|
||||
gtk_widget_show (GTK_WIDGET (win));
|
||||
gtk_window_present (win);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user