Merge branch 'fixibb' into 'master'

Fix IBB

Closes #8196

See merge request !90
This commit is contained in:
Philipp Hörist 2017-04-29 18:49:17 +02:00
commit b94c827400
7 changed files with 88 additions and 90 deletions

View File

@ -380,7 +380,7 @@ class Config:
'http_auth': [opt_str, 'ask'], # yes, no, ask 'http_auth': [opt_str, 'ask'], # yes, no, ask
'dont_ack_subscription': [opt_bool, False, _('Jabberd2 workaround')], 'dont_ack_subscription': [opt_bool, False, _('Jabberd2 workaround')],
# proxy65 for FT # proxy65 for FT
'file_transfer_proxies': [opt_str, 'proxy.eu.jabber.org, proxy.jabber.ru, proxy.jabbim.cz'], 'file_transfer_proxies': [opt_str, ''],
'use_ft_proxies': [opt_bool, False, _('If checked, Gajim will use your IP and proxies defined in file_transfer_proxies option for file transfer.'), True], 'use_ft_proxies': [opt_bool, False, _('If checked, Gajim will use your IP and proxies defined in file_transfer_proxies option for file transfer.'), True],
'test_ft_proxies_on_startup': [opt_bool, False, _('If True, Gajim will test file transfer proxies on startup to be sure it works. Openfire\'s proxies are known to fail this test even if they work.')], 'test_ft_proxies_on_startup': [opt_bool, False, _('If True, Gajim will test file transfer proxies on startup to be sure it works. Openfire\'s proxies are known to fail this test even if they work.')],
'msgwin-x-position': [opt_int, -1], # Default is to let the wm decide 'msgwin-x-position': [opt_int, -1], # Default is to let the wm decide

View File

@ -163,7 +163,7 @@ class FileStoppedEvent(FileRequestEvent):
type_ = 'file-stopped' type_ = 'file-stopped'
class FileHashErrorEvent(FileRequestEvent): class FileHashErrorEvent(FileRequestEvent):
type_ = 'file-hash-rror' type_ = 'file-hash-error'
class JingleIncomingEvent(Event): class JingleIncomingEvent(Event):
type_ = 'jingle-incoming' type_ = 'jingle-incoming'

View File

@ -146,7 +146,7 @@ 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, 'r') fp = open(self.jft.file_props.file_name, 'rb')
con.OpenStream(self.jft.file_props.sid, self.jft.session.peerjid, fp, con.OpenStream(self.jft.file_props.sid, self.jft.session.peerjid, fp,
blocksize=4096) blocksize=4096)

View File

