File: compress.tcl

package info (click to toggle)
coccinella 0.96.20-9
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, buster
  • size: 13,184 kB
  • sloc: tcl: 124,744; xml: 206; makefile: 66; sh: 62
file content (231 lines) | stat: -rw-r--r-- 6,171 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#  compress.tcl --
#  
#      This file is part of jabberlib.
#      It implements stream compression as defined in XEP-0138: 
#      Stream Compression
#      
#  Copyright (c) 2006-2007  Mats Bengtsson
#  
# This file is distributed under BSD style license.
#  
#  NB: There are several zlib packages floating around the net with the same
#      name!. But we must have the one implemented for TIP 234, see
#      http://www.tcl.tk/cgi-bin/tct/tip/234.html.
#      This is currently of version 2.0.1 so we rely on this when doing
#      package require. Beware!
#      
# $Id: compress.tcl,v 1.9 2008-01-04 13:41:32 matben Exp $

package require jlib
package require -exact zlib 2.0.1

package provide jlib::compress 0.1

namespace eval jlib::compress {

    variable methods {zlib}
    
    # NB: There are two namespaces:
    #     'http://jabber.org/features/compress' 
    #     'http://jabber.org/protocol/compress' 
    variable xmlns
    array set xmlns {
	features/compress    "http://jabber.org/features/compress"
	protocol/compress    "http://jabber.org/protocol/compress"
    }
    jlib::register_instance [namespace code instance]
}

proc jlib::compress::instance {jlibname} {
    $jlibname register_reset [namespace code reset]
}

proc jlib::compress::start {jlibname cmd} {
    
    variable xmlns
    variable methods
    
    # puts "jlib::compress::start"
    
    # Instance specific namespace.
    namespace eval ${jlibname}::compress {
	variable state
    }
    upvar ${jlibname}::compress::state state
    
    set state(cmd) $cmd
    set state(-method) [lindex $methods 0]
    
    # Set up the streams for zlib.
    set state(compress)   [zlib stream compress]
    set state(decompress) [zlib stream decompress]

    # Set up callback for the xmlns that is of interest to us.
    $jlibname element_register $xmlns(protocol/compress) [namespace code parse]

    if {[$jlibname have_feature]} {
	compress $jlibname
    } else {
	$jlibname trace_stream_features [namespace code features_write]
    }
}

proc jlib::compress::features_write {jlibname} {
    
     # puts "jlib::compress::features_write"
    
     $jlibname trace_stream_features {}
     compress $jlibname
}

# jlib::compress::compress --
# 
#       Initiating Entity Requests Stream Compression.

proc jlib::compress::compress {jlibname} {
    
    variable methods
    variable xmlns
    upvar ${jlibname}::compress::state state
    
    # puts "jlib::compress::compress"
       
    # Note: If the initiating entity did not understand any of the advertised 
    # compression methods, it SHOULD ignore the compression option and 
    # proceed as if no compression methods were advertised. 

    set have_method [$jlibname have_feature compression $state(-method)]
    if {!$have_method} {
	finish $jlibname
	return
    }
    
    # @@@ MUST match methods!!!
    # A compliant implementation MUST implement the ZLIB compression method...
    
    set methodE [wrapper::createtag method -chdata $state(-method)]

    set xmllist [wrapper::createtag compress  \
      -attrlist [list xmlns $xmlns(protocol/compress)] -subtags [list $methodE]]
    $jlibname send $xmllist

    # Wait for 'compressed' or 'failure' element.
}

proc jlib::compress::parse {jlibname xmldata} {
    
    # puts "jlib::compress::parse"
    
    set tag [wrapper::gettag $xmldata]
    
    switch -- $tag {
	compressed {
	    compressed $jlibname $xmldata
	}
	failure {
	    failure $jlibname $xmldata
	}
	default {
	    finish $jlibname compress-protocol-error
	}
    }
    return
}

proc jlib::compress::compressed {jlibname xmldata} {
    
    # puts "jlib::compress::compressed"
    
    # Example 5. Receiving Entity Acknowledges Stream Compression 
    #     <compressed xmlns='http://jabber.org/protocol/compress'/> 
    # Both entities MUST now consider the previous stream to be null and void, 
    # just as with TLS negotiation and SASL negotiation 
    # Therefore the initiating entity MUST initiate a new stream to the 
    # receiving entity: 
 
    $jlibname wrapper_reset
    
    # We must clear out any server info we've received so far.
    $jlibname stream_reset
    
    $jlibname set_socket_filter [namespace code out] [namespace code in]
    
    if {[catch {
	$jlibname sendstream -version 1.0
    } err]} {
	finish $jlibname network-failure $err
	return
    }
    finish $jlibname
}

# jlib::compress::out, in --
# 
#       Actual compression takes place here.
#       XEP says:
#       When using ZLIB for compression, the sending application SHOULD 
#       complete a partial flush of ZLIB when its current send is complete. 

proc jlib::compress::out {jlibname data} {
    upvar ${jlibname}::compress::state state

    $state(compress) put -flush $data
    return [$state(compress) get]
}

proc jlib::compress::in {jlibname cdata} {
    upvar ${jlibname}::compress::state state
    
    $state(decompress) put $cdata
    #$state(decompress) flush
    return [$state(decompress) get]
}

proc jlib::compress::failure {jlibname xmldata} {
    
    # puts "jlib::compress::failure"
    
    set c [wrapper::getchildren $xmldata]
    if {[llength $c]} {
	set errcode [wrapper::gettag [lindex $c 0]]
    } else {
	set errcode unknown-failure
    }
    finish $jlibname $errcode
}

proc jlib::compress::finish {jlibname {errcode ""} {errmsg ""}} {
    
    upvar ${jlibname}::compress::state state
    variable xmlns
    
    # puts "jlib::compress:finish errcode=$errcode, errmsg=$errmsg"

    # NB: We must keep our state array for the lifetime of the stream.
    $jlibname trace_stream_features {}
    $jlibname element_deregister $xmlns(protocol/compress) [namespace code parse]
    
    if {$errcode ne ""} {
	uplevel #0 $state(cmd) $jlibname [list $errcode $errmsg]
    } else {
	uplevel #0 $state(cmd) $jlibname
    }
}

proc jlib::compress::reset {jlibname} {
    
    upvar ${jlibname}::compress::state state

    # puts "jlib::compress::reset"
    
    if {[info exists state(compress)]} {
	$state(compress) close
	unset state(compress)
    }
    if {[info exists state(decompress)]} {
	$state(decompress) close
	unset state(decompress)
    }
    unset -nocomplain state
}