# HG changeset patch # User John Bailey # Date 1299345490 0 # Node ID 4f414608eaad719dd751918c96f4faacbdf25f4b # Parent db330f8c1a8cce2fa1d37a3f50ec14e1acbd8295# Parent 8cddae0547913eeb6d70b0530763705fa3ce42dd propagate from branch 'im.pidgin.pidgin.mxit' (head 342293440b7089597815dac27b11677a4cef7254) to branch 'im.pidgin.pidgin' (head 28c3d2da674aa9cd470995ce6bd39c4434e026fe) diff -r db330f8c1a8c -r 4f414608eaad ChangeLog --- a/ChangeLog Tue Mar 01 06:24:50 2011 +0000 +++ b/ChangeLog Sat Mar 05 17:18:10 2011 +0000 @@ -329,6 +329,40 @@ * Bonjour support now requires Apple Bonjour Print Services version 2.0.0 or newer (http://support.apple.com/kb/dl999). + libpurple: + * Fall back to an ordinary request if a UI does not support showing a + request with an icon. Fixes receiving MSN file transfer requests + including a thumbnail in Finch. + + Pidgin: + * Add support for the Gadu-Gadu protocol in the gevolution plugin to + provide Evolution integration with contacts with GG IDs. (#10709) + * Remap the "Set User Mood" shortcut to Control-D, which does not + conflict with the previous shortcut for Get Buddy Info on the + selected buddy. + * Add a plugin action menu (under Tools) for the Voice and Video + Settings plugin. + + Finch: + * Add support for drop-down account options (like the SILC cipher + and HMAC options or the QQ protocol version). + + XMPP: + * Unify the connection security-related settings into one dropdown. + * Fix a crash when multiple accounts are simultaneously performing + SASL authentication when built with Cyrus SASL support. (thanks + to Jan Kaluza) (#11560) + * Restore the ability to connect to XMPP servers that do not offer + Stream ID. (#12331) + * Added support for using Google's relay servers when making voice and + video calls to Google clients. + + Yahoo/Yahoo JAPAN: + * Stop doing unnecessary lookups of certain alias information. This + solves deadlocks when a given Yahoo account has a ridiculously large + (>500 buddies) list and may improve login speed for those on slow + connections. (#12532) + version 2.7.3 (08/10/2010): General: * Use silent build rules for automake >1.11. You can enable verbose diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/Makefile.am --- a/libpurple/protocols/mxit/Makefile.am Tue Mar 01 06:24:50 2011 +0000 +++ b/libpurple/protocols/mxit/Makefile.am Sat Mar 05 17:18:10 2011 +0000 @@ -33,7 +33,9 @@ roster.c \ roster.h \ splashscreen.c \ - splashscreen.h + splashscreen.h \ + voicevideo.c \ + voicevideo.h AM_CFLAGS = $(st) diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/Makefile.mingw --- a/libpurple/protocols/mxit/Makefile.mingw Tue Mar 01 06:24:50 2011 +0000 +++ b/libpurple/protocols/mxit/Makefile.mingw Sat Mar 05 17:18:10 2011 +0000 @@ -51,7 +51,8 @@ profile.c \ protocol.c \ roster.c \ - splashscreen.c + splashscreen.c \ + voicevideo.c OBJECTS = $(C_SRC:%.c=%.o) diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/actions.c --- a/libpurple/protocols/mxit/actions.c Tue Mar 01 06:24:50 2011 +0000 +++ b/libpurple/protocols/mxit/actions.c Sat Mar 05 17:18:10 2011 +0000 @@ -314,12 +314,11 @@ { char version[256]; - g_snprintf( version, sizeof( version ), "MXit libPurple Plugin v%s\n" + g_snprintf( version, sizeof( version ), "MXit Client Protocol v%i.%i\n\n" "Author:\nPieter Loubser\n\n" "Contributors:\nAndrew Victor\n\n" "Testers:\nBraeme Le Roux\n\n", - MXIT_PLUGIN_VERSION, ( MXIT_CP_PROTO_VESION / 10 ), ( MXIT_CP_PROTO_VESION % 10 ) ); mxit_popup( PURPLE_NOTIFY_MSG_INFO, _( "About" ), version ); diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/chunk.c --- a/libpurple/protocols/mxit/chunk.c Tue Mar 01 06:24:50 2011 +0000 +++ b/libpurple/protocols/mxit/chunk.c Sat Mar 05 17:18:10 2011 +0000 @@ -406,10 +406,9 @@ * @param chunkdata Chunked-data buffer * @param mxitId The username who's avatar to download * @param avatarId The Id of the avatar image (as string) - * @param imgsize The resolution of the avatar image * @return The number of bytes encoded in the buffer */ -int mxit_chunk_create_get_avatar( char* chunkdata, const char* mxitId, const char* avatarId, unsigned int imgsize ) +int mxit_chunk_create_get_avatar( char* chunkdata, const char* mxitId, const char* avatarId ) { int pos = 0; @@ -432,7 +431,7 @@ pos += add_int16( &chunkdata[pos], 1 ); /* image size [4 bytes] */ - pos += add_int32( &chunkdata[pos], imgsize ); + pos += add_int32( &chunkdata[pos], MXIT_AVATAR_SIZE ); return pos; } diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/chunk.h --- a/libpurple/protocols/mxit/chunk.h Tue Mar 01 06:24:50 2011 +0000 +++ b/libpurple/protocols/mxit/chunk.h Sat Mar 05 17:18:10 2011 +0000 @@ -152,7 +152,7 @@ int mxit_chunk_create_get( char* chunkdata, const char* fileid, int filesize, int offset ); int mxit_chunk_create_received( char* chunkdata, const char* fileid, unsigned char status ); int mxit_chunk_create_set_avatar( char* chunkdata, const unsigned char* data, int datalen ); -int mxit_chunk_create_get_avatar( char* chunkdata, const char* mxitId, const char* avatarId, unsigned int imgsize ); +int mxit_chunk_create_get_avatar( char* chunkdata, const char* mxitId, const char* avatarId ); /* Decode chunk */ void mxit_chunk_parse_offer( char* chunkdata, int datalen, struct offerfile_chunk* offer ); diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/formcmds.c --- a/libpurple/protocols/mxit/formcmds.c Tue Mar 01 06:24:50 2011 +0000 +++ b/libpurple/protocols/mxit/formcmds.c Sat Mar 05 17:18:10 2011 +0000 @@ -47,7 +47,11 @@ MXIT_CMD_REPLY, /* Reply (reply) */ MXIT_CMD_PLATREQ, /* Platform Request (platreq) */ MXIT_CMD_SELECTCONTACT, /* Select Contact (selc) */ - MXIT_CMD_IMAGE /* Inline image (img) */ + MXIT_CMD_IMAGE, /* Inline image (img) */ + MXIT_CMD_SCREENCONFIG, /* Chat-screen config (csc) */ + MXIT_CMD_SCREENINFO, /* Chat-screen info (csi) */ + MXIT_CMD_IMAGESTRIP, /* Image Strip (is) */ + MXIT_CMD_TABLE /* Table (tbl) */ } MXitCommandType; @@ -87,7 +91,7 @@ goto done; } - /* lets first see if we dont have the inline image already in cache */ + /* lets first see if we don't have the inline image already in cache */ if (g_hash_table_lookup(iireq->mx->session->iimages, iireq->url)) { /* inline image found in the cache, so we just ignore this reply */ goto done; @@ -149,8 +153,16 @@ else if (strcmp(type, "selc") == 0) /* select contact */ return MXIT_CMD_SELECTCONTACT; } - else if (strcmp(op, "img") == 0) - return MXIT_CMD_IMAGE; + else if (strcmp(op, "img") == 0) /* inline image */ + return MXIT_CMD_IMAGE; + else if (strcmp(op, "csc") == 0) /* chat-screen config */ + return MXIT_CMD_SCREENCONFIG; + else if (strcmp(op, "csi") == 0) /* chat-screen info */ + return MXIT_CMD_SCREENINFO; + else if (strcmp(op, "is") == 0) /* image-strip */ + return MXIT_CMD_IMAGESTRIP; + else if (strcmp(op, "tbl") == 0) /* table */ + return MXIT_CMD_TABLE; } return MXIT_CMD_UNKNOWN; @@ -333,7 +345,7 @@ g_string_append_printf(msg, "%s%s>", MXIT_II_TAG, iireq->url); mx->got_img = TRUE; - /* lets first see if we dont have the inline image already in cache */ + /* lets first see if we don't have the inline image already in cache */ if (g_hash_table_lookup(mx->session->iimages, iireq->url)) { /* inline image found in the cache, so we do not have to request it from the web */ g_free(iireq); diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/login.c --- a/libpurple/protocols/mxit/login.c Tue Mar 01 06:24:50 2011 +0000 +++ b/libpurple/protocols/mxit/login.c Sat Mar 05 17:18:10 2011 +0000 @@ -84,7 +84,7 @@ 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 ); + session->http_last_poll = mxit_now_milli(); return session; } @@ -106,7 +106,7 @@ 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 ); + session->last_tx = mxit_now_milli(); /* encrypt the user password */ session->encpwd = mxit_encrypt_password( session ); @@ -141,9 +141,10 @@ } /* This timer might already exist if we're registering a new account */ - if ( session->q_timer == 0 ) + if ( session->q_timer == 0 ) { /* start the tx queue manager timer */ - session->q_timer = purple_timeout_add_seconds( 2, mxit_manage_queue, session ); + session->q_timer = purple_timeout_add_seconds( 2, mxit_manage_queue_slow, session ); + } } @@ -238,7 +239,7 @@ /* nickname */ str = purple_request_fields_get_string( fields, "nickname" ); if ( ( !str ) || ( strlen( str ) < 3 ) ) { - err = _( "The Display Name you entered is invalid." ); + err = _( "The Display Name you entered is too short." ); goto out; } g_strlcpy( profile->nickname, str, sizeof( profile->nickname ) ); @@ -546,8 +547,8 @@ /* 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, + url = g_strdup_printf( "%s?type=getpid&sessionid=%s&login=%s&ver=%i.%i.%i&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 ), PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_MICRO_VERSION, 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 ); @@ -762,6 +763,12 @@ { purple_debug_info( MXIT_PLUGIN_ID, "mxit_reconnect\n" ); + /* remove the input cb function */ + if ( session->con->inpa ) { + purple_input_remove( session->con->inpa ); + session->con->inpa = 0; + } + /* close existing connection */ session->flags &= ~MXIT_FLAG_CONNECTED; purple_proxy_connect_cancel_with_handle( session->con ); diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/mxit.c --- a/libpurple/protocols/mxit/mxit.c Tue Mar 01 06:24:50 2011 +0000 +++ b/libpurple/protocols/mxit/mxit.c Sat Mar 05 17:18:10 2011 +0000 @@ -37,6 +37,7 @@ #include "filexfer.h" #include "actions.h" #include "multimx.h" +#include "voicevideo.h" #ifdef MXIT_LINK_CLICK @@ -524,7 +525,7 @@ if ( session->http ) return; - if ( session->last_tx <= time( NULL ) - MXIT_PING_INTERVAL ) { + if ( session->last_tx <= ( mxit_now_milli() - ( MXIT_PING_INTERVAL * 1000 ) ) ) { /* * this connection has been idle for too long, better ping * the server before it kills our connection. @@ -559,6 +560,8 @@ */ static void mxit_get_info( PurpleConnection *gc, const char *who ) { + PurpleBuddy* buddy; + struct contact* contact; struct MXitSession* session = (struct MXitSession*) gc->proto_data; const char* profilelist[] = { CP_PROFILE_BIRTHDATE, CP_PROFILE_GENDER, CP_PROFILE_FULLNAME, CP_PROFILE_FIRSTNAME, CP_PROFILE_LASTNAME, CP_PROFILE_REGCOUNTRY, CP_PROFILE_LASTSEEN, @@ -566,6 +569,22 @@ purple_debug_info( MXIT_PLUGIN_ID, "mxit_get_info: '%s'\n", who ); + /* find the buddy information for this contact (reference: "libpurple/blist.h") */ + buddy = purple_find_buddy( session->acc, who ); + if ( !buddy ) { + purple_debug_warning( MXIT_PLUGIN_ID, "mxit_get_info: unable to find the buddy '%s'\n", who ); + return; + } + + contact = purple_buddy_get_protocol_data( buddy ); + if ( !contact ) + return; + + /* only MXit users have profiles */ + if ( contact->type != MXIT_TYPE_MXIT ) { + mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "No profile available" ), _( "This contact does not have a profile." ) ); + return; + } /* send profile request */ mxit_send_extprofile_request( session, who, ARRAY_SIZE( profilelist ), profilelist ); @@ -588,7 +607,33 @@ /*------------------------------------------------------------------------ - * Buddy list menu. + * Re-Invite was selected from the buddy-list menu. + * + * @param node The entry in the buddy list. + * @param ignored (not used) + */ +static void mxit_reinvite( PurpleBlistNode *node, gpointer ignored ) +{ + PurpleBuddy* buddy; + struct contact* contact; + PurpleConnection* gc; + struct MXitSession* session; + + buddy = (PurpleBuddy *)node; + gc = purple_account_get_connection( purple_buddy_get_account( buddy ) ); + session = gc->proto_data; + + contact = purple_buddy_get_protocol_data( (PurpleBuddy*) node ); + if ( !contact ) + return; + + /* send a new invite */ + mxit_send_invite( session, contact->username, contact->alias, contact->groupname ); +} + + +/*------------------------------------------------------------------------ + * Buddy-list menu. * * @param node The entry in the buddy list. */ @@ -597,6 +642,7 @@ PurpleBuddy* buddy; struct contact* contact; GList* m = NULL; + PurpleMenuAction* act; if ( !PURPLE_BLIST_NODE_IS_BUDDY( node ) ) return NULL; @@ -606,6 +652,12 @@ if ( !contact ) return NULL; + if ( ( contact->subtype == MXIT_SUBTYPE_DELETED ) || ( contact->subtype == MXIT_SUBTYPE_REJECTED ) || ( contact->subtype == MXIT_SUBTYPE_NONE ) ) { + /* contact is in Deleted, Rejected or None state */ + act = purple_menu_action_new( _( "Re-Invite" ), PURPLE_CALLBACK( mxit_reinvite ), NULL, NULL ); + m = g_list_append(m, act); + } + return m; } @@ -686,8 +738,8 @@ NULL, /* attention_types */ sizeof( PurplePluginProtocolInfo ), /* struct_size */ mxit_get_text_table, /* get_account_text_table */ - NULL, /* initiate_media */ - NULL, /* get_media_caps */ + mxit_media_initiate, /* initiate_media */ + mxit_media_caps, /* get_media_caps */ mxit_get_moods, /* get_moods */ NULL, /* set_public_alias */ NULL /* get_public_alias */ @@ -706,7 +758,7 @@ MXIT_PLUGIN_ID, /* plugin id (must be unique) */ MXIT_PLUGIN_NAME, /* plugin name (this will be displayed in the UI) */ - MXIT_PLUGIN_VERSION, /* version of the plugin */ + DISPLAY_VERSION, /* version of the plugin */ MXIT_PLUGIN_SUMMARY, /* short summary of the plugin */ MXIT_PLUGIN_DESC, /* description of the plugin (can be long) */ diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/mxit.h --- a/libpurple/protocols/mxit/mxit.h Tue Mar 01 06:24:50 2011 +0000 +++ b/libpurple/protocols/mxit/mxit.h Sat Mar 05 17:18:10 2011 +0000 @@ -63,13 +63,12 @@ /* Plugin details */ #define MXIT_PLUGIN_ID "prpl-loubserp-mxit" #define MXIT_PLUGIN_NAME "MXit" -#define MXIT_PLUGIN_VERSION "2.4.0" #define MXIT_PLUGIN_EMAIL "Pieter Loubser " #define MXIT_PLUGIN_WWW "http://www.mxit.com" #define MXIT_PLUGIN_SUMMARY "MXit Protocol Plugin" #define MXIT_PLUGIN_DESC "MXit" -#define MXIT_HTTP_USERAGENT "libpurple-"MXIT_PLUGIN_VERSION +#define MXIT_HTTP_USERAGENT "libpurple-"DISPLAY_VERSION /* default connection settings */ @@ -111,7 +110,6 @@ /* define this to enable the link clicking support */ #define MXIT_LINK_CLICK - #ifdef MXIT_LINK_CLICK #define MXIT_LINK_PREFIX "gopher://" #define MXIT_LINK_KEY "MXIT" @@ -137,10 +135,13 @@ unsigned int http_seqno; /* HTTP request sequence number */ guint http_timer_id; /* timer resource id (pidgin) */ int http_interval; /* poll inverval */ - time_t http_last_poll; /* the last time a poll has been sent */ + gint64 http_last_poll; /* the last time a poll has been sent */ guint http_handler; /* HTTP connection handler */ void* http_out_req; /* HTTP outstanding request */ + /* other servers */ + char voip_server[HOST_NAME_MAX]; /* voice/video server */ + /* client */ struct login_data* logindata; char* encpwd; /* encrypted password */ @@ -159,7 +160,7 @@ /* transmit */ struct tx_queue queue; /* transmit packet queue (FIFO mode) */ - time_t last_tx; /* timestamp of last packet sent */ + gint64 last_tx; /* timestamp of last packet sent */ int outack; /* outstanding ack packet */ guint q_timer; /* timer handler for managing queue */ @@ -169,7 +170,7 @@ unsigned int rx_i; /* receive buffer current index */ int rx_res; /* amount of bytes still outstanding for the current packet */ char rx_state; /* current receiver state */ - time_t last_rx; /* timestamp of last packet received */ + gint64 last_rx; /* timestamp of last packet received */ GList* active_chats; /* list of all our contacts we received messages from (active chats) */ /* groupchat */ diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/profile.c --- a/libpurple/protocols/mxit/profile.c Tue Mar 01 06:24:50 2011 +0000 +++ b/libpurple/protocols/mxit/profile.c Sat Mar 05 17:18:10 2011 +0000 @@ -108,10 +108,10 @@ */ static const char* datetime( gint64 msecs ) { - time_t secs = msecs / 1000; + time_t secs = msecs / 1000; - struct tm t; - localtime_r( &secs, &t ); + struct tm t; + localtime_r( &secs, &t ); return purple_utf8_strftime( "%d-%m-%Y %H:%M:%S", &t ); } @@ -140,13 +140,10 @@ purple_notify_user_info_add_pair( info, _( "Display Name" ), profile->nickname ); purple_notify_user_info_add_pair( info, _( "Birthday" ), profile->birthday ); purple_notify_user_info_add_pair( info, _( "Gender" ), profile->male ? _( "Male" ) : _( "Female" ) ); -// purple_notify_user_info_add_pair( info, _( "Hidden Number" ), profile->hidden ? _( "Yes" ) : _( "No" ) ); /* optional information */ -// purple_notify_user_info_add_pair( info, _( "Title" ), profile->title ); purple_notify_user_info_add_pair( info, _( "First Name" ), profile->firstname ); purple_notify_user_info_add_pair( info, _( "Last Name" ), profile->lastname ); -// purple_notify_user_info_add_pair( info, _( "Email" ), profile->email ); purple_notify_user_info_add_pair( info, _( "Country" ), profile->regcountry ); purple_notify_user_info_add_section_break( info ); diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/protocol.c --- a/libpurple/protocols/mxit/protocol.c Tue Mar 01 06:24:50 2011 +0000 +++ b/libpurple/protocols/mxit/protocol.c Sat Mar 05 17:18:10 2011 +0000 @@ -37,6 +37,7 @@ #include "login.h" #include "formcmds.h" #include "http.h" +#include "voicevideo.h" #define MXIT_MS_OFFSET 3 @@ -45,6 +46,18 @@ #define CP_REC_TERM ( ( session->http ) ? CP_HTTP_REC_TERM : CP_SOCK_REC_TERM ) +/*------------------------------------------------------------------------ + * return the current timestamp in milliseconds + */ +gint64 mxit_now_milli( void ) +{ + GTimeVal now; + + g_get_current_time( &now ); + + return ( ( now.tv_sec * 1000 ) + ( now.tv_usec / 1000 ) ); +} + /*------------------------------------------------------------------------ * Display a notification popup message to the user. @@ -411,7 +424,7 @@ } /* update the timestamp of the last-transmitted packet */ - session->last_tx = time( NULL ); + session->last_tx = mxit_now_milli(); /* * we need to remember that we are still waiting for the ACK from @@ -474,17 +487,13 @@ packet->datalen = datalen; - /* - * shortcut: first check if there are any commands still outstanding. - * if not, then we might as well just write this packet directly and - * skip the whole queueing thing - */ - if ( session->outack == 0 ) { - /* no outstanding ACKs, so we might as well write it directly */ + /* shortcut */ + if ( ( session->queue.count == 0 ) && ( session->outack == 0 ) ) { + /* the queue is empty and there are no outstanding acks so we can write it directly */ mxit_send_packet( session, packet ); } else { - /* ACK still outstanding, so we need to queue this request until we have the ACK */ + /* we need to queue this packet */ if ( ( packet->cmd == CP_CMD_PING ) || ( packet->cmd == CP_CMD_POLL ) ) { /* we do NOT queue HTTP poll nor socket ping packets */ @@ -503,42 +512,89 @@ /*------------------------------------------------------------------------ - * Callback to manage the packet send queue (send next packet, timeout's, etc). + * Manage the packet send queue (send next packet, timeout's, etc). * * @param session The MXit session object */ -gboolean mxit_manage_queue( gpointer user_data ) +static void mxit_manage_queue( struct MXitSession* session ) { - struct MXitSession* session = (struct MXitSession*) user_data; struct tx_packet* packet = NULL; + gint64 now = mxit_now_milli(); if ( !( session->flags & MXIT_FLAG_CONNECTED ) ) { /* we are not connected, so ignore the queue */ - return TRUE; + return; } else if ( session->outack > 0 ) { /* we are still waiting for an outstanding ACK from the MXit server */ - if ( session->last_tx <= time( NULL ) - MXIT_ACK_TIMEOUT ) { + if ( session->last_tx <= mxit_now_milli() - ( MXIT_ACK_TIMEOUT * 1000 ) ) { /* ack timeout! so we close the connection here */ purple_debug_info( MXIT_PLUGIN_ID, "mxit_manage_queue: Timeout awaiting ACK for command '%i'\n", session->outack ); purple_connection_error( session->con, _( "Timeout while waiting for a response from the MXit server." ) ); } - return TRUE; + return; + } + + /* + * the mxit server has flood detection and it prevents you from sending messages to fast. + * this is a self defense mechanism, a very annoying feature. so the client must ensure that + * it does not send messages too fast otherwise mxit will ignore the user for 30 seconds. + * this is what we are trying to avoid here.. + */ + if ( session->last_tx > ( now - MXIT_TX_DELAY ) ) { + /* we need to wait a little before sending the next packet, so schedule a wakeup call */ + gint64 tdiff = now - ( session->last_tx ); + guint delay = ( MXIT_TX_DELAY - tdiff ) + 9; + if ( delay <= 0 ) + delay = MXIT_TX_DELAY; + purple_timeout_add( delay, mxit_manage_queue_fast, session ); + } + else { + /* get the next packet from the queue to send */ + packet = pop_tx_packet( session ); + if ( packet != NULL ) { + /* there was a packet waiting to be sent to the server, now is the time to do something about it */ + + /* send the packet to MXit server */ + mxit_send_packet( session, packet ); + } } - - packet = pop_tx_packet( session ); - if ( packet != NULL ) { - /* there was a packet waiting to be sent to the server, now is the time to do something about it */ - - /* send the packet to MXit server */ - mxit_send_packet( session, packet ); - } - +} + + +/*------------------------------------------------------------------------ + * Slow callback to manage the packet send queue. + * + * @param session The MXit session object + */ +gboolean mxit_manage_queue_slow( gpointer user_data ) +{ + struct MXitSession* session = (struct MXitSession*) user_data; + + mxit_manage_queue( session ); + + /* continue running */ return TRUE; } /*------------------------------------------------------------------------ + * Fast callback to manage the packet send queue. + * + * @param session The MXit session object + */ +gboolean mxit_manage_queue_fast( gpointer user_data ) +{ + struct MXitSession* session = (struct MXitSession*) user_data; + + mxit_manage_queue( session ); + + /* stop running */ + return FALSE; +} + + +/*------------------------------------------------------------------------ * Callback to manage HTTP server polling (HTTP connections ONLY) * * @param session The MXit session object @@ -547,9 +603,9 @@ { struct MXitSession* session = (struct MXitSession*) user_data; gboolean poll = FALSE; - time_t now = time( NULL ); + gint64 now = mxit_now_milli(); int polldiff; - int rxdiff; + gint64 rxdiff; if ( !( session->flags & MXIT_FLAG_LOGGEDIN ) ) { /* we only poll if we are actually logged in */ @@ -579,7 +635,7 @@ if ( poll ) { /* send poll request */ - session->http_last_poll = time( NULL ); + session->http_last_poll = mxit_now_milli(); mxit_send_poll( session ); } @@ -638,21 +694,36 @@ const char* locale; char data[CP_MAX_PACKET]; int datalen; + char* clientVersion; + unsigned int features = MXIT_CP_FEATURES; locale = purple_account_get_string( session->acc, MXIT_CONFIG_LOCALE, MXIT_DEFAULT_LOCALE ); + /* Voice and Video supported */ + if (mxit_audio_enabled() && mxit_video_enabled()) + features |= (MXIT_CF_VOICE | MXIT_CF_VIDEO); + else if (mxit_audio_enabled()) + features |= MXIT_CF_VOICE; + + /* generate client version string (eg, P-2.7.10-Y-PURPLE) */ + clientVersion = g_strdup_printf( "%c-%i.%i.%i-%s-%s", MXIT_CP_DISTCODE, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_MICRO_VERSION, MXIT_CP_ARCH, MXIT_CP_PLATFORM ); + /* convert the packet to a byte stream */ datalen = snprintf( data, sizeof( data ), "ms=%s%c%s%c%i%c%s%c" /* "ms"=password\1version\1maxreplyLen\1name\1 */ "%s%c%i%c%s%c%s%c" /* dateOfBirth\1gender\1location\1capabilities\1 */ - "%s%c%i%c%s%c%s", /* dc\1features\1dialingcode\1locale */ - session->encpwd, CP_FLD_TERM, MXIT_CP_VERSION, CP_FLD_TERM, CP_MAX_FILESIZE, CP_FLD_TERM, profile->nickname, CP_FLD_TERM, + "%s%c%i%c%s%c%s" /* dc\1features\1dialingcode\1locale */ + "%c%i%c%i", /* \1protocolVer\1lastRosterUpdate */ + session->encpwd, CP_FLD_TERM, clientVersion, CP_FLD_TERM, CP_MAX_FILESIZE, CP_FLD_TERM, profile->nickname, CP_FLD_TERM, profile->birthday, CP_FLD_TERM, ( profile->male ) ? 1 : 0, CP_FLD_TERM, MXIT_DEFAULT_LOC, CP_FLD_TERM, MXIT_CP_CAP, CP_FLD_TERM, - session->distcode, CP_FLD_TERM, MXIT_CP_FEATURES, CP_FLD_TERM, session->dialcode, CP_FLD_TERM, locale + session->distcode, CP_FLD_TERM, features, CP_FLD_TERM, session->dialcode, CP_FLD_TERM, locale, + CP_FLD_TERM, MXIT_CP_PROTO_VESION, CP_FLD_TERM, 0 ); /* queue packet for transmission */ mxit_queue_packet( session, data, datalen, CP_CMD_REGISTER ); + + g_free( clientVersion ); } @@ -663,21 +734,32 @@ */ void mxit_send_login( struct MXitSession* session ) { - const char* splashId; - const char* locale; - char data[CP_MAX_PACKET]; - int datalen; + const char* splashId; + const char* locale; + char data[CP_MAX_PACKET]; + int datalen; + char* clientVersion; + unsigned int features = MXIT_CP_FEATURES; locale = purple_account_get_string( session->acc, MXIT_CONFIG_LOCALE, MXIT_DEFAULT_LOCALE ); + /* Voice and Video supported */ + if (mxit_audio_enabled() && mxit_video_enabled()) + features |= (MXIT_CF_VOICE | MXIT_CF_VIDEO); + else if (mxit_audio_enabled()) + features |= MXIT_CF_VOICE; + + /* generate client version string (eg, P-2.7.10-Y-PURPLE) */ + clientVersion = g_strdup_printf( "%c-%i.%i.%i-%s-%s", MXIT_CP_DISTCODE, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_MICRO_VERSION, MXIT_CP_ARCH, MXIT_CP_PLATFORM ); + /* convert the packet to a byte stream */ datalen = snprintf( data, sizeof( data ), "ms=%s%c%s%c%i%c" /* "ms"=password\1version\1getContacts\1 */ "%s%c%s%c%i%c" /* capabilities\1dc\1features\1 */ "%s%c%s%c" /* dialingcode\1locale\1 */ "%i%c%i%c%i", /* maxReplyLen\1protocolVer\1lastRosterUpdate */ - session->encpwd, CP_FLD_TERM, MXIT_CP_VERSION, CP_FLD_TERM, 1, CP_FLD_TERM, - MXIT_CP_CAP, CP_FLD_TERM, session->distcode, CP_FLD_TERM, MXIT_CP_FEATURES, CP_FLD_TERM, + session->encpwd, CP_FLD_TERM, clientVersion, CP_FLD_TERM, 1, CP_FLD_TERM, + MXIT_CP_CAP, CP_FLD_TERM, session->distcode, CP_FLD_TERM, features, CP_FLD_TERM, session->dialcode, CP_FLD_TERM, locale, CP_FLD_TERM, CP_MAX_FILESIZE, CP_FLD_TERM, MXIT_CP_PROTO_VESION, CP_FLD_TERM, 0 ); @@ -689,6 +771,8 @@ /* queue packet for transmission */ mxit_queue_packet( session, data, datalen, CP_CMD_LOGIN ); + + g_free( clientVersion ); } @@ -732,7 +816,7 @@ * @param session The MXit session object * @param username Username who's profile is being requested (NULL = our own) * @param nr_attribs Number of attributes being requested - * @param attributes The names of the attributes + * @param attribute The names of the attributes */ void mxit_send_extprofile_request( struct MXitSession* session, const char* username, unsigned int nr_attrib, const char* attribute[] ) { @@ -742,7 +826,8 @@ datalen = snprintf( data, sizeof( data ), "ms=%s%c%i", /* "ms="mxitid\1nr_attributes */ - (username ? username : ""), CP_FLD_TERM, nr_attrib); + ( username ? username : "" ), CP_FLD_TERM, nr_attrib + ); /* add attributes */ for ( i = 0; i < nr_attrib; i++ ) @@ -790,6 +875,63 @@ /*------------------------------------------------------------------------ + * Send packet to request list of suggested friends. + * + * @param session The MXit session object + * @param max Maximum number of results to return + * @param nr_attribs Number of attributes being requested + * @param attribute The names of the attributes + */ +void mxit_send_suggest_friends( struct MXitSession* session, int max, unsigned int nr_attrib, const char* attribute[] ) +{ + char data[CP_MAX_PACKET]; + int datalen; + unsigned int i; + + /* convert the packet to a byte stream */ + datalen = snprintf( data, sizeof( data ), + "ms=%i%c%s%c%i%c%i", /* inputType \1 input \ 1 maxSuggestions \1 numAttributes \1 name0 ... \1 nameN */ + CP_SUGGEST_FRIENDS, CP_FLD_TERM, "", CP_FLD_TERM, max, CP_FLD_TERM, nr_attrib ); + + /* add attributes */ + for ( i = 0; i < nr_attrib; i++ ) + datalen += sprintf( data + datalen, "%c%s", CP_FLD_TERM, attribute[i] ); + + /* queue packet for transmission */ + mxit_queue_packet( session, data, datalen, CP_CMD_SUGGESTCONTACTS ); +} + + +/*------------------------------------------------------------------------ + * Send packet to perform a search for users. + * + * @param session The MXit session object + * @param max Maximum number of results to return + * @param text The search text + * @param nr_attribs Number of attributes being requested + * @param attribute The names of the attributes + */ +void mxit_send_suggest_search( struct MXitSession* session, int max, const char* text, unsigned int nr_attrib, const char* attribute[] ) +{ + char data[CP_MAX_PACKET]; + int datalen; + unsigned int i; + + /* convert the packet to a byte stream */ + datalen = snprintf( data, sizeof( data ), + "ms=%i%c%s%c%i%c%i", /* inputType \1 input \ 1 maxSuggestions \1 numAttributes \1 name0 ... \1 nameN */ + CP_SUGGEST_SEARCH, CP_FLD_TERM, text, CP_FLD_TERM, max, CP_FLD_TERM, nr_attrib ); + + /* add attributes */ + for ( i = 0; i < nr_attrib; i++ ) + datalen += sprintf( data + datalen, "%c%s", CP_FLD_TERM, attribute[i] ); + + /* queue packet for transmission */ + mxit_queue_packet( session, data, datalen, CP_CMD_SUGGESTCONTACTS ); +} + + +/*------------------------------------------------------------------------ * Send a presence update packet to the MXit server. * * @param session The MXit session object @@ -1039,7 +1181,6 @@ * @param nr_usernames Number of users being invited * @param usernames The usernames of the users being invited */ - void mxit_send_groupchat_invite( struct MXitSession* session, const char* roomid, int nr_usernames, const char* usernames[] ) { char data[CP_MAX_PACKET]; @@ -1271,7 +1412,7 @@ /* map chunk header over data buffer */ chunk = &data[datalen]; - size = mxit_chunk_create_get_avatar( chunk_data(chunk), mxitId, avatarId, MXIT_AVATAR_SIZE ); + size = mxit_chunk_create_get_avatar( chunk_data(chunk), mxitId, avatarId ); if ( size < 0 ) { purple_debug_error( MXIT_PLUGIN_ID, "Error creating get avatar chunk (%i)\n", size ); return; @@ -1322,6 +1463,10 @@ if ( records[1]->fcount >= 9 ) session->uid = g_strdup( records[1]->fields[8]->data ); + /* extract VoIP server (from protocol 6.2) */ + if ( records[1]->fcount >= 11 ) + g_strlcpy( session->voip_server, records[1]->fields[10]->data, sizeof( session->voip_server ) ); + /* display the current splash-screen */ if ( splash_popup_enabled( session ) ) splash_display( session ); @@ -1567,13 +1712,13 @@ */ static void mxit_parse_cmd_presence( struct MXitSession* session, struct record** records, int rcount ) { - struct record* rec; int i; purple_debug_info( MXIT_PLUGIN_ID, "mxit_parse_cmd_presence (%i recs)\n", rcount ); for ( i = 0; i < rcount; i++ ) { - rec = records[i]; + struct record* rec = records[i]; + int flags = 0; if ( rec->fcount < 6 ) { purple_debug_error( MXIT_PLUGIN_ID, "BAD PRESENCE RECORD! %i fields\n", rec->fcount ); @@ -1582,12 +1727,15 @@ /* * The format of the record is: - * contactAddressN\1presenceN\1moodN\1customMoodN\1statusMsgN\1avatarIdN + * contactAddressN \1 presenceN \1 moodN \1 customMoodN \1 statusMsgN \1 avatarIdN [ \1 flagsN ] */ mxit_strip_domain( rec->fields[0]->data ); /* contactAddress */ + if ( rec->fcount >= 7 ) /* flags field is included */ + flags = atoi( rec->fields[6]->data ); + mxit_update_buddy_presence( session, rec->fields[0]->data, atoi( rec->fields[1]->data ), atoi( rec->fields[2]->data ), - rec->fields[3]->data, rec->fields[4]->data ); + rec->fields[3]->data, rec->fields[4]->data, flags ); mxit_update_buddy_avatar( session, rec->fields[0]->data, rec->fields[5]->data ); } } @@ -1908,7 +2056,7 @@ { /* ignore ping/poll packets */ if ( ( packet->cmd != CP_CMD_PING ) && ( packet->cmd != CP_CMD_POLL ) ) - session->last_rx = time( NULL ); + session->last_rx = mxit_now_milli(); /* * when we pass the packet records to the next level for parsing diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/protocol.h --- a/libpurple/protocols/mxit/protocol.h Tue Mar 01 06:24:50 2011 +0000 +++ b/libpurple/protocols/mxit/protocol.h Sat Mar 05 17:18:10 2011 +0000 @@ -75,6 +75,8 @@ #define MXIT_CF_NO_AVATARS 0x200000 #define MXIT_CF_GAMING 0x400000 #define MXIT_CF_GAMING_UPDATE 0x800000 +#define MXIT_CF_VOICE 0x1000000 +#define MXIT_CF_VIDEO 0x2000000 /* Client features supported by this implementation */ #define MXIT_CP_FEATURES ( MXIT_CF_FILE_TRANSFER | MXIT_CF_FILE_ACCESS | MXIT_CF_AUDIO | MXIT_CF_MARKUP | MXIT_CF_EXT_MARKUP | MXIT_CF_NO_GATEWAYS | MXIT_CF_IMAGES | MXIT_CF_COMMANDS | MXIT_CF_VIBES | MXIT_CF_MIDP2 ) @@ -82,14 +84,13 @@ #define MXIT_PING_INTERVAL ( 5 * 60 ) /* ping the server after X seconds of being idle (5 minutes) */ #define MXIT_ACK_TIMEOUT ( 30 ) /* timeout after waiting X seconds for an ack from the server (30 seconds) */ +#define MXIT_TX_DELAY ( 100 ) /* delay between sending consecutive packets (100 ms) */ /* MXit client version */ -#define MXIT_CP_DISTCODE "P" /* client distribution code (magic, do not touch!) */ -#define MXIT_CP_RELEASE "5.9.0" /* client version */ +#define MXIT_CP_DISTCODE 'P' /* client distribution code (magic, do not touch!) */ #define MXIT_CP_ARCH "Y" /* client architecture series (Y not for Yoda but for PC-client) */ #define MXIT_CLIENT_ID "LP" /* client ID as specified by MXit */ #define MXIT_CP_PLATFORM "PURPLE" /* client platform */ -#define MXIT_CP_VERSION MXIT_CP_DISTCODE"-"MXIT_CP_RELEASE"-"MXIT_CP_ARCH"-"MXIT_CP_PLATFORM #define MXIT_CP_PROTO_VESION 60 /* client protocol version */ /* set operating system name */ @@ -107,7 +108,7 @@ #define MXIT_CP_CAP "utf8=true;cid="MXIT_CLIENT_ID /* Client settings */ -#define MAX_QUEUE_SIZE ( 1 << 4 ) /* tx queue size (16 packets) */ +#define MAX_QUEUE_SIZE ( 1 << 5 ) /* tx queue size (32 packets) */ #define MXIT_POPUP_WIN_NAME "MXit Notification" /* popup window name */ #define MXIT_MAX_ATTRIBS 10 /* maximum profile attributes supported */ #define MXIT_DEFAULT_LOCALE "en" /* default locale setting */ @@ -125,6 +126,7 @@ #define CP_CMD_TX_MSG 0x000A /* (10) send new message */ #define CP_CMD_REGISTER 0x000B /* (11) register */ //#define CP_CMD_PROFILE_SET 0x000C /* (12) set profile (DEPRECATED see CP_CMD_EXTPROFILE_SET) */ +#define CP_CMD_SUGGESTCONTACTS 0x000D /* (13) suggest contacts */ #define CP_CMD_POLL 0x0011 /* (17) poll the HTTP server for an update */ //#define CP_CMD_PROFILE_GET 0x001A /* (26) get profile (DEPRECATED see CP_CMD_EXTPROFILE_GET) */ #define CP_CMD_MEDIA 0x001B /* (27) get multimedia message */ @@ -202,6 +204,12 @@ /* profile flags */ #define CP_PROF_DOBLOCKED 0x40 /* date-of-birth cannot be changed */ +/* suggestion types */ +#define CP_SUGGEST_ADDRESSBOOK 0 /* address book search */ +#define CP_SUGGEST_FRIENDS 1 /* suggested friends */ +#define CP_SUGGEST_SEARCH 2 /* free-text search */ +#define CP_SUGGEST_MXITID 3 /* MXitId search */ + /* define this to enable protocol debugging (very verbose logging) */ #define DEBUG_PROTOCOL @@ -277,7 +285,8 @@ gboolean find_active_chat( const GList* chats, const char* who ); void mxit_cb_rx( gpointer data, gint source, PurpleInputCondition cond ); -gboolean mxit_manage_queue( gpointer user_data ); +gboolean mxit_manage_queue_slow( gpointer user_data ); +gboolean mxit_manage_queue_fast( gpointer user_data ); gboolean mxit_manage_polling( gpointer user_data ); void mxit_send_register( struct MXitSession* session ); @@ -293,6 +302,9 @@ void mxit_send_extprofile_update( struct MXitSession* session, const char* password, unsigned int nr_attrib, const char* attributes ); void mxit_send_extprofile_request( struct MXitSession* session, const char* username, unsigned int nr_attrib, const char* attribute[] ); +void mxit_send_suggest_friends( struct MXitSession* session, int max, unsigned int nr_attrib, const char* attribute[] ); +void mxit_send_suggest_search( struct MXitSession* session, int max, const char* text, unsigned int nr_attrib, const char* attribute[] ); + void mxit_send_invite( struct MXitSession* session, const char* username, const char* alias, const char* groupname ); void mxit_send_remove( struct MXitSession* session, const char* username ); void mxit_send_allow_sub( struct MXitSession* session, const char* username, const char* alias ); @@ -314,6 +326,7 @@ int mxit_parse_packet( struct MXitSession* session ); void dump_bytes( struct MXitSession* session, const char* buf, int len ); void mxit_close_connection( struct MXitSession* session ); +gint64 mxit_now_milli( void ); #endif /* _MXIT_PROTO_H_ */ diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/roster.c --- a/libpurple/protocols/mxit/roster.c Tue Mar 01 06:24:50 2011 +0000 +++ b/libpurple/protocols/mxit/roster.c Sat Mar 05 17:18:10 2011 +0000 @@ -443,8 +443,9 @@ * @param mood The new mood for the contact * @param customMood The custom mood identifier * @param statusMsg This is the contact's status message + * @param flags The contact's presence flags. */ -void mxit_update_buddy_presence( struct MXitSession* session, const char* username, short presence, short mood, const char* customMood, const char* statusMsg ) +void mxit_update_buddy_presence( struct MXitSession* session, const char* username, short presence, short mood, const char* customMood, const char* statusMsg, int flags ) { PurpleBuddy* buddy = NULL; struct contact* contact = NULL; @@ -470,6 +471,7 @@ contact->presence = presence; contact->mood = mood; + contact->capabilities = flags; /* validate mood */ if (( contact->mood < MXIT_MOOD_NONE ) || ( contact->mood > MXIT_MOOD_STRESSED )) diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/roster.h --- a/libpurple/protocols/mxit/roster.h Tue Mar 01 06:24:50 2011 +0000 +++ b/libpurple/protocols/mxit/roster.h Sat Mar 05 17:18:10 2011 +0000 @@ -79,6 +79,11 @@ #define MXIT_CFLAG_FOCUS_SEND_BLANK 0x20000 +/* MXit presence flags */ +#define MXIT_PFLAG_VOICE 0x1 +#define MXIT_PFLAG_VIDEO 0x2 + + /* Subscription types */ #define MXIT_SUBTYPE_BOTH 'B' #define MXIT_SUBTYPE_PENDING 'P' @@ -108,6 +113,7 @@ short mood; /* contact current mood */ int flags; /* contact flags */ short presence; /* presence state */ + int capabilities; /* contact capabilities */ short subtype; /* subscription type */ char* msg; /* invite/rejection message */ @@ -129,7 +135,7 @@ /* MXit Protocol callbacks */ void mxit_update_contact( struct MXitSession* session, struct contact* contact ); -void mxit_update_buddy_presence( struct MXitSession* session, const char* username, short presence, short mood, const char* customMood, const char* statusMsg ); +void mxit_update_buddy_presence( struct MXitSession* session, const char* username, short presence, short mood, const char* customMood, const char* statusMsg, int flags ); void mxit_update_buddy_avatar( struct MXitSession* session, const char* username, const char* avatarId ); void mxit_new_subscription( struct MXitSession* session, struct contact* contact ); void mxit_update_blist( struct MXitSession* session ); diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/voicevideo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/mxit/voicevideo.c Sat Mar 05 17:18:10 2011 +0000 @@ -0,0 +1,154 @@ +/* + * MXit Protocol libPurple Plugin + * + * -- voice & video -- + * + * Andrew Victor + * + * (C) Copyright 2010 MXit Lifestyle (Pty) Ltd. + * + * + * 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 "purple.h" +#include "mxit.h" +#include "roster.h" +#include "voicevideo.h" + +#if defined(USE_VV) && defined(MXIT_DEV_VV) + +#warning "MXit VV support enabled." + +/*------------------------------------------------------------------------ + * Does this client support Voice? + */ +gboolean mxit_audio_enabled(void) +{ + PurpleMediaManager *manager = purple_media_manager_get(); + PurpleMediaCaps caps = purple_media_manager_get_ui_caps(manager); + + return (caps & PURPLE_MEDIA_CAPS_AUDIO); +} + +/*------------------------------------------------------------------------ + * Does this client support Voice and Video? + */ +gboolean mxit_video_enabled(void) +{ + PurpleMediaManager *manager = purple_media_manager_get(); + PurpleMediaCaps caps = purple_media_manager_get_ui_caps(manager); + + return (caps & PURPLE_MEDIA_CAPS_VIDEO); +} + +/*------------------------------------------------------------------------ + * Return the list of media capabilities this contact supports. + * + * @param account The MXit account object + * @param who The username of the contact. + * @return The media capabilities supported + */ +PurpleMediaCaps mxit_media_caps(PurpleAccount *account, const char *who) +{ + struct MXitSession* session = purple_account_get_connection(account)->proto_data; + PurpleBuddy* buddy; + struct contact* contact; + PurpleMediaCaps capa = PURPLE_MEDIA_CAPS_NONE; + + purple_debug_info(MXIT_PLUGIN_ID, "mxit_media_caps: buddy '%s'\n", who); + + /* We need to have a voice/video server */ + if (strlen(session->voip_server) == 0) + return PURPLE_MEDIA_CAPS_NONE; + + /* find the buddy information for this contact (reference: "libpurple/blist.h") */ + buddy = purple_find_buddy(account, who); + if (!buddy) { + purple_debug_warning(MXIT_PLUGIN_ID, "mxit_media_caps: unable to find the buddy '%s'\n", who); + return PURPLE_MEDIA_CAPS_NONE; + } + + contact = purple_buddy_get_protocol_data(buddy); + if (!contact) + return PURPLE_MEDIA_CAPS_NONE; + + /* can only communicate with MXit users */ + if (contact->type != MXIT_TYPE_MXIT) + return PURPLE_MEDIA_CAPS_NONE; + + /* and only with contacts in the 'Both' subscription state */ + if (contact->subtype != MXIT_SUBTYPE_BOTH) + return PURPLE_MEDIA_CAPS_NONE; + + /* and only when they're online */ + if (contact->presence == MXIT_PRESENCE_OFFLINE) + return MXIT_PRESENCE_OFFLINE; + + /* they support voice-only */ + if (contact->capabilities & MXIT_PFLAG_VOICE) + capa |= PURPLE_MEDIA_CAPS_AUDIO; + + /* they support voice-and-video */ + if (contact->capabilities & MXIT_PFLAG_VIDEO) + capa |= (PURPLE_MEDIA_CAPS_AUDIO | PURPLE_MEDIA_CAPS_VIDEO | PURPLE_MEDIA_CAPS_AUDIO_VIDEO); + + return capa; +} + + +/*------------------------------------------------------------------------ + * Initiate a voice/video session with a contact. + * + * @param account The MXit account object + * @param who The username of the contact. + * @param type The type of media session to initiate + * @return TRUE if session was initiated + */ +gboolean mxit_media_initiate(PurpleAccount *account, const char *who, PurpleMediaSessionType type) +{ + purple_debug_info(MXIT_PLUGIN_ID, "mxit_media_initiate: buddy '%s'\n", who); + + return FALSE; +} + +#else + +/* + * Voice and Video not supported. + */ + +gboolean mxit_audio_enabled(void) +{ + return FALSE; +} + +gboolean mxit_video_enabled(void) +{ + return FALSE; +} + +PurpleMediaCaps mxit_media_caps(PurpleAccount *account, const char *who) +{ + return PURPLE_MEDIA_CAPS_NONE; +} + +gboolean mxit_media_initiate(PurpleAccount *account, const char *who, PurpleMediaSessionType type) +{ + return FALSE; +} + +#endif + diff -r db330f8c1a8c -r 4f414608eaad libpurple/protocols/mxit/voicevideo.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/mxit/voicevideo.h Sat Mar 05 17:18:10 2011 +0000 @@ -0,0 +1,41 @@ +/* + * MXit Protocol libPurple Plugin + * + * -- voice & video -- + * + * Andrew Victor + * + * (C) Copyright 2010 MXit Lifestyle (Pty) Ltd. + * + * + * 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 + */ + +#ifndef _MXIT_VOICEVICEO_H_ +#define _MXIT_VOICEVIDEO_H_ + +#include "media.h" + + +#undef MXIT_DEV_VV + + +gboolean mxit_audio_enabled(void); +gboolean mxit_video_enabled(void); +PurpleMediaCaps mxit_media_caps(PurpleAccount* account, const char* who); +gboolean mxit_media_initiate(PurpleAccount* account, const char* who, PurpleMediaSessionType type); + + +#endif /* _MXIT_VOICEVIDEO_H_ */