Refactor Bookmarks

- Simplify modules because nbxmpp handles more stuff
This commit is contained in:
Philipp Hörist 2019-02-03 23:02:32 +01:00
parent fa7f6f2b8c
commit a89bec0b9d
9 changed files with 145 additions and 286 deletions

View file

@ -1497,7 +1497,7 @@ class Connection(CommonConnection, ConnectionHandlers):
self.get_module('VCardTemp').request_vcard() self.get_module('VCardTemp').request_vcard()
# Get bookmarks # Get bookmarks
self.get_module('Bookmarks').get_bookmarks() self.get_module('Bookmarks').request_bookmarks()
# Get annotations # Get annotations
self.get_module('Annotations').get_annotations() self.get_module('Annotations').get_annotations()
@ -1625,7 +1625,7 @@ class Connection(CommonConnection, ConnectionHandlers):
# ask our VCard # ask our VCard
self.get_module('VCardTemp').request_vcard() self.get_module('VCardTemp').request_vcard()
self.get_module('Bookmarks').get_bookmarks() self.get_module('Bookmarks').request_bookmarks()
self.get_module('Annotations').get_annotations() self.get_module('Annotations').get_annotations()
self.get_module('Blocking').get_blocking_list() self.get_module('Blocking').get_blocking_list()

View file

