1
0
mirror of https://github.com/irssi/irssi.git synced 2024-12-04 14:46:39 -05:00

Moved rewritten server redirection code from core to irc. This new code

should be able to do the redirecting a lot more error-proof. Changed
lag-checking to use PINGs instead of NOTIFYs. This breaks scripts using
redirection. Hopefully this doesn't break too much things in irssi :)


git-svn-id: http://svn.irssi.org/repos/irssi/trunk@1980 dbcabf3a-b0e7-0310-adc4-f8d773084564
This commit is contained in:
Timo Sirainen 2001-11-11 18:59:19 +00:00 committed by cras
parent 712f3b383d
commit 850cf993eb
28 changed files with 911 additions and 789 deletions

View File

@ -44,7 +44,6 @@ libcore_a_SOURCES = \
rawlog.c \
servers.c \
servers-reconnect.c \
servers-redirect.c \
servers-setup.c \
settings.c \
signals.c \
@ -92,7 +91,6 @@ noinst_HEADERS = \
rawlog.h \
servers.h \
servers-reconnect.h \
servers-redirect.h \
servers-setup.h \
settings.h \
signals.h \

View File

@ -26,7 +26,6 @@
#include "window-item-def.h"
#include "servers.h"
#include "servers-redirect.h"
#include "channels.h"
#include "lib-config/iconfig.h"
@ -853,10 +852,8 @@ static void parse_command(const char *command, int expand_aliases,
}
cmd = g_strconcat("command ", newcmd, NULL);
if (server != NULL)
server_redirect_default(SERVER(server), cmd);
g_strdown(cmd);
oldcmd = current_command;
current_command = cmd+8;
if (!signal_emit(cmd, 3, args, server, item)) {

View File

@ -21,11 +21,6 @@ GIOChannel *connect_pipe[2];
int connect_tag;
int connect_pid;
/* For deciding if event should be handled internally */
GHashTable *eventtable; /* "event xxx" : GSList* of REDIRECT_RECs */
GHashTable *eventgrouptable; /* event group : GSList* of REDIRECT_RECs */
GHashTable *cmdtable; /* "command xxx" : REDIRECT_CMD_REC* */
RAWLOG_REC *rawlog;
LINEBUF_REC *buffer; /* receive buffer */
GHashTable *module_data;

View File

@ -1,359 +0,0 @@
/*
server-redirect.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 "servers.h"
#include "servers-redirect.h"
static int redirect_group;
static void server_eventtable_destroy(char *key, GSList *value)
{
GSList *tmp;
g_free(key);
for (tmp = value; tmp != NULL; tmp = tmp->next) {
REDIRECT_REC *rec = tmp->data;
g_free_not_null(rec->arg);
g_free(rec->name);
g_free(rec);
}
g_slist_free(value);
}
static void server_eventgrouptable_destroy(gpointer key, GSList *value)
{
g_slist_foreach(value, (GFunc) g_free, NULL);
g_slist_free(value);
}
static void server_cmdtable_destroy(char *key, REDIRECT_CMD_REC *value)
{
g_free(key);
g_slist_foreach(value->events, (GFunc) g_free, NULL);
g_slist_free(value->events);
g_free(value);
}
static void sig_disconnected(SERVER_REC *server)
{
g_return_if_fail(IS_SERVER(server));
if (server->eventtable != NULL) {
g_hash_table_foreach(server->eventtable,
(GHFunc) server_eventtable_destroy, NULL);
g_hash_table_destroy(server->eventtable);
}
g_hash_table_foreach(server->eventgrouptable,
(GHFunc) server_eventgrouptable_destroy, NULL);
g_hash_table_destroy(server->eventgrouptable);
if (server->cmdtable != NULL) {
g_hash_table_foreach(server->cmdtable,
(GHFunc) server_cmdtable_destroy, NULL);
g_hash_table_destroy(server->cmdtable);
}
}
void server_redirect_initv(SERVER_REC *server, const char *command,
int last, GSList *list)
{
REDIRECT_CMD_REC *rec;
g_return_if_fail(IS_SERVER(server));
g_return_if_fail(command != NULL);
g_return_if_fail(last > 0);
if (g_hash_table_lookup(server->cmdtable, command) != NULL) {
/* already in hash table. list of events SHOULD be the same. */
g_slist_foreach(list, (GFunc) g_free, NULL);
g_slist_free(list);
return;
}
rec = g_new(REDIRECT_CMD_REC, 1);
rec->last = last;
rec->events = list;
g_hash_table_insert(server->cmdtable, g_strdup(command), rec);
}
void server_redirect_init(SERVER_REC *server, const char *command,
int last, ...)
{
va_list args;
GSList *list;
char *event;
va_start(args, last);
list = NULL;
while ((event = va_arg(args, gchar *)) != NULL)
list = g_slist_append(list, g_strdup(event));
va_end(args);
server_redirect_initv(server, command, last, list);
}
int server_redirect_single_event(SERVER_REC *server, const char *arg,
int last, int group, const char *event,
const char *signal, int argpos)
{
REDIRECT_REC *rec;
GSList *list, *grouplist;
char *origkey;
g_return_val_if_fail(IS_SERVER(server), 0);
g_return_val_if_fail(event != NULL, 0);
g_return_val_if_fail(signal != NULL, 0);
g_return_val_if_fail(arg != NULL || argpos == -1, 0);
if (group == 0) group = ++redirect_group;
rec = g_new0(REDIRECT_REC, 1);
rec->arg = arg == NULL ? NULL : g_strdup(arg);
rec->argpos = argpos;
rec->name = g_strdup(signal);
rec->group = group;
rec->last = last;
if (g_hash_table_lookup_extended(server->eventtable, event,
(gpointer *) &origkey,
(gpointer *) &list)) {
g_hash_table_remove(server->eventtable, origkey);
} else {
list = NULL;
origkey = g_strdup(event);
}
grouplist = g_hash_table_lookup(server->eventgrouptable,
GINT_TO_POINTER(group));
if (grouplist != NULL) {
g_hash_table_remove(server->eventgrouptable,
GINT_TO_POINTER(group));
}
list = g_slist_append(list, rec);
grouplist = g_slist_append(grouplist, g_strdup(event));
g_hash_table_insert(server->eventtable, origkey, list);
g_hash_table_insert(server->eventgrouptable,
GINT_TO_POINTER(group), grouplist);
return group;
}
void server_redirect_event(SERVER_REC *server, const char *arg, int last, ...)
{
va_list args;
char *event, *signal;
int argpos, group;
g_return_if_fail(IS_SERVER(server));
va_start(args, last);
group = 0;
while ((event = va_arg(args, gchar *)) != NULL) {
signal = va_arg(args, gchar *);
argpos = va_arg(args, gint);
group = server_redirect_single_event(server, arg, last > 0,
group, event, signal,
argpos);
last--;
}
va_end(args);
}
void server_redirect_default(SERVER_REC *server, const char *command)
{
REDIRECT_CMD_REC *cmdrec;
REDIRECT_REC *rec;
GSList *events, *list, *grouplist;
char *event, *origkey;
int last;
g_return_if_fail(IS_SERVER(server));
g_return_if_fail(command != NULL);
if (server->cmdtable == NULL)
return; /* not connected yet */
cmdrec = g_hash_table_lookup(server->cmdtable, command);
if (cmdrec == NULL) return;
/* add all events used by command to eventtable and eventgrouptable */
redirect_group++; grouplist = NULL; last = cmdrec->last;
for (events = cmdrec->events; events != NULL; events = events->next) {
event = events->data;
if (g_hash_table_lookup_extended(server->eventtable, event,
(gpointer *) &origkey,
(gpointer *) &list)) {
g_hash_table_remove(server->eventtable, origkey);
} else {
list = NULL;
origkey = g_strdup(event);
}
rec = g_new0(REDIRECT_REC, 1);
rec->argpos = -1;
rec->name = g_strdup(event);
rec->group = redirect_group;
rec->last = last > 0;
grouplist = g_slist_append(grouplist, g_strdup(event));
list = g_slist_append(list, rec);
g_hash_table_insert(server->eventtable, origkey, list);
last--;
}
g_hash_table_insert(server->eventgrouptable,
GINT_TO_POINTER(redirect_group), grouplist);
}
void server_redirect_remove_next(SERVER_REC *server, const char *event,
GSList *item)
{
REDIRECT_REC *rec;
GSList *grouplist, *list, *events, *tmp;
char *origkey;
int group;
g_return_if_fail(IS_SERVER(server));
g_return_if_fail(event != NULL);
if (!g_hash_table_lookup_extended(server->eventtable, event,
(gpointer *) &origkey,
(gpointer *) &list))
return;
rec = item == NULL ? list->data : item->data;
if (!rec->last) {
/* this wasn't last expected event */
return;
}
group = rec->group;
/* get list of events from this group */
grouplist = g_hash_table_lookup(server->eventgrouptable,
GINT_TO_POINTER(group));
/* remove all of them */
for (list = grouplist; list != NULL; list = list->next) {
char *event = list->data;
if (!g_hash_table_lookup_extended(server->eventtable, event,
(gpointer *) &origkey,
(gpointer *) &events)) {
g_warning("server_redirect_remove_next() : "
"event in eventgrouptable but not in "
"eventtable");
continue;
}
/* remove the right group */
for (tmp = events; tmp != NULL; tmp = tmp->next) {
rec = tmp->data;
if (rec->group == group)
break;
}
if (rec == NULL) {
g_warning("server_redirect_remove_next() : "
"event in eventgrouptable but not in "
"eventtable (group)");
continue;
}
g_free(event);
events = g_slist_remove(events, rec);
g_free_not_null(rec->arg);
g_free(rec->name);
g_free(rec);
/* update hash table */
g_hash_table_remove(server->eventtable, origkey);
if (events == NULL)
g_free(origkey);
else {
g_hash_table_insert(server->eventtable,
origkey, events);
}
}
g_hash_table_remove(server->eventgrouptable, GINT_TO_POINTER(group));
g_slist_free(grouplist);
}
GSList *server_redirect_getqueue(SERVER_REC *server, const char *event,
const char *args)
{
REDIRECT_REC *rec;
GSList *list;
char **arglist;
int found;
g_return_val_if_fail(IS_SERVER(server), NULL);
g_return_val_if_fail(event != NULL, NULL);
list = g_hash_table_lookup(server->eventtable, event);
for (; list != NULL; list = list->next) {
rec = list->data;
if (rec->argpos == -1)
break;
if (rec->arg == NULL || args == NULL)
continue;
/* we need to check that the argument is right.. */
arglist = g_strsplit(args, " ", -1);
found = (strarray_length(arglist) > rec->argpos &&
find_substr(rec->arg, arglist[rec->argpos]));
g_strfreev(arglist);
if (found) break;
}
return list;
}
void servers_redirect_init(void)
{
redirect_group = 0;
signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected);
}
void servers_redirect_deinit(void)
{
signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
}

