soc.2008.masterpassword: e1abb37b: Final version of the API, corrected, cle...

scrouaf at soc.pidgin.im scrouaf at soc.pidgin.im
Tue Aug 5 08:41:38 EDT 2008


-----------------------------------------------------------------
Revision: e1abb37bd2f4911089b91dc5efc4b6ae05a376fc
Ancestor: 8ec70a9c5c00d55617f0638c9afcb24e873db681
Author: scrouaf at soc.pidgin.im
Date: 2008-08-04T22:26:21
Branch: im.pidgin.soc.2008.masterpassword
URL: http://d.pidgin.im/viewmtn/revision/info/e1abb37bd2f4911089b91dc5efc4b6ae05a376fc

Modified files:
        libpurple/keyring.c libpurple/keyring.h

ChangeLog: 

Final version of the API, corrected, cleaned, and documented.


-------------- next part --------------
============================================================
--- libpurple/keyring.c	b9e43ecc5ffd9d4aa697dd316db6da98213f9269
+++ libpurple/keyring.c	f3ca027916718615c3fcb40f1bcb27f1a83db8b0
@@ -1,5 +1,9 @@
 /**
  * @file keyring.c Keyring plugin API
+ * @todo
+ *  - purple_keyring_set_inuse()
+ *  - loading : find a way to fallback
+ *  - purple_keyring_drop()
  */
 
 /* purple
@@ -19,69 +23,302 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
+ * along with this program ; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
-
-/**
- * Most functions in this files are :
- *  - wrappers that will call the plugin
- *  - keyring managment stuff
- *  - accessors
- *
- * TODO :
- *  - unregister
- *  - use accessors
- *  - purple_keyring_init()
- *  - purple_keyring_set_inuse() needs to be async for error checking and reversability.
- *
- * Questions :
- *  - cleanup
- *  - warning
- *  - breaking API
- */
-
 #include <glib.h>
+#include "account.h"
 #include "keyring.h"
-#include "account.h"
+#include "signals.h"
+#include "core.h"
 
-/*******************************/
-/* opaque structures           */
-/*******************************/
+#define FALLBACK_KEYRING	"core-scrouaf-internalkeyring"
 
-/* used to import and export password info */
-struct _PurpleKeyringPasswordNode
+/******************************************/
+/** @name PurpleKeyring                   */
+/******************************************/
+/*@{*/
+
+struct _PurpleKeyring
 {
-	PurpleAccount * account;
-	const char * encryption;
-	const char * mode;
-	const char * data;
-/**
- * strings cannot be modified.
- * all are static excpet data
- */
+	char * name;		// same as plugin id
+	PurpleKeyringRead read_password;
+	PurpleKeyringSave save_password;
+	PurpleKeyringClose close_keyring;
+	PurpleKeyringChangeMaster change_master;
+	PurpleKeyringImportPassword import_password;
+	PurpleKeyringExportPassword export_password;
+	PurpleKeyringReadSync read_sync;
+	PurpleKeyringSaveSync save_sync;
+	gpointer r1;	/* RESERVED */
+	gpointer r2;	/* RESERVED */
+	gpointer r3;	/* RESERVED */
 };
 
 
-/*******************************/
-/* globals                     */
-/*******************************/
+/* Constructor */
+PurpleKeyring * 
+purple_keyring_new()
+{
+	return g_malloc(sizeof(PurpleKeyring));
+}
 
-GList * purple_keyring_keyringlist = NULL;	/* list of available keyrings 	*/
-PurpleKeyring * purple_keyring_inuse = NULL;	/* keyring being used		*/
+/* Destructor */
+void 
+purple_keyring_free(PurpleKeyring * keyring)
+{
+	g_free(keyring);
+	return;
+}
 
+/* Accessors */
+const char * 
+purple_keyring_get_name(const PurpleKeyring * keyring)
+{
+	g_return_val_if_fail(keyring != NULL, NULL);
 
-/*******************************/
-/* functions                   */
-/*******************************/
+	return keyring->name;
+}
 
