[evolution] Bug #619218 - Should select imported certificate when succeeded



commit 077116eac4cbfd5f06c44c8f5634469eab3130e6
Author: Milan Crha <mcrha redhat com>
Date:   Fri Jun 11 19:28:16 2010 +0200

    Bug #619218 - Should select imported certificate when succeeded

 smime/gui/certificate-manager.c |  108 ++++++++++++-
 smime/lib/e-cert-db.c           |  332 ++++++++++++++++++++++++++++++++++-----
 smime/lib/e-cert-db.h           |    7 +
 3 files changed, 400 insertions(+), 47 deletions(-)
---
diff --git a/smime/gui/certificate-manager.c b/smime/gui/certificate-manager.c
index cc6d702..9c28945 100644
--- a/smime/gui/certificate-manager.c
+++ b/smime/gui/certificate-manager.c
@@ -46,6 +46,7 @@
 #include <pk11func.h>
 
 #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"
@@ -91,6 +92,18 @@ 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,
@@ -153,17 +166,20 @@ import_your (GtkWidget *widget, CertificateManagerData *cfm)
 
 	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, NULL /* XXX */)) {
+						  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);
@@ -189,7 +205,6 @@ delete_your (GtkWidget *widget, CertificateManagerData *cfm)
 		if (cert
 		    && e_cert_db_delete_cert (e_cert_db_peek (), cert)) {
 			GtkTreeIter child_iter;
-			printf ("DELETE\n");
 			gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (cfm->yourcerts_streemodel),
 									&child_iter,
 									&iter);
@@ -243,6 +258,69 @@ 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)
 {
@@ -400,6 +478,8 @@ import_contact (GtkWidget *widget, CertificateManagerData *cfm)
 
 	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);
@@ -407,16 +487,24 @@ import_contact (GtkWidget *widget, CertificateManagerData *cfm)
 		if (e_cert_db_import_certs_from_file (e_cert_db_peek (),
 						      filename,
 						      E_CERT_CONTACT,
-						      NULL)) {
+						      &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);
 }
@@ -439,7 +527,6 @@ delete_contact (GtkWidget *widget, CertificateManagerData *cfm)
 		if (cert
 		    && e_cert_db_delete_cert (e_cert_db_peek (), cert)) {
 			GtkTreeIter child_iter;
-			printf ("DELETE\n");
 			gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (cfm->contactcerts_streemodel),
 									&child_iter,
 									&iter);
@@ -627,6 +714,8 @@ import_ca (GtkWidget *widget, CertificateManagerData *cfm)
 
 	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);
@@ -634,14 +723,22 @@ import_ca (GtkWidget *widget, CertificateManagerData *cfm)
 		if (e_cert_db_import_certs_from_file (e_cert_db_peek (),
 						      filename,
 						      E_CERT_CA,
-						      NULL)) {
+						      &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);
@@ -665,7 +762,6 @@ delete_ca (GtkWidget *widget, CertificateManagerData *cfm)
 		if (cert
 		    && e_cert_db_delete_cert (e_cert_db_peek (), cert)) {
 			GtkTreeIter child_iter;
-			printf ("DELETE\n");
 			gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (cfm->authoritycerts_streemodel),
 									&child_iter,
 									&iter);
diff --git a/smime/lib/e-cert-db.c b/smime/lib/e-cert-db.c
index a4fcbe4..833c19b 100644
--- a/smime/lib/e-cert-db.c
+++ b/smime/lib/e-cert-db.c
@@ -67,13 +67,13 @@
 #include "p12plcy.h"
 #include "pk11func.h"
 #include "nssckbi.h"
+#include <secerr.h>
 #include "secmod.h"
 #include "certdb.h"
 #include "plstr.h"
 #include "prprf.h"
 #include "prmem.h"
 #include "e-util/e-util.h"
-#include "e-util/e-dialog-utils.h"
 #include "e-util/e-util-private.h"
 #include <libedataserverui/e-passwords.h>
 #include <sys/types.h>
