file_props refactoring

This commit is contained in:
Jefry Lagrange 2012-06-14 12:27:23 -04:00
parent b6b44cb328
commit 2af1af2011
14 changed files with 876 additions and 804 deletions

View File

@ -3203,11 +3203,11 @@ class ChatControl(ChatControlBase):
""" """
Show an InfoBar on top of control Show an InfoBar on top of control
""" """
markup = '<b>%s:</b> %s' % (_('File transfer'), file_props['name']) markup = '<b>%s:</b> %s' % (_('File transfer'), file_props.name)
if 'desc' in file_props and file_props['desc']: if file_props.desc:
markup += ' (%s)' % file_props['desc'] markup += ' (%s)' % file_props.desc
markup += '\n%s: %s' % (_('Size'), helpers.convert_bytes( markup += '\n%s: %s' % (_('Size'), helpers.convert_bytes(
file_props['size'])) file_props.size))
b1 = gtk.Button(_('_Accept')) b1 = gtk.Button(_('_Accept'))
b1.connect('clicked', self._on_accept_file_request, file_props) b1.connect('clicked', self._on_accept_file_request, file_props)
b2 = gtk.Button(stock=gtk.STOCK_CANCEL) b2 = gtk.Button(stock=gtk.STOCK_CANCEL)
@ -3216,9 +3216,7 @@ class ChatControl(ChatControlBase):
gtk.MESSAGE_QUESTION) gtk.MESSAGE_QUESTION)
def _on_open_ft_folder(self, widget, file_props): def _on_open_ft_folder(self, widget, file_props):
if 'file-name' not in file_props: path = os.path.split(file_props.file_name)[0]
return
path = os.path.split(file_props['file-name'])[0]
if os.path.exists(path) and os.path.isdir(path): if os.path.exists(path) and os.path.isdir(path):
helpers.launch_file_manager(path) helpers.launch_file_manager(path)
ev = self._get_file_props_event(file_props, 'file-completed') ev = self._get_file_props_event(file_props, 'file-completed')
@ -3232,9 +3230,9 @@ class ChatControl(ChatControlBase):
def _got_file_completed(self, file_props): def _got_file_completed(self, file_props):
markup = '<b>%s:</b> %s' % (_('File transfer completed'), markup = '<b>%s:</b> %s' % (_('File transfer completed'),
file_props['name']) file_props.name)
if 'desc' in file_props and file_props['desc']: if file_props.desc:
markup += ' (%s)' % file_props['desc'] markup += ' (%s)' % file_props.desc
b1 = gtk.Button(_('_Open Containing Folder')) b1 = gtk.Button(_('_Open Containing Folder'))
b1.connect('clicked', self._on_open_ft_folder, file_props) b1.connect('clicked', self._on_open_ft_folder, file_props)
b2 = gtk.Button(stock=gtk.STOCK_OK) b2 = gtk.Button(stock=gtk.STOCK_OK)

View File

@ -37,6 +37,7 @@ from common.logger import LOG_DB_PATH
from common.pep import SUPPORTED_PERSONAL_USER_EVENTS from common.pep import SUPPORTED_PERSONAL_USER_EVENTS
from common.xmpp.protocol import NS_CHATSTATES from common.xmpp.protocol import NS_CHATSTATES
from common.jingle_transport import JingleTransportSocks5 from common.jingle_transport import JingleTransportSocks5
from common.file_props import FilesProp
import gtkgui_helpers import gtkgui_helpers
@ -1940,16 +1941,44 @@ class FileRequestReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
self.get_id() self.get_id()
self.fjid = self.conn._ft_get_from(self.stanza) self.fjid = self.conn._ft_get_from(self.stanza)
self.jid = gajim.get_jid_without_resource(self.fjid) self.jid = gajim.get_jid_without_resource(self.fjid)
self.file_props = {'type': 'r'}
self.file_props['sender'] = self.fjid
self.file_props['request-id'] = self.id_
if self.jingle_content: if self.jingle_content:
self.file_props['session-type'] = 'jingle' self.FT_content.use_security = bool(self.jingle_content.getTag(
self.file_props['stream-methods'] = xmpp.NS_BYTESTREAM 'security'))
if not self.FT_content.transport:
self.FT_content.transport = JingleTransportSocks5()
self.FT_content.transport.set_our_jid(
self.FT_content.session.ourjid)
self.FT_content.transport.set_connection(
self.FT_content.session.connection)
sid = self.FT_content.transport.sid
self.file_props = FilesProp.getNewFileProp(self.conn.name, sid)
self.file_props.session_sid = unicode(
self.stanza.getTag('jingle').getAttr('sid')
)
self.FT_content.file_props = self.file_props
self.FT_content.transport.set_file_props(self.file_props)
if self.file_props.streamhosts:
self.file_props.streamhosts.extend(
self.FT_content.transport.remote_candidates)
else:
self.file_props.streamhosts = \
self.FT_content.transport.remote_candidates
for host in self.file_props.streamhosts:
host['initiator'] = self.FT_content.session.initiator
host['target'] = self.FT_content.session.responder
else:
si = self.stanza.getTag('si')
self.file_props = FilesProp.getNewFileProp(self.conn.name,
unicode(si.getAttr('id'))
)
self.file_props.sender = self.fjid
self.file_props.request_id = self.id_
if self.jingle_content:
self.file_props.session_type = 'jingle'
self.file_props.stream_methods = xmpp.NS_BYTESTREAM
file_tag = self.jingle_content.getTag('description').getTag( file_tag = self.jingle_content.getTag('description').getTag(
'offer').getTag('file') 'offer').getTag('file')
else: else:
si = self.stanza.getTag('si')
profile = si.getAttr('profile') profile = si.getAttr('profile')
if profile != xmpp.NS_FILE: if profile != xmpp.NS_FILE:
self.conn.send_file_rejection(self.file_props, code='400', self.conn.send_file_rejection(self.file_props, code='400',
@ -1965,7 +1994,7 @@ class FileRequestReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
for f in self.dataform.iter_fields(): for f in self.dataform.iter_fields():
if f.var == 'stream-method' and f.type == 'list-single': if f.var == 'stream-method' and f.type == 'list-single':
values = [o[1] for o in f.options] values = [o[1] for o in f.options]
self.file_props['stream-methods'] = ' '.join(values) self.file_props.stream_methods = ' '.join(values)
if xmpp.NS_BYTESTREAM in values or xmpp.NS_IBB in values: if xmpp.NS_BYTESTREAM in values or xmpp.NS_IBB in values:
break break
else: else:
@ -1975,54 +2004,30 @@ class FileRequestReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
file_tag = si.getTag('file') file_tag = si.getTag('file')
for child in file_tag.getChildren(): for child in file_tag.getChildren():
name = child.getName() name = child.getName()
if name in ('name', 'size', 'hash', 'date'): val = child.getData()
val = child.getData() if val is None:
if val is None: continue
continue if name == 'name':
self.file_props[name] = val self.file_props.name = val
# Delete this, it shouldn't be necesary after file_props gets if name == 'size':
# refactored. self.file_props.size = val
if name == 'hash': if name == 'hash':
self.file_props['algo'] = child.getAttr('algo') self.file_props.algo = child.getAttr('algo')
self.file_props.hash_ = val
if name == 'date':
self.file_props.date = val
file_desc_tag = file_tag.getTag('desc') file_desc_tag = file_tag.getTag('desc')
if file_desc_tag is not None: if file_desc_tag is not None:
self.file_props['desc'] = file_desc_tag.getData() self.file_props.desc = file_desc_tag.getData()
if not self.jingle_content: if not self.jingle_content:
mime_type = si.getAttr('mime-type') mime_type = si.getAttr('mime-type')
if mime_type is not None: if mime_type is not None:
self.file_props['mime-type'] = mime_type self.file_props.mime_type = mime_type
self.file_props['receiver'] = self.conn._ft_get_our_jid() self.file_props.receiver = self.conn._ft_get_our_jid()
self.file_props['transfered_size'] = [] self.file_props.transfered_size = []
if self.jingle_content:
self.FT_content.use_security = bool(self.jingle_content.getTag(
'security'))
self.file_props['session-sid'] = unicode(self.stanza.getTag(
'jingle').getAttr('sid'))
self.FT_content.file_props = self.file_props
if not self.FT_content.transport:
self.FT_content.transport = JingleTransportSocks5()
self.FT_content.transport.set_our_jid(
self.FT_content.session.ourjid)
self.FT_content.transport.set_connection(
self.FT_content.session.connection)
self.file_props['sid'] = self.FT_content.transport.sid
self.FT_content.session.connection.files_props[
self.file_props['sid']] = self.file_props
self.FT_content.transport.set_file_props(self.file_props)
if self.file_props.has_key('streamhosts'):
self.file_props['streamhosts'].extend(
self.FT_content.transport.remote_candidates)
else:
self.file_props['streamhosts'] = \
self.FT_content.transport.remote_candidates
for host in self.file_props['streamhosts']:
host['initiator'] = self.FT_content.session.initiator
host['target'] = self.FT_content.session.responder
else:
self.file_props['sid'] = unicode(si.getAttr('id'))
return True return True
class FileRequestErrorEvent(nec.NetworkIncomingEvent): class FileRequestErrorEvent(nec.NetworkIncomingEvent):

153
src/common/file_props.py Normal file
View File

@ -0,0 +1,153 @@
"""
This module is in charge of taking care of all the infomation related to
individual files. Files are identified by the account name and its sid.
>>> print FilesProp.getFileProp('jabberid', '10')
None
>>> fp = FilesProp()
Traceback (most recent call last):
...
Exception: this class should not be instatiated
>>> print FilesProp.getAllFileProp()
[]
>>> fp = FilesProp.getNewFileProp('jabberid', '10')
>>> fp2 = FilesProp.getFileProp('jabberid', '10')
>>> fp == fp2
True
"""
class FilesProp:
_files_props = {}
def __init__(self):
raise Exception('this class should not be instatiated')
@classmethod
def getNewFileProp(cls, account, sid):
fp = FileProp(account, sid)
cls.setFileProp(fp, account, sid)
return fp
@classmethod
def getFileProp(cls, account, sid):
if (account, sid) in cls._files_props.keys():
return cls._files_props[account, sid]
@classmethod
def getFilePropByAccount(cls, account):
# Returns a list of file_props in one account
file_props = []
for account, sid in cls._files_props:
if account == account:
file_props.append(cls._files_props[account, sid])
return file_props
@classmethod
def getFilePropByType(cls, type_, sid):
# This method should be deleted. Getting fileprop by type and sid is not
# unique enough. More than one fileprop might have the same type and sid
files_prop = cls.getAllFileProp()
for fp in files_prop:
if fp.type_ == type_ and fp.sid == sid:
return fp
@classmethod
def getFilePropBySid(cls, sid):
# This method should be deleted. It is kept to make things compatible
# This method should be replaced and instead get the file_props by
# account and sid
files_prop = cls.getAllFileProp()
for fp in files_prop:
if fp.sid == sid:
return fp
@classmethod
def getAllFileProp(cls):
return cls._files_props.values()
@classmethod
def setFileProp(cls, fp, account, sid):
cls._files_props[account, sid] = fp
@classmethod
def deleteFileProp(cls, file_prop):
files_props = cls._files_props
a = s = None
for account, sid in files_props:
fp = files_props[account, sid]
if fp is file_prop:
a = account
s = sid
if a != None and s != None:
del files_props[a, s]
class FileProp(object):
def __init__(self, account, sid):
# Do not instatiate this class directly. Call FilesProp.getNeFileProp
# instead
self.streamhosts = []
self.transfered_size = []
self.started = False
self.completed = False
self.paused = False
self.stalled = False
self.connected = False
self.stopped = False
self.is_a_proxy = False
self.proxyhost = None
self.proxy_sender = None
self.proxy_receiver = None
self.streamhost_used = None
# method callback called in case of transfer failure
self.failure_cb = None
# method callback called when disconnecting
self.disconnect_cb = None
self.continue_cb = None
self.sha_str = None
# transfer type: 's' for sending and 'r' for receiving
self.type_ = None
self.error = None
self.elapsed_time = None
self.last_time = None
self.received_len = None
# full file path
self.file_name = None
self.name = None
self.file_desc = None
self.offset = None
self.sender = None
self.receiver = None
self.tt_account = None
self.size = None
self._sid = sid
self.account = account
self.mime_type = None
self.algo = None
self.direction = None
self.syn_id = None
self.seq = None
self.hash_ = None
self.session_sid = None
self.fd = None
self.startexmpp = None
self.session_type = None
def getsid(self):
# Getter of the property sid
return self._sid
def setsid(self, value):
# The sid value will change
# we need to change the in _files_props key as well
del FilesProp._files_props[self.account, self._sid]
self._sid = value
FilesProp._files_props[self.account, self._sid] = self
sid = property(getsid, setsid)
if __name__ == "__main__":
import doctest
doctest.testmod()

View File

@ -152,7 +152,7 @@ class ConnectionJingle(object):
# this is a file transfer # this is a file transfer
jingle.session_type_FT = True jingle.session_type_FT = True
self._sessions[jingle.sid] = jingle self._sessions[jingle.sid] = jingle
file_props['sid'] = jingle.sid file_props.sid = jingle.sid
if contact.supports(xmpp.NS_JINGLE_BYTESTREAM): if contact.supports(xmpp.NS_JINGLE_BYTESTREAM):
transport = JingleTransportSocks5() transport = JingleTransportSocks5()
elif contact.supports(xmpp.NS_JINGLE_IBB): elif contact.supports(xmpp.NS_JINGLE_IBB):

View File

@ -172,25 +172,25 @@ class JingleContent(object):
simode = xmpp.simplexml.Node(tag='offer') simode = xmpp.simplexml.Node(tag='offer')
file_tag = simode.setTag('file', namespace=xmpp.NS_FILE) file_tag = simode.setTag('file', namespace=xmpp.NS_FILE)
if 'name' in self.file_props: if self.file_props.name:
node = xmpp.simplexml.Node(tag='name') node = xmpp.simplexml.Node(tag='name')
node.addData(self.file_props['name']) node.addData(self.file_props.name)
file_tag.addChild(node=node) file_tag.addChild(node=node)
if 'size' in self.file_props: if self.file_props.size:
node = xmpp.simplexml.Node(tag='size') node = xmpp.simplexml.Node(tag='size')
node.addData(self.file_props['size']) node.addData(self.file_props.size)
file_tag.addChild(node=node) file_tag.addChild(node=node)
if 'hash' in self.file_props: if self.file_props.hash_:
# TODO: use xep-300 for this bit # TODO: use xep-300 for this bit
pass pass
# if the file is less than 10 mb, then it is small # if the file is less than 10 mb, then it is small
# lets calculate it right away # lets calculate it right away
if int(self.file_props['size']) < 10000000: if int(self.file_props.size) < 10000000:
h = self._calcHash() h = self._calcHash()
file_tag.addChild(node=h) file_tag.addChild(node=h)
desc = file_tag.setTag('desc') desc = file_tag.setTag('desc')
if 'desc' in self.file_props: if self.file_props.desc:
desc.setData(self.file_props['desc']) desc.setData(self.file_props.desc)
description_node.addChild(node=simode) description_node.addChild(node=simode)

View File

@ -76,11 +76,11 @@ class JingleFileTransfer(JingleContent):
self.weinitiate = True self.weinitiate = True
if self.file_props is not None: if self.file_props is not None:
self.file_props['sender'] = session.ourjid self.file_props.sender = session.ourjid
self.file_props['receiver'] = session.peerjid self.file_props.receiver = session.peerjid
self.file_props['session-type'] = 'jingle' self.file_props.session_type = 'jingle'
self.file_props['session-sid'] = session.sid self.file_props.session_sid = session.sid
self.file_props['transfered_size'] = [] self.file_props.transfered_size = []
log.info("FT request: %s" % file_props) log.info("FT request: %s" % file_props)
@ -92,7 +92,7 @@ class JingleFileTransfer(JingleContent):
log.info('ourjid: %s' % session.ourjid) log.info('ourjid: %s' % session.ourjid)
if self.file_props is not None: if self.file_props is not None:
self.file_props['sid'] = self.transport.sid self.file_props.sid = self.transport.sid
self.session = session self.session = session
self.media = 'file' self.media = 'file'
@ -119,13 +119,12 @@ class JingleFileTransfer(JingleContent):
FT_content=self)) FT_content=self))
self._listen_host() self._listen_host()
# Delete this after file_props refactoring this shouldn't be necesary # Delete this after file_props refactoring this shouldn't be necesary
self.session.file_hash = self.file_props['hash'] self.session.file_hash = self.file_props.hash_
self.session.hash_algo = self.file_props['algo'] self.session.hash_algo = self.file_props.algo
def __on_session_initiate_sent(self, stanza, content, error, action): def __on_session_initiate_sent(self, stanza, content, error, action):
# Calculate file_hash in a new thread # Calculate file_hash in a new thread
# if we haven't sent the hash already. # if we haven't sent the hash already.
if 'hash' not in self.file_props: if self.file_props.hash_ is None:
self.hashThread = threading.Thread(target=self.__send_hash) self.hashThread = threading.Thread(target=self.__send_hash)
self.hashThread.start() self.hashThread.start()
@ -143,7 +142,7 @@ class JingleFileTransfer(JingleContent):
if self.session.hash_algo == None: if self.session.hash_algo == None:
return return
try: try:
file_ = open(self.file_props['file-name'], 'r') file_ = open(self.file_props.file_name, 'r')
except: except:
# can't open file # can't open file
return return
@ -154,7 +153,7 @@ class JingleFileTransfer(JingleContent):
if not hash_: if not hash_:
# Hash alogrithm not supported # Hash alogrithm not supported
return return
self.file_props['hash'] = hash_ self.file_props.hash_ = hash_
h.addHash(hash_, self.session.hash_algo) h.addHash(hash_, self.session.hash_algo)
return h return h
@ -175,26 +174,21 @@ class JingleFileTransfer(JingleContent):
self.__state_changed(STATE_TRANSFERING) self.__state_changed(STATE_TRANSFERING)
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
self.file_props['streamhosts'] = self.transport.remote_candidates self.file_props.streamhosts = self.transport.remote_candidates
for host in self.file_props['streamhosts']: for host in self.file_props.streamhosts:
host['initiator'] = self.session.initiator host['initiator'] = self.session.initiator
host['target'] = self.session.responder host['target'] = self.session.responder
host['sid'] = self.file_props['sid'] host['sid'] = self.file_props.sid
response = stanza.buildReply('result') response = stanza.buildReply('result')
response.delChild(response.getQuery()) response.delChild(response.getQuery())
con.connection.send(response) con.connection.send(response)
if not gajim.socks5queue.get_file_props(
self.session.connection.name, self.file_props['sid']):
gajim.socks5queue.add_file_props(self.session.connection.name,
self.file_props)
fingerprint = None fingerprint = None
if self.use_security: if self.use_security:
fingerprint = 'client' fingerprint = 'client'
if self.transport.type == TransportType.SOCKS5: if self.transport.type == TransportType.SOCKS5:
gajim.socks5queue.connect_to_hosts(self.session.connection.name, gajim.socks5queue.connect_to_hosts(self.session.connection.name,
self.file_props['sid'], self.on_connect, self.file_props.sid, self.on_connect,
self._on_connect_error, fingerprint=fingerprint, self._on_connect_error, fingerprint=fingerprint,
receiving=False) receiving=False)
return return
@ -310,15 +304,15 @@ class JingleFileTransfer(JingleContent):
def _store_socks5_sid(self, sid, hash_id): def _store_socks5_sid(self, sid, hash_id):
# callback from socsk5queue.start_listener # callback from socsk5queue.start_listener
self.file_props['hash'] = hash_id self.file_props.hash_ = hash_id
def _listen_host(self): def _listen_host(self):
receiver = self.file_props['receiver'] receiver = self.file_props.receiver
sender = self.file_props['sender'] sender = self.file_props.sender
sha_str = helpers.get_auth_sha(self.file_props['sid'], sender, sha_str = helpers.get_auth_sha(self.file_props.sid, sender,
receiver) receiver)
self.file_props['sha_str'] = sha_str self.file_props.sha_str = sha_str
port = gajim.config.get('file_transfers_port') port = gajim.config.get('file_transfers_port')

