libpurple/account.c

branch
soc.2008.masterpassword
changeset 34021
25c14927f826
parent 28373
14e79bd71ac3
parent 34019
bc87f596bb4c
child 34022
c49f6e9ea27d
--- a/libpurple/account.c	Fri Aug 28 23:27:10 2009 +0000
+++ b/libpurple/account.c	Sat Aug 29 00:45:37 2009 +0000
@@ -28,6 +28,7 @@
 #include "core.h"
 #include "dbus-maybe.h"
 #include "debug.h"
+#include "keyring.h"
 #include "network.h"
 #include "notify.h"
 #include "pounce.h"
@@ -41,6 +42,7 @@
 #include "util.h"
 #include "xmlnode.h"
 
+
 typedef struct
 {
 	PurpleConnectionErrorInfo *current_error;
@@ -78,6 +80,12 @@
 	guint ref;
 } PurpleAccountRequestInfo;
 
+typedef struct
+{
+	gpointer cb;
+	gpointer data;
+} CbInfo;
+
 static PurpleAccountUiOps *account_ui_ops = NULL;
 
 static GList   *accounts = NULL;
@@ -89,6 +97,20 @@
 static void set_current_error(PurpleAccount *account,
 	PurpleConnectionErrorInfo *new_err);
 
+static void purple_account_register_got_password_cb(PurpleAccount * account, 
+	char * password, GError * error, gpointer data);
+
+
+static void purple_account_unregister_got_password_cb(PurpleAccount * account,
+	char * password, GError * error, gpointer data);
+
+static void purple_account_connect_got_password_cb(PurpleAccount * account,
+       gchar * password, GError * error, gpointer data);
+
+static void purple_account_get_password_async_finish(PurpleAccount * account,
+	char * password, GError * error, gpointer data);
+
+static void purple_accounts_delete_finish(PurpleAccount * account, GError * error, gpointer data);
 /*********************************************************************
  * Writing to disk                                                   *
  *********************************************************************/
@@ -194,8 +216,7 @@
 		gboolean boolean_value = purple_value_get_boolean(attr_value);
 		if (boolean_value == purple_value_get_boolean(default_value))
 			return NULL;
-		value = g_strdup(boolean_value ?
-								"true" : "false");
+		value = g_strdup(boolean_value ? "true" : "false");
 	}
 	else
 	{
@@ -364,8 +385,13 @@
 
 	xmlnode *node, *child;
 	const char *tmp;
+	const char *keyring_id;
+	const char *mode;
+	char *data;
 	PurplePresence *presence;
 	PurpleProxyInfo *proxy_info;
+	GError * error = NULL;
+	GDestroyNotify destroy;
 
 	node = xmlnode_new("account");
 
@@ -375,11 +401,34 @@
 	child = xmlnode_new_child(node, "name");
 	xmlnode_insert_data(child, purple_account_get_username(account), -1);
 
-	if (purple_account_get_remember_password(account) &&
-		((tmp = purple_account_get_password(account)) != NULL))
+	if (purple_account_get_remember_password(account))
 	{
-		child = xmlnode_new_child(node, "password");
-		xmlnode_insert_data(child, tmp, -1);
+		purple_debug_info("accounts", "Exporting password for account %s (%s).\n",
+			purple_account_get_username(account),
+			purple_account_get_protocol_id(account));
+
+		purple_keyring_export_password(account, &keyring_id, 
+			&mode, &data, &error, &destroy);
+
+		if (error != NULL) {
+
+			purple_debug_info("accounts",
+				"failed to export password for account %s : %s.\n",
+				purple_account_get_username(account),
+				error->message);
+
+		} else {
+			child = xmlnode_new_child(node, "password");
+			if (keyring_id != NULL)
+				xmlnode_set_attrib(child, "keyring_id", keyring_id);
+			if (mode != NULL)
+				xmlnode_set_attrib(child, "mode", mode);
+			if (data != NULL)
+				xmlnode_insert_data(child, data, -1);
+
+			if (destroy != NULL)
+				destroy(data);
+		}
 	}
 
 	if ((tmp = purple_account_get_alias(account)) != NULL)
@@ -455,6 +504,8 @@
 		return;
 	}
 
+	purple_debug_info("account", "Syncing accounts.\n");
+
 	node = accounts_to_xmlnode();
 	data = xmlnode_to_formatted_str(node, NULL);
 	purple_util_write_data_to_file("accounts.xml", data, -1);
@@ -803,7 +854,11 @@
 	xmlnode *child;
 	char *protocol_id = NULL;
 	char *name = NULL;
-	char *data;
+	const char *keyring_id = NULL;
+	const char *mode = NULL;
+	char *data = NULL;
+	gboolean result = FALSE;
+	GError * error = NULL;
 
 	child = xmlnode_get_child(node, "protocol");
 	if (child != NULL)
@@ -831,15 +886,6 @@
 	g_free(name);
 	g_free(protocol_id);
 
