cpw.ljfisher.ssl_client_auth: 1e31f50b: Added "Your Certificates" tab and import...
lucas.fisher at gmail.com
lucas.fisher at gmail.com
Sat Apr 16 19:35:53 EDT 2011
----------------------------------------------------------------------
Revision: 1e31f50bbbb7123130021077c77d04ca15938d3b
Parent: 086a90dd9225c84e8b8f86b5fc22aa8857ee1d05
Author: lucas.fisher at gmail.com
Date: 04/16/11 17:04:07
Branch: im.pidgin.cpw.ljfisher.ssl_client_auth
URL: http://d.pidgin.im/viewmtn/revision/info/1e31f50bbbb7123130021077c77d04ca15938d3b
Changelog:
Added "Your Certificates" tab and import/export of certificates using PKCS12.
Changes against parent 086a90dd9225c84e8b8f86b5fc22aa8857ee1d05
patched pidgin/gtkcertmgr.c
-------------- next part --------------
============================================================
--- pidgin/gtkcertmgr.c ea9690460570023612e9de6678a46c3ca480820c
+++ pidgin/gtkcertmgr.c e8f6c3d2915efea8febfee85ea5941f32b99ff7a
@@ -31,6 +31,7 @@
#include "pidginstock.h"
#include "certificate.h"
+#include "pkcs12.h"
#include "debug.h"
#include "notify.h"
#include "request.h"
@@ -532,6 +533,748 @@ const PidginCertificateManager tls_peers
};
/*****************************************************************************
+ * X.509 user certificates management interface *
+ *****************************************************************************/
+
+typedef struct {
+ GtkWidget *mgmt_widget;
+ GtkTreeView *listview;
+ GtkTreeSelection *listselect;
+ GtkWidget *importbutton;
+ GtkWidget *exportbutton;
+ GtkWidget *infobutton;
+ GtkWidget *deletebutton;
+ PurpleCertificatePool *user_crts;
+ PurplePrivateKeyPool *user_keys;
+ PurplePkcs12Scheme *pkcs12;
+} user_mgmt_data;
+
+user_mgmt_data *um_dat = NULL;
+
+/* Columns
+ See http://developer.gnome.org/doc/API/2.0/gtk/TreeWidget.html */
+enum
+{
+ UM_NAME_COLUMN,
+ UM_N_COLUMNS
+};
+
+static void
+user_mgmt_destroy(GtkWidget *mgmt_widget, gpointer data)
+{
+ purple_debug_info("certmgr",
+ "user self-destructs\n");
+
+ purple_signals_disconnect_by_handle(um_dat);
+ purple_request_close_with_handle(um_dat);
+ g_free(um_dat); um_dat = NULL;
+}
+
+static void
+user_mgmt_repopulate_list(void)
+{
+ GtkTreeView *listview = um_dat->listview;
+ PurpleCertificatePool *user_crts;
+ PurplePrivateKeyPool *user_keys;
+ GList *idlist, *l;
+
+ GtkListStore *store = GTK_LIST_STORE(
+ gtk_tree_view_get_model(GTK_TREE_VIEW(listview)));
+
+ /* First, delete everything in the list */
+ gtk_list_store_clear(store);
+
+ /* Locate the "user" pools */
+ user_crts = purple_certificate_find_pool("x509", "user");
+ user_keys = purple_privatekey_find_pool("x509", "user");
+
+ g_return_if_fail(user_crts);
+ g_return_if_fail(user_keys);
+
+ /* Grab the loaded certificates */
+ idlist = purple_certificate_pool_get_idlist(user_crts);
+
+ /* Populate the listview */
+ for (l = idlist; l; l = l->next) {
+ GtkTreeIter iter;
+
+ if ( ! purple_privatekey_pool_contains(user_keys, l->data)) {
+ purple_debug_warning("gtkcertmgr/user_mgmt",
+ "User cert %s is missing it's private key.\n",
+ (gchar*)l->data);
+ }
+
+ gtk_list_store_append(store, &iter);
+
+ gtk_list_store_set(GTK_LIST_STORE(store), &iter,
+ UM_NAME_COLUMN, l->data,
+ -1);
+ }
+ purple_certificate_pool_destroy_idlist(idlist);
+}
+
+static void
+user_mgmt_mod_cb(PurpleCertificatePool *pool, const gchar *id, gpointer data)
+{
+ g_assert (pool == um_dat->user_crts);
+
+ user_mgmt_repopulate_list();
+}
+
+static void
+user_mgmt_select_chg_cb(GtkTreeSelection *ignored, gpointer data)
+{
+ GtkTreeSelection *select = um_dat->listselect;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ /* See if things are selected */
+ if (gtk_tree_selection_get_selected(select, &model, &iter)) {
+ /* Enable buttons if something is selected */
+ gtk_widget_set_sensitive(GTK_WIDGET(um_dat->exportbutton), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(um_dat->infobutton), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(um_dat->deletebutton), TRUE);
+ } else {
+ /* Otherwise, disable them */
+ gtk_widget_set_sensitive(GTK_WIDGET(um_dat->exportbutton), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(um_dat->infobutton), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(um_dat->deletebutton), FALSE);
+
+ }
+}
+
+/**********************************************************
+ * Importing a crt and key from PKCS12 file
+ */
+
+typedef struct {
+ PurpleCertificate *crt;
+ PurplePrivateKey *key;
+ char *name;
+} pkcs12_import_data;
+
+static void
+pkcs12_import_data_free(pkcs12_import_data *data)
+{
+ purple_certificate_destroy(data->crt);
+ purple_privatekey_destroy(data->key);
+ g_free(data->name);
+ g_free(data);
+}
+
+static void
+pkcs12_import_key_password_ok_cb(gboolean result, pkcs12_import_data *data)
+{
+ if (!purple_certificate_pool_store(um_dat->user_crts, data->name, data->crt)) {
+ purple_notify_error(um_dat, NULL, _("Failed to save imported certificate."), NULL);
+ /* TODO: deleted corresponding key stored in privatekey pool */
+ }
+
+ pkcs12_import_data_free(data);
+}
+
+static void
+pkcs12_import_key_password_cancel_cb(pkcs12_import_data *data)
+{
+ pkcs12_import_data_free(data);
+}
+
+static void
+pkcs12_import_name_ok_cb(pkcs12_import_data *data, char* name)
+{
+ g_free(data->name);
+ data->name = g_strdup(name);
+
+ /* TODO: What if we have the same name? */
+ purple_privatekey_pool_store_request(
+ um_dat->user_keys,
+ data->name,
+ data->key,
+ pkcs12_import_key_password_ok_cb,
+ pkcs12_import_key_password_cancel_cb,
+ data);
+}
+
+static void
+pkcs12_import_name_cancel_cb(pkcs12_import_data *data)
+{
+ pkcs12_import_data_free(data);
+}
+
+static void
+user_mgmt_import_pkcs12(const gchar* filename, const gchar* password)
+{
+ PurpleCertificateScheme *x509_crts;
+ PurplePrivateKeyScheme *x509_keys;
+ PurpleCertificate *crt = NULL;
+ PurplePrivateKey *key = NULL;
+ pkcs12_import_data *data;
+ gboolean result;
+
+ purple_debug_info("gtkcertmgr/user_mgmt", "Importing pkcs12 file %s with password XXXXXX\n", filename);
+
+ /* Load the scheme of our user pool (ought to be x509) */
+ x509_crts = purple_certificate_pool_get_scheme(um_dat->user_crts);
+ g_return_if_fail(x509_crts);
+ x509_keys = purple_privatekey_pool_get_scheme(um_dat->user_keys);
+ g_return_if_fail(x509_keys);
+
+ /* Now load the certificate/keys from disk */
+ result = purple_pkcs12_import(um_dat->pkcs12, filename, password, &crt, &key);
+
+ /* Did it work? */
+ if (result) {
+ gchar *default_name;
+
+ /* Get name to add to pool as */
+ /* Make a guess about what the hostname should be */
+ default_name = purple_certificate_get_subject_name(crt);
+ /* TODO: Find a way to make sure that crt & key gets destroyed
+ if the window gets closed unusually, such as by handle
+ deletion */
+ /* TODO: Display some more information on the certificate? */
+
+ data = g_new0(pkcs12_import_data, 1);
+ data->crt = crt;
+ data->key = key;
+ data->name = default_name;
+
+ /* TODO: Enable custom cert name dialog */
+ purple_request_input(um_dat,
+ _("PKCS12 Import"),
+ _("Specify a name"),
+ _("Type the name for the imported certificate and key."),
+ default_name,
+ FALSE, /* Not multiline */
+ FALSE, /* Not masked? */
+ NULL, /* No hints? */
+ _("OK"),
+ G_CALLBACK(pkcs12_import_name_ok_cb),
+ _("Cancel"),
+ G_CALLBACK(pkcs12_import_name_cancel_cb),
+ NULL, NULL, NULL, /* No account/who/conv*/
+ data);
+ } else {
+ /* Errors! Oh no! */
+ /* TODO: Perhaps find a way to be specific about what just
+ went wrong? */
+ gchar * secondary;
+
+ purple_certificate_destroy(crt);
+ purple_privatekey_destroy(key);
+
+ secondary = g_strdup_printf(_("File %s could not be imported.\nMake sure that the file is readable, in PKCS12 format and you used the correct password.\n"), filename);
+ purple_notify_message(NULL, PURPLE_NOTIFY_MSG_ERROR,
+ _("Certificate Import Error"),
+ _("PKCS12 certificate import failed"),
+ secondary,
+ g_free,
+ secondary);
+ }
+}
+
+static void
+pkcs12_import_password_ok_cb(char *filename, PurpleRequestFields *fields)
+{
+ const char *entry;
+ gboolean remember;
+
+ entry = purple_request_fields_get_string(fields, "password");
+/* remember = purple_request_fields_get_bool(fields, "remember");*/
+
+ if (!entry || !*entry)
+ {
+ purple_notify_error(um_dat, NULL, _("A password is required to access a PKCS12 file."), NULL);
+ g_free(filename);
+ return;
+ }
+/*
+ if(remember)
+ purple_account_set_remember_password(account, TRUE);
+*/
+
+ purple_debug_info("gtkcertmgr/user_mgmt/import_pkcs12", "Got password for pkcs file %s\n", filename);
+ user_mgmt_import_pkcs12(filename, entry);
+ g_free(filename);
+}
+
+static void
+pkcs12_import_password_cancel_cb( char* filename)
+{
+ g_free(filename);
+}
+
+static void
+user_mgmt_import_ok_cb(gpointer data, char *filename)
+{
+ purple_debug_info("gtkcertmgr/user_mgmt/import_pkcs12", "Importing pkcs12 file %s\n", filename);
+ filename = g_strdup(filename); /* othewise it goes away after this func returns */
+ purple_pkcs12_request_password(
+ um_dat,
+ filename,
+ G_CALLBACK(pkcs12_import_password_ok_cb),
+ G_CALLBACK(pkcs12_import_password_cancel_cb),
+ (void*)filename);
+}
+
+static void
+user_mgmt_import_cb(GtkWidget *button, gpointer data)
+{
+ /* TODO: need to tell the user that we want a .PEM file! */
+ purple_request_file(um_dat,
+ _("Select a PKCS12 certificate file"),
+ "certificate.p12",
+ FALSE, /* Not a save dialog */
+ G_CALLBACK(user_mgmt_import_ok_cb),
+ NULL, /* Do nothing if cancelled */
+ NULL, NULL, NULL, NULL );/* No account,conv,etc. */
+}
+
+/**********************************************************
+ * Exporting crt and key to PKCS12 file
+ */
+
+typedef struct {
+ PurpleCertificate *crt;
+ PurplePrivateKey *key;
+ char* filename;
+ char* id;
+} pkcs12_export_data;
+
+static void
+pkcs12_export_data_free(pkcs12_export_data *data)
+{
+
+ g_return_if_fail(data);
+ purple_certificate_destroy(data->crt);
+ purple_privatekey_destroy(data->key);
+ g_free(data->filename);
+ g_free(data->id);
+ g_free(data);
+
+}
+
+static void
+pkcs12_export_password_ok_cb(pkcs12_export_data *data, PurpleRequestFields *fields)
+{
+ const char *entry;
+ gboolean remember;
+
+ purple_debug_info("certmgr/user_mgmt/pkcs12_export", "pkcs12 password ok cb\n");
+ entry = purple_request_fields_get_string(fields, "password");
+/* remember = purple_request_fields_get_bool(fields, "remember");*/
+
+ if (!entry || !*entry)
+ {
+ purple_notify_error(um_dat, NULL, _("A password is required to protect the PKCS12 file."), NULL);
+ pkcs12_export_data_free(data);
+ return;
+ }
+/*
+ if(remember)
+ purple_account_set_remember_password(account, TRUE);
+*/
+
+ purple_debug_info("gtkcertmgr/user_mgmt/export_pkcs12", "Got password for pkcs file %s\n", data->filename);
+
+ /* Finally create the pkcs12 file */
+
+ if (!purple_pkcs12_export(um_dat->pkcs12, data->filename, entry, data->crt, data->key)) {
+ /* Errors! Oh no! */
+ /* TODO: Perhaps find a way to be specific about what just
+ went wrong? */
+ gchar * secondary;
+
+ secondary = g_strdup_printf(
+ _("Export to file %s failed.\nCheck that you have write "
+ "permission to the target path\n"), data->filename);
+
+ purple_notify_message(NULL, PURPLE_NOTIFY_MSG_ERROR,
+ _("PKCS12 Export Error"),
+ _("PKCS12 certificate & key export failed"),
+ secondary,
+ NULL,
+ NULL);
+ }
+
+ pkcs12_export_data_free(data);
+}
+
+static void
+pkcs12_export_password_cancel_cb(pkcs12_export_data* data)
+{
+ pkcs12_export_data_free(data);
+}
+
+static void
+user_mgmt_export_ok_cb(pkcs12_export_data *data, const char *filename)
+{
+ purple_debug_info("certmgr/user_mgmt/pkcs12_export", "file ok cb\n");
+ data->filename = g_strdup(filename); /* it goes away otherwise */
+ purple_pkcs12_request_password(
+ um_dat,
+ data->filename,
+ G_CALLBACK(pkcs12_export_password_ok_cb),
+ G_CALLBACK(pkcs12_export_password_cancel_cb),
+ data);
+}
+
+static void
+user_mgmt_export_cancel_cb(pkcs12_export_data *data, const char *filename)
+{
+ /* Pressing cancel just frees the duplicated certificate & key*/
+ pkcs12_export_data_free(data);
+}
+
+static void
+pkcs12_get_key_password_ok_cb(PurplePrivateKey *key, pkcs12_export_data *data)
+{
+ char* secondary;
+
+ purple_debug_info("certmgr/user_mgmt/pkcs12_export", "key password ok cb\n");
+ if (NULL == key) {
+ purple_debug_error("gtkcertmgr/user_mgmt",
+ "Id %s was not in the user key pool or bad password\n",
+ data->id);
+
+ secondary = g_strdup_printf(
+ _("The private key named \"%s\" was not found or the key's password was incorrect."),
+ data->id);
+
+ purple_notify_message(NULL, PURPLE_NOTIFY_MSG_ERROR,
+ _("PKCS12 Export Error"),
+ _("PKCS12 certificate & key export failed"),
+ secondary,
+ NULL,
+ NULL);
+
+ pkcs12_export_data_free(data);
+
+ return;
+ }
+
+ data->key = key;
+
+ purple_request_file(um_dat,
+ _("PKCS12 Certificate & Key Export"),
+ "certificate.p12",
+ TRUE, /* Is a save dialog */
+ G_CALLBACK(user_mgmt_export_ok_cb),
+ G_CALLBACK(user_mgmt_export_cancel_cb),
+ NULL, NULL, NULL, /* No account,conv,etc. */
+ data); /* Pass the certificate & key on to the callback */
+}
+
+static void
+pkcs12_get_key_password_cancel_cb(pkcs12_export_data *data)
+{
+ pkcs12_export_data_free(data);
+}
+
+static void
+user_mgmt_export_cb(GtkWidget *button, void* stuff)
+{
+ PurpleCertificate *crt = NULL;
+ GtkTreeSelection *select = um_dat->listselect;
+ GtkTreeIter iter;
+ GtkTreeModel *model = NULL;
+ gchar *id = NULL;
+ pkcs12_export_data *data = NULL;
+
+ purple_debug_info("gtkcertmgr/user_mgmt", "1111111111111111\n");
+
+ /* See if things are selected */
+ if (!gtk_tree_selection_get_selected(select, &model, &iter)) {
+ purple_debug_warning("gtkcertmgr/user_mgmt",
+ "Export clicked with no selection?\n");
+ return;
+ }
+
+ /* Retrieve the selected name */
+ gtk_tree_model_get(model, &iter, UM_NAME_COLUMN, &id, -1);
+
+ /* Extract the certificate & keys from the pools now to make sure it doesn't
+ get deleted out from under us */
+ crt = purple_certificate_pool_retrieve(um_dat->user_crts, id);
+
+ if (NULL == crt) {
+ purple_debug_error("gtkcertmgr/user_mgmt",
+ "Id %s was not in the user cert pool?!\n",
+ id);
+ g_free(id);
+ return;
+ }
+
+ /* stuff we will need in our callbacks */
+ data = g_new0(pkcs12_export_data, 1);
+ data->crt = crt;
+ data->id = id;
+
+ purple_privatekey_pool_retrieve_request(
+ um_dat->user_keys,
+ id,
+ G_CALLBACK(pkcs12_get_key_password_ok_cb),
+ G_CALLBACK(pkcs12_get_key_password_cancel_cb),
+ data);
+}
+
+/**********************************************************
+ * Display certificate and key info
+ */
+
+static void
+user_mgmt_info_cb(GtkWidget *button, gpointer data)
+{
+ GtkTreeSelection *select = um_dat->listselect;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ gchar *id;
+ PurpleCertificate *crt;
+
+ /* See if things are selected */
+ if (!gtk_tree_selection_get_selected(select, &model, &iter)) {
+ purple_debug_warning("gtkcertmgr/user_mgmt",
+ "Info clicked with no selection?\n");
+ return;
+ }
+
+ /* Retrieve the selected name */
+ gtk_tree_model_get(model, &iter, UM_NAME_COLUMN, &id, -1);
+
+ /* Now retrieve the certificate */
+ crt = purple_certificate_pool_retrieve(um_dat->user_crts, id);
+ g_return_if_fail(crt);
+
+ /* Fire the notification */
+ purple_certificate_display_x509(crt);
+
+ g_free(id);
+ purple_certificate_destroy(crt);
+}
+
+/***********************************************************
+ * Delete a certificate and key
+ */
+
+static void
+user_mgmt_delete_confirm_cb(gchar *id, gint choice)
+{
+ if (1 == choice) {
+ /* Yes, delete was confirmed */
+ /* Now delete the thing */
+ if (!purple_certificate_pool_delete(um_dat->user_crts, id)) {
+ purple_debug_warning("gtkcertmgr/user_mgmt",
+ "Deletion failed of certificate for id %s\n",
+ id);
+ };
+ if (!purple_privatekey_pool_delete(um_dat->user_keys, id)) {
+ purple_debug_warning("gtkcertmgr/user_mgrm",
+ "Deletion failed of private key for id %s\n",
+ id);
+ }
+ }
+
+ g_free(id);
+}
+
+static void
+user_mgmt_delete_cb(GtkWidget *button, gpointer data)
+{
+ GtkTreeSelection *select = um_dat->listselect;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ /* See if things are selected */
+ if (gtk_tree_selection_get_selected(select, &model, &iter)) {
+
+ gchar *id;
+ gchar *primary;
+
+ /* Retrieve the selected hostname */
+ gtk_tree_model_get(model, &iter, UM_NAME_COLUMN, &id, -1);
+
+ /* Prompt to confirm deletion */
+ primary = g_strdup_printf(
+ _("Really delete certificate for %s?"), id );
+
+ purple_request_yes_no(um_dat, _("Confirm certificate delete"),
+ primary, NULL, /* Can this be NULL? */
+ 0, /* "yes" is the default action */
+ NULL, NULL, NULL,
+ id, /* id ownership passed to callback */
+ user_mgmt_delete_confirm_cb,
+ user_mgmt_delete_confirm_cb );
+
+ g_free(primary);
+
+ } else {
+ purple_debug_warning("gtkcertmgr/user_mgmt",
+ "Delete clicked with no selection?\n");
+ return;
+ }
+}
+
+/**********************************************************
+ * Setup the user certificate & key management tab
+ */
+
+static GtkWidget *
+user_mgmt_build(void)
+{
+ GtkWidget *bbox;
+ GtkListStore *store;
+ GtkWidget *sw;
+
+ /* This block of variables will end up in um_dat */
+ GtkTreeView *listview;
+ GtkTreeSelection *select;
+ GtkWidget *importbutton;
+ GtkWidget *exportbutton;
+ GtkWidget *infobutton;
+ GtkWidget *deletebutton;
+ /** Element to return to the Certmgr window to put in the Notebook */
+ GtkWidget *mgmt_widget;
+
+ /* Create a struct to store context information about this window */
+ um_dat = g_new0(user_mgmt_data, 1);
+
+ um_dat->mgmt_widget = mgmt_widget =
+ gtk_hbox_new(FALSE, /* Non-homogeneous */
+ PIDGIN_HIG_BOX_SPACE);
+ gtk_container_set_border_width(GTK_CONTAINER(mgmt_widget),
+ PIDGIN_HIG_BOX_SPACE);
+ gtk_widget_show(mgmt_widget);
+
+ /* Ensure that everything gets cleaned up when the dialog box
+ is closed */
+ g_signal_connect(G_OBJECT(mgmt_widget), "destroy",
+ G_CALLBACK(user_mgmt_destroy), NULL);
+
+ /* Scrolled window */
+ sw = gtk_scrolled_window_new(NULL,NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
+ gtk_box_pack_start(GTK_BOX(mgmt_widget), GTK_WIDGET(sw),
+ TRUE, TRUE, /* Take up lots of space */
+ 0);
+ gtk_widget_show(GTK_WIDGET(sw));
+
+ /* List view */
+ store = gtk_list_store_new(UM_N_COLUMNS, G_TYPE_STRING);
+
+ um_dat->listview = listview =
+ GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)));
+ g_object_unref(G_OBJECT(store));
+
+ {
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+
+ /* Set up the display columns */
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes(
+ _("Name"),
+ renderer,
+ "text", UM_NAME_COLUMN,
+ NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
+
+ gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
+ UM_NAME_COLUMN, GTK_SORT_ASCENDING);
+ }
+
+ /* Get the treeview selector into the struct */
+ um_dat->listselect = select =
+ gtk_tree_view_get_selection(GTK_TREE_VIEW(listview));
+
+ /* Force the selection mode */
+ gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE);
+
+ /* Use a callback to enable/disable the buttons based on whether
+ something is selected */
+ g_signal_connect(G_OBJECT(select), "changed",
+ G_CALLBACK(user_mgmt_select_chg_cb), NULL);
+
+ gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(listview));
+ gtk_widget_show(GTK_WIDGET(listview));
+
+ /* Fill the list for the first time */
+ user_mgmt_repopulate_list();
+
+ /* Right-hand side controls box */
+ bbox = gtk_vbutton_box_new();
+ gtk_box_pack_end(GTK_BOX(mgmt_widget), bbox,
+ FALSE, FALSE, /* Do not take up space */
+ 0);
+ gtk_box_set_spacing(GTK_BOX(bbox), PIDGIN_HIG_BOX_SPACE);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_START);
+ gtk_widget_show(bbox);
+
+ /* Import button */
+ /* TODO: This is the wrong stock button */
+ um_dat->importbutton = importbutton =
+ gtk_button_new_from_stock(GTK_STOCK_ADD);
+ gtk_box_pack_start(GTK_BOX(bbox), importbutton, FALSE, FALSE, 0);
+ gtk_widget_show(importbutton);
+ g_signal_connect(G_OBJECT(importbutton), "clicked",
+ G_CALLBACK(user_mgmt_import_cb), NULL);
+
+
+ /* Export button */
+ /* TODO: This is the wrong stock button */
+ um_dat->exportbutton = exportbutton =
+ gtk_button_new_from_stock(GTK_STOCK_SAVE);
+ gtk_box_pack_start(GTK_BOX(bbox), exportbutton, FALSE, FALSE, 0);
+ gtk_widget_show(exportbutton);
+ g_signal_connect(G_OBJECT(exportbutton), "clicked",
+ G_CALLBACK(user_mgmt_export_cb), NULL);
+
+
+ /* Info button */
+ um_dat->infobutton = infobutton =
+ gtk_button_new_from_stock(PIDGIN_STOCK_INFO);
+ gtk_box_pack_start(GTK_BOX(bbox), infobutton, FALSE, FALSE, 0);
+ gtk_widget_show(infobutton);
+ g_signal_connect(G_OBJECT(infobutton), "clicked",
+ G_CALLBACK(user_mgmt_info_cb), NULL);
+
+
+ /* Delete button */
+ um_dat->deletebutton = deletebutton =
+ gtk_button_new_from_stock(GTK_STOCK_DELETE);
+ gtk_box_pack_start(GTK_BOX(bbox), deletebutton, FALSE, FALSE, 0);
+ gtk_widget_show(deletebutton);
+ g_signal_connect(G_OBJECT(deletebutton), "clicked",
+ G_CALLBACK(user_mgmt_delete_cb), NULL);
+
+ /* Call the "selection changed" callback, which will probably disable
+ all the buttons since nothing is selected yet */
+ user_mgmt_select_chg_cb(select, NULL);
+
+ /* Bind us to the user pool */
+ um_dat->user_crts = purple_certificate_find_pool("x509", "user");
+ um_dat->user_keys = purple_privatekey_find_pool("x509", "user");
+ um_dat->pkcs12 = purple_pkcs12_find_scheme("pkcs12");
+
+ /**** libpurple signals ****/
+ /* Respond to certificate add/remove by just reloading everything */
+ purple_signal_connect(um_dat->user_crts, "certificate-stored",
+ um_dat, PURPLE_CALLBACK(user_mgmt_mod_cb),
+ NULL);
+ purple_signal_connect(um_dat->user_crts, "certificate-deleted",
+ um_dat, PURPLE_CALLBACK(user_mgmt_mod_cb),
+ NULL);
+
+ return mgmt_widget;
+}
+
+const PidginCertificateManager user_mgmt = {
+ user_mgmt_build, /* Widget creation function */
+ N_("Your Certificates")
+};
+
+/*****************************************************************************
* GTK+ main certificate manager *
*****************************************************************************/
typedef struct
@@ -631,6 +1374,9 @@ pidgin_certmgr_show(void)
gtk_notebook_append_page(GTK_NOTEBOOK (dlg->notebook),
(tls_peers_mgmt.build)(),
gtk_label_new(_(tls_peers_mgmt.label)) );
+ gtk_notebook_append_page(GTK_NOTEBOOK (dlg->notebook),
+ (user_mgmt.build)(),
+ gtk_label_new(_(user_mgmt.label)) );
gtk_widget_show(win);
}
More information about the Commits
mailing list