diff options
Diffstat (limited to 'sleekxmpp/xmlstream')
-rw-r--r-- | sleekxmpp/xmlstream/stanzabase.py | 215 | ||||
-rw-r--r-- | sleekxmpp/xmlstream/xmlstream.py | 13 |
2 files changed, 194 insertions, 34 deletions
diff --git a/sleekxmpp/xmlstream/stanzabase.py b/sleekxmpp/xmlstream/stanzabase.py index 5232ff5e..787ae5e3 100644 --- a/sleekxmpp/xmlstream/stanzabase.py +++ b/sleekxmpp/xmlstream/stanzabase.py @@ -1,37 +1,198 @@ -from __future__ import absolute_import -from sleekxmpp.xmlstream.matcher.xpath import MatchXPath +from xml.etree import cElementTree as ET class StanzaBase(object): + name = 'stanza' + namespace = 'jabber:client' + interfaces = set(('type', 'to', 'from', 'id', 'payload')) + types = set(('get', 'set', 'error', None, 'unavailable', 'normal', 'chat')) + sub_interfaces = tuple() - MATCHER = MatchXPath("") - - def __init__(self, stream, xml=None, extensions=[]): - self.extensions = extensions - self.p = {} #plugins - - self.xml = xml + def __init__(self, stream, xml=None, stype=None, sto=None, sfrom=None, sid=None): self.stream = stream - if xml is not None: - self.fromXML(xml) - - def fromXML(self, xml): - "Initialize based on incoming XML" - self._processXML(xml) - for ext in self.extensions: - ext.fromXML(self, xml) + self.xml = xml + if xml is None: + self.xml = ET.Element("{%(namespace)s}%(name)s" % {'name': self.name, 'namespace': self.namespace}) + if stype is not None: + self['type'] = stype + if sto is not None: + self['to'] = sto + if sfrom is not None: + self['from'] = sfrom + self.tag = "{%s}%s" % (self.stream.default_ns, self.name) + + def match(self, xml): + return xml.tag == self.tag + def __getitem__(self, attrib): + if attrib in self.interfaces: + if hasattr(self, "get%s" % attrib.title()): + return getattr(self, "get%s" % attrib.title())() + else: + if attrib in self.sub_interfaces: + return self._getSubText(attrib) + else: + return self._getAttr(attrib) + else: + return '' - def _processXML(self, xml, cur_ns=''): - if '}' in xml.tag: - ns,tag = xml.tag[1:].split('}') + def __setitem__(self, attrib, value): + if attrib.lower() in self.interfaces: + if value is not None: + if hasattr(self, "set%s" % attrib.title()): + getattr(self, "set%s" % attrib.title())(value,) + else: + if attrib in self.sub_interfaces: + return self._setSubText(attrib, text=value) + else: + self._setAttr(attrib, value) + else: + self.__delitem__(attrib) + return self + + def __delitem__(self, attrib): + if attrib.lower() in self.interfaces: + if hasattr(self, "del%s" % attrib.title()): + getattr(self, "del%s" % attrib.title())() + else: + if attrib in self.sub_interfaces: + return self._delSub(attrib) + else: + self._delAttr(attrib) + return self + + def setType(self, value): + if value in self.types: + if value is None and 'type' in self.xml.attrib: + del self.xml.attrib['type'] + elif value is not None: + self.xml.attrib['type'] = value else: - tag = xml.tag + raise ValueError + return self + + def getPayload(self): + return self.xml.getchildren() - def toXML(self, xml): - "Set outgoing XML" + def setPayload(self, value): + self.xml.append(value) - def extend(self, extension_class, xml=None): - "Initialize extension" + def delPayload(self): + self.clear() - def match(self, xml): - return self.MATCHER.match(xml) + def clear(self): + for child in self.xml.getchildren(): + self.xml.remove(child) + + def reply(self): + self['from'], self['to'] = self['to'], self['from'] + return self + + def error(self): + self['type'] = 'error' + + def _setAttr(self, name, value): + self.xml.attrib[name] = value + + def _delAttr(self, name): + if name in self.xml.attrib: + del self.xml.attrib[name] + + def _getAttr(self, name): + return self.xml.attrib.get(name, '') + + def _getSubText(self, name): + stanza = self.xml.find("{%s}%s" % (self.namespace, name)) + if stanza is None or stanza.text is None: + return '' + else: + return stanza.text + + def _setSubText(self, name, attrib={}, text=None): + 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 + return stanza + + def _delSub(self, name): + for child in self.xml.getchildren(): + if child.tag == "{%s}%s" % (self.namespace, name): + self.xml.remove(child) + + def unhandled(self): + pass + + def send(self): + self.stream.sendRaw(str(self)) + + def __str__(self, xml=None, xmlns='', stringbuffer=''): + if xml is None: + xml = self.xml + newoutput = [stringbuffer] + #TODO respect ET mapped namespaces + itag = xml.tag.split('}', 1)[-1] + if '}' in xml.tag: + ixmlns = xml.tag.split('}', 1)[0][1:] + else: + ixmlns = '' + nsbuffer = '' + #if xmlns != ixmlns and ixmlns != '': + # if ixmlns in self.namespace_map: + # if self.namespace_map[ixmlns] != '': + # itag = "%s:%s" % (self.namespace_map[ixmlns], itag) + # else: + # nsbuffer = """ xmlns="%s\"""" % ixmlns + if ixmlns not in (xmlns, self.namespace): + nsbuffer = """ xmlns="%s\"""" % ixmlns + newoutput.append("<%s" % itag) + newoutput.append(nsbuffer) + for attrib in xml.attrib: + newoutput.append(""" %s="%s\"""" % (attrib, self.xmlesc(xml.attrib[attrib]))) + if len(xml) or xml.text or xml.tail: + newoutput.append(">") + if xml.text: + newoutput.append(self.xmlesc(xml.text)) + if len(xml): + for child in xml.getchildren(): + newoutput.append(self.__str__(child, ixmlns)) + newoutput.append("</%s>" % (itag, )) + if xml.tail: + newoutput.append(self.xmlesc(xml.tail)) + elif xml.text: + newoutput.append(">%s</%s>" % (self.xmlesc(xml.text), itag)) + else: + newoutput.append(" />") + return ''.join(newoutput) + + def xmlesc(self, text): + text = list(text) + cc = 0 + matches = ('&', '<', '"', '>', "'") + for c in text: + if c in matches: + if c == '&': + text[cc] = '&' + elif c == '<': + text[cc] = '<' + elif c == '>': + text[cc] = '>' + elif c == "'": + text[cc] = ''' + elif self.escape_quotes: + text[cc] = '"' + cc += 1 + return ''.join(text) + + +if __name__ == '__main__': + x = Stanza() + x['from'] = 'you' + x['to'] = 'me' + print(x['from'], x['to']) + x.reply() + print(x['from'], x['to']) + x['from'] = None + print(x['from'], x['to']) + print(str(x)) diff --git a/sleekxmpp/xmlstream/xmlstream.py b/sleekxmpp/xmlstream/xmlstream.py index 8ffb7841..8971a02c 100644 --- a/sleekxmpp/xmlstream/xmlstream.py +++ b/sleekxmpp/xmlstream/xmlstream.py @@ -44,7 +44,7 @@ class XMLStream(object): self.__thread = {} - self.__root_stanza = {} + self.__root_stanza = [] self.__stanza = {} self.__stanza_extension = {} self.__handlers = [] @@ -251,11 +251,13 @@ class XMLStream(object): xmlobj = self.incoming_filter(xmlobj) stanza = None for stanza_class in self.__root_stanza: - if self.__root_stanza[stanza_class].match(xmlobj): + if xmlobj.tag == "{%s}%s" % (self.default_ns, stanza_class.name): + #if self.__root_stanza[stanza_class].match(xmlobj): stanza = stanza_class(self, xmlobj) break if stanza is None: stanza = StanzaBase(self, xmlobj) + logging.debug(self.__handlers) for handler in self.__handlers: if handler.match(xmlobj): handler.prerun(stanza) @@ -293,12 +295,9 @@ class XMLStream(object): return idx += 1 - def registerStanza(self, matcher, stanza_class, root=True): + def registerStanza(self, stanza_class): "Adds stanza. If root stanzas build stanzas sent in events while non-root stanzas build substanza objects." - if root: - self.__root_stanza[stanza_class] = matcher - else: - self.__stanza[stanza_class] = matcher + self.__root_stanza.append(stanza_class) def registerStanzaExtension(self, stanza_class, stanza_extension): if stanza_class not in stanza_extensions: |