diff --git a/src/adhoc_commands.py b/src/adhoc_commands.py index 2f556fcc00807a66f9fa0a07e4ea4593ba79af6d..bc947d49d4f849386385bc0edbfdf7bfe07a26f6 100644 --- a/src/adhoc_commands.py +++ b/src/adhoc_commands.py @@ -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() diff --git a/src/chat_control.py b/src/chat_control.py index 2885e4081b04ebdd0a0dcf8da35d0d968e593249..b74fc6ab42baa795f7b2b24398d795d40b59cedb 100644 --- a/src/chat_control.py +++ b/src/chat_control.py @@ -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) diff --git a/src/common/connection_handlers_events.py b/src/common/connection_handlers_events.py index 8899d6d82f1b6789a56b7f1a54742c3a4628742a..0cf10c0b6835efc4b376ca2244ed225a864ad4e7 100644 --- a/src/common/connection_handlers_events.py +++ b/src/common/connection_handlers_events.py @@ -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 + 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: - si = self.stanza.getTag('si') 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): diff --git a/src/common/dataforms.py b/src/common/dataforms.py index ca7ae513dc6984a2b5e43f2600f9cdce4fcbf98e..20d6b23ac46b665dbe5dc505897c30427b52617e 100644 --- a/src/common/dataforms.py +++ b/src/common/dataforms.py @@ -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(): diff --git a/src/common/file_props.py b/src/common/file_props.py new file mode 100644 index 0000000000000000000000000000000000000000..18402c6fc295f6f9103c0eaa7fb0c777714e172a --- /dev/null +++ b/src/common/file_props.py @@ -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() diff --git a/src/common/jingle.py b/src/common/jingle.py index e466a1df7b3ae59cb605eb2a51917677290ea1eb..770ff90879eecb0163e8d8f57145744e36a72fa7 100644 --- a/src/common/jingle.py +++ b/src/common/jingle.py @@ -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): diff --git a/src/common/jingle_content.py b/src/common/jingle_content.py index b31993ea67c15cfd588d46fff9a54253b2d97b7d..b1351454cb1dc894cd69bb39ecc38c15a3d9b82d 100644 --- a/src/common/jingle_content.py +++ b/src/common/jingle_content.py @@ -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) diff --git a/src/common/jingle_ft.py b/src/common/jingle_ft.py index e9b2c0855368831cfabc5b6d4ef78f4b91593f3b..7e29eecf02718693bf1443e4b98f9c31d8abbbd1 100644 --- a/src/common/jingle_ft.py +++ b/src/common/jingle_ft.py @@ -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 diff --git a/src/common/jingle_ftstates.py b/src/common/jingle_ftstates.py index 271f53927a76f3cf02fc3169c15a4f252ed66c5b..9d7e8e1d7f3222b802b61a832aecedfa833c74fb 100644 --- a/src/common/jingle_ftstates.py +++ b/src/common/jingle_ftstates.py @@ -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() diff --git a/src/common/jingle_transport.py b/src/common/jingle_transport.py index b9fd11626633b783c6bd1fac0281e79c8fa3fe5e..836e7975ec6f13097c23aa2fb47e6b0eb839c6eb 100644 --- a/src/common/jingle_transport.py +++ b/src/common/jingle_transport.py @@ -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: diff --git a/src/common/jingle_xtls.py b/src/common/jingle_xtls.py index f475393bf2135a50f4ff3277ed5eb53cfbe702e1..5e3c6ecf1c0cddc5e0abbd782fa2fd2c38780d83 100644 --- a/src/common/jingle_xtls.py +++ b/src/common/jingle_xtls.py @@ -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__': diff --git a/src/common/pep.py b/src/common/pep.py index be94e92350b44d016d7fceea0bf5aa55a578ff0c..87283026e7968caa18df4b715d9794ab73785db2 100644 --- a/src/common/pep.py +++ b/src/common/pep.py @@ -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): diff --git a/src/common/protocol/bytestream.py b/src/common/protocol/bytestream.py index b370ec26624ae24e9b91d5688f77afd41e33ee03..cc363c5be8dbbc570bd0249c4e015c5f7b40e983 100644 --- a/src/common/protocol/bytestream.py +++ b/src/common/protocol/bytestream.py @@ -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') diff --git a/src/common/proxy65_manager.py b/src/common/proxy65_manager.py index 879458aea80ff43829f688e40302b949aec466c8..0af5e49ff70aff09f154c3bf8842fbfee90ec0b4 100644 --- a/src/common/proxy65_manager.py +++ b/src/common/proxy65_manager.py @@ -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 diff --git a/src/common/resolver.py b/src/common/resolver.py index 898f146f4e595c8f7ecc8230150c38b15677b7ed..5f1ce22f3b19a83bd7b89424cfe9c90f2162a10e 100644 --- a/src/common/resolver.py +++ b/src/common/resolver.py @@ -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 diff --git a/src/common/socks5.py b/src/common/socks5.py index 534fcedbc3d237fcf49dc9de771c737bdbb39807..addbd235ccf1a1295f7d8e156c6029e1a5eb16d8 100644 --- a/src/common/socks5.py +++ b/src/common/socks5.py @@ -34,7 +34,7 @@ from errno import EISCONN from errno import EINPROGRESS from errno import EAFNOSUPPORT from xmpp.idlequeue import IdleObject - +from file_props import FilesProp import jingle_xtls if jingle_xtls.PYOPENSSL_PRESENT: @@ -69,7 +69,6 @@ class SocksQueue: progress_transfer_cb=None, error_cb=None): self.connected = 0 self.readers = {} - self.files_props = {} self.senders = {} self.idx = 1 self.listener = None @@ -83,84 +82,80 @@ class SocksQueue: self.on_success = {} # {id: cb} self.on_failure = {} # {id: cb} - def start_listener(self, port, sha_str, sha_handler, fp, fingerprint=None, - type='sender'): + def start_listener(self, port, sha_str, sha_handler, file_props, + fingerprint=None, typ='sender'): """ Start waiting for incomming connections on (host, port) and do a socks5 authentication using sid for generated SHA """ - sid = fp['sid'] - self.type = type # It says whether we are sending or receiving + sid = file_props.sid + self.type_ = typ # It says whether we are sending or receiving self.sha_handlers[sha_str] = (sha_handler, sid) if self.listener is None or self.listener.connections == []: - self.listener = Socks5Listener(self.idlequeue, port, fp, - fingerprint=fingerprint) + self.listener = Socks5Listener(self.idlequeue, port, file_props, + fingerprint=fingerprint) self.listener.queue = self self.listener.bind() else: # There is already a listener, we update the file's information # on the new connection. - self.listener.file_props = fp - + self.listener.file_props = file_props + self.connected += 1 return self.listener def send_success_reply(self, file_props, streamhost): - if 'streamhost-used' in file_props and \ - file_props['streamhost-used'] is True: - if 'proxyhosts' in file_props: - for proxy in file_props['proxyhosts']: - if proxy['host'] == streamhost['host']: - self.on_success[file_props['sid']](proxy) - return 1 + if file_props.streamhost_used == True: + for proxy in file_props.proxyhosts: + if proxy['host'] == streamhost['host']: + self.on_success[file_props.sid](proxy) + return 1 return 0 - if 'streamhosts' in file_props: - for host in file_props['streamhosts']: - if streamhost['state'] == 1: - return 0 - streamhost['state'] = 1 - self.on_success[file_props['sid']](streamhost) - return 1 - return 0 + for host in file_props.streamhosts: + if streamhost['state'] == 1: + return 0 + streamhost['state'] = 1 + self.on_success[file_props.sid](streamhost) + return 1 def connect_to_hosts(self, account, sid, on_success=None, on_failure=None, fingerprint=None, receiving=True): self.on_success[sid] = on_success self.on_failure[sid] = on_failure - file_props = self.files_props[account][sid] - file_props['failure_cb'] = on_failure + file_props = FilesProp.getFileProp(account, sid) + file_props.failure_cb = on_failure - if not file_props['streamhosts']: - on_failure(file_props['sid']) + if not file_props.streamhosts: + on_failure(file_props.sid) # add streamhosts to the queue - for streamhost in file_props['streamhosts']: + for streamhost in file_props.streamhosts: if 'type' in streamhost and streamhost['type'] == 'proxy': fp = None else: fp = fingerprint if receiving: - self.type = 'receiver' - socks5obj = Socks5ReceiverClient(self.idlequeue, streamhost, sid, - file_props, fingerprint=fp) + self.type_ = 'receiver' + socks5obj = Socks5ReceiverClient(self.idlequeue, streamhost, + sid, file_props, fingerprint=fp) self.add_sockobj(account, socks5obj) else: - if 'sha_str' in file_props: - idx = file_props['sha_str'] + if file_props.sha_str: + idx = file_props.sha_str else: idx = self.idx self.idx = self.idx + 1 - self.type = 'sender' + self.type_ = 'sender' if 'type' in streamhost and streamhost['type'] == 'proxy': - file_props['is_a_proxy'] = True - file_props['proxy_sender'] = streamhost['target'] - file_props['proxy_receiver'] = streamhost['initiator'] + file_props.is_a_proxy = True + file_props.proxy_sender = streamhost['target'] + file_props.proxy_receiver = streamhost['initiator'] socks5obj = Socks5SenderClient(self.idlequeue, idx, - self, _sock=None,host=str(streamhost['host']), - port=int(streamhost['port']),fingerprint=fp, + self, _sock=None,host=str(streamhost['host']), + port=int(streamhost['port']),fingerprint=fp, connected=False, file_props=file_props) socks5obj.streamhost = streamhost - self.add_sockobj(account, socks5obj, type='sender') + self.add_sockobj(account, socks5obj, type_='sender') streamhost['idx'] = socks5obj.queue_idx @@ -169,11 +164,11 @@ class SocksQueue: Called when there is a host connected to one of the senders's streamhosts. Stop other attempts for connections """ - for host in file_props['streamhosts']: + for host in file_props.streamhosts: if host != streamhost and 'idx' in host: if host['state'] == 1: # remove current - if self.type == 'sender': + if self.type_ == 'sender': self.remove_sender(streamhost['idx'], False) else: self.remove_receiver(streamhost['idx']) @@ -181,7 +176,7 @@ class SocksQueue: # set state -2, meaning that this streamhost is stopped, # but it may be connectected later if host['state'] >= 0: - if self.type == 'sender': + if self.type_ == 'sender': self.remove_sender(host['idx'], False) else: self.remove_receiver(host['idx']) @@ -200,30 +195,30 @@ class SocksQueue: streamhost['state'] = -1 # boolean, indicates that there are hosts, which are not tested yet unused_hosts = False - for host in file_props['streamhosts']: + for host in file_props.streamhosts: if 'idx' in host: if host['state'] >= 0: return elif host['state'] == -2: unused_hosts = True if unused_hosts: - for host in file_props['streamhosts']: + for host in file_props.streamhosts: if host['state'] == -2: host['state'] = 0 # FIXME: make the sender reconnect also - client = Socks5ReceiverClient(self.idlequeue, host, host['sid'], - file_props) + client = Socks5ReceiverClient(self.idlequeue, host, + host['sid'], file_props) self.add_sockobj(client.account, client) host['idx'] = client.queue_idx # we still have chances to connect return - if 'received-len' not in file_props or file_props['received-len'] == 0: + if file_props.received_len == 0: # there are no other streamhosts and transfer hasn't started self._connection_refused(streamhost, file_props, client.queue_idx) else: # transfer stopped, it is most likely stopped from sender client.disconnect() - file_props['error'] = -1 + file_props.error = -1 self.process_result(-1, client) def _connection_refused(self, streamhost, file_props, idx): @@ -235,22 +230,21 @@ class SocksQueue: streamhost['state'] = -1 # FIXME: should only the receiver be remove? what if we are sending? self.remove_receiver(idx, False) - if 'streamhosts' in file_props: - for host in file_props['streamhosts']: - if host['state'] != -1: - return + for host in file_props.streamhosts: + if host['state'] != -1: + return self.readers = {} # failure_cb exists - this means that it has never been called - if 'failure_cb' in file_props and file_props['failure_cb']: - file_props['failure_cb'](file_props['sid']) - del(file_props['failure_cb']) + if file_props.failure_cb: + file_props.failure_cb(file_props.sid) + file_props.failure_cb = None - def add_sockobj(self, account, sockobj, type='receiver'): + def add_sockobj(self, account, sockobj, type_='receiver'): """ Add new file a sockobj type receiver or sender, and use it to connect to server """ - if type == 'receiver': + if type_ == 'receiver': self._add(sockobj, self.readers, sockobj.file_props, self.idx) else: self._add(sockobj, self.senders, sockobj.file_props, self.idx) @@ -266,11 +260,11 @@ class SocksQueue: return 1 return None - def _add(self, sockobj, sockobjects, fp, hash): + def _add(self, sockobj, sockobjects, file_props, hash_): ''' Adds the sockobj to the current list of sockobjects ''' - keys = (fp['sid'], fp['name'], hash) + keys = (file_props.sid, file_props.name, hash_) sockobjects[keys] = sockobj def result_sha(self, sha_str, idx): @@ -284,21 +278,21 @@ class SocksQueue: for key in self.readers.keys(): if idx in key: reader = self.readers[key] - if reader.file_props['type'] != 's': + if reader.file_props.type_ != 's': return if reader.state != 5: return reader.state = 6 if reader.connected: - reader.file_props['error'] = 0 - reader.file_props['disconnect_cb'] = reader.disconnect - reader.file_props['started'] = True - reader.file_props['completed'] = False - reader.file_props['paused'] = False - reader.file_props['stalled'] = False - reader.file_props['elapsed-time'] = 0 - reader.file_props['last-time'] = self.idlequeue.current_time() - reader.file_props['received-len'] = 0 + reader.file_props.error = 0 + reader.file_props.disconnect_cb = reader.disconnect + reader.file_props.started = True + reader.file_props.completed = False + reader.file_props.paused = False + reader.file_props.stalled = False + reader.file_props.elapsed_time = 0 + reader.file_props.last_time = self.idlequeue.current_time() + reader.file_props.received_len = 0 reader.pauses = 0 # start sending file to proxy self.idlequeue.set_read_timeout(reader.fd, STALLED_TIMEOUT) @@ -308,59 +302,24 @@ class SocksQueue: def send_file(self, file_props, account, mode): for key in self.senders.keys(): - if self.senders == {}: - # Python acts very weird with this. When there is no keys - # in the dictionary It says that it has a key. - # Maybe it is my machine. Without this there is a KeyError - # traceback. - return - if file_props['name'] in key and file_props['sid'] in key \ + if self.senders == {}: + # Python acts very weird with this. When there is no keys + # in the dictionary It says that it has a key. + # Maybe it is my machine. Without this there is a KeyError + # traceback. + return + if file_props.name in key and file_props.sid in key \ and self.senders[key].mode == mode: - log.info("socks5: sending file") + log.info('socks5: sending file') sender = self.senders[key] - file_props['streamhost-used'] = True + file_props.streamhost_used = True sender.account = account - + sender.file_props = file_props result = sender.send_file() self.process_result(result, sender) - def add_file_props(self, account, file_props): - """ - File_prop to the dict of current file_props. It is identified by account - name and sid - """ - if file_props is None or ('sid' in file_props) is False: - return - _id = file_props['sid'] - if account not in self.files_props: - self.files_props[account] = {} - self.files_props[account][_id] = file_props - - def remove_file_props(self, account, sid): - if account in self.files_props: - fl_props = self.files_props[account] - if sid in fl_props: - if sid in self.on_success: - del self.on_success[sid] - if sid in self.on_failure: - del self.on_failure[sid] - del(fl_props[sid]) - - if len(self.files_props) == 0: - self.connected = 0 - - def get_file_props(self, account, sid): - """ - Get fil_prop by account name and session id - """ - if account in self.files_props: - fl_props = self.files_props[account] - if sid in fl_props: - return fl_props[sid] - return None - def isHashInSockObjs(self, sockobjs, hash): ''' It tells wether there is a particular hash in sockobjs or not @@ -372,7 +331,7 @@ class SocksQueue: def on_connection_accepted(self, sock, listener): sock_hash = sock.__hash__() - if self.type == 'sender' and \ + if self.type_ == 'sender' and \ not self.isHashInSockObjs(self.senders, sock_hash): sockobj = Socks5SenderServer(self.idlequeue, sock_hash, self, @@ -383,8 +342,8 @@ class SocksQueue: self.idlequeue.plug_idle(sockobj, False, True) self.connected += 1 - if self.type == 'receiver' and \ - not self.isHashInSockObjs(self.readers, sock_hash): + if self.type_ == 'receiver' and \ + not self.isHashInSockObjs(self.readers, sock_hash): sh = {} sh['host'] = sock[1][0] sh['port'] = sock[1][1] @@ -401,7 +360,6 @@ class SocksQueue: sockobj.queue = self self.connected += 1 - def process_result(self, result, actor): """ Take appropriate actions upon the result: @@ -413,8 +371,8 @@ class SocksQueue: return if result in (0, -1) and self.complete_transfer_cb is not None: account = actor.account - if account is None and 'tt_account' in actor.file_props: - account = actor.file_props['tt_account'] + if account is None and actor.file_props.tt_account: + account = actor.file_props.tt_account self.complete_transfer_cb(account, actor.file_props) elif self.progress_transfer_cb is not None: self.progress_transfer_cb(actor.account, actor.file_props) @@ -440,7 +398,7 @@ class SocksQueue: del(self.readers[key]) if not remove_all: break - + def remove_sender(self, idx, do_disconnect=True, remove_all=False): """ Remove sender from the list of senders and decrease the number of active @@ -490,7 +448,7 @@ class Socks5: self.remaining_buff = '' self.file = None self.connected = False - self.type = '' + self.type_ = '' self.mode = '' @@ -509,7 +467,7 @@ class Socks5: for ai in self.ais: try: self._sock = socket.socket(*ai[:3]) - + if not self.fingerprint is None: self._sock = OpenSSL.SSL.Connection( jingle_xtls.get_context('client'), self._sock) @@ -531,7 +489,6 @@ class Socks5: def do_connect(self): try: - #self._sock.setblocking(True) self._sock.connect(self._server) self._sock.setblocking(False) self._send=self._sock.send @@ -553,9 +510,9 @@ class Socks5: self._recv=self._sock.recv self.buff = '' self.connected = True - self.file_props['connected'] = True - self.file_props['disconnect_cb'] = self.disconnect - self.file_props['paused'] = False + self.file_props.connected = True + self.file_props.disconnect_cb = self.disconnect + self.file_props.paused = False self.state = 1 # connected # stop all others connections to sender's streamhosts @@ -567,17 +524,16 @@ class Socks5: self.idlequeue.remove_timeout(self.fd) if self.state > 5: # no activity for foo seconds - if self.file_props['stalled'] == False: - self.file_props['stalled'] = True + if self.file_props.stalled == False: + self.file_props.stalled = True self.queue.process_result(-1, self) - if 'received-len' not in self.file_props: - self.file_props['received-len'] = 0 + if not self.file_props.received_len: + self.file_props.received_len = 0 if SEND_TIMEOUT > 0: self.idlequeue.set_read_timeout(self.fd, SEND_TIMEOUT) else: # stop transfer, there is no error code for this self.pollend() - else: if self.mode == 'client': self.queue.reconnect_client(self, self.streamhost) @@ -585,11 +541,11 @@ class Socks5: def open_file_for_reading(self): if self.file is None: try: - self.file = open(self.file_props['file-name'], 'rb') - if 'offset' in self.file_props and self.file_props['offset']: - self.size = self.file_props['offset'] + self.file = open(self.file_props.file_name, 'rb') + if self.file_props.offset: + self.size = self.file_props.offset self.file.seek(self.size) - self.file_props['received-len'] = self.size + self.file_props.received_len = self.size except IOError, e: self.close_file() raise IOError, e @@ -605,27 +561,27 @@ class Socks5: def get_fd(self): """ - Test if file is already open and return its fd, or just open the file and - return the fd + Test if file is already open and return its fd, or just open the file + and return the fd """ - if 'fd' in self.file_props: - fd = self.file_props['fd'] + if self.file_props.fd: + fd = self.file_props.fd else: offset = 0 opt = 'wb' - if 'offset' in self.file_props and self.file_props['offset']: - offset = self.file_props['offset'] + if self.file_props.offset: + offset = self.file_props.offset opt = 'ab' - fd = open(self.file_props['file-name'], opt) - self.file_props['fd'] = fd - self.file_props['elapsed-time'] = 0 - self.file_props['last-time'] = self.idlequeue.current_time() - self.file_props['received-len'] = offset + fd = open(self.file_props.file_name, opt) + self.file_props.fd = fd + self.file_props.elapsed_time = 0 + self.file_props.last_time = self.idlequeue.current_time() + self.file_props.received_len = offset return fd def rem_fd(self, fd): - if 'fd' in self.file_props: - del(self.file_props['fd']) + if self.file_props.fd: + self.file_props.fd = None try: fd.close() except Exception: @@ -674,7 +630,7 @@ class Socks5: except IOError, e: self.state = 8 # end connection self.disconnect() - self.file_props['error'] = -7 # unable to read from file + self.file_props.error = -7 # unable to read from file return -1 buff = self.file.read(MAX_BUFF_LEN) if len(buff) > 0: @@ -690,17 +646,17 @@ class Socks5: # peer stopped reading self.state = 8 # end connection self.disconnect() - self.file_props['error'] = -1 + self.file_props.error = -1 return -1 self.size += lenn current_time = self.idlequeue.current_time() - self.file_props['elapsed-time'] += current_time - \ - self.file_props['last-time'] - self.file_props['last-time'] = current_time - self.file_props['received-len'] = self.size - if self.size >= int(self.file_props['size']): + self.file_props.elapsed_time += current_time - \ + self.file_props.last_time + self.file_props.last_time = current_time + self.file_props.received_len = self.size + if self.size >= int(self.file_props.size): self.state = 8 # end connection - self.file_props['error'] = 0 + self.file_props.error = 0 self.disconnect() return -1 if lenn != len(buff): @@ -710,7 +666,7 @@ class Socks5: self.state = 7 # continue to write in the socket if lenn == 0: return None - self.file_props['stalled'] = False + self.file_props.stalled = False return lenn else: self.state = 8 # end connection @@ -721,9 +677,9 @@ class Socks5: """ Read file contents from socket and write them to file """ - - if self.file_props is None or ('file-name' in self.file_props) is False: - self.file_props['error'] = -2 + + if self.file_props is None or not self.file_props.file_name: + self.file_props.error = -2 return None fd = None if self.remaining_buff != '': @@ -731,28 +687,28 @@ class Socks5: fd = self.get_fd() except IOError, e: self.disconnect(False) - self.file_props['error'] = -6 # file system error + self.file_props.error = -6 # file system error return 0 fd.write(self.remaining_buff) lenn = len(self.remaining_buff) current_time = self.idlequeue.current_time() - self.file_props['elapsed-time'] += current_time - \ - self.file_props['last-time'] - self.file_props['last-time'] = current_time - self.file_props['received-len'] += lenn + self.file_props.elapsed_time += current_time - \ + self.file_props.last_time + self.file_props.last_time = current_time + self.file_props.received_len += lenn self.remaining_buff = '' - if self.file_props['received-len'] == int(self.file_props['size']): + if self.file_props.received_len == int(self.file_props.size): self.rem_fd(fd) self.disconnect() - self.file_props['error'] = 0 - self.file_props['completed'] = True + self.file_props.error = 0 + self.file_props.completed = True return 0 else: try: fd = self.get_fd() except IOError, e: self.disconnect(False) - self.file_props['error'] = -6 # file system error + self.file_props.error = -6 # file system error return 0 try: buff = self._recv(MAX_BUFF_LEN) @@ -763,39 +719,39 @@ class Socks5: except Exception: buff = '' current_time = self.idlequeue.current_time() - self.file_props['elapsed-time'] += current_time - \ - self.file_props['last-time'] - self.file_props['last-time'] = current_time - self.file_props['received-len'] += len(buff) + self.file_props.elapsed_time += current_time - \ + self.file_props.last_time + self.file_props.last_time = current_time + self.file_props.received_len += len(buff) if len(buff) == 0: # Transfer stopped somehow: # reset, paused or network error self.rem_fd(fd) self.disconnect() - self.file_props['error'] = -1 + self.file_props.error = -1 return 0 try: fd.write(buff) except IOError, e: self.rem_fd(fd) self.disconnect() - self.file_props['error'] = -6 # file system error + self.file_props.error = -6 # file system error return 0 - if self.file_props['received-len'] >= int(self.file_props['size']): + if self.file_props.received_len >= int(self.file_props.size): # transfer completed self.rem_fd(fd) self.disconnect() - self.file_props['error'] = 0 - self.file_props['completed'] = True + self.file_props.error = 0 + self.file_props.completed = True return 0 # return number of read bytes. It can be used in progressbar if fd is not None: - self.file_props['stalled'] = False - if fd is None and self.file_props['stalled'] is False: + self.file_props.stalled = False + if fd is None and self.file_props.stalled is False: return None - if 'received-len' in self.file_props: - if self.file_props['received-len'] != 0: - return self.file_props['received-len'] + if self.file_props.received_len: + if self.file_props.received_len != 0: + return self.file_props.received_len return None def disconnect(self): @@ -814,7 +770,10 @@ class Socks5: if self.queue.listener.connections == []: self.queue.listener.disconnect() try: - self._sock.shutdown(socket.SHUT_RDWR) + if isinstance(self._sock, OpenSSL.SSL.Connection): + self._sock.shutdown() + else: + self._sock.shutdown(socket.SHUT_RDWR) self._sock.close() except Exception: # socket is already closed @@ -910,7 +869,7 @@ class Socks5: def continue_paused_transfer(self): if self.state < 5: return - if self.file_props['type'] == 'r': + if self.file_props.type_ == 'r': self.idlequeue.plug_idle(self, False, True) else: self.idlequeue.plug_idle(self, True, False) @@ -919,15 +878,15 @@ class Socks5: """ Get sha of sid + Initiator jid + Target jid """ - - if 'is_a_proxy' in self.file_props: - del(self.file_props['is_a_proxy']) + + if self.file_props.is_a_proxy: + self.file_props.is_a_proxy = None # Is this necesary? return hashlib.sha1('%s%s%s' % (self.sid, - self.file_props['proxy_sender'], - self.file_props['proxy_receiver'])).hexdigest() - return hashlib.sha1('%s%s%s' % (self.sid, self.initiator, self.target)).\ - hexdigest() - + self.file_props.proxy_sender, + self.file_props.proxy_receiver)).hexdigest() + return hashlib.sha1('%s%s%s' % (self.sid, self.initiator, + self.target)).hexdigest() + class Socks5Sender(IdleObject): """ @@ -936,24 +895,22 @@ class Socks5Sender(IdleObject): def __init__(self, idlequeue, sock_hash, parent, _sock, host=None, port=None, fingerprint = None, connected=True, file_props={}): - self.fingerprint = fingerprint self.queue_idx = sock_hash self.queue = parent self.file_props = file_props self.proxy = False - self._sock = _sock - if _sock is not None: - if self.fingerprint is not None: + if self.fingerprint is not None and not isinstance(self._sock, + OpenSSL.SSL.Connection): self._sock = OpenSSL.SSL.Connection( - jingle_xtls.get_context('server'), _sock) + jingle_xtls.get_context('server'), _sock) else: self._sock.setblocking(False) - + self.fd = _sock.fileno() self._recv = _sock.recv self._send = _sock.send @@ -961,18 +918,18 @@ class Socks5Sender(IdleObject): self.state = 1 # waiting for first bytes self.connect_timeout = 0 - self.file_props['error'] = 0 - self.file_props['disconnect_cb'] = self.disconnect - self.file_props['started'] = True - self.file_props['completed'] = False - self.file_props['paused'] = False - self.file_props['continue_cb'] = self.continue_paused_transfer - self.file_props['stalled'] = False - self.file_props['connected'] = True - self.file_props['elapsed-time'] = 0 - self.file_props['last-time'] = self.idlequeue.current_time() - self.file_props['received-len'] = 0 - self.type = 'sender' + self.file_props.error = 0 + self.file_props.disconnect_cb = self.disconnect + self.file_props.started = True + self.file_props.completed = False + self.file_props.paused = False + self.file_props.continue_cb = self.continue_paused_transfer + self.file_props.stalled = False + self.file_props.connected = True + self.file_props.elapsed_time = 0 + self.file_props.last_time = self.idlequeue.current_time() + self.file_props.received_len = 0 + self.type_ = 'sender' def start_transfer(self): """ @@ -980,14 +937,12 @@ class Socks5Sender(IdleObject): """ return self.write_next() - def set_connection_sock(self, _sock): - self._sock = _sock if self.fingerprint is not None: self._sock = OpenSSL.SSL.Connection( - jingle_xtls.get_context('client'), self._sock) + jingle_xtls.get_context('client'), _sock) else: self._sock.setblocking(False) @@ -1018,8 +973,8 @@ class Socks5Sender(IdleObject): # close connection and remove us from the queue Socks5.disconnect(self) if self.file_props is not None: - self.file_props['connected'] = False - self.file_props['disconnect_cb'] = None + self.file_props.connected = False + self.file_props.disconnect_cb = None if self.queue is not None: self.queue.remove_sender(self.queue_idx, False) @@ -1039,33 +994,32 @@ class Socks5Receiver(IdleObject): self.connected = False self.pauses = 0 self.file_props = file_props - self.file_props['disconnect_cb'] = self.disconnect - self.file_props['error'] = 0 - self.file_props['started'] = True - self.file_props['completed'] = False - self.file_props['paused'] = False - self.file_props['continue_cb'] = self.continue_paused_transfer - self.file_props['stalled'] = False - self.file_props['received-len'] = 0 - + self.file_props.disconnect_cb = self.disconnect + self.file_props.error = 0 + self.file_props.started = True + self.file_props.completed = False + self.file_props.paused = False + self.file_props.continue_cb = self.continue_paused_transfer + self.file_props.stalled = False + self.file_props.received_len = 0 def receive_file(self): """ Start receiving the file over verified connection """ - if self.file_props['started']: + if self.file_props.started: return - self.file_props['error'] = 0 - self.file_props['disconnect_cb'] = self.disconnect - self.file_props['started'] = True - self.file_props['completed'] = False - self.file_props['paused'] = False - self.file_props['continue_cb'] = self.continue_paused_transfer - self.file_props['stalled'] = False - self.file_props['connected'] = True - self.file_props['elapsed-time'] = 0 - self.file_props['last-time'] = self.idlequeue.current_time() - self.file_props['received-len'] = 0 + self.file_props.error = 0 + self.file_props.disconnect_cb = self.disconnect + self.file_props.started = True + self.file_props.completed = False + self.file_props.paused = False + self.file_props.continue_cb = self.continue_paused_transfer + self.file_props.stalled = False + self.file_props.connected = True + self.file_props.elapsed_time = 0 + self.file_props.last_time = self.idlequeue.current_time() + self.file_props.received_len = 0 self.pauses = 0 self.state = 7 # plug for reading @@ -1096,15 +1050,13 @@ class Socks5Receiver(IdleObject): # close connection Socks5.disconnect(self) if cb is True: - self.file_props['disconnect_cb'] = None + self.file_props.disconnect_cb = None if self.queue is not None: self.queue.remove_receiver(self.queue_idx, False) class Socks5Server(Socks5): def __init__(self, idlequeue, host, port, initiator, target, sid): - Socks5.__init__(self, idlequeue, host, port, initiator, target, sid) - self.mode = 'server' def main(self): @@ -1128,7 +1080,6 @@ class Socks5Server(Socks5): self.idlequeue.plug_idle(self, True, False) return None - def pollin(self): self.idlequeue.remove_timeout(self.fd) if self.connected: @@ -1142,7 +1093,7 @@ class Socks5Server(Socks5): elif self.state == 5: self.state = 7 - if self.type == 'sender': + if self.type_ == 'sender': # We wait for the end of the negotiation to # send the file self.idlequeue.plug_idle(self, False, False) @@ -1152,8 +1103,9 @@ class Socks5Server(Socks5): return elif self.state == 7: - if self.file_props['paused']: - self.file_props['continue_cb'] = self.continue_paused_transfer + if self.file_props.paused: + self.file_props.continue_cb = \ + self.continue_paused_transfer self.idlequeue.plug_idle(self, False, False) return self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT) @@ -1165,11 +1117,10 @@ class Socks5Server(Socks5): else: self.disconnect() - def pollend(self): self.state = 8 # end connection self.disconnect() - self.file_props['error'] = -1 + self.file_props.error = -1 self.queue.process_result(-1, self) def pollout(self): @@ -1177,26 +1128,31 @@ class Socks5Server(Socks5): self.disconnect() return self.idlequeue.remove_timeout(self.fd) - if self.state == 2: # send reply with desired auth type - self.send_raw(self._get_auth_response()) - elif self.state == 4: # send positive response to the 'connect' - self.send_raw(self._get_request_buff(self.sha_msg, 0x00)) - elif self.state == 7: - if self.file_props['paused']: - self.file_props['continue_cb'] = self.continue_paused_transfer - self.idlequeue.plug_idle(self, False, False) - return - result = self.start_transfer() # send - self.queue.process_result(result, self) - if result is None or result <= 0: + try: + if self.state == 2: # send reply with desired auth type + self.send_raw(self._get_auth_response()) + elif self.state == 4: # send positive response to the 'connect' + self.send_raw(self._get_request_buff(self.sha_msg, 0x00)) + elif self.state == 7: + if self.file_props.paused: + self.file_props.continue_cb = self.continue_paused_transfer + self.idlequeue.plug_idle(self, False, False) + return + result = self.start_transfer() # send + self.queue.process_result(result, self) + if result is None or result <= 0: + self.disconnect() + return + self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT) + elif self.state == 8: self.disconnect() return - self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT) - elif self.state == 8: - self.disconnect() + else: + self.disconnect() + except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError, + OpenSSL.SSL.WantX509LookupError), e: + log.info('caught SSL exception, ignored') return - else: - self.disconnect() if self.state < 5: self.state += 1 # unplug and plug this time for reading @@ -1206,9 +1162,7 @@ class Socks5Server(Socks5): class Socks5Client(Socks5): def __init__(self, idlequeue, host, port, initiator, target, sid): - Socks5.__init__(self, idlequeue, host, port, initiator, target, sid) - self.mode = 'client' def main(self, timeout=0): @@ -1251,9 +1205,8 @@ class Socks5Client(Socks5): if self.queue.on_success: result = self.queue.send_success_reply(self.file_props, self.streamhost) - if self.type == 'sender' and self.proxy: - self.queue.process_result( self.send_file() - , self) + if self.type_ == 'sender' and self.proxy: + self.queue.process_result(self.send_file(), self) return if result == 0: @@ -1262,16 +1215,16 @@ class Socks5Client(Socks5): # for senders: init file_props if result == 1 and self.state == 5: - if self.file_props['type'] == 's': - self.file_props['error'] = 0 - self.file_props['disconnect_cb'] = self.disconnect - self.file_props['started'] = True - self.file_props['completed'] = False - self.file_props['paused'] = False - self.file_props['stalled'] = False - self.file_props['elapsed-time'] = 0 - self.file_props['last-time'] = self.idlequeue.current_time() - self.file_props['received-len'] = 0 + if self.file_props.type_ == 's': + self.file_props.error = 0 + self.file_props.disconnect_cb = self.disconnect + self.file_props.started = True + self.file_props.completed = False + self.file_props.paused = False + self.file_props.stalled = False + self.file_props.elapsed_time = 0 + self.file_props.last_time = self.idlequeue.current_time() + self.file_props.received_len = 0 self.pauses = 0 # start sending file contents to socket #self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT) @@ -1281,7 +1234,7 @@ class Socks5Client(Socks5): # receiving file contents from socket self.idlequeue.plug_idle(self, False, True) - self.file_props['continue_cb'] = self.continue_paused_transfer + self.file_props.continue_cb = self.continue_paused_transfer # we have set up the connection, next - retrieve file self.state = 6 if self.state < 5: @@ -1289,12 +1242,11 @@ class Socks5Client(Socks5): self.state += 1 return None - def pollin(self): self.idlequeue.remove_timeout(self.fd) if self.connected: try: - if self.file_props['paused']: + if self.file_props.paused: self.idlequeue.plug_idle(self, False, False) return if self.state < 5: @@ -1303,7 +1255,7 @@ class Socks5Client(Socks5): self.queue.process_result(result, self) elif self.state == 5: # wait for proxy reply pass - elif self.file_props['type'] == 'r': + elif self.file_props.type_ == 'r': self.idlequeue.set_read_timeout(self.fd, STALLED_TIMEOUT) result = self.start_transfer() # receive self.queue.process_result(result, self) @@ -1324,8 +1276,8 @@ class Socks5Client(Socks5): self.send_raw(self._get_auth_buff()) elif self.state == 3: # send 'connect' request self.send_raw(self._get_request_buff(self._get_sha1_auth())) - elif self.file_props['type'] != 'r': - if self.file_props['paused']: + elif self.file_props.type_ != 'r': + if self.file_props.paused: self.idlequeue.plug_idle(self, False, False) return result = self.start_transfer() # send @@ -1344,39 +1296,30 @@ class Socks5Client(Socks5): if self.state >= 5: # error during transfer self.disconnect() - self.file_props['error'] = -1 + self.file_props.error = -1 self.queue.process_result(-1, self) else: self.queue.reconnect_client(self, self.streamhost) - class Socks5SenderClient(Socks5Client, Socks5Sender): def __init__(self, idlequeue, sock_hash, parent,_sock, host=None, - port=None, fingerprint = None, connected=True, file_props={}): - + port=None, fingerprint = None, connected=True, file_props={}): Socks5Client.__init__(self, idlequeue, host, port, None, None, - file_props['sid']) - - Socks5Sender.__init__(self,idlequeue, sock_hash, parent,_sock, - host, port, fingerprint , connected, file_props) - - - + file_props.sid) + Socks5Sender.__init__(self,idlequeue, sock_hash, parent,_sock, + host, port, fingerprint , connected, file_props) class Socks5SenderServer(Socks5Server, Socks5Sender): - - def __init__(self, idlequeue, sock_hash, parent,_sock, host=None, - port=None, fingerprint = None, connected=True, file_props={}): + def __init__(self, idlequeue, sock_hash, parent,_sock, host=None, + port=None, fingerprint = None, connected=True, file_props={}): Socks5Server.__init__(self, idlequeue, host, port, None, None, - file_props['sid']) - - Socks5Sender.__init__(self,idlequeue, sock_hash, parent, _sock, - host, port, fingerprint , connected, file_props) - + file_props.sid) + Socks5Sender.__init__(self,idlequeue, sock_hash, parent, _sock, + host, port, fingerprint , connected, file_props) class Socks5ReceiverClient(Socks5Client, Socks5Receiver): @@ -1384,27 +1327,21 @@ class Socks5ReceiverClient(Socks5Client, Socks5Receiver): def __init__(self, idlequeue, streamhost, sid, file_props = None, fingerprint=None): Socks5Client.__init__(self, idlequeue, streamhost['host'], - int(streamhost['port']), streamhost['initiator'], - streamhost['target'], sid) - + int(streamhost['port']), streamhost['initiator'], + streamhost['target'], sid) Socks5Receiver.__init__(self, idlequeue, streamhost, sid, file_props, - fingerprint) + fingerprint) - - class Socks5ReceiverServer(Socks5Server, Socks5Receiver): def __init__(self, idlequeue, streamhost, sid, file_props = None, fingerprint=None): - Socks5Server.__init__(self, idlequeue, streamhost['host'], - int(streamhost['port']), streamhost['initiator'], - streamhost['target'], sid) - + int(streamhost['port']), streamhost['initiator'], + streamhost['target'], sid) Socks5Receiver.__init__(self, idlequeue, streamhost, sid, file_props, - fingerprint) - + fingerprint) class Socks5Listener(IdleObject): @@ -1420,7 +1357,7 @@ class Socks5Listener(IdleObject): """ self.port = port self.ais = socket.getaddrinfo(None, port, socket.AF_UNSPEC, - socket.SOCK_STREAM, socket.SOL_TCP, socket.AI_PASSIVE) + socket.SOCK_STREAM, socket.SOL_TCP, socket.AI_PASSIVE) self.ais.sort(reverse=True) # Try IPv6 first self.queue_idx = -1 self.idlequeue = idlequeue @@ -1508,5 +1445,3 @@ class Socks5Listener(IdleObject): _sock[0].setblocking(False) self.connections.append(_sock[0]) return _sock - - diff --git a/src/common/stanza_session.py b/src/common/stanza_session.py index 618dd744a827ab293bdad1e636d34b5713b12248..9e3ae6acb256ca1c7974c8311e5e6599198886c9 100644 --- a/src/common/stanza_session.py +++ b/src/common/stanza_session.py @@ -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: diff --git a/src/common/xmpp/protocol.py b/src/common/xmpp/protocol.py index daac07278e3e1b9f6c5105c6f084a23a6e35c70b..d4c5fb25425d6b8b66669947ea00c761704cba71 100644 --- a/src/common/xmpp/protocol.py +++ b/src/common/xmpp/protocol.py @@ -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 diff --git a/src/config.py b/src/config.py index 6c90dadbf16106be4e8934a02e04daa03c993b48..b0241102600890a2d96a0670ea8c9ac3ff69ca4b 100644 --- a/src/config.py +++ b/src/config.py @@ -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)) diff --git a/src/dataforms_widget.py b/src/dataforms_widget.py index 25f0b93b80134e55305e9daaecde2d377cfd4136..eab227235892633da6609366f8dca67979083f41 100644 --- a/src/dataforms_widget.py +++ b/src/dataforms_widget.py @@ -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 diff --git a/src/filetransfers_window.py b/src/filetransfers_window.py index bcc67ce78c72a261298ae680ee6e0ae0d54d9db0..4ee201ae7426dacebf9ffad730a04ecc13827445 100644 --- a/src/filetransfers_window.py +++ b/src/filetransfers_window.py @@ -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['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.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) 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() diff --git a/src/groupchat_control.py b/src/groupchat_control.py index c5f6ef58726799cc20745102ea368d6a039ed3ba..a777d0be168a361bd0a64c1fe421cf1d621d904f 100644 --- a/src/groupchat_control.py +++ b/src/groupchat_control.py @@ -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() diff --git a/src/gui_interface.py b/src/gui_interface.py index 86de2342730b3ef3ab3b9242f79d05b1ab4af83c..c9fa3a71adb6a754086664bdd616fac3dbe54d40 100644 --- a/src/gui_interface.py +++ b/src/gui_interface.py @@ -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') diff --git a/src/roster_window.py b/src/roster_window.py index 18316811ed258ffd2c0a6e7cf9bab6a53dfd6069..d24087a268adf15d996d067359b8b3832c4ec0fc 100644 --- a/src/roster_window.py +++ b/src/roster_window.py @@ -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) diff --git a/src/search_window.py b/src/search_window.py index 2a0b41ad9d4a0760a2d74bffe634adad295c049c..1b2f3a02b9b4563b5a3c8bb4f761b3cff1309e5f 100644 --- a/src/search_window.py +++ b/src/search_window.py @@ -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: diff --git a/src/statusicon.py b/src/statusicon.py index c129c7899a0a8ee3ad19da438ca36f3f25cf84f5..7a109d97acd23875191b0202128c9e7cd43465cc 100644 --- a/src/statusicon.py +++ b/src/statusicon.py @@ -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() diff --git a/src/tooltips.py b/src/tooltips.py index 081c22951fe91c21946882273717519dd7faaa21..98f5af2cd7cd07c84c65209bfaae9248e5ef91b0 100644 --- a/src/tooltips.py +++ b/src/tooltips.py @@ -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 diff --git a/test/lib/gajim_mocks.py b/test/lib/gajim_mocks.py index 52b8d07569293379b8853d92fad773c37321bba1..4070641e9393c944497e9ff647e8ad36758bf724 100644 --- a/test/lib/gajim_mocks.py +++ b/test/lib/gajim_mocks.py @@ -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: