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