@ -251,7 +251,7 @@ class ConnectionBytestream:
if field.getValue() == nbxmpp.NS_IBB: if field.getValue() == nbxmpp.NS_IBB:
sid = file_props.sid sid = file_props.sid
file_props.transport_sid = sid file_props.transport_sid = sid
fp = open(file_props.file_name, 'r') fp = open(file_props.file_name, 'rb')
self.OpenStream(sid, file_props.receiver, fp) self.OpenStream(sid, file_props.receiver, fp)
raise nbxmpp.NodeProcessed raise nbxmpp.NodeProcessed
@ -759,7 +759,6 @@ class ConnectionIBBytestream(ConnectionBytestream):
def __init__(self): def __init__(self):
ConnectionBytestream.__init__(self) ConnectionBytestream.__init__(self)
self._streams = {} self._streams = {}
self.last_sent_ibb_id = None
def IBBIqHandler(self, conn, stanza): def IBBIqHandler(self, conn, stanza):
""" """
@ -767,12 +766,22 @@ class ConnectionIBBytestream(ConnectionBytestream):
""" """
typ = stanza.getType() typ = stanza.getType()
log.debug('IBBIqHandler called typ->%s' % typ) log.debug('IBBIqHandler called typ->%s' % typ)
if typ == 'set' and stanza.getTag('open', namespace=nbxmpp.NS_IBB): if typ == 'set' and stanza.getTag('open'):
self.StreamOpenHandler(conn, stanza) self.StreamOpenHandler(conn, stanza)
elif typ == 'set' and stanza.getTag('close', namespace=nbxmpp.NS_IBB): elif typ == 'set' and stanza.getTag('close'):
self.StreamCloseHandler(conn, stanza) self.StreamCloseHandler(conn, stanza)
elif typ == 'result': elif typ == 'set' and stanza.getTag('data'):
self.SendHandler() 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': elif typ == 'error':
gajim.socks5queue.error_cb() gajim.socks5queue.error_cb()
else: else:
@ -815,18 +824,23 @@ class ConnectionIBBytestream(ConnectionBytestream):
file_props.disconnect_cb = None file_props.disconnect_cb = None
file_props.continue_cb = None file_props.continue_cb = None
file_props.syn_id = stanza.getID() file_props.syn_id = stanza.getID()
file_props.fp = open(file_props.file_name, 'w') file_props.fp = open(file_props.file_name, 'wb')
conn.send(rep) conn.send(rep)
def CloseIBBStream(self, file_props): def CloseIBBStream(self, file_props):
file_props.connected = False file_props.connected = False
file_props.fp.close() file_props.fp.close()
file_props.stopped = True file_props.stopped = True
self.connection.send(nbxmpp.Protocol('iq', to = file_props.receiver
file_props.direction[1:], 'set', if file_props.direction == '<':
to = file_props.sender
self.connection.send(
nbxmpp.Protocol('iq', to, 'set',
payload=[nbxmpp.Node(nbxmpp.NS_IBB + ' close', payload=[nbxmpp.Node(nbxmpp.NS_IBB + ' close',
{'sid':file_props.sid})])) {'sid':file_props.transport_sid})]))
if file_props.session_type == 'jingle': if file_props.completed:
gajim.socks5queue.complete_transfer_cb(self.name, file_props)
elif file_props.session_type == 'jingle':
peerjid = \ peerjid = \
file_props.receiver if file_props.type_ == 's' else file_props.sender file_props.receiver if file_props.type_ == 's' else file_props.sender
session = self.get_jingle_session(peerjid, file_props.sid, 'file') session = self.get_jingle_session(peerjid, file_props.sid, 'file')
@ -844,7 +858,7 @@ class ConnectionIBBytestream(ConnectionBytestream):
base64 encoding that increases size of data by 1/3. base64 encoding that increases size of data by 1/3.
""" """
file_props = FilesProp.getFilePropBySid(sid) file_props = FilesProp.getFilePropBySid(sid)
file_props.direction = '|>' + to file_props.direction = '>'
file_props.block_size = blocksize file_props.block_size = blocksize
file_props.fp = fp file_props.fp = fp
file_props.seq = 0 file_props.seq = 0
@ -863,53 +877,41 @@ class ConnectionIBBytestream(ConnectionBytestream):
file_props.syn_id = syn.getID() file_props.syn_id = syn.getID()
return file_props return file_props
def SendHandler(self): def SendHandler(self, file_props):
""" """
Send next portion of data if it is time to do it. Used internally. Send next portion of data if it is time to do it. Used internally.
""" """
log.debug('SendHandler called') log.debug('SendHandler called')
for file_props in FilesProp.getAllFileProp(): if file_props.completed:
if not file_props.direction: self.CloseIBBStream(file_props)
# it's socks5 bytestream if file_props.paused:
continue return
sid = file_props.sid if not file_props.connected:
if file_props.direction[:2] == '|>': #TODO: Reply with out of order error
# We waitthat other part accept stream return
continue chunk = file_props.fp.read(file_props.block_size)
if file_props.direction[0] == '>': if chunk:
if file_props.paused: datanode = nbxmpp.Node(nbxmpp.NS_IBB + ' data', {
continue 'sid': file_props.transport_sid,
if not file_props.connected: 'seq': file_props.seq},
#TODO: Reply with out of order error base64.b64encode(chunk).decode('ascii'))
continue file_props.seq += 1
chunk = file_props.fp.read(file_props.block_size) file_props.started = True
if chunk: if file_props.seq == 65536:
datanode = nbxmpp.Node(nbxmpp.NS_IBB + ' data', { file_props.seq = 0
'sid': file_props.transport_sid, file_props.syn_id = self.connection.send(
'seq': file_props.seq}, base64.b64encode(chunk.encode( nbxmpp.Protocol(name='iq', to=file_props.receiver,
'utf-8')).decode('utf-8')) typ='set', payload=[datanode]))
file_props.seq += 1 current_time = time.time()
file_props.started = True file_props.elapsed_time += current_time - file_props.last_time
if file_props.seq == 65536: file_props.last_time = current_time
file_props.seq = 0 file_props.received_len += len(chunk)
self.last_sent_ibb_id = self.connection.send( if file_props.size == file_props.received_len:
nbxmpp.Protocol(name='iq', to=file_props.direction[1:], file_props.completed = True
typ='set', payload=[datanode])) gajim.socks5queue.progress_transfer_cb(self.name,
current_time = time.time() file_props)
file_props.elapsed_time += current_time - file_props.last_time else:
file_props.last_time = current_time log.debug('Nothing to read, but file not completed')
file_props.received_len += len(chunk)
gajim.socks5queue.progress_transfer_cb(self.name,
file_props)
else:
# notify the other side about stream closing
# notify the local user about sucessfull send
# delete the local stream
self.connection.send(nbxmpp.Protocol('iq',
file_props.direction[1:], 'set',
payload=[nbxmpp.Node(nbxmpp.NS_IBB + ' close',
{'sid': file_props.transport_sid})]))
file_props.completed = True
def IBBMessageHandler(self, conn, stanza): def IBBMessageHandler(self, conn, stanza):
""" """
@ -978,6 +980,7 @@ class ConnectionIBBytestream(ConnectionBytestream):
else: else:
conn.send(nbxmpp.Error(stanza, nbxmpp.ERR_ITEM_NOT_FOUND)) conn.send(nbxmpp.Error(stanza, nbxmpp.ERR_ITEM_NOT_FOUND))
def IBBAllIqHandler(self, conn, stanza): def IBBAllIqHandler(self, conn, stanza):
""" """
Handle remote side reply about if it agree or not to receive our Handle remote side reply about if it agree or not to receive our
@ -999,25 +1002,9 @@ class ConnectionIBBytestream(ConnectionBytestream):
else: else:
conn.Event('IBB', 'ERROR ON SEND', file_props) conn.Event('IBB', 'ERROR ON SEND', file_props)
elif stanza.getType() == 'result': elif stanza.getType() == 'result':
if file_props.direction[0] == '|': self.SendHandler(file_props)
file_props.direction = file_props.direction[1:]
self.SendHandler()
else:
conn.send(nbxmpp.Error(stanza,
nbxmpp.ERR_UNEXPECTED_REQUEST))
break break
else:
if stanza.getTag('data'):
sid = stanza.getTagAttr('data', 'sid')
file_props = FilesProp.getFilePropByTransportSid(self.name, sid)
if file_props.connected and self.IBBMessageHandler(conn,
stanza):
reply = stanza.buildReply('result')
reply.delChild('data')
conn.send(reply)
raise nbxmpp.NodeProcessed
elif syn_id == self.last_sent_ibb_id:
self.SendHandler()
class ConnectionSocks5BytestreamZeroconf(ConnectionSocks5Bytestream): class ConnectionSocks5BytestreamZeroconf(ConnectionSocks5Bytestream):

View File

@ -1271,6 +1271,11 @@ class AddNewContactWindow:
def _nec_gateway_prompt_received(self, obj): def _nec_gateway_prompt_received(self, obj):
if self.adding_jid: if self.adding_jid:
jid, transport, type_ = self.adding_jid jid, transport, type_ = self.adding_jid
if obj.stanza.getError():
ErrorDialog(_('Error while adding transport contact'),
_('This error occured while adding a contact for transport '
'%s:\n\n%s') % (transport, obj.stanza.getErrorMsg()))
return
if obj.prompt_jid: if obj.prompt_jid:
self._add_jid(obj.prompt_jid, type_) self._add_jid(obj.prompt_jid, type_)
else: else:

View File

@ -70,8 +70,7 @@ class FileTransfersWindow:
'notify_ft_complete_checkbox') 'notify_ft_complete_checkbox')
shall_notify = gajim.config.get('notify_on_file_complete') shall_notify = gajim.config.get('notify_on_file_complete')
self.notify_ft_checkbox.set_active(shall_notify self.notify_ft_checkbox.set_active(shall_notify)
)
self.model = Gtk.ListStore(GdkPixbuf.Pixbuf, str, str, str, str, int, self.model = Gtk.ListStore(GdkPixbuf.Pixbuf, str, str, str, str, int,
int, str) int, str)
self.tree.set_model(self.model) self.tree.set_model(self.model)
@ -841,7 +840,7 @@ class FileTransfersWindow:
if not is_row_selected: if not is_row_selected:
# no selection, disable the buttons # no selection, disable the buttons
self.set_all_insensitive() self.set_all_insensitive()
elif not is_stopped: elif not is_stopped and file_props.continue_cb:
if is_transfer_active(file_props): if is_transfer_active(file_props):
# file transfer is active # file transfer is active
self.toggle_pause_continue(True) self.toggle_pause_continue(True)