-	/* Read the password */
-	child = xmlnode_get_child(node, "password");
-	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
-	{
-		purple_account_set_remember_password(ret, TRUE);
-		purple_account_set_password(ret, data);
-		g_free(data);
-	}
-
 	/* Read the alias */
 	child = xmlnode_get_child(node, "alias");
 	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
@@ -912,6 +958,26 @@
 		parse_current_error(child, ret);
 	}
 
+	/* Read the password */
+
+	child = xmlnode_get_child(node, "password");
+	if (child != NULL)
+	{
+		keyring_id = xmlnode_get_attrib(child, "keyring_id");
+		mode = xmlnode_get_attrib(child, "mode");
+		data = xmlnode_get_data(child);
+
+		result = purple_keyring_import_password(ret, keyring_id, mode, data, &error);
+
+		if (result == TRUE) {
+			purple_debug_info("accounts", "password imported successfully.\n");
+			purple_account_set_remember_password(ret, TRUE);		
+		} else {
+			purple_debug_info("accounts", "failed to imported password.\n");
+		} 
+		g_free(data); 
+	}
+
 	return ret;
 }
 
@@ -1076,24 +1142,62 @@
 	purple_debug_info("account", "Registering account %s\n",
 					purple_account_get_username(account));
 
-	_purple_connection_new(account, TRUE, purple_account_get_password(account));
+	purple_keyring_get_password_async(account, purple_account_register_got_password_cb, NULL);
 }
 
+
+static void
+purple_account_register_got_password_cb(PurpleAccount * account, char * password, GError * error, gpointer data)
+{
+	g_return_if_fail(account != NULL);
+
+	_purple_connection_new(account, TRUE, password);
+}
+
+typedef struct
+{
+	PurpleAccountUnregistrationCb cb;
+	void *user_data;
+} UnregisterData;
+
 void
 purple_account_unregister(PurpleAccount *account, PurpleAccountUnregistrationCb cb, void *user_data)
 {
+	UnregisterData * data;
+
 	g_return_if_fail(account != NULL);
 
 	purple_debug_info("account", "Unregistering account %s\n",
 					  purple_account_get_username(account));
 
-	_purple_connection_new_unregister(account, purple_account_get_password(account), cb, user_data);
+	data = g_new0(UnregisterData, 1);
+	data->cb = cb;
+	data->user_data = user_data;
+
+	purple_keyring_get_password_async(account, purple_account_unregister_got_password_cb, data);
+
+}
+
+static void
+purple_account_unregister_got_password_cb(PurpleAccount * account, char * password, GError * error, gpointer data)
+{
+	UnregisterData * unregdata;
+	
+	g_return_if_fail(account != NULL);
+
+	unregdata = data;
+	g_return_if_fail(unregdata != NULL);
+
+	_purple_connection_new_unregister(account, password, unregdata->cb, unregdata->user_data);
+
+	g_free(unregdata);
 }
 
 static void
 request_password_ok_cb(PurpleAccount *account, PurpleRequestFields *fields)
 {
 	const char *entry;
+	char * password;
 	gboolean remember;
 
 	entry = purple_request_fields_get_string(fields, "password");
@@ -1105,12 +1209,16 @@
 		return;
 	}
 
-	if(remember)
-		purple_account_set_remember_password(account, TRUE);
-
-	purple_account_set_password(account, entry);
-
+	if(!remember)
+		purple_keyring_set_password_async(account, NULL, NULL, NULL, NULL);
+
+	purple_account_set_remember_password(account, remember);
+
+	password = g_strdup(entry);
+	purple_account_set_password(account, password);
+	g_free(password);
 	_purple_connection_new(account, FALSE, entry);
+
 }
 
 static void
@@ -1193,7 +1301,20 @@
 	purple_debug_info("account", "Connecting to account %s.\n", username);
 
 	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
-	password = purple_account_get_password(account);
+	purple_keyring_get_password_async(account, purple_account_connect_got_password_cb, prpl_info);
+
+}
+
+static void
+purple_account_connect_got_password_cb(PurpleAccount * account,
+				       gchar * password,
+				       GError * error,
+				       gpointer data)
+{
+	PurplePluginProtocolInfo *prpl_info;
+
+	prpl_info = data;
+
 	if ((password == NULL) &&
 		!(prpl_info->options & OPT_PROTO_NO_PASSWORD) &&
 		!(prpl_info->options & OPT_PROTO_PASSWORD_OPTIONAL))
@@ -1219,10 +1340,8 @@
 
 	gc = purple_account_get_connection(account);
 	_purple_connection_destroy(gc);
-	if (!purple_account_get_remember_password(account))
-		purple_account_set_password(account, NULL);
+
 	purple_account_set_connection(account, NULL);
-
 	account->disconnecting = FALSE;
 }
 
