         <open xmlns="http://jabber.org/protocol/ibb" sid="#{@sid}" block-size="4096"/>
       </iq>
     """)
-    callback = (result) =>
+    @session.sendIQ node.get(0), (result) =>
       if this.ok result
         @opened = true
-        @chunks.start => this.sendChunk()
-    @session.sendIQ node.get(0), callback
+        this.sendChunk()
 
   sendChunk: ->
     return if @closed
-    unless chunk = @chunks.chunk()
-      this.close()
-      return
+    @chunks.chunk (chunk) =>
+      unless 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
+      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
+
+      @session.sendIQ node.get(0), (result) =>
+        return unless this.ok result
+        pct = Math.ceil ++@sent / @chunks.total * 100
+        this.progress pct
+        this.sendChunk()
 
   close: ->
     return if @closed

    @to       = options.to
    @progress = options.progress
    @complete = options.complete
    @chunks   = new Chunks(@file)
    @opened   = false
    @closed   = false
    @sid      = @session.uniqueId()

  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
