source: protocols/twitter/twitter.c @ 7d53efb

Last change on this file since 7d53efb was 7d53efb, checked in by Geert Mulders <g.c.w.m.mulders@…>, at 2010-05-29T12:40:17Z

Added functionality to add and remove friendships.

  • Property mode set to 100644
File size: 10.1 KB
RevLine 
[1b221e0]1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  Simple module to facilitate twitter functionality.                       *
5*                                                                           *
6*  Copyright 2009 Geert Mulders <g.c.w.m.mulders@gmail.com>                 *
7*                                                                           *
8*  This library is free software; you can redistribute it and/or            *
9*  modify it under the terms of the GNU Lesser General Public               *
10*  License as published by the Free Software Foundation, version            *
11*  2.1.                                                                     *
12*                                                                           *
13*  This library is distributed in the hope that it will be useful,          *
14*  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
15*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        *
16*  Lesser General Public License for more details.                          *
17*                                                                           *
18*  You should have received a copy of the GNU Lesser General Public License *
19*  along with this library; if not, write to the Free Software Foundation,  *
20*  Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA           *
21*                                                                           *
22****************************************************************************/
23
24#include "nogaim.h"
[713d611]25#include "oauth.h"
[1b221e0]26#include "twitter.h"
27#include "twitter_http.h"
28#include "twitter_lib.h"
29
30/**
[62d2cfb]31 * Main loop function
32 */
[1b221e0]33gboolean twitter_main_loop(gpointer data, gint fd, b_input_condition cond)
34{
35        struct im_connection *ic = data;
[3e69802]36       
[1b221e0]37        // Check if we are still logged in...
[3bd4a93]38        if (!g_slist_find( twitter_connections, ic ))
[1b221e0]39                return 0;
40
[62d2cfb]41        // If the user uses multiple private message windows we need to get the
42        // users buddies.
[e88fbe27]43        if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "many") == 0)
[62d2cfb]44                twitter_get_statuses_friends(ic, -1);
45
[1b221e0]46        // Do stuff..
47        twitter_get_home_timeline(ic, -1);
48
49        // If we are still logged in run this function again after timeout.
50        return (ic->flags & OPT_LOGGED_IN) == OPT_LOGGED_IN;
51}
52
[713d611]53static void twitter_main_loop_start( struct im_connection *ic )
54{
55        struct twitter_data *td = ic->proto_data;
56       
57        imcb_log( ic, "Connecting to Twitter" );
58
59        // Run this once. After this queue the main loop function.
60        twitter_main_loop(ic, -1, 0);
61
62        // Queue the main_loop
63        // Save the return value, so we can remove the timeout on logout.
64        td->main_loop_id = b_timeout_add(60000, twitter_main_loop, ic);
65}
66
[c2ecadc]67
[3b878a1]68static const struct oauth_service twitter_oauth =
[c2ecadc]69{
70        "http://api.twitter.com/oauth/request_token",
71        "http://api.twitter.com/oauth/access_token",
72        "http://api.twitter.com/oauth/authorize",
73        .consumer_key = "xsDNKJuNZYkZyMcu914uEA",
74        .consumer_secret = "FCxqcr0pXKzsF9ajmP57S3VQ8V6Drk4o2QYtqMcOszo",
75};
76
[18dbb20]77static gboolean twitter_oauth_callback( struct oauth_info *info );
[713d611]78
79static void twitter_oauth_start( struct im_connection *ic )
80{
[18dbb20]81        struct twitter_data *td = ic->proto_data;
82       
[c42e8b9]83        imcb_log( ic, "Requesting OAuth request token" );
84
[c2ecadc]85        td->oauth_info = oauth_request_token( &twitter_oauth, twitter_oauth_callback, ic );
[713d611]86}
87
[18dbb20]88static gboolean twitter_oauth_callback( struct oauth_info *info )
[713d611]89{
90        struct im_connection *ic = info->data;
[18dbb20]91        struct twitter_data *td;
[713d611]92       
[18dbb20]93        if( !g_slist_find( twitter_connections, ic ) )
94                return FALSE;
95       
96        td = ic->proto_data;
[c42e8b9]97        if( info->stage == OAUTH_REQUEST_TOKEN )
[713d611]98        {
99                char name[strlen(ic->acc->user)+9], *msg;
100               
[c42e8b9]101                if( info->request_token == NULL )
102                {
103                        imcb_error( ic, "OAuth error: %s", info->http->status_string );
104                        imc_logout( ic, TRUE );
[18dbb20]105                        return FALSE;
[c42e8b9]106                }
107               
[713d611]108                sprintf( name, "twitter_%s", ic->acc->user );
109                msg = g_strdup_printf( "To finish OAuth authentication, please visit "
[c2ecadc]110                                       "%s and respond with the resulting PIN code.",
111                                       info->auth_url );
[713d611]112                imcb_buddy_msg( ic, name, msg, 0, 0 );
113                g_free( msg );
114        }
[c42e8b9]115        else if( info->stage == OAUTH_ACCESS_TOKEN )
116        {
[3b878a1]117                if( info->token == NULL || info->token_secret == NULL )
[c42e8b9]118                {
119                        imcb_error( ic, "OAuth error: %s", info->http->status_string );
120                        imc_logout( ic, TRUE );
[18dbb20]121                        return FALSE;
[c42e8b9]122                }
123               
[288b215]124                /* IM mods didn't do this so far and it's ugly but I should
125                   be able to get away with it... */
126                g_free( ic->acc->pass );
[f4b0911]127                ic->acc->pass = oauth_to_string( info );
[288b215]128               
[c42e8b9]129                twitter_main_loop_start( ic );
130        }
[18dbb20]131       
132        return TRUE;
[713d611]133}
134
[c2ecadc]135
[e88fbe27]136static char *set_eval_mode( set_t *set, char *value )
137{
138        if( g_strcasecmp( value, "one" ) == 0 ||
139            g_strcasecmp( value, "many" ) == 0 ||
[db57e7c]140            g_strcasecmp( value, "chat" ) == 0 )
[e88fbe27]141                return value;
142        else
143                return NULL;
144}
[1b221e0]145
[9997691]146static gboolean twitter_length_check( struct im_connection *ic, gchar *msg )
147{
148        int max = set_getint( &ic->acc->set, "message_length" ), len;
149       
150        if( max == 0 || ( len = g_utf8_strlen( msg, -1 ) ) <= max )
151                return TRUE;
152       
153        imcb_error( ic, "Maximum message length exceeded: %d > %d", len, max );
154       
155        return FALSE;
156}
157
[1b221e0]158static void twitter_init( account_t *acc )
159{
[62d2cfb]160        set_t *s;
[e88fbe27]161       
[9997691]162        s = set_add( &acc->set, "message_length", "140", set_eval_int, acc );
163       
[e88fbe27]164        s = set_add( &acc->set, "mode", "one", set_eval_mode, acc );
[2abceca]165        s->flags |= ACC_SET_OFFLINE_ONLY;
[713d611]166       
167        s = set_add( &acc->set, "oauth", "true", set_eval_bool, acc );
[1b221e0]168}
169
170/**
171 * Login method. Since the twitter API works with seperate HTTP request we
172 * only save the user and pass to the twitter_data object.
173 */
174static void twitter_login( account_t *acc )
175{
176        struct im_connection *ic = imcb_new( acc );
177        struct twitter_data *td = g_new0( struct twitter_data, 1 );
[e88fbe27]178        char name[strlen(acc->user)+9];
[62d2cfb]179
[d569019]180        twitter_connections = g_slist_append( twitter_connections, ic );
[713d611]181        ic->proto_data = td;
[a7c6d0e]182        ic->flags |= OPT_DOES_HTML;
[713d611]183       
[1b221e0]184        td->user = acc->user;
[713d611]185        if( !set_getbool( &acc->set, "oauth" ) )
[508c340]186                td->pass = g_strdup( acc->pass );
[713d611]187        else if( strstr( acc->pass, "oauth_token=" ) )
[f4b0911]188                td->oauth_info = oauth_from_string( acc->pass, &twitter_oauth );
[1b221e0]189        td->home_timeline_id = 0;
[e88fbe27]190       
191        sprintf( name, "twitter_%s", acc->user );
192        imcb_add_buddy( ic, name, NULL );
193        imcb_buddy_status( ic, name, OPT_LOGGED_IN, NULL, NULL );
[713d611]194       
[c2ecadc]195        if( td->pass || td->oauth_info )
[713d611]196                twitter_main_loop_start( ic );
197        else
198                twitter_oauth_start( ic );
[1b221e0]199}
200
201/**
202 * Logout method. Just free the twitter_data.
203 */
204static void twitter_logout( struct im_connection *ic )
205{
206        struct twitter_data *td = ic->proto_data;
207       
208        // Set the status to logged out.
209        ic->flags = 0;
210
[2abceca]211        // Remove the main_loop function from the function queue.
212        b_event_remove(td->main_loop_id);
213
[37d84b3]214        if(td->home_timeline_gc)
215                imcb_chat_free(td->home_timeline_gc);
[1014cab]216
[1b221e0]217        if( td )
218        {
[18dbb20]219                oauth_info_free( td->oauth_info );
[508c340]220                g_free( td->pass );
[1b221e0]221                g_free( td );
222        }
[62d2cfb]223
224        twitter_connections = g_slist_remove( twitter_connections, ic );
[1b221e0]225}
226
227/**
228 *
229 */
230static int twitter_buddy_msg( struct im_connection *ic, char *who, char *message, int away )
231{
[c42e8b9]232        struct twitter_data *td = ic->proto_data;
233       
[e88fbe27]234        if (g_strncasecmp(who, "twitter_", 8) == 0 &&
235            g_strcasecmp(who + 8, ic->acc->user) == 0)
[c42e8b9]236        {
[c2ecadc]237                if( set_getbool( &ic->acc->set, "oauth" ) &&
238                    td->oauth_info && td->oauth_info->token == NULL )
[18dbb20]239                {
[c2ecadc]240                        if( !oauth_access_token( message, td->oauth_info ) )
241                        {
242                                imcb_error( ic, "OAuth error: %s", "Failed to send access token request" );
243                                imc_logout( ic, TRUE );
244                                return FALSE;
245                        }
[18dbb20]246                }
[9997691]247                else if( twitter_length_check(ic, message) )
[c42e8b9]248                        twitter_post_status(ic, message);
249        }
[e88fbe27]250        else
[c42e8b9]251        {
[e88fbe27]252                twitter_direct_messages_new(ic, who, message);
[c42e8b9]253        }
[1b221e0]254        return( 0 );
255}
256
257/**
258 *
259 */
260static void twitter_set_my_name( struct im_connection *ic, char *info )
261{
262}
263
264static void twitter_get_info(struct im_connection *ic, char *who) 
265{
266}
267
268static void twitter_add_buddy( struct im_connection *ic, char *who, char *group )
269{
[7d53efb]270        twitter_friendships_create_destroy(ic, who, 1);
[1b221e0]271}
272
273static void twitter_remove_buddy( struct im_connection *ic, char *who, char *group )
274{
[7d53efb]275        twitter_friendships_create_destroy(ic, who, 0);
[1b221e0]276}
277
278static void twitter_chat_msg( struct groupchat *c, char *message, int flags )
279{
[9997691]280        if( c && message && twitter_length_check(c->ic, message))
[2abceca]281                twitter_post_status(c->ic, message);
[1b221e0]282}
283
284static void twitter_chat_invite( struct groupchat *c, char *who, char *message )
285{
286}
287
288static void twitter_chat_leave( struct groupchat *c )
289{
[16592d8]290        struct twitter_data *td = c->ic->proto_data;
291       
292        if( c != td->home_timeline_gc )
293                return; /* WTF? */
294       
295        /* If the user leaves the channel: Fine. Rejoin him/her once new
296           tweets come in. */
297        imcb_chat_free(td->home_timeline_gc);
298        td->home_timeline_gc = NULL;
[1b221e0]299}
300
301static struct groupchat *twitter_chat_with( struct im_connection *ic, char *who )
302{
303        return NULL;
304}
305
306static void twitter_keepalive( struct im_connection *ic )
307{
308}
309
310static void twitter_add_permit( struct im_connection *ic, char *who )
311{
312}
313
314static void twitter_rem_permit( struct im_connection *ic, char *who )
315{
316}
317
318static void twitter_add_deny( struct im_connection *ic, char *who )
319{
320}
321
322static void twitter_rem_deny( struct im_connection *ic, char *who )
323{
324}
325
326static int twitter_send_typing( struct im_connection *ic, char *who, int typing )
327{
328        return( 1 );
329}
330
331//static char *twitter_set_display_name( set_t *set, char *value )
332//{
333//      return value;
334//}
335
336void twitter_initmodule()
337{
338        struct prpl *ret = g_new0(struct prpl, 1);
339       
340        ret->name = "twitter";
341        ret->login = twitter_login;
342        ret->init = twitter_init;
343        ret->logout = twitter_logout;
344        ret->buddy_msg = twitter_buddy_msg;
345        ret->get_info = twitter_get_info;
346        ret->set_my_name = twitter_set_my_name;
347        ret->add_buddy = twitter_add_buddy;
348        ret->remove_buddy = twitter_remove_buddy;
349        ret->chat_msg = twitter_chat_msg;
350        ret->chat_invite = twitter_chat_invite;
351        ret->chat_leave = twitter_chat_leave;
352        ret->chat_with = twitter_chat_with;
353        ret->keepalive = twitter_keepalive;
354        ret->add_permit = twitter_add_permit;
355        ret->rem_permit = twitter_rem_permit;
356        ret->add_deny = twitter_add_deny;
357        ret->rem_deny = twitter_rem_deny;
358        ret->send_typing = twitter_send_typing;
359        ret->handle_cmp = g_strcasecmp;
360
361        register_protocol(ret);
[62d2cfb]362
363        // Initialise the twitter_connections GSList.
364        twitter_connections = NULL;
[1b221e0]365}
366
Note: See TracBrowser for help on using the repository browser.