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