View File

@ -1,36 +0,0 @@
#ifndef __SERVERS_REDIRECT_H
#define __SERVERS_REDIRECT_H
typedef struct {
int last; /* number of "last" events at the start of the events list */
GSList *events; /* char* list of events */
} REDIRECT_CMD_REC;
typedef struct {
char *name; /* event name */
char *arg; /* argument for event we are expecting or NULL */
int argpos; /* argument position */
int group; /* group of events this belongs to */
int last; /* if this event is received, remove all the events in this group */
}
REDIRECT_REC;
void server_redirect_init(SERVER_REC *server, const char *command, int last, ...);
void server_redirect_initv(SERVER_REC *server, const char *command, int last, GSList *list);
/* ... = char *event1, char *event2, ..., NULL */
void server_redirect_event(SERVER_REC *server, const char *arg, int last, ...);
/* ... = char *event, char *callback_signal, int argpos, ..., NULL */
int server_redirect_single_event(SERVER_REC *server, const char *arg, int last, int group,
const char *event, const char *signal, int argpos);
void server_redirect_default(SERVER_REC *server, const char *command);
void server_redirect_remove_next(SERVER_REC *server, const char *event, GSList *item);
GSList *server_redirect_getqueue(SERVER_REC *server, const char *event, const char *args);
void servers_redirect_init(void);
void servers_redirect_deinit(void);
#endif

View File

@ -31,7 +31,6 @@
#include "chat-protocols.h"
#include "servers.h"
#include "servers-reconnect.h"
#include "servers-redirect.h"
#include "servers-setup.h"
#include "channels.h"
#include "queries.h"
@ -136,10 +135,6 @@ void server_connect_finished(SERVER_REC *server)
server->connect_time = time(NULL);
server->rawlog = rawlog_create();
server->eventtable = g_hash_table_new((GHashFunc) g_istr_hash, (GCompareFunc) g_istr_equal);
server->eventgrouptable = g_hash_table_new((GHashFunc) g_direct_hash, (GCompareFunc) g_direct_equal);
server->cmdtable = g_hash_table_new((GHashFunc) g_istr_hash, (GCompareFunc) g_istr_equal);
servers = g_slist_append(servers, server);
signal_emit("server connected", 1, server);
}
@ -553,7 +548,6 @@ void servers_init(void)
signal_add("chat protocol deinit", (SIGNAL_FUNC) sig_chat_protocol_deinit);
servers_reconnect_init();
servers_redirect_init();
servers_setup_init();
}
@ -562,7 +556,6 @@ void servers_deinit(void)
signal_remove("chat protocol deinit", (SIGNAL_FUNC) sig_chat_protocol_deinit);
servers_setup_deinit();
servers_redirect_deinit();
servers_reconnect_deinit();
module_uniq_destroy("SERVER");

View File

@ -309,17 +309,10 @@ static void event_connected(IRC_SERVER_REC *server)
return;
/* someone has our nick, find out who. */
server_redirect_event(server, "whois", nick, FALSE, NULL,
"event 311", "nickfind event whois",
"", "event empty", NULL);
irc_send_cmdv(server, "WHOIS %s", nick);
server_redirect_event((SERVER_REC *) server, nick, 1,
"event 318", "event empty", 1,
"event 401", "event empty", 1,
"event 311", "nickfind event whois", 1,
"event 301", "event empty", 1,
"event 312", "event empty", 1,
"event 313", "event empty", 1,
"event 317", "event empty", 1,
"event 319", "event empty", 1, NULL);
}
static void event_nickfind_whois(IRC_SERVER_REC *server, const char *data)

View File

@ -30,7 +30,8 @@ libirc_core_a_SOURCES = \
modes.c \
mode-lists.c \
netsplit.c \
server-idle.c
servers-idle.c \
servers-redirect.c
noinst_HEADERS = \
bans.h \
@ -49,4 +50,5 @@ noinst_HEADERS = \
mode-lists.h \
module.h \
netsplit.h \
server-idle.h
servers-idle.h \
servers-redirect.h

View File

