Lots of moving stuff around - hopefully I didn't break too much :)

git-svn-id: http://svn.irssi.org/repos/irssi/trunk@632 dbcabf3a-b0e7-0310-adc4-f8d773084564
This commit is contained in:
Timo Sirainen 2000-08-26 15:39:44 +00:00 committed by cras
commit e395e87ded
160 changed files with 3954 additions and 2959 deletions

View file

@ -1,4 +1,4 @@
noinst_LTLIBRARIES = libcore.la
noinst_LIBRARIES = libcore.a
INCLUDES = \
$(GLIB_CFLAGS) \
@ -13,13 +13,17 @@ else
memdebug_src=
endif
libcore_la_SOURCES = \
libcore_a_SOURCES = \
args.c \
channels.c \
channels-setup.c \
commands.c \
chatnets.c \
core.c \
levels.c \
line-split.c \
log.c \
masks.c \
$(memdebug_src) \
misc.c \
modules.c \
@ -27,21 +31,38 @@ libcore_la_SOURCES = \
net-nonblock.c \
net-sendbuffer.c \
network.c \
nicklist.c \
pidwait.c \
queries.c \
rawlog.c \
server.c \
server-redirect.c \
servers.c \
servers-reconnect.c \
servers-redirect.c \
servers-setup.c \
settings.c \
signals.c \
special-vars.c
structure_headers = \
chatnet-rec.h \
channel-rec.h \
query-rec.h \
server-rec.h \
server-setup-rec.h \
server-connect-rec.h \
window-item-rec.h
noinst_HEADERS = \
args.h \
channels.h \
channels-setup.h \
commands.h \
chatnets.h \
core.h \
levels.h \
line-split.h \
log.h \
masks.h \
memdebug.h \
misc.h \
module.h \
@ -51,13 +72,19 @@ noinst_HEADERS = \
net-nonblock.h \
net-sendbuffer.h \
network.h \
nicklist.h \
pidwait.h \
queries.h \
rawlog.h \
server.h \
server-redirect.h \
servers.h \
servers-reconnect.h \
servers-redirect.h \
servers-setup.h \
settings.h \
signals.h \
special-vars.h
special-vars.h \
window-item-def.h \
$(structure_headers)
EXTRA_DIST = \
memdebug.c

21
src/core/channel-rec.h Normal file
View file

@ -0,0 +1,21 @@
/* CHANNEL_REC definition, used for inheritance */
#include "window-item-rec.h"
char *topic;
GHashTable *nicks; /* list of nicks */
int no_modes:1; /* channel doesn't support modes */
char *mode;
int limit; /* user limit */
char *key; /* password key */
int chanop:1; /* You're a channel operator */
int names_got:1; /* Received /NAMES list */
int wholist:1; /* WHO list got */
int synced:1; /* Channel synced - all queries done */
int joined:1; /* Have we even received JOIN event for this channel? */
int left:1; /* You just left the channel */
int kicked:1; /* You just got kicked */
int destroying:1;

170
src/core/channels-setup.c Normal file
View file

@ -0,0 +1,170 @@
/*
channels-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 "signals.h"
#include "lib-config/iconfig.h"
#include "settings.h"
#include "channels.h"
#include "channels-setup.h"
#include "servers-setup.h"
GSList *setupchannels;
static CHANNEL_SETUP_REC *channel_setup_read(CONFIG_NODE *node)
{
CHANNEL_SETUP_REC *rec;
char *channel, *password, *botmasks, *autosendcmd;
g_return_val_if_fail(node != NULL, NULL);
channel = config_node_get_str(node, "name", NULL);
if (channel == NULL) {
/* missing information.. */
return NULL;
}
password = config_node_get_str(node, "password", NULL);
botmasks = config_node_get_str(node, "botmasks", NULL);
autosendcmd = config_node_get_str(node, "autosendcmd", NULL);
rec = g_new(CHANNEL_SETUP_REC, 1);
rec->autojoin = config_node_get_bool(node, "autojoin", FALSE);
rec->name = g_strdup(channel);
rec->chatnet = g_strdup(config_node_get_str(node, "chatnet", NULL));
rec->password = (password == NULL || *password == '\0') ? NULL : g_strdup(password);
rec->botmasks = (botmasks == NULL || *botmasks == '\0') ? NULL : g_strdup(botmasks);
rec->autosendcmd = (autosendcmd == NULL || *autosendcmd == '\0') ? NULL : g_strdup(autosendcmd);
setupchannels = g_slist_append(setupchannels, rec);
signal_emit("channel setup created", 2, rec, node);
return rec;
}
static void channel_setup_save(CHANNEL_SETUP_REC *channel)
{
CONFIG_NODE *parentnode, *node;
int index;
index = g_slist_index(setupchannels, channel);
parentnode = iconfig_node_traverse("(channels", TRUE);
node = config_node_index(parentnode, index);
if (node == NULL)
node = config_node_section(parentnode, NULL, NODE_TYPE_BLOCK);
iconfig_node_clear(node);
iconfig_node_set_str(node, "name", channel->name);
iconfig_node_set_str(node, "chatnet", channel->chatnet);
if (channel->autojoin)
config_node_set_bool(node, "autojoin", TRUE);
iconfig_node_set_str(node, "password", channel->password);
iconfig_node_set_str(node, "botmasks", channel->botmasks);
iconfig_node_set_str(node, "autosendcmd", channel->autosendcmd);
}
static void channel_config_remove(CHANNEL_SETUP_REC *channel)
{
CONFIG_NODE *node;
node = iconfig_node_traverse("channels", FALSE);
if (node != NULL) iconfig_node_list_remove(node, g_slist_index(setupchannels, channel));
}
void channels_setup_create(CHANNEL_SETUP_REC *channel)
{
if (g_slist_find(setupchannels, channel) == NULL)
setupchannels = g_slist_append(setupchannels, channel);
channel_setup_save(channel);
signal_emit("channel setup created", 1, channel);
}
static void channels_setup_destroy_rec(CHANNEL_SETUP_REC *channel)
{
g_return_if_fail(channel != NULL);
setupchannels = g_slist_remove(setupchannels, channel);
signal_emit("channel setup destroyed", 1, channel);
g_free(channel->name);
g_free(channel->chatnet);
g_free_not_null(channel->password);
g_free_not_null(channel->botmasks);
g_free_not_null(channel->autosendcmd);
g_free(channel);
}
void channels_setup_destroy(CHANNEL_SETUP_REC *channel)
{
channel_config_remove(channel);
channels_setup_destroy_rec(channel);
}
CHANNEL_SETUP_REC *channels_setup_find(const char *channel, const char *chatnet)
{
GSList *tmp;
g_return_val_if_fail(channel != NULL, NULL);
for (tmp = setupchannels; tmp != NULL; tmp = tmp->next) {
CHANNEL_SETUP_REC *rec = tmp->data;
if (g_strcasecmp(rec->name, channel) == 0 &&
channel_chatnet_match(rec->chatnet, chatnet))
return rec;
}
return NULL;
}
static void channels_read_config(void)
{
CONFIG_NODE *node;
GSList *tmp;
while (setupchannels != NULL)
channels_setup_destroy_rec(setupchannels->data);
/* Read channels */
node = iconfig_node_traverse("channels", FALSE);
if (node != NULL) {
for (tmp = node->value; tmp != NULL; tmp = tmp->next)
channel_setup_read(tmp->data);
}
}
void channels_setup_init(void)
{
source_host_ok = FALSE;
signal_add("setup reread", (SIGNAL_FUNC) channels_read_config);
signal_add("irssi init read settings", (SIGNAL_FUNC) channels_read_config);
}
void channels_setup_deinit(void)
{
while (setupchannels != NULL)
channels_setup_destroy(setupchannels->data);
signal_remove("setup reread", (SIGNAL_FUNC) channels_read_config);
signal_remove("irssi init read settings", (SIGNAL_FUNC) channels_read_config);
}

33
src/core/channels-setup.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef __CHANNELS_SETUP_H
#define __CHANNELS_SETUP_H
#include "modules.h"
typedef struct {
char *name;
char *chatnet;
char *password;
char *botmasks;
char *autosendcmd;
int autojoin:1;
GHashTable *module_data;
} CHANNEL_SETUP_REC;
extern GSList *setupchannels;
void channels_setup_init(void);
void channels_setup_deinit(void);
void channels_setup_create(CHANNEL_SETUP_REC *channel);
void channels_setup_destroy(CHANNEL_SETUP_REC *channel);
CHANNEL_SETUP_REC *channels_setup_find(const char *channel,
const char *chatnet);
#define channel_chatnet_match(rec, chatnet) \
((rec) == NULL || (rec)[0] == '\0' || \
((chatnet) != NULL && g_strcasecmp(rec, chatnet) == 0))
#endif

116
src/core/channels.c Normal file
View file

@ -0,0 +1,116 @@
/*
channel.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 "channels.h"
typedef CHANNEL_REC *(*CHANNEL_FIND_FUNC)(SERVER_REC *, const char *);
GSList *channels; /* List of all channels */
void channel_init(CHANNEL_REC *channel, int automatic)
{
g_return_if_fail(channel != NULL);
g_return_if_fail(channel->name != NULL);
channels = g_slist_append(channels, channel);
if (channel->server != NULL) {
channel->server->channels =
g_slist_append(channel->server->channels, channel);
}
MODULE_DATA_INIT(channel);
channel->type = module_get_uniq_id("CHANNEL", 0);
channel->mode = g_strdup("");
channel->createtime = time(NULL);
signal_emit("channel created", 2, channel, GINT_TO_POINTER(automatic));
}
void channel_destroy(CHANNEL_REC *channel)
{
g_return_if_fail(IS_CHANNEL(channel));
if (channel->destroying) return;
channel->destroying = TRUE;
channels = g_slist_remove(channels, channel);
if (channel->server != NULL)
channel->server->channels = g_slist_remove(channel->server->channels, channel);
signal_emit("channel destroyed", 1, channel);
MODULE_DATA_DEINIT(channel);
g_free_not_null(channel->topic);
g_free_not_null(channel->key);
g_free(channel->name);
g_free(channel);
}
static CHANNEL_REC *channel_find_server(SERVER_REC *server,
const char *name)
{
GSList *tmp;
g_return_val_if_fail(IS_SERVER(server), NULL);
if (server->channel_find_func != NULL) {
/* use the server specific channel find function */
CHANNEL_FIND_FUNC channel_find_func;
channel_find_func =
(CHANNEL_FIND_FUNC) server->channel_find_func;
return channel_find_func(server, name);
}
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
CHANNEL_REC *rec = tmp->data;
if (rec->chat_type == server->channel_type &&
g_strcasecmp(name, rec->name) == 0)
return rec;
}
return NULL;
}
CHANNEL_REC *channel_find(SERVER_REC *server, const char *name)
{
g_return_val_if_fail(server == NULL || IS_SERVER(server), NULL);
g_return_val_if_fail(name != NULL, NULL);
if (server != NULL)
return channel_find_server(server, name);
/* find from any server */
return gslist_foreach_find(servers,
(FOREACH_FIND_FUNC) channel_find_server,
(void *) name);
}
void channels_init(void)
{
}
void channels_deinit(void)
{
module_uniq_destroy("CHANNEL");
}

31
src/core/channels.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef __CHANNELS_H
#define __CHANNELS_H
#include "servers.h"
#define IS_CHANNEL(channel) \
((channel) != NULL && \
module_find_id("CHANNEL", ((CHANNEL_REC *) (channel))->type) != -1)
/* Returns CHANNEL_REC if it's channel, NULL if it isn't. */
#define CHANNEL(channel) \
(IS_CHANNEL(channel) ? (CHANNEL_REC *) (channel) : NULL)
#define STRUCT_SERVER_REC SERVER_REC
typedef struct {
#include "channel-rec.h"
} CHANNEL_REC;
extern GSList *channels;
void channels_init(void);
void channels_deinit(void);
/* Create new channel record */
void channel_init(CHANNEL_REC *channel, int automatic);
void channel_destroy(CHANNEL_REC *channel);
/* find channel by name, if `server' is NULL, search from all servers */
CHANNEL_REC *channel_find(SERVER_REC *server, const char *name);
#endif

