Welcome to mirror list, hosted at ThFree Co, Russian Federation.

dev.gajim.org/gajim/gajim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrendan Taylor <bct@diffeq.com>2008-05-17 06:23:46 +0400
committerBrendan Taylor <bct@diffeq.com>2008-05-17 06:23:46 +0400
commit517d962221e9c133314c7074380ec6ea975978cf (patch)
tree6d604ecb4d45eb537eb5f66e9e817bf86288417b
parent75ad801f62ddce4b094dd093905a014f8d96cc42 (diff)
fixed link-local messaging (broken by session-centric) and removed a ton of duplicated/unused code
-rw-r--r--src/common/connection_handlers.py307
-rw-r--r--src/common/zeroconf/connection_handlers_zeroconf.py569
-rw-r--r--src/common/zeroconf/connection_zeroconf.py8
3 files changed, 214 insertions, 670 deletions
diff --git a/src/common/connection_handlers.py b/src/common/connection_handlers.py
index d8bc1e868..06b2d037b 100644
--- a/src/common/connection_handlers.py
+++ b/src/common/connection_handlers.py
@@ -82,7 +82,7 @@ class ConnectionBytestream:
if not file_props.has_key('stopped') 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
@@ -97,7 +97,7 @@ class ConnectionBytestream:
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():
@@ -112,14 +112,14 @@ class ConnectionBytestream:
if contact.jid == sender_jid:
file_props['error'] = -3
self.remove_transfer(file_props)
-
+
def remove_all_transfers(self):
''' stops and removes 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
@@ -130,7 +130,7 @@ class ConnectionBytestream:
if remove_from_list:
if self.files_props.has_key('sid'):
del(self.files_props['sid'])
-
+
def disconnect_transfer(self, file_props):
if file_props is None:
return
@@ -142,7 +142,7 @@ class ConnectionBytestream:
if host.has_key('idx') 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 '''
@@ -165,7 +165,7 @@ class ConnectionBytestream:
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:
@@ -313,7 +313,7 @@ class ConnectionBytestream:
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 not self.files_props.has_key(sid):
@@ -321,7 +321,7 @@ class ConnectionBytestream:
file_props = self.files_props[sid]
file_props['hash'] = hash_id
return
-
+
def _connect_error(self, to, _id, sid, code = 404):
''' cb, when there is an error establishing BS connection, or
when connection is rejected'''
@@ -360,7 +360,7 @@ class ConnectionBytestream:
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):
gajim.log.debug('_bytestreamErrorCB')
@@ -376,7 +376,7 @@ class ConnectionBytestream:
file_props['error'] = -4
self.dispatch('FILE_REQUEST_ERROR', (jid, file_props, ''))
raise common.xmpp.NodeProcessed
-
+
def _bytestreamSetCB(self, con, iq_obj):
gajim.log.debug('_bytestreamSetCB')
target = unicode(iq_obj.getAttr('to'))
@@ -440,14 +440,14 @@ class ConnectionBytestream:
if host['initiator'] == frm and host.has_key('idx'):
gajim.socks5queue.activate_proxy(host['idx'])
raise common.xmpp.NodeProcessed
-
+
def _bytestreamResultCB(self, con, iq_obj):
gajim.log.debug('_bytestreamResultCB')
frm = helpers.get_full_jid_from_iq(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: # this bytestream result is not what we need
@@ -512,9 +512,9 @@ class ConnectionBytestream:
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):
gajim.log.debug('_siResultCB')
id = iq_obj.getAttr('id')
@@ -551,7 +551,7 @@ class ConnectionBytestream:
return
self.send_socks5_info(file_props, fast = True)
raise common.xmpp.NodeProcessed
-
+
def _siSetCB(self, con, iq_obj):
gajim.log.debug('_siSetCB')
jid = helpers.get_jid_from_iq(iq_obj)
@@ -616,7 +616,7 @@ class ConnectionDisco:
For identity: category, type is mandatory, name is optional.
For feature: var is mandatory'''
self._discover(common.xmpp.NS_DISCO_INFO, jid, node, id_prefix)
-
+
def request_register_agent_info(self, agent):
if not self.connection:
return None
@@ -642,8 +642,8 @@ class ConnectionDisco:
else:
# fixed: blocking
common.xmpp.features_nb.register(self.connection, agent, info, None)
-
-
+
+
def _discover(self, ns, jid, node = None, id_prefix = None):
if not self.connection:
return
@@ -654,11 +654,11 @@ class ConnectionDisco:
if node:
iq.setQuerynode(node)
self.connection.send(iq)
-
+
def _ReceivedRegInfo(self, con, resp, agent):
common.xmpp.features_nb._ReceivedRegInfo(con, resp, agent)
self._IqCB(con, resp)
-
+
def _discoGetCB(self, con, iq_obj):
''' get disco info '''
frm = helpers.get_full_jid_from_iq(iq_obj)
@@ -675,10 +675,10 @@ class ConnectionDisco:
feature = common.xmpp.Node('feature')
feature.setAttr('var', f)
query.addChild(node=feature)
-
+
self.connection.send(iq)
raise common.xmpp.NodeProcessed
-
+
def _DiscoverItemsErrorCB(self, con, iq_obj):
gajim.log.debug('DiscoverItemsErrorCB')
jid = helpers.get_full_jid_from_iq(iq_obj)
@@ -710,7 +710,7 @@ class ConnectionDisco:
continue
items.append(attr)
jid = helpers.get_full_jid_from_iq(iq_obj)
- hostname = gajim.config.get_per('accounts', self.name,
+ hostname = gajim.config.get_per('accounts', self.name,
'hostname')
id = iq_obj.getID()
if jid == hostname and id[0] == 'p':
@@ -739,7 +739,7 @@ class ConnectionDisco:
if self.commandInfoQuery(con, iq_obj):
raise common.xmpp.NodeProcessed
-
+
else:
iq = iq_obj.buildReply('result')
q = iq.getTag('query')
@@ -851,7 +851,7 @@ class ConnectionVcard:
if send_caps:
return self.add_caps(p)
return p
-
+
def add_caps(self, p):
''' advertise our capabilities in presence stanza (xep-0115)'''
c = p.setTag('c', namespace = common.xmpp.NS_CAPS)
@@ -859,7 +859,7 @@ class ConnectionVcard:
c.setAttr('node', 'http://gajim.org')
c.setAttr('ver', gajim.caps_hash)
return p
-
+
def node_to_dict(self, node):
dict = {}
for info in node.getChildren():
@@ -902,7 +902,7 @@ class ConnectionVcard:
fil.close()
except IOError, e:
self.dispatch('ERROR', (_('Disk Write Error'), str(e)))
-
+
def get_cached_vcard(self, fjid, is_fake_jid = False):
'''return the vcard as a dict
return {} if vcard was too old
@@ -930,6 +930,12 @@ class ConnectionVcard:
if vcard.has_key('PHOTO'):
if not isinstance(vcard['PHOTO'], dict):
del vcard['PHOTO']
+ elif vcard['PHOTO'].has_key('SHA'):
+ cached_sha = vcard['PHOTO']['SHA']
+ if self.vcard_shas.has_key(jid) and self.vcard_shas[jid] != \
+ cached_sha:
+ # user change his vcard so don't use the cached one
+ return {}
vcard['jid'] = jid
vcard['resource'] = gajim.get_resource_from_jid(fjid)
return vcard
@@ -1195,13 +1201,9 @@ class ConnectionVcard:
#('VCARD', {entry1: data, entry2: {entry21: data, ...}, ...})
self.dispatch('VCARD', vcard)
-class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionCaps):
+# basic connection handlers used here and in zeroconf
+class ConnectionHandlersBase:
def __init__(self):
- ConnectionVcard.__init__(self)
- ConnectionBytestream.__init__(self)
- ConnectionCommands.__init__(self)
- ConnectionPubSub.__init__(self)
- self.gmail_url = None
# List of IDs we are waiting answers for {id: (type_of_request, data), }
self.awaiting_answers = {}
# List of IDs that will produce a timeout is answer doesn't arrive
@@ -1210,8 +1212,130 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
# keep the jids we auto added (transports contacts) to not send the
# SUBSCRIBED event to gui
self.automatically_added = []
+
+ # keep track of sessions this connection has with other JIDs
+ self.sessions = {}
+
+ def _FeatureNegCB(self, con, stanza, session):
+ gajim.log.debug('FeatureNegCB')
+ feature = stanza.getTag(name='feature', namespace=common.xmpp.NS_FEATURE)
+ form = common.xmpp.DataForm(node=feature.getTag('x'))
+
+ if form['FORM_TYPE'] == 'urn:xmpp:ssn':
+ self.dispatch('SESSION_NEG', (stanza.getFrom(), session, form))
+ else:
+ reply = stanza.buildReply()
+ reply.setType('error')
+
+ reply.addChild(feature)
+ reply.addChild(node=common.xmpp.ErrorNode('service-unavailable', typ='cancel'))
+
+ con.send(reply)
+
+ raise common.xmpp.NodeProcessed
+
+ def _InitE2ECB(self, con, stanza, session):
+ gajim.log.debug('InitE2ECB')
+ init = stanza.getTag(name='init', namespace=common.xmpp.NS_ESESSION_INIT)
+ form = common.xmpp.DataForm(node=init.getTag('x'))
+
+ self.dispatch('SESSION_NEG', (stanza.getFrom(), session, form))
+
+ raise common.xmpp.NodeProcessed
+
+ def get_or_create_session(self, jid, thread_id):
+ '''returns an existing session between this connection and 'jid', returns a new one if none exist.'''
+
+ pm = True
+ if not gajim.interface.is_pm_contact(jid, self.name):
+ pm = False
+ jid = gajim.get_jid_without_resource(jid)
+
+ session = self.find_session(jid, thread_id)
+
+ if session:
+ return session
+
+ if pm:
+ return self.make_new_session(jid, thread_id, type = 'pm')
+ else:
+ return self.make_new_session(jid, thread_id)
+
+ def find_session(self, jid, thread_id):
+ try:
+ if not thread_id:
+ return self.find_null_session(jid)
+ else:
+ return self.sessions[jid][thread_id]
+ except KeyError:
+ return None
+
+ def terminate_sessions(self):
+ '''send termination messages and delete all active sessions'''
+ for jid in self.sessions:
+ for thread_id in self.sessions[jid]:
+ self.sessions[jid][thread_id].terminate()
+
+ self.sessions = {}
+
+ def delete_session(self, jid, thread_id):
+ try:
+ del self.sessions[jid][thread_id]
+
+ if not self.sessions[jid]:
+ del self.sessions[jid]
+ except KeyError:
+ pass
+
+ def find_null_session(self, jid):
+ '''finds all of the sessions between us and a remote jid in which we
+haven't received a thread_id yet and returns the session that we last
+sent a message to.'''
+
+ sessions = self.sessions[jid].values()
+
+ # sessions that we haven't received a thread ID in
+ idless = filter(lambda s: not s.received_thread_id, sessions)
+
+ # filter out everything exceptthe default session type
+ chat_sessions = filter(lambda s: isinstance(s, ChatControlSession), idless)
+
+ if chat_sessions:
+ # return the session that we last sent a message in
+ chat_sessions.sort(key=lambda s: s.last_send)
+ return chat_sessions[-1]
+ else:
+ return None
+
+ def make_new_session(self, jid, thread_id=None, type='chat', klass=None):
+ if not klass:
+ klass = ChatControlSession
+
+ # determine if this session is a pm session
+ # if not, discard the resource
+ if not type == 'pm':
+ jid = gajim.get_jid_without_resource(jid)
+
+ sess = klass(self, common.xmpp.JID(jid), thread_id, type)
+
+ if not jid in self.sessions:
+ self.sessions[jid] = {}
+
+ self.sessions[jid][sess.thread_id] = sess
+
+ return sess
+
+class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionCaps, ConnectionHandlersBase):
+ def __init__(self):
+ ConnectionVcard.__init__(self)
+ ConnectionBytestream.__init__(self)
+ ConnectionCommands.__init__(self)
+ ConnectionPubSub.__init__(self)
+ ConnectionHandlersBase.__init__(self)
+ self.gmail_url = None
+
# keep the latest subscribed event for each jid to prevent loop when we
- # acknoledge presences
+ # acknowledge presences
self.subscribed_events = {}
# IDs of jabber:iq:last requests
self.last_ids = []
@@ -1220,8 +1344,6 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
# ID of urn:xmpp:ping requests
self.awaiting_xmpp_ping_id = None
- # keep track of sessions this connection has with other JIDs
- self.sessions = {}
try:
idle.init()
except:
@@ -1234,7 +1356,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
err = common.xmpp.Error(iq_obj,
common.xmpp.protocol.ERR_NOT_AUTHORIZED)
self.connection.send(err)
-
+
def _HttpAuthCB(self, con, iq_obj):
gajim.log.debug('HttpAuthCB')
opt = gajim.config.get_per('accounts', self.name, 'http_auth')
@@ -1248,33 +1370,6 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
self.dispatch('HTTP_AUTH', (method, url, id, iq_obj, msg));
raise common.xmpp.NodeProcessed
- def _FeatureNegCB(self, con, stanza, session):
- gajim.log.debug('FeatureNegCB')
- feature = stanza.getTag(name='feature', namespace=common.xmpp.NS_FEATURE)
- form = common.xmpp.DataForm(node=feature.getTag('x'))
-
- if form['FORM_TYPE'] == 'urn:xmpp:ssn':
- self.dispatch('SESSION_NEG', (stanza.getFrom(), session, form))
- else:
- reply = stanza.buildReply()
- reply.setType('error')
-
- reply.addChild(feature)
- reply.addChild(node=common.xmpp.ErrorNode('service-unavailable', typ='cancel'))
-
- con.send(reply)
-
- raise common.xmpp.NodeProcessed
-
- def _InitE2ECB(self, con, stanza, session):
- gajim.log.debug('InitE2ECB')
- init = stanza.getTag(name='init', namespace=common.xmpp.NS_ESESSION_INIT)
- form = common.xmpp.DataForm(node=init.getTag('x'))
-
- self.dispatch('SESSION_NEG', (stanza.getFrom(), session, form))
-
- raise common.xmpp.NodeProcessed
-
def _ErrorCB(self, con, iq_obj):
gajim.log.debug('ErrorCB')
jid_from = helpers.get_full_jid_from_iq(iq_obj)
@@ -1727,88 +1822,6 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
self.dispatch('GC_INVITATION',(frm, jid_from, reason, password,
is_continued))
- def get_or_create_session(self, jid, thread_id):
- '''returns an existing session between this connection and 'jid', returns a new one if none exist.'''
-
- pm = True
- if not gajim.interface.is_pm_contact(jid, self.name):
- pm = False
- jid = gajim.get_jid_without_resource(jid)
-
- session = self.find_session(jid, thread_id)
-
- if session:
- return session
-
- if pm:
- return self.make_new_session(jid, thread_id, type = 'pm')
- else:
- return self.make_new_session(jid, thread_id)
-
- def find_session(self, jid, thread_id):
- try:
- if not thread_id:
- return self.find_null_session(jid)
- else:
- return self.sessions[jid][thread_id]
- except KeyError:
- return None
-
- def terminate_sessions(self):
- '''send termination messages and delete all active sessions'''
- for jid in self.sessions:
- for thread_id in self.sessions[jid]:
- self.sessions[jid][thread_id].terminate()
-
- self.sessions = {}
-
- def delete_session(self, jid, thread_id):
- try:
- del self.sessions[jid][thread_id]
-
- if not self.sessions[jid]:
- del self.sessions[jid]
- except KeyError:
- pass
-
- def find_null_session(self, jid):
- '''finds all of the sessions between us and a remote jid in which we
-haven't received a thread_id yet and returns the session that we last
-sent a message to.'''
-
- sessions = self.sessions[jid].values()
-
- # sessions that we haven't received a thread ID in
- idless = filter(lambda s: not s.received_thread_id, sessions)
-
- # filter out everything exceptthe default session type
- chat_sessions = filter(lambda s: isinstance(s, ChatControlSession), idless)
-
- if chat_sessions:
- # return the session that we last sent a message in
- chat_sessions.sort(key=lambda s: s.last_send)
- return chat_sessions[-1]
- else:
- return None
-
- def make_new_session(self, jid, thread_id=None, type='chat', klass=None):
- if not klass:
- klass = ChatControlSession
-
- # determine if this session is a pm session
- # if not, discard the resource
- if not type == 'pm':
- jid = gajim.get_jid_without_resource(jid)
-
- sess = klass(self, common.xmpp.JID(jid), thread_id, type)
-
- if not jid in self.sessions:
- self.sessions[jid] = {}
-
- self.sessions[jid][sess.thread_id] = sess
-
- return sess
-
def _pubsubEventCB(self, con, msg):
''' Called when we receive <message/> with pubsub event. '''
# TODO: Logging? (actually services where logging would be useful, should
diff --git a/src/common/zeroconf/connection_handlers_zeroconf.py b/src/common/zeroconf/connection_handlers_zeroconf.py
index 2aa945686..3befa52a3 100644
--- a/src/common/zeroconf/connection_handlers_zeroconf.py
+++ b/src/common/zeroconf/connection_handlers_zeroconf.py
@@ -35,6 +35,7 @@ import common.xmpp
from common import helpers
from common import gajim
from common.zeroconf import zeroconf
+
STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
'invisible']
# kind of events we can wait for an answer
@@ -48,173 +49,23 @@ except:
gajim.log.debug(_('Unable to load idle module'))
HAS_IDLE = False
-from common.stanza_session import EncryptedStanzaSession
+from common import connection_handlers
+from session import ChatControlSession
-class ConnectionVcard:
- def __init__(self):
- self.vcard_sha = None
- self.vcard_shas = {} # sha of contacts
- self.room_jids = [] # list of gc jids so that vcard are saved in a folder
+class ConnectionVcard(connection_handlers.ConnectionVcard):
+ def add_sha(self, p, send_caps = True):
+ pass
- def add_sha(self, p, send_caps = True):
- pass
-
def add_caps(self, p):
pass
- def node_to_dict(self, node):
- dict = {}
-
- for info in node.getChildren():
- name = info.getName()
- if name in ('ADR', 'TEL', 'EMAIL'): # we can have several
- if not dict.has_key(name):
- dict[name] = []
- entry = {}
- for c in info.getChildren():
- entry[c.getName()] = c.getData()
- dict[name].append(entry)
- elif info.getChildren() == []:
- dict[name] = info.getData()
- else:
- dict[name] = {}
- for c in info.getChildren():
- dict[name][c.getName()] = c.getData()
-
- return dict
-
- def save_vcard_to_hd(self, full_jid, card):
- jid, nick = gajim.get_room_and_nick_from_fjid(full_jid)
- puny_jid = helpers.sanitize_filename(jid)
- path = os.path.join(gajim.VCARD_PATH, puny_jid)
- if jid in self.room_jids or os.path.isdir(path):
- # remove room_jid file if needed
- if os.path.isfile(path):
- os.remove(path)
- # create folder if needed
- if not os.path.isdir(path):
- os.mkdir(path, 0700)
- puny_nick = helpers.sanitize_filename(nick)
- path_to_file = os.path.join(gajim.VCARD_PATH, puny_jid, puny_nick)
- else:
- path_to_file = path
- fil = open(path_to_file, 'w')
- fil.write(str(card))
- fil.close()
-
- def get_cached_vcard(self, fjid, is_fake_jid = False):
- '''return the vcard as a dict
- return {} if vcard was too old
- return None if we don't have cached vcard'''
- jid, nick = gajim.get_room_and_nick_from_fjid(fjid)
- puny_jid = helpers.sanitize_filename(jid)
- if is_fake_jid:
- puny_nick = helpers.sanitize_filename(nick)
- path_to_file = os.path.join(gajim.VCARD_PATH, puny_jid, puny_nick)
- else:
- path_to_file = os.path.join(gajim.VCARD_PATH, puny_jid)
- if not os.path.isfile(path_to_file):
- return None
- # We have the vcard cached
- f = open(path_to_file)
- c = f.read()
- f.close()
- card = common.xmpp.Node(node = c)
- vcard = self.node_to_dict(card)
- if vcard.has_key('PHOTO'):
- if not isinstance(vcard['PHOTO'], dict):
- del vcard['PHOTO']
- elif vcard['PHOTO'].has_key('SHA'):
- cached_sha = vcard['PHOTO']['SHA']
- if self.vcard_shas.has_key(jid) and self.vcard_shas[jid] != \
- cached_sha:
- # user change his vcard so don't use the cached one
- return {}
- vcard['jid'] = jid
- vcard['resource'] = gajim.get_resource_from_jid(fjid)
- return vcard
-
def request_vcard(self, jid = None, is_fake_jid = False):
pass
-
+
def send_vcard(self, vcard):
pass
-class ConnectionBytestream:
- def __init__(self):
- self.files_props = {}
-
- def is_transfer_stopped(self, file_props):
- if file_props.has_key('error') and file_props['error'] != 0:
- return True
- if file_props.has_key('completed') and file_props['completed']:
- return True
- if file_props.has_key('connected') and file_props['connected'] == False:
- return True
- if not file_props.has_key('stopped') 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 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']).split('/')[0]
- if contact.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.jid == sender_jid:
- file_props['error'] = -3
- self.remove_transfer(file_props)
-
- def remove_all_transfers(self):
- ''' stops and removes 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 self.files_props.has_key('sid'):
- del(self.files_props['sid'])
-
- def disconnect_transfer(self, file_props):
- if file_props is None:
- return
- if file_props.has_key('hash'):
- gajim.socks5queue.remove_sender(file_props['hash'])
-
- if file_props.has_key('streamhosts'):
- for host in file_props['streamhosts']:
- if host.has_key('idx') and host['idx'] > 0:
- gajim.socks5queue.remove_receiver(host['idx'])
- gajim.socks5queue.remove_sender(host['idx'])
-
+class ConnectionBytestream(connection_handlers.ConnectionBytestream):
def send_socks5_info(self, file_props, fast = True, receiver = None,
sender = None):
''' send iq for the present streamhosts and proxies '''
@@ -274,43 +125,6 @@ class ConnectionBytestream:
streamhost.setAttr('jid', sender)
self.connection.send(iq)
- def send_file_rejection(self, file_props):
- ''' informs sender that we refuse 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 = 'error')
- iq.setAttr('id', file_props['request-id'])
- err = common.xmpp.ErrorNode(code = '403', typ = 'cancel', name =
- 'forbidden', text = 'Offer Declined')
- 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 file_props.has_key('offset') 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 send_file_request(self, file_props):
''' send iq for new FT request '''
if not self.connection or self.connected < 2:
@@ -318,7 +132,7 @@ class ConnectionBytestream:
our_jid = gajim.get_jid_from_account(self.name)
frm = our_jid
file_props['sender'] = frm
- fjid = file_props['receiver'].jid
+ fjid = file_props['receiver'].jid
iq = common.xmpp.Protocol(name = 'iq', to = fjid,
typ = 'set')
iq.setID(file_props['sid'])
@@ -343,70 +157,7 @@ class ConnectionBytestream:
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 not self.files_props.has_key(sid):
- return
- file_props = self.files_props[sid]
- file_props['hash'] = hash_id
- return
-
- def _connect_error(self, to, _id, sid, code = 404):
- ''' cb, when there is an error establishing BS connection, or
- when connection is rejected'''
- 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):
- '''cb, called after authentication to proxy server '''
- 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):
- gajim.log.debug('_bytestreamErrorCB')
- id = unicode(iq_obj.getAttr('id'))
- frm = unicode(iq_obj.getFrom())
- query = iq_obj.getTag('query')
- gajim.proxy65_manager.error_cb(frm, query)
- jid = unicode(iq_obj.getFrom())
- id = id[3:]
- if not self.files_props.has_key(id):
- return
- file_props = self.files_props[id]
- file_props['error'] = -4
- self.dispatch('FILE_REQUEST_ERROR', (jid, file_props, ''))
- raise common.xmpp.NodeProcessed
-
+
def _bytestreamSetCB(self, con, iq_obj):
gajim.log.debug('_bytestreamSetCB')
target = unicode(iq_obj.getAttr('to'))
@@ -432,7 +183,7 @@ class ConnectionBytestream:
if self.files_props.has_key(sid):
file_props = self.files_props[sid]
file_props['fast'] = streamhosts
- if file_props['type'] == 's':
+ if file_props['type'] == 's':
if file_props.has_key('streamhosts'):
file_props['streamhosts'].extend(streamhosts)
else:
@@ -465,14 +216,14 @@ class ConnectionBytestream:
if host['initiator'] == frm and host.has_key('idx'):
gajim.socks5queue.activate_proxy(host['idx'])
raise common.xmpp.NodeProcessed
-
+
def _bytestreamResultCB(self, con, iq_obj):
gajim.log.debug('_bytestreamResultCB')
frm = unicode(iq_obj.getFrom())
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: # this bytestream result is not what we need
@@ -531,9 +282,9 @@ class ConnectionBytestream:
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):
gajim.log.debug('_siResultCB')
self.peerhost = con._owner.Connection._sock.getsockname()
@@ -571,7 +322,7 @@ class ConnectionBytestream:
return
self.send_socks5_info(file_props, fast = True)
raise common.xmpp.NodeProcessed
-
+
def _siSetCB(self, con, iq_obj):
gajim.log.debug('_siSetCB')
jid = unicode(iq_obj.getFrom())
@@ -595,7 +346,7 @@ class ConnectionBytestream:
if mime_type is not None:
file_props['mime-type'] = mime_type
our_jid = gajim.get_jid_from_account(self.name)
- file_props['receiver'] = our_jid
+ file_props['receiver'] = our_jid
file_props['sender'] = unicode(iq_obj.getFrom())
file_props['request-id'] = unicode(iq_obj.getAttr('id'))
file_props['sid'] = unicode(si.getAttr('id'))
@@ -623,320 +374,100 @@ class ConnectionBytestream:
self.dispatch('FILE_REQUEST_ERROR', (jid, file_props, ''))
raise common.xmpp.NodeProcessed
-class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream):
+class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream, connection_handlers.ConnectionHandlersBase):
def __init__(self):
ConnectionVcard.__init__(self)
ConnectionBytestream.__init__(self)
- # List of IDs we are waiting answers for {id: (type_of_request, data), }
- self.awaiting_answers = {}
- # List of IDs that will produce a timeout is answer doesn't arrive
- # {time_of_the_timeout: (id, message to send to gui), }
- self.awaiting_timeouts = {}
- # keep the jids we auto added (transports contacts) to not send the
- # SUBSCRIBED event to gui
- self.automatically_added = []
- # keep track of sessions this connection has with other JIDs
- self.sessions = {}
+ connection_handlers.ConnectionHandlersBase.__init__(self)
+
try:
idle.init()
except:
HAS_IDLE = False
-
+
def _messageCB(self, ip, con, msg):
'''Called when we receive a message'''
+
+ gajim.log.debug('Zeroconf MessageCB')
+
+ frm = msg.getFrom()
mtype = msg.getType()
thread_id = msg.getThread()
- tim = msg.getTimestamp()
- tim = helpers.datetime_tuple(tim)
- tim = time.localtime(timegm(tim))
- frm = msg.getFrom()
+
+ if not mtype:
+ mtype = 'normal'
if frm == None:
for key in self.connection.zeroconf.contacts:
if ip == self.connection.zeroconf.contacts[key][zeroconf.C_ADDRESS]:
frm = key
+
frm = unicode(frm)
- jid = frm
- session = self.get_or_create_session(frm, thread_id, mtype)
+ session = self.get_or_create_session(frm, thread_id)
if thread_id and not session.received_thread_id:
session.received_thread_id = True
-
+
if msg.getTag('feature') and msg.getTag('feature').namespace == \
common.xmpp.NS_FEATURE:
if gajim.HAVE_PYCRYPTO:
self._FeatureNegCB(con, msg, session)
return
+
if msg.getTag('init') and msg.getTag('init').namespace == \
common.xmpp.NS_ESESSION_INIT:
self._InitE2ECB(con, msg, session)
- no_log_for = gajim.config.get_per('accounts', self.name,
- 'no_log_for').split()
encrypted = False
- chatstate = None
+ tim = msg.getTimestamp()
+ tim = helpers.datetime_tuple(tim)
+ tim = time.localtime(timegm(tim))
- e2e_tag = msg.getTag('c', namespace = common.xmpp.NS_STANZA_CRYPTO)
- if e2e_tag:
+ if msg.getTag('c', namespace = common.xmpp.NS_STANZA_CRYPTO):
encrypted = True
try:
msg = session.decrypt_stanza(msg)
except:
self.dispatch('FAILED_DECRYPT', (frm, tim))
-
+
msgtxt = msg.getBody()
- msghtml = msg.getXHTML()
subject = msg.getSubject() # if not there, it's None
- encTag = msg.getTag('x', namespace = common.xmpp.NS_ENCRYPTED)
- decmsg = ''
- form_node = msg.getTag('x', namespace = common.xmpp.NS_DATA)
# invitations
invite = None
+ encTag = msg.getTag('x', namespace = common.xmpp.NS_ENCRYPTED)
+
if not encTag:
invite = msg.getTag('x', namespace = common.xmpp.NS_MUC_USER)
if invite and not invite.getTag('invite'):
invite = None
- delayed = msg.getTag('x', namespace = common.xmpp.NS_DELAY) != None
- msg_id = None
- composing_xep = None
- xtags = msg.getTags('x')
- # chatstates - look for chatstate tags in a message if not delayed
- if not delayed:
- composing_xep = False
- children = msg.getChildren()
- for child in children:
- if child.getNamespace() == 'http://jabber.org/protocol/chatstates':
- chatstate = child.getName()
- composing_xep = 'XEP-0085'
- break
- # No JEP-0085 support, fallback to JEP-0022
- if not chatstate:
- chatstate_child = msg.getTag('x', namespace = common.xmpp.NS_EVENT)
- if chatstate_child:
- chatstate = 'active'
- composing_xep = 'XEP-0022'
- if not msgtxt and chatstate_child.getTag('composing'):
- chatstate = 'composing'
- # JEP-0172 User Nickname
- user_nick = msg.getTagData('nick')
- if not user_nick:
- user_nick = ''
if encTag and self.USE_GPG:
#decrypt
encmsg = encTag.getData()
-
+
keyID = gajim.config.get_per('accounts', self.name, 'keyid')
if keyID:
decmsg = self.gpg.decrypt(encmsg, keyID)
# \x00 chars are not allowed in C (so in GTK)
- decmsg = decmsg.replace('\x00', '')
- if decmsg:
- msgtxt = decmsg
- encrypted = True
- if mtype == 'error':
- error_msg = msg.getError()
- if not error_msg:
- error_msg = msgtxt
- msgtxt = None
- if self.name not in no_log_for:
- gajim.logger.write('error', frm, error_msg, tim = tim,
- subject = subject)
- self.dispatch('MSGERROR', (frm, msg.getErrorCode(), error_msg, msgtxt,
- tim))
- elif mtype == 'chat': # it's type 'chat'
- if not msg.getTag('body') and chatstate is None: #no <body>
- return
- if msg.getTag('body') and self.name not in no_log_for and jid not in\
- no_log_for and msgtxt:
- msg_id = gajim.logger.write('chat_msg_recv', frm, msgtxt, tim = tim,
- subject = subject)
- self.dispatch('MSG', (frm, msgtxt, tim, encrypted, mtype, subject,
- chatstate, msg_id, composing_xep, user_nick, msghtml, session,
- form_node))
- elif mtype == 'normal': # it's single message
- if self.name not in no_log_for and jid not in no_log_for and msgtxt:
- gajim.logger.write('single_msg_recv', frm, msgtxt, tim = tim,
- subject = subject)
- if invite:
- self.dispatch('MSG', (frm, msgtxt, tim, encrypted, 'normal',
- subject, chatstate, msg_id, composing_xep, user_nick, msghtml,
- session, form_node))
- # END messageCB
-
- def _FeatureNegCB(self, con, stanza, session):
- gajim.log.debug('FeatureNegCB')
- feature = stanza.getTag(name='feature', namespace=common.xmpp.NS_FEATURE)
- form = common.xmpp.DataForm(node=feature.getTag('x'))
-
- if form['FORM_TYPE'] == 'urn:xmpp:ssn':
- self.dispatch('SESSION_NEG', (stanza.getFrom(), session, form))
- else:
- reply = stanza.buildReply()
- reply.setType('error')
+ msgtxt = decmsg.replace('\x00', '')
+ encrypted = True
- reply.addChild(feature)
- reply.addChild(node=xmpp.ErrorNode('service-unavailable', typ='cancel'))
-
- con.send(reply)
-
- raise common.xmpp.NodeProcessed
-
- def _InitE2ECB(self, con, stanza, session):
- gajim.log.debug('InitE2ECB')
- init = stanza.getTag(name='init', namespace=common.xmpp.NS_ESESSION_INIT)
- form = common.xmpp.DataForm(node=init.getTag('x'))
-
- self.dispatch('SESSION_NEG', (stanza.getFrom(), session, form))
-
- raise common.xmpp.NodeProcessed
-
- def terminate_sessions(self):
- '''send termination messages and delete all active sessions'''
- # XXX
- pass
-
- def get_or_create_session(self, jid, thread_id, type):
- '''returns an existing session between this connection and 'jid', returns a new one if none exist.'''
- session = self.find_session(jid, thread_id, type)
-
- if session:
- return session
+ if mtype == 'error':
+ self.dispatch_error_msg(msg, msgtxt, session, frm, tim, subject)
else:
- # it's possible we initiated a session with a bare JID and this is the
- # first time we've seen a resource
- bare_jid = gajim.get_jid_without_resource(jid)
- if bare_jid != jid:
- session = self.find_session(bare_jid, thread_id, type)
- if session:
- if not session.received_thread_id:
- thread_id = session.thread_id
-
- self.move_session(bare_jid, thread_id, jid.split("/")[1])
- return session
-
- return self.make_new_session(jid, thread_id, type)
-
- def find_session(self, jid, thread_id, type):
- try:
- if type == 'chat' and not thread_id:
- return self.find_null_session(jid)
+ # XXX this shouldn't be hardcoded
+ if isinstance(session, ChatControlSession):
+ session.received(frm, msgtxt, tim, encrypted, subject, msg)
else:
- return self.sessions[jid][thread_id]
- except KeyError:
- return None
-
- def delete_session(self, jid, thread_id):
- try:
- del self.sessions[jid][thread_id]
-
- if not self.sessions[jid]:
- del self.sessions[jid]
- except KeyError:
- print "jid %s should have been in %s, but it wasn't. missing session?" % (repr(jid), repr(self.sessions.keys()))
-
- def move_session(self, original_jid, thread_id, to_resource):
- '''moves a session to another resource.'''
- session = self.sessions[original_jid][thread_id]
-
- del self.sessions[original_jid][thread_id]
-
- new_jid = gajim.get_jid_without_resource(original_jid) + '/' + to_resource
- session.jid = common.xmpp.JID(new_jid)
-
- if not new_jid in self.sessions:
- self.sessions[new_jid] = {}
-
- self.sessions[new_jid][thread_id] = session
-
- def find_null_session(self, jid):
- '''finds all of the sessions between us and jid that jid hasn't sent a thread_id in yet.
-
-returns the session that we last sent a message to.'''
-
- sessions_with_jid = self.sessions[jid].values()
- no_threadid_sessions = filter(lambda s: not s.received_thread_id, sessions_with_jid)
+ session.received(msg)
+ # END messageCB
- if no_threadid_sessions:
- no_threadid_sessions.sort(key=lambda s: s.last_send)
- return no_threadid_sessions[-1]
- else:
- return None
-
- def make_new_session(self, jid, thread_id = None, type = 'chat'):
- sess = EncryptedStanzaSession(self, common.xmpp.JID(jid), thread_id, type)
-
- if not jid in self.sessions:
- self.sessions[jid] = {}
-
- self.sessions[jid][sess.thread_id] = sess
-
- return sess
-
- def parse_data_form(self, node):
- dic = {}
- tag = node.getTag('title')
- if tag:
- dic['title'] = tag.getData()
- tag = node.getTag('instructions')
- if tag:
- dic['instructions'] = tag.getData()
- i = 0
- for child in node.getChildren():
- if child.getName() != 'field':
- continue
- var = child.getAttr('var')
- ctype = child.getAttr('type')
- label = child.getAttr('label')
- if not var and ctype != 'fixed': # We must have var if type != fixed
- continue
- dic[i] = {}
- if var:
- dic[i]['var'] = var
- if ctype:
- dic[i]['type'] = ctype
- if label:
- dic[i]['label'] = label
- tags = child.getTags('value')
- if len(tags):
- dic[i]['values'] = []
- for tag in tags:
- data = tag.getData()
- if ctype == 'boolean':
- if data in ('yes', 'true', 'assent', '1'):
- data = True
- else:
- data = False
- dic[i]['values'].append(data)
- tag = child.getTag('desc')
- if tag:
- dic[i]['desc'] = tag.getData()
- option_tags = child.getTags('option')
- if len(option_tags):
- dic[i]['options'] = {}
- j = 0
- for option_tag in option_tags:
- dic[i]['options'][j] = {}
- label = option_tag.getAttr('label')
- tags = option_tag.getTags('value')
- dic[i]['options'][j]['values'] = []
- for tag in tags:
- dic[i]['options'][j]['values'].append(tag.getData())
- if not label:
- label = dic[i]['options'][j]['values'][0]
- dic[i]['options'][j]['label'] = label
- j += 1
- if not dic[i].has_key('values'):
- dic[i]['values'] = [dic[i]['options'][0]['values'][0]]
- i += 1
- return dic
-
def store_metacontacts(self, tags):
''' fake empty method '''
- # serverside metacontacts are not supported with zeroconf
+ # serverside metacontacts are not supported with zeroconf
# (there is no server)
pass
diff --git a/src/common/zeroconf/connection_zeroconf.py b/src/common/zeroconf/connection_zeroconf.py
index f57338403..d306d199b 100644
--- a/src/common/zeroconf/connection_zeroconf.py
+++ b/src/common/zeroconf/connection_zeroconf.py
@@ -196,7 +196,7 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
return self.call_resolve_timeout
# callbacks called from zeroconf
- def _on_new_service(self,jid):
+ def _on_new_service(self, jid):
self.roster.setItem(jid)
self.dispatch('ROSTER_INFO', (jid, self.roster.getName(jid), 'both', 'no', self.roster.getGroups(jid)))
self.dispatch('NOTIFY', (jid, self.roster.getStatus(jid), self.roster.getMessage(jid), 'local', 0, None, 0, None))
@@ -362,7 +362,7 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
def send_message(self, jid, msg, keyID, type = 'chat', subject='',
chatstate = None, msg_id = None, composing_xep = None, resource = None,
- user_nick = None, session=None):
+ user_nick = None, session=None, forward_from=None, form_node=None, original_message=None):
fjid = jid
if not self.connection:
@@ -454,13 +454,13 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
def on_send_not_ok(reason):
reason += ' ' + _('Your message could not be sent.')
- self.dispatch('MSGERROR', [jid, '-1', reason, None, None])
+ self.dispatch('MSGERROR', [jid, '-1', reason, None, None, session])
ret = self.connection.send(msg_iq, msg != None, on_ok=on_send_ok,
on_not_ok=on_send_not_ok)
if ret == -1:
# Contact Offline
- self.dispatch('MSGERROR', [jid, '-1', _('Contact is offline. Your message could not be sent.'), None, None])
+ self.dispatch('MSGERROR', [jid, '-1', _('Contact is offline. Your message could not be sent.'), None, None, session])
def send_stanza(self, stanza):
# send a stanza untouched