CONFIGURATION100644 1751 1751 12012 7345731170 12656 0ustar baerchenbaerchen ____ _ _ _ _____ _ _ / ___| | | | / \|_ _|__| |_ __ _| |_ ___ | | | |_| | / _ \ | |/ __| __/ _` | __/ __| | |___| _ |/ ___ \| |\__ \ || (_| | |_\__ \ \____|_| |_/_/ \_\_||___/\__\__,_|\__|___/ 3.0 by Baerchen, September 2001 for eggdrop 1.4.x+ & TCL 8.3 baerchen@germany-chat.net CONFIGURATION ********************************************************************* IMPORTANT: This script was designed for TCL 8.3.x. Don't run it with earlier versions of TCL since it can crash your bot (though I'm not sure about 8.2.x). set cs(workdir) "/usr/home/bla/mybot/putallfileshere/" Directory where CHATstats looks for the files it reads and writes (data files, templates) Leave leading and trailing /'s as shown. Path should not contain any dots "." set cs(trigger) "." This defines what char has to be used in front of a channel command. "" is a valid option. set cs(idle) 300 CHATstats counts people's idle seconds. Set this to what you consider to be idle. Set to 0 to count each and every idle second. Set to a very high value (like 100000000) to virtually disable this feature. set cs(trimlimit) 0 After a time, the array holding the data gets spammed with dozens of users counting only a few words (flyby's). They play only a minor role for the CHATstats and would get deleted at 0600 (bot-time). Set to whatever or to 0 to disable this feature (50 turned out to be a good value for medium-frequency channels) --- set cs(global) { Here we start with the global configuration. Explanation: The global configuration represents the default settings for all channels where CHATstats is enabled. The global config includes all settings the script offers. In opposite, if you need different settings for a channel, you will need to create a channel specific variable that contains only the changed settings. These settings will override the global ones. We'll see later, here's the global config first (note the different notation): post=2 All info can be posted via 0 = Don't post anything, tell users to visit the channel's website 1 = PRIVMSG to the channel 2 = NOTICE to the user 3 = MSG to the user Getting info MSG'ed is very annoying and prevents users from calling info too often while NOTICE seems to be the least spamming way. timebalance=+0 Is your channel German and your bot resides on a server in the US? Then all shown times (e.g. activity stats) refer to the US time, which is probalby not what you want. People would see that there is highest activity in your chnnel at 1500 when it's 2100 in reality. So, you would set timefactor to +6. Vice versa, you would set timefactor to -6. adinterval=0 Want to advertize your website in the channel? Set this to the amount of minutes after which CHATstats informs the chan about the website. Set to 0 to disable. adsite=http://www.yoursitehere.com Set the website to be advertised (url only!) update=60 Defines if and after how many minutes the webpages get updated. Setting this variable to 0 creates no webpage at all. This is needed when the script shall be limited to IRC only. htmsuffix=.htm Set the suffix for the webpages to be created ulmethod=1 0 = do nothing, leave the webpages in $cs(workdir) 1 = move webpages to local folder 2 = upload webpages via FTP If you set ulmethod to 1 (otherwise disregard): localfolder=/usr/home/bla/public_html/subdir/ Set to full path where the files should be moved to. Leave leading and trailing /'s as shown. If you set ulmethod to 2, configure the next 5 variables (otherwise disregard): ftpname=www.myftp.com Set to name of the FTP-server - do not include any subdirectories. ftpport=21 Set the port of the FTP server (usually 21). ftpfolder=/subdir/subdir/subdir/ Set to subdir, where the HTMLs should be FTP'ed to including leading and trailing /'s as shown. Important: Set to nothing if not required. username=username password=password Set username and password for the FTP given above (Note: for security reasons, you should chmod 600 chatstats.tcl) } --- Done. If that's OK for (all) your channel(s), stop here and install. If you need one or more different settings for one or more channels, you need to insert the following into the script: set cs(#channelname) { setting=value } Here you put all settings that are different from the global config. Do not use uppercase letters for #yourchannel. E.g., if #foobar's webpages need to be uploaded to a different server than all other webpages (as given in cs(global)), you would do this: set cs(#example) { ulmethod=2 update=60 ftpname=www.myotherftp.com ftpfolder=/mydir/ username=username2 password=password2 adinterval=120 adsite=http://www.blah.org } Don't forget the {brackets}. They're important! This would advertize http://www.blah.org every 120 minutes. The webpages would get uploaded to www.myotherftp.com/mydir/, the update interval would be 60 minutes. Note that the FTP port is 21 too, so it doesn't need to be repeated. REMEMBER: Do this only for channels that need _different_ settings as given in the global configuration.DESCRIPTION100644 1751 1751 20272 7345731201 12434 0ustar baerchenbaerchen ____ _ _ _ _____ _ _ / ___| | | | / \|_ _|__| |_ __ _| |_ ___ | | | |_| | / _ \ | |/ __| __/ _` | __/ __| | |___| _ |/ ___ \| |\__ \ || (_| | |_\__ \ \____|_| |_/_/ \_\_||___/\__\__,_|\__|___/ 3.0 by Baerchen, September 2001 for eggdrop 1.4.x+ & TCL 8.3 baerchen@germany-chat.net DESCRIPTION ********************************************************************* With some major improvments and additions, this is probably the best version of CHATstats so far. The script gathers a bunch of info about a channel and creates some sort of statistics. In detail it monitors: - amount of joins - words and lines users speak - user's online times - user's idle times - amount of bans (active/passive) - amount of kicks (active/passive) - channel peaks and peak times The script then creates overall stats and rankings for each of the data, e.g. 'Personal stats for baerchen on #germany-chat Joins: 30 Time spent: 22h:25m Idle: 20h:23m -> Active chatting: 2h:2m TopTalkers: Rank 9 - 1949 words/146 lines (avg 13.3). Lutz_MMI is 428 words ahead AllStars: Rank 18 - 1020 words/228 lines (avg 4.4). torkel is 217 words ahead Kicks: 0 Bans: 1 Got kicked: 0 Got banned: 0' and much more. Counting user's spoken words often leads to competition among some of them. At a point, when there seem to be no more changes on the top of the ranking, +nC|C flagged users can do a cycle. I.e. the current TopTalkers ranking will be reset to 0 and their wordcount shoved to some kind of eternal ranking (AllStars). A lot of information about the channel (topic, current users etc.) and the bot (partyline users etc.) can be dumped to HTML files which then can be uploaded to an FTP server (or moved locally). The webpages created don't base on in-script HTML any longer but instead on templates, which means you can use your own HTML code. Also, you can decide which information goes into the webpages and which don't. If you don't want to bother with this, use the supplied templates and go right away. The distinction of the configuration in global and channel-specific settings gives CHATstats full multi-channel capabilities. See "http://www.germany-chat.net -> Bettenauslastung" to get an idea of how it _could_ look like (using the supplied templates). NOTE: CHATstats' v3.0 database is incompatible with earlier versions. Although there is a converting script, I highly recommended to start from the scratch. (Read more in the INSTALLATION file). COMMANDS ********************************************************************* PUB, -|- -------- .show <..> Shitload of options what stats to show PUB, nC|C --------- .change Manipulates users word balances. Two options .merge Merges two users in one .delete Deletes 's account for that channel .cyclestats Cycles the TopTalkers DCC, -|- --------- .help chatstats Shows all CHATstats related commands .help Shows help on a specific CHATstats command DCC, C|C -------- go Enables CHATstats for stop Disables CHATstats for DCC, n|- -------- update Creates webpages immediately chatstats Shows the most important configuration info trim Trims the database manually if necessary wipechan Deletes a channel from the databases back-up Makes a backup of the .dat file recover Read the .backup file to memory For detailled info, install the supplied chatstats.help and read :) NOTES & TRICKS ********************************************************************* - CHATstats ignores all 'Guest' nicks. - Don't forget to .stop and .wipechan when the bot leaves a channel. - Exclude other channel bots from being counted by adding them to the userlist. - This is supposed to be the last version where command names and variable names have hanged. They'll stay constant in the next versions. HISTORY ********************************************************************* 3.0 (major rewrite in order to implement new features) - CHATstats now monitors joins, kicks, bans, online times, idle times, channel peaks, users' spoken words and lines. The distinction between TopTalkers and Allstars has been kept - Introduced templates. Make your own HTML output - Introduced division of configuration in global and channel-specific settings, giving CHATstats full multi-channel capabilities - Added advertizing system. Make CHATstats advertize your website for info purposes - Reintroduced .back-up and .recover - Userlist for the channel-stats is now returned in mIRC-style (ops A-z, voices A-z, others A-z) - URLs in topics are now hyperlinked - Once again, changed commands and their syntax to match new features - Once again, changed variable names for better understanding - Took out some unneccessary variables (who cares for the names of the cachefiles ;-)) 2.11 - Fixed bugs of two non-existing variables that occured under certain circumstances when updating .htm pages. Thanks to LangerT of langersoft.de for heavy debugging ;-) - Fixed two other bugs regarding the creation of the AllStars page. - Fixed bug that after .wipechan'ing a channel, it was not deleted from the configuration array, therefore causing .chatstatus to output inaccurate information. - Fixed rare variable declaration bug in .go - Fixed very rare bug that if the bot was on two channels of which names start equal but end different (e.g. #test and #test1), the AllStars of #test1 were mixed up. Except for this one, integrity of data was _not_ affected by all of the above mentioned bugs. - Rewrote .chatstatus, now more accurate & informative. By doing so, the [lsort] error (see below) was eliminated. - Minor changes to html code - Added DCC commands for go and stop 2.1 - Fixed bug that after cycling stats, TopTalkers were not saved when the array was empty. If no word was spoken until a crash, rehash or restart occured, the Toptalkers had the same wordcount as before cycling - Fixed bug in activity.htm when $timezone and $offset are not set - Cleaned code; some speed and efficacy improvements - Introduced cs(botlogo) and cs(timefactor). See README - Introduced cs(interval): Changed method of updating htmls from a bind to a timer, which means that you can set the intervals more flexible (.restart is highly recommended) - Introduced cs(trigger): you can now define the trigger character for the public commands (.restart is highly recommended) - Fixed nasty bugs that occured when using TCL version < v8.3. There is still one error due to using an [lsort] option that has been implemented in 8.3. However, it's not vital to the script and affects .chatstatus only. I decided to live with this one ;-) 2.0 - Added DCC commands .chatstatus .wipechan and .update - Added configuration of colors and font for HTMLs. Now you can adapt the appearance of the HTMLs to your liking - Added some coloured bar.gifs - Added started/stopped/last reset information to .topten .topstars and HTMLs - Upon request, changed commands for .topten and .topstars to .toptalkers and .allstars (makes sense even ;-) - Upon request, chanstats, toptalkers, botstats and activitystats now update simultaneously every hour - Configuration wasn't saved in regular intervals - fixed - Minor changes to the layout of the HTMLs (merged tables and stuff) - Removed link to activity.htm on chanstats.htm - Deleted .backup and .rollback. Who needs that anyway ;-) - Cosmetic changes to the code. Changed cs(visitwebsite) to cs(nochaninfo) for better understanding - Changed README. A.o., added chapter "POSSIBLE PROBLEMS" - Thanks to |Starman| on this one 1.02 - cs(allowhtml) was not stringtolower'ed - if channels were entered with uppercase letters, it caused the TopTalkers.htm not to show the wordcount. 1.01 - Trying to unbind an unexisting bind caused bot not to start. - Limited host length in chanstats.htm to max. 50 chars in order not to mess up the table when using long hostnames. - After starting, TopStars array was read too early, therefore causing an error. Delayed 10 secs now. 1.0 - First public releaseINSTALLATION100644 1751 1751 24773 7345731207 12572 0ustar baerchenbaerchen ____ _ _ _ _____ _ _ / ___| | | | / \|_ _|__| |_ __ _| |_ ___ | | | |_| | / _ \ | |/ __| __/ _` | __/ __| | |___| _ |/ ___ \| |\__ \ || (_| | |_\__ \ \____|_| |_/_/ \_\_||___/\__\__,_|\__|___/ 3.0 by Baerchen, September 2001 for eggdrop 1.4.x+ & TCL 8.3 baerchen@germany-chat.net INSTALLATION ********************************************************************** - Put chatstats.tcl in your /scripts directory and make an entry in the bot config (e.g. source scripts/chatstats.tcl) Upgraders: ********** CHATstats 3.0 uses a different database than previous versions. If CHATstats finds "csconvertdb.tcl" in the same directory where chatstats.tcl is in, it assumes that you want to have your old databases converted. It will then search for the files cs_toptalkers.dat cs_allstars.dat cs_activity.dat in $cs(workdir) and convert them to the new database format. It is absolutely necessary to delete csconvertdb.tcl before the next rehash or restart takes place, else it would try to convert again. Although the script offers the possibility, I highly recommend _not_ to upgrade the database, but instead to start from the scratch. Some relational stats will appear really messed up. - Put chatstats.help in your /help directory and make an entry in the bot config (e.g. loadhelp chatstats.help) - Put the supplied templates in $cs(workdir) (see configuration) or use your own ones (see the HTML TEMPLATES manual below). - Put redbar.gif in the same directory where the HTMLs are uploaded/moved to. - First time installers: rehash Upgraders: restart (else the bot will go nuts) - Each user except the owner, who is allowed to use the channel commands has to be flagged +C| or |+C (UPPERCASE C) (except for the command "show" which is, of course, open to all users) - Use .go in DCC to start monitoring (even if you upgraded) STOP! If you decided to use the supplied templates, stop reading here. If you want to create your own templates, go on .. HTML TEMPLATES ********************************************************************* In earlier versions of CHATstats, you've had to go with my crappy in-script HTML. With the templates, you _can_ now use your own HTML. Just set up a file in notepad.exe, Frontpage or whatever, insert a few variables and you're done. You can define HOW MUCH of WHAT goes WHERE. Use ten webpages or just one, your choice. Although this seems to be more complicated than to go with predefined in-script HTML, it gives all users the opportunity to freely adapt CHATstats' output to their website's design and therefore a high degree of integration. NAMING A TEMPLATE --------------------------------------------------------------------- All templates have to named like this: blabla.global.template ^--- Never change this part. Must be "template". ^--- This part decides whether the template is used for just one channel or for all channels ^--- whatever you want, e.g. 'toptalkers' to indicate the this is the toptalkers template. The script looks for all files in $cs(workdir) with the suffix '.global.template' and uses them for _all_ channels. If there's one channel that needs a different template, copy the global template, apply the HTML changes, replace ".global." by the channelname (no "#" !) and save it to $cs(workdir). CHATstats will then use this template solely for that channel. There's no need to rehash or restart - just do '.update'. Also, you can add and delete templates from the directoy as you like - CHATstats uses only what it finds and will only complain if it finds no templates at all. Example: You have three channels #foo #bar and #foobar 1. There's only the file toptalkers.global.template: This is used for all three channels #foo, #bar & #foobar 2. Now you add the file toptalkers.foo.template to the directory: This file is used only for channel #foo. #bar and #foobar will still use toptalkers.global.template Don't forget the dots within the filenames. INSERTING PLACEHOLDERS AND VARIABLES --------------------------------------------------------------------- While parsing the templates, the bot needs to know where to put what. For many information, we just have to insert a PLACEHOLDER into the HTML code - like %%CHANNEL would always and everywhere be replaced by the channelname e.g. #foo. Easy. Listings like TopTalkers a.o. work a little bit different. What we just can't do is to insert rank1 toptalker1 wordcount1 percent1 rank2 toptalker2 wordcount2 percent2 rank3 toptalker3 wordcount3 percent3 in the HTML. This would work for three TopTalkers, but not for four. Instead we would type rank toptalker wordcount percent and repeat this incl. the HTML code until our listing is complete. Rank, toptalker, wordcount etc. is what I call VARIABLES. Let's get into this. First, we need to tell CHATstats when a listing starts and ends. We do this by inserting an HTML comment and the type of listing within the comment: x and y are arguments discussed later Then comes the HTML stuff and the needed variables Then we define the end of the listing by These two comments need to be on a line by itself. Never ever add other stuff AVAILABLE LISTINGS ------------------ x = maximum width in pixels of the graphical bar (the script needs to know how long the drawn bar can be at maximum) y = the amount of max. enumerations (you don't want to see all 354 TopTalkers, do you ?) AVAILABLE VARIABLES WITHIN LISTINGS ----------------------------------- !!USER returns a user on the partyline according to 'whom *' !!BOT returns the bot !!USER is on !!CHAN returns the botchannel !!USER is on !!USER returns a channel user according to /names !!HOST returns !!USER's ident@host !!DUR returns !!USER's online time !!IDLE returns !!USER's idle time !!BAN returns one ban from the channel's banlist. You can use this more than once e.g. to put two bans in one row !!TIME1 returns time start range e.g. 00:00 !!TIME2 returns time end range, e.g. 01:00 !!VALUE returns words spoken in time range !!PERCENT returns !!VALUE's percentage in relation to total !!WIDTH returns the current width of the bar x is the maximum width of the bar in pixels, e.g. 250 All starting with "Top" e.g. !!USER returns user's nick (e.g. TopTalkers) !!RANK returns !!USER's ranking !!VALUE returns !!USER's count (joins, words, etc.) !!PERCENT returns !!VALUE's percentual share !!WIDTH returns the current width of the bar x is the maximum width of the bar in pixels, e.g. 250 y is the maximum of returned results, e.g. 10 for 10 TopTalkers e.g. AVAILABLE PLACEHODERS --------------------- Placeholder returns .. %%TOPTALKERSAMOUNT amount of all TopTalkers %%TOPTALKERSWORDS total wordcount of TopTalkers %%TOPTALKERSLINES total linecount of TopTalkers %%TOPTALKERSRATIO TopTalkers' words/line ratio %%ALLSTARSAMOUNT amount of all AllStars %%ALLSTARSWORDS total wordcount of AllStars %%ALLSTARSLINES total linecount of TopTalkers %%ALLSTARSRATIO AllStars' words/line ratio %%TOTALJOINS amount of joins by all users %%TOTALKICKS amount of all kicks the bot has seen %%TOTALBANS amount of all bans the bot has seen %%TOTALONLINE added online time of all users %%TOTALIDLE added idletime of all users %%CHANNEL channel name %%CHANMODES channel modes %%CHANTOPIC channel topic %%CHANTOPSETTER nick who set the topic and date %%CHANUSERS channel's total users %%CHANOPS channel's ops %%CHANVOICES channel's voices %%CHANOTHERS channel's other users %%CHAN%USERS channel's total users percetual share %%CHAN%OPS channel's ops percetual share %%CHAN%VOICES channel's voices percetual share %%CHAN%OTHERS channel's other users percetual share %%TIMEBALANCE time balance according to $cs(timebalance) %%TIMENOW current day of week, date and time %%TIMENEXTUPDATE time of next update %%SCRIPTSTATUS "yes|no" for CHATstats en- or disbaled %%SCRIPTSTARTED date of CHATstats' very first start %%SCRIPTSTOPPED date when CHAtstats was stopped %%SCRIPTCYCLE date of the last cycle %%BOTNICK botnick %%BOTIRCSERVER IRC server bot is connected to %%BOTONLINE time bot is connected to %%BOTIRCSERVER %%BOTNETBOTS list of bots in the botnet delimited by , %%BOTNETSIZE botnet size %%BOTNETUSERS amount of users in the bot channels %%BOTUSERLIST bot's userlist length %%BOTUPLINK bot's uplink %%BOTDOWNLINKS bot's downlinks %%BOTUPTIME bot's uptime %%BOTOFFSET bot's offset %%BOTTIMEZONE bot's timezone EXAMPLES ********************************************************************* 1. You want a listing of all users currently on your channel: Current users in %%CHANNEL
!!USER!!HOST!!DUR!!IDLE
2. Now, you also want to add the TopVisitors to the same webpage: Current users in %%CHANNEL
!!USER!!HOST!!DUR!!IDLE
The TopVisitors are:
People's total online time in %%CHANNEL is %%TOTALONLINE.
!!RANK !!USER !!VALUE !!PERCENT
See, it's not too difficult. To get a better impression, have a look at the templates supplied with the script.botstats.global.template100644 1751 1751 2566 7345731133 15557 0ustar baerchenbaerchen BotStats for %%BOTNICK
BotStats for %%BOTNICK
%%TIMENOW
(Next update %%TIMENEXTUPDATE)
Uptime: %%BOTUPTIME
Connected to: %%BOTIRCSERVER for %%BOTONLINE
Userlist entries: %%BOTUSERLIST
Partyline users: %%BOTNETUSERS

!!USER@!!BOT, chat !!CHAN


Bots linked: %%BOTNETSIZE

%%BOTNETBOTS

Uplinks: %%BOTUPLINK
Downlinks: %%BOTDOWNLINKS
Brought to you by %%BOTNICK

chanstats.global.template100644 1751 1751 7770 7345731137 15712 0ustar baerchenbaerchen Channel Stats for %%CHANNEL
Channel Stats for %%CHANNEL
%%TIMENOW
(Next update %%TIMENEXTUPDATE)
Current channel information

Topic:  %%CHANTOPIC
Set by:  %%CHANTOPSETTER
Modes:  %%CHANMODES
Banlist:  !!BAN
Users:  Total: %%CHANUSERS (%%CHAN%USERS)
Opped: %%CHANOPS (%%CHAN%OPS) Voiced: %%CHANVOICES (%%CHAN%VOICES) Others: %%CHANOTHERS (%%CHAN%OTHERS)


Nick Ident@Host Online Idle
. . . .
!!USER !!HOST !!DUR !!IDLE


Overall activity statistics


The graph is an activity indicator for %%CHANNEL. It shows how many words are spoken within a certain timerange of the day. The bot is in timezone %%BOTTIMEZONE with offset %%BOTOFFSET. Time correction: %%TIMEBALANCE

Timerange Words
. .
!!TIME1-!!TIME2 !!VALUE (!!PERCENT)

Total: %%TWORDS words (100%) since %%SCRIPTSTARTED
Brought to you by %%BOTNICK

chatstats.help100644 1751 1751 10247 7345731144 13605 0ustar baerchenbaerchen%{help=chatstats} You can get help on individual commands: .help CHANNEL COMMANDS %bshow%b %{+C|+C} %bchange cyclestats delete merge%b %{+n} DCC COMMANDS %bgo stop update chatstatus%b %btrim wipechan back-up recover%b %{help=show} ### %bshow %bshow %b %bshow chan PUB -|- In the first form, it show the caller's stats or, if ?nick? is given, nick's stats. In the second form, it shows the current TopTen of the type of stats submitted In the third form, it shows all stats of form two on a channel basis %{help=go}%{+Cn|+C} ### %bgo%b DCC C|C Enables monitoring for . This does not toggle the creation of the webpages for that channel. To change this, you have to set the variable cs(allowhtml) within the chatstats.tcl itself. See also: stop %{help=stop}%{+Cn|+C} ### %bstop%b DCC C|C Disables monitoring for . All other commands remain available. When you use this after the bot has left a channel, you might also want to use .wipechan in order to completely erase the channel from all databases. Don't do this if you plan to re-.go one day :) %bstop%b does not toggle the creation of the webpages for that channel. To change this, you have to set the variable cs(allowhtml) within the chatstats.tcl itself. See also: go %{help=change}%{+Cn|+C} ### %bchange%b toptalker|allstar <+|-amount> PUB C|C There are two forms: change toptalker <+|-amount> Adds or substracts to/from 's TopTalker balance. Make sure you include the plus or minus change allstar <+|-amount> Adds or substracts to/from 's AllStar balance. Make sure you include the plus or minus Note that this command only affects the TopTalker and AllStar balance of a user, while 'merge' and 'delete' affect the whole data set. See also: merge delete %{help=merge}%{+Cn|+C} ### %bmerge%b PUB C|C Merges two users in one for the referring chanel, where the first nick is the source and the second nick is the destination. It then deletes the first nick. Example: merge foo bar Merges foo in bar and deletes foo. Note that this command affects the whole dataset, not only the TopTalker or AllStar balance. See also: change delete %{help=delete}%{+Cn|+C} ### %bdelete%b PUB C|C Deletes from the database for the referring channel. Note that this command affects the whole dataset, not only the TopTalker or AllStar balance. See also: change merge %{help=chatstatus}%{+n} ### %bchatstatus%b DCC n|- Displays various info about the script and its configuration. It also tries to figure out orphaned entries in the database. Orphaned entries result from the bot leaving a channel without being .wipechan'ed properly. %{help=trim}%{+n} ### %btrim%b DCC n|- _All_ TopTalkers with less than words will be deleted from the database immediately. This is useful if you set the trimlimit to 0 and the database has become spammed with flyby's over the time. Note that this command is not limited to one channel %{help=update}%{+n} ### %bupdate%b% [channel] DCC n|- If no channel is given as argument, the webpages for all channels which are configured to have webpages generated for, will be updated. If [channel] is given, only [channel] will be updated. %{help=wipechan}%{+n} ### %bwipechan%b DCC n|- Once you stop monitoring a channel, you might want to delete the referring data of this channel in the databases. No syntax check is done here, so this command relies on a correct input. In opposite to earlier versions of CHATstats, should _not_ be abbreviated. %{help=back-up}%{+n} ### %bback-up%b DCC n|- Makes a backup of the database. See also: recover %{help=recover}%{+n} ### %brecover%b DCC n|- Reads the backed up database file back to memory. No rehash or restart required. See also: back-up chatstats.tcl100644 1751 1751 124151 7345731161 13456 0ustar baerchenbaerchen# ____ _ _ _ _____ _ _ # / ___| | | | / \|_ _|__| |_ __ _| |_ ___ # | | | |_| | / _ \ | |/ __| __/ _` | __/ __| # | |___| _ |/ ___ \| |\__ \ || (_| | |_\__ \ # \____|_| |_/_/ \_\_||___/\__\__,_|\__|___/ # 3.0 by Baerchen, September 2001 # for eggdrop 1.4.x+ & TCL 8.3 # baerchen@germany-chat.net # # Read DESCRIPTION, CONFIGURATION & INSTALLATION. # _Before_ complaining about bugs, make sure you have read all manuals. # # CONFIGURATION set cs(workdir) "/usr/home/bla/mybot/putallfileshere/" set cs(trigger) "." set cs(idle) 300 set cs(trimlimit) 0 set cs(global) { post=2 timebalance=+0 adinterval=0 adsite=http://www.yoursitehere.com htmsuffix=.htm update=60 ulmethod=1 localfolder=/usr/home/bla/public_html/subdir/ ftpname=www.myftp.com ftpport=21 ftpfolder=/subdir/subdir/subdir/ username=username password=password } # CODEBASE bind pub - ${cs(trigger)}show cs:show bind pub nC|C ${cs(trigger)}change cs:change bind pub nC|C ${cs(trigger)}merge cs:merge bind pub nC|C ${cs(trigger)}delete cs:delete bind pub nC|C ${cs(trigger)}cyclestats cs:cycle bind dcc nC|C go cs:go bind dcc nC|C stop cs:stop bind dcc n trim cs:trim bind dcc n update cs:update bind dcc n wipechan cs:wipechan bind dcc n chatstats cs:status bind dcc n back-up cs:backup bind dcc n recover cs:recover bind time - "18 * * * *" cs:autosave bind time - "00 06 * * *" cs:autotrim set cs(ver) "CHATstats 3.0 by Baerchen" proc cs:ini {} { global cs csa csc csu numversion putlog "TCL LOADED: $cs(ver)" foreach e [timers] {if {[string match *cs:* $e]} {killtimer [lindex $e 2]}} array set csa ""; array set csc ""; array set csu "" if {![file isdirectory $cs(workdir)]} {file mkdir $cs(workdir)} if {![file exists $cs(workdir)CHATstats.dat]} { set fid [open $cs(workdir)CHATstats.dat w] puts $fid "CHATstats datafile v3.0\n--UserData--\n--ChannelData--\n--ActivityData--" close $fid } cs:read if {[file exists scripts/csconvertdb.tcl]} { source scripts/csconvertdb.tcl putlog " Found csconvertdb.tcl, converting database .." cs:convertdb } foreach e [array names csc] { cs:changevars $e if {[lindex $csc($e) 0] == "yes"} { bind pubm - "$e *" cs:count; bind topc - "$e *" cs:topic; bind nick - "$e *" cs:nick bind join - "$e *" cs:join; bind rejn - "$e *" cs:join ; bind kick - "$e *" cs:kick bind mode - "$e +b" cs:ban; bind splt - "$e *" cs:partquit; bind sign - "$e *" cs:partquit2 bind raw - PART cs:rawpart if {$numversion >= 1050000} {bind part - "$e *" cs:partquit2} else {bind part - "$e *" cs:partquit} if {$cs(update)} { timer $cs(update) "cs:html $e" if {$cs(adinterval)} {timer $cs(adinterval) "cs:advertize $e"} } } } set cs(ftperror) [catch {set cs(ftpclient) [exec which ftp]}] if {$cs(ftperror)} { if {[file executable /usr/bin/ftp]} {set cs(ftpclient) "/usr/bin/ftp"; set cs(ftperror) 0} if {[file executable /bin/ftp]} {set cs(ftpclient) "/bin/ftp"; set cs(ftperror) 0} } if {$cs(ftperror)} {putlog " Error configuring FTP client."} cs:save; set cs(rehash) 1 } proc cs:go {h idx a} { global botnick cs csa csc csu numversion set c [string tolower $a] if {![validchan $c] || ![botonchan $c]} {putdcc $idx "CHATstats: I'm not on $a."; return} if {[lsearch -exact [bind pubm - "$c *"] cs:count] == -1} { bind pubm - "$c *" cs:count; bind topc - "$c *" cs:topic; bind nick - "$c *" cs:nick bind join - "$c *" cs:join; bind rejn - "$c *" cs:join ; bind kick - "$c *" cs:kick bind mode - "$c +b" cs:ban; bind splt - "$c *" cs:partquit; bind sign - "$c *" cs:partquit2 bind raw - PART cs:rawpart if {$numversion >= 1050000} {bind part - "$c *" cs:partquit2} else {bind part - "$c *" cs:partquit} } else {putdcc $idx "CHATstats is already enabled for $c."; return} if {![info exists csa(00$c)]} { foreach e "00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23" {set csa($e$c) 0} set csa(24$c) 1 } if {![info exists csc($c)]} {set csc($c) "yes [unixtime] 0 0 [llength [chanlist $c]] [unixtime]"} else { set csc($c) [lreplace $csc($c) 0 0 "yes"]; set csc($c) [lreplace $csc($c) 2 2 0] if {[lindex $csc($c) 1] == 0} {set csc($c) [lreplace $csc($c) 1 1 [unixtime]]} } foreach e [chanlist $c] { if {([matchattr $e b]) || ($e == $botnick) || [string match -nocase "guest*" $e]} {continue} set el [cs:filter [string tolower $e]] if {[info exists csu($el$c)]} { set csu($el$c) [lreplace $csu($el$c) 0 0 [cs:filter $e]]; set csu($el$c) [lreplace $csu($el$c) 1 1 [unixtime]] } else {set csu($el$c) "[cs:filter $e] [unixtime] 1 0 0 0 0 0 0 0 0 0 0 0"} } cs:checkpeak $c; cs:save; putdcc $idx "CHATstats enabled for $c"; putlog "CHATstats enabled for $c ($h)."; cs:changevars $c if {$cs(update)} { timer $cs(update) "cs:html $c" if {$cs(adinterval)} {timer $cs(adinterval) "cs:advertize $c"} } } proc cs:stop {h idx a} { global cs csc numversion set c [string tolower $a] if {[lsearch -exact [bind pubm - "$c *"] cs:count] == -1} {putdcc $idx "CHATstats is not enabled for $c."; return} unbind pubm - "$c *" cs:count; unbind topc - "$c *" cs:topic; unbind nick - "$c *" cs:nick unbind join - "$c *" cs:join; unbind rejn - "$c *" cs:join ; unbind kick - "$c *" cs:kick unbind mode - "$c +b" cs:ban; unbind splt - "$c *" cs:partquit; unbind sign - "$c *" cs:partquit2 if {$numversion >= 1050000} {unbind part - "$c *" cs:partquit2} else {unbind part - "$c *" cs:partquit} if {[info exists csc($c)]} {set csc($c) [lreplace $csc($c) 0 0 "no"]; set csc($c) [lreplace $csc($c) 2 2 [unixtime]]} foreach e [array names csu] {if {[string match *$c $e]} {cs:reset $e}} cs:save; cs:changevars $c; if {$cs(update)} {cs:html $c} foreach e [timers] {if {[string match *cs:*$c* $e]} {killtimer [lindex $e 2]}} putdcc $idx "CHATstats disabled for $c. Channel commands still available (except $cs(trigger)show)." putlog "CHATstats disabled for $c ($h)." } proc cs:join {n uh h c} { global cs csu botnick set ni [string tolower [cs:filter $n]]; set c [string tolower $c]; set j [llength [chanlist $c]] if {$n == $botnick} {bind raw - 353 cs:rawjoin; return} if {[matchattr $n b] || [string match -nocase "guest*" $n]} {return} if {[info exists csu($ni$c)]} { set csu($ni$c) [lreplace $csu($ni$c) 0 0 [cs:filter $n]]; set csu($ni$c) [lreplace $csu($ni$c) 1 1 [unixtime]] set csu($ni$c) [lreplace $csu($ni$c) 2 2 [expr [lindex $csu($ni$c) 2] + 1]] } else {set csu($ni$c) "[cs:filter $n] [unixtime] 1 0 0 0 0 0 0 0 0 0 0 0"} cs:checkpeak $c } proc cs:rawjoin {f k a} { global botnick cs csc csu set c [string tolower [lindex $a 2]]; set clist [lindex [split $a :] 1] foreach e $clist { set e [string trimleft $e "%+@"] if {[matchattr $e b] || ($e == $botnick) || [string match -nocase "guest*" $e]} {continue} set el [cs:filter [string tolower $e]] if {[info exists csu($el$c)]} { set csu($el$c) [lreplace $csu($el$c) 0 0 [cs:filter $e]]; set csu($el$c) [lreplace $csu($el$c) 1 1 [unixtime]] } else {set csu($el$c) "[cs:filter $e] [unixtime] 1 0 0 0 0 0 0 0 0 0 0 0"} } return 0 } proc cs:count {n uh h c t} { global botnick cs csa csu if {([matchattr $n b]) || ($n == $botnick) || [string match -nocase "guest*" $n]} {return} set ni [cs:filter [string tolower $n]]; set c [string tolower $c] set t [llength [split $t]]; set u [unixtime] if {[info exists csu($ni$c)]} { set csu($ni$c) [lreplace $csu($ni$c) 4 4 [expr [lindex $csu($ni$c) 4] + $t]] set csu($ni$c) [lreplace $csu($ni$c) 5 5 [expr [lindex $csu($ni$c) 5] + 1]] set ls [lindex $csu($ni$c) 12]; set idle [expr $u - $ls] if {($ls > 0) && ($idle > $cs(idle))} { set csu($ni$c) [lreplace $csu($ni$c) 13 13 [expr [lindex $csu($ni$c) 13] + $idle]] set csu($ni$c) [lreplace $csu($ni$c) 12 12 $u] } else {set csu($ni$c) [lreplace $csu($ni$c) 12 12 $u]} } else {set csu($ni$c) "[cs:filter $n] $u 1 0 $t 1 0 0 0 0 0 0 $u 0"} cs:changevars $c; incr csa([strftime "%H" $u]$c) $t } proc cs:nick {n uh h c ne} { set c [string tolower $c] cs:join $ne $uh $h $c; cs:partquit2 $n $uh $h $c "" } proc cs:kick {n uh h c t r} { global csu if {$n == "" } {return} set ni [string tolower [cs:filter $n]]; set c [string tolower $c] if {[info exists csu($ni$c)]} {set csu($ni$c) [lreplace $csu($ni$c) 8 8 [expr [lindex $csu($ni$c) 8] + 1]]} set ta [string tolower [cs:filter $t]] if {[info exists csu($ta$c)]} {cs:reset $ta$c; set csu($ta$c) [lreplace $csu($ta$c) 10 10 [expr [lindex $csu($ta$c) 10] + 1]]} } proc cs:ban {n uh h c mc v} { global cs csu if {$n == "" } {return}; set ni [string tolower [cs:filter $n]]; set c [string tolower $c] if {[info exists csu($ni$c)]} {set csu($ni$c) [lreplace $csu($ni$c) 9 9 [expr [lindex $csu($ni$c) 9] + 1]]} foreach e [chanlist $c] { if {[string match -nocase $v $e![getchanhost $e $c]]} { set vi [string tolower [cs:filter $e]] if {[info exists csu($vi$c)]} {set csu($vi$c) [lreplace $csu($vi$c) 11 11 [expr [lindex $csu($vi$c) 11] + 1]]} } } } proc cs:partquit {n uh h c} {cs:partquit2 $n $uh $h $c ""} proc cs:partquit2 {n uh h c t} { global csu set ni [cs:filter [string tolower $n]]; set c [string tolower $c]; if {[info exists csu($ni$c)]} {cs:reset $ni$c} } proc cs:rawpart {f k a} { global botnick csc csu if {[lindex [split $f "!"] 0] == $botnick} { set c [string tolower $a]; foreach e [array names csu] {if {[string match *$c $e]} {cs:reset $e}} } cs:save; return 0 } proc cs:show {n uh h c a} { global cs csc csu botnick set c [string tolower $c]; cs:changevars $c if {$cs(post) == 0} {puthelp "PRIVMSG $c: Stats not available. Go visit ${c}'s website $cs(adsite)."; return} if {![info exists csc($c)]} {return} set a [cs:filter $a]; set what [string tolower [lindex $a 0]]; set who [lindex $a 1] if {$who == ""} {set who [cs:filter $n]} switch -exact $what { channel {set o "CHATstats for 04$c\n"; append o [cs:prep 0 1 $c ""]} joins {set o "Top Joiners of 04$c\n"; append o [cs:prep 1 2 $c ""]} visitors {set o "Top Visitors of 04$c\n"; append o [cs:prep 2 3 $c ""]} toptalkers {set o "Top Talkers of 04$c\n"; append o [cs:prep 1 4 $c ""]} stats {set o ""; append o [cs:prep 3 4 $c $who]} allstars {set o "Top AllStars of 04$c\n"; append o [cs:prep 1 6 $c ""]} kickers {set o "Top Kickers of 04$c\n"; append o [cs:prep 1 8 $c ""]} banners {set o "Top Banners of 04$c\n"; append o [cs:prep 1 9 $c ""]} kicked {set o "Most famous victims of 04$c (Kicks)\n"; append o [cs:prep 1 10 $c ""]} banned {set o "Most famous victims of 04$c (Bans)\n"; append o [cs:prep 1 11 $c ""]} idlers {set o "Top Idlers of 04$c\n"; append o [cs:prep 2 13 $c ""]} titties {set o "Hehe, I wish I had .."} default { puthelp "NOTICE $n :Usage: $cs(trigger)show " puthelp "NOTICE $n : e.g. $cs(trigger)show stats WhoEver or $cs(trigger)show channel" return } } set o [split $o "\n"] switch -exact $cs(post) { 1 {foreach e $o {puthelp "PRIVMSG $c :[cs:defilter $e]"}} 2 {foreach e $o {puthelp "NOTICE $n :[cs:defilter $e]"}} 3 {foreach e $o {puthelp "PRIVMSG $n :[cs:defilter $e]"}} } } proc cs:prep {type sortfor c who} { global cs csc csu if {$type == 0} { foreach e "i j t wc wl k ku b bu id" {set $e 0} foreach e [array names csu] { if {[string match *$c $e]} { incr i; incr j [lindex $csu($e) 2]; incr t [lindex $csu($e) 3]; incr wc [expr [lindex $csu($e) 4] + [lindex $csu($e) 6]] incr wl [expr [lindex $csu($e) 5] + [lindex $csu($e) 7]]; incr k [lindex $csu($e) 8]; incr b [lindex $csu($e) 10]; incr id [lindex $csu($e) 13] } } if {$i == 0} {append o "Apparently, $c has no users. Try again later"; return $o} if {$k != 0} {set insert ", one kick every [cs:duration [expr $t/$k]])."} else {set insert ")."} regexp {\d{1,10}\..{2}} [expr $k/$i.0] ku; regexp {\d{1,10}\..{2}} [expr $b/$i.0] bu append o "Monitoring: [lindex $csc($c) 0] Started: [cs:date $c sta] Stopped: [cs:date $c sto] Last cycle: [cs:date $c lr]\n" append o "Channel peak: [lindex $csc($c) 4] users on [cs:date $c peak]\n" append o "I've seen [cs:format $i] people joining [cs:format $j] times wasting [cs:duration $t].\n" append o "Their idletimes add up to [cs:duration $id] leaving [cs:duration [expr $t - $id]] of active chatting.\n" if {$wl > 0} { regexp {\d{1,10}\..{1}} [expr $wc/$wl.0] wla append o "All in all, people have spoken [cs:format $wc] words on [cs:format $wl] lines (avg $wla).\n" } append o "I count [cs:format $k] kicks/[cs:format $b] bans ($ku kicks/$bu bans per user$insert" return $o } set l "" foreach e [array names csu] {if {[string match *$c $e]} {lappend l "[lindex $csu($e) 0] [lindex $csu($e) $sortfor]"}} if {$l != ""} {set l [lsort -integer -decreasing -index 1 $l]} else {return "Insufficient data, please try again later"} if {$type == 1 || $type == 2} { for {set i 0} {$i<=9} {incr i} { set n [lindex [lindex $l $i] 0]; set r [lindex [lindex $l $i] 1] if {$n == "" || $r == 0} {append o "04[expr $i + 1]. N/A "; continue} if {$type == 2} { if {$r < 3600} { set r [expr $r/60.0]; regexp {\d{1,10}\..{1}} $r r; set r "$r mins"} else { set r [expr $r/3600.0]; regexp {\d{1,10}\..{1}} $r r; set r "$r hrs" } } append o "04[expr $i + 1]. $n $r " } return $o } if {$type == 3} { set w [string tolower $who] if {![info exists csu($w$c)]} {return "No record about $who"} if {[onchan $who $c]} { set ts [expr [lindex $csu($w$c) 3] + ([unixtime] - [lindex $csu($w$c) 1]) ]} else { set ts [lindex $csu($w$c) 3] } set rc [expr [lsearch [string tolower $l] $w*] + 1]; set insert1 ""; set insert2 ""; ; set insert3 "" set cw [lindex $csu($w$c) 4]; set aw [lindex $csu($w$c) 6] if {$ts == 0} {set ts "N/A"} else {set insert3 "-> Active chatting: [cs:duration [expr $ts - [lindex $csu($w$c) 13]]]"; set ts "[cs:duration $ts] "} if {$cw > 0} { regexp {\d{1,3}\..{1}} [expr $cw.0/[lindex $csu($w$c) 5]] cwavg if {$rc > 1} { set rcp [expr $rc - 2] set insert1 "04[lindex [lindex $l $rcp] 0] is [expr [lindex [lindex $l $rcp] 1] - $cw] words ahead" } } else {set cwavg "N/A"; set rc "N/A"} if {$aw > 0} { regexp {\d{1,3}\..{1}} [expr $aw.0/[lindex $csu($w$c) 7]] awavg set l ""; foreach e [array names csu] {if {[string match *$c $e]} {lappend l "[lindex $csu($e) 0] [lindex $csu($e) 6]"}} if {$l != ""} {set l [lsort -integer -decreasing -index 1 $l]} set ra [expr [lsearch [string tolower $l] $w*] + 1] if {$ra > 1} { set rap [expr $ra - 2] set insert2 "04[lindex [lindex $l $rap] 0] is [expr [lindex [lindex $l $rap] 1] - $aw] words ahead" } } else {set awavg "N/A"; set ra "N/A"} append o "Personal stats for 04$who on 04$c\n" append o "Joins: [lindex $csu($w$c) 2] Time spent: $ts Idle: [cs:duration [lindex $csu($w$c) 13]] $insert3\n" append o "TopTalkers: Rank $rc - $cw words/[lindex $csu($w$c) 5] lines (avg $cwavg). $insert1\n" append o "AllStars: Rank $ra - $aw words/[lindex $csu($w$c) 7] lines (avg $awavg). $insert2\n" append o "Kicks: [lindex $csu($w$c) 8] Bans: [lindex $csu($w$c) 9] Got kicked: [lindex $csu($w$c) 10] Got banned: [lindex $csu($w$c) 11]" return $o } } proc cs:change {n uh h c a} { global cs csc csu set c [string tolower $c]; if {![info exists csc($c)]} {return} set a [cs:filter $a]; set what [lindex $a 0] if {[string match -nocase toptalker $what]} {set p 4; set q 5; set str "TopTalker"} if {[string match -nocase allstar $what]} {set p 6; set q 7; set str "AllStar"} if {![info exists p]} {puthelp "NOTICE $n :Usage: $cs(trigger)change toptalker|allstar <+|-amount>"; return} set ni [lindex $a 1]; set nic [string tolower $ni]; set value [lindex $a 2] if {[info exists csu($nic$c)]} { if {[string is integer $value]} { set old [lindex $csu($nic$c) $p]; set lines [lindex $csu($nic$c) $q]; set new [expr $old + $value] if {$old > 0} {set x [expr $lines + int($value / ($old / $lines))]} else {set x [expr $lines + int($value / 4)]} if {$new < 0} {set new 0; set x 0; set value $old} set csu($nic$c) [lreplace $csu($nic$c) $p $p $new]; set csu($nic$c) [lreplace $csu($nic$c) $q $q $x] puthelp "NOTICE $n :Changed [cs:defilter $ni]'s $str balance from $old by $value to $new" } else {puthelp "NOTICE $n :Use an integer like +1000 or -500"} } else {puthelp "NOTICE $n :No record about [cs:defilter $ni] in $c"} } proc cs:merge {n uh h c a} { global cs csc csu set c [string tolower $c]; if {![info exists csc($c)]} {return} set a [cs:filter $a]; set from [lindex $a 0]; set i 2 set froml [string tolower $from]; set to [lindex $a 1]; set tol [string tolower $to] if {[llength $a] != 2} {puthelp "NOTICE $n :Usage: $cs(trigger)merge "; return} if {[info exists csu($froml$c)]} { if {[info exists csu($tol$c)]} { while {$i < 12} {set csu($tol$c) [lreplace $csu($tol$c) $i $i [expr [lindex $csu($froml$c) $i] + [lindex $csu($tol$c) $i]]]; incr i} set csu($tol$c) [lreplace $csu($tol$c) 13 13 [expr [lindex $csu($froml$c) 13] + [lindex $csu($tol$c) 13]]] unset csu($froml$c) puthelp "NOTICE $n :Merged [cs:defilter $from] in [cs:defilter $to], deleted [cs:defilter $from]" } else {puthelp "NOTICE $n :No record about [cs:defilter $to] in $c"} } else {puthelp "NOTICE $n :No record about [cs:defilter $from] in $c"} } proc cs:delete {n uh h c a} { global cs csc csu set c [string tolower $c]; if {![info exists csc($c)]} {return} if {$a == ""} {puthelp "NOTICE $n :Usage: $cs(trigger)delete "; return} set ni [cs:filter $a]; set nic [string tolower $ni] if {[info exists csu($nic$c)]} {unset csu($nic$c); puthelp "NOTICE $n :Deleted [cs:defilter $ni] in $c"} else { puthelp "NOTICE $n :No record about [cs:defilter $ni] in $c" } } proc cs:cycle {n uh h c a} { global cs csc csu set c [string tolower $c]; if {![info exists csc($c)]} {return}; set foobar 0 if {[lsearch -exact [bind pubm - "$c *"] cs:count] > -1} {unbind pubm -|- "$c *" cs:count; set foobar 1} cs:save foreach e [array names csu] { set csu($e) [lreplace $csu($e) 6 6 [expr [lindex $csu($e) 6] + [lindex $csu($e) 4]]] set csu($e) [lreplace $csu($e) 7 7 [expr [lindex $csu($e) 7] + [lindex $csu($e) 5]]] set csu($e) [lreplace $csu($e) 4 4 0]; set csu($e) [lreplace $csu($e) 5 5 0] } set csc($c) [lreplace $csc($c) 3 3 [unixtime]]; cs:save; if {$foobar} {bind pubm - "$c *" cs:count} puthelp "PRIVMSG $c :CHATstats: Finished cycling TopTalkers."; putlog "CHATstats: Finished cycling TopTalkers ($h, $c)" } proc cs:status {h idx a} { global cs csa csc csu set bc ""; set i 0; set al "csa csc csu" foreach e $al { foreach el [array names $e] { set el "#[lindex [split $el #] 1]" if {[lsearch $bc $el] > -1} {incr i; continue}; if {![validchan $el]} {incr i; lappend bc $el} } } putdcc $idx "CHATstats Info:" if {$bc != ""} { putdcc $idx "\nI'm not on the following channel(s), which occupy $i entries in my databases:" putdcc $idx "$bc - You might want to use the command .wipechan" } else { putdcc $idx "\nAll databases seem to be clean - I can't find any orphaned entries" } putdcc $idx "Database size: [array size csu] entries Trimlimit: $cs(trimlimit) words" putdcc $idx "\nIn detail, the following channel(s) are configured:" foreach e [array names csc] { set cname [string trimleft $e #]; set files ""; set cfiles ""; set gfiles ""; cs:changevars $e putdcc $idx " \n${e}" putdcc $idx " Monitoring: [lindex $csc($e) 0] / started: [cs:date $e sta] / stopped: [cs:date $e sto] / last cycle: [cs:date $e lr]" switch $cs(post) { 0 {set y "None, I tell them to visit the website"} 1 {set y "PRIVMSG to channel"} 2 {set y "NOTICE to user"} 3 {set y "PRIVMSG to user"} } putdcc $idx " Channel information: $y" putdcc $idx " Time correction: $cs(timebalance) hours, so right now it's [strftime %H:%M [expr [unixtime] + ($cs(timebalance) * 3600)]] from the user's POV." if {$cs(update)} { switch $cs(ulmethod) { 0 {set y ", left in $cs(workdir)"} 1 {set y ", moved to $cs(localfolder)"} 2 {set y ", uploaded to $cs(ftpname)$cs(ftpfolder) on port $cs(ftpport)"} } putdcc $idx " Webpage creation: yes$y" putdcc $idx " Interval: $cs(update) minutes" append cfiles "[glob -nocomplain -path $cs(workdir) *.${cname}.template] " append gfiles [glob -nocomplain -path $cs(workdir) *.global.template] foreach el $gfiles { set searchfor [string range $el 0 [string first "." $el]] if {[lsearch $cfiles $searchfor$cname.template] > -1} {set pos [lsearch $gfiles $el]; set gfiles [lreplace $gfiles $pos $pos]} } foreach el "$cfiles$gfiles" {lappend files [lindex [split $el "/"] end]} putdcc $idx " Templates in use: [join $files ", "]" if {$cs(adinterval)} {set adv "every $cs(adinterval) minutes"} else {set adv "no"} putdcc $idx " Advertisements: $adv" } else {putdcc $idx " Webpage creation: no"} } putdcc $idx "\nEnd of .chatstatus" } proc cs:read {} { global cs csa csc csu set fid [open $cs(workdir)CHATstats.dat r]; gets $fid l; gets $fid l if {![string match "--UserData--" $l]} { putlog "CHATstats: CHATstats.dat corrupted. Script not loaded properly." return } gets $fid l while {![string match "--ChannelData--" $l]} { if {![info exists cs(rehash)]} { set l [lreplace $l 1 1 0]; set l [lreplace $l 12 12 0] if {[lindex $l 3] > 900000000} {set l [lreplace $l 3 3 0]} if {[lindex $l 13] > [lindex $l 3]} {set l [lreplace $l 13 13 [lindex $l 3]]} set csu([string tolower [lindex $l 0]][lindex $l 14]) [lrange $l 0 13] } gets $fid l } gets $fid l while {![string match "--ActivityData--" $l]} {set csc([lindex $l 0]) [lrange $l 1 end]; gets $fid l} gets $fid l while {![eof $fid]} { if {![info exists cs(rehash)]} { set c [lindex $l 0]; set l [lrange $l 1 end] foreach e $l {set csa([lindex $e 0]$c) [lindex $e 1]} } gets $fid l } close $fid if {[info exists cs(recover)]} {set cs(rehash) 1} } proc cs:autosave {mi ho da mo ye} {cs:save} proc cs:save {} { global cs csa csc csu set fid [open $cs(workdir)CHATstats.dat w] puts $fid "CHATstats datafile v3.0" puts $fid "--UserData--" if {[array exists csu]} { foreach e [array names csu] {puts $fid "$csu($e) #[lindex [split $e #] 1]"} } puts $fid "--ChannelData--" if {[array exists csc]} { foreach e [array names csc] {puts $fid "$e $csc($e)"} } puts $fid "--ActivityData--" if {[array exists csa]} { foreach e [array names csa] {lappend l(#[lindex [split $e #] 1]) "[lindex [split $e #] 0] $csa($e)"} foreach e [array names l] {puts $fid "$e $l($e)"} } close $fid if {![file exists $cs(workdir)CHATstats.backup]} {file copy -force $cs(workdir)CHATstats.dat $cs(workdir)CHATstats.backup} } proc cs:backup {h idx a} { global cs csa csc csu if {[file exists $cs(workdir)CHATstats.dat]} { file copy -force $cs(workdir)CHATstats.dat $cs(workdir)CHATstats.backup putdcc $idx "Copied CHATstats.dat to CHATstats.backup." } else { putdcc $idx "Can't find $cs(workdir)CHATstats.dat." return } } proc cs:recover {h idx a} { global cs csa csc csu if {![file exists $cs(workdir)CHATstats.backup]} { putdcc $idx "Can't find file $cs(workdir)CHATstats.backup, aborting." return } if {[array exists csa]} {unset csa} if {[array exists csc]} {unset csc} if {[array exists csu]} {unset csu} file copy -force $cs(workdir)CHATstats.backup $cs(workdir)CHATstats.dat unset cs(rehash); set cs(recover) 1; cs:read; unset cs(recover) putdcc $idx "Data loaded from CHATstats.backup." } proc cs:wipechan {h idx a} { global cs csa csc csu set c [string tolower $a] if {$c == ""} {putdcc $idx "Usage: .wipechan "; return} if {[lsearch -exact [bind pubm - "$c *"] cs:count] > -1} { putdcc $idx "CHATstats is enabled on ${a}. Use \"stop $a\" first." return } foreach e [timers] {if {[string match *cs:*$c* $e]} {killtimer [lindex $e 2]}} array unset csa *$c; array unset csc $c; array unset csu *$c; cs:save putdcc $idx "Done. Deleted channel $a from all databases." } proc cs:trim {h idx a} { global csu set foo 0; set bar [array size csu] if {![string is integer $a]} {putdcc $idx "Can't trim by $a. Use an integer > 0"; return} foreach e [array names csu] {if {([lindex $csu($e) 4] < $a) && ([lindex $csu($e) 6] < $a)} {unset csu($e); incr foo}} cs:save if {$idx == -1} {putlog "CHATstats: Trimmed database, $foo of $bar users have been removed."} else { putdcc $idx "Trimmed database, $foo of $bar users have been removed." } } proc cs:autotrim {mi ho da mo ye} { global cs cs:trim "CHATstats" "-1" $cs(trimlimit) } proc cs:advertize {c} { global cs cs:changevars $c puthelp "PRIVMSG $c :I create diverse statistics for ${c}. Go visit $cs(adsite)." if {$cs(update) && $cs(adinterval)} {timer $cs(adinterval) "cs:advertize $c"} } proc cs:update {h idx a} { global cs set c [string tolower $a]; set l "" foreach e [binds cs:count] { regexp {#.*?\s} $e e; set e [string trim $e]; cs:changevars $e if {$cs(update)} {if {![validchan $e] || ![botonchan $e]} {putdcc $idx "I'm not on ${e}."; continue}; lappend l $e} } if {[llength $l] == 0} {putdcc $idx "No channels enabled or I'm not on any of the enabled channels at the moment"; return} set l [lsort $l] if {$c == ""} { putdcc $idx "Updating webpages for [join $l ", "]" foreach e $l { cs:changevars $e; foreach el [timers] {if {[string match "*cs:html $e*" $el]} {killtimer [lindex $el 2]}}; cs:html $e } } else { if {![validchan $c] || ![botonchan $c]} {putdcc $idx "I'm not on ${c}."; return} if {[lsearch $l $c] == -1} {putdcc $idx "CHATstats is not enabled in $c"; return} if {$cs(update)} { foreach e [timers] {if {[string match "*cs:html $c*" $e]} {killtimer [lindex $e 2]}} putdcc $idx "Updating webpages for $c"; cs:html $c } else {putdcc $idx "Configuration does not allow to create webpages for $c"} } } proc cs:html {c} { global cs csa csc cstemp1 cstemp2 csu cs:save; set cname [string trimleft $c #]; set ullist ""; set cfiles ""; set gfiles ""; cs:changevars $c if {![botonchan $c]} { putlog "Skipped creating webpages for $c. I'm not on that channel." if {$cs(update)} {timer $cs(update) "cs:html $c"}; return } if {$cs(ftperror) && $cs(ulmethod) == 2} { putlog "Skipped creating webpages for $c due to an FTP configuration error"; return } if {[array exists cstemp1]} {unset cstemp1} append cfiles "[glob -nocomplain -path $cs(workdir) *.${cname}.template] " append gfiles [glob -nocomplain -path $cs(workdir) *.global.template] foreach e $gfiles { set searchfor [string range $e 0 [string first "." $e]] if {[lsearch $cfiles $searchfor$cname.template] > -1} {set pos [lsearch $gfiles $e]; set gfiles [lreplace $gfiles $pos $pos]} } set files "$cfiles$gfiles" if {$files == ""} { putlog "Skipped creating webpages for $c. There are no templates in $cs(workdir)." if {$cs(update)} {timer $cs(update) "cs:html $c"} return } foreach e $files { set output "[string range $e 0 [string first "." $e]]$cname$cs(htmsuffix)"; cs:create $c $e $output; lappend ullist $output } if {[array exists cstemp2]} {unset cstemp2} if {$ullist != ""} { switch -exact $cs(ulmethod) { 1 {foreach e $ullist { if {[file exists $e]} {file copy -force $e $cs(localfolder); file delete -force $e} else { putlog "CHATstats: Skipped moving ${e}, file not found." } } } 2 {set ftperror [catch { set ftpid [open "|$cs(ftpclient) -n $cs(ftpname) $cs(ftpport)" w] puts $ftpid "user $cs(username) $cs(password)" foreach a $ullist { if {[file exists $a]} { puts $ftpid "put $a $cs(ftpfolder)[lindex [split $a "/"] end]" } else {putlog "CHATstats: Skipped uploading ${a}, file not found."} } puts $ftpid "quit" close $ftpid }] if {$ftperror} {putlog "CHATstats: An error occured while trying to use FTP."} foreach a $ullist {file delete -force $a} } } } if {$cs(update)} {timer $cs(update) "cs:html $c"} } proc cs:create {c input output} { global cs csa csc csu cstemp1 cstemp2 cst botnick offset timezone uptime server {server-online} if {![array exists cstemp2]} { set cstemp2(plusers) ""; set cstemp2(ulink) "None" if {[llength [bots]] > 0} {set cstemp2(bots) [join [lsort -dictionary [bots]] ", "]} else {set cstemp2(bots) "None"} foreach e [whom *] {if {$e != ""} {lappend cstemp2(plusers) [cs:filter "[lindex $e 0] [lindex $e 1] [lindex $e 6]"]}} set cstemp2(plusers) [lsort -dictionary $cstemp2(plusers)] foreach e [bots] { if {([validuser $e]) && ([string match *h* [getuser $e BOTFL]]) && ([islinked $e])} {set cstemp2(ulink) [cs:filter $e]} if {([validuser $e]) && ([matchattr $e b]) && (![string match *h* [getuser $e BOTFL]]) && ([islinked $e])} {lappend cstemp2(dlinks) [cs:filter $e]} } if {[info exists cstemp2(dlinks)]} {set cstemp2(dlinks) [join [lsort -dictionary $cstemp2(dlinks)] ", "]} else {set cstemp2(dlinks) "None"} } if {![array exists cstemp1]} { set cstemp1(all) 0; set cstemp1(ops) 0; set cstemp1(vos) 0; set cstemp1(chuserlist) ""; set oplist ""; set volist ""; set uslist "" set cstemp1(chanbans) ""; set topic [cs:filtertopic [topic $c]]; set topicline ""; foreach e "ttoptalkers tallstars tjoins totime ttwords ttlines tawords talines tkicks tbans titime" {set cstemp1($e) 0} foreach e [chanlist $c] { incr cstemp1(all) if {[isop $e $c]} {incr cstemp1(ops); set e "@[cs:filter $e]"; lappend oplist $e; continue} if {[isvoice $e $c]} {incr cstemp1(vos); set e "+[cs:filter $e]"; lappend volist $e; continue} set e " [cs:filter $e]"; lappend uslist $e } set cstemp1(chuserlist) [append cstemp1(chuserlist) " [lsort -dictionary $oplist]" " [lsort -dictionary $volist]" " [lsort -dictionary $uslist]"] set cstemp1(nos) [expr $cstemp1(all) - ($cstemp1(ops) + $cstemp1(vos))]; set cstemp1(nosp) [expr ($cstemp1(nos) * 100) / $cstemp1(all)] set cstemp1(vosp) [expr ($cstemp1(vos) * 100) / $cstemp1(all)]; set cstemp1(opsp) [expr ($cstemp1(ops) * 100) / $cstemp1(all)] foreach e [chanbans $c] {lappend cstemp1(chanbans) "[lindex [split $e] 0]"}; set cstemp1(chanbans) [lsort -dictionary $cstemp1(chanbans)] if {![info exists cst($c)]} {set cst($c) "N/A"} # regsub -all "(.{50}\[^http://\])" $topic {\1
} topic # personal hack to \n a topic without spaces after 50 chars if it doesn't contain a link foreach e [split $topic] { if {[string match "http://*" $e]} {set el $e; regsub -all "
" $e "" e; append topicline " $el" } else {append topicline " $e"} } set cstemp1(topic) $topicline if {![info exists timezone] || $timezone == ""} {set timezone "N/A"}; if {![info exists offset] || $offset == ""} {set offset "N/A"} foreach e [array names csu] { if {[string match *$c $e]} { if {[lindex $csu($e) 4] > 0} {incr cstemp1(ttoptalkers)} if {[lindex $csu($e) 6] > 0} {incr cstemp1(tallstars)} incr cstemp1(tjoins) [lindex $csu($e) 2]; incr cstemp1(totime) [lindex $csu($e) 3]; incr cstemp1(ttwords) [lindex $csu($e) 4] incr cstemp1(ttlines) [lindex $csu($e) 5]; incr cstemp1(tawords) [lindex $csu($e) 6]; incr cstemp1(talines) [lindex $csu($e) 7] incr cstemp1(tkicks) [lindex $csu($e) 8]; incr cstemp1(tbans) [lindex $csu($e) 10]; incr cstemp1(titime) [lindex $csu($e) 13] } } } set fid [open $input r]; set html [open $output w] while {![eof $fid]} { gets $fid l; set i 0 while {[string match "*%%*" $l]} { if {$i > 100} { putlog "An error occured in template [lindex [split $input "/"] end] .. most likely a variable has a wrong name. Line:" putlog "$l"; break } switch -glob $l { *%%TOPTALKERSAMOUNT* {regsub -all %%TOPTALKERSAMOUNT $l [cs:format $cstemp1(ttoptalkers)] l} *%%TOPTALKERSWORDS* {regsub -all %%TOPTALKERSWORDS $l [cs:format $cstemp1(ttwords)] l} *%%TOPTALKERSLINES* {regsub -all %%TOPTALKERSLINES $l [cs:format $cstemp1(ttlines)] l} *%%TOPTALKERSRATIO* {set x [expr $cstemp1(ttwords).0 / ($cstemp1(ttlines) + 1)]; regexp {\d+\..{1}} $x x; regsub -all %%TOPTALKERSRATIO $l $x l} *%%ALLSTARSAMOUNT* {regsub -all %%ALLSTARSAMOUNT $l [cs:format $cstemp1(tallstars)] l} *%%ALLSTARSWORDS* {regsub -all %%ALLSTARSWORDS $l [cs:format $cstemp1(tawords)] l} *%%ALLSTARSLINES* {regsub -all %%ALLSTARSLINES $l [cs:format $cstemp1(talines)] l} *%%ALLSTARSRATIO* {set x [expr $cstemp1(tawords).0 / ($cstemp1(talines) + 1)]; regexp {\d+\..{1}} $x x; regsub -all %%ALLSTARSRATIO $l $x l} *%%TWORDS* {regsub -all %%TWORDS $l [cs:format [expr $cstemp1(ttwords) + $cstemp1(tawords)]] l} *%%TLINES* {regsub -all %%TLINES $l [cs:format [expr $cstemp1(ttlines) + $cstemp1(talines)]] l} *%%TOTALJOINS* {regsub -all %%TOTALJOINS $l [cs:format $cstemp1(tjoins)] l} *%%TOTALONLINE* {regsub -all %%TOTALONLINE $l [cs:duration $cstemp1(totime)] l} *%%TOTALKICKS* {regsub -all %%TOTALKICKS $l [cs:format $cstemp1(tkicks)] l} *%%TOTALBANS* {regsub -all %%TOTALBANS $l [cs:format $cstemp1(tbans)] l} *%%TOTALIDLE* {regsub -all %%TOTALIDLE $l [cs:duration $cstemp1(titime)] l} *%%CHANNEL* {regsub -all %%CHANNEL $l $c l} *%%TIMEBALANCE* {regsub -all %%TIMEBALANCE $l $cs(timebalance) l} *%%TIMENOW* {regsub -all %%TIMENOW $l [cs:date $c admyhm] l} *%%TIMENEXTUPDATE* {regsub -all %%TIMENEXTUPDATE $l [strftime %H:%M [expr [unixtime] + ($cs(timebalance) * 3600) + ($cs(update) * 60)]] l} *%%CHANTOPIC* {regsub -all %%CHANTOPIC $l $cstemp1(topic) l} *%%CHANTOPSETTER* {regsub -all %%CHANTOPSETTER $l $cst($c) l} *%%CHANMODES* {regsub -all %%CHANMODES $l [getchanmode $c] l} *%%CHANUSERS* {regsub -all %%CHANUSERS $l $cstemp1(all) l} *%%CHANOPS* {regsub -all %%CHANOPS $l $cstemp1(ops) l} *%%CHANVOICES* {regsub -all %%CHANVOICES $l $cstemp1(vos) l} *%%CHANOTHERS* {regsub -all %%CHANOTHERS $l $cstemp1(nos) l} *%%CHAN%USERS* {regsub -all %%CHAN%USERS $l "100%" l} *%%CHAN%OPS* {regsub -all %%CHAN%OPS $l "$cstemp1(opsp)%" l} *%%CHAN%VOICES* {regsub -all %%CHAN%VOICES $l "$cstemp1(vosp)%" l} *%%CHAN%OTHERS* {regsub -all %%CHAN%OTHERS $l "$cstemp1(nosp)%" l} *%%SCRIPTSTATUS* {regsub -all %%SCRIPTSTATUS $l [lindex $csc($c) 0] l} *%%SCRIPTSTARTED* {regsub -all %%SCRIPTSTARTED $l [cs:date $c sta] l} *%%SCRIPTSTOPPED* {regsub -all %%SCRIPTSTOPPED $l [cs:date $c sto] l} *%%SCRIPTCYCLE* {regsub -all %%SCRIPTCYCLE $l [cs:date $c lr] l} *%%BOTNICK* {regsub -all %%BOTNICK $l $botnick l} *%%BOTIRCSERVER* {regsub -all %%BOTIRCSERVER $l $server l} *%%BOTONLINE* {regsub -all %%BOTONLINE $l [cs:duration [expr [unixtime] - ${server-online}]] l} *%%BOTNETBOTS* {regsub -all %%BOTNETBOTS $l $cstemp2(bots) l} *%%BOTNETSIZE* {regsub -all %%BOTNETSIZE $l [cs:format [llength $cstemp2(bots)]] l} *%%BOTNETUSERS* {regsub -all %%BOTNETUSERS $l [cs:format [llength $cstemp2(plusers)]] l} *%%BOTUSERLIST* {regsub -all %%BOTUSERLIST $l [cs:format [countusers]] l} *%%BOTUPLINK* {regsub -all %%BOTUPLINK $l [cs:defilter $cstemp2(ulink)] l} *%%BOTDOWNLINKS* {regsub -all %%BOTDOWNLINKS $l [cs:defilter $cstemp2(dlinks)] l} *%%BOTUPTIME* {regsub -all %%BOTUPTIME $l [cs:duration [expr [unixtime] - $uptime]] l} *%%BOTOFFSET* {regsub -all %%BOTOFFSET $l $offset l} *%%BOTTIMEZONE* {regsub -all %%BOTTIMEZONE $l $timezone l} } incr i } if {[string match -nocase "" $l]} { set what ""; set width 0; set amount 0 regexp {(\w+)\s(\d+)?,?(\d+)?} $l match what width amount set what [string tolower $what]; set eoc 0; set rep1 ""; set list "" while {!$eoc} {gets $fid nl; if {[string match -nocase "" $nl] || [eof $fid]} {set eoc 1} else {lappend rep1 [split $nl]}} switch -glob $what { partyline { foreach e $cstemp2(plusers) { regsub -all !!USER $rep1 [lindex $e 0] rep2; regsub -all !!BOT $rep2 [lindex $e 1] rep2; regsub -all !!CHAN $rep2 [lindex $e 2] rep2 puts $html [cs:defilter [join [join $rep2]]] } continue } bans { for {set i 0} {$i <= [llength $cstemp1(chanbans)]} {incr i} { regsub !!BAN $rep1 [lindex $cstemp1(chanbans) $i] rep2 while {[string match *!!BAN* $rep2]} {incr i; regsub !!BAN $rep2 [lindex $cstemp1(chanbans) $i] rep2} puts $html [cs:defilter [join [join $rep2]]] } continue } activity { if {$width == 0} { putlog "CHATstats: Syntax error in $input, must be: " continue } foreach e [array names csa] {if {[string match *$c $e]} {lappend list "[lindex [split $e #] 0] $csa($e)"}} set total 0; foreach e $list {incr total [lindex $e 1]}; set list [lsort -integer -decreasing -index 1 $list] set max [expr ([lindex [lindex $list 0] 1] * 100.0)/$total]; set list [lsort -increasing -index 0 $list] for {set i 0} {$i < 24} {incr i} { set int [lindex [lindex $list $i] 1]; set x [expr ($int * 100.0)/$total] regexp {\d{1,3}\..{1}} $x x; set barlength [expr int($x * ($width / $max) + ($x / 10))] regsub !!TIME1 $rep1 "[lindex [lindex $list $i] 0]:00" rep2 regsub !!TIME2 $rep2 "[lindex [lindex $list [expr $i + 1]] 0]:00" rep2 regsub !!VALUE $rep2 $int rep2 regsub !!PERCENT $rep2 "${x}%" rep2 regsub !!WIDTH $rep2 $barlength rep2 puts $html [join [join $rep2]] } continue } chanusers { foreach n $cstemp1(chuserlist) { set n [cs:defilter $n]; regsub -all "!!USER" $rep1 $n rep2; set n [string range $n 1 end]; regsub -all "!!HOST" $rep2 [string range [getchanhost $n] 0 45] rep2 set gcj [getchanjoin $n $c]; set u [unixtime] if {$gcj > 0} {regsub -all "!!DUR" $rep2 "[expr round((($u-$gcj)/60)/60)]h:[expr round(fmod((($u-$gcj)/60),60))]m" rep2} else { regsub -all "!!DUR" $rep2 "N/A" rep2 } regsub -all "!!IDLE" $rep2 "[getchanidle $n $c]m" rep2 puts $html [join [join $rep2]] } continue } top* { if {$width == 0 || $amount == 0} { putlog "CHATstats: Syntax error in $input, must be: " continue } set total 0 switch -exact $what { topjoiners {set sortfor 2} topvisitors {set sortfor 3} toptalkers {set sortfor 4} topallstars {set sortfor 6} topkickers {set sortfor 8} topbanners {set sortfor 9} topkicked {set sortfor 10} topbanned {set sortfor 11} topidlers {set sortfor 13} default {putlog "Unknown identifier found in template: $what - Aborting"; return} } foreach e [array names csu] {if {[string match *$c $e]} {lappend list "[lindex $csu($e) 0] [lindex $csu($e) $sortfor]"}} if {$list != ""} {set list [lsort -integer -decreasing -index 1 $list]} else {continue} foreach e $list {incr total [lindex $e 1]}; if {$total == 0} {continue} set max [expr ([lindex [lindex $list 0] 1] * 100.0)/$total]; set i 1 foreach e $list { set int [lindex $e 1]; if {$int == 0 || $i > $amount} {continue} set x [expr ($int * 100.0)/$total]; regexp {\d{1,3}\..{1}} $x x set barlength [expr int($x * ($width / $max) + ($x / 10))] regsub -all "!!RANK" $rep1 $i rep2 regsub -all "!!USER" $rep2 [lindex $e 0] rep2 if {$what == "topvisitors" || $what == "topidlers"} {regsub -all "!!VALUE" $rep2 [cs:duration $int] rep2} else { regsub -all "!!VALUE" $rep2 [cs:format $int] rep2 } regsub -all "!!PERCENT" $rep2 "${x}%" rep2 regsub -all "!!WIDTH" $rep2 $barlength rep2 puts $html [cs:defilter [join [join $rep2]]]; incr i } continue } default {puts $html $l} } } puts $html $l } close $html; close $fid } proc cs:checkpeak {c} { global cs csc set i [lindex $csc($c) 4]; set j [llength [chanlist $c]] if {$j > $i} { putserv "PRIVMSG $c :New peak for $c @ $j users! Old peak was $i users on [cs:date $c peak]." cs:changevars $c; set csc($c) [lreplace $csc($c) 4 4 $j]; set csc($c) [lreplace $csc($c) 5 5 [unixtime]]; cs:save } } proc cs:date {c what} { global cs csc switch -exact $what { sta {if {[lindex $csc($c) 1] == 0} {return "N/A"} else {return [strftime "%d.%m.%Y" [expr [lindex $csc($c) 1] + $cs(timebalance) * 3600]]}} sto {if {[lindex $csc($c) 2] == 0} {return "N/A"} else {return [strftime "%d.%m.%Y" [expr [lindex $csc($c) 2] + $cs(timebalance) * 3600]]}} lr {if {[lindex $csc($c) 3] == 0} {return "N/A"} else {return [strftime "%d.%m.%Y" [expr [lindex $csc($c) 3] + $cs(timebalance) * 3600]]}} peak {if {[lindex $csc($c) 5] == 0} {return "N/A"} else {return [strftime "%d.%m.%Y" [expr [lindex $csc($c) 5] + $cs(timebalance) * 3600]]}} admyhm {return [strftime "%A, %d.%m.%Y, %H:%M" [expr [unixtime] + $cs(timebalance) * 3600]]} } } proc cs:reset {w} { global cs csu set jtime [lindex $csu($w) 1]; set u [unixtime]; set nic [lindex [split $w #] 0] set c "#[lindex [split $w #] 1]"; set ls [lindex $csu($w) 12]; set idle 0 if {$jtime > 0} { set csu($w) [lreplace $csu($w) 3 3 [expr [lindex $csu($w) 3] + ($u - $jtime)]] set csu($w) [lreplace $csu($w) 1 1 0] if {$ls > 0} {set idle [expr $u - $ls]} else {set idle [expr $u - $jtime]} } else { if {$ls > 0} {set idle [expr $u - $ls]} } set csu($w) [lreplace $csu($w) 12 12 0] if {$idle > $cs(idle)} {set csu($w) [lreplace $csu($w) 13 13 [expr [lindex $csu($w) 13] + $idle]]} } proc cs:duration {du} { set o ""; set i [expr int($du/31536000)]; if {$i > 0} {lappend o "${i}y"} set i [expr int(fmod($du,31536000)/86400)]; if {$i > 0} {lappend o "${i}d"} set i [expr int(fmod($du,86400)/3600)]; if {$i > 0} {lappend o "${i}h"} set i [expr int(fmod($du,3600)/60)]; if {$i > 0} {lappend o "${i}m"} # set i [expr int(fmod($du,60))]; if {$i > 0} {lappend o "${i}s"} if {$o == ""} {return "N/A"} else {return [join $o ":"]} } proc cs:changevars {c} { global cs foreach e $cs(global) {set cs([lindex [split $e =] 0]) [lindex [split $e "="] 1]} if {[info exists cs($c)]} {foreach e $cs($c) {set cs([lindex [split $e =] 0]) [lindex [split $e "="] 1]}} } proc cs:topic {n uh h c t} { global cs cst cs:changevars $c; if {$n == "\*"} {set n "Unknown"}; set cst($c) "$n on [cs:date $c admyhm]" } proc cs:filtertopic {n} { regsub -all {|||(([0-9])?([0-9])?(\,([0-9])?([0-9])?)?)?|([0-9A-F][0-9A-F])?} $n "" n; return $n } proc cs:filter {n} { regsub -all \\\\ $n !1 n; regsub -all \\\[ $n !2 n; regsub -all \\\] $n !3 n; regsub -all \\\} $n !4 n regsub -all \\\{ $n !5 n; regsub -all \\\^ $n !6 n; regsub -all \\\" $n !7 n; return $n } proc cs:defilter {n} { regsub -all !1 $n \\ n; regsub -all !2 $n \[ n; regsub -all !3 $n \] n; regsub -all !4 $n \} n; regsub -all !5 $n \{ n; regsub -all !6 $n \^ n; regsub -all !7 $n \" n; return $n } proc cs:format {i} { if {![string is integer $i]} {return $i} while {[regsub {([0-9])([0-9]{3})($|\.)} $i {\1.\2} i]} {}; return $i } cs:inicsconvertdb.tcl100644 1751 1751 3205 7345731173 13733 0ustar baerchenbaerchenproc cs:convertdb {} { global cs csa csu foreach e "cs_toptalkers.dat cs_allstars.dat cs_activity.dat" { if {![file exists $cs(workdir)$e]} { putlog " Can't find file $cs(workdir)$e .. aborting." return } } set fid [open $cs(workdir)cs_toptalkers.dat] while {![eof $fid]} { gets $fid l if {[llength $l] == 3} { set count [lindex $l 2]; if {$count == 0} {continue} set user [lindex $l 0]; set nick [lindex $l 1]; set ls [expr $count / 10] if {[info exists csu($user)]} { set csu($user) [lreplace $csu($user) 4 4 [expr [lindex $csu($user) 4] + $count]] set csu($user) [lreplace $csu($user) 5 5 [expr [lindex $csu($user) 5] + $ls]] } else {set csu($user) "$nick 0 0 0 $count $ls 0 0 0 0 0 0 0 0"} } } close $fid set fid [open $cs(workdir)cs_allstars.dat] while {![eof $fid]} { gets $fid l if {[llength $l] == 3} { set count [lindex $l 2]; if {$count == 0} {continue} set user [lindex $l 0]; set nick [lindex $l 1]; set ls [expr $count / 10] if {[info exists csu($user)]} { set csu($user) [lreplace $csu($user) 6 6 [expr [lindex $csu($user) 6] + $count]] set csu($user) [lreplace $csu($user) 7 7 [expr [lindex $csu($user) 7] + $ls]] } else {set csu($user) "$nick 0 0 0 0 0 $count $ls 0 0 0 0 0 0"} } } close $fid set fid [open $cs(workdir)cs_activity.dat] while {![eof $fid]} { gets $fid l if {[llength $l] == 2} { set atime [lindex $l 0]; set count [lindex $l 1] if {[info exists csa($atime)]} {set csa($atime) [lreplace $csa($atime) 0 0 [expr $csa($atime) + $count]]} else {set csa($atime) $count} } } close $fid putlog " Finished. Everythings seems fine .." }otherstats.global.template100644 1751 1751 17602 7345731214 16131 0ustar baerchenbaerchen Other Stats for %%CHANNEL
Other stats for %%CHANNEL
%%TIMENOW
(Next update %%TIMENEXTUPDATE)
Monitoring: %%SCRIPTSTATUS
Started: %%SCRIPTSTARTED
Stopped: %%SCRIPTSTOPPED

Top Visitors:

Rank Nick Time spent % (of total)
. . . .
!!RANK !!USER !!VALUE !!PERCENT

Total online time: %%TOTALONLINE (100%)

Top Idlers:

Rank Nick Time idle % (of total)
. . . .
!!RANK !!USER !!VALUE !!PERCENT

Total idle time: %%TOTALIDLE (100%)

Top Kickers:

Rank Nick Kicks % (of total)
. . . .
!!RANK !!USER !!VALUE !!PERCENT

Total amount of kicks: %%TOTALKICKS (100%)

Top Banners:

Rank Nick Bans % (of total)
. . . .
!!RANK !!USER !!VALUE !!PERCENT

Total amount of bans: %%TOTALBANS (100%)

Most famous victims (Kicks):

Rank Nick Got kicked % (of total)
. . . .
!!RANK !!USER !!VALUE !!PERCENT

Most famous victims (Bans):

Rank Nick Got banned % (of total)
. . . .
!!RANK !!USER !!VALUE !!PERCENT


Brought to you by %%BOTNICK

redbar.gif100644 1751 1751 72 7345731220 12571 0ustar baerchenbaerchenGIF89a ¢Óæ..êRRîvvò˜˜îttêTTÔ, !C4"€;toptalls.global.template100644 1751 1751 7335 7345731224 15556 0ustar baerchenbaerchen TopTalkers & AllStars for %%CHANNEL
TopTalkers & AllStars for %%CHANNEL
%%TIMENOW
(Next update %%TIMENEXTUPDATE)
Monitoring: %%SCRIPTSTATUS
Started: %%SCRIPTSTARTED
Stopped: %%SCRIPTSTOPPED
Last cycle: %%SCRIPTCYCLE

Current TopTalkers Ranking:

Rank Nick Words % (of total)
. . . .
!!RANK !!USER !!VALUE !!PERCENT

A total of %%TOPTALKERSWORDS words has been spoken on %%TOPTALKERSLINES lines (avg %%TOPTALKERSRATIO words/line) by %%TOPTALKERSAMOUNT TopTalkers.

Current Allstars Ranking:

Rank Nick Words % (of total)
. . . .
!!RANK !!USER !!VALUE !!PERCENT

A total of %%ALLSTARSWORDS words has been spoken on %%ALLSTARSLINES lines (avg %%ALLSTARSRATIO words/line) by %%ALLSTARSAMOUNT AllStars.
Brought to you by %%BOTNICK