Changeset 2322a9f for protocols/twitter


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

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

Location:
protocols/twitter
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • protocols/twitter/twitter.c

    r4804b2f r2322a9f  
    3030
    3131#define twitter_msg( ic, fmt... ) \
    32         do {                                                        \
    33                 struct twitter_data *td = ic->proto_data;           \
    34                 if( td->home_timeline_gc )                          \
    35                         imcb_chat_log( td->home_timeline_gc, fmt ); \
    36                 else                                                \
    37                         imcb_log( ic, fmt );                        \
     32        do {                                            \
     33                struct twitter_data *td = ic->proto_data;   \
     34                if( td->timeline_gc )                       \
     35                        imcb_chat_log( td->timeline_gc, fmt ); \
     36                else                                        \
     37                        imcb_log( ic, fmt );                    \
    3838        } while( 0 );
    3939
     
    5252
    5353        // Do stuff..
    54         twitter_get_home_timeline(ic, -1);
     54        twitter_get_timeline(ic, -1);
    5555
    5656        // If we are still logged in run this function again after timeout.
     
    6969        // Queue the main_loop
    7070        // Save the return value, so we can remove the timeout on logout.
    71         td->main_loop_id = b_timeout_add(60000, twitter_main_loop, ic);
     71        td->main_loop_id =
     72            b_timeout_add(set_getint(&ic->acc->set, "fetch_interval") * 1000, twitter_main_loop, ic);
    7273}
    7374
     
    7778{
    7879        struct twitter_data *td = ic->proto_data;
     80
     81        td->flags &= ~TWITTER_DOING_TIMELINE;
    7982
    8083        if (set_getbool(&ic->acc->set, "oauth") && !td->oauth_info)
     
    216219                def_oauth = "true";
    217220        } else {                /* if( strcmp( acc->prpl->name, "identica" ) == 0 ) */
    218 
    219221                def_url = IDENTICA_API_URL;
    220222                def_oauth = "false";
     
    228230        s = set_add(&acc->set, "commands", "true", set_eval_bool, acc);
    229231
     232        s = set_add(&acc->set, "fetch_interval", "60", set_eval_int, acc);
     233        s->flags |= ACC_SET_OFFLINE_ONLY;
     234
     235        s = set_add(&acc->set, "fetch_mentions", "true", set_eval_bool, acc);
     236
    230237        s = set_add(&acc->set, "message_length", "140", set_eval_int, acc);
    231238
     
    235242        s = set_add(&acc->set, "show_ids", "false", set_eval_bool, acc);
    236243        s->flags |= ACC_SET_OFFLINE_ONLY;
     244
     245        s = set_add(&acc->set, "show_old_mentions", "true", set_eval_bool, acc);
    237246
    238247        s = set_add(&acc->set, "oauth", def_oauth, set_eval_bool, acc);
     
    317326        b_event_remove(td->main_loop_id);
    318327
    319         if (td->home_timeline_gc)
    320                 imcb_chat_free(td->home_timeline_gc);
     328        if (td->timeline_gc)
     329                imcb_chat_free(td->timeline_gc);
    321330
    322331        if (td) {
     
    404413        struct twitter_data *td = c->ic->proto_data;
    405414
    406         if (c != td->home_timeline_gc)
     415        if (c != td->timeline_gc)
    407416                return;         /* WTF? */
    408417
    409418        /* If the user leaves the channel: Fine. Rejoin him/her once new
    410419           tweets come in. */
    411         imcb_chat_free(td->home_timeline_gc);
    412         td->home_timeline_gc = NULL;
     420        imcb_chat_free(td->timeline_gc);
     421        td->timeline_gc = NULL;
    413422}
    414423
  • protocols/twitter/twitter.h

    r4804b2f r2322a9f  
    3636{
    3737        TWITTER_HAVE_FRIENDS = 1,
     38        TWITTER_DOING_TIMELINE = 0x10000,
     39        TWITTER_GOT_TIMELINE = 0x20000,
     40        TWITTER_GOT_MENTIONS = 0x40000,
    3841} twitter_flags_t;
    3942
     
    4447        char* user;
    4548        struct oauth_info *oauth_info;
     49
     50        gpointer home_timeline_obj;
     51        gpointer mentions_obj;
     52
     53        guint64 timeline_id;
     54
    4655        GSList *follow_ids;
    4756       
    48         guint64 home_timeline_id;
    4957        guint64 last_status_id; /* For undo */
    5058        gint main_loop_id;
    51         struct groupchat *home_timeline_gc;
     59        struct groupchat *timeline_gc;
    5260        gint http_fails;
    5361        twitter_flags_t flags;
  • 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
  • protocols/twitter/twitter_lib.h

    r4804b2f r2322a9f  
    7676#define TWITTER_BLOCKS_DESTROY_URL "/blocks/destroy/"
    7777
     78void twitter_get_timeline(struct im_connection *ic, gint64 next_cursor);
    7879void twitter_get_friends_ids(struct im_connection *ic, gint64 next_cursor);
    7980void twitter_get_home_timeline(struct im_connection *ic, gint64 next_cursor);
     81void twitter_get_mentions(struct im_connection *ic, gint64 next_cursor);
    8082void twitter_get_statuses_friends(struct im_connection *ic, gint64 next_cursor);
    8183
Note: See TracChangeset for help on using the changeset viewer.