@ -209,11 +209,10 @@ static void channel_send_query(IRC_SERVER_REC *server, int query)
for (tmp = chans; tmp != NULL; tmp = tmp->next) {
chanrec = tmp->data;
server_redirect_event((SERVER_REC *) server, chanstr, 4,
"event 403", "chanquery mode abort", 1,
"event 442", "chanquery mode abort", 1, /* "you're not on that channel" */
"event 479", "chanquery mode abort", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */
"event 324", "chanquery mode", 1, NULL);
server_redirect_event(server, "mode channel", chanstr, -1,
"chanquery mode abort",
"event 324", "chanquery mode",
"", "chanquery mode abort", NULL);
}
break;
@ -223,11 +222,11 @@ static void channel_send_query(IRC_SERVER_REC *server, int query)
for (tmp = chans; tmp != NULL; tmp = tmp->next) {
chanrec = tmp->data;
server_redirect_event((SERVER_REC *) server, chanstr, 3,
"event 401", "chanquery who abort", 1,
"event 403", "chanquery who abort", 1,
"event 315", "chanquery who end", 1,
"event 352", "silent event who", 1, NULL);
server_redirect_event(server, "who", chanstr, -1,
"chanquery who abort",
"event 315", "chanquery who end",
"event 352", "silent event who",
"", "chanquery who abort", NULL);
}
break;
@ -240,12 +239,11 @@ static void channel_send_query(IRC_SERVER_REC *server, int query)
mode requests - if channels are joined manually
irssi could ask modes separately but afterwards
join the two b/e/I modes together */
server_redirect_event((SERVER_REC *) server, chanstr, 4,
"event 403", "chanquery mode abort", 1,
"event 442", "chanquery mode abort", 1, /* "you're not on that channel" */
"event 479", "chanquery mode abort", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */
"event 368", "chanquery ban end", 1,
"event 367", "chanquery ban", 1, NULL);
server_redirect_event(server, "mode b", chanstr, -1,
"chanquery mode abort",
"event 367", "chanquery ban",
"event 368", "chanquery ban end",
"", "chanquery mode abort", NULL);
}
break;
@ -254,12 +252,11 @@ static void channel_send_query(IRC_SERVER_REC *server, int query)
for (tmp = chans; tmp != NULL; tmp = tmp->next) {
chanrec = tmp->data;
server_redirect_event((SERVER_REC *) server, chanstr, 4,
"event 403", "chanquery mode abort", 1,
"event 442", "chanquery mode abort", 1, /* "you're not on that channel" */
"event 479", "chanquery mode abort", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */
"event 349", "chanquery eban end", 1,
"event 348", "chanquery eban", 1, NULL);
server_redirect_event(server, "mode e", chanstr, -1,
"chanquery mode abort",
"event 348", "chanquery eban",
"event 349", "chanquery eban end",
"", "chanquery mode abort", NULL);
}
break;
@ -268,12 +265,11 @@ static void channel_send_query(IRC_SERVER_REC *server, int query)
for (tmp = chans; tmp != NULL; tmp = tmp->next) {
chanrec = tmp->data;
server_redirect_event((SERVER_REC *) server, chanstr, 4,
"event 403", "chanquery mode abort", 1,
"event 442", "chanquery mode abort", 1, /* "you're not on that channel" */
"event 479", "chanquery mode abort", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */
"event 347", "chanquery ilist end", 1,
"event 346", "chanquery ilist", 1, NULL);
server_redirect_event(server, "mode I", chanstr, -1,
"chanquery mode abort",
"event 346", "chanquery ilist",
"event 347", "chanquery ilist end",
"", "chanquery mode abort", NULL);
}
break;
@ -423,14 +419,6 @@ static void event_channel_mode(IRC_SERVER_REC *server, const char *data,
g_free(params);
}
static void multi_query_remove(IRC_SERVER_REC *server, const char *event, const char *data)
{
GSList *queue;
while ((queue = server_redirect_getqueue((SERVER_REC *) server, event, data)) != NULL)
server_redirect_remove_next((SERVER_REC *) server, event, queue);
}
static void event_end_of_who(IRC_SERVER_REC *server, const char *data)
{
IRC_CHANNEL_REC *chanrec;
@ -447,7 +435,6 @@ static void event_end_of_who(IRC_SERVER_REC *server, const char *data)
/* instead of multiple End of WHO replies we get
only this one... */
server->one_endofwho = TRUE;
multi_query_remove(server, "event 315", data);
/* check that the WHO actually did return something
(that it understood #chan1,#chan2,..) */
@ -549,8 +536,6 @@ static void multi_command_error(IRC_SERVER_REC *server, const char *data,
char *params, *channel, **chans;
int n;
multi_query_remove(server, event, data);
params = event_get_params(data, 2, NULL, &channel);
chans = g_strsplit(channel, ",", -1);

View File

@ -26,7 +26,7 @@
#include "settings.h"
#include "irc-servers.h"
#include "server-idle.h"
#include "servers-idle.h"
#include "ignore.h"
static void ctcp_queue_clean(IRC_SERVER_REC *server)
@ -57,7 +57,7 @@ void ctcp_send_reply(IRC_SERVER_REC *server, const char *data)
return;
/* Add to first in idle queue */
tag = server_idle_add(server, data, NULL, 0, NULL);
tag = server_idle_add(server, data);
server->ctcpqueue =
g_slist_append(server->ctcpqueue, GINT_TO_POINTER(tag));
}

View File

@ -244,9 +244,6 @@ static void cmd_list(const char *data, IRC_SERVER_REC *server,
irc_send_cmdv(server, "LIST %s", str);
cmd_params_free(free_arg);
/* add default redirection */
server_redirect_default((SERVER_REC *) server, "bogus command list");
}
/* SYNTAX: WHO [<nicks> | <channels> | **] */
@ -275,9 +272,6 @@ static void cmd_who(const char *data, IRC_SERVER_REC *server,
irc_send_cmdv(server, *rest == '\0' ? "WHO %s" : "WHO %s %s",
channel, rest);
cmd_params_free(free_arg);
/* add default redirection */
server_redirect_default((SERVER_REC *) server, "bogus command who");
}
static void cmd_names(const char *data, IRC_SERVER_REC *server,
@ -323,43 +317,10 @@ static void cmd_nick(const char *data, IRC_SERVER_REC *server, WI_ITEM_REC *item
if (!cmd_get_params(data, &free_arg, 1, &nick))
return;
if (strcmp(nick, server->nick) == 0) {
/* don't bother trying to change the nick to the one you
already have */
cmd_params_free(free_arg);
return;
}
server->nick_changing = TRUE;
irc_send_cmdv(server, "NICK %s", nick);
nick = g_strdup_printf("%s :%s", nick, nick);
server_redirect_event(SERVER(server), nick, 5,
"event nick", "nickchange over", -1,
"event 433", "nickchange over", 1,
/* 437: ircnet = target unavailable,
dalnet = banned in channel,
can't change nick */
"event 437", "nickchange over", -1,
"event 432", "nickchange over", 1,
"event 438", "nickchange over", 1, NULL);
g_free(nick);
cmd_params_free(free_arg);
}
static void sig_nickchange_over(IRC_SERVER_REC *server, const char *data,
const char *nick, const char *addr)
{
char *signal;
server->nick_changing = FALSE;
signal = g_strconcat("event ", current_server_event, NULL);
g_strdown(signal+6);
signal_emit(signal, 4, server, data, nick, addr);
g_free(signal);
}
static char *get_redirect_nicklist(const char *nicks, int *free)
{
char *str, *ret;
@ -419,20 +380,21 @@ static void cmd_whois(const char *data, IRC_SERVER_REC *server,
event_402 = "whois event noserver";
}
server->whois_found = FALSE;
irc_send_cmd_split(server, tmpstr->str, 2, server->max_whois_in_cmd);
/* do automatic /WHOWAS if any of the nicks wasn't found */
query = get_redirect_nicklist(query, &free_nick);
str = g_strconcat(qserver, " ", query, NULL);
server_redirect_event(SERVER(server), str, 2,
"event 318", "event 318", 1,
"event 402", event_402, 1,
"event 401", "whois not found", 1,
"event 311", "whois event", 1, NULL);
server_redirect_event(server, "whois", str, *qserver != '\0',
NULL,
"event 318", "event 318",
"event 402", event_402,
"event 401", "whois not found",
"event 311", "whois event", NULL);
g_free(str);
server->whois_found = FALSE;
irc_send_cmd_split(server, tmpstr->str, 2, server->max_whois_in_cmd);
if (free_nick) g_free(query);
cmd_params_free(free_arg);
}
@ -451,13 +413,14 @@ static void sig_whois_not_found(IRC_SERVER_REC *server, const char *data)
g_return_if_fail(data != NULL);
params = event_get_params(data, 2, NULL, &nick);
irc_send_cmdv(server, "WHOWAS %s 1", nick);
server->whowas_found = FALSE;
server_redirect_event(SERVER(server), nick, 1,
"event 369", "whowas event end", 1,
"event 314", "whowas event", 1,
"event 406", "event empty", 1, NULL);
server_redirect_event(server, "whowas", nick, -1, NULL,
"event 314", "whowas event",
"event 369", "whowas event end",
"", "event empty", NULL);
irc_send_cmdv(server, "WHOWAS %s 1", nick);
g_free(params);
}
@ -470,7 +433,7 @@ static void event_whowas(IRC_SERVER_REC *server, const char *data, const char *n
/* SYNTAX: WHOWAS [<nicks> [<count>]] */
static void cmd_whowas(const char *data, IRC_SERVER_REC *server)
{
char *nicks, *count;
char *nicks, *count, *nicks_redir;
void *free_arg;
int free_nick;
@ -480,15 +443,15 @@ static void cmd_whowas(const char *data, IRC_SERVER_REC *server)
return;
if (*nicks == '\0') nicks = server->nick;
nicks_redir = get_redirect_nicklist(nicks, &free_nick);
server_redirect_event(server, "whowas", nicks_redir, -1, NULL,
"event 314", "whowas event", NULL);
if (free_nick) g_free(nicks_redir);
server->whowas_found = FALSE;
irc_send_cmdv(server, *count == '\0' ? "WHOWAS %s" :
"WHOWAS %s %s", nicks, count);
nicks = get_redirect_nicklist(nicks, &free_nick);
server_redirect_event(SERVER(server), nicks, 1,
"event 369", "event 369", 1,
"event 314", "whowas event", 1, NULL);
if (free_nick) g_free(nicks);
cmd_params_free(free_arg);
}
@ -914,48 +877,6 @@ static void command_2self(const char *data, IRC_SERVER_REC *server)
cmd_params_free(free_arg);
}
static void sig_connected(IRC_SERVER_REC *server)
{
g_return_if_fail(server != NULL);
/* FIXME: these two aren't probably needed? this whole redirection
thing might need some rethinking :) */
/* WHOIS */
/*server_redirect_init(SERVER(server), "", 2,
"event 318", "event 402", "event 401",
"event 301", "event 311", "event 312", "event 313",
"event 317", "event 319", NULL);*/
/* NICK */
/*server_redirect_init(SERVER(server), "", 5,
"event nick", "event 433", "event 437",
"event 432", "event 438", NULL);*/
/* problem (doesn't really apply currently since there's no GUI):
second argument of server_redirect_init() is the command that
generates the redirection automatically when it's called, but the
command handler doesn't really know about the redirection itself.
every time the command is called, this redirection is generated.
this is a problem if the redirection is wanted sometimes but not
always. for example /WHO #channel could create a window with a
list of people in channel redirecting WHO's events to it's own use,
but /WHO -nogui #channel would use the default WHO handler which
doesn't know anything about redirection. with GUI /WHO the
redirection would be done twice then..
so the kludgy workaround currently is this: make the default
handler handle the redirection always.. when default WHO/LIST
handler is called, they call
server_redirect_default("bogus command who") or ..list..
this is really a problem if some script/plugin wants to override
some default command to use redirections.. */
server_redirect_init(SERVER(server), "bogus command who", 2, "event 401", "event 315", "event 352", NULL);
server_redirect_init(SERVER(server), "bogus command list", 1, "event 321", "event 322", "event 323", NULL);
}
void irc_commands_init(void)
{
tmpstr = g_string_new(NULL);
@ -1048,11 +969,9 @@ void irc_commands_init(void)
signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
signal_add("nickchange over", (SIGNAL_FUNC) sig_nickchange_over);
signal_add("whois not found", (SIGNAL_FUNC) sig_whois_not_found);
signal_add("whois event", (SIGNAL_FUNC) event_whois);
signal_add("whowas event", (SIGNAL_FUNC) event_whowas);
signal_add("server connected", (SIGNAL_FUNC) sig_connected);
command_set_options("connect", "+ircnet");
command_set_options("topic", "delete");
@ -1119,11 +1038,9 @@ void irc_commands_deinit(void)
signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
signal_remove("nickchange over", (SIGNAL_FUNC) sig_nickchange_over);
signal_remove("whois not found", (SIGNAL_FUNC) sig_whois_not_found);
signal_remove("whois event", (SIGNAL_FUNC) event_whois);
signal_remove("whowas event", (SIGNAL_FUNC) event_whowas);
signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
g_string_free(tmpstr, TRUE);
}

View File

@ -33,8 +33,9 @@
#include "irc-servers-setup.h"
#include "irc-servers.h"
#include "channel-rejoin.h"
#include "server-idle.h"
#include "servers-idle.h"
#include "servers-reconnect.h"
#include "servers-redirect.h"
#include "modes.h"
#include "settings.h"
@ -304,6 +305,7 @@ static void server_cmd_timeout(IRC_SERVER_REC *server, GTimeVal *now)
/* add to rawlog without CR+LF */
cmd[len-2] = '\0';
rawlog_output(server->rawlog, cmd);
server_redirect_command(server, cmd);
/* remove from queue */
g_free(cmd);
@ -506,6 +508,7 @@ void irc_servers_init(void)
irc_servers_setup_init();
irc_servers_reconnect_init();
servers_redirect_init();
servers_idle_init();
}
@ -527,5 +530,6 @@ void irc_servers_deinit(void)
irc_servers_setup_deinit();
irc_servers_reconnect_deinit();
servers_redirect_deinit();
servers_idle_deinit();
}

