source: protocols/twitter/twitter_lib.c @ 7989d40d

Last change on this file since 7989d40d was 5c18a76, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-17T15:51:01Z

Store exact Twitter usernames for all Twitter contacts when using mode=chat,
so that xxx:->@xxx translation always works properly (even when the nick was
stripped/etc).

  • Property mode set to 100644
File size: 19.8 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
[08579a1]24/* For strptime(): */
25#define _XOPEN_SOURCE
26
[1b221e0]27#include "twitter_http.h"
28#include "twitter.h"
29#include "bitlbee.h"
30#include "url.h"
31#include "misc.h"
32#include "base64.h"
33#include "xmltree.h"
34#include "twitter_lib.h"
35#include <ctype.h>
36#include <errno.h>
37
[e4e0b37]38/* GLib < 2.12.0 doesn't have g_ascii_strtoll(), work around using system strtoll(). */
39/* GLib < 2.12.4 can be buggy: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=488013 */
40#if !GLIB_CHECK_VERSION(2,12,5)
41#include <stdlib.h>
42#include <limits.h>
43#define g_ascii_strtoll strtoll
44#endif
45
[1b221e0]46#define TXL_STATUS 1
[62d2cfb]47#define TXL_USER 2
48#define TXL_ID 3
49
[1b221e0]50struct twitter_xml_list {
[62d2cfb]51        int type;
[8203da9]52        gint64 next_cursor;
[1b221e0]53        GSList *list;
54        gpointer data;
55};
56
57struct twitter_xml_user {
58        char *name;
59        char *screen_name;
60};
61
62struct twitter_xml_status {
[08579a1]63        time_t created_at;
[1b221e0]64        char *text;
65        struct twitter_xml_user *user;
66        guint64 id;
67};
68
[d6aa6dd]69static void twitter_groupchat_init(struct im_connection *ic);
70
[62d2cfb]71/**
72 * Frees a twitter_xml_user struct.
73 */
74static void txu_free(struct twitter_xml_user *txu)
75{
[a26af5c]76        if (txu == NULL)
77                return;
[62d2cfb]78        g_free(txu->name);
79        g_free(txu->screen_name);
[2abceca]80        g_free(txu);
[62d2cfb]81}
82
83
84/**
85 * Frees a twitter_xml_status struct.
86 */
87static void txs_free(struct twitter_xml_status *txs)
88{
89        g_free(txs->text);
90        txu_free(txs->user);
[2abceca]91        g_free(txs);
[62d2cfb]92}
93
94/**
95 * Free a twitter_xml_list struct.
96 * type is the type of list the struct holds.
97 */
98static void txl_free(struct twitter_xml_list *txl)
99{
100        GSList *l;
[a26af5c]101        if (txl == NULL)
102                return;
[62d2cfb]103        for ( l = txl->list; l ; l = g_slist_next(l) )
104                if (txl->type == TXL_STATUS)
105                        txs_free((struct twitter_xml_status *)l->data);
106                else if (txl->type == TXL_ID)
107                        g_free(l->data);
108        g_slist_free(txl->list);
109}
110
111/**
112 * Add a buddy if it is not allready added, set the status to logged in.
113 */
[3e69802]114static void twitter_add_buddy(struct im_connection *ic, char *name, const char *fullname)
[62d2cfb]115{
[1014cab]116        struct twitter_data *td = ic->proto_data;
117
[62d2cfb]118        // Check if the buddy is allready in the buddy list.
[21c87a7]119        if (!bee_user_by_handle( ic->bee, ic, name ))
[62d2cfb]120        {
[e88fbe27]121                char *mode = set_getstr(&ic->acc->set, "mode");
122               
[62d2cfb]123                // The buddy is not in the list, add the buddy and set the status to logged in.
124                imcb_add_buddy( ic, name, NULL );
[3e69802]125                imcb_rename_buddy( ic, name, fullname );
[e88fbe27]126                if (g_strcasecmp(mode, "chat") == 0)
[5c18a76]127                {
128                        /* Necessary so that nicks always get translated to the
129                           exact Twitter username. */
130                        imcb_buddy_nick_hint( ic, name, name );
[1014cab]131                        imcb_chat_add_buddy( td->home_timeline_gc, name );
[5c18a76]132                }
[e88fbe27]133                else if (g_strcasecmp(mode, "many") == 0)
[1014cab]134                        imcb_buddy_status( ic, name, OPT_LOGGED_IN, NULL, NULL );
[62d2cfb]135        }
136}
[1b221e0]137
[a7b9ec7]138/* Warning: May return a malloc()ed value, which will be free()d on the next
139   call. Only for short-term use. */
140static char *twitter_parse_error(struct http_request *req)
141{
142        static char *ret = NULL;
[3d93aed]143        struct xt_parser *xp = NULL;
[a7b9ec7]144        struct xt_node *node;
145       
146        g_free(ret);
147        ret = NULL;
148       
[3d93aed]149        if (req->body_size > 0)
[a7b9ec7]150        {
[3d93aed]151                xp = xt_new(NULL, NULL);
152                xt_feed(xp, req->reply_body, req->body_size);
153               
154                if ((node = xt_find_node(xp->root, "hash")) &&
155                    (node = xt_find_node(node->children, "error")) &&
156                    node->text_len > 0)
157                {
158                        ret = g_strdup_printf("%s (%s)", req->status_string, node->text);
159                        xt_free(xp);
160                        return ret;
161                }
162               
[a7b9ec7]163                xt_free(xp);
164        }
[3d93aed]165       
166        return req->status_string;
[a7b9ec7]167}
168
[1b221e0]169static void twitter_http_get_friends_ids(struct http_request *req);
170
171/**
172 * Get the friends ids.
173 */
[8203da9]174void twitter_get_friends_ids(struct im_connection *ic, gint64 next_cursor)
[1b221e0]175{
176        // Primitive, but hey! It works...     
177        char* args[2];
178        args[0] = "cursor";
[8203da9]179        args[1] = g_strdup_printf ("%lld", (long long) next_cursor);
[bb5ce4d1]180        twitter_http(ic, TWITTER_FRIENDS_IDS_URL, twitter_http_get_friends_ids, ic, 0, args, 2);
[1b221e0]181
182        g_free(args[1]);
183}
184
185/**
186 * Function to help fill a list.
187 */
188static xt_status twitter_xt_next_cursor( struct xt_node *node, struct twitter_xml_list *txl )
189{
[bd64716]190        char *end = NULL;
191       
192        if( node->text )
193                txl->next_cursor = g_ascii_strtoll( node->text, &end, 10 );
194        if( end == NULL )
195                txl->next_cursor = -1;
[1b221e0]196
197        return XT_HANDLED;
198}
199
200/**
201 * Fill a list of ids.
202 */
203static xt_status twitter_xt_get_friends_id_list( struct xt_node *node, struct twitter_xml_list *txl )
204{
205        struct xt_node *child;
[62d2cfb]206       
207        // Set the list type.
208        txl->type = TXL_ID;
[1b221e0]209
210        // The root <statuses> node should hold the list of statuses <status>
211        // Walk over the nodes children.
212        for( child = node->children ; child ; child = child->next )
213        {
214                if ( g_strcasecmp( "id", child->name ) == 0)
215                {
216                        // Add the item to the list.
[2abceca]217                        txl->list = g_slist_append (txl->list, g_memdup( child->text, child->text_len + 1 ));
[1b221e0]218                }
219                else if ( g_strcasecmp( "next_cursor", child->name ) == 0)
220                {
221                        twitter_xt_next_cursor(child, txl);
222                }
223        }
224
225        return XT_HANDLED;
226}
227
228/**
229 * Callback for getting the friends ids.
230 */
231static void twitter_http_get_friends_ids(struct http_request *req)
232{
233        struct im_connection *ic;
234        struct xt_parser *parser;
235        struct twitter_xml_list *txl;
[3bd4a93]236        struct twitter_data *td;
[1b221e0]237
238        ic = req->data;
239
[62d2cfb]240        // Check if the connection is still active.
241        if( !g_slist_find( twitter_connections, ic ) )
242                return;
[37aa317]243       
244        td = ic->proto_data;
[62d2cfb]245
[1b221e0]246        // Check if the HTTP request went well.
247        if (req->status_code != 200) {
248                // It didn't go well, output the error and return.
[3bd4a93]249                if (++td->http_fails >= 5)
[a7b9ec7]250                        imcb_error(ic, "Could not retrieve friends: %s", twitter_parse_error(req));
[3bd4a93]251               
[1b221e0]252                return;
[3bd4a93]253        } else {
254                td->http_fails = 0;
[1b221e0]255        }
256
257        txl = g_new0(struct twitter_xml_list, 1);
258
259        // Parse the data.
260        parser = xt_new( NULL, txl );
261        xt_feed( parser, req->reply_body, req->body_size );
262        twitter_xt_get_friends_id_list(parser->root, txl);
263        xt_free( parser );
264
265        if (txl->next_cursor)
266                twitter_get_friends_ids(ic, txl->next_cursor);
267
[62d2cfb]268        txl_free(txl);
[1b221e0]269        g_free(txl);
270}
271
272/**
273 * Function to fill a twitter_xml_user struct.
274 * It sets:
275 *  - the name and
276 *  - the screen_name.
277 */
278static xt_status twitter_xt_get_user( struct xt_node *node, struct twitter_xml_user *txu )
279{
280        struct xt_node *child;
281
282        // Walk over the nodes children.
283        for( child = node->children ; child ; child = child->next )
284        {
285                if ( g_strcasecmp( "name", child->name ) == 0)
286                {
287                        txu->name = g_memdup( child->text, child->text_len + 1 );
288                }
289                else if (g_strcasecmp( "screen_name", child->name ) == 0)
290                {
291                        txu->screen_name = g_memdup( child->text, child->text_len + 1 );
292                }
293        }
294        return XT_HANDLED;
295}
296
[62d2cfb]297/**
298 * Function to fill a twitter_xml_list struct.
299 * It sets:
300 *  - all <user>s from the <users> element.
301 */
302static xt_status twitter_xt_get_users( struct xt_node *node, struct twitter_xml_list *txl )
303{
304        struct twitter_xml_user *txu;
305        struct xt_node *child;
306
307        // Set the type of the list.
308        txl->type = TXL_USER;
309
310        // The root <users> node should hold the list of users <user>
311        // Walk over the nodes children.
312        for( child = node->children ; child ; child = child->next )
313        {
314                if ( g_strcasecmp( "user", child->name ) == 0)
315                {
316                        txu = g_new0(struct twitter_xml_user, 1);
317                        twitter_xt_get_user(child, txu);
318                        // Put the item in the front of the list.
319                        txl->list = g_slist_prepend (txl->list, txu);
320                }
321        }
322
323        return XT_HANDLED;
324}
325
326/**
327 * Function to fill a twitter_xml_list struct.
328 * It calls twitter_xt_get_users to get the <user>s from a <users> element.
329 * It sets:
330 *  - the next_cursor.
331 */
332static xt_status twitter_xt_get_user_list( struct xt_node *node, struct twitter_xml_list *txl )
333{
334        struct xt_node *child;
335
336        // Set the type of the list.
337        txl->type = TXL_USER;
338
339        // The root <user_list> node should hold a users <users> element
340        // Walk over the nodes children.
341        for( child = node->children ; child ; child = child->next )
342        {
343                if ( g_strcasecmp( "users", child->name ) == 0)
344                {
345                        twitter_xt_get_users(child, txl);
346                }
347                else if ( g_strcasecmp( "next_cursor", child->name ) == 0)
348                {
349                        twitter_xt_next_cursor(child, txl);
350                }
351        }
352
353        return XT_HANDLED;
354}
355
356
[1b221e0]357/**
358 * Function to fill a twitter_xml_status struct.
359 * It sets:
360 *  - the status text and
361 *  - the created_at timestamp and
362 *  - the status id and
363 *  - the user in a twitter_xml_user struct.
364 */
365static xt_status twitter_xt_get_status( struct xt_node *node, struct twitter_xml_status *txs )
366{
367        struct xt_node *child;
368
369        // Walk over the nodes children.
370        for( child = node->children ; child ; child = child->next )
371        {
372                if ( g_strcasecmp( "text", child->name ) == 0)
373                {
374                        txs->text = g_memdup( child->text, child->text_len + 1 );
375                }
376                else if (g_strcasecmp( "created_at", child->name ) == 0)
377                {
[08579a1]378                        struct tm parsed;
379                       
380                        /* Very sensitive to changes to the formatting of
381                           this field. :-( Also assumes the timezone used
382                           is UTC since C time handling functions suck. */
383                        if( strptime( child->text, "%a %b %d %H:%M:%S %z %Y", &parsed ) != NULL )
384                                txs->created_at = mktime_utc( &parsed );
[1b221e0]385                }
386                else if (g_strcasecmp( "user", child->name ) == 0)
387                {
388                        txs->user = g_new0(struct twitter_xml_user, 1);
389                        twitter_xt_get_user( child, txs->user );
390                }
391                else if (g_strcasecmp( "id", child->name ) == 0)
392                {
393                        txs->id = g_ascii_strtoull (child->text, NULL, 10);
394                }
395        }
396        return XT_HANDLED;
397}
398
399/**
400 * Function to fill a twitter_xml_list struct.
401 * It sets:
402 *  - all <status>es within the <status> element and
403 *  - the next_cursor.
404 */
405static xt_status twitter_xt_get_status_list( struct xt_node *node, struct twitter_xml_list *txl )
406{
407        struct twitter_xml_status *txs;
408        struct xt_node *child;
409
[62d2cfb]410        // Set the type of the list.
411        txl->type = TXL_STATUS;
412
[1b221e0]413        // The root <statuses> node should hold the list of statuses <status>
414        // Walk over the nodes children.
415        for( child = node->children ; child ; child = child->next )
416        {
417                if ( g_strcasecmp( "status", child->name ) == 0)
418                {
419                        txs = g_new0(struct twitter_xml_status, 1);
420                        twitter_xt_get_status(child, txs);
421                        // Put the item in the front of the list.
422                        txl->list = g_slist_prepend (txl->list, txs);
423                }
424                else if ( g_strcasecmp( "next_cursor", child->name ) == 0)
425                {
426                        twitter_xt_next_cursor(child, txl);
427                }
428        }
429
430        return XT_HANDLED;
431}
432
433static void twitter_http_get_home_timeline(struct http_request *req);
434
435/**
436 * Get the timeline.
437 */
[8203da9]438void twitter_get_home_timeline(struct im_connection *ic, gint64 next_cursor)
[1b221e0]439{
440        struct twitter_data *td = ic->proto_data;
441
442        char* args[4];
443        args[0] = "cursor";
[8203da9]444        args[1] = g_strdup_printf ("%lld", (long long) next_cursor);
[1b221e0]445        if (td->home_timeline_id) {
446                args[2] = "since_id";
[0519b0a]447                args[3] = g_strdup_printf ("%llu", (long long unsigned int) td->home_timeline_id);
[1b221e0]448        }
449
[bb5ce4d1]450        twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args, td->home_timeline_id ? 4 : 2);
[1b221e0]451
452        g_free(args[1]);
453        if (td->home_timeline_id) {
454                g_free(args[3]);
455        }
456}
457
[d6aa6dd]458static void twitter_groupchat_init(struct im_connection *ic)
459{
460        char *name_hint;
461        struct groupchat *gc;
462        struct twitter_data *td = ic->proto_data;
463       
464        td->home_timeline_gc = gc = imcb_chat_new( ic, "home/timeline" );
465       
[ffcdf13]466        name_hint = g_strdup_printf( "%s_%s", td->prefix, ic->acc->user );
[d6aa6dd]467        imcb_chat_name_hint( gc, name_hint );
468        g_free( name_hint );
469}
470
[62d2cfb]471/**
472 * Function that is called to see the statuses in a groupchat window.
473 */
474static void twitter_groupchat(struct im_connection *ic, GSList *list)
475{
476        struct twitter_data *td = ic->proto_data;
477        GSList *l = NULL;
478        struct twitter_xml_status *status;
479        struct groupchat *gc;
480
481        // Create a new groupchat if it does not exsist.
482        if (!td->home_timeline_gc)
[d6aa6dd]483                twitter_groupchat_init(ic);
484       
485        gc = td->home_timeline_gc;
486        if (!gc->joined)
[62d2cfb]487                imcb_chat_add_buddy( gc, ic->acc->user );
488
489        for ( l = list; l ; l = g_slist_next(l) )
490        {
491                status = l->data;
[a26af5c]492                if (status->user == NULL || status->text == NULL)
493                        continue;
494
[3e69802]495                twitter_add_buddy(ic, status->user->screen_name, status->user->name);
[d569019]496               
[0b3ffb1]497                strip_html(status->text);
498               
[62d2cfb]499                // Say it!
[d569019]500                if (g_strcasecmp(td->user, status->user->screen_name) == 0)
501                        imcb_chat_log (gc, "Your Tweet: %s", status->text);
502                else
[08579a1]503                        imcb_chat_msg (gc, status->user->screen_name, status->text, 0, status->created_at );
[d569019]504               
[62d2cfb]505                // Update the home_timeline_id to hold the highest id, so that by the next request
506                // we won't pick up the updates allready in the list.
507                td->home_timeline_id = td->home_timeline_id < status->id ? status->id : td->home_timeline_id;
508        }
509}
510
511/**
512 * Function that is called to see statuses as private messages.
513 */
514static void twitter_private_message_chat(struct im_connection *ic, GSList *list)
515{
516        struct twitter_data *td = ic->proto_data;
517        GSList *l = NULL;
518        struct twitter_xml_status *status;
[e88fbe27]519        char from[MAX_STRING];
520        gboolean mode_one;
521       
522        mode_one = g_strcasecmp( set_getstr( &ic->acc->set, "mode" ), "one" ) == 0;
[62d2cfb]523
[e88fbe27]524        if( mode_one )
525        {
[ffcdf13]526                g_snprintf( from, sizeof( from ) - 1, "%s_%s", td->prefix, ic->acc->user );
[e88fbe27]527                from[MAX_STRING-1] = '\0';
528        }
529       
[62d2cfb]530        for ( l = list; l ; l = g_slist_next(l) )
531        {
[e88fbe27]532                char *text = NULL;
533               
[62d2cfb]534                status = l->data;
[e88fbe27]535               
[0b3ffb1]536                strip_html( status->text );
[e88fbe27]537                if( mode_one )
538                        text = g_strdup_printf( "\002<\002%s\002>\002 %s",
539                                                status->user->screen_name, status->text );
[55b1e69]540                else
541                        twitter_add_buddy(ic, status->user->screen_name, status->user->name);
[e88fbe27]542               
543                imcb_buddy_msg( ic,
544                                mode_one ? from : status->user->screen_name,
545                                mode_one ? text : status->text,
546                                0, status->created_at );
547               
[62d2cfb]548                // Update the home_timeline_id to hold the highest id, so that by the next request
549                // we won't pick up the updates allready in the list.
550                td->home_timeline_id = td->home_timeline_id < status->id ? status->id : td->home_timeline_id;
[e88fbe27]551               
552                g_free( text );
[62d2cfb]553        }
554}
555
[1b221e0]556/**
557 * Callback for getting the home timeline.
558 */
559static void twitter_http_get_home_timeline(struct http_request *req)
560{
[62d2cfb]561        struct im_connection *ic = req->data;
[37aa317]562        struct twitter_data *td;
[1b221e0]563        struct xt_parser *parser;
564        struct twitter_xml_list *txl;
[62d2cfb]565
566        // Check if the connection is still active.
567        if( !g_slist_find( twitter_connections, ic ) )
568                return;
[37aa317]569       
570        td = ic->proto_data;
[1b221e0]571
572        // Check if the HTTP request went well.
[3bd4a93]573        if (req->status_code == 200)
574        {
575                td->http_fails = 0;
[c2ecadc]576                if (!(ic->flags & OPT_LOGGED_IN))
[3bd4a93]577                        imcb_connected(ic);
578        }
579        else if (req->status_code == 401)
580        {
581                imcb_error( ic, "Authentication failure" );
582                imc_logout( ic, FALSE );
583                return;
584        }
585        else
586        {
[1b221e0]587                // It didn't go well, output the error and return.
[3bd4a93]588                if (++td->http_fails >= 5)
[a7b9ec7]589                        imcb_error(ic, "Could not retrieve " TWITTER_HOME_TIMELINE_URL ": %s", twitter_parse_error(req));
[3bd4a93]590               
[1b221e0]591                return;
592        }
593
594        txl = g_new0(struct twitter_xml_list, 1);
595        txl->list = NULL;
[62d2cfb]596
[1b221e0]597        // Parse the data.
598        parser = xt_new( NULL, txl );
599        xt_feed( parser, req->reply_body, req->body_size );
600        // The root <statuses> node should hold the list of statuses <status>
601        twitter_xt_get_status_list(parser->root, txl);
602        xt_free( parser );
603
[62d2cfb]604        // See if the user wants to see the messages in a groupchat window or as private messages.
[e88fbe27]605        if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0)
[62d2cfb]606                twitter_groupchat(ic, txl->list);
[b4dd253]607        else
[62d2cfb]608                twitter_private_message_chat(ic, txl->list);
[1b221e0]609
610        // Free the structure. 
[62d2cfb]611        txl_free(txl);
[1b221e0]612        g_free(txl);
613}
614
615/**
[62d2cfb]616 * Callback for getting (twitter)friends...
617 *
618 * Be afraid, be very afraid! This function will potentially add hundreds of "friends". "Who has
619 * hundreds of friends?" you wonder? You probably not, since you are reading the source of
620 * BitlBee... Get a life and meet new people!
[1b221e0]621 */
[62d2cfb]622static void twitter_http_get_statuses_friends(struct http_request *req)
[1b221e0]623{
[62d2cfb]624        struct im_connection *ic = req->data;
[37aa317]625        struct twitter_data *td;
[62d2cfb]626        struct xt_parser *parser;
627        struct twitter_xml_list *txl;
[2abceca]628        GSList *l = NULL;
629        struct twitter_xml_user *user;
[62d2cfb]630
631        // Check if the connection is still active.
632        if( !g_slist_find( twitter_connections, ic ) )
633                return;
[37aa317]634       
635        td = ic->proto_data;
636       
[62d2cfb]637        // Check if the HTTP request went well.
[d6aa6dd]638        if (req->status_code == 401)
639        {
640                imcb_error( ic, "Authentication failure" );
641                imc_logout( ic, FALSE );
642                return;
643        } else if (req->status_code != 200) {
[62d2cfb]644                // It didn't go well, output the error and return.
[d6aa6dd]645                imcb_error(ic, "Could not retrieve " TWITTER_SHOW_FRIENDS_URL ": %s", twitter_parse_error(req));
646                imc_logout( ic, TRUE );
[62d2cfb]647                return;
[3bd4a93]648        } else {
649                td->http_fails = 0;
[62d2cfb]650        }
[d6aa6dd]651       
652        if( !td->home_timeline_gc &&
653            g_strcasecmp( set_getstr( &ic->acc->set, "mode" ), "chat" ) == 0 )
654                twitter_groupchat_init( ic );
[62d2cfb]655
656        txl = g_new0(struct twitter_xml_list, 1);
657        txl->list = NULL;
658
659        // Parse the data.
660        parser = xt_new( NULL, txl );
661        xt_feed( parser, req->reply_body, req->body_size );
662
663        // Get the user list from the parsed xml feed.
664        twitter_xt_get_user_list(parser->root, txl);
665        xt_free( parser );
666
667        // Add the users as buddies.
[1b221e0]668        for ( l = txl->list; l ; l = g_slist_next(l) )
[62d2cfb]669        {
670                user = l->data;
[3e69802]671                twitter_add_buddy(ic, user->screen_name, user->name);
[62d2cfb]672        }
[1b221e0]673
[62d2cfb]674        // if the next_cursor is set to something bigger then 0 there are more friends to gather.
675        if (txl->next_cursor > 0)
[051372c]676        {
[62d2cfb]677                twitter_get_statuses_friends(ic, txl->next_cursor);
[051372c]678        }
679        else
680        {
681                td->flags |= TWITTER_HAVE_FRIENDS;
682                twitter_login_finish(ic);
683        }
684       
[62d2cfb]685        // Free the structure.
686        txl_free(txl);
687        g_free(txl);
[1b221e0]688}
689
690/**
[62d2cfb]691 * Get the friends.
[1b221e0]692 */
[8203da9]693void twitter_get_statuses_friends(struct im_connection *ic, gint64 next_cursor)
[1b221e0]694{
[62d2cfb]695        char* args[2];
696        args[0] = "cursor";
[8203da9]697        args[1] = g_strdup_printf ("%lld", (long long) next_cursor);
[62d2cfb]698
[bb5ce4d1]699        twitter_http(ic, TWITTER_SHOW_FRIENDS_URL, twitter_http_get_statuses_friends, ic, 0, args, 2);
[62d2cfb]700
701        g_free(args[1]);
[1b221e0]702}
703
704/**
[7d53efb]705 * Callback to use after sending a post request to twitter.
[1b221e0]706 */
[7d53efb]707static void twitter_http_post(struct http_request *req)
[1b221e0]708{
709        struct im_connection *ic = req->data;
710
[62d2cfb]711        // Check if the connection is still active.
712        if( !g_slist_find( twitter_connections, ic ) )
713                return;
714
[1b221e0]715        // Check if the HTTP request went well.
716        if (req->status_code != 200) {
717                // It didn't go well, output the error and return.
[ba3233c]718                imcb_error(ic, "HTTP error: %s", twitter_parse_error(req));
[1b221e0]719                return;
720        }
721}
722
723/**
724 * Function to POST a new status to twitter.
725 */ 
726void twitter_post_status(struct im_connection *ic, char* msg)
727{
728        char* args[2];
729        args[0] = "status";
730        args[1] = msg;
[ba3233c]731        twitter_http(ic, TWITTER_STATUS_UPDATE_URL, twitter_http_post, ic, 1, args, 2);
[62d2cfb]732//      g_free(args[1]);
[1b221e0]733}
734
735
[62d2cfb]736/**
737 * Function to POST a new message to twitter.
738 */
739void twitter_direct_messages_new(struct im_connection *ic, char *who, char *msg)
740{
741        char* args[4];
742        args[0] = "screen_name";
743        args[1] = who;
744        args[2] = "text";
745        args[3] = msg;
746        // Use the same callback as for twitter_post_status, since it does basically the same.
[ba3233c]747        twitter_http(ic, TWITTER_DIRECT_MESSAGES_NEW_URL, twitter_http_post, ic, 1, args, 4);
[62d2cfb]748//      g_free(args[1]);
749//      g_free(args[3]);
750}
[7d53efb]751
752void twitter_friendships_create_destroy(struct im_connection *ic, char *who, int create)
753{
754        char* args[2];
755        args[0] = "screen_name";
756        args[1] = who;
[ba3233c]757        twitter_http(ic, create ? TWITTER_FRIENDSHIPS_CREATE_URL : TWITTER_FRIENDSHIPS_DESTROY_URL, twitter_http_post, ic, 1, args, 2);
[a26af5c]758}
Note: See TracBrowser for help on using the repository browser.