summaryrefslogtreecommitdiff
path: root/src/core/nicklist.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/nicklist.c')
-rw-r--r--src/core/nicklist.c268
1 files changed, 268 insertions, 0 deletions
diff --git a/src/core/nicklist.c b/src/core/nicklist.c
new file mode 100644
index 00000000..1ba78f94
--- /dev/null
+++ b/src/core/nicklist.c
@@ -0,0 +1,268 @@
+/*
+ nicklist.c : irssi
+
+ Copyright (C) 1999-2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "signals.h"
+#include "misc.h"
+
+#include "nicklist.h"
+#include "masks.h"
+
+/* Add new nick to list */
+NICK_REC *nicklist_insert(CHANNEL_REC *channel, const char *nick,
+ int op, int voice, int send_massjoin)
+{
+ NICK_REC *rec;
+
+ g_return_val_if_fail(IS_CHANNEL(channel), NULL);
+ g_return_val_if_fail(nick != NULL, NULL);
+
+ rec = g_new0(NICK_REC, 1);
+
+ if (op) rec->op = TRUE;
+ if (voice) rec->voice = TRUE;
+
+ rec->send_massjoin = send_massjoin;
+ rec->nick = g_strdup(nick);
+ rec->host = NULL;
+
+ g_hash_table_insert(channel->nicks, rec->nick, rec);
+ signal_emit("nicklist new", 2, channel, rec);
+ return rec;
+}
+
+static void nicklist_destroy(CHANNEL_REC *channel, NICK_REC *nick)
+{
+ signal_emit("nicklist remove", 2, channel, nick);
+
+ g_free(nick->nick);
+ g_free_not_null(nick->realname);
+ g_free_not_null(nick->host);
+ g_free(nick);
+}
+
+/* remove nick from list */
+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);
+ nicklist_destroy(channel, nick);
+}
+
+static NICK_REC *nicklist_find_wildcards(CHANNEL_REC *channel,
+ const char *mask)
+{
+ GSList *nicks, *tmp;
+ NICK_REC *nick;
+
+ nicks = nicklist_getnicks(channel);
+ nick = NULL;
+ for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
+ nick = tmp->data;
+
+ if (mask_match_address(channel->server, mask,
+ nick->nick, nick->host))
+ break;
+ }
+ g_slist_free(nicks);
+ return tmp == NULL ? NULL : nick;
+}
+
+GSList *nicklist_find_multiple(CHANNEL_REC *channel, const char *mask)
+{
+ GSList *nicks, *tmp, *next;
+
+ g_return_val_if_fail(IS_CHANNEL(channel), NULL);
+ g_return_val_if_fail(mask != NULL, NULL);
+
+ nicks = nicklist_getnicks(channel);
+ for (tmp = nicks; tmp != NULL; tmp = next) {
+ NICK_REC *nick = tmp->data;
+
+ next = tmp->next;
+ if (!mask_match_address(channel->server, mask,
+ nick->nick, nick->host))
+ nicks = g_slist_remove(nicks, tmp->data);
+ }
+
+ return nicks;
+}
+
+/* Find nick record from list */
+NICK_REC *nicklist_find(CHANNEL_REC *channel, const char *mask)
+{
+ NICK_REC *nickrec;
+ char *nick, *host;
+
+ g_return_val_if_fail(IS_CHANNEL(channel), NULL);
+ g_return_val_if_fail(mask != NULL, NULL);
+
+ nick = g_strdup(mask);
+ host = strchr(nick, '!');
+ if (host != NULL) *host++ = '\0';
+
+ if (strchr(nick, '*') || strchr(nick, '?')) {
+ g_free(nick);
+ return nicklist_find_wildcards(channel, 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;
+ }
+ g_free(nick);
+ return nickrec;
+}
+
+static void get_nicks_hash(gpointer key, NICK_REC *rec, GSList **list)
+{
+ *list = g_slist_append(*list, rec);
+}
+
+/* Get list of nicks */
+GSList *nicklist_getnicks(CHANNEL_REC *channel)
+{
+ GSList *list;
+
+ g_return_val_if_fail(IS_CHANNEL(channel), NULL);
+
+ list = NULL;
+ g_hash_table_foreach(channel->nicks, (GHFunc) get_nicks_hash, &list);
+ return list;
+}
+
+typedef struct {
+ CHANNEL_REC *channel;
+ const char *nick;
+ GSList *list;
+} NICKLIST_GET_SAME_REC;
+
+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);
+ }
+}
+
+GSList *nicklist_get_same(SERVER_REC *server, const char *nick)
+{
+ NICKLIST_GET_SAME_REC rec;
+ GSList *tmp;
+
+ g_return_val_if_fail(IS_SERVER(server), NULL);
+
+ rec.nick = nick;
+ 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, &rec);
+ }
+ return rec.list;
+}
+
+/* nick record comparision for sort functions */
+int nicklist_compare(NICK_REC *p1, NICK_REC *p2)
+{
+ if (p1 == NULL) return -1;
+ if (p2 == NULL) return 1;
+
+ if (p1->op && !p2->op) return -1;
+ if (!p1->op && p2->op) return 1;
+
+ if (!p1->op) {
+ if (p1->voice && !p2->voice) return -1;
+ if (!p1->voice && p2->voice) return 1;
+ }
+
+ return g_strcasecmp(p1->nick, p2->nick);
+}
+
+void nicklist_update_flags(SERVER_REC *server, const char *nick,
+ int gone, int serverop)
+{
+ GSList *nicks, *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;
+
+ rec->last_check = time(NULL);
+
+ if (gone != -1 && rec->gone != gone) {
+ rec->gone = gone;
+ signal_emit("nick gone changed", 2, channel, rec);
+ }
+
+ if (serverop != -1 && rec->serverop != serverop) {
+ rec->serverop = serverop;
+ signal_emit("nick serverop changed", 2, channel, rec);
+ }
+ }
+ g_slist_free(nicks);
+}
+
+static void sig_channel_created(CHANNEL_REC *channel)
+{
+ g_return_if_fail(IS_CHANNEL(channel));
+
+ channel->nicks = g_hash_table_new((GHashFunc) g_istr_hash,
+ (GCompareFunc) g_istr_equal);
+}
+
+static void nicklist_remove_hash(gpointer key, NICK_REC *nick,
+ CHANNEL_REC *channel)
+{
+ nicklist_destroy(channel, nick);
+}
+
+static void sig_channel_destroyed(CHANNEL_REC *channel)
+{
+ g_return_if_fail(IS_CHANNEL(channel));
+
+ g_hash_table_foreach(channel->nicks,
+ (GHFunc) nicklist_remove_hash, channel);
+ g_hash_table_destroy(channel->nicks);
+}
+
+void nicklist_init(void)
+{
+ signal_add_first("channel created", (SIGNAL_FUNC) sig_channel_created);
+ signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
+}
+
+void nicklist_deinit(void)
+{
+ signal_remove("channel created", (SIGNAL_FUNC) sig_channel_created);
+ signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
+}