From: pk910 Date: Sat, 30 Jun 2012 16:20:34 +0000 (+0200) Subject: added NeonBackup bot X-Git-Tag: v5.4~16 X-Git-Url: http://git.pk910.de/?p=NeonServV5.git;a=commitdiff_plain;h=ee3a72eb4a412a0a504d070db1b41c6907f7604d added NeonBackup bot --- diff --git a/Makefile.am b/Makefile.am index e125423..82b3e8e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,7 @@ checkversion: cd src && chmod +x version.sh && ./version.sh && cd .. noinst_PROGRAMS = neonserv -noinst_LTLIBRARIES = libDummyServ.la libfuncmds.la libglobalcmd.la libNeonHelp.la libNeonServ.la libNeonSpam.la libstats.la libNeonFun.la +noinst_LTLIBRARIES = libDummyServ.la libfuncmds.la libglobalcmd.la libNeonHelp.la libNeonBackup.la libNeonServ.la libNeonSpam.la libstats.la libNeonFun.la libDummyServ_la_SOURCES = src/modules/DummyServ.mod/bot_DummyServ.c \ src/modules/DummyServ.mod/module.c @@ -64,6 +64,12 @@ libNeonHelp_la_SOURCES = src/modules/NeonHelp.mod/bot_NeonHelp.c \ libNeonHelp_la_LDFLAGS = -module -rpath /nowhere -avoid-version -no-undefined libNeonHelp_la_LIBADD = $(MYSQL_LIBS) +libNeonBackup_la_SOURCES = src/modules/NeonBackup.mod/bot_NeonBackup.c \ + src/modules/NeonBackup.mod/cmd_neonbackup.c \ + src/modules/NeonBackup.mod/module.c +libNeonBackup_la_LDFLAGS = -module -rpath /nowhere -avoid-version -no-undefined +libNeonBackup_la_LIBADD = $(MYSQL_LIBS) + libNeonServ_la_SOURCES = src/modules/NeonServ.mod/bot_NeonServ.c \ src/modules/NeonServ.mod/cmd_neonserv.c \ src/modules/NeonServ.mod/cmd_neonserv_access.c \ @@ -192,6 +198,7 @@ neonserv_SOURCES = src/version.c \ src/QServer.c \ src/modules.c \ src/module_commands.c \ + src/ModuleFunctions.c \ src/memoryDebug.c neonserv_LDADD = $(MYSQL_LIBS) $(SYSTEM_LIBS) diff --git a/neonserv.example.conf b/neonserv.example.conf index bc09736..d93cd42 100644 --- a/neonserv.example.conf +++ b/neonserv.example.conf @@ -78,6 +78,16 @@ "chan_expire_freq" = "3d"; // How long is a channel unvisited (by masters or above) before it can be expired? "chan_expire_delay" = "30d"; + // Automatically register a Backup bot with NeonServ + "auto_backup_register" = 0; + // Automatically unregister all Backup when NeonServ gets removed + "auto_backup_unregister" = 1; + // BackupServ channel setting + "channel_backup_setting" = 1; + }; + "libNeonBackup" { + "enabled" = 1; + "protected" = 0; }; "libNeonSpam" { "enabled" = 1; diff --git a/src/ClientSocket.h b/src/ClientSocket.h index a65dfdf..9261be3 100644 --- a/src/ClientSocket.h +++ b/src/ClientSocket.h @@ -19,18 +19,19 @@ #include "main.h" -#define SOCKET_FLAG_DEAD 0x01 -#define SOCKET_FLAG_CONNECTED 0x02 -#define SOCKET_FLAG_READY 0x04 -#define SOCKET_FLAG_PREFERRED 0x08 /* prefered bot to send datas to the IRC World (NOTICE's WHO's etc pp) */ -#define SOCKET_FLAG_USE_QUEUE 0x10 -#define SOCKET_FLAG_RECONNECT 0x20 -#define SOCKET_FLAG_SSL 0x40 -#define SOCKET_FLAG_HAVE_SSL 0x80 -#define SOCKET_FLAG_QUITTED 0x100 -#define SOCKET_FLAG_FAST_JUMP 0x200 -#define SOCKET_FLAG_SILENT 0x400 -#define SOCKET_FLAG_CHANGENICK 0x800 +#define SOCKET_FLAG_DEAD 0x01 +#define SOCKET_FLAG_CONNECTED 0x02 +#define SOCKET_FLAG_READY 0x04 +#define SOCKET_FLAG_PREFERRED 0x08 /* prefered bot to send datas to the IRC World (NOTICE's WHO's etc pp) */ +#define SOCKET_FLAG_USE_QUEUE 0x10 +#define SOCKET_FLAG_RECONNECT 0x20 +#define SOCKET_FLAG_SSL 0x40 +#define SOCKET_FLAG_HAVE_SSL 0x80 +#define SOCKET_FLAG_QUITTED 0x100 +#define SOCKET_FLAG_FAST_JUMP 0x200 +#define SOCKET_FLAG_SILENT 0x400 +#define SOCKET_FLAG_CHANGENICK 0x800 +#define SOCKET_FLAG_REQUEST_INVITE 0x1000 #define SOCKET_HAVE_BOTCLASSVALUE1 0x10000000 #define SOCKET_HAVE_BOTCLASSVALUE2 0x20000000 diff --git a/src/IRCParser.c b/src/IRCParser.c index 2ff95c8..ca42770 100644 --- a/src/IRCParser.c +++ b/src/IRCParser.c @@ -27,6 +27,7 @@ #include "BanNode.h" #include "ModeNode.h" #include "tools.h" +#include "bots.h" struct irc_cmd *irc_commands = NULL; static struct UserNode *registering_users = NULL; @@ -798,6 +799,15 @@ static IRC_CMD(raw_005) { return 1; } +static IRC_CMD(raw_nojoin) { + if(from == NULL || argc < 3) return 0; + struct ChanNode *chan = getChanByName(argv[1]); + if(chan == NULL) return 0; + if(client->flags & SOCKET_FLAG_REQUEST_INVITE) + requestInvite(client->user, chan); + return 1; +} + void init_parser() { //all the raws we receive... register_irc_function("437", raw_437); @@ -808,6 +818,10 @@ void init_parser() { register_irc_function("324", raw_324); register_irc_function("332", raw_332); register_irc_function("367", raw_367); + register_irc_function("471", raw_nojoin); + register_irc_function("473", raw_nojoin); + register_irc_function("474", raw_nojoin); + register_irc_function("475", raw_nojoin); register_irc_function("INVITE", raw_invite); register_irc_function("NOTICE", raw_notice); register_irc_function("TOPIC", raw_topic); diff --git a/src/ModuleFunctions.c b/src/ModuleFunctions.c new file mode 100644 index 0000000..250de3f --- /dev/null +++ b/src/ModuleFunctions.c @@ -0,0 +1,90 @@ +/* ModuleFunctions.c - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ +#include "ModuleFunctions.h" +#include "modules.h" +#include "ChanNode.h" +#ifndef WIN32 +#include +#endif + +#define FUNCTION_GLOBAL_CMD_REGISTER_NEONBACKUP 0 +#define FUNCTION_GLOBAL_CMD_UNREGISTER_NEONBACKUP 1 +#define FUNCTION_NEONBACKUP_RECOVER_CHAN 2 + +#define TOTAL_FUNCTIONS 3 + +struct module_function { + struct ModuleInfo *module; + void *function; +}; + +static struct module_function module_functions[TOTAL_FUNCTIONS]; + +void init_modulefunctions() { + int i; + for(i = 0; i < TOTAL_FUNCTIONS; i++) { + module_functions[i].function = NULL; + } +} + +void scan_module(struct ModuleInfo *module) { + char *function_names[] = { + "global_cmd_register_neonbackup", /* FUNCTION_GLOBAL_CMD_REGISTER_NEONBACKUP */ + "global_cmd_unregister_neonbackup", /* FUNCTION_GLOBAL_CMD_UNREGISTER_NEONBACKUP */ + "neonbackup_recover_chan" /* FUNCTION_NEONBACKUP_RECOVER_CHAN */ + }; + int i; + for(i = 0; i < TOTAL_FUNCTIONS; i++) { + #ifndef WIN32 + void* func = dlsym(module->module, function_names[i]); + #else + FARPROC func = GetProcAddress(module->module, function_names[i]); + #endif + if(func) { + module_functions[i].module = module; + module_functions[i].function = func; + } + } +} + +void free_module_functions(struct ModuleInfo *module) { + int i; + for(i = 0; i < TOTAL_FUNCTIONS; i++) { + if(module_functions[i].module == module) { + module_functions[i].function = NULL; + } + } +} + +/* function handlers */ +void module_global_cmd_register_neonbackup(char *chan) { + if(!module_functions[FUNCTION_GLOBAL_CMD_REGISTER_NEONBACKUP].function) + return; + ((void (*)(char *)) module_functions[FUNCTION_GLOBAL_CMD_REGISTER_NEONBACKUP].function)(chan); +} + +void module_global_cmd_unregister_neonbackup(char *chan) { + if(!module_functions[FUNCTION_GLOBAL_CMD_UNREGISTER_NEONBACKUP].function) + return; + ((void (*)(char *)) module_functions[FUNCTION_GLOBAL_CMD_UNREGISTER_NEONBACKUP].function)(chan); +} + +void module_neonbackup_recover_chan(struct ChanNode *chan) { + if(!module_functions[FUNCTION_NEONBACKUP_RECOVER_CHAN].function) + return; + ((void (*)(struct ChanNode *)) module_functions[FUNCTION_NEONBACKUP_RECOVER_CHAN].function)(chan); +} diff --git a/src/ModuleFunctions.h b/src/ModuleFunctions.h new file mode 100644 index 0000000..51281d3 --- /dev/null +++ b/src/ModuleFunctions.h @@ -0,0 +1,34 @@ +/* ModuleFunctions.h - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ +#ifndef _ModuleFunctions_h +#define _ModuleFunctions_h +#include "overall.h" + +#ifndef DND_FUNCTIONS +struct ModuleInfo; +struct ChanNode; + +void init_modulefunctions(); +void scan_module(struct ModuleInfo *module); +void free_module_functions(struct ModuleInfo *module); + +/* MODULAR ACCESSIBLE */ void module_global_cmd_register_neonbackup(char *chan); +/* MODULAR ACCESSIBLE */ void module_global_cmd_unregister_neonbackup(char *chan); +/* MODULAR ACCESSIBLE */ void module_neonbackup_recover_chan(struct ChanNode *chan); + +#endif +#endif diff --git a/src/bots.c b/src/bots.c index 7ada743..1fe8cea 100644 --- a/src/bots.c +++ b/src/bots.c @@ -157,6 +157,22 @@ void requestOp(struct UserNode *user, struct ChanNode *chan) { } } +void requestInvite(struct UserNode *user, struct ChanNode *chan) { + struct ClientSocket *bot, *userbot = NULL; + struct ChanUser *chanuser = getChanUser(user, chan); + char invited = 0; + if(chanuser) return; + for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) { + if(!invited && (chanuser = getChanUser(bot->user, chan)) != NULL && (chanuser->flags & CHANUSERFLAG_OPPED)) { + invited = 1; + putsock(bot, "INVITE %s %s", user->nick, chan->name); + } + if(bot->user == user) { + userbot = bot; + } + } +} + TIMEQ_CALLBACK(channel_ban_timeout) { char *str_banid = data; MYSQL_RES *res; diff --git a/src/bots.h b/src/bots.h index b0712e8..dd40e34 100644 --- a/src/bots.h +++ b/src/bots.h @@ -29,6 +29,7 @@ void init_bots(); /* MODULAR ACCESSIBLE */ struct ClientSocket *getChannelBot(struct ChanNode *chan, int botid); /* MODULAR ACCESSIBLE */ void requestOp(struct UserNode *user, struct ChanNode *chan); +/* MODULAR ACCESSIBLE */ void requestInvite(struct UserNode *user, struct ChanNode *chan); /* MODULAR ACCESSIBLE */ TIMEQ_CALLBACK(channel_ban_timeout); /* MODULAR ACCESSIBLE */ void general_event_privctcp(struct UserNode *user, struct UserNode *target, char *command, char *text); /* MODULAR ACCESSIBLE */ void set_bot_alias(int botid, char *alias); diff --git a/src/main.c b/src/main.c index f3afaaf..0819378 100644 --- a/src/main.c +++ b/src/main.c @@ -40,6 +40,7 @@ #include "version.h" #include "modules.h" #include "module_commands.h" +#include "ModuleFunctions.h" time_t start_time; static int running, hard_restart; @@ -295,6 +296,7 @@ main: register_module_commands(); init_handleinfohandler(); init_tools(); + init_modulefunctions(); loadModules(); init_bots(); init_DBHelper(); diff --git a/src/modules.c b/src/modules.c index 4372c48..5ada206 100644 --- a/src/modules.c +++ b/src/modules.c @@ -46,6 +46,8 @@ /* 184-188 */ #include "version.h" /* 189 */ /* modules.h */ /* 190 */ /* UserNode.h */ +/* 191-193 */ #include "ModuleFunctions.h" +/* 194 */ /* bots.h */ #define Function void * @@ -251,7 +253,11 @@ void *global_functions[] = { /* 187 */ (Function) get_codelines, /* 188 */ (Function) get_patchlevel, /* 189 */ (Function) get_module_name, -/* 190 */ (Function) isUserModeSet +/* 190 */ (Function) isUserModeSet, +/* 191 */ (Function) module_global_cmd_register_neonbackup, +/* 192 */ (Function) module_global_cmd_unregister_neonbackup, +/* 193 */ (Function) module_neonbackup_recover_chan, +/* 194 */ (Function) requestInvite }; static int module_id_counter = 1; @@ -348,6 +354,7 @@ struct ModuleInfo *loadModule(char *name) { modinfo->state = 0; modinfo->next = modules; modules = modinfo; + scan_module(modinfo); return modinfo; } @@ -388,6 +395,7 @@ int ext_unload_module(char *name) { unregister_module_hooks(old_modinfo->module_id); ((void (*)(int)) old_modinfo->stopfunc)(MODSTATE_STARTSTOP); closemodule(old_modinfo->module); + free_module_functions(old_modinfo); free(old_modinfo->name); free(old_modinfo); return 1; @@ -410,6 +418,7 @@ int ext_reload_module(char *name) { unregister_module_hooks(old_modinfo->module_id); ((void (*)(int)) old_modinfo->stopfunc)(MODSTATE_RELOAD); closemodule(old_modinfo->module); + free_module_functions(old_modinfo); free(old_modinfo->name); free(old_modinfo); break; @@ -456,6 +465,7 @@ void stop_modules() { unregister_module_hooks(modinfo->module_id); ((void (*)(int)) modinfo->stopfunc)(MODSTATE_STARTSTOP); closemodule(modinfo->module); + free_module_functions(modinfo); free(modinfo->name); free(modinfo); } @@ -466,6 +476,7 @@ static void unregister_module_hooks(int module_id) { unregister_module_commands(module_id); unregister_module_events(module_id); unregister_module_timers(module_id); + } int module_loaded(int module_id) { @@ -487,3 +498,5 @@ char *get_module_name(int module_id) { } return NULL; } + + diff --git a/src/modules/DummyServ.mod/bot_DummyServ.c b/src/modules/DummyServ.mod/bot_DummyServ.c index 2911b23..1b078ec 100644 --- a/src/modules/DummyServ.mod/bot_DummyServ.c +++ b/src/modules/DummyServ.mod/bot_DummyServ.c @@ -108,6 +108,33 @@ static void start_bots(int type) { bind_unbound_required_functions(BOTID); } +static void dummyserv_event_invite(struct ClientSocket *client, struct UserNode *user, char *channel) { + if(client->botid != BOTID) + return; + MYSQL_RES *res; + MYSQL_ROW row; + printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` LEFT JOIN `channels` ON `chanid` = `channel_id` WHERE `channel_name` = '%s' AND `botclass` = '%d'", escape_string(channel), client->botid); + res = mysql_use(); + if ((row = mysql_fetch_row(res)) == NULL) { + reply(client, user, "NS_INVITE_FAIL", channel, client->user->nick); + return; + } + if(!strcmp(row[2], "1")) { + return; + } + int botid = atoi(row[0]); + struct ClientSocket *bot; + for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) { + if(bot->clientid == botid) + break; + } + if(bot) { + struct ChanNode *chan = getChanByName(channel); + if(!(chan && isUserOnChan(bot->user, chan))) + putsock(bot, "JOIN %s", channel); + } +} + void init_DummyServ(int type) { set_bot_alias(BOTID, BOTALIAS); start_bots(type); @@ -116,6 +143,7 @@ void init_DummyServ(int type) { //register events bind_bot_ready(dummyserv_bot_ready, module_id); + bind_invite(dummyserv_event_invite, module_id); set_trigger_callback(BOTID, module_id, dummyserv_trigger_callback); } diff --git a/src/modules/NeonBackup.mod/bot_NeonBackup.c b/src/modules/NeonBackup.mod/bot_NeonBackup.c new file mode 100644 index 0000000..916e3b2 --- /dev/null +++ b/src/modules/NeonBackup.mod/bot_NeonBackup.c @@ -0,0 +1,203 @@ +/* bot_NeonBackup.c - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ +#include "../module.h" +#include "../botid.h" + +#include "bot_NeonBackup.h" +#include "../../modcmd.h" +#include "cmd_neonbackup.h" +#include "../../lang.h" +#include "../../mysqlConn.h" +#include "../../ClientSocket.h" +#include "../../UserNode.h" +#include "../../ChanNode.h" +#include "../../ChanUser.h" +#include "../../IRCEvents.h" +#include "../../IRCParser.h" +#include "../../bots.h" +#include "../../DBHelper.h" +#include "../../WHOHandler.h" + +#define BOTID NEONBACKUP_BOTID +#define BOTALIAS "NeonBackup" + +static const struct default_language_entry msgtab[] = { + {NULL, NULL} +}; + +static void neonbackup_bot_ready(struct ClientSocket *client) { + MYSQL_RES *res; + MYSQL_ROW row; + + printf_mysql_query("SELECT `automodes`, `oper_user`, `oper_pass` FROM `bots` WHERE `id` = '%d'", client->clientid); + res = mysql_use(); + if ((row = mysql_fetch_row(res)) != NULL) { + if(row[1] && row[2]) { + putsock(client, "OPER %s %s", row[1], row[2]); + } + putsock(client, "MODE %s +%s", client->user->nick, row[0]); + } + + printf_mysql_query("SELECT `channel_name`, `channel_key` FROM `bot_channels` LEFT JOIN `channels` ON `chanid` = `channel_id` WHERE `botid` = '%d' AND `suspended` = '0'", client->clientid); + res = mysql_use(); + + while ((row = mysql_fetch_row(res)) != NULL) { + putsock(client, "JOIN %s %s", row[0], row[1]); + } +} + +static void neonbackup_trigger_callback(int clientid, struct ChanNode *chan, char *trigger) { + MYSQL_RES *res; + MYSQL_ROW row; + loadChannelSettings(chan); + if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) { + strcpy(trigger, "!"); + return; + } + printf_mysql_query("SELECT `trigger`, `defaulttrigger` FROM `bot_channels` LEFT JOIN `bots` ON `botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chan->channel_id, BOTID); + res = mysql_use(); + if(!(row = mysql_fetch_row(res))) { + strcpy(trigger, "+"); + return; + } + if(row[0] && *row[0]) + strcpy(trigger, row[0]); + else + strcpy(trigger, ((row[1] && *row[1]) ? row[1] : "+")); +} + +static void start_bots(int type) { + struct ClientSocket *client; + MYSQL_RES *res, *res2; + MYSQL_ROW row; + + if(type == MODSTATE_STARTSTOP) { + printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID); + res = mysql_use(); + + while ((row = mysql_fetch_row(res)) != NULL) { + client = create_socket(row[3], atoi(row[4]), row[10], row[5], row[0], row[1], row[2]); + client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0); + client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0); + client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0); + client->flags |= SOCKET_FLAG_REQUEST_INVITE; + client->botid = BOTID; + client->clientid = atoi(row[7]); + connect_socket(client); + } + } + + printf_mysql_query("SELECT `command`, `function`, `parameters`, `global_access`, `chan_access`, `flags` FROM `bot_binds` WHERE `botclass` = '%d'", BOTID); + res2 = mysql_use(); + while ((row = mysql_fetch_row(res2)) != NULL) { + if(bind_cmd_to_command(BOTID, row[0], row[1])) { + if(row[2] && strcmp(row[2], "")) { + bind_set_parameters(BOTID, row[0], row[2]); + } + if(row[3]) { + bind_set_global_access(BOTID, row[0], atoi(row[3])); + } + if(row[4]) { + bind_set_channel_access(BOTID, row[0], row[4]); + } + if(strcmp(row[5], "0")) + bind_set_bind_flags(BOTID, row[0], atoi(row[5])); + } + } + bind_unbound_required_functions(BOTID); +} + +void neonbackup_recover_chan(struct ChanNode *chan) { + +} + +static void neonbackup_event_join(struct ChanUser *chanuser) { + struct ClientSocket *client = getChannelBot(chanuser->chan, BOTID); + if(!client) return; //we can't "see" this event + if(chanuser->user == client->user) { + requestOp(client->user, chanuser->chan); + neonbackup_recover_chan(chanuser->chan); + } +} + +static void neonbackup_event_invite(struct ClientSocket *client, struct UserNode *user, char *channel) { + if(client->botid != BOTID) + return; + MYSQL_RES *res; + MYSQL_ROW row; + printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` LEFT JOIN `channels` ON `chanid` = `channel_id` WHERE `channel_name` = '%s' AND `botclass` = '%d'", escape_string(channel), client->botid); + res = mysql_use(); + if ((row = mysql_fetch_row(res)) == NULL) { + reply(client, user, "NS_INVITE_FAIL", channel, client->user->nick); + return; + } + if(!strcmp(row[2], "1")) { + reply(client, user, "MODCMD_CHAN_SUSPENDED"); + return; + } + int botid = atoi(row[0]); + struct ClientSocket *bot; + for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) { + if(bot->clientid == botid) + break; + } + if(bot) { + struct ChanNode *chan = getChanByName(channel); + if(chan && isUserOnChan(bot->user, chan)) { + reply(client, user, "NS_INVITE_ON_CHAN", bot->user->nick, chan->name); + } else + putsock(bot, "JOIN %s", channel); + } +} + +void init_NeonBackup(int type) { + set_bot_alias(BOTID, BOTALIAS); + start_bots(type); + + if(type == MODSTATE_REBIND) return; + + //register events + bind_bot_ready(neonbackup_bot_ready, module_id); + bind_join(neonbackup_event_join, module_id); + bind_invite(neonbackup_event_invite, module_id); + + set_trigger_callback(BOTID, module_id, neonbackup_trigger_callback); + + register_default_language_table(msgtab); +} + +void loop_NeonBackup() { + +} + +void free_NeonBackup(int type) { + unbind_allcmd(BOTID); + if(type == MODSTATE_STARTSTOP) { + //disconnect all our bots + struct ClientSocket *client; + for(client = getBots(0, NULL); client; client = getBots(0, client)) { + if(client->botid == BOTID) { + unbind_botwise_allcmd(0, client->clientid); + close_socket(client); + break; + } + } + } +} + +#undef BOTID +#undef BOTALIAS diff --git a/src/modules/NeonBackup.mod/bot_NeonBackup.h b/src/modules/NeonBackup.mod/bot_NeonBackup.h new file mode 100644 index 0000000..a805c3c --- /dev/null +++ b/src/modules/NeonBackup.mod/bot_NeonBackup.h @@ -0,0 +1,26 @@ +/* bot_NeonBackup.h - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ +#ifndef _bot_NeonBackup_h +#define _bot_NeonBackup_h + +#include "../../main.h" + +void init_NeonBackup(int type); +void loop_NeonBackup(); +void free_NeonBackup(int type); + +#endif \ No newline at end of file diff --git a/src/modules/NeonBackup.mod/cmd_neonbackup.c b/src/modules/NeonBackup.mod/cmd_neonbackup.c new file mode 100644 index 0000000..3c3eaf0 --- /dev/null +++ b/src/modules/NeonBackup.mod/cmd_neonbackup.c @@ -0,0 +1,28 @@ +/* cmd_neonbackup.c - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ +#include "../module.h" +#include "cmd_neonbackup.h" +#include "../../modcmd.h" +#include "../../ConfigParser.h" + +void register_commands() { + //NeonBackup Commands + register_command_alias(6, "NeonBackup"); + + + +} \ No newline at end of file diff --git a/src/modules/NeonBackup.mod/cmd_neonbackup.h b/src/modules/NeonBackup.mod/cmd_neonbackup.h new file mode 100644 index 0000000..f4f36a2 --- /dev/null +++ b/src/modules/NeonBackup.mod/cmd_neonbackup.h @@ -0,0 +1,36 @@ +/* cmd_neonbackup.h - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ +#ifndef _cmd_neonbackup_h +#define _cmd_neonbackup_h +#include "../module.h" +#include "../../main.h" +#include "../../modcmd.h" +#include "../../mysqlConn.h" +#include "../../ClientSocket.h" +#include "../../UserNode.h" +#include "../../ChanNode.h" +#include "../../ChanUser.h" +#include "../../DBHelper.h" +#include "../../IRCParser.h" +#include "bot_NeonBackup.h" +#include "../../lang.h" +#include "../../tools.h" + +void register_commands(); + + +#endif diff --git a/src/modules/NeonBackup.mod/module.c b/src/modules/NeonBackup.mod/module.c new file mode 100644 index 0000000..4fb205e --- /dev/null +++ b/src/modules/NeonBackup.mod/module.c @@ -0,0 +1,38 @@ +/* module.c - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ +#include "../module.h" +#include "bot_NeonBackup.h" +#include "cmd_neonbackup.h" + +static int module_initialize() { + register_commands(); + return 0; +} + +static void module_start(int type) { + init_NeonBackup(type); +} + +static void module_loop() { + loop_NeonBackup(); +} + +static void module_stop(int type) { + free_NeonBackup(type); +} + +MODULE_HEADER(module_initialize, module_start, module_loop, module_stop); diff --git a/src/modules/NeonFun.mod/bot_NeonFun.c b/src/modules/NeonFun.mod/bot_NeonFun.c index e5706ae..49364a2 100644 --- a/src/modules/NeonFun.mod/bot_NeonFun.c +++ b/src/modules/NeonFun.mod/bot_NeonFun.c @@ -99,6 +99,7 @@ static void start_bots(int type) { client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0); client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0); client->flags |= SOCKET_FLAG_SILENT; + client->flags |= SOCKET_FLAG_REQUEST_INVITE; client->botid = BOTID; client->clientid = atoi(row[7]); connect_socket(client); @@ -141,6 +142,36 @@ static int neonfun_freechan(struct ChanNode *chan) { return 0; } +static void neonfun_event_invite(struct ClientSocket *client, struct UserNode *user, char *channel) { + if(client->botid != BOTID) + return; + MYSQL_RES *res; + MYSQL_ROW row; + printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` LEFT JOIN `channels` ON `chanid` = `channel_id` WHERE `channel_name` = '%s' AND `botclass` = '%d'", escape_string(channel), client->botid); + res = mysql_use(); + if ((row = mysql_fetch_row(res)) == NULL) { + reply(client, user, "NS_INVITE_FAIL", channel, client->user->nick); + return; + } + if(!strcmp(row[2], "1")) { + reply(client, user, "MODCMD_CHAN_SUSPENDED"); + return; + } + int botid = atoi(row[0]); + struct ClientSocket *bot; + for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) { + if(bot->clientid == botid) + break; + } + if(bot) { + struct ChanNode *chan = getChanByName(channel); + if(chan && isUserOnChan(bot->user, chan)) { + reply(client, user, "NS_INVITE_ON_CHAN", bot->user->nick, chan->name); + } else + putsock(bot, "JOIN %s", channel); + } +} + void init_NeonFun(int type) { set_bot_alias(BOTID, BOTALIAS); start_bots(type); @@ -152,7 +183,8 @@ void init_NeonFun(int type) { bind_part(neonfun_parted, module_id); bind_quit(neonfun_quitted, module_id); bind_freechan(neonfun_freechan, module_id); - + bind_invite(neonfun_event_invite, module_id); + set_trigger_callback(BOTID, module_id, neonfun_trigger_callback); } diff --git a/src/modules/NeonHelp.mod/bot_NeonHelp.c b/src/modules/NeonHelp.mod/bot_NeonHelp.c index 614d0df..68cf662 100644 --- a/src/modules/NeonHelp.mod/bot_NeonHelp.c +++ b/src/modules/NeonHelp.mod/bot_NeonHelp.c @@ -125,6 +125,7 @@ static void start_bots(int type) { client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0); client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0); client->flags |= SOCKET_FLAG_SILENT; + client->flags |= SOCKET_FLAG_REQUEST_INVITE; client->botid = BOTID; client->clientid = atoi(row[7]); connect_socket(client); @@ -515,6 +516,36 @@ static void neonhelp_event_quit(struct UserNode *target, char *reason) { } } +static void neonhelp_event_invite(struct ClientSocket *client, struct UserNode *user, char *channel) { + if(client->botid != BOTID) + return; + MYSQL_RES *res; + MYSQL_ROW row; + printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` LEFT JOIN `channels` ON `chanid` = `channel_id` WHERE `channel_name` = '%s' AND `botclass` = '%d'", escape_string(channel), client->botid); + res = mysql_use(); + if ((row = mysql_fetch_row(res)) == NULL) { + reply(client, user, "NS_INVITE_FAIL", channel, client->user->nick); + return; + } + if(!strcmp(row[2], "1")) { + reply(client, user, "MODCMD_CHAN_SUSPENDED"); + return; + } + int botid = atoi(row[0]); + struct ClientSocket *bot; + for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) { + if(bot->clientid == botid) + break; + } + if(bot) { + struct ChanNode *chan = getChanByName(channel); + if(chan && isUserOnChan(bot->user, chan)) { + reply(client, user, "NS_INVITE_ON_CHAN", bot->user->nick, chan->name); + } else + putsock(bot, "JOIN %s", channel); + } +} + void init_NeonHelp(int type) { set_bot_alias(BOTID, BOTALIAS); start_bots(type); @@ -528,6 +559,7 @@ void init_NeonHelp(int type) { bind_part(neonhelp_event_part, module_id); bind_kick(neonhelp_event_kick, module_id); bind_quit(neonhelp_event_quit, module_id); + bind_invite(neonhelp_event_invite, module_id); set_trigger_callback(BOTID, module_id, neonhelp_trigger_callback); diff --git a/src/modules/NeonServ.mod/bot_NeonServ.c b/src/modules/NeonServ.mod/bot_NeonServ.c index 83f329b..16d6dbd 100644 --- a/src/modules/NeonServ.mod/bot_NeonServ.c +++ b/src/modules/NeonServ.mod/bot_NeonServ.c @@ -471,6 +471,7 @@ static void start_bots(int type) { client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0); client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0); client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0); + client->flags |= SOCKET_FLAG_REQUEST_INVITE; client->botid = BOTID; client->clientid = atoi(row[7]); connect_socket(client); diff --git a/src/modules/NeonServ.mod/cmd_neonserv.h b/src/modules/NeonServ.mod/cmd_neonserv.h index 49afad5..d5f0b5f 100644 --- a/src/modules/NeonServ.mod/cmd_neonserv.h +++ b/src/modules/NeonServ.mod/cmd_neonserv.h @@ -17,6 +17,7 @@ #ifndef _cmd_neonserv_h #define _cmd_neonserv_h #include "../module.h" +#include "../botid.h" #include "../../main.h" #include "../../modcmd.h" #include "../../IRCParser.h" diff --git a/src/modules/NeonServ.mod/cmd_neonserv_csuspend.c b/src/modules/NeonServ.mod/cmd_neonserv_csuspend.c index c264b64..1dad37d 100644 --- a/src/modules/NeonServ.mod/cmd_neonserv_csuspend.c +++ b/src/modules/NeonServ.mod/cmd_neonserv_csuspend.c @@ -56,6 +56,12 @@ CMD_BIND(neonserv_cmd_csuspend) { if(bot) { putsock(bot, "PART %s :Channel suspended.", channel); } + if(client->botid == NEONSERV_BOTID) { + char setting[128]; + sprintf(setting, "modules.%s.auto_backup_unregister", get_module_name(module_id)); + if(get_int_field(setting)) + module_global_cmd_unregister_neonbackup(channel); + } printf_mysql_query("UPDATE `bot_channels` SET `suspended` = '1' WHERE `id` = '%s'", row[1]); reply(getTextBot(), user, "NS_CSUSPEND_DONE", channel); logEvent(event); diff --git a/src/modules/NeonServ.mod/cmd_neonserv_cunsuspend.c b/src/modules/NeonServ.mod/cmd_neonserv_cunsuspend.c index eccc76a..b9c6a36 100644 --- a/src/modules/NeonServ.mod/cmd_neonserv_cunsuspend.c +++ b/src/modules/NeonServ.mod/cmd_neonserv_cunsuspend.c @@ -56,6 +56,12 @@ CMD_BIND(neonserv_cmd_cunsuspend) { if(bot) { putsock(bot, "JOIN %s", channel); } + if(client->botid == NEONSERV_BOTID) { + char setting[128]; + sprintf(setting, "modules.%s.auto_backup_register", get_module_name(module_id)); + if(get_int_field(setting)) + module_global_cmd_register_neonbackup(channel); + } printf_mysql_query("UPDATE `bot_channels` SET `suspended` = '0' WHERE `id` = '%s'", row[1]); reply(getTextBot(), user, "NS_CUNSUSPEND_DONE", channel); logEvent(event); diff --git a/src/modules/NeonServ.mod/cmd_neonserv_set.c b/src/modules/NeonServ.mod/cmd_neonserv_set.c index 2ebb968..2243c0d 100644 --- a/src/modules/NeonServ.mod/cmd_neonserv_set.c +++ b/src/modules/NeonServ.mod/cmd_neonserv_set.c @@ -23,6 +23,7 @@ static char* neonserv_cmd_set_trigger(struct ClientSocket *client, struct UserNo static char* neonserv_cmd_set_modes(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument); static char* neonserv_cmd_set_dynlimit(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument); static char* neonserv_cmd_set_nodelete(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument); +static char* neonserv_cmd_set_backupbot(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument); #define NS_VALID_FUNCTION 0x01 #define NS_VALID_STRING 0x02 @@ -80,6 +81,7 @@ static const struct { {"TOYS", "channel_toys", NS_VALID_OPTIONS | NS_HAS_OPT, "3"}, {"DYNLIMIT", "channel_dynlimit", NS_VALID_NUMERIC | NS_VALID_FUNCTION | NS_HAS_OPT, neonserv_cmd_set_dynlimit}, {"NODELETE", "channel_nodelete", NS_VALID_BOOLEAN | NS_VALID_FUNCTION, neonserv_cmd_set_nodelete}, + {"BACKUPBOT", NULL, NS_VALID_BOOLEAN | NS_VALID_FUNCTION, neonserv_cmd_set_backupbot}, {NULL, NULL, 0, NULL} }; @@ -132,6 +134,14 @@ CMD_BIND(neonserv_cmd_set) { while(channel_settings[i].setting) { if(!stricmp(channel_settings[i].setting, argv[0]) && (!(channel_settings[i].valid & NS_VALID_IF_HALFOP) || with_halfops)) { //setting found + if(!stricmp(channel_settings[i].setting, "BACKUPBOT")) { + char setting[128]; + sprintf(setting, "modules.%s.channel_backup_setting", get_module_name(module_id)); + if(!get_int_field(setting)) { + i++; + continue; + } + } if(channel_settings[i].valid & NS_VALID_FUNCTION) { neonserv_cmd_set_function *func = channel_settings[i].parameter; func(client, user, chan, event, channel_settings[i].setting, args); @@ -155,6 +165,7 @@ CMD_BIND(neonserv_cmd_set) { struct Table *table; char *content[2]; int with_halfops = get_int_field("General.have_halfop"); + int channel_backup_setting; i = 0; j = 0; while(channel_settings[i].setting) { @@ -163,6 +174,16 @@ CMD_BIND(neonserv_cmd_set) { i++; continue; } + if(!stricmp(channel_settings[i].setting, "BACKUPBOT")) { + char setting[128]; + sprintf(setting, "modules.%s.channel_backup_setting", get_module_name(module_id)); + channel_backup_setting = get_int_field(setting); + if(!channel_backup_setting) { + i++; + j++; + continue; + } + } if(channel_settings[i].chanfield) querypos += sprintf(query + querypos, ", `%s`", channel_settings[i].chanfield); i++; @@ -183,6 +204,10 @@ CMD_BIND(neonserv_cmd_set) { i++; continue; } + if(!stricmp(channel_settings[i].setting, "BACKUPBOT") && !channel_backup_setting) { + i++; + continue; + } if(channel_settings[i].chanfield) { j++; org_value = (row[j] ? row[j] : defaults[j]); @@ -468,4 +493,38 @@ static char* neonserv_cmd_set_nodelete(struct ClientSocket *client, struct UserN return value; } +static char* neonserv_cmd_set_backupbot(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) { + int backupbot; + //get current trigger + MYSQL_RES *res; + printf_mysql_query("SELECT `botid` FROM `bot_channels` LEFT JOIN `bots` ON `botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chan->channel_id, NEONBACKUP_BOTID); + res = mysql_use(); + if(mysql_fetch_row(res)) + backupbot = 1; + else + backupbot = 0; + if(argument) { + //change the channel setting + if(!strcmp(argument, "0") || !strcmp(argument, "off") || !strcmp(argument, get_language_string(user, "NS_SET_OFF"))) { + if(backupbot) { + module_global_cmd_unregister_neonbackup(chan->name); + backupbot = 0; + } + } else if(!strcmp(argument, "1") || !strcmp(argument, "on") || !strcmp(argument, get_language_string(user, "NS_SET_ON"))) { + if(!backupbot) { + module_global_cmd_register_neonbackup(chan->name); + backupbot = 1; + } + } else { + reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argument); + return NULL; + } + logEvent(event); + } + if(setting) { + reply(getTextBot(), user, "\002%s\002 %s", setting, (backupbot ? "1" : "0")); + } + return (backupbot ? "1" : "0"); +} + #undef MAX_QUERY_LEN diff --git a/src/modules/NeonServ.mod/cmd_neonserv_unvisited.c b/src/modules/NeonServ.mod/cmd_neonserv_unvisited.c index 455583c..62f86c0 100644 --- a/src/modules/NeonServ.mod/cmd_neonserv_unvisited.c +++ b/src/modules/NeonServ.mod/cmd_neonserv_unvisited.c @@ -49,14 +49,14 @@ void neonserv_cmd_unvisited_init() { static TIMEQ_CALLBACK(neonserv_check_unvisited_timer) { char tmp[200]; char *modname = get_module_name(module_id); - sprintf(tmp, "modules/%s/chan_expire_freq", modname); + sprintf(tmp, "modules.%s.chan_expire_freq", modname); char *check_freq_str = get_string_field(tmp); int check_freq; if(!check_freq_str || (check_freq = strToTime(NULL, check_freq_str)) < (60*60)) { timeq_add_name("neonserv_unvisited", 1800, module_id, neonserv_check_unvisited_timer, NULL); return; } - sprintf(tmp, "modules/%s/chan_expire_delay", modname); + sprintf(tmp, "modules.%s.chan_expire_delay", modname); char *check_expire_str = get_string_field(tmp); int duration; if(!check_expire_str || (duration = strToTime(NULL, check_expire_str)) < 60*60*24*7) return; @@ -156,7 +156,7 @@ static void neonserv_cmd_unvisited_async2(struct neonserv_cmd_unvisited_cache *c static void neonserv_cmd_unvisited_unreg(struct ClientSocket *client, char *channel) { MYSQL_RES *res; MYSQL_ROW row; - int sync_neonspam_unreg = get_int_field("General/sync_neonspam_unreg"); + int sync_neonspam_unreg = get_int_field("General.sync_neonspam_unreg"); int botid; if(client) botid = client->botid; @@ -195,6 +195,12 @@ static void neonserv_cmd_unvisited_unreg(struct ClientSocket *client, char *chan putsock(bot, "PART %s :Channel unregistered.", channel); } } + if(client->botid == NEONSERV_BOTID) { + char setting[128]; + sprintf(setting, "modules.%s.auto_backup_unregister", get_module_name(module_id)); + if(get_int_field(setting)) + module_global_cmd_unregister_neonbackup(channel); + } char *alertchan = get_string_field("General.alertchan"); if(alertchan) { struct ChanNode *alertchan_chan = getChanByName(alertchan); diff --git a/src/modules/NeonServ.mod/event_neonserv_invite.c b/src/modules/NeonServ.mod/event_neonserv_invite.c index 4092208..3dc36fb 100644 --- a/src/modules/NeonServ.mod/event_neonserv_invite.c +++ b/src/modules/NeonServ.mod/event_neonserv_invite.c @@ -16,6 +16,8 @@ */ static void neonserv_event_invite(struct ClientSocket *client, struct UserNode *user, char *channel) { + if(client->botid != BOTID) + return; MYSQL_RES *res; MYSQL_ROW row; printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` LEFT JOIN `channels` ON `chanid` = `channel_id` WHERE `channel_name` = '%s' AND `botclass` = '%d'", escape_string(channel), client->botid); diff --git a/src/modules/NeonServ.mod/event_neonserv_join.c b/src/modules/NeonServ.mod/event_neonserv_join.c index e2c54a5..5f8d144 100644 --- a/src/modules/NeonServ.mod/event_neonserv_join.c +++ b/src/modules/NeonServ.mod/event_neonserv_join.c @@ -31,6 +31,7 @@ static void neonserv_event_join(struct ChanUser *chanuser) { if(!client) return; //we can't "see" this event if(chanuser->user == client->user) { requestOp(client->user, chanuser->chan); + module_neonbackup_recover_chan(chanuser->chan); return; } if(chanuser->user->flags & USERFLAG_ISBOT) return; diff --git a/src/modules/NeonSpam.mod/bot_NeonSpam.c b/src/modules/NeonSpam.mod/bot_NeonSpam.c index b4db724..de645c2 100644 --- a/src/modules/NeonSpam.mod/bot_NeonSpam.c +++ b/src/modules/NeonSpam.mod/bot_NeonSpam.c @@ -183,6 +183,7 @@ static void start_bots(int type) { client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0); client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0); client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0); + client->flags |= SOCKET_FLAG_REQUEST_INVITE; client->botid = BOTID; client->clientid = atoi(row[7]); connect_socket(client); @@ -373,6 +374,36 @@ static int neonspam_event_freechan(struct ChanNode *chan) { return 1; } +static void neonspam_event_invite(struct ClientSocket *client, struct UserNode *user, char *channel) { + if(client->botid != BOTID) + return; + MYSQL_RES *res; + MYSQL_ROW row; + printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` LEFT JOIN `channels` ON `chanid` = `channel_id` WHERE `channel_name` = '%s' AND `botclass` = '%d'", escape_string(channel), client->botid); + res = mysql_use(); + if ((row = mysql_fetch_row(res)) == NULL) { + reply(client, user, "NS_INVITE_FAIL", channel, client->user->nick); + return; + } + if(!strcmp(row[2], "1")) { + reply(client, user, "MODCMD_CHAN_SUSPENDED"); + return; + } + int botid = atoi(row[0]); + struct ClientSocket *bot; + for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) { + if(bot->clientid == botid) + break; + } + if(bot) { + struct ChanNode *chan = getChanByName(channel); + if(chan && isUserOnChan(bot->user, chan)) { + reply(client, user, "NS_INVITE_ON_CHAN", bot->user->nick, chan->name); + } else + putsock(bot, "JOIN %s", channel); + } +} + void init_NeonSpam(int type) { set_bot_alias(BOTID, BOTALIAS); @@ -387,7 +418,8 @@ void init_NeonSpam(int type) { bind_privctcp(general_event_privctcp, module_id); bind_kick(neonspam_event_kick, module_id); bind_freechan(neonspam_event_freechan, module_id); - + bind_invite(neonspam_event_invite, module_id); + set_trigger_callback(BOTID, module_id, neonspam_trigger_callback); register_default_language_table(msgtab); diff --git a/src/modules/botid.h b/src/modules/botid.h index b0209fa..34c6b81 100644 --- a/src/modules/botid.h +++ b/src/modules/botid.h @@ -22,5 +22,6 @@ #define DUMMYSERV_BOTID 3 #define NEONHELP_BOTID 4 #define NEONFUN_BOTID 5 +#define NEONBACKUP_BOTID 6 #endif \ No newline at end of file diff --git a/src/modules/global.mod/cmd_global.h b/src/modules/global.mod/cmd_global.h index b1f80be..d44a18f 100644 --- a/src/modules/global.mod/cmd_global.h +++ b/src/modules/global.mod/cmd_global.h @@ -17,6 +17,7 @@ #ifndef _cmd_global_h #define _cmd_global_h #include "../module.h" +#include "../botid.h" #include "../../main.h" #include "../../modcmd.h" #include "../../IRCParser.h" @@ -71,4 +72,5 @@ CMD_BIND(global_cmd_unbind); CMD_BIND(global_cmd_unregister); CMD_BIND(global_cmd_version); + #endif \ No newline at end of file diff --git a/src/modules/global.mod/cmd_global_register.c b/src/modules/global.mod/cmd_global_register.c index 1f4690a..81e0180 100644 --- a/src/modules/global.mod/cmd_global_register.c +++ b/src/modules/global.mod/cmd_global_register.c @@ -114,7 +114,7 @@ CMD_BIND(global_cmd_register) { struct UserNode *cuser = getUserByNick(argv[1]); if(!cuser) { cuser = createTempUser(argv[1]); - if(!cuser) { + if(!cuser) { reply(getTextBot(), user, "NS_USER_UNKNOWN", argv[1]); return; } @@ -262,5 +262,52 @@ static void global_cmd_register_async1(struct ClientSocket *client, struct Clien reply(textclient, user, "NS_REGISTER_DONE", channel, auth); } else reply(textclient, user, "NS_REGISTER_DONE_NOAUTH", channel); + // NeonBackup SubBlock + if(client->botid == NEONSERV_BOTID) { + char setting[128]; + sprintf(setting, "modules.%s.auto_backup_register", get_module_name(module_id)); + if(get_int_field(setting)) + module_global_cmd_register_neonbackup(channel); + } logEvent(event); } + +void global_cmd_register_neonbackup(char *channel) { + MYSQL_RES *res; + MYSQL_ROW row, row2; + printf_mysql_query("SELECT `botid` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` LEFT JOIN `channels` ON `bot_channels`.`chanid` = `channels`.`channel_id` WHERE `channel_name` = '%s' AND botclass = '%d'", escape_string(channel), NEONBACKUP_BOTID); + res = mysql_use(); + if ((row = mysql_fetch_row(res)) != NULL) + return; + int chanid; + printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(channel)); + res = mysql_use(); + if ((row = mysql_fetch_row(res)) != NULL) { + chanid = atoi(row[0]); + } else + return; + printf_mysql_query("SELECT `id`, `max_channels`, `defaulttrigger`, `nick` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1' ORDER BY `register_priority` DESC", NEONBACKUP_BOTID); + res = mysql_use(); + int botid = 0; + while ((row = mysql_fetch_row(res)) != NULL) { + //check channel count + printf_mysql_query("SELECT COUNT(*) FROM `bot_channels` WHERE `botid` = '%s'", row[0]); + row2 = mysql_fetch_row(mysql_use()); + if(atoi(row2[0]) < atoi(row[1])) { + botid = atoi(row[0]); + break; + } + } + if(!botid) + return; + struct ClientSocket *bot; + for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) { + if(bot->clientid == botid) + break; + } + if(bot) { + putsock(bot, "JOIN %s", channel); + } + printf_mysql_query("INSERT INTO `bot_channels` (`botid`, `chanid`, `trigger`) VALUES ('%d', '%d', NULL)", botid, chanid); +} + diff --git a/src/modules/global.mod/cmd_global_unregister.c b/src/modules/global.mod/cmd_global_unregister.c index 97ef4f9..daa1737 100644 --- a/src/modules/global.mod/cmd_global_unregister.c +++ b/src/modules/global.mod/cmd_global_unregister.c @@ -46,7 +46,7 @@ CMD_BIND(global_cmd_unregister) { reply(getTextBot(), user, "NS_UNREGISTER_NODELETE", channel); return; } - int sync_neonspam_unreg = get_int_field("General/sync_neonspam_unreg"); + int sync_neonspam_unreg = get_int_field("General.sync_neonspam_unreg"); if(client->botid == 0) printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '0' AND `botid` = '%d'", chanid, client->clientid); else @@ -83,5 +83,38 @@ CMD_BIND(global_cmd_unregister) { putsock(bot, "PART %s :Channel unregistered.", channel); } } + // NeonBackup SubBlock + if(client->botid == NEONSERV_BOTID) { + char setting[128]; + sprintf(setting, "modules.%s.auto_backup_unregister", get_module_name(module_id)); + if(get_int_field(setting)) + module_global_cmd_unregister_neonbackup(channel); + } logEvent(event); } + +void global_cmd_unregister_neonbackup(char *channel) { + MYSQL_RES *res; + MYSQL_ROW row; + int chanid; + printf_mysql_query("SELECT `channel_id` FROM `channels` WHERE `channel_name` = '%s'", escape_string(channel)); + res = mysql_use(); + if ((row = mysql_fetch_row(res)) != NULL) { + chanid = atoi(row[0]); + } else + return; + printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chanid, NEONBACKUP_BOTID); + res = mysql_use(); + if ((row = mysql_fetch_row(res)) == NULL) + return; + int botid = atoi(row[0]); + struct ClientSocket *bot; + for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) { + if(bot->clientid == botid) + break; + } + printf_mysql_query("DELETE FROM `bot_channels` WHERE `id` = '%s'", row[1]); + if(bot && strcmp(row[2], "1")) { + putsock(bot, "PART %s :Channel unregistered.", channel); + } +} diff --git a/src/modules/module.h b/src/modules/module.h index b780ac1..2efec39 100644 --- a/src/modules/module.h +++ b/src/modules/module.h @@ -220,6 +220,10 @@ extern int module_id; /* 188 */ #define get_patchlevel ((const int (*)(void))global[188]) /* 189 */ #define get_module_name ((char * (*)(int))global[189]) /* 190 */ #define isUserModeSet ((int (*)(struct UserNode *, char))global[190]) +/* 191 */ #define module_global_cmd_register_neonbackup ((void (*)(char *))global[191]) +/* 192 */ #define module_global_cmd_unregister_neonbackup ((void (*)(char *))global[192]) +/* 193 */ #define module_neonbackup_recover_chan ((void (*)(struct ChanNode *))global[193]) +/* 194 */ #define requestInvite ((void (*)(struct UserNode *, struct ChanNode *))global[194]) #define MODULE_HEADER(initfunc,startfunc,loopfunc,stopfunc) \ void **global = NULL; \ diff --git a/src/version.h b/src/version.h index 063c73d..e4dc9ea 100644 --- a/src/version.h +++ b/src/version.h @@ -19,7 +19,7 @@ #include "main.h" -#define MODULE_VERSION 3 +#define MODULE_VERSION 4 #ifndef DND_FUNCTIONS extern const char *compilation;