diff options
Diffstat (limited to 'protocols')
-rw-r--r-- | protocols/jabber/jabber_util.c | 29 | ||||
-rw-r--r-- | protocols/jabber/message.c | 4 | ||||
-rw-r--r-- | protocols/msn/msn.c | 31 | ||||
-rw-r--r-- | protocols/msn/msn.h | 1 | ||||
-rw-r--r-- | protocols/msn/msn_util.c | 16 | ||||
-rw-r--r-- | protocols/msn/ns.c | 67 | ||||
-rw-r--r-- | protocols/nogaim.c | 48 | ||||
-rw-r--r-- | protocols/nogaim.h | 1 | ||||
-rw-r--r-- | protocols/twitter/Makefile | 43 | ||||
-rw-r--r-- | protocols/twitter/twitter.c | 232 | ||||
-rw-r--r-- | protocols/twitter/twitter.h | 52 | ||||
-rw-r--r-- | protocols/twitter/twitter_http.c | 161 | ||||
-rw-r--r-- | protocols/twitter/twitter_http.h | 34 | ||||
-rw-r--r-- | protocols/twitter/twitter_lib.c | 650 | ||||
-rw-r--r-- | protocols/twitter/twitter_lib.h | 86 |
15 files changed, 1384 insertions, 71 deletions
diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 6f58f124..608cb52a 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -670,10 +670,9 @@ int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ) time_t jabber_get_timestamp( struct xt_node *xt ) { - struct tm tp, utc; struct xt_node *c; - time_t res, tres; char *s = NULL; + struct tm tp; for( c = xt->children; ( c = xt_find_node( c, "x" ) ); c = c->next ) { @@ -691,30 +690,8 @@ time_t jabber_get_timestamp( struct xt_node *xt ) tp.tm_year -= 1900; tp.tm_mon --; - tp.tm_isdst = -1; /* GRRRRRRRRRRR */ - - res = mktime( &tp ); - /* Problem is, mktime() just gave us the GMT timestamp for the - given local time... While the given time WAS NOT local. So - we should fix this now. - - Now I could choose between messing with environment variables - (kludgy) or using timegm() (not portable)... Or doing the - following, which I actually prefer... */ - gmtime_r( &res, &utc ); - utc.tm_isdst = -1; /* Once more: GRRRRRRRRRRRRRRRRRR!!! */ - if( utc.tm_hour == tp.tm_hour && utc.tm_min == tp.tm_min ) - /* Sweet! We're in UTC right now... */ - return res; - - tres = mktime( &utc ); - res += res - tres; - - /* Yes, this is a hack. And it will go wrong around DST changes. - BUT this is more likely to be threadsafe than messing with - environment variables, and possibly more portable... */ - - return res; + + return mktime_utc( &tp ); } struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns ) diff --git a/protocols/jabber/message.c b/protocols/jabber/message.c index a226a225..e8161029 100644 --- a/protocols/jabber/message.c +++ b/protocols/jabber/message.c @@ -79,8 +79,8 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) if( type && strcmp( type, "headline" ) == 0 ) { - c = xt_find_node( node->children, "subject" ); - g_string_append_printf( fullmsg, "Headline: %s\n", c && c->text_len > 0 ? c->text : "" ); + if( ( c = xt_find_node( node->children, "subject" ) ) && c->text_len > 0 ) + g_string_append_printf( fullmsg, "Headline: %s\n", c->text ); /* <x xmlns="jabber:x:oob"><url>http://....</url></x> can contain a URL, it seems. */ for( c = node->children; c; c = c->next ) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 8b73f103..c7f56b7f 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -30,16 +30,13 @@ int msn_chat_id; GSList *msn_connections; GSList *msn_switchboards; -static char *msn_set_display_name( set_t *set, char *value ); +static char *set_eval_display_name( set_t *set, char *value ); static void msn_init( account_t *acc ) { - set_t *s; - - s = set_add( &acc->set, "display_name", NULL, msn_set_display_name, acc ); - s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY; - - s = set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc ); + set_add( &acc->set, "display_name", NULL, set_eval_display_name, acc ); + set_add( &acc->set, "local_display_name", "false", set_eval_bool, acc ); + set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc ); } static void msn_login( account_t *acc ) @@ -172,7 +169,7 @@ static void msn_set_away( struct im_connection *ic, char *state, char *message ) static void msn_set_my_name( struct im_connection *ic, char *info ) { - msn_set_display_name( set_find( &ic->acc->set, "display_name" ), info ); + msn_set_display_name( ic, info ); } static void msn_get_info(struct im_connection *ic, char *who) @@ -288,18 +285,14 @@ static int msn_send_typing( struct im_connection *ic, char *who, int typing ) return( 1 ); } -static char *msn_set_display_name( set_t *set, char *value ) +static char *set_eval_display_name( set_t *set, char *value ) { account_t *acc = set->data; struct im_connection *ic = acc->ic; - struct msn_data *md; - char buf[1024], *fn; - /* Double-check. */ + /* Allow any name if we're offline. */ if( ic == NULL ) - return NULL; - - md = ic->proto_data; + return value; if( strlen( value ) > 129 ) { @@ -307,16 +300,10 @@ static char *msn_set_display_name( set_t *set, char *value ) return NULL; } - fn = msn_http_encode( value ); - - g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, ic->acc->user, fn ); - msn_write( ic, buf, strlen( buf ) ); - g_free( fn ); - /* Returning NULL would be better, because the server still has to confirm the name change. However, it looks a bit confusing to the user. */ - return value; + return msn_set_display_name( ic, value ) ? value : NULL; } void msn_initmodule() diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 50f273ad..077203c9 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -161,6 +161,7 @@ char **msn_linesplit( char *line ); int msn_handler( struct msn_handler_data *h ); char *msn_http_encode( const char *input ); void msn_msgq_purge( struct im_connection *ic, GSList **list ); +gboolean msn_set_display_name( struct im_connection *ic, const char *rawname ); /* tables.c */ const struct msn_away_state *msn_away_state_by_number( int number ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index f85981e5..a8d24b30 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -37,10 +37,10 @@ int msn_write( struct im_connection *ic, char *s, int len ) { imcb_error( ic, "Short write() to main server" ); imc_logout( ic, TRUE ); - return( 0 ); + return 0; } - return( 1 ); + return 1; } int msn_logged_in( struct im_connection *ic ) @@ -375,3 +375,15 @@ void msn_msgq_purge( struct im_connection *ic, GSList **list ) imcb_log( ic, "%s", ret->str ); g_string_free( ret, TRUE ); } + +gboolean msn_set_display_name( struct im_connection *ic, const char *rawname ) +{ + char *fn = msn_http_encode( rawname ); + struct msn_data *md = ic->proto_data; + char buf[1024]; + + g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, ic->acc->user, fn ); + g_free( fn ); + + return msn_write( ic, buf, strlen( buf ) ) != 0; +} diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index d78d753a..8181c1af 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -34,6 +34,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ); static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); static void msn_auth_got_passport_token( struct msn_auth_data *mad ); +static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name ); gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) { @@ -230,25 +231,10 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } else if( num_parts >= 7 && strcmp( cmd[2], "OK" ) == 0 ) { - set_t *s; - if( num_parts == 7 ) - { - http_decode( cmd[4] ); - - strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) ); - ic->displayname[sizeof(ic->displayname)-1] = 0; - - if( ( s = set_find( &ic->acc->set, "display_name" ) ) ) - { - g_free( s->value ); - s->value = g_strdup( cmd[4] ); - } - } + msn_ns_got_display_name( ic, cmd[4] ); else - { imcb_log( ic, "Warning: Friendly name in server response was corrupted" ); - } imcb_log( ic, "Authenticated, getting buddy list" ); @@ -566,6 +552,9 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) imc_logout( ic, allow_reconnect ); return( 0 ); } +#if 0 + /* Discard this one completely for now since I don't care about the ack + and since MSN servers can apparently screw up the formatting. */ else if( strcmp( cmd[0], "REA" ) == 0 ) { if( num_parts != 5 ) @@ -596,6 +585,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) imcb_rename_buddy( ic, cmd[3], cmd[4] ); } } +#endif else if( strcmp( cmd[0], "IPG" ) == 0 ) { imcb_error( ic, "Received IPG command, we don't handle them yet." ); @@ -745,3 +735,48 @@ static void msn_auth_got_passport_token( struct msn_auth_data *mad ) imc_logout( ic, TRUE ); } } + +static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name ) +{ + set_t *s; + + if( ( s = set_find( &ic->acc->set, "display_name" ) ) == NULL ) + return FALSE; /* Shouldn't happen.. */ + + http_decode( name ); + + if( s->value && strcmp( s->value, name ) == 0 ) + { + return TRUE; + /* The names match, nothing to worry about. */ + } + else if( s->value != NULL && + ( strcmp( name, ic->acc->user ) == 0 || + set_getbool( &ic->acc->set, "local_display_name" ) ) ) + { + /* The server thinks our display name is our e-mail address + which is probably wrong, or the user *wants* us to do this: + Always use the locally set display_name. */ + return msn_set_display_name( ic, s->value ); + } + else + { + if( s->value && *s->value ) + imcb_log( ic, "BitlBee thinks your display name is `%s' but " + "the MSN server says it's `%s'. Using the MSN " + "server's name. Set local_display_name to true " + "to use the local name.", s->value, name ); + + if( g_utf8_validate( name, -1, NULL ) ) + { + g_free( s->value ); + s->value = g_strdup( name ); + } + else + { + imcb_log( ic, "Warning: Friendly name in server response was corrupted" ); + } + + return TRUE; + } +} diff --git a/protocols/nogaim.c b/protocols/nogaim.c index f7db5c37..74ec0642 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -126,6 +126,7 @@ void nogaim_init() extern void oscar_initmodule(); extern void byahoo_initmodule(); extern void jabber_initmodule(); + extern void twitter_initmodule(); #ifdef WITH_MSN msn_initmodule(); @@ -143,6 +144,10 @@ void nogaim_init() jabber_initmodule(); #endif +#ifdef WITH_TWITTER + twitter_initmodule(); +#endif + #ifdef WITH_PLUGINS load_plugins(); #endif @@ -559,6 +564,37 @@ struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle ) return NULL; } +void imcb_chat_name_hint( struct groupchat *c, const char *name ) +{ +#if 0 + if( !c->joined ) + { + struct im_connection *ic = c->ic; + char stripped[MAX_NICK_LENGTH+1], *full_name; + + strncpy( stripped, name, MAX_NICK_LENGTH ); + stripped[MAX_NICK_LENGTH] = '\0'; + nick_strip( stripped ); + if( set_getbool( &ic->irc->set, "lcnicks" ) ) + nick_lc( stripped ); + + full_name = g_strdup_printf( "&%s", stripped ); + + if( stripped[0] && + nick_cmp( stripped, ic->irc->channel + 1 ) != 0 && + irc_chat_by_channel( ic->irc, full_name ) == NULL ) + { + g_free( c->channel ); + c->channel = full_name; + } + else + { + g_free( full_name ); + } + } +#endif +} + void imcb_chat_free( struct groupchat *c ) { #if 0 @@ -622,7 +658,11 @@ void imcb_chat_msg( struct groupchat *c, const char *who, char *msg, uint32_t fl wrapped = word_wrap( msg, 425 ); if( c && u ) { - irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, "", wrapped ); + char *ts = NULL; + if( set_getbool( &ic->irc->set, "display_timestamps" ) ) + ts = format_timestamp( ic->irc, sent_at ); + irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, ts ? : "", wrapped ); + g_free( ts ); } else { @@ -825,8 +865,6 @@ char *set_eval_away_devoice( set_t *set, char *value ) } #endif - - /* The plan is to not allow straight calls to prpl functions anymore, but do them all from some wrappers. We'll start to define some down here: */ @@ -852,6 +890,10 @@ int imc_away_send_update( struct im_connection *ic ) { char *away, *msg = NULL; + if( ic->acc->prpl->away_states == NULL || + ic->acc->prpl->set_away == NULL ) + return 0; + away = set_getstr( &ic->acc->set, "away" ) ? : set_getstr( &ic->bee->set, "away" ); if( away && *away ) diff --git a/protocols/nogaim.h b/protocols/nogaim.h index a93dc5d2..6632827c 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -298,6 +298,7 @@ G_MODULE_EXPORT void imcb_chat_invited( struct im_connection *ic, char *handle, * the user her/himself. At that point the group chat will be visible to the * user, too. */ G_MODULE_EXPORT struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle ); +G_MODULE_EXPORT void imcb_chat_name_hint( struct groupchat *c, const char *name ); G_MODULE_EXPORT void imcb_chat_add_buddy( struct groupchat *b, const char *handle ); /* To remove a handle from a group chat. Reason can be NULL. */ G_MODULE_EXPORT void imcb_chat_remove_buddy( struct groupchat *b, const char *handle, const char *reason ); diff --git a/protocols/twitter/Makefile b/protocols/twitter/Makefile new file mode 100644 index 00000000..ca1e4695 --- /dev/null +++ b/protocols/twitter/Makefile @@ -0,0 +1,43 @@ +########################### +## Makefile for BitlBee ## +## ## +## Copyright 2002 Lintux ## +########################### + +### DEFINITIONS + +-include ../../Makefile.settings + +# [SH] Program variables +objects = twitter.o twitter_http.o twitter_lib.o + +CFLAGS += -Wall +LFLAGS += -r + +# [SH] Phony targets +all: twitter_mod.o +check: all +lcov: check +gcov: + gcov *.c + +.PHONY: all clean distclean + +clean: + rm -f *.o core + +distclean: clean + +### MAIN PROGRAM + +$(objects): ../../Makefile.settings Makefile + +$(objects): %.o: %.c + @echo '*' Compiling $< + @$(CC) -c $(CFLAGS) $< -o $@ + +twitter_mod.o: $(objects) + @echo '*' Linking twitter_mod.o + @$(LD) $(LFLAGS) $(objects) -o twitter_mod.o + + diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c new file mode 100644 index 00000000..727eff91 --- /dev/null +++ b/protocols/twitter/twitter.c @@ -0,0 +1,232 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple module to facilitate twitter functionality. * +* * +* Copyright 2009 Geert Mulders <g.c.w.m.mulders@gmail.com> * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public * +* License as published by the Free Software Foundation, version * +* 2.1. * +* * +* This library is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +* Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * +* * +****************************************************************************/ + +#include "nogaim.h" +#include "twitter.h" +#include "twitter_http.h" +#include "twitter_lib.h" + + +/** + * Main loop function + */ +gboolean twitter_main_loop(gpointer data, gint fd, b_input_condition cond) +{ + struct im_connection *ic = data; + + // Check if we are still logged in... + 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 (!set_getbool( &ic->acc->set, "use_groupchat" )) + twitter_get_statuses_friends(ic, -1); + + // Do stuff.. + twitter_get_home_timeline(ic, -1); + + // If we are still logged in run this function again after timeout. + return (ic->flags & OPT_LOGGED_IN) == OPT_LOGGED_IN; +} + + +static void twitter_init( account_t *acc ) +{ + set_t *s; + s = set_add( &acc->set, "use_groupchat", "false", set_eval_bool, acc ); + s->flags |= ACC_SET_OFFLINE_ONLY; +} + +/** + * Login method. Since the twitter API works with seperate HTTP request we + * only save the user and pass to the twitter_data object. + */ +static void twitter_login( account_t *acc ) +{ + struct im_connection *ic = imcb_new( acc ); + struct twitter_data *td = g_new0( struct twitter_data, 1 ); + + twitter_connections = g_slist_append( twitter_connections, ic ); + + td->user = acc->user; + td->pass = acc->pass; + td->home_timeline_id = 0; + + ic->proto_data = td; + + imcb_log( ic, "Connecting to Twitter" ); + + // Run this once. After this queue the main loop function. + twitter_main_loop(ic, -1, 0); + + // 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); +} + +/** + * Logout method. Just free the twitter_data. + */ +static void twitter_logout( struct im_connection *ic ) +{ + struct twitter_data *td = ic->proto_data; + + // Set the status to logged out. + ic->flags = 0; + + // 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 ) + { + g_free( td ); + } + + twitter_connections = g_slist_remove( twitter_connections, ic ); +} + +/** + * + */ +static int twitter_buddy_msg( struct im_connection *ic, char *who, char *message, int away ) +{ + // 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 ); +} + +/** + * + */ +static void twitter_set_my_name( struct im_connection *ic, char *info ) +{ +} + +static void twitter_get_info(struct im_connection *ic, char *who) +{ +} + +static void twitter_add_buddy( struct im_connection *ic, char *who, char *group ) +{ +} + +static void twitter_remove_buddy( struct im_connection *ic, char *who, char *group ) +{ +} + +static void twitter_chat_msg( struct groupchat *c, char *message, int flags ) +{ + if( c && message ) + twitter_post_status(c->ic, message); +} + +static void twitter_chat_invite( struct groupchat *c, char *who, char *message ) +{ +} + +static void twitter_chat_leave( struct groupchat *c ) +{ + struct twitter_data *td = c->ic->proto_data; + + if( c != td->home_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; +} + +static struct groupchat *twitter_chat_with( struct im_connection *ic, char *who ) +{ + return NULL; +} + +static void twitter_keepalive( struct im_connection *ic ) +{ +} + +static void twitter_add_permit( struct im_connection *ic, char *who ) +{ +} + +static void twitter_rem_permit( struct im_connection *ic, char *who ) +{ +} + +static void twitter_add_deny( struct im_connection *ic, char *who ) +{ +} + +static void twitter_rem_deny( struct im_connection *ic, char *who ) +{ +} + +static int twitter_send_typing( struct im_connection *ic, char *who, int typing ) +{ + return( 1 ); +} + +//static char *twitter_set_display_name( set_t *set, char *value ) +//{ +// return value; +//} + +void twitter_initmodule() +{ + struct prpl *ret = g_new0(struct prpl, 1); + + ret->name = "twitter"; + ret->login = twitter_login; + ret->init = twitter_init; + ret->logout = twitter_logout; + ret->buddy_msg = twitter_buddy_msg; + ret->get_info = twitter_get_info; + ret->set_my_name = twitter_set_my_name; + ret->add_buddy = twitter_add_buddy; + ret->remove_buddy = twitter_remove_buddy; + ret->chat_msg = twitter_chat_msg; + ret->chat_invite = twitter_chat_invite; + ret->chat_leave = twitter_chat_leave; + ret->chat_with = twitter_chat_with; + ret->keepalive = twitter_keepalive; + ret->add_permit = twitter_add_permit; + ret->rem_permit = twitter_rem_permit; + ret->add_deny = twitter_add_deny; + ret->rem_deny = twitter_rem_deny; + ret->send_typing = twitter_send_typing; + 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 new file mode 100644 index 00000000..88caa104 --- /dev/null +++ b/protocols/twitter/twitter.h @@ -0,0 +1,52 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple module to facilitate twitter functionality. * +* * +* Copyright 2009 Geert Mulders <g.c.w.m.mulders@gmail.com> * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public * +* License as published by the Free Software Foundation, version * +* 2.1. * +* * +* This library is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +* Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * +* * +****************************************************************************/ + +#include "nogaim.h" + +#ifndef _TWITTER_H +#define _TWITTER_H + +#ifdef DEBUG_TWITTER +#define debug( text... ) imcb_log( ic, text ); +#else +#define debug( text... ) +#endif + +struct twitter_data +{ + char* user; + char* pass; + guint64 home_timeline_id; + gint main_loop_id; + struct groupchat *home_timeline_gc; + gint http_fails; +}; + +/** + * 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_http.c b/protocols/twitter/twitter_http.c new file mode 100644 index 00000000..3632140f --- /dev/null +++ b/protocols/twitter/twitter_http.c @@ -0,0 +1,161 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple module to facilitate twitter functionality. * +* * +* Copyright 2009 Geert Mulders <g.c.w.m.mulders@gmail.com> * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public * +* License as published by the Free Software Foundation, version * +* 2.1. * +* * +* This library is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +* Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * +* * +****************************************************************************/ + +/***************************************************************************\ +* * +* Some funtions within this file have been copied from other files within * +* BitlBee. * +* * +****************************************************************************/ + +#include "twitter_http.h" +#include "twitter.h" +#include "bitlbee.h" +#include "url.h" +#include "misc.h" +#include "base64.h" +#include <ctype.h> +#include <errno.h> + + +char *twitter_url_append(char *url, char *key, char* value); + +/** + * Do a request. + * This is actually pretty generic function... Perhaps it should move to the lib/http_client.c + */ +void *twitter_http(char *url_string, http_input_function func, gpointer data, int is_post, char* user, char* pass, char** arguments, int arguments_len) +{ + url_t *url = g_new0( url_t, 1 ); + char *tmp; + char *request; + void *ret; + char *userpass = NULL; + char *userpass_base64; + char *url_arguments; + + // Fill the url structure. + if( !url_set( url, url_string ) ) + { + g_free( url ); + return NULL; + } + + if( url->proto != PROTO_HTTP && url->proto != PROTO_HTTPS ) + { + g_free( url ); + return NULL; + } + + // Concatenate user and pass + if (user && pass) { + userpass = g_strdup_printf("%s:%s", user, pass); + userpass_base64 = base64_encode((unsigned char*)userpass, strlen(userpass)); + } else { + userpass_base64 = NULL; + } + + url_arguments = g_malloc(1); + url_arguments[0] = '\0'; + + // Construct the url arguments. + if (arguments_len != 0) + { + int i; + for (i=0; i<arguments_len; i+=2) + { + tmp = twitter_url_append(url_arguments, arguments[i], arguments[i+1]); + g_free(url_arguments); + url_arguments = tmp; + } + } + + // Do GET stuff... + if (!is_post) + { + // Find the char-pointer of the end of the string. + tmp = url->file + strlen(url->file); + tmp[0] = '?'; + // append the url_arguments to the end of the url->file. + // TODO GM: Check the length? + g_stpcpy (tmp+1, url_arguments); + } + + + // Make the request. + request = g_strdup_printf( "%s %s HTTP/1.0\r\n" + "Host: %s\r\n" + "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n", + is_post ? "POST" : "GET", url->file, url->host ); + + // If a pass and user are given we append them to the request. + if (userpass_base64) + { + tmp = g_strdup_printf("%sAuthorization: Basic %s\r\n", request, userpass_base64); + g_free(request); + request = tmp; + } + + // Do POST stuff.. + if (is_post) + { + // Append the Content-Type and url-encoded arguments. + tmp = g_strdup_printf("%sContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %zd\r\n\r\n%s", + request, strlen(url_arguments), url_arguments); + g_free(request); + request = tmp; + } else { + // Append an extra \r\n to end the request... + tmp = g_strdup_printf("%s\r\n", request); + g_free(request); + request = tmp; + } + + ret = http_dorequest( url->host, url->port, url->proto == PROTO_HTTPS, request, func, data ); + + g_free( url ); + g_free( userpass ); + g_free( userpass_base64 ); + g_free( url_arguments ); + g_free( request ); + return ret; +} + +char *twitter_url_append(char *url, char *key, char* value) +{ + char *key_encoded = g_strndup(key, 3 * strlen(key)); + http_encode(key_encoded); + char *value_encoded = g_strndup(value, 3 * strlen(value)); + http_encode(value_encoded); + + char *retval; + if (strlen(url) != 0) + retval = g_strdup_printf("%s&%s=%s", url, key_encoded, value_encoded); + else + retval = g_strdup_printf("%s=%s", key_encoded, value_encoded); + + g_free(key_encoded); + g_free(value_encoded); + + return retval; +} diff --git a/protocols/twitter/twitter_http.h b/protocols/twitter/twitter_http.h new file mode 100644 index 00000000..ec4a0b7c --- /dev/null +++ b/protocols/twitter/twitter_http.h @@ -0,0 +1,34 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple module to facilitate twitter functionality. * +* * +* Copyright 2009 Geert Mulders <g.c.w.m.mulders@gmail.com> * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public * +* License as published by the Free Software Foundation, version * +* 2.1. * +* * +* This library is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +* Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * +* * +****************************************************************************/ + +#ifndef _TWITTER_HTTP_H +#define _TWITTER_HTTP_H + +#include "nogaim.h" +#include "http_client.h" + +void *twitter_http(char *url_string, http_input_function func, gpointer data, int is_post, + char* user, char* pass, char** arguments, int arguments_len); + +#endif //_TWITTER_HTTP_H + diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c new file mode 100644 index 00000000..b6863c02 --- /dev/null +++ b/protocols/twitter/twitter_lib.c @@ -0,0 +1,650 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple module to facilitate twitter functionality. * +* * +* Copyright 2009 Geert Mulders <g.c.w.m.mulders@gmail.com> * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public * +* License as published by the Free Software Foundation, version * +* 2.1. * +* * +* This library is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +* Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * +* * +****************************************************************************/ + +/* For strptime(): */ +#define _XOPEN_SOURCE + +#include "twitter_http.h" +#include "twitter.h" +#include "bitlbee.h" +#include "url.h" +#include "misc.h" +#include "base64.h" +#include "xmltree.h" +#include "twitter_lib.h" +#include <ctype.h> +#include <errno.h> + +#define TXL_STATUS 1 +#define TXL_USER 2 +#define TXL_ID 3 + +struct twitter_xml_list { + int type; + int next_cursor; + GSList *list; + gpointer data; +}; + +struct twitter_xml_user { + char *name; + char *screen_name; +}; + +struct twitter_xml_status { + time_t created_at; + char *text; + struct twitter_xml_user *user; + guint64 id; +}; + +/** + * Frees a twitter_xml_user struct. + */ +static void txu_free(struct twitter_xml_user *txu) +{ + 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) +{ + g_free(txs->text); + txu_free(txs->user); + g_free(txs); +} + +/** + * 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, const char *fullname) +{ + struct twitter_data *td = ic->proto_data; + + // Check if the buddy is allready in the buddy list. + if (!bee_user_by_handle( ic->bee, 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_rename_buddy( ic, name, fullname ); + if (set_getbool( &ic->acc->set, "use_groupchat" )) + imcb_chat_add_buddy( td->home_timeline_gc, name ); + else + imcb_buddy_status( ic, name, OPT_LOGGED_IN, NULL, NULL ); + } +} + +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) +{ + struct twitter_data *td = ic->proto_data; + + // Primitive, but hey! It works... + char* args[2]; + args[0] = "cursor"; + args[1] = g_strdup_printf ("%d", next_cursor); + twitter_http(TWITTER_FRIENDS_IDS_URL, twitter_http_get_friends_ids, ic, 0, td->user, td->pass, args, 2); + + g_free(args[1]); +} + +/** + * Function to help fill a list. + */ +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; + + return XT_HANDLED; +} + +/** + * Fill a list of ids. + */ +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. + for( child = node->children ; child ; child = child->next ) + { + if ( g_strcasecmp( "id", child->name ) == 0) + { + // Add the item to the list. + txl->list = g_slist_append (txl->list, g_memdup( child->text, child->text_len + 1 )); + } + else if ( g_strcasecmp( "next_cursor", child->name ) == 0) + { + twitter_xt_next_cursor(child, txl); + } + } + + return XT_HANDLED; +} + +/** + * Callback for getting the friends ids. + */ +static void twitter_http_get_friends_ids(struct http_request *req) +{ + struct im_connection *ic; + struct xt_parser *parser; + struct twitter_xml_list *txl; + struct twitter_data *td; + + ic = req->data; + + // 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) { + // It didn't go well, output the error and return. + if (++td->http_fails >= 5) + imcb_error(ic, "Could not retrieve friends. HTTP STATUS: %d", req->status_code); + + return; + } else { + td->http_fails = 0; + } + + txl = g_new0(struct twitter_xml_list, 1); + + // Parse the data. + parser = xt_new( NULL, txl ); + xt_feed( parser, req->reply_body, req->body_size ); + twitter_xt_get_friends_id_list(parser->root, txl); + xt_free( parser ); + + if (txl->next_cursor) + twitter_get_friends_ids(ic, txl->next_cursor); + + txl_free(txl); + g_free(txl); +} + +/** + * Function to fill a twitter_xml_user struct. + * It sets: + * - the name and + * - the screen_name. + */ +static xt_status twitter_xt_get_user( struct xt_node *node, struct twitter_xml_user *txu ) +{ + struct xt_node *child; + + // Walk over the nodes children. + for( child = node->children ; child ; child = child->next ) + { + if ( g_strcasecmp( "name", child->name ) == 0) + { + txu->name = g_memdup( child->text, child->text_len + 1 ); + } + else if (g_strcasecmp( "screen_name", child->name ) == 0) + { + txu->screen_name = g_memdup( child->text, child->text_len + 1 ); + } + } + return XT_HANDLED; +} + +/** + * 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 + * - the created_at timestamp and + * - the status id and + * - the user in a twitter_xml_user struct. + */ +static xt_status twitter_xt_get_status( struct xt_node *node, struct twitter_xml_status *txs ) +{ + struct xt_node *child; + + // 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( "created_at", child->name ) == 0) + { + struct tm parsed; + + /* Very sensitive to changes to the formatting of + this field. :-( Also assumes the timezone used + is UTC since C time handling functions suck. */ + if( strptime( child->text, "%a %b %d %H:%M:%S %z %Y", &parsed ) != NULL ) + txs->created_at = mktime_utc( &parsed ); + } + else if (g_strcasecmp( "user", child->name ) == 0) + { + txs->user = g_new0(struct twitter_xml_user, 1); + twitter_xt_get_user( child, txs->user ); + } + else if (g_strcasecmp( "id", child->name ) == 0) + { + txs->id = g_ascii_strtoull (child->text, NULL, 10); + } + } + return XT_HANDLED; +} + +/** + * Function to fill a twitter_xml_list struct. + * It sets: + * - all <status>es within the <status> element and + * - the next_cursor. + */ +static xt_status twitter_xt_get_status_list( struct xt_node *node, struct twitter_xml_list *txl ) +{ + 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 ) + { + if ( g_strcasecmp( "status", child->name ) == 0) + { + txs = g_new0(struct twitter_xml_status, 1); + twitter_xt_get_status(child, txs); + // Put the item in the front of the list. + txl->list = g_slist_prepend (txl->list, txs); + } + else if ( g_strcasecmp( "next_cursor", child->name ) == 0) + { + twitter_xt_next_cursor(child, txl); + } + } + + 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, int next_cursor) +{ + struct twitter_data *td = ic->proto_data; + + char* args[4]; + args[0] = "cursor"; + args[1] = g_strdup_printf ("%d", 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(TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, td->user, td->pass, args, td->home_timeline_id ? 4 : 2); + + g_free(args[1]); + if (td->home_timeline_id) { + g_free(args[3]); + } +} + +/** + * 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) + { + 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... + 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, status->user->name); + + // Say it! + if (g_strcasecmp(td->user, status->user->screen_name) == 0) + imcb_chat_log (gc, "Your Tweet: %s", status->text); + else + imcb_chat_msg (gc, status->user->screen_name, status->text, 0, status->created_at ); + + // 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, status->created_at ); + // 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 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 ); + return; + } + else + { + // It didn't go well, output the error and return. + if (++td->http_fails >= 5) + imcb_error(ic, "Could not retrieve " TWITTER_HOME_TIMELINE_URL ". 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 ); + // The root <statuses> node should hold the list of statuses <status> + twitter_xt_get_status_list(parser->root, txl); + xt_free( parser ); + + // 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 + twitter_private_message_chat(ic, txl->list); + + // Free the structure. + txl_free(txl); + g_free(txl); +} + +/** + * 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! + */ +static void twitter_http_get_statuses_friends(struct http_request *req) +{ + struct im_connection *ic = req->data; + struct twitter_data *td; + struct xt_parser *parser; + struct twitter_xml_list *txl; + GSList *l = NULL; + struct twitter_xml_user *user; + + // 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) { + // 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 " HTTP STATUS: %d", req->status_code); + + return; + } else { + td->http_fails = 0; + } + + 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 ); + + // Add the users as buddies. + for ( l = txl->list; l ; l = g_slist_next(l) ) + { + user = l->data; + twitter_add_buddy(ic, user->screen_name, user->name); + } + + // 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); +} + +/** + * Get the friends. + */ +void twitter_get_statuses_friends(struct im_connection *ic, int next_cursor) +{ + 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]); +} + +/** + * Callback after sending a new update to twitter. + */ +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. + imcb_error(ic, "Could not post tweet... HTTP STATUS: %d", req->status_code); + return; + } +} + +/** + * Function to POST a new status to twitter. + */ +void twitter_post_status(struct im_connection *ic, char* msg) +{ + struct twitter_data *td = ic->proto_data; + + char* args[2]; + 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]); +} + + +/** + * 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]); +} diff --git a/protocols/twitter/twitter_lib.h b/protocols/twitter/twitter_lib.h new file mode 100644 index 00000000..e47bfd95 --- /dev/null +++ b/protocols/twitter/twitter_lib.h @@ -0,0 +1,86 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple module to facilitate twitter functionality. * +* * +* Copyright 2009 Geert Mulders <g.c.w.m.mulders@gmail.com> * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public * +* License as published by the Free Software Foundation, version * +* 2.1. * +* * +* This library is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +* Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * +* * +****************************************************************************/ + + +#ifndef _TWITTER_LIB_H +#define _TWITTER_LIB_H + +#include "nogaim.h" +#include "twitter_http.h" + +#define TWITTER_API_URL "http://twitter.com" + +/* Status URLs */ +#define TWITTER_STATUS_UPDATE_URL TWITTER_API_URL "/statuses/update.xml" +#define TWITTER_STATUS_SHOW_URL TWITTER_API_URL "/statuses/show/" +#define TWITTER_STATUS_DESTROY_URL TWITTER_API_URL "/statuses/destroy/" + +/* Timeline URLs */ +#define TWITTER_PUBLIC_TIMELINE_URL TWITTER_API_URL "/statuses/public_timeline.xml" +#define TWITTER_FEATURED_USERS_URL TWITTER_API_URL "/statuses/featured.xml" +#define TWITTER_FRIENDS_TIMELINE_URL TWITTER_API_URL "/statuses/friends_timeline.xml" +#define TWITTER_HOME_TIMELINE_URL TWITTER_API_URL "/statuses/home_timeline.xml" +#define TWITTER_MENTIONS_URL TWITTER_API_URL "/statuses/mentions.xml" +#define TWITTER_USER_TIMELINE_URL TWITTER_API_URL "/statuses/user_timeline.xml" + +/* Users URLs */ +#define TWITTER_SHOW_USERS_URL TWITTER_API_URL "/users/show.xml" +#define TWITTER_SHOW_FRIENDS_URL TWITTER_API_URL "/statuses/friends.xml" +#define TWITTER_SHOW_FOLLOWERS_URL TWITTER_API_URL "/statuses/followers.xml" + +/* Direct messages URLs */ +#define TWITTER_DIRECT_MESSAGES_URL TWITTER_API_URL "/direct_messages.xml" +#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" +#define TWITTER_FRIENDSHIPS_DESTROY_URL TWITTER_API_URL "/friendships/destroy.xml" +#define TWITTER_FRIENDSHIPS_SHOW_URL TWITTER_API_URL "/friendships/show.xml" + +/* Social graphs URLs */ +#define TWITTER_FRIENDS_IDS_URL TWITTER_API_URL "/friends/ids.xml" +#define TWITTER_FOLLOWERS_IDS_URL TWITTER_API_URL "/followers/ids.xml" + +/* Account URLs */ +#define TWITTER_ACCOUNT_RATE_LIMIT_URL TWITTER_API_URL "/account/rate_limit_status.xml" + +/* Favorites URLs */ +#define TWITTER_FAVORITES_GET_URL TWITTER_API_URL "/favorites.xml" +#define TWITTER_FAVORITE_CREATE_URL TWITTER_API_URL "/favorites/create/" +#define TWITTER_FAVORITE_DESTROY_URL TWITTER_API_URL "/favorites/destroy/" + +/* Block URLs */ +#define TWITTER_BLOCKS_CREATE_URL TWITTER_API_URL "/blocks/create/" +#define TWITTER_BLOCKS_DESTROY_URL TWITTER_API_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_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 + |