View File

@ -14,6 +14,7 @@
import gajim import gajim
import xmpp import xmpp
from jingle_transport import * from jingle_transport import *
from common.socks5 import Socks5ReceiverClient, Socks5SenderClient
class JingleFileTransferStates: class JingleFileTransferStates:
@ -37,26 +38,18 @@ class StateInitialized(JingleFileTransferStates):
''' '''
def action(self, args=None): def action(self, args=None):
self.jft._listen_host()
if self.jft.weinitiate: if self.jft.weinitiate:
# update connection's fileprops # update connection's fileprops
self.jft.session.connection.files_props[self.jft.file_props['sid']] = \ self.jft._listen_host()
self.jft.file_props
# Listen on configured port for file transfer # Listen on configured port for file transfer
else: else:
# Add file_props to the queue
if not gajim.socks5queue.get_file_props(
self.jft.session.connection.name, self.jft.file_props['sid']):
gajim.socks5queue.add_file_props(
self.jft.session.connection.name,
self.jft.file_props)
fingerprint = None fingerprint = None
if self.jft.use_security: if self.jft.use_security:
fingerprint = 'client' fingerprint = 'client'
# Connect to the candidate host, on success call on_connect method # Connect to the candidate host, on success call on_connect method
gajim.socks5queue.connect_to_hosts( gajim.socks5queue.connect_to_hosts(
self.jft.session.connection.name, self.jft.session.connection.name,
self.jft.file_props['sid'], self.jft.on_connect, self.jft.file_props.sid, self.jft.on_connect,
self.jft._on_connect_error, fingerprint=fingerprint) self.jft._on_connect_error, fingerprint=fingerprint)
@ -156,9 +149,7 @@ class StateTransfering(JingleFileTransferStates):
''' '''
def __start_IBB_transfer(self, con): def __start_IBB_transfer(self, con):
con.files_props[self.jft.file_props['sid']] = \ fp = open(self.jft.file_props.file_name, 'r')
self.jft.file_props
fp = open(self.jft.file_props['file-name'], 'r')
con.OpenStream( self.jft.transport.sid, con.OpenStream( self.jft.transport.sid,
self.jft.session.peerjid, fp, blocksize=4096) self.jft.session.peerjid, fp, blocksize=4096)
@ -174,14 +165,14 @@ class StateTransfering(JingleFileTransferStates):
streamhost_used = self.jft.nominated_cand['peer-cand'] streamhost_used = self.jft.nominated_cand['peer-cand']
if streamhost_used['type'] == 'proxy': if streamhost_used['type'] == 'proxy':
self.jft.file_props['is_a_proxy'] = True self.jft.file_props.is_a_proxy = True
# This needs to be changed when requesting # This needs to be changed when requesting
if self.jft.weinitiate: if self.jft.weinitiate:
self.jft.file_props['proxy_sender'] = streamhost_used['initiator'] self.jft.file_props.proxy_sender = streamhost_used['initiator']
self.jft.file_props['proxy_receiver'] = streamhost_used['target'] self.jft.file_props.proxy_receiver = streamhost_used['target']
else: else:
self.jft.file_props['proxy_sender'] = streamhost_used['target'] self.jft.file_props.proxy_sender = streamhost_used['target']
self.jft.file_props['proxy_receiver'] = streamhost_used['initiator'] self.jft.file_props.proxy_receiver = streamhost_used['initiator']
# This needs to be changed when requesting # This needs to be changed when requesting
if not self.jft.weinitiate and streamhost_used['type'] == 'proxy': if not self.jft.weinitiate and streamhost_used['type'] == 'proxy':
@ -200,12 +191,12 @@ class StateTransfering(JingleFileTransferStates):
return return
if streamhost_used['type'] == 'proxy': if streamhost_used['type'] == 'proxy':
self.jft.file_props['streamhost-used'] = True self.jft.file_props.streamhost_used = True
streamhost_used['sid'] = self.jft.file_props['sid'] streamhost_used['sid'] = self.jft.file_props.sid
self.jft.file_props['streamhosts'] = [] self.jft.file_props.streamhosts = []
self.jft.file_props['streamhosts'].append(streamhost_used) self.jft.file_props.streamhosts.append(streamhost_used)
self.jft.file_props['proxyhosts'] = [] self.jft.file_props.proxyhosts = []
self.jft.file_props['proxyhosts'].append(streamhost_used) self.jft.file_props.proxyhosts.append(streamhost_used)
# This needs to be changed when requesting # This needs to be changed when requesting
if self.jft.weinitiate: if self.jft.weinitiate:
@ -218,7 +209,7 @@ class StateTransfering(JingleFileTransferStates):
connected=False, file_props=self.jft.file_props) connected=False, file_props=self.jft.file_props)
else: else:
sockobj = Socks5ReceiverClient(gajim.idlequeue, streamhost_used, sockobj = Socks5ReceiverClient(gajim.idlequeue, streamhost_used,
sid=self.jft.file_props['sid'], sid=self.jft.file_props.sid,
file_props=self.jft.file_props, fingerprint=None) file_props=self.jft.file_props, fingerprint=None)
sockobj.proxy = True sockobj.proxy = True
sockobj.streamhost = streamhost_used sockobj.streamhost = streamhost_used
@ -228,7 +219,7 @@ class StateTransfering(JingleFileTransferStates):
# If we offered the nominated candidate used, we activate # If we offered the nominated candidate used, we activate
# the proxy # the proxy
if not self.jft.isOurCandUsed(): if not self.jft.isOurCandUsed():
gajim.socks5queue.on_success[self.jft.file_props['sid']] = \ gajim.socks5queue.on_success[self.jft.file_props.sid] = \
self.jft.transport._on_proxy_auth_ok self.jft.transport._on_proxy_auth_ok
# TODO: add on failure # TODO: add on failure
else: else:

View File

@ -190,8 +190,8 @@ class JingleTransportSocks5(JingleTransport):
c['type'] = 'direct' c['type'] = 'direct'
c['jid'] = self.ourjid c['jid'] = self.ourjid
c['priority'] = (2**16) * type_preference c['priority'] = (2**16) * type_preference
c['initiator'] = self.file_props['sender'] c['initiator'] = self.file_props.sender
c['target'] = self.file_props['receiver'] c['target'] = self.file_props.receiver
local_ip_cand.append(c) local_ip_cand.append(c)
self._add_candidates(local_ip_cand) self._add_candidates(local_ip_cand)
@ -213,8 +213,8 @@ class JingleTransportSocks5(JingleTransport):
c['type'] = 'direct' c['type'] = 'direct'
c['jid'] = self.ourjid c['jid'] = self.ourjid
c['priority'] = (2**16) * type_preference c['priority'] = (2**16) * type_preference
c['initiator'] = self.file_props['sender'] c['initiator'] = self.file_props.sender
c['target'] = self.file_props['receiver'] c['target'] = self.file_props.receiver
additional_ip_cand.append(c) additional_ip_cand.append(c)
self._add_candidates(additional_ip_cand) self._add_candidates(additional_ip_cand)
@ -228,7 +228,7 @@ class JingleTransportSocks5(JingleTransport):
proxyhosts = socks5conn._get_file_transfer_proxies_from_config(self.file_props) proxyhosts = socks5conn._get_file_transfer_proxies_from_config(self.file_props)
if proxyhosts: if proxyhosts:
self.file_props['proxyhosts'] = proxyhosts self.file_props.proxyhosts = proxyhosts
for proxyhost in proxyhosts: for proxyhost in proxyhosts:
c = {'host': proxyhost['host']} c = {'host': proxyhost['host']}
@ -237,15 +237,15 @@ class JingleTransportSocks5(JingleTransport):
c['type'] = 'proxy' c['type'] = 'proxy'
c['jid'] = proxyhost['jid'] c['jid'] = proxyhost['jid']
c['priority'] = (2**16) * type_preference c['priority'] = (2**16) * type_preference
c['initiator'] = self.file_props['sender'] c['initiator'] = self.file_props.sender
c['target'] = self.file_props['receiver'] c['target'] = self.file_props.receiver
proxy_cand.append(c) proxy_cand.append(c)
self._add_candidates(proxy_cand) self._add_candidates(proxy_cand)
def get_content(self): def get_content(self):
sesn = self.connection.get_jingle_session(self.ourjid, sesn = self.connection.get_jingle_session(self.ourjid,
self.file_props['session-sid']) self.file_props.session_sid)
for content in sesn.contents.values(): for content in sesn.contents.values():
if content.transport == self: if content.transport == self:
return content return content
@ -256,7 +256,7 @@ class JingleTransportSocks5(JingleTransport):
if not self.connection: if not self.connection:
return return
sesn = self.connection.get_jingle_session(self.ourjid, sesn = self.connection.get_jingle_session(self.ourjid,
self.file_props['session-sid']) self.file_props.session_sid)
if sesn is None: if sesn is None:
return return

View File

