]>
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 2 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|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)
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))
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))
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); }
122 check_track_user(struct userNode
*user
)
125 dict_find(track_db
, (const char *)user
->nick
, &found
);
130 parse_track_conf(char *line
)
132 char *t
= NULL
, *s
= line
;
136 if ((t
= strchr(s
, ',')))
139 switch (tolower(s
[0]))
142 if(!strcasecmp(s
, "auth"))
143 set_track_auth(track_cfg
);
146 if(!strcasecmp(s
, "chanmode"))
147 set_track_chanmode(track_cfg
);
150 if(!strcasecmp(s
, "del"))
151 set_track_del(track_cfg
);
154 if(!strcasecmp(s
, "join"))
155 set_track_join(track_cfg
);
158 if(!strcasecmp(s
, "kick"))
159 set_track_kick(track_cfg
);
162 if(!strcasecmp(s
, "new"))
163 set_track_new(track_cfg
);
164 if(!strcasecmp(s
, "nick"))
165 set_track_nick(track_cfg
);
168 if(!strcasecmp(s
, "part"))
169 set_track_nick(track_cfg
);
172 if(!strcasecmp(s
, "umode"))
173 set_track_umode(track_cfg
);
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
))
186 TRACK("$bNICK$b change %s -> %s", old_nick
, user
->nick
);
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
))
199 if (chan
->members
.used
== 1) {
200 TRACK("$bCREATE$b %s by %s", chan
->name
, user
->nick
);
202 TRACK("$bJOIN$b %s by %s", chan
->name
, user
->nick
);
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
))
215 TRACK("$bPART$b %s by %s (%s)", mn
->channel
->name
, mn
->user
->nick
, reason
? reason
: "");
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
))))
225 TRACK("$bKICK$b %s from %s by %s", victim
->nick
, chan
->name
, (kicker
? kicker
->nick
: "some server"));
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
))
236 TRACK("$bNICK$b %s %s@%s [%s] on %s", user
->nick
, user
->ident
, user
->hostname
, irc_ntoa(&user
->ip
), user
->uplink
->name
);
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
))))
248 TRACK("$bKILL$b %s (%s@%s, on %s) by %s (%s)", user
->nick
, user
->ident
, user
->hostname
, user
->uplink
->name
, killer
->nick
, why
);
250 TRACK("$bQUIT$b %s (%s@%s, on %s) (%s)", user
->nick
, user
->ident
, user
->hostname
, user
->uplink
->name
, why
);
252 del_track_user(user
);
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
))) {
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
);
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
))
275 TRACK("$bUMODE$b %s %s", user
->nick
, mode_change
);
280 track_oper(struct userNode
*user
) {
281 if (!track_cfg
.enabled
) return;
282 if (user
->uplink
->burst
&& !track_cfg
.show_bursts
) return;
284 TRACK("$bOPER$b %s!%s@%s [%s] on %s", user
->nick
, user
->ident
, user
->hostname
, irc_ntoa(&user
->ip
), user
->uplink
->name
);
288 track_channel_mode(struct userNode
*who
, struct chanNode
*channel
, char **modes
, unsigned int argc
)
290 if (!track_cfg
.enabled
) return;
293 if (who
->uplink
->burst
&& !track_cfg
.show_bursts
) return;
294 if (!check_track_chanmode(track_cfg
) || !check_track_user(who
)) return;
298 static char targets
[MAXLEN
], string
[MAXLEN
];
299 struct userNode
*un
= NULL
;
300 char *tmp
= NULL
, *tg
= NULL
, *md
= NULL
;
307 unsplit_string(modes
, argc
, string
);
309 strcpy(string
, *modes
);
311 if((tg
= strchr(string
, ' ')))
314 for(md
= string
; *md
; md
++)
330 strcat(targets
, " ");
331 if ((tmp
= strchr(tg
, ' ')))
342 strcat(targets
, " ");
343 if ((tmp
= strchr(tg
, ' ')))
353 strcat(targets
, " ");
354 if ((tmp
= strchr(tg
, ' ')))
363 strcat(targets
, " ");
364 if ((tmp
= strchr(tg
, ' ')))
373 strcat(targets
, " ");
374 if ((tmp
= strchr(tg
, ' ')))
376 if((un
= GetUserN(tg
)))
377 strcat(targets
, un
->nick
);
386 strcat(targets
, " ");
387 if ((tmp
= strchr(tg
, ' ')))
389 if((un
= GetUserN(tg
)))
390 strcat(targets
, un
->nick
);
402 TRACK("$bMODE$b %s %s%s by %s", channel
->name
, string
, targets
, who
->nick
);
404 TRACK("$bMODE$b %s %s%s", channel
->name
, string
, targets
);
408 check_track_state(struct userNode
*user
)
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":"");
418 MODCMD_FUNC(cmd_track
)
422 char changed
= false;
426 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
427 check_track_state(user
);
431 for(i
= 1; i
< argc
; i
++)
444 if ((!strcasecmp(data
, "all")))
446 set_track_all(track_cfg
);
447 check_track_state(user
);
448 TRACK("$bALERT$b TRACK fully enabled by %s", user
->nick
);
450 else if (!strcasecmp(data
, "none"))
452 clear_track_all(track_cfg
);
453 check_track_state(user
);
454 TRACK("$bALERT$b TRACK disabled by %s", user
->nick
);
458 send_message_type(4, user
, track_cfg
.bot
, "Unrecognised parameter: %s", data
);
459 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
466 switch(tolower(data
[0]))
469 if(!strcasecmp(data
, "auth"))
472 set_track_auth(track_cfg
);
474 clear_track_auth(track_cfg
);
478 if(!strcasecmp(data
, "chanmode"))
481 set_track_chanmode(track_cfg
);
483 clear_track_chanmode(track_cfg
);
487 if(!strcasecmp(data
, "del"))
490 set_track_del(track_cfg
);
492 clear_track_del(track_cfg
);
496 if(!strcasecmp(data
, "join"))
499 set_track_join(track_cfg
);
501 clear_track_join(track_cfg
);
505 if(!strcasecmp(data
, "kick"))
508 set_track_kick(track_cfg
);
510 clear_track_kick(track_cfg
);
514 if(!strcasecmp(data
, "new"))
517 set_track_new(track_cfg
);
519 clear_track_new(track_cfg
);
521 if(!strcasecmp(data
, "nick"))
524 set_track_nick(track_cfg
);
526 clear_track_nick(track_cfg
);
530 if(!strcasecmp(data
, "part"))
533 set_track_part(track_cfg
);
535 clear_track_part(track_cfg
);
539 if(!strcasecmp(data
, "umode"))
542 set_track_umode(track_cfg
);
544 clear_track_umode(track_cfg
);
548 TRACK("Error, Unknown value %s", data
);
552 check_track_state(user
);
557 unsigned int pos
= 0;
558 memset(buf
, 0, sizeof(buf
));
559 for(i
= 1; i
< argc
; i
++)
564 if(pos
+ len
> sizeof(buf
))
566 strcpy(&buf
[pos
], data
);
571 TRACK("$bALERT$b TRACK command called with parameters '%s' by %s",
577 MODCMD_FUNC(cmd_deltrack
)
579 struct userNode
*un
= NULL
;
581 if((argc
> 1) && (un
= dict_find(clients
, argv
[1], NULL
)))
583 if(check_track_user(un
))
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
);
591 send_message_type(4, user
, track_cfg
.bot
, "This nick isn't monitored.");
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
);
601 MODCMD_FUNC(cmd_addtrack
)
603 struct userNode
*un
= NULL
;
605 if((argc
> 1) && (un
= dict_find(clients
, argv
[1], NULL
)))
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
);
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
);
621 MODCMD_FUNC(cmd_listtrack
)
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
);
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
);
633 send_message_type(4, user
, track_cfg
.bot
, "End of track list.");
638 track_conf_read(void) {
642 node
= conf_get_data("modules/track", RECDB_OBJECT
);
645 str
= database_get_data(node
, "snomask", RECDB_QSTRING
);
647 track_cfg
.snomask
= TRACK_NICK
|TRACK_KICK
|TRACK_JOIN
|TRACK_PART
|TRACK_CHANMODE
|TRACK_NEW
|TRACK_DEL
|TRACK_AUTH
;
649 parse_track_conf(str
);
650 str
= database_get_data(node
, "channel", RECDB_QSTRING
);
653 // XXX - dont do addchannel if the channel is being shared with
655 track_cfg
.channel
= AddChannel(str
, now
, "+sntOm", NULL
, NULL
);
656 if (!track_cfg
.channel
)
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;
666 track_cleanup(void) {
667 track_cfg
.enabled
= 0;
668 unreg_del_user_func(track_del_user
);
673 track_db
= dict_new();
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);
695 track_finalize(void) {
696 struct mod_chanmode change
;
701 node
= conf_get_data("modules/track", RECDB_OBJECT
);
704 str
= database_get_data(node
, "snomask", RECDB_QSTRING
);
706 track_cfg
.snomask
= TRACK_NICK
|TRACK_KICK
|TRACK_JOIN
|TRACK_PART
|TRACK_CHANMODE
|TRACK_NEW
|TRACK_DEL
|TRACK_AUTH
;
708 parse_track_conf(str
);
709 str
= database_get_data(node
, "bot", RECDB_QSTRING
);
712 track_cfg
.bot
= GetUserH(str
);
715 mod_chanmode_init(&change
);
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
);