     """)
     $('file', node).attr 'name', @file.name
 
-    callback = (result) =>
+    @session.sendIQ node.get(0), (result) =>
       methods = $('si feature x field[var="stream-method"] value', result)
       ok = (true for m in methods when $(m).text() == 'http://jabber.org/protocol/ibb').length > 0
       this.open() if ok
-
-    @session.sendIQ node.get(0), callback
 
   open: ->
     node = $("""

        <open xmlns="http://jabber.org/protocol/ibb" sid="#{@sid}" block-size="4096"/>
      </iq>
    """)
    callback = (result) =>
      if this.ok result
        @opened = true
        @chunks.start => this.sendChunk()
    @session.sendIQ node.get(0), callback

  sendChunk: ->
    return if @closed
    unless chunk = @chunks.chunk()
      this.close()
      return

    node = $("""
      <iq id="#{@session.uniqueId()}" to="#{@to}" type="set">
        <data xmlns="http://jabber.org/protocol/ibb" sid="#{@sid}" seq="#{@seq++}">#{chunk}</data>
      </iq>
    """)
    @seq = 0 if @seq > 65535
    callback = (result) =>
      return unless this.ok result
      pct = Math.ceil ++@sent / @chunks.total * 100
      this.progress pct
      this.sendChunk()
    @session.sendIQ node.get(0), callback

  close: ->
    return if @closed

  ok: (result) -> $(result).attr('type') == 'result'

  class Chunks
    CHUNK_SIZE = 3 / 4 * 4096

    constructor: (@file) ->
      @total = Math.ceil @file.size / CHUNK_SIZE
      @slice = @file.slice || @file.webkitSlice || @file.mozSlice
      @pos   = 0

    chunk: (callback) ->
      start = @pos
      end   = @pos + CHUNK_SIZE
      @pos  = end
      if start > @file.size
        callback null
      else
        chunk = @slice.call @file, start, end
        reader = new FileReader()
        reader.onload = (event) ->
          callback btoa event.target.result
        reader.readAsBinaryString chunk
