feature: nickname disambiguation

This commit is contained in:
nogaems 2019-03-18 23:20:41 +03:00
parent 80319b30cd
commit fe5589432d
No known key found for this signature in database
GPG Key ID: 91316FB98FDBB08B
8 changed files with 289 additions and 27 deletions

View File

@ -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);
}

View File

@ -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 *

View File

@ -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);

View File

@ -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);
}
/**

View File

@ -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
{

View File

@ -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);
}

View File

@ -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)

View File

@ -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);