From fb62f132a55896e235fd4956987548bdcd0be519 Mon Sep 17 00:00:00 2001 From: Flexo Date: Tue, 15 Mar 2016 21:39:36 +0000 Subject: Honour twitter's mutes and "hide retweets from this user" settings. --- protocols/twitter/twitter_lib.c | 129 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) (limited to 'protocols/twitter/twitter_lib.c') diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index 80747015..288e0207 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -239,6 +239,8 @@ 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_noretweets_ids(struct http_request *req); /** * Get the friends ids. @@ -255,6 +257,34 @@ void twitter_get_friends_ids(struct im_connection *ic, gint64 next_cursor) g_free(args[1]); } +/** + * Get the muted users ids. + */ +void twitter_get_mutes_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_MUTES_IDS_URL, twitter_http_get_mutes_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) +{ + char *args[2]; + + args[0] = "cursor"; + args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); + twitter_http(ic, TWITTER_NORETWEETS_IDS_URL, twitter_http_get_noretweets_ids, ic, 0, args, 2); + + g_free(args[1]); +} + /** * Fill a list of ids. */ @@ -336,6 +366,92 @@ static void twitter_http_get_friends_ids(struct http_request *req) txl_free(txl); } +/** + * Callback for getting the mutes ids. + */ +static void twitter_http_get_mutes_ids(struct http_request *req) +{ + struct im_connection *ic = req->data; + json_value *parsed; + struct twitter_xml_list *txl; + struct twitter_data *td; + + // Check if the connection is stil active + if (!g_slist_find(twitter_connections, ic)) { + return; + } + + td = ic->proto_data; + + // Parse the data. + if (!(parsed = twitter_parse_response(ic, req))) { + return; + } + + 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; + if (txl->next_cursor) { + /* Recurse while there are still more pages */ + twitter_get_mutes_ids(ic, txl->next_cursor); + } + + txl->list = NULL; + txl_free(txl); +} + +/** + * Callback for getting the no-retweets ids. + */ +static void twitter_http_get_noretweets_ids(struct http_request *req) +{ + struct im_connection *ic = req->data; + json_value *parsed; + struct twitter_xml_list *txl; + struct twitter_data *td; + + // Check if the connection is stil active + if (!g_slist_find(twitter_connections, ic)) { + return; + } + + td = ic->proto_data; + + // Parse the data. + if (!(parsed = twitter_parse_response(ic, req))) { + return; + } + + 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) { + unsigned int i; + for (i = 0; i < parsed->u.array.length; i++) { + json_value *c = parsed->u.array.values[i]; + if (c->type != json_integer) { + continue; + } + txl->list = g_slist_prepend(txl->list, + g_strdup_printf("%"PRIu64, c->u.integer)); + } + } + + json_value_free(parsed); + td->noretweets_ids = txl->list; + + txl->list = NULL; + txl_free(txl); +} + static gboolean twitter_xt_get_users(json_value *node, struct twitter_xml_list *txl); static void twitter_http_get_users_lookup(struct http_request *req); @@ -830,10 +946,22 @@ static void twitter_status_show(struct im_connection *ic, struct twitter_xml_sta { struct twitter_data *td = ic->proto_data; char *last_id_str; + char *uid_str; if (status->user == NULL || status->text == NULL) { return; } + + /* Check this is not a tweet that should be muted */ + uid_str = g_strdup_printf("%" PRIu64, status->user->uid); + if (g_slist_find_custom(td->mutes_ids, uid_str, (GCompareFunc)strcmp)) { + g_free(uid_str); + return; + } + if (status->id != status->rt_id && g_slist_find_custom(td->noretweets_ids, uid_str, (GCompareFunc)strcmp)) { + g_free(uid_str); + return; + } /* Grrrr. Would like to do this during parsing, but can't access settings from there. */ @@ -856,6 +984,7 @@ static void twitter_status_show(struct im_connection *ic, struct twitter_xml_sta last_id_str = g_strdup_printf("%" G_GUINT64_FORMAT, td->timeline_id); set_setstr(&ic->acc->set, "_last_tweet", last_id_str); g_free(last_id_str); + g_free(uid_str); } static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o, gboolean from_filter); -- cgit v1.2.3 From 9cf63aca0ffdc0cf708c3d17ee3ae9f92fa7cbf8 Mon Sep 17 00:00:00 2001 From: Flexo Date: Thu, 31 Mar 2016 18:49:52 +0000 Subject: Add mute and unmute commands. --- protocols/twitter/twitter_lib.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'protocols/twitter/twitter_lib.c') diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index 288e0207..6b38bd7c 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -1652,6 +1652,19 @@ void twitter_friendships_create_destroy(struct im_connection *ic, char *who, int twitter_http_post, ic, 1, args, 2); } +/** + * Mute or unmute a user + */ +void twitter_mute_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_MUTES_CREATE_URL : TWITTER_MUTES_DESTROY_URL, + twitter_http_post, ic, 1, args, 2); +} + void twitter_status_destroy(struct im_connection *ic, guint64 id) { char *url; -- cgit v1.2.3 From 0d581bd04e3a42d20437886d72a13c698f0ddf6a Mon Sep 17 00:00:00 2001 From: Flexo Date: Thu, 31 Mar 2016 22:04:33 +0000 Subject: Receive mute/unmute notifications from the stream. --- protocols/twitter/twitter_lib.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) (limited to 'protocols/twitter/twitter_lib.c') diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index 6b38bd7c..c60f159a 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -953,7 +953,7 @@ 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("%" PRIu64, status->user->uid); + uid_str = g_strdup_printf("%" G_GINT64_FORMAT, status->user->uid); if (g_slist_find_custom(td->mutes_ids, uid_str, (GCompareFunc)strcmp)) { g_free(uid_str); return; @@ -1121,6 +1121,8 @@ 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"); + struct twitter_xml_user *us = NULL; + struct twitter_xml_user *ut = NULL; if (!type || !source || source->type != json_object || !target || target->type != json_object) { @@ -1128,15 +1130,33 @@ static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value } 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); + us = twitter_xt_get_user(source); + ut = twitter_xt_get_user(target); if (g_strcasecmp(us->screen_name, td->user) == 0) { twitter_add_buddy(ic, ut->screen_name, ut->name); } - txu_free(us); - txu_free(ut); + } else if (strcmp(type, "mute") == 0) { + GSList *ids = td->mutes_ids; + ut = twitter_xt_get_user(target); + ids = g_slist_prepend(ids, + g_strdup_printf("%" G_GINT64_FORMAT, ut->uid)); + + td->mutes_ids = ids; + } else if (strcmp(type, "unmute") == 0) { + GSList *found; + char *uid_str; + ut = twitter_xt_get_user(target); + uid_str = g_strdup_printf("%" G_GINT64_FORMAT, ut->uid); + if ((found = g_slist_find_custom(td->mutes_ids, uid_str, + (GCompareFunc)strcmp))) { + td->mutes_ids = g_slist_remove(td->mutes_ids, found); + } + g_free(uid_str); } + txu_free(us); + txu_free(ut); + return TRUE; } -- cgit v1.2.3 From 166a571321826a68626eaf10a59901253237f09e Mon Sep 17 00:00:00 2001 From: Flexo Date: Fri, 1 Apr 2016 18:06:15 +0000 Subject: Avoid adding an id twice to the mutes list. Twitter doesn't error if you mute the same user multiple times. Also, correct signedness of the stringified user ids. bitlbee keeps them as unsigned even if the json library uses signed for integers... --- protocols/twitter/twitter_lib.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) (limited to 'protocols/twitter/twitter_lib.c') diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index c60f159a..82765201 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -953,7 +953,14 @@ 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_GINT64_FORMAT, status->user->uid); + uid_str = g_strdup_printf("%" PRIu64, status->user->uid); + if (getenv("BITLBEE_DEBUG")) { + GSList *item; + fprintf(stderr, "Checking mutes; this uid=%s\n", uid_str); + for (item = td->mutes_ids; item != NULL; item = item->next) { + fprintf(stderr, " id: %s\n", (char *)item->data); + } + } if (g_slist_find_custom(td->mutes_ids, uid_str, (GCompareFunc)strcmp)) { g_free(uid_str); return; @@ -1136,22 +1143,34 @@ static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value twitter_add_buddy(ic, ut->screen_name, ut->name); } } else if (strcmp(type, "mute") == 0) { - GSList *ids = td->mutes_ids; + GSList *found; + char *uid_str; ut = twitter_xt_get_user(target); - ids = g_slist_prepend(ids, - g_strdup_printf("%" G_GINT64_FORMAT, ut->uid)); - - td->mutes_ids = ids; + uid_str = g_strdup_printf("%" PRIu64, 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); + if (getenv("BITLBEE_DEBUG")) { + fprintf(stderr, "New mute: %s %"PRIu64"\n", + ut->screen_name, ut->uid); + } } else if (strcmp(type, "unmute") == 0) { GSList *found; char *uid_str; ut = twitter_xt_get_user(target); - uid_str = g_strdup_printf("%" G_GINT64_FORMAT, ut->uid); + uid_str = g_strdup_printf("%" PRIu64, ut->uid); if ((found = g_slist_find_custom(td->mutes_ids, uid_str, (GCompareFunc)strcmp))) { td->mutes_ids = g_slist_remove(td->mutes_ids, found); } g_free(uid_str); + twitter_log(ic, "Unmuted user %s", ut->screen_name); + if (getenv("BITLBEE_DEBUG")) { + fprintf(stderr, "New unmute: %s %"PRIu64"\n", + ut->screen_name, ut->uid); + } } txu_free(us); -- cgit v1.2.3