add XEP-313 (MAM) support
This commit is contained in:
parent
e8277c0521
commit
0a8af73650
|
@ -3006,7 +3006,7 @@ class ChatControl(ChatControlBase):
|
||||||
and gajim.HAVE_PYCRYPTO and self.contact.supports(NS_ESESSION):
|
and gajim.HAVE_PYCRYPTO and self.contact.supports(NS_ESESSION):
|
||||||
self.begin_e2e_negotiation()
|
self.begin_e2e_negotiation()
|
||||||
elif (not self.session or not self.session.status) and \
|
elif (not self.session or not self.session.status) and \
|
||||||
gajim.connections[self.account].archiving_supported:
|
gajim.connections[self.account].archiving_136_supported:
|
||||||
self.begin_archiving_negotiation()
|
self.begin_archiving_negotiation()
|
||||||
else:
|
else:
|
||||||
self.send_chatstate('active', self.contact)
|
self.send_chatstate('active', self.contact)
|
||||||
|
|
|
@ -316,6 +316,7 @@ class Config:
|
||||||
'ignore_incoming_attention': [opt_bool, False, _('If True, Gajim will ignore incoming attention requestd ("wizz").')],
|
'ignore_incoming_attention': [opt_bool, False, _('If True, Gajim will ignore incoming attention requestd ("wizz").')],
|
||||||
'remember_opened_chat_controls': [ opt_bool, True, _('If enabled, Gajim will reopen chat windows that were opened last time Gajim was closed.')],
|
'remember_opened_chat_controls': [ opt_bool, True, _('If enabled, Gajim will reopen chat windows that were opened last time Gajim was closed.')],
|
||||||
'positive_184_ack': [ opt_bool, False, _('If enabled, Gajim will show an icon to show that sent message has been received by your contact')],
|
'positive_184_ack': [ opt_bool, False, _('If enabled, Gajim will show an icon to show that sent message has been received by your contact')],
|
||||||
|
'last_mam_id': [opt_str, '', _('Last MAM id we are syncronized with')],
|
||||||
}, {})
|
}, {})
|
||||||
|
|
||||||
__options_per_key = {
|
__options_per_key = {
|
||||||
|
|
|
@ -423,6 +423,8 @@ class CommonConnection:
|
||||||
msg_iq.setTag(nbxmpp.NS_ENCRYPTED + ' x').setData(msgenc)
|
msg_iq.setTag(nbxmpp.NS_ENCRYPTED + ' x').setData(msgenc)
|
||||||
if self.carbons_enabled:
|
if self.carbons_enabled:
|
||||||
msg_iq.addChild(name='private', namespace=nbxmpp.NS_CARBONS)
|
msg_iq.addChild(name='private', namespace=nbxmpp.NS_CARBONS)
|
||||||
|
msg_iq.addChild(name='no-permanent-storage',
|
||||||
|
namespace=nbxmpp.NS_MSG_HINTS)
|
||||||
|
|
||||||
if form_node:
|
if form_node:
|
||||||
msg_iq.addChild(node=form_node)
|
msg_iq.addChild(node=form_node)
|
||||||
|
@ -501,6 +503,10 @@ class CommonConnection:
|
||||||
if self.carbons_enabled:
|
if self.carbons_enabled:
|
||||||
msg_iq.addChild(name='private',
|
msg_iq.addChild(name='private',
|
||||||
namespace=nbxmpp.NS_CARBONS)
|
namespace=nbxmpp.NS_CARBONS)
|
||||||
|
msg_iq.addChild(name='no-permanent-storage',
|
||||||
|
namespace=nbxmpp.NS_MSG_HINTS)
|
||||||
|
msg_iq.addChild(name='no-copy',
|
||||||
|
namespace=nbxmpp.NS_MSG_HINTS)
|
||||||
|
|
||||||
if callback:
|
if callback:
|
||||||
callback(jid, msg, keyID, forward_from, session, original_message,
|
callback(jid, msg, keyID, forward_from, session, original_message,
|
||||||
|
@ -1977,8 +1983,12 @@ class Connection(CommonConnection, ConnectionHandlers):
|
||||||
# Remove stored bookmarks accessible to everyone.
|
# Remove stored bookmarks accessible to everyone.
|
||||||
self.send_pb_purge(our_jid, 'storage:bookmarks')
|
self.send_pb_purge(our_jid, 'storage:bookmarks')
|
||||||
self.send_pb_delete(our_jid, 'storage:bookmarks')
|
self.send_pb_delete(our_jid, 'storage:bookmarks')
|
||||||
|
if nbxmpp.NS_MAM in obj.features:
|
||||||
|
self.archiving_supported = True
|
||||||
|
self.archiving_313_supported = True
|
||||||
if nbxmpp.NS_ARCHIVE in obj.features:
|
if nbxmpp.NS_ARCHIVE in obj.features:
|
||||||
self.archiving_supported = True
|
self.archiving_supported = True
|
||||||
|
self.archiving_136_supported = True
|
||||||
if nbxmpp.NS_ARCHIVE_AUTO in obj.features:
|
if nbxmpp.NS_ARCHIVE_AUTO in obj.features:
|
||||||
self.archive_auto_supported = True
|
self.archive_auto_supported = True
|
||||||
if nbxmpp.NS_ARCHIVE_MANAGE in obj.features:
|
if nbxmpp.NS_ARCHIVE_MANAGE in obj.features:
|
||||||
|
|
|
@ -53,10 +53,8 @@ from common.pubsub import ConnectionPubSub
|
||||||
from common.protocol.caps import ConnectionCaps
|
from common.protocol.caps import ConnectionCaps
|
||||||
from common.protocol.bytestream import ConnectionSocks5Bytestream
|
from common.protocol.bytestream import ConnectionSocks5Bytestream
|
||||||
from common.protocol.bytestream import ConnectionIBBytestream
|
from common.protocol.bytestream import ConnectionIBBytestream
|
||||||
from common.message_archiving import ConnectionArchive
|
from common.message_archiving import ConnectionArchive136
|
||||||
from common.message_archiving import ARCHIVING_COLLECTIONS_ARRIVED
|
from common.message_archiving import ConnectionArchive313
|
||||||
from common.message_archiving import ARCHIVING_COLLECTION_ARRIVED
|
|
||||||
from common.message_archiving import ARCHIVING_MODIFICATIONS_ARRIVED
|
|
||||||
from common.connection_handlers_events import *
|
from common.connection_handlers_events import *
|
||||||
|
|
||||||
from common import ged
|
from common import ged
|
||||||
|
@ -463,6 +461,7 @@ class ConnectionVcard:
|
||||||
|
|
||||||
if id_ not in self.awaiting_answers:
|
if id_ not in self.awaiting_answers:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.awaiting_answers[id_][0] == VCARD_PUBLISHED:
|
if self.awaiting_answers[id_][0] == VCARD_PUBLISHED:
|
||||||
if iq_obj.getType() == 'result':
|
if iq_obj.getType() == 'result':
|
||||||
vcard_iq = self.awaiting_answers[id_][1]
|
vcard_iq = self.awaiting_answers[id_][1]
|
||||||
|
@ -481,6 +480,7 @@ class ConnectionVcard:
|
||||||
if self.vcard_sha != new_sha and gajim.SHOW_LIST[
|
if self.vcard_sha != new_sha and gajim.SHOW_LIST[
|
||||||
self.connected] != 'invisible':
|
self.connected] != 'invisible':
|
||||||
if not self.connection or self.connected < 2:
|
if not self.connection or self.connected < 2:
|
||||||
|
del self.awaiting_answers[id_]
|
||||||
return
|
return
|
||||||
self.vcard_sha = new_sha
|
self.vcard_sha = new_sha
|
||||||
sshow = helpers.get_xmpp_show(gajim.SHOW_LIST[
|
sshow = helpers.get_xmpp_show(gajim.SHOW_LIST[
|
||||||
|
@ -494,6 +494,7 @@ class ConnectionVcard:
|
||||||
elif iq_obj.getType() == 'error':
|
elif iq_obj.getType() == 'error':
|
||||||
gajim.nec.push_incoming_event(VcardNotPublishedEvent(None,
|
gajim.nec.push_incoming_event(VcardNotPublishedEvent(None,
|
||||||
conn=self))
|
conn=self))
|
||||||
|
del self.awaiting_answers[id_]
|
||||||
elif self.awaiting_answers[id_][0] == VCARD_ARRIVED:
|
elif self.awaiting_answers[id_][0] == VCARD_ARRIVED:
|
||||||
# If vcard is empty, we send to the interface an empty vcard so that
|
# If vcard is empty, we send to the interface an empty vcard so that
|
||||||
# it knows it arrived
|
# it knows it arrived
|
||||||
|
@ -516,10 +517,12 @@ class ConnectionVcard:
|
||||||
vcard = {'jid': jid, 'resource': resource}
|
vcard = {'jid': jid, 'resource': resource}
|
||||||
gajim.nec.push_incoming_event(VcardReceivedEvent(None,
|
gajim.nec.push_incoming_event(VcardReceivedEvent(None,
|
||||||
conn=self, vcard_dict=vcard))
|
conn=self, vcard_dict=vcard))
|
||||||
|
del self.awaiting_answers[id_]
|
||||||
elif self.awaiting_answers[id_][0] == AGENT_REMOVED:
|
elif self.awaiting_answers[id_][0] == AGENT_REMOVED:
|
||||||
jid = self.awaiting_answers[id_][1]
|
jid = self.awaiting_answers[id_][1]
|
||||||
gajim.nec.push_incoming_event(AgentRemovedEvent(None, conn=self,
|
gajim.nec.push_incoming_event(AgentRemovedEvent(None, conn=self,
|
||||||
agent=jid))
|
agent=jid))
|
||||||
|
del self.awaiting_answers[id_]
|
||||||
elif self.awaiting_answers[id_][0] == METACONTACTS_ARRIVED:
|
elif self.awaiting_answers[id_][0] == METACONTACTS_ARRIVED:
|
||||||
if not self.connection:
|
if not self.connection:
|
||||||
return
|
return
|
||||||
|
@ -530,7 +533,9 @@ class ConnectionVcard:
|
||||||
if iq_obj.getErrorCode() not in ('403', '406', '404'):
|
if iq_obj.getErrorCode() not in ('403', '406', '404'):
|
||||||
self.private_storage_supported = False
|
self.private_storage_supported = False
|
||||||
self.get_roster_delimiter()
|
self.get_roster_delimiter()
|
||||||
|
del self.awaiting_answers[id_]
|
||||||
elif self.awaiting_answers[id_][0] == DELIMITER_ARRIVED:
|
elif self.awaiting_answers[id_][0] == DELIMITER_ARRIVED:
|
||||||
|
del self.awaiting_answers[id_]
|
||||||
if not self.connection:
|
if not self.connection:
|
||||||
return
|
return
|
||||||
if iq_obj.getType() == 'result':
|
if iq_obj.getType() == 'result':
|
||||||
|
@ -565,7 +570,9 @@ class ConnectionVcard:
|
||||||
gajim.nec.push_incoming_event(RosterReceivedEvent(None,
|
gajim.nec.push_incoming_event(RosterReceivedEvent(None,
|
||||||
conn=self))
|
conn=self))
|
||||||
GLib.timeout_add_seconds(10, self.discover_servers)
|
GLib.timeout_add_seconds(10, self.discover_servers)
|
||||||
|
del self.awaiting_answers[id_]
|
||||||
elif self.awaiting_answers[id_][0] == PRIVACY_ARRIVED:
|
elif self.awaiting_answers[id_][0] == PRIVACY_ARRIVED:
|
||||||
|
del self.awaiting_answers[id_]
|
||||||
if iq_obj.getType() != 'error':
|
if iq_obj.getType() != 'error':
|
||||||
self.privacy_rules_supported = True
|
self.privacy_rules_supported = True
|
||||||
self.get_privacy_list('block')
|
self.get_privacy_list('block')
|
||||||
|
@ -594,6 +601,7 @@ class ConnectionVcard:
|
||||||
# Ask metacontacts before roster
|
# Ask metacontacts before roster
|
||||||
self.get_metacontacts()
|
self.get_metacontacts()
|
||||||
elif self.awaiting_answers[id_][0] == BLOCKING_ARRIVED:
|
elif self.awaiting_answers[id_][0] == BLOCKING_ARRIVED:
|
||||||
|
del self.awaiting_answers[id_]
|
||||||
if iq_obj.getType() == 'result':
|
if iq_obj.getType() == 'result':
|
||||||
list_node = iq_obj.getTag('blocklist')
|
list_node = iq_obj.getTag('blocklist')
|
||||||
if not list_node:
|
if not list_node:
|
||||||
|
@ -602,6 +610,7 @@ class ConnectionVcard:
|
||||||
for i in list_node.iterTags('item'):
|
for i in list_node.iterTags('item'):
|
||||||
self.blocked_contacts.append(i.getAttr('jid'))
|
self.blocked_contacts.append(i.getAttr('jid'))
|
||||||
elif self.awaiting_answers[id_][0] == PEP_CONFIG:
|
elif self.awaiting_answers[id_][0] == PEP_CONFIG:
|
||||||
|
del self.awaiting_answers[id_]
|
||||||
if iq_obj.getType() == 'error':
|
if iq_obj.getType() == 'error':
|
||||||
return
|
return
|
||||||
if not iq_obj.getTag('pubsub'):
|
if not iq_obj.getTag('pubsub'):
|
||||||
|
@ -616,71 +625,6 @@ class ConnectionVcard:
|
||||||
gajim.nec.push_incoming_event(PEPConfigReceivedEvent(None,
|
gajim.nec.push_incoming_event(PEPConfigReceivedEvent(None,
|
||||||
conn=self, node=node, form=form))
|
conn=self, node=node, form=form))
|
||||||
|
|
||||||
elif self.awaiting_answers[id_][0] == ARCHIVING_COLLECTIONS_ARRIVED:
|
|
||||||
# TODO
|
|
||||||
print('ARCHIVING_COLLECTIONS_ARRIVED')
|
|
||||||
|
|
||||||
elif self.awaiting_answers[id_][0] == ARCHIVING_COLLECTION_ARRIVED:
|
|
||||||
def save_if_not_exists(with_, nick, direction, tim, payload):
|
|
||||||
assert len(payload) == 1, 'got several archiving messages in' +\
|
|
||||||
' the same time %s' % ''.join(payload)
|
|
||||||
if payload[0].getName() == 'body':
|
|
||||||
gajim.logger.save_if_not_exists(with_, direction, tim,
|
|
||||||
msg=payload[0].getData(), nick=nick)
|
|
||||||
elif payload[0].getName() == 'message':
|
|
||||||
print('Not implemented')
|
|
||||||
chat = iq_obj.getTag('chat')
|
|
||||||
if chat:
|
|
||||||
with_ = chat.getAttr('with')
|
|
||||||
start_ = chat.getAttr('start')
|
|
||||||
tim = helpers.datetime_tuple(start_)
|
|
||||||
tim = timegm(tim)
|
|
||||||
nb = 0
|
|
||||||
for element in chat.getChildren():
|
|
||||||
try:
|
|
||||||
secs = int(element.getAttr('secs'))
|
|
||||||
except TypeError:
|
|
||||||
secs = 0
|
|
||||||
if secs:
|
|
||||||
tim += secs
|
|
||||||
nick = element.getAttr('name')
|
|
||||||
if element.getName() == 'from':
|
|
||||||
save_if_not_exists(with_, nick, 'from', localtime(tim),
|
|
||||||
element.getPayload())
|
|
||||||
nb += 1
|
|
||||||
if element.getName() == 'to':
|
|
||||||
save_if_not_exists(with_, nick, 'to', localtime(tim),
|
|
||||||
element.getPayload())
|
|
||||||
nb += 1
|
|
||||||
set_ = chat.getTag('set')
|
|
||||||
first = set_.getTag('first')
|
|
||||||
if first:
|
|
||||||
try:
|
|
||||||
index = int(first.getAttr('index'))
|
|
||||||
except TypeError:
|
|
||||||
index = 0
|
|
||||||
try:
|
|
||||||
count = int(set_.getTagData('count'))
|
|
||||||
except TypeError:
|
|
||||||
count = 0
|
|
||||||
if count > index + nb:
|
|
||||||
# Request the next page
|
|
||||||
after = element.getTagData('last')
|
|
||||||
self.request_collection_page(with_, start_, after=after)
|
|
||||||
|
|
||||||
elif self.awaiting_answers[id_][0] == ARCHIVING_MODIFICATIONS_ARRIVED:
|
|
||||||
modified = iq_obj.getTag('modified')
|
|
||||||
if modified:
|
|
||||||
for element in modified.getChildren():
|
|
||||||
if element.getName() == 'changed':
|
|
||||||
with_ = element.getAttr('with')
|
|
||||||
start_ = element.getAttr('start')
|
|
||||||
self.request_collection_page(with_, start_)
|
|
||||||
#elif element.getName() == 'removed':
|
|
||||||
# do nothing
|
|
||||||
|
|
||||||
del self.awaiting_answers[id_]
|
|
||||||
|
|
||||||
def _vCardCB(self, con, vc):
|
def _vCardCB(self, con, vc):
|
||||||
"""
|
"""
|
||||||
Called when we receive a vCard Parse the vCard and send it to plugins
|
Called when we receive a vCard Parse the vCard and send it to plugins
|
||||||
|
@ -1421,13 +1365,14 @@ class ConnectionHandlersBase:
|
||||||
|
|
||||||
return sess
|
return sess
|
||||||
|
|
||||||
class ConnectionHandlers(ConnectionArchive, ConnectionVcard,
|
class ConnectionHandlers(ConnectionArchive136, ConnectionArchive313,
|
||||||
ConnectionSocks5Bytestream, ConnectionDisco, ConnectionCommands,
|
ConnectionVcard, ConnectionSocks5Bytestream, ConnectionDisco,
|
||||||
ConnectionPubSub, ConnectionPEP, ConnectionCaps, ConnectionHandlersBase,
|
ConnectionCommands, ConnectionPubSub, ConnectionPEP, ConnectionCaps,
|
||||||
ConnectionJingle, ConnectionIBBytestream):
|
ConnectionHandlersBase, ConnectionJingle, ConnectionIBBytestream):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
global HAS_IDLE
|
global HAS_IDLE
|
||||||
ConnectionArchive.__init__(self)
|
ConnectionArchive136.__init__(self)
|
||||||
|
ConnectionArchive313.__init__(self)
|
||||||
ConnectionVcard.__init__(self)
|
ConnectionVcard.__init__(self)
|
||||||
ConnectionSocks5Bytestream.__init__(self)
|
ConnectionSocks5Bytestream.__init__(self)
|
||||||
ConnectionIBBytestream.__init__(self)
|
ConnectionIBBytestream.__init__(self)
|
||||||
|
|
|
@ -1088,6 +1088,60 @@ class MessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
|
||||||
return
|
return
|
||||||
self.forwarded = True
|
self.forwarded = True
|
||||||
|
|
||||||
|
result = self.stanza.getTag('result', namespace=nbxmpp.NS_MAM)
|
||||||
|
if result:
|
||||||
|
forwarded = result.getTag('forwarded', namespace=nbxmpp.NS_FORWARD)
|
||||||
|
if not forwarded:
|
||||||
|
return
|
||||||
|
delay = forwarded.getTag('delay', namespace=nbxmpp.NS_DELAY2)
|
||||||
|
if not delay:
|
||||||
|
return
|
||||||
|
tim = delay.getAttr('stamp')
|
||||||
|
tim = helpers.datetime_tuple(tim)
|
||||||
|
tim = localtime(timegm(tim))
|
||||||
|
msg_ = forwarded.getTag('message')
|
||||||
|
to_ = msg_.getAttr('to')
|
||||||
|
if to_:
|
||||||
|
gajim.get_jid_without_resource(to_)
|
||||||
|
else:
|
||||||
|
to_ = gajim.get_jid_from_account(account)
|
||||||
|
frm_ = gajim.get_jid_without_resource(msg_.getAttr('from'))
|
||||||
|
nick = None
|
||||||
|
msg_txt = msg_.getTagData('body')
|
||||||
|
if to_ == gajim.get_jid_from_account(account):
|
||||||
|
with_ = frm_
|
||||||
|
direction = 'from'
|
||||||
|
res = gajim.get_resource_from_jid(msg_.getAttr('from'))
|
||||||
|
else:
|
||||||
|
with_ = to_
|
||||||
|
direction = 'to'
|
||||||
|
res = gajim.get_resource_from_jid(msg_.getAttr('to'))
|
||||||
|
is_pm = gajim.logger.jid_is_room_jid(with_)
|
||||||
|
if msg_.getAttr('type') == 'groupchat':
|
||||||
|
if is_pm == False:
|
||||||
|
log.warn('JID %s is marked as normal contact in database '
|
||||||
|
'but we got a groupchat message from it.')
|
||||||
|
return
|
||||||
|
if is_pm == None:
|
||||||
|
gajim.logger.get_jid_id(with_, 'ROOM')
|
||||||
|
nick = res
|
||||||
|
else:
|
||||||
|
if is_pm == None:
|
||||||
|
# we don't know this JID, we need to disco it.
|
||||||
|
server = gajim.get_server_from_jid(with_)
|
||||||
|
if server not in self.conn.mam_awaiting_disco_result:
|
||||||
|
self.conn.mam_awaiting_disco_result[server] = [
|
||||||
|
[with_, direction, tim, msg_txt, res]]
|
||||||
|
self.conn.discoverInfo(server)
|
||||||
|
else:
|
||||||
|
self.conn.mam_awaiting_disco_result[server].append(
|
||||||
|
[with_, direction, tim, msg_txt, res])
|
||||||
|
return
|
||||||
|
|
||||||
|
gajim.logger.save_if_not_exists(with_, direction, tim,
|
||||||
|
msg=msg_txt, nick=nick)
|
||||||
|
return
|
||||||
|
|
||||||
self.enc_tag = self.stanza.getTag('x', namespace=nbxmpp.NS_ENCRYPTED)
|
self.enc_tag = self.stanza.getTag('x', namespace=nbxmpp.NS_ENCRYPTED)
|
||||||
|
|
||||||
self.invite_tag = None
|
self.invite_tag = None
|
||||||
|
|
|
@ -223,13 +223,17 @@ class Logger:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def jid_is_room_jid(self, jid):
|
def jid_is_room_jid(self, jid):
|
||||||
self.cur.execute('SELECT jid_id FROM jids WHERE jid=? AND type=?',
|
"""
|
||||||
(jid, constants.JID_ROOM_TYPE))
|
Return True if it's a room jid, False if it's not, None if we don't know
|
||||||
|
"""
|
||||||
|
self.cur.execute('SELECT type FROM jids WHERE jid=?', (jid,))
|
||||||
row = self.cur.fetchone()
|
row = self.cur.fetchone()
|
||||||
if row is None:
|
if row is None:
|
||||||
return False
|
return None
|
||||||
else:
|
else:
|
||||||
return True
|
if row[0] == constants.JID_ROOM_TYPE:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def get_jid_id(self, jid, typestr=None):
|
def get_jid_id(self, jid, typestr=None):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -29,9 +29,97 @@ log = logging.getLogger('gajim.c.message_archiving')
|
||||||
ARCHIVING_COLLECTIONS_ARRIVED = 'archiving_collections_arrived'
|
ARCHIVING_COLLECTIONS_ARRIVED = 'archiving_collections_arrived'
|
||||||
ARCHIVING_COLLECTION_ARRIVED = 'archiving_collection_arrived'
|
ARCHIVING_COLLECTION_ARRIVED = 'archiving_collection_arrived'
|
||||||
ARCHIVING_MODIFICATIONS_ARRIVED = 'archiving_modifications_arrived'
|
ARCHIVING_MODIFICATIONS_ARRIVED = 'archiving_modifications_arrived'
|
||||||
|
MAM_RESULTS_ARRIVED = 'mam_results_arrived'
|
||||||
|
|
||||||
class ConnectionArchive:
|
class ConnectionArchive:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionArchive313(ConnectionArchive):
|
||||||
|
def __init__(self):
|
||||||
|
ConnectionArchive.__init__(self)
|
||||||
|
self.archiving_313_supported = False
|
||||||
|
self.mam_awaiting_disco_result = {}
|
||||||
|
gajim.ged.register_event_handler('raw-iq-received', ged.CORE,
|
||||||
|
self._nec_raw_iq_313_received)
|
||||||
|
gajim.ged.register_event_handler('agent-info-error-received', ged.CORE,
|
||||||
|
self._nec_agent_info_error)
|
||||||
|
gajim.ged.register_event_handler('agent-info-received', ged.CORE,
|
||||||
|
self._nec_agent_info)
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
gajim.ged.remove_event_handler('raw-iq-received', ged.CORE,
|
||||||
|
self._nec_raw_iq_313_received)
|
||||||
|
|
||||||
|
def _nec_agent_info_error(self, obj):
|
||||||
|
if obj.jid in self.mam_awaiting_disco_result:
|
||||||
|
log.warn('Unable to discover %s, ignoring those logs', obj.jid)
|
||||||
|
del self.mam_awaiting_disco_result[obj.jid]
|
||||||
|
|
||||||
|
def _nec_agent_info(self, obj):
|
||||||
|
if obj.jid in self.mam_awaiting_disco_result:
|
||||||
|
for identity in obj.identities:
|
||||||
|
if identity['category'] == 'conference':
|
||||||
|
# it's a groupchat
|
||||||
|
for with_, direction, tim, msg_txt, res in \
|
||||||
|
self.mam_awaiting_disco_result[obj.jid]:
|
||||||
|
gajim.logger.get_jid_id(with_, 'ROOM')
|
||||||
|
gajim.logger.save_if_not_exists(with_, direction, tim,
|
||||||
|
msg=msg_txt, nick=res)
|
||||||
|
del self.mam_awaiting_disco_result[obj.jid]
|
||||||
|
return
|
||||||
|
# it's not a groupchat
|
||||||
|
for with_, direction, tim, msg_txt, res in \
|
||||||
|
self.mam_awaiting_disco_result[obj.jid]:
|
||||||
|
gajim.logger.get_jid_id(with_)
|
||||||
|
gajim.logger.save_if_not_exists(with_, direction, tim,
|
||||||
|
msg=msg_txt)
|
||||||
|
del self.mam_awaiting_disco_result[obj.jid]
|
||||||
|
|
||||||
|
def _nec_raw_iq_313_received(self, obj):
|
||||||
|
if obj.conn.name != self.name:
|
||||||
|
return
|
||||||
|
|
||||||
|
id_ = obj.stanza.getID()
|
||||||
|
if id_ not in self.awaiting_answers:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.awaiting_answers[id_][0] == MAM_RESULTS_ARRIVED:
|
||||||
|
query = obj.stanza.getTag('query', namespace=nbxmpp.NS_MAM)
|
||||||
|
if query:
|
||||||
|
set_ = query.getTag('set', namespace=nbxmpp.NS_RSM)
|
||||||
|
if set_:
|
||||||
|
last = set_.getTagData('last')
|
||||||
|
if last:
|
||||||
|
gajim.config.set('last_mam_id', last)
|
||||||
|
self.request_archive(after=last)
|
||||||
|
del self.awaiting_answers[id_]
|
||||||
|
|
||||||
|
def request_archive(self, start=None, end=None, with_=None, after=None,
|
||||||
|
max=30):
|
||||||
|
iq_ = nbxmpp.Iq('get')
|
||||||
|
query = iq_.setTag('query', namespace=nbxmpp.NS_MAM)
|
||||||
|
if start:
|
||||||
|
query.addChild('start', payload=start)
|
||||||
|
if end:
|
||||||
|
query.addChild('end', payload=end)
|
||||||
|
if with_:
|
||||||
|
query.addChild('with', payload=with_)
|
||||||
|
set_ = query.setTag('set', namespace=nbxmpp.NS_RSM)
|
||||||
|
set_.setTagData('max', max)
|
||||||
|
if after:
|
||||||
|
set_.setTagData('after', after)
|
||||||
|
id_ = self.connection.getAnID()
|
||||||
|
iq_.setID(id_)
|
||||||
|
self.awaiting_answers[id_] = (MAM_RESULTS_ARRIVED, )
|
||||||
|
self.connection.send(iq_)
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionArchive136(ConnectionArchive):
|
||||||
|
def __init__(self):
|
||||||
|
ConnectionArchive.__init__(self)
|
||||||
|
self.archiving_136_supported = False
|
||||||
self.archive_auto_supported = False
|
self.archive_auto_supported = False
|
||||||
self.archive_manage_supported = False
|
self.archive_manage_supported = False
|
||||||
self.archive_manual_supported = False
|
self.archive_manual_supported = False
|
||||||
|
@ -45,11 +133,89 @@ class ConnectionArchive:
|
||||||
gajim.ged.register_event_handler(
|
gajim.ged.register_event_handler(
|
||||||
'archiving-preferences-changed-received', ged.CORE,
|
'archiving-preferences-changed-received', ged.CORE,
|
||||||
self._nec_archiving_changed_received)
|
self._nec_archiving_changed_received)
|
||||||
|
gajim.ged.register_event_handler('raw-iq-received', ged.CORE,
|
||||||
|
self._nec_raw_iq_136_received)
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
gajim.ged.remove_event_handler(
|
gajim.ged.remove_event_handler(
|
||||||
'archiving-preferences-changed-received', ged.CORE,
|
'archiving-preferences-changed-received', ged.CORE,
|
||||||
self._nec_archiving_changed_received)
|
self._nec_archiving_changed_received)
|
||||||
|
gajim.ged.remove_event_handler('raw-iq-received', ged.CORE,
|
||||||
|
self._nec_raw_iq_136_received)
|
||||||
|
|
||||||
|
def _nec_raw_iq_136_received(self, obj):
|
||||||
|
if obj.conn.name != self.name:
|
||||||
|
return
|
||||||
|
|
||||||
|
id_ = obj.stanza.getID()
|
||||||
|
if id_ not in self.awaiting_answers:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.awaiting_answers[id_][0] == ARCHIVING_COLLECTIONS_ARRIVED:
|
||||||
|
del self.awaiting_answers[id_]
|
||||||
|
# TODO
|
||||||
|
print('ARCHIVING_COLLECTIONS_ARRIVED')
|
||||||
|
|
||||||
|
elif self.awaiting_answers[id_][0] == ARCHIVING_COLLECTION_ARRIVED:
|
||||||
|
def save_if_not_exists(with_, nick, direction, tim, payload):
|
||||||
|
assert len(payload) == 1, 'got several archiving messages in' +\
|
||||||
|
' the same time %s' % ''.join(payload)
|
||||||
|
if payload[0].getName() == 'body':
|
||||||
|
gajim.logger.save_if_not_exists(with_, direction, tim,
|
||||||
|
msg=payload[0].getData(), nick=nick)
|
||||||
|
elif payload[0].getName() == 'message':
|
||||||
|
print('Not implemented')
|
||||||
|
chat = iq_obj.getTag('chat')
|
||||||
|
if chat:
|
||||||
|
with_ = chat.getAttr('with')
|
||||||
|
start_ = chat.getAttr('start')
|
||||||
|
tim = helpers.datetime_tuple(start_)
|
||||||
|
tim = timegm(tim)
|
||||||
|
nb = 0
|
||||||
|
for element in chat.getChildren():
|
||||||
|
try:
|
||||||
|
secs = int(element.getAttr('secs'))
|
||||||
|
except TypeError:
|
||||||
|
secs = 0
|
||||||
|
if secs:
|
||||||
|
tim += secs
|
||||||
|
nick = element.getAttr('name')
|
||||||
|
if element.getName() == 'from':
|
||||||
|
save_if_not_exists(with_, nick, 'from', localtime(tim),
|
||||||
|
element.getPayload())
|
||||||
|
nb += 1
|
||||||
|
if element.getName() == 'to':
|
||||||
|
save_if_not_exists(with_, nick, 'to', localtime(tim),
|
||||||
|
element.getPayload())
|
||||||
|
nb += 1
|
||||||
|
set_ = chat.getTag('set')
|
||||||
|
first = set_.getTag('first')
|
||||||
|
if first:
|
||||||
|
try:
|
||||||
|
index = int(first.getAttr('index'))
|
||||||
|
except TypeError:
|
||||||
|
index = 0
|
||||||
|
try:
|
||||||
|
count = int(set_.getTagData('count'))
|
||||||
|
except TypeError:
|
||||||
|
count = 0
|
||||||
|
if count > index + nb:
|
||||||
|
# Request the next page
|
||||||
|
after = element.getTagData('last')
|
||||||
|
self.request_collection_page(with_, start_, after=after)
|
||||||
|
del self.awaiting_answers[id_]
|
||||||
|
|
||||||
|
elif self.awaiting_answers[id_][0] == ARCHIVING_MODIFICATIONS_ARRIVED:
|
||||||
|
modified = iq_obj.getTag('modified')
|
||||||
|
if modified:
|
||||||
|
for element in modified.getChildren():
|
||||||
|
if element.getName() == 'changed':
|
||||||
|
with_ = element.getAttr('with')
|
||||||
|
start_ = element.getAttr('start')
|
||||||
|
self.request_collection_page(with_, start_)
|
||||||
|
#elif element.getName() == 'removed':
|
||||||
|
# do nothing
|
||||||
|
del self.awaiting_answers[id_]
|
||||||
|
|
||||||
def request_message_archiving_preferences(self):
|
def request_message_archiving_preferences(self):
|
||||||
iq_ = nbxmpp.Iq('get')
|
iq_ = nbxmpp.Iq('get')
|
||||||
|
|
|
@ -1134,12 +1134,18 @@ class Interface:
|
||||||
# Else disable autoaway
|
# Else disable autoaway
|
||||||
gajim.sleeper_state[account] = 'off'
|
gajim.sleeper_state[account] = 'off'
|
||||||
|
|
||||||
if obj.conn.archiving_supported:
|
if obj.conn.archiving_136_supported:
|
||||||
# Start merging logs from server
|
# Start merging logs from server
|
||||||
obj.conn.request_modifications_page(gajim.config.get_per('accounts',
|
obj.conn.request_modifications_page(gajim.config.get_per('accounts',
|
||||||
account, 'last_archiving_time'))
|
account, 'last_archiving_time'))
|
||||||
gajim.config.set_per('accounts', account, 'last_archiving_time',
|
gajim.config.set_per('accounts', account, 'last_archiving_time',
|
||||||
time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()))
|
time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()))
|
||||||
|
if obj.conn.archiving_313_supported:
|
||||||
|
mam_id = gajim.config.get('last_mam_id')
|
||||||
|
if mam_id:
|
||||||
|
obj.conn.request_archive(after=mam_id)
|
||||||
|
else:
|
||||||
|
obj.conn.request_archive(start='2013-02-24T03:51:42Z')
|
||||||
|
|
||||||
invisible_show = gajim.SHOW_LIST.index('invisible')
|
invisible_show = gajim.SHOW_LIST.index('invisible')
|
||||||
# We cannot join rooms if we are invisible
|
# We cannot join rooms if we are invisible
|
||||||
|
|
Loading…
Reference in New Issue