diff --git a/src/recipientdlg.c b/src/recipientdlg.c
index 6f7e98d..e288d04 100644
--- a/src/recipientdlg.c
+++ b/src/recipientdlg.c
@@ -1,1233 +1,1233 @@
/* 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 (GtkAction *action, RecipientDlg *dialog)
{
do_select_key (dialog, GPGME_PROTOCOL_OpenPGP);
}
static void
recplist_popup_x509 (GtkAction *action, RecipientDlg *dialog)
{
do_select_key (dialog, GPGME_PROTOCOL_CMS);
}
static void
recplist_popup_ignore (GtkAction *action, RecipientDlg *dialog)
{
GtkTreeModel *model;
GtkTreeIter iter;
struct userdata_s *info;
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 (menu, NULL, NULL, NULL, NULL,
event_button->button, event_button->time);
}
return TRUE;
}
}
return FALSE;
}
/* Create the popup menu for the recipient list. */
static GtkWidget *
recplist_popup_menu_new (GtkWidget *window, RecipientDlg *dialog)
{
static const GtkActionEntry entries[] =
{
/* Toplevel. */
{ "SelectPGPKey", NULL, N_("Select _PGP key..."), NULL,
NULL, G_CALLBACK (recplist_popup_pgp) },
{ "SelectCMSKey", NULL, N_("Select _S\\/MIME key..."), NULL,
NULL, G_CALLBACK (recplist_popup_x509) },
{ "ToggleIgnoreFlag", NULL, N_("Toggle _Ignore flag"), NULL,
NULL, G_CALLBACK (recplist_popup_ignore) }
};
static const char *ui_description =
""
" "
" "
" "
" "
" "
"";
GtkAccelGroup *accel_group;
GtkActionGroup *action_group;
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),
dialog);
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 (window), accel_group);
if (! gtk_ui_manager_add_ui_from_string (ui_manager, ui_description,
-1, &error))
{
g_message ("building clipboard menus failed: %s", error->message);
g_error_free (error);
exit (EXIT_FAILURE);
}
return gtk_ui_manager_get_widget (ui_manager, "/PopupMenu");
}
/************************************************************
****************** 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(dialog);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
labelKeys = gtk_label_new_with_mnemonic (_("_Recipient list"));
gtk_misc_set_alignment (GTK_MISC (labelKeys), 0.0, 0.5);
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_hbox_new (FALSE, 0);
+ 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_hseparator_new ();
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;
}