]>
Commit | Line | Data |
---|---|---|
1 | /* mod-track.c - User surveillance module | |
2 | * Copyright 2002-2004 srvx Development Team | |
3 | * | |
4 | * This file is part of x3. | |
5 | * | |
6 | * x3 is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 3 of the License, or | |
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) | |
76 | #define set_track_join(x) ((x).snomask |= TRACK_JOIN) | |
77 | #define set_track_part(x) ((x).snomask |= TRACK_PART) | |
78 | #define set_track_kick(x) ((x).snomask |= TRACK_KICK) | |
79 | #define set_track_new(x) ((x).snomask |= TRACK_NEW) | |
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) | |
88 | #define clear_track_join(x) ((x).snomask &= ~TRACK_JOIN) | |
89 | #define clear_track_part(x) ((x).snomask &= ~TRACK_PART) | |
90 | #define clear_track_kick(x) ((x).snomask &= ~TRACK_KICK) | |
91 | #define clear_track_new(x) ((x).snomask &= ~TRACK_NEW) | |
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 | ||
98 | extern struct modcmd *opserv_define_func(const char *name, modcmd_func_t *func, int min_level, int reqchan, int min_argc); | |
99 | ||
100 | extern time_t now; | |
101 | static 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; | |
108 | static char timestamp[16]; | |
109 | static dict_t track_db = NULL; | |
110 | ||
111 | const char *track_module_deps[] = { NULL }; | |
112 | ||
113 | static int finalized; | |
114 | int 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 | ||
119 | void | |
120 | add_track_user(struct userNode *user) | |
121 | { | |
122 | dict_insert(track_db, strdup(user->nick), user); | |
123 | } | |
124 | ||
125 | static void | |
126 | del_track_user(const char *nick) | |
127 | { | |
128 | dict_remove(track_db, nick); | |
129 | } | |
130 | ||
131 | static int | |
132 | check_track_user(const char *nick) | |
133 | { | |
134 | int found; | |
135 | if(!nick) | |
136 | return 0; | |
137 | dict_find(track_db, nick, &found); | |
138 | return found; | |
139 | } | |
140 | ||
141 | static void | |
142 | parse_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 | ||
192 | static void | |
193 | track_nick_change(struct userNode *user, const char *old_nick) { | |
194 | if (!track_cfg.enabled) return; | |
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 | } | |
204 | } | |
205 | } | |
206 | ||
207 | static int | |
208 | track_join(struct modeNode *mNode) { | |
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; | |
213 | if (check_track_join(track_cfg) && check_track_user(user->nick)) | |
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 | ||
225 | static void | |
226 | track_part(struct modeNode *mn, const char *reason) { | |
227 | if (!track_cfg.enabled) return; | |
228 | if (mn->user->dead) return; | |
229 | if (check_track_part(track_cfg) && check_track_user(mn->user->nick)) | |
230 | { | |
231 | UPDATE_TIMESTAMP(); | |
232 | TRACK("$bPART$b %s by %s (%s)", mn->channel->name, mn->user->nick, reason ? reason : ""); | |
233 | } | |
234 | } | |
235 | ||
236 | static void | |
237 | track_kick(struct userNode *kicker, struct userNode *victim, struct chanNode *chan) { | |
238 | if (!track_cfg.enabled) return; | |
239 | if (check_track_kick(track_cfg) && ((check_track_user(kicker->nick) || check_track_user(victim->nick)))) | |
240 | { | |
241 | UPDATE_TIMESTAMP(); | |
242 | TRACK("$bKICK$b %s from %s by %s", victim->nick, chan->name, (kicker ? kicker->nick : "some server")); | |
243 | } | |
244 | } | |
245 | ||
246 | static int | |
247 | track_new_user(struct userNode *user) { | |
248 | if (!track_cfg.enabled) return 0; | |
249 | if (user->uplink->burst && !track_cfg.show_bursts) return 0; | |
250 | if (check_track_new(track_cfg) && check_track_user(user->nick)) | |
251 | { | |
252 | UPDATE_TIMESTAMP(); | |
253 | TRACK("$bNICK$b %s %s@%s [%s] on %s", user->nick, user->ident, user->hostname, irc_ntoa(&user->ip), user->uplink->name); | |
254 | } | |
255 | return 0; | |
256 | } | |
257 | ||
258 | static void | |
259 | track_del_user(struct userNode *user, struct userNode *killer, const char *why) { | |
260 | if (!track_cfg.enabled) return; | |
261 | if (check_track_del(track_cfg) && (check_track_user(user->nick) || (killer && check_track_user(killer->nick)))) | |
262 | { | |
263 | UPDATE_TIMESTAMP(); | |
264 | if (killer) { | |
265 | TRACK("$bKILL$b %s (%s@%s, on %s) by %s (%s)", user->nick, user->ident, user->hostname, user->uplink->name, killer->nick, why); | |
266 | } else { | |
267 | TRACK("$bQUIT$b %s (%s@%s, on %s) (%s)", user->nick, user->ident, user->hostname, user->uplink->name, why); | |
268 | } | |
269 | del_track_user(user->nick); | |
270 | } | |
271 | } | |
272 | ||
273 | static void | |
274 | track_auth(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle)) { | |
275 | if (!track_cfg.enabled) return; | |
276 | if (user->uplink->burst && !track_cfg.show_bursts) return; | |
277 | if (user->handle_info && (check_track_auth(track_cfg) && check_track_user(user->nick))) { | |
278 | UPDATE_TIMESTAMP(); | |
279 | TRACK("$bAUTH$b %s!%s@%s [%s] on %s as %s", user->nick, user->ident, user->hostname, | |
280 | irc_ntoa(&user->ip), user->uplink->name, user->handle_info->handle); | |
281 | } | |
282 | } | |
283 | ||
284 | static void | |
285 | track_user_mode(struct userNode *user, const char *mode_change) { | |
286 | if (!track_cfg.enabled) return; | |
287 | if (user->uplink->burst && !track_cfg.show_bursts) return; | |
288 | if (!mode_change[1]) return; /* warning there has to be atleast one char in the buffer */ | |
289 | if(check_track_umode(track_cfg) && check_track_user(user->nick)) | |
290 | { | |
291 | UPDATE_TIMESTAMP(); | |
292 | TRACK("$bUMODE$b %s %s", user->nick, mode_change); | |
293 | } | |
294 | } | |
295 | ||
296 | static void | |
297 | track_oper(struct userNode *user) { | |
298 | if (!track_cfg.enabled) return; | |
299 | if (user->uplink->burst && !track_cfg.show_bursts) return; | |
300 | UPDATE_TIMESTAMP(); | |
301 | TRACK("$bOPER$b %s!%s@%s [%s] on %s", user->nick, user->ident, user->hostname, irc_ntoa(&user->ip), user->uplink->name); | |
302 | } | |
303 | ||
304 | static void | |
305 | track_channel_mode(struct userNode *who, struct chanNode *channel, char **modes, unsigned int argc) | |
306 | { | |
307 | if (!track_cfg.enabled) return; | |
308 | if(who) | |
309 | { | |
310 | if (who->uplink->burst && !track_cfg.show_bursts) return; | |
311 | if (!check_track_chanmode(track_cfg) || !check_track_user(who->nick)) return; | |
312 | } else | |
313 | return; | |
314 | ||
315 | static char targets[MAXLEN], string[MAXLEN]; | |
316 | struct userNode *un = NULL; | |
317 | char *tmp = NULL, *tg = NULL, *md = NULL; | |
318 | int add = 0; | |
319 | ||
320 | string[0] = 0; | |
321 | targets[0] = 0; | |
322 | ||
323 | if (argc > 0) | |
324 | unsplit_string(modes, argc, string); | |
325 | else | |
326 | strcpy(string, *modes); | |
327 | ||
328 | if((tg = strchr(string, ' '))) | |
329 | { | |
330 | *tg++ = 0; | |
331 | for(md = string; *md; md++) | |
332 | { | |
333 | if (*md == '+') | |
334 | { | |
335 | add = 1; | |
336 | md++; | |
337 | } | |
338 | if (*md == '-') | |
339 | { | |
340 | add = 0; | |
341 | md++; | |
342 | } | |
343 | switch(*md) | |
344 | { | |
345 | case 'k': | |
346 | { | |
347 | strcat(targets, " "); | |
348 | if ((tmp = strchr(tg, ' '))) | |
349 | *tmp++ = 0; | |
350 | strcat(targets, tg); | |
351 | if(tmp) | |
352 | tg = tmp; | |
353 | break; | |
354 | } | |
355 | case 'l': | |
356 | { | |
357 | if(add) | |
358 | { | |
359 | strcat(targets, " "); | |
360 | if ((tmp = strchr(tg, ' '))) | |
361 | *tmp++ = 0; | |
362 | strcat(targets, tg); | |
363 | if(tmp) | |
364 | tg = tmp; | |
365 | break; | |
366 | } | |
367 | } | |
368 | case 'b': | |
369 | { | |
370 | strcat(targets, " "); | |
371 | if ((tmp = strchr(tg, ' '))) | |
372 | *tmp++ = 0; | |
373 | strcat(targets, tg); | |
374 | if(tmp) | |
375 | tg = tmp; | |
376 | break; | |
377 | } | |
378 | case 'e': | |
379 | { | |
380 | strcat(targets, " "); | |
381 | if ((tmp = strchr(tg, ' '))) | |
382 | *tmp++ = 0; | |
383 | strcat(targets, tg); | |
384 | if(tmp) | |
385 | tg = tmp; | |
386 | break; | |
387 | } | |
388 | case 'o': | |
389 | { | |
390 | strcat(targets, " "); | |
391 | if ((tmp = strchr(tg, ' '))) | |
392 | *tmp++ = 0; | |
393 | if((un = GetUserN(tg))) | |
394 | strcat(targets, un->nick); | |
395 | else | |
396 | strcat(targets, tg); | |
397 | if(tmp) | |
398 | tg = tmp; | |
399 | break; | |
400 | } | |
401 | case 'v': | |
402 | { | |
403 | strcat(targets, " "); | |
404 | if ((tmp = strchr(tg, ' '))) | |
405 | *tmp++ = 0; | |
406 | if((un = GetUserN(tg))) | |
407 | strcat(targets, un->nick); | |
408 | else | |
409 | strcat(targets, tg); | |
410 | if(tmp) | |
411 | tg = tmp; | |
412 | break; | |
413 | } | |
414 | } | |
415 | } | |
416 | } | |
417 | UPDATE_TIMESTAMP(); | |
418 | if (who) | |
419 | TRACK("$bMODE$b %s %s%s by %s", channel->name, string, targets, who->nick); | |
420 | else | |
421 | TRACK("$bMODE$b %s %s%s", channel->name, string, targets); | |
422 | } | |
423 | ||
424 | static void | |
425 | check_track_state(struct userNode *user) | |
426 | { | |
427 | send_message_type(4, user, track_cfg.bot, "TRACK is tracking: %s%s%s%s%s%s%s%s%s", | |
428 | check_track_nick(track_cfg) ? " nick":"", check_track_join(track_cfg) ? " join":"", | |
429 | check_track_part(track_cfg) ? " part":"", check_track_kick(track_cfg) ? " kick":"", | |
430 | check_track_new(track_cfg) ? " new":"", check_track_del(track_cfg) ? " del":"", | |
431 | check_track_auth(track_cfg) ? " auth":"", check_track_chanmode(track_cfg) ? " chanmode":"", | |
432 | check_track_umode(track_cfg) ? " umode":""); | |
433 | } | |
434 | ||
435 | MODCMD_FUNC(cmd_track) | |
436 | { | |
437 | unsigned int i, add; | |
438 | const char *data; | |
439 | char changed = false; | |
440 | ||
441 | if(argc == 1) | |
442 | { | |
443 | svccmd_send_help_brief(user, track_cfg.bot, cmd); | |
444 | check_track_state(user); | |
445 | return 0; | |
446 | } | |
447 | ||
448 | for(i = 1; i < argc; i++) | |
449 | { | |
450 | data = argv[i]; | |
451 | add = 2; | |
452 | changed = true; | |
453 | ||
454 | if(*data == '+') | |
455 | add = 1; | |
456 | if(*data == '-') | |
457 | add = 0; | |
458 | ||
459 | if(add == 2) | |
460 | { | |
461 | if ((!strcasecmp(data, "all"))) | |
462 | { | |
463 | set_track_all(track_cfg); | |
464 | check_track_state(user); | |
465 | TRACK("$bALERT$b TRACK fully enabled by %s", user->nick); | |
466 | } | |
467 | else if (!strcasecmp(data, "none")) | |
468 | { | |
469 | clear_track_all(track_cfg); | |
470 | check_track_state(user); | |
471 | TRACK("$bALERT$b TRACK disabled by %s", user->nick); | |
472 | } | |
473 | else | |
474 | { | |
475 | send_message_type(4, user, track_cfg.bot, "Unrecognised parameter: %s", data); | |
476 | svccmd_send_help_brief(user, track_cfg.bot, cmd); | |
477 | } | |
478 | return 0; | |
479 | } | |
480 | ||
481 | data++; | |
482 | ||
483 | if(!strcasecmp(data, "auth")) { | |
484 | if (add) | |
485 | set_track_auth(track_cfg); | |
486 | else | |
487 | clear_track_auth(track_cfg); | |
488 | } else if(!strcasecmp(data, "chanmode")) { | |
489 | if (add) | |
490 | set_track_chanmode(track_cfg); | |
491 | else | |
492 | clear_track_chanmode(track_cfg); | |
493 | } else if(!strcasecmp(data, "del")) { | |
494 | if (add) | |
495 | set_track_del(track_cfg); | |
496 | else | |
497 | clear_track_del(track_cfg); | |
498 | } else if(!strcasecmp(data, "join")) { | |
499 | if(add) | |
500 | set_track_join(track_cfg); | |
501 | else | |
502 | clear_track_join(track_cfg); | |
503 | } else if(!strcasecmp(data, "kick")) { | |
504 | if(add) | |
505 | set_track_kick(track_cfg); | |
506 | else | |
507 | clear_track_kick(track_cfg); | |
508 | } else if(!strcasecmp(data, "new")) { | |
509 | if(add) | |
510 | set_track_new(track_cfg); | |
511 | else | |
512 | clear_track_new(track_cfg); | |
513 | } else if(!strcasecmp(data, "nick")) { | |
514 | if(add) | |
515 | set_track_nick(track_cfg); | |
516 | else | |
517 | clear_track_nick(track_cfg); | |
518 | } else if(!strcasecmp(data, "part")) { | |
519 | if(add) | |
520 | set_track_part(track_cfg); | |
521 | else | |
522 | clear_track_part(track_cfg); | |
523 | } else if(!strcasecmp(data, "umode")) { | |
524 | if(add) | |
525 | set_track_umode(track_cfg); | |
526 | else | |
527 | clear_track_umode(track_cfg); | |
528 | } else { | |
529 | TRACK("Error, Unknown value %s", data); | |
530 | } | |
531 | } | |
532 | check_track_state(user); | |
533 | ||
534 | if(changed) | |
535 | { | |
536 | char buf[256]; | |
537 | unsigned int pos = 0; | |
538 | memset(buf, 0, sizeof(buf)); | |
539 | for(i = 1; i < argc; i++) | |
540 | { | |
541 | unsigned int len; | |
542 | data = argv[i]; | |
543 | len = strlen(data); | |
544 | if(pos + len > sizeof(buf)) | |
545 | break; | |
546 | strcpy(&buf[pos], data); | |
547 | pos += len; | |
548 | } | |
549 | ||
550 | UPDATE_TIMESTAMP(); | |
551 | TRACK("$bALERT$b TRACK command called with parameters '%s' by %s", | |
552 | buf, user->nick); | |
553 | } | |
554 | return 0; | |
555 | } | |
556 | ||
557 | MODCMD_FUNC(cmd_deltrack) | |
558 | { | |
559 | struct userNode *un = NULL; | |
560 | ||
561 | if((argc > 1) && (un = dict_find(clients, argv[1], NULL))) | |
562 | { | |
563 | if(check_track_user(un->nick)) | |
564 | { | |
565 | del_track_user(un->nick); | |
566 | UPDATE_TIMESTAMP(); | |
567 | TRACK("$bALERT$b No longer monitoring %s!%s@%s on %s requested by %s", | |
568 | un->nick, un->ident, un->hostname, un->uplink->name, user->nick); | |
569 | } | |
570 | else | |
571 | send_message_type(4, user, track_cfg.bot, "This nick isn't monitored."); | |
572 | } | |
573 | else | |
574 | { | |
575 | send_message_type(4, user, track_cfg.bot, "No nick or invalid nick specified."); | |
576 | svccmd_send_help_brief(user, track_cfg.bot, cmd); | |
577 | } | |
578 | return 0; | |
579 | } | |
580 | ||
581 | MODCMD_FUNC(cmd_addtrack) | |
582 | { | |
583 | struct userNode *un = NULL; | |
584 | ||
585 | if((argc > 1) && (un = dict_find(clients, argv[1], NULL))) | |
586 | { | |
587 | add_track_user(un); | |
588 | UPDATE_TIMESTAMP(); | |
589 | TRACK("$bALERT$b Manually enabled monitoring of %s!%s@%s on %s requested by %s", | |
590 | un->nick, un->ident, un->hostname, un->uplink->name, user->nick); | |
591 | send_message_type(4, user, track_cfg.bot, "Now tracking %s!%s@%s on %s", un->nick,un->ident,un->hostname, un->uplink->name); | |
592 | } | |
593 | else | |
594 | { | |
595 | send_message_type(4, user, track_cfg.bot, "No nick or invalid nick specified."); | |
596 | svccmd_send_help_brief(user, track_cfg.bot, cmd); | |
597 | } | |
598 | return 0; | |
599 | } | |
600 | ||
601 | MODCMD_FUNC(cmd_listtrack) | |
602 | { | |
603 | dict_iterator_t it, next; | |
604 | if (track_db == NULL) return 0; | |
605 | struct userNode *un = NULL; | |
606 | send_message_type(4, user, track_cfg.bot, "Currently tracking:"); | |
607 | for (it=dict_first(track_db); it; it=next) { | |
608 | next = iter_next(it); | |
609 | un = it->data; | |
610 | send_message_type(4, user, track_cfg.bot, "%s!%s@%s [%s] on %s", | |
611 | un->nick, un->ident, un->hostname, irc_ntoa(&un->ip), un->uplink->name); | |
612 | } | |
613 | send_message_type(4, user, track_cfg.bot, "End of track list."); | |
614 | return 0; | |
615 | } | |
616 | ||
617 | static void | |
618 | track_conf_read(void) { | |
619 | dict_t node; | |
620 | char *str; | |
621 | ||
622 | node = conf_get_data("modules/track", RECDB_OBJECT); | |
623 | if (!node) | |
624 | return; | |
625 | str = database_get_data(node, "snomask", RECDB_QSTRING); | |
626 | if (!str) | |
627 | track_cfg.snomask = TRACK_NICK|TRACK_KICK|TRACK_JOIN|TRACK_PART|TRACK_CHANMODE|TRACK_NEW|TRACK_DEL|TRACK_AUTH; | |
628 | else | |
629 | parse_track_conf(str); | |
630 | str = database_get_data(node, "channel", RECDB_QSTRING); | |
631 | if (!str) | |
632 | return; | |
633 | // XXX - dont do addchannel if the channel is being shared with | |
634 | // another module: | |
635 | track_cfg.channel = AddChannel(str, now, "+sntOm", NULL, NULL); | |
636 | if (!track_cfg.channel) | |
637 | return; | |
638 | str = database_get_data(node, "show_bursts", RECDB_QSTRING); | |
639 | track_cfg.show_bursts = str ? enabled_string(str) : 0; | |
640 | track_cfg.enabled = 1; | |
641 | if (finalized) | |
642 | track_finalize(); | |
643 | } | |
644 | ||
645 | void | |
646 | track_cleanup(void) { | |
647 | track_cfg.enabled = 0; | |
648 | unreg_del_user_func(track_del_user); | |
649 | dict_delete(track_db); | |
650 | } | |
651 | ||
652 | int | |
653 | track_init(void) { | |
654 | track_db = dict_new(); | |
655 | dict_set_free_keys(track_db, free); | |
656 | ||
657 | reg_exit_func(track_cleanup); | |
658 | conf_register_reload(track_conf_read); | |
659 | reg_nick_change_func(track_nick_change); | |
660 | reg_join_func(track_join); | |
661 | reg_part_func(track_part); | |
662 | reg_kick_func(track_kick); | |
663 | reg_new_user_func(track_new_user); | |
664 | reg_del_user_func(track_del_user); | |
665 | reg_auth_func(track_auth); | |
666 | reg_channel_mode_func(track_channel_mode); | |
667 | reg_user_mode_func(track_user_mode); | |
668 | reg_oper_func(track_oper); | |
669 | opserv_define_func("TRACK", cmd_track, 800, 0, 0); | |
670 | opserv_define_func("DELTRACK", cmd_deltrack, 800, 0, 0); | |
671 | opserv_define_func("ADDTRACK", cmd_addtrack, 800, 0, 0); | |
672 | opserv_define_func("LISTTRACK", cmd_listtrack, 800, 0, 0); | |
673 | return 1; | |
674 | } | |
675 | ||
676 | int | |
677 | track_finalize(void) { | |
678 | struct mod_chanmode change; | |
679 | dict_t node; | |
680 | char *str; | |
681 | ||
682 | finalized = 1; | |
683 | node = conf_get_data("modules/track", RECDB_OBJECT); | |
684 | if (!node) | |
685 | return 0; | |
686 | str = database_get_data(node, "snomask", RECDB_QSTRING); | |
687 | if (!str) | |
688 | track_cfg.snomask = TRACK_NICK|TRACK_KICK|TRACK_JOIN|TRACK_PART|TRACK_CHANMODE|TRACK_NEW|TRACK_DEL|TRACK_AUTH; | |
689 | else | |
690 | parse_track_conf(str); | |
691 | str = database_get_data(node, "bot", RECDB_QSTRING); | |
692 | if (!str) | |
693 | return 0; | |
694 | track_cfg.bot = GetUserH(str); | |
695 | if (!track_cfg.bot) | |
696 | return 0; | |
697 | mod_chanmode_init(&change); | |
698 | change.argc = 1; | |
699 | change.args[0].mode = MODE_CHANOP; | |
700 | change.args[0].u.member = AddChannelUser(track_cfg.bot, track_cfg.channel); | |
701 | mod_chanmode_announce(track_cfg.bot, track_cfg.channel, &change); | |
702 | return 1; | |
703 | } | |
704 | ||
705 |