CONFIGURATION100644 1751 1751 12706 7356162453 12674 0ustar baerchenbaerchen ____ _ _ _ _____ _ _ / ___| | | | / \|_ _|__| |_ __ _| |_ ___ | | | |_| | / _ \ | |/ __| __/ _` | __/ __| | |___| _ |/ ___ \| |\__ \ || (_| | |_\__ \ \____|_| |_/_/ \_\_||___/\__\__,_|\__|___/ 3.1.0 by Baerchen, October 2001 for eggdrop 1.4.x+ & TCL 8.3 baerchen@germany-chat.net latest versions @ home.dal.net/baerchen 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(dont) "fserv type trigger" If CHATstats finds one of the words of this space delimited list in a user's line, it will not add the wordcount and the line to the user's stats. You don't need to include the plural of words, e.g. if you include "fserv" you don't need to add "fservs". Set to "" to disable this feature. --- set cs(global) { Here we start with the global configuration. 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 Determine how info is to be posted to the user: 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. The other way round, you would set timefactor to -6. 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) 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, no spaces!) 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 a local folder 2 = upload webpages via FTP Determine where the webpages shall go. 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 the 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 the 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) { setting1=value1 setting2=value2 .. } 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(#foobar) { 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/ at a 60 minute interval. 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 24107 7356162466 12452 0ustar baerchenbaerchen ____ _ _ _ _____ _ _ / ___| | | | / \|_ _|__| |_ __ _| |_ ___ | | | |_| | / _ \ | |/ __| __/ _` | __/ __| | |___| _ |/ ___ \| |\__ \ || (_| | |_\__ \ \____|_| |_/_/ \_\_||___/\__\__,_|\__|___/ 3.1.0 by Baerchen, October 2001 for eggdrop 1.4.x+ & TCL 8.3 baerchen@germany-chat.net latest versions @ home.dal.net/baerchen 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. Therefore you 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.x 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, -|- --------- (only available if helpfile is installed) .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. HISTORY ********************************************************************* 3.1.0 - Introduced new listing for templates: topactiveusers, which returns users' onlinetime minus idletime, sorted. %%TOTALACTIVE returns the total active chatting time of all users. - Introduced variable cs(dont): a space delimited list of words, which when spoken, prevents CHATstats from counting. highly recommended. - Three variables weren't available although built-in (TOTALWORDS & TOTALLINES & TOTALRATIO). - Added variable !!FLAGS to the chanusers listings (if user is recognized by bot, it returns his flags) - .dat file was holding data of channels that weren't enabled (wasn't checking for enabled channels in cs:rawpart and cs:rawjoin). This bug didn't affect anything except the size of the .dat file. After rehashing, you can .wipechan those channels. - 'wipechan' now understands more than one argument: wipechan #channel1 #channel2 #channel3 .. - cs(trim) went to the global variables. Each channel can be trimmed with different values - Fixed biggie: 'cyclestats' cycled all channels. Duh. - When script was stopped, %%TIMENEXTUPDATE still returned a value. - Fixed %%CHANNEL returning bs when channel name contained the character '&', e.g. #wine&dine (same for %%CHANTOPIC). - Fixed 'update' - under certain circumstances it was not possible to add a channel and have .update generate the websites - though normal ("scheduled") updating worked fine. - Fixed non-latin language based bug: if a nick used non-latin characters, an error in cs:update was raised stating the nick can't be found on the channel. Since this has nothing to do with the script itself but the way eggdrop and TCL work together, a quick workaround was to simply exclude that nick from further processing. - Updated and changed 'chatstats' slightly. - Updated helpfile (corrections, additions). - Gained speed improvements in regard to array operations. - Added sanity checks to some commands. - Cleaned up code and improved legibilty of the script. 3.0.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 25732 7356162475 12575 0ustar baerchenbaerchen ____ _ _ _ _____ _ _ / ___| | | | / \|_ _|__| |_ __ _| |_ ___ | | | |_| | / _ \ | |/ __| __/ _` | __/ __| | |___| _ |/ ___ \| |\__ \ || (_| | |_\__ \ \____|_| |_/_/ \_\_||___/\__\__,_|\__|___/ 3.1.0 by Baerchen, October 2001 for eggdrop 1.4.x+ & TCL 8.3 baerchen@germany-chat.net latest versions @ home.dal.net/baerchen INSTALLATION ********************************************************************** - Put chatstats.tcl in your /scripts directory and make an entry in the bot config (e.g. source scripts/chatstats.tcl) Upgraders from 2.x: ------------------- 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. - Copy chatstats.help in your /help directory and make an entry in the bot config (e.g. loadhelp chatstats.help) - Copy the supplied templates in $cs(workdir) (see configuration) or use your own ones (see the HTML TEMPLATES manual below). - Copy 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, you're finished. Next chapter deals with how to make your own templates. 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 be 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 parameters discussed later Then comes the HTML stuff and the needed variables Then we define the end of the listing by In opposite to variables and placeholders, 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 ----------------------------------- VARIABLE RETURNS .. -------- ---------- !!USER a user on the partyline according to 'whom *' !!BOT the bot !!USER is on !!CHAN the botchannel !!USER is on !!USER a channel user according to /names !!FLAGS user's botflags for the channel !!HOST !!USER's ident@host !!DUR !!USER's online time !!IDLE !!USER's idle time !!BAN one ban from the channel's banlist. You can use this more than once e.g. to put two bans in one row !!TIME1 time start range e.g. 00:00 !!TIME2 time end range, e.g. 01:00 !!VALUE words spoken in time range !!PERCENT !!VALUE's percentage in relation to total !!WIDTH 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 user's nick (e.g. from TopTalkers) !!RANK !!USER's ranking !!VALUE !!USER's count (joins, words, etc.) !!PERCENT !!VALUE's percentual share !!WIDTH 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 %%TOTALWORDS Toptalkers' + AllStar's words %%TOTALLINES Toptalkers' + AllStar's words %%TOTALRATIO Toptalkers' + AllStar's 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 %%TOTALACTIVE added active chatting time of all users %%CHANNEL channel name %%CHANMODES channel modes %%CHANTOPIC channel topic %%CHANTOPSETTER nick who set the topic and date %%CHANUSERS channel's total user amount %%CHANOPS channel's ops %%CHANVOICES channel's voices %%CHANOTHERS channel's other users %%CHAN%USERS channel's total users percentual 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" or "no" for CHATstats en- or disbaled %%SCRIPTSTARTED date of CHATstats' very first start %%SCRIPTSTOPPED date when CHAtstats was last stopped %%SCRIPTCYCLE date of the last cycle %%BOTNICK botnick %%BOTIRCSERVER IRC server the bot is connected to %%BOTONLINE time the 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
As might have noticed, it doesn't matter whether you put several variables or placeholders in one line or each of them in a single line. You can also mix them. To get a better impression, have a look at the templates supplied with the script.botstats.global.template100644 1751 1751 2721 7356162353 15554 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 10131 7356162361 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: %%TOTALWORDS words (100%) since %%SCRIPTSTARTED
Brought to you by %%BOTNICK

chatstats.help100644 1751 1751 10301 7356162366 13602 0ustar baerchenbaerchen%{help=chatstats} You can get help on individual commands: .help CHANNEL COMMANDS show %{+C|+C} change cyclestats delete merge DCC COMMANDS go stop %{+n} update chatstatus trim wipechan back-up recover %{help=show} ### show show show 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 one on a channel basis %{help=go}%{+Cn|+C} ### go DCC C|C Enables monitoring for . In opposite to earlier versions (- 2.x), it also starts creation of webpages for if configured. See also: stop %{help=stop}%{+Cn|+C} ### stop DCC C|C Disables monitoring for . All other commands remain available. If you want the bot to leave , use this _before_ doing so. In this case, you might also want to use 'wipechan' in order to completely delete from the database. Don't do this if you plan to re-.go one day :) In opposite to earlier versions (- 2.x), it also stops the creation of webpages for . See also: go wipechan %{help=change}%{+Cn|+C} ### change 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} ### merge 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} ### delete 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} ### chatstatus 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} ### trim ?channel? DCC n|- This command is useful if you set the trimlimit to 0 and the database has become spammed with flyby's over the time. If is given, all TopTalkers with less than words in will be deleted from the database immediately (no undo). If is omitted, _all_ TopTalkers of _all_ channels with less than words will be deleted from the database immediately (no undo). %{help=update}%{+n} ### update% ?? DCC n|- If is given, only 's webpages will get updated. If no argument is given, the webpages for all channels will get updated. %{help=wipechan}%{+n} ### wipechan ? ..? DCC n|- Once you stop monitoring , you might want to delete the referring data in the databases. In opposite to earlier versions of CHATstats, cannot be abbreviated. You can submit one or more channels as arguments. There's no undo, so don't do this if you plan to re-enable CHATstats for . %{help=back-up}%{+n} ### back-up DCC n|- Save the current data and makes a backup of the database. See also: recover %{help=recover}%{+n} ### recover DCC n|- Reads the backup to memory. No rehash or restart required. See also: back-up chatstats.tcl100644 1751 1751 126567 7356162403 13472 0ustar baerchenbaerchen# ____ _ _ _ _____ _ _ # / ___| | | | / \|_ _|__| |_ __ _| |_ ___ # | | | |_| | / _ \ | |/ __| __/ _` | __/ __| # | |___| _ |/ ___ \| |\__ \ || (_| | |_\__ \ # \____|_| |_/_/ \_\_||___/\__\__,_|\__|___/ # 3.1.0 by Baerchen, October 2001 # for eggdrop 1.4.x+ & TCL 8.3 # baerchen@germany-chat.net # latest versions @ home.dal.net/baerchen # # Read DESCRIPTION, CONFIGURATION & INSTALLATION. # # CONFIGURATION set cs(workdir) "/usr/home/bla/mybot/putallfileshere/" set cs(trigger) "." set cs(idle) 300 set cs(dont) "fserv type trigger" set cs(global) { post=2 timebalance=+0 trimlimit=0 adinterval=0 adsite=http://www.yoursitehere.com update=60 htmsuffix=.htm 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.1.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:cv $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."} 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 [clock seconds] 0 0 [llength [chanlist $c]] [clock seconds]" } else { set csc($c) [lreplace $csc($c) 0 0 "yes"] if {[lindex $csc($c) 1] == 0} {set csc($c) [lreplace $csc($c) 1 1 [clock seconds]]} set csc($c) [lreplace $csc($c) 2 2 0] } foreach e [chanlist $c] { if {([matchattr $e b]) || ($e == $botnick) || [string match -nocase "guest*" $e]} {continue} set el [cs:fl [string tolower $e]] if {[info exists csu($el$c)]} { set csu($el$c) [lreplace $csu($el$c) 0 0 [cs:fl $e]] set csu($el$c) [lreplace $csu($el$c) 1 1 [clock seconds]] } else {set csu($el$c) "[cs:fl $e] [clock seconds] 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:cv $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 [clock seconds]] } foreach e [array names csu *$c] {cs:reset $e} cs:save cs:cv $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:fl $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:fl $n]] set csu($ni$c) [lreplace $csu($ni$c) 1 1 [clock seconds]] set csu($ni$c) [lreplace $csu($ni$c) 2 2 [expr [lindex $csu($ni$c) 2] + 1]] } else {set csu($ni$c) "[cs:fl $n] [clock seconds] 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]] if {[lsearch -exact [bind pubm - "$c *"] cs:count] == -1} {return 0} set userlist [lindex [split $a :] 1] foreach e $userlist { set e [string trimleft $e "%+@"] if {[matchattr $e b] || ($e == $botnick) || [string match -nocase "guest*" $e]} {continue} set el [cs:fl [string tolower $e]] if {[info exists csu($el$c)]} { set csu($el$c) [lreplace $csu($el$c) 0 0 [cs:fl $e]] set csu($el$c) [lreplace $csu($el$c) 1 1 [clock seconds]] } else {set csu($el$c) "[cs:fl $e] [clock seconds] 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 set t [split $t] foreach e $cs(dont) {if {[lsearch $t *$e*] > -1} {return}} if {([matchattr $n b]) || ($n == $botnick) || [string match -nocase "guest*" $n]} {return} set t [llength $t]; set ni [cs:fl [string tolower $n]]; set c [string tolower $c]; set u [clock seconds] 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:fl $n] $u 1 0 $t 1 0 0 0 0 0 0 $u 0"} cs:cv $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:fl $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:fl $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:fl $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:fl $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:fl [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} {return 0} set c [string tolower $a] if {[lsearch -exact [bind pubm - "$c *"] cs:count] == -1} {return 0} foreach e [array names csu *$c] {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:cv $c if {$cs(post) == 0} {puthelp "PRIVMSG $c: Stats not available. Go visit $cs(adsite)"; return} if {![info exists csc($c)]} {return} set a [cs:fl $a]; set what [string tolower [lindex $a 0]]; set who [lindex $a 1]; set ch "04$c\n" if {$who == ""} {set who [cs:fl $n]} switch -exact $what { channel {set o "CHATstats for $ch"; append o [cs:prep 0 1 $c ""]} joins {set o "Top Joiners of $ch"; append o [cs:prep 1 2 $c ""]} visitors {set o "Top Visitors of $ch"; append o [cs:prep 2 3 $c ""]} toptalkers {set o "Top Talkers of $ch"; append o [cs:prep 1 4 $c ""]} stats {set o ""; append o [cs:prep 3 4 $c $who]} allstars {set o "Top AllStars of $ch"; append o [cs:prep 1 6 $c ""]} kickers {set o "Top Kickers of $ch"; append o [cs:prep 1 8 $c ""]} banners {set o "Top Banners of $ch"; append o [cs:prep 1 9 $c ""]} idlers {set o "Top Idlers of $ch"; append o [cs:prep 2 13 $c ""]} kicked {set o "Most famous victims (kicks) of $ch"; append o [cs:prep 1 10 $c ""]} banned {set o "Most famous victims (bans) of $ch"; append o [cs:prep 1 11 $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:dfl $e]"}} 2 {foreach e $o {puthelp "NOTICE $n :[cs:dfl $e]"}} 3 {foreach e $o {puthelp "PRIVMSG $n :[cs:dfl $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 *$c] { incr i; incr j [lindex $csu($e) 2]; incr t [lindex $csu($e) 3]; incr k [lindex $csu($e) 8] incr wc [expr [lindex $csu($e) 4] + [lindex $csu($e) 6]]; incr b [lindex $csu($e) 10] incr wl [expr [lindex $csu($e) 5] + [lindex $csu($e) 7]]; 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:dur [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:fmt $i] people joining [cs:fmt $j] times wasting [cs:dur $t].\n" append o "Their idletimes add up to [cs:dur $id] leaving [cs:dur [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:fmt $wc] words on [cs:fmt $wl] lines (avg $wla).\n" } append o "I count [cs:fmt $k] kicks/[cs:fmt $b] bans ($ku kicks/$bu bans per user$insert" return $o } set l "" foreach e [array names csu *$c] {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"} set cw [lindex $csu($w$c) 4]; set aw [lindex $csu($w$c) 6]; set insert1 ""; set insert2 "" set insert3 ""; set l ""; set cwavg "N/A"; set rc "N/A"; set awavg "N/A"; set ra "N/A" if {[onchan $who $c]} { set ts [expr [lindex $csu($w$c) 3] + ([clock seconds] - [lindex $csu($w$c) 1]) ]} else { set ts [lindex $csu($w$c) 3] } if {$ts == 0} {set ts "N/A"} else { set insert3 "-> Active chatting: [cs:dur [expr $ts - [lindex $csu($w$c) 13]]]" set ts "[cs:dur $ts] " } if {$cw > 0} { set rc [expr [lsearch [string tolower $l] $w*] + 1] 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" } } if {$aw > 0} { regexp {\d{1,3}\..{1}} [expr $aw.0/[lindex $csu($w$c) 7]] awavg foreach e [array names csu *$c] {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" } } append o "Personal stats for 04$who on 04$c\n" append o "Joins: [lindex $csu($w$c) 2] Time spent: $ts Idle: [cs:dur [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:fl $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:dfl $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:dfl $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:fl $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:dfl $from] in [cs:dfl $to], deleted [cs:dfl $from]" } else {puthelp "NOTICE $n :No record about [cs:dfl $to] in $c"} } else {puthelp "NOTICE $n :No record about [cs:dfl $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:fl $a]; set nic [string tolower $ni] if {[info exists csu($nic$c)]} { unset csu($nic$c) puthelp "NOTICE $n :Deleted [cs:dfl $ni] in $c" } else {puthelp "NOTICE $n :No record about [cs:dfl $ni] in $c"} } proc cs:cycle {n uh h c a} { global cs csc csu set c [string tolower $c]; set foobar 0 if {![info exists csc($c)]} {return} if {[lsearch -exact [bind pubm - "$c *"] cs:count] > -1} {unbind pubm -|- "$c *" cs:count; set foobar 1} foreach e [array names csu *$c] { 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 [clock seconds]] 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 "Database: $i orphaned entries for channels: [join $bc ", "] ('help wipechan' for more info)" } else {putdcc $idx "Database: clean, no orphaned entries ([array size csu] entries total)"} putdcc $idx "Valid idle time: > $cs(idle) seconds" putdcc $idx "Trigger words for invalid lines: $cs(dont)" putdcc $idx "Channel details:" foreach e [array names csc] { set cname [string trimleft $e #]; set files ""; set cfiles ""; set gfiles ""; cs:cv $e putdcc $idx " \n$e (Active: [lindex $csc($e) 0] Start: [cs:date $e sta] Stop: [cs:date $e sto] Last cycle: [cs:date $e lr])" switch $cs(post) { 0 {set y "None, I tell them to visit $cs(adsite)"} 1 {set y "PRIVMSG to channel"} 2 {set y "NOTICE to user"} 3 {set y "PRIVMSG to user"} } putdcc $idx " Database trim limit: < $cs(trimlimit) words" putdcc $idx " Channel information: $y" putdcc $idx " Time correction: $cs(timebalance) hours (current: [strftime %H:%M [clock seconds]] corrected: [strftime %H:%M [expr [clock seconds] + ($cs(timebalance) * 3600)]])" 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 " Webpages: 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)} {putdcc $idx " Advertisements: every $cs(adinterval) minutes"} else {putdcc $idx " Advertisements: no"} } else {putdcc $idx " Webpage creation: no"} } putdcc $idx "\nEnd of .chatstatus" } proc cs:read {} { global cs csa csc csu if {[info exists cs(rehash)]} {return} 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 {[llength $l] == 15} { 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] } else {putlog " Corrupted line in CHATstats.dat, not loaded: $l"} gets $fid l } gets $fid l while {![string match "--ActivityData--" $l]} { if {[llength $l] == 7} {set csc([lindex $l 0]) [lrange $l 1 end]} else { putlog " Corrupted line in CHATstats.dat, not loaded: $l" } gets $fid l } gets $fid l while {![eof $fid]} { if {[llength $l] == 26} { set c [lindex $l 0]; set l [lrange $l 1 end] foreach e $l {set csa([lindex $e 0]$c) [lindex $e 1]} } else {putlog " Corrupted line in CHATstats.dat, not loaded: $l"} gets $fid l } close $fid } 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 cs:save file copy -force $cs(workdir)CHATstats.dat $cs(workdir)CHATstats.backup putdcc $idx "Saved current data and copied CHATstats.dat to CHATstats.backup." } 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 } unset csa; unset csc; unset csu file copy -force $cs(workdir)CHATstats.backup $cs(workdir)CHATstats.dat unset cs(rehash); cs:read; set cs(rehash) 1 putdcc $idx "Database reloaded from CHATstats.backup." } proc cs:wipechan {h idx a} { global cs csa csc csu set c [string tolower $a]; set l "" if {$c == "" || [string range $c 0 0] != "#"} {putdcc $idx "Usage: .wipechan ? ..?"; return} foreach e $c { if {[lsearch -exact [bind pubm - "$e *"] cs:count] > -1} { putdcc $idx "CHATstats is enabled on $e. Use \".stop $e\" in DCC first." } else { set al "csa csc csu"; set f 0 foreach el $al {foreach ele [array names $el *$e] {set f 1}} if {!$f} {putdcc $idx "Can't find channel $e in database"} else { foreach el [timers] {if {[string match *cs:*$e* $el]} {killtimer [lindex $el 2]}} array unset csa *$e; array unset csc $e; array unset csu *$e; lappend l $e } } } if {$l != ""} {cs:save; putdcc $idx "Deleted all entries for [join $l ", "] from database."} } proc cs:trim {h idx a} { global cs csu set c [lindex [string tolower $a] 0]; set limit [lindex $a 1]; set foo 0; set l "" if {$idx == -1} { foreach e [array names csu *$c] {lappend l $e} if {$l != ""} { foreach e $l { if {([lindex $csu($e) 4] < $limit) && ([lindex $csu($e) 6] < $limit)} {unset csu($e); incr foo} } putlog "Trimmed CHATstats database for $c by $limit words, $foo of [llength $l] users have been removed." } else {putlog "CHATstats: No user in $c has less than $limit words, no need to trim database."} return } if {[string is integer $c]} { set limit $c; set bar [array size csu] foreach e [array names csu] { if {([lindex $csu($e) 4] < $a) && ([lindex $csu($e) 6] < $a)} {unset csu($e); incr foo} } cs:save putdcc $idx "Trimmed complete CHATstats database by $limit words, $foo of $bar users have been removed." } else { foreach e [array names csu *$c] {lappend l $e} if {$l == ""} {putdcc $idx "Can't find channel $c in CHATstats database"; return} foreach e $l { if {([lindex $csu($e) 4] < $limit) && ([lindex $csu($e) 6] < $limit)} {unset csu($e); incr foo} } putdcc $idx "Trimmed CHATstats database for $c by $limit words, $foo of [llength $l] users have been removed." } } proc cs:autotrim {mi ho da mo ye} { global cs set l "" foreach e [binds cs:count] { regexp {#.*?\s} $e e; set e [string trim $e]; lappend l $e } if {$l == ""} {return} else { foreach e $l { cs:cv $e; cs:trim "CHATstats" "-1" "$e $cs(trimlimit)" } } } proc cs:advertize {c} { global cs cs:cv $c puthelp "PRIVMSG $c :I create diverse statistics for $c. Go visit $cs(adsite)" 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:cv $e if {$cs(update)} { if {![validchan $e] || ![botonchan $e]} {putdcc $idx "I'm not on $e."; continue} lappend l $e } } if {[llength $l] == 0} {return} else {set l [lsort $l]} if {$c == ""} { foreach e $l { cs:cv $e foreach el [timers] { if {[string match "*cs:html $e*" $el]} {killtimer [lindex $el 2]} } set cs(manual) "$idx Successfully updated webpages for $e" cs:html $e } } else { cs:cv $c 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]} } set cs(manual) "$idx Successfully updated webpages for $c"; cs:html $c } else {putdcc $idx "Configuration does not allow webpages for $c"} } } proc cs:html {c} { global cs csa csc csx csy csu cs:save; set cname [string trimleft $c #]; set ullist ""; set cfiles ""; set gfiles ""; cs:cv $c if {$cs(ftperror) && $cs(ulmethod) == 2} { putlog "Skipped creating webpages for $c due to an FTP configuration error" return } if {![botonchan $c]} { putlog "I'm not on $c, skipped creating webpages." if {$cs(update)} {timer $cs(update) "cs:html $c"} return } 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 "There are no templates in $cs(workdir), skipped creating webpages for $c. " 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 csy]} {unset csy} if {[array exists csx]} {unset csx} 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 {[info exists cs(manual)]} { putdcc [lindex $cs(manual) 0] "[lrange $cs(manual) 1 end]" unset cs(manual) } if {$cs(update)} {timer $cs(update) "cs:html $c"} } proc cs:create {c input output} { global cs csa csc csu csx csy cst botnick offset timezone uptime server {server-online} if {![array exists csy]} { set csy(plusers) ""; set csy(ulink) "None" if {[llength [bots]] > 0} {set csy(bots) [join [lsort -dictionary [bots]] ", "]} else {set csy(bots) "None"} foreach e [whom *] {if {$e != ""} {lappend csy(plusers) [cs:fl "[lindex $e 0] [lindex $e 1] [lindex $e 6]"]}} set csy(plusers) [lsort -dictionary $csy(plusers)] foreach e [bots] { if {([validuser $e]) && ([string match *h* [getuser $e BOTFL]]) && ([islinked $e])} {set csy(ulink) [cs:fl $e]} if {([validuser $e]) && ([matchattr $e b]) && (![string match *h* [getuser $e BOTFL]]) && ([islinked $e])} {lappend csy(dlinks) [cs:fl $e]} } if {[info exists csy(dlinks)]} {set csy(dlinks) [join [lsort -dictionary $csy(dlinks)] ", "]} else {set csy(dlinks) "None"} } if {![array exists csx]} { set topic [cs:fltpc [topic $c]] foreach e "all nos ops vos ttoptalkers tallstars tjoins totime ttwords ttlines tawords talines tkicks tbans titime" {set csx($e) 0} foreach e "csx(chbans) csx(chul) csx(topic) oplist volist uslist" {set $e ""} foreach e [chanlist $c] { incr csx(all) if {[isop $e $c]} {incr csx(ops); set e "@[cs:fl $e]"; lappend oplist $e; continue} if {[isvoice $e $c]} {incr csx(vos); set e "+[cs:fl $e]"; lappend volist $e; continue} set e " [cs:fl $e]"; incr csx(nos); lappend uslist $e } set csx(chul) [append csx(chul) " [lsort -dictionary $oplist]" " [lsort -dictionary $volist]" " [lsort -dictionary $uslist]"] set csx(opsp) [expr ($csx(ops) * 100) / $csx(all)] set csx(vosp) [expr ($csx(vos) * 100) / $csx(all)] set csx(nosp) [expr ($csx(nos) * 100) / $csx(all)] foreach e [chanbans $c] {lappend csx(chbans) "[lindex [split $e] 0]"} set csx(chbans) [lsort -dictionary $csx(chbans)] if {![info exists cst($c)]} {set cst($c) "N/A"} # regsub -all "(.{50}\[^http://\])" $csx(topic) {\1
} csx(topic) foreach e [split $topic] { if {[string match "http://*" $e]} { set el $e regsub -all "
" $e "" e append csx(topic) " $el" } else {append csx(topic) " $e"} } if {![info exists timezone] || $timezone == ""} {set timezone "N/A"} if {![info exists offset] || $offset == ""} {set offset "N/A"} foreach e [array names csu *$c] { if {[lindex $csu($e) 4] > 0} {incr csx(ttoptalkers)} if {[lindex $csu($e) 6] > 0} {incr csx(tallstars)} incr csx(tjoins) [lindex $csu($e) 2]; incr csx(totime) [lindex $csu($e) 3]; incr csx(ttwords) [lindex $csu($e) 4] incr csx(ttlines) [lindex $csu($e) 5]; incr csx(tawords) [lindex $csu($e) 6]; incr csx(talines) [lindex $csu($e) 7] incr csx(tkicks) [lindex $csu($e) 8]; incr csx(tbans) [lindex $csu($e) 10]; incr csx(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 > 50} { putlog "CHATstats: unknown placeholder found in template [lindex [split $input "/"] end]. Line:" putlog "$l" break } switch -glob $l { *%%BOTNICK* {regsub -all %%BOTNICK $l $botnick l} *%%BOTIRCSERVER* {regsub -all %%BOTIRCSERVER $l $server l} *%%BOTONLINE* {regsub -all %%BOTONLINE $l [cs:dur [expr [clock seconds] - ${server-online}]] l} *%%BOTNETBOTS* {regsub -all %%BOTNETBOTS $l $csy(bots) l} *%%BOTNETSIZE* {regsub -all %%BOTNETSIZE $l [cs:fmt [llength $csy(bots)]] l} *%%BOTNETUSERS* {regsub -all %%BOTNETUSERS $l [cs:fmt [llength $csy(plusers)]] l} *%%BOTUSERLIST* {regsub -all %%BOTUSERLIST $l [cs:fmt [countusers]] l} *%%BOTUPLINK* {regsub -all %%BOTUPLINK $l [cs:dfl $csy(ulink)] l} *%%BOTDOWNLINKS* {regsub -all %%BOTDOWNLINKS $l [cs:dfl $csy(dlinks)] l} *%%BOTUPTIME* {regsub -all %%BOTUPTIME $l [cs:dur [expr [clock seconds] - $uptime]] l} *%%BOTOFFSET* {regsub -all %%BOTOFFSET $l $offset l} *%%BOTTIMEZONE* {regsub -all %%BOTTIMEZONE $l $timezone 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} *%%CHANNEL* {regsub & $c "\\\\&" cfix; regsub %%CHANNEL $l $cfix l} *%%CHANTOPIC* {regsub & $csx(topic) "\\\\&" ctopfix; regsub -all %%CHANTOPIC $l $ctopfix l} *%%CHANTOPSETTER* {regsub -all %%CHANTOPSETTER $l $cst($c) l} *%%CHANMODES* {regsub -all %%CHANMODES $l [getchanmode $c] l} *%%CHANUSERS* {regsub -all %%CHANUSERS $l $csx(all) l} *%%CHANOPS* {regsub -all %%CHANOPS $l $csx(ops) l} *%%CHANVOICES* {regsub -all %%CHANVOICES $l $csx(vos) l} *%%CHANOTHERS* {regsub -all %%CHANOTHERS $l $csx(nos) l} *%%CHAN%USERS* {regsub -all %%CHAN%USERS $l "100%" l} *%%CHAN%OPS* {regsub -all %%CHAN%OPS $l "$csx(opsp)%" l} *%%CHAN%VOICES* {regsub -all %%CHAN%VOICES $l "$csx(vosp)%" l} *%%CHAN%OTHERS* {regsub -all %%CHAN%OTHERS $l "$csx(nosp)%" l} *%%TIMEBALANCE* {regsub -all %%TIMEBALANCE $l $cs(timebalance) l} *%%TIMENOW* {regsub -all %%TIMENOW $l [cs:date $c curr] l} *%%TIMENEXTUPDATE* {regsub -all %%TIMENEXTUPDATE $l [cs:date $c nu] l} *%%TOPTALKERSAMOUNT* {regsub -all %%TOPTALKERSAMOUNT $l [cs:fmt $csx(ttoptalkers)] l} *%%TOPTALKERSWORDS* {regsub -all %%TOPTALKERSWORDS $l [cs:fmt $csx(ttwords)] l} *%%TOPTALKERSLINES* {regsub -all %%TOPTALKERSLINES $l [cs:fmt $csx(ttlines)] l} *%%TOPTALKERSRATIO* {set x [expr $csx(ttwords).0 / ($csx(ttlines) + 1)]; regexp {\d+\..{1}} $x x; regsub -all %%TOPTALKERSRATIO $l $x l} *%%ALLSTARSAMOUNT* {regsub -all %%ALLSTARSAMOUNT $l [cs:fmt $csx(tallstars)] l} *%%ALLSTARSWORDS* {regsub -all %%ALLSTARSWORDS $l [cs:fmt $csx(tawords)] l} *%%ALLSTARSLINES* {regsub -all %%ALLSTARSLINES $l [cs:fmt $csx(talines)] l} *%%ALLSTARSRATIO* {set x [expr $csx(tawords).0 / ($csx(talines) + 1)]; regexp {\d+\..{1}} $x x; regsub -all %%ALLSTARSRATIO $l $x l} *%%TOTALWORDS* {regsub -all %%TOTALWORDS $l [cs:fmt [expr $csx(ttwords) + $csx(tawords)]] l} *%%TOTALLINES* {regsub -all %%TOTALLINES $l [cs:fmt [expr $csx(ttlines) + $csx(talines)]] l} *%%TOTALRATIO* {set x [expr ($csx(ttwords) + $csx(tawords)) / ($csx(ttlines).0 + $csx(talines) + 1)] regexp {\d+\..{1}} $x x; regsub -all %%TOTALRATIO $l $x l} *%%TOTALJOINS* {regsub -all %%TOTALJOINS $l [cs:fmt $csx(tjoins)] l} *%%TOTALKICKS* {regsub -all %%TOTALKICKS $l [cs:fmt $csx(tkicks)] l} *%%TOTALBANS* {regsub -all %%TOTALBANS $l [cs:fmt $csx(tbans)] l} *%%TOTALONLINE* {regsub -all %%TOTALONLINE $l [cs:dur $csx(totime)] l} *%%TOTALIDLE* {regsub -all %%TOTALIDLE $l [cs:dur $csx(titime)] l} *%%TOTALACTIVE* {regsub -all %%TOTALACTIVE $l [cs:dur [expr $csx(totime) - $csx(titime)]] l} } incr i } if {[string match -nocase "" $l]} { set width 0; set amount 0; set eoc 0; set what ""; set rep1 ""; set list "" regexp {(\w+)\s(\d+)?,?(\d+)?} $l match what width amount set what [string tolower $what] while {!$eoc} { gets $fid nl if {[string match -nocase "" $nl] || [eof $fid]} {set eoc 1} else {append rep1 $nl} } switch -glob $what { partyline { foreach e $csy(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:dfl $rep2] } continue } bans { for {set i 0} {$i <= [llength $csx(chbans)]} {incr i} { regsub !!BAN $rep1 [lindex $csx(chbans) $i] rep2 while {[string match *!!BAN* $rep2]} {incr i; regsub !!BAN $rep2 [lindex $csx(chbans) $i] rep2} puts $html [cs:dfl $rep2] } continue } activity { if {$width == 0} { putlog "CHATstats: Syntax error in template $input, must be: (see file INSTALLATION for help)" continue } foreach e [array names csa *$c] {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 $rep2 } continue } chanusers { foreach n $csx(chul) { set n [cs:dfl $n]; set ni [string range $n 1 end]; set u [clock seconds] if {![onchan $ni $c]} {continue} set gcj [getchanjoin $ni $c] if {$gcj > 0} {set gcj "[expr round((($u-$gcj)/60)/60)]h:[expr round(fmod((($u-$gcj)/60),60))]m"} else {set gcj "N/A"} if {[nick2hand $ni $c] == "*"} {set flags "-"} else {set flags [chattr $ni $c]} if {$flags == "*"} {set flags "-"} regsub -all "!!USER" $rep1 $n rep2 regsub -all "!!HOST" $rep2 [string range [getchanhost $ni] 0 45] rep2 regsub -all "!!DUR" $rep2 $gcj rep2 regsub -all "!!IDLE" $rep2 "[getchanidle $n $c]m" rep2 regsub -all "!!FLAGS" $rep2 $flags rep2 puts $html $rep2 } continue } top* { if {$width == 0 || $amount == 0} { putlog "CHATstats: Syntax error in template $input, must be: (see file INSTALLATION for help)" 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} topactiveusers {} default {putlog "CHATstats: unknown listing found in template $what - aborting (see file INSTALLATION for help)."; return} } switch -exact $what { topactiveusers { foreach e [array names csu *$c] { lappend list "[lindex $csu($e) 0] [expr [lindex $csu($e) 3] - [lindex $csu($e) 13]]" } } default { foreach e [array names csu *$c] { 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 switch -exact $what { topactiveusers {regsub -all "!!VALUE" $rep2 [cs:dur $int] rep2} topvisitors {regsub -all "!!VALUE" $rep2 [cs:dur $int] rep2} topidlers {regsub -all "!!VALUE" $rep2 [cs:dur $int] rep2} default {regsub -all "!!VALUE" $rep2 [cs:fmt $int] rep2} } regsub -all "!!PERCENT" $rep2 "$x%" rep2 regsub -all "!!WIDTH" $rep2 $barlength rep2 puts $html [cs:dfl $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:cv $c set csc($c) [lreplace $csc($c) 4 4 $j] set csc($c) [lreplace $csc($c) 5 5 [clock seconds]] cs:save } } proc cs:date {c what} { global cs csc switch -exact $what { curr {return [strftime "%A, %d.%m.%Y, %H:%M" [expr [clock seconds] + $cs(timebalance) * 3600]]} nu {if {[lindex $csc($c) 2] == 0} {return [strftime %H:%M [expr [clock seconds] + ($cs(timebalance) * 3600) + ($cs(update) * 60)]]} else {return "N/A"}} sta {set i 1} sto {set i 2} lr {set i 3} peak {set i 5} } if {[lindex $csc($c) $i] == 0} {return "N/A"} else {return [strftime "%d.%m.%Y" [expr [lindex $csc($c) $i] + $cs(timebalance) * 3600]]} } proc cs:reset {w} { global cs csu set jt [lindex $csu($w) 1]; set u [clock seconds]; set nic [lindex [split $w #] 0] set c "#[lindex [split $w #] 1]"; set ls [lindex $csu($w) 12]; set idle 0 if {$jt > 0} { set csu($w) [lreplace $csu($w) 3 3 [expr [lindex $csu($w) 3] + ($u - $jt)]] set csu($w) [lreplace $csu($w) 1 1 0] if {$ls > 0} {set idle [expr $u - $ls]} else {set idle [expr $u - $jt]} } 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:dur {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:cv {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:cv $c if {$n == "\*"} {set n "Unknown"} set cst($c) "$n on [cs:date $c curr]" } proc cs:fltpc {n} { regsub -all {|||(([0-9])?([0-9])?(\,([0-9])?([0-9])?)?)?|([0-9A-F][0-9A-F])?} $n "" n return $n } proc cs:fl {n} { regsub -all \\\[ $n !2 n; regsub -all \\\] $n !3 n regsub -all \\\{ $n !5 n; regsub -all \\\} $n !4 n regsub -all \\\^ $n !6 n; regsub -all \\\" $n !7 n regsub -all \\\\ $n !1 n; return $n } proc cs:dfl {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:fmt {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 7356162460 13732 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 22316 7356162503 16130 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 active users:

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

Total active chatting time: %%TOTALACTIVE (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 7356162507 12601 0ustar baerchenbaerchenGIF89a ¢Óæ..êRRîvvò˜˜îttêTTÔ, !C4"€;toptalls.global.template100644 1751 1751 7472 7356162514 15562 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