-#include "versionscan.h"\r
-\r
-CommandTree* versionscan_commands;\r
-nick* versionscan_nick;\r
-int versionscannext;\r
-int versionscan_mode;\r
-vspattern* vspatterns;\r
-vsauthdata* vsauths;\r
-vsstatistic* vsstats;\r
-unsigned long hcount=0;\r
-unsigned long wcount=0;\r
-unsigned long kcount=0;\r
-unsigned long gcount=0;\r
-\r
-//sendnoticetouser(versionscan_nick, np, "");\r
-\r
-void versionscan_addstat(char* reply) {\r
- vsstatistic* v, *pv;\r
-\r
- pv=0;\r
- for (v=vsstats; v; v=v->next) {\r
- if (!ircd_strcmp(v->reply, reply)) {\r
- v->count++;\r
- return;\r
- }\r
- pv=v;\r
- }\r
- if (!pv) {\r
- vsstats=(vsstatistic*)malloc(sizeof(vsstatistic));\r
- vsstats->reply=(char*)malloc(strlen(reply)+1);\r
- strcpy(vsstats->reply, reply);\r
- vsstats->count=1;\r
- vsstats->next=0;\r
- }\r
- else {\r
- pv->next=(vsstatistic*)malloc(sizeof(vsstatistic));\r
- pv->next->reply=(char*)malloc(strlen(reply)+1);\r
- strcpy(pv->next->reply, reply);\r
- pv->next->count=1;\r
- pv->next->next=0;\r
- }\r
-}\r
-\r
-unsigned char versionscan_getlevelbyauth(char* auth) {\r
- vsauthdata* v;\r
- \r
- for (v=vsauths; v; v=v->next) {\r
- if (!ircd_strcmp(v->account, auth)) {\r
- return v->flags;\r
- }\r
- }\r
- return 0;\r
-}\r
-\r
-vsauthdata* versionscan_getauthbyauth(char* auth) {\r
- vsauthdata* v;\r
- \r
- for (v=vsauths; v; v=v->next) {\r
- if (!ircd_strcmp(v->account, auth)) {\r
- return v;\r
- }\r
- }\r
- return 0;\r
-}\r
-\r
-int IsVersionscanStaff(nick* np) {\r
- unsigned char level;\r
- \r
- if (!IsAccount(np)) {\r
- return 0;\r
- }\r
- level=versionscan_getlevelbyauth(np->authname);\r
- if (level & (VS_STAFF | VS_GLINE | VS_ADMIN)) {\r
- return 1;\r
- }\r
- return 0;\r
-}\r
-\r
-int IsVersionscanGlineAccess(nick* np) {\r
- unsigned char level;\r
- \r
- if (!IsAccount(np)) {\r
- return 0;\r
- }\r
- level=versionscan_getlevelbyauth(np->authname);\r
- if (level & (VS_GLINE | VS_ADMIN)) {\r
- return 1;\r
- }\r
- return 0;\r
-}\r
-\r
-int IsVersionscanAdmin(nick* np) {\r
- unsigned char level;\r
- \r
- if (!IsAccount(np)) {\r
- return 0;\r
- }\r
- level=versionscan_getlevelbyauth(np->authname);\r
- if (level & VS_ADMIN) {\r
- return 1;\r
- }\r
- return 0;\r
-}\r
-\r
-const char* versionscan_flagstochar(unsigned char flags) {\r
- static char outstring[50];\r
- int pos=0;\r
- \r
- outstring[pos++]='+';\r
- if (flags & VS_ADMIN) { outstring[pos++]='a'; }\r
- if (flags & VS_GLINE) { outstring[pos++]='g'; }\r
- if (flags & VS_STAFF) { outstring[pos++]='s'; }\r
- outstring[pos]='\0';\r
- \r
- return outstring;\r
-}\r
-\r
-void versionscan_addpattern(char* pattern, char* data, unsigned char action) {\r
- vspattern* v;\r
- \r
- if (!vspatterns) {\r
- vspatterns=(vspattern*)malloc(sizeof(vspattern));\r
- strncpy(vspatterns->pattern, pattern, VSPATTERNLEN);\r
- strncpy(vspatterns->data, data, VSDATALEN);\r
- vspatterns->action=action;\r
- vspatterns->next=0;\r
- vspatterns->hitcount=0;\r
- return;\r
- }\r
- \r
- for (v=vspatterns; v; v=v->next) {\r
- if (!v->next) {\r
- v->next=(vspattern*)malloc(sizeof(vspattern));\r
- strncpy(v->next->pattern, pattern, VSPATTERNLEN);\r
- strncpy(v->next->data, data, VSDATALEN);\r
- v->next->action=action;\r
- v->next->next=0;\r
- v->next->hitcount=0;\r
- return;\r
- }\r
- }\r
-}\r
-\r
-void versionscan_delpattern(char* pattern) {\r
- vspattern* v, *pv;\r
- \r
- pv=0;\r
- for (v=vspatterns; v; v=v->next) {\r
- if (!ircd_strcmp(v->pattern, pattern)) {\r
- if (pv) {\r
- pv->next=v->next;\r
- free(v);\r
- }\r
- else {\r
- vspatterns=v->next;\r
- free(v);\r
- }\r
- return;\r
- }\r
- pv=v;\r
- }\r
-}\r
-\r
-vspattern* versionscan_getpattern(char* pattern) {\r
- vspattern* v;\r
- \r
- for (v=vspatterns; v; v=v->next) {\r
- if (!ircd_strcmp(v->pattern, pattern)) {\r
- return v;\r
- }\r
- }\r
- return 0;\r
-}\r
-\r
-int versionscan_whois(void* sender, int cargc, char** cargv) {\r
- nick* np=(nick*)sender;\r
- nick* target;\r
- vsauthdata* v;\r
- \r
- if (cargc < 1) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: whois <nickname>");\r
- return CMD_ERROR;\r
- }\r
- if (!(target=getnickbynick(cargv[0]))) {\r
- sendnoticetouser(versionscan_nick, np, "No such nick.");\r
- return CMD_ERROR;\r
- }\r
- if (!IsAccount(target)) {\r
- sendnoticetouser(versionscan_nick, np, "%s is not authed with the network.", target->nick);\r
- return CMD_ERROR;\r
- }\r
- if (!(v=versionscan_getauthbyauth(target->authname))) {\r
- sendnoticetouser(versionscan_nick, np, "User %s is not in my database.", target->nick);\r
- return CMD_ERROR;\r
- }\r
- sendnoticetouser(versionscan_nick, np, "%s is authed as %s, with flags: %s", target->nick, target->authname, versionscan_flagstochar(v->flags));\r
-}\r
-\r
-int versionscan_showcommands(void* sender, int cargc, char** cargv) {\r
- nick* np=(nick*)sender;\r
- Command* cmdlist[150];\r
- int i, j;\r
- \r
- sendnoticetouser(versionscan_nick, np, "The following commands are registered at present:");\r
- j=getcommandlist(versionscan_commands, cmdlist, 150);\r
- for (i=0; i<j; i++) {\r
- if (cmdlist[i]->level & (VS_STAFF | VS_GLINE | VS_ADMIN)) {\r
- sendnoticetouser(versionscan_nick, np, "%s (%s)", cmdlist[i]->command->content, versionscan_flagstochar(cmdlist[i]->level));\r
- }\r
- else {\r
- sendnoticetouser(versionscan_nick, np, "%s", cmdlist[i]->command->content);\r
- }\r
- }\r
- sendnoticetouser(versionscan_nick, np, "End of list.");\r
- \r
- return CMD_OK;\r
-}\r
-\r
-int versionscan_help(void* sender, int cargc, char** cargv) {\r
- nick* np=(nick*)sender;\r
- \r
- if (cargc < 1) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: help <command>");\r
- return CMD_ERROR;\r
- }\r
- \r
- if (!strcasecmp(cargv[0], "help")) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: help <command>");\r
- sendnoticetouser(versionscan_nick, np, "Gives help on commands.");\r
- return;\r
- }\r
- if (!strcasecmp(cargv[0], "hello")) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: hello");\r
- sendnoticetouser(versionscan_nick, np, "Creates the first account on the bot.");\r
- return;\r
- }\r
- if (!strcasecmp(cargv[0], "scan")) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: scan <target>");\r
- sendnoticetouser(versionscan_nick, np, "Sends a version request to the specified target, which may be a nick or a channel.");\r
- return;\r
- }\r
- if (!strcasecmp(cargv[0], "broadcast")) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: broadcast [-f]");\r
- sendnoticetouser(versionscan_nick, np, "Send a network-wide CTCP version.");\r
- return;\r
- }\r
- if (!strcasecmp(cargv[0], "changelev")) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: changelev <nick> <level>");\r
- sendnoticetouser(versionscan_nick, np, "Changes a user's privileges.");\r
- sendnoticetouser(versionscan_nick, np, "+a -> admin access");\r
- sendnoticetouser(versionscan_nick, np, "+g -> g-line access");\r
- sendnoticetouser(versionscan_nick, np, "+s -> staff access");\r
- return;\r
- }\r
- if (!strcasecmp(cargv[0], "mode")) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: mode [<mode of operation>]");\r
- sendnoticetouser(versionscan_nick, np, "Where <mode of operation> is one of:");\r
- sendnoticetouser(versionscan_nick, np, "idle: do nothing");\r
- sendnoticetouser(versionscan_nick, np, "scan: scan newly connecting users and those targeted by the 'scan' command");\r
- sendnoticetouser(versionscan_nick, np, "stat: collect statistics after a network-wide CTCP version request");\r
- return;\r
- }\r
- if (!strcasecmp(cargv[0], "showcommands")) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: showcommands");\r
- sendnoticetouser(versionscan_nick, np, "Displays registered commands.");\r
- return;\r
- }\r
- if (!strcasecmp(cargv[0], "whois")) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: whois <nickname>");\r
- sendnoticetouser(versionscan_nick, np, "Display information about the specified user.");\r
- return;\r
- }\r
- if (!strcasecmp(cargv[0], "statistics")) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: statistics [<limit>]");\r
- sendnoticetouser(versionscan_nick, np, "Display statistics of collected CTCP version replies.");\r
- return;\r
- }\r
- if (!strcasecmp(cargv[0], "listpatterns")) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: listpatterns");\r
- sendnoticetouser(versionscan_nick, np, "Lists CTCP version reply patterns.");\r
- return;\r
- }\r
- if (!strcasecmp(cargv[0], "addpattern")) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: addpattern <pattern> <action> <data>");\r
- sendnoticetouser(versionscan_nick, np, "Adds a CTCP version reply pattern, where action is one of the following:");\r
- sendnoticetouser(versionscan_nick, np, "%d - warn", VS_WARN);\r
- sendnoticetouser(versionscan_nick, np, "%d - kill", VS_KILL);\r
- sendnoticetouser(versionscan_nick, np, "%d - g-line user@host", VS_GLUSER);\r
- sendnoticetouser(versionscan_nick, np, "%d - g-line *@host", VS_GLHOST);\r
- return;\r
- }\r
- if (!strcasecmp(cargv[0], "delpattern")) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: delpattern <pattern>");\r
- sendnoticetouser(versionscan_nick, np, "Deletes a CTCP version reply pattern.");\r
- return;\r
- }\r
- if (!strcasecmp(cargv[0], "status")) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: status");\r
- sendnoticetouser(versionscan_nick, np, "Gives various bits of information about the bot.");\r
- return;\r
- }\r
- \r
- return CMD_OK;\r
-}\r
-\r
-int versionscan_listpatterns(void* sender, int cargc, char** cargv) {\r
- nick* np=(nick*)sender;\r
- vspattern* v;\r
- \r
- for (v=vspatterns; v; v=v->next) {\r
- sendnoticetouser(versionscan_nick, np, "Pattern [%s]:", v->pattern);\r
- sendnoticetouser(versionscan_nick, np, "Data: %s", v->data);\r
- 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");\r
- sendnoticetouser(versionscan_nick, np, "Hit count: %lu", v->hitcount);\r
- } \r
- sendnoticetouser(versionscan_nick, np, "End of list.");\r
- return CMD_OK;\r
-}\r
-\r
-int versionscan_addpatterncmd(void* sender, int cargc, char** cargv) {\r
- nick* np=(nick*)sender;\r
- int action;\r
- \r
- if (cargc < 3) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: addpattern <pattern> <action> <data>");\r
- return CMD_ERROR;\r
- }\r
- \r
- action=atoi(cargv[1]);\r
- if ((action < VS_WARN) || (action > VS_GLHOST)) {\r
- sendnoticetouser(versionscan_nick, np, "Action must be a number between 1 and 4.");\r
- return CMD_ERROR;\r
- }\r
- \r
- if (versionscan_getpattern(cargv[0])) {\r
- sendnoticetouser(versionscan_nick, np, "That pattern already exists.");\r
- return CMD_ERROR;\r
- }\r
- \r
- if ((action > VS_KILL) && !IsVersionscanGlineAccess(np)) {\r
- sendnoticetouser(versionscan_nick, np, "You are not allowed to add G-Lines.");\r
- return CMD_ERROR;\r
- }\r
- \r
- versionscan_addpattern(cargv[0], cargv[2], (unsigned char)action);\r
- sendnoticetouser(versionscan_nick, np, "Done.");\r
- return CMD_OK;\r
-}\r
-\r
-int versionscan_delpatterncmd(void* sender, int cargc, char** cargv) {\r
- nick* np=(nick*)sender;\r
- \r
- if (cargc < 1) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: delpattern <pattern>");\r
- return CMD_ERROR;\r
- }\r
- \r
- if (!versionscan_getpattern(cargv[0])) {\r
- sendnoticetouser(versionscan_nick, np, "That pattern does not exist.");\r
- return CMD_ERROR;\r
- }\r
- \r
- versionscan_delpattern(cargv[0]);\r
- sendnoticetouser(versionscan_nick, np, "Done.");\r
- return CMD_OK;\r
-}\r
-\r
-int versionscan_status(void* sender, int cargc, char** cargv) {\r
- nick* np=(nick*)sender;\r
- vspattern* v;\r
- int pcount=0; unsigned long chcount=0;\r
- \r
- for (v=vspatterns; v; v=v->next) {\r
- pcount++;\r
- chcount+=v->hitcount;\r
- }\r
- \r
- sendnoticetouser(versionscan_nick, np, "Patterns: %d", pcount);\r
- sendnoticetouser(versionscan_nick, np, "Users hit: %lu (%lu from current patterns)", hcount, chcount);\r
- sendnoticetouser(versionscan_nick, np, "Warnings given: %lu", wcount);\r
- sendnoticetouser(versionscan_nick, np, "Kills sent: %lu", kcount);\r
- sendnoticetouser(versionscan_nick, np, "G-Lines set: %lu", gcount);\r
- return CMD_OK;\r
-}\r
-\r
-int versionscan_hello(void* sender, int cargc, char** cargv) {\r
- nick* np=(nick*)sender;\r
- \r
- if (vsauths) {\r
- sendnoticetouser(versionscan_nick, np, "The hello command cannot be used after the first user account has been created.");\r
- return CMD_ERROR;\r
- }\r
- \r
- vsauths=(vsauthdata*)malloc(sizeof(vsauthdata));\r
- strncpy(vsauths->account, np->authname, ACCOUNTLEN);\r
- vsauths->flags=VS_STAFF | VS_GLINE | VS_ADMIN;\r
- vsauths->next;\r
- \r
- sendnoticetouser(versionscan_nick, np, "An account has been created for you with the following flags: %s.", versionscan_flagstochar(vsauths->flags));\r
- return CMD_OK;\r
-}\r
-\r
-int versionscan_changelev(void* sender, int cargc, char** cargv) {\r
- nick* np=(nick*)sender;\r
- vsauthdata* v;\r
- nick* target;\r
- unsigned char flags=0;\r
- int i; int plus=1;\r
- \r
- if (cargc < 2) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: changelev <nick> [+|-]<level>");\r
- return CMD_ERROR;\r
- }\r
- \r
- if (!(target=getnickbynick(cargv[0]))) {\r
- sendnoticetouser(versionscan_nick, np, "No such nick.");\r
- return CMD_ERROR;\r
- }\r
- \r
- if (!IsAccount(target)) {\r
- sendnoticetouser(versionscan_nick, np, "%s is not authed.", target->nick);\r
- return CMD_ERROR;\r
- }\r
- \r
- if ((v=versionscan_getauthbyauth(target->authname))) {\r
- i=0;\r
- if ((cargv[1][0] == '+') || (cargv[1][0] =='-')) {\r
- plus=(cargv[1][0] == '+')?1:0;\r
- i++;\r
- flags=v->flags;\r
- }\r
- for (; cargv[1][i]; i++) {\r
- switch (cargv[1][i]) {\r
- case 'a':\r
- flags=(plus)?flags | VS_ADMIN:flags & (~VS_ADMIN);\r
- break;\r
- case 'g':\r
- flags=(plus)?flags | VS_GLINE:flags & (~VS_GLINE);\r
- break;\r
- case 's':\r
- flags=(plus)?flags | VS_STAFF:flags & (~VS_STAFF);\r
- break;\r
- default:\r
- sendnoticetouser(versionscan_nick, np, "Invalid level '%c'.", cargv[1][i]);\r
- return CMD_ERROR;\r
- break;\r
- }\r
- }\r
- if (!flags) {\r
- vsauthdata* pv, *prevv;\r
- \r
- prevv=0;\r
- for (pv=vsauths; pv; pv++) {\r
- if (pv == v) {\r
- if (prevv) {\r
- prevv->next=pv->next;\r
- free(pv);\r
- }\r
- else {\r
- vsauths=pv->next;\r
- free(pv);\r
- }\r
- }\r
- prevv=pv;\r
- }\r
- }\r
- else {\r
- v->flags=flags;\r
- }\r
- sendnoticetouser(versionscan_nick, np, "Done.");\r
- return CMD_OK;\r
- }\r
- else {\r
- i=0;\r
- if ((cargv[1][0] == '+') || (cargv[1][0] =='-')) {\r
- plus=(cargv[1][0] == '+')?1:0;\r
- i++;\r
- }\r
- for (; cargv[1][i]; i++) {\r
- switch (cargv[1][i]) {\r
- case 'a':\r
- flags=(plus)?flags | VS_ADMIN:flags & (~VS_ADMIN);\r
- break;\r
- case 'g':\r
- flags=(plus)?flags | VS_GLINE:flags & (~VS_GLINE);\r
- break;\r
- case 's':\r
- flags=(plus)?flags | VS_STAFF:flags & (~VS_STAFF);\r
- break;\r
- default:\r
- sendnoticetouser(versionscan_nick, np, "Invalid level '%c'.", cargv[1][i]);\r
- return CMD_ERROR;\r
- break;\r
- }\r
- }\r
- if (flags) {\r
- for (v=vsauths; v; v=v->next) {\r
- if (!v->next) {\r
- v->next=(vsauthdata*)malloc(sizeof(vsauthdata));\r
- strncpy(v->next->account, target->authname, ACCOUNTLEN);\r
- v->next->flags=flags;\r
- v->next->next=0;\r
- sendnoticetouser(versionscan_nick, np, "Done.");\r
- return CMD_OK;\r
- }\r
- }\r
- sendnoticetouser(versionscan_nick, np, "Error adding user to database.");\r
- }\r
- else {\r
- sendnoticetouser(versionscan_nick, np, "No level specified.");\r
- }\r
- }\r
- \r
- return CMD_ERROR;\r
-}\r
-\r
-int versionscan_scan(void* sender, int cargc, char** cargv) {\r
- nick* np=(nick*)sender;\r
- nick* n;\r
- channel* cp;\r
- \r
- if (cargc < 1) {\r
- sendnoticetouser(versionscan_nick, np, "Syntax: scan <target>");\r
- return CMD_ERROR;\r
- }\r
- \r
- if (versionscan_mode != VS_SCAN) {\r
- sendnoticetouser(versionscan_nick, np, "Scanning of users is currently disabled.");\r
- return CMD_ERROR;\r
- }\r
- \r
- if (cargv[0][0] == '#') {\r
- if ((cp=findchannel(cargv[0]))) {\r
- sendmessagetochannel(versionscan_nick, cp, "\001VERSION\001");\r
- sendnoticetouser(versionscan_nick, np, "Done.");\r
- }\r
- else {\r
- sendnoticetouser(versionscan_nick, np, "No such channel.");\r
- return CMD_ERROR;\r
- }\r
- }\r
- else {\r
- if ((n=getnickbynick(cargv[0]))) {\r
- if (IsOper(n)) {\r
- sendnoticetouser(versionscan_nick, np, "Cannot scan IRC Operators.");\r
- return CMD_ERROR;\r
- }\r
- sendmessagetouser(versionscan_nick, n, "\001VERSION\001");\r
- sendnoticetouser(versionscan_nick, np, "Done.");\r
- }\r
- else {\r
- sendnoticetouser(versionscan_nick, np, "No such nick.");\r
- return CMD_ERROR;\r
- }\r
- }\r
- return CMD_OK;\r
-}\r
-\r
-int versionscan_modecmd(void* sender, int cargc, char** cargv) {\r
- nick* np=(nick*)sender;\r
- int oldmode=versionscan_mode;\r
- \r
- if (cargc < 1) {\r
- sendnoticetouser(versionscan_nick, np, "Currently running in %s mode.", (versionscan_mode == VS_SCAN)?"SCAN":(versionscan_mode == VS_STAT)?"STATISTICS":"IDLE");\r
- return CMD_OK;\r
- }\r
- \r
- if (!ircd_strcmp(cargv[0], "idle")) {\r
- versionscan_mode=VS_IDLE;\r
- sendnoticetouser(versionscan_nick, np, "Now operating in IDLE mode.");\r
- }\r
- else if (!ircd_strcmp(cargv[0], "scan")) {\r
- versionscan_mode=VS_SCAN;\r
- sendnoticetouser(versionscan_nick, np, "Now operating in SCAN mode.");\r
- }\r
- else if (!ircd_strcmp(cargv[0], "stat")) {\r
- versionscan_mode=VS_STAT;\r
- sendnoticetouser(versionscan_nick, np, "Now operating in STATISTICS mode.");\r
- }\r
- else {\r
- sendnoticetouser(versionscan_nick, np, "Invalid mode of operation.");\r
- return CMD_ERROR;\r
- }\r
- \r
- if (oldmode == VS_STAT) {\r
- vsstatistic* v, *nv;\r
- \r
- for (v=vsstats; v;) {\r
- nv=v->next;\r
- free(v->reply);\r
- free(v);\r
- v=nv;\r
- }\r
- vsstats=0;\r
- }\r
- \r
- return CMD_OK;\r
-}\r
-\r
-int versionscan_statistics(void* sender, int cargc, char** cargv) {\r
- nick* np=(nick*)sender;\r
- vsstatistic* v;\r
- long rlimit=0, limit=100;\r
- \r
- if (versionscan_mode != VS_STAT) {\r
- sendnoticetouser(versionscan_nick, np, "No statistics are available unless STATISTICS mode of operation is enabled.");\r
- return;\r
- }\r
- if (cargc) {\r
- limit=atoi(cargv[0]);\r
- }\r
- if ((limit < 1) || (limit > 500)) {\r
- sendnoticetouser(versionscan_nick, np, "Invalid results limit. Valid values are 1-500.");\r
- return;\r
- }\r
- sendnoticetouser(versionscan_nick, np, "Reply: [Count]:");\r
- for (v=vsstats; (v && (rlimit < limit)); v=v->next) {\r
- sendnoticetouser(versionscan_nick, np, "%s [%lu]", v->reply, v->count);\r
- rlimit++;\r
- }\r
- sendnoticetouser(versionscan_nick, np, "End of list - %lu results returned.", rlimit);\r
-}\r
-\r
-int versionscan_broadcast(void* sender, int cargc, char** cargv) {\r
- nick* np=(nick*)sender;\r
- int force=0;\r
- \r
- if (cargc) {\r
- if (strcmp(cargv[0], "-f")) {\r
- sendnoticetouser(versionscan_nick, np, "Invalid flag.");\r
- return CMD_ERROR;\r
- }\r
- force=1;\r
- }\r
- \r
- if (versionscan_mode != VS_STAT) {\r
- if (!force) {\r
- sendnoticetouser(versionscan_nick, np, "Statistics collection mode is not currently enabled. Use the 'mode' command to change current mode of operation.");\r
- 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.");\r
- return CMD_ERROR;\r
- }\r
- sendnoticetouser(versionscan_nick, np, "Forcing network-wide CTCP version.");\r
- }\r
- \r
- irc_send("%s P $* :\001VERSION\001\r\n", longtonumeric(versionscan_nick->numeric, 5));\r
- sendnoticetouser(versionscan_nick, np, "Done.");\r
- \r
- return CMD_OK;\r
-}\r
-\r
-void versionscan_newnick(int hooknum, void* arg) {\r
- nick* np=(nick*)arg;\r
- \r
- /* ignore opers or auth'd users, helps cut down on spam during a burst */\r
- if (!(IsOper(np) || IsAccount(np)) && (versionscan_mode == VS_SCAN)) {\r
- sendmessagetouser(versionscan_nick, np, "\001VERSION\001");\r
- }\r
-}\r
-\r
-void versionscan_handler(nick* me, int type, void** args) {\r
- nick* sender;\r
- Command* cmd;\r
- char* cargv[50];\r
- int cargc;\r
- vspattern* v;\r
- char* p;\r
-\r
- switch (type) {\r
- case LU_PRIVMSG:\r
- case LU_SECUREMSG:\r
- /* nick */\r
- sender=args[0];\r
- \r
- if (!strncmp("\001VERSION", args[1], 8)) {\r
- sendnoticetouser(versionscan_nick, sender, "\001VERSION QuakeNet %s v%s.\001", VS_RNDESC, VS_VERSION);\r
- return;\r
- }\r
- \r
- cargc=splitline((char*)args[1], cargv, 50, 0);\r
- \r
- cmd=findcommandintree(versionscan_commands, cargv[0], 1);\r
- if (!cmd) {\r
- sendnoticetouser(versionscan_nick, sender, "Unknown command.");\r
- return;\r
- }\r
- \r
-/* if ((cmd->level & VS_AUTHED) && !IsAccount(sender)) {\r
- sendnoticetouser(versionscan_nick, sender, "Sorry, you need to be authed to use this command.");\r
- return;\r
- }\r
-*/ \r
- if ((cmd->level & VS_OPER) && !IsOper(sender)) {\r
- sendnoticetouser(versionscan_nick, sender, "Sorry, you need to be opered to use this command.");\r
- return;\r
- }\r
-/* \r
- if (((cmd->level & VS_STAFF) && !IsVersionscanStaff(sender)) || \r
- ((cmd->level & VS_GLINE) && !IsVersionscanGlineAccess(sender)) || \r
- ((cmd->level & VS_ADMIN) && !IsVersionscanAdmin(sender))) {\r
- sendnoticetouser(versionscan_nick, sender, "Sorry, you do not have access to this command.");\r
- return;\r
- }\r
-*/ /* \r
- if ((cmd->level & VS_GLINE) && !IsVersionscanGlineAccess(sender)) {\r
- sendnoticetouser(versionscan_nick, sender, "Sorry, you do not have access to this command.");\r
- return;\r
- }\r
- \r
- if ((cmd->level & VS_ADMIN) && !IsVersionscanAdmin(sender)) {\r
- sendnoticetouser(versionscan_nick, sender, "Sorry, you do not have access to this command.");\r
- return;\r
- }*/\r
- \r
- if (cmd->maxparams < (cargc-1)) {\r
- /* We need to do some rejoining */\r
- rejoinline(cargv[cmd->maxparams], cargc-(cmd->maxparams));\r
- cargc=(cmd->maxparams)+1;\r
- }\r
- \r
- (cmd->handler)((void*)sender, cargc-1, &(cargv[1]));\r
- break;\r
- case LU_PRIVNOTICE:\r
- sender=args[0];\r
- \r
- if (strncmp("\001VERSION", args[1], 8)) {\r
- break;\r
- }\r
- if ((p=strchr(&args[1][8], '\001'))) {\r
- *p++='\0';\r
- }\r
- if (versionscan_mode == VS_SCAN) {\r
- if (IsOper(sender)) {\r
- break;\r
- }\r
- for (v=vspatterns; v; v=v->next) {\r
- if (match2strings(v->pattern, &args[1][8])) {\r
- v->hitcount++;\r
- hcount++;\r
- switch (v->action) {\r
- case VS_WARN:\r
- sendnoticetouser(versionscan_nick, sender, v->data);\r
- wcount++;\r
- break;\r
- case VS_KILL:\r
- killuser(versionscan_nick, sender, v->data);\r
- kcount++;\r
- break;\r
- case VS_GLUSER:\r
- irc_send("%s GL * +*!%s@%s 3600 :%s\r\n", mynumeric->content, sender->ident, sender->host->name->content, v->data);\r
- gcount++;\r
- break;\r
- case VS_GLHOST:\r
- irc_send("%s GL * +*!*@%s 3600 :%s\r\n", mynumeric->content, sender->host->name->content, v->data);\r
- gcount++;\r
- break;\r
- default:\r
- /* oh dear, something's fucked */\r
- break;\r
- }\r
- break;\r
- }\r
- }\r
- }\r
- else if (versionscan_mode == VS_STAT) {\r
- versionscan_addstat(&args[1][8]);\r
- }\r
- break;\r
- case LU_KILLED:\r
- versionscan_nick=NULL;\r
- scheduleoneshot(time(NULL)+1, &versionscan_createfakeuser, NULL);\r
- break;\r
- }\r
-}\r
-\r
-void versionscan_createfakeuser(void* arg) {\r
- channel* cp;\r
- char buf[200];\r
- \r
- sprintf(buf, "%s v%s", VS_RNDESC, VS_VERSION);\r
- versionscan_nick=registerlocaluser(VS_NICK, VS_IDENT, VS_HOST, buf, VS_AUTHNAME, UMODE_ACCOUNT | UMODE_DEAF | UMODE_OPER | UMODE_SERVICE, versionscan_handler);\r
- if ((cp=findchannel(OPER_CHAN))) {\r
- localjoinchannel(versionscan_nick, cp);\r
- localgetops(versionscan_nick, cp);\r
- } else {\r
- localcreatechannel(versionscan_nick, OPER_CHAN);\r
- }\r
-}\r
-\r
-void _init() {\r
- vspatterns=0;\r
- vsauths=0;\r
- vsstats=0;\r
- versionscan_mode=VS_IDLE;\r
- \r
- versionscan_commands=newcommandtree();\r
- \r
- addcommandtotree(versionscan_commands, "showcommands", 0, 0, versionscan_showcommands);\r
- addcommandtotree(versionscan_commands, "help", VS_AUTHED | VS_STAFF, 1, versionscan_help);\r
- addcommandtotree(versionscan_commands, "hello", VS_AUTHED | VS_OPER, 0, versionscan_hello);\r
- addcommandtotree(versionscan_commands, "scan", VS_AUTHED | VS_STAFF, 1, versionscan_scan);\r
- addcommandtotree(versionscan_commands, "changelev", VS_AUTHED | VS_OPER | VS_ADMIN, 2, versionscan_changelev);\r
- addcommandtotree(versionscan_commands, "listpatterns", VS_AUTHED | VS_STAFF | VS_OPER, 0, versionscan_listpatterns);\r
- addcommandtotree(versionscan_commands, "addpattern", VS_AUTHED | VS_STAFF | VS_OPER, 3, versionscan_addpatterncmd);\r
- addcommandtotree(versionscan_commands, "delpattern", VS_AUTHED | VS_OPER | VS_ADMIN, 1, versionscan_delpatterncmd);\r
- addcommandtotree(versionscan_commands, "status", VS_AUTHED | VS_OPER | VS_ADMIN, 0, versionscan_status);\r
- addcommandtotree(versionscan_commands, "mode", VS_AUTHED | VS_OPER | VS_ADMIN, 1, versionscan_modecmd);\r
- addcommandtotree(versionscan_commands, "statistics", VS_AUTHED | VS_OPER | VS_STAFF, 1, versionscan_statistics);\r
- addcommandtotree(versionscan_commands, "broadcast", VS_AUTHED | VS_OPER | VS_ADMIN, 1, versionscan_broadcast);\r
- addcommandtotree(versionscan_commands, "whois", VS_AUTHED | VS_STAFF, 1, versionscan_whois);\r
- \r
- registerhook(HOOK_NICK_NEWNICK, &versionscan_newnick);\r
- \r
- scheduleoneshot(time(NULL)+1, &versionscan_createfakeuser, NULL);\r
-}\r
-\r
-void _fini() {\r
- void* p, *np;\r
- \r
- deregisterhook(HOOK_NICK_NEWNICK, &versionscan_newnick);\r
- if (versionscan_nick) {\r
- deregisterlocaluser(versionscan_nick, "Module unloaded.");\r
- versionscan_nick=NULL;\r
- }\r
- \r
- for (p=vspatterns; p;) {\r
- np=((vspattern*)p)->next;\r
- free(p);\r
- p=np;\r
- }\r
- for (p=vsauths; p;) {\r
- np=((vsauthdata*)p)->next;\r
- free(p);\r
- p=np;\r
- }\r
- for (p=vsstats; p;) {\r
- np=((vsstatistic*)p)->next;\r
- free(((vsstatistic*)p)->reply);\r
- free(p);\r
- p=np;\r
- }\r
-}\r
+#include "versionscan.h"
+#include "../lib/version.h"
+#include "../glines/glines.h"
+
+MODULE_VERSION("")
+
+CommandTree* versionscan_commands;
+nick* versionscan_nick;
+int versionscannext;
+int versionscan_mode;
+vspattern* vspatterns;
+vsauthdata* vsauths;
+vsstatistic* vsstats;
+unsigned long hcount=0;
+unsigned long wcount=0;
+unsigned long kcount=0;
+unsigned long gcount=0;
+schedule *vsconnect;
+
+void versionscan_addstat(char* reply) {
+ unsigned int replylen;
+ unsigned long replycrc;
+ vsstatistic* v, *pv;
+
+ replylen = strlen(reply);
+ replycrc = crc32i(reply);
+
+ pv=NULL;
+ for (v=vsstats; v; v=v->next) {
+ if (v->replylen==replylen && v->replycrc==replycrc) {
+ v->count++;
+ return;
+ }
+ pv=v;
+ }
+ if (!pv) {
+ vsstats=(vsstatistic*)malloc(sizeof(vsstatistic));
+ vsstats->reply=(char*)malloc(replylen + 1);
+ strcpy(vsstats->reply, reply);
+ vsstats->replylen = replylen;
+ vsstats->replycrc = replycrc;
+ vsstats->count=1;
+ vsstats->next=NULL;
+ }
+ else {
+ pv->next=(vsstatistic*)malloc(sizeof(vsstatistic));
+ pv->next->reply=(char*)malloc(replylen + 1);
+ strcpy(pv->next->reply, reply);
+ pv->next->replylen = replylen;
+ pv->next->replycrc = replycrc;
+ pv->next->count=1;
+ pv->next->next=NULL;
+ }
+}
+
+unsigned char versionscan_getlevelbyauth(char* auth) {
+ vsauthdata* v;
+
+ for (v=vsauths; v; v=v->next) {
+ if (!ircd_strcmp(v->account, auth)) {
+ return v->flags;
+ }
+ }
+ return 0;
+}
+
+vsauthdata* versionscan_getauthbyauth(char* auth) {
+ vsauthdata* v;
+
+ for (v=vsauths; v; v=v->next) {
+ if (!ircd_strcmp(v->account, auth)) {
+ return v;
+ }
+ }
+ return 0;
+}
+
+int IsVersionscanStaff(nick* np) {
+ unsigned char level;
+
+ if (!IsAccount(np)) {
+ return 0;
+ }
+ level=versionscan_getlevelbyauth(np->authname);
+ if (level & (VS_STAFF | VS_GLINE | VS_ADMIN)) {
+ return 1;
+ }
+ return 0;
+}
+
+int IsVersionscanGlineAccess(nick* np) {
+ unsigned char level;
+
+ if (!IsAccount(np)) {
+ return 0;
+ }
+ level=versionscan_getlevelbyauth(np->authname);
+ if (level & (VS_GLINE | VS_ADMIN)) {
+ return 1;
+ }
+ return 0;
+}
+
+int IsVersionscanAdmin(nick* np) {
+ unsigned char level;
+
+ if (!IsAccount(np)) {
+ return 0;
+ }
+ level=versionscan_getlevelbyauth(np->authname);
+ if (level & VS_ADMIN) {
+ return 1;
+ }
+ return 0;
+}
+
+const char* versionscan_flagstochar(unsigned char flags) {
+ static char outstring[50];
+ int pos=0;
+
+ outstring[pos++]='+';
+ if (flags & VS_ADMIN) { outstring[pos++]='a'; }
+ if (flags & VS_GLINE) { outstring[pos++]='g'; }
+ if (flags & VS_STAFF) { outstring[pos++]='s'; }
+ outstring[pos]='\0';
+
+ return outstring;
+}
+
+void versionscan_addpattern(char* pattern, char* data, unsigned char action) {
+ vspattern* v;
+
+ if (!vspatterns) {
+ vspatterns=(vspattern*)malloc(sizeof(vspattern));
+ strncpy(vspatterns->pattern, pattern, VSPATTERNLEN);
+ strncpy(vspatterns->data, data, VSDATALEN);
+ vspatterns->action=action;
+ vspatterns->next=0;
+ vspatterns->hitcount=0;
+ return;
+ }
+
+ for (v=vspatterns; v; v=v->next) {
+ if (!v->next) {
+ v->next=(vspattern*)malloc(sizeof(vspattern));
+ strncpy(v->next->pattern, pattern, VSPATTERNLEN);
+ strncpy(v->next->data, data, VSDATALEN);
+ v->next->action=action;
+ v->next->next=0;
+ v->next->hitcount=0;
+ return;
+ }
+ }
+}
+
+void versionscan_delpattern(char* pattern) {
+ vspattern* v, *pv;
+
+ pv=0;
+ for (v=vspatterns; v; v=v->next) {
+ if (!ircd_strcmp(v->pattern, pattern)) {
+ if (pv) {
+ pv->next=v->next;
+ free(v);
+ }
+ else {
+ vspatterns=v->next;
+ free(v);
+ }
+ return;
+ }
+ pv=v;
+ }
+}
+
+vspattern* versionscan_getpattern(char* pattern) {
+ vspattern* v;
+
+ for (v=vspatterns; v; v=v->next) {
+ if (!ircd_strcmp(v->pattern, pattern)) {
+ return v;
+ }
+ }
+ return 0;
+}
+
+int versionscan_whois(void* sender, int cargc, char** cargv) {
+ nick* np=(nick*)sender;
+ nick* target;
+ vsauthdata* v;
+
+ if (cargc < 1) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: whois <nickname>");
+ return CMD_ERROR;
+ }
+ if (!(target=getnickbynick(cargv[0]))) {
+ sendnoticetouser(versionscan_nick, np, "No such nick.");
+ return CMD_ERROR;
+ }
+ if (!IsAccount(target)) {
+ sendnoticetouser(versionscan_nick, np, "%s is not authed with the network.", target->nick);
+ return CMD_ERROR;
+ }
+ if (!(v=versionscan_getauthbyauth(target->authname))) {
+ sendnoticetouser(versionscan_nick, np, "User %s is not in my database.", target->nick);
+ return CMD_ERROR;
+ }
+ sendnoticetouser(versionscan_nick, np, "%s is authed as %s, with flags: %s", target->nick, target->authname, versionscan_flagstochar(v->flags));
+ return CMD_OK;
+}
+
+int versionscan_showcommands(void* sender, int cargc, char** cargv) {
+ nick* np=(nick*)sender;
+ Command* cmdlist[150];
+ int i, j;
+
+ sendnoticetouser(versionscan_nick, np, "The following commands are registered at present:");
+ j=getcommandlist(versionscan_commands, cmdlist, 150);
+ for (i=0; i<j; i++) {
+ if (cmdlist[i]->level & (VS_STAFF | VS_GLINE | VS_ADMIN)) {
+ sendnoticetouser(versionscan_nick, np, "%s (%s)", cmdlist[i]->command->content, versionscan_flagstochar(cmdlist[i]->level));
+ }
+ else {
+ sendnoticetouser(versionscan_nick, np, "%s", cmdlist[i]->command->content);
+ }
+ }
+ sendnoticetouser(versionscan_nick, np, "End of list.");
+
+ return CMD_OK;
+}
+
+int versionscan_help(void* sender, int cargc, char** cargv) {
+ nick* np=(nick*)sender;
+
+ if (cargc < 1) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: help <command>");
+ return CMD_ERROR;
+ }
+
+ if (!strcasecmp(cargv[0], "help")) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: help <command>");
+ sendnoticetouser(versionscan_nick, np, "Gives help on commands.");
+ return CMD_OK;
+ }
+ if (!strcasecmp(cargv[0], "hello")) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: hello");
+ sendnoticetouser(versionscan_nick, np, "Creates the first account on the bot.");
+ return CMD_OK;
+ }
+ if (!strcasecmp(cargv[0], "scan")) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: scan <target>");
+ sendnoticetouser(versionscan_nick, np, "Sends a version request to the specified target, which may be a nick or a channel.");
+ return CMD_OK;
+ }
+ if (!strcasecmp(cargv[0], "broadcast")) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: broadcast [-f]");
+ sendnoticetouser(versionscan_nick, np, "Send a network-wide CTCP version.");
+ return CMD_OK;
+ }
+ if (!strcasecmp(cargv[0], "changelev")) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: changelev <nick> <level>");
+ sendnoticetouser(versionscan_nick, np, "Changes a user's privileges.");
+ sendnoticetouser(versionscan_nick, np, "+a -> admin access");
+ sendnoticetouser(versionscan_nick, np, "+g -> g-line access");
+ sendnoticetouser(versionscan_nick, np, "+s -> staff access");
+ return CMD_OK;
+ }
+ if (!strcasecmp(cargv[0], "mode")) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: mode [<mode of operation>]");
+ sendnoticetouser(versionscan_nick, np, "Where <mode of operation> is one of:");
+ sendnoticetouser(versionscan_nick, np, "idle: do nothing");
+ sendnoticetouser(versionscan_nick, np, "scan: scan newly connecting users and those targeted by the 'scan' command");
+ sendnoticetouser(versionscan_nick, np, "stat: collect statistics after a network-wide CTCP version request");
+ return CMD_OK;
+ }
+ if (!strcasecmp(cargv[0], "showcommands")) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: showcommands");
+ sendnoticetouser(versionscan_nick, np, "Displays registered commands.");
+ return CMD_OK;
+ }
+ if (!strcasecmp(cargv[0], "whois")) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: whois <nickname>");
+ sendnoticetouser(versionscan_nick, np, "Display information about the specified user.");
+ return CMD_OK;
+ }
+ if (!strcasecmp(cargv[0], "statistics")) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: statistics [<limit>]");
+ sendnoticetouser(versionscan_nick, np, "Display statistics of collected CTCP version replies.");
+ return CMD_OK;
+ }
+ if (!strcasecmp(cargv[0], "listpatterns")) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: listpatterns");
+ sendnoticetouser(versionscan_nick, np, "Lists CTCP version reply patterns.");
+ return CMD_OK;
+ }
+ if (!strcasecmp(cargv[0], "addpattern")) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: addpattern <pattern> <action> <data>");
+ sendnoticetouser(versionscan_nick, np, "Adds a CTCP version reply pattern, where action is one of the following:");
+ sendnoticetouser(versionscan_nick, np, "%d - warn", VS_WARN);
+ sendnoticetouser(versionscan_nick, np, "%d - kill", VS_KILL);
+ sendnoticetouser(versionscan_nick, np, "%d - g-line user@host", VS_GLUSER);
+ sendnoticetouser(versionscan_nick, np, "%d - g-line *@host", VS_GLHOST);
+ return CMD_OK;
+ }
+ if (!strcasecmp(cargv[0], "delpattern")) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: delpattern <pattern>");
+ sendnoticetouser(versionscan_nick, np, "Deletes a CTCP version reply pattern.");
+ return CMD_OK;
+ }
+ if (!strcasecmp(cargv[0], "status")) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: status");
+ sendnoticetouser(versionscan_nick, np, "Gives various bits of information about the bot.");
+ return CMD_OK;
+ }
+
+ return CMD_OK;
+}
+
+int versionscan_listpatterns(void* sender, int cargc, char** cargv) {
+ nick* np=(nick*)sender;
+ vspattern* v;
+
+ for (v=vspatterns; v; v=v->next) {
+ sendnoticetouser(versionscan_nick, np, "Pattern [%s]:", v->pattern);
+ sendnoticetouser(versionscan_nick, np, "Data: %s", v->data);
+ 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");
+ sendnoticetouser(versionscan_nick, np, "Hit count: %lu", v->hitcount);
+ }
+ sendnoticetouser(versionscan_nick, np, "End of list.");
+ return CMD_OK;
+}
+
+int versionscan_addpatterncmd(void* sender, int cargc, char** cargv) {
+ nick* np=(nick*)sender;
+ int action;
+
+ if (cargc < 3) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: addpattern <pattern> <action> <data>");
+ return CMD_ERROR;
+ }
+
+ action=atoi(cargv[1]);
+ if ((action < VS_WARN) || (action > VS_GLHOST)) {
+ sendnoticetouser(versionscan_nick, np, "Action must be a number between 1 and 4.");
+ return CMD_ERROR;
+ }
+
+ if (versionscan_getpattern(cargv[0])) {
+ sendnoticetouser(versionscan_nick, np, "That pattern already exists.");
+ return CMD_ERROR;
+ }
+
+ if ((action > VS_KILL) && !IsVersionscanGlineAccess(np)) {
+ sendnoticetouser(versionscan_nick, np, "You are not allowed to add G-Lines.");
+ return CMD_ERROR;
+ }
+
+ versionscan_addpattern(cargv[0], cargv[2], (unsigned char)action);
+ sendnoticetouser(versionscan_nick, np, "Done.");
+ return CMD_OK;
+}
+
+int versionscan_delpatterncmd(void* sender, int cargc, char** cargv) {
+ nick* np=(nick*)sender;
+
+ if (cargc < 1) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: delpattern <pattern>");
+ return CMD_ERROR;
+ }
+
+ if (!versionscan_getpattern(cargv[0])) {
+ sendnoticetouser(versionscan_nick, np, "That pattern does not exist.");
+ return CMD_ERROR;
+ }
+
+ versionscan_delpattern(cargv[0]);
+ sendnoticetouser(versionscan_nick, np, "Done.");
+ return CMD_OK;
+}
+
+int versionscan_status(void* sender, int cargc, char** cargv) {
+ nick* np=(nick*)sender;
+ vspattern* v;
+ int pcount=0; unsigned long chcount=0;
+
+ for (v=vspatterns; v; v=v->next) {
+ pcount++;
+ chcount+=v->hitcount;
+ }
+
+ sendnoticetouser(versionscan_nick, np, "Patterns: %d", pcount);
+ sendnoticetouser(versionscan_nick, np, "Users hit: %lu (%lu from current patterns)", hcount, chcount);
+ sendnoticetouser(versionscan_nick, np, "Warnings given: %lu", wcount);
+ sendnoticetouser(versionscan_nick, np, "Kills sent: %lu", kcount);
+ sendnoticetouser(versionscan_nick, np, "G-Lines set: %lu", gcount);
+ return CMD_OK;
+}
+
+int versionscan_hello(void* sender, int cargc, char** cargv) {
+ nick* np=(nick*)sender;
+
+ if (vsauths) {
+ sendnoticetouser(versionscan_nick, np, "The hello command cannot be used after the first user account has been created.");
+ return CMD_ERROR;
+ }
+
+ vsauths=(vsauthdata*)malloc(sizeof(vsauthdata));
+ strncpy(vsauths->account, np->authname, ACCOUNTLEN);
+ vsauths->flags=VS_STAFF | VS_GLINE | VS_ADMIN;
+ vsauths->next=NULL;
+
+ sendnoticetouser(versionscan_nick, np, "An account has been created for you with the following flags: %s.", versionscan_flagstochar(vsauths->flags));
+ return CMD_OK;
+}
+
+int versionscan_changelev(void* sender, int cargc, char** cargv) {
+ nick* np=(nick*)sender;
+ vsauthdata* v;
+ nick* target;
+ unsigned char flags=0;
+ int i; int plus=1;
+
+ if (cargc < 2) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: changelev <nick> [+|-]<level>");
+ return CMD_ERROR;
+ }
+
+ if (!(target=getnickbynick(cargv[0]))) {
+ sendnoticetouser(versionscan_nick, np, "No such nick.");
+ return CMD_ERROR;
+ }
+
+ if (!IsAccount(target)) {
+ sendnoticetouser(versionscan_nick, np, "%s is not authed.", target->nick);
+ return CMD_ERROR;
+ }
+
+ if ((v=versionscan_getauthbyauth(target->authname))) {
+ i=0;
+ if ((cargv[1][0] == '+') || (cargv[1][0] =='-')) {
+ plus=(cargv[1][0] == '+')?1:0;
+ i++;
+ flags=v->flags;
+ }
+ for (; cargv[1][i]; i++) {
+ switch (cargv[1][i]) {
+ case 'a':
+ flags=(plus)?flags | VS_ADMIN:flags & (~VS_ADMIN);
+ break;
+ case 'g':
+ flags=(plus)?flags | VS_GLINE:flags & (~VS_GLINE);
+ break;
+ case 's':
+ flags=(plus)?flags | VS_STAFF:flags & (~VS_STAFF);
+ break;
+ default:
+ sendnoticetouser(versionscan_nick, np, "Invalid level '%c'.", cargv[1][i]);
+ return CMD_ERROR;
+ break;
+ }
+ }
+ if (!flags) {
+ vsauthdata* pv, *prevv;
+
+ prevv=0;
+ for (pv=vsauths; pv; pv++) {
+ if (pv == v) {
+ if (prevv) {
+ prevv->next=pv->next;
+ free(pv);
+ }
+ else {
+ vsauths=pv->next;
+ free(pv);
+ }
+ }
+ prevv=pv;
+ }
+ }
+ else {
+ v->flags=flags;
+ }
+ sendnoticetouser(versionscan_nick, np, "Done.");
+ return CMD_OK;
+ }
+ else {
+ i=0;
+ if ((cargv[1][0] == '+') || (cargv[1][0] =='-')) {
+ plus=(cargv[1][0] == '+')?1:0;
+ i++;
+ }
+ for (; cargv[1][i]; i++) {
+ switch (cargv[1][i]) {
+ case 'a':
+ flags=(plus)?flags | VS_ADMIN:flags & (~VS_ADMIN);
+ break;
+ case 'g':
+ flags=(plus)?flags | VS_GLINE:flags & (~VS_GLINE);
+ break;
+ case 's':
+ flags=(plus)?flags | VS_STAFF:flags & (~VS_STAFF);
+ break;
+ default:
+ sendnoticetouser(versionscan_nick, np, "Invalid level '%c'.", cargv[1][i]);
+ return CMD_ERROR;
+ break;
+ }
+ }
+ if (flags) {
+ for (v=vsauths; v; v=v->next) {
+ if (!v->next) {
+ v->next=(vsauthdata*)malloc(sizeof(vsauthdata));
+ strncpy(v->next->account, target->authname, ACCOUNTLEN);
+ v->next->flags=flags;
+ v->next->next=0;
+ sendnoticetouser(versionscan_nick, np, "Done.");
+ return CMD_OK;
+ }
+ }
+ sendnoticetouser(versionscan_nick, np, "Error adding user to database.");
+ }
+ else {
+ sendnoticetouser(versionscan_nick, np, "No level specified.");
+ }
+ }
+
+ return CMD_ERROR;
+}
+
+int versionscan_scan(void* sender, int cargc, char** cargv) {
+ nick* np=(nick*)sender;
+ nick* n;
+ channel* cp;
+
+ if (cargc < 1) {
+ sendnoticetouser(versionscan_nick, np, "Syntax: scan <target>");
+ return CMD_ERROR;
+ }
+
+ if (versionscan_mode != VS_SCAN) {
+ sendnoticetouser(versionscan_nick, np, "Scanning of users is currently disabled.");
+ return CMD_ERROR;
+ }
+
+ if (cargv[0][0] == '#') {
+ if ((cp=findchannel(cargv[0]))) {
+ sendmessagetochannel(versionscan_nick, cp, "\001VERSION\001");
+ sendnoticetouser(versionscan_nick, np, "Done.");
+ }
+ else {
+ sendnoticetouser(versionscan_nick, np, "No such channel.");
+ return CMD_ERROR;
+ }
+ }
+ else {
+ if ((n=getnickbynick(cargv[0]))) {
+ if (IsOper(n)) {
+ sendnoticetouser(versionscan_nick, np, "Cannot scan IRC Operators.");
+ return CMD_ERROR;
+ }
+ sendmessagetouser(versionscan_nick, n, "\001VERSION\001");
+ sendnoticetouser(versionscan_nick, np, "Done.");
+ }
+ else {
+ sendnoticetouser(versionscan_nick, np, "No such nick.");
+ return CMD_ERROR;
+ }
+ }
+ return CMD_OK;
+}
+
+int versionscan_modecmd(void* sender, int cargc, char** cargv) {
+ nick* np=(nick*)sender;
+ int oldmode=versionscan_mode;
+
+ if (cargc < 1) {
+ sendnoticetouser(versionscan_nick, np, "Currently running in %s mode.", (versionscan_mode == VS_SCAN)?"SCAN":(versionscan_mode == VS_STAT)?"STATISTICS":"IDLE");
+ return CMD_OK;
+ }
+
+ if (!ircd_strcmp(cargv[0], "idle")) {
+ versionscan_mode=VS_IDLE;
+ sendnoticetouser(versionscan_nick, np, "Now operating in IDLE mode.");
+ }
+ else if (!ircd_strcmp(cargv[0], "scan")) {
+ versionscan_mode=VS_SCAN;
+ sendnoticetouser(versionscan_nick, np, "Now operating in SCAN mode.");
+ }
+ else if (!ircd_strcmp(cargv[0], "stat")) {
+ versionscan_mode=VS_STAT;
+ sendnoticetouser(versionscan_nick, np, "Now operating in STATISTICS mode.");
+ }
+ else {
+ sendnoticetouser(versionscan_nick, np, "Invalid mode of operation.");
+ return CMD_ERROR;
+ }
+
+ if (oldmode == VS_STAT) {
+ vsstatistic* v, *nv;
+
+ for (v=vsstats; v;) {
+ nv=v->next;
+ free(v->reply);
+ free(v);
+ v=nv;
+ }
+ vsstats=0;
+ }
+
+ return CMD_OK;
+}
+
+int versionscan_statistics(void* sender, int cargc, char** cargv) {
+ nick* np=(nick*)sender;
+ vsstatistic* v;
+ long rlimit=0, limit=100;
+
+ if (versionscan_mode != VS_STAT) {
+ sendnoticetouser(versionscan_nick, np, "No statistics are available unless STATISTICS mode of operation is enabled.");
+ return CMD_ERROR;
+ }
+ if (cargc) {
+ limit=atoi(cargv[0]);
+ }
+ if ((limit < 1) || (limit > 500)) {
+ sendnoticetouser(versionscan_nick, np, "Invalid results limit. Valid values are 1-500.");
+ return CMD_ERROR;
+ }
+ sendnoticetouser(versionscan_nick, np, "Reply: [Count]:");
+ for (v=vsstats; (v && (rlimit < limit)); v=v->next) {
+ sendnoticetouser(versionscan_nick, np, "%s [%lu]", v->reply, v->count);
+ rlimit++;
+ }
+ sendnoticetouser(versionscan_nick, np, "End of list - %lu results returned.", rlimit);
+ return CMD_OK;
+}
+
+int versionscan_statsdump(void* sender, int cargc, char** cargv) {
+ nick* np=(nick*)sender;
+ vsstatistic* v;
+ long rlimit=0;
+ FILE *fout;
+
+ if (versionscan_mode != VS_STAT) {
+ sendnoticetouser(versionscan_nick, np, "No statistics are available unless STATISTICS mode of operation is enabled.");
+ return CMD_ERROR;
+ }
+ if (!(fout=fopen("data/versionscanstats","w"))) {
+ sendnoticetouser(versionscan_nick, np, "Unable to open save file.");
+ return CMD_ERROR;
+ }
+ for (v=vsstats; v; v=v->next) {
+ fprintf(fout, "%lu:%s\n", v->count, v->reply);
+ rlimit++;
+ }
+ fclose(fout);
+ sendnoticetouser(versionscan_nick, np, "%lu results saved.", rlimit);
+ return CMD_OK;
+}
+
+int versionscan_broadcast(void* sender, int cargc, char** cargv) {
+ nick* np=(nick*)sender;
+ int force=0;
+
+ if (cargc) {
+ if (strcmp(cargv[0], "-f")) {
+ sendnoticetouser(versionscan_nick, np, "Invalid flag.");
+ return CMD_ERROR;
+ }
+ force=1;
+ }
+
+ if (versionscan_mode != VS_STAT) {
+ if (!force) {
+ sendnoticetouser(versionscan_nick, np, "Statistics collection mode is not currently enabled. Use the 'mode' command to change current mode of operation.");
+ 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.");
+ return CMD_ERROR;
+ }
+ sendnoticetouser(versionscan_nick, np, "Forcing network-wide CTCP version.");
+ }
+
+ irc_send("%s P $* :\001VERSION\001\r\n", longtonumeric(versionscan_nick->numeric, 5));
+ sendnoticetouser(versionscan_nick, np, "Done.");
+
+ return CMD_OK;
+}
+
+void versionscan_newnick(int hooknum, void* arg) {
+ nick* np=(nick*)arg;
+
+ /* ignore opers or auth'd users, helps cut down on spam during a burst */
+ if (!(IsOper(np) || IsAccount(np)) && (versionscan_mode == VS_SCAN)) {
+ sendmessagetouser(versionscan_nick, np, "\001VERSION\001");
+ }
+}
+
+void versionscan_handler(nick* me, int type, void** args) {
+ nick* sender;
+ Command* cmd;
+ char* cargv[50];
+ int cargc;
+ vspattern* v;
+ char* p;
+
+ switch (type) {
+ case LU_PRIVMSG:
+ case LU_SECUREMSG:
+ /* nick */
+ sender=args[0];
+
+ if (!strncmp("\001VERSION", args[1], 8)) {
+ sendnoticetouser(versionscan_nick, sender, "\001VERSION QuakeNet %s v%s.\001", VS_RNDESC, VS_VERSION);
+ return;
+ }
+
+ cargc=splitline((char*)args[1], cargv, 50, 0);
+
+ cmd=findcommandintree(versionscan_commands, cargv[0], 1);
+ if (!cmd) {
+ sendnoticetouser(versionscan_nick, sender, "Unknown command.");
+ return;
+ }
+
+ if ((cmd->level & VS_AUTHED) && !IsAccount(sender)) {
+ sendnoticetouser(versionscan_nick, sender, "Sorry, you need to be authed to use this command.");
+ return;
+ }
+
+ if ((cmd->level & VS_OPER) && !IsOper(sender)) {
+ sendnoticetouser(versionscan_nick, sender, "Sorry, you need to be opered to use this command.");
+ return;
+ }
+
+ if (((cmd->level & VS_STAFF) && !IsVersionscanStaff(sender)) ||
+ ((cmd->level & VS_GLINE) && !IsVersionscanGlineAccess(sender)) ||
+ ((cmd->level & VS_ADMIN) && !IsVersionscanAdmin(sender))) {
+ sendnoticetouser(versionscan_nick, sender, "Sorry, you do not have access to this command.");
+ return;
+ }
+
+ if (cmd->maxparams < (cargc-1)) {
+ /* We need to do some rejoining */
+ rejoinline(cargv[cmd->maxparams], cargc-(cmd->maxparams));
+ cargc=(cmd->maxparams)+1;
+ }
+
+ (cmd->handler)((void*)sender, cargc-1, &(cargv[1]));
+ break;
+ case LU_PRIVNOTICE:
+ sender=args[0];
+
+ if (strncmp("\001VERSION ", args[1], 9)) {
+ break;
+ }
+ if ((p=strchr((char *)args[1] + 9, '\001'))) {
+ *p++='\0';
+ }
+ if (versionscan_mode == VS_SCAN) {
+ if (IsOper(sender)) {
+ break;
+ }
+ for (v=vspatterns; v; v=v->next) {
+ if (match2strings(v->pattern, (char *)args[1] + 9)) {
+ v->hitcount++;
+ hcount++;
+ switch (v->action) {
+ case VS_WARN:
+ sendnoticetouser(versionscan_nick, sender, "%s", v->data);
+ wcount++;
+ break;
+ case VS_KILL:
+ killuser(versionscan_nick, sender, "%s", v->data);
+ kcount++;
+ break;
+ case VS_GLUSER:
+ glinebynick(sender, 3600, v->data, GLINE_ALWAYS_USER, "versionscan");
+ gcount++;
+ break;
+ case VS_GLHOST:
+ glinebynick(sender, 3600, v->data, 0, "versionscan");
+ gcount++;
+ break;
+ default:
+ /* oh dear, something's fucked */
+ break;
+ }
+ break;
+ }
+ }
+ }
+ else if (versionscan_mode == VS_STAT) {
+ versionscan_addstat((char *)args[1] + 9);
+ }
+ break;
+ case LU_KILLED:
+ versionscan_nick=NULL;
+ scheduleoneshot(time(NULL)+1, &versionscan_createfakeuser, NULL);
+ break;
+ }
+}
+
+void versionscan_createfakeuser(void* arg) {
+ channel* cp;
+ char buf[200];
+
+ vsconnect=NULL;
+ sprintf(buf, "%s v%s", VS_RNDESC, VS_VERSION);
+ versionscan_nick=registerlocaluser(VS_NICK, VS_IDENT, VS_HOST, buf, VS_AUTHNAME, UMODE_ACCOUNT | UMODE_DEAF | UMODE_OPER | UMODE_SERVICE, versionscan_handler);
+ if ((cp=findchannel(OPER_CHAN))) {
+ localjoinchannel(versionscan_nick, cp);
+ localgetops(versionscan_nick, cp);
+ } else {
+ localcreatechannel(versionscan_nick, OPER_CHAN);
+ }
+}
+
+void _init() {
+ vspatterns=NULL;
+ vsauths=NULL;
+ vsstats=NULL;
+ versionscan_mode=VS_IDLE;
+
+ versionscan_commands=newcommandtree();
+
+ addcommandtotree(versionscan_commands, "showcommands", VS_AUTHED | VS_STAFF, 0, versionscan_showcommands);
+ addcommandtotree(versionscan_commands, "help", VS_AUTHED | VS_STAFF, 1, versionscan_help);
+ addcommandtotree(versionscan_commands, "hello", VS_AUTHED | VS_OPER, 0, versionscan_hello);
+ addcommandtotree(versionscan_commands, "scan", VS_AUTHED | VS_STAFF, 1, versionscan_scan);
+ addcommandtotree(versionscan_commands, "changelev", VS_AUTHED | VS_OPER | VS_ADMIN, 2, versionscan_changelev);
+ addcommandtotree(versionscan_commands, "listpatterns", VS_AUTHED | VS_STAFF | VS_OPER, 0, versionscan_listpatterns);
+ addcommandtotree(versionscan_commands, "addpattern", VS_AUTHED | VS_STAFF | VS_OPER, 3, versionscan_addpatterncmd);
+ addcommandtotree(versionscan_commands, "delpattern", VS_AUTHED | VS_OPER | VS_ADMIN, 1, versionscan_delpatterncmd);
+ addcommandtotree(versionscan_commands, "status", VS_AUTHED | VS_OPER | VS_ADMIN, 0, versionscan_status);
+ addcommandtotree(versionscan_commands, "mode", VS_AUTHED | VS_OPER | VS_ADMIN, 1, versionscan_modecmd);
+ addcommandtotree(versionscan_commands, "statistics", VS_AUTHED | VS_OPER | VS_STAFF, 1, versionscan_statistics);
+ addcommandtotree(versionscan_commands, "statsdump", VS_AUTHED | VS_OPER | VS_STAFF, 1, versionscan_statsdump);
+ addcommandtotree(versionscan_commands, "broadcast", VS_AUTHED | VS_OPER | VS_ADMIN, 1, versionscan_broadcast);
+ addcommandtotree(versionscan_commands, "whois", VS_AUTHED | VS_STAFF, 1, versionscan_whois);
+
+ registerhook(HOOK_NICK_NEWNICK, &versionscan_newnick);
+
+ vsconnect=scheduleoneshot(time(NULL)+1, &versionscan_createfakeuser, NULL);
+}
+
+void _fini() {
+ void* p, *np;
+
+ deregisterhook(HOOK_NICK_NEWNICK, &versionscan_newnick);
+
+ if (vsconnect) {
+ deleteschedule(vsconnect, &versionscan_createfakeuser, NULL);
+ vsconnect=NULL;
+ }
+
+ if (versionscan_nick) {
+ deregisterlocaluser(versionscan_nick, "Module unloaded.");
+ versionscan_nick=NULL;
+ }
+
+ destroycommandtree(versionscan_commands);
+
+ for (p=vspatterns; p;) {
+ np=((vspattern*)p)->next;
+ free(p);
+ p=np;
+ }
+ for (p=vsauths; p;) {
+ np=((vsauthdata*)p)->next;
+ free(p);
+ p=np;
+ }
+ for (p=vsstats; p;) {
+ np=((vsstatistic*)p)->next;
+ free(((vsstatistic*)p)->reply);
+ free(p);
+ p=np;
+ }
+}