197 lines
5.0 KiB
Tcl
197 lines
5.0 KiB
Tcl
|
#!/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
|