]> jfr.im git - irc/quakenet/newserv.git/blob - qabot/qabot_chancommands.c
r595@blue (orig r485): slug | 2006-05-04 18:02:24 +0100
[irc/quakenet/newserv.git] / qabot / qabot_chancommands.c
1 #include <stdio.h>
2 #include <time.h>
3
4 #include "../nick/nick.h"
5 #include "../localuser/localuserchannel.h"
6 #include "../core/hooks.h"
7 #include "../core/schedule.h"
8 #include "../lib/array.h"
9 #include "../lib/base64.h"
10 #include "../lib/irc_string.h"
11 #include "../lib/splitline.h"
12
13 #include "qabot.h"
14
15 int qabot_dochananswer(void* np, int cargc, char** cargv) {
16 nick* sender = (nick*)np;
17 qab_bot* bot = qabot_getcurrentbot();
18 int id;
19 char* ch;
20 qab_question* q;
21
22 if (cargc < 2) {
23 sendnoticetouser(bot->np, sender, "Syntax: !answer <id> <answer>");
24 return CMD_ERROR;
25 }
26
27 id = strtol(cargv[0], NULL, 10);
28 ch = cargv[1];
29
30 if ((id < 1) || (id > bot->lastquestionID)) {
31 sendnoticetouser(bot->np, sender, "Invalid question ID %d.", id);
32 return CMD_ERROR;
33 }
34
35 for (q = bot->questions[id % QUESTIONHASHSIZE]; q; q = q->next)
36 if (q->id == id)
37 break;
38
39 if (!q) {
40 sendnoticetouser(bot->np, sender, "Can't find question %d.", id);
41 return CMD_ERROR;
42 }
43
44 switch (q->flags & QAQ_QSTATE) {
45 case QAQ_ANSWERED:
46 sendnoticetouser(bot->np, sender, "Question %d has already been answered.", id);
47 return CMD_ERROR;
48
49 case QAQ_OFFTOPIC:
50 sendnoticetouser(bot->np, sender, "Question %d has been marked as off-topic.", id);
51 return CMD_ERROR;
52
53 case QAQ_SPAM:
54 sendnoticetouser(bot->np, sender, "Question %d has been marked as spam.", id);
55 return CMD_ERROR;
56
57 default:
58 break;
59 }
60
61 q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_ANSWERED;
62 q->answer = strdup(ch);
63
64 bot->answered++;
65
66 if (!bot->nextspam && !bot->micnumeric) {
67 sendmessagetochannel(bot->np, bot->public_chan->channel, "%s asked: %s", q->nick, q->question);
68 sendmessagetochannel(bot->np, bot->public_chan->channel, "%s answers: %s", sender->nick, ch);
69 }
70 else {
71 qab_answer* a;
72
73 a = (qab_answer*)malloc(sizeof(qab_answer));
74 a->question = q;
75 strncpy(a->nick, sender->nick, NICKLEN);
76 a->nick[NICKLEN] = '\0';
77 a->next = bot->answers;
78 bot->answers = a;
79
80 sendnoticetouser(bot->np, sender, "Can't send your answer right now. Answer was stored and will be sent later on.");
81 return CMD_OK;
82 }
83
84 sendnoticetouser(bot->np, sender, "Answer to question %d has been sent and stored.", id);
85
86 return CMD_OK;
87 }
88
89 int qabot_dochanblock(void* np, int cargc, char** cargv) {
90 nick* sender = (nick*)np;
91 qab_bot* bot = qabot_getcurrentbot();
92 qab_block* b;
93
94 if (cargc < 1) {
95 sendnoticetouser(bot->np, sender, "Syntax: !block [-q|-t] <account|mask>");
96 return CMD_ERROR;
97 }
98
99 if (cargc > 1) {
100 if (!ircd_strncmp(cargv[0], "-q", 2)) {
101 /* account block */
102 char* target = cargv[1];
103
104 if (*target == '#') {
105 target++;
106
107 if (strchr(target, '*') || strchr(target, '?')) {
108 sendnoticetouser(bot->np, sender, "Wildcard account blocks are not supported.");
109 return CMD_ERROR;
110 }
111 }
112 else {
113 nick* tnick;
114
115 if (!(tnick = getnickbynick(target))) {
116 sendnoticetouser(bot->np, sender, "Couldn't find user %s.", target);
117 return CMD_ERROR;
118 }
119
120 if (!IsAccount(tnick)) {
121 sendnoticetouser(bot->np, sender, "%s is not authed.", tnick->nick);
122 return CMD_ERROR;
123 }
124
125 target = tnick->authname;
126 }
127
128 b = (qab_block*)malloc(sizeof(qab_block));
129 b->type = QABBLOCK_ACCOUNT;
130 b->created = time(0);
131 strncpy(b->creator, IsAccount(sender) ? sender->authname : "UNKNOWN", ACCOUNTLEN);
132 b->creator[ACCOUNTLEN] = '\0';
133 b->blockstr = strdup(target);
134 b->prev = 0;
135 b->next = bot->blocks;
136 if (bot->blocks)
137 bot->blocks->prev = b;
138 bot->blocks = b;
139 bot->block_count++;
140
141 sendnoticetouser(bot->np, sender, "Now blocking all messages from users with accountname %s.", target);
142
143 if (bot->flags & QAB_BLOCKMARK) {
144 qab_question* q;
145 int i, spamqcount = 0;
146 nick* qnick;
147
148 for (i = 0; i < QUESTIONHASHSIZE; i++) {
149 for (q = bot->questions[i]; q; q = q->next) {
150 if ((q->flags & QAQ_QSTATE) != QAQ_NEW)
151 continue;
152
153 if (!(qnick = getnickbynumeric(q->numeric)))
154 continue;
155
156 if (!IsAccount(qnick))
157 continue;
158
159 if (ircd_strcmp(qnick->authname, b->blockstr))
160 continue;
161
162 q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_SPAM;
163 spamqcount++;
164 }
165 }
166
167 sendnoticetouser(bot->np, sender, "Block caused %d message%s to be marked as spam.", spamqcount, (spamqcount == 1) ? "" : "s");
168 }
169 }
170 else if (!ircd_strncmp(cargv[0], "-t", 2)) {
171 /* text block */
172 char* mask = cargv[1];
173
174 b = (qab_block*)malloc(sizeof(qab_block));
175 b->type = QABBLOCK_TEXT;
176 b->created = time(0);
177 strncpy(b->creator, sender->authname, ACCOUNTLEN);
178 b->creator[ACCOUNTLEN] = '\0';
179 b->blockstr = strdup(mask);
180 b->prev = 0;
181 b->next = bot->blocks;
182 if (bot->blocks)
183 bot->blocks->prev = b;
184 bot->blocks = b;
185 bot->block_count++;
186
187 sendnoticetouser(bot->np, sender, "Now blocking all questions which match %s.", mask);
188
189 if (bot->flags & QAB_BLOCKMARK) {
190 qab_question* q;
191 int i, spamqcount = 0;
192
193 for (i = 0; i < QUESTIONHASHSIZE; i++) {
194 for (q = bot->questions[i]; q; q = q->next) {
195 if ((q->flags & QAQ_QSTATE) != QAQ_NEW)
196 continue;
197
198 if (match(b->blockstr, q->question))
199 continue;
200
201 q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_SPAM;
202 spamqcount++;
203 }
204 }
205
206 sendnoticetouser(bot->np, sender, "Block caused %d message%s to be marked as spam.", spamqcount, (spamqcount == 1) ? "" : "s");
207 }
208 }
209 else {
210 sendnoticetouser(bot->np, sender, "Invalid flag.");
211 return CMD_ERROR;
212 }
213 }
214 else {
215 /* hostmask block */
216 char* mask = cargv[0];
217
218 if (!strchr(mask, '@') || !strchr(mask, '!')) {
219 sendnoticetouser(bot->np, sender, "%s is not a valid hostmask.", mask);
220 return CMD_ERROR;
221 }
222
223 b = (qab_block*)malloc(sizeof(qab_block));
224 b->type = QABBLOCK_HOST;
225 b->created = time(0);
226 strncpy(b->creator, sender->authname, ACCOUNTLEN);
227 b->creator[ACCOUNTLEN] = '\0';
228 b->blockstr = strdup(mask);
229 b->prev = 0;
230 b->next = bot->blocks;
231 if (bot->blocks)
232 bot->blocks->prev = b;
233 bot->blocks = b;
234 bot->block_count++;
235
236 sendnoticetouser(bot->np, sender, "Now blocking all messages from users with a hostmask matching %s.", mask);
237
238 if (bot->flags & QAB_BLOCKMARK) {
239 qab_question* q;
240 int i, spamqcount = 0;
241 nick* qnick;
242 char hostbuf[NICKLEN + USERLEN + HOSTLEN + 3];
243
244 for (i = 0; i < QUESTIONHASHSIZE; i++) {
245 for (q = bot->questions[i]; q; q = q->next) {
246 if ((q->flags & QAQ_QSTATE) != QAQ_NEW)
247 continue;
248
249 if (!(qnick = getnickbynumeric(q->numeric)))
250 continue;
251
252 sprintf(hostbuf,"%s!%s@%s", qnick->nick, qnick->ident, qnick->host->name->content);
253
254 if (match(b->blockstr, hostbuf))
255 continue;
256
257 q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_SPAM;
258 spamqcount++;
259 }
260 }
261
262 sendnoticetouser(bot->np, sender, "Block caused %d message%s to be marked as spam.", spamqcount, (spamqcount == 1) ? "" : "s");
263 }
264 }
265
266 return CMD_OK;
267 }
268
269 int qabot_dochanclear(void* np, int cargc, char** cargv) {
270 qab_bot* bot = qabot_getcurrentbot();
271 channel* cp = qabot_getcurrentchannel();
272 qab_spam* s;
273 qab_spam* ns;
274
275 for (s = bot->nextspam; s; s = ns) {
276 ns = s->next;
277 free(s->message);
278 free(s);
279 }
280
281 bot->nextspam = bot->lastspam = 0;
282
283 sendmessagetochannel(bot->np, cp, "Cleared message buffer.");
284 if (bot->micnumeric) {
285 bot->micnumeric = 0;
286 sendmessagetochannel(bot->np, cp, "Mic deactivated.");
287 }
288
289 return CMD_OK;
290 }
291
292 int qabot_dochanclosechan(void* np, int cargc, char** cargv) {
293 nick* sender = (nick*)np;
294 qab_bot* bot = qabot_getcurrentbot();
295 modechanges changes;
296
297 localsetmodeinit(&changes, bot->public_chan->channel, bot->np);
298 localdosetmode_simple(&changes, CHANMODE_INVITEONLY, 0);
299 localsetmodeflush(&changes, 1);
300 sendnoticetouser(bot->np, sender, "Public channel has been closed.");
301
302 return CMD_OK;
303 }
304
305 int qabot_dochanconfig(void* np, int cargc, char** cargv) {
306 nick* sender = (nick*)np;
307 qab_bot* bot = qabot_getcurrentbot();
308 char* opt;
309 char* value;
310
311 if (cargc < 1) {
312 sendnoticetouser(bot->np, sender, "Syntax: !config <option> [<value>]");
313 sendnoticetouser(bot->np, sender, "Displays or sets configuration option. Valid options are:");
314 sendnoticetouser(bot->np, sender, "blockcontrol - Block questions containing control chars.");
315 sendnoticetouser(bot->np, sender, "blockcolour - Block questions containing colour.");
316 sendnoticetouser(bot->np, sender, "blockmark - Mark questions affected by blocks as spam.");
317 sendnoticetouser(bot->np, sender, "authedonly - Accept questions from authed users only.");
318 sendnoticetouser(bot->np, sender, "linebreak - Separate questions with line breaks.");
319 sendnoticetouser(bot->np, sender, "flooddetect - Attempt to detect floodclone spam.");
320 sendnoticetouser(bot->np, sender, "floodblock - Automatically block floodclone spam.");
321 sendnoticetouser(bot->np, sender, "spamint - Text spam interval.");
322 sendnoticetouser(bot->np, sender, "nickblockint - Time to wait before sending another question.");
323 sendnoticetouser(bot->np, sender, "queuedqint - Queued answer spam interval.");
324 sendnoticetouser(bot->np, sender, "mictimeout - Idle time before mic is automatically disabled.");
325 return CMD_ERROR;
326 }
327
328 opt = cargv[0];
329 if (cargc == 2)
330 value = cargv[1];
331 else
332 value = 0;
333
334 if (!ircd_strcmp(opt, "blockcontrol")) {
335 if (value) {
336 if (!ircd_strcmp(value, "on")) {
337 bot->flags |= QAB_CONTROLCHAR;
338 sendnoticetouser(bot->np, sender, "Questions containing control characters will now be blocked.");
339 }
340 else if (!ircd_strcmp(value, "off")) {
341 bot->flags &= (~QAB_CONTROLCHAR);
342 sendnoticetouser(bot->np, sender, "Questions containing control characters will no longer be blocked.");
343 }
344 else
345 sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");
346 }
347 else
348 sendnoticetouser(bot->np, sender, "Control characters are currently %s blocked.", (bot->flags & QAB_CONTROLCHAR) ? "being" : "not being");
349 }
350 else if (!ircd_strcmp(opt, "blockcolour")) {
351 if (value) {
352 if (!ircd_strcmp(value, "on")) {
353 bot->flags |= QAB_COLOUR;
354 sendnoticetouser(bot->np, sender, "Questions containing colour will now be blocked.");
355 }
356 else if (!ircd_strcmp(value, "off")) {
357 bot->flags &= (~QAB_COLOUR);
358 sendnoticetouser(bot->np, sender, "Questions containing colour will no longer be blocked.");
359 }
360 else
361 sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");
362 }
363 else
364 sendnoticetouser(bot->np, sender, "Colours are currently %s blocked.", (bot->flags & QAB_COLOUR) ? "being" : "not being");
365 }
366 else if (!ircd_strcmp(opt, "blockmark")) {
367 if (value) {
368 if (!ircd_strcmp(value, "on")) {
369 bot->flags |= QAB_BLOCKMARK;
370 sendnoticetouser(bot->np, sender, "New blocks will automatically mark affected questions as spam.");
371 }
372 else if (!ircd_strcmp(value, "off")) {
373 bot->flags &= (~QAB_BLOCKMARK);
374 sendnoticetouser(bot->np, sender, "New blocks will no longer automatically mark affected questions as spam.");
375 }
376 else
377 sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");
378 }
379 else
380 sendnoticetouser(bot->np, sender, "Blocks are currently %smarking affected questions as spam.", (bot->flags & QAB_BLOCKMARK) ? "" : "not ");
381 }
382 else if (!ircd_strcmp(opt, "authedonly")) {
383 if (value) {
384 if (!ircd_strcmp(value, "on")) {
385 bot->flags |= QAB_AUTHEDONLY;
386 sendnoticetouser(bot->np, sender, "Questions from unauthed users will now be blocked.");
387 }
388 else if (!ircd_strcmp(value, "off")) {
389 bot->flags &= (~QAB_AUTHEDONLY);
390 sendnoticetouser(bot->np, sender, "Questions from unauthed users will no longer be blocked.");
391 }
392 else
393 sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");
394 }
395 else
396 sendnoticetouser(bot->np, sender, "Unauthed users may currently %ssend questions.", (bot->flags & QAB_AUTHEDONLY) ? "NOT " : "");
397 }
398 else if (!ircd_strcmp(opt, "linebreak")) {
399 if (value) {
400 if (!ircd_strcmp(value, "on")) {
401 bot->flags |= QAB_LINEBREAK;
402 sendnoticetouser(bot->np, sender, "Line breaks are now enabled.");
403 }
404 else if (!ircd_strcmp(value, "off")) {
405 bot->flags &= (~QAB_LINEBREAK);
406 sendnoticetouser(bot->np, sender, "Line breaks are now disabled.");
407 }
408 else
409 sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");
410 }
411 else
412 sendnoticetouser(bot->np, sender, "Line breaks are currently %s.", (bot->flags & QAB_LINEBREAK) ? "enabled" : "disabled");
413 }
414 else if (!ircd_strcmp(opt, "flooddetect")) {
415 if (value) {
416 if (!ircd_strcmp(value, "on")) {
417 bot->flags |= QAB_FLOODDETECT;
418 sendnoticetouser(bot->np, sender, "Flood detection is now enabled.");
419 }
420 else if (!ircd_strcmp(value, "off")) {
421 bot->flags &= (~QAB_FLOODDETECT);
422 sendnoticetouser(bot->np, sender, "Flood detection is now disabled.");
423 }
424 else
425 sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");
426 }
427 else
428 sendnoticetouser(bot->np, sender, "Flood detection is currently %s.", (bot->flags & QAB_FLOODDETECT) ? "enabled" : "disabled");
429 }
430 else if (!ircd_strcmp(opt, "floodblock")) {
431 if (value) {
432 if (!ircd_strcmp(value, "on")) {
433 bot->flags |= QAB_FLOODSTOP;
434 sendnoticetouser(bot->np, sender, "Flood blocking is now enabled.");
435 }
436 else if (!ircd_strcmp(value, "off")) {
437 bot->flags &= (~QAB_FLOODSTOP);
438 sendnoticetouser(bot->np, sender, "Flood blocking is now disabled.");
439 }
440 else
441 sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");
442 }
443 else
444 sendnoticetouser(bot->np, sender, "Flood blocking is currently %s.", (bot->flags & QAB_FLOODSTOP) ? "enabled" : "disabled");
445 }
446 else if (!ircd_strcmp(opt, "mictimeout")) {
447 if (value) {
448 int v = (int)strtol(value, NULL, 10);
449
450 if ((v < 0) || (v > 300)) {
451 sendnoticetouser(bot->np, sender, "Value must be between 0 (off) and 300.");
452 return CMD_ERROR;
453 }
454
455 bot->mic_timeout = v;
456 sendnoticetouser(bot->np, sender, "Value set.");
457 }
458 else {
459 if (bot->mic_timeout)
460 sendnoticetouser(bot->np, sender, "Mic timeout is currently %d second%s.", bot->mic_timeout, (bot->mic_timeout == 1) ? "" : "s");
461 else
462 sendnoticetouser(bot->np, sender, "Mic timeout is currently disabled.");
463 }
464 }
465 else if (!ircd_strcmp(opt, "spamint")) {
466 if (value) {
467 int v = (int)strtol(value, NULL, 10);
468
469 if ((v < 1) || (v > 30)) {
470 sendnoticetouser(bot->np, sender, "Value must be between 1 and 30.");
471 return CMD_ERROR;
472 }
473
474 bot->spam_interval = v;
475 sendnoticetouser(bot->np, sender, "Value set.");
476 }
477 else
478 sendnoticetouser(bot->np, sender, "Spam interval is currently %d second%s.", bot->spam_interval, (bot->spam_interval == 1) ? "" : "s");
479 }
480 else if (!ircd_strcmp(opt, "nickblockint")) {
481 if (value) {
482 int v = (int)strtol(value, NULL, 10);
483
484 if ((v < 1) || (v > 300)) {
485 sendnoticetouser(bot->np, sender, "Value must be between 1 and 300.");
486 return CMD_ERROR;
487 }
488
489 bot->ask_wait = v;
490 sendnoticetouser(bot->np, sender, "Value set.");
491 }
492 else
493 sendnoticetouser(bot->np, sender, "Nick block interval is currently %d second%s.", bot->ask_wait, (bot->ask_wait == 1) ? "" : "s");
494 }
495 else if (!ircd_strcmp(opt, "queuedqint")) {
496 if (value) {
497 int v = (int)strtol(value, NULL, 10);
498
499 if ((v < 1) || (v > 20)) {
500 sendnoticetouser(bot->np, sender, "Value must be between 1 and 20.");
501 return CMD_ERROR;
502 }
503
504 bot->queued_question_interval = v;
505 sendnoticetouser(bot->np, sender, "Value set.");
506 }
507 else
508 sendnoticetouser(bot->np, sender, "Queued question interval is currently %d second%s.", bot->queued_question_interval, (bot->queued_question_interval == 1) ? "" : "s");
509 }
510 else
511 sendnoticetouser(bot->np, sender, "Invalid configuration option.");
512
513 return CMD_OK;
514 }
515
516 int qabot_dochanhelp(void* np, int cargc, char** cargv) {
517 nick* sender = (nick*)np;
518 qab_bot* bot = qabot_getcurrentbot();
519 char* ch;
520
521 if (cargc < 1)
522 ch = "";
523 else
524 ch = cargv[0];
525
526 if (*ch) {
527 if (!ircd_strcmp(ch, "mic")) {
528 sendnoticetouser(bot->np, sender, "Syntax: !mic");
529 sendnoticetouser(bot->np, sender, "Turn the microphone on or off. When turned on, anything said by the microphone holder is relayed to %s.", bot->public_chan->name->content);
530 }
531 else if (!ircd_strcmp(ch, "clear")) {
532 sendnoticetouser(bot->np, sender, "Syntax: !clear");
533 sendnoticetouser(bot->np, sender, "Clear currently queued text to relay, and turn off the microphone.");
534 }
535 else if (!ircd_strcmp(ch, "ping")) {
536 sendnoticetouser(bot->np, sender, "Syntax: !ping");
537 sendnoticetouser(bot->np, sender, "Pings the bot.");
538 }
539 else if (!ircd_strcmp(ch, "config")) {
540 sendnoticetouser(bot->np, sender, "Syntax: !config <option|help> [<value>]");
541 sendnoticetouser(bot->np, sender, "Display or set bot configuration options.");
542 }
543 else if (!ircd_strcmp(ch, "answer")) {
544 sendnoticetouser(bot->np, sender, "Syntax: !answer <id> <answer>");
545 sendnoticetouser(bot->np, sender, "Answer a question.");
546 }
547 else if (!ircd_strcmp(ch, "block")) {
548 sendnoticetouser(bot->np, sender, "Syntax: !block [<-q|-t>] <mask>");
549 sendnoticetouser(bot->np, sender, "Add a block, where:");
550 sendnoticetouser(bot->np, sender, "-q: blocks a Q account.");
551 sendnoticetouser(bot->np, sender, "-t: blocks question text.");
552 sendnoticetouser(bot->np, sender, "No flag results in a hostmask block.");
553 }
554 else if (!ircd_strcmp(ch, "listblocks")) {
555 sendnoticetouser(bot->np, sender, "Syntax: !listblocks");
556 sendnoticetouser(bot->np, sender, "View the currently added blocks.");
557 }
558 else if (!ircd_strcmp(ch, "spam")) {
559 sendnoticetouser(bot->np, sender, "Syntax: !spam <id>");
560 sendnoticetouser(bot->np, sender, "Mark a question as spam. This stops it being answered.");
561 }
562 else if (!ircd_strcmp(ch, "offtopic")) {
563 sendnoticetouser(bot->np, sender, "Syntax: !offtopic <id>");
564 sendnoticetouser(bot->np, sender, "Mark a question as off-topic. This stops it being answered.");
565 }
566 else if (!ircd_strcmp(ch, "unblock")) {
567 sendnoticetouser(bot->np, sender, "Syntax: !unblock [<-q|-t>] <mask>");
568 sendnoticetouser(bot->np, sender, "Removes a block. See \"!help block\" for a description of the flags.");
569 }
570 else if (!ircd_strcmp(ch, "reset")) {
571 sendnoticetouser(bot->np, sender, "Syntax: !reset <all|questions|blocks|stats>");
572 sendnoticetouser(bot->np, sender, "Reset the questions, blocks or both; or the stats.");
573 }
574 else if (!ircd_strcmp(ch, "closechan")) {
575 sendnoticetouser(bot->np, sender, "Syntax: !closechan");
576 sendnoticetouser(bot->np, sender, "Closes the public channel.");
577 }
578 else if (!ircd_strcmp(ch, "openchan")) {
579 sendnoticetouser(bot->np, sender, "Syntax: !openchan");
580 sendnoticetouser(bot->np, sender, "Opens the public channel.");
581 }
582 else if (!ircd_strcmp(ch, "status")) {
583 sendnoticetouser(bot->np, sender, "Syntax: !status");
584 sendnoticetouser(bot->np, sender, "Displays some status information and statistics.");
585 }
586 else if (!ircd_strcmp(ch, "help")) {
587 sendnoticetouser(bot->np, sender, "Syntax !help [<command>]");
588 sendnoticetouser(bot->np, sender, "List available commands or view help for a particular command.");
589 }
590 else {
591 sendnoticetouser(bot->np, sender, "No help available for '%s'.", ch);
592 }
593 }
594 else {
595 sendnoticetouser(bot->np, sender, "The following channel commands are recognised:");
596 sendnoticetouser(bot->np, sender, "!answer - Answer a question.");
597 sendnoticetouser(bot->np, sender, "!block - Block a hostmask, account or string.");
598 sendnoticetouser(bot->np, sender, "!clear - Clear currently queued text to spam.");
599 sendnoticetouser(bot->np, sender, "!closechan - Close the public channel.");
600 sendnoticetouser(bot->np, sender, "!config - Display or set bot configuration options.");
601 sendnoticetouser(bot->np, sender, "!help - List commands or view the help for a command");
602 sendnoticetouser(bot->np, sender, "!listblocks - List currently added blocks.");
603 sendnoticetouser(bot->np, sender, "!mic - Turn the microphone on or off.");
604 sendnoticetouser(bot->np, sender, "!offtopic - Mark a question or questions as off-topic.");
605 sendnoticetouser(bot->np, sender, "!openchan - Open the public channel.");
606 sendnoticetouser(bot->np, sender, "!ping - Ping the bot.");
607 sendnoticetouser(bot->np, sender, "!reset - Clear all blocks, questions or both.");
608 sendnoticetouser(bot->np, sender, "!spam - Mark a question or questions as spam.");
609 sendnoticetouser(bot->np, sender, "!status - Display some status statistics.");
610 sendnoticetouser(bot->np, sender, "!unblock - Remove a block.");
611 sendnoticetouser(bot->np, sender, "End of list.");
612 }
613
614 return CMD_OK;
615 }
616
617 int qabot_dochanlistblocks(void* np, int cargc, char** cargv) {
618 nick* sender = (nick*)np;
619 qab_bot* bot = qabot_getcurrentbot();
620 qab_block* b;
621
622 if (!(b = bot->blocks)) {
623 sendnoticetouser(bot->np, sender, "There are no blocks currently added.");
624 return CMD_ERROR;
625 }
626
627 sendnoticetouser(bot->np, sender, "Type: Hostmask/Account/Textmask:");
628
629 for (; b; b = b->next) {
630 if (b->type == QABBLOCK_ACCOUNT)
631 sendnoticetouser(bot->np, sender, "A %s", b->blockstr);
632 else if (b->type == QABBLOCK_HOST)
633 sendnoticetouser(bot->np, sender, "H %s", b->blockstr);
634 else
635 sendnoticetouser(bot->np, sender, "T %s", b->blockstr);
636 }
637
638 sendnoticetouser(bot->np, sender, "End of list.");
639
640 return CMD_OK;
641 }
642
643 int qabot_dochanmic(void* np, int cargc, char** cargv) {
644 nick* sender = (nick*)np;
645 qab_bot* bot = qabot_getcurrentbot();
646 channel* cp = qabot_getcurrentchannel();
647
648 if (bot->micnumeric) {
649 if (bot->micnumeric == sender->numeric) {
650 bot->micnumeric = 0;
651 sendmessagetochannel(bot->np, cp, "Mic deactivated.");
652 if (!bot->lastspam)
653 qabot_spamstored((void*)bot);
654 }
655 else {
656 bot->lastmic = time(NULL);
657 bot->micnumeric = sender->numeric;
658 sendmessagetochannel(bot->np, cp, "%s now has the mic. Anything said by %s will be relayed in %s.",
659 sender->nick, sender->nick, bot->public_chan->name->content);
660 deleteschedule(0, qabot_spamstored, (void*)bot);
661 }
662 }
663 else {
664 bot->lastmic = time(NULL);
665 bot->micnumeric = sender->numeric;
666 sendmessagetochannel(bot->np, cp, "Mic activated. Anything said by %s will be relayed in %s.",
667 sender->nick, bot->public_chan->name->content);
668 deleteschedule(0, qabot_spamstored, (void*)bot);
669 }
670
671 return CMD_OK;
672 }
673
674 int qabot_dochanmoo(void* np, int cargc, char** cargv) {
675 qab_bot* bot = qabot_getcurrentbot();
676 char moostr[50];
677 int i, moocount = 5 + (rand() % 40);
678 channel* cp = qabot_getcurrentchannel();
679
680 moostr[0] = 'm';
681 for (i = 1; i < moocount; i++)
682 moostr[i] = ((rand() % 100) > 50) ? 'o': '0';
683 moostr[i] = '\0';
684
685 sendmessagetochannel(bot->np, cp, "%s", moostr);
686
687 return CMD_OK;
688 }
689
690 int qabot_dochanofftopic(void* np, int cargc, char** cargv) {
691 nick* sender = (nick*)np;
692 qab_bot* bot = qabot_getcurrentbot();
693 int id;
694 int i;
695 qab_question* q;
696
697 if (cargc < 1) {
698 sendnoticetouser(bot->np, sender, "Syntax: !spam <id> [<id> ... <id>]");
699 return CMD_ERROR;
700 }
701
702 for (i = 0; i < cargc; i++) {
703 id = strtol(cargv[i], NULL, 10);
704
705 if ((id < 1) || (id > bot->lastquestionID)) {
706 sendnoticetouser(bot->np, sender, "Invalid question ID %d.", id);
707 continue;
708 }
709
710 for (q = bot->questions[id % QUESTIONHASHSIZE]; q; q = q->next)
711 if (q->id == id)
712 break;
713
714 if (!q) {
715 sendnoticetouser(bot->np, sender, "Can't find question %d.", id);
716 continue;
717 }
718
719 switch (q->flags & QAQ_QSTATE) {
720 case QAQ_ANSWERED:
721 sendnoticetouser(bot->np, sender, "Question %d has already been answered.", id);
722 continue;
723
724 case QAQ_OFFTOPIC:
725 sendnoticetouser(bot->np, sender, "Question %d has already been marked as off-topic.", id);
726 continue;
727
728 case QAQ_SPAM:
729 sendnoticetouser(bot->np, sender, "Question %d has already been marked as spam.", id);
730 continue;
731
732 default:
733 break;
734 }
735
736 q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_OFFTOPIC;
737 sendnoticetouser(bot->np, sender, "Question %d has been marked as off-topic.", id);
738 }
739
740 return CMD_OK;
741 }
742
743 int qabot_dochanopenchan(void* np, int cargc, char** cargv) {
744 nick* sender = (nick*)np;
745 qab_bot* bot = qabot_getcurrentbot();
746 modechanges changes;
747
748 localsetmodeinit(&changes, bot->public_chan->channel, bot->np);
749 localdosetmode_simple(&changes, CHANMODE_MODERATE|CHANMODE_DELJOINS, CHANMODE_INVITEONLY);
750 localsetmodeflush(&changes, 1);
751 sendnoticetouser(bot->np, sender, "Public channel has been opened.");
752
753 return CMD_OK;
754 }
755
756 int qabot_dochanping(void* np, int cargc, char** cargv) {
757 qab_bot* bot = qabot_getcurrentbot();
758 channel* cp = qabot_getcurrentchannel();
759
760 sendmessagetochannel(bot->np, cp, "pong!");
761
762 return CMD_OK;
763 }
764
765 int qabot_dochanreset(void* np, int cargc, char** cargv) {
766 nick* sender = (nick*)np;
767 qab_bot* bot = qabot_getcurrentbot();
768 int r = 0;
769
770 if (cargc < 1) {
771 sendnoticetouser(bot->np, sender, "Syntax: !reset <blocks|questions|stats|all>");
772 return CMD_ERROR;
773 }
774
775 if (!ircd_strcmp(cargv[0], "blocks"))
776 r = 1;
777 else if (!ircd_strcmp(cargv[0], "questions"))
778 r = 2;
779 else if (!ircd_strcmp(cargv[0], "stats"))
780 r = 4;
781 else if (!ircd_strcmp(cargv[0], "all"))
782 r = 3;
783 else {
784 sendnoticetouser(bot->np, sender, "Unknown parameter: %s.", cargv[0]);
785 return CMD_ERROR;
786 }
787
788 if (r & 1) {
789 qab_block* b;
790
791 while (bot->blocks) {
792 b = bot->blocks;
793 bot->blocks = bot->blocks->next;
794 if (b->blockstr)
795 free(b->blockstr);
796 free(b);
797 }
798
799 bot->block_count = 0;
800
801 sendnoticetouser(bot->np, sender, "Reset (blocks): Done.");
802 }
803
804 if (r & 2) {
805 qab_question* q;
806 int i;
807
808 for (i = 0; i < QUESTIONHASHSIZE; i++) {
809 while (bot->questions[i]) {
810 q = bot->questions[i];
811 bot->questions[i] = bot->questions[i]->next;
812 if (q->question)
813 free(q->question);
814 if (q->answer)
815 free(q->answer);
816 free(q);
817 }
818 }
819
820 bot->lastquestionID = 0;
821 bot->answered = 0;
822
823 sendnoticetouser(bot->np, sender, "Reset (questions): Done.");
824 }
825
826 if (r & 4) {
827 bot->answered = 0;
828 bot->spammed = 0;
829 sendnoticetouser(bot->np, sender, "Reset (stats): Done.");
830 }
831
832 return CMD_OK;
833 }
834
835 int qabot_dochanspam(void* np, int cargc, char** cargv) {
836 nick* sender = (nick*)np;
837 qab_bot* bot = qabot_getcurrentbot();
838 int id;
839 int i;
840 qab_question* q;
841
842 if (cargc < 1) {
843 sendnoticetouser(bot->np, sender, "Syntax: !spam <id> [<id> ... <id>]");
844 return CMD_ERROR;
845 }
846
847 for (i = 0; i < cargc; i++) {
848 id = strtol(cargv[i], NULL, 10);
849
850 if ((id < 1) || (id > bot->lastquestionID)) {
851 sendnoticetouser(bot->np, sender, "Invalid question ID %d.", id);
852 continue;
853 }
854
855 for (q = bot->questions[id % QUESTIONHASHSIZE]; q; q = q->next)
856 if (q->id == id)
857 break;
858
859 if (!q) {
860 sendnoticetouser(bot->np, sender, "Can't find question %d.", id);
861 continue;
862 }
863
864 switch (q->flags & QAQ_QSTATE) {
865 case QAQ_ANSWERED:
866 sendnoticetouser(bot->np, sender, "Question %d has already been answered.", id);
867 continue;
868
869 case QAQ_OFFTOPIC:
870 sendnoticetouser(bot->np, sender, "Question %d has already been marked as off-topic.", id);
871 continue;
872
873 case QAQ_SPAM:
874 sendnoticetouser(bot->np, sender, "Question %d has already been marked as spam.", id);
875 continue;
876
877 default:
878 break;
879 }
880
881 q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_SPAM;
882 sendnoticetouser(bot->np, sender, "Question %d has been marked as spam.", id);
883 }
884
885 return CMD_OK;
886 }
887
888 int qabot_dochanstatus(void* np, int cargc, char** cargv) {
889 nick* sender = (nick*)np;
890 qab_bot* bot = qabot_getcurrentbot();
891
892 sendnoticetouser(bot->np, sender, "Lines spammed: %d", bot->spammed);
893 sendnoticetouser(bot->np, sender, "Questions asked: %d", bot->lastquestionID);
894 sendnoticetouser(bot->np, sender, "Questions answered: %d", bot->answered);
895 sendnoticetouser(bot->np, sender, "Blocks: %d", bot->block_count);
896 /*sendnoticetouser(bot->np, sender, "Question interval: %d seconds", bot->question_interval);*/
897 sendnoticetouser(bot->np, sender, "Spam interval: %d seconds", bot->spam_interval);
898 sendnoticetouser(bot->np, sender, "Nick block interval: %d seconds", bot->ask_wait);
899 sendnoticetouser(bot->np, sender, "Queued question interval: %d seconds", bot->queued_question_interval);
900 sendnoticetouser(bot->np, sender, "Block control chars: %s", (bot->flags & QAB_CONTROLCHAR) ? "Yes" : "No");
901 sendnoticetouser(bot->np, sender, "Block colour: %s", (bot->flags & QAB_COLOUR) ? "Yes" : "No");
902 sendnoticetouser(bot->np, sender, "Authed users only: %s", (bot->flags & QAB_AUTHEDONLY) ? "Yes" : "No");
903 sendnoticetouser(bot->np, sender, "Line break: %s", (bot->flags & QAB_LINEBREAK) ? "Yes" : "No");
904 sendnoticetouser(bot->np, sender, "Question flood detection: %s", (bot->flags & QAB_FLOODDETECT) ? "Yes" : "No");
905 sendnoticetouser(bot->np, sender, "Question flood blocking: %s", (bot->flags & QAB_FLOODSTOP) ? "Yes" : "No");
906 sendnoticetouser(bot->np, sender, "Blocks mark as spam: %s", (bot->flags & QAB_BLOCKMARK) ? "Yes" : "No");
907 if (bot->micnumeric) {
908 nick* mnick = getnickbynumeric(bot->micnumeric);
909
910 sendnoticetouser(bot->np, np, "Mic: Enabled (%s)", mnick ? mnick->nick : "UNKNOWN");
911 }
912 else
913 sendnoticetouser(bot->np, np, "Mic: Disabled");
914 sendnoticetouser(bot->np, sender, "Mic timeout: %d", bot->mic_timeout);
915 /*sendnoticetouser(bot->np, sender, "");*/
916
917 return CMD_OK;
918 }
919
920 int qabot_dochanunblock(void* np, int cargc, char** cargv) {
921 nick* sender = (nick*)np;
922 qab_bot* bot = qabot_getcurrentbot();
923 char* ch;
924 qab_block* b;
925 char type = -1;
926
927 if (cargc < 1) {
928 sendnoticetouser(bot->np, sender, "Syntax: !unblock [-q|-t] <account|mask>");
929 return CMD_ERROR;
930 }
931
932 if (cargc > 1) {
933 if (!ircd_strncmp(cargv[0], "-q", 2)) {
934 type = QABBLOCK_ACCOUNT;
935 ch = cargv[1];
936
937 if (*ch == '#')
938 ch++;
939 }
940 else if (!ircd_strncmp(cargv[0], "-t", 2)) {
941 type = QABBLOCK_TEXT;
942 ch = cargv[1];
943 }
944 else {
945 sendnoticetouser(bot->np, sender, "Invalid flag.");
946 return CMD_ERROR;
947 }
948 }
949 else {
950 type = QABBLOCK_HOST;
951 ch = cargv[0];
952 }
953
954 for (b = bot->blocks; b; b = b->next) {
955 if (b->type != type)
956 continue;
957
958 if (!ircd_strcmp(b->blockstr, ch)) {
959 if (b->next)
960 b->next->prev = b->prev;
961 if (b->prev)
962 b->prev->next = b->next;
963 else
964 bot->blocks = b->next;
965
966 free(b->blockstr);
967 free(b);
968
969 bot->block_count--;
970
971 sendnoticetouser(bot->np, sender, "Block removed.");
972 return CMD_OK;
973 }
974 }
975
976 sendnoticetouser(bot->np, sender, "No such block.");
977
978 return CMD_ERROR;
979 }