diff --git a/src/fileman.c b/src/fileman.c
index b859517..d55b3a6 100644
--- a/src/fileman.c
+++ b/src/fileman.c
@@ -1,1315 +1,1313 @@
/* fileman.c - The GNU Privacy Assistant
Copyright (C) 2000, 2001 G-N-U GmbH.
Copyright (C) 2007, 2008 g10 Code GmbH
This file is part of GPA.
GPA 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.
GPA is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see . */
/* The file encryption/decryption/sign window. */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "gpa.h"
#include "gtktools.h"
#include "gpawidgets.h"
#include "siglist.h"
#include "helpmenu.h"
#include "icons.h"
#include "fileman.h"
#include "gpafiledecryptop.h"
#include "gpafileencryptop.h"
#include "gpafilesignop.h"
#include "gpafileverifyop.h"
#if ! GTK_CHECK_VERSION (2, 10, 0)
#define GTK_STOCK_SELECT_ALL "gtk-select-all"
#endif
/* Object and class definition. */
struct _GpaFileManager
{
GtkWindow parent;
GtkWidget *window;
GtkWidget *list_files;
GList *selection_sensitive_actions;
};
struct _GpaFileManagerClass
{
GtkWindowClass parent_class;
};
/* There is only one instance of the file manage class. Use a global
variable to keep track of it. */
static GpaFileManager *instance;
/* We also need to save the parent class. */
static GObjectClass *parent_class;
/* Definition of the sensitivity function type. */
typedef gboolean (*sensitivity_func_t)(gpointer);
/* Constants to define the file list. */
enum
{
FILE_NAME_COLUMN,
FILE_N_COLUMNS
};
#define DND_TARGET_URI_LIST 1
/* Drag and drop target list. */
static GtkTargetEntry dnd_target_list[] =
{
{ "text/uri-list", 0, DND_TARGET_URI_LIST }
};
/* Local prototypes */
static GObject *gpa_file_manager_constructor
(GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties);
/*
* GtkWidget boilerplate.
*/
static void
gpa_file_manager_finalize (GObject *object)
{
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gpa_file_manager_init (GpaFileManager *fileman)
{
fileman->selection_sensitive_actions = NULL;
}
static void
gpa_file_manager_class_init (GpaFileManagerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
object_class->constructor = gpa_file_manager_constructor;
object_class->finalize = gpa_file_manager_finalize;
}
GType
gpa_file_manager_get_type (void)
{
static GType fileman_type = 0;
if (!fileman_type)
{
static const GTypeInfo fileman_info =
{
sizeof (GpaFileManagerClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gpa_file_manager_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GpaFileManager),
0, /* n_preallocs */
(GInstanceInitFunc) gpa_file_manager_init,
};
fileman_type = g_type_register_static (GTK_TYPE_WINDOW,
"GpaFileManager",
&fileman_info, 0);
}
return fileman_type;
}
/*
* File manager methods
*/
/* Return the currently selected files as a new list of filenames
* structs. The list and the texts must be freed by the caller.
*/
static GList *
get_selected_files (GtkWidget *list)
{
GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (list));
GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
GList *selection = gtk_tree_selection_get_selected_rows (sel, &model);
GList *files = NULL;
while (selection)
{
gpa_file_item_t file_item;
gchar *filename;
GtkTreeIter iter;
gtk_tree_model_get_iter (model, &iter, (GtkTreePath*) selection->data);
gtk_tree_model_get (model, &iter, FILE_NAME_COLUMN, &filename, -1);
file_item = g_malloc0 (sizeof (*file_item));
file_item->filename_in = filename;
files = g_list_append (files, file_item);
selection = g_list_next (selection);
}
/* Free the selection */
g_list_foreach (selection, (GFunc) gtk_tree_path_free, NULL);
g_list_free (selection);
return files;
}
/* Add file FILENAME to the file list of FILEMAN and select it */
static gboolean
add_file (GpaFileManager *fileman, const gchar *filename)
{
GtkListStore *store;
GtkTreeIter iter;
GtkTreePath *path;
GtkTreeSelection *sel;
gchar *filename_utf8;
/* The tree contains filenames in the UTF-8 encoding. */
filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
/* Try to convert from the current locale as fallback. This is important
for windows where g_filename_to_utf8 does not take locale into account
because the filedialogs already convert to utf8. */
if (!filename_utf8)
{
filename_utf8 = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
}
/* Last fallback is guranteed to never be NULL so in doubt we can still fail
later showing a filename that can't be found to the user etc.*/
if (!filename_utf8)
{
filename_utf8 = g_filename_display_name (filename);
}
store = GTK_LIST_STORE (gtk_tree_view_get_model
(GTK_TREE_VIEW (fileman->list_files)));
/* Check for duplicates. */
path = gtk_tree_path_new_first ();
if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
do
{
gchar *tmp;
gboolean exists;
gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, FILE_NAME_COLUMN,
&tmp, -1);
exists = g_str_equal (filename_utf8, tmp);
g_free (tmp);
if (exists)
{
g_free (filename_utf8);
gtk_tree_path_free (path);
return FALSE; /* This file is already in our list. */
}
}
while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
gtk_tree_path_free (path);
/* Append it to our list. */
gtk_list_store_append (store, &iter);
/* FIXME: Add the file status when/if gpgme supports it */
gtk_list_store_set (store, &iter, FILE_NAME_COLUMN, filename_utf8, -1);
/* Select the row */
sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (fileman->list_files));
gtk_tree_selection_select_iter (sel, &iter);
return TRUE;
}
/* Add a file created by an operation to the list */
static void
file_created_cb (GpaFileOperation *op, gpa_file_item_t item, gpointer data)
{
GpaFileManager *fileman = data;
add_file (fileman, item->filename_out);
}
/* Do whatever is required with a file operation, to ensure proper clean up */
static void
register_operation (GpaFileManager *fileman, GpaFileOperation *op)
{
g_signal_connect (G_OBJECT (op), "created_file",
G_CALLBACK (file_created_cb), fileman);
g_signal_connect (G_OBJECT (op), "completed",
G_CALLBACK (g_object_unref), NULL);
}
/* Management of the selection sensitive actions. */
/* Return true if a selection is active. */
static gboolean
has_selection (gpointer param)
{
GpaFileManager *fileman = param;
GtkTreeSelection *sel;
sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (fileman->list_files));
return (gtk_tree_selection_count_selected_rows (sel) > 0);
}
/* Add WIDGET to the list of sensitive actions of FILEMAN. */
static void
add_selection_sensitive_action (GpaFileManager *fileman,
GSimpleAction *action,
sensitivity_func_t callback)
{
g_object_set_data (G_OBJECT (action), "gpa_sensitivity", callback);
fileman->selection_sensitive_actions
= g_list_append (fileman->selection_sensitive_actions, action);
}
/* Update the sensitivity of the widget DATA and pass PARAM through to
the sensitivity callback. Usable as an iterator function in
g_list_foreach. */
static void
update_selection_sensitive_action (gpointer data, gpointer param)
{
sensitivity_func_t func;
func = g_object_get_data (G_OBJECT (data), "gpa_sensitivity");
g_simple_action_set_enabled (G_SIMPLE_ACTION (data), func (param));
}
/* Call update_selection_sensitive_action for all widgets in the list
of sensitive actions and pass FILEMAN through as the user data
parameter. */
static void
update_selection_sensitive_actions (GpaFileManager *fileman)
{
g_list_foreach (fileman->selection_sensitive_actions,
update_selection_sensitive_action,
(gpointer) fileman);
}
/* Actions as called by the menu items. */
static GSList *
get_load_file_name (GtkWidget *parent, const gchar *title,
const gchar *directory)
{
static GtkWidget *dialog;
GtkResponseType response;
GSList *filenames = NULL;
if (! dialog)
{
dialog = gtk_file_chooser_dialog_new
(title, GTK_WINDOW (parent), GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
}
if (directory)
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), directory);
gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (dialog));
/* Run the dialog until there is a valid response. */
response = gtk_dialog_run (GTK_DIALOG (dialog));
if (response == GTK_RESPONSE_OK)
filenames = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (dialog));
gtk_widget_hide (dialog);
return filenames;
}
/* Handle menu item "File/Open". */
void
open_file_one (gpointer data, gpointer user_data)
{
GpaFileManager *fileman = user_data;
gchar *filename = (gchar *) data;
/* FIXME: We are ignoring errors here. */
add_file (fileman, filename);
g_free (filename);
}
static void
file_open (GSimpleAction *simple, GVariant *parameter, gpointer param)
{
GpaFileManager *fileman = param;
GSList *filenames;
filenames = get_load_file_name (GTK_WIDGET (fileman), _("Open File"), NULL);
if (! filenames)
return;
g_slist_foreach (filenames, open_file_one, fileman);
g_slist_free (filenames);
}
/* Handle menu item "File/Clear". */
static void
file_clear (GSimpleAction *simple, GVariant *parameter, gpointer param)
{
GpaFileManager *fileman = param;
GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model
(GTK_TREE_VIEW (fileman->list_files)));
gtk_list_store_clear (store);
}
/* Handle menu item "File/Verify". */
static void
file_verify (GSimpleAction *simple, GVariant *parameter, gpointer param)
{
GpaFileManager *fileman = param;
GList *files;
GpaFileVerifyOperation *op;
files = get_selected_files (fileman->list_files);
if (!files)
return;
op = gpa_file_verify_operation_new (GTK_WIDGET (fileman), files);
register_operation (fileman, GPA_FILE_OPERATION (op));
}
/* Handle menu item "File/Sign". */
static void
file_sign (GSimpleAction *simple, GVariant *parameter, gpointer param)
{
GpaFileManager *fileman = param;
GList * files;
GpaFileSignOperation *op;
files = get_selected_files (fileman->list_files);
if (!files)
return;
op = gpa_file_sign_operation_new (GTK_WIDGET (fileman), files, FALSE);
register_operation (fileman, GPA_FILE_OPERATION (op));
}
/* Handle menu item "File/Encrypt". */
static void
file_encrypt (GSimpleAction *simple, GVariant *parameter, gpointer param)
{
GpaFileManager *fileman = param;
GList *files;
GpaFileEncryptOperation *op;
files = get_selected_files (fileman->list_files);
if (!files)
return;
op = gpa_file_encrypt_operation_new (GTK_WIDGET (fileman), files, FALSE);
register_operation (fileman, GPA_FILE_OPERATION (op));
}
/* Handle menu item "File/Decrypt". */
static void
file_decrypt (GSimpleAction *simple, GVariant *parameter, gpointer param)
{
GpaFileManager *fileman = param;
GList *files;
GpaFileDecryptOperation *op;
files = get_selected_files (fileman->list_files);
if (!files)
return;
op = gpa_file_decrypt_verify_operation_new (GTK_WIDGET (fileman), files);
register_operation (fileman, GPA_FILE_OPERATION (op));
}
/* Handle menu item "File/Close". */
static void
file_close (GSimpleAction *simple, GVariant *parameter, gpointer param)
{
GpaFileManager *fileman = param;
gtk_widget_destroy (GTK_WIDGET (fileman));
}
/* Handle menu item "File/Quit". */
static void
file_quit (GSimpleAction *simple, GVariant *parameter, gpointer param)
{
g_application_quit (G_APPLICATION (get_gpa_application ()));
}
/* Handle menu item "Edit/Select All". */
static void
edit_select_all (GSimpleAction *simple, GVariant *parameter, gpointer param)
{
GpaFileManager *fileman = param;
gtk_tree_selection_select_all (gtk_tree_view_get_selection
(GTK_TREE_VIEW (fileman->list_files)));
}
/* Construct the file manager menu and toolbar widgets and return
them. */
static void
fileman_action_new (GpaFileManager *fileman, GtkWidget **menubar,
GtkWidget **toolbar)
{
static const GActionEntry entries[] =
{
{ "File", NULL },
{ "Edit", NULL },
{ "file_open", file_open },
{ "file_clear", file_clear },
{ "file_sign", file_sign },
{ "file_verify", file_verify },
{ "file_encrypt", file_encrypt },
{ "file_decrypt", file_decrypt },
{ "file_close", file_close },
{ "file_quit", file_quit },
{ "edit_select_all", edit_select_all },
};
/*
static const GtkActionEntry old_entries[] =
{
// Toplevel.
{ "File", NULL, N_("_File"), NULL },
{ "Edit", NULL, N_("_Edit"), NULL },
// File menu.
{ "FileOpen", GTK_STOCK_OPEN, NULL, NULL,
N_("Open a file"), G_CALLBACK (file_open) },
{ "FileClear", GTK_STOCK_CLEAR, NULL, NULL,
N_("Close all files"), G_CALLBACK (file_clear) },
{ "FileSign", GPA_STOCK_SIGN, NULL, NULL,
N_("Sign the selected file"), G_CALLBACK (file_sign) },
{ "FileVerify", GPA_STOCK_VERIFY, NULL, NULL,
N_("Check signatures of selected file"), G_CALLBACK (file_verify) },
{ "FileEncrypt", GPA_STOCK_ENCRYPT, NULL, NULL,
N_("Encrypt the selected file"), G_CALLBACK (file_encrypt) },
{ "FileDecrypt", GPA_STOCK_DECRYPT, NULL, NULL,
N_("Decrypt the selected file"), G_CALLBACK (file_decrypt) },
{ "FileClose", GTK_STOCK_CLOSE, NULL, NULL,
N_("Close the window"), G_CALLBACK (file_close) },
{ "FileQuit", GTK_STOCK_QUIT, NULL, NULL,
N_("Quit the program"), G_CALLBACK (g_application_quit) },
// Edit menu.
{ "EditSelectAll", GTK_STOCK_SELECT_ALL, NULL, "A",
N_("Select all files"), G_CALLBACK (edit_select_all) }
};
*/
/*
static const char *ui_description =
""
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
#ifdef ENABLE_CARD_MANAGER
" "
#endif
#if 0
" "
#endif
" "
"";
*/
static const char *menu_string = {
""
""
""
""
};
/*
GtkAccelGroup *accel_group;
GtkActionGroup *action_group;
GtkAction *action;
GtkUIManager *ui_manager;
GError *error;
action_group = gtk_action_group_new ("MenuActions");
gtk_action_group_set_translation_domain (action_group, PACKAGE);
gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries),
fileman);
gtk_action_group_add_actions (action_group, gpa_help_menu_action_entries,
G_N_ELEMENTS (gpa_help_menu_action_entries),
fileman);
gtk_action_group_add_actions (action_group, gpa_windows_menu_action_entries,
G_N_ELEMENTS (gpa_windows_menu_action_entries),
fileman);
gtk_action_group_add_actions
(action_group, gpa_preferences_menu_action_entries,
G_N_ELEMENTS (gpa_preferences_menu_action_entries), fileman);
ui_manager = gtk_ui_manager_new ();
gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
accel_group = gtk_ui_manager_get_accel_group (ui_manager);
gtk_window_add_accel_group (GTK_WINDOW (fileman), accel_group);
if (! gtk_ui_manager_add_ui_from_string (ui_manager, ui_description,
-1, &error))
{
g_message ("building fileman menus failed: %s", error->message);
g_error_free (error);
exit (EXIT_FAILURE);
}
// Fixup the icon theme labels which are too long for the toolbar.
action = gtk_action_group_get_action (action_group, "WindowsKeyringEditor");
g_object_set (action, "short_label", _("Keyring"), NULL);
#ifdef ENABLE_CARD_MANAGER
action = gtk_action_group_get_action (action_group, "WindowsCardManager");
g_object_set (action, "short_label", _("Card"), NULL);
#endif
// Take care of sensitiveness of widgets.
action = gtk_action_group_get_action (action_group, "FileSign");
add_selection_sensitive_action (fileman, action, has_selection);
action = gtk_action_group_get_action (action_group, "FileVerify");
add_selection_sensitive_action (fileman, action, has_selection);
action = gtk_action_group_get_action (action_group, "FileEncrypt");
add_selection_sensitive_action (fileman, action, has_selection);
action = gtk_action_group_get_action (action_group, "FileDecrypt");
add_selection_sensitive_action (fileman, action, has_selection);
*menubar = gtk_ui_manager_get_widget (ui_manager, "/MainMenu");
*toolbar = gtk_ui_manager_get_widget (ui_manager, "/ToolBar");
gpa_toolbar_set_homogeneous (GTK_TOOLBAR (*toolbar), FALSE);
*/
GError **err;
GtkBuilder *gtk_builder = gtk_builder_new_from_string (menu_string, -1);
if (gtk_builder_add_from_string( gtk_builder, menu_string , -1, err) == 0) {
printf("ERROR: %s \n", (*err)->message);
}
GMenuModel *menu_bar_model = G_MENU_MODEL (gtk_builder_get_object (GTK_BUILDER (gtk_builder), "main_menu"));
*menubar = gtk_menu_bar_new_from_model (menu_bar_model);
/*
GMenuModel *popup_menu_model = G_MENU_MODEL (gtk_builder_get_object (GTK_BUILDER (gtk_builder), "popupmenu"));
*popup = gtk_menu_new_from_model (popup_menu_model);
*/
GObject *grid = gtk_builder_get_object (GTK_BUILDER (gtk_builder), "toolbar");
GtkCssProvider *css_provider = gtk_css_provider_new();
GdkDisplay *display = gdk_display_get_default();
GdkScreen *screen = gdk_display_get_default_screen (display);
gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER(css_provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
gtk_css_provider_load_from_data(css_provider,
"#toolbar {\n"
//" padding-left: 55px;\n"
// " padding-right: 5px;\n"
// " border-radius: 3px;\n"
"}\n", -1, NULL);
GtkStyleContext *style_context;
style_context = gtk_widget_get_style_context (GTK_WIDGET (grid));
//gtk_widget_add_css_class (grid, "toolbar");
*toolbar = grid;
// We must set the name to the toolbar for css to recognize it
gtk_widget_set_name(*toolbar, "toolbar");
gtk_style_context_add_class (style_context, "toolbar");
GtkApplication *gpa_app = get_gpa_application ();
g_action_map_add_action_entries (G_ACTION_MAP (gpa_app),
gpa_windows_menu_g_action_entries,
G_N_ELEMENTS (gpa_windows_menu_g_action_entries),
fileman);
g_action_map_add_action_entries (G_ACTION_MAP (gpa_app),
entries,
G_N_ELEMENTS (entries),
fileman);
g_action_map_add_action_entries (G_ACTION_MAP (gpa_app),
gpa_help_menu_g_action_entries,
G_N_ELEMENTS (gpa_help_menu_g_action_entries),
fileman);
g_action_map_add_action_entries (G_ACTION_MAP (gpa_app),
gpa_preferences_menu_g_action_entries,
G_N_ELEMENTS (gpa_preferences_menu_g_action_entries),
fileman);
GSimpleAction *action;
action = (GSimpleAction*)g_action_map_lookup_action (G_ACTION_MAP (gpa_app), "file_sign");
add_selection_sensitive_action (fileman, action, has_selection);
action = (GSimpleAction*)g_action_map_lookup_action (G_ACTION_MAP (gpa_app), "file_verify");
add_selection_sensitive_action (fileman, action, has_selection);
action = (GSimpleAction*)g_action_map_lookup_action (G_ACTION_MAP (gpa_app), "file_encrypt");
add_selection_sensitive_action (fileman, action, has_selection);
action = (GSimpleAction*)g_action_map_lookup_action (G_ACTION_MAP (gpa_app), "file_decrypt");
add_selection_sensitive_action (fileman, action, has_selection);
}
/* Drag and Drop handler. */
/* Handler for "drag-drop". This signal is emitted when the user
drops the selection. */
static gboolean
dnd_drop_handler (GtkWidget *widget, GdkDragContext *context,
gint x, gint y, guint tim, gpointer user_data)
{
GdkAtom target_type = gdk_atom_intern ("text/uri-list", FALSE);
GList *targets = gdk_drag_context_list_targets(context);
/* If the source offers a target we request the data from her. */
if (targets && g_list_find (targets,
GDK_ATOM_TO_POINTER (target_type)))
{
gtk_drag_get_data (widget, context, target_type, tim);
return TRUE;
}
return FALSE;
}
/* Handler for "drag-data-received". This signal is emitted when the
data has been received from the source. */
static void
dnd_data_received_handler (GtkWidget *widget, GdkDragContext *context,
gint x, gint y, GtkSelectionData *selection_data,
guint target_type, guint tim, gpointer user_data)
{
GpaFileManager *fileman = user_data;
gboolean dnd_success = FALSE;
gboolean delete_selection_data = FALSE;
// const guchar *our_selection_data = gtk_selection_data_get_data(selection_data);
/* Is that usable by us? */
if (selection_data && gtk_selection_data_get_length(selection_data) >= 0 )
{
GdkDragAction drag_action = gdk_drag_context_get_suggested_action(context);
if (drag_action == GDK_ACTION_MOVE)
delete_selection_data = TRUE;
/* Check that we got a format we can use. */
if (target_type == DND_TARGET_URI_LIST)
{
//char *p = (char *) selection_data->data;
char *p = (char *)gtk_selection_data_get_data(selection_data);
char **list;
int i;
list = g_uri_list_extract_uris (p);
for (i=0; list && list[i]; i++)
{
char *name = g_filename_from_uri (list[i], NULL, NULL);
if (name)
{
/* Canonical line endings are required for an uri-list. */
if ((p = strchr (name, '\r')))
*p = 0;
add_file (fileman, name);
g_free (name);
}
}
g_strfreev (list);
dnd_success = TRUE;
}
}
/* Finish the DnD processing. */
gtk_drag_finish (context, dnd_success, delete_selection_data, tim);
}
/* Construct the file list object. */
static GtkWidget *
file_list_new (GpaFileManager * fileman)
{
GtkWidget *scrollerFile;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkTreeSelection *sel;
GtkListStore *store = gtk_list_store_new (1, G_TYPE_STRING);
GtkWidget *list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (_("File"), renderer,
"text",
FILE_NAME_COLUMN,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE);
g_signal_connect_swapped (sel, "changed",
G_CALLBACK (update_selection_sensitive_actions),
fileman);
- gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (list), TRUE);
-
scrollerFile = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollerFile),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollerFile),
GTK_SHADOW_IN);
fileman->list_files = list;
gtk_widget_grab_focus (list);
gtk_container_add (GTK_CONTAINER (scrollerFile), list);
return scrollerFile;
}
/* Callback for the destroy signal. */
static void
file_manager_closed (GtkWidget *widget, gpointer param)
{
instance = NULL;
}
/* Construct a new class object of GpaFileManager. */
static GObject*
gpa_file_manager_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GObject *object;
GpaFileManager *fileman;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *icon;
gchar *markup;
GtkWidget *menubar;
GtkWidget *file_box;
GtkWidget *file_frame;
GtkWidget *toolbar;
GtkWidget *align;
guint pt, pb, pl, pr;
/* Invoke parent's constructor. */
object = parent_class->constructor (type,
n_construct_properties,
construct_properties);
fileman = GPA_FILE_MANAGER (object);
/* Initialize. */
gpa_window_set_title (GTK_WINDOW (fileman), _("File Manager"));
gtk_window_set_default_size (GTK_WINDOW (fileman), 640, 480);
/* Realize the window so that we can create pixmaps without warnings. */
gtk_widget_realize (GTK_WIDGET (fileman));
/* Use a vbox to show the menu, toolbar and the file container. */
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
/* Get the menu and the toolbar. */
fileman_action_new (fileman, &menubar, &toolbar);
gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, TRUE, 0);
/* Add a fancy label that tells us: This is the file manager. */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
icon = gtk_image_new_from_icon_name ("folder", GTK_ICON_SIZE_DND);
gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, TRUE, 0);
label = gtk_label_new (NULL);
markup = g_strdup_printf ("%s",
_("File Manager"));
gtk_label_set_markup (GTK_LABEL (label), markup);
g_free (markup);
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 10);
gtk_widget_set_halign (GTK_WIDGET (label), GTK_ALIGN_START);
gtk_widget_set_valign (GTK_WIDGET (label), GTK_ALIGN_CENTER);
/* Third a hbox with the file list. */
align = gtk_alignment_new (0.5, 0.5, 1, 1);
gtk_alignment_get_padding (GTK_ALIGNMENT (align),
&pt, &pb, &pl, &pr);
gtk_alignment_set_padding (GTK_ALIGNMENT (align), pt, pb + 5,
pl + 5, pr + 5);
gtk_box_pack_start (GTK_BOX (vbox), align, TRUE, TRUE, 0);
file_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
file_frame = file_list_new (fileman);
gtk_box_pack_start (GTK_BOX (file_box), file_frame, TRUE, TRUE, 0);
gtk_container_add (GTK_CONTAINER (align), file_box);
gtk_container_add (GTK_CONTAINER (fileman), vbox);
g_signal_connect (object, "destroy",
G_CALLBACK (file_manager_closed), object);
/* Make the file box a DnD destination. */
gtk_drag_dest_set (file_box,
(GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT),
dnd_target_list,
DIM (dnd_target_list),
GDK_ACTION_COPY);
g_signal_connect (file_box, "drag-drop",
G_CALLBACK (dnd_drop_handler), fileman);
g_signal_connect (file_box, "drag-data-received",
G_CALLBACK (dnd_data_received_handler), fileman);
return object;
}
static GpaFileManager *
gpa_fileman_new ()
{
GpaFileManager *fileman;
fileman = g_object_new (GPA_FILE_MANAGER_TYPE, NULL);
update_selection_sensitive_actions (fileman);
return fileman;
}
/* API */
GtkWidget *
gpa_file_manager_get_instance (void)
{
if (!instance)
{
instance = gpa_fileman_new ();
}
return GTK_WIDGET (instance);
}
gboolean gpa_file_manager_is_open (void)
{
return (instance != NULL);
}
void gpa_file_manager_open_file (GpaFileManager *fileman,
const gchar *filename)
{
if (!add_file (fileman, filename))
gpa_window_error (_("The file is already open."),
GTK_WIDGET (fileman));
/* FIXME: Release filename? */
}
diff --git a/src/gpa-tofu-list.c b/src/gpa-tofu-list.c
index 0ac153d..ddbea23 100644
--- a/src/gpa-tofu-list.c
+++ b/src/gpa-tofu-list.c
@@ -1,266 +1,265 @@
/* gpa-tofu-list.c - A list to show TOFU information.
* Copyright (C) 2016 g10 Code GmbH
*
* This file is part of GPA
*
* GPA 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.
*
* GPA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
#include
#include "gpa.h"
#include "convert.h"
#include "gtktools.h"
#include "keytable.h"
#include "gpa-tofu-list.h"
#ifdef ENABLE_TOFU_INFO
static gboolean tofu_list_query_tooltip_cb (GtkWidget *wdiget, int x, int y,
gboolean keyboard_mode,
GtkTooltip *tooltip,
gpointer user_data);
typedef enum
{
TOFU_ADDRESS,
TOFU_VALIDITY,
TOFU_POLICY,
TOFU_COUNT,
TOFU_FIRSTSIGN,
TOFU_LASTSIGN,
TOFU_FIRSTENCR,
TOFU_LASTENCR,
TOFU_N_COLUMNS
} SubkeyListColumn;
/* Create a new subkey list. */
GtkWidget *
gpa_tofu_list_new (void)
{
GtkListStore *store;
GtkWidget *list;
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
/* Init the model */
store = gtk_list_store_new (TOFU_N_COLUMNS,
G_TYPE_STRING, /* address */
G_TYPE_STRING, /* validity */
G_TYPE_STRING, /* policy */
G_TYPE_STRING, /* count */
G_TYPE_STRING, /* firstsign */
G_TYPE_STRING, /* lastsign */
G_TYPE_STRING, /* firstencr */
G_TYPE_STRING /* lastencr */
);
/* The view */
list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
- gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (list), TRUE);
/* Add the columns */
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
"text", TOFU_ADDRESS,
NULL);
gpa_set_column_title (column, _("Address"),
_("The mail address."));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
"text", TOFU_VALIDITY,
NULL);
gpa_set_column_title (column, _("Validity"),
_("The TOFU validity of the mail address:\n"
" Minimal = Only little history available\n"));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
"text", TOFU_POLICY,
NULL);
gpa_set_column_title (column, _("Policy"),
_("The TOFU policy set for this mail address."));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
"text", TOFU_COUNT,
NULL);
gpa_set_column_title (column, _("Count"),
_("The number of signatures seen for this address\n"
"and the number of encryption done to this address.")
);
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
"text", TOFU_FIRSTSIGN,
NULL);
gpa_set_column_title (column, _("First Sig"),
_("The date the first signature was verified."));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
"text", TOFU_LASTSIGN,
NULL);
gpa_set_column_title (column, _("Last Sig"),
_("The most recent date a signature was verified."));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
"text", TOFU_FIRSTENCR,
NULL);
gpa_set_column_title (column, _("First Enc"),
_("The date the first encrypted mail was sent."));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
"text", TOFU_LASTENCR,
NULL);
gpa_set_column_title (column, _("Last Enc"),
_("The most recent date an encrypted mail was sent."));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
g_object_set (list, "has-tooltip", TRUE, NULL);
g_signal_connect (list, "query-tooltip",
G_CALLBACK (tofu_list_query_tooltip_cb), list);
return list;
}
static const gchar *
tofu_validity_str (gpgme_tofu_info_t tofu)
{
switch (tofu->validity)
{
case 0: return _("Conflict");
case 1: return _("Unknown");
case 2: return _("Minimal");
case 3: return _("Basic");
case 4: return _("Full");
default: return "?";
}
}
static const gchar *
tofu_policy_str (gpgme_tofu_info_t tofu)
{
switch (tofu->policy)
{
case GPGME_TOFU_POLICY_NONE: return _("None");
case GPGME_TOFU_POLICY_AUTO: return _("Auto");
case GPGME_TOFU_POLICY_GOOD: return _("Good");
case GPGME_TOFU_POLICY_UNKNOWN: return _("Unknown");
case GPGME_TOFU_POLICY_BAD: return _("Bad");
case GPGME_TOFU_POLICY_ASK: return _("Ask");
}
return "?";
}
/* Set the key whose subkeys should be displayed. */
void
gpa_tofu_list_set_key (GtkWidget *list, gpgme_key_t key)
{
GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model
(GTK_TREE_VIEW (list)));
GtkTreeIter iter;
gpgme_user_id_t uid;
gpgme_tofu_info_t tofu;
char *countstr, *firstsign, *lastsign, *firstencr, *lastencr;
/* Empty the list */
gtk_list_store_clear (store);
if (!key || !key->uids)
return;
for (uid = key->uids; uid; uid = uid->next)
{
if (!uid->address || !uid->tofu)
continue; /* No address or tofu info. */
tofu = uid->tofu;
/* Note that we do not need to filter ADDRESS like we do with
* user ids because GPGME checked that it is a valid mail
* address. */
countstr = g_strdup_printf ("%hu/%hu", tofu->signcount, tofu->encrcount);
firstsign = gpa_date_string (tofu->signfirst);
lastsign = gpa_date_string (tofu->signlast);
firstencr = gpa_date_string (tofu->encrfirst);
lastencr = gpa_date_string (tofu->encrlast);
gtk_list_store_append (store, &iter);
gtk_list_store_set
(store, &iter,
TOFU_ADDRESS, uid->address,
TOFU_VALIDITY, tofu_validity_str (tofu),
TOFU_POLICY, tofu_policy_str (tofu),
TOFU_COUNT, countstr,
TOFU_FIRSTSIGN,firstsign,
TOFU_LASTSIGN, lastsign,
TOFU_FIRSTENCR,firstencr,
TOFU_LASTENCR, lastencr,
-1);
g_free (countstr);
g_free (firstsign);
g_free (lastsign);
g_free (firstencr);
g_free (lastencr);
}
}
/* Tooltip display callback. */
static gboolean
tofu_list_query_tooltip_cb (GtkWidget *widget, int x, int y,
gboolean keyboard_tip,
GtkTooltip *tooltip, gpointer user_data)
{
GtkTreeView *tv = GTK_TREE_VIEW (widget);
GtkTreeViewColumn *column;
char *text;
(void)user_data;
if (!gtk_tree_view_get_tooltip_context (tv, &x, &y, keyboard_tip,
NULL, NULL, NULL))
return FALSE; /* Not at a row - do not show a tooltip. */
if (!gtk_tree_view_get_path_at_pos (tv, x, y, NULL, &column, NULL, NULL))
return FALSE;
widget = gtk_tree_view_column_get_widget (column);
text = widget? gtk_widget_get_tooltip_text (widget) : NULL;
if (!text)
return FALSE; /* No tooltip desired. */
gtk_tooltip_set_text (tooltip, text);
g_free (text);
return TRUE; /* Show tooltip. */
}
#endif /*ENABLE_TOFU_INFO*/
diff --git a/src/gpa-uid-list.c b/src/gpa-uid-list.c
index 0136e57..afe5fd1 100644
--- a/src/gpa-uid-list.c
+++ b/src/gpa-uid-list.c
@@ -1,169 +1,168 @@
/* gpa-uid-list.c - A list to show User ID information.
* Copyright (C) 2018 g10 Code GmbH
*
* This file is part of GPA
*
* GPA 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.
*
* GPA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
#include
#include "gpa.h"
#include "convert.h"
#include "gtktools.h"
#include "keytable.h"
#include "gpa-uid-list.h"
static gboolean uid_list_query_tooltip_cb (GtkWidget *wdiget, int x, int y,
gboolean keyboard_mode,
GtkTooltip *tooltip,
gpointer user_data);
typedef enum
{
UID_ADDRESS,
UID_VALIDITY,
UID_UPDATE,
UID_FULLUID,
UID_N_COLUMNS
} UidListColumn;
/* Create a new user id list. */
GtkWidget *
gpa_uid_list_new (void)
{
GtkListStore *store;
GtkWidget *list;
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
/* Init the model */
store = gtk_list_store_new (UID_N_COLUMNS,
G_TYPE_STRING, /* address */
G_TYPE_STRING, /* validity */
G_TYPE_STRING, /* updated */
G_TYPE_STRING /* fulluid */
);
/* The view */
list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
- gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (list), TRUE);
/* Add the columns */
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
"text", UID_ADDRESS,
NULL);
gpa_set_column_title (column, _("Address"),
_("The mail address."));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
"text", UID_VALIDITY,
NULL);
gpa_set_column_title (column, _("Validity"),
_("The validity of the mail address\n"));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
"text", UID_UPDATE,
NULL);
gpa_set_column_title (column, _("Update"),
_("The date the key was last updated via this mail address."));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
"text", UID_FULLUID,
NULL);
gpa_set_column_title (column, _("User ID"),
_("The full user ID."));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
g_object_set (list, "has-tooltip", TRUE, NULL);
g_signal_connect (list, "query-tooltip",
G_CALLBACK (uid_list_query_tooltip_cb), list);
return list;
}
/* Set the key whose user ids shall be displayed. */
void
gpa_uid_list_set_key (GtkWidget *list, gpgme_key_t key)
{
GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model
(GTK_TREE_VIEW (list)));
GtkTreeIter iter;
gpgme_user_id_t uid;
/* Empty the list */
gtk_list_store_clear (store);
if (!key || !key->uids)
return;
for (uid = key->uids; uid; uid = uid->next)
{
char *lupd = gpa_update_origin_string (uid->last_update, uid->origin);
gtk_list_store_append (store, &iter);
gtk_list_store_set
(store, &iter,
UID_ADDRESS, uid->address? uid->address : "",
UID_VALIDITY, gpa_uid_validity_string (uid),
UID_UPDATE, lupd,
UID_FULLUID, uid->uid,
-1);
g_free (lupd);
}
}
/* Tooltip display callback. */
static gboolean
uid_list_query_tooltip_cb (GtkWidget *widget, int x, int y,
gboolean keyboard_tip,
GtkTooltip *tooltip, gpointer user_data)
{
GtkTreeView *tv = GTK_TREE_VIEW (widget);
GtkTreeViewColumn *column;
char *text;
(void)user_data;
if (!gtk_tree_view_get_tooltip_context (tv, &x, &y, keyboard_tip,
NULL, NULL, NULL))
return FALSE; /* Not at a row - do not show a tooltip. */
if (!gtk_tree_view_get_path_at_pos (tv, x, y, NULL, &column, NULL, NULL))
return FALSE;
widget = gtk_tree_view_column_get_widget (column);
text = widget? gtk_widget_get_tooltip_text (widget) : NULL;
if (!text)
return FALSE; /* No tooltip desired. */
gtk_tooltip_set_text (tooltip, text);
g_free (text);
return TRUE; /* Show tooltip. */
}
diff --git a/src/recipientdlg.c b/src/recipientdlg.c
index 8c723b2..eecf23d 100644
--- a/src/recipientdlg.c
+++ b/src/recipientdlg.c
@@ -1,1245 +1,1244 @@
/* recipientdlg.c - A dialog to select a mail recipient.
Copyright (C) 2008 g10 Code GmbH.
This file is part of GPA
GPA 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.
GPA is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see . */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include "gpa.h"
#include "i18n.h"
#include "gtktools.h"
#include "selectkeydlg.h"
#include "recipientdlg.h"
struct _RecipientDlg
{
GtkDialog parent;
GtkWidget *clist_keys;
GtkWidget *statushint;
GtkWidget *radio_pgp;
GtkWidget *radio_x509;
GtkWidget *radio_auto;
GtkWidget *popup_menu;
/* Flag to disable updates of the status hint. This is actual a
counter with updates only allowed if it is zero. */
int freeze_update_statushint;
/* Flag to disable any key selection. This is used while a key
selection is active. Implemented as a counter. */
int freeze_key_selection;
/* Set if this dialog has usable key to be passed back to the
caller. You need to call update_statushint to set it. */
int usable;
/* The selected protocol. This is also set by update_statushint. */
gpgme_protocol_t selected_protocol;
};
struct _RecipientDlgClass
{
GtkDialogClass parent_class;
};
/* The parent class. */
static GObjectClass *parent_class;
/* Indentifiers for our properties. */
enum
{
PROP_0,
PROP_WINDOW,
PROP_FORCE_ARMOR
};
/* For performance reasons we truncate the listing of ambiguous keys
at a reasonable value. */
#define TRUNCATE_KEYSEARCH_AT 40
/* An object to keep information about keys. */
struct keyinfo_s
{
/* An array with associated key(s) or NULL if none found/selected. */
gpgme_key_t *keys;
/* The allocated size of the KEYS array. This includes the
terminating NULL entry. */
unsigned int dimof_keys;
/* If set, indicates that the KEYS array has been truncated. */
int truncated:1;
};
/* Management information for each recipient. This data is used per
recipient. */
struct userdata_s
{
/* The recipient's address. */
char *mailbox;
/* Information about PGP keys. */
struct keyinfo_s pgp;
/* Information about X.509 keys. */
struct keyinfo_s x509;
/* If the user has set this field, no encryption key will be
required for the recipient. */
int ignore_recipient;
};
/* Identifiers for the columns of the RECPLIST. */
enum
{
RECPLIST_MAILBOX, /* The rfc822 mailbox to whom a key needs to
be associated. */
RECPLIST_HAS_PGP, /* A PGP certificate is available. */
RECPLIST_HAS_X509, /* An X.509 certificate is available. */
RECPLIST_KEYID, /* The key ID of the associated key. */
RECPLIST_USERDATA, /* Pointer to management information (struct
userdata_s *). */
RECPLIST_N_COLUMNS
};
/* Create the main list of this dialog. */
static GtkWidget *
recplist_window_new (void)
{
GtkListStore *store;
GtkWidget *list;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
/* Create a model and associate a view. */
store = gtk_list_store_new (RECPLIST_N_COLUMNS,
G_TYPE_STRING,
G_TYPE_BOOLEAN,
G_TYPE_BOOLEAN,
G_TYPE_STRING,
G_TYPE_POINTER);
list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
- gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (list), TRUE);
/* Define the columns. */
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes
(NULL, renderer, "markup", RECPLIST_MAILBOX, NULL);
gpa_set_column_title (column, _("Recipient"),
_("Shows the recipients of the message."
" A key needs to be assigned to each recipient."));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_toggle_new ();
column = gtk_tree_view_column_new_with_attributes
(NULL, renderer, "active", RECPLIST_HAS_PGP, NULL);
gpa_set_column_title (column, "PGP",
_("Checked if at least one matching"
" OpenPGP certificate has been found."));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_toggle_new ();
column = gtk_tree_view_column_new_with_attributes
(NULL, renderer, "active", RECPLIST_HAS_X509, NULL);
gpa_set_column_title (column, "X.509",
_("Checked if at least one matching"
" X.509 certificate for use with S/MIME"
" has been found."));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes
(NULL, renderer, "text", RECPLIST_KEYID, NULL);
gpa_set_column_title (column,
_("Key ID"),
_("Shows the key ID of the selected key or"
" an indication that a key needs to be selected."));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
return list;
}
/* Get an interator for the selected row. Store it in ITER and
returns the mdeol. if nothing is selected NULL is return and ITER
is not valid. */
static GtkTreeModel *
get_selected_row (RecipientDlg *dialog, GtkTreeIter *iter)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
g_return_val_if_fail (dialog, NULL);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->clist_keys));
if (gtk_tree_selection_count_selected_rows (selection) == 1
&& gtk_tree_selection_get_selected (selection, &model, iter))
return model;
return NULL;
}
/* Compute and display a new help text for the statushint. */
static void
update_statushint (RecipientDlg *dialog)
{
gpgme_protocol_t req_protocol, sel_protocol;
GtkTreeModel *model;
GtkTreeIter iter;
int missing_keys = 0;
int ambiguous_pgp_keys = 0;
int ambiguous_x509_keys = 0;
int n_pgp_keys = 0;
int n_x509_keys = 0;
int n_keys = 0;
const char *hint;
int okay = 0;
if (dialog->freeze_update_statushint)
return;
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->clist_keys));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->radio_pgp)))
req_protocol = GPGME_PROTOCOL_OpenPGP;
else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
(dialog->radio_x509)))
req_protocol = GPGME_PROTOCOL_CMS;
else
req_protocol = GPGME_PROTOCOL_UNKNOWN;
sel_protocol = GPGME_PROTOCOL_UNKNOWN;
if (gtk_tree_model_get_iter_first (model, &iter))
{
do
{
gboolean has_pgp, has_x509;
struct userdata_s *info;
gtk_tree_model_get (model, &iter,
RECPLIST_HAS_PGP, &has_pgp,
RECPLIST_HAS_X509, &has_x509,
RECPLIST_USERDATA, &info,
-1);
if (!info)
missing_keys++; /* Oops */
else if (info->ignore_recipient)
;
else if (!info->pgp.keys && !info->x509.keys)
missing_keys++;
else if ((req_protocol == GPGME_PROTOCOL_OpenPGP && !has_pgp)
||(req_protocol == GPGME_PROTOCOL_CMS && !has_x509))
; /* Not of the requested protocol. */
else
{
n_keys++;
if (info->pgp.keys && info->pgp.keys[0])
{
n_pgp_keys++;
if (info->pgp.keys[1])
ambiguous_pgp_keys++;
}
if (info->x509.keys && info->x509.keys[0])
{
n_x509_keys++;
if (info->x509.keys[1])
ambiguous_x509_keys++;
}
}
}
while (gtk_tree_model_iter_next (model, &iter));
}
if (req_protocol == GPGME_PROTOCOL_UNKNOWN)
{
/* We select the protocol with the most available keys,
preferring PGP. */
if (n_pgp_keys >= n_x509_keys)
sel_protocol = GPGME_PROTOCOL_OpenPGP;
else if (n_x509_keys)
sel_protocol = GPGME_PROTOCOL_CMS;
}
else
sel_protocol = req_protocol;
if (missing_keys)
hint = _("You need to select a key for each recipient.\n"
"To select a key right-click on the respective line.");
else if ((sel_protocol == GPGME_PROTOCOL_OpenPGP
&& ambiguous_pgp_keys)
|| (sel_protocol == GPGME_PROTOCOL_CMS
&& ambiguous_x509_keys)
|| (sel_protocol == GPGME_PROTOCOL_UNKNOWN
&& (ambiguous_pgp_keys || ambiguous_x509_keys )))
hint = _("You need to select exactly one key for each recipient.\n"
"To select a key right-click on the respective line.");
else if ((sel_protocol == GPGME_PROTOCOL_OpenPGP
&& n_keys != n_pgp_keys)
|| (sel_protocol == GPGME_PROTOCOL_CMS
&& n_keys != n_x509_keys)
|| (sel_protocol == GPGME_PROTOCOL_UNKNOWN))
hint = _("Although you selected keys for all recipients "
"a common encryption protocol can't be used. "
"Please decide on one protocol by clicking one "
"of the above radio buttons.");
else if (n_pgp_keys && sel_protocol == GPGME_PROTOCOL_OpenPGP)
{
hint = _("Using OpenPGP for encryption.");
okay = 1;
}
else if (n_x509_keys && sel_protocol == GPGME_PROTOCOL_CMS)
{
hint = _("Using S/MIME for encryption.");
okay = 1;
}
else
hint = _("No recipients - encryption is not possible");
gtk_label_set_text (GTK_LABEL (dialog->statushint), hint);
gtk_label_set_line_wrap (GTK_LABEL (dialog->statushint), TRUE);
dialog->usable = okay;
dialog->selected_protocol = sel_protocol;
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK,
okay);
}
/* Add KEY to the keyarray of KEYINFO. Ownership of KEY is moved to
KEYARRAY. Returns the number of keys in KEYINFO. */
static unsigned int
append_key_to_keyinfo (struct keyinfo_s *keyinfo, gpgme_key_t key)
{
unsigned int nkeys;
if (!keyinfo->keys)
{
keyinfo->dimof_keys = 5; /* Space for 4 keys. */
keyinfo->keys = g_new (gpgme_key_t, keyinfo->dimof_keys);
keyinfo->keys[0] = NULL;
}
for (nkeys=0; keyinfo->keys[nkeys]; nkeys++)
;
/* Note that we silently skip a KEY of NULL because we can't store
a NULL in the array. */
if (key)
{
if (nkeys+1 >= keyinfo->dimof_keys)
{
keyinfo->dimof_keys += 10;
keyinfo->keys = g_renew (gpgme_key_t, keyinfo->keys,
keyinfo->dimof_keys);
}
keyinfo->keys[nkeys++] = key;
keyinfo->keys[nkeys] = NULL;
}
return nkeys;
}
/* Clear the content of a keyinfo object. */
static void
clear_keyinfo (struct keyinfo_s *keyinfo)
{
unsigned int nkeys;
if (keyinfo)
{
if (keyinfo->keys)
{
for (nkeys=0; keyinfo->keys[nkeys]; nkeys++)
gpgme_key_unref (keyinfo->keys[nkeys]);
g_free (keyinfo->keys);
keyinfo->keys = NULL;
}
keyinfo->dimof_keys = 0;
keyinfo->truncated = 0;
}
}
/* Update the row in the list described by by STORE and ITER. The new
data shall be taken from INFO. */
static void
update_recplist_row (GtkListStore *store, GtkTreeIter *iter,
struct userdata_s *info)
{
char *infostr = NULL;
char *oldinfostr = NULL;
int any_pgp = 0, any_x509 = 0;
gpgme_key_t key;
char *mailbox;
char *oldmailbox;
if (info->pgp.keys && info->pgp.keys[0])
any_pgp = 1;
if (info->x509.keys && info->x509.keys[0])
any_x509 = 1;
if (info->ignore_recipient)
infostr = NULL;
else if (any_pgp && any_x509 && info->pgp.keys[1] && info->x509.keys[1])
infostr = g_strdup (_("[Ambiguous keys. Right-click to select]"));
else if (any_pgp && info->pgp.keys[1])
infostr = g_strdup (_("[Ambiguous PGP key. Right-click to select]"));
else if (any_x509 && info->x509.keys[1])
infostr = g_strdup (_("[Ambiguous X.509 key. Right-click to select]"));
else if (any_pgp && !info->pgp.keys[1])
{
/* Exactly one key found. */
key = info->pgp.keys[0];
infostr = gpa_gpgme_key_get_userid (key->uids);
}
else if (any_x509 && !info->x509.keys[1])
{
key = info->x509.keys[0];
infostr = gpa_gpgme_key_get_userid (key->uids);
}
else
infostr = g_strdup (_("[Right-click to select]"));
mailbox = g_markup_printf_escaped ("%s",
info->ignore_recipient? "true":"false",
info->mailbox);
g_print (" mbox=`%s' fmt=`%s'\n", info->mailbox, mailbox);
gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
RECPLIST_MAILBOX, &oldmailbox,
RECPLIST_KEYID, &oldinfostr,
-1);
gtk_list_store_set (store, iter,
RECPLIST_MAILBOX, mailbox,
RECPLIST_HAS_PGP, any_pgp,
RECPLIST_HAS_X509, any_x509,
RECPLIST_KEYID, infostr,
-1);
g_free (oldmailbox);
g_free (mailbox);
g_free (infostr);
g_free (oldinfostr);
}
/* Parse one recipient, this is the working horse of parse_recipeints. */
static void
parse_one_recipient (gpgme_ctx_t ctx, GtkListStore *store, GtkTreeIter *iter,
struct userdata_s *info)
{
static int have_locate = -1;
gpgme_key_t key = NULL;
gpgme_keylist_mode_t mode;
if (have_locate == -1)
have_locate = is_gpg_version_at_least ("2.0.10");
g_return_if_fail (info);
clear_keyinfo (&info->pgp);
gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
mode = gpgme_get_keylist_mode (ctx);
if (have_locate)
gpgme_set_keylist_mode (ctx, (mode | (GPGME_KEYLIST_MODE_LOCAL
| GPGME_KEYLIST_MODE_EXTERN)));
if (!gpgme_op_keylist_start (ctx, info->mailbox, 0))
{
while (!gpgme_op_keylist_next (ctx, &key))
{
if (key->revoked || key->disabled || key->expired
|| !key->can_encrypt)
gpgme_key_unref (key);
else if (append_key_to_keyinfo (&info->pgp, key)
>= TRUNCATE_KEYSEARCH_AT)
{
/* Note that the truncation flag is not 100% correct. In
case the next iteration would not yield a new key we
have not actually truncated the search. */
info->pgp.truncated = 1;
break;
}
}
}
gpgme_op_keylist_end (ctx);
gpgme_set_keylist_mode (ctx, mode);
clear_keyinfo (&info->x509);
gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
if (!gpgme_op_keylist_start (ctx, info->mailbox, 0))
{
while (!gpgme_op_keylist_next (ctx, &key))
{
if (key->revoked || key->disabled || key->expired
|| !key->can_encrypt)
gpgme_key_unref (key);
else if (append_key_to_keyinfo (&info->x509,key)
>= TRUNCATE_KEYSEARCH_AT)
{
info->x509.truncated = 1;
break;
}
}
}
gpgme_op_keylist_end (ctx);
update_recplist_row (store, iter, info);
}
/* Parse the list of recipients, find possible keys and update the
store. */
static void
parse_recipients (GtkListStore *store)
{
GtkTreeModel *model;
GtkTreeIter iter;
gpg_error_t err;
gpgme_ctx_t ctx;
err = gpgme_new (&ctx);
if (err)
gpa_gpgme_error (err);
model = GTK_TREE_MODEL (store);
/* Walk through the list, reading each row. */
if (gtk_tree_model_get_iter_first (model, &iter))
do
{
struct userdata_s *info;
gtk_tree_model_get (model, &iter,
RECPLIST_USERDATA, &info,
-1);
/* Do something with the data */
/*g_print ("parsing mailbox `%s'\n", info? info->mailbox:"(null)");*/
parse_one_recipient (ctx, store, &iter,info);
}
while (gtk_tree_model_iter_next (model, &iter));
gpgme_release (ctx);
}
/* Callback for the row-activated signal. */
static void
recplist_row_activated_cb (GtkTreeView *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column,
gpointer user_data)
{
/*RecipientDlg *dialog = user_data;*/
GtkTreeIter iter;
GtkTreeModel *model;
char *mailbox;
model = gtk_tree_view_get_model (tree_view);
if (!gtk_tree_model_get_iter (model, &iter, path))
return;
gtk_tree_model_get (model, &iter,
RECPLIST_MAILBOX, &mailbox,
-1);
g_free (mailbox);
}
static void
recplist_row_changed_cb (GtkTreeModel *model, GtkTreePath *path,
GtkTreeIter *changediter, gpointer user_data)
{
RecipientDlg *dialog = user_data;
g_return_if_fail (dialog);
update_statushint (dialog);
}
static void
rbutton_toggled_cb (GtkToggleButton *button, gpointer user_data)
{
RecipientDlg *dialog = user_data;
GtkTreeViewColumn *column;
int pgp = FALSE;
int x509 = FALSE;
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->radio_pgp)))
{
pgp = TRUE;
}
else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
(dialog->radio_x509)))
{
x509 = TRUE;
}
else
{
pgp = TRUE;
x509 = TRUE;
}
column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->clist_keys),
RECPLIST_HAS_PGP);
gtk_tree_view_column_set_visible (column, pgp);
column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->clist_keys),
RECPLIST_HAS_X509);
gtk_tree_view_column_set_visible (column, x509);
update_statushint (dialog);
}
/* The select key selection has returned. */
static void
select_key_response_cb (SelectKeyDlg *seldlg, int response, void *user_data)
{
RecipientDlg *dialog = user_data;
gpgme_key_t key;
if (response != GTK_RESPONSE_OK)
{
/* The dialog was canceled */
gtk_widget_destroy (GTK_WIDGET (seldlg));
dialog->freeze_key_selection--;
return;
}
key = select_key_dlg_get_key (seldlg);
if (key)
{
GtkTreeModel *model;
GtkTreeIter iter;
struct userdata_s *info = NULL;
char *uidstr = gpa_gpgme_key_get_userid (key->uids);
g_free (uidstr);
if ((model = get_selected_row (dialog, &iter)))
{
gtk_tree_model_get (model, &iter, RECPLIST_USERDATA, &info, -1);
if (info)
{
if (key->protocol == GPGME_PROTOCOL_OpenPGP)
{
clear_keyinfo (&info->pgp);
gpgme_key_ref (key);
append_key_to_keyinfo (&info->pgp, key);
}
else if (key->protocol == GPGME_PROTOCOL_CMS)
{
clear_keyinfo (&info->x509);
gpgme_key_ref (key);
append_key_to_keyinfo (&info->x509, key);
}
update_recplist_row (GTK_LIST_STORE (model), &iter, info);
update_statushint (dialog);
}
}
gpgme_key_unref (key);
}
gtk_widget_destroy (GTK_WIDGET (seldlg));
dialog->freeze_key_selection--;
}
static void
do_select_key (RecipientDlg *dialog, gpgme_protocol_t protocol)
{
GtkTreeModel *model;
GtkTreeIter iter;
struct userdata_s *info = NULL;
SelectKeyDlg *seldlg;
if ((model = get_selected_row (dialog, &iter)))
{
gtk_tree_model_get (model, &iter, RECPLIST_USERDATA, &info, -1);
if (info)
{
gpgme_key_t *keys;
if (protocol == GPGME_PROTOCOL_OpenPGP)
keys = info->pgp.keys;
else if (protocol == GPGME_PROTOCOL_CMS)
keys = info->x509.keys;
else
keys = NULL;
seldlg = select_key_dlg_new_with_keys (GTK_WIDGET (dialog),
protocol,
keys,
info->mailbox);
g_signal_connect (G_OBJECT (seldlg), "response",
G_CALLBACK (select_key_response_cb), dialog);
gtk_widget_show_all (GTK_WIDGET (seldlg));
}
}
else
dialog->freeze_key_selection--;
}
static void
recplist_popup_pgp (GSimpleAction *simple, GVariant *parameter, gpointer user_data)
{
RecipientDlg *dialog = user_data;
do_select_key (dialog, GPGME_PROTOCOL_OpenPGP);
}
static void
recplist_popup_x509 (GSimpleAction *simple, GVariant *parameter, gpointer user_data)
{
RecipientDlg *dialog = user_data;
do_select_key (dialog, GPGME_PROTOCOL_CMS);
}
static void
recplist_popup_ignore (GSimpleAction *simple, GVariant *parameter, gpointer user_data)
{
GtkTreeModel *model;
GtkTreeIter iter;
struct userdata_s *info;
RecipientDlg *dialog = user_data;
if ((model = get_selected_row (dialog, &iter)))
{
gtk_tree_model_get (model, &iter, RECPLIST_USERDATA, &info, -1);
info->ignore_recipient = !info->ignore_recipient;
update_recplist_row (GTK_LIST_STORE (model), &iter, info);
update_statushint (dialog);
}
dialog->freeze_key_selection--;
}
/* Left Click on the list auto selects an action. */
static void
recplist_default_action (RecipientDlg *dialog)
{
dialog->freeze_key_selection--;
}
static gint
recplist_display_popup_menu (RecipientDlg *dialog, GdkEvent *event,
GtkListStore *list)
{
GtkMenu *menu;
GdkEventButton *event_button;
g_return_val_if_fail (dialog, FALSE);
g_return_val_if_fail (event, FALSE);
menu = GTK_MENU (dialog->popup_menu);
if (event->type == GDK_BUTTON_PRESS)
{
event_button = (GdkEventButton *) event;
if (event_button->button == 1
|| event_button->button == 3)
{
GtkTreeSelection *selection;
GtkTreePath *path;
GtkTreeIter iter;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
/* Make sure the clicked key is selected. */
if (!dialog->freeze_key_selection
&& gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (list),
event_button->x,
event_button->y,
&path, NULL,
NULL, NULL))
{
dialog->freeze_key_selection++;
gtk_tree_model_get_iter (gtk_tree_view_get_model
(GTK_TREE_VIEW (list)), &iter, path);
if (!gtk_tree_selection_iter_is_selected (selection, &iter))
{
gtk_tree_selection_unselect_all (selection);
gtk_tree_selection_select_path (selection, path);
}
if (event_button->button == 1)
recplist_default_action (dialog);
else
gtk_menu_popup_at_pointer (menu, NULL);
}
return TRUE;
}
}
return FALSE;
}
/* Create the popup menu for the recipient list. */
static GtkWidget *
recplist_popup_menu_new (GtkWidget *window, RecipientDlg *dialog)
{
static const GActionEntry entries [] = {
{ "select_gpg_key", recplist_popup_pgp },
{ "select_cms_key", recplist_popup_x509 },
{ "toggle_ignore_flag", recplist_popup_ignore },
};
static const char *menu_string =
""
""
"";
GError **err;
GtkWidget *popup_menu_widget;
GtkBuilder *gtk_builder = gtk_builder_new ();
if (gtk_builder_add_from_string( gtk_builder, menu_string , -1, err) == 0) {
printf("ERROR menu: %s \n", (*err)->message);
}
GMenuModel *popup_menu_model = G_MENU_MODEL (gtk_builder_get_object (GTK_BUILDER (gtk_builder), "popup_menu"));
popup_menu_widget = gtk_menu_new_from_model (popup_menu_model);
GApplication *gpa_app = G_APPLICATION (get_gpa_application ());
g_action_map_add_action_entries (G_ACTION_MAP (gpa_app),
entries,
G_N_ELEMENTS (entries),
window);
return popup_menu_widget;
}
/************************************************************
****************** Object Management ********************
************************************************************/
static void
recipient_dlg_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
RecipientDlg *dialog = RECIPIENT_DLG (object);
switch (prop_id)
{
case PROP_WINDOW:
g_value_set_object (value,
gtk_window_get_transient_for (GTK_WINDOW (dialog)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
recipient_dlg_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
RecipientDlg *dialog = RECIPIENT_DLG (object);
switch (prop_id)
{
case PROP_WINDOW:
gtk_window_set_transient_for (GTK_WINDOW (dialog),
g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
recipient_dlg_finalize (GObject *object)
{
/* Fixme: Release the store. */
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
recipient_dlg_init (RecipientDlg *dialog)
{
}
static GObject*
recipient_dlg_constructor (GType type, guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GObject *object;
RecipientDlg *dialog;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *widget;
GtkWidget *labelKeys;
GtkWidget *scrollerKeys;
GtkWidget *clistKeys;
object = parent_class->constructor (type,
n_construct_properties,
construct_properties);
dialog = RECIPIENT_DLG (object);
gpa_window_set_title (GTK_WINDOW (dialog), _("Select keys for recipients"));
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK,
FALSE);
gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
//vbox = GTK_DIALOG (dialog)->vbox;
vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
labelKeys = gtk_label_new_with_mnemonic (_("_Recipient list"));
gtk_widget_set_halign (GTK_WIDGET (labelKeys), GTK_ALIGN_START);
gtk_widget_set_valign (GTK_WIDGET (labelKeys), GTK_ALIGN_CENTER);
gtk_box_pack_start (GTK_BOX (vbox), labelKeys, FALSE, FALSE, 0);
scrollerKeys = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollerKeys),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_box_pack_start (GTK_BOX (vbox), scrollerKeys, TRUE, TRUE, 0);
gtk_widget_set_size_request (scrollerKeys, 400, 200);
clistKeys = recplist_window_new ();
dialog->clist_keys = clistKeys;
gtk_container_add (GTK_CONTAINER (scrollerKeys), clistKeys);
gtk_label_set_mnemonic_widget (GTK_LABEL (labelKeys), clistKeys);
dialog->popup_menu = recplist_popup_menu_new (dialog->clist_keys, dialog);
g_signal_connect_swapped (G_OBJECT (dialog->clist_keys),
"button_press_event",
G_CALLBACK (recplist_display_popup_menu), dialog);
dialog->radio_pgp = gtk_radio_button_new_with_mnemonic
(NULL, _("Use _PGP"));
dialog->radio_x509 = gtk_radio_button_new_with_mnemonic
(gtk_radio_button_get_group (GTK_RADIO_BUTTON (dialog->radio_pgp)),
_("Use _X.509"));
dialog->radio_auto = gtk_radio_button_new_with_mnemonic
(gtk_radio_button_get_group (GTK_RADIO_BUTTON (dialog->radio_pgp)),
_("_Auto selection"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->radio_auto), TRUE);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), dialog->radio_pgp, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), dialog->radio_x509, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), dialog->radio_auto, FALSE, FALSE, 0);
widget = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
dialog->statushint = gtk_label_new (NULL);
gtk_box_pack_start (GTK_BOX (vbox), dialog->statushint, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (GTK_TREE_VIEW (dialog->clist_keys)),
"row-activated",
G_CALLBACK (recplist_row_activated_cb), dialog);
g_signal_connect (G_OBJECT (gtk_tree_view_get_model
(GTK_TREE_VIEW (dialog->clist_keys))),
"row-changed",
G_CALLBACK (recplist_row_changed_cb), dialog);
g_signal_connect (G_OBJECT (dialog->radio_pgp),
"toggled",
G_CALLBACK (rbutton_toggled_cb), dialog);
g_signal_connect (G_OBJECT (dialog->radio_x509),
"toggled",
G_CALLBACK (rbutton_toggled_cb), dialog);
g_signal_connect (G_OBJECT (dialog->radio_auto),
"toggled",
G_CALLBACK (rbutton_toggled_cb), dialog);
return object;
}
static void
recipient_dlg_class_init (RecipientDlgClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
object_class->constructor = recipient_dlg_constructor;
object_class->finalize = recipient_dlg_finalize;
object_class->set_property = recipient_dlg_set_property;
object_class->get_property = recipient_dlg_get_property;
g_object_class_install_property
(object_class,
PROP_WINDOW,
g_param_spec_object
("window", "Parent window",
"Parent window", GTK_TYPE_WIDGET,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
}
GType
recipient_dlg_get_type (void)
{
static GType this_type;
if (!this_type)
{
static const GTypeInfo this_info =
{
sizeof (RecipientDlgClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) recipient_dlg_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (RecipientDlg),
0, /* n_preallocs */
(GInstanceInitFunc) recipient_dlg_init,
};
this_type = g_type_register_static (GTK_TYPE_DIALOG,
"RecipientDlg",
&this_info, 0);
}
return this_type;
}
/************************************************************
********************** Public API ************************
************************************************************/
RecipientDlg *
recipient_dlg_new (GtkWidget *parent)
{
RecipientDlg *dialog;
dialog = g_object_new (RECIPIENT_DLG_TYPE,
"window", parent,
NULL);
return dialog;
}
/* Put RECIPIENTS into the list. PROTOCOL select the default protocol. */
void
recipient_dlg_set_recipients (RecipientDlg *dialog, GSList *recipients,
gpgme_protocol_t protocol)
{
GtkListStore *store;
GSList *recp;
GtkTreeIter iter;
const char *name;
GtkWidget *widget;
g_return_if_fail (dialog);
dialog->freeze_update_statushint++;
if (protocol == GPGME_PROTOCOL_OpenPGP)
widget = dialog->radio_pgp;
else if (protocol == GPGME_PROTOCOL_CMS)
widget = dialog->radio_x509;
else
widget = dialog->radio_auto;
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
if (widget != dialog->radio_auto)
{
gtk_widget_set_sensitive (GTK_WIDGET (dialog->radio_pgp), FALSE);
gtk_widget_set_sensitive (GTK_WIDGET (dialog->radio_x509), FALSE);
gtk_widget_set_sensitive (GTK_WIDGET (dialog->radio_auto), FALSE);
}
store = GTK_LIST_STORE (gtk_tree_view_get_model
(GTK_TREE_VIEW (dialog->clist_keys)));
gtk_list_store_clear (store);
for (recp = recipients; recp; recp = g_slist_next (recp))
{
name = recp->data;
if (name && *name)
{
struct userdata_s *info = g_malloc0 (sizeof *info);
info->mailbox = g_strdup (name);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
RECPLIST_MAILBOX, g_strdup (""),
RECPLIST_HAS_PGP, FALSE,
RECPLIST_HAS_X509, FALSE,
RECPLIST_KEYID, NULL,
RECPLIST_USERDATA, info,
-1);
}
}
parse_recipients (store);
dialog->freeze_update_statushint--;
update_statushint (dialog);
}
/* Return the selected keys as well as the selected protocol. */
gpgme_key_t *
recipient_dlg_get_keys (RecipientDlg *dialog, gpgme_protocol_t *r_protocol)
{
GtkTreeModel *model;
GtkTreeIter iter;
size_t idx, nkeys;
gpgme_key_t key, *keyarray;
gpgme_protocol_t protocol;
g_return_val_if_fail (dialog, NULL);
if (!dialog->usable)
return NULL; /* No valid keys available. */
protocol = dialog->selected_protocol;
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->clist_keys));
/* Count the number of possible keys. */
nkeys = 0;
if (gtk_tree_model_get_iter_first (model, &iter))
{
do
nkeys++;
while (gtk_tree_model_iter_next (model, &iter));
}
keyarray = g_new (gpgme_key_t, nkeys+1);
idx = 0;
if (gtk_tree_model_get_iter_first (model, &iter))
{
do
{
char *mailbox;
struct userdata_s *info;
if (idx >= nkeys)
{
g_debug ("key list grew unexpectedly\n");
break;
}
gtk_tree_model_get (model, &iter,
RECPLIST_MAILBOX, &mailbox,
RECPLIST_USERDATA, &info,
-1);
if (info && !info->ignore_recipient)
{
if (protocol == GPGME_PROTOCOL_OpenPGP && info->pgp.keys)
key = info->pgp.keys[0];
else if (protocol == GPGME_PROTOCOL_CMS && info->x509.keys)
key = info->x509.keys[0];
else
key = NULL;
if (key)
{
gpgme_key_ref (key);
keyarray[idx++] = key;
}
}
g_free (mailbox);
}
while (gtk_tree_model_iter_next (model, &iter));
}
g_assert (idx < nkeys+1);
keyarray[idx] = NULL;
if (r_protocol)
*r_protocol = protocol;
return keyarray;
}
diff --git a/src/verifydlg.c b/src/verifydlg.c
index 36609e4..01dafb3 100644
--- a/src/verifydlg.c
+++ b/src/verifydlg.c
@@ -1,446 +1,445 @@
/* fileverifydlg.c - Dialog for verifying files.
Copyright (C) 2000, 2001 G-N-U GmbH.
Copyright (C) 2005, 2012 g10 Code GmbH.
This file is part of GPA
GPA 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.
GPA 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 GPA; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */
#include
#include
#include
#include
#include
#include "gpa.h"
#include "gtktools.h"
#include "gpawidgets.h"
#include "verifydlg.h"
/* Properties */
enum
{
PROP_0,
PROP_WINDOW,
};
static GObjectClass *parent_class = NULL;
static void
gpa_file_verify_dialog_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GpaFileVerifyDialog *dialog = GPA_FILE_VERIFY_DIALOG (object);
switch (prop_id)
{
case PROP_WINDOW:
g_value_set_object (value,
gtk_window_get_transient_for (GTK_WINDOW (dialog)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gpa_file_verify_dialog_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GpaFileVerifyDialog *dialog = GPA_FILE_VERIFY_DIALOG (object);
switch (prop_id)
{
case PROP_WINDOW:
gtk_window_set_transient_for (GTK_WINDOW (dialog),
g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gpa_file_verify_dialog_finalize (GObject *object)
{
GpaFileVerifyDialog *dialog = GPA_FILE_VERIFY_DIALOG (object);
g_object_unref (dialog->ctx);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gpa_file_verify_dialog_init (GpaFileVerifyDialog *dialog)
{
}
static GObject*
gpa_file_verify_dialog_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GObject *object;
GpaFileVerifyDialog *dialog;
/* Invoke parent's constructor */
object = parent_class->constructor (type,
n_construct_properties,
construct_properties);
dialog = GPA_FILE_VERIFY_DIALOG (object);
/* Initialize */
dialog->ctx = gpa_context_new ();
/* Set up the dialog */
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
_("_Close"), GTK_RESPONSE_CLOSE, NULL);
gpa_window_set_title (GTK_WINDOW (dialog), _("Verify documents"));
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
dialog->notebook = gtk_notebook_new ();
//vboxEncrypt = gtk_dialog_get_content_area(dialog);
GtkWidget *box = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
gtk_box_pack_start (GTK_BOX (box),
dialog->notebook, TRUE, TRUE, 0);
/* Hide on response */
g_signal_connect (G_OBJECT (dialog), "response",
G_CALLBACK (gtk_widget_hide), NULL);
return object;
}
static void
gpa_file_verify_dialog_class_init (GpaFileVerifyDialogClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
object_class->constructor = gpa_file_verify_dialog_constructor;
object_class->finalize = gpa_file_verify_dialog_finalize;
object_class->set_property = gpa_file_verify_dialog_set_property;
object_class->get_property = gpa_file_verify_dialog_get_property;
/* Properties */
g_object_class_install_property (object_class,
PROP_WINDOW,
g_param_spec_object
("window", "Parent window",
"Parent window", GTK_TYPE_WIDGET,
G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
}
GType
gpa_file_verify_dialog_get_type (void)
{
static GType verify_dialog_type = 0;
if (!verify_dialog_type)
{
static const GTypeInfo verify_dialog_info =
{
sizeof (GpaFileVerifyDialogClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gpa_file_verify_dialog_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GpaFileVerifyDialog),
0, /* n_preallocs */
(GInstanceInitFunc) gpa_file_verify_dialog_init,
};
verify_dialog_type = g_type_register_static (GTK_TYPE_DIALOG,
"GpaFileVerifyDialog",
&verify_dialog_info, 0);
}
return verify_dialog_type;
}
/* Internal */
typedef struct
{
gchar *fpr;
gpgme_key_t key;
gpgme_validity_t validity;
unsigned long summary;
time_t created;
time_t expire;
char *sigdesc;
char *keydesc;
} SignatureData;
typedef enum
{
SIG_KEYID_COLUMN,
SIG_STATUS_COLUMN,
SIG_USERID_COLUMN,
SIG_DESC_COLUMN,
SIG_N_COLUMNS
} SignatureListColumn;
/* Return the text of the "status" column in pango markup language.
*/
static gchar*
signature_status_label (SignatureData *data)
{
gchar *text = NULL;
gchar *color = NULL;
gchar *label = NULL;
if (data->summary & GPGME_SIGSUM_VALID)
{
text = _("Valid");
color = "green";
}
else if (data->summary & GPGME_SIGSUM_RED)
{
text = _("Bad");
color = "red";
}
else if (data->summary & GPGME_SIGSUM_KEY_MISSING)
{
text = _("Unknown Key");
color = "red";
}
else if (data->summary & GPGME_SIGSUM_KEY_REVOKED)
{
text = _("Revoked Key");
color = "red";
}
else if (data->summary & GPGME_SIGSUM_KEY_EXPIRED)
{
text = _("Expired Key");
color = "orange";
}
else
{
/* If we arrived here we know the key is available, the signature is
* not bad, but it's not completely valid. So, the signature is good
* but the key is not valid. */
text = _("Key NOT valid");
color = "orange";
}
label = g_strdup_printf ("%s",
color, text);
return label;
}
/* Add a signature to the list */
static void
add_signature_to_model (GtkListStore *store, SignatureData *data)
{
GtkTreeIter iter;
const gchar *keyid;
gchar *userid;
gchar *status;
if (data->key)
{
keyid = gpa_gpgme_key_get_short_keyid (data->key);
}
else if (data->fpr && strlen (data->fpr) > 8)
{
/* We use the last 8 bytes of fingerprint for the keyID. */
keyid = data->fpr + strlen (data->fpr) - 8;
}
else
{
keyid = "";
}
status = signature_status_label (data);
userid = data->keydesc;
if (!userid)
userid = _("[Unknown user ID]");
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
SIG_KEYID_COLUMN, keyid,
SIG_STATUS_COLUMN, status,
SIG_USERID_COLUMN, userid,
SIG_DESC_COLUMN, data->sigdesc,
-1);
g_free (status);
gpgme_key_unref (data->key);
g_free (data->sigdesc);
g_free (data->keydesc);
g_free (data);
}
/* Fill the list of signatures with the data from the verification */
static void
fill_sig_model (GtkListStore *store, gpgme_signature_t sigs,
gpgme_ctx_t ctx)
{
SignatureData *data;
gpgme_signature_t sig;
for (sig = sigs; sig; sig = sig->next)
{
data = g_malloc (sizeof (SignatureData));
data->fpr = sig->fpr? g_strdup (sig->fpr) : NULL;
data->validity = sig->validity;
data->summary = sig->summary;
data->created = sig->timestamp;
data->expire = sig->exp_timestamp;
data->sigdesc = gpa_gpgme_get_signature_desc (ctx, sig,
&data->keydesc, &data->key);
add_signature_to_model (store, data);
}
}
/* Create the list of signatures */
static GtkWidget *
signature_list (gpgme_signature_t sigs, gpgme_ctx_t ctx)
{
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
GtkListStore *store;
GtkWidget *list;
store = gtk_list_store_new (SIG_N_COLUMNS, G_TYPE_STRING,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
- gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (list), TRUE);
gtk_widget_set_size_request (list, 400, 100);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (_("Key ID"), renderer,
"text", SIG_KEYID_COLUMN,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (_("Status"), renderer,
"markup",
SIG_STATUS_COLUMN, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (_("User Name"), renderer,
"text", SIG_USERID_COLUMN,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (_("Description"), renderer,
"text", SIG_DESC_COLUMN,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
fill_sig_model (store, sigs, ctx);
return list;
}
static GtkWidget *
verify_file_page (gpgme_signature_t sigs, const gchar *signed_file,
const gchar *signature_file, gpgme_ctx_t ctx)
{
GtkWidget *vbox;
GtkWidget *list;
GtkWidget *label;
GtkWidget *scrolled;
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
if (signed_file)
{
gchar *text = g_strdup_printf (_("Verified data in file: %s"),
signed_file);
label = gtk_label_new (text);
gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
g_free (text);
text = g_strdup_printf (_("Signature: %s"), signature_file);
label = gtk_label_new (text);
gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
g_free (text);
}
label = gtk_label_new (_("Signatures:"));
gtk_widget_set_halign (GTK_WIDGET (label), 0.0);
gtk_widget_set_valign (GTK_WIDGET (label), 0.5);
gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
list = signature_list (sigs, ctx);
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
GTK_SHADOW_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (scrolled), list);
gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
return vbox;
}
/* API */
GtkWidget *gpa_file_verify_dialog_new (GtkWidget *parent)
{
GpaFileVerifyDialog *dialog;
dialog = g_object_new (GPA_FILE_VERIFY_DIALOG_TYPE,
"window", parent,
NULL);
return GTK_WIDGET(dialog);
}
void
gpa_file_verify_dialog_set_title (GpaFileVerifyDialog *dialog,
const char *title)
{
if (dialog && title && *title)
gpa_window_set_title (GTK_WINDOW (dialog), title);
}
void gpa_file_verify_dialog_add_file (GpaFileVerifyDialog *dialog,
const gchar *filename,
const gchar *signed_file,
const gchar *signature_file,
gpgme_signature_t sigs)
{
GtkWidget *page;
page = verify_file_page (sigs, signed_file, signature_file,
dialog->ctx->ctx);
gtk_notebook_append_page (GTK_NOTEBOOK (dialog->notebook), page,
gtk_label_new (filename));
}