Mercurial > pidgin
view libpurple/protocols/mxit/actions.c @ 29685:6797736dbe37
Does anyone know the purpose of the ui_write, ui_read and data_not_sent
FT UI callbacks? It looks like they allow a UI to decide how to safe
incoming file transfers? They're not used in Pidgin or Finch. Are
they used elsewhere?
Valgrind is complaining about an invalid free. I think it happens either
when the local user cancels a file transfer or when the remote user
cancels a file transfer. I think this change fixes it.
Revision fa4ce539e5025eb07aad3ca824cd4c512010d8a8 is related to these
callbacks and to this change by foufou33@ gee male dot com
The valgrind error is:
==23064== Invalid free() / delete / delete[]
==23064== at 0x4C24D68: free (vg_replace_malloc.c:325)
==23064== by 0x9293209: g_array_free (in /lib/libglib-2.0.so.0.2200.3)
==23064== by 0x95B1995: purple_xfer_priv_data_destroy (ft.c:71)
==23064== by 0x92AA5D1: ??? (in /lib/libglib-2.0.so.0.2200.3)
==23064== by 0x92AAE17: g_hash_table_remove_all (in /lib/libglib-2.0.so.0.2200.3)
==23064== by 0x92AAFC4: g_hash_table_destroy (in /lib/libglib-2.0.so.0.2200.3)
==23064== by 0x95B579C: purple_xfers_uninit (ft.c:1642)
==23064== by 0x95ACF08: purple_core_quit (core.c:238)
==23064== by 0x43EB3E: gtk_blist_delete_cb (gtkblist.c:227)
==23064== by 0x6F9A727: ??? (in /usr/lib/libgtk-x11-2.0.so.0.1800.3)
==23064== Address 0x2355f0e0 is not stack'd, malloc'd or (recently) free'd
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Tue, 06 Apr 2010 09:52:27 +0000 |
parents | 29df7408df03 |
children | 40a1111c34d3 |
line wrap: on
line source
/* * MXit Protocol libPurple Plugin * * -- handle MXit plugin actions -- * * 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 "internal.h" #include "purple.h" #include "protocol.h" #include "mxit.h" #include "roster.h" #include "actions.h" #include "splashscreen.h" #include "cipher.h" #include "profile.h" /* MXit Moods */ static const char* moods[] = { /* 0 */ N_("None"), /* 1 */ N_("Angry"), /* 2 */ N_("Excited"), /* 3 */ N_("Grumpy"), /* 4 */ N_("Happy"), /* 5 */ N_("In Love"), /* 6 */ N_("Invincible"), /* 7 */ N_("Sad"), /* 8 */ N_("Hot"), /* 9 */ N_("Sick"), /* 10 */ N_("Sleepy") }; /*------------------------------------------------------------------------ * The user has selected to change their current mood. * * @param gc The connection object * @param fields The fields from the request pop-up */ static void mxit_cb_set_mood( PurpleConnection* gc, PurpleRequestFields* fields ) { struct MXitSession* session = (struct MXitSession*) gc->proto_data; int mood = purple_request_fields_get_choice( fields, "mood" ); purple_debug_info( MXIT_PLUGIN_ID, "mxit_cb_set_mood (%i)\n", mood ); if ( !PURPLE_CONNECTION_IS_VALID( gc ) ) { purple_debug_error( MXIT_PLUGIN_ID, "Unable to set mood; account offline.\n" ); return; } /* Save the new mood in session */ session->mood = mood; /* now send the update to MXit */ mxit_send_mood( session, mood ); } /*------------------------------------------------------------------------ * Create and display the mood selection window to the user. * * @param action The action object */ static void mxit_cb_action_mood( PurplePluginAction* action ) { PurpleConnection* gc = (PurpleConnection*) action->context; struct MXitSession* session = (struct MXitSession*) gc->proto_data; PurpleRequestFields* fields = NULL; PurpleRequestFieldGroup* group = NULL; PurpleRequestField* field = NULL; unsigned int i = 0; purple_debug_info( MXIT_PLUGIN_ID, "mxit_cb_action_mood\n" ); fields = purple_request_fields_new(); group = purple_request_field_group_new( NULL ); purple_request_fields_add_group( fields, group ); /* show current mood */ field = purple_request_field_string_new( "current", _( "Current Mood" ), _( moods[session->mood] ), FALSE ); purple_request_field_string_set_editable( field, FALSE ); /* current mood field is not editable */ purple_request_field_group_add_field( group, field ); /* add all moods to list */ field = purple_request_field_choice_new( "mood", _( "New Mood" ), 0 ); for ( i = 0; i < ARRAY_SIZE( moods ); i++ ) { purple_request_field_choice_add( field, _( moods[i] ) ); } purple_request_field_set_required( field, TRUE ); purple_request_field_choice_set_default_value( field, session->mood ); purple_request_field_group_add_field( group, field ); /* (reference: "libpurple/request.h") */ purple_request_fields( gc, _( "Mood" ), _( "Change your Mood" ), _( "How do you feel right now?" ), fields, _( "Set" ), G_CALLBACK( mxit_cb_set_mood ), _( "Cancel" ), NULL, purple_connection_get_account( gc ), NULL, NULL, gc ); } /*------------------------------------------------------------------------ * The user has selected to change their profile. * * @param gc The connection object * @param fields The fields from the request pop-up */ static void mxit_cb_set_profile( PurpleConnection* gc, PurpleRequestFields* fields ) { struct MXitSession* session = (struct MXitSession*) gc->proto_data; PurpleRequestField* field = NULL; const char* pin = NULL; const char* pin2 = NULL; const char* name = NULL; const char* bday = NULL; const char* err = NULL; int len; int i; purple_debug_info( MXIT_PLUGIN_ID, "mxit_cb_set_profile\n" ); if ( !PURPLE_CONNECTION_IS_VALID( gc ) ) { purple_debug_error( MXIT_PLUGIN_ID, "Unable to update profile; account offline.\n" ); return; } /* validate 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 < 4 ) || ( len > 10 ) ) { err = _( "The PIN you entered has an invalid length [4-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; } } pin2 = purple_request_fields_get_string( fields, "pin2" ); if ( ( !pin2 ) || ( strcmp( pin, pin2 ) != 0 ) ) { err = _( "The two PINs you entered do not match." ); goto out; } /* validate name */ name = purple_request_fields_get_string( fields, "name" ); if ( ( !name ) || ( strlen( name ) < 3 ) ) { err = _( "The name you entered is invalid." ); goto out; } /* validate birthdate */ bday = purple_request_fields_get_string( fields, "bday" ); if ( ( !bday ) || ( strlen( bday ) < 10 ) || ( !validateDate( bday ) ) ) { err = _( "The birthday you entered is invalid. The correct format is: 'YYYY-MM-DD'." ); goto out; } out: if ( !err ) { struct MXitProfile* profile = session->profile; GString* attributes = g_string_sized_new( 128 ); char attrib[512]; unsigned int acount = 0; /* all good, so we can now update the profile */ /* update pin */ purple_account_set_password( session->acc, pin ); g_free( session->encpwd ); session->encpwd = mxit_encrypt_password( session ); /* update name */ g_strlcpy( profile->nickname, name, sizeof( profile->nickname ) ); g_snprintf( attrib, sizeof( attrib ), "\01%s\01%i\01%s", CP_PROFILE_FULLNAME, CP_PROF_TYPE_UTF8, profile->nickname ); g_string_append( attributes, attrib ); acount++; /* update hidden */ field = purple_request_fields_get_field( fields, "hidden" ); profile->hidden = purple_request_field_bool_get_value( field ); g_snprintf( attrib, sizeof( attrib ), "\01%s\01%i\01%s", CP_PROFILE_HIDENUMBER, CP_PROF_TYPE_BOOL, ( profile->hidden ) ? "1" : "0" ); g_string_append( attributes, attrib ); acount++; /* update birthday */ strcpy( profile->birthday, bday ); g_snprintf( attrib, sizeof( attrib ), "\01%s\01%i\01%s", CP_PROFILE_BIRTHDATE, CP_PROF_TYPE_UTF8, profile->birthday ); g_string_append( attributes, attrib ); acount++; /* update gender */ profile->male = ( purple_request_fields_get_choice( fields, "male" ) != 0 ); g_snprintf( attrib, sizeof( attrib ), "\01%s\01%i\01%s", CP_PROFILE_GENDER, CP_PROF_TYPE_BOOL, ( profile->male ) ? "1" : "0" ); g_string_append( attributes, attrib ); acount++; /* update title */ name = purple_request_fields_get_string( fields, "title" ); if ( !name ) profile->title[0] = '\0'; else strcpy( profile->title, name ); g_snprintf( attrib, sizeof( attrib ), "\01%s\01%i\01%s", CP_PROFILE_TITLE, CP_PROF_TYPE_UTF8, profile->title ); g_string_append( attributes, attrib ); acount++; /* update firstname */ name = purple_request_fields_get_string( fields, "firstname" ); if ( !name ) profile->firstname[0] = '\0'; else strcpy( profile->firstname, name ); g_snprintf( attrib, sizeof( attrib ), "\01%s\01%i\01%s", CP_PROFILE_FIRSTNAME, CP_PROF_TYPE_UTF8, profile->firstname ); g_string_append( attributes, attrib ); acount++; /* update lastname */ name = purple_request_fields_get_string( fields, "lastname" ); if ( !name ) profile->lastname[0] = '\0'; else strcpy( profile->lastname, name ); g_snprintf( attrib, sizeof( attrib ), "\01%s\01%i\01%s", CP_PROFILE_LASTNAME, CP_PROF_TYPE_UTF8, profile->lastname ); g_string_append( attributes, attrib ); acount++; /* update email address */ name = purple_request_fields_get_string( fields, "email" ); if ( !name ) profile->email[0] = '\0'; else strcpy( profile->email, name ); g_snprintf( attrib, sizeof( attrib ), "\01%s\01%i\01%s", CP_PROFILE_EMAIL, CP_PROF_TYPE_UTF8, profile->email ); g_string_append( attributes, attrib ); acount++; /* update mobile number */ name = purple_request_fields_get_string( fields, "mobilenumber" ); if ( !name ) profile->mobilenr[0] = '\0'; else strcpy( profile->mobilenr, name ); g_snprintf( attrib, sizeof( attrib ), "\01%s\01%i\01%s", CP_PROFILE_MOBILENR, CP_PROF_TYPE_UTF8, profile->mobilenr ); g_string_append( attributes, attrib ); acount++; /* send the profile update to MXit */ mxit_send_extprofile_update( session, session->encpwd, acount, attributes->str ); g_string_free( attributes, TRUE ); } else { /* show error to user */ mxit_popup( PURPLE_NOTIFY_MSG_ERROR, _( "Profile Update Error" ), err ); } } /*------------------------------------------------------------------------ * Display and update the user's profile. * * @param action The action object */ static void mxit_cb_action_profile( PurplePluginAction* action ) { PurpleConnection* gc = (PurpleConnection*) action->context; struct MXitSession* session = (struct MXitSession*) gc->proto_data; struct MXitProfile* profile = session->profile; PurpleRequestFields* fields = NULL; PurpleRequestFieldGroup* group = NULL; PurpleRequestField* field = NULL; purple_debug_info( MXIT_PLUGIN_ID, "mxit_cb_action_profile\n" ); /* ensure that we actually have the user's profile information */ if ( !profile ) { /* no profile information yet, so we cannot update */ mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "Profile" ), _( "Your profile information is not yet retrieved. Please try again later." ) ); return; } fields = purple_request_fields_new(); group = purple_request_field_group_new( NULL ); purple_request_fields_add_group( fields, group ); /* pin */ field = purple_request_field_string_new( "pin", _( "PIN" ), session->acc->password, 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" ), session->acc->password, FALSE ); purple_request_field_string_set_masked( field, TRUE ); purple_request_field_group_add_field( group, field ); /* display name */ field = purple_request_field_string_new( "name", _( "Display 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_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 ); /* hidden */ field = purple_request_field_bool_new( "hidden", _( "Hide my number" ), profile->hidden ); purple_request_field_group_add_field( group, field ); /* title */ field = purple_request_field_string_new( "title", _( "Job Title" ), profile->title, FALSE ); purple_request_field_group_add_field( group, field ); /* first name */ field = purple_request_field_string_new( "firstname", _( "First Name" ), profile->firstname, FALSE ); purple_request_field_group_add_field( group, field ); /* last name */ field = purple_request_field_string_new( "lastname", _( "Last Name" ), profile->lastname, FALSE ); purple_request_field_group_add_field( group, field ); /* email */ field = purple_request_field_string_new( "email", _( "Email" ), profile->email, FALSE ); purple_request_field_group_add_field( group, field ); /* mobile number */ field = purple_request_field_string_new( "mobilenumber", _( "Mobile Number" ), profile->mobilenr, FALSE ); purple_request_field_group_add_field( group, field ); /* (reference: "libpurple/request.h") */ purple_request_fields( gc, _( "Profile" ), _( "Update your Profile" ), _( "Here you can update your MXit profile" ), fields, _( "Set" ), G_CALLBACK( mxit_cb_set_profile ), _( "Cancel" ), NULL, purple_connection_get_account( gc ), NULL, NULL, gc ); } /*------------------------------------------------------------------------ * Display the current splash-screen, or a notification pop-up if one is not available. * * @param action The action object */ static void mxit_cb_action_splash( PurplePluginAction* action ) { PurpleConnection* gc = (PurpleConnection*) action->context; struct MXitSession* session = (struct MXitSession*) gc->proto_data; if ( splash_current( session ) != NULL ) splash_display( session ); else mxit_popup( PURPLE_NOTIFY_MSG_INFO, _( "View Splash" ), _( "There is no splash-screen currently available" ) ); } /*------------------------------------------------------------------------ * Display info about the plugin. * * @param action The action object */ static void mxit_cb_action_about( PurplePluginAction* action ) { char version[256]; g_snprintf( version, sizeof( version ), "MXit libPurple Plugin v%s\n" "MXit Client Protocol v%s\n\n" "Author:\nPieter Loubser\n\n" "Contributors:\nAndrew Victor\n\n" "Testers:\nBraeme Le Roux\n\n", MXIT_PLUGIN_VERSION, MXIT_CP_RELEASE ); mxit_popup( PURPLE_NOTIFY_MSG_INFO, _( "About" ), version ); } /*------------------------------------------------------------------------ * Associate actions with the MXit plugin. * * @param plugin The MXit protocol plugin * @param context The connection context (if available) * @return The list of plugin actions */ GList* mxit_actions( PurplePlugin* plugin, gpointer context ) { PurplePluginAction* action = NULL; GList* m = NULL; /* display / change mood */ action = purple_plugin_action_new( _( "Change Mood..." ), mxit_cb_action_mood ); m = g_list_append( m, action ); /* display / change profile */ action = purple_plugin_action_new( _( "Change Profile..." ), mxit_cb_action_profile ); m = g_list_append( m, action ); /* display splash-screen */ action = purple_plugin_action_new( _( "View Splash..." ), mxit_cb_action_splash ); m = g_list_append( m, action ); /* display plugin version */ action = purple_plugin_action_new( _( "About..." ), mxit_cb_action_about ); m = g_list_append( m, action ); return m; }