Anope IRC Services  Version 1.8
bs_bot.c
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  */
13 /*************************************************************************/
14 
15 #include "module.h"
16 
17 static int do_bot(User * u);
18 static int delbot(BotInfo * bi);
19 static void myBotServHelp(User * u);
20 static void change_bot_nick(BotInfo * bi, char *newnick);
21 
28 int AnopeInit(int argc, char **argv)
29 {
30  Command *c;
31 
32  moduleAddAuthor("Anope");
33  moduleAddVersion(VERSION_STRING);
35 
36  c = createCommand("BOT", do_bot, is_services_admin, -1, -1, -1,
37  BOT_SERVADMIN_HELP_BOT, BOT_SERVADMIN_HELP_BOT);
39 
41 
42  return MOD_CONT;
43 }
44 
48 void AnopeFini(void)
49 {
50 
51 }
52 
53 
54 
59 static void myBotServHelp(User * u)
60 {
61  if (is_services_admin(u)) {
62  notice_lang(s_BotServ, u, BOT_HELP_CMD_BOT);
63  }
64 }
65 
71 static int do_bot(User * u)
72 {
73  BotInfo *bi;
74  char *cmd = strtok(NULL, " ");
75  char *ch = NULL;
76 
77  if (!cmd)
78  syntax_error(s_BotServ, u, "BOT", BOT_BOT_SYNTAX);
79  else if (!stricmp(cmd, "ADD")) {
80  char *nick = strtok(NULL, " ");
81  char *user = strtok(NULL, " ");
82  char *host = strtok(NULL, " ");
83  char *real = strtok(NULL, "");
84 
85  if (!nick || !user || !host || !real)
86  syntax_error(s_BotServ, u, "BOT", BOT_BOT_SYNTAX);
87  else if (readonly)
88  notice_lang(s_BotServ, u, BOT_BOT_READONLY);
89  else if (findbot(nick))
90  notice_lang(s_BotServ, u, BOT_BOT_ALREADY_EXISTS, nick);
91  else if (strlen(nick) > NickLen)
92  notice_lang(s_BotServ, u, BOT_BAD_NICK);
93  else if (strlen(user) >= USERMAX)
94  notice_lang(s_BotServ, u, BOT_LONG_IDENT, USERMAX - 1);
95  else if (strlen(user) > HOSTMAX)
96  notice_lang(s_BotServ, u, BOT_LONG_HOST, HOSTMAX);
97  else {
98  NickAlias *na;
99 
103  if (isdigit(nick[0]) || nick[0] == '-') {
104  notice_lang(s_BotServ, u, BOT_BAD_NICK);
105  return MOD_CONT;
106  }
107  for (ch = nick; *ch && (ch - nick) < NICKMAX; ch++) {
108  if (!isvalidnick(*ch)) {
109  notice_lang(s_BotServ, u, BOT_BAD_NICK);
110  return MOD_CONT;
111  }
112  }
113 
114  /* check for hardcored ircd forbidden nicks */
115  if (!anope_valid_nick(nick)) {
116  notice_lang(s_BotServ, u, BOT_BAD_NICK);
117  return MOD_CONT;
118  }
119 
120  if (!isValidHost(host, 3)) {
121  notice_lang(s_BotServ, u, BOT_BAD_HOST);
122  return MOD_CONT;
123  }
124  for (ch = user; *ch && (ch - user) < USERMAX; ch++) {
125  if (!isalnum(*ch)) {
126  notice_lang(s_BotServ, u, BOT_BAD_IDENT, USERMAX - 1);
127  return MOD_CONT;
128  }
129  }
130 
135  /* Check whether it's a services client's nick and return if so - Certus */
136  /* use nickIsServices reduce the total number lines of code - TSL */
137 
138  if (nickIsServices(nick, 0)) {
139  notice_lang(s_BotServ, u, BOT_BOT_CREATION_FAILED);
140  return MOD_CONT;
141  }
142 
143  /* We check whether the nick is registered, and inform the user
144  * if so. You need to drop the nick manually before you can use
145  * it as a bot nick from now on -GD
146  */
147  if ((na = findnick(nick))) {
148  notice_lang(s_BotServ, u, NICK_ALREADY_REGISTERED, nick);
149  return MOD_CONT;
150  }
151 
152  bi = makebot(nick);
153  if (!bi) {
154  notice_lang(s_BotServ, u, BOT_BOT_CREATION_FAILED);
155  return MOD_CONT;
156  }
157 
158  bi->user = sstrdup(user);
159  bi->host = sstrdup(host);
160  bi->real = sstrdup(real);
161  bi->created = time(NULL);
162  bi->chancount = 0;
163 
164  /* We check whether user with this nick is online, and kill it if so */
166 
167  /* We make the bot online, ready to serve */
168  anope_cmd_bot_nick(bi->nick, bi->user, bi->host, bi->real,
170 
171  alog("%s: %s!%s@%s added bot %s!%s@%s (%s) to the bot list",
172  s_BotServ, u->nick, u->username, u->host, bi->nick, bi->user,
173  bi->host, bi->real);
174  notice_lang(s_BotServ, u, BOT_BOT_ADDED, bi->nick, bi->user,
175  bi->host, bi->real);
176 
178  }
179  } else if (!stricmp(cmd, "CHANGE")) {
180  char *oldnick = strtok(NULL, " ");
181  char *nick = strtok(NULL, " ");
182  char *user = strtok(NULL, " ");
183  char *host = strtok(NULL, " ");
184  char *real = strtok(NULL, "");
185 
186  if (!oldnick || !nick)
187  syntax_error(s_BotServ, u, "BOT", BOT_BOT_SYNTAX);
188  else if (readonly)
189  notice_lang(s_BotServ, u, BOT_BOT_READONLY);
190  else if (!(bi = findbot(oldnick)))
191  notice_lang(s_BotServ, u, BOT_DOES_NOT_EXIST, oldnick);
192  else if (strlen(nick) > NickLen)
193  notice_lang(s_BotServ, u, BOT_BAD_NICK);
194  else if (user && strlen(user) >= USERMAX)
195  notice_lang(s_BotServ, u, BOT_LONG_IDENT, USERMAX - 1);
196  else if (host && strlen(host) > HOSTMAX)
197  notice_lang(s_BotServ, u, BOT_LONG_HOST, HOSTMAX);
198  else {
199  NickAlias *na;
200 
201  /* Checks whether there *are* changes.
202  * Case sensitive because we may want to change just the case.
203  * And we must finally check that the nick is not already
204  * taken by another bot.
205  */
206  if (!strcmp(bi->nick, nick)
207  && ((user) ? !strcmp(bi->user, user) : 1)
208  && ((host) ? !strcmp(bi->host, host) : 1)
209  && ((real) ? !strcmp(bi->real, real) : 1)) {
210  notice_lang(s_BotServ, u, BOT_BOT_ANY_CHANGES);
211  return MOD_CONT;
212  }
213 
214  /* Check whether it's a services client's nick and return if so - Certus */
215  /* use nickIsServices() to reduce the number of lines of code - TSL */
216  if (nickIsServices(nick, 0)) {
217  notice_lang(s_BotServ, u, BOT_BOT_CREATION_FAILED);
218  return MOD_CONT;
219  }
220 
224  if (isdigit(nick[0]) || nick[0] == '-') {
225  notice_lang(s_BotServ, u, BOT_BAD_NICK);
226  return MOD_CONT;
227  }
228  for (ch = nick; *ch && (ch - nick) < NICKMAX; ch++) {
229  if (!isvalidnick(*ch)) {
230  notice_lang(s_BotServ, u, BOT_BAD_NICK);
231  return MOD_CONT;
232  }
233  }
234 
235  /* check for hardcored ircd forbidden nicks */
236  if (!anope_valid_nick(nick)) {
237  notice_lang(s_BotServ, u, BOT_BAD_NICK);
238  return MOD_CONT;
239  }
240 
241  if (host && !isValidHost(host, 3)) {
242  notice_lang(s_BotServ, u, BOT_BAD_HOST);
243  return MOD_CONT;
244  }
245 
246  if (user) {
247  for (ch = user; *ch && (ch - user) < USERMAX; ch++) {
248  if (!isalnum(*ch)) {
249  notice_lang(s_BotServ, u, BOT_BAD_IDENT, USERMAX - 1);
250  return MOD_CONT;
251  }
252  }
253  }
254 
255  if (stricmp(bi->nick, nick) && findbot(nick)) {
256  notice_lang(s_BotServ, u, BOT_BOT_ALREADY_EXISTS, nick);
257  return MOD_CONT;
258  }
259 
260  if (stricmp(bi->nick, nick)) {
261  /* We check whether the nick is registered, and inform the user
262  * if so. You need to drop the nick manually before you can use
263  * it as a bot nick from now on -GD
264  */
265  if ((na = findnick(nick))) {
266  notice_lang(s_BotServ, u, NICK_ALREADY_REGISTERED,
267  nick);
268  return MOD_CONT;
269  }
270 
271  /* The new nick is really different, so we remove the Q line for
272  the old nick. */
273  if (ircd->sqline) {
275  }
276 
277  /* We check whether user with this nick is online, and kill it if so */
279  }
280 
281  /* Send the QUIT before changing the bot internally, so proto mods (InspIRCD 1.2)
282  * can get the uid if needed (or other things )and send that - Adam
283  */
284  if (user)
285  anope_cmd_quit(bi->nick, "Quit: Be right back");
286 
287  if (strcmp(nick, bi->nick))
288  change_bot_nick(bi, nick);
289 
290  if (user && strcmp(user, bi->user)) {
291  free(bi->user);
292  bi->user = sstrdup(user);
293  }
294  if (host && strcmp(host, bi->host)) {
295  free(bi->host);
296  bi->host = sstrdup(host);
297  }
298  if (real && strcmp(real, bi->real)) {
299  free(bi->real);
300  bi->real = sstrdup(real);
301  }
302 
303  /* If only the nick changes, we just make the bot change his nick,
304  else we must make it quit and rejoin. We must not forget to set
305  the Q:Line either (it's otherwise set in anope_cmd_bot_nick) */
306  if (!user) {
307  anope_cmd_chg_nick(oldnick, bi->nick);
308  anope_cmd_sqline(bi->nick, "Reserved for services");
309  } else {
310  anope_cmd_bot_nick(bi->nick, bi->user, bi->host, bi->real,
312  bot_rejoin_all(bi);
313  }
314 
315  alog("%s: %s!%s@%s changed bot %s to: %s!%s@%s (%s)",
316  s_BotServ, u->nick, u->username, u->host, oldnick, bi->nick, bi->user,
317  bi->host, bi->real);
318  notice_lang(s_BotServ, u, BOT_BOT_CHANGED, oldnick, bi->nick,
319  bi->user, bi->host, bi->real);
320 
322  }
323  } else if (!stricmp(cmd, "DEL")) {
324  char *nick = strtok(NULL, " ");
325 
326  if (!nick)
327  syntax_error(s_BotServ, u, "BOT", BOT_BOT_SYNTAX);
328  else if (readonly)
329  notice_lang(s_BotServ, u, BOT_BOT_READONLY);
330  else if (!(bi = findbot(nick)))
331  notice_lang(s_BotServ, u, BOT_DOES_NOT_EXIST, nick);
332  else {
333  send_event(EVENT_BOT_DEL, 1, bi->nick);
334  anope_cmd_quit(bi->nick,
335  "Quit: Help! I'm being deleted by %s!",
336  u->nick);
337  if (ircd->sqline) {
339  }
340  delbot(bi);
341 
342  alog("%s: %s!%s@%s deleted bot %s from the bot list",
343  s_BotServ, u->nick, u->username, u->host, nick);
344  notice_lang(s_BotServ, u, BOT_BOT_DELETED, nick);
345  }
346  } else
347  syntax_error(s_BotServ, u, "BOT", BOT_BOT_SYNTAX);
348 
349  return MOD_CONT;
350 }
351 
352 static int delbot(BotInfo * bi)
353 {
354  cs_remove_bot(bi);
355 
356  if (bi->next)
357  bi->next->prev = bi->prev;
358  if (bi->prev)
359  bi->prev->next = bi->next;
360  else
361  botlists[tolower(*bi->nick)] = bi->next;
362 
363  nbots--;
364 
365  free(bi->nick);
366  free(bi->user);
367  free(bi->host);
368  free(bi->real);
369 
370  free(bi);
371 
372  return 1;
373 }
374 
375 static void change_bot_nick(BotInfo * bi, char *newnick)
376 {
377  if (bi->next)
378  bi->next->prev = bi->prev;
379  if (bi->prev)
380  bi->prev->next = bi->next;
381  else
382  botlists[tolower(*bi->nick)] = bi->next;
383 
384  if (bi->nick)
385  free(bi->nick);
386  bi->nick = sstrdup(newnick);
387 
388  insert_bot(bi);
389 }
E void insert_bot(BotInfo *bi)
Definition: db-merger.c:1972
E int isValidHost(const char *host, int type)
Definition: misc.c:614
E int readonly
Definition: extern.h:776
char nick[NICKMAX]
Definition: services.h:875
E NickAlias * findnick(const char *nick)
Definition: db-merger.c:1857
E char * s_BotServ
Definition: extern.h:287
E IRCDVar * ircd
Definition: extern.h:39
E void send_event(const char *name, int argc,...)
Definition: events.c:37
E int stricmp(const char *s1, const char *s2)
Definition: compat.c:58
#define EVENT_BOT_CHANGE
Definition: events.h:23
int16 chancount
Definition: services.h:579
char * host
Definition: services.h:878
static int delbot(BotInfo *bi)
Definition: bs_bot.c:352
MDE void moduleAddAuthor(const char *author)
Definition: modules.c:1772
E void EnforceQlinedNick(char *nick, char *killer)
Definition: misc.c:837
E void syntax_error(char *service, User *u, const char *command, int msgnum)
Definition: language.c:295
#define EVENT_BOT_DEL
Definition: events.h:26
E void notice_lang(char *source, User *dest, int message,...)
Definition: send.c:169
MDE void moduleSetType(MODType type)
Definition: modules.c:818
static void change_bot_nick(BotInfo *bi, char *newnick)
Definition: bs_bot.c:375
#define EVENT_BOT_CREATE
Definition: events.h:22
E char * sstrdup(const char *s)
Definition: memory.c:105
E void bot_rejoin_all(BotInfo *bi)
Definition: botserv.c:814
char * botserv_bot_mode
Definition: services.h:296
E int nickIsServices(char *nick, int bot)
Definition: misc.c:857
int AnopeInit(int argc, char **argv)
Definition: bs_bot.c:28
static int do_bot(User *u)
Definition: bs_bot.c:71
E BotInfo * findbot(char *nick)
Definition: db-merger.c:1989
MDE void moduleAddVersion(const char *version)
Definition: modules.c:1760
BotInfo * prev
Definition: services.h:571
Command * c
Definition: ns_recover.c:17
char * real
Definition: services.h:576
#define BOTSERV
Definition: modules.h:57
E void anope_cmd_sqline(char *mask, char *reason)
Definition: ircd.c:524
E void alog(const char *fmt,...) FORMAT(printf
int sqline
Definition: services.h:314
E void anope_cmd_unsqline(char *user)
Definition: ircd.c:357
#define MOD_CONT
Definition: modules.h:54
MDE void moduleSetBotHelp(void(*func)(User *u))
Definition: modules.c:2114
static void myBotServHelp(User *u)
Definition: bs_bot.c:59
E int is_services_admin(User *u)
Definition: operserv.c:591
void AnopeFini(void)
Definition: bs_bot.c:48
char * username
Definition: services.h:877
time_t created
Definition: services.h:578
E void anope_cmd_chg_nick(char *oldnick, char *newnick)
Definition: ircd.c:539
#define tolower
Definition: services.h:190
Definition: modules.h:99
MDE Command * createCommand(const char *name, int(*func)(User *u), int(*has_priv)(User *u), int help_all, int help_reg, int help_oper, int help_admin, int help_root)
Definition: modules.c:987
char * host
Definition: services.h:575
E int nbots
Definition: extern.h:65
#define NICKMAX
Definition: config.h:62
BotInfo * next
Definition: services.h:571
E int NickLen
Definition: extern.h:282
char * nick
Definition: services.h:573
#define USERMAX
Definition: config.h:68
E BotInfo * makebot(char *nick)
Definition: botserv.c:578
E BotInfo * botlists[256]
Definition: extern.h:64
E void cs_remove_bot(const BotInfo *bi)
Definition: chanserv.c:1931
MDE int moduleAddCommand(CommandHash *cmdTable[], Command *c, int pos)
Definition: modules.c:1082
#define isvalidnick(c)
Definition: services.h:1407
E void anope_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes)
Definition: ircd.c:224
E void anope_cmd_quit(char *source, const char *fmt,...)
Definition: ircd.c:334
char * user
Definition: services.h:574
E int anope_valid_nick(char *nick)
Definition: ircd.c:661
#define HOSTMAX
Definition: config.h:71
#define MOD_UNIQUE
Definition: module.h:11