aboutsummaryrefslogtreecommitdiffstats
path: root/protocols/twitter/twitter_lib.c
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2012-11-25 00:55:47 +0000
committerWilmer van der Gaast <wilmer@gaast.net>2012-11-25 00:55:47 +0000
commitc9b5817211cfcbf66a44c6a347245d5913806f91 (patch)
treed934426c84e10d1d07bb1f04b9055051dd69bcd4 /protocols/twitter/twitter_lib.c
parent5f2f72849ec0713d65b709e6962aeaac25aa89c7 (diff)
Minor rework: Always fill td->log now and use it not just for show_ids, but
also for stream deduplication. Also, drop tweets from unknown people unless fetch_mentions is set. The stream will feed us that spam either way but not everyone wants to see it. Last, fixing a bug where in streaming mode, per-user last tweet times were no longer getting tracked.
Diffstat (limited to 'protocols/twitter/twitter_lib.c')
-rw-r--r--protocols/twitter/twitter_lib.c131
1 files changed, 84 insertions, 47 deletions
diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c
index 36efc18a..7048e6ae 100644
--- a/protocols/twitter/twitter_lib.c
+++ b/protocols/twitter/twitter_lib.c
@@ -457,12 +457,14 @@ static char* expand_entities(char* text, const json_value *entities);
* - the status id and
* - the user in a twitter_xml_user struct.
*/
-static gboolean twitter_xt_get_status(const json_value *node, struct twitter_xml_status *txs)
+static struct twitter_xml_status *twitter_xt_get_status(const json_value *node)
{
+ struct twitter_xml_status *txs;
const json_value *rt = NULL, *entities = NULL;
if (node->type != json_object)
return FALSE;
+ txs = g_new0(struct twitter_xml_status, 1);
JSON_O_FOREACH (node, k, v) {
if (strcmp("text", k) == 0 && v->type == json_string) {
@@ -491,20 +493,22 @@ static gboolean twitter_xt_get_status(const json_value *node, struct twitter_xml
/* If it's a (truncated) retweet, get the original. Even if the API claims it
wasn't truncated because it may be lying. */
if (rt) {
- struct twitter_xml_status *rtxs = g_new0(struct twitter_xml_status, 1);
- if (!twitter_xt_get_status(rt, rtxs)) {
+ struct twitter_xml_status *rtxs = twitter_xt_get_status(rt);
+ if (rtxs) {
+ g_free(txs->text);
+ txs->text = g_strdup_printf("RT @%s: %s", rtxs->user->screen_name, rtxs->text);
+ txs->id = rtxs->id;
txs_free(rtxs);
- return TRUE;
}
-
- g_free(txs->text);
- txs->text = g_strdup_printf("RT @%s: %s", rtxs->user->screen_name, rtxs->text);
- txs_free(rtxs);
} else if (entities) {
txs->text = expand_entities(txs->text, entities);
}
- return txs->text && txs->user && txs->id;
+ if (txs->text && txs->user && txs->id)
+ return txs;
+
+ txs_free(txs);
+ return NULL;
}
/**
@@ -584,7 +588,6 @@ static gboolean twitter_xt_get_status_list(struct im_connection *ic, const json_
struct twitter_xml_list *txl)
{
struct twitter_xml_status *txs;
- bee_user_t *bu;
int i;
// Set the type of the list.
@@ -596,54 +599,61 @@ static gboolean twitter_xt_get_status_list(struct im_connection *ic, const json_
// The root <statuses> node should hold the list of statuses <status>
// Walk over the nodes children.
for (i = 0; i < node->u.array.length; i ++) {
- txs = g_new0(struct twitter_xml_status, 1);
- twitter_xt_get_status(node->u.array.values[i], txs);
- // Put the item in the front of the list.
+ txs = twitter_xt_get_status(node->u.array.values[i]);
+ if (!txs)
+ continue;
+
txl->list = g_slist_prepend(txl->list, txs);
-
- if (txs->user && txs->user->screen_name &&
- (bu = bee_user_by_handle(ic->bee, ic, txs->user->screen_name))) {
- struct twitter_user_data *tud = bu->data;
-
- if (txs->id > tud->last_id) {
- tud->last_id = txs->id;
- tud->last_time = txs->created_at;
- }
- }
}
return TRUE;
}
+/* Will log messages either way. Need to keep track of IDs for stream deduping.
+ Plus, show_ids is on by default and I don't see why anyone would disable it. */
static char *twitter_msg_add_id(struct im_connection *ic,
struct twitter_xml_status *txs, const char *prefix)
{
struct twitter_data *td = ic->proto_data;
- char *ret = NULL;
-
- if (!set_getbool(&ic->acc->set, "show_ids")) {
- if (*prefix)
- return g_strconcat(prefix, txs->text, NULL);
- else
- return NULL;
- }
+ int reply_to = -1;
+ bee_user_t *bu;
- td->log[td->log_id].id = txs->id;
- td->log[td->log_id].bu = bee_user_by_handle(ic->bee, ic, txs->user->screen_name);
if (txs->reply_to) {
int i;
for (i = 0; i < TWITTER_LOG_LENGTH; i++)
if (td->log[i].id == txs->reply_to) {
- ret = g_strdup_printf("\002[\002%02d->%02d\002]\002 %s%s",
- td->log_id, i, prefix, txs->text);
+ reply_to = i;
break;
}
}
- if (ret == NULL)
- ret = g_strdup_printf("\002[\002%02d\002]\002 %s%s", td->log_id, prefix, txs->text);
- td->log_id = (td->log_id + 1) % TWITTER_LOG_LENGTH;
- return ret;
+ if (txs->user && txs->user->screen_name &&
+ (bu = bee_user_by_handle(ic->bee, ic, txs->user->screen_name))) {
+ struct twitter_user_data *tud = bu->data;
+
+ if (txs->id > tud->last_id) {
+ tud->last_id = txs->id;
+ tud->last_time = txs->created_at;
+ }
+ }
+
+ td->log_id = (td->log_id + 1) % TWITTER_LOG_LENGTH;
+ td->log[td->log_id].id = txs->id;
+ td->log[td->log_id].bu = bee_user_by_handle(ic->bee, ic, txs->user->screen_name);
+
+ if (set_getbool(&ic->acc->set, "show_ids")) {
+ if (reply_to != -1)
+ return g_strdup_printf("\002[\002%02d->%02d\002]\002 %s%s",
+ td->log_id, reply_to, prefix, txs->text);
+ else
+ return g_strdup_printf("\002[\002%02d\002]\002 %s%s",
+ td->log_id, prefix, txs->text);
+ } else {
+ if (*prefix)
+ return g_strconcat(prefix, txs->text, NULL);
+ else
+ return NULL;
+ }
}
static void twitter_groupchat_init(struct im_connection *ic)
@@ -825,19 +835,16 @@ static void twitter_http_stream(struct http_request *req)
}
static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value *o);
+static gboolean twitter_stream_handle_status(struct im_connection *ic, struct twitter_xml_status *txs);
static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o)
{
struct twitter_data *td = ic->proto_data;
- struct twitter_xml_status *txs = g_new0(struct twitter_xml_status, 1);
+ struct twitter_xml_status *txs;
json_value *c;
- if (twitter_xt_get_status(o, txs)) {
- GSList *output = g_slist_append(NULL, txs);
- twitter_groupchat(ic, output);
- txs_free(txs);
- g_slist_free(output);
- return TRUE;
+ if ((txs = twitter_xt_get_status(o))) {
+ return twitter_stream_handle_status(ic, txs);
} else if ((c = json_o_get(o, "direct_message")) &&
twitter_xt_get_dm(c, txs)) {
GSList *output = g_slist_append(NULL, txs);
@@ -859,10 +866,40 @@ static gboolean twitter_stream_handle_object(struct im_connection *ic, json_valu
}
return TRUE;
}
- txs_free(txs);
return FALSE;
}
+static gboolean twitter_stream_handle_status(struct im_connection *ic, struct twitter_xml_status *txs)
+{
+ struct twitter_data *td = ic->proto_data;
+ int i;
+
+ for (i = 0; i < TWITTER_LOG_LENGTH; i++) {
+ if (td->log[i].id == txs->id) {
+ /* Got a duplicate (RT, surely). Drop it. */
+ txs_free(txs);
+ return TRUE;
+ }
+ }
+
+ if (!(set_getbool(&ic->acc->set, "fetch_mentions") ||
+ bee_user_by_handle(ic->bee, ic, txs->user->screen_name))) {
+ /* Tweet is from an unknown person and the user does not want
+ to see @mentions, so drop it. twitter_stream_handle_event()
+ picks up new follows so this simple filter should be safe. */
+ /* TODO: The streaming API seems to do poor @mention matching.
+ I.e. I'm getting mentions for @WilmerSomething, not just for
+ @Wilmer. But meh. You want spam, you get spam. */
+ return TRUE;
+ }
+
+ GSList *output = g_slist_append(NULL, txs);
+ twitter_groupchat(ic, output);
+ txs_free(txs);
+ g_slist_free(output);
+ return TRUE;
+}
+
static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value *o)
{
struct twitter_data *td = ic->proto_data;