Jingle FT is now functionnal!! Thanks Jefry for the long time debugging with me

This commit is contained in:
Yann Leboulanger 2012-08-23 13:10:30 +02:00
commit 96dd70050b
28 changed files with 1096 additions and 1065 deletions

View file

@ -371,7 +371,7 @@ class CommandWindow:
_('The form is not filled correctly.'))
self.data_form_widget.set_sensitive(True)
return
self.data_form_widget.data_form.type = 'submit'
self.data_form_widget.data_form.type_ = 'submit'
else:
self.data_form_widget.hide()

View file

@ -1737,8 +1737,8 @@ class ChatControl(ChatControlBase):
# Send file
if (self.contact.supports(NS_FILE) or \
self.contact.supports(NS_JINGLE_FILE_TRANSFER)) or \
self.type_id == 'chat' or self.gc_contact.resource:
self.contact.supports(NS_JINGLE_FILE_TRANSFER)) or \
self.type_id == 'chat' or self.gc_contact.resource:
self._send_file_button.set_sensitive(True)
self._send_file_button.set_tooltip_text('')
else:
@ -3223,11 +3223,11 @@ class ChatControl(ChatControlBase):
"""
Show an InfoBar on top of control
"""
markup = '<b>%s:</b> %s' % (_('File transfer'), file_props['name'])
if 'desc' in file_props and file_props['desc']:
markup += ' (%s)' % file_props['desc']
markup = '<b>%s:</b> %s' % (_('File transfer'), file_props.name)
if file_props.desc:
markup += ' (%s)' % file_props.desc
markup += '\n%s: %s' % (_('Size'), helpers.convert_bytes(
file_props['size']))
file_props.size))
b1 = gtk.Button(_('_Accept'))
b1.connect('clicked', self._on_accept_file_request, file_props)
b2 = gtk.Button(stock=gtk.STOCK_CANCEL)
@ -3236,9 +3236,7 @@ class ChatControl(ChatControlBase):
gtk.MESSAGE_QUESTION)
def _on_open_ft_folder(self, widget, file_props):
if 'file-name' not in file_props:
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):
helpers.launch_file_manager(path)
ev = self._get_file_props_event(file_props, 'file-completed')
@ -3252,9 +3250,9 @@ class ChatControl(ChatControlBase):
def _got_file_completed(self, file_props):
markup = '<b>%s:</b> %s' % (_('File transfer completed'),
file_props['name'])
if 'desc' in file_props and file_props['desc']:
markup += ' (%s)' % file_props['desc']
file_props.name)
if file_props.desc:
markup += ' (%s)' % file_props.desc
b1 = gtk.Button(_('_Open Containing Folder'))
b1.connect('clicked', self._on_open_ft_folder, file_props)
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.xmpp.protocol import NS_CHATSTATES
from common.jingle_transport import JingleTransportSocks5
from common.file_props import FilesProp
import gtkgui_helpers
@ -1684,7 +1685,7 @@ class PEPReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
pep = pep_class.get_tag_as_PEP(self.fjid, self.conn.name,
self.event_tag)
if pep:
self.pep_type = pep.type
self.pep_type = pep.type_
return True
items = self.event_tag.getTag('items')
@ -1942,16 +1943,59 @@ class FileRequestReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
self.get_id()
self.fjid = self.conn._ft_get_from(self.stanza)
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:
self.file_props['session-type'] = 'jingle'
self.file_props['stream-methods'] = xmpp.NS_BYTESTREAM
file_tag = self.jingle_content.getTag('description').getTag(
'offer').getTag('file')
self.FT_content.use_security = bool(self.jingle_content.getTag(
'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(
'offer').getTag('file')
for child in file_tag.getChildren():
name = child.getName()
val = child.getData()
if val is None:
continue
if name == 'name':
self.file_props.name = val
if name == 'size':
self.file_props.size = val
if name == 'hash':
self.file_props.algo = child.getAttr('algo')
self.file_props.hash_ = val
if name == 'date':
self.file_props.date = val
else:
profile = si.getAttr('profile')
if profile != xmpp.NS_FILE:
self.conn.send_file_rejection(self.file_props, code='400',
@ -1965,9 +2009,9 @@ class FileRequestReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
return
self.dataform = dataforms.ExtendForm(node=form_tag)
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]
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:
break
else:
@ -1975,56 +2019,25 @@ class FileRequestReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
typ='stream')
raise xmpp.NodeProcessed
file_tag = si.getTag('file')
for child in file_tag.getChildren():
name = child.getName()
if name in ('name', 'size', 'hash', 'date'):
val = child.getData()
for name, val in file_tag.getAttrs().items():
if val is None:
continue
self.file_props[name] = val
# Delete this, it shouldn't be necesary after file_props gets
# refactored.
if name == 'hash':
self.file_props['algo'] = child.getAttr('algo')
if name == 'name':
self.file_props.name = val
if name == 'size':
self.file_props.size = val
file_desc_tag = file_tag.getTag('desc')
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:
mime_type = si.getAttr('mime-type')
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['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.file_props.receiver = self.conn._ft_get_our_jid()
self.file_props.transfered_size = []
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
class FileRequestErrorEvent(nec.NetworkIncomingEvent):

View file

@ -120,7 +120,7 @@ class DataField(ExtendedNode):
if extend is None:
ExtendedNode.__init__(self, 'field')
self.type = typ
self.type_ = typ
self.var = var
if value is not None:
self.value = value
@ -248,7 +248,7 @@ class DataField(ExtendedNode):
self.delChild(t)
return locals()
def is_valid(self):
return True
@ -463,7 +463,7 @@ class ListMultiField(ListField):
def iter_values(self):
for element in self.getTags('value'):
yield element.getData()
def is_valid(self):
if not self.required:
return True
@ -577,7 +577,7 @@ class DataRecord(ExtendedNode):
def __getitem__(self, item):
return self.vars[item]
def is_valid(self):
for f in self.iter_fields():
if not f.is_valid():

156
src/common/file_props.py Normal file
View file

@ -0,0 +1,156 @@
"""
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
self.request_id = None
self.proxyhosts = None
self.dstaddr = 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

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

View file

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

View file

@ -55,10 +55,11 @@ class JingleFileTransfer(JingleContent):
# events we might be interested in
self.callbacks['session-initiate'] += [self.__on_session_initiate]
self.callbacks['session-initiate-sent'] += [self.__on_session_initiate_sent]
self.callbacks['session-initiate-sent'] += [
self.__on_session_initiate_sent]
self.callbacks['content-add'] += [self.__on_session_initiate]
self.callbacks['session-accept'] += [self.__on_session_accept]
self.callbacks['session-terminate'] += [self.__on_session_terminate]
self.callbacks['session-terminate'] += [self.__on_session_terminate]
self.callbacks['session-info'] += [self.__on_session_info]
self.callbacks['transport-accept'] += [self.__on_transport_accept]
self.callbacks['transport-replace'] += [self.__on_transport_replace]
@ -77,11 +78,11 @@ class JingleFileTransfer(JingleContent):
self.weinitiate = True
if self.file_props is not None:
self.file_props['sender'] = session.ourjid
self.file_props['receiver'] = session.peerjid
self.file_props['session-type'] = 'jingle'
self.file_props['session-sid'] = session.sid
self.file_props['transfered_size'] = []
self.file_props.sender = session.ourjid
self.file_props.receiver = session.peerjid
self.file_props.session_type = 'jingle'
self.file_props.session_sid = session.sid
self.file_props.transfered_size = []
log.info("FT request: %s" % file_props)
@ -92,19 +93,15 @@ class JingleFileTransfer(JingleContent):
self.transport.set_our_jid(session.ourjid)
log.info('ourjid: %s' % session.ourjid)
if self.file_props is not None:
self.file_props['sid'] = self.transport.sid
self.session = session
self.media = 'file'
self.nominated_cand = {}
if gajim.contacts.is_gc_contact(session.connection.name,
session.peerjid):
if gajim.contacts.is_gc_contact(session.connection.name,
session.peerjid):
roomjid = session.peerjid.split('/')[0]
dstaddr = hashlib.sha1('%s%s%s' % (self.file_props['sid'],
session.ourjid,
roomjid)).hexdigest()
self.file_props['dstaddr'] = dstaddr
session.ourjid, roomjid)).hexdigest()
self.file_props.dstaddr = dstaddr
self.state = STATE_NOT_STARTED
self.states = {STATE_INITIALIZED : StateInitialized(self),
STATE_CAND_SENT : StateCandSent(self),
@ -112,45 +109,46 @@ class JingleFileTransfer(JingleContent):
STATE_TRANSFERING : StateTransfering(self),
STATE_TRANSPORT_REPLACE : StateTransportReplace(self),
STATE_CAND_SENT_AND_RECEIVED : StateCandSentAndRecv(self)
}
}
def __state_changed(self, nextstate, args=None):
# Executes the next state action and sets the next state
current_state = self.state
st = self.states[nextstate]
st.action(args)
self.state = nextstate
# state can have been changed during the action. Don't go back.
if self.state == current_state:
self.state = nextstate
def __on_session_initiate(self, stanza, content, error, action):
gajim.nec.push_incoming_event(FileRequestReceivedEvent(None,
conn=self.session.connection, stanza=stanza, jingle_content=content,
FT_content=self))
self._listen_host()
self._listen_host()
# Delete this after file_props refactoring this shouldn't be necesary
self.session.file_hash = self.file_props['hash']
self.session.hash_algo = self.file_props['algo']
self.session.file_hash = self.file_props.hash_
self.session.hash_algo = self.file_props.algo
def __on_session_initiate_sent(self, stanza, content, error, action):
# Calculate file_hash in a new thread
# 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.start()
def __send_hash(self):
# Send hash in a session info
checksum = xmpp.Node(tag='checksum',
payload=[xmpp.Node(tag='file',
payload=[self._calcHash()])])
checksum = xmpp.Node(tag='checksum', payload=[xmpp.Node(tag='file',
payload=[self._calcHash()])])
checksum.setNamespace(xmpp.NS_JINGLE_FILE_TRANSFER)
self.session.__session_info(checksum )
def _calcHash(self):
# Caculates the hash and returns a xep-300 hash stanza
if self.session.hash_algo == None:
return
try:
file_ = open(self.file_props['file-name'], 'r')
file_ = open(self.file_props.file_name, 'r')
except:
# can't open file
return
@ -161,10 +159,10 @@ class JingleFileTransfer(JingleContent):
if not hash_:
# Hash alogrithm not supported
return
self.file_props['hash'] = hash_
self.file_props.hash_ = hash_
h.addHash(hash_, self.session.hash_algo)
return h
def __on_session_accept(self, stanza, content, error, action):
log.info("__on_session_accept")
con = self.session.connection
@ -182,26 +180,21 @@ class JingleFileTransfer(JingleContent):
self.__state_changed(STATE_TRANSFERING)
raise xmpp.NodeProcessed
self.file_props['streamhosts'] = self.transport.remote_candidates
for host in self.file_props['streamhosts']:
self.file_props.streamhosts = self.transport.remote_candidates
for host in self.file_props.streamhosts:
host['initiator'] = self.session.initiator
host['target'] = self.session.responder
host['sid'] = self.file_props['sid']
host['sid'] = self.file_props.sid
response = stanza.buildReply('result')
response.delChild(response.getQuery())
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
if self.use_security:
fingerprint = 'client'
if self.transport.type == TransportType.SOCKS5:
if self.transport.type_ == TransportType.SOCKS5:
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,
receiving=False)
return
@ -213,7 +206,7 @@ class JingleFileTransfer(JingleContent):
def __on_session_info(self, stanza, content, error, action):
pass
def __on_transport_accept(self, stanza, content, error, action):
log.info("__on_transport_accept")
@ -280,15 +273,15 @@ class JingleFileTransfer(JingleContent):
return
# initiate transfer
self.__state_changed(STATE_TRANSFERING)
def __transport_setup(self, stanza=None, content=None, error=None,
action=None):
# Sets up a few transport specific things for the file transfer
if self.transport.type == TransportType.IBB:
if self.transport.type_ == TransportType.IBB:
# No action required, just set the state to transfering
self.state = STATE_TRANSFERING
def on_connect(self, streamhost):
"""
@ -317,15 +310,15 @@ class JingleFileTransfer(JingleContent):
def _store_socks5_sid(self, sid, hash_id):
# callback from socsk5queue.start_listener
self.file_props['hash'] = hash_id
self.file_props.hash_ = hash_id
def _listen_host(self):
receiver = self.file_props['receiver']
sender = self.file_props['sender']
sha_str = helpers.get_auth_sha(self.file_props['sid'], sender,
receiver = self.file_props.receiver
sender = self.file_props.sender
sha_str = helpers.get_auth_sha(self.file_props.sid, sender,
receiver)
self.file_props['sha_str'] = sha_str
self.file_props.sha_str = sha_str
port = gajim.config.get('file_transfers_port')
@ -336,11 +329,11 @@ class JingleFileTransfer(JingleContent):
if self.weinitiate:
listener = gajim.socks5queue.start_listener(port, sha_str,
self._store_socks5_sid, self.file_props,
fingerprint=fingerprint, type='sender')
fingerprint=fingerprint, typ='sender')
else:
listener = gajim.socks5queue.start_listener(port, sha_str,
self._store_socks5_sid, self.file_props,
fingerprint=fingerprint, type='receiver')
fingerprint=fingerprint, typ='receiver')
if not listener:
# send error message, notify the user

