Move IBB code to new IBB module
This commit is contained in:
parent
7ec93f89a2
commit
fdfc9c90a1
|
@ -34,7 +34,6 @@ from gajim.common import helpers
|
||||||
from gajim.common import jingle_xtls
|
from gajim.common import jingle_xtls
|
||||||
from gajim.common.jingle import ConnectionJingle
|
from gajim.common.jingle import ConnectionJingle
|
||||||
from gajim.common.protocol.bytestream import ConnectionSocks5Bytestream
|
from gajim.common.protocol.bytestream import ConnectionSocks5Bytestream
|
||||||
from gajim.common.protocol.bytestream import ConnectionIBBytestream
|
|
||||||
from gajim.common.connection_handlers_events import StreamReceivedEvent
|
from gajim.common.connection_handlers_events import StreamReceivedEvent
|
||||||
from gajim.common.connection_handlers_events import PresenceReceivedEvent
|
from gajim.common.connection_handlers_events import PresenceReceivedEvent
|
||||||
from gajim.common.connection_handlers_events import StreamConflictReceivedEvent
|
from gajim.common.connection_handlers_events import StreamConflictReceivedEvent
|
||||||
|
@ -185,10 +184,9 @@ class ConnectionHandlersBase:
|
||||||
|
|
||||||
class ConnectionHandlers(ConnectionSocks5Bytestream,
|
class ConnectionHandlers(ConnectionSocks5Bytestream,
|
||||||
ConnectionHandlersBase,
|
ConnectionHandlersBase,
|
||||||
ConnectionJingle, ConnectionIBBytestream):
|
ConnectionJingle):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
ConnectionSocks5Bytestream.__init__(self)
|
ConnectionSocks5Bytestream.__init__(self)
|
||||||
ConnectionIBBytestream.__init__(self)
|
|
||||||
ConnectionJingle.__init__(self)
|
ConnectionJingle.__init__(self)
|
||||||
ConnectionHandlersBase.__init__(self)
|
ConnectionHandlersBase.__init__(self)
|
||||||
|
|
||||||
|
@ -223,10 +221,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream,
|
||||||
nbxmpp.NS_BYTESTREAM)
|
nbxmpp.NS_BYTESTREAM)
|
||||||
con.RegisterHandler('iq', self._bytestreamErrorCB, 'error',
|
con.RegisterHandler('iq', self._bytestreamErrorCB, 'error',
|
||||||
nbxmpp.NS_BYTESTREAM)
|
nbxmpp.NS_BYTESTREAM)
|
||||||
con.RegisterHandlerOnce('iq', self.IBBAllIqHandler)
|
|
||||||
con.RegisterHandler('iq', self.IBBIqHandler, ns=nbxmpp.NS_IBB)
|
|
||||||
con.RegisterHandler('message', self.IBBMessageHandler, ns=nbxmpp.NS_IBB)
|
|
||||||
|
|
||||||
con.RegisterHandler('iq', self._JingleCB, 'result')
|
con.RegisterHandler('iq', self._JingleCB, 'result')
|
||||||
con.RegisterHandler('iq', self._JingleCB, 'error')
|
con.RegisterHandler('iq', self._JingleCB, 'error')
|
||||||
con.RegisterHandler('iq', self._JingleCB, 'set', nbxmpp.NS_JINGLE)
|
con.RegisterHandler('iq', self._JingleCB, 'set', nbxmpp.NS_JINGLE)
|
||||||
|
|
|
@ -146,8 +146,9 @@ class StateTransfering(JingleFileTransferStates):
|
||||||
def _start_ibb_transfer(self, con):
|
def _start_ibb_transfer(self, con):
|
||||||
self.jft.file_props.transport_sid = self.jft.transport.sid
|
self.jft.file_props.transport_sid = self.jft.transport.sid
|
||||||
fp = open(self.jft.file_props.file_name, 'rb')
|
fp = open(self.jft.file_props.file_name, 'rb')
|
||||||
con.OpenStream(self.jft.file_props.sid, self.jft.session.peerjid, fp,
|
con.get_module('IBB').send_open(self.jft.session.peerjid,
|
||||||
blocksize=4096)
|
self.jft.file_props.sid,
|
||||||
|
fp)
|
||||||
|
|
||||||
def _start_sock5_transfer(self):
|
def _start_sock5_transfer(self):
|
||||||
# It tells wether we start the transfer as client or server
|
# It tells wether we start the transfer as client or server
|
||||||
|
|
|
@ -74,6 +74,7 @@ MODULES = [
|
||||||
'vcard_avatars',
|
'vcard_avatars',
|
||||||
'vcard_temp',
|
'vcard_temp',
|
||||||
'announce',
|
'announce',
|
||||||
|
'ibb',
|
||||||
]
|
]
|
||||||
|
|
||||||
_imported_modules = [] # type: List[tuple]
|
_imported_modules = [] # type: List[tuple]
|
||||||
|
|
|
@ -0,0 +1,227 @@
|
||||||
|
# This file is part of Gajim.
|
||||||
|
#
|
||||||
|
# Gajim is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published
|
||||||
|
# by the Free Software Foundation; version 3 only.
|
||||||
|
#
|
||||||
|
# Gajim is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# XEP-0047: In-Band Bytestreams
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
import nbxmpp
|
||||||
|
from nbxmpp.protocol import NodeProcessed
|
||||||
|
from nbxmpp.structs import StanzaHandler
|
||||||
|
from nbxmpp.util import is_error_result
|
||||||
|
|
||||||
|
from gajim.common import app
|
||||||
|
from gajim.common.modules.base import BaseModule
|
||||||
|
from gajim.common.file_props import FilesProp
|
||||||
|
|
||||||
|
|
||||||
|
class IBB(BaseModule):
|
||||||
|
|
||||||
|
_nbxmpp_extends = 'IBB'
|
||||||
|
_nbxmpp_methods = [
|
||||||
|
'send_open',
|
||||||
|
'send_close',
|
||||||
|
'send_data',
|
||||||
|
'send_reply',
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, con):
|
||||||
|
BaseModule.__init__(self, con)
|
||||||
|
|
||||||
|
self.handlers = [
|
||||||
|
StanzaHandler(name='iq',
|
||||||
|
callback=self._ibb_received,
|
||||||
|
ns=nbxmpp.NS_IBB),
|
||||||
|
]
|
||||||
|
|
||||||
|
def _ibb_received(self, _con, stanza, properties):
|
||||||
|
if not properties.is_ibb:
|
||||||
|
return
|
||||||
|
|
||||||
|
if properties.ibb.type == 'data':
|
||||||
|
self._log.info('Data received, sid: %s, seq: %s',
|
||||||
|
properties.ibb.sid, properties.ibb.seq)
|
||||||
|
file_props = FilesProp.getFilePropByTransportSid(self._account,
|
||||||
|
properties.ibb.sid)
|
||||||
|
if not file_props:
|
||||||
|
self.send_reply(stanza, nbxmpp.ERR_ITEM_NOT_FOUND)
|
||||||
|
raise NodeProcessed
|
||||||
|
|
||||||
|
if file_props.connected:
|
||||||
|
self._on_data_received(stanza, file_props, properties)
|
||||||
|
self.send_reply(stanza)
|
||||||
|
|
||||||
|
elif properties.ibb.type == 'open':
|
||||||
|
self._log.info('Open received, sid: %s, blocksize: %s',
|
||||||
|
properties.ibb.sid, properties.ibb.block_size)
|
||||||
|
|
||||||
|
file_props = FilesProp.getFilePropByTransportSid(self._account,
|
||||||
|
properties.ibb.sid)
|
||||||
|
if not file_props:
|
||||||
|
self.send_reply(stanza, nbxmpp.ERR_ITEM_NOT_FOUND)
|
||||||
|
raise NodeProcessed
|
||||||
|
|
||||||
|
file_props.block_size = properties.ibb.block_size
|
||||||
|
file_props.direction = '<'
|
||||||
|
file_props.seq = 0
|
||||||
|
file_props.received_len = 0
|
||||||
|
file_props.last_time = time.time()
|
||||||
|
file_props.error = 0
|
||||||
|
file_props.paused = False
|
||||||
|
file_props.connected = True
|
||||||
|
file_props.completed = False
|
||||||
|
file_props.disconnect_cb = None
|
||||||
|
file_props.continue_cb = None
|
||||||
|
file_props.syn_id = stanza.getID()
|
||||||
|
file_props.fp = open(file_props.file_name, 'wb')
|
||||||
|
self.send_reply(stanza)
|
||||||
|
|
||||||
|
elif properties.ibb.type == 'close':
|
||||||
|
self._log.info('Close received, sid: %s', properties.ibb.sid)
|
||||||
|
file_props = FilesProp.getFilePropByTransportSid(self._account,
|
||||||
|
properties.ibb.sid)
|
||||||
|
if not file_props:
|
||||||
|
self.send_reply(stanza, nbxmpp.ERR_ITEM_NOT_FOUND)
|
||||||
|
raise NodeProcessed
|
||||||
|
|
||||||
|
self.send_reply(stanza)
|
||||||
|
file_props.fp.close()
|
||||||
|
file_props.completed = file_props.received_len >= file_props.size
|
||||||
|
if not file_props.completed:
|
||||||
|
file_props.error = -1
|
||||||
|
app.socks5queue.complete_transfer_cb(self._account, file_props)
|
||||||
|
|
||||||
|
raise NodeProcessed
|
||||||
|
|
||||||
|
def _on_data_received(self, stanza, file_props, properties):
|
||||||
|
ibb = properties.ibb
|
||||||
|
if ibb.seq != file_props.seq:
|
||||||
|
self.send_reply(stanza, nbxmpp.ERR_UNEXPECTED_REQUEST)
|
||||||
|
self.send_close(file_props)
|
||||||
|
raise NodeProcessed
|
||||||
|
|
||||||
|
self._log.debug('Data received: sid: %s, %s+%s bytes',
|
||||||
|
ibb.sid, file_props.fp.tell(), len(ibb.data))
|
||||||
|
|
||||||
|
file_props.seq += 1
|
||||||
|
file_props.started = True
|
||||||
|
file_props.fp.write(ibb.data)
|
||||||
|
current_time = time.time()
|
||||||
|
file_props.elapsed_time += current_time - file_props.last_time
|
||||||
|
file_props.last_time = current_time
|
||||||
|
file_props.received_len += len(ibb.data)
|
||||||
|
app.socks5queue.progress_transfer_cb(self._account, file_props)
|
||||||
|
if file_props.received_len >= file_props.size:
|
||||||
|
file_props.completed = True
|
||||||
|
|
||||||
|
def send_open(self, to, sid, fp):
|
||||||
|
self._log.info('Send open to %s, sid: %s', to, sid)
|
||||||
|
file_props = FilesProp.getFilePropBySid(sid)
|
||||||
|
file_props.direction = '>'
|
||||||
|
file_props.block_size = 4096
|
||||||
|
file_props.fp = fp
|
||||||
|
file_props.seq = -1
|
||||||
|
file_props.error = 0
|
||||||
|
file_props.paused = False
|
||||||
|
file_props.received_len = 0
|
||||||
|
file_props.last_time = time.time()
|
||||||
|
file_props.connected = True
|
||||||
|
file_props.completed = False
|
||||||
|
file_props.disconnect_cb = None
|
||||||
|
file_props.continue_cb = None
|
||||||
|
self._nbxmpp('IBB').send_open(to,
|
||||||
|
file_props.transport_sid,
|
||||||
|
4096,
|
||||||
|
callback=self._on_open_result,
|
||||||
|
user_data=file_props)
|
||||||
|
return file_props
|
||||||
|
|
||||||
|
def _on_open_result(self, result, file_props):
|
||||||
|
if is_error_result(result):
|
||||||
|
app.socks5queue.error_cb('Error', str(result))
|
||||||
|
self._log.warning('Error: %s', result)
|
||||||
|
return
|
||||||
|
self.send_data(file_props)
|
||||||
|
|
||||||
|
def send_close(self, file_props):
|
||||||
|
file_props.connected = False
|
||||||
|
file_props.fp.close()
|
||||||
|
file_props.stopped = True
|
||||||
|
to = file_props.receiver
|
||||||
|
if file_props.direction == '<':
|
||||||
|
to = file_props.sender
|
||||||
|
|
||||||
|
self._log.info('Send close to %s, sid: %s',
|
||||||
|
to, file_props.transport_sid)
|
||||||
|
self._nbxmpp('IBB').send_close(to, file_props.transport_sid,
|
||||||
|
callback=self._on_close_result)
|
||||||
|
|
||||||
|
if file_props.completed:
|
||||||
|
app.socks5queue.complete_transfer_cb(self._account, file_props)
|
||||||
|
else:
|
||||||
|
if file_props.type_ == 's':
|
||||||
|
peerjid = file_props.receiver
|
||||||
|
else:
|
||||||
|
peerjid = file_props.sender
|
||||||
|
session = self._con.get_jingle_session(
|
||||||
|
peerjid, file_props.sid, 'file')
|
||||||
|
# According to the xep, the initiator also cancels
|
||||||
|
# the jingle session if there are no more files to send using IBB
|
||||||
|
if session.weinitiate:
|
||||||
|
session.cancel_session()
|
||||||
|
|
||||||
|
def _on_close_result(self, result):
|
||||||
|
if is_error_result(result):
|
||||||
|
app.socks5queue.error_cb('Error', str(result))
|
||||||
|
self._log.warning('Error: %s', result)
|
||||||
|
return
|
||||||
|
|
||||||
|
def send_data(self, file_props):
|
||||||
|
if file_props.completed:
|
||||||
|
self.send_close(file_props)
|
||||||
|
return
|
||||||
|
|
||||||
|
chunk = file_props.fp.read(file_props.block_size)
|
||||||
|
if chunk:
|
||||||
|
file_props.seq += 1
|
||||||
|
file_props.started = True
|
||||||
|
if file_props.seq == 65536:
|
||||||
|
file_props.seq = 0
|
||||||
|
|
||||||
|
self._log.info('Send data to %s, sid: %s',
|
||||||
|
file_props.receiver, file_props.transport_sid)
|
||||||
|
self._nbxmpp('IBB').send_data(file_props.receiver,
|
||||||
|
file_props.transport_sid,
|
||||||
|
file_props.seq,
|
||||||
|
chunk,
|
||||||
|
callback=self._on_data_result,
|
||||||
|
user_data=file_props)
|
||||||
|
current_time = time.time()
|
||||||
|
file_props.elapsed_time += current_time - file_props.last_time
|
||||||
|
file_props.last_time = current_time
|
||||||
|
file_props.received_len += len(chunk)
|
||||||
|
if file_props.size == file_props.received_len:
|
||||||
|
file_props.completed = True
|
||||||
|
app.socks5queue.progress_transfer_cb(self._account, file_props)
|
||||||
|
|
||||||
|
def _on_data_result(self, result, file_props):
|
||||||
|
if is_error_result(result):
|
||||||
|
app.socks5queue.error_cb('Error', str(result))
|
||||||
|
self._log.warning('Error: %s', result)
|
||||||
|
return
|
||||||
|
self.send_data(file_props)
|
||||||
|
|
||||||
|
|
||||||
|
def get_instance(*args, **kwargs):
|
||||||
|
return IBB(*args, **kwargs), 'IBB'
|
|
@ -25,8 +25,6 @@
|
||||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import socket
|
import socket
|
||||||
import base64
|
|
||||||
import time
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import nbxmpp
|
import nbxmpp
|
||||||
|
@ -633,259 +631,6 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
|
||||||
raise nbxmpp.NodeProcessed
|
raise nbxmpp.NodeProcessed
|
||||||
|
|
||||||
|
|
||||||
class ConnectionIBBytestream(ConnectionBytestream):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
ConnectionBytestream.__init__(self)
|
|
||||||
self._streams = {}
|
|
||||||
|
|
||||||
def IBBIqHandler(self, conn, stanza):
|
|
||||||
"""
|
|
||||||
Handles streams state change. Used internally.
|
|
||||||
"""
|
|
||||||
typ = stanza.getType()
|
|
||||||
log.debug('IBBIqHandler called typ->%s', typ)
|
|
||||||
if typ == 'set' and stanza.getTag('open'):
|
|
||||||
self.StreamOpenHandler(conn, stanza)
|
|
||||||
elif typ == 'set' and stanza.getTag('close'):
|
|
||||||
self.StreamCloseHandler(conn, stanza)
|
|
||||||
elif typ == 'set' and stanza.getTag('data'):
|
|
||||||
sid = stanza.getTagAttr('data', 'sid')
|
|
||||||
file_props = FilesProp.getFilePropByTransportSid(self.name, sid)
|
|
||||||
if not file_props:
|
|
||||||
conn.send(nbxmpp.Error(stanza, nbxmpp.ERR_ITEM_NOT_FOUND))
|
|
||||||
elif file_props.connected and self.IBBMessageHandler(conn,
|
|
||||||
stanza):
|
|
||||||
reply = stanza.buildReply('result')
|
|
||||||
reply.delChild('data')
|
|
||||||
conn.send(reply)
|
|
||||||
elif not file_props.connected:
|
|
||||||
log.debug('Received IQ for closed filetransfer, IQ dropped')
|
|
||||||
elif typ == 'error':
|
|
||||||
app.socks5queue.error_cb()
|
|
||||||
else:
|
|
||||||
conn.send(nbxmpp.Error(stanza, nbxmpp.ERR_BAD_REQUEST))
|
|
||||||
raise nbxmpp.NodeProcessed
|
|
||||||
|
|
||||||
def StreamOpenHandler(self, conn, stanza):
|
|
||||||
"""
|
|
||||||
Handles opening of new incoming stream. Used internally.
|
|
||||||
"""
|
|
||||||
err = None
|
|
||||||
sid = stanza.getTagAttr('open', 'sid')
|
|
||||||
blocksize = stanza.getTagAttr('open', 'block-size')
|
|
||||||
log.debug('StreamOpenHandler called sid->%s blocksize->%s',
|
|
||||||
sid, blocksize)
|
|
||||||
file_props = FilesProp.getFilePropByTransportSid(self.name, sid)
|
|
||||||
try:
|
|
||||||
blocksize = int(blocksize)
|
|
||||||
except Exception:
|
|
||||||
err = nbxmpp.ERR_BAD_REQUEST
|
|
||||||
if not sid or not blocksize:
|
|
||||||
err = nbxmpp.ERR_BAD_REQUEST
|
|
||||||
elif not file_props:
|
|
||||||
err = nbxmpp.ERR_UNEXPECTED_REQUEST
|
|
||||||
if err:
|
|
||||||
rep = nbxmpp.Error(stanza, err)
|
|
||||||
else:
|
|
||||||
log.debug("Opening stream: id %s, block-size %s",
|
|
||||||
sid, blocksize)
|
|
||||||
rep = nbxmpp.Protocol('iq', stanza.getFrom(), 'result',
|
|
||||||
stanza.getTo(), {'id': stanza.getID()})
|
|
||||||
file_props.block_size = blocksize
|
|
||||||
file_props.direction = '<'
|
|
||||||
file_props.seq = 0
|
|
||||||
file_props.received_len = 0
|
|
||||||
file_props.last_time = time.time()
|
|
||||||
file_props.error = 0
|
|
||||||
file_props.paused = False
|
|
||||||
file_props.connected = True
|
|
||||||
file_props.completed = False
|
|
||||||
file_props.disconnect_cb = None
|
|
||||||
file_props.continue_cb = None
|
|
||||||
file_props.syn_id = stanza.getID()
|
|
||||||
file_props.fp = open(file_props.file_name, 'wb')
|
|
||||||
conn.send(rep)
|
|
||||||
|
|
||||||
def CloseIBBStream(self, file_props):
|
|
||||||
file_props.connected = False
|
|
||||||
file_props.fp.close()
|
|
||||||
file_props.stopped = True
|
|
||||||
to = file_props.receiver
|
|
||||||
if file_props.direction == '<':
|
|
||||||
to = file_props.sender
|
|
||||||
self.connection.send(
|
|
||||||
nbxmpp.Protocol('iq', to, 'set',
|
|
||||||
payload=[nbxmpp.Node(nbxmpp.NS_IBB + ' close',
|
|
||||||
{'sid':file_props.transport_sid})]))
|
|
||||||
if file_props.completed:
|
|
||||||
app.socks5queue.complete_transfer_cb(self.name, file_props)
|
|
||||||
elif file_props.session_type == 'jingle':
|
|
||||||
peerjid = \
|
|
||||||
file_props.receiver if file_props.type_ == 's' else file_props.sender
|
|
||||||
session = self.get_jingle_session(peerjid, file_props.sid, 'file')
|
|
||||||
# According to the xep, the initiator also cancels the jingle session
|
|
||||||
# if there are no more files to send using IBB
|
|
||||||
if session.weinitiate:
|
|
||||||
session.cancel_session()
|
|
||||||
|
|
||||||
def OpenStream(self, sid, to, fp, blocksize=4096):
|
|
||||||
"""
|
|
||||||
Start new stream. You should provide stream id 'sid', the endpoint jid
|
|
||||||
'to', the file object containing info for send 'fp'. Also the desired
|
|
||||||
blocksize can be specified.
|
|
||||||
Take into account that recommended stanza size is 4k and IBB uses
|
|
||||||
base64 encoding that increases size of data by 1/3.
|
|
||||||
"""
|
|
||||||
file_props = FilesProp.getFilePropBySid(sid)
|
|
||||||
file_props.direction = '>'
|
|
||||||
file_props.block_size = blocksize
|
|
||||||
file_props.fp = fp
|
|
||||||
file_props.seq = 0
|
|
||||||
file_props.error = 0
|
|
||||||
file_props.paused = False
|
|
||||||
file_props.received_len = 0
|
|
||||||
file_props.last_time = time.time()
|
|
||||||
file_props.connected = True
|
|
||||||
file_props.completed = False
|
|
||||||
file_props.disconnect_cb = None
|
|
||||||
file_props.continue_cb = None
|
|
||||||
syn = nbxmpp.Protocol('iq', to, 'set', payload=[nbxmpp.Node(
|
|
||||||
nbxmpp.NS_IBB + ' open', {'sid': file_props.transport_sid,
|
|
||||||
'block-size': blocksize, 'stanza': 'iq'})])
|
|
||||||
self.connection.send(syn)
|
|
||||||
file_props.syn_id = syn.getID()
|
|
||||||
return file_props
|
|
||||||
|
|
||||||
def SendHandler(self, file_props):
|
|
||||||
"""
|
|
||||||
Send next portion of data if it is time to do it. Used internally.
|
|
||||||
"""
|
|
||||||
log.debug('SendHandler called')
|
|
||||||
if file_props.completed:
|
|
||||||
self.CloseIBBStream(file_props)
|
|
||||||
if file_props.paused:
|
|
||||||
return
|
|
||||||
if not file_props.connected:
|
|
||||||
#TODO: Reply with out of order error
|
|
||||||
return
|
|
||||||
chunk = file_props.fp.read(file_props.block_size)
|
|
||||||
if chunk:
|
|
||||||
datanode = nbxmpp.Node(nbxmpp.NS_IBB + ' data', {
|
|
||||||
'sid': file_props.transport_sid,
|
|
||||||
'seq': file_props.seq},
|
|
||||||
base64.b64encode(chunk).decode('ascii'))
|
|
||||||
file_props.seq += 1
|
|
||||||
file_props.started = True
|
|
||||||
if file_props.seq == 65536:
|
|
||||||
file_props.seq = 0
|
|
||||||
file_props.syn_id = self.connection.send(
|
|
||||||
nbxmpp.Protocol(name='iq', to=file_props.receiver,
|
|
||||||
typ='set', payload=[datanode]))
|
|
||||||
current_time = time.time()
|
|
||||||
file_props.elapsed_time += current_time - file_props.last_time
|
|
||||||
file_props.last_time = current_time
|
|
||||||
file_props.received_len += len(chunk)
|
|
||||||
if file_props.size == file_props.received_len:
|
|
||||||
file_props.completed = True
|
|
||||||
app.socks5queue.progress_transfer_cb(self.name,
|
|
||||||
file_props)
|
|
||||||
else:
|
|
||||||
log.debug('Nothing to read, but file not completed')
|
|
||||||
|
|
||||||
def IBBMessageHandler(self, conn, stanza):
|
|
||||||
"""
|
|
||||||
Receive next portion of incoming datastream and store it write
|
|
||||||
it to temporary file. Used internally.
|
|
||||||
"""
|
|
||||||
sid = stanza.getTagAttr('data', 'sid')
|
|
||||||
seq = stanza.getTagAttr('data', 'seq')
|
|
||||||
data = stanza.getTagData('data')
|
|
||||||
log.debug('ReceiveHandler called sid->%s seq->%s', sid, seq)
|
|
||||||
try:
|
|
||||||
seq = int(seq)
|
|
||||||
data = base64.b64decode(data.encode('utf-8'))
|
|
||||||
except Exception:
|
|
||||||
seq = ''
|
|
||||||
data = b''
|
|
||||||
err = None
|
|
||||||
file_props = FilesProp.getFilePropByTransportSid(self.name, sid)
|
|
||||||
if file_props is None:
|
|
||||||
err = nbxmpp.ERR_ITEM_NOT_FOUND
|
|
||||||
else:
|
|
||||||
if not data:
|
|
||||||
err = nbxmpp.ERR_BAD_REQUEST
|
|
||||||
elif seq != file_props.seq:
|
|
||||||
err = nbxmpp.ERR_UNEXPECTED_REQUEST
|
|
||||||
else:
|
|
||||||
log.debug('Successfully received sid->%s %s+%s bytes',
|
|
||||||
sid, file_props.fp.tell(), len(data))
|
|
||||||
file_props.seq += 1
|
|
||||||
file_props.started = True
|
|
||||||
file_props.fp.write(data)
|
|
||||||
current_time = time.time()
|
|
||||||
file_props.elapsed_time += current_time - file_props.last_time
|
|
||||||
file_props.last_time = current_time
|
|
||||||
file_props.received_len += len(data)
|
|
||||||
app.socks5queue.progress_transfer_cb(self.name, file_props)
|
|
||||||
if file_props.received_len >= file_props.size:
|
|
||||||
file_props.completed = True
|
|
||||||
if err:
|
|
||||||
log.debug('Error on receive: %s', err)
|
|
||||||
conn.send(nbxmpp.Error(nbxmpp.Iq(to=stanza.getFrom(),
|
|
||||||
frm=stanza.getTo(),
|
|
||||||
payload=[nbxmpp.Node(nbxmpp.NS_IBB + ' close')]), err, reply=0))
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def StreamCloseHandler(self, conn, stanza):
|
|
||||||
"""
|
|
||||||
Handle stream closure due to all data transmitted.
|
|
||||||
Raise xmpppy event specifying successful data receive.
|
|
||||||
"""
|
|
||||||
sid = stanza.getTagAttr('close', 'sid')
|
|
||||||
log.debug('StreamCloseHandler called sid->%s', sid)
|
|
||||||
# look in sending files
|
|
||||||
file_props = FilesProp.getFilePropByTransportSid(self.name, sid)
|
|
||||||
if file_props:
|
|
||||||
reply = stanza.buildReply('result')
|
|
||||||
reply.delChild('close')
|
|
||||||
conn.send(reply)
|
|
||||||
# look in receiving files
|
|
||||||
file_props.fp.close()
|
|
||||||
file_props.completed = file_props.received_len >= file_props.size
|
|
||||||
if not file_props.completed:
|
|
||||||
file_props.error = -1
|
|
||||||
app.socks5queue.complete_transfer_cb(self.name, file_props)
|
|
||||||
else:
|
|
||||||
conn.send(nbxmpp.Error(stanza, nbxmpp.ERR_ITEM_NOT_FOUND))
|
|
||||||
|
|
||||||
|
|
||||||
def IBBAllIqHandler(self, conn, stanza):
|
|
||||||
"""
|
|
||||||
Handle remote side reply about if it agree or not to receive our
|
|
||||||
datastream.
|
|
||||||
Used internally. Raises xmpppy event specifying if the data transfer
|
|
||||||
is agreed upon.
|
|
||||||
"""
|
|
||||||
syn_id = stanza.getID()
|
|
||||||
log.debug('IBBAllIqHandler called syn_id->%s', syn_id)
|
|
||||||
for file_props in FilesProp.getAllFileProp():
|
|
||||||
if not file_props.direction or not file_props.connected:
|
|
||||||
# It's socks5 bytestream
|
|
||||||
# Or we closed the IBB stream
|
|
||||||
continue
|
|
||||||
if file_props.syn_id == syn_id:
|
|
||||||
if stanza.getType() == 'error':
|
|
||||||
if file_props.direction[0] == '<':
|
|
||||||
conn.Event('IBB', 'ERROR ON RECEIVE', file_props)
|
|
||||||
else:
|
|
||||||
conn.Event('IBB', 'ERROR ON SEND', file_props)
|
|
||||||
elif stanza.getType() == 'result':
|
|
||||||
self.SendHandler(file_props)
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
class ConnectionSocks5BytestreamZeroconf(ConnectionSocks5Bytestream):
|
class ConnectionSocks5BytestreamZeroconf(ConnectionSocks5Bytestream):
|
||||||
|
|
||||||
def _ft_get_from(self, iq_obj):
|
def _ft_get_from(self, iq_obj):
|
||||||
|
|
|
@ -882,7 +882,7 @@ class FileTransfersWindow:
|
||||||
con = app.connections[account]
|
con = app.connections[account]
|
||||||
# Check if we are in a IBB transfer
|
# Check if we are in a IBB transfer
|
||||||
if file_props.direction:
|
if file_props.direction:
|
||||||
con.CloseIBBStream(file_props)
|
con.get_module('IBB').send_close(file_props)
|
||||||
con.disconnect_transfer(file_props)
|
con.disconnect_transfer(file_props)
|
||||||
self.set_status(file_props, 'stop')
|
self.set_status(file_props, 'stop')
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue