diff options
Diffstat (limited to 'src/irc/notifylist')
-rw-r--r-- | src/irc/notifylist/Makefile.am | 15 | ||||
-rw-r--r-- | src/irc/notifylist/module.h | 44 | ||||
-rw-r--r-- | src/irc/notifylist/notify-commands.c | 81 | ||||
-rw-r--r-- | src/irc/notifylist/notify-ison.c | 354 | ||||
-rw-r--r-- | src/irc/notifylist/notify-setup.c | 84 | ||||
-rw-r--r-- | src/irc/notifylist/notify-setup.h | 9 | ||||
-rw-r--r-- | src/irc/notifylist/notify-whois.c | 186 | ||||
-rw-r--r-- | src/irc/notifylist/notifylist.c | 356 | ||||
-rw-r--r-- | src/irc/notifylist/notifylist.h | 32 |
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 |