1 #include "versionscan.h"
3 CommandTree
* versionscan_commands
;
4 nick
* versionscan_nick
;
10 unsigned long hcount
=0;
11 unsigned long wcount
=0;
12 unsigned long kcount
=0;
13 unsigned long gcount
=0;
16 void versionscan_addstat(char* reply
) {
17 unsigned int replylen
;
18 unsigned long replycrc
;
21 replylen
= strlen(reply
);
22 replycrc
= crc32i(reply
);
25 for (v
=vsstats
; v
; v
=v
->next
) {
26 if (v
->replylen
==replylen
&& v
->replycrc
==replycrc
) {
33 vsstats
=(vsstatistic
*)malloc(sizeof(vsstatistic
));
34 vsstats
->reply
=(char*)malloc(replylen
+ 1);
35 strcpy(vsstats
->reply
, reply
);
36 vsstats
->replylen
= replylen
;
37 vsstats
->replycrc
= replycrc
;
42 pv
->next
=(vsstatistic
*)malloc(sizeof(vsstatistic
));
43 pv
->next
->reply
=(char*)malloc(replylen
+ 1);
44 strcpy(pv
->next
->reply
, reply
);
45 pv
->next
->replylen
= replylen
;
46 pv
->next
->replycrc
= replycrc
;
52 unsigned char versionscan_getlevelbyauth(char* auth
) {
55 for (v
=vsauths
; v
; v
=v
->next
) {
56 if (!ircd_strcmp(v
->account
, auth
)) {
63 vsauthdata
* versionscan_getauthbyauth(char* auth
) {
66 for (v
=vsauths
; v
; v
=v
->next
) {
67 if (!ircd_strcmp(v
->account
, auth
)) {
74 int IsVersionscanStaff(nick
* np
) {
80 level
=versionscan_getlevelbyauth(np
->authname
);
81 if (level
& (VS_STAFF
| VS_GLINE
| VS_ADMIN
)) {
87 int IsVersionscanGlineAccess(nick
* np
) {
93 level
=versionscan_getlevelbyauth(np
->authname
);
94 if (level
& (VS_GLINE
| VS_ADMIN
)) {
100 int IsVersionscanAdmin(nick
* np
) {
103 if (!IsAccount(np
)) {
106 level
=versionscan_getlevelbyauth(np
->authname
);
107 if (level
& VS_ADMIN
) {
113 const char* versionscan_flagstochar(unsigned char flags
) {
114 static char outstring
[50];
117 outstring
[pos
++]='+';
118 if (flags
& VS_ADMIN
) { outstring
[pos
++]='a'; }
119 if (flags
& VS_GLINE
) { outstring
[pos
++]='g'; }
120 if (flags
& VS_STAFF
) { outstring
[pos
++]='s'; }
126 void versionscan_addpattern(char* pattern
, char* data
, unsigned char action
) {
130 vspatterns
=(vspattern
*)malloc(sizeof(vspattern
));
131 strncpy(vspatterns
->pattern
, pattern
, VSPATTERNLEN
);
132 strncpy(vspatterns
->data
, data
, VSDATALEN
);
133 vspatterns
->action
=action
;
135 vspatterns
->hitcount
=0;
139 for (v
=vspatterns
; v
; v
=v
->next
) {
141 v
->next
=(vspattern
*)malloc(sizeof(vspattern
));
142 strncpy(v
->next
->pattern
, pattern
, VSPATTERNLEN
);
143 strncpy(v
->next
->data
, data
, VSDATALEN
);
144 v
->next
->action
=action
;
152 void versionscan_delpattern(char* pattern
) {
156 for (v
=vspatterns
; v
; v
=v
->next
) {
157 if (!ircd_strcmp(v
->pattern
, pattern
)) {
172 vspattern
* versionscan_getpattern(char* pattern
) {
175 for (v
=vspatterns
; v
; v
=v
->next
) {
176 if (!ircd_strcmp(v
->pattern
, pattern
)) {
183 int versionscan_whois(void* sender
, int cargc
, char** cargv
) {
184 nick
* np
=(nick
*)sender
;
189 sendnoticetouser(versionscan_nick
, np
, "Syntax: whois <nickname>");
192 if (!(target
=getnickbynick(cargv
[0]))) {
193 sendnoticetouser(versionscan_nick
, np
, "No such nick.");
196 if (!IsAccount(target
)) {
197 sendnoticetouser(versionscan_nick
, np
, "%s is not authed with the network.", target
->nick
);
200 if (!(v
=versionscan_getauthbyauth(target
->authname
))) {
201 sendnoticetouser(versionscan_nick
, np
, "User %s is not in my database.", target
->nick
);
204 sendnoticetouser(versionscan_nick
, np
, "%s is authed as %s, with flags: %s", target
->nick
, target
->authname
, versionscan_flagstochar(v
->flags
));
208 int versionscan_showcommands(void* sender
, int cargc
, char** cargv
) {
209 nick
* np
=(nick
*)sender
;
210 Command
* cmdlist
[150];
213 sendnoticetouser(versionscan_nick
, np
, "The following commands are registered at present:");
214 j
=getcommandlist(versionscan_commands
, cmdlist
, 150);
215 for (i
=0; i
<j
; i
++) {
216 if (cmdlist
[i
]->level
& (VS_STAFF
| VS_GLINE
| VS_ADMIN
)) {
217 sendnoticetouser(versionscan_nick
, np
, "%s (%s)", cmdlist
[i
]->command
->content
, versionscan_flagstochar(cmdlist
[i
]->level
));
220 sendnoticetouser(versionscan_nick
, np
, "%s", cmdlist
[i
]->command
->content
);
223 sendnoticetouser(versionscan_nick
, np
, "End of list.");
228 int versionscan_help(void* sender
, int cargc
, char** cargv
) {
229 nick
* np
=(nick
*)sender
;
232 sendnoticetouser(versionscan_nick
, np
, "Syntax: help <command>");
236 if (!strcasecmp(cargv
[0], "help")) {
237 sendnoticetouser(versionscan_nick
, np
, "Syntax: help <command>");
238 sendnoticetouser(versionscan_nick
, np
, "Gives help on commands.");
241 if (!strcasecmp(cargv
[0], "hello")) {
242 sendnoticetouser(versionscan_nick
, np
, "Syntax: hello");
243 sendnoticetouser(versionscan_nick
, np
, "Creates the first account on the bot.");
246 if (!strcasecmp(cargv
[0], "scan")) {
247 sendnoticetouser(versionscan_nick
, np
, "Syntax: scan <target>");
248 sendnoticetouser(versionscan_nick
, np
, "Sends a version request to the specified target, which may be a nick or a channel.");
251 if (!strcasecmp(cargv
[0], "broadcast")) {
252 sendnoticetouser(versionscan_nick
, np
, "Syntax: broadcast [-f]");
253 sendnoticetouser(versionscan_nick
, np
, "Send a network-wide CTCP version.");
256 if (!strcasecmp(cargv
[0], "changelev")) {
257 sendnoticetouser(versionscan_nick
, np
, "Syntax: changelev <nick> <level>");
258 sendnoticetouser(versionscan_nick
, np
, "Changes a user's privileges.");
259 sendnoticetouser(versionscan_nick
, np
, "+a -> admin access");
260 sendnoticetouser(versionscan_nick
, np
, "+g -> g-line access");
261 sendnoticetouser(versionscan_nick
, np
, "+s -> staff access");
264 if (!strcasecmp(cargv
[0], "mode")) {
265 sendnoticetouser(versionscan_nick
, np
, "Syntax: mode [<mode of operation>]");
266 sendnoticetouser(versionscan_nick
, np
, "Where <mode of operation> is one of:");
267 sendnoticetouser(versionscan_nick
, np
, "idle: do nothing");
268 sendnoticetouser(versionscan_nick
, np
, "scan: scan newly connecting users and those targeted by the 'scan' command");
269 sendnoticetouser(versionscan_nick
, np
, "stat: collect statistics after a network-wide CTCP version request");
272 if (!strcasecmp(cargv
[0], "showcommands")) {
273 sendnoticetouser(versionscan_nick
, np
, "Syntax: showcommands");
274 sendnoticetouser(versionscan_nick
, np
, "Displays registered commands.");
277 if (!strcasecmp(cargv
[0], "whois")) {
278 sendnoticetouser(versionscan_nick
, np
, "Syntax: whois <nickname>");
279 sendnoticetouser(versionscan_nick
, np
, "Display information about the specified user.");
282 if (!strcasecmp(cargv
[0], "statistics")) {
283 sendnoticetouser(versionscan_nick
, np
, "Syntax: statistics [<limit>]");
284 sendnoticetouser(versionscan_nick
, np
, "Display statistics of collected CTCP version replies.");
287 if (!strcasecmp(cargv
[0], "listpatterns")) {
288 sendnoticetouser(versionscan_nick
, np
, "Syntax: listpatterns");
289 sendnoticetouser(versionscan_nick
, np
, "Lists CTCP version reply patterns.");
292 if (!strcasecmp(cargv
[0], "addpattern")) {
293 sendnoticetouser(versionscan_nick
, np
, "Syntax: addpattern <pattern> <action> <data>");
294 sendnoticetouser(versionscan_nick
, np
, "Adds a CTCP version reply pattern, where action is one of the following:");
295 sendnoticetouser(versionscan_nick
, np
, "%d - warn", VS_WARN
);
296 sendnoticetouser(versionscan_nick
, np
, "%d - kill", VS_KILL
);
297 sendnoticetouser(versionscan_nick
, np
, "%d - g-line user@host", VS_GLUSER
);
298 sendnoticetouser(versionscan_nick
, np
, "%d - g-line *@host", VS_GLHOST
);
301 if (!strcasecmp(cargv
[0], "delpattern")) {
302 sendnoticetouser(versionscan_nick
, np
, "Syntax: delpattern <pattern>");
303 sendnoticetouser(versionscan_nick
, np
, "Deletes a CTCP version reply pattern.");
306 if (!strcasecmp(cargv
[0], "status")) {
307 sendnoticetouser(versionscan_nick
, np
, "Syntax: status");
308 sendnoticetouser(versionscan_nick
, np
, "Gives various bits of information about the bot.");
315 int versionscan_listpatterns(void* sender
, int cargc
, char** cargv
) {
316 nick
* np
=(nick
*)sender
;
319 for (v
=vspatterns
; v
; v
=v
->next
) {
320 sendnoticetouser(versionscan_nick
, np
, "Pattern [%s]:", v
->pattern
);
321 sendnoticetouser(versionscan_nick
, np
, "Data: %s", v
->data
);
322 sendnoticetouser(versionscan_nick
, np
, "Action: %s", (v
->action
== VS_WARN
)?"warn":(v
->action
== VS_KILL
)?"kill":(v
->action
== VS_GLUSER
)?"g-line user@host":"g-line *@host");
323 sendnoticetouser(versionscan_nick
, np
, "Hit count: %lu", v
->hitcount
);
325 sendnoticetouser(versionscan_nick
, np
, "End of list.");
329 int versionscan_addpatterncmd(void* sender
, int cargc
, char** cargv
) {
330 nick
* np
=(nick
*)sender
;
334 sendnoticetouser(versionscan_nick
, np
, "Syntax: addpattern <pattern> <action> <data>");
338 action
=atoi(cargv
[1]);
339 if ((action
< VS_WARN
) || (action
> VS_GLHOST
)) {
340 sendnoticetouser(versionscan_nick
, np
, "Action must be a number between 1 and 4.");
344 if (versionscan_getpattern(cargv
[0])) {
345 sendnoticetouser(versionscan_nick
, np
, "That pattern already exists.");
349 if ((action
> VS_KILL
) && !IsVersionscanGlineAccess(np
)) {
350 sendnoticetouser(versionscan_nick
, np
, "You are not allowed to add G-Lines.");
354 versionscan_addpattern(cargv
[0], cargv
[2], (unsigned char)action
);
355 sendnoticetouser(versionscan_nick
, np
, "Done.");
359 int versionscan_delpatterncmd(void* sender
, int cargc
, char** cargv
) {
360 nick
* np
=(nick
*)sender
;
363 sendnoticetouser(versionscan_nick
, np
, "Syntax: delpattern <pattern>");
367 if (!versionscan_getpattern(cargv
[0])) {
368 sendnoticetouser(versionscan_nick
, np
, "That pattern does not exist.");
372 versionscan_delpattern(cargv
[0]);
373 sendnoticetouser(versionscan_nick
, np
, "Done.");
377 int versionscan_status(void* sender
, int cargc
, char** cargv
) {
378 nick
* np
=(nick
*)sender
;
380 int pcount
=0; unsigned long chcount
=0;
382 for (v
=vspatterns
; v
; v
=v
->next
) {
384 chcount
+=v
->hitcount
;
387 sendnoticetouser(versionscan_nick
, np
, "Patterns: %d", pcount
);
388 sendnoticetouser(versionscan_nick
, np
, "Users hit: %lu (%lu from current patterns)", hcount
, chcount
);
389 sendnoticetouser(versionscan_nick
, np
, "Warnings given: %lu", wcount
);
390 sendnoticetouser(versionscan_nick
, np
, "Kills sent: %lu", kcount
);
391 sendnoticetouser(versionscan_nick
, np
, "G-Lines set: %lu", gcount
);
395 int versionscan_hello(void* sender
, int cargc
, char** cargv
) {
396 nick
* np
=(nick
*)sender
;
399 sendnoticetouser(versionscan_nick
, np
, "The hello command cannot be used after the first user account has been created.");
403 vsauths
=(vsauthdata
*)malloc(sizeof(vsauthdata
));
404 strncpy(vsauths
->account
, np
->authname
, ACCOUNTLEN
);
405 vsauths
->flags
=VS_STAFF
| VS_GLINE
| VS_ADMIN
;
408 sendnoticetouser(versionscan_nick
, np
, "An account has been created for you with the following flags: %s.", versionscan_flagstochar(vsauths
->flags
));
412 int versionscan_changelev(void* sender
, int cargc
, char** cargv
) {
413 nick
* np
=(nick
*)sender
;
416 unsigned char flags
=0;
420 sendnoticetouser(versionscan_nick
, np
, "Syntax: changelev <nick> [+|-]<level>");
424 if (!(target
=getnickbynick(cargv
[0]))) {
425 sendnoticetouser(versionscan_nick
, np
, "No such nick.");
429 if (!IsAccount(target
)) {
430 sendnoticetouser(versionscan_nick
, np
, "%s is not authed.", target
->nick
);
434 if ((v
=versionscan_getauthbyauth(target
->authname
))) {
436 if ((cargv
[1][0] == '+') || (cargv
[1][0] =='-')) {
437 plus
=(cargv
[1][0] == '+')?1:0;
441 for (; cargv
[1][i
]; i
++) {
442 switch (cargv
[1][i
]) {
444 flags
=(plus
)?flags
| VS_ADMIN
:flags
& (~VS_ADMIN
);
447 flags
=(plus
)?flags
| VS_GLINE
:flags
& (~VS_GLINE
);
450 flags
=(plus
)?flags
| VS_STAFF
:flags
& (~VS_STAFF
);
453 sendnoticetouser(versionscan_nick
, np
, "Invalid level '%c'.", cargv
[1][i
]);
459 vsauthdata
* pv
, *prevv
;
462 for (pv
=vsauths
; pv
; pv
++) {
465 prevv
->next
=pv
->next
;
479 sendnoticetouser(versionscan_nick
, np
, "Done.");
484 if ((cargv
[1][0] == '+') || (cargv
[1][0] =='-')) {
485 plus
=(cargv
[1][0] == '+')?1:0;
488 for (; cargv
[1][i
]; i
++) {
489 switch (cargv
[1][i
]) {
491 flags
=(plus
)?flags
| VS_ADMIN
:flags
& (~VS_ADMIN
);
494 flags
=(plus
)?flags
| VS_GLINE
:flags
& (~VS_GLINE
);
497 flags
=(plus
)?flags
| VS_STAFF
:flags
& (~VS_STAFF
);
500 sendnoticetouser(versionscan_nick
, np
, "Invalid level '%c'.", cargv
[1][i
]);
506 for (v
=vsauths
; v
; v
=v
->next
) {
508 v
->next
=(vsauthdata
*)malloc(sizeof(vsauthdata
));
509 strncpy(v
->next
->account
, target
->authname
, ACCOUNTLEN
);
510 v
->next
->flags
=flags
;
512 sendnoticetouser(versionscan_nick
, np
, "Done.");
516 sendnoticetouser(versionscan_nick
, np
, "Error adding user to database.");
519 sendnoticetouser(versionscan_nick
, np
, "No level specified.");
526 int versionscan_scan(void* sender
, int cargc
, char** cargv
) {
527 nick
* np
=(nick
*)sender
;
532 sendnoticetouser(versionscan_nick
, np
, "Syntax: scan <target>");
536 if (versionscan_mode
!= VS_SCAN
) {
537 sendnoticetouser(versionscan_nick
, np
, "Scanning of users is currently disabled.");
541 if (cargv
[0][0] == '#') {
542 if ((cp
=findchannel(cargv
[0]))) {
543 sendmessagetochannel(versionscan_nick
, cp
, "\001VERSION\001");
544 sendnoticetouser(versionscan_nick
, np
, "Done.");
547 sendnoticetouser(versionscan_nick
, np
, "No such channel.");
552 if ((n
=getnickbynick(cargv
[0]))) {
554 sendnoticetouser(versionscan_nick
, np
, "Cannot scan IRC Operators.");
557 sendmessagetouser(versionscan_nick
, n
, "\001VERSION\001");
558 sendnoticetouser(versionscan_nick
, np
, "Done.");
561 sendnoticetouser(versionscan_nick
, np
, "No such nick.");
568 int versionscan_modecmd(void* sender
, int cargc
, char** cargv
) {
569 nick
* np
=(nick
*)sender
;
570 int oldmode
=versionscan_mode
;
573 sendnoticetouser(versionscan_nick
, np
, "Currently running in %s mode.", (versionscan_mode
== VS_SCAN
)?"SCAN":(versionscan_mode
== VS_STAT
)?"STATISTICS":"IDLE");
577 if (!ircd_strcmp(cargv
[0], "idle")) {
578 versionscan_mode
=VS_IDLE
;
579 sendnoticetouser(versionscan_nick
, np
, "Now operating in IDLE mode.");
581 else if (!ircd_strcmp(cargv
[0], "scan")) {
582 versionscan_mode
=VS_SCAN
;
583 sendnoticetouser(versionscan_nick
, np
, "Now operating in SCAN mode.");
585 else if (!ircd_strcmp(cargv
[0], "stat")) {
586 versionscan_mode
=VS_STAT
;
587 sendnoticetouser(versionscan_nick
, np
, "Now operating in STATISTICS mode.");
590 sendnoticetouser(versionscan_nick
, np
, "Invalid mode of operation.");
594 if (oldmode
== VS_STAT
) {
597 for (v
=vsstats
; v
;) {
609 int versionscan_statistics(void* sender
, int cargc
, char** cargv
) {
610 nick
* np
=(nick
*)sender
;
612 long rlimit
=0, limit
=100;
614 if (versionscan_mode
!= VS_STAT
) {
615 sendnoticetouser(versionscan_nick
, np
, "No statistics are available unless STATISTICS mode of operation is enabled.");
619 limit
=atoi(cargv
[0]);
621 if ((limit
< 1) || (limit
> 500)) {
622 sendnoticetouser(versionscan_nick
, np
, "Invalid results limit. Valid values are 1-500.");
625 sendnoticetouser(versionscan_nick
, np
, "Reply: [Count]:");
626 for (v
=vsstats
; (v
&& (rlimit
< limit
)); v
=v
->next
) {
627 sendnoticetouser(versionscan_nick
, np
, "%s [%lu]", v
->reply
, v
->count
);
630 sendnoticetouser(versionscan_nick
, np
, "End of list - %lu results returned.", rlimit
);
634 int versionscan_statsdump(void* sender
, int cargc
, char** cargv
) {
635 nick
* np
=(nick
*)sender
;
640 if (versionscan_mode
!= VS_STAT
) {
641 sendnoticetouser(versionscan_nick
, np
, "No statistics are available unless STATISTICS mode of operation is enabled.");
644 if (!(fout
=fopen("data/versionscanstats","w"))) {
645 sendnoticetouser(versionscan_nick
, np
, "Unable to open save file.");
648 for (v
=vsstats
; v
; v
=v
->next
) {
649 fprintf(fout
, "%lu:%s\n", v
->count
, v
->reply
);
653 sendnoticetouser(versionscan_nick
, np
, "%lu results saved.", rlimit
);
657 int versionscan_broadcast(void* sender
, int cargc
, char** cargv
) {
658 nick
* np
=(nick
*)sender
;
662 if (strcmp(cargv
[0], "-f")) {
663 sendnoticetouser(versionscan_nick
, np
, "Invalid flag.");
669 if (versionscan_mode
!= VS_STAT
) {
671 sendnoticetouser(versionscan_nick
, np
, "Statistics collection mode is not currently enabled. Use the 'mode' command to change current mode of operation.");
672 sendnoticetouser(versionscan_nick
, np
, "If you really wish to send a network-wide CTCP version whilst running in SCAN or IDLE mode, use the -f flag.");
675 sendnoticetouser(versionscan_nick
, np
, "Forcing network-wide CTCP version.");
678 irc_send("%s P $* :\001VERSION\001\r\n", longtonumeric(versionscan_nick
->numeric
, 5));
679 sendnoticetouser(versionscan_nick
, np
, "Done.");
684 void versionscan_newnick(int hooknum
, void* arg
) {
687 /* ignore opers or auth'd users, helps cut down on spam during a burst */
688 if (!(IsOper(np
) || IsAccount(np
)) && (versionscan_mode
== VS_SCAN
)) {
689 sendmessagetouser(versionscan_nick
, np
, "\001VERSION\001");
693 void versionscan_handler(nick
* me
, int type
, void** args
) {
707 if (!strncmp("\001VERSION", args
[1], 8)) {
708 sendnoticetouser(versionscan_nick
, sender
, "\001VERSION QuakeNet %s v%s.\001", VS_RNDESC
, VS_VERSION
);
712 cargc
=splitline((char*)args
[1], cargv
, 50, 0);
714 cmd
=findcommandintree(versionscan_commands
, cargv
[0], 1);
716 sendnoticetouser(versionscan_nick
, sender
, "Unknown command.");
720 if ((cmd
->level
& VS_AUTHED
) && !IsAccount(sender
)) {
721 sendnoticetouser(versionscan_nick
, sender
, "Sorry, you need to be authed to use this command.");
725 if ((cmd
->level
& VS_OPER
) && !IsOper(sender
)) {
726 sendnoticetouser(versionscan_nick
, sender
, "Sorry, you need to be opered to use this command.");
730 if (((cmd
->level
& VS_STAFF
) && !IsVersionscanStaff(sender
)) ||
731 ((cmd
->level
& VS_GLINE
) && !IsVersionscanGlineAccess(sender
)) ||
732 ((cmd
->level
& VS_ADMIN
) && !IsVersionscanAdmin(sender
))) {
733 sendnoticetouser(versionscan_nick
, sender
, "Sorry, you do not have access to this command.");
737 if (cmd
->maxparams
< (cargc
-1)) {
738 /* We need to do some rejoining */
739 rejoinline(cargv
[cmd
->maxparams
], cargc
-(cmd
->maxparams
));
740 cargc
=(cmd
->maxparams
)+1;
743 (cmd
->handler
)((void*)sender
, cargc
-1, &(cargv
[1]));
748 if (strncmp("\001VERSION ", args
[1], 9)) {
751 if ((p
=strchr((char *)args
[1] + 9, '\001'))) {
754 if (versionscan_mode
== VS_SCAN
) {
755 if (IsOper(sender
)) {
758 for (v
=vspatterns
; v
; v
=v
->next
) {
759 if (match2strings(v
->pattern
, (char *)args
[1] + 9)) {
764 sendnoticetouser(versionscan_nick
, sender
, v
->data
);
768 killuser(versionscan_nick
, sender
, v
->data
);
772 irc_send("%s GL * +*!%s@%s 3600 :%s\r\n", mynumeric
->content
, sender
->ident
, sender
->host
->name
->content
, v
->data
);
776 irc_send("%s GL * +*!*@%s 3600 :%s\r\n", mynumeric
->content
, sender
->host
->name
->content
, v
->data
);
780 /* oh dear, something's fucked */
787 else if (versionscan_mode
== VS_STAT
) {
788 versionscan_addstat((char *)args
[1] + 9);
792 versionscan_nick
=NULL
;
793 scheduleoneshot(time(NULL
)+1, &versionscan_createfakeuser
, NULL
);
798 void versionscan_createfakeuser(void* arg
) {
803 sprintf(buf
, "%s v%s", VS_RNDESC
, VS_VERSION
);
804 versionscan_nick
=registerlocaluser(VS_NICK
, VS_IDENT
, VS_HOST
, buf
, VS_AUTHNAME
, UMODE_ACCOUNT
| UMODE_DEAF
| UMODE_OPER
| UMODE_SERVICE
, versionscan_handler
);
805 if ((cp
=findchannel(OPER_CHAN
))) {
806 localjoinchannel(versionscan_nick
, cp
);
807 localgetops(versionscan_nick
, cp
);
809 localcreatechannel(versionscan_nick
, OPER_CHAN
);
817 versionscan_mode
=VS_IDLE
;
819 versionscan_commands
=newcommandtree();
821 addcommandtotree(versionscan_commands
, "showcommands", VS_AUTHED
| VS_STAFF
, 0, versionscan_showcommands
);
822 addcommandtotree(versionscan_commands
, "help", VS_AUTHED
| VS_STAFF
, 1, versionscan_help
);
823 addcommandtotree(versionscan_commands
, "hello", VS_AUTHED
| VS_OPER
, 0, versionscan_hello
);
824 addcommandtotree(versionscan_commands
, "scan", VS_AUTHED
| VS_STAFF
, 1, versionscan_scan
);
825 addcommandtotree(versionscan_commands
, "changelev", VS_AUTHED
| VS_OPER
| VS_ADMIN
, 2, versionscan_changelev
);
826 addcommandtotree(versionscan_commands
, "listpatterns", VS_AUTHED
| VS_STAFF
| VS_OPER
, 0, versionscan_listpatterns
);
827 addcommandtotree(versionscan_commands
, "addpattern", VS_AUTHED
| VS_STAFF
| VS_OPER
, 3, versionscan_addpatterncmd
);
828 addcommandtotree(versionscan_commands
, "delpattern", VS_AUTHED
| VS_OPER
| VS_ADMIN
, 1, versionscan_delpatterncmd
);
829 addcommandtotree(versionscan_commands
, "status", VS_AUTHED
| VS_OPER
| VS_ADMIN
, 0, versionscan_status
);
830 addcommandtotree(versionscan_commands
, "mode", VS_AUTHED
| VS_OPER
| VS_ADMIN
, 1, versionscan_modecmd
);
831 addcommandtotree(versionscan_commands
, "statistics", VS_AUTHED
| VS_OPER
| VS_STAFF
, 1, versionscan_statistics
);
832 addcommandtotree(versionscan_commands
, "statsdump", VS_AUTHED
| VS_OPER
| VS_STAFF
, 1, versionscan_statsdump
);
833 addcommandtotree(versionscan_commands
, "broadcast", VS_AUTHED
| VS_OPER
| VS_ADMIN
, 1, versionscan_broadcast
);
834 addcommandtotree(versionscan_commands
, "whois", VS_AUTHED
| VS_STAFF
, 1, versionscan_whois
);
836 registerhook(HOOK_NICK_NEWNICK
, &versionscan_newnick
);
838 vsconnect
=scheduleoneshot(time(NULL
)+1, &versionscan_createfakeuser
, NULL
);
844 deregisterhook(HOOK_NICK_NEWNICK
, &versionscan_newnick
);
847 deleteschedule(vsconnect
, &versionscan_createfakeuser
, NULL
);
851 if (versionscan_nick
) {
852 deregisterlocaluser(versionscan_nick
, "Module unloaded.");
853 versionscan_nick
=NULL
;
856 destroycommandtree(versionscan_commands
);
858 for (p
=vspatterns
; p
;) {
859 np
=((vspattern
*)p
)->next
;
863 for (p
=vsauths
; p
;) {
864 np
=((vsauthdata
*)p
)->next
;
868 for (p
=vsstats
; p
;) {
869 np
=((vsstatistic
*)p
)->next
;
870 free(((vsstatistic
*)p
)->reply
);