diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2019-10-24 21:59:55 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2019-10-24 21:59:55 (GMT) |
commit | a9c607a1be25b43a17ea55b21459a0433f4f3d5b (patch) | |
tree | 0bc9018cb2b533d32cf8693871eef563835973b0 /src/gui | |
parent | 7ba652c99e843b21c108fc242b8faa7f5f9502c0 (diff) |
Provided a dialog box to manage snapshots.
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/core/Makefile.am | 4 | ||||
-rw-r--r-- | src/gui/core/gresource.xml | 2 | ||||
-rw-r--r-- | src/gui/dialogs/Makefile.am | 2 | ||||
-rw-r--r-- | src/gui/dialogs/gresource.xml | 1 | ||||
-rw-r--r-- | src/gui/dialogs/snapshots.c | 873 | ||||
-rw-r--r-- | src/gui/dialogs/snapshots.h | 40 | ||||
-rw-r--r-- | src/gui/dialogs/snapshots.ui | 427 | ||||
-rw-r--r-- | src/gui/menus/binary.c | 57 |
8 files changed, 1402 insertions, 4 deletions
diff --git a/src/gui/core/Makefile.am b/src/gui/core/Makefile.am index d23dc07..db9fd47 100644 --- a/src/gui/core/Makefile.am +++ b/src/gui/core/Makefile.am @@ -8,7 +8,9 @@ RES_FILES = \ ../../../pixmaps/collapse.png \ ../../../pixmaps/collapse_dark.png \ ../../../pixmaps/expand.png \ - ../../../pixmaps/expand_dark.png + ../../../pixmaps/expand_dark.png \ + ../../../pixmaps/snapshot.png \ + ../../../pixmaps/snapshot_current.png libguicore_la_SOURCES = \ core.h core.c \ diff --git a/src/gui/core/gresource.xml b/src/gui/core/gresource.xml index ad3688c..6f5cb94 100644 --- a/src/gui/core/gresource.xml +++ b/src/gui/core/gresource.xml @@ -6,5 +6,7 @@ <file compressed="true" alias="collapse_dark.png">../../../pixmaps/collapse_dark.png</file> <file compressed="true" alias="expand.png">../../../pixmaps/expand.png</file> <file compressed="true" alias="expand_dark.png">../../../pixmaps/expand_dark.png</file> + <file compressed="true" alias="snapshot.png">../../../pixmaps/snapshot.png</file> + <file compressed="true" alias="snapshot_current.png">../../../pixmaps/snapshot_current.png</file> </gresource> </gresources> diff --git a/src/gui/dialogs/Makefile.am b/src/gui/dialogs/Makefile.am index ae5180b..575defd 100644 --- a/src/gui/dialogs/Makefile.am +++ b/src/gui/dialogs/Makefile.am @@ -10,6 +10,7 @@ UI_FILES = \ preferences.ui \ prefs_fgraph.ui \ prefs_labels.ui \ + snapshots.ui \ storage.ui libguidialogs_la_SOURCES = \ @@ -25,6 +26,7 @@ libguidialogs_la_SOURCES = \ prefs_fgraph.h prefs_fgraph.c \ prefs_labels.h prefs_labels.c \ resources.h resources.c \ + snapshots.h snapshots.c \ storage.h storage.c libguidialogs_la_LDFLAGS = diff --git a/src/gui/dialogs/gresource.xml b/src/gui/dialogs/gresource.xml index 1d18e39..bf81af4 100644 --- a/src/gui/dialogs/gresource.xml +++ b/src/gui/dialogs/gresource.xml @@ -7,6 +7,7 @@ <file compressed="true">preferences.ui</file> <file compressed="true">prefs_fgraph.ui</file> <file compressed="true">prefs_labels.ui</file> + <file compressed="true">snapshots.ui</file> <file compressed="true">storage.ui</file> </gresource> </gresources> diff --git a/src/gui/dialogs/snapshots.c b/src/gui/dialogs/snapshots.c new file mode 100644 index 0000000..1fcea67 --- /dev/null +++ b/src/gui/dialogs/snapshots.c @@ -0,0 +1,873 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * snapshots.c - gestion des instantanés de base de données + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "snapshots.h" + + +#include <assert.h> +#include <string.h> +#include <time.h> + + +#include <i18n.h> + + + +/* Colonnes de l'arborescence d'instantanés */ +typedef enum _SnapshotTreeColumn +{ + STC_ICON, /* Image de représentation */ + STC_TITLE, /* Meilleure représentation */ + + STC_ID, /* Identifiant de l'instantané */ + STC_TIMESTAMP, /* Valeur brute d'horodatage */ + STC_NAME, /* Désignation de l'instantané */ + STC_DESC, /* Description de l'instantané */ + +} SnapshotTreeColumn; + + +/* Réagit à une fermeture de la boîte de dialogue. */ +static void on_dialog_destroy(GtkWidget *, GtkBuilder *); + +/* Réagit à un changement dans le choix du serveur. */ +static void on_server_selection_changed(GtkComboBox *, GtkBuilder *); + +/* Recherche un élément d'arborescence selon un identifiant. */ +static bool find_suitable_parent(GtkTreeModel *, GtkTreeIter *, const char *, GtkTreeIter *); + +/* Met à jour l'affichage avec une nouvelle liste d'instantanés. */ +static void on_snapshots_updated(GHubClient *, GtkBuilder *); + +/* Réinitialise la zone d'affichage des informations. */ +static void reset_information_area(GtkBuilder *); + +/* Active ou non l'accès à la zone d'affichage des informations. */ +static void update_information_area_access(GtkBuilder *, bool); + +/* Active ou non l'accès à la zone de contrôle des instantanés. */ +static void update_control_area_access(GtkBuilder *, bool, bool, bool); + +/* Met à jour l'affichage des informations d'un instantané. */ +static void on_tree_selection_changed(GtkTreeSelection *, GtkBuilder *); + +/* Restaure sur demande un nouvel instantané. */ +static void restore_old_snapshot(GtkToolButton *, GtkBuilder *); + +/* Crée sur demande un nouvel instantané. */ +static void create_new_snapshot(GtkToolButton *, GtkBuilder *); + +/* Supprime sur demande un instantané. */ +static void remove_old_snapshot(GtkToolButton *, GtkBuilder *); + +/* Supprime sur demande un instantané et ses successeurs. */ +static void delete_old_snapshot(GtkToolButton *, GtkBuilder *); + +/* Applique à un instantané ses nouvelles informations. */ +static void apply_new_snapshot_info(GtkButton *, GtkBuilder *); + +/* Ferme la boîte de dialogue. */ +static void close_dialog_box(GtkButton *, GtkBuilder *); + + + +/****************************************************************************** +* * +* Paramètres : binary = binaire chargé en mémoire à traiter. * +* parent = fenêtre principale de l'éditeur. * +* outb = constructeur à détruire après usage. [OUT] * +* * +* Description : Affiche un gestionnaire d'instantanés de base de données. * +* * +* Retour : Adresse de la fenêtre mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GtkWidget *create_snapshots_dialog(GLoadedBinary *binary, GtkWindow *parent, GtkBuilder **outb) +{ + GtkWidget *result; /* Fenêtre à renvoyer */ + GtkBuilder *builder; /* Constructeur utilisé */ + GFile *file; /* Accès à une image interne */ + GIcon *icon; /* Image de représentation */ + GtkComboBox *combo; /* Liste de serveurs */ + + builder = gtk_builder_new_from_resource("/org/chrysalide/gui/dialogs/snapshots.ui"); + *outb = builder; + + result = GTK_WIDGET(gtk_builder_get_object(builder, "window")); + + gtk_window_set_transient_for(GTK_WINDOW(result), parent); + + g_object_ref(G_OBJECT(result)); + g_object_set_data_full(G_OBJECT(builder), "window", result, g_object_unref); + + g_object_ref(G_OBJECT(binary)); + g_object_set_data_full(G_OBJECT(builder), "binary", binary, g_object_unref); + + file = g_file_new_for_uri("resource:///org/chrysalide/gui/core/images/snapshot.png"); + icon = g_file_icon_new(file); + g_object_set_data_full(G_OBJECT(builder), "icon", icon, g_object_unref); + + file = g_file_new_for_uri("resource:///org/chrysalide/gui/core/images/snapshot_current.png"); + icon = g_file_icon_new(file); + g_object_set_data_full(G_OBJECT(builder), "current_icon", icon, g_object_unref); + + /* Connexion des signaux */ + + gtk_builder_add_callback_symbols(builder, + "on_dialog_destroy", G_CALLBACK(on_dialog_destroy), + "on_server_selection_changed", G_CALLBACK(on_server_selection_changed), + "on_tree_selection_changed", G_CALLBACK(on_tree_selection_changed), + "restore_old_snapshot", G_CALLBACK(restore_old_snapshot), + "create_new_snapshot", G_CALLBACK(create_new_snapshot), + "remove_old_snapshot", G_CALLBACK(remove_old_snapshot), + "delete_old_snapshot", G_CALLBACK(delete_old_snapshot), + "apply_new_snapshot_info", G_CALLBACK(apply_new_snapshot_info), + "close_dialog_box", G_CALLBACK(close_dialog_box), + NULL); + + gtk_builder_connect_signals(builder, builder); + + /* Mise à jour de l'interface */ + + reset_information_area(builder); + update_control_area_access(builder, false, false, false); + + combo = GTK_COMBO_BOX(gtk_builder_get_object(builder, "servers")); + + gtk_combo_box_set_active(combo, 0); + + return result; + +} + +/****************************************************************************** +* * +* Paramètres : dialog = fenêtre en cours de suppression. * +* builder = espace de référencement global. * +* * +* Description : Réagit à une fermeture de la boîte de dialogue. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_dialog_destroy(GtkWidget *dialog, GtkBuilder *builder) +{ + GHubClient *client; /* Cible des interactions */ + + /* Déconnexion de l'ancien */ + + client = G_HUB_CLIENT(g_object_get_data(G_OBJECT(builder), "client")); + + if (client != NULL) + g_signal_handlers_disconnect_by_func(client, on_snapshots_updated, builder); + +} + + +/****************************************************************************** +* * +* Paramètres : combo = liste de sélection à l'origine de la procédure. * +* builder = espace de référencement global. * +* * +* Description : Réagit à un changement dans le choix du serveur. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_server_selection_changed(GtkComboBox *combo, GtkBuilder *builder) +{ + GHubClient *client; /* Cible des interactions */ + gint active; /* Indice du serveur retenu */ + GLoadedBinary *binary; /* Binaire en cours d'étude */ + GtkTreeStore *store; /* Modèle de gestion */ + + /* Déconnexion de l'ancien */ + + client = G_HUB_CLIENT(g_object_get_data(G_OBJECT(builder), "client")); + + if (client != NULL) + g_signal_handlers_disconnect_by_func(client, on_snapshots_updated, builder); + + /* Connexion nouvelle */ + + active = gtk_combo_box_get_active(combo); + + binary = G_LOADED_BINARY(g_object_get_data(G_OBJECT(builder), "binary")); + + client = g_loaded_binary_get_client(binary, active == 0); + + if (client == NULL) + { + g_object_set_data(G_OBJECT(builder), "client", NULL); + + store = GTK_TREE_STORE(gtk_builder_get_object(builder, "store")); + gtk_tree_store_clear(store); + + reset_information_area(builder); + update_control_area_access(builder, false, false, false); + + } + + else + { + g_object_ref(G_OBJECT(client)); + g_object_set_data_full(G_OBJECT(builder), "client", client, g_object_unref); + + g_signal_connect(client, "snapshots-updated", G_CALLBACK(on_snapshots_updated), builder); + + on_snapshots_updated(client, builder); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : model = modèle de gestion de données à consulter. * +* iter = point de départ des recherches. * +* id = identifiant de l'instantané recherché. * +* found = emplacement de l'éventuel noeud trouvé. [OUT] * +* * +* Description : Recherche un élément d'arborescence selon un identifiant. * +* * +* Retour : true pour indiquer une recherche fructueuse, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool find_suitable_parent(GtkTreeModel *model, GtkTreeIter *iter, const char *id, GtkTreeIter *found) +{ + bool result; /* Bilan à retourner */ + gchar *value; /* Identifiant courant */ + gint count; /* Quantité de fils présents */ + gint i; /* Boucle de parcours */ + GtkTreeIter child; /* Localisation d'un fils */ +#ifndef NDEBUG + gboolean status; /* Bilan d'une consultation */ +#endif + + gtk_tree_model_get(model, iter, STC_ID, &value, -1); + + result = (strcmp(value, id) == 0); + + g_free(value); + + if (result) + *found = *iter; + + else + { + count = gtk_tree_model_iter_n_children(model, iter); + + for (i = 0; i < count && !result; i++) + { +#ifndef NDEBUG + status = gtk_tree_model_iter_nth_child(model, &child, iter, i); + assert(status); +#else + gtk_tree_model_iter_nth_child(model, &child, iter, i); +#endif + + result = find_suitable_parent(model, &child, id, found); + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : client = client connecté à l'origine de la procédure. * +* builder = espace de référencement global. * +* * +* Description : Met à jour l'affichage avec une nouvelle liste d'instantanés.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_snapshots_updated(GHubClient *client, GtkBuilder *builder) +{ + GtkTreeStore *store; /* Modèle de gestion */ + snapshot_info_t *info; /* Liste d'instantanés présents*/ + size_t count; /* Taille de cette liste */ + bool status; /* Validité de cet identifiant */ + size_t i; /* Boucle de parcours */ + char *id; /* Identifiant du parent */ + GtkTreeIter iter; /* Point d'insertion */ +#ifndef NDEBUG + gboolean check; /* Vérification par principe */ +#endif + GtkTreeIter parent; /* Parent du point d'insertion */ + GIcon *icon; /* Image de représentation */ + char *name; /* Désignation d'instantané */ + snapshot_id_t current; /* Instantané courant */ + GtkTreeView *treeview; /* Arborescence graphique */ + const char *raw; /* Identifiant brut */ + GtkTreeSelection *selection; /* Gestionnaire de sélection */ + + store = GTK_TREE_STORE(gtk_builder_get_object(builder, "store")); + + gtk_tree_store_clear(store); + + status = g_hub_client_get_snapshots(client, &info, &count); + + if (!status) + { + reset_information_area(builder); + update_control_area_access(builder, false, false, false); + } + + else + { + /* Remplissage */ + + for (i = 0; i < count; i++) + { + id = snapshot_id_as_string(get_snapshot_info_parent_id(&info[i])); + + if (strcmp(id, NO_SNAPSHOT_ROOT) == 0) + gtk_tree_store_append(store, &iter, NULL); + + else + { +#ifndef NDEBUG + check = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter); + assert(check); +#else + gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter); +#endif + + status = find_suitable_parent(GTK_TREE_MODEL(store), &iter, id, &parent); + assert(status); + + gtk_tree_store_append(store, &iter, &parent); + + } + + id = snapshot_id_as_string(get_snapshot_info_id(&info[i])); + + icon = G_ICON(g_object_get_data(G_OBJECT(builder), "icon")); + + name = get_snapshot_info_name(&info[i]); + + gtk_tree_store_set(store, &iter, + STC_ICON, icon, + STC_TITLE, name != NULL ? name : id, + STC_ID, id, + STC_TIMESTAMP, get_snapshot_info_created(&info[i]), + STC_NAME, name, + STC_DESC, get_snapshot_info_desc(&info[i]), + -1); + + exit_snapshot_info(&info[i]); + + } + + free(info); + + /* Ajout de l'instantané courant */ + + status = g_hub_client_get_current_snapshot(client, ¤t); + + if (status) + { + id = snapshot_id_as_string(¤t); + +#ifndef NDEBUG + check = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter); + assert(check); +#else + gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter); +#endif + + status = find_suitable_parent(GTK_TREE_MODEL(store), &iter, id, &parent); + + if (status) + { + gtk_tree_store_append(store, &iter, &parent); + + icon = G_ICON(g_object_get_data(G_OBJECT(builder), "current_icon")); + + gtk_tree_store_set(store, &iter, + STC_ICON, icon, + STC_TITLE, _("Current"), + -1); + + } + + } + + /* Plein affichage */ + + treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview")); + + gtk_tree_view_expand_all(treeview); + + /* Remise en place de la dernière sélection */ + + raw = g_object_get_data(G_OBJECT(builder), "selected"); + + if (raw != NULL) + { +#ifndef NDEBUG + check = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter); + assert(check); +#else + gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter); +#endif + + status = find_suitable_parent(GTK_TREE_MODEL(store), &iter, raw, &iter); + + if (status) + { + selection = gtk_tree_view_get_selection(treeview); + + gtk_tree_selection_select_iter(selection, &iter); + + } + + else + { + reset_information_area(builder); + + update_control_area_access(builder, false, false, false); + + g_object_set_data(G_OBJECT(builder), "selected", NULL); + + } + + } + + } + +} + + +/****************************************************************************** +* * +* Paramètres : builder = espace de référencement global. * +* * +* Description : Réinitialise la zone d'affichage des informations. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void reset_information_area(GtkBuilder *builder) +{ + GtkLabel *label; /* Etiquette à faire évoluer */ + GtkEntry *entry; /* Zone de saisie à actualiser */ + + label = GTK_LABEL(gtk_builder_get_object(builder, "identifier")); + gtk_label_set_text(label, "-"); + + label = GTK_LABEL(gtk_builder_get_object(builder, "timestamp")); + gtk_label_set_text(label, "-"); + + entry = GTK_ENTRY(gtk_builder_get_object(builder, "name")); + gtk_entry_set_text(entry, ""); + + entry = GTK_ENTRY(gtk_builder_get_object(builder, "description")); + gtk_entry_set_text(entry, ""); + + update_information_area_access(builder, false); + +} + + +/****************************************************************************** +* * +* Paramètres : builder = espace de référencement global. * +* state = état des possibilités d'interactions à appliquer. * +* * +* Description : Active ou non l'accès à la zone d'affichage des informations.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void update_information_area_access(GtkBuilder *builder, bool state) +{ + GtkWidget *widget; /* Composant à traiter */ + + widget = GTK_WIDGET(gtk_builder_get_object(builder, "identifier")); + gtk_widget_set_sensitive(widget, state); + + widget = GTK_WIDGET(gtk_builder_get_object(builder, "timestamp")); + gtk_widget_set_sensitive(widget, state); + + widget = GTK_WIDGET(gtk_builder_get_object(builder, "name")); + gtk_widget_set_sensitive(widget, state); + + widget = GTK_WIDGET(gtk_builder_get_object(builder, "description")); + gtk_widget_set_sensitive(widget, state); + + widget = GTK_WIDGET(gtk_builder_get_object(builder, "apply")); + gtk_widget_set_sensitive(widget, state); + +} + + +/****************************************************************************** +* * +* Paramètres : builder = espace de référencement global. * +* restore = accès à la restauration d'un instantané. * +* create = accès à la création d'un nouvel instantané. * +* delete = accès à la suppression d'instantanés. * +* * +* Description : Active ou non l'accès à la zone de contrôle des instantanés. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void update_control_area_access(GtkBuilder *builder, bool restore, bool create, bool delete) +{ + GtkWidget *widget; /* Composant à traiter */ + + widget = GTK_WIDGET(gtk_builder_get_object(builder, "restore")); + gtk_widget_set_sensitive(widget, restore); + + widget = GTK_WIDGET(gtk_builder_get_object(builder, "create")); + gtk_widget_set_sensitive(widget, create); + + widget = GTK_WIDGET(gtk_builder_get_object(builder, "remove")); + gtk_widget_set_sensitive(widget, delete); + + widget = GTK_WIDGET(gtk_builder_get_object(builder, "delete")); + gtk_widget_set_sensitive(widget, delete); + +} + + +/****************************************************************************** +* * +* Paramètres : selection = nouvelle sélection à appliquer. * +* builder = espace de référencement global. * +* * +* Description : Met à jour l'affichage des informations d'un instantané. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_tree_selection_changed(GtkTreeSelection *selection, GtkBuilder *builder) +{ + GtkTreeModel *model; /* Modèle de gestion */ + GtkTreeIter iter; /* Point de sélection */ + gchar *id; /* Identifiant d'instantané */ + guint64 timestamp; /* Horodatage associé */ + gchar *name; /* Eventuelle désignation */ + gchar *desc; /* Eventuelle description */ + GtkLabel *label; /* Etiquette à faire évoluer */ + char buf[27]; /* Tampon pour la date */ + GtkEntry *entry; /* Zone de saisie à actualiser */ + gboolean is_not_root; /* Particularité de sélection */ + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) + { + gtk_tree_model_get(model, &iter, + STC_ID, &id, + STC_TIMESTAMP, ×tamp, + STC_NAME, &name, + STC_DESC, &desc, + -1); + + if (id == NULL) + { + assert(name == NULL); + assert(desc == NULL); + + reset_information_area(builder); + + update_control_area_access(builder, false, true, false); + + g_object_set_data(G_OBJECT(builder), "selected", NULL); + + } + + else + { + label = GTK_LABEL(gtk_builder_get_object(builder, "identifier")); + gtk_label_set_text(label, id); + + ctime_r((time_t []) { timestamp / 1000000 }, buf); + buf[strlen(buf) - 1] = 0; + + label = GTK_LABEL(gtk_builder_get_object(builder, "timestamp")); + gtk_label_set_text(label, buf); + + entry = GTK_ENTRY(gtk_builder_get_object(builder, "name")); + gtk_entry_set_text(entry, name != NULL ? name : ""); + + if (name != NULL) + g_free(name); + + entry = GTK_ENTRY(gtk_builder_get_object(builder, "description")); + gtk_entry_set_text(entry, desc != NULL ? desc : ""); + + if (desc != NULL) + g_free(desc); + + update_information_area_access(builder, true); + + is_not_root = gtk_tree_model_iter_parent(model, (GtkTreeIter []) { { 0 } }, &iter); + + update_control_area_access(builder, true, false, is_not_root); + + g_object_set_data_full(G_OBJECT(builder), "selected", id, g_free); + + } + + } + +} + + +/****************************************************************************** +* * +* Paramètres : button = composant GTK à l'origine de la procédure. * +* builder = espace de référencement global. * +* * +* Description : Restaure sur demande un nouvel instantané. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void restore_old_snapshot(GtkToolButton *button, GtkBuilder *builder) +{ + const char *raw; /* Identifiant brut */ + snapshot_id_t id; /* Identifiant utilisable */ + bool status; /* Bilan d'une conversion */ + GHubClient *client; /* Cible des interactions */ + + raw = g_object_get_data(G_OBJECT(builder), "selected"); + + status = init_snapshot_id_from_text(&id, raw); + + if (status) + { + client = G_HUB_CLIENT(g_object_get_data(G_OBJECT(builder), "client")); + + g_hub_client_restore_snapshot(client, &id); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : button = composant GTK à l'origine de la procédure. * +* builder = espace de référencement global. * +* * +* Description : Crée sur demande un nouvel instantané. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void create_new_snapshot(GtkToolButton *button, GtkBuilder *builder) +{ + const char *raw; /* Identifiant brut */ + snapshot_id_t id; /* Identifiant utilisable */ + bool status; /* Bilan d'une conversion */ + GHubClient *client; /* Cible des interactions */ + + raw = g_object_get_data(G_OBJECT(builder), "selected"); + + status = init_snapshot_id_from_text(&id, raw); + + if (status) + { + client = G_HUB_CLIENT(g_object_get_data(G_OBJECT(builder), "client")); + + g_hub_client_create_snapshot(client, &id); + + } + +} + +/****************************************************************************** +* * +* Paramètres : button = composant GTK à l'origine de la procédure. * +* builder = espace de référencement global. * +* * +* Description : Supprime sur demande un instantané. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void remove_old_snapshot(GtkToolButton *button, GtkBuilder *builder) +{ + const char *raw; /* Identifiant brut */ + snapshot_id_t id; /* Identifiant utilisable */ + bool status; /* Bilan d'une conversion */ + GHubClient *client; /* Cible des interactions */ + + raw = g_object_get_data(G_OBJECT(builder), "selected"); + + status = init_snapshot_id_from_text(&id, raw); + + if (status) + { + client = G_HUB_CLIENT(g_object_get_data(G_OBJECT(builder), "client")); + + g_hub_client_remove_snapshot(client, &id, false); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : button = composant GTK à l'origine de la procédure. * +* builder = espace de référencement global. * +* * +* Description : Supprime sur demande un instantané et ses successeurs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void delete_old_snapshot(GtkToolButton *button, GtkBuilder *builder) +{ + const char *raw; /* Identifiant brut */ + snapshot_id_t id; /* Identifiant utilisable */ + bool status; /* Bilan d'une conversion */ + GHubClient *client; /* Cible des interactions */ + + raw = g_object_get_data(G_OBJECT(builder), "selected"); + + status = init_snapshot_id_from_text(&id, raw); + + if (status) + { + client = G_HUB_CLIENT(g_object_get_data(G_OBJECT(builder), "client")); + + g_hub_client_remove_snapshot(client, &id, true); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : button = composant GTK à l'origine de la procédure. * +* builder = espace de référencement global. * +* * +* Description : Applique à un instantané ses nouvelles informations. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void apply_new_snapshot_info(GtkButton *button, GtkBuilder *builder) +{ + const char *raw; /* Identifiant brut */ + snapshot_id_t id; /* Identifiant utilisable */ + bool status; /* Bilan d'une conversion */ + GHubClient *client; /* Cible des interactions */ + GtkEntry *entry; /* Zone de saisie à actualiser */ + + raw = g_object_get_data(G_OBJECT(builder), "selected"); + + status = init_snapshot_id_from_text(&id, raw); + + if (status) + { + client = G_HUB_CLIENT(g_object_get_data(G_OBJECT(builder), "client")); + + entry = GTK_ENTRY(gtk_builder_get_object(builder, "name")); + g_hub_client_set_snapshot_name(client, &id, gtk_entry_get_text(entry)); + + entry = GTK_ENTRY(gtk_builder_get_object(builder, "description")); + g_hub_client_set_snapshot_desc(client, &id, gtk_entry_get_text(entry)); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : button = composant GTK à l'origine de la procédure. * +* builder = espace de référencement global. * +* * +* Description : Ferme la boîte de dialogue. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void close_dialog_box(GtkButton *button, GtkBuilder *builder) +{ + GtkDialog *dialog; /* Fenêtre à manipuler */ + + dialog = GTK_DIALOG(gtk_builder_get_object(builder, "window")); + + gtk_dialog_response(dialog, GTK_RESPONSE_CLOSE); + +} diff --git a/src/gui/dialogs/snapshots.h b/src/gui/dialogs/snapshots.h new file mode 100644 index 0000000..05f3ac3 --- /dev/null +++ b/src/gui/dialogs/snapshots.h @@ -0,0 +1,40 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * snapshots.h - prototypes pour la gestion des instantanés de base de données + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GUI_DIALOGS_SNAPSHOTS_H +#define _GUI_DIALOGS_SNAPSHOTS_H + + +#include <gtk/gtk.h> + + +#include "../../analysis/binary.h" + + + +/* Affiche un gestionnaire d'instantanés de base de données. */ +GtkWidget *create_snapshots_dialog(GLoadedBinary *, GtkWindow *, GtkBuilder **); + + + +#endif /* _GUI_DIALOGS_SNAPSHOTS_H */ diff --git a/src/gui/dialogs/snapshots.ui b/src/gui/dialogs/snapshots.ui new file mode 100644 index 0000000..7c6d472 --- /dev/null +++ b/src/gui/dialogs/snapshots.ui @@ -0,0 +1,427 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.21.0 --> +<interface> + <requires lib="gtk+" version="3.20"/> + <object class="GtkImage" id="image-add"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="stock">gtk-add</property> + </object> + <object class="GtkImage" id="image-delete"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="stock">gtk-delete</property> + <property name="icon_size">3</property> + </object> + <object class="GtkImage" id="image-remove"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="stock">gtk-remove</property> + </object> + <object class="GtkImage" id="image-restore"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="stock">gtk-media-play</property> + <property name="icon_size">3</property> + </object> + <object class="GtkTreeStore" id="store"> + <columns> + <!-- column-name icon --> + <column type="GIcon"/> + <!-- column-name title --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + <!-- column-name timestamp --> + <column type="guint64"/> + <!-- column-name name --> + <column type="gchararray"/> + <!-- column-name desc --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkDialog" id="window"> + <property name="width_request">530</property> + <property name="can_focus">False</property> + <property name="title" translatable="yes">Snapshot management</property> + <property name="modal">True</property> + <property name="type_hint">dialog</property> + <property name="skip_taskbar_hint">True</property> + <signal name="destroy" handler="on_dialog_destroy" swapped="no"/> + <child internal-child="vbox"> + <object class="GtkBox"> + <property name="can_focus">False</property> + <property name="margin_left">8</property> + <property name="margin_right">8</property> + <property name="margin_top">8</property> + <property name="margin_bottom">8</property> + <property name="orientation">vertical</property> + <property name="spacing">2</property> + <child internal-child="action_area"> + <object class="GtkButtonBox"> + <property name="can_focus">False</property> + <property name="margin_top">8</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="apply"> + <property name="label">gtk-apply</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="apply_new_snapshot_info" swapped="no"/> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton"> + <property name="label">gtk-close</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="close_dialog_box" swapped="no"/> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">8</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">8</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Server:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkComboBoxText" id="servers"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <items> + <item translatable="yes">Internal</item> + </items> + <signal name="changed" handler="on_server_selection_changed" swapped="no"/> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">store</property> + <property name="headers_visible">False</property> + <child internal-child="selection"> + <object class="GtkTreeSelection"> + <signal name="changed" handler="on_tree_selection_changed" swapped="no"/> + </object> + </child> + <child> + <object class="GtkTreeViewColumn"> + <property name="title" translatable="yes">column</property> + <child> + <object class="GtkCellRendererPixbuf" id="snapicon"/> + <attributes> + <attribute name="gicon">0</attribute> + </attributes> + </child> + <child> + <object class="GtkCellRendererText"/> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkToolbar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="show_arrow">False</property> + <child> + <object class="GtkToolButton" id="restore"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="tooltip_text" translatable="yes">Restore an old snapshot</property> + <property name="label_widget">image-restore</property> + <signal name="clicked" handler="restore_old_snapshot" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> + </child> + <child> + <object class="GtkSeparatorToolItem"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="create"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="tooltip_text" translatable="yes">Create a new snapshot</property> + <property name="label_widget">image-add</property> + <signal name="clicked" handler="create_new_snapshot" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="remove"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="tooltip_text" translatable="yes">Remove a snapshot from the snapshot tree</property> + <property name="label_widget">image-remove</property> + <signal name="clicked" handler="remove_old_snapshot" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="delete"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="tooltip_text" translatable="yes">Delete a snapshot with all its children</property> + <property name="label_widget">image-delete</property> + <signal name="clicked" handler="delete_old_snapshot" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkFrame"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="left_padding">12</property> + <child> + <object class="GtkGrid"> + <property name="name">œ</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="row_spacing">8</property> + <property name="column_spacing">8</property> + <property name="row_homogeneous">True</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Identifier:</property> + <property name="xalign">1</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Timestamp:</property> + <property name="xalign">1</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Name:</property> + <property name="xalign">1</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Description:</property> + <property name="xalign">1</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="identifier"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">-</property> + <property name="selectable">True</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="timestamp"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">-</property> + <property name="selectable">True</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="name"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="placeholder_text" translatable="yes">No name</property> + <property name="input_hints">GTK_INPUT_HINT_SPELLCHECK | GTK_INPUT_HINT_NONE</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="description"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="placeholder_text" translatable="yes">No description</property> + <property name="input_hints">GTK_INPUT_HINT_SPELLCHECK | GTK_INPUT_HINT_NONE</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">3</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Description</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <child> + <placeholder/> + </child> + </object> +</interface> diff --git a/src/gui/menus/binary.c b/src/gui/menus/binary.c index cb131d7..aeaf6f6 100644 --- a/src/gui/menus/binary.c +++ b/src/gui/menus/binary.c @@ -34,6 +34,7 @@ #include "../dialogs/export_disass.h" #include "../dialogs/export_graph.h" #include "../dialogs/gotox.h" +#include "../dialogs/snapshots.h" #include "../dialogs/storage.h" #include "../../gtkext/easygtk.h" #include "../../gtkext/gtkdisplaypanel.h" @@ -47,9 +48,12 @@ static void mcb_binary_entry_points(GtkMenuItem *, GMenuBar *); /* Réagit au menu "Binaire -> Attacher un débogueur". */ static void mcb_binary_attach_debugger(GtkMenuItem *, GMenuBar *); -/* Réagit au menu "Binaire -> Enregistrements...". */ +/* Réagit au menu "Binaire -> Enregistrements". */ static void mcb_binary_storage(GtkMenuItem *, GMenuBar *); +/* Réagit au menu "Binaire -> Instantanés". */ +static void mcb_binary_snapshots(GtkMenuItem *, GMenuBar *); + /* Réagit au menu "Binaire -> Exporter -> Désassemblage". */ static void mcb_binary_export_disass(GtkMenuItem *, gpointer); @@ -96,13 +100,21 @@ GtkWidget *build_menu_binary(GObject *ref, GMenuBar *bar) G_CALLBACK(mcb_binary_attach_debugger), bar); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); + /* Séparation */ + submenuitem = qck_create_menu_separator(); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); - submenuitem = qck_create_menu_item(ref, "mnu_binary_storage", _("Storage..."), + /* Bases de données */ + + submenuitem = qck_create_menu_item(ref, "mnu_binary_storage", _("Storage"), G_CALLBACK(mcb_binary_storage), bar); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); + submenuitem = qck_create_menu_item(ref, "mnu_binary_snapshots", _("Snapshots"), + G_CALLBACK(mcb_binary_snapshots), bar); + gtk_container_add(GTK_CONTAINER(menubar), submenuitem); + /* Séparation */ submenuitem = qck_create_menu_separator(); @@ -271,7 +283,7 @@ static void mcb_binary_attach_debugger(GtkMenuItem *menuitem, GMenuBar *bar) * Paramètres : menuitem = élément de menu sélectionné. * * bar = barre de menu parente. * * * -* Description : Réagit au menu "Binaire -> Enregistrements...". * +* Description : Réagit au menu "Binaire -> Enregistrements". * * * * Retour : - * * * @@ -312,6 +324,45 @@ static void mcb_binary_storage(GtkMenuItem *menuitem, GMenuBar *bar) /****************************************************************************** * * * Paramètres : menuitem = élément de menu sélectionné. * +* bar = barre de menu parente. * +* * +* Description : Réagit au menu "Binaire -> Instantanés". * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void mcb_binary_snapshots(GtkMenuItem *menuitem, GMenuBar *bar) +{ + GLoadedBinary *binary; /* Edition courante */ + GtkBuilder *builder; /* Constructeur utilisé */ + GtkWindow *editor; /* Fenêtre graphique principale*/ + GtkWidget *dialog; /* Boîte de dialogue à montrer */ + + binary = G_LOADED_BINARY(get_current_content()); + + editor = get_editor_window(); + + dialog = create_snapshots_dialog(binary, editor, &builder); + + gtk_dialog_run(GTK_DIALOG(dialog)); + + gtk_widget_destroy(dialog); + + g_object_unref(G_OBJECT(builder)); + + g_object_unref(G_OBJECT(editor)); + + g_object_unref(G_OBJECT(binary)); + +} + + +/****************************************************************************** +* * +* Paramètres : menuitem = élément de menu sélectionné. * * unused = adresse non utilisée ici. * * * * Description : Réagit au menu "Binaire -> Exporter -> Désassemblage". * |