Philipp Hörist pushed to branch master at gajim / gajim
Commits: d6178669 by Philipp Hörist at 2019-07-21T14:30:14Z MUC: Use SyncThreshold for MUC history
Before SyncThreshold was only used for MAM history. Now its also used for MUC history.
- - - - - e97a6317 by Philipp Hörist at 2019-07-21T17:38:15Z XMLConsole: Add jabber:client namespace to templates
Without the namespace all child elements get a undeclared namespace
- - - - - dc282f22 by Philipp Hörist at 2019-07-21T18:02:05Z Refactor save_archive_id
Move the code out of the MAM module as we need it also for MUC history now
- - - - -
9 changed files:
- gajim/common/config.py - gajim/common/logger.py - gajim/common/modules/mam.py - gajim/common/modules/message.py - gajim/common/modules/muc.py - gajim/common/structs.py - gajim/groupchat_control.py - gajim/gtk/xml_console.py - gajim/session.py
Changes:
===================================== gajim/common/config.py ===================================== @@ -170,8 +170,6 @@ class Config: 'change_roster_title': [opt_bool, True, _('If enabled, Gajim will add * and [n] in contact list window title.')], 'restore_lines': [opt_int, 10, _('Number of messages from chat history to be restored when a chat tab/window is reopened.')], 'restore_timeout': [opt_int, -1, _('How far back in time (minutes) chat history is restored. -1 means no limit.')], - 'muc_restore_lines': [opt_int, 100, _('How many lines to request from server when entering a group chat. -1 means no limit.')], - 'muc_restore_timeout': [opt_int, -1, _('Minutes of backlog to request when entering a group chat. -1 means no limit.')], 'muc_autorejoin_timeout': [opt_int, 1, _('How many seconds to wait before trying to automatically rejoin a group chat you were disconnected from. Set to 0 to disable automatic rejoining.')], 'muc_autorejoin_on_kick': [opt_bool, False, _('Should automatic rejoin be activated when you were kicked from a group chat?')], 'send_on_ctrl_enter': [opt_bool, False, _('Send message on Ctrl+Enter and make a new line with Enter.')], @@ -429,8 +427,6 @@ class Config: }, {}), 'rooms': ({ 'speller_language': [opt_str, '', _('Language used for spell checking.')], - 'muc_restore_lines': [opt_int, -2, _('How many lines to request from server when entering a group chat. -1 means no limit, -2 means global value.')], - 'muc_restore_timeout': [opt_int, -2, _('Minutes of backlog to request when entering a group chat. -1 means no limit, -2 means global value.')], 'notify_on_all_messages': [opt_bool, False, _('If enabled, a notification is created for every message in this group chat.')], 'print_status': [opt_bool, False, _('Show a status message for all status changes (away, dnd, etc.) of users in a group chat.')], 'print_join_left': [opt_bool, False, _('Show a status message for every join or leave in a group chat.')],
===================================== gajim/common/logger.py ===================================== @@ -103,10 +103,7 @@ CACHE_SQL_STATEMENT = ''' hash_method TEXT, hash TEXT, data TEXT, - last_seen INTEGER); - CREATE TABLE rooms_last_message_time( - jid_id INTEGER PRIMARY KEY UNIQUE, - time INTEGER + last_seen INTEGER ); CREATE TABLE roster_entry( account_jid_id INTEGER, @@ -962,45 +959,6 @@ class Logger: return self._con.execute( sql, tuple(jids) + (start, end)).fetchone()
- def get_room_last_message_time(self, account, jid): - """ - Get the timestamp of the last message we received in a room. - - :param account: The account - - :param jid: The jid for which we request the last timestamp - - returns a timestamp or None - """ - sql = ''' - SELECT time FROM rooms_last_message_time - NATURAL JOIN jids WHERE jid = ? - ''' - - row = self._con.execute(sql, (jid,)).fetchone() - if not row: - return self.get_last_date_that_has_logs(account, jid) - return row.time - - def set_room_last_message_time(self, jid, timestamp): - """ - Set the timestamp of the last message we received in a room. - - :param jid: The jid - - :param timestamp: The timestamp in epoch - - """ - - jid_id = self.get_jid_id(jid, type_=JIDConstant.ROOM_TYPE) - sql = '''REPLACE INTO rooms_last_message_time - VALUES (:jid_id, COALESCE( - (SELECT time FROM rooms_last_message_time - WHERE jid_id = :jid_id AND time >= :time), :time))''' - - self._con.execute(sql, {"jid_id": jid_id, "time": timestamp}) - self._timeout_commit() - def save_transport_type(self, jid, type_): """ Save the type of the transport in DB @@ -1497,6 +1455,10 @@ class Logger: kwargs.get('sync_threshold', None) )) else: + for key, value in list(kwargs.items()): + if value is None: + del kwargs[key] + args = ' = ?, '.join(kwargs.keys()) + ' = ?' sql = '''UPDATE last_archive_message SET {} WHERE jid_id = ?'''.format(args)
===================================== gajim/common/modules/mam.py ===================================== @@ -73,6 +73,9 @@ class MAM(BaseModule): self._mam_query_ids.clear() self._catch_up_finished.clear()
+ def is_catch_up_finished(self, jid): + return jid in self._catch_up_finished + def _from_valid_archive(self, _stanza, properties): if properties.type.is_groupchat: expected_archive = properties.jid @@ -531,20 +534,6 @@ class MAM(BaseModule): query.setAttr('queryid', query_id) return iq
- def save_archive_id(self, jid, stanza_id, timestamp): - if jid is None: - jid = self._con.get_own_jid().getStripped() - if jid not in self._catch_up_finished: - return - self._log.info('Save: %s: %s, %s', jid, stanza_id, timestamp) - if stanza_id is None: - # mam:1 - app.logger.set_archive_infos(jid, last_muc_timestamp=timestamp) - else: - # mam:2 - app.logger.set_archive_infos( - jid, last_mam_id=stanza_id, last_muc_timestamp=timestamp) - def request_mam_preferences(self): self._log.info('Request MAM preferences') iq = nbxmpp.Iq('get', self.archiving_namespace)
===================================== gajim/common/modules/message.py ===================================== @@ -26,6 +26,7 @@ from gajim.common.i18n import _ from gajim.common.nec import NetworkIncomingEvent from gajim.common.nec import NetworkEvent from gajim.common.helpers import AdditionalDataDict +from gajim.common.caps_cache import muc_caps_cache from gajim.common.const import KindConstant from gajim.common.modules.base import BaseModule from gajim.common.modules.util import get_eme_message @@ -251,7 +252,6 @@ class Message(BaseModule): event.nickname = event.resource event.xhtml_msgtxt = event.xhtml event.nick = event.resource or '' - app.nec.push_incoming_event(NetworkEvent('gc-message-received', **vars(event))) # TODO: Some plugins modify msgtxt in the GUI event @@ -292,9 +292,16 @@ class Message(BaseModule): additional_data=event.additional_data, stanza_id=event.stanza_id, message_id=event.message_id) - app.logger.set_room_last_message_time(event.room_jid, event.timestamp) - self._con.get_module('MAM').save_archive_id( - event.room_jid, event.stanza_id, event.timestamp) + + if muc_caps_cache.has_mam(event.room_jid): + finished = self._con.get_module('MAM').is_catchup_finished( + event.room_jid) + if not finished: + return + + app.logger.set_archive_infos(event.room_jid, + last_mam_id=event.stanza_id, + last_muc_timestamp=event.timestamp)
def _check_for_mam_compliance(self, room_jid, stanza_id): namespace = caps_cache.muc_caps_cache.get_mam_namespace(room_jid)
===================================== gajim/common/modules/muc.py ===================================== @@ -17,6 +17,8 @@
import time import logging +from datetime import datetime +from datetime import timedelta from functools import partial
import nbxmpp @@ -30,9 +32,11 @@ from gajim.common import app from gajim.common import helpers from gajim.common.const import KindConstant from gajim.common.const import MUCJoinedState +from gajim.common.const import SyncThreshold from gajim.common.structs import MUCData from gajim.common.helpers import AdditionalDataDict from gajim.common.helpers import get_default_muc_config +from gajim.common.helpers import get_sync_threshold from gajim.common import idle from gajim.common.caps_cache import muc_caps_cache from gajim.common.nec import NetworkEvent @@ -130,11 +134,11 @@ class MUC(BaseModule): def get_mucs_with_state(self, states): return [muc for muc in self._muc_data.values() if muc.state in states]
- def join(self, room_jid, nick, password, rejoin=False, config=None): + def join(self, room_jid, nick, password, config=None): if not app.account_is_connected(self._account): return
- muc_data = MUCData(room_jid, nick, password, rejoin, config) + muc_data = MUCData(room_jid, nick, password, config) self._muc_data[room_jid] = muc_data
self._con.get_module('Discovery').disco_muc( @@ -149,7 +153,7 @@ class MUC(BaseModule): status=self._con.status)
muc_x = presence.setTag(nbxmpp.NS_MUC + ' x') - self._add_history_query(muc_x, str(muc_data.jid), muc_data.rejoin) + self._add_history_query(muc_x, str(muc_data.jid))
if muc_data.password is not None: muc_x.setTagData('password', muc_data.password) @@ -281,37 +285,27 @@ class MUC(BaseModule): show=show, status=self._con.status)
- def _add_history_query(self, muc_x, room_jid, rejoin): - last_date = app.logger.get_room_last_message_time( - self._account, room_jid) - if not last_date: - last_date = 0 - + def _add_history_query(self, muc_x, room_jid): if muc_caps_cache.has_mam(room_jid): # The room is MAM capable dont get MUC History muc_x.setTag('history', {'maxchars': '0'}) else: # Request MUC History (not MAM) - tags = {} - timeout = app.config.get_per('rooms', room_jid, - 'muc_restore_timeout') - if timeout is None or timeout == -2: - timeout = app.config.get('muc_restore_timeout') - if last_date == 0 and timeout >= 0: - last_date = time.time() - timeout * 60 - elif not rejoin and timeout >= 0: - last_date = max(last_date, time.time() - timeout * 60) - last_date = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime( - last_date)) - tags['since'] = last_date - - nb = app.config.get_per('rooms', room_jid, 'muc_restore_lines') - if nb is None or nb == -2: - nb = app.config.get('muc_restore_lines') - if nb >= 0: - tags['maxstanzas'] = nb - if tags: - muc_x.setTag('history', tags) + archive = app.logger.get_archive_infos(room_jid) + threshold = get_sync_threshold(room_jid, archive) + + since_epoch = 0 + if archive is not None and archive.last_muc_timestamp is not None: + since_epoch = float(archive.last_muc_timestamp) + + since_date = datetime.utcfromtimestamp(since_epoch) + if threshold != SyncThreshold.NO_THRESHOLD: + threshold_date = datetime.utcnow() - timedelta(days=threshold) + since_date = max(threshold_date, since_date) + + date_string = since_date.strftime('%Y-%m-%dT%H:%M:%SZ') + muc_x.setTag('history', {'since': date_string}) + self._log.info('Threshold for %s: %s', room_jid, threshold)
def _on_muc_presence(self, _con, _stanza, properties): muc_data = self._get_muc_data(properties.muc_jid)
===================================== gajim/common/structs.py ===================================== @@ -26,11 +26,10 @@ CapsIdentity = namedtuple('CapsIdentity', 'category type name lang')
class MUCData: - def __init__(self, room_jid, nick, password, rejoin, config=None): + def __init__(self, room_jid, nick, password, config=None): self._room_jid = JID(room_jid) self._nick = nick self._password = password - self._rejoin = rejoin self._config = config self._state = MUCJoinedState.NOT_JOINED
@@ -64,14 +63,6 @@ class MUCData: def state(self, value): self._state = value
- @property - def rejoin(self): - return self._rejoin - - @rejoin.setter - def rejoin(self, value): - self._rejoin = value - @property def config(self): return self._config
===================================== gajim/groupchat_control.py ===================================== @@ -511,10 +511,6 @@ class GroupchatControl(ChatControlBase): vcard_support and contact.affiliation.is_owner)
- # Sync Threshold - has_mam = muc_caps_cache.has_mam(self.room_jid) - self._get_action('choose-sync-').set_enabled(has_mam) - # Print join/left join_default = app.config.get('print_join_left_default') value = app.config.get_per('rooms', self.contact.jid, @@ -1414,8 +1410,7 @@ class GroupchatControl(ChatControlBase): if obj.conn.name != self.account: return password = app.gc_passwords.get(self.room_jid, '') - obj.conn.get_module('MUC').join(self.room_jid, self.nick, password, - rejoin=True) + obj.conn.get_module('MUC').join(self.room_jid, self.nick, password)
def _nec_decrypted_message_received(self, obj): if obj.conn.name != self.account: @@ -1552,7 +1547,7 @@ class GroupchatControl(ChatControlBase): return False password = app.gc_passwords.get(self.room_jid, '') app.connections[self.account].get_module('MUC').join( - self.room_jid, self.nick, password, rejoin=True) + self.room_jid, self.nick, password) return True
def draw_roster(self):
===================================== gajim/gtk/xml_console.py ===================================== @@ -34,9 +34,6 @@ from gajim.gtk.const import SettingKind from gajim.gtk.const import SettingType
-UNDECLARED = 'http://www.gajim.org/xmlns/undeclared' - - class XMLConsoleWindow(Gtk.ApplicationWindow): def __init__(self, account): Gtk.ApplicationWindow.__init__(self) @@ -141,19 +138,19 @@ class XMLConsoleWindow(Gtk.ApplicationWindow): input_text = None if text == 'Presence': input_text = ( - '<presence>\n' + '<presence xmlns="jabber:client">\n' '<show></show>\n' '<status></status>\n' '<priority></priority>\n' '</presence>') elif text == 'Message': input_text = ( - '<message to="" type="">\n' + '<message to="" type="" xmlns="jabber:client">\n' '<body></body>\n' '</message>') elif text == 'Iq': input_text = ( - '<iq to="" type="">\n' + '<iq to="" type="" xmlns="jabber:client">\n' '<query xmlns=""></query>\n' '</iq>')
@@ -176,8 +173,6 @@ class XMLConsoleWindow(Gtk.ApplicationWindow): if stanza: try: node = nbxmpp.Protocol(node=stanza) - if node.getNamespace() == UNDECLARED: - node.setNamespace(nbxmpp.NS_CLIENT) except Exception as error: ErrorDialog(_('Invalid Node'), str(error)) return
===================================== gajim/session.py ===================================== @@ -139,8 +139,11 @@ class ChatControlSession: stanza_id=obj.unique_id, message_id=obj.message_id)
- self.conn.get_module('MAM').save_archive_id( - None, obj.stanza_id, obj.timestamp) + jid = self.conn.get_own_jid().getStripped() + if self.conn.get_module('MAM').is_catchup_finished(jid): + app.logger.set_archive_infos(jid, + last_mam_id=obj.stanza_id, + last_muc_timestamp=obj.timestamp)
if obj.muc_pm and not obj.gc_control: # This is a carbon of a PM from a MUC we are not currently
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/f6ce10eb4d0c0c69ffa18258d1fe9ad073...