فهرست منبع

update watch.tcl

Signed-off-by: hwipl <33433250+hwipl@users.noreply.github.com>
hwipl 6 سال پیش
والد
کامیت
5720fc3599
1فایلهای تغییر یافته به همراه250 افزوده شده و 61 حذف شده
  1. 250 61
      scripts/watch.tcl

+ 250 - 61
scripts/watch.tcl

@@ -1,101 +1,290 @@
-#!/usr/bin/tclsh
+# 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
 
-proc watch_nick {nick host hand chan argv} {
+# tested versions, might run on earlier versions
+package require Tcl 8.6
+package require eggdrop 1.8.4
 
-	global watch_nick_user
-	set watch_nick_user $nick
+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: !watch <add|del|chk> <nick>"
-		#puts "PRIVMSG $nick :Usage: !watch <add|del> <nick>"
-		return
+		puthelp "PRIVMSG $nick :$usage"
+		return 0
 	}
 
-	# set some variables
+	# parse arguments and run command
 	set command [lindex $argv 0]
-	set nick2watch [lindex $argv 1]
-
-	if {$command == "add"} {
-		watch_add $nick2watch
-	} elseif {$command == "del" } {
-		watch_del $nick2watch
-	} elseif {$command == "chk" } {
-		watch_chk $nick2watch
+	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
 }
 
-proc watch_add {nick} {
 
-	# file where to save nicks
-	set nickdb "watch_nick.db"
+# 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
+}
 
-	# helper var to check if nick is already saved
-	set found 0
+# get all entries from whois file
+proc ::watch::fileGet {} {
+	variable whoisFile
 
-	# open file and start reading and comparing saved nicks with submitted one
-	if ![catch {open $nickdb r} input] {
+	# read entries from whois file
+	set entlist ""
+	if {![catch {open $whoisFile r} input]} {
 		while {[gets $input line] >= 0} {
-			if {[string compare -nocase $line $nick] == 0} {
-			set found 1
-			}
+			lappend entlist $line
 		}
 		close $input
 	}
 
-	# insert nick into nickdb if it´s not already in it
-	if { $found == 0} {
-		if ![catch {open $nickdb a} output] {
-			puts $output $nick
-			close $output
+	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
 	}
 }
 
-proc watch_del {nick} {
+# handle !watch subcommand "add"
+proc ::watch::add {chan nick whoisNick} {
+	variable whoisFile
 
-	# file where to save nicks
-	set nickdb "watch_nick.db"
+	# watch entry being added
+	set ent "$nick $whoisNick unknown"
 
-	# open file and read nicks from it (omit nick that´s about to get deleted)
-	if ![catch {open $nickdb r} input] {
-		while {[gets $input line] >= 0} {
-			if {$line != $nick} {
-				lappend nicklist $line
-			}
+	# check if entry already exists
+	foreach line [fileGet] {
+		if {[fileMatch $line $ent] == 0} {
+			# user already being watched
+			return 0
 		}
-		close $input
 	}
 
-	# write nicks to the file again
-	if ![catch {open $nickdb w} output] {
-		foreach entry $nicklist {
-			puts $output $entry
-		}
+	# 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"
+	}
 
-proc watch_chk {nick2watch} {
+	# update last status in file
+	set entlist [lreplace $entlist $i $i "$nick $whoisNick $newStatus"]
+	filePut $entlist
 
-	bind RAW - 401 watch_chk_nosuch
-	bind RAW - 311 watch_chk_info
-	putserv "WHOIS $nick2watch"
+	# return last status
+	return $last
 }
 
-proc watch_chk_nosuch {var1 var2 var3} {
-	global watch_nick_user
-	puthelp "PRIVMSG $watch_nick_user :offline $var1 || $var2 || $var3"
-	unbind RAW - 401 watch_chk_nosuch
-	unbind RAW - 311 watch_chk_info
+# 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
 }
 
-proc watch_chk_info {var1 var2 var3} {
-	global watch_nick_user
-	puthelp "PRIVMSG $watch_nick_user :online $var1 || $var2 || $var3"
-	unbind RAW - 401 watch_chk_nosuch
-	unbind RAW - 311 watch_chk_info
+
+# 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
+	}
 }
 
-bind pub - !watch watch_nick
+# 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
+}