diff options
Diffstat (limited to 'protocols/twitter')
| -rw-r--r-- | protocols/twitter/twitter.c | 80 | ||||
| -rw-r--r-- | protocols/twitter/twitter.h | 12 | ||||
| -rw-r--r-- | protocols/twitter/twitter_lib.c | 347 | ||||
| -rw-r--r-- | protocols/twitter/twitter_lib.h | 2 | 
4 files changed, 349 insertions, 92 deletions
| diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index 57a1ed80..76ccc3eb 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -29,12 +29,12 @@  #include "url.h"  #define twitter_msg( ic, fmt... ) \ -	do {                                                        \ -		struct twitter_data *td = ic->proto_data;           \ -		if( td->home_timeline_gc )                          \ -			imcb_chat_log( td->home_timeline_gc, fmt ); \ -		else                                                \ -			imcb_log( ic, fmt );                        \ +	do {                                            \ +		struct twitter_data *td = ic->proto_data;   \ +		if( td->timeline_gc )                       \ +			imcb_chat_log( td->timeline_gc, fmt );  \ +		else                                        \ +			imcb_log( ic, fmt );                    \  	} while( 0 );  GSList *twitter_connections = NULL; @@ -51,7 +51,7 @@ gboolean twitter_main_loop(gpointer data, gint fd, b_input_condition cond)  		return 0;  	// Do stuff.. -	twitter_get_home_timeline(ic, -1); +	twitter_get_timeline(ic, -1);  	// If we are still logged in run this function again after timeout.  	return (ic->flags & OPT_LOGGED_IN) == OPT_LOGGED_IN; @@ -68,7 +68,8 @@ static void twitter_main_loop_start(struct im_connection *ic)  	// Queue the main_loop  	// Save the return value, so we can remove the timeout on logout. -	td->main_loop_id = b_timeout_add(60000, twitter_main_loop, ic); +	td->main_loop_id = +	    b_timeout_add(set_getint(&ic->acc->set, "fetch_interval") * 1000, twitter_main_loop, ic);  }  static void twitter_oauth_start(struct im_connection *ic); @@ -77,6 +78,8 @@ void twitter_login_finish(struct im_connection *ic)  {  	struct twitter_data *td = ic->proto_data; +	td->flags &= ~TWITTER_DOING_TIMELINE; +  	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 && @@ -89,16 +92,16 @@ void twitter_login_finish(struct im_connection *ic)  }  static const struct oauth_service twitter_oauth = { -	"http://api.twitter.com/oauth/request_token", -	"http://api.twitter.com/oauth/access_token", +	"https://api.twitter.com/oauth/request_token", +	"https://api.twitter.com/oauth/access_token",  	"https://api.twitter.com/oauth/authorize",  	.consumer_key = "xsDNKJuNZYkZyMcu914uEA",  	.consumer_secret = "FCxqcr0pXKzsF9ajmP57S3VQ8V6Drk4o2QYtqMcOszo",  };  static const struct oauth_service identica_oauth = { -	"http://identi.ca/api/oauth/request_token", -	"http://identi.ca/api/oauth/access_token", +	"https://identi.ca/api/oauth/request_token", +	"https://identi.ca/api/oauth/access_token",  	"https://identi.ca/api/oauth/authorize",  	.consumer_key = "e147ff789fcbd8a5a07963afbb43f9da",  	.consumer_secret = "c596267f277457ec0ce1ab7bb788d828", @@ -215,7 +218,6 @@ static void twitter_init(account_t * acc)  		def_url = TWITTER_API_URL;  		def_oauth = "true";  	} else {		/* if( strcmp( acc->prpl->name, "identica" ) == 0 ) */ -  		def_url = IDENTICA_API_URL;  		def_oauth = "false";  	} @@ -227,6 +229,11 @@ static void twitter_init(account_t * acc)  	s = set_add(&acc->set, "commands", "true", set_eval_bool, acc); +	s = set_add(&acc->set, "fetch_interval", "60", set_eval_int, acc); +	s->flags |= ACC_SET_OFFLINE_ONLY; + +	s = set_add(&acc->set, "fetch_mentions", "true", set_eval_bool, acc); +  	s = set_add(&acc->set, "message_length", "140", set_eval_int, acc);  	s = set_add(&acc->set, "mode", "chat", set_eval_mode, acc); @@ -235,6 +242,8 @@ static void twitter_init(account_t * acc)  	s = set_add(&acc->set, "show_ids", "false", set_eval_bool, acc);  	s->flags |= ACC_SET_OFFLINE_ONLY; +	s = set_add(&acc->set, "show_old_mentions", "true", set_eval_bool, acc); +  	s = set_add(&acc->set, "oauth", def_oauth, set_eval_bool, acc);  } @@ -316,8 +325,8 @@ static void twitter_logout(struct im_connection *ic)  	// Remove the main_loop function from the function queue.  	b_event_remove(td->main_loop_id); -	if (td->home_timeline_gc) -		imcb_chat_free(td->home_timeline_gc); +	if (td->timeline_gc) +		imcb_chat_free(td->timeline_gc);  	if (td) {  		oauth_info_free(td->oauth_info); @@ -403,13 +412,13 @@ static void twitter_chat_leave(struct groupchat *c)  {  	struct twitter_data *td = c->ic->proto_data; -	if (c != td->home_timeline_gc) +	if (c != td->timeline_gc)  		return;		/* WTF? */  	/* If the user leaves the channel: Fine. Rejoin him/her once new  	   tweets come in. */ -	imcb_chat_free(td->home_timeline_gc); -	td->home_timeline_gc = NULL; +	imcb_chat_free(td->timeline_gc); +	td->timeline_gc = NULL;  }  static void twitter_keepalive(struct im_connection *ic) @@ -464,15 +473,14 @@ static void twitter_handle_command(struct im_connection *ic, char *message)  	} else if (g_strcasecmp(cmd[0], "undo") == 0) {  		guint64 id; -		if (cmd[1]) -			id = g_ascii_strtoull(cmd[1], NULL, 10); -		else -			id = td->last_status_id; - -		/* TODO: User feedback. */ -		if (id) +		if (cmd[1] == NULL) +			twitter_status_destroy(ic, td->last_status_id); +		else if (sscanf(cmd[1], "%" G_GUINT64_FORMAT, &id) == 1) { +			if (id < TWITTER_LOG_LENGTH && td->log) +				id = td->log[id].id; +			  			twitter_status_destroy(ic, id); -		else +		} else  			twitter_msg(ic, "Could not undo last action");  		g_free(cmds); @@ -490,11 +498,14 @@ static void twitter_handle_command(struct im_connection *ic, char *message)  		bee_user_t *bu;  		guint64 id; -		if ((bu = bee_user_by_handle(ic->bee, ic, cmd[1])) && +		if (g_str_has_prefix(cmd[1], "#") && +		    sscanf(cmd[1] + 1, "%" G_GUINT64_FORMAT, &id) == 1) { +			if (id < TWITTER_LOG_LENGTH && td->log) +				id = td->log[id].id; +		} else if ((bu = bee_user_by_handle(ic->bee, ic, cmd[1])) &&  		    (tud = bu->data) && tud->last_id)  			id = tud->last_id; -		else { -			id = g_ascii_strtoull(cmd[1], NULL, 10); +		else if (sscanf(cmd[1], "%" G_GUINT64_FORMAT, &id) == 1){  			if (id < TWITTER_LOG_LENGTH && td->log)  				id = td->log[id].id;  		} @@ -513,7 +524,15 @@ static void twitter_handle_command(struct im_connection *ic, char *message)  		bee_user_t *bu = NULL;  		guint64 id = 0; -		if ((bu = bee_user_by_handle(ic->bee, ic, cmd[1])) && +		if (g_str_has_prefix(cmd[1], "#") && +		    sscanf(cmd[1] + 1, "%" G_GUINT64_FORMAT, &id) == 1 && +		    (id < TWITTER_LOG_LENGTH) && td->log) { +			bu = td->log[id].bu; +			if (g_slist_find(ic->bee->users, bu)) +				id = td->log[id].id; +			else +				bu = NULL; +		} else if ((bu = bee_user_by_handle(ic->bee, ic, cmd[1])) &&  		    (tud = bu->data) && tud->last_id) {  			id = tud->last_id;  		} else if (sscanf(cmd[1], "%" G_GUINT64_FORMAT, &id) == 1 && @@ -524,6 +543,7 @@ static void twitter_handle_command(struct im_connection *ic, char *message)  			else  				bu = NULL;  		} +  		if (!id || !bu) {  			twitter_msg(ic, "User `%s' does not exist or didn't "  				    "post any statuses recently", cmd[1]); diff --git a/protocols/twitter/twitter.h b/protocols/twitter/twitter.h index c38d9b86..14e43824 100644 --- a/protocols/twitter/twitter.h +++ b/protocols/twitter/twitter.h @@ -35,6 +35,9 @@  typedef enum  {  	TWITTER_HAVE_FRIENDS = 1, +	TWITTER_DOING_TIMELINE = 0x10000, +	TWITTER_GOT_TIMELINE = 0x20000, +	TWITTER_GOT_MENTIONS = 0x40000,  } twitter_flags_t;  struct twitter_log_data; @@ -43,12 +46,17 @@ struct twitter_data  {  	char* user;  	struct oauth_info *oauth_info; + +	gpointer home_timeline_obj; +	gpointer mentions_obj; + +	guint64 timeline_id; +  	GSList *follow_ids; -	guint64 home_timeline_id;  	guint64 last_status_id; /* For undo */  	gint main_loop_id; -	struct groupchat *home_timeline_gc; +	struct groupchat *timeline_gc;  	gint http_fails;  	twitter_flags_t flags; diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index 14e98c53..d52c29ff 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -77,17 +77,20 @@ static void txu_free(struct twitter_xml_user *txu)  {  	if (txu == NULL)  		return; +  	g_free(txu->name);  	g_free(txu->screen_name);  	g_free(txu);  } -  /**   * Frees a twitter_xml_status struct.   */  static void txs_free(struct twitter_xml_status *txs)  { +	if (txs == NULL) +		return; +  	g_free(txs->text);  	txu_free(txs->user);  	g_free(txs); @@ -102,19 +105,40 @@ static void txl_free(struct twitter_xml_list *txl)  	GSList *l;  	if (txl == NULL)  		return; -	for (l = txl->list; l; l = g_slist_next(l)) -		if (txl->type == TXL_STATUS) + +	for (l = txl->list; l; l = g_slist_next(l)) { +		if (txl->type == TXL_STATUS) {  			txs_free((struct twitter_xml_status *) l->data); -		else if (txl->type == TXL_ID) +		} else if (txl->type == TXL_ID) {  			g_free(l->data); -		else if (txl->type == TXL_USER) +		} else if (txl->type == TXL_USER) {  			txu_free(l->data); +		} +	} +  	g_slist_free(txl->list);  	g_free(txl);  }  /** - * Add a buddy if it is not allready added, set the status to logged in. + * Compare status elements + */ +static gint twitter_compare_elements(gconstpointer a, gconstpointer b) +{ +	struct twitter_xml_status *a_status = (struct twitter_xml_status *) a; +	struct twitter_xml_status *b_status = (struct twitter_xml_status *) b; + +	if (a_status->created_at < b_status->created_at) { +		return -1; +	} else if (a_status->created_at > b_status->created_at) { +		return 1; +	} else { +		return 0; +	} +} + +/** + * Add a buddy if it is not already added, set the status to logged in.   */  static void twitter_add_buddy(struct im_connection *ic, char *name, const char *fullname)  { @@ -131,7 +155,7 @@ static void twitter_add_buddy(struct im_connection *ic, char *name, const char *  			/* Necessary so that nicks always get translated to the  			   exact Twitter username. */  			imcb_buddy_nick_hint(ic, name, name); -			imcb_chat_add_buddy(td->home_timeline_gc, name); +			imcb_chat_add_buddy(td->timeline_gc, name);  		} else if (g_strcasecmp(mode, "many") == 0)  			imcb_buddy_status(ic, name, OPT_LOGGED_IN, NULL, NULL);  	} @@ -259,7 +283,7 @@ static void twitter_http_get_friends_ids(struct http_request *req)  	}  	/* Create the room now that we "logged in". */ -	if (!td->home_timeline_gc && g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0) +	if (!td->timeline_gc && g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0)  		twitter_groupchat_init(ic);  	txl = g_new0(struct twitter_xml_list, 1); @@ -435,14 +459,11 @@ static xt_status twitter_xt_get_users(struct xt_node *node, struct twitter_xml_l  static xt_status twitter_xt_get_status(struct xt_node *node, struct twitter_xml_status *txs)  {  	struct xt_node *child, *rt = NULL; -	gboolean truncated = FALSE;  	// Walk over the nodes children.  	for (child = node->children; child; child = child->next) {  		if (g_strcasecmp("text", child->name) == 0) {  			txs->text = g_memdup(child->text, child->text_len + 1); -		} else if (g_strcasecmp("truncated", child->name) == 0 && child->text) { -			truncated = bool2int(child->text);  		} else if (g_strcasecmp("retweeted_status", child->name) == 0) {  			rt = child;  		} else if (g_strcasecmp("created_at", child->name) == 0) { @@ -463,8 +484,9 @@ static xt_status twitter_xt_get_status(struct xt_node *node, struct twitter_xml_  		}  	} -	/* If it's a truncated retweet, get the original because dots suck. */ -	if (truncated && rt) { +	/* If it's a (truncated) retweet, get the original. Even if the API claims it +	   wasn't truncated because it may be lying. */ +	if (rt) {  		struct twitter_xml_status *rtxs = g_new0(struct twitter_xml_status, 1);  		if (twitter_xt_get_status(rt, rtxs) != XT_HANDLED) {  			txs_free(rtxs); @@ -474,6 +496,27 @@ static xt_status twitter_xt_get_status(struct xt_node *node, struct twitter_xml_  		g_free(txs->text);  		txs->text = g_strdup_printf("RT @%s: %s", rtxs->user->screen_name, rtxs->text);  		txs_free(rtxs); +	} else { +		struct xt_node *urls, *url; +		 +		urls = xt_find_path(node, "entities/urls"); +		for (url = urls ? urls->children : NULL; url; url = url->next) { +			/* "short" is a reserved word. :-P */ +			struct xt_node *kort = xt_find_node(url->children, "url"); +			struct xt_node *disp = xt_find_node(url->children, "display_url"); +			char *pos, *new; +			 +			if (!kort || !kort->text || !disp || !disp->text || +			    !(pos = strstr(txs->text, kort->text))) +				continue; +			 +			*pos = '\0'; +			new = g_strdup_printf("%s%s <%s>%s", txs->text, kort->text, +			                      disp->text, pos + strlen(kort->text)); +			 +			g_free(txs->text); +			txs->text = new; +		}  	}  	return XT_HANDLED; @@ -521,32 +564,6 @@ static xt_status twitter_xt_get_status_list(struct im_connection *ic, struct xt_  	return XT_HANDLED;  } -static void twitter_http_get_home_timeline(struct http_request *req); - -/** - * Get the timeline. - */ -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("%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); -	} - -	twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args, -		     td->home_timeline_id ? 4 : 2); - -	g_free(args[1]); -	if (td->home_timeline_id) { -		g_free(args[3]); -	} -} -  static char *twitter_msg_add_id(struct im_connection *ic,  				struct twitter_xml_status *txs, const char *prefix)  { @@ -585,7 +602,7 @@ static void twitter_groupchat_init(struct im_connection *ic)  	struct twitter_data *td = ic->proto_data;  	GSList *l; -	td->home_timeline_gc = gc = imcb_chat_new(ic, "home/timeline"); +	td->timeline_gc = gc = imcb_chat_new(ic, "twitter/timeline");  	name_hint = g_strdup_printf("%s_%s", td->prefix, ic->acc->user);  	imcb_chat_name_hint(gc, name_hint); @@ -594,7 +611,7 @@ static void twitter_groupchat_init(struct im_connection *ic)  	for (l = ic->bee->users; l; l = l->next) {  		bee_user_t *bu = l->data;  		if (bu->ic == ic) -			imcb_chat_add_buddy(td->home_timeline_gc, bu->handle); +			imcb_chat_add_buddy(td->timeline_gc, bu->handle);  	}  } @@ -607,12 +624,13 @@ static void twitter_groupchat(struct im_connection *ic, GSList * list)  	GSList *l = NULL;  	struct twitter_xml_status *status;  	struct groupchat *gc; +	guint64 last_id = 0;  	// Create a new groupchat if it does not exsist. -	if (!td->home_timeline_gc) +	if (!td->timeline_gc)  		twitter_groupchat_init(ic); -	gc = td->home_timeline_gc; +	gc = td->timeline_gc;  	if (!gc->joined)  		imcb_chat_add_buddy(gc, ic->acc->user); @@ -620,26 +638,30 @@ static void twitter_groupchat(struct im_connection *ic, GSList * list)  		char *msg;  		status = l->data; -		if (status->user == NULL || status->text == NULL) +		if (status->user == NULL || status->text == NULL || last_id == status->id)  			continue; -		twitter_add_buddy(ic, status->user->screen_name, status->user->name); +		last_id = status->id;  		strip_html(status->text); +  		msg = twitter_msg_add_id(ic, status, "");  		// Say it! -		if (g_strcasecmp(td->user, status->user->screen_name) == 0) +		if (g_strcasecmp(td->user, status->user->screen_name) == 0) {  			imcb_chat_log(gc, "You: %s", msg ? msg : status->text); -		else +		} else { +			twitter_add_buddy(ic, status->user->screen_name, status->user->name); +  			imcb_chat_msg(gc, status->user->screen_name,  				      msg ? msg : status->text, 0, status->created_at); +		}  		g_free(msg); -		// Update the home_timeline_id to hold the highest id, so that by the next request +		// Update the timeline_id to hold the highest id, so that by the next request  		// we won't pick up the updates already in the list. -		td->home_timeline_id = MAX(td->home_timeline_id, status->id); +		td->timeline_id = MAX(td->timeline_id, status->id);  	}  } @@ -653,6 +675,7 @@ static void twitter_private_message_chat(struct im_connection *ic, GSList * list  	struct twitter_xml_status *status;  	char from[MAX_STRING];  	gboolean mode_one; +	guint64 last_id = 0;  	mode_one = g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "one") == 0; @@ -665,6 +688,10 @@ static void twitter_private_message_chat(struct im_connection *ic, GSList * list  		char *prefix = NULL, *text = NULL;  		status = l->data; +		if (status->user == NULL || status->text == NULL || last_id == status->id) +			continue; + +		last_id = status->id;  		strip_html(status->text);  		if (mode_one) @@ -679,15 +706,166 @@ static void twitter_private_message_chat(struct im_connection *ic, GSList * list  			       mode_one ? from : status->user->screen_name,  			       text ? text : status->text, 0, status->created_at); -		// Update the home_timeline_id to hold the highest id, so that by the next request +		// Update the timeline_id to hold the highest id, so that by the next request  		// we won't pick up the updates already in the list. -		td->home_timeline_id = MAX(td->home_timeline_id, status->id); +		td->timeline_id = MAX(td->timeline_id, status->id);  		g_free(text);  		g_free(prefix);  	}  } +static void twitter_http_get_home_timeline(struct http_request *req); +static void twitter_http_get_mentions(struct http_request *req); + +/** + * Get the timeline with optionally mentions + */ +void twitter_get_timeline(struct im_connection *ic, gint64 next_cursor) +{ +	struct twitter_data *td = ic->proto_data; +	gboolean include_mentions = set_getbool(&ic->acc->set, "fetch_mentions"); + +	if (td->flags & TWITTER_DOING_TIMELINE) { +		return; +	} + +	td->flags |= TWITTER_DOING_TIMELINE; + +	twitter_get_home_timeline(ic, next_cursor); + +	if (include_mentions) { +		twitter_get_mentions(ic, next_cursor); +	} +} + +/** + * Call this one after receiving timeline/mentions. Show to user once we have + * both. + */ +void twitter_flush_timeline(struct im_connection *ic) +{ +	struct twitter_data *td = ic->proto_data; +	gboolean include_mentions = set_getbool(&ic->acc->set, "fetch_mentions"); +	gboolean show_old_mentions = set_getbool(&ic->acc->set, "show_old_mentions"); +	struct twitter_xml_list *home_timeline = td->home_timeline_obj; +	struct twitter_xml_list *mentions = td->mentions_obj; +	GSList *output = NULL; +	GSList *l; + +	if (!(td->flags & TWITTER_GOT_TIMELINE)) { +		return; +	} + +	if (include_mentions && !(td->flags & TWITTER_GOT_MENTIONS)) { +		return; +	} + +	if (home_timeline && home_timeline->list) { +		for (l = home_timeline->list; l; l = g_slist_next(l)) { +			output = g_slist_insert_sorted(output, l->data, twitter_compare_elements); +		} +	} + +	if (include_mentions && mentions && mentions->list) { +		for (l = mentions->list; l; l = g_slist_next(l)) { +			if (!show_old_mentions && output && twitter_compare_elements(l->data, output->data) < 0) { +				continue; +			} + +			output = g_slist_insert_sorted(output, l->data, twitter_compare_elements); +		} +	} + +	// See if the user wants to see the messages in a groupchat window or as private messages. +	if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0) +		twitter_groupchat(ic, output); +	else +		twitter_private_message_chat(ic, output); + +	g_slist_free(output); + +	if (home_timeline && home_timeline->list) { +		txl_free(home_timeline); +	} + +	if (mentions && mentions->list) { +		txl_free(mentions); +	} + +	td->flags &= ~(TWITTER_DOING_TIMELINE | TWITTER_GOT_TIMELINE | TWITTER_GOT_MENTIONS); +} + +/** + * Get the timeline. + */ +void twitter_get_home_timeline(struct im_connection *ic, gint64 next_cursor) +{ +	struct twitter_data *td = ic->proto_data; + +	td->home_timeline_obj = NULL; +	td->flags &= ~TWITTER_GOT_TIMELINE; + +	char *args[6]; +	args[0] = "cursor"; +	args[1] = g_strdup_printf("%lld", (long long) next_cursor); +	args[2] = "include_entities"; +	args[3] = "true"; +	if (td->timeline_id) { +		args[4] = "since_id"; +		args[5] = g_strdup_printf("%llu", (long long unsigned int) td->timeline_id); +	} + +	if (twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args, +		     td->timeline_id ? 6 : 4) == NULL) { +		if (++td->http_fails >= 5) +			imcb_error(ic, "Could not retrieve %s: %s", +			           TWITTER_HOME_TIMELINE_URL, "connection failed"); +		td->flags |= TWITTER_GOT_TIMELINE; +		twitter_flush_timeline(ic); +	} + +	g_free(args[1]); +	if (td->timeline_id) { +		g_free(args[5]); +	} +} + +/** + * Get mentions. + */ +void twitter_get_mentions(struct im_connection *ic, gint64 next_cursor) +{ +	struct twitter_data *td = ic->proto_data; + +	td->mentions_obj = NULL; +	td->flags &= ~TWITTER_GOT_MENTIONS; + +	char *args[6]; +	args[0] = "cursor"; +	args[1] = g_strdup_printf("%lld", (long long) next_cursor); +	args[2] = "include_entities"; +	args[3] = "true"; +	if (td->timeline_id) { +		args[4] = "since_id"; +		args[5] = g_strdup_printf("%llu", (long long unsigned int) td->timeline_id); +	} + +	if (twitter_http(ic, TWITTER_MENTIONS_URL, twitter_http_get_mentions, ic, 0, args, +		     td->timeline_id ? 6 : 4) == NULL) { +		if (++td->http_fails >= 5) +			imcb_error(ic, "Could not retrieve %s: %s", +			           TWITTER_MENTIONS_URL, "connection failed"); +		td->flags |= TWITTER_GOT_MENTIONS; +		twitter_flush_timeline(ic); +	} + +	g_free(args[1]); +	if (td->timeline_id) { +		g_free(args[5]); +	} +} +  /**   * Callback for getting the home timeline.   */ @@ -712,14 +890,66 @@ static void twitter_http_get_home_timeline(struct http_request *req)  	} else if (req->status_code == 401) {  		imcb_error(ic, "Authentication failure");  		imc_logout(ic, FALSE); -		return; +		goto end;  	} else {  		// It didn't go well, output the error and return.  		if (++td->http_fails >= 5)  			imcb_error(ic, "Could not retrieve %s: %s",  				   TWITTER_HOME_TIMELINE_URL, twitter_parse_error(req)); +		goto end; +	} + +	txl = g_new0(struct twitter_xml_list, 1); +	txl->list = NULL; + +	// Parse the data. +	parser = xt_new(NULL, txl); +	xt_feed(parser, req->reply_body, req->body_size); +	// The root <statuses> node should hold the list of statuses <status> +	twitter_xt_get_status_list(ic, parser->root, txl); +	xt_free(parser); + +	td->home_timeline_obj = txl; + +      end: +	td->flags |= TWITTER_GOT_TIMELINE; + +	twitter_flush_timeline(ic); +} + +/** + * Callback for getting mentions. + */ +static void twitter_http_get_mentions(struct http_request *req) +{ +	struct im_connection *ic = req->data; +	struct twitter_data *td; +	struct xt_parser *parser; +	struct twitter_xml_list *txl; + +	// Check if the connection is still active. +	if (!g_slist_find(twitter_connections, ic))  		return; + +	td = ic->proto_data; + +	// Check if the HTTP request went well. +	if (req->status_code == 200) { +		td->http_fails = 0; +		if (!(ic->flags & OPT_LOGGED_IN)) +			imcb_connected(ic); +	} else if (req->status_code == 401) { +		imcb_error(ic, "Authentication failure"); +		imc_logout(ic, FALSE); +		goto end; +	} else { +		// It didn't go well, output the error and return. +		if (++td->http_fails >= 5) +			imcb_error(ic, "Could not retrieve %s: %s", +				   TWITTER_MENTIONS_URL, twitter_parse_error(req)); + +		goto end;  	}  	txl = g_new0(struct twitter_xml_list, 1); @@ -732,15 +962,12 @@ static void twitter_http_get_home_timeline(struct http_request *req)  	twitter_xt_get_status_list(ic, parser->root, txl);  	xt_free(parser); -	// See if the user wants to see the messages in a groupchat window or as private messages. -	if (txl->list == NULL); -	else if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0) -		twitter_groupchat(ic, txl->list); -	else -		twitter_private_message_chat(ic, txl->list); +	td->mentions_obj = txl; -	// Free the structure.   -	txl_free(txl); +      end: +	td->flags |= TWITTER_GOT_MENTIONS; + +	twitter_flush_timeline(ic);  }  /** diff --git a/protocols/twitter/twitter_lib.h b/protocols/twitter/twitter_lib.h index c33b2dfc..b06f5055 100644 --- a/protocols/twitter/twitter_lib.h +++ b/protocols/twitter/twitter_lib.h @@ -75,8 +75,10 @@  #define TWITTER_BLOCKS_CREATE_URL "/blocks/create/"  #define TWITTER_BLOCKS_DESTROY_URL "/blocks/destroy/" +void twitter_get_timeline(struct im_connection *ic, gint64 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_mentions(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, guint64 in_reply_to); | 
