]>
jfr.im git - irc/quakenet/newserv.git/blob - nickwatch/nickwatch.c
5 #include "../core/schedule.h"
6 #include "../lib/irc_string.h"
7 #include "../lib/splitline.h"
8 #include "../control/control.h"
9 #include "../newsearch/newsearch.h"
10 #include "../newsearch/parser.h"
12 #define NW_FORMAT_TIME "%d/%m/%y %H:%M GMT"
13 #define NW_DURATION_MAX (60*60*24*7) // 7 days
15 typedef struct nickwatch
{
25 struct nickwatch
*next
;
28 typedef struct nickwatchevent
{
29 char description
[128];
30 struct nickwatchevent
*next
;
33 static nickwatch
*nickwatches
;
34 static int nextnickwatch
= 1;
35 static int nickwatchext
;
37 static void nw_dummyreply(nick
*np
, char *format
, ...) { }
38 static void nw_dummywall(int level
, char *format
, ...) { }
40 static nickwatch
*nw_currentwatch
;
41 static array nw_pendingnicks
;
43 static int nw_nickunwatch(int id
) {
44 nickwatch
**pnext
, *nw
;
46 for (pnext
= &nickwatches
; *pnext
; pnext
= &((*pnext
)->next
)) {
60 static void nw_printnick(searchCtx
*ctx
, nick
*sender
, nick
*np
) {
61 char hostbuf
[HOSTLEN
+NICKLEN
+USERLEN
+4], modebuf
[34];
63 nickwatchevent
*nwe
= np
->exts
[nickwatchext
];
66 nw_currentwatch
->hits
++;
67 nw_currentwatch
->lastactive
= time(NULL
);
72 for (nwe
= np
->exts
[nickwatchext
]; nwe
; nwe
= nwe
->next
) {
74 len
+= snprintf(events
+ len
, sizeof(events
) - len
, ", ");
76 len
+= snprintf(events
+ len
, sizeof(events
) - len
, "%s", nwe
->description
);
79 strncpy(modebuf
, printflags(np
->umodes
, umodeflags
), sizeof(modebuf
));
81 controlwall(NO_OPER
, NL_HITS
, "nickwatch(#%d, %s): %s [%s] (%s) (%s)", nw_currentwatch
->id
, events
, visiblehostmask(np
,hostbuf
),
82 IPtostr(np
->ipaddress
), modebuf
, np
->realname
->name
->content
);
85 static void nwe_enqueue(nick
*np
, const char *format
, ...) {
90 nwe
= malloc(sizeof(nickwatchevent
));
93 vsnprintf(nwe
->description
, sizeof(nwe
->description
), format
, va
);
96 nwe
->next
= np
->exts
[nickwatchext
];
97 np
->exts
[nickwatchext
] = nwe
;
99 slot
= array_getfreeslot(&nw_pendingnicks
);
100 ((nick
**)nw_pendingnicks
.content
)[slot
] = np
;
103 static void nwe_clear(nick
*np
) {
104 nickwatchevent
*nwe
, *next
;
106 for (nwe
= np
->exts
[nickwatchext
]; nwe
; nwe
= next
) {
111 np
->exts
[nickwatchext
] = NULL
;
114 static void nw_sched_processevents(void *arg
) {
115 nickwatch
*nw
, *next
;
120 time_t now
= time(NULL
);
122 array_init(&nicks
, sizeof(nick
*));
123 marker
= nextnickmarker();
125 for (i
= 0; i
< nw_pendingnicks
.cursi
; i
++) {
126 np
= ((nick
**)nw_pendingnicks
.content
)[i
];
131 if (np
->marker
!= marker
) {
133 slot
= array_getfreeslot(&nicks
);
134 ((nick
**)nicks
.content
)[slot
] = np
;
138 array_free(&nw_pendingnicks
);
139 array_init(&nw_pendingnicks
, sizeof(nick
*));
141 for (nw
= nickwatches
; nw
; nw
= next
) {
142 nw_currentwatch
= nw
;
144 ast_nicksearch(nw
->tree
->root
, &nw_dummyreply
, mynick
, &nw_dummywall
, &nw_printnick
, NULL
, NULL
, 10, &nicks
);
145 if (nw
->expiry
&& nw
->expiry
<= now
) {
146 controlwall(NO_OPER
, NL_HITS
, "nickwatch(#%d) by %s expired (%d hits): %s", nw
->id
, nw
->createdby
, nw
->hits
, nw
->term
);
147 nw_nickunwatch(nw
->id
);
151 for (i
= 0; i
< nicks
.cursi
; i
++) {
152 np
= ((nick
**)nicks
.content
)[i
];
159 static void nw_hook_newnick(int hooknum
, void *arg
) {
161 nwe_enqueue(np
, "new user");
164 static void nw_hook_account(int hooknum
, void *arg
) {
166 nwe_enqueue(np
, "logged in with account %s", np
->authname
);
169 static void nw_hook_lostnick(int hooknum
, void *arg
) {
175 for (i
= 0; i
< nw_pendingnicks
.cursi
; i
++)
176 if (((nick
**)nw_pendingnicks
.content
)[i
] == np
)
177 ((nick
**)nw_pendingnicks
.content
)[i
] = NULL
;
180 static void nw_hook_rename(int hooknum
, void *arg
) {
183 char *oldnick
= args
[1];
184 nwe_enqueue(np
, "renamed from %s", oldnick
);
187 static void nw_hook_umodechange(int hooknum
, void *arg
) {
190 flag_t oldmodes
= (uintptr_t)args
[1];
192 strncpy(buf
, printflags(np
->umodes
, umodeflags
), sizeof(buf
));
193 nwe_enqueue(np
, "umodes %s -> %s", printflags(oldmodes
, umodeflags
), buf
);
196 static void nw_hook_message(int hooknum
, void *arg
) {
199 int isnotice
= (uintptr_t)args
[2];
200 nwe_enqueue(np
, isnotice
? "notice" : "message");
203 static void nw_hook_joinchannel(int hooknum
, void *arg
) {
205 channel
*cp
= args
[0];
207 nwe_enqueue(np
, "join channel %s", cp
->index
->name
->content
);
210 static int nw_cmd_nickwatch(void *source
, int cargc
, char **cargv
) {
211 nick
*sender
= source
;
214 time_t duration
= NW_DURATION_MAX
;
217 for (i
= 0; i
< cargc
&& cargv
[i
][0] == '-'; i
++) {
218 switch (cargv
[i
][1]) {
222 duration
= durationtolong(cargv
[i
]);
223 if (!duration
|| duration
> NW_DURATION_MAX
) {
224 controlreply(sender
, "Invalid duration. Maximum: %s.", longtoduration(NW_DURATION_MAX
, 1));
237 rejoinline(cargv
[i
],cargc
-i
);
239 tree
= parse_string(reg_nicksearch
, cargv
[i
]);
241 displaystrerror(controlreply
, sender
, cargv
[i
]);
245 nw
= malloc(sizeof(nickwatch
));
246 nw
->id
= nextnickwatch
++;
247 snprintf(nw
->createdby
, sizeof(nw
->createdby
), "#%s", sender
->authname
);
250 nw
->expiry
= duration
+ time(NULL
);
251 strncpy(nw
->term
, cargv
[i
], sizeof(nw
->term
));
253 nw
->next
= nickwatches
;
256 controlreply(sender
, "Done.");
261 static int nw_cmd_nickunwatch(void *source
, int cargc
, char **cargv
) {
262 nick
*sender
= source
;
270 if (nw_nickunwatch(id
)) {
271 controlreply(sender
, "Nickwatch #%d not found.", id
);
275 controlreply(sender
, "Done.");
279 static void nw_formattime(time_t time
, char *buf
, size_t bufsize
) {
281 strncpy(buf
, "(never)", bufsize
);
283 strftime(buf
, bufsize
, NW_FORMAT_TIME
, gmtime(&time
));
287 static int nw_cmd_nickwatches(void *source
, int cargc
, char **cargv
) {
288 nick
*sender
= source
;
290 char timebuf1
[20], timebuf2
[20];
292 controlreply(sender
, "ID Created By Hits Expires Last active Term");
294 for (nw
= nickwatches
; nw
; nw
= nw
->next
) {
295 nw_formattime(nw
->expiry
, timebuf1
, sizeof(timebuf1
));
296 nw_formattime(nw
->lastactive
, timebuf2
, sizeof(timebuf2
));
297 controlreply(sender
, "%-5d %-15s %-7d %-18s %-18s %s", nw
->id
, nw
->createdby
, nw
->hits
, timebuf1
, timebuf2
, nw
->term
);
300 controlreply(sender
, "--- End of nickwatches.");
306 nickwatchext
= registernickext("nickwatch");
308 array_init(&nw_pendingnicks
, sizeof(nick
*));
310 registercontrolhelpcmd("nickwatch", NO_OPER
, 3, &nw_cmd_nickwatch
, "Usage: nickwatch ?-d <duration (e.g. 12h5m)>? <nicksearch term>\nAdds a nickwatch entry.");
311 registercontrolhelpcmd("nickunwatch", NO_OPER
, 1, &nw_cmd_nickunwatch
, "Usage: nickunwatch <#id>\nRemoves a nickwatch entry.");
312 registercontrolhelpcmd("nickwatches", NO_OPER
, 0, &nw_cmd_nickwatches
, "Usage: nickwatches\nLists nickwatches.");
314 registerhook(HOOK_NICK_NEWNICK
, &nw_hook_newnick
);
315 registerhook(HOOK_NICK_ACCOUNT
, &nw_hook_account
);
316 registerhook(HOOK_NICK_LOSTNICK
, &nw_hook_lostnick
);
317 registerhook(HOOK_NICK_RENAME
, &nw_hook_rename
);
318 registerhook(HOOK_NICK_MODECHANGE
, &nw_hook_umodechange
);
319 registerhook(HOOK_NICK_MESSAGE
, &nw_hook_message
);
320 registerhook(HOOK_CHANNEL_CREATE
, &nw_hook_joinchannel
);
321 registerhook(HOOK_CHANNEL_JOIN
, &nw_hook_joinchannel
);
323 schedulerecurring(time(NULL
) + 5, 0, 1, &nw_sched_processevents
, NULL
);
327 nickwatch
*nw
, *next
;
329 deregistercontrolcmd("nickwatch", &nw_cmd_nickwatch
);
330 deregistercontrolcmd("nickunwatch", &nw_cmd_nickunwatch
);
331 deregistercontrolcmd("nickwatches", &nw_cmd_nickwatches
);
333 deregisterhook(HOOK_NICK_NEWNICK
, &nw_hook_newnick
);
334 deregisterhook(HOOK_NICK_ACCOUNT
, &nw_hook_account
);
335 deregisterhook(HOOK_NICK_LOSTNICK
, &nw_hook_lostnick
);
336 deregisterhook(HOOK_NICK_RENAME
, &nw_hook_rename
);
337 deregisterhook(HOOK_NICK_MODECHANGE
, &nw_hook_umodechange
);
338 deregisterhook(HOOK_NICK_MESSAGE
, &nw_hook_message
);
339 deregisterhook(HOOK_CHANNEL_CREATE
, &nw_hook_joinchannel
);
340 deregisterhook(HOOK_CHANNEL_JOIN
, &nw_hook_joinchannel
);
342 deleteallschedules(&nw_sched_processevents
);
344 /* Process all pending events */
345 nw_sched_processevents(NULL
);
347 array_free(&nw_pendingnicks
);
349 releasenickext(nickwatchext
);
351 for (nw
= nickwatches
; nw
; nw
= next
) {
354 parse_free(nw
->tree
);