evolution-3.6.4/smime/gui/certificate-manager.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found certificate-manager.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
clang-analyzer no-output-found certificate-manager.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
   1 /*
   2  *
   3  * This program is free software; you can redistribute it and/or
   4  * modify it under the terms of the GNU Lesser General Public
   5  * License as published by the Free Software Foundation; either
   6  * version 2 of the License, or (at your option) version 3.
   7  *
   8  * This program is distributed in the hope that it will be useful,
   9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11  * Lesser General Public License for more details.
  12  *
  13  * You should have received a copy of the GNU Lesser General Public
  14  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  15  *
  16  *
  17  * Authors:
  18  *		Chris Toshok <toshok@ximian.com>
  19  *
  20  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  21  *
  22  */
  23 
  24 #ifdef HAVE_CONFIG_H
  25 #include <config.h>
  26 #endif
  27 
  28 #include <gtk/gtk.h>
  29 
  30 #include <glib/gi18n.h>
  31 
  32 #include "ca-trust-dialog.h"
  33 #include "cert-trust-dialog.h"
  34 #include "certificate-manager.h"
  35 #include "certificate-viewer.h"
  36 
  37 #include "e-cert.h"
  38 #include "e-cert-trust.h"
  39 #include "e-cert-db.h"
  40 
  41 #include "nss.h"
  42 #include <cms.h>
  43 #include <cert.h>
  44 #include <certdb.h>
  45 #include <pkcs11.h>
  46 #include <pk11func.h>
  47 
  48 #include "shell/e-shell.h"
  49 #include "e-util/e-dialog-utils.h"
  50 #include "e-util/e-util.h"
  51 #include "e-util/e-util-private.h"
  52 #include "widgets/misc/e-preferences-window.h"
  53 
  54 #define E_CERT_MANAGER_CONFIG_GET_PRIVATE(obj) \
  55 	(G_TYPE_INSTANCE_GET_PRIVATE \
  56 	((obj), E_TYPE_CERT_MANAGER_CONFIG, ECertManagerConfigPrivate))
  57 
  58 G_DEFINE_TYPE (ECertManagerConfig, e_cert_manager_config, GTK_TYPE_BOX);
  59 
  60 enum {
  61 	PROP_0,
  62 	PROP_PREFERENCES_WINDOW
  63 };
  64 
  65 #define ECMC_TREE_VIEW(o) ecmc->priv->o->treeview
  66 #define PAGE_TREE_VIEW(o) o->treeview
  67 
  68 typedef struct {
  69 	GType type;
  70 	const gchar *column_title;
  71 	const gchar * (*get_cert_data_func) (ECert *cert);  /* Prototype to e_cert_get_ * functions */
  72 	gboolean visible;				   /* Default visibility of column */
  73 } CertTreeColumn;
  74 
  75 static CertTreeColumn yourcerts_columns[] = {
  76 
  77 	{ G_TYPE_STRING, N_("Certificate Name"),		e_cert_get_cn,			TRUE },
  78 	{ G_TYPE_STRING, N_("Issued To Organization"),		e_cert_get_org,			FALSE },
  79 	{ G_TYPE_STRING, N_("Issued To Organizational Unit"),	e_cert_get_org_unit,		FALSE },
  80 	{ G_TYPE_STRING, N_("Serial Number"),			e_cert_get_serial_number,	TRUE },
  81 	{ G_TYPE_STRING, N_("Purposes"),			e_cert_get_usage,		TRUE },
  82 	{ G_TYPE_STRING, N_("Issued By"),			e_cert_get_issuer_cn,		TRUE },
  83 	{ G_TYPE_STRING, N_("Issued By Organization"),		e_cert_get_issuer_org,		FALSE },
  84 	{ G_TYPE_STRING, N_("Issued By Organizational Unit"),	e_cert_get_issuer_org_unit,	FALSE },
  85 	{ G_TYPE_STRING, N_("Issued"),				e_cert_get_issued_on,		FALSE },
  86 	{ G_TYPE_STRING, N_("Expires"),				e_cert_get_expires_on,		TRUE },
  87 	{ G_TYPE_STRING, N_("SHA1 Fingerprint"),		e_cert_get_sha1_fingerprint,	FALSE },
  88 	{ G_TYPE_STRING, N_("MD5 Fingerprint"),			e_cert_get_md5_fingerprint,	FALSE },
  89 	{ G_TYPE_OBJECT, NULL,					NULL,				FALSE } /* Hidden column for ECert * object */
  90 
  91 };
  92 static const gchar * yourcerts_mime_types[] = { "application/x-x509-user-cert", "application/x-pkcs12", NULL };
  93 
  94 static CertTreeColumn contactcerts_columns[] = {
  95 
  96 	{ G_TYPE_STRING, N_("Certificate Name"),		e_cert_get_cn,			TRUE },
  97 	{ G_TYPE_STRING, N_("Email Address"),			e_cert_get_email,		TRUE },
  98 	{ G_TYPE_STRING, N_("Issued To Organization"),		e_cert_get_org,			FALSE },
  99 	{ G_TYPE_STRING, N_("Issued To Organizational Unit"),	e_cert_get_org_unit,		FALSE },
 100 	{ G_TYPE_STRING, N_("Serial Number"),			e_cert_get_serial_number,	TRUE },
 101 	{ G_TYPE_STRING, N_("Purposes"),			e_cert_get_usage,		TRUE },
 102 	{ G_TYPE_STRING, N_("Issued By"),			e_cert_get_issuer_cn,		TRUE },
 103 	{ G_TYPE_STRING, N_("Issued By Organization"),		e_cert_get_issuer_org,		FALSE },
 104 	{ G_TYPE_STRING, N_("Issued By Organizational Unit"),	e_cert_get_issuer_org_unit,	FALSE },
 105 	{ G_TYPE_STRING, N_("Issued"),				e_cert_get_issued_on,		FALSE },
 106 	{ G_TYPE_STRING, N_("Expires"),				e_cert_get_expires_on,		TRUE },
 107 	{ G_TYPE_STRING, N_("SHA1 Fingerprint"),		e_cert_get_sha1_fingerprint,	FALSE },
 108 	{ G_TYPE_STRING, N_("MD5 Fingerprint"),			e_cert_get_md5_fingerprint,	FALSE },
 109 	{ G_TYPE_OBJECT, NULL,					NULL,				FALSE }
 110 
 111 };
 112 static const gchar * contactcerts_mime_types[] = { "application/x-x509-email-cert", "application/x-x509-ca-cert", NULL };
 113 
 114 static CertTreeColumn authoritycerts_columns[] = {
 115 
 116 	{ G_TYPE_STRING, N_("Certificate Name"),		e_cert_get_cn,			TRUE },
 117 	{ G_TYPE_STRING, N_("Email Address"),			e_cert_get_email,		TRUE },
 118 	{ G_TYPE_STRING, N_("Serial Number"),			e_cert_get_serial_number,	TRUE },
 119 	{ G_TYPE_STRING, N_("Purposes"),			e_cert_get_usage,		TRUE },
 120 	{ G_TYPE_STRING, N_("Issued By"),			e_cert_get_issuer_cn,		FALSE },
 121 	{ G_TYPE_STRING, N_("Issued By Organization"),		e_cert_get_issuer_org,		FALSE },
 122 	{ G_TYPE_STRING, N_("Issued By Organizational Unit"),	e_cert_get_issuer_org_unit,	FALSE },
 123 	{ G_TYPE_STRING, N_("Issued"),				e_cert_get_issued_on,		FALSE },
 124 	{ G_TYPE_STRING, N_("Expires"),				e_cert_get_expires_on,		TRUE },
 125 	{ G_TYPE_STRING, N_("SHA1 Fingerprint"),		e_cert_get_sha1_fingerprint,	FALSE },
 126 	{ G_TYPE_STRING, N_("MD5 Fingerprint"),			e_cert_get_md5_fingerprint,	FALSE },
 127 	{ G_TYPE_OBJECT, NULL,					NULL,				FALSE }
 128 
 129 };
 130 static const gchar * authoritycerts_mime_types[] =  { "application/x-x509-ca-cert", NULL };
 131 
 132 typedef struct {
 133 	GtkTreeView *treeview;
 134 	GtkTreeModel *streemodel;
 135 	GHashTable *root_hash;
 136 	GtkMenu *popup_menu;
 137 	GtkWidget *view_button;
 138 	GtkWidget *edit_button;
 139 	GtkWidget *backup_button;
 140 	GtkWidget *backup_all_button;
 141 	GtkWidget *import_button;
 142 	GtkWidget *delete_button;
 143 
 144 	CertTreeColumn *columns;
 145 	gint columns_count;
 146 
 147 	ECertType cert_type;
 148 	const gchar *cert_filter_name;
 149 	const gchar **cert_mime_types;
 150 } CertPage;
 151 
 152 struct _ECertManagerConfigPrivate {
 153 	GtkBuilder *builder;
 154 
 155 	EPreferencesWindow *pref_window;
 156 
 157 	CertPage *yourcerts_page;
 158 	CertPage *contactcerts_page;
 159 	CertPage *authoritycerts_page;
 160 };
 161 
 162 static void view_cert (GtkWidget *button, CertPage *cp);
 163 static void edit_cert (GtkWidget *button, CertPage *cp);
 164 static void delete_cert (GtkWidget *button, CertPage *cp);
 165 static void import_cert (GtkWidget *button, CertPage *cp);
 166 
 167 static void load_certs (CertPage *cp);
 168 static void unload_certs (CertPage *cp);
 169 
 170 static void
 171 save_treeview_state (GtkTreeView *treeview)
 172 {
 173 	GKeyFile *keyfile;
 174 	GtkTreeModel *model;
 175 	GtkTreeSortable *sortable;
 176 	GtkSortType sort_type;
 177 	gint columns_count;
 178 	gint i = 0;
 179 	gint *list;
 180 	gchar *cfg_file, *data;
 181 	const gchar *tree_name;
 182 
 183 	g_return_if_fail (treeview && GTK_IS_TREE_VIEW (treeview));
 184 
 185 	model = gtk_tree_view_get_model (treeview);
 186 	g_return_if_fail (model && GTK_IS_TREE_MODEL_SORT (model));
 187 
 188 	keyfile = g_key_file_new ();
 189 	cfg_file = g_build_filename (e_get_user_config_dir (), "cert_trees.ini", NULL);
 190 	g_key_file_load_from_file (keyfile, cfg_file, 0, NULL);
 191 
 192 	tree_name = gtk_widget_get_name (GTK_WIDGET (treeview));
 193 	sortable = GTK_TREE_SORTABLE (model);
 194 
 195 	columns_count = gtk_tree_model_get_n_columns (model) - 1; /* Ignore the last column - the ECert * holder */
 196 	list = g_new0 (gint, columns_count);
 197 
 198 	for (i = 0; i < columns_count; i++) {
 199 		GtkTreeViewColumn *column = gtk_tree_view_get_column (treeview, i);
 200 		if (gtk_tree_view_column_get_visible (column)) {
 201 			list[gtk_tree_view_column_get_sort_column_id (column)] = gtk_tree_view_column_get_width (column);
 202 		} else {
 203 			list[gtk_tree_view_column_get_sort_column_id (column)] = 0;
 204 		}
 205 	}
 206 	g_key_file_set_integer_list (keyfile, tree_name, "columns", list, columns_count);
 207 	g_free (list);
 208 
 209 	list = g_new0 (gint, columns_count);
 210 	for (i = 0; i < columns_count; i++) {
 211 		GtkTreeViewColumn *column = gtk_tree_view_get_column (treeview, i);
 212 		list[i] = gtk_tree_view_column_get_sort_column_id (column);
 213 	}
 214 	g_key_file_set_integer_list (keyfile, tree_name, "columns-order", list, columns_count);
 215 	g_free (list);
 216 
 217 	gtk_tree_sortable_get_sort_column_id (sortable, &i, &sort_type);
 218 	g_key_file_set_integer (keyfile, tree_name, "sort-column", i);
 219 
 220 	g_key_file_set_integer (keyfile, tree_name, "sort-order", sort_type);
 221 
 222 	data = g_key_file_to_data (keyfile, NULL, NULL);
 223 	g_file_set_contents (cfg_file, data, -1,  NULL);
 224 
 225 	g_free (data);
 226 	g_free (cfg_file);
 227 	g_key_file_free (keyfile);
 228 }
 229 
 230 static void
 231 load_treeview_state (GtkTreeView *treeview)
 232 {
 233 	GKeyFile *keyfile;
 234 	gint i, *list;
 235 	gsize length;
 236 	GtkTreeSortable *sortable;
 237 	GtkTreeModel *model;
 238 	gchar *cfg_file;
 239 	const gchar *tree_name;
 240 
 241 	g_return_if_fail (treeview && GTK_IS_TREE_VIEW (treeview));
 242 
 243 	keyfile = g_key_file_new ();
 244 	cfg_file = g_build_filename (e_get_user_config_dir (), "cert_trees.ini", NULL);
 245 
 246 	if (!g_key_file_load_from_file (keyfile, cfg_file, 0, NULL)) {
 247 		g_key_file_free (keyfile);
 248 		g_free (cfg_file);
 249 		return;
 250 	}
 251 
 252 	model = GTK_TREE_MODEL (gtk_tree_view_get_model (treeview));
 253 	tree_name = gtk_widget_get_name (GTK_WIDGET (treeview));
 254 	list = g_key_file_get_integer_list (keyfile, tree_name,	"columns", &length, NULL);
 255 
 256 	if (list) {
 257 		gboolean all_hidden = TRUE;
 258 
 259 		if (length != (gtk_tree_model_get_n_columns (model) - 1)) {
 260 			g_debug ("%s: Unexpected number of columns in config file", G_STRFUNC);
 261 			g_free (list);
 262 			goto exit;
 263 		}
 264 
 265 		for (i = 0; all_hidden && i < length; i++) {
 266 			all_hidden = list[i] == 0;
 267 		}
 268 
 269 		for (i = 0; !all_hidden && i < length; i++) {
 270 			GtkTreeViewColumn *column = gtk_tree_view_get_column (treeview, i);
 271 			if (list[i]) {
 272 				gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
 273 				gtk_tree_view_column_set_fixed_width (column, list[i]);
 274 				gtk_tree_view_column_set_visible (column, TRUE);
 275 			} else {
 276 				gtk_tree_view_column_set_visible (column, FALSE);
 277 			}
 278 		}
 279 		g_free (list);
 280 	}
 281 
 282 	list = g_key_file_get_integer_list (keyfile, tree_name, "columns-order", &length, NULL);
 283 
 284 	if (list) {
 285 		GList *columns = gtk_tree_view_get_columns (treeview);
 286 
 287 		if (length != g_list_length (columns)) {
 288 			g_debug ("%s: Unexpected number of columns in config file", G_STRFUNC);
 289 			g_free (list);
 290 			goto exit;
 291 		}
 292 
 293 		for (i = (length - 1); i >= 0; i--) {
 294 			if ((list[i] >= 0) && (list[i] < length)) {
 295 				GtkTreeViewColumn *column = g_list_nth (columns, list[i])->data;
 296 				gtk_tree_view_move_column_after (treeview, column, NULL);
 297 			} else {
 298 				g_warning ("%s: Invalid column number", G_STRFUNC);
 299 			}
 300 		}
 301 		g_free (list);
 302 		g_list_free (columns);
 303 	}
 304 
 305 	sortable = GTK_TREE_SORTABLE (gtk_tree_view_get_model (treeview));
 306 	gtk_tree_sortable_set_sort_column_id (
 307 		sortable,
 308 		g_key_file_get_integer (keyfile, tree_name, "sort-column", 0),
 309 		g_key_file_get_integer (keyfile, tree_name, "sort-order", GTK_SORT_ASCENDING));
 310 
 311  exit:
 312 	g_free (cfg_file);
 313 	g_key_file_free (keyfile);
 314 }
 315 
 316 static void
 317 report_and_free_error (CertPage *cp,
 318                        const gchar *where,
 319                        GError *error)
 320 {
 321 	g_return_if_fail (cp != NULL);
 322 
 323 	e_notice (
 324 		gtk_widget_get_toplevel (GTK_WIDGET (cp->treeview)),
 325 		GTK_MESSAGE_ERROR, "%s: %s", where,
 326 		error ? error->message : _("Unknown error"));
 327 
 328 	if (error)
 329 		g_error_free (error);
 330 }
 331 
 332 static gboolean
 333 treeview_header_clicked (GtkWidget *widget,
 334                          GdkEventButton *event,
 335                          gpointer user_data)
 336 {
 337 	GtkMenu *menu = user_data;
 338 
 339 	if (event->button != 3)
 340 		return FALSE;
 341 
 342 	gtk_widget_show_all (GTK_WIDGET (menu));
 343 	gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event->button, event->time);
 344 
 345 	return TRUE;
 346 }
 347 
 348 static void
 349 header_popup_item_toggled (GtkCheckMenuItem *item,
 350                            gpointer user_data)
 351 {
 352 	GtkTreeViewColumn *column = user_data;
 353 
 354 	gtk_tree_view_column_set_visible (
 355 		column,
 356 		gtk_check_menu_item_get_active (item));
 357 }
 358 
 359 static void
 360 treeview_column_visibility_changed (GtkTreeViewColumn *column,
 361                                     GParamSpec *pspec,
 362                                     gpointer user_data)
 363 {
 364 	GtkCheckMenuItem *menu_item = user_data;
 365 
 366 	gtk_check_menu_item_set_active (
 367 		menu_item,
 368 		gtk_tree_view_column_get_visible (column));
 369 
 370 }
 371 
 372 static void
 373 treeview_selection_changed (GtkTreeSelection *selection,
 374                             CertPage *cp)
 375 {
 376 	GtkTreeIter iter;
 377 	gboolean cert_selected = FALSE;
 378 	GtkTreeModel *model;
 379 
 380 	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
 381 		ECert *cert;
 382 
 383 		gtk_tree_model_get (
 384 			model, &iter,
 385 			cp->columns_count - 1, &cert,
 386 			-1);
 387 
 388 		if (cert) {
 389 			cert_selected = TRUE;
 390 			g_object_unref (cert);
 391 		}
 392 	}
 393 
 394 	if (cp->delete_button)
 395 		gtk_widget_set_sensitive (cp->delete_button, cert_selected);
 396 	if (cp->edit_button)
 397 		gtk_widget_set_sensitive (cp->edit_button, cert_selected);
 398 	if (cp->view_button)
 399 		gtk_widget_set_sensitive (cp->view_button, cert_selected);
 400 }
 401 
 402 static void
 403 treeview_add_column (CertPage *cp,
 404                      gint column_index)
 405 {
 406 	GtkCellRenderer *cell;
 407 	GtkTreeViewColumn *column;
 408 	GtkWidget *header, *item;
 409 
 410 	if (cp->columns[column_index].type != G_TYPE_STRING)
 411 		return;
 412 
 413 	cell = gtk_cell_renderer_text_new ();
 414 	g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
 415 	column = gtk_tree_view_column_new_with_attributes (
 416 		gettext (cp->columns[column_index].column_title),
 417 		cell, "text", column_index, NULL);
 418 	gtk_tree_view_column_set_resizable (column, TRUE);
 419 	gtk_tree_view_column_set_reorderable (column, TRUE);
 420 	gtk_tree_view_column_set_sort_column_id (column, column_index);
 421 	gtk_tree_view_column_set_visible (column, cp->columns[column_index].visible);
 422 	gtk_tree_view_append_column (cp->treeview, column);
 423 
 424 	header = gtk_tree_view_column_get_button (column);
 425 	g_signal_connect (
 426 		header, "button-release-event",
 427 		G_CALLBACK (treeview_header_clicked), cp->popup_menu);
 428 
 429 	/* The first column should not be concealable so there's no point in displaying
 430 	 * it in the popup menu */
 431 	if (column_index == 0)
 432 		return;
 433 
 434 	/* Add item to header popup */
 435 	item = gtk_check_menu_item_new_with_label (
 436 		gettext (cp->columns[column_index].column_title));
 437 	gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), cp->columns[column_index].visible);
 438 	gtk_menu_attach (cp->popup_menu, item, 0, 1, column_index - 1, column_index);
 439 	g_signal_connect (
 440 		item, "toggled",
 441 		G_CALLBACK (header_popup_item_toggled), column);
 442 	g_signal_connect (
 443 		column, "notify::visible",
 444 		G_CALLBACK (treeview_column_visibility_changed), item);
 445 }
 446 
 447 struct find_cert_data {
 448 	ECert *cert;
 449 	GtkTreePath *path;
 450 	CertPage *cp;
 451 };
 452 
 453 static gboolean
 454 find_cert_cb (GtkTreeModel *model,
 455               GtkTreePath *path,
 456               GtkTreeIter *iter,
 457               gpointer data)
 458 {
 459 	struct find_cert_data *fcd = data;
 460 	ECert *cert = NULL;
 461 
 462 	g_return_val_if_fail (model != NULL, TRUE);
 463 	g_return_val_if_fail (iter != NULL, TRUE);
 464 	g_return_val_if_fail (data != NULL, TRUE);
 465 
 466 	/* Get the certificate object from model */
 467 	gtk_tree_model_get (model, iter, (fcd->cp->columns_count - 1), &cert, -1);
 468 
 469 	if (cert && g_strcmp0 (e_cert_get_serial_number (cert), e_cert_get_serial_number (fcd->cert)) == 0
 470 	    && g_strcmp0 (e_cert_get_subject_name (cert), e_cert_get_subject_name (fcd->cert)) == 0
 471 	    && g_strcmp0 (e_cert_get_sha1_fingerprint (cert), e_cert_get_sha1_fingerprint (fcd->cert)) == 0
 472 	    && g_strcmp0 (e_cert_get_md5_fingerprint (cert), e_cert_get_md5_fingerprint (fcd->cert)) == 0) {
 473 		fcd->path = gtk_tree_path_copy (path);
 474 	}
 475 
 476 	if (cert)
 477 		g_object_unref (cert);
 478 
 479 	return fcd->path != NULL;
 480 }
 481 
 482 static void
 483 select_certificate (CertPage *cp,
 484                     ECert *cert)
 485 {
 486 	GtkTreeModel *model;
 487 	GtkTreeSelection *selection;
 488 	struct find_cert_data fcd;
 489 
 490 	g_return_if_fail (cp != NULL);
 491 	g_return_if_fail (cert != NULL);
 492 	g_return_if_fail (E_IS_CERT (cert));
 493 
 494 	model = gtk_tree_view_get_model (cp->treeview);
 495 	g_return_if_fail (model != NULL);
 496 
 497 	fcd.cp = cp;
 498 	fcd.cert = cert;
 499 	fcd.path = NULL;
 500 
 501 	gtk_tree_model_foreach (model, find_cert_cb, &fcd);
 502 
 503 	if (fcd.path) {
 504 		gtk_tree_view_expand_to_path (cp->treeview, fcd.path);
 505 
 506 		selection = gtk_tree_view_get_selection (cp->treeview);
 507 		gtk_tree_selection_select_path (selection, fcd.path);
 508 
 509 		gtk_tree_view_scroll_to_cell (cp->treeview, fcd.path, NULL, TRUE, 0.5, 0.5);
 510 		gtk_tree_path_free (fcd.path);
 511 	}
 512 }
 513 
 514 static void
 515 view_cert (GtkWidget *button,
 516            CertPage *cp)
 517 {
 518 	GtkTreeIter iter;
 519 
 520 	if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (cp->treeview), NULL, &iter)) {
 521 		ECert *cert;
 522 
 523 		gtk_tree_model_get (
 524 			GTK_TREE_MODEL (cp->streemodel), &iter,
 525 			cp->columns_count - 1, &cert,
 526 			-1);
 527 
 528 		if (cert) {
 529 			GtkWidget *dialog = certificate_viewer_show (cert);
 530 			g_signal_connect (
 531 				dialog, "response",
 532 				G_CALLBACK (gtk_widget_destroy), NULL);
 533 			gtk_widget_show (dialog);
 534 			g_object_unref (cert);
 535 		}
 536 	}
 537 }
 538 
 539 static void
 540 edit_cert (GtkWidget *button,
 541            CertPage *cp)
 542 {
 543 	GtkTreeIter iter;
 544 
 545 	if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (cp->treeview), NULL, &iter)) {
 546 		ECert *cert;
 547 
 548 		gtk_tree_model_get (
 549 			GTK_TREE_MODEL (cp->streemodel), &iter,
 550 			cp->columns_count - 1, &cert,
 551 			-1);
 552 
 553 		if (cert) {
 554 			GtkWidget *dialog;
 555 			CERTCertificate *icert = e_cert_get_internal_cert (cert);
 556 
 557 			switch (cp->cert_type) {
 558 				case E_CERT_CA:
 559 					dialog = ca_trust_dialog_show (cert, FALSE);
 560 					ca_trust_dialog_set_trust (
 561 						dialog,
 562 						e_cert_trust_has_trusted_ca (icert->trust, TRUE,  FALSE, FALSE),
 563 						e_cert_trust_has_trusted_ca (icert->trust, FALSE, TRUE,  FALSE),
 564 						e_cert_trust_has_trusted_ca (icert->trust, FALSE, FALSE, TRUE));
 565 					break;
 566 				case E_CERT_CONTACT:
 567 					dialog = cert_trust_dialog_show (cert);
 568 					break;
 569 				default:
 570 					/* Other cert types cannot be edited */
 571 					return;
 572 			}
 573 
 574 			if ((gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) &&
 575 			    (cp->cert_type == E_CERT_CA)) {
 576 				gboolean trust_ssl, trust_email, trust_objsign;
 577 				CERTCertTrust trust;
 578 
 579 				ca_trust_dialog_get_trust (
 580 					dialog,
 581 					&trust_ssl, &trust_email, &trust_objsign);
 582 
 583 				e_cert_trust_init (&trust);
 584 				e_cert_trust_set_valid_ca (&trust);
 585 				e_cert_trust_add_ca_trust (
 586 					&trust,
 587 					trust_ssl, trust_email, trust_objsign);
 588 
 589 				e_cert_db_change_cert_trust (icert, &trust);
 590 			}
 591 
 592 			gtk_widget_destroy (dialog);
 593 			g_object_unref (cert);
 594 		}
 595 	}
 596 }
 597 
 598 static void
 599 import_cert (GtkWidget *button,
 600              CertPage *cp)
 601 {
 602 	GtkWidget *filesel;
 603 	GtkFileFilter *filter;
 604 	gint i;
 605 
 606 	filesel = gtk_file_chooser_dialog_new (
 607 		_("Select a certificate to import..."), NULL,
 608 		GTK_FILE_CHOOSER_ACTION_OPEN,
 609 		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 610 		GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
 611 	gtk_dialog_set_default_response (GTK_DIALOG (filesel), GTK_RESPONSE_OK);
 612 
 613 	filter = gtk_file_filter_new ();
 614 	gtk_file_filter_set_name (filter, cp->cert_filter_name);
 615 	for (i = 0; cp->cert_mime_types[i] != NULL; i++) {
 616 		gtk_file_filter_add_mime_type (filter, cp->cert_mime_types[i]);
 617 	}
 618 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (filesel), filter);
 619 
 620 	filter = gtk_file_filter_new ();
 621 	gtk_file_filter_set_name (filter, _("All files"));
 622 	gtk_file_filter_add_pattern (filter, "*");
 623 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (filesel), filter);
 624 
 625 	if (gtk_dialog_run (GTK_DIALOG (filesel)) == GTK_RESPONSE_OK) {
 626 		gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filesel));
 627 		GSList *imported_certs = NULL;
 628 		GError *error = NULL;
 629 		gboolean import;
 630 
 631 		/* destroy dialog to get rid of it in the GUI */
 632 		gtk_widget_destroy (filesel);
 633 
 634 		switch (cp->cert_type) {
 635 			case E_CERT_USER:
 636 				import = e_cert_db_import_pkcs12_file (e_cert_db_peek (), filename, &error);
 637 				break;
 638 			case E_CERT_CONTACT:
 639 			case E_CERT_CA:
 640 				import = e_cert_db_import_certs_from_file (
 641 					e_cert_db_peek (), filename,
 642 					cp->cert_type, &imported_certs, &error);
 643 				break;
 644 			default:
 645 				g_free (filename);
 646 				return;
 647 		}
 648 
 649 		if (import) {
 650 			unload_certs (cp);
 651 			load_certs (cp);
 652 
 653 			if (imported_certs)
 654 				select_certificate (cp, imported_certs->data);
 655 
 656 		} else {
 657 			report_and_free_error (cp, _("Failed to import certificate"), error);
 658 		}
 659 
 660 		g_slist_foreach (imported_certs, (GFunc) g_object_unref, NULL);
 661 		g_slist_free (imported_certs);
 662 		g_free (filename);
 663 	} else
 664 		gtk_widget_destroy (filesel);
 665 }
 666 
 667 static void
 668 delete_cert (GtkWidget *button,
 669              CertPage *cp)
 670 {
 671 	GtkTreeIter iter;
 672 
 673 	if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (cp->treeview), NULL, &iter)) {
 674 		ECert *cert;
 675 
 676 		gtk_tree_model_get (
 677 			GTK_TREE_MODEL (cp->streemodel), &iter,
 678 			cp->columns_count - 1, &cert,
 679 			-1);
 680 
 681 		if (cert && e_cert_db_delete_cert (e_cert_db_peek (), cert)) {
 682 			GtkTreeIter child_iter, parent_iter;
 683 			gboolean has_parent;
 684 			GtkTreeStore *store = GTK_TREE_STORE (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (cp->streemodel)));
 685 
 686 			gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (cp->streemodel), &child_iter, &iter);
 687 			has_parent = gtk_tree_model_iter_parent (GTK_TREE_MODEL (store), &parent_iter, &child_iter);
 688 			gtk_tree_store_remove (store, &child_iter);
 689 
 690 			/* Remove parent if it became empty */
 691 			if (has_parent && gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &parent_iter) == 0)
 692 				gtk_tree_store_remove (store, &parent_iter);
 693 
 694 			/* we need two unrefs here, one to unref the
 695 			 * gtk_tree_model_get above, and one to unref
 696 			 * the initial ref when we created the cert
 697 			 * and added it to the tree */
 698 			g_object_unref (cert);
 699 			g_object_unref (cert);
 700 		} else if (cert) {
 701 			g_object_unref (cert);
 702 		}
 703 	}
 704 
 705 }
 706 
 707 static void
 708 add_cert (CertPage *cp,
 709           ECert *cert)
 710 {
 711 	GtkTreeIter iter;
 712 	GtkTreeIter *parent_iter = NULL;
 713 	const gchar *organization = e_cert_get_org (cert);
 714 	GtkTreeModel *model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (cp->streemodel));
 715 	gint i;
 716 
 717 	if (organization) {
 718 		parent_iter = g_hash_table_lookup (cp->root_hash, organization);
 719 		if (!parent_iter) {
 720 			/* create a new toplevel node */
 721 			gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
 722 
 723 			gtk_tree_store_set (
 724 				GTK_TREE_STORE (model), &iter,
 725 				0, organization, -1);
 726 
 727 			/* now copy it off into parent_iter and insert it into
 728 			 * the hashtable */
 729 			parent_iter = gtk_tree_iter_copy (&iter);
 730 			g_hash_table_insert (cp->root_hash, g_strdup (organization), parent_iter);
 731 		}
 732 	}
 733 
 734 	gtk_tree_store_append (GTK_TREE_STORE (model), &iter, parent_iter);
 735 
 736 	for (i = 0; i < cp->columns_count; i++) {
 737 		const gchar * (*get_cert_data_func) (ECert *cert);
 738 
 739 		/* When e_cert_get_cn() is empty, use _get_nickname() */
 740 		if ((cp->columns[i].get_cert_data_func == e_cert_get_cn) && (!e_cert_get_cn (cert))) {
 741 			get_cert_data_func = e_cert_get_nickname;
 742 		} else {
 743 			get_cert_data_func = cp->columns[i].get_cert_data_func;
 744 		}
 745 
 746 		if (cp->columns[i].type == G_TYPE_STRING) {
 747 			gtk_tree_store_set (
 748 				GTK_TREE_STORE (model), &iter,
 749 				i, get_cert_data_func (cert), -1);
 750 		} else if (cp->columns[i].type == G_TYPE_OBJECT) {
 751 			gtk_tree_store_set (
 752 				GTK_TREE_STORE (model), &iter,
 753 				i, cert, -1);
 754 		}
 755 	}
 756 }
 757 
 758 static void
 759 unload_certs (CertPage *cp)
 760 {
 761 	GtkTreeStore *treemodel;
 762 	GType types[cp->columns_count];
 763 	gint i;
 764 
 765 	g_return_if_fail (cp != NULL);
 766 
 767 	for (i = 0; i < cp->columns_count; i++)
 768 		types[i] = cp->columns[i].type;
 769 	treemodel = gtk_tree_store_newv (cp->columns_count, types);
 770 
 771 	if (cp->streemodel)
 772 		g_object_unref (cp->streemodel);
 773 
 774 	cp->streemodel = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (treemodel));
 775 
 776 	g_object_unref (treemodel);
 777 	gtk_tree_view_set_model (cp->treeview, cp->streemodel);
 778 
 779 	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (cp->streemodel), 0, GTK_SORT_ASCENDING);
 780 
 781 	if (cp->root_hash)
 782 		g_hash_table_destroy (cp->root_hash);
 783 
 784 	cp->root_hash = g_hash_table_new_full (
 785 		(GHashFunc) g_str_hash,
 786 		(GEqualFunc) g_str_equal,
 787 		(GDestroyNotify) g_free,
 788 		(GDestroyNotify) gtk_tree_iter_free);
 789 }
 790 
 791 static void
 792 load_certs (CertPage *cp)
 793 {
 794 	CERTCertList *certList;
 795 	CERTCertListNode *node;
 796 
 797 	g_return_if_fail (cp != NULL);
 798 
 799 	certList = PK11_ListCerts (PK11CertListUnique, NULL);
 800 
 801 	for (node = CERT_LIST_HEAD (certList);
 802 	     !CERT_LIST_END (node, certList);
 803 	     node = CERT_LIST_NEXT (node)) {
 804 		ECert *cert = e_cert_new (CERT_DupCertificate ((CERTCertificate *) node->cert));
 805 		ECertType ct = e_cert_get_cert_type (cert);
 806 
 807 		/* show everything else in a contact tab */
 808 		if (ct == cp->cert_type || (cp->cert_type == E_CERT_CONTACT && ct != E_CERT_CA && ct != E_CERT_USER)) {
 809 			add_cert (cp, cert);
 810 		} else {
 811 			g_object_unref (cert);
 812 		}
 813 	}
 814 
 815 	CERT_DestroyCertList (certList);
 816 }
 817 
 818 static gboolean
 819 populate_ui (ECertManagerConfig *ecmc)
 820 {
 821 	/* This is an idle callback. */
 822 
 823 	ECertManagerConfigPrivate *priv = ecmc->priv;
 824 
 825 	unload_certs (priv->yourcerts_page);
 826 	load_certs (priv->yourcerts_page);
 827 
 828 	unload_certs (priv->contactcerts_page);
 829 	load_certs (priv->contactcerts_page);
 830 
 831 	unload_certs (priv->authoritycerts_page);
 832 	load_certs (priv->authoritycerts_page);
 833 
 834 	/* expand all three trees */
 835 	gtk_tree_view_expand_all (ECMC_TREE_VIEW (yourcerts_page));
 836 	gtk_tree_view_expand_all (ECMC_TREE_VIEW (contactcerts_page));
 837 	gtk_tree_view_expand_all (ECMC_TREE_VIEW (authoritycerts_page));
 838 
 839 	/* Now load settings of each treeview */
 840 	load_treeview_state (ECMC_TREE_VIEW (yourcerts_page));
 841 	load_treeview_state (ECMC_TREE_VIEW (contactcerts_page));
 842 	load_treeview_state (ECMC_TREE_VIEW (authoritycerts_page));
 843 
 844 	return FALSE;
 845 }
 846 
 847 static void
 848 initialize_ui (CertPage *cp)
 849 {
 850 	GtkTreeSelection *selection;
 851 	gint i;
 852 
 853 	cp->popup_menu = GTK_MENU (gtk_menu_new ());
 854 
 855 	/* Add columns to treeview */
 856 	for (i = 0; i < cp->columns_count; i++)
 857 		treeview_add_column (cp, i);
 858 
 859 	selection = gtk_tree_view_get_selection (cp->treeview);
 860 	g_signal_connect (
 861 		selection, "changed",
 862 		G_CALLBACK (treeview_selection_changed), cp);
 863 
 864 	if (cp->import_button)
 865 		g_signal_connect (
 866 			cp->import_button, "clicked",
 867 			G_CALLBACK (import_cert), cp);
 868 
 869 	if (cp->edit_button)
 870 		g_signal_connect (
 871 			cp->edit_button, "clicked",
 872 			G_CALLBACK (edit_cert), cp);
 873 
 874 	if (cp->delete_button)
 875 		g_signal_connect (
 876 			cp->delete_button, "clicked",
 877 			G_CALLBACK (delete_cert), cp);
 878 
 879 	if (cp->view_button)
 880 		g_signal_connect (
 881 			cp->view_button, "clicked",
 882 			G_CALLBACK (view_cert), cp);
 883 }
 884 
 885 static void
 886 cert_manager_config_window_hide (ECertManagerConfig *ecmc,
 887                                  EPreferencesWindow *epw)
 888 {
 889 	g_return_if_fail (ecmc);
 890 
 891 	save_treeview_state (ECMC_TREE_VIEW (yourcerts_page));
 892 	save_treeview_state (ECMC_TREE_VIEW (contactcerts_page));
 893 	save_treeview_state (ECMC_TREE_VIEW (authoritycerts_page));
 894 }
 895 
 896 static void
 897 free_cert (GtkTreeModel *model,
 898            GtkTreePath *path,
 899            GtkTreeIter *iter,
 900            gpointer user_data)
 901 {
 902 	CertPage *cp = user_data;
 903 	ECert *cert;
 904 
 905 	gtk_tree_model_get (model, iter, cp->columns_count - 1, &cert, -1);
 906 
 907 	/* Double unref: one for gtk_tree_model_get() and one for e_cert_new() */
 908 	g_object_unref (cert);
 909 	g_object_unref (cert);
 910 }
 911 
 912 static void
 913 cert_page_free (CertPage *cp)
 914 {
 915 	if (!cp)
 916 		return;
 917 
 918 	if (cp->streemodel) {
 919 		gtk_tree_model_foreach (GTK_TREE_MODEL (cp->streemodel),
 920 			(GtkTreeModelForeachFunc) free_cert, cp);
 921 		g_object_unref (cp->streemodel);
 922 		cp->streemodel = NULL;
 923 	}
 924 
 925 	if (cp->root_hash) {
 926 		g_hash_table_unref (cp->root_hash);
 927 		cp->root_hash = NULL;
 928 	}
 929 
 930 	g_free (cp);
 931 }
 932 
 933 static void
 934 cert_manager_config_dispose (GObject *object)
 935 {
 936 	ECertManagerConfig *ecmc = E_CERT_MANAGER_CONFIG (object);
 937 
 938 	if (ecmc->priv->yourcerts_page) {
 939 		cert_page_free (ecmc->priv->yourcerts_page);
 940 		ecmc->priv->yourcerts_page = NULL;
 941 	}
 942 
 943 	if (ecmc->priv->contactcerts_page) {
 944 		cert_page_free (ecmc->priv->contactcerts_page);
 945 		ecmc->priv->contactcerts_page = NULL;
 946 	}
 947 
 948 	if (ecmc->priv->authoritycerts_page) {
 949 		cert_page_free (ecmc->priv->authoritycerts_page);
 950 		ecmc->priv->authoritycerts_page = NULL;
 951 	}
 952 
 953 	if (ecmc->priv->builder) {
 954 		g_object_unref (ecmc->priv->builder);
 955 			ecmc->priv->builder = NULL;
 956 	}
 957 
 958 	if (ecmc->priv->pref_window) {
 959 		g_signal_handlers_disconnect_matched (ecmc->priv->pref_window, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, ecmc);
 960 		ecmc->priv->pref_window = NULL;
 961 	}
 962 
 963 	G_OBJECT_CLASS (e_cert_manager_config_parent_class)->dispose (object);
 964 }
 965 
 966 static void
 967 cert_manager_config_set_property (GObject *object,
 968                                   guint property_id,
 969                                   const GValue *value,
 970                                   GParamSpec *pspec)
 971 {
 972 	ECertManagerConfig *ecmc = E_CERT_MANAGER_CONFIG (object);
 973 
 974 	switch (property_id) {
 975 		case PROP_PREFERENCES_WINDOW:
 976 			ecmc->priv->pref_window = g_value_get_object (value);
 977 			/* When the preferences window is "closed" (= hidden), save
 978 			 * state of all treeviews. */
 979 			g_signal_connect_swapped (
 980 				ecmc->priv->pref_window, "hide",
 981 				G_CALLBACK (cert_manager_config_window_hide), ecmc);
 982 			return;
 983 	}
 984 
 985 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 986 }
 987 
 988 static void
 989 e_cert_manager_config_class_init (ECertManagerConfigClass *class)
 990 {
 991 	GObjectClass *object_class;
 992 
 993 	g_type_class_add_private (class, sizeof (ECertManagerConfigPrivate));
 994 
 995 	object_class = G_OBJECT_CLASS (class);
 996 	object_class->set_property = cert_manager_config_set_property;
 997 	object_class->dispose = cert_manager_config_dispose;
 998 
 999 	g_object_class_install_property (
1000 		object_class,
1001 		PROP_PREFERENCES_WINDOW,
1002 		g_param_spec_object (
1003 			"preferences-window",
1004 			NULL,
1005 			NULL,
1006 			E_TYPE_PREFERENCES_WINDOW,
1007 			G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
1008 }
1009 
1010 static void
1011 e_cert_manager_config_init (ECertManagerConfig *ecmc)
1012 {
1013 	ECertManagerConfigPrivate *priv;
1014 	GtkWidget *parent, *widget;
1015 	CertPage *cp;
1016 
1017 	priv = E_CERT_MANAGER_CONFIG_GET_PRIVATE (ecmc);
1018 	ecmc->priv = priv;
1019 
1020 	/* We need to peek the db here to make sure it (and NSS) are fully initialized. */
1021 	e_cert_db_peek ();
1022 
1023 	priv->builder = gtk_builder_new ();
1024 	e_load_ui_builder_definition (priv->builder, "smime-ui.ui");
1025 
1026 	cp = g_new0 (CertPage, 1);
1027 	priv->yourcerts_page = cp;
1028 	cp->treeview = GTK_TREE_VIEW (e_builder_get_widget (priv->builder, "yourcerts-treeview"));
1029 	cp->streemodel = NULL;
1030 	cp->view_button = e_builder_get_widget (priv->builder, "your-view-button");
1031 	cp->backup_button = e_builder_get_widget (priv->builder, "your-backup-button");
1032 	cp->backup_all_button = e_builder_get_widget (priv->builder, "your-backup-all-button");
1033 	cp->edit_button = NULL;
1034 	cp->import_button = e_builder_get_widget (priv->builder, "your-import-button");
1035 	cp->delete_button = e_builder_get_widget (priv->builder, "your-delete-button");
1036 	cp->columns = yourcerts_columns;
1037 	cp->columns_count = G_N_ELEMENTS (yourcerts_columns);
1038 	cp->cert_type = E_CERT_USER;
1039 	cp->cert_filter_name = _("All PKCS12 files");
1040 	cp->cert_mime_types = yourcerts_mime_types;
1041 	initialize_ui (cp);
1042 
1043 	cp = g_new0 (CertPage, 1);
1044 	priv->contactcerts_page = cp;
1045 	cp->treeview = GTK_TREE_VIEW (e_builder_get_widget (priv->builder, "contactcerts-treeview"));
1046 	cp->streemodel = NULL;
1047 	cp->view_button = e_builder_get_widget (priv->builder, "contact-view-button");
1048 	cp->backup_button = NULL;
1049 	cp->backup_all_button = NULL;
1050 	cp->edit_button = e_builder_get_widget (priv->builder, "contact-edit-button");
1051 	cp->import_button = e_builder_get_widget (priv->builder, "contact-import-button");
1052 	cp->delete_button = e_builder_get_widget (priv->builder, "contact-delete-button");
1053 	cp->columns = contactcerts_columns;
1054 	cp->columns_count = G_N_ELEMENTS (contactcerts_columns);
1055 	cp->cert_type = E_CERT_CONTACT;
1056 	cp->cert_filter_name = _("All email certificate files");
1057 	cp->cert_mime_types = contactcerts_mime_types;
1058 	initialize_ui (cp);
1059 
1060 	cp = g_new0 (CertPage, 1);
1061 	priv->authoritycerts_page = cp;
1062 	cp->treeview = GTK_TREE_VIEW (e_builder_get_widget (priv->builder, "authoritycerts-treeview"));
1063 	cp->streemodel = NULL;
1064 	cp->view_button = e_builder_get_widget (priv->builder, "authority-view-button");
1065 	cp->backup_button = NULL;
1066 	cp->backup_all_button = NULL;
1067 	cp->edit_button = e_builder_get_widget (priv->builder, "authority-edit-button");
1068 	cp->import_button = e_builder_get_widget (priv->builder, "authority-import-button");
1069 	cp->delete_button = e_builder_get_widget (priv->builder, "authority-delete-button");
1070 	cp->columns = authoritycerts_columns;
1071 	cp->columns_count = G_N_ELEMENTS (authoritycerts_columns);
1072 	cp->cert_type = E_CERT_CA;
1073 	cp->cert_filter_name = _("All CA certificate files");
1074 	cp->cert_mime_types = authoritycerts_mime_types;
1075 	initialize_ui (cp);
1076 
1077 	/* Run this in an idle callback so Evolution has a chance to
1078 	 * fully initialize itself and start its main loop before we
1079 	 * load certificates, since doing so may trigger a password
1080 	 * dialog, and dialogs require a main loop.
1081 	 * Schedule with priority higher than gtk+ uses for animations
1082 	 * (check docs for G_PRIORITY_HIGH_IDLE). */
1083 	g_idle_add_full (G_PRIORITY_DEFAULT, (GSourceFunc) populate_ui, ecmc, NULL);
1084 
1085 	/* Disconnect cert-manager-notebook from it's window and attach it
1086 	 * to this ECertManagerConfig */
1087 	widget = e_builder_get_widget (priv->builder, "cert-manager-notebook");
1088 	parent = gtk_widget_get_parent (widget);
1089 	gtk_container_remove (GTK_CONTAINER (parent), widget);
1090 	gtk_box_pack_start (GTK_BOX (ecmc), widget, TRUE, TRUE, 0);
1091 	gtk_widget_show_all (widget);
1092 
1093 	/* FIXME: remove when implemented */
1094 	gtk_widget_set_sensitive (priv->yourcerts_page->backup_button, FALSE);
1095 	gtk_widget_set_sensitive (priv->yourcerts_page->backup_all_button, FALSE);
1096 }
1097 
1098 GtkWidget *
1099 e_cert_manager_config_new (EPreferencesWindow *window)
1100 {
1101 	ECertManagerConfig *ecmc;
1102 
1103 	ecmc = g_object_new (E_TYPE_CERT_MANAGER_CONFIG, "preferences-window", window, NULL);
1104 
1105 	return GTK_WIDGET (ecmc);
1106 }