summaryrefslogtreecommitdiff
path: root/src/irc/notifylist
diff options
context:
space:
mode:
authorTimo Sirainen <cras@irssi.org>2000-04-26 08:03:38 +0000
committercras <cras@dbcabf3a-b0e7-0310-adc4-f8d773084564>2000-04-26 08:03:38 +0000
commitc95034c6de1bf72536595e1e3431d8ec64b9880e (patch)
treee51aa4528257ed8aa9d53640649519f299aaf0c7 /src/irc/notifylist
parentd01b094151705d433bc43cae9eeb304e6f110a17 (diff)
downloadirssi-c95034c6de1bf72536595e1e3431d8ec64b9880e.zip
..adding new files..
git-svn-id: http://svn.irssi.org/repos/irssi/trunk@171 dbcabf3a-b0e7-0310-adc4-f8d773084564
Diffstat (limited to 'src/irc/notifylist')
-rw-r--r--src/irc/notifylist/Makefile.am15
-rw-r--r--src/irc/notifylist/module.h44
-rw-r--r--src/irc/notifylist/notify-commands.c81
-rw-r--r--src/irc/notifylist/notify-ison.c354
-rw-r--r--src/irc/notifylist/notify-setup.c84
-rw-r--r--src/irc/notifylist/notify-setup.h9
-rw-r--r--src/irc/notifylist/notify-whois.c186
-rw-r--r--src/irc/notifylist/notifylist.c356
-rw-r--r--src/irc/notifylist/notifylist.h32
9 files changed, 1161 insertions, 0 deletions
diff --git a/src/irc/notifylist/Makefile.am b/src/irc/notifylist/Makefile.am
new file mode 100644
index 00000000..48dd5640
--- /dev/null
+++ b/src/irc/notifylist/Makefile.am
@@ -0,0 +1,15 @@
+noinst_LTLIBRARIES = libirc_notifylist.la
+
+INCLUDES = $(GLIB_CFLAGS) \
+ -I$(top_srcdir)/src -I$(top_srcdir)/src/core/ -I$(top_srcdir)/src/irc/core/
+
+libirc_notifylist_la_SOURCES = \
+ notifylist.c \
+ notify-commands.c \
+ notify-ison.c \
+ notify-setup.c \
+ notify-whois.c
+
+noinst_HEADERS = \
+ notifylist.h \
+ notify-setup.h
diff --git a/src/irc/notifylist/module.h b/src/irc/notifylist/module.h
new file mode 100644
index 00000000..ac0eadac
--- /dev/null
+++ b/src/irc/notifylist/module.h
@@ -0,0 +1,44 @@
+#include "common.h"
+
+#define MODULE_NAME "irc/notifylist"
+
+#define ISON_EVENT "event 303"
+
+typedef struct {
+ char *nick;
+ char *user, *host, *realname, *awaymsg;
+ time_t idle_time;
+
+ int host_ok:1; /* host matches the one in notifylist = this is the right person*/
+ int away_ok:1; /* not away, or we don't care about it */
+ int idle_ok:1; /* idle time is low enough, or we don't care about it */
+
+ int away:1; /* nick is away */
+ int join_announced:1; /* join to IRC has been announced */
+ int idle_changed:1; /* idle time is lower than in last check */
+
+ time_t last_whois;
+} NOTIFY_NICK_REC;
+
+typedef struct {
+ GSList *notify_users; /* NOTIFY_NICK_REC's of notifylist people who are in IRC */
+ GSList *ison_tempusers; /* Temporary list for saving /ISON events.. */
+} MODULE_SERVER_REC;
+
+#include "irc-server.h"
+
+NOTIFY_NICK_REC *notify_nick_create(IRC_SERVER_REC *server, const char *nick);
+void notify_nick_destroy(NOTIFY_NICK_REC *rec);
+NOTIFY_NICK_REC *notify_nick_find(IRC_SERVER_REC *server, const char *nick);
+
+void notifylist_left(IRC_SERVER_REC *server, NOTIFY_NICK_REC *rec);
+void notifylist_destroy_all(void);
+
+void notifylist_commands_init(void);
+void notifylist_commands_deinit(void);
+
+void notifylist_whois_init(void);
+void notifylist_whois_deinit(void);
+
+void notifylist_ison_init(void);
+void notifylist_ison_deinit(void);
diff --git a/src/irc/notifylist/notify-commands.c b/src/irc/notifylist/notify-commands.c
new file mode 100644
index 00000000..9ae5a076
--- /dev/null
+++ b/src/irc/notifylist/notify-commands.c
@@ -0,0 +1,81 @@
+/*
+ notify-commands.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 "commands.h"
+#include "misc.h"
+#include "settings.h"
+
+#include "notifylist.h"
+
+#define DEFAULT_NOTIFY_IDLE_TIME 60
+
+static void cmd_notify(gchar *data)
+{
+ char *params, *mask, *ircnets, *args, *idletime;
+ int away_check, idle_check_time;
+
+ g_return_if_fail(data != NULL);
+
+ args = "@idle";
+ params = cmd_get_params(data, 4 | PARAM_FLAG_MULTIARGS | PARAM_FLAG_GETREST, &args, &idletime, &mask, &ircnets);
+ if (*mask == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ if (stristr(args, "-idle") == NULL)
+ idle_check_time = 0;
+ else {
+ idle_check_time = is_numeric(idletime, 0) ? (atol(idletime)*60) :
+ (settings_get_int("notify_idle_time")*60);
+ }
+
+ away_check = stristr(args, "-away") != NULL;
+ notifylist_remove(mask);
+ notifylist_add(mask, ircnets, away_check, idle_check_time);
+
+ g_free(params);
+}
+
+static void cmd_unnotify(const char *data)
+{
+ char *params, *mask;
+
+ g_return_if_fail(data != NULL);
+
+ params = cmd_get_params(data, 1, &mask);
+ if (*mask == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ notifylist_remove(mask);
+
+ g_free(params);
+}
+
+void notifylist_commands_init(void)
+{
+ settings_add_int("misc", "notify_idle_time", DEFAULT_NOTIFY_IDLE_TIME);
+ command_bind("notify", NULL, (SIGNAL_FUNC) cmd_notify);
+ command_bind("unnotify", NULL, (SIGNAL_FUNC) cmd_unnotify);
+}
+
+void notifylist_commands_deinit(void)
+{
+ command_unbind("notify", (SIGNAL_FUNC) cmd_notify);
+ command_unbind("unnotify", (SIGNAL_FUNC) cmd_unnotify);
+}
diff --git a/src/irc/notifylist/notify-ison.c b/src/irc/notifylist/notify-ison.c
new file mode 100644
index 00000000..46aaa3b6
--- /dev/null
+++ b/src/irc/notifylist/notify-ison.c
@@ -0,0 +1,354 @@
+/*
+ notify-ison.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 "settings.h"
+
+#include "irc.h"
+#include "irc-server.h"
+#include "server-redirect.h"
+
+#include "notifylist.h"
+
+#define DEFAULT_NOTIFY_CHECK_TIME 60
+#define DEFAULT_NOTIFY_WHOIS_TIME (60*5)
+
+typedef struct {
+ char *nick;
+ int hostok;
+} ISON_REC;
+
+static int notify_tag;
+static int notify_whois_time;
+
+NOTIFY_NICK_REC *notify_nick_create(IRC_SERVER_REC *server, const char *nick)
+{
+ MODULE_SERVER_REC *mserver;
+ NOTIFY_NICK_REC *rec;
+
+ mserver = MODULE_DATA(server);
+
+ rec = g_new0(NOTIFY_NICK_REC, 1);
+ rec->nick = g_strdup(nick);
+
+ mserver->notify_users = g_slist_append(mserver->notify_users, rec);
+ return rec;
+}
+
+void notify_nick_destroy(NOTIFY_NICK_REC *rec)
+{
+ g_free(rec->nick);
+ g_free_not_null(rec->user);
+ g_free_not_null(rec->host);
+ g_free_not_null(rec->realname);
+ g_free_not_null(rec->awaymsg);
+ g_free(rec);
+}
+
+NOTIFY_NICK_REC *notify_nick_find(IRC_SERVER_REC *server, const char *nick)
+{
+ MODULE_SERVER_REC *mserver;
+ NOTIFY_NICK_REC *rec;
+ GSList *tmp;
+
+ mserver = MODULE_DATA(server);
+ for (tmp = mserver->notify_users; tmp != NULL; tmp = tmp->next) {
+ rec = tmp->data;
+
+ if (g_strcasecmp(rec->nick, nick) == 0)
+ return rec;
+ }
+
+ return NULL;
+}
+
+static int is_ison_queue_empty(IRC_SERVER_REC *server)
+{
+ GSList *tmp;
+
+ tmp = server_redirect_getqueue((SERVER_REC *) server, ISON_EVENT, NULL);
+ for (; tmp != NULL; tmp = tmp->next) {
+ REDIRECT_REC *rec = tmp->data;
+
+ if (strcmp(rec->name, "notifylist event") == 0)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void ison_send(IRC_SERVER_REC *server, GString *cmd)
+{
+ g_string_truncate(cmd, cmd->len-1);
+ g_string_prepend(cmd, "ISON :");
+
+ irc_send_cmd(server, cmd->str);
+ server_redirect_event((SERVER_REC *) server, NULL, 1, ISON_EVENT, "notifylist event", -1, NULL);
+
+ g_string_truncate(cmd, 0);
+}
+
+/* timeout function: send /ISON commands to server to check if someone in
+ notify list is in IRC */
+static void notifylist_timeout_server(IRC_SERVER_REC *server)
+{
+ GSList *tmp;
+ GString *cmd;
+ char *nick, *ptr;
+ int len;
+
+ g_return_if_fail(server != NULL);
+
+ if (!is_ison_queue_empty(server)) {
+ /* still not received all replies to previous /ISON commands.. */
+ return;
+ }
+
+ cmd = g_string_new(NULL);
+ for (tmp = notifies; tmp != NULL; tmp = tmp->next) {
+ NOTIFYLIST_REC *rec = tmp->data;
+
+ if (!notify_ircnets_match(rec, server->connrec->ircnet))
+ continue;
+
+ nick = g_strdup(rec->mask);
+ ptr = strchr(nick, '!');
+ if (ptr != NULL) *ptr = '\0';
+
+ len = strlen(nick);
+
+ if (cmd->len+len+1 > 510)
+ ison_send(server, cmd);
+
+ g_string_sprintfa(cmd, "%s ", nick);
+ g_free(nick);
+ }
+
+ if (cmd->len > 0)
+ ison_send(server, cmd);
+ g_string_free(cmd, TRUE);
+}
+
+static int notifylist_timeout_func(void)
+{
+ g_slist_foreach(servers, (GFunc) notifylist_timeout_server, NULL);
+ return 1;
+}
+
+static void ison_save_users(MODULE_SERVER_REC *mserver, char *online)
+{
+ char *ptr;
+
+ while (online != NULL && *online != '\0') {
+ ptr = strchr(online, ' ');
+ if (ptr != NULL) *ptr++ = '\0';
+
+ mserver->ison_tempusers =
+ g_slist_append(mserver->ison_tempusers, g_strdup(online));
+ online = ptr;
+ }
+}
+
+static void whois_send(IRC_SERVER_REC *server, char *nicks)
+{
+ char *p, *str;
+
+ irc_send_cmdv(server, "WHOIS %s", nicks);
+
+ /* "nick1,nick2" -> "nick1,nick2 nick1 nick2" because
+ End of WHOIS give nick1,nick2 while other whois events give
+ nick1 or nick2 */
+ str = g_strconcat(nicks, " ", nicks, NULL);
+ for (p = str+strlen(nicks)+1; *p != '\0'; p++)
+ if (*p == ',') *p = ' ';
+
+ server_redirect_event((SERVER_REC *) server, str, 2,
+ "event 318", "notifylist event whois end", 1,
+ "event 402", "event empty", -1,
+ "event 401", "event empty", 1,
+ "event 311", "notifylist event whois", 1,
+ "event 301", "notifylist event whois away", 1,
+ "event 312", "event empty", 1,
+ "event 313", "event empty", 1,
+ "event 317", "notifylist event whois idle", 1,
+ "event 319", "event empty", 1, NULL);
+ g_free(str);
+}
+
+static void whois_send_server(IRC_SERVER_REC *server, char *nick)
+{
+ char *str;
+
+ str = g_strdup_printf("%s %s", nick, nick);
+ whois_send(server, str);
+ g_free(str);
+}
+
+/* try to send as many nicks in one WHOIS as possible */
+static void whois_list_send(IRC_SERVER_REC *server, GSList *nicks)
+{
+ GSList *tmp;
+ GString *str;
+ char *nick;
+ int count;
+
+ str = g_string_new(NULL);
+ count = 0;
+
+ for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
+ nick = tmp->data;
+
+ count++;
+ g_string_sprintfa(str, "%s,", nick);
+
+ if (count >= server->max_whois_in_cmd) {
+ g_string_truncate(str, str->len-1);
+ whois_send(server, str->str);
+ count = 0;
+ }
+ }
+
+ if (str->len > 0) {
+ g_string_truncate(str, str->len-1);
+ whois_send(server, str->str);
+ }
+
+ g_string_free(str, TRUE);
+}
+
+static void ison_check_joins(IRC_SERVER_REC *server)
+{
+ MODULE_SERVER_REC *mserver;
+ NOTIFYLIST_REC *notify;
+ NOTIFY_NICK_REC *rec;
+ GSList *tmp, *newnicks;
+ int send_whois;
+ time_t now;
+
+ mserver = MODULE_DATA(server);
+
+ now = time(NULL);
+ newnicks = NULL;
+ for (tmp = mserver->ison_tempusers; tmp != NULL; tmp = tmp->next) {
+ char *nick = tmp->data;
+
+ notify = notifylist_find(nick, server->connrec->ircnet);
+ send_whois = notify != NULL &&
+ (notify->away_check || notify->idle_check_time > 0);
+
+ rec = notify_nick_find(server, nick);
+ if (rec != NULL) {
+ /* check if we want to send WHOIS yet.. */
+ if (now-rec->last_whois < notify_whois_time)
+ continue;
+ } else {
+ rec = notify_nick_create(server, nick);
+ if (!send_whois) newnicks = g_slist_append(newnicks, nick);
+ }
+
+ if (send_whois) {
+ /* we need away message or idle time -
+ send the WHOIS reply to the nick's server */
+ rec->last_whois = now;
+ whois_send_server(server, nick);
+ }
+ }
+
+ whois_list_send(server, newnicks);
+ g_slist_free(newnicks);
+}
+
+static void ison_check_parts(IRC_SERVER_REC *server)
+{
+ MODULE_SERVER_REC *mserver;
+ GSList *tmp, *next;
+
+ mserver = MODULE_DATA(server);
+ for (tmp = mserver->notify_users; tmp != NULL; tmp = next) {
+ NOTIFY_NICK_REC *rec = tmp->data;
+ next = tmp->next;
+
+ if (gslist_find_icase_string(mserver->ison_tempusers, rec->nick) != NULL)
+ continue;
+
+ notifylist_left(server, rec);
+ notify_nick_destroy(rec);
+ }
+}
+
+static void event_ison(const char *data, IRC_SERVER_REC *server)
+{
+ MODULE_SERVER_REC *mserver;
+ char *params, *online;
+
+ g_return_if_fail(data != NULL);
+ g_return_if_fail(server != NULL);
+
+ params = event_get_params(data, 2, NULL, &online);
+
+ mserver = MODULE_DATA(server);
+ ison_save_users(mserver, online);
+
+ if (!is_ison_queue_empty(server)) {
+ /* wait for the rest of the /ISON replies */
+ g_free(params);
+ return;
+ }
+
+ ison_check_joins(server);
+ ison_check_parts(server);
+
+ /* free memory used by temp list */
+ g_slist_foreach(mserver->ison_tempusers, (GFunc) g_free, NULL);
+ g_slist_free(mserver->ison_tempusers);
+ mserver->ison_tempusers = NULL;
+
+ g_free(params);
+}
+
+static void read_settings(void)
+{
+ if (notify_tag != -1) g_source_remove(notify_tag);
+ notify_tag = g_timeout_add(1000*settings_get_int("notify_check_time"), (GSourceFunc) notifylist_timeout_func, NULL);
+
+ notify_whois_time = settings_get_int("notify_whois_time");
+}
+
+void notifylist_ison_init(void)
+{
+ settings_add_int("misc", "notify_check_time", DEFAULT_NOTIFY_CHECK_TIME);
+ settings_add_int("misc", "notify_whois_time", DEFAULT_NOTIFY_WHOIS_TIME);
+
+ notify_tag = -1;
+ read_settings();
+
+ signal_add("notifylist event", (SIGNAL_FUNC) event_ison);
+ signal_add("setup changed", (SIGNAL_FUNC) read_settings);
+}
+
+void notifylist_ison_deinit(void)
+{
+ g_source_remove(notify_tag);
+
+ signal_remove("notifylist event", (SIGNAL_FUNC) event_ison);
+ signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
+}
diff --git a/src/irc/notifylist/notify-setup.c b/src/irc/notifylist/notify-setup.c
new file mode 100644
index 00000000..6ecbfa27
--- /dev/null
+++ b/src/irc/notifylist/notify-setup.c
@@ -0,0 +1,84 @@
+/*
+ notify-setup.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 "lib-config/iconfig.h"
+#include "settings.h"
+
+#include "irc-server.h"
+#include "notifylist.h"
+
+void notifylist_add_config(NOTIFYLIST_REC *rec)
+{
+ CONFIG_NODE *node;
+
+ node = iconfig_node_traverse("notifies", TRUE);
+ node = config_node_section(node, rec->mask, NODE_TYPE_BLOCK);
+
+ if (rec->away_check)
+ config_node_set_bool(node, "away_check", TRUE);
+ else
+ config_node_set_str(node, "away_check", NULL);
+
+ if (rec->idle_check_time > 0)
+ config_node_set_int(node, "idle_check_time", rec->idle_check_time/60);
+ else
+ config_node_set_str(node, "idle_check_time", NULL);
+
+ config_node_set_str(node, "ircnets", NULL);
+ if (rec->ircnets != NULL && *rec->ircnets != NULL) {
+ node = config_node_section(node, "ircnets", NODE_TYPE_LIST);
+ config_node_add_list(node, rec->ircnets);
+ }
+}
+
+void notifylist_remove_config(NOTIFYLIST_REC *rec)
+{
+ iconfig_set_str("notifies", rec->mask, NULL);
+}
+
+void notifylist_read_config(void)
+{
+ CONFIG_NODE *node;
+ NOTIFYLIST_REC *rec;
+ GSList *tmp;
+
+ notifylist_destroy_all();
+
+ node = iconfig_node_traverse("notifies", FALSE);
+ if (node == NULL) return;
+
+ for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
+ node = tmp->data;
+
+ if (node->type != NODE_TYPE_BLOCK)
+ continue;
+
+ rec = g_new0(NOTIFYLIST_REC, 1);
+ notifies = g_slist_append(notifies, rec);
+
+ rec->mask = g_strdup(node->key);
+ rec->away_check = config_node_get_bool(node, "away_check", FALSE);
+ rec->idle_check_time = config_node_get_int(node, "idle_check_time", 0)*60;
+
+ node = config_node_section(node, "ircnets", -1);
+ if (node != NULL) rec->ircnets = config_node_get_list(node);
+ }
+}
diff --git a/src/irc/notifylist/notify-setup.h b/src/irc/notifylist/notify-setup.h
new file mode 100644
index 00000000..bfaef0c8
--- /dev/null
+++ b/src/irc/notifylist/notify-setup.h
@@ -0,0 +1,9 @@
+#ifndef __NOTIFY_SETUP_H
+#define __NOTIFY_SETUP_H
+
+void notifylist_add_config(NOTIFYLIST_REC *rec);
+void notifylist_remove_config(NOTIFYLIST_REC *rec);
+
+void notifylist_read_config(void);
+
+#endif
diff --git a/src/irc/notifylist/notify-whois.c b/src/irc/notifylist/notify-whois.c
new file mode 100644
index 00000000..439a8af8
--- /dev/null
+++ b/src/irc/notifylist/notify-whois.c
@@ -0,0 +1,186 @@
+/*
+ notify-whois.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 "special-vars.h"
+
+#include "irc.h"
+#include "irc-server.h"
+#include "masks.h"
+
+#include "notifylist.h"
+
+static char *last_notify_nick;
+
+static void event_whois(const char *data, IRC_SERVER_REC *server)
+{
+ char *params, *nick, *user, *host, *realname;
+ NOTIFY_NICK_REC *nickrec;
+ NOTIFYLIST_REC *notify;
+
+ g_return_if_fail(data != NULL);
+ g_return_if_fail(server != NULL);
+
+ params = event_get_params(data, 6, NULL, &nick, &user, &host, NULL, &realname);
+
+ notify = notifylist_find(nick, server->connrec->ircnet);
+ if (notify != NULL && !irc_mask_match(notify->mask, nick, user, host)) {
+ /* user or host didn't match */
+ g_free(params);
+ return;
+ }
+
+ nickrec = notify_nick_find(server, nick);
+ if (nickrec != NULL) {
+ g_free_not_null(last_notify_nick);
+ last_notify_nick = g_strdup(nick);
+
+ g_free_not_null(nickrec->user);
+ g_free_not_null(nickrec->host);
+ g_free_not_null(nickrec->realname);
+ g_free_and_null(nickrec->awaymsg);
+ nickrec->user = g_strdup(user);
+ nickrec->host = g_strdup(host);
+ nickrec->realname = g_strdup(realname);
+
+ nickrec->away = FALSE;
+ nickrec->host_ok = TRUE;
+ nickrec->idle_ok = TRUE;
+ }
+ g_free(params);
+}
+
+static void event_whois_idle(const char *data, IRC_SERVER_REC *server)
+{
+ NOTIFY_NICK_REC *nickrec;
+ NOTIFYLIST_REC *notify;
+ char *params, *nick, *secstr;
+ long secs;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3, NULL, &nick, &secstr);
+ secs = atol(secstr);
+
+ notify = notifylist_find(nick, server->connrec->ircnet);
+ nickrec = notify_nick_find(server, nick);
+ if (notify != NULL && nickrec != NULL) {
+ time_t now = time(NULL);
+ nickrec->idle_changed = secs < now-nickrec->idle_time &&
+ now-nickrec->idle_time > notify->idle_check_time;
+
+ nickrec->idle_time = now-secs;
+ }
+
+ g_free(params);
+}
+
+static void event_whois_away(const char *data, IRC_SERVER_REC *server)
+{
+ NOTIFY_NICK_REC *nickrec;
+ char *params, *nick, *awaymsg;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3, NULL, &nick, &awaymsg);
+
+ nickrec = notify_nick_find(server, nick);
+ if (nickrec != NULL) {
+ nickrec->awaymsg = g_strdup(awaymsg);
+ nickrec->away = TRUE;
+ }
+
+ g_free(params);
+}
+
+/* All WHOIS replies got, now announce all the changes at once. */
+static void event_whois_end(const char *data, IRC_SERVER_REC *server)
+{
+ MODULE_SERVER_REC *mserver;
+ NOTIFYLIST_REC *notify;
+ NOTIFY_NICK_REC *rec;
+ GSList *tmp;
+ const char *event;
+ int away_ok;
+ time_t now;
+
+ now = time(NULL);
+ mserver = MODULE_DATA(server);
+ for (tmp = mserver->notify_users; tmp != NULL; tmp = tmp->next) {
+ rec = tmp->data;
+
+ if (rec->realname == NULL)
+ continue;
+
+ notify = notifylist_find(rec->nick, server->connrec->ircnet);
+ if (notify == NULL) continue;
+
+ away_ok = !notify->away_check || !rec->away;
+
+ event = NULL;
+ if (!rec->join_announced) {
+ rec->join_announced = TRUE;
+ rec->idle_time = now;
+ if (away_ok) event = "notifylist joined";
+ } else if (notify->away_check && rec->away_ok == rec->away)
+ event = "notifylist away changed";
+ else if (notify->idle_check_time > 0 && rec->idle_changed)
+ event = "notifylist unidle";
+
+ if (event != NULL) {
+ signal_emit(event, 6, server, rec->nick,
+ rec->user, rec->host,
+ rec->realname, rec->awaymsg);
+ }
+ rec->idle_ok = notify->idle_check_time <= 0 ||
+ now-rec->idle_time <= notify->idle_check_time;
+ rec->idle_changed = FALSE;
+ rec->away_ok = away_ok;
+ }
+}
+
+/* last person that NOTIFY detected a signon for */
+static char *expando_lastnotify(void *server, void *item, int *free_ret)
+{
+ return last_notify_nick;
+}
+
+void notifylist_whois_init(void)
+{
+ last_notify_nick = NULL;
+
+ signal_add("notifylist event whois", (SIGNAL_FUNC) event_whois);
+ signal_add("notifylist event whois away", (SIGNAL_FUNC) event_whois_away);
+ signal_add("notifylist event whois idle", (SIGNAL_FUNC) event_whois_idle);
+ signal_add("notifylist event whois end", (SIGNAL_FUNC) event_whois_end);
+ expando_create("D", expando_lastnotify);
+}
+
+void notifylist_whois_deinit(void)
+{
+ g_free_not_null(last_notify_nick);
+
+ signal_remove("notifylist event whois", (SIGNAL_FUNC) event_whois);
+ signal_remove("notifylist event whois away", (SIGNAL_FUNC) event_whois_away);
+ signal_remove("notifylist event whois idle", (SIGNAL_FUNC) event_whois_idle);
+ signal_remove("notifylist event whois end", (SIGNAL_FUNC) event_whois_end);
+ expando_destroy("D", expando_lastnotify);
+}
diff --git a/src/irc/notifylist/notifylist.c b/src/irc/notifylist/notifylist.c
new file mode 100644
index 00000000..00561dc9
--- /dev/null
+++ b/src/irc/notifylist/notifylist.c
@@ -0,0 +1,356 @@
+/*
+ notifylist.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 "modules.h"
+#include "signals.h"
+
+#include "irc.h"
+#include "irc-server.h"
+#include "server-redirect.h"
+#include "masks.h"
+#include "nicklist.h"
+
+#include "notifylist.h"
+#include "notify-setup.h"
+
+GSList *notifies;
+
+NOTIFYLIST_REC *notifylist_add(const char *mask, const char *ircnets,
+ int away_check, int idle_check_time)
+{
+ NOTIFYLIST_REC *rec;
+
+ g_return_val_if_fail(mask != NULL, NULL);
+
+ rec = g_new0(NOTIFYLIST_REC, 1);
+ rec->mask = g_strdup(mask);
+ rec->ircnets = ircnets == NULL || *ircnets == '\0' ? NULL :
+ g_strsplit(ircnets, " ", -1);
+ rec->away_check = away_check;
+ rec->idle_check_time = idle_check_time;
+
+ notifylist_add_config(rec);
+
+ notifies = g_slist_append(notifies, rec);
+ signal_emit("notifylist new", 1, rec);
+ return rec;
+}
+
+static void notify_destroy(NOTIFYLIST_REC *rec)
+{
+ if (rec->ircnets != NULL) g_strfreev(rec->ircnets);
+ g_free(rec->mask);
+ g_free(rec);
+}
+
+void notifylist_destroy_all(void)
+{
+ g_slist_foreach(notifies, (GFunc) notify_destroy, NULL);
+ g_slist_free(notifies);
+
+ notifies = NULL;
+}
+
+void notifylist_remove(const char *mask)
+{
+ NOTIFYLIST_REC *rec;
+
+ g_return_if_fail(mask != NULL);
+
+ rec = notifylist_find(mask, "*");
+ if (rec == NULL) return;
+
+ notifylist_remove_config(rec);
+ notifies = g_slist_remove(notifies, rec);
+ signal_emit("notifylist remove", 1, rec);
+
+ notify_destroy(rec);
+}
+
+int notify_ircnets_match(NOTIFYLIST_REC *rec, const char *ircnet)
+{
+ char **tmp;
+
+ if (rec->ircnets == NULL) return TRUE;
+ if (ircnet == NULL) return FALSE;
+ if (strcmp(ircnet, "*") == 0) return TRUE;
+
+ for (tmp = rec->ircnets; *tmp != NULL; tmp++) {
+ if (g_strcasecmp(*tmp, ircnet) == 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+NOTIFYLIST_REC *notifylist_find(const char *mask, const char *ircnet)
+{
+ NOTIFYLIST_REC *best;
+ GSList *tmp;
+ int len;
+
+ best = NULL;
+ len = strlen(mask);
+ for (tmp = notifies; tmp != NULL; tmp = tmp->next) {
+ NOTIFYLIST_REC *rec = tmp->data;
+
+ /* check mask */
+ if (g_strncasecmp(rec->mask, mask, len) != 0 ||
+ (rec->mask[len] != '\0' && rec->mask[len] != '!')) continue;
+
+ /* check ircnet */
+ if (rec->ircnets == NULL) {
+ best = rec;
+ continue;
+ }
+
+ if (notify_ircnets_match(rec, ircnet))
+ return rec;
+ }
+
+ return best;
+}
+
+int notifylist_ison_server(IRC_SERVER_REC *server, const char *nick)
+{
+ NOTIFY_NICK_REC *rec;
+
+ g_return_val_if_fail(nick != NULL, FALSE);
+ g_return_val_if_fail(server != NULL, FALSE);
+
+ rec = notify_nick_find(server, nick);
+ return rec != NULL && rec->host_ok && rec->away_ok && rec->idle_ok;
+}
+
+static IRC_SERVER_REC *notifylist_ison_serverlist(const char *nick, const char *taglist)
+{
+ IRC_SERVER_REC *server;
+ char **list, **tmp;
+
+ list = g_strsplit(taglist, " ", -1);
+
+ server = NULL;
+ for (tmp = list; *tmp != NULL; tmp++) {
+ server = (IRC_SERVER_REC *) server_find_ircnet(*tmp);
+
+ if (server != NULL && notifylist_ison_server(server, nick))
+ break;
+ }
+ g_strfreev(list);
+
+ return tmp == NULL ? NULL : server;
+}
+
+IRC_SERVER_REC *notifylist_ison(const char *nick, const char *serverlist)
+{
+ GSList *tmp;
+
+ g_return_val_if_fail(nick != NULL, FALSE);
+ g_return_val_if_fail(serverlist != NULL, FALSE);
+
+ if (*serverlist != '\0')
+ return notifylist_ison_serverlist(nick, serverlist);
+
+ /* any server.. */
+ for (tmp = servers; tmp != NULL; tmp = tmp->next) {
+ if (notifylist_ison_server(tmp->data, nick))
+ return tmp->data;
+ }
+
+ return NULL;
+}
+
+static void notifylist_init_server(IRC_SERVER_REC *server)
+{
+ MODULE_SERVER_REC *rec;
+
+ g_return_if_fail(server != NULL);
+
+ rec = g_new0(MODULE_SERVER_REC,1 );
+ MODULE_DATA_SET(server, rec);
+
+ server_redirect_init((SERVER_REC *) server, "command ison", 1, ISON_EVENT, NULL);
+}
+
+static void notifylist_deinit_server(IRC_SERVER_REC *server)
+{
+ MODULE_SERVER_REC *mserver;
+ NOTIFY_NICK_REC *rec;
+
+ g_return_if_fail(server != NULL);
+
+ mserver = MODULE_DATA(server);
+ while (mserver->notify_users != NULL) {
+ rec = mserver->notify_users->data;
+
+ mserver->notify_users = g_slist_remove(mserver->notify_users, rec);
+ notify_nick_destroy(rec);
+ }
+ g_free(mserver);
+}
+
+void notifylist_left(IRC_SERVER_REC *server, NOTIFY_NICK_REC *rec)
+{
+ MODULE_SERVER_REC *mserver;
+
+ mserver = MODULE_DATA(server);
+ mserver->notify_users = g_slist_remove(mserver->notify_users, rec);
+
+ if (rec->host_ok && rec->away_ok) {
+ signal_emit("notifylist left", 6,
+ server, rec->nick,
+ rec->user, rec->host,
+ rec->realname, rec->awaymsg);
+ }
+}
+
+static void notifylist_idle_reset(IRC_SERVER_REC *server, const char *nick)
+{
+ NOTIFY_NICK_REC *rec;
+ NOTIFYLIST_REC *notify;
+
+ notify = notifylist_find(nick, server->connrec->ircnet);
+ rec = notify_nick_find(server, nick);
+
+ if (notify != NULL && rec != NULL && notify->idle_check_time > 0 &&
+ time(NULL)-rec->idle_time > notify->idle_check_time) {
+ rec->idle_time = time(NULL);
+ signal_emit("notifylist unidle", 6,
+ server, rec->nick,
+ rec->user, rec->host,
+ rec->realname, rec->awaymsg);
+ }
+}
+
+static void event_quit(const char *data, IRC_SERVER_REC *server, const char *nick)
+{
+ NOTIFY_NICK_REC *rec;
+
+ if (*data == ':') data++; /* quit message */
+
+ rec = notify_nick_find(server, nick);
+ if (rec != NULL) notifylist_left(server, rec);
+}
+
+static void notifylist_check_join(IRC_SERVER_REC *server, const char *nick,
+ const char *userhost, const char *realname, int away)
+{
+ NOTIFYLIST_REC *notify;
+ NOTIFY_NICK_REC *rec;
+ char *user, *host;
+
+ notify = notifylist_find(nick, server->connrec->ircnet);
+ if (notify == NULL) return;
+
+ rec = notify_nick_find(server, nick);
+ if (rec != NULL && rec->join_announced) return;
+ if (rec == NULL) rec = notify_nick_create(server, nick);
+
+ user = g_strdup(userhost);
+ host = strchr(user, '@');
+ if (host != NULL) *host++ = '\0'; else host = "";
+
+ if (!irc_mask_match(notify->mask, nick, user, host)) {
+ g_free(user);
+ return;
+ }
+
+ if (notify->away_check && away == -1) {
+ /* we need to know if the nick is away */
+ g_free(user);
+ return;
+ }
+
+ g_free_not_null(rec->user);
+ g_free_not_null(rec->host);
+ g_free_not_null(rec->realname);
+ rec->user = g_strdup(user);
+ rec->host = g_strdup(host);
+ rec->realname = *realname == '\0' ? NULL : g_strdup(realname);
+
+ if (away != -1) rec->away = away;
+ rec->host_ok = TRUE;
+ rec->join_announced = TRUE;
+ rec->idle_time = time(NULL);
+
+ signal_emit("notifylist joined", 6,
+ server, rec->nick, rec->user, rec->host, realname, NULL);
+ g_free(user);
+}
+
+static void event_privmsg(const char *data, IRC_SERVER_REC *server, const char *nick, const char *address)
+{
+ if (nick != NULL) {
+ notifylist_check_join(server, nick, address, "", -1);
+ notifylist_idle_reset(server, nick);
+ }
+}
+
+static void event_join(const char *data, IRC_SERVER_REC *server, const char *nick, const char *address)
+{
+ notifylist_check_join(server, nick, address, "", -1);
+}
+
+static void sig_channel_wholist(CHANNEL_REC *channel)
+{
+ GSList *nicks, *tmp;
+
+ nicks = nicklist_getnicks(channel);
+ for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
+ NICK_REC *rec = tmp->data;
+
+ notifylist_check_join(channel->server, rec->nick, rec->host, rec->realname, rec->gone);
+ }
+ g_slist_free(nicks);
+}
+
+void notifylist_init(void)
+{
+ notifylist_read_config();
+
+ notifylist_commands_init();
+ notifylist_ison_init();
+ notifylist_whois_init();
+ signal_add("server connected", (SIGNAL_FUNC) notifylist_init_server);
+ signal_add("server disconnected", (SIGNAL_FUNC) notifylist_deinit_server);
+ signal_add("event quit", (SIGNAL_FUNC) event_quit);
+ signal_add("event privmsg", (SIGNAL_FUNC) event_privmsg);
+ signal_add("event join", (SIGNAL_FUNC) event_join);
+ signal_add("channel wholist", (SIGNAL_FUNC) sig_channel_wholist);
+ signal_add("setup reread", (SIGNAL_FUNC) notifylist_read_config);
+}
+
+void notifylist_deinit(void)
+{
+ notifylist_commands_deinit();
+ notifylist_ison_deinit();
+ notifylist_whois_deinit();
+
+ signal_remove("server connected", (SIGNAL_FUNC) notifylist_init_server);
+ signal_remove("server disconnected", (SIGNAL_FUNC) notifylist_deinit_server);
+ signal_remove("event quit", (SIGNAL_FUNC) event_quit);
+ signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg);
+ signal_remove("event join", (SIGNAL_FUNC) event_join);
+ signal_remove("channel wholist", (SIGNAL_FUNC) sig_channel_wholist);
+ signal_remove("setup reread", (SIGNAL_FUNC) notifylist_read_config);
+
+ notifylist_destroy_all();
+}
diff --git a/src/irc/notifylist/notifylist.h b/src/irc/notifylist/notifylist.h
new file mode 100644
index 00000000..0d4f3739
--- /dev/null
+++ b/src/irc/notifylist/notifylist.h
@@ -0,0 +1,32 @@
+#ifndef __NOTIFYLIST_H
+#define __NOTIFYLIST_H
+
+typedef struct {
+ char *mask; /* nick part must not contain wildcards */
+ char **ircnets; /* if non-NULL, check only from these irc networks */
+
+ /* notify when AWAY status changes (uses /USERHOST) */
+ int away_check:1;
+ /* notify when idle time is reset and it was bigger than this
+ (uses /WHOIS and PRIVMSG events) */
+ int idle_check_time;
+} NOTIFYLIST_REC;
+
+extern GSList *notifies;
+
+void notifylist_init(void);
+void notifylist_deinit(void);
+
+NOTIFYLIST_REC *notifylist_add(const char *mask, const char *ircnets,
+ int away_check, int idle_check_time);
+void notifylist_remove(const char *mask);
+
+IRC_SERVER_REC *notifylist_ison(const char *nick, const char *serverlist);
+int notifylist_ison_server(IRC_SERVER_REC *server, const char *nick);
+
+/* If `ircnet' is "*", it doesn't matter at all. */
+NOTIFYLIST_REC *notifylist_find(const char *mask, const char *ircnet);
+
+int notify_ircnets_match(NOTIFYLIST_REC *rec, const char *ircnet);
+
+#endif