View File

@ -37,12 +37,16 @@ struct _IRC_SERVER_CONNECT_REC {
struct _IRC_SERVER_REC {
#include "server-rec.h"
/* For deciding if event should be redirected */
GSList *redirects;
void *redirect_next;
void *redirect_continue;
char *real_address; /* address the irc server gives */
char *usermode; /* The whole mode string .. */
char *userhost; /* /USERHOST <nick> - set when joined to first channel */
int channels_formed; /* channels formed in irc network */
unsigned int nick_changing:1; /* We've sent nick change command to server */
unsigned int whois_coming:1; /* Mostly just to display away message right.. */
unsigned int whois_found:1; /* Did WHOIS return any entries? */
unsigned int whowas_found:1; /* Did WHOWAS return any entries? */

View File

@ -62,8 +62,10 @@ void irc_send_cmd_full(IRC_SERVER_REC *server, const char *cmd,
cmd = str;
}
if (send_now)
if (send_now) {
rawlog_output(server->rawlog, cmd);
server_redirect_command(server, cmd);
}
if (!raw) {
/* Add CR+LF to command */
@ -253,39 +255,34 @@ char *event_get_params(const char *data, int count, ...)
return duprec;
}
static void irc_server_event(IRC_SERVER_REC *server, const char *line, const char *nick, const char *address)
static void irc_server_event(IRC_SERVER_REC *server, const char *line,
const char *nick, const char *address)
{
char *event, *args, *callcmd;
GSList *list;
const char *signal;
char *event, *args;
g_return_if_fail(line != NULL);
/* get command.. */
/* split event / args */
event = g_strconcat("event ", line, NULL);
args = strchr(event+6, ' ');
if (args != NULL) *args++ = '\0'; else args = "";
while (*args == ' ') args++;
g_strdown(event);
list = server_redirect_getqueue((SERVER_REC *) server, event, args);
if (list == NULL)
callcmd = g_strdup(event);
else {
/* event is redirected somewhere else.. */
REDIRECT_REC *rec;
rec = list->data;
callcmd = g_strdup(rec->name);
rawlog_redirect(server->rawlog, callcmd);
server_redirect_remove_next((SERVER_REC *) server, event, list);
}
/* check if event needs to be redirected */
signal = server_redirect_get_signal(server, event, args);
if (signal == NULL)
signal = event;
else
rawlog_redirect(server->rawlog, signal);
/* emit it */
current_server_event = event+6;
g_strdown(callcmd);
if (!signal_emit(callcmd, 4, server, args, nick, address))
if (!signal_emit(signal, 4, server, args, nick, address))
signal_emit_id(signal_default_event, 4, server, line, nick, address);
current_server_event = NULL;
g_free(callcmd);
g_free(event);
}

View File

@ -24,6 +24,7 @@
#include "settings.h"
#include "irc-servers.h"
#include "servers-redirect.h"
typedef struct {
IRC_SERVER_REC *server;
@ -53,6 +54,20 @@ static void lag_free(LAG_REC *rec)
g_free(rec);
}
static void lag_send(LAG_REC *lag)
{
IRC_SERVER_REC *server;
g_get_current_time(&lag->time);
server = lag->server;
server->lag_sent = server->lag_last_check = time(NULL);
server_redirect_event(server, "ping", NULL, FALSE,
"lag ping error",
"event pong", "lag pong", NULL);
irc_send_cmdv(server, "PING %s", server->real_address);
}
static void lag_get(IRC_SERVER_REC *server)
{
LAG_REC *lag;
@ -61,57 +76,42 @@ static void lag_get(IRC_SERVER_REC *server)
/* nick changes may fail this check, so we should never do this
while there's nick change request waiting for reply in server.. */
if (server->nick_changing)
return;
lag = g_new0(LAG_REC, 1);
lags = g_slist_append(lags, lag);
lag->server = server;
g_get_current_time(&lag->time);
if (server->lag_sent == 0)
server->lag_sent = time(NULL);
server->lag_last_check = time(NULL);
irc_send_cmdv(server, "NOTICE %s :\001IRSSILAG %ld %ld\001",
server->nick, lag->time.tv_sec, lag->time.tv_usec);
lag_send(lag);
}
/* we use "ctcp reply" signal here, because "ctcp reply irssilag" can be
ignored with /IGNORE * CTCPS */
static void sig_irssilag(IRC_SERVER_REC *server, const char *data,
const char *nick, const char *addr,
const char *target)
/* we didn't receive PONG for some reason .. try again */
static void lag_ping_error(IRC_SERVER_REC *server)
{
GTimeVal now, sent;
LAG_REC *lag;
lag = lag_find(server);
if (lag != NULL)
lag_send(lag);
}
static void lag_event_pong(IRC_SERVER_REC *server, const char *data,
const char *nick, const char *addr)
{
GTimeVal now;
LAG_REC *lag;
g_return_if_fail(data != NULL);
if (strncmp(data, "IRSSILAG ", 9) != 0)
return;
data += 9;
lag = lag_find(server);
if (lag == NULL) {
/* not expecting lag reply.. */
return;
}
if (g_strcasecmp(nick, server->nick) != 0) {
/* we didn't sent this - not a lag notice */
return;
}
/* OK, it is a lag notice. */
server->lag_sent = 0;
if (sscanf(data, "%ld %ld", &sent.tv_sec, &sent.tv_usec) == 2) {
g_get_current_time(&now);
server->lag = (int) get_timeval_diff(&now, &sent);
server->lag = (int) get_timeval_diff(&now, &lag->time);
signal_emit("server lag", 1, server);
}
lag_free(lag);
}
@ -154,11 +154,6 @@ static int sig_check_lag(void)
return 1;
}
static void sig_empty(void)
{
/* don't print the "CTCP IRSSILAG reply .." text */
}
void lag_init(void)
{
settings_add_int("misc", "lag_check_time", 30);
@ -166,8 +161,8 @@ void lag_init(void)
lags = NULL;
timeout_tag = g_timeout_add(1000, (GSourceFunc) sig_check_lag, NULL);
signal_add("ctcp reply", (SIGNAL_FUNC) sig_irssilag);
signal_add("ctcp reply irssilag", (SIGNAL_FUNC) sig_empty);
signal_add_first("lag pong", (SIGNAL_FUNC) lag_event_pong);
signal_add("lag ping error", (SIGNAL_FUNC) lag_ping_error);
}
void lag_deinit(void)
@ -175,6 +170,6 @@ void lag_deinit(void)
g_source_remove(timeout_tag);
while (lags != NULL)
lag_free(lags->data);
signal_remove("ctcp reply", (SIGNAL_FUNC) sig_irssilag);
signal_remove("ctcp reply irssilag", (SIGNAL_FUNC) sig_empty);
signal_remove("lag pong", (SIGNAL_FUNC) lag_event_pong);
signal_remove("lag ping error", (SIGNAL_FUNC) lag_ping_error);
}

