# # Chanstats v1.3 (21/6/97) for eggdrop 1.x # by Ernst # ============================================================================= # # NOTE: Chanstats needs at least TCL version 7.6! If you are running 7.4, I # recommend upgrading to the latest stable version, 7.6pl2, avaliable at # ftp://ftp.sunlabs.com/pub/tcl. (recompile eggdrop after installing TCL) # # Please read the README file! # # To install: # =========== # - Change the variables below to reflect your environment # - Add the script to your bots config to be loaded on start # - Copy all the gif's to the same directory the stats page with reside # - Do a 'chmod 644 *.gif' in that dir so they become accessible through www # - .rehash the bot, and things should start auto-magically in 2 minutes # - If the page is not accessible, 'chmod 644' it after it is created once # # Have fun! # # ============================================================================= #### Stats *VITAL* configuration ############################################## # Location of statspages (do *NOT* include file extention!!) set statspage(#aide) "/aide/www/bot/aide" set statspage(#cours) "/aide/www/bot/cours" # The full URLs of where the pages will end (again, do *NOT* include the .htm) set statspage_url(#aide) "http://www.aide.igt.net/bot/aide" set statspage_url(#cours) "http://www.aide.igt.net/bot/cours" # What file extention to use in the above files set statsext "html" # Timezone your bot sits in (used in output only) if {![info exists timezone]} { set timezone "GMT-6" } #### Stats layout configuration ############################################### # Do you want to make the graph using the .gif's? (0 = no) # Don't forget to copy all gifs to the same dir where the stats pages will go! set statsgif 1 # Display the values after the bars in the graphs? (1 = yes) set graphnumbers 1 # Separate data for bots (+b flag) and normal users # 0 = bots are treated as normal users # 1 = bots are separated from other users set statsbotsalone 1 # Shows all user names in current ocupancy and peak stats? (0 = show none) set statsusers 1 # Shows all bans recorded in the bot (0 = just currently active on chan) set statsbansall 0 # Maximum width of some data shown in result page (in chars) set statshtmlmaxwidth 76 #### Stats functionality configuration ######################################## # Interval between stats pages update. set statsinterval 5 # Announce stats page on channel (once a day, will not hurt anybody) (0 = no) set statsannounce 0 # Execute something right after the stats page are created? Used for example # to upload your stats page to another server. May be an internal tcl proc # (e.g "putftp bla bla bla") or external (e.g "exec sh ~/Egg/putstats.sh"). # Specify as much commands as you want, one each line, surrounded bny "'s. # I have included my sendftp.tcl which can be used here. Another use of this # would be to chmod the file each time it is generated to guarantee it to be # accessible through the web. #set statsexec { # "exec /bin/chmod 644 /home/ernst/public_html/brasil/stats.htm" # "sendftp /home/bill/stats.htm www.gov.org bill secret /home/bgates/public_html/stats.htm" #} # Files to be used to store stats data (.stats.#chan & .stats.#chan.cache) set statsfile ".stats" # ============================================================================= # -- and here comes the script... --------------------------------------------- set statsver "1.3" set statserr [catch {clock scan "01/01/80 12:00:00 AM GMT"}] if {$statserr > 0} { putlog "chanstats: You need at least TCL 7.6 to run this script, sorry! :(" } { set statserr [catch {file exists just.a.test}] if {$statserr > 0} { putlog "chanstats: You need at least TCL 7.6 to run this script, sorry! :(" } } # -- procs binded to irc events ----------------------------------------------- # On join count joins, checks for a peak and checks if it is the bot joining proc stats_join {nick uhost hand chan} { global stats botnick set chan [string tolower $chan] set inchannel [llength [chanlist $chan]] if {[info exists stats(join!$chan)]} { incr stats(join!$chan) } if {[info exists stats(peak!$chan)]} { if {$inchannel >= [lindex $stats(peak!$chan) 0]} { unset stats(peak!$chan) lappend stats(peak!$chan) $inchannel lappend stats(peak!$chan) [clock seconds] lappend stats(peak!$chan) [lsort -command icompare [chanlist $chan]] # If it is a peak, save cache immediatelly savecache $chan } } { lappend stats(peak!$chan) $inchannel lappend stats(peak!$chan) [clock seconds] lappend stats(peak!$chan) [lsort -command icompare [chanlist $chan]] savecache $chan } if {$nick == $botnick} { set stats(botin!$chan) [clock seconds] } return 0 } proc stats_part {nick uhost hand chan partmsg} { global stats set chan [string tolower $chan] if {[info exists stats(part!$chan)]} { incr stats(part!$chan) } return 0 } proc stats_sign {nick uhost hand chan reason} { global stats set chan [string tolower $chan] if {[info exists stats(quit!$chan)]} { incr stats(quit!$chan) } return 0 } proc stats_kick {nick uhost hand chan kicked reason} { global stats set chan [string tolower $chan] if {[info exists stats(kick!$chan)]} { incr stats(kick!$chan) } return 0 } proc stats_nick {nick uhost hand chan newnick} { global stats set chan [string tolower $chan] if {[info exists stats(nick!$chan)]} { incr stats(nick!$chan) } return 0 } proc stats_splt {nick uhost hand chan} { global stats set chan [string tolower $chan] if {[info exists stats(splt!$chan)]} { incr stats(splt!$chan) } return 0 } proc stats_rejn {nick uhost hand chan} { global stats set chan [string tolower $chan] if {[info exists stats(rejn!$chan)]} { incr stats(rejn!$chan) } return 0 } set smnick "" set smuhost "" set smhand "" set smchan "" set smmodechange "" set smvictim "" proc stats_mode {nick uhost hand chan modechange victim} { global smnick smuhost smhand smchan smmodechange smvictim set smnick $nick set smuhost $uhost set smhand $hand set smchan $chan set smmodechange $modechange set smvictim $victim if [catch stats_mode_nobug] { # Bug dans la fonction ... } } proc stats_mode_nobug {} { global smnick smuhost smhand smchan smmodechange smvictim set nick $smnick set uhost $smuhost set hand $smhand set chan $smchan set modechange $smmodechange set victim $smvictim global stats set chan [string tolower $chan] set modechange "$modechange $victim" # It was an op if {[string tolower [lindex $modechange 0]] == "+o"} { if {[info exists stats(op!$chan)]} { incr stats(op!$chan) } # It was a deop } elseif {[string tolower [lindex $modechange 0]] == "-o"} { if {[info exists stats(deop!$chan)]} { incr stats(deop!$chan) } # It was a +v } elseif {[string tolower [lindex $modechange 0]] == "+v"} { if {[info exists stats(voic!$chan)]} { incr stats(voic!$chan) } # It was a -v } elseif {[string tolower [lindex $modechange 0]] == "-v"} { if {[info exists stats(devc!$chan)]} { incr stats(devc!$chan) } } return 0 } # On raw 001 save this time as 'connected to server' time proc stats_connected {text} { global stats set stats(server) [clock seconds] return 0 } # -- store topic -------------------------------------------------------------- bind topc - * stats_topc # Saves new topic when changed and who set it proc stats_topc {nick uhost hand chan topic} { global chtopic set chan [string tolower $chan] if {$nick == "*" && [info exists chtopic(topic!$chan)]} { if {$topic == $chtopic(topic!$chan)} { # Topic not changed, bot just rejoined return 0 } } set chtopic(topic!$chan) $topic if {$nick == "*"} { # When bot first joins the chan set chtopic(nick!$chan) "inconnu" } { set chtopic(nick!$chan) "$nick!$uhost" } set chtopic(time!$chan) [clock seconds] return 0 } # Proc to get topic of a channel: # [topic #chan topic] = Current topic # [topic #chan nick] = Who set it # [topic #chan unixtime] = When was it set proc topic { channel what } { global chtopic set channel [string tolower $channel] switch [string tolower $what] { "topic" { if {[info exist chtopic(topic!$channel)]} { return $chtopic(topic!$channel) } { return "inconnu" } } "nick" { if {[info exist chtopic(nick!$channel)]} { return $chtopic(nick!$channel) } { return "inconnu" } } "unixtime" { if {[info exist chtopic(time!$channel)]} { return $chtopic(time!$channel) } { return "0" } } default { if {[info exist chtopic(topic!$channel)]} { return $chtopic(topic!$channel) } { return "inconnu" } } } } # -- misc routines ------------------------------------------------------------ # Comparasion ignoring case for sorting purpose proc icompare {arg1 arg2} { return [string compare [string tolower $arg1] [string tolower $arg2]] } # Repeats 'char' 'ammount' times proc repchar { char ammount } { set output "" while {[string length $output] < $ammount} { set output "$char$output" } return $output } # Wordwrap returns a list where each element is a string with max 'len' width. # Words from 'input' are split in lines on spaces (wordwrapping, you know...) proc wordwrap {input len} { set pos 1 while {$pos > 0} { set pos [string last " " [string range $input 0 $len]] if {[string length $input] < $len} { lappend thelist "[string range $input 0 end]" set pos 0 } { lappend thelist "[string range $input 0 $pos]" } set input "[string range $input [expr $pos + 1] end]" } return $thelist } # Makes HTML bars for graphs, looks very cool :) proc makebars { quant color ascii } { set result "" set first 1 set part $quant set comp {} for {set i 5} {$i >= 0} {incr i -1} { set exp [expr int(pow(2,$i))] set ammount [expr $part / $exp] if {$ammount > 0} { lappend comp "$exp $ammount" set part [expr $part - [expr $ammount * $exp]] } } foreach this $comp { for {set i 0} {$i < [lindex $this 1]} {incr i} { if {$first} { set result "${result}\"[repchar" set first 0 } { set result "${result}\"\"" } } } return $result } # Input = unixtime, returns a string in format "x days, y mins, etc" proc for_time { input } { # Algorythm stolen from Floyd's implementation in seen: set totalyear [expr [clock seconds] - $input] if {$totalyear < 60} { return "less then a minute" } if {$totalyear > 31536000} { set yearsfull [expr $totalyear/31536000] set years [expr int($yearsfull)] set yearssub [expr 31536000*$years] set totalday [expr $totalyear - $yearssub] } if {$totalyear < 31536000} { set totalday $totalyear set years 0 } if {$totalday >= 86400} { set daysfull [expr $totalday/86400] set days [expr int($daysfull)] set dayssub [expr 86400*$days] set totalhour [expr $totalday - $dayssub] } if {$totalday < 86400} { set totalhour $totalday set days 0 } if {$totalhour > 3600} { set hoursfull [expr $totalhour/3600] set hours [expr int($hoursfull)] set hourssub [expr 3600*$hours] set totalmin [expr $totalhour - $hourssub] } if {$totalhour < 3600} { set totalmin $totalhour set hours 0 } if {$totalmin >= 60} { set minsfull [expr $totalmin/60] set mins [expr int($minsfull)] } if {$totalmin < 60} { set mins 0 } # Changed a bit from floyd if {$years < 1} {set yearstext ""} elseif {$years == 1} {set yearstext "$years année, "} {set yearstext "$years années, "} if {$days < 1} {set daystext ""} elseif {$days == 1} {set daystext "$days jour, "} {set daystext "$days jours, "} if {$hours < 1} {set hourstext ""} elseif {$hours == 1} {set hourstext "$hours heure, "} {set hourstext "$hours heures, "} if {$mins < 1} {set minstext ""} elseif {$mins == 1} {set minstext "$mins minute"} {set minstext "$mins minutes"} set output $yearstext$daystext$hourstext$minstext set output [string trimright $output " "] set output [string trimright $output ","] return "$output" } # Returns the time your bot is up, or the time since you last made a .restart proc botuptime {} { global stats_loaded if {![info exists stats_loaded]} { return "délais inconnu" } return [for_time $stats_loaded] } # Returns the time the bot is connected to the current server, # (or the time since you last made a .restart) proc connectedtime {} { global stats if {![info exists stats(server)]} { return "délais inconnu" } if {$stats(server) == -1} { return "délais inconnu" } return [for_time $stats(server)] } # Returns the time your bot is sitting in the specified channel proc channeltime {chan} { global stats set chan [string tolower $chan] if {![info exists stats(botin!$chan)]} { return "délais inconnu" } if {$stats(botin!$chan) == -1} { return "délais inconnu" } return [for_time $stats(botin!$chan)] } # -- the actual page generator ------------------------------------------------ # A generic "make graph" function to be also used in the future to generate # other stats graphs. Provides a flexible scale, asc/gif output, and coloured # bars (bl = blue etc) from a given input (in 'indata' format). proc makegraph {out indata} { # 'indata' is a list of lists in this format: # {hour {qnt color asc} {qnt color asc} ...} {hour {qnt color asc} ...} ... # 'hour's must be already sorted! {qnt color asc} is ONE coloured bar global statsgif graphnumbers # How many chars represent the max value in the scale (for ascii output) set maxascii 60 # How many "gif-blocks" are the max value in a scale (for gif output) set maxgif 50 # Color translation to Netscape HTMLs set color(bl) "0000ff" set color(gr) "f06000" set color(or) "00c800" set color(rd) "ff0000" set topsum 0 set tmpsum 0 # Gets the maximum value of the graph foreach thishour $indata { foreach thisdata [lrange $thishour 1 end] { scan [lindex $thisdata 0] %d i incr tmpsum $i } if {$tmpsum > $topsum} { set topsum $tmpsum } set tmpsum 0 } # We now have 50, 100, 200, 500 and 1000 scale flavors set scale 50 if {$topsum > 50} { set scale 100 } if {$topsum > 100} { set scale 200 } if {$topsum > 200} { set scale 500 } if {$topsum > 500} { set scale 1000 } # Print a header if {$statsgif} { puts $out "" puts $out " " } { puts $out "" # Haven't found an algorythm to generate these if {$scale == 50} { puts $out " 1 1 2 2 3 3 4 4 5" puts $out " 5 0 5 0 5 0 5 0 5 0" } elseif {$scale == 100} { puts $out " 1" puts $out " 1 2 3 4 5 6 7 8 9 0" puts $out " 0 0 0 0 0 0 0 0 0 0" } elseif {$scale == 200} { puts $out " 1 1 1 1 1 2" puts $out " 2 4 6 8 0 2 4 6 8 0" puts $out " 0 0 0 0 0 0 0 0 0 0" } elseif {$scale == 500} { puts $out " 1 1 2 2 3 3 4 4 5" puts $out " 5 0 5 0 5 0 5 0 5 0" puts $out " 0 0 0 0 0 0 0 0 0 0" } elseif {$scale == 1000} { puts $out " 1" puts $out " 1 2 3 4 5 6 7 8 9 0" puts $out " 0 0 0 0 0 0 0 0 0 0" puts $out " 0 0 0 0 0 0 0 0 0 0" } } set hourcount 0 set curridx 0 # Makes the graph, from 00 to 23th o'clock while { $hourcount < 24 } { if {$curridx >= [llength $indata]} { # puts $out " [format %02d $hourcount] ~" incr hourcount continue } scan [lindex [lindex $indata $curridx] 0] %d i if {$i != $hourcount} { puts $out " [format %02d $hourcount] ~" incr hourcount continue } set thisnumb "" set total 0 set thisdeed " [format %02d $hourcount] " if {$statsgif} { foreach data [lrange [lindex $indata $curridx] 1 end] { scan [lindex $data 0] %d i set thisdeed "$thisdeed[makebars [expr round((double($i) / $scale) * $maxgif)] [lindex $data 1] [lindex $data 2]]" if {$graphnumbers} { if {[lindex $data 0] != 0} { set thisnumb "${thisnumb} [lindex $data 0]" } incr total [lindex $data 0] } } if {$graphnumbers} { set thisnumb "$thisnumb ($total)" } puts $out "$thisdeed$thisnumb" } { foreach data [lrange [lindex $indata $curridx] 1 end] { scan [lindex $data 0] %d i set thisdeed "$thisdeed[repchar [lindex $data 2] [expr round((double($i) / $scale) * $maxascii)]]" if {$graphnumbers} { if {[lindex $data 0] != 0} { set thisnumb "${thisnumb}/[lindex $data 0]" } incr total [lindex $data 0] } } set thisnumb [string trimleft $thisnumb "/"] puts $out "$thisdeed $thisnumb ($total)" } incr curridx incr hourcount } } # Makes the html page from current data proc makepage {chan} { global statspage timezone statsinterval statsver stats statsfile global version statsver statshtmlmaxwidth statspage_url statsbotsalone global statsgif server statsext statsusers statsbansall botnick # Page header set out [open $statspage($chan).$statsext w] puts $out "" puts $out "Les statistiques de $chan (À [time] le [date])" puts $out "" puts $out "" puts $out "
Les Statistiques de $chan par AideBot
" if {[time] != "23:59"} { if {$chan == "#aide"} { set notchan "cours" } else { set notchan "aide" } puts $out "Pour #$notchan cliquez ici." } # Are there stats for yesterday? if {[file exists $statspage($chan).old.$statsext]} { set yesterday [clock format [file mtime $statspage($chan).old.$statsext] -format "%d %b %y"] puts $out "

