From 04a927cb733e2c47424569550a2faeb108094636 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 8 Jun 2010 00:04:58 +0100 Subject: Fixing some memory leakage. --- protocols/jabber/jabber.c | 2 ++ protocols/jabber/jabber.h | 1 + protocols/jabber/jabber_util.c | 26 ++++++++++++++++++++++++++ protocols/twitter/twitter.c | 2 ++ 4 files changed, 31 insertions(+) (limited to 'protocols') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 86320ada..8bb44691 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -285,6 +285,8 @@ static void jabber_logout( struct im_connection *ic ) if( jd->node_cache ) g_hash_table_destroy( jd->node_cache ); + jabber_buddy_remove_all( ic ); + xt_free( jd->xt ); g_free( jd->away_message ); diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 40cf3957..3f4144b8 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -229,6 +229,7 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid, g struct jabber_buddy *jabber_buddy_by_ext_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags ); int jabber_buddy_remove( struct im_connection *ic, char *full_jid ); int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ); +void jabber_buddy_remove_all( struct im_connection *ic ); time_t jabber_get_timestamp( struct xt_node *xt ); struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns ); void jabber_error_free( struct jabber_error *err ); diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index b8b625f7..651b7068 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -664,6 +664,32 @@ int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ) } } +static gboolean jabber_buddy_remove_all_cb( gpointer key, gpointer value, gpointer data ) +{ + struct jabber_buddy *bud, *next; + + bud = value; + while( bud ) + { + next = bud->next; + g_free( bud->ext_jid ); + g_free( bud->full_jid ); + g_free( bud->away_message ); + g_free( bud ); + bud = next; + } + + return TRUE; +} + +void jabber_buddy_remove_all( struct im_connection *ic ) +{ + struct jabber_data *jd = ic->proto_data; + + g_hash_table_foreach_remove( jd->buddies, jabber_buddy_remove_all_cb, NULL ); + g_hash_table_destroy( jd->buddies ); +} + time_t jabber_get_timestamp( struct xt_node *xt ) { struct xt_node *c; diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index a5fc68ab..db893e17 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -235,6 +235,8 @@ static void twitter_logout( struct im_connection *ic ) if( td ) { oauth_info_free( td->oauth_info ); + g_free( td->url_host ); + g_free( td->url_path ); g_free( td->pass ); g_free( td ); } -- cgit v1.2.3 From 4eef27179a98cc1dd478ee9ccd05f30e36ce43bc Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 23 Jun 2010 01:13:46 +0100 Subject: Added user_agent setting to Jabber accounts so people can get around ridiculous user agent restrictions on certain Jabber servers. Obviously this is pretty simple to detect and break, but it works at least with Openfire. --- protocols/jabber/iq.c | 4 ++-- protocols/jabber/jabber.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index 95b21e1e..68777b0b 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -64,7 +64,7 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) /* Of course this is a very essential query to support. ;-) */ if( strcmp( s, XMLNS_VERSION ) == 0 ) { - xt_add_child( reply, xt_new_node( "name", "BitlBee", NULL ) ); + xt_add_child( reply, xt_new_node( "name", set_getstr( &ic->acc->set, "user_agent" ), NULL ) ); xt_add_child( reply, xt_new_node( "version", BITLBEE_VERSION, NULL ) ); xt_add_child( reply, xt_new_node( "os", ARCH, NULL ) ); } @@ -104,7 +104,7 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) c = xt_new_node( "identity", NULL, NULL ); xt_add_attr( c, "category", "client" ); xt_add_attr( c, "type", "pc" ); - xt_add_attr( c, "name", "BitlBee" ); + xt_add_attr( c, "name", set_getstr( &ic->acc->set, "user_agent" ) ); xt_add_child( reply, c ); for( f = features; *f; f ++ ) diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 8bb44691..48b8ac43 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -79,6 +79,8 @@ static void jabber_init( account_t *acc ) s = set_add( &acc->set, "tls", "try", set_eval_tls, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; + s = set_add( &acc->set, "user_agent", "BitlBee", NULL, acc ); + s = set_add( &acc->set, "xmlconsole", "false", set_eval_bool, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; -- cgit v1.2.3 From 90ba4161e5c24306233bc4627d1cde39a54006cf Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 23 Jun 2010 23:37:24 +0100 Subject: Fixed a NULL pointer dereference in the Jabber module. --- protocols/jabber/message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/jabber/message.c b/protocols/jabber/message.c index e8161029..fa915bd8 100644 --- a/protocols/jabber/message.c +++ b/protocols/jabber/message.c @@ -54,7 +54,7 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) char *ns = xt_find_attr( c, "xmlns" ), *room; struct xt_node *inv, *reason; - if( strcmp( ns, XMLNS_MUC_USER ) == 0 && + if( ns && strcmp( ns, XMLNS_MUC_USER ) == 0 && ( inv = xt_find_node( c->children, "invite" ) ) ) { room = from; -- cgit v1.2.3 From d6aa6dd53c3352305508ffbf62d26f59dd19b777 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 24 Jun 2010 01:43:15 +0100 Subject: Load the whole Twitter contact list at login time if mode=chat/many, instead of adding contacts as they post tweets. Also in mode=chat, populate the channel *before* adding the user to it, avoiding a flood of joins. --- protocols/twitter/twitter.c | 33 ++++++++++++++++++--------- protocols/twitter/twitter.h | 8 +++++++ protocols/twitter/twitter_lib.c | 49 ++++++++++++++++++++++++++++------------- 3 files changed, 64 insertions(+), 26 deletions(-) (limited to 'protocols') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index db893e17..ca57e51e 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -39,11 +39,6 @@ gboolean twitter_main_loop(gpointer data, gint fd, b_input_condition cond) if (!g_slist_find( twitter_connections, ic )) return 0; - // If the user uses multiple private message windows we need to get the - // users buddies. - if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "many") == 0) - twitter_get_statuses_friends(ic, -1); - // Do stuff.. twitter_get_home_timeline(ic, -1); @@ -55,7 +50,7 @@ static void twitter_main_loop_start( struct im_connection *ic ) { struct twitter_data *td = ic->proto_data; - imcb_log( ic, "Connecting to Twitter" ); + imcb_log( ic, "Getting initial statuses" ); // Run this once. After this queue the main loop function. twitter_main_loop(ic, -1, 0); @@ -65,6 +60,23 @@ static void twitter_main_loop_start( struct im_connection *ic ) td->main_loop_id = b_timeout_add(60000, twitter_main_loop, ic); } +static void twitter_oauth_start( struct im_connection *ic ); + +void twitter_login_finish( struct im_connection *ic ) +{ + struct twitter_data *td = ic->proto_data; + + if( set_getbool( &ic->acc->set, "oauth" ) && !td->oauth_info ) + twitter_oauth_start( ic ); + else if( g_strcasecmp( set_getstr( &ic->acc->set, "mode" ), "one" ) != 0 && + !( td->flags & TWITTER_HAVE_FRIENDS ) ) + { + imcb_log( ic, "Getting contact list" ); + twitter_get_statuses_friends( ic, -1 ); + } + else + twitter_main_loop_start( ic ); +} static const struct oauth_service twitter_oauth = { @@ -127,7 +139,7 @@ static gboolean twitter_oauth_callback( struct oauth_info *info ) g_free( ic->acc->pass ); ic->acc->pass = oauth_to_string( info ); - twitter_main_loop_start( ic ); + twitter_login_finish( ic ); } return TRUE; @@ -210,10 +222,9 @@ static void twitter_login( account_t *acc ) imcb_add_buddy( ic, name, NULL ); imcb_buddy_status( ic, name, OPT_LOGGED_IN, NULL, NULL ); - if( td->oauth_info || !set_getbool( &acc->set, "oauth" ) ) - twitter_main_loop_start( ic ); - else - twitter_oauth_start( ic ); + imcb_log( ic, "Connecting" ); + + twitter_login_finish( ic ); } /** diff --git a/protocols/twitter/twitter.h b/protocols/twitter/twitter.h index 614919f9..e61d32be 100644 --- a/protocols/twitter/twitter.h +++ b/protocols/twitter/twitter.h @@ -32,6 +32,11 @@ #define debug( text... ) #endif +typedef enum +{ + TWITTER_HAVE_FRIENDS = 1, +} twitter_flags_t; + struct twitter_data { char* user; @@ -41,6 +46,7 @@ struct twitter_data gint main_loop_id; struct groupchat *home_timeline_gc; gint http_fails; + twitter_flags_t flags; gboolean url_ssl; int url_port; @@ -55,4 +61,6 @@ struct twitter_data */ GSList *twitter_connections; +void twitter_login_finish( struct im_connection *ic ); + #endif //_TWITTER_H diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index 585bdd43..fb7a6af9 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -58,6 +58,8 @@ struct twitter_xml_status { guint64 id; }; +static void twitter_groupchat_init(struct im_connection *ic); + /** * Frees a twitter_xml_user struct. */ @@ -432,6 +434,19 @@ void twitter_get_home_timeline(struct im_connection *ic, int next_cursor) } } +static void twitter_groupchat_init(struct im_connection *ic) +{ + char *name_hint; + struct groupchat *gc; + struct twitter_data *td = ic->proto_data; + + td->home_timeline_gc = gc = imcb_chat_new( ic, "home/timeline" ); + + name_hint = g_strdup_printf( "Twitter_%s", ic->acc->user ); + imcb_chat_name_hint( gc, name_hint ); + g_free( name_hint ); +} + /** * Function that is called to see the statuses in a groupchat window. */ @@ -444,18 +459,11 @@ static void twitter_groupchat(struct im_connection *ic, GSList *list) // Create a new groupchat if it does not exsist. if (!td->home_timeline_gc) - { - char *name_hint = g_strdup_printf( "Twitter_%s", ic->acc->user ); - td->home_timeline_gc = gc = imcb_chat_new( ic, "home/timeline" ); - imcb_chat_name_hint( gc, name_hint ); - g_free( name_hint ); - // Add the current user to the chat... + twitter_groupchat_init(ic); + + gc = td->home_timeline_gc; + if (!gc->joined) imcb_chat_add_buddy( gc, ic->acc->user ); - } - else - { - gc = td->home_timeline_gc; - } for ( l = list; l ; l = g_slist_next(l) ) { @@ -603,15 +611,23 @@ static void twitter_http_get_statuses_friends(struct http_request *req) td = ic->proto_data; // Check if the HTTP request went well. - if (req->status_code != 200) { + if (req->status_code == 401) + { + imcb_error( ic, "Authentication failure" ); + imc_logout( ic, FALSE ); + return; + } else if (req->status_code != 200) { // It didn't go well, output the error and return. - if (++td->http_fails >= 5) - imcb_error(ic, "Could not retrieve " TWITTER_SHOW_FRIENDS_URL ": %s", twitter_parse_error(req)); - + imcb_error(ic, "Could not retrieve " TWITTER_SHOW_FRIENDS_URL ": %s", twitter_parse_error(req)); + imc_logout( ic, TRUE ); return; } else { td->http_fails = 0; } + + if( !td->home_timeline_gc && + g_strcasecmp( set_getstr( &ic->acc->set, "mode" ), "chat" ) == 0 ) + twitter_groupchat_init( ic ); txl = g_new0(struct twitter_xml_list, 1); txl->list = NULL; @@ -638,6 +654,9 @@ static void twitter_http_get_statuses_friends(struct http_request *req) // Free the structure. txl_free(txl); g_free(txl); + + td->flags |= TWITTER_HAVE_FRIENDS; + twitter_login_finish(ic); } /** -- cgit v1.2.3 From 38ff846b14f1d1f80983a0818b9bcf60581a2a34 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 24 Jun 2010 02:06:49 +0100 Subject: Fixed an access-after-free() bug in the Jabber keepalive + cache cleanup code. --- protocols/jabber/jabber.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 48b8ac43..75351d0d 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -473,7 +473,8 @@ static void jabber_chat_invite_( struct groupchat *c, char *who, char *msg ) static void jabber_keepalive( struct im_connection *ic ) { /* Just any whitespace character is enough as a keepalive for XMPP sessions. */ - jabber_write( ic, "\n", 1 ); + if( !jabber_write( ic, "\n", 1 ) ) + return; /* This runs the garbage collection every minute, which means every packet is in the cache for about a minute (which should be enough AFAIK). */ -- cgit v1.2.3 From 051372c0219f067bb4b116bd06d482420b20e3c8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 24 Jun 2010 10:27:34 +0100 Subject: Don't create multiple main loops if the user follows >100 people. --- protocols/twitter/twitter_lib.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'protocols') diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index fb7a6af9..36422a5e 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -649,14 +649,18 @@ static void twitter_http_get_statuses_friends(struct http_request *req) // if the next_cursor is set to something bigger then 0 there are more friends to gather. if (txl->next_cursor > 0) + { twitter_get_statuses_friends(ic, txl->next_cursor); - + } + else + { + td->flags |= TWITTER_HAVE_FRIENDS; + twitter_login_finish(ic); + } + // Free the structure. txl_free(txl); g_free(txl); - - td->flags |= TWITTER_HAVE_FRIENDS; - twitter_login_finish(ic); } /** -- cgit v1.2.3 From 64f8c425da20554e6909d969b8748076825ef601 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 30 Jun 2010 00:06:07 +0100 Subject: Strip whitespace in Twitter OAuth PIN responses. --- protocols/twitter/twitter.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index ca57e51e..2e3ab634 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -268,7 +268,14 @@ static int twitter_buddy_msg( struct im_connection *ic, char *who, char *message if( set_getbool( &ic->acc->set, "oauth" ) && td->oauth_info && td->oauth_info->token == NULL ) { - if( !oauth_access_token( message, td->oauth_info ) ) + char pin[strlen(message)+1], *s; + + strcpy( pin, message ); + for( s = pin + sizeof( pin ) - 2; s > pin && isspace( *s ); s -- ) + *s = '\0'; + for( s = pin; *s && isspace( *s ); s ++ ) {} + + if( !oauth_access_token( s, td->oauth_info ) ) { imcb_error( ic, "OAuth error: %s", "Failed to send access token request" ); imc_logout( ic, TRUE ); -- cgit v1.2.3 From bd64716b5687e6652ada7112a43ff3455e32231e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 30 Jun 2010 00:30:05 +0100 Subject: next_cursor is a 64-bit integer. Make it so. This should fix issues with getting contact lists containing >100 people. I'm still not getting a full list but even Twitter claims I'm at the end of the list. Will investigate later. --- protocols/twitter/twitter_lib.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'protocols') diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index 36422a5e..f8efb711 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -41,7 +41,7 @@ struct twitter_xml_list { int type; - int next_cursor; + int64_t next_cursor; GSList *list; gpointer data; }; @@ -170,8 +170,12 @@ void twitter_get_friends_ids(struct im_connection *ic, int next_cursor) */ static xt_status twitter_xt_next_cursor( struct xt_node *node, struct twitter_xml_list *txl ) { - // Do something with the cursor. - txl->next_cursor = node->text != NULL ? atoi(node->text) : -1; + char *end = NULL; + + if( node->text ) + txl->next_cursor = g_ascii_strtoll( node->text, &end, 10 ); + if( end == NULL ) + txl->next_cursor = -1; return XT_HANDLED; } -- cgit v1.2.3 From 8203da9d2f792252d2144e5e9063391a3ceebfe9 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 30 Jun 2010 23:52:27 +0100 Subject: D'oh. Of course the getter functions should also treat next_cursor as a 64-bit integer. This code now successfully fetches lists with up to ~900 items. (Since this takes quite long, maybe there should be an upper limit.) --- protocols/twitter/twitter_lib.c | 14 +++++++------- protocols/twitter/twitter_lib.h | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'protocols') diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index f8efb711..d1b65c26 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -41,7 +41,7 @@ struct twitter_xml_list { int type; - int64_t next_cursor; + gint64 next_cursor; GSList *list; gpointer data; }; @@ -154,12 +154,12 @@ static void twitter_http_get_friends_ids(struct http_request *req); /** * Get the friends ids. */ -void twitter_get_friends_ids(struct im_connection *ic, int next_cursor) +void twitter_get_friends_ids(struct im_connection *ic, gint64 next_cursor) { // Primitive, but hey! It works... char* args[2]; args[0] = "cursor"; - args[1] = g_strdup_printf ("%d", next_cursor); + args[1] = g_strdup_printf ("%lld", (long long) next_cursor); twitter_http(ic, TWITTER_FRIENDS_IDS_URL, twitter_http_get_friends_ids, ic, 0, args, 2); g_free(args[1]); @@ -418,13 +418,13 @@ static void twitter_http_get_home_timeline(struct http_request *req); /** * Get the timeline. */ -void twitter_get_home_timeline(struct im_connection *ic, int next_cursor) +void twitter_get_home_timeline(struct im_connection *ic, gint64 next_cursor) { struct twitter_data *td = ic->proto_data; char* args[4]; args[0] = "cursor"; - args[1] = g_strdup_printf ("%d", next_cursor); + args[1] = g_strdup_printf ("%lld", (long long) next_cursor); if (td->home_timeline_id) { args[2] = "since_id"; args[3] = g_strdup_printf ("%llu", (long long unsigned int) td->home_timeline_id); @@ -670,11 +670,11 @@ static void twitter_http_get_statuses_friends(struct http_request *req) /** * Get the friends. */ -void twitter_get_statuses_friends(struct im_connection *ic, int next_cursor) +void twitter_get_statuses_friends(struct im_connection *ic, gint64 next_cursor) { char* args[2]; args[0] = "cursor"; - args[1] = g_strdup_printf ("%d", next_cursor); + args[1] = g_strdup_printf ("%lld", (long long) next_cursor); twitter_http(ic, TWITTER_SHOW_FRIENDS_URL, twitter_http_get_statuses_friends, ic, 0, args, 2); diff --git a/protocols/twitter/twitter_lib.h b/protocols/twitter/twitter_lib.h index 65a596cc..6b90f9bb 100644 --- a/protocols/twitter/twitter_lib.h +++ b/protocols/twitter/twitter_lib.h @@ -75,9 +75,9 @@ #define TWITTER_BLOCKS_CREATE_URL "/blocks/create/" #define TWITTER_BLOCKS_DESTROY_URL "/blocks/destroy/" -void twitter_get_friends_ids(struct im_connection *ic, int next_cursor); -void twitter_get_home_timeline(struct im_connection *ic, int next_cursor); -void twitter_get_statuses_friends(struct im_connection *ic, int next_cursor); +void twitter_get_friends_ids(struct im_connection *ic, gint64 next_cursor); +void twitter_get_home_timeline(struct im_connection *ic, gint64 next_cursor); +void twitter_get_statuses_friends(struct im_connection *ic, gint64 next_cursor); void twitter_post_status(struct im_connection *ic, char *msg); void twitter_direct_messages_new(struct im_connection *ic, char *who, char *message); -- cgit v1.2.3