aboutsummaryrefslogtreecommitdiffstats
path: root/protocols/twitter
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/twitter')
-rw-r--r--protocols/twitter/twitter.c255
-rw-r--r--protocols/twitter/twitter.h36
-rw-r--r--protocols/twitter/twitter_http.c54
-rw-r--r--protocols/twitter/twitter_http.h3
-rw-r--r--protocols/twitter/twitter_lib.c421
5 files changed, 452 insertions, 317 deletions
diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c
index eb30187f..f3dcde31 100644
--- a/protocols/twitter/twitter.c
+++ b/protocols/twitter/twitter.c
@@ -90,14 +90,15 @@ static struct twitter_filter *twitter_filter_get(struct groupchat *c,
{
struct twitter_data *td = c->ic->proto_data;
struct twitter_filter *tf = NULL;
- struct twitter_filter tfc = {type, (char*) text};
+ struct twitter_filter tfc = { type, (char *) text };
GSList *l;
for (l = td->filters; l; l = g_slist_next(l)) {
tf = l->data;
- if (twitter_filter_cmp(tf, &tfc) == 0)
+ if (twitter_filter_cmp(tf, &tfc) == 0) {
break;
+ }
tf = NULL;
}
@@ -109,15 +110,17 @@ static struct twitter_filter *twitter_filter_get(struct groupchat *c,
td->filters = g_slist_prepend(td->filters, tf);
}
- if (!g_slist_find(tf->groupchats, c))
+ if (!g_slist_find(tf->groupchats, c)) {
tf->groupchats = g_slist_prepend(tf->groupchats, c);
+ }
- if (td->filter_update_id > 0)
+ if (td->filter_update_id > 0) {
b_event_remove(td->filter_update_id);
+ }
/* Wait for other possible filter changes to avoid request spam */
td->filter_update_id = b_timeout_add(TWITTER_FILTER_UPDATE_WAIT,
- twitter_filter_update, c->ic);
+ twitter_filter_update, c->ic);
return tf;
}
@@ -148,12 +151,14 @@ static void twitter_filter_remove(struct groupchat *c)
}
}
- if (td->filter_update_id > 0)
+ if (td->filter_update_id > 0) {
b_event_remove(td->filter_update_id);
+ }
/* Wait for other possible filter changes to avoid request spam */
td->filter_update_id = b_timeout_add(TWITTER_FILTER_UPDATE_WAIT,
- twitter_filter_update, c->ic);}
+ twitter_filter_update, c->ic);
+}
static void twitter_filter_remove_all(struct im_connection *ic)
{
@@ -168,8 +173,9 @@ static void twitter_filter_remove_all(struct im_connection *ic)
/* Build up a list of groupchats to be freed */
for (p = tf->groupchats; p; p = g_slist_next(p)) {
- if (!g_slist_find(chats, p->data))
+ if (!g_slist_find(chats, p->data)) {
chats = g_slist_prepend(chats, p->data);
+ }
}
p = l;
@@ -216,8 +222,9 @@ static GSList *twitter_filter_parse(struct groupchat *c, const char *text)
};
for (f = fs; *f; f++) {
- if ((v = strchr(*f, ':')) == NULL)
+ if ((v = strchr(*f, ':')) == NULL) {
continue;
+ }
*(v++) = 0;
@@ -228,8 +235,9 @@ static GSList *twitter_filter_parse(struct groupchat *c, const char *text)
}
}
- if (t < 0 || strlen(v) == 0)
+ if (t < 0 || strlen(v) == 0) {
continue;
+ }
tf = twitter_filter_get(c, types[t], v);
ret = g_slist_prepend(ret, tf);
@@ -247,8 +255,9 @@ gboolean twitter_main_loop(gpointer data, gint fd, b_input_condition cond)
struct im_connection *ic = data;
// Check if we are still logged in...
- if (!g_slist_find(twitter_connections, ic))
+ if (!g_slist_find(twitter_connections, ic)) {
return FALSE;
+ }
// Do stuff..
return twitter_get_timeline(ic, -1) &&
@@ -260,24 +269,27 @@ static void twitter_main_loop_start(struct im_connection *ic)
struct twitter_data *td = ic->proto_data;
char *last_tweet = set_getstr(&ic->acc->set, "_last_tweet");
- if (last_tweet)
+
+ if (last_tweet) {
td->timeline_id = g_ascii_strtoull(last_tweet, NULL, 0);
+ }
/* Create the room now that we "logged in". */
- if (td->flags & TWITTER_MODE_CHAT)
+ 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
// 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;
@@ -285,8 +297,8 @@ static void twitter_main_loop_start(struct im_connection *ic)
/* 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);
+ b_timeout_add(set_getint(&ic->acc->set, "fetch_interval") * 1000,
+ twitter_main_loop, ic);
}
}
@@ -297,8 +309,9 @@ struct groupchat *twitter_groupchat_init(struct im_connection *ic)
struct twitter_data *td = ic->proto_data;
GSList *l;
- if (td->timeline_gc)
+ if (td->timeline_gc) {
return td->timeline_gc;
+ }
td->timeline_gc = gc = imcb_chat_new(ic, "twitter/timeline");
@@ -308,11 +321,12 @@ 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)
+ if (bu->ic == ic) {
imcb_chat_add_buddy(gc, bu->handle);
+ }
}
imcb_chat_add_buddy(gc, ic->acc->user);
-
+
return gc;
}
@@ -324,14 +338,15 @@ void twitter_login_finish(struct im_connection *ic)
td->flags &= ~TWITTER_DOING_TIMELINE;
- if (set_getbool(&ic->acc->set, "oauth") && !td->oauth_info)
+ if (set_getbool(&ic->acc->set, "oauth") && !td->oauth_info) {
twitter_oauth_start(ic);
- else if (!(td->flags & TWITTER_MODE_ONE) &&
- !(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
+ } else {
twitter_main_loop_start(ic);
+ }
}
static const struct oauth_service twitter_oauth = {
@@ -356,10 +371,11 @@ static const struct oauth_service *get_oauth_service(struct im_connection *ic)
{
struct twitter_data *td = ic->proto_data;
- if (strstr(td->url_host, "identi.ca"))
+ if (strstr(td->url_host, "identi.ca")) {
return &identica_oauth;
- else
+ } else {
return &twitter_oauth;
+ }
/* Could add more services, or allow configuring your own base URL +
API keys. */
@@ -371,10 +387,11 @@ static void twitter_oauth_start(struct im_connection *ic)
const char *url = set_getstr(&ic->acc->set, "base_url");
imcb_log(ic, "Requesting OAuth request token");
-
- if (!strstr(url, "twitter.com") && !strstr(url, "identi.ca"))
+
+ if (!strstr(url, "twitter.com") && !strstr(url, "identi.ca")) {
imcb_log(ic, "Warning: OAuth only works with identi.ca and "
- "Twitter.");
+ "Twitter.");
+ }
td->oauth_info = oauth_request_token(get_oauth_service(ic), twitter_oauth_callback, ic);
@@ -388,8 +405,9 @@ static gboolean twitter_oauth_callback(struct oauth_info *info)
struct im_connection *ic = info->data;
struct twitter_data *td;
- if (!g_slist_find(twitter_connections, ic))
+ if (!g_slist_find(twitter_connections, ic)) {
return FALSE;
+ }
td = ic->proto_data;
if (info->stage == OAUTH_REQUEST_TOKEN) {
@@ -403,24 +421,25 @@ static gboolean twitter_oauth_callback(struct oauth_info *info)
name = g_strdup_printf("%s_%s", td->prefix, ic->acc->user);
msg = g_strdup_printf("To finish OAuth authentication, please visit "
- "%s and respond with the resulting PIN code.",
- info->auth_url);
+ "%s and respond with the resulting PIN code.",
+ info->auth_url);
imcb_buddy_msg(ic, name, msg, 0, 0);
g_free(name);
g_free(msg);
} else if (info->stage == OAUTH_ACCESS_TOKEN) {
const char *sn;
-
+
if (info->token == NULL || info->token_secret == NULL) {
imcb_error(ic, "OAuth error: %s", twitter_parse_error(info->http));
imc_logout(ic, TRUE);
return FALSE;
}
-
+
if ((sn = oauth_params_get(&info->params, "screen_name"))) {
- if (ic->acc->prpl->handle_cmp(sn, ic->acc->user) != 0)
+ if (ic->acc->prpl->handle_cmp(sn, ic->acc->user) != 0) {
imcb_log(ic, "Warning: You logged in via OAuth as %s "
"instead of %s.", sn, ic->acc->user);
+ }
g_free(td->user);
td->user = g_strdup(sn);
}
@@ -443,16 +462,18 @@ int twitter_url_len_diff(gchar *msg, unsigned int target_len)
static GRegex *regex = NULL;
GMatchInfo *match_info;
- if (regex == NULL)
+ if (regex == NULL) {
regex = g_regex_new("(^|\\s)(http(s)?://[^\\s$]+)", 0, 0, NULL);
-
+ }
+
g_regex_match(regex, msg, 0, &match_info);
while (g_match_info_matches(match_info)) {
gchar *url = g_match_info_fetch(match_info, 2);
url_len_diff += target_len - g_utf8_strlen(url, -1);
/* Add another character for https://t.co/... URLs */
- if (g_match_info_fetch(match_info, 3) != NULL)
+ if (g_match_info_fetch(match_info, 3) != NULL) {
url_len_diff += 1;
+ }
g_free(url);
g_match_info_next(match_info, NULL);
}
@@ -467,11 +488,13 @@ static gboolean twitter_length_check(struct im_connection *ic, gchar * msg)
int target_len = set_getint(&ic->acc->set, "target_url_length");
int url_len_diff = 0;
- if (target_len > 0)
+ if (target_len > 0) {
url_len_diff = twitter_url_len_diff(msg, target_len);
+ }
- if (max == 0 || (len = g_utf8_strlen(msg, -1) + url_len_diff) <= max)
+ if (max == 0 || (len = g_utf8_strlen(msg, -1) + url_len_diff) <= max) {
return TRUE;
+ }
twitter_log(ic, "Maximum message length exceeded: %d > %d", len, max);
@@ -480,19 +503,21 @@ static gboolean twitter_length_check(struct im_connection *ic, gchar * msg)
static char *set_eval_commands(set_t * set, char *value)
{
- if (g_strcasecmp(value, "strict") == 0 )
+ if (g_strcasecmp(value, "strict") == 0) {
return value;
- else
+ } 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)
+ g_strcasecmp(value, "many") == 0 || g_strcasecmp(value, "chat") == 0) {
return value;
- else
+ } else {
return NULL;
+ }
}
static void twitter_init(account_t * acc)
@@ -506,7 +531,7 @@ static void twitter_init(account_t * acc)
def_url = TWITTER_API_URL;
def_tul = "22";
def_mentions = "true";
- } else { /* if( strcmp( acc->prpl->name, "identica" ) == 0 ) */
+ } else { /* if( strcmp( acc->prpl->name, "identica" ) == 0 ) */
def_url = IDENTICA_API_URL;
def_tul = "0";
def_mentions = "false";
@@ -538,7 +563,7 @@ static void twitter_init(account_t * acc)
s = set_add(&acc->set, "show_old_mentions", "0", set_eval_int, acc);
s = set_add(&acc->set, "strip_newlines", "false", set_eval_bool, acc);
-
+
s = set_add(&acc->set, "_last_tweet", "0", NULL, acc);
s->flags |= SET_HIDDEN | SET_NOSAVE;
@@ -559,7 +584,7 @@ static void twitter_login(account_t * acc)
char name[strlen(acc->user) + 9];
url_t url;
char *s;
-
+
if (!url_set(&url, set_getstr(&ic->acc->set, "base_url")) ||
(url.proto != PROTO_HTTP && url.proto != PROTO_HTTPS)) {
imcb_error(ic, "Incorrect API base URL: %s", set_getstr(&ic->acc->set, "base_url"));
@@ -570,7 +595,7 @@ static void twitter_login(account_t * acc)
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.");
+ "and you seem to be connecting to a different service.");
}
imcb_log(ic, "Connecting");
@@ -583,21 +608,23 @@ static void twitter_login(account_t * acc)
td->url_ssl = url.proto == PROTO_HTTPS;
td->url_port = url.port;
td->url_host = g_strdup(url.host);
- if (strcmp(url.file, "/") != 0)
+ if (strcmp(url.file, "/") != 0) {
td->url_path = g_strdup(url.file);
- else {
+ } else {
td->url_path = g_strdup("");
- if (g_str_has_suffix(url.host, "twitter.com"))
+ if (g_str_has_suffix(url.host, "twitter.com")) {
/* May fire for people who turned on HTTPS. */
imcb_error(ic, "Warning: Twitter requires a version number in API calls "
- "now. Try resetting the base_url account setting.");
+ "now. Try resetting the base_url account setting.");
+ }
}
-
+
/* Hacky string mangling: Turn identi.ca into identi.ca and api.twitter.com
into twitter, and try to be sensible if we get anything else. */
td->prefix = g_strdup(url.host);
- if (g_str_has_suffix(td->prefix, ".com"))
+ if (g_str_has_suffix(td->prefix, ".com")) {
td->prefix[strlen(url.host) - 4] = '\0';
+ }
if ((s = strrchr(td->prefix, '.')) && strlen(s) > 4) {
/* If we have at least 3 chars after the last dot, cut off the rest.
(mostly a www/api prefix or sth) */
@@ -605,9 +632,10 @@ static void twitter_login(account_t * acc)
g_free(td->prefix);
td->prefix = s;
}
-
- if (strstr(acc->pass, "oauth_token="))
+
+ if (strstr(acc->pass, "oauth_token=")) {
td->oauth_info = oauth_from_string(acc->pass, get_oauth_service(ic));
+ }
sprintf(name, "%s_%s", td->prefix, acc->user);
imcb_add_buddy(ic, name, NULL);
@@ -615,14 +643,15 @@ 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)
+ if (g_strcasecmp(s, "one") == 0) {
td->flags |= TWITTER_MODE_ONE;
- else if (g_strcasecmp(s, "many") == 0)
+ } else if (g_strcasecmp(s, "many") == 0) {
td->flags |= TWITTER_MODE_MANY;
- else
+ } else {
td->flags |= TWITTER_MODE_CHAT;
+ }
twitter_login_finish(ic);
}
@@ -640,12 +669,14 @@ static void twitter_logout(struct im_connection *ic)
// Remove the main_loop function from the function queue.
b_event_remove(td->main_loop_id);
- if (td->timeline_gc)
+ if (td->timeline_gc) {
imcb_chat_free(td->timeline_gc);
+ }
if (td) {
- if (td->filter_update_id > 0)
+ if (td->filter_update_id > 0) {
b_event_remove(td->filter_update_id);
+ }
http_close(td->stream);
twitter_filter_remove_all(ic);
@@ -678,19 +709,21 @@ static int twitter_buddy_msg(struct im_connection *ic, char *who, char *message,
char pin[strlen(message) + 1], *s;
strcpy(pin, message);
- for (s = pin + sizeof(pin) - 2; s > pin && g_ascii_isspace(*s); s--)
+ for (s = pin + sizeof(pin) - 2; s > pin && g_ascii_isspace(*s); s--) {
*s = '\0';
+ }
for (s = pin; *s && g_ascii_isspace(*s); s++) {
}
if (!oauth_access_token(s, td->oauth_info)) {
imcb_error(ic, "OAuth error: %s",
- "Failed to send access token request");
+ "Failed to send access token request");
imc_logout(ic, TRUE);
return FALSE;
}
- } else
+ } else {
twitter_handle_command(ic, message);
+ }
} else {
twitter_direct_messages_new(ic, who, message);
}
@@ -713,8 +746,9 @@ static void twitter_remove_buddy(struct im_connection *ic, char *who, char *grou
static void twitter_chat_msg(struct groupchat *c, char *message, int flags)
{
- if (c && message)
+ if (c && message) {
twitter_handle_command(c->ic, message);
+ }
}
static void twitter_chat_invite(struct groupchat *c, char *who, char *message)
@@ -736,17 +770,20 @@ static struct groupchat *twitter_chat_join(struct im_connection *ic,
for (l = fs; l; l = g_slist_next(l)) {
tf = l->data;
- if (topic->len > 0)
+ if (topic->len > 0) {
g_string_append(topic, ", ");
+ }
- if (tf->type == TWITTER_FILTER_TYPE_FOLLOW)
+ if (tf->type == TWITTER_FILTER_TYPE_FOLLOW) {
g_string_append_c(topic, '@');
+ }
g_string_append(topic, tf->text);
}
- if (topic->len > 0)
+ if (topic->len > 0) {
g_string_prepend(topic, "Twitter Filter: ");
+ }
imcb_chat_topic(c, NULL, topic->str, 0);
imcb_chat_add_buddy(c, ic->acc->user);
@@ -819,40 +856,48 @@ 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, char *arg, bee_user_t **bu_) {
+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 = NULL;
guint64 id = 0;
-
- if (bu_)
+
+ if (bu_) {
*bu_ = NULL;
- if (!arg || !arg[0])
+ }
+ if (!arg || !arg[0]) {
return 0;
-
+ }
+
if (arg[0] != '#' && (bu = bee_user_by_handle(ic->bee, ic, arg))) {
- if ((tud = bu->data))
+ if ((tud = bu->data)) {
id = tud->last_id;
+ }
} else {
- if (arg[0] == '#')
+ 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))
+ 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)
+ if (id < 1000000) {
id = 0;
+ }
}
}
- if (bu_)
+ if (bu_) {
*bu_ = bu;
+ }
return id;
}
@@ -862,7 +907,7 @@ static void twitter_handle_command(struct im_connection *ic, char *message)
char *cmds, **cmd, *new = NULL;
guint64 in_reply_to = 0, id;
gboolean allow_post =
- g_strcasecmp(set_getstr(&ic->acc->set, "commands"), "strict") != 0;
+ g_strcasecmp(set_getstr(&ic->acc->set, "commands"), "strict") != 0;
bee_user_t *bu = NULL;
cmds = g_strdup(message);
@@ -873,17 +918,18 @@ static void twitter_handle_command(struct im_connection *ic, char *message)
} 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) {
- if (cmd[1] == NULL)
+ if (cmd[1] == NULL) {
twitter_status_destroy(ic, td->last_status_id);
- else if ((id = twitter_message_id_from_command_arg(ic, cmd[1], NULL)))
+ } 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");
+ }
goto eof;
} else if ((g_strcasecmp(cmd[0], "favourite") == 0 ||
- g_strcasecmp(cmd[0], "favorite") == 0 ||
- g_strcasecmp(cmd[0], "fav") == 0) && cmd[1]) {
+ g_strcasecmp(cmd[0], "favorite") == 0 ||
+ g_strcasecmp(cmd[0], "fav") == 0) && cmd[1]) {
if ((id = twitter_message_id_from_command_arg(ic, cmd[1], NULL))) {
twitter_favourite_tweet(ic, id);
} else {
@@ -899,33 +945,35 @@ static void twitter_handle_command(struct im_connection *ic, char *message)
} else if ((g_strcasecmp(cmd[0], "report") == 0 ||
g_strcasecmp(cmd[0], "spam") == 0) && 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 */
twitter_message_id_from_command_arg(ic, cmd[1], &bu);
- if (bu)
+ if (bu) {
screen_name = bu->handle;
- else
+ } else {
screen_name = cmd[1];
-
+ }
+
twitter_report_spam(ic, screen_name);
goto eof;
} else if (g_strcasecmp(cmd[0], "rt") == 0 && cmd[1]) {
id = twitter_message_id_from_command_arg(ic, cmd[1], NULL);
td->last_status_id = 0;
- if (id)
+ if (id) {
twitter_status_retweet(ic, id);
- else
+ } else {
twitter_log(ic, "User `%s' does not exist or didn't "
- "post any statuses recently", cmd[1]);
+ "post any statuses recently", cmd[1]);
+ }
goto eof;
} else if (g_strcasecmp(cmd[0], "reply") == 0 && cmd[1] && cmd[2]) {
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]);
+ "post any statuses recently", cmd[1]);
goto eof;
}
message = new = g_strdup_printf("@%s %s", bu->handle, cmd[2]);
@@ -948,8 +996,9 @@ static void twitter_handle_command(struct im_connection *ic, char *message)
if (allow_post) {
char *s;
- if (!twitter_length_check(ic, message))
+ if (!twitter_length_check(ic, message)) {
goto eof;
+ }
s = cmd[0] + strlen(cmd[0]) - 1;
if (!new && s > cmd[0] && (*s == ':' || *s == ',')) {
@@ -959,12 +1008,13 @@ static void twitter_handle_command(struct im_connection *ic, char *message)
struct twitter_user_data *tud = bu->data;
new = g_strdup_printf("@%s %s", bu->handle,
- message + (s - cmd[0]) + 2);
+ message + (s - cmd[0]) + 2);
message = new;
if (time(NULL) < tud->last_time +
- set_getint(&ic->acc->set, "auto_reply_timeout"))
+ set_getint(&ic->acc->set, "auto_reply_timeout")) {
in_reply_to = tud->last_id;
+ }
}
}
@@ -980,21 +1030,22 @@ eof:
g_free(cmds);
}
-void twitter_log(struct im_connection *ic, char *format, ... )
+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)
+
+ if (td->timeline_gc) {
imcb_chat_log(td->timeline_gc, "%s", text);
- else
+ } else {
imcb_log(ic, "%s", text);
-
+ }
+
g_free(text);
}
diff --git a/protocols/twitter/twitter.h b/protocols/twitter/twitter.h
index 00230cc0..7cfd9148 100644
--- a/protocols/twitter/twitter.h
+++ b/protocols/twitter/twitter.h
@@ -28,13 +28,12 @@
#define _TWITTER_H
#ifdef DEBUG_TWITTER
-#define debug( text... ) imcb_log( ic, text );
+#define debug(text ...) imcb_log(ic, text);
#else
-#define debug( text... )
+#define debug(text ...)
#endif
-typedef enum
-{
+typedef enum {
TWITTER_HAVE_FRIENDS = 0x00001,
TWITTER_MODE_ONE = 0x00002,
TWITTER_MODE_MANY = 0x00004,
@@ -44,16 +43,14 @@ typedef enum
TWITTER_GOT_MENTIONS = 0x40000,
} twitter_flags_t;
-typedef enum
-{
+typedef enum {
TWITTER_FILTER_TYPE_FOLLOW = 0,
TWITTER_FILTER_TYPE_TRACK
} twitter_filter_type_t;
struct twitter_log_data;
-struct twitter_data
-{
+struct twitter_data {
char* user;
struct oauth_info *oauth_info;
@@ -64,7 +61,7 @@ struct twitter_data
GSList *follow_ids;
GSList *filters;
-
+
guint64 last_status_id; /* For undo */
gint main_loop_id;
gint filter_update_id;
@@ -73,7 +70,7 @@ struct twitter_data
struct groupchat *timeline_gc;
gint http_fails;
twitter_flags_t flags;
-
+
/* set base_url */
gboolean url_ssl;
int url_port;
@@ -81,47 +78,44 @@ struct twitter_data
char *url_path;
char *prefix; /* Used to generate contact + channel name. */
-
+
/* set show_ids */
struct twitter_log_data *log;
int log_id;
};
#define TWITTER_FILTER_UPDATE_WAIT 3000
-struct twitter_filter
-{
+struct twitter_filter {
twitter_filter_type_t type;
char *text;
guint64 uid;
GSList *groupchats;
};
-struct twitter_user_data
-{
+struct twitter_user_data {
guint64 last_id;
time_t last_time;
};
#define TWITTER_LOG_LENGTH 256
-struct twitter_log_data
-{
+struct twitter_log_data {
guint64 id;
struct bee_user *bu; /* DANGER: can be a dead pointer. Check it first. */
};
/**
- * This has the same function as the msn_connections GSList. We use this to
+ * This has the same function as the msn_connections GSList. We use this to
* make sure the connection is still alive in callbacks before we do anything
* else.
*/
extern GSList *twitter_connections;
-void twitter_login_finish( struct im_connection *ic );
+void twitter_login_finish(struct im_connection *ic);
struct http_request;
-char *twitter_parse_error( struct http_request *req );
+char *twitter_parse_error(struct http_request *req);
-void twitter_log(struct im_connection *ic, char *format, ... );
+void twitter_log(struct im_connection *ic, char *format, ...);
struct groupchat *twitter_groupchat_init(struct im_connection *ic);
#endif //_TWITTER_H
diff --git a/protocols/twitter/twitter_http.c b/protocols/twitter/twitter_http.c
index f7ab6e18..7a180b5e 100644
--- a/protocols/twitter/twitter_http.c
+++ b/protocols/twitter/twitter_http.c
@@ -47,7 +47,7 @@ static char *twitter_url_append(char *url, char *key, char *value);
* This is actually pretty generic function... Perhaps it should move to the lib/http_client.c
*/
struct http_request *twitter_http(struct im_connection *ic, char *url_string, http_input_function func,
- gpointer data, int is_post, char **arguments, int arguments_len)
+ gpointer data, int is_post, char **arguments, int arguments_len)
{
struct twitter_data *td = ic->proto_data;
char *tmp;
@@ -67,7 +67,7 @@ struct http_request *twitter_http(struct im_connection *ic, char *url_string, ht
url_arguments = tmp;
}
}
-
+
if (strstr(url_string, "://")) {
base_url = g_new0(url_t, 1);
if (!url_set(base_url, url_string)) {
@@ -75,28 +75,29 @@ struct http_request *twitter_http(struct im_connection *ic, char *url_string, ht
return NULL;
}
}
-
+
// Make the request.
g_string_printf(request, "%s %s%s%s%s HTTP/1.1\r\n"
- "Host: %s\r\n"
- "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n",
- is_post ? "POST" : "GET",
- base_url ? base_url->file : td->url_path,
- base_url ? "" : url_string,
- is_post ? "" : "?", is_post ? "" : url_arguments,
- base_url ? base_url->host : td->url_host);
+ "Host: %s\r\n"
+ "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n",
+ is_post ? "POST" : "GET",
+ base_url ? base_url->file : td->url_path,
+ base_url ? "" : url_string,
+ is_post ? "" : "?", is_post ? "" : url_arguments,
+ base_url ? base_url->host : td->url_host);
// If a pass and user are given we append them to the request.
if (td->oauth_info) {
char *full_header;
char *full_url;
- if (base_url)
+ if (base_url) {
full_url = g_strdup(url_string);
- else
+ } else {
full_url = g_strconcat(set_getstr(&ic->acc->set, "base_url"), url_string, NULL);
+ }
full_header = oauth_http_header(td->oauth_info, is_post ? "POST" : "GET",
- full_url, url_arguments);
+ full_url, url_arguments);
g_string_append_printf(request, "Authorization: %s\r\n", full_header);
g_free(full_header);
@@ -115,18 +116,20 @@ struct http_request *twitter_http(struct im_connection *ic, char *url_string, ht
if (is_post) {
// Append the Content-Type and url-encoded arguments.
g_string_append_printf(request,
- "Content-Type: application/x-www-form-urlencoded\r\n"
- "Content-Length: %zd\r\n\r\n%s",
- strlen(url_arguments), url_arguments);
+ "Content-Type: application/x-www-form-urlencoded\r\n"
+ "Content-Length: %zd\r\n\r\n%s",
+ strlen(url_arguments), url_arguments);
} else {
// Append an extra \r\n to end the request...
g_string_append(request, "\r\n");
}
- if (base_url)
- ret = http_dorequest(base_url->host, base_url->port, base_url->proto == PROTO_HTTPS, request->str, func, data);
- else
+ if (base_url) {
+ ret = http_dorequest(base_url->host, base_url->port, base_url->proto == PROTO_HTTPS, request->str, func,
+ data);
+ } else {
ret = http_dorequest(td->url_host, td->url_port, td->url_ssl, request->str, func, data);
+ }
g_free(url_arguments);
g_string_free(request, TRUE);
@@ -135,26 +138,31 @@ struct http_request *twitter_http(struct im_connection *ic, char *url_string, ht
}
struct http_request *twitter_http_f(struct im_connection *ic, char *url_string, http_input_function func,
- gpointer data, int is_post, char **arguments, int arguments_len, twitter_http_flags_t flags)
+ gpointer data, int is_post, char **arguments, int arguments_len,
+ twitter_http_flags_t flags)
{
struct http_request *ret = twitter_http(ic, url_string, func, data, is_post, arguments, arguments_len);
- if (ret)
+
+ if (ret) {
ret->flags |= flags;
+ }
return ret;
}
static char *twitter_url_append(char *url, char *key, char *value)
{
char *key_encoded = g_strndup(key, 3 * strlen(key));
+
http_encode(key_encoded);
char *value_encoded = g_strndup(value, 3 * strlen(value));
http_encode(value_encoded);
char *retval;
- if (strlen(url) != 0)
+ if (strlen(url) != 0) {
retval = g_strdup_printf("%s&%s=%s", url, key_encoded, value_encoded);
- else
+ } else {
retval = g_strdup_printf("%s=%s", key_encoded, value_encoded);
+ }
g_free(key_encoded);
g_free(value_encoded);
diff --git a/protocols/twitter/twitter_http.h b/protocols/twitter/twitter_http.h
index 09ef350c..d46ee4e5 100644
--- a/protocols/twitter/twitter_http.h
+++ b/protocols/twitter/twitter_http.h
@@ -38,7 +38,8 @@ struct oauth_info;
struct http_request *twitter_http(struct im_connection *ic, char *url_string, http_input_function func,
gpointer data, int is_post, char** arguments, int arguments_len);
struct http_request *twitter_http_f(struct im_connection *ic, char *url_string, http_input_function func,
- gpointer data, int is_post, char** arguments, int arguments_len, twitter_http_flags_t flags);
+ gpointer data, int is_post, char** arguments, int arguments_len,
+ twitter_http_flags_t flags);
#endif //_TWITTER_HTTP_H
diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c
index c8956606..05932bef 100644
--- a/protocols/twitter/twitter_lib.c
+++ b/protocols/twitter/twitter_lib.c
@@ -23,7 +23,7 @@
****************************************************************************/
/* For strptime(): */
-#if(__sun)
+#if (__sun)
#else
#define _XOPEN_SOURCE
#endif
@@ -69,8 +69,9 @@ struct twitter_xml_status {
*/
static void txu_free(struct twitter_xml_user *txu)
{
- if (txu == NULL)
+ if (txu == NULL) {
return;
+ }
g_free(txu->name);
g_free(txu->screen_name);
@@ -82,8 +83,9 @@ static void txu_free(struct twitter_xml_user *txu)
*/
static void txs_free(struct twitter_xml_status *txs)
{
- if (txs == NULL)
+ if (txs == NULL) {
return;
+ }
g_free(txs->text);
txu_free(txs->user);
@@ -97,8 +99,10 @@ static void txs_free(struct twitter_xml_status *txs)
static void txl_free(struct twitter_xml_list *txl)
{
GSList *l;
- if (txl == NULL)
+
+ if (txl == NULL) {
return;
+ }
for (l = txl->list; l; l = g_slist_next(l)) {
if (txl->type == TXL_STATUS) {
@@ -147,10 +151,12 @@ static void twitter_add_buddy(struct im_connection *ic, char *name, const char *
/* Necessary so that nicks always get translated to the
exact Twitter username. */
imcb_buddy_nick_hint(ic, name, name);
- if (td->timeline_gc)
+ if (td->timeline_gc) {
imcb_chat_add_buddy(td->timeline_gc, name);
- } else if (td->flags & TWITTER_MODE_MANY)
+ }
+ } else if (td->flags & TWITTER_MODE_MANY) {
imcb_buddy_status(ic, name, OPT_LOGGED_IN, NULL, NULL);
+ }
}
}
@@ -170,8 +176,9 @@ char *twitter_parse_error(struct http_request *req)
if (err && err->type == json_array && (err = err->u.array.values[0]) &&
err->type == json_object) {
const char *msg = json_o_str(err, "message");
- if (msg)
+ if (msg) {
ret = g_strdup_printf("%s (%s)", req->status_string, msg);
+ }
}
json_value_free(root);
}
@@ -188,34 +195,37 @@ static json_value *twitter_parse_response(struct im_connection *ic, struct http_
struct twitter_data *td = ic->proto_data;
json_value *ret;
char path[64] = "", *s;
-
+
if ((s = strchr(req->request, ' '))) {
- path[sizeof(path)-1] = '\0';
+ path[sizeof(path) - 1] = '\0';
strncpy(path, s + 1, sizeof(path) - 1);
- if ((s = strchr(path, '?')) || (s = strchr(path, ' ')))
+ if ((s = strchr(path, '?')) || (s = strchr(path, ' '))) {
*s = '\0';
+ }
}
-
+
/* Kinda nasty. :-( Trying to suppress error messages, but only
for periodic (i.e. mentions/timeline) queries. */
periodic = strstr(path, "timeline") || strstr(path, "mentions");
-
+
if (req->status_code == 401 && logging_in) {
/* IIRC Twitter once had an outage where they were randomly
throwing 401s so I'll keep treating this one as fatal
only during login. */
imcb_error(ic, "Authentication failure (%s)",
- twitter_parse_error(req));
+ twitter_parse_error(req));
imc_logout(ic, FALSE);
return NULL;
} else if (req->status_code != 200) {
// It didn't go well, output the error and return.
- if (!periodic || logging_in || ++td->http_fails >= 5)
+ if (!periodic || logging_in || ++td->http_fails >= 5) {
twitter_log(ic, "Error: Could not retrieve %s: %s",
- path, twitter_parse_error(req));
-
- if (logging_in)
+ path, twitter_parse_error(req));
+ }
+
+ if (logging_in) {
imc_logout(ic, TRUE);
+ }
return NULL;
} else {
td->http_fails = 0;
@@ -223,7 +233,7 @@ static json_value *twitter_parse_response(struct im_connection *ic, struct http_
if ((ret = json_parse(req->reply_body, req->body_size)) == NULL) {
imcb_error(ic, "Could not retrieve %s: %s",
- path, "XML parse error");
+ path, "XML parse error");
}
return ret;
}
@@ -237,6 +247,7 @@ void twitter_get_friends_ids(struct im_connection *ic, gint64 next_cursor)
{
// Primitive, but hey! It works...
char *args[2];
+
args[0] = "cursor";
args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor);
twitter_http(ic, TWITTER_FRIENDS_IDS_URL, twitter_http_get_friends_ids, ic, 0, args, 2);
@@ -256,23 +267,26 @@ static gboolean twitter_xt_get_friends_id_list(json_value *node, struct twitter_
txl->type = TXL_ID;
c = json_o_get(node, "ids");
- if (!c || c->type != json_array)
+ if (!c || c->type != json_array) {
return FALSE;
+ }
- for (i = 0; i < c->u.array.length; i ++) {
- if (c->u.array.values[i]->type != json_integer)
+ for (i = 0; i < c->u.array.length; i++) {
+ if (c->u.array.values[i]->type != json_integer) {
continue;
-
+ }
+
txl->list = g_slist_prepend(txl->list,
- g_strdup_printf("%" PRIu64, c->u.array.values[i]->u.integer));
+ g_strdup_printf("%" PRIu64, c->u.array.values[i]->u.integer));
}
-
+
c = json_o_get(node, "next_cursor");
- if (c && c->type == json_integer)
+ if (c && c->type == json_integer) {
txl->next_cursor = c->u.integer;
- else
+ } else {
txl->next_cursor = -1;
-
+ }
+
return TRUE;
}
@@ -291,8 +305,9 @@ static void twitter_http_get_friends_ids(struct http_request *req)
ic = req->data;
// Check if the connection is still active.
- if (!g_slist_find(twitter_connections, ic))
+ if (!g_slist_find(twitter_connections, ic)) {
return;
+ }
td = ic->proto_data;
@@ -300,20 +315,22 @@ static void twitter_http_get_friends_ids(struct http_request *req)
txl->list = td->follow_ids;
// Parse the data.
- if (!(parsed = twitter_parse_response(ic, req)))
+ if (!(parsed = twitter_parse_response(ic, req))) {
return;
-
+ }
+
twitter_xt_get_friends_id_list(parsed, txl);
json_value_free(parsed);
td->follow_ids = txl->list;
- if (txl->next_cursor)
+ if (txl->next_cursor) {
/* These were just numbers. Up to 4000 in a response AFAIK so if we get here
we may be using a spammer account. \o/ */
twitter_get_friends_ids(ic, txl->next_cursor);
- else
+ } else {
/* Now to convert all those numbers into names.. */
twitter_get_users_lookup(ic);
+ }
txl->list = NULL;
txl_free(txl);
@@ -331,10 +348,10 @@ static void twitter_get_users_lookup(struct im_connection *ic)
};
GString *ids = g_string_new("");
int i;
-
+
/* We can request up to 100 users at a time. */
- for (i = 0; i < 100 && td->follow_ids; i ++) {
- g_string_append_printf(ids, ",%s", (char*) td->follow_ids->data);
+ for (i = 0; i < 100 && td->follow_ids; i++) {
+ g_string_append_printf(ids, ",%s", (char *) td->follow_ids->data);
g_free(td->follow_ids->data);
td->follow_ids = g_slist_remove(td->follow_ids, td->follow_ids->data);
}
@@ -353,8 +370,8 @@ static void twitter_get_users_lookup(struct im_connection *ic)
/**
* Callback for getting (twitter)friends...
*
- * Be afraid, be very afraid! This function will potentially add hundreds of "friends". "Who has
- * hundreds of friends?" you wonder? You probably not, since you are reading the source of
+ * Be afraid, be very afraid! This function will potentially add hundreds of "friends". "Who has
+ * hundreds of friends?" you wonder? You probably not, since you are reading the source of
* BitlBee... Get a life and meet new people!
*/
static void twitter_http_get_users_lookup(struct http_request *req)
@@ -366,15 +383,17 @@ static void twitter_http_get_users_lookup(struct http_request *req)
struct twitter_xml_user *user;
// Check if the connection is still active.
- if (!g_slist_find(twitter_connections, ic))
+ if (!g_slist_find(twitter_connections, ic)) {
return;
+ }
txl = g_new0(struct twitter_xml_list, 1);
txl->list = NULL;
// Get the user list from the parsed xml feed.
- if (!(parsed = twitter_parse_response(ic, req)))
+ if (!(parsed = twitter_parse_response(ic, req))) {
return;
+ }
twitter_xt_get_users(parsed, txl);
json_value_free(parsed);
@@ -394,14 +413,14 @@ struct twitter_xml_user *twitter_xt_get_user(const json_value *node)
{
struct twitter_xml_user *txu;
json_value *jv;
-
+
txu = g_new0(struct twitter_xml_user, 1);
txu->name = g_strdup(json_o_str(node, "name"));
txu->screen_name = g_strdup(json_o_str(node, "screen_name"));
-
+
jv = json_o_get(node, "id");
txu->uid = jv->u.integer;
-
+
return txu;
}
@@ -418,15 +437,17 @@ static gboolean twitter_xt_get_users(json_value *node, struct twitter_xml_list *
// Set the type of the list.
txl->type = TXL_USER;
- if (!node || node->type != json_array)
+ if (!node || node->type != json_array) {
return FALSE;
+ }
// The root <users> node should hold the list of users <user>
// Walk over the nodes children.
- for (i = 0; i < node->u.array.length; i ++) {
+ for (i = 0; i < node->u.array.length; i++) {
txu = twitter_xt_get_user(node->u.array.values[i]);
- if (txu)
+ if (txu) {
txl->list = g_slist_prepend(txl->list, txu);
+ }
}
return TRUE;
@@ -452,12 +473,13 @@ 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)
+
+ if (node->type != json_object) {
return FALSE;
+ }
txs = g_new0(struct twitter_xml_status, 1);
- JSON_O_FOREACH (node, k, v) {
+ JSON_O_FOREACH(node, k, v) {
if (strcmp("text", k) == 0 && v->type == json_string) {
txs->text = g_memdup(v->u.string.ptr, v->u.string.length + 1);
strip_html(txs->text);
@@ -469,8 +491,9 @@ static struct twitter_xml_status *twitter_xt_get_status(const json_value *node)
/* Very sensitive to changes to the formatting of
this field. :-( Also assumes the timezone used
is UTC since C time handling functions suck. */
- if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL)
+ if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) {
txs->created_at = mktime_utc(&parsed);
+ }
} else if (strcmp("user", k) == 0 && v->type == json_object) {
txs->user = twitter_xt_get_user(v);
} else if (strcmp("id", k) == 0 && v->type == json_integer) {
@@ -496,9 +519,10 @@ static struct twitter_xml_status *twitter_xt_get_status(const json_value *node)
txs->text = expand_entities(txs->text, entities);
}
- if (txs->text && txs->user && txs->id)
+ if (txs->text && txs->user && txs->id) {
return txs;
-
+ }
+
txs_free(txs);
return NULL;
}
@@ -510,12 +534,13 @@ static struct twitter_xml_status *twitter_xt_get_dm(const json_value *node)
{
struct twitter_xml_status *txs;
const json_value *entities = NULL;
-
- if (node->type != json_object)
+
+ if (node->type != json_object) {
return FALSE;
+ }
txs = g_new0(struct twitter_xml_status, 1);
- JSON_O_FOREACH (node, k, v) {
+ JSON_O_FOREACH(node, k, v) {
if (strcmp("text", k) == 0 && v->type == json_string) {
txs->text = g_memdup(v->u.string.ptr, v->u.string.length + 1);
strip_html(txs->text);
@@ -525,8 +550,9 @@ static struct twitter_xml_status *twitter_xt_get_dm(const json_value *node)
/* Very sensitive to changes to the formatting of
this field. :-( Also assumes the timezone used
is UTC since C time handling functions suck. */
- if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL)
+ if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) {
txs->created_at = mktime_utc(&parsed);
+ }
} else if (strcmp("sender", k) == 0 && v->type == json_object) {
txs->user = twitter_xt_get_user(v);
} else if (strcmp("id", k) == 0 && v->type == json_integer) {
@@ -538,42 +564,48 @@ static struct twitter_xml_status *twitter_xt_get_dm(const json_value *node)
txs->text = expand_entities(txs->text, entities);
}
- if (txs->text && txs->user && txs->id)
+ if (txs->text && txs->user && txs->id) {
return txs;
-
+ }
+
txs_free(txs);
return NULL;
}
-static char* expand_entities(char* text, const json_value *entities) {
- JSON_O_FOREACH (entities, k, v) {
+static char* expand_entities(char* text, const json_value *entities)
+{
+ JSON_O_FOREACH(entities, k, v) {
int i;
-
- if (v->type != json_array)
+
+ if (v->type != json_array) {
continue;
- if (strcmp(k, "urls") != 0 && strcmp(k, "media") != 0)
+ }
+ if (strcmp(k, "urls") != 0 && strcmp(k, "media") != 0) {
continue;
-
- for (i = 0; i < v->u.array.length; i ++) {
- if (v->u.array.values[i]->type != json_object)
+ }
+
+ for (i = 0; i < v->u.array.length; i++) {
+ if (v->u.array.values[i]->type != json_object) {
continue;
-
+ }
+
const char *kort = json_o_str(v->u.array.values[i], "url");
const char *disp = json_o_str(v->u.array.values[i], "display_url");
char *pos, *new;
-
- if (!kort || !disp || !(pos = strstr(text, kort)))
+
+ if (!kort || !disp || !(pos = strstr(text, kort))) {
continue;
-
+ }
+
*pos = '\0';
new = g_strdup_printf("%s%s <%s>%s", text, kort,
disp, pos + strlen(kort));
-
+
g_free(text);
text = new;
}
}
-
+
return text;
}
@@ -591,17 +623,19 @@ static gboolean twitter_xt_get_status_list(struct im_connection *ic, const json_
// Set the type of the list.
txl->type = TXL_STATUS;
-
- if (node->type != json_array)
+
+ if (node->type != json_array) {
return FALSE;
+ }
// 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 ++) {
+ for (i = 0; i < node->u.array.length; i++) {
txs = twitter_xt_get_status(node->u.array.values[i]);
- if (!txs)
+ if (!txs) {
continue;
-
+ }
+
txl->list = g_slist_prepend(txl->list, txs);
}
@@ -611,7 +645,7 @@ static gboolean twitter_xt_get_status_list(struct im_connection *ic, const json_
/* 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_xml_status *txs, const char *prefix)
{
struct twitter_data *td = ic->proto_data;
int reply_to = -1;
@@ -619,11 +653,12 @@ static char *twitter_msg_add_id(struct im_connection *ic,
if (txs->reply_to) {
int i;
- for (i = 0; i < TWITTER_LOG_LENGTH; i++)
+ for (i = 0; i < TWITTER_LOG_LENGTH; i++) {
if (td->log[i].id == txs->reply_to) {
reply_to = i;
break;
}
+ }
}
if (txs->user && txs->user->screen_name &&
@@ -635,29 +670,32 @@ static char *twitter_msg_add_id(struct im_connection *ic,
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);
-
+
/* This is all getting hairy. :-( If we RT'ed something ourselves,
remember OUR id instead so undo will work. In other cases, the
original tweet's id should be remembered for deduplicating. */
- if (g_strcasecmp(txs->user->screen_name, td->user) == 0)
+ if (g_strcasecmp(txs->user->screen_name, td->user) == 0) {
td->log[td->log_id].id = txs->rt_id;
-
+ }
+
if (set_getbool(&ic->acc->set, "show_ids")) {
- if (reply_to != -1)
+ if (reply_to != -1) {
return g_strdup_printf("\002[\002%02x->%02x\002]\002 %s%s",
td->log_id, reply_to, prefix, txs->text);
- else
+ } else {
return g_strdup_printf("\002[\002%02x\002]\002 %s%s",
td->log_id, prefix, txs->text);
+ }
} else {
- if (*prefix)
+ if (*prefix) {
return g_strconcat(prefix, txs->text, NULL);
- else
+ } else {
return NULL;
+ }
}
}
@@ -677,13 +715,15 @@ static void twitter_status_show_filter(struct im_connection *ic, struct twitter_
switch (tf->type) {
case TWITTER_FILTER_TYPE_FOLLOW:
- if (status->user->uid != tf->uid)
+ if (status->user->uid != tf->uid) {
continue;
+ }
break;
case TWITTER_FILTER_TYPE_TRACK:
- if (strcasestr(status->text, tf->text) == NULL)
+ if (strcasestr(status->text, tf->text) == NULL) {
continue;
+ }
break;
default:
@@ -692,7 +732,7 @@ static void twitter_status_show_filter(struct im_connection *ic, struct twitter_
for (l = tf->groupchats; l; l = g_slist_next(l)) {
imcb_chat_msg(l->data, status->user->screen_name,
- msg ? msg : status->text, 0, 0);
+ msg ? msg : status->text, 0, 0);
}
}
@@ -712,17 +752,18 @@ static void twitter_status_show_chat(struct im_connection *ic, struct twitter_xm
// Create a new groupchat if it does not exsist.
gc = twitter_groupchat_init(ic);
- if (!me)
+ if (!me) {
/* MUST be done before twitter_msg_add_id() to avoid #872. */
twitter_add_buddy(ic, status->user->screen_name, status->user->name);
+ }
msg = twitter_msg_add_id(ic, status, "");
-
+
// Say it!
if (me) {
imcb_chat_log(gc, "You: %s", msg ? msg : status->text);
} else {
imcb_chat_msg(gc, status->user->screen_name,
- msg ? msg : status->text, 0, status->created_at);
+ msg ? msg : status->text, 0, status->created_at);
}
g_free(msg);
@@ -743,13 +784,14 @@ static void twitter_status_show_msg(struct im_connection *ic, struct twitter_xml
from[MAX_STRING - 1] = '\0';
}
- if (td->flags & TWITTER_MODE_ONE)
+ if (td->flags & TWITTER_MODE_ONE) {
prefix = g_strdup_printf("\002<\002%s\002>\002 ",
status->user->screen_name);
- else if (!me)
+ } else if (!me) {
twitter_add_buddy(ic, status->user->screen_name, status->user->name);
- else
+ } else {
prefix = g_strdup("You: ");
+ }
text = twitter_msg_add_id(ic, status, prefix ? prefix : "");
@@ -765,21 +807,24 @@ static void twitter_status_show(struct im_connection *ic, struct twitter_xml_sta
{
struct twitter_data *td = ic->proto_data;
char *last_id_str;
-
- if (status->user == NULL || status->text == NULL)
+
+ if (status->user == NULL || status->text == NULL) {
return;
-
+ }
+
/* Grrrr. Would like to do this during parsing, but can't access
settings from there. */
- if (set_getbool(&ic->acc->set, "strip_newlines"))
+ if (set_getbool(&ic->acc->set, "strip_newlines")) {
strip_newlines(status->text);
-
- if (status->from_filter)
+ }
+
+ if (status->from_filter) {
twitter_status_show_filter(ic, status);
- else if (td->flags & TWITTER_MODE_CHAT)
+ } else if (td->flags & TWITTER_MODE_CHAT) {
twitter_status_show_chat(ic, status);
- else
+ } else {
twitter_status_show_msg(ic, status);
+ }
// Update the timeline_id to hold the highest id, so that by the next request
// we won't pick up the updates already in the list.
@@ -800,34 +845,37 @@ static void twitter_http_stream(struct http_request *req)
int len = 0;
char c, *nl;
gboolean from_filter;
-
- if (!g_slist_find(twitter_connections, ic))
+
+ if (!g_slist_find(twitter_connections, ic)) {
return;
-
+ }
+
ic->flags |= OPT_PONGED;
td = ic->proto_data;
-
+
if ((req->flags & HTTPC_EOF) || !req->reply_body) {
- if (req == td->stream)
+ if (req == td->stream) {
td->stream = NULL;
- else if (req == td->filter_stream)
+ } else if (req == td->filter_stream) {
td->filter_stream = NULL;
+ }
imcb_error(ic, "Stream closed (%s)", req->status_string);
imc_logout(ic, TRUE);
return;
}
-
+
/* MUST search for CRLF, not just LF:
https://dev.twitter.com/docs/streaming-apis/processing#Parsing_responses */
- if (!(nl = strstr(req->reply_body, "\r\n")))
+ if (!(nl = strstr(req->reply_body, "\r\n"))) {
return;
-
+ }
+
len = nl - req->reply_body;
if (len > 0) {
c = req->reply_body[len];
req->reply_body[len] = '\0';
-
+
if ((parsed = json_parse(req->reply_body, req->body_size))) {
from_filter = (req == td->filter_stream);
twitter_stream_handle_object(ic, parsed, from_filter);
@@ -835,12 +883,13 @@ static void twitter_http_stream(struct http_request *req)
json_value_free(parsed);
req->reply_body[len] = c;
}
-
+
http_flush_bytes(req, len + 2);
-
+
/* One notification might bring multiple events! */
- if (req->body_size > 0)
+ if (req->body_size > 0) {
twitter_http_stream(req);
+ }
}
static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value *o);
@@ -851,7 +900,7 @@ static gboolean twitter_stream_handle_object(struct im_connection *ic, json_valu
struct twitter_data *td = ic->proto_data;
struct twitter_xml_status *txs;
json_value *c;
-
+
if ((txs = twitter_xt_get_status(o))) {
txs->from_filter = from_filter;
gboolean ret = twitter_stream_handle_status(ic, txs);
@@ -859,9 +908,10 @@ static gboolean twitter_stream_handle_object(struct im_connection *ic, json_valu
return ret;
} else if ((c = json_o_get(o, "direct_message")) &&
(txs = twitter_xt_get_dm(c))) {
- if (g_strcasecmp(txs->user->screen_name, td->user) != 0)
+ if (g_strcasecmp(txs->user->screen_name, td->user) != 0) {
imcb_buddy_msg(ic, txs->user->screen_name,
- txs->text, 0, txs->created_at);
+ txs->text, 0, txs->created_at);
+ }
txs_free(txs);
return TRUE;
} else if ((c = json_o_get(o, "event")) && c->type == json_string) {
@@ -885,14 +935,14 @@ static gboolean twitter_stream_handle_status(struct im_connection *ic, struct tw
{
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, probably). Drop it. */
return TRUE;
}
}
-
+
if (!(g_strcasecmp(txs->user->screen_name, td->user) == 0 ||
set_getbool(&ic->acc->set, "fetch_mentions") ||
bee_user_by_handle(ic->bee, ic, txs->user->screen_name))) {
@@ -904,9 +954,9 @@ static gboolean twitter_stream_handle_status(struct im_connection *ic, struct tw
@Wilmer. But meh. You want spam, you get spam. */
return TRUE;
}
-
+
twitter_status_show(ic, txs);
-
+
return TRUE;
}
@@ -916,12 +966,12 @@ static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value
json_value *source = json_o_get(o, "source");
json_value *target = json_o_get(o, "target");
const char *type = json_o_str(o, "event");
-
+
if (!type || !source || source->type != json_object
- || !target || target->type != json_object) {
+ || !target || target->type != json_object) {
return FALSE;
}
-
+
if (strcmp(type, "follow") == 0) {
struct twitter_xml_user *us = twitter_xt_get_user(source);
struct twitter_xml_user *ut = twitter_xt_get_user(target);
@@ -931,15 +981,15 @@ static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value
txu_free(us);
txu_free(ut);
}
-
+
return TRUE;
}
gboolean twitter_open_stream(struct im_connection *ic)
{
struct twitter_data *td = ic->proto_data;
- char *args[2] = {"with", "followings"};
-
+ char *args[2] = { "with", "followings" };
+
if ((td->stream = twitter_http(ic, TWITTER_USER_STREAM_URL,
twitter_http_stream, ic, 0, args, 2))) {
/* This flag must be enabled or we'll get no data until EOF
@@ -947,14 +997,14 @@ gboolean twitter_open_stream(struct im_connection *ic)
td->stream->flags |= HTTPC_STREAMING;
return TRUE;
}
-
+
return FALSE;
}
static gboolean twitter_filter_stream(struct im_connection *ic)
{
struct twitter_data *td = ic->proto_data;
- char *args[4] = {"follow", NULL, "track", NULL};
+ char *args[4] = { "follow", NULL, "track", NULL };
GString *followstr = g_string_new("");
GString *trackstr = g_string_new("");
gboolean ret = FALSE;
@@ -966,16 +1016,18 @@ static gboolean twitter_filter_stream(struct im_connection *ic)
switch (tf->type) {
case TWITTER_FILTER_TYPE_FOLLOW:
- if (followstr->len > 0)
+ if (followstr->len > 0) {
g_string_append_c(followstr, ',');
+ }
g_string_append_printf(followstr, "%" G_GUINT64_FORMAT,
- tf->uid);
+ tf->uid);
break;
case TWITTER_FILTER_TYPE_TRACK:
- if (trackstr->len > 0)
+ if (trackstr->len > 0) {
g_string_append_c(trackstr, ',');
+ }
g_string_append(trackstr, tf->text);
break;
@@ -988,12 +1040,13 @@ static gboolean twitter_filter_stream(struct im_connection *ic)
args[1] = followstr->str;
args[3] = trackstr->str;
- if (td->filter_stream)
+ if (td->filter_stream) {
http_close(td->filter_stream);
+ }
if ((td->filter_stream = twitter_http(ic, TWITTER_FILTER_STREAM_URL,
twitter_http_stream, ic, 0,
- args, 4))) {
+ args, 4))) {
/* This flag must be enabled or we'll get no data until EOF
(which err, kind of, defeats the purpose of a streaming API). */
td->filter_stream->flags |= HTTPC_STREAMING;
@@ -1021,30 +1074,35 @@ static void twitter_filter_users_post(struct http_request *req)
int i;
// Check if the connection is still active.
- if (!g_slist_find(twitter_connections, ic))
+ if (!g_slist_find(twitter_connections, ic)) {
return;
+ }
td = ic->proto_data;
- if (!(parsed = twitter_parse_response(ic, req)))
+ if (!(parsed = twitter_parse_response(ic, req))) {
return;
+ }
for (l = td->filters; l; l = g_slist_next(l)) {
tf = l->data;
- if (tf->type == TWITTER_FILTER_TYPE_FOLLOW)
+ if (tf->type == TWITTER_FILTER_TYPE_FOLLOW) {
users = g_list_prepend(users, tf);
+ }
}
- if (parsed->type != json_array)
+ if (parsed->type != json_array) {
goto finish;
+ }
for (i = 0; i < parsed->u.array.length; i++) {
id = json_o_get(parsed->u.array.values[i], "id");
name = json_o_str(parsed->u.array.values[i], "screen_name");
- if (!name || !id || id->type != json_integer)
+ if (!name || !id || id->type != json_integer) {
continue;
+ }
for (u = users; u; u = g_list_next(u)) {
tf = u->data;
@@ -1061,14 +1119,16 @@ finish:
json_value_free(parsed);
twitter_filter_stream(ic);
- if (!users)
+ if (!users) {
return;
+ }
fstr = g_string_new("");
for (u = users; u; u = g_list_next(u)) {
- if (fstr->len > 0)
+ if (fstr->len > 0) {
g_string_append(fstr, ", ");
+ }
g_string_append(fstr, tf->text);
}
@@ -1082,7 +1142,7 @@ finish:
gboolean twitter_open_filter_stream(struct im_connection *ic)
{
struct twitter_data *td = ic->proto_data;
- char *args[2] = {"screen_name", NULL};
+ char *args[2] = { "screen_name", NULL };
GString *ustr = g_string_new("");
struct twitter_filter *tf;
struct http_request *req;
@@ -1091,11 +1151,13 @@ gboolean twitter_open_filter_stream(struct im_connection *ic)
for (l = td->filters; l; l = g_slist_next(l)) {
tf = l->data;
- if (tf->type != TWITTER_FILTER_TYPE_FOLLOW || tf->uid != 0)
+ if (tf->type != TWITTER_FILTER_TYPE_FOLLOW || tf->uid != 0) {
continue;
+ }
- if (ustr->len > 0)
+ if (ustr->len > 0) {
g_string_append_c(ustr, ',');
+ }
g_string_append(ustr, tf->text);
}
@@ -1107,8 +1169,8 @@ gboolean twitter_open_filter_stream(struct im_connection *ic)
args[1] = ustr->str;
req = twitter_http(ic, TWITTER_USERS_LOOKUP_URL,
- twitter_filter_users_post,
- ic, 0, args, 2);
+ twitter_filter_users_post,
+ ic, 0, args, 2);
g_string_free(ustr, TRUE);
return req != NULL;
@@ -1140,7 +1202,7 @@ gboolean twitter_get_timeline(struct im_connection *ic, gint64 next_cursor)
if (include_mentions) {
twitter_get_mentions(ic, next_cursor);
}
-
+
return TRUE;
}
@@ -1160,7 +1222,7 @@ void twitter_flush_timeline(struct im_connection *ic)
GSList *l;
imcb_connected(ic);
-
+
if (!(td->flags & TWITTER_GOT_TIMELINE)) {
return;
}
@@ -1188,8 +1250,9 @@ void twitter_flush_timeline(struct im_connection *ic)
// See if the user wants to see the messages in a groupchat window or as private messages.
while (output) {
struct twitter_xml_status *txs = output->data;
- if (txs->id != last_id)
+ if (txs->id != last_id) {
twitter_status_show(ic, txs);
+ }
last_id = txs->id;
output = g_slist_remove(output, txs);
}
@@ -1226,10 +1289,11 @@ static void twitter_get_home_timeline(struct im_connection *ic, gint64 next_curs
}
if (twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args,
- td->timeline_id ? 6 : 4) == NULL) {
- if (++td->http_fails >= 5)
+ td->timeline_id ? 6 : 4) == NULL) {
+ if (++td->http_fails >= 5) {
imcb_error(ic, "Could not retrieve %s: %s",
TWITTER_HOME_TIMELINE_URL, "connection failed");
+ }
td->flags |= TWITTER_GOT_TIMELINE;
twitter_flush_timeline(ic);
}
@@ -1266,9 +1330,10 @@ static void twitter_get_mentions(struct im_connection *ic, gint64 next_cursor)
if (twitter_http(ic, TWITTER_MENTIONS_URL, twitter_http_get_mentions,
ic, 0, args, 6) == NULL) {
- if (++td->http_fails >= 5)
+ if (++td->http_fails >= 5) {
imcb_error(ic, "Could not retrieve %s: %s",
TWITTER_MENTIONS_URL, "connection failed");
+ }
td->flags |= TWITTER_GOT_MENTIONS;
twitter_flush_timeline(ic);
}
@@ -1288,8 +1353,9 @@ static void twitter_http_get_home_timeline(struct http_request *req)
struct twitter_xml_list *txl;
// Check if the connection is still active.
- if (!g_slist_find(twitter_connections, ic))
+ if (!g_slist_find(twitter_connections, ic)) {
return;
+ }
td = ic->proto_data;
@@ -1297,16 +1363,18 @@ static void twitter_http_get_home_timeline(struct http_request *req)
txl->list = NULL;
// The root <statuses> node should hold the list of statuses <status>
- if (!(parsed = twitter_parse_response(ic, req)))
+ if (!(parsed = twitter_parse_response(ic, req))) {
goto end;
+ }
twitter_xt_get_status_list(ic, parsed, txl);
json_value_free(parsed);
td->home_timeline_obj = txl;
- end:
- if (!g_slist_find(twitter_connections, ic))
+end:
+ if (!g_slist_find(twitter_connections, ic)) {
return;
+ }
td->flags |= TWITTER_GOT_TIMELINE;
@@ -1324,8 +1392,9 @@ static void twitter_http_get_mentions(struct http_request *req)
struct twitter_xml_list *txl;
// Check if the connection is still active.
- if (!g_slist_find(twitter_connections, ic))
+ if (!g_slist_find(twitter_connections, ic)) {
return;
+ }
td = ic->proto_data;
@@ -1333,16 +1402,18 @@ static void twitter_http_get_mentions(struct http_request *req)
txl->list = NULL;
// The root <statuses> node should hold the list of statuses <status>
- if (!(parsed = twitter_parse_response(ic, req)))
+ if (!(parsed = twitter_parse_response(ic, req))) {
goto end;
+ }
twitter_xt_get_status_list(ic, parsed, txl);
json_value_free(parsed);
td->mentions_obj = txl;
- end:
- if (!g_slist_find(twitter_connections, ic))
+end:
+ if (!g_slist_find(twitter_connections, ic)) {
return;
+ }
td->flags |= TWITTER_GOT_MENTIONS;
@@ -1360,23 +1431,26 @@ static void twitter_http_post(struct http_request *req)
json_value *parsed, *id;
// Check if the connection is still active.
- if (!g_slist_find(twitter_connections, ic))
+ if (!g_slist_find(twitter_connections, ic)) {
return;
+ }
td = ic->proto_data;
td->last_status_id = 0;
- if (!(parsed = twitter_parse_response(ic, req)))
+ if (!(parsed = twitter_parse_response(ic, req))) {
return;
-
+ }
+
if ((id = json_o_get(parsed, "id")) && id->type == json_integer) {
td->last_status_id = id->u.integer;
}
-
+
json_value_free(parsed);
-
- if (req->flags & TWITTER_HTTP_USER_ACK)
+
+ if (req->flags & TWITTER_HTTP_USER_ACK) {
twitter_log(ic, "Command processed successfully");
+ }
}
/**
@@ -1389,8 +1463,9 @@ void twitter_post_status(struct im_connection *ic, char *msg, guint64 in_reply_t
"in_reply_to_status_id",
g_strdup_printf("%" G_GUINT64_FORMAT, in_reply_to)
};
+
twitter_http(ic, TWITTER_STATUS_UPDATE_URL, twitter_http_post, ic, 1,
- args, in_reply_to ? 4 : 2);
+ args, in_reply_to ? 4 : 2);
g_free(args[3]);
}
@@ -1401,6 +1476,7 @@ void twitter_post_status(struct im_connection *ic, char *msg, guint64 in_reply_t
void twitter_direct_messages_new(struct im_connection *ic, char *who, char *msg)
{
char *args[4];
+
args[0] = "screen_name";
args[1] = who;
args[2] = "text";
@@ -1412,15 +1488,17 @@ void twitter_direct_messages_new(struct im_connection *ic, char *who, char *msg)
void twitter_friendships_create_destroy(struct im_connection *ic, char *who, int create)
{
char *args[2];
+
args[0] = "screen_name";
args[1] = who;
twitter_http(ic, create ? TWITTER_FRIENDSHIPS_CREATE_URL : TWITTER_FRIENDSHIPS_DESTROY_URL,
- twitter_http_post, ic, 1, args, 2);
+ twitter_http_post, ic, 1, args, 2);
}
void twitter_status_destroy(struct im_connection *ic, guint64 id)
{
char *url;
+
url = g_strdup_printf("%s%" G_GUINT64_FORMAT "%s",
TWITTER_STATUS_DESTROY_URL, id, ".json");
twitter_http_f(ic, url, twitter_http_post, ic, 1, NULL, 0,
@@ -1431,6 +1509,7 @@ void twitter_status_destroy(struct im_connection *ic, guint64 id)
void twitter_status_retweet(struct im_connection *ic, guint64 id)
{
char *url;
+
url = g_strdup_printf("%s%" G_GUINT64_FORMAT "%s",
TWITTER_STATUS_RETWEET_URL, id, ".json");
twitter_http_f(ic, url, twitter_http_post, ic, 1, NULL, 0,
@@ -1447,6 +1526,7 @@ void twitter_report_spam(struct im_connection *ic, char *screen_name)
"screen_name",
NULL,
};
+
args[1] = screen_name;
twitter_http_f(ic, TWITTER_REPORT_SPAM_URL, twitter_http_post,
ic, 1, args, 2, TWITTER_HTTP_USER_ACK);
@@ -1461,6 +1541,7 @@ void twitter_favourite_tweet(struct im_connection *ic, guint64 id)
"id",
NULL,
};
+
args[1] = g_strdup_printf("%" G_GUINT64_FORMAT, id);
twitter_http_f(ic, TWITTER_FAVORITE_CREATE_URL, twitter_http_post,
ic, 1, args, 2, TWITTER_HTTP_USER_ACK);