View File

@ -988,11 +988,6 @@ class Interface:
session = gajim.connections[account].get_jingle_session(jid=None, session = gajim.connections[account].get_jingle_session(jid=None,
sid=file_props.sid) sid=file_props.sid)
ft_win = self.instances['file_transfers'] ft_win = self.instances['file_transfers']
if not file_props.hash_:
# We disn't get the hash, sender probably don't support that
jid = file_props.sender
self.popup_ft_result(account, jid, file_props)
ft_win.set_status(file_props, 'ok')
h = Hashes() h = Hashes()
try: try:
file_ = open(file_props.file_name, 'rb') file_ = open(file_props.file_name, 'rb')
@ -1027,14 +1022,26 @@ class Interface:
if file_props.stalled or file_props.paused: if file_props.stalled or file_props.paused:
return return
if file_props.type_ == 'r' and file_props.hash_: # we receive a file if file_props.type_ == 'r': # we receive a file
gajim.socks5queue.remove_receiver(file_props.sid, True, True) gajim.socks5queue.remove_receiver(file_props.sid, True, True)
# we compare hashes
if file_props.session_type == 'jingle': if file_props.session_type == 'jingle':
# Compare hashes in a new thread if file_props.hash_ and file_props.error == 0:
self.hashThread = Thread(target=self.__compare_hashes, # We compare hashes in a new thread
args=(account, file_props)) self.hashThread = Thread(target=self.__compare_hashes,
self.hashThread.start() args=(account, file_props))
self.hashThread.start()
else:
# We disn't get the hash, sender probably don't support that
jid = file_props.sender
self.popup_ft_result(account, jid, file_props)
if file_props.error == 0:
ft.set_status(file_props, 'ok')
session = gajim.connections[account].get_jingle_session(jid=None,
sid=file_props.sid)
# End jingle session
# TODO: only if there are no other parallel downloads in this session
if session:
session.end_session()
else: # we send a file else: # we send a file
jid = file_props.receiver jid = file_props.receiver
gajim.socks5queue.remove_sender(file_props.sid, True, True) gajim.socks5queue.remove_sender(file_props.sid, True, True)