#
# 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}
"
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 "$chan, [getchanmode $chan] |
"
puts $out "Alias | Statut/Info | Adresse |
"
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 "$q$b | <-- C'est moi ça! |
"}
if {$botnick != $b} {
set hand [nick2hand $b $chan]
if [matchattr [nick2hand $b $chan] b] { set c " , (Bot)" }
puts $out "$q$b | Inactif [getchanidle $b $chan] min$c | [getchanhost $b $chan] |
"
if {$hand != "*"} {
if [matchattr [nick2hand $b $chan] b] {
puts $out " | [getuser [nick2hand $b $chan] XTRA NIV] |
"
} else {
puts $out " | Niveau: [dire_niveau [nick2hand $b $chan]] |
"
}
}
}
}
puts $out "
"
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]
}