Changeset de923d5 for protocols/twitter


Ignore:
Timestamp:
2011-06-11T17:11:08Z (14 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
c0f33f1
Parents:
5f74987
Message:

Use /friends/ids and /users/lookup instead of /statuses/friends to get a
list of contacts at login time. Still depends on adding an API version number
to base_url though.

Location:
protocols/twitter
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • protocols/twitter/twitter.c

    r5f74987 rde923d5  
    8383                 !(td->flags & TWITTER_HAVE_FRIENDS)) {
    8484                imcb_log(ic, "Getting contact list");
    85                 twitter_get_statuses_friends(ic, -1);
     85                twitter_get_friends_ids(ic, -1);
     86                //twitter_get_statuses_friends(ic, -1);
    8687        } else
    8788                twitter_main_loop_start(ic);
     
    168169                                         "instead of %s.", sn, ic->acc->user);
    169170                        }
     171                        g_free(td->user);
     172                        td->user = g_strdup(sn);
    170173                }
    171174
     
    257260        td = g_new0(struct twitter_data, 1);
    258261        ic->proto_data = td;
     262        td->user = g_strdup(acc->user);
    259263
    260264        td->url_ssl = url.proto == PROTO_HTTPS;
     
    270274                td->prefix = g_strdup(url.host);
    271275
    272         td->flags |= TWITTER_HAVE_FRIENDS;
    273         td->user = acc->user;
    274276        if (strstr(acc->pass, "oauth_token="))
    275277                td->oauth_info = oauth_from_string(acc->pass, get_oauth_service(ic));
     
    305307        if (td) {
    306308                oauth_info_free(td->oauth_info);
     309                g_free(td->user);
    307310                g_free(td->prefix);
    308311                g_free(td->url_host);
    309312                g_free(td->url_path);
    310                 g_free(td->pass);
    311313                g_free(td->log);
    312314                g_free(td);
  • protocols/twitter/twitter.h

    r5f74987 rde923d5  
    4343{
    4444        char* user;
    45         char* pass;
    4645        struct oauth_info *oauth_info;
     46        GSList *follow_ids;
     47       
    4748        guint64 home_timeline_id;
    4849        guint64 last_status_id; /* For undo */
     
    5253        twitter_flags_t flags;
    5354       
     55        /* set base_url */
    5456        gboolean url_ssl;
    5557        int url_port;
     
    5961        char *prefix; /* Used to generate contact + channel name. */
    6062       
     63        /* set show_ids */
    6164        struct twitter_log_data *log;
    6265        int log_id;
  • protocols/twitter/twitter_lib.c

    r5f74987 rde923d5  
    5555        gint64 next_cursor;
    5656        GSList *list;
    57         gpointer data;
    5857};
    5958
     
    109108                else if (txl->type == TXL_ID)
    110109                        g_free(l->data);
     110                else if (txl->type == TXL_USER)
     111                        txu_free(l->data);
    111112        g_slist_free(txl->list);
    112113        g_free(txl);
     
    120121        struct twitter_data *td = ic->proto_data;
    121122
    122         // Check if the buddy is allready in the buddy list.
     123        // Check if the buddy is already in the buddy list.
    123124        if (!bee_user_by_handle(ic->bee, ic, name)) {
    124125                char *mode = set_getstr(&ic->acc->set, "mode");
     
    138139
    139140/* Warning: May return a malloc()ed value, which will be free()d on the next
    140    call. Only for short-term use. */
     141   call. Only for short-term use. NOT THREADSAFE!  */
    141142char *twitter_parse_error(struct http_request *req)
    142143{
     
    151152                xp = xt_new(NULL, NULL);
    152153                xt_feed(xp, req->reply_body, req->body_size);
    153 
    154                 if ((node = xt_find_node(xp->root, "hash")) &&
    155                     (node = xt_find_node(node->children, "error")) && node->text_len > 0) {
    156                         ret = g_strdup_printf("%s (%s)", req->status_string, node->text);
    157                 }
     154               
     155                for (node = xp->root; node; node = node->next)
     156                        if ((node = xt_find_node(node->children, "error")) && node->text_len > 0) {
     157                                ret = g_strdup_printf("%s (%s)", req->status_string, node->text);
     158                                break;
     159                        }
    158160
    159161                xt_free(xp);
     
    207209        // Walk over the nodes children.
    208210        for (child = node->children; child; child = child->next) {
    209                 if (g_strcasecmp("id", child->name) == 0) {
    210                         // Add the item to the list.
    211                         txl->list =
    212                             g_slist_append(txl->list, g_memdup(child->text, child->text_len + 1));
     211                if (g_strcasecmp("ids", child->name) == 0) {
     212                        struct xt_node *idc;
     213                        for (idc = child->children; idc; idc = idc->next)
     214                                if (g_strcasecmp(idc->name, "id") == 0)
     215                                        txl->list = g_slist_prepend(txl->list,
     216                                                g_memdup(idc->text, idc->text_len + 1));
    213217                } else if (g_strcasecmp("next_cursor", child->name) == 0) {
    214218                        twitter_xt_next_cursor(child, txl);
     
    218222        return XT_HANDLED;
    219223}
     224
     225static void twitter_get_users_lookup(struct im_connection *ic);
    220226
    221227/**
     
    237243        td = ic->proto_data;
    238244
    239         // Check if the HTTP request went well.
    240         if (req->status_code != 200) {
     245        // Check if the HTTP request went well. More strict checks as this is
     246        // the first request we do in a session.
     247        if (req->status_code == 401) {
     248                imcb_error(ic, "Authentication failure");
     249                imc_logout(ic, FALSE);
     250                return;
     251        } else if (req->status_code != 200) {
    241252                // It didn't go well, output the error and return.
    242                 if (++td->http_fails >= 5)
    243                         imcb_error(ic, "Could not retrieve friends: %s", twitter_parse_error(req));
    244 
     253                imcb_error(ic, "Could not retrieve %s: %s",
     254                           TWITTER_FRIENDS_IDS_URL, twitter_parse_error(req));
     255                imc_logout(ic, TRUE);
    245256                return;
    246257        } else {
     
    248259        }
    249260
     261        /* Create the room now that we "logged in". */
     262        if (!td->home_timeline_gc && g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0)
     263                twitter_groupchat_init(ic);
     264
    250265        txl = g_new0(struct twitter_xml_list, 1);
     266        txl->list = td->follow_ids;
    251267
    252268        // Parse the data.
     
    256272        xt_free(parser);
    257273
     274        td->follow_ids = txl->list;
    258275        if (txl->next_cursor)
     276                /* These were just numbers. Up to 4000 in a response AFAIK so if we get here
     277                   we may be using a spammer account. \o/ */
    259278                twitter_get_friends_ids(ic, txl->next_cursor);
    260 
     279        else
     280                /* Now to convert all those numbers into names.. */
     281                twitter_get_users_lookup(ic);
     282
     283        txl->list = NULL;
    261284        txl_free(txl);
     285}
     286
     287static xt_status twitter_xt_get_users(struct xt_node *node, struct twitter_xml_list *txl);
     288static void twitter_http_get_users_lookup(struct http_request *req);
     289
     290static void twitter_get_users_lookup(struct im_connection *ic)
     291{
     292        struct twitter_data *td = ic->proto_data;
     293        char *args[2] = {
     294                "user_id",
     295                NULL,
     296        };
     297        GString *ids = g_string_new("");
     298        int i;
     299       
     300        /* We can request up to 100 users at a time. */
     301        for (i = 0; i < 100 && td->follow_ids; i ++) {
     302                g_string_append_printf(ids, ",%s", (char*) td->follow_ids->data);
     303                g_free(td->follow_ids->data);
     304                td->follow_ids = g_slist_remove(td->follow_ids, td->follow_ids->data);
     305        }
     306        if (ids->len > 0) {
     307                args[1] = ids->str + 1;
     308                /* POST, because I think ids can be up to 1KB long. */
     309                twitter_http(ic, TWITTER_USERS_LOOKUP_URL, twitter_http_get_users_lookup, ic, 1, args, 2);
     310        } else {
     311                /* We have all users. Continue with login. (Get statuses.) */
     312                td->flags |= TWITTER_HAVE_FRIENDS;
     313                twitter_login_finish(ic);
     314        }
     315        g_string_free(ids, TRUE);
     316}
     317
     318/**
     319 * Callback for getting (twitter)friends...
     320 *
     321 * Be afraid, be very afraid! This function will potentially add hundreds of "friends". "Who has
     322 * hundreds of friends?" you wonder? You probably not, since you are reading the source of
     323 * BitlBee... Get a life and meet new people!
     324 */
     325static void twitter_http_get_users_lookup(struct http_request *req)
     326{
     327        struct im_connection *ic = req->data;
     328        struct twitter_data *td;
     329        struct xt_parser *parser;
     330        struct twitter_xml_list *txl;
     331        GSList *l = NULL;
     332        struct twitter_xml_user *user;
     333
     334        // Check if the connection is still active.
     335        if (!g_slist_find(twitter_connections, ic))
     336                return;
     337
     338        td = ic->proto_data;
     339
     340        if (req->status_code != 200) {
     341                // It didn't go well, output the error and return.
     342                imcb_error(ic, "Could not retrieve %s: %s",
     343                           TWITTER_USERS_LOOKUP_URL, twitter_parse_error(req));
     344                imc_logout(ic, TRUE);
     345                return;
     346        } else {
     347                td->http_fails = 0;
     348        }
     349
     350        txl = g_new0(struct twitter_xml_list, 1);
     351        txl->list = NULL;
     352
     353        // Parse the data.
     354        parser = xt_new(NULL, txl);
     355        xt_feed(parser, req->reply_body, req->body_size);
     356
     357        // Get the user list from the parsed xml feed.
     358        twitter_xt_get_users(parser->root, txl);
     359        xt_free(parser);
     360
     361        // Add the users as buddies.
     362        for (l = txl->list; l; l = g_slist_next(l)) {
     363                user = l->data;
     364                twitter_add_buddy(ic, user->screen_name, user->name);
     365        }
     366
     367        // Free the structure.
     368        txl_free(txl);
     369
     370        twitter_get_users_lookup(ic);
    262371}
    263372
     
    304413                        // Put the item in the front of the list.
    305414                        txl->list = g_slist_prepend(txl->list, txu);
    306                 }
    307         }
    308 
    309         return XT_HANDLED;
    310 }
    311 
    312 /**
    313  * Function to fill a twitter_xml_list struct.
    314  * It calls twitter_xt_get_users to get the <user>s from a <users> element.
    315  * It sets:
    316  *  - the next_cursor.
    317  */
    318 static xt_status twitter_xt_get_user_list(struct xt_node *node, struct twitter_xml_list *txl)
    319 {
    320         struct xt_node *child;
    321 
    322         // Set the type of the list.
    323         txl->type = TXL_USER;
    324 
    325         // The root <user_list> node should hold a users <users> element
    326         // Walk over the nodes children.
    327         for (child = node->children; child; child = child->next) {
    328                 if (g_strcasecmp("users", child->name) == 0) {
    329                         twitter_xt_get_users(child, txl);
    330                 } else if (g_strcasecmp("next_cursor", child->name) == 0) {
    331                         twitter_xt_next_cursor(child, txl);
    332415                }
    333416        }
     
    634717                // It didn't go well, output the error and return.
    635718                if (++td->http_fails >= 5)
    636                         imcb_error(ic, "Could not retrieve " TWITTER_HOME_TIMELINE_URL ": %s",
    637                                    twitter_parse_error(req));
     719                        imcb_error(ic, "Could not retrieve %s: %s",
     720                                   TWITTER_HOME_TIMELINE_URL, twitter_parse_error(req));
    638721
    639722                return;
     
    662745
    663746/**
    664  * Callback for getting (twitter)friends...
    665  *
    666  * Be afraid, be very afraid! This function will potentially add hundreds of "friends". "Who has
    667  * hundreds of friends?" you wonder? You probably not, since you are reading the source of
    668  * BitlBee... Get a life and meet new people!
    669  */
    670 static void twitter_http_get_statuses_friends(struct http_request *req)
    671 {
    672         struct im_connection *ic = req->data;
    673         struct twitter_data *td;
    674         struct xt_parser *parser;
    675         struct twitter_xml_list *txl;
    676         GSList *l = NULL;
    677         struct twitter_xml_user *user;
    678 
    679         // Check if the connection is still active.
    680         if (!g_slist_find(twitter_connections, ic))
    681                 return;
    682 
    683         td = ic->proto_data;
    684 
    685         // Check if the HTTP request went well.
    686         if (req->status_code == 401) {
    687                 imcb_error(ic, "Authentication failure");
    688                 imc_logout(ic, FALSE);
    689                 return;
    690         } else if (req->status_code != 200) {
    691                 // It didn't go well, output the error and return.
    692                 imcb_error(ic, "Could not retrieve " TWITTER_SHOW_FRIENDS_URL ": %s",
    693                            twitter_parse_error(req));
    694                 imc_logout(ic, TRUE);
    695                 return;
    696         } else {
    697                 td->http_fails = 0;
    698         }
    699 
    700         if (!td->home_timeline_gc && g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0)
    701                 twitter_groupchat_init(ic);
    702 
    703         txl = g_new0(struct twitter_xml_list, 1);
    704         txl->list = NULL;
    705 
    706         // Parse the data.
    707         parser = xt_new(NULL, txl);
    708         xt_feed(parser, req->reply_body, req->body_size);
    709 
    710         // Get the user list from the parsed xml feed.
    711         twitter_xt_get_user_list(parser->root, txl);
    712         xt_free(parser);
    713 
    714         // Add the users as buddies.
    715         for (l = txl->list; l; l = g_slist_next(l)) {
    716                 user = l->data;
    717                 twitter_add_buddy(ic, user->screen_name, user->name);
    718         }
    719 
    720         // if the next_cursor is set to something bigger then 0 there are more friends to gather.
    721         if (txl->next_cursor > 0) {
    722                 twitter_get_statuses_friends(ic, txl->next_cursor);
    723         } else {
    724                 td->flags |= TWITTER_HAVE_FRIENDS;
    725                 twitter_login_finish(ic);
    726         }
    727 
    728         // Free the structure.
    729         txl_free(txl);
    730 }
    731 
    732 /**
    733  * Get the friends.
    734  */
    735 void twitter_get_statuses_friends(struct im_connection *ic, gint64 next_cursor)
    736 {
    737         char *args[2];
    738         args[0] = "cursor";
    739         args[1] = g_strdup_printf("%lld", (long long) next_cursor);
    740 
    741         twitter_http(ic, TWITTER_SHOW_FRIENDS_URL, twitter_http_get_statuses_friends, ic, 0, args,
    742                      2);
    743 
    744         g_free(args[1]);
    745 }
    746 
    747 /**
    748  * Callback to use after sending a post request to twitter.
     747 * Callback to use after sending a POST request to twitter.
     748 * (Generic, used for a few kinds of queries.)
    749749 */
    750750static void twitter_http_post(struct http_request *req)
     
    810810        // Use the same callback as for twitter_post_status, since it does basically the same.
    811811        twitter_http(ic, TWITTER_DIRECT_MESSAGES_NEW_URL, twitter_http_post, ic, 1, args, 4);
    812 //      g_free(args[1]);
    813 //      g_free(args[3]);
    814812}
    815813
     
    826824{
    827825        char *url;
    828         url =
    829             g_strdup_printf("%s%llu%s", TWITTER_STATUS_DESTROY_URL, (unsigned long long) id,
    830                             ".xml");
     826        url = g_strdup_printf("%s%llu%s", TWITTER_STATUS_DESTROY_URL,
     827                              (unsigned long long) id, ".xml");
    831828        twitter_http(ic, url, twitter_http_post, ic, 1, NULL, 0);
    832829        g_free(url);
     
    836833{
    837834        char *url;
    838         url =
    839             g_strdup_printf("%s%llu%s", TWITTER_STATUS_RETWEET_URL, (unsigned long long) id,
    840                             ".xml");
     835        url = g_strdup_printf("%s%llu%s", TWITTER_STATUS_RETWEET_URL,
     836                              (unsigned long long) id, ".xml");
    841837        twitter_http(ic, url, twitter_http_post, ic, 1, NULL, 0);
    842838        g_free(url);
  • protocols/twitter/twitter_lib.h

    r5f74987 rde923d5  
    4747
    4848/* Users URLs */
    49 #define TWITTER_SHOW_USERS_URL "/users/show.xml"
    50 #define TWITTER_SHOW_FRIENDS_URL "/statuses/friends.xml"
    51 #define TWITTER_SHOW_FOLLOWERS_URL "/statuses/followers.xml"
     49#define TWITTER_USERS_LOOKUP_URL "/users/lookup.xml"
    5250
    5351/* Direct messages URLs */
Note: See TracChangeset for help on using the changeset viewer.