Class: Jabber::FileTransfer::Helper

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.

### Methods

accept add_incoming_callback decline new offer

### Attributes

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

### Public Class methods

new(stream)

Create a new FileTransfer instance

[Source]

         # File lib/xmpp4r/bytestreams/helper/filetransfer.rb, line 139
    139:       def initialize(stream)
    140:         @stream = stream
    141:         @my_jid = nil
    142:         @allow_bytestreams = true
    143:         @allow_ibb = true
    144:
    145:         @incoming_cbs = CallbackList.new
    146:
    147:         @stream.add_iq_callback(150, self) { |iq|
    148:           if iq.type == :set
    149:             file = iq.first_element('si/file')
    150:             field = nil
    151:             iq.each_element('si/feature/x') { |e| field = e.field('stream-method') }
    152:
    153:             if file and field
    154:               @incoming_cbs.process(iq, file)
    155:               true
    156:             else
    157:               false
    158:             end
    159:           else
    160:             false
    161:           end
    162:         }
    163:       end

### Public Instance methods

accept(iq, offset=nil, length=nil)

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

[Source]

         # File lib/xmpp4r/bytestreams/helper/filetransfer.rb, line 186
    186:       def accept(iq, offset=nil, length=nil)
    187:         oldsi = iq.first_element('si')
    188:
    189:         answer = iq.answer(false)
    190:         answer.type = :result
    191:
    192:         si = answer.add(Bytestreams::IqSi.new)
    193:         if (offset or length) and oldsi.file.range
    194:           si.add(Bytestreams::IqSiFile.new)
    195:           si.file.add(Bytestreams::IqSiFileRange.new(offset, length))
    196:         end
    197:         si.add(FeatureNegotiation::IqFeature.new.import(oldsi.feature))
    198:         si.feature.x.type = :submit
    199:         stream_method = si.feature.x.field('stream-method')
    200:
    201:         if stream_method.options.keys.include?(Bytestreams::NS_BYTESTREAMS) and @allow_bytestreams
    202:           stream_method.values = [Bytestreams::NS_BYTESTREAMS]
    203:           stream_method.options = []
    204:           @stream.send(answer)
    205:
    206:           Bytestreams::SOCKS5BytestreamsTarget.new(@stream, oldsi.id, iq.from, iq.to)
    207:         elsif stream_method.options.keys.include?(Bytestreams::IBB::NS_IBB) and @allow_ibb
    208:           stream_method.values = [Bytestreams::IBB::NS_IBB]
    209:           stream_method.options = []
    210:           @stream.send(answer)
    211:
    212:           Bytestreams::IBBTarget.new(@stream, oldsi.id, iq.from, iq.to)
    213:         else
    214:           eanswer = iq.answer(false)
    215:           eanswer.type = :error
    216:           eanswer.add(ErrorResponse.new('bad-request')).type = :cancel
    217:           eanswer.error.add(REXML::Element.new('no-valid-streams')).add_namespace('http://jabber.org/protocol/si')
    218:           @stream.send(eanswer)
    219:
    220:           nil
    221:         end
    222:       end

add_incoming_callback(priority = 0, ref = nil, &block)

Add a callback which will be invoked upon an incoming file-transfer

block takes two arguments:

- Iq
- Bytestreams::IqSiFile in the Iq

You may then invoke accept or decline

[Source]

         # File lib/xmpp4r/bytestreams/helper/filetransfer.rb, line 172
    172:       def add_incoming_callback(priority = 0, ref = nil, &block)
    173:         @incoming_cbs.add(priority, ref, block)
    174:       end

decline(iq)

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

[Source]

         # File lib/xmpp4r/bytestreams/helper/filetransfer.rb, line 228
    228:       def decline(iq)
    229:         answer = iq.answer(false)
    230:         answer.type = :error
    231:         error = answer.add(ErrorResponse.new('forbidden', 'Offer declined'))
    232:         error.type = :cancel
    233:         @stream.send(answer)
    234:       end

offer(jid, source, desc=nil, from=nil)

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 ServerError

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]

[Source]

         # File lib/xmpp4r/bytestreams/helper/filetransfer.rb, line 250
    250:       def offer(jid, source, desc=nil, from=nil)
    251:         from = from || @my_jid || @stream.jid
    252:         session_id = Jabber::IdGenerator.instance.generate_id
    253:
    254:         offered_methods = {}
    255:         if @allow_bytestreams
    256:           offered_methods[Bytestreams::NS_BYTESTREAMS] = nil
    257:         end
    258:         if @allow_ibb
    259:           offered_methods[Bytestreams::IBB::NS_IBB] = nil
    260:         end
    261:
    262:         iq = Iq.new(:set, jid)
    263:         iq.from = from
    264:         si = iq.add(Bytestreams::IqSi.new(session_id, Bytestreams::PROFILE_FILETRANSFER, source.mime))
    265:
    266:         file = si.add(Bytestreams::IqSiFile.new(source.filename, source.size))
    267:         file.hash = source.md5
    268:         file.date = source.date
    269:         file.description = desc if desc
    270:         file.add(Bytestreams::IqSiFileRange.new) if source.can_range?
    271:
    272:         feature = si.add(REXML::Element.new('feature'))
    273:         feature.add_namespace 'http://jabber.org/protocol/feature-neg'
    274:         x = feature.add(Dataforms::XData.new(:form))
    275:         stream_method_field = x.add(Dataforms::XDataField.new('stream-method', :list_single))
    276:         stream_method_field.options = offered_methods
    277:
    278:         begin
    279:           stream_method = nil
    280:           response = nil
    281:           @stream.send_with_id(iq) do |r|
    282:             response = r
    283:             si = response.first_element('si')
    284:             if si and si.feature and si.feature.x
    285:               stream_method = si.feature.x.field('stream-method').values.first
    286:
    287:               if si.file and si.file.range
    288:                 if source.can_range?
    289:                   source.seek(si.file.range.offset) if si.file.range.offset
    290:                   source.length = si.file.range.length if si.file.range.length
    291:                 else
    292:                   source.read(si.file.range.offset)
    293:                 end
    294:               end
    295:             end
    296:           end
    297:         rescue ServerError => e
    298:           if e.error.code == 403  # Declined
    299:             return false
    300:           else
    301:             raise e
    302:           end
    303:         end
    304:
    305:         if stream_method == Bytestreams::NS_BYTESTREAMS and @allow_bytestreams
    306:           Bytestreams::SOCKS5BytestreamsInitiator.new(@stream, session_id, from, jid)
    307:         elsif stream_method == Bytestreams::IBB::NS_IBB and @allow_ibb
    308:           Bytestreams::IBBInitiator.new(@stream, session_id, from, jid)
    309:         else  # Target responded with a stream_method we didn't offer
    310:           eanswer = response.answer
    311:           eanswer.type = :error
    312:           eanswer.add ErrorResponse.new('bad-request')
    313:           @stream.send(eanswer)
    314:           nil
    315:         end
    316:       end

[Validate]