1 #include "versionscan.h"
2 #include "../lib/version.h"
6 CommandTree
* versionscan_commands
;
7 nick
* versionscan_nick
;
10 vspattern
* vspatterns
;
13 unsigned long hcount
=0;
14 unsigned long wcount
=0;
15 unsigned long kcount
=0;
16 unsigned long gcount
=0;
19 void versionscan_addstat(char* reply
) {
20 unsigned int replylen
;
21 unsigned long replycrc
;
24 replylen
= strlen(reply
);
25 replycrc
= crc32i(reply
);
28 for (v
=vsstats
; v
; v
=v
->next
) {
29 if (v
->replylen
==replylen
&& v
->replycrc
==replycrc
) {
36 vsstats
=(vsstatistic
*)malloc(sizeof(vsstatistic
));
37 vsstats
->reply
=(char*)malloc(replylen
+ 1);
38 strcpy(vsstats
->reply
, reply
);
39 vsstats
->replylen
= replylen
;
40 vsstats
->replycrc
= replycrc
;
45 pv
->next
=(vsstatistic
*)malloc(sizeof(vsstatistic
));
46 pv
->next
->reply
=(char*)malloc(replylen
+ 1);
47 strcpy(pv
->next
->reply
, reply
);
48 pv
->next
->replylen
= replylen
;
49 pv
->next
->replycrc
= replycrc
;
55 unsigned char versionscan_getlevelbyauth(char* auth
) {
58 for (v
=vsauths
; v
; v
=v
->next
) {
59 if (!ircd_strcmp(v
->account
, auth
)) {
66 vsauthdata
* versionscan_getauthbyauth(char* auth
) {
69 for (v
=vsauths
; v
; v
=v
->next
) {
70 if (!ircd_strcmp(v
->account
, auth
)) {
77 int IsVersionscanStaff(nick
* np
) {
83 level
=versionscan_getlevelbyauth(np
->authname
);
84 if (level
& (VS_STAFF
| VS_GLINE
| VS_ADMIN
)) {
90 int IsVersionscanGlineAccess(nick
* np
) {
96 level
=versionscan_getlevelbyauth(np
->authname
);
97 if (level
& (VS_GLINE
| VS_ADMIN
)) {
103 int IsVersionscanAdmin(nick
* np
) {
106 if (!IsAccount(np
)) {
109 level
=versionscan_getlevelbyauth(np
->authname
);
110 if (level
& VS_ADMIN
) {
116 const char* versionscan_flagstochar(unsigned char flags
) {
117 static char outstring
[50];
120 outstring
[pos
++]='+';
121 if (flags
& VS_ADMIN
) { outstring
[pos
++]='a'; }
122 if (flags
& VS_GLINE
) { outstring
[pos
++]='g'; }
123 if (flags
& VS_STAFF
) { outstring
[pos
++]='s'; }
129 void versionscan_addpattern(char* pattern
, char* data
, unsigned char action
) {
133 vspatterns
=(vspattern
*)malloc(sizeof(vspattern
));
134 strncpy(vspatterns
->pattern
, pattern
, VSPATTERNLEN
);
135 strncpy(vspatterns
->data
, data
, VSDATALEN
);
136 vspatterns
->action
=action
;
138 vspatterns
->hitcount
=0;
142 for (v
=vspatterns
; v
; v
=v
->next
) {
144 v
->next
=(vspattern
*)malloc(sizeof(vspattern
));
145 strncpy(v
->next
->pattern
, pattern
, VSPATTERNLEN
);
146 strncpy(v
->next
->data
, data
, VSDATALEN
);
147 v
->next
->action
=action
;
155 void versionscan_delpattern(char* pattern
) {
159 for (v
=vspatterns
; v
; v
=v
->next
) {
160 if (!ircd_strcmp(v
->pattern
, pattern
)) {
175 vspattern
* versionscan_getpattern(char* pattern
) {
178 for (v
=vspatterns
; v
; v
=v
->next
) {
179 if (!ircd_strcmp(v
->pattern
, pattern
)) {
186 int versionscan_whois(void* sender
, int cargc
, char** cargv
) {
187 nick
* np
=(nick
*)sender
;
192 sendnoticetouser(versionscan_nick
, np
, "Syntax: whois <nickname>");
195 if (!(target
=getnickbynick(cargv
[0]))) {
196 sendnoticetouser(versionscan_nick
, np
, "No such nick.");
199 if (!IsAccount(target
)) {
200 sendnoticetouser(versionscan_nick
, np
, "%s is not authed with the network.", target
->nick
);
203 if (!(v
=versionscan_getauthbyauth(target
->authname
))) {
204 sendnoticetouser(versionscan_nick
, np
, "User %s is not in my database.", target
->nick
);
207 sendnoticetouser(versionscan_nick
, np
, "%s is authed as %s, with flags: %s", target
->nick
, target
->authname
, versionscan_flagstochar(v
->flags
));
211 int versionscan_showcommands(void* sender
, int cargc
, char** cargv
) {
212 nick
* np
=(nick
*)sender
;
213 Command
* cmdlist
[150];
216 sendnoticetouser(versionscan_nick
, np
, "The following commands are registered at present:");
217 j
=getcommandlist(versionscan_commands
, cmdlist
, 150);
218 for (i
=0; i
<j
; i
++) {
219 if (cmdlist
[i
]->level
& (VS_STAFF
| VS_GLINE
| VS_ADMIN
)) {
220 sendnoticetouser(versionscan_nick
, np
, "%s (%s)", cmdlist
[i
]->command
->content
, versionscan_flagstochar(cmdlist
[i
]->level
));
223 sendnoticetouser(versionscan_nick
, np
, "%s", cmdlist
[i
]->command
->content
);
226 sendnoticetouser(versionscan_nick
, np
, "End of list.");
231 int versionscan_help(void* sender
, int cargc
, char** cargv
) {
232 nick
* np
=(nick
*)sender
;
235 sendnoticetouser(versionscan_nick
, np
, "Syntax: help <command>");
239 if (!strcasecmp(cargv
[0], "help")) {
240 sendnoticetouser(versionscan_nick
, np
, "Syntax: help <command>");
241 sendnoticetouser(versionscan_nick
, np
, "Gives help on commands.");
244 if (!strcasecmp(cargv
[0], "hello")) {
245 sendnoticetouser(versionscan_nick
, np
, "Syntax: hello");
246 sendnoticetouser(versionscan_nick
, np
, "Creates the first account on the bot.");
249 if (!strcasecmp(cargv
[0], "scan")) {
250 sendnoticetouser(versionscan_nick
, np
, "Syntax: scan <target>");
251 sendnoticetouser(versionscan_nick
, np
, "Sends a version request to the specified target, which may be a nick or a channel.");
254 if (!strcasecmp(cargv
[0], "broadcast")) {
255 sendnoticetouser(versionscan_nick
, np
, "Syntax: broadcast [-f]");
256 sendnoticetouser(versionscan_nick
, np
, "Send a network-wide CTCP version.");
259 if (!strcasecmp(cargv
[0], "changelev")) {
260 sendnoticetouser(versionscan_nick
, np
, "Syntax: changelev <nick> <level>");
261 sendnoticetouser(versionscan_nick
, np
, "Changes a user's privileges.");
262 sendnoticetouser(versionscan_nick
, np
, "+a -> admin access");
263 sendnoticetouser(versionscan_nick
, np
, "+g -> g-line access");
264 sendnoticetouser(versionscan_nick
, np
, "+s -> staff access");
267 if (!strcasecmp(cargv
[0], "mode")) {
268 sendnoticetouser(versionscan_nick
, np
, "Syntax: mode [<mode of operation>]");
269 sendnoticetouser(versionscan_nick
, np
, "Where <mode of operation> is one of:");
270 sendnoticetouser(versionscan_nick
, np
, "idle: do nothing");
271 sendnoticetouser(versionscan_nick
, np
, "scan: scan newly connecting users and those targeted by the 'scan' command");
272 sendnoticetouser(versionscan_nick
, np
, "stat: collect statistics after a network-wide CTCP version request");
275 if (!strcasecmp(cargv
[0], "showcommands")) {
276 sendnoticetouser(versionscan_nick
, np
, "Syntax: showcommands");
277 sendnoticetouser(versionscan_nick
, np
, "Displays registered commands.");
280 if (!strcasecmp(cargv
[0], "whois")) {
281 sendnoticetouser(versionscan_nick
, np
, "Syntax: whois <nickname>");
282 sendnoticetouser(versionscan_nick
, np
, "Display information about the specified user.");
285 if (!strcasecmp(cargv
[0], "statistics")) {
286 sendnoticetouser(versionscan_nick
, np
, "Syntax: statistics [<limit>]");
287 sendnoticetouser(versionscan_nick
, np
, "Display statistics of collected CTCP version replies.");
290 if (!strcasecmp(cargv
[0], "listpatterns")) {
291 sendnoticetouser(versionscan_nick
, np
, "Syntax: listpatterns");
292 sendnoticetouser(versionscan_nick
, np
, "Lists CTCP version reply patterns.");
295 if (!strcasecmp(cargv
[0], "addpattern")) {
296 sendnoticetouser(versionscan_nick
, np
, "Syntax: addpattern <pattern> <action> <data>");
297 sendnoticetouser(versionscan_nick
, np
, "Adds a CTCP version reply pattern, where action is one of the following:");
298 sendnoticetouser(versionscan_nick
, np
, "%d - warn", VS_WARN
);
299 sendnoticetouser(versionscan_nick
, np
, "%d - kill", VS_KILL
);
300 sendnoticetouser(versionscan_nick
, np
, "%d - g-line user@host", VS_GLUSER
);
301 sendnoticetouser(versionscan_nick
, np
, "%d - g-line *@host", VS_GLHOST
);
304 if (!strcasecmp(cargv
[0], "delpattern")) {
305 sendnoticetouser(versionscan_nick
, np
, "Syntax: delpattern <pattern>");
306 sendnoticetouser(versionscan_nick
, np
, "Deletes a CTCP version reply pattern.");
309 if (!strcasecmp(cargv
[0], "status")) {
310 sendnoticetouser(versionscan_nick
, np
, "Syntax: status");
311 sendnoticetouser(versionscan_nick
, np
, "Gives various bits of information about the bot.");
318 int versionscan_listpatterns(void* sender
, int cargc
, char** cargv
) {
319 nick
* np
=(nick
*)sender
;
322 for (v
=vspatterns
; v
; v
=v
->next
) {
323 sendnoticetouser(versionscan_nick
, np
, "Pattern [%s]:", v
->pattern
);
324 sendnoticetouser(versionscan_nick
, np
, "Data: %s", v
->data
);
325 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");
326 sendnoticetouser(versionscan_nick
, np
, "Hit count: %lu", v
->hitcount
);
328 sendnoticetouser(versionscan_nick
, np
, "End of list.");
332 int versionscan_addpatterncmd(void* sender
, int cargc
, char** cargv
) {
333 nick
* np
=(nick
*)sender
;
337 sendnoticetouser(versionscan_nick
, np
, "Syntax: addpattern <pattern> <action> <data>");
341 action
=atoi(cargv
[1]);
342 if ((action
< VS_WARN
) || (action
> VS_GLHOST
)) {
343 sendnoticetouser(versionscan_nick
, np
, "Action must be a number between 1 and 4.");
347 if (versionscan_getpattern(cargv
[0])) {
348 sendnoticetouser(versionscan_nick
, np
, "That pattern already exists.");
352 if ((action
> VS_KILL
) && !IsVersionscanGlineAccess(np
)) {
353 sendnoticetouser(versionscan_nick
, np
, "You are not allowed to add G-Lines.");
357 versionscan_addpattern(cargv
[0], cargv
[2], (unsigned char)action
);
358 sendnoticetouser(versionscan_nick
, np
, "Done.");
362 int versionscan_delpatterncmd(void* sender
, int cargc
, char** cargv
) {
363 nick
* np
=(nick
*)sender
;
366 sendnoticetouser(versionscan_nick
, np
, "Syntax: delpattern <pattern>");
370 if (!versionscan_getpattern(cargv
[0])) {
371 sendnoticetouser(versionscan_nick
, np
, "That pattern does not exist.");
375 versionscan_delpattern(cargv
[0]);
376 sendnoticetouser(versionscan_nick
, np
, "Done.");
380 int versionscan_status(void* sender
, int cargc
, char** cargv
) {
381 nick
* np
=(nick
*)sender
;
383 int pcount
=0; unsigned long chcount
=0;
385 for (v
=vspatterns
; v
; v
=v
->next
) {
387 chcount
+=v
->hitcount
;
390 sendnoticetouser(versionscan_nick
, np
, "Patterns: %d", pcount
);
391 sendnoticetouser(versionscan_nick
, np
, "Users hit: %lu (%lu from current patterns)", hcount
, chcount
);
392 sendnoticetouser(versionscan_nick
, np
, "Warnings given: %lu", wcount
);
393 sendnoticetouser(versionscan_nick
, np
, "Kills sent: %lu", kcount
);
394 sendnoticetouser(versionscan_nick
, np
, "G-Lines set: %lu", gcount
);
398 int versionscan_hello(void* sender
, int cargc
, char** cargv
) {
399 nick
* np
=(nick
*)sender
;
402 sendnoticetouser(versionscan_nick
, np
, "The hello command cannot be used after the first user account has been created.");
406 vsauths
=(vsauthdata
*)malloc(sizeof(vsauthdata
));
407 strncpy(vsauths
->account
, np
->authname
, ACCOUNTLEN
);
408 vsauths
->flags
=VS_STAFF
| VS_GLINE
| VS_ADMIN
;
411 sendnoticetouser(versionscan_nick
, np
, "An account has been created for you with the following flags: %s.", versionscan_flagstochar(vsauths
->flags
));
415 int versionscan_changelev(void* sender
, int cargc
, char** cargv
) {
416 nick
* np
=(nick
*)sender
;
419 unsigned char flags
=0;
423 sendnoticetouser(versionscan_nick
, np
, "Syntax: changelev <nick> [+|-]<level>");
427 if (!(target
=getnickbynick(cargv
[0]))) {
428 sendnoticetouser(versionscan_nick
, np
, "No such nick.");
432 if (!IsAccount(target
)) {
433 sendnoticetouser(versionscan_nick
, np
, "%s is not authed.", target
->nick
);
437 if ((v
=versionscan_getauthbyauth(target
->authname
))) {
439 if ((cargv
[1][0] == '+') || (cargv
[1][0] =='-')) {
440 plus
=(cargv
[1][0] == '+')?1:0;
444 for (; cargv
[1][i
]; i
++) {
445 switch (cargv
[1][i
]) {
447 flags
=(plus
)?flags
| VS_ADMIN
:flags
& (~VS_ADMIN
);
450 flags
=(plus
)?flags
| VS_GLINE
:flags
& (~VS_GLINE
);
453 flags
=(plus
)?flags
| VS_STAFF
:flags
& (~VS_STAFF
);
456 sendnoticetouser(versionscan_nick
, np
, "Invalid level '%c'.", cargv
[1][i
]);
462 vsauthdata
* pv
, *prevv
;
465 for (pv
=vsauths
; pv
; pv
++) {
468 prevv
->next
=pv
->next
;
482 sendnoticetouser(versionscan_nick
, np
, "Done.");
487 if ((cargv
[1][0] == '+') || (cargv
[1][0] =='-')) {
488 plus
=(cargv
[1][0] == '+')?1:0;
491 for (; cargv
[1][i
]; i
++) {
492 switch (cargv
[1][i
]) {
494 flags
=(plus
)?flags
| VS_ADMIN
:flags
& (~VS_ADMIN
);
497 flags
=(plus
)?flags
| VS_GLINE
:flags
& (~VS_GLINE
);
500 flags
=(plus
)?flags
| VS_STAFF
:flags
& (~VS_STAFF
);
503 sendnoticetouser(versionscan_nick
, np
, "Invalid level '%c'.", cargv
[1][i
]);
509 for (v
=vsauths
; v
; v
=v
->next
) {
511 v
->next
=(vsauthdata
*)malloc(sizeof(vsauthdata
));
512 strncpy(v
->next
->account
, target
->authname
, ACCOUNTLEN
);
513 v
->next
->flags
=flags
;
515 sendnoticetouser(versionscan_nick
, np
, "Done.");
519 sendnoticetouser(versionscan_nick
, np
, "Error adding user to database.");
522 sendnoticetouser(versionscan_nick
, np
, "No level specified.");
529 int versionscan_scan(void* sender
, int cargc
, char** cargv
) {
530 nick
* np
=(nick
*)sender
;
535 sendnoticetouser(versionscan_nick
, np
, "Syntax: scan <target>");
539 if (versionscan_mode
!= VS_SCAN
) {
540 sendnoticetouser(versionscan_nick
, np
, "Scanning of users is currently disabled.");
544 if (cargv
[0][0] == '#') {
545 if ((cp
=findchannel(cargv
[0]))) {
546 sendmessagetochannel(versionscan_nick
, cp
, "\001VERSION\001");
547 sendnoticetouser(versionscan_nick
, np
, "Done.");
550 sendnoticetouser(versionscan_nick
, np
, "No such channel.");
555 if ((n
=getnickbynick(cargv
[0]))) {
557 sendnoticetouser(versionscan_nick
, np
, "Cannot scan IRC Operators.");
560 sendmessagetouser(versionscan_nick
, n
, "\001VERSION\001");
561 sendnoticetouser(versionscan_nick
, np
, "Done.");
564 sendnoticetouser(versionscan_nick
, np
, "No such nick.");
571 int versionscan_modecmd(void* sender
, int cargc
, char** cargv
) {
572 nick
* np
=(nick
*)sender
;
573 int oldmode
=versionscan_mode
;
576 sendnoticetouser(versionscan_nick
, np
, "Currently running in %s mode.", (versionscan_mode
== VS_SCAN
)?"SCAN":(versionscan_mode
== VS_STAT
)?"STATISTICS":"IDLE");
580 if (!ircd_strcmp(cargv
[0], "idle")) {
581 versionscan_mode
=VS_IDLE
;
582 sendnoticetouser(versionscan_nick
, np
, "Now operating in IDLE mode.");
584 else if (!ircd_strcmp(cargv
[0], "scan")) {
585 versionscan_mode
=VS_SCAN
;
586 sendnoticetouser(versionscan_nick
, np
, "Now operating in SCAN mode.");
588 else if (!ircd_strcmp(cargv
[0], "stat")) {
589 versionscan_mode
=VS_STAT
;
590 sendnoticetouser(versionscan_nick
, np
, "Now operating in STATISTICS mode.");
593 sendnoticetouser(versionscan_nick
, np
, "Invalid mode of operation.");
597 if (oldmode
== VS_STAT
) {
600 for (v
=vsstats
; v
;) {
612 int versionscan_statistics(void* sender
, int cargc
, char** cargv
) {
613 nick
* np
=(nick
*)sender
;
615 long rlimit
=0, limit
=100;
617 if (versionscan_mode
!= VS_STAT
) {
618 sendnoticetouser(versionscan_nick
, np
, "No statistics are available unless STATISTICS mode of operation is enabled.");
622 limit
=atoi(cargv
[0]);
624 if ((limit
< 1) || (limit
> 500)) {
625 sendnoticetouser(versionscan_nick
, np
, "Invalid results limit. Valid values are 1-500.");
628 sendnoticetouser(versionscan_nick
, np
, "Reply: [Count]:");
629 for (v
=vsstats
; (v
&& (rlimit
< limit
)); v
=v
->next
) {
630 sendnoticetouser(versionscan_nick
, np
, "%s [%lu]", v
->reply
, v
->count
);
633 sendnoticetouser(versionscan_nick
, np
, "End of list - %lu results returned.", rlimit
);
637 int versionscan_statsdump(void* sender
, int cargc
, char** cargv
) {
638 nick
* np
=(nick
*)sender
;
643 if (versionscan_mode
!= VS_STAT
) {
644 sendnoticetouser(versionscan_nick
, np
, "No statistics are available unless STATISTICS mode of operation is enabled.");
647 if (!(fout
=fopen("data/versionscanstats","w"))) {
648 sendnoticetouser(versionscan_nick
, np
, "Unable to open save file.");
651 for (v
=vsstats
; v
; v
=v
->next
) {
652 fprintf(fout
, "%lu:%s\n", v
->count
, v
->reply
);
656 sendnoticetouser(versionscan_nick
, np
, "%lu results saved.", rlimit
);
660 int versionscan_broadcast(void* sender
, int cargc
, char** cargv
) {
661 nick
* np
=(nick
*)sender
;
665 if (strcmp(cargv
[0], "-f")) {
666 sendnoticetouser(versionscan_nick
, np
, "Invalid flag.");
672 if (versionscan_mode
!= VS_STAT
) {
674 sendnoticetouser(versionscan_nick
, np
, "Statistics collection mode is not currently enabled. Use the 'mode' command to change current mode of operation.");
675 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.");
678 sendnoticetouser(versionscan_nick
, np
, "Forcing network-wide CTCP version.");
681 irc_send("%s P $* :\001VERSION\001\r\n", longtonumeric(versionscan_nick
->numeric
, 5));
682 sendnoticetouser(versionscan_nick
, np
, "Done.");
687 void versionscan_newnick(int hooknum
, void* arg
) {
690 /* ignore opers or auth'd users, helps cut down on spam during a burst */
691 if (!(IsOper(np
) || IsAccount(np
)) && (versionscan_mode
== VS_SCAN
)) {
692 sendmessagetouser(versionscan_nick
, np
, "\001VERSION\001");
696 void versionscan_handler(nick
* me
, int type
, void** args
) {
710 if (!strncmp("\001VERSION", args
[1], 8)) {
711 sendnoticetouser(versionscan_nick
, sender
, "\001VERSION QuakeNet %s v%s.\001", VS_RNDESC
, VS_VERSION
);
715 cargc
=splitline((char*)args
[1], cargv
, 50, 0);
717 cmd
=findcommandintree(versionscan_commands
, cargv
[0], 1);
719 sendnoticetouser(versionscan_nick
, sender
, "Unknown command.");
723 if ((cmd
->level
& VS_AUTHED
) && !IsAccount(sender
)) {
724 sendnoticetouser(versionscan_nick
, sender
, "Sorry, you need to be authed to use this command.");
728 if ((cmd
->level
& VS_OPER
) && !IsOper(sender
)) {
729 sendnoticetouser(versionscan_nick
, sender
, "Sorry, you need to be opered to use this command.");
733 if (((cmd
->level
& VS_STAFF
) && !IsVersionscanStaff(sender
)) ||
734 ((cmd
->level
& VS_GLINE
) && !IsVersionscanGlineAccess(sender
)) ||
735 ((cmd
->level
& VS_ADMIN
) && !IsVersionscanAdmin(sender
))) {
736 sendnoticetouser(versionscan_nick
, sender
, "Sorry, you do not have access to this command.");
740 if (cmd
->maxparams
< (cargc
-1)) {
741 /* We need to do some rejoining */
742 rejoinline(cargv
[cmd
->maxparams
], cargc
-(cmd
->maxparams
));
743 cargc
=(cmd
->maxparams
)+1;
746 (cmd
->handler
)((void*)sender
, cargc
-1, &(cargv
[1]));
751 if (strncmp("\001VERSION ", args
[1], 9)) {
754 if ((p
=strchr((char *)args
[1] + 9, '\001'))) {
757 if (versionscan_mode
== VS_SCAN
) {
758 if (IsOper(sender
)) {
761 for (v
=vspatterns
; v
; v
=v
->next
) {
762 if (match2strings(v
->pattern
, (char *)args
[1] + 9)) {
767 sendnoticetouser(versionscan_nick
, sender
, "%s", v
->data
);
771 killuser(versionscan_nick
, sender
, "%s", v
->data
);
775 irc_send("%s GL * +*!%s@%s 3600 :%s\r\n", mynumeric
->content
, sender
->ident
, sender
->host
->name
->content
, v
->data
);
779 irc_send("%s GL * +*!*@%s 3600 :%s\r\n", mynumeric
->content
, sender
->host
->name
->content
, v
->data
);
783 /* oh dear, something's fucked */
790 else if (versionscan_mode
== VS_STAT
) {
791 versionscan_addstat((char *)args
[1] + 9);
795 versionscan_nick
=NULL
;
796 scheduleoneshot(time(NULL
)+1, &versionscan_createfakeuser
, NULL
);
801 void versionscan_createfakeuser(void* arg
) {
806 sprintf(buf
, "%s v%s", VS_RNDESC
, VS_VERSION
);
807 versionscan_nick
=registerlocaluser(VS_NICK
, VS_IDENT
, VS_HOST
, buf
, VS_AUTHNAME
, UMODE_ACCOUNT
| UMODE_DEAF
| UMODE_OPER
| UMODE_SERVICE
, versionscan_handler
);
808 if ((cp
=findchannel(OPER_CHAN
))) {
809 localjoinchannel(versionscan_nick
, cp
);
810 localgetops(versionscan_nick
, cp
);
812 localcreatechannel(versionscan_nick
, OPER_CHAN
);
820 versionscan_mode
=VS_IDLE
;
822 versionscan_commands
=newcommandtree();
824 addcommandtotree(versionscan_commands
, "showcommands", VS_AUTHED
| VS_STAFF
, 0, versionscan_showcommands
);
825 addcommandtotree(versionscan_commands
, "help", VS_AUTHED
| VS_STAFF
, 1, versionscan_help
);
826 addcommandtotree(versionscan_commands
, "hello", VS_AUTHED
| VS_OPER
, 0, versionscan_hello
);
827 addcommandtotree(versionscan_commands
, "scan", VS_AUTHED
| VS_STAFF
, 1, versionscan_scan
);
828 addcommandtotree(versionscan_commands
, "changelev", VS_AUTHED
| VS_OPER
| VS_ADMIN
, 2, versionscan_changelev
);
829 addcommandtotree(versionscan_commands
, "listpatterns", VS_AUTHED
| VS_STAFF
| VS_OPER
, 0, versionscan_listpatterns
);
830 addcommandtotree(versionscan_commands
, "addpattern", VS_AUTHED
| VS_STAFF
| VS_OPER
, 3, versionscan_addpatterncmd
);
831 addcommandtotree(versionscan_commands
, "delpattern", VS_AUTHED
| VS_OPER
| VS_ADMIN
, 1, versionscan_delpatterncmd
);
832 addcommandtotree(versionscan_commands
, "status", VS_AUTHED
| VS_OPER
| VS_ADMIN
, 0, versionscan_status
);
833 addcommandtotree(versionscan_commands
, "mode", VS_AUTHED
| VS_OPER
| VS_ADMIN
, 1, versionscan_modecmd
);
834 addcommandtotree(versionscan_commands
, "statistics", VS_AUTHED
| VS_OPER
| VS_STAFF
, 1, versionscan_statistics
);
835 addcommandtotree(versionscan_commands
, "statsdump", VS_AUTHED
| VS_OPER
| VS_STAFF
, 1, versionscan_statsdump
);
836 addcommandtotree(versionscan_commands
, "broadcast", VS_AUTHED
| VS_OPER
| VS_ADMIN
, 1, versionscan_broadcast
);
837 addcommandtotree(versionscan_commands
, "whois", VS_AUTHED
| VS_STAFF
, 1, versionscan_whois
);
839 registerhook(HOOK_NICK_NEWNICK
, &versionscan_newnick
);
841 vsconnect
=scheduleoneshot(time(NULL
)+1, &versionscan_createfakeuser
, NULL
);
847 deregisterhook(HOOK_NICK_NEWNICK
, &versionscan_newnick
);
850 deleteschedule(vsconnect
, &versionscan_createfakeuser
, NULL
);
854 if (versionscan_nick
) {
855 deregisterlocaluser(versionscan_nick
, "Module unloaded.");
856 versionscan_nick
=NULL
;
859 destroycommandtree(versionscan_commands
);
861 for (p
=vspatterns
; p
;) {
862 np
=((vspattern
*)p
)->next
;
866 for (p
=vsauths
; p
;) {
867 np
=((vsauthdata
*)p
)->next
;
871 for (p
=vsstats
; p
;) {
872 np
=((vsstatistic
*)p
)->next
;
873 free(((vsstatistic
*)p
)->reply
);