diff options
Diffstat (limited to 'protocols/twitter')
-rw-r--r-- | protocols/twitter/twitter.c | 113 | ||||
-rw-r--r-- | protocols/twitter/twitter.h | 13 | ||||
-rw-r--r-- | protocols/twitter/twitter_lib.c | 245 | ||||
-rw-r--r-- | protocols/twitter/twitter_lib.h | 10 |
4 files changed, 317 insertions, 64 deletions
diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index fcd76989..d43d2909 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); @@ -343,8 +350,10 @@ void twitter_login_finish(struct im_connection *ic) } else if (!(td->flags & TWITTER_MODE_ONE) && !(td->flags & TWITTER_HAVE_FRIENDS)) { imcb_log(ic, "Getting contact list"); + twitter_get_friends_ids(ic, -1); twitter_get_mutes_ids(ic, -1); + twitter_get_blocks_ids(ic, -1); twitter_get_noretweets_ids(ic, -1); } else { twitter_main_loop_start(ic); @@ -503,6 +512,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 || @@ -513,6 +539,15 @@ static char *set_eval_mode(set_t * set, char *value) } } +static char *set_eval_id_length(set_t * set, char *value) +{ + int len = atoi(value); + if (len >= 1 || len <= 4) + return value; + + return SET_INVALID; +} + static void twitter_init(account_t * acc) { set_t *s; @@ -557,6 +592,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, "id_length", "2", set_eval_id_length, 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, "autofill_reply", "true", set_eval_bool, acc); + s = set_add(&acc->set, "_last_tweet", "0", NULL, acc); s->flags |= SET_HIDDEN | SET_NOSAVE; @@ -580,6 +623,7 @@ static void twitter_login(account_t * acc) char name[strlen(acc->user) + 9]; url_t url; char *s; + size_t i; if (!url_set(&url, set_getstr(&ic->acc->set, "base_url")) || (url.proto != PROTO_HTTP && url.proto != PROTO_HTTPS)) { @@ -637,8 +681,17 @@ 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->id_length = set_getint(&ic->acc->set, "id_length"); + td->log_length = 0; + for (i = 0; i < td->id_length; i++) { + td->log_length = (td->log_length << 4) + 0x0F; + } + td->log_length += 1; + + 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) { @@ -649,6 +702,10 @@ static void twitter_login(account_t * acc) td->flags |= TWITTER_MODE_CHAT; } + td->mutes_ids = g_hash_table_new_full(g_str_hash, (GEqualFunc)strcmp, (GDestroyNotify)g_free, NULL); + td->blocks_ids = g_hash_table_new_full(g_str_hash, (GEqualFunc)strcmp, (GDestroyNotify)g_free, NULL); + td->noretweets_ids = g_hash_table_new_full(g_str_hash, (GEqualFunc)strcmp, (GDestroyNotify)g_free, NULL); + twitter_login_finish(ic); } @@ -674,11 +731,9 @@ static void twitter_logout(struct im_connection *ic) b_event_remove(td->filter_update_id); } - g_slist_foreach(td->mutes_ids, (GFunc) g_free, NULL); - g_slist_free(td->mutes_ids); - - g_slist_foreach(td->noretweets_ids, (GFunc) g_free, NULL); - g_slist_free(td->noretweets_ids); + g_hash_table_unref(td->mutes_ids); + g_hash_table_unref(td->blocks_ids); + g_hash_table_unref(td->noretweets_ids); http_close(td->stream); twitter_filter_remove_all(ic); @@ -882,7 +937,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)) { @@ -973,7 +1028,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; @@ -992,7 +1048,11 @@ static void twitter_handle_command(struct im_connection *ic, char *message) "post any statuses recently", cmd[1]); goto eof; } - message = new = g_strdup_printf("@%s %s", bu->handle, cmd[2]); + if (!set_getbool(&ic->acc->set, "autofill_reply")) { + message = new = g_strdup_printf("@%s %s", bu->handle, cmd[2]); + } else { + message = cmd[2]; + } in_reply_to = id; allow_post = TRUE; } else if (g_strcasecmp(cmd[0], "rawreply") == 0 && cmd[1] && cmd[2]) { @@ -1012,12 +1072,43 @@ 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; + } else if (g_strcasecmp(cmd[0], "dm") == 0 && cmd[1] && cmd[2]) { + if ((bu = bee_user_by_handle(ic->bee, ic, cmd[1]))) { + twitter_direct_messages_new(ic, bu->handle, cmd[2]); + } else { + twitter_direct_messages_new(ic, cmd[1], cmd[2]); + } + goto eof; + } else if (g_strcasecmp(cmd[0], "rtoff") == 0 && cmd[1]) { + twitter_retweet_enable_disable(ic, cmd[1], 0); + goto eof; + } else if (g_strcasecmp(cmd[0], "rton") == 0 && cmd[1]) { + twitter_retweet_enable_disable(ic, cmd[1], 1); + goto eof; + } else if (g_strcasecmp(cmd[0], "block") == 0 && cmd[1]) { + twitter_block_create_destroy(ic, cmd[1], 1); + goto eof; + } else if (g_strcasecmp(cmd[0], "unblock") == 0 && cmd[1]) { + twitter_block_create_destroy(ic, cmd[1], 0); + goto eof; } + if (allow_post) { char *s; diff --git a/protocols/twitter/twitter.h b/protocols/twitter/twitter.h index 86c88262..bf47d4fc 100644 --- a/protocols/twitter/twitter.h +++ b/protocols/twitter/twitter.h @@ -60,15 +60,18 @@ struct twitter_data { guint64 timeline_id; GSList *follow_ids; - GSList *mutes_ids; - GSList *noretweets_ids; GSList *filters; + GHashTable *mutes_ids; + GHashTable *blocks_ids; + GHashTable *noretweets_ids; guint64 last_status_id; /* For undo */ 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 +87,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; + + int id_length; + int log_length; }; #define TWITTER_FILTER_UPDATE_WAIT 3000 @@ -99,7 +107,6 @@ struct twitter_user_data { time_t last_time; }; -#define TWITTER_LOG_LENGTH 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 8425c58e..4addb650 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -240,6 +240,7 @@ static json_value *twitter_parse_response(struct im_connection *ic, struct http_ static void twitter_http_get_friends_ids(struct http_request *req); static void twitter_http_get_mutes_ids(struct http_request *req); +static void twitter_http_get_blocks_ids(struct http_request *req); static void twitter_http_get_noretweets_ids(struct http_request *req); /** @@ -272,6 +273,20 @@ void twitter_get_mutes_ids(struct im_connection *ic, gint64 next_cursor) } /** + * Get the blocked users ids. + */ +void twitter_get_blocks_ids(struct im_connection *ic, gint64 next_cursor) +{ + char *args[2]; + + args[0] = "cursor"; + args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); + twitter_http(ic, TWITTER_BLOCKS_IDS_URL, twitter_http_get_blocks_ids, ic, 0, args, 2); + + g_free(args[1]); +} + +/** * Get the ids for users from whom we should ignore retweets. */ void twitter_get_noretweets_ids(struct im_connection *ic, gint64 next_cursor) @@ -367,14 +382,15 @@ static void twitter_http_get_friends_ids(struct http_request *req) } /** - * Callback for getting the mutes ids. + * Callback for getting the blocks and mutes ids. */ -static void twitter_http_get_mutes_ids(struct http_request *req) +static void twitter_http_get_mutes_blocks_ids(struct http_request *req, int blocks) { struct im_connection *ic = req->data; json_value *parsed; struct twitter_xml_list *txl; struct twitter_data *td; + GSList *elem; // Check if the connection is stil active if (!g_slist_find(twitter_connections, ic)) { @@ -394,24 +410,45 @@ static void twitter_http_get_mutes_ids(struct http_request *req) } txl = g_new0(struct twitter_xml_list, 1); - txl->list = td->mutes_ids; /* mute ids API response is similar enough to friends response to reuse this method */ twitter_xt_get_friends_id_list(parsed, txl); json_value_free(parsed); - td->mutes_ids = txl->list; + for (elem = txl->list; elem; elem = elem->next) { + g_hash_table_add(blocks ? td->blocks_ids : td->mutes_ids, elem->data); + } + if (txl->next_cursor) { /* Recurse while there are still more pages */ - twitter_get_mutes_ids(ic, txl->next_cursor); + if (blocks) { + twitter_get_blocks_ids(ic, txl->next_cursor); + } else { + twitter_get_mutes_ids(ic, txl->next_cursor); + } } - txl->list = NULL; txl_free(txl); } /** + * Callback for getting the mutes ids. + */ +static void twitter_http_get_mutes_ids(struct http_request *req) +{ + twitter_http_get_mutes_blocks_ids(req, 0); +} + +/** + * Callback for getting the blocks ids. + */ +static void twitter_http_get_blocks_ids(struct http_request *req) +{ + twitter_http_get_mutes_blocks_ids(req, 1); +} + +/** * Callback for getting the no-retweets ids. */ static void twitter_http_get_noretweets_ids(struct http_request *req) @@ -439,8 +476,6 @@ static void twitter_http_get_noretweets_ids(struct http_request *req) } txl = g_new0(struct twitter_xml_list, 1); - txl->list = td->noretweets_ids; - // Process the retweet ids txl->type = TXL_ID; if (parsed->type == json_array) { @@ -450,15 +485,12 @@ static void twitter_http_get_noretweets_ids(struct http_request *req) if (c->type != json_integer) { continue; } - txl->list = g_slist_prepend(txl->list, - g_strdup_printf("%" PRId64, c->u.integer)); + g_hash_table_add(td->noretweets_ids, g_strdup_printf("%"PRId64, c->u.integer)); } } json_value_free(parsed); - td->noretweets_ids = txl->list; - txl->list = NULL; txl_free(txl); } @@ -816,7 +848,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; @@ -834,26 +866,39 @@ 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); + return g_strdup_printf("\002[\002%0*x->%0*x\002]\002 %s%s", + td->id_length, td->log_id, td->id_length, + reply_to, prefix, txs->text); } else { - return g_strdup_printf("\002[\002%02x\002]\002 %s%s", - td->log_id, prefix, txs->text); + return g_strdup_printf("\002[\002%0*x\002]\002 %s%s", + td->id_length, td->log_id, prefix, txs->text); } } else { if (*prefix) { @@ -981,11 +1026,12 @@ static void twitter_status_show(struct im_connection *ic, struct twitter_xml_sta /* Check this is not a tweet that should be muted */ uid_str = g_strdup_printf("%" G_GUINT64_FORMAT, status->user->uid); - if (g_slist_find_custom(td->mutes_ids, uid_str, (GCompareFunc)strcmp)) { + if (g_hash_table_lookup(td->mutes_ids, uid_str) || + g_hash_table_lookup(td->blocks_ids, uid_str)) { g_free(uid_str); return; } - if (status->id != status->rt_id && g_slist_find_custom(td->noretweets_ids, uid_str, (GCompareFunc)strcmp)) { + if (status->id != status->rt_id && g_hash_table_lookup(td->noretweets_ids, uid_str)) { g_free(uid_str); return; } @@ -1034,8 +1080,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); @@ -1094,8 +1155,12 @@ static gboolean twitter_stream_handle_object(struct im_connection *ic, json_valu } 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) { - imcb_buddy_msg(ic, txs->user->screen_name, - txs->text, 0, txs->created_at); + char *uid_str = g_strdup_printf("%" PRIu64, txs->user->uid); + if (!g_hash_table_lookup(td->blocks_ids, uid_str)) { + imcb_buddy_msg(ic, txs->user->screen_name, + txs->text, 0, txs->created_at); + } + g_free(uid_str); } txs_free(txs); return TRUE; @@ -1119,10 +1184,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; } @@ -1165,33 +1232,25 @@ static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value if (g_strcasecmp(us->screen_name, td->user) == 0) { twitter_add_buddy(ic, ut->screen_name, ut->name); } - } else if (strcmp(type, "mute") == 0) { - GSList *found; + } else if (strcmp(type, "mute") == 0 || strcmp(type, "block") == 0) { char *uid_str; + int mute = strcmp(type, "mute") == 0; ut = twitter_xt_get_user(target); uid_str = g_strdup_printf("%" G_GUINT64_FORMAT, ut->uid); - if (!(found = g_slist_find_custom(td->mutes_ids, uid_str, - (GCompareFunc)strcmp))) { - td->mutes_ids = g_slist_prepend(td->mutes_ids, uid_str); - } - twitter_log(ic, "Muted user %s", ut->screen_name); + g_hash_table_add(mute ? td->mutes_ids : td->blocks_ids, uid_str); + twitter_log(ic, "%s user %s", mute ? "Muted" : "Blocked", ut->screen_name); if (getenv("BITLBEE_DEBUG")) { fprintf(stderr, "New mute: %s %"G_GUINT64_FORMAT"\n", ut->screen_name, ut->uid); } - } else if (strcmp(type, "unmute") == 0) { - GSList *found; + } else if (strcmp(type, "unmute") == 0 || strcmp(type, "unblock") == 0) { char *uid_str; + int unmute = strcmp(type, "unmute") == 0; ut = twitter_xt_get_user(target); uid_str = g_strdup_printf("%" G_GUINT64_FORMAT, ut->uid); - if ((found = g_slist_find_custom(td->mutes_ids, uid_str, - (GCompareFunc)strcmp))) { - char *found_str = found->data; - td->mutes_ids = g_slist_delete_link(td->mutes_ids, found); - g_free(found_str); - } + g_hash_table_remove(unmute ? td->mutes_ids : td->blocks_ids, uid_str); g_free(uid_str); - twitter_log(ic, "Unmuted user %s", ut->screen_name); + twitter_log(ic, "%s user %s", unmute ? "Unmuted" : "Blocked", ut->screen_name); if (getenv("BITLBEE_DEBUG")) { fprintf(stderr, "New unmute: %s %"G_GUINT64_FORMAT"\n", ut->screen_name, ut->uid); @@ -1214,6 +1273,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; } @@ -1269,6 +1329,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; } @@ -1683,10 +1744,12 @@ static void twitter_http_post(struct http_request *req) */ void twitter_post_status(struct im_connection *ic, char *msg, guint64 in_reply_to) { - char *args[4] = { + char *args[6] = { "status", msg, "in_reply_to_status_id", - g_strdup_printf("%" G_GUINT64_FORMAT, in_reply_to) + g_strdup_printf("%" G_GUINT64_FORMAT, in_reply_to), + "auto_populate_reply_metadata", + "true", }; if (set_getbool(&ic->acc->set, "in_korea") && !in_reply_to) { @@ -1697,7 +1760,7 @@ void twitter_post_status(struct im_connection *ic, char *msg, guint64 in_reply_t } twitter_http(ic, TWITTER_STATUS_UPDATE_URL, twitter_http_post, ic, 1, - args, in_reply_to ? 4 : 2); + args, in_reply_to ? (set_getbool(&ic->acc->set, "autofill_reply") ? 6 : 4) : 2); g_free(args[3]); } @@ -1740,6 +1803,32 @@ void twitter_mute_create_destroy(struct im_connection *ic, char *who, int create twitter_http_post, ic, 1, args, 2); } +/** + * Block or unblock a user + */ +void twitter_block_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_BLOCKS_CREATE_URL : TWITTER_BLOCKS_DESTROY_URL, + twitter_http_post, ic, 1, args, 2); +} + +/** + * Enable or disable retweets for user + */ +void twitter_retweet_enable_disable(struct im_connection *ic, char *who, int enable) +{ + char *args[4]; + args[0] = "screen_name"; + args[1] = who; + args[2] = "retweets"; + args[3] = enable ? "true" : "false"; + twitter_http(ic, TWITTER_FRIENDSHIPS_UPDATE_URL, twitter_http_post, ic, 1, args, 4); +} + void twitter_status_destroy(struct im_connection *ic, guint64 id) { char *url; @@ -1831,3 +1920,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 5a4b8550..03da6421 100644 --- a/protocols/twitter/twitter_lib.h +++ b/protocols/twitter/twitter_lib.h @@ -57,12 +57,14 @@ #define TWITTER_FRIENDSHIPS_CREATE_URL "/friendships/create.json" #define TWITTER_FRIENDSHIPS_DESTROY_URL "/friendships/destroy.json" #define TWITTER_FRIENDSHIPS_SHOW_URL "/friendships/show.json" +#define TWITTER_FRIENDSHIPS_UPDATE_URL "/friendships/update.json" /* Social graphs URLs */ #define TWITTER_FRIENDS_IDS_URL "/friends/ids.json" #define TWITTER_FOLLOWERS_IDS_URL "/followers/ids.json" #define TWITTER_MUTES_IDS_URL "/mutes/users/ids.json" #define TWITTER_NORETWEETS_IDS_URL "/friendships/no_retweets/ids.json" +#define TWITTER_BLOCKS_IDS_URL "/blocks/ids.json" /* Account URLs */ #define TWITTER_ACCOUNT_RATE_LIMIT_URL "/account/rate_limit_status.json" @@ -73,8 +75,8 @@ #define TWITTER_FAVORITE_DESTROY_URL "/favorites/destroy.json" /* Block URLs */ -#define TWITTER_BLOCKS_CREATE_URL "/blocks/create/" -#define TWITTER_BLOCKS_DESTROY_URL "/blocks/destroy/" +#define TWITTER_BLOCKS_CREATE_URL "/blocks/create.json" +#define TWITTER_BLOCKS_DESTROY_URL "/blocks/destroy.json" /* Mute URLs */ #define TWITTER_MUTES_CREATE_URL "/mutes/users/create.json" @@ -92,6 +94,7 @@ gboolean twitter_open_filter_stream(struct im_connection *ic); gboolean twitter_get_timeline(struct im_connection *ic, gint64 next_cursor); void twitter_get_friends_ids(struct im_connection *ic, gint64 next_cursor); void twitter_get_mutes_ids(struct im_connection *ic, gint64 next_cursor); +void twitter_get_blocks_ids(struct im_connection *ic, gint64 next_cursor); void twitter_get_noretweets_ids(struct im_connection *ic, gint64 next_cursor); void twitter_get_statuses_friends(struct im_connection *ic, gint64 next_cursor); @@ -99,11 +102,14 @@ 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 *message); void twitter_friendships_create_destroy(struct im_connection *ic, char *who, int create); void twitter_mute_create_destroy(struct im_connection *ic, char *who, int create); +void twitter_block_create_destroy(struct im_connection *ic, char *who, int create); +void twitter_retweet_enable_disable(struct im_connection *ic, char *who, int enable); void twitter_status_destroy(struct im_connection *ic, guint64 id); 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 |