diff libpurple/account.c @ 21563:1b174854bb80

merge of '30fcf2f336afb635b62a5c3ed3adb3e1fa1dd2d1' and 'bb60447c0a8c79afca320f4dc689096f4788e7fa'
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Sat, 17 Nov 2007 01:55:21 +0000
parents 665e04562de0
children 14afe5a92fc2 975336b01aa9
line wrap: on
line diff
--- a/libpurple/account.c	Wed Nov 14 03:15:32 2007 +0000
+++ b/libpurple/account.c	Sat Nov 17 01:55:21 2007 +0000
@@ -41,6 +41,14 @@
 #include "util.h"
 #include "xmlnode.h"
 
+typedef struct
+{
+	PurpleConnectionErrorInfo *current_error;
+} PurpleAccountPrivate;
+
+#define PURPLE_ACCOUNT_GET_PRIVATE(account) \
+	((PurpleAccountPrivate *) (account->priv))
+
 /* TODO: Should use PurpleValue instead of this?  What about "ui"? */
 typedef struct
 {
@@ -52,7 +60,7 @@
 	{
 		int integer;
 		char *string;
-		gboolean bool;
+		gboolean boolean;
 
 	} value;
 
@@ -63,7 +71,10 @@
 	PurpleAccountRequestType type;
 	PurpleAccount *account;
 	void *ui_handle;
-
+	char *user;
+	gpointer userdata;
+	PurpleAccountRequestAuthorizationCb auth_cb;
+	PurpleAccountRequestAuthorizationCb deny_cb;
 } PurpleAccountRequestInfo;
 
 static PurpleAccountUiOps *account_ui_ops = NULL;
@@ -74,6 +85,9 @@
 
 static GList *handles = NULL;
 
+static void set_current_error(PurpleAccount *account,
+	PurpleConnectionErrorInfo *new_err);
+
 /*********************************************************************
  * Writing to disk                                                   *
  *********************************************************************/
@@ -104,7 +118,7 @@
 	}
 	else if (setting->type == PURPLE_PREF_BOOLEAN) {
 		xmlnode_set_attrib(child, "type", "bool");
-		snprintf(buf, sizeof(buf), "%d", setting->value.bool);
+		snprintf(buf, sizeof(buf), "%d", setting->value.boolean);
 		xmlnode_insert_data(child, buf, -1);
 	}
 }
@@ -307,8 +321,32 @@
 }
 
 static xmlnode *
+current_error_to_xmlnode(PurpleConnectionErrorInfo *err)
+{
+	xmlnode *node, *child;
+	char type_str[3];
+
+	node = xmlnode_new("current_error");
+
+	if(err == NULL)
+		return node;
+
+	child = xmlnode_new_child(node, "type");
+	snprintf(type_str, sizeof(type_str), "%u", err->type);
+	xmlnode_insert_data(child, type_str, -1);
+
+	child = xmlnode_new_child(node, "description");
+	if(err->description)
+		xmlnode_insert_data(child, err->description, -1);
+
+	return node;
+}
+
+static xmlnode *
 account_to_xmlnode(PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
 	xmlnode *node, *child;
 	const char *tmp;
 	PurplePresence *presence;
@@ -365,6 +403,9 @@
 		xmlnode_insert_child(node, child);
 	}
 
+	child = current_error_to_xmlnode(priv->current_error);
+	xmlnode_insert_child(node, child);
+
 	return node;
 }
 
@@ -669,6 +710,42 @@
 	purple_account_set_proxy_info(account, proxy_info);
 }
 
+static void
+parse_current_error(xmlnode *node, PurpleAccount *account)
+{
+	guint type;
+	char *type_str = NULL, *description = NULL;
+	xmlnode *child;
+	PurpleConnectionErrorInfo *current_error = NULL;
+
+	child = xmlnode_get_child(node, "type");
+	if (child == NULL || (type_str = xmlnode_get_data(child)) == NULL)
+		return;
+	type = atoi(type_str);
+	g_free(type_str);
+
+	if (type > PURPLE_CONNECTION_ERROR_OTHER_ERROR)
+	{
+		purple_debug_error("account",
+			"Invalid PurpleConnectionError value %d found when "
+			"loading account information for %s\n",
+			type, purple_account_get_username(account));
+		type = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
+	}
+
+	child = xmlnode_get_child(node, "description");
+	if (child)
+		description = xmlnode_get_data(child);
+	if (description == NULL)
+		description = g_strdup("");
+
+	current_error = g_new0(PurpleConnectionErrorInfo, 1);
+	current_error->type = type;
+	current_error->description = description;
+
+	set_current_error(account, current_error);
+}
+
 static PurpleAccount *
 parse_account(xmlnode *node)
 {
@@ -778,6 +855,13 @@
 		parse_proxy_info(child, ret);
 	}
 
