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