--- 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