summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/connection.py1
-rw-r--r--src/core.py18
-rw-r--r--src/pubsub.py197
3 files changed, 216 insertions, 0 deletions
diff --git a/src/connection.py b/src/connection.py
index 8bef6eb2..d021f44b 100644
--- a/src/connection.py
+++ b/src/connection.py
@@ -56,6 +56,7 @@ class Connection(sleekxmpp.ClientXMPP):
self.register_plugin('xep_0030')
self.register_plugin('xep_0004')
self.register_plugin('xep_0045')
+ self.register_plugin('xep_0060')
self.register_plugin('xep_0071')
self.register_plugin('xep_0085')
if config.get('send_poezio_info', 'true') == 'true':
diff --git a/src/core.py b/src/core.py
index 3f24fb1b..6db97919 100644
--- a/src/core.py
+++ b/src/core.py
@@ -40,6 +40,7 @@ import multiuserchat as muc
import tabs
import xhtml
+import pubsub
import windows
import connection
import timed_events
@@ -129,6 +130,7 @@ class Core(object):
'version': (self.command_version, _('Usage: /version <jid>\nVersion: get the software version of the given JID (usually its XMPP client and Operating System)'), None),
'reconnect': (self.command_reconnect, _('Usage: /connect\nConnect: disconnect from the remote server if you are currently connected and then connect to it again'), None),
'server_cycle': (self.command_server_cycle, _('Usage: /server_cycle [domain] [message]\nServer Cycle: disconnect and reconnects in all the rooms in domain.'), None),
+ 'pubsub': (self.command_pubsub, _('Usage: /pubsub <domain>\nPubsub: Open a pubsub browser on the given domain'), None),
}
self.key_func = {
@@ -1369,6 +1371,22 @@ class Core(object):
tab.get_room().joined = False
self.command_join(tab.get_name())
+ def command_pubsub(self, args):
+ """
+ Opens a pubsub browser on the given domain
+ """
+ args = common.shell_split(args)
+ if len(args) != 1:
+ return self.command_help('pubsub')
+ domain = args[0]
+ tab = self.get_tab_by_name('%s@@pubsubbrowser' % (domain,), pubsub.PubsubBrowserTab)
+ if tab:
+ self.command_win('%s' % tab.nb)
+ else:
+ new_tab = pubsub.PubsubBrowserTab(domain)
+ self.add_tab(new_tab, True)
+ self.refresh_window()
+
def go_to_room_number(self):
"""
Read 2 more chars and go to the tab
diff --git a/src/pubsub.py b/src/pubsub.py
new file mode 100644
index 00000000..73c03bcc
--- /dev/null
+++ b/src/pubsub.py
@@ -0,0 +1,197 @@
+# Copyright 2010-2011 Le Coz Florent <louiz@louiz.org>
+#
+# This file is part of Poezio.
+#
+# Poezio 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 of the License.
+#
+# Poezio 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 Poezio. If not, see <http://www.gnu.org/licenses/>.
+
+import logging
+log = logging.getLogger(__name__)
+
+import curses
+
+import windows
+import tabs
+
+from sleekxmpp.xmlstream import ElementBase, ET
+
+class PubsubNode(object):
+ node_type = None # unknown yet
+ def __init__(self, name):
+ self.items = []
+ self.name = name
+
+
+class LeafNode(PubsubNode):
+ node_type = "leaf"
+ def __init__(self, name):
+ PubsubNode.__init__(self, name)
+
+
+class CollectionNode(PubsubNode):
+ node_type = "collection"
+ def __init__(self, name):
+ PubsubNode.__init__(self, name)
+ self.subnodes = []
+
+
+class PubsubItem(object):
+ def __init__(self, idd, content):
+ self.idd = idd
+ self.content = content
+
+
+class PubsubBrowserTab(tabs.Tab):
+ """
+ A tab containing a pubsub browser letting the user
+ list nodes and items, view, add and delete items, etc
+ """
+ def __init__(self, server):
+ """
+ Server is the name of the pubsub server, for example:
+ pubsub.example.com
+ All action done in this tab will be made on that server.
+ """
+ tabs.Tab.__init__(self)
+ self.current_node = None # the subnode we are listing. None means the root
+ self.server = server
+ self.nodes = [] # the lower level of nodes
+
+ self.tab_win = windows.GlobalInfoBar()
+ self.upper_message = windows.Topic()
+ self.upper_message.set_message('Pubsub server: %s' % (self.server,))
+
+ # Node List View
+ node_columns = ('node', 'name',)
+ self.node_list_header = windows.ColumnHeaderWin(node_columns)
+ self.node_listview = windows.ListWin(node_columns)
+
+ # Item List View
+ item_columns = ('name',)
+ self.item_list_header = windows.ColumnHeaderWin(item_columns)
+ self.item_listview = windows.ListWin(item_columns)
+
+ self.default_help_message = windows.HelpText("ā€œcā€: create a node.")
+ self.input = self.default_help_message
+
+ self.key_func['c'] = self.command_create_node
+ self.key_func["KEY_DOWN"] = self.node_listview.move_cursor_down
+ self.key_func["KEY_UP"] = self.node_listview.move_cursor_up
+ self.resize()
+
+ self.get_nodes()
+
+ def resize(self):
+ self.upper_message.resize(1, self.width, 0, 0)
+ self.tab_win.resize(1, self.width, self.height-2, 0)
+
+ column_size = {'node': self.width//4,
+ 'name': self.width//4,}
+ self.node_list_header.resize_columns(column_size)
+ self.node_list_header.resize(1, self.width//2, 1, 0)
+ self.node_listview.resize_columns(column_size)
+ self.node_listview.resize(self.height//2-2, self.width//2, 2, 0)
+
+ column_size = {'name': self.width//2,}
+ self.item_list_header.resize_columns(column_size)
+ self.item_list_header.resize(self.height//2+1, self.width//2, self.height//2, 0)
+ self.item_listview.resize_columns(column_size)
+ self.item_listview.resize(self.height//2-4, self.width//2, self.height//2+3, 0)
+
+ self.input.resize(1, self.width, self.height-1, 0)
+
+ def refresh(self):
+ if self.need_resize:
+ self.resize()
+ log.debug(' TAB Refresh: %s'%self.__class__.__name__)
+ self.upper_message.refresh()
+ self.node_list_header.refresh()
+ self.node_listview.refresh()
+ self.item_list_header.refresh()
+ self.item_listview.refresh()
+ self.tab_win.refresh()
+ self.input.refresh()
+
+ def get_name(self):
+ return '%s@@pubsubbrowser' % (self.server,)
+
+ def on_input(self, key):
+ res = self.input.do_command(key)
+ if res:
+ return True
+ if key in self.key_func:
+ return self.key_func[key]()
+
+ def get_items(self, node):
+ """
+ Get all items in the given node
+ """
+ items = self.core.xmpp.plugin['xep_0060'].get_items(self.server, node.name)
+ item_list = []
+ if items:
+ for it in items:
+ item_list.append(PubsubItem(it.attrib['id'], ET.tostring(it)))
+ node.items = item_list
+ log.debug('Item on node %s: %s' % (node.name, item_list))
+
+ def add_nodes(self, node_list, parent=None):
+ """
+ Add Node objects to the list of the parent.
+ If parent is None, they are added to the root list.
+ If the current selected node is parent, we add
+ them directly to the node_listview
+ """
+ log.debug('Adding nodes to %s: %s' % (node_list, parent,))
+ if not parent:
+ list_to_append = self.nodes
+ else:
+ list_to_append = parent.nodes
+ for node in node_list:
+ new_node = LeafNode(node['node'])
+ list_to_append.append(new_node)
+ self.get_items(new_node)
+ self.node_listview.add_lines(node_list)
+
+ def get_nodes(self, node=None):
+ """
+ Get all subnodes of the given node. If no node is given, get
+ the root nodes
+ """
+ nodes = self.core.xmpp.plugin['xep_0060'].get_nodes(self.server)
+ lines = [{'name': nodes[node] or '',
+ 'node': node} for node in nodes.keys()]
+ self.add_nodes(lines)
+
+ def create_node(self, node_name):
+ if node_name:
+ res = self.core.xmpp.plugin['xep_0060'].create_node(self.server, node_name)
+ if res:
+ self.node_listview.add_lines([{'name': '', 'node': node_name}])
+ self.reset_help_message()
+ return True
+
+ def reset_help_message(self, txt=None):
+ """
+ Just reset the help message when a command ends
+ """
+ curses.curs_set(0)
+ self.input = self.default_help_message
+ return True
+
+ def command_create_node(self):
+ """
+ Prompt for a node name and create it on Enter key
+ """
+ curses.curs_set(1)
+ self.input = windows.CommandInput("[Create node]", self.reset_help_message, self.create_node, None)
+ self.input.resize(1, self.width, self.height-1, 0)
+ return True