diff options
| author | rob rob@31f1291d-b8d6-0310-a050-a5561fc1590b <rob rob@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864> | 2004-07-19 14:08:30 +0000 |
|---|---|---|
| committer | rob rob@31f1291d-b8d6-0310-a050-a5561fc1590b <rob rob@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864> | 2004-07-19 14:08:30 +0000 |
| commit | a1479a87757fb5e9b48f3c8bb5dd9cc247406f1a (patch) | |
| tree | 06d23a51082a398c512ed8f1e39bdac60d4dd658 /src/botserv.c | |
| parent | 7fffea77edbe72cd66f7a55f41a3966204f9cf86 (diff) | |
BUILD : 1.7.4 (264) BUGS : N/A NOTES : Switched to autoconf - try to commit part 1
git-svn-id: svn://svn.anope.org/anope/trunk@264 31f1291d-b8d6-0310-a050-a5561fc1590b
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@169 5417fbe8-f217-4b02-8779-1006273d7864
Diffstat (limited to 'src/botserv.c')
| -rw-r--r-- | src/botserv.c | 2593 |
1 files changed, 2593 insertions, 0 deletions
diff --git a/src/botserv.c b/src/botserv.c new file mode 100644 index 000000000..418e029d6 --- /dev/null +++ b/src/botserv.c @@ -0,0 +1,2593 @@ +/* BotServ functions + * + * (C) 2003 Anope Team + * Contact us at info@anope.org + * + * Please read COPYING and README for furhter details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + * + * $Id$ + * + */ + +/*************************************************************************/ + +#include "services.h" +#include "pseudo.h" + +/** + * RFC: defination of a valid nick + * nickname = ( letter / special ) *8( letter / digit / special / "-" ) + * letter = %x41-5A / %x61-7A ; A-Z / a-z + * digit = %x30-39 ; 0-9 + * special = %x5B-60 / %x7B-7D ; "[", "]", "\", "`", "_", "^", "{", "|", "}" + **/ +#define isvalidnick(c) ( isalnum(c) || ((c) >='\x5B' && (c) <='\x60') || ((c) >='\x7B' && (c) <='\x7D') || (c)=='-' ) + + +/*************************************************************************/ + +BotInfo *botlists[256]; /* Hash list of bots */ +int nbots = 0; + +/*************************************************************************/ + +BotInfo *makebot(char *nick); +static UserData *get_user_data(Channel * c, User * u); +static void unassign(User * u, ChannelInfo * ci); + +static void check_ban(ChannelInfo * ci, User * u, int ttbtype); +static void bot_kick(ChannelInfo * ci, User * u, int message, ...); +static void bot_raw_ban(User * requester, ChannelInfo * ci, char *nick, + char *reason); +static void bot_raw_kick(User * requester, ChannelInfo * ci, char *nick, + char *reason); +static void bot_raw_mode(User * requester, ChannelInfo * ci, char *mode, + char *nick); +static void bot_raw_unban(ChannelInfo * ci, char *nick); + +static int do_help(User * u); +static int do_bot(User * u); +static int do_botlist(User * u); +static int do_assign(User * u); +static int do_unassign(User * u); +static int do_info(User * u); +static int do_set(User * u); +static int do_kickcmd(User * u); +static int do_badwords(User * u); +static int do_say(User * u); +static int do_act(User * u); +void moduleAddBotServCmds(void); +char *normalizeBuffer(char *); +/*************************************************************************/ +/* *INDENT-OFF* */ +void moduleAddBotServCmds(void) { + Command *c; + c = createCommand("HELP",do_help,NULL, -1,-1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("BOTLIST", do_botlist, NULL, BOT_HELP_BOTLIST, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("ASSIGN", do_assign, NULL, BOT_HELP_ASSIGN, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("UNASSIGN", do_unassign, NULL, BOT_HELP_UNASSIGN, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("INFO", do_info, NULL, BOT_HELP_INFO, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("SET", do_set, NULL, BOT_HELP_SET,-1, BOT_SERVADMIN_HELP_SET,BOT_SERVADMIN_HELP_SET, BOT_SERVADMIN_HELP_SET); addCoreCommand(BOTSERV,c); + c = createCommand("SET DONTKICKOPS", NULL, NULL, BOT_HELP_SET_DONTKICKOPS, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("SET DONTKICKVOICES", NULL, NULL, BOT_HELP_SET_DONTKICKVOICES, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("SET FANTASY", NULL, NULL, BOT_HELP_SET_FANTASY, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("SET GREET", NULL, NULL, BOT_HELP_SET_GREET, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("SET SYMBIOSIS", NULL, NULL, BOT_HELP_SET_SYMBIOSIS, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("KICK", do_kickcmd, NULL, BOT_HELP_KICK, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("KICK BADWORDS", NULL, NULL, BOT_HELP_KICK_BADWORDS, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("KICK BOLDS", NULL, NULL, BOT_HELP_KICK_BOLDS, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("KICK CAPS", NULL, NULL, BOT_HELP_KICK_CAPS, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("KICK COLORS", NULL, NULL, BOT_HELP_KICK_COLORS, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("KICK FLOOD", NULL, NULL, BOT_HELP_KICK_FLOOD, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("KICK REPEAT", NULL, NULL, BOT_HELP_KICK_REPEAT, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("KICK REVERSES", NULL, NULL, BOT_HELP_KICK_REVERSES, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("KICK UNDERLINES", NULL, NULL, BOT_HELP_KICK_UNDERLINES, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("BADWORDS", do_badwords, NULL, BOT_HELP_BADWORDS, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("SAY", do_say, NULL, BOT_HELP_SAY, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + c = createCommand("ACT", do_act, NULL, BOT_HELP_ACT, -1,-1,-1,-1); addCoreCommand(BOTSERV,c); + + /* Services admins commands */ + c = createCommand("BOT", do_bot, is_services_admin, -1,-1, BOT_SERVADMIN_HELP_BOT,BOT_SERVADMIN_HELP_BOT, BOT_SERVADMIN_HELP_BOT); addCoreCommand(BOTSERV,c); + c = createCommand("SET NOBOT", NULL, NULL, -1,-1, BOT_SERVADMIN_HELP_SET_NOBOT,BOT_SERVADMIN_HELP_SET_NOBOT, BOT_SERVADMIN_HELP_SET_NOBOT); addCoreCommand(BOTSERV,c); + c = createCommand("SET PRIVATE", NULL, NULL, -1,-1, BOT_SERVADMIN_HELP_SET_PRIVATE,BOT_SERVADMIN_HELP_SET_PRIVATE, BOT_SERVADMIN_HELP_SET_PRIVATE); addCoreCommand(BOTSERV,c); +} +/* *INDENT-ON* */ +/*************************************************************************/ +/*************************************************************************/ + +/* Return information on memory use. Assumes pointers are valid. */ + +void get_botserv_stats(long *nrec, long *memuse) +{ + long count = 0, mem = 0; + int i; + BotInfo *bi; + + for (i = 0; i < 256; i++) { + for (bi = botlists[i]; bi; bi = bi->next) { + count++; + mem += sizeof(*bi); + mem += strlen(bi->nick) + 1; + mem += strlen(bi->user) + 1; + mem += strlen(bi->host) + 1; + mem += strlen(bi->real) + 1; + } + } + + *nrec = count; + *memuse = mem; +} + +/*************************************************************************/ +/*************************************************************************/ + +/* BotServ initialization. */ + +void bs_init(void) +{ + Command *cmd; + moduleAddBotServCmds(); + cmd = findCommand(BOTSERV, "SET SYMBIOSIS"); + if (cmd) + cmd->help_param1 = s_ChanServ; +} + +/*************************************************************************/ + +/* Main BotServ routine. */ + +void botserv(User * u, char *buf) +{ + char *cmd, *s; + + cmd = strtok(buf, " "); + + if (!cmd) { + return; + } else if (stricmp(cmd, "\1PING") == 0) { + if (!(s = strtok(NULL, ""))) + s = "\1"; + notice(s_BotServ, u->nick, "\1PING %s", s); + } else if (skeleton) { + notice_lang(s_BotServ, u, SERVICE_OFFLINE, s_BotServ); + } else { + mod_run_cmd(s_BotServ, u, BOTSERV, cmd); + } + +} + +/*************************************************************************/ + +/* Handles all messages sent to bots. (Currently only answers to pings ;) */ + +void botmsgs(User * u, BotInfo * bi, char *buf) +{ + char *cmd = strtok(buf, " "); + char *s; + + if (!cmd || !u) + return; + + if (!stricmp(cmd, "\1PING")) { + if (!(s = strtok(NULL, ""))) + s = "\1"; + notice(bi->nick, u->nick, "\1PING %s", s); + } +} + +/*************************************************************************/ + +/* Handles all messages that are sent to registered channels where a + * bot is on. + * + */ + +void botchanmsgs(User * u, ChannelInfo * ci, char *buf) +{ + int c; + int16 cstatus = 0; + char *cmd; + UserData *ud; + + if (!u) + return; + + /* Answer to ping if needed, without breaking the buffer. */ + if (!strnicmp(buf, "\1PING", 5)) + notice(ci->bi->nick, u->nick, buf); + + /* If it's a /me, cut the CTCP part at the beginning (not + * at the end, because one character just doesn't matter, + * but the ACTION may create strange behaviours with the + * caps or badwords kickers */ + if (!strnicmp(buf, "\1ACTION ", 8)) + buf += 8; + + /* Now we can make kicker stuff. We try to order the checks + * from the fastest one to the slowest one, since there's + * no need to process other kickers if an user is kicked before + * the last kicker check. + * + * But FIRST we check whether the user is protected in any + * way. + */ + + /* We first retrieve the user status on the channel if needed */ + if (ci->botflags & (BS_DONTKICKOPS | BS_DONTKICKVOICES)) + cstatus = chan_get_user_status(ci->c, u); + + if (buf && !check_access(u, ci, CA_NOKICK) && +#ifdef HAS_HALFOP +#if defined(IRC_UNREAL) || defined (IRC_VIAGRA) + (!(ci->botflags & BS_DONTKICKOPS) + || !(cstatus & (CUS_HALFOP | CUS_OP | CUS_OWNER | CUS_PROTECT))) +# elif defined (IRC_ULTIMATE3) || defined(IRC_RAGE2) + (!(ci->botflags & BS_DONTKICKOPS) + || !(cstatus & (CUS_HALFOP | CUS_OP | CUS_PROTECT))) +# else + (!(ci->botflags & BS_DONTKICKOPS) + || !(cstatus & (CUS_HALFOP | CUS_OP))) +# endif +#else + (!(ci->botflags & BS_DONTKICKOPS) || !(cstatus & CUS_OP)) +#endif + && (!(ci->botflags & BS_DONTKICKVOICES) || !(cstatus & CUS_VOICE))) { + /* Bolds kicker */ + if ((ci->botflags & BS_KICK_BOLDS) && strchr(buf, 2)) { + check_ban(ci, u, TTB_BOLDS); + bot_kick(ci, u, BOT_REASON_BOLD); + return; + } + + /* Color kicker */ + if ((ci->botflags & BS_KICK_COLORS) && strchr(buf, 3)) { + check_ban(ci, u, TTB_COLORS); + bot_kick(ci, u, BOT_REASON_COLOR); + return; + } + + /* Reverses kicker */ + if ((ci->botflags & BS_KICK_REVERSES) && strchr(buf, 22)) { + check_ban(ci, u, TTB_REVERSES); + bot_kick(ci, u, BOT_REASON_REVERSE); + return; + } + + /* Underlines kicker */ + if ((ci->botflags & BS_KICK_UNDERLINES) && strchr(buf, 31)) { + check_ban(ci, u, TTB_UNDERLINES); + bot_kick(ci, u, BOT_REASON_UNDERLINE); + return; + } + + /* Caps kicker */ + if ((ci->botflags & BS_KICK_CAPS) + && ((c = strlen(buf)) >= ci->capsmin)) { + int i = 0; + char *s = buf; + + do { + if (isupper(*s)) + i++; + } while (*s++); + + if (i >= ci->capsmin && i * 100 / c >= ci->capspercent) { + check_ban(ci, u, TTB_CAPS); + bot_kick(ci, u, BOT_REASON_CAPS); + return; + } + } + + /* Bad words kicker */ + if (ci->botflags & BS_KICK_BADWORDS) { + int i; + int mustkick = 0; + char *nbuf; + BadWord *bw; + + /* Normalize the buffer */ + nbuf = normalizeBuffer(buf); + + for (i = 0, bw = ci->badwords; i < ci->bwcount; i++, bw++) { + if (!bw->in_use) + continue; + + if (bw->type == BW_ANY + && ((BSCaseSensitive && strstr(nbuf, bw->word)) + || (!BSCaseSensitive && stristr(nbuf, bw->word)))) { + mustkick = 1; + } else if (bw->type == BW_SINGLE) { + int len = strlen(bw->word); + + if ((BSCaseSensitive && strstr(nbuf, bw->word)) + || (!BSCaseSensitive + && (!stricmp(nbuf, bw->word)))) { + mustkick = 1; + /* two next if are quite odd isn't it? =) */ + } else if ((strchr(nbuf, ' ') == nbuf + len) + && + ((BSCaseSensitive + && (strstr(nbuf, bw->word) == nbuf)) + || (!BSCaseSensitive + && (stristr(nbuf, bw->word) == + nbuf)))) { + mustkick = 1; + } else + if ((strrchr(nbuf, ' ') == + nbuf + strlen(nbuf) - len - 1) + && + ((BSCaseSensitive + && (strstr(nbuf, bw->word) == + nbuf + strlen(nbuf) - len)) + || (!BSCaseSensitive + && (stristr(nbuf, bw->word) == + nbuf + strlen(nbuf) - len)))) { + mustkick = 1; + } else { + char *wordbuf = scalloc(len + 3, 1); + + wordbuf[0] = ' '; + wordbuf[len + 1] = ' '; + wordbuf[len + 2] = '\0'; + memcpy(wordbuf + 1, bw->word, len); + + if ((BSCaseSensitive && (strstr(nbuf, wordbuf))) + || (!BSCaseSensitive + && (stristr(nbuf, wordbuf)))) + mustkick = 1; + } + } else if (bw->type == BW_START) { + int len = strlen(bw->word); + + if ((BSCaseSensitive + && (!strncmp(nbuf, bw->word, len))) + || (!BSCaseSensitive + && (!strnicmp(nbuf, bw->word, len)))) { + mustkick = 1; + } else { + char *wordbuf = scalloc(len + 2, 1); + + memcpy(wordbuf + 1, bw->word, len); + wordbuf[0] = ' '; + wordbuf[len + 1] = '\0'; + + if ((BSCaseSensitive && (strstr(nbuf, wordbuf))) + || (!BSCaseSensitive + && (stristr(nbuf, wordbuf)))) + mustkick = 1; + + free(wordbuf); + } + } else if (bw->type == BW_END) { + int len = strlen(bw->word); + + if ((BSCaseSensitive + && + (!strncmp + (nbuf + strlen(nbuf) - len, bw->word, len))) + || (!BSCaseSensitive + && + (!strnicmp + (nbuf + strlen(nbuf) - len, bw->word, + len)))) { + mustkick = 1; + } else { + char *wordbuf = scalloc(len + 2, 1); + + memcpy(wordbuf, bw->word, len); + wordbuf[len] = ' '; + wordbuf[len + 1] = '\0'; + + if ((BSCaseSensitive && (strstr(nbuf, wordbuf))) + || (!BSCaseSensitive + && (stristr(nbuf, wordbuf)))) + mustkick = 1; + + free(wordbuf); + } + } + + if (mustkick) { + check_ban(ci, u, TTB_BADWORDS); + if (BSGentleBWReason) + bot_kick(ci, u, BOT_REASON_BADWORD_GENTLE); + else + bot_kick(ci, u, BOT_REASON_BADWORD, bw->word); + return; + } + } + + /* Free the normalized buffer */ + if (nbuf) + free(nbuf); + } + + /* Flood kicker */ + if (ci->botflags & BS_KICK_FLOOD) { + time_t now = time(NULL); + + ud = get_user_data(ci->c, u); + if (!ud) + return; + + if (now - ud->last_start > ci->floodsecs) { + ud->last_start = time(NULL); + ud->lines = 0; + } + + ud->lines++; + if (ud->lines >= ci->floodlines) { + check_ban(ci, u, TTB_FLOOD); + bot_kick(ci, u, BOT_REASON_FLOOD); + return; + } + } + + /* Repeat kicker */ + if (ci->botflags & BS_KICK_REPEAT) { + ud = get_user_data(ci->c, u); + if (!ud) + return; + + if (ud->lastline && stricmp(ud->lastline, buf)) { + free(ud->lastline); + ud->lastline = sstrdup(buf); + ud->times = 0; + } else { + if (!ud->lastline) + ud->lastline = sstrdup(buf); + ud->times++; + } + + if (ud->times >= ci->repeattimes) { + check_ban(ci, u, TTB_REPEAT); + bot_kick(ci, u, BOT_REASON_REPEAT); + return; + } + } + } + + + /* return if the user is on the ignore list */ + if (get_ignore(u->nick) != NULL) { + return; + } + + /* Fantaisist commands */ + + if (buf && (ci->botflags & BS_FANTASY) && *buf == '!' + && check_access(u, ci, CA_FANTASIA)) { + cmd = strtok(buf, " "); + + if (cmd) { +#if defined(IRC_UNREAL) || defined (IRC_VIAGRA) + if (!stricmp(cmd, "!deowner")) { + if (is_founder(u, ci)) + bot_raw_mode(u, ci, "-q", u->nick); + } else +#endif + if (!stricmp(cmd, "!kb")) { + char *target = strtok(NULL, " "); + char *reason = strtok(NULL, ""); + + if (!target && check_access(u, ci, CA_BANME)) { + bot_raw_ban(u, ci, u->nick, "Requested"); + } else if (target && check_access(u, ci, CA_BAN)) { + if (!stricmp(target, ci->bi->nick)) { + bot_raw_ban(u, ci, u->nick, "Oops!"); + } else { + if (!reason) + bot_raw_ban(u, ci, target, "Requested"); + else + bot_raw_ban(u, ci, target, reason); + } + } + } else if ((!stricmp(cmd, "!kick")) || (!stricmp(cmd, "!k"))) { + char *target = strtok(NULL, " "); + char *reason = strtok(NULL, ""); + + if (!target && check_access(u, ci, CA_KICKME)) { + bot_raw_kick(u, ci, u->nick, "Requested"); + } else if (target && check_access(u, ci, CA_KICK)) { + if (!stricmp(target, ci->bi->nick)) + bot_raw_kick(u, ci, u->nick, "Oops!"); + else if (!reason) + bot_raw_kick(u, ci, target, "Requested"); + else + bot_raw_kick(u, ci, target, reason); + } +#if defined(IRC_UNREAL) || defined (IRC_VIAGRA) + } else if (!stricmp(cmd, "!owner")) { + if (is_founder(u, ci)) + bot_raw_mode(u, ci, "+q", u->nick); +#endif + } else if (!stricmp(cmd, "!seen")) { + char *target = strtok(NULL, " "); + char buf[BUFSIZE]; + + if (target) { + User *u2; + NickAlias *na; + ChanAccess *access; + + if (!stricmp(ci->bi->nick, target)) { + /* If we look for the bot */ + snprintf(buf, sizeof(buf), + getstring(u->na, BOT_SEEN_BOT), u->nick); + send_cmd(ci->bi->nick, "PRIVMSG %s :%s", ci->name, + buf); + } else if (!(na = findnick(target)) + || (na->status & NS_VERBOTEN)) { + /* If the nick is not registered or forbidden */ + snprintf(buf, sizeof(buf), + getstring(u->na, BOT_SEEN_UNKNOWN), + target); + send_cmd(ci->bi->nick, "PRIVMSG %s :%s", ci->name, + buf); + } else if ((u2 = nc_on_chan(ci->c, na->nc))) { + /* If the nick we're looking for is on the channel, + * there are three possibilities: it's yourself, + * it's the nick we look for, it's an alias of the + * nick we look for. + */ + if (u == u2 || (u->na && u->na->nc == na->nc)) + snprintf(buf, sizeof(buf), + getstring(u->na, BOT_SEEN_YOU), + u->nick); + else if (!stricmp(u2->nick, target)) + snprintf(buf, sizeof(buf), + getstring(u->na, BOT_SEEN_ON_CHANNEL), + u2->nick); + else + snprintf(buf, sizeof(buf), + getstring(u->na, + BOT_SEEN_ON_CHANNEL_AS), + target, u2->nick); + send_cmd(ci->bi->nick, "PRIVMSG %s :%s", ci->name, + buf); + } else if ((access = get_access_entry(na->nc, ci))) { + /* User is on the access list but not present actually. + Special case: if access->last_seen is 0 it's that we + never seen the user. + */ + if (access->last_seen) { + char durastr[192]; + duration(u->na, durastr, sizeof(durastr), + time(NULL) - access->last_seen); + snprintf(buf, sizeof(buf), + getstring(u->na, BOT_SEEN_ON), target, + durastr); + } else { + snprintf(buf, sizeof(buf), + getstring(u->na, BOT_SEEN_NEVER), + target); + } + send_cmd(ci->bi->nick, "PRIVMSG %s :%s", ci->name, + buf); + } else { + /* All other cases */ + snprintf(buf, sizeof(buf), + getstring(u->na, BOT_SEEN_UNKNOWN), + target); + send_cmd(ci->bi->nick, "PRIVMSG %s :%s", ci->name, + buf); + } + } + } else if (!stricmp(cmd, "!unban") + && check_access(u, ci, CA_UNBAN)) { + char *target = strtok(NULL, " "); + + if (!target) + bot_raw_unban(ci, u->nick); + else + bot_raw_unban(ci, target); + } else { + CSModeUtil *util = csmodeutils; + + do { + if (!stricmp(cmd, util->bsname)) { + char *target = strtok(NULL, " "); + + if (!target + && check_access(u, ci, util->levelself)) + bot_raw_mode(u, ci, util->mode, u->nick); + else if (target + && check_access(u, ci, util->level)) + bot_raw_mode(u, ci, util->mode, target); + } + } while ((++util)->name != NULL); + } + } + } +} + +/*************************************************************************/ + +/* Load/save data files. */ + + +#define SAFE(x) do { \ + if ((x) < 0) { \ + if (!forceload) \ + fatal("Read error on %s", BotDBName); \ + failed = 1; \ + break; \ + } \ +} while (0) + +void load_bs_dbase(void) +{ + dbFILE *f; + int c, ver; + int16 tmp16; + int32 tmp32; + BotInfo *bi; + int failed = 0; + + if (!(f = open_db(s_BotServ, BotDBName, "r", BOT_VERSION))) + return; + + ver = get_file_version(f); + + while (!failed && (c = getc_db(f)) != 0) { + char *s; + + if (c != 1) + fatal("Invalid format in %s %d", BotDBName, c); + + SAFE(read_string(&s, f)); + bi = makebot(s); + free(s); + SAFE(read_string(&bi->user, f)); + SAFE(read_string(&bi->host, f)); + SAFE(read_string(&bi->real, f)); + if (ver >= 10) { + SAFE(read_int16(&tmp16, f)); + bi->flags = tmp16; + } + SAFE(read_int32(&tmp32, f)); + bi->created = tmp32; + SAFE(read_int16(&tmp16, f)); + bi->chancount = tmp16; + } + + close_db(f); +} + +#undef SAFE + +/*************************************************************************/ + +#define SAFE(x) do { \ + if ((x) < 0) { \ + restore_db(f); \ + log_perror("Write error on %s", BotDBName); \ + if (time(NULL) - lastwarn > WarningTimeout) { \ + wallops(NULL, "Write error on %s: %s", BotDBName, \ + strerror(errno)); \ + lastwarn = time(NULL); \ + } \ + return; \ + } \ +} while (0) + +void save_bs_dbase(void) +{ + dbFILE *f; + BotInfo *bi; + static time_t lastwarn = 0; + int i; + + if (!(f = open_db(s_BotServ, BotDBName, "w", BOT_VERSION))) + return; + + for (i = 0; i < 256; i++) { + for (bi = botlists[i]; bi; bi = bi->next) { + SAFE(write_int8(1, f)); + SAFE(write_string(bi->nick, f)); + SAFE(write_string(bi->user, f)); + SAFE(write_string(bi->host, f)); + SAFE(write_string(bi->real, f)); + SAFE(write_int16(bi->flags, f)); + SAFE(write_int32(bi->created, f)); + SAFE(write_int16(bi->chancount, f)); + } + } + SAFE(write_int8(0, f)); + + close_db(f); + +} + +#undef SAFE + +/*************************************************************************/ + +void save_bs_rdb_dbase(void) +{ +#ifdef USE_RDB + int i; + BotInfo *bi; + + if (!rdb_open()) + return; + + rdb_clear_table("anope_bs_core"); + + for (i = 0; i < 256; i++) { + for (bi = botlists[i]; bi; bi = bi->next) { + rdb_save_bs_core(bi); + } + } + rdb_close(); +#endif +} + +/*************************************************************************/ + +/* Inserts a bot in the bot list. I can't be much explicit mh? */ + +static void insert_bot(BotInfo * bi) +{ + BotInfo *ptr, *prev; + + for (prev = NULL, ptr = botlists[tolower(*bi->nick)]; + ptr != NULL && stricmp(ptr->nick, bi->nick) < 0; + prev = ptr, ptr = ptr->next); + bi->prev = prev; + bi->next = ptr; + if (!prev) + botlists[tolower(*bi->nick)] = bi; + else + prev->next = bi; + if (ptr) + ptr->prev = bi; +} + +/*************************************************************************/ + +BotInfo *makebot(char *nick) +{ + BotInfo *bi; + + bi = scalloc(sizeof(BotInfo), 1); + bi->nick = sstrdup(nick); + bi->lastmsg = time(NULL); + insert_bot(bi); + nbots++; + return bi; +} + +/*************************************************************************/ + +static void change_bot_nick(BotInfo * bi, char *newnick) +{ + if (bi->next) + bi->next->prev = bi->prev; + if (bi->prev) + bi->prev->next = bi->next; + else + botlists[tolower(*bi->nick)] = bi->next; + + if (bi->nick) + free(bi->nick); + bi->nick = sstrdup(newnick); + + insert_bot(bi); +} + +/*************************************************************************/ + +static int delbot(BotInfo * bi) +{ + cs_remove_bot(bi); + + if (bi->next) + bi->next->prev = bi->prev; + if (bi->prev) + bi->prev->next = bi->next; + else + botlists[tolower(*bi->nick)] = bi->next; + + nbots--; + + free(bi->nick); + free(bi->user); + free(bi->host); + free(bi->real); + + free(bi); + + return 1; +} + +/*************************************************************************/ + +BotInfo *findbot(char *nick) +{ + BotInfo *bi; + + if (!nick || !*nick) + return NULL; + + for (bi = botlists[tolower(*nick)]; bi; bi = bi->next) + if (!stricmp(nick, bi->nick)) + return bi; + + return NULL; +} + +/*************************************************************************/ + +/* Unassign a bot from a channel. Assumes u, ci and ci->bi are not NULL */ + +static void unassign(User * u, ChannelInfo * ci) +{ + if (ci->c && ci->c->usercount >= BSMinUsers) { + send_cmd(ci->bi->nick, "PART %s :UNASSIGN from %s", ci->name, + u->nick); + } + ci->bi->chancount--; + ci->bi = NULL; +} + +/*************************************************************************/ + +/* Returns ban data associated with an user if it exists, allocates it + otherwise. */ + +static BanData *get_ban_data(Channel * c, User * u) +{ + char mask[BUFSIZE]; + BanData *bd, *next; + time_t now = time(NULL); + + if (!c || !u) + return NULL; + + snprintf(mask, sizeof(mask), "%s@%s", u->username, GetHost(u)); + + for (bd = c->bd; bd; bd = next) { + if (now - bd->last_use > BSKeepData) { + if (bd->next) + bd->next->prev = bd->prev; + if (bd->prev) + bd->prev->next = bd->next; + else + c->bd = bd->next; + if (bd->mask) + free(bd->mask); + next = bd->next; + free(bd); + continue; + } + if (!stricmp(bd->mask, mask)) { + bd->last_use = now; + return bd; + } + next = bd->next; + } + + /* If we fall here it is that we haven't found the record */ + bd = scalloc(sizeof(BanData), 1); + bd->mask = sstrdup(mask); + bd->last_use = now; + + bd->prev = NULL; + bd->next = c->bd; + if (bd->next) + bd->next->prev = bd; + c->bd = bd; + + return bd; +} + +/*************************************************************************/ + +/* Returns BotServ data associated with an user on a given channel. + * Allocates it if necessary. + */ + +static UserData *get_user_data(Channel * c, User * u) +{ + struct c_userlist *user; + + if (!c || !u) + return NULL; + + for (user = c->users; user; user = user->next) { + if (user->user == u) { + if (user->ud) { + time_t now = time(NULL); + + /* Checks whether data is obsolete */ + if (now - user->ud->last_use > BSKeepData) { + if (user->ud->lastline) + free(user->ud->lastline); + /* We should not free and realloc, but reset to 0 + instead. */ + memset(user->ud, 0, sizeof(UserData)); + user->ud->last_use = now; + } + + return user->ud; + } else { + user->ud = scalloc(sizeof(UserData), 1); + user->ud->last_use = time(NULL); + return user->ud; + } + } + } + + return NULL; +} + +/*************************************************************************/ + +/* Makes the bot join a channel and op himself. */ + +void bot_join(ChannelInfo * ci) +{ + int i; + + if (!ci || !ci->c || !ci->bi) + return; + + if (BSSmartJoin) { + /* We check for bans */ + int count = ci->c->bancount; + if (count) { + char botmask[BUFSIZE]; + char **bans = scalloc(sizeof(char *) * count, 1); + char *av[3]; + + memcpy(bans, ci->c->bans, sizeof(char *) * count); + snprintf(botmask, sizeof(botmask), "%s!%s@%s", ci->bi->nick, + ci->bi->user, ci->bi->host); + + av[0] = ci->c->name; + av[1] = sstrdup("-b"); + for (i = 0; i < count; i++) { + if (match_wild_nocase(ci->c->bans[i], botmask)) { + send_mode(ci->bi->nick, ci->name, "%s", bans[i]); + av[2] = sstrdup(bans[i]); + do_cmode(ci->bi->nick, 3, av); + free(av[2]); + } + } + free(av[1]); + free(bans); + } + + /* Should we be invited? */ + if ((ci->c->mode & CMODE_i) + || (ci->c->limit && ci->c->usercount >= ci->c->limit)) + send_cmd(NULL, "NOTICE @%s :%s invited %s into the channel.", + ci->c->name, ci->bi->nick, ci->bi->nick); + } +#ifdef IRC_BAHAMUT + send_cmd(ci->bi->nick, "SJOIN %ld %s", ci->c->creation_time, + ci->c->name); +#elif defined(IRC_HYBRID) + send_cmd(NULL, "SJOIN %ld %s + :%s", time(NULL), ci->c->name, + ci->bi->nick); +#else + send_cmd(ci->bi->nick, "JOIN %s", ci->c->name); +#endif + +#if defined(IRC_UNREAL) || defined (IRC_VIAGRA) + send_mode(ci->bi->nick, ci->c->name, "+ao %s %s", ci->bi->nick, + ci->bi->nick); +#elif defined(IRC_PTLINK) + /* PTLinks requieres an IRCop to u-line changes, so use ChanServ */ + send_mode(s_ChanServ, ci->c->name, "+ao %s %s", ci->bi->nick, + ci->bi->nick); +#else + send_mode(ci->bi->nick, ci->c->name, "+o %s", ci->bi->nick); +#endif +} + +/*************************************************************************/ + +/ |
