]>
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
) {
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
) {
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
) {
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
) {
238 if (!track_cfg
.enabled
) return;
239 if (check_track_kick(track_cfg
) && ((check_track_user(kicker
->nick
) || check_track_user(victim
->nick
))))
242 TRACK("$bKICK$b %s from %s by %s", victim
->nick
, chan
->name
, (kicker
? kicker
->nick
: "some server"));
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
))
253 TRACK("$bNICK$b %s %s@%s [%s] on %s", user
->nick
, user
->ident
, user
->hostname
, irc_ntoa(&user
->ip
), user
->uplink
->name
);
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
))))
265 TRACK("$bKILL$b %s (%s@%s, on %s) by %s (%s)", user
->nick
, user
->ident
, user
->hostname
, user
->uplink
->name
, killer
->nick
, why
);
267 TRACK("$bQUIT$b %s (%s@%s, on %s) (%s)", user
->nick
, user
->ident
, user
->hostname
, user
->uplink
->name
, why
);
269 del_track_user(user
->nick
);
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
))) {
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
);
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
))
292 TRACK("$bUMODE$b %s %s", user
->nick
, mode_change
);
297 track_oper(struct userNode
*user
) {
298 if (!track_cfg
.enabled
) return;
299 if (user
->uplink
->burst
&& !track_cfg
.show_bursts
) return;
301 TRACK("$bOPER$b %s!%s@%s [%s] on %s", user
->nick
, user
->ident
, user
->hostname
, irc_ntoa(&user
->ip
), user
->uplink
->name
);
305 track_channel_mode(struct userNode
*who
, struct chanNode
*channel
, char **modes
, unsigned int argc
)
307 if (!track_cfg
.enabled
) return;
310 if (who
->uplink
->burst
&& !track_cfg
.show_bursts
) return;
311 if (!check_track_chanmode(track_cfg
) || !check_track_user(who
->nick
)) return;
315 static char targets
[MAXLEN
], string
[MAXLEN
];
316 struct userNode
*un
= NULL
;
317 char *tmp
= NULL
, *tg
= NULL
, *md
= NULL
;
324 unsplit_string(modes
, argc
, string
);
326 strcpy(string
, *modes
);
328 if((tg
= strchr(string
, ' ')))
331 for(md
= string
; *md
; md
++)
347 strcat(targets
, " ");
348 if ((tmp
= strchr(tg
, ' ')))
359 strcat(targets
, " ");
360 if ((tmp
= strchr(tg
, ' ')))
370 strcat(targets
, " ");
371 if ((tmp
= strchr(tg
, ' ')))
380 strcat(targets
, " ");
381 if ((tmp
= strchr(tg
, ' ')))
390 strcat(targets
, " ");
391 if ((tmp
= strchr(tg
, ' ')))
393 if((un
= GetUserN(tg
)))
394 strcat(targets
, un
->nick
);
403 strcat(targets
, " ");
404 if ((tmp
= strchr(tg
, ' ')))
406 if((un
= GetUserN(tg
)))
407 strcat(targets
, un
->nick
);
419 TRACK("$bMODE$b %s %s%s by %s", channel
->name
, string
, targets
, who
->nick
);
421 TRACK("$bMODE$b %s %s%s", channel
->name
, string
, targets
);
425 check_track_state(struct userNode
*user
)
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":"");
435 MODCMD_FUNC(cmd_track
)
439 char changed
= false;
443 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
444 check_track_state(user
);
448 for(i
= 1; i
< argc
; i
++)
461 if ((!strcasecmp(data
, "all")))
463 set_track_all(track_cfg
);
464 check_track_state(user
);
465 TRACK("$bALERT$b TRACK fully enabled by %s", user
->nick
);
467 else if (!strcasecmp(data
, "none"))
469 clear_track_all(track_cfg
);
470 check_track_state(user
);
471 TRACK("$bALERT$b TRACK disabled by %s", user
->nick
);
475 send_message_type(4, user
, track_cfg
.bot
, "Unrecognised parameter: %s", data
);
476 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
483 if(!strcasecmp(data
, "auth")) {
485 set_track_auth(track_cfg
);
487 clear_track_auth(track_cfg
);
488 } else if(!strcasecmp(data
, "chanmode")) {
490 set_track_chanmode(track_cfg
);
492 clear_track_chanmode(track_cfg
);
493 } else if(!strcasecmp(data
, "del")) {
495 set_track_del(track_cfg
);
497 clear_track_del(track_cfg
);
498 } else if(!strcasecmp(data
, "join")) {
500 set_track_join(track_cfg
);
502 clear_track_join(track_cfg
);
503 } else if(!strcasecmp(data
, "kick")) {
505 set_track_kick(track_cfg
);
507 clear_track_kick(track_cfg
);
508 } else if(!strcasecmp(data
, "new")) {
510 set_track_new(track_cfg
);
512 clear_track_new(track_cfg
);
513 } else if(!strcasecmp(data
, "nick")) {
515 set_track_nick(track_cfg
);
517 clear_track_nick(track_cfg
);
518 } else if(!strcasecmp(data
, "part")) {
520 set_track_part(track_cfg
);
522 clear_track_part(track_cfg
);
523 } else if(!strcasecmp(data
, "umode")) {
525 set_track_umode(track_cfg
);
527 clear_track_umode(track_cfg
);
529 TRACK("Error, Unknown value %s", data
);
532 check_track_state(user
);
537 unsigned int pos
= 0;
538 memset(buf
, 0, sizeof(buf
));
539 for(i
= 1; i
< argc
; i
++)
544 if(pos
+ len
> sizeof(buf
))
546 strcpy(&buf
[pos
], data
);
551 TRACK("$bALERT$b TRACK command called with parameters '%s' by %s",
557 MODCMD_FUNC(cmd_deltrack
)
559 struct userNode
*un
= NULL
;
561 if((argc
> 1) && (un
= dict_find(clients
, argv
[1], NULL
)))
563 if(check_track_user(un
->nick
))
565 del_track_user(un
->nick
);
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
);
571 send_message_type(4, user
, track_cfg
.bot
, "This nick isn't monitored.");
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
);
581 MODCMD_FUNC(cmd_addtrack
)
583 struct userNode
*un
= NULL
;
585 if((argc
> 1) && (un
= dict_find(clients
, argv
[1], NULL
)))
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
);
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_listtrack
)
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
);
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
);
613 send_message_type(4, user
, track_cfg
.bot
, "End of track list.");
618 track_conf_read(void) {
622 node
= conf_get_data("modules/track", RECDB_OBJECT
);
625 str
= database_get_data(node
, "snomask", RECDB_QSTRING
);
627 track_cfg
.snomask
= TRACK_NICK
|TRACK_KICK
|TRACK_JOIN
|TRACK_PART
|TRACK_CHANMODE
|TRACK_NEW
|TRACK_DEL
|TRACK_AUTH
;
629 parse_track_conf(str
);
630 str
= database_get_data(node
, "channel", RECDB_QSTRING
);
633 // XXX - dont do addchannel if the channel is being shared with
635 track_cfg
.channel
= AddChannel(str
, now
, "+sntOm", NULL
, NULL
);
636 if (!track_cfg
.channel
)
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;
646 track_cleanup(void) {
647 track_cfg
.enabled
= 0;
648 unreg_del_user_func(track_del_user
);
649 dict_delete(track_db
);
654 track_db
= dict_new();
655 dict_set_free_keys(track_db
, free
);
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);
677 track_finalize(void) {
678 struct mod_chanmode change
;
683 node
= conf_get_data("modules/track", RECDB_OBJECT
);
686 str
= database_get_data(node
, "snomask", RECDB_QSTRING
);
688 track_cfg
.snomask
= TRACK_NICK
|TRACK_KICK
|TRACK_JOIN
|TRACK_PART
|TRACK_CHANMODE
|TRACK_NEW
|TRACK_DEL
|TRACK_AUTH
;
690 parse_track_conf(str
);
691 str
= database_get_data(node
, "bot", RECDB_QSTRING
);
694 track_cfg
.bot
= GetUserH(str
);
697 mod_chanmode_init(&change
);
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
);