moontalk/client/moontalk-tcl/moontk.tcl
2024-02-17 18:26:14 +00:00

197 lines
5.0 KiB
Tcl
Executable File

#!/usr/bin/wish
# Default values.
set host "7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion"
set port "50000"
set username "anonymous"
set reconnect_max_tries -1
set reconnect_time 10000
set notification_exe "/usr/bin/aplay"
set notification_file "./notification.wav"
set notification_delay 1000
# Don't touch these
set identity "Anon ?"
set reconnect_try 0
set sock 0
set notification_cooldown 0
proc window_visibility {w val} {
if {$val} {
wm deiconify $w
} else {
wm withdraw $w
}
}
proc on_user_connect {w} {
global reconnect_try
set reconnect_try 0
window_visibility . true
socket_connect
window_visibility $w false
}
proc display_connect_dialog {} {
global reconnect_try
global host
global port
set w .wconnect
if { [winfo exists $w] } {
window_visibility $w true
focus $w
} else {
toplevel $w
wm title $w "MoonTk - Connect to MoonTalk"
set callback_wrapper "on_user_connect $w"
pack [label $w.lh -text "Host:"] -anchor w
pack [entry $w.eh -textvariable host] -fill x
pack [label $w.lp -text "Port:"] -anchor w
pack [entry $w.ep -textvariable port] -fill x
pack [button $w.bc -text "connect" -command $callback_wrapper]
bind $w.eh <Return> $callback_wrapper
bind $w.eh <KP_Enter> $callback_wrapper
bind $w.ep <Return> $callback_wrapper
bind $w.ep <KP_Enter> $callback_wrapper
focus $w
}
}
wm title . "MoonTk"
pack [entry .input] -side bottom -fill x
pack [scrollbar .sy -command {.messages yview}] -side right -fill y
pack [text .messages -wrap none -xscrollcommand {.sx set} -yscrollcommand {.sy set}] -fill both -expand 1
pack [scrollbar .sx -orient horizontal -command {.messages xview}] -fill x
proc socket_connect {} {
global sock
global host
global port
append_message "Connecting to $host:$port..."
if {[catch {socket -async $host $port} sock]} {
on_socket_connection_failed
} else {
fconfigure $sock -blocking false
fconfigure $sock -translation binary
fileevent $sock readable on_socket_receive
fileevent $sock writable on_socket_connect
}
}
proc on_socket_connect {} {
global reconnect_try
global sock
set error [fconfigure $sock -error]
if {$error ne ""} {
catch {close $sock}
on_socket_connection_failed
return
}
append_message "Successfully connected to the server."
fileevent $sock writable {}
set reconnect_try 0
}
proc on_socket_connection_failed {} {
global reconnect_time
global reconnect_max_tries
global reconnect_try
if { $reconnect_max_tries != -1
&& $reconnect_try >= $reconnect_max_tries } {
tk_messageBox -message "Maximum reconnect tries reached." -type ok
display_connect_dialog
} else {
set reconnect_try [expr {$reconnect_try + 1}]
append_message "Failed to connect to the server, retrying in [expr {$reconnect_time/1000}] seconds."
after $reconnect_time socket_connect
}
}
proc on_socket_disconnect {} {
append_message "Disconnected from server..."
socket_connect
}
proc parse_identity {data} {
global identity
regexp -all {^Server: You are now known as \"(.+)\"\.} $data whole_match ident
if {[info exists ident]} {
set identity $ident
}
}
proc reset_notification {} {
global notification_cooldown
set notification_cooldown 0
}
proc play_notification {} {
global notification_exe
global notification_file
global notification_cooldown
global notification_delay
set notification_cooldown 1
exec $notification_exe $notification_file "&"
after $notification_delay reset_notification
}
proc on_socket_receive {} {
global sock
global identity
global notification_cooldown
set error [fconfigure $sock -error]
# catch gets = read error
# eof = other side disconnected
if { $error ne ""
|| [catch {gets $sock} data]
|| [eof $sock]} {
catch {close $sock}
on_socket_disconnect
return
}
if {[string match "Server: *" $data]} {
parse_identity $data
}
if { !$notification_cooldown } {
play_notification
}
append_message $data
}
proc send_message {msg} {
global sock
global identity
set formatted_msg [format_message $msg]
puts $sock $formatted_msg
flush $sock
append_message "$identity: $formatted_msg"
}
proc timestamp {} {
return [clock format [clock seconds] -gmt true -format {%Y/%m/%d %H:%M:XX}]
}
proc format_message {msg} {
global username
set ts [timestamp]
if {[string match "/*" $msg]} {
return $msg
} else {
return "<$ts $username> $msg"
}
}
proc append_message {msg} {
.messages insert end "$msg\n"
.messages see end
}
proc user_enter {} {
send_message [.input get]
.input delete 0 end
}
bind .input <Return> user_enter
bind .input <KP_Enter> user_enter
window_visibility . false
display_connect_dialog