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