--- a/libpurple/protocols/msn/p2p.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/msn/p2p.c Mon Mar 07 06:43:26 2011 +0000
@@ -23,72 +23,139 @@
+msn_p2p_info_new(MsnP2PVersion version) - return g_new0(MsnP2PInfo, 1);
+ MsnP2PInfo *info = g_new0(MsnP2PInfo, 1); + info->version = version; + case MSN_P2P_VERSION_ONE: + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", version); msn_p2p_info_dup(MsnP2PInfo *info)
MsnP2PInfo *new_info = g_new0(MsnP2PInfo, 1);
+ new_info->version = info->version; + switch (info->version) { + case MSN_P2P_VERSION_ONE: + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_free(MsnP2PInfo *info)
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_header_from_wire(MsnP2PInfo *info, const char *wire)
- header = &info->header;
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: { + MsnP2PHeader *header = &info->header.v1; - header->session_id = msn_pop32le(wire);
- header->id = msn_pop32le(wire);
- header->offset = msn_pop64le(wire);
- header->total_size = msn_pop64le(wire);
- header->length = msn_pop32le(wire);
- header->flags = msn_pop32le(wire);
- header->ack_id = msn_pop32le(wire);
- header->ack_sub_id = msn_pop32le(wire);
- header->ack_size = msn_pop64le(wire);
+ header->session_id = msn_pop32le(wire); + header->id = msn_pop32le(wire); + header->offset = msn_pop64le(wire); + header->total_size = msn_pop64le(wire); + header->length = msn_pop32le(wire); + header->flags = msn_pop32le(wire); + header->ack_id = msn_pop32le(wire); + header->ack_sub_id = msn_pop32le(wire); + header->ack_size = msn_pop64le(wire); - return P2P_PACKET_HEADER_SIZE;
+ len = P2P_PACKET_HEADER_SIZE; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_header_to_wire(MsnP2PInfo *info, size_t *len)
- header = &info->header;
- tmp = wire = g_new(char, P2P_PACKET_HEADER_SIZE);
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: { + MsnP2PHeader *header = &info->header.v1; + tmp = wire = g_new(char, P2P_PACKET_HEADER_SIZE); + msn_push32le(tmp, header->session_id); + msn_push32le(tmp, header->id); + msn_push64le(tmp, header->offset); + msn_push64le(tmp, header->total_size); + msn_push32le(tmp, header->length); + msn_push32le(tmp, header->flags); + msn_push32le(tmp, header->ack_id); + msn_push32le(tmp, header->ack_sub_id); + msn_push64le(tmp, header->ack_size); - msn_push32le(tmp, header->session_id);
- msn_push32le(tmp, header->id);
- msn_push64le(tmp, header->offset);
- msn_push64le(tmp, header->total_size);
- msn_push32le(tmp, header->length);
- msn_push32le(tmp, header->flags);
- msn_push32le(tmp, header->ack_id);
- msn_push32le(tmp, header->ack_sub_id);
- msn_push64le(tmp, header->ack_size);
+ *len = P2P_PACKET_HEADER_SIZE;
- *len = P2P_PACKET_HEADER_SIZE;
+ case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); @@ -127,15 +194,30 @@
msn_p2p_info_to_string(MsnP2PInfo *info, GString *str)
- g_string_append_printf(str, "Session ID: %u\r\n", info->header.session_id);
- g_string_append_printf(str, "ID: %u\r\n", info->header.id);
- g_string_append_printf(str, "Offset: %" G_GUINT64_FORMAT "\r\n", info->header.offset);
- g_string_append_printf(str, "Total size: %" G_GUINT64_FORMAT "\r\n", info->header.total_size);
- g_string_append_printf(str, "Length: %u\r\n", info->header.length);
- g_string_append_printf(str, "Flags: 0x%x\r\n", info->header.flags);
- g_string_append_printf(str, "ACK ID: %u\r\n", info->header.ack_id);
- g_string_append_printf(str, "SUB ID: %u\r\n", info->header.ack_sub_id);
- g_string_append_printf(str, "ACK Size: %" G_GUINT64_FORMAT "\r\n", info->header.ack_size);
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: { + MsnP2PHeader *header = &info->header.v1; + g_string_append_printf(str, "Session ID: %u\r\n", header->session_id); + g_string_append_printf(str, "ID: %u\r\n", header->id); + g_string_append_printf(str, "Offset: %" G_GUINT64_FORMAT "\r\n", header->offset); + g_string_append_printf(str, "Total size: %" G_GUINT64_FORMAT "\r\n", header->total_size); + g_string_append_printf(str, "Length: %u\r\n", header->length); + g_string_append_printf(str, "Flags: 0x%x\r\n", header->flags); + g_string_append_printf(str, "ACK ID: %u\r\n", header->ack_id); + g_string_append_printf(str, "SUB ID: %u\r\n", header->ack_sub_id); + g_string_append_printf(str, "ACK Size: %" G_GUINT64_FORMAT "\r\n", header->ack_size); + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); g_string_append_printf(str, "Footer: 0x%08X\r\n", info->footer.value);
@@ -150,67 +232,232 @@
msn_p2p_info_is_valid(MsnP2PInfo *info)
- return info->header.total_size >= info->header.length;
+ gboolean valid = FALSE; + switch (info->version) { + case MSN_P2P_VERSION_ONE: + valid = info->header.v1.total_size >= info->header.v1.length; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_is_final(MsnP2PInfo *info)
- return info->header.offset + info->header.length >= info->header.total_size;
+ gboolean final = FALSE; + switch (info->version) { + case MSN_P2P_VERSION_ONE: + final = info->header.v1.offset + info->header.v1.length >= info->header.v1.total_size; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_get_session_id(MsnP2PInfo *info)
- return info->header.session_id;
+ guint32 session_id = 0; + switch (info->version) { + case MSN_P2P_VERSION_ONE: + session_id = info->header.v1.session_id; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_get_id(MsnP2PInfo *info)
- return info->header.id;
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + id = info->header.v1.id; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_get_offset(MsnP2PInfo *info)
- return info->header.offset;
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + offset = info->header.v1.offset; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_get_total_size(MsnP2PInfo *info)
- return info->header.total_size;
+ guint64 total_size = 0; + switch (info->version) { + case MSN_P2P_VERSION_ONE: + total_size = info->header.v1.total_size; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_get_length(MsnP2PInfo *info)
- return info->header.length;
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + length = info->header.v1.length; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_get_flags(MsnP2PInfo *info)
- return info->header.flags;
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + flags = info->header.v1.flags; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_get_ack_id(MsnP2PInfo *info)
- return info->header.ack_id;
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + ack_id = info->header.v1.ack_id; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_get_ack_sub_id(MsnP2PInfo *info)
- return info->header.ack_sub_id;
+ guint32 ack_sub_id = 0; + switch (info->version) { + case MSN_P2P_VERSION_ONE: + ack_sub_id = info->header.v1.ack_sub_id; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_get_ack_size(MsnP2PInfo *info)
- return info->header.ack_size;
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + ack_size = info->header.v1.ack_size; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); @@ -222,55 +469,156 @@
msn_p2p_info_set_session_id(MsnP2PInfo *info, guint32 session_id)
- info->header.session_id = session_id;
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.session_id = session_id; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_set_id(MsnP2PInfo *info, guint32 id)
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.id = id; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_set_offset(MsnP2PInfo *info, guint64 offset)
- info->header.offset = offset;
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.offset = offset; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_set_total_size(MsnP2PInfo *info, guint64 total_size)
- info->header.total_size = total_size;
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.total_size = total_size; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_set_length(MsnP2PInfo *info, guint32 length)
- info->header.length = length;
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.length = length; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_set_flags(MsnP2PInfo *info, guint32 flags)
- info->header.flags = flags;
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.flags = flags; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_set_ack_id(MsnP2PInfo *info, guint32 ack_id)
- info->header.ack_id = ack_id;
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.ack_id = ack_id; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_set_ack_sub_id(MsnP2PInfo *info, guint32 ack_sub_id)
- info->header.ack_sub_id = ack_sub_id;
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.ack_sub_id = ack_sub_id; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); msn_p2p_info_set_ack_size(MsnP2PInfo *info, guint64 ack_size)
- info->header.ack_size = ack_size;
+ switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.ack_size = ack_size; + case MSN_P2P_VERSION_TWO: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); --- a/libpurple/protocols/mxit/formcmds.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/formcmds.c Mon Mar 07 06:43:26 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) */ @@ -87,7 +91,7 @@
- /* 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 */
@@ -149,8 +153,16 @@
else if (strcmp(type, "selc") == 0) /* select contact */
return MXIT_CMD_SELECTCONTACT;
- else if (strcmp(op, "img") == 0)
+ else if (strcmp(op, "img") == 0) /* inline 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 */ @@ -333,7 +345,7 @@
g_string_append_printf(msg, "%s%s>", MXIT_II_TAG, iireq->url);
- /* 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 */
--- a/libpurple/protocols/mxit/login.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/login.c Mon Mar 07 06:43:26 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(); @@ -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 @@
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." ); g_strlcpy( profile->nickname, str, sizeof( profile->nickname ) );
@@ -546,8 +547,8 @@
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 );
--- a/libpurple/protocols/mxit/mxit.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/mxit.c Mon Mar 07 06:43:26 2011 +0000
@@ -37,6 +37,7 @@
@@ -524,7 +525,7 @@
- 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 )
+ 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 ); + purple_debug_warning( MXIT_PLUGIN_ID, "mxit_get_info: unable to find the buddy '%s'\n", who ); + contact = purple_buddy_get_protocol_data( buddy ); + /* 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." ) ); /* send profile request */
mxit_send_extprofile_request( session, who, ARRAY_SIZE( profilelist ), profilelist );
@@ -588,7 +607,33 @@
/*------------------------------------------------------------------------
+ * 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 ) + struct contact* contact; + 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 ); + /* send a new invite */ + mxit_send_invite( session, contact->username, contact->alias, contact->groupname ); +/*------------------------------------------------------------------------ * @param node The entry in the buddy list.
@@ -597,6 +642,7 @@
if ( !PURPLE_BLIST_NODE_IS_BUDDY( node ) )
@@ -606,6 +652,12 @@
+ 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); @@ -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) */
--- a/libpurple/protocols/mxit/mxit.h Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/mxit.h Mon Mar 07 06:43:26 2011 +0000
@@ -63,13 +63,12 @@
#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 <libpurple@mxit.com>"
#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_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 */
+ char voip_server[HOST_NAME_MAX]; /* voice/video server */ struct login_data* logindata;
char* encpwd; /* encrypted password */
@@ -159,7 +160,7 @@
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) */
--- a/libpurple/protocols/mxit/profile.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/profile.c Mon Mar 07 06:43:26 2011 +0000
@@ -108,10 +108,10 @@
static const char* datetime( gint64 msecs )
- time_t secs = msecs / 1000;
+ time_t secs = msecs / 1000;
- localtime_r( &secs, &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 );
--- a/libpurple/protocols/mxit/protocol.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/protocol.c Mon Mar 07 06:43:26 2011 +0000
@@ -37,6 +37,7 @@
@@ -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 ) + 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 */
+ 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 );
- /* 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 */
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." ) );
+ * 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; + purple_timeout_add( delay, mxit_manage_queue_fast, session ); + /* 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 ); /*------------------------------------------------------------------------
+ * 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 ); +/*------------------------------------------------------------------------ * 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;
- time_t now = time( NULL );
+ gint64 now = mxit_now_milli();
if ( !( session->flags & MXIT_FLAG_LOGGEDIN ) ) {
/* we only poll if we are actually logged in */
@@ -579,7 +635,7 @@
- session->http_last_poll = time( NULL );
+ session->http_last_poll = mxit_now_milli(); mxit_send_poll( session );
@@ -638,21 +694,36 @@
char data[CP_MAX_PACKET];
+ 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 )
- char data[CP_MAX_PACKET];
+ char data[CP_MAX_PACKET]; + 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 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]; + /* 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 ); + 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]; + /* 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 ); + 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 */
- 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 ); purple_debug_error( MXIT_PLUGIN_ID, "Error creating get avatar chunk (%i)\n", size );
@@ -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 )
purple_debug_info( MXIT_PLUGIN_ID, "mxit_parse_cmd_presence (%i recs)\n", rcount );
for ( i = 0; i < rcount; i++ ) {
+ struct record* rec = records[i]; 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
--- a/libpurple/protocols/mxit/protocol.h Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/protocol.h Mon Mar 07 06:43:26 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
-#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 @@
#define CP_PROF_DOBLOCKED 0x40 /* date-of-birth cannot be changed */
+#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) */
@@ -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_ */
--- a/libpurple/protocols/mxit/roster.h Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/roster.h Mon Mar 07 06:43:26 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 #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 );
--- a/pidgin/gtkdocklet-gtk.c Mon Mar 07 06:42:57 2011 +0000
+++ b/pidgin/gtkdocklet-gtk.c Mon Mar 07 06:43:26 2011 +0000
@@ -47,19 +47,37 @@
docklet_gtk_embed_timeout_cb(gpointer data)
- /* The docklet was not embedded within the timeout.
- * Remove it as a visibility manager, but leave the plugin
- * loaded so that it can embed automatically if/when a notification
- * area becomes available.
- purple_debug_info("docklet", "failed to embed within timeout\n");
- pidgin_docklet_remove();
- purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", FALSE);
+#if !GTK_CHECK_VERSION(2,12,0) + if (gtk_status_icon_is_embedded(docklet)) { + /* Older GTK+ (<2.12) don't implement the embedded signal, but the + information is still accessable through the above function. */ + purple_debug_info("docklet", "embedded\n"); + pidgin_docklet_embedded(); + purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", TRUE); + /* The docklet was not embedded within the timeout. + * Remove it as a visibility manager, but leave the plugin + * loaded so that it can embed automatically if/when a notification + * area becomes available. + purple_debug_info("docklet", "failed to embed within timeout\n"); + pidgin_docklet_remove(); + purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", FALSE); +#if GTK_CHECK_VERSION(2,12,0) +#if GTK_CHECK_VERSION(2,12,0) docklet_gtk_embedded_cb(GtkWidget *widget, gpointer data)
@@ -82,6 +100,7 @@
docklet_gtk_destroyed_cb(GtkWidget *widget, gpointer data)
@@ -206,7 +225,9 @@
g_signal_connect(G_OBJECT(docklet), "activate", G_CALLBACK(docklet_gtk_status_activated_cb), NULL);
g_signal_connect(G_OBJECT(docklet), "popup-menu", G_CALLBACK(docklet_gtk_status_clicked_cb), NULL);
+#if GTK_CHECK_VERSION(2,12,0) g_signal_connect(G_OBJECT(docklet), "notify::embedded", G_CALLBACK(docklet_gtk_embedded_cb), NULL);
g_signal_connect(G_OBJECT(docklet), "destroy", G_CALLBACK(docklet_gtk_destroyed_cb), NULL);
gtk_status_icon_set_visible(docklet, TRUE);
@@ -226,11 +247,15 @@
pidgin_docklet_embedded();
+#if GTK_CHECK_VERSION(2,12,0) if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded")) {
embed_timeout = purple_timeout_add_seconds(LONG_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
embed_timeout = purple_timeout_add_seconds(SHORT_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
+ embed_timeout = purple_timeout_add_seconds(SHORT_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL); purple_debug_info("docklet", "GTK+ created\n");
--- a/po/de.po Mon Mar 07 06:42:57 2011 +0000
+++ b/po/de.po Mon Mar 07 06:43:26 2011 +0000
@@ -11,8 +11,8 @@
"Project-Id-Version: de\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-02-06 14:22+0100\n"
-"PO-Revision-Date: 2011-02-06 14:22+0100\n"
+"POT-Creation-Date: 2011-03-06 12:25+0100\n" +"PO-Revision-Date: 2011-03-06 12:25+0100\n" "Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n"
"Language-Team: German <de@li.org>\n"
@@ -3239,9 +3239,7 @@
-#. purple_notify_user_info_add_pair( info, _( "Hidden Number" ), profile->hidden ? _( "Yes" ) : _( "No" ) );
-#. purple_notify_user_info_add_pair( info, _( "Title" ), profile->title );
@@ -4010,7 +4008,6 @@
-#. purple_notify_user_info_add_pair( info, _( "Email" ), profile->email );
@@ -6148,6 +6145,9 @@
+msgid "The Display Name you entered is too short." +msgstr "Der eingegebene Anzeigename ist zu kurz." msgid "The PIN you entered has an invalid length [7-10]."
msgstr "Die eingegebene PIN hat eine ungültige Länge [7-10]."
@@ -6227,33 +6227,6 @@
msgid "Retrieving User Information..."
msgstr "Abrufen der Benutzerinformationen..."
-msgstr "Lade das Menü..."
-msgstr "Status-Nachricht"
-msgid "Rejection Message"
-msgstr "Ablehnungsnachricht"
-msgstr "Versteckte Nummer"
-msgstr "Ihre MXit-ID..."
-#. Configuration options
-#. WAP server (reference: "libpurple/accountopt.h")
-msgid "Connect via HTTP"
-msgstr "Über HTTP verbinden"
-msgid "Enable splash-screen popup"
-msgstr "Startbildschirm-Popup aktivieren"
msgid "You have been kicked from this MultiMX."
msgstr "Sie wurden von MultiMX hinausgeworfen."
@@ -6268,6 +6241,43 @@
msgstr "Sie haben eingeladen"
+msgstr "Lade das Menü..." +msgstr "Status-Nachricht" +msgid "Rejection Message" +msgstr "Ablehnungsnachricht" +msgstr "Versteckte Nummer" +msgid "No profile available" +msgstr "Kein Profil verfügbar" +msgid "This contact does not have a profile." +msgstr "Dieser Kontakt hat kein Profil." +msgstr "Ihre MXit-ID..." +#. contact is in Deleted, Rejected or None state +msgstr "Erneut einladen" +#. Configuration options +#. WAP server (reference: "libpurple/accountopt.h") +msgid "Connect via HTTP" +msgstr "Über HTTP verbinden" +msgid "Enable splash-screen popup" +msgstr "Startbildschirm-Popup aktivieren" @@ -7571,6 +7581,14 @@
msgid "You have been disconnected from chat room %s."
msgstr "Die Verbindung zum Raum %s wurde unterbrochen."
+msgid "The new formatting is invalid." +msgstr "Die neue Formatierung ist ungültig." +msgid "Username formatting can change only capitalization and whitespace." +"Benutzernamen-Formatierung kann nur die Groß-/Kleinschreibung und " msgstr "Pop-Up Nachricht"
@@ -7846,14 +7864,6 @@
msgid "ICQ Privacy Options"
msgstr "ICQ Privatsphärenoptionen"
-msgid "The new formatting is invalid."
-msgstr "Die neue Formatierung ist ungültig."
-msgid "Username formatting can change only capitalization and whitespace."
-"Benutzernamen-Formatierung kann nur die Groß-/Kleinschreibung und "
msgid "Change Address To:"
msgstr "Ändere die Adresse zu:"
@@ -7961,75 +7971,6 @@
"ist notwendig für IM-Bilder. Da Ihre IP-Adresse verwendet wird, kann dies "
"eine Verletzung der Privatsphäre bedeuten."
-msgstr "Ungültiger SNAC"
-msgid "Server rate limit exceeded"
-msgstr "Server-Datenrate überschritten"
-msgid "Client rate limit exceeded"
-msgstr "Client-Datenrate überschritten"
-msgid "Service unavailable"
-msgstr "Dienst nicht verfügbar"
-msgid "Service not defined"
-msgstr "Dienst nicht definiert"
-msgid "Not supported by host"
-msgstr "Nicht unterstützt vom Host"
-msgid "Not supported by client"
-msgstr "Nicht unterstützt vom Client"
-msgid "Refused by client"
-msgstr "Abgelehnt vom Client"
-msgstr "Antwort zu groß"
-msgstr "Antworten verloren"
-msgstr "Anfrage verweigert"
-msgid "Busted SNAC payload"
-msgstr "Ruinierte SNAC-Daten"
-msgid "Insufficient rights"
-msgstr "Ungenügende Rechte"
-msgid "In local permit/deny"
-msgstr "In lokaler erlaubt/verboten-Liste"
-msgid "Warning level too high (sender)"
-msgstr "Warnstufe zu hoch (Absender)"
-msgid "Warning level too high (receiver)"
-msgstr "Warnstufe zu hoch (Empfänger)"
-msgid "User temporarily unavailable"
-msgstr "Benutzer ist temporär nicht verfügbar"
-msgstr "Keine Übereinstimmung"
-msgid "Request ambiguous"
-msgstr "Anfrage ist nicht eindeutig"
-msgstr "Warteschlange voll"
-msgid "Not while on AOL"
-msgstr "Nicht solange bei AOL angemeldet"
@@ -8148,6 +8089,75 @@
+msgstr "Ungültiger SNAC" +msgid "Server rate limit exceeded" +msgstr "Server-Datenrate überschritten" +msgid "Client rate limit exceeded" +msgstr "Client-Datenrate überschritten" +msgid "Service unavailable" +msgstr "Dienst nicht verfügbar" +msgid "Service not defined" +msgstr "Dienst nicht definiert" +msgid "Not supported by host" +msgstr "Nicht unterstützt vom Host" +msgid "Not supported by client" +msgstr "Nicht unterstützt vom Client" +msgid "Refused by client" +msgstr "Abgelehnt vom Client" +msgstr "Antwort zu groß" +msgstr "Antworten verloren" +msgstr "Anfrage verweigert" +msgid "Busted SNAC payload" +msgstr "Ruinierte SNAC-Daten" +msgid "Insufficient rights" +msgstr "Ungenügende Rechte" +msgid "In local permit/deny" +msgstr "In lokaler erlaubt/verboten-Liste" +msgid "Warning level too high (sender)" +msgstr "Warnstufe zu hoch (Absender)" +msgid "Warning level too high (receiver)" +msgstr "Warnstufe zu hoch (Empfänger)" +msgid "User temporarily unavailable" +msgstr "Benutzer ist temporär nicht verfügbar" +msgstr "Keine Übereinstimmung" +msgid "Request ambiguous" +msgstr "Anfrage ist nicht eindeutig" +msgstr "Warteschlange voll" +msgid "Not while on AOL" +msgstr "Nicht solange bei AOL angemeldet" #. Translators: This string is a menu option that, if selected, will cause
#. you to appear online to the chosen user even when your status is set to