From 07018c0afa7485b06424bf6787d242e7ee523d34 Mon Sep 17 00:00:00 2001 From: Nathan Fritz Date: Thu, 17 Dec 2009 01:54:22 +0000 Subject: * fixed many stanza bugs * added stanza unhandled (unhandled iqs now reply with feature-not-implemented) * added stanza exceptions (stanzas may now reply with exceptions when their handler raises an exception) --- sleekxmpp/xmlstream/handler/waiter.py | 2 +- sleekxmpp/xmlstream/matcher/id.py | 6 ++++++ sleekxmpp/xmlstream/stanzabase.py | 37 ++++++++++++++++++++++++----------- sleekxmpp/xmlstream/xmlstream.py | 16 ++++++++++++--- 4 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 sleekxmpp/xmlstream/matcher/id.py (limited to 'sleekxmpp/xmlstream') diff --git a/sleekxmpp/xmlstream/handler/waiter.py b/sleekxmpp/xmlstream/handler/waiter.py index 140ce443..ba296386 100644 --- a/sleekxmpp/xmlstream/handler/waiter.py +++ b/sleekxmpp/xmlstream/handler/waiter.py @@ -20,7 +20,7 @@ class Waiter(base.BaseHandler): return self._payload.get(True, timeout) except queue.Empty: logging.warning("Timed out waiting for %s" % self.name) - return StanzaBase(stype='error') + return False def checkDelete(self): return True diff --git a/sleekxmpp/xmlstream/matcher/id.py b/sleekxmpp/xmlstream/matcher/id.py new file mode 100644 index 00000000..ec7597d4 --- /dev/null +++ b/sleekxmpp/xmlstream/matcher/id.py @@ -0,0 +1,6 @@ +from . import base + +class MatcherId(base.MatcherBase): + + def match(self, xml): + return xml.get('id') == self._criteria diff --git a/sleekxmpp/xmlstream/stanzabase.py b/sleekxmpp/xmlstream/stanzabase.py index 5403c69f..49ddc305 100644 --- a/sleekxmpp/xmlstream/stanzabase.py +++ b/sleekxmpp/xmlstream/stanzabase.py @@ -1,4 +1,5 @@ from xml.etree import cElementTree as ET +import logging class JID(object): def __init__(self, jid): @@ -45,7 +46,12 @@ class ElementBase(object): if self.xml is None: self.xml = xml if self.xml is None: - self.xml = ET.Element("{%(namespace)s}%(name)s" % {'name': self.name, 'namespace': self.namespace}) + for ename in self.name.split('/'): + new = ET.Element("{%(namespace)s}%(name)s" % {'name': self.name, 'namespace': self.namespace}) + if self.xml is None: + self.xml = new + else: + self.xml.append(new) if self.parent is not None: self.parent.xml.append(self.xml) return True #had to generate XML @@ -70,7 +76,7 @@ class ElementBase(object): else: return self._getAttr(attrib) elif attrib in self.plugin_attrib_map: - self.initPlugin(attrib) + if attrib not in self.plugins: self.initPlugin(attrib) return self.plugins[attrib] else: return '' @@ -87,9 +93,10 @@ class ElementBase(object): self._setAttr(attrib, value) else: self.__delitem__(attrib) - elif attrib in self.plugin_map: + elif attrib in self.plugin_attrib_map: + if attrib not in self.plugins: self.initPlugin(attrib) self.initPlugin(attrib) - self.plugins[attrib].setValues(value) + self.plugins[attrib][attrib] = value return self def __delitem__(self, attrib): @@ -101,7 +108,7 @@ class ElementBase(object): return self._delSub(attrib) else: self._delAttr(attrib) - elif attrib in self.plugin_map: + elif attrib in self.plugin_attrib_map: if attrib in self.plugins: del self.plugins[attrib] return self @@ -114,7 +121,10 @@ class ElementBase(object): return True def _setAttr(self, name, value): - self.xml.attrib[name] = value + if value is None or value == '': + self.__delitem__(name) + else: + self.xml.attrib[name] = value def _delAttr(self, name): if name in self.xml.attrib: @@ -131,12 +141,14 @@ class ElementBase(object): return stanza.text def _setSubText(self, name, attrib={}, text=None): + if text is None or text == '': + return self.__delitem__(name) stanza = self.xml.find("{%s}%s" % (self.namespace, name)) if stanza is None: - self.xml.append(ET.Element("{%s}%s" % (self.namespace, name), attrib)) - stanza = self.xml.find("{%s}%s" % (self.namespace, name)) - if text is not None: - stanza.text = text + #self.xml.append(ET.Element("{%s}%s" % (self.namespace, name), attrib)) + stanza = ET.Element("{%s}%s" % (self.namespace, name)) + self.xml.append(stanza) + stanza.text = text return stanza def _delSub(self, name): @@ -228,6 +240,9 @@ class StanzaBase(ElementBase): def unhandled(self): pass + def exception(self, text): + logging.error(text) + def send(self): self.stream.sendRaw(str(self)) @@ -285,7 +300,7 @@ class StanzaBase(ElementBase): text[cc] = '>' elif c == "'": text[cc] = ''' - elif self.escape_quotes: + else: text[cc] = '"' cc += 1 return ''.join(text) diff --git a/sleekxmpp/xmlstream/xmlstream.py b/sleekxmpp/xmlstream/xmlstream.py index e6107642..73729031 100644 --- a/sleekxmpp/xmlstream/xmlstream.py +++ b/sleekxmpp/xmlstream/xmlstream.py @@ -262,6 +262,8 @@ class XMLStream(object): handler.prerun(stanza) self.eventqueue.put(('stanza', handler, stanza)) if handler.checkDelete(): self.__handlers.pop(self.__handlers.index(handler)) + else: + stanza.unhandled() #loop through handlers and test match #spawn threads as necessary, call handlers, sending Stanza @@ -274,10 +276,18 @@ class XMLStream(object): except queue.Empty: event = None if event is not None: - etype, handler, stanza = event + etype, handler, *args = event if etype == 'stanza': - handler.run(stanza) - if etype == 'quit': + try: + handler.run(args[0]) + except: + args[0].exception(traceback.format_exc()) + elif etype == 'sched': + try: + handler.run(*args) + except: + logging.error(traceback.format_exc()) + elif etype == 'quit': logging.debug("Quitting eventRunner thread") return False -- cgit v1.2.3