]> jfr.im git - irc/evilnet/x3.git/blame - src/mod-track.c
testing commit diffs
[irc/evilnet/x3.git] / src / mod-track.c
CommitLineData
ec311f39 1/* mod-track.c - User surveillance module
2 * Copyright 2002-2004 srvx Development Team
3 *
4 * This file is part of x3.
5 *
d0f04f71 6 * x3 is free software; you can redistribute it and/or modify
ec311f39 7 * it under the terms of the GNU General Public License as published by
348683aa 8 * the Free Software Foundation; either version 3 of the License, or
ec311f39 9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 */
20
21/* Adds new section to srvx.conf:
22 * "modules" {
23 * "track" {
24 * // What data to show.
25 * "snomask" "nick,join,part,kick,new,del,auth,chanmode,umode";
26 * // Where to send track messages?
27 * "channel" "#wherever";
28 * // Which bot?
29 * "bot" "OpServ";
30 * // Show new users and joins from net joins? (off by default)
31 * "show_bursts" "0";
32 * };
33 * };
34 */
35
36#include "conf.h"
37#include "chanserv.h"
38#include "helpfile.h"
39#include "nickserv.h"
40#include "modcmd.h"
41#include "proto.h"
42#include "dict.h"
43#include "hash.h"
44
45#ifdef HAVE_NETINET_IN_H
46#include <netinet/in.h>
47#endif
48#ifdef HAVE_ARPA_INET_H
49#include <arpa/inet.h>
50#endif
51
52/* track snomask definitions */
53#define TRACK_NICK 0x0001 /* report nickchanges */
54#define TRACK_JOIN 0x0002 /* report join/part */
55#define TRACK_PART 0x0004 /* report parts */
56#define TRACK_KICK 0x0008 /* report kicks */
57#define TRACK_NEW 0x0010 /* report new users */
58#define TRACK_DEL 0x0020 /* report quits */
59#define TRACK_AUTH 0x0040 /* report auths */
60#define TRACK_CHANMODE 0x0080 /* report channel modes */
61#define TRACK_UMODE 0x0100 /* report user modes */
62
63/* check track status */
64#define check_track_nick(x) ((x).snomask & TRACK_NICK)
65#define check_track_join(x) ((x).snomask & TRACK_JOIN)
66#define check_track_part(x) ((x).snomask & TRACK_PART)
67#define check_track_kick(x) ((x).snomask & TRACK_KICK)
68#define check_track_new(x) ((x).snomask & TRACK_NEW)
69#define check_track_del(x) ((x).snomask & TRACK_DEL)
70#define check_track_auth(x) ((x).snomask & TRACK_AUTH)
71#define check_track_chanmode(x) ((x).snomask & TRACK_CHANMODE)
72#define check_track_umode(x) ((x).snomask & TRACK_UMODE)
73
74/* set track status */
75#define set_track_nick(x) ((x).snomask |= TRACK_NICK)
6cf5f880 76#define set_track_join(x) ((x).snomask |= TRACK_JOIN)
ec311f39 77#define set_track_part(x) ((x).snomask |= TRACK_PART)
78#define set_track_kick(x) ((x).snomask |= TRACK_KICK)
6cf5f880 79#define set_track_new(x) ((x).snomask |= TRACK_NEW)
ec311f39 80#define set_track_del(x) ((x).snomask |= TRACK_DEL)
81#define set_track_auth(x) ((x).snomask |= TRACK_AUTH)
82#define set_track_chanmode(x) ((x).snomask |= TRACK_CHANMODE)
83#define set_track_umode(x) ((x).snomask |= TRACK_UMODE)
84#define set_track_all(x) ((x).snomask |= TRACK_NICK|TRACK_JOIN|TRACK_PART|TRACK_KICK|TRACK_NEW|TRACK_DEL|TRACK_AUTH|TRACK_CHANMODE|TRACK_UMODE)
85
86/* clear track status */
87#define clear_track_nick(x) ((x).snomask &= ~TRACK_NICK)
6cf5f880 88#define clear_track_join(x) ((x).snomask &= ~TRACK_JOIN)
ec311f39 89#define clear_track_part(x) ((x).snomask &= ~TRACK_PART)
90#define clear_track_kick(x) ((x).snomask &= ~TRACK_KICK)
6cf5f880 91#define clear_track_new(x) ((x).snomask &= ~TRACK_NEW)
ec311f39 92#define clear_track_del(x) ((x).snomask &= ~TRACK_DEL)
93#define clear_track_auth(x) ((x).snomask &= ~TRACK_AUTH)
94#define clear_track_chanmode(x) ((x).snomask &= ~TRACK_CHANMODE)
95#define clear_track_umode(x) ((x).snomask &= ~TRACK_UMODE)
96#define clear_track_all(x) ((x).snomask &= ~(TRACK_NICK|TRACK_JOIN|TRACK_PART|TRACK_KICK|TRACK_NEW|TRACK_DEL|TRACK_AUTH|TRACK_CHANMODE|TRACK_UMODE))
97
98extern struct modcmd *opserv_define_func(const char *name, modcmd_func_t *func, int min_level, int reqchan, int min_argc);
99
100extern time_t now;
101static struct {
102 struct chanNode *channel;
103 struct userNode *bot;
104 unsigned int snomask;
105 unsigned int show_bursts : 1;
106 unsigned int enabled : 1;
107} track_cfg;
108static char timestamp[16];
109static dict_t track_db = NULL;
110
111const char *track_module_deps[] = { NULL };
112
113static int finalized;
114int track_finalize(void);
115
116#define TRACK(FORMAT, ARGS...) send_channel_message(track_cfg.channel, track_cfg.bot, "%s "FORMAT, timestamp , ## ARGS)
117#define UPDATE_TIMESTAMP() strftime(timestamp, sizeof(timestamp), "[%H:%M:%S]", localtime(&now))
118
6cf5f880 119void
120add_track_user(struct userNode *user)
121{
122 dict_insert(track_db, strdup(user->nick), user);
123}
124
125static void
126del_track_user(const char *nick)
127{
128 dict_remove(track_db, nick);
129}
130
ec311f39 131static int
6cf5f880 132check_track_user(const char *nick)
ec311f39 133{
134 int found;
6cf5f880 135 if(!nick)
7637f48f 136 return 0;
6cf5f880 137 dict_find(track_db, nick, &found);
ec311f39 138 return found;
139}
140
141static void
142parse_track_conf(char *line)
143{
144 char *t = NULL, *s = line;
145
146 while(s)
147 {
148 if ((t = strchr(s, ',')))
149 *t++ = 0;
150
151 switch (tolower(s[0]))
152 {
153 case 'a':
154 if(!strcasecmp(s, "auth"))
155 set_track_auth(track_cfg);
156 break;
157 case 'c':
158 if(!strcasecmp(s, "chanmode"))
159 set_track_chanmode(track_cfg);
160 break;
161 case 'd':
162 if(!strcasecmp(s, "del"))
163 set_track_del(track_cfg);
164 break;
165 case 'j':
166 if(!strcasecmp(s, "join"))
167 set_track_join(track_cfg);
168 break;
169 case 'k':
170 if(!strcasecmp(s, "kick"))
171 set_track_kick(track_cfg);
172 break;
173 case 'n':
174 if(!strcasecmp(s, "new"))
175 set_track_new(track_cfg);
176 if(!strcasecmp(s, "nick"))
177 set_track_nick(track_cfg);
178 break;
179 case 'p':
180 if(!strcasecmp(s, "part"))
181 set_track_nick(track_cfg);
182 break;
183 case 'u':
184 if(!strcasecmp(s, "umode"))
185 set_track_umode(track_cfg);
186 break;
187 }
188 s = t;
189 }
190}
191
192static void
2732298d 193track_nick_change(struct userNode *user, const char *old_nick, UNUSED_ARG(void *extra)) {
ec311f39 194 if (!track_cfg.enabled) return;
6cf5f880 195
196 if(check_track_user(old_nick)) {
197 del_track_user(old_nick);
198 add_track_user(user);
199 if (check_track_nick(track_cfg))
200 {
201 UPDATE_TIMESTAMP();
202 TRACK("$bNICK$b change %s -> %s", old_nick, user->nick);
203 }
ec311f39 204 }
205}
206
207static int
2732298d 208track_join(struct modeNode *mNode, UNUSED_ARG(void *extra)) {
ec311f39 209 struct userNode *user = mNode->user;
210 struct chanNode *chan = mNode->channel;
211 if (!track_cfg.enabled) return 0;
212 if (user->uplink->burst && !track_cfg.show_bursts) return 0;
6cf5f880 213 if (check_track_join(track_cfg) && check_track_user(user->nick))
ec311f39 214 {
215 UPDATE_TIMESTAMP();
216 if (chan->members.used == 1) {
217 TRACK("$bCREATE$b %s by %s", chan->name, user->nick);
218 } else {
219 TRACK("$bJOIN$b %s by %s", chan->name, user->nick);
220 }
221 }
222 return 0;
223}
224
225static void
63637aea 226track_part(struct modeNode *mn, const char *reason, UNUSED_ARG(void *extra)) {
ec311f39 227 if (!track_cfg.enabled) return;
228 if (mn->user->dead) return;
6cf5f880 229 if (check_track_part(track_cfg) && check_track_user(mn->user->nick))
ec311f39 230 {
231 UPDATE_TIMESTAMP();
232 TRACK("$bPART$b %s by %s (%s)", mn->channel->name, mn->user->nick, reason ? reason : "");
233 }
234}
235
236static void
91667658 237track_kick(struct userNode *kicker, struct userNode *victim, struct chanNode *chan, UNUSED_ARG(void *extra)) {
ec311f39 238 if (!track_cfg.enabled) return;
72d5504b 239 if (check_track_kick(track_cfg) && check_track_user(victim->nick))
ec311f39 240 {
72d5504b 241 if (kicker) /* net rider kicks dont have a kicker set */
242 {
243 if (!check_track_user(kicker->nick))
244 return;
245 }
246
ec311f39 247 UPDATE_TIMESTAMP();
248 TRACK("$bKICK$b %s from %s by %s", victim->nick, chan->name, (kicker ? kicker->nick : "some server"));
249 }
250}
251
252static int
2732298d 253track_new_user(struct userNode *user, UNUSED_ARG(void *extra)) {
f1d4a7db 254
ec311f39 255 if (!track_cfg.enabled) return 0;
256 if (user->uplink->burst && !track_cfg.show_bursts) return 0;
6cf5f880 257 if (check_track_new(track_cfg) && check_track_user(user->nick))
ec311f39 258 {
259 UPDATE_TIMESTAMP();
260 TRACK("$bNICK$b %s %s@%s [%s] on %s", user->nick, user->ident, user->hostname, irc_ntoa(&user->ip), user->uplink->name);
261 }
262 return 0;
263}
264
265static void
2732298d 266track_del_user(struct userNode *user, struct userNode *killer, const char *why, UNUSED_ARG(void *extra)) {
ec311f39 267 if (!track_cfg.enabled) return;
6cf5f880 268 if (check_track_del(track_cfg) && (check_track_user(user->nick) || (killer && check_track_user(killer->nick))))
ec311f39 269 {
270 UPDATE_TIMESTAMP();
271 if (killer) {
272 TRACK("$bKILL$b %s (%s@%s, on %s) by %s (%s)", user->nick, user->ident, user->hostname, user->uplink->name, killer->nick, why);
273 } else {
274 TRACK("$bQUIT$b %s (%s@%s, on %s) (%s)", user->nick, user->ident, user->hostname, user->uplink->name, why);
275 }
6cf5f880 276 del_track_user(user->nick);
ec311f39 277 }
278}
279
280static void
81ac4787 281track_auth(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle), UNUSED_ARG(void *extra)) {
ec311f39 282 if (!track_cfg.enabled) return;
283 if (user->uplink->burst && !track_cfg.show_bursts) return;
6cf5f880 284 if (user->handle_info && (check_track_auth(track_cfg) && check_track_user(user->nick))) {
ec311f39 285 UPDATE_TIMESTAMP();
286 TRACK("$bAUTH$b %s!%s@%s [%s] on %s as %s", user->nick, user->ident, user->hostname,
287 irc_ntoa(&user->ip), user->uplink->name, user->handle_info->handle);
288 }
289}
290
291static void
3a196bdb 292track_user_mode(struct userNode *user, const char *mode_change, UNUSED_ARG(void *extra)) {
ec311f39 293 if (!track_cfg.enabled) return;
294 if (user->uplink->burst && !track_cfg.show_bursts) return;
295 if (!mode_change[1]) return; /* warning there has to be atleast one char in the buffer */
6cf5f880 296 if(check_track_umode(track_cfg) && check_track_user(user->nick))
ec311f39 297 {
298 UPDATE_TIMESTAMP();
299 TRACK("$bUMODE$b %s %s", user->nick, mode_change);
300 }
301}
302
303static void
2732298d 304track_oper(struct userNode *user, UNUSED_ARG(void *extra)) {
ec311f39 305 if (!track_cfg.enabled) return;
306 if (user->uplink->burst && !track_cfg.show_bursts) return;
307 UPDATE_TIMESTAMP();
308 TRACK("$bOPER$b %s!%s@%s [%s] on %s", user->nick, user->ident, user->hostname, irc_ntoa(&user->ip), user->uplink->name);
309}
310
311static void
ee8c50bd 312track_channel_mode(struct userNode *who, struct chanNode *channel, char **modes, unsigned int argc, UNUSED_ARG(void *extra))
ec311f39 313{
314 if (!track_cfg.enabled) return;
315 if(who)
316 {
317 if (who->uplink->burst && !track_cfg.show_bursts) return;
6cf5f880 318 if (!check_track_chanmode(track_cfg) || !check_track_user(who->nick)) return;
ec311f39 319 } else
320 return;
321
322 static char targets[MAXLEN], string[MAXLEN];
323 struct userNode *un = NULL;
324 char *tmp = NULL, *tg = NULL, *md = NULL;
325 int add = 0;
326
327 string[0] = 0;
328 targets[0] = 0;
329
330 if (argc > 0)
331 unsplit_string(modes, argc, string);
332 else
333 strcpy(string, *modes);
334
335 if((tg = strchr(string, ' ')))
336 {
337 *tg++ = 0;
338 for(md = string; *md; md++)
339 {
340 if (*md == '+')
341 {
342 add = 1;
343 md++;
344 }
345 if (*md == '-')
346 {
347 add = 0;
348 md++;
349 }
350 switch(*md)
351 {
352 case 'k':
353 {
354 strcat(targets, " ");
355 if ((tmp = strchr(tg, ' ')))
356 *tmp++ = 0;
357 strcat(targets, tg);
358 if(tmp)
359 tg = tmp;
360 break;
361 }
362 case 'l':
363 {
364 if(add)
365 {
366 strcat(targets, " ");
367 if ((tmp = strchr(tg, ' ')))
368 *tmp++ = 0;
369 strcat(targets, tg);
370 if(tmp)
371 tg = tmp;
372 break;
373 }
374 }
375 case 'b':
376 {
377 strcat(targets, " ");
378 if ((tmp = strchr(tg, ' ')))
379 *tmp++ = 0;
380 strcat(targets, tg);
381 if(tmp)
382 tg = tmp;
383 break;
384 }
385 case 'e':
386 {
387 strcat(targets, " ");
388 if ((tmp = strchr(tg, ' ')))
389 *tmp++ = 0;
390 strcat(targets, tg);
391 if(tmp)
392 tg = tmp;
393 break;
394 }
395 case 'o':
396 {
397 strcat(targets, " ");
398 if ((tmp = strchr(tg, ' ')))
399 *tmp++ = 0;
400 if((un = GetUserN(tg)))
401 strcat(targets, un->nick);
402 else
403 strcat(targets, tg);
404 if(tmp)
405 tg = tmp;
406 break;
407 }
408 case 'v':
409 {
410 strcat(targets, " ");
411 if ((tmp = strchr(tg, ' ')))
412 *tmp++ = 0;
413 if((un = GetUserN(tg)))
414 strcat(targets, un->nick);
415 else
416 strcat(targets, tg);
417 if(tmp)
418 tg = tmp;
419 break;
420 }
421 }
422 }
423 }
424 UPDATE_TIMESTAMP();
425 if (who)
426 TRACK("$bMODE$b %s %s%s by %s", channel->name, string, targets, who->nick);
427 else
428 TRACK("$bMODE$b %s %s%s", channel->name, string, targets);
429}
430
431static void
432check_track_state(struct userNode *user)
433{
12673a59 434 send_message_type(4, user, track_cfg.bot, "TRACK is tracking: %s%s%s%s%s%s%s%s%s",
ec311f39 435 check_track_nick(track_cfg) ? " nick":"", check_track_join(track_cfg) ? " join":"",
436 check_track_part(track_cfg) ? " part":"", check_track_kick(track_cfg) ? " kick":"",
437 check_track_new(track_cfg) ? " new":"", check_track_del(track_cfg) ? " del":"",
438 check_track_auth(track_cfg) ? " auth":"", check_track_chanmode(track_cfg) ? " chanmode":"",
439 check_track_umode(track_cfg) ? " umode":"");
440}
441
442MODCMD_FUNC(cmd_track)
443{
444 unsigned int i, add;
445 const char *data;
446 char changed = false;
447
448 if(argc == 1)
449 {
12673a59 450 svccmd_send_help_brief(user, track_cfg.bot, cmd);
ec311f39 451 check_track_state(user);
452 return 0;
453 }
454
455 for(i = 1; i < argc; i++)
456 {
457 data = argv[i];
458 add = 2;
459 changed = true;
460
6cf5f880 461 if(*data == '+')
ec311f39 462 add = 1;
6cf5f880 463 if(*data == '-')
ec311f39 464 add = 0;
465
466 if(add == 2)
467 {
e5c85987 468 if ((!strcasecmp(data, "all")))
ec311f39 469 {
470 set_track_all(track_cfg);
471 check_track_state(user);
472 TRACK("$bALERT$b TRACK fully enabled by %s", user->nick);
473 }
e5c85987 474 else if (!strcasecmp(data, "none"))
ec311f39 475 {
476 clear_track_all(track_cfg);
477 check_track_state(user);
478 TRACK("$bALERT$b TRACK disabled by %s", user->nick);
479 }
480 else
b34a7505 481 {
482 send_message_type(4, user, track_cfg.bot, "Unrecognised parameter: %s", data);
483 svccmd_send_help_brief(user, track_cfg.bot, cmd);
484 }
ec311f39 485 return 0;
486 }
487
6cf5f880 488 data++;
489
490 if(!strcasecmp(data, "auth")) {
491 if (add)
492 set_track_auth(track_cfg);
493 else
494 clear_track_auth(track_cfg);
495 } else if(!strcasecmp(data, "chanmode")) {
496 if (add)
497 set_track_chanmode(track_cfg);
498 else
499 clear_track_chanmode(track_cfg);
500 } else if(!strcasecmp(data, "del")) {
501 if (add)
502 set_track_del(track_cfg);
503 else
504 clear_track_del(track_cfg);
505 } else if(!strcasecmp(data, "join")) {
506 if(add)
507 set_track_join(track_cfg);
508 else
509 clear_track_join(track_cfg);
510 } else if(!strcasecmp(data, "kick")) {
511 if(add)
512 set_track_kick(track_cfg);
513 else
514 clear_track_kick(track_cfg);
515 } else if(!strcasecmp(data, "new")) {
516 if(add)
517 set_track_new(track_cfg);
518 else
519 clear_track_new(track_cfg);
520 } else if(!strcasecmp(data, "nick")) {
521 if(add)
522 set_track_nick(track_cfg);
523 else
524 clear_track_nick(track_cfg);
525 } else if(!strcasecmp(data, "part")) {
526 if(add)
527 set_track_part(track_cfg);
528 else
529 clear_track_part(track_cfg);
530 } else if(!strcasecmp(data, "umode")) {
531 if(add)
532 set_track_umode(track_cfg);
533 else
534 clear_track_umode(track_cfg);
535 } else {
536 TRACK("Error, Unknown value %s", data);
ec311f39 537 }
538 }
539 check_track_state(user);
540
541 if(changed)
542 {
543 char buf[256];
544 unsigned int pos = 0;
545 memset(buf, 0, sizeof(buf));
546 for(i = 1; i < argc; i++)
547 {
548 unsigned int len;
549 data = argv[i];
550 len = strlen(data);
551 if(pos + len > sizeof(buf))
552 break;
553 strcpy(&buf[pos], data);
554 pos += len;
555 }
556
557 UPDATE_TIMESTAMP();
558 TRACK("$bALERT$b TRACK command called with parameters '%s' by %s",
559 buf, user->nick);
560 }
561 return 0;
562}
563
564MODCMD_FUNC(cmd_deltrack)
565{
566 struct userNode *un = NULL;
567
568 if((argc > 1) && (un = dict_find(clients, argv[1], NULL)))
569 {
6cf5f880 570 if(check_track_user(un->nick))
ec311f39 571 {
6cf5f880 572 del_track_user(un->nick);
ec311f39 573 UPDATE_TIMESTAMP();
574 TRACK("$bALERT$b No longer monitoring %s!%s@%s on %s requested by %s",
575 un->nick, un->ident, un->hostname, un->uplink->name, user->nick);
576 }
577 else
578 send_message_type(4, user, track_cfg.bot, "This nick isn't monitored.");
579 }
580 else
b34a7505 581 {
ec311f39 582 send_message_type(4, user, track_cfg.bot, "No nick or invalid nick specified.");
12673a59 583 svccmd_send_help_brief(user, track_cfg.bot, cmd);
b34a7505 584 }
ec311f39 585 return 0;
586}
587
588MODCMD_FUNC(cmd_addtrack)
589{
6cf5f880 590 struct userNode *un = NULL;
ec311f39 591
6cf5f880 592 if((argc > 1) && (un = dict_find(clients, argv[1], NULL)))
593 {
594 add_track_user(un);
595 UPDATE_TIMESTAMP();
596 TRACK("$bALERT$b Manually enabled monitoring of %s!%s@%s on %s requested by %s",
597 un->nick, un->ident, un->hostname, un->uplink->name, user->nick);
b34a7505 598 send_message_type(4, user, track_cfg.bot, "Now tracking %s!%s@%s on %s", un->nick,un->ident,un->hostname, un->uplink->name);
6cf5f880 599 }
600 else
b34a7505 601 {
6cf5f880 602 send_message_type(4, user, track_cfg.bot, "No nick or invalid nick specified.");
12673a59 603 svccmd_send_help_brief(user, track_cfg.bot, cmd);
b34a7505 604 }
6cf5f880 605 return 0;
ec311f39 606}
607
608MODCMD_FUNC(cmd_listtrack)
609{
610 dict_iterator_t it, next;
611 if (track_db == NULL) return 0;
612 struct userNode *un = NULL;
613 send_message_type(4, user, track_cfg.bot, "Currently tracking:");
614 for (it=dict_first(track_db); it; it=next) {
615 next = iter_next(it);
616 un = it->data;
617 send_message_type(4, user, track_cfg.bot, "%s!%s@%s [%s] on %s",
618 un->nick, un->ident, un->hostname, irc_ntoa(&un->ip), un->uplink->name);
619 }
620 send_message_type(4, user, track_cfg.bot, "End of track list.");
621 return 0;
622}
623
624static void
625track_conf_read(void) {
626 dict_t node;
627 char *str;
628
629 node = conf_get_data("modules/track", RECDB_OBJECT);
630 if (!node)
631 return;
632 str = database_get_data(node, "snomask", RECDB_QSTRING);
633 if (!str)
634 track_cfg.snomask = TRACK_NICK|TRACK_KICK|TRACK_JOIN|TRACK_PART|TRACK_CHANMODE|TRACK_NEW|TRACK_DEL|TRACK_AUTH;
635 else
636 parse_track_conf(str);
637 str = database_get_data(node, "channel", RECDB_QSTRING);
638 if (!str)
639 return;
b34a7505 640 // XXX - dont do addchannel if the channel is being shared with
641 // another module:
642 track_cfg.channel = AddChannel(str, now, "+sntOm", NULL, NULL);
ec311f39 643 if (!track_cfg.channel)
644 return;
645 str = database_get_data(node, "show_bursts", RECDB_QSTRING);
646 track_cfg.show_bursts = str ? enabled_string(str) : 0;
647 track_cfg.enabled = 1;
648 if (finalized)
649 track_finalize();
650}
651
652void
30874d66 653track_cleanup(UNUSED_ARG(void *extra)) {
ec311f39 654 track_cfg.enabled = 0;
2732298d 655 unreg_del_user_func(track_del_user, NULL);
6cf5f880 656 dict_delete(track_db);
ec311f39 657}
658
659int
660track_init(void) {
661 track_db = dict_new();
6cf5f880 662 dict_set_free_keys(track_db, free);
ec311f39 663
30874d66 664 reg_exit_func(track_cleanup, NULL);
ec311f39 665 conf_register_reload(track_conf_read);
2732298d 666 reg_nick_change_func(track_nick_change, NULL);
667 reg_join_func(track_join, NULL);
63637aea 668 reg_part_func(track_part, NULL);
ee8c50bd 669 reg_kick_func(track_kick, NULL);
2732298d 670 reg_new_user_func(track_new_user, NULL);
671 reg_del_user_func(track_del_user, NULL);
81ac4787 672 reg_auth_func(track_auth, NULL);
ee8c50bd 673 reg_channel_mode_func(track_channel_mode, NULL);
3a196bdb 674 reg_user_mode_func(track_user_mode, NULL);
2732298d 675 reg_oper_func(track_oper, NULL);
ec311f39 676 opserv_define_func("TRACK", cmd_track, 800, 0, 0);
677 opserv_define_func("DELTRACK", cmd_deltrack, 800, 0, 0);
678 opserv_define_func("ADDTRACK", cmd_addtrack, 800, 0, 0);
679 opserv_define_func("LISTTRACK", cmd_listtrack, 800, 0, 0);
680 return 1;
681}
682
683int
684track_finalize(void) {
685 struct mod_chanmode change;
686 dict_t node;
687 char *str;
688
689 finalized = 1;
690 node = conf_get_data("modules/track", RECDB_OBJECT);
691 if (!node)
692 return 0;
693 str = database_get_data(node, "snomask", RECDB_QSTRING);
694 if (!str)
695 track_cfg.snomask = TRACK_NICK|TRACK_KICK|TRACK_JOIN|TRACK_PART|TRACK_CHANMODE|TRACK_NEW|TRACK_DEL|TRACK_AUTH;
696 else
697 parse_track_conf(str);
698 str = database_get_data(node, "bot", RECDB_QSTRING);
699 if (!str)
700 return 0;
701 track_cfg.bot = GetUserH(str);
702 if (!track_cfg.bot)
703 return 0;
704 mod_chanmode_init(&change);
705 change.argc = 1;
706 change.args[0].mode = MODE_CHANOP;
707 change.args[0].u.member = AddChannelUser(track_cfg.bot, track_cfg.channel);
708 mod_chanmode_announce(track_cfg.bot, track_cfg.channel, &change);
709 return 1;
710}
711
712