]>
jfr.im git - irc/evilnet/x3.git/blob - src/mod-track.c
1 /* mod-track.c - User surveillance module
2 * Copyright 2002-2004 srvx Development Team
4 * This file is part of x3.
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.
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.
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.
21 /* Adds new section to srvx.conf:
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";
30 * // Show new users and joins from net joins? (off by default)
45 #ifdef HAVE_NETINET_IN_H
46 #include <netinet/in.h>
48 #ifdef HAVE_ARPA_INET_H
49 #include <arpa/inet.h>
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 */
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)
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)
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))
98 extern struct modcmd
*opserv_define_func(const char *name
, modcmd_func_t
*func
, int min_level
, int reqchan
, int min_argc
);
102 struct chanNode
*channel
;
103 struct userNode
*bot
;
104 unsigned int snomask
;
105 unsigned int show_bursts
: 1;
106 unsigned int enabled
: 1;
108 static char timestamp
[16];
109 static dict_t track_db
= NULL
;
111 const char *track_module_deps
[] = { NULL
};
113 static int finalized
;
114 int track_finalize(void);
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))
120 add_track_user(struct userNode
*user
)
122 dict_insert(track_db
, strdup(user
->nick
), user
);
126 del_track_user(const char *nick
)
128 dict_remove(track_db
, nick
);
132 check_track_user(const char *nick
)
137 dict_find(track_db
, nick
, &found
);
142 parse_track_conf(char *line
)
144 char *t
= NULL
, *s
= line
;
148 if ((t
= strchr(s
, ',')))
151 switch (tolower(s
[0]))
154 if(!strcasecmp(s
, "auth"))
155 set_track_auth(track_cfg
);
158 if(!strcasecmp(s
, "chanmode"))
159 set_track_chanmode(track_cfg
);
162 if(!strcasecmp(s
, "del"))
163 set_track_del(track_cfg
);
166 if(!strcasecmp(s
, "join"))
167 set_track_join(track_cfg
);
170 if(!strcasecmp(s
, "kick"))
171 set_track_kick(track_cfg
);
174 if(!strcasecmp(s
, "new"))
175 set_track_new(track_cfg
);
176 if(!strcasecmp(s
, "nick"))
177 set_track_nick(track_cfg
);
180 if(!strcasecmp(s
, "part"))
181 set_track_nick(track_cfg
);
184 if(!strcasecmp(s
, "umode"))
185 set_track_umode(track_cfg
);
193 track_nick_change(struct userNode
*user
, const char *old_nick
, UNUSED_ARG(void *extra
)) {
194 if (!track_cfg
.enabled
) return;
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
))
202 TRACK("$bNICK$b change %s -> %s", old_nick
, user
->nick
);
208 track_join(struct modeNode
*mNode
, UNUSED_ARG(void *extra
)) {
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
))
216 if (chan
->members
.used
== 1) {
217 TRACK("$bCREATE$b %s by %s", chan
->name
, user
->nick
);
219 TRACK("$bJOIN$b %s by %s", chan
->name
, user
->nick
);
226 track_part(struct modeNode
*mn
, const char *reason
, UNUSED_ARG(void *extra
)) {
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
))
232 TRACK("$bPART$b %s by %s (%s)", mn
->channel
->name
, mn
->user
->nick
, reason
? reason
: "");
237 track_kick(struct userNode
*kicker
, struct userNode
*victim
, struct chanNode
*chan
, UNUSED_ARG(void *extra
)) {
238 if (!track_cfg
.enabled
) return;
239 if (check_track_kick(track_cfg
) && check_track_user(victim
->nick
))
241 if (kicker
) /* net rider kicks dont have a kicker set */
243 if (!check_track_user(kicker
->nick
))
248 TRACK("$bKICK$b %s from %s by %s", victim
->nick
, chan
->name
, (kicker
? kicker
->nick
: "some server"));
253 track_new_user(struct userNode
*user
, UNUSED_ARG(void *extra
)) {
255 if (!track_cfg
.enabled
) return 0;
256 if (user
->uplink
->burst
&& !track_cfg
.show_bursts
) return 0;
257 if (check_track_new(track_cfg
) && check_track_user(user
->nick
))
260 TRACK("$bNICK$b %s %s@%s [%s] on %s", user
->nick
, user
->ident
, user
->hostname
, irc_ntoa(&user
->ip
), user
->uplink
->name
);
266 track_del_user(struct userNode
*user
, struct userNode
*killer
, const char *why
, UNUSED_ARG(void *extra
)) {
267 if (!track_cfg
.enabled
) return;
268 if (check_track_del(track_cfg
) && (check_track_user(user
->nick
) || (killer
&& check_track_user(killer
->nick
))))
272 TRACK("$bKILL$b %s (%s@%s, on %s) by %s (%s)", user
->nick
, user
->ident
, user
->hostname
, user
->uplink
->name
, killer
->nick
, why
);
274 TRACK("$bQUIT$b %s (%s@%s, on %s) (%s)", user
->nick
, user
->ident
, user
->hostname
, user
->uplink
->name
, why
);
276 del_track_user(user
->nick
);
281 track_auth(struct userNode
*user
, UNUSED_ARG(struct handle_info
*old_handle
), UNUSED_ARG(void *extra
)) {
282 if (!track_cfg
.enabled
) return;
283 if (user
->uplink
->burst
&& !track_cfg
.show_bursts
) return;
284 if (user
->handle_info
&& (check_track_auth(track_cfg
) && check_track_user(user
->nick
))) {
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
);
292 track_user_mode(struct userNode
*user
, const char *mode_change
, UNUSED_ARG(void *extra
)) {
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 */
296 if(check_track_umode(track_cfg
) && check_track_user(user
->nick
))
299 TRACK("$bUMODE$b %s %s", user
->nick
, mode_change
);
304 track_oper(struct userNode
*user
, UNUSED_ARG(void *extra
)) {
305 if (!track_cfg
.enabled
) return;
306 if (user
->uplink
->burst
&& !track_cfg
.show_bursts
) return;
308 TRACK("$bOPER$b %s!%s@%s [%s] on %s", user
->nick
, user
->ident
, user
->hostname
, irc_ntoa(&user
->ip
), user
->uplink
->name
);
312 track_channel_mode(struct userNode
*who
, struct chanNode
*channel
, char **modes
, unsigned int argc
, UNUSED_ARG(void *extra
))
314 if (!track_cfg
.enabled
) return;
317 if (who
->uplink
->burst
&& !track_cfg
.show_bursts
) return;
318 if (!check_track_chanmode(track_cfg
) || !check_track_user(who
->nick
)) return;
322 static char targets
[MAXLEN
], string
[MAXLEN
];
323 struct userNode
*un
= NULL
;
324 char *tmp
= NULL
, *tg
= NULL
, *md
= NULL
;
331 unsplit_string(modes
, argc
, string
);
333 strcpy(string
, *modes
);
335 if((tg
= strchr(string
, ' ')))
338 for(md
= string
; *md
; md
++)
354 strcat(targets
, " ");
355 if ((tmp
= strchr(tg
, ' ')))
366 strcat(targets
, " ");
367 if ((tmp
= strchr(tg
, ' ')))
377 strcat(targets
, " ");
378 if ((tmp
= strchr(tg
, ' ')))
387 strcat(targets
, " ");
388 if ((tmp
= strchr(tg
, ' ')))
397 strcat(targets
, " ");
398 if ((tmp
= strchr(tg
, ' ')))
400 if((un
= GetUserN(tg
)))
401 strcat(targets
, un
->nick
);
410 strcat(targets
, " ");
411 if ((tmp
= strchr(tg
, ' ')))
413 if((un
= GetUserN(tg
)))
414 strcat(targets
, un
->nick
);
426 TRACK("$bMODE$b %s %s%s by %s", channel
->name
, string
, targets
, who
->nick
);
428 TRACK("$bMODE$b %s %s%s", channel
->name
, string
, targets
);
432 check_track_state(struct userNode
*user
)
434 send_message_type(4, user
, track_cfg
.bot
, "TRACK is tracking: %s%s%s%s%s%s%s%s%s",
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":"");
442 MODCMD_FUNC(cmd_track
)
446 char changed
= false;
450 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
451 check_track_state(user
);
455 for(i
= 1; i
< argc
; i
++)
468 if ((!strcasecmp(data
, "all")))
470 set_track_all(track_cfg
);
471 check_track_state(user
);
472 TRACK("$bALERT$b TRACK fully enabled by %s", user
->nick
);
474 else if (!strcasecmp(data
, "none"))
476 clear_track_all(track_cfg
);
477 check_track_state(user
);
478 TRACK("$bALERT$b TRACK disabled by %s", user
->nick
);
482 send_message_type(4, user
, track_cfg
.bot
, "Unrecognised parameter: %s", data
);
483 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
490 if(!strcasecmp(data
, "auth")) {
492 set_track_auth(track_cfg
);
494 clear_track_auth(track_cfg
);
495 } else if(!strcasecmp(data
, "chanmode")) {
497 set_track_chanmode(track_cfg
);
499 clear_track_chanmode(track_cfg
);
500 } else if(!strcasecmp(data
, "del")) {
502 set_track_del(track_cfg
);
504 clear_track_del(track_cfg
);
505 } else if(!strcasecmp(data
, "join")) {
507 set_track_join(track_cfg
);
509 clear_track_join(track_cfg
);
510 } else if(!strcasecmp(data
, "kick")) {
512 set_track_kick(track_cfg
);
514 clear_track_kick(track_cfg
);
515 } else if(!strcasecmp(data
, "new")) {
517 set_track_new(track_cfg
);
519 clear_track_new(track_cfg
);
520 } else if(!strcasecmp(data
, "nick")) {
522 set_track_nick(track_cfg
);
524 clear_track_nick(track_cfg
);
525 } else if(!strcasecmp(data
, "part")) {
527 set_track_part(track_cfg
);
529 clear_track_part(track_cfg
);
530 } else if(!strcasecmp(data
, "umode")) {
532 set_track_umode(track_cfg
);
534 clear_track_umode(track_cfg
);
536 TRACK("Error, Unknown value %s", data
);
539 check_track_state(user
);
544 unsigned int pos
= 0;
545 memset(buf
, 0, sizeof(buf
));
546 for(i
= 1; i
< argc
; i
++)
551 if(pos
+ len
> sizeof(buf
))
553 strcpy(&buf
[pos
], data
);
558 TRACK("$bALERT$b TRACK command called with parameters '%s' by %s",
564 MODCMD_FUNC(cmd_deltrack
)
566 struct userNode
*un
= NULL
;
568 if((argc
> 1) && (un
= dict_find(clients
, argv
[1], NULL
)))
570 if(check_track_user(un
->nick
))
572 del_track_user(un
->nick
);
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
);
578 send_message_type(4, user
, track_cfg
.bot
, "This nick isn't monitored.");
582 send_message_type(4, user
, track_cfg
.bot
, "No nick or invalid nick specified.");
583 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
588 MODCMD_FUNC(cmd_addtrack
)
590 struct userNode
*un
= NULL
;
592 if((argc
> 1) && (un
= dict_find(clients
, argv
[1], NULL
)))
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
);
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
);
602 send_message_type(4, user
, track_cfg
.bot
, "No nick or invalid nick specified.");
603 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
608 MODCMD_FUNC(cmd_listtrack
)
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
);
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
);
620 send_message_type(4, user
, track_cfg
.bot
, "End of track list.");
625 track_conf_read(void) {
629 node
= conf_get_data("modules/track", RECDB_OBJECT
);
632 str
= database_get_data(node
, "snomask", RECDB_QSTRING
);
634 track_cfg
.snomask
= TRACK_NICK
|TRACK_KICK
|TRACK_JOIN
|TRACK_PART
|TRACK_CHANMODE
|TRACK_NEW
|TRACK_DEL
|TRACK_AUTH
;
636 parse_track_conf(str
);
637 str
= database_get_data(node
, "channel", RECDB_QSTRING
);
638 modes
= database_get_data(node
, "channel_modes", RECDB_QSTRING
);
641 // XXX - dont do addchannel if the channel is being shared with
643 track_cfg
.channel
= AddChannel(str
, now
, (modes
? modes
: "+sntOm"), NULL
, NULL
);
644 if (!track_cfg
.channel
)
646 str
= database_get_data(node
, "show_bursts", RECDB_QSTRING
);
647 track_cfg
.show_bursts
= str
? enabled_string(str
) : 0;
648 track_cfg
.enabled
= 1;
654 track_cleanup(UNUSED_ARG(void *extra
)) {
655 track_cfg
.enabled
= 0;
656 unreg_del_user_func(track_del_user
, NULL
);
657 dict_delete(track_db
);
662 track_db
= dict_new();
663 dict_set_free_keys(track_db
, free
);
665 reg_exit_func(track_cleanup
, NULL
);
666 conf_register_reload(track_conf_read
);
667 reg_nick_change_func(track_nick_change
, NULL
);
668 reg_join_func(track_join
, NULL
);
669 reg_part_func(track_part
, NULL
);
670 reg_kick_func(track_kick
, NULL
);
671 reg_new_user_func(track_new_user
, NULL
);
672 reg_del_user_func(track_del_user
, NULL
);
673 reg_auth_func(track_auth
, NULL
);
674 reg_channel_mode_func(track_channel_mode
, NULL
);
675 reg_user_mode_func(track_user_mode
, NULL
);
676 reg_oper_func(track_oper
, NULL
);
677 opserv_define_func("TRACK", cmd_track
, 800, 0, 0);
678 opserv_define_func("DELTRACK", cmd_deltrack
, 800, 0, 0);
679 opserv_define_func("ADDTRACK", cmd_addtrack
, 800, 0, 0);
680 opserv_define_func("LISTTRACK", cmd_listtrack
, 800, 0, 0);
685 track_finalize(void) {
686 struct mod_chanmode change
;
691 node
= conf_get_data("modules/track", RECDB_OBJECT
);
694 str
= database_get_data(node
, "snomask", RECDB_QSTRING
);
696 track_cfg
.snomask
= TRACK_NICK
|TRACK_KICK
|TRACK_JOIN
|TRACK_PART
|TRACK_CHANMODE
|TRACK_NEW
|TRACK_DEL
|TRACK_AUTH
;
698 parse_track_conf(str
);
699 str
= database_get_data(node
, "bot", RECDB_QSTRING
);
702 track_cfg
.bot
= GetUserH(str
);
705 mod_chanmode_init(&change
);
707 change
.args
[0].mode
= MODE_CHANOP
;
708 change
.args
[0].u
.member
= AddChannelUser(track_cfg
.bot
, track_cfg
.channel
);
709 mod_chanmode_announce(track_cfg
.bot
, track_cfg
.channel
, &change
);