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

Commits:

17 changed files:

Changes:

  • gajim/common/connection.py
    ... ... @@ -73,6 +73,9 @@ from gajim.common.modules.last_activity import LastActivity
    73 73
     from gajim.common.modules.http_auth import HTTPAuth
    
    74 74
     from gajim.common.modules.vcard_temp import VCardTemp
    
    75 75
     from gajim.common.modules.vcard_avatars import VCardAvatars
    
    76
    +from gajim.common.modules.pubsub import PubSub
    
    77
    +from gajim.common.modules.bookmarks import Bookmarks
    
    78
    +from gajim.common.modules.user_avatar import UserAvatar
    
    76 79
     from gajim.common.connection_handlers import *
    
    77 80
     from gajim.common.contacts import GC_Contact
    
    78 81
     from gajim.gtkgui_helpers import get_action
    
    ... ... @@ -113,7 +116,6 @@ class CommonConnection:
    113 116
             self.old_show = ''
    
    114 117
             self.priority = app.get_priority(name, 'offline')
    
    115 118
             self.time_to_reconnect = None
    
    116
    -        self.bookmarks = []
    
    117 119
     
    
    118 120
             self.blocked_list = []
    
    119 121
             self.blocked_contacts = []
    
    ... ... @@ -491,18 +493,6 @@ class CommonConnection:
    491 493
         def account_changed(self, new_name):
    
    492 494
             self.name = new_name
    
    493 495
     
    
    494
    -    def get_bookmarks(self):
    
    495
    -        """
    
    496
    -        To be implemented by derived classes
    
    497
    -        """
    
    498
    -        raise NotImplementedError
    
    499
    -
    
    500
    -    def store_bookmarks(self):
    
    501
    -        """
    
    502
    -        To be implemented by derived classes
    
    503
    -        """
    
    504
    -        raise NotImplementedError
    
    505
    -
    
    506 496
         def get_metacontacts(self):
    
    507 497
             """
    
    508 498
             To be implemented by derived classes
    
    ... ... @@ -670,6 +660,9 @@ class Connection(CommonConnection, ConnectionHandlers):
    670 660
             self.register_module('HTTPAuth', HTTPAuth, self)
    
    671 661
             self.register_module('VCardTemp', VCardTemp, self)
    
    672 662
             self.register_module('VCardAvatars', VCardAvatars, self)
    
    663
    +        self.register_module('PubSub', PubSub, self)
    
    664
    +        self.register_module('Bookmarks', Bookmarks, self)
    
    665
    +        self.register_module('UserAvatar', UserAvatar, self)
    
    673 666
     
    
    674 667
             app.ged.register_event_handler('privacy-list-received', ged.CORE,
    
    675 668
                 self._nec_privacy_list_received)
    
    ... ... @@ -1774,8 +1767,8 @@ class Connection(CommonConnection, ConnectionHandlers):
    1774 1767
                 # ask our VCard
    
    1775 1768
                 self.get_module('VCardTemp').request_vcard()
    
    1776 1769
     
    
    1777
    -            # Get bookmarks from private namespace
    
    1778
    -            self.get_bookmarks()
    
    1770
    +            # Get bookmarks
    
    1771
    +            self.get_module('Bookmarks').get_bookmarks()
    
    1779 1772
     
    
    1780 1773
                 # Get annotations
    
    1781 1774
                 self.get_module('Annotations').get_annotations()
    
    ... ... @@ -1916,8 +1909,7 @@ class Connection(CommonConnection, ConnectionHandlers):
    1916 1909
                         self.pubsub_publish_options_supported = True
    
    1917 1910
                     else:
    
    1918 1911
                         # Remove stored bookmarks accessible to everyone.
    
    1919
    -                    self.send_pb_purge(our_jid, 'storage:bookmarks')
    
    1920
    -                    self.send_pb_delete(our_jid, 'storage:bookmarks')
    
    1912
    +                    self.get_module('Bookmarks').purge_pubsub_bookmarks()
    
    1921 1913
     
    
    1922 1914
                 if obj.fjid == hostname:
    
    1923 1915
                     if nbxmpp.NS_SECLABEL in obj.features:
    
    ... ... @@ -2255,99 +2247,6 @@ class Connection(CommonConnection, ConnectionHandlers):
    2255 2247
                 return True
    
    2256 2248
             return False
    
    2257 2249
     
    
    2258
    -    def _request_bookmarks_xml(self):
    
    2259
    -        if not app.account_is_connected(self.name):
    
    2260
    -            return
    
    2261
    -        iq = nbxmpp.Iq(typ='get')
    
    2262
    -        iq2 = iq.addChild(name='query', namespace=nbxmpp.NS_PRIVATE)
    
    2263
    -        iq2.addChild(name='storage', namespace='storage:bookmarks')
    
    2264
    -        self.connection.send(iq)
    
    2265
    -        app.log('bookmarks').info('Request Bookmarks (PrivateStorage)')
    
    2266
    -
    
    2267
    -    def _check_bookmarks_received(self):
    
    2268
    -        if not self.bookmarks:
    
    2269
    -            self._request_bookmarks_xml()
    
    2270
    -
    
    2271
    -    def get_bookmarks(self, storage_type=None):
    
    2272
    -        """
    
    2273
    -        Get Bookmarks from storage or PubSub if supported as described in XEP
    
    2274
    -        0048
    
    2275
    -
    
    2276
    -        storage_type can be set to xml to force request to xml storage
    
    2277
    -        """
    
    2278
    -        if not app.account_is_connected(self.name):
    
    2279
    -            return
    
    2280
    -
    
    2281
    -        if storage_type != 'xml':
    
    2282
    -            if self.pep_supported and self.pubsub_publish_options_supported:
    
    2283
    -                self.send_pb_retrieve('', 'storage:bookmarks')
    
    2284
    -                app.log('bookmarks').info('Request Bookmarks (PubSub)')
    
    2285
    -                # some server (ejabberd) are so slow to answer that we
    
    2286
    -                # request via XML if we don't get answer in the next 30 seconds
    
    2287
    -                app.idlequeue.set_alarm(self._check_bookmarks_received, 30)
    
    2288
    -                return
    
    2289
    -
    
    2290
    -        self._request_bookmarks_xml()
    
    2291
    -
    
    2292
    -    def get_bookmarks_storage_node(self):
    
    2293
    -        NS_GAJIM_BM = 'xmpp:gajim.org/bookmarks'
    
    2294
    -        storage_node = nbxmpp.Node(
    
    2295
    -            tag='storage', attrs={'xmlns': 'storage:bookmarks'})
    
    2296
    -        for bm in self.bookmarks:
    
    2297
    -            conf_node = storage_node.addChild(name="conference")
    
    2298
    -            conf_node.setAttr('jid', bm['jid'])
    
    2299
    -            conf_node.setAttr('autojoin', bm['autojoin'])
    
    2300
    -            conf_node.setAttr('name', bm['name'])
    
    2301
    -            conf_node.setTag(
    
    2302
    -                'minimize', namespace=NS_GAJIM_BM).setData(bm['minimize'])
    
    2303
    -            # Only add optional elements if not empty
    
    2304
    -            # Note: need to handle both None and '' as empty
    
    2305
    -            #   thus shouldn't use "is not None"
    
    2306
    -            if bm.get('nick', None):
    
    2307
    -                conf_node.setTagData('nick', bm['nick'])
    
    2308
    -            if bm.get('password', None):
    
    2309
    -                conf_node.setTagData('password', bm['password'])
    
    2310
    -            if bm.get('print_status', None):
    
    2311
    -                conf_node.setTag(
    
    2312
    -                    'print_status',
    
    2313
    -                    namespace=NS_GAJIM_BM).setData(bm['print_status'])
    
    2314
    -        return storage_node
    
    2315
    -
    
    2316
    -    @staticmethod
    
    2317
    -    def get_bookmark_publish_options():
    
    2318
    -        options = nbxmpp.Node(nbxmpp.NS_DATA + ' x',
    
    2319
    -                              attrs={'type': 'submit'})
    
    2320
    -        f = options.addChild('field',
    
    2321
    -                             attrs={'var': 'FORM_TYPE', 'type': 'hidden'})
    
    2322
    -        f.setTagData('value', nbxmpp.NS_PUBSUB_PUBLISH_OPTIONS)
    
    2323
    -        f = options.addChild('field', attrs={'var': 'pubsub#access_model'})
    
    2324
    -        f.setTagData('value', 'whitelist')
    
    2325
    -        return options
    
    2326
    -
    
    2327
    -    def store_bookmarks(self, storage_type=None):
    
    2328
    -        """
    
    2329
    -        Send bookmarks to the storage namespace or PubSub if supported
    
    2330
    -
    
    2331
    -        storage_type can be set to 'pubsub' or 'xml' so store in only one method
    
    2332
    -        else it will be stored on both
    
    2333
    -        """
    
    2334
    -        if not app.account_is_connected(self.name):
    
    2335
    -            return
    
    2336
    -
    
    2337
    -        storage_node = self.get_bookmarks_storage_node()
    
    2338
    -
    
    2339
    -        if storage_type != 'xml':
    
    2340
    -            if self.pep_supported and self.pubsub_publish_options_supported:
    
    2341
    -                self.send_pb_publish(
    
    2342
    -                    '', 'storage:bookmarks', storage_node, 'current',
    
    2343
    -                    options=self.get_bookmark_publish_options())
    
    2344
    -                app.log('bookmarks').info('Bookmarks published (PubSub)')
    
    2345
    -
    
    2346
    -        if storage_type != 'pubsub':
    
    2347
    -            iq = nbxmpp.Iq('set', nbxmpp.NS_PRIVATE, payload=storage_node)
    
    2348
    -            self.connection.send(iq)
    
    2349
    -            app.log('bookmarks').info('Bookmarks published (PrivateStorage)')
    
    2350
    -
    
    2351 2250
         def get_roster_delimiter(self):
    
    2352 2251
             """
    
    2353 2252
             Get roster group delimiter from storage as described in XEP 0083
    
    ... ... @@ -2614,11 +2513,7 @@ class Connection(CommonConnection, ConnectionHandlers):
    2614 2513
                 destroy.setAttr('jid', jid)
    
    2615 2514
             self.connection.send(iq)
    
    2616 2515
             i = 0
    
    2617
    -        for bm in self.bookmarks:
    
    2618
    -            if bm['jid'] == room_jid:
    
    2619
    -                del self.bookmarks[i]
    
    2620
    -                break
    
    2621
    -            i += 1
    
    2516
    +        self.get_module('Bookmarks').bookmarks.pop(jid, None)
    
    2622 2517
             self.store_bookmarks()
    
    2623 2518
     
    
    2624 2519
         def send_gc_status(self, nick, jid, show, status, auto=False):
    

  • gajim/common/connection_handlers.py
    ... ... @@ -50,7 +50,6 @@ from gajim.common import jingle_xtls
    50 50
     from gajim.common import configpaths
    
    51 51
     from gajim.common.caps_cache import muc_caps_cache
    
    52 52
     from gajim.common.commands import ConnectionCommands
    
    53
    -from gajim.common.pubsub import ConnectionPubSub
    
    54 53
     from gajim.common.protocol.caps import ConnectionCaps
    
    55 54
     from gajim.common.protocol.bytestream import ConnectionSocks5Bytestream
    
    56 55
     from gajim.common.protocol.bytestream import ConnectionIBBytestream
    
    ... ... @@ -339,15 +338,15 @@ class ConnectionPEP(object):
    339 338
             if message:
    
    340 339
                 i = item.addChild('text')
    
    341 340
                 i.addData(message)
    
    342
    -        self._pubsub_connection.send_pb_publish('', nbxmpp.NS_ACTIVITY, item,
    
    343
    -            '0')
    
    341
    +        self.get_module('PubSub').send_pb_publish(
    
    342
    +            '', nbxmpp.NS_ACTIVITY, item, '0')
    
    344 343
     
    
    345 344
         def retract_activity(self):
    
    346 345
             if not self.pep_supported:
    
    347 346
                 return
    
    348 347
             self.send_activity(None)
    
    349 348
             # not all client support new XEP, so we still retract
    
    350
    -        self._pubsub_connection.send_pb_retract('', nbxmpp.NS_ACTIVITY, '0')
    
    349
    +        self.get_module('PubSub').send_pb_retract('', nbxmpp.NS_ACTIVITY, '0')
    
    351 350
     
    
    352 351
         def send_mood(self, mood, message=None):
    
    353 352
             if self.connected == 1:
    
    ... ... @@ -363,14 +362,14 @@ class ConnectionPEP(object):
    363 362
             if message:
    
    364 363
                 i = item.addChild('text')
    
    365 364
                 i.addData(message)
    
    366
    -        self._pubsub_connection.send_pb_publish('', nbxmpp.NS_MOOD, item, '0')
    
    365
    +        self.get_module('PubSub').send_pb_publish('', nbxmpp.NS_MOOD, item, '0')
    
    367 366
     
    
    368 367
         def retract_mood(self):
    
    369 368
             if not self.pep_supported:
    
    370 369
                 return
    
    371 370
             self.send_mood(None)
    
    372 371
             # not all client support new XEP, so we still retract
    
    373
    -        self._pubsub_connection.send_pb_retract('', nbxmpp.NS_MOOD, '0')
    
    372
    +        self.get_module('PubSub').send_pb_retract('', nbxmpp.NS_MOOD, '0')
    
    374 373
     
    
    375 374
         def send_tune(self, artist='', title='', source='', track=0, length=0,
    
    376 375
         items=None):
    
    ... ... @@ -399,14 +398,14 @@ class ConnectionPEP(object):
    399 398
                 i.addData(length)
    
    400 399
             if items:
    
    401 400
                 item.addChild(payload=items)
    
    402
    -        self._pubsub_connection.send_pb_publish('', nbxmpp.NS_TUNE, item, '0')
    
    401
    +        self.get_module('PubSub').send_pb_publish('', nbxmpp.NS_TUNE, item, '0')
    
    403 402
     
    
    404 403
         def retract_tune(self):
    
    405 404
             if not self.pep_supported:
    
    406 405
                 return
    
    407 406
             self.send_tune(None)
    
    408 407
             # not all client support new XEP, so we still retract
    
    409
    -        self._pubsub_connection.send_pb_retract('', nbxmpp.NS_TUNE, '0')
    
    408
    +        self.get_module('PubSub').send_pb_retract('', nbxmpp.NS_TUNE, '0')
    
    410 409
     
    
    411 410
         def send_nickname(self, nick):
    
    412 411
             if self.connected == 1:
    
    ... ... @@ -418,13 +417,13 @@ class ConnectionPEP(object):
    418 417
                 return
    
    419 418
             item = nbxmpp.Node('nick', {'xmlns': nbxmpp.NS_NICK})
    
    420 419
             item.addData(nick)
    
    421
    -        self._pubsub_connection.send_pb_publish('', nbxmpp.NS_NICK, item, '0')
    
    420
    +        self.get_module('PubSub').send_pb_publish('', nbxmpp.NS_NICK, item, '0')
    
    422 421
     
    
    423 422
         def retract_nickname(self):
    
    424 423
             if not self.pep_supported:
    
    425 424
                 return
    
    426 425
     
    
    427
    -        self._pubsub_connection.send_pb_retract('', nbxmpp.NS_NICK, '0')
    
    426
    +        self.get_module('PubSub').send_pb_retract('', nbxmpp.NS_NICK, '0')
    
    428 427
     
    
    429 428
         def send_location(self, info):
    
    430 429
             if self.connected == 1:
    
    ... ... @@ -439,14 +438,14 @@ class ConnectionPEP(object):
    439 438
                 if info.get(field, None):
    
    440 439
                     i = item.addChild(field)
    
    441 440
                     i.addData(info[field])
    
    442
    -        self._pubsub_connection.send_pb_publish('', nbxmpp.NS_LOCATION, item, '0')
    
    441
    +        self.get_module('PubSub').send_pb_publish('', nbxmpp.NS_LOCATION, item, '0')
    
    443 442
     
    
    444 443
         def retract_location(self):
    
    445 444
             if not self.pep_supported:
    
    446 445
                 return
    
    447 446
             self.send_location({})
    
    448 447
             # not all client support new XEP, so we still retract
    
    449
    -        self._pubsub_connection.send_pb_retract('', nbxmpp.NS_LOCATION, '0')
    
    448
    +        self.get_module('PubSub').send_pb_retract('', nbxmpp.NS_LOCATION, '0')
    
    450 449
     
    
    451 450
     # basic connection handlers used here and in zeroconf
    
    452 451
     class ConnectionHandlersBase:
    
    ... ... @@ -915,7 +914,7 @@ class ConnectionHandlersBase:
    915 914
     
    
    916 915
     class ConnectionHandlers(ConnectionArchive313,
    
    917 916
     ConnectionSocks5Bytestream, ConnectionDisco,
    
    918
    -ConnectionCommands, ConnectionPubSub, ConnectionPEP, ConnectionCaps,
    
    917
    +ConnectionCommands, ConnectionPEP, ConnectionCaps,
    
    919 918
     ConnectionHandlersBase, ConnectionJingle, ConnectionIBBytestream,
    
    920 919
     ConnectionHTTPUpload):
    
    921 920
         def __init__(self):
    
    ... ... @@ -923,7 +922,6 @@ ConnectionHTTPUpload):
    923 922
             ConnectionSocks5Bytestream.__init__(self)
    
    924 923
             ConnectionIBBytestream.__init__(self)
    
    925 924
             ConnectionCommands.__init__(self)
    
    926
    -        ConnectionPubSub.__init__(self)
    
    927 925
             ConnectionPEP.__init__(self, account=self.name, dispatcher=self,
    
    928 926
                 pubsub_connection=self)
    
    929 927
             ConnectionHTTPUpload.__init__(self)
    
    ... ... @@ -949,8 +947,6 @@ ConnectionHTTPUpload):
    949 947
     
    
    950 948
             self.privacy_default_list = None
    
    951 949
     
    
    952
    -        app.nec.register_incoming_event(PrivateStorageBookmarksReceivedEvent)
    
    953
    -        app.nec.register_incoming_event(BookmarksReceivedEvent)
    
    954 950
             app.nec.register_incoming_event(StreamConflictReceivedEvent)
    
    955 951
             app.nec.register_incoming_event(StreamOtherHostReceivedEvent)
    
    956 952
             app.nec.register_incoming_event(MessageReceivedEvent)
    
    ... ... @@ -961,8 +957,6 @@ ConnectionHTTPUpload):
    961 957
     
    
    962 958
             app.ged.register_event_handler('roster-set-received',
    
    963 959
                 ged.CORE, self._nec_roster_set_received)
    
    964
    -        app.ged.register_event_handler('private-storage-bookmarks-received',
    
    965
    -            ged.CORE, self._nec_private_storate_bookmarks_received)
    
    966 960
             app.ged.register_event_handler('roster-received', ged.CORE,
    
    967 961
                 self._nec_roster_received)
    
    968 962
             app.ged.register_event_handler('iq-error-received', ged.CORE,
    
    ... ... @@ -988,12 +982,9 @@ ConnectionHTTPUpload):
    988 982
             ConnectionHandlersBase.cleanup(self)
    
    989 983
             ConnectionCaps.cleanup(self)
    
    990 984
             ConnectionArchive313.cleanup(self)
    
    991
    -        ConnectionPubSub.cleanup(self)
    
    992 985
             ConnectionHTTPUpload.cleanup(self)
    
    993 986
             app.ged.remove_event_handler('roster-set-received',
    
    994 987
                 ged.CORE, self._nec_roster_set_received)
    
    995
    -        app.ged.remove_event_handler('private-storage-bookmarks-received',
    
    996
    -            ged.CORE, self._nec_private_storate_bookmarks_received)
    
    997 988
             app.ged.remove_event_handler('roster-received', ged.CORE,
    
    998 989
                 self._nec_roster_received)
    
    999 990
             app.ged.remove_event_handler('iq-error-received', ged.CORE,
    
    ... ... @@ -1144,28 +1135,6 @@ ConnectionHTTPUpload):
    1144 1135
                     conn=self, stanza=obj.stanza))
    
    1145 1136
                 return True
    
    1146 1137
     
    
    1147
    -    def _nec_private_storate_bookmarks_received(self, obj):
    
    1148
    -        if obj.conn.name != self.name:
    
    1149
    -            return
    
    1150
    -        app.log('bookmarks').info('Received Bookmarks (PrivateStorage)')
    
    1151
    -        resend_to_pubsub = False
    
    1152
    -        bm_jids = [b['jid'] for b in self.bookmarks]
    
    1153
    -        for bm in obj.bookmarks:
    
    1154
    -            if bm['jid'] not in bm_jids:
    
    1155
    -                self.bookmarks.append(bm)
    
    1156
    -                # We got a bookmark that was not in pubsub
    
    1157
    -                resend_to_pubsub = True
    
    1158
    -        if resend_to_pubsub:
    
    1159
    -            self.store_bookmarks('pubsub')
    
    1160
    -
    
    1161
    -    def _PrivateCB(self, con, iq_obj):
    
    1162
    -        """
    
    1163
    -        Private Data (XEP 048 and 049)
    
    1164
    -        """
    
    1165
    -        log.debug('PrivateCB')
    
    1166
    -        app.nec.push_incoming_event(PrivateStorageReceivedEvent(None,
    
    1167
    -            conn=self, stanza=iq_obj))
    
    1168
    -
    
    1169 1138
         def _SecLabelCB(self, con, iq_obj):
    
    1170 1139
             """
    
    1171 1140
             Security Label callback, used for catalogues.
    
    ... ... @@ -1540,8 +1509,8 @@ ConnectionHTTPUpload):
    1540 1509
                 # ask our VCard
    
    1541 1510
                 self.get_module('VCardTemp').request_vcard()
    
    1542 1511
     
    
    1543
    -        # Get bookmarks from private namespace
    
    1544
    -        self.get_bookmarks()
    
    1512
    +        # Get bookmarks
    
    1513
    +        self.get_module('Bookmarks').get_bookmarks()
    
    1545 1514
     
    
    1546 1515
             # Get annotations from private namespace
    
    1547 1516
             self.get_module('Annotations').get_annotations()
    
    ... ... @@ -1645,7 +1614,6 @@ ConnectionHTTPUpload):
    1645 1614
                 nbxmpp.NS_MUC_OWNER)
    
    1646 1615
             con.RegisterHandler('iq', self._MucAdminCB, 'result',
    
    1647 1616
                 nbxmpp.NS_MUC_ADMIN)
    
    1648
    -        con.RegisterHandler('iq', self._PrivateCB, 'result', nbxmpp.NS_PRIVATE)
    
    1649 1617
             con.RegisterHandler('iq', self._SecLabelCB, 'result',
    
    1650 1618
                 nbxmpp.NS_SECLABEL_CATALOG)
    
    1651 1619
             con.RegisterHandler('iq', self._CommandExecuteCB, 'set',
    
    ... ... @@ -1657,8 +1625,6 @@ ConnectionHTTPUpload):
    1657 1625
             con.RegisterHandler('iq', self._PrivacySetCB, 'set', nbxmpp.NS_PRIVACY)
    
    1658 1626
             con.RegisterHandler('iq', self._ArchiveCB, ns=nbxmpp.NS_MAM_1)
    
    1659 1627
             con.RegisterHandler('iq', self._ArchiveCB, ns=nbxmpp.NS_MAM_2)
    
    1660
    -        con.RegisterHandler('iq', self._PubSubCB, 'result')
    
    1661
    -        con.RegisterHandler('iq', self._PubSubErrorCB, 'error')
    
    1662 1628
             con.RegisterHandler('iq', self._JingleCB, 'result')
    
    1663 1629
             con.RegisterHandler('iq', self._JingleCB, 'error')
    
    1664 1630
             con.RegisterHandler('iq', self._JingleCB, 'set', nbxmpp.NS_JINGLE)
    

  • gajim/common/connection_handlers_events.py
    ... ... @@ -309,118 +309,6 @@ class MucAdminReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
    309 309
                         self.users_dict[jid]['reason'] = reason
    
    310 310
             return True
    
    311 311
     
    
    312
    -class PrivateStorageReceivedEvent(nec.NetworkIncomingEvent):
    
    313
    -    name = 'private-storage-received'
    
    314
    -    base_network_events = []
    
    315
    -
    
    316
    -    def generate(self):
    
    317
    -        query = self.stanza.getTag('query')
    
    318
    -        self.storage_node = query.getTag('storage')
    
    319
    -        if self.storage_node:
    
    320
    -            self.namespace = self.storage_node.getNamespace()
    
    321
    -            return True
    
    322
    -
    
    323
    -
    
    324
    -class BookmarksHelper:
    
    325
    -    def parse_bookmarks(self):
    
    326
    -        self.bookmarks = []
    
    327
    -        NS_GAJIM_BM = 'xmpp:gajim.org/bookmarks'
    
    328
    -        confs = self.storage_node.getTags('conference')
    
    329
    -        for conf in confs:
    
    330
    -            autojoin_val = conf.getAttr('autojoin')
    
    331
    -            if not autojoin_val:  # not there (it's optional)
    
    332
    -                autojoin_val = False
    
    333
    -            minimize_val = conf.getTag('minimize', namespace=NS_GAJIM_BM)
    
    334
    -            if not minimize_val:  # not there, try old Gajim behaviour
    
    335
    -                minimize_val = conf.getAttr('minimize')
    
    336
    -                if not minimize_val:  # not there (it's optional)
    
    337
    -                    minimize_val = False
    
    338
    -            else:
    
    339
    -                minimize_val = minimize_val.getData()
    
    340
    -
    
    341
    -            print_status = conf.getTag('print_status', namespace=NS_GAJIM_BM)
    
    342
    -            if not print_status:  # not there, try old Gajim behaviour
    
    343
    -                print_status = conf.getTagData('print_status')
    
    344
    -                if not print_status:  # not there, try old Gajim behaviour
    
    345
    -                    print_status = conf.getTagData('show_status')
    
    346
    -            else:
    
    347
    -                print_status = print_status.getData()
    
    348
    -
    
    349
    -            try:
    
    350
    -                jid = helpers.parse_jid(conf.getAttr('jid'))
    
    351
    -            except helpers.InvalidFormat:
    
    352
    -                log.warning('Invalid JID: %s, ignoring it'
    
    353
    -                            % conf.getAttr('jid'))
    
    354
    -                continue
    
    355
    -
    
    356
    -            bm = {'name': conf.getAttr('name'),
    
    357
    -                  'jid': jid,
    
    358
    -                  'autojoin': autojoin_val,
    
    359
    -                  'minimize': minimize_val,
    
    360
    -                  'password': conf.getTagData('password'),
    
    361
    -                  'nick': conf.getTagData('nick'),
    
    362
    -                  'print_status': print_status}
    
    363
    -
    
    364
    -            bm_jids = [b['jid'] for b in self.bookmarks]
    
    365
    -            if bm['jid'] not in bm_jids:
    
    366
    -                self.bookmarks.append(bm)
    
    367
    -
    
    368
    -class PrivateStorageBookmarksReceivedEvent(nec.NetworkIncomingEvent,
    
    369
    -BookmarksHelper):
    
    370
    -    name = 'private-storage-bookmarks-received'
    
    371
    -    base_network_events = ['private-storage-received']
    
    372
    -
    
    373
    -    def generate(self):
    
    374
    -        self.conn = self.base_event.conn
    
    375
    -        self.storage_node = self.base_event.storage_node
    
    376
    -        if self.base_event.namespace != nbxmpp.NS_BOOKMARKS:
    
    377
    -            return
    
    378
    -        self.parse_bookmarks()
    
    379
    -        return True
    
    380
    -
    
    381
    -class BookmarksReceivedEvent(nec.NetworkIncomingEvent):
    
    382
    -    name = 'bookmarks-received'
    
    383
    -    base_network_events = ['private-storage-bookmarks-received',
    
    384
    -        'pubsub-bookmarks-received']
    
    385
    -
    
    386
    -    def generate(self):
    
    387
    -        self.conn = self.base_event.conn
    
    388
    -        self.bookmarks = self.base_event.bookmarks
    
    389
    -        return True
    
    390
    -
    
    391
    -class PubsubReceivedEvent(nec.NetworkIncomingEvent):
    
    392
    -    name = 'pubsub-received'
    
    393
    -    base_network_events = []
    
    394
    -
    
    395
    -    def generate(self):
    
    396
    -        self.jid = self.stanza.getFrom()
    
    397
    -        self.pubsub_node = self.stanza.getTag('pubsub')
    
    398
    -        if not self.pubsub_node:
    
    399
    -            return
    
    400
    -        self.items_node = self.pubsub_node.getTag('items')
    
    401
    -        if not self.items_node:
    
    402
    -            return
    
    403
    -        return True
    
    404
    -
    
    405
    -class PubsubBookmarksReceivedEvent(nec.NetworkIncomingEvent, BookmarksHelper):
    
    406
    -    name = 'pubsub-bookmarks-received'
    
    407
    -    base_network_events = ['pubsub-received']
    
    408
    -
    
    409
    -    def generate(self):
    
    410
    -        self.conn = self.base_event.conn
    
    411
    -        self.item_node = self.base_event.items_node.getTag('item')
    
    412
    -        if not self.item_node:
    
    413
    -            return
    
    414
    -        children = self.item_node.getChildren()
    
    415
    -        if not children:
    
    416
    -            return
    
    417
    -        self.storage_node = children[0]
    
    418
    -        ns = self.storage_node.getNamespace()
    
    419
    -        if ns != nbxmpp.NS_BOOKMARKS:
    
    420
    -            return
    
    421
    -        self.parse_bookmarks()
    
    422
    -        return True
    
    423
    -
    
    424 312
     class IqErrorReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
    
    425 313
         name = 'iq-error-received'
    
    426 314
         base_network_events = []
    

  • gajim/common/const.py
    ... ... @@ -119,6 +119,11 @@ class RequestAvatar(IntEnum):
    119 119
         ROOM = 1
    
    120 120
         USER = 2
    
    121 121
     
    
    122
    +@unique
    
    123
    +class BookmarkStorageType(IntEnum):
    
    124
    +    PRIVATE = 0
    
    125
    +    PUBSUB = 1
    
    126
    +
    
    122 127
     SSLError = {
    
    123 128
         2: _("Unable to get issuer certificate"),
    
    124 129
         3: _("Unable to get certificate CRL"),
    

  • gajim/common/modules/bookmarks.py
    1
    +# This file is part of Gajim.
    
    2
    +#
    
    3
    +# Gajim is free software; you can redistribute it and/or modify
    
    4
    +# it under the terms of the GNU General Public License as published
    
    5
    +# by the Free Software Foundation; version 3 only.
    
    6
    +#
    
    7
    +# Gajim is distributed in the hope that it will be useful,
    
    8
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    9
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
    10
    +# GNU General Public License for more details.
    
    11
    +#
    
    12
    +# You should have received a copy of the GNU General Public License
    
    13
    +# along with Gajim.  If not, see <http://www.gnu.org/licenses/>.
    
    14
    +
    
    15
    +# XEP-0048: Bookmarks
    
    16
    +
    
    17
    +import logging
    
    18
    +
    
    19
    +import nbxmpp
    
    20
    +
    
    21
    +from gajim.common import app
    
    22
    +from gajim.common import helpers
    
    23
    +from gajim.common.const import BookmarkStorageType
    
    24
    +from gajim.common.nec import NetworkIncomingEvent
    
    25
    +
    
    26
    +log = logging.getLogger('gajim.c.m.bookmarks')
    
    27
    +
    
    28
    +
    
    29
    +class Bookmarks:
    
    30
    +    def __init__(self, con):
    
    31
    +        self._con = con
    
    32
    +        self._account = con.name
    
    33
    +        self.bookmarks = {}
    
    34
    +
    
    35
    +        self.handlers = []
    
    36
    +
    
    37
    +    def _pubsub_support(self):
    
    38
    +        return (self._con.pep_supported and
    
    39
    +                self._con.pubsub_publish_options_supported)
    
    40
    +
    
    41
    +    def get_bookmarks(self, storage_type=None):
    
    42
    +        if not app.account_is_connected(self._account):
    
    43
    +            return
    
    44
    +
    
    45
    +        if storage_type in (None, BookmarkStorageType.PUBSUB):
    
    46
    +            if self._pubsub_support():
    
    47
    +                self._request_pubsub_bookmarks()
    
    48
    +            else:
    
    49
    +                # Fallback, request private storage
    
    50
    +                self._request_private_bookmarks()
    
    51
    +        else:
    
    52
    +            log.info('Request Bookmarks (PrivateStorage)')
    
    53
    +            self._request_private_bookmarks()
    
    54
    +
    
    55
    +    def _request_pubsub_bookmarks(self):
    
    56
    +        log.info('Request Bookmarks (PubSub)')
    
    57
    +        self._con.get_module('PubSub').send_pb_retrieve(
    
    58
    +            '', 'storage:bookmarks',
    
    59
    +            cb=self._pubsub_bookmarks_received)
    
    60
    +
    
    61
    +    def _pubsub_bookmarks_received(self, conn, stanza):
    
    62
    +        if not nbxmpp.isResultNode(stanza):
    
    63
    +            log.info('No pubsub bookmarks: %s', stanza.getError())
    
    64
    +            # Fallback, request private storage
    
    65
    +            self._request_private_bookmarks()
    
    66
    +            return
    
    67
    +
    
    68
    +        log.info('Received Bookmarks (PubSub)')
    
    69
    +        self._parse_bookmarks(stanza)
    
    70
    +        self._request_private_bookmarks()
    
    71
    +
    
    72
    +    def _request_private_bookmarks(self):
    
    73
    +        if not app.account_is_connected(self._account):
    
    74
    +            return
    
    75
    +
    
    76
    +        iq = nbxmpp.Iq(typ='get')
    
    77
    +        query = iq.addChild(name='query', namespace=nbxmpp.NS_PRIVATE)
    
    78
    +        query.addChild(name='storage', namespace='storage:bookmarks')
    
    79
    +        log.info('Request Bookmarks (PrivateStorage)')
    
    80
    +        self._con.connection.SendAndCallForResponse(
    
    81
    +            iq, self._private_bookmarks_received)
    
    82
    +
    
    83
    +    def _private_bookmarks_received(self, stanza):
    
    84
    +        if not nbxmpp.isResultNode(stanza):
    
    85
    +            log.info('No private bookmarks: %s', stanza.getError())
    
    86
    +        else:
    
    87
    +            log.info('Received Bookmarks (PrivateStorage)')
    
    88
    +            merged = self._parse_bookmarks(stanza, check_merge=True)
    
    89
    +            if merged:
    
    90
    +                log.info('Merge PrivateStorage with PubSub')
    
    91
    +                self.store_bookmarks(BookmarkStorageType.PUBSUB)
    
    92
    +        self.auto_join_bookmarks()
    
    93
    +        app.nec.push_incoming_event(BookmarksReceivedEvent(
    
    94
    +            None, account=self._account))
    
    95
    +
    
    96
    +    @staticmethod
    
    97
    +    def _get_storage_node(stanza):
    
    98
    +        node = stanza.getTag('pubsub', namespace=nbxmpp.NS_PUBSUB)
    
    99
    +        if node is None:
    
    100
    +            node = stanza.getTag('event', namespace=nbxmpp.NS_PUBSUB_EVENT)
    
    101
    +            if node is None:
    
    102
    +                # Private Storage
    
    103
    +                query = stanza.getQuery()
    
    104
    +                if query is None:
    
    105
    +                    return
    
    106
    +                storage = query.getTag('storage',
    
    107
    +                                       namespace=nbxmpp.NS_BOOKMARKS)
    
    108
    +                if storage is None:
    
    109
    +                    return
    
    110
    +                return storage
    
    111
    +
    
    112
    +        items_node = node.getTag('items')
    
    113
    +        if items_node is None:
    
    114
    +            return
    
    115
    +        if items_node.getAttr('node') != nbxmpp.NS_BOOKMARKS:
    
    116
    +            return
    
    117
    +
    
    118
    +        item_node = items_node.getTag('item')
    
    119
    +        if item_node is None:
    
    120
    +            return
    
    121
    +
    
    122
    +        storage = item_node.getTag('storage', namespace=nbxmpp.NS_BOOKMARKS)
    
    123
    +        if storage is None:
    
    124
    +            return
    
    125
    +        return storage
    
    126
    +
    
    127
    +    def _parse_bookmarks(self, stanza, check_merge=False):
    
    128
    +        merged = False
    
    129
    +        storage = self._get_storage_node(stanza)
    
    130
    +        if storage is None:
    
    131
    +            return
    
    132
    +
    
    133
    +        NS_GAJIM_BM = 'xmpp:gajim.org/bookmarks'
    
    134
    +        confs = storage.getTags('conference')
    
    135
    +        for conf in confs:
    
    136
    +            autojoin_val = conf.getAttr('autojoin')
    
    137
    +            if not autojoin_val:  # not there (it's optional)
    
    138
    +                autojoin_val = False
    
    139
    +            minimize_val = conf.getTag('minimize', namespace=NS_GAJIM_BM)
    
    140
    +            if not minimize_val:  # not there, try old Gajim behaviour
    
    141
    +                minimize_val = conf.getAttr('minimize')
    
    142
    +                if not minimize_val:  # not there (it's optional)
    
    143
    +                    minimize_val = False
    
    144
    +            else:
    
    145
    +                minimize_val = minimize_val.getData()
    
    146
    +
    
    147
    +            print_status = conf.getTag('print_status', namespace=NS_GAJIM_BM)
    
    148
    +            if not print_status:  # not there, try old Gajim behaviour
    
    149
    +                print_status = conf.getTagData('print_status')
    
    150
    +                if not print_status:  # not there, try old Gajim behaviour
    
    151
    +                    print_status = conf.getTagData('show_status')
    
    152
    +            else:
    
    153
    +                print_status = print_status.getData()
    
    154
    +
    
    155
    +            try:
    
    156
    +                jid = helpers.parse_jid(conf.getAttr('jid'))
    
    157
    +            except helpers.InvalidFormat:
    
    158
    +                log.warning('Invalid JID: %s, ignoring it'
    
    159
    +                            % conf.getAttr('jid'))
    
    160
    +                continue
    
    161
    +
    
    162
    +            if check_merge:
    
    163
    +                if jid not in self.bookmarks:
    
    164
    +                    merged = True
    
    165
    +
    
    166
    +            log.debug('Found Bookmark: %s', jid)
    
    167
    +            self.bookmarks[jid] = {
    
    168
    +                'name': conf.getAttr('name'),
    
    169
    +                'autojoin': autojoin_val,
    
    170
    +                'minimize': minimize_val,
    
    171
    +                'password': conf.getTagData('password'),
    
    172
    +                'nick': conf.getTagData('nick'),
    
    173
    +                'print_status': print_status}
    
    174
    +
    
    175
    +        return merged
    
    176
    +
    
    177
    +    def _build_storage_node(self):
    
    178
    +        NS_GAJIM_BM = 'xmpp:gajim.org/bookmarks'
    
    179
    +        storage_node = nbxmpp.Node(
    
    180
    +            tag='storage', attrs={'xmlns': 'storage:bookmarks'})
    
    181
    +        for jid, bm in self.bookmarks.items():
    
    182
    +            conf_node = storage_node.addChild(name="conference")
    
    183
    +            conf_node.setAttr('jid', jid)
    
    184
    +            conf_node.setAttr('autojoin', bm['autojoin'])
    
    185
    +            conf_node.setAttr('name', bm['name'])
    
    186
    +            conf_node.setTag(
    
    187
    +                'minimize', namespace=NS_GAJIM_BM).setData(bm['minimize'])
    
    188
    +            # Only add optional elements if not empty
    
    189
    +            # Note: need to handle both None and '' as empty
    
    190
    +            #   thus shouldn't use "is not None"
    
    191
    +            if bm.get('nick', None):
    
    192
    +                conf_node.setTagData('nick', bm['nick'])
    
    193
    +            if bm.get('password', None):
    
    194
    +                conf_node.setTagData('password', bm['password'])
    
    195
    +            if bm.get('print_status', None):
    
    196
    +                conf_node.setTag(
    
    197
    +                    'print_status',
    
    198
    +                    namespace=NS_GAJIM_BM).setData(bm['print_status'])
    
    199
    +        return storage_node
    
    200
    +
    
    201
    +    @staticmethod
    
    202
    +    def get_bookmark_publish_options():
    
    203
    +        options = nbxmpp.Node(nbxmpp.NS_DATA + ' x',
    
    204
    +                              attrs={'type': 'submit'})
    
    205
    +        f = options.addChild('field',
    
    206
    +                             attrs={'var': 'FORM_TYPE', 'type': 'hidden'})
    
    207
    +        f.setTagData('value', nbxmpp.NS_PUBSUB_PUBLISH_OPTIONS)
    
    208
    +        f = options.addChild('field', attrs={'var': 'pubsub#access_model'})
    
    209
    +        f.setTagData('value', 'whitelist')
    
    210
    +        return options
    
    211
    +
    
    212
    +    def store_bookmarks(self, storage_type=None):
    
    213
    +        if not app.account_is_connected(self._account):
    
    214
    +            return
    
    215
    +
    
    216
    +        storage_node = self._build_storage_node()
    
    217
    +
    
    218
    +        if storage_type is None:
    
    219
    +            if self._pubsub_support():
    
    220
    +                self._pubsub_store(storage_node)
    
    221
    +            else:
    
    222
    +                self._private_store(storage_node)
    
    223
    +        elif storage_type == BookmarkStorageType.PUBSUB:
    
    224
    +            if self._pubsub_support():
    
    225
    +                self._pubsub_store(storage_node)
    
    226
    +        elif storage_type == BookmarkStorageType.PRIVATE:
    
    227
    +            self._private_store(storage_node)
    
    228
    +
    
    229
    +    def _pubsub_store(self, storage_node):
    
    230
    +        self._con.get_module('PubSub').send_pb_publish(
    
    231
    +            '', 'storage:bookmarks', storage_node, 'current',
    
    232
    +            options=self.get_bookmark_publish_options(),
    
    233
    +            cb=self._pubsub_store_result)
    
    234
    +        log.info('Publish Bookmarks (PubSub)')
    
    235
    +
    
    236
    +    def _private_store(self, storage_node):
    
    237
    +        iq = nbxmpp.Iq('set', nbxmpp.NS_PRIVATE, payload=storage_node)
    
    238
    +        log.info('Publish Bookmarks (PrivateStorage)')
    
    239
    +        self._con.connection.SendAndCallForResponse(
    
    240
    +            iq, self._private_store_result)
    
    241
    +
    
    242
    +    def _pubsub_store_result(self, conn, stanza):
    
    243
    +        if not nbxmpp.isResultNode(stanza):
    
    244
    +            log.error('Error: %s', stanza.getError())
    
    245
    +            return
    
    246
    +
    
    247
    +    def _private_store_result(self, stanza):
    
    248
    +        if not nbxmpp.isResultNode(stanza):
    
    249
    +            log.error('Error: %s', stanza.getError())
    
    250
    +            return
    
    251
    +
    
    252
    +    def auto_join_bookmarks(self):
    
    253
    +        if app.is_invisible(self._account):
    
    254
    +            return
    
    255
    +        for jid, bm in self.bookmarks.items():
    
    256
    +            if bm['autojoin'] in ('1', 'true'):
    
    257
    +                # Only join non-opened groupchats. Opened one are already
    
    258
    +                # auto-joined on re-connection
    
    259
    +                if jid not in app.gc_connected[self._account]:
    
    260
    +                    # we are not already connected
    
    261
    +                    minimize = bm['minimize'] in ('1', 'true')
    
    262
    +                    app.interface.join_gc_room(
    
    263
    +                        self._account, jid, bm['nick'],
    
    264
    +                        bm['password'], minimize=minimize)
    
    265
    +
    
    266
    +    def add_bookmark(self, name, jid, autojoin,
    
    267
    +                     minimize, password, nick):
    
    268
    +        self.bookmarks[jid] = {
    
    269
    +            'name': name,
    
    270
    +            'autojoin': autojoin,
    
    271
    +            'minimize': minimize,
    
    272
    +            'password': password,
    
    273
    +            'nick': nick}
    
    274
    +
    
    275
    +        self.store_bookmarks()
    
    276
    +        app.nec.push_incoming_event(BookmarksReceivedEvent(
    
    277
    +            None, account=self._account))
    
    278
    +
    
    279
    +    def get_name_from_bookmark(self, jid):
    
    280
    +        try:
    
    281
    +            return self.bookmarks[jid]['name']
    
    282
    +        except KeyError:
    
    283
    +            return jid.split('@')[0]
    
    284
    +
    
    285
    +    def purge_pubsub_bookmarks(self):
    
    286
    +        log.info('Purge/Delete Bookmarks on PubSub, '
    
    287
    +                 'because publish options are not available')
    
    288
    +        self._con.get_module('PubSub').send_pb_purge('', 'storage:bookmarks')
    
    289
    +        self._con.get_module('PubSub').send_pb_delete('', 'storage:bookmarks')
    
    290
    +
    
    291
    +
    
    292
    +class BookmarksReceivedEvent(NetworkIncomingEvent):
    
    293
    +    name = 'bookmarks-received'
    
    294
    +    base_network_events = []

  • gajim/common/modules/pubsub.py
    1
    +# Copyright (C) 2006 Tomasz Melcer <liori AT exroot.org>
    
    2
    +# Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org>
    
    3
    +# Copyright (C) 2007 Jean-Marie Traissard <jim AT lapin.org>
    
    4
    +# Copyright (C) 2008 Stephan Erb <steve-e AT h3c.de>
    
    5
    +# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
    
    6
    +#
    
    7
    +# This file is part of Gajim.
    
    8
    +#
    
    9
    +# Gajim is free software; you can redistribute it and/or modify
    
    10
    +# it under the terms of the GNU General Public License as published
    
    11
    +# by the Free Software Foundation; version 3 only.
    
    12
    +#
    
    13
    +# Gajim is distributed in the hope that it will be useful,
    
    14
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    15
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
    16
    +# GNU General Public License for more details.
    
    17
    +#
    
    18
    +# You should have received a copy of the GNU General Public License
    
    19
    +# along with Gajim.  If not, see <http://www.gnu.org/licenses/>.
    
    20
    +
    
    21
    +# XEP-0060: Publish-Subscribe
    
    22
    +
    
    23
    +import logging
    
    24
    +
    
    25
    +import nbxmpp
    
    26
    +
    
    27
    +from gajim.common import app
    
    28
    +
    
    29
    +log = logging.getLogger('gajim.c.m.pubsub')
    
    30
    +
    
    31
    +
    
    32
    +class PubSub:
    
    33
    +    def __init__(self, con):
    
    34
    +        self._con = con
    
    35
    +        self._account = con.name
    
    36
    +
    
    37
    +        self.handlers = []
    
    38
    +
    
    39
    +    def send_pb_subscription_query(self, jid, cb, **kwargs):
    
    40
    +        if not app.account_is_connected(self._account):
    
    41
    +            return
    
    42
    +
    
    43
    +        query = nbxmpp.Iq('get', to=jid)
    
    44
    +        pb = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
    
    45
    +        pb.addChild('subscriptions')
    
    46
    +
    
    47
    +        self._con.connection.SendAndCallForResponse(query, cb, kwargs)
    
    48
    +
    
    49
    +    def send_pb_subscribe(self, jid, node, cb, **kwargs):
    
    50
    +        if not app.account_is_connected(self._account):
    
    51
    +            return
    
    52
    +
    
    53
    +        our_jid = app.get_jid_from_account(self._account)
    
    54
    +        query = nbxmpp.Iq('set', to=jid)
    
    55
    +        pb = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
    
    56
    +        pb.addChild('subscribe', {'node': node, 'jid': our_jid})
    
    57
    +
    
    58
    +        self._con.connection.SendAndCallForResponse(query, cb, kwargs)
    
    59
    +
    
    60
    +    def send_pb_unsubscribe(self, jid, node, cb, **kwargs):
    
    61
    +        if not app.account_is_connected(self._account):
    
    62
    +            return
    
    63
    +
    
    64
    +        our_jid = app.get_jid_from_account(self._account)
    
    65
    +        query = nbxmpp.Iq('set', to=jid)
    
    66
    +        pb = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
    
    67
    +        pb.addChild('unsubscribe', {'node': node, 'jid': our_jid})
    
    68
    +
    
    69
    +        self._con.connection.SendAndCallForResponse(query, cb, kwargs)
    
    70
    +
    
    71
    +    def send_pb_publish(self, jid, node, item,
    
    72
    +                        id_=None, options=None, cb=None, **kwargs):
    
    73
    +        if not app.account_is_connected(self._account):
    
    74
    +            return
    
    75
    +
    
    76
    +        if cb is None:
    
    77
    +            cb = self._default_callback
    
    78
    +
    
    79
    +        query = nbxmpp.Iq('set', to=jid)
    
    80
    +        e = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
    
    81
    +        p = e.addChild('publish', {'node': node})
    
    82
    +        attrs = {}
    
    83
    +        if id_:
    
    84
    +            attrs = {'id': id_}
    
    85
    +        p.addChild('item', attrs, [item])
    
    86
    +        if options:
    
    87
    +            p = e.addChild('publish-options')
    
    88
    +            p.addChild(node=options)
    
    89
    +
    
    90
    +        self._con.connection.SendAndCallForResponse(query, cb, kwargs)
    
    91
    +
    
    92
    +    @staticmethod
    
    93
    +    def get_pb_retrieve_iq(jid, node, item_id=None):
    
    94
    +        """
    
    95
    +        Get IQ to query items from a node
    
    96
    +        """
    
    97
    +        query = nbxmpp.Iq('get', to=jid)
    
    98
    +        r = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
    
    99
    +        r = r.addChild('items', {'node': node})
    
    100
    +        if item_id is not None:
    
    101
    +            r.addChild('item', {'id': item_id})
    
    102
    +        return query
    
    103
    +
    
    104
    +    def send_pb_retrieve(self, jid, node, item_id=None, cb=None, **kwargs):
    
    105
    +        """
    
    106
    +        Get items from a node
    
    107
    +        """
    
    108
    +        if not app.account_is_connected(self._account):
    
    109
    +            return
    
    110
    +
    
    111
    +        if cb is None:
    
    112
    +            cb = self._default_callback
    
    113
    +
    
    114
    +        query = self.get_pb_retrieve_iq(jid, node, item_id)
    
    115
    +
    
    116
    +        self._con.connection.SendAndCallForResponse(query, cb, kwargs)
    
    117
    +
    
    118
    +    def send_pb_retract(self, jid, node, id_, cb=None, **kwargs):
    
    119
    +        """
    
    120
    +        Delete item from a node
    
    121
    +        """
    
    122
    +        if not app.account_is_connected(self._account):
    
    123
    +            return
    
    124
    +
    
    125
    +        if cb is None:
    
    126
    +            cb = self._default_callback
    
    127
    +
    
    128
    +        query = nbxmpp.Iq('set', to=jid)
    
    129
    +        r = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
    
    130
    +        r = r.addChild('retract', {'node': node, 'notify': '1'})
    
    131
    +        r = r.addChild('item', {'id': id_})
    
    132
    +
    
    133
    +        self._con.connection.SendAndCallForResponse(query, cb, kwargs)
    
    134
    +
    
    135
    +    def send_pb_purge(self, jid, node, cb=None, **kwargs):
    
    136
    +        """
    
    137
    +        Purge node: Remove all items
    
    138
    +        """
    
    139
    +        if not app.account_is_connected(self._account):
    
    140
    +            return
    
    141
    +
    
    142
    +        if cb is None:
    
    143
    +            cb = self._default_callback
    
    144
    +
    
    145
    +        query = nbxmpp.Iq('set', to=jid)
    
    146
    +        d = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
    
    147
    +        d = d.addChild('purge', {'node': node})
    
    148
    +
    
    149
    +        self._con.connection.SendAndCallForResponse(query, cb, kwargs)
    
    150
    +
    
    151
    +    def send_pb_delete(self, jid, node, on_ok=None, on_fail=None):
    
    152
    +        """
    
    153
    +        Delete node
    
    154
    +        """
    
    155
    +        if not app.account_is_connected(self._account):
    
    156
    +            return
    
    157
    +        query = nbxmpp.Iq('set', to=jid)
    
    158
    +        d = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
    
    159
    +        d = d.addChild('delete', {'node': node})
    
    160
    +
    
    161
    +        def response(con, resp, jid, node):
    
    162
    +            if resp.getType() == 'result' and on_ok:
    
    163
    +                on_ok(jid, node)
    
    164
    +            elif on_fail:
    
    165
    +                msg = resp.getErrorMsg()
    
    166
    +                on_fail(jid, node, msg)
    
    167
    +
    
    168
    +        self._con.connection.SendAndCallForResponse(
    
    169
    +            query, response, {'jid': jid, 'node': node})
    
    170
    +
    
    171
    +    def send_pb_create(self, jid, node, cb,
    
    172
    +                       configure=False, configure_form=None):
    
    173
    +        """
    
    174
    +        Create a new node
    
    175
    +        """
    
    176
    +        if not app.account_is_connected(self._account):
    
    177
    +            return
    
    178
    +        query = nbxmpp.Iq('set', to=jid)
    
    179
    +        c = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
    
    180
    +        c = c.addChild('create', {'node': node})
    
    181
    +        if configure:
    
    182
    +            conf = c.addChild('configure')
    
    183
    +            if configure_form is not None:
    
    184
    +                conf.addChild(node=configure_form)
    
    185
    +
    
    186
    +        self._con.connection.SendAndCallForResponse(query, cb)
    
    187
    +
    
    188
    +    def send_pb_configure(self, jid, node, form, cb=None):
    
    189
    +        if not app.account_is_connected(self._account):
    
    190
    +            return
    
    191
    +
    
    192
    +        if cb is None:
    
    193
    +            cb = self._default_callback
    
    194
    +
    
    195
    +        query = nbxmpp.Iq('set', to=jid)
    
    196
    +        c = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
    
    197
    +        c = c.addChild('configure', {'node': node})
    
    198
    +        c.addChild(node=form)
    
    199
    +
    
    200
    +        self._con.connection.SendAndCallForResponse(query, cb)
    
    201
    +
    
    202
    +    def request_pb_configuration(self, jid, node, cb=None):
    
    203
    +        if not app.account_is_connected(self._account):
    
    204
    +            return
    
    205
    +
    
    206
    +        if cb is None:
    
    207
    +            cb = self._default_callback
    
    208
    +
    
    209
    +        query = nbxmpp.Iq('get', to=jid)
    
    210
    +        e = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
    
    211
    +        e = e.addChild('configure', {'node': node})
    
    212
    +
    
    213
    +        self._con.connection.SendAndCallForResponse(query, cb)
    
    214
    +
    
    215
    +    def _default_callback(self, conn, stanza, *args, **kwargs):
    
    216
    +        if not nbxmpp.isResultNode(stanza):
    
    217
    +            log.warning('Error: %s', stanza.getError())

  • gajim/common/modules/user_avatar.py
    1
    +# This file is part of Gajim.
    
    2
    +#
    
    3
    +# Gajim is free software; you can redistribute it and/or modify
    
    4
    +# it under the terms of the GNU General Public License as published
    
    5
    +# by the Free Software Foundation; version 3 only.
    
    6
    +#
    
    7
    +# Gajim is distributed in the hope that it will be useful,
    
    8
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    9
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
    10
    +# GNU General Public License for more details.
    
    11
    +#
    
    12
    +# You should have received a copy of the GNU General Public License
    
    13
    +# along with Gajim.  If not, see <http://www.gnu.org/licenses/>.
    
    14
    +
    
    15
    +# XEP-0084: User Avatar
    
    16
    +
    
    17
    +import logging
    
    18
    +import base64
    
    19
    +import binascii
    
    20
    +
    
    21
    +import nbxmpp
    
    22
    +
    
    23
    +from gajim.common import app
    
    24
    +from gajim.common.exceptions import StanzaMalformed
    
    25
    +
    
    26
    +log = logging.getLogger('gajim.c.m.user_avatar')
    
    27
    +
    
    28
    +
    
    29
    +class UserAvatar:
    
    30
    +    def __init__(self, con):
    
    31
    +        self._con = con
    
    32
    +        self._account = con.name
    
    33
    +
    
    34
    +        self.handlers = []
    
    35
    +
    
    36
    +    def get_pubsub_avatar(self, jid, item_id):
    
    37
    +        log.info('Request: %s %s', jid, item_id)
    
    38
    +        self._con.get_module('PubSub').send_pb_retrieve(
    
    39
    +            jid, 'urn:xmpp:avatar:data', item_id, self._avatar_received)
    
    40
    +
    
    41
    +    def _validate_avatar_node(self, stanza):
    
    42
    +        jid = stanza.getFrom()
    
    43
    +        if jid is None:
    
    44
    +            jid = self._con.get_own_jid().getStripped()
    
    45
    +        else:
    
    46
    +            jid = jid.getStripped()
    
    47
    +
    
    48
    +        if nbxmpp.isErrorNode(stanza):
    
    49
    +            raise StanzaMalformed(stanza.getErrorMsg())
    
    50
    +
    
    51
    +        pubsub_node = stanza.getTag('pubsub')
    
    52
    +        if pubsub_node is None:
    
    53
    +            raise StanzaMalformed('No pubsub node', stanza)
    
    54
    +
    
    55
    +        items_node = pubsub_node.getTag('items')
    
    56
    +        if items_node is None:
    
    57
    +            raise StanzaMalformed('No items node', stanza)
    
    58
    +
    
    59
    +        if items_node.getAttr('node') != 'urn:xmpp:avatar:data':
    
    60
    +            raise StanzaMalformed('Wrong namespace', stanza)
    
    61
    +
    
    62
    +        item = items_node.getTag('item')
    
    63
    +        if item is None:
    
    64
    +            raise StanzaMalformed('No item node', stanza)
    
    65
    +
    
    66
    +        sha = item.getAttr('id')
    
    67
    +        data_tag = item.getTag('data', namespace='urn:xmpp:avatar:data')
    
    68
    +        if sha is None or data_tag is None:
    
    69
    +            raise StanzaMalformed('No id attr or data node found', stanza)
    
    70
    +
    
    71
    +        data = data_tag.getData()
    
    72
    +        if data is None:
    
    73
    +            raise StanzaMalformed('Data node empty', stanza)
    
    74
    +
    
    75
    +        data = base64.b64decode(data.encode('utf-8'))
    
    76
    +
    
    77
    +        return jid, sha, data
    
    78
    +
    
    79
    +    def _avatar_received(self, conn, stanza):
    
    80
    +        try:
    
    81
    +            jid, sha, data = self._validate_avatar_node(stanza)
    
    82
    +        except (StanzaMalformed, binascii.Error) as error:
    
    83
    +            log.warning('Error: %s %s', stanza.getFrom(), error)
    
    84
    +            return
    
    85
    +
    
    86
    +        log.info('Received: %s %s', jid, sha)
    
    87
    +        app.interface.save_avatar(data)
    
    88
    +
    
    89
    +        if self._con.get_own_jid().bareMatch(jid):
    
    90
    +            app.config.set_per('accounts', self._account, 'avatar_sha', sha)
    
    91
    +        else:
    
    92
    +            own_jid = self._con.get_own_jid().getStripped()
    
    93
    +            app.logger.set_avatar_sha(own_jid, jid, sha)
    
    94
    +            app.contacts.set_avatar(self._account, jid, sha)
    
    95
    +
    
    96
    +        app.interface.update_avatar(self._account, jid)

  • gajim/common/pep.py
    ... ... @@ -485,7 +485,8 @@ class AvatarNotificationPEP(AbstractPEP):
    485 485
             for item in items.getTags('item'):
    
    486 486
                 metadata = item.getTag('metadata')
    
    487 487
                 if metadata is None:
    
    488
    -                app.log('avatar').warning('Invalid avatar stanza:\n%s', items)
    
    488
    +                app.log('c.m.user_avatar').warning(
    
    489
    +                    'Invalid avatar stanza:\n%s', items)
    
    489 490
                     break
    
    490 491
                 info = item.getTag('metadata').getTag('info')
    
    491 492
                 if info is not None:
    
    ... ... @@ -498,23 +499,22 @@ class AvatarNotificationPEP(AbstractPEP):
    498 499
             con = app.connections[account]
    
    499 500
             if self.avatar is None:
    
    500 501
                 # Remove avatar
    
    501
    -            app.log('avatar').info('Remove (Pubsub): %s', jid)
    
    502
    +            app.log('c.m.user_avatar').info('Remove: %s', jid)
    
    502 503
                 app.contacts.set_avatar(account, jid, None)
    
    503 504
                 own_jid = con.get_own_jid().getStripped()
    
    504 505
                 app.logger.set_avatar_sha(own_jid, jid, None)
    
    505 506
                 app.interface.update_avatar(account, jid)
    
    506 507
             else:
    
    507 508
                 sha = app.contacts.get_avatar_sha(account, jid)
    
    508
    -            app.log('avatar').info(
    
    509
    -                'Update (Pubsub): %s %s', jid, self.avatar['id'])
    
    509
    +            app.log('c.m.user_avatar').info(
    
    510
    +                'Update: %s %s', jid, self.avatar['id'])
    
    510 511
                 if sha == self.avatar['id']:
    
    511
    -                app.log('avatar').info(
    
    512
    -                    'Avatar already known (Pubsub): %s %s',
    
    512
    +                app.log('c.m.user_avatar').info(
    
    513
    +                    'Avatar already known: %s %s',
    
    513 514
                         jid, self.avatar['id'])
    
    514 515
                     return
    
    515
    -            app.log('avatar').info('Request (Pubsub): %s', jid)
    
    516
    -            con.get_pubsub_avatar(jid, 'urn:xmpp:avatar:data',
    
    517
    -                                  self.avatar['id'])
    
    516
    +            con.get_module('UserAvatar').get_pubsub_avatar(
    
    517
    +                jid, self.avatar['id'])
    
    518 518
     
    
    519 519
     
    
    520 520
     SUPPORTED_PERSONAL_USER_EVENTS = [
    

  • gajim/common/pubsub.py deleted
    1
    -# -*- coding:utf-8 -*-
    
    2
    -## src/common/pubsub.py
    
    3
    -##
    
    4
    -## Copyright (C) 2006 Tomasz Melcer <liori AT exroot.org>
    
    5
    -## Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org>
    
    6
    -## Copyright (C) 2007 Jean-Marie Traissard <jim AT lapin.org>
    
    7
    -## Copyright (C) 2008 Stephan Erb <steve-e AT h3c.de>
    
    8
    -##
    
    9
    -## This file is part of Gajim.
    
    10
    -##
    
    11
    -## Gajim is free software; you can redistribute it and/or modify
    
    12
    -## it under the terms of the GNU General Public License as published
    
    13
    -## by the Free Software Foundation; version 3 only.
    
    14
    -##
    
    15
    -## Gajim is distributed in the hope that it will be useful,
    
    16
    -## but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    17
    -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    
    18
    -## GNU General Public License for more details.
    
    19
    -##
    
    20
    -## You should have received a copy of the GNU General Public License
    
    21
    -## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    22
    -##
    
    23
    -
    
    24
    -import base64
    
    25
    -import binascii
    
    26
    -
    
    27
    -import nbxmpp
    
    28
    -from gajim.common import app
    
    29
    -#TODO: Doesn't work
    
    30
    -#from common.connection_handlers import PEP_CONFIG
    
    31
    -PEP_CONFIG = 'pep_config'
    
    32
    -from gajim.common import ged
    
    33
    -from gajim.common.connection_handlers_events import PubsubReceivedEvent
    
    34
    -from gajim.common.connection_handlers_events import PubsubBookmarksReceivedEvent
    
    35
    -from gajim.common.exceptions import StanzaMalformed
    
    36
    -
    
    37
    -import logging
    
    38
    -log = logging.getLogger('gajim.c.pubsub')
    
    39
    -
    
    40
    -class ConnectionPubSub:
    
    41
    -    def __init__(self):
    
    42
    -        self.__callbacks = {}
    
    43
    -        app.nec.register_incoming_event(PubsubBookmarksReceivedEvent)
    
    44
    -        app.ged.register_event_handler('pubsub-bookmarks-received',
    
    45
    -            ged.CORE, self._nec_pubsub_bookmarks_received)
    
    46
    -
    
    47
    -    def cleanup(self):
    
    48
    -        app.ged.remove_event_handler('pubsub-bookmarks-received',
    
    49
    -            ged.CORE, self._nec_pubsub_bookmarks_received)
    
    50
    -
    
    51
    -    def send_pb_subscription_query(self, jid, cb, *args, **kwargs):
    
    52
    -        if not self.connection or self.connected < 2:
    
    53
    -            return
    
    54
    -        query = nbxmpp.Iq('get', to=jid)
    
    55
    -        pb = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
    
    56
    -        pb.addChild('subscriptions')
    
    57
    -
    
    58
    -        id_ = self.connection.send(query)
    
    59
    -
    
    60
    -        self.__callbacks[id_] = (cb, args, kwargs)
    
    61
    -
    
    62
    -    def send_pb_subscribe(self, jid, node, cb, *args, **kwargs):
    
    63
    -        if not self.connection or self.connected < 2:
    
    64
    -            return
    
    65
    -        our_jid = app.get_jid_from_account(self.name)
    
    66
    -        query = nbxmpp.Iq('set', to=jid)
    
    67
    -        pb = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
    
    68
    -        pb.addChild('subscribe', {'node': node, 'jid': our_jid})
    
    69
    -
    
    70
    -        id_ = self.connection.send(query)
    
    71
    -
    
    72
    -        self.__callbacks[id_] = (cb, args, kwargs)
    
    73
    -
    
    74
    -    def send_pb_unsubscribe(self, jid, node, cb, *args, **kwargs):
    
    75
    -        if not self.connection or self.connected < 2:
    
    76
    -            return
    
    77
    -        our_jid = app.get_jid_from_account(self.name)
    
    78
    -        query = nbxmpp.Iq('set', to=jid)
    
    79
    -        pb = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
    
    80
    -        pb.addChild('unsubscribe', {'node': node, 'jid': our_jid})
    
    81
    -
    
    82
    -        id_ = self.connection.send(query)
    
    83
    -
    
    84
    -        self.__callbacks[id_] = (cb, args, kwargs)
    
    85
    -
    
    86
    -    def send_pb_publish(self, jid, node, item, id_=None, options=None):
    
    87
    -        """
    
    88
    -        Publish item to a node
    
    89
    -        """
    
    90
    -        if not self.connection or self.connected < 2:
    
    91
    -            return
    
    92
    -        query = nbxmpp.Iq('set', to=jid)
    
    93
    -        e = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
    
    94
    -        p = e.addChild('publish', {'node': node})
    
    95
    -        attrs = {}
    
    96
    -        if id_:
    
    97
    -            attrs = {'id': id_}
    
    98
    -        p.addChild('item', attrs, [item])
    
    99
    -        if options:
    
    100
    -            p = e.addChild('publish-options')
    
    101
    -            p.addChild(node=options)
    
    102
    -
    
    103
    -        self.connection.send(query)
    
    104
    -
    
    105
    -    @staticmethod
    
    106
    -    def get_pb_retrieve_iq(jid, node, item_id=None):
    
    107
    -        """
    
    108
    -        Get IQ to query items from a node
    
    109
    -        """
    
    110
    -        query = nbxmpp.Iq('get', to=jid)
    
    111
    -        r = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
    
    112
    -        r = r.addChild('items', {'node': node})
    
    113
    -        if item_id is not None:
    
    114
    -            r.addChild('item', {'id': item_id})
    
    115
    -        return query
    
    116
    -
    
    117
    -    def send_pb_retrieve(self, jid, node, item_id=None, cb=None, *args, **kwargs):
    
    118
    -        """
    
    119
    -        Get items from a node
    
    120
    -        """
    
    121
    -        if not self.connection or self.connected < 2:
    
    122
    -            return
    
    123
    -        query = self.get_pb_retrieve_iq(jid, node, item_id)
    
    124
    -        id_ = self.connection.send(query)
    
    125
    -
    
    126
    -        if cb:
    
    127
    -            self.__callbacks[id_] = (cb, args, kwargs)
    
    128
    -
    
    129
    -    def get_pubsub_avatar(self, jid, node, item_id):
    
    130
    -        query = self.get_pb_retrieve_iq(jid, node, item_id)
    
    131
    -        self.connection.SendAndCallForResponse(
    
    132
    -            query, self._nec_pubsub_avatar_received, {'jid': jid})
    
    133
    -
    
    134
    -    def send_pb_retract(self, jid, node, id_):
    
    135
    -        """
    
    136
    -        Delete item from a node
    
    137
    -        """
    
    138
    -        if not self.connection or self.connected < 2:
    
    139
    -            return
    
    140
    -        query = nbxmpp.Iq('set', to=jid)
    
    141
    -        r = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
    
    142
    -        r = r.addChild('retract', {'node': node, 'notify': '1'})
    
    143
    -        r = r.addChild('item', {'id': id_})
    
    144
    -
    
    145
    -        self.connection.send(query)
    
    146
    -
    
    147
    -    def send_pb_purge(self, jid, node):
    
    148
    -        """
    
    149
    -        Purge node: Remove all items
    
    150
    -        """
    
    151
    -        if not self.connection or self.connected < 2:
    
    152
    -            return
    
    153
    -        query = nbxmpp.Iq('set', to=jid)
    
    154
    -        d = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
    
    155
    -        d = d.addChild('purge', {'node': node})
    
    156
    -
    
    157
    -        self.connection.send(query)
    
    158
    -
    
    159
    -    def send_pb_delete(self, jid, node, on_ok=None, on_fail=None):
    
    160
    -        """
    
    161
    -        Delete node
    
    162
    -        """
    
    163
    -        if not self.connection or self.connected < 2:
    
    164
    -            return
    
    165
    -        query = nbxmpp.Iq('set', to=jid)
    
    166
    -        d = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
    
    167
    -        d = d.addChild('delete', {'node': node})
    
    168
    -
    
    169
    -        def response(con, resp, jid, node):
    
    170
    -            if resp.getType() == 'result' and on_ok:
    
    171
    -                on_ok(jid, node)
    
    172
    -            elif on_fail:
    
    173
    -                msg = resp.getErrorMsg()
    
    174
    -                on_fail(jid, node, msg)
    
    175
    -
    
    176
    -        self.connection.SendAndCallForResponse(query, response, {'jid': jid,
    
    177
    -            'node': node})
    
    178
    -
    
    179
    -    def send_pb_create(self, jid, node, configure=False, configure_form=None):
    
    180
    -        """
    
    181
    -        Create a new node
    
    182
    -        """
    
    183
    -        if not self.connection or self.connected < 2:
    
    184
    -            return
    
    185
    -        query = nbxmpp.Iq('set', to=jid)
    
    186
    -        c = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
    
    187
    -        c = c.addChild('create', {'node': node})
    
    188
    -        if configure:
    
    189
    -            conf = c.addChild('configure')
    
    190
    -            if configure_form is not None:
    
    191
    -                conf.addChild(node=configure_form)
    
    192
    -
    
    193
    -        self.connection.send(query)
    
    194
    -
    
    195
    -    def send_pb_configure(self, jid, node, form):
    
    196
    -        if not self.connection or self.connected < 2:
    
    197
    -            return
    
    198
    -        query = nbxmpp.Iq('set', to=jid)
    
    199
    -        c = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
    
    200
    -        c = c.addChild('configure', {'node': node})
    
    201
    -        c.addChild(node=form)
    
    202
    -
    
    203
    -        self.connection.send(query)
    
    204
    -
    
    205
    -    def _PubSubCB(self, conn, stanza):
    
    206
    -        log.debug('_PubsubCB')
    
    207
    -        try:
    
    208
    -            cb, args, kwargs = self.__callbacks.pop(stanza.getID())
    
    209
    -            cb(conn, stanza, *args, **kwargs)
    
    210
    -        except Exception:
    
    211
    -            pass
    
    212
    -        app.nec.push_incoming_event(PubsubReceivedEvent(None,
    
    213
    -            conn=self, stanza=stanza))
    
    214
    -
    
    215
    -    def _nec_pubsub_bookmarks_received(self, obj):
    
    216
    -        if obj.conn.name != self.name:
    
    217
    -            return
    
    218
    -        app.log('bookmarks').info('Received Bookmarks (PubSub)')
    
    219
    -        bm_jids = [b['jid'] for b in self.bookmarks]
    
    220
    -        for bm in obj.bookmarks:
    
    221
    -            if bm['jid'] not in bm_jids:
    
    222
    -                self.bookmarks.append(bm)
    
    223
    -        # We got bookmarks from pubsub, now get those from xml to merge them
    
    224
    -        self.get_bookmarks(storage_type='xml')
    
    225
    -
    
    226
    -    def _validate_avatar_node(self, stanza):
    
    227
    -        jid = stanza.getFrom()
    
    228
    -        if jid is None:
    
    229
    -            jid = self.get_own_jid().getStripped()
    
    230
    -        else:
    
    231
    -            jid = jid.getStripped()
    
    232
    -
    
    233
    -        if nbxmpp.isErrorNode(stanza):
    
    234
    -            raise StanzaMalformed(stanza.getErrorMsg())
    
    235
    -
    
    236
    -        pubsub_node = stanza.getTag('pubsub')
    
    237
    -        if pubsub_node is None:
    
    238
    -            raise StanzaMalformed('No pubsub node', stanza)
    
    239
    -
    
    240
    -        items_node = pubsub_node.getTag('items')
    
    241
    -        if items_node is None:
    
    242
    -            raise StanzaMalformed('No items node', stanza)
    
    243
    -
    
    244
    -        if items_node.getAttr('node') != 'urn:xmpp:avatar:data':
    
    245
    -            raise StanzaMalformed('Wrong namespace', stanza)
    
    246
    -
    
    247
    -        item = items_node.getTag('item')
    
    248
    -        if item is None:
    
    249
    -            raise StanzaMalformed('No item node', stanza)
    
    250
    -
    
    251
    -        sha = item.getAttr('id')
    
    252
    -        data_tag = item.getTag('data', namespace='urn:xmpp:avatar:data')
    
    253
    -        if sha is None or data_tag is None:
    
    254
    -            raise StanzaMalformed('No id attr or data node found', stanza)
    
    255
    -
    
    256
    -        data = data_tag.getData()
    
    257
    -        if data is None:
    
    258
    -            raise StanzaMalformed('Data node empty', stanza)
    
    259
    -
    
    260
    -        data = base64.b64decode(data.encode('utf-8'))
    
    261
    -
    
    262
    -        return jid, sha, data
    
    263
    -
    
    264
    -    def _nec_pubsub_avatar_received(self, conn, stanza, jid):
    
    265
    -        try:
    
    266
    -            jid, sha, data = self._validate_avatar_node(stanza)
    
    267
    -        except (StanzaMalformed, binascii.Error) as error:
    
    268
    -            app.log('avatar').warning(
    
    269
    -                'Error loading Avatar (Pubsub): %s %s', jid, error)
    
    270
    -            return
    
    271
    -
    
    272
    -        app.log('avatar').info(
    
    273
    -            'Received Avatar (Pubsub): %s %s', jid, sha)
    
    274
    -        app.interface.save_avatar(data)
    
    275
    -
    
    276
    -        if self.get_own_jid().bareMatch(jid):
    
    277
    -            app.config.set_per('accounts', self.name, 'avatar_sha', sha)
    
    278
    -        else:
    
    279
    -            own_jid = self.get_own_jid().getStripped()
    
    280
    -            app.logger.set_avatar_sha(own_jid, jid, sha)
    
    281
    -            app.contacts.set_avatar(self.name, jid, sha)
    
    282
    -
    
    283
    -        app.interface.update_avatar(self.name, jid)
    
    284
    -
    
    285
    -    def _PubSubErrorCB(self, conn, stanza):
    
    286
    -        log.debug('_PubsubErrorCB')
    
    287
    -        pubsub = stanza.getTag('pubsub')
    
    288
    -        if not pubsub:
    
    289
    -            return
    
    290
    -        items = pubsub.getTag('items')
    
    291
    -        if not items:
    
    292
    -            return
    
    293
    -        if items.getAttr('node') == 'storage:bookmarks':
    
    294
    -            # Receiving bookmarks from pubsub failed, so take them from xml
    
    295
    -            self.get_bookmarks(storage_type='xml')
    
    296
    -
    
    297
    -    def request_pb_configuration(self, jid, node):
    
    298
    -        if not self.connection or self.connected < 2:
    
    299
    -            return
    
    300
    -        query = nbxmpp.Iq('get', to=jid)
    
    301
    -        e = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
    
    302
    -        e = e.addChild('configure', {'node': node})
    
    303
    -        id_ = self.connection.getAnID()
    
    304
    -        query.setID(id_)
    
    305
    -        self.awaiting_answers[id_] = (PEP_CONFIG,)
    
    306
    -        self.connection.send(query)

  • gajim/config.py
    ... ... @@ -1900,11 +1900,13 @@ class ManageBookmarksWindow:
    1900 1900
                 iter_ = self.treestore.append(None, [None, account, None, None,
    
    1901 1901
                         None, None, None, None])
    
    1902 1902
     
    
    1903
    -            for bookmark in app.connections[account].bookmarks:
    
    1903
    +            con = app.connections[account]
    
    1904
    +            bookmarks = con.get_module('Bookmarks').bookmarks
    
    1905
    +            for jid, bookmark in bookmarks.items():
    
    1904 1906
                     if not bookmark['name']:
    
    1905 1907
                         # No name was given for this bookmark.
    
    1906 1908
                         # Use the first part of JID instead...
    
    1907
    -                    name = bookmark['jid'].split("@")[0]
    
    1909
    +                    name = jid.split("@")[0]
    
    1908 1910
                         bookmark['name'] = name
    
    1909 1911
     
    
    1910 1912
                     # make '1', '0', 'true', 'false' (or other) to True/False
    
    ... ... @@ -1920,7 +1922,7 @@ class ManageBookmarksWindow:
    1920 1922
                     self.treestore.append(iter_, [
    
    1921 1923
                                     account,
    
    1922 1924
                                     bookmark['name'],
    
    1923
    -                                bookmark['jid'],
    
    1925
    +                                jid,
    
    1924 1926
                                     autojoin,
    
    1925 1927
                                     minimize,
    
    1926 1928
                                     bookmark['password'],
    
    ... ... @@ -2047,15 +2049,17 @@ class ManageBookmarksWindow:
    2047 2049
             Parse the treestore data into our new bookmarks array, then send the new
    
    2048 2050
             bookmarks to the server.
    
    2049 2051
             """
    
    2052
    +
    
    2050 2053
             (model, iter_) = self.selection.get_selected()
    
    2051 2054
             if iter_ and model.iter_parent(iter_):
    
    2052
    -            #bookmark selected, check it
    
    2055
    +            # bookmark selected, check it
    
    2053 2056
                 if not self.check_valid_bookmark():
    
    2054 2057
                     return
    
    2055 2058
     
    
    2056 2059
             for account in self.treestore:
    
    2057 2060
                 acct = account[1]
    
    2058
    -            app.connections[acct].bookmarks = []
    
    2061
    +            con = app.connections[acct]
    
    2062
    +            con.get_module('Bookmarks').bookmarks = {}
    
    2059 2063
     
    
    2060 2064
                 for bm in account.iterchildren():
    
    2061 2065
                     # Convert True/False/None to '1' or '0'
    
    ... ... @@ -2067,13 +2071,17 @@ class ManageBookmarksWindow:
    2067 2071
                     nick = bm[6]
    
    2068 2072
     
    
    2069 2073
                     # create the bookmark-dict
    
    2070
    -                bmdict = { 'name': name, 'jid': jid, 'autojoin': autojoin,
    
    2071
    -                    'minimize': minimize, 'password': pw, 'nick': nick,
    
    2074
    +                bmdict = {
    
    2075
    +                    'name': name,
    
    2076
    +                    'autojoin': autojoin,
    
    2077
    +                    'minimize': minimize,
    
    2078
    +                    'password': pw,
    
    2079
    +                    'nick': nick,
    
    2072 2080
                         'print_status': bm[7]}
    
    2073 2081
     
    
    2074
    -                app.connections[acct].bookmarks.append(bmdict)
    
    2082
    +                con.get_module('Bookmarks').bookmarks[jid] = bmdict
    
    2075 2083
     
    
    2076
    -            app.connections[acct].store_bookmarks()
    
    2084
    +            con.get_module('Bookmarks').store_bookmarks()
    
    2077 2085
                 gui_menu_builder.build_bookmark_menu(acct)
    
    2078 2086
             self.window.destroy()
    
    2079 2087
     
    
    ... ... @@ -2900,8 +2908,10 @@ class ManagePEPServicesWindow:
    2900 2908
             model, iter_ = selection.get_selected()
    
    2901 2909
             node = model[iter_][0]
    
    2902 2910
             our_jid = app.get_jid_from_account(self.account)
    
    2903
    -        app.connections[self.account].send_pb_delete(our_jid, node,
    
    2904
    -            on_ok=self.node_removed, on_fail=self.node_not_removed)
    
    2911
    +        con = app.connections[self.account]
    
    2912
    +        con.get_module('PubSub').send_pb_delete(our_jid, node,
    
    2913
    +                           on_ok=self.node_removed,
    
    2914
    +                           on_fail=self.node_not_removed)
    
    2905 2915
     
    
    2906 2916
         def on_configure_button_clicked(self, widget):
    
    2907 2917
             selection = self.treeview.get_selection()
    
    ... ... @@ -2910,13 +2920,15 @@ class ManagePEPServicesWindow:
    2910 2920
             model, iter_ = selection.get_selected()
    
    2911 2921
             node = model[iter_][0]
    
    2912 2922
             our_jid = app.get_jid_from_account(self.account)
    
    2913
    -        app.connections[self.account].request_pb_configuration(our_jid, node)
    
    2923
    +        con = app.connections[self.account]
    
    2924
    +        con.get_module('PubSub').request_pb_configuration(our_jid, node)
    
    2914 2925
     
    
    2915 2926
         def _nec_pep_config_received(self, obj):
    
    2916 2927
             def on_ok(form, node):
    
    2917 2928
                 form.type_ = 'submit'
    
    2918 2929
                 our_jid = app.get_jid_from_account(self.account)
    
    2919
    -            app.connections[self.account].send_pb_configure(our_jid, node, form)
    
    2930
    +            con = app.connections[self.account]
    
    2931
    +            con.get_module('PubSub').send_pb_configure(our_jid, node, form)
    
    2920 2932
             window = dialogs.DataFormWindow(obj.form, (on_ok, obj.node))
    
    2921 2933
             title = _('Configure %s') % obj.node
    
    2922 2934
             window.set_title(title)
    

  • gajim/dialogs.py
    ... ... @@ -2520,7 +2520,8 @@ class JoinGroupchatWindow(Gtk.ApplicationWindow):
    2520 2520
             self.autojoin_switch.set_sensitive(switch.get_active())
    
    2521 2521
     
    
    2522 2522
         def _add_bookmark(self, account, nickname, password):
    
    2523
    -        if not app.connections[account].private_storage_supported:
    
    2523
    +        con = app.connections[account]
    
    2524
    +        if not con.private_storage_supported:
    
    2524 2525
                 return
    
    2525 2526
     
    
    2526 2527
             add_bookmark = self.bookmark_switch.get_active()
    
    ... ... @@ -2531,8 +2532,8 @@ class JoinGroupchatWindow(Gtk.ApplicationWindow):
    2531 2532
     
    
    2532 2533
             # Add as bookmark, with autojoin and not minimized
    
    2533 2534
             name = app.get_nick_from_jid(self.room_jid)
    
    2534
    -        app.interface.add_gc_bookmark(
    
    2535
    -            account, name, self.room_jid, autojoin, 1, password, nickname)
    
    2535
    +        con.get_module('Bookmarks').add_bookmark(
    
    2536
    +            name, self.room_jid, autojoin, 1, password, nickname)
    
    2536 2537
     
    
    2537 2538
         def _on_destroy(self, *args):
    
    2538 2539
             if self.minimal_mode == 0:
    
    ... ... @@ -2784,10 +2785,11 @@ class StartChatDialog(Gtk.ApplicationWindow):
    2784 2785
             show_account = len(self.accounts) > 1
    
    2785 2786
             for account in self.accounts:
    
    2786 2787
                 self.new_groupchat_rows[account] = None
    
    2787
    -            bookmarks = app.connections[account].bookmarks
    
    2788
    +            con = app.connections[account]
    
    2789
    +            bookmarks = con.get_module('Bookmarks').bookmarks
    
    2788 2790
                 groupchats = {}
    
    2789
    -            for bookmark in bookmarks:
    
    2790
    -                groupchats[bookmark['jid']] = bookmark['name']
    
    2791
    +            for jid, bookmark in bookmarks.items():
    
    2792
    +                groupchats[jid] = bookmark['name']
    
    2791 2793
     
    
    2792 2794
                 for jid in app.contacts.get_gc_list(account):
    
    2793 2795
                     if jid in groupchats:
    

  • gajim/disco.py
    ... ... @@ -1757,29 +1757,29 @@ class MucBrowser(AgentBrowser):
    1757 1757
                 self.join_button = None
    
    1758 1758
     
    
    1759 1759
         def on_bookmark_button_clicked(self, *args):
    
    1760
    +        con = app.connections[self.account]
    
    1760 1761
             model, iter = self.window.services_treeview.get_selection().get_selected()
    
    1761 1762
             if not iter:
    
    1762 1763
                 return
    
    1763 1764
             name = app.config.get_per('accounts', self.account, 'name')
    
    1764 1765
             room_jid = model[iter][0]
    
    1765 1766
             bm = {
    
    1766
    -                'name': room_jid.split('@')[0],
    
    1767
    -                'jid': room_jid,
    
    1768
    -                'autojoin': '0',
    
    1769
    -                'minimize': '0',
    
    1770
    -                'password': '',
    
    1771
    -                'nick': name
    
    1767
    +            'name': room_jid.split('@')[0],
    
    1768
    +            'autojoin': '0',
    
    1769
    +            'minimize': '0',
    
    1770
    +            'password': '',
    
    1771
    +            'nick': name
    
    1772 1772
             }
    
    1773 1773
     
    
    1774
    -        for bookmark in app.connections[self.account].bookmarks:
    
    1775
    -            if bookmark['jid'] == bm['jid']:
    
    1776
    -                dialogs.ErrorDialog( _('Bookmark already set'),
    
    1777
    -                _('Group Chat "%s" is already in your bookmarks.') % bm['jid'],
    
    1774
    +        if room_jid in con.get_module('Bookmarks').bookmarks:
    
    1775
    +            dialogs.ErrorDialog(
    
    1776
    +                _('Bookmark already set'),
    
    1777
    +                _('Group Chat "%s" is already in your bookmarks.') % room_jid,
    
    1778 1778
                     transient_for=self.window.window)
    
    1779
    -                return
    
    1779
    +            return
    
    1780 1780
     
    
    1781
    -        app.connections[self.account].bookmarks.append(bm)
    
    1782
    -        app.connections[self.account].store_bookmarks()
    
    1781
    +        con.get_module('Bookmarks').bookmarks[room_jid] = bm
    
    1782
    +        con.get_module('Bookmarks').store_bookmarks()
    
    1783 1783
     
    
    1784 1784
             gui_menu_builder.build_bookmark_menu(self.account)
    
    1785 1785
     
    
    ... ... @@ -1951,8 +1951,9 @@ class DiscussionGroupsBrowser(AgentBrowser):
    1951 1951
             self.subscribe_button = None
    
    1952 1952
             self.unsubscribe_button = None
    
    1953 1953
     
    
    1954
    -        app.connections[account].send_pb_subscription_query(jid,
    
    1955
    -            self._on_pep_subscriptions)
    
    1954
    +        con = app.connections[account]
    
    1955
    +        con.get_module('PubSub').send_pb_subscription_query(
    
    1956
    +            jid, self._on_pep_subscriptions)
    
    1956 1957
     
    
    1957 1958
         def _create_treemodel(self):
    
    1958 1959
             """
    
    ... ... @@ -2122,10 +2123,11 @@ class DiscussionGroupsBrowser(AgentBrowser):
    2122 2123
             model, iter_ = self.window.services_treeview.get_selection().get_selected()
    
    2123 2124
             if iter_ is None: return
    
    2124 2125
     
    
    2125
    -        groupnode = model.get_value(iter_, 1)   # 1 = groupnode
    
    2126
    +        node = model.get_value(iter_, 1)   # 1 = groupnode
    
    2126 2127
     
    
    2127
    -        app.connections[self.account].send_pb_subscribe(self.jid, groupnode,
    
    2128
    -            self._on_pep_subscribe, groupnode)
    
    2128
    +        con = app.connections[self.account]
    
    2129
    +        con.get_module('PubSub').send_pb_subscribe(
    
    2130
    +            self.jid, node, self._on_pep_subscribe, groupnode=node)
    
    2129 2131
     
    
    2130 2132
         def on_unsubscribe_button_clicked(self, widget):
    
    2131 2133
             """
    
    ... ... @@ -2134,10 +2136,11 @@ class DiscussionGroupsBrowser(AgentBrowser):
    2134 2136
             model, iter_ = self.window.services_treeview.get_selection().get_selected()
    
    2135 2137
             if iter_ is None: return
    
    2136 2138
     
    
    2137
    -        groupnode = model.get_value(iter_, 1) # 1 = groupnode
    
    2139
    +        node = model.get_value(iter_, 1) # 1 = groupnode
    
    2138 2140
     
    
    2139
    -        app.connections[self.account].send_pb_unsubscribe(self.jid, groupnode,
    
    2140
    -            self._on_pep_unsubscribe, groupnode)
    
    2141
    +        con = app.connections[self.account]
    
    2142
    +        con.get_module('PubSub').send_pb_unsubscribe(
    
    2143
    +            self.jid, node, self._on_pep_unsubscribe, groupnode=node)
    
    2141 2144
     
    
    2142 2145
         def _on_pep_subscriptions(self, conn, request):
    
    2143 2146
             """
    
    ... ... @@ -2168,8 +2171,6 @@ class DiscussionGroupsBrowser(AgentBrowser):
    2168 2171
             # we now know subscriptions, update button states
    
    2169 2172
             self.update_actions()
    
    2170 2173
     
    
    2171
    -        raise nbxmpp.NodeProcessed
    
    2172
    -
    
    2173 2174
         def _on_pep_subscribe(self, conn, request, groupnode):
    
    2174 2175
             """
    
    2175 2176
             We have just subscribed to a node. Update UI
    
    ... ... @@ -2184,8 +2185,6 @@ class DiscussionGroupsBrowser(AgentBrowser):
    2184 2185
     
    
    2185 2186
             self.update_actions()
    
    2186 2187
     
    
    2187
    -        raise nbxmpp.NodeProcessed
    
    2188
    -
    
    2189 2188
         def _on_pep_unsubscribe(self, conn, request, groupnode):
    
    2190 2189
             """
    
    2191 2190
             We have just unsubscribed from a node. Update UI
    
    ... ... @@ -2200,7 +2199,5 @@ class DiscussionGroupsBrowser(AgentBrowser):
    2200 2199
     
    
    2201 2200
             self.update_actions()
    
    2202 2201
     
    
    2203
    -        raise nbxmpp.NodeProcessed
    
    2204
    -
    
    2205 2202
     # Fill the global agent type info dictionary
    
    2206 2203
     _agent_type_info = _gen_agent_type_info()

  • gajim/groupchat_control.py
    ... ... @@ -348,13 +348,10 @@ class GroupchatControl(ChatControlBase):
    348 348
             self.room_jid = self.contact.jid
    
    349 349
             self.nick = nick
    
    350 350
             self.new_nick = ''
    
    351
    -        self.name = ''
    
    352
    -        for bm in app.connections[self.account].bookmarks:
    
    353
    -            if bm['jid'] == self.room_jid:
    
    354
    -                self.name = bm['name']
    
    355
    -                break
    
    356
    -        if not self.name:
    
    357
    -            self.name = self.room_jid.split('@')[0]
    
    351
    +
    
    352
    +        bm_module = app.connections[self.account].get_module('Bookmarks')
    
    353
    +        self.name = bm_module.get_name_from_bookmark(self.room_jid)
    
    354
    +
    
    358 355
             self.contact.name = self.name
    
    359 356
     
    
    360 357
             self.widget_set_visible(self.xml.get_object('banner_eventbox'),
    
    ... ... @@ -589,13 +586,9 @@ class GroupchatControl(ChatControlBase):
    589 586
             # Bookmarks
    
    590 587
             con = app.connections[self.account]
    
    591 588
             bookmark_support = con.bookmarks_available()
    
    592
    -        not_bookmarked = True
    
    593
    -        for bm in con.bookmarks:
    
    594
    -            if bm['jid'] == self.room_jid:
    
    595
    -                not_bookmarked = False
    
    596
    -                break
    
    589
    +        bookmarked = self.room_jid in con.get_module('Bookmarks').bookmarks
    
    597 590
             win.lookup_action('bookmark-' + self.control_id).set_enabled(
    
    598
    -            online and bookmark_support and not_bookmarked)
    
    591
    +            online and bookmark_support and not bookmarked)
    
    599 592
     
    
    600 593
             # Request Voice
    
    601 594
             role = self.get_role(self.nick)
    
    ... ... @@ -712,9 +705,10 @@ class GroupchatControl(ChatControlBase):
    712 705
             Bookmark the room, without autojoin and not minimized
    
    713 706
             """
    
    714 707
             password = app.gc_passwords.get(self.room_jid, '')
    
    715
    -        app.interface.add_gc_bookmark(
    
    716
    -            self.account, self.name, self.room_jid,
    
    717
    -            '0', '0', password, self.nick)
    
    708
    +        con = app.connections[self.account]
    
    709
    +        con.get_module('Bookmarks').add_bookmark(
    
    710
    +            self.name, self.room_jid,
    
    711
    +            '1', '1', password, self.nick)
    
    718 712
             self.update_actions()
    
    719 713
     
    
    720 714
         def _on_request_voice(self, action, param):
    

  • gajim/groups.py
    ... ... @@ -67,7 +67,9 @@ class GroupsPostWindow:
    67 67
             item.addChild('content', {}, [buf.get_text(buf.get_start_iter(), buf.get_end_iter(), True)])
    
    68 68
     
    
    69 69
             # publish it to node
    
    70
    -        app.connections[self.account].send_pb_publish(self.servicejid, self.groupid, item, '0')
    
    70
    +        con = app.connections[self.account]
    
    71
    +        con.get_module('PubSub').send_pb_publish(
    
    72
    +            self.servicejid, self.groupid, item, '0')
    
    71 73
     
    
    72 74
             # close the window
    
    73 75
             self.window.destroy()

  • gajim/gui_interface.py
    ... ... @@ -824,17 +824,7 @@ class Interface:
    824 824
                 self.instances[account]['sub_request'][obj.jid].destroy()
    
    825 825
     
    
    826 826
         def handle_event_bookmarks(self, obj):
    
    827
    -        # ('BOOKMARKS', account, [{name,jid,autojoin,password,nick}, {}])
    
    828
    -        # We received a bookmark item from the server (JEP48)
    
    829
    -        # Auto join GC windows if necessary
    
    830
    -
    
    831
    -        gui_menu_builder.build_bookmark_menu(obj.conn.name)
    
    832
    -        invisible_show = app.SHOW_LIST.index('invisible')
    
    833
    -        # do not autojoin if we are invisible
    
    834
    -        if obj.conn.connected == invisible_show:
    
    835
    -            return
    
    836
    -
    
    837
    -        GLib.idle_add(self.auto_join_bookmarks, obj.conn.name)
    
    827
    +        gui_menu_builder.build_bookmark_menu(obj.account)
    
    838 828
     
    
    839 829
         def handle_event_file_send_error(self, account, array):
    
    840 830
             jid = array[0]
    
    ... ... @@ -1728,7 +1718,6 @@ class Interface:
    1728 1718
                 if isinstance(ctrl, ChatControlBase):
    
    1729 1719
                     ctrl.scroll_to_end()
    
    1730 1720
     
    
    1731
    -
    
    1732 1721
         def join_gc_minimal(self, account, room_jid, password=None,
    
    1733 1722
         transient_for=None):
    
    1734 1723
             if account is not None:
    
    ... ... @@ -1738,9 +1727,10 @@ class Interface:
    1738 1727
                     app.interface.join_gc_room(account, room_jid, '', '')
    
    1739 1728
                     return
    
    1740 1729
     
    
    1741
    -            for bookmark in app.connections[account].bookmarks:
    
    1742
    -                if bookmark['jid'] != room_jid:
    
    1743
    -                    continue
    
    1730
    +            con = app.connections[account]
    
    1731
    +            bookmarks = con.get_module('Bookmarks').bookmarks
    
    1732
    +            bookmark = bookmarks.get(room_jid, None)
    
    1733
    +            if bookmark is not None:
    
    1744 1734
                     app.interface.join_gc_room(
    
    1745 1735
                         account, room_jid, bookmark['nick'], bookmark['password'])
    
    1746 1736
                     return
    
    ... ... @@ -2469,51 +2459,6 @@ class Interface:
    2469 2459
                 return False
    
    2470 2460
             return True
    
    2471 2461
     
    
    2472
    -    def auto_join_bookmarks(self, account):
    
    2473
    -        """
    
    2474
    -        Autojoin bookmarked GCs that have 'auto join' on for this account
    
    2475
    -        """
    
    2476
    -        for bm in app.connections[account].bookmarks:
    
    2477
    -            if bm['autojoin'] in ('1', 'true'):
    
    2478
    -                jid = bm['jid']
    
    2479
    -                # Only join non-opened groupchats. Opened one are already
    
    2480
    -                # auto-joined on re-connection
    
    2481
    -                if not jid in app.gc_connected[account]:
    
    2482
    -                    # we are not already connected
    
    2483
    -                    minimize = bm['minimize'] in ('1', 'true')
    
    2484
    -                    self.join_gc_room(account, jid, bm['nick'],
    
    2485
    -                        bm['password'], minimize = minimize)
    
    2486
    -
    
    2487
    -    def add_gc_bookmark(self, account, name, jid, autojoin, minimize, password,
    
    2488
    -                        nick):
    
    2489
    -        """
    
    2490
    -        Add a bookmark for this account, sorted in bookmark list
    
    2491
    -        """
    
    2492
    -        bm = {
    
    2493
    -                'name': name,
    
    2494
    -                'jid': jid,
    
    2495
    -                'autojoin': autojoin,
    
    2496
    -                'minimize': minimize,
    
    2497
    -                'password': password,
    
    2498
    -                'nick': nick
    
    2499
    -        }
    
    2500
    -        place_found = False
    
    2501
    -        index = 0
    
    2502
    -        # check for duplicate entry and respect alpha order
    
    2503
    -        for bookmark in app.connections[account].bookmarks:
    
    2504
    -            if bookmark['jid'] == bm['jid']:
    
    2505
    -                return
    
    2506
    -            if bookmark['name'] > bm['name']:
    
    2507
    -                place_found = True
    
    2508
    -                break
    
    2509
    -            index += 1
    
    2510
    -        if place_found:
    
    2511
    -            app.connections[account].bookmarks.insert(index, bm)
    
    2512
    -        else:
    
    2513
    -            app.connections[account].bookmarks.append(bm)
    
    2514
    -        app.connections[account].store_bookmarks()
    
    2515
    -        gui_menu_builder.build_bookmark_menu(account)
    
    2516
    -
    
    2517 2462
         # does JID exist only within a groupchat?
    
    2518 2463
         def is_pm_contact(self, fjid, account):
    
    2519 2464
             bare_jid = app.get_jid_without_resource(fjid)
    

  • gajim/gui_menu_builder.py
    ... ... @@ -172,14 +172,15 @@ show_bookmarked=False, force_resource=False):
    172 172
         rooms2 = [] # a list of (room_jid, account) tuple
    
    173 173
         r_jids = [] # list of room jids
    
    174 174
         for account in connected_accounts:
    
    175
    -        for room in app.connections[account].bookmarks:
    
    176
    -            r_jid = room['jid']
    
    177
    -            if r_jid in r_jids:
    
    175
    +        con = app.connections[account]
    
    176
    +        boomarks = con.get_module('Bookmarks').bookmarks
    
    177
    +        for jid, bookmark in boomarks.items():
    
    178
    +            if jid in r_jids:
    
    178 179
                     continue
    
    179
    -            if r_jid not in app.gc_connected[account] or not \
    
    180
    -            app.gc_connected[account][r_jid]:
    
    181
    -                rooms2.append((r_jid, account))
    
    182
    -                r_jids.append(r_jid)
    
    180
    +            if jid not in app.gc_connected[account] or not \
    
    181
    +            app.gc_connected[account][jid]:
    
    182
    +                rooms2.append((jid, account))
    
    183
    +                r_jids.append(jid)
    
    183 184
     
    
    184 185
         if not rooms2:
    
    185 186
             return
    
    ... ... @@ -675,7 +676,9 @@ def get_groupchat_menu(control_id):
    675 676
     
    
    676 677
     
    
    677 678
     def get_bookmarks_menu(account, rebuild=False):
    
    678
    -    if not app.connections[account].bookmarks:
    
    679
    +    con = app.connections[account]
    
    680
    +    boomarks = con.get_module('Bookmarks').bookmarks
    
    681
    +    if not boomarks:
    
    679 682
             return None
    
    680 683
         menu = Gio.Menu()
    
    681 684
     
    
    ... ... @@ -688,12 +691,12 @@ def get_bookmarks_menu(account, rebuild=False):
    688 691
     
    
    689 692
         # Build Bookmarks
    
    690 693
         section = Gio.Menu()
    
    691
    -    for bookmark in app.connections[account].bookmarks:
    
    694
    +    for jid, bookmark in boomarks.items():
    
    692 695
             name = bookmark['name']
    
    693 696
             if not name:
    
    694 697
                 # No name was given for this bookmark.
    
    695 698
                 # Use the first part of JID instead...
    
    696
    -            name = bookmark['jid'].split("@")[0]
    
    699
    +            name = jid.split("@")[0]
    
    697 700
     
    
    698 701
             # Shorten long names
    
    699 702
             name = (name[:42] + '..') if len(name) > 42 else name
    
    ... ... @@ -703,7 +706,7 @@ def get_bookmarks_menu(account, rebuild=False):
    703 706
     
    
    704 707
             # Create Variant Dict
    
    705 708
             dict_ = {'account': GLib.Variant('s', account),
    
    706
    -                 'jid': GLib.Variant('s', bookmark['jid'])}
    
    709
    +                 'jid': GLib.Variant('s', jid)}
    
    707 710
             if bookmark['nick']:
    
    708 711
                 dict_['nick'] = GLib.Variant('s', bookmark['nick'])
    
    709 712
             if bookmark['password']:
    

  • gajim/roster_window.py
    ... ... @@ -2154,7 +2154,8 @@ class RosterWindow:
    2154 2154
                                 auto=auto)
    
    2155 2155
                 if was_invisible and status != 'offline':
    
    2156 2156
                     # We come back from invisible, join bookmarks
    
    2157
    -                app.interface.auto_join_bookmarks(account)
    
    2157
    +                con = app.connections[account]
    
    2158
    +                con.get_module('Bookmarks').auto_join_bookmarks()
    
    2158 2159
     
    
    2159 2160
     
    
    2160 2161
         def chg_contact_status(self, contact, show, status, account):
    
    ... ... @@ -2712,9 +2713,9 @@ class RosterWindow:
    2712 2713
     ### FIXME: order callbacks in itself...
    
    2713 2714
     ################################################################################
    
    2714 2715
     
    
    2715
    -    def on_bookmark_menuitem_activate(self, widget, account, bookmark):
    
    2716
    -        app.interface.join_gc_room(account, bookmark['jid'], bookmark['nick'],
    
    2717
    -                bookmark['password'])
    
    2716
    +    def on_bookmark_menuitem_activate(self, widget, account, jid, bookmark):
    
    2717
    +        app.interface.join_gc_room(
    
    2718
    +            account, jid, bookmark['nick'], bookmark['password'])
    
    2718 2719
     
    
    2719 2720
         def on_info(self, widget, contact, account):
    
    2720 2721
             """
    
    ... ... @@ -5439,16 +5440,17 @@ class RosterWindow:
    5439 5440
             gc_sub_menu.append(item)
    
    5440 5441
     
    
    5441 5442
             # User has at least one bookmark.
    
    5442
    -        if app.connections[account].bookmarks:
    
    5443
    +        con = app.connections[account]
    
    5444
    +        if con.get_module('Bookmarks').bookmarks:
    
    5443 5445
                 item = Gtk.SeparatorMenuItem.new()
    
    5444 5446
                 gc_sub_menu.append(item)
    
    5445 5447
     
    
    5446
    -        for bookmark in app.connections[account].bookmarks:
    
    5448
    +        for jid, bookmark in con.get_module('Bookmarks').bookmarks.items():
    
    5447 5449
                 name = bookmark['name']
    
    5448 5450
                 if not name:
    
    5449 5451
                     # No name was given for this bookmark.
    
    5450 5452
                     # Use the first part of JID instead...
    
    5451
    -                name = bookmark['jid'].split("@")[0]
    
    5453
    +                name = jid.split("@")[0]
    
    5452 5454
     
    
    5453 5455
                 # Shorten long names
    
    5454 5456
                 name = (name[:42] + '..') if len(name) > 42 else name
    
    ... ... @@ -5456,8 +5458,9 @@ class RosterWindow:
    5456 5458
                 # Do not use underline.
    
    5457 5459
                 item = Gtk.MenuItem.new_with_label(name)
    
    5458 5460
                 item.set_use_underline(False)
    
    5459
    -            item.connect('activate', self.on_bookmark_menuitem_activate,
    
    5460
    -                    account, bookmark)
    
    5461
    +            item.connect(
    
    5462
    +                'activate', self.on_bookmark_menuitem_activate,
    
    5463
    +                account, jid, bookmark)
    
    5461 5464
                 gc_sub_menu.append(item)
    
    5462 5465
     
    
    5463 5466
         def show_appropriate_context_menu(self, event, iters):