#################################
### BotnetStats.tcl           ###
### Version 1.6               ###
### By Wcc                    ###
### wcc@techmonkeys.org       ###
### http://dawg.oc255.net:81/ ###
### EFnet #|DAWG|Tcl          ###
#################################

############################################################################
### Copyright © 2000 - 2002 |DAWG| Scripting Group. All rights reserved. ###
############################################################################

####################################################################
## This script generates an HTML web page displaying the current  ##
## users on the partyline, a list of connected bots, and a map of ##
## the botnet.                                                    ##
####################################################################

##############
## COMMANDS ##
#######################################
## DCC ## .bhtml (Can be changed)    ##
######### Manually updates the stats ##
######### page.                      ##
#######################################

##########################################################
## Just load the script, edit the settings, and rehash. ##
##########################################################

################################################################
# Set the command used to manually update the stats page here. #
################################################################

set botnetstats_setting(command) "bhtml"

######################################################################
# Set the command used to remove a bot from the down bots list here. #
######################################################################

set botnetstats_setting(dcommand) "bdel"

###########################################################################
# Set the flag required to manually update the stats page and remove down #
# bots here.                                                              #
###########################################################################

set botnetstats_setting(flag) "+t"

################################################
# Set the filename of the stats web page here. #
################################################

set botnetstats_setting(page) "/wr/botnet.html"

###########################################################################
# Set the path to the DAWG template file you would like to use. You can   #
# obtain templates by visiting http://dawg.oc255.net:81/ and clicking the #
# templates link.                                                         #
###########################################################################

set botnetstats_setting(tpl) "./scripts/BotnetStats_DAWG.tpl"

#################################################
# Show users' hostmasks in the partyline table? #
#################################################

set botnetstats_setting(showparty) 0

#########################################
# How often should the data be updated? #
#########################################

set botnetstats_setting(timer) "60"

###############################################
# Show which server each bot is connected to? #
###############################################

set botnetstats_setting(showserver) 1

############################################################
# Set the directory in which to store database files here. #
############################################################

set botnetstats_setting(db) "./scripts/"

###################################
# Enable use of bold in DCC chat? #
###################################

set botnetstats_setting(bold) 1

###############################################
# Prefix "BOTNETSTATS:" in DCC chat messages? #
###############################################

set botnetstats_setting(BOTNETSTATS:) 1

####################
# Code begins here #
####################

if {![string match 1.6.* $version]} { putlog "\002BOTNETSTATS:\002 \002WARNING:\002 This script is intended to run on eggdrop 1.6.x or later." }
if {[info tclversion] < 8.2} { putlog "\002BOTNETSTATS:\002 \002WARNING:\002 This script is intended to run on Tcl Version 8.2 or later." }

bind dcc $botnetstats_setting(flag) $botnetstats_setting(command) botnetstats_man_update
bind dcc $botnetstats_setting(flag) $botnetstats_setting(dcommand) botnetstats_downdel
bind raw - 311 botnetstats_raw
bind raw - 312 botnetstats_raw
bind link - * botnetstats_link
bind disc - * botnetstats_link

set botnetstats_setting(version) "1.6"