View File

@ -1,22 +0,0 @@
#ifndef __SERVER_IDLE_H
#define __SERVER_IDLE_H
/* Add new idle command to queue */
int server_idle_add(IRC_SERVER_REC *server, const char *cmd, const char *arg, int last, ...);
/* Add new idle command to first of queue */
int server_idle_add_first(IRC_SERVER_REC *server, const char *cmd, const char *arg, int last, ...);
/* Add new idle command to specified position of queue */
int server_idle_insert(IRC_SERVER_REC *server, const char *cmd, const char *arg, int tag, int last, ...);
/* Check if record is still in queue */
int server_idle_find(IRC_SERVER_REC *server, int tag);
/* Remove record from idle queue */
int server_idle_remove(IRC_SERVER_REC *server, int tag);
void servers_idle_init(void);
void servers_idle_deinit(void);
#endif

View File

@ -22,49 +22,54 @@
#include "signals.h"
#include "irc-servers.h"
#include "server-idle.h"
#include "servers-idle.h"
#include "servers-redirect.h"
typedef struct {
char *event;
char *signal;
int argpos;
} REDIRECT_IDLE_REC;
typedef struct {
char *cmd;
char *arg;
int tag;
int last;
char *redirect_cmd;
int remote;
char *failure_signal;
GSList *redirects;
} SERVER_IDLE_REC;
static int idle_tag, idlepos;
/* Add new idle command to queue */
static SERVER_IDLE_REC *server_idle_create(const char *cmd, const char *arg, int last, va_list args)
static SERVER_IDLE_REC *
server_idle_create(const char *cmd, const char *redirect_cmd, const char *arg,
int remote, const char *failure_signal, va_list va)
{
REDIRECT_IDLE_REC *rrec;
SERVER_IDLE_REC *rec;
char *event;
const char *event, *signal;
g_return_val_if_fail(cmd != NULL, FALSE);
rec = g_new0(SERVER_IDLE_REC, 1);
rec->tag = ++idlepos;
rec->arg = arg == NULL ? NULL : g_strdup(arg);
rec->cmd = g_strdup(cmd);
rec->last = last;
rec->arg = g_strdup(arg);
rec->tag = ++idlepos;
while ((event = va_arg(args, char *)) != NULL) {
rrec = g_new(REDIRECT_IDLE_REC, 1);
rec->redirects = g_slist_append(rec->redirects, rrec);
rec->redirect_cmd = g_strdup(redirect_cmd);
rec->remote = remote;
rec->failure_signal = g_strdup(failure_signal);
rrec->event = g_strdup(event);
rrec->signal = g_strdup(va_arg(args, char *));
rrec->argpos = va_arg(args, int);
while ((event = va_arg(va, const char *)) != NULL) {
signal = va_arg(va, const char *);
if (signal == NULL) {
g_warning("server_idle_create(%s): "
"signal not specified for event",
redirect_cmd);
break;
}
rec->redirects =
g_slist_append(rec->redirects, g_strdup(event));
rec->redirects =
g_slist_append(rec->redirects, g_strdup(signal));
}
return rec;
@ -87,78 +92,82 @@ static SERVER_IDLE_REC *server_idle_find_rec(IRC_SERVER_REC *server, int tag)
}
/* Add new idle command to queue */
int server_idle_add(IRC_SERVER_REC *server, const char *cmd, const char *arg, int last, ...)
int server_idle_add_redir(IRC_SERVER_REC *server, const char *cmd,
const char *redirect_cmd, const char *arg,
int remote, const char *failure_signal, ...)
{
va_list args;
va_list va;
SERVER_IDLE_REC *rec;
g_return_val_if_fail(server != NULL, -1);
va_start(args, last);
rec = server_idle_create(cmd, arg, last, args);
va_start(va, failure_signal);
rec = server_idle_create(cmd, redirect_cmd, arg, remote,
failure_signal, va);
server->idles = g_slist_append(server->idles, rec);
va_end(args);
va_end(va);
return rec->tag;
}
/* Add new idle command to first of queue */
int server_idle_add_first(IRC_SERVER_REC *server, const char *cmd, const char *arg, int last, ...)
int server_idle_add_first_redir(IRC_SERVER_REC *server, const char *cmd,
const char *redirect_cmd, const char *arg,
int remote, const char *failure_signal, ...)
{
va_list args;
va_list va;
SERVER_IDLE_REC *rec;
g_return_val_if_fail(server != NULL, -1);
va_start(args, last);
rec = server_idle_create(cmd, arg, last, args);
va_start(va, failure_signal);
rec = server_idle_create(cmd, redirect_cmd, arg, remote,
failure_signal, va);
server->idles = g_slist_prepend(server->idles, rec);
va_end(args);
va_end(va);
return rec->tag;
}
/* Add new idle command to specified position of queue */
int server_idle_insert(IRC_SERVER_REC *server, const char *cmd, const char *arg, int tag, int last, ...)
int server_idle_insert_redir(IRC_SERVER_REC *server, const char *cmd, int tag,
const char *redirect_cmd, const char *arg,
int remote, const char *failure_signal, ...)
{
va_list args;
va_list va;
SERVER_IDLE_REC *rec;
int pos;
g_return_val_if_fail(server != NULL, -1);
va_start(args, last);
va_start(va, failure_signal);
/* find the position of tag in idle list */
rec = server_idle_find_rec(server, tag);
pos = g_slist_index(server->idles, rec);
rec = server_idle_create(cmd, arg, last, args);
rec = server_idle_create(cmd, redirect_cmd, arg, remote,
failure_signal, va);
server->idles = pos < 0 ?
g_slist_append(server->idles, rec) :
g_slist_insert(server->idles, rec, pos);
va_end(args);
va_end(va);
return rec->tag;
}
static void server_idle_destroy(IRC_SERVER_REC *server, SERVER_IDLE_REC *rec)
{
GSList *tmp;
g_return_if_fail(server != NULL);
server->idles = g_slist_remove(server->idles, rec);
for (tmp = rec->redirects; tmp != NULL; tmp = tmp->next) {
REDIRECT_IDLE_REC *rec = tmp->data;
g_free(rec->event);
g_free(rec->signal);
g_free(rec);
}
g_slist_foreach(rec->redirects, (GFunc) g_free, NULL);
g_slist_free(rec->redirects);
g_free_not_null(rec->arg);
g_free_not_null(rec->redirect_cmd);
g_free_not_null(rec->failure_signal);
g_free(rec->cmd);
g_free(rec);
}
@ -188,26 +197,20 @@ int server_idle_remove(IRC_SERVER_REC *server, int tag)
static void server_idle_next(IRC_SERVER_REC *server)
{
SERVER_IDLE_REC *rec;
GSList *tmp;
int group;
g_return_if_fail(server != NULL);
if (server->idles == NULL) return;
if (server->idles == NULL)
return;
rec = server->idles->data;
/* Send command */
irc_send_cmd(server, rec->cmd);
/* Add server redirections */
group = 0;
for (tmp = rec->redirects; tmp != NULL; tmp = tmp->next) {
REDIRECT_IDLE_REC *rrec = tmp->data;
group = server_redirect_single_event((SERVER_REC *) server, rec->arg, rec->last > 0,
group, rrec->event, rrec->signal, rrec->argpos);
if (rec->last > 0) rec->last--;
if (rec->redirect_cmd != NULL) {
server_redirect_event_list(server, rec->redirect_cmd, rec->arg,
rec->remote, rec->failure_signal,
rec->redirects);
}
irc_send_cmd(server, rec->cmd);
server_idle_destroy(server, rec);
}

View File

@ -0,0 +1,34 @@
#ifndef __SERVERS_IDLE_H
#define __SERVERS_IDLE_H
/* Add new idle command to queue */
int server_idle_add_redir(IRC_SERVER_REC *server, const char *cmd,
const char *redirect_cmd, const char *arg,
int remote, const char *failure_signal, ...);
#define server_idle_add(server, cmd) \
server_idle_add_redir(server, cmd, NULL, NULL, 0, NULL, NULL)
/* Add new idle command to first of queue */
int server_idle_add_first_redir(IRC_SERVER_REC *server, const char *cmd,
const char *redirect_cmd, const char *arg,
int remote, const char *failure_signal, ...);
#define server_idle_add_first(server, cmd) \
server_idle_add_first_redir(server, cmd, NULL, NULL, 0, NULL, NULL)
/* Add new idle command to specified position of queue */
int server_idle_insert_redir(IRC_SERVER_REC *server, const char *cmd, int tag,
const char *redirect_cmd, const char *arg,
int remote, const char *failure_signal, ...);
#define server_idle_insert(server, cmd, tag) \
server_idle_insert_redir(server, cmd, tag, NULL, NULL, 0, NULL, NULL)
/* Check if record is still in queue */
int server_idle_find(IRC_SERVER_REC *server, int tag);
/* Remove record from idle queue */
int server_idle_remove(IRC_SERVER_REC *server, int tag);
void servers_idle_init(void);
void servers_idle_deinit(void);
#endif

View File

@ -0,0 +1,569 @@
/*
server-redirect.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 "irc-servers.h"
#include "servers-redirect.h"
typedef struct {
int refcount;
int remote;
int timeout;
GSList *start, *stop; /* char *event, int argpos, ... */
} REDIRECT_CMD_REC;
typedef struct {
REDIRECT_CMD_REC *cmd;
time_t created;
int destroyed;
char *arg;
int remote;
char *failure_signal, *default_signal;
GSList *signals; /* event, signal, ... */
} REDIRECT_REC;
static GHashTable *command_redirects; /* "command xxx" : REDIRECT_CMD_REC* */
/* Find redirection command record for specified command line. */
static REDIRECT_CMD_REC *redirect_cmd_find(const char *command)
{
REDIRECT_CMD_REC *rec;
const char *p;
char *cmd;
p = strchr(command, ' ');
if (p == NULL)
rec = g_hash_table_lookup(command_redirects, command);
else {
cmd = g_strndup(command, (int) (p-command));
rec = g_hash_table_lookup(command_redirects, cmd);
g_free(cmd);
}
return rec;
}
static void redirect_cmd_destroy(REDIRECT_CMD_REC *rec)
{
GSList *tmp;
for (tmp = rec->start; tmp != NULL; tmp = tmp->next->next)
g_free(tmp->data);
for (tmp = rec->stop; tmp != NULL; tmp = tmp->next->next)
g_free(tmp->data);
g_slist_free(rec->start);
g_slist_free(rec->stop);
g_free(rec);
}
static void redirect_cmd_ref(REDIRECT_CMD_REC *rec)
{
rec->refcount++;
}
static void redirect_cmd_unref(REDIRECT_CMD_REC *rec)
{
if (--rec->refcount <= 0)
redirect_cmd_destroy(rec);
}
static void redirect_destroy(REDIRECT_REC *rec)
{
redirect_cmd_unref(rec->cmd);
g_free_not_null(rec->arg);
g_free_not_null(rec->failure_signal);
g_free_not_null(rec->default_signal);
g_slist_foreach(rec->signals, (GFunc) g_free, NULL);
g_slist_free(rec->signals);
g_free(rec);
}
void server_redirect_register(const char *command,
int remote, int timeout, ...)
{
va_list va;
GSList *start, *stop, **list;
const char *event;
int argpos;
va_start(va, timeout);
start = stop = NULL; list = &start;
for (;;) {
event = va_arg(va, const char *);
if (event == NULL) {
if (list == &stop)
break;
list = &stop;
continue;
}
argpos = va_arg(va, int);
*list = g_slist_append(*list, g_strdup(event));
*list = g_slist_append(*list, GINT_TO_POINTER(argpos));
}
va_end(va);
server_redirect_register_list(command, remote, timeout, start, stop);
}
void server_redirect_register_list(const char *command,
int remote, int timeout,
GSList *start, GSList *stop)
{
REDIRECT_CMD_REC *rec;
gpointer key, value;
g_return_if_fail(command != NULL);
g_return_if_fail(stop != NULL);
if (g_hash_table_lookup_extended(command_redirects, command,
&key, &value)) {
/* Already registered - might have changed so destroy
the old one */
g_hash_table_remove(command_redirects, command);
redirect_cmd_unref(value);
g_free(key);
}
rec = g_new0(REDIRECT_CMD_REC, 1);
redirect_cmd_ref(rec);
rec->remote = remote;
rec->timeout = timeout;
rec->start = start;
rec->stop = stop;
g_hash_table_insert(command_redirects, g_strdup(command), rec);
}
void server_redirect_event(IRC_SERVER_REC *server, const char *command,
const char *arg, int remote,
const char *failure_signal, ...)
{
GSList *signals;
const char *event, *signal;
va_list va;
va_start(va, failure_signal);
signals = NULL;
while ((event = va_arg(va, const char *)) != NULL) {
signal = va_arg(va, const char *);
if (signal == NULL) {
g_warning("server_redirect_event(%s): "
"signal not specified for event", command);
break;
}
signals = g_slist_append(signals, g_strdup(event));
signals = g_slist_append(signals, g_strdup(signal));
}
va_end(va);
server_redirect_event_list(server, command, arg, remote,
failure_signal, signals);
}
void server_redirect_event_list(IRC_SERVER_REC *server, const char *command,
const char *arg, int remote,
const char *failure_signal, GSList *signals)
{
REDIRECT_CMD_REC *cmdrec;
REDIRECT_REC *rec;
GSList *default_signal;
char *default_signal_key;
g_return_if_fail(IS_IRC_SERVER(server));
g_return_if_fail(command != NULL);
g_return_if_fail((g_slist_length(signals) & 1) == 0);
if (server->redirect_next != NULL) {
redirect_destroy(server->redirect_next);
server->redirect_next = NULL;
}
cmdrec = g_hash_table_lookup(command_redirects, command);
if (cmdrec == NULL) {
g_warning("Unknown redirection command: %s", command);
return;
}
redirect_cmd_ref(cmdrec);
rec = g_new0(REDIRECT_REC, 1);
rec->created = time(NULL);
rec->cmd = cmdrec;
rec->arg = g_strdup(arg);
rec->remote = remote != -1 ? remote : cmdrec->remote;
rec->failure_signal = g_strdup(failure_signal);
default_signal = gslist_find_string(signals, "");
if (default_signal != NULL) {
default_signal_key = default_signal->data;
rec->default_signal = default_signal->next->data;
signals = g_slist_remove(signals, default_signal_key);
signals = g_slist_remove(signals, rec->default_signal);
g_free(default_signal_key);
}
rec->signals = signals;
server->redirect_next = rec;
}
void server_redirect_command(IRC_SERVER_REC *server, const char *command)
{
REDIRECT_CMD_REC *cmdrec;
REDIRECT_REC *rec;
g_return_if_fail(IS_IRC_SERVER(server));
g_return_if_fail(command != NULL);
if (server->redirect_next != NULL) {
rec = server->redirect_next;
server->redirect_next = NULL;
} else {
cmdrec = redirect_cmd_find(command);
if (cmdrec == NULL)
return;
/* no redirection wanted, but still register the command
so future redirections wont get messed up. */
redirect_cmd_ref(cmdrec);
rec = g_new0(REDIRECT_REC, 1);
rec->created = time(NULL);
rec->cmd = cmdrec;
rec->remote = cmdrec->remote;
}
server->redirects = g_slist_append(server->redirects, rec);
}
static int redirect_args_match(const char *event_args,
const char *arg, int pos)
{
const char *start;
if (pos == -1)
return TRUE;
/* skip to the start of the wanted argument */
while (pos > 0 && *event_args != '\0') {
while (*event_args != ' ' && *event_args != '\0') event_args++;
while (*event_args == ' ') event_args++;
pos--;
}
/* now compare the arguments */
start = event_args;
while (*arg != '\0') {
while (*arg != '\0' && *arg != ' ' && *event_args != '\0') {
if (*arg != *event_args)
break;
arg++; event_args++;
}
if ((*arg == '\0' || *arg == ' ') &&
(*event_args == '\0' || *event_args == ' '))
return TRUE;
/* compare the next argument */
while (*arg != ' ' && *arg != '\0') arg++;
while (*arg == ' ') arg++;
event_args = start;
}
return FALSE;
}
static GSList *redirect_cmd_list_find(GSList *list, const char *event)
{
while (list != NULL) {
const char *str = list->data;
if (strcmp(str, event) == 0)
break;
list = list->next->next;
}
return list;
}
static const char *redirect_match(REDIRECT_REC *redirect, const char *event,
const char *args, int *match_stop)
{
GSList *tmp, *cmdpos;
int stop_signal;
for (tmp = redirect->signals; tmp != NULL; tmp = tmp->next->next) {
if (strcmp(tmp->data, event) != 0)
continue;
/* find the argument position */
cmdpos = redirect_cmd_list_find(redirect->cmd->start, event);
if (cmdpos != NULL)
stop_signal = FALSE;
else {
cmdpos = redirect_cmd_list_find(redirect->cmd->stop,
event);
stop_signal = cmdpos != NULL;
}
/* check that arguments match */
if (args != NULL && redirect->arg != NULL && cmdpos != NULL &&
!redirect_args_match(args, redirect->arg,
GPOINTER_TO_INT(cmdpos->next->data)))
continue;
*match_stop = stop_signal;
return tmp->next->data;
}
*match_stop = redirect_cmd_list_find(redirect->cmd->stop,
event) != NULL;
return NULL;
}
static REDIRECT_REC *redirect_find(IRC_SERVER_REC *server, const char *event,
const char *args, const char **signal,
int *match_stop)
{
REDIRECT_REC *redirect;
GSList *tmp, *next;
time_t now;
/* find the redirection */
*signal = NULL; redirect = NULL;
for (tmp = server->redirects; tmp != NULL; tmp = tmp->next) {
REDIRECT_REC *rec = tmp->data;
*signal = redirect_match(rec, event, args, match_stop);
if (*signal != NULL) {
redirect = rec;
break;
}
}
/* remove the destroyed, non-remote and timeouted remote
redirections that should have happened before this redirection */
now = time(NULL);
for (tmp = server->redirects; tmp != NULL; tmp = next) {
REDIRECT_REC *rec = tmp->data;
if (rec == redirect)
break;
next = tmp->next;
if (rec->destroyed ||
(rec->remote && (now-rec->created) > rec->cmd->timeout) ||
(redirect != NULL && !rec->remote)) {
server->redirects =
g_slist_remove(server->redirects, rec);
if (!rec->destroyed && rec->failure_signal != NULL) {
/* emit the failure signal */
signal_emit(rec->failure_signal, 1, server);
}
redirect_destroy(rec);
}
}
return redirect;
}
const char *server_redirect_get_signal(IRC_SERVER_REC *server,
const char *event,
const char *args)
{
REDIRECT_REC *redirect;
const char *signal;
int match_stop;
if (server->redirects == NULL)
return NULL;
if (server->redirect_continue == NULL) {
/* find the redirection */
redirect = redirect_find(server, event, args,
&signal, &match_stop);
} else {
/* redirection is already started, now we'll just need to
keep redirecting until stop-event is found. */
redirect = server->redirect_continue;
signal = redirect_match(redirect, event, NULL, &match_stop);
if (signal == NULL) {
/* unknown event - redirect to the default signal.
FIXME: if stop event isn't properly got, this
could break everything. Add some checks that if
we get eg. 10 different unknown events after this,
or if one of them matches to another redirection,
abort this. */
signal = redirect->default_signal;
}
}
if (!match_stop || redirect == NULL)
server->redirect_continue = redirect;
else {
/* stop event - remove this redirection next time this
function is called (can't destroy now or our return
value would be corrupted) */
redirect->destroyed = TRUE;
server->redirect_continue = NULL;
}
return signal;
}
static void sig_disconnected(IRC_SERVER_REC *server)
{
if (!IS_IRC_SERVER(server))
return;
g_slist_foreach(server->redirects, (GFunc) redirect_destroy, NULL);
g_slist_free(server->redirects);
if (server->redirect_next != NULL)
redirect_destroy(server->redirect_next);
}
static void cmd_redirect_destroy(char *key, REDIRECT_CMD_REC *cmd)
{
g_free(key);
redirect_cmd_unref(cmd);
}
void servers_redirect_init(void)
{
command_redirects = g_hash_table_new((GHashFunc) g_str_hash, (GCompareFunc) g_str_equal);
/* WHOIS - register as remote command by default
with a timeout of one minute */
server_redirect_register("whois", TRUE, 60,
"event 311", 1, /* Begins the WHOIS */
"event 401", 1, /* No such nick */
NULL,
"event 318", 1, /* End of WHOIS */
"event 402", 1, /* No such server */
NULL);
/* WHOWAS */
server_redirect_register("whowas", FALSE, 0,
"event 314", 1, /* Begins the WHOWAS */
"event 406", 1, /* There was no such nick */
NULL,
"event 369", 1, /* End of WHOWAS */
NULL);
/* WHO */
server_redirect_register("who", FALSE, 0,
"event 352", 1, /* Begins the WHO */
"event 401", 1, /* No such nick/channel */
NULL,
"event 315", 1, /* End of WHO */
"event 403", 1, /* no such channel */
NULL);
/* LIST */
server_redirect_register("list", FALSE, 0,
"event 321", 1, /* Begins the LIST */
NULL,
"event 323", 1, /* End of LIST */
NULL);
/* ISON */
server_redirect_register("ison", FALSE, 0,
NULL,
"event 303", 1, /* ISON */
NULL);
/* USERHOST */
server_redirect_register("userhost", FALSE, 0,
"event 401", 1, /* no such nick */
NULL,
"event 302", 1, /* Userhost */
"event 461", 1, /* Not enough parameters */
NULL);
/* MODE #channel */
server_redirect_register("mode channel", FALSE, 0,
NULL,
"event 324", 1, /* MODE-reply */
"event 403", 1, /* no such channel */
"event 442", 1, /* "you're not on that channel" */
"event 479", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */
NULL);
/* MODE #channel b */
server_redirect_register("mode b", FALSE, 0,
"event 367", 1,
NULL,
"event 368", 1, /* End of Channel ban List */
"event 403", 1, /* no such channel */
"event 442", 1, /* "you're not on that channel" */
"event 479", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */
NULL);
/* MODE #channel e */
server_redirect_register("mode e", FALSE, 0,
"event 348", 1,
NULL,
"event 349", 1, /* End of ban exceptions */
"event 482", 1, /* not channel operator - OPN's ircd doesn't want non-ops to see ban exceptions */
"event 403", 1, /* no such channel */
"event 442", 1, /* "you're not on that channel" */
"event 479", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */
"event 472", -1, /* unknown mode (you should check e-mode's existance from 004 event instead of relying on this) */
NULL);
/* MODE #channel I */
server_redirect_register("mode e", FALSE, 0,
"event 346", 1,
NULL,
"event 347", 1, /* End of invite list */
"event 403", 1, /* no such channel */
"event 442", 1, /* "you're not on that channel" */
"event 479", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */
"event 472", -1, /* unknown mode (you should check I-mode's existance from 004 event instead of relying on this) */
NULL);
/* PING */
server_redirect_register("ping", TRUE, 60,
NULL,
"event 402", -1, /* no such server */
"event pong", -1, /* PONG */
NULL);
signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected);
}
void servers_redirect_deinit(void)
{
g_hash_table_foreach(command_redirects,
(GHFunc) cmd_redirect_destroy, NULL);
g_hash_table_destroy(command_redirects);
signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
}