@ -32,6 +32,7 @@ import socket
import base64 import base64
import gobject import gobject
import time import time
import pdb
from common import xmpp from common import xmpp
from common import gajim from common import gajim
@ -39,40 +40,42 @@ from common import helpers
from common import dataforms from common import dataforms
from common import ged from common import ged
from common import jingle_xtls from common import jingle_xtls
from common.file_props import FilesProp
from common.socks5 import Socks5Receiver from common.socks5 import Socks5Receiver
import logging import logging
log = logging.getLogger('gajim.c.p.bytestream') log = logging.getLogger('gajim.c.p.bytestream')
def is_transfer_paused(file_props): def is_transfer_paused(file_props):
if 'stopped' in file_props and file_props['stopped']: if file_props.stopped:
return False return False
if 'completed' in file_props and file_props['completed']: if file_props.completed:
return False return False
if 'disconnect_cb' not in file_props: if file_props.disconnect_cb:
return False return False
return file_props['paused'] return file_props.paused
def is_transfer_active(file_props): def is_transfer_active(file_props):
if 'stopped' in file_props and file_props['stopped']: if file_props.stopped:
return False return False
if 'completed' in file_props and file_props['completed']: if file_props.completed:
return False return False
if 'started' not in file_props or not file_props['started']: if not file_props.started:
return False return False
if 'paused' not in file_props: if file_props.paused:
return True return True
return not file_props['paused'] return not file_props.paused
def is_transfer_stopped(file_props): def is_transfer_stopped(file_props):
if 'error' in file_props and file_props['error'] != 0: if not file_props:
return True return True
if 'completed' in file_props and file_props['completed']: if file_props.error != 0:
return True return True
if 'connected' in file_props and file_props['connected'] == False: if file_props.completed:
return True return True
if 'stopped' not in file_props or not file_props['stopped']: if not file_props.connected:
return True
if not file_props.stopped:
return False return False
return True return True
@ -80,7 +83,6 @@ def is_transfer_stopped(file_props):
class ConnectionBytestream: class ConnectionBytestream:
def __init__(self): def __init__(self):
self.files_props = {}
gajim.ged.register_event_handler('file-request-received', ged.GUI1, gajim.ged.register_event_handler('file-request-received', ged.GUI1,
self._nec_file_request_received) self._nec_file_request_received)
@ -94,7 +96,7 @@ class ConnectionBytestream:
return our_jid + '/' + resource return our_jid + '/' + resource
def _ft_get_receiver_jid(self, file_props): def _ft_get_receiver_jid(self, file_props):
return file_props['receiver'].jid + '/' + file_props['receiver'].resource return file_props.receiver.jid + '/' + file_props.receiver.resource
def _ft_get_from(self, iq_obj): def _ft_get_from(self, iq_obj):
return helpers.get_full_jid_from_iq(iq_obj) return helpers.get_full_jid_from_iq(iq_obj)
@ -108,20 +110,19 @@ class ConnectionBytestream:
""" """
if not self.connection or self.connected < 2: if not self.connection or self.connected < 2:
return return
file_props['sender'] = self._ft_get_our_jid() file_props.sender = self._ft_get_our_jid()
fjid = self._ft_get_receiver_jid(file_props) fjid = self._ft_get_receiver_jid(file_props)
iq = xmpp.Iq(to=fjid, typ='set') iq = xmpp.Iq(to=fjid, typ='set')
iq.setID(file_props['sid']) iq.setID(file_props.sid)
self.files_props[file_props['sid']] = file_props
si = iq.setTag('si', namespace=xmpp.NS_SI) si = iq.setTag('si', namespace=xmpp.NS_SI)
si.setAttr('profile', xmpp.NS_FILE) si.setAttr('profile', xmpp.NS_FILE)
si.setAttr('id', file_props['sid']) si.setAttr('id', file_props.sid)
file_tag = si.setTag('file', namespace=xmpp.NS_FILE) file_tag = si.setTag('file', namespace=xmpp.NS_FILE)
file_tag.setAttr('name', file_props['name']) file_tag.setAttr('name', file_props.name)
file_tag.setAttr('size', file_props['size']) file_tag.setAttr('size', file_props.size)
desc = file_tag.setTag('desc') desc = file_tag.setTag('desc')
if 'desc' in file_props: if file_props.desc:
desc.setData(file_props['desc']) desc.setData(file_props.desc)
file_tag.setTag('range') file_tag.setTag('range')
feature = si.setTag('feature', namespace=xmpp.NS_FEATURE) feature = si.setTag('feature', namespace=xmpp.NS_FEATURE)
_feature = xmpp.DataForm(typ='form') _feature = xmpp.DataForm(typ='form')
@ -142,24 +143,22 @@ class ConnectionBytestream:
# file transfer initiated by a jingle session # file transfer initiated by a jingle session
log.info("send_file_approval: jingle session accept") log.info("send_file_approval: jingle session accept")
if file_props.get('session-type') == 'jingle': if file_props.session_type == 'jingle':
session = self.get_jingle_session(file_props['sender'], session = self.get_jingle_session(file_props.sender,
file_props['session-sid']) file_props.session_sid)
if not session: if not session:
return return
content = None content = None
for c in session.contents.values(): for c in session.contents.values():
if c.transport.sid == file_props['sid']: if c.transport.sid == file_props.sid:
content = c content = c
break break
if not content: if not content:
return return
gajim.socks5queue.add_file_props(self.name, file_props)
if not session.accepted: if not session.accepted:
if session.get_content('file', content.name).use_security: if session.get_content('file', content.name).use_security:
id_ = jingle_xtls.send_cert_request(self, id_ = jingle_xtls.send_cert_request(self,
file_props['sender']) file_props.sender)
jingle_xtls.key_exchange_pend(id_, content) jingle_xtls.key_exchange_pend(id_, content)
return return
session.approve_session() session.approve_session()
@ -167,19 +166,19 @@ class ConnectionBytestream:
session.approve_content('file', content.name) session.approve_content('file', content.name)
return return
iq = xmpp.Iq(to=unicode(file_props['sender']), typ='result') iq = xmpp.Iq(to=unicode(file_props.sender), typ='result')
iq.setAttr('id', file_props['request-id']) iq.setAttr('id', file_props.request_id)
si = iq.setTag('si', namespace=xmpp.NS_SI) si = iq.setTag('si', namespace=xmpp.NS_SI)
if 'offset' in file_props and file_props['offset']: if file_props.offset:
file_tag = si.setTag('file', namespace=xmpp.NS_FILE) file_tag = si.setTag('file', namespace=xmpp.NS_FILE)
range_tag = file_tag.setTag('range') range_tag = file_tag.setTag('range')
range_tag.setAttr('offset', file_props['offset']) range_tag.setAttr('offset', file_props.offset)
feature = si.setTag('feature', namespace=xmpp.NS_FEATURE) feature = si.setTag('feature', namespace=xmpp.NS_FEATURE)
_feature = xmpp.DataForm(typ='submit') _feature = xmpp.DataForm(typ='submit')
feature.addChild(node=_feature) feature.addChild(node=_feature)
field = _feature.setField('stream-method') field = _feature.setField('stream-method')
field.delAttr('type') field.delAttr('type')
if xmpp.NS_BYTESTREAM in file_props['stream-methods']: if xmpp.NS_BYTESTREAM in file_props.stream_methods:
field.setValue(xmpp.NS_BYTESTREAM) field.setValue(xmpp.NS_BYTESTREAM)
else: else:
field.setValue(xmpp.NS_IBB) field.setValue(xmpp.NS_IBB)
@ -195,12 +194,12 @@ class ConnectionBytestream:
# user response to ConfirmationDialog may come after we've disconneted # user response to ConfirmationDialog may come after we've disconneted
if not self.connection or self.connected < 2: if not self.connection or self.connected < 2:
return return
if file_props['session-type'] == 'jingle': if file_props.session_type == 'jingle':
jingle = self._sessions[file_props['session-sid']] jingle = self._sessions[file_props.session_sid]
jingle.cancel_session() jingle.cancel_session()
return return
iq = xmpp.Iq(to=unicode(file_props['sender']), typ='error') iq = xmpp.Iq(to=unicode(file_props.sender), typ='error')
iq.setAttr('id', file_props['request-id']) iq.setAttr('id', file_props.request_id)
if code == '400' and typ in ('stream', 'profile'): if code == '400' and typ in ('stream', 'profile'):
name = 'bad-request' name = 'bad-request'
text = '' text = ''
@ -217,13 +216,13 @@ class ConnectionBytestream:
self.connection.send(iq) self.connection.send(iq)
def _siResultCB(self, con, iq_obj): def _siResultCB(self, con, iq_obj):
file_props = self.files_props.get(iq_obj.getAttr('id')) file_props = FilesProp.getFileProp(con.name, iq_obj.getAttr('id'))
if not file_props: if not file_props:
return return
if 'request-id' in file_props: if file_props.request_id:
# we have already sent streamhosts info # we have already sent streamhosts info
return return
file_props['receiver'] = self._ft_get_from(iq_obj) file_props.receiver = self._ft_get_from(iq_obj)
si = iq_obj.getTag('si') si = iq_obj.getTag('si')
file_tag = si.getTag('file') file_tag = si.getTag('file')
range_tag = None range_tag = None
@ -232,10 +231,10 @@ class ConnectionBytestream:
if range_tag: if range_tag:
offset = range_tag.getAttr('offset') offset = range_tag.getAttr('offset')
if offset: if offset:
file_props['offset'] = int(offset) file_props.offset = int(offset)
length = range_tag.getAttr('length') length = range_tag.getAttr('length')
if length: if length:
file_props['length'] = int(length) file_props.length = int(length)
feature = si.setTag('feature') feature = si.setTag('feature')
if feature.getNamespace() != xmpp.NS_FEATURE: if feature.getNamespace() != xmpp.NS_FEATURE:
return return
@ -246,9 +245,9 @@ class ConnectionBytestream:
self._send_socks5_info(file_props) self._send_socks5_info(file_props)
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
if field.getValue() == xmpp.NS_IBB: if field.getValue() == xmpp.NS_IBB:
sid = file_props['sid'] sid = file_props.sid
fp = open(file_props['file-name'], 'r') fp = open(file_props.file_name, 'r')
self.OpenStream(sid, file_props['receiver'], fp) self.OpenStream(sid, file_props.receiver, fp)
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
def _siSetCB(self, con, iq_obj): def _siSetCB(self, con, iq_obj):
@ -258,20 +257,18 @@ class ConnectionBytestream:
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
def _nec_file_request_received(self, obj): def _nec_file_request_received(self, obj):
if obj.conn.name != self.name: pass
return
gajim.socks5queue.add_file_props(self.name, obj.file_props)
def _siErrorCB(self, con, iq_obj): def _siErrorCB(self, con, iq_obj):
si = iq_obj.getTag('si') si = iq_obj.getTag('si')
profile = si.getAttr('profile') profile = si.getAttr('profile')
if profile != xmpp.NS_FILE: if profile != xmpp.NS_FILE:
return return
file_props = self.files_props.get(iq_obj.getAttr('id')) file_props = FilesProp.getFileProp(con.name, iq_obj.getAttr('id'))
if not file_props: if not file_props:
return return
jid = self._ft_get_from(iq_obj) jid = self._ft_get_from(iq_obj)
file_props['error'] = -3 file_props.error = -3
from common.connection_handlers_events import FileRequestErrorEvent from common.connection_handlers_events import FileRequestErrorEvent
gajim.nec.push_incoming_event(FileRequestErrorEvent(None, conn=self, gajim.nec.push_incoming_event(FileRequestErrorEvent(None, conn=self,
jid=jid, file_props=file_props, error_msg='')) jid=jid, file_props=file_props, error_msg=''))
@ -299,59 +296,54 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
""" """
Stop all active transfer to or from the given contact Stop all active transfer to or from the given contact
""" """
for file_props in self.files_props.values(): for file_props in FilesProp.getAllFileProp():
if is_transfer_stopped(file_props): if is_transfer_stopped(file_props):
continue continue
receiver_jid = unicode(file_props['receiver']) receiver_jid = unicode(file_props.receiver)
if contact.get_full_jid() == receiver_jid: if contact.get_full_jid() == receiver_jid:
file_props['error'] = -5 file_props.error = -5
self.remove_transfer(file_props) self.remove_transfer(file_props)
from common.connection_handlers_events import \ from common.connection_handlers_events import \
FileRequestErrorEvent FileRequestErrorEvent
gajim.nec.push_incoming_event(FileRequestErrorEvent(None, gajim.nec.push_incoming_event(FileRequestErrorEvent(None,
conn=self, jid=contact.jid, file_props=file_props, conn=self, jid=contact.jid, file_props=file_props,
error_msg='')) error_msg=''))
sender_jid = unicode(file_props['sender']) sender_jid = unicode(file_props.sender)
if contact.get_full_jid() == sender_jid: if contact.get_full_jid() == sender_jid:
file_props['error'] = -3 file_props.error = -3
self.remove_transfer(file_props) self.remove_transfer(file_props)
def remove_all_transfers(self): def remove_all_transfers(self):
""" """
Stop and remove all active connections from the socks5 pool Stop and remove all active connections from the socks5 pool
""" """
for file_props in self.files_props.values(): for file_props in FilesProp.getAllFileProp():
self.remove_transfer(file_props, remove_from_list=False) self.remove_transfer(file_props, remove_from_list=False)
self.files_props = {}
def remove_transfer(self, file_props, remove_from_list=True): def remove_transfer(self, file_props, remove_from_list=True):
if file_props is None: if file_props is None:
return return
self.disconnect_transfer(file_props) self.disconnect_transfer(file_props)
sid = file_props['sid'] sid = file_props.sid
gajim.socks5queue.remove_file_props(self.name, sid) gajim.socks5queue.remove_file_props(self.name, sid)
if remove_from_list:
if 'sid' in self.files_props:
del(self.files_props['sid'])
def disconnect_transfer(self, file_props): def disconnect_transfer(self, file_props):
if file_props is None: if file_props is None:
return return
if 'hash' in file_props: if file_props.hash_:
gajim.socks5queue.remove_sender(file_props['hash']) gajim.socks5queue.remove_sender(file_props.hash_)
if 'streamhosts' in file_props: if file_props.streamhosts:
for host in file_props['streamhosts']: for host in file_props.streamhosts:
if 'idx' in host and host['idx'] > 0: if 'idx' in host and host['idx'] > 0:
gajim.socks5queue.remove_receiver(host['idx']) gajim.socks5queue.remove_receiver(host['idx'])
gajim.socks5queue.remove_sender(host['idx']) gajim.socks5queue.remove_sender(host['idx'])
if 'direction' in file_props: if file_props.direction:
# it's a IBB # it's a IBB
sid = file_props['sid'] FilesProp.deleteFileProp(file_props)
if sid in self.files_props: del(file_props)
del self.files_props[sid]
def _send_socks5_info(self, file_props): def _send_socks5_info(self, file_props):
""" """
@ -359,28 +351,28 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
""" """
if not self.connection or self.connected < 2: if not self.connection or self.connected < 2:
return return
receiver = file_props['receiver'] receiver = file_props.receiver
sender = file_props['sender'] sender = file_props.sender
sha_str = helpers.get_auth_sha(file_props['sid'], sender, receiver) sha_str = helpers.get_auth_sha(file_props.sid, sender, receiver)
file_props['sha_str'] = sha_str file_props.sha_str = sha_str
port = gajim.config.get('file_transfers_port') port = gajim.config.get('file_transfers_port')
listener = gajim.socks5queue.start_listener(port, sha_str, listener = gajim.socks5queue.start_listener(port, sha_str,
self._result_socks5_sid, file_props) self._result_socks5_sid, file_props)
if not listener: if not listener:
file_props['error'] = -5 file_props.error = -5
from common.connection_handlers_events import FileRequestErrorEvent from common.connection_handlers_events import FileRequestErrorEvent
gajim.nec.push_incoming_event(FileRequestErrorEvent(None, conn=self, gajim.nec.push_incoming_event(FileRequestErrorEvent(None, conn=self,
jid=unicode(receiver), file_props=file_props, error_msg='')) jid=unicode(receiver), file_props=file_props, error_msg=''))
self._connect_error(unicode(receiver), file_props['sid'], self._connect_error(unicode(receiver), file_props.sid,
file_props['sid'], code=406) file_props.sid, code=406)
else: else:
iq = xmpp.Iq(to=unicode(receiver), typ='set') iq = xmpp.Iq(to=unicode(receiver), typ='set')
file_props['request-id'] = 'id_' + file_props['sid'] file_props.request_id = 'id_' + file_props.sid
iq.setID(file_props['request-id']) iq.setID(file_props.request_id)
query = iq.setTag('query', namespace=xmpp.NS_BYTESTREAM) query = iq.setTag('query', namespace=xmpp.NS_BYTESTREAM)
query.setAttr('sid', file_props['sid']) query.setAttr('sid', file_props.sid)
self._add_addiditional_streamhosts_to_query(query, file_props) self._add_addiditional_streamhosts_to_query(query, file_props)
self._add_local_ips_as_streamhosts_to_query(query, file_props) self._add_local_ips_as_streamhosts_to_query(query, file_props)
@ -406,7 +398,7 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
if not addr[4][0] in my_ips and not addr[4][0].startswith('127'): if not addr[4][0] in my_ips and not addr[4][0].startswith('127'):
my_ips.append(addr[4][0]) my_ips.append(addr[4][0])
sender = file_props['sender'] sender = file_props.sender
port = gajim.config.get('file_transfers_port') port = gajim.config.get('file_transfers_port')
self._add_streamhosts_to_query(query, sender, port, my_ips) self._add_streamhosts_to_query(query, sender, port, my_ips)
except socket.gaierror: except socket.gaierror:
@ -416,7 +408,7 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
sec_txt=_('Invalid local address? :-O'))) sec_txt=_('Invalid local address? :-O')))
def _add_addiditional_streamhosts_to_query(self, query, file_props): def _add_addiditional_streamhosts_to_query(self, query, file_props):
sender = file_props['sender'] sender = file_props.sender
port = gajim.config.get('file_transfers_port') port = gajim.config.get('file_transfers_port')
ft_add_hosts_to_send = gajim.config.get('ft_add_hosts_to_send') ft_add_hosts_to_send = gajim.config.get('ft_add_hosts_to_send')
additional_hosts = [] additional_hosts = []
@ -469,12 +461,12 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
log.debug('Got GUPnP-IGD answer: external: %s:%s, internal: %s:%s', log.debug('Got GUPnP-IGD answer: external: %s:%s, internal: %s:%s',
ext_ip, ext_port, local_ip, local_port) ext_ip, ext_port, local_ip, local_port)
if local_port != gajim.config.get('file_transfers_port'): if local_port != gajim.config.get('file_transfers_port'):
sender = file_props['sender'] sender = file_props.sender
receiver = file_props['receiver'] receiver = file_props.receiver
sha_str = helpers.get_auth_sha(file_props['sid'], sender, sha_str = helpers.get_auth_sha(file_props.sid, sender,
receiver) receiver)
listener = gajim.socks5queue.start_listener(local_port, sha_str, listener = gajim.socks5queue.start_listener(local_port, sha_str,
self._result_socks5_sid, file_props['sid']) self._result_socks5_sid, file_props.sid)
if listener: if listener:
self._add_streamhosts_to_query(query, sender, ext_port, self._add_streamhosts_to_query(query, sender, ext_port,
[ext_ip]) [ext_ip])
@ -507,9 +499,9 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
def _add_proxy_streamhosts_to_query(self, query, file_props): def _add_proxy_streamhosts_to_query(self, query, file_props):
proxyhosts = self._get_file_transfer_proxies_from_config(file_props) proxyhosts = self._get_file_transfer_proxies_from_config(file_props)
if proxyhosts: if proxyhosts:
file_props['proxy_receiver'] = unicode(file_props['receiver']) file_props.proxy_receiver = unicode(file_props.receiver)
file_props['proxy_sender'] = unicode(file_props['sender']) file_props.proxy_sender = unicode(file_props.sender)
file_props['proxyhosts'] = proxyhosts file_props.proxyhosts = proxyhosts
for proxyhost in proxyhosts: for proxyhost in proxyhosts:
self._add_streamhosts_to_query(query, proxyhost['jid'], self._add_streamhosts_to_query(query, proxyhost['jid'],
@ -536,9 +528,9 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
continue continue
host_dict = { host_dict = {
'state': 0, 'state': 0,
'target': unicode(file_props['receiver']), 'target': unicode(file_props.receiver),
'id': file_props['sid'], 'id': file_props.sid,
'sid': file_props['sid'], 'sid': file_props.sid,
'initiator': proxy, 'initiator': proxy,
'host': host, 'host': host,
'port': unicode(_port), 'port': unicode(_port),
@ -553,10 +545,8 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
""" """
Store the result of SHA message from auth Store the result of SHA message from auth
""" """
if sid not in self.files_props: file_props = FilesProp.getFilePropBySid(sid)
return file_props.hash_ = hash_id
file_props = self.files_props[sid]
file_props['hash'] = hash_id
return return
def _connect_error(self, to, _id, sid, code=404): def _connect_error(self, to, _id, sid, code=404):
@ -579,10 +569,10 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
err.setData(msg) err.setData(msg)
self.connection.send(iq) self.connection.send(iq)
if code == 404: if code == 404:
file_props = gajim.socks5queue.get_file_props(self.name, sid) file_props = FilesProp.getFileProp(self.name, sid)
if file_props is not None: if file_props is not None:
self.disconnect_transfer(file_props) self.disconnect_transfer(file_props)
file_props['error'] = -3 file_props.error = -3
from common.connection_handlers_events import \ from common.connection_handlers_events import \
FileRequestErrorEvent FileRequestErrorEvent
gajim.nec.push_incoming_event(FileRequestErrorEvent(None, gajim.nec.push_incoming_event(FileRequestErrorEvent(None,
@ -594,14 +584,14 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
""" """
if not self.connection or self.connected < 2: if not self.connection or self.connected < 2:
return return
file_props = self.files_props[proxy['sid']] file_props = FilesProp.getFileProp(self.connection, proxy['sid'])
iq = xmpp.Iq(to=proxy['initiator'], typ='set') iq = xmpp.Iq(to=proxy['initiator'], typ='set')
auth_id = "au_" + proxy['sid'] auth_id = "au_" + proxy['sid']
iq.setID(auth_id) iq.setID(auth_id)
query = iq.setTag('query', namespace=xmpp.NS_BYTESTREAM) query = iq.setTag('query', namespace=xmpp.NS_BYTESTREAM)
query.setAttr('sid', proxy['sid']) query.setAttr('sid', proxy['sid'])
activate = query.setTag('activate') activate = query.setTag('activate')
activate.setData(file_props['proxy_receiver']) activate.setData(file_props.proxy_receiver)
iq.setID(auth_id) iq.setID(auth_id)
self.connection.send(iq) self.connection.send(iq)
@ -613,10 +603,10 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
gajim.proxy65_manager.error_cb(frm, query) gajim.proxy65_manager.error_cb(frm, query)
jid = helpers.get_jid_from_iq(iq_obj) jid = helpers.get_jid_from_iq(iq_obj)
id_ = id_[3:] id_ = id_[3:]
if id_ not in self.files_props: file_props = FilesProp.getFilePropBySid(id_)
if not file_props:
return return
file_props = self.files_props[id_] file_props.error = -4
file_props['error'] = -4
from common.connection_handlers_events import FileRequestErrorEvent from common.connection_handlers_events import FileRequestErrorEvent
gajim.nec.push_incoming_event(FileRequestErrorEvent(None, conn=self, gajim.nec.push_incoming_event(FileRequestErrorEvent(None, conn=self,
jid=jid, file_props=file_props, error_msg='')) jid=jid, file_props=file_props, error_msg=''))
@ -627,7 +617,7 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
id_ = unicode(iq_obj.getAttr('id')) id_ = unicode(iq_obj.getAttr('id'))
query = iq_obj.getTag('query') query = iq_obj.getTag('query')
sid = unicode(query.getAttr('sid')) sid = unicode(query.getAttr('sid'))
file_props = gajim.socks5queue.get_file_props(self.name, sid) file_props = FilesProp.getFileProp(self.name, sid)
streamhosts = [] streamhosts = []
for item in query.getChildren(): for item in query.getChildren():
if item.getName() == 'streamhost': if item.getName() == 'streamhost':
@ -647,28 +637,24 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
if 'port' not in host_dict: if 'port' not in host_dict:
continue continue
streamhosts.append(host_dict) streamhosts.append(host_dict)
if file_props is None: file_props = FilesProp.getFilePropBySid(sid)
if sid in self.files_props: if file_props is not None:
file_props = self.files_props[sid] file_props.fast = streamhosts
file_props['fast'] = streamhosts if file_props.type_ == 's': # FIXME: remove fast xmlns
if file_props['type'] == 's': # FIXME: remove fast xmlns # only psi do this
# only psi do this if file_props.streamhosts:
if 'streamhosts' in file_props: file_props.streamhosts.extend(streamhosts)
file_props['streamhosts'].extend(streamhosts) else:
else: file_props.streamhosts = streamhosts
file_props['streamhosts'] = streamhosts gajim.socks5queue.connect_to_hosts(self.name, sid,
if not gajim.socks5queue.get_file_props(self.name, sid): self.send_success_connect_reply, None)
gajim.socks5queue.add_file_props(self.name, file_props) raise xmpp.NodeProcessed
gajim.socks5queue.connect_to_hosts(self.name, sid, else:
self.send_success_connect_reply, None)
raise xmpp.NodeProcessed
if file_props is None:
log.warn('Gajim got streamhosts for unknown transfer. Ignoring it.') log.warn('Gajim got streamhosts for unknown transfer. Ignoring it.')
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
file_props['streamhosts'] = streamhosts file_props.streamhosts = streamhosts
if file_props['type'] == 'r': if file_props.type_ == 'r':
gajim.socks5queue.connect_to_hosts(self.name, sid, gajim.socks5queue.connect_to_hosts(self.name, sid,
self.send_success_connect_reply, self._connect_error) self.send_success_connect_reply, self._connect_error)
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
@ -681,13 +667,12 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
return return
frm = self._ft_get_from(iq_obj) frm = self._ft_get_from(iq_obj)
id_ = real_id[3:] id_ = real_id[3:]
if id_ in self.files_props: file_props = FilesProp.getFilePropBySid(id_)
file_props = self.files_props[id_] if file_props.streamhost_used:
if file_props['streamhost-used']: for host in file_props.proxyhosts:
for host in file_props['proxyhosts']: if host['initiator'] == frm and 'idx' in host:
if host['initiator'] == frm and 'idx' in host: gajim.socks5queue.activate_proxy(host['idx'])
gajim.socks5queue.activate_proxy(host['idx']) raise xmpp.NodeProcessed
raise xmpp.NodeProcessed
def _bytestreamResultCB(self, con, iq_obj): def _bytestreamResultCB(self, con, iq_obj):
frm = self._ft_get_from(iq_obj) frm = self._ft_get_from(iq_obj)
@ -700,67 +685,62 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
except Exception: # this bytestream result is not what we need except Exception: # this bytestream result is not what we need
pass pass
id_ = real_id[3:] id_ = real_id[3:]
if id_ in self.files_props: file_props = FilesProp.getFileProp(con.name, id_)
file_props = self.files_props[id_] if file_props is None:
else:
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
if streamhost is None: if streamhost is None:
# proxy approves the activate query # proxy approves the activate query
if real_id.startswith('au_'): if real_id.startswith('au_'):
if 'streamhost-used' not in file_props or \ if file_props.streamhost_used is False:
file_props['streamhost-used'] is False:
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
if 'proxyhosts' not in file_props: if not file_props.proxyhosts:
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
for host in file_props['proxyhosts']: for host in file_props.proxyhosts:
if host['initiator'] == frm and \ if host['initiator'] == frm and \
unicode(query.getAttr('sid')) == file_props['sid']: unicode(query.getAttr('sid')) == file_props.sid:
gajim.socks5queue.activate_proxy(host['idx']) gajim.socks5queue.activate_proxy(host['idx'])
break break
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
jid = self._ft_get_streamhost_jid_attr(streamhost) jid = self._ft_get_streamhost_jid_attr(streamhost)
if 'streamhost-used' in file_props and \ if file_props.streamhost_used is True:
file_props['streamhost-used'] is True:
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
if real_id.startswith('au_'): if real_id.startswith('au_'):
if 'stopped' in file_props and file_props['stopped']: if file_props.stopped:
self.remove_transfer(file_props) self.remove_transfer(file_props)
else: else:
gajim.socks5queue.send_file(file_props, self.name) gajim.socks5queue.send_file(file_props, self.name)
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
proxy = None proxy = None
if 'proxyhosts' in file_props: if file_props.proxyhosts:
for proxyhost in file_props['proxyhosts']: for proxyhost in file_props.proxyhosts:
if proxyhost['jid'] == jid: if proxyhost['jid'] == jid:
proxy = proxyhost proxy = proxyhost
if 'stopped' in file_props and file_props['stopped']: if file_props.stopped:
self.remove_transfer(file_props) self.remove_transfer(file_props)
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
if proxy is not None: if proxy is not None:
file_props['streamhost-used'] = True file_props.streamhost_used = True
if 'streamhosts' not in file_props: file_props.streamhosts.append(proxy)
file_props['streamhosts'] = [] file_props.is_a_proxy = True
file_props['streamhosts'].append(proxy)
file_props['is_a_proxy'] = True
receiver = Socks5Receiver(gajim.idlequeue, proxy, receiver = Socks5Receiver(gajim.idlequeue, proxy,
file_props['sid'], file_props) file_props.sid, file_props)
gajim.socks5queue.add_receiver(self.name, receiver) gajim.socks5queue.add_receiver(self.name, receiver)
proxy['idx'] = receiver.queue_idx proxy['idx'] = receiver.queue_idx
gajim.socks5queue.on_success = self._proxy_auth_ok gajim.socks5queue.on_success = self._proxy_auth_ok
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
else: else:
if 'stopped' in file_props and file_props['stopped']: if file_props.stopped:
self.remove_transfer(file_props) self.remove_transfer(file_props)
else: else:
gajim.socks5queue.send_file(file_props, self.name, 'client') gajim.socks5queue.send_file(file_props, self.name, 'client')
if 'fast' in file_props: if file_props.fast:
fasts = file_props['fast'] fasts = file_props.fast
if len(fasts) > 0: if len(fasts) > 0:
self._connect_error(frm, fasts[0]['id'], file_props['sid'], self._connect_error(frm, fasts[0]['id'], file_props.sid,
code=406) code=406)
raise xmpp.NodeProcessed raise xmpp.NodeProcessed
@ -800,33 +780,33 @@ class ConnectionIBBytestream(ConnectionBytestream):
blocksize = stanza.getTagAttr('open', 'block-size') blocksize = stanza.getTagAttr('open', 'block-size')
log.debug('StreamOpenHandler called sid->%s blocksize->%s' % (sid, log.debug('StreamOpenHandler called sid->%s blocksize->%s' % (sid,
blocksize)) blocksize))
file_props = FilesProp.getFileProp(self.name, sid)
try: try:
blocksize = int(blocksize) blocksize = int(blocksize)
except: except:
err = xmpp.ERR_BAD_REQUEST err = xmpp.ERR_BAD_REQUEST
if not sid or not blocksize: if not sid or not blocksize:
err = xmpp.ERR_BAD_REQUEST err = xmpp.ERR_BAD_REQUEST
elif not gajim.socks5queue.get_file_props(self.name, sid): elif not file_props:
err = xmpp.ERR_UNEXPECTED_REQUEST err = xmpp.ERR_UNEXPECTED_REQUEST
if err: if err:
rep = xmpp.Error(stanza, err) rep = xmpp.Error(stanza, err)
else: else:
file_props = gajim.socks5queue.get_file_props(self.name, sid)
log.debug("Opening stream: id %s, block-size %s" % (sid, blocksize)) log.debug("Opening stream: id %s, block-size %s" % (sid, blocksize))
rep = xmpp.Protocol('iq', stanza.getFrom(), 'result', rep = xmpp.Protocol('iq', stanza.getFrom(), 'result',
stanza.getTo(), {'id': stanza.getID()}) stanza.getTo(), {'id': stanza.getID()})
file_props['block-size'] = blocksize file_props.block_size = blocksize
file_props['seq'] = 0 file_props.seq = 0
file_props['received-len'] = 0 file_props.received_len = 0
file_props['last-time'] = time.time() file_props.last_time = time.time()
file_props['error'] = 0 file_props.error = 0
file_props['paused'] = False file_props.paused = False
file_props['connected'] = True file_props.connected = True
file_props['completed'] = False file_props.completed = False
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, 'w')
conn.send(rep) conn.send(rep)
def OpenStream(self, sid, to, fp, blocksize=4096): def OpenStream(self, sid, to, fp, blocksize=4096):
@ -837,62 +817,59 @@ class ConnectionIBBytestream(ConnectionBytestream):
Take into account that recommended stanza size is 4k and IBB uses Take into account that recommended stanza size is 4k and IBB uses
base64 encoding that increases size of data by 1/3. base64 encoding that increases size of data by 1/3.
""" """
if sid not in self.files_props.keys():
return
if not xmpp.JID(to).getResource(): if not xmpp.JID(to).getResource():
return return
self.files_props[sid]['direction'] = '|>' + to file_props = FilesProp.getFilePropBySid(sid)
self.files_props[sid]['block-size'] = blocksize file_props.direction = '|>' + to
self.files_props[sid]['fp'] = fp file_props.block_size = blocksize
self.files_props[sid]['seq'] = 0 file_props.fp = fp
self.files_props[sid]['error'] = 0 file_props.seq = 0
self.files_props[sid]['paused'] = False file_props.error = 0
self.files_props[sid]['received-len'] = 0 file_props.paused = False
self.files_props[sid]['last-time'] = time.time() file_props.received_len = 0
self.files_props[sid]['connected'] = True file_props.last_time = time.time()
self.files_props[sid]['completed'] = False file_props.connected = True
self.files_props[sid]['disconnect_cb'] = None file_props.completed = False
self.files_props[sid]['continue_cb'] = None file_props.disconnect_cb = None
file_props.continue_cb = None
syn = xmpp.Protocol('iq', to, 'set', payload=[xmpp.Node(xmpp.NS_IBB + \ syn = xmpp.Protocol('iq', to, 'set', payload=[xmpp.Node(xmpp.NS_IBB + \
' open', {'sid': sid, 'block-size': blocksize, 'stanza': 'iq'})]) ' open', {'sid': sid, 'block-size': blocksize, 'stanza': 'iq'})])
self.connection.send(syn) self.connection.send(syn)
self.files_props[sid]['syn_id'] = syn.getID() file_props.syn_id = syn.getID()
return self.files_props[sid] return file_props
def SendHandler(self): def SendHandler(self):
""" """
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')
if not self.files_props: #pdb.set_trace()
return for file_props in FilesProp.getAllFileProp():
for file_props in self.files_props.values(): if not file_props.direction:
if 'direction' not in file_props:
# it's socks5 bytestream # it's socks5 bytestream
continue continue
sid = file_props['sid'] sid = file_props.sid
if file_props['direction'][:2] == '|>': if file_props.direction[:2] == '|>':
# We waitthat other part accept stream # We waitthat other part accept stream
continue continue
if file_props['direction'][0] == '>': if file_props.direction[0] == '>':
if 'paused' in file_props and file_props['paused']: if file_props.paused:
continue continue
chunk = file_props['fp'].read(file_props['block-size']) chunk = file_props.fp.read(file_props.block_size)
if chunk: if chunk:
datanode = xmpp.Node(xmpp.NS_IBB + ' data', {'sid': sid, datanode = xmpp.Node(xmpp.NS_IBB + ' data', {'sid': sid,
'seq': file_props['seq']}, base64.encodestring(chunk)) 'seq': file_props.seq}, base64.encodestring(chunk))
file_props['seq'] += 1 file_props.seq += 1
file_props['started'] = True file_props.started = True
if file_props['seq'] == 65536: if file_props.seq == 65536:
file_props['seq'] = 0 file_props.seq = 0
self.last_sent_ibb_id = self.connection.send(xmpp.Protocol( self.last_sent_ibb_id = self.connection.send(xmpp.Protocol(
name='iq', to=file_props['direction'][1:], typ='set', name='iq', to=file_props.direction[1:], typ='set',
payload=[datanode])) payload=[datanode]))
current_time = time.time() current_time = time.time()
file_props['elapsed-time'] += current_time - file_props[ file_props.elapsed_time += current_time - file_props.last_time
'last-time'] file_props.last_time = current_time
file_props['last-time'] = current_time file_props.received_len += len(chunk)
file_props['received-len'] += len(chunk)
gajim.socks5queue.progress_transfer_cb(self.name, gajim.socks5queue.progress_transfer_cb(self.name,
file_props) file_props)
else: else:
@ -900,11 +877,12 @@ class ConnectionIBBytestream(ConnectionBytestream):
# notify the local user about sucessfull send # notify the local user about sucessfull send
# delete the local stream # delete the local stream
self.connection.send(xmpp.Protocol('iq', self.connection.send(xmpp.Protocol('iq',
file_props['direction'][1:], 'set', file_props.direction[1:], 'set',
payload=[xmpp.Node(xmpp.NS_IBB + ' close', payload=[xmpp.Node(xmpp.NS_IBB + ' close',
{'sid':sid})])) {'sid':sid})]))
file_props['completed'] = True file_props.completed = True
del self.files_props[sid] FilesProp.deleteFileProp(file_props)
del(file_props)
def IBBMessageHandler(self, conn, stanza): def IBBMessageHandler(self, conn, stanza):
""" """
@ -922,28 +900,27 @@ class ConnectionIBBytestream(ConnectionBytestream):
seq = '' seq = ''
data = '' data = ''
err = None err = None
if not gajim.socks5queue.get_file_props(self.name, sid): file_props = FilesProp.getFileProp(self.name, sid)
if file_props is None:
err = xmpp.ERR_ITEM_NOT_FOUND err = xmpp.ERR_ITEM_NOT_FOUND
else: else:
file_props = gajim.socks5queue.get_file_props(self.name, sid)
if not data: if not data:
err = xmpp.ERR_BAD_REQUEST err = xmpp.ERR_BAD_REQUEST
elif seq <> file_props['seq']: elif seq <> file_props.seq:
err = xmpp.ERR_UNEXPECTED_REQUEST err = xmpp.ERR_UNEXPECTED_REQUEST
else: else:
log.debug('Successfull receive sid->%s %s+%s bytes' % (sid, log.debug('Successfull receive sid->%s %s+%s bytes' % (sid,
file_props['fp'].tell(), len(data))) file_props.fp.tell(), len(data)))
file_props['seq'] += 1 file_props.seq += 1
file_props['started'] = True file_props.started = True
file_props['fp'].write(data) file_props.fp.write(data)
current_time = time.time() current_time = time.time()
file_props['elapsed-time'] += current_time - file_props[ file_props.elapsed_time += current_time - file_props.last_time
'last-time'] file_props.last_time = current_time
file_props['last-time'] = current_time file_props.received_len += len(data)
file_props['received-len'] += len(data)
gajim.socks5queue.progress_transfer_cb(self.name, file_props) gajim.socks5queue.progress_transfer_cb(self.name, file_props)
if file_props['received-len'] >= file_props['size']: if file_props.received_len >= file_props.size:
file_props['completed'] = True file_props.completed = True
if err: if err:
log.debug('Error on receive: %s' % err) log.debug('Error on receive: %s' % err)
conn.send(xmpp.Error(xmpp.Iq(to=stanza.getFrom(), conn.send(xmpp.Error(xmpp.Iq(to=stanza.getFrom(),
@ -960,19 +937,16 @@ class ConnectionIBBytestream(ConnectionBytestream):
sid = stanza.getTagAttr('close', 'sid') sid = stanza.getTagAttr('close', 'sid')
log.debug('StreamCloseHandler called sid->%s' % sid) log.debug('StreamCloseHandler called sid->%s' % sid)
# look in sending files # look in sending files
if sid in self.files_props.keys(): file_props = FilesProp.getFileProp(self.name, sid)
if file_props:
reply = stanza.buildReply('result') reply = stanza.buildReply('result')
reply.delChild('close') reply.delChild('close')
conn.send(reply) conn.send(reply)
gajim.socks5queue.complete_transfer_cb(self.name, self.files_props[sid]) # look in receiving files
del self.files_props[sid]
# look in receiving files
elif gajim.socks5queue.get_file_props(self.name, sid):
file_props = gajim.socks5queue.get_file_props(self.name, sid)
reply = stanza.buildReply('result') reply = stanza.buildReply('result')
reply.delChild('close') reply.delChild('close')
conn.send(reply) conn.send(reply)
file_props['fp'].close() file_props.fp.close()
gajim.socks5queue.complete_transfer_cb(self.name, file_props) gajim.socks5queue.complete_transfer_cb(self.name, file_props)
gajim.socks5queue.remove_file_props(self.name, sid) gajim.socks5queue.remove_file_props(self.name, sid)
else: else:
@ -987,21 +961,21 @@ class ConnectionIBBytestream(ConnectionBytestream):
""" """
syn_id = stanza.getID() syn_id = stanza.getID()
log.debug('IBBAllIqHandler called syn_id->%s' % syn_id) log.debug('IBBAllIqHandler called syn_id->%s' % syn_id)
for sid in self.files_props.keys(): for file_props in FilesProp.getAllFileProp():
file_props = self.files_props[sid] if not file_props.direction:
if not 'direction' in file_props:
# It's socks5 bytestream # It's socks5 bytestream
continue continue
if file_props['syn_id'] == syn_id: if file_props.syn_id == syn_id:
if stanza.getType() == 'error': if stanza.getType() == 'error':
if file_props['direction'][0] == '<': if file_props.direction[0] == '<':
conn.Event('IBB', 'ERROR ON RECEIVE', file_props) conn.Event('IBB', 'ERROR ON RECEIVE', file_props)
else: else:
conn.Event('IBB', 'ERROR ON SEND', file_props) conn.Event('IBB', 'ERROR ON SEND', file_props)
del self.files_props[sid] FilesProp.deleteFileProp(file_props)
del(file_props)
elif stanza.getType() == 'result': elif stanza.getType() == 'result':
if file_props['direction'][0] == '|': if file_props.direction[0] == '|':
file_props['direction'] = file_props['direction'][1:] file_props.direction = file_props.direction[1:]
self.SendHandler() self.SendHandler()
else: else:
conn.send(xmpp.Error(stanza, conn.send(xmpp.Error(stanza,
@ -1026,7 +1000,7 @@ class ConnectionSocks5BytestreamZeroconf(ConnectionSocks5Bytestream):
return gajim.get_jid_from_account(self.name) return gajim.get_jid_from_account(self.name)
def _ft_get_receiver_jid(self, file_props): def _ft_get_receiver_jid(self, file_props):
return file_props['receiver'].jid return file_props.receiver.jid
def _ft_get_streamhost_jid_attr(self, streamhost): def _ft_get_streamhost_jid_attr(self, streamhost):
return streamhost.getAttr('jid') return streamhost.getAttr('jid')

View File

@ -31,6 +31,7 @@ from common import gajim
from common import helpers from common import helpers
from socks5 import Socks5 from socks5 import Socks5
from common.xmpp.idlequeue import IdleObject from common.xmpp.idlequeue import IdleObject
from common.file_props import FilesProp
S_INITIAL = 0 S_INITIAL = 0
S_STARTED = 1 S_STARTED = 1
@ -248,9 +249,10 @@ class HostTester(Socks5, IdleObject):
self.on_success = on_success self.on_success = on_success
self.on_failure = on_failure self.on_failure = on_failure
self._sock = None self._sock = None
self.file_props = {'is_a_proxy': True, self.file_props = FilesProp.getNewFileProp(jid, sid)
'proxy_sender': sender_jid, self.file_props.is_a_proxy = True
'proxy_receiver': 'test@gajim.org/test2'} self.file_props.proxy_sender = sender_jid
self.file_props.proxy_receiver = 'test@gajim.org/test2'
Socks5.__init__(self, gajim.idlequeue, host, port, None, None, None) Socks5.__init__(self, gajim.idlequeue, host, port, None, None, None)
self.sid = sid self.sid = sid
@ -367,9 +369,10 @@ class ReceiverTester(Socks5, IdleObject):
self.on_success = on_success self.on_success = on_success
self.on_failure = on_failure self.on_failure = on_failure
self._sock = None self._sock = None
self.file_props = {'is_a_proxy': True, self.file_props = FilesProp.getNewFileProp(jid, sid)
'proxy_sender': sender_jid, self.file_props.is_a_proxy = True
'proxy_receiver': 'test@gajim.org/test2'} self.file_props.proxy_sender = sender_jid
self.file_props.proxy_receiver = 'test@gajim.org/test2'
Socks5.__init__(self, gajim.idlequeue, host, port, None, None, None) Socks5.__init__(self, gajim.idlequeue, host, port, None, None, None)
self.sid = sid self.sid = sid

View File

@ -34,7 +34,7 @@ from errno import EISCONN
from errno import EINPROGRESS from errno import EINPROGRESS
from errno import EAFNOSUPPORT from errno import EAFNOSUPPORT
from xmpp.idlequeue import IdleObject from xmpp.idlequeue import IdleObject
from file_props import FilesProp
import jingle_xtls import jingle_xtls
if jingle_xtls.PYOPENSSL_PRESENT: if jingle_xtls.PYOPENSSL_PRESENT:
@ -69,7 +69,6 @@ class SocksQueue:
progress_transfer_cb=None, error_cb=None): progress_transfer_cb=None, error_cb=None):
self.connected = 0 self.connected = 0
self.readers = {} self.readers = {}
self.files_props = {}
self.senders = {} self.senders = {}
self.idx = 1 self.idx = 1
self.listener = None self.listener = None
@ -83,58 +82,54 @@ class SocksQueue:
self.on_success = {} # {id: cb} self.on_success = {} # {id: cb}
self.on_failure = {} # {id: cb} self.on_failure = {} # {id: cb}
def start_listener(self, port, sha_str, sha_handler, fp, fingerprint=None, def start_listener(self, port, sha_str, sha_handler, file_props, fingerprint=None,
type='sender'): type='sender'):
""" """
Start waiting for incomming connections on (host, port) and do a socks5 Start waiting for incomming connections on (host, port) and do a socks5
authentication using sid for generated SHA authentication using sid for generated SHA
""" """
sid = fp['sid'] sid = file_props.sid
self.type = type # It says whether we are sending or receiving self.type = type # It says whether we are sending or receiving
self.sha_handlers[sha_str] = (sha_handler, sid) self.sha_handlers[sha_str] = (sha_handler, sid)
if self.listener is None or self.listener.connections == []: if self.listener is None or self.listener.connections == []:
self.listener = Socks5Listener(self.idlequeue, port, fp, self.listener = Socks5Listener(self.idlequeue, port, file_props,
fingerprint=fingerprint) fingerprint=fingerprint)
self.listener.queue = self self.listener.queue = self
self.listener.bind() self.listener.bind()
else: else:
# There is already a listener, we update the file's information # There is already a listener, we update the file's information
# on the new connection. # on the new connection.
self.listener.file_props = fp self.listener.file_props = file_props
self.connected += 1 self.connected += 1
return self.listener return self.listener
def send_success_reply(self, file_props, streamhost): def send_success_reply(self, file_props, streamhost):
if 'streamhost-used' in file_props and \ if file_props.streamhost_used == True:
file_props['streamhost-used'] is True: for proxy in file_props.proxyhosts:
if 'proxyhosts' in file_props: if proxy['host'] == streamhost['host']:
for proxy in file_props['proxyhosts']: self.on_success[file_props.sid](proxy)
if proxy['host'] == streamhost['host']: return 1
self.on_success[file_props['sid']](proxy)
return 1
return 0 return 0
if 'streamhosts' in file_props: for host in file_props.streamhosts:
for host in file_props['streamhosts']: if streamhost['state'] == 1:
if streamhost['state'] == 1: return 0
return 0 streamhost['state'] = 1
streamhost['state'] = 1 self.on_success[file_props.sid](streamhost)
self.on_success[file_props['sid']](streamhost) return 1
return 1
return 0
def connect_to_hosts(self, account, sid, on_success=None, on_failure=None, def connect_to_hosts(self, account, sid, on_success=None, on_failure=None,
fingerprint=None, receiving=True): fingerprint=None, receiving=True):
self.on_success[sid] = on_success self.on_success[sid] = on_success
self.on_failure[sid] = on_failure self.on_failure[sid] = on_failure
file_props = self.files_props[account][sid] file_props = FilesProp.getFileProp(account, sid)
file_props['failure_cb'] = on_failure file_props.failure_cb = on_failure
if not file_props['streamhosts']: if not file_props.streamhosts:
on_failure(file_props['sid']) on_failure(file_props.sid)
# add streamhosts to the queue # add streamhosts to the queue
for streamhost in file_props['streamhosts']: for streamhost in file_props.streamhosts:
if 'type' in streamhost and streamhost['type'] == 'proxy': if 'type' in streamhost and streamhost['type'] == 'proxy':
fp = None fp = None
else: else:
@ -145,16 +140,16 @@ class SocksQueue:
file_props, fingerprint=fp) file_props, fingerprint=fp)
self.add_sockobj(account, socks5obj) self.add_sockobj(account, socks5obj)
else: else:
if 'sha_str' in file_props: if file_props.sha_str:
idx = file_props['sha_str'] idx = file_props.sha_str
else: else:
idx = self.idx idx = self.idx
self.idx = self.idx + 1 self.idx = self.idx + 1
self.type = 'sender' self.type = 'sender'
if 'type' in streamhost and streamhost['type'] == 'proxy': if 'type' in streamhost and streamhost['type'] == 'proxy':
file_props['is_a_proxy'] = True file_props.is_a_proxy = True
file_props['proxy_sender'] = streamhost['target'] file_props.proxy_sender = streamhost['target']
file_props['proxy_receiver'] = streamhost['initiator'] file_props.proxy_receiver = streamhost['initiator']
socks5obj = Socks5SenderClient(self.idlequeue, idx, socks5obj = Socks5SenderClient(self.idlequeue, idx,
self, _sock=None,host=str(streamhost['host']), self, _sock=None,host=str(streamhost['host']),
port=int(streamhost['port']),fingerprint=fp, port=int(streamhost['port']),fingerprint=fp,
@ -169,7 +164,7 @@ class SocksQueue:
Called when there is a host connected to one of the senders's Called when there is a host connected to one of the senders's
streamhosts. Stop other attempts for connections streamhosts. Stop other attempts for connections
""" """
for host in file_props['streamhosts']: for host in file_props.streamhosts:
if host != streamhost and 'idx' in host: if host != streamhost and 'idx' in host:
if host['state'] == 1: if host['state'] == 1:
# remove current # remove current
@ -200,14 +195,14 @@ class SocksQueue:
streamhost['state'] = -1 streamhost['state'] = -1
# boolean, indicates that there are hosts, which are not tested yet # boolean, indicates that there are hosts, which are not tested yet
unused_hosts = False unused_hosts = False
for host in file_props['streamhosts']: for host in file_props.streamhosts:
if 'idx' in host: if 'idx' in host:
if host['state'] >= 0: if host['state'] >= 0:
return return
elif host['state'] == -2: elif host['state'] == -2:
unused_hosts = True unused_hosts = True
if unused_hosts: if unused_hosts:
for host in file_props['streamhosts']: for host in file_props.streamhosts:
if host['state'] == -2: if host['state'] == -2:
host['state'] = 0 host['state'] = 0
# FIXME: make the sender reconnect also # FIXME: make the sender reconnect also
@ -217,13 +212,13 @@ class SocksQueue:
host['idx'] = client.queue_idx host['idx'] = client.queue_idx
# we still have chances to connect # we still have chances to connect
return return
if 'received-len' not in file_props or file_props['received-len'] == 0: if file_props.received_len == 0:
# there are no other streamhosts and transfer hasn't started # there are no other streamhosts and transfer hasn't started
self._connection_refused(streamhost, file_props, client.queue_idx) self._connection_refused(streamhost, file_props, client.queue_idx)
else: else:
# transfer stopped, it is most likely stopped from sender # transfer stopped, it is most likely stopped from sender
client.disconnect() client.disconnect()
file_props['error'] = -1 file_props.error = -1
self.process_result(-1, client) self.process_result(-1, client)
def _connection_refused(self, streamhost, file_props, idx): def _connection_refused(self, streamhost, file_props, idx):
@ -235,15 +230,14 @@ class SocksQueue:
streamhost['state'] = -1 streamhost['state'] = -1
# FIXME: should only the receiver be remove? what if we are sending? # FIXME: should only the receiver be remove? what if we are sending?
self.remove_receiver(idx, False) self.remove_receiver(idx, False)
if 'streamhosts' in file_props: for host in file_props.streamhosts:
for host in file_props['streamhosts']: if host['state'] != -1:
if host['state'] != -1: return
return
self.readers = {} self.readers = {}
# failure_cb exists - this means that it has never been called # failure_cb exists - this means that it has never been called
if 'failure_cb' in file_props and file_props['failure_cb']: if file_props.failure_cb:
file_props['failure_cb'](file_props['sid']) file_props.failure_cb(file_props.sid)
del(file_props['failure_cb']) file_props.failure_cb = None
def add_sockobj(self, account, sockobj, type='receiver'): def add_sockobj(self, account, sockobj, type='receiver'):
""" """
@ -266,11 +260,11 @@ class SocksQueue:
return 1 return 1
return None return None
def _add(self, sockobj, sockobjects, fp, hash): def _add(self, sockobj, sockobjects, file_props, hash_):
''' '''
Adds the sockobj to the current list of sockobjects Adds the sockobj to the current list of sockobjects
''' '''
keys = (fp['sid'], fp['name'], hash) keys = (file_props.sid, file_props.name, hash_)
sockobjects[keys] = sockobj sockobjects[keys] = sockobj
def result_sha(self, sha_str, idx): def result_sha(self, sha_str, idx):
@ -284,21 +278,21 @@ class SocksQueue:
for key in self.readers.keys(): for key in self.readers.keys():
if idx in key: if idx in key:
reader = self.readers[key] reader = self.readers[key]
if reader.file_props['type'] != 's': if reader.file_props.type_ != 's':
return return
if reader.state != 5: if reader.state != 5:
return return
reader.state = 6 reader.state = 6
if reader.connected: if reader.connected:
reader.file_props['error'] = 0 reader.file_props.error = 0
reader.file_props['disconnect_cb'] = reader.disconnect reader.file_props.disconnect_cb = reader.disconnect
reader.file_props['started'] = True reader.file_props.started = True
reader.file_props['completed'] = False reader.file_props.completed = False
reader.file_props['paused'] = False reader.file_props.paused = False
reader.file_props['stalled'] = False reader.file_props.stalled = False
reader.file_props['elapsed-time'] = 0 reader.file_props.elapsed_time = 0
reader.file_props['last-time'] = self.idlequeue.current_time() reader.file_props.last_time = self.idlequeue.current_time()
reader.file_props['received-len'] = 0 reader.file_props.received_len = 0
reader.pauses = 0 reader.pauses = 0
# start sending file to proxy # start sending file to proxy
self.idlequeue.set_read_timeout(reader.fd, STALLED_TIMEOUT) self.idlequeue.set_read_timeout(reader.fd, STALLED_TIMEOUT)
@ -314,53 +308,34 @@ class SocksQueue:
# Maybe it is my machine. Without this there is a KeyError # Maybe it is my machine. Without this there is a KeyError
# traceback. # traceback.
return return
if file_props['name'] in key and file_props['sid'] in key \ if file_props.name in key and file_props.sid in key \
and self.senders[key].mode == mode: and self.senders[key].mode == mode:
log.info("socks5: sending file") log.info("socks5: sending file")
sender = self.senders[key] sender = self.senders[key]
file_props['streamhost-used'] = True file_props.streamhost_used = True
sender.account = account sender.account = account
sender.file_props = file_props sender.file_props = file_props
result = sender.send_file() result = sender.send_file()
self.process_result(result, sender) self.process_result(result, sender)
def add_file_props(self, account, file_props):
"""
File_prop to the dict of current file_props. It is identified by account
name and sid
"""
if file_props is None or ('sid' in file_props) is False:
return
_id = file_props['sid']
if account not in self.files_props:
self.files_props[account] = {}
self.files_props[account][_id] = file_props
def remove_file_props(self, account, sid): def remove_file_props(self, account, sid):
if account in self.files_props: fp = FilesProp.getFileProp(account, sid)
fl_props = self.files_props[account] if not fp:
if sid in fl_props: log.warning('trying to remove a file props that doesnt exist ' +
if sid in self.on_success: 'from account ' + str(account) + ' and sid ' + str(sid))
del self.on_success[sid] return
if sid in self.on_failure: if sid in self.on_success:
del self.on_failure[sid] del self.on_success[fp.sid]
del(fl_props[sid]) if sid in self.on_failure:
del self.on_failure[fp.sid]
if len(self.files_props) == 0: FilesProp.deleteFileProp(fp)
if len(FilesProp.getFilePropByAccount(account)) == 0:
self.connected = 0 self.connected = 0
def get_file_props(self, account, sid):
"""
Get fil_prop by account name and session id
"""
if account in self.files_props:
fl_props = self.files_props[account]
if sid in fl_props:
return fl_props[sid]
return None
def isHashInSockObjs(self, sockobjs, hash): def isHashInSockObjs(self, sockobjs, hash):
''' '''
It tells wether there is a particular hash in sockobjs or not It tells wether there is a particular hash in sockobjs or not
@ -413,8 +388,8 @@ class SocksQueue:
return return
if result in (0, -1) and self.complete_transfer_cb is not None: if result in (0, -1) and self.complete_transfer_cb is not None:
account = actor.account account = actor.account
if account is None and 'tt_account' in actor.file_props: if account is None and actor.file_props.tt_account:
account = actor.file_props['tt_account'] account = actor.file_props.tt_account
self.complete_transfer_cb(account, actor.file_props) self.complete_transfer_cb(account, actor.file_props)
elif self.progress_transfer_cb is not None: elif self.progress_transfer_cb is not None:
self.progress_transfer_cb(actor.account, actor.file_props) self.progress_transfer_cb(actor.account, actor.file_props)
@ -553,9 +528,9 @@ class Socks5:
self._recv=self._sock.recv self._recv=self._sock.recv
self.buff = '' self.buff = ''
self.connected = True self.connected = True
self.file_props['connected'] = True self.file_props.connected = True
self.file_props['disconnect_cb'] = self.disconnect self.file_props.disconnect_cb = self.disconnect
self.file_props['paused'] = False self.file_props.paused = False
self.state = 1 # connected self.state = 1 # connected
# stop all others connections to sender's streamhosts # stop all others connections to sender's streamhosts
@ -567,11 +542,11 @@ class Socks5:
self.idlequeue.remove_timeout(self.fd) self.idlequeue.remove_timeout(self.fd)
if self.state > 5: if self.state > 5:
# no activity for foo seconds # no activity for foo seconds
if self.file_props['stalled'] == False: if self.file_props.stalled == False:
self.file_props['stalled'] = True self.file_props.stalled = True
self.queue.process_result(-1, self) self.queue.process_result(-1, self)
if 'received-len' not in self.file_props: if not self.file_props.received_len:
self.file_props['received-len'] = 0 self.file_props.received_len = 0
if SEND_TIMEOUT > 0: if SEND_TIMEOUT > 0:
self.idlequeue.set_read_timeout(self.fd, SEND_TIMEOUT) self.idlequeue.set_read_timeout(self.fd, SEND_TIMEOUT)
else: else:
@ -585,11 +560,11 @@ class Socks5:
def open_file_for_reading(self): def open_file_for_reading(self):
if self.file is None: if self.file is None:
try: try:
self.file = open(self.file_props['file-name'], 'rb') self.file = open(self.file_props.file_name, 'rb')
if 'offset' in self.file_props and self.file_props['offset']: if self.file_props.offset:
self.size = self.file_props['offset'] self.size = self.file_props.offset
self.file.seek(self.size) self.file.seek(self.size)
self.file_props['received-len'] = self.size self.file_props.received_len = self.size
except IOError, e: except IOError, e:
self.close_file() self.close_file()
raise IOError, e raise IOError, e
@ -608,24 +583,24 @@ class Socks5:
Test if file is already open and return its fd, or just open the file and Test if file is already open and return its fd, or just open the file and
return the fd return the fd
""" """
if 'fd' in self.file_props: if self.file_props.fd:
fd = self.file_props['fd'] fd = self.file_props.fd
else: else:
offset = 0 offset = 0
opt = 'wb' opt = 'wb'
if 'offset' in self.file_props and self.file_props['offset']: if self.file_props.offset:
offset = self.file_props['offset'] offset = self.file_props.offset
opt = 'ab' opt = 'ab'
fd = open(self.file_props['file-name'], opt) fd = open(self.file_props.file_name, opt)
self.file_props['fd'] = fd self.file_props.fd = fd
self.file_props['elapsed-time'] = 0 self.file_props.elapsed_time = 0
self.file_props['last-time'] = self.idlequeue.current_time() self.file_props.last_time = self.idlequeue.current_time()
self.file_props['received-len'] = offset self.file_props.received_len = offset
return fd return fd
def rem_fd(self, fd): def rem_fd(self, fd):
if 'fd' in self.file_props: if self.file_props.fd:
del(self.file_props['fd']) self.file_props.fd = None
try: try:
fd.close() fd.close()
except Exception: except Exception:
@ -674,7 +649,7 @@ class Socks5:
except IOError, e: except IOError, e:
self.state = 8 # end connection self.state = 8 # end connection
self.disconnect() self.disconnect()
self.file_props['error'] = -7 # unable to read from file self.file_props.error = -7 # unable to read from file
return -1 return -1
buff = self.file.read(MAX_BUFF_LEN) buff = self.file.read(MAX_BUFF_LEN)
if len(buff) > 0: if len(buff) > 0:
@ -690,17 +665,17 @@ class Socks5:
# peer stopped reading # peer stopped reading
self.state = 8 # end connection self.state = 8 # end connection
self.disconnect() self.disconnect()
self.file_props['error'] = -1 self.file_props.error = -1
return -1 return -1
self.size += lenn self.size += lenn
current_time = self.idlequeue.current_time() current_time = self.idlequeue.current_time()
self.file_props['elapsed-time'] += current_time - \ self.file_props.elapsed_time += current_time - \
self.file_props['last-time'] self.file_props.last_time
self.file_props['last-time'] = current_time self.file_props.last_time = current_time
self.file_props['received-len'] = self.size self.file_props.received_len = self.size
if self.size >= int(self.file_props['size']): if self.size >= int(self.file_props.size):
self.state = 8 # end connection self.state = 8 # end connection
self.file_props['error'] = 0 self.file_props.error = 0
self.disconnect() self.disconnect()
return -1 return -1
if lenn != len(buff): if lenn != len(buff):
@ -710,7 +685,7 @@ class Socks5:
self.state = 7 # continue to write in the socket self.state = 7 # continue to write in the socket
if lenn == 0: if lenn == 0:
return None return None
self.file_props['stalled'] = False self.file_props.stalled = False
return lenn return lenn
else: else:
self.state = 8 # end connection self.state = 8 # end connection
@ -722,8 +697,8 @@ class Socks5:
Read file contents from socket and write them to file Read file contents from socket and write them to file
""" """
if self.file_props is None or ('file-name' in self.file_props) is False: if self.file_props is None or not self.file_props.file_name:
self.file_props['error'] = -2 self.file_props.error = -2
return None return None
fd = None fd = None
if self.remaining_buff != '': if self.remaining_buff != '':
@ -731,28 +706,28 @@ class Socks5:
fd = self.get_fd() fd = self.get_fd()
except IOError, e: except IOError, e:
self.disconnect(False) self.disconnect(False)
self.file_props['error'] = -6 # file system error self.file_props.error = -6 # file system error
return 0 return 0
fd.write(self.remaining_buff) fd.write(self.remaining_buff)
lenn = len(self.remaining_buff) lenn = len(self.remaining_buff)
current_time = self.idlequeue.current_time() current_time = self.idlequeue.current_time()
self.file_props['elapsed-time'] += current_time - \ self.file_props.elapsed_time += current_time - \
self.file_props['last-time'] self.file_props.last_time
self.file_props['last-time'] = current_time self.file_props.last_time = current_time
self.file_props['received-len'] += lenn self.file_props.received_len += lenn
self.remaining_buff = '' self.remaining_buff = ''
if self.file_props['received-len'] == int(self.file_props['size']): if self.file_props.received_len == int(self.file_props.size):
self.rem_fd(fd) self.rem_fd(fd)
self.disconnect() self.disconnect()
self.file_props['error'] = 0 self.file_props.error = 0
self.file_props['completed'] = True self.file_props.completed = True
return 0 return 0
else: else:
try: try:
fd = self.get_fd() fd = self.get_fd()
except IOError, e: except IOError, e:
self.disconnect(False) self.disconnect(False)
self.file_props['error'] = -6 # file system error self.file_props.error = -6 # file system error
return 0 return 0
try: try:
buff = self._recv(MAX_BUFF_LEN) buff = self._recv(MAX_BUFF_LEN)
@ -763,39 +738,39 @@ class Socks5:
except Exception: except Exception:
buff = '' buff = ''
current_time = self.idlequeue.current_time() current_time = self.idlequeue.current_time()
self.file_props['elapsed-time'] += current_time - \ self.file_props.elapsed_time += current_time - \
self.file_props['last-time'] self.file_props.last_time
self.file_props['last-time'] = current_time self.file_props.last_time = current_time
self.file_props['received-len'] += len(buff) self.file_props.received_len += len(buff)
if len(buff) == 0: if len(buff) == 0:
# Transfer stopped somehow: # Transfer stopped somehow:
# reset, paused or network error # reset, paused or network error
self.rem_fd(fd) self.rem_fd(fd)
self.disconnect() self.disconnect()
self.file_props['error'] = -1 self.file_props.error = -1
return 0 return 0
try: try:
fd.write(buff) fd.write(buff)
except IOError, e: except IOError, e:
self.rem_fd(fd) self.rem_fd(fd)
self.disconnect() self.disconnect()
self.file_props['error'] = -6 # file system error self.file_props.error = -6 # file system error
return 0 return 0
if self.file_props['received-len'] >= int(self.file_props['size']): if self.file_props.received_len >= int(self.file_props.size):
# transfer completed # transfer completed
self.rem_fd(fd) self.rem_fd(fd)
self.disconnect() self.disconnect()
self.file_props['error'] = 0 self.file_props.error = 0
self.file_props['completed'] = True self.file_props.completed = True
return 0 return 0
# return number of read bytes. It can be used in progressbar # return number of read bytes. It can be used in progressbar
if fd is not None: if fd is not None:
self.file_props['stalled'] = False self.file_props.stalled = False
if fd is None and self.file_props['stalled'] is False: if fd is None and self.file_props.stalled is False:
return None return None
if 'received-len' in self.file_props: if self.file_props.received_len:
if self.file_props['received-len'] != 0: if self.file_props.received_len != 0:
return self.file_props['received-len'] return self.file_props.received_len
return None return None
def disconnect(self): def disconnect(self):
@ -910,7 +885,7 @@ class Socks5:
def continue_paused_transfer(self): def continue_paused_transfer(self):
if self.state < 5: if self.state < 5:
return return
if self.file_props['type'] == 'r': if self.file_props.type_ == 'r':
self.idlequeue.plug_idle(self, False, True) self.idlequeue.plug_idle(self, False, True)
else: else:
self.idlequeue.plug_idle(self, True, False) self.idlequeue.plug_idle(self, True, False)
@ -920,11 +895,11 @@ class Socks5:
Get sha of sid + Initiator jid + Target jid Get sha of sid + Initiator jid + Target jid
""" """
if 'is_a_proxy' in self.file_props: if self.file_props.is_a_proxy:
del(self.file_props['is_a_proxy']) self.file_props.is_a_proxy = None # Is this necesary?
return hashlib.sha1('%s%s%s' % (self.sid, return hashlib.sha1('%s%s%s' % (self.sid,
self.file_props['proxy_sender'], self.file_props.proxy_sender,
self.file_props['proxy_receiver'])).hexdigest() self.file_props.proxy_receiver)).hexdigest()
return hashlib.sha1('%s%s%s' % (self.sid, self.initiator, self.target)).\ return hashlib.sha1('%s%s%s' % (self.sid, self.initiator, self.target)).\
hexdigest() hexdigest()
@ -961,17 +936,17 @@ class Socks5Sender(IdleObject):
self.state = 1 # waiting for first bytes self.state = 1 # waiting for first bytes
self.connect_timeout = 0 self.connect_timeout = 0
self.file_props['error'] = 0 self.file_props.error = 0
self.file_props['disconnect_cb'] = self.disconnect self.file_props.disconnect_cb = self.disconnect
self.file_props['started'] = True self.file_props.started = True
self.file_props['completed'] = False self.file_props.completed = False
self.file_props['paused'] = False self.file_props.paused = False
self.file_props['continue_cb'] = self.continue_paused_transfer self.file_props.continue_cb = self.continue_paused_transfer
self.file_props['stalled'] = False self.file_props.stalled = False
self.file_props['connected'] = True self.file_props.connected = True
self.file_props['elapsed-time'] = 0 self.file_props.elapsed_time = 0
self.file_props['last-time'] = self.idlequeue.current_time() self.file_props.last_time = self.idlequeue.current_time()
self.file_props['received-len'] = 0 self.file_props.received_len = 0
self.type = 'sender' self.type = 'sender'
def start_transfer(self): def start_transfer(self):
@ -1018,8 +993,8 @@ class Socks5Sender(IdleObject):
# close connection and remove us from the queue # close connection and remove us from the queue
Socks5.disconnect(self) Socks5.disconnect(self)
if self.file_props is not None: if self.file_props is not None:
self.file_props['connected'] = False self.file_props.connected = False
self.file_props['disconnect_cb'] = None self.file_props.disconnect_cb = None
if self.queue is not None: if self.queue is not None:
self.queue.remove_sender(self.queue_idx, False) self.queue.remove_sender(self.queue_idx, False)
@ -1039,33 +1014,33 @@ class Socks5Receiver(IdleObject):
self.connected = False self.connected = False
self.pauses = 0 self.pauses = 0
self.file_props = file_props self.file_props = file_props
self.file_props['disconnect_cb'] = self.disconnect self.file_props.disconnect_cb = self.disconnect
self.file_props['error'] = 0 self.file_props.error = 0
self.file_props['started'] = True self.file_props.started = True
self.file_props['completed'] = False self.file_props.completed = False
self.file_props['paused'] = False self.file_props.paused = False
self.file_props['continue_cb'] = self.continue_paused_transfer self.file_props.continue_cb = self.continue_paused_transfer
self.file_props['stalled'] = False self.file_props.stalled = False
self.file_props['received-len'] = 0 self.file_props.received_len = 0
def receive_file(self): def receive_file(self):
""" """
Start receiving the file over verified connection Start receiving the file over verified connection
""" """
if self.file_props['started']: if self.file_props.started:
return return
self.file_props['error'] = 0 self.file_props.error = 0
self.file_props['disconnect_cb'] = self.disconnect self.file_props.disconnect_cb = self.disconnect
self.file_props['started'] = True self.file_props.started = True
self.file_props['completed'] = False self.file_props.completed = False
self.file_props['paused'] = False self.file_props.paused = False
self.file_props['continue_cb'] = self.continue_paused_transfer self.file_props.continue_cb = self.continue_paused_transfer
self.file_props['stalled'] = False self.file_props.stalled = False
self.file_props['connected'] = True self.file_props.connected = True
self.file_props['elapsed-time'] = 0 self.file_props.elapsed_time = 0
self.file_props['last-time'] = self.idlequeue.current_time() self.file_props.last_time = self.idlequeue.current_time()
self.file_props['received-len'] = 0 self.file_props.received_len = 0
self.pauses = 0 self.pauses = 0
self.state = 7 self.state = 7
# plug for reading # plug for reading
@ -1096,7 +1071,7 @@ class Socks5Receiver(IdleObject):
# close connection # close connection
Socks5.disconnect(self) Socks5.disconnect(self)
if cb is True: if cb is True:
self.file_props['disconnect_cb'] = None self.file_props.disconnect_cb = None
if self.queue is not None: if self.queue is not None:
self.queue.remove_receiver(self.queue_idx, False) self.queue.remove_receiver(self.queue_idx, False)
@ -1152,8 +1127,8 @@ class Socks5Server(Socks5):
return return
elif self.state == 7: elif self.state == 7:
if self.file_props['paused']: if self.file_props.paused:
self.file_props['continue_cb'] = self.continue_paused_transfer self.file_props.continue_cb = self.continue_paused_transfer
self.idlequeue.plug_idle(self, False, False) self.idlequeue.plug_idle(self, False, False)
return return
self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT) self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT)
@ -1169,7 +1144,7 @@ class Socks5Server(Socks5):
def pollend(self): def pollend(self):
self.state = 8 # end connection self.state = 8 # end connection
self.disconnect() self.disconnect()
self.file_props['error'] = -1 self.file_props.error = -1
self.queue.process_result(-1, self) self.queue.process_result(-1, self)
def pollout(self): def pollout(self):
@ -1182,8 +1157,8 @@ class Socks5Server(Socks5):
elif self.state == 4: # send positive response to the 'connect' elif self.state == 4: # send positive response to the 'connect'
self.send_raw(self._get_request_buff(self.sha_msg, 0x00)) self.send_raw(self._get_request_buff(self.sha_msg, 0x00))
elif self.state == 7: elif self.state == 7:
if self.file_props['paused']: if self.file_props.paused:
self.file_props['continue_cb'] = self.continue_paused_transfer self.file_props.continue_cb = self.continue_paused_transfer
self.idlequeue.plug_idle(self, False, False) self.idlequeue.plug_idle(self, False, False)
return return
result = self.start_transfer() # send result = self.start_transfer() # send
@ -1262,16 +1237,16 @@ class Socks5Client(Socks5):
# for senders: init file_props # for senders: init file_props
if result == 1 and self.state == 5: if result == 1 and self.state == 5:
if self.file_props['type'] == 's': if self.file_props.type_ == 's':
self.file_props['error'] = 0 self.file_props.error = 0
self.file_props['disconnect_cb'] = self.disconnect self.file_props.disconnect_cb = self.disconnect
self.file_props['started'] = True self.file_props.started = True
self.file_props['completed'] = False self.file_props.completed = False
self.file_props['paused'] = False self.file_props.paused = False
self.file_props['stalled'] = False self.file_props.stalled = False
self.file_props['elapsed-time'] = 0 self.file_props.elapsed_time = 0
self.file_props['last-time'] = self.idlequeue.current_time() self.file_props.last_time = self.idlequeue.current_time()
self.file_props['received-len'] = 0 self.file_props.received_len = 0
self.pauses = 0 self.pauses = 0
# start sending file contents to socket # start sending file contents to socket
#self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT) #self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT)
@ -1281,7 +1256,7 @@ class Socks5Client(Socks5):
# receiving file contents from socket # receiving file contents from socket
self.idlequeue.plug_idle(self, False, True) self.idlequeue.plug_idle(self, False, True)
self.file_props['continue_cb'] = self.continue_paused_transfer self.file_props.continue_cb = self.continue_paused_transfer
# we have set up the connection, next - retrieve file # we have set up the connection, next - retrieve file
self.state = 6 self.state = 6
if self.state < 5: if self.state < 5:
@ -1294,7 +1269,7 @@ class Socks5Client(Socks5):
self.idlequeue.remove_timeout(self.fd) self.idlequeue.remove_timeout(self.fd)
if self.connected: if self.connected:
try: try:
if self.file_props['paused']: if self.file_props.paused:
self.idlequeue.plug_idle(self, False, False) self.idlequeue.plug_idle(self, False, False)
return return
if self.state < 5: if self.state < 5:
@ -1303,7 +1278,7 @@ class Socks5Client(Socks5):
self.queue.process_result(result, self) self.queue.process_result(result, self)
elif self.state == 5: # wait for proxy reply elif self.state == 5: # wait for proxy reply
pass pass
elif self.file_props['type'] == 'r': elif self.file_props.type_ == 'r':
self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT) self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT)
result = self.start_transfer() # receive result = self.start_transfer() # receive
self.queue.process_result(result, self) self.queue.process_result(result, self)
@ -1324,8 +1299,8 @@ class Socks5Client(Socks5):
self.send_raw(self._get_auth_buff()) self.send_raw(self._get_auth_buff())
elif self.state == 3: # send 'connect' request elif self.state == 3: # send 'connect' request
self.send_raw(self._get_request_buff(self._get_sha1_auth())) self.send_raw(self._get_request_buff(self._get_sha1_auth()))
elif self.file_props['type'] != 'r': elif self.file_props.type_ != 'r':
if self.file_props['paused']: if self.file_props.paused:
self.idlequeue.plug_idle(self, False, False) self.idlequeue.plug_idle(self, False, False)
return return
result = self.start_transfer() # send result = self.start_transfer() # send
@ -1344,7 +1319,7 @@ class Socks5Client(Socks5):
if self.state >= 5: if self.state >= 5:
# error during transfer # error during transfer
self.disconnect() self.disconnect()
self.file_props['error'] = -1 self.file_props.error = -1
self.queue.process_result(-1, self) self.queue.process_result(-1, self)
else: else:
self.queue.reconnect_client(self, self.streamhost) self.queue.reconnect_client(self, self.streamhost)
@ -1357,7 +1332,7 @@ class Socks5SenderClient(Socks5Client, Socks5Sender):
port=None, fingerprint = None, connected=True, file_props={}): port=None, fingerprint = None, connected=True, file_props={}):
Socks5Client.__init__(self, idlequeue, host, port, None, None, Socks5Client.__init__(self, idlequeue, host, port, None, None,
file_props['sid']) file_props.sid)
Socks5Sender.__init__(self,idlequeue, sock_hash, parent,_sock, Socks5Sender.__init__(self,idlequeue, sock_hash, parent,_sock,
host, port, fingerprint , connected, file_props) host, port, fingerprint , connected, file_props)
@ -1372,7 +1347,7 @@ class Socks5SenderServer(Socks5Server, Socks5Sender):
port=None, fingerprint = None, connected=True, file_props={}): port=None, fingerprint = None, connected=True, file_props={}):
Socks5Server.__init__(self, idlequeue, host, port, None, None, Socks5Server.__init__(self, idlequeue, host, port, None, None,
file_props['sid']) file_props.sid)
Socks5Sender.__init__(self,idlequeue, sock_hash, parent, _sock, Socks5Sender.__init__(self,idlequeue, sock_hash, parent, _sock,
host, port, fingerprint , connected, file_props) host, port, fingerprint , connected, file_props)

View File

@ -33,6 +33,7 @@ import dialogs
from common import gajim from common import gajim
from common import helpers from common import helpers
from common.file_props import FilesProp
from common.protocol.bytestream import (is_transfer_active, is_transfer_paused, from common.protocol.bytestream import (is_transfer_active, is_transfer_paused,
is_transfer_stopped) is_transfer_stopped)
from common.xmpp.protocol import NS_JINGLE_FILE_TRANSFER from common.xmpp.protocol import NS_JINGLE_FILE_TRANSFER
@ -147,22 +148,20 @@ class FileTransfersWindow:
Find all transfers with peer 'jid' that belong to 'account' Find all transfers with peer 'jid' that belong to 'account'
""" """
active_transfers = [[], []] # ['senders', 'receivers'] active_transfers = [[], []] # ['senders', 'receivers']
allfp = FilesProp.getAllFileProp()
# 'account' is the sender for file_props in allfp:
for file_props in self.files_props['s'].values(): if file_props.type_ == 's' and file_props.tt_account == account:
if file_props['tt_account'] == account: # 'account' is the sender
receiver_jid = unicode(file_props['receiver']).split('/')[0] receiver_jid = unicode(file_props.receiver).split('/')[0]
if jid == receiver_jid: if jid == receiver_jid and not is_transfer_stopped(file_props):
if not is_transfer_stopped(file_props): active_transfers[0].append(file_props)
active_transfers[0].append(file_props) elif file_props.type_ == 'r' and file_props.tt_account == account:
# 'account' is the recipient
# 'account' is the recipient sender_jid = unicode(file_props.sender).split('/')[0]
for file_props in self.files_props['r'].values(): if jid == sender_jid and not is_transfer_stopped(file_props):
if file_props['tt_account'] == account: active_transfers[1].append(file_props)
sender_jid = unicode(file_props['sender']).split('/')[0] else:
if jid == sender_jid: raise Exception('file_props has no type')
if not is_transfer_stopped(file_props):
active_transfers[1].append(file_props)
return active_transfers return active_transfers
def show_completed(self, jid, file_props): def show_completed(self, jid, file_props):
@ -171,46 +170,46 @@ class FileTransfersWindow:
""" """
def on_open(widget, file_props): def on_open(widget, file_props):
dialog.destroy() dialog.destroy()
if 'file-name' not in file_props: if not file_props.file_name:
return return
path = os.path.split(file_props['file-name'])[0] path = os.path.split(file_props.file_name)[0]
if os.path.exists(path) and os.path.isdir(path): if os.path.exists(path) and os.path.isdir(path):
helpers.launch_file_manager(path) helpers.launch_file_manager(path)
self.tree.get_selection().unselect_all() self.tree.get_selection().unselect_all()
if file_props['type'] == 'r': if file_props.type_ == 'r':
# file path is used below in 'Save in' # file path is used below in 'Save in'
(file_path, file_name) = os.path.split(file_props['file-name']) (file_path, file_name) = os.path.split(file_props.file_name)
else: else:
file_name = file_props['name'] file_name = file_props.name
sectext = '\t' + _('Filename: %s') % gobject.markup_escape_text( sectext = '\t' + _('Filename: %s') % gobject.markup_escape_text(
file_name) file_name)
sectext += '\n\t' + _('Size: %s') % \ sectext += '\n\t' + _('Size: %s') % \
helpers.convert_bytes(file_props['size']) helpers.convert_bytes(file_props.size)
if file_props['type'] == 'r': if file_props.type_ == 'r':
jid = unicode(file_props['sender']).split('/')[0] jid = unicode(file_props.sender).split('/')[0]
sender_name = gajim.contacts.get_first_contact_from_jid( sender_name = gajim.contacts.get_first_contact_from_jid(
file_props['tt_account'], jid).get_shown_name() file_props.tt_account, jid).get_shown_name()
sender = sender_name sender = sender_name
else: else:
#You is a reply of who sent a file #You is a reply of who sent a file
sender = _('You') sender = _('You')
sectext += '\n\t' + _('Sender: %s') % sender sectext += '\n\t' + _('Sender: %s') % sender
sectext += '\n\t' + _('Recipient: ') sectext += '\n\t' + _('Recipient: ')
if file_props['type'] == 's': if file_props.type_ == 's':
jid = unicode(file_props['receiver']).split('/')[0] jid = unicode(file_props.receiver).split('/')[0]
receiver_name = gajim.contacts.get_first_contact_from_jid( receiver_name = gajim.contacts.get_first_contact_from_jid(
file_props['tt_account'], jid).get_shown_name() file_props.tt_account, jid).get_shown_name()
recipient = receiver_name recipient = receiver_name
else: else:
#You is a reply of who received a file #You is a reply of who received a file
recipient = _('You') recipient = _('You')
sectext += recipient sectext += recipient
if file_props['type'] == 'r': if file_props.type_ == 'r':
sectext += '\n\t' + _('Saved in: %s') % file_path sectext += '\n\t' + _('Saved in: %s') % file_path
dialog = dialogs.HigDialog(None, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, dialog = dialogs.HigDialog(None, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE,
_('File transfer completed'), sectext) _('File transfer completed'), sectext)
if file_props['type'] == 'r': if file_props.type_ == 'r':
button = gtk.Button(_('_Open Containing Folder')) button = gtk.Button(_('_Open Containing Folder'))
button.connect('clicked', on_open, file_props) button.connect('clicked', on_open, file_props)
dialog.action_area.pack_start(button) dialog.action_area.pack_start(button)
@ -236,10 +235,10 @@ class FileTransfersWindow:
self.tree.get_selection().unselect_all() self.tree.get_selection().unselect_all()
def show_stopped(self, jid, file_props, error_msg=''): def show_stopped(self, jid, file_props, error_msg=''):
if file_props['type'] == 'r': if file_props.type_ == 'r':
file_name = os.path.basename(file_props['file-name']) file_name = os.path.basename(file_props.file_name)
else: else:
file_name = file_props['name'] file_name = file_props.name
sectext = '\t' + _('Filename: %s') % gobject.markup_escape_text( sectext = '\t' + _('Filename: %s') % gobject.markup_escape_text(
file_name) file_name)
sectext += '\n\t' + _('Recipient: %s') % jid sectext += '\n\t' + _('Recipient: %s') % jid
@ -254,13 +253,13 @@ class FileTransfersWindow:
sid = gajim.connections[account].start_file_transfer(jid, sid = gajim.connections[account].start_file_transfer(jid,
file_props, file_props,
True) True)
file_props['sid'] = sid file_props.sid = sid
if file_props['type'] == 'r': if file_props.type_ == 'r':
file_name = os.path.basename(file_props['file-name']) file_name = os.path.basename(file_props.file_name)
else: else:
file_name = file_props['name'] file_name = file_props.name
dialogs.YesNoDialog(('File transfer error'), dialogs.YesNoDialog(('File transfer error'),
_('The file %(file)s has been fully received, but it seems to be ' _('The file %(file)s has been fully received, but it seems to be '
'wrongly received.\nDo you want to reload it?') % \ 'wrongly received.\nDo you want to reload it?') % \
@ -339,10 +338,8 @@ class FileTransfersWindow:
return False return False
if contact.supports(NS_JINGLE_FILE_TRANSFER): if contact.supports(NS_JINGLE_FILE_TRANSFER):
log.info("contact %s supports jingle file transfer"%(contact.get_full_jid())) log.info("contact %s supports jingle file transfer"%(contact.get_full_jid()))
# this call has the side effect of setting file_props['sid'] to the jingle sid, but for the sake of clarity gajim.connections[account].start_file_transfer(contact.get_full_jid(),
# make it explicit here file_props)
sid = gajim.connections[account].start_file_transfer(contact.get_full_jid(), file_props)
file_props['sid'] = sid
self.add_transfer(account, contact, file_props) self.add_transfer(account, contact, file_props)
else: else:
log.info("contact does not support jingle file transfer") log.info("contact does not support jingle file transfer")
@ -354,7 +351,8 @@ class FileTransfersWindow:
file_dir = os.path.dirname(file_path) file_dir = os.path.dirname(file_path)
if file_dir: if file_dir:
gajim.config.set('last_save_dir', file_dir) gajim.config.set('last_save_dir', file_dir)
file_props['file-name'] = file_path file_props.file_name = file_path
file_props.type_ = 'r'
self.add_transfer(account, contact, file_props) self.add_transfer(account, contact, file_props)
gajim.connections[account].send_file_approval(file_props) gajim.connections[account].send_file_approval(file_props)
@ -375,14 +373,14 @@ class FileTransfersWindow:
return return
stat = os.stat(file_path) stat = os.stat(file_path)
dl_size = stat.st_size dl_size = stat.st_size
file_size = file_props['size'] file_size = file_props.size
dl_finished = dl_size >= file_size dl_finished = dl_size >= file_size
def on_response(response): def on_response(response):
if response < 0: if response < 0:
return return
elif response == 100: elif response == 100:
file_props['offset'] = dl_size file_props.offset = dl_size
dialog2.destroy() dialog2.destroy()
self._start_receive(file_path, account, contact, file_props) self._start_receive(file_path, account, contact, file_props)
@ -419,7 +417,7 @@ class FileTransfersWindow:
on_response_ok=(on_ok, account, contact, file_props), on_response_ok=(on_ok, account, contact, file_props),
on_response_cancel=(on_cancel, account, contact, file_props)) on_response_cancel=(on_cancel, account, contact, file_props))
dialog2.set_current_name(file_props['name']) dialog2.set_current_name(file_props.name)
dialog2.connect('delete-event', lambda widget, event: dialog2.connect('delete-event', lambda widget, event:
on_cancel(widget, account, contact, file_props)) on_cancel(widget, account, contact, file_props))
@ -428,17 +426,17 @@ class FileTransfersWindow:
Show dialog asking for comfirmation and store location of new file Show dialog asking for comfirmation and store location of new file
requested by a contact requested by a contact
""" """
if file_props is None or 'name' not in file_props: if not file_props or not file_props.name:
return return
sec_text = '\t' + _('File: %s') % gobject.markup_escape_text( sec_text = '\t' + _('File: %s') % gobject.markup_escape_text(
file_props['name']) file_props.name)
if 'size' in file_props: if file_props.size:
sec_text += '\n\t' + _('Size: %s') % \ sec_text += '\n\t' + _('Size: %s') % \
helpers.convert_bytes(file_props['size']) helpers.convert_bytes(file_props.size)
if 'mime-type' in file_props: if file_props.mime_type:
sec_text += '\n\t' + _('Type: %s') % file_props['mime-type'] sec_text += '\n\t' + _('Type: %s') % file_props.mime_type
if 'desc' in file_props: if file_props.desc:
sec_text += '\n\t' + _('Description: %s') % file_props['desc'] sec_text += '\n\t' + _('Description: %s') % file_props.desc
prim_text = _('%s wants to send you a file:') % contact.jid prim_text = _('%s wants to send you a file:') % contact.jid
dialog = None dialog = None
@ -459,22 +457,21 @@ class FileTransfersWindow:
return self.images.setdefault(ident, return self.images.setdefault(ident,
self.window.render_icon(self.icons[ident], gtk.ICON_SIZE_MENU)) self.window.render_icon(self.icons[ident], gtk.ICON_SIZE_MENU))
def set_status(self, typ, sid, status): def set_status(self,file_props, status):
""" """
Change the status of a transfer to state 'status' Change the status of a transfer to state 'status'
""" """
iter_ = self.get_iter_by_sid(typ, sid) iter_ = self.get_iter_by_sid(file_props.type_, file_props.sid)
if iter_ is None: if iter_ is None:
return return
sid = self.model[iter_][C_SID].decode('utf-8') self.model[iter_][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]]
if status == 'stop': if status == 'stop':
file_props['stopped'] = True file_props.stopped = True
elif status == 'ok': elif status == 'ok':
file_props['completed'] = True file_props.completed = True
text = self._format_percent(100) text = self._format_percent(100)
received_size = int(file_props['received-len']) received_size = int(file_props.received_len)
full_size = int(file_props['size']) full_size = int(file_props.size)
text += helpers.convert_bytes(received_size) + '/' + \ text += helpers.convert_bytes(received_size) + '/' + \
helpers.convert_bytes(full_size) helpers.convert_bytes(full_size)
self.model.set(iter_, C_PROGRESS, text) self.model.set(iter_, C_PROGRESS, text)
@ -482,8 +479,8 @@ class FileTransfersWindow:
elif status == 'computing': elif status == 'computing':
self.model.set(iter_, C_PULSE, 1) self.model.set(iter_, C_PULSE, 1)
text = _('Checking file...') + '\n' text = _('Checking file...') + '\n'
received_size = int(file_props['received-len']) received_size = int(file_props.received_len)
full_size = int(file_props['size']) full_size = int(file_props.size)
text += helpers.convert_bytes(received_size) + '/' + \ text += helpers.convert_bytes(received_size) + '/' + \
helpers.convert_bytes(full_size) helpers.convert_bytes(full_size)
self.model.set(iter_, C_PROGRESS, text) self.model.set(iter_, C_PROGRESS, text)
@ -496,8 +493,8 @@ class FileTransfersWindow:
gobject.timeout_add(100, pulse) gobject.timeout_add(100, pulse)
elif status == 'hash_error': elif status == 'hash_error':
text = _('File error') + '\n' text = _('File error') + '\n'
received_size = int(file_props['received-len']) received_size = int(file_props.received_len)
full_size = int(file_props['size']) full_size = int(file_props.size)
text += helpers.convert_bytes(received_size) + '/' + \ text += helpers.convert_bytes(received_size) + '/' + \
helpers.convert_bytes(full_size) helpers.convert_bytes(full_size)
self.model.set(iter_, C_PROGRESS, text) self.model.set(iter_, C_PROGRESS, text)
@ -535,14 +532,14 @@ class FileTransfersWindow:
return _('%(hours)02.d:%(minutes)02.d:%(seconds)02.d') % times return _('%(hours)02.d:%(minutes)02.d:%(seconds)02.d') % times
def _get_eta_and_speed(self, full_size, transfered_size, file_props): def _get_eta_and_speed(self, full_size, transfered_size, file_props):
if len(file_props['transfered_size']) == 0: if len(file_props.transfered_size) == 0:
return 0., 0. return 0., 0.
elif len(file_props['transfered_size']) == 1: elif len(file_props.transfered_size) == 1:
speed = round(float(transfered_size) / file_props['elapsed-time']) speed = round(float(transfered_size) / file_props.elapsed_time)
else: else:
# first and last are (time, transfered_size) # first and last are (time, transfered_size)
first = file_props['transfered_size'][0] first = file_props.transfered_size[0]
last = file_props['transfered_size'][-1] last = file_props.transfered_size[-1]
transfered = last[1] - first[1] transfered = last[1] - first[1]
tim = last[0] - first[0] tim = last[0] - first[0]
if tim == 0: if tim == 0:
@ -556,16 +553,16 @@ class FileTransfersWindow:
def _remove_transfer(self, iter_, sid, file_props): def _remove_transfer(self, iter_, sid, file_props):
self.model.remove(iter_) self.model.remove(iter_)
if 'tt_account' in file_props: if file_props.tt_account:
# file transfer is set # file transfer is set
account = file_props['tt_account'] account = file_props.tt_account
if account in gajim.connections: if account in gajim.connections:
# there is a connection to the account # there is a connection to the account
gajim.connections[account].remove_transfer(file_props) gajim.connections[account].remove_transfer(file_props)
if file_props['type'] == 'r': # we receive a file if file_props.type_ == 'r': # we receive a file
other = file_props['sender'] other = file_props.sender
else: # we send a file else: # we send a file
other = file_props['receiver'] other = file_props.receiver
if isinstance(other, unicode): if isinstance(other, unicode):
jid = gajim.get_jid_without_resource(other) jid = gajim.get_jid_without_resource(other)
else: # It's a Contact instance else: # It's a Contact instance
@ -573,21 +570,19 @@ class FileTransfersWindow:
for ev_type in ('file-error', 'file-completed', 'file-request-error', for ev_type in ('file-error', 'file-completed', 'file-request-error',
'file-send-error', 'file-stopped'): 'file-send-error', 'file-stopped'):
for event in gajim.events.get_events(account, jid, [ev_type]): for event in gajim.events.get_events(account, jid, [ev_type]):
if event.parameters['sid'] == file_props['sid']: if event.parameters['sid'] == file_props.sid:
gajim.events.remove_events(account, jid, event) gajim.events.remove_events(account, jid, event)
gajim.interface.roster.draw_contact(jid, account) gajim.interface.roster.draw_contact(jid, account)
gajim.interface.roster.show_title() gajim.interface.roster.show_title()
del(self.files_props[sid[0]][sid[1:]]) FilesProp.deleteFileProp(files_props)
del(file_props) del(file_props)
def set_progress(self, typ, sid, transfered_size, iter_=None): def set_progress(self, typ, sid, transfered_size, iter_=None):
""" """
Change the progress of a transfer with new transfered size Change the progress of a transfer with new transfered size
""" """
if sid not in self.files_props[typ]: file_props = FilesProp.getFilePropByType(typ, sid)
return full_size = int(file_props.size)
file_props = self.files_props[typ][sid]
full_size = int(file_props['size'])
if full_size == 0: if full_size == 0:
percent = 0 percent = 0
else: else:
@ -607,14 +602,14 @@ class FileTransfersWindow:
# Kb/s # Kb/s
# remaining time # remaining time
if 'offset' in file_props and file_props['offset']: if file_props.offset:
transfered_size -= file_props['offset'] transfered_size -= file_props.offset
full_size -= file_props['offset'] full_size -= file_props.offset
if file_props['elapsed-time'] > 0: if file_props.elapsed_time > 0:
file_props['transfered_size'].append((file_props['last-time'], transfered_size)) file_props.transfered_size.append((file_props.last_time, transfered_size))
if len(file_props['transfered_size']) > 6: if len(file_props.transfered_size) > 6:
file_props['transfered_size'].pop(0) file_props.transfered_size.pop(0)
eta, speed = self._get_eta_and_speed(full_size, transfered_size, eta, speed = self._get_eta_and_speed(full_size, transfered_size,
file_props) file_props)
@ -630,24 +625,24 @@ class FileTransfersWindow:
self.model.set(iter_, C_TIME, text) self.model.set(iter_, C_TIME, text)
# try to guess what should be the status image # try to guess what should be the status image
if file_props['type'] == 'r': if file_props.type_ == 'r':
status = 'download' status = 'download'
else: else:
status = 'upload' status = 'upload'
if 'paused' in file_props and file_props['paused'] == True: if file_props.paused == True:
status = 'pause' status = 'pause'
elif 'stalled' in file_props and file_props['stalled'] == True: elif file_props.stalled == True:
status = 'waiting' status = 'waiting'
if 'connected' in file_props and file_props['connected'] == False: if file_props.connected == False:
status = 'stop' status = 'stop'
self.model.set(iter_, 0, self.get_icon(status)) self.model.set(iter_, 0, self.get_icon(status))
if transfered_size == full_size: if transfered_size == full_size:
# If we are receiver and this is a jingle session # If we are receiver and this is a jingle session
if file_props['type'] == 'r' and 'session-sid' in file_props: if file_props.type_ == 'r' and file_props.session_sid:
# Show that we are computing the hash # Show that we are computing the hash
self.set_status(typ, sid, 'computing') self.set_status(file_props, 'computing')
else: else:
self.set_status(typ, sid, 'ok') self.set_status(file_props, 'ok')
elif just_began: elif just_began:
path = self.model.get_path(iter_) path = self.model.get_path(iter_)
self.select_func(path) self.select_func(path)
@ -668,8 +663,6 @@ class FileTransfersWindow:
""" """
Create new file_props dict and set initial file transfer properties in it Create new file_props dict and set initial file transfer properties in it
""" """
file_props = {'file-name' : file_path, 'name' : file_name,
'type' : 's', 'desc' : file_desc}
if os.path.isfile(file_path): if os.path.isfile(file_path):
stat = os.stat(file_path) stat = os.stat(file_path)
else: else:
@ -679,16 +672,17 @@ class FileTransfersWindow:
dialogs.ErrorDialog(_('Invalid File'), dialogs.ErrorDialog(_('Invalid File'),
_('It is not possible to send empty files')) _('It is not possible to send empty files'))
return None return None
file_props['elapsed-time'] = 0 file_props = FilesProp.getNewFileProp(account,
file_props['size'] = unicode(stat[6]) sid=helpers.get_random_string_16())
file_props['sid'] = helpers.get_random_string_16() file_props.file_name = file_path
file_props['completed'] = False file_props.name = file_name
file_props['started'] = False file_props.type_ = 's'
file_props['sender'] = account file_props.desc = file_desc
file_props['receiver'] = contact file_props.elapsed_time = 0
file_props['tt_account'] = account file_props.size = unicode(stat[6])
# keep the last time: transfered_size to compute transfer speed file_props.sender = account
file_props['transfered_size'] = [] file_props.receiver = contact
file_props.tt_account = account
return file_props return file_props
def add_transfer(self, account, contact, file_props): def add_transfer(self, account, contact, file_props):
@ -698,32 +692,31 @@ class FileTransfersWindow:
self.on_transfers_list_leave_notify_event(None) self.on_transfers_list_leave_notify_event(None)
if file_props is None: if file_props is None:
return return
file_props['elapsed-time'] = 0 file_props.elapsed_time = 0
self.files_props[file_props['type']][file_props['sid']] = file_props
iter_ = self.model.prepend() iter_ = self.model.prepend()
text_labels = '<b>' + _('Name: ') + '</b>\n' text_labels = '<b>' + _('Name: ') + '</b>\n'
if file_props['type'] == 'r': if file_props.type_ == 'r':
text_labels += '<b>' + _('Sender: ') + '</b>' text_labels += '<b>' + _('Sender: ') + '</b>'
else: else:
text_labels += '<b>' + _('Recipient: ') + '</b>' text_labels += '<b>' + _('Recipient: ') + '</b>'
if file_props['type'] == 'r': if file_props.type_ == 'r':
file_name = os.path.split(file_props['file-name'])[1] file_name = os.path.split(file_props.file_name)[1]
else: else:
file_name = file_props['name'] file_name = file_props.name
text_props = gobject.markup_escape_text(file_name) + '\n' text_props = gobject.markup_escape_text(file_name) + '\n'
text_props += contact.get_shown_name() text_props += contact.get_shown_name()
self.model.set(iter_, 1, text_labels, 2, text_props, C_PULSE, -1, C_SID, self.model.set(iter_, 1, text_labels, 2, text_props, C_PULSE, -1, C_SID,
file_props['type'] + file_props['sid']) file_props.type_ + file_props.sid)
self.set_progress(file_props['type'], file_props['sid'], 0, iter_) self.set_progress(file_props.type_, file_props.sid, 0, iter_)
if 'started' in file_props and file_props['started'] is False: if file_props.started is False:
status = 'waiting' status = 'waiting'
elif file_props['type'] == 'r': elif file_props.type_ == 'r':
status = 'download' status = 'download'
else: else:
status = 'upload' status = 'upload'
file_props['tt_account'] = account file_props.tt_account = account
self.set_status(file_props['type'], file_props['sid'], status) self.set_status(file_props, status)
self.set_cleanup_sensitivity() self.set_cleanup_sensitivity()
self.window.show_all() self.window.show_all()
@ -743,7 +736,7 @@ class FileTransfersWindow:
self.tooltip.hide_tooltip() self.tooltip.hide_tooltip()
return return
sid = self.model[iter_][C_SID].decode('utf-8') sid = self.model[iter_][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = FilesProp.getFilePropByType(sid[0], sid[1:])
if file_props is not None: if file_props is not None:
if self.tooltip.timeout == 0 or self.tooltip.id != props[0]: if self.tooltip.timeout == 0 or self.tooltip.id != props[0]:
self.tooltip.id = row self.tooltip.id = row
@ -798,7 +791,7 @@ class FileTransfersWindow:
return return
current_iter = self.model.get_iter(path) current_iter = self.model.get_iter(path)
sid = self.model[current_iter][C_SID].decode('utf-8') sid = self.model[current_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = FilesProp.getFilePropByType(sid[0], sid[1:])
self.remove_menuitem.set_sensitive(is_row_selected) self.remove_menuitem.set_sensitive(is_row_selected)
self.open_folder_menuitem.set_sensitive(is_row_selected) self.open_folder_menuitem.set_sensitive(is_row_selected)
is_stopped = False is_stopped = False
@ -856,7 +849,7 @@ class FileTransfersWindow:
while i >= 0: while i >= 0:
iter_ = self.model.get_iter((i)) iter_ = self.model.get_iter((i))
sid = self.model[iter_][C_SID].decode('utf-8') sid = self.model[iter_][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = FilesProp.getFilePropByType(sid[0], sid[1:])
if is_transfer_stopped(file_props): if is_transfer_stopped(file_props):
self._remove_transfer(iter_, sid, file_props) self._remove_transfer(iter_, sid, file_props)
i -= 1 i -= 1
@ -891,20 +884,20 @@ class FileTransfersWindow:
return return
s_iter = selected[1] s_iter = selected[1]
sid = self.model[s_iter][C_SID].decode('utf-8') sid = self.model[s_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = FilesProp.getFilePropByType(sid[0], sid[1:])
if is_transfer_paused(file_props): if is_transfer_paused(file_props):
file_props['last-time'] = time.time() file_props.last_time = time.time()
file_props['paused'] = False file_props.paused = False
types = {'r' : 'download', 's' : 'upload'} types = {'r' : 'download', 's' : 'upload'}
self.set_status(file_props['type'], file_props['sid'], types[sid[0]]) self.set_status(file_props, types[sid[0]])
self.toggle_pause_continue(True) self.toggle_pause_continue(True)
if file_props['continue_cb']: if file_props.continue_cb:
file_props['continue_cb']() file_props.continue_cb()
elif is_transfer_active(file_props): elif is_transfer_active(file_props):
file_props['paused'] = True file_props.paused = True
self.set_status(file_props['type'], file_props['sid'], 'pause') self.set_status(file_props, 'pause')
# reset that to compute speed only when we resume # reset that to compute speed only when we resume
file_props['transfered_size'] = [] file_props.transfered_size = []
self.toggle_pause_continue(False) self.toggle_pause_continue(False)
def on_cancel_button_clicked(self, widget): def on_cancel_button_clicked(self, widget):
@ -913,14 +906,12 @@ class FileTransfersWindow:
return return
s_iter = selected[1] s_iter = selected[1]
sid = self.model[s_iter][C_SID].decode('utf-8') sid = self.model[s_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = FilesProp.getFilePropByType(sid[0], sid[1:])
if 'tt_account' not in file_props: account = file_props.tt_account
return
account = file_props['tt_account']
if account not in gajim.connections: if account not in gajim.connections:
return return
gajim.connections[account].disconnect_transfer(file_props) gajim.connections[account].disconnect_transfer(file_props)
self.set_status(file_props['type'], file_props['sid'], 'stop') self.set_status(file_props, 'stop')
def show_tooltip(self, widget): def show_tooltip(self, widget):
if self.height_diff == 0: if self.height_diff == 0:
@ -934,7 +925,7 @@ class FileTransfersWindow:
if props and self.tooltip.id == props[0]: if props and self.tooltip.id == props[0]:
iter_ = self.model.get_iter(props[0]) iter_ = self.model.get_iter(props[0])
sid = self.model[iter_][C_SID].decode('utf-8') sid = self.model[iter_][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = FilesProp.getFilePropByType(sid[0], sid[1:])
# bounding rectangle of coordinates for the cell within the treeview # bounding rectangle of coordinates for the cell within the treeview
rect = self.tree.get_cell_area(props[0], props[1]) rect = self.tree.get_cell_area(props[0], props[1])
# position of the treeview on the screen # position of the treeview on the screen
@ -1022,10 +1013,10 @@ class FileTransfersWindow:
return return
s_iter = selected[1] s_iter = selected[1]
sid = self.model[s_iter][C_SID].decode('utf-8') sid = self.model[s_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = FilesProp.getFilePropByType(sid[0], sid[1:])
if 'file-name' not in file_props: if not file_props.file_name:
return return
path = os.path.split(file_props['file-name'])[0] path = os.path.split(file_props.file_name)[0]
if os.path.exists(path) and os.path.isdir(path): if os.path.exists(path) and os.path.isdir(path):
helpers.launch_file_manager(path) helpers.launch_file_manager(path)
@ -1044,7 +1035,7 @@ class FileTransfersWindow:
return return
s_iter = selected[1] s_iter = selected[1]
sid = self.model[s_iter][C_SID].decode('utf-8') sid = self.model[s_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = FilesProp.getFilePropByType(sid[0], sid[1:])
self._remove_transfer(s_iter, sid, file_props) self._remove_transfer(s_iter, sid, file_props)
self.set_all_insensitive() self.set_all_insensitive()

View File

@ -84,6 +84,7 @@ from common.connection_handlers_events import OurShowEvent, \
FileRequestErrorEvent, InformationEvent FileRequestErrorEvent, InformationEvent
from common.connection import Connection from common.connection import Connection
from common import jingle from common import jingle
from common.file_props import FilesProp
import roster_window import roster_window
import profile_window import profile_window
@ -168,12 +169,12 @@ class Interface:
sid = obj.id_ sid = obj.id_
if len(obj.id_) > 3 and obj.id_[2] == '_': if len(obj.id_) > 3 and obj.id_[2] == '_':
sid = obj.id_[3:] sid = obj.id_[3:]
if sid in ft.files_props['s']: file_props = FilesProp.getFileProp(obj.conn.name, sid)
file_props = ft.files_props['s'][sid] if file_props :
if unicode(obj.errcode) == '400': if unicode(obj.errcode) == '400':
file_props['error'] = -3 file_props.error = -3
else: else:
file_props['error'] = -4 file_props.error = -4
gajim.nec.push_incoming_event(FileRequestErrorEvent(None, gajim.nec.push_incoming_event(FileRequestErrorEvent(None,
conn=obj.conn, jid=obj.jid, file_props=file_props, conn=obj.conn, jid=obj.jid, file_props=file_props,
error_msg=obj.errmsg)) error_msg=obj.errmsg))
@ -183,12 +184,11 @@ class Interface:
sid = obj.id_ sid = obj.id_
if len(obj.id_) > 3 and obj.id_[2] == '_': if len(obj.id_) > 3 and obj.id_[2] == '_':
sid = obj.id_[3:] sid = obj.id_[3:]
if sid in obj.conn.files_props: file_props = FilesProp.getFileProp(obj.conn.name, sid)
file_props = obj.conn.files_props[sid] self.handle_event_file_send_error(obj.conn.name, (obj.fjid,
self.handle_event_file_send_error(obj.conn.name, (obj.fjid, file_props))
file_props)) obj.conn.disconnect_transfer(file_props)
obj.conn.disconnect_transfer(file_props) return
return
ctrl = self.msg_win_mgr.get_control(obj.fjid, obj.conn.name) ctrl = self.msg_win_mgr.get_control(obj.fjid, obj.conn.name)
if ctrl and ctrl.type_id == message_control.TYPE_GC: if ctrl and ctrl.type_id == message_control.TYPE_GC:
@ -802,7 +802,7 @@ class Interface:
jid = array[0] jid = array[0]
file_props = array[1] file_props = array[1]
ft = self.instances['file_transfers'] ft = self.instances['file_transfers']
ft.set_status(file_props['type'], file_props['sid'], 'stop') ft.set_status(file_props, 'stop')
if helpers.allow_popup_window(account): if helpers.allow_popup_window(account):
ft.show_send_error(file_props) ft.show_send_error(file_props)
@ -814,7 +814,7 @@ class Interface:
path = gtkgui_helpers.get_icon_path('gajim-ft_error', 48) path = gtkgui_helpers.get_icon_path('gajim-ft_error', 48)
event_type = _('File Transfer Error') event_type = _('File Transfer Error')
notify.popup(event_type, jid, account, 'file-send-error', path, notify.popup(event_type, jid, account, 'file-send-error', path,
event_type, file_props['name']) event_type, file_props.name)
def handle_event_gmail_notify(self, obj): def handle_event_gmail_notify(self, obj):
jid = obj.jid jid = obj.jid
@ -856,8 +856,8 @@ class Interface:
def handle_event_file_request_error(self, obj): def handle_event_file_request_error(self, obj):
# ('FILE_REQUEST_ERROR', account, (jid, file_props, error_msg)) # ('FILE_REQUEST_ERROR', account, (jid, file_props, error_msg))
ft = self.instances['file_transfers'] ft = self.instances['file_transfers']
ft.set_status(obj.file_props['type'], obj.file_props['sid'], 'stop') ft.set_status(obj.file_props, 'stop')
errno = obj.file_props['error'] errno = obj.file_props.error
if helpers.allow_popup_window(obj.conn.name): if helpers.allow_popup_window(obj.conn.name):
if errno in (-4, -5): if errno in (-4, -5):
@ -878,7 +878,7 @@ class Interface:
path = gtkgui_helpers.get_icon_path('gajim-ft_error', 48) path = gtkgui_helpers.get_icon_path('gajim-ft_error', 48)
event_type = _('File Transfer Error') event_type = _('File Transfer Error')
notify.popup(event_type, obj.jid, obj.conn.name, msg_type, path, notify.popup(event_type, obj.jid, obj.conn.name, msg_type, path,
title=event_type, text=obj.file_props['name']) title=event_type, text=obj.file_props.name)
def handle_event_file_request(self, obj): def handle_event_file_request(self, obj):
account = obj.conn.name account = obj.conn.name
@ -916,92 +916,90 @@ class Interface:
if time.time() - self.last_ftwindow_update > 0.5: if time.time() - self.last_ftwindow_update > 0.5:
# update ft window every 500ms # update ft window every 500ms
self.last_ftwindow_update = time.time() self.last_ftwindow_update = time.time()
self.instances['file_transfers'].set_progress(file_props['type'], self.instances['file_transfers'].set_progress(file_props.type_,
file_props['sid'], file_props['received-len']) file_props.sid, file_props.received_len)
def __compare_hashes(self, account, file_props): def __compare_hashes(self, account, file_props):
session = gajim.connections[account].get_jingle_session(jid=None, session = gajim.connections[account].get_jingle_session(jid=None,
sid=file_props['session-sid']) sid=file_props.session_sid)
ft_win = self.instances['file_transfers'] ft_win = self.instances['file_transfers']
if not session.file_hash: if not session.file_hash:
# We disn't get the hash, sender probably don't support that # We disn't get the hash, sender probably don't support that
jid = unicode(file_props['sender']) jid = unicode(file_props.sender)
self.popup_ft_result(account, jid, file_props) self.popup_ft_result(account, jid, file_props)
ft_win.set_status(file_props['type'], file_props['sid'], 'ok') ft_win.set_status(file_props, 'ok')
h = Hashes() h = Hashes()
try: try:
file_ = open(file_props['file-name'], 'r') file_ = open(file_props.file_name, 'r')
except: except:
return return
hash_ = h.calculateHash(session.hash_algo, file_) hash_ = h.calculateHash(session.hash_algo, file_)
file_.close() file_.close()
# If the hash we received and the hash of the file are the same, # If the hash we received and the hash of the file are the same,
# then the file is not corrupt # then the file is not corrupt
jid = unicode(file_props['sender']) jid = unicode(file_props.sender)
if session.file_hash == hash_: if session.file_hash == hash_:
self.popup_ft_result(account, jid, file_props) self.popup_ft_result(account, jid, file_props)
ft_win.set_status(file_props['type'], file_props['sid'], 'ok') ft_win.set_status(file_props, 'ok')
else: else:
# wrong hash, we need to get the file again! # wrong hash, we need to get the file again!
file_props['error'] = -10 file_props.error = -10
self.popup_ft_result(account, jid, file_props) self.popup_ft_result(account, jid, file_props)
ft_win.set_status(file_props['type'], file_props['sid'], ft_win.set_status(file_props, 'hash_error')
'hash_error')
# End jingle session # End jingle session
if session: if session:
session.end_session() session.end_session()
def handle_event_file_rcv_completed(self, account, file_props): def handle_event_file_rcv_completed(self, account, file_props):
ft = self.instances['file_transfers'] ft = self.instances['file_transfers']
if file_props['error'] == 0: if file_props.error == 0:
ft.set_progress(file_props['type'], file_props['sid'], ft.set_progress(file_props.type_, file_props.sid,
file_props['received-len']) file_props.received_len)
else: else:
ft.set_status(file_props['type'], file_props['sid'], 'stop') ft.set_status(file_props, 'stop')
if 'stalled' in file_props and file_props['stalled'] or \ if file_props.stalled or file_props.paused:
'paused' in file_props and file_props['paused']:
return return
if file_props['type'] == 'r': # we receive a file if file_props.type_ == 'r': # we receive a file
# If we have a jingle session id, it is a jingle transfer # If we have a jingle session id, it is a jingle transfer
# we compare hashes # we compare hashes
if 'session-sid' in file_props: if file_props.session_sid:
# Compare hashes in a new thread # Compare hashes in a new thread
self.hashThread = Thread(target=self.__compare_hashes, self.hashThread = Thread(target=self.__compare_hashes,
args=(account, file_props)) args=(account, file_props))
self.hashThread.start() self.hashThread.start()
gajim.socks5queue.remove_receiver(file_props['sid'], True, True) gajim.socks5queue.remove_receiver(file_props.sid, True, True)
else: # we send a file else: # we send a file
jid = unicode(file_props['receiver']) jid = unicode(file_props.receiver)
gajim.socks5queue.remove_sender(file_props['sid'], True, True) gajim.socks5queue.remove_sender(file_props.sid, True, True)
self.popup_ft_result(account, jid, file_props) self.popup_ft_result(account, jid, file_props)
def popup_ft_result(self, account, jid, file_props): def popup_ft_result(self, account, jid, file_props):
ft = self.instances['file_transfers'] ft = self.instances['file_transfers']
if helpers.allow_popup_window(account): if helpers.allow_popup_window(account):
if file_props['error'] == 0: if file_props.error == 0:
if gajim.config.get('notify_on_file_complete'): if gajim.config.get('notify_on_file_complete'):
ft.show_completed(jid, file_props) ft.show_completed(jid, file_props)
elif file_props['error'] == -1: elif file_props.error == -1:
ft.show_stopped(jid, file_props, ft.show_stopped(jid, file_props,
error_msg=_('Remote contact stopped transfer')) error_msg=_('Remote contact stopped transfer'))
elif file_props['error'] == -6: elif file_props.error == -6:
ft.show_stopped(jid, file_props, ft.show_stopped(jid, file_props,
error_msg=_('Error opening file')) error_msg=_('Error opening file'))
elif file_props['error'] == -10: elif file_props.error == -10:
ft.show_hash_error(jid, file_props, account) ft.show_hash_error(jid, file_props, account)
return return
msg_type = '' msg_type = ''
event_type = '' event_type = ''
if file_props['error'] == 0 and gajim.config.get( if file_props.error == 0 and gajim.config.get(
'notify_on_file_complete'): 'notify_on_file_complete'):
msg_type = 'file-completed' msg_type = 'file-completed'
event_type = _('File Transfer Completed') event_type = _('File Transfer Completed')
elif file_props['error'] in (-1, -6): elif file_props.error in (-1, -6):
msg_type = 'file-stopped' msg_type = 'file-stopped'
event_type = _('File Transfer Stopped') event_type = _('File Transfer Stopped')
elif file_props['error'] == -10: elif file_props.error == -10:
msg_type = 'file-hash-error' msg_type = 'file-hash-error'
event_type = _('File Transfer Failed') event_type = _('File Transfer Failed')
@ -1017,12 +1015,12 @@ class Interface:
self.add_event(account, jid, msg_type, file_props) self.add_event(account, jid, msg_type, file_props)
if file_props is not None: if file_props is not None:
if file_props['type'] == 'r': if file_props.type_ == 'r':
# get the name of the sender, as it is in the roster # get the name of the sender, as it is in the roster
sender = unicode(file_props['sender']).split('/')[0] sender = unicode(file_props.sender).split('/')[0]
name = gajim.contacts.get_first_contact_from_jid(account, name = gajim.contacts.get_first_contact_from_jid(account,
sender).get_shown_name() sender).get_shown_name()
filename = os.path.basename(file_props['file-name']) filename = os.path.basename(file_props.file_name)
if event_type == _('File Transfer Completed'): if event_type == _('File Transfer Completed'):
txt = _('You successfully received %(filename)s from ' txt = _('You successfully received %(filename)s from '
'%(name)s.') % {'filename': filename, 'name': name} '%(name)s.') % {'filename': filename, 'name': name}
@ -1036,14 +1034,14 @@ class Interface:
'failed.') % {'filename': filename, 'name': name} 'failed.') % {'filename': filename, 'name': name}
img_name = 'gajim-ft_stopped' img_name = 'gajim-ft_stopped'
else: else:
receiver = file_props['receiver'] receiver = file_props.receiver
if hasattr(receiver, 'jid'): if hasattr(receiver, 'jid'):
receiver = receiver.jid receiver = receiver.jid
receiver = receiver.split('/')[0] receiver = receiver.split('/')[0]
# get the name of the contact, as it is in the roster # get the name of the contact, as it is in the roster
name = gajim.contacts.get_first_contact_from_jid(account, name = gajim.contacts.get_first_contact_from_jid(account,
receiver).get_shown_name() receiver).get_shown_name()
filename = os.path.basename(file_props['file-name']) filename = os.path.basename(file_props.file_name)
if event_type == _('File Transfer Completed'): if event_type == _('File Transfer Completed'):
txt = _('You successfully sent %(filename)s to %(name)s.')\ txt = _('You successfully sent %(filename)s to %(name)s.')\
% {'filename': filename, 'name': name} % {'filename': filename, 'name': name}
@ -1164,17 +1162,10 @@ class Interface:
def handle_event_jingleft_cancel(self, obj): def handle_event_jingleft_cancel(self, obj):
ft = self.instances['file_transfers'] ft = self.instances['file_transfers']
file_props = None file_props = None
# get the file_props of our session # get the file_props of our session
for sid in obj.conn.files_props: file_props = FilesProp.getFileProp(obj.conn.name, sid)
fp = obj.conn.files_props[sid] ft.set_status(file_props, 'stop')
if fp['session-sid'] == obj.sid: file_props.error = -4 # is it the right error code?
file_props = fp
break
ft.set_status(file_props['type'], file_props['sid'], 'stop')
file_props['error'] = -4 # is it the right error code?
ft.show_stopped(obj.jid, file_props, 'Peer cancelled ' + ft.show_stopped(obj.jid, file_props, 'Peer cancelled ' +
'the transfer') 'the transfer')

View File

@ -730,23 +730,23 @@ class FileTransfersTooltip(BaseTooltip):
current_row = 1 current_row = 1
self.create_window() self.create_window()
properties = [] properties = []
name = file_props['name'] name = file_props.name
if file_props['type'] == 'r': if file_props.type_ == 'r':
file_name = os.path.split(file_props['file-name'])[1] file_name = os.path.split(file_props.file_name)[1]
else: else:
file_name = file_props['name'] file_name = file_props.name
properties.append((_('Name: '), properties.append((_('Name: '),
gobject.markup_escape_text(file_name))) gobject.markup_escape_text(file_name)))
if file_props['type'] == 'r': if file_props.type_ == 'r':
type_ = _('Download') type_ = _('Download')
actor = _('Sender: ') actor = _('Sender: ')
sender = unicode(file_props['sender']).split('/')[0] sender = unicode(file_props.sender).split('/')[0]
name = gajim.contacts.get_first_contact_from_jid( name = gajim.contacts.get_first_contact_from_jid(
file_props['tt_account'], sender).get_shown_name() file_props.tt_account, sender).get_shown_name()
else: else:
type_ = _('Upload') type_ = _('Upload')
actor = _('Recipient: ') actor = _('Recipient: ')
receiver = file_props['receiver'] receiver = file_props.receiver
if hasattr(receiver, 'name'): if hasattr(receiver, 'name'):
name = receiver.get_shown_name() name = receiver.get_shown_name()
else: else:
@ -754,26 +754,24 @@ class FileTransfersTooltip(BaseTooltip):
properties.append((_('Type: '), type_)) properties.append((_('Type: '), type_))
properties.append((actor, gobject.markup_escape_text(name))) properties.append((actor, gobject.markup_escape_text(name)))
transfered_len = file_props.get('received-len', 0) transfered_len = file_props.received_len
if not transfered_len:
transfered_len = 0
properties.append((_('Transferred: '), helpers.convert_bytes(transfered_len))) properties.append((_('Transferred: '), helpers.convert_bytes(transfered_len)))
status = '' status = ''
if 'started' not in file_props or not file_props['started']: if file_props.started:
status = _('Not started') status = _('Not started')
elif 'connected' in file_props: if file_props.stopped == True:
if 'stopped' in file_props and \ status = _('Stopped')
file_props['stopped'] == True: elif file_props.completed:
status = _('Stopped') status = _('Completed')
elif file_props['completed']: elif file_props.connected == False:
if file_props.completed:
status = _('Completed') status = _('Completed')
elif file_props['connected'] == False:
if file_props['completed']:
status = _('Completed')
else: else:
if 'paused' in file_props and \ if file_props.paused == True:
file_props['paused'] == True:
status = _('?transfer status:Paused') status = _('?transfer status:Paused')
elif 'stalled' in file_props and \ elif file_props.stalled == True:
file_props['stalled'] == True:
#stalled is not paused. it is like 'frozen' it stopped alone #stalled is not paused. it is like 'frozen' it stopped alone
status = _('Stalled') status = _('Stalled')
else: else:
@ -781,10 +779,9 @@ class FileTransfersTooltip(BaseTooltip):
else: else:
status = _('Not started') status = _('Not started')
properties.append((_('Status: '), status)) properties.append((_('Status: '), status))
if 'desc' in file_props: file_desc = file_props.desc
file_desc = file_props['desc'] properties.append((_('Description: '), gobject.markup_escape_text(
properties.append((_('Description: '), gobject.markup_escape_text( file_desc)))
file_desc)))
while properties: while properties:
property_ = properties.pop(0) property_ = properties.pop(0)
current_row += 1 current_row += 1