" } # Page sections. Uncomment the ones you don't want or change their order # - Channel topic if {[time] != "23:59"} { puts $out "

Topic: [topic $chan topic]
" puts $out "
(activé par [topic $chan nick] le [ctime [topic $chan unixtime]])
" puts $out "

" } #autre script... if {[string range [time] 0 3] != "00:5"} { if {![onchan $botnick $chan]} { puts $out "Je ne suis présentement pas sur $chan, Essaie un peu plus tard." puts $out

} puts $out "

" puts $out "" puts $out "" puts $out "" foreach b [chanlist $chan] { set c "" if {[isop $b $chan]} {set q "@"} {set q ""} if {[isvoice $b $chan]} {set q "+"} if {$botnick == $b} {puts $out ""} if {$botnick != $b} { set hand [nick2hand $b $chan] if [matchattr [nick2hand $b $chan] b] { set c " , (Bot)" } puts $out "" if {$hand != "*"} { if [matchattr [nick2hand $b $chan] b] { puts $out "" } else { puts $out "" } } } } puts $out "
$chan, [getchanmode $chan]
AliasStatut/InfoAdresse
$q$b<-- C'est moi ça!
$q$bInactif [getchanidle $b $chan] min$c[getchanhost $b $chan]
[getuser [nick2hand $b $chan] XTRA NIV]
Niveau: [dire_niveau [nick2hand $b $chan]]

