Sun, 13 Jan 2013 15:09:02 -0600
Merge revision 33422 from release-2.x.y
/* 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); 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_account_get_password(account)) != 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); 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); }