Code: Select all
##
# Protect Ops v2.0.6
# by MC_8 - Carl M. Gregory <mc8@purehype.net>
# This script will only run on eggdrop 1.6.14 or greater.
#
# R.I.P. Mom, To always be remembered; Nancy Marie Gregory.
#
# My Website - http://mc.purehype.net/
# Have a bug or script not working correctly?
# http://mc.purehype.net/bugzilla/
# Have a question?
# http://forum.purehype.net/viewforum.php?f=5
##
##
# Description
##
# This script basically does what 'chanset''s 'protectops' and 'dontkickops'
# does, but with more options and customized reactions. A "super protectops" as
# someone called it, wording in relation to slennox's script "super bitch".
#
# This can also be setup to protect others, not just op's.
##
##
# Commands
##
# DCC:
#
# chanset <channel> <+/->mc.protect_ops
# This will enable (+) or disable (-) the script for the specific
# channel.
##
##
# Configuration
##
#
## Kick protection settings.
# What op'd users do you want to protect from op kick's? If you want to protect
# every op that is currently op'd, regardless if there a registered op in the
# bot, then set this to "-|-". Set this to "" to disable kick protection. Flag
# syntax, <global>|<channel>
set mc_po(:config:kick:protect) "NBn|N"
# What do you want to do upon other op kicking an op? Separate each command
# with a new line.
# Valid commands are:
# /msg <nick|channel> <text>
# /notice <nick|channel> <text>
# /ban <channel> <nick> [time [reason]]
# If time is specified;
# 0 = Perm ban.
# Any number greater than 0 is the ban expiration in min's.
# If the number is greater than 0, the reason will be put into the
# bot's internal banlist record as the reason for adding the ban. Otherwise
# the ban is considered a server ban and reason is just ignored. Also, if
# you want the ban to be "sticky" (read up on '.help stick') then append the
# time with an '!' (exclamation point).
# /kick <channel> <nick>
# /deop <channel> <nick>
# /raw <raw_irc_code>
# See: http://www.user-com.undernet.org/documents/rfc1459.txt
# /chattr <handle> <flag changes> [channel]
# This acts exactly the same way as a '.chattr' in the DCC console, see
# '.help chattr'.
# /note <handle> <text>
# Sends an internal note via the notes module to <handle>.
# /flagnote <flag [channel]> <text>
# Sends an internal note via the notes module to all whom match the
# specified flag(s). Flag format is global|channel.
# Valid replacement variables are;
# %botnick - The bot's IRC nickname.
# %channel - The channel the action took place in.
# %reason - The reason specified for the action.
# %nick - The IRC nickname that performed the action.
# %ident - The ident of the IRC nickname that performed the action.
# %host - The host of the IRC nickname that performed the action.
# %handle - The handle of the IRC nickname that performed the action.
# %victim_nick - The IRC nickname of the victim.
# %victim_ident - The ident of the victim.
# %victim_host - The host of the victim.
# %victim_handle - The handle of the victim.
set mc_po(:config:kick:do) {
/deop %channel %nick
/ban %channel %nick [1440 [don't kick a protected op]]
/chattr %handle -mtfo|-mtfo %channel
/msg %nick You just kicked %victim_nick, that's a protected op!
/note eggie %nick Kicked %victim_nick on %channel his ident is %ident
}
## Ban protection settings.
# What op'd users do you want to protect from op ban's? If you want to protect
# every op that is currently op'd, regardless if there a registered op in the
# bot, then set this to "-|-". Set this to "" to disable ban protection. Flag
# syntax: <global>|<channel>
set mc_po(:config:ban:protect) "NnB|N"
# What do you want to do upon other op banning an op? Separate each command
# with a new line.
# Valid commands are:
# /msg <nick|channel> <text>
# /notice <nick|channel> <text>
# /ban <channel> <nick> [time [reason]]
# If time is specified;
# 0 = Perm ban.
# Any number greater than 0 is the ban expiration in min's.
# If the number is greater than 0, the reason will be put into the
# bot's internal banlist record as the reason for adding the ban. Otherwise
# the ban is considered a server ban and reason is just ignored. Also, if
# you want the ban to be "sticky" (read up on '.help stick') then append the
# time with an '!' (exclamation point).
# /kick <channel> <nick>
# /deop <channel> <nick>
# /raw <raw_irc_code>
# See: http://www.user-com.undernet.org/documents/rfc1459.txt
# /chattr <handle> <flag changes> [channel]
# This acts exactly the same way as a '.chattr' in the DCC console, see
# '.help chattr'.
# /note <handle> <text>
# Sends an internal note via the notes module to <handle>.
# /flagnote <flag [channel]> <text>
# Sends an internal note via the notes module to all whom match the
# specified flag(s). Flag format is global|channel.
# /reverse [option]
# Removes the ban set. If option is set to 'valid_only', it will only
# reverse the ban if the user that matches the ban is a valid op (registered
# with the bot and has the 'o' flag).
# Valid replacement variables are;
# %botnick - The bot's IRC nickname.
# %channel - The channel the action took place in.
# %nick - The IRC nickname that performed the action.
# %ident - The ident of the IRC nickname that performed the action.
# %host - The host of the IRC nickname that performed the action.
# %handle - The handle of the IRC nickname that performed the action.
# %victim_nick - The IRC nickname of the victim.
# %victim_ident - The ident of the victim.
# %victim_host - The host of the victim.
# %victim_handle - The handle of the victim.
# %banmask - The banmask that triggered this.
set mc_po(:config:ban:do) {
/chattr %handle -mtfo|-mtfo %channel
/deop %channel %nick
/chattr %handle -mtfo|-mtfo %channel
/msg %nick You just banned %victim_nick, that's an op!
/reverse valid_only
/note eggie %nick did a ban on %victim_nick on %channel his ident is %ident
/ban %channel %nick [1440 [don't kick a protected op]]
}
## Deop protection settings.
# What op'd users do you want to protect from op deop's? If you want to protect
# every op that is currently op'd, regardless if there a registered op in the
# bot, then set this to "-|-". Set this to "" to disable deop protection. Flag
# syntax: <global>|<channel>
set mc_po(:config:deop:protect) "NnB|N"
# What do you want to do upon other op deopping an op? Separate each command
# with a new line.
# Valid commands are:
# /msg <nick|channel> <text>
# /notice <nick|channel> <text>
# /ban <channel> <nick> [time [reason]]
# If time is specified;
# 0 = Perm ban.
# Any number greater than 0 is the ban expiration in min's.
# If the number is greater than 0, the reason will be put into the
# bot's internal banlist record as the reason for adding the ban. Otherwise
# the ban is considered a server ban and reason is just ignored. Also, if
# you want the ban to be "sticky" (read up on '.help stick') then append the
# time with an '!' (exclamation point).
# /kick <channel> <nick>
# /deop <channel> <nick>
# /raw <raw_irc_code>
# See: http://www.user-com.undernet.org/documents/rfc1459.txt
# /chattr <handle> <flag changes> [channel]
# This acts exactly the same way as a '.chattr' in the DCC console, see
# '.help chattr'.
# /note <handle> <text>
# Sends an internal note via the notes module to <handle>.
# /flagnote <flag [channel]> <text>
# Sends an internal note via the notes module to all whom match the
# specified flag(s). Flag format is global|channel.
# /reverse [option]
# Re-ops the victim. If option is set to 'valid_only', it will only reverse
# the op status if the user is a valid op (registered with the bot and has
# the 'o' flag).
# Valid replacement variables are;
# %botnick - The bot's IRC nickname.
# %channel - The channel the action took place in.
# %nick - The IRC nickname that performed the action.
# %ident - The ident of the IRC nickname that performed the action.
# %host - The host of the IRC nickname that performed the action.
# %handle - The handle of the IRC nickname that performed the action.
# %victim_nick - The IRC nickname of the victim.
# %victim_ident - The ident of the victim.
# %victim_host - The host of the victim.
# %victim_handle - The handle of the victim.
set mc_po(:config:deop:do) {
/deop %channel %nick
/ban %channel %nick [1440 [don't deop a protected op]]
/chattr %handle -mtfo|-mtfo %channel
/msg %nick You just deopped %victim_nick, that's an op!
/reverse valid_only
/note eggie %nick deop %victim_nick on %channel his ident is %ident
}
## Miscellaneous settings.
# What flagged users do you want to exempt from this script? Set to "" to exempt
# no one.
set mc_po(:config:exempt) "b|"
# What other flagged users do you want to protect as well? This is useful if
# the matching flagged user is not op'd, the script will still protect him/her.
# Set this to "" to disable. Flag syntax: <global>|<channel>
set mc_po(:config:also:protect) ""
# [0=no/1=yes] If the bot is not opped, do you want to perform the *:do command
# setup above? In respects to /msg, /notice, /ban, and /kick -- with proper
# respects to the channels (/msg and /notice being the channel the action took
# place in -- the others being the channels specified).
set mc_po(:config:bigtalker) 1
# How do you want to mask hosts? This is used for banning and adding
# a user to the userfile (if either enabled).
# 0 - *!user@host.domain
# 1 - *!*user@host.domain
# 2 - *!*@host.domain
# 3 - *!*user@*.domain
# 4 - *!*@*.domain
# 5 - nick!user@host.domain
# 6 - nick!*user@host.domain
# 7 - nick!*@host.domain
# 8 - nick!*user@*.domain
# 9 - nick!*@*.domain
# You can also specify a type of 10-19 which corresponds to types 0-9,
# using this sub rule; If host.domain is a(n)-
# name - Instead of using a * wildcard to replace portions of the
# host.domain, it replaces the numbers in the host.domain with a
# '?' (question mark) wildcard.
# ip - It will mask as normal, with no '?' (question mark)
# replacements as does hostname.
set mc_po(:config:maskhostbytype) 3
## SVS Client (Script Version Service) v4.1.2 ##
# Once a day, the SVS Client will connect to MC_8's SVS Server to determine if
# there is a newer version of this script available. If a newer version is
# found, the script will be auto updated.
# [0=no/1=yes] Do you want to enable auto updating? If you chose to disable
# auto updating, it will not automatically update the script upon finding a
# newer version.
set mc_po(:config:svs:enable) 0
#
##
##
# Done with configurations, do not edit past here unless you know TCL.
##
#
## SVS insert (pre code)
#Script:mc_po
catch {unset temp}
foreach temp(bind) [binds mc:po:*] {
foreach {temp(1) temp(2) temp(3) temp(4) temp(5)} $temp(bind) break
catch {unbind $temp(1) $temp(2) $temp(3) $temp(5)}
}
set mc_po(info:vars) ""
foreach {temp(name) temp(value)} [array get mc_po :config:*] {
lappend mc_po(info:vars) [list $temp(name) $temp(value)]
}
set mc_po(info:loc) [info script]
array set mc_po [list \
script "Protect Ops" \
version "v2.0.6" \
svs:script "protectops" \
svs:version "002000006000" \
svs:client_version "v4.1.2" \
svs:client_svs_version "004001002000" \
svs:server "mc.svs.purehype.net" \
svs:port "80" \
svs:get "/index.tcl"]
set mc_po(svs:query) "svs=$mc_po(svs:script)&"
append mc_po(svs:query) "version=$mc_po(svs:version)&"
append mc_po(svs:query) \
"svs_version=$mc_po(svs:client_svs_version)"
if {![info exists numversion] ||
([string range $numversion 0 4] < "10614") ||
(([string range $numversion 0 4] == "10614") &&
([string range $numversion 5 6] != "00"))} {
set temp(tag) "$mc_po(script) $mc_po(version)"
putloglev o * \
"$temp(tag) by MC_8 will only work on eggdrop 1.6.14 (stable) or greater."
putloglev o * "$temp(tag) will not work with eggdrop $version."
putloglev o * "$temp(tag) not loaded."
uplevel #0 {
if {[info exists temp] && ![array exists temp]} {unset temp}
set temp(svs_return) [list 0 "Need to upgrade eggdrop."]
}; return 1
}
## ^
setudef flag mc.protect_ops
# Error Catching System (ECS), v4.1.
proc mc:po:errchk {command args} {
# Enable (1) or disable (0) auto reporting of bugs to mc8@purehype.net.
# This setting here for those who want to disable it in fear of privacy
# violations.
set enable_auto_reporting 0
if {![info exists ::lastCommand]} {set ::lastCommand [list]}
set ::lastCommand \
"[list [list [clock seconds] $command $args]] $::lastCommand"
set ::lastCommand [lrange $::lastCommand 0 4]
if {![catch {eval $command $args} return]} {return $return}
if {$::errorCode == "mc.ecs.done"} {return -errorcode mc.ecs.done -code error}
set temp(lastbind) [expr {[info exists ::lastbind]?$::lastbind:"-NULL-"}]
set temp(eversion) [expr {[info exists ::version]?$::version:"-NULL-"}]
set message "
************************************
(ECS 4.1) Error found in TCL script.
--------------
Script name : $::mc_po(script)
Script version: $::mc_po(version)
Egg. Version : $temp(eversion)
TCL Version : [info tclversion] ([info patchlevel])
--------------
Last Bind : $temp(lastbind)
Last Commands :"
foreach line $::lastCommand {
foreach {time command arg} $line break
append message "\n ${time}- $command $arg"
}
append message "\n Error stack :"
foreach line [split $::errorInfo \n] {
append message "\n $line"
}
append message "\n --------------"
set message [lrange [split $message \n] 1 end]
set offset [string first * [lindex $message 0]]
set new_message [list]
foreach line $message {lappend new_message [string range $line $offset end]}
set message $new_message
if {!$enable_auto_reporting ||
[catch {socket -async mc.purehype.net 80} sid]} {
foreach line $message {putloglev o * $line}
putloglev o * "Submit this bug to http://mc.purehype.net/bugzilla/ . If"
putloglev o * "you are experiencing problems with bugzilla, contact MC_8"
putloglev o * "via email at mc8@purehype.net. Please include all"
putloglev o * "information shown here, in this ECS report."
putloglev o * "************************************"
return -errorcode mc.ecs.done -code error
}
fconfigure $sid -blocking 0 -buffering line
set query [list]
# This info is passed should I need to hunt down the bot's owner for more
# information.
lappend query "Admin : [expr {[info exists ::admin]?$::admin:""}]"
lappend query "Owner : [expr {[info exists ::owner]?$::owner:""}]"
lappend query "Botnick : [expr {[info exists ::botnick]?$::botnick:""}]"
lappend query "Server : [expr {[info exists ::server]?$::server:""}]"
lappend query "Channels: [join [lsort -dictionary [channels]] ", "]"
lappend query ""
foreach line $message {lappend query $line}
lappend query "************************************"
set new_query [list]
foreach line $query {
regsub -all -- "(\002|\017|\026|\037)" $line "" line
regsub -all -- "\003(\[0-9\]\[0-9\]?(,\[0-9\]\[0-9\]?)?)?" $line "" line
regsub -all {\%} $line "%25" line
set i [string length $line]
while {[regexp {[^a-zA-Z0-9%]} $line toh] && ($i >= 0)} {
scan "$toh" %c dec
regsub -all -- "\\${toh}" $line "%[format %X $dec]" line
incr i -1
}; lappend new_query $line
}; set query $new_query
set query "message=[join $query %0a]"
puts $sid "POST /report_bug.tcl HTTP/1.0\
\nHost: mc.purehype.net:80\
\nContent-type: application/x-www-form-urlencoded\
\nContent-Length: [expr [string length $query] +2]"
puts $sid \n$query
close $sid
foreach line $message {putloglev o * $line}
putloglev o * "Automatically sending bug report to MC_8."
putloglev o * "If you have a firewall setup, it may block the sending of this"
putloglev o * "report. You can check the status of your bug, as soon as MC_8"
putloglev o * "adds it, at http://mc.purehype.net/bugzilla/ ."
putloglev o * "************************************"
return -errorcode mc.ecs.done -code error
}
# ^
bind join - * mc:po:bind:join
proc mc:po:bind:join {nick uhost handle channel} {
return [mc:po:errchk mc:po:bind:join_ $nick $uhost $handle $channel]
}
proc mc:po:bind:join_ {nick uhost handle channel} {
if {![isbotnick $nick]} {mc:po:list ial add $nick $uhost $channel}
}
bind raw - 315 mc:po:bind:raw
proc mc:po:bind:raw {from keyword arg} {
return [mc:po:errchk mc:po:bind:raw_ $from $keyword $arg]
}
proc mc:po:bind:raw_ {from keyword arg} {
set channel [lindex [split $arg] 1]
if {![validchan $channel]} {return 0}
mc:po:list ial remove "" $channel
foreach temp(user) [chanlist $channel] {
if {[isbotnick $temp(user)]} {continue}
mc:po:list ial add $temp(user) [getchanhost $temp(user) $channel] $channel
}
return 0
}
bind part - * mc:po:bind:part
proc mc:po:bind:part {nick uhost handle channel text} {
return [mc:po:errchk mc:po:bind:part_ $nick $uhost $handle $channel $text]
}
proc mc:po:bind:part_ {nick uhost handle channel text} {
if {[isbotnick $nick]} {mc:po:list ial remove "" $channel} \
else {mc:po:list ial schedule_remove $nick $channel 30}
}
bind sign - * mc:po:bind:sign
proc mc:po:bind:sign {nick uhost handle channel reason} {
return [mc:po:errchk mc:po:bind:sign_ $nick $uhost $handle $channel $reason]
}
proc mc:po:bind:sign_ {nick uhost handle channel reason} {
if {[isbotnick $nick]} {mc:po:list ial remove "" $channel} \
else {mc:po:list ial schedule_remove $nick $channel 30}
}
bind kick - * mc:po:bind:kick
proc mc:po:bind:kick {nick uhost handle channel target reason} {
return [mc:po:errchk mc:po:bind:kick_ \
$nick $uhost $handle $channel $target $reason]
}
proc mc:po:bind:kick_ {nick uhost handle channel target reason} {
if {[isbotnick $target]} {mc:po:list ial remove "" $channel} \
elseif {$nick == $target} {mc:po:list ial schedule_remove $nick $channel 30} \
else {
mc:po:list eval $nick $channel kick $target $reason
mc:po:list ial schedule_remove $target $channel 30
}
}
bind mode - * mc:po:bind:mode
proc mc:po:bind:mode {nick uhost handle channel mode victim} {
return [mc:po:errchk mc:po:bind:mode_ \
$nick $uhost $handle $channel $mode $victim]
}
proc mc:po:bind:mode_ {nick uhost handle channel mode victim} {
if {[isbotnick $nick] || ($nick == "")} {return 0}
switch -- $mode {
"+b" {
foreach temp(user) [mc:po:list ial find $channel $victim] {
set temp(nick) [lindex $temp(user) 0]
if {$temp(nick) == $nick} {continue}
set temp() [mc:po:list eval $nick $channel ban $temp(nick) \
[lindex $temp(user) 1] $victim]
if {$temp() == "1"} {
# Action taken.
break
}
}
}
"-o" {
if {$victim != $nick} {mc:po:list eval $nick $channel deop $victim}
}
}
}
bind nick - * mc:po:bind:nick
proc mc:po:bind:nick {nick uhost handle channel newnick} {
return [mc:po:errchk mc:po:bind:nick_ $nick $uhost $handle $channel $newnick]
}
proc mc:po:bind:nick_ {nick uhost handle channel newnick} {
if {![isbotnick $newnick]} {
mc:po:list ial remove $nick $channel
mc:po:list ial add $newnick $uhost $channel
}
}
proc mc:po:list {command {args ""}} {
return [mc:po:errchk mc:po:list_ $command $args]
}
proc mc:po:list_ {command arg} {
set args $arg
global mc_po
switch -- $command {
"ial" {
# Ial format; nick uhost channel
if {![info exists mc_po(:ial:)]} {set mc_po(:ial:) ""}
set temp(command) [lindex $args 0]
set args [lrange $args 1 end]
switch -- $temp(command) {
"add" {
# mc:po:list ial add <nick> <uhost> <channel>
foreach {nick uhost channel} $args break
mc:po:list ial remove $nick $channel
lappend mc_po(:ial:) [list $nick $uhost $channel]
}
"remove" {
# mc:po:list ial remove [nick] [channel]
set nick ""; set channel ""
foreach {nick channel} $args break
set temp(new_list) ""
foreach temp(entry) [mc:po:list ial list] {
set temp(nick) [string tolower [lindex $temp(entry) 0]]
set temp(channel) [string tolower [lindex $temp(entry) 2]]
if {(($nick == "") || ($temp(nick) == [string tolower $nick])) &&
(($channel == "") ||
($temp(channel) == [string tolower $channel]))} {
mc:po:list ial kill_schedule $temp(nick) $temp(channel)
continue
}
lappend temp(new_list) $temp(entry)
}
set mc_po(:ial:) $temp(new_list)
}
"find" {
# mc:po:list ial find <channel> <nick!user@host*>
foreach {channel nuhost_masked} $args break
set nuhost_masked [string tolower $nuhost_masked]
set temp(return) ""
foreach temp(entry) [mc:po:list ial list $channel] {
set temp(nick) [string tolower [lindex $temp(entry) 0]]
set temp(uhost) [string tolower [lindex $temp(entry) 1]]
if {[string match $nuhost_masked $temp(nick)!$temp(uhost)]} {
lappend temp(return) [lrange $temp(entry) 0 1]
}
}
return $temp(return)
}
"list" {
# mc:po:list ial list [channel]
set channel ""
foreach channel $args break
if {$channel == ""} {return $mc_po(:ial:)}
set temp(return) ""
foreach temp(entry) $mc_po(:ial:) {
set temp(channel) [string tolower [lindex $temp(entry) 2]]
if {$temp(channel) == [string tolower $channel]} {
lappend temp(return) $temp(entry)
}
}
return $temp(return)
}
"schedule_remove" {
# mc:po:list ial schedule_remove <nick> <channel> <seconds>
foreach {nick channel time} $args break
set nick [string tolower $nick]
set channel [string tolower $channel]
set temp(list) [list mc:po:list remove $nick $channel]
foreach temp(utimer) [utimers] {
if {[lsearch -exact $temp(utimer) $temp(list)] == "1"} {
return 0
}
}
utimer $time $temp(list)
}
"kill_schedule" {
# mc:po:list ial kill_schedule <nick> <channel>
foreach {nick channel} $args break
set nick [string tolower $nick]
set channel [string tolower $channel]
set temp(list) [list mc:po:list remove $nick $channel]
foreach temp(utimer) [utimers] {
if {[lsearch -exact $temp(utimer) $temp(list)] == "1"} {
killutimer [lindex $temp(utimer) 2]
break
}
}
}
}
}
"is_protected" {
# mc:po:list is_protected <nick> <handle> <channel> <type> \
# <punisher_handle>
foreach {nick handle channel type punisher_handle} $args break
global botnet-nick
if {
([channel get $channel mc.protect_ops]) &&
((($nick != "") && ([onchan $nick $channel])) ||
($nick == "")) &&
($punisher_handle != ${botnet-nick}) &&
((($mc_po(:config:${type}:protect) == "-|-") &&
((($type == "deop") && ([wasop $nick $channel])) ||
((($type == "kick") || ($type == "ban")) &&
([isop $nick $channel])))) ||
(($mc_po(:config:${type}:protect) != "") &&
([matchattr $handle $mc_po(:config:${type}:protect) $channel])) ||
(($mc_po(:config:also:protect) != "") &&
([matchattr $handle $mc_po(:config:also:protect) $channel]))) &&
(($mc_po(:config:exempt) != "") &&
(![matchattr $punisher_handle $mc_po(:config:exempt) $channel]))
} {return 1} else {return 0}
}
"eval" {
# mc:po:list eval <nick> <channel> kick <target_nick> [reason]
# mc:po:list eval <nick> <channel> deop <target_nick>
# mc:po:list eval <nick> <channel> ban <target_nick> <target_uhost> \
# <banmask>
global botnick botnet-nick
set reason ""; set banmask ""
foreach {nick channel type target_nick reason banmask} $args break
if {($nick != "") && ([set uhost [getchanhost $nick]] != "")} {
regexp -- {^(.*)@(.*)$} $uhost -> ident host
set handle [nick2hand $nick]
} else {
set ident ""
set host ""
set handle ""
}
if {$type == "ban"} {
regexp -- {^(.*)@(.*)$} $reason -> target_ident target_host
set target_handle [finduser $target_nick!$reason]
set reason ""
} else {
regexp -- {^(.*)@(.*)$} [getchanhost $target_nick $channel] -> \
target_ident target_host
set target_handle [nick2hand $target_nick $channel]
}
if {
![mc:po:list is_protected $target_nick $target_handle $channel $type $handle]
} {return 0}
set temp(return_number) 1
set temp(do) [mc:po:replace -- $mc_po(:config:${type}:do) [list \
%botnick $botnick \
%channel $channel \
%reason $reason \
%nick $nick \
%ident $ident \
%host $host \
%handle $handle \
%victim_nick $target_nick \
%victim_ident $target_ident \
%victim_host $target_host \
%victim_handle $target_handle\
%banmask $banmask]]
foreach temp(command) [split $temp(do) \n] {
set temp(command) [string trim $temp(command) " \t"]
if {$temp(command) == ""} {continue}
set temp(command) [split $temp(command)]
set temp(args) [lrange $temp(command) 1 end]
set temp(command) [string tolower [lindex $temp(command) 0]]
switch -- $temp(command) {
"/msg" {
if {![botisop $channel] && !$mc_po(:config:bigtalker)} {continue}
set temp(to) [lindex $temp(args) 0]
if {$temp(to) == ""} {continue} ;# Server action?
putserv "PRIVMSG $temp(to) :[join [lrange $temp(args) 1 end]]"
}
"/notice" {
if {![botisop $channel] && !$mc_po(:config:bigtalker)} {continue}
set temp(to) [lindex $temp(args) 0]
if {$temp(to) == ""} {continue} ;# Server action?
putserv "NOTICE $temp(to) :[join [lrange $temp(args) 1 end]]"
}
"/ban" {
foreach {temp(channel) temp(nick) temp(time) temp(reason)} \
$temp(args) break
if {$temp(nick) == ""} {continue} ;# Server action?
if {![validchan $temp(channel)]} {
set temp() "$temp(command) [join $temp(args)]"
putloglev o * "$mc_po(script): Invalid channel; $temp()"
continue
}
if {![onchan $temp(nick) $temp(channel)]} {
set temp() "$temp(command) [join $temp(args)]"
putloglev o * "$mc_po(script): Nickname not on channel; $temp()"
continue
}
if {![botisop $temp(channel)] && !$mc_po(:config:bigtalker)} {
continue
}
set temp(banmask) [mc:po:maskhostbytype \
$temp(nick)![getchanhost $temp(nick)] \
$mc_po(:config:maskhostbytype)]
if {$temp(time) == ""} {
putserv "MODE $temp(channel) +b $temp(banmask)"
continue
}
set temp(sticky) [string match *! $temp(time)]
regexp -- {^(.*)!?$} $temp(time) -> temp(time)
if {[regexp -- {[^0-9]} $temp(time)]} {
set temp() "$temp(command) [join $temp(args)]"
putloglev o * "$mc_po(script): Invalid time format; $temp()"
continue
}
newchanban $temp(channel) $temp(banmask) ${botnet-nick} $reason \
$temp(time) [expr {$temp(sticky)?"sticky":"none"}]
}
"/kick" {
set temp(channel) [lindex $temp(args) 0]
set temp(nick) [lindex $temp(args) 1]
if {![validchan $temp(channel)]} {
set temp() "$temp(command) [join $temp(args)]"
putloglev o * "$mc_po(script): Invalid channel; $temp()"
continue
}
if {![onchan $temp(nick) $temp(channel)]} {
set temp() "$temp(command) [join $temp(args)]"
putloglev o * "$mc_po(script): Nickname not on channel; $temp()"
continue
}
if {![botisop $temp(channel)] && !$mc_po(:config:bigtalker)} {
continue
}
putserv "KICK $temp(channel) $temp(nick) :$reason"
}
"/deop" {
set temp(channel) [lindex $temp(args) 0]
set temp(nick) [lindex $temp(args) 1]
if {![validchan $temp(channel)]} {
set temp() "$temp(command) [join $temp(args)]"
putloglev o * "$mc_po(script): Invalid channel; $temp()"
continue
}
if {![onchan $temp(nick) $temp(channel)]} {
set temp() "$temp(command) [join $temp(args)]"
putloglev o * "$mc_po(script): Nickname not on channel; $temp()"
continue
}
if {![botisop $temp(channel)] && !$mc_po(:config:bigtalker)} {
continue
}
if {![isop $temp(nick) $temp(channel)]} {continue}
putserv "MODE $temp(channel) -o $temp(nick)"
}
"/chattr" {
set temp(handle) [lindex $temp(args) 0]
set temp(flags) [lindex $temp(args) 1]
set temp(channel) [lindex $temp(args) 2]
if {($temp(handle) == "") || ($temp(handle) == "*")} {
continue
}
if {(![validchan $temp(channel)]) && ($temp(channel) != "")} {
set temp() "$temp(command) [join $temp(args)]"
putloglev o * "$mc_po(script): Invalid channel; $temp()"
continue
}
if {$temp(channel) == ""} {chattr $temp(handle) $temp(flags)} \
else {chattr $temp(handle) $temp(flags) $temp(channel)}
}
"/raw" {
putserv [join $temp(args)]
}
"/note" {
set temp(handle) [lindex $temp(args) 0]
set temp(message) [join [lrange $temp(args) 1 end]]
if {![validuser $temp(handle)]} {
set temp() "$temp(command) [join $temp(args)]"
putloglev o * "$mc_po(script): Invalid handle; $temp()"
continue
}
if {[sendnote ${botnet-nick} $temp(handle) $temp(message)] == "3"} {
set temp() "note box too full"
putloglev o * \
"$mc_po(script): Cannot send note to $temp(handle), $temp()."
}
}
"/flagnote" {
set temp(flag) [lindex $temp(args) 0]
set temp(channel) [lindex $temp(args) 1]
set temp(message) [join [lrange $temp(args) 2 end]]
if {![validchan $temp(channel)]} {
set temp(channel) ""
set temp(message) [join [lrange $temp(args) 1 end]]
}
if {$temp(channel) == ""} {
set temp(userlist) [userlist $temp(flag)]
} else {
set temp(userlist) [userlist $temp(flag) $temp(channel)]
}
foreach temp(handle) $temp(userlist) {
if {
[sendnote ${botnet-nick} $temp(handle) $temp(message)] == "3"
} {
set temp() "note box too full"
putloglev o * \
"$mc_po(script): Cannot send note to $temp(handle), $temp()."
}
}
}
"/reverse" {
if {![regexp {^(ban|deop)$} $type]} {continue}
set temp(option) [lindex $temp(args) 0]
if {($temp(option) == "valid_only") &&
(![matchattr $target_handle o|o $channel])} {
if {$type == "ban"} {set temp(return_number) 0}
continue
}
set temp(return_number) 1
if {$type == "ban"} {putserv "MODE $channel -b $banmask"} \
else {putserv "MODE $channel +o $target_nick"}
}
default {
set temp() "$temp(command) [join $temp(args)]"
putloglev o * "$mc_po(script): Unknown command; $temp()"
}
}
}
return $temp(return_number)
}
}
}
## More Tools quick procs.
## -- http://mc.purehype.net/script_info.tcl?script=moretools
# badargs <args> <min_llength> <max_llength|end> <argNames>
# version:
# v1.0
proc mc:po:badargs {{args ""}} {
if {[llength $args] < 4} {
error {
wrong # args: should be "mc:po:badargs args min_llength max_llength argNames"
}
}
set index 0
foreach varName [list args min max names] {
set check_$varName [lindex $args $index]
incr index
}
if {[regexp -- {([^0-9])} $check_min -> bad]} {
error "bad number \"$bad\" in: $check_min"
}
if {[regexp -- {([^0-9])} $check_max -> bad] && ($check_max != "end")} {
error "bad number \"$bad\" in: $check_max"
}
# Make sure $check_args is in list format, if not then make it so.
# Were not going to use 2list here, don't want to evoke a 'too many nested
# calls to Tcl_EvalObj' error since '2list' uses on this proc.
if {[catch {llength $check_args} llength]} {
set check_args [split $check_args]
set llength $check_args
}
if {($llength < $check_min) || (($llength != "end") &&
($llength > $check_max))} {
if {[info level] == "1"} {return 1}
error "wrong # args: should be \"[lindex [info level -1] 0] $check_names\""
}; return 0
}
# 2list <text>
# version:
# v1.0+no_unlist
proc mc:po:2list {{args ""}} {
mc:po:badargs $args 1 1 "text"
foreach text $args break
return [expr {([catch {llength $text}])?[split $text]:$text}]
}
# replace [switches] <text> <substitutions>
# version:
# v1.3
proc mc:po:replace {{args ""}} {
mc:po:badargs $args 2 4 "?switches? text substitutions"
set switches ""
for {set i 0} {[string match -* [set arg [lindex $args $i]]]} {incr i} {
if {![regexp -- {^-(nocase|-)$} $arg -> switch]} {
error "bad switch \"$arg\": must be -nocase, or --"
}
if {$switch == "-"} {
incr i
break
}; lappend switches $switch
}
set nocase [expr {([lsearch -exact $switches "nocase"] >= "0") ? 1 : 0}]
set text [lindex $args $i]
set substitutions [lindex $args [expr $i+1]]
mc:po:badargs [lrange $args $i end] 2 2 "?switches? text substitutions"
# Check to see if $substitutions is in list format, if not make it so.
set substitutions [mc:po:2list $substitutions]
if {[info tclversion] >= "8.1"} {
return [expr {($nocase)?
[string map -nocase $substitutions $text]:
[string map $substitutions $text]}]
}
set re_syntax {([][\\\*\+\?\{\}\,\(\)\:\.\^\$\=\!\|])}
foreach {a b} $substitutions {
regsub -all -- $re_syntax $a {\\\1} a
if {$nocase} {regsub -all -nocase -- $a $text $b text} \
else {regsub -all -- $a $text $b text}
}; return $text
}
# maskhostbytype <nick!ident@host.domain> [type]
# version:
# v2.1+no_unlist
proc mc:po:maskhostbytype {{args ""}} {
mc:po:badargs $args 1 2 "nick!ident@host.domain ?type?"
set type ""
foreach {nuhost type} $args break
set type [expr {($type == "")?5:$type}]
if {![regexp -- {^1?[0-9]$} $type]} {
set valid "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 {or 19}"
error "bad type \"$type\": must be [join $valid ", "]"
}
# Define the maximum length the ircd allows for an ident. Standard is 9,
# however I made it to a variable incase someone wants to change it up.
set ident_max-length 9
# Define the maximum length the ircd allows for a hostname/ ip. Standard is
# 63, however I made it to a variable incase someone wants to change it up.
set host_max-length 63
if {![regexp -- {^(.*[^!])!((.*)@(.*))$} $nuhost -> nick uhost ident host]} {
error "invalid nick!ident@host.domain: $nuhost"
}
set maskhost 1
if {[string length $type] == "2"} {
# Type must be 10-19.
if {[info tclversion] < "8.1"} {
set re_syntax_1 {([12][0-9][0-9]|[1-9][0-9]|[1-9])}
set re_syntax_2 {([12][0-9][0-9]|[1-9][0-9]|[0-9])}
} else {
set re_syntax_1 {([12]\d{2}|[1-9][0-9]|[1-9])}
set re_syntax_2 {([12]\d{2}|[1-9][0-9]|[0-9])}
}
set re_syntax ^$re_syntax_1\\.$re_syntax_2\\.$re_syntax_2\\.$re_syntax_2\$
if {![regexp -- $re_syntax $host]} {
regsub -all -- {[0-9]} $host ? host
set maskhost 0
}; set type [string index $type 1]
}
# Previous version used regexp instead of these string matches. String match
# in this case is ~3 microseconds faster.
if {[string match {[0-4]} $type]} {set nick *}
if {[string match {[2479]} $type]} {set ident *}
if {[string match {[1368]} $type]} {regsub -- {^~?(.*)$} $ident *\\1 ident}
if {[string match {[3489]} $type] && $maskhost} {
set host [lindex [split [maskhost $host] @] end]
}
if {[set length [string length $ident]] > ${ident_max-length}} {
set ident *[string range $ident [expr $length-${ident_max-length}] end]
}
if {[set length [string length $host]] > ${host_max-length}} {
set host *[string range $host [expr $length-${host_max-length}] end]
}
return $nick!$ident@$host
}
## End of More Tools quick procs.
## SVS insert (post code)
if {![info exists mc_po(:config:svs:enable)] ||
![string match {[01]} $mc_po(:config:svs:enable)]} {
set mc_po(:config:svs:enable) 0
}
bind time - "00 00 *" mc:po:do_svs
proc mc:po:do_svs {{args ""}} {
global mc_po
set query $mc_po(svs:query)
if {$args == ""} {append query "&log=0"}
if {[catch {connect $mc_po(svs:server) $mc_po(svs:port)} ind]} {
set temp(1) "SVS problem connecting to $mc_po(svs:server)"
set temp(2) "on port $mc_po(svs:port)"
putloglev d * "$mc_po(script): $temp(1) $temp(2): $ind"
return 0
}
putdcc $ind "GET $mc_po(svs:get)?$query HTTP/1.0\n"
putdcc $ind "Host: $mc_po(svs:server):$mc_po(svs:port)\n\n"
control $ind mc:po:svs_talk
}
proc mc:po:svs_memory {action} {
global mc_po
switch -- $action {
"setup" {
upvar index index
foreach _item [list header memory rfc_memory] {
upvar $_item $_item
set $_item [list svs $_item $index]
}
}
"remove" {
upvar index index
mc:po:svs_memory setup
catch {unset mc_po($header)}
catch {unset mc_po($memory)}
foreach _item [array names mc_po $rfc_memory:*] {unset mc_po($_item)}
}
}
}
proc mc:po:svs_talk {index text} {
global mc_po
mc:po:svs_memory setup
if {$text == ""} {
mc:po:svs_memory remove
return 1
}
set text [split $text]
set rfc [lindex $text 0]
set text [join [lrange $text 1 end]]
if {![info exists mc_po($header)]} {
if {$rfc == "002"} {set mc_po($header) 1}
return 0
}
switch -- $rfc {
001 {return 0}
002 {return 0}
003 {return 0}
010 {
if {$text != $mc_po(svs:script)} {
set temp(1) "wanted $mc_po(svs:script), got $text"
putloglev d * "$mc_po(script): SVS Error: $temp(1)"
mc:po:svs_memory remove
return 1
}
if {$mc_po(:config:svs:enable)} {return 0}
set mc_po($rfc_memory:[string index $rfc end]) $text
return 0
}
011 {
if {$mc_po(:config:svs:enable)} {return 0}
set mc_po($rfc_memory:[string index $rfc end]) $text
return 0
}
012 {
if {$mc_po(:config:svs:enable)} {return 0}
set mc_po($rfc_memory:[string index $rfc end]) $text
return 0
}
013 {
if {$mc_po(:config:svs:enable)} {return 0}
set mc_po($rfc_memory:[string index $rfc end]) $text
return 0
}
014 {
if {$mc_po(:config:svs:enable)} {return 0}
set mc_po($rfc_memory:[string index $rfc end]) $text
return 0
}
017 {
if {$mc_po(:config:svs:enable)} {return 0}
if {$text == ""} {
set text "Newer version of this script exists."
}
foreach number [list 0 1 2 3 4] {
if {![info exists mc_po($rfc_memory:$number)]} {continue}
regsub -all -- %$number $text $mc_po($rfc_memory:$number) text
}
putloglev o * "SVS, $mc_po(script): $text"
mc:po:svs_memory remove
return 1
}
004 {
# Quit.
if {!$mc_po(:config:svs:enable)} {
mc:po:svs_memory remove
return 1
}
if {[info exists mc_po($memory)]} {
set file $mc_po(info:loc)~new
set temp(vars) $mc_po(info:vars)
set io [open $file w]
for {set i 0} {$i <= [llength $mc_po($memory)]} {incr i} {
set line [lindex $mc_po($memory) $i]
set regexp {^[; ]*set mc_po\((:config:[^)]*)\) *(.?)}
if {[regexp -- $regexp $line -> name type]} {
set continue 0
foreach item $temp(vars) {
set item_name [lindex $item 0]
set item_value [lindex $item 1]
if {$name != $item_name} {continue}
set lsearch_index [lsearch -exact $temp(vars) $item]
set temp(vars) \
[lreplace $temp(vars) $lsearch_index $lsearch_index]
puts $io [list set mc_po($name) $item_value]
if {$type == "\{"} {
while {1} {
if {[regexp -- {\}(?:[; ][; ]*(.*))?} $line -> extra]} {
if {$extra != ""} {
puts $io $extra
}
break
}
incr i
set line [lindex $mc_po($memory) $i]
}
puts $io ""
} elseif {$type == "\""} {
regsub -- {"} $line "" line
while {1} {
if {[regexp -- {[^\\]"(?:[; ][; ]*(.*))?} $line -> extra] ||
[regexp -- {^"(?:[; ][; ]*(.*))?} $line -> extra]} {
if {$extra != ""} {
puts $io $extra
}
break
}
incr i
set line [lindex $mc_po($memory) $i]
}
puts $io ""
}
set continue 1
break
}
if {$continue} {continue}
}
puts $io $line
}
close $io
set file $mc_po(info:loc)
putloglev o * "$mc_po(script): Auto update testing new script..."
if {[catch {uplevel "source $file~new"}]} {
file delete -force -- $file~new
putloglev o * "$mc_po(script): Auto update failed:"
putloglev o * $::errorInfo
putloglev o * \
"$mc_po(script): Loading previous script version..."
uplevel "source $file"
} else {
upvar #0 temp upvar_temp
if {[info exists upvar_temp(svs_return)]} {
set temp(return_code) [lindex $upvar_temp(svs_return) 0]
set temp(return_arg) [lindex $upvar_temp(svs_return) 1]
if {!$temp(return_code)} {
file delete -force -- $file~new
set temp() "message from new version: $temp(return_arg)"
putloglev o * "$mc_po(script): Auto update failed, $temp()"
putloglev o * \
"$mc_po(script): Loading previous script version..."
uplevel "source $file"
} else {
file rename -force -- $file~new $file
set temp() "good, message from new version: $temp(return_arg)"
putloglev o * "$mc_po(script): Auto update test $temp()"
putloglev o * \
"$mc_po(script): Moving and reloading new version..."
uplevel "source $file"
}
} else {
file rename -force -- $file~new $file
putloglev o * "$mc_po(script): Auto update test good."
putloglev o * \
"$mc_po(script): Moving and reloading new version..."
uplevel "source $file"
}
}
}
mc:po:svs_memory remove
return 1
}
200 {
set temp(host) [lindex $text 1]
set temp(port) [lindex $text 2]
set temp(get) [lindex $text 3]
set temp(cache) "$temp(host) at $temp(port)"
putloglev d * \
"$mc_po(script): SVS is being redirected to $temp(cache)."
utimer 6 [list mc:po:do_svs_ $temp(host) $temp(port) $temp(get)]
mc:po:svs_memory remove
return 1
}
300 {
if {$mc_po(:config:svs:enable)} {
lappend mc_po($memory) $text
}; return 0
}
}
}
catch {unset index}
if {![info exists mc_loaded]} {set mc_loaded(scripts) [list]}
if {![array exists mc_loaded]} {unset mc_loaded; set mc_loaded(scripts) [list]}
set index [lsearch -exact $mc_loaded(scripts) mc_po]
set mc_loaded(scripts) [lreplace $mc_loaded(scripts) $index $index mc_po]
## ^
putloglev o * "$mc_po(script) $mc_po(version) by MC_8 loaded."