From dff0e0bdf3acea7d301242421b4fa906ff46278d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 11 Nov 2012 14:42:20 +0000 Subject: Showing tweets now, and leaking less memory. Still lots of cleanup left to do. --- protocols/twitter/twitter.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'protocols/twitter/twitter.c') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index 93ef4ae2..ea440a15 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -4,6 +4,7 @@ * Simple module to facilitate twitter functionality. * * * * Copyright 2009 Geert Mulders * +* Copyright 2010-2012 Wilmer van der Gaast * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * @@ -65,11 +66,18 @@ static void twitter_main_loop_start(struct im_connection *ic) // Run this once. After this queue the main loop function. twitter_main_loop(ic, -1, 0); - - // Queue the main_loop - // Save the return value, so we can remove the timeout on logout. - td->main_loop_id = - b_timeout_add(set_getint(&ic->acc->set, "fetch_interval") * 1000, twitter_main_loop, ic); + + if (set_getbool(&ic->acc->set, "stream")) { + /* That fetch was just to get backlog, the stream will give + us the rest. \o/ */ + twitter_open_stream(ic); + } else { + /* Not using the streaming API, so keep polling the old- + fashioned way. :-( */ + td->main_loop_id = + b_timeout_add(set_getint(&ic->acc->set, "fetch_interval") * 1000, + twitter_main_loop, ic); + } } static void twitter_oauth_start(struct im_connection *ic); @@ -278,6 +286,9 @@ static void twitter_init(account_t * acc) s = set_add(&acc->set, "show_old_mentions", "20", set_eval_int, acc); s = set_add(&acc->set, "strip_newlines", "false", set_eval_bool, acc); + + s = set_add(&acc->set, "stream", "true", set_eval_bool, acc); + s->flags |= ACC_SET_OFFLINE_ONLY; } /** -- cgit v1.2.3 From 1388d303ba0d2097ff745d4a17192195cebbd349 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 11 Nov 2012 17:57:20 +0000 Subject: Mostly finished HTTP streaming support: Shrink the buffer and add a http_close(). --- protocols/twitter/twitter.c | 1 + 1 file changed, 1 insertion(+) (limited to 'protocols/twitter/twitter.c') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index ea440a15..f538f885 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -373,6 +373,7 @@ static void twitter_logout(struct im_connection *ic) imcb_chat_free(td->timeline_gc); if (td) { + http_close(td->stream); oauth_info_free(td->oauth_info); g_free(td->user); g_free(td->prefix); -- cgit v1.2.3 From e132b60e77f395463cf95dc4ee09e96e9658ae35 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 11 Nov 2012 23:32:47 +0000 Subject: Extend keepalive code to time out connections when pings don't get acknowledged, using this for Twitter streams and MSN so far. --- protocols/twitter/twitter.c | 1 + 1 file changed, 1 insertion(+) (limited to 'protocols/twitter/twitter.c') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index f538f885..6bde497a 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -71,6 +71,7 @@ static void twitter_main_loop_start(struct im_connection *ic) /* That fetch was just to get backlog, the stream will give us the rest. \o/ */ twitter_open_stream(ic); + ic->flags |= OPT_PONGS; } else { /* Not using the streaming API, so keep polling the old- fashioned way. :-( */ -- cgit v1.2.3 From f26d9a3e54a89b640902d6ffad4f3d32b76dc97e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 24 Nov 2012 14:10:34 +0000 Subject: Add help info for "stream" setting. Also, disable it for non-Twitter accounts. --- protocols/twitter/twitter.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'protocols/twitter/twitter.c') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index 6bde497a..b7eacc4b 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -64,13 +64,17 @@ static void twitter_main_loop_start(struct im_connection *ic) imcb_log(ic, "Getting initial statuses"); - // Run this once. After this queue the main loop function. + // Run this once. After this queue the main loop function (or open the + // stream if available). twitter_main_loop(ic, -1, 0); if (set_getbool(&ic->acc->set, "stream")) { /* That fetch was just to get backlog, the stream will give us the rest. \o/ */ twitter_open_stream(ic); + + /* Stream sends keepalives (empty lines) or actual data at + least twice a minute. Disconnect if this stops. */ ic->flags |= OPT_PONGS; } else { /* Not using the streaming API, so keep polling the old- @@ -95,7 +99,6 @@ void twitter_login_finish(struct im_connection *ic) !(td->flags & TWITTER_HAVE_FRIENDS)) { imcb_log(ic, "Getting contact list"); twitter_get_friends_ids(ic, -1); - //twitter_get_statuses_friends(ic, -1); } else twitter_main_loop_start(ic); } @@ -288,12 +291,14 @@ static void twitter_init(account_t * acc) s = set_add(&acc->set, "strip_newlines", "false", set_eval_bool, acc); - s = set_add(&acc->set, "stream", "true", set_eval_bool, acc); - s->flags |= ACC_SET_OFFLINE_ONLY; + if (strcmp(acc->prpl->name, "twitter") == 0) { + s = set_add(&acc->set, "stream", "true", set_eval_bool, acc); + s->flags |= ACC_SET_OFFLINE_ONLY; + } } /** - * Login method. Since the twitter API works with seperate HTTP request we + * Login method. Since the twitter API works with separate HTTP request we * only save the user and pass to the twitter_data object. */ static void twitter_login(account_t * acc) @@ -311,6 +316,12 @@ static void twitter_login(account_t * acc) return; } + if (!strstr(url.host, "twitter.com") && + set_getbool(&ic->acc->set, "stream")) { + imcb_error(ic, "Warning: The streaming API is only supported by Twitter, " + "and you seem to be connecting to a different service."); + } + imcb_log(ic, "Connecting"); twitter_connections = g_slist_append(twitter_connections, ic); -- cgit v1.2.3 From c9b5817211cfcbf66a44c6a347245d5913806f91 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Nov 2012 00:55:47 +0000 Subject: 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. --- protocols/twitter/twitter.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'protocols/twitter/twitter.c') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index b7eacc4b..d6cc89f1 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -285,7 +285,6 @@ static void twitter_init(account_t * acc) s = set_add(&acc->set, "oauth", "true", set_eval_oauth, acc); s = set_add(&acc->set, "show_ids", "true", set_eval_bool, acc); - s->flags |= ACC_SET_OFFLINE_ONLY; s = set_add(&acc->set, "show_old_mentions", "20", set_eval_int, acc); @@ -362,8 +361,8 @@ static void twitter_login(account_t * acc) imcb_add_buddy(ic, name, NULL); imcb_buddy_status(ic, name, OPT_LOGGED_IN, NULL, NULL); - if (set_getbool(&acc->set, "show_ids")) - td->log = g_new0(struct twitter_log_data, TWITTER_LOG_LENGTH); + td->log = g_new0(struct twitter_log_data, TWITTER_LOG_LENGTH); + td->log_id = -1; twitter_login_finish(ic); } -- cgit v1.2.3 From 96dd574444f2c99bb0a82b2c354804f03e306f23 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Nov 2012 13:11:19 +0000 Subject: s/twitter_msg/twitter_log/ and use it in a few more places. --- protocols/twitter/twitter.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'protocols/twitter/twitter.c') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index d6cc89f1..ee410abc 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -3,7 +3,7 @@ * BitlBee - An IRC to IM gateway * * Simple module to facilitate twitter functionality. * * * -* Copyright 2009 Geert Mulders * +* Copyright 2009-2010 Geert Mulders * * Copyright 2010-2012 Wilmer van der Gaast * * * * This library is free software; you can redistribute it and/or * @@ -29,17 +29,7 @@ #include "twitter_lib.h" #include "url.h" -#define twitter_msg( ic, fmt... ) \ - do { \ - struct twitter_data *td = ic->proto_data; \ - if( td->timeline_gc ) \ - imcb_chat_log( td->timeline_gc, fmt ); \ - else \ - imcb_log( ic, fmt ); \ - } while( 0 ); - GSList *twitter_connections = NULL; - /** * Main loop function */ @@ -244,7 +234,7 @@ static gboolean twitter_length_check(struct im_connection *ic, gchar * msg) if (max == 0 || (len = g_utf8_strlen(msg, -1) + url_len_diff) <= max) return TRUE; - imcb_error(ic, "Maximum message length exceeded: %d > %d", len, max); + twitter_log(ic, "Maximum message length exceeded: %d > %d", len, max); return FALSE; } @@ -560,7 +550,7 @@ static void twitter_handle_command(struct im_connection *ic, char *message) twitter_status_destroy(ic, id); } else - twitter_msg(ic, "Could not undo last action"); + twitter_log(ic, "Could not undo last action"); g_free(cmds); return; @@ -569,7 +559,7 @@ static void twitter_handle_command(struct im_connection *ic, char *message) if ((id = twitter_message_id_from_command_arg(ic, td, cmd[1]))) { twitter_favourite_tweet(ic, id); } else { - twitter_msg(ic, "Please provide a message ID or username."); + twitter_log(ic, "Please provide a message ID or username."); } g_free(cmds); return; @@ -606,7 +596,7 @@ static void twitter_handle_command(struct im_connection *ic, char *message) if (id) twitter_status_retweet(ic, id); else - twitter_msg(ic, "User `%s' does not exist or didn't " + twitter_log(ic, "User `%s' does not exist or didn't " "post any statuses recently", cmd[1]); g_free(cmds); @@ -637,7 +627,7 @@ static void twitter_handle_command(struct im_connection *ic, char *message) } if (!id || !bu) { - twitter_msg(ic, "User `%s' does not exist or didn't " + twitter_log(ic, "User `%s' does not exist or didn't " "post any statuses recently", cmd[1]); g_free(cmds); return; @@ -684,6 +674,25 @@ static void twitter_handle_command(struct im_connection *ic, char *message) g_free(cmds); } +void twitter_log(struct im_connection *ic, char *format, ... ) +{ + struct twitter_data *td = ic->proto_data; + va_list params; + char *text; + + va_start(params, format); + text = g_strdup_vprintf(format, params); + va_end(params); + + if (td->timeline_gc) + imcb_chat_log(td->timeline_gc, "%s", text); + else + imcb_log(ic, "%s", text); + + g_free(text); +} + + void twitter_initmodule() { struct prpl *ret = g_new0(struct prpl, 1); -- cgit v1.2.3 From 631ec80ccd9d3deeb590ae9537ad4260d804363d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Nov 2012 14:26:23 +0000 Subject: Changed mode/room management a little bit. --- protocols/twitter/twitter.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) (limited to 'protocols/twitter/twitter.c') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index ee410abc..25304bbf 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -52,6 +52,10 @@ static void twitter_main_loop_start(struct im_connection *ic) { struct twitter_data *td = ic->proto_data; + /* Create the room now that we "logged in". */ + if (td->flags & TWITTER_MODE_CHAT) + twitter_groupchat_init(ic); + imcb_log(ic, "Getting initial statuses"); // Run this once. After this queue the main loop function (or open the @@ -75,6 +79,32 @@ static void twitter_main_loop_start(struct im_connection *ic) } } +struct groupchat *twitter_groupchat_init(struct im_connection *ic) +{ + char *name_hint; + struct groupchat *gc; + struct twitter_data *td = ic->proto_data; + GSList *l; + + if (td->timeline_gc) + return td->timeline_gc; + + td->timeline_gc = gc = imcb_chat_new(ic, "twitter/timeline"); + + name_hint = g_strdup_printf("%s_%s", td->prefix, ic->acc->user); + imcb_chat_name_hint(gc, name_hint); + g_free(name_hint); + + for (l = ic->bee->users; l; l = l->next) { + bee_user_t *bu = l->data; + if (bu->ic == ic) + imcb_chat_add_buddy(td->timeline_gc, bu->handle); + } + imcb_chat_add_buddy(gc, ic->acc->user); + + return gc; +} + static void twitter_oauth_start(struct im_connection *ic); void twitter_login_finish(struct im_connection *ic) @@ -85,8 +115,8 @@ void twitter_login_finish(struct im_connection *ic) if (set_getbool(&ic->acc->set, "oauth") && !td->oauth_info) twitter_oauth_start(ic); - else if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "one") != 0 && - !(td->flags & TWITTER_HAVE_FRIENDS)) { + else if ((td->flags & TWITTER_MODE_ONE) && + !(td->flags & TWITTER_HAVE_FRIENDS)) { imcb_log(ic, "Getting contact list"); twitter_get_friends_ids(ic, -1); } else @@ -353,6 +383,14 @@ static void twitter_login(account_t * acc) td->log = g_new0(struct twitter_log_data, TWITTER_LOG_LENGTH); td->log_id = -1; + + s = set_getstr(&ic->acc->set, "mode"); + if (g_strcasecmp(s, "one") == 0) + td->flags |= TWITTER_MODE_ONE; + else if (g_strcasecmp(s, "many") == 0) + td->flags |= TWITTER_MODE_MANY; + else + td->flags |= TWITTER_MODE_CHAT; twitter_login_finish(ic); } -- cgit v1.2.3 From 7f557d53d986c5f688c5781fea04a46464e5b491 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Nov 2012 14:58:29 +0000 Subject: Fixing two oopses from my last commit. --- protocols/twitter/twitter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'protocols/twitter/twitter.c') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index 25304bbf..4f79cd5f 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -115,7 +115,7 @@ void twitter_login_finish(struct im_connection *ic) if (set_getbool(&ic->acc->set, "oauth") && !td->oauth_info) twitter_oauth_start(ic); - else if ((td->flags & TWITTER_MODE_ONE) && + else if (!(td->flags & TWITTER_MODE_ONE) && !(td->flags & TWITTER_HAVE_FRIENDS)) { imcb_log(ic, "Getting contact list"); twitter_get_friends_ids(ic, -1); -- cgit v1.2.3 From 29f72b7a4b4fa960b6fccb45243fa3f5d87a99bf Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Nov 2012 17:43:13 +0000 Subject: Finally cleaned up the show-tweet functions. --- protocols/twitter/twitter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'protocols/twitter/twitter.c') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index 4f79cd5f..2dfb4a26 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -98,7 +98,7 @@ struct groupchat *twitter_groupchat_init(struct im_connection *ic) for (l = ic->bee->users; l; l = l->next) { bee_user_t *bu = l->data; if (bu->ic == ic) - imcb_chat_add_buddy(td->timeline_gc, bu->handle); + imcb_chat_add_buddy(gc, bu->handle); } imcb_chat_add_buddy(gc, ic->acc->user); -- cgit v1.2.3 From 3592b95ac23e243425e20ff9f69f407cb5ec4a74 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Nov 2012 20:21:24 +0000 Subject: To address #991, adding a strict commands mode, where one has to use "post" to post tweets. --- protocols/twitter/twitter.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) (limited to 'protocols/twitter/twitter.c') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index 2dfb4a26..ad75c886 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -218,16 +218,6 @@ static gboolean twitter_oauth_callback(struct oauth_info *info) return TRUE; } - -static char *set_eval_mode(set_t * set, char *value) -{ - if (g_strcasecmp(value, "one") == 0 || - g_strcasecmp(value, "many") == 0 || g_strcasecmp(value, "chat") == 0) - return value; - else - return NULL; -} - int twitter_url_len_diff(gchar *msg, unsigned int target_len) { int url_len_diff = 0; @@ -269,6 +259,23 @@ static gboolean twitter_length_check(struct im_connection *ic, gchar * msg) return FALSE; } +static char *set_eval_commands(set_t * set, char *value) +{ + if (g_strcasecmp(value, "strict") == 0 ) + return value; + else + return set_eval_bool(set, value); +} + +static char *set_eval_mode(set_t * set, char *value) +{ + if (g_strcasecmp(value, "one") == 0 || + g_strcasecmp(value, "many") == 0 || g_strcasecmp(value, "chat") == 0) + return value; + else + return NULL; +} + static void twitter_init(account_t * acc) { set_t *s; @@ -288,7 +295,7 @@ static void twitter_init(account_t * acc) s = set_add(&acc->set, "base_url", def_url, NULL, acc); s->flags |= ACC_SET_OFFLINE_ONLY; - s = set_add(&acc->set, "commands", "true", set_eval_bool, acc); + s = set_add(&acc->set, "commands", "true", set_eval_commands, acc); s = set_add(&acc->set, "fetch_interval", "60", set_eval_int, acc); s->flags |= ACC_SET_OFFLINE_ONLY; @@ -568,6 +575,8 @@ static void twitter_handle_command(struct im_connection *ic, char *message) struct twitter_data *td = ic->proto_data; char *cmds, **cmd, *new = NULL; guint64 in_reply_to = 0; + gboolean strict_commands = + g_strcasecmp(set_getstr(&ic->acc->set, "commands"), "strict") == 0; cmds = g_strdup(message); cmd = split_command_parts(cmds); @@ -575,7 +584,7 @@ static void twitter_handle_command(struct im_connection *ic, char *message) if (cmd[0] == NULL) { g_free(cmds); return; - } else if (!set_getbool(&ic->acc->set, "commands")) { + } else if (!(strict_commands || set_getbool(&ic->acc->set, "commands"))) { /* Not supporting commands. */ } else if (g_strcasecmp(cmd[0], "undo") == 0) { guint64 id; @@ -674,9 +683,12 @@ static void twitter_handle_command(struct im_connection *ic, char *message) in_reply_to = id; } else if (g_strcasecmp(cmd[0], "post") == 0) { message += 5; + strict_commands = FALSE; } - { + if (strict_commands) { + twitter_log(ic, "Unknown command: %s", cmd[0]); + } else { char *s; bee_user_t *bu; -- cgit v1.2.3 From f97b8e9637acba704e976dff79436a83c0f9c63a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Nov 2012 20:43:52 +0000 Subject: Use hex for show_ids, but stick to the 2-char maximum. a 256-message backlog really should be enough. --- protocols/twitter/twitter.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'protocols/twitter/twitter.c') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index ad75c886..fdfc83ec 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -557,13 +557,13 @@ static guint64 twitter_message_id_from_command_arg(struct im_connection *ic, str bee_user_t *bu; guint64 id = 0; if (g_str_has_prefix(arg, "#") && - sscanf(arg + 1, "%" G_GUINT64_FORMAT, &id) == 1) { + sscanf(arg + 1, "%" G_GINT64_MODIFIER "x", &id) == 1) { if (id < TWITTER_LOG_LENGTH && td->log) id = td->log[id].id; } else if ((bu = bee_user_by_handle(ic->bee, ic, arg)) && (tud = bu->data) && tud->last_id) id = tud->last_id; - else if (sscanf(arg, "%" G_GUINT64_FORMAT, &id) == 1){ + else if (sscanf(arg, "%" G_GINT64_MODIFIER "x", &id) == 1){ if (id < TWITTER_LOG_LENGTH && td->log) id = td->log[id].id; } -- cgit v1.2.3 From 67f68282bb20ad3af6dfa6017b89b89ab0a1767f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Nov 2012 22:09:41 +0000 Subject: Only a few commands use twitter_message_id_from_command_arg(), others were still using a decimal scanf format string. Messy code duplication. :-( --- protocols/twitter/twitter.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'protocols/twitter/twitter.c') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index fdfc83ec..91050578 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -591,7 +591,7 @@ static void twitter_handle_command(struct im_connection *ic, char *message) if (cmd[1] == NULL) twitter_status_destroy(ic, td->last_status_id); - else if (sscanf(cmd[1], "%" G_GUINT64_FORMAT, &id) == 1) { + else if (sscanf(cmd[1], "%" G_GINT64_MODIFIER "x", &id) == 1) { if (id < TWITTER_LOG_LENGTH && td->log) id = td->log[id].id; @@ -626,7 +626,7 @@ static void twitter_handle_command(struct im_connection *ic, char *message) /* Report nominally works on users but look up the user who posted the given ID if the user wants to do it that way */ if (g_str_has_prefix(cmd[1], "#") && - sscanf(cmd[1] + 1, "%" G_GUINT64_FORMAT, &id) == 1) { + sscanf(cmd[1] + 1, "%" G_GINT64_MODIFIER "x", &id) == 1) { if (id < TWITTER_LOG_LENGTH && td->log) { if (g_slist_find(ic->bee->users, td->log[id].bu)) { screen_name = td->log[id].bu->handle; @@ -654,7 +654,7 @@ static void twitter_handle_command(struct im_connection *ic, char *message) guint64 id = 0; if (g_str_has_prefix(cmd[1], "#") && - sscanf(cmd[1] + 1, "%" G_GUINT64_FORMAT, &id) == 1 && + sscanf(cmd[1] + 1, "%" G_GINT64_MODIFIER "x", &id) == 1 && (id < TWITTER_LOG_LENGTH) && td->log) { bu = td->log[id].bu; if (g_slist_find(ic->bee->users, bu)) @@ -664,7 +664,7 @@ static void twitter_handle_command(struct im_connection *ic, char *message) } else if ((bu = bee_user_by_handle(ic->bee, ic, cmd[1])) && (tud = bu->data) && tud->last_id) { id = tud->last_id; - } else if (sscanf(cmd[1], "%" G_GUINT64_FORMAT, &id) == 1 && + } else if (sscanf(cmd[1], "%" G_GINT64_MODIFIER "x", &id) == 1 && (id < TWITTER_LOG_LENGTH) && td->log) { bu = td->log[id].bu; if (g_slist_find(ic->bee->users, bu)) -- cgit v1.2.3 From 3ca001bcb054e861ef9ad6e818fbb6615a519804 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 2 Dec 2012 12:53:12 +0000 Subject: Extend twitter_message_id_from_command_arg() a little bit and use it for all commands. Also fixed reply command in strict commands mode. --- protocols/twitter/twitter.c | 154 +++++++++++++++++++------------------------- 1 file changed, 66 insertions(+), 88 deletions(-) (limited to 'protocols/twitter/twitter.c') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index 91050578..651bf345 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -552,21 +552,40 @@ static void twitter_buddy_data_free(struct bee_user *bu) * * Returns 0 if the user provides garbage. */ -static guint64 twitter_message_id_from_command_arg(struct im_connection *ic, struct twitter_data *td, char *arg) { +static guint64 twitter_message_id_from_command_arg(struct im_connection *ic, char *arg, bee_user_t **bu_) { + struct twitter_data *td = ic->proto_data; struct twitter_user_data *tud; - bee_user_t *bu; + bee_user_t *bu = NULL; guint64 id = 0; - if (g_str_has_prefix(arg, "#") && - sscanf(arg + 1, "%" G_GINT64_MODIFIER "x", &id) == 1) { - if (id < TWITTER_LOG_LENGTH && td->log) - id = td->log[id].id; - } else if ((bu = bee_user_by_handle(ic->bee, ic, arg)) && - (tud = bu->data) && tud->last_id) - id = tud->last_id; - else if (sscanf(arg, "%" G_GINT64_MODIFIER "x", &id) == 1){ - if (id < TWITTER_LOG_LENGTH && td->log) + + if (bu_) + *bu_ = NULL; + if (!arg || !arg[0]) + return 0; + + if (arg[0] != '#' && (bu = bee_user_by_handle(ic->bee, ic, arg))) { + if ((tud = bu->data)) + id = tud->last_id; + } else { + if (arg[0] == '#') + arg++; + if (sscanf(arg, "%" G_GINT64_MODIFIER "x", &id) == 1 && + id < TWITTER_LOG_LENGTH) { + bu = td->log[id].bu; id = td->log[id].id; + /* Beware of dangling pointers! */ + if (!g_slist_find(ic->bee->users, bu)) + bu = NULL; + } else if (sscanf(arg, "%" G_GINT64_MODIFIER "d", &id) == 1) { + /* Allow normal tweet IDs as well; not a very useful + feature but it's always been there. Just ignore + very low IDs to avoid accidents. */ + if (id < 1000000) + id = 0; + } } + if (bu_) + *bu_ = bu; return id; } @@ -574,70 +593,56 @@ static void twitter_handle_command(struct im_connection *ic, char *message) { struct twitter_data *td = ic->proto_data; char *cmds, **cmd, *new = NULL; - guint64 in_reply_to = 0; - gboolean strict_commands = - g_strcasecmp(set_getstr(&ic->acc->set, "commands"), "strict") == 0; + guint64 in_reply_to = 0, id; + gboolean allow_post = + g_strcasecmp(set_getstr(&ic->acc->set, "commands"), "strict") != 0; + bee_user_t *bu = NULL; cmds = g_strdup(message); cmd = split_command_parts(cmds); if (cmd[0] == NULL) { - g_free(cmds); - return; - } else if (!(strict_commands || set_getbool(&ic->acc->set, "commands"))) { - /* Not supporting commands. */ + goto eof; + } else if (!set_getbool(&ic->acc->set, "commands") && allow_post) { + /* Not supporting commands if "commands" is set to true/strict. */ } else if (g_strcasecmp(cmd[0], "undo") == 0) { - guint64 id; - if (cmd[1] == NULL) twitter_status_destroy(ic, td->last_status_id); - else if (sscanf(cmd[1], "%" G_GINT64_MODIFIER "x", &id) == 1) { - if (id < TWITTER_LOG_LENGTH && td->log) - id = td->log[id].id; - + else if ((id = twitter_message_id_from_command_arg(ic, cmd[1], NULL))) twitter_status_destroy(ic, id); - } else + else twitter_log(ic, "Could not undo last action"); - g_free(cmds); - return; + goto eof; } else if (g_strcasecmp(cmd[0], "favourite") == 0 && cmd[1]) { - guint64 id; - if ((id = twitter_message_id_from_command_arg(ic, td, cmd[1]))) { + if ((id = twitter_message_id_from_command_arg(ic, cmd[1], NULL))) { twitter_favourite_tweet(ic, id); } else { twitter_log(ic, "Please provide a message ID or username."); } - g_free(cmds); - return; + goto eof; } else if (g_strcasecmp(cmd[0], "follow") == 0 && cmd[1]) { twitter_add_buddy(ic, cmd[1], NULL); - g_free(cmds); - return; + goto eof; } else if (g_strcasecmp(cmd[0], "unfollow") == 0 && cmd[1]) { twitter_remove_buddy(ic, cmd[1], NULL); - g_free(cmds); - return; + goto eof; } else if ((g_strcasecmp(cmd[0], "report") == 0 || g_strcasecmp(cmd[0], "spam") == 0) && cmd[1]) { - char * screen_name; - guint64 id; - screen_name = cmd[1]; + char *screen_name; + /* Report nominally works on users but look up the user who posted the given ID if the user wants to do it that way */ - if (g_str_has_prefix(cmd[1], "#") && - sscanf(cmd[1] + 1, "%" G_GINT64_MODIFIER "x", &id) == 1) { - if (id < TWITTER_LOG_LENGTH && td->log) { - if (g_slist_find(ic->bee->users, td->log[id].bu)) { - screen_name = td->log[id].bu->handle; - } - } - } + twitter_message_id_from_command_arg(ic, cmd[1], &bu); + if (bu) + screen_name = bu->handle; + else + screen_name = cmd[1]; + twitter_report_spam(ic, screen_name); - g_free(cmds); - return; + goto eof; } else if (g_strcasecmp(cmd[0], "rt") == 0 && cmd[1]) { - guint64 id = twitter_message_id_from_command_arg(ic, td, cmd[1]); + id = twitter_message_id_from_command_arg(ic, cmd[1], NULL); td->last_status_id = 0; if (id) @@ -646,57 +651,27 @@ static void twitter_handle_command(struct im_connection *ic, char *message) twitter_log(ic, "User `%s' does not exist or didn't " "post any statuses recently", cmd[1]); - g_free(cmds); - return; + goto eof; } else if (g_strcasecmp(cmd[0], "reply") == 0 && cmd[1] && cmd[2]) { - struct twitter_user_data *tud; - bee_user_t *bu = NULL; - guint64 id = 0; - - if (g_str_has_prefix(cmd[1], "#") && - sscanf(cmd[1] + 1, "%" G_GINT64_MODIFIER "x", &id) == 1 && - (id < TWITTER_LOG_LENGTH) && td->log) { - bu = td->log[id].bu; - if (g_slist_find(ic->bee->users, bu)) - id = td->log[id].id; - else - bu = NULL; - } else if ((bu = bee_user_by_handle(ic->bee, ic, cmd[1])) && - (tud = bu->data) && tud->last_id) { - id = tud->last_id; - } else if (sscanf(cmd[1], "%" G_GINT64_MODIFIER "x", &id) == 1 && - (id < TWITTER_LOG_LENGTH) && td->log) { - bu = td->log[id].bu; - if (g_slist_find(ic->bee->users, bu)) - id = td->log[id].id; - else - bu = NULL; - } - + id = twitter_message_id_from_command_arg(ic, cmd[1], &bu); if (!id || !bu) { twitter_log(ic, "User `%s' does not exist or didn't " "post any statuses recently", cmd[1]); - g_free(cmds); - return; + goto eof; } message = new = g_strdup_printf("@%s %s", bu->handle, message + (cmd[2] - cmd[0])); in_reply_to = id; + allow_post = TRUE; } else if (g_strcasecmp(cmd[0], "post") == 0) { message += 5; - strict_commands = FALSE; + allow_post = TRUE; } - if (strict_commands) { - twitter_log(ic, "Unknown command: %s", cmd[0]); - } else { + if (allow_post) { char *s; - bee_user_t *bu; - if (!twitter_length_check(ic, message)) { - g_free(new); - g_free(cmds); - return; - } + if (!twitter_length_check(ic, message)) + goto eof; s = cmd[0] + strlen(cmd[0]) - 1; if (!new && s > cmd[0] && (*s == ':' || *s == ',')) { @@ -719,8 +694,11 @@ static void twitter_handle_command(struct im_connection *ic, char *message) this would delete the second-last Tweet. Prevent that. */ td->last_status_id = 0; twitter_post_status(ic, message, in_reply_to); - g_free(new); + } else { + twitter_log(ic, "Unknown command: %s", cmd[0]); } +eof: + g_free(new); g_free(cmds); } -- cgit v1.2.3