set botnetstats_notpl 0
if {![info exists botnetstats_setting(tpl)] || [catch {source $botnetstats_setting(tpl)}]} {
	putlog "\002BOTNETSTATS:\002 Could not open template; using default."
	set botnetstats_notpl 1
}
foreach {s v} [list Page_CC #000000 Page_HC #000000 Page_LinkC #0000FF Page_TTextC #000000 Page_TextC #000000 Page_BGC #FFFFFF Page_TCC_2 #E0E0E0 Page_TCC_1 \
	#C0C0C0 Page_THC_2 #8080E0 Page_THC_1 #8080C0 Page_TCS 4  Page_THS 5 Page_TitleS 6 Page_Title {Botnet Status} Page_TitleTag {Botnet Status} Page_Img {} \
	Page_Linked_Bots 1 Page_Down_Bots 1 Page_Partyline 1 Page_Botnet_Map 1] {
		if {$botnetstats_notpl || ![info exists botnetstats_setting($s)]} { set $s $v  }
}
if {![string match "* botnetstats_getinfo *" [utimers]]} { utimer $botnetstats_setting(timer) botnetstats_getinfo }
proc botnetstats_readarray {array file} {
	upvar $array ours
	if {[catch {open $file r} fd]} { return }
	set arraydata [split [read $fd] \n]
	close $fd
	if {[array exists ours]} { unset ours }
	foreach line $arraydata {
		if {[string range $line 0 2] != "%!%"} { continue }
		if {[scan [string range $line 3 end] "%\[^!!!\]!!!%s" name data] > 0} {
			if {![info exists data]} { set data "" }
			set ours($name) $data
		}
	}
}
proc botnetstats_savearray {array file} {
	upvar $array ours
	if {[catch {open $file w} fd] || ![array exists ours]} { return }
	foreach entry [array names ours] { puts $fd "%!%$entry!!!$ours($entry)" }
	close $fd
}
if {![array exists botnetstats_master] && [file exists [set botnetstats_setting(db_master) ${botnetstats_setting(db)}botnetstatsmaster.db]]} { botnetstats_readarray botnetstats_master $botnetstats_setting(db_master) }
proc botnetstats_dopre {} {
	global botnetstats_setting
	if {!$botnetstats_setting(BOTNETSTATS:)} { return "" }
	if {!$botnetstats_setting(bold)} { return "BOTNETSTATS: " }
	return "\002BOTNETSTATS:\002 "
}
proc botnetstats_format_td {type line center text} {
	global botnetstats_setting
	switch -- $type {
		"header" { return "<td align=\"left\" bgcolor=\"$botnetstats_setting(Page_THC_$line)\"><font size=\"$botnetstats_setting(Page_THS)\" color=\"$botnetstats_setting(Page_HC)\">[expr ${center}!=0?"<center>":""]$text[expr ${center}!=0?"</center>":""]</font></td>" }
		"cell" { return "<td align=\"left\" bgcolor=\"$botnetstats_setting(Page_TCC_$line)\"><font size=\"$botnetstats_setting(Page_TCS)\" color=\"$botnetstats_setting(Page_CC)\">[expr ${center}!=0?"<center>":""]$text[expr ${center}!=0?"</center>":""]</font></td>" }
	}
}
proc botnetstats_ncm {pattern string} { return [string match [string tolower $pattern] [string tolower $string]] }
proc botnetstats_man_update {hand idx text} {
	botnetstats_do_html
	putdcc $idx "[botnetstats_dopre]Web page updated."
}
proc botnetstats_downdel {hand idx text} {
	global botnetstats_master botnetstats_setting
	if {[set text [join [lindex [split $text] 0]]] == ""} { putdcc $idx "[botnetstats_dopre]Usage: .$botnetstats_setting(dcommand) <bot>" ; return }
	if {![info exists botnetstats_master($text)]} { putdcc $idx "[botnetstats_dopre]$text is not a known bot." ; return }
	unset botnetstats_master($text)
	botnetstats_savearray botnetstats_master $botnetstats_setting(db_master)
	botnetstats_do_html
	putdcc $idx "[botnetstats_dopre]$text has been removed from the down-bot list."
}
proc botnetstats_raw {from keyword text} {
	global botnetstats_servers botnetstats_hosts
	switch -- $keyword {
		"311" {
			if {[set nick2hand [nick2hand [lindex [split $text] 1]]] != "*"} { set botnetstats_hosts($nick2hand) [lindex [split $text] 1]![lindex [split $text] 2]@[lindex [split $text] 3] }
		}
		"312" {
			if {[set nick2hand [nick2hand [lindex [split $text] 1]]] != "*"} { set botnetstats_servers($nick2hand) [lindex [split $text] 2] }
		}
	}
}
proc botnetstats_link {bot {uplink {}}} {
	global botnetstats_master botnetstats_setting
	if {$uplink != ""} { set botnetstats_master($bot) $uplink }
	botnetstats_savearray botnetstats_master $botnetstats_setting(db_master)
	botnetstats_do_html
}
proc botnetstats_getinfo {} {
	global server botnick botnetstats_setting
	if {$botnetstats_setting(showserver) && $server != ""} {
		foreach bot [bots] {
			if {[set hand2nick [hand2nick $bot]] != ""} { putserv "WHOIS $hand2nick" }
		}
		putserv "WHOIS $botnick"
	}
	if {![string match "* botnetstats_getinfo *" [utimers]]} { utimer $botnetstats_setting(timer) botnetstats_getinfo }
}
proc botnetstats_do_html {} {
	global botnetstats_setting botnetstats_page_item botnet-nick numversion botnetstats_servers botnetstats_hosts botnetstats_master
	set locbot ${botnet-nick}
	if {![info exists botnetstats_servers($locbot)] || !$botnetstats_setting(showserver)} { set server "-" } { set server $botnetstats_servers($locbot) }
	foreach bot [botlist] { set botnetstats_master([lindex $bot 0]) [lindex $bot 1] }
	set botnetstats_master($locbot) $locbot
	set stats [open $botnetstats_setting(page) w]
	puts $stats "<html>\n  <head>\n    <title>$botnetstats_setting(Page_TitleTag)</title>\n    <META NAME=\"description\" CONTENT=\"Botnet Stats\">\n    <META NAME=\"keywords\" CONTENT=\"eggdrop, bot, stats, botnet, link\">\n  </head>\n\n  <body bgcolor=\"$botnetstats_setting(Page_BGC)\" link=\"$botnetstats_setting(Page_LinkC)\" alink=\"$botnetstats_setting(Page_LinkC)\" vlink=\"$botnetstats_setting(Page_LinkC)\">"
	if {$botnetstats_setting(Page_Img) != ""} { puts $stats "    <center><img src=\"$botnetstats_setting(Page_Img)\"></img></center>" }
	puts $stats "    <center><font size=\"$botnetstats_setting(Page_TitleS)\" color=\"$botnetstats_setting(Page_TTextC)\">$botnetstats_setting(Page_Title)</font></center>\n    <br>"
	if {$botnetstats_setting(Page_Linked_Bots)} {
		puts $stats "    <br>\n    <center><font size=\"$botnetstats_setting(Page_THS)\" color=\"$botnetstats_setting(Page_TextC)\">Linked Bots</font></center>\n    <br>\n    <table align=\"center\">\n      <tr>"
		foreach {a b} [list 1 Number 2 Bot 1 Uplink 2 Server 1 Version] { puts $stats "        [botnetstats_format_td header $a 1 $b]" }
		puts $stats "      </tr>\n      <tr>"
		foreach {a b} [list 1 1 2 $locbot 1 $locbot 2 $server 1 [join [scan $numversion %1d%2d%2d] .]] { puts $stats "        [botnetstats_format_td cell $a 1 $b]" }
		puts $stats "      </tr>"
		set bnum 0
		set matches 0
		foreach b [botlist] {
			set bot [lindex $b 0]
			if {$botnetstats_setting(showserver) && [validuser $bot] && [info exists botnetstats_hosts($bot)]} {
				foreach h [getuser $bot HOSTS] {
					regsub -all -- "~" $h "\*" h
					if {[string match $h $botnetstats_hosts($bot)]} { set matches 1 ; break }
				}
			}
			if {!$matches || ![info exists botnetstats_servers($bot)]} { set botnetstats_servers($bot) "-" }
			incr bnum
			puts $stats "      <tr>"
			foreach {a b} [list 1 $bnum 2 $bot 1 [lindex $b 1] 2 $botnetstats_servers($bot) 1 [join [scan [lindex $b 2] %1d%2d%2d] .]] { puts $stats "        [botnetstats_format_td cell $a 1 $b]" }
			puts $stats "      </tr>"
		}
		puts $stats "    </table>\n    <br>\n    <br>"
	}
	if {$botnetstats_setting(Page_Down_Bots)} {
		puts $stats "    <br>\n    <center><font size=\"$botnetstats_setting(Page_THS)\" color=\"$botnetstats_setting(Page_TextC)\">Down Bots</font></center>\n    <br>\n    <table align=\"center\">\n      <tr>"
		foreach {a b} [list 1 Number 2 Bot 1 Uplink] { puts $stats "        [botnetstats_format_td header $a 1 $b]" }
		puts $stats "      </tr>"
		if {[expr [array size botnetstats_master] - [llength [bots]] - 1] == 0} {
			puts $stats "      <tr>"
			foreach a [list 1 2 1] { puts $stats "        [botnetstats_format_td cell $a 1 -]" }
			puts $stats "      </tr>"
		} {
			set i 0
			foreach bot [array names botnetstats_master] {
				if {[islinked $bot] || [string compare $bot $locbot] == 0} { continue }
				incr i
				puts $stats "      <tr>"
				foreach {a b} [list 1 $i 2 $bot 1 [lindex $botnetstats_master($bot) 0]] { puts $stats "        [botnetstats_format_td cell $a 1 $b]" }
				puts $stats "      </tr>"
			}
		}
		puts $stats "    </table>\n    <br>\n    <br>"
	}
	if {$botnetstats_setting(Page_Partyline)} {
		puts $stats "    <center><font size=\"$botnetstats_setting(Page_THS)\" color=\"$botnetstats_setting(Page_TextC)\">Partyline</font></center>\n    <br>\n    <table align=\"center\">\n      <tr>"
		foreach {a b} [list 1 Number 2 User 1 Bot 2 Host 1 Idle 2 Away] { puts $stats "        [botnetstats_format_td header $a 1 $b]" }
		puts $stats "      </tr>"
		set bnum 0
		foreach u [whom 0] {
			incr bnum
			foreach {a b} [list hand [lindex $u 0] bot [lindex $u 1] idle [duration [expr [lindex $u 4] * 60]] flag [lindex $u 3] host [expr ($botnetstats_setting(showparty))?"[lindex $u 2]":"-"] away [expr {([lindex $u 5] != "")?"[join [lrange $u 5 end]]":"-"}]] { set $a $b }
			puts $stats "      <tr>"
			foreach {a b} [list 1 $bnum 2 ${flag}$hand 1 $bot 2 $host 1 $idle 2 $away] { puts $stats "        [botnetstats_format_td cell $a 1 $b]" }
			puts $stats "      </tr>"
		}
		if {$bnum == 0} {
			puts $stats "      <tr>"
			foreach a [list 1 2 1 2 1 2] { puts $stats "        [botnetstats_format_td cell $a 1 -]" }
			puts $stats "      </tr>"
		}
		puts $stats "    </table>\n    <br>\n    <br>"
	}
	if {$botnetstats_setting(Page_Botnet_Map)} {
		puts $stats "    <center><font size=\"$botnetstats_setting(Page_THS)\" color=\"$botnetstats_setting(Page_TextC)\">Botnet Map</font></center>\n    <br>\n    <table align=\"center\">\n      <tr>\n        [botnetstats_format_td header 1 1 Map]\n      </tr>\n      <tr>\n        <td align=\"left\" bgcolor=\"$botnetstats_setting(Page_TCC_1)\"><font size=\"$botnetstats_setting(Page_TCS)\" color=\"$botnetstats_setting(Page_CC)\">\n<pre>\n\n   $locbot   "
		botnetstats_get_uplinks $locbot
		botnetstats_mapgen "     " $stats $locbot
		puts $stats "</pre>\n        </td>\n      </tr>\n    </table>\n    <br>\n    <br>"
	}
	puts $stats "    <center><font color=\"$botnetstats_setting(Page_TextC)\">Last Updated: [clock format [clock seconds] -format "%D %I:%M %p"]</font></center>\n    <center><font color=\"$botnetstats_setting(Page_TextC)\">Generated By: $locbot</font></center>\n  </body>\n</html>\n<!--<DAWGID>BotnetStats $botnetstats_setting(version)</DAWGID>-->"
	close $stats
}
proc botnetstats_get_uplinks {locbot} {
	global botnetstats_uplink
	catch { unset botnetstats_uplink }
	foreach b [botlist] { set botnetstats_uplink([lindex $b 0]) [lindex $b 1] }
	set botnetstats_uplink($locbot) $locbot
}
proc botnetstats_mapgen {indent fd bot} {
	global botnetstats_uplink
	foreach bot2 [array names botnetstats_uplink] {
		if {![string match $bot $bot2] && [string match $botnetstats_uplink($bot2) $bot]} { lappend downlinks $bot2 }
	}
	if {![info exists downlinks]} { return }
	foreach bot2 $downlinks {
		if {[string match $bot2 [lindex $downlinks end]]} {
			puts $fd "$indent `-$bot2     "
			botnetstats_mapgen "$indent  " $fd $bot2
		} { 
			puts $fd "$indent |-$bot2     "
			botnetstats_mapgen "$indent |   " $fd $bot2
		}
	}
}
putlog "\002BOTNETSTATS:\002 BotnetStats.tcl Version $botnetstats_setting(version) by Wcc is loaded."