View File

@ -0,0 +1,66 @@
#ifndef __SERVERS_REDIRECT_H
#define __SERVERS_REDIRECT_H
/* Register new redirection command.
remote - Specifies if the command is by default a remote command
(eg. sent to another server). server_redirect_event() may override this.
timeout - If remote is TRUE, specifies how many seconds to wait for
reply before aborting.
... - char *start, int argpos, char *start, int argpos, ..., NULL,
char *stop, int argpos, char *stop, int argpos, ..., NULL
List of events that start and stop this redirection.
Start event list may be just NULL, but there must be at least one
stop event. `argpos' specifies the word number in event string which
is compared to wanted argument, -1 = don't compare, TRUE always. */
void server_redirect_register(const char *command,
int remote, int timeout, ...);
/* start/stop lists shouldn't be free'd after, and their strings
should be dynamically allocated */
void server_redirect_register_list(const char *command,
int remote, int timeout,
GSList *start, GSList *stop);
/* Specify that the next command sent to server will be redirected.
NOTE: This command MUST be called before irc_send_cmd().
command - Specifies the registered command that should be used for this
redirection.
arg - The argument to be compared in event strings. You can give multiple
arguments separated with space.
remote - Specifies if the command is a remote command, -1 = use default.
failure_signal - If irssi can't find the stop signal for the redirection,
this signal is called.
... - char *event, char *redirect_signal, ..., NULL
If the `event' is "", all the events belonging to the redirection but not
specified here, will be sent there. */
void server_redirect_event(IRC_SERVER_REC *server, const char *command,
const char *arg, int remote,
const char *failure_signal, ...);
/* Signals list shouldn't be free'd after, and it's strings should be
dynamically allocated */
void server_redirect_event_list(IRC_SERVER_REC *server, const char *command,
const char *arg, int remote,
const char *failure_signal, GSList *signals);
/* INTERNAL: */
/* irc_send_cmd() calls this to make sure redirecting knows
what's sent to server */
void server_redirect_command(IRC_SERVER_REC *server, const char *command);
/* Returns the redirection signal for specified event.
This is the function that contains the real redirecting logic. */
const char *server_redirect_get_signal(IRC_SERVER_REC *server,
const char *event,
const char *args);
void servers_redirect_init(void);
void servers_redirect_deinit(void);
#endif

