anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

bs_bot.cpp (10085B)

      1 /* BotServ core functions
      2  *
      3  * (C) 2003-2022 Anope Team
      4  * Contact us at team@anope.org
      5  *
      6  * Please read COPYING and README for further details.
      7  *
      8  * Based on the original code of Epona by Lara.
      9  * Based on the original code of Services by Andy Church.
     10  */
     11 
     12 #include "module.h"
     13 
     14 class CommandBSBot : public Command
     15 {
     16  private:
     17 	void DoAdd(CommandSource &source, const std::vector<Anope::string> &params)
     18 	{
     19 		const Anope::string &nick = params[1];
     20 		const Anope::string &user = params[2];
     21 		const Anope::string &host = params[3];
     22 		const Anope::string &real = params[4];
     23 
     24 		if (BotInfo::Find(nick, true))
     25 		{
     26 			source.Reply(_("Bot \002%s\002 already exists."), nick.c_str());
     27 			return;
     28 		}
     29 
     30 		Configuration::Block *networkinfo = Config->GetBlock("networkinfo");
     31 
     32 		if (nick.length() > networkinfo->Get<unsigned>("nicklen"))
     33 		{
     34 			source.Reply(_("Bot nicks may only be %d characters long."), networkinfo->Get<unsigned>("nicklen"));
     35 			return;
     36 		}
     37 
     38 		if (user.length() > networkinfo->Get<unsigned>("userlen"))
     39 		{
     40 			source.Reply(_("Bot idents may only be %d characters long."), networkinfo->Get<unsigned>("userlen"));
     41 			return;
     42 		}
     43 
     44 		if (host.length() > networkinfo->Get<unsigned>("hostlen"))
     45 		{
     46 			source.Reply(_("Bot hosts may only be %d characters long."), networkinfo->Get<unsigned>("hostlen"));
     47 			return;
     48 		}
     49 
     50 		if (!IRCD->IsNickValid(nick))
     51 		{
     52 			source.Reply(_("Bot nicks may only contain valid nick characters."));
     53 			return;
     54 		}
     55 
     56 		if (!IRCD->IsIdentValid(user))
     57 		{
     58 			source.Reply(_("Bot idents may only contain valid ident characters."));
     59 			return;
     60 		}
     61 
     62 		if (!IRCD->IsHostValid(host))
     63 		{
     64 			source.Reply(_("Bot hosts may only contain valid host characters."));
     65 			return;
     66 		}
     67 
     68 		/* We check whether the nick is registered, and inform the user
     69 		* if so. You need to drop the nick manually before you can use
     70 		* it as a bot nick from now on -GD
     71 		*/
     72 		if (NickAlias::Find(nick))
     73 		{
     74 			source.Reply(NICK_ALREADY_REGISTERED, nick.c_str());
     75 			return;
     76 		}
     77 
     78 		User *u = User::Find(nick, true);
     79 		if (u)
     80 		{
     81 			source.Reply(_("Nick \002%s\002 is currently in use."), u->nick.c_str());
     82 			return;
     83 		}
     84 
     85 		BotInfo *bi = new BotInfo(nick, user, host, real);
     86 
     87 		Log(LOG_ADMIN, source, this) << "ADD " << bi->GetMask() << " " << bi->realname;
     88 
     89 		source.Reply(_("%s!%s@%s (%s) added to the bot list."), bi->nick.c_str(), bi->GetIdent().c_str(), bi->host.c_str(), bi->realname.c_str());
     90 
     91 		FOREACH_MOD(OnBotCreate, (bi));
     92 		return;
     93 	}
     94 
     95 	void DoChange(CommandSource &source, const std::vector<Anope::string> &params)
     96 	{
     97 		const Anope::string &oldnick = params[1];
     98 		const Anope::string &nick = params.size() > 2 ? params[2] : "";
     99 		const Anope::string &user = params.size() > 3 ? params[3] : "";
    100 		const Anope::string &host = params.size() > 4 ? params[4] : "";
    101 		const Anope::string &real = params.size() > 5 ? params[5] : "";
    102 
    103 		if (oldnick.empty() || nick.empty())
    104 		{
    105 			this->OnSyntaxError(source, "CHANGE");
    106 			return;
    107 		}
    108 
    109 		BotInfo *bi = BotInfo::Find(oldnick, true);
    110 		if (!bi)
    111 		{
    112 			source.Reply(BOT_DOES_NOT_EXIST, oldnick.c_str());
    113 			return;
    114 		}
    115 
    116 		if (bi->conf)
    117 		{
    118 			source.Reply(_("Bot %s is not changeable."), bi->nick.c_str());
    119 			return;
    120 		}
    121 
    122 		Configuration::Block *networkinfo = Config->GetBlock("networkinfo");
    123 
    124 		if (nick.length() > networkinfo->Get<unsigned>("nicklen"))
    125 		{
    126 			source.Reply(_("Bot nicks may only be %d characters long."), networkinfo->Get<unsigned>("nicklen"));
    127 			return;
    128 		}
    129 
    130 		if (user.length() > networkinfo->Get<unsigned>("userlen"))
    131 		{
    132 			source.Reply(_("Bot idents may only be %d characters long."), networkinfo->Get<unsigned>("userlen"));
    133 			return;
    134 		}
    135 
    136 		if (host.length() > networkinfo->Get<unsigned>("hostlen"))
    137 		{
    138 			source.Reply(_("Bot hosts may only be %d characters long."), networkinfo->Get<unsigned>("hostlen"));
    139 			return;
    140 		}
    141 
    142 		/* Checks whether there *are* changes.
    143 		* Case sensitive because we may want to change just the case.
    144 		* And we must finally check that the nick is not already
    145 		* taken by another bot.
    146 		*/
    147 		if (nick.equals_cs(bi->nick) && (!user.empty() ? user.equals_cs(bi->GetIdent()) : 1) && (!host.empty() ? host.equals_cs(bi->host) : 1) && (!real.empty() ? real.equals_cs(bi->realname) : 1))
    148 		{
    149 			source.Reply(_("The old information is the same as the new information specified."));
    150 			return;
    151 		}
    152 
    153 		if (!IRCD->IsNickValid(nick))
    154 		{
    155 			source.Reply(_("Bot nicks may only contain valid nick characters."));
    156 			return;
    157 		}
    158 
    159 		if (!user.empty() && !IRCD->IsIdentValid(user))
    160 		{
    161 			source.Reply(_("Bot idents may only contain valid ident characters."));
    162 			return;
    163 		}
    164 
    165 		if (!host.empty() && !IRCD->IsHostValid(host))
    166 		{
    167 			source.Reply(_("Bot hosts may only contain valid host characters."));
    168 			return;
    169 		}
    170 
    171 		if (!nick.equals_ci(bi->nick))
    172 		{
    173 			if (BotInfo::Find(nick, true))
    174 			{
    175 				source.Reply(_("Bot \002%s\002 already exists."), nick.c_str());
    176 				return;
    177 			}
    178 
    179 			if (User::Find(nick, true))
    180 			{
    181 				source.Reply(_("Nick \002%s\002 is currently in use."), nick.c_str());
    182 				return;
    183 			}
    184 		}
    185 
    186 		if (!nick.equals_ci(bi->nick))
    187 		{
    188 			/* We check whether the nick is registered, and inform the user
    189 			* if so. You need to drop the nick manually before you can use
    190 			* it as a bot nick from now on -GD
    191 			*/
    192 			if (NickAlias::Find(nick))
    193 			{
    194 				source.Reply(NICK_ALREADY_REGISTERED, nick.c_str());
    195 				return;
    196 			}
    197 
    198 			/* The new nick is really different, so we remove the Q line for the old nick. */
    199 			XLine x_del(bi->nick);
    200 			IRCD->SendSQLineDel(&x_del);
    201 
    202 			/* Add a Q line for the new nick */
    203 			XLine x(nick, "Reserved for services");
    204 			IRCD->SendSQLine(NULL, &x);
    205 		}
    206 
    207 		if (!user.empty())
    208 		{
    209 			IRCD->SendQuit(bi, "Quit: Be right back");
    210 			bi->introduced = false;
    211 		}
    212 		else
    213 			IRCD->SendNickChange(bi, nick);
    214 
    215 		if (!nick.equals_cs(bi->nick))
    216 			bi->SetNewNick(nick);
    217 
    218 		if (!user.empty() && !user.equals_cs(bi->GetIdent()))
    219 			bi->SetIdent(user);
    220 		if (!host.empty() && !host.equals_cs(bi->host))
    221 			bi->host = host;
    222 		if (!real.empty() && !real.equals_cs(bi->realname))
    223 			bi->realname = real;
    224 
    225 		if (!user.empty())
    226 			bi->OnKill();
    227 
    228 		source.Reply(_("Bot \002%s\002 has been changed to %s!%s@%s (%s)."), oldnick.c_str(), bi->nick.c_str(), bi->GetIdent().c_str(), bi->host.c_str(), bi->realname.c_str());
    229 		Log(LOG_ADMIN, source, this) << "CHANGE " << oldnick << " to " << bi->GetMask() << " " << bi->realname;
    230 
    231 		FOREACH_MOD(OnBotChange, (bi));
    232 		return;
    233 	}
    234 
    235 	void DoDel(CommandSource &source, const std::vector<Anope::string> &params)
    236 	{
    237 		const Anope::string &nick = params[1];
    238 
    239 		if (nick.empty())
    240 		{
    241 			this->OnSyntaxError(source, "DEL");
    242 			return;
    243 		}
    244 
    245 		BotInfo *bi = BotInfo::Find(nick, true);
    246 		if (!bi)
    247 		{
    248 			source.Reply(BOT_DOES_NOT_EXIST, nick.c_str());
    249 			return;
    250 		}
    251 
    252 		if (bi->conf)
    253 		{
    254 			source.Reply(_("Bot %s is not deletable."), bi->nick.c_str());
    255 			return;
    256 		}
    257 
    258 		FOREACH_MOD(OnBotDelete, (bi));
    259 
    260 		Log(LOG_ADMIN, source, this) << "DEL " << bi->nick;
    261 
    262 		source.Reply(_("Bot \002%s\002 has been deleted."), nick.c_str());
    263 		delete bi;
    264 		return;
    265 	}
    266  public:
    267 	CommandBSBot(Module *creator) : Command(creator, "botserv/bot", 1, 6)
    268 	{
    269 		this->SetDesc(_("Maintains network bot list"));
    270 		this->SetSyntax(_("\002ADD \037nick\037 \037user\037 \037host\037 \037real\037\002"));
    271 		this->SetSyntax(_("\002CHANGE \037oldnick\037 \037newnick\037 [\037user\037 [\037host\037 [\037real\037]]]\002"));
    272 		this->SetSyntax(_("\002DEL \037nick\037\002"));
    273 	}
    274 
    275 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
    276 	{
    277 		const Anope::string &cmd = params[0];
    278 
    279 		if (Anope::ReadOnly)
    280 		{
    281 			source.Reply(_("Sorry, bot modification is temporarily disabled."));
    282 			return;
    283 		}
    284 
    285 		if (cmd.equals_ci("ADD"))
    286 		{
    287 			// ADD nick user host real - 5
    288 			if (!source.HasCommand("botserv/bot/add"))
    289 			{
    290 				source.Reply(ACCESS_DENIED);
    291 				return;
    292 			}
    293 
    294 			if (params.size() < 5)
    295 			{
    296 				this->OnSyntaxError(source, "ADD");
    297 				return;
    298 			}
    299 
    300 			std::vector<Anope::string> tempparams = params;
    301 			// ADD takes less params than CHANGE, so we need to take 6 if given and append it with a space to 5.
    302 			if (tempparams.size() >= 6)
    303 				tempparams[4] = tempparams[4] + " " + tempparams[5];
    304 
    305 			return this->DoAdd(source, tempparams);
    306 		}
    307 		else if (cmd.equals_ci("CHANGE"))
    308 		{
    309 			// CHANGE oldn newn user host real - 6
    310 			// but only oldn and newn are required
    311 			if (!source.HasCommand("botserv/bot/change"))
    312 			{
    313 				source.Reply(ACCESS_DENIED);
    314 				return;
    315 			}
    316 
    317 			if (params.size() < 3)
    318 			{
    319 				this->OnSyntaxError(source, "CHANGE");
    320 				return;
    321 			}
    322 
    323 			return this->DoChange(source, params);
    324 		}
    325 		else if (cmd.equals_ci("DEL"))
    326 		{
    327 			// DEL nick
    328 			if (!source.HasCommand("botserv/bot/del"))
    329 			{
    330 				source.Reply(ACCESS_DENIED);
    331 				return;
    332 			}
    333 
    334 			if (params.size() < 1)
    335 			{
    336 				this->OnSyntaxError(source, "DEL");
    337 				return;
    338 			}
    339 
    340 			return this->DoDel(source, params);
    341 		}
    342 		else
    343 			this->OnSyntaxError(source, "");
    344 
    345 		return;
    346 	}
    347 
    348 	bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
    349 	{
    350 		this->SendSyntax(source);
    351 		source.Reply(" ");
    352 		source.Reply(_("Allows Services Operators to create, modify, and delete\n"
    353 				"bots that users will be able to use on their own\n"
    354 				"channels.\n"
    355 				" \n"
    356 				"\002BOT ADD\002 adds a bot with the given nickname, username,\n"
    357 				"hostname and realname. Since no integrity checks are done\n"
    358 				"for these settings, be really careful.\n"
    359 				" \n"
    360 				"\002BOT CHANGE\002 allows you to change the nickname, username, hostname\n"
    361 				"or realname of a bot without deleting it (and\n"
    362 				"all the data associated with it).\n"
    363 				" \n"
    364 				"\002BOT DEL\002 removes the given bot from the bot list.\n"
    365 				" \n"
    366 				"\002Note\002: You cannot create a bot with a nick that is\n"
    367 				"currently registered. If an unregistered user is currently\n"
    368 				"using the nick, they will be killed."));
    369 		return true;
    370 	}
    371 };
    372 
    373 class BSBot : public Module
    374 {
    375 	CommandBSBot commandbsbot;
    376 
    377  public:
    378 	BSBot(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
    379 		commandbsbot(this)
    380 	{
    381 
    382 	}
    383 };
    384 
    385 MODULE_INIT(BSBot)