@@ -96,6 +96,225 @@ struct _ECertDBPrivate {
 #define PARENT_TYPE G_TYPE_OBJECT
 static GObjectClass *parent_class;
 
+GQuark
+e_certdb_error_quark (void)
+{
+	static GQuark q = 0;
+	if (q == 0)
+		q = g_quark_from_static_string ("e-certdb-error-quark");
+
+	return q;
+}
+
+static const gchar *
+nss_error_to_string (glong errorcode)
+{
+#define cs(a,b) case a: return b;
+
+	switch (errorcode) {
+	cs (SEC_ERROR_IO, "An I/O error occurred during security authorization.")
+	cs (SEC_ERROR_LIBRARY_FAILURE, "security library failure.")
+	cs (SEC_ERROR_BAD_DATA, "security library: received bad data.")
+	cs (SEC_ERROR_OUTPUT_LEN, "security library: output length error.")
+	cs (SEC_ERROR_INPUT_LEN, "security library has experienced an input length error.")
+	cs (SEC_ERROR_INVALID_ARGS, "security library: invalid arguments.")
+	cs (SEC_ERROR_INVALID_ALGORITHM, "security library: invalid algorithm.")
+	cs (SEC_ERROR_INVALID_AVA, "security library: invalid AVA.")
+	cs (SEC_ERROR_INVALID_TIME, "Improperly formatted time string.")
+	cs (SEC_ERROR_BAD_DER, "security library: improperly formatted DER-encoded message.")
+	cs (SEC_ERROR_BAD_SIGNATURE, "Peer's certificate has an invalid signature.")
+	cs (SEC_ERROR_EXPIRED_CERTIFICATE, "Peer's Certificate has expired.")
+	cs (SEC_ERROR_REVOKED_CERTIFICATE, "Peer's Certificate has been revoked.")
+	cs (SEC_ERROR_UNKNOWN_ISSUER, "Peer's Certificate issuer is not recognized.")
+	cs (SEC_ERROR_BAD_KEY, "Peer's public key is invalid.")
+	cs (SEC_ERROR_BAD_PASSWORD, "The security password entered is incorrect.")
+	cs (SEC_ERROR_RETRY_PASSWORD, "New password entered incorrectly.  Please try again.")
+	cs (SEC_ERROR_NO_NODELOCK, "security library: no nodelock.")
+	cs (SEC_ERROR_BAD_DATABASE, "security library: bad database.")
+	cs (SEC_ERROR_NO_MEMORY, "security library: memory allocation failure.")
+	cs (SEC_ERROR_UNTRUSTED_ISSUER, "Peer's certificate issuer has been marked as not trusted by the user.")
+	cs (SEC_ERROR_UNTRUSTED_CERT, "Peer's certificate has been marked as not trusted by the user.")
+	cs (SEC_ERROR_DUPLICATE_CERT, "Certificate already exists in your database.")
+	cs (SEC_ERROR_DUPLICATE_CERT_NAME, "Downloaded certificate's name duplicates one already in your database.")
+	cs (SEC_ERROR_ADDING_CERT, "Error adding certificate to database.")
+	cs (SEC_ERROR_FILING_KEY, "Error refiling the key for this certificate.")
+	cs (SEC_ERROR_NO_KEY, "The private key for this certificate cannot be found in key database")
+	cs (SEC_ERROR_CERT_VALID, "This certificate is valid.")
+	cs (SEC_ERROR_CERT_NOT_VALID, "This certificate is not valid.")
+	cs (SEC_ERROR_CERT_NO_RESPONSE, "Cert Library: No Response")
+	cs (SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, "The certificate issuer's certificate has expired.  Check your system date and time.")
+	cs (SEC_ERROR_CRL_EXPIRED, "The CRL for the certificate's issuer has expired.  Update it or check your system date and time.")
+	cs (SEC_ERROR_CRL_BAD_SIGNATURE, "The CRL for the certificate's issuer has an invalid signature.")
+	cs (SEC_ERROR_CRL_INVALID, "New CRL has an invalid format.")
+	cs (SEC_ERROR_EXTENSION_VALUE_INVALID, "Certificate extension value is invalid.")
+	cs (SEC_ERROR_EXTENSION_NOT_FOUND, "Certificate extension not found.")
+	cs (SEC_ERROR_CA_CERT_INVALID, "Issuer certificate is invalid.")
+	cs (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID, "Certificate path length constraint is invalid.")
+	cs (SEC_ERROR_CERT_USAGES_INVALID, "Certificate usages field is invalid.")
+	cs (SEC_INTERNAL_ONLY, "**Internal ONLY module**")
+	cs (SEC_ERROR_INVALID_KEY, "The key does not support the requested operation.")
+	cs (SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, "Certificate contains unknown critical extension.")
+	cs (SEC_ERROR_OLD_CRL, "New CRL is not later than the current one.")
+	cs (SEC_ERROR_NO_EMAIL_CERT, "Not encrypted or signed: you do not yet have an email certificate.")
+	cs (SEC_ERROR_NO_RECIPIENT_CERTS_QUERY, "Not encrypted: you do not have certificates for each of the recipients.")
+	cs (SEC_ERROR_NOT_A_RECIPIENT, "Cannot decrypt: you are not a recipient, or matching certificate and private key not found.")
+	cs (SEC_ERROR_PKCS7_KEYALG_MISMATCH, "Cannot decrypt: key encryption algorithm does not match your certificate.")
+	cs (SEC_ERROR_PKCS7_BAD_SIGNATURE, "Signature verification failed: no signer found, too many signers found, or improper or corrupted data.")
+	cs (SEC_ERROR_UNSUPPORTED_KEYALG, "Unsupported or unknown key algorithm.")
+	cs (SEC_ERROR_DECRYPTION_DISALLOWED, "Cannot decrypt: encrypted using a disallowed algorithm or key size.")
+	cs (XP_SEC_FORTEZZA_BAD_CARD, "Fortezza card has not been properly initialized.  Please remove it and return it to your issuer.")
+	cs (XP_SEC_FORTEZZA_NO_CARD, "No Fortezza cards Found")
+	cs (XP_SEC_FORTEZZA_NONE_SELECTED, "No Fortezza card selected")
+	cs (XP_SEC_FORTEZZA_MORE_INFO, "Please select a personality to get more info on")
+	cs (XP_SEC_FORTEZZA_PERSON_NOT_FOUND, "Personality not found")
+	cs (XP_SEC_FORTEZZA_NO_MORE_INFO, "No more information on that Personality")
+	cs (XP_SEC_FORTEZZA_BAD_PIN, "Invalid Pin")
+	cs (XP_SEC_FORTEZZA_PERSON_ERROR, "Couldn't initialize Fortezza personalities.")
+	cs (SEC_ERROR_NO_KRL, "No KRL for this site's certificate has been found.")
+	cs (SEC_ERROR_KRL_EXPIRED, "The KRL for this site's certificate has expired.")
+	cs (SEC_ERROR_KRL_BAD_SIGNATURE, "The KRL for this site's certificate has an invalid signature.")
+	cs (SEC_ERROR_REVOKED_KEY, "The key for this site's certificate has been revoked.")
+	cs (SEC_ERROR_KRL_INVALID, "New KRL has an invalid format.")
+	cs (SEC_ERROR_NEED_RANDOM, "security library: need random data.")
+	cs (SEC_ERROR_NO_MODULE, "security library: no security module can perform the requested operation.")
+	cs (SEC_ERROR_NO_TOKEN, "The security card or token does not exist, needs to be initialized, or has been removed.")
+	cs (SEC_ERROR_READ_ONLY, "security library: read-only database.")
+	cs (SEC_ERROR_NO_SLOT_SELECTED, "No slot or token was selected.")
+	cs (SEC_ERROR_CERT_NICKNAME_COLLISION, "A certificate with the same nickname already exists.")
+	cs (SEC_ERROR_KEY_NICKNAME_COLLISION, "A key with the same nickname already exists.")
+	cs (SEC_ERROR_SAFE_NOT_CREATED, "error while creating safe object")
+	cs (SEC_ERROR_BAGGAGE_NOT_CREATED, "error while creating baggage object")
+	cs (XP_JAVA_REMOVE_PRINCIPAL_ERROR, "Couldn't remove the principal")
+	cs (XP_JAVA_DELETE_PRIVILEGE_ERROR, "Couldn't delete the privilege")
+	cs (XP_JAVA_CERT_NOT_EXISTS_ERROR, "This principal doesn't have a certificate")
+	cs (SEC_ERROR_BAD_EXPORT_ALGORITHM, "Required algorithm is not allowed.")
+	cs (SEC_ERROR_EXPORTING_CERTIFICATES, "Error attempting to export certificates.")
+	cs (SEC_ERROR_IMPORTING_CERTIFICATES, "Error attempting to import certificates.")
+	cs (SEC_ERROR_PKCS12_DECODING_PFX, "Unable to import.  Decoding error.  File not valid.")
+	cs (SEC_ERROR_PKCS12_INVALID_MAC, "Unable to import.  Invalid MAC.  Incorrect password or corrupt file.")
+	cs (SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, "Unable to import.  MAC algorithm not supported.")
+	cs (SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE, "Unable to import.  Only password integrity and privacy modes supported.")
+	cs (SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, "Unable to import.  File structure is corrupt.")
+	cs (SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, "Unable to import.  Encryption algorithm not supported.")
+	cs (SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, "Unable to import.  File version not supported.")
+	cs (SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT, "Unable to import.  Incorrect privacy password.")
+	cs (SEC_ERROR_PKCS12_CERT_COLLISION, "Unable to import.  Same nickname already exists in database.")
+	cs (SEC_ERROR_USER_CANCELLED, "The user pressed cancel.")
+	cs (SEC_ERROR_PKCS12_DUPLICATE_DATA, "Not imported, already in database.")
+	cs (SEC_ERROR_MESSAGE_SEND_ABORTED, "Message not sent.")
+	cs (SEC_ERROR_INADEQUATE_KEY_USAGE, "Certificate key usage inadequate for attempted operation.")
+	cs (SEC_ERROR_INADEQUATE_CERT_TYPE, "Certificate type not approved for application.")
+	cs (SEC_ERROR_CERT_ADDR_MISMATCH, "Address in signing certificate does not match address in message headers.")
+	cs (SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, "Unable to import.  Error attempting to import private key.")
+	cs (SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, "Unable to import.  Error attempting to import certificate chain.")
+	cs (SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, "Unable to export.  Unable to locate certificate or key by nickname.")
+	cs (SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, "Unable to export.  Private Key could not be located and exported.")
+	cs (SEC_ERROR_PKCS12_UNABLE_TO_WRITE, "Unable to export.  Unable to write the export file.")
+	cs (SEC_ERROR_PKCS12_UNABLE_TO_READ, "Unable to import.  Unable to read the import file.")
+	cs (SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, "Unable to export.  Key database corrupt or deleted.")
+	cs (SEC_ERROR_KEYGEN_FAIL, "Unable to generate public/private key pair.")
+	cs (SEC_ERROR_INVALID_PASSWORD, "Password entered is invalid.  Please pick a different one.")
+	cs (SEC_ERROR_RETRY_OLD_PASSWORD, "Old password entered incorrectly.  Please try again.")
+	cs (SEC_ERROR_BAD_NICKNAME, "Certificate nickname already in use.")
+	cs (SEC_ERROR_NOT_FORTEZZA_ISSUER, "Peer FORTEZZA chain has a non-FORTEZZA Certificate.")
+	cs (SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY, "A sensitive key cannot be moved to the slot where it is needed.")
+	cs (SEC_ERROR_JS_INVALID_MODULE_NAME, "Invalid module name.")
+	cs (SEC_ERROR_JS_INVALID_DLL, "Invalid module path/filename")
+	cs (SEC_ERROR_JS_ADD_MOD_FAILURE, "Unable to add module")
+	cs (SEC_ERROR_JS_DEL_MOD_FAILURE, "Unable to delete module")
+	cs (SEC_ERROR_OLD_KRL, "New KRL is not later than the current one.")
+	cs (SEC_ERROR_CKL_CONFLICT, "New CKL has different issuer than current CKL.  Delete current CKL.")
+	cs (SEC_ERROR_CERT_NOT_IN_NAME_SPACE, "The Certifying Authority for this certificate is not permitted to issue a certificate with this name.")
+	cs (SEC_ERROR_KRL_NOT_YET_VALID, "The key revocation list for this certificate is not yet valid.")
+	cs (SEC_ERROR_CRL_NOT_YET_VALID, "The certificate revocation list for this certificate is not yet valid.")
+	cs (SEC_ERROR_UNKNOWN_CERT, "The requested certificate could not be found.")
+	cs (SEC_ERROR_UNKNOWN_SIGNER, "The signer's certificate could not be found.")
+	cs (SEC_ERROR_CERT_BAD_ACCESS_LOCATION,	 "The location for the certificate status server has invalid format.")
+	cs (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE, "The OCSP response cannot be fully decoded; it is of an unknown type.")
+	cs (SEC_ERROR_OCSP_BAD_HTTP_RESPONSE, "The OCSP server returned unexpected/invalid HTTP data.")
+	cs (SEC_ERROR_OCSP_MALFORMED_REQUEST, "The OCSP server found the request to be corrupted or improperly formed.")
+	cs (SEC_ERROR_OCSP_SERVER_ERROR, "The OCSP server experienced an internal error.")
+	cs (SEC_ERROR_OCSP_TRY_SERVER_LATER, "The OCSP server suggests trying again later.")
+	cs (SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, "The OCSP server requires a signature on this request.")
+	cs (SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, "The OCSP server has refused this request as unauthorized.")
+	cs (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, "The OCSP server returned an unrecognizable status.")
+	cs (SEC_ERROR_OCSP_UNKNOWN_CERT, "The OCSP server has no status for the certificate.")
+	cs (SEC_ERROR_OCSP_NOT_ENABLED, "You must enable OCSP before performing this operation.")
+	cs (SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER, "You must set the OCSP default responder before performing this operation.")
+	cs (SEC_ERROR_OCSP_MALFORMED_RESPONSE, "The response from the OCSP server was corrupted or improperly formed.")
+	cs (SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE, "The signer of the OCSP response is not authorized to give status for this certificate.")
+	cs (SEC_ERROR_OCSP_FUTURE_RESPONSE, "The OCSP response is not yet valid (contains a date in the future).")
+	cs (SEC_ERROR_OCSP_OLD_RESPONSE, "The OCSP response contains out-of-date information.")
+	cs (SEC_ERROR_DIGEST_NOT_FOUND, "The CMS or PKCS #7 Digest was not found in signed message.")
+	cs (SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE, "The CMS or PKCS #7 Message type is unsupported.")
+	cs (SEC_ERROR_MODULE_STUCK, "PKCS #11 module could not be removed because it is still in use.")
+	cs (SEC_ERROR_BAD_TEMPLATE, "Could not decode ASN.1 data. Specified template was invalid.")
+	cs (SEC_ERROR_CRL_NOT_FOUND, "No matching CRL was found.")
+	cs (SEC_ERROR_REUSED_ISSUER_AND_SERIAL, "You are attempting to import a cert with the same issuer/serial as an existing cert, but that is not the same cert.")
+	cs (SEC_ERROR_BUSY, "NSS could not shutdown. Objects are still in use.")
+	cs (SEC_ERROR_EXTRA_INPUT, "DER-encoded message contained extra unused data.")
+	cs (SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE, "Unsupported elliptic curve.")
+	cs (SEC_ERROR_UNSUPPORTED_EC_POINT_FORM, "Unsupported elliptic curve point form.")
+	cs (SEC_ERROR_UNRECOGNIZED_OID, "Unrecognized Object Identifier.")
+	cs (SEC_ERROR_OCSP_INVALID_SIGNING_CERT, "Invalid OCSP signing certificate in OCSP response.")
+	cs (SEC_ERROR_REVOKED_CERTIFICATE_CRL, "Certificate is revoked in issuer's certificate revocation list.")
+	cs (SEC_ERROR_REVOKED_CERTIFICATE_OCSP, "Issuer's OCSP responder reports certificate is revoked.")
+	cs (SEC_ERROR_CRL_INVALID_VERSION, "Issuer's Certificate Revocation List has an unknown version number.")
+	cs (SEC_ERROR_CRL_V1_CRITICAL_EXTENSION, "Issuer's V1 Certificate Revocation List has a critical extension.")
+	cs (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION, "Issuer's V2 Certificate Revocation List has an unknown critical extension.")
+	cs (SEC_ERROR_UNKNOWN_OBJECT_TYPE, "Unknown object type specified.")
+	cs (SEC_ERROR_INCOMPATIBLE_PKCS11, "PKCS #11 driver violates the spec in an incompatible way.")
+	cs (SEC_ERROR_NO_EVENT, "No new slot event is available at this time.")
+	cs (SEC_ERROR_CRL_ALREADY_EXISTS, "CRL already exists.")
+	cs (SEC_ERROR_NOT_INITIALIZED, "NSS is not initialized.")
+	cs (SEC_ERROR_TOKEN_NOT_LOGGED_IN, "The operation failed because the PKCS#11 token is not logged in.")
+	cs (SEC_ERROR_OCSP_RESPONDER_CERT_INVALID, "Configured OCSP responder's certificate is invalid.")
+	cs (SEC_ERROR_OCSP_BAD_SIGNATURE, "OCSP response has an invalid signature.")
+
+	#if defined (NSS_VMAJOR) && defined (NSS_VMINOR) && defined (NSS_VPATCH) && (NSS_VMAJOR > 3 || (NSS_VMAJOR == 3 && NSS_VMINOR > 12) || (NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH >= 2))
+	cs (SEC_ERROR_OUT_OF_SEARCH_LIMITS, "Cert validation search is out of search limits")
+	cs (SEC_ERROR_INVALID_POLICY_MAPPING, "Policy mapping contains anypolicy")
+	cs (SEC_ERROR_POLICY_VALIDATION_FAILED, "Cert chain fails policy validation")
+	cs (SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE, "Unknown location type in cert AIA extension")
+	cs (SEC_ERROR_BAD_HTTP_RESPONSE, "Server returned bad HTTP response")
+	cs (SEC_ERROR_BAD_LDAP_RESPONSE, "Server returned bad LDAP response")
+	cs (SEC_ERROR_FAILED_TO_ENCODE_DATA, "Failed to encode data with ASN1 encoder")
+	cs (SEC_ERROR_BAD_INFO_ACCESS_LOCATION, "Bad information access location in cert extension")
+	cs (SEC_ERROR_LIBPKIX_INTERNAL, "Libpkix internal error occured during cert validation.")
+	cs (SEC_ERROR_PKCS11_GENERAL_ERROR, "A PKCS #11 module returned CKR_GENERAL_ERROR, indicating that an unrecoverable error has occurred.")
+	cs (SEC_ERROR_PKCS11_FUNCTION_FAILED, "A PKCS #11 module returned CKR_FUNCTION_FAILED, indicating that the requested function could not be performed.  Trying the same operation again might succeed.")
+	cs (SEC_ERROR_PKCS11_DEVICE_ERROR, "A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem has occurred with the token or slot.")
+	#endif
+	}
+
+	#undef cs
+
+	return NULL;
+}
+
+static void
+set_nss_error (GError **error)
+{
+	glong err_code;
+	const gchar *err_str;
+
+	if (!error)
+		return;
+
+	g_return_if_fail (*error == NULL);
+
+	err_code = PORT_GetError ();
+
+	if (!err_code)
+		return;
+
+	err_str = nss_error_to_string (err_code);
+	if (!err_str)
+		return;
+
+	*error = g_error_new_literal (E_CERTDB_ERROR, err_code, err_str);
+}
+
 static SECStatus PR_CALLBACK
 collect_certs(gpointer arg, SECItem **certs, gint numcerts)
 {
@@ -437,7 +656,7 @@ e_cert_db_find_cert_by_nickname (ECertDB *certdb,
 		return ecert;
 	}
 	else {
-		/* XXX gerror */
+		set_nss_error (error);
 		return NULL;
 	}
 }
@@ -456,7 +675,7 @@ e_cert_db_find_cert_by_key (ECertDB *certdb,
 	CERTCertificate *cert;
 
 	if (!db_key) {
-		/* XXX gerror */
+		set_nss_error (error);
 		return NULL;
 	}
 
@@ -481,7 +700,7 @@ e_cert_db_find_cert_by_key (ECertDB *certdb,
 		return e_cert;
 	}
 
-	/* XXX gerror */
+	set_nss_error (error);
 	return NULL;
 }
 
@@ -521,7 +740,7 @@ e_cert_db_find_cert_by_email_address (ECertDB *certdb,
 		CERT_GetDefaultCertDB(), (gchar *) email);
 
 	if (!any_cert) {
-		/* XXX gerror */
+		set_nss_error (error);
 		return NULL;
 	}
 
@@ -532,21 +751,21 @@ e_cert_db_find_cert_by_email_address (ECertDB *certdb,
 					      &any_cert->derSubject,
 					      PR_Now(), PR_TRUE);
 	if (!certlist) {
-		/* XXX gerror */
+		set_nss_error (error);
 		CERT_DestroyCertificate(any_cert);
 		return NULL;
 	}
 
 	if (SECSuccess != CERT_FilterCertListByUsage (
 		certlist, certUsageEmailRecipient, PR_FALSE)) {
-		/* XXX gerror */
+		set_nss_error (error);
 		CERT_DestroyCertificate(any_cert);
 		CERT_DestroyCertList (certlist);
 		return NULL;
 	}
 
 	if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist)) {
-		/* XXX gerror */
+		set_nss_error (error);
 		CERT_DestroyCertificate(any_cert);
 		CERT_DestroyCertList (certlist);
 		return NULL;
@@ -653,12 +872,12 @@ handle_ca_cert_download(ECertDB *cert_db, GList *certs, GError **error)
 	}
 
 	if (!certToShow) {
-		/* XXX gerror */
+		set_nss_error (error);
 		return FALSE;
 	}
 
 	if (!e_cert_get_raw_der (certToShow, &raw_der, &der.len)) {
-		/* XXX gerror */
+		set_nss_error (error);
 		return FALSE;
 	}
 