12
src/core/chatnet-rec.h Normal file
View file

@ -0,0 +1,12 @@
int type; /* should always be "CHATNET" */
int chat_type;
char *name;
char *nick;
char *username;
char *realname;
char *own_host; /* address to use when connecting this server */
char *autosendcmd; /* command to send after connecting to this ircnet */
IPADDR *own_ip; /* resolved own_address if not NULL */

148
src/core/chatnets.c Normal file
View file

@ -0,0 +1,148 @@
/*
chatnets.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 "network.h"
#include "signals.h"
#include "special-vars.h"
#include "lib-config/iconfig.h"
#include "settings.h"
#include "chatnets.h"
#include "servers.h"
GSList *chatnets; /* list of available chat networks */
void chatnet_read(CHATNET_REC *chatnet, void *nodep)
{
CONFIG_NODE *node = nodep;
g_return_if_fail(chatnet != NULL);
g_return_if_fail(node != NULL);
g_return_if_fail(node->key != NULL);
chatnet->type = module_get_uniq_id("CHATNET", 0);
chatnet->name = g_strdup(node->key);
chatnet->nick = g_strdup(config_node_get_str(node, "nick", NULL));
chatnet->username = g_strdup(config_node_get_str(node, "username", NULL));
chatnet->realname = g_strdup(config_node_get_str(node, "realname", NULL));
chatnet->own_host = g_strdup(config_node_get_str(node, "host", NULL));
chatnet->autosendcmd = g_strdup(config_node_get_str(node, "autosendcmd", NULL));
chatnets = g_slist_append(chatnets, chatnet);
}
void *chatnet_save(CHATNET_REC *chatnet, void *parentnode)
{
CONFIG_NODE *node = parentnode;
g_return_val_if_fail(parentnode != NULL, NULL);
g_return_val_if_fail(IS_CHATNET(chatnet), NULL);
node = config_node_section(node, chatnet->name, NODE_TYPE_BLOCK);
iconfig_node_clear(node);
iconfig_node_set_str(node, "nick", chatnet->nick);
iconfig_node_set_str(node, "username", chatnet->username);
iconfig_node_set_str(node, "realname", chatnet->realname);
iconfig_node_set_str(node, "host", chatnet->own_host);
iconfig_node_set_str(node, "autosendcmd", chatnet->autosendcmd);
return node;
}
void chatnet_create(CHATNET_REC *chatnet)
{
g_return_if_fail(chatnet != NULL);
chatnet->type = module_get_uniq_id("CHATNET", 0);
if (g_slist_find(chatnets, chatnet) == NULL)
chatnets = g_slist_append(chatnets, chatnet);
signal_emit("chatnet created", 1, chatnet);
}
void chatnet_remove(CHATNET_REC *chatnet)
{
g_return_if_fail(IS_CHATNET(chatnet));
signal_emit("chatnet removed", 1, chatnet);
chatnet_destroy(chatnet);
}
void chatnet_destroy(CHATNET_REC *chatnet)
{
g_return_if_fail(IS_CHATNET(chatnet));
chatnets = g_slist_remove(chatnets, chatnet);
signal_emit("chatnet destroyed", 1, chatnet);
g_free(chatnet->name);
g_free_not_null(chatnet->nick);
g_free_not_null(chatnet->username);
g_free_not_null(chatnet->realname);
g_free_not_null(chatnet->own_host);
g_free_not_null(chatnet->autosendcmd);
g_free(chatnet);
}
/* Find the irc network by name */
CHATNET_REC *chatnet_find(const char *name)
{
GSList *tmp;
g_return_val_if_fail(name != NULL, NULL);
for (tmp = chatnets; tmp != NULL; tmp = tmp->next) {
CHATNET_REC *rec = tmp->data;
if (g_strcasecmp(rec->name, name) == 0)
return rec;
}
return NULL;
}
static void sig_connected(SERVER_REC *server)
{
CHATNET_REC *rec;
g_return_if_fail(IS_SERVER(server));
if (server->connrec->chatnet == NULL)
return;
rec = chatnet_find(server->connrec->chatnet);
if (rec != NULL && rec->autosendcmd)
eval_special_string(rec->autosendcmd, "", server, NULL);
}
void chatnets_init(void)
{
signal_add("event connected", (SIGNAL_FUNC) sig_connected);
}
void chatnets_deinit(void)
{
while (chatnets != NULL)
chatnet_destroy(chatnets->data);
signal_remove("event connected", (SIGNAL_FUNC) sig_connected);
module_uniq_destroy("CHATNET");
}

37
src/core/chatnets.h Normal file
View file

@ -0,0 +1,37 @@
#ifndef __CHATNETS_H
#define __CHATNETS_H
#include "modules.h"
#define IS_CHATNET(chatnet) \
((chatnet) != NULL && \
module_find_id("CHATNET", (chatnet)->type) != -1)
/* Returns CHATNET_REC if it's chatnet, NULL if it isn't. */
#define CHATNET(chatnet) \
(IS_CHATNET(chatnet) ? (CHATNET_REC *) (chatnet) : NULL)
typedef struct {
#include "chatnet-rec.h"
} CHATNET_REC;
extern GSList *chatnets; /* list of available chat networks */
/* read/save to configuration file */
void chatnet_read(CHATNET_REC *chatnet, void *node);
void *chatnet_save(CHATNET_REC *chatnet, void *parentnode);
/* add the chatnet to chat networks list */
void chatnet_create(CHATNET_REC *chatnet);
/* remove the chatnet from chat networks list */
void chatnet_remove(CHATNET_REC *chatnet);
/* destroy the chatnet structure. doesn't remove from config file */
void chatnet_destroy(CHATNET_REC *chatnet);
/* Find the irc network by name */
CHATNET_REC *chatnet_find(const char *name);
void chatnets_init(void);
void chatnets_deinit(void);
#endif

View file

