Mercurial > pidgin
comparison libpurple/protocols/mxit/login.c @ 28526: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 |
comparison
equal
deleted
inserted
replaced
28525:13e668ef158d | 28526:69aa4660401a |
---|---|
1 /* | |
2 * MXit Protocol libPurple Plugin | |
3 * | |
4 * -- MXit user login functionality -- | |
5 * | |
6 * Pieter Loubser <libpurple@mxit.com> | |
7 * | |
8 * (C) Copyright 2009 MXit Lifestyle (Pty) Ltd. | |
9 * <http://www.mxitlifestyle.com> | |
10 * | |
11 * This program is free software; you can redistribute it and/or modify | |
12 * it under the terms of the GNU General Public License as published by | |
13 * the Free Software Foundation; either version 2 of the License, or | |
14 * (at your option) any later version. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA | |
24 */ | |
25 | |
26 #include <stdio.h> | |
27 #include <string.h> | |
28 | |
29 #include "purple.h" | |
30 | |
31 #include "protocol.h" | |
32 #include "mxit.h" | |
33 #include "cipher.h" | |
34 #include "login.h" | |
35 #include "profile.h" | |
36 | |
37 /* requesting captcha size */ | |
38 #define MXIT_CAPTCHA_HEIGHT 50 | |
39 #define MXIT_CAPTCHA_WIDTH 150 | |
40 | |
41 | |
42 /* prototypes */ | |
43 static void mxit_register_view( struct MXitSession* session ); | |
44 static void get_clientinfo( struct MXitSession* session ); | |
45 | |
46 | |
47 /*------------------------------------------------------------------------ | |
48 * Create a new mxit session object | |
49 * | |
50 * @return The MXit session object | |
51 */ | |
52 static struct MXitSession* mxit_create_object( PurpleAccount* account ) | |
53 { | |
54 struct MXitSession* session = NULL; | |
55 PurpleConnection* con = NULL; | |
56 | |
57 /* currently the wapsite does not handle a '+' in front of the username (mxitid) so we just strip it */ | |
58 if ( account->username[0] == '+' ) { | |
59 char* fixed; | |
60 | |
61 /* cut off the '+' */ | |
62 fixed = g_strdup( &account->username[1] ); | |
63 purple_account_set_username( account, fixed ); | |
64 g_free( fixed ); | |
65 } | |
66 | |
67 session = g_new0( struct MXitSession, 1 ); | |
68 | |
69 /* configure the connection (reference: "libpurple/connection.h") */ | |
70 con = purple_account_get_connection( account ); | |
71 con->proto_data = session; | |
72 con->flags |= PURPLE_CONNECTION_NO_BGCOLOR | PURPLE_CONNECTION_NO_URLDESC | PURPLE_CONNECTION_HTML; | |
73 session->con = con; | |
74 | |
75 /* add account */ | |
76 session->acc = account; | |
77 | |
78 /* configure the session (reference: "libpurple/account.h") */ | |
79 g_strlcpy( session->server, purple_account_get_string( account, MXIT_CONFIG_SERVER_ADDR, DEFAULT_SERVER ), sizeof( session->server ) ); | |
80 g_strlcpy( session->http_server, purple_account_get_string( account, MXIT_CONFIG_HTTPSERVER, DEFAULT_HTTP_SERVER ), sizeof( session->http_server ) ); | |
81 session->port = purple_account_get_int( account, MXIT_CONFIG_SERVER_PORT, DEFAULT_PORT ); | |
82 g_strlcpy( session->distcode, purple_account_get_string( account, MXIT_CONFIG_DISTCODE, "" ), sizeof( session->distcode ) ); | |
83 g_strlcpy( session->clientkey, purple_account_get_string( account, MXIT_CONFIG_CLIENTKEY, "" ), sizeof( session->clientkey ) ); | |
84 g_strlcpy( session->dialcode, purple_account_get_string( account, MXIT_CONFIG_DIALCODE, "" ), sizeof( session->dialcode ) ); | |
85 session->http = purple_account_get_bool( account, MXIT_CONFIG_USE_HTTP, FALSE ); | |
86 session->iimages = g_hash_table_new( g_str_hash, g_str_equal ); | |
87 session->rx_state = RX_STATE_RLEN; | |
88 session->http_interval = MXIT_HTTP_POLL_MIN; | |
89 session->http_last_poll = time( NULL ); | |
90 | |
91 return session; | |
92 } | |
93 | |
94 | |
95 /*------------------------------------------------------------------------ | |
96 * We now have a connection established with MXit, so we can start the | |
97 * login procedure | |
98 * | |
99 * @param session The MXit session object | |
100 */ | |
101 static void mxit_connected( struct MXitSession* session ) | |
102 { | |
103 int state; | |
104 | |
105 purple_debug_info( MXIT_PLUGIN_ID, "mxit_connected\n" ); | |
106 | |
107 session->flags |= MXIT_FLAG_CONNECTED; | |
108 purple_connection_update_progress( session->con, _( "Logging In..." ), 2, 4 ); | |
109 | |
110 /* create a timer to send a ping packet if the connection is idle */ | |
111 session->last_tx = time( NULL ); | |
112 | |
113 /* encrypt the user password */ | |
114 session->encpwd = mxit_encrypt_password( session ); | |
115 | |
116 state = purple_account_get_int( session->acc, MXIT_CONFIG_STATE, MXIT_STATE_LOGIN ); | |
117 if ( state == MXIT_STATE_LOGIN ) { | |
118 /* create and send login packet */ | |
119 mxit_send_login( session ); | |
120 } | |
121 else { | |
122 if ( !session->profile ) { | |
123 /* we have lost the session profile, so ask the user to enter it again */ | |
124 mxit_register_view( session ); | |
125 } | |
126 else { | |
127 /* create and send the register packet */ | |
128 mxit_send_register( session ); | |
129 } | |
130 } | |
131 | |
132 /* enable signals */ | |
133 mxit_enable_signals( session ); | |
134 | |
135 #ifdef MXIT_LINK_CLICK | |
136 /* register for uri click notification */ | |
137 mxit_register_uri_handler(); | |
138 #endif | |
139 | |
140 /* start the polling if this is a HTTP connection */ | |
141 if ( session->http ) { | |
142 session->http_timer_id = purple_timeout_add_seconds( 2, mxit_manage_polling, session ); | |
143 } | |
144 | |
145 /* start the tx queue manager timer */ | |
146 session->q_timer = purple_timeout_add_seconds( 2, mxit_manage_queue, session ); | |
147 } | |
148 | |
149 | |
150 /*------------------------------------------------------------------------ | |
151 * Callback invoked once the connection has been established to the MXit server, | |
152 * or on connection failure. | |
153 * | |
154 * @param user_data The MXit session object | |
155 * @param source The file-descriptor associated with the connection | |
156 * @param error_message Message explaining why the connection failed | |
157 */ | |
158 static void mxit_cb_connect( gpointer user_data, gint source, const gchar* error_message ) | |
159 { | |
160 struct MXitSession* session = (struct MXitSession*) user_data; | |
161 | |
162 purple_debug_info( MXIT_PLUGIN_ID, "mxit_cb_connect\n" ); | |
163 | |
164 /* source is the file descriptor of the new connection */ | |
165 if ( source < 0 ) { | |
166 purple_debug_info( MXIT_PLUGIN_ID, "mxit_cb_connect failed: %s\n", error_message ); | |
167 purple_connection_error( session->con, _( "Unable to connect to the mxit server. Please check your server server settings." ) ); | |
168 return; | |
169 } | |
170 | |
171 /* we now have an open and active TCP connection to the mxit server */ | |
172 session->fd = source; | |
173 | |
174 /* start listening on the open connection for messages from the server (reference: "libpurple/eventloop.h") */ | |
175 session->con->inpa = purple_input_add( session->fd, PURPLE_INPUT_READ, mxit_cb_rx, session ); | |
176 | |
177 mxit_connected( session ); | |
178 } | |
179 | |
180 | |
181 /*------------------------------------------------------------------------ | |
182 * Attempt to establish a connection to the MXit server. | |
183 * | |
184 * @param session The MXit session object | |
185 */ | |
186 static void mxit_login_connect( struct MXitSession* session ) | |
187 { | |
188 PurpleProxyConnectData* data = NULL; | |
189 | |
190 purple_debug_info( MXIT_PLUGIN_ID, "mxit_login_connect\n" ); | |
191 | |
192 purple_connection_update_progress( session->con, _( "Connecting..." ), 1, 4 ); | |
193 | |
194 /* | |
195 * at this stage we have all the user's information we require | |
196 * for logging into MXit. we will now create a new connection to | |
197 * a MXit server. | |
198 */ | |
199 | |
200 if ( !session->http ) { | |
201 /* socket connection */ | |
202 data = purple_proxy_connect( session->con, session->acc, session->server, session->port, mxit_cb_connect, session ); | |
203 if ( !data ) { | |
204 purple_connection_error( session->con, _( "Unable to connect to the mxit server. Please check your server server settings." ) ); | |
205 return; | |
206 } | |
207 } | |
208 else { | |
209 /* http connection */ | |
210 mxit_connected( session ); | |
211 } | |
212 } | |
213 | |
214 | |
215 /*------------------------------------------------------------------------ | |
216 * Register a new account with MXit | |
217 * | |
218 * @param gc The connection object | |
219 * @param fields This is the fields filled-in by the user | |
220 */ | |
221 static void mxit_cb_register_ok( PurpleConnection *gc, PurpleRequestFields *fields ) | |
222 { | |
223 struct MXitSession* session = (struct MXitSession*) gc->proto_data; | |
224 struct MXitProfile* profile = session->profile; | |
225 const char* str; | |
226 const char* pin; | |
227 char* err = NULL; | |
228 int len; | |
229 int i; | |
230 | |
231 purple_debug_info( MXIT_PLUGIN_ID, "mxit_cb_register_ok\n" ); | |
232 | |
233 if ( !PURPLE_CONNECTION_IS_VALID( gc ) ) { | |
234 purple_debug_error( MXIT_PLUGIN_ID, "Unable to register; account offline.\n" ); | |
235 return; | |
236 } | |
237 | |
238 /* nickname */ | |
239 str = purple_request_fields_get_string( fields, "nickname" ); | |
240 if ( ( !str ) || ( strlen( str ) < 3 ) ) { | |
241 err = "The nick name you entered is invalid."; | |
242 goto out; | |
243 } | |
244 g_strlcpy( profile->nickname, str, sizeof( profile->nickname ) ); | |
245 | |
246 /* birthdate */ | |
247 str = purple_request_fields_get_string( fields, "bday" ); | |
248 if ( ( !str ) || ( strlen( str ) < 10 ) || ( !validateDate( str ) ) ) { | |
249 err = "The birthday you entered is invalid. The correct format is: 'YYYY-MM-DD'."; | |
250 goto out; | |
251 } | |
252 g_strlcpy( profile->birthday, str, sizeof( profile->birthday ) ); | |
253 | |
254 /* gender */ | |
255 if ( purple_request_fields_get_choice( fields, "male" ) == 0 ) | |
256 profile->male = FALSE; | |
257 else | |
258 profile->male = TRUE; | |
259 | |
260 /* pin */ | |
261 pin = purple_request_fields_get_string( fields, "pin" ); | |
262 if ( !pin ) { | |
263 err = "The PIN you entered is invalid."; | |
264 goto out; | |
265 } | |
266 len = strlen( pin ); | |
267 if ( ( len < 7 ) || ( len > 10 ) ) { | |
268 err = "The PIN you entered has an invalid length [7-10]."; | |
269 goto out; | |
270 } | |
271 for ( i = 0; i < len; i++ ) { | |
272 if ( !g_ascii_isdigit( pin[i] ) ) { | |
273 err = "The PIN is invalid. It should only consist of digits [0-9]."; | |
274 goto out; | |
275 } | |
276 } | |
277 str = purple_request_fields_get_string( fields, "pin2" ); | |
278 if ( ( !str ) || ( strcmp( pin, str ) != 0 ) ) { | |
279 err = "The two PINs you entered does not match."; | |
280 goto out; | |
281 } | |
282 g_strlcpy( profile->pin, pin, sizeof( profile->pin ) ); | |
283 | |
284 out: | |
285 if ( !err ) { | |
286 purple_account_set_password( session->acc, session->profile->pin ); | |
287 mxit_login_connect( session ); | |
288 } | |
289 else { | |
290 /* show error to user */ | |
291 mxit_popup( PURPLE_NOTIFY_MSG_ERROR, _( "Registration Error" ), _( err ) ); | |
292 mxit_register_view( session ); | |
293 } | |
294 } | |
295 | |
296 | |
297 /*------------------------------------------------------------------------ | |
298 * Register a new account with MXit | |
299 * | |
300 * @param gc The connection object | |
301 * @param fields This is the fields filled-in by the user | |
302 */ | |
303 static void mxit_cb_register_cancel( PurpleConnection *gc, PurpleRequestFields *fields ) | |
304 { | |
305 purple_debug_info( MXIT_PLUGIN_ID, "mxit_cb_register_cancel\n" ); | |
306 | |
307 /* disconnect */ | |
308 purple_account_disconnect( gc->account ); | |
309 } | |
310 | |
311 | |
312 /*------------------------------------------------------------------------ | |
313 * Show a window to the user so that he can enter his information | |
314 * | |
315 * @param session The MXit session object | |
316 */ | |
317 static void mxit_register_view( struct MXitSession* session ) | |
318 { | |
319 struct MXitProfile* profile; | |
320 PurpleRequestFields* fields; | |
321 PurpleRequestFieldGroup* group; | |
322 PurpleRequestField* field; | |
323 | |
324 if ( !session->profile ) { | |
325 /* we need to create a profile object here */ | |
326 session->profile = g_new0( struct MXitProfile, 1 ); | |
327 } | |
328 profile = session->profile; | |
329 | |
330 fields = purple_request_fields_new(); | |
331 group = purple_request_field_group_new( NULL ); | |
332 purple_request_fields_add_group( fields, group ); | |
333 | |
334 /* mxit login name */ | |
335 field = purple_request_field_string_new( "loginname", _( "MXit Login Name" ), purple_account_get_username( session->acc ), FALSE ); | |
336 purple_request_field_string_set_editable( field, FALSE ); | |
337 purple_request_field_group_add_field( group, field ); | |
338 | |
339 /* nick name */ | |
340 field = purple_request_field_string_new( "nickname", _( "Nick Name" ), profile->nickname, FALSE ); | |
341 purple_request_field_group_add_field( group, field ); | |
342 | |
343 /* birthday */ | |
344 field = purple_request_field_string_new( "bday", _( "Birthday" ), profile->birthday, FALSE ); | |
345 purple_request_field_string_set_default_value( field, "YYYY-MM-DD" ); | |
346 purple_request_field_group_add_field( group, field ); | |
347 | |
348 /* gender */ | |
349 field = purple_request_field_choice_new( "male", _( "Gender" ), ( profile->male ) ? 1 : 0 ); | |
350 purple_request_field_choice_add( field, _( "Female" ) ); /* 0 */ | |
351 purple_request_field_choice_add( field, _( "Male" ) ); /* 1 */ | |
352 purple_request_field_group_add_field( group, field ); | |
353 | |
354 /* pin */ | |
355 field = purple_request_field_string_new( "pin", _( "PIN" ), profile->pin, FALSE ); | |
356 purple_request_field_string_set_masked( field, TRUE ); | |
357 purple_request_field_group_add_field( group, field ); | |
358 field = purple_request_field_string_new( "pin2", _( "Verify PIN" ), "", FALSE ); | |
359 purple_request_field_string_set_masked( field, TRUE ); | |
360 purple_request_field_group_add_field( group, field ); | |
361 | |
362 /* show the form to the user to complete */ | |
363 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 ); | |
364 } | |
365 | |
366 | |
367 /*------------------------------------------------------------------------ | |
368 * Callback function invoked once the Authorization information has been submitted | |
369 * to the MXit WAP site. | |
370 * | |
371 * @param url_data libPurple internal object (see purple_util_fetch_url_request) | |
372 * @param user_data The MXit session object | |
373 * @param url_text The data returned from the WAP site | |
374 * @param len The length of the data returned | |
375 * @param error_message Descriptive error message | |
376 */ | |
377 static void mxit_cb_clientinfo2( PurpleUtilFetchUrlData* url_data, gpointer user_data, const gchar* url_text, gsize len, const gchar* error_message ) | |
378 { | |
379 struct MXitSession* session = (struct MXitSession*) user_data; | |
380 gchar** parts; | |
381 gchar** host; | |
382 int state; | |
383 | |
384 purple_debug_info( MXIT_PLUGIN_ID, "mxit_clientinfo_cb2\n" ); | |
385 | |
386 #ifdef DEBUG_PROTOCOL | |
387 purple_debug_info( MXIT_PLUGIN_ID, "HTTP RESPONSE: '%s'\n", url_text ); | |
388 #endif | |
389 | |
390 if ( !url_text ) { | |
391 /* no reply from the WAP site */ | |
392 purple_connection_error( session->con, _( "Error contacting the MXit WAP site. Please try again later." ) ); | |
393 return; | |
394 } | |
395 | |
396 /* explode the response from the WAP site into an array */ | |
397 parts = g_strsplit( url_text, ";", 15 ); | |
398 | |
399 if ( !parts ) { | |
400 /* wapserver error */ | |
401 purple_connection_error( session->con, _( "MXit is currently unable to process the request. Please try again later." ) ); | |
402 return; | |
403 } | |
404 | |
405 /* check wapsite return code */ | |
406 switch ( parts[0][0] ) { | |
407 case '0' : | |
408 /* valid reply! */ | |
409 break; | |
410 case '1' : | |
411 purple_connection_error( session->con, _( "Wrong security code entered. Please try again later." ) ); | |
412 return; | |
413 case '2' : | |
414 purple_connection_error( session->con, _( "Your session has expired. Please try again later." ) ); | |
415 return; | |
416 case '5' : | |
417 purple_connection_error( session->con, _( "Invalid country selected. Please try again." ) ); | |
418 return; | |
419 case '6' : | |
420 purple_connection_error( session->con, _( "Username is not registered. Please register first." ) ); | |
421 return; | |
422 case '7' : | |
423 purple_connection_error( session->con, _( "Username is already registered. Please choose another username." ) ); | |
424 /* this user's account already exists, so we need to change the registration login flag to be login */ | |
425 purple_account_set_int( session->acc, MXIT_CONFIG_STATE, MXIT_STATE_LOGIN ); | |
426 return; | |
427 case '3' : | |
428 case '4' : | |
429 default : | |
430 purple_connection_error( session->con, _( "Internal error. Please try again later." ) ); | |
431 return; | |
432 } | |
433 | |
434 /* now parse and split the distribution code and the client key */ | |
435 g_strlcpy( session->distcode, &parts[1][2], 36 + 1 ); | |
436 g_strlcpy( session->clientkey, &parts[1][38], 8 + 1 ); | |
437 | |
438 /* get the dial code for the client */ | |
439 g_strlcpy( session->dialcode, parts[4], sizeof( session->dialcode ) ); | |
440 | |
441 /* parse the proxy server address and port number */ | |
442 host = g_strsplit( parts[2], ":", 4 ); | |
443 g_strlcpy( session->server, &host[1][2], sizeof( session->server ) ); | |
444 session->port = atoi( &host[2][0] ); | |
445 | |
446 /* parse the http proxy server address and port number */ | |
447 g_strlcpy( session->http_server, parts[3], sizeof( session->http_server ) ); | |
448 | |
449 purple_debug_info( MXIT_PLUGIN_ID, "distcode='%s', clientkey='%s', dialcode='%s'\n", session->distcode, session->clientkey, session->dialcode ); | |
450 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] ); | |
451 | |
452 /* save the information (reference: "libpurple/account.h") */ | |
453 purple_account_set_string( session->acc, MXIT_CONFIG_DISTCODE, session->distcode ); | |
454 purple_account_set_string( session->acc, MXIT_CONFIG_CLIENTKEY, session->clientkey ); | |
455 purple_account_set_string( session->acc, MXIT_CONFIG_DIALCODE, session->dialcode ); | |
456 purple_account_set_string( session->acc, MXIT_CONFIG_SERVER_ADDR, session->server ); | |
457 purple_account_set_int( session->acc, MXIT_CONFIG_SERVER_PORT, session->port ); | |
458 purple_account_set_string( session->acc, MXIT_CONFIG_HTTPSERVER, session->http_server ); | |
459 | |
460 /* update the state */ | |
461 state = purple_account_get_int( session->acc, MXIT_CONFIG_STATE, MXIT_STATE_LOGIN ); | |
462 if ( state == MXIT_STATE_REGISTER1 ) | |
463 purple_account_set_int( session->acc, MXIT_CONFIG_STATE, MXIT_STATE_REGISTER2 ); | |
464 | |
465 /* freeup the memory */ | |
466 g_strfreev( host ); | |
467 g_strfreev( parts ); | |
468 | |
469 if ( state == MXIT_STATE_LOGIN ) { | |
470 /* now we can continue with the login process */ | |
471 mxit_login_connect( session ); | |
472 } | |
473 else { | |
474 /* the user is registering so we need to get more information from him/her first to complete the process */ | |
475 mxit_register_view( session ); | |
476 } | |
477 } | |
478 | |
479 | |
480 /*------------------------------------------------------------------------ | |
481 * Free up the data associated with the Authorization process. | |
482 * | |
483 * @param data The data object to free | |
484 */ | |
485 static void free_logindata( struct login_data* data ) | |
486 { | |
487 if ( !data ) | |
488 return; | |
489 | |
490 /* free up the login resources */ | |
491 g_free( data->wapserver ); | |
492 g_free( data->sessionid ); | |
493 g_free( data->captcha ); | |
494 g_free( data->cc ); | |
495 g_free( data->locale ); | |
496 g_free( data ); | |
497 } | |
498 | |
499 | |
500 /*------------------------------------------------------------------------ | |
501 * This function is called when the user accepts the Authorization form. | |
502 * | |
503 * @param gc The connection object | |
504 * @param fields The list of fields in the accepted form | |
505 */ | |
506 static void mxit_cb_captcha_ok( PurpleConnection* gc, PurpleRequestFields* fields ) | |
507 { | |
508 struct MXitSession* session = (struct MXitSession*) gc->proto_data; | |
509 PurpleUtilFetchUrlData* url_data; | |
510 PurpleRequestField* field; | |
511 const char* captcha_resp; | |
512 GList* entries; | |
513 GList* entry; | |
514 char* url; | |
515 int state; | |
516 | |
517 /* get the captcha response */ | |
518 captcha_resp = purple_request_fields_get_string( fields, "code" ); | |
519 if ( ( captcha_resp == NULL ) || ( captcha_resp[0] == '\0' ) ) { | |
520 /* the user did not fill in the captcha */ | |
521 mxit_popup( PURPLE_NOTIFY_MSG_ERROR, _( "Error" ), _( "You did not enter the security code" ) ); | |
522 free_logindata( session->logindata ); | |
523 purple_account_disconnect( session->acc ); | |
524 return; | |
525 } | |
526 | |
527 /* get chosen country */ | |
528 field = purple_request_fields_get_field( fields, "country" ); | |
529 entries = purple_request_field_list_get_selected( field ); | |
530 entry = g_list_first( entries ); | |
531 session->logindata->cc = purple_request_field_list_get_data( field, entry->data ); | |
532 purple_account_set_string( session->acc, MXIT_CONFIG_COUNTRYCODE, session->logindata->cc ); | |
533 | |
534 /* get chosen language */ | |
535 field = purple_request_fields_get_field( fields, "locale" ); | |
536 entries = purple_request_field_list_get_selected( field ); | |
537 entry = g_list_first( entries ); | |
538 session->logindata->locale = purple_request_field_list_get_data( field, entry->data ); | |
539 purple_account_set_string( session->acc, MXIT_CONFIG_LOCALE, session->logindata->locale ); | |
540 | |
541 #ifdef DEBUG_PROTOCOL | |
542 purple_debug_info( MXIT_PLUGIN_ID, "cc='%s', locale='%s', captcha='%s'\n", session->logindata->cc, session->logindata->locale, captcha_resp ); | |
543 #endif | |
544 | |
545 /* get state */ | |
546 state = purple_account_get_int( session->acc, MXIT_CONFIG_STATE, MXIT_STATE_LOGIN ); | |
547 | |
548 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", | |
549 session->logindata->wapserver, session->logindata->sessionid, purple_url_encode( session->acc->username ), MXIT_CP_RELEASE, MXIT_CLIENT_ID, MXIT_CP_ARCH, | |
550 captcha_resp, session->logindata->cc, session->logindata->locale, ( state == MXIT_STATE_REGISTER1 ) ? 0 : 1, MXIT_CP_PLATFORM, MXIT_CP_OS, | |
551 MXIT_CAPTCHA_HEIGHT, MXIT_CAPTCHA_WIDTH, time( NULL ) ); | |
552 url_data = purple_util_fetch_url_request( url, TRUE, MXIT_HTTP_USERAGENT, TRUE, NULL, FALSE, mxit_cb_clientinfo2, session ); | |
553 | |
554 #ifdef DEBUG_PROTOCOL | |
555 purple_debug_info( MXIT_PLUGIN_ID, "HTTP REQUEST: '%s'\n", url ); | |
556 #endif | |
557 g_free( url ); | |
558 | |
559 /* free up the login resources */ | |
560 free_logindata( session->logindata ); | |
561 } | |
562 | |
563 | |
564 /*------------------------------------------------------------------------ | |
565 * This function is called when the user cancels the Authorization form. | |
566 * | |
567 * @param gc The connection object | |
568 * @param fields The list of fields in the cancelled form | |
569 */ | |
570 static void mxit_cb_captcha_cancel( PurpleConnection* gc, PurpleRequestFields* fields ) | |
571 { | |
572 struct MXitSession* session = (struct MXitSession*) gc->proto_data; | |
573 | |
574 /* free up the login resources */ | |
575 free_logindata( session->logindata ); | |
576 | |
577 /* we cannot continue, so we disconnect this account */ | |
578 purple_account_disconnect( session->acc ); | |
579 } | |
580 | |
581 | |
582 /*------------------------------------------------------------------------ | |
583 * Callback function invoked once the client information has been retrieved from | |
584 * the MXit WAP site. Display page where user can select their authorization information. | |
585 * | |
586 * @param url_data libPurple internal object (see purple_util_fetch_url_request) | |
587 * @param user_data The MXit session object | |
588 * @param url_text The data returned from the WAP site | |
589 * @param len The length of the data returned | |
590 * @param error_message Descriptive error message | |
591 */ | |
592 static void mxit_cb_clientinfo1( PurpleUtilFetchUrlData* url_data, gpointer user_data, const gchar* url_text, gsize len, const gchar* error_message ) | |
593 { | |
594 struct MXitSession* session = (struct MXitSession*) user_data; | |
595 struct login_data* logindata; | |
596 PurpleRequestFields* fields; | |
597 PurpleRequestFieldGroup* group = NULL; | |
598 PurpleRequestField* field = NULL; | |
599 gchar** parts; | |
600 gchar** countries; | |
601 gchar** locales; | |
602 int i; | |
603 | |
604 purple_debug_info( MXIT_PLUGIN_ID, "mxit_clientinfo_cb1\n" ); | |
605 | |
606 #ifdef DEBUG_PROTOCOL | |
607 purple_debug_info( MXIT_PLUGIN_ID, "RESPONSE: %s\n", url_text ); | |
608 #endif | |
609 | |
610 if ( !url_text ) { | |
611 /* no reply from the WAP site */ | |
612 purple_connection_error( session->con, _( "Error contacting the MXit WAP site. Please try again later." ) ); | |
613 return; | |
614 } | |
615 | |
616 /* explode the response from the WAP site into an array */ | |
617 parts = g_strsplit( url_text, ";", 15 ); | |
618 | |
619 if ( ( !parts ) || ( parts[0][0] != '0' ) ) { | |
620 /* server could not find the user */ | |
621 purple_connection_error( session->con, _( "MXit is currently unable to process the request. Please try again later." ) ); | |
622 return; | |
623 } | |
624 | |
625 /* save received settings */ | |
626 logindata = g_new0( struct login_data, 1 ); | |
627 logindata->wapserver = g_strdup( parts[1] ); | |
628 logindata->sessionid = g_strdup( parts[2] ); | |
629 session->logindata = logindata; | |
630 | |
631 /* now generate the popup requesting the user for action */ | |
632 | |
633 fields = purple_request_fields_new(); | |
634 group = purple_request_field_group_new( NULL ); | |
635 purple_request_fields_add_group( fields, group ); | |
636 | |
637 /* add the captcha */ | |
638 logindata->captcha = purple_base64_decode( parts[3], &logindata->captcha_size ); | |
639 field = purple_request_field_image_new( "capcha", _( "Security Code" ), (gchar*) logindata->captcha, logindata->captcha_size ); | |
640 purple_request_field_group_add_field( group, field ); | |
641 | |
642 /* ask for input */ | |
643 field = purple_request_field_string_new( "code", _( "Enter Security Code" ), NULL, FALSE ); | |
644 purple_request_field_group_add_field( group, field ); | |
645 | |
646 /* choose your country, but be careful, we already know your IP! ;-) */ | |
647 countries = g_strsplit( parts[4], ",", 500 ); | |
648 field = purple_request_field_list_new( "country", _( "Your Country" ) ); | |
649 purple_request_field_list_set_multi_select( field, FALSE ); | |
650 for ( i = 0; countries[i]; i++ ) { | |
651 gchar** country; | |
652 | |
653 country = g_strsplit( countries[i], "|", 2 ); | |
654 if ( !country ) { | |
655 /* oops, this is not good, time to bail */ | |
656 break; | |
657 } | |
658 purple_request_field_list_add( field, country[1], g_strdup( country[0] ) ); | |
659 if ( strcmp( country[1], parts[6] ) == 0 ) { | |
660 /* based on the user's ip, this is his current country code, so we default to it */ | |
661 purple_request_field_list_add_selected( field, country[1] ); | |
662 } | |
663 g_strfreev( country ); | |
664 } | |
665 purple_request_field_group_add_field( group, field ); | |
666 | |
667 /* choose your language */ | |
668 locales = g_strsplit( parts[5], ",", 200 ); | |
669 field = purple_request_field_list_new( "locale", _( "Your Language" ) ); | |
670 purple_request_field_list_set_multi_select( field, FALSE ); | |
671 for ( i = 0; locales[i]; i++ ) { | |
672 gchar** locale; | |
673 | |
674 locale = g_strsplit( locales[i], "|", 2 ); | |
675 if ( !locale ) { | |
676 /* oops, this is not good, time to bail */ | |
677 break; | |
678 } | |
679 purple_request_field_list_add( field, locale[1], g_strdup( locale[0] ) ); | |
680 g_strfreev( locale ); | |
681 } | |
682 purple_request_field_list_add_selected( field, "English" ); | |
683 purple_request_field_group_add_field( group, field ); | |
684 | |
685 /* display the form to the user and wait for his/her input */ | |
686 purple_request_fields( session->con, "MXit", _( "MXit Authorization" ), _( "MXit account validation" ), fields, | |
687 _( "Continue" ), G_CALLBACK( mxit_cb_captcha_ok ), _( "Cancel" ), G_CALLBACK( mxit_cb_captcha_cancel ), session->acc, NULL, NULL, session->con ); | |
688 | |
689 /* freeup the memory */ | |
690 g_strfreev( parts ); | |
691 } | |
692 | |
693 | |
694 /*------------------------------------------------------------------------ | |
695 * Initiate a request for the client information (distribution code, client key, etc) | |
696 * required for logging in from the MXit WAP site. | |
697 * | |
698 * @param session The MXit session object | |
699 */ | |
700 static void get_clientinfo( struct MXitSession* session ) | |
701 { | |
702 PurpleUtilFetchUrlData* url_data; | |
703 const char* wapserver; | |
704 char* url; | |
705 | |
706 purple_debug_info( MXIT_PLUGIN_ID, "get_clientinfo\n" ); | |
707 | |
708 purple_connection_update_progress( session->con, _( "Retrieving User Information..." ), 0, 4 ); | |
709 | |
710 /* get the WAP site as was configured by the user in the advanced settings */ | |
711 wapserver = purple_account_get_string( session->acc, MXIT_CONFIG_WAPSERVER, DEFAULT_WAPSITE ); | |
712 | |
713 /* reference: "libpurple/util.h" */ | |
714 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 ) ); | |
715 url_data = purple_util_fetch_url_request( url, TRUE, MXIT_HTTP_USERAGENT, TRUE, NULL, FALSE, mxit_cb_clientinfo1, session ); | |
716 | |
717 #ifdef DEBUG_PROTOCOL | |
718 purple_debug_info( MXIT_PLUGIN_ID, "HTTP REQUEST: '%s'\n", url ); | |
719 #endif | |
720 g_free( url ); | |
721 } | |
722 | |
723 | |
724 /*------------------------------------------------------------------------ | |
725 * Log the user into MXit. | |
726 * | |
727 * @param account The account object | |
728 */ | |
729 void mxit_login( PurpleAccount* account ) | |
730 { | |
731 struct MXitSession* session = NULL; | |
732 | |
733 purple_debug_info( MXIT_PLUGIN_ID, "mxit_login\n" ); | |
734 | |
735 /* create and save a new mxit session */ | |
736 session = mxit_create_object( account ); | |
737 | |
738 /* | |
739 * before we can login we need to have a valid distribution code and client key for authentication. | |
740 * if we don't have any info saved from a previous login, we need to get it from the MXit WAP site. | |
741 * we do cache it, so this step is only done on the very first login for each account. | |
742 */ | |
743 if ( ( session->distcode == NULL ) || ( strlen( session->distcode ) == 0 ) ) { | |
744 /* this must be the very first login, so we need to retrieve the user information */ | |
745 get_clientinfo( session ); | |
746 } | |
747 else { | |
748 /* we can continue with the login */ | |
749 mxit_login_connect( session ); | |
750 } | |
751 } | |
752 | |
753 | |
754 /*------------------------------------------------------------------------ | |
755 * Perform a reconnect to the MXit server, and maintain same session object. | |
756 * | |
757 * @param account The account object | |
758 */ | |
759 void mxit_reconnect( struct MXitSession* session ) | |
760 { | |
761 purple_debug_info( MXIT_PLUGIN_ID, "mxit_reconnect\n" ); | |
762 | |
763 /* close existing connection */ | |
764 session->flags &= ~MXIT_FLAG_CONNECTED; | |
765 purple_proxy_connect_cancel_with_handle( session->con ); | |
766 | |
767 /* perform the re-connect */ | |
768 mxit_login_connect( session ); | |
769 } | |
770 | |
771 | |
772 /*------------------------------------------------------------------------ | |
773 * Register a new account with MXit | |
774 * | |
775 * @param acc The account object | |
776 */ | |
777 void mxit_register( PurpleAccount* account ) | |
778 { | |
779 struct MXitSession* session = NULL; | |
780 | |
781 purple_debug_info( MXIT_PLUGIN_ID, "mxit_register\n" ); | |
782 | |
783 /* create and save a new mxit session */ | |
784 session = mxit_create_object( account ); | |
785 purple_account_set_int( account, MXIT_CONFIG_STATE, MXIT_STATE_REGISTER1 ); | |
786 | |
787 get_clientinfo( session ); | |
788 } | |
789 |