#####
# !!!!!!! NOT A OFFICIAL RELEASE !!!!!!!!
# Multichannel seen implementation by PreSSo (andrejp@luz.fe.uni-lj.si)
# loosely based on seen by Robey
# will show when nicks were last seen on the channel(s) no matter
# if they are on the bot's userlist or not.
# requires eggdrop 1.3.x bot
# needs adbtools.tcl loaded!
# Repaired by Ze_PilOt for 1.3.x
#
# HISTORY:
# version 1.0 (dunno exactly, been a while)
# version 1.1 (6 Aug, 1996)
# - various small fixes
# version 1.2 (18 Aug, 1996)
# - new faster check_expired (this one really blows the socks off:)
# - changed default nickexpire to 30 days
# - various small changes
# version 1.3 (18 Aug, 1996)
# - added configurable bind msg/pub flags for users (see settings)
# version 1.4 (1 Sep, 1996)
# - added force update command. this was needed to fix the
# bug where bot was showing incorrect seen info for users
# that were added to the bot's userlist after they were
# already in the seen nicks list (.seenupd)
# - added dcc seen command
# version 1.5 (2 Oct, 1996)
# - the script now also reports how the user left (leave, kick..)
# - old seen.nicks file is no longer valid (delete it)
# - shows the channel where nick was last on for all nicks, not
# just valid users (the code was already there, just not used:)
# version 1.6 (17 Jan, 1997)
# - the bot now reports 'one of my channels' instead of '#channel'
# if the channel is marked +secret
# version 1.7 (24 Jan, 1997)
# - cosmetical fixes
# version 1.8 (25 Jan, 1997)
# - err...:) a little bug fix:) It won't putlog stupid things now:)
# version 1.9 (29 Jul, 1997)
# - changed and tuned script, so it should run on 1.1.5 now
# Times for checking for expires (60 M.) and nicksaving (15 M.) are
# now hardcoded, hey... who cares? I for my part don#t know why it
# wouldn#t work with variables... Blackb|rd
# version 1.9.1 (10 Aug, 1997)
# - "corrected" and "rewrote" some of the answers (the grammar part
# wasn't very good - my opinion... :)) - Queux
# version 1.9.2 (16 Dec, 1997) (non official release !!!)
# - I upgraded the script to use with eggdrop 1.3.x .. The seen on the
# party don't work at 100%, but work perfectly on a channel ...
#
# COMMANDS:
# dcc, msg: seen <nick>
# public: !seen <nick>
#
# TODO:
# - nicks get added to the nicklist even though they are valid bot users - fix this
# - do a configurable 'reply on seen nick'
#####
### *** SETTINGS! ***
# filename of the file where nicks list will be saved
# (defaults to seen.nicks)
set seennicks {seen.nicks}
# save nicks each (this setting) minutes (defaults to 15
# minutes)
set nicksavetime 10
# check for expired users on every this much minutes
# this should be set to a reasonable value like one hour or
# one day or something like that (defaults to 60 minutes)
set expirechk 30
# time in hours for the nick that is NOT on the bot's
# userlist to expire. this keeps the seennicks file from
# getting huge (defaults to 720 hours -> 30 days)
set nickexpire 336
###
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# !!! DO NOT CHANGE ANYTHING BELOW THIS LINE !!!
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
###
set seenver "adbseen.tcl v1.9.2fr"
if {!([info exists seenpubf])} {set seenpubf "-"}
if {!([info exists seenmsgf])} {set seenmsgf "-"}
set nlist ""
# delete fake/existing userlist users from the seennicks list
proc seen_del_existing {uhand} {
global nlist
# delete nicks if the user exists in the userlist
append fwho "+" $uhand
set ind [lsearch -exact $nlist [string tolower $fwho]]
set deld 0
if {$ind != -1} {
set nlist [lreplace $nlist $ind [expr $ind + 3]]
return 1
}
return 0
}
# force nick update
proc force_seenupd {hand idx arg} {
global seennicks
if {[llength $arg] < 1} {
#update all users
putdcc $idx "Updating seen information for all users in the userlist..."
set deld 0
foreach uhand [userlist] {
incr deld [seen_del_existing $uhand]
}
if {$deld} {
putdcc $idx "Removed $deld nick(s) from nicks list that existed in the userlist."
}
} else {
#update specified nicks
foreach uhand $arg {
seen_del_existing $uhand
}
}
putdcc $idx "Update complete."
}
# update nick's status..
proc nick_upd {chan nick uhand how} {
global nlist
#set uhand [string tolower $uhand]
if {$uhand!="*"} {
# this user is a valid user
setlaston $uhand
setuser $uhand XTRA seenon $chan
setuser $uhand XTRA seenhow $how
# delete possible fake user entry in the nick list
append fwho "-" $uhand
set ind [lsearch -exact $nlist [string tolower $fwho]]
if {$ind != -1} {
set nlist [lreplace $nlist $ind [expr $ind + 3]]
}
seen_del_existing $uhand
return 1
} else {
# this user is NOT a valid user..
if {[validuser $nick]} {
# ..but he's using the nick of one of the valid users!
append mnick "-" [string tolower $nick]
} else {
# ..and he's using his own nick.. (this one will most probably only happen to $botnick)
append mnick "+" [string tolower $nick]
}
}
set timeon [unixtime]
set ind [lsearch -exact $nlist $mnick]
if {($ind >= 0)} {
#found nick! replace it
set nlist [lreplace $nlist [expr $ind + 1] [expr $ind + 3] $timeon $chan $how]
} else {
#nick nonexistant. append to the list
lappend nlist $mnick $timeon $chan $how
}
}
# save nicks
proc dcc_nick_save {hand idx arg} {
global seennicks
nick_save
putdcc $idx "Nicks saved to file ${seennicks}"
}
proc nick_save {} {
global seennicks nlist nicksavetime
set f [open $seennicks w]
puts $f $nlist
close $f
timer $nicksavetime "nick_save"
}
# delete expired users from the list
proc check_expired {} {
global nickexpire expirechk nlist
putlog "-Seen- Checking for expired users. The bot will not respond until it's finished."
set total [expr [llength $nlist] - 1]
set mtotal [expr $total / 4]
set nulist ""
set nrdel 0
set ind 0
set nrtot 0
foreach ent $nlist {
switch $ind {
0 {
set nik $ent
set ind 1
}
1 {
set loff $ent
set ind 2
}
2 {
set lchan $ent
set ind 3
}
3 {
if {[expr ([unixtime] - $loff) / 3600] < $nickexpire} {
#hasn't yet expired, add to the nulist
lappend nulist $nik $loff $lchan $ent
} else {incr nrdel 1}
set ind 0
}
}
}
set nlist $nulist
if {$nrdel > 0} {
putlog "-Seen- Deleted $nrdel expired nicks out of total $mtotal ([expr 100.0 * $nrdel / $mtotal]%)."
}
putlog "-Seen- Done. Next check will be done in $expirechk minutes."
timer $expirechk "check_expired"
}
proc putseen {out isdcc text} {
if {$isdcc} {
putdcc $out $text
} else {
putserv "PRIVMSG $out :$text"
}
}
# return how <who> left
proc adb_seengethow {who} {
switch [user-get $who seenhow] {
1 {
return "*kicked*"
}
default {
return "on"
}
}
}
# return 'one of my channels' if the channel
# is +secret
# return 'the channel'/'my party line' if the
# nick was on the same channel as the user is on
# return channel nick was last seen on otherwise
proc thechan {whochan userchan} {
if {$whochan == "my party line"} {
return "my party line"
}
if {[lsearch [channels] $whochan] == -1} {
return $whochan
}
if {[string tolower $whochan] == [string tolower $userchan]} {
return "this channel"
}
if {[lsearch [channel info $whochan] "+secret"] == -1} {
return $whochan
}
return ""
}
# show when <who> was last on
proc adb_seen {channel nick uhost handle who isdcc} {
global nlist botnick
set unick ""
if {$isdcc == 0} {
if {[string compare $channel $nick] != 0} {
append unick $nick ": "
}
}
if {$who == ""} {
putseen $channel $isdcc "${unick}Correct syntax is 'seen <nick>'"
return 1
}
set who [string trim [lindex $who 0] ?]
if {[string compare [string tolower $botnick] [string tolower $who]] == 0} {
putseen $channel $isdcc "${unick}Sure, I guess you don't see me now - right ??"
return 1
}
if {[string compare [string tolower $nick] [string tolower $who]] == 0} {
putseen $channel $isdcc "${unick}Aren't you in here right now ?? :)"
return 1
}
if {$unick==""} {
#request via MSG!
foreach chan [channels] {
if {[onchan $who $chan]} {
putseen $channel $isdcc "Hmm... Isn't $who on IRC right now ??"
return 1
}
if {[onchansplit $who $chan]} {
putseen $channel $isdcc "${who} was just on IRC, but got netsplit.. shame, huh?:)"
return 1
}
foreach i [chanlist $chan] {
set hand [finduser $i![getchanhost $i $chan]]
if {($hand != "*") && ([string compare [string tolower $hand] [string tolower $who]] == 0)} {
if {[onchansplit $i $chan]} {
putseen $channel $isdcc "$i is ${who}, and $i was just on [thechan $chan $channel] but got netsplit.."
} {
putseen $channel $isdcc "$i is ${who}, and $i is on [thechan $chan $channel] right now!"
}
return 1
}
}
}
} else {
#request via PUB!
#check if the nick is on YOUR channel
if {[onchansplit $who $channel]} {
putseen $channel $isdcc "${unick}${who} was just here, but got netsplit.. shame, huh?:)"
return 1
}
if {[onchan $who $channel]} {
putseen $channel $isdcc "${unick}${who} is on the channel right now - look in front of you !!"
return 1
}
foreach i [chanlist $channel] {
set hand [finduser $i![getchanhost $i $channel]]
if {($hand != "*") && ([string compare [string tolower $hand] [string tolower $who]] == 0)} {
if {[onchansplit $i $channel]} {
putseen $channel $isdcc "${unick}$i is ${who}, and $i was just here but got netsplit"
} {
putseen $channel $isdcc "${unick}$i is ${who}, and $i is on the channel right now!"
}
return 1
}
}
#hmm.. obviously not. let's check if he's on other channels we're on
set channel [string tolower $channel]
foreach chan [channels] {
if {[string compare [string tolower $chan] $channel] == 0} {
#already did this channel (YOUR channel)
continue
}
if {[onchansplit $who $chan]} {
putseen $channel $isdcc "${unick}${who} was just on [thechan $chan $channel] but got netsplit.. shame, huh?:)"
return 1
}
if {[onchan $who $chan]} {
putseen $channel $isdcc "${unick}If I'm not mistaken ${who} is on [thechan $chan $channel] at the moment..."
return 1
}
foreach i [chanlist $chan] {
set hand [finduser $i![getchanhost $i $chan]]
if {($hand != "*") && ([string compare [string tolower $hand] [string tolower $who]] == 0)} {
if {[onchansplit $i $chan]} {
putseen $channel $isdcc "${unick}$i is ${who}, and $i was just on [thechan $chan $channel] but got netsplit.."
} {
putseen $channel $isdcc "${unick}$i is ${who}, and $i is on [thechan $chan $channel] right now!"
}
return 1
}
}
}
}
if {[hand2idx $who] >= 0} {
if {[matchattr $handle p]} {
putseen $channel $isdcc "${unick}$who is on my party line right now !!"
return 1
}
}
append fwho "-" $who
set find [lsearch -exact $nlist [string tolower $fwho]]
if {$find!=-1} {
set ind $find
set ending " I cannot guarantee that it really was ${who} though (different host than the one I have stored in my userlist) !!"
} else {
append rwho "+" $who
set ind [lsearch -exact $nlist [string tolower $rwho]]
set ending ""
}
if {$ind == -1} {
if {[validuser $who]} {
set last [getuser $who LASTON $channel]
set seenon [thechan [getuser $who XTRA seenon] $channel]
switch [getuser $who XTRA seenhow] {
1 {
set seenhow "*kicked*"
}
default {
set seenhow ""
}
}
if {$last == 0} {
putseen $channel $isdcc "${unick}Sorry, but I haven't seen ${who} recently."
return 1
} else {
if {$seenon != ""} {
putseen $channel $isdcc "${unick}I last saw $who on $seenon - [tdiff [unixtime] $last]ago."
} else {
putseen $channel $isdcc "${unick}I last saw $who [tdiff [unixtime] $last]ago."
}
return 1
}
}
putseen $channel $isdcc "${unick}I haven't seen anyone with the nick - ${who}."
return 1
} else {
set last [lindex $nlist [expr $ind + 1]]
set seenon [thechan [lindex $nlist [expr $ind + 2]] $channel]
switch [lindex $nlist [expr $ind + 3]] {
1 {
set seenhow "*kicked*"
}
default {
set seenhow ""
}
}
if {($seenhow != "")&&($seenon != "")} {
putseen $channel $isdcc "${unick}I last saw $who on $seenon - $seenhow - [tdiff [unixtime] $last]ago."
} else {
putseen $channel $isdcc "${unick}I last saw $who [tdiff [unixtime] $last]ago."
}
return 1
}
}
# time difference
proc tdiff {time2 time1} {
set ltime [expr $time2 - $time1]
set seconds [expr $ltime % 60]
set ltime [expr ($ltime - $seconds) / 60]
set minutes [expr $ltime % 60]
set ltime [expr ($ltime - $minutes) / 60]
set hours [expr $ltime % 24]
set days [expr ($ltime - $hours) / 24]
set result ""
if {$days} {
append result "$days "
if {$days == 1} {
append result "day "
} else {
append result "days "
}
}
if {$hours} {
append result "$hours "
if {$hours == 1} {
append result "hour "
} else {
append result "hours "
}
}
if {$minutes} {
append result "$minutes "
if {$minutes == 1} {
append result "minute "
} else {
append result "minutes "
}
}
if {$seconds} {
append result " $seconds "
if {$seconds == 1} {
append result "second "
} else {
append result "seconds "
}
}
return $result
}
proc dcc_seen {hand idx arg} {
adb_seen $idx $hand "" $hand $arg 1
}
bind dcc - seen dcc_seen
proc pub_seen {nick uhost hand channel who} {
adb_seen $channel $nick $uhost $hand $who 0
}
bind pub - seen pub_seen
proc msg_seen {nick uhost hand who} {
adb_seen $nick $nick $uhost $hand $who 0
}
bind msg - seen msg_seen
proc seen_join {nick uhost hand channel} {
nick_upd $channel $nick $hand 0
}
bind join - * seen_join
proc seen_part {nick uhost hand channel} {
nick_upd $channel $nick $hand 0
}
bind part - * seen_part
proc seen_sign {nick uhost hand channel reason} {
nick_upd $channel $nick $hand 0
}
bind sign - * seen_sign
proc seen_nickch {nick uhost hand channel newnick} {
nick_upd $channel $nick $hand 0
nick_upd $channel $newnick $hand 0
}
bind nick - * seen_nickch
proc seen_kick {nick uhost hand channel kicked reason} {
set hand [nick2hand $kicked $channel]
nick_upd $channel $kicked $hand 1
}
bind kick - * seen_kick
proc seen_chof {hand idx} {
nick_upd "my party line" $hand $hand 0
}
bind chof - * seen_chof
#for testing/emergency nick save only
bind dcc m savenicks dcc_nick_save
#force deletion of nicks in the nickfile that are in the userlist
#(this command should be issued if new users are added to the bot's
#userlist)
bind dcc m seenupd force_seenupd
# script initialization
putlog "$seenver loaded"
# set defaults
if {!([info exists seennicks])} { set seennicks {seen.nicks} }
if {!([info exists nicksavetime])} { set nicksavetime 15 }
if {!([info exists nickexpire])} { set nickexpire 720 }
if {!([info exists expirechk])} { set expirechk 60 }
if [file exists $seennicks] {
set f [open $seennicks r]
if {[gets $f nlist] != -1} {
if {[expr [llength $nlist] % 4] != 0} {
putlog "-Seen- Invalid nicks list.. Clearing nicks list."
set nlist ""
}
} else {
putlog "-Seen- Invalid data file. Nicks list not loaded."
set nlist ""
}
close $f
}
# update users on the channel
foreach chan [channels] {
foreach n [chanlist $chan] {
set hand [nick2hand $n $chan]
nick_upd $chan $n $hand 0
}
}
nick_save
check_expired