http://i2p2.de%|%I2P%|% [Zarutian]: An start of an http://www.i2p2.de/samv2.html%|%SAMv2%|% library for Tcl ====== # I, Zarutian, hereby put this code into the International public domain. package require Tcl 8.5 package provide i2p/sam2 0.1 namespace eval i2p {} namespace eval i2p::sam2 { variable defaults { bridge {host localhost port none} style STREAM stream {limit none}} variable session_counter 0 variable sessions proc new_session {params} { variable session_counter set i session[incr session_counter] variable defaults if {![dict exists $params style]} { dict set params style [dict get $defaults style] } if {![dict exists $params bridge]} { dict set params bridge [dict get $defaults bridge] } if {![dict exists $params bridge host]} { dict set params bridge host [dict get $defaults bridge host] } if {![dict exists $params bridge port]} { dict set params bridge port [dict get $defaults bridge port] } if {![dict exists $params stream]} { dict set params stream [dict get $defaults stream] } if {![dict exists $params condition_callback} { error "an condition_callback must be provided" } if {![dict exists $params my_name]} { error "my_name must be provided" } variable sessions dict set sessions $i condition_callback [dict get $params condition_callback] dict set sessions $i my_name [dict get $params my_name] dict set sessions $i socket [set sock [socket -async [dict get $params bridge host] [dict get $params bridge port]]] fconfigure $sock -buffering none -translation binary -encoding binary -blocking no fileevent $sock readable [list i2p::sam2::raw_recive_stage1 $i] puts -nonewline $sock "HELLO VERSION MIN=2.0 MAX=2.0\n" flush $sock return $i } proc raw_recive_stage1 {session_id} { variable sessions set sock [dict get $sessions $session_id socket] if {[eof $sock]} { close $sock after 0 [list {*}[dict get $sessions $session_id condition_callback] bridge connection closed $session_id ] return } dict append sessions $session_id raw_buffer [set buffer [read $sock]] if {[string first $buffer "\n"] != -1} { if {![string equal [string range $buffer 0 12] "HELLO REPLY "]} { after 0 [list {*}[dict get $sessions $session_id conditional_callback] bridge connection noHelloReply $session_id] return } set line [split $buffer "\n"] set done 0 foreach pair [split $line " "] { lassign [split $pair "="] key value if {[string equal $key "RESULT"} { incr done; set RESULT $value } if {[string equal $key "VERSION"} { incr done; set VERSION $value } } if {$done != 2} { after 0 [list {*}[dict get $sessions $session_id conditional_callback] bridge connection missingHelloReplyParams $session_id] return } if {[string equal $RESULT "NOVERSION]} { after 0 [list {*}[dict get $sessions $session_id conditional_callback] bridge connection noversion $session_id] return } if {![string equal $RESULT "OK"]} { after 0 [list {*}[dict get $sessions $session_id conditional_callback] bridge connection resultNotOk $session_id] return } if {![string equal $VERSION "2.0"]} { after 0 [list {*}[dict get $sessions $session_id conditional_callback] bridge connection versionNot2.0 $session_id] return } #--- dict set sessions $session_id raw_buffer [string range [dict get $sessions $session_id raw_buffer] \ [expr {[string first $buffer "\n"] + 1} end] puts -nonewline $sock "SESSION CREATE STYLE=" puts -nonewline $sock [string toupper [dict get $sessions $session_id style]] puts -nonewline $sock " DESTINATION=" puts -nonewline $sock [dict get $sessions $session_id my_name] puts -nonewline $sock "\n" flush $sock fileevent $sock readable [list i2p::sam2::raw_recive_stage2 $session_id] } } proc raw_recive_stage2 {session_id} { variable sessions set sock [dict get $sessions $session_id socket] if {[eof $sock]} { close $sock after 0 [list {*}[dict get $sessions $session_id condition_callback] bridge connection closed $session_id ] return } dict append sessions $session_id raw_buffer [set buffer [read $sock]] if {[string first $buffer "\n"] != -1} { if {![string equal "SESSION STATUS " [string range $buffer 0 14]]} { after 0 [list {*}[dict get $sessions $session_id conditional_callback] bridge connection noSessionStatus $session_id] return } # not done } } } ======