diff --git a/src/gpa-key-details.c b/src/gpa-key-details.c
index a5a0c83..c935d53 100644
--- a/src/gpa-key-details.c
+++ b/src/gpa-key-details.c
@@ -1,894 +1,896 @@
/* gpa-key-details.c - A widget to show key details.
* Copyright (C) 2000, 2001 G-N-U GmbH.
* Copyright (C) 2005, 2008, 2009 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 .
*/
/*
This widget is used to display details of a key.
*/
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include "gpa.h"
#include "convert.h"
#include "keytable.h"
#include "siglist.h"
#include "certchain.h"
#include "gpasubkeylist.h"
#include "gpa-uid-list.h"
#include "gpa-tofu-list.h"
#include "gpa-key-details.h"
#include "gtktools.h"
/* Object's class definition. */
struct _GpaKeyDetailsClass
{
GtkNotebookClass parent_class;
};
/* Object definition. */
struct _GpaKeyDetails
{
GtkNotebook parent_instance;
/* Widgets in the details page. */
GtkWidget *details_num_label;
GtkWidget *details_table;
GtkWidget *detail_public_private;
GtkWidget *detail_capabilities;
GtkWidget *detail_name;
GtkWidget *detail_fingerprint;
GtkWidget *detail_expiry;
GtkWidget *detail_key_id;
GtkWidget *detail_owner_trust;
GtkWidget *detail_key_trust;
GtkWidget *detail_key_type;
GtkWidget *detail_creation;
GtkWidget *detail_last_update;
/* The widgets in the user ID page. */
GtkWidget *uid_page;
GtkWidget *uid_list;
/* The widgets in the signatures page. */
GtkWidget *signatures_page;
GtkWidget *signatures_list;
GtkWidget *signatures_uids;
GtkWidget *certchain_list;
/* The widgets in the subkeys page. */
GtkWidget *subkeys_page;
GtkWidget *subkeys_list;
/* The widgets in the TOFU page. */
GtkWidget *tofu_page;
GtkWidget *tofu_list;
/* The key currently shown or NULL. */
gpgme_key_t current_key;
};
/* The parent class. */
static GObjectClass *parent_class;
/* Local prototypes */
static void gpa_key_details_finalize (GObject *object);
/************************************************************
******************* Implementation *********************
************************************************************/
/* Callback for the "changed" signal to update the popdown menu on the
signatures page of the notebook. */
static void
signatures_uid_changed (GtkComboBox *combo, gpointer user_data)
{
GpaKeyDetails *kdt = user_data;
if (kdt->signatures_list)
{
/* Note that we need to subtract one, as the first entry (with
index 0 means) "all user names". */
gpa_siglist_set_signatures
(kdt->signatures_list, kdt->current_key,
gtk_combo_box_get_active (GTK_COMBO_BOX (combo)) - 1);
}
}
/* Fill the details page with the properties of the public key. */
static void
details_page_fill_key (GpaKeyDetails *kdt, gpgme_key_t key)
{
gpgme_user_id_t uid;
gpgme_key_t seckey;
char *text;
seckey = gpa_keytable_lookup_key (gpa_keytable_get_secret_instance(),
key->subkeys->fpr);
if (seckey)
{
if (seckey->subkeys && seckey->subkeys->is_cardkey)
gtk_label_set_text (GTK_LABEL (kdt->detail_public_private),
_("The key has both a smartcard based private part"
" and a public part"));
else
gtk_label_set_text (GTK_LABEL (kdt->detail_public_private),
_("The key has both a private and a public part"));
}
else
gtk_label_set_text (GTK_LABEL (kdt->detail_public_private),
_("The key has only a public part"));
gtk_label_set_text (GTK_LABEL (kdt->detail_capabilities),
gpa_get_key_capabilities_text (key));
/* One user ID per line. */
text = gpa_gpgme_key_get_userid (key->uids);
if (key->uids)
{
for (uid = key->uids->next; uid; uid = uid->next)
{
gchar *uid_string = gpa_gpgme_key_get_userid (uid);
gchar *tmp = text;
text = g_strconcat (text, "\n", uid_string, NULL);
g_free (tmp);
g_free (uid_string);
}
}
gtk_label_set_text (GTK_LABEL (kdt->detail_name), text);
g_free (text);
text = gpa_gpgme_key_format_fingerprint (key->subkeys->fpr);
gtk_label_set_text (GTK_LABEL (kdt->detail_fingerprint), text);
g_free (text);
text = (gchar*) gpa_gpgme_key_get_short_keyid (key);
gtk_label_set_text (GTK_LABEL (kdt->detail_key_id), text);
text = gpa_expiry_date_string (key->subkeys->expires);
gtk_label_set_text (GTK_LABEL (kdt->detail_expiry), text);
g_free (text);
gtk_label_set_text (GTK_LABEL (kdt->detail_key_trust),
gpa_key_validity_string (key));
text = gpgme_pubkey_algo_string (key->subkeys);
gtk_label_set_text (GTK_LABEL (kdt->detail_key_type), text? text : "?");
gpgme_free (text);
text = g_strdup_printf (_("%s %u bits"),
gpgme_pubkey_algo_name (key->subkeys->pubkey_algo)?
gpgme_pubkey_algo_name (key->subkeys->pubkey_algo):
(key->subkeys->curve? "ECC" : "?"),
key->subkeys->length);
if (key->subkeys->curve)
{
char *text2;
text2 = g_strdup_printf ("%s, %s", text, key->subkeys->curve);
g_free (text);
text = text2;
}
gpa_add_tooltip (kdt->detail_key_type, text);
g_free (text);
gtk_label_set_text (GTK_LABEL (kdt->detail_owner_trust),
gpa_key_ownertrust_string (key));
text = gpa_creation_date_string (key->subkeys->timestamp);
gtk_label_set_text (GTK_LABEL (kdt->detail_creation), text);
g_free (text);
#if GPGME_VERSION_NUMBER >= 0x010100 /* GPGME >= 1.10.0 */
text = gpa_update_origin_string (key->last_update, key->origin);
gtk_label_set_text (GTK_LABEL (kdt->detail_last_update), text);
g_free (text);
#endif
gtk_widget_hide (kdt->details_num_label);
gtk_widget_show_all (kdt->details_table);
gtk_widget_set_no_show_all (kdt->details_num_label, TRUE);
gtk_widget_set_no_show_all (kdt->details_table, FALSE);
}
/* Fill the details page with the number of selected keys. */
static void
details_page_fill_num_keys (GpaKeyDetails *kdt, gint num_key)
{
if (!num_key)
gtk_label_set_text (GTK_LABEL (kdt->details_num_label),
_("No keys selected"));
else
{
char *text = g_strdup_printf (ngettext("%d key selected",
"%d keys selected",
num_key), num_key);
gtk_label_set_text (GTK_LABEL (kdt->details_num_label), text);
g_free (text);
}
gtk_widget_show_all (kdt->details_num_label);
gtk_widget_hide (kdt->details_table);
gtk_widget_set_no_show_all (kdt->details_num_label, FALSE);
gtk_widget_set_no_show_all (kdt->details_table, TRUE);
gtk_notebook_set_current_page (GTK_NOTEBOOK (kdt), 0);
}
/* Add a single row to the details table. */
static GtkWidget *
add_details_row (GtkWidget *grid, gint row, gchar *text,
gboolean selectable)
{
GtkWidget *widget;
widget = gtk_label_new (text);
gtk_grid_attach (GTK_GRID (grid), widget, 0, row, 1, 1);
- gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.0);
+ gtk_widget_set_halign (GTK_WIDGET (widget), 1.0);
+ gtk_widget_set_valign (GTK_WIDGET (widget), 0.0);
widget = gtk_label_new ("");
gtk_label_set_selectable (GTK_LABEL (widget), selectable);
- gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+ gtk_widget_set_halign (GTK_WIDGET (widget), 0.0);
+ gtk_widget_set_valign (GTK_WIDGET (widget), 0.5);
gtk_grid_attach (GTK_GRID (grid), widget, 1, row, 1, 1);
return widget;
}
static void
construct_details_page (GpaKeyDetails *kdt)
{
GtkWidget *grid;
GtkWidget *label;
GtkWidget *vbox;
GtkWidget *scrolled;
GtkWidget *viewport;
gint table_row;
/* Details Page */
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
GTK_SHADOW_NONE);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
viewport = gtk_viewport_new (NULL, NULL);
gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_NONE);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
gtk_container_add (GTK_CONTAINER (viewport), vbox);
gtk_container_add (GTK_CONTAINER (scrolled), viewport);
label = gtk_label_new ("");
kdt->details_num_label = label;
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
grid = gtk_grid_new ();
kdt->details_table = grid;
gtk_box_pack_start (GTK_BOX (vbox), grid, TRUE, TRUE, 0);
// gtk_table_set_row_spacing (GTK_TABLE (grid), 0, 2);
// gtk_table_set_col_spacing (GTK_TABLE (grid), 0, 4);
table_row = 0;
kdt->detail_public_private = add_details_row
(grid, table_row++, "", TRUE);
kdt->detail_capabilities = add_details_row
(grid, table_row++, "", TRUE);
kdt->detail_name = add_details_row
(grid, table_row++, _("User name:"), TRUE);
kdt->detail_fingerprint = add_details_row
(grid, table_row++, _("Fingerprint:"), TRUE);
kdt->detail_key_id = add_details_row
(grid, table_row++, _("Key ID:"), TRUE);
kdt->detail_expiry = add_details_row
(grid, table_row++, _("Expires at:"), FALSE);
kdt->detail_owner_trust = add_details_row
(grid, table_row++, _("Owner Trust:"), FALSE);
kdt->detail_key_trust = add_details_row
(grid, table_row++, _("Key validity:"), FALSE);
kdt->detail_key_type = add_details_row
(grid, table_row++, _("Key type:"), FALSE);
kdt->detail_creation = add_details_row
(grid, table_row++, _("Created at:"), FALSE);
kdt->detail_last_update = add_details_row
(grid, table_row++, _("Last update:"), FALSE);
gtk_notebook_append_page (GTK_NOTEBOOK (kdt), scrolled,
gtk_label_new (_("Details")));
}
/* Create and append new page with USER ID info for KEY. If KEY is NULL
remove an existing USER ID page. */
static void
build_uid_page (GpaKeyDetails *kdt, gpgme_key_t key)
{
GtkWidget *vbox;
GtkWidget *scrolled;
GtkWidget *uidlist;
int pnum;
/* First remove an existing page. */
if (kdt->uid_page)
{
pnum = gtk_notebook_page_num (GTK_NOTEBOOK (kdt), kdt->uid_page);
if (pnum >= 0)
gtk_notebook_remove_page (GTK_NOTEBOOK (kdt), pnum);
kdt->uid_page = NULL;
if (kdt->uid_list)
{
g_object_unref (kdt->uid_list);
kdt->uid_list = NULL;
}
}
if (!key)
return;
/* Create a new page. */
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
uidlist = gpa_uid_list_new ();
gtk_container_add (GTK_CONTAINER (scrolled), uidlist);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
kdt->uid_list = uidlist;
g_object_ref (kdt->uid_list);
kdt->uid_page = vbox;
gtk_notebook_append_page (GTK_NOTEBOOK (kdt), kdt->uid_page,
gtk_label_new (_("User IDs")));
/* Fill this page. */
gpa_uid_list_set_key (kdt->uid_list, key);
}
/* Add the signatures page to the notebook. */
static void
build_signatures_page (GpaKeyDetails *kdt, gpgme_key_t key)
{
GtkWidget *label;
GtkWidget *vbox, *hbox;
GtkWidget *scrolled;
int pnum;
if (kdt->signatures_page)
{
if (kdt->signatures_uids)
g_signal_handlers_disconnect_by_func
(G_OBJECT (kdt->signatures_uids),
G_CALLBACK (signatures_uid_changed), kdt);
pnum = gtk_notebook_page_num (GTK_NOTEBOOK (kdt), kdt->signatures_page);
if (pnum >= 0)
gtk_notebook_remove_page (GTK_NOTEBOOK (kdt), pnum);
kdt->signatures_page = NULL;
kdt->signatures_uids = NULL;
}
if (kdt->signatures_list)
{
g_object_unref (kdt->signatures_list);
kdt->signatures_list = NULL;
}
if (kdt->certchain_list)
{
g_object_unref (kdt->certchain_list);
kdt->certchain_list = NULL;
}
if (!key)
return;
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
/* If there is more than one OpenPGP UID, we need a select button. */
if (key->uids && key->uids->next && key->protocol == GPGME_PROTOCOL_OpenPGP)
{
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
label = gtk_label_new (_("Show signatures on user name:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
kdt->signatures_uids = gtk_combo_box_text_new ();
gtk_box_pack_start (GTK_BOX (hbox), kdt->signatures_uids, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
/* Connect the signal to update the list of user IDs in the
signatures page of the notebook. */
g_signal_connect (G_OBJECT (kdt->signatures_uids), "changed",
G_CALLBACK (signatures_uid_changed), kdt);
}
/* Signature list. */
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
if (key->protocol == GPGME_PROTOCOL_OpenPGP)
{
kdt->signatures_list = gpa_siglist_new ();
g_object_ref (kdt->signatures_list);
gtk_container_add (GTK_CONTAINER (scrolled), kdt->signatures_list);
}
else
{
kdt->certchain_list = gpa_certchain_new ();
g_object_ref (kdt->certchain_list);
gtk_container_add (GTK_CONTAINER (scrolled), kdt->certchain_list);
}
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
kdt->signatures_page = vbox;
gtk_notebook_append_page (GTK_NOTEBOOK (kdt), vbox,
gtk_label_new
(kdt->certchain_list? _("Chain"):_("Signatures")));
/* Fill this page. */
if (kdt->certchain_list)
{
gpa_certchain_update (kdt->certchain_list, key);
}
else if (kdt->signatures_uids)
{
gpgme_user_id_t uid;
GtkComboBox *combo;
int i;
/* Make the combo widget's width shrink as much as
possible. This (hopefully) fixes the previous behaviour
correctly: displaying a key with slightly longer signed UIDs
caused the top-level window to pseudo-randomly increase it's
size (which couldn't even be undone by the user anymore). */
combo = GTK_COMBO_BOX (kdt->signatures_uids);
gtk_widget_set_size_request (GTK_WIDGET (combo), 0, -1);
gtk_combo_box_text_append (combo, NULL, _("All signatures"));
gtk_combo_box_set_active (combo, 0);
for (i=1, uid = key->uids; uid; i++, uid = uid->next)
{
gchar *uid_string = gpa_gpgme_key_get_userid (uid);
gtk_combo_box_text_append (combo, NULL, uid_string);
g_free (uid_string);
}
gpa_siglist_set_signatures (kdt->signatures_list, key, -1);
}
else
{
gpa_siglist_set_signatures (kdt->signatures_list, key, 0);
}
}
/* Create and append new page with all subkeys for KEY. If KEY is
NULL remove an existing subkeys page. */
static void
build_subkeys_page (GpaKeyDetails *kdt, gpgme_key_t key)
{
GtkWidget *vbox;
GtkWidget *scrolled;
GtkWidget *subkeylist;
int pnum;
/* First remove an existing page. */
if (kdt->subkeys_page)
{
pnum = gtk_notebook_page_num (GTK_NOTEBOOK (kdt), kdt->subkeys_page);
if (pnum >= 0)
gtk_notebook_remove_page (GTK_NOTEBOOK (kdt), pnum);
kdt->subkeys_page = NULL;
if (kdt->subkeys_list)
{
g_object_unref (kdt->subkeys_list);
kdt->subkeys_list = NULL;
}
}
if (!key)
return;
/* Create a new page. */
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
subkeylist = gpa_subkey_list_new ();
gtk_container_add (GTK_CONTAINER (scrolled), subkeylist);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
kdt->subkeys_list = subkeylist;
g_object_ref (kdt->subkeys_list);
kdt->subkeys_page = vbox;
gtk_notebook_append_page (GTK_NOTEBOOK (kdt), kdt->subkeys_page,
gtk_label_new
(key->protocol == GPGME_PROTOCOL_OpenPGP
? _("Subkeys") : _("Key")));
/* Fill this page. */
gpa_subkey_list_set_key (kdt->subkeys_list, key);
}
/* Create and append new page with TOFU info for KEY. If KEY is NULL
remove an existing TOFU page. */
static void
build_tofu_page (GpaKeyDetails *kdt, gpgme_key_t key)
{
#ifdef ENABLE_TOFU_INFO
GtkWidget *vbox;
GtkWidget *scrolled;
GtkWidget *tofulist;
int pnum;
/* First remove an existing page. */
if (kdt->tofu_page)
{
pnum = gtk_notebook_page_num (GTK_NOTEBOOK (kdt), kdt->tofu_page);
if (pnum >= 0)
gtk_notebook_remove_page (GTK_NOTEBOOK (kdt), pnum);
kdt->tofu_page = NULL;
if (kdt->tofu_list)
{
g_object_unref (kdt->tofu_list);
kdt->tofu_list = NULL;
}
}
if (!key)
return;
/* Create a new page. */
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
tofulist = gpa_tofu_list_new ();
gtk_container_add (GTK_CONTAINER (scrolled), tofulist);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
kdt->tofu_list = tofulist;
g_object_ref (kdt->tofu_list);
kdt->tofu_page = vbox;
gtk_notebook_append_page (GTK_NOTEBOOK (kdt), kdt->tofu_page,
gtk_label_new (_("Tofu")));
/* Fill this page. */
gpa_tofu_list_set_key (kdt->tofu_list, key);
#endif /*ENABLE_TOFU_INFO*/
}
/* Signal handler for the "changed_ui_mode" signal. */
static void
ui_mode_changed (GpaOptions *options, gpointer param)
{
GpaKeyDetails *kdt = param;
if (gpa_options_get_simplified_ui (gpa_options_get_instance ()))
{
build_uid_page (kdt, NULL);
build_signatures_page (kdt, NULL);
build_subkeys_page (kdt, NULL);
}
else
{
build_uid_page (kdt, kdt->current_key);
build_signatures_page (kdt, kdt->current_key);
build_subkeys_page (kdt, kdt->current_key);
}
build_tofu_page (kdt, kdt->current_key);
gtk_notebook_set_show_tabs
(GTK_NOTEBOOK (kdt), gtk_notebook_get_n_pages (GTK_NOTEBOOK (kdt)) > 1);
gtk_widget_show_all (GTK_WIDGET (kdt));
}
/* This function constructs the container holding all widgets making
up this data widget. It is called during instance creation. */
static void
construct_main_widget (GpaKeyDetails *kdt)
{
/* Details Page */
construct_details_page (kdt);
/* Connect the signal to act on the simplified UI change signal. */
g_signal_connect (G_OBJECT (gpa_options_get_instance ()),
"changed_ui_mode",
G_CALLBACK (ui_mode_changed), kdt);
}
/************************************************************
****************** Object Management ********************
************************************************************/
static void
gpa_key_details_class_init (void *class_ptr, void *class_data)
{
GpaKeyDetailsClass *klass = class_ptr;
parent_class = g_type_class_peek_parent (klass);
G_OBJECT_CLASS (klass)->finalize = gpa_key_details_finalize;
}
static void
gpa_key_details_init (GTypeInstance *instance, void *class_ptr)
{
GpaKeyDetails *kdt = GPA_KEY_DETAILS (instance);
construct_main_widget (kdt);
}
static void
gpa_key_details_finalize (GObject *object)
{
GpaKeyDetails *kdt = GPA_KEY_DETAILS (object);
if (kdt->current_key)
{
gpgme_key_unref (kdt->current_key);
kdt->current_key = NULL;
}
if (kdt->uid_list)
{
g_object_unref (kdt->uid_list);
kdt->uid_list = NULL;
}
if (kdt->signatures_list)
{
g_object_unref (kdt->signatures_list);
kdt->signatures_list = NULL;
}
if (kdt->certchain_list)
{
g_object_unref (kdt->certchain_list);
kdt->certchain_list = NULL;
}
if (kdt->subkeys_list)
{
g_object_unref (kdt->subkeys_list);
kdt->subkeys_list = NULL;
}
if (kdt->tofu_list)
{
g_object_unref (kdt->tofu_list);
kdt->tofu_list = NULL;
}
parent_class->finalize (object);
}
/* Construct the class. */
GType
gpa_key_details_get_type (void)
{
static GType this_type = 0;
if (!this_type)
{
static const GTypeInfo this_info =
{
sizeof (GpaKeyDetailsClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
gpa_key_details_class_init,
(GClassFinalizeFunc) NULL,
NULL, /* class_data */
sizeof (GpaKeyDetails),
0, /* n_preallocs */
gpa_key_details_init
};
this_type = g_type_register_static (GTK_TYPE_NOTEBOOK,
"GpaKeyDetails",
&this_info, 0);
}
return this_type;
}
/************************************************************
********************** Public API ************************
************************************************************/
GtkWidget *
gpa_key_details_new ()
{
return GTK_WIDGET (g_object_new (GPA_KEY_DETAILS_TYPE, NULL));
}
/* Update the key details widget KEYDETAILS with KEY. The caller also
needs to provide the number of keys, so that the widget may show a
key count instead of a key. The actual key details are only shown
if KEY is not NULL and KEYCOUNT is 1. */
void
gpa_key_details_update (GtkWidget *keydetails, gpgme_key_t key, int keycount)
{
GpaKeyDetails *kdt;
GtkWidget *widget;
int pnum;
g_return_if_fail (GPA_IS_KEY_DETAILS (keydetails));
kdt = GPA_KEY_DETAILS (keydetails);
/* Save the currently selected page. */
pnum = gtk_notebook_get_current_page (GTK_NOTEBOOK (kdt));
if (pnum >= 0
&& (widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (kdt), pnum)))
{
if (widget == kdt->uid_page)
pnum = 1;
else if (widget == kdt->signatures_page)
pnum = 2;
else if (widget == kdt->subkeys_page)
pnum = 3;
#ifdef ENABLE_TOFU_INFO
else if (widget == kdt->tofu_page)
pnum = 4;
#endif /*ENABLE_TOFU_INFO*/
else
pnum = 0;
}
else
pnum = 0;
if (kdt->current_key)
{
gpgme_key_unref (kdt->current_key);
kdt->current_key = NULL;
}
if (key && keycount == 1)
{
gpgme_key_ref (key);
kdt->current_key = key;
details_page_fill_key (kdt, key);
/* Depend the generation of pages on the mode of the UI. */
if (gpa_options_get_simplified_ui (gpa_options_get_instance ()))
{
build_uid_page (kdt, NULL);
build_signatures_page (kdt, NULL);
build_subkeys_page (kdt, NULL);
}
else
{
build_uid_page (kdt, key);
build_signatures_page (kdt, key);
build_subkeys_page (kdt, key);
}
}
else
{
details_page_fill_num_keys (kdt, keycount);
build_signatures_page (kdt, NULL);
}
build_tofu_page (kdt, key);
gtk_notebook_set_show_tabs
(GTK_NOTEBOOK (kdt), gtk_notebook_get_n_pages (GTK_NOTEBOOK (kdt)) > 1);
gtk_widget_show_all (keydetails);
/* Try to select the last selected page. */
if (pnum == 1 && kdt->uid_page)
pnum = gtk_notebook_page_num (GTK_NOTEBOOK (kdt), kdt->uid_page);
else if (pnum == 2 && kdt->signatures_page)
pnum = gtk_notebook_page_num (GTK_NOTEBOOK (kdt), kdt->signatures_page);
else if (pnum == 3 && kdt->subkeys_page)
pnum = gtk_notebook_page_num (GTK_NOTEBOOK (kdt), kdt->subkeys_page);
#ifdef ENABLE_TOFU_INFO
else if (pnum == 4 && kdt->tofu_page)
pnum = gtk_notebook_page_num (GTK_NOTEBOOK (kdt), kdt->tofu_page);
#endif /*ENABLE_TOFU_INFO*/
else
pnum = 0;
gtk_notebook_set_current_page (GTK_NOTEBOOK (kdt), pnum);
}
/* Find the key identified by pattern and show the details of the
first key found. Pattern should be the fingerprint of a key so
that only one key will be shown. */
void
gpa_key_details_find (GtkWidget *keydetails, const char *pattern)
{
gpg_error_t err;
gpgme_ctx_t ctx;
gpgme_key_t key = NULL;
int any = 0;
err = gpgme_new (&ctx);
if (err)
gpa_gpgme_error (err);
gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
if (!gpgme_op_keylist_start (ctx, pattern, 0))
{
while (!gpgme_op_keylist_next (ctx, &key))
{
gpa_key_details_update (keydetails, key, 1);
gpgme_key_unref (key);
any = 1;
break;
}
}
gpgme_op_keylist_end (ctx);
if (!any)
{
gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
if (!gpgme_op_keylist_start (ctx, pattern, 0))
{
while (!gpgme_op_keylist_next (ctx, &key))
{
gpa_key_details_update (keydetails, key, 1);
gpgme_key_unref (key);
any = 1;
break;
}
}
gpgme_op_keylist_end (ctx);
}
gpgme_release (ctx);
if (!any)
gpa_key_details_update (keydetails, NULL, 0);
}
diff --git a/src/keygenwizard.c b/src/keygenwizard.c
index e0c5392..d6bba28 100644
--- a/src/keygenwizard.c
+++ b/src/keygenwizard.c
@@ -1,470 +1,474 @@
/* keygendlg.c - The GNU Privacy Assistant
Copyright (C) 2000, 2001 G-N-U GmbH.
Copyright (C) 2008, 2009 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
#include
#include
#include
#include "gpa.h"
#include "icons.h"
#include "gtktools.h"
#include "gpawidgets.h"
#include "qdchkpwd.h"
#include "gpgmetools.h"
#include "keygenwizard.h"
#define STANDARD_KEY_LENGTH 2048
/* The key generation wizard.
New users should not be overwhelmed by too many options most of which
are not easily explained and will only confuse them. To solve that
problem we use default values for the algorithm and size of the keys
and we use a wizard interface to present the necessary options like
name and email address in a step by step manner. */
/* Helper functions. */
/* Return a copy of string with leading and trailing whitespace
stripped. */
static char *
string_strip_dup (const char *string)
{
return g_strstrip (g_strdup (string));
}
/* The wizard itself. */
typedef struct
{
GtkWidget *window;
GtkWidget *wizard;
GtkWidget *name_page;
GtkWidget *email_page;
GtkWidget *wait_page;
GtkWidget *final_page;
GtkWidget *backup_page;
GtkWidget *backup_dir_page;
GpaKeyGenWizardGenerateCb generate;
gpointer generate_data;
} GPAKeyGenWizard;
/* Internal API. */
static gboolean gpa_keygen_wizard_generate_action (gpointer data);
/* The user ID pages. */
static GtkWidget *
gpa_keygen_wizard_simple_page (GPAKeyGenWizard *keygen_wizard,
const gchar *description_text,
const gchar *label_text)
{
GtkWidget *align;
guint pt, pb, pl, pr;
GtkWidget *vbox;
GtkWidget *description;
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *entry;
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 + 5, pb + 5, pl + 5, pr + 5);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (align), vbox);
description = gtk_label_new (description_text);
gtk_box_pack_start (GTK_BOX (vbox), description, TRUE, TRUE, 0);
- gtk_misc_set_alignment (GTK_MISC (description), 0.0, 0.0);
+ gtk_widget_set_halign (GTK_WIDGET (description), 0.0);
+ gtk_widget_set_valign (GTK_WIDGET (description), 0.0);
gtk_label_set_line_wrap (GTK_LABEL (description), TRUE);
gtk_label_set_justify (GTK_LABEL (description), GTK_JUSTIFY_LEFT);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
label = gtk_label_new (label_text);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
+ gtk_widget_set_halign (GTK_WIDGET (description), 1.0);
+ gtk_widget_set_valign (GTK_WIDGET (description), 0.5);
entry = gtk_entry_new ();
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 5);
g_object_set_data (G_OBJECT (align), "gpa_keygen_entry", entry);
g_object_set_data (G_OBJECT (align), "gpa_wizard_focus_child", entry);
return align;
}
static gchar *
gpa_keygen_wizard_simple_get_text (GtkWidget *vbox)
{
GtkWidget *entry;
entry = g_object_get_data (G_OBJECT (vbox), "gpa_keygen_entry");
return string_strip_dup ((gchar *) gtk_entry_get_text (GTK_ENTRY (entry)));
}
static void
gpa_keygen_wizard_simple_grab_focus (GtkWidget *vbox)
{
GtkWidget *entry;
entry = g_object_get_data (G_OBJECT (vbox), "gpa_keygen_entry");
gtk_widget_grab_focus (entry);
}
static gboolean
name_validate_cb (GtkWidget *widget, gpointer data)
{
GPAKeyGenWizard *wizard = data;
const gchar *name;
name = gtk_entry_get_text (GTK_ENTRY (widget));
while (*name && g_unichar_isspace (g_utf8_get_char (name)))
name = g_utf8_next_char (name);
gtk_assistant_set_page_complete (GTK_ASSISTANT (wizard->window),
wizard->name_page,
!gpa_validate_gpg_name (name));
return FALSE;
}
static GtkWidget *
keygen_wizard_name_page (GPAKeyGenWizard *wizard)
{
GtkWidget *widget;
GtkWidget *entry;
widget = gpa_keygen_wizard_simple_page
(wizard,
_("Please insert your full name.\n\n"
"Your name will be part of the new key to make it easier for others"
" to identify keys."),
_("Your Name:"));
entry = g_object_get_data (G_OBJECT (widget), "gpa_keygen_entry");
g_signal_connect (G_OBJECT (entry), "changed",
G_CALLBACK (name_validate_cb), wizard);
return widget;
}
static gboolean
email_validate_cb (GtkWidget *widget, gpointer data)
{
GPAKeyGenWizard *wizard = data;
const gchar *email;
email = gtk_entry_get_text (GTK_ENTRY (widget));
while (*email && g_unichar_isspace (g_utf8_get_char (email)))
email = g_utf8_next_char (email);
gtk_assistant_set_page_complete (GTK_ASSISTANT (wizard->window),
wizard->email_page,
!gpa_validate_gpg_email (email));
return FALSE;
}
static GtkWidget *
keygen_wizard_email_page (GPAKeyGenWizard *wizard)
{
GtkWidget *widget;
GtkWidget *entry;
widget = gpa_keygen_wizard_simple_page
(wizard,
_("Please insert your email address.\n\n"
"Your email address will be part of the new key to make it easier"
" for others to identify keys. If you have several email addresses,"
" you can add further email addresses later."),
_("Your Email Address:"));
entry = g_object_get_data (G_OBJECT (widget), "gpa_keygen_entry");
g_signal_connect (G_OBJECT (entry), "changed",
G_CALLBACK (email_validate_cb), wizard);
return widget;
}
/* Backup copies and revocation certificate. */
static GtkWidget *
gpa_keygen_wizard_backup_page (GPAKeyGenWizard *wizard)
{
GtkWidget *vbox;
GtkWidget *description;
GtkWidget *radio;
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
description = gtk_label_new
(_("It is recommended that you create a backup copy of your new key,"
" once it has been generated.\n\n"
"Do you want to create a backup copy?"));
gtk_box_pack_start (GTK_BOX (vbox), description, TRUE, TRUE, 0);
- gtk_misc_set_alignment (GTK_MISC (description), 0.0, 0.0);
+ gtk_widget_set_halign (GTK_WIDGET (description), 0.0);
+ gtk_widget_set_valign (GTK_WIDGET (description), 0.0);
gtk_label_set_line_wrap (GTK_LABEL (description), TRUE);
gtk_label_set_justify (GTK_LABEL (description), GTK_JUSTIFY_LEFT);
radio = gtk_radio_button_new_with_mnemonic (NULL, _("Create _backup copy"));
gtk_box_pack_start (GTK_BOX (vbox), radio, FALSE, TRUE, 5);
g_object_set_data (G_OBJECT (vbox), "gpa_keygen_backup", radio);
radio = gtk_radio_button_new_with_mnemonic_from_widget
(GTK_RADIO_BUTTON (radio), _("Do it _later"));
gtk_box_pack_start (GTK_BOX (vbox), radio, FALSE, TRUE, 5);
return vbox;
}
static GtkWidget *
gpa_keygen_wizard_message_page (const gchar *description_text)
{
GtkWidget *vbox;
GtkWidget *description;
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
description = gtk_label_new (description_text);
gtk_box_pack_start (GTK_BOX (vbox), description, TRUE, TRUE, 0);
- gtk_misc_set_alignment (GTK_MISC (description), 0.0, 0.0);
+ gtk_widget_set_halign (GTK_WIDGET (description), 0.0);
+ gtk_widget_set_valign (GTK_WIDGET (description), 0.0);
gtk_label_set_line_wrap (GTK_LABEL (description), TRUE);
gtk_label_set_justify (GTK_LABEL (description), GTK_JUSTIFY_LEFT);
return vbox;
}
static GtkWidget *
gpa_keygen_wizard_wait_page (GPAKeyGenWizard *wizard)
{
return gpa_keygen_wizard_message_page
(_("Your key is being generated.\n\n"
"Even on fast computers this may take a while. Please be patient."));
}
static GtkWidget *
gpa_keygen_wizard_final_page (GPAKeyGenWizard * keygen_wizard)
{
GtkWidget *widget;
char *desc;
desc = g_strdup_printf
(_("Congratulations!\n\n"
"You have successfully generated a key."
" The key is indefinitely valid and has a length of %d bits."),
STANDARD_KEY_LENGTH);
widget = gpa_keygen_wizard_message_page (desc);
g_free (desc);
return widget;
}
/* Extract the values the user entered and call gpa_generate_key.
Return TRUE if the key was created successfully. */
static gboolean
gpa_keygen_wizard_generate_action (gpointer data)
//GtkAssistant *assistant, GtkWidget *page, gpointer data)
{
GPAKeyGenWizard *wizard = data;
gpa_keygen_para_t *para;
gboolean do_backup;
GtkWidget *radio;
para = gpa_keygen_para_new ();
/* Shall we make backups? */
radio = g_object_get_data (G_OBJECT (wizard->backup_page),
"gpa_keygen_backup");
do_backup = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio));
/* The User ID. */
para->name = gpa_keygen_wizard_simple_get_text (wizard->name_page);
para->email = gpa_keygen_wizard_simple_get_text (wizard->email_page);
/* Default values for newbie mode. */
para->algo = GPA_KEYGEN_ALGO_RSA_RSA;
para->keysize = STANDARD_KEY_LENGTH;
wizard->generate (para, do_backup, wizard->generate_data);
gpa_keygen_para_free (para);
return FALSE;
}
/* Handler for the close button. Destroy the main window */
static void
keygen_wizard_close (GtkWidget *widget, gpointer param)
{
GPAKeyGenWizard *wizard = param;
gtk_widget_destroy (wizard->window);
}
static void
free_keygen_wizard (gpointer data)
{
GPAKeyGenWizard *keygen_wizard = data;
g_free (keygen_wizard);
}
void
keygen_wizard_prepare_cb (GtkAssistant *assistant, GtkWidget *page,
gpointer data)
{
GPAKeyGenWizard *wizard = data;
if (page == wizard->name_page || page == wizard->email_page)
gpa_keygen_wizard_simple_grab_focus (page);
else if (page == wizard->wait_page)
gpa_keygen_wizard_generate_action (wizard);
}
GtkWidget *
gpa_keygen_wizard_new (GtkWidget *parent,
GpaKeyGenWizardGenerateCb generate_action,
gpointer data)
{
GPAKeyGenWizard *wizard;
GtkWidget *window;
GdkPixbuf *genkey_pixbuf;
GdkPixbuf *backup_pixbuf;
wizard = g_malloc (sizeof (*wizard));
GtkWidget *wizard_genkey = gtk_image_new_from_resource ("/org/gnupg/gpa/wizard_genkey.xpm");
genkey_pixbuf = gtk_image_get_pixbuf (GTK_IMAGE (wizard_genkey));
GtkWidget *wizard_backup = gtk_image_new_from_resource ("/org/gnupg/gpa/wizard_backup.xpm");
backup_pixbuf = gtk_image_get_pixbuf (GTK_IMAGE (wizard_backup));
wizard->generate = generate_action;
wizard->generate_data = data;
window = gtk_assistant_new ();
wizard->window = window;
gpa_window_set_title (GTK_WINDOW (window), _("Generate key"));
g_object_set_data_full (G_OBJECT (window), "user_data",
wizard, free_keygen_wizard);
wizard->name_page = keygen_wizard_name_page (wizard);
gtk_assistant_append_page (GTK_ASSISTANT (window), wizard->name_page);
gtk_assistant_set_page_type (GTK_ASSISTANT (window), wizard->name_page,
GTK_ASSISTANT_PAGE_CONTENT);
gtk_assistant_set_page_title (GTK_ASSISTANT (window), wizard->name_page,
/* FIXME */ _("Generate key"));
gtk_assistant_set_page_side_image (GTK_ASSISTANT (window), wizard->name_page,
genkey_pixbuf);
wizard->email_page = keygen_wizard_email_page (wizard);
gtk_assistant_append_page (GTK_ASSISTANT (window), wizard->email_page);
gtk_assistant_set_page_type (GTK_ASSISTANT (window), wizard->email_page,
GTK_ASSISTANT_PAGE_CONTENT);
gtk_assistant_set_page_title (GTK_ASSISTANT (window), wizard->email_page,
/* FIXME */ _("Generate key"));
gtk_assistant_set_page_side_image (GTK_ASSISTANT (window), wizard->email_page,
genkey_pixbuf);
/* FIXME: A better GUI would have a "Generate backup" button on the
finish page after the key was generated. */
wizard->backup_page = gpa_keygen_wizard_backup_page (wizard);
gtk_assistant_append_page (GTK_ASSISTANT (window), wizard->backup_page);
gtk_assistant_set_page_type (GTK_ASSISTANT (window), wizard->backup_page,
GTK_ASSISTANT_PAGE_CONTENT);
gtk_assistant_set_page_title (GTK_ASSISTANT (window), wizard->backup_page,
/* FIXME */ _("Generate key"));
gtk_assistant_set_page_side_image (GTK_ASSISTANT (window),
wizard->backup_page,
backup_pixbuf);
gtk_assistant_set_page_complete (GTK_ASSISTANT (wizard->window),
wizard->backup_page, TRUE);
/* FIXME: We need to integrate the progress bar for the operation
into the page. Also, after the operation completes, the
assistant is destroyed, so the final page will never be
shown. The whole thing is upside down, and should be redone. */
wizard->wait_page = gpa_keygen_wizard_wait_page (wizard);
gtk_assistant_append_page (GTK_ASSISTANT (window), wizard->wait_page);
gtk_assistant_set_page_type (GTK_ASSISTANT (window), wizard->wait_page,
GTK_ASSISTANT_PAGE_PROGRESS);
gtk_assistant_set_page_title (GTK_ASSISTANT (window), wizard->wait_page,
/* FIXME */ _("Generate key"));
gtk_assistant_set_page_side_image (GTK_ASSISTANT (window), wizard->wait_page,
genkey_pixbuf);
/* The final page does not contain information about the generated
key. It should also offer a "generate backup" button, then the
backup page can be removed. */
wizard->final_page = gpa_keygen_wizard_final_page (wizard);
gtk_assistant_append_page (GTK_ASSISTANT (window), wizard->final_page);
gtk_assistant_set_page_type (GTK_ASSISTANT (window), wizard->final_page,
GTK_ASSISTANT_PAGE_SUMMARY);
gtk_assistant_set_page_title (GTK_ASSISTANT (window), wizard->final_page,
/* FIXME */ _("Generate key"));
gtk_assistant_set_page_side_image (GTK_ASSISTANT (window), wizard->final_page,
genkey_pixbuf);
g_signal_connect (G_OBJECT (window), "prepare",
G_CALLBACK (keygen_wizard_prepare_cb), wizard);
g_signal_connect (G_OBJECT (window), "close",
G_CALLBACK (keygen_wizard_close), wizard);
g_signal_connect (G_OBJECT (window), "cancel",
G_CALLBACK (keygen_wizard_close), wizard);
gtk_window_set_modal (GTK_WINDOW (window), TRUE);
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (parent));
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER_ON_PARENT);
g_object_unref (genkey_pixbuf);
g_object_unref (backup_pixbuf);
return window;
}