#include "module.h" #define AUTHOR "DrStein" #define MYNAME "bs_zbot" #define VERSION "0.8.8" /* -------------------------------------------- * MODULE AUTHOR AND RELEASE DATE * -------------------------------------------- * Name: bs_zbot * Author: DrStein * Date: 12-20-2004 * * -------------------------------------------- * MODULE DESCRIPTION * -------------------------------------------- * This module provides a new feature to * BotServ bots which convert them into an * infobot like Zbot (http://zbot.zero.org). * * Only users who have access to SAY can use * !learn, and who have access to PROTECT can * use !forget, !rename and others destructive * commands. * Everybody can use ?, ??, !whoset, !stats, * !last, !top, !find. * * The module will store the data into MySQL * tables. * * NOTE: Please don't request new features * until the 1.0.0 version is released * * -------------------------------------------- * COMMANDS LIST * -------------------------------------------- * !learn * !forget * !whoset * !stats * !rename * !last * !replace * !lock * !unlock * !append * !ignore {add|del|list|clear} [mask] * !top [num] * !find * * ? * ?? * * /msg BotServ SET ZBOT {ON|OFF} * * For Services Admin only: * ----------------------- * /msg BotServ ZBOT LISTCHANS [pattern] * /msg BotServ ZBOT STATS * /msg BotServ ZBOT DELCHAN * * For Services Root only * ---------------------- * /msg BotServ ZBOT CLEARDB * Note: SuperAdmin required for this command * * -------------------------------------------- * MODULE SUPPORT * -------------------------------------------- * IRCd: Tested on Unreal 3.2.2, but supports * all IRCds which Anope support. * Anope version: Tested on 1.7.6 (SVN), but * should support all versions with MySQL * support. * * -------------------------------------------- * CHANGELOG * -------------------------------------------- * v0.8.8 - Added an error trap, in order to * avoid segfault when the connection * to the MySQL server fails. * * v0.8.7 - !find should reply to the user * instead of the channel. * * v0.8.6 - Fixed a typo causing Segfault :( * * v0.8.5 - Fixed an overflow exploit. UPGRADE! * * v0.8.4 - I forgot to fix something around. * * v0.8.3 - Fixed some memleaks and a nice * exploit - thanks Keeper. * * v0.8.2 - Fixed non escaped inputs. Upgrade! * * v0.8.1 - Fixed typo in USE_NICK_PRIVMSG and * USE_CHAN_PRIVMSG. * Thanks to dotslasher * * v0.8.0 - Added more administration commands. * Messages stuff cleaned up. * * v0.7.0 - Added Services Admin features like * LISTCHANS and STATS. * * v0.6.0 - Added UnrealIRCD 3.2.1 Tokens * support. * * v0.5.0 - Added a new feature: !find. * Now you can configure the MySQL * sock file. Removed a lot of #ifdef * stuff, replaced for nice functions. * All the messages are now #defined * for easiest translation. The code * style has been changed to K&R (not * pure, something like Anope style) * Sorted a level issue (thanks crazy). * * v0.4.0 - Added the new feature !ignore. * Old users must execute the next: * ALTER TABLE `channels` CHANGE `name` * `name` VARCHAR( 255 ) NOT NULL * Another new feature: !top * Optimized few things around. * * v0.3.0 - Added /bs SET ZBOT {ON|OFF} * v0.2.0 - Added the new command !append. * Fixed and depured a lot of code. * Added options for use PRIVMSG * instead of notices. MySQL error * results are noticed. * * v0.1.0 - Added new features like !lock, * !unlock, hits count, and fixed * several minor bugs. * Old users must execute the next: * ALTER TABLE `terms` CHANGE `date` * `date` DATETIME NOT NULL * for best precision in !last * * v0.0.4 - Fixed minor bug. Thanks Trystan. * * v0.0.3 - Fixed bug in !rename, !learn. * ALTER TABLE `terms` DROP INDEX `key` * is necessary for old users. * * v0.0.2 - Fixed exploit using MySQL injection * * v0.0.1 - Initial release. * * -------------------------------------------- * GRATEFULNESS * -------------------------------------------- * Thanks to: Rob, heinz, GeniusDex, crazytoon. * Special thanks to: foobar and dengel. * * -------------------------------------------- * RELEASE NOTES * -------------------------------------------- * I added an error trap, in order to avoid a * Segmentation Fault when the connection to * the MySQL server is lost. * Thanks to bitnapper for point this out. * * *** New Strings: * * *** Mod Strings: * * *** Del Strings: * * * Enjoy bs_zbot. * * -------------------------------------------- * START OF CONFIGURATION BLOCK - please read * the comments. * -------------------------------------------- */ /* MySQL database */ #define zbot_DB "module_bs_zbot" /* MySQL user */ #define zbot_USER "Zbot" /* MySQL pass */ #define zbot_PASS "mypass" /* MySQL host */ #define zbot_HOST "localhost" /* MySQL host */ #define zbot_PORT 3306 /* MySQL sock */ #define zbot_SOCK "/var/run/mysqld/mysqld.sock" /* Use MSG for private messages * (if you want it, remove the "//") */ // #define USE_NICK_PRIVMSG /* Use MSG for public messages * (if you want it, remove the "//") */ // #define USE_CHAN_PRIVMSG /* Language stuff - if edit, don't remove the %s,%d, etc. */ #define ERROR_TRY_AGAIN "An error has occured, please try again later." #define ERROR_NOT_DEFINED "%s is not defined" #define ERROR_LOCKED "%s is locked" #define ERROR_ALREADY_DEFINED "This key is already defined." #define ERROR_NO_ENTRIES "There are not entries defined" #define LEARN_SYNTAX "Syntax: !learn " #define DELETE_DONE "%s has been deleted" #define DELETE_SYNTAX "Syntax: !forget " #define WHOSET_RESULT "%s (%s) defined by %s [%s] [%s hits]" #define STATS_RESULT "%d entries, %d hits" #define RENAME_DONE "%s is now known as %s" #define RENAME_SYNTAX "Syntax: !rename " #define REPLACE_SYNTAX "Syntax: !replace " #define XLAST_ERROR_VALUE "The last value must be greater than 0" #define XLAST_RESULT "Last %d =%s" #define LOCK_ERROR_LOCKED "%s is already locked" #define LOCK_DONE "%s is now locked" #define LOCK_SYNTAX "Syntax: !lock " #define UNLOCK_ERROR_NOT_LOCKED "%s is not locked" #define UNLOCK_DONE "%s is now unlocked" #define UNLOCK_SYNTAX "Syntax: !unlock " #define APPEND_SYNTAX "Syntax: !append " #define ERROR_OVERFLOW "You can not append more text to this key." #define ASK_ERROR_NOT_DEFINED "%s == " #define IGNORE_SYNTAX "Syntax: !ignore {add|del|list|clear} [mask]" #define IGNORE_CLEAR_DONE "%d entries deleted. The ignore list is now empty" #define IGNORE_ERROR_EMPTY "The ignore list is already empty" #define IGNORE_ERROR_MASK "Mask must be in the form nick!ident@host" #define IGNORE_ERROR_TOOWIDE "%s coverage is too wide; Please use a more specific mask." #define IGNORE_DONE "The mask %s is now being ignored" #define IGNORE_DEL_ERROR "The mask %s doesn't exists in my database" #define IGNORE_DEL_DONE "The mask %s is not being ignored anymore" #define XTOP_WRONG_VALUE "The top value must be greater than 0" #define FIND_SYNTAX "Syntax: !find " #define FIND_ERROR_NOWILD "Listing * is not allowed" #define FIND_ERROR_LENGTH "At least 3 characters to search." #define ZBOT_SET_SYNTAX "Syntax:SET channel ZBOT {ON|OFF}" #define ZBOT_SET_ON "Zbot is now active on %s." #define ZBOT_SET_ALREADY_ON "Zbot is already ON" #define ZBOT_SET_ALREADY_OFF "Zbot is already OFF" #define ZBOT_SET_OFF "Zbot is now disabled for %s." #define ZBOT_LISTCHANS_SYNTAX "Syntax: ZBOT LISTCHANS [pattern]" #define ZBOT_LISTCHANS_HEAD "List of entries matching %s :" #define ZBOT_LISTCHANS_FOOT "End of list - %d/%d matches shown." #define ZBOT_STATS_SYNTAX "Syntax: ZBOT STATS" #define ZBOT_STATS_CHANNELS "There are %d channels using Zbot" #define ZBOT_STATS_KEYS "There are %d keys in my database" #define ZBOT_CLEARDB_SYNTAX "Syntax: ZBOT CLEARDB" #define ZBOT_CLEARDB_DONE "The database has been cleaned" #define ZBOT_DELCHAN_SYNTAX "Syntax: ZBOT DELCHAN " #define ZBOT_DELCHAN_DONE "The channel %s has been removed from the DB" #define ZBOT_HELP_MAIN "Syntax: ZBOT { LISTCHANS|STATS }" #define ZBOT_HELP_SET "Activate or deactivate the InfoBot feature." #define ZBOT_HELP_LISTCHANS "List all the channels wich have Zbot activated for the given delimiter." #define ZBOT_HELP_STATS "Show stats for Zbot." #define ZBOT_HELP_DELCHAN "Delete a channel from the DB, including the keys and ignores as well." #define ZBOT_HELP_CLEARDB "Clean up the whole DB. Reserved for Services Root (SuperAdmin required)." /* --------------------------------------------- * Please don't edit anything below here. * --------------------------------------------- */ /* Size for key and meaning */ #define MAX_KEY 255 #define MAX_MEANING 65536 /* MySQL handler */ MYSQL *my_mysql; MYSQL_RES *my_res; MYSQL_ROW my_row; /* Function for get the channel messages */ int msg_handler(char *source, int ac, char **av); /* Function for send the MySQL queries */ static int my_query(char *sql); /* Add the real scape strings (should I use the existant one?) */ char *my_quote(char *mystring); /* Check that the needed tables exists */ int check_mytable(); /* Check if the key is already defined */ int check_key(char *key, char *chan); /* Check if the key is locked */ int is_lock(char *key, char *chan); /* Do the hits increments */ void do_inchit(char *key, char *chan); /* Gets the command and call the specifc functions */ int do_command(User * u, ChannelInfo * ci); /* Add a new key to the database */ int do_learn(User * u, ChannelInfo * ci); /* Delete a key from the database */ int do_delete(User * u, ChannelInfo * ci); /* Rename an existant key */ int do_rename(User * u, ChannelInfo * ci); /* Get the !whoset and ?? extra information */ int do_whoset(User * u, ChannelInfo * ci); /* Get the entries and hits counts */ int do_stats(User * u, ChannelInfo * ci); /* Get the last entries added */ int do_xlast(User * u, ChannelInfo * ci); /* Replace an existant key */ int do_replace(User * u, ChannelInfo * ci); /* Lock a key */ int do_lock(User * u, ChannelInfo * ci); /* Unlock a key */ int do_unlock(User * u, ChannelInfo * ci); /* Append a new meaning to the key */ int do_append(User * u, ChannelInfo * ci); /* Set Zbot on or off */ int do_onoff(User * u); /* Check if the channel is on the channels table */ int check_on_off(char *chan); /* BotServ HELP */ void BS_zbot_help(User * u); /* Ignore routine */ int do_ignore(User * u, ChannelInfo * ci); /* Check if the user is ignored */ int check_ignored(User * u, ChannelInfo * ci); /* Get the great hits! */ int do_xtop(User * u, ChannelInfo * ci); /* Send a msg to nick */ void do_msgnick(char *whosend, char *nick, const char *fmt, ...); /* Send a msg to chan */ void do_msgchan(char *whosend, char *nick, const char *fmt, ...); /* Search for a key */ int do_find(User * u, ChannelInfo * ci); /* Services admins utils */ int do_sadminutils(User * u); /* ------------------------- * Future supported commands * ------------------------- int do_link(User * u, ChannelInfo * ci); */ /* Retrive the meaning of a key */ int do_ask(User * u, ChannelInfo * ci); /* Global var to contain the module buffer */ char *mod_current_buffer = NULL; /* Global var to contain the PRIVMSG */ char *text = NULL; int AnopeInit(void) { Command *c; Message *msg = NULL; int status = 0; int result; c = createCommand("SET", do_onoff, NULL, -1, -1, -1, -1, -1); moduleAddCommand(BOTSERV, c, MOD_HEAD); c = createCommand("ZBOT", do_sadminutils, is_services_admin, -1, -1, -1, -1, -1); moduleAddCommand(BOTSERV, c, MOD_HEAD); #ifdef IRC_UNREAL32 msg = createMessage("PRIVMSG", msg_handler); if (UseTokens) { msg = createMessage("!", msg_handler); } #else msg = createMessage("PRIVMSG", msg_handler); #endif status += moduleAddMessage(msg, MOD_HEAD); if (status == 0) { alog("[%s.so] Loaded successfully", MYNAME); } else { alog("[%s.so] FAILED to load - result %d", MYNAME, status); return MOD_STOP; } moduleSetBotHelp(BS_zbot_help); moduleAddAuthor(AUTHOR); moduleAddVersion(VERSION); my_mysql = mysql_init(NULL); if (my_mysql == NULL) { alog("[%s.so] Error - Cannot create MySQL Object. Unloading...", MYNAME); return MOD_STOP; } #if defined(zbot_HOST) && defined(zbot_USER) && defined(zbot_PASS) && defined(zbot_DB) && defined(zbot_PORT) && defined(zbot_SOCK) if ((!mysql_real_connect(my_mysql, zbot_HOST, zbot_USER, zbot_PASS, zbot_DB, zbot_PORT, zbot_SOCK, 0))) { alog("[%s.so] Error - Cannot connect to MySQL Server - %s", MYNAME, mysql_error(my_mysql)); return MOD_STOP; } if (mysql_select_db(my_mysql, zbot_DB)) { alog("[%s.so] Cant connect to MySQL: %s\n", MYNAME, mysql_error(my_mysql)); alog("[%s.so] unloading...", MYNAME); return MOD_STOP; } #else alog("[%s.so] module not properly configured", MYNAME); return MOD_STOP; #endif result = check_mytable(); if (result == -1) return MOD_STOP; return MOD_CONT; } void AnopeFini(void) { mysql_close(my_mysql); alog("[%s.so] module unloaded", MYNAME); } int msg_handler(char *source, int ac, char **av) { User *u; ChannelInfo *ci; if (ac != 2) return MOD_CONT; if (!(u = finduser(source))) return MOD_CONT; if (*av[0] == '#') { if (s_BotServ && (ci = cs_findchan(av[0]))) if (!(ci->flags & CI_VERBOTEN) && ci->c && ci->bi) if (mod_current_buffer) { text = mod_current_buffer; if (text[0] == '!') { if ((check_on_off(ci->name) == 1) && (check_ignored(u, ci) == 0)) do_command(u, ci); } else if (text[0] == '?') { if ((check_on_off(ci->name) == 1) && (check_ignored(u, ci) == 0)) do_ask(u, ci); } else return MOD_CONT; } } return MOD_CONT; } int do_command(User * u, ChannelInfo * ci) { char *cmd = NULL; char *text = NULL; if (mod_current_buffer) text = mod_current_buffer; cmd = myStrGetToken(text, ' ', 0); if (!cmd) return MOD_CONT; if ((ci->botflags & BS_FANTASY)) { if (!stricmp(cmd, "!learn")) do_learn(u, ci); else if (!stricmp(cmd, "!forget")) do_delete(u, ci); else if (!stricmp(cmd, "!whoset")) do_whoset(u, ci); else if (!stricmp(cmd, "!stats")) do_stats(u, ci); else if (!stricmp(cmd, "!rename")) do_rename(u, ci); else if (!stricmp(cmd, "!last")) do_xlast(u, ci); else if (!stricmp(cmd, "!replace")) do_replace(u, ci); else if (!stricmp(cmd, "!lock")) do_lock(u, ci); else if (!stricmp(cmd, "!unlock")) do_unlock(u, ci); else if (!stricmp(cmd, "!append")) do_append(u, ci); else if (!stricmp(cmd, "!ignore")) do_ignore(u, ci); else if (!stricmp(cmd, "!top")) do_xtop(u, ci); else if (!stricmp(cmd, "!find")) do_find(u, ci); else return MOD_CONT; } return MOD_CONT; } int do_learn(User * u, ChannelInfo * ci) { char *text = NULL; char *key = NULL; char *akey = NULL; char *meaning = NULL; char *ameaning = NULL; char *ciname = NULL; char *sql; int result; if (mod_current_buffer) text = mod_current_buffer; key = myStrGetToken(text, ' ', 1); meaning = myStrGetTokenRemainder(text, ' ', 2); sql = (char *) malloc(MAX_SQL_BUF); if ((ci->botflags & BS_FANTASY) && check_access(u, ci, CA_SAY)) { if (key && meaning) { strnrepl(key, MAX_KEY, "%", "%%"); if (check_key(key, ci->name) == 0) { strnrepl(meaning, MAX_MEANING, "%", "%%"); ameaning = meaning; akey = key; key = my_quote(key); meaning = my_quote(meaning); ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "INSERT INTO `terms` (`chan`, `key`, `meaning`, `author`, `locked`, `date`, `hits`) values ('%s', '%s', '%s', '%s', 0, NOW( ), 0);", ciname, key, meaning, u->nick); free(key); free(meaning); free(ciname); result = my_query(sql); if (!result) { do_msgnick(ci->bi->nick, u->nick, "%s == %s", akey, ameaning); } else do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } else do_msgnick(ci->bi->nick, u->nick, ERROR_ALREADY_DEFINED); } else do_msgnick(ci->bi->nick, u->nick, LEARN_SYNTAX); } free(sql); return MOD_CONT; } int do_delete(User * u, ChannelInfo * ci) { char *text = NULL; char *key = NULL; char *akey = NULL; char *ciname = NULL; char *sql; int result; if (mod_current_buffer) text = mod_current_buffer; key = myStrGetToken(text, ' ', 1); sql = (char *) malloc(MAX_SQL_BUF); if ((ci->botflags & BS_FANTASY) && check_access(u, ci, CA_PROTECTME)) { if (key) { strnrepl(key, MAX_KEY, "%", "%%"); if ((is_lock(key, ci->name)) == 1) { do_msgnick(ci->bi->nick, u->nick, ERROR_LOCKED, key); free(sql); return MOD_CONT; } if (check_key(key, ci->name) == -1) { akey = key; key = my_quote(key); ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "DELETE FROM `terms` WHERE `key` = '%s' AND `chan` = '%s';", key, ciname); free(key); free(ciname); result = my_query(sql); if (!result) do_msgnick(ci->bi->nick, u->nick, DELETE_DONE, akey); else do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } else do_msgnick(ci->bi->nick, u->nick, ERROR_NOT_DEFINED, key); } else do_msgnick(ci->bi->nick, u->nick, DELETE_SYNTAX); } free(sql); return MOD_CONT; } int do_whoset(User * u, ChannelInfo * ci) { char *text = NULL; char *key = NULL; char *akey = NULL; char *ciname = NULL; char *sql; char *mydate = NULL; char *sdate = NULL; int result; int counted = 0; if (mod_current_buffer) text = mod_current_buffer; key = myStrGetToken(text, ' ', 1); sql = (char *) malloc(MAX_SQL_BUF); if ((ci->botflags & BS_FANTASY)) { if (key) { strnrepl(key, MAX_KEY, "%", "%%"); akey = key; key = my_quote(key); ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "SELECT `id`, `author`, `date`, `hits` FROM `terms` WHERE `key` = '%s' AND `chan` = '%s';", key, ciname); free(key); free(ciname); result = my_query(sql); if (!result) { my_res = mysql_store_result(my_mysql); counted = mysql_num_rows(my_res); if (counted > 0) { my_row = mysql_fetch_row(my_res); mydate = my_row[2]; sdate = myStrGetToken(mydate, ' ', 0); do_msgchan(ci->bi->nick, ci->name, WHOSET_RESULT, akey, my_row[0], my_row[1], sdate, my_row[3]); } else { do_msgnick(ci->bi->nick, u->nick, ERROR_NOT_DEFINED, akey); } mysql_free_result(my_res); } else do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } } free(sql); return MOD_CONT; } int do_stats(User * u, ChannelInfo * ci) { char *cmd = NULL; char *text = NULL; char *ciname = NULL; char *sql; int result; int counted = 0; int hits = 0; if (mod_current_buffer) text = mod_current_buffer; cmd = myStrGetToken(text, ' ', 0); sql = (char *) malloc(MAX_SQL_BUF); if ((ci->botflags & BS_FANTASY)) { ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "SELECT `hits` FROM `terms` WHERE `chan` = '%s';", ciname); free(ciname); result = my_query(sql); if (!result) { my_res = mysql_store_result(my_mysql); counted = mysql_num_rows(my_res); while ((my_row = mysql_fetch_row(my_res))) { hits = hits + atoi(my_row[0]); } do_msgchan(ci->bi->nick, ci->name, STATS_RESULT, counted, hits); mysql_free_result(my_res); } else do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } free(sql); return MOD_CONT; } int do_rename(User * u, ChannelInfo * ci) { char *text = NULL; char *cmd = NULL; char *oldkey = NULL; char *aoldkey = NULL; char *newkey = NULL; char *anewkey = NULL; char *ciname = NULL; char *sql; int result; if (mod_current_buffer) text = mod_current_buffer; cmd = myStrGetToken(text, ' ', 0); oldkey = myStrGetToken(text, ' ', 1); newkey = myStrGetToken(text, ' ', 2); sql = (char *) malloc(MAX_SQL_BUF); if ((ci->botflags & BS_FANTASY) && check_access(u, ci, CA_PROTECTME)) { if (oldkey && newkey) { strnrepl(oldkey, MAX_KEY, "%", "%%"); if (is_lock(oldkey, ci->name) == 1) { do_msgnick(ci->bi->nick, u->nick, ERROR_LOCKED, oldkey); free(sql); return MOD_CONT; } if (check_key(oldkey, ci->name) == -1) { strnrepl(newkey, MAX_KEY, "%", "%%"); if (check_key(newkey, ci->name) == 0) { aoldkey = oldkey; oldkey = my_quote(oldkey); anewkey = newkey; newkey = my_quote(newkey); ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "UPDATE `terms` SET `key` = '%s' WHERE `chan` = '%s' AND `key` = '%s';", newkey, ciname, oldkey); free(oldkey); free(newkey); free(ciname); result = my_query(sql); if (!result) do_msgchan(ci->bi->nick, ci->name, RENAME_DONE, aoldkey, anewkey); else do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } else do_msgnick(ci->bi->nick, u->nick, ERROR_ALREADY_DEFINED, newkey); } else do_msgnick(ci->bi->nick, u->nick, ERROR_NOT_DEFINED, oldkey); } else { do_msgnick(ci->bi->nick, u->nick, RENAME_SYNTAX); free(sql); return MOD_CONT; } } free(sql); return MOD_CONT; } int do_replace(User * u, ChannelInfo * ci) { char *text = NULL; char *cmd = NULL; char *key = NULL; char *akey = NULL; char *meaning = NULL; char *ameaning = NULL; char *ciname = NULL; char *sql; int result; if (mod_current_buffer) text = mod_current_buffer; cmd = myStrGetToken(text, ' ', 0); key = myStrGetToken(text, ' ', 1); meaning = myStrGetTokenRemainder(text, ' ', 2); sql = (char *) malloc(MAX_SQL_BUF); if ((ci->botflags & BS_FANTASY) && check_access(u, ci, CA_PROTECTME)) { if (key && meaning) { strnrepl(key, MAX_KEY, "%", "%%"); if (is_lock(key, ci->name) == 1) { do_msgnick(ci->bi->nick, u->nick, ERROR_LOCKED, key); free(sql); return MOD_CONT; } strnrepl(meaning, MAX_MEANING, "%", "%%"); if (check_key(key, ci->name) == -1) { ameaning = meaning; meaning = my_quote(meaning); akey = key; key = my_quote(key); ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "UPDATE `terms` SET `meaning` = '%s' WHERE `chan` = '%s' AND `key` = '%s';", meaning, ciname, key); free(meaning); free(key); free(ciname); result = my_query(sql); if (!result) do_msgchan(ci->bi->nick, ci->name, "%s == %s", akey, ameaning); else do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } else do_msgnick(ci->bi->nick, u->nick, ERROR_NOT_DEFINED, key); } else { do_msgnick(ci->bi->nick, u->nick, REPLACE_SYNTAX); free(sql); return MOD_CONT; } } free(sql); return MOD_CONT; } int do_xlast(User * u, ChannelInfo * ci) { char *text = NULL; char *sql; char *last = NULL; char *slimit = NULL; char *space = " "; char *ciname = NULL; int counted = 0; int result, limit; int malloc_size = (255 * 25); if (mod_current_buffer) text = mod_current_buffer; slimit = myStrGetToken(text, ' ', 1); if (!slimit) limit = 25; else limit = atoi(slimit); if (limit < 1) { do_msgnick(ci->bi->nick, u->nick, XLAST_ERROR_VALUE); return MOD_CONT; } sql = (char *) malloc(MAX_SQL_BUF); last = (char *) malloc(malloc_size); if ((ci->botflags & BS_FANTASY)) { ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "SELECT `key` FROM `terms` WHERE `chan` = '%s' ORDER BY `date` DESC LIMIT %d", ciname, limit); free(ciname); result = mysql_query(my_mysql, sql); if (!result) { my_res = mysql_store_result(my_mysql); counted = mysql_num_rows(my_res); if (counted > 0) { snprintf(last, malloc_size, "= "); while ((my_row = mysql_fetch_row(my_res))) { strncat(last, my_row[0], malloc_size); strncat(last, space, malloc_size); } do_msgchan(ci->bi->nick, ci->name, XLAST_RESULT, limit, last); } else { do_msgnick(ci->bi->nick, u->nick, ERROR_NO_ENTRIES); } mysql_free_result(my_res); } else do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } free(last); free(sql); return MOD_CONT; } int do_lock(User * u, ChannelInfo * ci) { char *text = NULL; char *key = NULL; char *akey = NULL; char *ciname = NULL; char *sql; int result; if (mod_current_buffer) text = mod_current_buffer; key = myStrGetToken(text, ' ', 1); sql = (char *) malloc(MAX_SQL_BUF); if ((ci->botflags & BS_FANTASY) && check_access(u, ci, CA_PROTECTME)) { if (key) { strnrepl(key, MAX_KEY, "%", "%%"); if (is_lock(key, ci->name) == 1) { do_msgnick(ci->bi->nick, u->nick, LOCK_ERROR_LOCKED, key); free(sql); return MOD_CONT; } if (check_key(key, ci->name) == -1) { akey = key; key = my_quote(key); ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "UPDATE `terms` SET `locked` = 1 WHERE `chan` = '%s' AND `key` = '%s';", ciname, key); free(key); free(ciname); result = my_query(sql); if (!result) do_msgnick(ci->bi->nick, u->nick, LOCK_DONE, akey); else do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } else do_msgnick(ci->bi->nick, u->nick, ERROR_NOT_DEFINED, akey); } else { do_msgnick(ci->bi->nick, u->nick, LOCK_SYNTAX); free(sql); return MOD_CONT; } } free(sql); return MOD_CONT; } int do_unlock(User * u, ChannelInfo * ci) { char *text = NULL; char *key = NULL; char *akey = NULL; char *ciname = NULL; char *sql; int result; if (mod_current_buffer) text = mod_current_buffer; key = myStrGetToken(text, ' ', 1); sql = (char *) malloc(MAX_SQL_BUF); if ((ci->botflags & BS_FANTASY) && check_access(u, ci, CA_PROTECTME)) { if (key) { strnrepl(key, MAX_KEY, "%", "%%"); if (is_lock(key, ci->name) == 0) { do_msgnick(ci->bi->nick, u->nick, UNLOCK_ERROR_NOT_LOCKED, key); free(sql); return MOD_CONT; } if (check_key(key, ci->name) == -1) { akey = key; key = my_quote(key); ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "UPDATE `terms` SET `locked` = 0 WHERE `chan` = '%s' AND `key` = '%s';", ciname, key); free(key); free(ciname); result = my_query(sql); if (!result) do_msgnick(ci->bi->nick, u->nick, UNLOCK_DONE, akey); else do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } else do_msgnick(ci->bi->nick, u->nick, ERROR_NOT_DEFINED, akey); } else { do_msgnick(ci->bi->nick, u->nick, UNLOCK_SYNTAX); free(sql); return MOD_CONT; } } free(sql); return MOD_CONT; } int do_append(User * u, ChannelInfo * ci) { char *text = NULL; char *cmd = NULL; char *key = NULL; char *akey = NULL; char *meaning = NULL; char *ameaning = NULL; char *oldmeaning = NULL; char *newmeaning; char *ciname = NULL; char *space = " "; char *sql; int result; int max_size = 250; if (mod_current_buffer) text = mod_current_buffer; cmd = myStrGetToken(text, ' ', 0); key = myStrGetToken(text, ' ', 1); meaning = myStrGetTokenRemainder(text, ' ', 2); sql = (char *) malloc(MAX_SQL_BUF); if ((ci->botflags & BS_FANTASY) && check_access(u, ci, CA_PROTECTME)) { if (key && meaning) { strnrepl(key, MAX_KEY, "%", "%%"); if (is_lock(key, ci->name) == 1) { do_msgnick(ci->bi->nick, u->nick, ERROR_LOCKED, key); free(sql); return MOD_CONT; } if (check_key(key, ci->name) == -1) { strnrepl(meaning, MAX_MEANING, "%", "%%"); ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "SELECT `meaning` FROM `terms` WHERE `chan` = '%s' AND `key` = '%s';", ciname, key); result = my_query(sql); my_res = mysql_store_result(my_mysql); my_row = mysql_fetch_row(my_res); oldmeaning = my_row[0]; mysql_free_result(my_res); /* We need to avoid overflows */ if ((strlen(oldmeaning) + strlen(meaning)) > max_size) { free(ciname); free(sql); do_msgnick(ci->bi->nick, u->nick, ERROR_OVERFLOW); return MOD_CONT; } newmeaning = (char *) malloc(max_size); snprintf(newmeaning, max_size, "%s", oldmeaning); strncat(newmeaning, space, (max_size - 1)); strncat(newmeaning, meaning, (max_size - 1)); ameaning = newmeaning; newmeaning = my_quote(newmeaning); akey = key; key = my_quote(key); snprintf(sql, MAX_SQL_BUF, "UPDATE `terms` SET `meaning` = '%s' WHERE `chan` = '%s' AND `key` = '%s';", newmeaning, ciname, key); result = my_query(sql); free(key); free(newmeaning); free(ciname); if (!result) do_msgchan(ci->bi->nick, ci->name, "%s == %s", akey, ameaning); else do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } else do_msgnick(ci->bi->nick, u->nick, ERROR_NOT_DEFINED, key); } else { do_msgnick(ci->bi->nick, u->nick, APPEND_SYNTAX); free(sql); return MOD_CONT; } } free(sql); return MOD_CONT; } int do_ask(User * u, ChannelInfo * ci) { char *text = NULL; char *cmd = NULL; char *key = NULL; char *akey = NULL; char *ciname = NULL; char *sql; int result; int counted = 0; if (mod_current_buffer) text = mod_current_buffer; cmd = myStrGetToken(text, ' ', 0); key = myStrGetToken(text, ' ', 1); if (!cmd) return MOD_CONT; sql = (char *) malloc(MAX_SQL_BUF); if ((ci->botflags & BS_FANTASY)) { if (!stricmp(cmd, "?")) { if (key) { strnrepl(key, MAX_KEY, "%", "%%"); akey = key; key = my_quote(key); ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "SELECT `meaning` FROM `terms` WHERE `key` = '%s' AND chan = '%s'", key, ciname); free(ciname); result = my_query(sql); if (!result) { my_res = mysql_store_result(my_mysql); counted = mysql_num_rows(my_res); if (counted > 0) { my_row = mysql_fetch_row(my_res); do_msgchan(ci->bi->nick, ci->name, "%s == %s", akey, my_row[0]); mysql_free_result(my_res); do_inchit(key, ci->name); } else { do_msgchan(ci->bi->nick, ci->name, ASK_ERROR_NOT_DEFINED, akey); mysql_free_result(my_res); } } else { do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } free(key); } } else if (!stricmp(cmd, "??")) { if (key) { strnrepl(key, MAX_KEY, "%", "%%"); akey = key; key = my_quote(key); ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "SELECT `meaning` FROM `terms` WHERE `key` = '%s' AND `chan` = '%s';", key, ciname); free(ciname); result = my_query(sql); if (!result) { my_res = mysql_store_result(my_mysql); counted = mysql_num_rows(my_res); if (counted > 0) { my_row = mysql_fetch_row(my_res); do_msgchan(ci->bi->nick, ci->name, "%s == %s", akey, my_row[0]); mysql_free_result(my_res); do_inchit(key, ci->name); do_whoset(u, ci); } else { do_msgchan(ci->bi->nick, ci->name, ASK_ERROR_NOT_DEFINED, akey); mysql_free_result(my_res); } } else { do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } free(key); } } else { free(sql); return MOD_CONT; } } free(sql); return MOD_CONT; } int do_ignore(User * u, ChannelInfo * ci) { char *text = NULL; char *pattern = NULL; char *apattern = NULL; char *cmd = NULL; char *ciname = NULL; char *sql; int result; int counted; int i = 0; if (mod_current_buffer) text = mod_current_buffer; cmd = myStrGetToken(text, ' ', 1); pattern = myStrGetToken(text, ' ', 2); sql = (char *) malloc(MAX_SQL_BUF); if ((ci->botflags & BS_FANTASY) && check_access(u, ci, CA_PROTECTME)) { if (!cmd) { do_msgnick(ci->bi->nick, u->nick, IGNORE_SYNTAX); free(sql); return MOD_CONT; } if (!stricmp(cmd, "clear")) { if (check_access(u, ci, CA_CLEAR)) { ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "DELETE FROM `ignores` WHERE `chan` = '%s';", ciname); free(ciname); result = my_query(sql); i = mysql_affected_rows(my_mysql); if (i > 0) do_msgnick(ci->bi->nick, u->nick, IGNORE_CLEAR_DONE, i); else do_msgnick(ci->bi->nick, u->nick, IGNORE_ERROR_EMPTY); free(mysql); return MOD_CONT; } else { free(sql); return MOD_CONT; } } if (!stricmp(cmd, "list")) { ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "SELECT * FROM `ignores` WHERE `chan` = '%s';", ciname); free(ciname); result = my_query(sql); if (result) { do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); free(sql); return MOD_CONT; } my_res = mysql_store_result(my_mysql); counted = mysql_num_rows(my_res); if (counted == 0) { do_msgnick(ci->bi->nick, u->nick, IGNORE_ERROR_EMPTY); mysql_free_result(my_res); free(sql); return MOD_CONT; } do_msgnick(ci->bi->nick, u->nick, "%-5s %-40s %s", "Num", "Mask", "Set by"); while ((my_row = mysql_fetch_row(my_res))) { i++; do_msgnick(ci->bi->nick, u->nick, "%-5d %-30s %s", i, my_row[1], my_row[2]); } mysql_free_result(my_res); free(sql); return MOD_CONT; } if (!pattern) { do_msgnick(ci->bi->nick, u->nick, IGNORE_SYNTAX); free(sql); return MOD_CONT; } if (strlen(pattern) < 5) { do_msgnick(ci->bi->nick, u->nick, IGNORE_ERROR_MASK); free(sql); return MOD_CONT; } if ((!(strstr(pattern, "!"))) || (!(strstr(pattern, "@")))) { do_msgnick(ci->bi->nick, u->nick, IGNORE_ERROR_MASK); free(sql); return MOD_CONT; } strnrepl(pattern, MAX_KEY, "%", "%%"); if ((stricmp(pattern, "*") == 0) || (stricmp(pattern, "*!*@*") == 0)) { do_msgnick(ci->bi->nick, u->nick, IGNORE_ERROR_TOOWIDE, pattern); free(sql); return MOD_CONT; } if (pattern && strspn(pattern, "!*@*?") > strlen(pattern)) { do_msgnick(ci->bi->nick, u->nick, IGNORE_ERROR_TOOWIDE, pattern); free(sql); return MOD_CONT; } if (!stricmp(cmd, "add")) { apattern = pattern; pattern = my_quote(pattern); ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "INSERT INTO `ignores` (`chan`, `mask`, `author`) VALUES ('%s', '%s', '%s');", ciname, pattern, u->nick); free(pattern); free(ciname); result = my_query(sql); if (!result) do_msgnick(ci->bi->nick, u->nick, IGNORE_DONE, apattern); else do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } else if (!stricmp(cmd, "del")) { apattern = pattern; pattern = my_quote(pattern); ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "DELETE FROM `ignores` WHERE `mask`= '%s' AND `chan` = '%s';", pattern, ciname); free(ciname); free(pattern); result = my_query(sql); if (!result) { if (!mysql_affected_rows(my_mysql)) do_msgnick(ci->bi->nick, u->nick, IGNORE_DEL_ERROR, apattern); else do_msgnick(ci->bi->nick, u->nick, IGNORE_DEL_DONE, apattern); } else do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } free(sql); } return MOD_CONT; } int check_ignored(User * u, ChannelInfo * ci) { char *sql; char mask[BUFSIZE]; // Real host char mask2[BUFSIZE]; // Virtual host int result; int counted; char *ciname = NULL; sql = (char *) malloc(MAX_SQL_BUF); if (check_access(u, ci, CA_SAY)) { free(sql); return 0; } snprintf(mask, sizeof(mask), "%s!%s@%s", u->nick, u->username, u->host); if (u->vident) snprintf(mask2, sizeof(mask2), "%s!%s@%s", u->nick, u->vident, u->vhost); else snprintf(mask2, sizeof(mask2), "%s!%s@%s", u->nick, u->username, u->vhost); ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "SELECT `mask` FROM `ignores` WHERE `chan` = '%s';", ciname); free(ciname); result = my_query(sql); if (result) { alog("[%s.so] Unexpected error consulting to MySQL. Result: %d", MYNAME, result); free(sql); return 1; // We set it as ignored, so he must try again. } my_res = mysql_store_result(my_mysql); counted = mysql_num_rows(my_res); if (counted == 0) { mysql_free_result(my_res); free(sql); return 0; } while ((my_row = mysql_fetch_row(my_res))) { if ((match_wild_nocase(my_row[0], mask)) || (match_wild_nocase(my_row[0], mask2))) { mysql_free_result(my_res); free(sql); return 1; } } return 0; } int do_xtop(User * u, ChannelInfo * ci) { char *text = NULL; char *sql; char *top = NULL; char *slimit = NULL; char *space = " "; char *ciname = NULL; int counted = 0; int result, limit; int malloc_size = (255 * 25); if (mod_current_buffer) text = mod_current_buffer; slimit = myStrGetToken(text, ' ', 1); if (!slimit) limit = 10; else limit = atoi(slimit); if (limit < 1) { do_msgnick(ci->bi->nick, u->nick, XTOP_WRONG_VALUE); return MOD_CONT; } sql = (char *) malloc(MAX_SQL_BUF); top = (char *) malloc(malloc_size); if ((ci->botflags & BS_FANTASY)) { ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "SELECT `key` FROM `terms` WHERE `chan` = '%s' ORDER BY `hits` DESC LIMIT %d", ciname, limit); free(ciname); result = mysql_query(my_mysql, sql); if (!result) { my_res = mysql_store_result(my_mysql); counted = mysql_num_rows(my_res); if (counted > 0) { snprintf(top, malloc_size, "= "); while ((my_row = mysql_fetch_row(my_res))) { strncat(top, my_row[0], malloc_size); strncat(top, space, malloc_size); } do_msgchan(ci->bi->nick, ci->name, "Top %d =%s", limit, top); } else { do_msgnick(ci->bi->nick, u->nick, ERROR_NO_ENTRIES); } mysql_free_result(my_res); } else do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } free(top); free(sql); return MOD_CONT; } int do_find(User * u, ChannelInfo * ci) { char *text = NULL; char *sql; char *found = NULL; char *target = NULL; char *ciname = NULL; char *space = " "; int counted = 0; int result; int malloc_size = (255 * 25); if (mod_current_buffer) text = mod_current_buffer; target = myStrGetToken(text, ' ', 1); if (!target) { do_msgnick(ci->bi->nick, u->nick, FIND_SYNTAX); return MOD_CONT; } if (!strcmp(target, "*")) { do_msgnick(ci->bi->nick, u->nick, FIND_ERROR_NOWILD); return MOD_CONT; } if (strlen(target) < 3) { do_msgnick(ci->bi->nick, u->nick, FIND_ERROR_LENGTH); return MOD_CONT; } sql = (char *) malloc(MAX_SQL_BUF); found = (char *) malloc(malloc_size); if ((ci->botflags & BS_FANTASY)) { target = my_quote(target); ciname = my_quote(ci->name); snprintf(sql, MAX_SQL_BUF, "SELECT `key` FROM `terms` WHERE `chan` = '%s' AND `key` LIKE '%%%s%%';", ciname, target); free(target); free(ciname); result = mysql_query(my_mysql, sql); if (!result) { my_res = mysql_store_result(my_mysql); counted = mysql_num_rows(my_res); if (counted > 0) { snprintf(found, malloc_size, "= "); while ((my_row = mysql_fetch_row(my_res))) { strncat(found, my_row[0], malloc_size); strncat(found, space, malloc_size); } do_msgnick(ci->bi->nick, u->nick, "Result =%s", found); } else { do_msgnick(ci->bi->nick, u->nick, ERROR_NO_ENTRIES); } mysql_free_result(my_res); } else do_msgnick(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } free(found); free(sql); return MOD_CONT; } void do_inchit(char *key, char *chan) { char *sql; sql = (char *) malloc(MAX_SQL_BUF); chan = my_quote(chan); snprintf(sql, MAX_SQL_BUF, "UPDATE `terms` SET `hits` = `hits` + 1 WHERE `chan` = '%s' AND `key` = '%s';", chan, key); free(chan); my_query(sql); } int is_lock(char *key, char *chan) { char *sql; int locked; int result; key = my_quote(key); chan = my_quote(chan); sql = (char *) malloc(MAX_SQL_BUF); snprintf(sql, MAX_SQL_BUF, "SELECT `locked` FROM `terms` WHERE `chan` = '%s' AND `key` = '%s' AND `locked` = 1;", chan, key); free(key); free(chan); result = my_query(sql); my_res = mysql_store_result(my_mysql); locked = mysql_num_rows(my_res); mysql_free_result(my_res); free(sql); if (locked == 1) { return 1; } return 0; } int check_key(char *key, char *chan) { char *sql; int counted = 0; sql = (char *) malloc(MAX_SQL_BUF); key = my_quote(key); chan = my_quote(chan); snprintf(sql, MAX_SQL_BUF, "SELECT `meaning` FROM `terms` WHERE `chan` = '%s' AND `key` = '%s';", chan, key); free(key); free(chan); my_query(sql); my_res = mysql_store_result(my_mysql); counted = mysql_num_rows(my_res); mysql_free_result(my_res); free(sql); if (counted > 0) return -1; return 0; } int check_mytable() { char *sql; int result; sql = (char *) malloc(MAX_SQL_BUF); snprintf(sql, MAX_SQL_BUF, "SHOW TABLES LIKE 'terms';"); mysql_query(my_mysql, sql); my_res = mysql_store_result(my_mysql); if (mysql_num_rows(my_res) == 0) { snprintf(sql, MAX_SQL_BUF, "CREATE TABLE `terms` (`id` int(11) NOT NULL auto_increment, `chan` varchar(255) NOT NULL default '', `key` varchar(255) NOT NULL default '', `meaning` text NOT NULL, `author` varchar(80) NOT NULL default '', `locked` int(1) NOT NULL default '0', `date` datetime NOT NULL default '0000-00-00 00:00:00', `hits` int(11) NOT NULL default '0', PRIMARY KEY (`id`)) TYPE=MyISAM;"); result = my_query(sql); if (!result) alog("[%s.so] Created table terms", MYNAME); else { alog("[%s.so] Error creating the required tables!.", MYNAME); alog("[%s.so] Unloading...", MYNAME); return -1; } } snprintf(sql, MAX_SQL_BUF, "SHOW TABLES LIKE 'channels';"); mysql_query(my_mysql, sql); my_res = mysql_store_result(my_mysql); if (mysql_num_rows(my_res) == 0) { snprintf(sql, MAX_SQL_BUF, "CREATE TABLE `channels` (`id` int(11) NOT NULL auto_increment, `name` varchar(255) NOT NULL default '', PRIMARY KEY (`id`), UNIQUE KEY `value` (`name`)) TYPE=MyISAM PACK_KEYS=0;"); result = my_query(sql); if (!result) alog("[%s.so] Created table channels", MYNAME); else { alog("[%s.so] Error creating the required tables!.", MYNAME); alog("[%s.so] Unloading...", MYNAME); return -1; } } snprintf(sql, MAX_SQL_BUF, "SHOW TABLES LIKE 'ignores';"); mysql_query(my_mysql, sql); my_res = mysql_store_result(my_mysql); if (mysql_num_rows(my_res) == 0) { snprintf(sql, MAX_SQL_BUF, "CREATE TABLE `ignores` (`chan` varchar(255) NOT NULL default '', `mask` varchar(255) NOT NULL default '', `author` varchar(255) NOT NULL default '') TYPE=MyISAM;"); result = my_query(sql); if (!result) alog("[%s.so] Created table ignores", MYNAME); else { alog("[%s.so] Error creating the required tables!.", MYNAME); alog("[%s.so] Unloading...", MYNAME); return -1; } } mysql_free_result(my_res); free(sql); return 0; } static int my_query(char *sql) { int result; if (debug) alog(sql); result = mysql_query(my_mysql, sql); if (result) { log_perror(mysql_error(my_mysql)); return result; } return 0; } char *my_quote(char *mystring) { int slen; char *quoted; slen = strlen(mystring); quoted = malloc((1 + (slen * 2)) * sizeof(char)); mysql_real_escape_string(my_mysql, quoted, mystring, slen); return quoted; } int do_onoff(User * u) { char *sql; char *args = NULL; char *chan = NULL; char *option = NULL; char *value = NULL; char *achan = NULL; int is_servadmin = is_services_admin(u); int result; ChannelInfo *ci; if (moduleGetLastBuffer()) { args = sstrdup(moduleGetLastBuffer()); chan = myStrGetToken(args, ' ', 0); option = myStrGetToken(args, ' ', 1); value = myStrGetToken(args, ' ', 2); free(args); } if (readonly) return MOD_CONT; else if (!chan || !option || !value) return MOD_CONT; else if (is_servadmin && !stricmp(option, "PRIVATE")) return MOD_CONT; else if (!(ci = cs_findchan(chan))) return MOD_CONT; else if (ci->flags & CI_VERBOTEN) return MOD_CONT; else if (!is_servadmin && !check_access(u, ci, CA_SET)) return MOD_CONT; else { if (!stricmp(option, "ZBOT")) { sql = (char *) malloc(MAX_SQL_BUF); if (!stricmp(value, "ON")) { if (check_on_off(chan) < 1) { achan = chan; chan = my_quote(chan); snprintf(sql, MAX_SQL_BUF, "INSERT INTO `channels` (`name`) VALUES ('%s');", chan); free(chan); result = my_query(sql); if (!result) notice(s_BotServ, u->nick, ZBOT_SET_ON, achan); else notice(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } else notice(s_BotServ, u->nick, ZBOT_SET_ALREADY_ON); } else if (!stricmp(value, "OFF")) { if (check_on_off(chan) == 1) { achan = chan; chan = my_quote(chan); snprintf(sql, MAX_SQL_BUF, "DELETE FROM `channels` WHERE `name` = '%s';", chan); free(chan); result = my_query(sql); if (!result) notice(s_BotServ, u->nick, ZBOT_SET_OFF, achan); else notice(ci->bi->nick, u->nick, ERROR_TRY_AGAIN); } else notice(s_BotServ, u->nick, ZBOT_SET_ALREADY_OFF); } else notice(s_BotServ, u->nick, ZBOT_SET_SYNTAX); free(sql); } else return MOD_CONT; } return MOD_STOP; } int do_sadminutils(User * u) { char *sql; char *args = NULL; char *option = NULL; char *value = NULL; char *tmp = NULL; char *s = NULL; int result, from = 0, to = 0; /* Just to be sure */ if (!is_services_admin(u)) { notice_lang(s_BotServ, u, ACCESS_DENIED); return MOD_CONT; } if (moduleGetLastBuffer()) { args = sstrdup(moduleGetLastBuffer()); option = myStrGetToken(args, ' ', 0); value = myStrGetToken(args, ' ', 1); free(args); } if (!option) return MOD_CONT; else { if (!stricmp(option, "LISTCHANS")) { if (!value) { notice(s_BotServ, u->nick, ZBOT_LISTCHANS_SYNTAX); return MOD_CONT; } else { int counted = 0, counting = 0; /* Just like ChanServ LIST */ if (value) { if (value[0] == '#') { tmp = myStrGetOnlyToken((value + 1), '-', 0); if (!tmp) { return MOD_CONT; } for (s = tmp; *s; s++) { if (!isdigit(*s)) { return MOD_CONT; } } from = atoi(tmp); tmp = myStrGetTokenRemainder(value, '-', 1); if (!tmp) { return MOD_CONT; } for (s = tmp; *s; s++) { if (!isdigit(*s)) { return MOD_CONT; } } to = atoi(tmp); value = sstrdup("*"); /* set me free please! */ } } sql = (char *) malloc(MAX_SQL_BUF); /* set me free please! */ snprintf(sql, MAX_SQL_BUF, "SELECT `name` FROM `channels`;"); result = my_query(sql); if (result) notice(s_BotServ, u->nick, ERROR_TRY_AGAIN); else { my_res = mysql_store_result(my_mysql); counted = mysql_num_rows(my_res); if (counted > 0) { notice(s_BotServ, u->nick, ZBOT_LISTCHANS_HEAD, value); while ((my_row = mysql_fetch_row(my_res))) { if (stricmp(value, my_row[0]) == 0 || match_wild_nocase(value, my_row[0])) { counting++; notice(s_BotServ, u->nick, " %s", my_row[0]); } } notice(s_BotServ, u->nick, ZBOT_LISTCHANS_FOOT, counting, counted); } mysql_free_result(my_res); } free(value); free(sql); } } else if (!stricmp(option, "STATS")) { int nchans = 0, nkeys = 0; sql = (char *) malloc(MAX_SQL_BUF); /* set me free please! */ snprintf(sql, MAX_SQL_BUF, "SELECT `id` FROM `channels`;"); result = my_query(sql); if (result) { notice(s_BotServ, u->nick, ERROR_TRY_AGAIN); free(sql); return MOD_CONT; } else { my_res = mysql_store_result(my_mysql); nchans = mysql_num_rows(my_res); mysql_free_result(my_res); } snprintf(sql, MAX_SQL_BUF, "SELECT `id` FROM `terms`;"); result = my_query(sql); if (result) { notice(s_BotServ, u->nick, ERROR_TRY_AGAIN); free(sql); return MOD_CONT; } else { my_res = mysql_store_result(my_mysql); nkeys = mysql_num_rows(my_res); mysql_free_result(my_res); } notice(s_BotServ, u->nick, ZBOT_STATS_CHANNELS, nchans); notice(s_BotServ, u->nick, ZBOT_STATS_KEYS, nkeys); free(sql); } else if (!stricmp(option, "DELCHAN")) { char *chan = value; if (!value) { notice(s_BotServ, u->nick, ZBOT_DELCHAN_SYNTAX); return MOD_CONT; } chan = my_quote(chan); sql = (char *) malloc(MAX_SQL_BUF); /* set me free please! */ snprintf(sql, MAX_SQL_BUF, "DELETE FROM `channels` WHERE `name` = '%s';", chan); result = my_query(sql); if (result) { notice(s_BotServ, u->nick, ERROR_TRY_AGAIN); free(chan); free(sql); return MOD_CONT; } snprintf(sql, MAX_SQL_BUF, "DELETE FROM `terms` WHERE chan = '%s';", chan); result = my_query(sql); if (result) { notice(s_BotServ, u->nick, ERROR_TRY_AGAIN); free(chan); free(sql); return MOD_CONT; } snprintf(sql, MAX_SQL_BUF, "DELETE FROM `ignores` WHERE chan = '%s';", chan); free(chan); result = my_query(sql); if (result) { notice(s_BotServ, u->nick, ERROR_TRY_AGAIN); free(sql); return MOD_CONT; } notice(s_BotServ, u->nick, ZBOT_DELCHAN_DONE, value); free(sql); } else if (!stricmp(option, "CLEARDB")) { if (is_services_root(u) && u->isSuperAdmin) { sql = (char *) malloc(MAX_SQL_BUF); /* set me free please! */ snprintf(sql, MAX_SQL_BUF, "TRUNCATE `channels`;"); result = my_query(sql); if (result) { notice(s_BotServ, u->nick, ERROR_TRY_AGAIN); free(sql); return MOD_CONT; } snprintf(sql, MAX_SQL_BUF, "TRUNCATE `ignores`;"); result = my_query(sql); if (result) { notice(s_BotServ, u->nick, ERROR_TRY_AGAIN); free(sql); return MOD_CONT; } snprintf(sql, MAX_SQL_BUF, "TRUNCATE `terms`;"); result = my_query(sql); if (result) { notice(s_BotServ, u->nick, ERROR_TRY_AGAIN); free(sql); return MOD_CONT; } alog("[%.so] %s is cleaning the database!", MYNAME, u->nick); notice(s_BotServ, u->nick, ZBOT_CLEARDB_DONE); free(sql); } else notice_lang(s_BotServ, u, ACCESS_DENIED); } else notice(s_BotServ, u->nick, ZBOT_HELP_MAIN); } return MOD_CONT; } void BS_zbot_help(User * u) { notice(s_BotServ, u->nick, ZBOT_SET_SYNTAX); notice(s_BotServ, u->nick, ZBOT_HELP_SET); if (is_services_admin(u)) { notice(s_BotServ, u->nick, "\002\002"); notice(s_BotServ, u->nick, ZBOT_HELP_MAIN); notice(s_BotServ, u->nick, "\002\002"); notice(s_BotServ, u->nick, ZBOT_LISTCHANS_SYNTAX); notice(s_BotServ, u->nick, ZBOT_HELP_LISTCHANS); notice(s_BotServ, u->nick, "\002\002"); notice(s_BotServ, u->nick, ZBOT_STATS_SYNTAX); notice(s_BotServ, u->nick, ZBOT_HELP_STATS); notice(s_BotServ, u->nick, "\002\002"); notice(s_BotServ, u->nick, ZBOT_DELCHAN_SYNTAX); notice(s_BotServ, u->nick, ZBOT_HELP_DELCHAN); } else if (is_services_root(u)) { notice(s_BotServ, u->nick, "\002\002"); notice(s_BotServ, u->nick, ZBOT_CLEARDB_SYNTAX); notice(s_BotServ, u->nick, ZBOT_HELP_CLEARDB); } } int check_on_off(char *chan) { char *sql; int result, counted = 0; sql = (char *) malloc(MAX_SQL_BUF); chan = my_quote(chan); snprintf(sql, MAX_SQL_BUF, "SELECT * FROM `channels` WHERE `name` = '%s';", chan); free(chan); result = my_query(sql); if (result) { alog("[%.so] An error has occured, please check your MySQL connection", MYNAME); return -1; } my_res = mysql_store_result(my_mysql); counted = mysql_num_rows(my_res); mysql_free_result(my_res); free(sql); if (counted < 1) return 0; return 1; } void do_msgnick(char *whosend, char *nick, const char *fmt, ...) { va_list args; char buf[BUFSIZE]; *buf = '\0'; if (fmt) { va_start(args, fmt); vsnprintf(buf, BUFSIZE - 1, fmt, args); if (!buf) { return; } #if defined(USE_NICK_PRIVMSG) privmsg(whosend, nick, buf); #else notice(whosend, nick, buf); #endif va_end(args); } } void do_msgchan(char *whosend, char *chan, const char *fmt, ...) { va_list args; char buf[BUFSIZE]; *buf = '\0'; if (fmt) { va_start(args, fmt); vsnprintf(buf, BUFSIZE - 1, fmt, args); if (!buf) { return; } #if defined(USE_CHAN_PRIVMSG) privmsg(whosend, chan, buf); #else notice(whosend, chan, buf); #endif va_end(args); } } /* EOF */