]> jfr.im git - irc/quakenet/newserv.git/blob - qabot/qabot_chancommands.c
Initial Import
[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 if (bot->recording_section) {
282 sendmessagetochannel(bot->np, cp, "Deactivate recorder before using clear.");
283 return CMD_ERROR;
284 }
285
286 for (s = bot->nextspam; s; s = ns) {
287 ns = s->next;
288 free(s->message);
289 free(s);
290 }
291
292 bot->nextspam = bot->lastspam = 0;
293
294 sendmessagetochannel(bot->np, cp, "Cleared message buffer.");
295 if (bot->micnumeric) {
296 bot->micnumeric = 0;
297 sendmessagetochannel(bot->np, cp, "Mic deactivated.");
298 }
299
300 return CMD_OK;
301 }
302
303 int qabot_dochanclosechan(void* np, int cargc, char** cargv) {
304 nick* sender = (nick*)np;
305 qab_bot* bot = qabot_getcurrentbot();
306 channel* cp = qabot_getcurrentchannel();
307 modechanges changes;
308
309 localsetmodeinit(&changes, bot->public_chan->channel, bot->np);
310 localdosetmode_simple(&changes, CHANMODE_INVITEONLY, 0);
311 localsetmodeflush(&changes, 1);
312 sendnoticetouser(bot->np, sender, "Public channel has been closed.");
313
314 return CMD_OK;
315 }
316
317 int qabot_dochanconfig(void* np, int cargc, char** cargv) {
318 nick* sender = (nick*)np;
319 qab_bot* bot = qabot_getcurrentbot();
320 channel* cp = qabot_getcurrentchannel();
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 channel* cp = qabot_getcurrentchannel();
533 char* ch;
534
535 if (cargc < 1)
536 ch = "";
537 else
538 ch = cargv[0];
539
540 if (*ch) {
541 if (!ircd_strcmp(ch, "mic")) {
542 sendnoticetouser(bot->np, sender, "Syntax: !mic");
543 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);
544 }
545 else if (!ircd_strcmp(ch, "clear")) {
546 sendnoticetouser(bot->np, sender, "Syntax: !clear");
547 sendnoticetouser(bot->np, sender, "Clear currently queued text to relay, and turn off the microphone.");
548 }
549 else if (!ircd_strcmp(ch, "ping")) {
550 sendnoticetouser(bot->np, sender, "Syntax: !ping");
551 sendnoticetouser(bot->np, sender, "Pings the bot.");
552 }
553 else if (!ircd_strcmp(ch, "config")) {
554 sendnoticetouser(bot->np, sender, "Syntax: !config <option|help> [<value>]");
555 sendnoticetouser(bot->np, sender, "Display or set bot configuration options.");
556 }
557 else if (!ircd_strcmp(ch, "answer")) {
558 sendnoticetouser(bot->np, sender, "Syntax: !answer <id> <answer>");
559 sendnoticetouser(bot->np, sender, "Answer a question.");
560 }
561 else if (!ircd_strcmp(ch, "block")) {
562 sendnoticetouser(bot->np, sender, "Syntax: !block [<-q|-t>] <mask>");
563 sendnoticetouser(bot->np, sender, "Add a block, where:");
564 sendnoticetouser(bot->np, sender, "-q: blocks a Q account.");
565 sendnoticetouser(bot->np, sender, "-t: blocks question text.");
566 sendnoticetouser(bot->np, sender, "No flag results in a hostmask block.");
567 }
568 else if (!ircd_strcmp(ch, "listblocks")) {
569 sendnoticetouser(bot->np, sender, "Syntax: !listblocks");
570 sendnoticetouser(bot->np, sender, "View the currently added blocks.");
571 }
572 else if (!ircd_strcmp(ch, "spam")) {
573 sendnoticetouser(bot->np, sender, "Syntax: !spam <id>");
574 sendnoticetouser(bot->np, sender, "Mark a question as spam. This stops it being answered.");
575 }
576 else if (!ircd_strcmp(ch, "offtopic")) {
577 sendnoticetouser(bot->np, sender, "Syntax: !offtopic <id>");
578 sendnoticetouser(bot->np, sender, "Mark a question as off-topic. This stops it being answered.");
579 }
580 else if (!ircd_strcmp(ch, "unblock")) {
581 sendnoticetouser(bot->np, sender, "Syntax: !unblock [<-q|-t>] <mask>");
582 sendnoticetouser(bot->np, sender, "Removes a block. See \"!help block\" for a description of the flags.");
583 }
584 else if (!ircd_strcmp(ch, "reset")) {
585 sendnoticetouser(bot->np, sender, "Syntax: !reset <all|questions|blocks|stats>");
586 sendnoticetouser(bot->np, sender, "Reset the questions, blocks or both; or the stats.");
587 }
588 else if (!ircd_strcmp(ch, "closechan")) {
589 sendnoticetouser(bot->np, sender, "Syntax: !closechan");
590 sendnoticetouser(bot->np, sender, "Closes the public channel.");
591 }
592 else if (!ircd_strcmp(ch, "openchan")) {
593 sendnoticetouser(bot->np, sender, "Syntax: !openchan");
594 sendnoticetouser(bot->np, sender, "Opens the public channel.");
595 }
596 else if (!ircd_strcmp(ch, "status")) {
597 sendnoticetouser(bot->np, sender, "Syntax: !status");
598 sendnoticetouser(bot->np, sender, "Displays some status information and statistics.");
599 }
600 else if (!ircd_strcmp(ch, "help")) {
601 sendnoticetouser(bot->np, sender, "Syntax !help [<command>]");
602 sendnoticetouser(bot->np, sender, "List available commands or view help for a particular command.");
603 }
604 else {
605 sendnoticetouser(bot->np, sender, "No help available for '%s'.", ch);
606 }
607 }
608 else {
609 sendnoticetouser(bot->np, sender, "The following channel commands are recognised:");
610 sendnoticetouser(bot->np, sender, "!answer - Answer a question.");
611 sendnoticetouser(bot->np, sender, "!block - Block a hostmask, account or string.");
612 sendnoticetouser(bot->np, sender, "!clear - Clear currently queued text to spam.");
613 sendnoticetouser(bot->np, sender, "!closechan - Close the public channel.");
614 sendnoticetouser(bot->np, sender, "!config - Display or set bot configuration options.");
615 sendnoticetouser(bot->np, sender, "!help - List commands or view the help for a command");
616 sendnoticetouser(bot->np, sender, "!listblocks - List currently added blocks.");
617 sendnoticetouser(bot->np, sender, "!mic - Turn the microphone on or off.");
618 sendnoticetouser(bot->np, sender, "!offtopic - Mark a question or questions as off-topic.");
619 sendnoticetouser(bot->np, sender, "!openchan - Open the public channel.");
620 sendnoticetouser(bot->np, sender, "!ping - Ping the bot.");
621 sendnoticetouser(bot->np, sender, "!reset - Clear all blocks, questions or both.");
622 sendnoticetouser(bot->np, sender, "!spam - Mark a question or questions as spam.");
623 sendnoticetouser(bot->np, sender, "!status - Display some status statistics.");
624 sendnoticetouser(bot->np, sender, "!unblock - Remove a block.");
625 sendnoticetouser(bot->np, sender, "End of list.");
626 }
627
628 return CMD_OK;
629 }
630
631 int qabot_dochanlistblocks(void* np, int cargc, char** cargv) {
632 nick* sender = (nick*)np;
633 qab_bot* bot = qabot_getcurrentbot();
634 channel* cp = qabot_getcurrentchannel();
635 qab_block* b;
636
637 if (!(b = bot->blocks)) {
638 sendnoticetouser(bot->np, sender, "There are no blocks currently added.");
639 return;
640 }
641
642 sendnoticetouser(bot->np, sender, "Type: Hostmask/Account/Textmask:");
643
644 for (; b; b = b->next) {
645 if (b->type == QABBLOCK_ACCOUNT)
646 sendnoticetouser(bot->np, sender, "A %s", b->blockstr);
647 else if (b->type == QABBLOCK_HOST)
648 sendnoticetouser(bot->np, sender, "H %s", b->blockstr);
649 else
650 sendnoticetouser(bot->np, sender, "T %s", b->blockstr);
651 }
652
653 sendnoticetouser(bot->np, sender, "End of list.");
654
655 return CMD_OK;
656 }
657
658 int qabot_dochanmic(void* np, int cargc, char** cargv) {
659 nick* sender = (nick*)np;
660 qab_bot* bot = qabot_getcurrentbot();
661 channel* cp = qabot_getcurrentchannel();
662
663 if (bot->recording_section)
664 sendmessagetochannel(bot->np, cp, "Deactivate recorder before attempting to use mic.");
665 else if (bot->micnumeric) {
666 if (bot->micnumeric == sender->numeric) {
667 bot->micnumeric = 0;
668 sendmessagetochannel(bot->np, cp, "Mic deactivated.");
669 if (!bot->lastspam)
670 qabot_spamstored((void*)bot);
671 }
672 else {
673 bot->lastmic = time(NULL);
674 bot->micnumeric = sender->numeric;
675 sendmessagetochannel(bot->np, cp, "%s now has the mic. Anything said by %s will be relayed in %s.",
676 sender->nick, sender->nick, bot->public_chan->name->content);
677 deleteschedule(0, qabot_spamstored, (void*)bot);
678 }
679 }
680 else {
681 bot->lastmic = time(NULL);
682 bot->micnumeric = sender->numeric;
683 sendmessagetochannel(bot->np, cp, "Mic activated. Anything said by %s will be relayed in %s.",
684 sender->nick, bot->public_chan->name->content);
685 deleteschedule(0, qabot_spamstored, (void*)bot);
686 }
687
688 return CMD_OK;
689 }
690
691 int qabot_dochanmoo(void* np, int cargc, char** cargv) {
692 nick* sender = (nick*)np;
693 qab_bot* bot = qabot_getcurrentbot();
694 channel* cp = qabot_getcurrentchannel();
695 char moostr[50];
696 int i, moocount = 5 + (rand() % 40);
697
698 moostr[0] = 'm';
699 for (i = 1; i < moocount; i++)
700 moostr[i] = ((rand() % 100) > 50) ? 'o': '0';
701 moostr[i] = '\0';
702
703 sendmessagetochannel(bot->np, cp, "%s", moostr);
704
705 return CMD_OK;
706 }
707
708 int qabot_dochanofftopic(void* np, int cargc, char** cargv) {
709 nick* sender = (nick*)np;
710 qab_bot* bot = qabot_getcurrentbot();
711 channel* cp = qabot_getcurrentchannel();
712 int id;
713 int i;
714 qab_question* q;
715
716 if (cargc < 1) {
717 sendnoticetouser(bot->np, sender, "Syntax: !spam <id> [<id> ... <id>]");
718 return CMD_ERROR;
719 }
720
721 for (i = 0; i < cargc; i++) {
722 id = strtol(cargv[i], NULL, 10);
723
724 if ((id < 1) || (id > bot->lastquestionID)) {
725 sendnoticetouser(bot->np, sender, "Invalid question ID %d.", id);
726 continue;
727 }
728
729 for (q = bot->questions[id % QUESTIONHASHSIZE]; q; q = q->next)
730 if (q->id == id)
731 break;
732
733 if (!q) {
734 sendnoticetouser(bot->np, sender, "Can't find question %d.", id);
735 continue;
736 }
737
738 switch (q->flags & QAQ_QSTATE) {
739 case QAQ_ANSWERED:
740 sendnoticetouser(bot->np, sender, "Question %d has already been answered.", id);
741 continue;
742
743 case QAQ_OFFTOPIC:
744 sendnoticetouser(bot->np, sender, "Question %d has already been marked as off-topic.", id);
745 continue;
746
747 case QAQ_SPAM:
748 sendnoticetouser(bot->np, sender, "Question %d has already been marked as spam.", id);
749 continue;
750
751 default:
752 break;
753 }
754
755 q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_OFFTOPIC;
756 sendnoticetouser(bot->np, sender, "Question %d has been marked as off-topic.", id);
757 }
758
759 return CMD_OK;
760 }
761
762 int qabot_dochanopenchan(void* np, int cargc, char** cargv) {
763 nick* sender = (nick*)np;
764 qab_bot* bot = qabot_getcurrentbot();
765 channel* cp = qabot_getcurrentchannel();
766 modechanges changes;
767
768 localsetmodeinit(&changes, bot->public_chan->channel, bot->np);
769 localdosetmode_simple(&changes, CHANMODE_MODERATE|CHANMODE_DELJOINS, CHANMODE_INVITEONLY);
770 localsetmodeflush(&changes, 1);
771 sendnoticetouser(bot->np, sender, "Public channel has been opened.");
772
773 return CMD_OK;
774 }
775
776 int qabot_dochanping(void* np, int cargc, char** cargv) {
777 nick* sender = (nick*)np;
778 qab_bot* bot = qabot_getcurrentbot();
779 channel* cp = qabot_getcurrentchannel();
780
781 sendmessagetochannel(bot->np, cp, "pong!");
782
783 return CMD_OK;
784 }
785
786 int qabot_dochanreset(void* np, int cargc, char** cargv) {
787 nick* sender = (nick*)np;
788 qab_bot* bot = qabot_getcurrentbot();
789 channel* cp = qabot_getcurrentchannel();
790 int r = 0;
791
792 if (cargc < 1) {
793 sendnoticetouser(bot->np, sender, "Syntax: !reset <blocks|questions|stats|all>");
794 return CMD_ERROR;
795 }
796
797 if (!ircd_strcmp(cargv[0], "blocks"))
798 r = 1;
799 else if (!ircd_strcmp(cargv[0], "questions"))
800 r = 2;
801 else if (!ircd_strcmp(cargv[0], "stats"))
802 r = 4;
803 else if (!ircd_strcmp(cargv[0], "all"))
804 r = 3;
805 else {
806 sendnoticetouser(bot->np, sender, "Unknown parameter: %s.", cargv[0]);
807 return;
808 }
809
810 if (r & 1) {
811 qab_block* b;
812
813 while (bot->blocks) {
814 b = bot->blocks;
815 bot->blocks = bot->blocks->next;
816 if (b->blockstr)
817 free(b->blockstr);
818 free(b);
819 }
820
821 bot->block_count = 0;
822
823 sendnoticetouser(bot->np, sender, "Reset (blocks): Done.");
824 }
825
826 if (r & 2) {
827 qab_question* q;
828 int i;
829
830 for (i = 0; i < QUESTIONHASHSIZE; i++) {
831 while (bot->questions[i]) {
832 q = bot->questions[i];
833 bot->questions[i] = bot->questions[i]->next;
834 if (q->question)
835 free(q->question);
836 if (q->answer)
837 free(q->answer);
838 free(q);
839 }
840 }
841
842 bot->lastquestionID = 0;
843 bot->answered = 0;
844
845 sendnoticetouser(bot->np, sender, "Reset (questions): Done.");
846 }
847
848 if (r & 4) {
849 bot->answered = 0;
850 bot->spammed = 0;
851 sendnoticetouser(bot->np, sender, "Reset (stats): Done.");
852 }
853
854 return CMD_OK;
855 }
856
857 int qabot_dochanspam(void* np, int cargc, char** cargv) {
858 nick* sender = (nick*)np;
859 qab_bot* bot = qabot_getcurrentbot();
860 channel* cp = qabot_getcurrentchannel();
861 int id;
862 int i;
863 qab_question* q;
864
865 if (cargc < 1) {
866 sendnoticetouser(bot->np, sender, "Syntax: !spam <id> [<id> ... <id>]");
867 return CMD_ERROR;
868 }
869
870 for (i = 0; i < cargc; i++) {
871 id = strtol(cargv[i], NULL, 10);
872
873 if ((id < 1) || (id > bot->lastquestionID)) {
874 sendnoticetouser(bot->np, sender, "Invalid question ID %d.", id);
875 continue;
876 }
877
878 for (q = bot->questions[id % QUESTIONHASHSIZE]; q; q = q->next)
879 if (q->id == id)
880 break;
881
882 if (!q) {
883 sendnoticetouser(bot->np, sender, "Can't find question %d.", id);
884 continue;
885 }
886
887 switch (q->flags & QAQ_QSTATE) {
888 case QAQ_ANSWERED:
889 sendnoticetouser(bot->np, sender, "Question %d has already been answered.", id);
890 continue;
891
892 case QAQ_OFFTOPIC:
893 sendnoticetouser(bot->np, sender, "Question %d has already been marked as off-topic.", id);
894 continue;
895
896 case QAQ_SPAM:
897 sendnoticetouser(bot->np, sender, "Question %d has already been marked as spam.", id);
898 continue;
899
900 default:
901 break;
902 }
903
904 q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_SPAM;
905 sendnoticetouser(bot->np, sender, "Question %d has been marked as spam.", id);
906 }
907
908 return CMD_OK;
909 }
910
911 int qabot_dochanstatus(void* np, int cargc, char** cargv) {
912 nick* sender = (nick*)np;
913 qab_bot* bot = qabot_getcurrentbot();
914 channel* cp = qabot_getcurrentchannel();
915
916 sendnoticetouser(bot->np, sender, "Lines spammed: %d", bot->spammed);
917 sendnoticetouser(bot->np, sender, "Questions asked: %d", bot->lastquestionID);
918 sendnoticetouser(bot->np, sender, "Questions answered: %d", bot->answered);
919 sendnoticetouser(bot->np, sender, "Blocks: %d", bot->block_count);
920 /*sendnoticetouser(bot->np, sender, "Question interval: %d seconds", bot->question_interval);*/
921 sendnoticetouser(bot->np, sender, "Spam interval: %d seconds", bot->spam_interval);
922 sendnoticetouser(bot->np, sender, "Nick block interval: %d seconds", bot->ask_wait);
923 sendnoticetouser(bot->np, sender, "Queued question interval: %d seconds", bot->queued_question_interval);
924 sendnoticetouser(bot->np, sender, "Block control chars: %s", (bot->flags & QAB_CONTROLCHAR) ? "Yes" : "No");
925 sendnoticetouser(bot->np, sender, "Block colour: %s", (bot->flags & QAB_COLOUR) ? "Yes" : "No");
926 sendnoticetouser(bot->np, sender, "Authed users only: %s", (bot->flags & QAB_AUTHEDONLY) ? "Yes" : "No");
927 sendnoticetouser(bot->np, sender, "Line break: %s", (bot->flags & QAB_LINEBREAK) ? "Yes" : "No");
928 sendnoticetouser(bot->np, sender, "Question flood detection: %s", (bot->flags & QAB_FLOODDETECT) ? "Yes" : "No");
929 sendnoticetouser(bot->np, sender, "Question flood blocking: %s", (bot->flags & QAB_FLOODSTOP) ? "Yes" : "No");
930 sendnoticetouser(bot->np, sender, "Blocks mark as spam: %s", (bot->flags & QAB_BLOCKMARK) ? "Yes" : "No");
931 if (bot->micnumeric) {
932 nick* mnick = getnickbynumeric(bot->micnumeric);
933
934 sendnoticetouser(bot->np, np, "Mic: Enabled (%s)", mnick ? mnick->nick : "UNKNOWN");
935 }
936 else
937 sendnoticetouser(bot->np, np, "Mic: Disabled");
938 sendnoticetouser(bot->np, sender, "Mic timeout: %d", bot->mic_timeout);
939 /*sendnoticetouser(bot->np, sender, "");*/
940
941 return CMD_OK;
942 }
943
944 int qabot_dochanunblock(void* np, int cargc, char** cargv) {
945 nick* sender = (nick*)np;
946 qab_bot* bot = qabot_getcurrentbot();
947 channel* cp = qabot_getcurrentchannel();
948 char* ch;
949 qab_block* b;
950 char type = -1;
951
952 if (cargc < 1) {
953 sendnoticetouser(bot->np, sender, "Syntax: !unblock [-q|-t] <account|mask>");
954 return CMD_ERROR;
955 }
956
957 if (cargc > 1) {
958 if (!ircd_strncmp(cargv[0], "-q", 2)) {
959 type = QABBLOCK_ACCOUNT;
960 ch = cargv[1];
961
962 if (*ch == '#')
963 ch++;
964 }
965 else if (!ircd_strncmp(cargv[0], "-t", 2)) {
966 type = QABBLOCK_TEXT;
967 ch = cargv[1];
968 }
969 else {
970 sendnoticetouser(bot->np, sender, "Invalid flag.");
971 return CMD_ERROR;
972 }
973 }
974 else {
975 type = QABBLOCK_HOST;
976 ch = cargv[0];
977 }
978
979 for (b = bot->blocks; b; b = b->next) {
980 if (b->type != type)
981 continue;
982
983 if (!ircd_strcmp(b->blockstr, ch)) {
984 if (b->next)
985 b->next->prev = b->prev;
986 if (b->prev)
987 b->prev->next = b->next;
988 else
989 bot->blocks = b->next;
990
991 free(b->blockstr);
992 free(b);
993
994 bot->block_count--;
995
996 sendnoticetouser(bot->np, sender, "Block removed.");
997 return CMD_OK;
998 }
999 }
1000
1001 sendnoticetouser(bot->np, sender, "No such block.");
1002
1003 return CMD_ERROR;
1004 }
1005
1006 int qabot_dochanlisttexts(void* np, int cargc, char** cargv) {
1007 nick* sender = (nick*)np;
1008 qab_bot* bot = qabot_getcurrentbot();
1009 qab_text* texts = bot->texts;
1010
1011 if (!texts) {
1012 sendnoticetouser(bot->np, sender, "There are no texts added.");
1013 return CMD_ERROR;
1014 }
1015
1016 sendnoticetouser(bot->np, sender, "Name: Sections:");
1017 for (; texts; texts = texts->next) {
1018 sendnoticetouser(bot->np, sender, "%-15s %d", texts->name, texts->section_count);
1019 }
1020
1021 sendnoticetouser(bot->np, sender, "End of list.");
1022
1023 return CMD_OK;
1024 }
1025
1026 int qabot_dochanshowsection(void* np, int cargc, char** cargv) {
1027 nick* sender = (nick*)np;
1028 qab_bot* bot = qabot_getcurrentbot();
1029 qab_text* texts = bot->texts;
1030 qab_textsection* section;
1031 int count = 0;
1032
1033 if (cargc < 2) {
1034 sendnoticetouser(bot->np, sender, "Syntax: !showsection <text name> <section number>");
1035 return CMD_ERROR;
1036 }
1037
1038 if (!texts) {
1039 sendnoticetouser(bot->np, sender, "There are no texts added.");
1040 return CMD_ERROR;
1041 }
1042
1043 id = (int)strtol(cargv[1]);
1044
1045 for (; texts; texts = texts->next) {
1046 if (!ircd_strcmp(texts->name, cargv[0])) {
1047 for (section = texts->sections; section && (count <= section->section_count); section = section->next) {
1048 if (++count == id) {
1049 qab_spam* lines;
1050 int lineno = 0;
1051
1052 sendnoticetouser(bot->np, sender, "Section %d (of text %s) contents:", count, texts->name);
1053 for (lines = section->lines; lines; lines = lines->next)
1054 sendnoticetouser(bot->np, sender, "%-2d> %s", ++lineno, lines->message);
1055 sendnoticetouser(bot->np, sender, "End of section.");
1056
1057 return CMD_OK;
1058 }
1059 }
1060 sendnoticetouser(bot->np, sender, "No such section.");
1061 return CMD_ERROR;
1062 }
1063 }
1064
1065 sendnoticetouser(bot->np, sender, "No such text.");
1066
1067 return CMD_ERROR;
1068 }
1069
1070 int qabot_dochanaddtext(void* np, int cargc, char** cargv) {
1071 nick* sender = (nick*)np;
1072 qab_bot* bot = qabot_getcurrentbot();
1073 qab_text* texts = bot->texts;
1074
1075 if (cargc < 1) {
1076 sendnoticetouser(bot->np, sender, "Syntax: !addtext <text name>");
1077 return CMD_ERROR;
1078 }
1079
1080 for (; texts; texts = texts->next) {
1081 if (!ircd_strcmp(texts->name, cargv[0])) {
1082 sendnoticetouser(bot->np, sender, "A text with this name already exists.");
1083 return CMD_ERROR;
1084 }
1085 }
1086
1087 texts = (qab_text*)malloc(sizeof(qab_text));
1088 strncpy(texts->name, cargc[0], NICKLEN);
1089 texts->name[NICKLEN] = '\0';
1090 texts->sections = 0;
1091 texts->sections_tail = 0;
1092 texts->section_count = 0;
1093 texts->next = bot->texts;
1094 texts->prev = 0;
1095 if (bot->texts)
1096 bot->texts->prev = texts;
1097 bot->texts = texts;
1098
1099 sendnoticetouser(bot->np, sender, "Added text '%s'.", texts->name);
1100
1101 return CMD_OK;
1102 }
1103
1104 int qabot_dochandeltext(void* np, int cargc, char** cargv) {
1105 nick* sender = (nick*)np;
1106 qab_bot* bot = qabot_getcurrentbot();
1107 qab_text* texts = bot->texts;
1108
1109 if (cargc < 1) {
1110 sendnoticetouser(bot->np, sender, "Syntax: !deltext <text name>");
1111 return CMD_ERROR;
1112 }
1113
1114 for (; texts; texts = texts->next) {
1115 if (!ircd_strcmp(texts->name, cargv[0])) {
1116 sendnoticetouser(bot->np, sender, "Text '%s' deleted.", texts->name);
1117 qabot_freetext(bot, texts);
1118 return CMD_OK;
1119 }
1120 }
1121
1122 sendnoticetouser(bot->np, sender, "No such text.");
1123
1124 return CMD_ERROR;
1125 }
1126
1127 int qabot_dochanaddsection(void* np, int cargc, char** cargv) {
1128 nick* sender = (nick*)np;
1129 qab_bot* bot = qabot_getcurrentbot();
1130 qab_text* texts = bot->texts;
1131 qab_textsection* section;
1132
1133 if (cargc < 1) {
1134 sendnoticetouser(bot->np, sender, "Syntax: !addsection <text name> [<section number>]");
1135 return CMD_ERROR;
1136 }
1137
1138 for (; texts; texts = texts->next) {
1139 if (!ircd_strcmp(texts->name, cargv[0])) {
1140 int num;
1141 if (cargc == 1 || !texts->sections_tail) {
1142 section = (qab_textsection*)malloc(sizeof(qab_textsection));
1143 section->lines = 0;
1144 section->lines_tail = 0;
1145 section->line_count = 0;
1146 section->prev = 0;
1147 section->next = 0;
1148 texts->sections = section;
1149 texts->sections_tail = section;
1150 texts->section_count++;
1151 num = 1;
1152 }
1153 else {
1154 }
1155
1156 sendnoticetouser(bot->np, sender, "Section %d added.", num);
1157 return CMD_OK;
1158 }
1159 }
1160
1161 sendnoticetouser(bot->np, sender, "No such text.");
1162
1163 return CMD_ERROR;
1164 }
1165
1166 int qabot_dochandelsection(void* np, int cargc, char** cargv) {
1167 nick* sender = (nick*)np;
1168 qab_bot* bot = qabot_getcurrentbot();
1169 qab_text* texts = bot->texts;
1170 qab_textsection* section;
1171
1172 if (cargc < 2) {
1173 sendnoticetouser(bot->np, sender, "Syntax: !delsection <text name> <section number>");
1174 return CMD_ERROR;
1175 }
1176
1177 for (; texts; texts = texts->next) {
1178 if (!ircd_strcmp(texts->name, cargv[0])) {
1179 for (section = texts->sections; section && (count <= section->section_count); section = section->next) {
1180 if (++count == id) {
1181 qabot_freesection(texts, section);
1182 sendnoticetouser(bot->np, sender, "Section deleted.");
1183 return CMD_OK;
1184 }
1185 }
1186 sendnoticetouser(bot->np, sender, "No such section.");
1187 return CMD_ERROR;
1188 }
1189 }
1190
1191 sendnoticetouser(bot->np, sender, "No such text.");
1192
1193 return CMD_ERROR;
1194 }
1195
1196 int qabot_dochanrecord(void* np, int cargc, char** cargv) {
1197 nick* sender = (nick*)np;
1198 qab_bot* bot = qabot_getcurrentbot();
1199 channel* cp = qabot_getcurrentchannel();
1200
1201 if (bot->recording_section) {
1202 if (bot->micnumeric == sender->numeric) {
1203 bot->micnumeric = 0;
1204 bot->recording_section = 0;
1205 sendmessagetochannel(bot->np, cp, "Recorder deactivated.");
1206 }
1207 else {
1208 sendmessagetochannel(bot->np, cp, "The recorder is already in use.");
1209 }
1210 }
1211 else if (bot->micnumeric)
1212 sendmessagetochannel(bot->np, cp, "Deactivate mic before attempting to use recorder.");
1213 else if (cargc >= 2) {
1214 qab_text* texts = bot->texts;
1215 qab_textsection* section;
1216 int id = (int)strtol(cargv[1]);
1217
1218 for (; texts; texts = texts->next) {
1219 if (!ircd_strcmp(texts->name, cargv[0])) {
1220 for (section = texts->sections; section && (count <= section->section_count); section = section->next) {
1221 if (++count == id) {
1222 bot->lastmic = time(NULL);
1223 bot->micnumeric = sender->numeric;
1224 bot->recording_section = count;
1225 sendmessagetochannel(bot->np, cp, "Recorder activated. Anything said by %s will be relayed in %s.",
1226 sender->nick, bot->public_chan->name->content);
1227 deleteschedule(0, qabot_spamstored, (void*)bot);
1228 return CMD_OK;
1229 }
1230 }
1231 sendnoticetouser(bot->np, sender, "No such section.");
1232 return CMD_ERROR;
1233 }
1234 }
1235
1236 sendnoticetouser(bot->np, sender, "No such text.");
1237 return CMD_ERROR;
1238 }
1239 else
1240 sendmessagetochannel(bot->np, cp, "syntax: !record [<text name> <section number>]");
1241
1242 return CMD_OK;
1243 }