diff options
Diffstat (limited to 'protocols/twitter')
-rw-r--r-- | protocols/twitter/twitter.c | 57 | ||||
-rw-r--r-- | protocols/twitter/twitter.h | 10 | ||||
-rw-r--r-- | protocols/twitter/twitter_lib.c | 131 | ||||
-rw-r--r-- | protocols/twitter/twitter_lib.h | 1 |
4 files changed, 180 insertions, 19 deletions
diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index b2039171..9017d3b3 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -304,7 +304,7 @@ static void twitter_main_loop_start(struct im_connection *ic) struct groupchat *twitter_groupchat_init(struct im_connection *ic) { - char *name_hint; + char *name_hint, *tmp; struct groupchat *gc; struct twitter_data *td = ic->proto_data; GSList *l; @@ -315,7 +315,14 @@ struct groupchat *twitter_groupchat_init(struct im_connection *ic) td->timeline_gc = gc = imcb_chat_new(ic, "twitter/timeline"); - name_hint = g_strdup_printf("%s_%s", td->prefix, ic->acc->user); + tmp = set_getstr(&ic->acc->set, "channel_name"); + + if (tmp == NULL || strlen(tmp) == 0) { + name_hint = g_strdup_printf("%s_%s", td->prefix, ic->acc->user); + } else { + name_hint = g_strdup(tmp); + } + imcb_chat_name_hint(gc, name_hint); g_free(name_hint); @@ -518,6 +525,23 @@ static char *set_eval_commands(set_t * set, char *value) } } +static char *set_eval_channel_name(set_t * set, char *value) +{ + size_t len; + + if (value == NULL) { + return NULL; + } + + len = strlen(value); + + if (len < MAX_NICK_LENGTH && len > 0) { + return value; + } else { + return NULL; + } +} + static char *set_eval_mode(set_t * set, char *value) { if (g_strcasecmp(value, "one") == 0 || @@ -572,6 +596,12 @@ static void twitter_init(account_t * acc) s = set_add(&acc->set, "strip_newlines", "false", set_eval_bool, acc); + s = set_add(&acc->set, "long_ids", "false", set_eval_bool, acc); + s->flags |= ACC_SET_OFFLINE_ONLY; + + s = set_add(&acc->set, "channel_name", NULL, set_eval_channel_name, acc); + s->flags |= ACC_SET_OFFLINE_ONLY; + s = set_add(&acc->set, "_last_tweet", "0", NULL, acc); s->flags |= SET_HIDDEN | SET_NOSAVE; @@ -649,8 +679,13 @@ static void twitter_login(account_t * acc) imcb_add_buddy(ic, name, NULL); imcb_buddy_status(ic, name, OPT_LOGGED_IN, NULL, NULL); - td->log = g_new0(struct twitter_log_data, TWITTER_LOG_LENGTH); + td->long_ids = set_getbool(&ic->acc->set, "long_ids"); + td->log_length = (td->long_ids) ? TWITTER_LONG_LOG_LENGTH : TWITTER_SHORT_LOG_LENGTH; + + td->log = g_new0(struct twitter_log_data, td->log_length); + td->filter_log = g_new0(struct twitter_log_data, td->log_length); td->log_id = -1; + td->filter_log_id = -1; s = set_getstr(&ic->acc->set, "mode"); if (g_strcasecmp(s, "one") == 0) { @@ -894,7 +929,7 @@ static guint64 twitter_message_id_from_command_arg(struct im_connection *ic, cha if (arg[0] == '#') { arg++; } - if (parse_int64(arg, 16, &id) && id < TWITTER_LOG_LENGTH) { + if (parse_int64(arg, 16, &id) && id < td->log_length) { bu = td->log[id].bu; id = td->log[id].id; } else if (parse_int64(arg, 10, &id)) { @@ -985,7 +1020,8 @@ static void twitter_handle_command(struct im_connection *ic, char *message) twitter_report_spam(ic, screen_name); goto eof; - } else if (g_strcasecmp(cmd[0], "rt") == 0 && cmd[1]) { + } else if ((g_strcasecmp(cmd[0], "rt") == 0 || + g_strcasecmp(cmd[0], "retweet") == 0) && cmd[1]) { id = twitter_message_id_from_command_arg(ic, cmd[1], NULL); td->last_status_id = 0; @@ -1024,7 +1060,18 @@ static void twitter_handle_command(struct im_connection *ic, char *message) twitter_status_show_url(ic, id); } goto eof; + } else if (g_strcasecmp(cmd[0], "quote") == 0 && cmd[1]) { + id = twitter_message_id_from_command_arg(ic, cmd[1], NULL); + td->last_status_id = 0; + if (id) { + twitter_status_quote_post(ic, id, cmd[2]); + } else { + twitter_log(ic, "User '%s' does not exist or didn't " + "post any statuses recently", cmd[1]); + } + + goto eof; } else if (g_strcasecmp(cmd[0], "post") == 0) { message += 5; allow_post = TRUE; diff --git a/protocols/twitter/twitter.h b/protocols/twitter/twitter.h index 86c88262..61afa4bb 100644 --- a/protocols/twitter/twitter.h +++ b/protocols/twitter/twitter.h @@ -68,7 +68,9 @@ struct twitter_data { gint main_loop_id; gint filter_update_id; struct http_request *stream; + time_t stream_opentime; struct http_request *filter_stream; + time_t filter_stream_opentime; struct groupchat *timeline_gc; gint http_fails; twitter_flags_t flags; @@ -84,6 +86,11 @@ struct twitter_data { /* set show_ids */ struct twitter_log_data *log; int log_id; + struct twitter_log_data *filter_log; + int filter_log_id; + + gboolean long_ids; + int log_length; }; #define TWITTER_FILTER_UPDATE_WAIT 3000 @@ -99,7 +106,8 @@ struct twitter_user_data { time_t last_time; }; -#define TWITTER_LOG_LENGTH 256 +#define TWITTER_SHORT_LOG_LENGTH 256 +#define TWITTER_LONG_LOG_LENGTH (256 * 256) struct twitter_log_data { guint64 id; /* DANGER: bu can be a dead pointer. Check it first. diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index 77f487ae..bffd61aa 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -790,7 +790,7 @@ 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 < td->log_length; i++) { if (td->log[i].id == txs->reply_to) { reply_to = i; break; @@ -808,26 +808,52 @@ static char *twitter_msg_add_id(struct im_connection *ic, } } - 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 (txs->from_filter) { + td->filter_log_id = (td->filter_log_id + 1) % td->log_length; + td->filter_log[td->filter_log_id].id = txs->id; + td->filter_log[td->filter_log_id].bu = bee_user_by_handle(ic->bee, ic, txs->user->screen_name); + } else { + td->log_id = (td->log_id + 1) % td->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) { - td->log[td->log_id].id = txs->rt_id; - /* More useful than NULL. */ - td->log[td->log_id].bu = &twitter_log_local_user; + if (txs->from_filter) { + td->filter_log[td->filter_log_id].id = txs->rt_id; + /* More useful than NULL. */ + td->filter_log[td->filter_log_id].bu = &twitter_log_local_user; + } else { + td->log[td->log_id].id = txs->rt_id; + /* More useful than NULL. */ + td->log[td->log_id].bu = &twitter_log_local_user; + } } if (set_getbool(&ic->acc->set, "show_ids")) { if (reply_to != -1) { - return g_strdup_printf("\002[\002%02x->%02x\002]\002 %s%s", - td->log_id, reply_to, prefix, txs->text); + if (td->long_ids) { + return g_strdup_printf("\002[\002%04x->%04x\002]\002 %s%s", + txs->from_filter ? td->filter_log_id : td->log_id, + reply_to, prefix, txs->text); + } else { + return g_strdup_printf("\002[\002%02x->%02x\002]\002 %s%s", + txs->from_filter ? td->filter_log_id : td->log_id, + reply_to, prefix, txs->text); + } } else { - return g_strdup_printf("\002[\002%02x\002]\002 %s%s", - td->log_id, prefix, txs->text); + if (td->long_ids) { + return g_strdup_printf("\002[\002%04x\002]\002 %s%s", + txs->from_filter ? td->filter_log_id : td->log_id, + prefix, txs->text); + } else { + return g_strdup_printf("\002[\002%02x\002]\002 %s%s", + txs->from_filter ? td->filter_log_id : td->log_id, + prefix, txs->text); + } } } else { if (*prefix) { @@ -1009,8 +1035,23 @@ static void twitter_http_stream(struct http_request *req) if ((req->flags & HTTPC_EOF) || !req->reply_body) { if (req == td->stream) { td->stream = NULL; + + if (req->status_code == 200 && + td->stream_opentime + 3 < time(NULL)) { + debug("Reconnecting to twitter stream."); + twitter_open_stream(ic); + twitter_get_timeline(ic, -1); + return; + } } else if (req == td->filter_stream) { td->filter_stream = NULL; + + if (req->status_code == 200 && + td->filter_stream_opentime + 3 < time(NULL)) { + debug("Reconnecting to twitter filter stream."); + twitter_open_filter_stream(ic); + return; + } } imcb_error(ic, "Stream closed (%s)", req->status_string); @@ -1090,10 +1131,12 @@ static gboolean twitter_stream_handle_object(struct im_connection *ic, json_valu static gboolean twitter_stream_handle_status(struct im_connection *ic, struct twitter_xml_status *txs) { struct twitter_data *td = ic->proto_data; + struct twitter_log_data *tl; int i; - for (i = 0; i < TWITTER_LOG_LENGTH; i++) { - if (td->log[i].id == txs->id) { + tl = txs->from_filter ? td->filter_log : td->log; + for (i = 0; i < td->log_length; i++) { + if (tl[i].id == txs->id) { /* Got a duplicate (RT, probably). Drop it. */ return TRUE; } @@ -1185,6 +1228,7 @@ gboolean twitter_open_stream(struct im_connection *ic) /* 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->stream->flags |= HTTPC_STREAMING; + td->stream_opentime = time(NULL); return TRUE; } @@ -1240,6 +1284,7 @@ static gboolean twitter_filter_stream(struct im_connection *ic) /* 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; + td->filter_stream_opentime = time(NULL); ret = TRUE; } @@ -1791,3 +1836,63 @@ void twitter_status_show_url(struct im_connection *ic, guint64 id) twitter_http(ic, url, twitter_http_status_show_url, ic, 0, NULL, 0); g_free(url); } + +struct twitter_http_msg { + struct im_connection *ic; + char *message; +}; + +static void twitter_http_status_quote_post(struct http_request *req) +{ + struct twitter_http_msg *thm = req->data; + struct im_connection *ic = thm->ic; + struct twitter_data *td = ic->proto_data; + char *message; + const char *name; + json_value *parsed, *id; + + if (!g_slist_find(twitter_connections, ic)) { + goto eof; + } + + if (!(parsed = twitter_parse_response(ic, req))) { + goto eof; + } + + name = json_o_str(json_o_get(parsed, "user"), "screen_name"); + id = json_o_get(parsed, "id"); + + if (name && id && id->type == json_integer) { + message = g_strdup_printf("%s https://twitter.com/%s/status/%" G_GUINT64_FORMAT, thm->message, name, id->u.integer); + + /*if (!twitter_length_check(ic, message)) { + goto eof; + }*/ + + td->last_status_id = 0; + twitter_post_status(ic, message, 0); + } else { + twitter_log(ic, "Error: could not fetch url for quoted tweet."); + } + + json_value_free(parsed); + +eof: + g_free(thm->message); + g_free(thm); +} + +void twitter_status_quote_post(struct im_connection *ic, guint64 id, char *message) +{ + struct twitter_http_msg *thm; + char *url; + + thm = g_new0(struct twitter_http_msg, 1); + + thm->ic = ic; + thm->message = g_strdup(message); + + url = g_strdup_printf("%s%" G_GUINT64_FORMAT "%s", TWITTER_STATUS_SHOW_URL, id, ".json"); + twitter_http(ic, url, twitter_http_status_quote_post, thm, 0, NULL, 0); + g_free(url); +} diff --git a/protocols/twitter/twitter_lib.h b/protocols/twitter/twitter_lib.h index 6833d23d..d3b6ae9e 100644 --- a/protocols/twitter/twitter_lib.h +++ b/protocols/twitter/twitter_lib.h @@ -105,6 +105,7 @@ void twitter_status_retweet(struct im_connection *ic, guint64 id); void twitter_report_spam(struct im_connection *ic, char *screen_name); void twitter_favourite_tweet(struct im_connection *ic, guint64 id); void twitter_status_show_url(struct im_connection *ic, guint64 id); +void twitter_status_quote_post(struct im_connection *ic, guint64 id, char *message); #endif //_TWITTER_LIB_H |