Refactor Pubsub/Bookmarks/UserAvatar into own modules
This commit is contained in:
parent
858e472ef4
commit
2ca0ca38a5
|
@ -73,6 +73,9 @@ from gajim.common.modules.last_activity import LastActivity
|
|||
from gajim.common.modules.http_auth import HTTPAuth
|
||||
from gajim.common.modules.vcard_temp import VCardTemp
|
||||
from gajim.common.modules.vcard_avatars import VCardAvatars
|
||||
from gajim.common.modules.pubsub import PubSub
|
||||
from gajim.common.modules.bookmarks import Bookmarks
|
||||
from gajim.common.modules.user_avatar import UserAvatar
|
||||
from gajim.common.connection_handlers import *
|
||||
from gajim.common.contacts import GC_Contact
|
||||
from gajim.gtkgui_helpers import get_action
|
||||
|
@ -113,7 +116,6 @@ class CommonConnection:
|
|||
self.old_show = ''
|
||||
self.priority = app.get_priority(name, 'offline')
|
||||
self.time_to_reconnect = None
|
||||
self.bookmarks = []
|
||||
|
||||
self.blocked_list = []
|
||||
self.blocked_contacts = []
|
||||
|
@ -491,18 +493,6 @@ class CommonConnection:
|
|||
def account_changed(self, new_name):
|
||||
self.name = new_name
|
||||
|
||||
def get_bookmarks(self):
|
||||
"""
|
||||
To be implemented by derived classes
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def store_bookmarks(self):
|
||||
"""
|
||||
To be implemented by derived classes
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_metacontacts(self):
|
||||
"""
|
||||
To be implemented by derived classes
|
||||
|
@ -670,6 +660,9 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
self.register_module('HTTPAuth', HTTPAuth, self)
|
||||
self.register_module('VCardTemp', VCardTemp, self)
|
||||
self.register_module('VCardAvatars', VCardAvatars, self)
|
||||
self.register_module('PubSub', PubSub, self)
|
||||
self.register_module('Bookmarks', Bookmarks, self)
|
||||
self.register_module('UserAvatar', UserAvatar, self)
|
||||
|
||||
app.ged.register_event_handler('privacy-list-received', ged.CORE,
|
||||
self._nec_privacy_list_received)
|
||||
|
@ -1774,8 +1767,8 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
# ask our VCard
|
||||
self.get_module('VCardTemp').request_vcard()
|
||||
|
||||
# Get bookmarks from private namespace
|
||||
self.get_bookmarks()
|
||||
# Get bookmarks
|
||||
self.get_module('Bookmarks').get_bookmarks()
|
||||
|
||||
# Get annotations
|
||||
self.get_module('Annotations').get_annotations()
|
||||
|
@ -1916,8 +1909,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
self.pubsub_publish_options_supported = True
|
||||
else:
|
||||
# Remove stored bookmarks accessible to everyone.
|
||||
self.send_pb_purge(our_jid, 'storage:bookmarks')
|
||||
self.send_pb_delete(our_jid, 'storage:bookmarks')
|
||||
self.get_module('Bookmarks').purge_pubsub_bookmarks()
|
||||
|
||||
if obj.fjid == hostname:
|
||||
if nbxmpp.NS_SECLABEL in obj.features:
|
||||
|
@ -2255,99 +2247,6 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
return True
|
||||
return False
|
||||
|
||||
def _request_bookmarks_xml(self):
|
||||
if not app.account_is_connected(self.name):
|
||||
return
|
||||
iq = nbxmpp.Iq(typ='get')
|
||||
iq2 = iq.addChild(name='query', namespace=nbxmpp.NS_PRIVATE)
|
||||
iq2.addChild(name='storage', namespace='storage:bookmarks')
|
||||
self.connection.send(iq)
|
||||
app.log('bookmarks').info('Request Bookmarks (PrivateStorage)')
|
||||
|
||||
def _check_bookmarks_received(self):
|
||||
if not self.bookmarks:
|
||||
self._request_bookmarks_xml()
|
||||
|
||||
def get_bookmarks(self, storage_type=None):
|
||||
"""
|
||||
Get Bookmarks from storage or PubSub if supported as described in XEP
|
||||
0048
|
||||
|
||||
storage_type can be set to xml to force request to xml storage
|
||||
"""
|
||||
if not app.account_is_connected(self.name):
|
||||
return
|
||||
|
||||
if storage_type != 'xml':
|
||||
if self.pep_supported and self.pubsub_publish_options_supported:
|
||||
self.send_pb_retrieve('', 'storage:bookmarks')
|
||||
app.log('bookmarks').info('Request Bookmarks (PubSub)')
|
||||
# some server (ejabberd) are so slow to answer that we
|
||||
# request via XML if we don't get answer in the next 30 seconds
|
||||
app.idlequeue.set_alarm(self._check_bookmarks_received, 30)
|
||||
return
|
||||
|
||||
self._request_bookmarks_xml()
|
||||
|
||||
def get_bookmarks_storage_node(self):
|
||||
NS_GAJIM_BM = 'xmpp:gajim.org/bookmarks'
|
||||
storage_node = nbxmpp.Node(
|
||||
tag='storage', attrs={'xmlns': 'storage:bookmarks'})
|
||||
for bm in self.bookmarks:
|
||||
conf_node = storage_node.addChild(name="conference")
|
||||
conf_node.setAttr('jid', bm['jid'])
|
||||
conf_node.setAttr('autojoin', bm['autojoin'])
|
||||
conf_node.setAttr('name', bm['name'])
|
||||
conf_node.setTag(
|
||||
'minimize', namespace=NS_GAJIM_BM).setData(bm['minimize'])
|
||||
# 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'])
|
||||
if bm.get('print_status', None):
|
||||
conf_node.setTag(
|
||||
'print_status',
|
||||
namespace=NS_GAJIM_BM).setData(bm['print_status'])
|
||||
return storage_node
|
||||
|
||||
@staticmethod
|
||||
def get_bookmark_publish_options():
|
||||
options = nbxmpp.Node(nbxmpp.NS_DATA + ' x',
|
||||
attrs={'type': 'submit'})
|
||||
f = options.addChild('field',
|
||||
attrs={'var': 'FORM_TYPE', 'type': 'hidden'})
|
||||
f.setTagData('value', nbxmpp.NS_PUBSUB_PUBLISH_OPTIONS)
|
||||
f = options.addChild('field', attrs={'var': 'pubsub#access_model'})
|
||||
f.setTagData('value', 'whitelist')
|
||||
return options
|
||||
|
||||
def store_bookmarks(self, storage_type=None):
|
||||
"""
|
||||
Send bookmarks to the storage namespace or PubSub if supported
|
||||
|
||||
storage_type can be set to 'pubsub' or 'xml' so store in only one method
|
||||
else it will be stored on both
|
||||
"""
|
||||
if not app.account_is_connected(self.name):
|
||||
return
|
||||
|
||||
storage_node = self.get_bookmarks_storage_node()
|
||||
|
||||
if storage_type != 'xml':
|
||||
if self.pep_supported and self.pubsub_publish_options_supported:
|
||||
self.send_pb_publish(
|
||||
'', 'storage:bookmarks', storage_node, 'current',
|
||||
options=self.get_bookmark_publish_options())
|
||||
app.log('bookmarks').info('Bookmarks published (PubSub)')
|
||||
|
||||
if storage_type != 'pubsub':
|
||||
iq = nbxmpp.Iq('set', nbxmpp.NS_PRIVATE, payload=storage_node)
|
||||
self.connection.send(iq)
|
||||
app.log('bookmarks').info('Bookmarks published (PrivateStorage)')
|
||||
|
||||
def get_roster_delimiter(self):
|
||||
"""
|
||||
Get roster group delimiter from storage as described in XEP 0083
|
||||
|
@ -2614,11 +2513,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
destroy.setAttr('jid', jid)
|
||||
self.connection.send(iq)
|
||||
i = 0
|
||||
for bm in self.bookmarks:
|
||||
if bm['jid'] == room_jid:
|
||||
del self.bookmarks[i]
|
||||
break
|
||||
i += 1
|
||||
self.get_module('Bookmarks').bookmarks.pop(jid, None)
|
||||
self.store_bookmarks()
|
||||
|
||||
def send_gc_status(self, nick, jid, show, status, auto=False):
|
||||
|
|
|
@ -50,7 +50,6 @@ from gajim.common import jingle_xtls
|
|||
from gajim.common import configpaths
|
||||
from gajim.common.caps_cache import muc_caps_cache
|
||||
from gajim.common.commands import ConnectionCommands
|
||||
from gajim.common.pubsub import ConnectionPubSub
|
||||
from gajim.common.protocol.caps import ConnectionCaps
|
||||
from gajim.common.protocol.bytestream import ConnectionSocks5Bytestream
|
||||
from gajim.common.protocol.bytestream import ConnectionIBBytestream
|
||||
|
@ -339,15 +338,15 @@ class ConnectionPEP(object):
|
|||
if message:
|
||||
i = item.addChild('text')
|
||||
i.addData(message)
|
||||
self._pubsub_connection.send_pb_publish('', nbxmpp.NS_ACTIVITY, item,
|
||||
'0')
|
||||
self.get_module('PubSub').send_pb_publish(
|
||||
'', nbxmpp.NS_ACTIVITY, item, '0')
|
||||
|
||||
def retract_activity(self):
|
||||
if not self.pep_supported:
|
||||
return
|
||||
self.send_activity(None)
|
||||
# not all client support new XEP, so we still retract
|
||||
self._pubsub_connection.send_pb_retract('', nbxmpp.NS_ACTIVITY, '0')
|
||||
self.get_module('PubSub').send_pb_retract('', nbxmpp.NS_ACTIVITY, '0')
|
||||
|
||||
def send_mood(self, mood, message=None):
|
||||
if self.connected == 1:
|
||||
|
@ -363,14 +362,14 @@ class ConnectionPEP(object):
|
|||
if message:
|
||||
i = item.addChild('text')
|
||||
i.addData(message)
|
||||
self._pubsub_connection.send_pb_publish('', nbxmpp.NS_MOOD, item, '0')
|
||||
self.get_module('PubSub').send_pb_publish('', nbxmpp.NS_MOOD, item, '0')
|
||||
|
||||
def retract_mood(self):
|
||||
if not self.pep_supported:
|
||||
return
|
||||
self.send_mood(None)
|
||||
# not all client support new XEP, so we still retract
|
||||
self._pubsub_connection.send_pb_retract('', nbxmpp.NS_MOOD, '0')
|
||||
self.get_module('PubSub').send_pb_retract('', nbxmpp.NS_MOOD, '0')
|
||||
|
||||
def send_tune(self, artist='', title='', source='', track=0, length=0,
|
||||
items=None):
|
||||
|
@ -399,14 +398,14 @@ class ConnectionPEP(object):
|
|||
i.addData(length)
|
||||
if items:
|
||||
item.addChild(payload=items)
|
||||
self._pubsub_connection.send_pb_publish('', nbxmpp.NS_TUNE, item, '0')
|
||||
self.get_module('PubSub').send_pb_publish('', nbxmpp.NS_TUNE, item, '0')
|
||||
|
||||
def retract_tune(self):
|
||||
if not self.pep_supported:
|
||||
return
|
||||
self.send_tune(None)
|
||||
# not all client support new XEP, so we still retract
|
||||
self._pubsub_connection.send_pb_retract('', nbxmpp.NS_TUNE, '0')
|
||||
self.get_module('PubSub').send_pb_retract('', nbxmpp.NS_TUNE, '0')
|
||||
|
||||
def send_nickname(self, nick):
|
||||
if self.connected == 1:
|
||||
|
@ -418,13 +417,13 @@ class ConnectionPEP(object):
|
|||
return
|
||||
item = nbxmpp.Node('nick', {'xmlns': nbxmpp.NS_NICK})
|
||||
item.addData(nick)
|
||||
self._pubsub_connection.send_pb_publish('', nbxmpp.NS_NICK, item, '0')
|
||||
self.get_module('PubSub').send_pb_publish('', nbxmpp.NS_NICK, item, '0')
|
||||
|
||||
def retract_nickname(self):
|
||||
if not self.pep_supported:
|
||||
return
|
||||
|
||||
self._pubsub_connection.send_pb_retract('', nbxmpp.NS_NICK, '0')
|
||||
self.get_module('PubSub').send_pb_retract('', nbxmpp.NS_NICK, '0')
|
||||
|
||||
def send_location(self, info):
|
||||
if self.connected == 1:
|
||||
|
@ -439,14 +438,14 @@ class ConnectionPEP(object):
|
|||
if info.get(field, None):
|
||||
i = item.addChild(field)
|
||||
i.addData(info[field])
|
||||
self._pubsub_connection.send_pb_publish('', nbxmpp.NS_LOCATION, item, '0')
|
||||
self.get_module('PubSub').send_pb_publish('', nbxmpp.NS_LOCATION, item, '0')
|
||||
|
||||
def retract_location(self):
|
||||
if not self.pep_supported:
|
||||
return
|
||||
self.send_location({})
|
||||
# not all client support new XEP, so we still retract
|
||||
self._pubsub_connection.send_pb_retract('', nbxmpp.NS_LOCATION, '0')
|
||||
self.get_module('PubSub').send_pb_retract('', nbxmpp.NS_LOCATION, '0')
|
||||
|
||||
# basic connection handlers used here and in zeroconf
|
||||
class ConnectionHandlersBase:
|
||||
|
@ -915,7 +914,7 @@ class ConnectionHandlersBase:
|
|||
|
||||
class ConnectionHandlers(ConnectionArchive313,
|
||||
ConnectionSocks5Bytestream, ConnectionDisco,
|
||||
ConnectionCommands, ConnectionPubSub, ConnectionPEP, ConnectionCaps,
|
||||
ConnectionCommands, ConnectionPEP, ConnectionCaps,
|
||||
ConnectionHandlersBase, ConnectionJingle, ConnectionIBBytestream,
|
||||
ConnectionHTTPUpload):
|
||||
def __init__(self):
|
||||
|
@ -923,7 +922,6 @@ ConnectionHTTPUpload):
|
|||
ConnectionSocks5Bytestream.__init__(self)
|
||||
ConnectionIBBytestream.__init__(self)
|
||||
ConnectionCommands.__init__(self)
|
||||
ConnectionPubSub.__init__(self)
|
||||
ConnectionPEP.__init__(self, account=self.name, dispatcher=self,
|
||||
pubsub_connection=self)
|
||||
ConnectionHTTPUpload.__init__(self)
|
||||
|
@ -949,8 +947,6 @@ ConnectionHTTPUpload):
|
|||
|
||||
self.privacy_default_list = None
|
||||
|
||||
app.nec.register_incoming_event(PrivateStorageBookmarksReceivedEvent)
|
||||
app.nec.register_incoming_event(BookmarksReceivedEvent)
|
||||
app.nec.register_incoming_event(StreamConflictReceivedEvent)
|
||||
app.nec.register_incoming_event(StreamOtherHostReceivedEvent)
|
||||
app.nec.register_incoming_event(MessageReceivedEvent)
|
||||
|
@ -961,8 +957,6 @@ ConnectionHTTPUpload):
|
|||
|
||||
app.ged.register_event_handler('roster-set-received',
|
||||
ged.CORE, self._nec_roster_set_received)
|
||||
app.ged.register_event_handler('private-storage-bookmarks-received',
|
||||
ged.CORE, self._nec_private_storate_bookmarks_received)
|
||||
app.ged.register_event_handler('roster-received', ged.CORE,
|
||||
self._nec_roster_received)
|
||||
app.ged.register_event_handler('iq-error-received', ged.CORE,
|
||||
|
@ -988,12 +982,9 @@ ConnectionHTTPUpload):
|
|||
ConnectionHandlersBase.cleanup(self)
|
||||
ConnectionCaps.cleanup(self)
|
||||
ConnectionArchive313.cleanup(self)
|
||||
ConnectionPubSub.cleanup(self)
|
||||
ConnectionHTTPUpload.cleanup(self)
|
||||
app.ged.remove_event_handler('roster-set-received',
|
||||
ged.CORE, self._nec_roster_set_received)
|
||||
app.ged.remove_event_handler('private-storage-bookmarks-received',
|
||||
ged.CORE, self._nec_private_storate_bookmarks_received)
|
||||
app.ged.remove_event_handler('roster-received', ged.CORE,
|
||||
self._nec_roster_received)
|
||||
app.ged.remove_event_handler('iq-error-received', ged.CORE,
|
||||
|
@ -1144,28 +1135,6 @@ ConnectionHTTPUpload):
|
|||
conn=self, stanza=obj.stanza))
|
||||
return True
|
||||
|
||||
def _nec_private_storate_bookmarks_received(self, obj):
|
||||
if obj.conn.name != self.name:
|
||||
return
|
||||
app.log('bookmarks').info('Received Bookmarks (PrivateStorage)')
|
||||
resend_to_pubsub = False
|
||||
bm_jids = [b['jid'] for b in self.bookmarks]
|
||||
for bm in obj.bookmarks:
|
||||
if bm['jid'] not in bm_jids:
|
||||
self.bookmarks.append(bm)
|
||||
# We got a bookmark that was not in pubsub
|
||||
resend_to_pubsub = True
|
||||
if resend_to_pubsub:
|
||||
self.store_bookmarks('pubsub')
|
||||
|
||||
def _PrivateCB(self, con, iq_obj):
|
||||
"""
|
||||
Private Data (XEP 048 and 049)
|
||||
"""
|
||||
log.debug('PrivateCB')
|
||||
app.nec.push_incoming_event(PrivateStorageReceivedEvent(None,
|
||||
conn=self, stanza=iq_obj))
|
||||
|
||||
def _SecLabelCB(self, con, iq_obj):
|
||||
"""
|
||||
Security Label callback, used for catalogues.
|
||||
|
@ -1540,8 +1509,8 @@ ConnectionHTTPUpload):
|
|||
# ask our VCard
|
||||
self.get_module('VCardTemp').request_vcard()
|
||||
|
||||
# Get bookmarks from private namespace
|
||||
self.get_bookmarks()
|
||||
# Get bookmarks
|
||||
self.get_module('Bookmarks').get_bookmarks()
|
||||
|
||||
# Get annotations from private namespace
|
||||
self.get_module('Annotations').get_annotations()
|
||||
|
@ -1645,7 +1614,6 @@ ConnectionHTTPUpload):
|
|||
nbxmpp.NS_MUC_OWNER)
|
||||
con.RegisterHandler('iq', self._MucAdminCB, 'result',
|
||||
nbxmpp.NS_MUC_ADMIN)
|
||||
con.RegisterHandler('iq', self._PrivateCB, 'result', nbxmpp.NS_PRIVATE)
|
||||
con.RegisterHandler('iq', self._SecLabelCB, 'result',
|
||||
nbxmpp.NS_SECLABEL_CATALOG)
|
||||
con.RegisterHandler('iq', self._CommandExecuteCB, 'set',
|
||||
|
@ -1657,8 +1625,6 @@ ConnectionHTTPUpload):
|
|||
con.RegisterHandler('iq', self._PrivacySetCB, 'set', nbxmpp.NS_PRIVACY)
|
||||
con.RegisterHandler('iq', self._ArchiveCB, ns=nbxmpp.NS_MAM_1)
|
||||
con.RegisterHandler('iq', self._ArchiveCB, ns=nbxmpp.NS_MAM_2)
|
||||
con.RegisterHandler('iq', self._PubSubCB, 'result')
|
||||
con.RegisterHandler('iq', self._PubSubErrorCB, 'error')
|
||||
con.RegisterHandler('iq', self._JingleCB, 'result')
|
||||
con.RegisterHandler('iq', self._JingleCB, 'error')
|
||||
con.RegisterHandler('iq', self._JingleCB, 'set', nbxmpp.NS_JINGLE)
|
||||
|
|
|
@ -309,118 +309,6 @@ class MucAdminReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
|
|||
self.users_dict[jid]['reason'] = reason
|
||||
return True
|
||||
|
||||
class PrivateStorageReceivedEvent(nec.NetworkIncomingEvent):
|
||||
name = 'private-storage-received'
|
||||
base_network_events = []
|
||||
|
||||
def generate(self):
|
||||
query = self.stanza.getTag('query')
|
||||
self.storage_node = query.getTag('storage')
|
||||
if self.storage_node:
|
||||
self.namespace = self.storage_node.getNamespace()
|
||||
return True
|
||||
|
||||
|
||||
class BookmarksHelper:
|
||||
def parse_bookmarks(self):
|
||||
self.bookmarks = []
|
||||
NS_GAJIM_BM = 'xmpp:gajim.org/bookmarks'
|
||||
confs = self.storage_node.getTags('conference')
|
||||
for conf in confs:
|
||||
autojoin_val = conf.getAttr('autojoin')
|
||||
if not autojoin_val: # not there (it's optional)
|
||||
autojoin_val = False
|
||||
minimize_val = conf.getTag('minimize', namespace=NS_GAJIM_BM)
|
||||
if not minimize_val: # not there, try old Gajim behaviour
|
||||
minimize_val = conf.getAttr('minimize')
|
||||
if not minimize_val: # not there (it's optional)
|
||||
minimize_val = False
|
||||
else:
|
||||
minimize_val = minimize_val.getData()
|
||||
|
||||
print_status = conf.getTag('print_status', namespace=NS_GAJIM_BM)
|
||||
if not print_status: # not there, try old Gajim behaviour
|
||||
print_status = conf.getTagData('print_status')
|
||||
if not print_status: # not there, try old Gajim behaviour
|
||||
print_status = conf.getTagData('show_status')
|
||||
else:
|
||||
print_status = print_status.getData()
|
||||
|
||||
try:
|
||||
jid = helpers.parse_jid(conf.getAttr('jid'))
|
||||
except helpers.InvalidFormat:
|
||||
log.warning('Invalid JID: %s, ignoring it'
|
||||
% conf.getAttr('jid'))
|
||||
continue
|
||||
|
||||
bm = {'name': conf.getAttr('name'),
|
||||
'jid': jid,
|
||||
'autojoin': autojoin_val,
|
||||
'minimize': minimize_val,
|
||||
'password': conf.getTagData('password'),
|
||||
'nick': conf.getTagData('nick'),
|
||||
'print_status': print_status}
|
||||
|
||||
bm_jids = [b['jid'] for b in self.bookmarks]
|
||||
if bm['jid'] not in bm_jids:
|
||||
self.bookmarks.append(bm)
|
||||
|
||||
class PrivateStorageBookmarksReceivedEvent(nec.NetworkIncomingEvent,
|
||||
BookmarksHelper):
|
||||
name = 'private-storage-bookmarks-received'
|
||||
base_network_events = ['private-storage-received']
|
||||
|
||||
def generate(self):
|
||||
self.conn = self.base_event.conn
|
||||
self.storage_node = self.base_event.storage_node
|
||||
if self.base_event.namespace != nbxmpp.NS_BOOKMARKS:
|
||||
return
|
||||
self.parse_bookmarks()
|
||||
return True
|
||||
|
||||
class BookmarksReceivedEvent(nec.NetworkIncomingEvent):
|
||||
name = 'bookmarks-received'
|
||||
base_network_events = ['private-storage-bookmarks-received',
|
||||
'pubsub-bookmarks-received']
|
||||
|
||||
def generate(self):
|
||||
self.conn = self.base_event.conn
|
||||
self.bookmarks = self.base_event.bookmarks
|
||||
return True
|
||||
|
||||
class PubsubReceivedEvent(nec.NetworkIncomingEvent):
|
||||
name = 'pubsub-received'
|
||||
base_network_events = []
|
||||
|
||||
def generate(self):
|
||||
self.jid = self.stanza.getFrom()
|
||||
self.pubsub_node = self.stanza.getTag('pubsub')
|
||||
if not self.pubsub_node:
|
||||
return
|
||||
self.items_node = self.pubsub_node.getTag('items')
|
||||
if not self.items_node:
|
||||
return
|
||||
return True
|
||||
|
||||
class PubsubBookmarksReceivedEvent(nec.NetworkIncomingEvent, BookmarksHelper):
|
||||
name = 'pubsub-bookmarks-received'
|
||||
base_network_events = ['pubsub-received']
|
||||
|
||||
def generate(self):
|
||||
self.conn = self.base_event.conn
|
||||
self.item_node = self.base_event.items_node.getTag('item')
|
||||
if not self.item_node:
|
||||
return
|
||||
children = self.item_node.getChildren()
|
||||
if not children:
|
||||
return
|
||||
self.storage_node = children[0]
|
||||
ns = self.storage_node.getNamespace()
|
||||
if ns != nbxmpp.NS_BOOKMARKS:
|
||||
return
|
||||
self.parse_bookmarks()
|
||||
return True
|
||||
|
||||
class IqErrorReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
|
||||
name = 'iq-error-received'
|
||||
base_network_events = []
|
||||
|
|
|
@ -119,6 +119,11 @@ class RequestAvatar(IntEnum):
|
|||
ROOM = 1
|
||||
USER = 2
|
||||
|
||||
@unique
|
||||
class BookmarkStorageType(IntEnum):
|
||||
PRIVATE = 0
|
||||
PUBSUB = 1
|
||||
|
||||
SSLError = {
|
||||
2: _("Unable to get issuer certificate"),
|
||||
3: _("Unable to get certificate CRL"),
|
||||
|
|
|
@ -0,0 +1,294 @@
|
|||
# This file is part of Gajim.
|
||||
#
|
||||
# Gajim is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation; version 3 only.
|
||||
#
|
||||
# Gajim is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# XEP-0048: Bookmarks
|
||||
|
||||
import logging
|
||||
|
||||
import nbxmpp
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common import helpers
|
||||
from gajim.common.const import BookmarkStorageType
|
||||
from gajim.common.nec import NetworkIncomingEvent
|
||||
|
||||
log = logging.getLogger('gajim.c.m.bookmarks')
|
||||
|
||||
|
||||
class Bookmarks:
|
||||
def __init__(self, con):
|
||||
self._con = con
|
||||
self._account = con.name
|
||||
self.bookmarks = {}
|
||||
|
||||
self.handlers = []
|
||||
|
||||
def _pubsub_support(self):
|
||||
return (self._con.pep_supported and
|
||||
self._con.pubsub_publish_options_supported)
|
||||
|
||||
def get_bookmarks(self, storage_type=None):
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
|
||||
if storage_type in (None, BookmarkStorageType.PUBSUB):
|
||||
if self._pubsub_support():
|
||||
self._request_pubsub_bookmarks()
|
||||
else:
|
||||
# Fallback, request private storage
|
||||
self._request_private_bookmarks()
|
||||
else:
|
||||
log.info('Request Bookmarks (PrivateStorage)')
|
||||
self._request_private_bookmarks()
|
||||
|
||||
def _request_pubsub_bookmarks(self):
|
||||
log.info('Request Bookmarks (PubSub)')
|
||||
self._con.get_module('PubSub').send_pb_retrieve(
|
||||
'', 'storage:bookmarks',
|
||||
cb=self._pubsub_bookmarks_received)
|
||||
|
||||
def _pubsub_bookmarks_received(self, conn, stanza):
|
||||
if not nbxmpp.isResultNode(stanza):
|
||||
log.info('No pubsub bookmarks: %s', stanza.getError())
|
||||
# Fallback, request private storage
|
||||
self._request_private_bookmarks()
|
||||
return
|
||||
|
||||
log.info('Received Bookmarks (PubSub)')
|
||||
self._parse_bookmarks(stanza)
|
||||
self._request_private_bookmarks()
|
||||
|
||||
def _request_private_bookmarks(self):
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
|
||||
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._private_bookmarks_received)
|
||||
|
||||
def _private_bookmarks_received(self, stanza):
|
||||
if not nbxmpp.isResultNode(stanza):
|
||||
log.info('No private bookmarks: %s', stanza.getError())
|
||||
else:
|
||||
log.info('Received Bookmarks (PrivateStorage)')
|
||||
merged = self._parse_bookmarks(stanza, check_merge=True)
|
||||
if merged:
|
||||
log.info('Merge PrivateStorage with PubSub')
|
||||
self.store_bookmarks(BookmarkStorageType.PUBSUB)
|
||||
self.auto_join_bookmarks()
|
||||
app.nec.push_incoming_event(BookmarksReceivedEvent(
|
||||
None, 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
|
||||
|
||||
def _parse_bookmarks(self, stanza, check_merge=False):
|
||||
merged = False
|
||||
storage = self._get_storage_node(stanza)
|
||||
if storage is None:
|
||||
return
|
||||
|
||||
NS_GAJIM_BM = 'xmpp:gajim.org/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
|
||||
minimize_val = conf.getTag('minimize', namespace=NS_GAJIM_BM)
|
||||
if not minimize_val: # not there, try old Gajim behaviour
|
||||
minimize_val = conf.getAttr('minimize')
|
||||
if not minimize_val: # not there (it's optional)
|
||||
minimize_val = False
|
||||
else:
|
||||
minimize_val = minimize_val.getData()
|
||||
|
||||
print_status = conf.getTag('print_status', namespace=NS_GAJIM_BM)
|
||||
if not print_status: # not there, try old Gajim behaviour
|
||||
print_status = conf.getTagData('print_status')
|
||||
if not print_status: # not there, try old Gajim behaviour
|
||||
print_status = conf.getTagData('show_status')
|
||||
else:
|
||||
print_status = print_status.getData()
|
||||
|
||||
try:
|
||||
jid = helpers.parse_jid(conf.getAttr('jid'))
|
||||
except helpers.InvalidFormat:
|
||||
log.warning('Invalid JID: %s, ignoring it'
|
||||
% conf.getAttr('jid'))
|
||||
continue
|
||||
|
||||
if check_merge:
|
||||
if jid not in self.bookmarks:
|
||||
merged = True
|
||||
|
||||
log.debug('Found Bookmark: %s', jid)
|
||||
self.bookmarks[jid] = {
|
||||
'name': conf.getAttr('name'),
|
||||
'autojoin': autojoin_val,
|
||||
'minimize': minimize_val,
|
||||
'password': conf.getTagData('password'),
|
||||
'nick': conf.getTagData('nick'),
|
||||
'print_status': print_status}
|
||||
|
||||
return merged
|
||||
|
||||
def _build_storage_node(self):
|
||||
NS_GAJIM_BM = 'xmpp:gajim.org/bookmarks'
|
||||
storage_node = nbxmpp.Node(
|
||||
tag='storage', attrs={'xmlns': 'storage:bookmarks'})
|
||||
for jid, bm in self.bookmarks.items():
|
||||
conf_node = storage_node.addChild(name="conference")
|
||||
conf_node.setAttr('jid', jid)
|
||||
conf_node.setAttr('autojoin', bm['autojoin'])
|
||||
conf_node.setAttr('name', bm['name'])
|
||||
conf_node.setTag(
|
||||
'minimize', namespace=NS_GAJIM_BM).setData(bm['minimize'])
|
||||
# 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'])
|
||||
if bm.get('print_status', None):
|
||||
conf_node.setTag(
|
||||
'print_status',
|
||||
namespace=NS_GAJIM_BM).setData(bm['print_status'])
|
||||
return storage_node
|
||||
|
||||
@staticmethod
|
||||
def get_bookmark_publish_options():
|
||||
options = nbxmpp.Node(nbxmpp.NS_DATA + ' x',
|
||||
attrs={'type': 'submit'})
|
||||
f = options.addChild('field',
|
||||
attrs={'var': 'FORM_TYPE', 'type': 'hidden'})
|
||||
f.setTagData('value', nbxmpp.NS_PUBSUB_PUBLISH_OPTIONS)
|
||||
f = options.addChild('field', attrs={'var': 'pubsub#access_model'})
|
||||
f.setTagData('value', 'whitelist')
|
||||
return options
|
||||
|
||||
def store_bookmarks(self, storage_type=None):
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
|
||||
storage_node = self._build_storage_node()
|
||||
|
||||
if storage_type is None:
|
||||
if self._pubsub_support():
|
||||
self._pubsub_store(storage_node)
|
||||
else:
|
||||
self._private_store(storage_node)
|
||||
elif storage_type == BookmarkStorageType.PUBSUB:
|
||||
if self._pubsub_support():
|
||||
self._pubsub_store(storage_node)
|
||||
elif storage_type == BookmarkStorageType.PRIVATE:
|
||||
self._private_store(storage_node)
|
||||
|
||||
def _pubsub_store(self, storage_node):
|
||||
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):
|
||||
iq = nbxmpp.Iq('set', nbxmpp.NS_PRIVATE, payload=storage_node)
|
||||
log.info('Publish Bookmarks (PrivateStorage)')
|
||||
self._con.connection.SendAndCallForResponse(
|
||||
iq, self._private_store_result)
|
||||
|
||||
def _pubsub_store_result(self, conn, stanza):
|
||||
if not nbxmpp.isResultNode(stanza):
|
||||
log.error('Error: %s', stanza.getError())
|
||||
return
|
||||
|
||||
def _private_store_result(self, stanza):
|
||||
if not nbxmpp.isResultNode(stanza):
|
||||
log.error('Error: %s', stanza.getError())
|
||||
return
|
||||
|
||||
def auto_join_bookmarks(self):
|
||||
if app.is_invisible(self._account):
|
||||
return
|
||||
for jid, bm in self.bookmarks.items():
|
||||
if bm['autojoin'] in ('1', 'true'):
|
||||
# Only join non-opened groupchats. Opened one are already
|
||||
# auto-joined on re-connection
|
||||
if jid not in app.gc_connected[self._account]:
|
||||
# we are not already connected
|
||||
minimize = bm['minimize'] in ('1', 'true')
|
||||
app.interface.join_gc_room(
|
||||
self._account, jid, bm['nick'],
|
||||
bm['password'], minimize=minimize)
|
||||
|
||||
def add_bookmark(self, name, jid, autojoin,
|
||||
minimize, password, nick):
|
||||
self.bookmarks[jid] = {
|
||||
'name': name,
|
||||
'autojoin': autojoin,
|
||||
'minimize': minimize,
|
||||
'password': password,
|
||||
'nick': nick}
|
||||
|
||||
self.store_bookmarks()
|
||||
app.nec.push_incoming_event(BookmarksReceivedEvent(
|
||||
None, account=self._account))
|
||||
|
||||
def get_name_from_bookmark(self, jid):
|
||||
try:
|
||||
return self.bookmarks[jid]['name']
|
||||
except KeyError:
|
||||
return jid.split('@')[0]
|
||||
|
||||
def purge_pubsub_bookmarks(self):
|
||||
log.info('Purge/Delete Bookmarks on PubSub, '
|
||||
'because publish options are not available')
|
||||
self._con.get_module('PubSub').send_pb_purge('', 'storage:bookmarks')
|
||||
self._con.get_module('PubSub').send_pb_delete('', 'storage:bookmarks')
|
||||
|
||||
|
||||
class BookmarksReceivedEvent(NetworkIncomingEvent):
|
||||
name = 'bookmarks-received'
|
||||
base_network_events = []
|
|
@ -0,0 +1,217 @@
|
|||
# Copyright (C) 2006 Tomasz Melcer <liori AT exroot.org>
|
||||
# Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org>
|
||||
# Copyright (C) 2007 Jean-Marie Traissard <jim AT lapin.org>
|
||||
# Copyright (C) 2008 Stephan Erb <steve-e AT h3c.de>
|
||||
# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
|
||||
#
|
||||
# This file is part of Gajim.
|
||||
#
|
||||
# Gajim is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation; version 3 only.
|
||||
#
|
||||
# Gajim is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# XEP-0060: Publish-Subscribe
|
||||
|
||||
import logging
|
||||
|
||||
import nbxmpp
|
||||
|
||||
from gajim.common import app
|
||||
|
||||
log = logging.getLogger('gajim.c.m.pubsub')
|
||||
|
||||
|
||||
class PubSub:
|
||||
def __init__(self, con):
|
||||
self._con = con
|
||||
self._account = con.name
|
||||
|
||||
self.handlers = []
|
||||
|
||||
def send_pb_subscription_query(self, jid, cb, **kwargs):
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
|
||||
query = nbxmpp.Iq('get', to=jid)
|
||||
pb = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
|
||||
pb.addChild('subscriptions')
|
||||
|
||||
self._con.connection.SendAndCallForResponse(query, cb, kwargs)
|
||||
|
||||
def send_pb_subscribe(self, jid, node, cb, **kwargs):
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
|
||||
our_jid = app.get_jid_from_account(self._account)
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
pb = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
|
||||
pb.addChild('subscribe', {'node': node, 'jid': our_jid})
|
||||
|
||||
self._con.connection.SendAndCallForResponse(query, cb, kwargs)
|
||||
|
||||
def send_pb_unsubscribe(self, jid, node, cb, **kwargs):
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
|
||||
our_jid = app.get_jid_from_account(self._account)
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
pb = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
|
||||
pb.addChild('unsubscribe', {'node': node, 'jid': our_jid})
|
||||
|
||||
self._con.connection.SendAndCallForResponse(query, cb, kwargs)
|
||||
|
||||
def send_pb_publish(self, jid, node, item,
|
||||
id_=None, options=None, cb=None, **kwargs):
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
|
||||
if cb is None:
|
||||
cb = self._default_callback
|
||||
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
e = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
|
||||
p = e.addChild('publish', {'node': node})
|
||||
attrs = {}
|
||||
if id_:
|
||||
attrs = {'id': id_}
|
||||
p.addChild('item', attrs, [item])
|
||||
if options:
|
||||
p = e.addChild('publish-options')
|
||||
p.addChild(node=options)
|
||||
|
||||
self._con.connection.SendAndCallForResponse(query, cb, kwargs)
|
||||
|
||||
@staticmethod
|
||||
def get_pb_retrieve_iq(jid, node, item_id=None):
|
||||
"""
|
||||
Get IQ to query items from a node
|
||||
"""
|
||||
query = nbxmpp.Iq('get', to=jid)
|
||||
r = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
|
||||
r = r.addChild('items', {'node': node})
|
||||
if item_id is not None:
|
||||
r.addChild('item', {'id': item_id})
|
||||
return query
|
||||
|
||||
def send_pb_retrieve(self, jid, node, item_id=None, cb=None, **kwargs):
|
||||
"""
|
||||
Get items from a node
|
||||
"""
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
|
||||
if cb is None:
|
||||
cb = self._default_callback
|
||||
|
||||
query = self.get_pb_retrieve_iq(jid, node, item_id)
|
||||
|
||||
self._con.connection.SendAndCallForResponse(query, cb, kwargs)
|
||||
|
||||
def send_pb_retract(self, jid, node, id_, cb=None, **kwargs):
|
||||
"""
|
||||
Delete item from a node
|
||||
"""
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
|
||||
if cb is None:
|
||||
cb = self._default_callback
|
||||
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
r = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
|
||||
r = r.addChild('retract', {'node': node, 'notify': '1'})
|
||||
r = r.addChild('item', {'id': id_})
|
||||
|
||||
self._con.connection.SendAndCallForResponse(query, cb, kwargs)
|
||||
|
||||
def send_pb_purge(self, jid, node, cb=None, **kwargs):
|
||||
"""
|
||||
Purge node: Remove all items
|
||||
"""
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
|
||||
if cb is None:
|
||||
cb = self._default_callback
|
||||
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
d = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
|
||||
d = d.addChild('purge', {'node': node})
|
||||
|
||||
self._con.connection.SendAndCallForResponse(query, cb, kwargs)
|
||||
|
||||
def send_pb_delete(self, jid, node, on_ok=None, on_fail=None):
|
||||
"""
|
||||
Delete node
|
||||
"""
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
d = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
|
||||
d = d.addChild('delete', {'node': node})
|
||||
|
||||
def response(con, resp, jid, node):
|
||||
if resp.getType() == 'result' and on_ok:
|
||||
on_ok(jid, node)
|
||||
elif on_fail:
|
||||
msg = resp.getErrorMsg()
|
||||
on_fail(jid, node, msg)
|
||||
|
||||
self._con.connection.SendAndCallForResponse(
|
||||
query, response, {'jid': jid, 'node': node})
|
||||
|
||||
def send_pb_create(self, jid, node, cb,
|
||||
configure=False, configure_form=None):
|
||||
"""
|
||||
Create a new node
|
||||
"""
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
c = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
|
||||
c = c.addChild('create', {'node': node})
|
||||
if configure:
|
||||
conf = c.addChild('configure')
|
||||
if configure_form is not None:
|
||||
conf.addChild(node=configure_form)
|
||||
|
||||
self._con.connection.SendAndCallForResponse(query, cb)
|
||||
|
||||
def send_pb_configure(self, jid, node, form, cb=None):
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
|
||||
if cb is None:
|
||||
cb = self._default_callback
|
||||
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
c = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
|
||||
c = c.addChild('configure', {'node': node})
|
||||
c.addChild(node=form)
|
||||
|
||||
self._con.connection.SendAndCallForResponse(query, cb)
|
||||
|
||||
def request_pb_configuration(self, jid, node, cb=None):
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
|
||||
if cb is None:
|
||||
cb = self._default_callback
|
||||
|
||||
query = nbxmpp.Iq('get', to=jid)
|
||||
e = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
|
||||
e = e.addChild('configure', {'node': node})
|
||||
|
||||
self._con.connection.SendAndCallForResponse(query, cb)
|
||||
|
||||
def _default_callback(self, conn, stanza, *args, **kwargs):
|
||||
if not nbxmpp.isResultNode(stanza):
|
||||
log.warning('Error: %s', stanza.getError())
|
|
@ -0,0 +1,96 @@
|
|||
# This file is part of Gajim.
|
||||
#
|
||||
# Gajim is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation; version 3 only.
|
||||
#
|
||||
# Gajim is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# XEP-0084: User Avatar
|
||||
|
||||
import logging
|
||||
import base64
|
||||
import binascii
|
||||
|
||||
import nbxmpp
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common.exceptions import StanzaMalformed
|
||||
|
||||
log = logging.getLogger('gajim.c.m.user_avatar')
|
||||
|
||||
|
||||
class UserAvatar:
|
||||
def __init__(self, con):
|
||||
self._con = con
|
||||
self._account = con.name
|
||||
|
||||
self.handlers = []
|
||||
|
||||
def get_pubsub_avatar(self, jid, item_id):
|
||||
log.info('Request: %s %s', jid, item_id)
|
||||
self._con.get_module('PubSub').send_pb_retrieve(
|
||||
jid, 'urn:xmpp:avatar:data', item_id, self._avatar_received)
|
||||
|
||||
def _validate_avatar_node(self, stanza):
|
||||
jid = stanza.getFrom()
|
||||
if jid is None:
|
||||
jid = self._con.get_own_jid().getStripped()
|
||||
else:
|
||||
jid = jid.getStripped()
|
||||
|
||||
if nbxmpp.isErrorNode(stanza):
|
||||
raise StanzaMalformed(stanza.getErrorMsg())
|
||||
|
||||
pubsub_node = stanza.getTag('pubsub')
|
||||
if pubsub_node is None:
|
||||
raise StanzaMalformed('No pubsub node', stanza)
|
||||
|
||||
items_node = pubsub_node.getTag('items')
|
||||
if items_node is None:
|
||||
raise StanzaMalformed('No items node', stanza)
|
||||
|
||||
if items_node.getAttr('node') != 'urn:xmpp:avatar:data':
|
||||
raise StanzaMalformed('Wrong namespace', stanza)
|
||||
|
||||
item = items_node.getTag('item')
|
||||
if item is None:
|
||||
raise StanzaMalformed('No item node', stanza)
|
||||
|
||||
sha = item.getAttr('id')
|
||||
data_tag = item.getTag('data', namespace='urn:xmpp:avatar:data')
|
||||
if sha is None or data_tag is None:
|
||||
raise StanzaMalformed('No id attr or data node found', stanza)
|
||||
|
||||
data = data_tag.getData()
|
||||
if data is None:
|
||||
raise StanzaMalformed('Data node empty', stanza)
|
||||
|
||||
data = base64.b64decode(data.encode('utf-8'))
|
||||
|
||||
return jid, sha, data
|
||||
|
||||
def _avatar_received(self, conn, stanza):
|
||||
try:
|
||||
jid, sha, data = self._validate_avatar_node(stanza)
|
||||
except (StanzaMalformed, binascii.Error) as error:
|
||||
log.warning('Error: %s %s', stanza.getFrom(), error)
|
||||
return
|
||||
|
||||
log.info('Received: %s %s', jid, sha)
|
||||
app.interface.save_avatar(data)
|
||||
|
||||
if self._con.get_own_jid().bareMatch(jid):
|
||||
app.config.set_per('accounts', self._account, 'avatar_sha', sha)
|
||||
else:
|
||||
own_jid = self._con.get_own_jid().getStripped()
|
||||
app.logger.set_avatar_sha(own_jid, jid, sha)
|
||||
app.contacts.set_avatar(self._account, jid, sha)
|
||||
|
||||
app.interface.update_avatar(self._account, jid)
|
|
@ -485,7 +485,8 @@ class AvatarNotificationPEP(AbstractPEP):
|
|||
for item in items.getTags('item'):
|
||||
metadata = item.getTag('metadata')
|
||||
if metadata is None:
|
||||
app.log('avatar').warning('Invalid avatar stanza:\n%s', items)
|
||||
app.log('c.m.user_avatar').warning(
|
||||
'Invalid avatar stanza:\n%s', items)
|
||||
break
|
||||
info = item.getTag('metadata').getTag('info')
|
||||
if info is not None:
|
||||
|
@ -498,23 +499,22 @@ class AvatarNotificationPEP(AbstractPEP):
|
|||
con = app.connections[account]
|
||||
if self.avatar is None:
|
||||
# Remove avatar
|
||||
app.log('avatar').info('Remove (Pubsub): %s', jid)
|
||||
app.log('c.m.user_avatar').info('Remove: %s', jid)
|
||||
app.contacts.set_avatar(account, jid, None)
|
||||
own_jid = con.get_own_jid().getStripped()
|
||||
app.logger.set_avatar_sha(own_jid, jid, None)
|
||||
app.interface.update_avatar(account, jid)
|
||||
else:
|
||||
sha = app.contacts.get_avatar_sha(account, jid)
|
||||
app.log('avatar').info(
|
||||
'Update (Pubsub): %s %s', jid, self.avatar['id'])
|
||||
app.log('c.m.user_avatar').info(
|
||||
'Update: %s %s', jid, self.avatar['id'])
|
||||
if sha == self.avatar['id']:
|
||||
app.log('avatar').info(
|
||||
'Avatar already known (Pubsub): %s %s',
|
||||
app.log('c.m.user_avatar').info(
|
||||
'Avatar already known: %s %s',
|
||||
jid, self.avatar['id'])
|
||||
return
|
||||
app.log('avatar').info('Request (Pubsub): %s', jid)
|
||||
con.get_pubsub_avatar(jid, 'urn:xmpp:avatar:data',
|
||||
self.avatar['id'])
|
||||
con.get_module('UserAvatar').get_pubsub_avatar(
|
||||
jid, self.avatar['id'])
|
||||
|
||||
|
||||
SUPPORTED_PERSONAL_USER_EVENTS = [
|
||||
|
|
|
@ -1,306 +0,0 @@
|
|||
# -*- coding:utf-8 -*-
|
||||
## src/common/pubsub.py
|
||||
##
|
||||
## Copyright (C) 2006 Tomasz Melcer <liori AT exroot.org>
|
||||
## Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org>
|
||||
## Copyright (C) 2007 Jean-Marie Traissard <jim AT lapin.org>
|
||||
## Copyright (C) 2008 Stephan Erb <steve-e AT h3c.de>
|
||||
##
|
||||
## This file is part of Gajim.
|
||||
##
|
||||
## Gajim is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published
|
||||
## by the Free Software Foundation; version 3 only.
|
||||
##
|
||||
## Gajim is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
##
|
||||
|
||||
import base64
|
||||
import binascii
|
||||
|
||||
import nbxmpp
|
||||
from gajim.common import app
|
||||
#TODO: Doesn't work
|
||||
#from common.connection_handlers import PEP_CONFIG
|
||||
PEP_CONFIG = 'pep_config'
|
||||
from gajim.common import ged
|
||||
from gajim.common.connection_handlers_events import PubsubReceivedEvent
|
||||
from gajim.common.connection_handlers_events import PubsubBookmarksReceivedEvent
|
||||
from gajim.common.exceptions import StanzaMalformed
|
||||
|
||||
import logging
|
||||
log = logging.getLogger('gajim.c.pubsub')
|
||||
|
||||
class ConnectionPubSub:
|
||||
def __init__(self):
|
||||
self.__callbacks = {}
|
||||
app.nec.register_incoming_event(PubsubBookmarksReceivedEvent)
|
||||
app.ged.register_event_handler('pubsub-bookmarks-received',
|
||||
ged.CORE, self._nec_pubsub_bookmarks_received)
|
||||
|
||||
def cleanup(self):
|
||||
app.ged.remove_event_handler('pubsub-bookmarks-received',
|
||||
ged.CORE, self._nec_pubsub_bookmarks_received)
|
||||
|
||||
def send_pb_subscription_query(self, jid, cb, *args, **kwargs):
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
query = nbxmpp.Iq('get', to=jid)
|
||||
pb = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
|
||||
pb.addChild('subscriptions')
|
||||
|
||||
id_ = self.connection.send(query)
|
||||
|
||||
self.__callbacks[id_] = (cb, args, kwargs)
|
||||
|
||||
def send_pb_subscribe(self, jid, node, cb, *args, **kwargs):
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
our_jid = app.get_jid_from_account(self.name)
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
pb = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
|
||||
pb.addChild('subscribe', {'node': node, 'jid': our_jid})
|
||||
|
||||
id_ = self.connection.send(query)
|
||||
|
||||
self.__callbacks[id_] = (cb, args, kwargs)
|
||||
|
||||
def send_pb_unsubscribe(self, jid, node, cb, *args, **kwargs):
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
our_jid = app.get_jid_from_account(self.name)
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
pb = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
|
||||
pb.addChild('unsubscribe', {'node': node, 'jid': our_jid})
|
||||
|
||||
id_ = self.connection.send(query)
|
||||
|
||||
self.__callbacks[id_] = (cb, args, kwargs)
|
||||
|
||||
def send_pb_publish(self, jid, node, item, id_=None, options=None):
|
||||
"""
|
||||
Publish item to a node
|
||||
"""
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
e = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
|
||||
p = e.addChild('publish', {'node': node})
|
||||
attrs = {}
|
||||
if id_:
|
||||
attrs = {'id': id_}
|
||||
p.addChild('item', attrs, [item])
|
||||
if options:
|
||||
p = e.addChild('publish-options')
|
||||
p.addChild(node=options)
|
||||
|
||||
self.connection.send(query)
|
||||
|
||||
@staticmethod
|
||||
def get_pb_retrieve_iq(jid, node, item_id=None):
|
||||
"""
|
||||
Get IQ to query items from a node
|
||||
"""
|
||||
query = nbxmpp.Iq('get', to=jid)
|
||||
r = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
|
||||
r = r.addChild('items', {'node': node})
|
||||
if item_id is not None:
|
||||
r.addChild('item', {'id': item_id})
|
||||
return query
|
||||
|
||||
def send_pb_retrieve(self, jid, node, item_id=None, cb=None, *args, **kwargs):
|
||||
"""
|
||||
Get items from a node
|
||||
"""
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
query = self.get_pb_retrieve_iq(jid, node, item_id)
|
||||
id_ = self.connection.send(query)
|
||||
|
||||
if cb:
|
||||
self.__callbacks[id_] = (cb, args, kwargs)
|
||||
|
||||
def get_pubsub_avatar(self, jid, node, item_id):
|
||||
query = self.get_pb_retrieve_iq(jid, node, item_id)
|
||||
self.connection.SendAndCallForResponse(
|
||||
query, self._nec_pubsub_avatar_received, {'jid': jid})
|
||||
|
||||
def send_pb_retract(self, jid, node, id_):
|
||||
"""
|
||||
Delete item from a node
|
||||
"""
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
r = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
|
||||
r = r.addChild('retract', {'node': node, 'notify': '1'})
|
||||
r = r.addChild('item', {'id': id_})
|
||||
|
||||
self.connection.send(query)
|
||||
|
||||
def send_pb_purge(self, jid, node):
|
||||
"""
|
||||
Purge node: Remove all items
|
||||
"""
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
d = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
|
||||
d = d.addChild('purge', {'node': node})
|
||||
|
||||
self.connection.send(query)
|
||||
|
||||
def send_pb_delete(self, jid, node, on_ok=None, on_fail=None):
|
||||
"""
|
||||
Delete node
|
||||
"""
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
d = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
|
||||
d = d.addChild('delete', {'node': node})
|
||||
|
||||
def response(con, resp, jid, node):
|
||||
if resp.getType() == 'result' and on_ok:
|
||||
on_ok(jid, node)
|
||||
elif on_fail:
|
||||
msg = resp.getErrorMsg()
|
||||
on_fail(jid, node, msg)
|
||||
|
||||
self.connection.SendAndCallForResponse(query, response, {'jid': jid,
|
||||
'node': node})
|
||||
|
||||
def send_pb_create(self, jid, node, configure=False, configure_form=None):
|
||||
"""
|
||||
Create a new node
|
||||
"""
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
c = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB)
|
||||
c = c.addChild('create', {'node': node})
|
||||
if configure:
|
||||
conf = c.addChild('configure')
|
||||
if configure_form is not None:
|
||||
conf.addChild(node=configure_form)
|
||||
|
||||
self.connection.send(query)
|
||||
|
||||
def send_pb_configure(self, jid, node, form):
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
query = nbxmpp.Iq('set', to=jid)
|
||||
c = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
|
||||
c = c.addChild('configure', {'node': node})
|
||||
c.addChild(node=form)
|
||||
|
||||
self.connection.send(query)
|
||||
|
||||
def _PubSubCB(self, conn, stanza):
|
||||
log.debug('_PubsubCB')
|
||||
try:
|
||||
cb, args, kwargs = self.__callbacks.pop(stanza.getID())
|
||||
cb(conn, stanza, *args, **kwargs)
|
||||
except Exception:
|
||||
pass
|
||||
app.nec.push_incoming_event(PubsubReceivedEvent(None,
|
||||
conn=self, stanza=stanza))
|
||||
|
||||
def _nec_pubsub_bookmarks_received(self, obj):
|
||||
if obj.conn.name != self.name:
|
||||
return
|
||||
app.log('bookmarks').info('Received Bookmarks (PubSub)')
|
||||
bm_jids = [b['jid'] for b in self.bookmarks]
|
||||
for bm in obj.bookmarks:
|
||||
if bm['jid'] not in bm_jids:
|
||||
self.bookmarks.append(bm)
|
||||
# We got bookmarks from pubsub, now get those from xml to merge them
|
||||
self.get_bookmarks(storage_type='xml')
|
||||
|
||||
def _validate_avatar_node(self, stanza):
|
||||
jid = stanza.getFrom()
|
||||
if jid is None:
|
||||
jid = self.get_own_jid().getStripped()
|
||||
else:
|
||||
jid = jid.getStripped()
|
||||
|
||||
if nbxmpp.isErrorNode(stanza):
|
||||
raise StanzaMalformed(stanza.getErrorMsg())
|
||||
|
||||
pubsub_node = stanza.getTag('pubsub')
|
||||
if pubsub_node is None:
|
||||
raise StanzaMalformed('No pubsub node', stanza)
|
||||
|
||||
items_node = pubsub_node.getTag('items')
|
||||
if items_node is None:
|
||||
raise StanzaMalformed('No items node', stanza)
|
||||
|
||||
if items_node.getAttr('node') != 'urn:xmpp:avatar:data':
|
||||
raise StanzaMalformed('Wrong namespace', stanza)
|
||||
|
||||
item = items_node.getTag('item')
|
||||
if item is None:
|
||||
raise StanzaMalformed('No item node', stanza)
|
||||
|
||||
sha = item.getAttr('id')
|
||||
data_tag = item.getTag('data', namespace='urn:xmpp:avatar:data')
|
||||
if sha is None or data_tag is None:
|
||||
raise StanzaMalformed('No id attr or data node found', stanza)
|
||||
|
||||
data = data_tag.getData()
|
||||
if data is None:
|
||||
raise StanzaMalformed('Data node empty', stanza)
|
||||
|
||||
data = base64.b64decode(data.encode('utf-8'))
|
||||
|
||||
return jid, sha, data
|
||||
|
||||
def _nec_pubsub_avatar_received(self, conn, stanza, jid):
|
||||
try:
|
||||
jid, sha, data = self._validate_avatar_node(stanza)
|
||||
except (StanzaMalformed, binascii.Error) as error:
|
||||
app.log('avatar').warning(
|
||||
'Error loading Avatar (Pubsub): %s %s', jid, error)
|
||||
return
|
||||
|
||||
app.log('avatar').info(
|
||||
'Received Avatar (Pubsub): %s %s', jid, sha)
|
||||
app.interface.save_avatar(data)
|
||||
|
||||
if self.get_own_jid().bareMatch(jid):
|
||||
app.config.set_per('accounts', self.name, 'avatar_sha', sha)
|
||||
else:
|
||||
own_jid = self.get_own_jid().getStripped()
|
||||
app.logger.set_avatar_sha(own_jid, jid, sha)
|
||||
app.contacts.set_avatar(self.name, jid, sha)
|
||||
|
||||
app.interface.update_avatar(self.name, jid)
|
||||
|
||||
def _PubSubErrorCB(self, conn, stanza):
|
||||
log.debug('_PubsubErrorCB')
|
||||
pubsub = stanza.getTag('pubsub')
|
||||
if not pubsub:
|
||||
return
|
||||
items = pubsub.getTag('items')
|
||||
if not items:
|
||||
return
|
||||
if items.getAttr('node') == 'storage:bookmarks':
|
||||
# Receiving bookmarks from pubsub failed, so take them from xml
|
||||
self.get_bookmarks(storage_type='xml')
|
||||
|
||||
def request_pb_configuration(self, jid, node):
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
query = nbxmpp.Iq('get', to=jid)
|
||||
e = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB_OWNER)
|
||||
e = e.addChild('configure', {'node': node})
|
||||
id_ = self.connection.getAnID()
|
||||
query.setID(id_)
|
||||
self.awaiting_answers[id_] = (PEP_CONFIG,)
|
||||
self.connection.send(query)
|
|
@ -1900,11 +1900,13 @@ class ManageBookmarksWindow:
|
|||
iter_ = self.treestore.append(None, [None, account, None, None,
|
||||
None, None, None, None])
|
||||
|
||||
for bookmark in app.connections[account].bookmarks:
|
||||
con = app.connections[account]
|
||||
bookmarks = con.get_module('Bookmarks').bookmarks
|
||||
for jid, bookmark in bookmarks.items():
|
||||
if not bookmark['name']:
|
||||
# No name was given for this bookmark.
|
||||
# Use the first part of JID instead...
|
||||
name = bookmark['jid'].split("@")[0]
|
||||
name = jid.split("@")[0]
|
||||
bookmark['name'] = name
|
||||
|
||||
# make '1', '0', 'true', 'false' (or other) to True/False
|
||||
|
@ -1920,7 +1922,7 @@ class ManageBookmarksWindow:
|
|||
self.treestore.append(iter_, [
|
||||
account,
|
||||
bookmark['name'],
|
||||
bookmark['jid'],
|
||||
jid,
|
||||
autojoin,
|
||||
minimize,
|
||||
bookmark['password'],
|
||||
|
@ -2047,15 +2049,17 @@ class ManageBookmarksWindow:
|
|||
Parse the treestore data into our new bookmarks array, then send the new
|
||||
bookmarks to the server.
|
||||
"""
|
||||
|
||||
(model, iter_) = self.selection.get_selected()
|
||||
if iter_ and model.iter_parent(iter_):
|
||||
#bookmark selected, check it
|
||||
# bookmark selected, check it
|
||||
if not self.check_valid_bookmark():
|
||||
return
|
||||
|
||||
for account in self.treestore:
|
||||
acct = account[1]
|
||||
app.connections[acct].bookmarks = []
|
||||
con = app.connections[acct]
|
||||
con.get_module('Bookmarks').bookmarks = {}
|
||||
|
||||
for bm in account.iterchildren():
|
||||
# Convert True/False/None to '1' or '0'
|
||||
|
@ -2067,13 +2071,17 @@ class ManageBookmarksWindow:
|
|||
nick = bm[6]
|
||||
|
||||
# create the bookmark-dict
|
||||
bmdict = { 'name': name, 'jid': jid, 'autojoin': autojoin,
|
||||
'minimize': minimize, 'password': pw, 'nick': nick,
|
||||
bmdict = {
|
||||
'name': name,
|
||||
'autojoin': autojoin,
|
||||
'minimize': minimize,
|
||||
'password': pw,
|
||||
'nick': nick,
|
||||
'print_status': bm[7]}
|
||||
|
||||
app.connections[acct].bookmarks.append(bmdict)
|
||||
con.get_module('Bookmarks').bookmarks[jid] = bmdict
|
||||
|
||||
app.connections[acct].store_bookmarks()
|
||||
con.get_module('Bookmarks').store_bookmarks()
|
||||
gui_menu_builder.build_bookmark_menu(acct)
|
||||
self.window.destroy()
|
||||
|
||||
|
@ -2900,8 +2908,10 @@ class ManagePEPServicesWindow:
|
|||
model, iter_ = selection.get_selected()
|
||||
node = model[iter_][0]
|
||||
our_jid = app.get_jid_from_account(self.account)
|
||||
app.connections[self.account].send_pb_delete(our_jid, node,
|
||||
on_ok=self.node_removed, on_fail=self.node_not_removed)
|
||||
con = app.connections[self.account]
|
||||
con.get_module('PubSub').send_pb_delete(our_jid, node,
|
||||
on_ok=self.node_removed,
|
||||
on_fail=self.node_not_removed)
|
||||
|
||||
def on_configure_button_clicked(self, widget):
|
||||
selection = self.treeview.get_selection()
|
||||
|
@ -2910,13 +2920,15 @@ class ManagePEPServicesWindow:
|
|||
model, iter_ = selection.get_selected()
|
||||
node = model[iter_][0]
|
||||
our_jid = app.get_jid_from_account(self.account)
|
||||
app.connections[self.account].request_pb_configuration(our_jid, node)
|
||||
con = app.connections[self.account]
|
||||
con.get_module('PubSub').request_pb_configuration(our_jid, node)
|
||||
|
||||
def _nec_pep_config_received(self, obj):
|
||||
def on_ok(form, node):
|
||||
form.type_ = 'submit'
|
||||
our_jid = app.get_jid_from_account(self.account)
|
||||
app.connections[self.account].send_pb_configure(our_jid, node, form)
|
||||
con = app.connections[self.account]
|
||||
con.get_module('PubSub').send_pb_configure(our_jid, node, form)
|
||||
window = dialogs.DataFormWindow(obj.form, (on_ok, obj.node))
|
||||
title = _('Configure %s') % obj.node
|
||||
window.set_title(title)
|
||||
|
|
|
@ -2520,7 +2520,8 @@ class JoinGroupchatWindow(Gtk.ApplicationWindow):
|
|||
self.autojoin_switch.set_sensitive(switch.get_active())
|
||||
|
||||
def _add_bookmark(self, account, nickname, password):
|
||||
if not app.connections[account].private_storage_supported:
|
||||
con = app.connections[account]
|
||||
if not con.private_storage_supported:
|
||||
return
|
||||
|
||||
add_bookmark = self.bookmark_switch.get_active()
|
||||
|
@ -2531,8 +2532,8 @@ class JoinGroupchatWindow(Gtk.ApplicationWindow):
|
|||
|
||||
# Add as bookmark, with autojoin and not minimized
|
||||
name = app.get_nick_from_jid(self.room_jid)
|
||||
app.interface.add_gc_bookmark(
|
||||
account, name, self.room_jid, autojoin, 1, password, nickname)
|
||||
con.get_module('Bookmarks').add_bookmark(
|
||||
name, self.room_jid, autojoin, 1, password, nickname)
|
||||
|
||||
def _on_destroy(self, *args):
|
||||
if self.minimal_mode == 0:
|
||||
|
@ -2784,10 +2785,11 @@ class StartChatDialog(Gtk.ApplicationWindow):
|
|||
show_account = len(self.accounts) > 1
|
||||
for account in self.accounts:
|
||||
self.new_groupchat_rows[account] = None
|
||||
bookmarks = app.connections[account].bookmarks
|
||||
con = app.connections[account]
|
||||
bookmarks = con.get_module('Bookmarks').bookmarks
|
||||
groupchats = {}
|
||||
for bookmark in bookmarks:
|
||||
groupchats[bookmark['jid']] = bookmark['name']
|
||||
for jid, bookmark in bookmarks.items():
|
||||
groupchats[jid] = bookmark['name']
|
||||
|
||||
for jid in app.contacts.get_gc_list(account):
|
||||
if jid in groupchats:
|
||||
|
|
|
@ -1757,29 +1757,29 @@ class MucBrowser(AgentBrowser):
|
|||
self.join_button = None
|
||||
|
||||
def on_bookmark_button_clicked(self, *args):
|
||||
con = app.connections[self.account]
|
||||
model, iter = self.window.services_treeview.get_selection().get_selected()
|
||||
if not iter:
|
||||
return
|
||||
name = app.config.get_per('accounts', self.account, 'name')
|
||||
room_jid = model[iter][0]
|
||||
bm = {
|
||||
'name': room_jid.split('@')[0],
|
||||
'jid': room_jid,
|
||||
'autojoin': '0',
|
||||
'minimize': '0',
|
||||
'password': '',
|
||||
'nick': name
|
||||
'name': room_jid.split('@')[0],
|
||||
'autojoin': '0',
|
||||
'minimize': '0',
|
||||
'password': '',
|
||||
'nick': name
|
||||
}
|
||||
|
||||
for bookmark in app.connections[self.account].bookmarks:
|
||||
if bookmark['jid'] == bm['jid']:
|
||||
dialogs.ErrorDialog( _('Bookmark already set'),
|
||||
_('Group Chat "%s" is already in your bookmarks.') % bm['jid'],
|
||||
if room_jid in con.get_module('Bookmarks').bookmarks:
|
||||
dialogs.ErrorDialog(
|
||||
_('Bookmark already set'),
|
||||
_('Group Chat "%s" is already in your bookmarks.') % room_jid,
|
||||
transient_for=self.window.window)
|
||||
return
|
||||
return
|
||||
|
||||
app.connections[self.account].bookmarks.append(bm)
|
||||
app.connections[self.account].store_bookmarks()
|
||||
con.get_module('Bookmarks').bookmarks[room_jid] = bm
|
||||
con.get_module('Bookmarks').store_bookmarks()
|
||||
|
||||
gui_menu_builder.build_bookmark_menu(self.account)
|
||||
|
||||
|
@ -1951,8 +1951,9 @@ class DiscussionGroupsBrowser(AgentBrowser):
|
|||
self.subscribe_button = None
|
||||
self.unsubscribe_button = None
|
||||
|
||||
app.connections[account].send_pb_subscription_query(jid,
|
||||
self._on_pep_subscriptions)
|
||||
con = app.connections[account]
|
||||
con.get_module('PubSub').send_pb_subscription_query(
|
||||
jid, self._on_pep_subscriptions)
|
||||
|
||||
def _create_treemodel(self):
|
||||
"""
|
||||
|
@ -2122,10 +2123,11 @@ class DiscussionGroupsBrowser(AgentBrowser):
|
|||
model, iter_ = self.window.services_treeview.get_selection().get_selected()
|
||||
if iter_ is None: return
|
||||
|
||||
groupnode = model.get_value(iter_, 1) # 1 = groupnode
|
||||
node = model.get_value(iter_, 1) # 1 = groupnode
|
||||
|
||||
app.connections[self.account].send_pb_subscribe(self.jid, groupnode,
|
||||
self._on_pep_subscribe, groupnode)
|
||||
con = app.connections[self.account]
|
||||
con.get_module('PubSub').send_pb_subscribe(
|
||||
self.jid, node, self._on_pep_subscribe, groupnode=node)
|
||||
|
||||
def on_unsubscribe_button_clicked(self, widget):
|
||||
"""
|
||||
|
@ -2134,10 +2136,11 @@ class DiscussionGroupsBrowser(AgentBrowser):
|
|||
model, iter_ = self.window.services_treeview.get_selection().get_selected()
|
||||
if iter_ is None: return
|
||||
|
||||
groupnode = model.get_value(iter_, 1) # 1 = groupnode
|
||||
node = model.get_value(iter_, 1) # 1 = groupnode
|
||||
|
||||
app.connections[self.account].send_pb_unsubscribe(self.jid, groupnode,
|
||||
self._on_pep_unsubscribe, groupnode)
|
||||
con = app.connections[self.account]
|
||||
con.get_module('PubSub').send_pb_unsubscribe(
|
||||
self.jid, node, self._on_pep_unsubscribe, groupnode=node)
|
||||
|
||||
def _on_pep_subscriptions(self, conn, request):
|
||||
"""
|
||||
|
@ -2168,8 +2171,6 @@ class DiscussionGroupsBrowser(AgentBrowser):
|
|||
# we now know subscriptions, update button states
|
||||
self.update_actions()
|
||||
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
def _on_pep_subscribe(self, conn, request, groupnode):
|
||||
"""
|
||||
We have just subscribed to a node. Update UI
|
||||
|
@ -2184,8 +2185,6 @@ class DiscussionGroupsBrowser(AgentBrowser):
|
|||
|
||||
self.update_actions()
|
||||
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
def _on_pep_unsubscribe(self, conn, request, groupnode):
|
||||
"""
|
||||
We have just unsubscribed from a node. Update UI
|
||||
|
@ -2200,7 +2199,5 @@ class DiscussionGroupsBrowser(AgentBrowser):
|
|||
|
||||
self.update_actions()
|
||||
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
# Fill the global agent type info dictionary
|
||||
_agent_type_info = _gen_agent_type_info()
|
||||
|
|
|
@ -348,13 +348,10 @@ class GroupchatControl(ChatControlBase):
|
|||
self.room_jid = self.contact.jid
|
||||
self.nick = nick
|
||||
self.new_nick = ''
|
||||
self.name = ''
|
||||
for bm in app.connections[self.account].bookmarks:
|
||||
if bm['jid'] == self.room_jid:
|
||||
self.name = bm['name']
|
||||
break
|
||||
if not self.name:
|
||||
self.name = self.room_jid.split('@')[0]
|
||||
|
||||
bm_module = app.connections[self.account].get_module('Bookmarks')
|
||||
self.name = bm_module.get_name_from_bookmark(self.room_jid)
|
||||
|
||||
self.contact.name = self.name
|
||||
|
||||
self.widget_set_visible(self.xml.get_object('banner_eventbox'),
|
||||
|
@ -589,13 +586,9 @@ class GroupchatControl(ChatControlBase):
|
|||
# Bookmarks
|
||||
con = app.connections[self.account]
|
||||
bookmark_support = con.bookmarks_available()
|
||||
not_bookmarked = True
|
||||
for bm in con.bookmarks:
|
||||
if bm['jid'] == self.room_jid:
|
||||
not_bookmarked = False
|
||||
break
|
||||
bookmarked = self.room_jid in con.get_module('Bookmarks').bookmarks
|
||||
win.lookup_action('bookmark-' + self.control_id).set_enabled(
|
||||
online and bookmark_support and not_bookmarked)
|
||||
online and bookmark_support and not bookmarked)
|
||||
|
||||
# Request Voice
|
||||
role = self.get_role(self.nick)
|
||||
|
@ -712,9 +705,10 @@ class GroupchatControl(ChatControlBase):
|
|||
Bookmark the room, without autojoin and not minimized
|
||||
"""
|
||||
password = app.gc_passwords.get(self.room_jid, '')
|
||||
app.interface.add_gc_bookmark(
|
||||
self.account, self.name, self.room_jid,
|
||||
'0', '0', password, self.nick)
|
||||
con = app.connections[self.account]
|
||||
con.get_module('Bookmarks').add_bookmark(
|
||||
self.name, self.room_jid,
|
||||
'1', '1', password, self.nick)
|
||||
self.update_actions()
|
||||
|
||||
def _on_request_voice(self, action, param):
|
||||
|
|
|
@ -67,7 +67,9 @@ class GroupsPostWindow:
|
|||
item.addChild('content', {}, [buf.get_text(buf.get_start_iter(), buf.get_end_iter(), True)])
|
||||
|
||||
# publish it to node
|
||||
app.connections[self.account].send_pb_publish(self.servicejid, self.groupid, item, '0')
|
||||
con = app.connections[self.account]
|
||||
con.get_module('PubSub').send_pb_publish(
|
||||
self.servicejid, self.groupid, item, '0')
|
||||
|
||||
# close the window
|
||||
self.window.destroy()
|
||||
|
|
|
@ -824,17 +824,7 @@ class Interface:
|
|||
self.instances[account]['sub_request'][obj.jid].destroy()
|
||||
|
||||
def handle_event_bookmarks(self, obj):
|
||||
# ('BOOKMARKS', account, [{name,jid,autojoin,password,nick}, {}])
|
||||
# We received a bookmark item from the server (JEP48)
|
||||
# Auto join GC windows if necessary
|
||||
|
||||
gui_menu_builder.build_bookmark_menu(obj.conn.name)
|
||||
invisible_show = app.SHOW_LIST.index('invisible')
|
||||
# do not autojoin if we are invisible
|
||||
if obj.conn.connected == invisible_show:
|
||||
return
|
||||
|
||||
GLib.idle_add(self.auto_join_bookmarks, obj.conn.name)
|
||||
gui_menu_builder.build_bookmark_menu(obj.account)
|
||||
|
||||
def handle_event_file_send_error(self, account, array):
|
||||
jid = array[0]
|
||||
|
@ -1728,7 +1718,6 @@ class Interface:
|
|||
if isinstance(ctrl, ChatControlBase):
|
||||
ctrl.scroll_to_end()
|
||||
|
||||
|
||||
def join_gc_minimal(self, account, room_jid, password=None,
|
||||
transient_for=None):
|
||||
if account is not None:
|
||||
|
@ -1738,9 +1727,10 @@ class Interface:
|
|||
app.interface.join_gc_room(account, room_jid, '', '')
|
||||
return
|
||||
|
||||
for bookmark in app.connections[account].bookmarks:
|
||||
if bookmark['jid'] != room_jid:
|
||||
continue
|
||||
con = app.connections[account]
|
||||
bookmarks = con.get_module('Bookmarks').bookmarks
|
||||
bookmark = bookmarks.get(room_jid, None)
|
||||
if bookmark is not None:
|
||||
app.interface.join_gc_room(
|
||||
account, room_jid, bookmark['nick'], bookmark['password'])
|
||||
return
|
||||
|
@ -2469,51 +2459,6 @@ class Interface:
|
|||
return False
|
||||
return True
|
||||
|
||||
def auto_join_bookmarks(self, account):
|
||||
"""
|
||||
Autojoin bookmarked GCs that have 'auto join' on for this account
|
||||
"""
|
||||
for bm in app.connections[account].bookmarks:
|
||||
if bm['autojoin'] in ('1', 'true'):
|
||||
jid = bm['jid']
|
||||
# Only join non-opened groupchats. Opened one are already
|
||||
# auto-joined on re-connection
|
||||
if not jid in app.gc_connected[account]:
|
||||
# we are not already connected
|
||||
minimize = bm['minimize'] in ('1', 'true')
|
||||
self.join_gc_room(account, jid, bm['nick'],
|
||||
bm['password'], minimize = minimize)
|
||||
|
||||
def add_gc_bookmark(self, account, name, jid, autojoin, minimize, password,
|
||||
nick):
|
||||
"""
|
||||
Add a bookmark for this account, sorted in bookmark list
|
||||
"""
|
||||
bm = {
|
||||
'name': name,
|
||||
'jid': jid,
|
||||
'autojoin': autojoin,
|
||||
'minimize': minimize,
|
||||
'password': password,
|
||||
'nick': nick
|
||||
}
|
||||
place_found = False
|
||||
index = 0
|
||||
# check for duplicate entry and respect alpha order
|
||||
for bookmark in app.connections[account].bookmarks:
|
||||
if bookmark['jid'] == bm['jid']:
|
||||
return
|
||||
if bookmark['name'] > bm['name']:
|
||||
place_found = True
|
||||
break
|
||||
index += 1
|
||||
if place_found:
|
||||
app.connections[account].bookmarks.insert(index, bm)
|
||||
else:
|
||||
app.connections[account].bookmarks.append(bm)
|
||||
app.connections[account].store_bookmarks()
|
||||
gui_menu_builder.build_bookmark_menu(account)
|
||||
|
||||
# does JID exist only within a groupchat?
|
||||
def is_pm_contact(self, fjid, account):
|
||||
bare_jid = app.get_jid_without_resource(fjid)
|
||||
|
|
|
@ -172,14 +172,15 @@ show_bookmarked=False, force_resource=False):
|
|||
rooms2 = [] # a list of (room_jid, account) tuple
|
||||
r_jids = [] # list of room jids
|
||||
for account in connected_accounts:
|
||||
for room in app.connections[account].bookmarks:
|
||||
r_jid = room['jid']
|
||||
if r_jid in r_jids:
|
||||
con = app.connections[account]
|
||||
boomarks = con.get_module('Bookmarks').bookmarks
|
||||
for jid, bookmark in boomarks.items():
|
||||
if jid in r_jids:
|
||||
continue
|
||||
if r_jid not in app.gc_connected[account] or not \
|
||||
app.gc_connected[account][r_jid]:
|
||||
rooms2.append((r_jid, account))
|
||||
r_jids.append(r_jid)
|
||||
if jid not in app.gc_connected[account] or not \
|
||||
app.gc_connected[account][jid]:
|
||||
rooms2.append((jid, account))
|
||||
r_jids.append(jid)
|
||||
|
||||
if not rooms2:
|
||||
return
|
||||
|
@ -675,7 +676,9 @@ def get_groupchat_menu(control_id):
|
|||
|
||||
|
||||
def get_bookmarks_menu(account, rebuild=False):
|
||||
if not app.connections[account].bookmarks:
|
||||
con = app.connections[account]
|
||||
boomarks = con.get_module('Bookmarks').bookmarks
|
||||
if not boomarks:
|
||||
return None
|
||||
menu = Gio.Menu()
|
||||
|
||||
|
@ -688,12 +691,12 @@ def get_bookmarks_menu(account, rebuild=False):
|
|||
|
||||
# Build Bookmarks
|
||||
section = Gio.Menu()
|
||||
for bookmark in app.connections[account].bookmarks:
|
||||
for jid, bookmark in boomarks.items():
|
||||
name = bookmark['name']
|
||||
if not name:
|
||||
# No name was given for this bookmark.
|
||||
# Use the first part of JID instead...
|
||||
name = bookmark['jid'].split("@")[0]
|
||||
name = jid.split("@")[0]
|
||||
|
||||
# Shorten long names
|
||||
name = (name[:42] + '..') if len(name) > 42 else name
|
||||
|
@ -703,7 +706,7 @@ def get_bookmarks_menu(account, rebuild=False):
|
|||
|
||||
# Create Variant Dict
|
||||
dict_ = {'account': GLib.Variant('s', account),
|
||||
'jid': GLib.Variant('s', bookmark['jid'])}
|
||||
'jid': GLib.Variant('s', jid)}
|
||||
if bookmark['nick']:
|
||||
dict_['nick'] = GLib.Variant('s', bookmark['nick'])
|
||||
if bookmark['password']:
|
||||
|
|
|
@ -2154,7 +2154,8 @@ class RosterWindow:
|
|||
auto=auto)
|
||||
if was_invisible and status != 'offline':
|
||||
# We come back from invisible, join bookmarks
|
||||
app.interface.auto_join_bookmarks(account)
|
||||
con = app.connections[account]
|
||||
con.get_module('Bookmarks').auto_join_bookmarks()
|
||||
|
||||
|
||||
def chg_contact_status(self, contact, show, status, account):
|
||||
|
@ -2712,9 +2713,9 @@ class RosterWindow:
|
|||
### FIXME: order callbacks in itself...
|
||||
################################################################################
|
||||
|
||||
def on_bookmark_menuitem_activate(self, widget, account, bookmark):
|
||||
app.interface.join_gc_room(account, bookmark['jid'], bookmark['nick'],
|
||||
bookmark['password'])
|
||||
def on_bookmark_menuitem_activate(self, widget, account, jid, bookmark):
|
||||
app.interface.join_gc_room(
|
||||
account, jid, bookmark['nick'], bookmark['password'])
|
||||
|
||||
def on_info(self, widget, contact, account):
|
||||
"""
|
||||
|
@ -5439,16 +5440,17 @@ class RosterWindow:
|
|||
gc_sub_menu.append(item)
|
||||
|
||||
# User has at least one bookmark.
|
||||
if app.connections[account].bookmarks:
|
||||
con = app.connections[account]
|
||||
if con.get_module('Bookmarks').bookmarks:
|
||||
item = Gtk.SeparatorMenuItem.new()
|
||||
gc_sub_menu.append(item)
|
||||
|
||||
for bookmark in app.connections[account].bookmarks:
|
||||
for jid, bookmark in con.get_module('Bookmarks').bookmarks.items():
|
||||
name = bookmark['name']
|
||||
if not name:
|
||||
# No name was given for this bookmark.
|
||||
# Use the first part of JID instead...
|
||||
name = bookmark['jid'].split("@")[0]
|
||||
name = jid.split("@")[0]
|
||||
|
||||
# Shorten long names
|
||||
name = (name[:42] + '..') if len(name) > 42 else name
|
||||
|
@ -5456,8 +5458,9 @@ class RosterWindow:
|
|||
# Do not use underline.
|
||||
item = Gtk.MenuItem.new_with_label(name)
|
||||
item.set_use_underline(False)
|
||||
item.connect('activate', self.on_bookmark_menuitem_activate,
|
||||
account, bookmark)
|
||||
item.connect(
|
||||
'activate', self.on_bookmark_menuitem_activate,
|
||||
account, jid, bookmark)
|
||||
gc_sub_menu.append(item)
|
||||
|
||||
def show_appropriate_context_menu(self, event, iters):
|
||||
|
|
Loading…
Reference in New Issue