diff -urNd operstats-0.1.5/configure operstats-0.1.6/configure --- operstats-0.1.5/configure Sat Apr 21 19:47:41 2001 +++ operstats-0.1.6/configure Tue May 8 18:27:34 2001 @@ -183,26 +183,28 @@ export ok INPUT -ok=0 -echo "Would you like to read the upgrade notes for 0.1.5?" -while [ $ok -eq 0 ] ; do - echo2 "[Yes] " - if read INPUT ; then : ; else echo "" ; exit 1 ; fi - if [ ! "$INPUT" ] ; then - more doc/UPGRADING - ok=1 - fi - case $INPUT in - [Yy]*) +if [ -f doc/UPGRADING ] ; then + ok=0 + echo "Would you like to read the upgrade notes (Recommended)?" + while [ $ok -eq 0 ] ; do + echo2 "[Yes] " + if read INPUT ; then : ; else echo "" ; exit 1 ; fi + if [ ! "$INPUT" ] ; then more doc/UPGRADING ok=1 - ;; - [Nn]*) - ok=1 - ;; - esac -done -echo "" + fi + case $INPUT in + [Yy]*) + more doc/UPGRADING + ok=1 + ;; + [Nn]*) + ok=1 + ;; + esac + done + echo "" +fi ok=0 echo "Where do you want OperStats to be installed?" diff -urNd operstats-0.1.5/dist/operstats.conf operstats-0.1.6/dist/operstats.conf --- operstats-0.1.5/dist/operstats.conf Sun Apr 29 01:21:51 2001 +++ operstats-0.1.6/dist/operstats.conf Tue May 8 18:25:28 2001 @@ -15,7 +15,7 @@ # Format: Info operstats.server.name Server Description # This is required. -Info operstats.example.net OperStats v0.1.5 +Info operstats.example.net OperStats v0.1.6 # Connection Information: Where should we connect to? # Note: The 'name.of.uplink' is important for sanity checks in JUPE. @@ -45,24 +45,24 @@ #SRA SRARoleNick SRARoleNickPassword # OperServ Information - IRC Operator Service -# Format: OperServ NickName UserName HostName Modes RealName +# Format: OperatorService NickName UserName HostName Modes RealName # Mode suggestions: # UnrealIRCd: +ioS # IRCu : +iok # Other : +io # Comment to disable. -OperServ OperServ service example.net +io IRC Operator Service +OperatorService OperServ service example.net +io IRC Operator Service # StatServ Information - Statistical Service -# Format: StatServ NickName UserName HostName Modes RealName +# Format: StatisticalService NickName UserName HostName Modes RealName # Mode suggestions: # UnrealIRCd: +iS # IRCu : +ik # Other : +i # Comment to disable. -StatServ StatServ service example.net +i Statistical Service +StatisticalService StatServ service example.net +i Statistical Service # GlobalNoticer Information - Global Noticer # Needed by: OS:LOGONMSG, OS:GLOBAL @@ -197,12 +197,16 @@ # Triggers in the DBs override Triggers in the conf, so you will need to # change the Trigger through OperServ to change the limit. (Do this by # simply adding it with the TRIGGER command.) -# Note: If you're doing this for Services you should set this rather high. -# Most Services use the same host for things like enforcers, which may set -# off clone detection. A safe number would be about twice the maximum users -# your network regularily sees. #Trigger *@example.net 500 + +# Should we completely exempt certain hosts from clone detection? If so, +# define those hosts here. These hosts will be immune to all clone +# detection. Triggers set for excepted hosts will have no effect. Use one +# line per exception. The format is: +# Exception user@host + +#Exception *@example.net # Should we date-stamp new LogonMSGs? If this is enabled, LogonMSGs will be # stamped with the date like so: [News - January 1, 1970] diff -urNd operstats-0.1.5/dist/operstats.zone operstats-0.1.6/dist/operstats.zone --- operstats-0.1.5/dist/operstats.zone Wed Dec 31 16:00:00 1969 +++ operstats-0.1.6/dist/operstats.zone Tue May 15 08:18:11 2001 @@ -0,0 +1,74 @@ +IDLW -1200 -43200 International Date Line West +NT -1100 -39600 Nome +HST -1000 -36000 Hawaii Standard +CAT -1000 -36000 Central Alaska +AHST -1000 -36000 Alaska-Hawaii Standard +AKST -0900 -32400 Alaska Standard +YST -0900 -32400 Yukon Standard +HDT -0900 -32400 Hawaii Daylight +AKDT -0800 -28800 Alaska Daylight +YDT -0800 -28800 Yukon Daylight +PST -0800 -28800 Pacific Standard +PDT -0700 -25200 Pacific Daylight +MST -0700 -25200 Mountain Standard +MDT -0600 -21600 Mountain Daylight +CST -0600 -21600 Central Standard +CDT -0500 -18000 Central Daylight +EST -0500 -18000 Eastern Standard +SAT -0400 -14400 Chile +EDT -0400 -14400 Eastern Daylight +AST -0400 -14400 Atlantic Standard +NFT -0330 -12600 Newfoundland +NST -0330 -12600 Newfoundland Standard +GST -0300 -10800 Greenland Standard +ADT -0300 -10800 Atlantic Daylight +BST -0300 -10800 Brazil Standard +NDT -0230 -9000 Newfoundland Daylight +AT -0200 -7200 Azores +WAT -0100 -3600 West Africa +GMT +0000 0 Greenwich Mean +UT +0000 0 Coordinated Universal +UTC +0000 0 Coordinated Universal +WET +0000 0 Western European +WEST +0000 0 Western European +CET +0100 3600 Central European +FWT +0100 3600 French Winter +MET +0100 3600 Middle European +MEZ +0100 3600 Middle European +MEWT +0100 3600 Middle European Winter +SWT +0100 3600 Swedish Winter +BST +0100 3600 British Summer +GB +0100 3600 GMT with Daylight Savings +CEST +0200 7200 Central European Summer +EET +0200 7200 Eastern Europe +FST +0200 7200 French Summer +MEST +0200 7200 Middle European Summer +MESZ +0200 7200 Middle European Summer +SAST +0200 7200 South African Standard +SST +0200 7200 Swedish Summer +EEST +0300 10800 Eastern Europe Summer +BT +0300 10800 Baghdad, USSR Zone 2 +MSK +0300 10800 Moscow +MSD +0300 10800 Moscow Daylight +IT +0330 12600 Iran +ZP4 +0400 14400 USSR Zone 3 +ZP5 +0500 18000 USSR Zone 4 +IST +0530 19800 Indian Standard +ZP6 +0600 21600 USSR Zone 5 +NST +0630 23400 North Sumatra +SST +0700 25200 South Sumatra, USSR Zone 6 +CCT +0800 28800 China Coast +AWST +0800 28800 West Australian Standard +WST +0800 28800 West Australian Standard +PHT +0800 28800 Asia Manila +JST +0900 32400 Japan Standard +ROK +0900 32400 Republic of Korea +CAST +0930 34200 Central Australian Standard +GST +1000 36000 Guam Standard +EAST +1000 36000 Eastern Australian Standard +CADT +1030 37800 Central Australian Daylight +EADT +1100 39600 Eastern Australian Daylight +IDLE +1200 43200 International Date Line East +NZST +1200 43200 New Zealand Standard +NZT +1200 43200 New Zealand +NZDT +1300 46800 New Zealand Daylight diff -urNd operstats-0.1.5/doc/CHANGES operstats-0.1.6/doc/CHANGES --- operstats-0.1.5/doc/CHANGES Sun Apr 29 00:55:00 2001 +++ operstats-0.1.6/doc/CHANGES Mon May 21 20:24:42 2001 @@ -1,3 +1,22 @@ +OperStats -- v0.1.6 - skold +----- + +* Changed conf-directives OperServ and StatServ to OperatorService and + StatisticalService. People who don't bother reading the documentation + kept changing both OperServ's and StatServ's, thus disabling them, then + then asking me why they're disabled. RTFM. +* Added Exception lines. Makes certain hosts immune to clone detection. +* The logfiles are now reopened if closed somehow. (ie, deleting the log) +* 'Sync'd to network' notices now show stats counts instead of real counts. +* TLD function now allows lookups by full name. (ie, TLD canada returns CA) +* TRIGGER can no longer be accessed if clone detection is off. +* Added a CLONES function to list current clones on the network. +* Made several changes to the crontab scripts. - Suggested by Borg +* SS STATS now allows filtering via several tokens. - Suggested by Borg +* Uptime is no longer only visible by IRCOps in STATS. +* IRCds with gimpy version replies (which aren't supported) no longer crash OS. +* Added TimeZone lookup function to StatServ. + OperStats -- v0.1.5 - skold ----- diff -urNd operstats-0.1.5/doc/FAQ operstats-0.1.6/doc/FAQ --- operstats-0.1.5/doc/FAQ Sun Apr 29 01:37:09 2001 +++ operstats-0.1.6/doc/FAQ Mon May 14 08:08:34 2001 @@ -10,6 +10,8 @@ Q: What does the 'Hits' number in STATS mean? Q: I removed a realname AKill, but it's still AKilled on the server. Q: OperStats keeps killing my services. +Q: I'm changing a Trigger in my conf, but it's not changing! +Q: Some of the TimeZones are wrong. -- @@ -75,6 +77,27 @@ already have an AKill in place for your services. If in doubt, rm your operserv.db, double check the trigger in your operstats.conf, and restart them. + +-- + +Q: I'm changing a Trigger in my conf, but it's not changing! + +A: Once you have a Trigger in the conf, it's saved to the operserv.db. + After that, the value in the DB overrides the value in the conf. Thus, + if it was originally 50 in the conf, it's now 50 in the DB. If you + change it to 25 in the conf, the DB's value of 50 overrides it, and it + stays as 50. If you need to change Trigger limits, do so by re-adding + the trigger through OperServ. + +-- + +Q: Some of the TimeZones are wrong. + +A: If you're absolutely sure one is wrong, let me know. If your complaint + is that you get several results for the same TimeZone, the reason for + this is that some TimeZones share the same abbreviation, so rather + than omit all but one of them, all of them are shown. However, I may + still have gotten some wrong, so feel free to point out any problems :) -- diff -urNd operstats-0.1.5/doc/TODO operstats-0.1.6/doc/TODO --- operstats-0.1.5/doc/TODO Sun Apr 29 00:56:49 2001 +++ operstats-0.1.6/doc/TODO Mon May 21 20:25:30 2001 @@ -15,11 +15,6 @@ where these modify the default levels so you dont have to define everything. -* Add flood protection - -* AutoRouting - Attempt X number of reconnects within X time period, waiting X - time period between connects .. - * Spam detection bot (-i, globops if msg'd) * voltage (Joe@AlphaNine.com) reports that OperStats crashes after diff -urNd operstats-0.1.5/doc/UPGRADING operstats-0.1.6/doc/UPGRADING --- operstats-0.1.5/doc/UPGRADING Tue Apr 24 22:49:11 2001 +++ operstats-0.1.6/doc/UPGRADING Tue May 8 18:34:33 2001 @@ -1,11 +1,20 @@ -OperStats 0.1.5 Upgrade notes +OperStats Upgrade notes ----- -If you are upgrading from a previous version of OperStats, there are +If you are upgrading from a version of OperStats before 0.1.5, there are several things to consider: * You will need to remove your statserv.db. The format of this DB has changed since previous versions. + +If you are upgrading from OperStats 0.1.5, you will need to make some +changes to your conf file: + +* The OperServ and StatServ directives have been changed to OperatorService + and StatisticalService. Hence, your lines should now read like this: + + OperatorService OperServ service example.net +io IRC Operator Service + StatisticalService StatServ service example.net +i Statistical Service ----- diff -urNd operstats-0.1.5/inc/config.h operstats-0.1.6/inc/config.h --- operstats-0.1.5/inc/config.h Mon Apr 30 22:06:48 2001 +++ operstats-0.1.6/inc/config.h Mon May 14 02:24:00 2001 @@ -13,6 +13,7 @@ #define LOGFILE "operstats.log" /* Our log file */ #define MOTDFILE "operstats.motd" /* Our MOTD file */ #define TLDFILE "operstats.tld" /* Our TLD listing */ +#define ZONEFILE "operstats.zone" /* Our TimeZone listing */ #define STATSERV_DB "statserv.db" /* StatServ DB */ #define OPERSERV_DB "operserv.db" /* OperServ DB */ #define CHANNELS_IN "os-channels.html" /* channels.html Source */ diff -urNd operstats-0.1.5/inc/extern.h operstats-0.1.6/inc/extern.h --- operstats-0.1.5/inc/extern.h Tue Apr 24 22:14:20 2001 +++ operstats-0.1.6/inc/extern.h Tue May 15 07:23:01 2001 @@ -70,6 +70,8 @@ E void notice_list (const char *source, const char *dest, const char **text); E SRA *findsra (const char *nick); E TLD *findtld (const char *param); +E TLD *findtldname (const char *param); +E Zone *findzone (const char *param); E int is_akilled (const char *mask); E int dotime (const char *s); E char *create_mask (User *u); @@ -78,6 +80,7 @@ E char *strscpy (char *d, const char *s, size_t len); E char *time_ago (time_t event); E char *get_time (time_t event, int fulldate); +E char *zone_time (int offset); E char *stripcodes (char *buffer); E int is_midnight (void); E void dumpchans (void); @@ -85,6 +88,7 @@ E void dumptlds (void); E char *replace (char *string, char *oldpiece, char *newpiece); E char *itoa (int num); +E void flushlists (void); /* process.c */ E ServStat *statlist[1024]; @@ -152,6 +156,7 @@ E AutoKill *akilllist[1024]; E MSG *msglist; E Trigger *triggerlist; +E Exception *exceptionlist; E void operserv (const char *source, char *buf); E int check_akill (const char *nick, const char *user, const char *host, const char *real); E void load_os_dbase (void); @@ -159,11 +164,15 @@ E void expire_akills (void); E Trigger *new_trigger (const char *host, int limit); E Trigger *findtrig (const char *user, const char *host); +E Exception *findexcept (const char *user, const char *host); +E Exception *new_exception (const char *host); /* statserv.c */ E void statserv (const char *source, char *buf); E void load_ss_dbase (void); E void save_ss_dbase (void); E void load_tlds (void); +E void load_zones (void); E void reset_daily_stats (void); E TLD *tldlist; +E Zone *zonelist; diff -urNd operstats-0.1.5/inc/operstats.h operstats-0.1.6/inc/operstats.h --- operstats-0.1.5/inc/operstats.h Tue Apr 24 21:59:31 2001 +++ operstats-0.1.6/inc/operstats.h Mon May 14 08:21:50 2001 @@ -128,11 +128,13 @@ typedef struct channel_ Channel; typedef struct sra_ SRA; typedef struct tld_ TLD; +typedef struct zone_ Zone; typedef struct msg_ MSG; typedef struct servstat_ ServStat; typedef struct akill_ AutoKill; typedef struct clone_ Clone; typedef struct trigger_ Trigger; +typedef struct exception_ Exception; /* User structure: One per user */ struct user_ { @@ -176,6 +178,12 @@ int limit; }; +/* Clone Exceptions */ +struct exception_ { + Exception *next, *prev; + char host[HOSTLEN]; +}; + /* Top-Level-Domain list */ struct tld_ { TLD *next, *prev; @@ -183,6 +191,15 @@ char *desc; /* Text description of TLD */ int cnt; /* Number of clients from TLD */ int hits; /* Daily hits to this TLD */ +}; + +/* TimeZone list */ +struct zone_ { + Zone *next, *prev; + char *name; /* TimeZone Name (ie, PST) */ + char *noffset; /* Named offset (ie, -0800) */ + char *desc; /* Full Description */ + int offset; /* GMT Offset in seconds */ }; /* LogonMSGs */ diff -urNd operstats-0.1.5/inc/os-help.h operstats-0.1.6/inc/os-help.h --- operstats-0.1.5/inc/os-help.h Sun Apr 29 00:53:37 2001 +++ operstats-0.1.6/inc/os-help.h Tue May 8 18:23:44 2001 @@ -34,7 +34,9 @@ " ", "\2JUPE\2 Jupiter a server or nick", "\2AKILL\2 Add, Remove, or List AutoKills", + "\2CLONES\2 List the current clones on the network", "\2TRIGGER\2 Add, Remove, or List Triggers", + "\2EXCEPTION\2 Add, Remove, or List Exceptions", NULL }; @@ -66,6 +68,21 @@ NULL }; +static const char *clones_help[] = +{ + "Syntax: \2CLONES Pattern [Limit]\2", + " ", + "Lists the current clones on the network. Only hostnames matching", + "Pattern will be shown. Use * to show all clones. If you give Limit,", + "only Limit matching hosts will be shown.", + " ", + "Regardless of the given Limit, no more than 250 matches will be shown.", + " ", + "Examples: \2CLONES *hostname.com 25\2", + " \2CLONES *\2", + NULL +}; + static const char *akill_help[] = { "Syntax: \2AKILL ADD|DEL|LIST [Mask|Number|Option]\2", @@ -161,3 +178,18 @@ NULL }; +static const char *exception_help[] = +{ + "Syntax: \2EXCEPTION ADD|DEL|LIST [Host|Number|ALL]", + " ", + "Allows you to add, remove or list Exceptions. An Exception allows", + "the specified host to have total immunity to clone detection.", + "Exceptions also override any Trigger-set limits.", + " ", + "Examples: \2EXCEPTION ADD service@example.net\2", + " \2EXCEPTION DEL 1\2", + " \2EXCEPTION DEL ALL\2", + " \2EXCEPTION DEL service@example.net\2", + " \2EXCEPTION LIST\2", + NULL +}; \ No newline at end of file diff -urNd operstats-0.1.5/inc/response.h operstats-0.1.6/inc/response.h --- operstats-0.1.5/inc/response.h Mon Apr 30 04:37:26 2001 +++ operstats-0.1.6/inc/response.h Mon May 14 09:57:15 2001 @@ -62,6 +62,9 @@ #define OS_LOGONMSG_DELETED "LogonMSG \2#%d\2 has been deleted." #define OS_LOGONMSG_NOT_FOUND "LogonMSG \2#%s\2 was not found." #define OS_ALL_LOGONMSG_DELETED "%d LogonMSGs have been deleted." +#define OS_CLONES_START "*** \2Current Clones List: Showing %d matches\2 ***" +#define OS_CLONES_HEADER "Host Nicknames" +#define OS_CLONES_END "*** \2End of Clones List: %d matches shown\2 ***" #define OS_TRIGGER_FORMAT "Triggers must be in user@host format." #define OS_TRIGGER_ADDED "\2%s\2 has been added to the Trigger list." #define OS_RETRIGGER "\2%s\2 was ReTriggered to \2%d\2." @@ -71,6 +74,15 @@ #define OS_TRIGGER_DELETED "Trigger %s %s has been deleted." #define OS_TRIGGER_NOT_FOUND "No Triggers matching \2%s\2 found." #define OS_ALL_TRIGGER_DELETED "%d Triggers have been deleted." +#define OS_EXCEPTION_FORMAT "Exceptions must be in user@host format." +#define OS_EXCEPTION_ADDED "\2%s\2 has been added to the Exception list." +#define OS_ALREADY_EXCEPT "\2%s\2 is already in the Exception list." +#define OS_EXCEPTION_LIST_START "*** \2Exception List\2 ***" +#define OS_EXCEPTION_LIST "[%d] %s" +#define OS_EXCEPTION_LIST_END "*** \2End of Exceptions\2 ***" +#define OS_EXCEPTION_DELETED "Exception %s %s has been deleted." +#define OS_EXCEPTION_NOT_FOUND "No Exceptions matching \2%s\2 found." +#define OS_EXCEPTIONS_DELETED "%d Exceptions have been deleted." #define OS_DB_SYNC_COMPLETE "DataBase Sync Completed." #define OS_MAX_CLONES "Too many connections from your host" @@ -83,6 +95,8 @@ #define SS_TLDSTATS_START "*** \2TLD Statistics for %s\2 ***" #define SS_TLDSTATS "%s (%s): %d%% (%d hit%s)" #define SS_TLDSTATS_END "*** \2End of TLD Statistics - %d hits in %d TLDs\2 ***" +#define SS_ZONE_IS "It's %s in %s Time (%s, %s)" +#define SS_ZONE_NOT_FOUND "Sorry, I can't find a TimeZone for \2%s\2." #define SS_STATS_HEADER "*** \2Network Statistics\2 ***" #define SS_STATS_CURUSER "Current Users : %d" #define SS_STATS_MAXUSER "Max Users : %d" @@ -107,6 +121,7 @@ #define SS_STATS_DAILY_CHANS "Max Channels : %-5d - %s" #define SS_STATS_DAILY_SERVS "Max Servers : %-5d - %s" #define SS_STATS_FOOTER "*** \2End of Stats\2 ***" +#define SS_BAD_TOKEN "Sorry, I don't know what %s is." #define SS_SERVERS_HEADER "*** \2Servers List\2 ***" #define SS_SERVERS_FOOTER "*** \2End of Servers\2 ***" #define SS_MAP_HEADER "*** \2Server Map\2 ***" diff -urNd operstats-0.1.5/inc/ss-help.h operstats-0.1.6/inc/ss-help.h --- operstats-0.1.5/inc/ss-help.h Sun Apr 29 00:53:38 2001 +++ operstats-0.1.6/inc/ss-help.h Mon May 21 21:59:47 2001 @@ -43,6 +43,12 @@ NULL }; +static const char *ss_help_zone[] = +{ + "\2ZONE\2 Perform a TimeZone lookup", + NULL +}; + static const char *ss_oper_help[] = { "\2SERVERS\2 Show a listing of servers and versions", @@ -60,7 +66,7 @@ static const char *stats_help[] = { - "Syntax: \2STATS\2", + "Syntax: \2STATS [+CMNUD]\2", " ", "Shows various information about the network, such as how many", "users servers and channels there are, how fast the network is", @@ -68,21 +74,45 @@ "shows daily channel, user and server records, and when they were", "set during the day. These stats are reset at midnight, GMT.", " ", - "Example: \2STATS\2", + "If any of the tokens CMNUD are given, the STATS output is filtered", + "to match these tokens. The token string must be preceded by a +.", + "Each token corresponds to a particular part of the full STATS output:", + " C - Show Current Stats (Users, Channels, Servers, Time)", + " M - Show Max Stats (Users, Channels, Servers, Hits, and Times)", + " N - Show NetSpeed Stat", + " U - Show Uptime Stat", + " D - Show Daily Stats (Hits, Users, Channels, Servers)", + " ", + "Examples: \2STATS\2", + " \2STATS +CMNUD\2", NULL }; static const char *stats_help_oper[] = { - "Syntax: \2STATS [Server]\2", + "Syntax: \2STATS [+CMNUD|Server]\2", " ", "Shows various information about the network, such as how many", "users servers and channels there are, how fast the network is", - "running, and max user, server and channel counts. If \2Server\2", - "is provided, statistics on that server are shown.", + "running, and max user, server and channel counts. \2STATS\2 also", + "shows daily channel, user and server records, and when they were", + "set during the day. These stats are reset at midnight, GMT.", + " ", + "If any of the tokens CMNUD are given, the STATS output is filtered", + "to match these tokens. The token string must be preceded by a +.", + "Each token corresponds to a particular part of the full STATS output:", + " C - Show Current Stats (Users, Channels, Servers, Time)", + " M - Show Max Stats (Users, Channels, Servers, Hits, and Times)", + " N - Show NetSpeed Stat", + " U - Show Uptime Stat", + " D - Show Daily Stats (Hits, Users, Channels, Servers)", + " ", + "If you provide a server name, statistics for that server will be", + "shown.", " ", "Examples: \2STATS\2", - " \2STATS server.network.org\2", + " \2STATS +C", + " \2STATS server.*\2", NULL }; @@ -119,6 +149,24 @@ " ", "Examples: \2TLDSTATS\2", " \2TLDSTATS net\2", + NULL +}; + +static const char *zone_help[] = +{ + "Syntax: \2ZONE TimeZone\2", + " ", + "Performs a TimeZone lookup. If the TimeZone is found, the", + "TimeZone name, GMT Offset, and current time will be displayed.", + " ", + "Note that several TimeZones share the same abbreviation, so you", + "may get more than one result.", + " ", + "Also remember Daylight Savings Time; PDT and PST are NOT the", + "same thing! Depending on the time of year, either one may be", + "correct.", + " ", + "Example: \2ZONE GMT\2", NULL }; diff -urNd operstats-0.1.5/misc/crontab operstats-0.1.6/misc/crontab --- operstats-0.1.5/misc/crontab Sun Apr 29 01:02:32 2001 +++ operstats-0.1.6/misc/crontab Sat May 12 03:39:08 2001 @@ -18,43 +18,43 @@ operstats down and seeing if they come back a minute or so later. If they don't, you did something wrong. -* * * * * ~/operstatschk +* * * * * /home/user/operstatschk >/dev/null 2>&1 This will run the backup script every night at midnight. As above, this looks in your home directory. -0 0 * * * ~/backup +0 0 * * * /home/user/backup >/dev/null 2>&1 This will check for the channels.html file, and move it if found. This will run the script to check for it every minute. The channels.html is updated with your DBs (every 20 minutes by default). Don't bother with this one if you don't have OperStats set up to generate a channels list. -* * * * * ~/mvchanlist +* * * * * /home/user/mvchanlist >/dev/null 2>&1 This will check for the tldstats.html file, and move it if found. This will run the script to check for it every minute. The tldstats.html is updated with your DBs (every 20 minutes by default). Don't bother with this if you don't have OperStats set up to generate a tldstats.html file. -* * * * * ~/mvtldstats +* * * * * /home/user/mvtldstats >/dev/null 2>&1 This will check for the stats.js file, and move it if found. This will run the script to check for it every minute. The stats.js is updated with your DBs (every 20 minutes by default). Don't bother with this one if you don't have OperStats set up to generate a stats.js file. -* * * * * ~/mvstats +* * * * * /home/user/mvstats >/dev/null 2>&1 Make sure you've edited the backup and operstatschk files accordingly. To clarify, this is what your crontab should look like: MAILTO="" -* * * * * ~/operstatschk -0 0 * * * ~/backup -* * * * * ~/mvchanlist -* * * * * ~/mvtldstats -* * * * * ~/mvstats +* * * * * /home/user/operstatschk >/dev/null 2>&1 +0 0 * * * /home/user/backup >/dev/null 2>&1 +* * * * * /home/user/mvchanlist >/dev/null 2>&1 +* * * * * /home/user/mvtldstats >/dev/null 2>&1 +* * * * * /home/user/mvstats >/dev/null 2>&1 Now save and exit. It should now be installed and working properly. diff -urNd operstats-0.1.5/misc/makeconf operstats-0.1.6/misc/makeconf --- operstats-0.1.5/misc/makeconf Sun Apr 29 01:22:08 2001 +++ operstats-0.1.6/misc/makeconf Tue May 8 18:27:52 2001 @@ -210,7 +210,7 @@ # Format: Info operstats.server.name Server Description # This is required. -Info $INFONAME OperStats v0.1.5 +Info $INFONAME OperStats v0.1.6 # Connection Information: Where should we connect to? # Note: The 'name.of.uplink' is important for sanity checks in JUPE. @@ -404,12 +404,16 @@ # Triggers in the DBs override Triggers in the conf, so you will need to # change the Trigger through OperServ to change the limit. (Do this by # simply adding it with the TRIGGER command.) -# Note: If you're doing this for Services you should set this rather high. -# Most Services use the same host for things like enforcers, which may set -# off clone detection. A safe number would be about twice the maximum users -# your network regularily sees. #Trigger *@example.net 500 + +# Should we completely exempt certain hosts from clone detection? If so, +# define those hosts here. These hosts will be immune to all clone +# detection. Triggers set for excepted hosts will have no effect. Use one +# line per exception. The format is: +# Exception user@host + +#Exception *@example.net # Should we date-stamp new LogonMSGs? If this is enabled, LogonMSGs will be # stamped with the date like so: [News - January 1, 1970] diff -urNd operstats-0.1.5/src/Makefile operstats-0.1.6/src/Makefile --- operstats-0.1.5/src/Makefile Thu Apr 26 23:46:01 2001 +++ operstats-0.1.6/src/Makefile Tue May 15 08:19:44 2001 @@ -2,7 +2,7 @@ include ../Makefile.inc -VERSION=0.1.5 +VERSION=0.1.6 OBJS=main.o shared.o operserv.o statserv.o process.o socket.o function.o \ server.o conf.o @@ -31,6 +31,9 @@ fi @if [ ! -r $(DEST)/operstats.tld ]; then \ cp ../dist/operstats.tld $(DEST)/operstats.tld; \ + fi + @if [ ! -r $(DEST)/operstats.zone ]; then \ + cp ../dist/operstats.zone $(DEST)/operstats.zone; \ fi @if [ ! -r $(DEST)/operstats.motd ] ; then \ cp ../dist/operstats.motd $(DEST)/operstats.motd; \ diff -urNd operstats-0.1.5/src/conf.c operstats-0.1.6/src/conf.c --- operstats-0.1.5/src/conf.c Thu Apr 26 23:43:51 2001 +++ operstats-0.1.6/src/conf.c Tue May 15 08:02:38 2001 @@ -23,16 +23,10 @@ int wait_restart, maxclones, maxclonekills, lagthreshold; /* Add a new SRA into the sra list. */ -static SRA * new_sra (const char *nick, const char *pass) +static SRA *new_sra (const char *nick, const char *pass) { SRA *sra; - if ((sra = findsra (nick))) /* Don't want dupes, rehash */ - { - sra->pass = sstrdup (pass); - return sra; - } - sra = scalloc (sizeof (SRA), 1); sra->nick = sstrdup (nick); @@ -143,7 +137,7 @@ fatal ("Config: Connect is not set properly: No port."); } - if (!stricmp (item, "OperServ")) + if (!stricmp (item, "OperatorService")) { /* In case the client info changes */ char nick[NICKLEN], user[USERLEN], host[HOSTLEN]; @@ -228,7 +222,7 @@ } } - if (!stricmp (item, "StatServ")) + if (!stricmp (item, "StatisticalService")) { /* In case the client info changes */ char nick[NICKLEN], user[USERLEN], host[HOSTLEN]; @@ -426,7 +420,7 @@ fatal ("Config: Missing password for SRA %s", nick); else new_sra (nick, pass); - } + } if (!stricmp (item, "Trigger")) { @@ -453,6 +447,21 @@ fatal ("Config: Missing limit for Trigger %s", host); else new_trigger (host, limit); + } + + if (!stricmp (item, "Exception")) + { + char *host; + + s = strtok (NULL, " "); + strip (s); + + if (s) + host = s; + else + host = ""; + + new_exception (host); } if (!stricmp (item, "SyncTime")) diff -urNd operstats-0.1.5/src/function.c operstats-0.1.6/src/function.c --- operstats-0.1.5/src/function.c Tue Apr 24 22:50:11 2001 +++ operstats-0.1.6/src/function.c Tue May 15 08:42:47 2001 @@ -49,6 +49,9 @@ tm = *localtime (&t); strftime (buf, sizeof (buf) - 1, "[%d/%m %H:%M:%S] ", &tm); + if (!log_file) + open_log (); + if (log_file) { fputs (buf, log_file); @@ -78,6 +81,9 @@ tm = *localtime (&t); strftime (buf, sizeof (buf) - 1, "[%d/%m %H:%M:%S] ", &tm); + if (!debug_file) + open_debug (); + if (debug_file) { fputs (buf, debug_file); @@ -568,6 +574,23 @@ return timebuf; } +/* Return the time with the given offset. */ +char *zone_time (int offset) +{ + struct tm tm; + static char timebuf[256]; + time_t event; + + event = time (NULL) + offset; + + tm = *gmtime (&event); + + strftime (timebuf, sizeof (timebuf), "%H:%M:%S, %b %d, %Y", &tm); + + timebuf[sizeof(timebuf)-1] = 0; + return timebuf; +} + /* Return the time elapsed since an event */ char *time_ago (time_t event) { @@ -787,6 +810,36 @@ return NULL; } +/* Find a TLD by full name. Return NULL if tld could not be found. */ +TLD *findtldname (const char *param) +{ + TLD *tld; + + if (!param) + return NULL; + + for (tld = tldlist; tld; tld = tld->next) + if (!stricmp (param, tld->desc)) + return tld; + + return NULL; +} + +/* Find a TimeZone. Return NULL if TimeZone could not be found. */ +Zone *findzone (const char *param) +{ + Zone *zone; + + if (!param) + return NULL; + + for (zone = zonelist; zone; zone = zone->next) + if (!stricmp (param, zone->name)) + return zone; + + return NULL; +} + /* Find a server for stats purposes. */ ServStat *findserv (const char *server) { @@ -1252,4 +1305,61 @@ static char ret[32]; sprintf (ret, "%d", num); return ret; +} + +/* Clear all SRAs, TLDs, and TimeZones. */ +void flushlists (void) +{ + SRA *sra; + TLD *tld; + Zone *zone; + + for (sra = sralist; sra; sra = sra->next) + { + free (sra->nick); + free (sra->pass); + + if (sra->prev) + sra->prev->next = sra->next; + else + sralist = sra->next; + + if (sra->next) + sra->next->prev = sra->prev; + } + + free (sra); + + for (tld = tldlist; tld; tld = tld->next) + { + free (tld->name); + free (tld->desc); + + if (tld->prev) + tld->prev->next = tld->next; + else + tldlist = tld->next; + + if (tld->next) + tld->next->prev = tld->prev; + } + + free (tld); + + for (zone = zonelist; zone; zone = zone->next) + { + free (zone->name); + free (zone->noffset); + free (zone->desc); + + if (zone->prev) + zone->prev->next = zone->next; + else + zonelist = zone->next; + + if (zone->next) + zone->next->prev = zone->prev; + } + + free (zone); } diff -urNd operstats-0.1.5/src/main.c operstats-0.1.6/src/main.c --- operstats-0.1.5/src/main.c Tue Apr 24 22:53:16 2001 +++ operstats-0.1.6/src/main.c Thu May 17 15:38:14 2001 @@ -258,7 +258,8 @@ if (statserv_on == TRUE) { load_ss_dbase (); - load_tlds (); +/* load_tlds (); + load_zones (); */ } /* Count our stuff */ diff -urNd operstats-0.1.5/src/operserv.c operstats-0.1.6/src/operserv.c --- operstats-0.1.5/src/operserv.c Sun Apr 29 21:48:20 2001 +++ operstats-0.1.6/src/operserv.c Tue May 15 08:12:20 2001 @@ -14,10 +14,12 @@ AutoKill *akilllist[1024]; MSG *msglist = NULL; Trigger *triggerlist = NULL; +Exception *exceptionlist = NULL; static void do_help (const char *source); static void do_global (const char *source); static void do_jupe (const char *source); +static void do_clones (const char *source); static void do_akill (const char *source); static void do_akill_add (const char *source); static void do_akill_del (const char *source); @@ -30,6 +32,10 @@ static void do_trigger_add (const char *source); static void do_trigger_del (const char *source); static void do_trigger_list (const char *source); +static void do_exception (const char *source); +static void do_exception_add (const char *source); +static void do_exception_del (const char *source); +static void do_exception_list (const char *source); static void sh_auth (const char *source); static void sh_deauth (const char *source); #ifdef RAWINJECT @@ -96,7 +102,7 @@ trigger->next = triggerlist; if (trigger->next) - trigger->next->prev = trigger; + trigger->next->prev = trigger; triggerlist = trigger; @@ -122,9 +128,65 @@ } free (mask); + return NULL; +} + +/* Add a new exception to the exception list */ +Exception *new_exception (const char *host) +{ + Exception *exception; + char *username, *hostname; + + username = sstrdup (host); + hostname = strchr (username, '@'); + + if (!hostname) + return NULL; + + *hostname++ = 0; + + if ((exception = findexcept (username, hostname))) + { + free (username); + return exception; + } + + exception = scalloc (sizeof (Exception), 1); + + strscpy (exception->host, host, HOSTLEN); + + exception->next = exceptionlist; + + if (exception->next) + exception->next->prev = exception; + + exceptionlist = exception; + + free (username); + + return exception; +} + +/* Search for an exception */ +Exception *findexcept (const char *user, const char *host) +{ + Exception *exception; + char *mask; + + mask = smalloc (strlen (user) + strlen (host) + 2); + sprintf (mask, "%s@%s", user, host); + + for (exception = exceptionlist; exception; exception = exception->next) + if (match_wild_nocase (exception->host, mask)) + { + free (mask); + return exception; + } + + free (mask); return NULL; -} +} /* Main OperServ routine. */ void operserv (const char *source, char *buf) @@ -167,8 +229,10 @@ {"HELP", H_IRCOP, do_help}, {"GLOBAL", H_IRCOP, do_global}, {"JUPE", H_IRCOP, do_jupe}, + {"CLONES", H_IRCOP, do_clones}, {"AKILL", H_IRCOP, do_akill}, {"TRIGGER", H_IRCOP, do_trigger}, + {"EXCEPTION", H_IRCOP, do_exception}, {"AUTH", H_IRCOP, sh_auth}, {"DEAUTH", H_SRA, sh_deauth}, {"SHUTDOWN", H_SRA, sh_shutdown}, @@ -194,7 +258,13 @@ if ((command->process == do_global && globalnoticer_on == FALSE) || (command->process == do_logonmsg && - globalnoticer_on == FALSE)) + globalnoticer_on == FALSE) || + (command->process == do_clones && + !maxclones) || + (command->process == do_trigger && + !maxclones) || + (command->process == do_exception && + !maxclones)) { notice (s_OperServ, source, ERR_UNKNOWN_COMMAND, strupper (cmd), s_OperServ); @@ -243,8 +313,10 @@ { {"GLOBAL", H_IRCOP, global_help}, {"JUPE", H_IRCOP, jupe_help}, + {"CLONES", H_IRCOP, clones_help}, {"AKILL", H_IRCOP, akill_help}, {"TRIGGER", H_IRCOP, trigger_help}, + {"EXCEPTION", H_IRCOP, exception_help}, {"AUTH", H_IRCOP, auth_help}, {"DEAUTH", H_SRA, deauth_help}, {"SHUTDOWN", H_SRA, shutdown_help}, @@ -268,7 +340,13 @@ if ((command->process == global_help && globalnoticer_on == FALSE) || (command->process == logonmsg_help && - globalnoticer_on == FALSE)) + globalnoticer_on == FALSE) || + (command->process == clones_help && + !maxclones) || + (command->process == trigger_help && + !maxclones) || + (command->process == exception_help && + !maxclones)) { notice (s_OperServ, source, ERR_NO_HELP, strupper (cmd)); return; @@ -1041,6 +1119,65 @@ notice (s_OperServ, source, OS_LOGONMSG_LIST_END); } +/* Display the list of clones on the network */ +static void do_clones (const char *source) +{ + Clone *clone; + User *user; + char *param = strtok (NULL, " "); + char *limit = strtok (NULL, " "); + int i, j, max = 250, shown = 0; + + if (!param) + { + notice (s_OperServ, source, RPL_SYNTAX, "CLONES Pattern [Limit]"); + notice (s_OperServ, source, ERR_MORE_INFO, s_OperServ, "CLONES"); + return; + } + + if (limit) + { + max = atoi (limit); + + if (max > 250) + max = 250; + } + + notice (s_OperServ, source, OS_CLONES_START, max); + notice (s_OperServ, source, OS_CLONES_HEADER); + + for (i = 0; i < 1024; i++) + { + for (clone = clonelist[i]; clone; clone = clone->next) + { + int shost = 0; + + if (!match_wild_nocase (param, clone->host)) + continue; + + if (clone->cnt < 2) + continue; + + for (j = 0; j < 1024; j++) + { + for (user = userlist[j]; user; user = user->next) + { + /* Very few hosts will go over this.. */ + notice (s_OperServ, source, "%s%-44s %s%s%s%s%s", + shost ? "" : "\2", shost ? "" : clone->host, + user->nick, shost ? "" : " (", + shost ? "" : itoa (clone->cnt), shost ? "" : ")", + shost ? "" : "\2"); + shost = 1; + shown++; + } + } + } + } + + notice (s_OperServ, source, OS_CLONES_END, shown); +} + /* Handle a TRIGGER command */ static void do_trigger (const char *source) { @@ -1211,6 +1348,175 @@ notice (s_OperServ, source, OS_TRIGGER_LIST_END); } +/* Handle a EXCEPTION command */ +static void do_exception (const char *source) +{ + char *cmd = strtok (NULL, " "); + + if (!cmd) + { + notice (s_OperServ, source, RPL_SYNTAX, + "EXCEPTION ADD|DEL|LIST [Host|Number]"); + notice (s_OperServ, source, ERR_MORE_INFO, s_OperServ, "EXCEPTION"); + } + + else + { + Hash_SUB *command, hash_table[] = + { + {"ADD", H_IRCOP, do_exception_add}, + {"DEL", H_IRCOP, do_exception_del}, + {"LIST", H_IRCOP, do_exception_list}, + {NULL} + }; + + if ((command = get_sub_hash (s_OperServ, source, strupper (cmd), + hash_table))) + (*command->process) (source); + else + { + notice (s_OperServ, source, RPL_SYNTAX, + "EXCEPTION ADD|DEL|LIST [Host|Number]"); + notice (s_OperServ, source, ERR_MORE_INFO, s_OperServ, "EXCEPTION"); + } + } +} + +/* Add a exception to the list */ +static void do_exception_add (const char *source) +{ + Exception *exception; + char *mask = strtok (NULL, " "); + char *username, *hostname; + + if (!mask) + { + notice (s_OperServ, source, RPL_SYNTAX, "EXCEPTION ADD Host"); + notice (s_OperServ, source, ERR_MORE_INFO, s_OperServ, "EXCEPTION"); + return; + } + + if (!strchr (mask, '@')) + { + notice (s_OperServ, source, OS_EXCEPTION_FORMAT); + return; + } + + if (!is_sra (source)) + { + int i, nonwild = 0; + + for (i = 0; i < strlen (mask); i++) + if (!(mask[i] == '*' || mask[i] == '?' || mask[i] == '@' || + mask[i] == '.')) + nonwild++; + + if (nonwild < nonwildreq) + { + notice (s_OperServ, source, ERR_TOOMANYWILD, nonwildreq); + return; + } + } + + username = sstrdup (mask); + hostname = strchr (username, '@'); + + if (!hostname) + return; + + *hostname++ = 0; + + if ((exception = findexcept (username, hostname))) + { + notice (s_OperServ, source, OS_ALREADY_EXCEPT, mask); + free (username); + return; + } + + free (username); + + new_exception (mask); + notice (s_OperServ, source, OS_EXCEPTION_ADDED, mask); +} + +/* Remove a exception. */ +static void do_exception_del (const char *source) +{ + Exception *exception; + char *param = strtok (NULL, " "); + int i = 0; + + if (!param) + { + notice (s_OperServ, source, RPL_SYNTAX, "EXCEPTION DEL Number|Host|ALL"); + notice (s_OperServ, source, ERR_MORE_INFO, s_OperServ, "EXCEPTION"); + return; + } + + if (!stricmp (param, "ALL")) + { + for (exception = exceptionlist; exception; exception = exception->next) + { + i++; + + /* Notice them up here so we can show the host */ + notice (s_OperServ, source, OS_EXCEPTIONS_DELETED, + exception->host); + + if (exception->prev) + exception->prev->next = exception->next; + else + exceptionlist = exception->next; + if (exception->next) + exception->next->prev = exception->prev; + } + + free (exception); + return; + } + else + { + for (exception = exceptionlist; exception; exception = exception->next) + { + i++; + if (!stricmp (param, exception->host) || i == atoi (param)) + { + if (exception->prev) + exception->prev->next = exception->next; + else + exceptionlist = exception->next; + if (exception->next) + exception->next->prev = exception->prev; + + free (exception); + if (atoi (param) > 0) + notice (s_OperServ, source, OS_EXCEPTION_DELETED, "#", param); + else + notice (s_OperServ, source, OS_EXCEPTION_DELETED, "on", param); + return; + } + } + } + notice (s_OperServ, source, OS_EXCEPTION_NOT_FOUND, param); +} + +/* List the current exceptions */ +static void do_exception_list (const char *source) +{ + Exception *exception; + int i = 0; + + notice (s_OperServ, source, OS_EXCEPTION_LIST_START); + + for (exception = exceptionlist; exception; exception = exception->next) + { + i++; + notice (s_OperServ, source, OS_EXCEPTION_LIST, i, exception->host); + } + + notice (s_OperServ, source, OS_EXCEPTION_LIST_END); +} + /* Load the OperServ DB from disk */ void load_os_dbase (void) { @@ -1284,6 +1590,15 @@ new_trigger (host, limit); } + + if (!strcmp (item, "EX")) + { + char *host; + + host = strtok (NULL, "\n"); + + new_exception (host); + } } fclose (f); } @@ -1295,6 +1610,7 @@ AutoKill *akill; MSG *msg; Trigger *trigger; + Exception *exception; int i; char backup[2048]; @@ -1338,6 +1654,12 @@ */ for (trigger = triggerlist; trigger; trigger = trigger->next) fprintf (f, "TR %s %d\n", trigger->host, trigger->limit); + + /* Write any Exceptions: One line per exception. Format: + EX host + */ + for (exception = exceptionlist; exception; exception = exception->next) + fprintf (f, "EX %s\n", exception->host); fclose (f); remove (backup); diff -urNd operstats-0.1.5/src/process.c operstats-0.1.6/src/process.c --- operstats-0.1.5/src/process.c Tue Apr 24 22:39:41 2001 +++ operstats-0.1.6/src/process.c Thu May 17 16:12:59 2001 @@ -393,8 +393,16 @@ { if (!stricmp (server->name, source)) { - server->version = sstrdup (av[1]); - server->flags = sstrdup (av[3]); + /* Some jackasses edit their IRCd's version reply, + or run OperStats with unsupported servers. We need + to make sure av[1] and av[3] actually EXIST here, + otherwise we crash. If we DONT find them, they'll + stay as the defaults of 'Unknown' and 'XX'. + */ + if (av[1]) + server->version = sstrdup (av[1]); + if (av[3]) + server->flags = sstrdup (av[3]); } } } @@ -1001,7 +1009,8 @@ { globops (operserv_on == TRUE ? s_OperServ : s_StatServ, "Sync'd to network in %s: %d users, %d channels, %d servers.", - duration (time (NULL) - burststart), usercnt, chancnt, servcnt); + duration (time (NULL) - burststart), userstat, countchans (0), + servstat); } #endif diff -urNd operstats-0.1.5/src/server.c operstats-0.1.6/src/server.c --- operstats-0.1.5/src/server.c Tue Apr 24 22:08:31 2001 +++ operstats-0.1.6/src/server.c Fri May 4 22:36:37 2001 @@ -89,66 +89,75 @@ { Clone *clone; Trigger *trigger; - int limit; + Exception *exception; + int limit, excepted = 0; if (!(clone = findclone (u->host))) clone = new_clone (u->host); clone->cnt++; - /* Check for a trigger for this host */ - if ((trigger = findtrig (u->user, u->host))) - limit = trigger->limit; - else - limit = maxclones; + /* Check if this host is excepted */ + if ((exception = findexcept (u->user, u->host))) + excepted = 1; - if (clone->cnt > limit) + /* Check for a trigger for this host */ + if (!excepted) { - /* If they've broke the max clone limit, akill them */ - if (maxclonekills && clone->kills >= maxclonekills) + if ((trigger = findtrig (u->user, u->host))) + limit = trigger->limit; + else + limit = maxclones; + + if (clone->cnt > limit) { - AutoKill *akill, **list; - char *mask; + /* If they've broke the max clone limit, akill them */ + if (maxclonekills && clone->kills >= maxclonekills) + { + AutoKill *akill, **list; + char *mask; - mask = smalloc (strlen (u->user) + strlen (u->host) + 2); - snprintf (mask, strlen (u->user) + strlen (u->host) + 2, "*@%s", - u->host); + mask = smalloc (strlen (u->user) + strlen (u->host) + 2); + snprintf (mask, strlen (u->user) + strlen (u->host) + 2, + "*@%s", u->host); - /* Ignore it if we already have it. (which we shouldn't) */ - if (is_akilled (mask)) - return; + /* Ignore it if we already have it. (which we shouldn't) */ + if (is_akilled (mask)) + return; - akill = scalloc (sizeof (AutoKill), 1); - akill->mask = sstrdup (mask); - akill->reason = sstrdup (OS_MAX_CLONES); - akill->setter = sstrdup (me.name); - akill->realname = 0; - akill->set = time (NULL); - akill->expires = def_akill_time; - list = &akilllist[AHASH(akill->mask)]; - akill->next = *list; - if (*list) - (*list)->prev = akill; - *list = akill; + akill = scalloc (sizeof (AutoKill), 1); + akill->mask = sstrdup (mask); + akill->reason = sstrdup (OS_MAX_CLONES); + akill->setter = sstrdup (me.name); + akill->realname = 0; + akill->set = time (NULL); + akill->expires = def_akill_time; + list = &akilllist[AHASH(akill->mask)]; + akill->next = *list; + if (*list) + (*list)->prev = akill; + *list = akill; #ifdef IRCUP9 - /* We use 999999999 because we'll expire it ourselves. */ - send_cmd (me.name, "GLINE * +*@%s 999999999 :%s", - u->host, akill->reason); + /* We use 999999999 because we'll expire it ourselves. */ + send_cmd (me.name, "GLINE * +*@%s 999999999 :%s", + u->host, akill->reason); #elif defined (BAHAMUT) - send_cmd (me.name, "AKILL %s * 0 %s %ld :%s", u->host, - s_OperServ, time (NULL), akill->reason); + send_cmd (me.name, "AKILL %s * 0 %s %ld :%s", u->host, + s_OperServ, time (NULL), akill->reason); #else - send_cmd (me.name, "%s %s * :%s", me.token ? "V" : "AKILL", - u->host, akill->reason); + send_cmd (me.name, "%s %s * :%s", me.token ? "V" : "AKILL", + u->host, akill->reason); #endif - free (mask); - } - kill_user (s_OperServ, u->nick, OS_MAX_CLONES); + free (mask); + } - if (maxclonekills) - clone->kills++; + kill_user (s_OperServ, u->nick, OS_MAX_CLONES); + + if (maxclonekills) + clone->kills++; + } } } diff -urNd operstats-0.1.5/src/shared.c operstats-0.1.6/src/shared.c --- operstats-0.1.5/src/shared.c Mon Apr 16 21:46:44 2001 +++ operstats-0.1.6/src/shared.c Thu May 17 16:13:19 2001 @@ -340,6 +340,9 @@ stamplogons_on = FALSE; logupdates_on = FALSE; + /* Flush TLDs, SRAs, and TimeZones (some might be removed) */ + flushlists (); + /* Now re-read. */ load_conf (); @@ -369,7 +372,10 @@ gn.isonline = 0; } - /* Re-read TLDs too */ + /* Re-read StatServ stuff too */ if (statserv_on == TRUE) + { load_tlds (); + load_zones (); + } } diff -urNd operstats-0.1.5/src/statserv.c operstats-0.1.6/src/statserv.c --- operstats-0.1.5/src/statserv.c Mon Apr 30 04:37:11 2001 +++ operstats-0.1.6/src/statserv.c Mon May 21 21:53:25 2001 @@ -12,7 +12,8 @@ #include "../inc/shared-help.h" TLD *tldlist = NULL; -Boolean_T tldlookup = FALSE; +Zone *zonelist = NULL; +Boolean_T tldlookup = FALSE, zonelookup = FALSE; static void do_help (const char *source); static void do_stats (const char *source); @@ -21,6 +22,7 @@ static void do_tld (const char *source); static void do_tldmap (const char *source); static void do_tldstats (const char *source); +static void do_zone (const char *source); static void do_reset (const char *source); static void do_flush (const char *source); static void do_sendpings (const char *source); @@ -78,6 +80,7 @@ {"TLD", H_NONE, do_tld}, {"TLDMAP", H_NONE, do_tldmap}, {"TLDSTATS", H_NONE, do_tldstats}, + {"ZONE", H_NONE, do_zone}, {"MAP", H_IRCOP, do_map}, {"SERVERS", H_IRCOP, do_servers}, {"AUTH", H_IRCOP, sh_auth}, @@ -158,6 +161,8 @@ notice_list (s_StatServ, source, ss_base_help); if (tldlookup == TRUE) notice_list (s_StatServ, source, ss_help_tld); + if (zonelookup == TRUE) + notice_list (s_StatServ, source, ss_help_zone); if (is_oper (source)) notice_list (s_StatServ, source, ss_oper_help); if (operserv_on == FALSE && is_oper (source)) @@ -176,6 +181,7 @@ {"TLD", H_NONE, tld_help}, {"TLDMAP", H_NONE, tldmap_help}, {"TLDSTATS", H_NONE, tldstats_help}, + {"ZONE", H_NONE, zone_help}, {"MAP", H_IRCOP, map_help}, {"SERVERS", H_IRCOP, servers_help}, {"AUTH", H_IRCOP, auth_help}, @@ -199,9 +205,10 @@ if ((command = get_help_hash (s_StatServ, source, strupper (cmd), hash_table))) { - if ((command->process == tld_help || + if (((command->process == tld_help || command->process == tldmap_help || - command->process == tldstats_help) && tldlookup == FALSE) + command->process == tldstats_help) && tldlookup == FALSE) || + ((command->process == zone_help) && zonelookup == FALSE)) { notice (s_StatServ, source, ERR_NO_HELP, strupper (cmd)); return; @@ -239,82 +246,9 @@ /* Show some basic stats. */ static void do_stats (const char *source) { - long uptime; char *param = strtok (NULL, " "); - if (!param || (param && !is_oper (source))) - { - uptime = (time (NULL) - me.since); - - notice (s_StatServ, source, SS_STATS_HEADER); - notice (s_StatServ, source, " "); - notice (s_StatServ, source, SS_STATS_CURUSER, userstat); - notice (s_StatServ, source, SS_STATS_MAXUSER, maxusercnt); - if (is_oper (source)) - notice (s_StatServ, source, SS_STATS_CURCHANOPER, countchans (0), - countchans (1)); - else - notice (s_StatServ, source, SS_STATS_CURCHAN, countchans (0)); - notice (s_StatServ, source, SS_STATS_MAXCHAN, maxchancnt); - notice (s_StatServ, source, SS_STATS_CURSERV, servstat); - notice (s_StatServ, source, SS_STATS_MAXSERV, maxservcnt); - notice (s_StatServ, source, SS_STATS_MAXHITS, maxhitcnt); - - /* If anyone can make this smaller, I'm listening ;) */ - if (speedsample > 1000000000) - notice (s_StatServ, source, SS_STATS_CURSPEEDGB, (float) - speedsample / (float) 1000000000, (float) speedstat / - (float) (speedstat > 1000000000 ? 1000000000 : speedstat > - 1000000 ? 1000000 : speedstat > 1000 ? 1000 : 1), speedstat > - 1000000000 ? "GB" : speedstat > 1000000 ? "MBs" : speedstat > - 1000 ? "KB" : "bytes"); - if (speedsample > 1000000) - notice (s_StatServ, source, SS_STATS_CURSPEEDMB, (float) - speedsample / (float) 1000000, (float) speedstat / - (float) (speedstat > 1000000000 ? 1000000000 : speedstat > - 1000000 ? 1000000 : speedstat > 1000 ? 1000 : 1), speedstat > - 1000000000 ? "GB" : speedstat > 1000000 ? "MB" : speedstat > - 1000 ? "KB" : "bytes"); - else if (speedsample > 1000) - notice (s_StatServ, source, SS_STATS_CURSPEEDKB, (float) - speedsample / (float) 1000, (float) speedstat / - (float) (speedstat > 1000000000 ? 1000000000 : speedstat > - 1000000 ? 1000000 : speedstat > 1000 ? 1000 : 1), speedstat > - 1000000000 ? "GB" : speedstat > 1000000 ? "MB" : speedstat > - 1000 ? "KB" : "bytes"); - else - notice (s_StatServ, source, SS_STATS_CURSPEEDBYTES, speedsample, - (float) speedstat / (float) (speedstat > 1000000000 ? - 1000000000 : speedstat > 1000000 ? 1000000 : speedstat > - 1000 ? 1000 : 1), speedstat > 1000000000 ? "GB" : speedstat - > 1000000 ? "MBs" : speedstat > 1000 ? "KB" : "bytes"); - if (is_oper (source)) - notice (s_StatServ, source, SS_STATS_UPTIME, uptime/86400, - uptime/86400 == 1 ? "" : "s", (uptime/3600) % 24, - (uptime/60) %60, uptime % 60); - notice (s_StatServ, source, SS_STATS_CURTIME, get_time (time (NULL), - 1)); - notice (s_StatServ, source, SS_STATS_MAXUSERTIME, get_time - (maxusertime, 1)); - notice (s_StatServ, source, SS_STATS_MAXCHANTIME, get_time - (maxchantime, 1)); - notice (s_StatServ, source, SS_STATS_MAXSERVTIME, get_time - (maxservtime, 1)); - notice (s_StatServ, source, " "); - notice (s_StatServ, source, SS_STATS_DAILY, get_time (time (NULL), - 0)); - notice (s_StatServ, source, " "); - notice (s_StatServ, source, SS_STATS_DAILY_HITS, dailyhitcnt); - notice (s_StatServ, source, SS_STATS_DAILY_USERS, dailyuserstat, - get_time (dailyusertime, 2)); - notice (s_StatServ, source, SS_STATS_DAILY_CHANS, dailychanstat, - get_time (dailychantime, 2)); - notice (s_StatServ, source, SS_STATS_DAILY_SERVS, dailyservstat, - get_time (dailyservtime, 2)); - notice (s_StatServ, source, " "); - notice (s_StatServ, source, SS_STATS_FOOTER); - } - else + if (param && is_oper (source) && !strchr (param, '+')) { ServStat *serverstat; @@ -362,6 +296,142 @@ notice (s_StatServ, source, " "); notice (s_StatServ, source, SS_STATS_FOOTER); } + else + { + long uptime; + + uptime = (time (NULL) - me.since); + + /* Make sure they're not giving us bogus tokens */ + if (param && (!strchr (param, 'C') && !strchr (param, 'c') && + !strchr (param, 'M') && !strchr (param, 'm') && + !strchr (param, 'N') && !strchr (param, 'n') && + !strchr (param, 'U') && !strchr (param, 'u') && + !strchr (param, 'D') && !strchr (param, 'd'))) + { + notice (s_StatServ, source, SS_BAD_TOKEN, param); + return; + } + + notice (s_StatServ, source, SS_STATS_HEADER); + notice (s_StatServ, source, " "); + + if (!param || (param && strchr (param, 'C')) || + (param && strchr (param, 'c'))) + notice (s_StatServ, source, SS_STATS_CURUSER, userstat); + + if (!param || (param && strchr (param, 'M')) || + (param && strchr (param, 'm'))) + notice (s_StatServ, source, SS_STATS_MAXUSER, maxusercnt); + + if (!param || (param && strchr (param, 'C')) || + (param && strchr (param, 'c'))) + { + if (is_oper (source)) + notice (s_StatServ, source, SS_STATS_CURCHANOPER, + countchans (0), countchans (1)); + else + notice (s_StatServ, source, SS_STATS_CURCHAN, countchans (0)); + } + + if (!param || (param && strchr (param, 'M')) || + (param && strchr (param, 'm'))) + notice (s_StatServ, source, SS_STATS_MAXCHAN, maxchancnt); + + if (!param || (param && strchr (param, 'C')) || + (param && strchr (param, 'c'))) + notice (s_StatServ, source, SS_STATS_CURSERV, servstat); + + if (!param || (param && strchr (param, 'M')) || + (param && strchr (param, 'm'))) + { + notice (s_StatServ, source, SS_STATS_MAXSERV, maxservcnt); + notice (s_StatServ, source, SS_STATS_MAXHITS, maxhitcnt); + } + + if (!param || (param && strchr (param, 'N')) || + (param && strchr (param, 'n'))) + { + /* If anyone can make this smaller, I'm listening ;) */ + if (speedsample > 1000000000) + notice (s_StatServ, source, SS_STATS_CURSPEEDGB, (float) + speedsample / (float) 1000000000, (float) speedstat / + (float) (speedstat > 1000000000 ? 1000000000 : speedstat > + 1000000 ? 1000000 : speedstat > 1000 ? 1000 : 1), + speedstat > 1000000000 ? "GB" : speedstat > 1000000 ? "MBs" + : speedstat > 1000 ? "KB" : "bytes"); + if (speedsample > 1000000) + notice (s_StatServ, source, SS_STATS_CURSPEEDMB, (float) + speedsample / (float) 1000000, (float) speedstat / + (float) (speedstat > 1000000000 ? 1000000000 : speedstat > + 1000000 ? 1000000 : speedstat > 1000 ? 1000 : 1), + speedstat > 1000000000 ? "GB" : speedstat > 1000000 ? "MB" + : speedstat > 1000 ? "KB" : "bytes"); + else if (speedsample > 1000) + notice (s_StatServ, source, SS_STATS_CURSPEEDKB, (float) + speedsample / (float) 1000, (float) speedstat / + (float) (speedstat > 1000000000 ? 1000000000 : speedstat > + 1000000 ? 1000000 : speedstat > 1000 ? 1000 : 1), + speedstat > 1000000000 ? "GB" : speedstat > 1000000 ? "MB" + : speedstat > 1000 ? "KB" : "bytes"); + else + notice (s_StatServ, source, SS_STATS_CURSPEEDBYTES, speedsample, + (float) speedstat / (float) (speedstat > 1000000000 ? + 1000000000 : speedstat > 1000000 ? 1000000 : speedstat > + 1000 ? 1000 : 1), speedstat > 1000000000 ? "GB" : speedstat + > 1000000 ? "MBs" : speedstat > 1000 ? "KB" : "bytes"); + } + + if (!param || (param && strchr (param, 'U')) || + (param && strchr (param, 'u'))) + { + notice (s_StatServ, source, SS_STATS_UPTIME, uptime/86400, + uptime/86400 == 1 ? "" : "s", (uptime/3600) % 24, + (uptime/60) %60, uptime % 60); + } + + if (!param || (param && strchr (param, 'C')) || + (param && strchr (param, 'c'))) + notice (s_StatServ, source, SS_STATS_CURTIME, get_time (time (NULL), + 1)); + + if (!param || (param && strchr (param, 'M')) || + (param && strchr (param, 'm'))) + { + notice (s_StatServ, source, SS_STATS_MAXUSERTIME, get_time + (maxusertime, 1)); + notice (s_StatServ, source, SS_STATS_MAXCHANTIME, get_time + (maxchantime, 1)); + notice (s_StatServ, source, SS_STATS_MAXSERVTIME, get_time + (maxservtime, 1)); + } + + if (!param || (param && strchr (param, 'D')) || + (param && strchr (param, 'd'))) + { + /* We only want this blank line here if theres something else + above. + */ + if (param && (strchr (param, 'C') || strchr (param, 'c') || + strchr (param, 'M') || strchr (param, 'm') || + strchr (param, 'N') || strchr (param, 'n') || + strchr (param, 'U') || strchr (param, 'u'))) + notice (s_StatServ, source, " "); + notice (s_StatServ, source, SS_STATS_DAILY, get_time (time (NULL), + 0)); + notice (s_StatServ, source, " "); + notice (s_StatServ, source, SS_STATS_DAILY_HITS, dailyhitcnt); + notice (s_StatServ, source, SS_STATS_DAILY_USERS, dailyuserstat, + get_time (dailyusertime, 2)); + notice (s_StatServ, source, SS_STATS_DAILY_CHANS, dailychanstat, + get_time (dailychantime, 2)); + notice (s_StatServ, source, SS_STATS_DAILY_SERVS, dailyservstat, + get_time (dailyservtime, 2)); + } + + notice (s_StatServ, source, " "); + notice (s_StatServ, source, SS_STATS_FOOTER); + } } /* Show a listing of servers and their version replies. */ @@ -417,6 +487,9 @@ tld = findtld (param); if (!tld) + tld = findtldname (param); + + if (!tld) { notice (s_StatServ, source, SS_TLD_NOT_FOUND, param); return; @@ -531,6 +604,49 @@ } } +/* Display the current time and/or GMT offset of the given timezone. */ +static void do_zone (const char *source) +{ + Zone *zone; + char *param = strtok (NULL, " "); + int found = 0; + + if (zonelookup == FALSE) + { + notice (s_StatServ, source, ERR_UNKNOWN_COMMAND, "ZONE", s_StatServ); + return; + } + + if (!param) + { + notice (s_StatServ, source, RPL_SYNTAX, "ZONE TimeZone"); + notice (s_StatServ, source, ERR_MORE_INFO, s_StatServ, "ZONE"); + return; + } + + /* Search the TimeZone list, returning matches as they're found. + Note that this doesn't call an external function: Since several + TimeZones may share the same abbreviation, we'll search the list + and return all matches. + */ + for (zone = zonelist; zone; zone = zone->next) + { + if (!stricmp (param, zone->name)) + { + notice (s_StatServ, source, SS_ZONE_IS, zone_time (zone->offset), + zone->desc, zone->name, zone->noffset); + found = 1; + } + } + + /* If we didn't find anything, let them know. */ + if (!found) + { + notice (s_StatServ, source, SS_ZONE_NOT_FOUND, strupper (param)); + return; + } +} + /* Reset a given server's stats */ static void do_reset (const char *source) { @@ -920,12 +1036,6 @@ { TLD *tld; - if ((tld = findtld (name))) /* Don't want dupes, rehash */ - { - tld->desc = sstrdup (desc); - return 0; - } - tld = scalloc (sizeof (TLD), 1); tld->name = sstrdup (name); @@ -981,6 +1091,87 @@ } fclose (f); tldlookup = TRUE; +} + +/* Add a new TimeZone into the timezones list. */ +static Zone *new_zone (const char *name, const char *noffset, + const char *offset, const char *desc) +{ + Zone *zone; + + zone = scalloc (sizeof (Zone), 1); + + zone->name = sstrdup (name); + zone->noffset = sstrdup (noffset); + zone->offset = atoi (offset); + zone->desc = sstrdup (desc); + + zone->next = zonelist; + + if (zone->next) + zone->next->prev = zone; + + zonelist = zone; + + return zone; +} + +/* Load the TimeZones into memory. */ +void load_zones (void) +{ + FILE *f = fopen (ZONEFILE, "r"); + char *s, dBuf[BUFSIZE], *name, *noffset, *offset, *desc; + + log ("Loading %s...", ZONEFILE); + + if (!f) + { + zonelookup = FALSE; + return; + } + + while (fgets (dBuf, 2047, f)) + { + s = strtok (dBuf, " "); + strip (s); + + if (s) + name = s; + else + name = ""; + + s = strtok (NULL, " "); + strip (s); + + if (s) + noffset = s; + else + noffset = ""; + + s = strtok (NULL, " "); + strip (s); + + if (s) + offset = s; + else + offset = ""; + + s = strtok (NULL, ""); + strip (s); + + if (s) + desc = s; + else + desc = ""; + + if (!desc) + log ("Invalid TimeZone %s: Missing data!", name); + else + new_zone (name, noffset, offset, desc); + } + + fclose (f); + zonelookup = TRUE; } /* Ping all servers. */