@ -15,96 +15,97 @@
# XEP-0048: Bookmarks # XEP-0048: Bookmarks
from typing import Any from typing import Any
from typing import Dict
from typing import List from typing import List
from typing import Optional from typing import Optional
import logging import logging
import copy import copy
from collections import OrderedDict
import nbxmpp import nbxmpp
from nbxmpp.structs import BookmarkData
from nbxmpp.const import BookmarkStoreType
from gi.repository import GLib from gi.repository import GLib
from gajim.common import app from gajim.common import app
from gajim.common import helpers
from gajim.common.const import PEPEventType
from gajim.common.nec import NetworkEvent from gajim.common.nec import NetworkEvent
from gajim.common.exceptions import StanzaMalformed from gajim.common.modules.base import BaseModule
from gajim.common.modules.pep import AbstractPEPModule from gajim.common.modules.util import event_node
from gajim.common.modules.pep import AbstractPEPData
from gajim.common.modules.util import from_xs_boolean
from gajim.common.modules.util import to_xs_boolean
log = logging.getLogger('gajim.c.m.bookmarks') log = logging.getLogger('gajim.c.m.bookmarks')
class BookmarksData(AbstractPEPData): class Bookmarks(BaseModule):
type_ = PEPEventType.BOOKMARKS _nbxmpp_extends = 'Bookmarks'
_nbxmpp_methods = [
'request_bookmarks',
class Bookmarks(AbstractPEPModule): 'store_bookmarks',
]
name = 'storage'
namespace = 'storage:bookmarks'
pep_class = BookmarksData
store_publish = False
_log = log
def __init__(self, con): def __init__(self, con):
AbstractPEPModule.__init__(self, con) BaseModule.__init__(self, con)
self._register_pubsub_handler(self._bookmark_event_received)
self.bookmarks = {} self._conversion = False
self.conversion = False self._bookmarks = []
self._join_timeouts = [] self._join_timeouts = []
self._request_in_progress = False self._request_in_progress = False
def pass_disco(self, from_, _identities, features, _data, _node): @property
if nbxmpp.NS_BOOKMARK_CONVERSION not in features: def conversion(self):
return return self._conversion
self.conversion = True
log.info('Discovered Bookmarks Conversion: %s', from_)
def _extract_info(self, item): @property
storage = item.getTag('storage', namespace=self.namespace) def bookmarks(self):
if storage is None: return self._bookmarks
raise StanzaMalformed('No storage node')
return storage
def _notification_received(self, jid: nbxmpp.JID, user_pep: Any) -> None: @bookmarks.setter
if self._request_in_progress: def bookmarks(self, value):
log.info('Ignore update, pubsub request in progress') self._bookmarks = value
return
if not self._con.get_own_jid().bareMatch(jid): @event_node(nbxmpp.NS_BOOKMARKS)
log.warning('%s has an open access bookmarks node', jid) def _bookmark_event_received(self, _con, _stanza, properties):
bookmarks = properties.pubsub_event.data
if not properties.is_self_message:
log.warning('%s has an open access bookmarks node', properties.jid)
return return
if not self._pubsub_support() or not self.conversion: if not self._pubsub_support() or not self.conversion:
return return
old_bookmarks = self._convert_to_set(self.bookmarks) if self._request_in_progress:
self.bookmarks = self._parse_bookmarks(user_pep.data) log.info('Ignore update, pubsub request in progress')
return
old_bookmarks = self._convert_to_set(self._bookmarks)
self._bookmarks = bookmarks
self._act_on_changed_bookmarks(old_bookmarks) self._act_on_changed_bookmarks(old_bookmarks)
app.nec.push_incoming_event( app.nec.push_incoming_event(
NetworkEvent('bookmarks-received', account=self._account)) NetworkEvent('bookmarks-received', account=self._account))
def pass_disco(self, from_, _identities, features, _data, _node):
if nbxmpp.NS_BOOKMARK_CONVERSION not in features:
return
self._conversion = True
log.info('Discovered Bookmarks Conversion: %s', from_)
def _act_on_changed_bookmarks(self, old_bookmarks): def _act_on_changed_bookmarks(self, old_bookmarks):
new_bookmarks = self._convert_to_set(self.bookmarks) new_bookmarks = self._convert_to_set(self._bookmarks)
changed = new_bookmarks - old_bookmarks changed = new_bookmarks - old_bookmarks
if not changed: if not changed:
return return
join = [jid for jid, autojoin in changed if autojoin] join = [jid for jid, autojoin in changed if autojoin]
bookmarks = []
for jid in join: for jid in join:
log.info('Schedule autojoin in 10s for: %s', jid) log.info('Schedule autojoin in 10s for: %s', jid)
bookmarks.append(self.get_bookmark_from_jid(jid))
# If another client creates a MUC, the MUC is locked until the # If another client creates a MUC, the MUC is locked until the
# configuration is finished. Give the user some time to finish # configuration is finished. Give the user some time to finish
# the configuration. # the configuration.
timeout_id = GLib.timeout_add_seconds( timeout_id = GLib.timeout_add_seconds(
10, self._join_with_timeout, join) 10, self._join_with_timeout, bookmarks)
self._join_timeouts.append(timeout_id) self._join_timeouts.append(timeout_id)
# TODO: leave mucs # TODO: leave mucs
@ -113,256 +114,122 @@ class Bookmarks(AbstractPEPModule):
@staticmethod @staticmethod
def _convert_to_set(bookmarks): def _convert_to_set(bookmarks):
set_ = set() set_ = set()
for jid in bookmarks: for bookmark in bookmarks:
set_.add((jid, bookmarks[jid]['autojoin'])) set_.add((bookmark.jid, bookmark.autojoin))
return set_ return set_
def get_bookmark_from_jid(self, jid):
for bookmark in self._bookmarks:
if bookmark.jid == jid:
return bookmark
def get_sorted_bookmarks(self, short_name=False): def get_sorted_bookmarks(self, short_name=False):
# This returns a sorted by name copy of the bookmarks # This returns a sorted by name copy of the bookmarks
sorted_bookmarks = {} sorted_bookmarks = []
for jid, bookmarks in self.bookmarks.items(): for bookmark in self._bookmarks:
bookmark_copy = copy.deepcopy(bookmarks) bookmark_copy = copy.deepcopy(bookmark)
if not bookmark_copy['name']: if not bookmark_copy.name:
# No name was given for this bookmark # No name was given for this bookmark
# Use the first part of JID instead # Use the first part of JID instead
name = jid.split("@")[0] name = bookmark_copy.jid.split("@")[0]
bookmark_copy['name'] = name bookmark_copy = bookmark_copy._replace(name=name)
if short_name: if short_name:
name = bookmark_copy['name'] name = bookmark_copy.name
name = (name[:42] + '..') if len(name) > 42 else name name = (name[:42] + '..') if len(name) > 42 else name
bookmark_copy['name'] = name bookmark_copy = bookmark_copy._replace(name=name)
sorted_bookmarks[jid] = bookmark_copy sorted_bookmarks.append(bookmark_copy)
return OrderedDict(
sorted(sorted_bookmarks.items(), sorted_bookmarks.sort(key=lambda x: x.name.lower())
key=lambda bookmark: bookmark[1]['name'].lower())) return sorted_bookmarks
def _pubsub_support(self) -> bool: def _pubsub_support(self) -> bool:
return (self._con.get_module('PEP').supported and return (self._con.get_module('PEP').supported and
self._con.get_module('PubSub').publish_options) self._con.get_module('PubSub').publish_options)
def get_bookmarks(self): def request_bookmarks(self):
if not app.account_is_connected(self._account): if not app.account_is_connected(self._account):
return return
self._request_in_progress = True
type_ = BookmarkStoreType.PRIVATE
if self._pubsub_support() and self.conversion: if self._pubsub_support() and self.conversion:
self._request_pubsub_bookmarks() type_ = BookmarkStoreType.PUBSUB
else:
self._request_private_bookmarks()
def _request_pubsub_bookmarks(self) -> None: self._nbxmpp('Bookmarks').request_bookmarks(
log.info('Request Bookmarks (PubSub)') type_, callback=self._bookmarks_received)
self._request_in_progress = True
self._con.get_module('PubSub').send_pb_retrieve(
'', 'storage:bookmarks', cb=self._bookmarks_received)
def _request_private_bookmarks(self) -> None: def _bookmarks_received(self, bookmarks):
self._request_in_progress = True
iq = nbxmpp.Iq(typ='get')
query = iq.addChild(name='query', namespace=nbxmpp.NS_PRIVATE)
query.addChild(name='storage', namespace='storage:bookmarks')
log.info('Request Bookmarks (PrivateStorage)')
self._con.connection.SendAndCallForResponse(
iq, self._bookmarks_received, {})
def _bookmarks_received(self, _con, stanza):
self._request_in_progress = False self._request_in_progress = False
if not nbxmpp.isResultNode(stanza): self._bookmarks = bookmarks
log.info('No bookmarks found: %s', stanza.getError()) self.auto_join_bookmarks()
else:
log.info('Received Bookmarks')
storage = self._get_storage_node(stanza)
if storage is not None:
self.bookmarks = self._parse_bookmarks(storage)
self.auto_join_bookmarks()
app.nec.push_incoming_event( app.nec.push_incoming_event(
NetworkEvent('bookmarks-received', account=self._account)) NetworkEvent('bookmarks-received', account=self._account))
@staticmethod
def _get_storage_node(stanza):
node = stanza.getTag('pubsub', namespace=nbxmpp.NS_PUBSUB)
if node is None:
node = stanza.getTag('event', namespace=nbxmpp.NS_PUBSUB_EVENT)
if node is None:
# Private Storage
query = stanza.getQuery()
if query is None:
return
storage = query.getTag('storage',
namespace=nbxmpp.NS_BOOKMARKS)
if storage is None:
return
return storage
items_node = node.getTag('items')
if items_node is None:
return
if items_node.getAttr('node') != nbxmpp.NS_BOOKMARKS:
return
item_node = items_node.getTag('item')
if item_node is None:
return
storage = item_node.getTag('storage', namespace=nbxmpp.NS_BOOKMARKS)
if storage is None:
return
return storage
@staticmethod
def _parse_bookmarks(storage: nbxmpp.Node) -> Dict[str, Dict[str, Any]]:
bookmarks = {}
confs = storage.getTags('conference')
for conf in confs:
autojoin_val = conf.getAttr('autojoin')
if not autojoin_val: # not there (it's optional)
autojoin_val = False
try:
jid = helpers.parse_jid(conf.getAttr('jid'))
except helpers.InvalidFormat:
log.warning('Invalid JID: %s, ignoring it',
conf.getAttr('jid'))
continue
bookmark = {
'name': conf.getAttr('name'),
'password': conf.getTagData('password'),
'nick': conf.getTagData('nick'),
}
try:
bookmark['autojoin'] = from_xs_boolean(autojoin_val)
except ValueError as error:
log.warning(error)
continue
log.debug('Found Bookmark: %s', jid)
bookmarks[jid] = bookmark
return bookmarks
@staticmethod
def _build_storage_node(bookmarks):
storage_node = nbxmpp.Node(
tag='storage', attrs={'xmlns': 'storage:bookmarks'})
for jid, bm in bookmarks.items():
conf_node = storage_node.addChild(name="conference")
conf_node.setAttr('jid', jid)
conf_node.setAttr('autojoin', to_xs_boolean(bm['autojoin']))
conf_node.setAttr('name', bm['name'])
# Only add optional elements if not empty
# Note: need to handle both None and '' as empty
# thus shouldn't use "is not None"
if bm.get('nick', None):
conf_node.setTagData('nick', bm['nick'])
if bm.get('password', None):
conf_node.setTagData('password', bm['password'])
return storage_node
def _build_node(self, _data):
pass
@staticmethod
def get_bookmark_publish_options() -> nbxmpp.Node:
options = nbxmpp.Node(nbxmpp.NS_DATA + ' x',
attrs={'type': 'submit'})
field = options.addChild('field',
attrs={'var': 'FORM_TYPE', 'type': 'hidden'})
field.setTagData('value', nbxmpp.NS_PUBSUB_PUBLISH_OPTIONS)
field = options.addChild('field', attrs={'var': 'pubsub#access_model'})
field.setTagData('value', 'whitelist')
return options
def store_bookmarks(self): def store_bookmarks(self):
if not app.account_is_connected(self._account): if not app.account_is_connected(self._account):
return return
storage_node = self._build_storage_node(self.bookmarks) type_ = BookmarkStoreType.PRIVATE
if self._pubsub_support() and self.conversion: if self._pubsub_support() and self.conversion:
self._pubsub_store(storage_node) type_ = BookmarkStoreType.PUBSUB
else:
self._private_store(storage_node) self._nbxmpp('Bookmarks').store_bookmarks(self._bookmarks, type_)
app.nec.push_incoming_event( app.nec.push_incoming_event(
NetworkEvent('bookmarks-received', account=self._account)) NetworkEvent('bookmarks-received', account=self._account))
def _pubsub_store(self, storage_node: nbxmpp.Node) -> None: def _join_with_timeout(self, bookmarks: List[Any]) -> None:
self._con.get_module('PubSub').send_pb_publish(
'', 'storage:bookmarks', storage_node, 'current',
options=self.get_bookmark_publish_options(),
cb=self._pubsub_store_result)
log.info('Publish Bookmarks (PubSub)')
def _private_store(self, storage_node: nbxmpp.Node) -> None:
iq = nbxmpp.Iq('set', nbxmpp.NS_PRIVATE, payload=storage_node)
log.info('Publish Bookmarks (PrivateStorage)')
self._con.connection.SendAndCallForResponse(
iq, self._private_store_result)
@staticmethod
def _pubsub_store_result(_con, stanza):
if not nbxmpp.isResultNode(stanza):
log.error('Error: %s', stanza.getError())
return
@staticmethod
def _private_store_result(stanza: nbxmpp.Iq) -> None:
if not nbxmpp.isResultNode(stanza):
log.error('Error: %s', stanza.getError())
return
def _join_with_timeout(self, bookmarks: Optional[List[str]] = None) -> None:
self._join_timeouts.pop(0) self._join_timeouts.pop(0)
self.auto_join_bookmarks(bookmarks) self.auto_join_bookmarks(bookmarks)
def auto_join_bookmarks(self, bookmarks: Optional[List[str]] = None) -> None: def auto_join_bookmarks(self, bookmarks: Optional[List[Any]] = None) -> None:
if app.is_invisible(self._account): if app.is_invisible(self._account):
return return
if bookmarks is None:
bookmarks = self.bookmarks.keys()
for jid in bookmarks: if bookmarks is None:
bookmark = self.bookmarks[jid] bookmarks = self._bookmarks
if bookmark['autojoin']:
for bookmark in bookmarks:
if bookmark.autojoin:
# Only join non-opened groupchats. Opened one are already # Only join non-opened groupchats. Opened one are already
# auto-joined on re-connection # auto-joined on re-connection
if jid not in app.gc_connected[self._account]: if bookmark.jid not in app.gc_connected[self._account]:
# we are not already connected # we are not already connected
log.info('Autojoin Bookmark: %s', jid) log.info('Autojoin Bookmark: %s', bookmark.jid)
minimize = app.config.get_per('rooms', jid, minimize = app.config.get_per('rooms', bookmark.jid,
'minimize_on_autojoin', True) 'minimize_on_autojoin', True)
app.interface.join_gc_room( app.interface.join_gc_room(
self._account, jid, bookmark['nick'], self._account, bookmark.jid, bookmark.nick,
bookmark['password'], minimize=minimize) bookmark.password, minimize=minimize)
def add_bookmark(self, name, jid, autojoin, password, nick): def add_bookmark(self, name, jid, autojoin, password, nick):
self.bookmarks[jid] = { bookmark = BookmarkData(jid=jid,
'name': name, name=name,
'autojoin': autojoin, autojoin=autojoin,
'password': password, password=password,
'nick': nick, nick=nick)
} self._bookmarks.append(bookmark)
self.store_bookmarks() self.store_bookmarks()
def remove(self, jid: str, publish: bool = True) -> None: def remove(self, jid: str, publish: bool = True) -> None:
if self.bookmarks.pop(jid, None) is None: bookmark = self.get_bookmark_from_jid(jid)
if bookmark is None:
return return
self.bookmark.remove(bookmark)
if publish: if publish:
self.store_bookmarks() self.store_bookmarks()
def get_name_from_bookmark(self, jid: str) -> str: def get_name_from_bookmark(self, jid: str) -> str:
fallback = jid.split('@')[0] fallback = jid.split('@')[0]
try: bookmark = self.get_bookmark_from_jid(jid)
return self.bookmarks[jid]['name'] or fallback if bookmark is None:
except KeyError:
return fallback return fallback
return bookmark.name or fallback
def is_bookmark(self, jid: str) -> bool: def is_bookmark(self, jid: str) -> bool:
return jid in self.bookmarks return self.get_bookmark_from_jid(jid) is not None
def purge_pubsub_bookmarks(self) -> None: def purge_pubsub_bookmarks(self) -> None:
log.info('Purge/Delete Bookmarks on PubSub, ' log.info('Purge/Delete Bookmarks on PubSub, '

View file

@ -468,7 +468,7 @@ class GroupchatControl(ChatControlBase):
# Bookmarks # Bookmarks
con = app.connections[self.account] con = app.connections[self.account]
bookmarked = self.room_jid in con.get_module('Bookmarks').bookmarks bookmarked = con.get_module('Bookmarks').is_bookmark(self.room_jid)
self._get_action('bookmark-').set_enabled(self.is_connected and self._get_action('bookmark-').set_enabled(self.is_connected and
not bookmarked) not bookmarked)

View file

@ -16,6 +16,7 @@ from enum import IntEnum
from gi.repository import Gtk from gi.repository import Gtk
from gi.repository import Gdk from gi.repository import Gdk
from nbxmpp.structs import BookmarkData
from gajim.common import app from gajim.common import app
from gajim.common import helpers from gajim.common import helpers
@ -57,14 +58,14 @@ class ManageBookmarksWindow:
con = app.connections[account] con = app.connections[account]
bookmarks = con.get_module('Bookmarks').get_sorted_bookmarks() bookmarks = con.get_module('Bookmarks').get_sorted_bookmarks()
for jid, bookmark in bookmarks.items(): for bookmark in bookmarks:
self.treestore.append(iter_, [account, self.treestore.append(iter_, [account,
bookmark['name'], bookmark.name,
jid, bookmark.jid,
bookmark['autojoin'], bookmark.autojoin,
bookmark['password'], bookmark.password,
bookmark['nick'], bookmark.nick,
bookmark['name']]) bookmark.name])
self.view = self.xml.get_object('bookmarks_treeview') self.view = self.xml.get_object('bookmarks_treeview')
self.view.set_model(self.treestore) self.view.set_model(self.treestore)
@ -190,20 +191,17 @@ class ManageBookmarksWindow:
for account in self.treestore: for account in self.treestore:
acct = account[1] acct = account[1]
con = app.connections[acct] con = app.connections[acct]
con.get_module('Bookmarks').bookmarks = {}
bookmarks = []
for bm in account.iterchildren(): for bm in account.iterchildren():
# create the bookmark-dict # create the bookmark-dict
bmdict = { bookmark = BookmarkData(jid=bm[Row.ROOM_JID],
'name': bm[Row.ROOM_NAME], name=bm[Row.ROOM_NAME],
'autojoin': bm[Row.AUTOJOIN], autojoin=bm[Row.AUTOJOIN],
'password': bm[Row.PASSWORD], password=bm[Row.PASSWORD],
'nick': bm[Row.NICK], nick=bm[Row.NICK])
} bookmarks.append(bookmark)
con.get_module('Bookmarks').bookmarks = bookmarks
jid = bm[Row.ROOM_JID]
con.get_module('Bookmarks').bookmarks[jid] = bmdict
con.get_module('Bookmarks').store_bookmarks() con.get_module('Bookmarks').store_bookmarks()
self.window.destroy() self.window.destroy()

View file

@ -1707,7 +1707,7 @@ class MucBrowser(AgentBrowser):
return return
room_jid = model[iter_][0] room_jid = model[iter_][0]
if room_jid in con.get_module('Bookmarks').bookmarks: if con.get_module('Bookmarks').is_bookmark(room_jid):
ErrorDialog( ErrorDialog(
_('Bookmark already set'), _('Bookmark already set'),
_('Group Chat "%s" is already in your bookmarks.') % room_jid, _('Group Chat "%s" is already in your bookmarks.') % room_jid,

View file

@ -92,8 +92,8 @@ class StartChatDialog(Gtk.ApplicationWindow):
con = app.connections[account] con = app.connections[account]
bookmarks = con.get_module('Bookmarks').bookmarks bookmarks = con.get_module('Bookmarks').bookmarks
groupchats = {} groupchats = {}
for jid, bookmark in bookmarks.items(): for bookmark in bookmarks:
groupchats[jid] = bookmark['name'] groupchats[bookmark.jid] = bookmark.name
for jid in app.contacts.get_gc_list(account): for jid in app.contacts.get_gc_list(account):
if jid in groupchats: if jid in groupchats:

View file

@ -1552,11 +1552,10 @@ class Interface:
return return
con = app.connections[account] con = app.connections[account]
bookmarks = con.get_module('Bookmarks').bookmarks bookmark = con.get_module('Bookmarks').get_bookmark_from_jid(room_jid)
bookmark = bookmarks.get(room_jid, None)
if bookmark is not None: if bookmark is not None:
app.interface.join_gc_room( app.interface.join_gc_room(
account, room_jid, bookmark['nick'], bookmark['password']) account, bookmark.jid, bookmark.nick, bookmark.password)
return return
try: try:

View file

@ -167,14 +167,13 @@ show_bookmarked=False, force_resource=False):
r_jids = [] # list of room jids r_jids = [] # list of room jids
for account in connected_accounts: for account in connected_accounts:
con = app.connections[account] con = app.connections[account]
boomarks = con.get_module('Bookmarks').bookmarks for bookmark in con.get_module('Bookmarks').bookmarks:
for jid in boomarks.keys(): if bookmark.jid in r_jids:
if jid in r_jids:
continue continue
if jid not in app.gc_connected[account] or not \ if bookmark.jid not in app.gc_connected[account] or not \
app.gc_connected[account][jid]: app.gc_connected[account][bookmark.jid]:
rooms2.append((jid, account)) rooms2.append((bookmark.jid, account))
r_jids.append(jid) r_jids.append(bookmark.jid)
if not rooms2: if not rooms2:
return return
@ -736,7 +735,7 @@ def get_groupchat_menu(control_id, account, jid):
def get_bookmarks_menu(account, rebuild=False): def get_bookmarks_menu(account, rebuild=False):
con = app.connections[account] con = app.connections[account]
boomarks = con.get_module('Bookmarks').get_sorted_bookmarks(short_name=True) bookmarks = con.get_module('Bookmarks').get_sorted_bookmarks(short_name=True)
menu = Gio.Menu() menu = Gio.Menu()
@ -749,19 +748,17 @@ def get_bookmarks_menu(account, rebuild=False):
# Build Bookmarks # Build Bookmarks
section = Gio.Menu() section = Gio.Menu()
for jid, bookmark in boomarks.items(): for bookmark in bookmarks:
name = bookmark['name']
action = 'app.{}-activate-bookmark'.format(account) action = 'app.{}-activate-bookmark'.format(account)
menuitem = Gio.MenuItem.new(name, action) menuitem = Gio.MenuItem.new(bookmark.name, action)
# Create Variant Dict # Create Variant Dict
dict_ = {'account': GLib.Variant('s', account), dict_ = {'account': GLib.Variant('s', account),
'jid': GLib.Variant('s', jid)} 'jid': GLib.Variant('s', bookmark.jid)}
if bookmark['nick']: if bookmark.nick:
dict_['nick'] = GLib.Variant('s', bookmark['nick']) dict_['nick'] = GLib.Variant('s', bookmark.nick)
if bookmark['password']: if bookmark.password:
dict_['password'] = GLib.Variant('s', bookmark['password']) dict_['password'] = GLib.Variant('s', bookmark.password)
variant_dict = GLib.Variant('a{sv}', dict_) variant_dict = GLib.Variant('a{sv}', dict_)
menuitem.set_action_and_target_value(action, variant_dict) menuitem.set_action_and_target_value(action, variant_dict)

View file

@ -2706,9 +2706,9 @@ class RosterWindow:
### FIXME: order callbacks in itself... ### FIXME: order callbacks in itself...
################################################################################ ################################################################################
def on_bookmark_menuitem_activate(self, widget, account, jid, bookmark): def on_bookmark_menuitem_activate(self, widget, account, bookmark):
app.interface.join_gc_room( app.interface.join_gc_room(
account, jid, bookmark['nick'], bookmark['password']) account, bookmark.jid, bookmark.nick, bookmark.password)
def on_info(self, widget, contact, account): def on_info(self, widget, contact, account):
""" """
@ -5421,15 +5421,13 @@ class RosterWindow:
bookmarks = con.get_module('Bookmarks').get_sorted_bookmarks( bookmarks = con.get_module('Bookmarks').get_sorted_bookmarks(
short_name=True) short_name=True)
for jid, bookmark in bookmarks.items(): for bookmark in bookmarks:
name = bookmark['name']
# Do not use underline. # Do not use underline.
item = Gtk.MenuItem.new_with_label(name) item = Gtk.MenuItem.new_with_label(bookmark.name)
item.set_use_underline(False) item.set_use_underline(False)
item.connect( item.connect(
'activate', self.on_bookmark_menuitem_activate, 'activate', self.on_bookmark_menuitem_activate,
account, jid, bookmark) account, bookmark)
gc_sub_menu.append(item) gc_sub_menu.append(item)
def show_appropriate_context_menu(self, event, iters): def show_appropriate_context_menu(self, event, iters):