+	/* Read current error */
+	child = xmlnode_get_child(node, "current_error");
+	if (child != NULL)
+	{
+		parse_current_error(child, ret);
+	}
+
 	return ret;
 }
 
@@ -824,6 +908,7 @@
 purple_account_new(const char *username, const char *protocol_id)
 {
 	PurpleAccount *account = NULL;
+	PurpleAccountPrivate *priv = NULL;
 	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 	PurpleStatusType *status_type;
@@ -838,6 +923,8 @@
 
 	account = g_new0(PurpleAccount, 1);
 	PURPLE_DBUS_REGISTER_POINTER(account, PurpleAccount);
+	priv = g_new0(PurpleAccountPrivate, 1);
+	account->priv = priv;
 
 	purple_account_set_username(account, username);
 
@@ -878,6 +965,7 @@
 void
 purple_account_destroy(PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv = NULL;
 	GList *l;
 
 	g_return_if_fail(account != NULL);
@@ -909,6 +997,10 @@
 	if(account->system_log)
 		purple_log_free(account->system_log);
 
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	g_free(priv->current_error);
+	g_free(priv);
+
 	PURPLE_DBUS_UNREGISTER_POINTER(account);
 	g_free(account);
 }
@@ -1157,6 +1249,28 @@
 	}
 }
 
+static void
+request_auth_cb(void *data)
+{
+	PurpleAccountRequestInfo *info = data;
+	info->auth_cb(info->userdata);
+	purple_signal_emit(purple_accounts_get_handle(),
+			"account-authorization-granted", info->account, info->user);
+	g_free(info->user);
+	g_free(info);
+}
+
+static void
+request_deny_cb(void *data)
+{
+	PurpleAccountRequestInfo *info = data;
+	info->deny_cb(info->userdata);
+	purple_signal_emit(purple_accounts_get_handle(),
+			"account-authorization-denied", info->account, info->user);
+	g_free(info->user);
+	g_free(info);
+}
+
 void *
 purple_account_request_authorization(PurpleAccount *account, const char *remote_user,
 				     const char *id, const char *alias, const char *message, gboolean on_list,
@@ -1164,18 +1278,35 @@
 {
 	PurpleAccountUiOps *ui_ops;
 	PurpleAccountRequestInfo *info;
+	int plugin_return;
 
 	g_return_val_if_fail(account     != NULL, NULL);
 	g_return_val_if_fail(remote_user != NULL, NULL);
 
 	ui_ops = purple_accounts_get_ui_ops();
 
+	plugin_return = GPOINTER_TO_INT(
+			purple_signal_emit_return_1(purple_accounts_get_handle(),
+				"account-authorization-requested", account, remote_user));
+
+	if (plugin_return > 0) {
+		auth_cb(user_data);
+		return NULL;
+	} else if (plugin_return < 0) {
+		deny_cb(user_data);
+		return NULL;
+	}
+
 	if (ui_ops != NULL && ui_ops->request_authorize != NULL) {
 		info            = g_new0(PurpleAccountRequestInfo, 1);
 		info->type      = PURPLE_ACCOUNT_REQUEST_AUTHORIZATION;
 		info->account   = account;
+		info->auth_cb   = auth_cb;
+		info->deny_cb   = deny_cb;
+		info->userdata  = user_data;
+		info->user      = g_strdup(remote_user);
 		info->ui_handle = ui_ops->request_authorize(account, remote_user, id, alias, message,
-							    on_list, auth_cb, deny_cb, user_data);
+							    on_list, request_auth_cb, request_deny_cb, info);
 
 		handles = g_list_append(handles, info);
 		return info->ui_handle;
@@ -1578,7 +1709,7 @@
 	setting = g_new0(PurpleAccountSetting, 1);
 
 	setting->type       = PURPLE_PREF_BOOLEAN;
-	setting->value.bool = value;
+	setting->value.boolean = value;
 
 	g_hash_table_insert(account->settings, g_strdup(name), setting);
 
@@ -1664,7 +1795,7 @@
 
 	setting->type       = PURPLE_PREF_BOOLEAN;
 	setting->ui         = g_strdup(ui);
-	setting->value.bool = value;
+	setting->value.boolean = value;
 
 	table = get_ui_settings_table(account, ui);
 
@@ -1939,7 +2070,7 @@
 
 	g_return_val_if_fail(setting->type == PURPLE_PREF_BOOLEAN, default_value);
 
-	return setting->value.bool;
+	return setting->value.boolean;
 }
 
 int
@@ -2005,7 +2136,7 @@
 
 	g_return_val_if_fail(setting->type == PURPLE_PREF_BOOLEAN, default_value);
 
-	return setting->value.bool;
+	return setting->value.boolean;
 }
 
 PurpleLog *
