source: protocols/twitter/twitter_lib.c @ 704dd38

Last change on this file since 704dd38 was 704dd38, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-06-01T21:51:27Z

Merging head.

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