@ -19,12 +19,11 @@
*/
#include "module.h"
#include "modules.h"
#include "signals.h"
#include "commands.h"
#include "misc.h"
#include "server.h"
#include "server-redirect.h"
#include "servers.h"
#include "servers-redirect.h"
#include "special-vars.h"
#include "lib-config/iconfig.h"
@ -617,6 +616,8 @@ static void parse_command(const char *command, int expand_aliases,
const char *alias, *newcmd;
char *cmd, *orig, *args, *oldcmd;
g_return_if_fail(command != NULL);
cmd = orig = g_strconcat("command ", command, NULL);
args = strchr(cmd+8, ' ');
if (args != NULL) *args++ = '\0'; else args = "";
@ -643,7 +644,7 @@ static void parse_command(const char *command, int expand_aliases,
cmd = g_strconcat("command ", newcmd, NULL);
if (server != NULL)
server_redirect_default((SERVER_REC *) server, cmd);
server_redirect_default(SERVER(server), cmd);
g_strdown(cmd);
oldcmd = current_command;

View file

@ -1,7 +1,7 @@
/*
core.c : irssi
Copyright (C) 1999 Timo Sirainen
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
@ -20,7 +20,6 @@
#include "module.h"
#include "modules.h"
#include "pidwait.h"
#include "net-disconnect.h"
@ -28,12 +27,17 @@
#include "signals.h"
#include "settings.h"
#include "server.h"
#include "servers.h"
#include "chatnets.h"
#include "commands.h"
#include "log.h"
#include "rawlog.h"
#include "special-vars.h"
#include "channels.h"
#include "queries.h"
#include "nicklist.h"
int irssi_gui;
void core_init(void)
@ -47,18 +51,28 @@ void core_init(void)
settings_init();
commands_init();
chatnets_init();
servers_init();
log_init();
rawlog_init();
special_vars_init();
channels_init();
queries_init();
nicklist_init();
}
void core_deinit(void)
{
nicklist_deinit();
queries_deinit();
channels_deinit();
special_vars_deinit();
rawlog_deinit();
log_deinit();
servers_deinit();
chatnets_deinit();
commands_deinit();
settings_deinit();

137
src/core/masks.c Normal file
View file

@ -0,0 +1,137 @@
/*
masks.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 "network.h"
#include "misc.h"
#include "servers.h"
typedef int (*MASK_MATCH_FUNC) (const char *, const char *);
/* Returns TRUE if mask contains '!' ie. address should be checked too.
Also checks if mask contained any wildcards. */
static int check_address(const char *mask, int *wildcards)
{
int ret;
ret = FALSE;
while (*mask != '\0') {
if (*mask == '!') {
if (*wildcards) return TRUE;
ret = TRUE;
}
if (*mask == '?' || *mask == '*') {
*wildcards = TRUE;
if (ret) return TRUE;
}
mask++;
}
return ret;
}
static int check_mask(SERVER_REC *server, const char *mask,
const char *str, int wildcards)
{
MASK_MATCH_FUNC mask_match_func;
if (server != NULL && server->mask_match_func != NULL) {
/* use server specified mask match function */
mask_match_func = (MASK_MATCH_FUNC)server->mask_match_func;
return mask_match_func(mask, str);
}
return wildcards ? match_wildcards(mask, str) :
g_strcasecmp(mask, str) == 0;
}
int mask_match(SERVER_REC *server, const char *mask,
const char *nick, const char *user, const char *host)
{
char *str;
int ret, wildcards;
g_return_val_if_fail(server == NULL || IS_SERVER(server), FALSE);
g_return_val_if_fail(mask != NULL && nick != NULL &&
nick != NULL && host != NULL, FALSE);
str = !check_address(mask, &wildcards) ? (char *) nick :
g_strdup_printf("%s!%s@%s", nick, user, host);
ret = check_mask(server, mask, str, wildcards);
if (str != nick) g_free(str);
return ret;
}
int mask_match_address(SERVER_REC *server, const char *mask,
const char *nick, const char *address)
{
char *str;
int ret, wildcards;
g_return_val_if_fail(server == NULL || IS_SERVER(server), FALSE);
g_return_val_if_fail(mask != NULL && nick != NULL, FALSE);
if (address == NULL) address = "";
str = !check_address(mask, &wildcards) ? (char *) nick :
g_strdup_printf("%s!%s", nick, address);
ret = check_mask(server, mask, str, wildcards);
if (str != nick) g_free(str);
return ret;
}
int masks_match(SERVER_REC *server, const char *masks,
const char *nick, const char *address)
{
MASK_MATCH_FUNC mask_match_func;
char **list, **tmp, *mask;
int found;
g_return_val_if_fail(server == NULL || IS_SERVER(server), FALSE);
g_return_val_if_fail(masks != NULL &&
nick != NULL && address != NULL, FALSE);
mask_match_func = server != NULL && server->mask_match_func != NULL ?
(MASK_MATCH_FUNC) server->mask_match_func :
(MASK_MATCH_FUNC) match_wildcards;
found = FALSE;
mask = g_strdup_printf("%s!%s", nick, address);
list = g_strsplit(masks, " ", -1);
for (tmp = list; *tmp != NULL; tmp++) {
if (strchr(*tmp, '!') == NULL &&
g_strcasecmp(*tmp, nick) == 0) {
found = TRUE;
break;
}
if (mask_match_func(*tmp, mask)) {
found = TRUE;
break;
}
}
g_strfreev(list);
g_free(mask);
return found;
}

13
src/core/masks.h Normal file
View file

@ -0,0 +1,13 @@
#ifndef __MASKS_H
#define __MASKS_H
#include "servers.h"
int mask_match(SERVER_REC *server, const char *mask,
const char *nick, const char *user, const char *host);
int mask_match_address(SERVER_REC *server, const char *mask,
const char *nick, const char *address);
int masks_match(SERVER_REC *server, const char *masks,
const char *nick, const char *address);
#endif

View file

@ -38,7 +38,7 @@ typedef struct {
static GHashTable *data = NULL, *preallocs = NULL;
static const char *comment = "";
static void add_flow_checks(guchar *p, unsigned long size)
static void add_flow_checks(char *p, unsigned long size)
{
#ifdef ENABLE_BUFFER_CHECKS
int n;
@ -75,7 +75,7 @@ static void mem_check(void)
#endif
}
static void data_add(void *p, int size, const char *file, int line)
static void data_add(char *p, int size, const char *file, int line)
{
MEM_REC *rec;
@ -106,7 +106,19 @@ static void data_add(void *p, int size, const char *file, int line)
mem_check();
}
static void *data_remove(void *p, const char *file, int line)
static void data_clear(char *p)
{
MEM_REC *rec;
if (g_hash_table_lookup(preallocs, p) != NULL)
p += BUFFER_CHECK_SIZE;
rec = g_hash_table_lookup(data, p);
if (rec != NULL && rec->size > 0)
memset(p, 'F', rec->size);
}
static void *data_remove(char *p, const char *file, int line)
{
MEM_REC *rec;
@ -132,34 +144,34 @@ static void *data_remove(void *p, const char *file, int line)
void *ig_malloc(int size, const char *file, int line)
{
void *p;
char *p;
size += BUFFER_CHECK_SIZE*2;
p = g_malloc(size);
data_add(p, size, file, line);
return p+BUFFER_CHECK_SIZE;
return (void *) (p+BUFFER_CHECK_SIZE);
}
void *ig_malloc0(int size, const char *file, int line)
{
void *p;
char *p;
size += BUFFER_CHECK_SIZE*2;
p = g_malloc0(size);
data_add(p, size, file, line);
return p+BUFFER_CHECK_SIZE;
return (void *) (p+BUFFER_CHECK_SIZE);
}
void *ig_realloc(void *mem, unsigned long size, const char *file, int line)
{
void *p;
char *p, *oldmem = mem;
size += BUFFER_CHECK_SIZE*2;
mem -= BUFFER_CHECK_SIZE;
data_remove(mem, file, line);
p = g_realloc(mem, size);
oldmem -= BUFFER_CHECK_SIZE;
data_remove(oldmem, file, line);
p = g_realloc(oldmem, size);
data_add(p, size, file, line);
return p+BUFFER_CHECK_SIZE;
return (void *) (p+BUFFER_CHECK_SIZE);
}
char *ig_strdup(const char *str, const char *file, int line)
@ -252,11 +264,14 @@ char *ig_strdup_vprintf(const char *file, int line, const char *format, va_list
void ig_free(void *p)
{
if (p == NULL) g_error("ig_free() : trying to free NULL");
char *cp = p;
p -= BUFFER_CHECK_SIZE;
p = data_remove(p, "??", 0);
if (p != NULL) g_free(p);
if (cp == NULL) g_error("ig_free() : trying to free NULL");
cp -= BUFFER_CHECK_SIZE;
data_clear(cp);
cp = data_remove(cp, "??", 0);
if (cp != NULL) g_free(cp);
}
GString *ig_string_new(const char *file, int line, const char *str)
@ -264,13 +279,13 @@ GString *ig_string_new(const char *file, int line, const char *str)
GString *ret;
ret = g_string_new(str);
data_add(ret, INT_MIN, file, line);
data_add((void *) ret, INT_MIN, file, line);
return ret;
}
void ig_string_free(const char *file, int line, GString *str, gboolean freeit)
{
data_remove(str, file, line);
data_remove((void *) str, file, line);
if (!freeit)
data_add(str->str, INT_MIN, file, line);
@ -304,7 +319,7 @@ void ig_profile_line(void *key, MEM_REC *rec)
strcmp(rec->file, "ig_strdup_vprintf") == 0 ||
strcmp(rec->file, "ig_strconcat") == 0 ||
strcmp(rec->file, "ig_string_free (free = FALSE)") == 0))
data = rec->p + BUFFER_CHECK_SIZE;
data = (char *) rec->p + BUFFER_CHECK_SIZE;
else
data = rec->comment;
fprintf(stderr, "%s:%d %d bytes (%s)\n", rec->file, rec->line, rec->size, data);

View file

@ -196,12 +196,12 @@ GSList *gslist_find_icase_string(GSList *list, const char *key)
return NULL;
}
void *gslist_foreach_find(GSList *list, FOREACH_FIND_FUNC func, void *data)
void *gslist_foreach_find(GSList *list, FOREACH_FIND_FUNC func, const void *data)
{
void *ret;
while (list != NULL) {
ret = func(list->data, data);
ret = func(list->data, (void *) data);
if (ret != NULL) return ret;
list = list->next;

View file

@ -23,7 +23,7 @@ GSList *gslist_find_icase_string(GSList *list, const char *key);
GList *glist_find_string(GList *list, const char *key);
GList *glist_find_icase_string(GList *list, const char *key);
void *gslist_foreach_find(GSList *list, FOREACH_FIND_FUNC func, void *data);
void *gslist_foreach_find(GSList *list, FOREACH_FIND_FUNC func, const void *data);
/* `list' contains pointer to structure with a char* to string. */
char *gslistptr_to_string(GSList *list, int offset, const char *delimiter);

View file

@ -324,6 +324,11 @@ void module_unload(MODULE_REC *module)
g_free(module);
}
static void uniq_get_modules(char *key, void *value, GSList **list)
{
*list = g_slist_append(*list, key);
}
void modules_init(void)
{
modules = NULL;
@ -342,11 +347,19 @@ void modules_init(void)
void modules_deinit(void)
{
g_hash_table_foreach(idlookup, (GHFunc) module_uniq_destroy, NULL);
g_hash_table_destroy(idlookup);
g_hash_table_destroy(uniqids);
GSList *list;
g_hash_table_foreach(stridlookup, (GHFunc) module_uniq_destroy, NULL);
list = NULL;
g_hash_table_foreach(idlookup, (GHFunc) uniq_get_modules, &list);
g_hash_table_foreach(stridlookup, (GHFunc) uniq_get_modules, &list);
while (list != NULL) {
module_uniq_destroy(list->data);
list = g_slist_remove(list, list->data);
}
g_hash_table_destroy(idlookup);
g_hash_table_destroy(stridlookup);
g_hash_table_destroy(uniqids);
g_hash_table_destroy(uniqstrids);
}

268
src/core/nicklist.c Normal file
View file

@ -0,0 +1,268 @@
/*
nicklist.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 "nicklist.h"
#include "masks.h"
/* Add new nick to list */
NICK_REC *nicklist_insert(CHANNEL_REC *channel, const char *nick,
int op, int voice, int send_massjoin)
{
NICK_REC *rec;
g_return_val_if_fail(IS_CHANNEL(channel), NULL);
g_return_val_if_fail(nick != NULL, NULL);
rec = g_new0(NICK_REC, 1);
if (op) rec->op = TRUE;
if (voice) rec->voice = TRUE;
rec->send_massjoin = send_massjoin;
rec->nick = g_strdup(nick);
rec->host = NULL;
g_hash_table_insert(channel->nicks, rec->nick, rec);
signal_emit("nicklist new", 2, channel, rec);
return rec;
}
static void nicklist_destroy(CHANNEL_REC *channel, NICK_REC *nick)
{
signal_emit("nicklist remove", 2, channel, nick);
g_free(nick->nick);
g_free_not_null(nick->realname);
g_free_not_null(nick->host);
g_free(nick);
}
/* remove nick from list */
void nicklist_remove(CHANNEL_REC *channel, NICK_REC *nick)
{
g_return_if_fail(IS_CHANNEL(channel));
g_return_if_fail(nick != NULL);
g_hash_table_remove(channel->nicks, nick->nick);
nicklist_destroy(channel, nick);
}
static NICK_REC *nicklist_find_wildcards(CHANNEL_REC *channel,
const char *mask)
{
GSList *nicks, *tmp;
NICK_REC *nick;
nicks = nicklist_getnicks(channel);
nick = NULL;
for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
nick = tmp->data;
if (mask_match_address(channel->server, mask,
nick->nick, nick->host))
break;
}
g_slist_free(nicks);
return tmp == NULL ? NULL : nick;
}
GSList *nicklist_find_multiple(CHANNEL_REC *channel, const char *mask)
{
GSList *nicks, *tmp, *next;
g_return_val_if_fail(IS_CHANNEL(channel), NULL);
g_return_val_if_fail(mask != NULL, NULL);
nicks = nicklist_getnicks(channel);
for (tmp = nicks; tmp != NULL; tmp = next) {
NICK_REC *nick = tmp->data;
next = tmp->next;
if (!mask_match_address(channel->server, mask,
nick->nick, nick->host))
nicks = g_slist_remove(nicks, tmp->data);
}
return nicks;
}
/* Find nick record from list */
NICK_REC *nicklist_find(CHANNEL_REC *channel, const char *mask)
{
NICK_REC *nickrec;
char *nick, *host;
g_return_val_if_fail(IS_CHANNEL(channel), NULL);
g_return_val_if_fail(mask != NULL, NULL);
nick = g_strdup(mask);
host = strchr(nick, '!');
if (host != NULL) *host++ = '\0';
if (strchr(nick, '*') || strchr(nick, '?')) {
g_free(nick);
return nicklist_find_wildcards(channel, mask);
}
nickrec = g_hash_table_lookup(channel->nicks, nick);
if (nickrec != NULL && host != NULL &&
(nickrec->host == NULL || !match_wildcards(host, nickrec->host))) {
/* hosts didn't match */
nickrec = NULL;
}
g_free(nick);
return nickrec;
}
static void get_nicks_hash(gpointer key, NICK_REC *rec, GSList **list)
{
*list = g_slist_append(*list, rec);
}
/* Get list of nicks */
GSList *nicklist_getnicks(CHANNEL_REC *channel)
{
GSList *list;
g_return_val_if_fail(IS_CHANNEL(channel), NULL);
list = NULL;
g_hash_table_foreach(channel->nicks, (GHFunc) get_nicks_hash, &list);
return list;
}
typedef struct {
CHANNEL_REC *channel;
const char *nick;
GSList *list;
} NICKLIST_GET_SAME_REC;
static void get_nicks_same_hash(gpointer key, NICK_REC *nick,
NICKLIST_GET_SAME_REC *rec)
{
if (g_strcasecmp(nick->nick, rec->nick) == 0) {
rec->list = g_slist_append(rec->list, rec->channel);
rec->list = g_slist_append(rec->list, nick);
}
}
GSList *nicklist_get_same(SERVER_REC *server, const char *nick)
{
NICKLIST_GET_SAME_REC rec;
GSList *tmp;
g_return_val_if_fail(IS_SERVER(server), NULL);
rec.nick = nick;
rec.list = NULL;
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
rec.channel = tmp->data;
g_hash_table_foreach(rec.channel->nicks,
(GHFunc) get_nicks_same_hash, &rec);
}
return rec.list;
}
/* nick record comparision for sort functions */
int nicklist_compare(NICK_REC *p1, NICK_REC *p2)
{
if (p1 == NULL) return -1;
if (p2 == NULL) return 1;
if (p1->op && !p2->op) return -1;
if (!p1->op && p2->op) return 1;
if (!p1->op) {
if (p1->voice && !p2->voice) return -1;
if (!p1->voice && p2->voice) return 1;
}
return g_strcasecmp(p1->nick, p2->nick);
}
void nicklist_update_flags(SERVER_REC *server, const char *nick,
int gone, int serverop)
{
GSList *nicks, *tmp;
CHANNEL_REC *channel;
NICK_REC *rec;
g_return_if_fail(IS_SERVER(server));
g_return_if_fail(nick != NULL);
nicks = nicklist_get_same(server, nick);
for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
channel = tmp->data;
rec = tmp->next->data;
rec->last_check = time(NULL);
if (gone != -1 && rec->gone != gone) {
rec->gone = gone;
signal_emit("nick gone changed", 2, channel, rec);
}
if (serverop != -1 && rec->serverop != serverop) {
rec->serverop = serverop;
signal_emit("nick serverop changed", 2, channel, rec);
}
}
g_slist_free(nicks);
}
static void sig_channel_created(CHANNEL_REC *channel)
{
g_return_if_fail(IS_CHANNEL(channel));
channel->nicks = g_hash_table_new((GHashFunc) g_istr_hash,
(GCompareFunc) g_istr_equal);
}
static void nicklist_remove_hash(gpointer key, NICK_REC *nick,
CHANNEL_REC *channel)
{
nicklist_destroy(channel, nick);
}
static void sig_channel_destroyed(CHANNEL_REC *channel)
{
g_return_if_fail(IS_CHANNEL(channel));
g_hash_table_foreach(channel->nicks,
(GHFunc) nicklist_remove_hash, channel);
g_hash_table_destroy(channel->nicks);
}
void nicklist_init(void)
{
signal_add_first("channel created", (SIGNAL_FUNC) sig_channel_created);
signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
}
void nicklist_deinit(void)
{
signal_remove("channel created", (SIGNAL_FUNC) sig_channel_created);
signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
}

50
src/core/nicklist.h Normal file
View file

@ -0,0 +1,50 @@
#ifndef __NICKLIST_H
#define __NICKLIST_H
#include "servers.h"
#include "channels.h"
typedef struct {
time_t last_check; /* last time gone was checked */
char *nick;
char *host;
char *realname;
int hops;
/* status in server */
int gone:1;
int serverop:1;
/* status in channel */
int send_massjoin:1; /* Waiting to be sent in massjoin signal */
int op:1;
int halfop:1;
int voice:1;
} NICK_REC;
/* Add new nick to list */
NICK_REC *nicklist_insert(CHANNEL_REC *channel, const char *nick,
int op, int voice, int send_massjoin);
/* remove nick from list */
void nicklist_remove(CHANNEL_REC *channel, NICK_REC *nick);
/* Find nick record from list */
NICK_REC *nicklist_find(CHANNEL_REC *channel, const char *mask);
/* Get list of nicks that match the mask */
GSList *nicklist_find_multiple(CHANNEL_REC *channel, const char *mask);
/* Get list of nicks */
GSList *nicklist_getnicks(CHANNEL_REC *channel);
/* Get all the nick records of `nick'. Returns channel, nick, channel, ... */
GSList *nicklist_get_same(SERVER_REC *server, const char *nick);
/* Update specified nick's status in server. */
void nicklist_update_flags(SERVER_REC *server, const char *nick,
int gone, int ircop);
/* Nick record comparision for sort functions */
int nicklist_compare(NICK_REC *p1, NICK_REC *p2);
void nicklist_init(void);
void nicklist_deinit(void);
#endif

124
src/core/queries.c Normal file
View file

@ -0,0 +1,124 @@
/*
queries.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 "queries.h"
GSList *queries;
typedef QUERY_REC *(*QUERY_FIND_FUNC)(SERVER_REC *, const char *);
void query_init(QUERY_REC *query, int automatic)
{
g_return_if_fail(query != NULL);
g_return_if_fail(query->name != NULL);
queries = g_slist_append(queries, query);
if (query->server != NULL) {
query->server->queries =
g_slist_append(query->server->queries, query);
}
MODULE_DATA_INIT(query);
query->type = module_get_uniq_id("QUERY", 0);
if (query->server != NULL)
query->server_tag = g_strdup(query->server->tag);
signal_emit("query created", 2, query, GINT_TO_POINTER(automatic));
}
void query_destroy(QUERY_REC *query)
{
g_return_if_fail(IS_QUERY(query));
if (query->destroying) return;
query->destroying = TRUE;
queries = g_slist_remove(queries, query);
if (query->server != NULL) {
query->server->queries =
g_slist_remove(query->server->queries, query);
}
signal_emit("query destroyed", 1, query);
MODULE_DATA_DEINIT(query);
g_free_not_null(query->address);
g_free(query->name);
g_free(query->server_tag);
g_free(query);
}
static QUERY_REC *query_find_server(SERVER_REC *server, const char *nick)
{
GSList *tmp;
g_return_val_if_fail(IS_SERVER(server), NULL);
if (server->query_find_func != NULL) {
/* use the server specific query find function */
QUERY_FIND_FUNC query_find_func;
query_find_func = (QUERY_FIND_FUNC) server->query_find_func;
return query_find_func(server, nick);
}
for (tmp = server->queries; tmp != NULL; tmp = tmp->next) {
QUERY_REC *rec = tmp->data;
if (rec->chat_type == server->query_type &&
g_strcasecmp(nick, rec->name) == 0)
return rec;
}
return NULL;
}
QUERY_REC *query_find(SERVER_REC *server, const char *nick)
{
g_return_val_if_fail(server == NULL || IS_SERVER(server), NULL);
g_return_val_if_fail(nick != NULL, NULL);
if (server != NULL)
return query_find_server(server, nick);
/* find from any server */
return gslist_foreach_find(servers,
(FOREACH_FIND_FUNC) query_find_server,
(void *) nick);
}
void query_change_server(QUERY_REC *query, SERVER_REC *server)
{
g_return_if_fail(IS_QUERY(query));
query->server = server;
signal_emit("query server changed", 2, query, server);
}
void queries_init(void)
{
}
void queries_deinit(void)
{
module_uniq_destroy("QUERY");
}

