mirror of
https://github.com/anope/anope.git
synced 2026-06-27 03:36:37 +02:00
7a92feb474
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@2212 5417fbe8-f217-4b02-8779-1006273d7864
466 lines
10 KiB
C
466 lines
10 KiB
C
/* BotServ core functions
|
|
*
|
|
* (C) 2003-2009 Anope Team
|
|
* Contact us at team@anope.org
|
|
*
|
|
* Please read COPYING and README for further details.
|
|
*
|
|
* Based on the original code of Epona by Lara.
|
|
* Based on the original code of Services by Andy Church.
|
|
*
|
|
* $Id$
|
|
*
|
|
*/
|
|
/*************************************************************************/
|
|
|
|
#include "module.h"
|
|
|
|
void myBotServHelp(User * u);
|
|
|
|
class CommandBSBot : public Command
|
|
{
|
|
private:
|
|
CommandReturn DoAdd(User *u, std::vector<std::string> ¶ms)
|
|
{
|
|
const char *nick = params[1].c_str();
|
|
const char *user = params.size() > 2 ? params[2].c_str() : NULL;
|
|
const char *host = params.size() > 3 ? params[3].c_str() : NULL;
|
|
const char *real = params.size() > 4 ? params[4].c_str() : NULL;
|
|
const char *ch = NULL;
|
|
BotInfo *bi;
|
|
|
|
if (!nick || !user || !host || !real)
|
|
{
|
|
this->OnSyntaxError(u);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (findbot(nick))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_BOT_ALREADY_EXISTS, nick);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (strlen(nick) > NickLen)
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_BAD_NICK);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (strlen(user) >= USERMAX)
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_LONG_IDENT, USERMAX - 1);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (strlen(user) > HOSTMAX)
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_LONG_HOST, HOSTMAX);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
/* Check the nick is valid re RFC 2812 */
|
|
if (isdigit(nick[0]) || nick[0] == '-')
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_BAD_NICK);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
for (ch = nick; *ch && (ch - nick) < NICKMAX; ch++)
|
|
{
|
|
if (!isvalidnick(*ch))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_BAD_NICK);
|
|
return MOD_CONT;
|
|
}
|
|
}
|
|
|
|
/* check for hardcored ircd forbidden nicks */
|
|
if (!ircdproto->IsNickValid(nick))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_BAD_NICK);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
/* Check the host is valid re RFC 2812 */
|
|
if (!isValidHost(host, 3))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_BAD_HOST);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
for (ch = user; *ch && (ch - user) < USERMAX; ch++)
|
|
{
|
|
if (!isalnum(*ch))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_LONG_IDENT, USERMAX - 1);
|
|
return MOD_CONT;
|
|
}
|
|
}
|
|
|
|
|
|
/* We check whether the nick is registered, and inform the user
|
|
* if so. You need to drop the nick manually before you can use
|
|
* it as a bot nick from now on -GD
|
|
*/
|
|
if (findnick(nick))
|
|
{
|
|
notice_lang(s_BotServ, u, NICK_ALREADY_REGISTERED, nick);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
bi = new BotInfo(nick);
|
|
if (!bi)
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_BOT_CREATION_FAILED);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
bi->user = sstrdup(user);
|
|
bi->host = sstrdup(host);
|
|
bi->real = sstrdup(real);
|
|
bi->created = time(NULL);
|
|
bi->chancount = 0;
|
|
|
|
/* We check whether user with this nick is online, and kill it if so */
|
|
EnforceQlinedNick(nick, s_BotServ);
|
|
|
|
/* We make the bot online, ready to serve */
|
|
ircdproto->SendClientIntroduction(bi->nick, bi->user, bi->host, bi->real,
|
|
ircd->pseudoclient_mode, bi->uid.c_str());
|
|
|
|
notice_lang(s_BotServ, u, BOT_BOT_ADDED, bi->nick, bi->user,
|
|
bi->host, bi->real);
|
|
|
|
send_event(EVENT_BOT_CREATE, 1, bi->nick);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
CommandReturn DoChange(User *u, std::vector<std::string> ¶ms)
|
|
{
|
|
const char *oldnick = params[1].c_str();
|
|
const char *nick = params.size() > 2 ? params[2].c_str() : NULL;
|
|
const char *user = params.size() > 3 ? params[3].c_str() : NULL;
|
|
const char *host = params.size() > 4 ? params[4].c_str() : NULL;
|
|
const char *real = params.size() > 5 ? params[5].c_str() : NULL;
|
|
const char *ch = NULL;
|
|
BotInfo *bi;
|
|
|
|
if (!oldnick || !nick)
|
|
{
|
|
this->OnSyntaxError(u);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (!(bi = findbot(oldnick)))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_DOES_NOT_EXIST, oldnick);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (stricmp(oldnick, nick) && nickIsServices(oldnick, 0))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_DOES_NOT_EXIST, oldnick);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (strlen(nick) > NickLen)
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_BAD_NICK);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (user && strlen(user) >= USERMAX)
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_LONG_IDENT, USERMAX - 1);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (host && strlen(host) > HOSTMAX)
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_LONG_HOST, HOSTMAX);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (stricmp(oldnick, nick) && nickIsServices(nick, 0))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_DOES_NOT_EXIST, oldnick);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
/* Checks whether there *are* changes.
|
|
* Case sensitive because we may want to change just the case.
|
|
* And we must finally check that the nick is not already
|
|
* taken by another bot.
|
|
*/
|
|
if (!strcmp(bi->nick, nick)
|
|
&& ((user) ? !strcmp(bi->user, user) : 1)
|
|
&& ((host) ? !strcmp(bi->host, host) : 1)
|
|
&& ((real) ? !strcmp(bi->real, real) : 1))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_BOT_ANY_CHANGES);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
/* Check the nick is valid re RFC 2812 */
|
|
if (isdigit(nick[0]) || nick[0] == '-')
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_BAD_NICK);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
for (ch = nick; *ch && (ch - nick) < NICKMAX; ch++)
|
|
{
|
|
if (!isvalidnick(*ch))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_BAD_NICK);
|
|
return MOD_CONT;
|
|
}
|
|
}
|
|
|
|
/* check for hardcored ircd forbidden nicks */
|
|
if (!ircdproto->IsNickValid(nick))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_BAD_NICK);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (host && !isValidHost(host, 3))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_BAD_HOST);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (user)
|
|
{
|
|
for (ch = user; *ch && (ch - user) < USERMAX; ch++)
|
|
{
|
|
if (!isalnum(*ch))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_LONG_IDENT, USERMAX - 1);
|
|
return MOD_CONT;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (stricmp(bi->nick, nick) && findbot(nick))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_BOT_ALREADY_EXISTS, nick);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (stricmp(bi->nick, nick))
|
|
{
|
|
/* We check whether the nick is registered, and inform the user
|
|
* if so. You need to drop the nick manually before you can use
|
|
* it as a bot nick from now on -GD
|
|
*/
|
|
if (findnick(nick))
|
|
{
|
|
notice_lang(s_BotServ, u, NICK_ALREADY_REGISTERED, nick);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
/* The new nick is really different, so we remove the Q line for
|
|
the old nick. */
|
|
if (ircd->sqline)
|
|
{
|
|
ircdproto->SendSQLineDel(bi->nick);
|
|
}
|
|
|
|
/* We check whether user with this nick is online, and kill it if so */
|
|
EnforceQlinedNick(nick, s_BotServ);
|
|
}
|
|
|
|
if (user)
|
|
ircdproto->SendQuit(bi, "Quit: Be right back");
|
|
else {
|
|
ircdproto->SendChangeBotNick(bi, nick);
|
|
ircdproto->SendSQLine(bi->nick, "Reserved for services");
|
|
}
|
|
|
|
if (strcmp(nick, bi->nick))
|
|
bi->ChangeNick(nick);
|
|
|
|
if (user && strcmp(user, bi->user))
|
|
{
|
|
delete [] bi->user;
|
|
bi->user = sstrdup(user);
|
|
}
|
|
if (host && strcmp(host, bi->host))
|
|
{
|
|
delete [] bi->host;
|
|
bi->host = sstrdup(host);
|
|
}
|
|
if (real && strcmp(real, bi->real))
|
|
{
|
|
delete [] bi->real;
|
|
bi->real = sstrdup(real);
|
|
}
|
|
|
|
if (user)
|
|
{
|
|
ircdproto->SendQuit(bi, "Quit: Be right back");
|
|
// This isn't the nicest way to do this, unfortunately.
|
|
bi->uid = ts6_uid_retrieve();
|
|
ircdproto->SendClientIntroduction(bi->nick, bi->user, bi->host, bi->real,
|
|
ircd->pseudoclient_mode, bi->uid.c_str());
|
|
bi->RejoinAll();
|
|
}
|
|
|
|
notice_lang(s_BotServ, u, BOT_BOT_CHANGED,
|
|
oldnick, bi->nick, bi->user, bi->host, bi->real);
|
|
|
|
send_event(EVENT_BOT_CHANGE, 1, bi->nick);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
CommandReturn DoDel(User *u, std::vector<std::string> ¶ms)
|
|
{
|
|
const char *nick = params[1].c_str();
|
|
BotInfo *bi;
|
|
|
|
if (!nick)
|
|
{
|
|
this->OnSyntaxError(u);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (!(bi = findbot(nick)))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_DOES_NOT_EXIST, nick);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (nickIsServices(nick, 0))
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_DOES_NOT_EXIST, nick);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
send_event(EVENT_BOT_DEL, 1, bi->nick);
|
|
|
|
ircdproto->SendQuit(bi, "Quit: Help! I'm being deleted by %s!", u->nick);
|
|
ircdproto->SendSQLineDel(bi->nick);
|
|
|
|
delete bi;
|
|
notice_lang(s_BotServ, u, BOT_BOT_DELETED, nick);
|
|
return MOD_CONT;
|
|
}
|
|
public:
|
|
CommandBSBot() : Command("BOT", 1, 6)
|
|
{
|
|
}
|
|
|
|
CommandReturn Execute(User *u, std::vector<std::string> ¶ms)
|
|
{
|
|
const char *cmd = params[0].c_str();
|
|
|
|
if (readonly)
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_BOT_READONLY);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (!stricmp(cmd, "ADD"))
|
|
{
|
|
// ADD nick user host real - 5
|
|
if (!u->nc->HasCommand("botserv/bot/add"))
|
|
{
|
|
notice_lang(s_BotServ, u, PERMISSION_DENIED);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (params.size() < 5)
|
|
{
|
|
this->OnSyntaxError(u);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
// ADD takes less params than CHANGE, so we need to take 6 if given and append it with a space to 5.
|
|
if (params.size() >= 6)
|
|
params[5] = params[5] + " " + params[6];
|
|
|
|
return this->DoAdd(u, params);
|
|
}
|
|
else if (!stricmp(cmd, "CHANGE"))
|
|
{
|
|
// CHANGE oldn newn user host real - 6
|
|
// but only oldn and newn are required
|
|
if (!u->nc->HasCommand("botserv/bot/change"))
|
|
{
|
|
notice_lang(s_BotServ, u, PERMISSION_DENIED);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (params.size() < 3)
|
|
{
|
|
this->OnSyntaxError(u);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
return this->DoChange(u, params);
|
|
}
|
|
else if (!stricmp(cmd, "DEL"))
|
|
{
|
|
// DEL nick
|
|
if (!u->nc->HasCommand("botserv/bot/del"))
|
|
{
|
|
notice_lang(s_BotServ, u, PERMISSION_DENIED);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (params.size() < 1)
|
|
{
|
|
this->OnSyntaxError(u);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
return this->DoDel(u, params);
|
|
}
|
|
else
|
|
this->OnSyntaxError(u);
|
|
|
|
return MOD_CONT;
|
|
}
|
|
|
|
bool OnHelp(User *u, const std::string &subcommand)
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_SERVADMIN_HELP_BOT);
|
|
return true;
|
|
}
|
|
|
|
void OnSyntaxError(User *u)
|
|
{
|
|
syntax_error(s_BotServ, u, "BOT", BOT_BOT_SYNTAX);
|
|
}
|
|
};
|
|
|
|
class BSBot : public Module
|
|
{
|
|
public:
|
|
BSBot(const std::string &modname, const std::string &creator) : Module(modname, creator)
|
|
{
|
|
this->SetAuthor("Anope");
|
|
this->SetVersion("$Id$");
|
|
this->SetType(CORE);
|
|
this->AddCommand(BOTSERV, new CommandBSBot(), MOD_UNIQUE);
|
|
|
|
this->SetBotHelp(myBotServHelp);
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Add the help response to Anopes /bs help output.
|
|
* @param u The user who is requesting help
|
|
**/
|
|
void myBotServHelp(User * u)
|
|
{
|
|
notice_lang(s_BotServ, u, BOT_HELP_CMD_BOT);
|
|
}
|
|
|
|
|
|
|
|
MODULE_INIT("bs_bot", BSBot)
|