Anope IRC Services  Version 1.8
botserv.c
Go to the documentation of this file.
1 /* BotServ 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 
16 #include "services.h"
17 #include "pseudo.h"
18 
19 
20 /*************************************************************************/
21 
22 BotInfo *botlists[256]; /* Hash list of bots */
23 int nbots = 0;
24 
25 /*************************************************************************/
26 
27 static UserData *get_user_data(Channel * c, User * u);
28 
29 static void check_ban(ChannelInfo * ci, User * u, int ttbtype);
30 static void bot_kick(ChannelInfo * ci, User * u, int message, ...);
31 
32 E void moduleAddBotServCmds(void);
33 
34 /*************************************************************************/
35 /* *INDENT-OFF* */
38 }
39 /* *INDENT-ON* */
40 /*************************************************************************/
41 /*************************************************************************/
42 
43 /* Return information on memory use. Assumes pointers are valid. */
44 
45 void get_botserv_stats(long *nrec, long *memuse)
46 {
47  long count = 0, mem = 0;
48  int i;
49  BotInfo *bi;
50 
51  for (i = 0; i < 256; i++) {
52  for (bi = botlists[i]; bi; bi = bi->next) {
53  count++;
54  mem += sizeof(*bi);
55  mem += strlen(bi->nick) + 1;
56  mem += strlen(bi->user) + 1;
57  mem += strlen(bi->host) + 1;
58  mem += strlen(bi->real) + 1;
59  }
60  }
61 
62  *nrec = count;
63  *memuse = mem;
64 }
65 
66 /*************************************************************************/
67 /*************************************************************************/
68 
69 /* BotServ initialization. */
70 
71 void bs_init(void)
72 {
73  if (s_BotServ) {
75  }
76 }
77 
78 /*************************************************************************/
79 
80 /* Main BotServ routine. */
81 
82 void botserv(User * u, char *buf)
83 {
84  char *cmd, *s;
85 
86  cmd = strtok(buf, " ");
87 
88  if (!cmd) {
89  return;
90  } else if (stricmp(cmd, "\1PING") == 0) {
91  if (!(s = strtok(NULL, ""))) {
92  s = "";
93  }
94  anope_cmd_ctcp(s_BotServ, u->nick, "PING %s", s);
95  } else if (skeleton) {
96  notice_lang(s_BotServ, u, SERVICE_OFFLINE, s_BotServ);
97  } else {
98  mod_run_cmd(s_BotServ, u, BOTSERV, cmd);
99  }
100 
101 }
102 
103 /*************************************************************************/
104 
105 /* Handles all messages sent to bots. (Currently only answers to pings ;) */
106 
107 void botmsgs(User * u, BotInfo * bi, char *buf)
108 {
109  char *cmd = strtok(buf, " ");
110  char *s;
111 
112  if (!cmd || !u)
113  return;
114 
115  if (!stricmp(cmd, "\1PING")) {
116  if (!(s = strtok(NULL, ""))) {
117  s = "";
118  }
119  anope_cmd_ctcp(bi->nick, u->nick, "PING %s", s);
120  }
121 }
122 
123 /*************************************************************************/
124 
125 /* Handles all messages that are sent to registered channels where a
126  * bot is on.
127  *
128  */
129 
130 void botchanmsgs(User * u, ChannelInfo * ci, char *buf)
131 {
132  int c;
133  int16 cstatus = 0;
134  char *cmd;
135  UserData *ud;
136  int was_action = 0;
137 
138  if (!u || !buf || !ci) {
139  return;
140  }
141 
142  /* Answer to ping if needed, without breaking the buffer. */
143  if (!strnicmp(buf, "\1PING", 5)) {
144  anope_cmd_ctcp(ci->bi->nick, u->nick, "PING %s", buf);
145  }
146 
147  /* If it's a /me, cut the CTCP part at the beginning (not
148  * at the end, because one character just doesn't matter,
149  * but the ACTION may create strange behaviours with the
150  * caps or badwords kickers */
151  if (!strnicmp(buf, "\1ACTION ", 8)) {
152  buf += 8;
153  was_action = 1;
154  }
155 
156  /* Now we can make kicker stuff. We try to order the checks
157  * from the fastest one to the slowest one, since there's
158  * no need to process other kickers if an user is kicked before
159  * the last kicker check.
160  *
161  * But FIRST we check whether the user is protected in any
162  * way.
163  */
164 
165  /* We first retrieve the user status on the channel if needed */
167  cstatus = chan_get_user_status(ci->c, u);
168 
169  if (buf && !check_access(u, ci, CA_NOKICK) &&
170  (!(ci->botflags & BS_DONTKICKOPS)
171  || !(cstatus & (CUS_HALFOP | CUS_OP | CUS_OWNER | CUS_PROTECT)))
172 
173  && (!(ci->botflags & BS_DONTKICKVOICES) || !(cstatus & CUS_VOICE))) {
174  /* Bolds kicker */
175  if ((ci->botflags & BS_KICK_BOLDS) && strchr(buf, 2)) {
176  check_ban(ci, u, TTB_BOLDS);
177  bot_kick(ci, u, BOT_REASON_BOLD);
178  return;
179  }
180 
181  /* Color kicker */
182  if ((ci->botflags & BS_KICK_COLORS) && strchr(buf, 3)) {
183  check_ban(ci, u, TTB_COLORS);
184  bot_kick(ci, u, BOT_REASON_COLOR);
185  return;
186  }
187 
188  /* Reverses kicker */
189  if ((ci->botflags & BS_KICK_REVERSES) && strchr(buf, 22)) {
190  check_ban(ci, u, TTB_REVERSES);
191  bot_kick(ci, u, BOT_REASON_REVERSE);
192  return;
193  }
194 
195  /* Underlines kicker */
196  if ((ci->botflags & BS_KICK_UNDERLINES) && strchr(buf, 31)) {
197  check_ban(ci, u, TTB_UNDERLINES);
198  bot_kick(ci, u, BOT_REASON_UNDERLINE);
199  return;
200  }
201 
202  /* Caps kicker */
203  if ((ci->botflags & BS_KICK_CAPS)
204  && ((c = strlen(buf)) >= ci->capsmin)) {
205  int i = 0;
206  int l = 0;
207  char *s = buf;
208 
209  do {
210  if (isupper(*s))
211  i++;
212  else if (islower(*s))
213  l++;
214  } while (*s++);
215 
216  /* i counts uppercase chars, l counts lowercase chars. Only
217  * alphabetic chars (so islower || isupper) qualify for the
218  * percentage of caps to kick for; the rest is ignored. -GD
219  */
220 
221  if (i >= ci->capsmin && i * 100 / (i + l) >= ci->capspercent) {
222  check_ban(ci, u, TTB_CAPS);
223  bot_kick(ci, u, BOT_REASON_CAPS);
224  return;
225  }
226  }
227 
228  /* Bad words kicker */
229  if (ci->botflags & BS_KICK_BADWORDS) {
230  int i;
231  int mustkick = 0;
232  char *nbuf;
233  BadWord *bw;
234 
235  /* Normalize the buffer */
236  nbuf = normalizeBuffer(buf);
237 
238  for (i = 0, bw = ci->badwords; i < ci->bwcount; i++, bw++) {
239  if (!bw->in_use)
240  continue;
241 
242  if (bw->type == BW_ANY
243  && ((BSCaseSensitive && strstr(nbuf, bw->word))
244  || (!BSCaseSensitive && stristr(nbuf, bw->word)))) {
245  mustkick = 1;
246  } else if (bw->type == BW_SINGLE) {
247  int len = strlen(bw->word);
248  int buf_len = strlen(nbuf);
249 
250  if ((BSCaseSensitive && !strcmp(nbuf, bw->word))
251  || (!BSCaseSensitive
252  && (!stricmp(nbuf, bw->word)))) {
253  mustkick = 1;
254  /* two next if are quite odd isn't it? =) */
255  } else if ((strchr(nbuf, ' ') == nbuf + len)
256  && ((BSCaseSensitive && strstr(nbuf, bw->word) == nbuf)
257  || (!BSCaseSensitive && stristr(nbuf, bw->word) == nbuf))) {
258  mustkick = 1;
259  } else {
260  if (len < buf_len && (strrchr(nbuf, ' ') == nbuf + buf_len - len - 1)
261  && ((BSCaseSensitive && (strstr(nbuf, bw->word) == nbuf + buf_len - len))
262  || (!BSCaseSensitive && (stristr(nbuf, bw->word) == nbuf + buf_len - len)))) {
263  mustkick = 1;
264  } else {
265  char *wordbuf = scalloc(len + 3, 1);
266 
267  wordbuf[0] = ' ';
268  wordbuf[len + 1] = ' ';
269  wordbuf[len + 2] = '\0';
270  memcpy(wordbuf + 1, bw->word, len);
271 
272  if ((BSCaseSensitive
273  && (strstr(nbuf, wordbuf)))
274  || (!BSCaseSensitive
275  && (stristr(nbuf, wordbuf)))) {
276  mustkick = 1;
277  }
278 
279  /* free previous (sc)allocated memory (#850) */
280  free(wordbuf);
281  }
282  }
283  } else if (bw->type == BW_START) {
284  int len = strlen(bw->word);
285 
286  if ((BSCaseSensitive
287  && (!strncmp(nbuf, bw->word, len)))
288  || (!BSCaseSensitive
289  && (!strnicmp(nbuf, bw->word, len)))) {
290  mustkick = 1;
291  } else {
292  char *wordbuf = scalloc(len + 2, 1);
293 
294  memcpy(wordbuf + 1, bw->word, len);
295  wordbuf[0] = ' ';
296  wordbuf[len + 1] = '\0';
297 
298  if ((BSCaseSensitive && (strstr(nbuf, wordbuf)))
299  || (!BSCaseSensitive
300  && (stristr(nbuf, wordbuf))))
301  mustkick = 1;
302 
303  free(wordbuf);
304  }
305  } else if (bw->type == BW_END) {
306  int len = strlen(bw->word);
307  int buf_len = strlen(nbuf);
308 
309  if ((BSCaseSensitive && len <= buf_len && !strncmp(nbuf + buf_len - len, bw->word, len))
310  || (!BSCaseSensitive && len <= buf_len && !strnicmp(nbuf + buf_len - len, bw->word, len))) {
311  mustkick = 1;
312  } else {
313  char *wordbuf = scalloc(len + 2, 1);
314 
315  memcpy(wordbuf, bw->word, len);
316  wordbuf[len] = ' ';
317  wordbuf[len + 1] = '\0';
318 
319  if ((BSCaseSensitive && (strstr(nbuf, wordbuf)))
320  || (!BSCaseSensitive
321  && (stristr(nbuf, wordbuf))))
322  mustkick = 1;
323 
324  free(wordbuf);
325  }
326  }
327 
328  if (mustkick) {
329  check_ban(ci, u, TTB_BADWORDS);
330  if (BSGentleBWReason)
331  bot_kick(ci, u, BOT_REASON_BADWORD_GENTLE);
332  else
333  bot_kick(ci, u, BOT_REASON_BADWORD, bw->word);
334 
335  /* free the normalized buffer before return (#850) */
336  Anope_Free(nbuf);
337 
338  return;
339  }
340  }
341 
342  /* Free the normalized buffer */
343  Anope_Free(nbuf);
344  }
345 
346  /* Flood kicker */
347  if (ci->botflags & BS_KICK_FLOOD) {
348  time_t now = time(NULL);
349 
350  ud = get_user_data(ci->c, u);
351  if (!ud) {
352  return;
353  }
354 
355  if (now - ud->last_start > ci->floodsecs) {
356  ud->last_start = time(NULL);
357  ud->lines = 0;
358  }
359 
360  ud->lines++;
361  if (ud->lines >= ci->floodlines) {
362  check_ban(ci, u, TTB_FLOOD);
363  bot_kick(ci, u, BOT_REASON_FLOOD);
364  return;
365  }
366  }
367 
368  /* Repeat kicker */
369  if (ci->botflags & BS_KICK_REPEAT) {
370  ud = get_user_data(ci->c, u);
371  if (!ud) {
372  return;
373  }
374  if (ud->lastline && stricmp(ud->lastline, buf)) {
375  free(ud->lastline);
376  ud->lastline = sstrdup(buf);
377  ud->times = 0;
378  } else {
379  if (!ud->lastline)
380  ud->lastline = sstrdup(buf);
381  ud->times++;
382  }
383 
384  if (ud->times >= ci->repeattimes) {
385  check_ban(ci, u, TTB_REPEAT);
386  bot_kick(ci, u, BOT_REASON_REPEAT);
387  return;
388  }
389  }
390  }
391 
392 
393  /* return if the user is on the ignore list */
394  if (get_ignore(u->nick) != NULL) {
395  return;
396  }
397 
398  /* Fantaisist commands */
399 
400  if (buf && (ci->botflags & BS_FANTASY) && *buf == *BSFantasyCharacter && !was_action) {
401  cmd = strtok(buf, " ");
402 
403  if (cmd && (cmd[0] == *BSFantasyCharacter)) {
404  char *params = strtok(NULL, "");
405  char *event_name = EVENT_BOT_FANTASY_NO_ACCESS;
406 
407  /* Strip off the fantasy character */
408  cmd++;
409 
410  if (check_access(u, ci, CA_FANTASIA))
411  event_name = EVENT_BOT_FANTASY;
412 
413  if (params)
414  send_event(event_name, 4, cmd, u->nick, ci->name, params);
415  else
416  send_event(event_name, 3, cmd, u->nick, ci->name);
417  }
418  }
419 }
420 
421 /*************************************************************************/
422 
423 /* Load/save data files. */
424 
425 
426 #define SAFE(x) do { \
427  if ((x) < 0) { \
428  if (!forceload) \
429  fatal("Read error on %s", BotDBName); \
430  failed = 1; \
431  break; \
432  } \
433 } while (0)
434 
435 void load_bs_dbase(void)
436 {
437  dbFILE *f;
438  int c, ver;
439  uint16 tmp16;
440  uint32 tmp32;
441  BotInfo *bi;
442  int failed = 0;
443 
444  if (!(f = open_db(s_BotServ, BotDBName, "r", BOT_VERSION)))
445  return;
446 
447  ver = get_file_version(f);
448 
449  while (!failed && (c = getc_db(f)) != 0) {
450  char *s;
451 
452  if (c != 1)
453  fatal("Invalid format in %s %d", BotDBName, c);
454 
455  SAFE(read_string(&s, f));
456  bi = makebot(s);
457  free(s);
458  SAFE(read_string(&bi->user, f));
459  SAFE(read_string(&bi->host, f));
460  SAFE(read_string(&bi->real, f));
461  if (ver >= 10) {
462  SAFE(read_int16(&tmp16, f));
463  bi->flags = tmp16;
464  }
465  SAFE(read_int32(&tmp32, f));
466  bi->created = tmp32;
467  SAFE(read_int16(&tmp16, f));
468  bi->chancount = tmp16;
469  }
470 
471  close_db(f);
472 }
473 
474 #undef SAFE
475 
476 /*************************************************************************/
477 
478 #define SAFE(x) do { \
479  if ((x) < 0) { \
480  restore_db(f); \
481  log_perror("Write error on %s", BotDBName); \
482  if (time(NULL) - lastwarn > WarningTimeout) { \
483  anope_cmd_global(NULL, "Write error on %s: %s", BotDBName, \
484  strerror(errno)); \
485  lastwarn = time(NULL); \
486  } \
487  return; \
488  } \
489 } while (0)
490 
491 void save_bs_dbase(void)
492 {
493  dbFILE *f;
494  BotInfo *bi;
495  static time_t lastwarn = 0;
496  int i;
497 
498  if (!(f = open_db(s_BotServ, BotDBName, "w", BOT_VERSION)))
499  return;
500 
501  for (i = 0; i < 256; i++) {
502  for (bi = botlists[i]; bi; bi = bi->next) {
503  SAFE(write_int8(1, f));
504  SAFE(write_string(bi->nick, f));
505  SAFE(write_string(bi->user, f));
506  SAFE(write_string(bi->host, f));
507  SAFE(write_string(bi->real, f));
508  SAFE(write_int16(bi->flags, f));
509  SAFE(write_int32(bi->created, f));
510  SAFE(write_int16(bi->chancount, f));
511  }
512  }
513  SAFE(write_int8(0, f));
514 
515  close_db(f);
516 
517 }
518 
519 #undef SAFE
520 
521 /*************************************************************************/
522 
524 {
525 #ifdef USE_RDB
526  int i;
527  BotInfo *bi;
528 
529  if (!rdb_open())
530  return;
531 
532  if (rdb_tag_table("anope_bs_core") == 0) {
533  alog("Unable to tag table 'anope_bs_core' - BotServ RDB save failed.");
534  rdb_close();
535  return;
536  }
537 
538  for (i = 0; i < 256; i++) {
539  for (bi = botlists[i]; bi; bi = bi->next) {
540  if (rdb_save_bs_core(bi) == 0) {
541  alog("Unable to save BotInfo for %s - BotServ RDB save failed.", bi->nick);
542  rdb_close();
543  return;
544  }
545  }
546  }
547 
548  if (rdb_clean_table("anope_bs_core") == 0)
549  alog("Unable to clean table 'anope_bs_core' - BotServ RDB save failed.");
550 
551  rdb_close();
552 #endif
553 }
554 
555 /*************************************************************************/
556 
557 /* Inserts a bot in the bot list. I can't be much explicit mh? */
558 
559 void insert_bot(BotInfo * bi)
560 {
561  BotInfo *ptr, *prev;
562 
563  for (prev = NULL, ptr = botlists[tolower(*bi->nick)];
564  ptr != NULL && stricmp(ptr->nick, bi->nick) < 0;
565  prev = ptr, ptr = ptr->next);
566  bi->prev = prev;
567  bi->next = ptr;
568  if (!prev)
569  botlists[tolower(*bi->nick)] = bi;
570  else
571  prev->next = bi;
572  if (ptr)
573  ptr->prev = bi;
574 }
575 
576 /*************************************************************************/
577 
578 BotInfo *makebot(char *nick)
579 {
580  BotInfo *bi;
581 
582  if (!nick) {
583  if (debug) {
584  alog("debug: makebot called with NULL values");
585  }
586  return NULL;
587  }
588 
589  bi = scalloc(sizeof(BotInfo), 1);
590  bi->nick = sstrdup(nick);
591  bi->lastmsg = time(NULL);
592  insert_bot(bi);
593  nbots++;
594  return bi;
595 }
596 
597 /*************************************************************************/
598 
599 
600 /*************************************************************************/
601 
602 
603 /*************************************************************************/
604 
605 BotInfo *findbot(char *nick)
606 {
607  BotInfo *bi;
608  Uid *ud;
609 
610  /* to keep make strict happy */
611  ud = NULL;
612 
613  if (!nick || !*nick)
614  return NULL;
615 
616  for (bi = botlists[tolower(*nick)]; bi; bi = bi->next) {
617  if (UseTS6 && ircd->ts6) {
618  ud = find_nickuid(nick);
619  }
620  if (!stricmp(nick, bi->nick)) {
621  return bi;
622  }
623  if (ud && UseTS6 && ircd->ts6) {
624  if (!stricmp(ud->nick, bi->nick)) {
625  return bi;
626  }
627  }
628  }
629 
630  return NULL;
631 }
632 
633 /*************************************************************************/
634 
635 /* Unassign a bot from a channel. Assumes u, ci and ci->bi are not NULL */
636 
637 void unassign(User * u, ChannelInfo * ci)
638 {
639  send_event(EVENT_BOT_UNASSIGN, 2, ci->name, ci->bi->nick);
640 
641  if (ci->c && ci->c->usercount >= BSMinUsers) {
642  anope_cmd_part(ci->bi->nick, ci->name, "UNASSIGN from %s",
643  u->nick);
644  }
645  ci->bi->chancount--;
646  ci->bi = NULL;
647 }
648 
649 /*************************************************************************/
650 
651 /* Returns ban data associated with an user if it exists, allocates it
652  otherwise. */
653 
655 {
656  char mask[BUFSIZE];
657  BanData *bd, *next;
658  time_t now = time(NULL);
659 
660  if (!c || !u)
661  return NULL;
662 
663  snprintf(mask, sizeof(mask), "%s@%s", common_get_vident(u),
664  common_get_vhost(u));
665 
666  for (bd = c->bd; bd; bd = next) {
667  if (now - bd->last_use > BSKeepData) {
668  if (bd->next)
669  bd->next->prev = bd->prev;
670  if (bd->prev)
671  bd->prev->next = bd->next;
672  else
673  c->bd = bd->next;
674  if (bd->mask)
675  free(bd->mask);
676  next = bd->next;
677  free(bd);
678  continue;
679  }
680  if (!stricmp(bd->mask, mask)) {
681  bd->last_use = now;
682  return bd;
683  }
684  next = bd->next;
685  }
686 
687  /* If we fall here it is that we haven't found the record */
688  bd = scalloc(sizeof(BanData), 1);
689  bd->mask = sstrdup(mask);
690  bd->last_use = now;
691 
692  bd->prev = NULL;
693  bd->next = c->bd;
694  if (bd->next)
695  bd->next->prev = bd;
696  c->bd = bd;
697 
698  return bd;
699 }
700 
701 /*************************************************************************/
702 
703 /* Returns BotServ data associated with an user on a given channel.
704  * Allocates it if necessary.
705  */
706 
708 {
709  struct c_userlist *user;
710 
711  if (!c || !u)
712  return NULL;
713 
714  for (user = c->users; user; user = user->next) {
715  if (user->user == u) {
716  if (user->ud) {
717  time_t now = time(NULL);
718 
719  /* Checks whether data is obsolete */
720  if (now - user->ud->last_use > BSKeepData) {
721  if (user->ud->lastline)
722  free(user->ud->lastline);
723  /* We should not free and realloc, but reset to 0
724  instead. */
725  memset(user->ud, 0, sizeof(UserData));
726  user->ud->last_use = now;
727  }
728 
729  return user->ud;
730  } else {
731  user->ud = scalloc(sizeof(UserData), 1);
732  user->ud->last_use = time(NULL);
733  return user->ud;
734  }
735  }
736  }
737 
738  return NULL;
739 }
740 
741 /*************************************************************************/
742 
743 /* Makes the bot join a channel and op himself. */
744 
746 {
747  if (!ci || !ci->c || !ci->bi)
748  return;
749 
750  if (BSSmartJoin) {
751  /* We check for bans */
752  if (ci->c->bans && ci->c->bans->count) {
753  char buf[BUFSIZE];
754  char *av[4];
755  Entry *ban, *next;
756  int ac;
757 
758  if (ircdcap->tsmode) {
759  snprintf(buf, BUFSIZE - 1, "%ld", (long int) time(NULL));
760  av[0] = ci->c->name;
761  av[1] = buf;
762  av[2] = sstrdup("-b");
763  ac = 4;
764  } else {
765  av[0] = ci->c->name;
766  av[1] = sstrdup("-b");
767  ac = 3;
768  }
769 
770  for (ban = ci->c->bans->entries; ban; ban = next) {
771  next = ban->next;
772  if (entry_match
773  (ban, ci->bi->nick, ci->bi->user, ci->bi->host, 0)) {
774  anope_cmd_mode(whosends(ci), ci->name, "-b %s",
775  ban->mask);
776  if (ircdcap->tsmode)
777  av[3] = sstrdup(ban->mask);
778  else
779  av[2] = sstrdup(ban->mask);
780 
781  do_cmode(whosends(ci), ac, av);
782 
783  if (ircdcap->tsmode)
784  free(av[3]);
785  else
786  free(av[2]);
787  }
788  }
789 
790  if (ircdcap->tsmode)
791  free(av[2]);
792  else
793  free(av[1]);
794  }
795 
796  /* Should we be invited? */
797  if ((ci->c->mode & anope_get_invite_mode())
798  || (ci->c->limit && ci->c->usercount >= ci->c->limit))
799  anope_cmd_notice_ops(NULL, ci->c->name,
800  "%s invited %s into the channel.",
801  ci->bi->nick, ci->bi->nick);
802  }
803  anope_cmd_join(ci->bi->nick, ci->c->name, ci->c->creation_time);
804  anope_cmd_bot_chan_mode(ci->bi->nick, ci->c->name);
805  send_event(EVENT_BOT_JOIN, 2, ci->name, ci->bi->nick);
806 }
807 
808 /*************************************************************************/
809 
810 /* This makes the bot rejoin all channel he is on when he gets killed
811  * or changed.
812  */
813 
815 {
816  int i;
817  ChannelInfo *ci;
818 
819  for (i = 0; i < 256; i++)
820  for (ci = chanlists[i]; ci; ci = ci->next)
821  if (ci->bi == bi && ci->c && (ci->c->usercount >= BSMinUsers))
822  bot_join(ci);
823 }
824 
825 /*************************************************************************/
826 
827 /* This makes a ban if the user has to have one. In every cases it increments
828  the kick count for the user. */
829 
830 static void check_ban(ChannelInfo * ci, User * u, int ttbtype)
831 {
832  BanData *bd = get_ban_data(ci->c, u);
833 
834  if (!bd)
835  return;
836 
837  /* Bug #1135 - Don't kick/ban ULined clients */
838  if (is_ulined(u->server->name))
839  return;
840 
841  bd->ttb[ttbtype]++;
842  if (ci->ttb[ttbtype] && bd->ttb[ttbtype] >= ci->ttb[ttbtype]) {
843  /* bd->ttb[ttbtype] can possibly be > ci->ttb[ttbtype] if ci->ttb[ttbtype] was changed after
844  * the user has been kicked - Adam
845  */
846  char *av[4];
847  int ac;
848  char mask[BUFSIZE];
849  char buf[BUFSIZE];
850 
851  bd->ttb[ttbtype] = 0;
852 
853  get_idealban(ci, u, mask, sizeof(mask));
854 
855  if (ircdcap->tsmode) {
856  snprintf(buf, BUFSIZE - 1, "%ld", (long int) time(NULL));
857  av[0] = ci->name;
858  av[1] = buf;
859  av[2] = sstrdup("+b");
860  av[3] = mask;
861  ac = 4;
862  } else {
863  av[0] = ci->name;
864  av[1] = sstrdup("+b");
865  av[2] = mask;
866  ac = 3;
867  }
868 
869  anope_cmd_mode(ci->bi->nick, ci->name, "+b %s", mask);
870  do_cmode(ci->bi->nick, ac, av);
871  send_event(EVENT_BOT_BAN, 3, u->nick, ci->name, mask);
872  if (ircdcap->tsmode)
873  free(av[2]);
874  else
875  free(av[1]);
876  }
877 }
878 
879 /*************************************************************************/
880 
881 /* This makes a bot kick an user. Works somewhat like notice_lang in fact ;) */
882 
883 static void bot_kick(ChannelInfo * ci, User * u, int message, ...)
884 {
885  va_list args;
886  char buf[1024];
887  const char *fmt;
888  char *av[3];
889 
890  if (!ci || !ci->bi || !ci->c || !u)
891  return;
892 
893  /* Bug #1135 - Don't kick ULined clients */
894  if (is_ulined(u->server->name))
895  return;
896 
897  va_start(args, message);
898  fmt = getstring(u->na, message);
899  if (!fmt)
900  return;
901  vsnprintf(buf, sizeof(buf), fmt, args);
902  va_end(args);
903 
904  av[0] = ci->name;
905  av[1] = u->nick;
906  av[2] = buf;
907  anope_cmd_kick(ci->bi->nick, av[0], av[1], "%s", av[2]);
908  do_kick(ci->bi->nick, 3, av);
909  send_event(EVENT_BOT_KICK, 3, u->nick, ci->name, buf);
910 }
911 
912 /*************************************************************************/
913 
914 /* Makes a simple ban and kicks the target */
915 
916 void bot_raw_ban(User * requester, ChannelInfo * ci, char *nick,
917  char *reason)
918 {
919  int ac;
920  char *av[4];
921  char mask[BUFSIZE];
922  char buf[BUFSIZE];
923  User *u = finduser(nick);
924 
925  if (!u)
926  return;
927 
928  if (ircd->protectedumode) {
929  if (is_protected(u) && (requester != u)) {
930  anope_cmd_privmsg(ci->bi->nick, ci->name, "%s",
931  getstring2(NULL, PERMISSION_DENIED));
932  return;
933  }
934  }
935 
936  if ((ci->flags & CI_PEACE) && stricmp(requester->nick, nick)
937  && (get_access(u, ci) >= get_access(requester, ci)))
938  return;
939 
940  if (ircd->except) {
941  if (is_excepted(ci, u) == 1) {
942  anope_cmd_privmsg(ci->bi->nick, ci->name, "%s",
943  getstring2(NULL, BOT_EXCEPT));
944  return;
945  }
946  }
947 
948  get_idealban(ci, u, mask, sizeof(mask));
949 
950  if (ircdcap->tsmode) {
951  snprintf(buf, BUFSIZE - 1, "%ld", (long int) time(NULL));
952  av[0] = ci->name;
953  av[1] = buf;
954  av[2] = sstrdup("+b");
955  av[3] = mask;
956  ac = 4;
957  } else {
958  av[0] = ci->name;
959  av[1] = sstrdup("+b");
960  av[2] = mask;
961  ac = 3;
962  }
963 
964  anope_cmd_mode(ci->bi->nick, ci->name, "+b %s", mask);
965  do_cmode(ci->bi->nick, ac, av);
966 
967  /* We need to free our sstrdup'd "+b" -GD */
968  if (ircdcap->tsmode)
969  free(av[2]);
970  else
971  free(av[1]);
972 
973  av[0] = ci->name;
974  av[1] = nick;
975 
976  if (!reason) {
977  av[2] = ci->bi->nick;
978  } else {
979  if (strlen(reason) > 200)
980  reason[200] = '\0';
981  av[2] = reason;
982  }
983 
984  /* Check if we need to do a signkick or not -GD */
985  if ((ci->flags & CI_SIGNKICK)
986  || ((ci->flags & CI_SIGNKICK_LEVEL)
987  && !check_access(requester, ci, CA_SIGNKICK)))
988  anope_cmd_kick(ci->bi->nick, av[0], av[1], "%s (%s)", av[2],
989  requester->nick);
990  else
991  anope_cmd_kick(ci->bi->nick, av[0], av[1], "%s", av[2]);
992 
993  do_kick(ci->bi->nick, 3, av);
994  send_event(EVENT_BOT_KICK, 3, av[1], av[0], av[2]);
995 }
996 
997 /*************************************************************************/
998 
999 /* Makes a kick with a "dynamic" reason ;) */
1000 
1001 void bot_raw_kick(User * requester, ChannelInfo * ci, char *nick,
1002  char *reason)
1003 {
1004  char *av[3];
1005  User *u = finduser(nick);
1006 
1007  if (!u || !is_on_chan(ci->c, u))
1008  return;
1009 
1010  if (ircd->protectedumode) {
1011  if (is_protected(u) && (requester != u)) {
1012  anope_cmd_privmsg(ci->bi->nick, ci->name, "%s",
1013  getstring2(NULL, PERMISSION_DENIED));
1014  return;
1015  }
1016  }
1017 
1018  if ((ci->flags & CI_PEACE) && stricmp(requester->nick, nick)
1019  && (get_access(u, ci) >= get_access(requester, ci)))
1020  return;
1021 
1022  av[0] = ci->name;
1023  av[1] = nick;
1024 
1025  if (!reason) {
1026  av[2] = ci->bi->nick;
1027  } else {
1028  if (strlen(reason) > 200)
1029  reason[200] = '\0';
1030  av[2] = reason;
1031  }
1032 
1033  if ((ci->flags & CI_SIGNKICK)
1034  || ((ci->flags & CI_SIGNKICK_LEVEL)
1035  && !check_access(requester, ci, CA_SIGNKICK)))
1036  anope_cmd_kick(ci->bi->nick, av[0], av[1], "%s (%s)", av[2],
1037  requester->nick);
1038  else
1039  anope_cmd_kick(ci->bi->nick, av[0], av[1], "%s", av[2]);
1040  do_kick(ci->bi->nick, 3, av);
1041  send_event(EVENT_BOT_KICK, 3, av[1], av[0], av[2]);
1042 }
1043 
1044 /*************************************************************************/
1045 
1046 /* Makes a mode operation on a channel for a nick */
1047 
1048 void bot_raw_mode(User * requester, ChannelInfo * ci, char *mode,
1049  char *nick)
1050 {
1051  char *av[4];
1052  int ac;
1053  char buf[BUFSIZE];
1054  User *u;
1055 
1056  *buf = '\0';
1057  u = finduser(nick);
1058 
1059  if (!u || !is_on_chan(ci->c, u))
1060  return;
1061 
1062  snprintf(buf, BUFSIZE - 1, "%ld", (long int) time(NULL));
1063 
1064  if (ircd->protectedumode) {
1065  if (is_protected(u) && *mode == '-' && (requester != u)) {
1066  anope_cmd_privmsg(ci->bi->nick, ci->name, "%s",
1067  getstring2(NULL, PERMISSION_DENIED));
1068  return;
1069  }
1070  }
1071 
1072  if (*mode == '-' && (ci->flags & CI_PEACE)
1073  && stricmp(requester->nick, nick)
1074  && (get_access(u, ci) >= get_access(requester, ci)))
1075  return;
1076 
1077  if (ircdcap->tsmode) {
1078  av[0] = ci->name;
1079  av[1] = buf;
1080  av[2] = mode;
1081  av[3] = GET_USER(u);
1082  ac = 4;
1083  anope_cmd_mode(ci->bi->nick, av[0], "%s %s", av[2], av[3]);
1084  } else {
1085  av[0] = ci->name;
1086  av[1] = mode;
1087  av[2] = GET_USER(u);
1088  ac = 3;
1089  anope_cmd_mode(ci->bi->nick, av[0], "%s %s", av[1], av[2]);
1090  }
1091 
1092  do_cmode(ci->bi->nick, ac, av);
1093 }
1094 
1095 /*************************************************************************/
1101 char *normalizeBuffer(char *buf)
1102 {
1103  char *newbuf;
1104  int i, len, j = 0;
1105 
1106  len = strlen(buf);
1107  newbuf = (char *) smalloc(sizeof(char) * len + 1);
1108 
1109  for (i = 0; i < len; i++) {
1110  switch (buf[i]) {
1111  /* ctrl char */
1112  case 1:
1113  break;
1114  /* Bold ctrl char */
1115  case 2:
1116  break;
1117  /* Color ctrl char */
1118  case 3:
1119  /* If the next character is a digit, its also removed */
1120  if (isdigit(buf[i + 1])) {
1121  i++;
1122 
1123  /* not the best way to remove colors
1124  * which are two digit but no worse then
1125  * how the Unreal does with +S - TSL
1126  */
1127  if (isdigit(buf[i + 1])) {
1128  i++;
1129  }
1130 
1131  /* Check for background color code
1132  * and remove it as well
1133  */
1134  if (buf[i + 1] == ',') {
1135  i++;
1136 
1137  if (isdigit(buf[i + 1])) {
1138  i++;
1139  }
1140  /* not the best way to remove colors
1141  * which are two digit but no worse then
1142  * how the Unreal does with +S - TSL
1143  */
1144  if (isdigit(buf[i + 1])) {
1145  i++;
1146  }
1147  }
1148  }
1149 
1150  break;
1151  /* line feed char */
1152  case 10:
1153  break;
1154  /* carriage returns char */
1155  case 13:
1156  break;
1157  /* Reverse ctrl char */
1158  case 22:
1159  break;
1160  /* Underline ctrl char */
1161  case 31:
1162  break;
1163  /* A valid char gets copied into the new buffer */
1164  default:
1165  newbuf[j] = buf[i];
1166  j++;
1167  }
1168  }
1169 
1170  /* Terminate the string */
1171  newbuf[j] = 0;
1172 
1173  return (newbuf);
1174 }
BotInfo * makebot(char *nick)
Definition: botserv.c:578
E char ** BotServCoreModules
Definition: extern.h:491
#define BS_KICK_REPEAT
Definition: services.h:808
#define BS_FANTASY
Definition: services.h:795
#define TTB_FLOOD
Definition: services.h:817
#define Anope_Free(x)
Definition: extern.h:1391
int16 times
Definition: services.h:985
int16 usercount
Definition: services.h:1020
static BanData * get_ban_data(Channel *c, User *u)
Definition: botserv.c:654
#define TTB_UNDERLINES
Definition: services.h:814
E IRCDCAPAB * ircdcap
Definition: extern.h:40
int nbots
Definition: botserv.c:23
void unassign(User *u, ChannelInfo *ci)
Definition: botserv.c:637
char nick[NICKMAX]
Definition: services.h:875
void load_bs_dbase(void)
Definition: botserv.c:435
E int snprintf(char *buf, size_t size, const char *fmt,...)
Definition: compat.c:37
E void anope_cmd_part(char *nick, char *chan, const char *fmt,...)
Definition: ircd.c:367
E int BotServCoreNumber
Definition: extern.h:492
uint32 botflags
Definition: services.h:700
void insert_bot(BotInfo *bi)
Definition: botserv.c:559
char * word
Definition: services.h:642
int16 capspercent
Definition: services.h:705
E char * s_BotServ
Definition: extern.h:287
E IRCDVar * ircd
Definition: extern.h:39
#define CA_FANTASIA
Definition: services.h:765
#define BW_START
Definition: services.h:648
void bot_raw_mode(User *requester, ChannelInfo *ci, char *mode, char *nick)
Definition: botserv.c:1048
uint16 type
Definition: services.h:643
E void do_kick(const char *source, int ac, char **av)
Definition: channels.c:638
E int strnicmp(const char *s1, const char *s2, size_t len)
Definition: compat.c:73
#define BW_END
Definition: services.h:649
#define BS_KICK_CAPS
Definition: services.h:806
E int check_access(User *user, ChannelInfo *ci, int what)
Definition: chanserv.c:1974
#define EVENT_BOT_JOIN
Definition: events.h:21
Entry * next
Definition: services.h:1038
void bs_init(void)
Definition: botserv.c:71
#define CA_NOKICK
Definition: services.h:764
#define TTB_REPEAT
Definition: services.h:818
E void send_event(const char *name, int argc,...)
Definition: events.c:37
BotInfo * botlists[256]
Definition: botserv.c:22
E int is_ulined(char *server)
Definition: servers.c:495
E int stricmp(const char *s1, const char *s2)
Definition: compat.c:58
void botserv(User *u, char *buf)
Definition: botserv.c:82
E void anope_cmd_join(char *user, char *channel, time_t chantime)
Definition: ircd.c:352
E char * stristr(char *s1, char *s2)
Definition: misc.c:113
E void modules_core_init(int number, char **list)
Definition: modules.c:127
int32 count
Definition: services.h:1034
BotInfo * findbot(char *nick)
Definition: botserv.c:605
int16 chancount
Definition: services.h:579
#define getstring(na, index)
Definition: extern.h:731
char * lastline
Definition: services.h:984
E int BSMinUsers
Definition: extern.h:422
#define TTB_BADWORDS
Definition: services.h:815
E Uid * find_nickuid(const char *uid)
Definition: users.c:468
#define getstring2(nc, index)
Definition: extern.h:733
#define CUS_VOICE
Definition: services.h:1342
void save_bs_dbase(void)
Definition: botserv.c:491
#define write_int8(val, f)
Definition: datafiles.h:60
E int BSKeepData
Definition: extern.h:421
void get_botserv_stats(long *nrec, long *memuse)
Definition: botserv.c:45
#define CA_SIGNKICK
Definition: services.h:780
E int is_on_chan(Channel *c, User *u)
Definition: channels.c:517
E int is_protected(User *user)
Definition: users.c:924
int16 ttb[TTB_SIZE]
Definition: services.h:969
void bot_raw_kick(User *requester, ChannelInfo *ci, char *nick, char *reason)
Definition: botserv.c:1001
time_t last_start
Definition: services.h:981
E int BSSmartJoin
Definition: extern.h:424
char name[CHANMAX]
Definition: services.h:654
int except
Definition: services.h:320
E void notice_lang(char *source, User *dest, int message,...)
Definition: send.c:169
#define BS_KICK_FLOOD
Definition: services.h:807
E ChannelInfo * chanlists[256]
Definition: extern.h:167
E int is_excepted(ChannelInfo *ci, User *user)
Definition: users.c:950
E int BSCaseSensitive
Definition: extern.h:426
E int read_int16(uint16 *ret, dbFILE *f)
Definition: datafiles.c:405
#define BS_KICK_BADWORDS
Definition: services.h:805
void bot_rejoin_all(BotInfo *bi)
Definition: botserv.c:814
E char * sstrdup(const char *s)
Definition: memory.c:105
int rdb_close()
Definition: rdb.c:47
E void * scalloc(long elsize, long els)
Definition: memory.c:55
#define CI_PEACE
Definition: services.h:721
E int get_idealban(ChannelInfo *ci, User *u, char *ret, int retlen)
Definition: chanserv.c:2380
E void anope_cmd_kick(char *source, char *chan, char *user, const char *fmt,...)
Definition: ircd.c:230
E void E void E void fatal(const char *fmt,...) FORMAT(printf
void bot_join(ChannelInfo *ci)
Definition: botserv.c:745
void save_bs_rdb_dbase(void)
Definition: botserv.c:523
#define TTB_COLORS
Definition: services.h:812
BadWord * badwords
Definition: services.h:704
#define getc_db(f)
Definition: datafiles.h:48
uint32 flags
Definition: services.h:669
E int read_string(char **ret, dbFILE *f)
Definition: db-merger.c:1806
E int get_file_version(dbFILE *f)
Definition: datafiles.c:30
Definition: services.h:1037
int16 flags
Definition: services.h:577
uint32 mode
Definition: services.h:1006
E int write_int16(uint16 val, dbFILE *f)
Definition: db-merger.c:1737
int rdb_save_bs_core(BotInfo *bi)
Definition: rdb.c:301
E User * finduser(const char *nick)
Definition: users.c:323
uint32 protectedumode
Definition: services.h:323
time_t creation_time
Definition: services.h:1002
E int entry_match(Entry *e, char *nick, char *user, char *host, uint32 ip)
Definition: channels.c:2272
#define TTB_CAPS
Definition: services.h:816
#define BS_KICK_BOLDS
Definition: services.h:801
E void close_db(dbFILE *f)
Definition: db-merger.c:1706
#define BS_KICK_UNDERLINES
Definition: services.h:804
#define BW_ANY
Definition: services.h:646
BotInfo * prev
Definition: services.h:571
#define CUS_HALFOP
Definition: services.h:1343
struct channel_ * c
Definition: services.h:692
char * name
Definition: services.h:854
#define CUS_PROTECT
Definition: services.h:1345
Command * c
Definition: ns_recover.c:17
char * real
Definition: services.h:576
Server * server
Definition: services.h:884
#define BOTSERV
Definition: modules.h:57
E int chan_get_user_status(Channel *chan, User *user)
Definition: channels.c:109
u_int32_t uint32
Definition: db-merger.c:123
E char * BSFantasyCharacter
Definition: extern.h:427
E dbFILE * open_db(const char *service, const char *filename, const char *mode, uint32 version)
Definition: datafiles.c:295
E void alog(const char *fmt,...) FORMAT(printf
#define SAFE(x)
Definition: botserv.c:478
time_t lastmsg
Definition: services.h:581
#define BS_DONTKICKOPS
Definition: services.h:793
E int UseTS6
Definition: extern.h:364
int16_t int16
Definition: db-merger.c:120
#define TTB_REVERSES
Definition: services.h:813
#define EVENT_BOT_FANTASY_NO_ACCESS
Definition: events.h:25
void bot_raw_ban(User *requester, ChannelInfo *ci, char *nick, char *reason)
Definition: botserv.c:916
char nick[NICKMAX]
Definition: services.h:418
E int debug
Definition: extern.h:775
#define E
Definition: extern.h:18
#define BW_SINGLE
Definition: services.h:647
static time_t lastwarn
Definition: datafiles.c:19
#define CUS_OWNER
Definition: services.h:1344
int16 lines
Definition: services.h:980
#define CI_SIGNKICK
Definition: services.h:737
int16 floodlines
Definition: services.h:706
struct c_userlist * next
Definition: services.h:1016
#define CI_SIGNKICK_LEVEL
Definition: services.h:739
#define whosends(ci)
Definition: extern.h:163
char * mask
Definition: services.h:965
#define EVENT_BOT_FANTASY
Definition: events.h:24
E int skeleton
Definition: extern.h:778
BanData * bd
Definition: services.h:1022
time_t created
Definition: services.h:578
BanData * prev
Definition: services.h:963
E void anope_cmd_bot_chan_mode(char *nick, char *chan)
Definition: ircd.c:324
void botmsgs(User *u, BotInfo *bi, char *buf)
Definition: botserv.c:107
int rdb_clean_table(char *table)
Definition: rdb.c:113
EList * bans
Definition: services.h:1012
#define tolower
Definition: services.h:190
E void anope_cmd_mode(char *source, char *dest, const char *fmt,...)
Definition: ircd.c:211
BanData * next
Definition: services.h:963
static void bot_kick(ChannelInfo *ci, User *u, int message,...)
Definition: botserv.c:883
E int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
#define EVENT_BOT_UNASSIGN
Definition: events.h:20
char * host
Definition: services.h:575
E void do_cmode(const char *source, int ac, char **av)
Definition: channels.c:1183
BotInfo * next
Definition: services.h:571
static void check_ban(ChannelInfo *ci, User *u, int ttbtype)
Definition: botserv.c:830
int rdb_open()
Definition: rdb.c:31
E IgnoreData * get_ignore(const char *nick)
Definition: process.c:106
int16 floodsecs
Definition: services.h:706
uint32 tsmode
Definition: services.h:381
E void anope_cmd_privmsg(char *source, char *dest, const char *fmt,...)
Definition: ircd.c:296
Entry * entries
Definition: services.h:1033
int16 * ttb
Definition: services.h:701
char * nick
Definition: services.h:573
char name[CHANMAX]
Definition: services.h:1000
#define GET_USER(u)
Definition: services.h:270
#define EVENT_BOT_KICK
Definition: events.h:28
Definition: services.h:416
char * normalizeBuffer(char *buf)
Definition: botserv.c:1101
int16 capsmin
Definition: services.h:705
static UserData * get_user_data(Channel *c, User *u)
Definition: botserv.c:707
int rdb_tag_table(char *table)
Definition: rdb.c:75
E void * smalloc(long size)
Definition: memory.c:30
uint16 in_use
Definition: services.h:641
int ts6
Definition: services.h:366
int16 repeattimes
Definition: services.h:707
#define BS_KICK_REVERSES
Definition: services.h:803
#define EVENT_BOT_BAN
Definition: events.h:29
E int get_access(User *user, ChannelInfo *ci)
Definition: chanserv.c:2332
char * mask
Definition: services.h:1042
E int read_int32(uint32 *ret, dbFILE *f)
Definition: datafiles.c:444
MDE void mod_run_cmd(char *service, User *u, CommandHash *cmdTable[], const char *cmd)
Definition: commands.c:67
E int write_string(const char *s, dbFILE *f)
Definition: db-merger.c:1826
uint32 limit
Definition: services.h:1007
BotInfo * bi
Definition: services.h:699
E void anope_cmd_ctcp(char *source, char *dest, const char *fmt,...)
Definition: ircd.c:672
#define TTB_BOLDS
Definition: services.h:811
E int BSGentleBWReason
Definition: extern.h:425
E int write_int32(uint32 val, dbFILE *f)
Definition: db-merger.c:1773
char * user
Definition: services.h:574
ChannelInfo * next
Definition: services.h:653
E char * common_get_vhost(User *u)
Definition: actions.c:251
E char * BotDBName
Definition: extern.h:335
#define BUFSIZE
Definition: config.h:47
E int anope_get_invite_mode()
Definition: ircd.c:1221
#define BS_KICK_COLORS
Definition: services.h:802
E void moduleAddBotServCmds(void)
Definition: botserv.c:36
#define CUS_OP
Definition: services.h:1341
E void anope_cmd_notice_ops(char *source, char *dest, const char *fmt,...)
Definition: ircd.c:244
E char * common_get_vident(User *u)
Definition: actions.c:272
NickAlias * na
Definition: services.h:892
#define BS_DONTKICKVOICES
Definition: services.h:794
struct channel_::c_userlist * users
void botchanmsgs(User *u, ChannelInfo *ci, char *buf)
Definition: botserv.c:130
#define BOT_VERSION
Definition: services.h:461
time_t last_use
Definition: services.h:967
u_int16_t uint16
Definition: db-merger.c:121