Welcome to mirror list, hosted at ThFree Co, Russian Federation.

dev.gajim.org/gajim/python-nbxmpp.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'nbxmpp/modules/bookmarks')
-rw-r--r--nbxmpp/modules/bookmarks/__init__.py0
-rw-r--r--nbxmpp/modules/bookmarks/native_bookmarks.py129
-rw-r--r--nbxmpp/modules/bookmarks/pep_bookmarks.py109
-rw-r--r--nbxmpp/modules/bookmarks/private_bookmarks.py59
-rw-r--r--nbxmpp/modules/bookmarks/util.py152
5 files changed, 449 insertions, 0 deletions
diff --git a/nbxmpp/modules/bookmarks/__init__.py b/nbxmpp/modules/bookmarks/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/nbxmpp/modules/bookmarks/__init__.py
diff --git a/nbxmpp/modules/bookmarks/native_bookmarks.py b/nbxmpp/modules/bookmarks/native_bookmarks.py
new file mode 100644
index 0000000..16da9e9
--- /dev/null
+++ b/nbxmpp/modules/bookmarks/native_bookmarks.py
@@ -0,0 +1,129 @@
+# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
+#
+# This file is part of nbxmpp.
+#
+# This program 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; either version 3
+# of the License, or (at your option) any later version.
+#
+# This program 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 this program; If not, see <http://www.gnu.org/licenses/>.
+
+from nbxmpp.namespaces import Namespace
+from nbxmpp.protocol import NodeProcessed
+from nbxmpp.structs import StanzaHandler
+from nbxmpp.task import iq_request_task
+from nbxmpp.errors import MalformedStanzaError
+from nbxmpp.modules.base import BaseModule
+from nbxmpp.modules.util import raise_if_error
+from nbxmpp.modules.util import finalize
+from nbxmpp.modules.bookmarks.util import parse_bookmark
+from nbxmpp.modules.bookmarks.util import build_conference_node
+
+
+BOOKMARK_OPTIONS = {
+ 'pubsub#notify_delete': 'true',
+ 'pubsub#notify_retract': 'true',
+ 'pubsub#persist_items': 'true',
+ 'pubsub#max_items': 'max',
+ 'pubsub#access_model': 'whitelist',
+ 'pubsub#send_last_published_item': 'never',
+}
+
+
+class NativeBookmarks(BaseModule):
+
+ _depends = {
+ 'retract': 'PubSub',
+ 'publish': 'PubSub',
+ 'request_items': 'PubSub',
+ }
+
+ def __init__(self, client):
+ BaseModule.__init__(self, client)
+
+ self._client = client
+ self.handlers = [
+ StanzaHandler(name='message',
+ callback=self._process_pubsub_bookmarks,
+ ns=Namespace.PUBSUB_EVENT,
+ priority=16),
+ ]
+
+ def _process_pubsub_bookmarks(self, _client, _stanza, properties):
+ if not properties.is_pubsub_event:
+ return
+
+ if properties.pubsub_event.node != Namespace.BOOKMARKS_1:
+ return
+
+ item = properties.pubsub_event.item
+ if item is None:
+ # Retract, Deleted or Purged
+ return
+
+ try:
+ bookmark_item = parse_bookmark(item)
+ except MalformedStanzaError as error:
+ self._log.warning(error)
+ self._log.warning(error.stanza)
+ raise NodeProcessed
+
+ pubsub_event = properties.pubsub_event._replace(data=bookmark_item)
+ self._log.info('Received bookmark item from: %s', properties.jid)
+ self._log.info(bookmark_item)
+
+ properties.pubsub_event = pubsub_event
+
+ @iq_request_task
+ def request_bookmarks(self):
+ _task = yield
+
+ items = yield self.request_items(Namespace.BOOKMARKS_1)
+ raise_if_error(items)
+
+ bookmarks = []
+ for item in items:
+ try:
+ bookmark_item = self.parse_bookmark(item)
+ except MalformedStanzaError as error:
+ self._log.warning(error)
+ self._log.warning(error.stanza)
+ continue
+
+ bookmarks.append(bookmark_item)
+
+ for bookmark in bookmarks:
+ self._log.info(bookmark)
+
+ yield bookmarks
+
+ @iq_request_task
+ def retract_bookmark(self, bookmark_jid):
+ task = yield
+
+ self._log.info('Retract Bookmark: %s', bookmark_jid)
+
+ result = yield self.retract(Namespace.BOOKMARKS_1, str(bookmark_jid))
+ yield finalize(task, result)
+
+ @iq_request_task
+ def store_bookmarks(self, bookmarks):
+ _task = yield
+
+ self._log.info('Store Bookmarks')
+
+ for bookmark in bookmarks:
+ self.publish(Namespace.BOOKMARKS_1,
+ build_conference_node(bookmark),
+ id_=str(bookmark.jid),
+ options=BOOKMARK_OPTIONS,
+ force_node_options=True)
+
+ yield True
diff --git a/nbxmpp/modules/bookmarks/pep_bookmarks.py b/nbxmpp/modules/bookmarks/pep_bookmarks.py
new file mode 100644
index 0000000..508843d
--- /dev/null
+++ b/nbxmpp/modules/bookmarks/pep_bookmarks.py
@@ -0,0 +1,109 @@
+# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
+#
+# This file is part of nbxmpp.
+#
+# This program 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; either version 3
+# of the License, or (at your option) any later version.
+#
+# This program 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 this program; If not, see <http://www.gnu.org/licenses/>.
+
+from nbxmpp.namespaces import Namespace
+from nbxmpp.protocol import NodeProcessed
+from nbxmpp.structs import StanzaHandler
+from nbxmpp.task import iq_request_task
+from nbxmpp.errors import MalformedStanzaError
+from nbxmpp.modules.base import BaseModule
+from nbxmpp.modules.util import raise_if_error
+from nbxmpp.modules.bookmarks.util import parse_bookmarks
+from nbxmpp.modules.bookmarks.util import build_storage_node
+
+
+BOOKMARK_OPTIONS = {
+ 'pubsub#persist_items': 'true',
+ 'pubsub#access_model': 'whitelist',
+}
+
+
+class PEPBookmarks(BaseModule):
+
+ _depends = {
+ 'publish': 'PubSub',
+ 'request_items': 'PubSub',
+ }
+
+ def __init__(self, client):
+ BaseModule.__init__(self, client)
+
+ self._client = client
+ self.handlers = [
+ StanzaHandler(name='message',
+ callback=self._process_pubsub_bookmarks,
+ ns=Namespace.PUBSUB_EVENT,
+ priority=16),
+ ]
+
+ def _process_pubsub_bookmarks(self, _client, stanza, properties):
+ if not properties.is_pubsub_event:
+ return
+
+ if properties.pubsub_event.node != Namespace.BOOKMARKS:
+ return
+
+ item = properties.pubsub_event.item
+ if item is None:
+ # Retract, Deleted or Purged
+ return
+
+ try:
+ bookmarks = parse_bookmarks(item, self._log)
+ except MalformedStanzaError as error:
+ self._log.warning(error)
+ self._log.warning(stanza)
+ raise NodeProcessed
+
+ if not bookmarks:
+ self._log.info('Bookmarks removed')
+ return
+
+ pubsub_event = properties.pubsub_event._replace(data=bookmarks)
+ self._log.info('Received bookmarks from: %s', properties.jid)
+ for bookmark in bookmarks:
+ self._log.info(bookmark)
+
+ properties.pubsub_event = pubsub_event
+
+ @iq_request_task
+ def request_bookmarks(self):
+ _task = yield
+
+ items = yield self.request_items(Namespace.BOOKMARKS, max_items=1)
+ raise_if_error(items)
+
+ if not items:
+ yield []
+
+ bookmarks = parse_bookmarks(items[0], self._log)
+ for bookmark in bookmarks:
+ self._log.info(bookmark)
+
+ yield bookmarks
+
+ @iq_request_task
+ def store_bookmarks(self, bookmarks):
+ _task = yield
+
+ self._log.info('Store Bookmarks')
+
+ self.publish(Namespace.BOOKMARKS,
+ build_storage_node(bookmarks),
+ id_='current',
+ options=BOOKMARK_OPTIONS,
+ force_node_options=True)
diff --git a/nbxmpp/modules/bookmarks/private_bookmarks.py b/nbxmpp/modules/bookmarks/private_bookmarks.py
new file mode 100644
index 0000000..88d8a62
--- /dev/null
+++ b/nbxmpp/modules/bookmarks/private_bookmarks.py
@@ -0,0 +1,59 @@
+# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
+#
+# This file is part of nbxmpp.
+#
+# This program 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; either version 3
+# of the License, or (at your option) any later version.
+#
+# This program 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 this program; If not, see <http://www.gnu.org/licenses/>.
+
+from nbxmpp.namespaces import Namespace
+from nbxmpp.protocol import Iq
+from nbxmpp.task import iq_request_task
+from nbxmpp.modules.util import raise_if_error
+from nbxmpp.modules.util import finalize
+from nbxmpp.modules.base import BaseModule
+from nbxmpp.modules.bookmarks.util import build_storage_node
+from nbxmpp.modules.bookmarks.util import get_private_request
+from nbxmpp.modules.bookmarks.util import parse_private_bookmarks
+
+
+
+class PrivateBookmarks(BaseModule):
+ def __init__(self, client):
+ BaseModule.__init__(self, client)
+
+ self._client = client
+ self.handlers = []
+
+ @iq_request_task
+ def request_bookmarks(self):
+ _task = yield
+
+ response = yield get_private_request()
+ raise_if_error(response)
+
+
+ bookmarks = parse_private_bookmarks(response, self._log)
+ for bookmark in bookmarks:
+ self._log.info(bookmark)
+
+ yield bookmarks
+
+ @iq_request_task
+ def store_bookmarks(self, bookmarks):
+ task = yield
+
+ self._log.info('Store Bookmarks')
+
+ storage_node = build_storage_node(bookmarks)
+ result = yield Iq('set', Namespace.PRIVATE, payload=storage_node)
+ yield finalize(task, result)
diff --git a/nbxmpp/modules/bookmarks/util.py b/nbxmpp/modules/bookmarks/util.py
new file mode 100644
index 0000000..2672131
--- /dev/null
+++ b/nbxmpp/modules/bookmarks/util.py
@@ -0,0 +1,152 @@
+# Copyright (C) 2020 Philipp Hörist <philipp AT hoerist.com>
+#
+# This file is part of nbxmpp.
+#
+# This program 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; either version 3
+# of the License, or (at your option) any later version.
+#
+# This program 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 this program; If not, see <http://www.gnu.org/licenses/>.
+
+from nbxmpp.protocol import Node
+from nbxmpp.protocol import validate_resourcepart
+from nbxmpp.protocol import JID
+from nbxmpp.protocol import Iq
+from nbxmpp.util import from_xs_boolean
+from nbxmpp.util import to_xs_boolean
+from nbxmpp.namespaces import Namespace
+from nbxmpp.errors import MalformedStanzaError
+from nbxmpp.structs import BookmarkData
+
+
+def parse_nickname(nick):
+ if nick is None:
+ return None
+
+ try:
+ return validate_resourcepart(nick)
+ except Exception:
+ return None
+
+
+def parse_autojoin(autojoin):
+ if autojoin is None:
+ return False
+
+ try:
+ return from_xs_boolean(autojoin)
+ except ValueError:
+ return False
+
+
+def parse_bookmark(item):
+ conference = item.getTag('conference', namespace=Namespace.BOOKMARKS_1)
+ if conference is None:
+ raise MalformedStanzaError('conference node missing', item)
+
+ try:
+ jid = JID.from_string(item.getAttr('id'))
+ except Exception as error:
+ raise MalformedStanzaError('invalid jid: %s' % error, item)
+
+ if jid.localpart is None or jid.resource is not None:
+ raise MalformedStanzaError('invalid jid', item)
+
+ autojoin = parse_autojoin(conference.getAttr('autojoin'))
+ nick = parse_nickname(conference.getTagData('nick'))
+ name = conference.getAttr('name') or None
+ password = conference.getTagData('password') or None
+
+ return BookmarkData(jid=jid,
+ name=name,
+ autojoin=autojoin,
+ password=password,
+ nick=nick)
+
+
+def parse_bookmarks(item, log):
+ storage_node = item.getTag('storage', namespace=Namespace.BOOKMARKS)
+ if storage_node is None:
+ raise MalformedStanzaError('storage node missing', item)
+
+ return parse_storage_node(storage_node, log)
+
+
+def parse_private_bookmarks(response, log):
+ query = response.getQuery()
+ storage_node = query.getTag('storage', namespace=Namespace.BOOKMARKS)
+ if storage_node is None:
+ raise MalformedStanzaError('storage node missing', response)
+
+ return parse_storage_node(storage_node, log)
+
+
+def parse_storage_node(storage, log):
+ bookmarks = []
+ confs = storage.getTags('conference')
+ for conf in confs:
+ try:
+ jid = JID.from_string(conf.getAttr('jid'))
+ except Exception:
+ log.warning('invalid jid: %s', conf)
+ continue
+
+ if jid.localpart is None or jid.resource is not None:
+ log.warning('invalid jid: %s', conf)
+ continue
+
+ autojoin = parse_autojoin(conf.getAttr('autojoin'))
+ nick = parse_nickname(conf.getTagData('nick'))
+ name = conf.getAttr('name') or None
+ password = conf.getTagData('password') or None
+
+ bookmark = BookmarkData(
+ jid=jid,
+ name=name,
+ autojoin=autojoin,
+ password=password,
+ nick=nick)
+ bookmarks.append(bookmark)
+
+ return bookmarks
+
+
+def build_conference_node(bookmark):
+ attrs = {'xmlns': Namespace.BOOKMARKS_1}
+ if bookmark.autojoin:
+ attrs['autojoin'] = 'true'
+ if bookmark.name:
+ attrs['name'] = bookmark.name
+ conference = Node(tag='conference', attrs=attrs)
+ if bookmark.nick:
+ conference.setTagData('nick', bookmark.nick)
+ return conference
+
+
+def build_storage_node(bookmarks):
+ storage_node = Node(tag='storage', attrs={'xmlns': Namespace.BOOKMARKS})
+ for bookmark in bookmarks:
+ conf_node = storage_node.addChild(name="conference")
+ conf_node.setAttr('jid', bookmark.jid)
+ conf_node.setAttr('autojoin', to_xs_boolean(bookmark.autojoin))
+ if bookmark.name:
+ conf_node.setAttr('name', bookmark.name)
+ if bookmark.nick:
+ conf_node.setTagData('nick', bookmark.nick)
+ if bookmark.password:
+ conf_node.setTagData('password', bookmark.password)
+ return storage_node
+
+
+def get_private_request():
+ iq = Iq(typ='get')
+ query = iq.addChild(name='query', namespace=Namespace.PRIVATE)
+ query.addChild(name='storage', namespace=Namespace.BOOKMARKS)
+ return iq