libpurple/protocols/gg/account.c

branch
soc.2008.masterpassword
changeset 34106
1b0c94670bcc
parent 33351
bd15903d0d89
child 34145
fa72f1e5cd77
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/gg/account.c	Wed Aug 22 18:19:53 2012 -0400
@@ -0,0 +1,648 @@
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * Rewritten from scratch during Google Summer of Code 2012
+ * by Tomek Wasilczyk (http://www.wasilczyk.pl).
+ *
+ * Previously implemented by:
+ *  - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
+ *  - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
+ *  - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "account.h"
+
+#include <libgadu.h>
+#include <debug.h>
+
+#include "deprecated.h"
+#include "purplew.h"
+#include "utils.h"
+#include "libgaduw.h"
+#include "validator.h"
+
+/*******************************************************************************
+ * Token requesting.
+ ******************************************************************************/
+
+typedef struct
+{
+	ggp_account_token_cb callback;
+	PurpleConnection *gc;
+	void *user_data;
+} ggp_account_token_reqdata;
+
+static void ggp_account_token_response(struct gg_http *h, gboolean success,
+	gboolean cancelled, gpointer _reqdata);
+
+/******************************************************************************/
+
+void ggp_account_token_free(ggp_account_token *token)
+{
+	if (!token)
+		return;
+	g_free(token->id);
+	g_free(token->data);
+	g_free(token);
+}
+
+void ggp_account_token_request(PurpleConnection *gc,
+	ggp_account_token_cb callback, void *user_data)
+{
+	struct gg_http *h;
+	ggp_account_token_reqdata *reqdata;
+
+	purple_debug_info("gg", "ggp_account_token_request: "
+		"requesting token...\n");
+
+	if (!ggp_deprecated_setup_proxy(gc))
+	{
+		callback(gc, NULL, user_data);
+		return;
+	}
+	
+	h = gg_token(TRUE);
+	
+	if (!h)
+	{
+		callback(gc, NULL, user_data);
+		return;
+	}
+	
+	reqdata = g_new(ggp_account_token_reqdata, 1);
+	reqdata->callback = callback;
+	reqdata->gc = gc;
+	reqdata->user_data = user_data;
+	ggp_libgaduw_http_watch(gc, h, ggp_account_token_response, reqdata,
+		TRUE);
+}
+
+static void ggp_account_token_response(struct gg_http *h, gboolean success,
+	gboolean cancelled, gpointer _reqdata)
+{
+	ggp_account_token_reqdata *reqdata = _reqdata;
+	struct gg_token *token_info;
+	ggp_account_token *token = NULL;
+	
+	g_assert(!(success && cancelled));
+	
+	if (cancelled)
+		purple_debug_info("gg", "ggp_account_token_handler: "
+			"cancelled\n");
+	else if (success)
+	{
+		purple_debug_info("gg", "ggp_account_token_handler: "
+			"got token\n");
+	
+		token = g_new(ggp_account_token, 1);
+	
+		token_info = h->data;
+		token->id = g_strdup(token_info->tokenid);
+		token->size = h->body_size;
+		token->data = g_memdup(h->body, token->size);
+		token->length = token_info->length;
+	}
+	else
+	{
+		purple_debug_error("gg", "ggp_account_token_handler: error\n");
+		purple_notify_error(
+			purple_connection_get_account(reqdata->gc),
+			_("Token Error"),
+			_("Unable to fetch the token."), NULL);
+	}
+	
+	reqdata->callback(reqdata->gc, token, reqdata->user_data);
+	g_free(reqdata);
+}
+
+gboolean ggp_account_token_validate(ggp_account_token *token,
+	const gchar *value)
+{
+	if (strlen(value) != token->length)
+		return FALSE;
+	return g_regex_match_simple("^[a-zA-Z0-9]+$", value, 0, 0);
+}
+
+/*******************************************************************************
+ * New account registration.
+ ******************************************************************************/
+
+typedef struct
+{
+	ggp_account_token *token;
+	PurpleConnection *gc;
+	
+	gchar *email;
+	gchar *password;
+	gchar *token_value;
+	gboolean password_remember;
+} ggp_account_register_data;
+
+static void ggp_account_register_dialog(PurpleConnection *gc,
+	ggp_account_token *token, gpointer _register_data);
+static void ggp_account_register_dialog_ok(
+	ggp_account_register_data *register_data, PurpleRequestFields *fields);
+#if 0
+static void ggp_account_register_dialog_invalid(
+	ggp_account_register_data *register_data, const gchar *message);
+#endif
+static void ggp_account_register_dialog_cancel(
+	ggp_account_register_data *register_data, PurpleRequestFields *fields);
+static void ggp_account_register_response(struct gg_http *h, gboolean success,
+	gboolean cancelled, gpointer _reqdata);
+static void ggp_account_register_completed(
+	ggp_account_register_data *register_data, gboolean success);
+
+#define GGP_ACCOUNT_REGISTER_TITLE _("Register New Gadu-Gadu Account")
+
+/******************************************************************************/
+
+void ggp_account_register(PurpleAccount *account)
+{
+	PurpleConnection *gc = purple_account_get_connection(account);
+	ggp_account_register_data *register_data;
+	
+	purple_debug_info("gg", "ggp_account_register\n");
+	
+	register_data = g_new0(ggp_account_register_data, 1);
+	register_data->gc = gc;
+	register_data->password_remember = TRUE;
+	
+	ggp_account_token_request(gc, ggp_account_register_dialog,
+		register_data);
+}
+
+static void ggp_account_register_dialog(PurpleConnection *gc,
+	ggp_account_token *token, gpointer _register_data)
+{
+	PurpleRequestFields *fields;
+	PurpleRequestFieldGroup *main_group, *password_group, *token_group;
+	PurpleRequestField *field, *field_password;
+	ggp_account_register_data *register_data = _register_data;
+	
+	purple_debug_info("gg", "ggp_account_register_dialog(%p, %p, %p)\n",
+		gc, token, _register_data);
+	if (!token)
+	{
+		ggp_account_register_completed(register_data, FALSE);
+		return;
+	}
+	
+	fields = purple_request_fields_new();
+	main_group = purple_request_field_group_new(NULL);
+	purple_request_fields_add_group(fields, main_group);
+	
+	field = purple_request_field_string_new("email", _("Email"),
+		register_data->email, FALSE);
+	purple_request_field_set_required(field, TRUE);
+	purple_request_field_set_validator(field,
+		purple_request_field_email_validator, NULL);
+	purple_request_field_group_add_field(main_group, field);
+
+	password_group = purple_request_field_group_new(_("Password"));
+	purple_request_fields_add_group(fields, password_group);
+
+	field = purple_request_field_string_new("password1", _("Password"),
+		register_data->password, FALSE);
+	purple_request_field_set_required(field, TRUE);
+	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_set_validator(field, ggp_validator_password, NULL);
+	purple_request_field_group_add_field(password_group, field);
+	field_password = field;
+	
+	field = purple_request_field_string_new("password2",
+		_("Password (again)"), register_data->password, FALSE);
+	purple_request_field_set_required(field, TRUE);
+	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_set_validator(field, ggp_validator_password_equal,
+		field_password);
+	purple_request_field_group_add_field(password_group, field);
+	
+	field = purple_request_field_bool_new("password_remember",
+		_("Remember password"), register_data->password_remember);
+	purple_request_field_group_add_field(password_group, field);
+	
+	token_group = purple_request_field_group_new(_("Captcha"));
+	purple_request_fields_add_group(fields, token_group);
+	
+	field = purple_request_field_string_new("token_value",
+		_("Enter text from image below"), register_data->token_value,
+		FALSE);
+	purple_request_field_set_required(field, TRUE);
+	purple_request_field_set_validator(field, ggp_validator_token, token);
+	purple_request_field_group_add_field(token_group, field);
+	purple_debug_info("gg", "token set %p\n", register_data->token);
+	
+	field = purple_request_field_image_new("token_image", _("Captcha"),
+		token->data, token->size);
+	purple_request_field_group_add_field(token_group, field);
+
+	register_data->token = token;
+	
+	purple_request_fields(gc,
+		GGP_ACCOUNT_REGISTER_TITLE,
+		GGP_ACCOUNT_REGISTER_TITLE,
+		_("Please, fill in the following fields"), fields,
+		_("OK"), G_CALLBACK(ggp_account_register_dialog_ok),
+		_("Cancel"), G_CALLBACK(ggp_account_register_dialog_cancel),
+		purple_connection_get_account(gc), NULL, NULL, register_data);
+}
+
+static void ggp_account_register_dialog_cancel(
+	ggp_account_register_data *register_data, PurpleRequestFields *fields)
+{
+	purple_debug_info("gg", "ggp_account_register_dialog_cancel(%p, %p)\n",
+		register_data, fields);
+
+	ggp_account_register_completed(register_data, FALSE);
+}
+
+static void ggp_account_register_dialog_ok(
+	ggp_account_register_data *register_data, PurpleRequestFields *fields)
+{
+	struct gg_http *h;
+
+	purple_debug_misc("gg", "ggp_account_register_dialog_ok(%p, %p)\n",
+		register_data, fields);
+
+	g_free(register_data->email);
+	g_free(register_data->password);
+	g_free(register_data->token_value);
+	
+	register_data->email = g_strdup(
+		purple_request_fields_get_string(fields, "email"));
+	register_data->password = g_strdup(
+		purple_request_fields_get_string(fields, "password1"));
+	register_data->password_remember =
+		purple_request_fields_get_bool(fields, "password_remember");
+	register_data->token_value = g_strdup(
+		purple_request_fields_get_string(fields, "token_value"));
+
+	g_assert(register_data->email != NULL);
+	g_assert(register_data->password != NULL);
+	g_assert(register_data->token_value != NULL);
+
+	h = gg_register3(register_data->email, register_data->password,
+		register_data->token->id, register_data->token_value, TRUE);
+	
+	ggp_libgaduw_http_watch(register_data->gc, h,
+		ggp_account_register_response, register_data, TRUE);
+}
+
+#if 0
+// libgadu 1.12.x: use it for invalid token
+static void ggp_account_register_dialog_invalid(
+	ggp_account_register_data *register_data, const gchar *message)
+{
+	purple_debug_warning("gg", "ggp_account_register_dialog_invalid: %s\n",
+		message);
+	ggp_account_register_dialog(register_data->gc, register_data->token,
+		register_data);
+	purple_notify_error(purple_connection_get_account(register_data->gc),
+		GGP_ACCOUNT_REGISTER_TITLE, message, NULL);
+}
+#endif
+
+static void ggp_account_register_response(struct gg_http *h, gboolean success,
+	gboolean cancelled, gpointer _register_data)
+{
+	ggp_account_register_data *register_data = _register_data;
+	PurpleAccount *account =
+		purple_connection_get_account(register_data->gc);
+	struct gg_pubdir *register_result = h->data;
+	uin_t uin;
+	gchar *tmp;
+	
+	g_assert(!(success && cancelled));
+	
+	if (cancelled)
+	{
+		purple_debug_info("gg", "ggp_account_register_response: "
+			"cancelled\n");
+		ggp_account_register_completed(register_data, FALSE);
+		return;
+	}
+	if (!success || !register_result->success)
+	{
+		//TODO (libgadu 1.12.x): check register_result->error
+		purple_debug_error("gg", "ggp_account_register_response: "
+			"error\n");
+		purple_notify_error(NULL,
+			GGP_ACCOUNT_REGISTER_TITLE,
+			_("Unable to register new account. "
+			"An unknown error occurred."), NULL);
+		ggp_account_register_completed(register_data, FALSE);
+		return;
+	}
+
+	uin = register_result->uin;
+	purple_debug_info("gg", "ggp_account_register_response: "
+		"registered uin %u\n", uin);
+	
+	purple_account_set_username(account, ggp_uin_to_str(uin));
+	purple_account_set_remember_password(account,
+		register_data->password_remember);
+	purple_account_set_password(account, register_data->password, NULL, NULL);
+	
+	tmp = g_strdup_printf(_("Your new GG number: %u."), uin);
+	purple_notify_info(account, GGP_ACCOUNT_REGISTER_TITLE,
+		_("Registration completed successfully!"), tmp);
+	g_free(tmp);
+	
+	ggp_account_register_completed(register_data, TRUE);
+}
+
+static void ggp_account_register_completed(
+	ggp_account_register_data *register_data, gboolean success)
+{
+	PurpleAccount *account =
+		purple_connection_get_account(register_data->gc);
+
+	purple_debug_misc("gg", "ggp_account_register_completed: %d\n",
+		success);
+	
+	g_free(register_data->email);
+	g_free(register_data->password);
+	g_free(register_data->token_value);
+	ggp_account_token_free(register_data->token);
+	g_free(register_data);
+	
+	purple_account_disconnect(account);
+	purple_account_register_completed(account, success);
+}
+
+/*******************************************************************************
+ * Password change.
+ ******************************************************************************/
+
+typedef struct
+{
+	ggp_account_token *token;
+	PurpleConnection *gc;
+	
+	gchar *email;
+	gchar *password_current;
+	gchar *password_new;
+	gchar *token_value;
+} ggp_account_chpass_data;
+
+static void ggp_account_chpass_data_free(ggp_account_chpass_data *chpass_data);
+static void ggp_account_chpass_dialog(PurpleConnection *gc,
+	ggp_account_token *token, gpointer _chpass_data);
+static void ggp_account_chpass_dialog_ok(
+	ggp_account_chpass_data *chpass_data, PurpleRequestFields *fields);
+static void ggp_account_chpass_dialog_invalid(
+	ggp_account_chpass_data *chpass_data, const gchar *message);
+static void ggp_account_chpass_dialog_cancel(
+	ggp_account_chpass_data *chpass_data, PurpleRequestFields *fields);
+static void ggp_account_chpass_response(struct gg_http *h, gboolean success,
+	gboolean cancelled, gpointer _chpass_data);
+
+#define GGP_ACCOUNT_CHPASS_TITLE _("Password change")
+
+/******************************************************************************/
+
+static void ggp_account_chpass_data_free(ggp_account_chpass_data *chpass_data)
+{
+	g_free(chpass_data->email);
+	g_free(chpass_data->password_current);
+	g_free(chpass_data->password_new);
+	g_free(chpass_data->token_value);
+	ggp_account_token_free(chpass_data->token);
+	g_free(chpass_data);
+}
+
+void ggp_account_chpass(PurpleConnection *gc)
+{
+	ggp_account_chpass_data *chpass_data;
+	void ggp_account_change_passwd(PurpleConnection *gc);
+	purple_debug_info("gg", "ggp_account_chpass\n");
+	
+	chpass_data = g_new0(ggp_account_chpass_data, 1);
+	chpass_data->gc = gc;
+	
+	ggp_account_token_request(gc, ggp_account_chpass_dialog, chpass_data);
+}
+
+static void ggp_account_chpass_dialog(PurpleConnection *gc,
+	ggp_account_token *token, gpointer _chpass_data)
+{
+	ggp_account_chpass_data *chpass_data = _chpass_data;
+	PurpleAccount *account = purple_connection_get_account(chpass_data->gc);
+	PurpleRequestFields *fields;
+	PurpleRequestFieldGroup *main_group, *password_group, *token_group;
+	PurpleRequestField *field, *field_password;
+	gchar *primary;
+	
+	purple_debug_info("gg", "ggp_account_chpass_dialog(%p, %p, %p)\n",
+		gc, token, _chpass_data);
+	if (!token)
+	{
+		ggp_account_chpass_data_free(chpass_data);
+		return;
+	}
+	
+	fields = purple_request_fields_new();
+	main_group = purple_request_field_group_new(NULL);
+	purple_request_fields_add_group(fields, main_group);
+	
+	field = purple_request_field_string_new("email",
+		_("New email address"), chpass_data->email, FALSE);
+	purple_request_field_set_required(field, TRUE);
+	purple_request_field_set_validator(field,
+		purple_request_field_email_validator, NULL);
+	purple_request_field_group_add_field(main_group, field);
+
+	password_group = purple_request_field_group_new(_("Password"));
+	purple_request_fields_add_group(fields, password_group);
+
+	field = purple_request_field_string_new("password_current",
+		_("Current password"), chpass_data->password_current, FALSE);
+	purple_request_field_set_required(field, TRUE);
+	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_group_add_field(password_group, field);
+	
+	field = purple_request_field_string_new("password_new1",
+		_("Password"), chpass_data->password_new, FALSE);
+	purple_request_field_set_required(field, TRUE);
+	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_set_validator(field, ggp_validator_password, NULL);
+	purple_request_field_group_add_field(password_group, field);
+	field_password = field;
+	
+	field = purple_request_field_string_new("password_new2",
+		_("Password (retype)"), chpass_data->password_new, FALSE);
+	purple_request_field_set_required(field, TRUE);
+	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_set_validator(field, ggp_validator_password_equal,
+		field_password);
+	purple_request_field_group_add_field(password_group, field);
+	
+	token_group = purple_request_field_group_new(_("Captcha"));
+	purple_request_fields_add_group(fields, token_group);
+	
+	field = purple_request_field_string_new("token_value",
+		_("Enter text from image below"), chpass_data->token_value,
+		FALSE);
+	purple_request_field_set_required(field, TRUE);
+	purple_request_field_set_validator(field, ggp_validator_token, token);
+	purple_request_field_group_add_field(token_group, field);
+	
+	field = purple_request_field_image_new("token_image", _("Captcha"),
+		token->data, token->size);
+	purple_request_field_group_add_field(token_group, field);
+	
+	chpass_data->token = token;
+	
+	primary = g_strdup_printf(_("Change password for %s"),
+		purple_account_get_username(account));
+	
+	purple_request_fields(gc, GGP_ACCOUNT_CHPASS_TITLE, primary,
+		_("Please enter your current password and your new password."),
+		fields,
+		_("OK"), G_CALLBACK(ggp_account_chpass_dialog_ok),
+		_("Cancel"), G_CALLBACK(ggp_account_chpass_dialog_cancel),
+		account, NULL, NULL, chpass_data);
+	
+	g_free(primary);
+}
+
+static void ggp_account_chpass_dialog_ok(
+	ggp_account_chpass_data *chpass_data, PurpleRequestFields *fields)
+{
+	PurpleAccount *account = purple_connection_get_account(chpass_data->gc);
+	struct gg_http *h;
+	uin_t uin;
+
+	purple_debug_misc("gg", "ggp_account_chpass_dialog_ok(%p, %p)\n",
+		chpass_data, fields);
+
+	g_free(chpass_data->email);
+	g_free(chpass_data->password_current);
+	g_free(chpass_data->password_new);
+	g_free(chpass_data->token_value);
+	
+	chpass_data->email = g_strdup(
+		purple_request_fields_get_string(fields, "email"));
+	chpass_data->password_current = g_strdup(
+		purple_request_fields_get_string(fields, "password_current"));
+	chpass_data->password_new = g_strdup(
+		purple_request_fields_get_string(fields, "password_new1"));
+	chpass_data->token_value = g_strdup(
+		purple_request_fields_get_string(fields, "token_value"));
+
+	g_assert(chpass_data->email != NULL);
+	g_assert(chpass_data->password_current != NULL);
+	g_assert(chpass_data->password_new != NULL);
+	g_assert(chpass_data->token_value != NULL);
+
+	if (g_utf8_collate(chpass_data->password_current,
+		purple_connection_get_password(chpass_data->gc)) != 0)
+	{
+		g_free(chpass_data->password_current);
+		chpass_data->password_current = NULL;
+		ggp_account_chpass_dialog_invalid(chpass_data,
+			_("Your current password is different from the one that"
+			" you specified."));
+		return;
+	}
+	if (g_utf8_collate(chpass_data->password_current,
+		chpass_data->password_new) == 0)
+	{
+		g_free(chpass_data->password_new);
+		chpass_data->password_new = NULL;
+		ggp_account_chpass_dialog_invalid(chpass_data,
+			_("New password have to be different from the current "
+			"one."));
+		return;
+	}
+
+	uin = ggp_str_to_uin(purple_account_get_username(account));
+	purple_debug_info("gg", "ggp_account_chpass_dialog_ok: validation ok "
+		"[token id=%s, value=%s]\n",
+		chpass_data->token->id, chpass_data->token_value);
+	h = gg_change_passwd4(uin, chpass_data->email,
+		chpass_data->password_current, chpass_data->password_new,
+		chpass_data->token->id, chpass_data->token_value, TRUE);
+	
+	ggp_libgaduw_http_watch(chpass_data->gc, h,
+		ggp_account_chpass_response, chpass_data, TRUE);
+}
+
+static void ggp_account_chpass_dialog_invalid(
+	ggp_account_chpass_data *chpass_data, const gchar *message)
+{
+	purple_debug_warning("gg", "ggp_account_chpass_dialog_invalid: %s\n",
+		message);
+	ggp_account_chpass_dialog(chpass_data->gc, chpass_data->token,
+		chpass_data);
+	purple_notify_error(purple_connection_get_account(chpass_data->gc),
+		GGP_ACCOUNT_CHPASS_TITLE, message, NULL);
+}
+
+static void ggp_account_chpass_dialog_cancel(
+	ggp_account_chpass_data *chpass_data, PurpleRequestFields *fields)
+{
+	ggp_account_chpass_data_free(chpass_data);
+}
+
+static void ggp_account_chpass_response(struct gg_http *h, gboolean success,
+	gboolean cancelled, gpointer _chpass_data)
+{
+	ggp_account_chpass_data *chpass_data = _chpass_data;
+	PurpleAccount *account =
+		purple_connection_get_account(chpass_data->gc);
+	struct gg_pubdir *chpass_result = h->data;
+	
+	g_assert(!(success && cancelled));
+	
+	if (cancelled)
+	{
+		purple_debug_info("gg", "ggp_account_chpass_response: "
+			"cancelled\n");
+		ggp_account_chpass_data_free(chpass_data);
+		return;
+	}
+	if (!success || !chpass_result->success)
+	{
+		//TODO (libgadu 1.12.x): check chpass_result->error
+		purple_debug_error("gg", "ggp_account_chpass_response: "
+			"error\n");
+		purple_notify_error(NULL,
+			GGP_ACCOUNT_CHPASS_TITLE,
+			_("Unable to change password. "
+			"An unknown error occurred."), NULL);
+		ggp_account_chpass_data_free(chpass_data);
+		return;
+	}
+
+	purple_debug_info("gg", "ggp_account_chpass_response: "
+		"password changed\n");
+	
+	purple_account_set_password(account, chpass_data->password_new, NULL, NULL);
+
+	purple_notify_info(account, GGP_ACCOUNT_CHPASS_TITLE,
+		_("Your password has been changed."), NULL);
+	
+	ggp_account_chpass_data_free(chpass_data);
+	
+	//TODO: reconnect / check how it is done in original client
+	purple_account_disconnect(account);
+}

mercurial