" puts $out "
" } #fin autre script... # - Current users set thebots "" set theops "" set theusers "" set thevoice "" set bots 0 set ops 0 set users 0 set voice 0 set total 0 foreach nick [chanlist $chan] { incr total if {([matchattr [nick2hand $nick $chan] b]) && ($statsbotsalone)} { if {$statsusers} { lappend thebots $nick } incr bots } elseif {[isop $nick $chan]} { if {$statsusers} { lappend theops $nick } incr ops } elseif {[isvoice $nick $chan]} { if {$statsusers} { lappend thevoice $nick } incr voice } { if {$statsusers} { lappend theusers $nick } incr users } } # This looks kinda messy, but works (I hope) set theops [subst -nocommands [lsort -command icompare $theops]] set theusers [subst -nocommands [lsort -command icompare $theusers]] regsub -all " " $theops ", " theops regsub -all " " $theusers ", " theusers # Make lists of strings at the proper size to fit the page set theops [wordwrap $theops [expr $statshtmlmaxwidth - 17]] set theusers [wordwrap $theusers [expr $statshtmlmaxwidth - 17]] puts $out "


Statistiques des usagers

    " puts $out "
    "
    	if {$statsbotsalone} {
    		# Don't show the names of the bots, just count them
    		puts $out "   Bots: [format %3s $bots]"
    	}
    	# Lists of ops in chan (line 1)
    	puts $out "    Ops: [format %3s $ops] [lindex $theops 0]"
    	# Prints rest of array, one item per line, if avaliable
    	if {[llength $theops] > 1} {
    		foreach nextops [lrange $theops 1 end] {
    			puts $out "             $nextops"
    		}
    	}
    	# The same for voiced users
    	puts $out "Aidants: [format %3s $voice] [lindex $thevoice 0]"
    	if {[llength $thevoice] > 1} {
    		foreach nextvoice [lrange $thevoice 1 end] {
    			puts $out "             $nextvoice"
    		}
    	}
    	# The same goes for other users
    	puts $out "Usagers: [format %3s $users] [lindex $theusers 0]"
    	if {[llength $theusers] > 1} {
    		foreach nextusers [lrange $theusers 1 end] {
    			puts $out "               $nextusers"
    		}
    	}
    	puts $out "------------"
    	puts $out "  Total: [format %3s $total]"
    	puts $out "
    " puts $out "
