- Home»
- Cod sursa: status.tcl
status.tcl
status.tcl
Statusd is a reimagining of Seend script designed to track users by storing thier latest activity & hostmask. Activities include joined, parted, kicked, quit, nick change, spoke, and action. If status is not found script will check channels nick list. If nick isn't in channel then a pattern search w
| Postat de | Copyright | Categorie | Review user | Vizualizari | Data |
|---|---|---|---|---|---|
| btc | lee8oi | stats | Cod netestat | 640 | 2023-12-25 12:46:03 |
namespace eval statusd {
########################################################################
# Copyright ©2011 [email protected]
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# http://www.gnu.org/licenses/
#
# Statusd v0.3.7(10.24.11)
# by: <lee8oiAtgmail><lee8oiOnfreenode>
# github link: https://github.com/lee8oi/statusd/blob/master/statusd.tcl
#
# Status oriented rebuild of Seend v1.8.3
#
# -------------------------------------------------------------------
#
# Statusd is a reimagining of Seend script designed to track users by storing
# thier latest activity & hostmask. Activities include joined, parted, kicked,
# quit, nick change, spoke, and action. If status is not found script will check
# channels nick list. If nick isn't in channel then a pattern search will be
# performed instead and results displayed. Script also includes the ability
# to search for nicks by hostmask using the host parameter. As well as an
# automatic backup system that saves on .die, restart, timed intervals.
#
# *Configuration options can be changed using the dcc command 'statusd'.
# Configurable options include all listed in configuration section.
#
# Initial channel setup:
# (starts logging and enables public status command. Run in partyline.)
# .chanset #channel +statusd
#
# Public command syntax:
# !status <nick> ?channel?
# !status host <hostmask>
#
# DCC command syntax:
# (omitting value and/or option displays help)
# .statusd set ?option? ?value?
# .statusd ?load|store?
#
# Example Usage:
# (public)
# <lee8oi> !status lee8oi
# <dukelovett> lee8oi spoke in #dukelovett 4 minutes 21 seconds ago. Message:
# I thought it was a great idea so I got started.tcl paste
# <lee8oi> !status lee8oi #dukelovett2
# <dukelovett> lee8oi joined #dukelovett2 5 minutes 59 seconds ago.
# <lee8oi> !status host *lee*
# <dukelovett> *lee* host matches the following nicks: lee8oi
#
# (DCC/partyline)
# <lee8oi> .statusd set
# <dukelovett> Configurable options: trigger backupfile
# interval logbackups use_current_chan. Setting config without a value shows
# help. ie: '.statusd set trigger' for trigger help.
# <lee8oi> .statusd set trigger
# <dukelovett> Usage: .statusd set trigger <string>
# <lee8oi> .statusd set trigger !seen
# <dukelovett> Statusd trigger changed to: !seen
#
#
# Thanks: drsprite. This script was concieved from your suggestions & comments.
#
# Updates:
# v0.3
# 1.Added configuration backup system. Script configuration settings are now
# saved & restored through the backup system as well as with '.statusd load'
# and '.statusd store' commands via dcc/partyline.
# 2.Removed backup_trigger & its configuration options since backups can be
# performed via dcc/partyline. Also a couple other minor fixes.
# 3.Script now checks if nick is in channel when a status is not found. If
# nick is not in channel then a pattern search will be performed and results
# returned.
# 4.Fixed bug that caused nick patterns with * symbols to trigger 'currently in
# chan' responses.
# 5.Modified pattern search to also search channel nick list for matching names.
# 6.Added chancheck function to validate specified channels. This fixes a bug
# related to users specifying channels that the bot has not joined.
# 7.Fixed configuration system to eliminate the extra binds leftover after
# changing command trigger & configuration via partyline.
#
# -------------------------------------------------------------------
# Configuration Defaults:
#
# *Set command trigger
# +-------+
variable trigger !status
# +-------+
#
# *Set backupfile location/name
# +--------------------------+
variable backupfile "scripts/statusdData.tcl"
# +--------------------------+
#
# *Set configfile location/name
# +--------------------------+
variable configfile "scripts/statusdConfig.tcl"
# +--------------------------+
#
# *Set backup interval time (in mins)
# +---+
variable interval 5
# +---+
#
# *Log backup messages
# 1 = on, 0 = off
# +---+
variable logbackups 0
# +---+
#
# *Use current channel if no channel specified(channel only)
# -Off defaults to using the channel with most recent activity.
# 1 = on, 0 = off
# +---+
variable use_current_chan 1
# +---+
#
########################################################################
variable timeseen
variable lastmsg
variable status
variable statustime
variable statustext
variable lastchan
variable nickcase
variable nickhost
variable ver "0.3.7"
setudef flag statusd
proc config_load {args} {
if {[file exists [set ::statusd::configfile]]} {
source [set ::statusd::configfile]
}
bind msg - [set ::statusd::trigger] ::statusd::msg_show_status
bind pub - [set ::statusd::trigger] ::statusd::show_status
}
}
::statusd::config_load
bind dcc n statusd ::statusd::dcc_proc
bind pubm - * ::statusd::status_logger_pubm
bind sign - * ::statusd::status_logger_sign
bind part - * ::statusd::status_logger_part
bind join - * ::statusd::status_logger_join
bind kick - * ::statusd::status_logger_kick
bind nick - * ::statusd::status_logger_nick
bind evnt - prerestart ::statusd::prerestart
bind evnt - loaded ::statusd::loaded
bind ctcp - "ACTION" ::statusd::status_logger_action
if {![info exists ::statusd_dietrace]} {
# .die trigger. do backup
trace add execution *dcc:die enter ::statusd::backup_data
trace add execution *msg:die enter ::statusd::backup_data
}
if {![info exists statusd_timer_running]} {
# no existing timer. start new one.
timer [set ::statusd::interval] ::statusd::timer_proc
set statusd_timer_running 1
}
namespace eval statusd {
proc prerestart {type} {
# prerestart trigger. do backup.
::statusd::backup_data
if {[set ::statusd::logbackups]} {
# logging is enabled.
putlog "Status backup performed."
}
}
proc config_store {args} {
set fs [open [set ::statusd::configfile] w+]
# create variable lines and 'array set' lines using array data.
foreach arr {trigger backupfile configfile interval\
logbackups use_current_chan} {
set arg "::statusd::${arr}"
set arg2 [set ${arg}]
if {[string is integer $arg2]} {
puts $fs "variable $arr $arg2"
} else {
puts $fs "variable $arr \"$arg2\""
}
}
close $fs;
}
proc loaded {type} {
# bot loaded trigger do restore.
if {[file exists [set ::statusd::backupfile]]} {
source [set ::statusd::backupfile]
}
::statusd::config_load
}
proc timer_proc {args} {
# call self at timed intervals. do backup
::statusd::backup_data
timer [set ::statusd::interval] ::statusd::timer_proc
return 1
}
proc backup_data {args} {
# backup to file
set fs [open [set ::statusd::backupfile] w+]
# create variable lines and 'array set' lines using array data.
foreach arr {status nickcase lastchan statustime statustext nickhost} {
set arrg "::statusd::${arr}"
puts $fs "variable $arrg"
puts $fs "array set $arr [list [array get [set arrg]]]"
}
close $fs;
::statusd::config_store
if {[set ::statusd::logbackups]} {
# logging is enabled.
putlog "Status backup performed."
}
}
proc chancheck {channel} {
if {[catch {channel info $channel} err]} {
set checkvar 0
} else {
set checkvar 1
}
return $checkvar
}
proc search_names {searchterm channel} {
variable ::statusd::nickcase
variable ::statusd::status
set channel [string tolower $channel]
set lterm [string tolower $searchterm]
set namelist [array names nickcase "\*${lterm}\*"]
if {$channel != ""} {
set fromchanlist [::statusd::search_nicklist "\*$searchterm\*" $channel "no"]
} else {
set fromchanlist ""
}
if { $namelist != "" || $fromchanlist != "" } {
# names matching pattern exist.
set newlist "[string trimleft $fromchanlist]"
if {[regexp {^\#} $channel]} {
foreach elem $namelist {
if {[info exists status($elem,$channel)]} {
append newlist " " $nickcase($elem)
}
}
if {$newlist != ""} {
set result "'${searchterm}' matches from $channel: [lsort -unique $newlist]"
} else {
set result "'${searchterm}' not found."
}
} elseif {$channel == ""} {
foreach elem $namelist {
if {[info exists nickcase($elem)]} {
append newlist " " $nickcase($elem)
}
}
if {$newlist != ""} {
set result "'${searchterm}' matches: $newlist"
} else {
set result "'${searchterm}' not found."
}
}
} else {
set result "'${searchterm}' not found."
}
return $result
}
proc search_nicklist {nick chan check} {
set newlist ""
set nicklist [split [chanlist $chan]]
if {$check == "yes"} {
set stripnick [string map {\* ""} $nick]
} else {
set stripnick $nick
}
foreach elem $nicklist {
if {[string match -nocase $stripnick $elem]} {
append newlist " " $elem
}
}
if {$check == "yes"} {
if {$newlist != "" } {
return "true"
}
} else {
return $newlist
}
}
proc search_hosts {searchterm} {
variable ::statusd::nickhost
variable ::statusd::nickcase
set namelist [array names nickhost]
set hostlist ""
set elemname ""
set elemval ""
foreach elem $namelist {
set lelem [string tolower $elem]
set elemname [set nickcase($lelem)]
set elemval $nickhost($elem)
if {[string match $searchterm $elemval]} {
append hostlist " " $elemname
}
}
if { $hostlist != "" } {
set result "'${searchterm}' host matches the following nicks:$hostlist"
} else {
set result "'${searchterm}' not found."
}
return $result
}
proc set_status {nick userhost channel status text} {
set lnick [string tolower $nick]
set lchan [string tolower $channel]
set ::statusd::status($lnick,$lchan) $status
set ::statusd::statustext($lnick,$lchan) $text
set ::statusd::statustime($lnick,$lchan) [clock seconds]
set ::statusd::nickcase($lnick) $nick
set ::statusd::nickhost($lnick) $userhost
set ::statusd::lastchan($lnick) $lchan
}
proc get_status {nick channel} {
set lnick [string tolower $nick]
set lchan [string tolower $channel]
set lstatus [set ::statusd::status($lnick,$lchan)]
set ltext [set ::statusd::statustext($lnick,$lchan)]
set ltime [set ::statusd::statustime($lnick,$lchan)]
set ncase [set ::statusd::nickcase($lnick)]
set durat [duration [expr {[clock seconds] - $ltime}]]
if {$lstatus == "Quit"} {
set result "$ncase was last seen quitting $durat ago. $ltext"
} elseif {$lstatus == "Parted"} {
set result "$ncase was last seen Parting from $channel $durat ago."
} elseif {$lstatus == "Joined"} {
set result "$ncase joined $channel $durat ago."
} elseif {$lstatus == "Kicked"} {
set result "$ncase was kicked from $channel $durat ago. Reason: $ltext"
} elseif {$lstatus == "Nick Change"} {
set result "$ncase was last seen changing name $ltext $durat ago."
} elseif {$lstatus == "Spoke"} {
set result "$ncase spoke in $channel $durat ago. Message: $ltext"
} elseif {$lstatus == "Action"} {
set result "$ncase was seen acting in $channel $durat ago: * $ncase $ltext"
} else {
set result "Status error. Unknown status type."
}
return $result
}
proc msg_show_status {nick userhost handle text} {
#Status check via msg/query
set arg1 [lindex [split $text] 0]
set arg2 [lindex [split $text] 1]
set larg1 [string tolower $arg1]
variable ::statusd::status
variable ::statusd::lastchan
if {$arg2 != "" && [regexp {^\#} $arg2]} {
#2nd arg is channel
if {[::statusd::chancheck $arg2]} {
if {[info exists status($larg1,$arg2)]} {
#status available.
set vstatus [::statusd::get_status $arg1 $arg2]
} else {
set listvar [::statusd::search_nicklist $arg1 $arg2 "check"]
if {$listvar == "true"} {
set vstatus "$arg1 is currently in $arg2"
} else {
set vstatus [::statusd::search_names $arg1 $arg2]
}
}
} else {
set vstatus "invalid channel"
}
putserv "PRIVMSG $nick :$vstatus"
} elseif {$larg1 == "host"} {
if {$arg2 != ""} {
set vstatus [::statusd::search_hosts $arg2]
} else {
set pubcom [set ::statusd::trigger]
set vstatus "Usage: $pubcom host <hostmask>"
}
putserv "PRIVMSG $nick :$vstatus"
} elseif {$arg2 == "" && $arg1 != ""} {
#no channel specified. nick only.
if {[info exists lastchan($larg1)]} {
set lastch [set lastchan($larg1)]
} else {
set lastch "#NOCHAN"
}
if {[info exists status($larg1,$lastch)]} {
#status available
set vstatus [::statusd::get_status $arg1 $lastch]
} else {
set searchresults [::statusd::search_names $arg1 ""]
set vstatus "No status found. Specify a channel to check nick list.\
$searchresults"
}
putserv "PRIVMSG $nick :$vstatus"
} else {
#no args provided.
variable ::statusd::ver
set pubcom [set ::statusd::trigger]
putserv "PRIVMSG $nick :Usage: $pubcom <nick> <channel> |or| $pubcom host <hostmask>"
}
}
proc show_status {nick userhost handle channel text} {
#status check via channel
if {[channel get $channel statusd]} {
set arg1 [lindex [split $text] 0]
set arg2 [lindex [split $text] 1]
set larg1 [string tolower $arg1]
variable ::statusd::status
if {$arg2 != "" && [regexp {^\#} $arg2]} {
#2nd arg is channel
if {[::statusd::chancheck $arg2]} {
if {[info exists status($larg1,$arg2)]} {
#status available.
set vstatus [::statusd::get_status $arg1 $arg2]
} else {
#fall back to pattern search.
set listvar [::statusd::search_nicklist $arg1 $arg2 "yes"]
if {$listvar == "true"} {
set vstatus "$arg1 is currently in $arg2"
} else {
set vstatus [::statusd::search_names $arg1 $arg2]
}
}
} else {
set vstatus "invalid channel"
}
putserv "PRIVMSG $channel :$vstatus"
} elseif {$larg1 == "host"} {
if {$arg2 != ""} {
set vstatus [::statusd::search_hosts $arg2]
} else {
set pubcom [set ::statusd::trigger]
set vstatus "Usage: $pubcom host <hostmask>"
}
putserv "PRIVMSG $channel :$vstatus"
} elseif {$arg2 == "" && $arg1 != ""} {
#no channel specified. nick only.
if {[set ::statusd::use_current_chan]} {
#use current chan
set chanvar $channel
} else {
#use most recent channel
if {[info exists ::statusd::lastchan($larg1)]} {
#Use recorded last channel.
set chanvar [set ::statusd::lastchan($larg1)]
} else {
#fall back to current channel.
set chanvar $channel
}
}
if {[info exists status($larg1,$chanvar)]} {
#status available
set vstatus [::statusd::get_status $arg1 $chanvar]
} else {
set listvar [::statusd::search_nicklist $arg1 $chanvar "yes"]
if {$listvar == "true"} {
set vstatus "$arg1 is currently in $chanvar"
} else {
set vstatus [::statusd::search_names $arg1 $chanvar]
}
}
putserv "PRIVMSG $channel :$vstatus"
} else {
#no args provided.
variable ::statusd::ver
set pubcom [set ::statusd::trigger]
putserv "PRIVMSG $channel :Usage: $pubcom <nick> ?channel? |or| $pubcom host <hostmask>"
}
}
}
proc dcc_proc {handle idx text} {
set textarr [split $text]
set text1 [string tolower [lindex $textarr 0]]
set text2 [string tolower [lindex $textarr 1]]
set text3 [string tolower [lindex $textarr 2]]
switch $text1 {
"" {
putdcc $idx "Usage: .statusd ?set|load|store?"
}
"store" {
::statusd::backup_data
putdcc $idx "Statusd backup performed."
}
"load" {
::statusd::loaded ""
putdcc $idx "Statusd configuration loaded."
}
"set" {
switch $text2 {
"" {
putdcc $idx "Configurable options are: trigger, \
backupfile, interval, logbackups,\
use_current_chan. Setting config without a value shows help.\
ie: '.statusd set trigger' for trigger help."
}
"trigger" {
if {$text3 != ""} {
unbind msg - [set ::statusd::trigger] ::statusd::msg_show_status
unbind pub - [set ::statusd::trigger] ::statusd::show_status
set ::statusd::trigger $text3
bind msg - [set ::statusd::trigger] ::statusd::msg_show_status
bind pub - [set ::statusd::trigger] ::statusd::show_status
putdcc $idx "Statusd trigger changed to: $text3"
} else {
putdcc $idx "Usage: .statusd set trigger <string>"
}
}
"backupfile" {
if {$text3 != ""} {
set ::statusd::backupfile "[lindex $textarr 2]"
putdcc $idx "Statusd backupfile changed to: [lindex $textarr 2]"
} else {
putdcc $idx "Usage: .statusd set backupfile location/filename"
}
}
"interval" {
if {$text3 != "" && [string is integer $text3]} {
set ::statusd::interval $text3
putdcc $idx "Statusd interval changed to: $text3"
} else {
putdcc $idx "Usage: .statusd set interval <integer>"
}
}
"logbackups" {
if {$text3 != "" && [string is integer $text3]} {
if {$text3 == 1 || $text3 == 0} {
set ::statusd::logbackups $text3
putdcc $idx "Statusd logbackups changed to: $text3"
} else {
putdcc $idx "Use 1 for on. 0 for off."
}
} else {
putdcc $idx "Usage: .statusd set logbackups <1|0>"
}
}
"use_current_chan" {
if {$text3 != "" && [string is integer $text3]} {
if {$text3 == 1 || $text3 == 0} {
set ::statusd::use_current_chan $text3
putdcc $idx "Statusd use_current_chan changed to: $text3"
} else {
putdcc $idx "Use 1 for on. 0 for off."
}
} else {
putdcc $idx "Usage: .statusd set use_current_chan <1|0>"
}
}
default {
putdcc $idx "Configurable options are: trigger, \
backupfile, interval, logbackups,\
use_current_chan. Setting config without a value shows help.\
ie: '.statusd set trigger' for trigger help."
}
}
}
default {
putdcc $idx "Usage: .statusd ?set|load|store?"
}
}
}
proc status_logger_pubm {nick userhost handle channel text} {
#public channel message logger.
if {[channel get $channel statusd]} {
set arg1 [lindex [split $text] 0]
if {$arg1 != [set ::statusd::trigger]} {
# not a status request. Ok to save.
::statusd::set_status $nick $userhost $channel "Spoke" $text
}
}
}
proc status_logger_sign {nick userhost handle channel text} {
if {[channel get $channel statusd]} {
::statusd::set_status $nick $userhost $channel "Quit" $text
}
}
proc status_logger_part {nick userhost handle channel text} {
if {[channel get $channel statusd]} {
::statusd::set_status $nick $userhost $channel "Parted" ""
}
}
proc status_logger_join {nick userhost handle channel} {
if {[channel get $channel statusd]} {
::statusd::set_status $nick $userhost $channel "Joined" ""
}
}
proc status_logger_kick {nick userhost handle channel target reason} {
if {[channel get $channel statusd]} {
set ltarg [string tolower $target]
if {[info exists ::statusd::nickhost($ltarg)] && [set ::statusd::nickhost($ltarg)] != "none"} {
set curmask [set ::statusd::nickhost($ltarg)]
} else {
set curmask "none"
}
::statusd::set_status $target $curmask $channel "Kicked" $reason
}
}
proc status_logger_nick {nick userhost handle channel newnick} {
if {[channel get $channel statusd]} {
::statusd::set_status $nick $userhost $channel "Nick Change" "to $newnick"
::statusd::set_status $newnick $userhost $channel "Nick Change" "from $nick"
}
}
proc status_logger_action { nick userhost hand dest keyword text } {
if {[string index $dest 0] != "#"} { return 0 }
if {[channel get $dest statusd]} {
::statusd::set_status $nick $userhost $dest "Action" $text
}
}
}
putlog "Statusd [set ::statusd::ver] loaded."
IRC Snippets