diff --git a/src/core/nicklist.c b/src/core/nicklist.c index c5b5aaac..387394aa 100644 --- a/src/core/nicklist.c +++ b/src/core/nicklist.c @@ -34,6 +34,8 @@ static void nick_hash_add(CHANNEL_REC *channel, NICK_REC *nick) { NICK_REC *list; + nick->next = NULL; + list = g_hash_table_lookup(channel->nicks, nick->nick); if (list == NULL) g_hash_table_insert(channel->nicks, nick->nick, nick); @@ -41,7 +43,12 @@ static void nick_hash_add(CHANNEL_REC *channel, NICK_REC *nick) /* multiple nicks with same name */ while (list->next != NULL) list = list->next; - list->next = nick; + list->next = nick; + } + + if (nick == channel->ownnick) { + /* move our own nick to beginning of the nick list.. */ + nicklist_set_own(channel, nick); } } @@ -110,8 +117,9 @@ void nicklist_remove(CHANNEL_REC *channel, NICK_REC *nick) nicklist_destroy(channel, nick); } -static void nicklist_rename_list(SERVER_REC *server, const char *old_nick, - const char *new_nick, GSList *nicks) +static void nicklist_rename_list(SERVER_REC *server, void *new_nick_id, + const char *old_nick, const char *new_nick, + GSList *nicks) { CHANNEL_REC *channel; NICK_REC *nickrec; @@ -124,6 +132,9 @@ static void nicklist_rename_list(SERVER_REC *server, const char *old_nick, /* remove old nick from hash table */ nick_hash_remove(channel, nickrec); + if (new_nick_id != NULL) + nickrec->unique_id = new_nick_id; + g_free(nickrec->nick); nickrec->nick = g_strdup(new_nick); @@ -138,14 +149,15 @@ static void nicklist_rename_list(SERVER_REC *server, const char *old_nick, void nicklist_rename(SERVER_REC *server, const char *old_nick, const char *new_nick) { - nicklist_rename_list(server, old_nick, new_nick, + nicklist_rename_list(server, NULL, old_nick, new_nick, nicklist_get_same(server, old_nick)); } -void nicklist_rename_unique(SERVER_REC *server, void *old_nick_id, - const char *old_nick, const char *new_nick) +void nicklist_rename_unique(SERVER_REC *server, + void *old_nick_id, const char *old_nick, + void *new_nick_id, const char *new_nick) { - nicklist_rename_list(server, old_nick, new_nick, + nicklist_rename_list(server, new_nick_id, old_nick, new_nick, nicklist_get_same_unique(server, old_nick_id)); } @@ -273,9 +285,13 @@ typedef struct { static void get_nicks_same_hash(gpointer key, NICK_REC *nick, NICKLIST_GET_SAME_REC *rec) { - if (g_strcasecmp(nick->nick, rec->nick) == 0) { - rec->list = g_slist_append(rec->list, rec->channel); - rec->list = g_slist_append(rec->list, nick); + while (nick != NULL) { + if (g_strcasecmp(nick->nick, rec->nick) == 0) { + rec->list = g_slist_append(rec->list, rec->channel); + rec->list = g_slist_append(rec->list, nick); + } + + nick = nick->next; } } @@ -305,9 +321,14 @@ typedef struct { static void get_nicks_same_hash_unique(gpointer key, NICK_REC *nick, NICKLIST_GET_SAME_UNIQUE_REC *rec) { - if (nick->unique_id == rec->id) { - rec->list = g_slist_append(rec->list, rec->channel); - rec->list = g_slist_append(rec->list, nick); + while (nick != NULL) { + if (nick->unique_id == rec->id) { + rec->list = g_slist_append(rec->list, rec->channel); + rec->list = g_slist_append(rec->list, nick); + break; + } + + nick = nick->next; } } @@ -404,6 +425,9 @@ void nicklist_set_own(CHANNEL_REC *channel, NICK_REC *nick) next = nick->next; nick->next = first; + + while (first->next != nick) + first = first->next; first->next = next; g_hash_table_insert(channel->nicks, nick->nick, nick); diff --git a/src/core/nicklist.h b/src/core/nicklist.h index eb0adecb..a9683500 100644 --- a/src/core/nicklist.h +++ b/src/core/nicklist.h @@ -21,8 +21,9 @@ void nicklist_remove(CHANNEL_REC *channel, NICK_REC *nick); /* Change nick */ void nicklist_rename(SERVER_REC *server, const char *old_nick, const char *new_nick); -void nicklist_rename_unique(SERVER_REC *server, void *old_nick_id, - const char *old_nick, const char *new_nick); +void nicklist_rename_unique(SERVER_REC *server, + void *old_nick_id, const char *old_nick, + void *new_nick_id, const char *new_nick); /* Find nick */ NICK_REC *nicklist_find(CHANNEL_REC *channel, const char *nick); diff --git a/src/core/servers.c b/src/core/servers.c index 02fda4d9..4b91f846 100644 --- a/src/core/servers.c +++ b/src/core/servers.c @@ -428,6 +428,16 @@ void server_connect_free(SERVER_CONNECT_REC *conn) g_free(conn); } +void server_change_nick(SERVER_REC *server, const char *nick) +{ + g_free(server->connrec->nick); + g_free(server->nick); + server->connrec->nick = g_strdup(nick); + server->nick = g_strdup(nick); + + signal_emit("server nick changed", 1, server); +} + /* Update own IPv4 and IPv6 records */ void server_connect_own_ip_save(SERVER_CONNECT_REC *conn, IPADDR *ip4, IPADDR *ip6) diff --git a/src/core/servers.h b/src/core/servers.h index 86b6a9e7..75e4cbf0 100644 --- a/src/core/servers.h +++ b/src/core/servers.h @@ -50,6 +50,9 @@ void server_connect_finished(SERVER_REC *server); /* connection to server failed */ void server_connect_failed(SERVER_REC *server, const char *msg); +/* Change your nick */ +void server_change_nick(SERVER_REC *server, const char *nick); + /* Update own IPv4 and IPv6 records */ void server_connect_own_ip_save(SERVER_CONNECT_REC *conn, IPADDR *ip4, IPADDR *ip6); diff --git a/src/fe-common/core/fe-messages.c b/src/fe-common/core/fe-messages.c index e8435414..fa5e88af 100644 --- a/src/fe-common/core/fe-messages.c +++ b/src/fe-common/core/fe-messages.c @@ -501,15 +501,33 @@ static void sig_message_topic(SERVER_REC *server, const char *channel, static int printnick_exists(NICK_REC *first, NICK_REC *ignore, const char *nick) { + char *printnick; + while (first != NULL) { - if (first != ignore && strcmp(first->nick, nick) == 0) - return TRUE; - first = first->next; + if (first != ignore) { + printnick = g_hash_table_lookup(printnicks, first); + if (printnick != NULL && strcmp(printnick, nick) == 0) + return TRUE; + } + + first = first->next; } return FALSE; } +static NICK_REC *printnick_find_original(NICK_REC *nick) +{ + while (nick != NULL) { + if (g_hash_table_lookup(printnicks, nick) == NULL) + return nick; + + nick = nick->next; + } + + return NULL; +} + static void sig_nicklist_new(CHANNEL_REC *channel, NICK_REC *nick) { NICK_REC *firstnick; @@ -517,13 +535,21 @@ static void sig_nicklist_new(CHANNEL_REC *channel, NICK_REC *nick) char *nickhost, *p; int n; - if (nick->host == NULL || nick == channel->ownnick) + if (nick->host == NULL) return; firstnick = g_hash_table_lookup(channel->nicks, nick->nick); if (firstnick->next == NULL) return; + if (nick == channel->ownnick) { + /* own nick is being added, might be a nick change and + someone else having the original nick already in use.. */ + nick = printnick_find_original(firstnick->next); + if (nick == NULL) + return; /* nope, we have it */ + } + /* identical nick already exists, have to change it somehow.. */ p = strchr(nick->host, '@'); if (p == NULL) p = nick->host; else p++; @@ -546,7 +572,8 @@ static void sig_nicklist_new(CHANNEL_REC *channel, NICK_REC *nick) } while (printnick_exists(firstnick, nick, newnick->str)); g_hash_table_insert(printnicks, nick, newnick->str); - g_string_free(newnick, FALSE); + g_string_free(newnick, FALSE); + g_free(nickhost); } static void sig_nicklist_remove(CHANNEL_REC *channel, NICK_REC *nick) diff --git a/src/irc/core/irc-nicklist.c b/src/irc/core/irc-nicklist.c index 9795c414..5863dcc9 100644 --- a/src/irc/core/irc-nicklist.c +++ b/src/irc/core/irc-nicklist.c @@ -300,11 +300,7 @@ static void event_nick(SERVER_REC *server, const char *data, if (g_strcasecmp(orignick, server->nick) == 0) { /* You changed your nick */ - g_free(server->connrec->nick); - g_free(server->nick); - server->connrec->nick = g_strdup(nick); - server->nick = g_strdup(nick); - signal_emit("server nick changed", 1, server); + server_change_nick(server, nick); } nicklist_rename(server, orignick, nick);