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 140 140: def initialize(stream) 141: @stream = stream 142: @my_jid = nil 143: @allow_bytestreams = true 144: @allow_ibb = true 145: 146: @incoming_cbs = CallbackList.new 147: 148: @stream.add_iq_callback(150, self) { |iq| 149: if iq.type == :set 150: file = iq.first_element('si/file') 151: field = nil 152: iq.each_element('si/feature/x') { |e| field = e.field('stream-method') } 153: 154: if file and field 155: @incoming_cbs.process(iq, file) 156: true 157: else 158: false 159: end 160: else 161: false 162: end 163: } 164: 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 187 187: def accept(iq, offset=nil, length=nil) 188: oldsi = iq.first_element('si') 189: 190: answer = iq.answer(false) 191: answer.type = :result 192: 193: si = answer.add(Bytestreams::IqSi.new) 194: if (offset or length) and oldsi.file.range 195: si.add(Bytestreams::IqSiFile.new) 196: si.file.add(Bytestreams::IqSiFileRange.new(offset, length)) 197: end 198: si.add(FeatureNegotiation::IqFeature.new.import(oldsi.feature)) 199: si.feature.x.type = :submit 200: stream_method = si.feature.x.field('stream-method') 201: 202: if stream_method.options.keys.include?(Bytestreams::IqQueryBytestreams::NS_BYTESTREAMS) and @allow_bytestreams 203: stream_method.values = [Bytestreams::IqQueryBytestreams::NS_BYTESTREAMS] 204: stream_method.options = [] 205: @stream.send(answer) 206: 207: Bytestreams::SOCKS5BytestreamsTarget.new(@stream, oldsi.id, iq.from, iq.to) 208: elsif stream_method.options.keys.include?(Bytestreams::IBB::NS_IBB) and @allow_ibb 209: stream_method.values = [Bytestreams::IBB::NS_IBB] 210: stream_method.options = [] 211: @stream.send(answer) 212: 213: Bytestreams::IBBTarget.new(@stream, oldsi.id, iq.from, iq.to) 214: else 215: eanswer = iq.answer(false) 216: eanswer.type = :error 217: eanswer.add(Error.new('bad-request')).type = :cancel 218: eanswer.error.add(REXML::Element.new('no-valid-streams')).add_namespace('http://jabber.org/protocol/si') 219: @stream.send(eanswer) 220: 221: nil 222: end 223: 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 173 173: def add_incoming_callback(priority = 0, ref = nil, &block) 174: @incoming_cbs.add(priority, ref, block) 175: 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 229 229: def decline(iq) 230: answer = iq.answer(false) 231: answer.type = :error 232: error = answer.add(Error.new('forbidden', 'Offer declined')) 233: error.type = :cancel 234: @stream.send(answer) 235: 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 |
from: | [String] or [nil] Optional jid for components |
result: | [Bytestreams::SOCKS5BytestreamsInitiator] or [Bytestreams::IBBInitiator] or [nil] |
# File lib/xmpp4r/bytestreams/helper/filetransfer.rb, line 251 251: def offer(jid, source, desc=nil, from=nil) 252: from = from || @my_jid || @stream.jid 253: session_id = Jabber::IdGenerator.instance.generate_id 254: 255: offered_methods = {} 256: if @allow_bytestreams 257: offered_methods[Bytestreams::IqQueryBytestreams::NS_BYTESTREAMS] = nil 258: end 259: if @allow_ibb 260: offered_methods[Bytestreams::IBB::NS_IBB] = nil 261: end 262: 263: iq = Iq::new(:set, jid) 264: iq.from = from 265: si = iq.add(Bytestreams::IqSi.new(session_id, Bytestreams::IqSi::PROFILE_FILETRANSFER, source.mime)) 266: 267: file = si.add(Bytestreams::IqSiFile.new(source.filename, source.size)) 268: file.hash = source.md5 269: file.date = source.date 270: file.description = desc if desc 271: file.add(Bytestreams::IqSiFileRange.new) if source.can_range? 272: 273: feature = si.add(REXML::Element.new('feature')) 274: feature.add_namespace 'http://jabber.org/protocol/feature-neg' 275: x = feature.add(Dataforms::XData.new(:form)) 276: stream_method_field = x.add(Dataforms::XDataField.new('stream-method', :list_single)) 277: stream_method_field.options = offered_methods 278: 279: begin 280: stream_method = nil 281: response = nil 282: @stream.send_with_id(iq) { |r| 283: response = r 284: si = response.first_element('si') 285: if response.type == :result and si and si.feature and si.feature.x 286: stream_method = si.feature.x.field('stream-method').values.first 287: 288: if si.file and si.file.range 289: if source.can_range? 290: source.seek(si.file.range.offset) if si.file.range.offset 291: source.length = si.file.range.length if si.file.range.length 292: else 293: source.read(si.file.range.offset) 294: end 295: end 296: end 297: true 298: } 299: rescue ErrorException => e 300: if e.error.code == 403 # Declined 301: return false 302: else 303: raise e 304: end 305: end 306: 307: if stream_method == Bytestreams::IqQueryBytestreams::NS_BYTESTREAMS and @allow_bytestreams 308: Bytestreams::SOCKS5BytestreamsInitiator.new(@stream, session_id, from, jid) 309: elsif stream_method == Bytestreams::IBB::NS_IBB and @allow_ibb 310: Bytestreams::IBBInitiator.new(@stream, session_id, from, jid) 311: else # Target responded with a stream_method we didn't offer 312: eanswer = response.answer 313: eanswer.type = :error 314: eanswer.add Error::new('bad-request') 315: @stream.send(eanswer) 316: nil 317: end 318: end