@@ -1556,14 +1675,52 @@
 void
 purple_account_set_password(PurpleAccount *account, const char *password)
 {
+	schedule_accounts_save();
+
 	g_return_if_fail(account != NULL);
 
 	g_free(account->password);
+
 	account->password = g_strdup(password);
 
+	if (purple_account_get_remember_password(account) == TRUE)
+		purple_keyring_set_password_async(account, g_strdup(password), g_free, NULL, NULL);
+}
+
+void 
+purple_account_set_password_async(PurpleAccount * account, 
+				  gchar * password,
+				  GDestroyNotify destroypassword,
+				  PurpleKeyringSaveCallback cb,
+				  gpointer data)
+{
+	/**
+	 * This is so we can force an account sync by calling
+	 * it with account == NULL.
+	 */
 	schedule_accounts_save();
+
+	g_return_if_fail(account != NULL);
+
+	g_free(account->password);
+
+	account->password = g_strdup(password);
+
+	if (purple_account_get_remember_password(account) == FALSE) {
+
+		account->password = g_strdup(password);
+		purple_debug_info("account",
+			"Password for %s set, not sent to keyring.\n",
+			purple_account_get_username(account));
+
+		if (cb != NULL)
+			cb(account, NULL, data);
+
+	} else {
+		purple_keyring_set_password_async(account, password,
+			destroypassword, cb, data);
+	}
 }
-
 void
 purple_account_set_alias(PurpleAccount *account, const char *alias)
 {
@@ -1960,13 +2117,92 @@
 	return account->username;
 }
 
+#ifndef PURPLE_DISABLE_DEPRECATED
+/* XXX will be replaced by the async code in 3.0 */
 const char *
-purple_account_get_password(const PurpleAccount *account)
+purple_account_get_password(PurpleAccount *account)
 {
 	g_return_val_if_fail(account != NULL, NULL);
 
+	if (account->password == NULL) {
+		purple_debug_info("accounts",
+			"Reading password for account %s (%s) from sync keyring.\n",
+			purple_account_get_username(account),
+			purple_account_get_protocol_id(account));
+
+		account->password = g_strdup(purple_keyring_get_password_sync(account));
+
+	} else {
+		purple_debug_info("accounts",
+			"Reading password for account %s (%s) from cached.\n",
+			purple_account_get_username(account),
+			purple_account_get_protocol_id(account));
+	}
+
 	return account->password;
 }
+#endif
+
+void
+purple_account_get_password_async(PurpleAccount * account,
+				  PurpleKeyringReadCallback cb,
+				  gpointer data)
+{
+	CbInfo * info = g_new0(CbInfo,1);
+	info->cb = cb;
+	info->data = data;
+
+	if(account == NULL) {
+		cb(NULL, NULL, NULL, data);
+		return;
+	}
+
+	if (account->password != NULL) {
+		purple_debug_info("accounts",
+			"Reading password for account %s (%s) from cached (async).\n",
+			purple_account_get_username(account),
+			purple_account_get_protocol_id(account));
+		cb(account, account->password, NULL, data);
+
+	} else {
+		purple_debug_info("accounts",
+			"Reading password for account %s (%s) from async keyring.\n",
+			purple_account_get_username(account),
+			purple_account_get_protocol_id(account));
+		purple_keyring_get_password_async(account, 
+			purple_account_get_password_async_finish, info);
+	}
+}
+
+static void
+purple_account_get_password_async_finish(PurpleAccount * account,
+					 char * password,
+					 GError * error,
+					 gpointer data)
+{
+	CbInfo * info;
+	PurpleKeyringReadCallback cb;
+
+	
+
+	purple_debug_info("accounts",
+		"Read password for account %s (%s) from async keyring.\n",
+		purple_account_get_username(account),
+		purple_account_get_protocol_id(account));
+
+	info = data;
+
+	g_return_if_fail(account != NULL);
+	g_free(account->password);
+	account->password = g_strdup(password);
+	g_return_if_fail(info != NULL);
+
+	cb = info->cb;
+	if (cb != NULL)
+		cb(account, password, error, info->data);
+
+	g_free(data);
+}
 
 const char *
 purple_account_get_alias(const PurpleAccount *account)
@@ -2412,7 +2648,7 @@
 	PurpleConnection *gc = purple_account_get_connection(account);
 	PurplePlugin *prpl = NULL;
 
-	purple_account_set_password(account, new_pw);
+	purple_account_set_password_async(account, g_strdup(new_pw), g_free, NULL, NULL);
 
 	if (gc != NULL)
 	        prpl = purple_connection_get_prpl(gc);
@@ -2620,7 +2856,18 @@
 	/* This will cause the deletion of an old buddy icon. */
 	purple_buddy_icons_set_account_icon(account, NULL, 0);
 
-	purple_account_destroy(account);
+	/* this is async because we do not want the
+	 * account overwritten before we are done.
+	 */
+	purple_keyring_set_password_async(account, NULL, NULL, 
+		purple_accounts_delete_finish, NULL);
+
+}
+
+static void
+purple_accounts_delete_finish(PurpleAccount * account, GError * error, gpointer data)
+{
+		purple_account_destroy(account);
 }
 
 void

mercurial