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