1
0
mirror of https://github.com/irssi/irssi.git synced 2024-09-29 04:45:57 -04:00
irssi/src/irc/notifylist/notify-ison.c

343 lines
8.2 KiB
C

/*
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 "signals.h"
#include "misc.h"
#include "settings.h"
#include "irc.h"
#include "irc-servers.h"
#include "servers-redirect.h"
#include "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;
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(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 > 510)
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);
irc_send_cmdv(server, "WHOIS %s", whois_request);
}
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 (gslist_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);
}