summaryrefslogtreecommitdiffstats
path: root/src/irc/notifylist/notify-ison.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/irc/notifylist/notify-ison.c')
-rw-r--r--src/irc/notifylist/notify-ison.c348
1 files changed, 348 insertions, 0 deletions
diff --git a/src/irc/notifylist/notify-ison.c b/src/irc/notifylist/notify-ison.c
new file mode 100644
index 0000000..809394c
--- /dev/null
+++ b/src/irc/notifylist/notify-ison.c
@@ -0,0 +1,348 @@
+/*
+ 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/misc.h>
+#include <irssi/src/core/settings.h>
+
+#include <irssi/src/irc/core/irc.h>
+#include <irssi/src/irc/core/irc-servers.h>
+#include <irssi/src/irc/core/servers-redirect.h>
+
+#include <irssi/src/irc/notifylist/notifylist.h>
+
+#define DEFAULT_NOTIFY_CHECK_TIME "1min"
+#define DEFAULT_NOTIFY_WHOIS_TIME "5min"
+
+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_ascii_strcasecmp(rec->nick, nick) == 0)
+ return rec;
+ }
+
+ return NULL;
+}
+
+static void ison_send(IRC_SERVER_REC *server, GString *cmd)
+{
+ MODULE_SERVER_REC *mserver;
+
+ if (!server->connected) {
+ return;
+ }
+
+ mserver = MODULE_DATA(server);
+ mserver->ison_count++;
+
+ g_string_truncate(cmd, cmd->len-1);
+ g_string_prepend(cmd, "ISON :");
+
+ server_redirect_event(server, "ison", 1, NULL, -1, NULL,
+ "event 303", "notifylist event", NULL);
+ irc_send_cmd_later(server, cmd->str);
+
+ 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)
+{
+ MODULE_SERVER_REC *mserver;
+ GSList *tmp;
+ GString *cmd;
+ char *nick, *ptr;
+ int len;
+
+ g_return_if_fail(server != NULL);
+
+ if (!IS_IRC_SERVER(server))
+ return;
+
+ mserver = MODULE_DATA(server);
+ if (mserver->ison_count > 0) {
+ /* 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 (!notifylist_ircnets_match(rec, server->connrec->chatnet))
+ continue;
+
+ nick = g_strdup(rec->mask);
+ ptr = strchr(nick, '!');
+ if (ptr != NULL) *ptr = '\0';
+
+ len = strlen(nick);
+
+ if (cmd->len+len+1 > server->max_message_len)
+ ison_send(server, cmd);
+
+ g_string_append_printf(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, const char *nicks,
+ const char *whois_request)
+{
+ char *p, *str;
+
+ /* "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, "whois", 1, str, TRUE,
+ "notifylist event whois end",
+ "event 318", "notifylist event whois end",
+ "event 311", "notifylist event whois",
+ "event 301", "notifylist event whois away",
+ "", "event empty", NULL);
+ g_free(str);
+
+ str = g_strdup_printf("WHOIS %s", whois_request);
+ irc_send_cmd_later(server, str);
+ 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, nick, 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_append_printf(str, "%s,", nick);
+
+ if (count >= server->max_whois_in_cmd) {
+ g_string_truncate(str, str->len-1);
+ whois_send(server, str->str, str->str);
+ g_string_truncate(str, 0);
+ count = 0;
+ }
+ }
+
+ if (str->len > 0) {
+ g_string_truncate(str, str->len-1);
+ whois_send(server, str->str, 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->chatnet);
+ send_whois = notify != NULL && notify->away_check;
+
+ 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 -
+ 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 (i_slist_find_icase_string(mserver->ison_tempusers, rec->nick) != NULL)
+ continue;
+
+ notifylist_left(server, rec);
+ }
+}
+
+static void event_ison(IRC_SERVER_REC *server, const char *data)
+{
+ 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 (--mserver->ison_count > 0) {
+ /* 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(settings_get_time("notify_check_time"),
+ (GSourceFunc) notifylist_timeout_func, NULL);
+
+ notify_whois_time = settings_get_time("notify_whois_time")/1000;
+}
+
+void notifylist_ison_init(void)
+{
+ settings_add_time("misc", "notify_check_time", DEFAULT_NOTIFY_CHECK_TIME);
+ settings_add_time("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);
+}