source: protocols/twitter/twitter_lib.c @ 4346c3f4

Last change on this file since 4346c3f4 was 4346c3f4, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-16T23:31:55Z

Merging mainline.

  • 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       
461        name_hint = g_strdup_printf( "Twitter_%s", ic->acc->user );
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        {
521                g_snprintf( from, sizeof( from ) - 1, "twitter_%s", ic->acc->user );
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.