#!/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 $callback_wrapper bind $w.eh $callback_wrapper bind $w.ep $callback_wrapper bind $w.ep $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 user_enter bind .input user_enter window_visibility . false display_connect_dialog