-/* manipulate keyring list, used by config interface */
+PurpleKeyringRead 
+purple_keyring_get_read_password(const PurpleKeyring * keyring)
+{
+	g_return_val_if_fail(keyring != NULL, NULL);
 
+	return keyring->read_password;
+}
+
+PurpleKeyringSave 
+purple_keyring_get_save_password(const PurpleKeyring * keyring)
+{
+	g_return_val_if_fail(keyring != NULL, NULL);
+
+	return keyring->save_password;
+}
+
+PurpleKeyringReadSync
+purple_keyring_get_read_sync(const PurpleKeyring * keyring)
+{
+	g_return_val_if_fail(keyring != NULL, NULL);
+
+	return keyring->read_sync;
+}
+
+PurpleKeyringSaveSync
+purple_keyring_get_save_sync(const PurpleKeyring * keyring)
+{
+	g_return_val_if_fail(keyring != NULL, NULL);
+
+	return keyring->save_sync;
+}
+
+PurpleKeyringClose 
+purple_keyring_get_close_keyring(const PurpleKeyring * keyring)
+{
+	g_return_val_if_fail(keyring != NULL, NULL);
+
+	return keyring->close_keyring;
+}
+
+PurpleKeyringChangeMaster 
+purple_keyring_get_change_master(const PurpleKeyring * keyring)
+{
+	g_return_val_if_fail(keyring != NULL, NULL);
+
+	return keyring->change_master;
+}
+
+PurpleKeyringImportPassword 
+purple_keyring_get_import_password(const PurpleKeyring * keyring)
+{
+	g_return_val_if_fail(keyring != NULL, NULL);
+
+	return keyring->import_password;
+}
+
+PurpleKeyringExportPassword 
+purple_keyring_get_export_password(const PurpleKeyring * keyring)
+{
+	g_return_val_if_fail(keyring != NULL, NULL);
+
+	return keyring->export_password;
+}
+
+void 
+purple_keyring_set_name(PurpleKeyring * keyring, char * name)
+{
+	g_return_if_fail(keyring != NULL);
+
+	g_free(keyring->name);
+	keyring->name = g_strdup(name);
+
+	return;
+}
+
+void
+purple_keyring_set_read_password(PurpleKeyring * keyring, PurpleKeyringRead read)
+{
+	g_return_if_fail(keyring != NULL);
+
+	keyring->read_password = read;
+
+	return;
+}
+
+void
+purple_keyring_set_save_password(PurpleKeyring * keyring, PurpleKeyringSave save)
+{
+	g_return_if_fail(keyring != NULL);
+
+	keyring->save_password = save;
+
+	return;
+}
+
+void 
+purple_keyring_set_read_sync(PurpleKeyring * keyring, PurpleKeyringReadSync read)
+{
+	g_return_if_fail(keyring != NULL);
+
+	keyring->read_sync = read;
+
+	return;
+}
+
+void 
+purple_keyring_set_save_sync(PurpleKeyring * keyring, PurpleKeyringSaveSync save)
+{
+	g_return_if_fail(keyring != NULL);
+
+	keyring->save_sync = save;
+
+	return;
+}
+
+void
+purple_keyring_set_close_keyring(PurpleKeyring * keyring, PurpleKeyringClose close)
+{
+	g_return_if_fail(keyring != NULL);
+
+	keyring->close_keyring = close;
+
+	return;
+}
+
+void
+purple_keyring_set_change_master(PurpleKeyring * keyring, PurpleKeyringChangeMaster change)
+{
+	g_return_if_fail(keyring != NULL);
+
+	keyring->change_master = change;
+
+	return;
+}
+
+void
+purple_keyring_set_import_password(PurpleKeyring * keyring, PurpleKeyringImportPassword import)
+{
+	g_return_if_fail(keyring != NULL);
+
+	keyring->import_password = import;
+
+	return;
+}
+
+void
+purple_keyring_set_export_password(PurpleKeyring * keyring, PurpleKeyringExportPassword export)
+{
+	g_return_if_fail(keyring != NULL);
+
+	keyring->export_password = export;
+
+	return;
+}
+
+/*@}*/
+
+
+/***************************************/
+/** @name Keyring API                  */
+/** @todo (maybe)                      */
+/**  - rename as purple_keyrings       */
+/***************************************/
+/*@{*/
+
+static GList * purple_keyring_keyrings;		/* list of available keyrings   */
+static const PurpleKeyring * purple_keyring_inuse;	/* keyring being used	        */
+static char * purple_keyring_to_use;
+
+
+void 
+purple_keyring_init()
+{
+	PurpleCore * core;
+	const char * touse;
+
+	/* Make sure we don't have junk */
+	purple_keyring_keyrings = NULL;
+	purple_keyring_inuse = NULL;
+
+	/* register signals */
+	core = purple_get_core();
+
+	purple_signal_register(core, "keyring-register",
+		purple_marshal_VOID__POINTER_POINTER, 
+		NULL, 2,
+		purple_value_new(PURPLE_TYPE_STRING),			/* keyring name */
+		purple_value_new(PURPLE_TYPE_BOXED, "PurpleKeyring *")); /* a pointer to the keyring */
+
+	purple_signal_register(core, "keyring-unregister",
+		purple_marshal_VOID__POINTER_POINTER, 
+		NULL, 2,
+		purple_value_new(PURPLE_TYPE_STRING),			/* keyring name */
+		purple_value_new(PURPLE_TYPE_BOXED, "PurpleKeyring *")); /* a pointer to the keyring */
+
+	/* see what keyring we want to use */
+	touse = purple_prefs_get_string("active-keyring");
+
+	if (touse == NULL) {
+
+		purple_keyring_to_use = g_strdup(FALLBACK_KEYRING);
+
+	} else {
+
+		purple_keyring_to_use = g_strdup(touse);
+	}
+
+	return;
+}
+
+void
+purple_keyring_uninit()
+{
+	g_free(purple_keyring_to_use);
+}
+
+static PurpleKeyring *
+purple_keyring_find_keyring_by_id(char * id)
+{
+	GList * l;
+	PurpleKeyring * keyring;
+	const char * name;
+
+	for (l = purple_keyring_keyrings; l != NULL; l = l->next) {
+		keyring = l->data;
+		name = purple_keyring_get_name(keyring);
+
+		if (strcmp(id, name) == 0)
+			return keyring;
+	}
+
+	return NULL;
+}
+
 const GList * 
-purple_keyring_get_keyringlist()
+purple_keyring_get_keyrings()
 {
-	return purple_keyring_keyringlist;
+	return purple_keyring_keyrings;
 }
 
 const PurpleKeyring * 
@@ -91,25 +328,44 @@ purple_keyring_get_inuse()
 }
 
 
