]>
Commit | Line | Data |
---|---|---|
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 | ||
15 | qab_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 | ||
61 | int 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 | ||
179 | void 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 |
248 | void 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 |
309 | void 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 | ||
338 | void 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 | ||
361 | void 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 | ||
393 | void 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 | } |