/* * Copyright (C) 2004 Morten Fjord-Larsen * Copyright (C) 2005 Kouji TAKAO * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include "gpass/configuration.h" #include "gpass/password.h" #include "gpass/error.h" #include "helper.h" #include "entry-tree.h" #include "summary.h" #include "application.h" #include "lock.h" #include "attribute-editor.h" #include "window.h" static GPassViewClass *parent_class = NULL; static void gpass_window_instance_init(GTypeInstance *instance, gpointer g_class) { GPassWindow *self = GPASS_WINDOW(instance); self->current = NULL; self->copied = NULL; self->lock_timeout = 0; self->status_timeout = 0; self->attribute_editor = NULL; } static void gpass_window_paste_sensitive(GPassWindow *self); static GError * gpass_window_instance_loaded_glade_xml(GPassView *view) { GPassWindow *self = GPASS_WINDOW(view); GtkToolbar *toolbar; BonoboDockItem *dockitem; GtkWidget *separator; GPassConfiguration *config; gint x, y, width, height; gint separator_position; GtkWidget *widget; GError *error = NULL; gnome_app_enable_layout_config(GNOME_APP(view->window), TRUE); config = gpass_configuration_instance(); g_object_get(config, "window_x", &x, "window_y", &y, NULL); if (x >= 0 && y >= 0) { gtk_window_move(GTK_WINDOW(view->window), x, y); } g_object_get(config, "window_width", &width, "window_height", &height, NULL); if (width > 0 && height > 0) { gtk_window_set_default_size(GTK_WINDOW(view->window), width, height); } toolbar = GTK_TOOLBAR(glade_xml_get_widget(view->xml, "toolbar")); dockitem = BONOBO_DOCK_ITEM(glade_xml_get_widget(view->xml, "toolbar-dock")); gnome_app_setup_toolbar(toolbar, dockitem); separator = glade_xml_get_widget(view->xml, "separator"); g_object_get(config, "pane_width", &separator_position, NULL); if (separator_position != 0) { gtk_paned_set_position(GTK_PANED(separator), separator_position); } widget = glade_xml_get_widget(GPASS_VIEW(self)->xml, "undo-menu"); gtk_widget_set_sensitive(widget, FALSE); widget = glade_xml_get_widget(GPASS_VIEW(self)->xml, "redo-menu"); gtk_widget_set_sensitive(widget, FALSE); gpass_window_edit_items_sensitive(self); gpass_window_paste_sensitive(self); error = gpass_entry_tree_initialize(self); if (error != NULL) { return error; } gpass_summary_initialize(self); return parent_class->loaded_glade_xml(view); } static void stop_lock_timeout(GPassWindow *self) { if (self->lock_timeout != 0) { g_source_remove(self->lock_timeout); self->lock_timeout = 0; } } #define msec_to_min(s) ((s) * 1000 * 60) static gboolean lock_timeout_func(gpointer data); static void start_lock_timeout(GPassWindow *self) { GPassConfiguration *config = gpass_configuration_instance(); gboolean lock; stop_lock_timeout(self); g_object_get(config, "lock", &lock, NULL); if (lock) { gint lock_timeout; g_object_get(config, "lock_timeout", &lock_timeout, NULL); self->lock_timeout = g_timeout_add(msec_to_min(lock_timeout), lock_timeout_func, self); } } static gboolean lock_timeout_func(gpointer data) { GPassWindow *self = GPASS_WINDOW(data); GPassApplication *app = GPASS_APPLICATION(GPASS_VIEW(self)->model); GPassGnomeLock *lock = g_object_new(GPASS_TYPE_GNOME_LOCK, "template", "lock", "model", app, NULL); GPassViewResult result; GError *error; gtk_widget_hide(GPASS_VIEW(self)->window); gtk_window_iconify(GTK_WINDOW(GPASS_VIEW(lock)->window)); error = gpass_view_run(GPASS_VIEW(lock), &result); if (error != NULL) { gpass_error_show_and_exit(error); } g_object_unref(lock); if (result == GPASS_LOCK_RESULT_CLOSE) { GPASS_VIEW(self)->result = GPASS_VIEW_RESULT_SUCCEED; gpass_view_shutdown_main_loop(GPASS_VIEW(self)); } else { gtk_widget_show(GPASS_VIEW(self)->window); } return TRUE; } static void clipboard_clear(void); static GError * gpass_window_instance_run(GPassView *view, GPassViewResult *result) { GPassWindow *self = GPASS_WINDOW(view); GPassConfiguration *config = gpass_configuration_instance(); gboolean toolbar_visible, statusbar_visible; GtkWidget *menuitem; GError *error = NULL; error = gpass_entry_tree_build(self); if (error != NULL) { return error; } gtk_widget_show_all(view->window); g_object_get(config, "toolbar_visible", &toolbar_visible, NULL); if (!toolbar_visible) { menuitem = glade_xml_get_widget(view->xml, "toolbar-visible-menu"); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), FALSE); } g_object_get(config, "statusbar_visible", &statusbar_visible, NULL); if (!statusbar_visible) { menuitem = glade_xml_get_widget(view->xml, "statusbar-visible-menu"); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), FALSE); } view->main_loop = g_main_loop_new(NULL, FALSE); GDK_THREADS_LEAVE(); start_lock_timeout(self); g_main_loop_run(view->main_loop); stop_lock_timeout(self); if (self->status_timeout != 0) { g_source_remove(self->status_timeout); } GDK_THREADS_ENTER(); g_main_loop_unref(view->main_loop); if (self->attribute_editor != NULL) { g_object_unref(self->attribute_editor); self->attribute_editor = NULL; } gpass_window_save(self); gtk_widget_hide(view->window); *result = view->result; clipboard_clear(); return NULL; } static void gpass_window_class_init(gpointer g_class, gpointer g_class_data) { GPassViewClass *view_class = GPASS_VIEW_CLASS(g_class); parent_class = g_type_class_peek_parent(g_class); view_class->loaded_glade_xml = gpass_window_instance_loaded_glade_xml; view_class->run = gpass_window_instance_run; } GType gpass_window_get_type(void) { static GType type = 0; if (type == 0) { static const GTypeInfo info = { sizeof(GPassWindowClass), NULL, NULL, gpass_window_class_init, NULL, NULL, sizeof(GPassWindow), 0, gpass_window_instance_init, }; type = g_type_register_static(GPASS_TYPE_VIEW, "GPassWindowType", &info, 0); } return type; } void gpass_window_save(GPassWindow *self) { gint x, y; gint width, height; GPassConfiguration *config; GtkWidget *widget; gboolean toolbar_visible, statusbar_visible; gint pane_width; gtk_window_get_position(GTK_WINDOW(GPASS_VIEW(self)->window), &x, &y); gtk_window_get_size(GTK_WINDOW(GPASS_VIEW(self)->window), &width, &height); widget = glade_xml_get_widget(GPASS_VIEW(self)->xml, "toolbar-visible-menu"); toolbar_visible = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); widget = glade_xml_get_widget(GPASS_VIEW(self)->xml, "statusbar-visible-menu"); statusbar_visible = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); widget = glade_xml_get_widget(GPASS_VIEW(self)->xml, "separator"); pane_width = gtk_paned_get_position(GTK_PANED(widget)); config = gpass_configuration_instance(); g_object_set(config, "window_x", x, "window_y", y, "window_width", width, "window_height", height, "toolbar_visible", toolbar_visible, "statusbar_visible", statusbar_visible, "pane_width", pane_width, NULL); } static void window_status_set(GPassWindow *self, const gchar *status) { GnomeAppBar *statusbar = GNOME_APPBAR(glade_xml_get_widget(GPASS_VIEW(self)->xml, "statusbar")); gnome_appbar_set_status(statusbar, status); } static gboolean status_erace_timeout(gpointer data) { GPassWindow *self = GPASS_WINDOW(data); window_status_set(self, ""); self->status_timeout = 0; return FALSE; } void gpass_window_status_say(GPassWindow *self, const gchar *fmt, ...) { va_list va; gchar *str; va_start(va, fmt); str = g_strdup_vprintf(fmt,va); va_end(va); window_status_set(self, str); g_free(str); if (self->status_timeout != 0) { g_source_remove(self->status_timeout); } self->status_timeout = g_timeout_add(5 * 1000, status_erace_timeout, self); } void gpass_window_undo_redo_sensitive(GPassWindow *self) { GPassApplication *app; const gchar *description; GtkWidget *widget; app = GPASS_APPLICATION(GPASS_VIEW(self)->model); gpass_command_stack_get_undo_description(app->command_stack, &description); widget = glade_xml_get_widget(GPASS_VIEW(self)->xml, "undo-menu"); gtk_widget_set_sensitive(widget, description != NULL); gpass_command_stack_get_redo_description(app->command_stack, &description); widget = glade_xml_get_widget(GPASS_VIEW(self)->xml, "redo-menu"); gtk_widget_set_sensitive(widget, description != NULL); } void gpass_window_edit_items_sensitive(GPassWindow *self) { static char *edit_items[] = { "cut-menu", "copy-menu", "edit-menu", "unlink-menu", "run-menu", "edit-button", "unlink-button", "run-button", "cut-popup-menu", "copy-popup-menu", "edit-popup-menu", "unlink-popup-menu", "run-popup-menu", }; gboolean sensitive; gboolean copy_password_sensitive; gboolean copy_id_sensitive; GtkWidget *widget; int i; if (self->current == NULL) { sensitive = FALSE; copy_password_sensitive = FALSE; copy_id_sensitive = FALSE; } else { GPassEntry *entry = self->current; const gchar *id; gchar *password; sensitive = TRUE; g_object_get(entry, "id", &id, NULL); if (GPASS_IS_PASSWORD(entry)) { g_object_get(entry, "password", &password, NULL); } else { password = NULL; } if (id == NULL || *id == '\0') { copy_id_sensitive = FALSE; } else { copy_id_sensitive = TRUE; } if (password == NULL || *password == '\0') { copy_password_sensitive = FALSE; } else { copy_password_sensitive = TRUE; } g_free(password); } for (i = 0; i < G_N_ELEMENTS(edit_items); i++) { widget = glade_xml_get_widget(GPASS_VIEW(self)->xml, edit_items[i]); gtk_widget_set_sensitive(widget, sensitive); } widget = glade_xml_get_widget(GPASS_VIEW(self)->xml, "copy-password-menu"); gtk_widget_set_sensitive(widget, copy_password_sensitive); widget = glade_xml_get_widget(GPASS_VIEW(self)->xml, "copy-password-popup-menu"); gtk_widget_set_sensitive(widget, copy_password_sensitive); widget = glade_xml_get_widget(GPASS_VIEW(self)->xml, "copy-id-menu"); gtk_widget_set_sensitive(widget, copy_id_sensitive); widget = glade_xml_get_widget(GPASS_VIEW(self)->xml, "copy-id-popup-menu"); gtk_widget_set_sensitive(widget, copy_id_sensitive); widget = glade_xml_get_widget(GPASS_VIEW(self)->xml, "copy-both-menu"); gtk_widget_set_sensitive(widget, copy_password_sensitive && copy_id_sensitive); widget = glade_xml_get_widget(GPASS_VIEW(self)->xml, "copy-both-popup-menu"); gtk_widget_set_sensitive(widget, copy_password_sensitive && copy_id_sensitive); } static void gpass_window_paste_sensitive(GPassWindow *self) { GtkWidget *widget; widget = glade_xml_get_widget(GPASS_VIEW(self)->xml, "paste-menu"); gtk_widget_set_sensitive(widget, self->copied != NULL); } void gpass_window_before_command(GPassWindow *self) { stop_lock_timeout(self); } void gpass_window_after_command(GPassWindow *self) { start_lock_timeout(self); } /*********************************************************** * * Clipboard * ***********************************************************/ typedef struct { GPassWindow *self; GSList *list; } clipboard_context_t; static void clipboard_on_get_selection(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gpointer user_data) { clipboard_context_t *context = user_data; GSList *p; gchar *str; p = context->list; while (p != NULL && p->data == NULL) { p = g_slist_next(p); } if (p != NULL) { str = p->data; gtk_selection_data_set(selection_data, GDK_TARGET_STRING, 8, str, strlen(str)); if (p->next != NULL) { p->data = NULL; g_free(str); } gpass_window_status_say(context->self, _("ID/password retrieved from clipboard " "by another application.")); } } static void clipboard_on_clear_selection(GtkClipboard *clipboard, gpointer user_data) { clipboard_context_t *context = user_data; GSList *p; for (p = context->list; p != NULL; p = g_slist_next(p)) { g_free(p->data); p->data = NULL; } g_slist_free(context->list); g_free(context); } static void clipboard_copy_to(GPassWindow *self, GdkAtom atom, const gchar **str, int n) { GtkClipboard *clipboard = gtk_clipboard_get(atom); GtkTargetList *target_list; GtkTargetEntry *targets; clipboard_context_t *context; gint num_targets; GList *p; gint i; target_list = gtk_target_list_new(NULL, 0); gtk_target_list_add_text_targets(target_list, 0); num_targets = g_list_length(target_list->list); targets = g_new0(GtkTargetEntry, num_targets); i = 0; for (p = target_list->list; p != NULL; p = g_list_next(p)) { GtkTargetPair *pair = p->data; targets[i].target = gdk_atom_name(pair->target); i++; } context = g_new(clipboard_context_t, 1); context->self = self; context->list = NULL; for (i = n - 1; i >= 0; i--) { context->list = g_slist_prepend(context->list, g_strdup(str[i])); } gtk_clipboard_set_with_data(clipboard, targets, num_targets, clipboard_on_get_selection, clipboard_on_clear_selection, context); gtk_clipboard_set_can_store(clipboard, NULL, 0); g_free(targets); gtk_target_list_unref(target_list); } static void clipboard_copy_sequence(GPassWindow *self, const gchar **str, int n) { clipboard_copy_to(self, GDK_SELECTION_PRIMARY, str, n); clipboard_copy_to(self, GDK_SELECTION_CLIPBOARD, str, n); clipboard_copy_to(self, GDK_SELECTION_CLIPBOARD, str, n); } static void clipboard_copy(GPassWindow *self, const gchar *str) { const char *seq[] = { str }; clipboard_copy_sequence(self, seq, 1); } static void clipboard_clear(void) { GtkClipboard *clipboard; clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY); gtk_clipboard_clear(clipboard); clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); gtk_clipboard_clear(clipboard); } /*********************************************************** * * Signal handler * ***********************************************************/ /***** save *****/ static void save(GtkWidget *widget) { GPassWindow *self; GPassApplication *app; gboolean result; const gchar *msg; GError *error; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); app = GPASS_APPLICATION(GPASS_VIEW(self)->model); error = gpass_application_passwords_save(app, &result); if (error != NULL) { gpass_helper_error(error); } if (result) { msg = _("Password collection saved."); } else { msg = _("No changed the password collection."); } gpass_window_status_say(self, msg); gpass_window_after_command(self); } void gpass_window_on_save_menu_activate(GtkWidget *widget, gpointer user_data) { save(widget); } void gpass_window_on_save_button_clicked(GtkWidget *widget, gpointer user_data) { save(widget); } /***** change master password *****/ static void change_master_password(GtkWidget *widget) { GPassWindow *self; GPassApplication *app; GPassView *view; GPassViewResult view_result; GError *error; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); app = GPASS_APPLICATION(GPASS_VIEW(self)->model); error = gpass_view_factory_create_view (app->view_factory, "change-master-password", app, &view); if (error != NULL) { gpass_helper_error(error); } error = gpass_view_run(view, &view_result); if (error != NULL) { gpass_helper_error(error); } if (view_result == GPASS_VIEW_RESULT_SUCCEED) { gpass_window_status_say(self, _("Changed the master password.")); } gpass_window_after_command(self); } void gpass_window_on_change_password_menu_activate(GtkWidget *widget, gpointer user_data) { change_master_password(widget); } /***** quit *****/ static void confirm_quit(GtkWidget *widget) { GPassWindow *self; GPassApplication *app; GPassView *view; GPassViewResult view_result; GError *error; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); app = GPASS_APPLICATION(GPASS_VIEW(self)->model); if (gpass_application_passwords_is_changed(app)) { error = gpass_view_factory_create_view (app->view_factory, "confirm-quit", app, &view); if (error != NULL) { gpass_helper_error(error); } error = gpass_view_run(view, &view_result); if (error != NULL) { gpass_helper_error(error); } if (view_result != GPASS_VIEW_RESULT_SUCCEED) { gpass_window_after_command(self); return; } } GPASS_VIEW(self)->result = GPASS_VIEW_RESULT_SUCCEED; gpass_view_shutdown_main_loop(GPASS_VIEW(self)); } void gpass_window_on_quit_menu_activate(GtkWidget *widget, gpointer user_data) { confirm_quit(widget); } gboolean gpass_window_on_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data) { confirm_quit(widget); return TRUE; } /***** edit password *****/ static gboolean edit_entry(GPassWindow *self, GPassEntry *entry, GPassEntry **result) { GPassApplication *app = GPASS_APPLICATION(GPASS_VIEW(self)->model); GPassGnomeAttributeEditor *editor; GPassAttributeList *attributes; GPassViewResult view_result; const gchar *type; GError *error; if (self->attribute_editor == NULL) { editor = g_object_new(GPASS_TYPE_GNOME_ATTRIBUTE_EDITOR, "template", "attribute-editor", "model", app, NULL); self->attribute_editor = GPASS_VIEW(editor); } else { editor = GPASS_GNOME_ATTRIBUTE_EDITOR(self->attribute_editor); } g_object_get(entry, "type", &type, NULL); attributes = gpass_entry_class_attributes(GPASS_ENTRY_GET_CLASS(entry)); gpass_entry_get_attributes(entry, attributes); gpass_gnome_attribute_editor_set(editor, type, attributes, gpass_entry_has_child(entry)); g_object_unref(attributes); error = gpass_view_run(GPASS_VIEW(editor), &view_result); if (error != NULL) { gpass_error_show_and_exit(error); } if (view_result != GPASS_VIEW_RESULT_SUCCEED) { return FALSE; } gpass_gnome_attribute_editor_get(editor, &type, &attributes); error = gpass_entry_factory_create_entry(app->entry_factory, type, result); if (error != NULL) { gpass_error_show_and_exit(error); } gpass_entry_set_attributes(*result, attributes); g_object_unref(attributes); return TRUE; } static void push_edit_command(GtkWidget *widget) { GPassWindow *self; GPassApplication *app; GPassCommand *command; GPassEntry *original; GPassEntry *edited; time_t now; const gchar *name; GError *error; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); if (self->current == NULL) { goto end; } original = self->current; if (!edit_entry(self, original, &edited)) { goto end; } if (gpass_entry_equal(original, edited)) { g_object_unref(edited); goto end; } now = time(NULL); g_object_set(edited, "modification-time", now, NULL); app = GPASS_APPLICATION(GPASS_VIEW(self)->model); command = gpass_edit_command_new(app, self->current, edited); gpass_command_stack_push(app->command_stack, command); error = gpass_command_stack_redo(app->command_stack); if (error != NULL) { gpass_helper_error(error); } gpass_window_edit_items_sensitive(self); gpass_window_undo_redo_sensitive(self); g_object_get(original, "name", &name, NULL); gpass_window_status_say(self, _("Edited `%s'."), name); end: gpass_window_after_command(self); } void gpass_window_on_edit_menu_activate(GtkWidget *widget, gpointer user_data) { push_edit_command(widget); } void gpass_window_on_edit_button_clicked(GtkWidget *widget, gpointer user_data) { push_edit_command(widget); } void gpass_window_on_entry_tree_row_activated(GtkWidget *widget, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data) { push_edit_command(widget); } /***** add password *****/ static void add_password(GtkWidget *widget) { GPassWindow *self; GPassApplication *app; GPassEntry *default_entry, *entry; time_t now; GError *error; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); app = GPASS_APPLICATION(GPASS_VIEW(self)->model); error = gpass_entry_factory_create_default_entry(app->entry_factory, &default_entry); if (error != NULL) { gpass_error_show_and_exit(error); } now = time(NULL); g_object_set(default_entry, "creation-time", now, "modification-time", now, NULL); if (edit_entry(self, default_entry, &entry)) { const gchar *name; gpass_entry_tree_push_insert_command(self, entry, _("Add %s")); g_object_get(entry, "name", &name, NULL); gpass_window_status_say(self, _("Added `%s'."), name); } g_object_unref(default_entry); gpass_window_after_command(self); } void gpass_window_on_add_menu_activate(GtkWidget *widget, gpointer user_data) { add_password(widget); } void gpass_window_on_add_button_clicked(GtkWidget *widget, gpointer user_data) { add_password(widget); } /***** unlink password *****/ static void unlink_password(GtkWidget *widget) { GPassWindow *self; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); gpass_entry_tree_push_unlink_command(self, _("Remove %s")); gpass_window_after_command(self); } void gpass_window_on_unlink_menu_activate(GtkWidget *widget, gpointer user_data) { unlink_password(widget); } void gpass_window_on_unlink_button_clicked(GtkWidget *widget, gpointer user_data) { unlink_password(widget); } /***** undo / redo *****/ void gpass_window_on_undo_menu_activate(GtkWidget *widget, gpointer user_data) { GPassWindow *self; GPassApplication *app; const gchar *description; GError *error; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); app = GPASS_APPLICATION(GPASS_VIEW(self)->model); gpass_command_stack_get_undo_description(app->command_stack, &description); if (description == NULL) { goto end; } error = gpass_command_stack_undo(app->command_stack); if (error != NULL) { gpass_helper_error(error); } gpass_window_undo_redo_sensitive(self); gpass_window_status_say(self, _("Undo `%s'."), description); end: gpass_window_after_command(self); } void gpass_window_on_redo_menu_activate(GtkWidget *widget, gpointer user_data) { GPassWindow *self; GPassApplication *app; const gchar *description; GError *error; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); app = GPASS_APPLICATION(GPASS_VIEW(self)->model); gpass_command_stack_get_redo_description(app->command_stack, &description); if (description == NULL) { goto end; } error = gpass_command_stack_redo(app->command_stack); if (error != NULL) { gpass_helper_error(error); } gpass_window_undo_redo_sensitive(self); gpass_window_status_say(self, _("Redo `%s'."), description); end: gpass_window_after_command(self); } /***** run command *****/ static void run_command(GtkWidget *widget) { GPassWindow *self; GPassEntry *entry; const gchar *launcher; GString *command; GError *error; GPassEntryFactoryCursor *cursor; GPassApplication *app; const gchar *type; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); if (self->current == NULL) { goto end; } entry = self->current; app = GPASS_APPLICATION(GPASS_VIEW(self)->model); cursor = gpass_entry_factory_create_cursor(app->entry_factory); g_object_get(entry, "type", &type, NULL); error = gpass_entry_factory_cursor_seek(cursor, type); if (error != NULL) { gpass_helper_error(error); } g_object_get(cursor, "launcher", &launcher, NULL); command = g_string_new(NULL); gpass_entry_format(entry, launcher, &command); g_object_unref(cursor); if (command->len > 0) { error = NULL; if (g_spawn_command_line_async(command->str, &error)) { gpass_window_status_say(self, _("Executed `%s'."), command->str); } else { gpass_window_status_say(self, _("Failed executing `%s': %s"), command->str, error == NULL ? "" : error->message); } if (error != NULL) { g_error_free(error); } } else { const gchar *name; g_object_get(entry, "name", &name, NULL); gpass_window_status_say(self, _("No goto command for `%s'."), name); } g_string_free(command, TRUE); end: gpass_window_after_command(self); } void gpass_window_on_run_menu_activate(GtkWidget *widget, gpointer user_data) { run_command(widget); } void gpass_window_on_run_button_clicked(GtkWidget *widget, gpointer user_data) { run_command(widget); } /***** copy password and id to clipboard *****/ void gpass_window_on_copy_password_menu_activate(GtkWidget *widget, gpointer user_data) { GPassWindow *self; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); if (self->current != NULL) { GPassEntry *entry = self->current; const gchar *str; g_object_get(entry, "password", &str, NULL); if (str != NULL && *str != '\0') { const gchar *name; clipboard_copy(self, str); g_object_get(entry, "name", &name, NULL); gpass_window_status_say (self, _("Password for '%s' copied to clipboard."), name); } } gpass_window_after_command(self); } void gpass_window_on_copy_id_menu_activate(GtkWidget *widget, gpointer user_data) { GPassWindow *self; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); if (self->current != NULL) { GPassEntry *entry = self->current; const gchar *str; g_object_get(entry, "id", &str, NULL); if (str != NULL && *str != '\0') { const gchar *name; clipboard_copy(self, str); g_object_get(entry, "name", &name, NULL); gpass_window_status_say (self, _("ID for '%s' copied to clipboard."), name); } } gpass_window_after_command(self); } void gpass_window_on_copy_both_menu_activate(GtkWidget *widget, gpointer user_data) { GPassWindow *self; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); if (self->current != NULL) { GPassEntry *entry = self->current; const gchar *name, *id, *password; const gchar *seq[2]; int num_seq; g_object_get(entry, "id", &id, "password", &password, "name", &name, NULL); seq[0] = id; if (password == NULL || *password == '\0') { seq[1] = NULL; num_seq = 1; } else { seq[1] = password; num_seq = 2; } clipboard_copy_sequence(self, seq, num_seq); gpass_window_status_say (self, _("ID/Password for '%s' copied to clipboard."), name); } gpass_window_after_command(self); } /***** copy, cut and paste *****/ void gpass_window_on_copy_menu_activate(GtkWidget *widget, gpointer user_data) { GPassWindow *self; const gchar *name; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); if (self->current == NULL) { goto end; } if (self->copied != NULL) { g_object_unref(self->copied); } self->copied = self->current; g_object_ref(self->copied); gpass_window_paste_sensitive(self); g_object_get(self->copied, "name", &name, NULL); gpass_window_status_say(self, _("Copied `%s'."), name); end: gpass_window_after_command(self); } void gpass_window_on_cut_menu_activate(GtkWidget *widget, gpointer user_data) { GPassWindow *self; const gchar *name; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); if (self->current == NULL) { goto end; } if (self->copied != NULL) { g_object_unref(self->copied); } self->copied = self->current; g_object_ref(self->copied); gpass_window_paste_sensitive(self); gpass_entry_tree_push_unlink_command(self, _("Cut %s")); g_object_get(self->copied, "name", &name, NULL); gpass_window_status_say(self, _("Cutted `%s'."), name); end: gpass_window_after_command(self); } void gpass_window_on_paste_menu_activate(GtkWidget *widget, gpointer user_data) { GPassWindow *self; GPassApplication *app; const gchar *type; GPassEntry *entry; GPassAttributeList *attributes; const gchar *name; time_t now; GError *error; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); if (self->copied == NULL) { goto end; } app = GPASS_APPLICATION(GPASS_VIEW(self)->model); g_object_get(self->copied, "type", &type, NULL); error = gpass_entry_factory_create_entry(app->entry_factory, type, &entry); if (error != NULL) { gpass_helper_error(error); } attributes = gpass_entry_class_attributes(GPASS_ENTRY_GET_CLASS(self->copied)); gpass_entry_get_attributes(GPASS_ENTRY(self->copied), attributes); gpass_entry_set_attributes(entry, attributes); g_object_unref(attributes); now = time(NULL); g_object_set(entry, "modification-time", now, NULL); gpass_entry_tree_push_insert_command(self, entry, _("Paste %s")); g_object_get(entry, "name", &name, NULL); gpass_window_status_say(self, _("Pasted `%s'."), name); end: gpass_window_after_command(self); } /***** preferences *****/ void gpass_window_on_preferences_menu_activate(GtkWidget *widget, gpointer user_data) { GPassWindow *self; GPassApplication *app; GPassView *view; GPassViewResult result; GError *error; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); app = GPASS_APPLICATION(GPASS_VIEW(self)->model); error = gpass_view_factory_create_view(app->view_factory, "preferences", app, &view); if (error != NULL) { gpass_helper_error(error); } error = gpass_view_run(view, &result); if (error != NULL) { gpass_helper_error(error); } if (result == GPASS_VIEW_RESULT_SUCCEED) { gpass_window_status_say(self, _("Modified preferences.")); } gpass_window_after_command(self); } /***** visible *****/ void gpass_window_on_toolbar_visible_menu_activate(GtkWidget *widget, gpointer user_data) { GPassWindow *self; GtkWidget *toolbar; gboolean active; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); toolbar = glade_xml_get_widget(GPASS_VIEW(self)->xml, "toolbar-dock"); active = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); if (active) { gtk_widget_show(toolbar); gpass_window_status_say(self, _("Show the toolbar.")); } else { gtk_widget_hide(toolbar); gpass_window_status_say(self, _("Hide the toolbar.")); } gpass_window_after_command(self); } void gpass_window_on_statusbar_visible_menu_activate(GtkWidget *widget, gpointer user_data) { GPassWindow *self; GtkWidget *statusbar; gboolean active; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); statusbar = glade_xml_get_widget(GPASS_VIEW(self)->xml, "statusbar"); active = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); if (active) { gtk_widget_show(statusbar); gpass_window_status_say(self, _("Show the statusbar.")); } else { gtk_widget_hide(statusbar); gpass_window_status_say(self, _("Hide the statusbar.")); } gpass_window_after_command(self); } /***** about *****/ void gpass_window_on_about_menu_activate(GtkWidget *widget, gpointer user_data) { GPassWindow *self; GtkWidget *about; const gchar *authors[] = { _("Morten Fjord-Larsen"), _("Kouji TAKAO"), NULL }; const gchar *documenters[] = { NULL }; gchar *translator; GdkPixbuf *logo_pixbuf; GError *error = NULL; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_before_command(self); if (_("Translator") == "Translator") { translator = NULL; } else { translator = g_strdup(_("Put your translator here.")); } logo_pixbuf = gdk_pixbuf_new_from_file(PIXMAPS_DIR "/gpass-icon.png", &error); if (error != NULL) { gpass_error_show_and_exit(error); } about = gnome_about_new (_("GPass"), VERSION, "Copyright (c) 2004 Morten Fjord-Larsen\n" "Copyright (c) 2005 Kouji TAKAO", _("A simple password manager for the GNOME desktop"), authors, documenters, translator, logo_pixbuf); gtk_window_set_icon(GTK_WINDOW(about), logo_pixbuf); g_object_unref(logo_pixbuf); g_free(translator); gtk_widget_show_all(GTK_WIDGET(about)); gpass_window_after_command(self); } /***** popup menu *****/ static void select_entry_at_pos(GPassWindow *self, gint x, gint y) { GtkTreeView *entry_tree; GtkTreePath *path; gboolean result; entry_tree = GTK_TREE_VIEW (glade_xml_get_widget(GPASS_VIEW(self)->xml, "entry-tree")); result = gtk_tree_view_get_path_at_pos(entry_tree, x, y, &path, NULL, NULL, NULL); if (result) { GtkTreeModel *tree_model; GtkTreeIter iter; tree_model = gtk_tree_view_get_model(entry_tree); result = gtk_tree_model_get_iter(tree_model, &iter, path); gtk_tree_path_free(path); if (result) { GtkTreeSelection *selection; selection = gtk_tree_view_get_selection(entry_tree); gtk_tree_selection_select_iter(selection, &iter); } } } static void show_popup_menu(GPassWindow *self, GdkEventButton *event) { GtkWidget *menu; gint button, event_time; menu = glade_xml_get_widget(GPASS_VIEW(self)->xml, "popup-menu"); g_signal_connect(menu, "deactivate", G_CALLBACK(gtk_widget_hide), NULL); if (event) { GtkTreeView *entry_tree; button = event->button; event_time = event->time; entry_tree = GTK_TREE_VIEW (glade_xml_get_widget(GPASS_VIEW(self)->xml, "entry-tree")); if (event->window == gtk_tree_view_get_bin_window(entry_tree)) { select_entry_at_pos(self, event->x, event->y); } } else { button = 0; event_time = gtk_get_current_event_time(); } gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, button, event_time); } gboolean gpass_window_on_entry_tree_button_press_event(GtkWidget *widget, GdkEventButton *event) { GPassWindow *self; gpass_view_self_from_widget(widget, (gpointer **) &self); gpass_window_after_command(self); if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { show_popup_menu(self, event); return TRUE; } return FALSE; }