From fe5589432de68d30a7e941daf67b4f4ea13d76ff Mon Sep 17 00:00:00 2001 From: nogaems Date: Mon, 18 Mar 2019 23:20:41 +0300 Subject: [PATCH 1/3] feature: nickname disambiguation --- src/twc-chat.c | 18 +++++++ src/twc-chat.h | 4 ++ src/twc-commands.c | 55 +++++++++++++++++++++ src/twc-config.c | 6 +++ src/twc-config.h | 1 + src/twc-tox-callbacks.c | 106 ++++++++++++++++++++++++++++++---------- src/twc-utils.c | 101 +++++++++++++++++++++++++++++++++++++- src/twc-utils.h | 25 ++++++++++ 8 files changed, 289 insertions(+), 27 deletions(-) diff --git a/src/twc-chat.c b/src/twc-chat.c index 97921b8..f2724cc 100644 --- a/src/twc-chat.c +++ b/src/twc-chat.c @@ -57,6 +57,10 @@ twc_chat_new(struct t_twc_profile *profile, const char *name) chat->profile = profile; chat->friend_number = chat->group_number = -1; chat->nicks = NULL; + chat->ids = NULL; + chat->completion = NULL; + chat->last_search = NULL; + chat->prev_comp = NULL; size_t full_name_size = strlen(profile->name) + 1 + strlen(name) + 1; char *full_name = malloc(full_name_size); @@ -137,6 +141,8 @@ twc_chat_new_group(struct t_twc_profile *profile, int32_t group_number) chat->nicklist_group = weechat_nicklist_add_group(chat->buffer, NULL, NULL, NULL, true); chat->nicks = weechat_list_new(); + chat->ids = weechat_list_new(); + chat->completion = weechat_list_new(); weechat_buffer_set(chat->buffer, "nicklist", "1"); } @@ -395,6 +401,18 @@ twc_chat_free(struct t_twc_chat *chat) weechat_list_remove_all(chat->nicks); weechat_list_free(chat->nicks); } + if (chat->ids) + { + weechat_list_remove_all(chat->ids); + weechat_list_free(chat->ids); + } + if (chat->completion) + { + weechat_list_remove_all(chat->completion); + weechat_list_free(chat->completion); + } + free(chat->last_search); + free(chat->prev_comp); free(chat); } diff --git a/src/twc-chat.h b/src/twc-chat.h index a37176e..8ed87af 100644 --- a/src/twc-chat.h +++ b/src/twc-chat.h @@ -39,6 +39,10 @@ struct t_twc_chat struct t_gui_nick_group *nicklist_group; struct t_weelist *nicks; + struct t_weelist *ids; + struct t_weelist *completion; + char *last_search; + char *prev_comp; }; struct t_twc_chat * diff --git a/src/twc-commands.c b/src/twc-commands.c index a3a0618..3336bc7 100644 --- a/src/twc-commands.c +++ b/src/twc-commands.c @@ -1330,6 +1330,58 @@ twc_cmd_send(const void *pointer, void *data, struct t_gui_buffer *buffer, return WEECHAT_RC_OK; } +/** + * Custom completion for nicknames in groups. + */ +int +twc_input_complete(const void *pointer, void *data, struct t_gui_buffer *buffer, + const char *command) +{ + struct t_twc_chat *chat = twc_chat_search_buffer(buffer); + if (chat && chat->group_number >= 0) + { + const char *input = weechat_buffer_get_string(buffer, "input"); + if (!strcmp(input, "")) + return WEECHAT_RC_OK; + size_t last_search_len = + chat->last_search ? strlen(chat->last_search) : 0; + int cmp = strncmp(chat->last_search, input, last_search_len); + if (cmp || !last_search_len) + { + free(chat->last_search); + chat->last_search = strdup(input); + free(chat->prev_comp); + chat->prev_comp = NULL; + twc_starts_with(chat->nicks, chat->last_search, chat->completion); + } + + const char *comp = + twc_get_next_completion(chat->completion, chat->prev_comp); + if (!comp) + return WEECHAT_RC_OK; + + weechat_buffer_set(buffer, "completion_freeze", "1"); + + char *terminator = ": "; /* Probably put it in a config */ + char temp[strlen(comp) + strlen(terminator) + 1]; + sprintf(temp, "%s%s", comp, terminator); + weechat_buffer_set(buffer, "input", temp); + + int input_pos = weechat_buffer_get_integer(buffer, "input_length"); + int input_pos_str_size = snprintf(NULL, 0, "%d", input_pos); + char input_pos_str[input_pos_str_size + 1]; + snprintf(input_pos_str, input_pos_str_size + 1, "%d", input_pos); + weechat_buffer_set(buffer, "input_pos", input_pos_str); + + weechat_buffer_set(buffer, "completion_freeze", "0"); + + free(chat->prev_comp); + chat->prev_comp = strdup(comp); + return WEECHAT_RC_OK_EAT; + } + return WEECHAT_RC_OK; +} + /** * Register Tox-WeeChat commands. */ @@ -1421,6 +1473,9 @@ twc_commands_init() weechat_hook_command_run("/save", twc_cmd_save, NULL, NULL); + weechat_hook_command_run("/input complete_next", twc_input_complete, NULL, + NULL); + weechat_hook_command("status", "change your Tox status", "online|busy|away", "", NULL, twc_cmd_status, NULL, NULL); diff --git a/src/twc-config.c b/src/twc-config.c index 4b69d5e..2854026 100644 --- a/src/twc-config.c +++ b/src/twc-config.c @@ -38,6 +38,7 @@ struct t_config_section *twc_config_section_profile_default = NULL; struct t_config_option *twc_config_friend_request_message; struct t_config_option *twc_config_short_id_size; +struct t_config_option *twc_config_show_id; char *twc_profile_option_names[TWC_PROFILE_NUM_OPTIONS] = { "save_file", @@ -374,6 +375,11 @@ twc_config_init() NULL, 2, TOX_PUBLIC_KEY_SIZE * 2, "8", NULL, 0, twc_config_check_value_callback, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + twc_config_show_id = weechat_config_new_option( + twc_config_file, twc_config_section_look, "show_id", "boolean", + "show short Tox IDs in message logs and presence logs of group chats", + NULL, 0, 0, "on", NULL, 0, twc_config_check_value_callback, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL); } /** diff --git a/src/twc-config.h b/src/twc-config.h index 80d9418..4095d8c 100644 --- a/src/twc-config.h +++ b/src/twc-config.h @@ -24,6 +24,7 @@ struct t_twc_profile; extern struct t_config_option *twc_config_friend_request_message; extern struct t_config_option *twc_config_short_id_size; +extern struct t_config_option *twc_config_show_id; enum t_twc_proxy { diff --git a/src/twc-tox-callbacks.c b/src/twc-tox-callbacks.c index 6117fb6..be1b0b4 100644 --- a/src/twc-tox-callbacks.c +++ b/src/twc-tox-callbacks.c @@ -28,6 +28,7 @@ #endif /* TOXAV_ENABLED */ #include "twc-chat.h" +#include "twc-config.h" #include "twc-friend-request.h" #include "twc-group-invite.h" #include "twc-message-queue.h" @@ -412,6 +413,9 @@ twc_handle_group_message(Tox *tox, int32_t group_number, int32_t peer_number, char *myname = twc_get_self_name_nt(profile->tox); char *name = twc_get_peer_name_nt(profile->tox, group_number, peer_number); + char *short_id = + twc_get_peer_id_short(profile->tox, group_number, peer_number); + char *full_name = twc_get_peer_name_prefixed(short_id, name); char *tags = "notify_message"; char *message_nt = twc_null_terminate(message, length); @@ -425,10 +429,14 @@ twc_handle_group_message(Tox *tox, int32_t group_number, int32_t peer_number, if (weechat_string_has_highlight(message_nt, myname)) tags = "notify_highlight"; - twc_chat_print_message(chat, tags, nick_color, name, message_nt, - message_type); + twc_chat_print_message( + chat, tags, nick_color, + weechat_config_boolean(twc_config_show_id) ? full_name : name, + message_nt, message_type); free(name); + free(short_id); + free(full_name); free(myname); free(message_nt); } @@ -456,58 +464,88 @@ twc_group_peer_list_changed_callback(Tox *tox, uint32_t group_number, struct t_weelist *new_nicks; struct t_weelist_item *n; + struct t_weelist *new_ids; + struct t_weelist_item *id; npeers = tox_conference_peer_count(profile->tox, group_number, &err); if (err == TOX_ERR_CONFERENCE_PEER_QUERY_OK) { new_nicks = weechat_list_new(); + new_ids = weechat_list_new(); for (i = 0; i < npeers; i++) { char *name = twc_get_peer_name_nt(profile->tox, group_number, i); + char *id = twc_get_peer_id_short(profile->tox, group_number, i); weechat_list_add(new_nicks, name, WEECHAT_LIST_POS_END, NULL); + weechat_list_add(new_ids, id, WEECHAT_LIST_POS_END, NULL); free(name); + free(id); } } else return; + bool changed = false; + /* searching for exits */ n = weechat_list_get(chat->nicks, 0); + id = weechat_list_get(chat->ids, 0); - while (n) + while (id && n) { + const char *short_id = weechat_list_string(id); const char *name = weechat_list_string(n); - if (!weechat_list_search(new_nicks, name)) + if (!weechat_list_search(new_ids, short_id)) { - weechat_printf(chat->buffer, "%s%s just left the group chat", - weechat_prefix("quit"), name); - nick = weechat_nicklist_search_nick(chat->buffer, - chat->nicklist_group, name); + char *full_name = twc_get_peer_name_prefixed(short_id, name); + nick = weechat_nicklist_search_nick( + chat->buffer, chat->nicklist_group, full_name); weechat_nicklist_remove_nick(chat->buffer, nick); + weechat_printf( + chat->buffer, "%s%s just left the group chat", + weechat_prefix("quit"), + weechat_config_boolean(twc_config_show_id) ? full_name : name); + changed = true; + free(full_name); } n = weechat_list_next(n); + id = weechat_list_next(id); } /* searching for joins */ n = weechat_list_get(new_nicks, 0); + id = weechat_list_get(new_ids, 0); - while (n) + while (id && n) { + const char *short_id = weechat_list_string(id); const char *name = weechat_list_string(n); - if (!weechat_list_search(chat->nicks, name)) + if (!weechat_list_search(chat->ids, short_id)) { - weechat_printf(chat->buffer, "%s%s just joined the group chat", - weechat_prefix("join"), name); - weechat_nicklist_add_nick(chat->buffer, chat->nicklist_group, name, - NULL, NULL, NULL, 1); + char *full_name = twc_get_peer_name_prefixed(short_id, name); + weechat_nicklist_add_nick(chat->buffer, chat->nicklist_group, + full_name, NULL, NULL, NULL, 1); + weechat_printf( + chat->buffer, "%s%s just joined the group chat", + weechat_prefix("join"), + weechat_config_boolean(twc_config_show_id) ? full_name : name); + changed = true; + free(full_name); } n = weechat_list_next(n); + id = weechat_list_next(id); } - weechat_list_remove_all(chat->nicks); - weechat_list_free(chat->nicks); - chat->nicks = new_nicks; + if (changed) + { + weechat_list_remove_all(chat->nicks); + weechat_list_free(chat->nicks); + weechat_list_remove_all(chat->ids); + weechat_list_free(chat->ids); + chat->nicks = new_nicks; + chat->ids = new_ids; + } } void @@ -523,10 +561,13 @@ twc_group_peer_name_callback(Tox *tox, uint32_t group_number, struct t_gui_nick *nick = NULL; const char *prev_name; char *name; + const char *short_id; + char *prev_full_name; + char *full_name; bool rc; TOX_ERR_CONFERENCE_PEER_QUERY err = TOX_ERR_CONFERENCE_PEER_QUERY_OK; - struct t_weelist_item *n; + struct t_weelist_item *n, *id; npeers = tox_conference_peer_count(profile->tox, group_number, &err); @@ -550,27 +591,40 @@ twc_group_peer_name_callback(Tox *tox, uint32_t group_number, twc_group_peer_list_changed_callback(tox, group_number, data); return; } - + id = weechat_list_get(chat->ids, peer_number); + short_id = weechat_list_string(id); prev_name = weechat_list_string(n); + prev_full_name = twc_get_peer_name_prefixed(short_id, prev_name); + name = twc_null_terminate(pname, pname_len); + full_name = twc_get_peer_name_prefixed(short_id, name); nick = weechat_nicklist_search_nick(chat->buffer, chat->nicklist_group, - prev_name); - + prev_full_name); weechat_nicklist_remove_nick(chat->buffer, nick); + if (!twc_get_peer_name_count(chat->nicks, prev_name)) + { + nick = weechat_nicklist_search_nick(chat->buffer, chat->nicklist_group, + prev_name); + weechat_nicklist_remove_nick(chat->buffer, nick); + } err = TOX_ERR_CONFERENCE_PEER_QUERY_OK; rc = tox_conference_peer_number_is_ours(tox, group_number, peer_number, &err); + bool show_id = weechat_config_boolean(twc_config_show_id); if ((err == TOX_ERR_CONFERENCE_PEER_QUERY_OK) && (!rc)) - weechat_printf(chat->buffer, "%s%s is now known as %s", - weechat_prefix("network"), prev_name, name); - + weechat_printf( + chat->buffer, "%s%s is now known as %s", weechat_prefix("network"), + show_id ? prev_full_name : prev_name, show_id ? full_name : name); weechat_list_set(n, name); - + weechat_nicklist_add_nick(chat->buffer, chat->nicklist_group, full_name, + NULL, NULL, NULL, 1); weechat_nicklist_add_nick(chat->buffer, chat->nicklist_group, name, NULL, - NULL, NULL, 1); + NULL, NULL, 0); + free(prev_full_name); + free(full_name); free(name); } diff --git a/src/twc-utils.c b/src/twc-utils.c index 8405dfd..74276bb 100644 --- a/src/twc-utils.c +++ b/src/twc-utils.c @@ -178,7 +178,106 @@ twc_get_friend_id_short(Tox *tox, int32_t friend_number) } /** - * Reverse the bytes of a 32-bit integer. + * Return a group peer's Tox ID in short form. Return value must be freed. + */ +char * +twc_get_peer_id_short(Tox *tox, uint32_t conference_number, + uint32_t peer_number) +{ + uint8_t peer_id[TOX_PUBLIC_KEY_SIZE]; + TOX_ERR_CONFERENCE_PEER_QUERY err; + size_t short_id_length = weechat_config_integer(twc_config_short_id_size); + short_id_length = + short_id_length > 4 ? short_id_length : 4; /* Let's use a sane value */ + char *hex_address = malloc(short_id_length + 1); + + tox_conference_peer_get_public_key(tox, conference_number, peer_number, + peer_id, &err); + if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) + memset(peer_id, 0, TOX_PUBLIC_KEY_SIZE); + + twc_bin2hex(peer_id, short_id_length / 2, hex_address); + return hex_address; +} + +/** + * Prefix a nickname with Tox ID in short form. Return value must be freed. + */ +char * +twc_get_peer_name_prefixed(const char *id, const char *name) +{ + if (!name) + name = "Tox User"; + size_t full_length = strlen(id) + strlen(name) + 4; + char *full_name = malloc(full_length); + snprintf(full_name, full_length, "[%s] %s", id, name); + return full_name; +} + +/** + * Return amount of times a certain nickname repeats in a t_weelist list. + */ +size_t +twc_get_peer_name_count(struct t_weelist *list, const char *name) +{ + size_t count = 0; + struct t_weelist_item *item = weechat_list_get(list, 0); + for (item = weechat_list_get(list, 0); item; item = weechat_list_next(item)) + { + if (!strcmp(weechat_list_string(item), name)) + count++; + } + return count; +} + +/** + * Return t_weelist* to a list of strings which start with a certain string, + * NULL otherwise if there's no such strings. Must be properly freed after + * usage. + */ +struct t_weelist * +twc_starts_with(struct t_weelist *list, const char *search, + struct t_weelist *result) +{ + size_t length = strlen(search); + weechat_list_remove_all(result); + if (!search || !length) + return result; + struct t_weelist_item *item = weechat_list_get(list, 0); + while (item) + { + const char *string = weechat_list_string(item); + if (strlen(string) >= length && !strncmp(search, string, length)) + weechat_list_add(result, string, WEECHAT_LIST_POS_SORT, NULL); + item = weechat_list_next(item); + } + return result; +} + +/** + * Return next completion string regarding of a previous one. + */ + +const char * +twc_get_next_completion(struct t_weelist *completion_list, + const char *prev_comp) +{ + if (!weechat_list_size(completion_list)) + return NULL; + const char *comp = + weechat_list_string(weechat_list_get(completion_list, 0)); + if (prev_comp) + { + struct t_weelist_item *item = + weechat_list_search(completion_list, prev_comp); + if (item && (item = weechat_list_next(item))) + comp = weechat_list_string(item); + } + return comp; +} + +/** + * reverse the bytes of a 32-bit integer. */ uint32_t twc_uint32_reverse_bytes(uint32_t num) diff --git a/src/twc-utils.h b/src/twc-utils.h index b1d2f3d..6b641f7 100644 --- a/src/twc-utils.h +++ b/src/twc-utils.h @@ -49,6 +49,31 @@ twc_get_self_name_nt(Tox *tox); char * twc_get_friend_id_short(Tox *tox, int32_t friend_number); +char * +twc_get_peer_id_short(Tox *tox, uint32_t conference_number, + uint32_t peer_number); + +char * +twc_get_peer_name_prefixed(const char *id, const char *name); + +char * +twc_get_peer_name_prefixed_and_aligned(const char *id, const char *name, + size_t max); + +size_t +twc_get_max_string_length(struct t_weelist *list); + +size_t +twc_get_peer_name_count(struct t_weelist *list, const char *name); + +struct t_weelist * +twc_starts_with(struct t_weelist *list, const char *search, + struct t_weelist *result); + +const char * +twc_get_next_completion(struct t_weelist *completion_list, + const char *prev_comp); + uint32_t twc_uint32_reverse_bytes(uint32_t num); From 5c8f9bc239b6a2fc126e6a1a112117f4a64efa39 Mon Sep 17 00:00:00 2001 From: nogaems Date: Wed, 27 Mar 2019 06:33:29 +0300 Subject: [PATCH 2/3] feature: /ignore command Like it's already implemented in irc plugin, this commit adds the /ignore command. Now you can filter messages in group chats to not be shown, based on a part of Tox ID. The ignore list of IDs is manageable in this way: [tox] /ignore list add del ommit messages from people with certain Tox IDs list: show the list of ignores add: add an ID to the list del: delete an ID from the list --- src/twc-chat.c | 45 +++++++++++++++++ src/twc-chat.h | 9 ++++ src/twc-commands.c | 108 ++++++++++++++++++++++++++++++++++++++++ src/twc-config.c | 81 ++++++++++++++++++++++++++++++ src/twc-profile.c | 11 ++-- src/twc-profile.h | 1 + src/twc-tox-callbacks.c | 29 +++++++---- src/twc-utils.c | 17 +++++++ src/twc-utils.h | 5 +- 9 files changed, 290 insertions(+), 16 deletions(-) diff --git a/src/twc-chat.c b/src/twc-chat.c index f2724cc..657a71d 100644 --- a/src/twc-chat.c +++ b/src/twc-chat.c @@ -280,6 +280,51 @@ twc_chat_search_buffer(struct t_gui_buffer *buffer) return NULL; } +/** + * Set a prefix to a nickname in the nicklist of a chat. + */ +void +twc_chat_update_prefix(struct t_twc_chat *chat, const char *id, + const char *prefix, const char *prefix_color) +{ + struct t_gui_nick_group *ptr_group = NULL; + struct t_gui_nick *ptr_nick = NULL; + + weechat_nicklist_get_next_item(chat->buffer, &ptr_group, &ptr_nick); + while (ptr_group || ptr_nick) + { + if (ptr_nick) + { + const char *name_field = weechat_nicklist_nick_get_string( + chat->buffer, ptr_nick, "name"); + if (!weechat_strncasecmp(id, name_field + sizeof(char), strlen(id))) + { + weechat_nicklist_nick_set(chat->buffer, ptr_nick, + "prefix", prefix); + weechat_nicklist_nick_set(chat->buffer, ptr_nick, + "prefix_color", prefix_color); + weechat_nicklist_nick_set(chat->buffer, ptr_nick, "color", + "default"); + return; + } + } + weechat_nicklist_get_next_item(chat->buffer, &ptr_group, &ptr_nick); + } +} + +/** + * Update prefix for a certain nickname structure pointer. + */ +void +twc_chat_update_prefix_by_nick(struct t_gui_buffer *buffer, + struct t_gui_nick *nick, const char *prefix, + const char *prefix_color) +{ + weechat_nicklist_nick_set(buffer, nick, "prefix", prefix); + weechat_nicklist_nick_set(buffer, nick, "prefix_color", prefix_color); + weechat_nicklist_nick_set(buffer, nick, "color", "default"); +} + /** * Print a chat message to a chat's buffer. */ diff --git a/src/twc-chat.h b/src/twc-chat.h index 8ed87af..836e8eb 100644 --- a/src/twc-chat.h +++ b/src/twc-chat.h @@ -56,6 +56,15 @@ twc_chat_search_group(struct t_twc_profile *profile, int32_t group_number, struct t_twc_chat * twc_chat_search_buffer(struct t_gui_buffer *target_buffer); +void +twc_chat_update_prefix(struct t_twc_chat *chat, const char *id, + const char *prefix, const char *prefix_color); + +void +twc_chat_update_prefix_by_nick(struct t_gui_buffer *buffer, + struct t_gui_nick *nick, const char *prefix, + const char *prefix_color); + enum t_twc_rc twc_chat_set_logging(struct t_twc_chat const *const chat, bool logging); diff --git a/src/twc-commands.c b/src/twc-commands.c index 3336bc7..44ed2c3 100644 --- a/src/twc-commands.c +++ b/src/twc-commands.c @@ -1381,6 +1381,102 @@ twc_input_complete(const void *pointer, void *data, struct t_gui_buffer *buffer, } return WEECHAT_RC_OK; } +/** + * Update a certain nick's prefix in all opened group chats + */ +void +twc_name_prefix_in_groupchats(struct t_twc_profile *profile, const char *id, + const char *prefix, const char *prefix_color) +{ + struct t_twc_list_item *item; + struct t_twc_chat *chat; + size_t index; + twc_list_foreach (profile->chats, index, item) + { + chat = (struct t_twc_chat *)(item->chat); + if ((chat->group_number) >= 0) + { + twc_chat_update_prefix(chat, id, prefix, prefix_color); + } + } +} + +/** + * Command /ignore callback. + */ +int +twc_cmd_ignore(const void *pointer, void *data, struct t_gui_buffer *buffer, + int argc, char **argv, char **argv_eol) +{ + struct t_twc_profile *profile = twc_profile_search_buffer(buffer); + TWC_CHECK_PROFILE(profile); + TWC_CHECK_PROFILE_LOADED(profile); + + /* list ignores */ + if ((argc == 1) || + ((argc == 2) && (weechat_strcasecmp(argv[1], "list") == 0))) + { + if (!weechat_list_size(profile->ignores)) + { + weechat_printf(profile->buffer, "ignore list is empty"); + return WEECHAT_RC_OK; + } + weechat_printf(profile->buffer, "ignore list:"); + size_t i = 0; + struct t_weelist_item *item; + for (item = weechat_list_get(profile->ignores, 0); item; + item = weechat_list_next(item)) + { + weechat_printf(profile->buffer, " [%d] %s", i, + weechat_list_string(item)); + i++; + } + return WEECHAT_RC_OK; + } + /* add ignore */ + + const char *id = argv_eol[2]; + struct t_weelist_item *item; + item = weechat_list_casesearch(profile->ignores, id); + + if (weechat_strcasecmp(argv[1], "add") == 0) + { + WEECHAT_COMMAND_MIN_ARGS(3, "add"); + if (!item) + { + weechat_list_add(profile->ignores, id, WEECHAT_LIST_POS_END, NULL); + weechat_printf(profile->buffer, + "%sID '%s' has been added to the ignore list", + weechat_prefix("action"), id); + twc_name_prefix_in_groupchats(profile, id, "-", "yellow"); + } + else + weechat_printf(profile->buffer, + "%sID '%s' is already in the ignore list", + weechat_prefix("error"), id); + return WEECHAT_RC_OK; + } + + /* delete ignore */ + if (weechat_strcasecmp(argv[1], "del") == 0) + { + WEECHAT_COMMAND_MIN_ARGS(3, "del"); + if (item) + { + weechat_list_remove(profile->ignores, item); + weechat_printf(profile->buffer, + "%sID '%s' has been deleted from the ignore list", + weechat_prefix("action"), id); + twc_name_prefix_in_groupchats(profile, id, " ", "default"); + } + else + weechat_printf(profile->buffer, + "%sthere's no ID '%s' in the ignore list", + weechat_prefix("error"), id); + return WEECHAT_RC_OK; + } + return WEECHAT_RC_ERROR; +} /** * Register Tox-WeeChat commands. @@ -1519,4 +1615,16 @@ twc_commands_init() "%(filename)" " || %(tox_friend_name)|%(tox_friend_tox_id) %(filename)", twc_cmd_send, NULL, NULL); + weechat_hook_command("ignore", + "ommit messages from people with certain Tox IDs", + "list" + " || add " + " || del ", + "list: show the list of ignores\n" + "add: add an ID to the list\n" + "del: delete an ID from the list\n", + "list" + " || add %*" + " || del %*", + twc_cmd_ignore, NULL, NULL); } diff --git a/src/twc-config.c b/src/twc-config.c index 2854026..f823f0e 100644 --- a/src/twc-config.c +++ b/src/twc-config.c @@ -35,6 +35,7 @@ struct t_config_file *twc_config_file = NULL; struct t_config_section *twc_config_section_look = NULL; struct t_config_section *twc_config_section_profile = NULL; struct t_config_section *twc_config_section_profile_default = NULL; +struct t_config_section *twc_config_section_ignore = NULL; struct t_config_option *twc_config_friend_request_message; struct t_config_option *twc_config_short_id_size; @@ -207,6 +208,80 @@ twc_config_profile_change_callback(const void *pointer, void *data, } } +/* + * Reads ignore option from configuration file. + * + * Returns: + * 1: OK + * 0: error + */ +int +twc_config_ignore_read_callback(const void *pointer, void *data, + struct t_config_file *config_file, + struct t_config_section *section, + const char *option_name, const char *value) +{ + /* make C compiler happy */ + (void)pointer; + (void)data; + (void)config_file; + (void)section; + if (option_name) + { + char *profile_name = strrchr(option_name, '.'); + if (profile_name) + { + profile_name = strndup(option_name, + (profile_name - option_name) / sizeof(char)); + struct t_twc_profile *profile = + twc_profile_search_name(profile_name); + if (profile) + { + weechat_list_add(profile->ignores, value, WEECHAT_LIST_POS_END, + NULL); + } + free(profile_name); + } + } + return 1; +} + +/* + * Writes ignore section in tox configuration file. + */ +int +twc_config_ignore_write_callback(const void *pointer, void *data, + struct t_config_file *config_file, + const char *section_name) +{ + /* make C compiler happy */ + (void)pointer; + (void)data; + + if (!weechat_config_write_line(config_file, section_name, NULL)) + return WEECHAT_CONFIG_WRITE_ERROR; + + struct t_twc_list_item *item; + size_t index; + twc_list_foreach (twc_profiles, index, item) + { + size_t option_name_len = + strlen(item->profile->name) + strlen(".ignore") + 1; + char option_name[option_name_len]; + snprintf(option_name, option_name_len - 1, "%s.ignore", + item->profile->name); + struct t_weelist_item *ignore_item; + for (ignore_item = weechat_list_get(item->profile->ignores, 0); + ignore_item; ignore_item = weechat_list_next(ignore_item)) + { + if (!weechat_config_write_line(config_file, option_name, + weechat_list_string(ignore_item))) + return WEECHAT_CONFIG_WRITE_ERROR; + } + } + return WEECHAT_CONFIG_WRITE_OK; +} + /** * Create a new option for a profile. Returns NULL if an error occurs. */ @@ -351,6 +426,12 @@ twc_config_init() twc_config_file, "profile_default", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + twc_config_section_ignore = weechat_config_new_section( + twc_config_file, "ignore", 0, 0, twc_config_ignore_read_callback, NULL, + NULL, twc_config_ignore_write_callback, NULL, NULL, + twc_config_ignore_write_callback, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL); + for (int i = 0; i < TWC_PROFILE_NUM_OPTIONS; ++i) { twc_config_profile_default[i] = diff --git a/src/twc-profile.c b/src/twc-profile.c index 7936794..f460033 100644 --- a/src/twc-profile.c +++ b/src/twc-profile.c @@ -166,6 +166,7 @@ twc_profile_new(const char *name) profile->tox_online = false; profile->chats = twc_list_new(); + profile->ignores = weechat_list_new(); profile->friend_requests = twc_list_new(); profile->group_chat_invites = twc_list_new(); profile->message_queues = weechat_hashtable_new( @@ -247,10 +248,10 @@ twc_tox_new_print_error(struct t_twc_profile *profile, weechat_prefix("error"), options->proxy_host); break; case TOX_ERR_NEW_PROXY_BAD_PORT: - weechat_printf(profile->buffer, - "%scould not load Tox (invalid proxy port: \"%" - PRIu16 "\")", - weechat_prefix("error"), options->proxy_port); + weechat_printf( + profile->buffer, + "%scould not load Tox (invalid proxy port: \"%" PRIu16 "\")", + weechat_prefix("error"), options->proxy_port); break; case TOX_ERR_NEW_PROXY_NOT_FOUND: weechat_printf( @@ -698,6 +699,8 @@ twc_profile_free(struct t_twc_profile *profile) /* free things */ twc_chat_free_list(profile->chats); + weechat_list_remove_all(profile->ignores); + weechat_list_free(profile->ignores); twc_friend_request_free_list(profile->friend_requests); twc_group_chat_invite_free_list(profile->group_chat_invites); twc_tfer_free(profile->tfer); diff --git a/src/twc-profile.h b/src/twc-profile.h index eca37f5..baeb1d2 100644 --- a/src/twc-profile.h +++ b/src/twc-profile.h @@ -59,6 +59,7 @@ struct t_twc_profile struct t_hook *tox_do_timer; struct t_twc_list *chats; + struct t_weelist *ignores; struct t_twc_list *friend_requests; struct t_twc_list *group_chat_invites; struct t_hashtable *message_queues; diff --git a/src/twc-tox-callbacks.c b/src/twc-tox-callbacks.c index be1b0b4..918fe42 100644 --- a/src/twc-tox-callbacks.c +++ b/src/twc-tox-callbacks.c @@ -408,13 +408,18 @@ twc_handle_group_message(Tox *tox, int32_t group_number, int32_t peer_number, bool rc; struct t_twc_profile *profile = data; + char *short_id = + twc_get_peer_id_short(profile->tox, group_number, peer_number); + if (twc_is_id_ignored(profile, short_id)) + { + free(short_id); + return; + } struct t_twc_chat *chat = twc_chat_search_group(profile, group_number, true); char *myname = twc_get_self_name_nt(profile->tox); char *name = twc_get_peer_name_nt(profile->tox, group_number, peer_number); - char *short_id = - twc_get_peer_id_short(profile->tox, group_number, peer_number); char *full_name = twc_get_peer_name_prefixed(short_id, name); char *tags = "notify_message"; char *message_nt = twc_null_terminate(message, length); @@ -526,6 +531,12 @@ twc_group_peer_list_changed_callback(Tox *tox, uint32_t group_number, char *full_name = twc_get_peer_name_prefixed(short_id, name); weechat_nicklist_add_nick(chat->buffer, chat->nicklist_group, full_name, NULL, NULL, NULL, 1); + nick = weechat_nicklist_search_nick( + chat->buffer, chat->nicklist_group, full_name); + bool ignored = twc_is_id_ignored(profile, short_id); + twc_chat_update_prefix_by_nick(chat->buffer, nick, + ignored ? "-" : " ", + ignored ? "yellow" : "default"); weechat_printf( chat->buffer, "%s%s just joined the group chat", weechat_prefix("join"), @@ -602,12 +613,6 @@ twc_group_peer_name_callback(Tox *tox, uint32_t group_number, nick = weechat_nicklist_search_nick(chat->buffer, chat->nicklist_group, prev_full_name); weechat_nicklist_remove_nick(chat->buffer, nick); - if (!twc_get_peer_name_count(chat->nicks, prev_name)) - { - nick = weechat_nicklist_search_nick(chat->buffer, chat->nicklist_group, - prev_name); - weechat_nicklist_remove_nick(chat->buffer, nick); - } err = TOX_ERR_CONFERENCE_PEER_QUERY_OK; rc = tox_conference_peer_number_is_ours(tox, group_number, peer_number, @@ -620,9 +625,11 @@ twc_group_peer_name_callback(Tox *tox, uint32_t group_number, weechat_list_set(n, name); weechat_nicklist_add_nick(chat->buffer, chat->nicklist_group, full_name, NULL, NULL, NULL, 1); - weechat_nicklist_add_nick(chat->buffer, chat->nicklist_group, name, NULL, - NULL, NULL, 0); - + bool ignored = twc_is_id_ignored(profile, short_id); + nick = weechat_nicklist_search_nick(chat->buffer, chat->nicklist_group, full_name); + twc_chat_update_prefix_by_nick(chat->buffer, nick, + ignored ? "-" : " ", + ignored ? "yellow" : "default"); free(prev_full_name); free(full_name); free(name); diff --git a/src/twc-utils.c b/src/twc-utils.c index 74276bb..fa8990c 100644 --- a/src/twc-utils.c +++ b/src/twc-utils.c @@ -276,6 +276,23 @@ twc_get_next_completion(struct t_weelist *completion_list, return comp; } +/** + * Checks if an ID is ignored. + */ +bool +twc_is_id_ignored(struct t_twc_profile *profile, const char *short_id) +{ + struct t_weelist_item *ignore_item; + for (ignore_item = weechat_list_get(profile->ignores, 0); ignore_item; + ignore_item = weechat_list_next(ignore_item)) + { + if (!weechat_strncasecmp(short_id, weechat_list_string(ignore_item), + strlen(weechat_list_string(ignore_item)))) + return true; + } + return false; +} + /** * reverse the bytes of a 32-bit integer. */ diff --git a/src/twc-utils.h b/src/twc-utils.h index 6b641f7..377683f 100644 --- a/src/twc-utils.h +++ b/src/twc-utils.h @@ -21,10 +21,11 @@ #define TOX_WEECHAT_UTILS_H #include - #include #include +#include "twc-profile.h" + void twc_hex2bin(const char *hex, size_t size, uint8_t *out); @@ -73,6 +74,8 @@ twc_starts_with(struct t_weelist *list, const char *search, const char * twc_get_next_completion(struct t_weelist *completion_list, const char *prev_comp); +bool +twc_is_id_ignored(struct t_twc_profile *profile, const char *short_id); uint32_t twc_uint32_reverse_bytes(uint32_t num); From dd8f1f58a84e37f924a5861676456a3ca5afb0e7 Mon Sep 17 00:00:00 2001 From: nogaems Date: Tue, 2 Apr 2019 14:22:56 +0300 Subject: [PATCH 3/3] improve: circumvention of the short ID collisions Even though it's a pretty rare case to happen, it's still possible to occure that there are two+ peers in a group chat with the same first 2 bytes of the ID. Since we're using 2 (that means 4 character length) as a minimal possible value for the shortened ID form, I've changed the ignore list storage in the way that you can now store as many bytes as you want regardless of the option `tox.look.short_id_size`. If the ID collision happens, you can increase the value of that option and you don't have to change your ignore list. --- src/twc-chat.c | 10 +++++++--- src/twc-commands.c | 2 +- src/twc-tox-callbacks.c | 11 ++++++----- src/twc-utils.c | 11 ++++++----- src/twc-utils.h | 3 ++- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/twc-chat.c b/src/twc-chat.c index 657a71d..4da921e 100644 --- a/src/twc-chat.c +++ b/src/twc-chat.c @@ -24,6 +24,7 @@ #include #include +#include "twc-config.h" #include "twc-list.h" #include "twc-message-queue.h" #include "twc-profile.h" @@ -297,10 +298,13 @@ twc_chat_update_prefix(struct t_twc_chat *chat, const char *id, { const char *name_field = weechat_nicklist_nick_get_string( chat->buffer, ptr_nick, "name"); - if (!weechat_strncasecmp(id, name_field + sizeof(char), strlen(id))) + size_t short_id_length = + weechat_config_integer(twc_config_short_id_size); + if (!weechat_strncasecmp(id, name_field + sizeof(char), + short_id_length)) { - weechat_nicklist_nick_set(chat->buffer, ptr_nick, - "prefix", prefix); + weechat_nicklist_nick_set(chat->buffer, ptr_nick, "prefix", + prefix); weechat_nicklist_nick_set(chat->buffer, ptr_nick, "prefix_color", prefix_color); weechat_nicklist_nick_set(chat->buffer, ptr_nick, "color", diff --git a/src/twc-commands.c b/src/twc-commands.c index 44ed2c3..5ad92d4 100644 --- a/src/twc-commands.c +++ b/src/twc-commands.c @@ -1437,7 +1437,7 @@ twc_cmd_ignore(const void *pointer, void *data, struct t_gui_buffer *buffer, const char *id = argv_eol[2]; struct t_weelist_item *item; - item = weechat_list_casesearch(profile->ignores, id); + item = twc_is_id_ignored(profile, id); if (weechat_strcasecmp(argv[1], "add") == 0) { diff --git a/src/twc-tox-callbacks.c b/src/twc-tox-callbacks.c index 918fe42..b1af588 100644 --- a/src/twc-tox-callbacks.c +++ b/src/twc-tox-callbacks.c @@ -533,7 +533,8 @@ twc_group_peer_list_changed_callback(Tox *tox, uint32_t group_number, full_name, NULL, NULL, NULL, 1); nick = weechat_nicklist_search_nick( chat->buffer, chat->nicklist_group, full_name); - bool ignored = twc_is_id_ignored(profile, short_id); + struct t_weelist_item *ignored = + twc_is_id_ignored(profile, short_id); twc_chat_update_prefix_by_nick(chat->buffer, nick, ignored ? "-" : " ", ignored ? "yellow" : "default"); @@ -625,10 +626,10 @@ twc_group_peer_name_callback(Tox *tox, uint32_t group_number, weechat_list_set(n, name); weechat_nicklist_add_nick(chat->buffer, chat->nicklist_group, full_name, NULL, NULL, NULL, 1); - bool ignored = twc_is_id_ignored(profile, short_id); - nick = weechat_nicklist_search_nick(chat->buffer, chat->nicklist_group, full_name); - twc_chat_update_prefix_by_nick(chat->buffer, nick, - ignored ? "-" : " ", + struct t_weelist_item *ignored = twc_is_id_ignored(profile, short_id); + nick = weechat_nicklist_search_nick(chat->buffer, chat->nicklist_group, + full_name); + twc_chat_update_prefix_by_nick(chat->buffer, nick, ignored ? "-" : " ", ignored ? "yellow" : "default"); free(prev_full_name); free(full_name); diff --git a/src/twc-utils.c b/src/twc-utils.c index fa8990c..97d4293 100644 --- a/src/twc-utils.c +++ b/src/twc-utils.c @@ -277,9 +277,10 @@ twc_get_next_completion(struct t_weelist *completion_list, } /** - * Checks if an ID is ignored. + * Checks if an ID is ignored. Returns the item from the ignore list if so, NULL + * otherwise. */ -bool +struct t_weelist_item * twc_is_id_ignored(struct t_twc_profile *profile, const char *short_id) { struct t_weelist_item *ignore_item; @@ -287,10 +288,10 @@ twc_is_id_ignored(struct t_twc_profile *profile, const char *short_id) ignore_item = weechat_list_next(ignore_item)) { if (!weechat_strncasecmp(short_id, weechat_list_string(ignore_item), - strlen(weechat_list_string(ignore_item)))) - return true; + strlen(short_id))) + return ignore_item; } - return false; + return NULL; } /** diff --git a/src/twc-utils.h b/src/twc-utils.h index 377683f..18baa0e 100644 --- a/src/twc-utils.h +++ b/src/twc-utils.h @@ -74,7 +74,8 @@ twc_starts_with(struct t_weelist *list, const char *search, const char * twc_get_next_completion(struct t_weelist *completion_list, const char *prev_comp); -bool + +struct t_weelist_item * twc_is_id_ignored(struct t_twc_profile *profile, const char *short_id); uint32_t