From d48202d221ed6d61571aed16a886e70009c5b4b6 Mon Sep 17 00:00:00 2001 From: Stephan Erb Date: Thu, 10 Dec 2009 21:52:32 +0100 Subject: [PATCH 1/7] Move ConnectionBytestream to common/protocols. --- src/common/connection_handlers.py | 610 +--------------- src/common/protocol/bytestream.py | 662 ++++++++++++++++++ .../zeroconf/connection_handlers_zeroconf.py | 19 +- 3 files changed, 666 insertions(+), 625 deletions(-) create mode 100644 src/common/protocol/bytestream.py diff --git a/src/common/connection_handlers.py b/src/common/connection_handlers.py index 5e65a371e..650a54e60 100644 --- a/src/common/connection_handlers.py +++ b/src/common/connection_handlers.py @@ -30,7 +30,6 @@ import os import base64 -import socket import sys import operator import hashlib @@ -41,7 +40,6 @@ from time import (altzone, daylight, gmtime, localtime, mktime, strftime, from calendar import timegm import datetime -import socks5 import common.xmpp from common import helpers @@ -51,6 +49,7 @@ from common.commands import ConnectionCommands from common.pubsub import ConnectionPubSub from common.pep import ConnectionPEP from common.protocol.caps import ConnectionCaps +from common.protocol.bytestream import ConnectionBytestream import common.caps_cache as capscache if gajim.HAVE_FARSIGHT: from common.jingle import ConnectionJingle @@ -84,613 +83,6 @@ except Exception: log.debug(_('Unable to load idle module')) HAS_IDLE = False -class ConnectionBytestream: - def __init__(self): - self.files_props = {} - self.awaiting_xmpp_ping_id = None - - def is_transfer_stopped(self, file_props): - if 'error' in file_props and file_props['error'] != 0: - return True - if 'completed' in file_props and file_props['completed']: - return True - if 'connected' in file_props and file_props['connected'] == False: - return True - if 'stopped' not in file_props or not file_props['stopped']: - return False - return True - - def send_success_connect_reply(self, streamhost): - """ - Send reply to the initiator of FT that we made a connection - """ - if not self.connection or self.connected < 2: - return - if streamhost is None: - return None - iq = common.xmpp.Iq(to = streamhost['initiator'], typ = 'result', - frm = streamhost['target']) - iq.setAttr('id', streamhost['id']) - query = iq.setTag('query') - query.setNamespace(common.xmpp.NS_BYTESTREAM) - stream_tag = query.setTag('streamhost-used') - stream_tag.setAttr('jid', streamhost['jid']) - self.connection.send(iq) - - def remove_transfers_for_contact(self, contact): - """ - Stop all active transfer for contact - """ - for file_props in self.files_props.values(): - if self.is_transfer_stopped(file_props): - continue - receiver_jid = unicode(file_props['receiver']) - if contact.get_full_jid() == receiver_jid: - file_props['error'] = -5 - self.remove_transfer(file_props) - self.dispatch('FILE_REQUEST_ERROR', (contact.jid, file_props, '')) - sender_jid = unicode(file_props['sender']) - if contact.get_full_jid() == sender_jid: - 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(): - self.remove_transfer(file_props, remove_from_list = False) - del(self.files_props) - 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']) - - 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 'streamhosts' in file_props: - 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']) - - def send_socks5_info(self, file_props, fast = True, receiver = None, sender - = None): - """ - Send iq for the present streamhosts and proxies - """ - if not self.connection or self.connected < 2: - return - if not isinstance(self.peerhost, tuple): - return - port = gajim.config.get('file_transfers_port') - ft_add_hosts_to_send = gajim.config.get('ft_add_hosts_to_send') - cfg_proxies = gajim.config.get_per('accounts', self.name, - 'file_transfer_proxies') - if receiver is None: - receiver = file_props['receiver'] - if sender is None: - sender = file_props['sender'] - proxyhosts = [] - if fast and cfg_proxies: - proxies = [e.strip() for e in cfg_proxies.split(',')] - default = gajim.proxy65_manager.get_default_for_name(self.name) - if default: - # add/move default proxy at top of the others - if proxies.__contains__(default): - proxies.remove(default) - proxies.insert(0, default) - - for proxy in proxies: - (host, _port, jid) = gajim.proxy65_manager.get_proxy(proxy, self.name) - if host is None: - continue - host_dict={ - 'state': 0, - 'target': unicode(receiver), - 'id': file_props['sid'], - 'sid': file_props['sid'], - 'initiator': proxy, - 'host': host, - 'port': unicode(_port), - 'jid': jid - } - proxyhosts.append(host_dict) - sha_str = helpers.get_auth_sha(file_props['sid'], sender, - receiver) - file_props['sha_str'] = sha_str - ft_add_hosts = [] - if ft_add_hosts_to_send: - ft_add_hosts_to_send = [e.strip() for e in ft_add_hosts_to_send.split(',')] - for ft_host in ft_add_hosts_to_send: - ft_add_hosts.append(ft_host) - listener = gajim.socks5queue.start_listener(port, - sha_str, self._result_socks5_sid, file_props['sid']) - if listener is None: - file_props['error'] = -5 - self.dispatch('FILE_REQUEST_ERROR', (unicode(receiver), file_props, - '')) - self._connect_error(unicode(receiver), file_props['sid'], - file_props['sid'], code = 406) - return - - iq = common.xmpp.Protocol(name = 'iq', to = unicode(receiver), - typ = 'set') - file_props['request-id'] = 'id_' + file_props['sid'] - iq.setID(file_props['request-id']) - query = iq.setTag('query') - query.setNamespace(common.xmpp.NS_BYTESTREAM) - query.setAttr('mode', 'plain') - query.setAttr('sid', file_props['sid']) - for ft_host in ft_add_hosts: - # The streamhost, if set - ostreamhost = common.xmpp.Node(tag = 'streamhost') - query.addChild(node = ostreamhost) - ostreamhost.setAttr('port', unicode(port)) - ostreamhost.setAttr('host', ft_host) - ostreamhost.setAttr('jid', sender) - try: - # The ip we're connected to server with - my_ips = [self.peerhost[0]] - # all IPs from local DNS - for addr in socket.getaddrinfo(socket.gethostname(), None): - if not addr[4][0] in my_ips and not addr[4][0].startswith('127'): - my_ips.append(addr[4][0]) - for ip in my_ips: - streamhost = common.xmpp.Node(tag = 'streamhost') - query.addChild(node = streamhost) - streamhost.setAttr('port', unicode(port)) - streamhost.setAttr('host', ip) - streamhost.setAttr('jid', sender) - except socket.gaierror: - self.dispatch('ERROR', (_('Wrong host'), - _('Invalid local address? :-O'))) - - if fast and proxyhosts != [] and gajim.config.get_per('accounts', - self.name, 'use_ft_proxies'): - file_props['proxy_receiver'] = unicode(receiver) - file_props['proxy_sender'] = unicode(sender) - file_props['proxyhosts'] = proxyhosts - for proxyhost in proxyhosts: - streamhost = common.xmpp.Node(tag = 'streamhost') - query.addChild(node=streamhost) - streamhost.setAttr('port', proxyhost['port']) - streamhost.setAttr('host', proxyhost['host']) - streamhost.setAttr('jid', proxyhost['jid']) - - # don't add the proxy child tag for streamhosts, which are proxies - # proxy = streamhost.setTag('proxy') - # proxy.setNamespace(common.xmpp.NS_STREAM) - self.connection.send(iq) - - def send_file_rejection(self, file_props, code='403', typ=None): - """ - Inform sender that we refuse to download the file - - typ is used when code = '400', in this case typ can be 'strean' for - invalid stream or 'profile' for invalid profile - """ - # user response to ConfirmationDialog may come after we've disconneted - if not self.connection or self.connected < 2: - return - iq = common.xmpp.Protocol(name = '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 = '' - else: - name = 'forbidden' - text = 'Offer Declined' - err = common.xmpp.ErrorNode(code=code, typ='cancel', name=name, text=text) - if code == '400' and typ in ('stream', 'profile'): - if typ == 'stream': - err.setTag('no-valid-streams', namespace=common.xmpp.NS_SI) - else: - err.setTag('bad-profile', namespace=common.xmpp.NS_SI) - iq.addChild(node=err) - self.connection.send(iq) - - def send_file_approval(self, file_props): - """ - Send iq, confirming that we want to download the file - """ - # user response to ConfirmationDialog may come after we've disconneted - if not self.connection or self.connected < 2: - return - iq = common.xmpp.Protocol(name = 'iq', - to = unicode(file_props['sender']), typ = 'result') - iq.setAttr('id', file_props['request-id']) - si = iq.setTag('si') - si.setNamespace(common.xmpp.NS_SI) - if 'offset' in file_props and file_props['offset']: - file_tag = si.setTag('file') - file_tag.setNamespace(common.xmpp.NS_FILE) - range_tag = file_tag.setTag('range') - range_tag.setAttr('offset', file_props['offset']) - feature = si.setTag('feature') - feature.setNamespace(common.xmpp.NS_FEATURE) - _feature = common.xmpp.DataForm(typ='submit') - feature.addChild(node=_feature) - field = _feature.setField('stream-method') - field.delAttr('type') - field.setValue(common.xmpp.NS_BYTESTREAM) - self.connection.send(iq) - - def _ft_get_our_jid(self): - our_jid = gajim.get_jid_from_account(self.name) - resource = self.server_resource - return our_jid + '/' + resource - - def _ft_get_receiver_jid(self, file_props): - return file_props['receiver'].jid + '/' + file_props['receiver'].resource - - def send_file_request(self, file_props): - """ - Send iq for new FT request - """ - if not self.connection or self.connected < 2: - return - file_props['sender'] = self._ft_get_our_jid() - fjid = self._ft_get_receiver_jid(file_props) - iq = common.xmpp.Protocol(name = 'iq', to = fjid, - typ = 'set') - iq.setID(file_props['sid']) - self.files_props[file_props['sid']] = file_props - si = iq.setTag('si') - si.setNamespace(common.xmpp.NS_SI) - si.setAttr('profile', common.xmpp.NS_FILE) - si.setAttr('id', file_props['sid']) - file_tag = si.setTag('file') - file_tag.setNamespace(common.xmpp.NS_FILE) - 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']) - file_tag.setTag('range') - feature = si.setTag('feature') - feature.setNamespace(common.xmpp.NS_FEATURE) - _feature = common.xmpp.DataForm(typ='form') - feature.addChild(node=_feature) - field = _feature.setField('stream-method') - field.setAttr('type', 'list-single') - field.addOption(common.xmpp.NS_BYTESTREAM) - self.connection.send(iq) - - def _result_socks5_sid(self, sid, hash_id): - """ - 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 - return - - def _connect_error(self, to, _id, 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 - msg_dict = { - 404: 'Could not connect to given hosts', - 405: 'Cancel', - 406: 'Not acceptable', - } - msg = msg_dict[code] - iq = None - iq = common.xmpp.Protocol(name = 'iq', to = to, - typ = 'error') - iq.setAttr('id', _id) - 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 - self.dispatch('FILE_REQUEST_ERROR', (to, file_props, msg)) - - def _proxy_auth_ok(self, proxy): - """ - Called after authentication to proxy server - """ - if not self.connection or self.connected < 2: - return - file_props = self.files_props[proxy['sid']] - iq = common.xmpp.Protocol(name = 'iq', to = proxy['initiator'], - typ = 'set') - auth_id = "au_" + proxy['sid'] - iq.setID(auth_id) - query = iq.setTag('query') - query.setNamespace(common.xmpp.NS_BYTESTREAM) - query.setAttr('sid', proxy['sid']) - activate = query.setTag('activate') - activate.setData(file_props['proxy_receiver']) - iq.setID(auth_id) - self.connection.send(iq) - - # register xmpppy handlers for bytestream and FT stanzas - def _bytestreamErrorCB(self, con, iq_obj): - log.debug('_bytestreamErrorCB') - id_ = unicode(iq_obj.getAttr('id')) - frm = helpers.get_full_jid_from_iq(iq_obj) - query = iq_obj.getTag('query') - 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: - return - file_props = self.files_props[id_] - file_props['error'] = -4 - self.dispatch('FILE_REQUEST_ERROR', (jid, file_props, '')) - raise common.xmpp.NodeProcessed - - def _ft_get_from(self, iq_obj): - return helpers.get_full_jid_from_iq(iq_obj) - - def _bytestreamSetCB(self, con, iq_obj): - log.debug('_bytestreamSetCB') - target = unicode(iq_obj.getAttr('to')) - 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) - streamhosts=[] - for item in query.getChildren(): - if item.getName() == 'streamhost': - host_dict={ - 'state': 0, - 'target': target, - 'id': id_, - 'sid': sid, - 'initiator': self._ft_get_from(iq_obj) - } - for attr in item.getAttrs(): - host_dict[attr] = item.getAttr(attr) - 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) - raise common.xmpp.NodeProcessed - - 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 common.xmpp.NodeProcessed - - def _ResultCB(self, con, iq_obj): - log.debug('_ResultCB') - # if we want to respect xep-0065 we have to check for proxy - # activation result in any result iq - real_id = unicode(iq_obj.getAttr('id')) - if real_id == self.awaiting_xmpp_ping_id: - self.awaiting_xmpp_ping_id = None - return - if not real_id.startswith('au_'): - 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 common.xmpp.NodeProcessed - - def _ft_get_streamhost_jid_attr(self, streamhost): - return helpers.parse_jid(streamhost.getAttr('jid')) - - def _bytestreamResultCB(self, con, iq_obj): - log.debug('_bytestreamResultCB') - frm = self._ft_get_from(iq_obj) - real_id = unicode(iq_obj.getAttr('id')) - query = iq_obj.getTag('query') - gajim.proxy65_manager.resolve_result(frm, query) - - try: - streamhost = query.getTag('streamhost-used') - 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: - raise common.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: - raise common.xmpp.NodeProcessed - if 'proxyhosts' not in file_props: - raise common.xmpp.NodeProcessed - for host in file_props['proxyhosts']: - if host['initiator'] == frm and \ - unicode(query.getAttr('sid')) == file_props['sid']: - gajim.socks5queue.activate_proxy(host['idx']) - break - raise common.xmpp.NodeProcessed - jid = self._ft_get_streamhost_jid_attr(streamhost) - if 'streamhost-used' in file_props and \ - file_props['streamhost-used'] is True: - raise common.xmpp.NodeProcessed - - if real_id.startswith('au_'): - if 'stopped' in file and file_props['stopped']: - self.remove_transfer(file_props) - else: - gajim.socks5queue.send_file(file_props, self.name) - raise common.xmpp.NodeProcessed - - proxy = None - if 'proxyhosts' in file_props: - for proxyhost in file_props['proxyhosts']: - if proxyhost['jid'] == jid: - proxy = proxyhost - - 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 = socks5.Socks5Receiver(gajim.idlequeue, proxy, - file_props['sid'], file_props) - gajim.socks5queue.add_receiver(self.name, receiver) - proxy['idx'] = receiver.queue_idx - gajim.socks5queue.on_success = self._proxy_auth_ok - raise common.xmpp.NodeProcessed - - else: - if 'stopped' in file_props and file_props['stopped']: - self.remove_transfer(file_props) - else: - gajim.socks5queue.send_file(file_props, self.name) - 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) - - raise common.xmpp.NodeProcessed - - def _siResultCB(self, con, iq_obj): - log.debug('_siResultCB') - id_ = iq_obj.getAttr('id') - if id_ not in self.files_props: - # no such jid - return - file_props = self.files_props[id_] - if file_props is None: - # file properties for jid is none - return - if 'request-id' in file_props: - # we have already sent streamhosts info - return - file_props['receiver'] = self._ft_get_from(iq_obj) - si = iq_obj.getTag('si') - file_tag = si.getTag('file') - range_tag = None - if file_tag: - range_tag = file_tag.getTag('range') - if range_tag: - offset = range_tag.getAttr('offset') - if offset: - file_props['offset'] = int(offset) - length = range_tag.getAttr('length') - if length: - file_props['length'] = int(length) - feature = si.setTag('feature') - if feature.getNamespace() != common.xmpp.NS_FEATURE: - return - form_tag = feature.getTag('x') - form = common.xmpp.DataForm(node=form_tag) - field = form.getField('stream-method') - if field.getValue() != common.xmpp.NS_BYTESTREAM: - return - self.send_socks5_info(file_props, fast = True) - raise common.xmpp.NodeProcessed - - def _siSetCB(self, con, iq_obj): - log.debug('_siSetCB') - jid = self._ft_get_from(iq_obj) - file_props = {'type': 'r'} - file_props['sender'] = jid - file_props['request-id'] = unicode(iq_obj.getAttr('id')) - si = iq_obj.getTag('si') - profile = si.getAttr('profile') - mime_type = si.getAttr('mime-type') - if profile != common.xmpp.NS_FILE: - self.send_file_rejection(file_props, code='400', typ='profile') - raise common.xmpp.NodeProcessed - feature_tag = si.getTag('feature', namespace=common.xmpp.NS_FEATURE) - if not feature_tag: - return - form_tag = feature_tag.getTag('x', namespace=common.xmpp.NS_DATA) - if not form_tag: - return - form = common.dataforms.ExtendForm(node=form_tag) - for f in form.iter_fields(): - if f.var == 'stream-method' and f.type == 'list-single': - values = [o[1] for o in f.options] - if common.xmpp.NS_BYTESTREAM in values: - break - else: - self.send_file_rejection(file_props, code='400', typ='stream') - raise common.xmpp.NodeProcessed - file_tag = si.getTag('file') - for attribute in file_tag.getAttrs(): - if attribute in ('name', 'size', 'hash', 'date'): - val = file_tag.getAttr(attribute) - if val is None: - continue - file_props[attribute] = val - file_desc_tag = file_tag.getTag('desc') - if file_desc_tag is not None: - file_props['desc'] = file_desc_tag.getData() - - if mime_type is not None: - file_props['mime-type'] = mime_type - our_jid = gajim.get_jid_from_account(self.name) - resource = self.server_resource - file_props['receiver'] = self._ft_get_our_jid() - file_props['sid'] = unicode(si.getAttr('id')) - file_props['transfered_size'] = [] - gajim.socks5queue.add_file_props(self.name, file_props) - self.dispatch('FILE_REQUEST', (jid, file_props)) - raise common.xmpp.NodeProcessed - - def _siErrorCB(self, con, iq_obj): - log.debug('_siErrorCB') - si = iq_obj.getTag('si') - profile = si.getAttr('profile') - if profile != common.xmpp.NS_FILE: - return - id_ = iq_obj.getAttr('id') - if id_ not in self.files_props: - # no such jid - return - file_props = self.files_props[id_] - if file_props is None: - # file properties for jid is none - return - jid = self._ft_get_from(iq_obj) - file_props['error'] = -3 - self.dispatch('FILE_REQUEST_ERROR', (jid, file_props, '')) - raise common.xmpp.NodeProcessed class ConnectionDisco: """ diff --git a/src/common/protocol/bytestream.py b/src/common/protocol/bytestream.py new file mode 100644 index 000000000..92d0d9c73 --- /dev/null +++ b/src/common/protocol/bytestream.py @@ -0,0 +1,662 @@ +# -*- coding:utf-8 -*- +## src/common/connection_handlers.py +## +## Copyright (C) 2006 Dimitur Kirov +## Junglecow J +## Copyright (C) 2006-2007 Tomasz Melcer +## Travis Shirk +## Nikos Kouremenos +## Copyright (C) 2006-2008 Yann Leboulanger +## Copyright (C) 2007 Julien Pivotto +## Copyright (C) 2007-2008 Brendan Taylor +## Jean-Marie Traissard +## Stephan Erb +## Copyright (C) 2008 Jonathan Schleifer +## +## This file is part of Gajim. +## +## Gajim is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published +## by the Free Software Foundation; version 3 only. +## +## Gajim is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Gajim. If not, see . +## + +import socket + +import common.xmpp +from common import gajim + + + +class ConnectionBytestream: + + def __init__(self): + self.files_props = {} + self.awaiting_xmpp_ping_id = None + + def is_transfer_stopped(self, file_props): + if 'error' in file_props and file_props['error'] != 0: + return True + if 'completed' in file_props and file_props['completed']: + return True + if 'connected' in file_props and file_props['connected'] == False: + return True + if 'stopped' not in file_props or not file_props['stopped']: + return False + return True + + def send_success_connect_reply(self, streamhost): + """ + Send reply to the initiator of FT that we made a connection + """ + if not self.connection or self.connected < 2: + return + if streamhost is None: + return None + iq = common.xmpp.Iq(to = streamhost['initiator'], typ = 'result', + frm = streamhost['target']) + iq.setAttr('id', streamhost['id']) + query = iq.setTag('query') + query.setNamespace(common.xmpp.NS_BYTESTREAM) + stream_tag = query.setTag('streamhost-used') + stream_tag.setAttr('jid', streamhost['jid']) + self.connection.send(iq) + + def remove_transfers_for_contact(self, contact): + """ + Stop all active transfer for contact + """ + for file_props in self.files_props.values(): + if self.is_transfer_stopped(file_props): + continue + receiver_jid = unicode(file_props['receiver']) + if contact.get_full_jid() == receiver_jid: + file_props['error'] = -5 + self.remove_transfer(file_props) + self.dispatch('FILE_REQUEST_ERROR', (contact.jid, file_props, '')) + sender_jid = unicode(file_props['sender']) + if contact.get_full_jid() == sender_jid: + 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(): + self.remove_transfer(file_props, remove_from_list = False) + del(self.files_props) + 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']) + + 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 'streamhosts' in file_props: + 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']) + + def send_socks5_info(self, file_props, fast = True, receiver = None, sender + = None): + """ + Send iq for the present streamhosts and proxies + """ + if not self.connection or self.connected < 2: + return + if not isinstance(self.peerhost, tuple): + return + port = gajim.config.get('file_transfers_port') + ft_add_hosts_to_send = gajim.config.get('ft_add_hosts_to_send') + cfg_proxies = gajim.config.get_per('accounts', self.name, + 'file_transfer_proxies') + if receiver is None: + receiver = file_props['receiver'] + if sender is None: + sender = file_props['sender'] + proxyhosts = [] + if fast and cfg_proxies: + proxies = [e.strip() for e in cfg_proxies.split(',')] + default = gajim.proxy65_manager.get_default_for_name(self.name) + if default: + # add/move default proxy at top of the others + if proxies.__contains__(default): + proxies.remove(default) + proxies.insert(0, default) + + for proxy in proxies: + (host, _port, jid) = gajim.proxy65_manager.get_proxy(proxy, self.name) + if host is None: + continue + host_dict={ + 'state': 0, + 'target': unicode(receiver), + 'id': file_props['sid'], + 'sid': file_props['sid'], + 'initiator': proxy, + 'host': host, + 'port': unicode(_port), + 'jid': jid + } + proxyhosts.append(host_dict) + sha_str = helpers.get_auth_sha(file_props['sid'], sender, + receiver) + file_props['sha_str'] = sha_str + ft_add_hosts = [] + if ft_add_hosts_to_send: + ft_add_hosts_to_send = [e.strip() for e in ft_add_hosts_to_send.split(',')] + for ft_host in ft_add_hosts_to_send: + ft_add_hosts.append(ft_host) + listener = gajim.socks5queue.start_listener(port, + sha_str, self._result_socks5_sid, file_props['sid']) + if listener is None: + file_props['error'] = -5 + self.dispatch('FILE_REQUEST_ERROR', (unicode(receiver), file_props, + '')) + self._connect_error(unicode(receiver), file_props['sid'], + file_props['sid'], code = 406) + return + + iq = common.xmpp.Protocol(name = 'iq', to = unicode(receiver), + typ = 'set') + file_props['request-id'] = 'id_' + file_props['sid'] + iq.setID(file_props['request-id']) + query = iq.setTag('query') + query.setNamespace(common.xmpp.NS_BYTESTREAM) + query.setAttr('mode', 'plain') + query.setAttr('sid', file_props['sid']) + for ft_host in ft_add_hosts: + # The streamhost, if set + ostreamhost = common.xmpp.Node(tag = 'streamhost') + query.addChild(node = ostreamhost) + ostreamhost.setAttr('port', unicode(port)) + ostreamhost.setAttr('host', ft_host) + ostreamhost.setAttr('jid', sender) + try: + # The ip we're connected to server with + my_ips = [self.peerhost[0]] + # all IPs from local DNS + for addr in socket.getaddrinfo(socket.gethostname(), None): + if not addr[4][0] in my_ips and not addr[4][0].startswith('127'): + my_ips.append(addr[4][0]) + for ip in my_ips: + streamhost = common.xmpp.Node(tag = 'streamhost') + query.addChild(node = streamhost) + streamhost.setAttr('port', unicode(port)) + streamhost.setAttr('host', ip) + streamhost.setAttr('jid', sender) + except socket.gaierror: + self.dispatch('ERROR', (_('Wrong host'), + _('Invalid local address? :-O'))) + + if fast and proxyhosts != [] and gajim.config.get_per('accounts', + self.name, 'use_ft_proxies'): + file_props['proxy_receiver'] = unicode(receiver) + file_props['proxy_sender'] = unicode(sender) + file_props['proxyhosts'] = proxyhosts + for proxyhost in proxyhosts: + streamhost = common.xmpp.Node(tag = 'streamhost') + query.addChild(node=streamhost) + streamhost.setAttr('port', proxyhost['port']) + streamhost.setAttr('host', proxyhost['host']) + streamhost.setAttr('jid', proxyhost['jid']) + + # don't add the proxy child tag for streamhosts, which are proxies + # proxy = streamhost.setTag('proxy') + # proxy.setNamespace(common.xmpp.NS_STREAM) + self.connection.send(iq) + + def send_file_rejection(self, file_props, code='403', typ=None): + """ + Inform sender that we refuse to download the file + + typ is used when code = '400', in this case typ can be 'strean' for + invalid stream or 'profile' for invalid profile + """ + # user response to ConfirmationDialog may come after we've disconneted + if not self.connection or self.connected < 2: + return + iq = common.xmpp.Protocol(name = '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 = '' + else: + name = 'forbidden' + text = 'Offer Declined' + err = common.xmpp.ErrorNode(code=code, typ='cancel', name=name, text=text) + if code == '400' and typ in ('stream', 'profile'): + if typ == 'stream': + err.setTag('no-valid-streams', namespace=common.xmpp.NS_SI) + else: + err.setTag('bad-profile', namespace=common.xmpp.NS_SI) + iq.addChild(node=err) + self.connection.send(iq) + + def send_file_approval(self, file_props): + """ + Send iq, confirming that we want to download the file + """ + # user response to ConfirmationDialog may come after we've disconneted + if not self.connection or self.connected < 2: + return + iq = common.xmpp.Protocol(name = 'iq', + to = unicode(file_props['sender']), typ = 'result') + iq.setAttr('id', file_props['request-id']) + si = iq.setTag('si') + si.setNamespace(common.xmpp.NS_SI) + if 'offset' in file_props and file_props['offset']: + file_tag = si.setTag('file') + file_tag.setNamespace(common.xmpp.NS_FILE) + range_tag = file_tag.setTag('range') + range_tag.setAttr('offset', file_props['offset']) + feature = si.setTag('feature') + feature.setNamespace(common.xmpp.NS_FEATURE) + _feature = common.xmpp.DataForm(typ='submit') + feature.addChild(node=_feature) + field = _feature.setField('stream-method') + field.delAttr('type') + field.setValue(common.xmpp.NS_BYTESTREAM) + self.connection.send(iq) + + def _ft_get_our_jid(self): + our_jid = gajim.get_jid_from_account(self.name) + resource = self.server_resource + return our_jid + '/' + resource + + def _ft_get_receiver_jid(self, file_props): + return file_props['receiver'].jid + '/' + file_props['receiver'].resource + + def send_file_request(self, file_props): + """ + Send iq for new FT request + """ + if not self.connection or self.connected < 2: + return + file_props['sender'] = self._ft_get_our_jid() + fjid = self._ft_get_receiver_jid(file_props) + iq = common.xmpp.Protocol(name = 'iq', to = fjid, + typ = 'set') + iq.setID(file_props['sid']) + self.files_props[file_props['sid']] = file_props + si = iq.setTag('si') + si.setNamespace(common.xmpp.NS_SI) + si.setAttr('profile', common.xmpp.NS_FILE) + si.setAttr('id', file_props['sid']) + file_tag = si.setTag('file') + file_tag.setNamespace(common.xmpp.NS_FILE) + 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']) + file_tag.setTag('range') + feature = si.setTag('feature') + feature.setNamespace(common.xmpp.NS_FEATURE) + _feature = common.xmpp.DataForm(typ='form') + feature.addChild(node=_feature) + field = _feature.setField('stream-method') + field.setAttr('type', 'list-single') + field.addOption(common.xmpp.NS_BYTESTREAM) + self.connection.send(iq) + + def _result_socks5_sid(self, sid, hash_id): + """ + 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 + return + + def _connect_error(self, to, _id, 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 + msg_dict = { + 404: 'Could not connect to given hosts', + 405: 'Cancel', + 406: 'Not acceptable', + } + msg = msg_dict[code] + iq = None + iq = common.xmpp.Protocol(name = 'iq', to = to, + typ = 'error') + iq.setAttr('id', _id) + 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 + self.dispatch('FILE_REQUEST_ERROR', (to, file_props, msg)) + + def _proxy_auth_ok(self, proxy): + """ + Called after authentication to proxy server + """ + if not self.connection or self.connected < 2: + return + file_props = self.files_props[proxy['sid']] + iq = common.xmpp.Protocol(name = 'iq', to = proxy['initiator'], + typ = 'set') + auth_id = "au_" + proxy['sid'] + iq.setID(auth_id) + query = iq.setTag('query') + query.setNamespace(common.xmpp.NS_BYTESTREAM) + query.setAttr('sid', proxy['sid']) + activate = query.setTag('activate') + activate.setData(file_props['proxy_receiver']) + iq.setID(auth_id) + self.connection.send(iq) + + # register xmpppy handlers for bytestream and FT stanzas + def _bytestreamErrorCB(self, con, iq_obj): + log.debug('_bytestreamErrorCB') + id_ = unicode(iq_obj.getAttr('id')) + frm = helpers.get_full_jid_from_iq(iq_obj) + query = iq_obj.getTag('query') + 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: + return + file_props = self.files_props[id_] + file_props['error'] = -4 + self.dispatch('FILE_REQUEST_ERROR', (jid, file_props, '')) + raise common.xmpp.NodeProcessed + + def _ft_get_from(self, iq_obj): + return helpers.get_full_jid_from_iq(iq_obj) + + def _bytestreamSetCB(self, con, iq_obj): + log.debug('_bytestreamSetCB') + target = unicode(iq_obj.getAttr('to')) + 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) + streamhosts=[] + for item in query.getChildren(): + if item.getName() == 'streamhost': + host_dict={ + 'state': 0, + 'target': target, + 'id': id_, + 'sid': sid, + 'initiator': self._ft_get_from(iq_obj) + } + for attr in item.getAttrs(): + host_dict[attr] = item.getAttr(attr) + 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) + raise common.xmpp.NodeProcessed + + 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 common.xmpp.NodeProcessed + + def _ResultCB(self, con, iq_obj): + log.debug('_ResultCB') + # if we want to respect xep-0065 we have to check for proxy + # activation result in any result iq + real_id = unicode(iq_obj.getAttr('id')) + if real_id == self.awaiting_xmpp_ping_id: + self.awaiting_xmpp_ping_id = None + return + if not real_id.startswith('au_'): + 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 common.xmpp.NodeProcessed + + def _ft_get_streamhost_jid_attr(self, streamhost): + return helpers.parse_jid(streamhost.getAttr('jid')) + + def _bytestreamResultCB(self, con, iq_obj): + log.debug('_bytestreamResultCB') + frm = self._ft_get_from(iq_obj) + real_id = unicode(iq_obj.getAttr('id')) + query = iq_obj.getTag('query') + gajim.proxy65_manager.resolve_result(frm, query) + + try: + streamhost = query.getTag('streamhost-used') + 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: + raise common.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: + raise common.xmpp.NodeProcessed + if 'proxyhosts' not in file_props: + raise common.xmpp.NodeProcessed + for host in file_props['proxyhosts']: + if host['initiator'] == frm and \ + unicode(query.getAttr('sid')) == file_props['sid']: + gajim.socks5queue.activate_proxy(host['idx']) + break + raise common.xmpp.NodeProcessed + jid = self._ft_get_streamhost_jid_attr(streamhost) + if 'streamhost-used' in file_props and \ + file_props['streamhost-used'] is True: + raise common.xmpp.NodeProcessed + + if real_id.startswith('au_'): + if 'stopped' in file and file_props['stopped']: + self.remove_transfer(file_props) + else: + gajim.socks5queue.send_file(file_props, self.name) + raise common.xmpp.NodeProcessed + + proxy = None + if 'proxyhosts' in file_props: + for proxyhost in file_props['proxyhosts']: + if proxyhost['jid'] == jid: + proxy = proxyhost + + 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 = socks5.Socks5Receiver(gajim.idlequeue, proxy, + file_props['sid'], file_props) + gajim.socks5queue.add_receiver(self.name, receiver) + proxy['idx'] = receiver.queue_idx + gajim.socks5queue.on_success = self._proxy_auth_ok + raise common.xmpp.NodeProcessed + + else: + if 'stopped' in file_props and file_props['stopped']: + self.remove_transfer(file_props) + else: + gajim.socks5queue.send_file(file_props, self.name) + 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) + + raise common.xmpp.NodeProcessed + + def _siResultCB(self, con, iq_obj): + log.debug('_siResultCB') + id_ = iq_obj.getAttr('id') + if id_ not in self.files_props: + # no such jid + return + file_props = self.files_props[id_] + if file_props is None: + # file properties for jid is none + return + if 'request-id' in file_props: + # we have already sent streamhosts info + return + file_props['receiver'] = self._ft_get_from(iq_obj) + si = iq_obj.getTag('si') + file_tag = si.getTag('file') + range_tag = None + if file_tag: + range_tag = file_tag.getTag('range') + if range_tag: + offset = range_tag.getAttr('offset') + if offset: + file_props['offset'] = int(offset) + length = range_tag.getAttr('length') + if length: + file_props['length'] = int(length) + feature = si.setTag('feature') + if feature.getNamespace() != common.xmpp.NS_FEATURE: + return + form_tag = feature.getTag('x') + form = common.xmpp.DataForm(node=form_tag) + field = form.getField('stream-method') + if field.getValue() != common.xmpp.NS_BYTESTREAM: + return + self.send_socks5_info(file_props, fast = True) + raise common.xmpp.NodeProcessed + + def _siSetCB(self, con, iq_obj): + log.debug('_siSetCB') + jid = self._ft_get_from(iq_obj) + file_props = {'type': 'r'} + file_props['sender'] = jid + file_props['request-id'] = unicode(iq_obj.getAttr('id')) + si = iq_obj.getTag('si') + profile = si.getAttr('profile') + mime_type = si.getAttr('mime-type') + if profile != common.xmpp.NS_FILE: + self.send_file_rejection(file_props, code='400', typ='profile') + raise common.xmpp.NodeProcessed + feature_tag = si.getTag('feature', namespace=common.xmpp.NS_FEATURE) + if not feature_tag: + return + form_tag = feature_tag.getTag('x', namespace=common.xmpp.NS_DATA) + if not form_tag: + return + form = common.dataforms.ExtendForm(node=form_tag) + for f in form.iter_fields(): + if f.var == 'stream-method' and f.type == 'list-single': + values = [o[1] for o in f.options] + if common.xmpp.NS_BYTESTREAM in values: + break + else: + self.send_file_rejection(file_props, code='400', typ='stream') + raise common.xmpp.NodeProcessed + file_tag = si.getTag('file') + for attribute in file_tag.getAttrs(): + if attribute in ('name', 'size', 'hash', 'date'): + val = file_tag.getAttr(attribute) + if val is None: + continue + file_props[attribute] = val + file_desc_tag = file_tag.getTag('desc') + if file_desc_tag is not None: + file_props['desc'] = file_desc_tag.getData() + + if mime_type is not None: + file_props['mime-type'] = mime_type + our_jid = gajim.get_jid_from_account(self.name) + resource = self.server_resource + file_props['receiver'] = self._ft_get_our_jid() + file_props['sid'] = unicode(si.getAttr('id')) + file_props['transfered_size'] = [] + gajim.socks5queue.add_file_props(self.name, file_props) + self.dispatch('FILE_REQUEST', (jid, file_props)) + raise common.xmpp.NodeProcessed + + def _siErrorCB(self, con, iq_obj): + log.debug('_siErrorCB') + si = iq_obj.getTag('si') + profile = si.getAttr('profile') + if profile != common.xmpp.NS_FILE: + return + id_ = iq_obj.getAttr('id') + if id_ not in self.files_props: + # no such jid + return + file_props = self.files_props[id_] + if file_props is None: + # file properties for jid is none + return + jid = self._ft_get_from(iq_obj) + file_props['error'] = -3 + self.dispatch('FILE_REQUEST_ERROR', (jid, file_props, '')) + raise common.xmpp.NodeProcessed + + +class ConnectionBytestreamZeroconf(ConnectionBytestream): + + def _ft_get_from(self, iq_obj): + return unicode(iq_obj.getFrom()) + + def _ft_get_our_jid(self): + return gajim.get_jid_from_account(self.name) + + def _ft_get_receiver_jid(self, file_props): + return file_props['receiver'].jid + + def _ft_get_streamhost_jid_attr(self, streamhost): + return streamhost.getAttr('jid') + +# vim: se ts=3: \ No newline at end of file diff --git a/src/common/zeroconf/connection_handlers_zeroconf.py b/src/common/zeroconf/connection_handlers_zeroconf.py index b38afdfdb..018d2af20 100644 --- a/src/common/zeroconf/connection_handlers_zeroconf.py +++ b/src/common/zeroconf/connection_handlers_zeroconf.py @@ -28,7 +28,6 @@ import socket from calendar import timegm -from common import socks5 import common.xmpp from common import helpers @@ -36,6 +35,7 @@ from common import gajim from common.zeroconf import zeroconf from common.commands import ConnectionCommands from common.pep import ConnectionPEP +from common.protocol.bytestream import ConnectionBytestreamZeroconf import logging log = logging.getLogger('gajim.c.z.connection_handlers_zeroconf') @@ -69,25 +69,12 @@ class ConnectionVcard(connection_handlers.ConnectionVcard): def send_vcard(self, vcard): pass -class ConnectionBytestream(connection_handlers.ConnectionBytestream): - def _ft_get_from(self, iq_obj): - return unicode(iq_obj.getFrom()) - def _ft_get_our_jid(self): - return gajim.get_jid_from_account(self.name) - - def _ft_get_receiver_jid(self, file_props): - return file_props['receiver'].jid - - def _ft_get_streamhost_jid_attr(self, streamhost): - return streamhost.getAttr('jid') - - -class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream, +class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestreamZeroconf, ConnectionCommands, ConnectionPEP, connection_handlers.ConnectionHandlersBase): def __init__(self): ConnectionVcard.__init__(self) - ConnectionBytestream.__init__(self) + ConnectionBytestreamZeroconf.__init__(self) ConnectionCommands.__init__(self) connection_handlers.ConnectionHandlersBase.__init__(self) From f846d51f07c6031c61d34d758a045c811d93d361 Mon Sep 17 00:00:00 2001 From: Stephan Erb Date: Thu, 10 Dec 2009 22:09:37 +0100 Subject: [PATCH 2/7] Follow the most basic coding standards. --- src/common/protocol/bytestream.py | 175 +++++++++++++----------------- 1 file changed, 78 insertions(+), 97 deletions(-) diff --git a/src/common/protocol/bytestream.py b/src/common/protocol/bytestream.py index 92d0d9c73..e5f4f2694 100644 --- a/src/common/protocol/bytestream.py +++ b/src/common/protocol/bytestream.py @@ -30,13 +30,14 @@ import socket -import common.xmpp +from common import xmpp from common import gajim - +from common import helpers +from common import dataforms class ConnectionBytestream: - + def __init__(self): self.files_props = {} self.awaiting_xmpp_ping_id = None @@ -60,11 +61,10 @@ class ConnectionBytestream: return if streamhost is None: return None - iq = common.xmpp.Iq(to = streamhost['initiator'], typ = 'result', - frm = streamhost['target']) + iq = xmpp.Iq(to=streamhost['initiator'], typ='result', + frm=streamhost['target']) iq.setAttr('id', streamhost['id']) - query = iq.setTag('query') - query.setNamespace(common.xmpp.NS_BYTESTREAM) + query = iq.setTag('query', namespace=xmpp.NS_BYTESTREAM) stream_tag = query.setTag('streamhost-used') stream_tag.setAttr('jid', streamhost['jid']) self.connection.send(iq) @@ -91,11 +91,11 @@ class ConnectionBytestream: Stop and remove all active connections from the socks5 pool """ for file_props in self.files_props.values(): - self.remove_transfer(file_props, remove_from_list = False) + self.remove_transfer(file_props, remove_from_list=False) del(self.files_props) self.files_props = {} - def remove_transfer(self, file_props, remove_from_list = True): + def remove_transfer(self, file_props, remove_from_list=True): if file_props is None: return self.disconnect_transfer(file_props) @@ -118,8 +118,8 @@ class ConnectionBytestream: gajim.socks5queue.remove_receiver(host['idx']) gajim.socks5queue.remove_sender(host['idx']) - def send_socks5_info(self, file_props, fast = True, receiver = None, sender - = None): + def send_socks5_info(self, file_props, fast=True, receiver=None, sender + =None): """ Send iq for the present streamhosts and proxies """ @@ -149,7 +149,7 @@ class ConnectionBytestream: (host, _port, jid) = gajim.proxy65_manager.get_proxy(proxy, self.name) if host is None: continue - host_dict={ + host_dict = { 'state': 0, 'target': unicode(receiver), 'id': file_props['sid'], @@ -160,8 +160,7 @@ class ConnectionBytestream: 'jid': jid } proxyhosts.append(host_dict) - sha_str = helpers.get_auth_sha(file_props['sid'], sender, - receiver) + sha_str = helpers.get_auth_sha(file_props['sid'], sender, receiver) file_props['sha_str'] = sha_str ft_add_hosts = [] if ft_add_hosts_to_send: @@ -172,24 +171,21 @@ class ConnectionBytestream: sha_str, self._result_socks5_sid, file_props['sid']) if listener is None: file_props['error'] = -5 - self.dispatch('FILE_REQUEST_ERROR', (unicode(receiver), file_props, - '')) + self.dispatch('FILE_REQUEST_ERROR', (unicode(receiver), file_props, '')) self._connect_error(unicode(receiver), file_props['sid'], - file_props['sid'], code = 406) + file_props['sid'], code=406) return - iq = common.xmpp.Protocol(name = 'iq', to = unicode(receiver), - typ = 'set') + iq = xmpp.Iq(name='iq', to=unicode(receiver), typ='set') file_props['request-id'] = 'id_' + file_props['sid'] iq.setID(file_props['request-id']) - query = iq.setTag('query') - query.setNamespace(common.xmpp.NS_BYTESTREAM) + query = iq.setTag('query', namespace=xmpp.NS_BYTESTREAM) query.setAttr('mode', 'plain') query.setAttr('sid', file_props['sid']) for ft_host in ft_add_hosts: # The streamhost, if set - ostreamhost = common.xmpp.Node(tag = 'streamhost') - query.addChild(node = ostreamhost) + ostreamhost = xmpp.Node(tag='streamhost') + query.addChild(node=ostreamhost) ostreamhost.setAttr('port', unicode(port)) ostreamhost.setAttr('host', ft_host) ostreamhost.setAttr('jid', sender) @@ -201,8 +197,8 @@ class ConnectionBytestream: if not addr[4][0] in my_ips and not addr[4][0].startswith('127'): my_ips.append(addr[4][0]) for ip in my_ips: - streamhost = common.xmpp.Node(tag = 'streamhost') - query.addChild(node = streamhost) + streamhost = xmpp.Node(tag='streamhost') + query.addChild(node=streamhost) streamhost.setAttr('port', unicode(port)) streamhost.setAttr('host', ip) streamhost.setAttr('jid', sender) @@ -216,7 +212,7 @@ class ConnectionBytestream: file_props['proxy_sender'] = unicode(sender) file_props['proxyhosts'] = proxyhosts for proxyhost in proxyhosts: - streamhost = common.xmpp.Node(tag = 'streamhost') + streamhost = xmpp.Node(tag='streamhost') query.addChild(node=streamhost) streamhost.setAttr('port', proxyhost['port']) streamhost.setAttr('host', proxyhost['host']) @@ -237,8 +233,7 @@ class ConnectionBytestream: # user response to ConfirmationDialog may come after we've disconneted if not self.connection or self.connected < 2: return - iq = common.xmpp.Protocol(name = 'iq', - to = unicode(file_props['sender']), typ = 'error') + iq = xmpp.Iq(to=unicode(file_props['sender']), typ='error') iq.setAttr('id', file_props['request-id']) if code == '400' and typ in ('stream', 'profile'): name = 'bad-request' @@ -246,12 +241,12 @@ class ConnectionBytestream: else: name = 'forbidden' text = 'Offer Declined' - err = common.xmpp.ErrorNode(code=code, typ='cancel', name=name, text=text) + err = xmpp.ErrorNode(code=code, typ='cancel', name=name, text=text) if code == '400' and typ in ('stream', 'profile'): if typ == 'stream': - err.setTag('no-valid-streams', namespace=common.xmpp.NS_SI) + err.setTag('no-valid-streams', namespace=xmpp.NS_SI) else: - err.setTag('bad-profile', namespace=common.xmpp.NS_SI) + err.setTag('bad-profile', namespace=xmpp.NS_SI) iq.addChild(node=err) self.connection.send(iq) @@ -262,23 +257,19 @@ class ConnectionBytestream: # user response to ConfirmationDialog may come after we've disconneted if not self.connection or self.connected < 2: return - iq = common.xmpp.Protocol(name = 'iq', - to = unicode(file_props['sender']), typ = 'result') + iq = xmpp.Iq(to=unicode(file_props['sender']), typ='result') iq.setAttr('id', file_props['request-id']) - si = iq.setTag('si') - si.setNamespace(common.xmpp.NS_SI) + si = iq.setTag('si', namespace=xmpp.NS_SI) if 'offset' in file_props and file_props['offset']: - file_tag = si.setTag('file') - file_tag.setNamespace(common.xmpp.NS_FILE) + file_tag = si.setTag('file', namespace=xmpp.NS_FILE) range_tag = file_tag.setTag('range') range_tag.setAttr('offset', file_props['offset']) - feature = si.setTag('feature') - feature.setNamespace(common.xmpp.NS_FEATURE) - _feature = common.xmpp.DataForm(typ='submit') + 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') - field.setValue(common.xmpp.NS_BYTESTREAM) + field.setValue(xmpp.NS_BYTESTREAM) self.connection.send(iq) def _ft_get_our_jid(self): @@ -297,29 +288,25 @@ class ConnectionBytestream: return file_props['sender'] = self._ft_get_our_jid() fjid = self._ft_get_receiver_jid(file_props) - iq = common.xmpp.Protocol(name = 'iq', to = fjid, - typ = 'set') + iq = xmpp.Iq(to=fjid, typ='set') iq.setID(file_props['sid']) self.files_props[file_props['sid']] = file_props - si = iq.setTag('si') - si.setNamespace(common.xmpp.NS_SI) - si.setAttr('profile', common.xmpp.NS_FILE) + si = iq.setTag('si', namespace=xmpp.NS_SI) + si.setAttr('profile', xmpp.NS_FILE) si.setAttr('id', file_props['sid']) - file_tag = si.setTag('file') - file_tag.setNamespace(common.xmpp.NS_FILE) + file_tag = si.setTag('file', namespace=xmpp.NS_FILE) 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']) file_tag.setTag('range') - feature = si.setTag('feature') - feature.setNamespace(common.xmpp.NS_FEATURE) - _feature = common.xmpp.DataForm(typ='form') + feature = si.setTag('feature', namespace=xmpp.NS_FEATURE) + _feature = xmpp.DataForm(typ='form') feature.addChild(node=_feature) field = _feature.setField('stream-method') field.setAttr('type', 'list-single') - field.addOption(common.xmpp.NS_BYTESTREAM) + field.addOption(xmpp.NS_BYTESTREAM) self.connection.send(iq) def _result_socks5_sid(self, sid, hash_id): @@ -345,9 +332,7 @@ class ConnectionBytestream: 406: 'Not acceptable', } msg = msg_dict[code] - iq = None - iq = common.xmpp.Protocol(name = 'iq', to = to, - typ = 'error') + iq = xmpp.Iq(to=to, typ='error') iq.setAttr('id', _id) err = iq.setTag('error') err.setAttr('code', unicode(code)) @@ -367,12 +352,10 @@ class ConnectionBytestream: if not self.connection or self.connected < 2: return file_props = self.files_props[proxy['sid']] - iq = common.xmpp.Protocol(name = 'iq', to = proxy['initiator'], - typ = 'set') + iq = xmpp.Iq(to=proxy['initiator'], typ='set') auth_id = "au_" + proxy['sid'] iq.setID(auth_id) - query = iq.setTag('query') - query.setNamespace(common.xmpp.NS_BYTESTREAM) + query = iq.setTag('query', namespace=xmpp.NS_BYTESTREAM) query.setAttr('sid', proxy['sid']) activate = query.setTag('activate') activate.setData(file_props['proxy_receiver']) @@ -393,7 +376,7 @@ class ConnectionBytestream: file_props = self.files_props[id_] file_props['error'] = -4 self.dispatch('FILE_REQUEST_ERROR', (jid, file_props, '')) - raise common.xmpp.NodeProcessed + raise xmpp.NodeProcessed def _ft_get_from(self, iq_obj): return helpers.get_full_jid_from_iq(iq_obj) @@ -404,12 +387,11 @@ class 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) - streamhosts=[] + file_props = gajim.socks5queue.get_file_props(self.name, sid) + streamhosts = [] for item in query.getChildren(): if item.getName() == 'streamhost': - host_dict={ + host_dict = { 'state': 0, 'target': target, 'id': id_, @@ -425,7 +407,6 @@ class ConnectionBytestream: 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: @@ -434,13 +415,13 @@ class ConnectionBytestream: gajim.socks5queue.add_file_props(self.name, file_props) gajim.socks5queue.connect_to_hosts(self.name, sid, self.send_success_connect_reply, None) - raise common.xmpp.NodeProcessed + raise xmpp.NodeProcessed 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 common.xmpp.NodeProcessed + raise xmpp.NodeProcessed def _ResultCB(self, con, iq_obj): log.debug('_ResultCB') @@ -460,7 +441,7 @@ class ConnectionBytestream: for host in file_props['proxyhosts']: if host['initiator'] == frm and 'idx' in host: gajim.socks5queue.activate_proxy(host['idx']) - raise common.xmpp.NodeProcessed + raise xmpp.NodeProcessed def _ft_get_streamhost_jid_attr(self, streamhost): return helpers.parse_jid(streamhost.getAttr('jid')) @@ -480,32 +461,32 @@ class ConnectionBytestream: if id_ in self.files_props: file_props = self.files_props[id_] else: - raise common.xmpp.NodeProcessed + 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: - raise common.xmpp.NodeProcessed + raise xmpp.NodeProcessed if 'proxyhosts' not in file_props: - raise common.xmpp.NodeProcessed + raise xmpp.NodeProcessed for host in file_props['proxyhosts']: if host['initiator'] == frm and \ unicode(query.getAttr('sid')) == file_props['sid']: gajim.socks5queue.activate_proxy(host['idx']) break - raise common.xmpp.NodeProcessed + raise xmpp.NodeProcessed jid = self._ft_get_streamhost_jid_attr(streamhost) if 'streamhost-used' in file_props and \ file_props['streamhost-used'] is True: - raise common.xmpp.NodeProcessed + raise xmpp.NodeProcessed if real_id.startswith('au_'): if 'stopped' in file and file_props['stopped']: self.remove_transfer(file_props) else: gajim.socks5queue.send_file(file_props, self.name) - raise common.xmpp.NodeProcessed + raise xmpp.NodeProcessed proxy = None if 'proxyhosts' in file_props: @@ -524,7 +505,7 @@ class ConnectionBytestream: gajim.socks5queue.add_receiver(self.name, receiver) proxy['idx'] = receiver.queue_idx gajim.socks5queue.on_success = self._proxy_auth_ok - raise common.xmpp.NodeProcessed + raise xmpp.NodeProcessed else: if 'stopped' in file_props and file_props['stopped']: @@ -535,9 +516,9 @@ class ConnectionBytestream: fasts = file_props['fast'] if len(fasts) > 0: self._connect_error(frm, fasts[0]['id'], file_props['sid'], - code = 406) + code=406) - raise common.xmpp.NodeProcessed + raise xmpp.NodeProcessed def _siResultCB(self, con, iq_obj): log.debug('_siResultCB') @@ -566,15 +547,15 @@ class ConnectionBytestream: if length: file_props['length'] = int(length) feature = si.setTag('feature') - if feature.getNamespace() != common.xmpp.NS_FEATURE: + if feature.getNamespace() != xmpp.NS_FEATURE: return form_tag = feature.getTag('x') - form = common.xmpp.DataForm(node=form_tag) + form = xmpp.DataForm(node=form_tag) field = form.getField('stream-method') - if field.getValue() != common.xmpp.NS_BYTESTREAM: + if field.getValue() != xmpp.NS_BYTESTREAM: return - self.send_socks5_info(file_props, fast = True) - raise common.xmpp.NodeProcessed + self.send_socks5_info(file_props, fast=True) + raise xmpp.NodeProcessed def _siSetCB(self, con, iq_obj): log.debug('_siSetCB') @@ -585,24 +566,24 @@ class ConnectionBytestream: si = iq_obj.getTag('si') profile = si.getAttr('profile') mime_type = si.getAttr('mime-type') - if profile != common.xmpp.NS_FILE: + if profile != xmpp.NS_FILE: self.send_file_rejection(file_props, code='400', typ='profile') - raise common.xmpp.NodeProcessed - feature_tag = si.getTag('feature', namespace=common.xmpp.NS_FEATURE) + raise xmpp.NodeProcessed + feature_tag = si.getTag('feature', namespace=xmpp.NS_FEATURE) if not feature_tag: return - form_tag = feature_tag.getTag('x', namespace=common.xmpp.NS_DATA) + form_tag = feature_tag.getTag('x', namespace=xmpp.NS_DATA) if not form_tag: return - form = common.dataforms.ExtendForm(node=form_tag) + form = dataforms.ExtendForm(node=form_tag) for f in form.iter_fields(): if f.var == 'stream-method' and f.type == 'list-single': values = [o[1] for o in f.options] - if common.xmpp.NS_BYTESTREAM in values: + if xmpp.NS_BYTESTREAM in values: break else: self.send_file_rejection(file_props, code='400', typ='stream') - raise common.xmpp.NodeProcessed + raise xmpp.NodeProcessed file_tag = si.getTag('file') for attribute in file_tag.getAttrs(): if attribute in ('name', 'size', 'hash', 'date'): @@ -623,13 +604,13 @@ class ConnectionBytestream: file_props['transfered_size'] = [] gajim.socks5queue.add_file_props(self.name, file_props) self.dispatch('FILE_REQUEST', (jid, file_props)) - raise common.xmpp.NodeProcessed + raise xmpp.NodeProcessed def _siErrorCB(self, con, iq_obj): log.debug('_siErrorCB') si = iq_obj.getTag('si') profile = si.getAttr('profile') - if profile != common.xmpp.NS_FILE: + if profile != xmpp.NS_FILE: return id_ = iq_obj.getAttr('id') if id_ not in self.files_props: @@ -642,11 +623,11 @@ class ConnectionBytestream: jid = self._ft_get_from(iq_obj) file_props['error'] = -3 self.dispatch('FILE_REQUEST_ERROR', (jid, file_props, '')) - raise common.xmpp.NodeProcessed - - + raise xmpp.NodeProcessed + + class ConnectionBytestreamZeroconf(ConnectionBytestream): - + def _ft_get_from(self, iq_obj): return unicode(iq_obj.getFrom()) @@ -658,5 +639,5 @@ class ConnectionBytestreamZeroconf(ConnectionBytestream): def _ft_get_streamhost_jid_attr(self, streamhost): return streamhost.getAttr('jid') - -# vim: se ts=3: \ No newline at end of file + +# vim: se ts=3: From bb50871bce61da82c04c1eb16559675960a22b75 Mon Sep 17 00:00:00 2001 From: Stephan Erb Date: Thu, 10 Dec 2009 23:01:48 +0100 Subject: [PATCH 3/7] Remove logging of callback method calls. Such cross-cutting concerns are better directly implemented in the xmpp dispatcher. --- src/common/protocol/bytestream.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/common/protocol/bytestream.py b/src/common/protocol/bytestream.py index e5f4f2694..63ed7e673 100644 --- a/src/common/protocol/bytestream.py +++ b/src/common/protocol/bytestream.py @@ -364,7 +364,6 @@ class ConnectionBytestream: # register xmpppy handlers for bytestream and FT stanzas def _bytestreamErrorCB(self, con, iq_obj): - log.debug('_bytestreamErrorCB') id_ = unicode(iq_obj.getAttr('id')) frm = helpers.get_full_jid_from_iq(iq_obj) query = iq_obj.getTag('query') @@ -382,7 +381,6 @@ class ConnectionBytestream: return helpers.get_full_jid_from_iq(iq_obj) def _bytestreamSetCB(self, con, iq_obj): - log.debug('_bytestreamSetCB') target = unicode(iq_obj.getAttr('to')) id_ = unicode(iq_obj.getAttr('id')) query = iq_obj.getTag('query') @@ -424,7 +422,6 @@ class ConnectionBytestream: raise xmpp.NodeProcessed def _ResultCB(self, con, iq_obj): - log.debug('_ResultCB') # if we want to respect xep-0065 we have to check for proxy # activation result in any result iq real_id = unicode(iq_obj.getAttr('id')) @@ -447,7 +444,6 @@ class ConnectionBytestream: return helpers.parse_jid(streamhost.getAttr('jid')) def _bytestreamResultCB(self, con, iq_obj): - log.debug('_bytestreamResultCB') frm = self._ft_get_from(iq_obj) real_id = unicode(iq_obj.getAttr('id')) query = iq_obj.getTag('query') @@ -521,7 +517,6 @@ class ConnectionBytestream: raise xmpp.NodeProcessed def _siResultCB(self, con, iq_obj): - log.debug('_siResultCB') id_ = iq_obj.getAttr('id') if id_ not in self.files_props: # no such jid @@ -558,7 +553,6 @@ class ConnectionBytestream: raise xmpp.NodeProcessed def _siSetCB(self, con, iq_obj): - log.debug('_siSetCB') jid = self._ft_get_from(iq_obj) file_props = {'type': 'r'} file_props['sender'] = jid @@ -597,8 +591,6 @@ class ConnectionBytestream: if mime_type is not None: file_props['mime-type'] = mime_type - our_jid = gajim.get_jid_from_account(self.name) - resource = self.server_resource file_props['receiver'] = self._ft_get_our_jid() file_props['sid'] = unicode(si.getAttr('id')) file_props['transfered_size'] = [] @@ -607,7 +599,6 @@ class ConnectionBytestream: raise xmpp.NodeProcessed def _siErrorCB(self, con, iq_obj): - log.debug('_siErrorCB') si = iq_obj.getTag('si') profile = si.getAttr('profile') if profile != xmpp.NS_FILE: From 24e2047fe309c7fae7e4cb0d1b60970f8d79fd53 Mon Sep 17 00:00:00 2001 From: Stephan Erb Date: Thu, 10 Dec 2009 23:22:51 +0100 Subject: [PATCH 4/7] Remove obvious code duplication. --- src/common/protocol/bytestream.py | 56 +++++++++++-------------------- 1 file changed, 19 insertions(+), 37 deletions(-) diff --git a/src/common/protocol/bytestream.py b/src/common/protocol/bytestream.py index 63ed7e673..9bb7e9402 100644 --- a/src/common/protocol/bytestream.py +++ b/src/common/protocol/bytestream.py @@ -182,13 +182,7 @@ class ConnectionBytestream: query = iq.setTag('query', namespace=xmpp.NS_BYTESTREAM) query.setAttr('mode', 'plain') query.setAttr('sid', file_props['sid']) - for ft_host in ft_add_hosts: - # The streamhost, if set - ostreamhost = xmpp.Node(tag='streamhost') - query.addChild(node=ostreamhost) - ostreamhost.setAttr('port', unicode(port)) - ostreamhost.setAttr('host', ft_host) - ostreamhost.setAttr('jid', sender) + self._add_streamhosts_to_query(query, sender, port, fd_add_hosts) try: # The ip we're connected to server with my_ips = [self.peerhost[0]] @@ -196,12 +190,7 @@ class ConnectionBytestream: for addr in socket.getaddrinfo(socket.gethostname(), None): if not addr[4][0] in my_ips and not addr[4][0].startswith('127'): my_ips.append(addr[4][0]) - for ip in my_ips: - streamhost = xmpp.Node(tag='streamhost') - query.addChild(node=streamhost) - streamhost.setAttr('port', unicode(port)) - streamhost.setAttr('host', ip) - streamhost.setAttr('jid', sender) + self._add_streamhosts_to_query(query, sender, port, my_ips) except socket.gaierror: self.dispatch('ERROR', (_('Wrong host'), _('Invalid local address? :-O'))) @@ -211,18 +200,21 @@ class ConnectionBytestream: file_props['proxy_receiver'] = unicode(receiver) file_props['proxy_sender'] = unicode(sender) file_props['proxyhosts'] = proxyhosts - for proxyhost in proxyhosts: - streamhost = xmpp.Node(tag='streamhost') - query.addChild(node=streamhost) - streamhost.setAttr('port', proxyhost['port']) - streamhost.setAttr('host', proxyhost['host']) - streamhost.setAttr('jid', proxyhost['jid']) - # don't add the proxy child tag for streamhosts, which are proxies - # proxy = streamhost.setTag('proxy') - # proxy.setNamespace(common.xmpp.NS_STREAM) + for proxyhost in proxyhosts: + self._add_streamhosts_to_query(query, proxyhost['jid'], + proxyhost['port'], [proxyhost['host']]) + self.connection.send(iq) + def _add_streamhosts_to_query(self, query, sender, port, hosts): + for host in hosts: + streamhost = xmpp.Node(tag='streamhost') + query.addChild(node=streamhost) + streamhost.setAttr('port', unicode(port)) + streamhost.setAttr('host', host) + streamhost.setAttr('jid', sender) + def send_file_rejection(self, file_props, code='403', typ=None): """ Inform sender that we refuse to download the file @@ -517,13 +509,8 @@ class ConnectionBytestream: raise xmpp.NodeProcessed def _siResultCB(self, con, iq_obj): - id_ = iq_obj.getAttr('id') - if id_ not in self.files_props: - # no such jid - return - file_props = self.files_props[id_] - if file_props is None: - # file properties for jid is none + file_props = self.files_props.get(iq_obj.getAttr('id')) + if not file_props: return if 'request-id' in file_props: # we have already sent streamhosts info @@ -603,19 +590,14 @@ class ConnectionBytestream: profile = si.getAttr('profile') if profile != xmpp.NS_FILE: return - id_ = iq_obj.getAttr('id') - if id_ not in self.files_props: - # no such jid - return - file_props = self.files_props[id_] - if file_props is None: - # file properties for jid is none + file_props = self.files_props.get(iq_obj.getAttr('id')) + if not file_props: return jid = self._ft_get_from(iq_obj) file_props['error'] = -3 self.dispatch('FILE_REQUEST_ERROR', (jid, file_props, '')) raise xmpp.NodeProcessed - + class ConnectionBytestreamZeroconf(ConnectionBytestream): From 9bfb5753c281e035d41b652447b4d907d90ab581 Mon Sep 17 00:00:00 2001 From: Stephan Erb Date: Thu, 10 Dec 2009 23:53:39 +0100 Subject: [PATCH 5/7] Move three methods from filetransfer_window to protocol/bytestream. One of the methods was duplicated. Additionally, apply a very few coding standards. --- src/common/protocol/bytestream.py | 49 ++++++++---- src/filetransfers_window.py | 125 +++++++++++------------------- 2 files changed, 82 insertions(+), 92 deletions(-) diff --git a/src/common/protocol/bytestream.py b/src/common/protocol/bytestream.py index 9bb7e9402..9a7ea62e4 100644 --- a/src/common/protocol/bytestream.py +++ b/src/common/protocol/bytestream.py @@ -36,22 +36,45 @@ from common import helpers from common import dataforms +def is_transfer_paused(file_props): + if 'stopped' in file_props and file_props['stopped']: + return False + if 'completed' in file_props and file_props['completed']: + return False + if 'disconnect_cb' not in file_props: + return False + return file_props['paused'] + +def is_transfer_active(file_props): + if 'stopped' in file_props and file_props['stopped']: + return False + if 'completed' in file_props and file_props['completed']: + return False + if 'started' not in file_props or not file_props['started']: + return False + if 'paused' not in file_props: + return True + return not file_props['paused'] + +def is_transfer_stopped(file_props): + if 'error' in file_props and file_props['error'] != 0: + return True + if 'completed' in file_props and file_props['completed']: + return True + if 'connected' in file_props and file_props['connected'] == False: + return True + if 'stopped' not in file_props or not file_props['stopped']: + return False + return True + + class ConnectionBytestream: def __init__(self): self.files_props = {} self.awaiting_xmpp_ping_id = None - def is_transfer_stopped(self, file_props): - if 'error' in file_props and file_props['error'] != 0: - return True - if 'completed' in file_props and file_props['completed']: - return True - if 'connected' in file_props and file_props['connected'] == False: - return True - if 'stopped' not in file_props or not file_props['stopped']: - return False - return True + def send_success_connect_reply(self, streamhost): """ @@ -74,7 +97,7 @@ class ConnectionBytestream: Stop all active transfer for contact """ for file_props in self.files_props.values(): - if self.is_transfer_stopped(file_props): + if is_transfer_stopped(file_props): continue receiver_jid = unicode(file_props['receiver']) if contact.get_full_jid() == receiver_jid: @@ -176,13 +199,13 @@ class ConnectionBytestream: file_props['sid'], code=406) return - iq = xmpp.Iq(name='iq', to=unicode(receiver), typ='set') + iq = xmpp.Iq(to=unicode(receiver), typ='set') file_props['request-id'] = 'id_' + file_props['sid'] iq.setID(file_props['request-id']) query = iq.setTag('query', namespace=xmpp.NS_BYTESTREAM) query.setAttr('mode', 'plain') query.setAttr('sid', file_props['sid']) - self._add_streamhosts_to_query(query, sender, port, fd_add_hosts) + self._add_streamhosts_to_query(query, sender, port, ft_add_hosts) try: # The ip we're connected to server with my_ips = [self.peerhost[0]] diff --git a/src/filetransfers_window.py b/src/filetransfers_window.py index d3d23a156..55cb90281 100644 --- a/src/filetransfers_window.py +++ b/src/filetransfers_window.py @@ -33,6 +33,8 @@ import dialogs from common import gajim from common import helpers +from common.protocol.bytestream import (is_transfer_active, is_transfer_paused, + is_transfer_stopped) C_IMAGE = 0 C_LABELS = 1 @@ -55,18 +57,17 @@ class FileTransfersWindow: self.cleanup_button = self.xml.get_widget('cleanup_button') self.notify_ft_checkbox = self.xml.get_widget( 'notify_ft_complete_checkbox') - notify = gajim.config.get('notify_on_file_complete') - if notify: - self.notify_ft_checkbox.set_active(True) - else: - self.notify_ft_checkbox.set_active(False) + + shall_notify = gajim.config.get('notify_on_file_complete') + self.notify_ft_checkbox.set_active(shall_notify + ) self.model = gtk.ListStore(gtk.gdk.Pixbuf, str, str, str, str, int, str) self.tree.set_model(self.model) col = gtk.TreeViewColumn() render_pixbuf = gtk.CellRendererPixbuf() - col.pack_start(render_pixbuf, expand = True) + col.pack_start(render_pixbuf, expand=True) render_pixbuf.set_property('xpad', 3) render_pixbuf.set_property('ypad', 3) render_pixbuf.set_property('yalign', .0) @@ -104,7 +105,7 @@ class FileTransfersWindow: renderer = gtk.CellRendererProgress() renderer.set_property('yalign', 0.5) renderer.set_property('xalign', 0.5) - col.pack_start(renderer, expand = False) + col.pack_start(renderer, expand=False) col.add_attribute(renderer, 'text' , C_PROGRESS) col.add_attribute(renderer, 'value' , C_PERCENT) col.set_resizable(True) @@ -137,14 +138,14 @@ class FileTransfersWindow: """ Find all transfers with peer 'jid' that belong to 'account' """ - active_transfers = [[],[]] # ['senders', 'receivers'] + 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 self.is_transfer_stopped(file_props): + if not is_transfer_stopped(file_props): active_transfers[0].append(file_props) # 'account' is the recipient @@ -152,7 +153,7 @@ class FileTransfersWindow: if file_props['tt_account'] == account: sender_jid = unicode(file_props['sender']).split('/')[0] if jid == sender_jid: - if not self.is_transfer_stopped(file_props): + if not is_transfer_stopped(file_props): active_transfers[1].append(file_props) return active_transfers @@ -185,8 +186,8 @@ class FileTransfersWindow: else: #You is a reply of who sent a file sender = _('You') - sectext += '\n\t' +_('Sender: %s') % sender - sectext += '\n\t' +_('Recipient: ') + sectext += '\n\t' + _('Sender: %s') % sender + sectext += '\n\t' + _('Recipient: ') if file_props['type'] == 's': jid = unicode(file_props['receiver']).split('/')[0] receiver_name = gajim.contacts.get_first_contact_from_jid( @@ -197,7 +198,7 @@ class FileTransfersWindow: recipient = _('You') sectext += recipient if file_props['type'] == 'r': - sectext += '\n\t' +_('Saved in: %s') % file_path + sectext += '\n\t' + _('Saved in: %s') % file_path dialog = dialogs.HigDialog(None, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, _('File transfer completed'), sectext) if file_props['type'] == 'r': @@ -222,10 +223,10 @@ class FileTransfersWindow: Show error dialog to the sender saying that transfer has been canceled """ dialogs.InformationDialog(_('File transfer cancelled'), -_('Connection with peer cannot be established.')) + _('Connection with peer cannot be established.')) self.tree.get_selection().unselect_all() - def show_stopped(self, jid, file_props, error_msg = ''): + def show_stopped(self, jid, file_props, error_msg=''): if file_props['type'] == 'r': file_name = os.path.basename(file_props['file-name']) else: @@ -238,7 +239,6 @@ _('Connection with peer cannot be established.')) self.tree.get_selection().unselect_all() def show_file_send_request(self, account, contact): - desc_entry = gtk.Entry() def on_ok(widget): @@ -259,8 +259,8 @@ _('Connection with peer cannot be established.')) gtk.RESPONSE_OK, True, # select multiple true as we can select many files to send gajim.config.get('last_send_dir'), - on_response_ok = on_ok, - on_response_cancel = lambda e:dialog.destroy() + on_response_ok=on_ok, + on_response_cancel=lambda e:dialog.destroy() ) btn = gtk.Button(_('_Send')) @@ -270,8 +270,8 @@ _('Connection with peer cannot be established.')) dialog.set_default_response(gtk.RESPONSE_OK) desc_hbox = gtk.HBox(False, 5) - desc_hbox.pack_start(gtk.Label(_('Description: ')),False,False,0) - desc_hbox.pack_start(desc_entry,True,True,0) + desc_hbox.pack_start(gtk.Label(_('Description: ')), False, False, 0) + desc_hbox.pack_start(desc_entry, True, True, 0) dialog.vbox.pack_start(desc_hbox, False, False, 0) @@ -376,14 +376,14 @@ _('Connection with peer cannot be established.')) gajim.connections[account].send_file_rejection(file_props) dialog2 = dialogs.FileChooserDialog( - title_text = _('Save File as...'), - action = gtk.FILE_CHOOSER_ACTION_SAVE, - buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, + title_text=_('Save File as...'), + action=gtk.FILE_CHOOSER_ACTION_SAVE, + buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK), - default_response = gtk.RESPONSE_OK, - current_folder = gajim.config.get('last_save_dir'), - on_response_ok = (on_ok, account, contact, file_props), - on_response_cancel = (on_cancel, account, contact, file_props)) + default_response=gtk.RESPONSE_OK, + current_folder=gajim.config.get('last_save_dir'), + 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.connect('delete-event', lambda widget, event: @@ -393,8 +393,8 @@ _('Connection with peer cannot be established.')) gajim.connections[account].send_file_rejection(file_props) dialog = dialogs.NonModalConfirmationDialog(prim_text, sec_text, - on_response_ok = (on_response_ok, account, contact, file_props), - on_response_cancel = (on_response_cancel, account, file_props)) + on_response_ok=(on_response_ok, account, contact, file_props), + on_response_cancel=(on_response_cancel, account, file_props)) dialog.connect('delete-event', lambda widget, event: on_response_cancel(widget, account, file_props)) dialog.popup() @@ -446,7 +446,7 @@ _('Connection with peer cannot be established.')) #Print remaining time in format 00:00:00 #You can change the places of (hours), (minutes), (seconds) - #they are not translatable. - return _('%(hours)02.d:%(minutes)02.d:%(seconds)02.d') % times + return _('%(hours)02.d:%(minutes)02.d:%(seconds)02.d') % times def _get_eta_and_speed(self, full_size, transfered_size, file_props): if len(file_props['transfered_size']) == 0: @@ -494,7 +494,7 @@ _('Connection with peer cannot be established.')) del(self.files_props[sid[0]][sid[1:]]) del(file_props) - def set_progress(self, typ, sid, transfered_size, iter_ = None): + def set_progress(self, typ, sid, transfered_size, iter_=None): """ Change the progress of a transfer with new transfered size """ @@ -582,7 +582,7 @@ _('Connection with peer cannot be established.')) if os.path.isfile(file_path): stat = os.stat(file_path) else: - dialogs.ErrorDialog(_('Invalid File'), _('File: ') + file_path) + dialogs.ErrorDialog(_('Invalid File'), _('File: ') + file_path) return None if stat[6] == 0: dialogs.ErrorDialog(_('Invalid File'), @@ -659,14 +659,13 @@ _('Connection with peer cannot be established.')) self.tooltip.timeout = gobject.timeout_add(500, self.show_tooltip, widget) - def on_transfers_list_leave_notify_event(self, widget = None, event = None): + def on_transfers_list_leave_notify_event(self, widget=None, event=None): if event is not None: self.height_diff = int(event.y) elif self.height_diff is 0: return pointer = self.tree.get_pointer() - props = self.tree.get_path_at_pos(pointer[0], - pointer[1] - self.height_diff) + props = self.tree.get_path_at_pos(pointer[0], pointer[1] - self.height_diff) if self.tooltip.timeout > 0: if not props or self.tooltip.id == props[0]: self.tooltip.hide_tooltip() @@ -675,37 +674,6 @@ _('Connection with peer cannot be established.')) # try to open the containing folder self.on_open_folder_menuitem_activate(widget) - def is_transfer_paused(self, file_props): - if 'stopped' in file_props and file_props['stopped']: - return False - if 'completed' in file_props and file_props['completed']: - return False - if 'disconnect_cb' not in file_props: - return False - return file_props['paused'] - - def is_transfer_active(self, file_props): - if 'stopped' in file_props and file_props['stopped']: - return False - if 'completed' in file_props and file_props['completed']: - return False - if 'started' not in file_props or not file_props['started']: - return False - if 'paused' not in file_props: - return True - return not file_props['paused'] - - def is_transfer_stopped(self, file_props): - if 'error' in file_props and file_props['error'] != 0: - return True - if 'completed' in file_props and file_props['completed']: - return True - if 'connected' in file_props and file_props['connected'] == False: - return True - if 'stopped' not in file_props or not file_props['stopped']: - return False - return True - def set_cleanup_sensitivity(self): """ Check if there are transfer rows and set cleanup_button sensitive, or @@ -743,7 +711,7 @@ _('Connection with peer cannot be established.')) self.remove_menuitem.set_sensitive(is_row_selected) self.open_folder_menuitem.set_sensitive(is_row_selected) is_stopped = False - if self.is_transfer_stopped(file_props): + if is_transfer_stopped(file_props): is_stopped = True self.cancel_button.set_sensitive(not is_stopped) self.cancel_menuitem.set_sensitive(not is_stopped) @@ -751,11 +719,11 @@ _('Connection with peer cannot be established.')) # no selection, disable the buttons self.set_all_insensitive() elif not is_stopped: - if self.is_transfer_active(file_props): + if is_transfer_active(file_props): # file transfer is active self.toggle_pause_continue(True) self.pause_button.set_sensitive(True) - elif self.is_transfer_paused(file_props): + elif is_transfer_paused(file_props): # file transfer is paused self.toggle_pause_continue(False) self.pause_button.set_sensitive(True) @@ -798,7 +766,7 @@ _('Connection with peer cannot be established.')) iter_ = self.model.get_iter((i)) sid = self.model[iter_][C_SID].decode('utf-8') file_props = self.files_props[sid[0]][sid[1:]] - if self.is_transfer_stopped(file_props): + if is_transfer_stopped(file_props): self._remove_transfer(iter_, sid, file_props) i -= 1 self.tree.get_selection().unselect_all() @@ -840,7 +808,7 @@ _('Connection with peer cannot be established.')) self.set_status(file_props['type'], file_props['sid'], types[sid[0]]) self.toggle_pause_continue(True) file_props['continue_cb']() - elif self.is_transfer_active(file_props): + elif is_transfer_active(file_props): file_props['paused'] = True self.set_status(file_props['type'], file_props['sid'], 'pause') # reset that to compute speed only when we resume @@ -876,7 +844,7 @@ _('Connection with peer cannot be established.')) sid = self.model[iter_][C_SID].decode('utf-8') file_props = self.files_props[sid[0]][sid[1:]] # bounding rectangle of coordinates for the cell within the treeview - rect = self.tree.get_cell_area(props[0],props[1]) + rect = self.tree.get_cell_area(props[0], props[1]) # position of the treeview on the screen position = widget.window.get_origin() self.tooltip.show_tooltip(file_props , rect.height, @@ -898,10 +866,9 @@ _('Connection with peer cannot be established.')) def show_context_menu(self, event, iter_): # change the sensitive propery of the buttons and menuitems - path = None - if iter_ is not None: + if iter_: path = self.model.get_path(iter_) - self.set_buttons_sensitive(path, True) + self.set_buttons_sensitive(path, True) event_button = gtkgui_helpers.get_possible_button_event(event) self.file_transfers_menu.show_all() @@ -950,16 +917,16 @@ _('Connection with peer cannot be established.')) except TypeError: self.tree.get_selection().unselect_all() if event.button == 3: # Right click - if path is not None: + if path: self.tree.get_selection().select_path(path) iter_ = self.model.get_iter(path) self.show_context_menu(event, iter_) - if path is not None: + if path: return True def on_open_folder_menuitem_activate(self, widget): selected = self.tree.get_selection().get_selected() - if selected is None or selected[1] is None: + if not selected or not selected[1]: return s_iter = selected[1] sid = self.model[s_iter][C_SID].decode('utf-8') @@ -981,7 +948,7 @@ _('Connection with peer cannot be established.')) def on_remove_menuitem_activate(self, widget): selected = self.tree.get_selection().get_selected() - if selected is None or selected[1] is None: + if not selected or not selected[1]: return s_iter = selected[1] sid = self.model[s_iter][C_SID].decode('utf-8') From 24f44d8bddcbad1040b3ff5ef4e7455f66a242f6 Mon Sep 17 00:00:00 2001 From: Stephan Erb Date: Thu, 10 Dec 2009 23:54:51 +0100 Subject: [PATCH 6/7] Remove zeroconf dummy methods. --- .../zeroconf/connection_handlers_zeroconf.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/common/zeroconf/connection_handlers_zeroconf.py b/src/common/zeroconf/connection_handlers_zeroconf.py index 018d2af20..0d45379c3 100644 --- a/src/common/zeroconf/connection_handlers_zeroconf.py +++ b/src/common/zeroconf/connection_handlers_zeroconf.py @@ -173,21 +173,6 @@ ConnectionCommands, ConnectionPEP, connection_handlers.ConnectionHandlersBase): # (there is no server) pass - def remove_transfers_for_contact(self, contact): - """ - Stop all active transfer for contact - """ - pass - - def remove_all_transfers(self): - """ - Stops and removes all active connections from the socks5 pool - """ - pass - - def remove_transfer(self, file_props, remove_from_list = True): - pass - def _DiscoverItemsGetCB(self, con, iq_obj): log.debug('DiscoverItemsGetCB') From 9eb35dcf18c1736c8ab9bae35324f59609975e8e Mon Sep 17 00:00:00 2001 From: Stephan Erb Date: Fri, 11 Dec 2009 01:00:29 +0100 Subject: [PATCH 7/7] Split send_socks5_info monster method into smaller methods. (Extract Method Refactoring) (I don't think what we have here is good, but it is atleast readable) --- src/common/protocol/bytestream.py | 183 ++++++++++++++++-------------- src/gui_interface.py | 2 +- 2 files changed, 97 insertions(+), 88 deletions(-) diff --git a/src/common/protocol/bytestream.py b/src/common/protocol/bytestream.py index 9a7ea62e4..282548839 100644 --- a/src/common/protocol/bytestream.py +++ b/src/common/protocol/bytestream.py @@ -72,9 +72,6 @@ class ConnectionBytestream: def __init__(self): self.files_props = {} - self.awaiting_xmpp_ping_id = None - - def send_success_connect_reply(self, streamhost): """ @@ -92,9 +89,9 @@ class ConnectionBytestream: stream_tag.setAttr('jid', streamhost['jid']) self.connection.send(iq) - def remove_transfers_for_contact(self, contact): + def stop_all_active_file_transfers(self, contact): """ - Stop all active transfer for contact + Stop all active transfer to or from the given contact """ for file_props in self.files_props.values(): if is_transfer_stopped(file_props): @@ -115,7 +112,6 @@ class ConnectionBytestream: """ for file_props in self.files_props.values(): self.remove_transfer(file_props, remove_from_list=False) - del(self.files_props) self.files_props = {} def remove_transfer(self, file_props, remove_from_list=True): @@ -140,95 +136,40 @@ class ConnectionBytestream: if 'idx' in host and host['idx'] > 0: gajim.socks5queue.remove_receiver(host['idx']) gajim.socks5queue.remove_sender(host['idx']) - - def send_socks5_info(self, file_props, fast=True, receiver=None, sender - =None): + + def _send_socks5_info(self, file_props): """ Send iq for the present streamhosts and proxies """ if not self.connection or self.connected < 2: return - if not isinstance(self.peerhost, tuple): - return - port = gajim.config.get('file_transfers_port') - ft_add_hosts_to_send = gajim.config.get('ft_add_hosts_to_send') - cfg_proxies = gajim.config.get_per('accounts', self.name, - 'file_transfer_proxies') - if receiver is None: - receiver = file_props['receiver'] - if sender is None: - sender = file_props['sender'] - proxyhosts = [] - if fast and cfg_proxies: - proxies = [e.strip() for e in cfg_proxies.split(',')] - default = gajim.proxy65_manager.get_default_for_name(self.name) - if default: - # add/move default proxy at top of the others - if proxies.__contains__(default): - proxies.remove(default) - proxies.insert(0, default) + receiver = file_props['receiver'] + sender = file_props['sender'] - for proxy in proxies: - (host, _port, jid) = gajim.proxy65_manager.get_proxy(proxy, self.name) - if host is None: - continue - host_dict = { - 'state': 0, - 'target': unicode(receiver), - 'id': file_props['sid'], - 'sid': file_props['sid'], - 'initiator': proxy, - 'host': host, - 'port': unicode(_port), - 'jid': jid - } - proxyhosts.append(host_dict) sha_str = helpers.get_auth_sha(file_props['sid'], sender, receiver) file_props['sha_str'] = sha_str - ft_add_hosts = [] - if ft_add_hosts_to_send: - ft_add_hosts_to_send = [e.strip() for e in ft_add_hosts_to_send.split(',')] - for ft_host in ft_add_hosts_to_send: - ft_add_hosts.append(ft_host) - listener = gajim.socks5queue.start_listener(port, - sha_str, self._result_socks5_sid, file_props['sid']) - if listener is None: + + port = gajim.config.get('file_transfers_port') + listener = gajim.socks5queue.start_listener(port, sha_str, + self._result_socks5_sid, file_props['sid']) + if not listener: file_props['error'] = -5 self.dispatch('FILE_REQUEST_ERROR', (unicode(receiver), file_props, '')) self._connect_error(unicode(receiver), file_props['sid'], file_props['sid'], code=406) - return - - iq = xmpp.Iq(to=unicode(receiver), typ='set') - file_props['request-id'] = 'id_' + file_props['sid'] - iq.setID(file_props['request-id']) - query = iq.setTag('query', namespace=xmpp.NS_BYTESTREAM) - query.setAttr('mode', 'plain') - query.setAttr('sid', file_props['sid']) - self._add_streamhosts_to_query(query, sender, port, ft_add_hosts) - try: - # The ip we're connected to server with - my_ips = [self.peerhost[0]] - # all IPs from local DNS - for addr in socket.getaddrinfo(socket.gethostname(), None): - if not addr[4][0] in my_ips and not addr[4][0].startswith('127'): - my_ips.append(addr[4][0]) - self._add_streamhosts_to_query(query, sender, port, my_ips) - except socket.gaierror: - self.dispatch('ERROR', (_('Wrong host'), - _('Invalid local address? :-O'))) - - if fast and proxyhosts != [] and gajim.config.get_per('accounts', - self.name, 'use_ft_proxies'): - file_props['proxy_receiver'] = unicode(receiver) - file_props['proxy_sender'] = unicode(sender) - file_props['proxyhosts'] = proxyhosts - - for proxyhost in proxyhosts: - self._add_streamhosts_to_query(query, proxyhost['jid'], - proxyhost['port'], [proxyhost['host']]) - - self.connection.send(iq) + else: + iq = xmpp.Iq(to=unicode(receiver), typ='set') + file_props['request-id'] = 'id_' + file_props['sid'] + iq.setID(file_props['request-id']) + query = iq.setTag('query', namespace=xmpp.NS_BYTESTREAM) + query.setAttr('mode', 'plain') + 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) + self._add_proxy_streamhosts_to_query(query, file_props) + + self.connection.send(iq) def _add_streamhosts_to_query(self, query, sender, port, hosts): for host in hosts: @@ -238,6 +179,77 @@ class ConnectionBytestream: streamhost.setAttr('host', host) streamhost.setAttr('jid', sender) + def _add_local_ips_as_streamhosts_to_query(self, query, file_props): + try: + my_ips = [self.peerhost[0]] # The ip we're connected to server with + # all IPs from local DNS + for addr in socket.getaddrinfo(socket.gethostname(), None): + 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'] + port = gajim.config.get('file_transfers_port') + self._add_streamhosts_to_query(query, sender, port, my_ips) + except socket.gaierror: + self.dispatch('ERROR', (_('Wrong host'), + _('Invalid local address? :-O'))) + + def _add_addiditional_streamhosts_to_query(self, query, file_props): + 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 = [] + if ft_add_hosts_to_send: + additional_hosts = [e.strip() for e in ft_add_hosts_to_send.split(',')] + else: + additional_hosts = [] + self._add_streamhosts_to_query(query, sender, port, additional_hosts) + + 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 + + for proxyhost in proxyhosts: + self._add_streamhosts_to_query(query, proxyhost['jid'], + proxyhost['port'], [proxyhost['host']]) + + def _get_file_transfer_proxies_from_config(self, file_props): + configured_proxies = gajim.config.get_per('accounts', self.name, + 'file_transfer_proxies') + shall_use_proxies = gajim.config.get_per('accounts', self.name, + 'use_ft_proxies') + if shall_use_proxies and configured_proxies: + proxyhost_dicts = [] + proxies = [item.strip() for item in configured_proxies.split(',')] + default_proxy = gajim.proxy65_manager.get_default_for_name(self.name) + if default_proxy: + # add/move default proxy at top of the others + if default_proxy in proxies: + proxies.remove(default_proxy) + proxies.insert(0, default_proxy) + + for proxy in proxies: + (host, _port, jid) = gajim.proxy65_manager.get_proxy(proxy, self.name) + if not host: + continue + host_dict = { + 'state': 0, + 'target': unicode(file_props['receiver']), + 'id': file_props['sid'], + 'sid': file_props['sid'], + 'initiator': proxy, + 'host': host, + 'port': unicode(_port), + 'jid': jid + } + proxyhost_dicts.append(host_dict) + return proxyhost_dicts + else: + return [] + def send_file_rejection(self, file_props, code='403', typ=None): """ Inform sender that we refuse to download the file @@ -440,9 +452,6 @@ class ConnectionBytestream: # if we want to respect xep-0065 we have to check for proxy # activation result in any result iq real_id = unicode(iq_obj.getAttr('id')) - if real_id == self.awaiting_xmpp_ping_id: - self.awaiting_xmpp_ping_id = None - return if not real_id.startswith('au_'): return frm = self._ft_get_from(iq_obj) @@ -559,7 +568,7 @@ class ConnectionBytestream: field = form.getField('stream-method') if field.getValue() != xmpp.NS_BYTESTREAM: return - self.send_socks5_info(file_props, fast=True) + self._send_socks5_info(file_props) raise xmpp.NodeProcessed def _siSetCB(self, con, iq_obj): diff --git a/src/gui_interface.py b/src/gui_interface.py index 6f9c62244..52689e8e1 100644 --- a/src/gui_interface.py +++ b/src/gui_interface.py @@ -440,7 +440,7 @@ class Interface: # TODO: This causes problems when another # resource signs off! - conn.remove_transfers_for_contact(contact1) + conn.stop_all_active_file_transfers(contact1) # disable encryption, since if any messages are # lost they'll be not decryptable (note that