aboutsummaryrefslogtreecommitdiffstats
path: root/protocols/twitter
diff options
context:
space:
mode:
authorGeert Mulders <g.c.w.m.mulders@gmail.com>2010-03-25 22:31:27 +0100
committerGeert Mulders <g.c.w.m.mulders@gmail.com>2010-03-25 22:31:27 +0100
commit62d2cfb0b7b5e7f3eda9ca13b1877d3ad74fcd5e (patch)
treeb23b05667c3626b2d7d5e2d44f03218311ab9280 /protocols/twitter
parentb4dd25398db477b06452be195de14ca352008665 (diff)
Added option to get tweeds either through groupchat or privmes.
Diffstat (limited to 'protocols/twitter')
-rw-r--r--protocols/twitter/twitter.c37
-rw-r--r--protocols/twitter/twitter.h7
-rw-r--r--protocols/twitter/twitter_lib.c369
-rw-r--r--protocols/twitter/twitter_lib.h10
4 files changed, 330 insertions, 93 deletions
diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c
index 1cc7eaeb..b6b23fa5 100644
--- a/protocols/twitter/twitter.c
+++ b/protocols/twitter/twitter.c
@@ -28,8 +28,8 @@
/**
- * * Main loop function
- * */
+ * Main loop function
+ */
gboolean twitter_main_loop(gpointer data, gint fd, b_input_condition cond)
{
struct im_connection *ic = data;
@@ -37,6 +37,11 @@ gboolean twitter_main_loop(gpointer data, gint fd, b_input_condition cond)
if ((ic->flags & OPT_LOGGED_IN) != OPT_LOGGED_IN)
return 0;
+ // If the user uses multiple private message windows we need to get the
+ // users buddies.
+ if (!set_getbool( &ic->acc->set, "use_groupchat" ))
+ twitter_get_statuses_friends(ic, -1);
+
// Do stuff..
twitter_get_home_timeline(ic, -1);
@@ -47,6 +52,8 @@ gboolean twitter_main_loop(gpointer data, gint fd, b_input_condition cond)
static void twitter_init( account_t *acc )
{
+ set_t *s;
+ s = set_add( &acc->set, "use_groupchat", "false", set_eval_bool, acc );
}
/**
@@ -57,7 +64,7 @@ static void twitter_login( account_t *acc )
{
struct im_connection *ic = imcb_new( acc );
struct twitter_data *td = g_new0( struct twitter_data, 1 );
-
+
td->user = acc->user;
td->pass = acc->pass;
td->home_timeline_id = 0;
@@ -67,11 +74,6 @@ static void twitter_login( account_t *acc )
// Set the status to logged in.
ic->flags = OPT_LOGGED_IN;
- // Try to get the buddies...
- //twitter_get_friends_ids(ic, -1);
-
- //twitter_get_home_timeline(ic, -1);
-
// Run this once. After this queue the main loop function.
twitter_main_loop(ic, -1, 0);
@@ -80,6 +82,8 @@ static void twitter_login( account_t *acc )
imcb_log( ic, "Connecting to twitter" );
imcb_connected(ic);
+
+ twitter_connections = g_slist_append( twitter_connections, ic );
}
/**
@@ -96,6 +100,8 @@ static void twitter_logout( struct im_connection *ic )
{
g_free( td );
}
+
+ twitter_connections = g_slist_remove( twitter_connections, ic );
}
/**
@@ -103,8 +109,11 @@ static void twitter_logout( struct im_connection *ic )
*/
static int twitter_buddy_msg( struct im_connection *ic, char *who, char *message, int away )
{
- imcb_log( ic, "In twitter_buddy_msg...");
- twitter_post_status(ic, message);
+ // Let's just update the status.
+// if ( g_strcasecmp(who, ic->acc->user) == 0 )
+ twitter_post_status(ic, message);
+// else
+// twitter_direct_messages_new(ic, who, message);
return( 0 );
}
@@ -123,11 +132,6 @@ static void twitter_set_away( struct im_connection *ic, char *state, char *messa
static void twitter_set_my_name( struct im_connection *ic, char *info )
{
- imcb_log( ic, "In twitter_set_my_name..." );
-// char * aap = twitter_http("http://gertje.org", NULL, ic, 1, "geert", "poep", NULL, 0);
-
-// imcb_log( ic, aap );
-// g_free(aap);
}
static void twitter_get_info(struct im_connection *ic, char *who)
@@ -217,5 +221,8 @@ void twitter_initmodule()
ret->handle_cmp = g_strcasecmp;
register_protocol(ret);
+
+ // Initialise the twitter_connections GSList.
+ twitter_connections = NULL;
}
diff --git a/protocols/twitter/twitter.h b/protocols/twitter/twitter.h
index 5b032929..05a861bb 100644
--- a/protocols/twitter/twitter.h
+++ b/protocols/twitter/twitter.h
@@ -40,4 +40,11 @@ struct twitter_data
struct groupchat *home_timeline_gc;
};
+/**
+ * This has the same function as the msn_connections GSList. We use this to
+ * make sure the connection is still alive in callbacks before we do anything
+ * else.
+ */
+GSList *twitter_connections;
+
#endif //_TWITTER_H
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 );
+}
+
diff --git a/protocols/twitter/twitter_lib.h b/protocols/twitter/twitter_lib.h
index 28ca871f..e47bfd95 100644
--- a/protocols/twitter/twitter_lib.h
+++ b/protocols/twitter/twitter_lib.h
@@ -50,9 +50,9 @@
/* Direct messages URLs */
#define TWITTER_DIRECT_MESSAGES_URL TWITTER_API_URL "/direct_messages.xml"
-#define TWITTER_DIRECT_MESSAGENEW_URL TWITTER_API_URL "/direct_messages/new.xml"
-#define TWITTER_DIRECT_MESSAGESSENT_URL TWITTER_API_URL "/direct_messages/sent.xml"
-#define TWITTER_DIRECT_MESSAGEDESTROY_URL TWITTER_API_URL "/direct_messages/destroy/"
+#define TWITTER_DIRECT_MESSAGES_NEW_URL TWITTER_API_URL "/direct_messages/new.xml"
+#define TWITTER_DIRECT_MESSAGES_SENT_URL TWITTER_API_URL "/direct_messages/sent.xml"
+#define TWITTER_DIRECT_MESSAGES_DESTROY_URL TWITTER_API_URL "/direct_messages/destroy/"
/* Friendships URLs */
#define TWITTER_FRIENDSHIPS_CREATE_URL TWITTER_API_URL "/friendships/create.xml"
@@ -77,8 +77,10 @@
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_post_status(struct im_connection *ic, char* msg);
+void twitter_post_status(struct im_connection *ic, char *msg);
+void twitter_direct_messages_new(struct im_connection *ic, char *who, char *message);
#endif //_TWITTER_LIB_H