32
src/core/queries.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef __QUERIES_H
#define __QUERIES_H
#include "servers.h"
#define IS_QUERY(query) \
((query) != NULL && \
module_find_id("QUERY", ((QUERY_REC *) (query))->type) != -1)
/* Returns QUERY_REC if it's query, NULL if it isn't. */
#define QUERY(query) \
(IS_QUERY(query) ? (QUERY_REC *) (query) : NULL)
#define STRUCT_SERVER_REC SERVER_REC
typedef struct {
#include "query-rec.h"
} QUERY_REC;
extern GSList *queries;
void query_init(QUERY_REC *query, int automatic);
void query_destroy(QUERY_REC *query);
/* Find query by name, if `server' is NULL, search from all servers */
QUERY_REC *query_find(SERVER_REC *server, const char *nick);
void query_change_server(QUERY_REC *query, SERVER_REC *server);
void queries_init(void);
void queries_deinit(void);
#endif

9
src/core/query-rec.h Normal file
View file

@ -0,0 +1,9 @@
/* QUERY_REC definition, used for inheritance */
#include "window-item-rec.h"
char *address;
char *server_tag;
int unwanted:1; /* TRUE if the other side closed or
some error occured (DCC chats!) */
int destroying:1;

View file

@ -0,0 +1,26 @@
/* SERVER_CONNECT_REC definition, used for inheritance */
int type;
int chat_type;
/* if we're connecting via proxy, or just NULLs */
char *proxy;
int proxy_port;
char *proxy_string;
char *address;
int port;
char *chatnet;
IPADDR *own_ip;
char *password;
char *nick;
char *username;
char *realname;
/* when reconnecting, the old server status */
int reconnection:1; /* we're trying to reconnect */
char *channels;
char *away_reason;
char *usermode;

50
src/core/server-rec.h Normal file
View file

@ -0,0 +1,50 @@
/* SERVER_REC definition, used for inheritance */
int type; /* should always be "SERVER" */
int chat_type;
STRUCT_SERVER_CONNECT_REC *connrec;
time_t connect_time; /* connection time */
time_t real_connect_time; /* time when server replied that we really are connected */
char *tag; /* tag name for addressing server */
char *nick; /* current nick */
int connected:1; /* connected to server */
int connection_lost:1; /* Connection lost unintentionally */
void *handle; /* NET_SENDBUF_REC socket */
int readtag; /* input tag */
/* for net_connect_nonblock() */
int 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* */
void *rawlog;
void *buffer; /* receive buffer */
GHashTable *module_data;
char *version; /* server version */
char *away_reason;
int server_operator:1;
int usermode_away:1;
int banned:1; /* not allowed to connect to this server */
GSList *channels;
GSList *queries;
/* support for multiple server types */
void *channel_find_func;
void *query_find_func;
int channel_type;
int query_type;
void *mask_match_func;
#undef STRUCT_SERVER_CONNECT_REC

View file

@ -0,0 +1,19 @@
int type;
int chat_type;
char *chatnet;
char *address;
int port;
char *password;
char *own_host; /* address to use when connecting this server */
IPADDR *own_ip; /* resolved own_address if not NULL */
time_t last_connect; /* to avoid reconnecting too fast.. */
int autoconnect:1;
int last_failed:1; /* if last connection attempt failed */
int banned:1; /* if we're banned from this server */
GHashTable *module_data;

View file

@ -1,83 +0,0 @@
#ifndef __SERVER_H
#define __SERVER_H
#ifndef __NETWORK_H
typedef struct _ipaddr IPADDR;
#endif
/* all strings should be either NULL or dynamically allocated */
/* address and nick are mandatory, rest are optional */
typedef struct {
/* if we're connecting via proxy, or just NULLs */
char *proxy;
int proxy_port;
char *proxy_string;
char *address;
int port;
char *ircnet;
IPADDR *own_ip;
char *password;
char *nick;
char *username;
char *realname;
/* when reconnecting, the old server status */
int reconnection:1; /* we're trying to reconnect */
char *channels;
char *away_reason;
char *usermode;
} SERVER_CONNECT_REC;
typedef struct {
int type; /* server type */
SERVER_CONNECT_REC *connrec;
time_t connect_time; /* connection time */
time_t real_connect_time; /* time when server replied that we really are connected */
char *tag; /* tag name for addressing server */
char *nick; /* current nick */
int connected:1; /* connected to server */
int connection_lost:1; /* Connection lost unintentionally */
void *handle; /* NET_SENDBUF_REC socket */
int readtag; /* input tag */
/* for net_connect_nonblock() */
int 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* */
void *rawlog;
void *buffer; /* receive buffer */
GHashTable *module_data;
char *version; /* server version */
char *away_reason;
int usermode_away:1;
int banned:1; /* not allowed to connect to this server */
} SERVER_REC;
extern GSList *servers, *lookup_servers;
/* Connect to server */
int server_connect(SERVER_REC *server);
/* Disconnect from server */
void server_disconnect(SERVER_REC *server);
SERVER_REC *server_find_tag(const char *tag);
SERVER_REC *server_find_ircnet(const char *ircnet);
void servers_init(void);
void servers_deinit(void);
#endif

View file

