Ignore:
Timestamp:
2011-08-25T18:08:07Z (8 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
429a9b1
Parents:
4804b2f
Message:

Merging Twitter-mentions patch from meh. Bug #663.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • protocols/twitter/twitter_lib.c

    r4804b2f r2322a9f  
    7878        if (txu == NULL)
    7979                return;
     80
    8081        g_free(txu->name);
    8182        g_free(txu->screen_name);
     
    8384}
    8485
    85 
    8686/**
    8787 * Frees a twitter_xml_status struct.
     
    8989static void txs_free(struct twitter_xml_status *txs)
    9090{
     91        if (txs == NULL)
     92                return;
     93
    9194        g_free(txs->text);
    9295        txu_free(txs->user);
     
    103106        if (txl == NULL)
    104107                return;
    105         for (l = txl->list; l; l = g_slist_next(l))
    106                 if (txl->type == TXL_STATUS)
     108
     109        for (l = txl->list; l; l = g_slist_next(l)) {
     110                if (txl->type == TXL_STATUS) {
    107111                        txs_free((struct twitter_xml_status *) l->data);
    108                 else if (txl->type == TXL_ID)
     112                } else if (txl->type == TXL_ID) {
    109113                        g_free(l->data);
    110                 else if (txl->type == TXL_USER)
     114                } else if (txl->type == TXL_USER) {
    111115                        txu_free(l->data);
     116                }
     117        }
     118
    112119        g_slist_free(txl->list);
    113120        g_free(txl);
     
    115122
    116123/**
    117  * Add a buddy if it is not allready added, set the status to logged in.
     124 * Compare status elements
     125 */
     126static gint twitter_compare_elements(gconstpointer a, gconstpointer b)
     127{
     128        struct twitter_xml_status *a_status = (struct twitter_xml_status *) a;
     129        struct twitter_xml_status *b_status = (struct twitter_xml_status *) b;
     130
     131        if (a_status->created_at < b_status->created_at) {
     132                return -1;
     133        } else if (a_status->created_at > b_status->created_at) {
     134                return 1;
     135        } else {
     136                return 0;
     137        }
     138}
     139
     140/**
     141 * Add a buddy if it is not already added, set the status to logged in.
    118142 */
    119143static void twitter_add_buddy(struct im_connection *ic, char *name, const char *fullname)
     
    132156                           exact Twitter username. */
    133157                        imcb_buddy_nick_hint(ic, name, name);
    134                         imcb_chat_add_buddy(td->home_timeline_gc, name);
     158                        imcb_chat_add_buddy(td->timeline_gc, name);
    135159                } else if (g_strcasecmp(mode, "many") == 0)
    136160                        imcb_buddy_status(ic, name, OPT_LOGGED_IN, NULL, NULL);
     
    260284
    261285        /* Create the room now that we "logged in". */
    262         if (!td->home_timeline_gc && g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0)
     286        if (!td->timeline_gc && g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0)
    263287                twitter_groupchat_init(ic);
    264288
     
    522546}
    523547
    524 static void twitter_http_get_home_timeline(struct http_request *req);
    525 
    526 /**
    527  * Get the timeline.
    528  */
    529 void twitter_get_home_timeline(struct im_connection *ic, gint64 next_cursor)
    530 {
    531         struct twitter_data *td = ic->proto_data;
    532 
    533         char *args[4];
    534         args[0] = "cursor";
    535         args[1] = g_strdup_printf("%lld", (long long) next_cursor);
    536         if (td->home_timeline_id) {
    537                 args[2] = "since_id";
    538                 args[3] = g_strdup_printf("%llu", (long long unsigned int) td->home_timeline_id);
    539         }
    540 
    541         twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args,
    542                      td->home_timeline_id ? 4 : 2);
    543 
    544         g_free(args[1]);
    545         if (td->home_timeline_id) {
    546                 g_free(args[3]);
    547         }
    548 }
    549 
    550548static char *twitter_msg_add_id(struct im_connection *ic,
    551549                                struct twitter_xml_status *txs, const char *prefix)
     
    586584        GSList *l;
    587585
    588         td->home_timeline_gc = gc = imcb_chat_new(ic, "home/timeline");
     586        td->timeline_gc = gc = imcb_chat_new(ic, "twitter/timeline");
    589587
    590588        name_hint = g_strdup_printf("%s_%s", td->prefix, ic->acc->user);
     
    595593                bee_user_t *bu = l->data;
    596594                if (bu->ic == ic)
    597                         imcb_chat_add_buddy(td->home_timeline_gc, bu->handle);
     595                        imcb_chat_add_buddy(td->timeline_gc, bu->handle);
    598596        }
    599597}
     
    608606        struct twitter_xml_status *status;
    609607        struct groupchat *gc;
     608        guint64 last_id = 0;
    610609
    611610        // Create a new groupchat if it does not exsist.
    612         if (!td->home_timeline_gc)
     611        if (!td->timeline_gc)
    613612                twitter_groupchat_init(ic);
    614613
    615         gc = td->home_timeline_gc;
     614        gc = td->timeline_gc;
    616615        if (!gc->joined)
    617616                imcb_chat_add_buddy(gc, ic->acc->user);
     
    621620
    622621                status = l->data;
    623                 if (status->user == NULL || status->text == NULL)
     622                if (status->user == NULL || status->text == NULL || last_id == status->id)
    624623                        continue;
    625624
    626                 twitter_add_buddy(ic, status->user->screen_name, status->user->name);
     625                last_id = status->id;
    627626
    628627                strip_html(status->text);
     628
    629629                msg = twitter_msg_add_id(ic, status, "");
    630630
    631631                // Say it!
    632                 if (g_strcasecmp(td->user, status->user->screen_name) == 0)
     632                if (g_strcasecmp(td->user, status->user->screen_name) == 0) {
    633633                        imcb_chat_log(gc, "You: %s", msg ? msg : status->text);
    634                 else
     634                } else {
     635                        twitter_add_buddy(ic, status->user->screen_name, status->user->name);
     636
    635637                        imcb_chat_msg(gc, status->user->screen_name,
    636638                                      msg ? msg : status->text, 0, status->created_at);
     639                }
    637640
    638641                g_free(msg);
    639642
    640                 // Update the home_timeline_id to hold the highest id, so that by the next request
     643                // Update the timeline_id to hold the highest id, so that by the next request
    641644                // we won't pick up the updates already in the list.
    642                 td->home_timeline_id = MAX(td->home_timeline_id, status->id);
     645                td->timeline_id = MAX(td->timeline_id, status->id);
    643646        }
    644647}
     
    654657        char from[MAX_STRING];
    655658        gboolean mode_one;
     659        guint64 last_id = 0;
    656660
    657661        mode_one = g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "one") == 0;
     
    666670
    667671                status = l->data;
     672                if (status->user == NULL || status->text == NULL || last_id == status->id)
     673                        continue;
     674
     675                last_id = status->id;
    668676
    669677                strip_html(status->text);
     
    680688                               text ? text : status->text, 0, status->created_at);
    681689
    682                 // Update the home_timeline_id to hold the highest id, so that by the next request
     690                // Update the timeline_id to hold the highest id, so that by the next request
    683691                // we won't pick up the updates already in the list.
    684                 td->home_timeline_id = MAX(td->home_timeline_id, status->id);
     692                td->timeline_id = MAX(td->timeline_id, status->id);
    685693
    686694                g_free(text);
    687695                g_free(prefix);
     696        }
     697}
     698
     699static void twitter_http_get_home_timeline(struct http_request *req);
     700static void twitter_http_get_mentions(struct http_request *req);
     701
     702/**
     703 * Get the timeline with optionally mentions
     704 */
     705void twitter_get_timeline(struct im_connection *ic, gint64 next_cursor)
     706{
     707        struct twitter_data *td = ic->proto_data;
     708        gboolean include_mentions = set_getbool(&ic->acc->set, "fetch_mentions");
     709
     710        if (td->flags & TWITTER_DOING_TIMELINE) {
     711                return;
     712        }
     713
     714        td->flags |= TWITTER_DOING_TIMELINE;
     715
     716        twitter_get_home_timeline(ic, next_cursor);
     717
     718        if (include_mentions) {
     719                twitter_get_mentions(ic, next_cursor);
     720        }
     721}
     722
     723/**
     724 * Call this one after receiving timeline/mentions. Show to user once we have
     725 * both.
     726 */
     727void twitter_flush_timeline(struct im_connection *ic)
     728{
     729        struct twitter_data *td = ic->proto_data;
     730        gboolean include_mentions = set_getbool(&ic->acc->set, "fetch_mentions");
     731        gboolean show_old_mentions = set_getbool(&ic->acc->set, "show_old_mentions");
     732        struct twitter_xml_list *home_timeline = td->home_timeline_obj;
     733        struct twitter_xml_list *mentions = td->mentions_obj;
     734        GSList *output = NULL;
     735        GSList *l;
     736
     737        if (!(td->flags & TWITTER_GOT_TIMELINE)) {
     738                return;
     739        }
     740
     741        if (include_mentions && !(td->flags & TWITTER_GOT_MENTIONS)) {
     742                return;
     743        }
     744
     745        if (home_timeline && home_timeline->list) {
     746                for (l = home_timeline->list; l; l = g_slist_next(l)) {
     747                        output = g_slist_insert_sorted(output, l->data, twitter_compare_elements);
     748                }
     749        }
     750
     751        if (include_mentions && mentions && mentions->list) {
     752                for (l = mentions->list; l; l = g_slist_next(l)) {
     753                        if (!show_old_mentions && output && twitter_compare_elements(l->data, output->data) < 0) {
     754                                continue;
     755                        }
     756
     757                        output = g_slist_insert_sorted(output, l->data, twitter_compare_elements);
     758                }
     759        }
     760
     761        // See if the user wants to see the messages in a groupchat window or as private messages.
     762        if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0)
     763                twitter_groupchat(ic, output);
     764        else
     765                twitter_private_message_chat(ic, output);
     766
     767        g_slist_free(output);
     768
     769        if (home_timeline && home_timeline->list) {
     770                txl_free(home_timeline);
     771        }
     772
     773        if (mentions && mentions->list) {
     774                txl_free(mentions);
     775        }
     776
     777        td->flags &= ~(TWITTER_DOING_TIMELINE | TWITTER_GOT_TIMELINE | TWITTER_GOT_MENTIONS);
     778}
     779
     780/**
     781 * Get the timeline.
     782 */
     783void twitter_get_home_timeline(struct im_connection *ic, gint64 next_cursor)
     784{
     785        struct twitter_data *td = ic->proto_data;
     786
     787        td->home_timeline_obj = NULL;
     788        td->flags &= ~TWITTER_GOT_TIMELINE;
     789
     790        char *args[4];
     791        args[0] = "cursor";
     792        args[1] = g_strdup_printf("%lld", (long long) next_cursor);
     793        if (td->timeline_id) {
     794                args[2] = "since_id";
     795                args[3] = g_strdup_printf("%llu", (long long unsigned int) td->timeline_id);
     796        }
     797
     798        twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args,
     799                     td->timeline_id ? 4 : 2);
     800
     801        g_free(args[1]);
     802        if (td->timeline_id) {
     803                g_free(args[3]);
     804        }
     805}
     806
     807/**
     808 * Get mentions.
     809 */
     810void twitter_get_mentions(struct im_connection *ic, gint64 next_cursor)
     811{
     812        struct twitter_data *td = ic->proto_data;
     813
     814        td->mentions_obj = NULL;
     815        td->flags &= ~TWITTER_GOT_MENTIONS;
     816
     817        char *args[4];
     818        args[0] = "cursor";
     819        args[1] = g_strdup_printf("%lld", (long long) next_cursor);
     820        if (td->timeline_id) {
     821                args[2] = "since_id";
     822                args[3] = g_strdup_printf("%llu", (long long unsigned int) td->timeline_id);
     823        }
     824
     825        twitter_http(ic, TWITTER_MENTIONS_URL, twitter_http_get_mentions, ic, 0, args,
     826                     td->timeline_id ? 4 : 2);
     827
     828        g_free(args[1]);
     829        if (td->timeline_id) {
     830                g_free(args[3]);
    688831        }
    689832}
     
    713856                imcb_error(ic, "Authentication failure");
    714857                imc_logout(ic, FALSE);
    715                 return;
     858                goto end;
    716859        } else {
    717860                // It didn't go well, output the error and return.
     
    720863                                   TWITTER_HOME_TIMELINE_URL, twitter_parse_error(req));
    721864
    722                 return;
     865                goto end;
    723866        }
    724867
     
    733876        xt_free(parser);
    734877
    735         // See if the user wants to see the messages in a groupchat window or as private messages.
    736         if (txl->list == NULL);
    737         else if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0)
    738                 twitter_groupchat(ic, txl->list);
    739         else
    740                 twitter_private_message_chat(ic, txl->list);
    741 
    742         // Free the structure. 
    743         txl_free(txl);
     878        td->home_timeline_obj = txl;
     879
     880      end:
     881        td->flags |= TWITTER_GOT_TIMELINE;
     882
     883        twitter_flush_timeline(ic);
     884}
     885
     886/**
     887 * Callback for getting mentions.
     888 */
     889static void twitter_http_get_mentions(struct http_request *req)
     890{
     891        struct im_connection *ic = req->data;
     892        struct twitter_data *td;
     893        struct xt_parser *parser;
     894        struct twitter_xml_list *txl;
     895
     896        // Check if the connection is still active.
     897        if (!g_slist_find(twitter_connections, ic))
     898                return;
     899
     900        td = ic->proto_data;
     901
     902        // Check if the HTTP request went well.
     903        if (req->status_code == 200) {
     904                td->http_fails = 0;
     905                if (!(ic->flags & OPT_LOGGED_IN))
     906                        imcb_connected(ic);
     907        } else if (req->status_code == 401) {
     908                imcb_error(ic, "Authentication failure");
     909                imc_logout(ic, FALSE);
     910                goto end;
     911        } else {
     912                // It didn't go well, output the error and return.
     913                if (++td->http_fails >= 5)
     914                        imcb_error(ic, "Could not retrieve " TWITTER_MENTIONS_URL ": %s",
     915                                   twitter_parse_error(req));
     916
     917                goto end;
     918        }
     919
     920        txl = g_new0(struct twitter_xml_list, 1);
     921        txl->list = NULL;
     922
     923        // Parse the data.
     924        parser = xt_new(NULL, txl);
     925        xt_feed(parser, req->reply_body, req->body_size);
     926        // The root <statuses> node should hold the list of statuses <status>
     927        twitter_xt_get_status_list(ic, parser->root, txl);
     928        xt_free(parser);
     929
     930        td->mentions_obj = txl;
     931
     932      end:
     933        td->flags |= TWITTER_GOT_MENTIONS;
     934
     935        twitter_flush_timeline(ic);
    744936}
    745937
Note: See TracChangeset for help on using the changeset viewer.