mirror of
https://github.com/irssi/irssi.git
synced 2026-08-17 23:52:22 +02:00
Added bot plugin, it also has almost-functional botnet.
Changed configure.in's functionality so that you could tell what modules you want to build in main irssi binary and it will create automatically the .c files that need to call the module_init()/deinit() functions. Fixed several minor things.. git-svn-id: http://svn.irssi.org/repos/irssi/trunk@230 dbcabf3a-b0e7-0310-adc4-f8d773084564
This commit is contained in:
parent
487da41745
commit
76605ad0ae
41 changed files with 2809 additions and 246 deletions
|
|
@ -1,4 +1,4 @@
|
|||
SUBDIRS = core dcc flood notifylist
|
||||
SUBDIRS = core bot dcc flood notifylist
|
||||
|
||||
noinst_LTLIBRARIES = libirc.la
|
||||
|
||||
|
|
|
|||
8
src/irc/bot/.cvsignore
Normal file
8
src/irc/bot/.cvsignore
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
*.la
|
||||
*.lo
|
||||
*.o
|
||||
.deps
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
so_locations
|
||||
24
src/irc/bot/Makefile.am
Normal file
24
src/irc/bot/Makefile.am
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
plugindir = $(libdir)/irssi/plugins
|
||||
plugin_LTLIBRARIES = libirc_bot.la
|
||||
|
||||
INCLUDES = $(GLIB_CFLAGS) \
|
||||
-I$(top_srcdir)/src -I$(top_srcdir)/src/core/ -I$(top_srcdir)/src/irc/core/
|
||||
|
||||
libirc_bot_la_LIBADD = -lcrypt
|
||||
|
||||
libirc_bot_la_SOURCES = \
|
||||
bot.c \
|
||||
bot-commands.c \
|
||||
bot-events.c \
|
||||
bot-users.c \
|
||||
botnet.c \
|
||||
botnet-connection.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
bot.h \
|
||||
botnet.h \
|
||||
bot-users.h
|
||||
|
||||
EXTRA_DIST = \
|
||||
users.sample \
|
||||
botnets.sample
|
||||
165
src/irc/bot/bot-commands.c
Normal file
165
src/irc/bot/bot-commands.c
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
bot-commands.c : IRC bot plugin for irssi
|
||||
|
||||
Copyright (C) 1999-2000 Timo Sirainen
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "commands.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "irc-server.h"
|
||||
#include "channels.h"
|
||||
#include "nicklist.h"
|
||||
#include "masks.h"
|
||||
|
||||
#include "bot-users.h"
|
||||
|
||||
static void event_privmsg(const char *data, IRC_SERVER_REC *server,
|
||||
const char *nick, const char *address)
|
||||
{
|
||||
char *params, *target, *msg, *args, *str;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg);
|
||||
if (nick == NULL) nick = server->real_address;
|
||||
|
||||
if (*msg == 1 || ischannel(*target)) {
|
||||
g_free(params);
|
||||
return;
|
||||
}
|
||||
|
||||
/* private message for us */
|
||||
str = g_strconcat("bot command ", msg, NULL);
|
||||
args = strchr(str+12, ' ');
|
||||
if (args != NULL) *args++ = '\0'; else args = "";
|
||||
|
||||
g_strdown(str);
|
||||
if (signal_emit(str, 4, args, server, nick, address)) {
|
||||
/* msg was a command - the msg event. */
|
||||
signal_stop();
|
||||
}
|
||||
g_free(str);
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void botcmd_op(const char *data, IRC_SERVER_REC *server,
|
||||
const char *nick, const char *address)
|
||||
{
|
||||
CHANNEL_REC *channel;
|
||||
USER_REC *user;
|
||||
USER_CHAN_REC *userchan;
|
||||
GSList *tmp;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (*data == '\0') {
|
||||
/* no password given? .. */
|
||||
return;
|
||||
}
|
||||
|
||||
user = botuser_find(nick, address);
|
||||
if (user == NULL || (user->not_flags & USER_OP) ||
|
||||
!botuser_verify_password(user, data)) {
|
||||
/* not found, can't op with this mask or failed password */
|
||||
return;
|
||||
}
|
||||
|
||||
/* find the channels where to op.. */
|
||||
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
|
||||
channel = tmp->data;
|
||||
|
||||
userchan = g_hash_table_lookup(user->channels, channel->name);
|
||||
if ((user->flags & USER_OP) || (userchan->flags & USER_OP))
|
||||
signal_emit("command op", 3, nick, server, channel);
|
||||
}
|
||||
}
|
||||
|
||||
static void botcmd_ident(const char *data, IRC_SERVER_REC *server,
|
||||
const char *nick, const char *address)
|
||||
{
|
||||
USER_REC *user;
|
||||
char *mask;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
user = botuser_find(nick, address);
|
||||
if (user != NULL) {
|
||||
/* Already know this host */
|
||||
return;
|
||||
}
|
||||
|
||||
user = botuser_find(nick, NULL);
|
||||
if (user == NULL || !botuser_verify_password(user, data)) {
|
||||
/* failed password */
|
||||
return;
|
||||
}
|
||||
|
||||
/* add the new mask */
|
||||
mask = irc_get_mask(nick, address, IRC_MASK_USER | IRC_MASK_DOMAIN);
|
||||
botuser_add_mask(user, mask);
|
||||
|
||||
irc_send_cmdv(server, "NOTICE %s :Added new mask %s", nick, mask);
|
||||
g_free(mask);
|
||||
}
|
||||
|
||||
static void botcmd_pass(const char *data, IRC_SERVER_REC *server,
|
||||
const char *nick, const char *address)
|
||||
{
|
||||
USER_REC *user;
|
||||
char *params, *pass, *newpass;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2, &pass, &newpass);
|
||||
|
||||
user = botuser_find(nick, address);
|
||||
if (user == NULL || *pass == '\0') {
|
||||
g_free(params);
|
||||
return;
|
||||
}
|
||||
|
||||
if (user->password != NULL &&
|
||||
(*newpass == '\0' || !botuser_verify_password(user, pass))) {
|
||||
g_free(params);
|
||||
return;
|
||||
}
|
||||
|
||||
/* change the password */
|
||||
botuser_set_password(user, user->password == NULL ? pass : newpass);
|
||||
irc_send_cmdv(server, "NOTICE %s :Password changed", nick);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
void bot_commands_init(void)
|
||||
{
|
||||
signal_add("event privmsg", (SIGNAL_FUNC) event_privmsg);
|
||||
signal_add_last("bot command op", (SIGNAL_FUNC) botcmd_op);
|
||||
signal_add_last("bot command ident", (SIGNAL_FUNC) botcmd_ident);
|
||||
signal_add_last("bot command pass", (SIGNAL_FUNC) botcmd_pass);
|
||||
}
|
||||
|
||||
void bot_commands_deinit(void)
|
||||
{
|
||||
signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg);
|
||||
signal_remove("bot command op", (SIGNAL_FUNC) botcmd_op);
|
||||
signal_remove("bot command ident", (SIGNAL_FUNC) botcmd_ident);
|
||||
signal_remove("bot command pass", (SIGNAL_FUNC) botcmd_pass);
|
||||
}
|
||||
199
src/irc/bot/bot-events.c
Normal file
199
src/irc/bot/bot-events.c
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
bot-events.c : IRC bot plugin for irssi
|
||||
|
||||
Copyright (C) 1999 Timo Sirainen
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "commands.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "irc-server.h"
|
||||
#include "channels.h"
|
||||
#include "nicklist.h"
|
||||
#include "modes.h"
|
||||
#include "netsplit.h"
|
||||
|
||||
#include "bot-users.h"
|
||||
|
||||
static int get_flags(USER_REC *user, CHANNEL_REC *channel)
|
||||
{
|
||||
USER_CHAN_REC *userchan;
|
||||
|
||||
g_return_val_if_fail(user != NULL, 0);
|
||||
g_return_val_if_fail(channel != NULL, 0);
|
||||
|
||||
userchan = g_hash_table_lookup(user->channels, channel->name);
|
||||
return (user->flags | (userchan == NULL ? 0 : userchan->flags)) &
|
||||
(~user->not_flags);
|
||||
}
|
||||
|
||||
static void event_massjoin(CHANNEL_REC *channel, GSList *users)
|
||||
{
|
||||
USER_REC *user;
|
||||
USER_CHAN_REC *userchan;
|
||||
NICK_REC *nick;
|
||||
GString *modestr, *nickstr;
|
||||
int flags;
|
||||
|
||||
g_return_if_fail(channel != NULL);
|
||||
g_return_if_fail(users != NULL);
|
||||
|
||||
modestr = g_string_new(NULL);
|
||||
nickstr = g_string_new(NULL);
|
||||
|
||||
for (; users != NULL; users = users->next) {
|
||||
user = users->data;
|
||||
userchan = g_hash_table_lookup(user->channels, channel->name);
|
||||
nick = userchan->nickrec;
|
||||
|
||||
flags = get_flags(user, channel);
|
||||
if (!nick->op && (flags & USER_AUTO_OP)) {
|
||||
g_string_sprintfa(modestr, "+o");
|
||||
g_string_sprintfa(nickstr, "%s,", nick->nick);
|
||||
}
|
||||
|
||||
if (!nick->voice && !nick->op && (flags & USER_AUTO_VOICE)) {
|
||||
g_string_sprintfa(modestr, "+v");
|
||||
g_string_sprintfa(nickstr, "%s,", nick->nick);
|
||||
}
|
||||
}
|
||||
|
||||
if (nickstr->len > 0) {
|
||||
g_string_truncate(nickstr, nickstr->len-1);
|
||||
g_string_sprintfa(modestr, " %s", nickstr->str);
|
||||
|
||||
channel_set_mode(channel->server, channel->name, modestr->str);
|
||||
}
|
||||
|
||||
g_string_free(modestr, TRUE);
|
||||
g_string_free(nickstr, TRUE);
|
||||
}
|
||||
|
||||
/* Parse channel mode string */
|
||||
static void parse_channel_mode(CHANNEL_REC *channel, const char *mode,
|
||||
const char *nick, const char *address)
|
||||
{
|
||||
NICK_REC *nickrec, *splitnick;
|
||||
USER_REC *user;
|
||||
GString *str;
|
||||
char *ptr, *curmode, type, *dup, *modestr;
|
||||
int flags;
|
||||
|
||||
g_return_if_fail(channel != NULL);
|
||||
g_return_if_fail(nick != NULL);
|
||||
g_return_if_fail(modestr != NULL);
|
||||
|
||||
user = botuser_find(nick, address);
|
||||
flags = user == NULL ? 0 : get_flags(user, channel);
|
||||
|
||||
if (!channel->chanop || (flags & USER_MASTER) ||
|
||||
g_strcasecmp(nick, channel->server->nick) == 0) {
|
||||
/* can't do anything or we/master did mode change,
|
||||
don't bother checking what */
|
||||
return;
|
||||
}
|
||||
|
||||
str = g_string_new(NULL);
|
||||
dup = modestr = g_strdup(mode);
|
||||
|
||||
type = '+';
|
||||
curmode = cmd_get_param(&modestr);
|
||||
for (; *curmode != '\0'; curmode++) {
|
||||
if (*curmode == '+' || *curmode == '-') {
|
||||
type = *curmode;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!HAS_MODE_ARG(*curmode))
|
||||
ptr = NULL;
|
||||
else {
|
||||
ptr = cmd_get_param(&modestr);
|
||||
if (*ptr == '\0') continue;
|
||||
}
|
||||
|
||||
if (*curmode != 'o')
|
||||
continue;
|
||||
|
||||
if (type == '-' && strcmp(channel->server->nick, ptr) == 0) {
|
||||
/* we aren't chanop anymore .. */
|
||||
g_string_truncate(str, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (type != '+')
|
||||
continue;
|
||||
|
||||
/* check that op is valid */
|
||||
nickrec = nicklist_find(channel, ptr);
|
||||
if (nickrec == NULL || nickrec->host == NULL)
|
||||
continue;
|
||||
|
||||
user = botuser_find(ptr, nickrec->host);
|
||||
flags = user == NULL ? 0 : get_flags(user, channel);
|
||||
if (flags & USER_OP)
|
||||
continue;
|
||||
|
||||
if (address == NULL) {
|
||||
/* server opped, check if user was opped before netsplit. */
|
||||
splitnick = netsplit_find_channel(channel->server, nickrec->nick, nickrec->host, channel->name);
|
||||
if (splitnick != NULL && splitnick->op)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* this one isn't supposed to get ops! */
|
||||
g_string_sprintfa(str, "%s ", ptr);
|
||||
}
|
||||
g_free(dup);
|
||||
|
||||
if (str->len != 0)
|
||||
signal_emit("command deop", 3, str->str, channel->server, channel);
|
||||
g_string_free(str, TRUE);
|
||||
}
|
||||
|
||||
static void event_mode(const char *data, IRC_SERVER_REC *server,
|
||||
const char *nick, const char *address)
|
||||
{
|
||||
CHANNEL_REC *chanrec;
|
||||
char *params, *channel, *mode;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &channel, &mode);
|
||||
|
||||
if (ischannel(*channel)) {
|
||||
/* channel mode change */
|
||||
chanrec = channel_find(server, channel);
|
||||
if (chanrec != NULL)
|
||||
parse_channel_mode(chanrec, mode, nick, address);
|
||||
}
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
void bot_events_init(void)
|
||||
{
|
||||
signal_add_last("bot massjoin", (SIGNAL_FUNC) event_massjoin);
|
||||
signal_add("event mode", (SIGNAL_FUNC) event_mode);
|
||||
}
|
||||
|
||||
void bot_events_deinit(void)
|
||||
{
|
||||
signal_remove("bot massjoin", (SIGNAL_FUNC) event_massjoin);
|
||||
signal_remove("event mode", (SIGNAL_FUNC) event_mode);
|
||||
}
|
||||
503
src/irc/bot/bot-users.c
Normal file
503
src/irc/bot/bot-users.c
Normal file
|
|
@ -0,0 +1,503 @@
|
|||
/*
|
||||
bot-users.c : IRC bot plugin for irssi - user handling
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE /* for crypt() */
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "misc.h"
|
||||
#include "lib-config/iconfig.h"
|
||||
|
||||
#include "channels.h"
|
||||
#include "nicklist.h"
|
||||
#include "masks.h"
|
||||
|
||||
#include "bot-users.h"
|
||||
|
||||
#define WRITE_USERS_INTERVAL (60*15)
|
||||
|
||||
static char *user_flags = "oavm"; /* Keep these in the same order as USER_xxx flags */
|
||||
|
||||
static CONFIG_REC *userconfig;
|
||||
static GHashTable *users;
|
||||
|
||||
static int writeusers_tag;
|
||||
static time_t last_write;
|
||||
|
||||
int botuser_flags2value(const char *flags)
|
||||
{
|
||||
char *pos;
|
||||
int val;
|
||||
|
||||
g_return_val_if_fail(flags != NULL, 0);
|
||||
|
||||
val = 0;
|
||||
while (*flags != '\0') {
|
||||
pos = strchr(user_flags, *flags);
|
||||
if (pos != NULL)
|
||||
val |= 1 << (int) (pos-user_flags);
|
||||
flags++;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
char *botuser_value2flags(int value)
|
||||
{
|
||||
char *str, *p;
|
||||
int n;
|
||||
|
||||
p = str = g_malloc(USER_FLAG_COUNT+1);
|
||||
for (n = 0; n < USER_FLAG_COUNT; n++) {
|
||||
if (value & (1 << n))
|
||||
*p++ = user_flags[n];
|
||||
}
|
||||
*p = '\0';
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* save channel specific user record */
|
||||
static void botuser_save_chan(const char *key, USER_CHAN_REC *rec, CONFIG_NODE *node)
|
||||
{
|
||||
CONFIG_NODE *noderec;
|
||||
char *str;
|
||||
|
||||
noderec = config_node_section(node, rec->channel, NODE_TYPE_BLOCK);
|
||||
|
||||
str = rec->flags == 0 ? NULL :
|
||||
botuser_value2flags(rec->flags);
|
||||
config_node_set_str(userconfig, noderec, "flags", str);
|
||||
g_free_not_null(str);
|
||||
}
|
||||
|
||||
static void botuser_config_save(USER_REC *user)
|
||||
{
|
||||
CONFIG_NODE *node, *subnode, *noderec;
|
||||
GSList *tmp;
|
||||
char *str;
|
||||
|
||||
node = config_node_traverse(userconfig, "users", TRUE);
|
||||
node = config_node_section(node, user->nick, NODE_TYPE_BLOCK);
|
||||
|
||||
str = user->flags == 0 ? NULL :
|
||||
botuser_value2flags(user->flags);
|
||||
config_node_set_str(userconfig, node, "flags", str);
|
||||
g_free_not_null(str);
|
||||
|
||||
config_node_set_str(userconfig, node, "password", user->password);
|
||||
|
||||
/* Save masks */
|
||||
if (user->masks == NULL)
|
||||
config_node_set_str(userconfig, node, "masks", NULL);
|
||||
else {
|
||||
subnode = config_node_section(node, "masks", NODE_TYPE_LIST);
|
||||
|
||||
for (tmp = user->masks; tmp != NULL; tmp = tmp->next) {
|
||||
USER_MASK_REC *rec = tmp->data;
|
||||
|
||||
noderec = config_node_section(subnode, NULL, NODE_TYPE_BLOCK);
|
||||
config_node_set_str(userconfig, noderec, "mask", rec->mask);
|
||||
|
||||
str = user->flags == 0 ? NULL :
|
||||
botuser_value2flags(rec->not_flags);
|
||||
config_node_set_str(userconfig, noderec, "not_flags", str);
|
||||
g_free_not_null(str);
|
||||
}
|
||||
}
|
||||
|
||||
/* Save channels */
|
||||
if (g_hash_table_size(user->channels) == 0)
|
||||
config_node_set_str(userconfig, node, "channels", NULL);
|
||||
else {
|
||||
subnode = config_node_section(node, "channels", NODE_TYPE_LIST);
|
||||
g_hash_table_foreach(user->channels, (GHFunc) botuser_save_chan, subnode);
|
||||
}
|
||||
}
|
||||
|
||||
static USER_MASK_REC *botuser_create_mask(USER_REC *user, const char *mask)
|
||||
{
|
||||
USER_MASK_REC *rec;
|
||||
|
||||
rec = g_new0(USER_MASK_REC, 1);
|
||||
rec->mask = g_strdup(mask);
|
||||
|
||||
user->masks = g_slist_append(user->masks, rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
USER_MASK_REC *botuser_add_mask(USER_REC *user, const char *mask)
|
||||
{
|
||||
USER_MASK_REC *rec;
|
||||
|
||||
rec = botuser_create_mask(user, mask);
|
||||
botuser_config_save(user);
|
||||
return rec;
|
||||
}
|
||||
|
||||
static int botuser_find_mask(USER_REC *user, const char *nick, const char *host)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_val_if_fail(user != NULL, FALSE);
|
||||
g_return_val_if_fail(nick != NULL, FALSE);
|
||||
g_return_val_if_fail(host != NULL, FALSE);
|
||||
|
||||
/* Check that masks match */
|
||||
for (tmp = user->masks; tmp != NULL; tmp = tmp->next) {
|
||||
USER_MASK_REC *rec = tmp->data;
|
||||
|
||||
if (irc_mask_match_address(rec->mask, nick, host)) {
|
||||
user->not_flags = rec->not_flags;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void botuser_getusers_hash(void *key, USER_REC *user, GList **list)
|
||||
{
|
||||
*list = g_list_append(*list, user);
|
||||
}
|
||||
|
||||
USER_REC *botuser_find(const char *nick, const char *host)
|
||||
{
|
||||
USER_REC *user;
|
||||
char *stripnick;
|
||||
GList *list, *tmp;
|
||||
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
|
||||
/* First check for user with same nick */
|
||||
stripnick = nick_strip(nick);
|
||||
user = g_hash_table_lookup(users, stripnick);
|
||||
g_free(stripnick);
|
||||
|
||||
if (user != NULL && host != NULL &&
|
||||
!botuser_find_mask(user, nick, host)) {
|
||||
/* mask didn't match, check for more.. */
|
||||
user = NULL;
|
||||
}
|
||||
|
||||
if (user != NULL || host == NULL)
|
||||
return user;
|
||||
|
||||
/* Check for different nicks.. */
|
||||
list = NULL;
|
||||
g_hash_table_foreach(users, (GHFunc) botuser_getusers_hash, &list);
|
||||
for (tmp = list; tmp != NULL; tmp = tmp->next) {
|
||||
if (botuser_find_mask(tmp->data, nick, host)) {
|
||||
user = tmp->data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_list_free(list);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
USER_REC *botuser_find_rec(CHANNEL_REC *channel, NICK_REC *nick)
|
||||
{
|
||||
USER_REC *user, *rec;
|
||||
USER_CHAN_REC *userchan;
|
||||
GList *list, *tmp;
|
||||
|
||||
g_return_val_if_fail(channel != NULL, NULL);
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
|
||||
user = NULL; list = NULL;
|
||||
g_hash_table_foreach(users, (GHFunc) botuser_getusers_hash, &list);
|
||||
for (tmp = list; tmp != NULL; tmp = tmp->next) {
|
||||
rec = tmp->data;
|
||||
|
||||
userchan = g_hash_table_lookup(rec->channels, channel->name);
|
||||
if (userchan != NULL && userchan->nickrec == nick) {
|
||||
user = rec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_list_free(list);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
static USER_CHAN_REC *botuser_channel(USER_REC *user, const char *channel)
|
||||
{
|
||||
USER_CHAN_REC *rec;
|
||||
|
||||
g_return_val_if_fail(user != NULL, NULL);
|
||||
g_return_val_if_fail(channel != NULL, NULL);
|
||||
|
||||
rec = g_hash_table_lookup(user->channels, channel);
|
||||
if (rec != NULL) return rec;
|
||||
|
||||
rec = g_new0(USER_CHAN_REC, 1);
|
||||
rec->channel = g_strdup(channel);
|
||||
g_hash_table_insert(user->channels, rec->channel, rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
void botuser_set_password(USER_REC *user, const char *password)
|
||||
{
|
||||
char *pass, salt[3];
|
||||
|
||||
g_return_if_fail(user != NULL);
|
||||
g_return_if_fail(password != NULL);
|
||||
|
||||
salt[0] = rand()%20 + 'A';
|
||||
salt[1] = rand()%20 + 'A';
|
||||
salt[2] = '\0';
|
||||
pass = crypt(password, salt);
|
||||
|
||||
if (user->password != NULL) g_free(user->password);
|
||||
user->password = g_strdup(pass);
|
||||
botuser_config_save(user);
|
||||
}
|
||||
|
||||
int botuser_verify_password(USER_REC *user, const char *password)
|
||||
{
|
||||
char *pass, salt[3];
|
||||
|
||||
g_return_val_if_fail(user != NULL, FALSE);
|
||||
g_return_val_if_fail(password != NULL, FALSE);
|
||||
|
||||
if (user->password == NULL || strlen(user->password) < 3)
|
||||
return FALSE;
|
||||
|
||||
salt[0] = user->password[0];
|
||||
salt[1] = user->password[1];
|
||||
salt[2] = '\0';
|
||||
pass = crypt(password, salt);
|
||||
return strcmp(user->password, pass) == 0;
|
||||
}
|
||||
|
||||
static void event_massjoin(CHANNEL_REC *channel, GSList *nicks)
|
||||
{
|
||||
USER_REC *user;
|
||||
USER_CHAN_REC *userchan;
|
||||
GSList *users;
|
||||
|
||||
g_return_if_fail(channel != NULL);
|
||||
g_return_if_fail(nicks != NULL);
|
||||
|
||||
users = NULL;
|
||||
for (; nicks != NULL; nicks = nicks->next) {
|
||||
NICK_REC *rec = nicks->data;
|
||||
|
||||
user = botuser_find(rec->nick, rec->host);
|
||||
if (user != NULL) {
|
||||
userchan = botuser_channel(user, channel->name);
|
||||
userchan->nickrec = rec;
|
||||
users = g_slist_append(users, user);
|
||||
}
|
||||
}
|
||||
|
||||
if (users != NULL) {
|
||||
signal_emit("bot massjoin", 2, channel, users);
|
||||
g_slist_free(users);
|
||||
}
|
||||
}
|
||||
|
||||
/* channel synced - find everyone's NICK_REC's */
|
||||
static void sig_channel_sync(CHANNEL_REC *channel)
|
||||
{
|
||||
USER_REC *user;
|
||||
USER_CHAN_REC *userchan;
|
||||
GSList *tmp, *nicks;
|
||||
|
||||
g_return_if_fail(channel != NULL);
|
||||
|
||||
nicks = nicklist_getnicks(channel);
|
||||
for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
|
||||
NICK_REC *rec = tmp->data;
|
||||
|
||||
if (rec->send_massjoin)
|
||||
continue; /* This will be checked in "massjoin" signal */
|
||||
|
||||
user = botuser_find(rec->nick, rec->host);
|
||||
if (user != NULL) {
|
||||
userchan = botuser_channel(user, channel->name);
|
||||
userchan->nickrec = rec;
|
||||
}
|
||||
}
|
||||
g_slist_free(nicks);
|
||||
}
|
||||
|
||||
/* user left channel - remove from users record */
|
||||
static void sig_nicklist_remove(CHANNEL_REC *channel, NICK_REC *nick)
|
||||
{
|
||||
USER_REC *user;
|
||||
USER_CHAN_REC *userchan;
|
||||
|
||||
g_return_if_fail(channel != NULL);
|
||||
g_return_if_fail(nick != NULL);
|
||||
|
||||
user = botuser_find_rec(channel, nick);
|
||||
userchan = user == NULL ? NULL :
|
||||
g_hash_table_lookup(user->channels, channel->name);
|
||||
if (userchan != NULL) userchan->nickrec = NULL;
|
||||
}
|
||||
|
||||
/* Free memory used by user channel record */
|
||||
static void user_destroy_chan(const char *key, USER_CHAN_REC *rec)
|
||||
{
|
||||
g_free(rec->channel);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
static void usermask_destroy(USER_MASK_REC *rec)
|
||||
{
|
||||
g_free(rec->mask);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
/* Free memory used by user record */
|
||||
static void user_destroy(const char *key, USER_REC *user)
|
||||
{
|
||||
g_slist_foreach(user->masks, (GFunc) usermask_destroy, NULL);
|
||||
g_slist_free(user->masks);
|
||||
|
||||
g_hash_table_foreach(user->channels, (GHFunc) user_destroy_chan, NULL);
|
||||
g_hash_table_destroy(user->channels);
|
||||
|
||||
g_free_not_null(user->password);
|
||||
g_free(user->nick);
|
||||
g_free(user);
|
||||
}
|
||||
|
||||
static int sig_write_users(void)
|
||||
{
|
||||
if (last_write + WRITE_USERS_INTERVAL <= time(NULL)) {
|
||||
last_write = time(NULL);
|
||||
config_write(userconfig, NULL, -1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void botuser_config_read_user(CONFIG_NODE *node)
|
||||
{
|
||||
USER_REC *user;
|
||||
USER_CHAN_REC *userchan;
|
||||
USER_MASK_REC *usermask;
|
||||
CONFIG_NODE *subnode;
|
||||
GSList *tmp;
|
||||
char *value;
|
||||
|
||||
g_return_if_fail(node != NULL);
|
||||
|
||||
/* nick = { ... } */
|
||||
if (node->key == NULL || node->value == NULL)
|
||||
return;
|
||||
|
||||
/* Add new user */
|
||||
user = g_new0(USER_REC, 1);
|
||||
user->nick = g_strdup(node->key);
|
||||
g_hash_table_insert(users, user->nick, user);
|
||||
|
||||
/* password, flags */
|
||||
user->password = g_strdup(config_node_get_str(node, "password", NULL));
|
||||
user->flags = botuser_flags2value(config_node_get_str(node, "flags", ""));
|
||||
|
||||
/* get masks */
|
||||
user->masks = NULL;
|
||||
subnode = config_node_section(node, "masks", -1);
|
||||
tmp = subnode == NULL ? NULL : subnode->value;
|
||||
for (; tmp != NULL; tmp = tmp->next) {
|
||||
subnode = tmp->data;
|
||||
|
||||
value = config_node_get_str(subnode, "mask", NULL);
|
||||
if (value == NULL) continue; /* mask is required */
|
||||
|
||||
usermask = botuser_create_mask(user, value);
|
||||
value = config_node_get_str(subnode, "not_flags", "");
|
||||
usermask->not_flags = botuser_flags2value(value);
|
||||
}
|
||||
|
||||
/* get channels - must be last, messes up pvalue */
|
||||
user->channels = g_hash_table_new((GHashFunc) g_istr_hash, (GCompareFunc) g_istr_equal);
|
||||
subnode = config_node_section(node, "channels", -1);
|
||||
tmp = subnode == NULL ? NULL : subnode->value;
|
||||
for (; tmp != NULL; tmp = tmp->next) {
|
||||
subnode = tmp->data;
|
||||
|
||||
value = config_node_get_str(subnode, "channel", NULL);
|
||||
if (value == NULL) continue; /* channel is required */
|
||||
|
||||
/* create user channel specific record */
|
||||
userchan = g_new0(USER_CHAN_REC, 1);
|
||||
userchan->channel = g_strdup(value);
|
||||
g_hash_table_insert(user->channels, userchan->channel, userchan);
|
||||
|
||||
value = config_node_get_str(subnode, "flags", "");
|
||||
userchan->flags = botuser_flags2value(value);
|
||||
}
|
||||
}
|
||||
|
||||
static void botuser_config_read(void)
|
||||
{
|
||||
CONFIG_NODE *node;
|
||||
GSList *tmp;
|
||||
char *fname;
|
||||
|
||||
/* Read users from ~/.irssi/users */
|
||||
fname = g_strdup_printf("%s/.irssi/users", g_get_home_dir());
|
||||
userconfig = config_open(fname, 0600);
|
||||
g_free(fname);
|
||||
|
||||
if (userconfig == NULL)
|
||||
return; /* access denied?! */
|
||||
|
||||
config_parse(userconfig);
|
||||
|
||||
node = config_node_traverse(userconfig, "users", FALSE);
|
||||
tmp = node == NULL ? NULL : node->value;
|
||||
for (; tmp != NULL; tmp = tmp->next)
|
||||
botuser_config_read_user(tmp->data);
|
||||
}
|
||||
|
||||
void bot_users_init(void)
|
||||
{
|
||||
users = g_hash_table_new((GHashFunc) g_istr_hash, (GCompareFunc) g_istr_equal);
|
||||
|
||||
last_write = time(NULL);
|
||||
writeusers_tag = g_timeout_add(10000, (GSourceFunc) sig_write_users, NULL);
|
||||
|
||||
botuser_config_read();
|
||||
signal_add_last("massjoin", (SIGNAL_FUNC) event_massjoin);
|
||||
signal_add_last("channel sync", (SIGNAL_FUNC) sig_channel_sync);
|
||||
signal_add_last("nicklist remove", (SIGNAL_FUNC) sig_nicklist_remove);
|
||||
}
|
||||
|
||||
void bot_users_deinit(void)
|
||||
{
|
||||
if (userconfig != NULL) {
|
||||
config_write(userconfig, NULL, -1);
|
||||
config_close(userconfig);
|
||||
}
|
||||
|
||||
g_source_remove(writeusers_tag);
|
||||
|
||||
g_hash_table_foreach(users, (GHFunc) user_destroy, NULL);
|
||||
g_hash_table_destroy(users);
|
||||
|
||||
signal_remove("massjoin", (SIGNAL_FUNC) event_massjoin);
|
||||
signal_remove("channel sync", (SIGNAL_FUNC) sig_channel_sync);
|
||||
signal_remove("nicklist remove", (SIGNAL_FUNC) sig_nicklist_remove);
|
||||
}
|
||||
47
src/irc/bot/bot-users.h
Normal file
47
src/irc/bot/bot-users.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef __BOT_USERS_H
|
||||
#define __BOT_USERS_H
|
||||
|
||||
#define USER_OP 0x0001
|
||||
#define USER_AUTO_OP 0x0002
|
||||
#define USER_AUTO_VOICE 0x0004
|
||||
#define USER_MASTER 0x0008
|
||||
|
||||
#define USER_FLAG_COUNT 4
|
||||
|
||||
/* Channel specific flags */
|
||||
typedef struct {
|
||||
char *channel;
|
||||
int flags;
|
||||
NICK_REC *nickrec; /* Nick record in channel,
|
||||
FIXME: User can be in channel with multiple nicks too! */
|
||||
} USER_CHAN_REC;
|
||||
|
||||
typedef struct {
|
||||
char *mask;
|
||||
int not_flags; /* do not let this mask use these flags.. */
|
||||
} USER_MASK_REC;
|
||||
|
||||
/* User specific flags */
|
||||
typedef struct {
|
||||
char *nick;
|
||||
int flags;
|
||||
char *password;
|
||||
|
||||
GSList *masks;
|
||||
GHashTable *channels;
|
||||
|
||||
int not_flags; /* active not_flags based on current host mask,
|
||||
botuser_find() updates this */
|
||||
} USER_REC;
|
||||
|
||||
int botuser_flags2value(const char *flags);
|
||||
char *botuser_value2flags(int value);
|
||||
|
||||
USER_REC *botuser_find(const char *nick, const char *host);
|
||||
USER_REC *botuser_find_rec(CHANNEL_REC *channel, NICK_REC *nick);
|
||||
USER_MASK_REC *botuser_add_mask(USER_REC *user, const char *mask);
|
||||
|
||||
void botuser_set_password(USER_REC *user, const char *password);
|
||||
int botuser_verify_password(USER_REC *user, const char *password);
|
||||
|
||||
#endif
|
||||
49
src/irc/bot/bot.c
Normal file
49
src/irc/bot/bot.c
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
bot.c : IRC bot plugin for 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"
|
||||
|
||||
void bot_commands_deinit(void);
|
||||
void bot_commands_init(void);
|
||||
|
||||
void bot_events_init(void);
|
||||
void bot_events_deinit(void);
|
||||
|
||||
void bot_users_init(void);
|
||||
void bot_users_deinit(void);
|
||||
|
||||
void botnet_init(void);
|
||||
void botnet_deinit(void);
|
||||
|
||||
void irc_bot_init(void)
|
||||
{
|
||||
bot_users_init();
|
||||
bot_commands_init();
|
||||
bot_events_init();
|
||||
botnet_init();
|
||||
}
|
||||
|
||||
void irc_bot_deinit(void)
|
||||
{
|
||||
bot_users_deinit();
|
||||
bot_commands_deinit();
|
||||
bot_events_deinit();
|
||||
botnet_deinit();
|
||||
}
|
||||
26
src/irc/bot/bot.h
Normal file
26
src/irc/bot/bot.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef __BOT_H
|
||||
#define __BOT_H
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PLUGIN_REC *plugin;
|
||||
gboolean loaded;
|
||||
|
||||
GHashTable *users;
|
||||
GSList *botnets;
|
||||
|
||||
gchar *nick;
|
||||
gint rank;
|
||||
|
||||
time_t last_write;
|
||||
}
|
||||
PLUGIN_DATA;
|
||||
|
||||
void plugin_bot_events(PLUGIN_REC *plugin);
|
||||
|
||||
#include "botnet.h"
|
||||
#include "users.h"
|
||||
|
||||
#define MODULE_NAME "bot"
|
||||
|
||||
#endif
|
||||
553
src/irc/bot/botnet-connection.c
Normal file
553
src/irc/bot/botnet-connection.c
Normal file
|
|
@ -0,0 +1,553 @@
|
|||
/*
|
||||
botnet-connection.c : IRC bot plugin for 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 "net-nonblock.h"
|
||||
#include "signals.h"
|
||||
#include "commands.h"
|
||||
#include "misc.h"
|
||||
#include "line-split.h"
|
||||
#include "lib-config/iconfig.h"
|
||||
|
||||
#include "botnet.h"
|
||||
|
||||
#define BOTNET_RECONNECT_TIME (60*5)
|
||||
|
||||
static void sig_bot_read(BOT_REC *bot)
|
||||
{
|
||||
BOTNET_REC *botnet;
|
||||
char tmpbuf[1024], *str;
|
||||
int ret, recvlen, reconnect;
|
||||
|
||||
botnet = bot->botnet;
|
||||
for (;;) {
|
||||
recvlen = bot->handle == -1 ? -1 :
|
||||
net_receive(bot->handle, tmpbuf, sizeof(tmpbuf));
|
||||
ret = line_split(tmpbuf, recvlen, &str, (LINEBUF_REC **) &bot->buffer);
|
||||
|
||||
if (ret == 0)
|
||||
break;
|
||||
if (ret == -1) {
|
||||
/* connection lost */
|
||||
reconnect = !bot->disconnect && bot->uplink;
|
||||
bot_destroy(bot);
|
||||
|
||||
if (reconnect) {
|
||||
/* wasn't intentional disconnection from
|
||||
our uplink, reconnect */
|
||||
botnet_connect(botnet->name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s\r\n", str);
|
||||
signal_emit("botnet event", 2, bot, str);
|
||||
}
|
||||
}
|
||||
|
||||
static void connect_downlink(BOTNET_REC *botnet, int handle,
|
||||
IPADDR *ip, const char *host)
|
||||
{
|
||||
BOT_DOWNLINK_REC *downlink;
|
||||
BOT_REC *bot;
|
||||
|
||||
g_return_if_fail(botnet != NULL);
|
||||
|
||||
/* identify the bot who's trying to connect.. */
|
||||
downlink = bot_downlink_find(botnet, ip, host);
|
||||
if (downlink == NULL || downlink->password == NULL) {
|
||||
/* unknown bot, close connection /
|
||||
bot didn't have password, don't let it connect to us */
|
||||
net_disconnect(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
bot = g_new0(BOT_REC, 1);
|
||||
bot->botnet = botnet;
|
||||
bot->link = downlink;
|
||||
g_node_append_data(botnet->bots, bot);
|
||||
|
||||
/* connected.. */
|
||||
bot->handle = handle;
|
||||
bot->read_tag = g_input_add(handle, G_INPUT_READ, (GInputFunction) sig_bot_read, bot);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char *botnet;
|
||||
IPADDR ip;
|
||||
int handle;
|
||||
} BOT_CONNECT_REC;
|
||||
|
||||
static void sig_host_got(RESOLVED_NAME_REC *name, BOT_CONNECT_REC *rec)
|
||||
{
|
||||
BOTNET_REC *botnet;
|
||||
|
||||
botnet = botnet_find(rec->botnet);
|
||||
if (botnet == NULL || !botnet->connected) {
|
||||
/* this botnet isn't connected anymore.. */
|
||||
net_disconnect(rec->handle);
|
||||
} else {
|
||||
connect_downlink(botnet, rec->handle, &rec->ip,
|
||||
name->error ? NULL : name->name);
|
||||
}
|
||||
g_free(rec->botnet);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
static void sig_botnet_listen(BOTNET_REC *botnet)
|
||||
{
|
||||
BOT_CONNECT_REC *rec;
|
||||
IPADDR ip;
|
||||
int handle;
|
||||
|
||||
g_return_if_fail(botnet != NULL);
|
||||
|
||||
/* accept connection */
|
||||
handle = net_accept(botnet->listen_handle, &ip, NULL);
|
||||
if (handle == -1)
|
||||
return;
|
||||
|
||||
rec = g_new0(BOT_CONNECT_REC, 1);
|
||||
rec->botnet = g_strdup(botnet->name);
|
||||
memcpy(&rec->ip, &ip, sizeof(IPADDR));
|
||||
rec->handle = handle;
|
||||
|
||||
if (!net_gethostbyaddr_nonblock(&ip, (NET_HOST_CALLBACK) sig_host_got, rec)) {
|
||||
/* failed for some reason, try without host */
|
||||
connect_downlink(botnet, handle, &ip, NULL);
|
||||
g_free(rec->botnet);
|
||||
g_free(rec);
|
||||
}
|
||||
}
|
||||
|
||||
static int botnet_listen(BOTNET_REC *botnet)
|
||||
{
|
||||
IPADDR addr;
|
||||
int port;
|
||||
|
||||
g_return_val_if_fail(botnet != NULL, FALSE);
|
||||
|
||||
if (botnet->port <= 0)
|
||||
return FALSE;
|
||||
|
||||
port = botnet->port;
|
||||
if (botnet->addr == NULL)
|
||||
botnet->listen_handle = net_listen(NULL, &port);
|
||||
else {
|
||||
net_host2ip(botnet->addr, &addr);
|
||||
botnet->listen_handle = net_listen(&addr, &port);
|
||||
}
|
||||
|
||||
if (botnet->listen_handle == -1) {
|
||||
g_warning("Couldn't start listening botnet\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
botnet->listen_tag = g_input_add(botnet->listen_handle, G_INPUT_READ,
|
||||
(GInputFunction) sig_botnet_listen, botnet);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void sig_botnet_connected(int handle, BOT_UPLINK_REC *uplink)
|
||||
{
|
||||
BOTNET_REC *botnet;
|
||||
BOT_REC *bot;
|
||||
|
||||
g_return_if_fail(uplink != NULL);
|
||||
|
||||
botnet = uplink->botnet;
|
||||
|
||||
if (handle == -1) {
|
||||
/* error, try another bot */
|
||||
botnet_connect(botnet->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* connected to bot */
|
||||
bot = g_new0(BOT_REC, 1);
|
||||
bot->botnet = botnet;
|
||||
bot->link = uplink;
|
||||
bot->uplink = TRUE;
|
||||
|
||||
bot->handle = handle;
|
||||
bot->read_tag = g_input_add(handle, G_INPUT_READ, (GInputFunction) sig_bot_read, bot);
|
||||
|
||||
botnet->uplink = bot;
|
||||
g_node_append_data(botnet->bots, bot);
|
||||
|
||||
/* send nick/pass */
|
||||
bot_send_cmdv(bot, "PASS %s", uplink->password);
|
||||
bot_send_cmdv(bot, "NICK %s", botnet->nick);
|
||||
}
|
||||
|
||||
int botnet_connect(const char *network)
|
||||
{
|
||||
BOTNET_REC *botnet;
|
||||
BOT_REC *bot;
|
||||
BOT_UPLINK_REC *uplink, *best;
|
||||
GSList *tmp;
|
||||
time_t now;
|
||||
|
||||
g_return_val_if_fail(network != NULL, FALSE);
|
||||
|
||||
/* find botnet */
|
||||
botnet = botnet_find(network);
|
||||
if (botnet == NULL) return FALSE;
|
||||
|
||||
if (botnet->bots == NULL) {
|
||||
/* create bot record for us */
|
||||
bot = g_new0(BOT_REC, 1);
|
||||
bot->botnet = botnet;
|
||||
bot->nick = g_strdup(botnet->nick);
|
||||
bot->priority = botnet->priority;
|
||||
bot->connected = TRUE;
|
||||
bot->master = TRUE;
|
||||
|
||||
bot->handle = -1;
|
||||
bot->read_tag = -1;
|
||||
|
||||
botnet->connected = TRUE;
|
||||
botnet->master = bot;
|
||||
|
||||
botnet->bots = g_node_new(bot);
|
||||
}
|
||||
|
||||
if (botnet->listen_handle == -1) {
|
||||
/* start listening */
|
||||
botnet_listen(botnet);
|
||||
}
|
||||
|
||||
/* find some bot where we can try to connect to */
|
||||
now = time(NULL);
|
||||
uplink = best = NULL;
|
||||
for (tmp = botnet->uplinks; tmp != NULL; tmp = tmp->next) {
|
||||
uplink = tmp->data;
|
||||
|
||||
if (uplink->last_connect+BOTNET_RECONNECT_TIME > now)
|
||||
continue;
|
||||
|
||||
if (uplink->last_connect == 0) {
|
||||
/* haven't yet tried to connect to this bot */
|
||||
best = uplink;
|
||||
break;
|
||||
}
|
||||
|
||||
if (best == NULL || uplink->last_connect < best->last_connect)
|
||||
best = uplink;
|
||||
}
|
||||
|
||||
if (best == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* connect to uplink */
|
||||
best->last_connect = time(NULL);
|
||||
net_connect_nonblock(best->host, best->port, NULL, (NET_CALLBACK) sig_botnet_connected, best);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int botnet_send_botinfo(GNode *node, BOT_REC *client)
|
||||
{
|
||||
BOT_REC *parent, *bot;
|
||||
|
||||
bot = node->data;
|
||||
parent = node->parent == NULL ? NULL : node->parent->data;
|
||||
if (parent == NULL && client->uplink) parent = client;
|
||||
|
||||
bot_send_cmdv(client, "%s - BOTINFO %s %s %d", bot->botnet->nick, bot->nick,
|
||||
parent != NULL ? parent->nick : "-", bot->priority);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* send botnet links to specified bot */
|
||||
static void botnet_send_links(BOT_REC *bot, int downlinks)
|
||||
{
|
||||
GNode *node;
|
||||
|
||||
if (!downlinks) {
|
||||
/* send uplinks */
|
||||
if (bot->botnet->uplink == NULL)
|
||||
return;
|
||||
|
||||
node = g_node_find(bot->botnet->bots, G_IN_ORDER,
|
||||
G_TRAVERSE_ALL, bot->botnet->uplink);
|
||||
if (node == NULL)
|
||||
return;
|
||||
|
||||
g_node_traverse(node, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1,
|
||||
(GNodeTraverseFunc) botnet_send_botinfo, bot);
|
||||
return;
|
||||
}
|
||||
|
||||
/* send downlinks = all non-uplink nodes */
|
||||
for (node = bot->botnet->bots->children; node != NULL; node = node->next) {
|
||||
BOT_REC *rec = node->data;
|
||||
|
||||
if (rec == bot || rec->uplink || !rec->connected)
|
||||
continue;
|
||||
|
||||
g_node_traverse(node, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1,
|
||||
(GNodeTraverseFunc) botnet_send_botinfo, bot);
|
||||
}
|
||||
}
|
||||
|
||||
static void botnet_connect_event_uplink(BOT_REC *bot, const char *data)
|
||||
{
|
||||
BOTNET_REC *botnet;
|
||||
BOT_REC *ownbot;
|
||||
char *str, *p;
|
||||
int num;
|
||||
|
||||
botnet = bot->botnet;
|
||||
g_return_if_fail(botnet != NULL);
|
||||
|
||||
if (g_strcasecmp(data, "NICKERROR") == 0) {
|
||||
/* nick already in use, change it by adding a number
|
||||
at the end of it */
|
||||
p = botnet->nick+strlen(botnet->nick);
|
||||
while (p > botnet->nick && isdigit(p[-1])) p--;
|
||||
num = *p == '\0' ? 2 : atoi(p)+1; *p = '\0';
|
||||
str = g_strdup_printf("%s%d", botnet->nick, num);
|
||||
g_free(botnet->nick); botnet->nick = str;
|
||||
|
||||
ownbot = botnet->bots->data;
|
||||
g_free(ownbot->nick); ownbot->nick = g_strdup(str);
|
||||
|
||||
/* try again.. */
|
||||
bot_send_cmdv(bot, "NICK %s", botnet->nick);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_strcasecmp(data, "CONNECTED") == 0) {
|
||||
/* connected, wait for SYNC command */
|
||||
bot->connected = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* error? what? */
|
||||
}
|
||||
|
||||
static void botnet_event(BOT_REC *bot, const char *data)
|
||||
{
|
||||
BOT_DOWNLINK_REC *downlink;
|
||||
|
||||
g_return_if_fail(bot != NULL);
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (bot->connected)
|
||||
return;
|
||||
|
||||
if (bot->uplink) {
|
||||
botnet_connect_event_uplink(bot, data);
|
||||
return;
|
||||
}
|
||||
|
||||
downlink = bot->link;
|
||||
|
||||
if (!bot->pass_ok && g_strncasecmp(data, "PASS ", 5) == 0) {
|
||||
/* password sent, check that it matches */
|
||||
if (strcmp(data+5, downlink->password) == 0) {
|
||||
/* ok, connected! */
|
||||
bot->pass_ok = TRUE;
|
||||
} else {
|
||||
/* wrong password, disconnect */
|
||||
bot_disconnect(bot);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_strncasecmp(data, "NICK ", 5) == 0) {
|
||||
/* set bot's nick */
|
||||
if (!bot->pass_ok) {
|
||||
/* password has to be sent before nick, kill the
|
||||
stupid bot. */
|
||||
bot_disconnect(bot);
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_strcasecmp(bot->botnet->nick, data+5) == 0 ||
|
||||
bot_find_nick(bot->botnet, data+5) != NULL) {
|
||||
/* nick already exists */
|
||||
bot_send_cmd(bot, "NICKERROR");
|
||||
return;
|
||||
}
|
||||
|
||||
/* set the nick */
|
||||
bot->nick = g_strdup(data+5);
|
||||
bot->connected = TRUE;
|
||||
bot_send_cmd(bot, "CONNECTED");
|
||||
|
||||
/* send info about all the bots that are connected now
|
||||
to this botnet */
|
||||
botnet_send_botinfo(bot->botnet->bots, bot);
|
||||
botnet_send_links(bot, FALSE);
|
||||
botnet_send_links(bot, TRUE);
|
||||
bot_send_cmdv(bot, "%s - MASTER %s", bot->botnet->nick, bot->botnet->master->nick);
|
||||
bot_send_cmdv(bot, "%s - SYNC", bot->botnet->nick);
|
||||
return;
|
||||
}
|
||||
|
||||
/* pass/nick not sent yet */
|
||||
bot_send_cmd(bot, "ERROR");
|
||||
}
|
||||
|
||||
static void botnet_event_sync(BOT_REC *bot)
|
||||
{
|
||||
/* send our record to host */
|
||||
botnet_send_botinfo(bot->botnet->bots, bot);
|
||||
|
||||
/* send our downlinks to host */
|
||||
botnet_send_links(bot, TRUE);
|
||||
}
|
||||
|
||||
static BOT_REC *bot_add(BOTNET_REC *botnet, const char *nick, const char *parent)
|
||||
{
|
||||
GNode *node;
|
||||
BOT_REC *rec;
|
||||
|
||||
g_return_val_if_fail(botnet != NULL, NULL);
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
|
||||
node = bot_find_nick(botnet, nick);
|
||||
if (node != NULL) return node->data;
|
||||
|
||||
node = bot_find_nick(botnet, parent);
|
||||
if (node == NULL) return NULL;
|
||||
|
||||
rec = g_new0(BOT_REC, 1);
|
||||
rec->botnet = botnet;
|
||||
rec->nick = g_strdup(nick);
|
||||
|
||||
rec->handle = -1;
|
||||
rec->read_tag = -1;
|
||||
rec->connected = TRUE;
|
||||
|
||||
g_node_append_data(node, rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
static void botnet_event_botinfo(BOT_REC *bot, const char *data, const char *sender)
|
||||
{
|
||||
char *str, *params, *nick, *parent, *priority;
|
||||
BOT_REC *rec;
|
||||
|
||||
str = g_strdup_printf("BOTINFO %s", data);
|
||||
botnet_broadcast(bot->botnet, bot, sender, str);
|
||||
g_free(str);
|
||||
|
||||
params = cmd_get_params(data, 3, &nick, &parent, &priority);
|
||||
if (*parent == '-' && parent[1] == '\0')
|
||||
parent = NULL;
|
||||
|
||||
if (parent == NULL && bot->botnet->uplink != NULL &&
|
||||
bot->botnet->uplink == bot) {
|
||||
/* our uplink */
|
||||
if (bot->nick == NULL) bot->nick = g_strdup(nick);
|
||||
rec = bot;
|
||||
} else {
|
||||
rec = bot_add(bot->botnet, nick, parent);
|
||||
}
|
||||
|
||||
if (rec != NULL) {
|
||||
rec->priority = atoi(priority);
|
||||
}
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void botnet_event_botquit(BOT_REC *bot, const char *data)
|
||||
{
|
||||
GNode *node;
|
||||
|
||||
node = bot_find_nick(bot->botnet, data);
|
||||
if (node != NULL) bot_destroy(node->data);
|
||||
}
|
||||
|
||||
static void sig_bot_disconnected(BOT_REC *bot)
|
||||
{
|
||||
BOT_REC *master, *tmpbot;
|
||||
GNode *node;
|
||||
char *str;
|
||||
|
||||
if (!bot->botnet->connected)
|
||||
return;
|
||||
|
||||
if (bot->connected && bot->handle != -1) {
|
||||
/* send notice to rest of the botnet about quit */
|
||||
str = g_strdup_printf("BOTQUIT %s", bot->nick);
|
||||
botnet_broadcast(bot->botnet, bot, NULL, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
if (bot->master) {
|
||||
/* master quit */
|
||||
node = bot_find_path(bot->botnet, bot->nick);
|
||||
tmpbot = node == NULL ? NULL : node->data;
|
||||
|
||||
if (tmpbot != NULL && tmpbot->disconnect) {
|
||||
/* we lost the connection to master - find new
|
||||
master for the botnet*/
|
||||
master = botnet_find_master(bot->botnet, NULL);
|
||||
botnet_set_master(bot->botnet, master);
|
||||
|
||||
str = g_strdup_printf("MASTER %s", master->nick);
|
||||
botnet_broadcast(bot->botnet, bot, NULL, str);
|
||||
g_free(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int print_bot(GNode *node)
|
||||
{
|
||||
BOT_REC *bot = node->data;
|
||||
|
||||
fprintf(stderr, "%s %d %d\r\n", bot->nick, bot->connected, bot->disconnect);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void cmd_bots(void)
|
||||
{
|
||||
BOTNET_REC *botnet = botnet_find("ircnet");
|
||||
|
||||
fprintf(stderr, "\r\n");
|
||||
g_node_traverse(botnet->bots, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1,
|
||||
(GNodeTraverseFunc) print_bot, NULL);
|
||||
}
|
||||
|
||||
void botnet_connection_init(void)
|
||||
{
|
||||
signal_add("botnet event", (SIGNAL_FUNC) botnet_event);
|
||||
signal_add("botnet event sync", (SIGNAL_FUNC) botnet_event_sync);
|
||||
signal_add("botnet event botinfo", (SIGNAL_FUNC) botnet_event_botinfo);
|
||||
signal_add("botnet event botquit", (SIGNAL_FUNC) botnet_event_botquit);
|
||||
signal_add("bot disconnected", (SIGNAL_FUNC) sig_bot_disconnected);
|
||||
command_bind("bots", NULL, (SIGNAL_FUNC) cmd_bots);
|
||||
}
|
||||
|
||||
void botnet_connection_deinit(void)
|
||||
{
|
||||
signal_remove("botnet event", (SIGNAL_FUNC) botnet_event);
|
||||
signal_remove("botnet event sync", (SIGNAL_FUNC) botnet_event_sync);
|
||||
signal_remove("botnet event botinfo", (SIGNAL_FUNC) botnet_event_botinfo);
|
||||
signal_remove("botnet event botquit", (SIGNAL_FUNC) botnet_event_botquit);
|
||||
signal_remove("bot disconnected", (SIGNAL_FUNC) sig_bot_disconnected);
|
||||
command_unbind("bots", (SIGNAL_FUNC) cmd_bots);
|
||||
}
|
||||
622
src/irc/bot/botnet.c
Normal file
622
src/irc/bot/botnet.c
Normal file
|
|
@ -0,0 +1,622 @@
|
|||
/*
|
||||
botnet.c : IRC bot plugin for 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 "net-nonblock.h"
|
||||
#include "signals.h"
|
||||
#include "commands.h"
|
||||
#include "misc.h"
|
||||
#include "line-split.h"
|
||||
#include "lib-config/iconfig.h"
|
||||
|
||||
#include "botnet.h"
|
||||
|
||||
void botnet_connection_init(void);
|
||||
void botnet_connection_deinit(void);
|
||||
|
||||
static GSList *botnets;
|
||||
|
||||
void bot_send_cmd(BOT_REC *bot, char *data)
|
||||
{
|
||||
g_return_if_fail(bot != NULL);
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
net_transmit(bot->handle, data, strlen(data));
|
||||
net_transmit(bot->handle, "\n", 1);
|
||||
}
|
||||
|
||||
void bot_send_cmdv(BOT_REC *bot, char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *str;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
str = g_strdup_vprintf(format, args);
|
||||
bot_send_cmd(bot, str);
|
||||
g_free(str);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* broadcast a message to everyone in bot network, except for `except_bot'
|
||||
if it's not NULL */
|
||||
void botnet_broadcast(BOTNET_REC *botnet, BOT_REC *except_bot,
|
||||
const char *source, const char *data)
|
||||
{
|
||||
GNode *node;
|
||||
char *str;
|
||||
|
||||
g_return_if_fail(botnet != NULL);
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
str = g_strdup_printf("%s - %s", source != NULL ? source :
|
||||
botnet->nick, data);
|
||||
for (node = botnet->bots->children; node != NULL; node = node->next) {
|
||||
BOT_REC *rec = node->data;
|
||||
|
||||
if (rec != except_bot && rec->handle != -1)
|
||||
bot_send_cmd(rec, str);
|
||||
}
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
BOTNET_REC *botnet_find(const char *name)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_val_if_fail(name != NULL, NULL);
|
||||
|
||||
for (tmp = botnets; tmp != NULL; tmp = tmp->next) {
|
||||
BOTNET_REC *rec = tmp->data;
|
||||
|
||||
if (g_strcasecmp(rec->name, name) == 0)
|
||||
return rec;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
gconstpointer key;
|
||||
int priority;
|
||||
GNode *node;
|
||||
} BOT_FIND_REC;
|
||||
|
||||
static int gnode_find_nick(GNode *node, BOT_FIND_REC *rec)
|
||||
{
|
||||
BOT_REC *bot = node->data;
|
||||
|
||||
if (bot == NULL) return FALSE;
|
||||
|
||||
if (bot->nick != NULL && g_strcasecmp(bot->nick, rec->key) == 0) {
|
||||
rec->node = node;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GNode *bot_find_nick(BOTNET_REC *botnet, const char *nick)
|
||||
{
|
||||
BOT_FIND_REC rec;
|
||||
|
||||
g_return_val_if_fail(botnet != NULL, NULL);
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
|
||||
rec.key = nick;
|
||||
rec.node = NULL;
|
||||
g_node_traverse(botnet->bots, 0, G_TRAVERSE_ALL, -1,
|
||||
(GNodeTraverseFunc) gnode_find_nick, &rec);
|
||||
return rec.node;
|
||||
}
|
||||
|
||||
/* Return the bot who we should send the message if we wanted `nick' to get it. */
|
||||
GNode *bot_find_path(BOTNET_REC *botnet, const char *nick)
|
||||
{
|
||||
BOT_FIND_REC rec;
|
||||
GNode *node;
|
||||
|
||||
g_return_val_if_fail(botnet != NULL, NULL);
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
|
||||
rec.key = nick;
|
||||
rec.node = NULL;
|
||||
for (node = botnet->bots->children; node != NULL; node = node->next) {
|
||||
g_node_traverse(node, 0, G_TRAVERSE_ALL, -1,
|
||||
(GNodeTraverseFunc) gnode_find_nick, &rec);
|
||||
if (rec.node != NULL) return node;
|
||||
}
|
||||
return rec.node;
|
||||
}
|
||||
|
||||
/* check if `addr' is an IP address - this is checked to make sure that
|
||||
if we have an address like "192.168.0.*", it wouldn't match to host name
|
||||
192.168.0.host.org */
|
||||
static int is_ip_mask(const char *addr)
|
||||
{
|
||||
while (*addr != '\0') {
|
||||
if (!isdigit(*addr) && *addr != '.' &&
|
||||
*addr != '*' && *addr != '?') return FALSE;
|
||||
addr++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOT_DOWNLINK_REC *bot_downlink_find(BOTNET_REC *botnet, IPADDR *ip, const char *host)
|
||||
{
|
||||
GSList *tmp, *tmp2;
|
||||
char ipname[MAX_IP_LEN];
|
||||
|
||||
g_return_val_if_fail(botnet != NULL, NULL);
|
||||
g_return_val_if_fail(ip != NULL, NULL);
|
||||
|
||||
net_ip2host(ip, ipname);
|
||||
|
||||
for (tmp = botnet->downlinks; tmp != NULL; tmp = tmp->next) {
|
||||
BOT_DOWNLINK_REC *rec = tmp->data;
|
||||
|
||||
for (tmp2 = rec->valid_addrs; tmp2 != NULL; tmp2 = tmp2->next) {
|
||||
if (match_wildcards(tmp2->data, ipname))
|
||||
return rec;
|
||||
if (match_wildcards(tmp2->data, host) &&
|
||||
!is_ip_mask(tmp2->data))
|
||||
return rec;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int gnode_find_master(GNode *node, BOT_FIND_REC *rec)
|
||||
{
|
||||
BOT_REC *bot = node->data;
|
||||
|
||||
if (bot == NULL) return FALSE;
|
||||
|
||||
if (!bot->disconnect && bot->priority > rec->priority) {
|
||||
rec->node = node;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOT_REC *botnet_find_master(BOTNET_REC *botnet, BOT_REC *old_master)
|
||||
{
|
||||
BOT_FIND_REC rec;
|
||||
|
||||
g_return_val_if_fail(botnet != NULL, NULL);
|
||||
|
||||
rec.node = NULL;
|
||||
rec.priority = old_master == NULL ? -1 : old_master->priority;
|
||||
g_node_traverse(botnet->bots, 0, G_TRAVERSE_ALL, -1,
|
||||
(GNodeTraverseFunc) gnode_find_master, &rec);
|
||||
return rec.node == NULL ? old_master : rec.node->data;
|
||||
}
|
||||
|
||||
void botnet_set_master(BOTNET_REC *botnet, BOT_REC *bot)
|
||||
{
|
||||
g_return_if_fail(botnet != NULL);
|
||||
g_return_if_fail(bot != NULL);
|
||||
|
||||
if (botnet->master != NULL)
|
||||
botnet->master->master = FALSE;
|
||||
|
||||
bot->master = TRUE;
|
||||
botnet->master = bot;
|
||||
}
|
||||
|
||||
void bot_nick_destroy(BOT_CHANNEL_REC *rec, NICK_REC *nick)
|
||||
{
|
||||
g_return_if_fail(rec != NULL);
|
||||
g_return_if_fail(nick != NULL);
|
||||
|
||||
rec->nicks = g_slist_remove(rec->nicks, nick);
|
||||
|
||||
g_free(nick->nick);
|
||||
g_free_not_null(nick->realname);
|
||||
g_free_not_null(nick->host);
|
||||
g_free(nick);
|
||||
}
|
||||
|
||||
void bot_channel_destroy(BOT_IRCNET_REC *ircnet, BOT_CHANNEL_REC *rec)
|
||||
{
|
||||
g_return_if_fail(ircnet != NULL);
|
||||
g_return_if_fail(rec != NULL);
|
||||
|
||||
ircnet->channels = g_slist_remove(ircnet->channels, rec);
|
||||
|
||||
while (rec->nicks != NULL)
|
||||
bot_nick_destroy(rec, rec->nicks->data);
|
||||
|
||||
g_slist_foreach(rec->banlist, (GFunc) g_free, NULL);
|
||||
g_slist_foreach(rec->ebanlist, (GFunc) g_free, NULL);
|
||||
g_slist_foreach(rec->invitelist, (GFunc) g_free, NULL);
|
||||
|
||||
g_slist_free(rec->banlist);
|
||||
g_slist_free(rec->ebanlist);
|
||||
g_slist_free(rec->invitelist);
|
||||
|
||||
g_free_not_null(rec->mode);
|
||||
g_free_not_null(rec->key);
|
||||
g_free(rec->name);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
void bot_ircnet_destroy(BOT_REC *bot, BOT_IRCNET_REC *rec)
|
||||
{
|
||||
g_return_if_fail(bot != NULL);
|
||||
g_return_if_fail(rec != NULL);
|
||||
|
||||
bot->ircnets = g_slist_remove(bot->ircnets, bot);
|
||||
|
||||
while (rec->channels != NULL)
|
||||
bot_channel_destroy(rec, rec->channels->data);
|
||||
|
||||
g_free(rec->tag);
|
||||
g_free(rec->ircnet);
|
||||
g_free(rec->server);
|
||||
g_free(rec->nick);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
void bot_disconnect(BOT_REC *bot)
|
||||
{
|
||||
bot->disconnect = TRUE;
|
||||
|
||||
signal_emit("bot disconnected", 1, bot);
|
||||
|
||||
if (bot->read_tag != -1) {
|
||||
g_source_remove(bot->read_tag);
|
||||
bot->read_tag = -1;
|
||||
}
|
||||
if (bot->handle != -1) {
|
||||
net_disconnect(bot->handle);
|
||||
bot->handle = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void bot_mark_disconnect(GNode *node)
|
||||
{
|
||||
BOT_REC *bot = node->data;
|
||||
|
||||
bot->disconnect = TRUE;
|
||||
}
|
||||
|
||||
#define bot_mark_disconnects(node) \
|
||||
g_node_traverse(node, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, \
|
||||
(GNodeTraverseFunc) bot_mark_disconnect, NULL)
|
||||
|
||||
void bot_destroy(BOT_REC *bot)
|
||||
{
|
||||
GNode *node;
|
||||
|
||||
g_return_if_fail(bot != NULL);
|
||||
|
||||
node = g_node_find(bot->botnet->bots, 0, G_TRAVERSE_ALL, bot);
|
||||
if (node != NULL) {
|
||||
if (!bot->disconnect)
|
||||
bot_mark_disconnects(node);
|
||||
}
|
||||
|
||||
bot_disconnect(bot);
|
||||
|
||||
if (node != NULL) {
|
||||
while (node->children != NULL)
|
||||
bot_destroy(node->children->data);
|
||||
g_node_destroy(node);
|
||||
}
|
||||
|
||||
if (bot->botnet->uplink == bot)
|
||||
bot->botnet->uplink = NULL;
|
||||
if (bot->botnet->master == bot)
|
||||
bot->botnet->master = NULL;
|
||||
|
||||
while (bot->ircnets != NULL)
|
||||
bot_ircnet_destroy(bot, bot->ircnets->data);
|
||||
|
||||
line_split_free(bot->buffer);
|
||||
g_free_not_null(bot->nick);
|
||||
g_free(bot);
|
||||
}
|
||||
|
||||
void bot_downlink_destroy(BOT_DOWNLINK_REC *rec)
|
||||
{
|
||||
rec->botnet->downlinks = g_slist_remove(rec->botnet->downlinks, rec);
|
||||
|
||||
g_slist_foreach(rec->valid_addrs, (GFunc) g_free, NULL);
|
||||
g_slist_free(rec->valid_addrs);
|
||||
|
||||
g_free_not_null(rec->password);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
void bot_uplink_destroy(BOT_UPLINK_REC *rec)
|
||||
{
|
||||
rec->botnet->uplinks = g_slist_remove(rec->botnet->uplinks, rec);
|
||||
|
||||
g_free(rec->host);
|
||||
g_free_not_null(rec->password);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
void botnet_disconnect(BOTNET_REC *botnet)
|
||||
{
|
||||
botnet->connected = FALSE;
|
||||
|
||||
bot_destroy(botnet->bots->data);
|
||||
botnet->bots = NULL;
|
||||
|
||||
if (botnet->listen_tag != -1) {
|
||||
g_source_remove(botnet->listen_tag);
|
||||
botnet->listen_tag = -1;
|
||||
}
|
||||
if (botnet->listen_handle != -1) {
|
||||
net_disconnect(botnet->listen_handle);
|
||||
botnet->listen_handle = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void botnet_destroy(BOTNET_REC *botnet)
|
||||
{
|
||||
botnets = g_slist_remove(botnets, botnet);
|
||||
|
||||
while (botnet->uplinks != NULL)
|
||||
bot_uplink_destroy(botnet->uplinks->data);
|
||||
while (botnet->downlinks != NULL)
|
||||
bot_downlink_destroy(botnet->downlinks->data);
|
||||
|
||||
botnet_disconnect(botnet);
|
||||
|
||||
g_free_not_null(botnet->addr);
|
||||
g_free(botnet->name);
|
||||
g_free(botnet->nick);
|
||||
g_free(botnet);
|
||||
}
|
||||
|
||||
static void botnet_event(BOT_REC *bot, const char *data)
|
||||
{
|
||||
char *params, *source, *target, *command, *args, *event;
|
||||
|
||||
if (!bot->connected)
|
||||
return;
|
||||
|
||||
params = cmd_get_params(data, 4 | PARAM_FLAG_GETREST,
|
||||
&source, &target, &command, &args);
|
||||
|
||||
if (*target == '-' && target[1] == '\0')
|
||||
target = NULL;
|
||||
g_strdown(command);
|
||||
|
||||
event = g_strconcat("botnet event ", command, NULL);
|
||||
signal_emit(event, 4, bot, args, source, target);
|
||||
g_free(event);
|
||||
|
||||
g_free(params);
|
||||
}
|
||||
|
||||
static void botnet_event_bcast(BOT_REC *bot, const char *data, const char *sender)
|
||||
{
|
||||
char *str;
|
||||
|
||||
/* broadcast message to all bots */
|
||||
str = g_strdup_printf("BCAST %s", data);
|
||||
botnet_broadcast(bot->botnet, bot, sender, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void botnet_event_master(BOT_REC *bot, const char *data, const char *sender)
|
||||
{
|
||||
BOTNET_REC *botnet;
|
||||
BOT_REC *master;
|
||||
GNode *node;
|
||||
char *str;
|
||||
|
||||
botnet = bot->botnet;
|
||||
|
||||
node = bot_find_nick(bot->botnet, data);
|
||||
master = node == NULL ? NULL : node->data;
|
||||
master = botnet_find_master(bot->botnet, master);
|
||||
g_return_if_fail(master != NULL);
|
||||
|
||||
if (node == NULL || node->data != master) {
|
||||
/* no, we don't agree with that master -
|
||||
send our own to everyone. */
|
||||
bot = NULL;
|
||||
}
|
||||
|
||||
botnet_set_master(botnet, master);
|
||||
|
||||
str = g_strdup_printf("MASTER %s", master->nick);
|
||||
botnet_broadcast(botnet, bot, sender, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void botnet_config_read_ips(BOT_DOWNLINK_REC *rec, CONFIG_NODE *node)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_if_fail(rec != NULL);
|
||||
g_return_if_fail(node != NULL);
|
||||
|
||||
node = config_node_section(node, "valid_addrs", -1);
|
||||
tmp = node == NULL ? NULL : node->value;
|
||||
for (; tmp != NULL; tmp = tmp->next) {
|
||||
node = tmp->data;
|
||||
rec->valid_addrs = g_slist_append(rec->valid_addrs, g_strdup(node->value));
|
||||
}
|
||||
}
|
||||
|
||||
static void botnet_config_read_uplink(BOTNET_REC *botnet, CONFIG_NODE *node)
|
||||
{
|
||||
BOT_UPLINK_REC *rec;
|
||||
char *value;
|
||||
|
||||
g_return_if_fail(botnet != NULL);
|
||||
g_return_if_fail(node != NULL);
|
||||
|
||||
value = config_node_get_str(node, "host", NULL);
|
||||
if (value == NULL) return; /* host required */
|
||||
|
||||
rec = g_new0(BOT_UPLINK_REC, 1);
|
||||
rec->botnet = botnet;
|
||||
rec->host = g_strdup(value);
|
||||
rec->port = config_node_get_int(node, "port", DEFAULT_BOTNET_PORT);
|
||||
rec->password = g_strdup(config_node_get_str(node, "password", NULL));
|
||||
|
||||
botnet->uplinks = g_slist_append(botnet->uplinks, rec);
|
||||
}
|
||||
|
||||
static void botnet_config_read_downlink(BOTNET_REC *botnet, CONFIG_NODE *node)
|
||||
{
|
||||
BOT_DOWNLINK_REC *rec;
|
||||
|
||||
g_return_if_fail(botnet != NULL);
|
||||
g_return_if_fail(node != NULL);
|
||||
|
||||
rec = g_new0(BOT_DOWNLINK_REC, 1);
|
||||
|
||||
botnet_config_read_ips(rec, node);
|
||||
if (rec->valid_addrs == NULL) {
|
||||
g_free(rec);
|
||||
return;
|
||||
}
|
||||
|
||||
rec->botnet = botnet;
|
||||
rec->password = g_strdup(config_node_get_str(node, "password", NULL));
|
||||
botnet->downlinks = g_slist_append(botnet->downlinks, rec);
|
||||
}
|
||||
|
||||
static void botnet_config_read_botnet(CONFIG_NODE *node)
|
||||
{
|
||||
CONFIG_NODE *subnode;
|
||||
BOTNET_REC *botnet;
|
||||
GSList *tmp;
|
||||
|
||||
g_return_if_fail(node != NULL);
|
||||
|
||||
if (node->key == NULL || node->value == NULL)
|
||||
return;
|
||||
|
||||
/* New botnet */
|
||||
botnet = g_new0(BOTNET_REC, 1);
|
||||
botnet->name = g_strdup(node->key);
|
||||
botnet->nick = g_strdup(config_node_get_str(node, "nick", "bot"));
|
||||
botnet->priority = config_node_get_int(node, "priority", DEFAULT_BOTNET_PRIORITY);
|
||||
botnet->autoconnect = config_node_get_bool(node, "autoconnect", FALSE);
|
||||
|
||||
botnet->addr = g_strdup(config_node_get_str(node, "listen_addr", NULL));
|
||||
botnet->port = config_node_get_int(node, "listen_port", DEFAULT_BOTNET_PORT);
|
||||
|
||||
botnet->listen_handle = -1;
|
||||
botnet->listen_tag = -1;
|
||||
|
||||
/* read uplinks */
|
||||
subnode = config_node_section(node, "uplinks", -1);
|
||||
tmp = subnode == NULL ? NULL : subnode->value;
|
||||
for (; tmp != NULL; tmp = tmp->next)
|
||||
botnet_config_read_uplink(botnet, tmp->data);
|
||||
|
||||
/* read downlinks */
|
||||
subnode = config_node_section(node, "downlinks", -1);
|
||||
tmp = subnode == NULL ? NULL : subnode->value;
|
||||
for (; tmp != NULL; tmp = tmp->next)
|
||||
botnet_config_read_downlink(botnet, tmp->data);
|
||||
|
||||
botnets = g_slist_append(botnets, botnet);
|
||||
}
|
||||
|
||||
static void botnet_config_read(void)
|
||||
{
|
||||
CONFIG_REC *config;
|
||||
CONFIG_NODE *node;
|
||||
GSList *tmp;
|
||||
char *fname;
|
||||
|
||||
/* Read botnets from ~/.irssi/botnets */
|
||||
fname = g_strdup_printf("%s/.irssi/botnets", g_get_home_dir());
|
||||
config = config_open(fname, -1);
|
||||
g_free(fname);
|
||||
|
||||
if (config == NULL)
|
||||
return;
|
||||
|
||||
config_parse(config);
|
||||
|
||||
node = config_node_traverse(config, "botnets", FALSE);
|
||||
tmp = node == NULL ? NULL : node->value;
|
||||
for (; tmp != NULL; tmp = tmp->next)
|
||||
botnet_config_read_botnet(tmp->data);
|
||||
config_close(config);
|
||||
}
|
||||
|
||||
/* FIXME: this command is just temporary */
|
||||
static void cmd_botnet(const char *data)
|
||||
{
|
||||
BOTNET_REC *botnet;
|
||||
char *str;
|
||||
|
||||
botnet = botnets->data;
|
||||
|
||||
str = g_strdup_printf("BCAST %s", data);
|
||||
botnet_broadcast(botnet, NULL, NULL, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void autoconnect_botnets(void)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
for (tmp = botnets; tmp != NULL; tmp = tmp->next) {
|
||||
BOTNET_REC *rec = tmp->data;
|
||||
|
||||
if (rec->autoconnect)
|
||||
botnet_connect(rec->name);
|
||||
}
|
||||
}
|
||||
|
||||
void botnet_init(void)
|
||||
{
|
||||
botnet_config_read();
|
||||
botnet_connection_init();
|
||||
|
||||
signal_add("botnet event", (SIGNAL_FUNC) botnet_event);
|
||||
signal_add("botnet event bcast", (SIGNAL_FUNC) botnet_event_bcast);
|
||||
signal_add("botnet event master", (SIGNAL_FUNC) botnet_event_master);
|
||||
command_bind("botnet", NULL, (SIGNAL_FUNC) cmd_botnet);
|
||||
|
||||
autoconnect_botnets();
|
||||
}
|
||||
|
||||
void botnet_deinit(void)
|
||||
{
|
||||
while (botnets)
|
||||
botnet_destroy(botnets->data);
|
||||
|
||||
botnet_connection_deinit();
|
||||
|
||||
signal_remove("botnet event", (SIGNAL_FUNC) botnet_event);
|
||||
signal_remove("botnet event bcast", (SIGNAL_FUNC) botnet_event_bcast);
|
||||
signal_remove("botnet event master", (SIGNAL_FUNC) botnet_event_master);
|
||||
command_unbind("botnet", (SIGNAL_FUNC) cmd_botnet);
|
||||
}
|
||||
124
src/irc/bot/botnet.h
Normal file
124
src/irc/bot/botnet.h
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
#ifndef __BOT_BOTNET_H
|
||||
#define __BOT_BOTNET_H
|
||||
|
||||
#include "nicklist.h"
|
||||
|
||||
#define DEFAULT_BOTNET_PORT 2255
|
||||
#define DEFAULT_BOTNET_PRIORITY 5
|
||||
|
||||
typedef struct _botnet_rec BOTNET_REC;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
GSList *nicks; /* NICK_RECs */
|
||||
int chanop:1;
|
||||
|
||||
GSList *banlist;
|
||||
GSList *ebanlist;
|
||||
GSList *invitelist;
|
||||
|
||||
char *mode;
|
||||
int limit;
|
||||
char *key;
|
||||
} BOT_CHANNEL_REC;
|
||||
|
||||
typedef struct {
|
||||
char *tag; /* same as server->tag */
|
||||
char *ircnet;
|
||||
char *server;
|
||||
char *nick;
|
||||
|
||||
GSList *channels;
|
||||
} BOT_IRCNET_REC;
|
||||
|
||||
typedef struct {
|
||||
BOTNET_REC *botnet;
|
||||
void *link; /* NULL, BOT_UPLINK_REC or BOT_DOWNLINK_REC */
|
||||
|
||||
int uplink:1; /* this is our uplink */
|
||||
int pass_ok:1; /* downlink's password was ok */
|
||||
int connected:1; /* bot is in this botnet now */
|
||||
int disconnect:1; /* just disconnecting this bot.. */
|
||||
int master:1; /* this bot is the bot network's current master */
|
||||
|
||||
char *nick; /* bot's unique nick in botnet */
|
||||
int priority;
|
||||
|
||||
int handle;
|
||||
int read_tag;
|
||||
void *buffer;
|
||||
|
||||
GSList *ircnets;
|
||||
} BOT_REC;
|
||||
|
||||
typedef struct {
|
||||
BOTNET_REC *botnet;
|
||||
|
||||
char *host;
|
||||
int port;
|
||||
char *password;
|
||||
|
||||
time_t last_connect;
|
||||
} BOT_UPLINK_REC;
|
||||
|
||||
typedef struct {
|
||||
BOTNET_REC *botnet;
|
||||
|
||||
GSList *valid_addrs; /* IP/host masks where this bot is allowed to connect */
|
||||
char *password;
|
||||
} BOT_DOWNLINK_REC;
|
||||
|
||||
struct _botnet_rec {
|
||||
int connected:1;
|
||||
int autoconnect:1;
|
||||
|
||||
char *name; /* botnet name */
|
||||
char *nick; /* our nick in botnet */
|
||||
int priority; /* our priority in botnet */
|
||||
|
||||
char *addr; /* in what address we should listen, NULL = all */
|
||||
int port; /* what port we should listen, 0 = default, -1 = don't listen */
|
||||
|
||||
int listen_handle;
|
||||
int listen_tag;
|
||||
|
||||
GSList *uplinks;
|
||||
GSList *downlinks;
|
||||
|
||||
GNode *bots;
|
||||
BOT_REC *uplink; /* our current uplink */
|
||||
BOT_REC *master; /* link to current master */
|
||||
};
|
||||
|
||||
void bot_send_cmd(BOT_REC *bot, char *data);
|
||||
void bot_send_cmdv(BOT_REC *bot, char *format, ...);
|
||||
|
||||
/* broadcast a message to everyone in bot network, except for `except_bot'
|
||||
if it's not NULL */
|
||||
void botnet_broadcast(BOTNET_REC *botnet, BOT_REC *except_bot,
|
||||
const char *source, const char *data);
|
||||
|
||||
BOT_REC *botnet_find_master(BOTNET_REC *botnet, BOT_REC *old_master);
|
||||
void botnet_set_master(BOTNET_REC *botnet, BOT_REC *bot);
|
||||
|
||||
BOTNET_REC *botnet_find(const char *name);
|
||||
GNode *bot_find_nick(BOTNET_REC *botnet, const char *nick);
|
||||
/* Return the bot who we should send the message if we wanted `nick' to get it. */
|
||||
GNode *bot_find_path(BOTNET_REC *botnet, const char *nick);
|
||||
|
||||
BOT_DOWNLINK_REC *bot_downlink_find(BOTNET_REC *botnet, IPADDR *ip, const char *host);
|
||||
|
||||
void bot_nick_destroy(BOT_CHANNEL_REC *rec, NICK_REC *nick);
|
||||
void bot_channel_destroy(BOT_IRCNET_REC *ircnet, BOT_CHANNEL_REC *rec);
|
||||
void bot_ircnet_destroy(BOT_REC *bot, BOT_IRCNET_REC *rec);
|
||||
|
||||
void bot_disconnect(BOT_REC *bot);
|
||||
void bot_destroy(BOT_REC *bot);
|
||||
|
||||
void bot_downlink_destroy(BOT_DOWNLINK_REC *rec);
|
||||
void bot_uplink_destroy(BOT_UPLINK_REC *rec);
|
||||
|
||||
int botnet_connect(const char *network);
|
||||
void botnet_disconnect(BOTNET_REC *botnet);
|
||||
|
||||
#endif
|
||||
15
src/irc/bot/botnets.sample
Normal file
15
src/irc/bot/botnets.sample
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
botnets = {
|
||||
irssinet = {
|
||||
nick = irssibot;
|
||||
priority = 5;
|
||||
autoconnect = yes;
|
||||
uplinks = (
|
||||
{ host = "main.botnet.org"; password = "mypass"; }
|
||||
);
|
||||
downlinks = (
|
||||
{ password = "thepass"; valid_addrs = ( "192.168.0.*" ); },
|
||||
{ password = "blah"; valid_addrs = ( "*.botnet.org" ); },
|
||||
{ password = "localpass"; valid_addrs = ( "127.*" ); }
|
||||
);
|
||||
};
|
||||
};
|
||||
3
src/irc/bot/module.h
Normal file
3
src/irc/bot/module.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#include "common.h"
|
||||
|
||||
#define MODULE_NAME "irc/bot"
|
||||
18
src/irc/bot/users.sample
Normal file
18
src/irc/bot/users.sample
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
users =
|
||||
{
|
||||
mynick = {
|
||||
flags = oa;
|
||||
masks = (
|
||||
{ mask="*!*@somewhere" },
|
||||
{ mask="*!*@somewhere.else"; not_flags=a; }
|
||||
);
|
||||
};
|
||||
|
||||
other = {
|
||||
masks = ( { mask="*!nick@home.org"; } );
|
||||
channels = (
|
||||
{ channel = "#irssi";flags = oa; },
|
||||
{ channel = "#chan";flags = oa; }
|
||||
);
|
||||
};
|
||||
};
|
||||
|
|
@ -41,7 +41,6 @@ noinst_HEADERS = \
|
|||
channels-setup.h \
|
||||
ignore.h \
|
||||
irc.h \
|
||||
irc-core.h \
|
||||
irc-server.h \
|
||||
ircnet-setup.h \
|
||||
masks.h \
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ static IRC_SERVER_REC *connect_server(const char *data)
|
|||
if (*host != '\0') {
|
||||
IPADDR ip;
|
||||
|
||||
if (net_gethostname(host, &ip) == 0) {
|
||||
if (net_gethostbyname(host, &ip) == 0) {
|
||||
if (conn->own_ip == NULL)
|
||||
conn->own_ip = g_new(IPADDR, 1);
|
||||
memcpy(conn->own_ip, &ip, sizeof(IPADDR));
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
#ifndef __IRC_CORE_H
|
||||
#define __IRC_CORE_H
|
||||
|
||||
void irc_core_init(void);
|
||||
void irc_core_deinit(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
#include "signals.h"
|
||||
|
||||
#include "irc.h"
|
||||
#include "modes.h"
|
||||
#include "mode-lists.h"
|
||||
#include "nicklist.h"
|
||||
|
||||
|
|
@ -322,9 +323,6 @@ void channel_set_singlemode(IRC_SERVER_REC *server, const char *channel, const c
|
|||
g_string_free(str, TRUE);
|
||||
}
|
||||
|
||||
#define MODE_HAS_ARG(c) ((c) == 'b' || (c) == 'e' || (c) == 'I' || \
|
||||
(c) == 'v' || (c) == 'o' || (c) == 'l' || (c) == 'k')
|
||||
|
||||
void channel_set_mode(IRC_SERVER_REC *server, const char *channel, const char *mode)
|
||||
{
|
||||
char *modestr, *curmode, *orig;
|
||||
|
|
@ -343,7 +341,7 @@ void channel_set_mode(IRC_SERVER_REC *server, const char *channel, const char *m
|
|||
|
||||
curmode = cmd_get_param(&modestr);
|
||||
for (; *curmode != '\0'; curmode++) {
|
||||
if (count == server->connrec->max_modes && MODE_HAS_ARG(*curmode)) {
|
||||
if (count == server->connrec->max_modes && HAS_MODE_ARG(*curmode)) {
|
||||
irc_send_cmdv(server, "MODE %s %s%s", channel, tmode->str, targs->str);
|
||||
|
||||
count = 0;
|
||||
|
|
@ -353,7 +351,7 @@ void channel_set_mode(IRC_SERVER_REC *server, const char *channel, const char *m
|
|||
|
||||
g_string_append_c(tmode, *curmode);
|
||||
|
||||
if (MODE_HAS_ARG(*curmode)) {
|
||||
if (HAS_MODE_ARG(*curmode)) {
|
||||
char *arg;
|
||||
|
||||
count++;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@
|
|||
#include "server.h"
|
||||
#include "channels.h"
|
||||
|
||||
#define HAS_MODE_ARG(c) ((c) == 'b' || (c) == 'e' || (c) == 'I' || \
|
||||
(c) == 'v' || (c) == 'o' || (c) == 'l' || (c) == 'k')
|
||||
|
||||
void modes_init(void);
|
||||
void modes_deinit(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef __NICKLIST_H
|
||||
#define __NICKLIST_H
|
||||
|
||||
#include "irc-server.h"
|
||||
#include "channels.h"
|
||||
|
||||
typedef struct {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ static void get_source_host_ip(void)
|
|||
/* FIXME: This will block! */
|
||||
if (!source_host_ok) {
|
||||
source_host_ok = *settings_get_str("hostname") != '\0' &&
|
||||
net_gethostname(settings_get_str("hostname"), &ip) == 0;
|
||||
net_gethostbyname(settings_get_str("hostname"), &ip) == 0;
|
||||
if (source_host_ok) {
|
||||
source_host_ip = g_new(IPADDR, 1);
|
||||
memcpy(source_host_ip, &ip, sizeof(IPADDR));
|
||||
|
|
@ -100,7 +100,7 @@ create_addr_conn(const char *address, int port, const char *password,
|
|||
/* resolve the IP and use it */
|
||||
IPADDR ip;
|
||||
|
||||
if (net_gethostname(sserver->own_host, &ip) == 0) {
|
||||
if (net_gethostbyname(sserver->own_host, &ip) == 0) {
|
||||
if (conn->own_ip == NULL)
|
||||
conn->own_ip = g_new(IPADDR, 1);
|
||||
memcpy(conn->own_ip, &ip, sizeof(IPADDR));
|
||||
|
|
|
|||
|
|
@ -508,7 +508,7 @@ static void event_no_such_nick(gchar *data, IRC_SERVER_REC *server)
|
|||
g_free(params);
|
||||
}
|
||||
|
||||
void dcc_init(void)
|
||||
void irc_dcc_init(void)
|
||||
{
|
||||
dcc_conns = NULL;
|
||||
dcc_timeouttag = g_timeout_add(1000, (GSourceFunc) dcc_timeout_func, NULL);
|
||||
|
|
@ -542,7 +542,7 @@ void dcc_init(void)
|
|||
dcc_files_init();
|
||||
}
|
||||
|
||||
void dcc_deinit(void)
|
||||
void irc_dcc_deinit(void)
|
||||
{
|
||||
dcc_chat_deinit();
|
||||
dcc_files_deinit();
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ static void read_settings(void)
|
|||
}
|
||||
}
|
||||
|
||||
void flood_init(void)
|
||||
void irc_flood_init(void)
|
||||
{
|
||||
settings_add_int("flood", "flood_timecheck", 5000);
|
||||
settings_add_int("flood", "flood_max_msgs", 4);
|
||||
|
|
@ -272,7 +272,7 @@ void flood_init(void)
|
|||
autoignore_init();
|
||||
}
|
||||
|
||||
void flood_deinit(void)
|
||||
void irc_flood_deinit(void)
|
||||
{
|
||||
autoignore_deinit();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
void irc_core_init(void);
|
||||
void irc_core_deinit(void);
|
||||
|
||||
void dcc_init(void);
|
||||
void dcc_deinit(void);
|
||||
|
||||
void flood_init(void);
|
||||
void flood_deinit(void);
|
||||
|
||||
void notifylist_init(void);
|
||||
void notifylist_deinit(void);
|
||||
|
||||
void irc_init(void)
|
||||
{
|
||||
irc_core_init();
|
||||
dcc_init();
|
||||
flood_init();
|
||||
notifylist_init();
|
||||
}
|
||||
|
||||
void irc_deinit(void)
|
||||
{
|
||||
notifylist_deinit();
|
||||
flood_deinit();
|
||||
dcc_deinit();
|
||||
irc_core_deinit();
|
||||
}
|
||||
|
|
@ -322,7 +322,7 @@ static void sig_channel_wholist(CHANNEL_REC *channel)
|
|||
g_slist_free(nicks);
|
||||
}
|
||||
|
||||
void notifylist_init(void)
|
||||
void irc_notifylist_init(void)
|
||||
{
|
||||
notifylist_read_config();
|
||||
|
||||
|
|
@ -338,7 +338,7 @@ void notifylist_init(void)
|
|||
signal_add("setup reread", (SIGNAL_FUNC) notifylist_read_config);
|
||||
}
|
||||
|
||||
void notifylist_deinit(void)
|
||||
void irc_notifylist_deinit(void)
|
||||
{
|
||||
notifylist_commands_deinit();
|
||||
notifylist_ison_deinit();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue