summaryrefslogtreecommitdiff
path: root/src/tabs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tabs')
-rw-r--r--src/tabs/xmltab.py168
1 files changed, 139 insertions, 29 deletions
diff --git a/src/tabs/xmltab.py b/src/tabs/xmltab.py
index 84ecf00c..30b5b1c3 100644
--- a/src/tabs/xmltab.py
+++ b/src/tabs/xmltab.py
@@ -13,23 +13,62 @@ log = logging.getLogger(__name__)
import curses
import os
from slixmpp.xmlstream import matcher
-from slixmpp.xmlstream.handler import Callback
+from slixmpp.xmlstream.stanzabase import ElementBase
+from xml.etree import ElementTree as ET
from . import Tab
+import text_buffer
import windows
from xhtml import clean_text
from decorators import command_args_parser
+from common import safeJID
+
+
+class MatchJID(object):
+
+ def __init__(self, jid, dest=''):
+ self.jid = jid
+ self.dest = dest
+
+ def match(self, xml):
+ from_ = safeJID(xml['from'])
+ to_ = safeJID(xml['to'])
+ if self.jid.full == self.jid.bare:
+ from_ = from_.bare
+ to_ = to_.bare
+
+ if self.dest == 'from':
+ return from_ == self.jid
+ elif self.dest == 'to':
+ return to_ == self.jid
+ return self.jid in (from_, to_)
+
+ def __repr__(self):
+ return '%s%s%s' % (self.dest, ': ' if self.dest else '', self.jid)
+
+MATCHERS_MAPPINGS = {
+ MatchJID: ('JID', lambda obj: repr(obj)),
+ matcher.MatcherId: ('ID', lambda obj: obj._criteria),
+ matcher.MatchXMLMask: ('XMLMask', lambda obj: obj._criteria),
+ matcher.MatchXPath: ('XPath', lambda obj: obj._criteria)
+}
class XMLTab(Tab):
def __init__(self):
Tab.__init__(self)
self.state = 'normal'
self.name = 'XMLTab'
- self.text_win = windows.TextWin()
- self.core.xml_buffer.add_window(self.text_win)
+ self.filters = []
+
+ self.core_buffer = self.core.xml_buffer
+ self.filtered_buffer = text_buffer.TextBuffer()
+
self.info_header = windows.XMLInfoWin()
+ self.text_win = windows.XMLTextWin()
+ self.core_buffer.add_window(self.text_win)
self.default_help_message = windows.HelpText("/ to enter a command")
+
self.register_command('close', self.close,
shortdesc=_("Close this tab."))
self.register_command('clear', self.command_clear,
@@ -42,8 +81,21 @@ class XMLTab(Tab):
shortdesc=_('Filter by id.'))
self.register_command('filter_xpath', self.command_filter_xpath,
usage='<xpath>',
- desc=_('Show only the stanzas matching the xpath <xpath>.'),
+ desc=_('Show only the stanzas matching the xpath <xpath>.'
+ ' Any occurrences of %n will be replaced by jabber:client.'),
shortdesc=_('Filter by XPath.'))
+ self.register_command('filter_jid', self.command_filter_jid,
+ usage='<jid>',
+ desc=_('Show only the stanzas matching the jid <jid> in from= or to=.'),
+ shortdesc=_('Filter by JID.'))
+ self.register_command('filter_from', self.command_filter_from,
+ usage='<jid>',
+ desc=_('Show only the stanzas matching the jid <jid> in from=.'),
+ shortdesc=_('Filter by JID from.'))
+ self.register_command('filter_to', self.command_filter_to,
+ usage='<jid>',
+ desc=_('Show only the stanzas matching the jid <jid> in to=.'),
+ shortdesc=_('Filter by JID to.'))
self.register_command('filter_xmlmask', self.command_filter_xmlmask,
usage=_('<xml mask>'),
desc=_('Show only the stanzas matching the given xml mask.'),
@@ -64,6 +116,34 @@ class XMLTab(Tab):
self.filter_type = ''
self.filter = ''
+ def gen_filter_repr(self):
+ if not self.filters:
+ self.filter_type = ''
+ self.filter = ''
+ return
+ filter_types = map(lambda x: MATCHERS_MAPPINGS[type(x)][0], self.filters)
+ filter_strings = map(lambda x: MATCHERS_MAPPINGS[type(x)][1](x), self.filters)
+ self.filter_type = ','.join(filter_types)
+ self.filter = ','.join(filter_strings)
+
+ def update_filters(self, matcher):
+ if not self.filters:
+ messages = self.core_buffer.messages[:]
+ self.filtered_buffer.messages = []
+ self.core_buffer.del_window(self.text_win)
+ self.filtered_buffer.add_window(self.text_win)
+ else:
+ messages = self.filtered_buffer.messages
+ self.filtered_buffer.messages = []
+ self.filters.append(matcher)
+ new_messages = []
+ for msg in messages:
+ if self.match_stanza(ElementBase(ET.fromstring(clean_text(msg.txt)))):
+ new_messages.append(msg)
+ self.filtered_buffer.messages = new_messages
+ self.text_win.rebuild_everything(self.filtered_buffer)
+ self.gen_filter_repr()
+
def on_freeze(self):
"""
Freeze the display.
@@ -71,46 +151,66 @@ class XMLTab(Tab):
self.text_win.toggle_lock()
self.refresh()
+ def match_stanza(self, stanza):
+ for matcher in self.filters:
+ if not matcher.match(stanza):
+ return False
+ return True
+
@command_args_parser.raw
def command_filter_xmlmask(self, mask):
"""/filter_xmlmask <xml mask>"""
try:
- handler = Callback('custom matcher', matcher.MatchXMLMask(mask),
- self.core.incoming_stanza)
- self.core.xmpp.remove_handler('custom matcher')
- self.core.xmpp.register_handler(handler)
- self.filter_type = "XML Mask Filter"
- self.filter = mask
+ self.update_filters(matcher.MatchXMLMask(mask))
self.refresh()
except:
self.core.information('Invalid XML Mask', 'Error')
self.command_reset('')
+ @command_args_parser.raw
+ def command_filter_to(self, jid):
+ """/filter_jid_to <jid>"""
+ jid_obj = safeJID(jid)
+ if not jid_obj:
+ return self.core.information('Invalid JID: %s' % jid, 'Error')
+
+ self.update_filters(MatchJID(jid_obj, dest='to'))
+ self.refresh()
+
+ @command_args_parser.raw
+ def command_filter_from(self, jid):
+ """/filter_jid_from <jid>"""
+ jid_obj = safeJID(jid)
+ if not jid_obj:
+ return self.core.information('Invalid JID: %s' % jid, 'Error')
+
+ self.update_filters(MatchJID(jid_obj, dest='from'))
+ self.refresh()
+
+ @command_args_parser.raw
+ def command_filter_jid(self, jid):
+ """/filter_jid <jid>"""
+ jid_obj = safeJID(jid)
+ if not jid_obj:
+ return self.core.information('Invalid JID: %s' % jid, 'Error')
+
+ self.update_filters(MatchJID(jid_obj))
+ self.refresh()
+
@command_args_parser.quoted(1)
def command_filter_id(self, args):
"""/filter_id <id>"""
if args is None:
return self.core.command_help('filter_id')
- self.core.xmpp.remove_handler('custom matcher')
- handler = Callback('custom matcher', matcher.MatcherId(arg),
- self.core.incoming_stanza)
- self.core.xmpp.register_handler(handler)
- self.filter_type = "Id Filter"
- self.filter = args[0]
+ self.update_filters(matcher.MatcherId(args[0]))
self.refresh()
@command_args_parser.raw
def command_filter_xpath(self, xpath):
"""/filter_xpath <xpath>"""
try:
- handler = Callback('custom matcher', matcher.MatchXPath(
- xpath.replace('%n', self.core.xmpp.default_ns)),
- self.core.incoming_stanza)
- self.core.xmpp.remove_handler('custom matcher')
- self.core.xmpp.register_handler(handler)
- self.filter_type = "XPath Filter"
- self.filter = xpath
+ self.update_filters(matcher.MatchXPath(xpath.replace('%n', self.core.xmpp.default_ns)))
self.refresh()
except:
self.core.information('Invalid XML Path', 'Error')
@@ -119,8 +219,11 @@ class XMLTab(Tab):
@command_args_parser.ignored
def command_reset(self):
"""/reset"""
- self.core.xmpp.remove_handler('custom matcher')
- self.core.xmpp.register_handler(self.core.all_stanzas)
+ if self.filters:
+ self.filters = []
+ self.filtered_buffer.del_window(self.text_win)
+ self.core_buffer.add_window(self.text_win)
+ self.text_win.rebuild_everything(self.core_buffer)
self.filter_type = ''
self.filter = ''
self.refresh()
@@ -130,8 +233,11 @@ class XMLTab(Tab):
"""/dump <filename>"""
if args is None:
return self.core.command_help('dump')
- xml = self.core.xml_buffer.messages[:]
- text = '\n'.join(('%s %s' % (msg.str_time, clean_text(msg.txt)) for msg in xml))
+ if self.filters:
+ xml = self.filtered_buffer.messages[:]
+ else:
+ xml = self.core_buffer.messages[:]
+ text = '\n'.join(('%s %s %s' % (msg.str_time, msg.nickname, clean_text(msg.txt)) for msg in xml))
filename = os.path.expandvars(os.path.expanduser(args[0]))
try:
with open(filename, 'w') as fd:
@@ -167,8 +273,12 @@ class XMLTab(Tab):
"""
/clear
"""
- self.core.xml_buffer.messages = []
- self.text_win.rebuild_everything(self.core.xml_buffer)
+ if self.filters:
+ buffer = self.core_buffer
+ else:
+ buffer = self.filtered_buffer
+ buffer.messages = []
+ self.text_win.rebuild_everything(buffer)
self.refresh()
self.core.doupdate()