@@ -674,6 +893,7 @@ handle_ca_cert_download(ECertDB *cert_db, GList *certs, GError **error)
 		}
 		if (!tmpCert) {
 			g_warning ("Couldn't create cert from DER blob");
+			set_nss_error (error);
 			return FALSE;
 		}
 	}
@@ -683,9 +903,8 @@ handle_ca_cert_download(ECertDB *cert_db, GList *certs, GError **error)
 #endif
 
 	if (tmpCert->isperm) {
-		/* XXX we shouldn't be popping up dialogs in this code. */
-		e_notice (NULL, GTK_MESSAGE_WARNING, _("Certificate already exists"));
-		/* XXX gerror */
+		if (error && !*error)
+			*error = g_error_new_literal (E_CERTDB_ERROR, 0, _("Certificate already exists"));
 		return FALSE;
 	}
 	else {
@@ -697,7 +916,7 @@ handle_ca_cert_download(ECertDB *cert_db, GList *certs, GError **error)
 		if (!confirm_download_ca_cert (
 			cert_db, certToShow, &trust_ssl,
 			&trust_email, &trust_objsign)) {
-			/* XXX gerror */
+			set_nss_error (error);
 			return FALSE;
 		}
 
@@ -718,8 +937,8 @@ handle_ca_cert_download(ECertDB *cert_db, GList *certs, GError **error)
 					     nickname,
 					     &trust);
 