" # - Current bans puts $out "


Bans sur $chan

    " puts $out "
    "
    	set banwidth1 [expr $statshtmlmaxwidth - 42]
    	set banwidth2 [expr $banwidth1 + 12]
    	if {$statsbansall} {
    		puts $out " G = bot global ban   C = bot channel ban  U = user ban"
    		puts $out ""
    		puts $out [format %-2s%-${banwidth1}s%-10s%-30s "" "hostmask" "creator" "comment"]
    	} {
    		puts $out "  masques d'adresse bannis"
    	}
    	puts $out [repchar "-" $statshtmlmaxwidth]
    	if {$statsbansall} {
    		foreach thisban [banlist] {
    			set thecomment [wordwrap [lindex $thisban 1] 30]
    			puts $out [format %-2s%-${banwidth1}s%-10s%-30s "G" [lindex $thisban 0] [lindex $thisban 5] [lindex $thecomment 0]]
    			if {[llength $thecomment] > 1} {
    				foreach nextcomment [lrange $thecomment 1 end] {
    					puts $out [format %-${banwidth2}s%-30s "" $nextcomment]
    				}
    			}
    			lappend otherbans [string tolower [lindex $thisban 0]]
    		}
    		foreach thisban [banlist $chan] {
    			set thecomment [wordwrap [lindex $thisban 1] 30]
    			puts $out [format %-2s%-${banwidth1}s%-10s%-30s "C" [lindex $thisban 0] [lindex $thisban 5] [lindex $thecomment 0]]
    			if {[llength $thecomment] > 1} {
    				foreach nextcomment [lrange $thecomment 1 end] {
    					puts $out [format %-${banwidth2}s%-30s "" $nextcomment]
    				}
    			}
    			lappend otherbans [string tolower [lindex $thisban 0]]
    		}
    	}
    	if {![info exist otherbans]} { set otherbans "" }
    	foreach thisban [chanbans $chan] {
    		if {[lsearch $otherbans [string tolower $thisban]] == -1} {
    			if {$statsbansall} {
    				puts $out [format %-2s%-${banwidth1}s%-10s%-30s "U" $thisban "-" "-"]
    			} {
    				puts $out "  $thisban"
    			}
    		}
    	}
    	unset banwidth1
    	unset banwidth2
    	unset otherbans
    	puts $out "
    " puts $out "
