fixed link-local messaging (broken by session-centric) and removed a ton of duplicated/unused code
This commit is contained in:
parent
75ad801f62
commit
517d962221
|
@ -930,6 +930,12 @@ class ConnectionVcard:
|
||||||
if vcard.has_key('PHOTO'):
|
if vcard.has_key('PHOTO'):
|
||||||
if not isinstance(vcard['PHOTO'], dict):
|
if not isinstance(vcard['PHOTO'], dict):
|
||||||
del vcard['PHOTO']
|
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['jid'] = jid
|
||||||
vcard['resource'] = gajim.get_resource_from_jid(fjid)
|
vcard['resource'] = gajim.get_resource_from_jid(fjid)
|
||||||
return vcard
|
return vcard
|
||||||
|
@ -1195,13 +1201,9 @@ class ConnectionVcard:
|
||||||
#('VCARD', {entry1: data, entry2: {entry21: data, ...}, ...})
|
#('VCARD', {entry1: data, entry2: {entry21: data, ...}, ...})
|
||||||
self.dispatch('VCARD', vcard)
|
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):
|
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), }
|
# List of IDs we are waiting answers for {id: (type_of_request, data), }
|
||||||
self.awaiting_answers = {}
|
self.awaiting_answers = {}
|
||||||
# List of IDs that will produce a timeout is answer doesn't arrive
|
# List of IDs that will produce a timeout is answer doesn't arrive
|
||||||
|
@ -1210,43 +1212,9 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
||||||
# keep the jids we auto added (transports contacts) to not send the
|
# keep the jids we auto added (transports contacts) to not send the
|
||||||
# SUBSCRIBED event to gui
|
# SUBSCRIBED event to gui
|
||||||
self.automatically_added = []
|
self.automatically_added = []
|
||||||
# keep the latest subscribed event for each jid to prevent loop when we
|
|
||||||
# acknoledge presences
|
|
||||||
self.subscribed_events = {}
|
|
||||||
# IDs of jabber:iq:last requests
|
|
||||||
self.last_ids = []
|
|
||||||
# IDs of jabber:iq:version requests
|
|
||||||
self.version_ids = []
|
|
||||||
# ID of urn:xmpp:ping requests
|
|
||||||
self.awaiting_xmpp_ping_id = None
|
|
||||||
|
|
||||||
# keep track of sessions this connection has with other JIDs
|
# keep track of sessions this connection has with other JIDs
|
||||||
self.sessions = {}
|
self.sessions = {}
|
||||||
try:
|
|
||||||
idle.init()
|
|
||||||
except:
|
|
||||||
HAS_IDLE = False
|
|
||||||
|
|
||||||
def build_http_auth_answer(self, iq_obj, answer):
|
|
||||||
if answer == 'yes':
|
|
||||||
self.connection.send(iq_obj.buildReply('result'))
|
|
||||||
elif answer == 'no':
|
|
||||||
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')
|
|
||||||
if opt in ('yes', 'no'):
|
|
||||||
self.build_http_auth_answer(iq_obj, opt)
|
|
||||||
else:
|
|
||||||
id = iq_obj.getTagAttr('confirm', 'id')
|
|
||||||
method = iq_obj.getTagAttr('confirm', 'method')
|
|
||||||
url = iq_obj.getTagAttr('confirm', 'url')
|
|
||||||
msg = iq_obj.getTagData('body') # In case it's a message with a body
|
|
||||||
self.dispatch('HTTP_AUTH', (method, url, id, iq_obj, msg));
|
|
||||||
raise common.xmpp.NodeProcessed
|
|
||||||
|
|
||||||
def _FeatureNegCB(self, con, stanza, session):
|
def _FeatureNegCB(self, con, stanza, session):
|
||||||
gajim.log.debug('FeatureNegCB')
|
gajim.log.debug('FeatureNegCB')
|
||||||
|
@ -1275,6 +1243,133 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
||||||
|
|
||||||
raise common.xmpp.NodeProcessed
|
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
|
||||||
|
# acknowledge presences
|
||||||
|
self.subscribed_events = {}
|
||||||
|
# IDs of jabber:iq:last requests
|
||||||
|
self.last_ids = []
|
||||||
|
# IDs of jabber:iq:version requests
|
||||||
|
self.version_ids = []
|
||||||
|
# ID of urn:xmpp:ping requests
|
||||||
|
self.awaiting_xmpp_ping_id = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
idle.init()
|
||||||
|
except:
|
||||||
|
HAS_IDLE = False
|
||||||
|
|
||||||
|
def build_http_auth_answer(self, iq_obj, answer):
|
||||||
|
if answer == 'yes':
|
||||||
|
self.connection.send(iq_obj.buildReply('result'))
|
||||||
|
elif answer == 'no':
|
||||||
|
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')
|
||||||
|
if opt in ('yes', 'no'):
|
||||||
|
self.build_http_auth_answer(iq_obj, opt)
|
||||||
|
else:
|
||||||
|
id = iq_obj.getTagAttr('confirm', 'id')
|
||||||
|
method = iq_obj.getTagAttr('confirm', 'method')
|
||||||
|
url = iq_obj.getTagAttr('confirm', 'url')
|
||||||
|
msg = iq_obj.getTagData('body') # In case it's a message with a body
|
||||||
|
self.dispatch('HTTP_AUTH', (method, url, id, iq_obj, msg));
|
||||||
|
raise common.xmpp.NodeProcessed
|
||||||
|
|
||||||
def _ErrorCB(self, con, iq_obj):
|
def _ErrorCB(self, con, iq_obj):
|
||||||
gajim.log.debug('ErrorCB')
|
gajim.log.debug('ErrorCB')
|
||||||
jid_from = helpers.get_full_jid_from_iq(iq_obj)
|
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,
|
self.dispatch('GC_INVITATION',(frm, jid_from, reason, password,
|
||||||
is_continued))
|
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):
|
def _pubsubEventCB(self, con, msg):
|
||||||
''' Called when we receive <message/> with pubsub event. '''
|
''' Called when we receive <message/> with pubsub event. '''
|
||||||
# TODO: Logging? (actually services where logging would be useful, should
|
# TODO: Logging? (actually services where logging would be useful, should
|
||||||
|
|
|
@ -35,6 +35,7 @@ import common.xmpp
|
||||||
from common import helpers
|
from common import helpers
|
||||||
from common import gajim
|
from common import gajim
|
||||||
from common.zeroconf import zeroconf
|
from common.zeroconf import zeroconf
|
||||||
|
|
||||||
STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
|
STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
|
||||||
'invisible']
|
'invisible']
|
||||||
# kind of events we can wait for an answer
|
# kind of events we can wait for an answer
|
||||||
|
@ -48,173 +49,23 @@ except:
|
||||||
gajim.log.debug(_('Unable to load idle module'))
|
gajim.log.debug(_('Unable to load idle module'))
|
||||||
HAS_IDLE = False
|
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):
|
def add_sha(self, p, send_caps = True):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def add_caps(self, p):
|
def add_caps(self, p):
|
||||||
pass
|
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):
|
def request_vcard(self, jid = None, is_fake_jid = False):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def send_vcard(self, vcard):
|
def send_vcard(self, vcard):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class ConnectionBytestream:
|
class ConnectionBytestream(connection_handlers.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'])
|
|
||||||
|
|
||||||
def send_socks5_info(self, file_props, fast = True, receiver = None,
|
def send_socks5_info(self, file_props, fast = True, receiver = None,
|
||||||
sender = None):
|
sender = None):
|
||||||
''' send iq for the present streamhosts and proxies '''
|
''' send iq for the present streamhosts and proxies '''
|
||||||
|
@ -274,43 +125,6 @@ class ConnectionBytestream:
|
||||||
streamhost.setAttr('jid', sender)
|
streamhost.setAttr('jid', sender)
|
||||||
self.connection.send(iq)
|
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):
|
def send_file_request(self, file_props):
|
||||||
''' send iq for new FT request '''
|
''' send iq for new FT request '''
|
||||||
if not self.connection or self.connected < 2:
|
if not self.connection or self.connected < 2:
|
||||||
|
@ -344,69 +158,6 @@ class ConnectionBytestream:
|
||||||
field.addOption(common.xmpp.NS_BYTESTREAM)
|
field.addOption(common.xmpp.NS_BYTESTREAM)
|
||||||
self.connection.send(iq)
|
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):
|
def _bytestreamSetCB(self, con, iq_obj):
|
||||||
gajim.log.debug('_bytestreamSetCB')
|
gajim.log.debug('_bytestreamSetCB')
|
||||||
target = unicode(iq_obj.getAttr('to'))
|
target = unicode(iq_obj.getAttr('to'))
|
||||||
|
@ -623,20 +374,12 @@ class ConnectionBytestream:
|
||||||
self.dispatch('FILE_REQUEST_ERROR', (jid, file_props, ''))
|
self.dispatch('FILE_REQUEST_ERROR', (jid, file_props, ''))
|
||||||
raise common.xmpp.NodeProcessed
|
raise common.xmpp.NodeProcessed
|
||||||
|
|
||||||
class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream):
|
class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream, connection_handlers.ConnectionHandlersBase):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
ConnectionVcard.__init__(self)
|
ConnectionVcard.__init__(self)
|
||||||
ConnectionBytestream.__init__(self)
|
ConnectionBytestream.__init__(self)
|
||||||
# List of IDs we are waiting answers for {id: (type_of_request, data), }
|
connection_handlers.ConnectionHandlersBase.__init__(self)
|
||||||
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 = {}
|
|
||||||
try:
|
try:
|
||||||
idle.init()
|
idle.init()
|
||||||
except:
|
except:
|
||||||
|
@ -644,21 +387,24 @@ class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream):
|
||||||
|
|
||||||
def _messageCB(self, ip, con, msg):
|
def _messageCB(self, ip, con, msg):
|
||||||
'''Called when we receive a message'''
|
'''Called when we receive a message'''
|
||||||
|
|
||||||
|
gajim.log.debug('Zeroconf MessageCB')
|
||||||
|
|
||||||
|
frm = msg.getFrom()
|
||||||
mtype = msg.getType()
|
mtype = msg.getType()
|
||||||
thread_id = msg.getThread()
|
thread_id = msg.getThread()
|
||||||
tim = msg.getTimestamp()
|
|
||||||
tim = helpers.datetime_tuple(tim)
|
if not mtype:
|
||||||
tim = time.localtime(timegm(tim))
|
mtype = 'normal'
|
||||||
frm = msg.getFrom()
|
|
||||||
|
|
||||||
if frm == None:
|
if frm == None:
|
||||||
for key in self.connection.zeroconf.contacts:
|
for key in self.connection.zeroconf.contacts:
|
||||||
if ip == self.connection.zeroconf.contacts[key][zeroconf.C_ADDRESS]:
|
if ip == self.connection.zeroconf.contacts[key][zeroconf.C_ADDRESS]:
|
||||||
frm = key
|
frm = key
|
||||||
frm = unicode(frm)
|
|
||||||
jid = frm
|
|
||||||
|
|
||||||
session = self.get_or_create_session(frm, thread_id, mtype)
|
frm = unicode(frm)
|
||||||
|
|
||||||
|
session = self.get_or_create_session(frm, thread_id)
|
||||||
|
|
||||||
if thread_id and not session.received_thread_id:
|
if thread_id and not session.received_thread_id:
|
||||||
session.received_thread_id = True
|
session.received_thread_id = True
|
||||||
|
@ -668,17 +414,17 @@ class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream):
|
||||||
if gajim.HAVE_PYCRYPTO:
|
if gajim.HAVE_PYCRYPTO:
|
||||||
self._FeatureNegCB(con, msg, session)
|
self._FeatureNegCB(con, msg, session)
|
||||||
return
|
return
|
||||||
|
|
||||||
if msg.getTag('init') and msg.getTag('init').namespace == \
|
if msg.getTag('init') and msg.getTag('init').namespace == \
|
||||||
common.xmpp.NS_ESESSION_INIT:
|
common.xmpp.NS_ESESSION_INIT:
|
||||||
self._InitE2ECB(con, msg, session)
|
self._InitE2ECB(con, msg, session)
|
||||||
|
|
||||||
no_log_for = gajim.config.get_per('accounts', self.name,
|
|
||||||
'no_log_for').split()
|
|
||||||
encrypted = False
|
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 msg.getTag('c', namespace = common.xmpp.NS_STANZA_CRYPTO):
|
||||||
if e2e_tag:
|
|
||||||
encrypted = True
|
encrypted = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -687,43 +433,16 @@ class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream):
|
||||||
self.dispatch('FAILED_DECRYPT', (frm, tim))
|
self.dispatch('FAILED_DECRYPT', (frm, tim))
|
||||||
|
|
||||||
msgtxt = msg.getBody()
|
msgtxt = msg.getBody()
|
||||||
msghtml = msg.getXHTML()
|
|
||||||
subject = msg.getSubject() # if not there, it's None
|
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
|
# invitations
|
||||||
invite = None
|
invite = None
|
||||||
|
encTag = msg.getTag('x', namespace = common.xmpp.NS_ENCRYPTED)
|
||||||
|
|
||||||
if not encTag:
|
if not encTag:
|
||||||
invite = msg.getTag('x', namespace = common.xmpp.NS_MUC_USER)
|
invite = msg.getTag('x', namespace = common.xmpp.NS_MUC_USER)
|
||||||
if invite and not invite.getTag('invite'):
|
if invite and not invite.getTag('invite'):
|
||||||
invite = None
|
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:
|
if encTag and self.USE_GPG:
|
||||||
#decrypt
|
#decrypt
|
||||||
|
@ -733,210 +452,22 @@ class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream):
|
||||||
if keyID:
|
if keyID:
|
||||||
decmsg = self.gpg.decrypt(encmsg, keyID)
|
decmsg = self.gpg.decrypt(encmsg, keyID)
|
||||||
# \x00 chars are not allowed in C (so in GTK)
|
# \x00 chars are not allowed in C (so in GTK)
|
||||||
decmsg = decmsg.replace('\x00', '')
|
msgtxt = decmsg.replace('\x00', '')
|
||||||
if decmsg:
|
encrypted = True
|
||||||
msgtxt = decmsg
|
|
||||||
encrypted = True
|
|
||||||
if mtype == 'error':
|
if mtype == 'error':
|
||||||
error_msg = msg.getError()
|
self.dispatch_error_msg(msg, msgtxt, session, frm, tim, subject)
|
||||||
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:
|
else:
|
||||||
reply = stanza.buildReply()
|
# XXX this shouldn't be hardcoded
|
||||||
reply.setType('error')
|
if isinstance(session, ChatControlSession):
|
||||||
|
session.received(frm, msgtxt, tim, encrypted, subject, msg)
|
||||||
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
|
|
||||||
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)
|
|
||||||
else:
|
else:
|
||||||
return self.sessions[jid][thread_id]
|
session.received(msg)
|
||||||
except KeyError:
|
# END messageCB
|
||||||
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)
|
|
||||||
|
|
||||||
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):
|
def store_metacontacts(self, tags):
|
||||||
''' fake empty method '''
|
''' fake empty method '''
|
||||||
# serverside metacontacts are not supported with zeroconf
|
# serverside metacontacts are not supported with zeroconf
|
||||||
# (there is no server)
|
# (there is no server)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,7 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
|
||||||
return self.call_resolve_timeout
|
return self.call_resolve_timeout
|
||||||
|
|
||||||
# callbacks called from zeroconf
|
# callbacks called from zeroconf
|
||||||
def _on_new_service(self,jid):
|
def _on_new_service(self, jid):
|
||||||
self.roster.setItem(jid)
|
self.roster.setItem(jid)
|
||||||
self.dispatch('ROSTER_INFO', (jid, self.roster.getName(jid), 'both', 'no', self.roster.getGroups(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))
|
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='',
|
def send_message(self, jid, msg, keyID, type = 'chat', subject='',
|
||||||
chatstate = None, msg_id = None, composing_xep = None, resource = None,
|
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
|
fjid = jid
|
||||||
|
|
||||||
if not self.connection:
|
if not self.connection:
|
||||||
|
@ -454,13 +454,13 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
|
||||||
|
|
||||||
def on_send_not_ok(reason):
|
def on_send_not_ok(reason):
|
||||||
reason += ' ' + _('Your message could not be sent.')
|
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,
|
ret = self.connection.send(msg_iq, msg != None, on_ok=on_send_ok,
|
||||||
on_not_ok=on_send_not_ok)
|
on_not_ok=on_send_not_ok)
|
||||||
if ret == -1:
|
if ret == -1:
|
||||||
# Contact Offline
|
# 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):
|
def send_stanza(self, stanza):
|
||||||
# send a stanza untouched
|
# send a stanza untouched
|
||||||
|
|
Loading…
Reference in New Issue