View File

@ -3,8 +3,6 @@
#define MODULE_NAME "irc/notifylist"
#define ISON_EVENT "event 303"
typedef struct {
char *nick;
char *user, *host, *realname, *awaymsg;
@ -22,6 +20,8 @@ typedef struct {
} NOTIFY_NICK_REC;
typedef struct {
int ison_count; /* number of ISON requests sent */
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;

View File

@ -81,28 +81,19 @@ NOTIFY_NICK_REC *notify_nick_find(IRC_SERVER_REC *server, const char *nick)
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)
{
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", NULL, -1, NULL,
"event 303", "notifylist event", NULL);
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);
}
@ -111,6 +102,7 @@ static void ison_send(IRC_SERVER_REC *server, GString *cmd)
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;
@ -121,7 +113,8 @@ static void notifylist_timeout_server(IRC_SERVER_REC *server)
if (!IS_IRC_SERVER(server))
return;
if (!is_ison_queue_empty(server)) {
mserver = MODULE_DATA(server);
if (mserver->ison_count > 0) {
/* still not received all replies to previous /ISON commands.. */
return;
}
@ -184,16 +177,13 @@ static void whois_send(IRC_SERVER_REC *server, char *nicks)
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);
server_redirect_event(server, "whois", str, FALSE,
"notifylist event whois end",
"event 318", "notifylist event whois end",
"event 311", "notifylist event whois",
"event 301", "notifylist event whois away",
"event 317", "notifylist event whois idle",
"", "event empty", NULL);
g_free(str);
}
@ -311,7 +301,7 @@ static void event_ison(IRC_SERVER_REC *server, const char *data)
mserver = MODULE_DATA(server);
ison_save_users(mserver, online);
if (!is_ison_queue_empty(server)) {
if (--mserver->ison_count > 0) {
/* wait for the rest of the /ISON replies */
g_free(params);
return;

View File

@ -144,8 +144,10 @@ static void event_whois_end(IRC_SERVER_REC *server, const char *data)
if (event != NULL) {
signal_emit(event, 6, server, rec->nick,
rec->user, rec->host,
rec->realname, rec->awaymsg);
rec->user != NULL ? rec->user : "??",
rec->host != NULL ? rec->host : "??",
rec->realname != NULL ? rec->realname : "??",
rec->awaymsg);
}
rec->idle_ok = notify->idle_check_time <= 0 ||
rec->idle_time <= notify->idle_check_time;

View File

@ -196,8 +196,6 @@ static void notifylist_init_server(IRC_SERVER_REC *server)
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)

