00001
00002
00003
00004
00005
00006
00007
00008
00009
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> ¶ms)
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
00069
00070
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> ¶ms)
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
00134
00135
00136
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
00171
00172
00173
00174 if (NickAlias::Find(nick))
00175 {
00176 source.Reply(NICK_ALREADY_REGISTERED, nick.c_str());
00177 return;
00178 }
00179
00180
00181 XLine x_del(bi->nick);
00182 IRCD->SendSQLineDel(&x_del);
00183
00184
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> ¶ms)
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> ¶ms) 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
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
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
00292
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
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)