Mercurial > pidgin.yaz
diff libpurple/protocols/mxit/login.c @ 28903:69aa4660401a
Initial addition of the MXit protocol plugin, provided by the MXit folks
themselves.
author | John Bailey <rekkanoryo@rekkanoryo.org> |
---|---|
date | Sun, 08 Nov 2009 23:55:56 +0000 |
parents | |
children | 95f8e7fb1f67 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/mxit/login.c Sun Nov 08 23:55:56 2009 +0000 @@ -0,0 +1,789 @@ +/* + * MXit Protocol libPurple Plugin + * + * -- MXit user login functionality -- + * + * Pieter Loubser <libpurple@mxit.com> + * + * (C) Copyright 2009 MXit Lifestyle (Pty) Ltd. + * <http://www.mxitlifestyle.com> + * + * 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 <stdio.h> +#include <string.h> + +#include "purple.h" + +#include "protocol.h" +#include "mxit.h" +#include "cipher.h" +#include "login.h" +#include "profile.h" + +/* requesting captcha size */ +#define MXIT_CAPTCHA_HEIGHT 50 +#define MXIT_CAPTCHA_WIDTH 150 + + +/* prototypes */ +static void mxit_register_view( struct MXitSession* session ); +static void get_clientinfo( struct MXitSession* session ); + + +/*------------------------------------------------------------------------ + * Create a new mxit session object + * + * @return The MXit session object + */ +static struct MXitSession* mxit_create_object( PurpleAccount* account ) +{ + struct MXitSession* session = NULL; + PurpleConnection* con = NULL; + + /* currently the wapsite does not handle a '+' in front of the username (mxitid) so we just strip it */ + if ( account->username[0] == '+' ) { + char* fixed; + + /* cut off the '+' */ + fixed = g_strdup( &account->username[1] ); + purple_account_set_username( account, fixed ); + g_free( fixed ); + } + + session = g_new0( struct MXitSession, 1 ); + + /* configure the connection (reference: "libpurple/connection.h") */ + con = purple_account_get_connection( account ); + con->proto_data = session; + con->flags |= PURPLE_CONNECTION_NO_BGCOLOR | PURPLE_CONNECTION_NO_URLDESC | PURPLE_CONNECTION_HTML; + session->con = con; + + /* add account */ + session->acc = account; + + /* configure the session (reference: "libpurple/account.h") */ + g_strlcpy( session->server, purple_account_get_string( account, MXIT_CONFIG_SERVER_ADDR, DEFAULT_SERVER ), sizeof( session->server ) ); + g_strlcpy( session->http_server, purple_account_get_string( account, MXIT_CONFIG_HTTPSERVER, DEFAULT_HTTP_SERVER ), sizeof( session->http_server ) ); + session->port = purple_account_get_int( account, MXIT_CONFIG_SERVER_PORT, DEFAULT_PORT ); + g_strlcpy( session->distcode, purple_account_get_string( account, MXIT_CONFIG_DISTCODE, "" ), sizeof( session->distcode ) ); + g_strlcpy( session->clientkey, purple_account_get_string( account, MXIT_CONFIG_CLIENTKEY, "" ), sizeof( session->clientkey ) ); + g_strlcpy( session->dialcode, purple_account_get_string( account, MXIT_CONFIG_DIALCODE, "" ), sizeof( session->dialcode ) ); + session->http = purple_account_get_bool( account, MXIT_CONFIG_USE_HTTP, FALSE ); + session->iimages = g_hash_table_new( g_str_hash, g_str_equal ); + session->rx_state = RX_STATE_RLEN; + session->http_interval = MXIT_HTTP_POLL_MIN; + session->http_last_poll = time( NULL ); + + return session; +} + + +/*------------------------------------------------------------------------ + * We now have a connection established with MXit, so we can start the + * login procedure + * + * @param session The MXit session object + */ +static void mxit_connected( struct MXitSession* session ) +{ + int state; + + purple_debug_info( MXIT_PLUGIN_ID, "mxit_connected\n" ); + + session->flags |= MXIT_FLAG_CONNECTED; + purple_connection_update_progress( session->con, _( "Logging In..." ), 2, 4 ); + + /* create a timer to send a ping packet if the connection is idle */ + session->last_tx = time( NULL ); + + /* encrypt the user password */ + session->encpwd = mxit_encrypt_password( session ); + + state = purple_account_get_int( session->acc, MXIT_CONFIG_STATE, MXIT_STATE_LOGIN ); + if ( state == MXIT_STATE_LOGIN ) { + /* create and send login packet */ + mxit_send_login( session ); + } + else { + if ( !session->profile ) { + /* we have lost the session profile, so ask the user to enter it again */ + mxit_register_view( session ); + } + else { + /* create and send the register packet */ + mxit_send_register( session ); + } + } + + /* enable signals */ + mxit_enable_signals( session ); + +#ifdef MXIT_LINK_CLICK + /* register for uri click notification */ + mxit_register_uri_handler(); +#endif + + /* start the polling if this is a HTTP connection */ + if ( session->http ) { + session->http_timer_id = purple_timeout_add_seconds( 2, mxit_manage_polling, session ); + } + + /* start the tx queue manager timer */ + session->q_timer = purple_timeout_add_seconds( 2, mxit_manage_queue, session ); +} + + +/*------------------------------------------------------------------------ + * Callback invoked once the connection has been established to the MXit server, + * or on connection failure. + * + * @param user_data The MXit session object + * @param source The file-descriptor associated with the connection + * @param error_message Message explaining why the connection failed + */ +static void mxit_cb_connect( gpointer user_data, gint source, const gchar* error_message ) +{ + struct MXitSession* session = (struct MXitSession*) user_data; + + purple_debug_info( MXIT_PLUGIN_ID, "mxit_cb_connect\n" ); + + /* source is the file descriptor of the new connection */ + if ( source < 0 ) { + purple_debug_info( MXIT_PLUGIN_ID, "mxit_cb_connect failed: %s\n", error_message ); + purple_connection_error( session->con, _( "Unable to connect to the mxit server. Please check your server server settings." ) ); + return; + } + + /* we now have an open and active TCP connection to the mxit server */ + session->fd = source; + + /* start listening on the open connection for messages from the server (reference: "libpurple/eventloop.h") */ + session->con->inpa = purple_input_add( session->fd, PURPLE_INPUT_READ, mxit_cb_rx, session ); + + mxit_connected( session ); +} + + +/*------------------------------------------------------------------------ + * Attempt to establish a connection to the MXit server. + * + * @param session The MXit session object + */ +static void mxit_login_connect( struct MXitSession* session ) +{ + PurpleProxyConnectData* data = NULL; + + purple_debug_info( MXIT_PLUGIN_ID, "mxit_login_connect\n" ); + + purple_connection_update_progress( session->con, _( "Connecting..." ), 1, 4 ); + + /* + * at this stage we have all the user's information we require + * for logging into MXit. we will now create a new connection to + * a MXit server. + */ + + if ( !session->http ) { + /* socket connection */ + data = purple_proxy_connect( session->con, session->acc, session->server, session->port, mxit_cb_connect, session ); + if ( !data ) { + purple_connection_error( session->con, _( "Unable to connect to the mxit server. Please check your server server settings." ) ); + return; + } + } + else { + /* http connection */ + mxit_connected( session ); + } +} + + +/*------------------------------------------------------------------------ + * Register a new account with MXit + * + * @param gc The connection object + * @param fields This is the fields filled-in by the user + */ +static void mxit_cb_register_ok( PurpleConnection *gc, PurpleRequestFields *fields ) +{ + struct MXitSession* session = (struct MXitSession*) gc->proto_data; + struct MXitProfile* profile = session->profile; + const char* str; + const char* pin; + char* err = NULL; + int len; + int i; + + purple_debug_info( MXIT_PLUGIN_ID, "mxit_cb_register_ok\n" ); + + if ( !PURPLE_CONNECTION_IS_VALID( gc ) ) { + purple_debug_error( MXIT_PLUGIN_ID, "Unable to register; account offline.\n" ); + return; + } + + /* nickname */ + str = purple_request_fields_get_string( fields, "nickname" ); + if ( ( !str ) || ( strlen( str ) < 3 ) ) { + err = "The nick name you entered is invalid."; + goto out; + } + g_strlcpy( profile->nickname, str, sizeof( profile->nickname ) ); + + /* birthdate */ + str = purple_request_fields_get_string( fields, "bday" ); + if ( ( !str ) || ( strlen( str ) < 10 ) || ( !validateDate( str ) ) ) { + err = "The birthday you entered is invalid. The correct format is: 'YYYY-MM-DD'."; + goto out; + } + g_strlcpy( profile->birthday, str, sizeof( profile->birthday ) ); + + /* gender */ + if ( purple_request_fields_get_choice( fields, "male" ) == 0 ) + profile->male = FALSE; + else + profile->male = TRUE; + + /* pin */ + pin = purple_request_fields_get_string( fields, "pin" ); + if ( !pin ) { + err = "The PIN you entered is invalid."; + goto out; + } + len = strlen( pin ); + if ( ( len < 7 ) || ( len > 10 ) ) { + err = "The PIN you entered has an invalid length [7-10]."; + goto out; + } + for ( i = 0; i < len; i++ ) { + if ( !g_ascii_isdigit( pin[i] ) ) { + err = "The PIN is invalid. It should only consist of digits [0-9]."; + goto out; + } + } + str = purple_request_fields_get_string( fields, "pin2" ); + if ( ( !str ) || ( strcmp( pin, str ) != 0 ) ) { + err = "The two PINs you entered does not match."; + goto out; + } + g_strlcpy( profile->pin, pin, sizeof( profile->pin ) ); + +out: + if ( !err ) { + purple_account_set_password( session->acc, session->profile->pin ); + mxit_login_connect( session ); + } + else { + /* show error to user */ + mxit_popup( PURPLE_NOTIFY_MSG_ERROR, _( "Registration Error" ), _( err ) ); + mxit_register_view( session ); + } +} + + +/*------------------------------------------------------------------------ + * Register a new account with MXit + * + * @param gc The connection object + * @param fields This is the fields filled-in by the user + */ +static void mxit_cb_register_cancel( PurpleConnection *gc, PurpleRequestFields *fields ) +{ + purple_debug_info( MXIT_PLUGIN_ID, "mxit_cb_register_cancel\n" ); + + /* disconnect */ + purple_account_disconnect( gc->account ); +} + + +/*------------------------------------------------------------------------ + * Show a window to the user so that he can enter his information + * + * @param session The MXit session object + */ +static void mxit_register_view( struct MXitSession* session ) +{ + struct MXitProfile* profile; + PurpleRequestFields* fields; + PurpleRequestFieldGroup* group; + PurpleRequestField* field; + + if ( !session->profile ) { + /* we need to create a profile object here */ + session->profile = g_new0( struct MXitProfile, 1 ); + } + profile = session->profile; + + fields = purple_request_fields_new(); + group = purple_request_field_group_new( NULL ); + purple_request_fields_add_group( fields, group ); + + /* mxit login name */ + field = purple_request_field_string_new( "loginname", _( "MXit Login Name" ), purple_account_get_username( session->acc ), FALSE ); + purple_request_field_string_set_editable( field, FALSE ); + purple_request_field_group_add_field( group, field ); + + /* nick name */ + field = purple_request_field_string_new( "nickname", _( "Nick Name" ), profile->nickname, FALSE ); + purple_request_field_group_add_field( group, field ); + + /* birthday */ + field = purple_request_field_string_new( "bday", _( "Birthday" ), profile->birthday, FALSE ); + purple_request_field_string_set_default_value( field, "YYYY-MM-DD" ); + purple_request_field_group_add_field( group, field ); + + /* gender */ + field = purple_request_field_choice_new( "male", _( "Gender" ), ( profile->male ) ? 1 : 0 ); + purple_request_field_choice_add( field, _( "Female" ) ); /* 0 */ + purple_request_field_choice_add( field, _( "Male" ) ); /* 1 */ + purple_request_field_group_add_field( group, field ); + + /* pin */ + field = purple_request_field_string_new( "pin", _( "PIN" ), profile->pin, FALSE ); + purple_request_field_string_set_masked( field, TRUE ); + purple_request_field_group_add_field( group, field ); + field = purple_request_field_string_new( "pin2", _( "Verify PIN" ), "", FALSE ); + purple_request_field_string_set_masked( field, TRUE ); + purple_request_field_group_add_field( group, field ); + + /* show the form to the user to complete */ + purple_request_fields( session->con, _( "Register New MXit Account" ), _( "Register New MXit Account" ), _( "Please fill in the following fields:" ), fields, _( "OK" ), G_CALLBACK( mxit_cb_register_ok ), _( "Cancel" ), G_CALLBACK( mxit_cb_register_cancel ), session->acc, NULL, NULL, session->con ); +} + + +/*------------------------------------------------------------------------ + * Callback function invoked once the Authorization information has been submitted + * to the MXit WAP site. + * + * @param url_data libPurple internal object (see purple_util_fetch_url_request) + * @param user_data The MXit session object + * @param url_text The data returned from the WAP site + * @param len The length of the data returned + * @param error_message Descriptive error message + */ +static void mxit_cb_clientinfo2( PurpleUtilFetchUrlData* url_data, gpointer user_data, const gchar* url_text, gsize len, const gchar* error_message ) +{ + struct MXitSession* session = (struct MXitSession*) user_data; + gchar** parts; + gchar** host; + int state; + + purple_debug_info( MXIT_PLUGIN_ID, "mxit_clientinfo_cb2\n" ); + +#ifdef DEBUG_PROTOCOL + purple_debug_info( MXIT_PLUGIN_ID, "HTTP RESPONSE: '%s'\n", url_text ); +#endif + + if ( !url_text ) { + /* no reply from the WAP site */ + purple_connection_error( session->con, _( "Error contacting the MXit WAP site. Please try again later." ) ); + return; + } + + /* explode the response from the WAP site into an array */ + parts = g_strsplit( url_text, ";", 15 ); + + if ( !parts ) { + /* wapserver error */ + purple_connection_error( session->con, _( "MXit is currently unable to process the request. Please try again later." ) ); + return; + } + + /* check wapsite return code */ + switch ( parts[0][0] ) { + case '0' : + /* valid reply! */ + break; + case '1' : + purple_connection_error( session->con, _( "Wrong security code entered. Please try again later." ) ); + return; + case '2' : + purple_connection_error( session->con, _( "Your session has expired. Please try again later." ) ); + return; + case '5' : + purple_connection_error( session->con, _( "Invalid country selected. Please try again." ) ); + return; + case '6' : + purple_connection_error( session->con, _( "Username is not registered. Please register first." ) ); + return; + case '7' : + purple_connection_error( session->con, _( "Username is already registered. Please choose another username." ) ); + /* this user's account already exists, so we need to change the registration login flag to be login */ + purple_account_set_int( session->acc, MXIT_CONFIG_STATE, MXIT_STATE_LOGIN ); + return; + case '3' : + case '4' : + default : + purple_connection_error( session->con, _( "Internal error. Please try again later." ) ); + return; + } + + /* now parse and split the distribution code and the client key */ + g_strlcpy( session->distcode, &parts[1][2], 36 + 1 ); + g_strlcpy( session->clientkey, &parts[1][38], 8 + 1 ); + + /* get the dial code for the client */ + g_strlcpy( session->dialcode, parts[4], sizeof( session->dialcode ) ); + + /* parse the proxy server address and port number */ + host = g_strsplit( parts[2], ":", 4 ); + g_strlcpy( session->server, &host[1][2], sizeof( session->server ) ); + session->port = atoi( &host[2][0] ); + + /* parse the http proxy server address and port number */ + g_strlcpy( session->http_server, parts[3], sizeof( session->http_server ) ); + + purple_debug_info( MXIT_PLUGIN_ID, "distcode='%s', clientkey='%s', dialcode='%s'\n", session->distcode, session->clientkey, session->dialcode ); + purple_debug_info( MXIT_PLUGIN_ID, "sock_server='%s', http_server='%s', port='%i', cc='%s'\n", session->server, session->http_server, session->port, parts[11] ); + + /* save the information (reference: "libpurple/account.h") */ + purple_account_set_string( session->acc, MXIT_CONFIG_DISTCODE, session->distcode ); + purple_account_set_string( session->acc, MXIT_CONFIG_CLIENTKEY, session->clientkey ); + purple_account_set_string( session->acc, MXIT_CONFIG_DIALCODE, session->dialcode ); + purple_account_set_string( session->acc, MXIT_CONFIG_SERVER_ADDR, session->server ); + purple_account_set_int( session->acc, MXIT_CONFIG_SERVER_PORT, session->port ); + purple_account_set_string( session->acc, MXIT_CONFIG_HTTPSERVER, session->http_server ); + + /* update the state */ + state = purple_account_get_int( session->acc, MXIT_CONFIG_STATE, MXIT_STATE_LOGIN ); + if ( state == MXIT_STATE_REGISTER1 ) + purple_account_set_int( session->acc, MXIT_CONFIG_STATE, MXIT_STATE_REGISTER2 ); + + /* freeup the memory */ + g_strfreev( host ); + g_strfreev( parts ); + + if ( state == MXIT_STATE_LOGIN ) { + /* now we can continue with the login process */ + mxit_login_connect( session ); + } + else { + /* the user is registering so we need to get more information from him/her first to complete the process */ + mxit_register_view( session ); + } +} + + +/*------------------------------------------------------------------------ + * Free up the data associated with the Authorization process. + * + * @param data The data object to free + */ +static void free_logindata( struct login_data* data ) +{ + if ( !data ) + return; + + /* free up the login resources */ + g_free( data->wapserver ); + g_free( data->sessionid ); + g_free( data->captcha ); + g_free( data->cc ); + g_free( data->locale ); + g_free( data ); +} + + +/*------------------------------------------------------------------------ + * This function is called when the user accepts the Authorization form. + * + * @param gc The connection object + * @param fields The list of fields in the accepted form + */ +static void mxit_cb_captcha_ok( PurpleConnection* gc, PurpleRequestFields* fields ) +{ + struct MXitSession* session = (struct MXitSession*) gc->proto_data; + PurpleUtilFetchUrlData* url_data; + PurpleRequestField* field; + const char* captcha_resp; + GList* entries; + GList* entry; + char* url; + int state; + + /* get the captcha response */ + captcha_resp = purple_request_fields_get_string( fields, "code" ); + if ( ( captcha_resp == NULL ) || ( captcha_resp[0] == '\0' ) ) { + /* the user did not fill in the captcha */ + mxit_popup( PURPLE_NOTIFY_MSG_ERROR, _( "Error" ), _( "You did not enter the security code" ) ); + free_logindata( session->logindata ); + purple_account_disconnect( session->acc ); + return; + } + + /* get chosen country */ + field = purple_request_fields_get_field( fields, "country" ); + entries = purple_request_field_list_get_selected( field ); + entry = g_list_first( entries ); + session->logindata->cc = purple_request_field_list_get_data( field, entry->data ); + purple_account_set_string( session->acc, MXIT_CONFIG_COUNTRYCODE, session->logindata->cc ); + + /* get chosen language */ + field = purple_request_fields_get_field( fields, "locale" ); + entries = purple_request_field_list_get_selected( field ); + entry = g_list_first( entries ); + session->logindata->locale = purple_request_field_list_get_data( field, entry->data ); + purple_account_set_string( session->acc, MXIT_CONFIG_LOCALE, session->logindata->locale ); + +#ifdef DEBUG_PROTOCOL + purple_debug_info( MXIT_PLUGIN_ID, "cc='%s', locale='%s', captcha='%s'\n", session->logindata->cc, session->logindata->locale, captcha_resp ); +#endif + + /* get state */ + state = purple_account_get_int( session->acc, MXIT_CONFIG_STATE, MXIT_STATE_LOGIN ); + + url = g_strdup_printf( "%s?type=getpid&sessionid=%s&login=%s&ver=%s&clientid=%s&cat=%s&chalresp=%s&cc=%s&loc=%s&path=%i&brand=%s&model=%s&h=%i&w=%i&ts=%li", + session->logindata->wapserver, session->logindata->sessionid, purple_url_encode( session->acc->username ), MXIT_CP_RELEASE, MXIT_CLIENT_ID, MXIT_CP_ARCH, + captcha_resp, session->logindata->cc, session->logindata->locale, ( state == MXIT_STATE_REGISTER1 ) ? 0 : 1, MXIT_CP_PLATFORM, MXIT_CP_OS, + MXIT_CAPTCHA_HEIGHT, MXIT_CAPTCHA_WIDTH, time( NULL ) ); + url_data = purple_util_fetch_url_request( url, TRUE, MXIT_HTTP_USERAGENT, TRUE, NULL, FALSE, mxit_cb_clientinfo2, session ); + +#ifdef DEBUG_PROTOCOL + purple_debug_info( MXIT_PLUGIN_ID, "HTTP REQUEST: '%s'\n", url ); +#endif + g_free( url ); + + /* free up the login resources */ + free_logindata( session->logindata ); +} + + +/*------------------------------------------------------------------------ + * This function is called when the user cancels the Authorization form. + * + * @param gc The connection object + * @param fields The list of fields in the cancelled form + */ +static void mxit_cb_captcha_cancel( PurpleConnection* gc, PurpleRequestFields* fields ) +{ + struct MXitSession* session = (struct MXitSession*) gc->proto_data; + + /* free up the login resources */ + free_logindata( session->logindata ); + + /* we cannot continue, so we disconnect this account */ + purple_account_disconnect( session->acc ); +} + + +/*------------------------------------------------------------------------ + * Callback function invoked once the client information has been retrieved from + * the MXit WAP site. Display page where user can select their authorization information. + * + * @param url_data libPurple internal object (see purple_util_fetch_url_request) + * @param user_data The MXit session object + * @param url_text The data returned from the WAP site + * @param len The length of the data returned + * @param error_message Descriptive error message + */ +static void mxit_cb_clientinfo1( PurpleUtilFetchUrlData* url_data, gpointer user_data, const gchar* url_text, gsize len, const gchar* error_message ) +{ + struct MXitSession* session = (struct MXitSession*) user_data; + struct login_data* logindata; + PurpleRequestFields* fields; + PurpleRequestFieldGroup* group = NULL; + PurpleRequestField* field = NULL; + gchar** parts; + gchar** countries; + gchar** locales; + int i; + + purple_debug_info( MXIT_PLUGIN_ID, "mxit_clientinfo_cb1\n" ); + +#ifdef DEBUG_PROTOCOL + purple_debug_info( MXIT_PLUGIN_ID, "RESPONSE: %s\n", url_text ); +#endif + + if ( !url_text ) { + /* no reply from the WAP site */ + purple_connection_error( session->con, _( "Error contacting the MXit WAP site. Please try again later." ) ); + return; + } + + /* explode the response from the WAP site into an array */ + parts = g_strsplit( url_text, ";", 15 ); + + if ( ( !parts ) || ( parts[0][0] != '0' ) ) { + /* server could not find the user */ + purple_connection_error( session->con, _( "MXit is currently unable to process the request. Please try again later." ) ); + return; + } + + /* save received settings */ + logindata = g_new0( struct login_data, 1 ); + logindata->wapserver = g_strdup( parts[1] ); + logindata->sessionid = g_strdup( parts[2] ); + session->logindata = logindata; + + /* now generate the popup requesting the user for action */ + + fields = purple_request_fields_new(); + group = purple_request_field_group_new( NULL ); + purple_request_fields_add_group( fields, group ); + + /* add the captcha */ + logindata->captcha = purple_base64_decode( parts[3], &logindata->captcha_size ); + field = purple_request_field_image_new( "capcha", _( "Security Code" ), (gchar*) logindata->captcha, logindata->captcha_size ); + purple_request_field_group_add_field( group, field ); + + /* ask for input */ + field = purple_request_field_string_new( "code", _( "Enter Security Code" ), NULL, FALSE ); + purple_request_field_group_add_field( group, field ); + + /* choose your country, but be careful, we already know your IP! ;-) */ + countries = g_strsplit( parts[4], ",", 500 ); + field = purple_request_field_list_new( "country", _( "Your Country" ) ); + purple_request_field_list_set_multi_select( field, FALSE ); + for ( i = 0; countries[i]; i++ ) { + gchar** country; + + country = g_strsplit( countries[i], "|", 2 ); + if ( !country ) { + /* oops, this is not good, time to bail */ + break; + } + purple_request_field_list_add( field, country[1], g_strdup( country[0] ) ); + if ( strcmp( country[1], parts[6] ) == 0 ) { + /* based on the user's ip, this is his current country code, so we default to it */ + purple_request_field_list_add_selected( field, country[1] ); + } + g_strfreev( country ); + } + purple_request_field_group_add_field( group, field ); + + /* choose your language */ + locales = g_strsplit( parts[5], ",", 200 ); + field = purple_request_field_list_new( "locale", _( "Your Language" ) ); + purple_request_field_list_set_multi_select( field, FALSE ); + for ( i = 0; locales[i]; i++ ) { + gchar** locale; + + locale = g_strsplit( locales[i], "|", 2 ); + if ( !locale ) { + /* oops, this is not good, time to bail */ + break; + } + purple_request_field_list_add( field, locale[1], g_strdup( locale[0] ) ); + g_strfreev( locale ); + } + purple_request_field_list_add_selected( field, "English" ); + purple_request_field_group_add_field( group, field ); + + /* display the form to the user and wait for his/her input */ + purple_request_fields( session->con, "MXit", _( "MXit Authorization" ), _( "MXit account validation" ), fields, + _( "Continue" ), G_CALLBACK( mxit_cb_captcha_ok ), _( "Cancel" ), G_CALLBACK( mxit_cb_captcha_cancel ), session->acc, NULL, NULL, session->con ); + + /* freeup the memory */ + g_strfreev( parts ); +} + + +/*------------------------------------------------------------------------ + * Initiate a request for the client information (distribution code, client key, etc) + * required for logging in from the MXit WAP site. + * + * @param session The MXit session object + */ +static void get_clientinfo( struct MXitSession* session ) +{ + PurpleUtilFetchUrlData* url_data; + const char* wapserver; + char* url; + + purple_debug_info( MXIT_PLUGIN_ID, "get_clientinfo\n" ); + + purple_connection_update_progress( session->con, _( "Retrieving User Information..." ), 0, 4 ); + + /* get the WAP site as was configured by the user in the advanced settings */ + wapserver = purple_account_get_string( session->acc, MXIT_CONFIG_WAPSERVER, DEFAULT_WAPSITE ); + + /* reference: "libpurple/util.h" */ + url = g_strdup_printf( "%s/res/?type=challenge&getcountries=true&getlanguage=true&getimage=true&h=%i&w=%i&ts=%li", wapserver, MXIT_CAPTCHA_HEIGHT, MXIT_CAPTCHA_WIDTH, time( NULL ) ); + url_data = purple_util_fetch_url_request( url, TRUE, MXIT_HTTP_USERAGENT, TRUE, NULL, FALSE, mxit_cb_clientinfo1, session ); + +#ifdef DEBUG_PROTOCOL + purple_debug_info( MXIT_PLUGIN_ID, "HTTP REQUEST: '%s'\n", url ); +#endif + g_free( url ); +} + + +/*------------------------------------------------------------------------ + * Log the user into MXit. + * + * @param account The account object + */ +void mxit_login( PurpleAccount* account ) +{ + struct MXitSession* session = NULL; + + purple_debug_info( MXIT_PLUGIN_ID, "mxit_login\n" ); + + /* create and save a new mxit session */ + session = mxit_create_object( account ); + + /* + * before we can login we need to have a valid distribution code and client key for authentication. + * if we don't have any info saved from a previous login, we need to get it from the MXit WAP site. + * we do cache it, so this step is only done on the very first login for each account. + */ + if ( ( session->distcode == NULL ) || ( strlen( session->distcode ) == 0 ) ) { + /* this must be the very first login, so we need to retrieve the user information */ + get_clientinfo( session ); + } + else { + /* we can continue with the login */ + mxit_login_connect( session ); + } +} + + +/*------------------------------------------------------------------------ + * Perform a reconnect to the MXit server, and maintain same session object. + * + * @param account The account object + */ +void mxit_reconnect( struct MXitSession* session ) +{ + purple_debug_info( MXIT_PLUGIN_ID, "mxit_reconnect\n" ); + + /* close existing connection */ + session->flags &= ~MXIT_FLAG_CONNECTED; + purple_proxy_connect_cancel_with_handle( session->con ); + + /* perform the re-connect */ + mxit_login_connect( session ); +} + + +/*------------------------------------------------------------------------ + * Register a new account with MXit + * + * @param acc The account object + */ +void mxit_register( PurpleAccount* account ) +{ + struct MXitSession* session = NULL; + + purple_debug_info( MXIT_PLUGIN_ID, "mxit_register\n" ); + + /* create and save a new mxit session */ + session = mxit_create_object( account ); + purple_account_set_int( account, MXIT_CONFIG_STATE, MXIT_STATE_REGISTER1 ); + + get_clientinfo( session ); +} +