diff options
| author | Geert Mulders <g.c.w.m.mulders@gmail.com> | 2010-03-25 22:31:27 +0100 | 
|---|---|---|
| committer | Geert Mulders <g.c.w.m.mulders@gmail.com> | 2010-03-25 22:31:27 +0100 | 
| commit | 62d2cfb0b7b5e7f3eda9ca13b1877d3ad74fcd5e (patch) | |
| tree | b23b05667c3626b2d7d5e2d44f03218311ab9280 /protocols/twitter/twitter_lib.c | |
| parent | b4dd25398db477b06452be195de14ca352008665 (diff) | |
Added option to get tweeds either through groupchat or privmes.
Diffstat (limited to 'protocols/twitter/twitter_lib.c')
| -rw-r--r-- | protocols/twitter/twitter_lib.c | 369 | 
1 files changed, 295 insertions, 74 deletions
| diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index d548b5f2..f07897ed 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -33,9 +33,13 @@  #include <errno.h>  #define TXL_STATUS 1 -#define TXL_ID 1 +#define TXL_USER 2 +#define TXL_ID 3 + +static void twitter_imcb_chat_msg( struct groupchat *c, char *who, char *msg, uint32_t flags, time_t sent_at );  struct twitter_xml_list { +	int type;  	int next_cursor;  	GSList *list;  	gpointer data; @@ -53,9 +57,54 @@ struct twitter_xml_status {  	guint64 id;  }; -void txl_free(struct twitter_xml_list *txl, int type); -void txs_free(struct twitter_xml_status *txs); -void txu_free(struct twitter_xml_user *txu); +/** + * Frees a twitter_xml_user struct. + */ +static void txu_free(struct twitter_xml_user *txu) +{ +	g_free(txu->name); +	g_free(txu->screen_name); +} + + +/** + * Frees a twitter_xml_status struct. + */ +static void txs_free(struct twitter_xml_status *txs) +{ +	g_free(txs->created_at); +	g_free(txs->text); +	txu_free(txs->user); +} + +/** + * Free a twitter_xml_list struct. + * type is the type of list the struct holds. + */ +static void txl_free(struct twitter_xml_list *txl) +{ +	GSList *l; +	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) +			g_free(l->data); +	g_slist_free(txl->list); +} + +/** + * Add a buddy if it is not allready added, set the status to logged in. + */ +static void twitter_add_buddy(struct im_connection *ic, char *name) +{ +	// Check if the buddy is allready in the buddy list. +	if (!user_findhandle( ic, name )) +	{ +		// The buddy is not in the list, add the buddy and set the status to logged in. +		imcb_add_buddy( ic, name, NULL ); +		imcb_buddy_status( ic, name, OPT_LOGGED_IN, NULL, NULL ); +	} +}  static void twitter_http_get_friends_ids(struct http_request *req); @@ -92,6 +141,9 @@ static xt_status twitter_xt_next_cursor( struct xt_node *node, struct twitter_xm  static xt_status twitter_xt_get_friends_id_list( struct xt_node *node, struct twitter_xml_list *txl )  {  	struct xt_node *child; +	 +	// Set the list type. +	txl->type = TXL_ID;  	// The root <statuses> node should hold the list of statuses <status>  	// Walk over the nodes children. @@ -122,6 +174,10 @@ static void twitter_http_get_friends_ids(struct http_request *req)  	ic = req->data; +	// Check if the connection is still active. +	if( !g_slist_find( twitter_connections, ic ) ) +		return; +  	// Check if the HTTP request went well.  	if (req->status_code != 200) {  		// It didn't go well, output the error and return. @@ -141,7 +197,7 @@ static void twitter_http_get_friends_ids(struct http_request *req)  	if (txl->next_cursor)  		twitter_get_friends_ids(ic, txl->next_cursor); -	txl_free(txl, TXL_ID); +	txl_free(txl);  	g_free(txl);  } @@ -171,6 +227,66 @@ static xt_status twitter_xt_get_user( struct xt_node *node, struct twitter_xml_u  }  /** + * Function to fill a twitter_xml_list struct. + * It sets: + *  - all <user>s from the <users> element. + */ +static xt_status twitter_xt_get_users( struct xt_node *node, struct twitter_xml_list *txl ) +{ +	struct twitter_xml_user *txu; +	struct xt_node *child; + +	// Set the type of the list. +	txl->type = TXL_USER; + +	// The root <users> node should hold the list of users <user> +	// Walk over the nodes children. +	for( child = node->children ; child ; child = child->next ) +	{ +		if ( g_strcasecmp( "user", child->name ) == 0) +		{ +			txu = g_new0(struct twitter_xml_user, 1); +			twitter_xt_get_user(child, txu); +			// Put the item in the front of the list. +			txl->list = g_slist_prepend (txl->list, txu); +		} +	} + +	return XT_HANDLED; +} + +/** + * Function to fill a twitter_xml_list struct. + * It calls twitter_xt_get_users to get the <user>s from a <users> element. + * It sets: + *  - the next_cursor. + */ +static xt_status twitter_xt_get_user_list( struct xt_node *node, struct twitter_xml_list *txl ) +{ +	struct xt_node *child; + +	// Set the type of the list. +	txl->type = TXL_USER; + +	// The root <user_list> node should hold a users <users> element +	// Walk over the nodes children. +	for( child = node->children ; child ; child = child->next ) +	{ +		if ( g_strcasecmp( "users", child->name ) == 0) +		{ +			twitter_xt_get_users(child, txl); +		} +		else if ( g_strcasecmp( "next_cursor", child->name ) == 0) +		{ +			twitter_xt_next_cursor(child, txl); +		} +	} + +	return XT_HANDLED; +} + + +/**   * Function to fill a twitter_xml_status struct.   * It sets:   *  - the status text and @@ -217,6 +333,9 @@ static xt_status twitter_xt_get_status_list( struct xt_node *node, struct twitte  	struct twitter_xml_status *txs;  	struct xt_node *child; +	// Set the type of the list. +	txl->type = TXL_STATUS; +  	// The root <statuses> node should hold the list of statuses <status>  	// Walk over the nodes children.  	for( child = node->children ; child ; child = child->next ) @@ -263,15 +382,70 @@ void twitter_get_home_timeline(struct im_connection *ic, int next_cursor)  }  /** + * Function that is called to see the statuses in a groupchat window. + */ +static void twitter_groupchat(struct im_connection *ic, GSList *list) +{ +	struct twitter_data *td = ic->proto_data; +	GSList *l = NULL; +	struct twitter_xml_status *status; +	struct groupchat *gc; + +	// Create a new groupchat if it does not exsist. +	if (!td->home_timeline_gc) +	{    +		td->home_timeline_gc = gc = imcb_chat_new( ic, "home/timeline" ); +		// Add the current user to the chat... +		imcb_chat_add_buddy( gc, ic->acc->user ); +	} +	else +	{    +		gc = td->home_timeline_gc; +	} + +	for ( l = list; l ; l = g_slist_next(l) ) +	{ +		status = l->data; +		twitter_add_buddy(ic, status->user->screen_name); +		// Say it! +		twitter_imcb_chat_msg (gc, status->user->screen_name, status->text, 0, 0 ); +		// Update the home_timeline_id to hold the highest id, so that by the next request +		// we won't pick up the updates allready in the list. +		td->home_timeline_id = td->home_timeline_id < status->id ? status->id : td->home_timeline_id; +	} +} + +/** + * Function that is called to see statuses as private messages. + */ +static void twitter_private_message_chat(struct im_connection *ic, GSList *list) +{ +	struct twitter_data *td = ic->proto_data; +	GSList *l = NULL; +	struct twitter_xml_status *status; + +	for ( l = list; l ; l = g_slist_next(l) ) +	{ +		status = l->data; +		imcb_buddy_msg( ic, status->user->screen_name, status->text, 0, 0 ); +		// Update the home_timeline_id to hold the highest id, so that by the next request +		// we won't pick up the updates allready in the list. +		td->home_timeline_id = td->home_timeline_id < status->id ? status->id : td->home_timeline_id; +	} +} + +/**   * Callback for getting the home timeline.   */  static void twitter_http_get_home_timeline(struct http_request *req)  { -	struct im_connection *ic = req->data;; +	struct im_connection *ic = req->data;  	struct xt_parser *parser;  	struct twitter_xml_list *txl; -	struct twitter_data *td = ic->proto_data; -	struct groupchat *gc; + +	// Check if the connection is still active. +	if( !g_slist_find( twitter_connections, ic ) ) +		return;  	// Check if the HTTP request went well.  	if (req->status_code != 200) { @@ -282,94 +456,92 @@ static void twitter_http_get_home_timeline(struct http_request *req)  	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(parser->root, txl);  	xt_free( parser ); -	 -	GSList *l; -	struct twitter_xml_status *status; -	// Create a new groupchat if it does not exsist. -	if (!td->home_timeline_gc) -	{ -		td->home_timeline_gc = gc = imcb_chat_new( ic, "home/timeline" ); -		// Add the current user to the chat... -		imcb_chat_add_buddy( gc, ic->acc->user ); -	} +	// See if the user wants to see the messages in a groupchat window or as private messages. +	if (set_getbool( &ic->acc->set, "use_groupchat" )) +		twitter_groupchat(ic, txl->list);  	else -	{ -		gc = td->home_timeline_gc; -	} - -	for ( l = txl->list; l ; l = g_slist_next(l) ) -	{ -		status = l->data; -		// TODO Put the next part in a new function.... - -		// Ugly hack, to show current user in chat... -		if ( g_strcasecmp(status->user->screen_name, ic->acc->user) == 0) -		{ -			char *tmp = g_strdup_printf ("_%s_", status->user->screen_name); -			g_free(status->user->screen_name); -			status->user->screen_name = tmp; -		} - -		// Check if the buddy is allready in the buddy list. -		if (!user_findhandle( ic, status->user->screen_name )) -		{ -			// The buddy is not in the list, add the buddy... -			imcb_add_buddy( ic, status->user->screen_name, NULL ); -			imcb_buddy_status( ic, status->user->screen_name, OPT_LOGGED_IN, NULL, NULL ); -		} - -		// Say it! -		imcb_chat_msg (gc, status->user->screen_name, status->text, 0, 0 ); -		// Update the home_timeline_id to hold the highest id, so that by the next request -		// we won't pick up the updates allready in the list. -		td->home_timeline_id = td->home_timeline_id < status->id ? status->id : td->home_timeline_id; -	} +		twitter_private_message_chat(ic, txl->list);  	// Free the structure.	 -	txl_free(txl, TXL_STATUS); +	txl_free(txl);  	g_free(txl);  }  /** - * Free a twitter_xml_list struct. - * type is the type of list the struct holds. + * Callback for getting (twitter)friends... + * + * Be afraid, be very afraid! This function will potentially add hundreds of "friends". "Who has  + * hundreds of friends?" you wonder? You probably not, since you are reading the source of  + * BitlBee... Get a life and meet new people!   */ -void txl_free(struct twitter_xml_list *txl, int type) +static void twitter_http_get_statuses_friends(struct http_request *req)  { -	GSList *l; +	struct im_connection *ic = req->data; +	struct xt_parser *parser; +	struct twitter_xml_list *txl; + +	// Check if the connection is still active. +	if( !g_slist_find( twitter_connections, ic ) ) +		return; + +	// Check if the HTTP request went well. +	if (req->status_code != 200) { +		// It didn't go well, output the error and return. +		imcb_error(ic, "Could not retrieve home/timeline. HTTP STATUS: %d", req->status_code); +		return; +	} + +	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 ); + +	// Get the user list from the parsed xml feed. +	twitter_xt_get_user_list(parser->root, txl); +	xt_free( parser ); + +	GSList *l = NULL; +	struct twitter_xml_user *user; +	// Add the users as buddies.  	for ( l = txl->list; l ; l = g_slist_next(l) ) -		if (type == TXL_STATUS) -			txs_free((struct twitter_xml_status *)l->data); -		else if (type == TXL_ID) -			g_free(l->data); -	g_slist_free(txl->list); -} +	{ +		user = l->data; +		twitter_add_buddy(ic, user->screen_name); +	} -/** - * Frees a twitter_xml_status struct. - */ -void txs_free(struct twitter_xml_status *txs) -{ -	g_free(txs->created_at); -	g_free(txs->text); -	txu_free(txs->user); +	// 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); + +	// Free the structure. +	txl_free(txl); +	g_free(txl);  }  /** - * Frees a twitter_xml_user struct. + * Get the friends.   */ -void txu_free(struct twitter_xml_user *txu) +void twitter_get_statuses_friends(struct im_connection *ic, int next_cursor)  { -	g_free(txu->name); -	g_free(txu->screen_name); +	struct twitter_data *td = ic->proto_data; + +	char* args[2]; +	args[0] = "cursor"; +	args[1] = g_strdup_printf ("%d", next_cursor); + +	twitter_http(TWITTER_SHOW_FRIENDS_URL, twitter_http_get_statuses_friends, ic, 0, td->user, td->pass, args, 2); + +	g_free(args[1]);  }  /** @@ -379,6 +551,10 @@ static void twitter_http_post_status(struct http_request *req)  {  	struct im_connection *ic = req->data; +	// Check if the connection is still active. +	if( !g_slist_find( twitter_connections, ic ) ) +		return; +  	// Check if the HTTP request went well.  	if (req->status_code != 200) {  		// It didn't go well, output the error and return. @@ -399,7 +575,52 @@ void twitter_post_status(struct im_connection *ic, char* msg)  	args[0] = "status";  	args[1] = msg;  	twitter_http(TWITTER_STATUS_UPDATE_URL, twitter_http_post_status, ic, 1, td->user, td->pass, args, 2); -	g_free(args[1]); +//	g_free(args[1]);  } +/** + * Function to POST a new message to twitter. + */ +void twitter_direct_messages_new(struct im_connection *ic, char *who, char *msg) +{ +	struct twitter_data *td = ic->proto_data; + +	char* args[4]; +	args[0] = "screen_name"; +	args[1] = who; +	args[2] = "text"; +	args[3] = msg; +	// Use the same callback as for twitter_post_status, since it does basically the same. +	twitter_http(TWITTER_DIRECT_MESSAGES_NEW_URL, twitter_http_post_status, ic, 1, td->user, td->pass, args, 4); +//	g_free(args[1]); +//	g_free(args[3]); +} + + +/** + * This function "overwrites" the imcb_chat_msg function. Because in the original the logged in user is filtered out. + */ +static void twitter_imcb_chat_msg( struct groupchat *c, char *who, char *msg, uint32_t flags, time_t sent_at ) +{ +	struct im_connection *ic = c->ic; +	char *wrapped; +	user_t *u; + +	u = user_findhandle( ic, who ); +	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 )  +			|| ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) ) +		strip_html( msg ); + +	wrapped = word_wrap( msg, 425 ); +	if( c && u ) +	{    +		irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, "", wrapped ); +	} +	else +	{    +		imcb_log( ic, "Message from/to conversation %s@%p (unknown conv/user): %s", who, c, wrapped ); +	} +	g_free( wrapped ); +} + | 
