bs_bot.cpp

Go to the documentation of this file.
00001 /* BotServ core functions
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  */
00011 
00012 /*************************************************************************/
00013 
00014 #include "module.h"
00015 
00016 class CommandBSBot : public Command
00017 {
00018  private:
00019         void DoAdd(CommandSource &source, const std::vector<Anope::string> &params)
00020         {
00021                 const Anope::string &nick = params[1];
00022                 const Anope::string &user = params[2];
00023                 const Anope::string &host = params[3];
00024                 const Anope::string &real = params[4];
00025 
00026                 if (BotInfo::Find(nick, true))
00027                 {
00028                         source.Reply(_("Bot \002%s\002 already exists."), nick.c_str());
00029                         return;
00030                 }
00031 
00032                 if (nick.length() > Config->NickLen)
00033                 {
00034                         source.Reply(_("Bot nicks may only be %d characters long."), Config->NickLen);
00035                         return;
00036                 }
00037 
00038                 if (user.length() > Config->UserLen)
00039                 {
00040                         source.Reply(_("Bot idents may only be %d characters long."), Config->UserLen);
00041                         return;
00042                 }
00043 
00044                 if (host.length() > Config->HostLen)
00045                 {
00046                         source.Reply(_("Bot hosts may only be %d characters long."), Config->HostLen);
00047                         return;
00048                 }
00049 
00050                 if (!IRCD->IsNickValid(nick))
00051                 {
00052                         source.Reply(_("Bot nicks may only contain valid nick characters."));
00053                         return;
00054                 }
00055 
00056                 if (!IRCD->IsIdentValid(user))
00057                 {
00058                         source.Reply(_("Bot idents may only contain valid ident characters."));
00059                         return;
00060                 }
00061 
00062                 if (!IRCD->IsHostValid(host))
00063                 {
00064                         source.Reply(_("Bot hosts may only contain valid host characters."));
00065                         return;
00066                 }
00067 
00068                 /* We check whether the nick is registered, and inform the user
00069                 * if so. You need to drop the nick manually before you can use
00070                 * it as a bot nick from now on -GD
00071                 */
00072                 if (NickAlias::Find(nick))
00073                 {
00074                         source.Reply(NICK_ALREADY_REGISTERED, nick.c_str());
00075                         return;
00076                 }
00077 
00078                 BotInfo *bi = new BotInfo(nick, user, host, real);
00079 
00080                 Log(LOG_ADMIN, source, this) << "ADD " << bi->GetMask() << " " << bi->realname;
00081 
00082                 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());
00083 
00084                 FOREACH_MOD(I_OnBotCreate, OnBotCreate(bi));
00085                 return;
00086         }
00087 
00088         void DoChange(CommandSource &source, const std::vector<Anope::string> &params)
00089         {
00090                 const Anope::string &oldnick = params[1];
00091                 const Anope::string &nick = params.size() > 2 ? params[2] : "";
00092                 const Anope::string &user = params.size() > 3 ? params[3] : "";
00093                 const Anope::string &host = params.size() > 4 ? params[4] : "";
00094                 const Anope::string &real = params.size() > 5 ? params[5] : "";
00095 
00096                 if (oldnick.empty() || nick.empty())
00097                 {
00098                         this->OnSyntaxError(source, "CHANGE");
00099                         return;
00100                 }
00101 
00102                 BotInfo *bi = BotInfo::Find(oldnick, true);
00103                 if (!bi)
00104                 {
00105                         source.Reply(BOT_DOES_NOT_EXIST, oldnick.c_str());
00106                         return;
00107                 }
00108 
00109                 if (bi->conf)
00110                 {
00111                         source.Reply(_("Bot %s is not changeable."), bi->nick.c_str());
00112                         return;
00113                 }
00114 
00115                 if (nick.length() > Config->NickLen)
00116                 {
00117                         source.Reply(_("Bot nicks may only be %d characters long."), Config->NickLen);
00118                         return;
00119                 }
00120 
00121                 if (!user.empty() && user.length() > Config->UserLen)
00122                 {
00123                         source.Reply(_("Bot idents may only be %d characters long."), Config->UserLen);
00124                         return;
00125                 }
00126 
00127                 if (!host.empty() && host.length() > Config->HostLen)
00128                 {
00129                         source.Reply(_("Bot hosts may only be %d characters long."), Config->HostLen);
00130                         return;
00131                 }
00132 
00133                 /* Checks whether there *are* changes.
00134                 * Case sensitive because we may want to change just the case.
00135                 * And we must finally check that the nick is not already
00136                 * taken by another bot.
00137                 */
00138                 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))
00139                 {
00140                         source.Reply(_("Old info is equal to the new one."));
00141                         return;
00142                 }
00143 
00144                 if (!IRCD->IsNickValid(nick))
00145                 {
00146                         source.Reply(_("Bot nicks may only contain valid nick characters."));
00147                         return;
00148                 }
00149 
00150                 if (!user.empty() && !IRCD->IsIdentValid(user))
00151                 {
00152                         source.Reply(_("Bot idents may only contain valid ident characters."));
00153                         return;
00154                 }
00155 
00156                 if (!host.empty() && !IRCD->IsHostValid(host))
00157                 {
00158                         source.Reply(_("Bot hosts may only contain valid host characters."));
00159                         return;
00160                 }
00161 
00162                 if (!nick.equals_ci(bi->nick) && BotInfo::Find(nick, true))
00163                 {
00164                         source.Reply(_("Bot \002%s\002 already exists."), nick.c_str());
00165                         return;
00166                 }
00167 
00168                 if (!nick.equals_ci(bi->nick))
00169                 {
00170                         /* We check whether the nick is registered, and inform the user
00171                         * if so. You need to drop the nick manually before you can use
00172                         * it as a bot nick from now on -GD
00173                         */
00174                         if (NickAlias::Find(nick))
00175                         {
00176                                 source.Reply(NICK_ALREADY_REGISTERED, nick.c_str());
00177                                 return;
00178                         }
00179 
00180                         /* The new nick is really different, so we remove the Q line for the old nick. */
00181                         XLine x_del(bi->nick);
00182                         IRCD->SendSQLineDel(&x_del);
00183 
00184                         /* Add a Q line for the new nick */
00185                         XLine x(nick, "Reserved for services");
00186                         IRCD->SendSQLine(NULL, &x);
00187                 }
00188 
00189                 if (!user.empty())
00190                         IRCD->SendQuit(bi, "Quit: Be right back");
00191                 else
00192                         IRCD->SendNickChange(bi, nick);
00193 
00194                 if (!nick.equals_cs(bi->nick))
00195                         bi->SetNewNick(nick);
00196 
00197                 if (!user.empty() && !user.equals_cs(bi->GetIdent()))
00198                         bi->SetIdent(user);
00199                 if (!host.empty() && !host.equals_cs(bi->host))
00200                         bi->host = host;
00201                 if (!real.empty() && !real.equals_cs(bi->realname))
00202                         bi->realname = real;
00203 
00204                 if (!user.empty())
00205                 {
00206                         IRCD->SendClientIntroduction(bi);
00207                         bi->RejoinAll();
00208                 }
00209 
00210                 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());
00211                 Log(LOG_ADMIN, source, this) << "CHANGE " << oldnick << " to " << bi->GetMask() << " " << bi->realname;
00212 
00213                 FOREACH_MOD(I_OnBotChange, OnBotChange(bi));
00214                 return;
00215         }
00216 
00217         void DoDel(CommandSource &source, const std::vector<Anope::string> &params)
00218         {
00219                 const Anope::string &nick = params[1];
00220 
00221                 if (nick.empty())
00222                 {
00223                         this->OnSyntaxError(source, "DEL");
00224                         return;
00225                 }
00226 
00227                 BotInfo *bi = BotInfo::Find(nick, true);
00228                 if (!bi)
00229                 {
00230                         source.Reply(BOT_DOES_NOT_EXIST, nick.c_str());
00231                         return;
00232                 }
00233 
00234                 if (bi->conf)
00235                 {
00236                         source.Reply(_("Bot %s is not deletable."), bi->nick.c_str());
00237                         return;
00238                 }
00239 
00240                 FOREACH_MOD(I_OnBotDelete, OnBotDelete(bi));
00241 
00242                 Log(LOG_ADMIN, source, this) << "DEL " << bi->nick;
00243 
00244                 source.Reply(_("Bot \002%s\002 has been deleted."), nick.c_str());
00245                 delete bi;
00246                 return;
00247         }
00248  public:
00249         CommandBSBot(Module *creator) : Command(creator, "botserv/bot", 1, 6)
00250         {
00251                 this->SetDesc(_("Maintains network bot list"));
00252                 this->SetSyntax(_("\002ADD \037nick\037 \037user\037 \037host\037 \037real\037\002"));
00253                 this->SetSyntax(_("\002CHANGE \037oldnick\037 \037newnick\037 [\037user\037 [\037host\037 [\037real\037]]]\002"));
00254                 this->SetSyntax(_("\002DEL \037nick\037\002"));
00255         }
00256 
00257         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00258         {
00259                 const Anope::string &cmd = params[0];
00260 
00261                 if (Anope::ReadOnly)
00262                 {
00263                         source.Reply(_("Sorry, bot modification is temporarily disabled."));
00264                         return;
00265                 }
00266 
00267                 if (cmd.equals_ci("ADD"))
00268                 {
00269                         // ADD nick user host real - 5
00270                         if (!source.HasCommand("botserv/bot/add"))
00271                         {
00272                                 source.Reply(ACCESS_DENIED);
00273                                 return;
00274                         }
00275 
00276                         if (params.size() < 5)
00277                         {
00278                                 this->OnSyntaxError(source, "ADD");
00279                                 return;
00280                         }
00281 
00282                         std::vector<Anope::string> tempparams = params;
00283                         // ADD takes less params than CHANGE, so we need to take 6 if given and append it with a space to 5.
00284                         if (tempparams.size() >= 6)
00285                                 tempparams[4] = tempparams[4] + " " + tempparams[5];
00286 
00287                         return this->DoAdd(source, tempparams);
00288                 }
00289                 else if (cmd.equals_ci("CHANGE"))
00290                 {
00291                         // CHANGE oldn newn user host real - 6
00292                         // but only oldn and newn are required
00293                         if (!source.HasCommand("botserv/bot/change"))
00294                         {
00295                                 source.Reply(ACCESS_DENIED);
00296                                 return;
00297                         }
00298 
00299                         if (params.size() < 3)
00300                         {
00301                                 this->OnSyntaxError(source, "CHANGE");
00302                                 return;
00303                         }
00304 
00305                         return this->DoChange(source, params);
00306                 }
00307                 else if (cmd.equals_ci("DEL"))
00308                 {
00309                         // DEL nick
00310                         if (!source.HasCommand("botserv/bot/del"))
00311                         {
00312                                 source.Reply(ACCESS_DENIED);
00313                                 return;
00314                         }
00315 
00316                         if (params.size() < 1)
00317                         {
00318                                 this->OnSyntaxError(source, "DEL");
00319                                 return;
00320                         }
00321 
00322                         return this->DoDel(source, params);
00323                 }
00324                 else
00325                         this->OnSyntaxError(source, "");
00326 
00327                 return;
00328         }
00329 
00330         bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00331         {
00332                 this->SendSyntax(source);
00333                 source.Reply(" ");
00334                 source.Reply(_("Allows Services Operators to create, modify, and delete\n"
00335                                 "bots that users will be able to use on their own\n"
00336                                 "channels.\n"
00337                                 " \n"
00338                                 "\002BOT ADD\002 adds a bot with the given nickname, username,\n"
00339                                 "hostname and realname. Since no integrity checks are done\n"
00340                                 "for these settings, be really careful.\n"
00341                                 "\002BOT CHANGE\002 allows to change nickname, username, hostname\n"
00342                                 "or realname of a bot without actually delete it (and all\n"
00343                                 "the data associated with it).\n"
00344                                 "\002BOT DEL\002 removes the given bot from the bot list.\n"
00345                                 " \n"
00346                                 "\002Note\002: you cannot create a bot that has a nick that is\n"
00347                                 "currently registered. If an unregistered user is currently\n"
00348                                 "using the nick, they will be killed."));
00349                 return true;
00350         }
00351 };
00352 
00353 class BSBot : public Module
00354 {
00355         CommandBSBot commandbsbot;
00356 
00357  public:
00358         BSBot(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE),
00359                 commandbsbot(this)
00360         {
00361                 this->SetAuthor("Anope");
00362 
00363         }
00364 };
00365 
00366 MODULE_INIT(BSBot)