source: protocols/twitter/twitter_lib.c @ ffcdf13

Last change on this file since ffcdf13 was ffcdf13, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-17T15:06:56Z

When using non-Twitter Twitter API services, prefix the channel and contact
name with that service name, not always Twitter. This is especially useful
when having multiple accounts on different sites with the same username.

Also adding an "identica" protocol entry for convenience.

Based on a patch from kensanata, bug #648.

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