/*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the program; if not, see
*
*
* Authors:
* Chris Toshok
*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include "ca-trust-dialog.h"
#include "cert-trust-dialog.h"
#include "certificate-manager.h"
#include "certificate-viewer.h"
#include "e-cert.h"
#include "e-cert-trust.h"
#include "e-cert-db.h"
#include "nss.h"
#include
#include
#include
#include
#include
#include "shell/e-shell.h"
#include "e-util/e-dialog-utils.h"
#include "e-util/e-util.h"
#include "e-util/e-util-private.h"
#include "widgets/misc/e-preferences-window.h"
typedef struct {
GtkBuilder *builder;
GtkWidget *yourcerts_treeview;
GtkTreeStore *yourcerts_treemodel;
GtkTreeModel *yourcerts_streemodel;
GHashTable *yourcerts_root_hash;
GtkWidget *view_your_button;
GtkWidget *backup_your_button;
GtkWidget *backup_all_your_button;
GtkWidget *import_your_button;
GtkWidget *delete_your_button;
GtkWidget *contactcerts_treeview;
GtkTreeModel *contactcerts_streemodel;
GHashTable *contactcerts_root_hash;
GtkWidget *view_contact_button;
GtkWidget *edit_contact_button;
GtkWidget *import_contact_button;
GtkWidget *delete_contact_button;
GtkWidget *authoritycerts_treeview;
GtkTreeModel *authoritycerts_streemodel;
GHashTable *authoritycerts_root_hash;
GtkWidget *view_ca_button;
GtkWidget *edit_ca_button;
GtkWidget *import_ca_button;
GtkWidget *delete_ca_button;
} CertificateManagerData;
typedef void (*AddCertCb)(CertificateManagerData *cfm, ECert *cert);
static void unload_certs (CertificateManagerData *cfm, ECertType type);
static void load_certs (CertificateManagerData *cfm, ECertType type, AddCertCb add_cert);
static void add_user_cert (CertificateManagerData *cfm, ECert *cert);
static void add_contact_cert (CertificateManagerData *cfm, ECert *cert);
static void add_ca_cert (CertificateManagerData *cfm, ECert *cert);
static void
report_and_free_error (CertificateManagerData *cfm, const gchar *where, GError *error)
{
g_return_if_fail (cfm != NULL);
e_notice (gtk_widget_get_toplevel (cfm->yourcerts_treeview),
GTK_MESSAGE_ERROR, "%s: %s", where, error ? error->message : _("Unknown error"));
if (error)
g_error_free (error);
}
static void
handle_selection_changed (GtkTreeSelection *selection,
gint cert_column,
GtkWidget *view_button,
GtkWidget *edit_button,
GtkWidget *delete_button)
{
GtkTreeIter iter;
gboolean cert_selected = FALSE;
GtkTreeModel *model;
if (gtk_tree_selection_get_selected (selection,
&model,
&iter)) {
ECert *cert;
gtk_tree_model_get (model,
&iter,
cert_column, &cert,
-1);
if (cert) {
cert_selected = TRUE;
g_object_unref (cert);
}
}
if (delete_button)
gtk_widget_set_sensitive (delete_button, cert_selected);
if (edit_button)
gtk_widget_set_sensitive (edit_button, cert_selected);
if (view_button)
gtk_widget_set_sensitive (view_button, cert_selected);
}
static void
import_your (GtkWidget *widget, CertificateManagerData *cfm)
{
GtkWidget *filesel;
GtkFileFilter* filter;
filesel = gtk_file_chooser_dialog_new (_("Select a certificate to import..."),
NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (filesel), GTK_RESPONSE_OK);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("All PKCS12 files"));
gtk_file_filter_add_mime_type (filter, "application/x-x509-user-cert");
gtk_file_filter_add_mime_type (filter, "application/x-pkcs12");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (filesel), 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 (GTK_FILE_CHOOSER (filesel), filter);
if (GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (filesel))) {
gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filesel));
GError *error = NULL;
/* destroy dialog to get rid of it in the GUI */
gtk_widget_destroy (filesel);
if (e_cert_db_import_pkcs12_file (e_cert_db_peek (),
filename, &error)) {
/* there's no telling how many certificates were added during the import,
so we blow away the contact cert display and regenerate it. */
unload_certs (cfm, E_CERT_USER);
load_certs (cfm, E_CERT_USER, add_user_cert);
gtk_tree_view_expand_all (GTK_TREE_VIEW (cfm->yourcerts_treeview));
} else {
report_and_free_error (cfm, _("Failed to import user's certificate"), error);
}
g_free (filename);
} else
gtk_widget_destroy (filesel);
}
static void
delete_your (GtkWidget *widget, CertificateManagerData *cfm)
{
GtkTreeIter iter;
if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->yourcerts_treeview)),
NULL,
&iter)) {
ECert *cert;
gtk_tree_model_get (GTK_TREE_MODEL (cfm->yourcerts_streemodel),
&iter,
4, &cert,
-1);
if (cert
&& e_cert_db_delete_cert (e_cert_db_peek (), cert)) {
GtkTreeIter child_iter;
gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (cfm->yourcerts_streemodel),
&child_iter,
&iter);
gtk_tree_store_remove (GTK_TREE_STORE (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (cfm->yourcerts_streemodel))),
&child_iter);
/* we need two unrefs here, one to unref the
gtk_tree_model_get above, and one to unref
the initial ref when we created the cert
and added it to the tree */
g_object_unref (cert);
g_object_unref (cert);
}
}
}
static void
view_your (GtkWidget *widget, CertificateManagerData *cfm)
{
GtkTreeIter iter;
if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->yourcerts_treeview)),
NULL,
&iter)) {
ECert *cert;
gtk_tree_model_get (GTK_TREE_MODEL (cfm->yourcerts_streemodel),
&iter,
4, &cert,
-1);
if (cert) {
GtkWidget *dialog = certificate_viewer_show (cert);
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (dialog);
}
}
}
static void
backup_your (GtkWidget *widget, CertificateManagerData *cfm)
{
/* FIXME: implement */
}
static void
backup_all_your (GtkWidget *widget, CertificateManagerData *cfm)
{
/* FIXME: implement */
}
struct find_cert_data {
ECert *cert;
GtkTreePath *path;
gint cert_index;
};
static gboolean
find_cert_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
{
struct find_cert_data *fcd = data;
ECert *cert = NULL;
g_return_val_if_fail (model != NULL, TRUE);
g_return_val_if_fail (iter != NULL, TRUE);
g_return_val_if_fail (data != NULL, TRUE);
gtk_tree_model_get (model, iter, fcd->cert_index, &cert, -1);
if (cert && g_strcmp0 (e_cert_get_serial_number (cert), e_cert_get_serial_number (fcd->cert)) == 0
&& g_strcmp0 (e_cert_get_subject_name (cert), e_cert_get_subject_name (fcd->cert)) == 0
&& g_strcmp0 (e_cert_get_sha1_fingerprint (cert), e_cert_get_sha1_fingerprint (fcd->cert)) == 0
&& g_strcmp0 (e_cert_get_md5_fingerprint (cert), e_cert_get_md5_fingerprint (fcd->cert)) == 0) {
fcd->path = gtk_tree_path_copy (path);
}
return fcd->path != NULL;
}
static void
select_certificate (CertificateManagerData *cfm, GtkTreeView *treeview, ECert *cert)
{
GtkTreeModel *model;
GtkTreeSelection *selection;
struct find_cert_data fcd;
g_return_if_fail (treeview != NULL);
g_return_if_fail (GTK_IS_TREE_VIEW (treeview));
g_return_if_fail (cert != NULL);
g_return_if_fail (E_IS_CERT (cert));
model = gtk_tree_view_get_model (treeview);
g_return_if_fail (model != NULL);
fcd.cert = cert;
fcd.path = NULL;
fcd.cert_index = cfm->yourcerts_treeview == GTK_WIDGET (treeview) ? 4
: cfm->authoritycerts_treeview == GTK_WIDGET (treeview) ? 1
: 3;
gtk_tree_model_foreach (model, find_cert_cb, &fcd);
if (fcd.path) {
gtk_tree_view_expand_to_path (treeview, fcd.path);
selection = gtk_tree_view_get_selection (treeview);
gtk_tree_selection_select_path (selection, fcd.path);
gtk_tree_view_scroll_to_cell (treeview, fcd.path, NULL, FALSE, 0.0, 0.0);
gtk_tree_path_free (fcd.path);
}
}
static void
yourcerts_selection_changed (GtkTreeSelection *selection, CertificateManagerData *cfm)
{
handle_selection_changed (selection,
4,
cfm->view_your_button,
NULL,
cfm->delete_your_button);
}
static GtkTreeModel*
create_yourcerts_treemodel (void)
{
return GTK_TREE_MODEL (gtk_tree_store_new (5,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_OBJECT));
}
static void
initialize_yourcerts_ui (CertificateManagerData *cfm)
{
GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
GtkTreeSelection *selection;
GtkTreeViewColumn *column;
column = gtk_tree_view_column_new_with_attributes (_("Certificate Name"),
cell,
"text", 0,
NULL);
gtk_tree_view_column_set_resizable (column, TRUE);
gtk_tree_view_append_column (GTK_TREE_VIEW (cfm->yourcerts_treeview),
column);
gtk_tree_view_column_set_sort_column_id (column, 0);
column = gtk_tree_view_column_new_with_attributes (_("Purposes"),
cell,
"text", 1,
NULL);
gtk_tree_view_column_set_resizable (column, TRUE);
gtk_tree_view_append_column (GTK_TREE_VIEW (cfm->yourcerts_treeview),
column);
gtk_tree_view_column_set_sort_column_id (column, 1);
column = gtk_tree_view_column_new_with_attributes (_("Serial Number"),
cell,
"text", 2,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (cfm->yourcerts_treeview),
column);
gtk_tree_view_column_set_sort_column_id (column, 2);
column = gtk_tree_view_column_new_with_attributes (_("Expires"),
cell,
"text", 3,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (cfm->yourcerts_treeview),
column);
gtk_tree_view_column_set_sort_column_id (column, 3);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->yourcerts_treeview));
g_signal_connect (selection, "changed", G_CALLBACK (yourcerts_selection_changed), cfm);
if (cfm->import_your_button)
g_signal_connect (cfm->import_your_button, "clicked", G_CALLBACK (import_your), cfm);
if (cfm->delete_your_button)
g_signal_connect (cfm->delete_your_button, "clicked", G_CALLBACK (delete_your), cfm);
if (cfm->view_your_button)
g_signal_connect (cfm->view_your_button, "clicked", G_CALLBACK (view_your), cfm);
if (cfm->backup_your_button)
g_signal_connect (cfm->backup_your_button, "clicked", G_CALLBACK (backup_your), cfm);
if (cfm->backup_all_your_button)
g_signal_connect (cfm->backup_all_your_button, "clicked", G_CALLBACK (backup_all_your), cfm);
}
static void
view_contact (GtkWidget *widget, CertificateManagerData *cfm)
{
GtkTreeIter iter;
if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->contactcerts_treeview)),
NULL,
&iter)) {
ECert *cert;
gtk_tree_model_get (GTK_TREE_MODEL (cfm->contactcerts_streemodel),
&iter,
3, &cert,
-1);
if (cert) {
GtkWidget *dialog = certificate_viewer_show (cert);
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (dialog);
}
}
}
static void
edit_contact (GtkWidget *widget, CertificateManagerData *cfm)
{
GtkTreeIter iter;
if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->contactcerts_treeview)),
NULL,
&iter)) {
ECert *cert;
gtk_tree_model_get (GTK_TREE_MODEL (cfm->contactcerts_streemodel),
&iter,
3, &cert,
-1);
if (cert) {
GtkWidget *dialog = cert_trust_dialog_show (cert);
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (dialog);
}
}
}
static void
import_contact (GtkWidget *widget, CertificateManagerData *cfm)
{
GtkWidget *filesel;
GtkFileFilter *filter;
filesel = gtk_file_chooser_dialog_new (_("Select a certificate to import..."),
NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (filesel), GTK_RESPONSE_OK);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("All email certificate files"));
gtk_file_filter_add_mime_type (filter, "application/x-x509-email-cert");
gtk_file_filter_add_mime_type (filter, "application/x-x509-ca-cert");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (filesel), 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 (GTK_FILE_CHOOSER (filesel), filter);
if (GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (filesel))) {
gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filesel));
GError *error = NULL;
GSList *imported_certs = NULL;
/* destroy dialog to get rid of it in the GUI */
gtk_widget_destroy (filesel);
if (e_cert_db_import_certs_from_file (e_cert_db_peek (),
filename,
E_CERT_CONTACT,
&imported_certs,
&error)) {
/* there's no telling how many certificates were added during the import,
so we blow away the contact cert display and regenerate it. */
unload_certs (cfm, E_CERT_CONTACT);
load_certs (cfm, E_CERT_CONTACT, add_contact_cert);
gtk_tree_view_expand_all (GTK_TREE_VIEW (cfm->contactcerts_treeview));
if (imported_certs)
select_certificate (cfm, GTK_TREE_VIEW (cfm->contactcerts_treeview), imported_certs->data);
} else {
report_and_free_error (cfm, _("Failed to import contact's certificate"), error);
}
g_free (filename);
g_slist_foreach (imported_certs, (GFunc) g_object_unref, NULL);
g_slist_free (imported_certs);
} else
gtk_widget_destroy (filesel);
}
static void
delete_contact (GtkWidget *widget, CertificateManagerData *cfm)
{
GtkTreeIter iter;
if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->contactcerts_treeview)),
NULL,
&iter)) {
ECert *cert;
gtk_tree_model_get (GTK_TREE_MODEL (cfm->contactcerts_streemodel),
&iter,
3, &cert,
-1);
if (cert
&& e_cert_db_delete_cert (e_cert_db_peek (), cert)) {
GtkTreeIter child_iter;
gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (cfm->contactcerts_streemodel),
&child_iter,
&iter);
gtk_tree_store_remove (GTK_TREE_STORE (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (cfm->contactcerts_streemodel))),
&child_iter);
/* we need two unrefs here, one to unref the
gtk_tree_model_get above, and one to unref
the initial ref when we created the cert
and added it to the tree */
g_object_unref (cert);
g_object_unref (cert);
}
}
}
static void
contactcerts_selection_changed (GtkTreeSelection *selection, CertificateManagerData *cfm)
{
handle_selection_changed (selection,
3,
cfm->view_contact_button,
cfm->edit_contact_button,
cfm->delete_contact_button);
}
static GtkTreeModel*
create_contactcerts_treemodel (void)
{
return GTK_TREE_MODEL (gtk_tree_store_new (4,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_OBJECT));
}
static void
initialize_contactcerts_ui (CertificateManagerData *cfm)
{
GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
GtkTreeSelection *selection;
GtkTreeViewColumn *column;
column = gtk_tree_view_column_new_with_attributes (_("Certificate Name"),
cell,
"text", 0,
NULL);
gtk_tree_view_column_set_resizable (column, TRUE);
gtk_tree_view_append_column (GTK_TREE_VIEW (cfm->contactcerts_treeview),
column);
gtk_tree_view_column_set_sort_column_id (column, 0);
column = gtk_tree_view_column_new_with_attributes (_("E-Mail Address"),
cell,
"text", 1,
NULL);
gtk_tree_view_column_set_resizable (column, TRUE);
gtk_tree_view_append_column (GTK_TREE_VIEW (cfm->contactcerts_treeview),
column);
gtk_tree_view_column_set_sort_column_id (column, 1);
column = gtk_tree_view_column_new_with_attributes (_("Purposes"),
cell,
"text", 2,
NULL);
gtk_tree_view_column_set_resizable (column, TRUE);
gtk_tree_view_append_column (GTK_TREE_VIEW (cfm->contactcerts_treeview),
column);
gtk_tree_view_column_set_sort_column_id (column, 2);
cfm->contactcerts_root_hash = g_hash_table_new (g_str_hash, g_str_equal);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->contactcerts_treeview));
g_signal_connect (selection, "changed", G_CALLBACK (contactcerts_selection_changed), cfm);
if (cfm->view_contact_button)
g_signal_connect (cfm->view_contact_button, "clicked", G_CALLBACK (view_contact), cfm);
if (cfm->edit_contact_button)
g_signal_connect (cfm->edit_contact_button, "clicked", G_CALLBACK (edit_contact), cfm);
if (cfm->import_contact_button)
g_signal_connect (cfm->import_contact_button, "clicked", G_CALLBACK (import_contact), cfm);
if (cfm->delete_contact_button)
g_signal_connect (cfm->delete_contact_button, "clicked", G_CALLBACK (delete_contact), cfm);
}
static void
view_ca (GtkWidget *widget, CertificateManagerData *cfm)
{
GtkTreeIter iter;
if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->authoritycerts_treeview)),
NULL,
&iter)) {
ECert *cert;
gtk_tree_model_get (GTK_TREE_MODEL (cfm->authoritycerts_streemodel),
&iter,
1, &cert,
-1);
if (cert) {
GtkWidget *dialog = certificate_viewer_show (cert);
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (dialog);
}
}
}
static void
edit_ca (GtkWidget *widget, CertificateManagerData *cfm)
{
GtkTreeIter iter;
if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->authoritycerts_treeview)),
NULL,
&iter)) {
ECert *cert;
gtk_tree_model_get (GTK_TREE_MODEL (cfm->authoritycerts_streemodel),
&iter,
1, &cert,
-1);
if (cert) {
GtkWidget *dialog = ca_trust_dialog_show (cert, FALSE);
CERTCertificate *icert = e_cert_get_internal_cert (cert);
ca_trust_dialog_set_trust (dialog,
e_cert_trust_has_trusted_ca (icert->trust, TRUE, FALSE, FALSE),
e_cert_trust_has_trusted_ca (icert->trust, FALSE, TRUE, FALSE),
e_cert_trust_has_trusted_ca (icert->trust, FALSE, FALSE, TRUE));
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
gboolean trust_ssl, trust_email, trust_objsign;
CERTCertTrust trust;
ca_trust_dialog_get_trust (dialog,
&trust_ssl, &trust_email, &trust_objsign);
e_cert_trust_init (&trust);
e_cert_trust_set_valid_ca (&trust);
e_cert_trust_add_ca_trust (&trust,
trust_ssl,
trust_email,
trust_objsign);
e_cert_db_change_cert_trust (icert, &trust);
}
gtk_widget_destroy (dialog);
}
}
}
static void
import_ca (GtkWidget *widget, CertificateManagerData *cfm)
{
GtkWidget *filesel;
GtkFileFilter *filter;
filesel = gtk_file_chooser_dialog_new (_("Select a certificate to import..."),
NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (filesel), GTK_RESPONSE_OK);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("All CA certificate files"));
gtk_file_filter_add_mime_type (filter, "application/x-x509-ca-cert");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (filesel), 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 (GTK_FILE_CHOOSER (filesel), filter);
if (GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (filesel))) {
gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filesel));
GSList *imported_certs = NULL;
GError *error = NULL;
/* destroy dialog to get rid of it in the GUI */
gtk_widget_destroy (filesel);
if (e_cert_db_import_certs_from_file (e_cert_db_peek (),
filename,
E_CERT_CA,
&imported_certs,
&error)) {
/* there's no telling how many certificates were added during the import,
so we blow away the CA cert display and regenerate it. */
unload_certs (cfm, E_CERT_CA);
load_certs (cfm, E_CERT_CA, add_ca_cert);
if (imported_certs)
select_certificate (cfm, GTK_TREE_VIEW (cfm->authoritycerts_treeview), imported_certs->data);
} else {
report_and_free_error (cfm, _("Failed to import certificate authority's certificate"), error);
}
g_slist_foreach (imported_certs, (GFunc) g_object_unref, NULL);
g_slist_free (imported_certs);
g_free (filename);
} else
gtk_widget_destroy (filesel);
}
static void
delete_ca (GtkWidget *widget, CertificateManagerData *cfm)
{
GtkTreeIter iter;
if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->authoritycerts_treeview)),
NULL,
&iter)) {
ECert *cert;
gtk_tree_model_get (GTK_TREE_MODEL (cfm->authoritycerts_streemodel),
&iter,
1, &cert,
-1);
if (cert
&& e_cert_db_delete_cert (e_cert_db_peek (), cert)) {
GtkTreeIter child_iter;
gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (cfm->authoritycerts_streemodel),
&child_iter,
&iter);
gtk_tree_store_remove (GTK_TREE_STORE (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (cfm->authoritycerts_streemodel))),
&child_iter);
/* we need two unrefs here, one to unref the
gtk_tree_model_get above, and one to unref
the initial ref when we created the cert
and added it to the tree */
g_object_unref (cert);
g_object_unref (cert);
}
}
}
static void
authoritycerts_selection_changed (GtkTreeSelection *selection, CertificateManagerData *cfm)
{
handle_selection_changed (selection,
1,
cfm->view_ca_button,
cfm->edit_ca_button,
cfm->delete_ca_button);
}
static GtkTreeModel*
create_authoritycerts_treemodel (void)
{
return GTK_TREE_MODEL (gtk_tree_store_new (2,
G_TYPE_STRING,
G_TYPE_OBJECT));
}
static void
initialize_authoritycerts_ui (CertificateManagerData *cfm)
{
GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
GtkTreeSelection *selection;
GtkTreeViewColumn *column;
column = gtk_tree_view_column_new_with_attributes (_("Certificate Name"),
cell,
"text", 0,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (cfm->authoritycerts_treeview),
column);
gtk_tree_view_column_set_sort_column_id (column, 0);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cfm->authoritycerts_treeview));
g_signal_connect (selection, "changed", G_CALLBACK (authoritycerts_selection_changed), cfm);
if (cfm->view_ca_button)
g_signal_connect (cfm->view_ca_button, "clicked", G_CALLBACK (view_ca), cfm);
if (cfm->edit_ca_button)
g_signal_connect (cfm->edit_ca_button, "clicked", G_CALLBACK (edit_ca), cfm);
if (cfm->import_ca_button)
g_signal_connect (cfm->import_ca_button, "clicked", G_CALLBACK (import_ca), cfm);
if (cfm->delete_ca_button)
g_signal_connect (cfm->delete_ca_button, "clicked", G_CALLBACK (delete_ca), cfm);
}
static void
add_user_cert (CertificateManagerData *cfm, ECert *cert)
{
GtkTreeIter iter;
GtkTreeIter *parent_iter = NULL;
const gchar *organization = e_cert_get_org (cert);
GtkTreeModel *model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (cfm->yourcerts_streemodel));
if (organization) {
parent_iter = g_hash_table_lookup (cfm->yourcerts_root_hash, organization);
if (!parent_iter) {
/* create a new toplevel node */
gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
0, organization, -1);
/* now copy it off into parent_iter and insert it into
the hashtable */
parent_iter = gtk_tree_iter_copy (&iter);
g_hash_table_insert (cfm->yourcerts_root_hash, g_strdup (organization), parent_iter);
}
}
gtk_tree_store_append (GTK_TREE_STORE (model), &iter, parent_iter);
if (e_cert_get_cn (cert))
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
0, e_cert_get_cn (cert),
1, e_cert_get_usage (cert),
2, e_cert_get_serial_number (cert),
3, e_cert_get_expires_on (cert),
4, cert,
-1);
else
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
0, e_cert_get_nickname (cert),
1, e_cert_get_usage (cert),
2, e_cert_get_serial_number (cert),
3, e_cert_get_expires_on (cert),
4, cert,
-1);
}
static void
add_contact_cert (CertificateManagerData *cfm, ECert *cert)
{
GtkTreeIter iter;
GtkTreeIter *parent_iter = NULL;
const gchar *organization = e_cert_get_org (cert);
GtkTreeModel *model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (cfm->contactcerts_streemodel));
if (organization) {
parent_iter = g_hash_table_lookup (cfm->contactcerts_root_hash, organization);
if (!parent_iter) {
/* create a new toplevel node */
gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
0, organization, -1);
/* now copy it off into parent_iter and insert it into
the hashtable */
parent_iter = gtk_tree_iter_copy (&iter);
g_hash_table_insert (cfm->contactcerts_root_hash, g_strdup (organization), parent_iter);
}
}
gtk_tree_store_append (GTK_TREE_STORE (model), &iter, parent_iter);
if (e_cert_get_cn (cert))
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
0, e_cert_get_cn (cert),
1, e_cert_get_email (cert),
2, e_cert_get_usage (cert),
3, cert,
-1);
else
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
0, e_cert_get_nickname (cert),
1, e_cert_get_email (cert),
2, e_cert_get_usage (cert),
3, cert,
-1);
}
static void
add_ca_cert (CertificateManagerData *cfm, ECert *cert)
{
GtkTreeIter iter;
GtkTreeIter *parent_iter = NULL;
const gchar *organization = e_cert_get_org (cert);
GtkTreeModel *model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (cfm->authoritycerts_streemodel));
if (organization) {
parent_iter = g_hash_table_lookup (cfm->authoritycerts_root_hash, organization);
if (!parent_iter) {
/* create a new toplevel node */
gtk_tree_store_append (GTK_TREE_STORE (model),
&iter, NULL);
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
0, organization, -1);
/* now copy it off into parent_iter and insert it into
the hashtable */
parent_iter = gtk_tree_iter_copy (&iter);
g_hash_table_insert (cfm->authoritycerts_root_hash, g_strdup (organization), parent_iter);
}
}
gtk_tree_store_append (GTK_TREE_STORE (model), &iter, parent_iter);
if (e_cert_get_cn (cert))
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
0, e_cert_get_cn (cert),
1, cert,
-1);
else
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
0, e_cert_get_nickname (cert),
1, cert,
-1);
}
static void
destroy_key (gpointer data)
{
g_free (data);
}
static void
destroy_value (gpointer data)
{
gtk_tree_iter_free (data);
}
static void
unload_certs (CertificateManagerData *cfm,
ECertType type)
{
GtkTreeModel *treemodel;
switch (type) {
case E_CERT_USER:
treemodel = create_yourcerts_treemodel ();
cfm->yourcerts_streemodel = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (treemodel));
g_object_unref (treemodel);
gtk_tree_view_set_model (GTK_TREE_VIEW (cfm->yourcerts_treeview),
cfm->yourcerts_streemodel);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (cfm->yourcerts_streemodel),
0,
GTK_SORT_ASCENDING);
if (cfm->yourcerts_root_hash)
g_hash_table_destroy (cfm->yourcerts_root_hash);
cfm->yourcerts_root_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
destroy_key, destroy_value);
break;
case E_CERT_CONTACT:
treemodel = create_contactcerts_treemodel ();
cfm->contactcerts_streemodel = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (treemodel));
g_object_unref (treemodel);
gtk_tree_view_set_model (GTK_TREE_VIEW (cfm->contactcerts_treeview),
cfm->contactcerts_streemodel);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (cfm->contactcerts_streemodel),
0,
GTK_SORT_ASCENDING);
if (cfm->contactcerts_root_hash)
g_hash_table_destroy (cfm->contactcerts_root_hash);
cfm->contactcerts_root_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
destroy_key, destroy_value);
break;
case E_CERT_SITE:
break;
case E_CERT_CA:
treemodel = create_authoritycerts_treemodel ();
cfm->authoritycerts_streemodel = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (treemodel));
g_object_unref (treemodel);
gtk_tree_view_set_model (GTK_TREE_VIEW (cfm->authoritycerts_treeview),
cfm->authoritycerts_streemodel);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (cfm->authoritycerts_streemodel),
0,
GTK_SORT_ASCENDING);
if (cfm->authoritycerts_root_hash)
g_hash_table_destroy (cfm->authoritycerts_root_hash);
cfm->authoritycerts_root_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
destroy_key, destroy_value);
break;
case E_CERT_UNKNOWN:
/* nothing to do here */
break;
}
}
static void
load_certs (CertificateManagerData *cfm,
ECertType type,
AddCertCb add_cert)
{
CERTCertList *certList;
CERTCertListNode *node;
certList = PK11_ListCerts (PK11CertListUnique, NULL);
for (node = CERT_LIST_HEAD (certList);
!CERT_LIST_END (node, certList);
node = CERT_LIST_NEXT (node)) {
ECert *cert = e_cert_new (CERT_DupCertificate ((CERTCertificate*) node->cert));
ECertType ct = e_cert_get_cert_type (cert);
/* show everything else in a contact tab */
if (ct == type || (type == E_CERT_CONTACT && ct != E_CERT_CA && ct != E_CERT_USER)) {
add_cert (cfm, cert);
} else {
g_object_unref (cert);
}
}
CERT_DestroyCertList (certList);
}
static gboolean
populate_ui (CertificateManagerData *cfm)
{
/* This is an idle callback. */
unload_certs (cfm, E_CERT_USER);
load_certs (cfm, E_CERT_USER, add_user_cert);
unload_certs (cfm, E_CERT_CONTACT);
load_certs (cfm, E_CERT_CONTACT, add_contact_cert);
unload_certs (cfm, E_CERT_CA);
load_certs (cfm, E_CERT_CA, add_ca_cert);
/* expand all three trees */
gtk_tree_view_expand_all (GTK_TREE_VIEW (cfm->yourcerts_treeview));
gtk_tree_view_expand_all (GTK_TREE_VIEW (cfm->contactcerts_treeview));
return FALSE;
}
GtkWidget *
certificate_manager_config_new (EPreferencesWindow *window)
{
EShell *shell;
GtkWidget *parent;
GtkWidget *widget;
CertificateManagerData *cfm_data;
shell = e_preferences_window_get_shell (window);
g_return_val_if_fail (E_IS_SHELL (shell), NULL);
/* We need to peek the db here to make sure it (and NSS) are fully initialized. */
e_cert_db_peek ();
cfm_data = g_new0 (CertificateManagerData, 1);
cfm_data->builder = gtk_builder_new ();
e_load_ui_builder_definition (cfm_data->builder, "smime-ui.ui");
cfm_data->yourcerts_treeview = e_builder_get_widget (cfm_data->builder, "yourcerts-treeview");
cfm_data->contactcerts_treeview = e_builder_get_widget (cfm_data->builder, "contactcerts-treeview");
cfm_data->authoritycerts_treeview = e_builder_get_widget (cfm_data->builder, "authoritycerts-treeview");
cfm_data->view_your_button = e_builder_get_widget (cfm_data->builder, "your-view-button");
cfm_data->backup_your_button = e_builder_get_widget (cfm_data->builder, "your-backup-button");
cfm_data->backup_all_your_button = e_builder_get_widget (cfm_data->builder, "your-backup-all-button");
cfm_data->import_your_button = e_builder_get_widget (cfm_data->builder, "your-import-button");
cfm_data->delete_your_button = e_builder_get_widget (cfm_data->builder, "your-delete-button");
cfm_data->view_contact_button = e_builder_get_widget (cfm_data->builder, "contact-view-button");
cfm_data->edit_contact_button = e_builder_get_widget (cfm_data->builder, "contact-edit-button");
cfm_data->import_contact_button = e_builder_get_widget (cfm_data->builder, "contact-import-button");
cfm_data->delete_contact_button = e_builder_get_widget (cfm_data->builder, "contact-delete-button");
cfm_data->view_ca_button = e_builder_get_widget (cfm_data->builder, "authority-view-button");
cfm_data->edit_ca_button = e_builder_get_widget (cfm_data->builder, "authority-edit-button");
cfm_data->import_ca_button = e_builder_get_widget (cfm_data->builder, "authority-import-button");
cfm_data->delete_ca_button = e_builder_get_widget (cfm_data->builder, "authority-delete-button");
initialize_yourcerts_ui (cfm_data);
initialize_contactcerts_ui (cfm_data);
initialize_authoritycerts_ui (cfm_data);
/* Run this in an idle callback so Evolution has a chance to
* fully initialize itself and start its main loop before we
* load certificates, since doing so may trigger a password
* dialog, and dialogs require a main loop. */
g_idle_add ((GSourceFunc) populate_ui, cfm_data);
widget = e_builder_get_widget (cfm_data->builder, "cert-manager-notebook");
g_object_ref (widget);
parent = gtk_widget_get_parent (widget);
gtk_container_remove (GTK_CONTAINER (parent), widget);
/* FIXME: remove when implemented */
gtk_widget_set_sensitive (cfm_data->backup_your_button, FALSE);
gtk_widget_set_sensitive (cfm_data->backup_all_your_button, FALSE);
return widget;
}