" # - Usage graphic puts $out "


Statistiques du canal par heure (en moyenne)

    " puts $out "
    "
    	if {$statsgif} {
    		if {$statsbotsalone} {
    			puts $out " \"+\" bot     \"=\" op      \"*\" aidant  \"-\" usager  ~ pas d'information"
    		} {
    			puts $out " \"=\" op      \"*\" aidant  \"-\" usager  ~ pas d'information"
    		}
    	} {
    		if {$statsbotsalone} {
    			puts $out " + bot     = op      * aidant  - usager  ~ pas d'information"
    		} {
    			puts $out " = op      * aidant  - usager  ~ pas d'information"
    		}
    	}
    
    	# Collect saved data and make graph
    	set in [open $statsfile.[string tolower $chan] r]
    	catch {unset graphdata}
    	set input "---"
    	set count 1
    	set lasthour ""
    	while {$input != ""} {
    		set input [gets $in]
    		set thishour [string range $input 0 1]
    		if {$thishour != $lasthour} {
    			if {![info exist statscount(bot!$thishour)]} {
    				set statscount(bot!$thishour) [lindex [string range $input 3 end] 0]
    				set statscount(op!$thishour) [lindex [string range $input 3 end] 1]
    				set statscount(user!$thishour) [lindex [string range $input 3 end] 2]
    				set statscount(voice!$thishour) [lindex [string range $input 3 end] 3]
    			}
    			if {$lasthour != ""} {
    				# Calculates the average
    				set tempcount(bot!$lasthour) [expr round([expr $statscount(bot!$lasthour) / double($count)])]
    				set tempcount(op!$lasthour) [expr round([expr $statscount(op!$lasthour) / double($count)])]
    				set tempcount(user!$lasthour) [expr round([expr $statscount(user!$lasthour) / double($count)])]
    				if {[info exist statscount(voice!$lasthour)]} {
    					set tempcount(voice!$lasthour) [expr round([expr $statscount(voice!$lasthour) / double($count)])]
    				} {
    					set tempcount(voice!$lasthour) 0
    				}
    				# Appends data to list
    				catch "unset tmpdata"
    				lappend tmpdata "$lasthour"
    				lappend tmpdata "$tempcount(bot!$lasthour) bl +"
    				lappend tmpdata "$tempcount(op!$lasthour) gr +"
    				lappend tmpdata "$tempcount(voice!$lasthour) or ="
    				lappend tmpdata "$tempcount(user!$lasthour) rd *"
    				lappend graphdata $tmpdata
    				set count 1
    			}
    			set lasthour "$thishour"
    		} {
    			# Next acumulated data
    			set statscount(bot!$thishour) [expr $statscount(bot!$thishour) + [lindex [string range $input 3 end] 0]]
    			set statscount(op!$thishour) [expr $statscount(op!$thishour) + [lindex [string range $input 3 end] 1]]
    			set statscount(user!$thishour) [expr $statscount(user!$thishour) + [lindex [string range $input 3 end] 2]]
    		   	set statscount(voice!$thishour) [expr $statscount(voice!$thishour) + [lindex [string range $input 3 end] 3]]
    			incr count
    		}
    	}
    	if {[info exists graphdata]} {
    		makegraph $out $graphdata
    	}
    	close $in
    	puts $out "
    " puts $out "" # - Peak usage that day puts $out "


    Pointe d'utilisation aujourd'hui

      " puts $out "
      "
      	puts $out " Pointe: [lindex $stats(peak!$chan) 0]"
      	puts $out "  Heure: [format %3s [clock format [lindex $stats(peak!$chan) 1] -format "%H:%M:%S"]]"
      	# Prints peak users using wordwrapping
      	if {$statsusers} {
      		set peakusers [subst -nocommands [lindex $stats(peak![string tolower $chan]) 2]]
      		regsub -all " " $peakusers ", " peakusers
      		set peakusers [wordwrap $peakusers [expr $statshtmlmaxwidth - 16]]
      		puts $out "Usagers: [lindex $peakusers 0]"
      		# Prints rest of array, one item per line, if avaliable
      		if {[llength $peakusers] > 1} {
      			foreach nextpeak [lrange $peakusers 1 end] {
      				puts $out "         $nextpeak"
      			}
      		}
      	}
      	puts $out "
      " puts $out "" # - General stats (joins, kicks, etc) puts $out "


      Statistiques générales du jour

        " puts $out "
        "
        	puts $out "             Joins: [format %3s $stats(join!$chan)]"
        	puts $out "    Part/Quit/Kick: [format %3s [expr $stats(part!$chan) + $stats(quit!$chan) + $stats(kick!$chan)]] Total \($stats(part!$chan)/$stats(quit!$chan)/$stats(kick!$chan)\)"
        	puts $out "Changement d'alias: [format %3s $stats(nick!$chan)]"
        	puts $out "        Mode +o/-o: [format %3s $stats(op!$chan)]/$stats(deop!$chan)"
        	puts $out "        Mode +v/-v: [format %3s $stats(voic!$chan)]/$stats(devc!$chan)"
        	puts $out "    Splits/Retours: [format %3s $stats(splt!$chan)]/$stats(rejn!$chan)"
        	puts $out "
        " puts $out "" # - Bots uptime puts $out "


        État du bot

          " puts $out "
          "
          	puts $out "AideBot roule depuis [botuptime]."
          	if {$stats(server) != -1} {
          		puts $out "Branché à [string range $server 0 [expr [string first ":" $server] - 1]] depuis [connectedtime]."
          	}
          	puts $out "Dans le canal $chan depuis [channeltime $chan]."
          	puts $out "
          " puts $out "" # Footer puts $out "
          " # if {$statsgif} { puts $out "\"\"" } puts $out "
          [date] [time]" # puts $out "Updating each $statsinterval minutes

          " # Close html file gracefully (yeah, html specs rule) puts $out "
          " close $out return 1 } # Save current data in a cache file, in case of bot going down proc savecache {chan} { global statsver stats statsfile botnick set chan [string tolower $chan] set out [open $statsfile.$chan.cache w] puts $out $statsver puts $out [date] if {[info exists stats(join!$chan)]} { puts $out $stats(join!$chan) } { puts $out 0 } if {[info exists stats(part!$chan)]} { puts $out $stats(part!$chan) } { puts $out 0 } if {[info exists stats(kick!$chan)]} { puts $out $stats(kick!$chan) } { puts $out 0 } if {[info exists stats(quit!$chan)]} { puts $out $stats(quit!$chan) } { puts $out 0 } if {[info exists stats(nick!$chan)]} { puts $out $stats(nick!$chan) } { puts $out 0 } if {[info exists stats(op!$chan)]} { puts $out $stats(op!$chan) } { puts $out 0 } if {[info exists stats(deop!$chan)]} { puts $out $stats(deop!$chan) } { puts $out 0 } if {[info exists stats(voic!$chan)]} { puts $out $stats(voic!$chan) } { puts $out 0 } if {[info exists stats(devc!$chan)]} { puts $out $stats(devc!$chan) } { puts $out 0 } if {[info exists stats(splt!$chan)]} { puts $out $stats(splt!$chan) } { puts $out 0 } if {[info exists stats(rejn!$chan)]} { puts $out $stats(rejn!$chan) } { puts $out 0 } if {[info exists stats(peak!$chan)]} { puts $out $stats(peak!$chan) } { if {[onchan $botnick $chan]} { lappend peak [llength [chanlist $chan]] lappend peak [clock seconds] lappend peak [lsort -command icompare [chanlist $chan]] puts $out "$peak" unset peak } { puts $out "0 [clock seconds] \{\}" } } close $out } # Resets all stats for a chan. Done once a day in stats_doit proc resetstats {chan} { global stats botnick putlog "chanstats: Reseting stats for $chan" set chan [string tolower $chan] set stats(join!$chan) 0 set stats(part!$chan) 0 set stats(kick!$chan) 0 set stats(quit!$chan) 0 set stats(nick!$chan) 0 set stats(op!$chan) 0 set stats(deop!$chan) 0 set stats(voic!$chan) 0 set stats(devc!$chan) 0 set stats(splt!$chan) 0 set stats(rejn!$chan) 0 if {[onchan $botnick $chan]} { lappend peak [llength [chanlist $chan]] lappend peak [clock seconds] lappend peak [lsort -command icompare [chanlist $chan]] set stats(peak!$chan) $peak unset peak } { set stats(peak!$chan) "0 [clock seconds] \{\}" } } # Restores all data in cache in case of bot going up after a down proc restorecache {chan} { global statsver stats statsfile stats_going set chan [string tolower $chan] if {![file exists $statsfile.$chan.cache]} { # No cache exists, must start from ZERO resetstats $chan } { # Cache file is here, load it set in [open $statsfile.$chan.cache r] set thisver [gets $in] if {$thisver != $statsver} { putlog "chanstats: It looks like you just upgraded from $thisver to $statsver. Have fun! :\)" resetstats $chan close $in return 0 } putlog "chanstats: Restoring cache for $chan" set stats(date!$chan) [gets $in] set stats(join!$chan) [gets $in] set stats(part!$chan) [gets $in] set stats(kick!$chan) [gets $in] set stats(quit!$chan) [gets $in] set stats(nick!$chan) [gets $in] set stats(op!$chan) [gets $in] set stats(deop!$chan) [gets $in] set stats(voic!$chan) [gets $in] set stats(devc!$chan) [gets $in] set stats(splt!$chan) [gets $in] set stats(rejn!$chan) [gets $in] set stats(peak!$chan) [gets $in] close $in } } # Do the whole process once each $statsinterval minutes proc stats_doit {} { global difftogmt statsfile statspage statsinterval stats_going global botnick statsannounce statspage_url statsbotsalone statsexec global statsext # Wait again for 5 mins timer $statsinterval stats_doit set donesomething 0 foreach statschan [array names statspage] { # If bot is not in channel, nothing can be done :( if {[lsearch -exact [string tolower [channels]] [string tolower $statschan]] >= 0} { if {[onchan $botnick $statschan]} { if {($stats_going == 1) && ($statsannounce == 1) && [info exist statspage_url($statschan)]} { puthelp "PRIVMSG $statschan :Hi people! I am generating some stats about this channel at $statspage_url($statschan).$statsext ! Take a look at them!" set stats_going 2 } set lwrstatschan [string tolower $statschan] set donesomething 1 # Count users set bots 0 set ops 0 set voice 0 set users 0 foreach nick [chanlist $statschan] { if {([matchattr [nick2hand $nick $statschan] b]) && ($statsbotsalone)} { incr bots } elseif {[isop $nick $statschan]} { incr ops } elseif {[isvoice $nick $statschan]} { incr voice } else { incr users } } # Check to see if you are in a new day since last stats set thisday [expr ([clock seconds] + $difftogmt) / 86400] if {[file exists $statsfile.$lwrstatschan]} { set laststats [expr ([file mtime $statsfile.$lwrstatschan] + $difftogmt) / 86400] if {[expr $thisday - $laststats] == 1} { putlog "chanstats: Old stats found for $statschan (yesterday). Cycling" # Last stats saved are from yesterday, make backup and get ready # for new day file rename -force $statsfile.$lwrstatschan $statsfile.$lwrstatschan.yesterday if {[file exists $statspage($statschan).$statsext]} { file rename -force $statspage($statschan).$statsext $statspage($statschan).old.$statsext if {($statsannounce == 1) && ([info exist statspage_url($statschan)])} { puthelp "PRIVMSG $statschan :Hi! Accumulated stats for this channel for yesterday can be found at $statspage_url($statschan).old.$statsext !" } } resetstats $statschan } elseif {[expr $thisday - $laststats] > 1} { putlog "chanstats: Old stats found for $statschan (too old). Cycling" # New day has begun, delete old stats file delete -force $statsfile.$lwrstatschan if {[file exists $statspage($statschan).$statsext]} { file rename -force $statspage($statschan).$statsext $statspage($statschan).old.$statsext if {($statsannounce == 1) && ([info exist statspage_url($statschan)])} { puthelp "PRIVMSG $statschan :Hi! Accumulated stats for this channel for [expr $thisday - $laststats] days ago can be found at $statspage_url($statschan).old.$statsext!" } } resetstats $statschan } } # Saves data in cache set hour [clock format [clock seconds] -format %H] set out [open $statsfile.$lwrstatschan a+] puts $out "$hour:$bots $ops $users $voice" close $out savecache $statschan # Make the html page for current chan with current data if {[onchan $botnick $statschan]} { makepage $statschan } } { putlog "chanstats: I am not in $statschan. Could not update the stats page!" } } } if {$donesomething && [info exists statsexec]} { foreach thisexec $statsexec { if {[catch {eval $thisexec}]} { putlog "chanstats: Something wrong while executing: $thisexec" putlog " Please correct 'set statsexec' setting in chanstats" } } } } # Initialize the stats process once the bot is up (only if a good TCL is found) proc statsinit {} { global difftogmt statspage stats_going statsver statsinterval stats # Difference to GMT (to cycle at the right time. Hmm, isn't this strange?) set difftogmt [expr [clock scan "01/01/80 12:00:00 AM GMT"] - [clock scan "01/01/80 12:00:00 AM"]] # Binding of all events to keep track of statistics bind join - * stats_join bind part - * stats_part bind sign - * stats_sign bind kick - * stats_kick bind nick - * stats_nick bind mode - * stats_mode bind splt - * stats_splt bind rejn - * stats_rejn # Binds on a "connection" to log this (if compiled with USE_CONSOLE_R) set err [catch {bind raw - "% 001 *" stats_connected}] if {$err} { set stats(server) -1 putlog "chanstats: I recommend recompiling eggdrop with USE_CONSOLE_R defined" putlog " This will add the 'connected to server' stats output" } { if {![info exists stats(server)]} { set stats(server) [clock seconds] } } # Restores cached information when bot comes up if needed/possible foreach chan [array names statspage] { if {[lsearch -exact [string tolower [channels]] [string tolower $chan]] == -1} { putlog "chanstats: I am not monitoring $chan. How should I make the stats page?" unset statspage($chan) } { if {[info exists stats_going]} { # It's just a rehash, variables not lost, so don't restore anything putlog "chanstats: No cache restoration for $chan needed, already running" } { # The bot is going up or .restart was used restorecache $chan } } } if {![info exists stats_going]} { set stats_going 1 # Set everything up two minutes after bot is up # (time to enter all channels, set things up and get relaxed) timer 2 stats_doit } putlog "- chanstats v$statsver by Ernst loaded \($statsinterval mins interval\)" } # Only initialize if a TCL with clock/file support is found if {!$statserr} { statsinit } unset statserr if {![info exists stats_loaded]} { # "Uptime" information. Not very great, but works if noone does a .restart set stats_loaded [unixtime] }