View file

@ -14,13 +14,14 @@
import gajim
import xmpp
from jingle_transport import *
from common.socks5 import Socks5ReceiverClient, Socks5SenderClient
class JingleFileTransferStates:
# This class implements the state machine design pattern
'''
This class implements the state machine design pattern
'''
def __init__(self, jingleft):
self.jft = jingleft
def action(self, args=None):
@ -31,37 +32,26 @@ class JingleFileTransferStates:
class StateInitialized(JingleFileTransferStates):
'''
This state initializes the file transfer
'''
def action(self, args=None):
self.jft._listen_host()
if self.jft.weinitiate:
# update connection's fileprops
self.jft.session.connection.files_props[self.jft.file_props['sid']] = \
self.jft.file_props
self.jft._listen_host()
# Listen on configured port for file transfer
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
if self.jft.use_security:
fingerprint = 'client'
# Connect to the candidate host, on success call on_connect method
gajim.socks5queue.connect_to_hosts(
self.jft.session.connection.name,
self.jft.file_props['sid'], self.jft.on_connect,
self.jft._on_connect_error, fingerprint=fingerprint)
gajim.socks5queue.connect_to_hosts(self.jft.session.connection.name,
self.jft.file_props.sid, self.jft.on_connect,
self.jft._on_connect_error, fingerprint=fingerprint)
class StateCandSent(JingleFileTransferStates):
'''
This state sends our nominated candidate
'''
@ -96,7 +86,6 @@ class StateCandSent(JingleFileTransferStates):
self._sendCand(args)
class StateCandReceived(JingleFileTransferStates):
'''
This state happens when we receive a candidate.
It takes the arguments: canError if we receive a candidate-error
@ -119,13 +108,10 @@ class StateCandReceived(JingleFileTransferStates):
# We save the candidate nominated by peer
self.jft.nominated_cand['peer-cand'] = streamhost_used
def action(self, args=None):
self._recvCand(args)
class StateCandSentAndRecv( StateCandSent, StateCandReceived):
'''
This state happens when we have received and sent the candidates.
It takes the boolean argument: sendCand in order to decide whether
@ -133,14 +119,12 @@ class StateCandSentAndRecv( StateCandSent, StateCandReceived):
'''
def action(self, args=None):
if args['sendCand']:
self._sendCand(args)
else:
self._recvCand(args)
class StateTransportReplace(JingleFileTransferStates):
'''
This state initiates transport replace
'''
@ -149,18 +133,15 @@ class StateTransportReplace(JingleFileTransferStates):
self.jft.session.transport_replace()
class StateTransfering(JingleFileTransferStates):
'''
This state will start the transfer depeding on the type of transport
we have.
'''
def __start_IBB_transfer(self, con):
con.files_props[self.jft.file_props['sid']] = \
self.jft.file_props
fp = open(self.jft.file_props['file-name'], 'r')
con.OpenStream( self.jft.transport.sid,
self.jft.session.peerjid, fp, blocksize=4096)
fp = open(self.jft.file_props.file_name, 'r')
con.OpenStream( self.jft.transport.sid, self.jft.session.peerjid, fp,
blocksize=4096)
def __start_SOCK5_transfer(self):
# It tells wether we start the transfer as client or server
@ -172,16 +153,17 @@ class StateTransfering(JingleFileTransferStates):
else:
mode = 'server'
streamhost_used = self.jft.nominated_cand['peer-cand']
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
if self.jft.weinitiate:
self.jft.file_props['proxy_sender'] = streamhost_used['initiator']
self.jft.file_props['proxy_receiver'] = streamhost_used['target']
self.jft.file_props.proxy_sender = streamhost_used['initiator']
self.jft.file_props.proxy_receiver = streamhost_used['target']
else:
self.jft.file_props['proxy_sender'] = streamhost_used['target']
self.jft.file_props['proxy_receiver'] = streamhost_used['initiator']
self.jft.file_props.proxy_sender = streamhost_used['target']
self.jft.file_props.proxy_receiver = streamhost_used[
'initiator']
# This needs to be changed when requesting
if not self.jft.weinitiate and streamhost_used['type'] == 'proxy':
@ -199,13 +181,13 @@ class StateTransfering(JingleFileTransferStates):
s[sender].connected:
return
if streamhost_used['type'] == 'proxy':
self.jft.file_props['streamhost-used'] = True
streamhost_used['sid'] = self.jft.file_props['sid']
self.jft.file_props['streamhosts'] = []
self.jft.file_props['streamhosts'].append(streamhost_used)
self.jft.file_props['proxyhosts'] = []
self.jft.file_props['proxyhosts'].append(streamhost_used)
if streamhost_used['type'] == 'proxy':
self.jft.file_props.streamhost_used = True
streamhost_used['sid'] = self.jft.file_props.sid
self.jft.file_props.streamhosts = []
self.jft.file_props.streamhosts.append(streamhost_used)
self.jft.file_props.proxyhosts = []
self.jft.file_props.proxyhosts.append(streamhost_used)
# This needs to be changed when requesting
if self.jft.weinitiate:
@ -218,7 +200,7 @@ class StateTransfering(JingleFileTransferStates):
connected=False, file_props=self.jft.file_props)
else:
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)
sockobj.proxy = True
sockobj.streamhost = streamhost_used
@ -228,7 +210,7 @@ class StateTransfering(JingleFileTransferStates):
# If we offered the nominated candidate used, we activate
# the proxy
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
# TODO: add on failure
else:
@ -237,8 +219,8 @@ class StateTransfering(JingleFileTransferStates):
self.jft.session.connection.name, mode)
def action(self, args=None):
if self.jft.transport.type == TransportType.IBB:
if self.jft.transport.type_ == TransportType.IBB:
self.__start_IBB_transfer(self.jft.session.connection)
elif self.jft.transport.type == TransportType.SOCKS5:
elif self.jft.transport.type_ == TransportType.SOCKS5:
self.__start_SOCK5_transfer()

View file

@ -47,7 +47,7 @@ class JingleTransport(object):
"""
def __init__(self, type_):
self.type = type_
self.type_ = type_
self.candidates = []
self.remote_candidates = []
@ -78,7 +78,7 @@ class JingleTransport(object):
Return the list of transport candidates from a transport stanza
"""
return []
def set_connection(self, conn):
self.connection = conn
if not self.sid:
@ -89,7 +89,7 @@ class JingleTransport(object):
def set_our_jid(self, jid):
self.ourjid = jid
def set_sid(self, sid):
self.sid = sid
@ -132,8 +132,8 @@ class JingleTransportSocks5(JingleTransport):
transport = xmpp.Node('transport')
transport.setNamespace(xmpp.NS_JINGLE_BYTESTREAM)
transport.setAttr('sid', self.sid)
if 'dstaddr' in self.file_props:
transport.setAttr('dstaddr', self.file_props['dstaddr'])
if self.file_props.dstaddr:
transport.setAttr('dstaddr', self.file_props.dstaddr)
return transport
def parse_transport_stanza(self, transport):
@ -170,6 +170,9 @@ class JingleTransportSocks5(JingleTransport):
self.candidates.append(cand)
def _add_local_ips_as_candidates(self):
if not gajim.config.get_per('accounts', self.connection.name,
'ft_send_local_ips'):
return
if not self.connection:
return
local_ip_cand = []
@ -192,8 +195,8 @@ class JingleTransportSocks5(JingleTransport):
c['type'] = 'direct'
c['jid'] = self.ourjid
c['priority'] = (2**16) * type_preference
c['initiator'] = self.file_props['sender']
c['target'] = self.file_props['receiver']
c['initiator'] = self.file_props.sender
c['target'] = self.file_props.receiver
local_ip_cand.append(c)
self._add_candidates(local_ip_cand)
@ -215,8 +218,8 @@ class JingleTransportSocks5(JingleTransport):
c['type'] = 'direct'
c['jid'] = self.ourjid
c['priority'] = (2**16) * type_preference
c['initiator'] = self.file_props['sender']
c['target'] = self.file_props['receiver']
c['initiator'] = self.file_props.sender
c['target'] = self.file_props.receiver
additional_ip_cand.append(c)
self._add_candidates(additional_ip_cand)
@ -230,7 +233,7 @@ class JingleTransportSocks5(JingleTransport):
proxyhosts = socks5conn._get_file_transfer_proxies_from_config(self.file_props)
if proxyhosts:
self.file_props['proxyhosts'] = proxyhosts
self.file_props.proxyhosts = proxyhosts
for proxyhost in proxyhosts:
c = {'host': proxyhost['host']}
@ -239,15 +242,15 @@ class JingleTransportSocks5(JingleTransport):
c['type'] = 'proxy'
c['jid'] = proxyhost['jid']
c['priority'] = (2**16) * type_preference
c['initiator'] = self.file_props['sender']
c['target'] = self.file_props['receiver']
c['initiator'] = self.file_props.sender
c['target'] = self.file_props.receiver
proxy_cand.append(c)
self._add_candidates(proxy_cand)
def get_content(self):
sesn = self.connection.get_jingle_session(self.ourjid,
self.file_props['session-sid'])
self.file_props.session_sid)
for content in sesn.contents.values():
if content.transport == self:
return content
@ -258,10 +261,10 @@ class JingleTransportSocks5(JingleTransport):
if not self.connection:
return
sesn = self.connection.get_jingle_session(self.ourjid,
self.file_props['session-sid'])
self.file_props.session_sid)
if sesn is None:
return
iq = xmpp.Iq(to=proxy['jid'], frm=self.ourjid, typ='set')
auth_id = "au_" + proxy['sid']
iq.setID(auth_id)
@ -323,7 +326,7 @@ class JingleTransportIBB(JingleTransport):
transport.setAttr('block-size', self.block_sz)
transport.setAttr('sid', self.sid)
return transport
try:
import farstream
except Exception:

View file

@ -63,8 +63,8 @@ def load_cert_file(cert_path, cert_store):
try:
f = open(cert_path)
except IOError, e:
log.warning('Unable to open certificate file %s: %s' % \
(cert_path, str(e)))
log.warning('Unable to open certificate file %s: %s' % (cert_path,
str(e)))
return
lines = f.readlines()
i = 0
@ -76,14 +76,14 @@ def load_cert_file(cert_path, cert_store):
cert = ''.join(lines[begin:i+2])
try:
x509cert = OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_PEM, cert)
OpenSSL.crypto.FILETYPE_PEM, cert)
cert_store.add_cert(x509cert)
except OpenSSL.crypto.Error, exception_obj:
log.warning('Unable to load a certificate from file %s: %s' %\
(cert_path, exception_obj.args[0][0][2]))
(cert_path, exception_obj.args[0][0][2]))
except:
log.warning('Unknown error while loading certificate from file '
'%s' % cert_path)
'%s' % cert_path)
begin = -1
i += 1
@ -94,7 +94,8 @@ def get_context(fingerprint, verify_cb=None):
ctx = SSL.Context(SSL.TLSv1_METHOD)
if fingerprint == 'server': # for testing purposes only
ctx.set_verify(SSL.VERIFY_NONE|SSL.VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb or default_callback)
ctx.set_verify(SSL.VERIFY_NONE|SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
verify_cb or default_callback)
elif fingerprint == 'client':
ctx.set_verify(SSL.VERIFY_PEER, verify_cb or default_callback)
@ -103,13 +104,15 @@ def get_context(fingerprint, verify_cb=None):
ctx.use_certificate_file(cert_name + '.cert')
store = ctx.get_cert_store()
for f in os.listdir(os.path.expanduser(gajim.MY_PEER_CERTS_PATH)):
load_cert_file(os.path.join(os.path.expanduser(gajim.MY_PEER_CERTS_PATH), f), store)
load_cert_file(os.path.join(os.path.expanduser(
gajim.MY_PEER_CERTS_PATH), f), store)
log.debug('certificate file ' + f + ' loaded fingerprint ' + \
fingerprint)
return ctx
def send_cert(con, jid_from, sid):
certpath = os.path.join(gajim.MY_CERT_DIR, SELF_SIGNED_CERTIFICATE) + '.cert'
certpath = os.path.join(gajim.MY_CERT_DIR, SELF_SIGNED_CERTIFICATE) + \
'.cert'
certfile = open(certpath, 'r')
certificate = ''
for line in certfile.readlines():
@ -225,14 +228,17 @@ def createCertificate(req, (issuerCert, issuerKey), serial, (notBefore, notAfter
def make_certs(filepath, CN):
"""
make self signed certificates
filepath : absolute path of certificate file, will be appended the '.pkey' and '.cert' extensions
filepath : absolute path of certificate file, will be appended the '.pkey'
and '.cert' extensions
CN : common name
"""
key = createKeyPair(TYPE_RSA, 1024)
req = createCertRequest(key, CN=CN)
cert = createCertificate(req, (req, key), 0, (0, 60*60*24*365*5)) # five years
open(filepath + '.pkey', 'w').write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key))
open(filepath + '.cert', 'w').write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
open(filepath + '.pkey', 'w').write(crypto.dump_privatekey(
crypto.FILETYPE_PEM, key))
open(filepath + '.cert', 'w').write(crypto.dump_certificate(
crypto.FILETYPE_PEM, cert))
if __name__ == '__main__':

View file

@ -211,14 +211,14 @@ import gtkgui_helpers
class AbstractPEP(object):
type = ''
type_ = ''
namespace = ''
@classmethod
def get_tag_as_PEP(cls, jid, account, event_tag):
items = event_tag.getTag('items', {'node': cls.namespace})
if items:
log.debug("Received PEP 'user %s' from %s" % (cls.type, jid))
log.debug("Received PEP 'user %s' from %s" % (cls.type_, jid))
return cls(jid, account, items)
else:
return None
@ -237,18 +237,18 @@ class AbstractPEP(object):
def _update_contacts(self, jid, account):
for contact in gajim.contacts.get_contacts(account, jid):
if self._retracted:
if self.type in contact.pep:
del contact.pep[self.type]
if self.type_ in contact.pep:
del contact.pep[self.type_]
else:
contact.pep[self.type] = self
contact.pep[self.type_] = self
def _update_account(self, account):
acc = gajim.connections[account]
if self._retracted:
if self.type in acc.pep:
del acc.pep[self.type]
if self.type_ in acc.pep:
del acc.pep[self.type_]
else:
acc.pep[self.type] = self
acc.pep[self.type_] = self
def asPixbufIcon(self):
'''SHOULD be implemented by subclasses'''
@ -262,7 +262,7 @@ class AbstractPEP(object):
class UserMoodPEP(AbstractPEP):
'''XEP-0107: User Mood'''
type = 'mood'
type_ = 'mood'
namespace = xmpp.NS_MOOD
def _extract_info(self, items):
@ -308,7 +308,7 @@ class UserMoodPEP(AbstractPEP):
class UserTunePEP(AbstractPEP):
'''XEP-0118: User Tune'''
type = 'tune'
type_ = 'tune'
namespace = xmpp.NS_TUNE
def _extract_info(self, items):
@ -354,7 +354,7 @@ class UserTunePEP(AbstractPEP):
class UserActivityPEP(AbstractPEP):
'''XEP-0108: User Activity'''
type = 'activity'
type_ = 'activity'
namespace = xmpp.NS_ACTIVITY
def _extract_info(self, items):
@ -420,7 +420,7 @@ class UserActivityPEP(AbstractPEP):
class UserNicknamePEP(AbstractPEP):
'''XEP-0172: User Nickname'''
type = 'nickname'
type_ = 'nickname'
namespace = xmpp.NS_NICK
def _extract_info(self, items):
@ -449,7 +449,7 @@ class UserNicknamePEP(AbstractPEP):
class UserLocationPEP(AbstractPEP):
'''XEP-0080: User Location'''
type = 'location'
type_ = 'location'
namespace = xmpp.NS_LOCATION
def _extract_info(self, items):

View file

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

View file

@ -31,6 +31,7 @@ from common import gajim
from common import helpers
from socks5 import Socks5
from common.xmpp.idlequeue import IdleObject
from common.file_props import FilesProp
S_INITIAL = 0
S_STARTED = 1
@ -173,9 +174,11 @@ class ProxyResolver:
def disconnect(self, connection):
if self.host_tester:
self.host_tester.disconnect()
FilesProp.deleteFileProp(self.host_tester.file_props)
self.host_tester = None
if self.receiver_tester:
self.receiver_tester.disconnect()
FilesProp.deleteFileProp(self.receiver_tester.file_props)
self.receiver_tester = None
try:
self.connections.remove(connection)
@ -248,9 +251,10 @@ class HostTester(Socks5, IdleObject):
self.on_success = on_success
self.on_failure = on_failure
self._sock = None
self.file_props = {'is_a_proxy': True,
'proxy_sender': sender_jid,
'proxy_receiver': 'test@gajim.org/test2'}
self.file_props = FilesProp.getNewFileProp(jid, sid)
self.file_props.is_a_proxy = True
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)
self.sid = sid
@ -367,9 +371,10 @@ class ReceiverTester(Socks5, IdleObject):
self.on_success = on_success
self.on_failure = on_failure
self._sock = None
self.file_props = {'is_a_proxy': True,
'proxy_sender': sender_jid,
'proxy_receiver': 'test@gajim.org/test2'}
self.file_props = FilesProp.getNewFileProp(jid, sid)
self.file_props.is_a_proxy = True
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)
self.sid = sid

View file

@ -297,23 +297,23 @@ class NsLookup(IdleCommand):
IdleCommand.__init__(self, on_result)
self.commandtimeout = 10
self.host = host.lower()
self.type = type.lower()
self.type_ = type.lower()
if not host_pattern.match(self.host):
# invalid host name
log.error('Invalid host: %s' % self.host)
self.canexecute = False
return
if not ns_type_pattern.match(self.type):
log.error('Invalid querytype: %s' % self.type)
if not ns_type_pattern.match(self.type_):
log.error('Invalid querytype: %s' % self.type_)
self.canexecute = False
return
def _compose_command_args(self):
return ['nslookup', '-type=' + self.type, self.host]
return ['nslookup', '-type=' + self.type_, self.host]
def _return_result(self):
if self.result_handler:
self.result_handler(self.host, self.type, self.result)
self.result_handler(self.host, self.type_, self.result)
self.result_handler = None
# below lines is on how to use API and assist in testing

File diff suppressed because it is too large Load diff

View file

@ -57,7 +57,7 @@ class StanzaSession(object):
'''
self.conn = conn
self.jid = jid
self.type = type_
self.type_ = type_
self.resource = jid.getResource()
if thread_id:

View file

@ -167,7 +167,7 @@ NS_HASHES_MD5 = 'urn:xmpp:hash-function-textual-names:md5'
NS_HASHES_SHA1 = 'urn:xmpp:hash-function-textual-names:sha-1'
NS_HASHES_SHA256 = 'urn:xmpp:hash-function-textual-names:sha-256'
NS_HASHES_SHA512 = 'urn:xmpp:hash-function-textual-names:sha-512'
xmpp_stream_error_conditions = '''
bad-format -- -- -- The entity has sent XML that cannot be processed.
bad-namespace-prefix -- -- -- The entity has sent a namespace prefix that is unsupported, or has sent no namespace prefix on an element that requires such a prefix.
@ -1037,12 +1037,12 @@ class Iq(Protocol):
attrs={'id': self.getID()})
iq.setQuery(self.getQuery().getName()).setNamespace(self.getQueryNS())
return iq
class Hashes(Node):
class Hashes(Node):
"""
Hash elements for various XEPs as defined in XEP-300
"""
"""
RECOMENDED HASH USE:
Algorithm Support
@ -1053,14 +1053,14 @@ class Hashes(Node):
SHA-256 MUST
SHA-512 SHOULD
"""
supported = ('md5', 'sha-1', 'sha-256', 'sha-512')
def __init__(self, nsp=NS_HASHES):
Node.__init__(self, None, {}, [], None, None, False, None)
self.setNamespace(nsp)
self.setName('hash')
def calculateHash(self, algo, file_string):
"""
Calculate the hash and add it. It is preferable doing it here
@ -1078,12 +1078,12 @@ class Hashes(Node):
hl = hashlib.sha256()
elif algo == 'sha-512':
hl = hashlib.sha512()
if hl:
hl.update(file_string)
hash_ = hl.hexdigest()
else: # if it is a file
if algo == 'md5':
hl = hashlib.md5()
elif algo == 'sha-1':
@ -1092,18 +1092,18 @@ class Hashes(Node):
hl = hashlib.sha256()
elif algo == 'sha-512':
hl = hashlib.sha512()
if hl:
for line in file_string:
hl.update(line)
hash_ = hl.hexdigest()
return hash_
return hash_
def addHash(self, hash_, algo):
self.setAttr('algo', algo)
self.setData(hash_)
class Acks(Node):
"""
Acknowledgement elements for Stream Management

View file

@ -4118,7 +4118,7 @@ class ManagePEPServicesWindow:
def _nec_pep_config_received(self, obj):
def on_ok(form, node):
form.type = 'submit'
form.type_ = 'submit'
our_jid = gajim.get_jid_from_account(self.account)
gajim.connections[self.account].send_pb_configure(our_jid, node, form)
window = dialogs.DataFormWindow(obj.form, (on_ok, obj.node))

View file

@ -185,7 +185,7 @@ class DataFormWidget(gtk.Alignment, object):
# note: we store also text-private and hidden fields,
# we just do not display them.
# TODO: boolean fields
#elif field.type=='boolean': fieldtypes.append(bool)
#elif field.type_=='boolean': fieldtypes.append(bool)
fieldtypes.append(str)
fieldvars.append(field.var)
@ -215,7 +215,7 @@ class DataFormWidget(gtk.Alignment, object):
self.clean_data_form = self.clean_multiple_data_form
readwrite = self._data_form.type != 'result'
readwrite = self._data_form.type_ != 'result'
if not readwrite:
self.buttons_vbox.set_no_show_all(True)
self.buttons_vbox.hide()
@ -343,25 +343,25 @@ class SingleForm(gtk.Table, object):
linecounter = 0
# is the form changeable?
readwrite = dataform.type != 'result'
readwrite = dataform.type_ != 'result'
# for each field...
for field in self._data_form.iter_fields():
if field.type == 'hidden': continue
if field.type_ == 'hidden': continue
commonlabel = True
commonlabelcenter = False
commonwidget = True
widget = None
if field.type == 'boolean':
if field.type_ == 'boolean':
commonlabelcenter = True
widget = gtk.CheckButton()
widget.connect('toggled', self.on_boolean_checkbutton_toggled,
field)
widget.set_active(field.value)
elif field.type == 'fixed':
elif field.type_ == 'fixed':
leftattach = 1
rightattach = 2
if field.label is None:
@ -375,7 +375,7 @@ class SingleForm(gtk.Table, object):
self.attach(widget, leftattach, rightattach, linecounter,
linecounter+1, xoptions=gtk.FILL, yoptions=gtk.FILL)
elif field.type == 'list-single':
elif field.type_ == 'list-single':
# TODO: What if we have radio buttons and non-required field?
# TODO: We cannot deactivate them all...
if len(field.options) < 6:
@ -409,7 +409,7 @@ class SingleForm(gtk.Table, object):
widget.connect('changed', on_list_single_combobox_changed, field)
widget.set_sensitive(readwrite)
elif field.type == 'list-multi':
elif field.type_ == 'list-multi':
# TODO: When more than few choices, make a list
if len(field.options) < 6:
# 5 option max: show checkbutton
@ -439,12 +439,12 @@ class SingleForm(gtk.Table, object):
on_list_multi_treeview_changed, field)
tv.set_sensitive(readwrite)
elif field.type == 'jid-single':
elif field.type_ == 'jid-single':
widget = gtk.Entry()
widget.connect('changed', self.on_text_single_entry_changed, field)
widget.set_text(field.value)
elif field.type == 'jid-multi':
elif field.type_ == 'jid-multi':
commonwidget = False
xml = gtkgui_helpers.get_gtk_builder('data_form_window.ui',
@ -493,14 +493,14 @@ class SingleForm(gtk.Table, object):
del xml
elif field.type == 'text-private':
elif field.type_ == 'text-private':
commonlabelcenter = True
widget = gtk.Entry()
widget.connect('changed', self.on_text_single_entry_changed, field)
widget.set_visibility(False)
widget.set_text(field.value)
elif field.type == 'text-multi':
elif field.type_ == 'text-multi':
# TODO: bigger text view
commonwidget = False
@ -524,7 +524,7 @@ class SingleForm(gtk.Table, object):
self.attach(widget, 1, 2, linecounter, linecounter+1)
else:
# field.type == 'text-single' or field.type is nonstandard:
# field.type_ == 'text-single' or field.type_ is nonstandard:
# JEP says that if we don't understand some type, we
# should handle it as text-single
commonlabelcenter = True

View file

@ -33,6 +33,7 @@ import dialogs
from common import gajim
from common import helpers
from common.file_props import FilesProp
from common.protocol.bytestream import (is_transfer_active, is_transfer_paused,
is_transfer_stopped)
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'
"""
active_transfers = [[], []] # ['senders', 'receivers']
# 'account' is the sender
for file_props in self.files_props['s'].values():
if file_props['tt_account'] == account:
receiver_jid = unicode(file_props['receiver']).split('/')[0]
if jid == receiver_jid:
if not is_transfer_stopped(file_props):
active_transfers[0].append(file_props)
# 'account' is the recipient
for file_props in self.files_props['r'].values():
if file_props['tt_account'] == account:
sender_jid = unicode(file_props['sender']).split('/')[0]
if jid == sender_jid:
if not is_transfer_stopped(file_props):
active_transfers[1].append(file_props)
allfp = FilesProp.getAllFileProp()
for file_props in allfp:
if file_props.type_ == 's' and file_props.tt_account == account:
# 'account' is the sender
receiver_jid = unicode(file_props.receiver).split('/')[0]
if jid == receiver_jid and not is_transfer_stopped(file_props):
active_transfers[0].append(file_props)
elif file_props.type_ == 'r' and file_props.tt_account == account:
# 'account' is the recipient
sender_jid = unicode(file_props.sender).split('/')[0]
if jid == sender_jid and not is_transfer_stopped(file_props):
active_transfers[1].append(file_props)
else:
raise Exception('file_props has no type')
return active_transfers
def show_completed(self, jid, file_props):
@ -171,46 +170,46 @@ class FileTransfersWindow:
"""
def on_open(widget, file_props):
dialog.destroy()
if 'file-name' not in file_props:
if not file_props.file_name:
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):
helpers.launch_file_manager(path)
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, file_name) = os.path.split(file_props['file-name'])
(file_path, file_name) = os.path.split(file_props.file_name)
else:
file_name = file_props['name']
file_name = file_props.name
sectext = '\t' + _('Filename: %s') % gobject.markup_escape_text(
file_name)
sectext += '\n\t' + _('Size: %s') % \
helpers.convert_bytes(file_props['size'])
if file_props['type'] == 'r':
jid = unicode(file_props['sender']).split('/')[0]
helpers.convert_bytes(file_props.size)
if file_props.type_ == 'r':
jid = unicode(file_props.sender).split('/')[0]
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
else:
#You is a reply of who sent a file
sender = _('You')
sectext += '\n\t' + _('Sender: %s') % sender
sectext += '\n\t' + _('Recipient: ')
if file_props['type'] == 's':
jid = unicode(file_props['receiver']).split('/')[0]
if file_props.type_ == 's':
jid = unicode(file_props.receiver).split('/')[0]
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
else:
#You is a reply of who received a file
recipient = _('You')
sectext += recipient
if file_props['type'] == 'r':
if file_props.type_ == 'r':
sectext += '\n\t' + _('Saved in: %s') % file_path
dialog = dialogs.HigDialog(None, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE,
_('File transfer completed'), sectext)
if file_props['type'] == 'r':
if file_props.type_ == 'r':
button = gtk.Button(_('_Open Containing Folder'))
button.connect('clicked', on_open, file_props)
dialog.action_area.pack_start(button)
@ -236,10 +235,10 @@ class FileTransfersWindow:
self.tree.get_selection().unselect_all()
def show_stopped(self, jid, file_props, error_msg=''):
if file_props['type'] == 'r':
file_name = os.path.basename(file_props['file-name'])
if file_props.type_ == 'r':
file_name = os.path.basename(file_props.file_name)
else:
file_name = file_props['name']
file_name = file_props.name
sectext = '\t' + _('Filename: %s') % gobject.markup_escape_text(
file_name)
sectext += '\n\t' + _('Recipient: %s') % jid
@ -254,13 +253,13 @@ class FileTransfersWindow:
sid = gajim.connections[account].start_file_transfer(jid,
file_props,
True)
file_props['sid'] = sid
file_props.sid = sid
if file_props['type'] == 'r':
file_name = os.path.basename(file_props['file-name'])
if file_props.type_ == 'r':
file_name = os.path.basename(file_props.file_name)
else:
file_name = file_props['name']
file_name = file_props.name
dialogs.YesNoDialog(('File transfer error'),
_('The file %(file)s has been fully received, but it seems to be '
'wrongly received.\nDo you want to reload it?') % \
@ -339,10 +338,8 @@ class FileTransfersWindow:
return False
if contact.supports(NS_JINGLE_FILE_TRANSFER):
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
# make it explicit here
sid = gajim.connections[account].start_file_transfer(contact.get_full_jid(), file_props)
file_props['sid'] = sid
gajim.connections[account].start_file_transfer(contact.get_full_jid(),
file_props)
self.add_transfer(account, contact, file_props)
else:
log.info("contact does not support jingle file transfer")
@ -354,7 +351,8 @@ class FileTransfersWindow:
file_dir = os.path.dirname(file_path)
if 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)
gajim.connections[account].send_file_approval(file_props)
@ -375,14 +373,14 @@ class FileTransfersWindow:
return
stat = os.stat(file_path)
dl_size = stat.st_size
file_size = file_props['size']
file_size = file_props.size
dl_finished = dl_size >= file_size
def on_response(response):
if response < 0:
return
elif response == 100:
file_props['offset'] = dl_size
file_props.offset = dl_size
dialog2.destroy()
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_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:
on_cancel(widget, account, contact, file_props))
@ -428,17 +426,17 @@ class FileTransfersWindow:
Show dialog asking for comfirmation and store location of new file
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
sec_text = '\t' + _('File: %s') % gobject.markup_escape_text(
file_props['name'])
if 'size' in file_props:
file_props.name)
if file_props.size:
sec_text += '\n\t' + _('Size: %s') % \
helpers.convert_bytes(file_props['size'])
if 'mime-type' in file_props:
sec_text += '\n\t' + _('Type: %s') % file_props['mime-type']
if 'desc' in file_props:
sec_text += '\n\t' + _('Description: %s') % file_props['desc']
helpers.convert_bytes(file_props.size)
if file_props.mime_type:
sec_text += '\n\t' + _('Type: %s') % file_props.mime_type
if file_props.desc:
sec_text += '\n\t' + _('Description: %s') % file_props.desc
prim_text = _('%s wants to send you a file:') % contact.jid
dialog = None
@ -459,22 +457,21 @@ class FileTransfersWindow:
return self.images.setdefault(ident,
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'
"""
iter_ = self.get_iter_by_sid(typ, sid)
iter_ = self.get_iter_by_sid(file_props.type_, file_props.sid)
if iter_ is None:
return
sid = self.model[iter_][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]]
self.model[iter_][C_SID].decode('utf-8')
if status == 'stop':
file_props['stopped'] = True
file_props.stopped = True
elif status == 'ok':
file_props['completed'] = True
file_props.completed = True
text = self._format_percent(100)
received_size = int(file_props['received-len'])
full_size = int(file_props['size'])
received_size = int(file_props.received_len)
full_size = int(file_props.size)
text += helpers.convert_bytes(received_size) + '/' + \
helpers.convert_bytes(full_size)
self.model.set(iter_, C_PROGRESS, text)
@ -482,8 +479,8 @@ class FileTransfersWindow:
elif status == 'computing':
self.model.set(iter_, C_PULSE, 1)
text = _('Checking file...') + '\n'
received_size = int(file_props['received-len'])
full_size = int(file_props['size'])
received_size = int(file_props.received_len)
full_size = int(file_props.size)
text += helpers.convert_bytes(received_size) + '/' + \
helpers.convert_bytes(full_size)
self.model.set(iter_, C_PROGRESS, text)
@ -496,8 +493,8 @@ class FileTransfersWindow:
gobject.timeout_add(100, pulse)
elif status == 'hash_error':
text = _('File error') + '\n'
received_size = int(file_props['received-len'])
full_size = int(file_props['size'])
received_size = int(file_props.received_len)
full_size = int(file_props.size)
text += helpers.convert_bytes(received_size) + '/' + \
helpers.convert_bytes(full_size)
self.model.set(iter_, C_PROGRESS, text)
@ -535,14 +532,14 @@ class FileTransfersWindow:
return _('%(hours)02.d:%(minutes)02.d:%(seconds)02.d') % times
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.
elif len(file_props['transfered_size']) == 1:
speed = round(float(transfered_size) / file_props['elapsed-time'])
elif len(file_props.transfered_size) == 1:
speed = round(float(transfered_size) / file_props.elapsed_time)
else:
# first and last are (time, transfered_size)
first = file_props['transfered_size'][0]
last = file_props['transfered_size'][-1]
first = file_props.transfered_size[0]
last = file_props.transfered_size[-1]
transfered = last[1] - first[1]
tim = last[0] - first[0]
if tim == 0:
@ -556,16 +553,18 @@ class FileTransfersWindow:
def _remove_transfer(self, iter_, sid, file_props):
self.model.remove(iter_)
if 'tt_account' in file_props:
if not file_props:
return
if file_props.tt_account:
# file transfer is set
account = file_props['tt_account']
account = file_props.tt_account
if account in gajim.connections:
# there is a connection to the account
gajim.connections[account].remove_transfer(file_props)
if file_props['type'] == 'r': # we receive a file
other = file_props['sender']
if file_props.type_ == 'r': # we receive a file
other = file_props.sender
else: # we send a file
other = file_props['receiver']
other = file_props.receiver
if isinstance(other, unicode):
jid = gajim.get_jid_without_resource(other)
else: # It's a Contact instance
@ -573,21 +572,19 @@ class FileTransfersWindow:
for ev_type in ('file-error', 'file-completed', 'file-request-error',
'file-send-error', 'file-stopped'):
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.interface.roster.draw_contact(jid, account)
gajim.interface.roster.show_title()
del(self.files_props[sid[0]][sid[1:]])
FilesProp.deleteFileProp(file_props)
del(file_props)
def set_progress(self, typ, sid, transfered_size, iter_=None):
"""
Change the progress of a transfer with new transfered size
"""
if sid not in self.files_props[typ]:
return
file_props = self.files_props[typ][sid]
full_size = int(file_props['size'])
file_props = FilesProp.getFilePropByType(typ, sid)
full_size = int(file_props.size)
if full_size == 0:
percent = 0
else:
@ -607,14 +604,14 @@ class FileTransfersWindow:
# Kb/s
# remaining time
if 'offset' in file_props and file_props['offset']:
transfered_size -= file_props['offset']
full_size -= file_props['offset']
if file_props.offset:
transfered_size -= file_props.offset
full_size -= file_props.offset
if file_props['elapsed-time'] > 0:
file_props['transfered_size'].append((file_props['last-time'], transfered_size))
if len(file_props['transfered_size']) > 6:
file_props['transfered_size'].pop(0)
if file_props.elapsed_time > 0:
file_props.transfered_size.append((file_props.last_time, transfered_size))
if len(file_props.transfered_size) > 6:
file_props.transfered_size.pop(0)
eta, speed = self._get_eta_and_speed(full_size, transfered_size,
file_props)
@ -630,24 +627,24 @@ class FileTransfersWindow:
self.model.set(iter_, C_TIME, text)
# try to guess what should be the status image
if file_props['type'] == 'r':
if file_props.type_ == 'r':
status = 'download'
else:
status = 'upload'
if 'paused' in file_props and file_props['paused'] == True:
if file_props.paused == True:
status = 'pause'
elif 'stalled' in file_props and file_props['stalled'] == True:
elif file_props.stalled == True:
status = 'waiting'
if 'connected' in file_props and file_props['connected'] == False:
if file_props.connected == False:
status = 'stop'
self.model.set(iter_, 0, self.get_icon(status))
if transfered_size == full_size:
# 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
self.set_status(typ, sid, 'computing')
self.set_status(file_props, 'computing')
else:
self.set_status(typ, sid, 'ok')
self.set_status(file_props, 'ok')
elif just_began:
path = self.model.get_path(iter_)
self.select_func(path)
@ -668,8 +665,6 @@ class FileTransfersWindow:
"""
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):
stat = os.stat(file_path)
else:
@ -679,16 +674,17 @@ class FileTransfersWindow:
dialogs.ErrorDialog(_('Invalid File'),
_('It is not possible to send empty files'))
return None
file_props['elapsed-time'] = 0
file_props['size'] = unicode(stat[6])
file_props['sid'] = helpers.get_random_string_16()
file_props['completed'] = False
file_props['started'] = False
file_props['sender'] = account
file_props['receiver'] = contact
file_props['tt_account'] = account
# keep the last time: transfered_size to compute transfer speed
file_props['transfered_size'] = []
file_props = FilesProp.getNewFileProp(account,
sid=helpers.get_random_string_16())
file_props.file_name = file_path
file_props.name = file_name
file_props.type_ = 's'
file_props.desc = file_desc
file_props.elapsed_time = 0
file_props.size = unicode(stat[6])
file_props.sender = account
file_props.receiver = contact
file_props.tt_account = account
return file_props
def add_transfer(self, account, contact, file_props):
@ -698,32 +694,31 @@ class FileTransfersWindow:
self.on_transfers_list_leave_notify_event(None)
if file_props is None:
return
file_props['elapsed-time'] = 0
self.files_props[file_props['type']][file_props['sid']] = file_props
file_props.elapsed_time = 0
iter_ = self.model.prepend()
text_labels = '<b>' + _('Name: ') + '</b>\n'
if file_props['type'] == 'r':
if file_props.type_ == 'r':
text_labels += '<b>' + _('Sender: ') + '</b>'
else:
text_labels += '<b>' + _('Recipient: ') + '</b>'
if file_props['type'] == 'r':
file_name = os.path.split(file_props['file-name'])[1]
if file_props.type_ == 'r':
file_name = os.path.split(file_props.file_name)[1]
else:
file_name = file_props['name']
file_name = file_props.name
text_props = gobject.markup_escape_text(file_name) + '\n'
text_props += contact.get_shown_name()
self.model.set(iter_, 1, text_labels, 2, text_props, C_PULSE, -1, C_SID,
file_props['type'] + file_props['sid'])
self.set_progress(file_props['type'], file_props['sid'], 0, iter_)
if 'started' in file_props and file_props['started'] is False:
file_props.type_ + file_props.sid)
self.set_progress(file_props.type_, file_props.sid, 0, iter_)
if file_props.started is False:
status = 'waiting'
elif file_props['type'] == 'r':
elif file_props.type_ == 'r':
status = 'download'
else:
status = 'upload'
file_props['tt_account'] = account
self.set_status(file_props['type'], file_props['sid'], status)
file_props.tt_account = account
self.set_status(file_props, status)
self.set_cleanup_sensitivity()
self.window.show_all()
@ -743,7 +738,7 @@ class FileTransfersWindow:
self.tooltip.hide_tooltip()
return
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 self.tooltip.timeout == 0 or self.tooltip.id != props[0]:
self.tooltip.id = row
@ -798,7 +793,7 @@ class FileTransfersWindow:
return
current_iter = self.model.get_iter(path)
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.open_folder_menuitem.set_sensitive(is_row_selected)
is_stopped = False
@ -856,7 +851,7 @@ class FileTransfersWindow:
while i >= 0:
iter_ = self.model.get_iter((i))
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):
self._remove_transfer(iter_, sid, file_props)
i -= 1
@ -876,7 +871,7 @@ class FileTransfersWindow:
self.continue_menuitem.set_no_show_all(True)
else:
label = _('Continue')
label = _('_Continue')
self.pause_button.set_label(label)
self.pause_button.set_image(gtk.image_new_from_stock(
gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_MENU))
@ -891,20 +886,20 @@ class FileTransfersWindow:
return
s_iter = selected[1]
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):
file_props['last-time'] = time.time()
file_props['paused'] = False
file_props.last_time = time.time()
file_props.paused = False
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)
if file_props['continue_cb']:
file_props['continue_cb']()
if file_props.continue_cb:
file_props.continue_cb()
elif is_transfer_active(file_props):
file_props['paused'] = True
self.set_status(file_props['type'], file_props['sid'], 'pause')
file_props.paused = True
self.set_status(file_props, 'pause')
# reset that to compute speed only when we resume
file_props['transfered_size'] = []
file_props.transfered_size = []
self.toggle_pause_continue(False)
def on_cancel_button_clicked(self, widget):
@ -913,14 +908,12 @@ class FileTransfersWindow:
return
s_iter = selected[1]
sid = self.model[s_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]]
if 'tt_account' not in file_props:
return
account = file_props['tt_account']
file_props = FilesProp.getFilePropByType(sid[0], sid[1:])
account = file_props.tt_account
if account not in gajim.connections:
return
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):
if self.height_diff == 0:
@ -934,7 +927,7 @@ class FileTransfersWindow:
if props and self.tooltip.id == props[0]:
iter_ = self.model.get_iter(props[0])
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
rect = self.tree.get_cell_area(props[0], props[1])
# position of the treeview on the screen
@ -1022,10 +1015,10 @@ class FileTransfersWindow:
return
s_iter = selected[1]
sid = self.model[s_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]]
if 'file-name' not in file_props:
file_props = FilesProp.getFilePropByType(sid[0], sid[1:])
if not file_props.file_name:
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):
helpers.launch_file_manager(path)
@ -1044,7 +1037,7 @@ class FileTransfersWindow:
return
s_iter = selected[1]
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.set_all_insensitive()

View file

@ -950,7 +950,7 @@ class GroupchatControl(ChatControlBase):
if not self.form_widget:
return
form_node = self.form_widget.data_form.get_purged()
form_node.type = 'submit'
form_node.type_ = 'submit'
obj.conn.send_captcha(self.room_jid, form_node)
self.form_widget.hide()
self.form_widget.destroy()

View file

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

View file

@ -1970,9 +1970,9 @@ class RosterWindow:
return True
elif event.type_ in ('file-error', 'file-stopped'):
msg_err = ''
if data['error'] == -1:
if data.error == -1:
msg_err = _('Remote contact stopped transfer')
elif data['error'] == -6:
elif data.error == -6:
msg_err = _('Error opening file')
ft.show_stopped(jid, data, error_msg=msg_err)
gajim.events.remove_events(account, jid, event)

View file

@ -89,7 +89,7 @@ class SearchWindow:
def on_search_button_clicked(self, button):
if self.is_form:
self.data_form_widget.data_form.type = 'submit'
self.data_form_widget.data_form.type_ = 'submit'
gajim.connections[self.account].send_search_form(self.jid,
self.data_form_widget.data_form.get_purged(), True)
else:

View file

@ -447,7 +447,7 @@ class StatusIcon:
def on_clicked(self, widget, event):
self.on_tray_leave_notify_event(widget, None)
if event.type != gtk.gdk.BUTTON_PRESS:
if event.type_ != gtk.gdk.BUTTON_PRESS:
return
if event.button == 1: # Left click
self.on_left_click()

View file

@ -733,23 +733,23 @@ class FileTransfersTooltip(BaseTooltip):
current_row = 1
self.create_window()
properties = []
name = file_props['name']
if file_props['type'] == 'r':
file_name = os.path.split(file_props['file-name'])[1]
name = file_props.name
if file_props.type_ == 'r':
file_name = os.path.split(file_props.file_name)[1]
else:
file_name = file_props['name']
file_name = file_props.name
properties.append((_('Name: '),
gobject.markup_escape_text(file_name)))
if file_props['type'] == 'r':
if file_props.type_ == 'r':
type_ = _('Download')
actor = _('Sender: ')
sender = unicode(file_props['sender']).split('/')[0]
sender = unicode(file_props.sender).split('/')[0]
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:
type_ = _('Upload')
actor = _('Recipient: ')
receiver = file_props['receiver']
receiver = file_props.receiver
if hasattr(receiver, 'name'):
name = receiver.get_shown_name()
else:
@ -757,26 +757,24 @@ class FileTransfersTooltip(BaseTooltip):
properties.append((_('Type: '), type_))
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)))
status = ''
if 'started' not in file_props or not file_props['started']:
if file_props.started:
status = _('Not started')
elif 'connected' in file_props:
if 'stopped' in file_props and \
file_props['stopped'] == True:
status = _('Stopped')
elif file_props['completed']:
if file_props.stopped == True:
status = _('Stopped')
elif file_props.completed:
status = _('Completed')
elif file_props.connected == False:
if file_props.completed:
status = _('Completed')
elif file_props['connected'] == False:
if file_props['completed']:
status = _('Completed')
else:
if 'paused' in file_props and \
file_props['paused'] == True:
if file_props.paused == True:
status = _('?transfer status:Paused')
elif 'stalled' in file_props and \
file_props['stalled'] == True:
elif file_props.stalled == True:
#stalled is not paused. it is like 'frozen' it stopped alone
status = _('Stalled')
else:
@ -784,10 +782,9 @@ class FileTransfersTooltip(BaseTooltip):
else:
status = _('Not started')
properties.append((_('Status: '), status))
if 'desc' in file_props:
file_desc = file_props['desc']
properties.append((_('Description: '), gobject.markup_escape_text(
file_desc)))
file_desc = file_props.desc
properties.append((_('Description: '), gobject.markup_escape_text(
file_desc)))
while properties:
property_ = properties.pop(0)
current_row += 1

View file

@ -133,7 +133,7 @@ class MockSession(Mock):
self.conn = conn
self.jid = jid
self.type = type_
self.type_ = type_
self.thread_id = thread_id
if not self.thread_id: