summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTimo Sirainen <cras@irssi.org>2001-02-17 21:46:35 +0000
committercras <cras@dbcabf3a-b0e7-0310-adc4-f8d773084564>2001-02-17 21:46:35 +0000
commit0d4d9204a96b017981d0a8c1ea8af753741dfbec (patch)
tree0f1a332fcb152845a12d53892ba441c78264f47f /src
parentbe6ba53fa47bc546279a2575523281845fe80da9 (diff)
downloadirssi-0d4d9204a96b017981d0a8c1ea8af753741dfbec.zip
Support for multiple identically named nicks.
git-svn-id: http://svn.irssi.org/repos/irssi/trunk@1238 dbcabf3a-b0e7-0310-adc4-f8d773084564
Diffstat (limited to 'src')
-rw-r--r--src/core/nick-rec.h4
-rw-r--r--src/core/nicklist.c167
-rw-r--r--src/core/nicklist.h7
3 files changed, 158 insertions, 20 deletions
diff --git a/src/core/nick-rec.h b/src/core/nick-rec.h
index e9817e0c..7dff6f32 100644
--- a/src/core/nick-rec.h
+++ b/src/core/nick-rec.h
@@ -21,3 +21,7 @@ unsigned int halfop:1;
unsigned int voice:1;
GHashTable *module_data;
+
+void *unique_id; /* unique ID to use for comparing if one nick is in another channels,
+ or NULL = nicks are unique, just keep comparing them. */
+NICK_REC *next; /* support for multiple identically named nicks */
diff --git a/src/core/nicklist.c b/src/core/nicklist.c
index fab66154..ee9aee0d 100644
--- a/src/core/nicklist.c
+++ b/src/core/nicklist.c
@@ -30,6 +30,41 @@
#define isalnumhigh(a) \
(isalnum(a) || (unsigned char) (a) >= 128)
+static void nick_hash_add(CHANNEL_REC *channel, NICK_REC *nick)
+{
+ NICK_REC *list;
+
+ list = g_hash_table_lookup(channel->nicks, nick->nick);
+ if (list == NULL)
+ g_hash_table_insert(channel->nicks, nick->nick, nick);
+ else {
+ /* multiple nicks with same name */
+ while (list->next != NULL)
+ list = list->next;
+ list->next = nick;
+ }
+}
+
+static void nick_hash_remove(CHANNEL_REC *channel, NICK_REC *nick)
+{
+ NICK_REC *list;
+
+ list = g_hash_table_lookup(channel->nicks, nick->nick);
+ if (list == NULL)
+ return;
+
+ if (list->next == NULL)
+ g_hash_table_remove(channel->nicks, nick->nick);
+ else if (list == nick) {
+ g_hash_table_insert(channel->nicks, nick->nick,
+ nick->next);
+ } else {
+ while (list->next != nick)
+ list = list->next;
+ list->next = nick->next;
+ }
+}
+
/* Add new nick to list */
void nicklist_insert(CHANNEL_REC *channel, NICK_REC *nick)
{
@@ -38,7 +73,7 @@ void nicklist_insert(CHANNEL_REC *channel, NICK_REC *nick)
nick->type = module_get_uniq_id("NICK", 0);
nick->chat_type = channel->chat_type;
- g_hash_table_insert(channel->nicks, nick->nick, nick);
+ nick_hash_add(channel, nick);
signal_emit("nicklist new", 2, channel, nick);
}
@@ -71,37 +106,49 @@ void nicklist_remove(CHANNEL_REC *channel, NICK_REC *nick)
g_return_if_fail(IS_CHANNEL(channel));
g_return_if_fail(nick != NULL);
- g_hash_table_remove(channel->nicks, nick->nick);
+ nick_hash_remove(channel, nick);
nicklist_destroy(channel, nick);
}
-/* Change nick */
-void nicklist_rename(SERVER_REC *server, const char *old_nick,
- const char *new_nick)
+static void nicklist_rename_list(SERVER_REC *server, const char *old_nick,
+ const char *new_nick, GSList *nicks)
{
CHANNEL_REC *channel;
NICK_REC *nickrec;
- GSList *nicks, *tmp;
+ GSList *tmp;
- nicks = nicklist_get_same(server, old_nick);
for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
channel = tmp->data;
nickrec = tmp->next->data;
/* remove old nick from hash table */
- g_hash_table_remove(channel->nicks, nickrec->nick);
+ nick_hash_remove(channel, nickrec);
g_free(nickrec->nick);
nickrec->nick = g_strdup(new_nick);
/* add new nick to hash table */
- g_hash_table_insert(channel->nicks, nickrec->nick, nickrec);
+ nick_hash_add(channel, nickrec);
signal_emit("nicklist changed", 3, channel, nickrec, old_nick);
}
g_slist_free(nicks);
}
+void nicklist_rename(SERVER_REC *server, const char *old_nick,
+ const char *new_nick)
+{
+ return nicklist_rename_list(server, 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)
+{
+ return nicklist_rename_list(server, old_nick, new_nick,
+ nicklist_get_same_unique(server, old_nick_id));
+}
+
static NICK_REC *nicklist_find_wildcards(CHANNEL_REC *channel,
const char *mask)
{
@@ -150,6 +197,21 @@ NICK_REC *nicklist_find(CHANNEL_REC *channel, const char *nick)
return g_hash_table_lookup(channel->nicks, nick);
}
+NICK_REC *nicklist_find_unique(CHANNEL_REC *channel, const char *nick,
+ void *id)
+{
+ NICK_REC *rec;
+
+ g_return_val_if_fail(IS_CHANNEL(channel), NULL);
+ g_return_val_if_fail(nick != NULL, NULL);
+
+ rec = g_hash_table_lookup(channel->nicks, nick);
+ while (rec != NULL && rec->unique_id != id)
+ rec = rec->next;
+
+ return rec;
+}
+
/* Find nick mask, wildcards allowed */
NICK_REC *nicklist_find_mask(CHANNEL_REC *channel, const char *mask)
{
@@ -170,10 +232,13 @@ NICK_REC *nicklist_find_mask(CHANNEL_REC *channel, const char *mask)
nickrec = g_hash_table_lookup(channel->nicks, nick);
- if (nickrec != NULL && host != NULL &&
- (nickrec->host == NULL || !match_wildcards(host, nickrec->host))) {
- /* hosts didn't match */
- nickrec = NULL;
+ if (host != NULL) {
+ while (nickrec != NULL) {
+ if (nickrec->host != NULL &&
+ match_wildcards(host, nickrec->host))
+ break; /* match */
+ nickrec = nickrec->next;
+ }
}
g_free(nick);
return nickrec;
@@ -181,7 +246,10 @@ NICK_REC *nicklist_find_mask(CHANNEL_REC *channel, const char *mask)
static void get_nicks_hash(gpointer key, NICK_REC *rec, GSList **list)
{
- *list = g_slist_append(*list, rec);
+ while (rec != NULL) {
+ *list = g_slist_append(*list, rec);
+ rec = rec->next;
+ }
}
/* Get list of nicks */
@@ -228,6 +296,40 @@ GSList *nicklist_get_same(SERVER_REC *server, const char *nick)
return rec.list;
}
+typedef struct {
+ CHANNEL_REC *channel;
+ void *id;
+ GSList *list;
+} NICKLIST_GET_SAME_UNIQUE_REC;
+
+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);
+ }
+}
+
+GSList *nicklist_get_same_unique(SERVER_REC *server, void *id)
+{
+ NICKLIST_GET_SAME_UNIQUE_REC rec;
+ GSList *tmp;
+
+ g_return_val_if_fail(IS_SERVER(server), NULL);
+ g_return_val_if_fail(id != NULL, NULL);
+
+ rec.id = id;
+ rec.list = NULL;
+ for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
+ rec.channel = tmp->data;
+ g_hash_table_foreach(rec.channel->nicks,
+ (GHFunc) get_nicks_same_hash_unique,
+ &rec);
+ }
+ return rec.list;
+}
+
/* nick record comparision for sort functions */
int nicklist_compare(NICK_REC *p1, NICK_REC *p2)
{
@@ -245,17 +347,15 @@ int nicklist_compare(NICK_REC *p1, NICK_REC *p2)
return g_strcasecmp(p1->nick, p2->nick);
}
-void nicklist_update_flags(SERVER_REC *server, const char *nick,
- int gone, int serverop)
+static void nicklist_update_flags_list(SERVER_REC *server, int gone,
+ int serverop, GSList *nicks)
{
- GSList *nicks, *tmp;
+ GSList *tmp;
CHANNEL_REC *channel;
NICK_REC *rec;
g_return_if_fail(IS_SERVER(server));
- g_return_if_fail(nick != NULL);
- nicks = nicklist_get_same(server, nick);
for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
channel = tmp->data;
rec = tmp->next->data;
@@ -275,6 +375,20 @@ void nicklist_update_flags(SERVER_REC *server, const char *nick,
g_slist_free(nicks);
}
+void nicklist_update_flags(SERVER_REC *server, const char *nick,
+ int gone, int serverop)
+{
+ return nicklist_update_flags_list(server, gone, serverop,
+ nicklist_get_same(server, nick));
+}
+
+void nicklist_update_flags_unique(SERVER_REC *server, void *id,
+ int gone, int serverop)
+{
+ return nicklist_update_flags_list(server, gone, serverop,
+ nicklist_get_same_unique(server, id));
+}
+
static void sig_channel_created(CHANNEL_REC *channel)
{
g_return_if_fail(IS_CHANNEL(channel));
@@ -286,7 +400,13 @@ static void sig_channel_created(CHANNEL_REC *channel)
static void nicklist_remove_hash(gpointer key, NICK_REC *nick,
CHANNEL_REC *channel)
{
- nicklist_destroy(channel, nick);
+ NICK_REC *next;
+
+ while (nick != NULL) {
+ next = nick->next;
+ nicklist_destroy(channel, nick);
+ nick = next;
+ }
}
static void sig_channel_destroyed(CHANNEL_REC *channel)
@@ -305,6 +425,13 @@ static NICK_REC *nick_nfind(CHANNEL_REC *channel, const char *nick, int len)
tmpnick = g_strndup(nick, len);
rec = g_hash_table_lookup(channel->nicks, tmpnick);
+
+ /* if there's multiple, get the one with identical case */
+ while (rec->next != NULL) {
+ if (strcmp(rec->nick, tmpnick) == 0)
+ break;
+ }
+
g_free(tmpnick);
return rec;
}
diff --git a/src/core/nicklist.h b/src/core/nicklist.h
index 2c47562d..c0dfa65b 100644
--- a/src/core/nicklist.h
+++ b/src/core/nicklist.h
@@ -21,9 +21,13 @@ 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);
/* Find nick */
NICK_REC *nicklist_find(CHANNEL_REC *channel, const char *nick);
+NICK_REC *nicklist_find_unique(CHANNEL_REC *channel, const char *nick,
+ void *id);
/* Find nick mask, wildcards allowed */
NICK_REC *nicklist_find_mask(CHANNEL_REC *channel, const char *mask);
/* Get list of nicks that match the mask */
@@ -32,10 +36,13 @@ GSList *nicklist_find_multiple(CHANNEL_REC *channel, const char *mask);
GSList *nicklist_getnicks(CHANNEL_REC *channel);
/* Get all the nick records of `nick'. Returns channel, nick, channel, ... */
GSList *nicklist_get_same(SERVER_REC *server, const char *nick);
+GSList *nicklist_get_same_unique(SERVER_REC *server, void *id);
/* Update specified nick's status in server. */
void nicklist_update_flags(SERVER_REC *server, const char *nick,
int gone, int ircop);
+void nicklist_update_flags_unique(SERVER_REC *server, void *id,
+ int gone, int ircop);
/* Nick record comparision for sort functions */
int nicklist_compare(NICK_REC *p1, NICK_REC *p2);