source [file join [file dirname [info script]] history.tcl]
namespace eval ::xmppplugin {
- variable version 0.2
+ variable version 0.3
variable uid; if {![info exists uid]} { set uid 0 }
variable defaults {
-server "all.tclers.tk"
-resource "Bullfrog"
-port 5222
-channel "tcl@tach.tclers.tk"
- callback ""
- motd {}
- users {}
+ -nick ""
+ callback ""
+ motd {}
+ users {}
}
namespace export connect send post splituri
}
+#autosocks::config -proxy socks5 -proxyhost localhost -proxyport 9050
+
+
proc ::xmppplugin::connect {callback args} {
variable defaults
variable uid
upvar #0 $context xmpp
array set xmpp $defaults
array set xmpp $args ;# see XmppLogin for the list of pairs
-
+ set xmpp(msgid) 0
set xmpp(callback) $callback
+ if {$xmpp(-nick) eq ""} {set xmpp(-nick) $xmpp(-username)}
set xmpp(jlib) [jlib::new [namespace origin OnNetwork] \
-messagecommand [namespace origin OnMessage] \
-presencecommand [namespace origin OnPresence] \
} else {
$xmpp(jlib) connect connect $xmpp(jid) $xmpp(-passwd) \
-command [list [namespace origin OnConnect] $context] \
- -secure 1 -method tlssasl \
- -ip $xmpp(-server) -port $xmpp(-port)
+ -secure 1 -method tlssasl -transport tcp\
+ -ip $xmpp(-server) -port $xmpp(-port) -timeout 120000
}
return $context
}
return
}
"/me *" { }
+ "/ping *" {
+ set target [string trim [string range $msg 6 end]]
+ ping $ctx $target
+ return
+ }
default {
Callback $ctx system $channel [mc "unrecognised chat command '%s'" $msg]
return
}
set margs [list -type $type -body $msg -xlist $xlist]
if {$thread ne ""} { lappend margs -thread $thread }
+ if {$type eq "chat"} {
+ # we _SHOULD_ only do this if we negotiated support with the remote client
+ lappend margs -id [incr xmpp(msgid)] -xlist \
+ [list [wrapper::createtag request -attrlist {xmlns urn:xmpp:receipts}]]
+ }
eval [linsert $margs 0 $xmpp(jlib) send_message $channel]
if {$type eq "chat"} {
set mtype normal
ok {
Callback $ctx connect
$jlib send_presence
- $jlib send_presence -priority 2 -show available
+ $jlib send_presence -priority 2
$jlib roster send_get -command [list [namespace origin OnRosterGet] $ctx]
if {$xmpp(-autoconnect) && $xmpp(-channel) ne {}} {
- Log $ctx "Attempting to join $xmpp(-channel)"
+ Log $ctx "Attempting to join '$xmpp(-channel)' as '$xmpp(-nick)'"
JoinMUC $ctx $xmpp(-channel) $jlib $xmpp(-nick)
}
}
}
proc ::xmppplugin::JoinMUC {ctx channel jlib nick} {
+ Log $ctx "JoinMUC '$channel' as '$nick'"
#set t 1202713200
#set since [list since [clock format $t -format {%Y-%m-%dT%T}]]
set since [list maxstanzas 100]
}
proc ::xmppplugin::OnRosterChange {ctx jlib what {jid {}} args} {
- #Log $ctx "Roster '$what' '$jid' '$args'"
+ Log $ctx "Roster '$what' '$jid' '$args'"
#enterroster | exitroster | set jid args | remove jid |
#switch -exact -- $what {}
return 0
[wrapper::getfirstchildwithtag $xmldata status]]
Callback $ctx traffic left $room $nick {} $time -status $status
}
+ } else {
+ # chat or roster user - if we have an open chat for them, fix the icon
+ # FIX ME: move into callback and fix up session
+ set Session ::xmpp1
+ upvar #0 $Session session
+ array set a [linsert [wrapper::getattrlist $xmldata] 0 type available]
+ set w [XmppFindWindow $Session $a(from)]
+ if {[winfo exists $w] && $w ne $session(window)} {
+ set image [XmppGetPresenceImage $Session $a(from)]
+ $session(app).nb tab $w -image $image
+ }
+ #Callback $ctx presence $a(from)
}
} err]} { puts stderr "OnPresenceChange: $err" }
return 0
proc ::xmppplugin::OnPresence {jlib xmldata} {
set ctx [set [set jlib]::AppContext]
if {[catch {OnPresence2 $ctx $jlib $xmldata} res]} {
- Log $ctx "OnPresence: $err" error
+ Log $ctx "OnPresence: $res" error
return 0
}
return $res
proc ::xmppplugin::OnIq {jlib xmldata} {
set ctx [set [set jlib]::AppContext]
if {[catch {OnIq2 $ctx $jlib $xmldata} res]} {
- Log $ctx "OnIq: $err" error
+ Log $ctx "OnIq: $res" error
return 0
}
return $res
return 0
}
+proc ::xmppplugin::ping {ctx jid} {
+ upvar #0 $ctx xmpp
+ set xmllist [wrapper::createtag ping -attrlist [list xmlns urn:xmpp:ping]]
+ $xmpp(jlib) send_iq get [list $xmllist] -to $jid \
+ -command [namespace code [list on_ping $ctx $jid \
+ [clock clicks -milliseconds]]]
+ return
+}
+proc ::xmppplugin::on_ping {ctx jid sent type args} {
+ switch -exact -- $type {
+ result {
+ set t [expr {[clock clicks -milliseconds] - $sent}]
+ Callback $ctx status "ping to $jid took $t ms"
+ }
+ error {
+ set t [expr {[clock clicks -milliseconds] - $sent}]
+ set msg [lindex [lindex $args 0] 0]
+ Callback $ctx status "ping to $jid failed in $t ms: $msg"
+ }
+ default {
+ Log $ctx "on_ping: $ctx $jid $sent ms $type '$args'"
+ }
+ }
+}
+
proc ::xmppplugin::OnMessage {jlib xmldata} {
set ctx [set [set jlib]::AppContext]
if {[catch {OnMessage2 $ctx $jlib $xmldata} err]} {
}
headline {
Callback $ctx chat $a(to) $a(from) \
- "header: [wrapper::etcdata [lindex $body 0]]" normal $time
+ "header: [wrapper::getcdata [lindex $body 0]]" normal $time
Log $ctx "$a(from)->$a(to) headline $xmldata"
}
error {
}
$chan(window) hook add post [list ::xmppplugin::post $chan(xmpp) $channel]
bind $chan(window) <Destroy> "+unset -nocomplain $Channel"
-
+ XmppAddTab $Session $chan(window) $channel
+ after idle [list $session(app).nb select $chan(window)]
+ return $chan(window)
+}
+
+proc XmppAddTab {Session window jid} {
+ upvar #0 $Session session
+ upvar #0 $session(xmpp) xmpp
# If the channel domain is a muc then use the resource.
- upvar #0 $chan(xmpp) xmpp
- jlib::splitjidex $channel node domain resource
+ jlib::splitjidex $jid node domain resource
if {[$xmpp(jlib) muc isroom $node@$domain]} {
set title $resource
+ set image ::img::msgchat
+ $session(app).nb add $window -text $title -image $image -compound left
} elseif {$node ne {}} {
set title $node
- } else { set title $domain }
- $session(app).nb add $chan(window) -text $title
- after idle [list $session(app).nb select $chan(window)]
- return $chan(window)
+ set rs [dict create {*}[$xmpp(jlib) roster getpresence\
+ $node@$domain -resource $resource]]
+ set image [XmppGetPresenceImage $Session $jid]
+ $session(app).nb add $window -text $title -image $image -compound left
+ } else {
+ set title $domain
+ $session(app).nb add $window -text $title -compound none
+ }
+}
+
+proc XmppGetPresenceImage {Session jid} {
+ upvar #0 $Session session
+ upvar #0 $session(xmpp) xmpp
+ jlib::splitjidex $jid node domain resource
+ if {$resource eq {}} {
+ array set info [lindex [$xmpp(jlib) roster getpresence $node@$domain] 0]
+ } else {
+ array set info [$xmpp(jlib) roster getpresence $node@$domain -resource $resource]
+ }
+ if {[info exist info(-show)]} {set show $info(-show)} else {set show available}
+ if {$info(-type) eq "unavailable"} {set show unavailable}
+ switch -exact -- $show {
+ available { set image ::img::presence::available }
+ unavailable { set image ::img::presence::unavailable }
+ chat { set image ::img::presence::chat }
+ away { set image ::img::presence::away }
+ xa { set image ::img::presence::xa }
+ dnd { set image ::img::presence::dnd }
+ default {
+ return -code error "unknown presence type \"$show\""
+ }
+ }
+ return $image
}
proc XmppChatstate {Chat chatstate} {
if {$name eq $target} {
# check for detached window
if {[lsearch -exact [$session(app).nb tabs] $wid] == -1} {
- if {[wm state $wid] eq "withdrawn"} { wm deiconify $wid }
+ if {[winfo toplevel $wid] eq $wid} {
+ if {[wm state $wid] eq "withdrawn"} { wm deiconify $wid }
+ } else {
+ XmppAddTab $Session $wid $target
+ }
} else {
if {[$session(app).nb tab $wid -state] eq "hidden"} {
$session(app).nb tab $wid -state normal
foreach {type line} $args break
Debug $Session $line $type
}
+ status {
+ Status $Session [lindex $args 0]
+ }
version { return "" }
default {
puts stderr "*** unknown xmpp callback \"$state\": $args"
[font actual TkTextFont] -slant italic
}
namespace eval ::img {}
+
+
+ proc ImageSetTransparency {img} {
+ set clr [$img get 0 0]
+ set width [image width $img]
+ set height [image height $img]
+ for {set r 0} {$r < $height} {incr r} {
+ for {set c 0} {$c < $width} {incr c} {
+ if {[$img get $c $r] eq $clr} {
+ $img transparency set $c $r 1
+ }
+ }
+ }
+ }
+
set imgdir [file join [file dirname [info script]] images]
image create photo ::img::msgnorm -file [file join $imgdir mail.gif]
image create photo ::img::msgchat -file [file join $imgdir chat.gif]
+ #ImageSetTransparency ::img::msgchat
}
proc messagewidget::messagewidget {w args} {
return $w
}
+# widget method dispatch
proc messagewidget::WidgetProc {self cmd args} {
upvar #0 [namespace current]::$self state
switch -exact -- $cmd {
}
}
+# Accessor for the summary tree widget.
proc messagewidget::Summary {self args} {
upvar #0 [namespace current]::$self state
if {[llength $args] == 0} {
return [uplevel 1 [list $state(mlist)] $args]
}
+# Accessor for the body display widget.
proc messagewidget::Body {self args} {
upvar #0 [namespace current]::$self state
if {[llength $args] == 0} {
return $r
}
-# -date : date/time as clock seconds
+# Add --
+# Add a new message item. Options are:
+# -from jid
+# -to jid
+# -subject string
+# -date date/time as clock seconds
+# -body data
#
proc messagewidget::Add {self args} {
upvar #0 [namespace current]::$self state
"[dict get $M -body]\n" body
}
+# -------------------------------------------------------------------------
+# Data store --
+#proc messagewidget::StoreItem
+#proc messagewidget::Store
+
# -------------------------------------------------------------------------
package provide messagewidget $messagewidget::version