Philipp Hörist pushed to branch master at gajim / gajim

Commits:

9 changed files:

Changes:

  • gajim/common/config.py
    ... ... @@ -170,8 +170,6 @@ class Config:
    170 170
             'change_roster_title': [opt_bool, True, _('If enabled, Gajim will add * and [n] in contact list window title.')],
    
    171 171
             'restore_lines': [opt_int, 10, _('Number of messages from chat history to be restored when a chat tab/window is reopened.')],
    
    172 172
             'restore_timeout': [opt_int, -1, _('How far back in time (minutes) chat history is restored. -1 means no limit.')],
    
    173
    -        'muc_restore_lines': [opt_int, 100, _('How many lines to request from server when entering a group chat. -1 means no limit.')],
    
    174
    -        'muc_restore_timeout': [opt_int, -1, _('Minutes of backlog to request when entering a group chat. -1 means no limit.')],
    
    175 173
             '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.')],
    
    176 174
             'muc_autorejoin_on_kick': [opt_bool, False, _('Should automatic rejoin be activated when you were kicked from a group chat?')],
    
    177 175
             '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:
    429 427
             }, {}),
    
    430 428
             'rooms': ({
    
    431 429
                 'speller_language': [opt_str, '', _('Language used for spell checking.')],
    
    432
    -            '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.')],
    
    433
    -            'muc_restore_timeout': [opt_int, -2, _('Minutes of backlog to request when entering a group chat. -1 means no limit, -2 means global value.')],
    
    434 430
                 'notify_on_all_messages': [opt_bool, False, _('If enabled, a notification is created for every message in this group chat.')],
    
    435 431
                 'print_status': [opt_bool, False, _('Show a status message for all status changes (away, dnd, etc.) of users in a group chat.')],
    
    436 432
                 '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 = '''
    103 103
                 hash_method TEXT,
    
    104 104
                 hash TEXT,
    
    105 105
                 data TEXT,
    
    106
    -            last_seen INTEGER);
    
    107
    -    CREATE TABLE rooms_last_message_time(
    
    108
    -            jid_id INTEGER PRIMARY KEY UNIQUE,
    
    109
    -            time INTEGER
    
    106
    +            last_seen INTEGER
    
    110 107
         );
    
    111 108
         CREATE TABLE roster_entry(
    
    112 109
                 account_jid_id INTEGER,
    
    ... ... @@ -962,45 +959,6 @@ class Logger:
    962 959
             return self._con.execute(
    
    963 960
                 sql, tuple(jids) + (start, end)).fetchone()
    
    964 961
     
    
    965
    -    def get_room_last_message_time(self, account, jid):
    
    966
    -        """
    
    967
    -        Get the timestamp of the last message we received in a room.
    
    968
    -
    
    969
    -        :param account: The account
    
    970
    -
    
    971
    -        :param jid:     The jid for which we request the last timestamp
    
    972
    -
    
    973
    -        returns a timestamp or None
    
    974
    -        """
    
    975
    -        sql = '''
    
    976
    -            SELECT time FROM rooms_last_message_time
    
    977
    -            NATURAL JOIN jids WHERE jid = ?
    
    978
    -            '''
    
    979
    -
    
    980
    -        row = self._con.execute(sql, (jid,)).fetchone()
    
    981
    -        if not row:
    
    982
    -            return self.get_last_date_that_has_logs(account, jid)
    
    983
    -        return row.time
    
    984
    -
    
    985
    -    def set_room_last_message_time(self, jid, timestamp):
    
    986
    -        """
    
    987
    -        Set the timestamp of the last message we received in a room.
    
    988
    -
    
    989
    -        :param jid:         The jid
    
    990
    -
    
    991
    -        :param timestamp:   The timestamp in epoch
    
    992
    -
    
    993
    -        """
    
    994
    -
    
    995
    -        jid_id = self.get_jid_id(jid, type_=JIDConstant.ROOM_TYPE)
    
    996
    -        sql = '''REPLACE INTO rooms_last_message_time
    
    997
    -                 VALUES (:jid_id, COALESCE(
    
    998
    -                 (SELECT time FROM rooms_last_message_time
    
    999
    -                  WHERE jid_id = :jid_id AND time >= :time), :time))'''
    
    1000
    -
    
    1001
    -        self._con.execute(sql, {"jid_id": jid_id, "time": timestamp})
    
    1002
    -        self._timeout_commit()
    
    1003
    -
    
    1004 962
         def save_transport_type(self, jid, type_):
    
    1005 963
             """
    
    1006 964
             Save the type of the transport in DB
    
    ... ... @@ -1497,6 +1455,10 @@ class Logger:
    1497 1455
                     kwargs.get('sync_threshold', None)
    
    1498 1456
                 ))
    
    1499 1457
             else:
    
    1458
    +            for key, value in list(kwargs.items()):
    
    1459
    +                if value is None:
    
    1460
    +                    del kwargs[key]
    
    1461
    +
    
    1500 1462
                 args = ' = ?, '.join(kwargs.keys()) + ' = ?'
    
    1501 1463
                 sql = '''UPDATE last_archive_message SET {}
    
    1502 1464
                          WHERE jid_id = ?'''.format(args)
    

  • gajim/common/modules/mam.py
    ... ... @@ -73,6 +73,9 @@ class MAM(BaseModule):
    73 73
             self._mam_query_ids.clear()
    
    74 74
             self._catch_up_finished.clear()
    
    75 75
     
    
    76
    +    def is_catch_up_finished(self, jid):
    
    77
    +        return jid in self._catch_up_finished
    
    78
    +
    
    76 79
         def _from_valid_archive(self, _stanza, properties):
    
    77 80
             if properties.type.is_groupchat:
    
    78 81
                 expected_archive = properties.jid
    
    ... ... @@ -531,20 +534,6 @@ class MAM(BaseModule):
    531 534
             query.setAttr('queryid', query_id)
    
    532 535
             return iq
    
    533 536
     
    
    534
    -    def save_archive_id(self, jid, stanza_id, timestamp):
    
    535
    -        if jid is None:
    
    536
    -            jid = self._con.get_own_jid().getStripped()
    
    537
    -        if jid not in self._catch_up_finished:
    
    538
    -            return
    
    539
    -        self._log.info('Save: %s: %s, %s', jid, stanza_id, timestamp)
    
    540
    -        if stanza_id is None:
    
    541
    -            # mam:1
    
    542
    -            app.logger.set_archive_infos(jid, last_muc_timestamp=timestamp)
    
    543
    -        else:
    
    544
    -            # mam:2
    
    545
    -            app.logger.set_archive_infos(
    
    546
    -                jid, last_mam_id=stanza_id, last_muc_timestamp=timestamp)
    
    547
    -
    
    548 537
         def request_mam_preferences(self):
    
    549 538
             self._log.info('Request MAM preferences')
    
    550 539
             iq = nbxmpp.Iq('get', self.archiving_namespace)
    

  • gajim/common/modules/message.py
    ... ... @@ -26,6 +26,7 @@ from gajim.common.i18n import _
    26 26
     from gajim.common.nec import NetworkIncomingEvent
    
    27 27
     from gajim.common.nec import NetworkEvent
    
    28 28
     from gajim.common.helpers import AdditionalDataDict
    
    29
    +from gajim.common.caps_cache import muc_caps_cache
    
    29 30
     from gajim.common.const import KindConstant
    
    30 31
     from gajim.common.modules.base import BaseModule
    
    31 32
     from gajim.common.modules.util import get_eme_message
    
    ... ... @@ -251,7 +252,6 @@ class Message(BaseModule):
    251 252
                 event.nickname = event.resource
    
    252 253
                 event.xhtml_msgtxt = event.xhtml
    
    253 254
                 event.nick = event.resource or ''
    
    254
    -
    
    255 255
                 app.nec.push_incoming_event(NetworkEvent('gc-message-received',
    
    256 256
                                                          **vars(event)))
    
    257 257
                 # TODO: Some plugins modify msgtxt in the GUI event
    
    ... ... @@ -292,9 +292,16 @@ class Message(BaseModule):
    292 292
                                             additional_data=event.additional_data,
    
    293 293
                                             stanza_id=event.stanza_id,
    
    294 294
                                             message_id=event.message_id)
    
    295
    -            app.logger.set_room_last_message_time(event.room_jid, event.timestamp)
    
    296
    -            self._con.get_module('MAM').save_archive_id(
    
    297
    -                event.room_jid, event.stanza_id, event.timestamp)
    
    295
    +
    
    296
    +        if muc_caps_cache.has_mam(event.room_jid):
    
    297
    +            finished = self._con.get_module('MAM').is_catchup_finished(
    
    298
    +                event.room_jid)
    
    299
    +            if not finished:
    
    300
    +                return
    
    301
    +
    
    302
    +        app.logger.set_archive_infos(event.room_jid,
    
    303
    +                                     last_mam_id=event.stanza_id,
    
    304
    +                                     last_muc_timestamp=event.timestamp)
    
    298 305
     
    
    299 306
         def _check_for_mam_compliance(self, room_jid, stanza_id):
    
    300 307
             namespace = caps_cache.muc_caps_cache.get_mam_namespace(room_jid)
    

  • gajim/common/modules/muc.py
    ... ... @@ -17,6 +17,8 @@
    17 17
     
    
    18 18
     import time
    
    19 19
     import logging
    
    20
    +from datetime import datetime
    
    21
    +from datetime import timedelta
    
    20 22
     from functools import partial
    
    21 23
     
    
    22 24
     import nbxmpp
    
    ... ... @@ -30,9 +32,11 @@ from gajim.common import app
    30 32
     from gajim.common import helpers
    
    31 33
     from gajim.common.const import KindConstant
    
    32 34
     from gajim.common.const import MUCJoinedState
    
    35
    +from gajim.common.const import SyncThreshold
    
    33 36
     from gajim.common.structs import MUCData
    
    34 37
     from gajim.common.helpers import AdditionalDataDict
    
    35 38
     from gajim.common.helpers import get_default_muc_config
    
    39
    +from gajim.common.helpers import get_sync_threshold
    
    36 40
     from gajim.common import idle
    
    37 41
     from gajim.common.caps_cache import muc_caps_cache
    
    38 42
     from gajim.common.nec import NetworkEvent
    
    ... ... @@ -130,11 +134,11 @@ class MUC(BaseModule):
    130 134
         def get_mucs_with_state(self, states):
    
    131 135
             return [muc for muc in self._muc_data.values() if muc.state in states]
    
    132 136
     
    
    133
    -    def join(self, room_jid, nick, password, rejoin=False, config=None):
    
    137
    +    def join(self, room_jid, nick, password, config=None):
    
    134 138
             if not app.account_is_connected(self._account):
    
    135 139
                 return
    
    136 140
     
    
    137
    -        muc_data = MUCData(room_jid, nick, password, rejoin, config)
    
    141
    +        muc_data = MUCData(room_jid, nick, password, config)
    
    138 142
             self._muc_data[room_jid] = muc_data
    
    139 143
     
    
    140 144
             self._con.get_module('Discovery').disco_muc(
    
    ... ... @@ -149,7 +153,7 @@ class MUC(BaseModule):
    149 153
                 status=self._con.status)
    
    150 154
     
    
    151 155
             muc_x = presence.setTag(nbxmpp.NS_MUC + ' x')
    
    152
    -        self._add_history_query(muc_x, str(muc_data.jid), muc_data.rejoin)
    
    156
    +        self._add_history_query(muc_x, str(muc_data.jid))
    
    153 157
     
    
    154 158
             if muc_data.password is not None:
    
    155 159
                 muc_x.setTagData('password', muc_data.password)
    
    ... ... @@ -281,37 +285,27 @@ class MUC(BaseModule):
    281 285
                 show=show,
    
    282 286
                 status=self._con.status)
    
    283 287
     
    
    284
    -    def _add_history_query(self, muc_x, room_jid, rejoin):
    
    285
    -        last_date = app.logger.get_room_last_message_time(
    
    286
    -            self._account, room_jid)
    
    287
    -        if not last_date:
    
    288
    -            last_date = 0
    
    289
    -
    
    288
    +    def _add_history_query(self, muc_x, room_jid):
    
    290 289
             if muc_caps_cache.has_mam(room_jid):
    
    291 290
                 # The room is MAM capable dont get MUC History
    
    292 291
                 muc_x.setTag('history', {'maxchars': '0'})
    
    293 292
             else:
    
    294 293
                 # Request MUC History (not MAM)
    
    295
    -            tags = {}
    
    296
    -            timeout = app.config.get_per('rooms', room_jid,
    
    297
    -                                         'muc_restore_timeout')
    
    298
    -            if timeout is None or timeout == -2:
    
    299
    -                timeout = app.config.get('muc_restore_timeout')
    
    300
    -            if last_date == 0 and timeout >= 0:
    
    301
    -                last_date = time.time() - timeout * 60
    
    302
    -            elif not rejoin and timeout >= 0:
    
    303
    -                last_date = max(last_date, time.time() - timeout * 60)
    
    304
    -            last_date = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(
    
    305
    -                last_date))
    
    306
    -            tags['since'] = last_date
    
    307
    -
    
    308
    -            nb = app.config.get_per('rooms', room_jid, 'muc_restore_lines')
    
    309
    -            if nb is None or nb == -2:
    
    310
    -                nb = app.config.get('muc_restore_lines')
    
    311
    -            if nb >= 0:
    
    312
    -                tags['maxstanzas'] = nb
    
    313
    -            if tags:
    
    314
    -                muc_x.setTag('history', tags)
    
    294
    +            archive = app.logger.get_archive_infos(room_jid)
    
    295
    +            threshold = get_sync_threshold(room_jid, archive)
    
    296
    +
    
    297
    +            since_epoch = 0
    
    298
    +            if archive is not None and archive.last_muc_timestamp is not None:
    
    299
    +                since_epoch = float(archive.last_muc_timestamp)
    
    300
    +
    
    301
    +            since_date = datetime.utcfromtimestamp(since_epoch)
    
    302
    +            if threshold != SyncThreshold.NO_THRESHOLD:
    
    303
    +                threshold_date = datetime.utcnow() - timedelta(days=threshold)
    
    304
    +                since_date = max(threshold_date, since_date)
    
    305
    +
    
    306
    +            date_string = since_date.strftime('%Y-%m-%dT%H:%M:%SZ')
    
    307
    +            muc_x.setTag('history', {'since': date_string})
    
    308
    +            self._log.info('Threshold for %s: %s', room_jid, threshold)
    
    315 309
     
    
    316 310
         def _on_muc_presence(self, _con, _stanza, properties):
    
    317 311
             muc_data = self._get_muc_data(properties.muc_jid)
    

  • gajim/common/structs.py
    ... ... @@ -26,11 +26,10 @@ CapsIdentity = namedtuple('CapsIdentity', 'category type name lang')
    26 26
     
    
    27 27
     
    
    28 28
     class MUCData:
    
    29
    -    def __init__(self, room_jid, nick, password, rejoin, config=None):
    
    29
    +    def __init__(self, room_jid, nick, password, config=None):
    
    30 30
             self._room_jid = JID(room_jid)
    
    31 31
             self._nick = nick
    
    32 32
             self._password = password
    
    33
    -        self._rejoin = rejoin
    
    34 33
             self._config = config
    
    35 34
             self._state = MUCJoinedState.NOT_JOINED
    
    36 35
     
    
    ... ... @@ -64,14 +63,6 @@ class MUCData:
    64 63
         def state(self, value):
    
    65 64
             self._state = value
    
    66 65
     
    
    67
    -    @property
    
    68
    -    def rejoin(self):
    
    69
    -        return self._rejoin
    
    70
    -
    
    71
    -    @rejoin.setter
    
    72
    -    def rejoin(self, value):
    
    73
    -        self._rejoin = value
    
    74
    -
    
    75 66
         @property
    
    76 67
         def config(self):
    
    77 68
             return self._config

  • gajim/groupchat_control.py
    ... ... @@ -511,10 +511,6 @@ class GroupchatControl(ChatControlBase):
    511 511
                 vcard_support and
    
    512 512
                 contact.affiliation.is_owner)
    
    513 513
     
    
    514
    -        # Sync Threshold
    
    515
    -        has_mam = muc_caps_cache.has_mam(self.room_jid)
    
    516
    -        self._get_action('choose-sync-').set_enabled(has_mam)
    
    517
    -
    
    518 514
             # Print join/left
    
    519 515
             join_default = app.config.get('print_join_left_default')
    
    520 516
             value = app.config.get_per('rooms', self.contact.jid,
    
    ... ... @@ -1414,8 +1410,7 @@ class GroupchatControl(ChatControlBase):
    1414 1410
             if obj.conn.name != self.account:
    
    1415 1411
                 return
    
    1416 1412
             password = app.gc_passwords.get(self.room_jid, '')
    
    1417
    -        obj.conn.get_module('MUC').join(self.room_jid, self.nick, password,
    
    1418
    -                                        rejoin=True)
    
    1413
    +        obj.conn.get_module('MUC').join(self.room_jid, self.nick, password)
    
    1419 1414
     
    
    1420 1415
         def _nec_decrypted_message_received(self, obj):
    
    1421 1416
             if obj.conn.name != self.account:
    
    ... ... @@ -1552,7 +1547,7 @@ class GroupchatControl(ChatControlBase):
    1552 1547
                 return False
    
    1553 1548
             password = app.gc_passwords.get(self.room_jid, '')
    
    1554 1549
             app.connections[self.account].get_module('MUC').join(
    
    1555
    -            self.room_jid, self.nick, password, rejoin=True)
    
    1550
    +            self.room_jid, self.nick, password)
    
    1556 1551
             return True
    
    1557 1552
     
    
    1558 1553
         def draw_roster(self):
    

  • gajim/gtk/xml_console.py
    ... ... @@ -34,9 +34,6 @@ from gajim.gtk.const import SettingKind
    34 34
     from gajim.gtk.const import SettingType
    
    35 35
     
    
    36 36
     
    
    37
    -UNDECLARED = 'http://www.gajim.org/xmlns/undeclared'
    
    38
    -
    
    39
    -
    
    40 37
     class XMLConsoleWindow(Gtk.ApplicationWindow):
    
    41 38
         def __init__(self, account):
    
    42 39
             Gtk.ApplicationWindow.__init__(self)
    
    ... ... @@ -141,19 +138,19 @@ class XMLConsoleWindow(Gtk.ApplicationWindow):
    141 138
             input_text = None
    
    142 139
             if text == 'Presence':
    
    143 140
                 input_text = (
    
    144
    -                '<presence>\n'
    
    141
    +                '<presence xmlns="jabber:client">\n'
    
    145 142
                     '<show></show>\n'
    
    146 143
                     '<status></status>\n'
    
    147 144
                     '<priority></priority>\n'
    
    148 145
                     '</presence>')
    
    149 146
             elif text == 'Message':
    
    150 147
                 input_text = (
    
    151
    -                '<message to="" type="">\n'
    
    148
    +                '<message to="" type="" xmlns="jabber:client">\n'
    
    152 149
                     '<body></body>\n'
    
    153 150
                     '</message>')
    
    154 151
             elif text == 'Iq':
    
    155 152
                 input_text = (
    
    156
    -                '<iq to="" type="">\n'
    
    153
    +                '<iq to="" type="" xmlns="jabber:client">\n'
    
    157 154
                     '<query xmlns=""></query>\n'
    
    158 155
                     '</iq>')
    
    159 156
     
    
    ... ... @@ -176,8 +173,6 @@ class XMLConsoleWindow(Gtk.ApplicationWindow):
    176 173
             if stanza:
    
    177 174
                 try:
    
    178 175
                     node = nbxmpp.Protocol(node=stanza)
    
    179
    -                if node.getNamespace() == UNDECLARED:
    
    180
    -                    node.setNamespace(nbxmpp.NS_CLIENT)
    
    181 176
                 except Exception as error:
    
    182 177
                     ErrorDialog(_('Invalid Node'), str(error))
    
    183 178
                     return
    

  • gajim/session.py
    ... ... @@ -139,8 +139,11 @@ class ChatControlSession:
    139 139
                     stanza_id=obj.unique_id,
    
    140 140
                     message_id=obj.message_id)
    
    141 141
     
    
    142
    -        self.conn.get_module('MAM').save_archive_id(
    
    143
    -            None, obj.stanza_id, obj.timestamp)
    
    142
    +        jid = self.conn.get_own_jid().getStripped()
    
    143
    +        if self.conn.get_module('MAM').is_catchup_finished(jid):
    
    144
    +            app.logger.set_archive_infos(jid,
    
    145
    +                                         last_mam_id=obj.stanza_id,
    
    146
    +                                         last_muc_timestamp=obj.timestamp)
    
    144 147
     
    
    145 148
             if obj.muc_pm and not obj.gc_control:
    
    146 149
                 # This is a carbon of a PM from a MUC we are not currently