| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- # watch.tcl
- #
- # This script watches users with the !watch command and informs the caller when
- # the user gets online or offline.
- #
- # Usage:
- # !watch add user watch user's status
- # !watch del user stop watching user's status
- # !watch check user check user's status once
- #
- # Enable for a channel with: .chanset #channel +watch
- # Disable for a channel with: .chanset #channel -watch
- #
- # See https://github.com/hwipl/eggdrop-scripts for the latest version and
- # additional information including the license (MIT).
- # tested versions, might run on earlier versions
- package require Tcl 8.6
- package require eggdrop 1.8.4
- namespace eval ::watch {
- # channel flag for enabling/disabling
- setudef flag watch
- # name of file for watched nicks
- variable whoisFile "watchnick.db"
- # list of pending whois requests
- variable whoisList {}
- }
- # handle !watch command and call subcommands
- proc ::watch::watchNick {nick host hand chan argv} {
- set usage "Usage: !watch <add|del|check> <nick>"
- # check channel flag if enabled in this channel
- if {![channel get $chan watch]} {
- return 0
- }
- # check if there are enough parameters
- if {[llength $argv] < 2} {
- puthelp "PRIVMSG $nick :$usage"
- return 0
- }
- # parse arguments and run command
- set command [lindex $argv 0]
- set whoisNick [lindex $argv 1]
- switch $command {
- "add" {
- add $chan $nick $whoisNick
- check $nick $whoisNick
- }
- "del" {
- del $nick $whoisNick
- }
- "check" {
- # set last status to "unknown" so reply is not filtered
- lastStatus $nick $whoisNick "unknown"
- check $nick $whoisNick
- }
- default {
- puthelp "PRIVMSG $nick :$usage"
- }
- }
- return 1
- }
- # check if entry a in whois file matches entry b
- proc ::watch::fileMatch {a b} {
- # only check first two columns, ignore rest
- if {[string compare -nocase [lindex $a 0] [lindex $b 0]] != 0} {
- return 1
- }
- if {[string compare -nocase [lindex $a 1] [lindex $b 1]] != 0} {
- return 1
- }
- return 0
- }
- # get all entries from whois file
- proc ::watch::fileGet {} {
- variable whoisFile
- # read entries from whois file
- set entlist ""
- if {![catch {open $whoisFile r} input]} {
- while {[gets $input line] >= 0} {
- lappend entlist $line
- }
- close $input
- }
- return $entlist
- }
- # write all entries from entlist to whois file
- proc ::watch::filePut {entlist} {
- variable whoisFile
- if {![catch {open $whoisFile w} output]} {
- foreach e $entlist {
- puts $output $e
- }
- close $output
- }
- }
- # handle !watch subcommand "add"
- proc ::watch::add {chan nick whoisNick} {
- variable whoisFile
- # watch entry being added
- set ent "$nick $whoisNick unknown"
- # check if entry already exists
- foreach line [fileGet] {
- if {[fileMatch $line $ent] == 0} {
- # user already being watched
- return 0
- }
- }
- # new watch entry, insert nick into nickdb
- if {![catch {open $whoisFile a} output]} {
- puts $output $ent
- close $output
- }
- }
- # handle !watch subcommand "del"
- proc ::watch::del {nick whoisNick} {
- # watch entry being deleted
- set ent "$nick $whoisNick"
- # find entry in whois file that's about to get deleted
- set entlist [fileGet]
- set i 0
- foreach line $entlist {
- if {[fileMatch $line $ent] == 0} {
- # delete entry and write everything back to whois file
- filePut [lreplace $entlist $i $i]
- return
- }
- incr i
- }
- }
- # update last status with newStatus and return old status
- proc ::watch::lastStatus {nick whoisNick newStatus} {
- # get old status from file and remember line number
- set entlist [fileGet]
- set ent "$nick $whoisNick"
- set last ""
- set i 0
- foreach line $entlist {
- if {[fileMatch $line $ent] == 0} {
- set last [lindex $line 2]
- break
- }
- incr i
- }
- # if there was no entry in the file, stop and return an invalid status
- if {$last == ""} {
- return "none"
- }
- # update last status in file
- set entlist [lreplace $entlist $i $i "$nick $whoisNick $newStatus"]
- filePut $entlist
- # return last status
- return $last
- }
- # register for whois return codes
- proc ::watch::bindWhois {} {
- # 401 - No Such User (offline)
- # 311 - User Info (online)
- bind RAW - 401 ::watch::checkReply
- bind RAW - 311 ::watch::checkReply
- }
- # unregister whois return codes if no whois is pending
- proc ::watch::unbindWhois {} {
- variable whoisList
- # if no whois is pending any more, remove binds
- if {[llength $whoisList] == 0} {
- # 401 - No Such User (offline)
- # 311 - User Info (online)
- unbind RAW - 401 ::watch::checkReply
- unbind RAW - 311 ::watch::checkReply
- }
- }
- # add entry with nick and whoisNick to whois list
- proc ::watch::addWhois {nick whoisNick} {
- variable whoisList
- lappend whoisList "$nick $whoisNick"
- }
- # remove entry with nick and whoisNick from whois list
- proc ::watch::delWhois {nick whoisNick} {
- variable whoisList
- set i [lsearch $whoisList "$nick $whoisNick"]
- set whoisList [lreplace $whoisList $i $i]
- }
- # find name of user who issued the whois for whoisNick
- proc ::watch::findWhois {whoisNick} {
- variable whoisList
- set nick ""
- foreach e $whoisList {
- if {$whoisNick == [lindex $e 1]} {
- set nick [lindex $e 0]
- break
- }
- }
- return $nick
- }
- # handle !watch subcommand "check"
- proc ::watch::check {nick whoisNick} {
- variable whoisList
- # register events
- bindWhois
- # add entry to whois list
- addWhois $nick $whoisNick
- # whois user
- putserv "WHOIS $whoisNick"
- return 1
- }
- # handle server replies of whois commands
- proc ::watch::checkReply {from keyword txt} {
- variable whoisList
- set whoisNick [lindex [split $txt] 1]
- # set state according to reply keyword
- set state "offline"
- if {$keyword == 311} {
- set state "online"
- }
- # find entry in whois list
- set nick [findWhois $whoisNick]
- if {$nick == ""} {
- putlog "Error finding entry in whoisList."
- return 0
- }
- # remove entry from whois list
- delWhois $nick $whoisNick
- unbindWhois
- # update and get last status of watched user
- set last [lastStatus $nick $whoisNick $state]
- if {$last == $state} {
- return 0
- }
- puthelp "PRIVMSG $nick :$whoisNick is $state."
- return 0
- }
- # periodically check watched nicks
- proc ::watch::periodic {minute hour day month weekday} {
- # check each entry in whois file
- set entlist [fileGet]
- foreach e $entlist {
- set nick [lindex $e 0]
- set whoisNick [lindex $e 1]
- check $nick $whoisNick
- }
- }
- namespace eval ::watch {
- bind pub - !watch ::watch::watchNick
- bind cron - "*/1 * * * *" ::watch::periodic
- putlog "Loaded watch.tcl"
- }
|