Mercurial > hg > egg-tcls
view tj.tcl @ 613:ea6ebcf42b47
TJ: Initial commit of the TJ2.0 refactoring effort. Instead of using Eggdrop
XTRA user flags for storing data, we now employ a SQLite3 database. The
database schema is probably not yet "final", so maybe beware of deploying
this script yet. Also add example configuration file and script for creating
the empty database tables.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Wed, 10 Feb 2021 11:12:13 +0200 |
parents | 14dfb925a64a |
children | 8c61b4032648 |
line wrap: on
line source
########################################################################## # # TJ v2.0 by ccr/TNSP <ccr@tnsp.org> # (C) Copyright 2021 Tecnic Software productions (TNSP) # # This script is freely distributable under GNU GPL (version 2) license. # ########################################################################## ### The configuration should be in config.tj in same directory ### as this script. Or change the line below to point where ever ### you wish. See "config.tj.example" for an example config file. source [file dirname [info script]]/config.tj ### Required utillib.tcl source [file dirname [info script]]/utillib.tcl ########################################################################## # No need to look below this line ########################################################################## package require sqlite3 package require textutil::split set tj_name "TJ" set tj_message "$tj_name v2.0 (C) 2021 ccr/TNSP" # ------------------------------------------------------------------------ ### Utility functions proc tj_log {umsg} { global tj_log_enable tj_name if {$tj_log_enable != 0} { putlog "${tj_name}: $umsg" } } proc tj_qm {uid} { global tj_messages if {[info exists tj_messages($uid)]} { return $tj_messages($uid) } else { return $uid } } proc tj_smsg {apublic anick achan amsg {aargs {}}} { global tj_preferredmsg tj_cmd_name set amsg [string map [list "@cmd@" $tj_cmd_name] $amsg] utl_msg_args $tj_preferredmsg $apublic $anick $achan $amsg $aargs } proc tj_msg {apublic anick achan aid {aargs {}}} { tj_smsg $apublic $anick $achan [tj_qm $aid] $aargs } proc tj_correct_handle {uhand} { set ulower [string tolower $uhand] foreach uuser [userlist] { if {[string tolower $uuser] == $ulower} { return $uuser } } return "" } proc tj_cmd_match {uid ustr} { global tj_commands return [utl_cmd_match tj_commands $uid $ustr] } proc tj_arg_rest {rarglist rindex rstr} { upvar $rstr dstr if {$rindex < [llength $rarglist]} { set dstr [join [lrange $rarglist $rindex end] " "] return 1 } else { return 0 } } proc tj_get_id {rstr rindex rid} { global tj_default_id upvar $rindex uindex upvar $rid uid if {[string index $rstr 0] == "#"} { set uid [string tolower [string range $rstr 1 end]] incr uindex return 1 } else { set uid $tj_default_id return 0 } } proc tj_ctime {ustamp} { return [clock format $ustamp -format [tj_qm "datefmt"]] } # ------------------------------------------------------------------------ proc tj_str_append { qlist qvalue qsingular qplural } { upvar $qlist ulist if {$qvalue > 0} { if {$qvalue > 1} { set qfmt $qplural } else { set qfmt $qsingular } lappend ulist [utl_str_map_values [tj_qm "tj_str_${qfmt}"] [list $qvalue]] } } proc tj_get_tj_str {udelta} { if {$udelta < 0} { set utmp [expr -$udelta] } else { set utmp $udelta } set uyears [expr ($utmp / (365*24*60*60))] set urem [expr ($utmp % (365*24*60*60))] set udays [expr ($urem / (24*60*60))] set urem [expr ($urem % (24*60*60))] set uhours [expr ($urem / (60*60))] set urem [expr ($urem % (60*60))] set uminutes [expr ($urem / 60)] set ulist {} tj_str_append ulist $uyears "year" "years" tj_str_append ulist $udays "day" "days" tj_str_append ulist $uhours "hour" "hours" tj_str_append ulist $uminutes "minute" "minutes" set ustr [join [lrange $ulist 0 end-1] [tj_qm "tj_str_sep"]] if {[llength $ulist] > 1} { append ustr [tj_qm "tj_str_sep_last"] } append ustr [lindex $ulist end] return $ustr } proc tj_get_tj_str_delta { ustamp } { set udelta [expr $ustamp - [clock seconds]] if {$udelta < 0} { set ufmt "tj_past" } else { set ufmt "tj_remaining" } # return [utl_str_map_values [tj_qm $ufmt] [list ]] return [tj_get_tj_str $udelta] } proc tj_display_tjs {upublic unick uchan uname uid} { set uclock [clock seconds] set nresults 0 set usql "SELECT * FROM tj WHERE uuser='[utl_escape $uname]' AND utype=0 AND uid='[utl_escape $uid]'" tj_dbh eval $usql { incr nresults set ustamp [utl_sql_datetime_to_stamp $utarget] set udelta [expr $ustamp - $uclock] if {$udelta < 0} { set ufmt "tj_past" } else { set ufmt "tj_remaining" } tj_msg $upublic $unick $uchan $ufmt [list $uname $uid [tj_get_tj_str $udelta] [tj_ctime $ustamp]] } if {!$nresults} { tj_msg $upublic $unick $uchan "tj_not_set" [list $uname $uid] } } # ------------------------------------------------------------------------ proc tj_cmd {unick $uhost uhand uchan uargs upublic} { global tj_messages tj_default_id tj_default_time tj_default_desc # Check if we have a valid user if {![utl_valid_user $uhand]} { tj_msg $upublic $unick $uchan "err_invalid_user" [list $uhand] return 1 } set uhand [tj_correct_handle $uhand] # Check and handle arguments set rarglist [::textutil::split::splitx $uargs {\s+}] set rcmd [lindex $rarglist 0] if {[tj_cmd_match "help" $rcmd]} { # Show help foreach ukey $tj_messages(help_full) { tj_msg $upublic $unick $uchan $ukey } return 1 } elseif {[tj_cmd_match "set" $rcmd]} { # !tj set [#id] <[-/+]days [[+/-]<hours>] | dd.mm.yyyy [hh:mm]> [<desc>] set rindex 1 if {![utl_arg_get $rarglist rindex rarg 0]} { tj_msg $upublic $unick $uchan "help_set" return 1 } # Check for #id prefix if {[tj_get_id $rarg rindex uid]} { set rdesc "" } else { set rdesc $tj_default_desc } if {![utl_arg_get $rarglist rindex rarg 1]} { tj_msg $upublic $unick $uchan "help_set" return 1 } # Is it a time stamp? if {[regexp {\d+\.\d+\.\d\d\d\d} $rarg rdate]} { # Seems so .. check for hours set rtime $tj_default_time if {[utl_arg_get $rarglist rindex rarg 0]} { if {[regexp {\d+:\d+} $rarg rtime]} { incr rindex } else { set rtime $tj_default_time } } tj_arg_rest $rarglist $rindex rdesc # Check the timestamp validity if {[catch {set rstamp [clock scan "${rdate} ${rtime}" -format "%d.%m.%Y %H:%M"]} uerrmsg]} { tj_msg $upublic $unick $uchan "err_timestamp" [list $uerrmsg $rdate $rtime] return 1 } } elseif {[regexp {(\+|\-)?(\d+)} $rarg -> dsign rdays]} { # Check for days if {$dsign == "-"} { set rdays [expr -$rdays] } set rhours 0 if {[utl_arg_get $rarglist rindex rarg 0]} { if {[regexp {(\+|\-)?(\d+)} $rarg -> hsign rhours]} { if {$hsign == "-"} { set rhours [expr -$rhours] } incr rindex } tj_arg_rest $rarglist $rindex rdesc if {$rhours < -24 || $rhours > 24} { tj_msg $upublic $unick $uchan "err_invalid_hours" [list $rhours] return 1 } } # Compute target timestamp set rstamp [expr [clock seconds] + ($rdays * 24 * 60 * 60) + ($rhours * 60 * 60)] } else { # Only description, if any if {![tj_arg_rest $rarglist 1 rdesc]} { tj_msg $upublic $unick $uchan "err_invalid_format" [list] return 1 } set rstamp "invalid" } # Check if ID exists set umode 1 set nres 0 set usql "SELECT * FROM tj WHERE uid='[utl_escape $uid]'" tj_dbh eval $usql { set umode 0 set cid $id set ctarget $utarget incr nres } # Check for DB sanity if {$nres > 1} { tj_msg $upublic $unick $uchan "err_db_corrupt" [list $nres] tj_log "too many $nres fatal error piip" return 1 } # Check if we are trying to add a new entry without valid timestamp if {$rstamp == "invalid"} { if {$umode} { tj_msg $upublic $unick $uchan "err_missing_timestamp" return 1 } set rdate $ctarget set ustamp [utl_sql_datetime_to_stamp $ctarget] } else { set rdate [utl_sql_stamp_to_datetime $rstamp] set ustamp $rstamp } set utjstr [tj_get_tj_str_delta $rstamp] set udate [tj_ctime $ustamp] # Max reminders .. set usql "SELECT COUNT(*) FROM tj WHERE uuser='[utl_escape $uhand]'" if {[catch {set nreminders [tj_dbh onecolumn $usql]} uerrmsg]} { tj_msg $upublic $unick $uchan "err_sql" [list $uerrmsg] tj_log "$uerrmsg on SQL:\n$usql" return 1 } # Check for maximum reminders if {$nreminders > 5} { tj_msg $upublic $unick $uchan "err_too_many" [list $nreminders] return 1 } if {$umode} { # Insert new entry set usql "INSERT INTO tj (uid,uuser,ucreated,udesc,utype,utarget) VALUES ('[utl_escape $uid]', '[utl_escape $uhand]', [unixtime], '[utl_escape $rdesc]', 0, '$rdate')" if {[catch {tj_dbh eval $usql} uerrmsg]} { tj_msg $upublic $unick $uchan "err_sql" [list $uerrmsg] tj_log "$uerrmsg on SQL:\n$usql" return 1 } set cid [tj_dbh last_insert_rowid] tj_msg $upublic $unick $uchan "tj_set" [list $cid $uid $uhand $rdesc $udate $utjstr] tj_log "tj_set $cid:$uid:$uhand:$rdesc:$rdate:$udate" } else { # Update existing entry set usqlargs {} if {[string length $rdesc] > 0} { lappend usqlargs "udesc='[utl_escape $rdesc]'" } if {$rstamp != "invalid"} { lappend usqlargs "utarget='$rdate'" } if {[llength $usqlargs] > 0} { set usql "UPDATE tj SET [join $usqlargs ,] WHERE uid='[utl_escape $uid]'" if {[catch {tj_dbh eval $usql} uerrmsg]} { tj_msg $upublic $unick $uchan "err_sql" [list $uerrmsg] tj_log "$uerrmsg on SQL:\n$usql" return 1 } } tj_msg $upublic $unick $uchan "tj_updated" [list $cid $uid $uhand $rdesc $udate $utjstr] tj_log "tj_updated $cid:$uid:$uhand:$rdesc:$rdate:$udate" } } elseif {[tj_cmd_match "remind" $rcmd]} { # !tj remind <#id> <<dd.mm.yyyy [hh:mm]>|<message>> # !tj remind <#id> <<dd.mm [hh:mm]>|<message>> if {[llength $rarglist] < 3} { tj_msg $upublic $unick $uchan "help_add" return 1 } } elseif {[tj_cmd_match "list" $rcmd]} { # !tj list # List reminders set uclock [clock seconds] set nresults 0 set usql "SELECT * FROM tj WHERE uuser='[utl_escape $uhand]' ORDER BY ucreated" tj_dbh eval $usql { incr nresults tj_msg $upublic $unick $uchan "#${nresults}: $utype : $utarget : $uid : $udesc" } if {!$nresults} { tj_msg $upublic $unick $uchan "no_results" [list $uname] } } elseif {[tj_cmd_match "delete" $rcmd]} { # !tj delete <id> tj_msg $upublic $unick $uchan "help_delete" } elseif {[tj_cmd_match "show" $rcmd]} { # !tj show [#id] <name> # Check for #id prefix set rindex 1 if {[utl_arg_get $rarglist rindex rarg 0]} { tj_get_id $rarg rindex uid } if {![utl_arg_get $rarglist rindex rarg 0]} { tj_msg $upublic $unick $uchan "help_show" return 1 } set uname [tj_correct_handle $rarg] if {$uname == ""} { tj_msg $upublic $unick $uchan "err_unknown_user" [list $rcmd] return 1 } tj_display_tjs $upublic $unick $uchan $uname $uid } else { # !tj [#id] [name] set uname $uhand set rindex 0 if {[utl_arg_get $rarglist rindex rarg 0]} { # Check for #id prefix tj_get_id $rarg rindex uid if {[utl_arg_get $rarglist rindex rarg 0]} { set uname [tj_correct_handle $rarg] if {$uname == ""} { tj_msg $upublic $unick $uchan "err_unknown_user" [list $rcmd] return 1 } } } else { set uid $tj_default_id } tj_display_tjs $upublic $unick $uchan $uname $uid } return 1 } #------------------------------------------------------------------------- # Script initialization #------------------------------------------------------------------------- putlog "$tj_message" if {[catch {sqlite3 tj_dbh $tj_db_file} uerrmsg]} { putlog "Could not open SQLite3 database '${tj_db_file}': ${uerrmsg}" exit 2 } # end of script