]>
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
) {
249 if (!track_cfg
.enabled
) return 0;
250 if (user
->uplink
->burst
&& !track_cfg
.show_bursts
) return 0;
251 if (check_track_new(track_cfg
) && check_track_user(user
->nick
))
254 TRACK("$bNICK$b %s %s@%s [%s] on %s", user
->nick
, user
->ident
, user
->hostname
, irc_ntoa(&user
->ip
), user
->uplink
->name
);
260 track_del_user(struct userNode
*user
, struct userNode
*killer
, const char *why
) {
261 if (!track_cfg
.enabled
) return;
262 if (check_track_del(track_cfg
) && (check_track_user(user
->nick
) || (killer
&& check_track_user(killer
->nick
))))
266 TRACK("$bKILL$b %s (%s@%s, on %s) by %s (%s)", user
->nick
, user
->ident
, user
->hostname
, user
->uplink
->name
, killer
->nick
, why
);
268 TRACK("$bQUIT$b %s (%s@%s, on %s) (%s)", user
->nick
, user
->ident
, user
->hostname
, user
->uplink
->name
, why
);
270 del_track_user(user
->nick
);
275 track_auth(struct userNode
*user
, UNUSED_ARG(struct handle_info
*old_handle
)) {
276 if (!track_cfg
.enabled
) return;
277 if (user
->uplink
->burst
&& !track_cfg
.show_bursts
) return;
278 if (user
->handle_info
&& (check_track_auth(track_cfg
) && check_track_user(user
->nick
))) {
280 TRACK("$bAUTH$b %s!%s@%s [%s] on %s as %s", user
->nick
, user
->ident
, user
->hostname
,
281 irc_ntoa(&user
->ip
), user
->uplink
->name
, user
->handle_info
->handle
);
286 track_user_mode(struct userNode
*user
, const char *mode_change
) {
287 if (!track_cfg
.enabled
) return;
288 if (user
->uplink
->burst
&& !track_cfg
.show_bursts
) return;
289 if (!mode_change
[1]) return; /* warning there has to be atleast one char in the buffer */
290 if(check_track_umode(track_cfg
) && check_track_user(user
->nick
))
293 TRACK("$bUMODE$b %s %s", user
->nick
, mode_change
);
298 track_oper(struct userNode
*user
) {
299 if (!track_cfg
.enabled
) return;
300 if (user
->uplink
->burst
&& !track_cfg
.show_bursts
) return;
302 TRACK("$bOPER$b %s!%s@%s [%s] on %s", user
->nick
, user
->ident
, user
->hostname
, irc_ntoa(&user
->ip
), user
->uplink
->name
);
306 track_channel_mode(struct userNode
*who
, struct chanNode
*channel
, char **modes
, unsigned int argc
)
308 if (!track_cfg
.enabled
) return;
311 if (who
->uplink
->burst
&& !track_cfg
.show_bursts
) return;
312 if (!check_track_chanmode(track_cfg
) || !check_track_user(who
->nick
)) return;
316 static char targets
[MAXLEN
], string
[MAXLEN
];
317 struct userNode
*un
= NULL
;
318 char *tmp
= NULL
, *tg
= NULL
, *md
= NULL
;
325 unsplit_string(modes
, argc
, string
);
327 strcpy(string
, *modes
);
329 if((tg
= strchr(string
, ' ')))
332 for(md
= string
; *md
; md
++)
348 strcat(targets
, " ");
349 if ((tmp
= strchr(tg
, ' ')))
360 strcat(targets
, " ");
361 if ((tmp
= strchr(tg
, ' ')))
371 strcat(targets
, " ");
372 if ((tmp
= strchr(tg
, ' ')))
381 strcat(targets
, " ");
382 if ((tmp
= strchr(tg
, ' ')))
391 strcat(targets
, " ");
392 if ((tmp
= strchr(tg
, ' ')))
394 if((un
= GetUserN(tg
)))
395 strcat(targets
, un
->nick
);
404 strcat(targets
, " ");
405 if ((tmp
= strchr(tg
, ' ')))
407 if((un
= GetUserN(tg
)))
408 strcat(targets
, un
->nick
);
420 TRACK("$bMODE$b %s %s%s by %s", channel
->name
, string
, targets
, who
->nick
);
422 TRACK("$bMODE$b %s %s%s", channel
->name
, string
, targets
);
426 check_track_state(struct userNode
*user
)
428 send_message_type(4, user
, track_cfg
.bot
, "TRACK is tracking: %s%s%s%s%s%s%s%s%s",
429 check_track_nick(track_cfg
) ? " nick":"", check_track_join(track_cfg
) ? " join":"",
430 check_track_part(track_cfg
) ? " part":"", check_track_kick(track_cfg
) ? " kick":"",
431 check_track_new(track_cfg
) ? " new":"", check_track_del(track_cfg
) ? " del":"",
432 check_track_auth(track_cfg
) ? " auth":"", check_track_chanmode(track_cfg
) ? " chanmode":"",
433 check_track_umode(track_cfg
) ? " umode":"");
436 MODCMD_FUNC(cmd_track
)
440 char changed
= false;
444 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
445 check_track_state(user
);
449 for(i
= 1; i
< argc
; i
++)
462 if ((!strcasecmp(data
, "all")))
464 set_track_all(track_cfg
);
465 check_track_state(user
);
466 TRACK("$bALERT$b TRACK fully enabled by %s", user
->nick
);
468 else if (!strcasecmp(data
, "none"))
470 clear_track_all(track_cfg
);
471 check_track_state(user
);
472 TRACK("$bALERT$b TRACK disabled by %s", user
->nick
);
476 send_message_type(4, user
, track_cfg
.bot
, "Unrecognised parameter: %s", data
);
477 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
484 if(!strcasecmp(data
, "auth")) {
486 set_track_auth(track_cfg
);
488 clear_track_auth(track_cfg
);
489 } else if(!strcasecmp(data
, "chanmode")) {
491 set_track_chanmode(track_cfg
);
493 clear_track_chanmode(track_cfg
);
494 } else if(!strcasecmp(data
, "del")) {
496 set_track_del(track_cfg
);
498 clear_track_del(track_cfg
);
499 } else if(!strcasecmp(data
, "join")) {
501 set_track_join(track_cfg
);
503 clear_track_join(track_cfg
);
504 } else if(!strcasecmp(data
, "kick")) {
506 set_track_kick(track_cfg
);
508 clear_track_kick(track_cfg
);
509 } else if(!strcasecmp(data
, "new")) {
511 set_track_new(track_cfg
);
513 clear_track_new(track_cfg
);
514 } else if(!strcasecmp(data
, "nick")) {
516 set_track_nick(track_cfg
);
518 clear_track_nick(track_cfg
);
519 } else if(!strcasecmp(data
, "part")) {
521 set_track_part(track_cfg
);
523 clear_track_part(track_cfg
);
524 } else if(!strcasecmp(data
, "umode")) {
526 set_track_umode(track_cfg
);
528 clear_track_umode(track_cfg
);
530 TRACK("Error, Unknown value %s", data
);
533 check_track_state(user
);
538 unsigned int pos
= 0;
539 memset(buf
, 0, sizeof(buf
));
540 for(i
= 1; i
< argc
; i
++)
545 if(pos
+ len
> sizeof(buf
))
547 strcpy(&buf
[pos
], data
);
552 TRACK("$bALERT$b TRACK command called with parameters '%s' by %s",
558 MODCMD_FUNC(cmd_deltrack
)
560 struct userNode
*un
= NULL
;
562 if((argc
> 1) && (un
= dict_find(clients
, argv
[1], NULL
)))
564 if(check_track_user(un
->nick
))
566 del_track_user(un
->nick
);
568 TRACK("$bALERT$b No longer monitoring %s!%s@%s on %s requested by %s",
569 un
->nick
, un
->ident
, un
->hostname
, un
->uplink
->name
, user
->nick
);
572 send_message_type(4, user
, track_cfg
.bot
, "This nick isn't monitored.");
576 send_message_type(4, user
, track_cfg
.bot
, "No nick or invalid nick specified.");
577 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
582 MODCMD_FUNC(cmd_addtrack
)
584 struct userNode
*un
= NULL
;
586 if((argc
> 1) && (un
= dict_find(clients
, argv
[1], NULL
)))
590 TRACK("$bALERT$b Manually enabled monitoring of %s!%s@%s on %s requested by %s",
591 un
->nick
, un
->ident
, un
->hostname
, un
->uplink
->name
, user
->nick
);
592 send_message_type(4, user
, track_cfg
.bot
, "Now tracking %s!%s@%s on %s", un
->nick
,un
->ident
,un
->hostname
, un
->uplink
->name
);
596 send_message_type(4, user
, track_cfg
.bot
, "No nick or invalid nick specified.");
597 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
602 MODCMD_FUNC(cmd_listtrack
)
604 dict_iterator_t it
, next
;
605 if (track_db
== NULL
) return 0;
606 struct userNode
*un
= NULL
;
607 send_message_type(4, user
, track_cfg
.bot
, "Currently tracking:");
608 for (it
=dict_first(track_db
); it
; it
=next
) {
609 next
= iter_next(it
);
611 send_message_type(4, user
, track_cfg
.bot
, "%s!%s@%s [%s] on %s",
612 un
->nick
, un
->ident
, un
->hostname
, irc_ntoa(&un
->ip
), un
->uplink
->name
);
614 send_message_type(4, user
, track_cfg
.bot
, "End of track list.");
619 track_conf_read(void) {
623 node
= conf_get_data("modules/track", RECDB_OBJECT
);
626 str
= database_get_data(node
, "snomask", RECDB_QSTRING
);
628 track_cfg
.snomask
= TRACK_NICK
|TRACK_KICK
|TRACK_JOIN
|TRACK_PART
|TRACK_CHANMODE
|TRACK_NEW
|TRACK_DEL
|TRACK_AUTH
;
630 parse_track_conf(str
);
631 str
= database_get_data(node
, "channel", RECDB_QSTRING
);
634 // XXX - dont do addchannel if the channel is being shared with
636 track_cfg
.channel
= AddChannel(str
, now
, "+sntOm", NULL
, NULL
);
637 if (!track_cfg
.channel
)
639 str
= database_get_data(node
, "show_bursts", RECDB_QSTRING
);
640 track_cfg
.show_bursts
= str
? enabled_string(str
) : 0;
641 track_cfg
.enabled
= 1;
647 track_cleanup(void) {
648 track_cfg
.enabled
= 0;
649 unreg_del_user_func(track_del_user
);
650 dict_delete(track_db
);
655 track_db
= dict_new();
656 dict_set_free_keys(track_db
, free
);
658 reg_exit_func(track_cleanup
);
659 conf_register_reload(track_conf_read
);
660 reg_nick_change_func(track_nick_change
);
661 reg_join_func(track_join
);
662 reg_part_func(track_part
);
663 reg_kick_func(track_kick
);
664 reg_new_user_func(track_new_user
);
665 reg_del_user_func(track_del_user
);
666 reg_auth_func(track_auth
);
667 reg_channel_mode_func(track_channel_mode
);
668 reg_user_mode_func(track_user_mode
);
669 reg_oper_func(track_oper
);
670 opserv_define_func("TRACK", cmd_track
, 800, 0, 0);
671 opserv_define_func("DELTRACK", cmd_deltrack
, 800, 0, 0);
672 opserv_define_func("ADDTRACK", cmd_addtrack
, 800, 0, 0);
673 opserv_define_func("LISTTRACK", cmd_listtrack
, 800, 0, 0);
678 track_finalize(void) {
679 struct mod_chanmode change
;
684 node
= conf_get_data("modules/track", RECDB_OBJECT
);
687 str
= database_get_data(node
, "snomask", RECDB_QSTRING
);
689 track_cfg
.snomask
= TRACK_NICK
|TRACK_KICK
|TRACK_JOIN
|TRACK_PART
|TRACK_CHANMODE
|TRACK_NEW
|TRACK_DEL
|TRACK_AUTH
;
691 parse_track_conf(str
);
692 str
= database_get_data(node
, "bot", RECDB_QSTRING
);
695 track_cfg
.bot
= GetUserH(str
);
698 mod_chanmode_init(&change
);
700 change
.args
[0].mode
= MODE_CHANOP
;
701 change
.args
[0].u
.member
= AddChannelUser(track_cfg
.bot
, track_cfg
.channel
);
702 mod_chanmode_announce(track_cfg
.bot
, track_cfg
.channel
, &change
);