]> jfr.im git - irc/quakenet/newserv.git/blame - qabot/qabot_bot.c
Merge default.
[irc/quakenet/newserv.git] / qabot / qabot_bot.c
CommitLineData
f011b15a
CP
1#include <stdio.h>
2#include <time.h>
3
4#include "../nick/nick.h"
5#include "../localuser/localuserchannel.h"
6#include "../core/hooks.h"
7#include "../core/schedule.h"
8#include "../lib/array.h"
9#include "../lib/base64.h"
10#include "../lib/irc_string.h"
11#include "../lib/splitline.h"
12
13#include "qabot.h"
14
15qab_bot* qabot_getbot() {
16 qab_bot* bot;
17 int i;
18
19 bot = (qab_bot*)malloc(sizeof(qab_bot));
20 bot->nick[0] = '\0';
21 bot->user[0] = '\0';
22 bot->host = 0;
23 bot->np = 0;
24 bot->public_chan = 0;
25 bot->question_chan = 0;
26 bot->staff_chan = 0;
27 bot->blocks = 0;
28 bot->block_count = 0;
29
30 bot->spammed = 0;
31
32 bot->flags = DEFAULTBOTFLAGS;
33
34 /*bot->question_interval = QUESTIONINTERVAL;*/
35 bot->spam_interval = SPAMINTERVAL;
36 bot->ask_wait = ASKWAIT;
37 bot->queued_question_interval = QUEUEDQUESTIONINTERVAL;
38
39 bot->lastquestionID = 0;
40 bot->answered = 0;
41
42 for (i = 0; i < QUESTIONHASHSIZE; i++)
43 bot->questions[i] = 0;
44
45 bot->nextspam = 0;
46 bot->lastspam = 0;
47 bot->spamtime = 0;
48 bot->answers = 0;
49
50 bot->micnumeric = 0;
79590bee
P
51 bot->recnumeric = 0;
52 bot->recfile = NULL;
53 bot->playfile = NULL;
f011b15a
CP
54
55 bot->next = 0;
56 bot->prev = 0;
57
58 return bot;
59}
60
61int qabot_addbot(char* nickname, char* user, char* host, char* pub_chan, char* qu_chan, char* stff_chan, flag_t flags, int spam_interval,
62 int ask_wait, int queued_question_interval, nick* sender) {
63 qab_bot* bot;
64 channel* cp;
65
66 if (*pub_chan != '#') {
67 if (sender)
68 sendnoticetouser(qabot_nick, sender, "Invalid public channel.");
69 return 0;
70 }
71
72 if (*qu_chan != '#') {
73 if (sender)
74 sendnoticetouser(qabot_nick, sender, "Invalid question channel.");
75 return 0;
76 }
77
78 if (*stff_chan != '#') {
79 if (sender)
80 sendnoticetouser(qabot_nick, sender, "Invalid staff channel.");
81 return 0;
82 }
83
84 for (bot = qab_bots; bot; bot = bot->next) {
85 if (!ircd_strcmp(bot->nick, nickname)) {
86 if (sender)
87 sendnoticetouser(qabot_nick, sender, "That QABot already exists.");
88 return 0;
89 }
90
91 if (!ircd_strcmp(bot->public_chan->name->content, pub_chan)) {
92 if (sender)
93 sendnoticetouser(qabot_nick, sender, "That public channel is already in use by %s.", bot->nick);
94 return 0;
95 }
96
97 if (!ircd_strcmp(bot->question_chan->name->content, qu_chan)) {
98 if (sender)
99 sendnoticetouser(qabot_nick, sender, "That question channel is already in use by %s.", bot->nick);
100 return 0;
101 }
102
103 if (!ircd_strcmp(bot->staff_chan->name->content, stff_chan)) {
104 if (sender)
105 sendnoticetouser(qabot_nick, sender, "That staff channel is already in use by %s.", bot->nick);
106 return 0;
107 }
108 }
109
110 bot = qabot_getbot();
111 strncpy(bot->nick, nickname, NICKLEN);
112 bot->nick[NICKLEN] = '\0';
113 strncpy(bot->user, user, USERLEN);
114 bot->user[USERLEN] = '\0';
115 bot->host = strdup(host);
116 if (!ircd_strcmp(nickname, "Tutor"))
117 bot->np = registerlocaluser(nickname, user, host, TUTOR_NAME, TUTOR_ACCOUNT, QABOT_CHILD_UMODE|UMODE_ACCOUNT, &qabot_child_handler);
118 else
119 bot->np = registerlocaluser(nickname, user, host, QABOT_NAME, NULL, QABOT_CHILD_UMODE, &qabot_child_handler);
120
121 bot->flags = flags;
122 bot->spam_interval = spam_interval;
123 bot->ask_wait = ask_wait;
124 bot->queued_question_interval = queued_question_interval;
125
126 bot->mic_timeout = QABOT_MICTIMEOUT;
127
128 bot->lastmic = 0;
129
130 if ((cp = findchannel(pub_chan))) {
131 localjoinchannel(bot->np, cp);
132 localgetops(bot->np, cp);
133 bot->public_chan = cp->index;
134 }
135 else {
136 localcreatechannel(bot->np, pub_chan);
137 cp = findchannel(pub_chan);
138 bot->public_chan = cp->index;
139 }
140
141 if ((cp = findchannel(qu_chan))) {
142 localjoinchannel(bot->np, cp);
143 bot->question_chan = cp->index;
144 }
145 else {
146 localcreatechannel(bot->np, qu_chan);
147 cp = findchannel(qu_chan);
148 bot->question_chan = cp->index;
149 }
150
151 if (!IsModerated(cp)) {
152 irc_send("%s M %s +m\r\n", mynumeric->content, cp->index->name->content);
153 SetModerated(cp);
154 }
155
156 if ((cp = findchannel(stff_chan))) {
157 localjoinchannel(bot->np, cp);
158 localgetops(bot->np, cp);
159 bot->staff_chan = cp->index;
160 }
161 else {
162 localcreatechannel(bot->np, stff_chan);
163 cp = findchannel(stff_chan);
164 bot->staff_chan = cp->index;
165 }
166
167 bot->next = qab_bots;
168 if (qab_bots)
169 qab_bots->prev = bot;
170 qab_bots = bot;
171
172 bot->np->exts[qabot_nickext] = (void*)bot;
173
174 scheduleoneshot(time(NULL) + 10, &qabot_timer, (void*)bot);
175
176 return 1;
177}
178
179void qabot_delbot(qab_bot* bot) {
180 qab_block* b;
181 qab_question* q;
182 qab_spam* s;
183 qab_spam* ns;
184 qab_answer* a;
185 qab_answer* na;
186 int i;
187
188 deleteschedule(0, qabot_spam, (void*)bot);
189 deleteschedule(0, qabot_spamstored, (void*)bot);
190 deleteschedule(0, qabot_createbotfakeuser, (void*)bot);
191 deleteschedule(0, qabot_timer, (void*)bot);
79590bee
P
192
193 if (bot->recfile) {
194 fclose(bot->recfile);
195 bot->recfile = NULL;
196 }
197
198 if (bot->playfile) {
199 fclose(bot->playfile);
200 bot->playfile = NULL;
201 }
202
f011b15a
CP
203 while (bot->blocks) {
204 b = bot->blocks;
205 bot->blocks = bot->blocks->next;
206 if (b->blockstr)
207 free(b->blockstr);
208 free(b);
209 }
210
211 for (i = 0; i < QUESTIONHASHSIZE; i++) {
212 while (bot->questions[i]) {
213 q = bot->questions[i];
214 bot->questions[i] = bot->questions[i]->next;
215 if (q->question)
216 free(q->question);
217 if (q->answer)
218 free(q->answer);
219 free(q);
220 }
221 }
222
223 for (s = bot->nextspam; s; s = ns) {
224 ns = s->next;
225 free(s->message);
226 free(s);
227 }
228
229 for (a = bot->answers; a; a = na) {
230 na = a->next;
231 free(a);
232 }
233
234 if (bot->host)
235 free(bot->host);
236 deregisterlocaluser(bot->np, "Bot deleted.");
237
238 if (bot->next)
239 bot->next->prev = bot->prev;
240 if (bot->prev)
241 bot->prev->next = bot->next;
242 else
243 qab_bots = bot->next;
244
245 free(bot);
246}
247
79590bee
P
248void qabot_playback(qab_bot *bot) {
249 char buf[1024];
250 unsigned long lines;
251
252 if (!(bot->playfile)) {
253 return;
254 }
255
256 lines = 0;
257
258 while (!feof(bot->playfile)) {
259 fscanf(bot->playfile, "%[^\n]\n", buf);
260
261 if (!ircd_strcmp("--PAUSE--", buf)) {
262 if (bot->staff_chan && bot->staff_chan->channel) {
263 sendmessagetochannel(bot->np, bot->staff_chan->channel, "Pause found in playback, use !continue when ready to continue playback.");
264 sendmessagetochannel(bot->np, bot->staff_chan->channel, "%lu lines ready to send to channel. This will take approx. %sto send.", lines, longtoduration((lines * SPAMINTERVAL), 1));
265 }
266
267 return;
268 }
269
270 lines++;
271
272 /* Copied from microphone code */
273 if (bot->lastspam) {
274 qab_spam* s;
275
276 s = (qab_spam*)malloc(sizeof(qab_spam));
277 s->message = strdup(buf);
278 s->next = 0;
279 bot->lastspam->next = s;
280 bot->lastspam = s;
281 }
282 else {
283 if ((bot->spamtime + bot->spam_interval) < time(0)) {
284 sendmessagetochannel(bot->np, bot->public_chan->channel, "%s", buf);
285 bot->spammed++;
286 bot->spamtime = time(0);
287 }
288 else {
289 qab_spam* s;
290
291 s = (qab_spam*)malloc(sizeof(qab_spam));
292 s->message = strdup(buf);
293 s->next = 0;
294 bot->nextspam = bot->lastspam = s;
295 scheduleoneshot(bot->spamtime + bot->spam_interval, qabot_spam, (void*)bot);
296 }
297 }
298 }
299
300 fclose(bot->playfile);
301 bot->playfile = NULL;
302
303 if (bot->staff_chan && bot->staff_chan->channel) {
304 sendmessagetochannel(bot->np, bot->staff_chan->channel, "End of playback.");
305 sendmessagetochannel(bot->np, bot->staff_chan->channel, "%lu lines ready to send to channel. This will take approx. %sto send.", lines, longtoduration((lines * SPAMINTERVAL), 1));
306 }
307}
308
f011b15a
CP
309void qabot_spam(void* arg) {
310 qab_bot* bot = (qab_bot*)arg;
311 qab_spam* s;
312
313 if (!bot->nextspam)
314 return;
315
316 if (bot->np) {
317 sendmessagetochannel(bot->np, bot->public_chan->channel, "%s", bot->nextspam->message);
318 bot->spammed++;
319 }
320
321 s = bot->nextspam;
322 bot->nextspam = s->next;
323
324 free(s->message);
325 free(s);
326
327 bot->spamtime = time(0);
328
329 if (bot->nextspam)
330 scheduleoneshot(bot->spamtime + bot->spam_interval, qabot_spam, (void*)bot);
331 else {
332 bot->lastspam = 0;
333 if (!bot->micnumeric)
334 qabot_spamstored((void*)bot);
335 }
336}
337
338void qabot_spamstored(void* arg) {
339 qab_bot* bot = (qab_bot*)arg;
340 qab_answer* a;
341
342 if (!bot->answers)
343 return;
344
345 if (bot->np) {
346 sendmessagetochannel(bot->np, bot->public_chan->channel, "%s asked: %s", bot->answers->question->nick,
347 bot->answers->question->question);
348 sendmessagetochannel(bot->np, bot->public_chan->channel, "%s answered: %s", bot->answers->nick,
349 bot->answers->question->answer);
350 }
351
352 a = bot->answers;
353 bot->answers = a->next;
354
355 free(a);
356
357 if (bot->answers)
358 scheduleoneshot(time(0) + bot->queued_question_interval, qabot_spamstored, (void*)bot);
359}
360
361void qabot_createbotfakeuser(void* arg) {
362 qab_bot* bot = (qab_bot*)arg;
363
364 if (bot->np)
365 return;
366
367 bot->np = registerlocaluser(bot->nick, bot->user, bot->host, QABOT_NAME, NULL, QABOT_CHILD_UMODE, &qabot_child_handler);
368
369 bot->np->exts[qabot_nickext] = (void*)bot;
370
371 if (bot->public_chan->channel) {
372 localjoinchannel(bot->np, bot->public_chan->channel);
373 localgetops(bot->np, bot->public_chan->channel);
374 }
375 else
376 localcreatechannel(bot->np, bot->public_chan->name->content);
377
378 if (bot->question_chan->channel) {
379 localjoinchannel(bot->np, bot->question_chan->channel);
380 localgetops(bot->np, bot->question_chan->channel);
381 }
382 else
383 localcreatechannel(bot->np, bot->question_chan->name->content);
384
385 if (bot->staff_chan->channel) {
386 localjoinchannel(bot->np, bot->staff_chan->channel);
387 localgetops(bot->np, bot->staff_chan->channel);
388 }
389 else
390 localcreatechannel(bot->np, bot->staff_chan->name->content);
391}
392
393void qabot_timer(void* arg) {
394 qab_bot* bot = (qab_bot*)arg;
395
396 if (!bot)
397 return;
398
399 if (bot->micnumeric && (bot->mic_timeout > 0) && (time(NULL) >= (bot->lastmic + bot->mic_timeout))) {
400 bot->micnumeric = 0;
401
402 sendmessagetochannel(bot->np, bot->staff_chan->channel, "Mic deactivated (idle timeout).");
403 if (!bot->lastspam)
404 qabot_spamstored((void*)bot);
405 }
406
407 scheduleoneshot(time(NULL) + 10, &qabot_timer, (void*)bot);
408}