source: protocols/twitter/twitter_lib.c @ a26af5c

Last change on this file since a26af5c was a26af5c, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-13T20:13:46Z

Fixing NULL pointer dereferences in Twitter module. Based on patch from
wahjava (bug #650).

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