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

Commits:

19 changed files:

Changes:

  • gajim/application.py
    ... ... @@ -38,10 +38,14 @@ from datetime import datetime
    38 38
     from pathlib import Path
    
    39 39
     from urllib.parse import unquote
    
    40 40
     
    
    41
    -from gi.repository import GLib, Gio, Gtk
    
    41
    +import nbxmpp
    
    42
    +from gi.repository import Gio
    
    43
    +from gi.repository import GLib
    
    44
    +from gi.repository import Gtk
    
    42 45
     
    
    43 46
     import gajim
    
    44 47
     from gajim.common import app
    
    48
    +from gajim.common import ged
    
    45 49
     from gajim.common import configpaths
    
    46 50
     from gajim.common import logging_helpers
    
    47 51
     from gajim.common import exceptions
    
    ... ... @@ -227,6 +231,10 @@ class GajimApplication(Gtk.Application):
    227 231
             from gajim import gui_menu_builder
    
    228 232
             gui_menu_builder.build_accounts_menu()
    
    229 233
     
    
    234
    +        app.ged.register_event_handler('feature-discovered',
    
    235
    +                                       ged.CORE,
    
    236
    +                                       self._on_feature_discovered)
    
    237
    +
    
    230 238
         def _open_uris(self, uris):
    
    231 239
             for uri in uris:
    
    232 240
                 app.log('uri_handler').info('open %s', uri)
    
    ... ... @@ -498,3 +506,14 @@ class GajimApplication(Gtk.Application):
    498 506
                 elif new_state and state == 'online':
    
    499 507
                     # We go online
    
    500 508
                     self.lookup_action(account + action_name).set_enabled(True)
    
    509
    +
    
    510
    +    def _on_feature_discovered(self, event):
    
    511
    +        if event.feature == nbxmpp.NS_VCARD:
    
    512
    +            action = '%s-profile' % event.account
    
    513
    +            self.lookup_action(action).set_enabled(True)
    
    514
    +        elif event.feature in (nbxmpp.NS_MAM_1, nbxmpp.NS_MAM_2):
    
    515
    +            action = '%s-archive' % event.account
    
    516
    +            self.lookup_action(action).set_enabled(True)
    
    517
    +        elif event.feature == nbxmpp.NS_PRIVACY:
    
    518
    +            action = '%s-privacylists' % event.account
    
    519
    +            self.lookup_action(action).set_enabled(True)

  • gajim/common/app.py
    ... ... @@ -67,13 +67,6 @@ plugin_manager = None # Plugins Manager
    67 67
     
    
    68 68
     logger = cast(LoggerT, None)
    
    69 69
     
    
    70
    -# For backwards compatibility needed
    
    71
    -# some plugins use that
    
    72
    -gajimpaths = configpaths.gajimpaths
    
    73
    -
    
    74
    -
    
    75
    -RecentGroupchat = namedtuple('RecentGroupchat', ['room', 'server', 'nickname'])
    
    76
    -
    
    77 70
     css_config = None
    
    78 71
     
    
    79 72
     os_info = None # used to cache os information
    
    ... ... @@ -149,17 +142,43 @@ socks5queue = None
    149 142
     gupnp_igd = None
    
    150 143
     
    
    151 144
     gajim_identity = {'type': 'pc', 'category': 'client', 'name': 'Gajim'}
    
    152
    -gajim_common_features = [nbxmpp.NS_BYTESTREAM, nbxmpp.NS_SI, nbxmpp.NS_FILE,
    
    153
    -    nbxmpp.NS_MUC, nbxmpp.NS_MUC_USER, nbxmpp.NS_MUC_ADMIN, nbxmpp.NS_MUC_OWNER,
    
    154
    -    nbxmpp.NS_MUC_CONFIG, nbxmpp.NS_COMMANDS, nbxmpp.NS_DISCO_INFO, 'ipv6',
    
    155
    -    'jabber:iq:gateway', nbxmpp.NS_LAST, nbxmpp.NS_PRIVACY, nbxmpp.NS_PRIVATE,
    
    156
    -    nbxmpp.NS_REGISTER, nbxmpp.NS_VERSION, nbxmpp.NS_DATA, nbxmpp.NS_ENCRYPTED,
    
    157
    -    'msglog', 'sslc2s', 'stringprep', nbxmpp.NS_PING, nbxmpp.NS_TIME_REVISED,
    
    158
    -    nbxmpp.NS_SSN, nbxmpp.NS_MOOD, nbxmpp.NS_ACTIVITY, nbxmpp.NS_NICK,
    
    159
    -    nbxmpp.NS_ROSTERX, nbxmpp.NS_SECLABEL, nbxmpp.NS_HASHES_2,
    
    160
    -    nbxmpp.NS_HASHES_MD5, nbxmpp.NS_HASHES_SHA1, nbxmpp.NS_HASHES_SHA256,
    
    161
    -    nbxmpp.NS_HASHES_SHA512, nbxmpp.NS_CONFERENCE, nbxmpp.NS_CORRECT,
    
    162
    -    nbxmpp.NS_EME, 'urn:xmpp:avatar:metadata+notify', 'storage:bookmarks+notify']
    
    145
    +
    
    146
    +gajim_common_features = [
    
    147
    +    nbxmpp.NS_BYTESTREAM,
    
    148
    +    nbxmpp.NS_SI,
    
    149
    +    nbxmpp.NS_FILE,
    
    150
    +    nbxmpp.NS_MUC,
    
    151
    +    nbxmpp.NS_COMMANDS,
    
    152
    +    nbxmpp.NS_DISCO_INFO,
    
    153
    +    nbxmpp.NS_LAST,
    
    154
    +    nbxmpp.NS_DATA,
    
    155
    +    nbxmpp.NS_ENCRYPTED,
    
    156
    +    nbxmpp.NS_PING,
    
    157
    +    nbxmpp.NS_TIME_REVISED,
    
    158
    +    nbxmpp.NS_VERSION,
    
    159
    +    nbxmpp.NS_ROSTERX,
    
    160
    +    nbxmpp.NS_SECLABEL,
    
    161
    +    nbxmpp.NS_CONFERENCE,
    
    162
    +    nbxmpp.NS_CORRECT,
    
    163
    +    nbxmpp.NS_EME,
    
    164
    +    nbxmpp.NS_HASHES,
    
    165
    +    nbxmpp.NS_HASHES_2,
    
    166
    +    nbxmpp.NS_HASHES_MD5,
    
    167
    +    nbxmpp.NS_HASHES_SHA1,
    
    168
    +    nbxmpp.NS_HASHES_SHA256,
    
    169
    +    nbxmpp.NS_HASHES_SHA512,
    
    170
    +    nbxmpp.NS_HASHES_SHA3_256,
    
    171
    +    nbxmpp.NS_HASHES_SHA3_512,
    
    172
    +    nbxmpp.NS_HASHES_BLAKE2B_256,
    
    173
    +    nbxmpp.NS_HASHES_BLAKE2B_512,
    
    174
    +    nbxmpp.NS_JINGLE,
    
    175
    +    nbxmpp.NS_JINGLE_FILE_TRANSFER_5,
    
    176
    +    nbxmpp.NS_JINGLE_XTLS,
    
    177
    +    nbxmpp.NS_JINGLE_BYTESTREAM,
    
    178
    +    nbxmpp.NS_JINGLE_IBB,
    
    179
    +    nbxmpp.NS_AVATAR_METADATA + '+notify',
    
    180
    +    nbxmpp.NS_BOOKMARKS + '+notify',
    
    181
    +]
    
    163 182
     
    
    164 183
     # Optional features gajim supports per account
    
    165 184
     gajim_optional_features = {}  # type: Dict[str, List[str]]
    
    ... ... @@ -580,6 +599,9 @@ def get_recent_groupchats(account):
    580 599
         recent_groupchats = config.get_per(
    
    581 600
             'accounts', account, 'recent_groupchats').split()
    
    582 601
     
    
    602
    +    RecentGroupchat = namedtuple('RecentGroupchat',
    
    603
    +                                 ['room', 'server', 'nickname'])
    
    604
    +
    
    583 605
         recent_list = []
    
    584 606
         for groupchat in recent_groupchats:
    
    585 607
             jid = nbxmpp.JID(groupchat)
    

  • gajim/common/configpaths.py
    ... ... @@ -241,7 +241,3 @@ class ConfigPaths:
    241 241
     
    
    242 242
     
    
    243 243
     _paths = ConfigPaths()
    244
    -
    
    245
    -# For backwards compatibility needed
    
    246
    -# some plugins use that
    
    247
    -gajimpaths = _paths

  • gajim/common/connection.py
    ... ... @@ -1684,14 +1684,6 @@ class Connection(CommonConnection, ConnectionHandlers):
    1684 1684
                 show=show,
    
    1685 1685
                 caps=ptype != 'unavailable')
    
    1686 1686
     
    
    1687
    -    def send_captcha(self, jid, form_node):
    
    1688
    -        if not app.account_is_connected(self.name):
    
    1689
    -            return
    
    1690
    -        iq = nbxmpp.Iq(typ='set', to=jid)
    
    1691
    -        captcha = iq.addChild(name='captcha', namespace=nbxmpp.NS_CAPTCHA)
    
    1692
    -        captcha.addChild(node=form_node)
    
    1693
    -        self.connection.send(iq)
    
    1694
    -
    
    1695 1687
         def check_unique_room_id_support(self, server, instance):
    
    1696 1688
             if not app.account_is_connected(self.name):
    
    1697 1689
                 return
    

  • gajim/common/connection_handlers.py
    ... ... @@ -585,12 +585,18 @@ class ConnectionHandlers(ConnectionSocks5Bytestream,
    585 585
                 nbxmpp.NS_PUBKEY_PUBKEY)
    
    586 586
     
    
    587 587
             for handler in modules.get_handlers(self):
    
    588
    -            con.RegisterHandler(*handler)
    
    588
    +            if len(handler) == 5:
    
    589
    +                name, func, typ, ns, priority = handler
    
    590
    +                con.RegisterHandler(name, func, typ, ns, priority=priority)
    
    591
    +            else:
    
    592
    +                con.RegisterHandler(*handler)
    
    589 593
             self.handlers_registered = True
    
    590 594
     
    
    591 595
         def _unregister_handlers(self):
    
    592 596
             if not self.connection:
    
    593 597
                 return
    
    594 598
             for handler in modules.get_handlers(self):
    
    599
    +            if len(handler) > 4:
    
    600
    +                handler = handler[:4]
    
    595 601
                 self.connection.UnregisterHandler(*handler)
    
    596 602
             self.handlers_registered = False

  • gajim/common/connection_handlers_events.py
    ... ... @@ -40,27 +40,6 @@ from gajim.common.file_props import FilesProp
    40 40
     
    
    41 41
     log = logging.getLogger('gajim.c.connection_handlers_events')
    
    42 42
     
    
    43
    -CONDITION_TO_CODE = {
    
    44
    -    'realjid-public': 100,
    
    45
    -    'affiliation-changed': 101,
    
    46
    -    'unavailable-shown': 102,
    
    47
    -    'unavailable-not-shown': 103,
    
    48
    -    'configuration-changed': 104,
    
    49
    -    'self-presence': 110,
    
    50
    -    'logging-enabled': 170,
    
    51
    -    'logging-disabled': 171,
    
    52
    -    'non-anonymous': 172,
    
    53
    -    'semi-anonymous': 173,
    
    54
    -    'fully-anonymous': 174,
    
    55
    -    'room-created': 201,
    
    56
    -    'nick-assigned': 210,
    
    57
    -    'banned': 301,
    
    58
    -    'new-nick': 303,
    
    59
    -    'kicked': 307,
    
    60
    -    'removed-affiliation': 321,
    
    61
    -    'removed-membership': 322,
    
    62
    -    'removed-shutdown': 332,
    
    63
    -}
    
    64 43
     
    
    65 44
     class HelperEvent:
    
    66 45
         def get_jid_resource(self, check_fake_jid=False):
    
    ... ... @@ -378,14 +357,7 @@ class GcPresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
    378 357
                 self.status_code = ['destroyed']
    
    379 358
             else:
    
    380 359
                 self.reason = self.stanza.getReason()
    
    381
    -            conditions = self.stanza.getStatusConditions()
    
    382
    -            if conditions:
    
    383
    -                self.status_code = []
    
    384
    -                for condition in conditions:
    
    385
    -                    if condition in CONDITION_TO_CODE:
    
    386
    -                        self.status_code.append(CONDITION_TO_CODE[condition])
    
    387
    -            else:
    
    388
    -                self.status_code = self.stanza.getStatusCode()
    
    360
    +            self.status_code = self.stanza.getStatusCode()
    
    389 361
     
    
    390 362
             self.role = self.stanza.getRole()
    
    391 363
             self.affiliation = self.stanza.getAffiliation()
    
    ... ... @@ -429,60 +401,12 @@ class GcMessageReceivedEvent(nec.NetworkIncomingEvent):
    429 401
                 # message from server
    
    430 402
                 self.nick = ''
    
    431 403
     
    
    432
    -        conditions = self.stanza.getStatusConditions()
    
    433
    -        if conditions:
    
    434
    -            self.status_code = []
    
    435
    -            for condition in conditions:
    
    436
    -                if condition in CONDITION_TO_CODE:
    
    437
    -                    self.status_code.append(CONDITION_TO_CODE[condition])
    
    438
    -        else:
    
    439
    -            self.status_code = self.stanza.getStatusCode()
    
    440
    -
    
    441 404
             if not self.stanza.getTag('body'): # no <body>
    
    442
    -            # It could be a config change. See
    
    443
    -            # http://www.xmpp.org/extensions/xep-0045.html#roomconfig-notify
    
    444
    -            if self.stanza.getTag('x'):
    
    445
    -                if self.status_code != []:
    
    446
    -                    app.nec.push_incoming_event(GcConfigChangedReceivedEvent(
    
    447
    -                        None, conn=self.conn, msg_event=self))
    
    448
    -            if self.msg_obj.form_node:
    
    449
    -                # It could be a voice request. See
    
    450
    -                # http://www.xmpp.org/extensions/xep-0045.html#voiceapprove
    
    451
    -                from gajim.gtk.single_message import SingleMessageWindow
    
    452
    -                SingleMessageWindow(
    
    453
    -                    self.conn.name, self.fjid,
    
    454
    -                    action='receive', from_whom=self.fjid,
    
    455
    -                    subject='', message='', resource='', session=None,
    
    456
    -                    form_node=self.msg_obj.form_node)
    
    457 405
                 return
    
    458 406
     
    
    459 407
             from gajim.common.modules.security_labels import parse_securitylabel
    
    460 408
             self.displaymarking = parse_securitylabel(self.stanza)
    
    461 409
     
    
    462
    -        self.captcha_form = None
    
    463
    -        captcha_tag = self.stanza.getTag('captcha', namespace=nbxmpp.NS_CAPTCHA)
    
    464
    -        if captcha_tag:
    
    465
    -            self.captcha_form = captcha_tag.getTag('x',
    
    466
    -                namespace=nbxmpp.NS_DATA)
    
    467
    -            for field in self.captcha_form.getTags('field'):
    
    468
    -                for media in field.getTags('media'):
    
    469
    -                    for uri in media.getTags('uri'):
    
    470
    -                        uri_data = uri.getData()
    
    471
    -                        if uri_data.startswith('cid:'):
    
    472
    -                            uri_data = uri_data[4:]
    
    473
    -                            found = False
    
    474
    -                            for data in self.stanza.getTags('data',
    
    475
    -                            namespace=nbxmpp.NS_BOB):
    
    476
    -                                if data.getAttr('cid') == uri_data:
    
    477
    -                                    uri.setData(data.getData())
    
    478
    -                                    found = True
    
    479
    -                            if not found:
    
    480
    -                                self.conn.get_module('BitsOfBinary').get_bob_data(
    
    481
    -                                    uri_data, self.fjid,
    
    482
    -                                    self.conn._dispatch_gc_msg_with_captcha,
    
    483
    -                                    [self.stanza, self.msg_obj], 0)
    
    484
    -                                return
    
    485
    -
    
    486 410
             from gajim.common.modules.misc import parse_correction
    
    487 411
             self.correct_id = parse_correction(self.stanza)
    
    488 412
     
    

  • gajim/common/ged.py
    ... ... @@ -24,6 +24,7 @@ Global Events Dispatcher module.
    24 24
     
    
    25 25
     import logging
    
    26 26
     import traceback
    
    27
    +import inspect
    
    27 28
     
    
    28 29
     from nbxmpp import NodeProcessed
    
    29 30
     
    
    ... ... @@ -84,13 +85,19 @@ class GlobalEventsDispatcher:
    84 85
                         Error: %s''', handler, priority, event_name, error)
    
    85 86
     
    
    86 87
         def raise_event(self, event_name, *args, **kwargs):
    
    87
    -        log.debug('%s Args: %s', event_name, str(args))
    
    88
    +        log.debug('Raise event: %s', event_name)
    
    88 89
             if event_name in self.handlers:
    
    89 90
                 node_processed = False
    
    90 91
                 # Iterate over a copy of the handlers list, so while iterating
    
    91 92
                 # the original handlers list can be modified
    
    92 93
                 for _priority, handler in list(self.handlers[event_name]):
    
    93 94
                     try:
    
    95
    +                    if inspect.ismethod(handler):
    
    96
    +                        log.debug('Call handler %s on %s',
    
    97
    +                                  handler.__name__,
    
    98
    +                                  handler.__self__)
    
    99
    +                    else:
    
    100
    +                        log.debug('Call handler %s', handler.__name__)
    
    94 101
                         if handler(*args, **kwargs):
    
    95 102
                             return True
    
    96 103
                     except NodeProcessed:
    

  • gajim/common/helpers.py
    ... ... @@ -1161,56 +1161,47 @@ def prepare_and_validate_gpg_keyID(account, jid, keyID):
    1161 1161
         return keyID
    
    1162 1162
     
    
    1163 1163
     def update_optional_features(account=None):
    
    1164
    -    if account:
    
    1164
    +    if account is not None:
    
    1165 1165
             accounts = [account]
    
    1166 1166
         else:
    
    1167
    -        accounts = [a for a in app.connections]
    
    1168
    -    for a in accounts:
    
    1169
    -        app.gajim_optional_features[a] = []
    
    1170
    -        if app.config.get_per('accounts', a, 'subscribe_mood'):
    
    1171
    -            app.gajim_optional_features[a].append(nbxmpp.NS_MOOD + '+notify')
    
    1172
    -        if app.config.get_per('accounts', a, 'subscribe_activity'):
    
    1173
    -            app.gajim_optional_features[a].append(nbxmpp.NS_ACTIVITY + \
    
    1174
    -                '+notify')
    
    1175
    -        if app.config.get_per('accounts', a, 'publish_tune'):
    
    1176
    -            app.gajim_optional_features[a].append(nbxmpp.NS_TUNE)
    
    1177
    -        if app.config.get_per('accounts', a, 'publish_location'):
    
    1178
    -            app.gajim_optional_features[a].append(nbxmpp.NS_LOCATION)
    
    1179
    -        if app.config.get_per('accounts', a, 'subscribe_tune'):
    
    1180
    -            app.gajim_optional_features[a].append(nbxmpp.NS_TUNE + '+notify')
    
    1181
    -        if app.config.get_per('accounts', a, 'subscribe_nick'):
    
    1182
    -            app.gajim_optional_features[a].append(nbxmpp.NS_NICK + '+notify')
    
    1183
    -        if app.config.get_per('accounts', a, 'subscribe_location'):
    
    1184
    -            app.gajim_optional_features[a].append(nbxmpp.NS_LOCATION + \
    
    1185
    -                '+notify')
    
    1167
    +        accounts = app.connections.keys()
    
    1168
    +
    
    1169
    +    for account_ in accounts:
    
    1170
    +        features = []
    
    1171
    +        app.gajim_optional_features[account_] = features
    
    1172
    +        if app.config.get_per('accounts', account_, 'subscribe_mood'):
    
    1173
    +            features.append(nbxmpp.NS_MOOD + '+notify')
    
    1174
    +        if app.config.get_per('accounts', account_, 'subscribe_activity'):
    
    1175
    +            features.append(nbxmpp.NS_ACTIVITY + '+notify')
    
    1176
    +        if app.config.get_per('accounts', account_, 'subscribe_tune'):
    
    1177
    +            features.append(nbxmpp.NS_TUNE + '+notify')
    
    1178
    +        if app.config.get_per('accounts', account_, 'subscribe_nick'):
    
    1179
    +            features.append(nbxmpp.NS_NICK + '+notify')
    
    1180
    +        if app.config.get_per('accounts', account_, 'subscribe_location'):
    
    1181
    +            features.append(nbxmpp.NS_LOCATION + '+notify')
    
    1186 1182
             if app.config.get('outgoing_chat_state_notifactions') != 'disabled':
    
    1187
    -            app.gajim_optional_features[a].append(nbxmpp.NS_CHATSTATES)
    
    1183
    +            features.append(nbxmpp.NS_CHATSTATES)
    
    1188 1184
             if not app.config.get('ignore_incoming_xhtml'):
    
    1189
    -            app.gajim_optional_features[a].append(nbxmpp.NS_XHTML_IM)
    
    1190
    -        if app.config.get_per('accounts', a, 'answer_receipts'):
    
    1191
    -            app.gajim_optional_features[a].append(nbxmpp.NS_RECEIPTS)
    
    1192
    -        app.gajim_optional_features[a].append(nbxmpp.NS_JINGLE)
    
    1185
    +            features.append(nbxmpp.NS_XHTML_IM)
    
    1186
    +        if app.config.get_per('accounts', account_, 'answer_receipts'):
    
    1187
    +            features.append(nbxmpp.NS_RECEIPTS)
    
    1193 1188
             if app.is_installed('FARSTREAM'):
    
    1194
    -            app.gajim_optional_features[a].append(nbxmpp.NS_JINGLE_RTP)
    
    1195
    -            app.gajim_optional_features[a].append(nbxmpp.NS_JINGLE_RTP_AUDIO)
    
    1196
    -            app.gajim_optional_features[a].append(nbxmpp.NS_JINGLE_RTP_VIDEO)
    
    1197
    -            app.gajim_optional_features[a].append(nbxmpp.NS_JINGLE_ICE_UDP)
    
    1198
    -        app.gajim_optional_features[a].append(
    
    1199
    -            nbxmpp.NS_JINGLE_FILE_TRANSFER_5)
    
    1200
    -        app.gajim_optional_features[a].append(nbxmpp.NS_JINGLE_XTLS)
    
    1201
    -        app.gajim_optional_features[a].append(nbxmpp.NS_JINGLE_BYTESTREAM)
    
    1202
    -        app.gajim_optional_features[a].append(nbxmpp.NS_JINGLE_IBB)
    
    1189
    +            features.append(nbxmpp.NS_JINGLE_RTP)
    
    1190
    +            features.append(nbxmpp.NS_JINGLE_RTP_AUDIO)
    
    1191
    +            features.append(nbxmpp.NS_JINGLE_RTP_VIDEO)
    
    1192
    +            features.append(nbxmpp.NS_JINGLE_ICE_UDP)
    
    1203 1193
     
    
    1204 1194
             # Give plugins the possibility to add their features
    
    1205
    -        app.plugin_manager.extension_point('update_caps', a)
    
    1195
    +        app.plugin_manager.extension_point('update_caps', account_)
    
    1206 1196
     
    
    1207
    -        app.caps_hash[a] = caps_cache.compute_caps_hash([app.gajim_identity],
    
    1208
    -                app.gajim_common_features + app.gajim_optional_features[a])
    
    1197
    +        app.caps_hash[account_] = caps_cache.compute_caps_hash(
    
    1198
    +            [app.gajim_identity],
    
    1199
    +            app.gajim_common_features + features)
    
    1209 1200
             # re-send presence with new hash
    
    1210
    -        connected = app.connections[a].connected
    
    1201
    +        connected = app.connections[account_].connected
    
    1211 1202
             if connected > 1 and app.SHOW_LIST[connected] != 'invisible':
    
    1212
    -            app.connections[a].change_status(app.SHOW_LIST[connected],
    
    1213
    -                    app.connections[a].status)
    
    1203
    +            app.connections[account_].change_status(
    
    1204
    +                app.SHOW_LIST[connected], app.connections[account_].status)
    
    1214 1205
     
    
    1215 1206
     def jid_is_blocked(account, jid):
    
    1216 1207
         con = app.connections[account]
    

  • gajim/common/modules/chatstates.py
    ... ... @@ -171,6 +171,11 @@ class Chatstate:
    171 171
                             if contact is not None:
    
    172 172
                                 contact = contact.as_contact()
    
    173 173
                             else:
    
    174
    +                            # Contact not found, maybe we left the group chat
    
    175
    +                            # or the contact was removed from the roster
    
    176
    +                            log.info(
    
    177
    +                                'Contact %s not found, reset chatstate', jid)
    
    178
    +                            self._chatstates.pop(jid, None)
    
    174 179
                                 self._last_mouse_activity.pop(jid, None)
    
    175 180
                                 self._last_keyboard_activity.pop(jid, None)
    
    176 181
                                 continue
    
    ... ... @@ -206,14 +211,21 @@ class Chatstate:
    206 211
             current_state = self._chatstates.get(contact.jid)
    
    207 212
             setting = app.config.get('outgoing_chat_state_notifications')
    
    208 213
             if setting == 'disabled':
    
    209
    -            # Send a last 'gone' state after user disabled chatstates
    
    214
    +            # Send a last 'active' state after user disabled chatstates
    
    210 215
                 if current_state is not None:
    
    211
    -                log.info('Send: %-10s - %s', State.GONE, contact.jid)
    
    212
    -                app.nec.push_outgoing_event(
    
    213
    -                    MessageOutgoingEvent(None,
    
    214
    -                                         account=self._account,
    
    215
    -                                         jid=contact.jid,
    
    216
    -                                         chatstate=str(State.GONE)))
    
    216
    +                log.info('Send: %-10s - %s', State.ACTIVE, contact.jid)
    
    217
    +
    
    218
    +                event_attrs = {'account': self._account,
    
    219
    +                               'jid': contact.jid,
    
    220
    +                               'chatstate': str(State.ACTIVE)}
    
    221
    +
    
    222
    +                if contact.is_groupchat():
    
    223
    +                    app.nec.push_outgoing_event(
    
    224
    +                        GcMessageOutgoingEvent(None, **event_attrs))
    
    225
    +                else:
    
    226
    +                    app.nec.push_outgoing_event(
    
    227
    +                        MessageOutgoingEvent(None, **event_attrs))
    
    228
    +
    
    217 229
                 self._chatstates.pop(contact.jid, None)
    
    218 230
                 self._last_mouse_activity.pop(contact.jid, None)
    
    219 231
                 self._last_keyboard_activity.pop(contact.jid, None)
    

  • gajim/common/modules/mam.py
    ... ... @@ -21,6 +21,7 @@ from datetime import datetime, timedelta
    21 21
     import nbxmpp
    
    22 22
     
    
    23 23
     from gajim.common import app
    
    24
    +from gajim.common.nec import NetworkEvent
    
    24 25
     from gajim.common.nec import NetworkIncomingEvent
    
    25 26
     from gajim.common.const import ArchiveState
    
    26 27
     from gajim.common.const import KindConstant
    
    ... ... @@ -65,9 +66,11 @@ class MAM:
    65 66
     
    
    66 67
             self.available = True
    
    67 68
             log.info('Discovered MAM %s: %s', self.archiving_namespace, from_)
    
    68
    -        # TODO: Move this GUI code out
    
    69
    -        action = app.app.lookup_action('%s-archive' % self._account)
    
    70
    -        action.set_enabled(True)
    
    69
    +
    
    70
    +        app.nec.push_incoming_event(
    
    71
    +            NetworkEvent('feature-discovered',
    
    72
    +                         account=self._account,
    
    73
    +                         feature=self.archiving_namespace))
    
    71 74
     
    
    72 75
         def _from_valid_archive(self, stanza, message, groupchat):
    
    73 76
             if groupchat:
    

  • gajim/common/modules/message.py
    ... ... @@ -28,7 +28,6 @@ from gajim.common.helpers import AdditionalDataDict
    28 28
     from gajim.common.modules.security_labels import parse_securitylabel
    
    29 29
     from gajim.common.modules.user_nickname import parse_nickname
    
    30 30
     from gajim.common.modules.carbons import parse_carbon
    
    31
    -from gajim.common.modules.bits_of_binary import parse_bob_data
    
    32 31
     from gajim.common.modules.misc import parse_delay
    
    33 32
     from gajim.common.modules.misc import parse_eme
    
    34 33
     from gajim.common.modules.misc import parse_correction
    
    ... ... @@ -58,7 +57,8 @@ class Message:
    58 57
                                             nbxmpp.NS_MAM_1,
    
    59 58
                                             nbxmpp.NS_MAM_2,
    
    60 59
                                             nbxmpp.NS_CONFERENCE,
    
    61
    -                                        nbxmpp.NS_IBB])
    
    60
    +                                        nbxmpp.NS_IBB,
    
    61
    +                                        nbxmpp.NS_CAPTCHA,])
    
    62 62
     
    
    63 63
         def _message_received(self, _con, stanza):
    
    64 64
             # https://tools.ietf.org/html/rfc6120#section-8.1.1.1
    
    ... ... @@ -259,8 +259,6 @@ class Message:
    259 259
                 event.additional_data.set_value(
    
    260 260
                     'gajim', 'user_timestamp', user_timestamp)
    
    261 261
     
    
    262
    -        parse_bob_data(event.stanza)
    
    263
    -
    
    264 262
             event_attr = {
    
    265 263
                 'popup': False,
    
    266 264
                 'msg_log_id': None,
    

  • gajim/common/modules/muc.py
    ... ... @@ -22,11 +22,13 @@ import weakref
    22 22
     import nbxmpp
    
    23 23
     
    
    24 24
     from gajim.common import i18n
    
    25
    -from gajim.common.modules import dataforms
    
    26 25
     from gajim.common import app
    
    27 26
     from gajim.common import helpers
    
    28 27
     from gajim.common.caps_cache import muc_caps_cache
    
    28
    +from gajim.common.nec import NetworkEvent
    
    29 29
     from gajim.common.nec import NetworkIncomingEvent
    
    30
    +from gajim.common.modules import dataforms
    
    31
    +from gajim.common.modules.bits_of_binary import parse_bob_data
    
    30 32
     
    
    31 33
     log = logging.getLogger('gajim.c.m.muc')
    
    32 34
     
    
    ... ... @@ -37,8 +39,11 @@ class MUC:
    37 39
             self._account = con.name
    
    38 40
     
    
    39 41
             self.handlers = [
    
    40
    -            ('message', self._mediated_invite, '', nbxmpp.NS_MUC_USER),
    
    42
    +            ('message', self._on_config_change, '', nbxmpp.NS_MUC_USER),
    
    43
    +            ('message', self._mediated_invite, 'normal', nbxmpp.NS_MUC_USER),
    
    41 44
                 ('message', self._direct_invite, '', nbxmpp.NS_CONFERENCE),
    
    45
    +            ('message', self._on_captcha_challenge, '', nbxmpp.NS_CAPTCHA),
    
    46
    +            ('message', self._on_voice_request, '', nbxmpp.NS_DATA, 45),
    
    42 47
             ]
    
    43 48
     
    
    44 49
         def pass_disco(self, from_, identities, features, _data, _node):
    
    ... ... @@ -110,6 +115,62 @@ class MUC:
    110 115
             log.info('Set subject for %s', room_jid)
    
    111 116
             self._con.connection.send(message)
    
    112 117
     
    
    118
    +    def _on_voice_request(self, _con, stanza):
    
    119
    +        data_form = stanza.getTag('x', namespace=nbxmpp.NS_DATA)
    
    120
    +        if data_form is None:
    
    121
    +            return
    
    122
    +
    
    123
    +        if stanza.getBody():
    
    124
    +            return
    
    125
    +
    
    126
    +        room_jid = str(stanza.getFrom())
    
    127
    +        contact = app.contacts.get_groupchat_contact(self._account, room_jid)
    
    128
    +        if contact is None:
    
    129
    +            return
    
    130
    +
    
    131
    +        data_form = dataforms.extend_form(data_form)
    
    132
    +        try:
    
    133
    +            if data_form['FORM_TYPE'].value != nbxmpp.NS_MUC_REQUEST:
    
    134
    +                return
    
    135
    +        except KeyError:
    
    136
    +            return
    
    137
    +
    
    138
    +        app.nec.push_incoming_event(
    
    139
    +            NetworkEvent('voice-approval',
    
    140
    +                         account=self._account,
    
    141
    +                         room_jid=room_jid,
    
    142
    +                         form=data_form))
    
    143
    +        raise nbxmpp.NodeProcessed
    
    144
    +
    
    145
    +    def _on_captcha_challenge(self, _con, stanza):
    
    146
    +        captcha = stanza.getTag('captcha', namespace=nbxmpp.NS_CAPTCHA)
    
    147
    +        if captcha is None:
    
    148
    +            return
    
    149
    +
    
    150
    +        parse_bob_data(stanza)
    
    151
    +        room_jid = str(stanza.getFrom())
    
    152
    +        contact = app.contacts.get_groupchat_contact(self._account, room_jid)
    
    153
    +        if contact is None:
    
    154
    +            return
    
    155
    +
    
    156
    +        log.info('Captcha challenge received from %s', room_jid)
    
    157
    +        data_form = captcha.getTag('x', namespace=nbxmpp.NS_DATA)
    
    158
    +        data_form = dataforms.extend_form(node=data_form)
    
    159
    +        app.nec.push_incoming_event(
    
    160
    +            NetworkEvent('captcha-challenge',
    
    161
    +                         account=self._account,
    
    162
    +                         room_jid=room_jid,
    
    163
    +                         form=data_form))
    
    164
    +        raise nbxmpp.NodeProcessed
    
    165
    +
    
    166
    +    def send_captcha(self, room_jid, form_node):
    
    167
    +        if not app.account_is_connected(self._account):
    
    168
    +            return
    
    169
    +        iq = nbxmpp.Iq(typ='set', to=room_jid)
    
    170
    +        captcha = iq.addChild(name='captcha', namespace=nbxmpp.NS_CAPTCHA)
    
    171
    +        captcha.addChild(node=form_node)
    
    172
    +        self._con.connection.send(iq)
    
    173
    +
    
    113 174
         def request_config(self, room_jid):
    
    114 175
             if not app.account_is_connected(self._account):
    
    115 176
                 return
    
    ... ... @@ -154,6 +215,41 @@ class MUC:
    154 215
             self._con.connection.SendAndCallForResponse(
    
    155 216
                 iq, self._default_response, {})
    
    156 217
     
    
    218
    +    def _on_config_change(self, _con, stanza):
    
    219
    +        muc_user = stanza.getTag('x', namespace=nbxmpp.NS_MUC_USER)
    
    220
    +        if muc_user is None:
    
    221
    +            return
    
    222
    +
    
    223
    +        if stanza.getBody():
    
    224
    +            return
    
    225
    +
    
    226
    +        room_list = app.contacts.get_gc_list(self._account)
    
    227
    +        room_jid = str(stanza.getFrom())
    
    228
    +        if room_jid not in room_list:
    
    229
    +            # Message not from a group chat
    
    230
    +            return
    
    231
    +
    
    232
    +        # https://xmpp.org/extensions/xep-0045.html#registrar-statuscodes
    
    233
    +        change_codes = ['100', '102', '103', '104',
    
    234
    +                        '170', '171', '172', '173', '174']
    
    235
    +
    
    236
    +        codes = set()
    
    237
    +        for status in muc_user.getTags('status'):
    
    238
    +            code = status.getAttr('code')
    
    239
    +            if code in change_codes:
    
    240
    +                codes.add(code)
    
    241
    +
    
    242
    +        if not codes:
    
    243
    +            return
    
    244
    +
    
    245
    +        log.info('Received config change: %s', codes)
    
    246
    +        app.nec.push_incoming_event(
    
    247
    +            NetworkEvent('gc-config-changed-received',
    
    248
    +                         account=self._account,
    
    249
    +                         room_jid=room_jid,
    
    250
    +                         status_codes=codes))
    
    251
    +        raise nbxmpp.NodeProcessed
    
    252
    +
    
    157 253
         def destroy(self, room_jid, reason='', jid=''):
    
    158 254
             if not app.account_is_connected(self._account):
    
    159 255
                 return
    
    ... ... @@ -272,6 +368,9 @@ class MUC:
    272 368
             if stanza.getType() == 'error':
    
    273 369
                 return
    
    274 370
     
    
    371
    +        if stanza.getBody():
    
    372
    +            return
    
    373
    +
    
    275 374
             decline = muc_user.getTag('decline')
    
    276 375
             if decline is not None:
    
    277 376
     
    

  • gajim/common/modules/privacylists.py
    ... ... @@ -20,6 +20,7 @@ import nbxmpp
    20 20
     
    
    21 21
     from gajim.common import app
    
    22 22
     from gajim.common import helpers
    
    23
    +from gajim.common.nec import NetworkEvent
    
    23 24
     from gajim.common.nec import NetworkIncomingEvent
    
    24 25
     from gajim.common.connection_handlers_events import InformationEvent
    
    25 26
     
    
    ... ... @@ -51,9 +52,11 @@ class PrivacyLists:
    51 52
     
    
    52 53
             self.supported = True
    
    53 54
             log.info('Discovered XEP-0016: Privacy Lists: %s', from_)
    
    54
    -        # TODO: Move this GUI code out
    
    55
    -        action = app.app.lookup_action('%s-privacylists' % self._account)
    
    56
    -        action.set_enabled(True)
    
    55
    +
    
    56
    +        app.nec.push_incoming_event(
    
    57
    +            NetworkEvent('feature-discovered',
    
    58
    +                         account=self._account,
    
    59
    +                         feature=nbxmpp.NS_PRIVACY))
    
    57 60
     
    
    58 61
         def _list_push_received(self, _con, stanza):
    
    59 62
             result = stanza.buildReply('result')
    

  • gajim/common/modules/vcard_temp.py
    ... ... @@ -23,6 +23,7 @@ import nbxmpp
    23 23
     
    
    24 24
     from gajim.common import app
    
    25 25
     from gajim.common.const import RequestAvatar
    
    26
    +from gajim.common.nec import NetworkEvent
    
    26 27
     from gajim.common.nec import NetworkIncomingEvent
    
    27 28
     from gajim.common.connection_handlers_events import InformationEvent
    
    28 29
     
    
    ... ... @@ -47,9 +48,10 @@ class VCardTemp:
    47 48
     
    
    48 49
             self.supported = True
    
    49 50
             log.info('Discovered vcard-temp: %s', from_)
    
    50
    -        # TODO: Move this GUI code out
    
    51
    -        action = app.app.lookup_action('%s-profile' % self._account)
    
    52
    -        action.set_enabled(True)
    
    51
    +
    
    52
    +        app.nec.push_incoming_event(NetworkEvent('feature-discovered',
    
    53
    +                                                 account=self._account,
    
    54
    +                                                 feature=nbxmpp.NS_VCARD))
    
    53 55
     
    
    54 56
         @staticmethod
    
    55 57
         def _node_to_dict(node):
    

  • gajim/gajim.py
    ... ... @@ -24,10 +24,9 @@ from ctypes import CDLL, byref, create_string_buffer
    24 24
     from ctypes.util import find_library
    
    25 25
     from distutils.version import LooseVersion as V
    
    26 26
     
    
    27
    -# Install _() in namespace
    
    28 27
     from gajim.common import i18n
    
    29 28
     
    
    30
    -_MIN_NBXMPP_VER = "0.9.90"
    
    29
    +_MIN_NBXMPP_VER = "0.9.90.2"
    
    31 30
     _MIN_GTK_VER = "3.22.0"
    
    32 31
     
    
    33 32
     
    

  • gajim/groupchat_control.py
    ... ... @@ -44,7 +44,6 @@ from gajim import gtkgui_helpers
    44 44
     from gajim import gui_menu_builder
    
    45 45
     from gajim import message_control
    
    46 46
     from gajim import vcard
    
    47
    -from gajim import dataforms_widget
    
    48 47
     
    
    49 48
     from gajim.common.const import AvatarSize
    
    50 49
     from gajim.common.caps_cache import muc_caps_cache
    
    ... ... @@ -53,7 +52,6 @@ from gajim.common import app
    53 52
     from gajim.common import helpers
    
    54 53
     from gajim.common.helpers import launch_browser_mailer
    
    55 54
     from gajim.common.helpers import AdditionalDataDict
    
    56
    -from gajim.common.modules import dataforms
    
    57 55
     from gajim.common import ged
    
    58 56
     from gajim.common import i18n
    
    59 57
     from gajim.common.i18n import _
    
    ... ... @@ -72,11 +70,13 @@ from gajim.gtk.dialogs import ConfirmationDialogCheck
    72 70
     from gajim.gtk.dialogs import DoubleInputDialog
    
    73 71
     from gajim.gtk.dialogs import InputDialog
    
    74 72
     from gajim.gtk.dialogs import ChangeNickDialog
    
    73
    +from gajim.gtk.single_message import SingleMessageWindow
    
    75 74
     from gajim.gtk.filechoosers import AvatarChooserDialog
    
    76 75
     from gajim.gtk.add_contact import AddNewContactWindow
    
    77 76
     from gajim.gtk.tooltips import GCTooltip
    
    78 77
     from gajim.gtk.groupchat_config import GroupchatConfig
    
    79 78
     from gajim.gtk.adhoc_commands import CommandWindow
    
    79
    +from gajim.gtk.dataform import DataFormWidget
    
    80 80
     from gajim.gtk.util import NickCompletionGenerator
    
    81 81
     from gajim.gtk.util import get_icon_name
    
    82 82
     from gajim.gtk.util import get_affiliation_surface
    
    ... ... @@ -330,6 +330,10 @@ class GroupchatControl(ChatControlBase):
    330 330
                 self._nec_decrypted_message_received)
    
    331 331
             app.ged.register_event_handler('gc-stanza-message-outgoing', ged.OUT_POSTCORE,
    
    332 332
                 self._message_sent)
    
    333
    +        app.ged.register_event_handler('captcha-challenge', ged.GUI1,
    
    334
    +                                       self._on_captcha_challenge)
    
    335
    +        app.ged.register_event_handler('voice-approval', ged.GUI1,
    
    336
    +                                       self._on_voice_approval)
    
    333 337
             self.is_connected = False
    
    334 338
             # disable win, we are not connected yet
    
    335 339
             ChatControlBase.got_disconnected(self)
    
    ... ... @@ -1073,6 +1077,59 @@ class GroupchatControl(ChatControlBase):
    1073 1077
                 return
    
    1074 1078
             self._update_banner_state_image()
    
    1075 1079
     
    
    1080
    +    def _on_voice_approval(self, event):
    
    1081
    +        if event.account != self.account:
    
    1082
    +            return
    
    1083
    +        if event.room_jid != self.room_jid:
    
    1084
    +            return
    
    1085
    +        SingleMessageWindow(self.account,
    
    1086
    +                            self.room_jid,
    
    1087
    +                            action='receive',
    
    1088
    +                            from_whom=self.room_jid,
    
    1089
    +                            form_node=event.form)
    
    1090
    +
    
    1091
    +    def _on_captcha_challenge(self, event):
    
    1092
    +        if event.account != self.account:
    
    1093
    +            return
    
    1094
    +        if event.room_jid != self.room_jid:
    
    1095
    +            return
    
    1096
    +
    
    1097
    +        if self.form_widget:
    
    1098
    +            self.form_widget.hide()
    
    1099
    +            self.form_widget.destroy()
    
    1100
    +            self.btn_box.destroy()
    
    1101
    +
    
    1102
    +        self.form_widget = DataFormWidget(event.form)
    
    1103
    +
    
    1104
    +        def on_send_dataform_clicked(widget):
    
    1105
    +            if not self.form_widget:
    
    1106
    +                return
    
    1107
    +            form_node = self.form_widget.get_submit_form()
    
    1108
    +            con = app.connections[self.account]
    
    1109
    +            con.get_module('MUC').send_captcha(self.room_jid, form_node)
    
    1110
    +            self.form_widget.hide()
    
    1111
    +            self.form_widget.destroy()
    
    1112
    +            self.btn_box.destroy()
    
    1113
    +            self.form_widget = None
    
    1114
    +            del self.btn_box
    
    1115
    +
    
    1116
    +        # self.form_widget.connect('validated', on_send_dataform_clicked)
    
    1117
    +        self.form_widget.show_all()
    
    1118
    +        vbox = self.xml.get_object('gc_textviews_vbox')
    
    1119
    +        vbox.pack_start(self.form_widget, False, True, 0)
    
    1120
    +
    
    1121
    +        valid_button = Gtk.Button(stock=Gtk.STOCK_OK)
    
    1122
    +        valid_button.connect('clicked', on_send_dataform_clicked)
    
    1123
    +        self.btn_box = Gtk.HButtonBox()
    
    1124
    +        self.btn_box.set_layout(Gtk.ButtonBoxStyle.END)
    
    1125
    +        self.btn_box.pack_start(valid_button, True, True, 0)
    
    1126
    +        self.btn_box.show_all()
    
    1127
    +        vbox.pack_start(self.btn_box, False, False, 0)
    
    1128
    +        if self.parent_win:
    
    1129
    +            self.parent_win.redraw_tab(self, 'attention')
    
    1130
    +        else:
    
    1131
    +            self.attention_flag = True
    
    1132
    +
    
    1076 1133
         def _nec_mam_decrypted_message_received(self, obj):
    
    1077 1134
             if obj.conn.name != self.account:
    
    1078 1135
                 return
    
    ... ... @@ -1090,45 +1147,7 @@ class GroupchatControl(ChatControlBase):
    1090 1147
         def _nec_gc_message_received(self, obj):
    
    1091 1148
             if obj.room_jid != self.room_jid or obj.conn.name != self.account:
    
    1092 1149
                 return
    
    1093
    -        if obj.captcha_form:
    
    1094
    -            if self.form_widget:
    
    1095
    -                self.form_widget.hide()
    
    1096
    -                self.form_widget.destroy()
    
    1097
    -                self.btn_box.destroy()
    
    1098
    -            dataform = dataforms.extend_form(node=obj.captcha_form)
    
    1099
    -            self.form_widget = dataforms_widget.DataFormWidget(dataform)
    
    1100
    -
    
    1101
    -            def on_send_dataform_clicked(widget):
    
    1102
    -                if not self.form_widget:
    
    1103
    -                    return
    
    1104
    -                form_node = self.form_widget.data_form.get_purged()
    
    1105
    -                form_node.type_ = 'submit'
    
    1106
    -                obj.conn.send_captcha(self.room_jid, form_node)
    
    1107
    -                self.form_widget.hide()
    
    1108
    -                self.form_widget.destroy()
    
    1109
    -                self.btn_box.destroy()
    
    1110
    -                self.form_widget = None
    
    1111
    -                del self.btn_box
    
    1112
    -
    
    1113
    -            self.form_widget.connect('validated', on_send_dataform_clicked)
    
    1114
    -            self.form_widget.show_all()
    
    1115
    -            vbox = self.xml.get_object('gc_textviews_vbox')
    
    1116
    -            vbox.pack_start(self.form_widget, False, True, 0)
    
    1117
    -
    
    1118
    -            valid_button = Gtk.Button(stock=Gtk.STOCK_OK)
    
    1119
    -            valid_button.connect('clicked', on_send_dataform_clicked)
    
    1120
    -            self.btn_box = Gtk.HButtonBox()
    
    1121
    -            self.btn_box.set_layout(Gtk.ButtonBoxStyle.END)
    
    1122
    -            self.btn_box.pack_start(valid_button, True, True, 0)
    
    1123
    -            self.btn_box.show_all()
    
    1124
    -            vbox.pack_start(self.btn_box, False, False, 0)
    
    1125
    -            if self.parent_win:
    
    1126
    -                self.parent_win.redraw_tab(self, 'attention')
    
    1127
    -            else:
    
    1128
    -                self.attention_flag = True
    
    1129
    -        if '100' in obj.status_code:
    
    1130
    -            # Room is not anonymous
    
    1131
    -            self.is_anonymous = False
    
    1150
    +
    
    1132 1151
             if not obj.nick:
    
    1133 1152
                 # message from server
    
    1134 1153
                 self.print_conversation(
    
    ... ... @@ -1416,40 +1435,40 @@ class GroupchatControl(ChatControlBase):
    1416 1435
             else:
    
    1417 1436
                 self.subject_button.show()
    
    1418 1437
     
    
    1419
    -    def _nec_gc_config_changed_received(self, obj):
    
    1420
    -        # statuscode is a list
    
    1438
    +    def _nec_gc_config_changed_received(self, event):
    
    1421 1439
             # http://www.xmpp.org/extensions/xep-0045.html#roomconfig-notify
    
    1422
    -        # http://www.xmpp.org/extensions/xep-0045.html#registrar-statuscodes...
    
    1423
    -        # -init
    
    1424
    -        if obj.room_jid != self.room_jid or obj.conn.name != self.account:
    
    1440
    +        if event.account != self.account:
    
    1441
    +            return
    
    1442
    +
    
    1443
    +        if event.room_jid != self.room_jid:
    
    1425 1444
                 return
    
    1426 1445
     
    
    1427 1446
             changes = []
    
    1428
    -        if '100' in obj.status_code:
    
    1447
    +        if '100' in event.status_codes:
    
    1429 1448
                 # Can be a presence (see chg_contact_status in groupchat_control.py)
    
    1430 1449
                 changes.append(_('Any occupant is allowed to see your full JID'))
    
    1431 1450
                 self.is_anonymous = False
    
    1432
    -        if '102' in obj.status_code:
    
    1451
    +        if '102' in event.status_codes:
    
    1433 1452
                 changes.append(_('Room now shows unavailable members'))
    
    1434
    -        if '103' in obj.status_code:
    
    1453
    +        if '103' in event.status_codes:
    
    1435 1454
                 changes.append(_('Room now does not show unavailable members'))
    
    1436
    -        if '104' in obj.status_code:
    
    1455
    +        if '104' in event.status_codes:
    
    1437 1456
                 changes.append(_('A setting not related to privacy has been '
    
    1438 1457
                                  'changed'))
    
    1439 1458
                 app.connections[self.account].get_module('Discovery').disco_muc(
    
    1440 1459
                     self.room_jid, self.update_actions, update=True)
    
    1441
    -        if '170' in obj.status_code:
    
    1460
    +        if '170' in event.status_codes:
    
    1442 1461
                 # Can be a presence (see chg_contact_status in groupchat_control.py)
    
    1443 1462
                 changes.append(_('Room logging is now enabled'))
    
    1444
    -        if '171' in obj.status_code:
    
    1463
    +        if '171' in event.status_codes:
    
    1445 1464
                 changes.append(_('Room logging is now disabled'))
    
    1446
    -        if '172' in obj.status_code:
    
    1465
    +        if '172' in event.status_codes:
    
    1447 1466
                 changes.append(_('Room is now non-anonymous'))
    
    1448 1467
                 self.is_anonymous = False
    
    1449
    -        if '173' in obj.status_code:
    
    1468
    +        if '173' in event.status_codes:
    
    1450 1469
                 changes.append(_('Room is now semi-anonymous'))
    
    1451 1470
                 self.is_anonymous = True
    
    1452
    -        if '174' in obj.status_code:
    
    1471
    +        if '174' in event.status_codes:
    
    1453 1472
                 changes.append(_('Room is now fully anonymous'))
    
    1454 1473
                 self.is_anonymous = True
    
    1455 1474
     
    
    ... ... @@ -2172,6 +2191,10 @@ class GroupchatControl(ChatControlBase):
    2172 2191
                 ged.GUI1, self._nec_mam_decrypted_message_received)
    
    2173 2192
             app.ged.remove_event_handler('gc-stanza-message-outgoing', ged.OUT_POSTCORE,
    
    2174 2193
                 self._message_sent)
    
    2194
    +        app.ged.remove_event_handler('captcha-challenge', ged.GUI1,
    
    2195
    +                                     self._on_captcha_challenge)
    
    2196
    +        app.ged.remove_event_handler('voice-approval', ged.GUI1,
    
    2197
    +                                     self._on_voice_approval)
    
    2175 2198
     
    
    2176 2199
             if self.is_connected:
    
    2177 2200
                 app.connections[self.account].send_gc_status(self.nick,
    

  • gajim/gtk/single_message.py
    ... ... @@ -20,12 +20,11 @@ from gi.repository import GLib
    20 20
     from gajim.common import app
    
    21 21
     from gajim.common import helpers
    
    22 22
     from gajim.common.i18n import _
    
    23
    -from gajim.common.modules import dataforms
    
    24 23
     from gajim.common.connection_handlers_events import MessageOutgoingEvent
    
    25 24
     
    
    26
    -from gajim.dataforms_widget import DataFormWidget
    
    27 25
     from gajim.conversation_textview import ConversationTextview
    
    28 26
     
    
    27
    +from gajim.gtk.dataform import DataFormWidget
    
    29 28
     from gajim.gtk.dialogs import ErrorDialog
    
    30 29
     from gajim.gtk.dialogs import AspellDictError
    
    31 30
     from gajim.gtk.util import get_builder
    
    ... ... @@ -83,9 +82,7 @@ class SingleMessageWindow:
    83 82
             parent_box = self.xml.get_object('conversation_scrolledwindow').\
    
    84 83
                                get_parent()
    
    85 84
             if form_node:
    
    86
    -            dataform = dataforms.extend_form(node=form_node)
    
    87
    -            dataform.type_ = 'submit'
    
    88
    -            self.form_widget = DataFormWidget(dataform)
    
    85
    +            self.form_widget = DataFormWidget(form_node)
    
    89 86
                 self.form_widget.show_all()
    
    90 87
                 parent_box.add(self.form_widget)
    
    91 88
                 parent_box.child_set_property(self.form_widget, 'position',
    
    ... ... @@ -282,7 +279,7 @@ class SingleMessageWindow:
    282 279
             message = self.message_tv_buffer.get_text(begin, end, True)
    
    283 280
     
    
    284 281
             if self.form_widget:
    
    285
    -            form_node = self.form_widget.data_form
    
    282
    +            form_node = self.form_widget.get_submit_form()
    
    286 283
             else:
    
    287 284
                 form_node = None
    
    288 285
     
    

  • gajim/remote_control.py
    ... ... @@ -385,8 +385,8 @@ class GajimRemote(Server):
    385 385
                 # event has not been handled at GUI level
    
    386 386
                 return
    
    387 387
             self.raise_signal('GCMessage', (obj.conn.name, [obj.fjid, obj.msgtxt,
    
    388
    -            obj.timestamp, obj.delayed, obj.xhtml_msgtxt, obj.status_code,
    
    389
    -            obj.displaymarking, obj.captcha_form, obj.needs_highlight]))
    
    388
    +            obj.timestamp, obj.delayed, obj.xhtml_msgtxt,
    
    389
    +            obj.displaymarking, obj.needs_highlight]))
    
    390 390
     
    
    391 391
         def on_our_status(self, obj):
    
    392 392
             self.raise_signal('AccountPresence', (obj.show, obj.conn.name))
    

  • setup.cfg
    ... ... @@ -22,7 +22,7 @@ test_suite = test
    22 22
     install_requires =
    
    23 23
         cssutils>=1.0.2
    
    24 24
         keyring
    
    25
    -    nbxmpp>=0.9.90
    
    25
    +    nbxmpp>=0.9.90.2
    
    26 26
         precis-i18n>=1.0.0
    
    27 27
         pyOpenSSL>=0.12
    
    28 28