Changes in / [70ec7ab:5ca1416]


Ignore:
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • doc/user-guide/commands.xml

    r70ec7ab r5ca1416  
    121121                        <description>
    122122                                <para>
    123                                         This commands deletes an account from your account list. You should signoff the account before deleting it.
     123                                        This command deletes an account from your account list. You should signoff the account before deleting it.
    124124                                </para>
    125125
     
    853853                                <varlistentry><term>favourite &lt;screenname|#id&gt;</term><listitem><para>Favo<emphasis>u</emphasis>rite the given user's most recent tweet, or the given tweet ID.</para></listitem></varlistentry>
    854854                                <varlistentry><term>post &lt;message&gt;</term><listitem><para>Post a tweet</para></listitem></varlistentry>
     855                                <varlistentry><term>url &lt;screenname|#id&gt;</term><listitem><para>Show URL for a tweet to open it in a browser (and see context)</para></listitem></varlistentry>
    855856                        </variablelist>
    856857
  • protocols/twitter/twitter.c

    r70ec7ab r5ca1416  
    867867}
    868868
     869bee_user_t twitter_log_local_user;
     870
    869871/** Convert the given bitlbee tweet ID, bitlbee username, or twitter tweet ID
    870872 *  into a twitter tweet ID.
     
    897899                        bu = td->log[id].bu;
    898900                        id = td->log[id].id;
    899                         /* Beware of dangling pointers! */
    900                         if (!g_slist_find(ic->bee->users, bu)) {
    901                                 bu = NULL;
    902                         }
    903901                } else if (twitter_parse_id(arg, 10, &id)) {
    904902                        /* Allow normal tweet IDs as well; not a very useful
     
    911909        }
    912910        if (bu_) {
     911                if (bu == &twitter_log_local_user) {
     912                        /* HACK alert. There's no bee_user object for the local
     913                         * user so just fake one for the few cmds that need it. */
     914                        twitter_log_local_user.handle = td->user;
     915                } else {
     916                        /* Beware of dangling pointers! */
     917                        if (!g_slist_find(ic->bee->users, bu)) {
     918                                bu = NULL;
     919                        }
     920                }
    913921                *bu_ = bu;
    914922        }
     
    10031011                in_reply_to = id;
    10041012                allow_post = TRUE;
     1013        } else if (g_strcasecmp(cmd[0], "url") == 0) {
     1014                id = twitter_message_id_from_command_arg(ic, cmd[1], &bu);
     1015                if (!id) {
     1016                        twitter_log(ic, "Tweet `%s' does not exist", cmd[1]);
     1017                } else {
     1018                        /* More common link is twitter.com/$UID/status/$ID (and that's
     1019                         * what this will 302 to) but can't generate that since for RTs,
     1020                         * bu here points at the retweeter while id contains the id of
     1021                         * the original message. */
     1022                        twitter_log(ic, "https://twitter.com/statuses/%lld", id);
     1023                }
     1024                goto eof;
     1025
    10051026        } else if (g_strcasecmp(cmd[0], "post") == 0) {
    10061027                message += 5;
  • protocols/twitter/twitter.h

    r70ec7ab r5ca1416  
    101101struct twitter_log_data {
    102102        guint64 id;
    103         struct bee_user *bu; /* DANGER: can be a dead pointer. Check it first. */
     103        /* DANGER: bu can be a dead pointer. Check it first.
     104         * twitter_message_id_from_command_arg() will do this. */
     105        struct bee_user *bu;
    104106};
    105107
     
    110112 */
    111113extern GSList *twitter_connections;
     114
     115/**
     116 * Evil hack: Fake bee_user which will always point at the local user.
     117 * Sometimes used as a return value by twitter_message_id_from_command_arg.
     118 * NOT thread safe but don't you dare to even think of ever making BitlBee
     119 * threaded. :-)
     120 */
     121extern bee_user_t twitter_log_local_user;
    112122
    113123void twitter_login_finish(struct im_connection *ic);
  • protocols/twitter/twitter_lib.c

    r70ec7ab r5ca1416  
    460460#endif
    461461
    462 static char* expand_entities(char* text, const json_value *entities);
     462static void expand_entities(char **text, const json_value *node);
    463463
    464464/**
     
    473473{
    474474        struct twitter_xml_status *txs;
    475         const json_value *rt = NULL, *entities = NULL;
     475        const json_value *rt = NULL;
    476476
    477477        if (node->type != json_object) {
     
    501501                } else if (strcmp("in_reply_to_status_id", k) == 0 && v->type == json_integer) {
    502502                        txs->reply_to = v->u.integer;
    503                 } else if (strcmp("entities", k) == 0 && v->type == json_object) {
    504                         entities = v;
    505503                }
    506504        }
     
    516514                        txs_free(rtxs);
    517515                }
    518         } else if (entities) {
    519                 txs->text = expand_entities(txs->text, entities);
     516        } else {
     517                expand_entities(&txs->text, node);
    520518        }
    521519
     
    534532{
    535533        struct twitter_xml_status *txs;
    536         const json_value *entities = NULL;
    537534
    538535        if (node->type != json_object) {
     
    561558        }
    562559
    563         if (entities) {
    564                 txs->text = expand_entities(txs->text, entities);
    565         }
     560        expand_entities(&txs->text, node);
    566561
    567562        if (txs->text && txs->user && txs->id) {
     
    573568}
    574569
    575 static char* expand_entities(char* text, const json_value *entities)
    576 {
     570static void expand_entities(char **text, const json_value *node)
     571{
     572        json_value *entities, *quoted;
     573        char *quote_url = NULL, *quote_text = NULL;
     574
     575        if (!((entities = json_o_get(node, "entities")) && entities->type == json_object))
     576                return;
     577        if ((quoted = json_o_get(node, "quoted_status")) && quoted->type == json_object) {
     578                /* New "retweets with comments" feature. Note that this info
     579                 * seems to be included in the streaming API only! Grab the
     580                 * full message and try to insert it when we run into the
     581                 * Tweet entity. */
     582                struct twitter_xml_status *txs = twitter_xt_get_status(quoted);
     583                quote_text = g_strdup_printf("@%s: %s", txs->user->screen_name, txs->text);
     584                quote_url = g_strdup_printf("%s/status/%" G_GUINT64_FORMAT, txs->user->screen_name, txs->id);
     585                txs_free(txs);
     586        } else {
     587                quoted = NULL;
     588        }
     589
    577590        JSON_O_FOREACH(entities, k, v) {
    578591                int i;
     
    586599
    587600                for (i = 0; i < v->u.array.length; i++) {
     601                        const char *format = "%s%s <%s>%s";
     602
    588603                        if (v->u.array.values[i]->type != json_object) {
    589604                                continue;
     
    592607                        const char *kort = json_o_str(v->u.array.values[i], "url");
    593608                        const char *disp = json_o_str(v->u.array.values[i], "display_url");
     609                        const char *full = json_o_str(v->u.array.values[i], "expanded_url");
    594610                        char *pos, *new;
    595611
    596                         if (!kort || !disp || !(pos = strstr(text, kort))) {
     612                        if (!kort || !disp || !(pos = strstr(*text, kort))) {
    597613                                continue;
    598614                        }
     615                        if (quote_url && strstr(full, quote_url)) {
     616                                format = "%s<%s> [%s]%s";
     617                                disp = quote_text;
     618                        }
    599619
    600620                        *pos = '\0';
    601                         new = g_strdup_printf("%s%s <%s>%s", text, kort,
     621                        new = g_strdup_printf(format, *text, kort,
    602622                                              disp, pos + strlen(kort));
    603623
    604                         g_free(text);
    605                         text = new;
    606                 }
    607         }
    608 
    609         return text;
     624                        g_free(*text);
     625                        *text = new;
     626                }
     627        }
     628        g_free(quote_text);
     629        g_free(quote_url);
    610630}
    611631
     
    681701        if (g_strcasecmp(txs->user->screen_name, td->user) == 0) {
    682702                td->log[td->log_id].id = txs->rt_id;
     703                /* More useful than NULL. */
     704                td->log[td->log_id].bu = &twitter_log_local_user;
    683705        }
    684706
Note: See TracChangeset for help on using the changeset viewer.