-		if (srv != SECSuccess) {
-			/* XXX gerror */
+		if (srv != SECSuccess && PORT_GetError() != SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
+			set_nss_error (error);
 			return FALSE;
 		}
 
@@ -763,7 +982,7 @@ e_cert_db_delete_cert (ECertDB *certdb,
 	    nsNSSCertificate *nssCert = NS_STATIC_CAST(nsNSSCertificate*, aCert); */
 
 	CERTCertificate *cert;
-	SECStatus srv = SECSuccess;
+
 	if (!e_cert_mark_for_deletion (ecert)) {
 		return FALSE;
 	}
@@ -780,12 +999,11 @@ e_cert_db_delete_cert (ECertDB *certdb,
 		CERTCertTrust trust;
 
 		e_cert_trust_init_with_values (&trust, 0, 0, 0);
-		srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
+		CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
 					   cert, &trust);
 	}
 
-	/*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("cert deleted: %d", srv));*/
-	return (srv) ? FALSE : TRUE;
+	return TRUE;
 }
 
 /* importing certificates */
@@ -793,6 +1011,7 @@ gboolean
 e_cert_db_import_certs (ECertDB *certdb,
 			gchar *data, guint32 length,
 			ECertType cert_type,
+			GSList **imported_certs,
 			GError **error)
 {
 	/*nsNSSShutDownPreventionLock locker;*/
@@ -803,7 +1022,7 @@ e_cert_db_import_certs (ECertDB *certdb,
 	gboolean rv;
 
 	if (!certCollection) {
-		/* XXX gerror */
+		set_nss_error (error);
 		PORT_FreeArena(arena, PR_FALSE);
 		return FALSE;
 	}
@@ -815,7 +1034,7 @@ e_cert_db_import_certs (ECertDB *certdb,
 
 		cert = e_cert_new_from_der ((gchar *)currItem->data, currItem->len);
 		if (!cert) {
-			/* XXX gerror */
+			set_nss_error (error);
 			g_list_foreach (certs, (GFunc)g_object_unref, NULL);
 			g_list_free (certs);
 			PORT_FreeArena(arena, PR_FALSE);
@@ -826,10 +1045,24 @@ e_cert_db_import_certs (ECertDB *certdb,
 	switch (cert_type) {
 	case E_CERT_CA:
 		rv = handle_ca_cert_download(certdb, certs, error);
+		if (rv && imported_certs) {
+			GList *l;
+
+			/* copy certificates to the caller */
+			*imported_certs = NULL;
+			for (l = certs; l; l = l->next) {
+				ECert *cert = l->data;
+
+				if (cert)
+					*imported_certs = g_slist_prepend (*imported_certs, g_object_ref (cert));
+			}
+
+			*imported_certs = g_slist_reverse (*imported_certs);
+		}
 		break;
 	default:
 		/* We only deal with import CA certs in this method currently.*/
-		/* XXX gerror */
+		set_nss_error (error);
 		PORT_FreeArena(arena, PR_FALSE);
 		rv = FALSE;
 	}
@@ -843,6 +1076,7 @@ e_cert_db_import_certs (ECertDB *certdb,
 gboolean
 e_cert_db_import_email_cert (ECertDB *certdb,
 			     gchar *data, guint32 length,
+			     GSList **imported_certs,
 			     GError **error)
 {
 	/*nsNSSShutDownPreventionLock locker;*/
@@ -856,8 +1090,7 @@ e_cert_db_import_email_cert (ECertDB *certdb,
 	CERTDERCerts *certCollection = e_cert_db_get_certs_from_package (arena, data, length);
 
 	if (!certCollection) {
-		/* XXX g_error */
-
+		set_nss_error (error);
 		PORT_FreeArena(arena, PR_FALSE);
 		return FALSE;
 	}
@@ -865,14 +1098,14 @@ e_cert_db_import_email_cert (ECertDB *certdb,
 	cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certCollection->rawCerts,
 				       (gchar *)NULL, PR_FALSE, PR_TRUE);
 	if (!cert) {
-		/* XXX g_error */
+		set_nss_error (error);
 		rv = FALSE;
 		goto loser;
 	}
 	numcerts = certCollection->numcerts;
 	rawCerts = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts);
 	if (!rawCerts) {
-		/* XXX g_error */
+		set_nss_error (error);
 		rv = FALSE;
 		goto loser;
 	}
@@ -885,11 +1118,26 @@ e_cert_db_import_email_cert (ECertDB *certdb,
 			       numcerts, rawCerts, NULL, PR_TRUE, PR_FALSE,
 			       NULL);
 	if (srv != SECSuccess) {
-		/* XXX g_error */
+		set_nss_error (error);
 		rv = FALSE;
 		goto loser;
 	}
 	CERT_SaveSMimeProfile(cert, NULL, NULL);
+
+	if (imported_certs) {
+		*imported_certs = NULL;
+		for (i = 0; i < certCollection->numcerts; i++) {
+			SECItem *currItem = &certCollection->rawCerts[i];
+			ECert *cert;
+
+			cert = e_cert_new_from_der ((gchar *)currItem->data, currItem->len);
+			if (cert)
+				*imported_certs = g_slist_prepend (*imported_certs, cert);
+		}
+
+		*imported_certs = g_slist_reverse (*imported_certs);
+	}
+
 	PORT_Free(rawCerts);
  loser:
 	if (cert)
@@ -1041,26 +1289,26 @@ e_cert_db_import_user_cert (ECertDB *certdb,
 
 	arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 	if (arena == NULL) {
-		/* XXX g_error */
+		set_nss_error (error);
 		goto loser;
 	}
 
 	collectArgs = e_cert_db_get_certs_from_package (arena, data, length);
 	if (!collectArgs) {
-		/* XXX g_error */
+		set_nss_error (error);
 		goto loser;
 	}
 
 	cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts,
 				       (gchar *)NULL, PR_FALSE, PR_TRUE);
 	if (!cert) {
-		/* XXX g_error */
+		set_nss_error (error);
 		goto loser;
 	}
 
 	slot = PK11_KeyForCertExists(cert, NULL, NULL);
 	if (slot == NULL) {
-		/* XXX g_error */
+		set_nss_error (error);
 		goto loser;
 	}
 	PK11_FreeSlot(slot);
@@ -1079,7 +1327,7 @@ e_cert_db_import_user_cert (ECertDB *certdb,
 	/* user wants to import the cert */
 	slot = PK11_ImportCertForKey(cert, nickname, NULL);
 	if (!slot) {
-		/* XXX g_error */
+		set_nss_error (error);
 		goto loser;
 	}
 	PK11_FreeSlot(slot);
@@ -1105,6 +1353,7 @@ e_cert_db_import_user_cert (ECertDB *certdb,
 gboolean
 e_cert_db_import_server_cert (ECertDB *certdb,
 			      gchar *data, guint32 length,
+			      GSList **imported_certs,
 			      GError **error)
 {
 	/* not c&p'ing this over at the moment, as we don't have a UI
@@ -1116,6 +1365,7 @@ gboolean
 e_cert_db_import_certs_from_file (ECertDB *cert_db,
 				  const gchar *file_path,
 				  ECertType cert_type,
+				  GSList **imported_certs,
 				  GError **error)
 {
 	gboolean rv;
@@ -1133,25 +1383,25 @@ e_cert_db_import_certs_from_file (ECertDB *cert_db,
 
 	default:
 		/* not supported (yet) */
-		/* XXX gerror */
+		set_nss_error (error);
 		return FALSE;
 	}
 
 	fd = g_open (file_path, O_RDONLY|O_BINARY, 0);
 	if (fd == -1) {
-		/* XXX gerror */
+		set_nss_error (error);
 		return FALSE;
 	}
 
 	if (-1 == fstat (fd, &sb)) {
-		/* XXX gerror */
+		set_nss_error (error);
 		close (fd);
 		return FALSE;
 	}
 
 	buf = g_malloc (sb.st_size);
 	if (!buf) {
-		/* XXX gerror */
+		set_nss_error (error);
 		close (fd);
 		return FALSE;
 	}
@@ -1161,7 +1411,7 @@ e_cert_db_import_certs_from_file (ECertDB *cert_db,
 	close (fd);
 
 	if (bytes_read != sb.st_size) {
-		/* XXX gerror */
+		set_nss_error (error);
 		rv = FALSE;
 	}
 	else {
@@ -1169,15 +1419,15 @@ e_cert_db_import_certs_from_file (ECertDB *cert_db,
 
 		switch (cert_type) {
 		case E_CERT_CA:
-			rv = e_cert_db_import_certs (cert_db, buf, bytes_read, cert_type, error);
+			rv = e_cert_db_import_certs (cert_db, buf, bytes_read, cert_type, imported_certs, error);
 			break;
 
 		case E_CERT_SITE:
-			rv = e_cert_db_import_server_cert (cert_db, buf, bytes_read, error);
+			rv = e_cert_db_import_server_cert (cert_db, buf, bytes_read, imported_certs, error);
 			break;
 
 		case E_CERT_CONTACT:
-			rv = e_cert_db_import_email_cert (cert_db, buf, bytes_read, error);
+			rv = e_cert_db_import_email_cert (cert_db, buf, bytes_read, imported_certs, error);
 			break;
 
 		default:
diff --git a/smime/lib/e-cert-db.h b/smime/lib/e-cert-db.h
index 0e19e00..7d5f185 100644
--- a/smime/lib/e-cert-db.h
+++ b/smime/lib/e-cert-db.h
@@ -34,6 +34,9 @@
 #define E_IS_CERT_DB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CERT_DB))
 #define E_CERT_DB_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CERT_DB, ECertDBClass))
 
+#define E_CERTDB_ERROR e_certdb_error_quark()
+GQuark e_certdb_error_quark (void) G_GNUC_CONST;
+
 typedef struct _ECertDB ECertDB;
 typedef struct _ECertDBClass ECertDBClass;
 typedef struct _ECertDBPrivate ECertDBPrivate;
@@ -102,10 +105,12 @@ gboolean             e_cert_db_delete_cert (ECertDB *certdb,
 gboolean             e_cert_db_import_certs (ECertDB *certdb,
 					     gchar *data, guint32 length,
 					     ECertType cert_type,
+					     GSList **imported_certs,
 					     GError **error);
 
 gboolean             e_cert_db_import_email_cert (ECertDB *certdb,
 						  gchar *data, guint32 length,
+						  GSList **imported_certs,
 						  GError **error);
 
 gboolean             e_cert_db_import_user_cert (ECertDB *certdb,
@@ -114,11 +119,13 @@ gboolean             e_cert_db_import_user_cert (ECertDB *certdb,
 
 gboolean             e_cert_db_import_server_cert (ECertDB *certdb,
 						   gchar *data, guint32 length,
+						   GSList **imported_certs,
 						   GError **error);
 
 gboolean             e_cert_db_import_certs_from_file (ECertDB *cert_db,
 						       const gchar *file_path,
 						       ECertType cert_type,
+						       GSList **imported_certs,
 						       GError **error);
 
 gboolean             e_cert_db_import_pkcs12_file (ECertDB *cert_db,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]