[evolution] Bug 680451 - Add Certificate support into Contact editor
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution] Bug 680451 - Add Certificate support into Contact editor
- Date: Thu, 2 Jul 2015 16:15:51 +0000 (UTC)
commit 0442acbf12f58951c9ba49db626affb00d231481
Author: Milan Crha <mcrha redhat com>
Date: Thu Jul 2 18:12:50 2015 +0200
Bug 680451 - Add Certificate support into Contact editor
addressbook/gui/contact-editor/contact-editor.ui | 174 ++++++
addressbook/gui/contact-editor/e-contact-editor.c | 638 ++++++++++++++++++++
.../org.gnome.evolution.addressbook.gschema.xml.in | 5 +
3 files changed, 817 insertions(+), 0 deletions(-)
---
diff --git a/addressbook/gui/contact-editor/contact-editor.ui
b/addressbook/gui/contact-editor/contact-editor.ui
index 1c5dd93..31ca435 100644
--- a/addressbook/gui/contact-editor/contact-editor.ui
+++ b/addressbook/gui/contact-editor/contact-editor.ui
@@ -1935,6 +1935,172 @@
<property name="tab_fill">False</property>
</packing>
</child>
+ <child>
+ <object class="GtkGrid" id="certs-grid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">12</property>
+ <property name="margin_right">12</property>
+ <property name="margin_top">12</property>
+ <property name="margin_bottom">12</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="margin_bottom">12</property>
+ <property name="hexpand">True</property>
+ <property name="shadow_type">in</property>
+ <property name="min_content_height">160</property>
+ <child>
+ <object class="GtkTreeView" id="certs-treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection1"/>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButtonBox" id="buttonbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">6</property>
+ <property name="orientation">vertical</property>
+ <property name="layout_style">start</property>
+ <child>
+ <object class="GtkButton" id="cert-add-pgp-btn">
+ <property name="label" translatable="yes">Add _PGP</property>
+ <property name="use_underline">True</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cert-add-x509-btn">
+ <property name="label" translatable="yes">Add _X.509</property>
+ <property name="use_underline">True</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cert-remove-btn">
+ <property name="label" translatable="yes">_Remove</property>
+ <property name="use_underline">True</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <object class="GtkButton" id="cert-load-pgp-btn">
+ <property name="label" translatable="yes">Load P_GP</property>
+ <property name="use_underline">True</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cert-load-x509-btn">
+ <property name="label" translatable="yes">_Load X.509</property>
+ <property name="use_underline">True</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cert-save-btn">
+ <property name="label" translatable="yes">_Save</property>
+ <property name="use_underline">True</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="cert-preview-scw">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Certificates</property>
+ </object>
+ <packing>
+ <property name="position">4</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
</object>
<packing>
<property name="expand">True</property>
@@ -2139,6 +2305,14 @@
<property name="use_underline">True</property>
</object>
</child>
+ <child>
+ <object class="GtkCheckMenuItem" id="menuitem-config-certs">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Show Certificates</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
</object>
</interface>
diff --git a/addressbook/gui/contact-editor/e-contact-editor.c
b/addressbook/gui/contact-editor/e-contact-editor.c
index a7c5a8b..488fc32 100644
--- a/addressbook/gui/contact-editor/e-contact-editor.c
+++ b/addressbook/gui/contact-editor/e-contact-editor.c
@@ -35,6 +35,10 @@
#include <gdk/gdkkeysyms.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
+#define GCR_API_SUBJECT_TO_CHANGE
+#include <gcr/gcr.h>
+#undef GCR_API_SUBJECT_TO_CHANGE
+
#include "shell/e-shell.h"
#include "e-util/e-util.h"
@@ -72,6 +76,7 @@
#define CHECK_JOB 8
#define CHECK_MISC 9
#define CHECK_NOTE 10
+#define CHECK_CERTS 11
/* IM columns */
enum {
@@ -1703,6 +1708,17 @@ check_notes_for_data (EContactEditor *editor)
}
static gboolean
+check_certs_for_data (EContactEditor *editor)
+{
+ GtkWidget *treeview = e_builder_get_widget (editor->priv->builder, "certs-treeview");
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
+ return model && gtk_tree_model_get_iter_first (model, &iter);
+}
+
+static gboolean
check_section_for_data (EContactEditor *editor,
gint check)
{
@@ -1739,6 +1755,9 @@ check_section_for_data (EContactEditor *editor,
case CHECK_NOTE:
has_data = check_notes_for_data (editor);
break;
+ case CHECK_CERTS:
+ has_data = check_certs_for_data (editor);
+ break;
default:
g_warning ("unknown data check requested");
}
@@ -1782,6 +1801,7 @@ config_sensitize_cb (GtkWidget *button,
config_sensitize_item (editor, "menuitem-config-other", CHECK_OTHER);
config_sensitize_item (editor, "menuitem-config-notes", CHECK_NOTE);
+ config_sensitize_item (editor, "menuitem-config-certs", CHECK_CERTS);
}
/*
@@ -1834,6 +1854,7 @@ configure_visibility (EContactEditor *editor)
show_tab);
configure_widget_visibility (editor, settings, "scrolledwindow-notes", "editor-show-notes",
CHECK_NOTE);
+ configure_widget_visibility (editor, settings, "certs-grid", "editor-show-certs", CHECK_CERTS);
g_object_unref (settings);
}
@@ -1876,6 +1897,7 @@ config_save_cb (GtkWidget *button,
config_menuitem_save (editor, settings, "menuitem-config-other", "editor-show-mailing-other");
config_menuitem_save (editor, settings, "menuitem-config-notes", "editor-show-notes");
+ config_menuitem_save (editor, settings, "menuitem-config-certs", "editor-show-certs");
g_object_unref (settings);
@@ -1932,6 +1954,7 @@ init_config (EContactEditor *editor)
init_config_menuitem (editor, settings, "menuitem-config-other", "editor-show-mailing-other");
init_config_menuitem (editor, settings, "menuitem-config-notes", "editor-show-notes");
+ init_config_menuitem (editor, settings, "menuitem-config-certs", "editor-show-certs");
g_object_unref (settings);
}
@@ -3143,6 +3166,617 @@ sensitize_simple (EContactEditor *editor)
}
}
+enum CertKind {
+ CERT_KIND_X509,
+ CERT_KIND_PGP
+};
+
+enum CertColumns {
+ CERT_COLUMN_SUBJECT_STRING,
+ CERT_COLUMN_KIND_STRING,
+ CERT_COLUMN_KIND_INT,
+ CERT_COLUMN_DATA_ECONTACTCERT,
+ CERT_COLUMN_CERT_GCRCERTIFICATE,
+ N_CERT_COLUMNS
+};
+
+static void
+cert_tab_selection_changed_cb (GtkTreeSelection *selection,
+ EContactEditor *editor)
+{
+ GtkWidget *widget;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean has_selected;
+
+ g_return_if_fail (E_IS_CONTACT_EDITOR (editor));
+
+ has_selected = gtk_tree_selection_get_selected (selection, &model, &iter);
+
+ widget = e_builder_get_widget (editor->priv->builder, "cert-remove-btn");
+ gtk_widget_set_sensitive (widget, has_selected);
+
+ widget = e_builder_get_widget (editor->priv->builder, "cert-load-pgp-btn");
+ gtk_widget_set_sensitive (widget, has_selected && is_field_supported (editor, E_CONTACT_PGP_CERT));
+
+ widget = e_builder_get_widget (editor->priv->builder, "cert-load-x509-btn");
+ gtk_widget_set_sensitive (widget, has_selected && is_field_supported (editor, E_CONTACT_X509_CERT));
+
+ widget = e_builder_get_widget (editor->priv->builder, "cert-save-btn");
+ gtk_widget_set_sensitive (widget, has_selected);
+
+ widget = e_builder_get_widget (editor->priv->builder, "cert-preview-scw");
+ widget = gtk_bin_get_child (GTK_BIN (widget));
+
+ if (GTK_IS_VIEWPORT (widget))
+ widget = gtk_bin_get_child (GTK_BIN (widget));
+
+ g_return_if_fail (GCR_IS_CERTIFICATE_WIDGET (widget));
+
+ if (has_selected) {
+ GcrCertificate *cert = NULL;
+
+ gtk_tree_model_get (model, &iter, CERT_COLUMN_CERT_GCRCERTIFICATE, &cert, -1);
+
+ gcr_certificate_widget_set_certificate (GCR_CERTIFICATE_WIDGET (widget), cert);
+
+ g_clear_object (&cert);
+ } else {
+ gcr_certificate_widget_set_certificate (GCR_CERTIFICATE_WIDGET (widget), NULL);
+ }
+}
+
+static void
+cert_add_filters_for_kind (GtkFileChooser *file_chooser,
+ enum CertKind kind)
+{
+ GtkFileFilter *filter;
+
+ g_return_if_fail (GTK_IS_FILE_CHOOSER (file_chooser));
+ g_return_if_fail (kind == CERT_KIND_PGP || kind == CERT_KIND_X509);
+
+ if (kind == CERT_KIND_X509) {
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("X.509 certificates"));
+ gtk_file_filter_add_mime_type (filter, "application/x-x509-user-cert");
+ gtk_file_chooser_add_filter (file_chooser, filter);
+ } else {
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("PGP keys"));
+ gtk_file_filter_add_mime_type (filter, "application/pgp-keys");
+ gtk_file_chooser_add_filter (file_chooser, filter);
+ }
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("All files"));
+ gtk_file_filter_add_pattern (filter, "*");
+ gtk_file_chooser_add_filter (file_chooser, filter);
+}
+
+static EContactCert *
+cert_load_for_kind (EContactEditor *editor,
+ enum CertKind kind)
+{
+ EContactCert *cert = NULL;
+ GtkWindow *parent;
+ GtkWidget *dialog;
+ GtkFileChooser *file_chooser;
+ GError *error = NULL;
+
+ g_return_val_if_fail (E_IS_CONTACT_EDITOR (editor), NULL);
+ g_return_val_if_fail (kind == CERT_KIND_PGP || kind == CERT_KIND_X509, NULL);
+
+ parent = eab_editor_get_window (EAB_EDITOR (editor));
+ dialog = gtk_file_chooser_dialog_new (
+ kind == CERT_KIND_PGP ? _("Open PGP key") : _("Open X.509 certificate"), parent,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Open"), GTK_RESPONSE_OK,
+ NULL);
+
+ file_chooser = GTK_FILE_CHOOSER (dialog);
+ gtk_file_chooser_set_local_only (file_chooser, TRUE);
+ gtk_file_chooser_set_select_multiple (file_chooser, FALSE);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+ cert_add_filters_for_kind (file_chooser, kind);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
+ gchar *filename;
+ gchar *content = NULL;
+ gsize length = 0;
+
+ filename = gtk_file_chooser_get_filename (file_chooser);
+ if (!filename) {
+ g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Chosen file is
not a local file."));
+ } else if (g_file_get_contents (filename, &content, &length, &error) && length > 0) {
+ cert = e_contact_cert_new ();
+ cert->length = length;
+ cert->data = content;
+ }
+
+ g_free (filename);
+ }
+
+ gtk_widget_destroy (dialog);
+
+ if (error) {
+ e_notice (parent, GTK_MESSAGE_ERROR, _("Failed to load certificate: %s"), error->message);
+ g_clear_error (&error);
+ }
+
+ return cert;
+}
+
+static void
+cert_update_row_with_cert (GtkListStore *list_store,
+ GtkTreeIter *iter,
+ EContactCert *cert,
+ enum CertKind kind)
+{
+ GcrCertificate *gcr_cert = NULL;
+ gchar *subject = NULL;
+
+ g_return_if_fail (GTK_IS_LIST_STORE (list_store));
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (cert != NULL);
+ g_return_if_fail (kind == CERT_KIND_PGP || kind == CERT_KIND_X509);
+
+ if (kind == CERT_KIND_X509) {
+ gcr_cert = gcr_simple_certificate_new ((const guchar *) cert->data, cert->length);
+ if (gcr_cert)
+ subject = gcr_certificate_get_subject_name (gcr_cert);
+ }
+
+ gtk_list_store_set (list_store, iter,
+ CERT_COLUMN_SUBJECT_STRING, subject,
+ CERT_COLUMN_KIND_STRING, kind == CERT_KIND_X509 ? C_("cert-kind", "X.509") : C_("cert-kind",
"PGP"),
+ CERT_COLUMN_KIND_INT, kind,
+ CERT_COLUMN_DATA_ECONTACTCERT, cert,
+ CERT_COLUMN_CERT_GCRCERTIFICATE, gcr_cert,
+ -1);
+
+ g_clear_object (&gcr_cert);
+ g_free (subject);
+}
+
+static void
+cert_add_kind (EContactEditor *editor,
+ enum CertKind kind)
+{
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ EContactCert *cert;
+
+ g_return_if_fail (E_IS_CONTACT_EDITOR (editor));
+ g_return_if_fail (kind == CERT_KIND_PGP || kind == CERT_KIND_X509);
+
+ tree_view = GTK_TREE_VIEW (e_builder_get_widget (editor->priv->builder, "certs-treeview"));
+ g_return_if_fail (tree_view != NULL);
+
+ model = gtk_tree_view_get_model (tree_view);
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ cert = cert_load_for_kind (editor, kind);
+ if (cert) {
+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+ cert_update_row_with_cert (GTK_LIST_STORE (model), &iter, cert, kind);
+ e_contact_cert_free (cert);
+
+ gtk_tree_selection_select_iter (selection, &iter);
+
+ object_changed (G_OBJECT (tree_view), editor);
+ }
+}
+
+static void
+cert_add_pgp_btn_clicked_cb (GtkWidget *button,
+ EContactEditor *editor)
+{
+ g_return_if_fail (E_IS_CONTACT_EDITOR (editor));
+
+ cert_add_kind (editor, CERT_KIND_PGP);
+}
+
+static void
+cert_add_x509_btn_clicked_cb (GtkWidget *button,
+ EContactEditor *editor)
+{
+ g_return_if_fail (E_IS_CONTACT_EDITOR (editor));
+
+ cert_add_kind (editor, CERT_KIND_X509);
+}
+
+static void
+cert_remove_btn_clicked_cb (GtkWidget *button,
+ EContactEditor *editor)
+{
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter, select;
+ gboolean have_select;
+
+ g_return_if_fail (E_IS_CONTACT_EDITOR (editor));
+
+ tree_view = GTK_TREE_VIEW (e_builder_get_widget (editor->priv->builder, "certs-treeview"));
+ g_return_if_fail (tree_view != NULL);
+
+ selection = gtk_tree_view_get_selection (tree_view);
+ g_return_if_fail (gtk_tree_selection_get_selected (selection, &model, &iter));
+
+ select = iter;
+ have_select = gtk_tree_model_iter_next (model, &select);
+ if (!have_select) {
+ select = iter;
+ have_select = gtk_tree_model_iter_previous (model, &select);
+ }
+
+ if (have_select)
+ gtk_tree_selection_select_iter (selection, &select);
+
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+
+ object_changed (G_OBJECT (tree_view), editor);
+}
+
+static void
+cert_load_kind (EContactEditor *editor,
+ enum CertKind kind)
+{
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ EContactCert *cert;
+
+ g_return_if_fail (E_IS_CONTACT_EDITOR (editor));
+ g_return_if_fail (kind == CERT_KIND_PGP || kind == CERT_KIND_X509);
+
+ tree_view = GTK_TREE_VIEW (e_builder_get_widget (editor->priv->builder, "certs-treeview"));
+ g_return_if_fail (tree_view != NULL);
+
+ selection = gtk_tree_view_get_selection (tree_view);
+ g_return_if_fail (gtk_tree_selection_get_selected (selection, &model, &iter));
+
+ cert = cert_load_for_kind (editor, kind);
+ if (cert) {
+ cert_update_row_with_cert (GTK_LIST_STORE (model), &iter, cert, kind);
+ e_contact_cert_free (cert);
+
+ object_changed (G_OBJECT (tree_view), editor);
+ }
+}
+
+static void
+cert_load_pgp_btn_clicked_cb (GtkWidget *button,
+ EContactEditor *editor)
+{
+ g_return_if_fail (E_IS_CONTACT_EDITOR (editor));
+
+ cert_load_kind (editor, CERT_KIND_PGP);
+}
+
+static void
+cert_load_x509_btn_clicked_cb (GtkWidget *button,
+ EContactEditor *editor)
+{
+ g_return_if_fail (E_IS_CONTACT_EDITOR (editor));
+
+ cert_load_kind (editor, CERT_KIND_X509);
+}
+
+static void
+cert_save_btn_clicked_cb (GtkWidget *button,
+ EContactEditor *editor)
+{
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ EContactCert *cert = NULL;
+ gint kind = -1;
+ GtkWindow *parent;
+ GtkWidget *dialog;
+ GtkFileChooser *file_chooser;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_CONTACT_EDITOR (editor));
+
+ tree_view = GTK_TREE_VIEW (e_builder_get_widget (editor->priv->builder, "certs-treeview"));
+ g_return_if_fail (tree_view != NULL);
+
+ selection = gtk_tree_view_get_selection (tree_view);
+ g_return_if_fail (gtk_tree_selection_get_selected (selection, &model, &iter));
+
+ gtk_tree_model_get (model, &iter,
+ CERT_COLUMN_KIND_INT, &kind,
+ CERT_COLUMN_DATA_ECONTACTCERT, &cert,
+ -1);
+
+ g_return_if_fail (kind == CERT_KIND_X509 || kind == CERT_KIND_PGP);
+ g_return_if_fail (cert != NULL);
+
+ parent = eab_editor_get_window (EAB_EDITOR (editor));
+ dialog = gtk_file_chooser_dialog_new (
+ kind == CERT_KIND_PGP ? _("Save PGP key") : _("Save X.509 certificate"), parent,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Save"), GTK_RESPONSE_OK,
+ NULL);
+
+ file_chooser = GTK_FILE_CHOOSER (dialog);
+ gtk_file_chooser_set_local_only (file_chooser, TRUE);
+ gtk_file_chooser_set_select_multiple (file_chooser, FALSE);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+ cert_add_filters_for_kind (file_chooser, kind);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
+ gchar *filename;
+
+ filename = gtk_file_chooser_get_filename (file_chooser);
+ if (!filename) {
+ g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Chosen file is
not a local file."));
+ } else {
+ g_file_set_contents (filename, cert->data, cert->length, &error);
+ }
+
+ g_free (filename);
+ }
+
+ gtk_widget_destroy (dialog);
+ e_contact_cert_free (cert);
+
+ if (error) {
+ e_notice (parent, GTK_MESSAGE_ERROR, _("Failed to save certificate: %s"), error->message);
+ g_clear_error (&error);
+ }
+}
+
+static void
+init_certs (EContactEditor *editor)
+{
+ GtkListStore *list_store;
+ GtkTreeView *tree_view;
+ GtkTreeViewColumn *column;
+ GtkTreeSelection *selection;
+ GtkCellRenderer *renderer;
+ GcrCertificateWidget *certificate_widget;
+ GtkWidget *widget;
+
+ tree_view = GTK_TREE_VIEW (e_builder_get_widget (editor->priv->builder, "certs-treeview"));
+ g_return_if_fail (tree_view != NULL);
+
+ gtk_tree_view_set_headers_visible (tree_view, FALSE);
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_append_column (tree_view, column);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_tree_view_column_add_attribute (column, renderer, "text", CERT_COLUMN_KIND_STRING);
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_expand (column, TRUE);
+ gtk_tree_view_append_column (tree_view, column);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_tree_view_column_add_attribute (column, renderer, "text", CERT_COLUMN_SUBJECT_STRING);
+
+ list_store = gtk_list_store_new (N_CERT_COLUMNS,
+ G_TYPE_STRING, /* CERT_COLUMN_SUBJECT_STRING */
+ G_TYPE_STRING, /* CERT_COLUMN_KIND_STRING */
+ G_TYPE_INT, /* CERT_COLUMN_KIND_INT */
+ E_TYPE_CONTACT_CERT, /* CERT_COLUMN_DATA_ECONTACTCERT */
+ GCR_TYPE_CERTIFICATE); /* CERT_COLUMN_CERT_GCRCERTIFICATE */
+
+ gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (list_store));
+
+ certificate_widget = gcr_certificate_widget_new (NULL);
+ gtk_widget_show (GTK_WIDGET (certificate_widget));
+ widget = e_builder_get_widget (editor->priv->builder, "cert-preview-scw");
+ gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (certificate_widget));
+
+ selection = gtk_tree_view_get_selection (tree_view);
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+ g_signal_connect (selection, "changed", G_CALLBACK (cert_tab_selection_changed_cb), editor);
+
+ widget = e_builder_get_widget (editor->priv->builder, "cert-add-pgp-btn");
+ g_signal_connect (widget, "clicked", G_CALLBACK (cert_add_pgp_btn_clicked_cb), editor);
+
+ widget = e_builder_get_widget (editor->priv->builder, "cert-add-x509-btn");
+ g_signal_connect (widget, "clicked", G_CALLBACK (cert_add_x509_btn_clicked_cb), editor);
+
+ widget = e_builder_get_widget (editor->priv->builder, "cert-remove-btn");
+ g_signal_connect (widget, "clicked", G_CALLBACK (cert_remove_btn_clicked_cb), editor);
+
+ widget = e_builder_get_widget (editor->priv->builder, "cert-load-pgp-btn");
+ g_signal_connect (widget, "clicked", G_CALLBACK (cert_load_pgp_btn_clicked_cb), editor);
+
+ widget = e_builder_get_widget (editor->priv->builder, "cert-load-x509-btn");
+ g_signal_connect (widget, "clicked", G_CALLBACK (cert_load_x509_btn_clicked_cb), editor);
+
+ widget = e_builder_get_widget (editor->priv->builder, "cert-save-btn");
+ g_signal_connect (widget, "clicked", G_CALLBACK (cert_save_btn_clicked_cb), editor);
+}
+
+static void
+fill_in_certs (EContactEditor *editor)
+{
+ GtkTreeModel *model;
+ GtkListStore *list_store;
+ GtkWidget *widget;
+ GList *attrs, *link;
+ GtkTreeIter iter;
+ enum CertKind kind;
+
+ widget = e_builder_get_widget (editor->priv->builder, "certs-treeview");
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+ list_store = GTK_LIST_STORE (model);
+
+ /* Clear */
+
+ gtk_list_store_clear (list_store);
+
+ /* Fill in */
+
+ attrs = e_vcard_get_attributes (E_VCARD (editor->priv->contact));
+ for (link = attrs; link; link = g_list_next (link)) {
+ EVCardAttribute *attr = link->data;
+ EContactCert *cert;
+ GString *value;
+ GtkTreeIter iter;
+
+ if (e_vcard_attribute_has_type (attr, "X509"))
+ kind = CERT_KIND_X509;
+ else if (e_vcard_attribute_has_type (attr, "PGP"))
+ kind = CERT_KIND_PGP;
+ else
+ continue;
+
+ value = e_vcard_attribute_get_value_decoded (attr);
+ if (!value || !value->len) {
+ if (value)
+ g_string_free (value, TRUE);
+ continue;
+ }
+
+ cert = e_contact_cert_new ();
+ cert->length = value->len;
+ cert->data = g_malloc (cert->length);
+ memcpy (cert->data, value->str, cert->length);
+
+ gtk_list_store_append (list_store, &iter);
+
+ cert_update_row_with_cert (list_store, &iter, cert, kind);
+
+ e_contact_cert_free (cert);
+ g_string_free (value, TRUE);
+ }
+
+ if (gtk_tree_model_get_iter_first (model, &iter)) {
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+ gtk_tree_selection_select_iter (selection, &iter);
+ }
+}
+
+static void
+extract_certs_for_kind (EContactEditor *editor,
+ enum CertKind kind,
+ EContactField field,
+ GtkTreeModel *model)
+{
+ GtkTreeIter iter;
+ gboolean valid;
+ EVCard *vcard;
+ GList *attrs = NULL, *link;
+
+ if (is_field_supported (editor, field)) {
+ valid = gtk_tree_model_get_iter_first (model, &iter);
+ while (valid) {
+ EContactCert *cert = NULL;
+ gint set_kind = -1;
+
+ gtk_tree_model_get (model, &iter,
+ CERT_COLUMN_KIND_INT, &set_kind,
+ CERT_COLUMN_DATA_ECONTACTCERT, &cert,
+ -1);
+
+ if (cert && set_kind == kind) {
+ EVCardAttribute *attr;
+
+ attr = e_vcard_attribute_new ("", e_contact_vcard_attribute (field));
+ e_vcard_attribute_add_param_with_value (
+ attr, e_vcard_attribute_param_new (EVC_TYPE),
+ field == E_CONTACT_X509_CERT ? "X509" : "PGP");
+ e_vcard_attribute_add_param_with_value (
+ attr,
+ e_vcard_attribute_param_new (EVC_ENCODING),
+ "b");
+
+ e_vcard_attribute_add_value_decoded (attr, cert->data, cert->length);
+
+ attrs = g_list_prepend (attrs, attr);
+ }
+
+ e_contact_cert_free (cert);
+
+ valid = gtk_tree_model_iter_next (model, &iter);
+ }
+ }
+
+ attrs = g_list_reverse (attrs);
+
+ vcard = E_VCARD (editor->priv->contact);
+
+ for (link = attrs; link; link = g_list_next (link)) {
+ /* takes ownership of the attribute */
+ e_vcard_append_attribute (vcard, link->data);
+ }
+
+ g_list_free (attrs);
+}
+
+static void
+extract_certs (EContactEditor *editor)
+{
+ GtkWidget *widget;
+ GtkTreeModel *model;
+ GList *attrs, *link;
+ EVCard *vcard;
+
+ widget = e_builder_get_widget (editor->priv->builder, "certs-treeview");
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+
+ vcard = E_VCARD (editor->priv->contact);
+ attrs = g_list_copy (e_vcard_get_attributes (vcard));
+
+ for (link = attrs; link; link = g_list_next (link)) {
+ EVCardAttribute *attr = link->data;
+
+ /* Remove only those types the editor can work with. */
+ if ((!e_vcard_attribute_get_name (attr) ||
+ g_ascii_strcasecmp (EVC_KEY, e_vcard_attribute_get_name (attr)) == 0) &&
+ (e_vcard_attribute_has_type (attr, "X509") ||
+ e_vcard_attribute_has_type (attr, "PGP"))) {
+ e_vcard_remove_attribute (vcard, attr);
+ }
+ }
+
+ g_list_free (attrs);
+
+ /* The saved order will always be X.509 first, then PGP */
+ extract_certs_for_kind (editor, CERT_KIND_X509, E_CONTACT_X509_CERT, model);
+ extract_certs_for_kind (editor, CERT_KIND_PGP, E_CONTACT_PGP_CERT, model);
+}
+
+static void
+sensitize_certs (EContactEditor *editor)
+{
+ GtkWidget *widget;
+
+ widget = e_builder_get_widget (editor->priv->builder, "certs-grid");
+
+ gtk_widget_set_sensitive (widget, editor->priv->target_editable && (
+ is_field_supported (editor, E_CONTACT_X509_CERT) ||
+ is_field_supported (editor, E_CONTACT_PGP_CERT)));
+
+ widget = e_builder_get_widget (editor->priv->builder, "cert-add-pgp-btn");
+ gtk_widget_set_sensitive (widget, is_field_supported (editor, E_CONTACT_PGP_CERT));
+
+ widget = e_builder_get_widget (editor->priv->builder, "cert-add-x509-btn");
+ gtk_widget_set_sensitive (widget, is_field_supported (editor, E_CONTACT_X509_CERT));
+
+ widget = e_builder_get_widget (editor->priv->builder, "certs-treeview");
+ cert_tab_selection_changed_cb (gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)), editor);
+}
+
static void
fill_in_all (EContactEditor *editor)
{
@@ -3165,6 +3799,7 @@ fill_in_all (EContactEditor *editor)
fill_in_sip (editor);
fill_in_im (editor);
fill_in_address (editor);
+ fill_in_certs (editor);
/* Visibility of sections and status of menuitems in the config-menu depend on data
* they have to be initialized here instead of init_all() and sensitize_all()
@@ -3187,6 +3822,7 @@ extract_all (EContactEditor *editor)
extract_sip (editor);
extract_im (editor);
extract_address (editor);
+ extract_certs (editor);
}
static void
@@ -3211,6 +3847,7 @@ sensitize_all (EContactEditor *editor)
sensitize_sip (editor);
sensitize_im (editor);
sensitize_address (editor);
+ sensitize_certs (editor);
if (weak_pointer) {
g_object_remove_weak_pointer (G_OBJECT (focused_widget), &weak_pointer);
@@ -3247,6 +3884,7 @@ init_all (EContactEditor *editor)
init_im (editor);
init_personal (editor);
init_address (editor);
+ init_certs (editor);
init_config (editor);
/* with so many scrolled windows, we need to
diff --git a/data/org.gnome.evolution.addressbook.gschema.xml.in
b/data/org.gnome.evolution.addressbook.gschema.xml.in
index 79e67f1..1a460b1 100644
--- a/data/org.gnome.evolution.addressbook.gschema.xml.in
+++ b/data/org.gnome.evolution.addressbook.gschema.xml.in
@@ -110,5 +110,10 @@
<summary>Show notes-tab</summary>
<_description>Whether to show notes in the editor</_description>
</key>
+ <key type="b" name="editor-show-certs">
+ <_default>true</_default>
+ <summary>Show Certificates tab</summary>
+ <_description>Whether to show Certificates tab in the editor</_description>
+ </key>
</schema>
</schemalist>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]