1 #include "versionscan.h"
2 #include "../lib/version.h"
3 #include "../glines/glines.h"
7 CommandTree
* versionscan_commands
;
8 nick
* versionscan_nick
;
11 vspattern
* vspatterns
;
14 unsigned long hcount
=0;
15 unsigned long wcount
=0;
16 unsigned long kcount
=0;
17 unsigned long gcount
=0;
20 void versionscan_addstat(char* reply
) {
21 unsigned int replylen
;
22 unsigned long replycrc
;
25 replylen
= strlen(reply
);
26 replycrc
= crc32i(reply
);
29 for (v
=vsstats
; v
; v
=v
->next
) {
30 if (v
->replylen
==replylen
&& v
->replycrc
==replycrc
) {
37 vsstats
=(vsstatistic
*)malloc(sizeof(vsstatistic
));
38 vsstats
->reply
=(char*)malloc(replylen
+ 1);
39 strcpy(vsstats
->reply
, reply
);
40 vsstats
->replylen
= replylen
;
41 vsstats
->replycrc
= replycrc
;
46 pv
->next
=(vsstatistic
*)malloc(sizeof(vsstatistic
));
47 pv
->next
->reply
=(char*)malloc(replylen
+ 1);
48 strcpy(pv
->next
->reply
, reply
);
49 pv
->next
->replylen
= replylen
;
50 pv
->next
->replycrc
= replycrc
;
56 unsigned char versionscan_getlevelbyauth(char* auth
) {
59 for (v
=vsauths
; v
; v
=v
->next
) {
60 if (!ircd_strcmp(v
->account
, auth
)) {
67 vsauthdata
* versionscan_getauthbyauth(char* auth
) {
70 for (v
=vsauths
; v
; v
=v
->next
) {
71 if (!ircd_strcmp(v
->account
, auth
)) {
78 int IsVersionscanStaff(nick
* np
) {
84 level
=versionscan_getlevelbyauth(np
->authname
);
85 if (level
& (VS_STAFF
| VS_GLINE
| VS_ADMIN
)) {
91 int IsVersionscanGlineAccess(nick
* np
) {
97 level
=versionscan_getlevelbyauth(np
->authname
);
98 if (level
& (VS_GLINE
| VS_ADMIN
)) {
104 int IsVersionscanAdmin(nick
* np
) {
107 if (!IsAccount(np
)) {
110 level
=versionscan_getlevelbyauth(np
->authname
);
111 if (level
& VS_ADMIN
) {
117 const char* versionscan_flagstochar(unsigned char flags
) {
118 static char outstring
[50];
121 outstring
[pos
++]='+';
122 if (flags
& VS_ADMIN
) { outstring
[pos
++]='a'; }
123 if (flags
& VS_GLINE
) { outstring
[pos
++]='g'; }
124 if (flags
& VS_STAFF
) { outstring
[pos
++]='s'; }
130 void versionscan_addpattern(char* pattern
, char* data
, unsigned char action
) {
134 vspatterns
=(vspattern
*)malloc(sizeof(vspattern
));
135 strncpy(vspatterns
->pattern
, pattern
, VSPATTERNLEN
);
136 strncpy(vspatterns
->data
, data
, VSDATALEN
);
137 vspatterns
->action
=action
;
139 vspatterns
->hitcount
=0;
143 for (v
=vspatterns
; v
; v
=v
->next
) {
145 v
->next
=(vspattern
*)malloc(sizeof(vspattern
));
146 strncpy(v
->next
->pattern
, pattern
, VSPATTERNLEN
);
147 strncpy(v
->next
->data
, data
, VSDATALEN
);
148 v
->next
->action
=action
;
156 void versionscan_delpattern(char* pattern
) {
160 for (v
=vspatterns
; v
; v
=v
->next
) {
161 if (!ircd_strcmp(v
->pattern
, pattern
)) {
176 vspattern
* versionscan_getpattern(char* pattern
) {
179 for (v
=vspatterns
; v
; v
=v
->next
) {
180 if (!ircd_strcmp(v
->pattern
, pattern
)) {
187 int versionscan_whois(void* sender
, int cargc
, char** cargv
) {
188 nick
* np
=(nick
*)sender
;
193 sendnoticetouser(versionscan_nick
, np
, "Syntax: whois <nickname>");
196 if (!(target
=getnickbynick(cargv
[0]))) {
197 sendnoticetouser(versionscan_nick
, np
, "No such nick.");
200 if (!IsAccount(target
)) {
201 sendnoticetouser(versionscan_nick
, np
, "%s is not authed with the network.", target
->nick
);
204 if (!(v
=versionscan_getauthbyauth(target
->authname
))) {
205 sendnoticetouser(versionscan_nick
, np
, "User %s is not in my database.", target
->nick
);
208 sendnoticetouser(versionscan_nick
, np
, "%s is authed as %s, with flags: %s", target
->nick
, target
->authname
, versionscan_flagstochar(v
->flags
));
212 int versionscan_showcommands(void* sender
, int cargc
, char** cargv
) {
213 nick
* np
=(nick
*)sender
;
214 Command
* cmdlist
[150];
217 sendnoticetouser(versionscan_nick
, np
, "The following commands are registered at present:");
218 j
=getcommandlist(versionscan_commands
, cmdlist
, 150);
219 for (i
=0; i
<j
; i
++) {
220 if (cmdlist
[i
]->level
& (VS_STAFF
| VS_GLINE
| VS_ADMIN
)) {
221 sendnoticetouser(versionscan_nick
, np
, "%s (%s)", cmdlist
[i
]->command
->content
, versionscan_flagstochar(cmdlist
[i
]->level
));
224 sendnoticetouser(versionscan_nick
, np
, "%s", cmdlist
[i
]->command
->content
);
227 sendnoticetouser(versionscan_nick
, np
, "End of list.");
232 int versionscan_help(void* sender
, int cargc
, char** cargv
) {
233 nick
* np
=(nick
*)sender
;
236 sendnoticetouser(versionscan_nick
, np
, "Syntax: help <command>");
240 if (!strcasecmp(cargv
[0], "help")) {
241 sendnoticetouser(versionscan_nick
, np
, "Syntax: help <command>");
242 sendnoticetouser(versionscan_nick
, np
, "Gives help on commands.");
245 if (!strcasecmp(cargv
[0], "hello")) {
246 sendnoticetouser(versionscan_nick
, np
, "Syntax: hello");
247 sendnoticetouser(versionscan_nick
, np
, "Creates the first account on the bot.");
250 if (!strcasecmp(cargv
[0], "scan")) {
251 sendnoticetouser(versionscan_nick
, np
, "Syntax: scan <target>");
252 sendnoticetouser(versionscan_nick
, np
, "Sends a version request to the specified target, which may be a nick or a channel.");
255 if (!strcasecmp(cargv
[0], "broadcast")) {
256 sendnoticetouser(versionscan_nick
, np
, "Syntax: broadcast [-f]");
257 sendnoticetouser(versionscan_nick
, np
, "Send a network-wide CTCP version.");
260 if (!strcasecmp(cargv
[0], "changelev")) {
261 sendnoticetouser(versionscan_nick
, np
, "Syntax: changelev <nick> <level>");
262 sendnoticetouser(versionscan_nick
, np
, "Changes a user's privileges.");
263 sendnoticetouser(versionscan_nick
, np
, "+a -> admin access");
264 sendnoticetouser(versionscan_nick
, np
, "+g -> g-line access");
265 sendnoticetouser(versionscan_nick
, np
, "+s -> staff access");
268 if (!strcasecmp(cargv
[0], "mode")) {
269 sendnoticetouser(versionscan_nick
, np
, "Syntax: mode [<mode of operation>]");
270 sendnoticetouser(versionscan_nick
, np
, "Where <mode of operation> is one of:");
271 sendnoticetouser(versionscan_nick
, np
, "idle: do nothing");
272 sendnoticetouser(versionscan_nick
, np
, "scan: scan newly connecting users and those targeted by the 'scan' command");
273 sendnoticetouser(versionscan_nick
, np
, "stat: collect statistics after a network-wide CTCP version request");
276 if (!strcasecmp(cargv
[0], "showcommands")) {
277 sendnoticetouser(versionscan_nick
, np
, "Syntax: showcommands");
278 sendnoticetouser(versionscan_nick
, np
, "Displays registered commands.");
281 if (!strcasecmp(cargv
[0], "whois")) {
282 sendnoticetouser(versionscan_nick
, np
, "Syntax: whois <nickname>");
283 sendnoticetouser(versionscan_nick
, np
, "Display information about the specified user.");
286 if (!strcasecmp(cargv
[0], "statistics")) {
287 sendnoticetouser(versionscan_nick
, np
, "Syntax: statistics [<limit>]");
288 sendnoticetouser(versionscan_nick
, np
, "Display statistics of collected CTCP version replies.");
291 if (!strcasecmp(cargv
[0], "listpatterns")) {
292 sendnoticetouser(versionscan_nick
, np
, "Syntax: listpatterns");
293 sendnoticetouser(versionscan_nick
, np
, "Lists CTCP version reply patterns.");
296 if (!strcasecmp(cargv
[0], "addpattern")) {
297 sendnoticetouser(versionscan_nick
, np
, "Syntax: addpattern <pattern> <action> <data>");
298 sendnoticetouser(versionscan_nick
, np
, "Adds a CTCP version reply pattern, where action is one of the following:");
299 sendnoticetouser(versionscan_nick
, np
, "%d - warn", VS_WARN
);
300 sendnoticetouser(versionscan_nick
, np
, "%d - kill", VS_KILL
);
301 sendnoticetouser(versionscan_nick
, np
, "%d - g-line user@host", VS_GLUSER
);
302 sendnoticetouser(versionscan_nick
, np
, "%d - g-line *@host", VS_GLHOST
);
305 if (!strcasecmp(cargv
[0], "delpattern")) {
306 sendnoticetouser(versionscan_nick
, np
, "Syntax: delpattern <pattern>");
307 sendnoticetouser(versionscan_nick
, np
, "Deletes a CTCP version reply pattern.");
310 if (!strcasecmp(cargv
[0], "status")) {
311 sendnoticetouser(versionscan_nick
, np
, "Syntax: status");
312 sendnoticetouser(versionscan_nick
, np
, "Gives various bits of information about the bot.");
319 int versionscan_listpatterns(void* sender
, int cargc
, char** cargv
) {
320 nick
* np
=(nick
*)sender
;
323 for (v
=vspatterns
; v
; v
=v
->next
) {
324 sendnoticetouser(versionscan_nick
, np
, "Pattern [%s]:", v
->pattern
);
325 sendnoticetouser(versionscan_nick
, np
, "Data: %s", v
->data
);
326 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");
327 sendnoticetouser(versionscan_nick
, np
, "Hit count: %lu", v
->hitcount
);
329 sendnoticetouser(versionscan_nick
, np
, "End of list.");
333 int versionscan_addpatterncmd(void* sender
, int cargc
, char** cargv
) {
334 nick
* np
=(nick
*)sender
;
338 sendnoticetouser(versionscan_nick
, np
, "Syntax: addpattern <pattern> <action> <data>");
342 action
=atoi(cargv
[1]);
343 if ((action
< VS_WARN
) || (action
> VS_GLHOST
)) {
344 sendnoticetouser(versionscan_nick
, np
, "Action must be a number between 1 and 4.");
348 if (versionscan_getpattern(cargv
[0])) {
349 sendnoticetouser(versionscan_nick
, np
, "That pattern already exists.");
353 if ((action
> VS_KILL
) && !IsVersionscanGlineAccess(np
)) {
354 sendnoticetouser(versionscan_nick
, np
, "You are not allowed to add G-Lines.");
358 versionscan_addpattern(cargv
[0], cargv
[2], (unsigned char)action
);
359 sendnoticetouser(versionscan_nick
, np
, "Done.");
363 int versionscan_delpatterncmd(void* sender
, int cargc
, char** cargv
) {
364 nick
* np
=(nick
*)sender
;
367 sendnoticetouser(versionscan_nick
, np
, "Syntax: delpattern <pattern>");
371 if (!versionscan_getpattern(cargv
[0])) {
372 sendnoticetouser(versionscan_nick
, np
, "That pattern does not exist.");
376 versionscan_delpattern(cargv
[0]);
377 sendnoticetouser(versionscan_nick
, np
, "Done.");
381 int versionscan_status(void* sender
, int cargc
, char** cargv
) {
382 nick
* np
=(nick
*)sender
;
384 int pcount
=0; unsigned long chcount
=0;
386 for (v
=vspatterns
; v
; v
=v
->next
) {
388 chcount
+=v
->hitcount
;
391 sendnoticetouser(versionscan_nick
, np
, "Patterns: %d", pcount
);
392 sendnoticetouser(versionscan_nick
, np
, "Users hit: %lu (%lu from current patterns)", hcount
, chcount
);
393 sendnoticetouser(versionscan_nick
, np
, "Warnings given: %lu", wcount
);
394 sendnoticetouser(versionscan_nick
, np
, "Kills sent: %lu", kcount
);
395 sendnoticetouser(versionscan_nick
, np
, "G-Lines set: %lu", gcount
);
399 int versionscan_hello(void* sender
, int cargc
, char** cargv
) {
400 nick
* np
=(nick
*)sender
;
403 sendnoticetouser(versionscan_nick
, np
, "The hello command cannot be used after the first user account has been created.");
407 vsauths
=(vsauthdata
*)malloc(sizeof(vsauthdata
));
408 strncpy(vsauths
->account
, np
->authname
, ACCOUNTLEN
);
409 vsauths
->flags
=VS_STAFF
| VS_GLINE
| VS_ADMIN
;
412 sendnoticetouser(versionscan_nick
, np
, "An account has been created for you with the following flags: %s.", versionscan_flagstochar(vsauths
->flags
));
416 int versionscan_changelev(void* sender
, int cargc
, char** cargv
) {
417 nick
* np
=(nick
*)sender
;
420 unsigned char flags
=0;
424 sendnoticetouser(versionscan_nick
, np
, "Syntax: changelev <nick> [+|-]<level>");
428 if (!(target
=getnickbynick(cargv
[0]))) {
429 sendnoticetouser(versionscan_nick
, np
, "No such nick.");
433 if (!IsAccount(target
)) {
434 sendnoticetouser(versionscan_nick
, np
, "%s is not authed.", target
->nick
);
438 if ((v
=versionscan_getauthbyauth(target
->authname
))) {
440 if ((cargv
[1][0] == '+') || (cargv
[1][0] =='-')) {
441 plus
=(cargv
[1][0] == '+')?1:0;
445 for (; cargv
[1][i
]; i
++) {
446 switch (cargv
[1][i
]) {
448 flags
=(plus
)?flags
| VS_ADMIN
:flags
& (~VS_ADMIN
);
451 flags
=(plus
)?flags
| VS_GLINE
:flags
& (~VS_GLINE
);
454 flags
=(plus
)?flags
| VS_STAFF
:flags
& (~VS_STAFF
);
457 sendnoticetouser(versionscan_nick
, np
, "Invalid level '%c'.", cargv
[1][i
]);
463 vsauthdata
* pv
, *prevv
;
466 for (pv
=vsauths
; pv
; pv
++) {
469 prevv
->next
=pv
->next
;
483 sendnoticetouser(versionscan_nick
, np
, "Done.");
488 if ((cargv
[1][0] == '+') || (cargv
[1][0] =='-')) {
489 plus
=(cargv
[1][0] == '+')?1:0;
492 for (; cargv
[1][i
]; i
++) {
493 switch (cargv
[1][i
]) {
495 flags
=(plus
)?flags
| VS_ADMIN
:flags
& (~VS_ADMIN
);
498 flags
=(plus
)?flags
| VS_GLINE
:flags
& (~VS_GLINE
);
501 flags
=(plus
)?flags
| VS_STAFF
:flags
& (~VS_STAFF
);
504 sendnoticetouser(versionscan_nick
, np
, "Invalid level '%c'.", cargv
[1][i
]);
510 for (v
=vsauths
; v
; v
=v
->next
) {
512 v
->next
=(vsauthdata
*)malloc(sizeof(vsauthdata
));
513 strncpy(v
->next
->account
, target
->authname
, ACCOUNTLEN
);
514 v
->next
->flags
=flags
;
516 sendnoticetouser(versionscan_nick
, np
, "Done.");
520 sendnoticetouser(versionscan_nick
, np
, "Error adding user to database.");
523 sendnoticetouser(versionscan_nick
, np
, "No level specified.");
530 int versionscan_scan(void* sender
, int cargc
, char** cargv
) {
531 nick
* np
=(nick
*)sender
;
536 sendnoticetouser(versionscan_nick
, np
, "Syntax: scan <target>");
540 if (versionscan_mode
!= VS_SCAN
) {
541 sendnoticetouser(versionscan_nick
, np
, "Scanning of users is currently disabled.");
545 if (cargv
[0][0] == '#') {
546 if ((cp
=findchannel(cargv
[0]))) {
547 sendmessagetochannel(versionscan_nick
, cp
, "\001VERSION\001");
548 sendnoticetouser(versionscan_nick
, np
, "Done.");
551 sendnoticetouser(versionscan_nick
, np
, "No such channel.");
556 if ((n
=getnickbynick(cargv
[0]))) {
558 sendnoticetouser(versionscan_nick
, np
, "Cannot scan IRC Operators.");
561 sendmessagetouser(versionscan_nick
, n
, "\001VERSION\001");
562 sendnoticetouser(versionscan_nick
, np
, "Done.");
565 sendnoticetouser(versionscan_nick
, np
, "No such nick.");
572 int versionscan_modecmd(void* sender
, int cargc
, char** cargv
) {
573 nick
* np
=(nick
*)sender
;
574 int oldmode
=versionscan_mode
;
577 sendnoticetouser(versionscan_nick
, np
, "Currently running in %s mode.", (versionscan_mode
== VS_SCAN
)?"SCAN":(versionscan_mode
== VS_STAT
)?"STATISTICS":"IDLE");
581 if (!ircd_strcmp(cargv
[0], "idle")) {
582 versionscan_mode
=VS_IDLE
;
583 sendnoticetouser(versionscan_nick
, np
, "Now operating in IDLE mode.");
585 else if (!ircd_strcmp(cargv
[0], "scan")) {
586 versionscan_mode
=VS_SCAN
;
587 sendnoticetouser(versionscan_nick
, np
, "Now operating in SCAN mode.");
589 else if (!ircd_strcmp(cargv
[0], "stat")) {
590 versionscan_mode
=VS_STAT
;
591 sendnoticetouser(versionscan_nick
, np
, "Now operating in STATISTICS mode.");
594 sendnoticetouser(versionscan_nick
, np
, "Invalid mode of operation.");
598 if (oldmode
== VS_STAT
) {
601 for (v
=vsstats
; v
;) {
613 int versionscan_statistics(void* sender
, int cargc
, char** cargv
) {
614 nick
* np
=(nick
*)sender
;
616 long rlimit
=0, limit
=100;
618 if (versionscan_mode
!= VS_STAT
) {
619 sendnoticetouser(versionscan_nick
, np
, "No statistics are available unless STATISTICS mode of operation is enabled.");
623 limit
=atoi(cargv
[0]);
625 if ((limit
< 1) || (limit
> 500)) {
626 sendnoticetouser(versionscan_nick
, np
, "Invalid results limit. Valid values are 1-500.");
629 sendnoticetouser(versionscan_nick
, np
, "Reply: [Count]:");
630 for (v
=vsstats
; (v
&& (rlimit
< limit
)); v
=v
->next
) {
631 sendnoticetouser(versionscan_nick
, np
, "%s [%lu]", v
->reply
, v
->count
);
634 sendnoticetouser(versionscan_nick
, np
, "End of list - %lu results returned.", rlimit
);
638 int versionscan_statsdump(void* sender
, int cargc
, char** cargv
) {
639 nick
* np
=(nick
*)sender
;
644 if (versionscan_mode
!= VS_STAT
) {
645 sendnoticetouser(versionscan_nick
, np
, "No statistics are available unless STATISTICS mode of operation is enabled.");
648 if (!(fout
=fopen("data/versionscanstats","w"))) {
649 sendnoticetouser(versionscan_nick
, np
, "Unable to open save file.");
652 for (v
=vsstats
; v
; v
=v
->next
) {
653 fprintf(fout
, "%lu:%s\n", v
->count
, v
->reply
);
657 sendnoticetouser(versionscan_nick
, np
, "%lu results saved.", rlimit
);
661 int versionscan_broadcast(void* sender
, int cargc
, char** cargv
) {
662 nick
* np
=(nick
*)sender
;
666 if (strcmp(cargv
[0], "-f")) {
667 sendnoticetouser(versionscan_nick
, np
, "Invalid flag.");
673 if (versionscan_mode
!= VS_STAT
) {
675 sendnoticetouser(versionscan_nick
, np
, "Statistics collection mode is not currently enabled. Use the 'mode' command to change current mode of operation.");
676 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.");
679 sendnoticetouser(versionscan_nick
, np
, "Forcing network-wide CTCP version.");
682 irc_send("%s P $* :\001VERSION\001\r\n", longtonumeric(versionscan_nick
->numeric
, 5));
683 sendnoticetouser(versionscan_nick
, np
, "Done.");
688 void versionscan_newnick(int hooknum
, void* arg
) {
691 /* ignore opers or auth'd users, helps cut down on spam during a burst */
692 if (!(IsOper(np
) || IsAccount(np
)) && (versionscan_mode
== VS_SCAN
)) {
693 sendmessagetouser(versionscan_nick
, np
, "\001VERSION\001");
697 void versionscan_handler(nick
* me
, int type
, void** args
) {
711 if (!strncmp("\001VERSION", args
[1], 8)) {
712 sendnoticetouser(versionscan_nick
, sender
, "\001VERSION QuakeNet %s v%s.\001", VS_RNDESC
, VS_VERSION
);
716 cargc
=splitline((char*)args
[1], cargv
, 50, 0);
718 cmd
=findcommandintree(versionscan_commands
, cargv
[0], 1);
720 sendnoticetouser(versionscan_nick
, sender
, "Unknown command.");
724 if ((cmd
->level
& VS_AUTHED
) && !IsAccount(sender
)) {
725 sendnoticetouser(versionscan_nick
, sender
, "Sorry, you need to be authed to use this command.");
729 if ((cmd
->level
& VS_OPER
) && !IsOper(sender
)) {
730 sendnoticetouser(versionscan_nick
, sender
, "Sorry, you need to be opered to use this command.");
734 if (((cmd
->level
& VS_STAFF
) && !IsVersionscanStaff(sender
)) ||
735 ((cmd
->level
& VS_GLINE
) && !IsVersionscanGlineAccess(sender
)) ||
736 ((cmd
->level
& VS_ADMIN
) && !IsVersionscanAdmin(sender
))) {
737 sendnoticetouser(versionscan_nick
, sender
, "Sorry, you do not have access to this command.");
741 if (cmd
->maxparams
< (cargc
-1)) {
742 /* We need to do some rejoining */
743 rejoinline(cargv
[cmd
->maxparams
], cargc
-(cmd
->maxparams
));
744 cargc
=(cmd
->maxparams
)+1;
747 (cmd
->handler
)((void*)sender
, cargc
-1, &(cargv
[1]));
752 if (strncmp("\001VERSION ", args
[1], 9)) {
755 if ((p
=strchr((char *)args
[1] + 9, '\001'))) {
758 if (versionscan_mode
== VS_SCAN
) {
759 if (IsOper(sender
)) {
762 for (v
=vspatterns
; v
; v
=v
->next
) {
763 if (match2strings(v
->pattern
, (char *)args
[1] + 9)) {
768 sendnoticetouser(versionscan_nick
, sender
, "%s", v
->data
);
772 killuser(versionscan_nick
, sender
, "%s", v
->data
);
776 glinebynick(sender
, 3600, v
->data
, GLINE_ALWAYS_USER
, "versionscan");
780 glinebynick(sender
, 3600, v
->data
, 0, "versionscan");
784 /* oh dear, something's fucked */
791 else if (versionscan_mode
== VS_STAT
) {
792 versionscan_addstat((char *)args
[1] + 9);
796 versionscan_nick
=NULL
;
797 scheduleoneshot(time(NULL
)+1, &versionscan_createfakeuser
, NULL
);
802 void versionscan_createfakeuser(void* arg
) {
807 sprintf(buf
, "%s v%s", VS_RNDESC
, VS_VERSION
);
808 versionscan_nick
=registerlocaluser(VS_NICK
, VS_IDENT
, VS_HOST
, buf
, VS_AUTHNAME
, UMODE_ACCOUNT
| UMODE_DEAF
| UMODE_OPER
| UMODE_SERVICE
, versionscan_handler
);
809 if ((cp
=findchannel(OPER_CHAN
))) {
810 localjoinchannel(versionscan_nick
, cp
);
811 localgetops(versionscan_nick
, cp
);
813 localcreatechannel(versionscan_nick
, OPER_CHAN
);
821 versionscan_mode
=VS_IDLE
;
823 versionscan_commands
=newcommandtree();
825 addcommandtotree(versionscan_commands
, "showcommands", VS_AUTHED
| VS_STAFF
, 0, versionscan_showcommands
);
826 addcommandtotree(versionscan_commands
, "help", VS_AUTHED
| VS_STAFF
, 1, versionscan_help
);
827 addcommandtotree(versionscan_commands
, "hello", VS_AUTHED
| VS_OPER
, 0, versionscan_hello
);
828 addcommandtotree(versionscan_commands
, "scan", VS_AUTHED
| VS_STAFF
, 1, versionscan_scan
);
829 addcommandtotree(versionscan_commands
, "changelev", VS_AUTHED
| VS_OPER
| VS_ADMIN
, 2, versionscan_changelev
);
830 addcommandtotree(versionscan_commands
, "listpatterns", VS_AUTHED
| VS_STAFF
| VS_OPER
, 0, versionscan_listpatterns
);
831 addcommandtotree(versionscan_commands
, "addpattern", VS_AUTHED
| VS_STAFF
| VS_OPER
, 3, versionscan_addpatterncmd
);
832 addcommandtotree(versionscan_commands
, "delpattern", VS_AUTHED
| VS_OPER
| VS_ADMIN
, 1, versionscan_delpatterncmd
);
833 addcommandtotree(versionscan_commands
, "status", VS_AUTHED
| VS_OPER
| VS_ADMIN
, 0, versionscan_status
);
834 addcommandtotree(versionscan_commands
, "mode", VS_AUTHED
| VS_OPER
| VS_ADMIN
, 1, versionscan_modecmd
);
835 addcommandtotree(versionscan_commands
, "statistics", VS_AUTHED
| VS_OPER
| VS_STAFF
, 1, versionscan_statistics
);
836 addcommandtotree(versionscan_commands
, "statsdump", VS_AUTHED
| VS_OPER
| VS_STAFF
, 1, versionscan_statsdump
);
837 addcommandtotree(versionscan_commands
, "broadcast", VS_AUTHED
| VS_OPER
| VS_ADMIN
, 1, versionscan_broadcast
);
838 addcommandtotree(versionscan_commands
, "whois", VS_AUTHED
| VS_STAFF
, 1, versionscan_whois
);
840 registerhook(HOOK_NICK_NEWNICK
, &versionscan_newnick
);
842 vsconnect
=scheduleoneshot(time(NULL
)+1, &versionscan_createfakeuser
, NULL
);
848 deregisterhook(HOOK_NICK_NEWNICK
, &versionscan_newnick
);
851 deleteschedule(vsconnect
, &versionscan_createfakeuser
, NULL
);
855 if (versionscan_nick
) {
856 deregisterlocaluser(versionscan_nick
, "Module unloaded.");
857 versionscan_nick
=NULL
;
860 destroycommandtree(versionscan_commands
);
862 for (p
=vspatterns
; p
;) {
863 np
=((vspattern
*)p
)->next
;
867 for (p
=vsauths
; p
;) {
868 np
=((vsauthdata
*)p
)->next
;
872 for (p
=vsstats
; p
;) {
873 np
=((vsstatistic
*)p
)->next
;
874 free(((vsstatistic
*)p
)->reply
);