View File

@ -46,47 +46,6 @@ void
server_disconnect(server)
Irssi::Server server
void
server_redirect_init(server, command, last, ...)
Irssi::Server server
char *command
int last
PREINIT:
STRLEN n_a;
GSList *list;
int n;
CODE:
list = NULL;
for (n = 3; n < items; n++) {
list = g_slist_append(list, SvPV(ST(n), n_a));
}
server_redirect_initv(server, command, last, list);
int
server_redirect_single_event(server, arg, last, group, event, signal, argpos)
Irssi::Server server
char *arg
int last
int group
char *event
char *signal
int argpos
void
server_redirect_event(server, arg, last, ...)
Irssi::Server server
char *arg
int last
PREINIT:
STRLEN n_a;
int n, group;
CODE:
group = 0;
for (n = 3; n+3 <= items; n += 3, last--) {
group = server_redirect_single_event(server, arg, last > 0, group,
(char *) SvPV(ST(n), n_a), (char *) SvPV(ST(n+1), n_a), (int) SvIV(ST(n+2)));
}
int
isnickflag(server, flag)
Irssi::Server server

View File

@ -18,7 +18,6 @@
#include "chatnets.h"
#include "servers.h"
#include "servers-reconnect.h"
#include "servers-redirect.h"
#include "servers-setup.h"
#include "channels.h"
#include "queries.h"

View File

@ -35,6 +35,44 @@ ctcp_send_reply(server, data)
Irssi::Irc::Server server
char *data
MODULE = Irssi::Irc::Server PACKAGE = Irssi::Irc::Server PREFIX = server_
void
server_redirect_register(command, remote, timeout, ...)
char *command
int remote
int timeout
PREINIT:
STRLEN n_a;
GSList *start, *stop, **list;
int n;
CODE:
start = stop = NULL; list = &start;
for (n = 3; n < items; n++) {
if (ST(n) == &PL_sv_undef) list = &stop;
if (SvPOK(ST(n)))
*list = g_slist_append(*list, SvPV(ST(n), n_a));
}
server_redirect_register_list(command, remote, timeout, start, stop);
void
server_redirect_event(server, command, arg, remote, failure_signal, ...)
Irssi::Irc::Server server
char *command
char *arg
int remote
char *failure_signal
PREINIT:
STRLEN n_a;
GSList *list;
int n;
CODE:
list = NULL;
for (n = 5; n < items; n++) {
list = g_slist_append(list, SvPV(ST(n), n_a));
}
server_redirect_event_list(server, command, arg, remote, failure_signal, list);
MODULE = Irssi::Irc::Server PACKAGE = Irssi::Irc::Connect PREFIX = irc_server_
Irssi::Irc::Server

View File

@ -10,6 +10,7 @@
#include "modes.h"
#include "mode-lists.h"
#include "netsplit.h"
#include "servers-redirect.h"
#include "dcc/dcc.h"
#include "dcc/dcc-file.h"