@@ -2172,6 +2303,65 @@
 	return prpl_info->offline_message(buddy);
 }
 
+static void
+signed_on_cb(PurpleConnection *gc,
+             gpointer unused)
+{
+	PurpleAccount *account = purple_connection_get_account(gc);
+	purple_account_clear_current_error(account);
+}
+
+static void
+set_current_error(PurpleAccount *account,
+                  PurpleConnectionErrorInfo *new_err)
+{
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	PurpleConnectionErrorInfo *old_err = priv->current_error;
+
+	if(new_err == old_err)
+		return;
+
+	priv->current_error = new_err;
+
+	purple_signal_emit(purple_accounts_get_handle(),
+	                   "account-error-changed",
+	                   account, old_err, new_err);
+	schedule_accounts_save();
+
+	if(old_err)
+		g_free(old_err->description);
+
+	g_free(old_err);
+}
+
+static void
+connection_error_cb(PurpleConnection *gc,
+                    PurpleConnectionError type,
+                    const gchar *description,
+                    gpointer unused)
+{
+	PurpleAccount *account = purple_connection_get_account(gc);
+	PurpleConnectionErrorInfo *err = g_new0(PurpleConnectionErrorInfo, 1);
+
+	err->type = type;
+	err->description = g_strdup(description);
+
+	set_current_error(account, err);
+}
+
+const PurpleConnectionErrorInfo *
+purple_account_get_current_error(PurpleAccount *account)
+{
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	return priv->current_error;
+}
+
+void
+purple_account_clear_current_error(PurpleAccount *account)
+{
+	set_current_error(account, NULL);
+}
+
 void
 purple_accounts_add(PurpleAccount *account)
 {
@@ -2196,6 +2386,11 @@
 
 	schedule_accounts_save();
 
+	/* Clearing the error ensures that account-error-changed is emitted,
+	 * which is the end of the guarantee that the the error's pointer is
+	 * valid.
+	 */
+	purple_account_clear_current_error(account);
 	purple_signal_emit(purple_accounts_get_handle(), "account-removed", account);
 }
 
@@ -2401,6 +2596,7 @@
 purple_accounts_init(void)
 {
 	void *handle = purple_accounts_get_handle();
+	void *conn_handle = purple_connections_get_handle();
 
 	purple_signal_register(handle, "account-connecting",
 						 purple_marshal_VOID__POINTER, NULL, 1,
@@ -2452,6 +2648,38 @@
 							 			PURPLE_SUBTYPE_ACCOUNT),
 						 purple_value_new(PURPLE_TYPE_STRING));
 
+	purple_signal_register(handle, "account-authorization-requested",
+						purple_marshal_INT__POINTER_POINTER,
+						purple_value_new(PURPLE_TYPE_INT), 2,
+						purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "account-authorization-denied",
+						purple_marshal_VOID__POINTER_POINTER, NULL, 2,
+						purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "account-authorization-granted",
+						purple_marshal_VOID__POINTER_POINTER, NULL, 2,
+						purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "account-error-changed",
+	                       purple_marshal_VOID__POINTER_POINTER_POINTER,
+	                       NULL, 3,
+	                       purple_value_new(PURPLE_TYPE_SUBTYPE,
+	                                        PURPLE_SUBTYPE_ACCOUNT),
+	                       purple_value_new(PURPLE_TYPE_POINTER),
+	                       purple_value_new(PURPLE_TYPE_POINTER));
+
+	purple_signal_connect(conn_handle, "signed-on", handle,
+	                      PURPLE_CALLBACK(signed_on_cb), NULL);
+	purple_signal_connect(conn_handle, "connection-error", handle,
+	                      PURPLE_CALLBACK(connection_error_cb), NULL);
+
 	load_accounts();
 
 }
@@ -2459,6 +2687,7 @@
 void
 purple_accounts_uninit(void)
 {
+	gpointer handle = purple_accounts_get_handle();
 	if (save_timer != 0)
 	{
 		purple_timeout_remove(save_timer);
@@ -2466,5 +2695,6 @@
 		sync_accounts();
 	}
 
-	purple_signals_unregister_by_instance(purple_accounts_get_handle());
+	purple_signals_disconnect_by_handle(handle);
+	purple_signals_unregister_by_instance(handle);
 }