split XEP-0096 (FT negociation) and XEP-0066 (Socks5 bytestream) into 2 clases
This commit is contained in:
parent
7387d779c0
commit
72f10672e5
10
AUTHORS
10
AUTHORS
|
@ -1,8 +1,13 @@
|
|||
CURRENT DEVELOPERS:
|
||||
|
||||
Alexander Cherniuk (ts33kr AT gmail.com)
|
||||
Nikos Kouremenos (kourem AT gmail.com)
|
||||
Yann Leboulanger (asterix AT lagaule.org)
|
||||
Julien Pivotto (roidelapluie AT gmail.com)
|
||||
Jonathan Schleifer (js-gajim AT webkeks.org)
|
||||
Travis Shirk (travis AT pobox.com)
|
||||
Brendan Taylor (whateley AT gmail.com)
|
||||
Jean-Marie Traissard (jim AT lapin.org)
|
||||
|
||||
PAST DEVELOPERS:
|
||||
|
||||
|
@ -10,8 +15,3 @@ Stefan Bethge (stefan AT lanpartei.de)
|
|||
Stephan Erb (steve-e AT h3c.de)
|
||||
Vincent Hanquez (tab AT snarc.org)
|
||||
Dimitur Kirov (dkirov AT gmail.com)
|
||||
Nikos Kouremenos (kourem AT gmail.com)
|
||||
Julien Pivotto (roidelapluie AT gmail.com)
|
||||
Travis Shirk (travis AT pobox.com)
|
||||
Brendan Taylor (whateley AT gmail.com)
|
||||
Jean-Marie Traissard (jim AT lapin.org)
|
||||
|
|
|
@ -49,7 +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
|
||||
from common.protocol.bytestream import ConnectionSocks5Bytestream
|
||||
import common.caps_cache as capscache
|
||||
if gajim.HAVE_FARSIGHT:
|
||||
from common.jingle import ConnectionJingle
|
||||
|
@ -915,13 +915,13 @@ class ConnectionHandlersBase:
|
|||
|
||||
return sess
|
||||
|
||||
class ConnectionHandlers(ConnectionVcard, ConnectionBytestream,
|
||||
ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionPEP,
|
||||
ConnectionCaps, ConnectionHandlersBase, ConnectionJingle):
|
||||
class ConnectionHandlers(ConnectionVcard, ConnectionSocks5Bytestream,
|
||||
ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionPEP,
|
||||
ConnectionCaps, ConnectionHandlersBase, ConnectionJingle):
|
||||
def __init__(self):
|
||||
global HAS_IDLE
|
||||
ConnectionVcard.__init__(self)
|
||||
ConnectionBytestream.__init__(self)
|
||||
ConnectionSocks5Bytestream.__init__(self)
|
||||
ConnectionCommands.__init__(self)
|
||||
ConnectionPubSub.__init__(self)
|
||||
ConnectionPEP.__init__(self, account=self.name, dispatcher=self,
|
||||
|
|
|
@ -75,6 +75,190 @@ class ConnectionBytestream:
|
|||
def __init__(self):
|
||||
self.files_props = {}
|
||||
|
||||
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 _ft_get_from(self, iq_obj):
|
||||
return helpers.get_full_jid_from_iq(iq_obj)
|
||||
|
||||
def _ft_get_streamhost_jid_attr(self, streamhost):
|
||||
return helpers.parse_jid(streamhost.getAttr('jid'))
|
||||
|
||||
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 = xmpp.Iq(to=fjid, typ='set')
|
||||
iq.setID(file_props['sid'])
|
||||
self.files_props[file_props['sid']] = file_props
|
||||
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', 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', 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(xmpp.NS_BYTESTREAM)
|
||||
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 = xmpp.Iq(to=unicode(file_props['sender']), typ='result')
|
||||
iq.setAttr('id', file_props['request-id'])
|
||||
si = iq.setTag('si', namespace=xmpp.NS_SI)
|
||||
if 'offset' in file_props and file_props['offset']:
|
||||
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', namespace=xmpp.NS_FEATURE)
|
||||
_feature = xmpp.DataForm(typ='submit')
|
||||
feature.addChild(node=_feature)
|
||||
field = _feature.setField('stream-method')
|
||||
field.delAttr('type')
|
||||
field.setValue(xmpp.NS_BYTESTREAM)
|
||||
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 = xmpp.Iq(to=unicode(file_props['sender']), typ='error')
|
||||
iq.setAttr('id', file_props['request-id'])
|
||||
if code == '400' and typ in ('stream', 'profile'):
|
||||
name = 'bad-request'
|
||||
text = ''
|
||||
else:
|
||||
name = 'forbidden'
|
||||
text = 'Offer Declined'
|
||||
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=xmpp.NS_SI)
|
||||
else:
|
||||
err.setTag('bad-profile', namespace=xmpp.NS_SI)
|
||||
iq.addChild(node=err)
|
||||
self.connection.send(iq)
|
||||
|
||||
def _siResultCB(self, con, iq_obj):
|
||||
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
|
||||
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() != xmpp.NS_FEATURE:
|
||||
return
|
||||
form_tag = feature.getTag('x')
|
||||
form = xmpp.DataForm(node=form_tag)
|
||||
field = form.getField('stream-method')
|
||||
if field.getValue() != xmpp.NS_BYTESTREAM:
|
||||
return
|
||||
self._send_socks5_info(file_props)
|
||||
raise xmpp.NodeProcessed
|
||||
|
||||
def _siSetCB(self, con, iq_obj):
|
||||
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 != xmpp.NS_FILE:
|
||||
self.send_file_rejection(file_props, code='400', typ='profile')
|
||||
raise xmpp.NodeProcessed
|
||||
feature_tag = si.getTag('feature', namespace=xmpp.NS_FEATURE)
|
||||
if not feature_tag:
|
||||
return
|
||||
form_tag = feature_tag.getTag('x', namespace=xmpp.NS_DATA)
|
||||
if not form_tag:
|
||||
return
|
||||
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 xmpp.NS_BYTESTREAM in values:
|
||||
break
|
||||
else:
|
||||
self.send_file_rejection(file_props, code='400', typ='stream')
|
||||
raise 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
|
||||
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 xmpp.NodeProcessed
|
||||
|
||||
def _siErrorCB(self, con, iq_obj):
|
||||
si = iq_obj.getTag('si')
|
||||
profile = si.getAttr('profile')
|
||||
if profile != xmpp.NS_FILE:
|
||||
return
|
||||
file_props = self.files_props.get(iq_obj.getAttr('id'))
|
||||
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 ConnectionSocks5Bytestream(ConnectionBytestream):
|
||||
|
||||
def send_success_connect_reply(self, streamhost):
|
||||
"""
|
||||
Send reply to the initiator of FT that we made a connection
|
||||
|
@ -252,92 +436,6 @@ class ConnectionBytestream:
|
|||
else:
|
||||
return []
|
||||
|
||||
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 = xmpp.Iq(to=unicode(file_props['sender']), typ='error')
|
||||
iq.setAttr('id', file_props['request-id'])
|
||||
if code == '400' and typ in ('stream', 'profile'):
|
||||
name = 'bad-request'
|
||||
text = ''
|
||||
else:
|
||||
name = 'forbidden'
|
||||
text = 'Offer Declined'
|
||||
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=xmpp.NS_SI)
|
||||
else:
|
||||
err.setTag('bad-profile', namespace=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 = xmpp.Iq(to=unicode(file_props['sender']), typ='result')
|
||||
iq.setAttr('id', file_props['request-id'])
|
||||
si = iq.setTag('si', namespace=xmpp.NS_SI)
|
||||
if 'offset' in file_props and file_props['offset']:
|
||||
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', namespace=xmpp.NS_FEATURE)
|
||||
_feature = xmpp.DataForm(typ='submit')
|
||||
feature.addChild(node=_feature)
|
||||
field = _feature.setField('stream-method')
|
||||
field.delAttr('type')
|
||||
field.setValue(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 = xmpp.Iq(to=fjid, typ='set')
|
||||
iq.setID(file_props['sid'])
|
||||
self.files_props[file_props['sid']] = file_props
|
||||
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', 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', 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(xmpp.NS_BYTESTREAM)
|
||||
self.connection.send(iq)
|
||||
|
||||
def _result_socks5_sid(self, sid, hash_id):
|
||||
"""
|
||||
Store the result of SHA message from auth
|
||||
|
@ -406,9 +504,6 @@ class ConnectionBytestream:
|
|||
self.dispatch('FILE_REQUEST_ERROR', (jid, file_props, ''))
|
||||
raise xmpp.NodeProcessed
|
||||
|
||||
def _ft_get_from(self, iq_obj):
|
||||
return helpers.get_full_jid_from_iq(iq_obj)
|
||||
|
||||
def _bytestreamSetCB(self, con, iq_obj):
|
||||
target = unicode(iq_obj.getAttr('to'))
|
||||
id_ = unicode(iq_obj.getAttr('id'))
|
||||
|
@ -466,9 +561,6 @@ class ConnectionBytestream:
|
|||
gajim.socks5queue.activate_proxy(host['idx'])
|
||||
raise xmpp.NodeProcessed
|
||||
|
||||
def _ft_get_streamhost_jid_attr(self, streamhost):
|
||||
return helpers.parse_jid(streamhost.getAttr('jid'))
|
||||
|
||||
def _bytestreamResultCB(self, con, iq_obj):
|
||||
frm = self._ft_get_from(iq_obj)
|
||||
real_id = unicode(iq_obj.getAttr('id'))
|
||||
|
@ -542,98 +634,7 @@ class ConnectionBytestream:
|
|||
|
||||
raise xmpp.NodeProcessed
|
||||
|
||||
def _siResultCB(self, con, iq_obj):
|
||||
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
|
||||
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() != xmpp.NS_FEATURE:
|
||||
return
|
||||
form_tag = feature.getTag('x')
|
||||
form = xmpp.DataForm(node=form_tag)
|
||||
field = form.getField('stream-method')
|
||||
if field.getValue() != xmpp.NS_BYTESTREAM:
|
||||
return
|
||||
self._send_socks5_info(file_props)
|
||||
raise xmpp.NodeProcessed
|
||||
|
||||
def _siSetCB(self, con, iq_obj):
|
||||
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 != xmpp.NS_FILE:
|
||||
self.send_file_rejection(file_props, code='400', typ='profile')
|
||||
raise xmpp.NodeProcessed
|
||||
feature_tag = si.getTag('feature', namespace=xmpp.NS_FEATURE)
|
||||
if not feature_tag:
|
||||
return
|
||||
form_tag = feature_tag.getTag('x', namespace=xmpp.NS_DATA)
|
||||
if not form_tag:
|
||||
return
|
||||
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 xmpp.NS_BYTESTREAM in values:
|
||||
break
|
||||
else:
|
||||
self.send_file_rejection(file_props, code='400', typ='stream')
|
||||
raise 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
|
||||
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 xmpp.NodeProcessed
|
||||
|
||||
def _siErrorCB(self, con, iq_obj):
|
||||
si = iq_obj.getTag('si')
|
||||
profile = si.getAttr('profile')
|
||||
if profile != xmpp.NS_FILE:
|
||||
return
|
||||
file_props = self.files_props.get(iq_obj.getAttr('id'))
|
||||
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):
|
||||
class ConnectionSocks5BytestreamZeroconf(ConnectionSocks5Bytestream):
|
||||
|
||||
def _ft_get_from(self, iq_obj):
|
||||
return unicode(iq_obj.getFrom())
|
||||
|
|
|
@ -35,7 +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
|
||||
from common.protocol.bytestream import ConnectionSocks5BytestreamZeroconf
|
||||
|
||||
import logging
|
||||
log = logging.getLogger('gajim.c.z.connection_handlers_zeroconf')
|
||||
|
@ -70,8 +70,9 @@ class ConnectionVcard(connection_handlers.ConnectionVcard):
|
|||
pass
|
||||
|
||||
|
||||
class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestreamZeroconf,
|
||||
ConnectionCommands, ConnectionPEP, connection_handlers.ConnectionHandlersBase):
|
||||
class ConnectionHandlersZeroconf(ConnectionVcard,
|
||||
ConnectionSocks5BytestreamZeroconf, ConnectionCommands, ConnectionPEP,
|
||||
connection_handlers.ConnectionHandlersBase):
|
||||
def __init__(self):
|
||||
ConnectionVcard.__init__(self)
|
||||
ConnectionBytestreamZeroconf.__init__(self)
|
||||
|
|
Loading…
Reference in New Issue