@ -0,0 +1,356 @@
/*
servers-reconnect.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 "commands.h"
#include "network.h"
#include "signals.h"
#include "servers-setup.h"
#include "servers-reconnect.h"
#include "settings.h"
GSList *reconnects;
static int last_reconnect_tag;
static int reconnect_timeout_tag;
static int reconnect_time;
static void server_reconnect_add(SERVER_CONNECT_REC *conn,
time_t next_connect)
{
RECONNECT_REC *rec;
g_return_if_fail(IS_SERVER_CONNECT(conn));
rec = g_new(RECONNECT_REC, 1);
rec->tag = ++last_reconnect_tag;
rec->conn = conn;
rec->next_connect = next_connect;
reconnects = g_slist_append(reconnects, rec);
}
static void server_reconnect_destroy(RECONNECT_REC *rec, int free_conn)
{
g_return_if_fail(rec != NULL);
reconnects = g_slist_remove(reconnects, rec);
signal_emit("server reconnect remove", 1, rec);
if (free_conn) server_connect_free(rec->conn);
g_free(rec);
if (reconnects == NULL)
last_reconnect_tag = 0;
}
static int server_reconnect_timeout(void)
{
SERVER_CONNECT_REC *conn;
GSList *list, *tmp;
time_t now;
/* If server_connect() removes the next reconnection in queue,
we're screwed. I don't think this should happen anymore, but just
to be sure we don't crash, do this safely. */
list = g_slist_copy(reconnects);
now = time(NULL);
for (tmp = list; tmp != NULL; tmp = tmp->next) {
RECONNECT_REC *rec = tmp->data;
if (g_slist_find(reconnects, rec) == NULL)
continue;
if (rec->next_connect <= now) {
conn = rec->conn;
server_reconnect_destroy(rec, FALSE);
server_connect(conn);
}
}
g_slist_free(list);
return 1;
}
static void sserver_connect(SERVER_SETUP_REC *rec, SERVER_CONNECT_REC *conn)
{
conn->address = g_strdup(rec->address);
conn->port = rec->port;
server_setup_fill_reconn(conn, rec);
if (rec->last_connect > time(NULL)-reconnect_time) {
/* can't reconnect this fast, wait.. */
server_reconnect_add(conn, rec->last_connect+reconnect_time);
} else {
/* connect to server.. */
server_connect(conn);
}
}
static SERVER_CONNECT_REC *
server_connect_copy_skeleton(SERVER_CONNECT_REC *src)
{
SERVER_CONNECT_REC *dest;
dest = NULL;
signal_emit("server connect copy", 2, &dest, src);
g_return_val_if_fail(dest != NULL, NULL);
dest->proxy = g_strdup(src->proxy);
dest->proxy_port = src->proxy_port;
dest->proxy_string = g_strdup(src->proxy_string);
dest->chatnet = g_strdup(src->chatnet);
dest->nick = g_strdup(src->nick);
dest->username = g_strdup(src->username);
dest->realname = g_strdup(src->realname);
if (src->own_ip != NULL) {
dest->own_ip = g_new(IPADDR, 1);
memcpy(dest->own_ip, src->own_ip, sizeof(IPADDR));
}
dest->channels = g_strdup(src->channels);
dest->away_reason = g_strdup(src->away_reason);
return dest;
}
#define server_should_reconnect(server) \
((server)->connection_lost && \
((server)->connrec->chatnet != NULL || !(server)->banned))
static void sig_reconnect(SERVER_REC *server)
{
SERVER_CONNECT_REC *conn;
SERVER_SETUP_REC *sserver;
GSList *tmp;
int found, through;
time_t now;
g_return_if_fail(IS_SERVER(server));
if (reconnect_time == -1 || !server_should_reconnect(server))
return;
conn = server_connect_copy_skeleton(server->connrec);
/* save the server status */
if (server->connected) {
conn->reconnection = TRUE;
g_free_not_null(conn->away_reason);
conn->away_reason = !server->usermode_away ? NULL :
g_strdup(server->away_reason);
signal_emit("server reconnect save status", 2, conn, server);
}
sserver = server_setup_find(server->connrec->address,
server->connrec->port);
if (sserver != NULL) {
/* save the last connection time/status */
sserver->last_connect = server->connect_time == 0 ?
time(NULL) : server->connect_time;
sserver->last_failed = !server->connected;
if (server->banned) sserver->banned = TRUE;
}
if (sserver == NULL || conn->chatnet == NULL) {
/* not in any chatnet, just reconnect back to same server */
conn->address = g_strdup(server->connrec->address);
conn->port = server->connrec->port;
conn->password = server->connrec->password == NULL ? NULL :
g_strdup(server->connrec->password);
if (server->connect_time != 0 &&
time(NULL)-server->connect_time > reconnect_time) {
/* there's been enough time since last connection,
reconnect back immediately */
server_connect(conn);
} else {
/* reconnect later.. */
server_reconnect_add(conn, (server->connect_time == 0 ? time(NULL) :
server->connect_time) + reconnect_time);
}
return;
}
/* always try to first connect to the first on the list where we
haven't got unsuccessful connection attempts for the last half
an hour. */
now = time(NULL);
for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
SERVER_SETUP_REC *rec = tmp->data;
if (rec->chatnet != NULL && g_strcasecmp(conn->chatnet, rec->chatnet) == 0 &&
!rec->banned && (!rec->last_connect || !rec->last_failed ||
rec->last_connect < now-FAILED_RECONNECT_WAIT)) {
sserver_connect(rec, conn);
return;
}
}
/* just try the next server in list */
found = through = FALSE;
for (tmp = setupservers; tmp != NULL; ) {
SERVER_SETUP_REC *rec = tmp->data;
if (!found && g_strcasecmp(rec->address, server->connrec->address) == 0 &&
server->connrec->port == rec->port)
found = TRUE;
else if (found && !rec->banned && rec->chatnet != NULL &&
g_strcasecmp(conn->chatnet, rec->chatnet) == 0) {
sserver_connect(rec, conn);
break;
}
if (tmp->next != NULL) {
tmp = tmp->next;
continue;
}
if (through) {
/* shouldn't happen unless there's no servers in
this chatnet in setup.. */
server_connect_free(conn);
break;
}
tmp = setupservers;
found = through = TRUE;
}
}
/* Remove all servers from reconnect list */
/* SYNTAX: RMRECONNS */
static void cmd_rmreconns(void)
{
while (reconnects != NULL)
server_reconnect_destroy(reconnects->data, TRUE);
}
static RECONNECT_REC *reconnect_find_tag(int tag)
{
GSList *tmp;
for (tmp = reconnects; tmp != NULL; tmp = tmp->next) {
RECONNECT_REC *rec = tmp->data;
if (rec->tag == tag)
return rec;
}
return NULL;
}
/* Try to reconnect immediately */
/* SYNTAX: RECONNECT <tag> */
static void cmd_reconnect(const char *data, SERVER_REC *server)
{
SERVER_CONNECT_REC *conn;
RECONNECT_REC *rec;
char *str;
int tag;
if (*data == '\0') {
/* reconnect back to same server */
if (server == NULL) cmd_return_error(CMDERR_NOT_CONNECTED);
str = g_strdup_printf("%s %d %s %s", server->connrec->address,
server->connrec->port, server->connrec->password,
server->connrec->nick);
signal_emit("command server", 2, str, server);
g_free(str);
return;
}
if (g_strncasecmp(data, "RECON-", 6) == 0)
data += 6;
tag = atoi(data);
rec = tag <= 0 ? NULL : reconnect_find_tag(tag);
if (rec == NULL)
signal_emit("server reconnect not found", 1, data);
else {
conn = rec->conn;
server_reconnect_destroy(rec, FALSE);
server_connect(conn);
}
}
static void cmd_disconnect(const char *data, SERVER_REC *server)
{
RECONNECT_REC *rec;
int tag;
if (g_strncasecmp(data, "RECON-", 6) != 0)
return; /* handle only reconnection removing */
rec = sscanf(data+6, "%d", &tag) == 1 && tag > 0 ?
reconnect_find_tag(tag) : NULL;
if (rec == NULL)
signal_emit("server reconnect not found", 1, data);
else
server_reconnect_destroy(rec, TRUE);
signal_stop();
}
static void read_settings(void)
{
reconnect_time = settings_get_int("server_reconnect_time");
}
void servers_reconnect_init(void)
{
settings_add_int("server", "server_reconnect_time", 300);
reconnects = NULL;
last_reconnect_tag = 0;
reconnect_timeout_tag = g_timeout_add(1000, (GSourceFunc) server_reconnect_timeout, NULL);
read_settings();
signal_add("server connect failed", (SIGNAL_FUNC) sig_reconnect);
signal_add("server disconnected", (SIGNAL_FUNC) sig_reconnect);
command_bind("rmreconns", NULL, (SIGNAL_FUNC) cmd_rmreconns);
command_bind("reconnect", NULL, (SIGNAL_FUNC) cmd_reconnect);
command_bind_first("disconnect", NULL, (SIGNAL_FUNC) cmd_disconnect);
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
}
void servers_reconnect_deinit(void)
{
g_source_remove(reconnect_timeout_tag);
while (reconnects != NULL)
server_reconnect_destroy(reconnects->data, TRUE);
signal_remove("server connect failed", (SIGNAL_FUNC) sig_reconnect);
signal_remove("server disconnected", (SIGNAL_FUNC) sig_reconnect);
command_unbind("rmreconns", (SIGNAL_FUNC) cmd_rmreconns);
command_unbind("reconnect", (SIGNAL_FUNC) cmd_reconnect);
command_unbind("disconnect", (SIGNAL_FUNC) cmd_disconnect);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
}

View file

@ -0,0 +1,20 @@
#ifndef __SERVER_RECONNECT_H
#define __SERVER_RECONNECT_H
/* wait for half an hour before trying to reconnect to host where last
connection failed */
#define FAILED_RECONNECT_WAIT (60*30)
typedef struct {
int tag;
time_t next_connect;
SERVER_CONNECT_REC *conn;
} RECONNECT_REC;
extern GSList *reconnects;
void servers_reconnect_init(void);
void servers_reconnect_deinit(void);
#endif

View file

@ -22,8 +22,8 @@
#include "signals.h"
#include "misc.h"
#include "server.h"
#include "server-redirect.h"
#include "servers.h"
#include "servers-redirect.h"
static int redirect_group;
@ -60,7 +60,7 @@ static void server_cmdtable_destroy(char *key, REDIRECT_CMD_REC *value)
static void sig_disconnected(SERVER_REC *server)
{
g_return_if_fail(server != NULL);
g_return_if_fail(IS_SERVER(server));
if (server->eventtable != NULL) {
g_hash_table_foreach(server->eventtable,
@ -84,7 +84,7 @@ void server_redirect_initv(SERVER_REC *server, const char *command,
{
REDIRECT_CMD_REC *rec;
g_return_if_fail(server != NULL);
g_return_if_fail(IS_SERVER(server));
g_return_if_fail(command != NULL);
g_return_if_fail(last > 0);
@ -125,7 +125,7 @@ int server_redirect_single_event(SERVER_REC *server, const char *arg,
GSList *list, *grouplist;
char *origkey;
g_return_val_if_fail(server != NULL, 0);
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);
@ -171,7 +171,7 @@ void server_redirect_event(SERVER_REC *server, const char *arg, int last, ...)
char *event, *signal;
int argpos, group;
g_return_if_fail(server != NULL);
g_return_if_fail(IS_SERVER(server));
va_start(args, last);
@ -197,7 +197,7 @@ void server_redirect_default(SERVER_REC *server, const char *command)
char *event, *origkey;
int last;
g_return_if_fail(server != NULL);
g_return_if_fail(IS_SERVER(server));
g_return_if_fail(command != NULL);
if (server->cmdtable == NULL)
@ -245,7 +245,7 @@ void server_redirect_remove_next(SERVER_REC *server, const char *event,
char *origkey;
int group;
g_return_if_fail(server != NULL);
g_return_if_fail(IS_SERVER(server));
g_return_if_fail(event != NULL);
if (!g_hash_table_lookup_extended(server->eventtable, event,
@ -321,6 +321,9 @@ GSList *server_redirect_getqueue(SERVER_REC *server, const char *event,
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) {
@ -328,7 +331,7 @@ GSList *server_redirect_getqueue(SERVER_REC *server, const char *event,
if (rec->argpos == -1)
break;
if (rec->arg == NULL)
if (rec->arg == NULL || args == NULL)
continue;
/* we need to check that the argument is right.. */

View file

@ -1,7 +1,7 @@
#ifndef __SERVER_REDIRECT_H
#define __SERVER_REDIRECT_H
#ifndef __SERVERS_REDIRECT_H
#define __SERVERS_REDIRECT_H
#include "server.h"
#include "servers.h"
typedef struct {
int last; /* number of "last" events at the start of the events list */

456
src/core/servers-setup.c Normal file
View file

@ -0,0 +1,456 @@
/*
servers-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 "signals.h"
#include "network.h"
#include "lib-config/iconfig.h"
#include "settings.h"
#include "servers.h"
#include "servers-setup.h"
#include "chatnets.h"
GSList *setupservers;
int source_host_ok; /* Use source_host_ip .. */
IPADDR *source_host_ip; /* Resolved address */
static void get_source_host_ip(void)
{
IPADDR ip;
if (source_host_ok)
return;
/* FIXME: This will block! */
source_host_ok = *settings_get_str("hostname") != '\0' &&
net_gethostbyname(settings_get_str("hostname"), &ip) == 0;
if (source_host_ok) {
if (source_host_ip == NULL)
source_host_ip = g_new(IPADDR, 1);
memcpy(source_host_ip, &ip, sizeof(IPADDR));
}
}
static void conn_set_ip(SERVER_CONNECT_REC *conn,
IPADDR **own_ip, const char *own_host)
{
IPADDR ip;
if (*own_ip != NULL) {
/* use already resolved IP */
if (conn->own_ip == NULL)
conn->own_ip = g_new(IPADDR, 1);
memcpy(conn->own_ip, *own_ip, sizeof(IPADDR));
return;
}
/* resolve the IP and use it */
if (net_gethostbyname(own_host, &ip) == 0) {
if (conn->own_ip == NULL)
conn->own_ip = g_new(IPADDR, 1);
memcpy(conn->own_ip, &ip, sizeof(IPADDR));
*own_ip = g_new(IPADDR, 1);
memcpy(*own_ip, &ip, sizeof(IPADDR));
}
}
/* Fill information to connection from server setup record */
void server_setup_fill_reconn(SERVER_CONNECT_REC *conn,
SERVER_SETUP_REC *sserver)
{
g_return_if_fail(IS_SERVER_CONNECT(conn));
g_return_if_fail(IS_SERVER_SETUP(sserver));
if (sserver->own_host != NULL)
conn_set_ip(conn, &sserver->own_ip, sserver->own_host);
if (sserver->chatnet != NULL && conn->chatnet == NULL)
conn->chatnet = g_strdup(sserver->chatnet);
if (sserver->password != NULL && conn->password == NULL)
conn->password = g_strdup(sserver->password);
signal_emit("server setup fill reconn", 2, conn, sserver);
}
static void server_setup_fill(SERVER_CONNECT_REC *conn,
const char *address, int port)
{
g_return_if_fail(conn != NULL);
g_return_if_fail(address != NULL);
conn->type = module_get_uniq_id("SERVER CONNECT", 0);
conn->address = g_strdup(address);
conn->port = port > 0 ? port : 6667;
if (!conn->nick) conn->nick = g_strdup(settings_get_str("default_nick"));
conn->username = g_strdup(settings_get_str("user_name"));
conn->realname = g_strdup(settings_get_str("real_name"));
/* proxy settings */
if (settings_get_bool("use_proxy")) {
conn->proxy = g_strdup(settings_get_str("proxy_address"));
conn->proxy_port = settings_get_int("proxy_port");
conn->proxy_string = g_strdup(settings_get_str("proxy_string"));
}
/* source IP */
get_source_host_ip();
if (source_host_ok) {
conn->own_ip = g_new(IPADDR, 1);
memcpy(conn->own_ip, source_host_ip, sizeof(IPADDR));
}
}
static void server_setup_fill_server(SERVER_CONNECT_REC *conn,
SERVER_SETUP_REC *sserver)
{
g_return_if_fail(IS_SERVER_CONNECT(conn));
g_return_if_fail(IS_SERVER_SETUP(sserver));
sserver->last_connect = time(NULL);
if (sserver->port > 0) conn->port = sserver->port;
server_setup_fill_reconn(conn, sserver);
signal_emit("server setup fill server", 2, conn, sserver);
}
static void server_setup_fill_chatnet(SERVER_CONNECT_REC *conn,
CHATNET_REC *chatnet)
{
g_return_if_fail(IS_SERVER_CONNECT(conn));
g_return_if_fail(IS_CHATNET(chatnet));
if (chatnet->nick) {
g_free(conn->nick);
conn->nick = g_strdup(chatnet->nick);;
}
if (chatnet->username) {
g_free(conn->username);
conn->username = g_strdup(chatnet->username);;
}
if (chatnet->realname) {
g_free(conn->realname);
conn->realname = g_strdup(chatnet->realname);;
}
if (chatnet->own_host != NULL)
conn_set_ip(conn, &chatnet->own_ip, chatnet->own_host);
signal_emit("server setup fill chatnet", 2, conn, chatnet);
}
static SERVER_CONNECT_REC *
create_addr_conn(const char *address, int port,
const char *password, const char *nick)
{
SERVER_CONNECT_REC *conn;
SERVER_SETUP_REC *sserver;
CHATNET_REC *chatnet;
g_return_val_if_fail(address != NULL, NULL);
sserver = server_setup_find(address, port);
chatnet = sserver->chatnet == NULL ? NULL :
chatnet_find(sserver->chatnet);
conn = NULL;
signal_emit("server setup connect", 2, &conn, chatnet);
if (conn == NULL) {
/* no chat protocol wanted this server? */
return NULL;
}
/* fill in the defaults */
server_setup_fill(conn, address, port);
/* fill the rest from chat network settings */
if (chatnet != NULL)
server_setup_fill_chatnet(conn, chatnet);
/* fill the information from setup */
if (sserver != NULL)
server_setup_fill_server(conn, sserver);
/* nick / password given in command line overrides all settings */
if (password && *password) {
g_free_not_null(conn->password);
conn->password = g_strdup(password);
}
if (nick && *nick) {
g_free_not_null(conn->nick);
conn->nick = g_strdup(nick);
}
return conn;
}
/* Connect to server where last connect succeeded (or we haven't tried to
connect yet). If there's no such server, connect to server where we
haven't connected for the longest time */
static SERVER_CONNECT_REC *
create_chatnet_conn(const char *dest, int port,
const char *password, const char *nick)
{
SERVER_SETUP_REC *bestrec;
GSList *tmp;
time_t now, besttime;
now = time(NULL);
bestrec = NULL; besttime = now;
for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
SERVER_SETUP_REC *rec = tmp->data;
if (rec->chatnet == NULL ||
g_strcasecmp(rec->chatnet, dest) != 0)
continue;
if (!rec->last_failed) {
bestrec = rec;
break;
}
if (bestrec == NULL || besttime > rec->last_connect) {
bestrec = rec;
besttime = rec->last_connect;
}
}
return bestrec == NULL ? NULL :
create_addr_conn(bestrec->address, 0, NULL, nick);
}
/* Create server connection record. `dest' is required, rest can be NULL.
`dest' is either a server address or chat network */
SERVER_CONNECT_REC *
server_create_conn(const char *dest, int port,
const char *password, const char *nick)
{
SERVER_CONNECT_REC *rec;
g_return_val_if_fail(dest != NULL, NULL);
if (chatnet_find(dest)) {
rec = create_chatnet_conn(dest, port, password, nick);
if (rec != NULL)
return rec;
}
return create_addr_conn(dest, port, password, nick);
}
/* Find matching server from setup. Try to find record with a same port,
but fallback to any server with the same address. */
SERVER_SETUP_REC *server_setup_find(const char *address, int port)
{
SERVER_SETUP_REC *server;
GSList *tmp;
g_return_val_if_fail(address != NULL, NULL);
server = NULL;
for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
SERVER_SETUP_REC *rec = tmp->data;
if (g_strcasecmp(rec->address, address) == 0) {
server = rec;
if (rec->port == port)
break;
}
}
return server;
}
/* Find matching server from setup. Ports must match or NULL is returned. */
SERVER_SETUP_REC *server_setup_find_port(const char *address, int port)
{
SERVER_SETUP_REC *rec;
rec = server_setup_find(address, port);
return rec == NULL || rec->port != port ? NULL : rec;
}
static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node)
{
SERVER_SETUP_REC *rec;
char *server, *chatnet;
int port;
g_return_val_if_fail(node != NULL, NULL);
server = config_node_get_str(node, "address", NULL);
if (server == NULL)
return NULL;
port = config_node_get_int(node, "port", 6667);
if (server_setup_find_port(server, port) != NULL) {
/* already exists - don't let it get there twice or
server reconnects will screw up! */
return NULL;
}
rec = NULL;
chatnet = config_node_get_str(node, "chatnet", NULL);
signal_emit("server setup read", 3, &rec, node,
chatnet == NULL ? NULL : chatnet_find(chatnet));
if (rec == NULL) {
/* no chat protocol wanted this server? */
return NULL;
}
rec->type = module_get_uniq_id("SERVER SETUP", 0);
rec->chatnet = g_strdup(chatnet);
rec->address = g_strdup(server);
rec->password = g_strdup(config_node_get_str(node, "password", NULL));
rec->port = port;
rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE);
rec->own_host = g_strdup(config_node_get_str(node, "own_host", 0));
setupservers = g_slist_append(setupservers, rec);
return rec;
}
static void server_setup_save(SERVER_SETUP_REC *rec)
{
CONFIG_NODE *parentnode, *node;
int index;
index = g_slist_index(setupservers, rec);
parentnode = iconfig_node_traverse("(servers", TRUE);
node = config_node_index(parentnode, index);
if (node == NULL)
node = config_node_section(parentnode, NULL, NODE_TYPE_BLOCK);
iconfig_node_clear(node);
iconfig_node_set_str(node, "address", rec->address);
iconfig_node_set_str(node, "chatnet", rec->chatnet);
config_node_set_int(node, "port", rec->port);
iconfig_node_set_str(node, "password", rec->password);
iconfig_node_set_str(node, "own_host", rec->own_host);
if (rec->autoconnect)
config_node_set_bool(node, "autoconnect", TRUE);
signal_emit("server setup saved", 2, rec, node);
}
static void server_setup_remove_config(SERVER_SETUP_REC *rec)
{
CONFIG_NODE *node;
int index;
node = iconfig_node_traverse("servers", FALSE);
if (node != NULL) {
index = g_slist_index(setupservers, rec);
iconfig_node_list_remove(node, index);
}
}
static void server_setup_destroy(SERVER_SETUP_REC *rec)
{
setupservers = g_slist_remove(setupservers, rec);
signal_emit("server setup destroyed", 1, rec);
g_free_not_null(rec->own_host);
g_free_not_null(rec->own_ip);
g_free_not_null(rec->chatnet);
g_free(rec->address);
g_free_not_null(rec->password);
g_free(rec);
}
void server_setup_add(SERVER_SETUP_REC *rec)
{
if (g_slist_find(setupservers, rec) == NULL)
setupservers = g_slist_append(setupservers, rec);
server_setup_save(rec);
}
void server_setup_remove(SERVER_SETUP_REC *rec)
{
server_setup_remove_config(rec);
server_setup_destroy(rec);
}
static void read_servers(void)
{
CONFIG_NODE *node;
GSList *tmp;
while (setupservers != NULL)
server_setup_destroy(setupservers->data);
/* Read servers */
node = iconfig_node_traverse("servers", FALSE);
if (node != NULL) {
for (tmp = node->value; tmp != NULL; tmp = tmp->next)
server_setup_read(tmp->data);
}
}
static void read_settings(void)
{
g_free_and_null(source_host_ip);
source_host_ok = FALSE;
get_source_host_ip();
}
void servers_setup_init(void)
{
settings_add_str("server", "hostname", "");
settings_add_str("server", "default_nick", NULL);
settings_add_str("server", "user_name", NULL);
settings_add_str("server", "real_name", NULL);
settings_add_bool("proxy", "use_proxy", FALSE);
settings_add_str("proxy", "proxy_address", "");
settings_add_int("proxy", "proxy_port", 6667);
settings_add_str("proxy", "proxy_string", "CONNECT %s %d");
source_host_ip = NULL;
read_settings();
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
signal_add("setup reread", (SIGNAL_FUNC) read_servers);
signal_add("irssi init read settings", (SIGNAL_FUNC) read_servers);
}
void servers_setup_deinit(void)
{
g_free_not_null(source_host_ip);
while (setupservers != NULL)
server_setup_destroy(setupservers->data);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
signal_remove("setup reread", (SIGNAL_FUNC) read_servers);
signal_remove("irssi init read settings", (SIGNAL_FUNC) read_servers);
module_uniq_destroy("SERVER SETUP");
}

46
src/core/servers-setup.h Normal file
View file

@ -0,0 +1,46 @@
#ifndef __SERVERS_SETUP_H
#define __SERVERS_SETUP_H
#include "servers.h"
#define IS_SERVER_SETUP(server) \
((server) != NULL && \
module_find_id("SERVER SETUP", (server)->type) != -1)
#define SERVER_SETUP(server) \
(IS_SERVER_SETUP(server) ? (SERVER_SETUP_REC *) (server) : NULL)
/* servers */
typedef struct {
#include "server-setup-rec.h"
} SERVER_SETUP_REC;
extern GSList *setupservers;
extern IPADDR *source_host_ip; /* Resolved address */
extern int source_host_ok; /* Use source_host_ip .. */
/* Fill reconnection specific information to connection
from server setup record */
void server_setup_fill_reconn(SERVER_CONNECT_REC *conn,
SERVER_SETUP_REC *sserver);
/* Create server connection record. `dest' is required, rest can be NULL.
`dest' is either a server address or chat network */
SERVER_CONNECT_REC *
server_create_conn(const char *dest, int port,
const char *password, const char *nick);
/* Find matching server from setup. Try to find record with a same port,
but fallback to any server with the same address. */
SERVER_SETUP_REC *server_setup_find(const char *address, int port);
/* Find matching server from setup. Ports must match or NULL is returned. */
SERVER_SETUP_REC *server_setup_find_port(const char *address, int port);
void server_setup_add(SERVER_SETUP_REC *rec);
void server_setup_remove(SERVER_SETUP_REC *rec);
void servers_setup_init(void);
void servers_setup_deinit(void);
#endif

View file

@ -19,24 +19,26 @@
*/
#include "module.h"
#include "modules.h"
#include "signals.h"
#include "line-split.h"
#include "net-nonblock.h"
#include "net-sendbuffer.h"
#include "rawlog.h"
#include "misc.h"
#include "server.h"
#include "server-redirect.h"
#include "rawlog.h"
#include "settings.h"
#include "servers.h"
#include "servers-redirect.h"
#include "servers-setup.h"
#include "channels.h"
#include "queries.h"
GSList *servers, *lookup_servers;
/* connection to server failed */
static void server_cant_connect(SERVER_REC *server, const char *msg)
{
g_return_if_fail(server != NULL);
g_return_if_fail(IS_SERVER(server));
lookup_servers = g_slist_remove(lookup_servers, server);
@ -52,6 +54,7 @@ static void server_cant_connect(SERVER_REC *server, const char *msg)
}
MODULE_DATA_DEINIT(server);
server_connect_free(server->connrec);
g_free_not_null(server->nick);
g_free(server->tag);
g_free(server);
@ -62,6 +65,8 @@ static char *server_create_address_tag(const char *address)
{
const char *start, *end;
g_return_val_if_fail(address != NULL, NULL);
/* try to generate a reasonable server tag */
if (strchr(address, '.') == NULL) {
start = end = NULL;
@ -91,7 +96,9 @@ static char *server_create_tag(SERVER_CONNECT_REC *conn)
char *tag;
int num;
tag = conn->ircnet != NULL ? g_strdup(conn->ircnet) :
g_return_val_if_fail(IS_SERVER_CONNECT(conn), NULL);
tag = conn->chatnet != NULL ? g_strdup(conn->chatnet) :
server_create_address_tag(conn->address);
/* then just append numbers after tag until unused is found.. */
@ -109,6 +116,8 @@ static void server_connect_callback_init(SERVER_REC *server, int handle)
{
int error;
g_return_if_fail(IS_SERVER(server));
error = net_geterror(handle);
if (error != 0) {
server->connection_lost = TRUE;
@ -122,8 +131,12 @@ static void server_connect_callback_init(SERVER_REC *server, int handle)
server->connect_tag = -1;
server->connect_time = time(NULL);
server->rawlog = rawlog_create();
servers = g_slist_append(servers, server);
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);
}
@ -134,6 +147,8 @@ static void server_connect_callback_readpipe(SERVER_REC *server)
const char *errormsg;
int handle;
g_return_if_fail(IS_SERVER(server));
g_source_remove(server->connect_tag);
server->connect_tag = -1;
@ -182,13 +197,14 @@ static void server_connect_callback_readpipe(SERVER_REC *server)
signal_emit("server connecting", 2, server, &iprec.ip);
}
int server_connect(SERVER_REC *server)
int server_start_connect(SERVER_REC *server)
{
const char *connect_address;
g_return_val_if_fail(server != NULL, FALSE);
MODULE_DATA_INIT(server);
server->type = module_get_uniq_id("SERVER", 0);
if (pipe(server->connect_pipe) != 0) {
g_warning("server_connect(): pipe() failed.");
@ -213,9 +229,48 @@ int server_connect(SERVER_REC *server)
return TRUE;
}
/* Connect to server */
SERVER_REC *server_connect(SERVER_CONNECT_REC *conn)
{
SERVER_REC *server;
g_return_val_if_fail(IS_SERVER_CONNECT(conn), NULL);
server = NULL;
signal_emit("server connect", 2, &server, conn);
return server;
}
static int server_remove_channels(SERVER_REC *server)
{
GSList *tmp;
int found;
g_return_val_if_fail(server != NULL, FALSE);
found = FALSE;
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
CHANNEL_REC *channel = tmp->data;
channel->server = NULL;
channel_destroy(channel);
found = TRUE;
}
for (tmp = server->queries; tmp != NULL; tmp = tmp->next)
query_change_server(tmp->data, NULL);
g_slist_free(server->channels);
g_slist_free(server->queries);
return found;
}
void server_disconnect(SERVER_REC *server)
{
g_return_if_fail(server != NULL);
int chans;
g_return_if_fail(IS_SERVER(server));
if (server->connect_tag != -1) {
/* still connecting to server.. */
@ -229,12 +284,27 @@ void server_disconnect(SERVER_REC *server)
signal_emit("server disconnected", 1, server);
if (server->handle != NULL)
net_sendbuffer_destroy(server->handle, TRUE);
/* close all channels */
chans = server_remove_channels(server);
if (server->handle != NULL) {
if (!chans || server->connection_lost)
net_sendbuffer_destroy(server->handle, TRUE);
else {
/* we were on some channels, try to let the server
disconnect so that our quit message is guaranteed
to get displayed */
net_disconnect_later(net_sendbuffer_handle(server->handle));
net_sendbuffer_destroy(server->handle, FALSE);
}
server->handle = NULL;
}
if (server->readtag > 0)
g_source_remove(server->readtag);
MODULE_DATA_DEINIT(server);
server_connect_free(server->connrec);
rawlog_destroy(server->rawlog);
line_split_free(server->buffer);
g_free_not_null(server->version);
@ -268,29 +338,54 @@ SERVER_REC *server_find_tag(const char *tag)
return NULL;
}
SERVER_REC *server_find_ircnet(const char *ircnet)
SERVER_REC *server_find_chatnet(const char *chatnet)
{
GSList *tmp;
g_return_val_if_fail(ircnet != NULL, NULL);
if (*ircnet == '\0') return NULL;
g_return_val_if_fail(chatnet != NULL, NULL);
if (*chatnet == '\0') return NULL;
for (tmp = servers; tmp != NULL; tmp = tmp->next) {
SERVER_REC *server = tmp->data;
if (server->connrec->ircnet != NULL &&
g_strcasecmp(server->connrec->ircnet, ircnet) == 0)
if (server->connrec->chatnet != NULL &&
g_strcasecmp(server->connrec->chatnet, chatnet) == 0)
return server;
}
return NULL;
}
void server_connect_free(SERVER_CONNECT_REC *conn)
{
g_return_if_fail(IS_SERVER_CONNECT(conn));
signal_emit("server connect free", 1, conn);
g_free_not_null(conn->proxy);
g_free_not_null(conn->proxy_string);
g_free_not_null(conn->address);
g_free_not_null(conn->chatnet);
g_free_not_null(conn->own_ip);
g_free_not_null(conn->password);
g_free_not_null(conn->nick);
g_free_not_null(conn->username);
g_free_not_null(conn->realname);
g_free_not_null(conn->channels);
g_free_not_null(conn->away_reason);
g_free_not_null(conn->usermode);
g_free(conn);
}
void servers_init(void)
{
lookup_servers = servers = NULL;
servers_redirect_init();
servers_setup_init();
}
void servers_deinit(void)
@ -300,5 +395,9 @@ void servers_deinit(void)
while (lookup_servers != NULL)
server_cant_connect(lookup_servers->data, NULL);
servers_setup_deinit();
servers_redirect_deinit();
module_uniq_destroy("SERVER");
module_uniq_destroy("SERVER CONNECT");
}

52
src/core/servers.h Normal file
View file

@ -0,0 +1,52 @@
#ifndef __SERVERS_H
#define __SERVERS_H
#include "modules.h"
#ifndef __NETWORK_H
typedef struct _ipaddr IPADDR;
#endif
#define IS_SERVER(server) \
((server) != NULL && module_find_id("SERVER", (server)->type) != -1)
#define IS_SERVER_CONNECT(conn) \
((conn) != NULL && \
module_find_id("SERVER CONNECT", (conn)->type) != -1)
/* Returns SERVER_REC if it's server, NULL if it isn't. */
#define SERVER(server) \
(IS_SERVER(server) ? (SERVER_REC *) (server) : NULL)
/* Returns SERVER_CONNECT_REC if it's server connection, NULL if it isn't. */
#define SERVER_CONNECT(conn) \
(IS_SERVER_CONNECT(conn) ? (SERVER_CONNECT_REC *) (conn) : NULL)
/* all strings should be either NULL or dynamically allocated */
/* address and nick are mandatory, rest are optional */
typedef struct {
#include "server-connect-rec.h"
} SERVER_CONNECT_REC;
#define STRUCT_SERVER_CONNECT_REC SERVER_CONNECT_REC
typedef struct {
#include "server-rec.h"
} SERVER_REC;
extern GSList *servers, *lookup_servers;
void servers_init(void);
void servers_deinit(void);
/* Connect to server */
SERVER_REC *server_connect(SERVER_CONNECT_REC *conn);
/* Disconnect from server */
void server_disconnect(SERVER_REC *server);
SERVER_REC *server_find_tag(const char *tag);
SERVER_REC *server_find_chatnet(const char *chatnet);
int server_start_connect(SERVER_REC *server);
void server_connect_free(SERVER_CONNECT_REC *conn);
#endif

View file

@ -32,6 +32,7 @@ typedef struct {
#define iconfig_node_set_str(a, b, c) config_node_set_str(mainconfig, a, b, c)
#define iconfig_node_list_remove(a, b) config_node_list_remove(mainconfig, a, b)
#define iconfig_node_remove(a, b) config_node_remove(mainconfig, a, b)
#define iconfig_node_clear(a) config_node_clear(mainconfig, a)
extern CONFIG_REC *mainconfig;

View file

@ -310,7 +310,8 @@ void signal_stop_by_name(const char *signal)
static void signal_remove_module(void *signal, SIGNAL_REC *rec, const char *module)
{
int signal_id, list, index;
unsigned int index;
int signal_id, list;
signal_id = GPOINTER_TO_INT(signal);

View file

@ -25,6 +25,10 @@
#include "misc.h"
#include "irssi-version.h"
#include "channels.h"
#include "queries.h"
#include "window-item-def.h"
#include <sys/utsname.h>
#define ALIGN_RIGHT 0x01
@ -99,7 +103,7 @@ static char *get_internal_setting(const char *key, int type, int *free_ret)
return NULL;
}
static char *get_long_variable_value(const char *key, void *server,
static char *get_long_variable_value(const char *key, SERVER_REC *server,
void *item, int *free_ret)
{
EXPANDO_FUNC func;
@ -126,7 +130,7 @@ static char *get_long_variable_value(const char *key, void *server,
return NULL;
}
static char *get_long_variable(char **cmd, void *server,
static char *get_long_variable(char **cmd, SERVER_REC *server,
void *item, int *free_ret)
{
char *start, *var, *ret;
@ -142,7 +146,7 @@ static char *get_long_variable(char **cmd, void *server,
}
/* return the value of the variable found from `cmd' */
static char *get_variable(char **cmd, void *server, void *item,
static char *get_variable(char **cmd, SERVER_REC *server, void *item,
char **arglist, int *free_ret, int *arg_used)
{
if (isdigit(**cmd) || **cmd == '*' || **cmd == '-' || **cmd == '~') {
@ -183,7 +187,7 @@ static char *get_history(char **cmd, void *item, int *free_ret)
return ret;
}
static char *get_special_value(char **cmd, void *server, void *item,
static char *get_special_value(char **cmd, SERVER_REC *server, void *item,
char **arglist, int *free_ret, int *arg_used)
{
char command, *value, *p;
@ -313,7 +317,7 @@ static char *get_alignment(const char *text, int align, int flags, char pad)
/* Parse and expand text after '$' character. return value has to be
g_free()'d if `free_ret' is TRUE. */
char *parse_special(char **cmd, void *server, void *item,
char *parse_special(char **cmd, SERVER_REC *server, void *item,
char **arglist, int *free_ret, int *arg_used)
{
static char **nested_orig_cmd = NULL; /* FIXME: KLUDGE! */
@ -405,7 +409,7 @@ char *parse_special(char **cmd, void *server, void *item,
}
/* parse the whole string. $ and \ chars are replaced */
char *parse_special_string(const char *cmd, void *server, void *item,
char *parse_special_string(const char *cmd, SERVER_REC *server, void *item,
const char *data, int *arg_used)
{
char code, **arglist, *ret;
@ -466,7 +470,7 @@ char *parse_special_string(const char *cmd, void *server, void *item,
/* execute the commands in string - commands can be split with ';' */
void eval_special_string(const char *cmd, const char *data,
void *server, void *item)
SERVER_REC *server, void *item)
{
const char *cmdchars;
char *orig, *str, *start, *ret;
@ -556,40 +560,101 @@ void special_history_func_set(SPECIAL_HISTORY_FUNC func)
history_func = func;
}
/* text of your AWAY message, if any */
static char *expando_awaymsg(SERVER_REC *server, void *item, int *free_ret)
{
return server == NULL ? "" : server->away_reason;
}
/* current channel */
static char *expando_channel(SERVER_REC *server, void *item, int *free_ret)
{
return !IS_CHANNEL(item) ? NULL : CHANNEL(item)->name;
}
/* time client was started, $time() format */
static char *expando_clientstarted(void *server, void *item, int *free_ret)
static char *expando_clientstarted(SERVER_REC *server, void *item, int *free_ret)
{
*free_ret = TRUE;
return g_strdup_printf("%ld", (long) client_start_time);
}
/* client version text string */
static char *expando_version(void *server, void *item, int *free_ret)
static char *expando_version(SERVER_REC *server, void *item, int *free_ret)
{
return IRSSI_VERSION;
}
/* current value of CMDCHARS */
static char *expando_cmdchars(void *server, void *item, int *free_ret)
static char *expando_cmdchars(SERVER_REC *server, void *item, int *free_ret)
{
return (char *) settings_get_str("cmdchars");
}
/* modes of current channel, if any */
static char *expando_chanmode(SERVER_REC *server, void *item, int *free_ret)
{
return !IS_CHANNEL(item) ? NULL : CHANNEL(item)->mode;
}
/* current nickname */
static char *expando_nick(SERVER_REC *server, void *item, int *free_ret)
{
return server == NULL ? "" : server->nick;
}
/* value of STATUS_OPER if you are an irc operator */
static char *expando_statusoper(SERVER_REC *server, void *item, int *free_ret)
{
return server == NULL || !server->server_operator ? "" :
(char *) settings_get_str("STATUS_OPER");
}
/* if you are a channel operator in $C, expands to a '@' */
static char *expando_chanop(SERVER_REC *server, void *item, int *free_ret)
{
return IS_CHANNEL(item) && CHANNEL(item)->chanop ? "@" : "";
}
/* nickname of whomever you are QUERYing */
static char *expando_query(SERVER_REC *server, void *item, int *free_ret)
{
return !IS_QUERY(item) ? "" : QUERY(item)->name;
}
/* version of current server */
static char *expando_serverversion(SERVER_REC *server, void *item, int *free_ret)
{
return server == NULL ? "" : server->version;
}
/* target of current input (channel or QUERY nickname) */
static char *expando_target(SERVER_REC *server, void *item, int *free_ret)
{
return ((WI_ITEM_REC *) item)->name;
}
/* client release date (numeric version string) */
static char *expando_releasedate(void *server, void *item, int *free_ret)
static char *expando_releasedate(SERVER_REC *server, void *item, int *free_ret)
{
return IRSSI_VERSION_DATE;
}
/* current working directory */
static char *expando_workdir(void *server, void *item, int *free_ret)
static char *expando_workdir(SERVER_REC *server, void *item, int *free_ret)
{
*free_ret = TRUE;
return g_get_current_dir();
}
/* value of REALNAME */
static char *expando_realname(SERVER_REC *server, void *item, int *free_ret)
{
return server == NULL ? "" : server->connrec->realname;
}
/* time of day (hh:mm) */
static char *expando_time(void *server, void *item, int *free_ret)
static char *expando_time(SERVER_REC *server, void *item, int *free_ret)
{
time_t now = time(NULL);
struct tm *tm;
@ -600,13 +665,13 @@ static char *expando_time(void *server, void *item, int *free_ret)
}
/* a literal '$' */
static char *expando_dollar(void *server, void *item, int *free_ret)
static char *expando_dollar(SERVER_REC *server, void *item, int *free_ret)
{
return "$";
}
/* system name */
static char *expando_sysname(void *server, void *item, int *free_ret)
static char *expando_sysname(SERVER_REC *server, void *item, int *free_ret)
{
struct utsname un;
@ -619,7 +684,7 @@ static char *expando_sysname(void *server, void *item, int *free_ret)
}
/* system release */
static char *expando_sysrelease(void *server, void *item, int *free_ret)
static char *expando_sysrelease(SERVER_REC *server, void *item, int *free_ret)
{
struct utsname un;
@ -631,8 +696,22 @@ static char *expando_sysrelease(void *server, void *item, int *free_ret)
}
/* Server tag */
static char *expando_servertag(SERVER_REC *server, void *item, int *free_ret)
{
return server == NULL ? "" : server->tag;
}
/* Server chatnet */
static char *expando_chatnet(SERVER_REC *server, void *item, int *free_ret)
{
return server == NULL ? "" : server->connrec->chatnet;
}
void special_vars_init(void)
{
settings_add_str("misc", "STATUS_OPER", "*");
client_start_time = time(NULL);
memset(char_expandos, 0, sizeof(char_expandos));
@ -640,22 +719,36 @@ void special_vars_init(void)
(GCompareFunc) g_str_equal);
history_func = NULL;
char_expandos['A'] = expando_awaymsg;
char_expandos['C'] = expando_channel;
char_expandos['F'] = expando_clientstarted;
char_expandos['J'] = expando_version;
char_expandos['K'] = expando_cmdchars;
char_expandos['M'] = expando_chanmode;
char_expandos['N'] = expando_nick;
char_expandos['O'] = expando_statusoper;
char_expandos['P'] = expando_chanop;
char_expandos['Q'] = expando_query;
char_expandos['R'] = expando_serverversion;
char_expandos['T'] = expando_target;
char_expandos['V'] = expando_releasedate;
char_expandos['W'] = expando_workdir;
char_expandos['Y'] = expando_realname;
char_expandos['Z'] = expando_time;
char_expandos['$'] = expando_dollar;
expando_create("sysname", expando_sysname);
expando_create("sysrelease", expando_sysrelease);
expando_create("tag", expando_servertag);
expando_create("chatnet", expando_chatnet);
}
void special_vars_deinit(void)
{
expando_destroy("sysname", expando_sysname);
expando_destroy("sysrelease", expando_sysrelease);
expando_destroy("tag", expando_servertag);
expando_destroy("chatnet", expando_chatnet);
g_hash_table_destroy(expandos);
}

View file

@ -1,18 +1,25 @@
#ifndef __SPECIAL_VARS_H
#define __SPECIAL_VARS_H
typedef char* (*EXPANDO_FUNC) (void *server, void *item, int *free_ret);
typedef char* (*SPECIAL_HISTORY_FUNC) (const char *text, void *item, int *free_ret);
#include "servers.h"
typedef char* (*EXPANDO_FUNC)
(SERVER_REC *server, void *item, int *free_ret);
typedef char* (*SPECIAL_HISTORY_FUNC)
(const char *text, void *item, int *free_ret);
/* Parse and expand text after '$' character. return value has to be
g_free()'d if `free_ret' is TRUE. */
char *parse_special(char **cmd, void *server, void *item, char **arglist, int *free_ret, int *arg_used);
char *parse_special(char **cmd, SERVER_REC *server, void *item,
char **arglist, int *free_ret, int *arg_used);
/* parse the whole string. $ and \ chars are replaced */
char *parse_special_string(const char *cmd, void *server, void *item, const char *data, int *arg_used);
char *parse_special_string(const char *cmd, SERVER_REC *server, void *item,
const char *data, int *arg_used);
/* execute the commands in string - commands can be split with ';' */
void eval_special_string(const char *cmd, const char *data, void *server, void *item);
void eval_special_string(const char *cmd, const char *data,
SERVER_REC *server, void *item);
/* Create expando - overrides any existing ones. */
void expando_create(const char *key, EXPANDO_FUNC func);

View file

@ -0,0 +1,9 @@
#ifndef __WINDOW_ITEM_DEF_H
#define __WINDOW_ITEM_DEF_H
#define STRUCT_SERVER_REC SERVER_REC
typedef struct {
#include "window-item-rec.h"
} WI_ITEM_REC;
#endif

View file

@ -0,0 +1,14 @@
/* WI_ITEM_REC definition, used for inheritance */
int type; /* window item type - channel/query/.. */
int chat_type; /* chat server type - irc/silc/.. */
GHashTable *module_data;
STRUCT_SERVER_REC *server;
char *name;
time_t createtime;
int new_data;
int last_color; /* if NEWDATA_HILIGHT is set, color number could be specified here */
#undef STRUCT_SERVER_REC