| Class | Jabber::FileTransfer::Helper |
| In: |
lib/xmpp4r/bytestreams/helper/filetransfer.rb
|
| Parent: | Object |
The FileTransfer helper provides the ability to respond to incoming and to offer outgoing file-transfers.
| allow_bytestreams | [RW] | Set this to false if you don‘t want to use SOCKS5Bytestreams |
| allow_ibb | [RW] | Set this to false if you don‘t want to use IBB |
| my_jid | [RW] | Set this if you want to use this helper in a Component |
Create a new FileTransfer instance
# File lib/xmpp4r/bytestreams/helper/filetransfer.rb, line 136
136: def initialize(stream)
137: @stream = stream
138: @my_jid = nil
139: @allow_bytestreams = true
140: @allow_ibb = true
141:
142: @incoming_cbs = CallbackList.new
143:
144: @stream.add_iq_callback(150, self) { |iq|
145: if iq.type == :set
146: file = iq.first_element('si/file')
147: field = nil
148: iq.each_element('si/feature/x') { |e| field = e.field('stream-method') }
149:
150: if file and field
151: @incoming_cbs.process(iq, file)
152: true
153: else
154: false
155: end
156: else
157: false
158: end
159: }
160: end
Accept an incoming file-transfer, to be used in a block given to add_incoming_callback
offset and length will be ignored if there is no ‘si/file/range’ in iq.
| iq: | [Iq] of file-transfer we want to accept |
| offset: | [Fixnum] or [nil] |
| length: | [Fixnum] or [nil] |
| result: | [Bytestreams::SOCKS5BytestreamsTarget] or [Bytestreams::IBBTarget] or [nil] if no valid stream-method |
# File lib/xmpp4r/bytestreams/helper/filetransfer.rb, line 183
183: def accept(iq, offset=nil, length=nil)
184: oldsi = iq.first_element('si')
185:
186: answer = iq.answer(false)
187: answer.type = :result
188:
189: si = answer.add(Bytestreams::IqSi.new)
190: if (offset or length) and oldsi.file.range
191: si.add(Bytestreams::IqSiFile.new)
192: si.file.add(Bytestreams::IqSiFileRange.new(offset, length))
193: end
194: si.add(FeatureNegotiation::IqFeature.new.import(oldsi.feature))
195: si.feature.x.type = :submit
196: stream_method = si.feature.x.field('stream-method')
197:
198: if stream_method.options.keys.include?(Bytestreams::IqQueryBytestreams::NS_BYTESTREAMS) and @allow_bytestreams
199: stream_method.values = [Bytestreams::IqQueryBytestreams::NS_BYTESTREAMS]
200: stream_method.options = []
201: @stream.send(answer)
202:
203: Bytestreams::SOCKS5BytestreamsTarget.new(@stream, oldsi.id, iq.from, iq.to)
204: elsif stream_method.options.keys.include?(Bytestreams::IBB::NS_IBB) and @allow_ibb
205: stream_method.values = [Bytestreams::IBB::NS_IBB]
206: stream_method.options = []
207: @stream.send(answer)
208:
209: Bytestreams::IBBTarget.new(@stream, oldsi.id, iq.from, iq.to)
210: else
211: eanswer = iq.answer(false)
212: eanswer.type = :error
213: eanswer.add(Error.new('bad-request')).type = :cancel
214: eanswer.error.add(REXML::Element.new('no-valid-streams')).add_namespace('http://jabber.org/protocol/si')
215: @stream.send(eanswer)
216:
217: nil
218: end
219: end
Add a callback which will be invoked upon an incoming file-transfer
block takes two arguments:
You may then invoke accept or decline
# File lib/xmpp4r/bytestreams/helper/filetransfer.rb, line 169
169: def add_incoming_callback(priority = 0, ref = nil, &block)
170: @incoming_cbs.add(priority, ref, block)
171: end
Decline an incoming file-transfer, to be used in a block given to add_incoming_callback
| iq: | [Iq] of file-transfer we want to decline |
# File lib/xmpp4r/bytestreams/helper/filetransfer.rb, line 225
225: def decline(iq)
226: answer = iq.answer(false)
227: answer.type = :error
228: error = answer.add(Error.new('forbidden', 'Offer declined'))
229: error.type = :cancel
230: @stream.send(answer)
231: end
Offer a file to somebody
Will wait for a response from the peer
The result is a stream which you can configure, or nil if the peer responded with an invalid stream-method.
May raise an ErrorException
| jid: | [JID] to send the file to |
| source: | File-transfer source, implementing the FileSource interface |
| desc: | [String] or [nil] Optional file description |
| result: | [Bytestreams::SOCKS5BytestreamsInitiator] or [Bytestreams::IBBInitiator] or [nil] |
# File lib/xmpp4r/bytestreams/helper/filetransfer.rb, line 246
246: def offer(jid, source, desc=nil)
247: session_id = Jabber::IdGenerator.instance.generate_id
248:
249: offered_methods = {}
250: if @allow_bytestreams
251: offered_methods[Bytestreams::IqQueryBytestreams::NS_BYTESTREAMS] = nil
252: end
253: if @allow_ibb
254: offered_methods[Bytestreams::IBB::NS_IBB] = nil
255: end
256:
257: iq = Iq::new(:set, jid)
258: iq.from = @my_jid
259: si = iq.add(Bytestreams::IqSi.new(session_id, Bytestreams::IqSi::PROFILE_FILETRANSFER, source.mime))
260:
261: file = si.add(Bytestreams::IqSiFile.new(source.filename, source.size))
262: file.hash = source.md5
263: file.date = source.date
264: file.description = desc if desc
265: file.add(Bytestreams::IqSiFileRange.new) if source.can_range?
266:
267: feature = si.add(REXML::Element.new('feature'))
268: feature.add_namespace 'http://jabber.org/protocol/feature-neg'
269: x = feature.add(Dataforms::XData.new(:form))
270: stream_method_field = x.add(Dataforms::XDataField.new('stream-method', :list_single))
271: stream_method_field.options = offered_methods
272:
273: begin
274: stream_method = nil
275: response = nil
276: @stream.send_with_id(iq) { |r|
277: response = r
278: si = response.first_element('si')
279: if response.type == :result and si and si.feature and si.feature.x
280: stream_method = si.feature.x.field('stream-method').values.first
281:
282: if si.file and si.file.range
283: if source.can_range?
284: source.seek(si.file.range.offset) if si.file.range.offset
285: source.length = si.file.range.length if si.file.range.length
286: else
287: source.read(si.file.range.offset)
288: end
289: end
290: end
291: true
292: }
293: rescue ErrorException => e
294: if e.error.code == 403 # Declined
295: return false
296: else
297: raise e
298: end
299: end
300:
301: if stream_method == Bytestreams::IqQueryBytestreams::NS_BYTESTREAMS and @allow_bytestreams
302: Bytestreams::SOCKS5BytestreamsInitiator.new(@stream, session_id, @my_jid || @stream.jid, jid)
303: elsif stream_method == Bytestreams::IBB::NS_IBB and @allow_ibb
304: Bytestreams::IBBInitiator.new(@stream, session_id, @my_jid || @stream.jid, jid)
305: else # Target responded with a stream_method we didn't offer
306: eanswer = response.answer
307: eanswer.type = :error
308: eanswer.add Error::new('bad-request')
309: @stream.send(eanswer)
310: nil
311: end
312: end