################################################
#################### ABOUT #####################
################################################
#
# Reminder-0.2 by Fredrik Bostrom
# for Eggdrop IRC bot
#
# Usage:
# !remind nick time message
# - creates a new reminder for nick in the
# current channel at time with message
# - time is a format parseable by the tcl
# command 'clock scan'. If the time consists
# of several words, it has to be enclosed
# in "".
# - examples:
# !remind morbaq "tomorrow 10:00" Call Peter
# !remind morbaq "2009-12-31 23:59" Happy new year!
#
# !reminders
# - lists all active reminders
#
# !cancelReminder id
# - cancels the reminder with id
# - the id is the number preceeding the
# reminder in the list produced by
# !reminders
# - note: the id may change as new reminders
# are added or old reminders removed. Always
# check the id just before cancelling
#
#
################################################
################ CONFIGURATION #################
################################################
set datafile "scripts/reminders.dat"
################################################
######## DON'T EDIT BEOYND THIS LINE! ##########
################################################
bind pub - "!clockscan" pub:clockscan
bind pub - "!remind" pub:newReminder
bind pub - "!remindme" pub:newReminderfornick
bind pub - "!reminders" pub:getReminders
bind pub n "!cancelReminder" pub:cancelReminder
bind pub n "\$inspectReminders" pub:inspectReminders
array set reminders {}
# save to file
proc saveReminders {} {
global reminders
global datafile
set file [open $datafile w+]
puts $file [array get reminders]
close $file
}
# the run-at-time procedure
proc at {time args} {
if {[llength $args]==1} {
set args [lindex $args 0]
}
set dt [expr {($time - [clock seconds])*1000}]
return [after $dt $args]
}
proc printReminder {reminderId {tonick ""} {fire "false"}} {
global reminders
# get the reminder
set reminder $reminders($reminderId)
set when [clock format [lindex $reminder 0] -format "%Y-%m-%dT%H:%M:%SZ"]
set chan [lindex $reminder 1]
set who [lindex $reminder 2]
set timer [lindex $reminder 3]
set what [lindex $reminder 4]
if {$fire} {
if {[onchan $who $chan]} {
putserv "PRIVMSG $chan :\[remind\] $who: $what"
} else {
putserv "PRIVMSG $chan :!tell $who \[remind\] $what"
#tell {nick uhost hand chan text}
tell $who "" "" $chan "$who \[remind\] $what"
}
} else {
putserv "NOTICE $tonick :\[remind\] $reminderId: for $who at $when: $what"
}
}
proc fireReminder {reminderId} {
global reminders
printReminder $reminderId "" "true"
unset reminders($reminderId)
saveReminders
}
proc pub:clockscan {nick host handle chan text} {
set timeError ""
# parse parameters
set curTime [clock format [clock seconds] -format "%H:%M:%SZ" -gmt 1]
regsub -all {([0-9]+)y$} $text "\\1 years $curTime" text
regsub -all {([0-9]+)mo$} $text "\\1 months $curTime" text
regsub -all {([0-9]+)w$} $text "\\1 weeks $curTime" text
regsub -all {([0-9]+)d$} $text "\\1 days $curTime" text
regsub -all {([0-9]+)hr?$} $text {\1 hours} text
regsub -all {([0-9]+)m$} $text {\1 minutes} text
regsub -all {([0-9]+)s$} $text {\1 seconds} text
set time [catch {clock scan $text} timeResult]
if {$time != 0} {
putserv "NOTICE $chan :\[remind\] unable to parse time: $timeResult"
return 1
}
set ISOTimeResult [clock format $timeResult -format "%Y-%m-%dT%H:%M:%SZ" -gmt 1]
if {[clock seconds] > $timeResult} {
putserv "NOTICE $chan :\[clockscan\] error: \"$text\" (parsed as $timeResult → $ISOTimeResult) is in the past"
return 1
}
putserv "NOTICE $chan :\[clockscan\] parsed \"$text\" as $timeResult → $ISOTimeResult"
}
proc pub:newReminderfornick {nick host handle chan text} {
global reminders
set timeError ""
# parse parameters
set id [clock seconds]
set who $nick
set when [lindex $text 0]
set curTime [clock format [clock seconds] -format "%H:%M:%SZ" -gmt 1]
regsub -all {([0-9]+)y$} $when "\\1 years $curTime" when
regsub -all {([0-9]+)mo$} $when "\\1 months $curTime" when
regsub -all {([0-9]+)w$} $when "\\1 weeks $curTime" when
regsub -all {([0-9]+)d$} $when "\\1 days $curTime" when
regsub -all {([0-9]+)hr?$} $when {\1 hours} when
regsub -all {([0-9]+)m$} $when {\1 minutes} when
regsub -all {([0-9]+)s$} $when {\1 seconds} when
set time [catch {clock scan $when} timeResult]
set what [lrange $text 1 end]
if {$when == ""} {
putserv "NOTICE $chan :\[remind\] !remindme \"<time>\" <message> (time is a format parseable by the TCL command 'clock scan' - https://www.tcl.tk/man/tcl8.6/TclCmd/clock.html)"
return 0
}
if {$time != 0} {
putserv "NOTICE $chan :\[remind\] unable to parse time: $timeResult"
return 1
}
set ISOTimeResult [clock format $timeResult -format "%Y-%m-%dT%H:%M:%SZ" -gmt 1]
if {[clock seconds] > $timeResult} {
putserv "NOTICE $chan :\[remind\] error: \"$when\" (parsed as $timeResult → $ISOTimeResult) is in the past"
return 1
}
# create new entry
set new [list $timeResult $chan $who null $what]
# activate the event
set timer [at $timeResult fireReminder $id]
# putlog "new timer: $timer"
# set the timer associated with this reminder
set new [lreplace $new 3 3 $timer]
# putlog "new reminder: $new"
set reminders($id) $new
saveReminders
putserv "NOTICE $chan :\[remind\] ok, i'll remind you at $ISOTimeResult"
}
proc pub:newReminder {nick host handle chan text} {
global reminders
# parse parameters
set id [clock seconds]
set who [lindex $text 0]
set when [lindex $text 1]
set curTime [clock format [clock seconds] -format "%H:%M:%SZ" -gmt 1]
regsub -all {([0-9]+)y$} $when "\\1 years $curTime" when
regsub -all {([0-9]+)mo$} $when "\\1 months $curTime" when
regsub -all {([0-9]+)w$} $when "\\1 weeks $curTime" when
regsub -all {([0-9]+)d$} $when "\\1 days $curTime" when
regsub -all {([0-9]+)hr?$} $when {\1 hours} when
regsub -all {([0-9]+)m$} $when {\1 minutes} when
regsub -all {([0-9]+)s$} $when {\1 seconds} when
set time [catch {clock scan $when} timeResult]
set what [lrange $text 2 end]
if {$who == "" || $when == "" || $what == ""} {
putserv "NOTICE $chan :\[remind\] !remind <nick> \"<time>\" <message> (time is a format parseable by the TCL command 'clock scan' - https://www.tcl.tk/man/tcl8.6/TclCmd/clock.html)"
return 0
}
if {$time != 0} {
putserv "NOTICE $chan :\[remind\] unable to parse time: $timeResult"
return 1
}
set ISOTimeResult [clock format $timeResult -format "%Y-%m-%dT%H:%M:%SZ" -gmt 1]
if {[clock seconds] > $timeResult} {
putserv "NOTICE $chan :\[remind\] error: \"$when\" (parsed as $ISOTimeResult) is in the past"
return 1
}
# create new entry
set new [list $timeResult $chan $who null $what]
# activate the event
set timer [at $timeResult fireReminder $id]
# putlog "new timer: $timer"
# set the timer associated with this reminder
set new [lreplace $new 3 3 $timer]
# putlog "new reminder: $new"
set reminders($id) $new
saveReminders
putserv "NOTICE $chan :\[remind\] ok, i'll remind $who at $ISOTimeResult"
}
proc pub:getReminders {nick host handle chan text} {
global reminders
set chanReminders {}
# count all reminders for this channel
foreach {key value} [array get reminders] {
if {[lindex $value 1] == $chan} {
lappend chanReminders $key
}
}
# count the reminders
set howMany [llength $chanReminders]
# do we have reminders?
if {$howMany < 1} {
putserv "NOTICE $nick :\[remind\] no active reminders"
return
}
# print reminders for this channel
putserv "NOTICE $nick :\[remind\] $howMany active reminder(s):"
foreach key $chanReminders {
printReminder $key $nick
}
}
proc pub:cancelReminder {nick host handle chan text} {
global reminders
set reminder $reminders($text)
set timer [lindex $reminder 3]
# putlog "Cancelling timer: $timer"
after cancel $timer
unset reminders($text)
putserv "PRIVMSG $chan :Removed reminder with id $text"
saveReminders
}
proc pub:inspectReminders {nick host handle chan text} {
global reminders
set timerString [after info]
set reminderString [array get reminders]
putserv "NOTICE $nick :Reminders: $reminderString"
putserv "NOTICE $nick :Timers: $timerString"
}
proc initReminders {} {
global reminders
set reminderString [array get reminders]
# putlog "Initiating reminders: $reminderString"
# get current time
set time [clock seconds]
# get active timers
set activeTimers [after info]
# check for expired reminders and fire them
foreach {key value} [array get reminders] {
if {[lindex $value 0] < $time} {
fireReminder $key
} elseif {[lsearch $activeTimers [lindex $value 3]] == -1} {
# if the reminder hasn't expired, check if the timer is already set
set timerId [at [lindex $value 0] fireReminder $key]
set reminders($key) [lreplace $value 3 3 $timerId]
}
}
saveReminders
}
# read the old if they exist
set file [open $datafile]
set content [read $file]
close $file
if {$content == ""} {
set content {}
}
array set reminders $content
initReminders
###################################
putlog "Reminder script loaded!"
###################################