]>
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
)
127 dict_find(track_db
, (const char *)user
->nick
, &found
);
132 parse_track_conf(char *line
)
134 char *t
= NULL
, *s
= line
;
138 if ((t
= strchr(s
, ',')))
141 switch (tolower(s
[0]))
144 if(!strcasecmp(s
, "auth"))
145 set_track_auth(track_cfg
);
148 if(!strcasecmp(s
, "chanmode"))
149 set_track_chanmode(track_cfg
);
152 if(!strcasecmp(s
, "del"))
153 set_track_del(track_cfg
);
156 if(!strcasecmp(s
, "join"))
157 set_track_join(track_cfg
);
160 if(!strcasecmp(s
, "kick"))
161 set_track_kick(track_cfg
);
164 if(!strcasecmp(s
, "new"))
165 set_track_new(track_cfg
);
166 if(!strcasecmp(s
, "nick"))
167 set_track_nick(track_cfg
);
170 if(!strcasecmp(s
, "part"))
171 set_track_nick(track_cfg
);
174 if(!strcasecmp(s
, "umode"))
175 set_track_umode(track_cfg
);
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
))
188 TRACK("$bNICK$b change %s -> %s", old_nick
, user
->nick
);
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
))
201 if (chan
->members
.used
== 1) {
202 TRACK("$bCREATE$b %s by %s", chan
->name
, user
->nick
);
204 TRACK("$bJOIN$b %s by %s", chan
->name
, user
->nick
);
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
))
217 TRACK("$bPART$b %s by %s (%s)", mn
->channel
->name
, mn
->user
->nick
, reason
? reason
: "");
222 track_kick(struct userNode
*kicker
, struct userNode
*victim
, struct chanNode
*chan
) {
223 if (!track_cfg
.enabled
) return;
224 if (check_track_kick(track_cfg
) && ((check_track_user(kicker
) || check_track_user(victim
))))
227 TRACK("$bKICK$b %s from %s by %s", victim
->nick
, chan
->name
, (kicker
? kicker
->nick
: "some server"));
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
))
238 TRACK("$bNICK$b %s %s@%s [%s] on %s", user
->nick
, user
->ident
, user
->hostname
, irc_ntoa(&user
->ip
), user
->uplink
->name
);
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
))))
250 TRACK("$bKILL$b %s (%s@%s, on %s) by %s (%s)", user
->nick
, user
->ident
, user
->hostname
, user
->uplink
->name
, killer
->nick
, why
);
252 TRACK("$bQUIT$b %s (%s@%s, on %s) (%s)", user
->nick
, user
->ident
, user
->hostname
, user
->uplink
->name
, why
);
254 del_track_user(user
);
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
))) {
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
);
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
))
277 TRACK("$bUMODE$b %s %s", user
->nick
, mode_change
);
282 track_oper(struct userNode
*user
) {
283 if (!track_cfg
.enabled
) return;
284 if (user
->uplink
->burst
&& !track_cfg
.show_bursts
) return;
286 TRACK("$bOPER$b %s!%s@%s [%s] on %s", user
->nick
, user
->ident
, user
->hostname
, irc_ntoa(&user
->ip
), user
->uplink
->name
);
290 track_channel_mode(struct userNode
*who
, struct chanNode
*channel
, char **modes
, unsigned int argc
)
292 if (!track_cfg
.enabled
) return;
295 if (who
->uplink
->burst
&& !track_cfg
.show_bursts
) return;
296 if (!check_track_chanmode(track_cfg
) || !check_track_user(who
)) return;
300 static char targets
[MAXLEN
], string
[MAXLEN
];
301 struct userNode
*un
= NULL
;
302 char *tmp
= NULL
, *tg
= NULL
, *md
= NULL
;
309 unsplit_string(modes
, argc
, string
);
311 strcpy(string
, *modes
);
313 if((tg
= strchr(string
, ' ')))
316 for(md
= string
; *md
; md
++)
332 strcat(targets
, " ");
333 if ((tmp
= strchr(tg
, ' ')))
344 strcat(targets
, " ");
345 if ((tmp
= strchr(tg
, ' ')))
355 strcat(targets
, " ");
356 if ((tmp
= strchr(tg
, ' ')))
365 strcat(targets
, " ");
366 if ((tmp
= strchr(tg
, ' ')))
375 strcat(targets
, " ");
376 if ((tmp
= strchr(tg
, ' ')))
378 if((un
= GetUserN(tg
)))
379 strcat(targets
, un
->nick
);
388 strcat(targets
, " ");
389 if ((tmp
= strchr(tg
, ' ')))
391 if((un
= GetUserN(tg
)))
392 strcat(targets
, un
->nick
);
404 TRACK("$bMODE$b %s %s%s by %s", channel
->name
, string
, targets
, who
->nick
);
406 TRACK("$bMODE$b %s %s%s", channel
->name
, string
, targets
);
410 check_track_state(struct userNode
*user
)
412 send_message_type(4, user
, track_cfg
.bot
, "TRACK is tracking: %s%s%s%s%s%s%s%s%s",
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":"");
420 MODCMD_FUNC(cmd_track
)
424 char changed
= false;
428 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
429 check_track_state(user
);
433 for(i
= 1; i
< argc
; i
++)
446 if ((!strcasecmp(data
, "all")))
448 set_track_all(track_cfg
);
449 check_track_state(user
);
450 TRACK("$bALERT$b TRACK fully enabled by %s", user
->nick
);
452 else if (!strcasecmp(data
, "none"))
454 clear_track_all(track_cfg
);
455 check_track_state(user
);
456 TRACK("$bALERT$b TRACK disabled by %s", user
->nick
);
460 send_message_type(4, user
, track_cfg
.bot
, "Unrecognised parameter: %s", data
);
461 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
468 switch(tolower(data
[0]))
471 if(!strcasecmp(data
, "auth"))
474 set_track_auth(track_cfg
);
476 clear_track_auth(track_cfg
);
480 if(!strcasecmp(data
, "chanmode"))
483 set_track_chanmode(track_cfg
);
485 clear_track_chanmode(track_cfg
);
489 if(!strcasecmp(data
, "del"))
492 set_track_del(track_cfg
);
494 clear_track_del(track_cfg
);
498 if(!strcasecmp(data
, "join"))
501 set_track_join(track_cfg
);
503 clear_track_join(track_cfg
);
507 if(!strcasecmp(data
, "kick"))
510 set_track_kick(track_cfg
);
512 clear_track_kick(track_cfg
);
516 if(!strcasecmp(data
, "new"))
519 set_track_new(track_cfg
);
521 clear_track_new(track_cfg
);
523 if(!strcasecmp(data
, "nick"))
526 set_track_nick(track_cfg
);
528 clear_track_nick(track_cfg
);
532 if(!strcasecmp(data
, "part"))
535 set_track_part(track_cfg
);
537 clear_track_part(track_cfg
);
541 if(!strcasecmp(data
, "umode"))
544 set_track_umode(track_cfg
);
546 clear_track_umode(track_cfg
);
550 TRACK("Error, Unknown value %s", data
);
554 check_track_state(user
);
559 unsigned int pos
= 0;
560 memset(buf
, 0, sizeof(buf
));
561 for(i
= 1; i
< argc
; i
++)
566 if(pos
+ len
> sizeof(buf
))
568 strcpy(&buf
[pos
], data
);
573 TRACK("$bALERT$b TRACK command called with parameters '%s' by %s",
579 MODCMD_FUNC(cmd_deltrack
)
581 struct userNode
*un
= NULL
;
583 if((argc
> 1) && (un
= dict_find(clients
, argv
[1], NULL
)))
585 if(check_track_user(un
))
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
);
593 send_message_type(4, user
, track_cfg
.bot
, "This nick isn't monitored.");
597 send_message_type(4, user
, track_cfg
.bot
, "No nick or invalid nick specified.");
598 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
603 MODCMD_FUNC(cmd_addtrack
)
605 struct userNode
*un
= NULL
;
607 if((argc
> 1) && (un
= dict_find(clients
, argv
[1], NULL
)))
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
);
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
);
617 send_message_type(4, user
, track_cfg
.bot
, "No nick or invalid nick specified.");
618 svccmd_send_help_brief(user
, track_cfg
.bot
, cmd
);
623 MODCMD_FUNC(cmd_listtrack
)
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
);
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
);
635 send_message_type(4, user
, track_cfg
.bot
, "End of track list.");
640 track_conf_read(void) {
644 node
= conf_get_data("modules/track", RECDB_OBJECT
);
647 str
= database_get_data(node
, "snomask", RECDB_QSTRING
);
649 track_cfg
.snomask
= TRACK_NICK
|TRACK_KICK
|TRACK_JOIN
|TRACK_PART
|TRACK_CHANMODE
|TRACK_NEW
|TRACK_DEL
|TRACK_AUTH
;
651 parse_track_conf(str
);
652 str
= database_get_data(node
, "channel", RECDB_QSTRING
);
655 // XXX - dont do addchannel if the channel is being shared with
657 track_cfg
.channel
= AddChannel(str
, now
, "+sntOm", NULL
, NULL
);
658 if (!track_cfg
.channel
)
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;
668 track_cleanup(void) {
669 track_cfg
.enabled
= 0;
670 unreg_del_user_func(track_del_user
);
675 track_db
= dict_new();
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);
697 track_finalize(void) {
698 struct mod_chanmode change
;
703 node
= conf_get_data("modules/track", RECDB_OBJECT
);
706 str
= database_get_data(node
, "snomask", RECDB_QSTRING
);
708 track_cfg
.snomask
= TRACK_NICK
|TRACK_KICK
|TRACK_JOIN
|TRACK_PART
|TRACK_CHANMODE
|TRACK_NEW
|TRACK_DEL
|TRACK_AUTH
;
710 parse_track_conf(str
);
711 str
= database_get_data(node
, "bot", RECDB_QSTRING
);
714 track_cfg
.bot
= GetUserH(str
);
717 mod_chanmode_init(&change
);
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
);