Anope IRC Services  Version 1.8
bs_badwords.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_badwords(User * u);
18 static void myBotServHelp(User * u);
19 static int badwords_del_callback(User * u, int num, va_list args);
20 static int badwords_list(User * u, int index, ChannelInfo * ci, int *sent_header);
21 static int badwords_list_callback(User * u, int num, va_list args);
22 
29 int AnopeInit(int argc, char **argv)
30 {
31  Command *c;
32 
33  moduleAddAuthor("Anope");
34  moduleAddVersion(VERSION_STRING);
36 
37  c = createCommand("BADWORDS", do_badwords, NULL, BOT_HELP_BADWORDS, -1,
38  -1, -1, -1);
40 
42 
43  return MOD_CONT;
44 }
45 
49 void AnopeFini(void)
50 {
51 
52 }
53 
54 
55 
60 static void myBotServHelp(User * u)
61 {
62  notice_lang(s_BotServ, u, BOT_HELP_CMD_BADWORDS);
63 }
64 
70 static int do_badwords(User * u)
71 {
72  char *chan = strtok(NULL, " ");
73  char *cmd = strtok(NULL, " ");
74  char *word = strtok(NULL, "");
75  ChannelInfo *ci;
76  BadWord *bw;
77 
78  int i;
79  int need_args = (cmd
80  && (!stricmp(cmd, "LIST") || !stricmp(cmd, "CLEAR")));
81 
82  if (!cmd || (need_args ? 0 : !word)) {
83  syntax_error(s_BotServ, u, "BADWORDS", BOT_BADWORDS_SYNTAX);
84  } else if (!(ci = cs_findchan(chan))) {
85  notice_lang(s_BotServ, u, CHAN_X_NOT_REGISTERED, chan);
86  } else if (ci->flags & CI_VERBOTEN) {
87  notice_lang(s_BotServ, u, CHAN_X_FORBIDDEN, chan);
88  } else if (!check_access(u, ci, CA_BADWORDS)
89  && (!need_args || !is_services_admin(u))) {
90  notice_lang(s_BotServ, u, ACCESS_DENIED);
91  } else if (stricmp(cmd, "ADD") == 0) {
92 
93  char *opt, *pos;
94  int type = BW_ANY;
95 
96  if (readonly) {
97  notice_lang(s_BotServ, u, BOT_BADWORDS_DISABLED);
98  return MOD_CONT;
99  }
100 
101  pos = strrchr(word, ' ');
102  if (pos) {
103  opt = pos + 1;
104  if (*opt) {
105  if (!stricmp(opt, "SINGLE"))
106  type = BW_SINGLE;
107  else if (!stricmp(opt, "START"))
108  type = BW_START;
109  else if (!stricmp(opt, "END"))
110  type = BW_END;
111  if (type != BW_ANY)
112  *pos = 0;
113  }
114  }
115 
116  for (bw = ci->badwords, i = 0; i < ci->bwcount; bw++, i++) {
117  if (bw->word && ((BSCaseSensitive && (!strcmp(bw->word, word)))
118  || (!BSCaseSensitive
119  && (!stricmp(bw->word, word))))) {
120  notice_lang(s_BotServ, u, BOT_BADWORDS_ALREADY_EXISTS,
121  bw->word, ci->name);
122  return MOD_CONT;
123  }
124  }
125 
126  for (i = 0; i < ci->bwcount; i++) {
127  if (!ci->badwords[i].in_use)
128  break;
129  }
130  if (i == ci->bwcount) {
131  if (i < BSBadWordsMax) {
132  ci->bwcount++;
133  ci->badwords =
134  srealloc(ci->badwords, sizeof(BadWord) * ci->bwcount);
135  } else {
136  notice_lang(s_BotServ, u, BOT_BADWORDS_REACHED_LIMIT,
137  BSBadWordsMax);
138  return MOD_CONT;
139  }
140  }
141  bw = &ci->badwords[i];
142  bw->in_use = 1;
143  bw->word = sstrdup(word);
144  bw->type = type;
145 
146  alog("%s: %s!%s@%s added badword \"%s\" to %s",
147  s_BotServ, u->nick, u->username, u->host, bw->word, ci->name);
148  notice_lang(s_BotServ, u, BOT_BADWORDS_ADDED, bw->word, ci->name);
149 
150  } else if (stricmp(cmd, "DEL") == 0) {
151  int deleted = 0, a, b;
152 
153  if (readonly) {
154  notice_lang(s_BotServ, u, BOT_BADWORDS_DISABLED);
155  return MOD_CONT;
156  }
157 
158  /* Special case: is it a number/list? Only do search if it isn't. */
159  if (isdigit(*word) && strspn(word, "1234567890,-") == strlen(word)) {
160  int count, last = -1;
161  deleted =
162  process_numlist(word, &count, badwords_del_callback, u, ci,
163  &last);
164  if (!deleted) {
165  if (count == 1) {
166  notice_lang(s_BotServ, u, BOT_BADWORDS_NO_SUCH_ENTRY,
167  last, ci->name);
168  } else {
169  notice_lang(s_BotServ, u, BOT_BADWORDS_NO_MATCH,
170  ci->name);
171  }
172  } else if (deleted == 1) {
173  alog("%s: %s!%s@%s deleted 1 badword from %s",
174  s_BotServ, u->nick, u->username, u->host, ci->name);
175  notice_lang(s_BotServ, u, BOT_BADWORDS_DELETED_ONE,
176  ci->name);
177  } else {
178  alog("%s: %s!%s@%s deleted %d badwords from %s",
179  s_BotServ, u->nick, u->username, u->host, deleted, ci->name);
180  notice_lang(s_BotServ, u, BOT_BADWORDS_DELETED_SEVERAL,
181  deleted, ci->name);
182  }
183  } else {
184  for (i = 0; i < ci->bwcount; i++) {
185  if (ci->badwords[i].in_use
186  && !stricmp(ci->badwords[i].word, word))
187  break;
188  }
189  if (i == ci->bwcount) {
190  notice_lang(s_BotServ, u, BOT_BADWORDS_NOT_FOUND, word,
191  chan);
192  return MOD_CONT;
193  }
194  bw = &ci->badwords[i];
195  alog("%s: %s!%s@%s deleted badword \"%s\" from %s",
196  s_BotServ, u->nick, u->username, u->host, bw->word, ci->name);
197  notice_lang(s_BotServ, u, BOT_BADWORDS_DELETED, bw->word,
198  ci->name);
199  if (bw->word)
200  free(bw->word);
201  bw->word = NULL;
202  bw->in_use = 0;
203  deleted = 1;
204  }
205 
206  if (deleted) {
207  /* Reordering - DrStein */
208  for (b = 0; b < ci->bwcount; b++) {
209  if (ci->badwords[b].in_use) {
210  for (a = 0; a < ci->bwcount; a++) {
211  if (a > b)
212  break;
213  if (!(ci->badwords[a].in_use)) {
214  ci->badwords[a].in_use = ci->badwords[b].in_use;
215  ci->badwords[a].type = ci->badwords[b].type;
216  if (ci->badwords[b].word) {
217  ci->badwords[a].word = sstrdup(ci->badwords[b].word);
218  free(ci->badwords[b].word);
219  }
220  ci->badwords[b].word = NULL;
221  ci->badwords[b].in_use = 0;
222  break;
223  }
224  }
225  }
226  }
227  /* After reordering only the entries at the end could still be empty.
228  * We ll free the places no longer in use... - Viper */
229  for (i = ci->bwcount - 1; i >= 0; i--) {
230  if (ci->badwords[i].in_use)
231  break;
232  ci->bwcount--;
233  }
234  ci->badwords =
235  srealloc(ci->badwords,sizeof(BadWord) * ci->bwcount);
236  }
237 
238  } else if (stricmp(cmd, "LIST") == 0) {
239  int sent_header = 0;
240 
241  if (ci->bwcount == 0) {
242  notice_lang(s_BotServ, u, BOT_BADWORDS_LIST_EMPTY, chan);
243  return MOD_CONT;
244  }
245  if (word && strspn(word, "1234567890,-") == strlen(word)) {
246  process_numlist(word, NULL, badwords_list_callback, u, ci,
247  &sent_header);
248  } else {
249  for (i = 0; i < ci->bwcount; i++) {
250  if (!(ci->badwords[i].in_use))
251  continue;
252  if (word && ci->badwords[i].word
253  && !match_wild_nocase(word, ci->badwords[i].word))
254  continue;
255  badwords_list(u, i, ci, &sent_header);
256  }
257  }
258  if (!sent_header)
259  notice_lang(s_BotServ, u, BOT_BADWORDS_NO_MATCH, chan);
260 
261  } else if (stricmp(cmd, "CLEAR") == 0) {
262 
263  if (readonly) {
264  notice_lang(s_BotServ, u, BOT_BADWORDS_DISABLED);
265  return MOD_CONT;
266  }
267 
268  for (i = 0; i < ci->bwcount; i++)
269  if (ci->badwords[i].word)
270  free(ci->badwords[i].word);
271 
272  free(ci->badwords);
273  ci->badwords = NULL;
274  ci->bwcount = 0;
275 
276  alog("%s: %s!%s@%s cleared badwords on %s",
277  s_BotServ, u->nick, u->username, u->host, ci->name);
278  notice_lang(s_BotServ, u, BOT_BADWORDS_CLEAR);
279 
280  } else {
281  syntax_error(s_BotServ, u, "BADWORDS", BOT_BADWORDS_SYNTAX);
282  }
283  return MOD_CONT;
284 }
285 
286 static int badwords_del_callback(User * u, int num, va_list args)
287 {
288  BadWord *bw;
289  ChannelInfo *ci = va_arg(args, ChannelInfo *);
290  int *last = va_arg(args, int *);
291 
292  *last = num;
293 
294  if (num < 1 || num > ci->bwcount)
295  return 0;
296 
297  bw = &ci->badwords[num - 1];
298  if (bw->word)
299  free(bw->word);
300  bw->word = NULL;
301  bw->in_use = 0;
302 
303  return 1;
304 }
305 
306 static int badwords_list(User * u, int index, ChannelInfo * ci, int *sent_header)
307 {
308  BadWord *bw = &ci->badwords[index];
309 
310  if (!bw->in_use)
311  return 0;
312  if (!*sent_header) {
313  notice_lang(s_BotServ, u, BOT_BADWORDS_LIST_HEADER, ci->name);
314  *sent_header = 1;
315  }
316 
317  notice_lang(s_BotServ, u, BOT_BADWORDS_LIST_FORMAT, index + 1,
318  bw->word,
319  ((bw->type ==
320  BW_SINGLE) ? "(SINGLE)" : ((bw->type ==
321  BW_START) ? "(START)"
322  : ((bw->type ==
323  BW_END) ? "(END)" : "")))
324  );
325  return 1;
326 }
327 
328 static int badwords_list_callback(User * u, int num, va_list args)
329 {
330  ChannelInfo *ci = va_arg(args, ChannelInfo *);
331  int *sent_header = va_arg(args, int *);
332  if (num < 1 || num > ci->bwcount)
333  return 0;
334  return badwords_list(u, num - 1, ci, sent_header);
335 }
E size_t strspn(const char *s, const char *accept)
Definition: compat.c:106
E int process_numlist(const char *numstr, int *count_ret, range_callback_t callback, User *u,...)
Definition: misc.c:292
E int readonly
Definition: extern.h:776
E int match_wild_nocase(const char *pattern, const char *str)
Definition: misc.c:268
char nick[NICKMAX]
Definition: services.h:875
char * word
Definition: services.h:642
void AnopeFini(void)
Definition: bs_badwords.c:49
E char * s_BotServ
Definition: extern.h:287
#define BW_START
Definition: services.h:648
uint16 type
Definition: services.h:643
#define BW_END
Definition: services.h:649
E int check_access(User *user, ChannelInfo *ci, int what)
Definition: chanserv.c:1974
E int stricmp(const char *s1, const char *s2)
Definition: compat.c:58
static int badwords_list_callback(User *u, int num, va_list args)
Definition: bs_badwords.c:328
#define CI_VERBOTEN
Definition: services.h:725
char * host
Definition: services.h:878
MDE void moduleAddAuthor(const char *author)
Definition: modules.c:1772
E void syntax_error(char *service, User *u, const char *command, int msgnum)
Definition: language.c:295
char name[CHANMAX]
Definition: services.h:654
E void notice_lang(char *source, User *dest, int message,...)
Definition: send.c:169
MDE void moduleSetType(MODType type)
Definition: modules.c:818
E int BSBadWordsMax
Definition: extern.h:423
E int BSCaseSensitive
Definition: extern.h:426
E char * sstrdup(const char *s)
Definition: memory.c:105
BadWord * badwords
Definition: services.h:704
uint32 flags
Definition: services.h:669
uint16 bwcount
Definition: services.h:703
MDE void moduleAddVersion(const char *version)
Definition: modules.c:1760
#define BW_ANY
Definition: services.h:646
static int badwords_del_callback(User *u, int num, va_list args)
Definition: bs_badwords.c:286
Command * c
Definition: ns_recover.c:17
#define BOTSERV
Definition: modules.h:57
E void alog(const char *fmt,...) FORMAT(printf
#define MOD_CONT
Definition: modules.h:54
static void myBotServHelp(User *u)
Definition: bs_badwords.c:60
#define CA_BADWORDS
Definition: services.h:763
MDE void moduleSetBotHelp(void(*func)(User *u))
Definition: modules.c:2114
E int is_services_admin(User *u)
Definition: operserv.c:591
int AnopeInit(int argc, char **argv)
Definition: bs_badwords.c:29
#define BW_SINGLE
Definition: services.h:647
char * username
Definition: services.h:877
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
static int badwords_list(User *u, int index, ChannelInfo *ci, int *sent_header)
Definition: bs_badwords.c:306
E ChannelInfo * cs_findchan(const char *chan)
Definition: db-merger.c:2000
E void * srealloc(void *oldptr, long newsize)
Definition: memory.c:80
uint16 in_use
Definition: services.h:641
static int do_badwords(User *u)
Definition: bs_badwords.c:70
MDE int moduleAddCommand(CommandHash *cmdTable[], Command *c, int pos)
Definition: modules.c:1082
#define MOD_UNIQUE
Definition: module.h:11