-/**
- * If reading fails, export empty, issue warning, continue
- * If writing fails, abort.
- */
+/* fire and forget */
+/** @todo ? : add dummy callback ? */
+static void
+purple_keyring_drop_passwords(const PurpleKeyring * keyring)
+{
+	GList * cur;
+	PurpleKeyringSave save;
+
+	GError * error;
+
+	save = purple_keyring_get_save_password(keyring);
+
+	r_return_if_fail(save != NULL);
+
+	for (cur = purple_accounts_get_all(); 
+	     cur != NULL;
+	     cur = cur->next)
+		save(cur->data, "", NULL, NULL, NULL);
+
+	return;
+}
+
 struct _PurpleKeyringChangeTracker
 {
-	GError ** error;			// could probably be dropped
-	PurpleKeyringSetInUseCb cb;
+	GError * error;			// could probably be dropped
+	PurpleKeyringSetInUseCallback cb;
 	gpointer data;
-	PurpleKeyring * new;
-	PurpleKeyring * old;		// we are done when : finished == TRUE && read_outstanding == 0
+	const PurpleKeyring * new;
+	const PurpleKeyring * old;		// we are done when : finished == TRUE && read_outstanding == 0
 	int read_outstanding;
 	gboolean finished;
 	gboolean abort;
+	gboolean force;
 };
 
 void
 purple_keyring_set_inuse_check_error_cb(const PurpleAccount * account,
-					GError ** error,
+					GError * error,
 					gpointer data)
 {
 
@@ -119,53 +375,60 @@ purple_keyring_set_inuse_check_error_cb(
 
 	tracker = (struct _PurpleKeyringChangeTracker *)data;
 
+	g_return_if_fail(tracker->abort == FALSE);
+
+	tracker->read_outstanding--;
+
 	name = purple_account_get_username(account);
 
-	if ((error != NULL) && ((**error).domain == ERR_PIDGINKEYRING)) {
 
-		switch((**error).code) {
+	if ((error != NULL) && (error->domain == ERR_PIDGINKEYRING)) {
 
-			case ERR_NOPASSWD :
-				g_debug("No password found while changing keyring for account %s", name);
+		tracker->error = error;
+
+		switch(error->code) {
+
+			case ERR_NOCAP :
+				g_debug("Keyring could not save passwords : %s", name, error->message);
 				break;
 
-			case ERR_NOACCOUNT :
-				g_debug("No info on account %s found while changing keyring", name);
+			case ERR_NOPASSWD :
+				g_debug("No password found while changing keyring for account %s", name, error->message);
 				break;
 
 			case ERR_NOCHANNEL :
-				g_debug("Failed to communicate with backend while changing keyring for account %s, aborting change.", name);
+				g_debug("Failed to communicate with backend while changing keyring for account %s : %s Aborting changes.", name, error->message);
 				tracker->abort == TRUE;
 				break;
 
 			default :
-				// FIXME : display error string
-				g_debug("Unknown error while changing keyring for account %s", name);
+				g_debug("Unknown error while changing keyring for account %s : %s", name, error->message);
 				break;
 		}
 	}
 
 	/* if this was the last one */
-	if (tracker->finished == TRUE) && (tracker->read_outstanding == 0)) {
+	if (tracker->finished == TRUE && tracker->read_outstanding == 0) {
 	
-		if (tracker->abort == TRUE) {
-			
-			tracker->abort = TRUE;
+		if (tracker->abort == TRUE && tracker->force == FALSE) {
 
-			close = purple_keyring_get_close_keyring(tracker->old);
-			close(error);			
+			if (tracker->cb != NULL)
+				tracker->cb(tracker->old, FALSE, tracker->error, tracker->data);
 
-			g_free(tracker);
-			return;
-		} else {
+			purple_keyring_drop_passwords(tracker->new);
+
 			close = purple_keyring_get_close_keyring(tracker->new);
-			close(error);
+			if (close != NULL)
+				close(NULL);
 
-			tracker->cb(TRUE, error, tracker->data);
-			g_free(tracker);
-			return;
+		} else {
+			close = purple_keyring_get_close_keyring(tracker->old);
+			close(&error);
+
+			tracker->cb(tracker->new, TRUE, error, tracker->data);
 		}
 
+		g_free(tracker);
 	}
 	return;
 }
@@ -173,402 +436,552 @@ purple_keyring_set_inuse_got_pw_cb(const
 
 void
 purple_keyring_set_inuse_got_pw_cb(const PurpleAccount * account, 
-			 gchar * password, 
-			 GError ** error, 
-			 gpointer data)
+				  gchar * password, 
+				  GError * error, 
+				  gpointer data)
 {
-	PurpleKeyring * new;
+	const PurpleKeyring * new;
 	PurpleKeyringSave save;
 	struct _PurpleKeyringChangeTracker * tracker;
 
-	
 	tracker = (struct _PurpleKeyringChangeTracker *)data;
 	new = tracker->new;
 
-	/* XXX check for read error or just forward ? */
+	g_return_if_fail(tracker->abort == FALSE);
 
-	tracker->read_outstanding--;
-	
-	save = purple_keyring_get_save_password(new);
-	save(account, password, error, purple_keyring_set_inuse_check_error_cb, 
-		tracker);
+	if (error != NULL) {
 
+		if (error->code == ERR_NOPASSWD ||
+		    error->code == ERR_NOACCOUNT ||
+		    tracker->force == TRUE) {
+
+			/* don't save password, and directly trigger callback */
+			purple_keyring_set_inuse_check_error_cb(account, error, data);
+
+		} else {
+
+			/* fatal error, abort all */
+			tracker->abort = TRUE;
+		}
+
+	} else {
+
+		save = purple_keyring_get_save_password(new);
+
+		if (save != NULL) {
+			/* this test is probably totally useless, since there's no point
+			 * in having a keyring that can't store passwords, but it
+			 * will prevent crash with invalid keyrings
+			 */
+			save(account, password, NULL, 
+			     purple_keyring_set_inuse_check_error_cb, tracker);
+
+		} else {
+			error = g_error_new(ERR_PIDGINKEYRING , ERR_NOCAP,
+				"cannot store passwords in new keyring");
+			purple_keyring_set_inuse_check_error_cb(account, error, data);
+			g_error_free(error);
+		}
+	}
+
 	return;
 }
 
-/* FIXME : needs to be async and cancelable */
-/* PurpleKeyringSetInUseCb */
-void 
-purple_keyring_set_inuse(PurpleKeyring * new,
-			 GError ** error,
-			 PurpleKeyringSetInUseCb cb,
+
+
+
+void
+purple_keyring_set_inuse(const PurpleKeyring * newkeyring,
+			 gboolean force,
+			 PurpleKeyringSetInUseCallback cb,
 			 gpointer data)
 {
-
 	GList * cur;
-	const PurpleKeyring * old;
+	const PurpleKeyring * oldkeyring;
 	PurpleKeyringRead read;
+	PurpleKeyringClose close;
 	struct _PurpleKeyringChangeTracker * tracker;
+	GError * error;
 
+	read = purple_keyring_get_read_password(oldkeyring);
 
-	if (purple_keyring_inuse != NULL) {
+	if (read == NULL) {
+		error = g_error_new(ERR_PIDGINKEYRING , ERR_NOCAP,
+			"Existing keyring cannot read passwords");
+		g_debug("Existing keyring cannot read passwords");
 
+		/* at this point, we know the keyring won't let us
+		 * read passwords, so there no point in copying them.
+		 * therefore we just cleanup the old and setup the new 
+		 * one later.
+		 */
+
+		purple_keyring_drop_passwords(newkeyring);
+
+		close = purple_keyring_get_close_keyring(oldkeyring);
+
+		if (close != NULL)
+			close(NULL);	/* we can't do much about errors at this point*/
+
+	}
+
+	if (purple_keyring_inuse != NULL && read != NULL) {
+
 		tracker = g_malloc(sizeof(struct _PurpleKeyringChangeTracker));
-		old = purple_keyring_get_inuse();
+		oldkeyring = purple_keyring_get_inuse();
 
-		tracker->error = error;
 		tracker->cb = cb;
 		tracker->data = data;
-		tracker->new = new;
-		tracker->old = old;
+		tracker->new = newkeyring;
+		tracker->old = oldkeyring;
 		tracker->read_outstanding = 0;
 		tracker->finished = FALSE;
 		tracker->abort = FALSE;
+		tracker->force = force;
+		tracker->error = NULL;
 
 		for (cur = purple_accounts_get_all(); 
-		    (cur != NULL) && (tracker->abort != TRUE);
+		    (cur != NULL) && (tracker->abort == FALSE);
 		    cur = cur->next)
 		{
 			tracker->read_outstanding++;
 
-			if (cur->next == NULL) {
+			if (cur->next == NULL)
 				tracker->finished = TRUE;
-			}
 
-			read = purple_keyring_get_read_password(old);
-			read(cur->data, error, purple_keyring_set_inuse_got_pw_cb, tracker);
+			read(cur->data, purple_keyring_set_inuse_got_pw_cb, tracker);
 		}
 
 	} else { /* no keyring was set before. */
 
-		purple_keyring_inuse = new;
-		cb(data);
+		purple_keyring_inuse = newkeyring;
+
+		if (cb != NULL)
+			cb(newkeyring, TRUE, error, data);
+
+		g_error_free(error);
+
 		return;
 	}
 }
 
-/* register a keyring plugin */
-/**
- * XXX : function to unregister a keyring ?
- *	 validate input ? add magix field ?
- */
+
 void 
-purple_keyring_register(PurpleKeyring * info)
+purple_plugin_keyring_register(PurpleKeyring * keyring)
 {
-	// TODO : emit signal
-	purple_keyring_keyringlist = g_list_prepend(purple_keyring_keyringlist,
-		info);
+	const char * keyring_id;
+	PurpleCore * core;
+
+	g_return_if_fail(keyring != NULL);
+	
+	keyring_id = purple_keyring_get_name(keyring);
+
+	/* keyring with no name. Add error handling ? */
+	g_return_if_fail(keyring_id != NULL);
+
+	/* If this is the configured keyring, use it. */
+	if (purple_keyring_inuse == NULL &&
+	    strcmp(keyring_id, purple_keyring_to_use) == 0) {
+
+		/** @todo add callback to make sure all is ok */
+		purple_keyring_set_inuse(keyring, TRUE, NULL, NULL);
+
+	}
+
+	core = purple_get_core();
+
+	purple_signal_emit(core, "keyring-register", keyring_id, keyring);
+
+	purple_keyring_keyrings = g_list_prepend(purple_keyring_keyrings,
+		keyring);
 }
 
-purple_keyring_unregister(PurpleKeyring * info)
+
+void 
+purple_plugin_keyring_unregister(PurpleKeyring * keyring)
 {
-	
+	PurpleCore * core;
+	const PurpleKeyring * inuse;
+	PurpleKeyring * fallback;
+	const char * keyring_id;
+
+	core = purple_get_core();
+	keyring_id = purple_keyring_get_name(keyring);
+	purple_signal_emit(core, "keyring-unregister", keyring_id, keyring);
+
+	inuse = purple_keyring_get_inuse();
+
+	if (inuse == keyring) {
+		fallback = purple_keyring_find_keyring_by_id(FALLBACK_KEYRING);
+
+		/* this is problematic. If it fails, we won't detect it */
+		purple_keyring_set_inuse(fallback, TRUE, NULL, NULL);
+	}
+
+	purple_keyring_keyrings = g_list_remove(purple_keyring_keyrings,
+		keyring);
 }
-/**
- * wrappers to import and export passwords
- */
 
 
-/** 
- * used by account.c while reading a password from xml
- * might not really need to be async.
- * TODO : rewrite InternalKeyring as async
- */
-void
-purple_keyring_import_password(const PurpleKeyringPasswordNode * passwordnode,
-				GError ** error,
-				PurpleKeyringImportCallback cb,
-				gpointer data)
+/*@}*/
+
+
+/***************************************/
+/** @name Keyring plugin wrappers      */
+/***************************************/
+/*@{*/
+
+
+void purple_keyring_import_password(PurpleAccount * account, 
+				    char * keyringid,
+				    char * mode,
+				    char * data,
+				    GError ** error)
 {
+	const PurpleKeyring * inuse;
 	PurpleKeyringImportPassword import;
+	const char * realid;
 
-	if (purple_keyring_inuse == NULL) {
+	inuse = purple_keyring_get_inuse();
 
-		g_set_error(error, ERR_PIDGINKEYRING, ERR_NOKEYRING, 
-			"No Keyring configured.");
-		cb(error, data);
+	if (inuse == NULL) {
+		*error = g_error_new(ERR_PIDGINKEYRING , ERR_NOKEYRING,
+			"No keyring configured, cannot import password info");
+		g_debug("No keyring configured, cannot import password info");
+		return;
+	}
 
-	} else {
-		import = purple_keyring_get_import_password(purple_keyring_inuse);
-		import(passwordnode, error, cb, data);
+	realid = purple_keyring_get_name(inuse);
+	/*
+	 * we want to be sure that either :
+	 *  - there is a keyringid specified and it matches the one configured
+	 *  - or the configured keyring is the fallback, compatible one.
+	 */
+	if ((keyringid != NULL && strcmp(realid, keyringid) != 0) ||
+	    strcmp(FALLBACK_KEYRING, realid)) {
+		*error = g_error_new(ERR_PIDGINKEYRING , ERR_INVALID,
+			"Specified keyring id does not match the configured one.");
+		g_debug("Specified keyring id does not match the configured one.");
+		return;
 	}
+
+	import = purple_keyring_get_import_password(inuse);
+	if (import == NULL) {
+		*error = g_error_new(ERR_PIDGINKEYRING , ERR_NOCAP,
+			"Keyring cannot import password info.");
+		g_debug("Keyring cannot import password info. This might be normal");
+		return;
+	}
+	
+	import(account, mode, data, error);
+
 	return;
 }
 
-/* 
- * used by account.c while syncing accounts
- *  returned data must be g_free()'d
- */
-void
+void 
 purple_keyring_export_password(PurpleAccount * account,
+			       const char ** keyringid,
+			       const char ** mode,
+			       const char ** data,
 			       GError ** error,
-			       PurpleKeyringExportCallback cb,
-			       gpointer data)
+			       GDestroyNotify ** destroy)
 {
+	const PurpleKeyring * inuse;
 	PurpleKeyringExportPassword export;
+	const char * realid;
 
-	if (purple_keyring_inuse == NULL) {
+	inuse = purple_keyring_get_inuse();
 
-		g_set_error(error, ERR_PIDGINKEYRING, ERR_NOKEYRING, 
-			"No Keyring configured.");
-		cb(NULL, error, data);
+	if (inuse == NULL) {
+		*error = g_error_new(ERR_PIDGINKEYRING , ERR_NOKEYRING,
+			"No keyring configured, cannot import password info");
+		g_debug("No keyring configured, cannot import password info");
+		return;
+	}
 
-	} else {
-		export = purple_keyring_get_export_password(purple_keyring_inuse);
-		export(account, error, cb, data);
+	*keyringid = purple_keyring_get_name(inuse);
+
+	if (*keyringid == NULL) {
+		*error = g_error_new(ERR_PIDGINKEYRING , ERR_INVALID,
+			"Plugin does not have a keyring id");
+		g_debug("Plugin does not have a keyring id");
+		return;
 	}
+
+	export = purple_keyring_get_export_password(inuse);
+
+	if (export == NULL) {
+		*error = g_error_new(ERR_PIDGINKEYRING , ERR_NOCAP,
+			"Keyring cannot export password info.");
+		g_debug("Keyring cannot export password info. This might be normal");
+		return;
+	}
+
+	export(account, mode, data, error, destroy);
+
 	return;
 }
 
 
-/** 
- * functions called from the code to access passwords (account.h):
- *	purple_account_get_password()	<- TODO : rewrite these functions as asynch, as well as functions calling them. Will most likely break API compatibility.
- *	purple_account_set_password()
- * so these functions will call : 
+/**
+ * This should be renamed purple_keyring_get_password() when getting
+ * to 3.0, while dropping purple_keyring_get_password_sync().
  */
 void 
-purple_keyring_get_password(const PurpleAccount *account,
-			    GError ** error,
-			    PurpleKeyringReadCallback cb,
-			    gpointer data)
+purple_keyring_get_password_async(const PurpleAccount * account,
+				  PurpleKeyringReadCallback cb,
+				  gpointer data)
 {
+	GError * error = NULL;
+	const PurpleKeyring * inuse;
 	PurpleKeyringRead read;
 
-	if (purple_keyring_inuse == NULL) {
+	if (account == NULL) {
+		error = g_error_new(ERR_PIDGINKEYRING, ERR_INVALID,
+			"No account passed to the function.");
 
-		g_set_error(error, ERR_PIDGINKEYRING, ERR_NOKEYRING, 
-			"No Keyring configured.");
-		cb(account, NULL, error, data);
+		if (cb != NULL)
+			cb(account, NULL, error, data);
 
+		g_error_free(error);
+
 	} else {
+		inuse = purple_keyring_get_inuse();
 
-		read = purple_keyring_get_read_password(purple_keyring_inuse);
-		read(account, error, cb, data);
+		if (inuse == NULL) {
+			error = g_error_new(ERR_PIDGINKEYRING, ERR_NOKEYRING,
+				"No keyring configured.");
 
+			if (cb != NULL)
+				cb(account, NULL, error, data);
+
+			g_error_free(error);
+
+		} else {
+			read = purple_keyring_get_read_password(inuse);
+
+			if (read == NULL) {
+				error = g_error_new(ERR_PIDGINKEYRING, ERR_NOCAP,
+					"Keyring cannot read password.");
+
+				if (cb != NULL)
+					cb(account, NULL, error, data);
+
+				g_error_free(error);
+
+			} else {
+				read(account, cb, data);
+			}
+		}
 	}
+
 	return;
 }
 
+/**
+ * This should be renamed purple_keyring_set_password() when getting
+ * to 3.0, while dropping purple_keyring_set_password_sync().
+ */
 void 
-purple_keyring_set_password(const PurpleAccount * account, 
-			    gchar * password, 
-			    GError ** error, 
-			    PurpleKeyringSaveCallback cb,
-			    gpointer data)
+purple_keyring_set_password_async(const PurpleAccount * account, 
+				  gchar * password,
+				  GDestroyNotify destroypassword,
+				  PurpleKeyringSaveCallback cb,
+				  gpointer data)
 {
+	GError * error = NULL;
+	const PurpleKeyring * inuse;
 	PurpleKeyringSave save;
 
-	if (purple_keyring_inuse == NULL) {
+	if (account == NULL) {
+		error = g_error_new(ERR_PIDGINKEYRING, ERR_INVALID,
+			"No account passed to the function.");
 
-		g_set_error(error, ERR_PIDGINKEYRING, ERR_NOKEYRING, 
-				"No Keyring configured.");
-		cb(account, error, data);
+		if (cb != NULL)
+			cb(account, error, data);
 
+		g_error_free(error);
+
 	} else {
-		save = purple_keyring_get_save_password(purple_keyring_inuse);
-		save(account, password, error, cb, data);
+		inuse = purple_keyring_get_inuse();
+
+		if (inuse == NULL) {
+			error = g_error_new(ERR_PIDGINKEYRING, ERR_NOKEYRING,
+				"No keyring configured.");
+
+			if (cb != NULL)
+				cb(account, error, data);
+
+			g_error_free(error);
+
+		} else {
+			save = purple_keyring_get_save_password(inuse);
+
+			if (save == NULL) {
+				error = g_error_new(ERR_PIDGINKEYRING, ERR_NOCAP,
+					"Keyring cannot save password.");
+
+				if (cb != NULL)
+					cb(account, error, data);
+
+				g_error_free(error);
+
+			} else {
+				save(account, password, destroypassword, cb, data);
+			}
+		}
 	}
+
 	return;
 }
 
-/* accessors for data structure fields */
-	/* PurpleKeyring */
-const char *
-purple_keyring_get_name(const PurpleKeyring * info)
-{
-	return info->name;
-}
 
-PurpleKeyringRead 
-purple_keyring_get_read_password(const PurpleKeyring * info)
+/**
+ * This should be dropped at 3.0 (it's here for compatibility)
+ */
+const char * 
+purple_keyring_get_password_sync(const PurpleAccount * account)
 {
-	return info->read_password;
-}
+	PurpleKeyringReadSync read;
+	PurpleKeyring * keyring;
+	const PurpleKeyring * inuse;
 
-PurpleKeyringSave
-purple_keyring_get_save_password(const PurpleKeyring * info)
-{
-	return info->save_password;
-}
+	if (account == NULL) {
+		return NULL;
 
-PurpleKeyringClose 
-purple_keyring_get_close_keyring(const PurpleKeyring * info)
-{
-	return info->close_keyring;
-}
+	} else {
 
-PurpleKeyringFree 
-purple_keyring_get_free_password(const PurpleKeyring * info)
-{
-	return info->free_password;
-}
+		inuse = purple_keyring_get_inuse();
 
-PurpleKeyringChangeMaster 
-purple_keyring_get_change_master(const PurpleKeyring * info)
-{
-	return info->change_master;
-}
+		if (inuse == NULL) {
 
-PurpleKeyringImportPassword
-purple_keyring_get_import_password(const PurpleKeyring * info)
-{
-	return info->import_password;
-}
+			return NULL;
 
-PurpleKeyringExportPassword 
-purple_keyring_get_export_password(const PurpleKeyring * info)
-{
-	return info->export_password;
-}
+		} else {
 
+			read = purple_keyring_get_read_sync(keyring);
 
-void 
-purple_keyring_set_name(PurpleKeyring * info,
-			char * name)
-{
-	info->name = name;
-}
+			if (read == NULL){
 
-void 
-purple_keyring_set_read_password(PurpleKeyring * info,
-				 PurpleKeyringRead read)
-{
-	info->read_password = read; /*  returned data must be g_free()'d */
-}
+				return NULL;
 
-void 
-purple_keyring_set_save_password(PurpleKeyring * info,
-				 PurpleKeyringSave save)
-{
-	info->save_password = save;
-}
+			} else {
 
-void 
-purple_keyring_set_close_keyring(PurpleKeyring * info,
-				 PurpleKeyringClose close)
-{
-	info->close_keyring = close;
+				return read(account);
+
+			}
+		}
+	}
 }
 
+/**
+ * This should be dropped at 3.0 (it's here for compatibility)
+ */
 void 
-purple_keyring_set_free_password(PurpleKeyring * info,
-				 PurpleKeyringFree free)
+purple_keyring_set_password_sync(PurpleAccount * account,
+				 const char *password)
 {
-	info->free_password = free;
-}
+	PurpleKeyringSaveSync save;
+	const PurpleKeyring * inuse;
 
-void 
-purple_keyring_set_change_master(PurpleKeyring * info,
-				 PurpleKeyringChangeMaster change_master)
-{
-	info->change_master = change_master;
-}
+	if (account != NULL) {
 
-void 
-purple_keyring_set_import_password(PurpleKeyring * info,
-				   PurpleKeyringImportPassword import_password)
-{
-	info->import_password = import_password;
-}
-void 
-purple_keyring_set_export_password(PurpleKeyring * info,
-				   PurpleKeyringExportPassword export_password)
-{
-	info->export_password = export_password;
-}
+		inuse = purple_keyring_get_inuse();
 
+		if (inuse != NULL) {
 
-	/* PurpleKeyringPasswordNode */
+			save = purple_keyring_get_save_sync(inuse);
 
-PurpleKeyringPasswordNode * 
-purple_keyring_password_node_new()
-{
-	PurpleKeyringPasswordNode * ret;
+			if (save != NULL){
 
-	ret = g_malloc(sizeof(PurpleKeyringPasswordNode));
-	return ret;
-}
+				return save(account, password);
 
-void 
-purple_keyring_password_node_free(PurpleKeyringPasswordNode * node)
-{
-	g_free(node);
+			}
+		}
+	}
+
 	return;
 }
 
-const PurpleAccount * 
-purple_keyring_password_node_get_account(const PurpleKeyringPasswordNode * info)
+void
+purple_keyring_close(PurpleKeyring * keyring,
+		     GError ** error)
 {
-	return info->account;
-}
+	PurpleKeyringClose close;
 
-const char * 
-purple_keyring_password_node_get_encryption(const PurpleKeyringPasswordNode * info)
-{
-	return info->encryption;
-}
+	if (keyring == NULL) {
+		*error = g_error_new(ERR_PIDGINKEYRING, ERR_INVALID,
+			"No keyring passed to the function.");
 
-const char * 
-purple_keyring_password_node_get_mode(const PurpleKeyringPasswordNode * info)
-{
-	return info->mode;
-}
+		return;
 
-const char * 
-purple_keyring_password_node_get_data(const PurpleKeyringPasswordNode * info)
-{
-	return info->data;
-}
+	} else {
+		close = purple_keyring_get_close_keyring(keyring);
 
+		if (close == NULL) {
+			*error = g_error_new(ERR_PIDGINKEYRING, ERR_NOCAP,
+				"Keyring doesn't support being closed.");
 
-void 
-purple_keyring_password_node_set_account(PurpleKeyringPasswordNode * info, 
-					 PurpleAccount * account)
-{
-	info->account = account;
-	return;	
-}
+		} else {
+			close(error);
 
-void 
-purple_keyring_password_node_set_encryption(PurpleKeyringPasswordNode * info,
-					    const char * encryption)
-{
-	info->encryption = encryption;
+		}
+	}
+
 	return;
 }
 
+
 void 
-purple_keyring_password_node_set_mode(PurpleKeyringPasswordNode * info,
-				      const char * mode)
+purple_keyring_change_master(PurpleKeyringChangeMasterCallback cb,
+			     gpointer data)
 {
-	info->mode = mode;
-	return;
-}
+	GError * error = NULL;
+	PurpleKeyringChangeMaster change;
+	const PurpleKeyring * inuse;
 
-void 
-purple_keyring_password_node_set_data(PurpleKeyringPasswordNode * info,
-				      const char * data)
-{
-	info->data = data;
+	inuse = purple_keyring_get_inuse();
+	
+	if (inuse == NULL) {
+		error = g_error_new(ERR_PIDGINKEYRING, ERR_NOCAP,
+			"Keyring doesn't support master passwords.");
+
+		cb(FALSE, error, data);
+
+		g_error_free(error);
+
+	} else {
+
+		change = purple_keyring_get_change_master(inuse);
+
+		if (change == NULL) {
+			error = g_error_new(ERR_PIDGINKEYRING, ERR_NOCAP,
+				"Keyring doesn't support master passwords.");
+
+			cb(FALSE, error, data);
+
+			g_error_free(error);
+
+		} else {
+			change(cb, data);
+
+		}
+	}
 	return;
 }
 
-GQuark
-purple_keyring_error_domain()
+/*@}*/
+
+
+/***************************************/
+/** @name Error Codes                  */
+/***************************************/
+/*@{*/
+
+GQuark purple_keyring_error_domain()
 {
 	return g_quark_from_static_string("Libpurple keyring");
 }
 
+/*}@*/
+
-/**
- * prepare stuff (called at startup)
- * TODO : see if we need to cleanup
- */
-void purple_keyring_init()
-{//FIXME
-	/**
-	 * read safe to use in confing
-	 * make sure said safe is loaded
-	 * else fallback
-	 */
-}
============================================================
--- libpurple/keyring.h	ba4ac59f91aad78d10cfa5c1aa9340cb8a3b5aa3
+++ libpurple/keyring.h	624d3d7937e242c93b82d4ed7a4271b1ef6fc0c3
@@ -4,6 +4,7 @@
  *
  * @todo 
  *  - Offer a way to prompt the user for a password or for a password change.
+ *  - write accessors and types for sync access.
  */
 
 /* purple
@@ -59,23 +60,23 @@ typedef struct _PurpleKeyring PurpleKeyr
  *
  * @param account The account of which the password was asked.
  * @param password The password that was read. This should be freed when the callback returns.
- * @param error Error that could have occured. Must be freed if non NULL.
+ * @param error Error that could have occured. Must be freed by the calling function.
  * @param data Data passed to the callback.
  */
 typedef void (*PurpleKeyringReadCallback)(const PurpleAccount * account,
 					  gchar * password,
-					  GError ** error,
+					  GError * error,
 					  gpointer data);
 
 /**
  * Callback for once a password has been stored. If there was a problem, the error will be set.
  *
+ * @param error Error that could have occured. Must be freed by the calling function.
  * @param account The account of which the password was saved.
- * @param error Error that could have occured. Must be freed if non NULL.
  * @param data Data passed to the callback.
  */
 typedef void (*PurpleKeyringSaveCallback)(const PurpleAccount * account, 
-					  GError ** error,
+					  GError * error,
 					  gpointer data);
 
 /**
@@ -86,9 +87,22 @@ typedef void (*PurpleKeyringChangeMaster
  * @param data Data passed to the callback.
  */
 typedef void (*PurpleKeyringChangeMasterCallback)(gboolean result,
-						  GError ** error,
+						  GError * error,
 						  gpointer data);
 
+/**
+ * Callback for when we change the keyring.
+ *
+ * @param keyring The keyring that is in use.
+ * @param result TRUE if the keyring was changed, FALSE otherwise.
+ * @param error An error that might have occured.
+ * @param data A pointer to user supplied data.
+ */
+typedef void (*PurpleKeyringSetInUseCallback)(const PurpleKeyring * keyring,
+					      gboolean result,
+					      GError * error,
+					      gpointer data);
+
 /*@}*/
 
 /********************************************************/
@@ -124,6 +138,25 @@ typedef void (*PurpleKeyringSave)(const 
 				  gpointer data);
 
 /**
+ * Read a password in an sync way. This is only used for API
+ * compatibility, and plugins are not expected to support this.
+ * Also, this should be dropped in 3.0.
+ * @param account The account.
+ * @return The password for the account.
+ */
+typedef const char * (*PurpleKeyringReadSync)(const PurpleAccount * account);
+
+/**
+ * Read a password in an sync way. This is only used for API
+ * compatibility, and plugins are not expected to support this.
+ * Also, this should be dropped in 3.0.
+ * @param account The account.
+ * @param password The password to save.
+ */
+typedef void (*PurpleKeyringSaveSync)(PurpleAccount * account,
+				      const char * password);
+
+/**
  * Close the keyring.
  * This will be called so the keyring can do any cleanup it wants.
  * @param error An error that may occur.
@@ -137,12 +170,9 @@ typedef void (*PurpleKeyringClose)(GErro
  * @param cb A callback to call once the master password has been changed.
  * @param data A pointer to pass to the callback.
  */
-typedef void (*PurpleKeyringChangeMaster)(GError ** error,
-					  PurpleKeyringChangeMasterCallback cb,
+typedef void (*PurpleKeyringChangeMaster)(PurpleKeyringChangeMasterCallback cb,
 					  gpointer data);
 
-
-/* */
 /**
  * Import info on an XML node.
  * This is not async because it is not meant to prompt for a master password and decrypt passwords.
@@ -167,30 +197,12 @@ typedef gboolean (*PurpleKeyringExportPa
  * @return TRUE on success, FALSE on failure.
  */
 typedef gboolean (*PurpleKeyringExportPassword)(PurpleAccount * account,
-						char ** mode,
-						char ** data,
+						const char ** mode,
+						const char ** data,
 						GError ** error,
 						GDestroyNotify ** destroy);
 
-/**
- * information about a keyring
- * @todo : move as hidden, so we can have hidden fields.
- */
-struct _PurpleKeyring
-{
-	char *  name;
-	PurpleKeyringRead read_password;
-	PurpleKeyringSave save_password;
-	PurpleKeyringClose close_keyring;
-	PurpleKeyringChangeMaster change_master;
-	PurpleKeyringImportPassword import_password;
-	PurpleKeyringExportPassword export_password;
-	gpointer r1;	/* RESERVED */
-	gpointer r2;	/* RESERVED */
-	gpointer r3;	/* RESERVED */
-};
 
-
 /*@}*/
 
 
@@ -200,16 +212,22 @@ struct _PurpleKeyring
 /*@{*/
 
 /**
- * Prepare stuff at startup
+ * Prepare stuff at startup.
  */
 void 
 purple_keyring_init();
 
 /**
+ * Do some cleanup.
+ */
+void
+purple_keyring_uninit();
+
+/**
  * Get the keyring list. Used by the UI.
  */
 const GList * 
-purple_keyring_get_keyringlist();
+purple_keyring_get_keyrings();
 
 /**
  * Get the keyring being used.
@@ -226,12 +244,16 @@ purple_keyring_get_inuse();
  * @param error Error that may occur.
  * @param cb The callback to call once the change is done.
  * @param data A pointer that will be passed to the callback.
+ * @param force FALSE if the change can be cancelled. If this is TRUE and an 
+ * error occurs, data might be lost.
  */
 void
 purple_keyring_set_inuse(const PurpleKeyring * newkeyring,
+			 gboolean force,
 			 PurpleKeyringSetInUseCallback cb,
 			 gpointer data);
 
+
 /**
  * Register a keyring plugin.
  * @param keyrint The keyring to register.
@@ -280,9 +302,9 @@ purple_keyring_export_password(PurpleAcc
  */
 void 
 purple_keyring_export_password(PurpleAccount * account,
-			       char ** keyringid,
-			       char ** mode,
-			       char ** data,
+			       const char ** keyringid,
+			       const char ** mode,
+			       const char ** data,
 			       GError ** error,
 			       GDestroyNotify ** destroy);
 
@@ -336,7 +358,7 @@ purple_keyring_set_password_async(const 
  * @param account The account for which we want the password.
  * @return A pointer to the the password.
  */
-char * 
+const char * 
 purple_keyring_get_password_sync(const PurpleAccount * account);
 
 /**
@@ -382,12 +404,16 @@ PurpleKeyringSave purple_keyring_get_sav
 const char * purple_keyring_get_name(const PurpleKeyring * info);
 PurpleKeyringRead purple_keyring_get_read_password(const PurpleKeyring * info);
 PurpleKeyringSave purple_keyring_get_save_password(const PurpleKeyring * info);
+PurpleKeyringReadSync purple_keyring_get_read_sync(const PurpleKeyring * info);
+PurpleKeyringSaveSync purple_keyring_get_save_sync(const PurpleKeyring * info);
 PurpleKeyringClose purple_keyring_get_close_keyring(const PurpleKeyring * info);
 PurpleKeyringChangeMaster purple_keyring_get_change_master(const PurpleKeyring * info);
 PurpleKeyringImportPassword purple_keyring_get_import_password(const PurpleKeyring * info);
 PurpleKeyringExportPassword purple_keyring_get_export_password(const PurpleKeyring * info);
 
 void purple_keyring_set_name(PurpleKeyring * info, char * name);		/* must be static, will not be auto-freed upon destruction */
+void purple_keyring_set_read_sync(PurpleKeyring * info, PurpleKeyringReadSync read);
+void purple_keyring_set_save_sync(PurpleKeyring * info, PurpleKeyringSaveSync save);
 void purple_keyring_set_read_password(PurpleKeyring * info, PurpleKeyringRead read);
 void purple_keyring_set_save_password(PurpleKeyring * info, PurpleKeyringSave save);
 void purple_keyring_set_close_keyring(PurpleKeyring * info, PurpleKeyringClose close);
@@ -420,6 +446,8 @@ enum PurpleKeyringError
 	ERR_WRONGFORMAT,	/**< data passed is not in suitable format. */
 	ERR_NOKEYRING,		/**< no keyring configured. */
 	ERR_NOCHANNEL,		/**< failed to communicate with the backend */
+	ERR_INVALID,		/**< invalid input */
+	ERR_NOCAP,		/**< keyring doesn't support this */
 	ERR_UNKNOWN		/**< unknown error */
 };
 


More information about the Commits mailing list