mirror of
https://github.com/correl/SleekXMPP.git
synced 2024-11-27 19:19:54 +00:00
* added proper message and iq stanzas. presence left to do
This commit is contained in:
parent
6be17ebbe2
commit
007b04dd30
6 changed files with 283 additions and 39 deletions
|
@ -37,7 +37,7 @@ import sys
|
|||
import random
|
||||
import copy
|
||||
from . import plugins
|
||||
from . import stanza
|
||||
#from . import stanza
|
||||
srvsupport = True
|
||||
try:
|
||||
import dns.resolver
|
||||
|
@ -87,6 +87,8 @@ class ClientXMPP(basexmpp, XMLStream):
|
|||
#self.register_plugins()
|
||||
|
||||
def importStanzas(self):
|
||||
pass
|
||||
return
|
||||
for modname in stanza.__all__:
|
||||
__import__("%s.%s" % (globals()['stanza'].__name__, modname))
|
||||
for register in getattr(stanza, modname).stanzas:
|
||||
|
|
|
@ -26,6 +26,8 @@ from . xmlstream.handler.xmlcallback import XMLCallback
|
|||
from . xmlstream.handler.xmlwaiter import XMLWaiter
|
||||
from . xmlstream.handler.callback import Callback
|
||||
from . import plugins
|
||||
from . stanza.message import Message
|
||||
from . stanza.iq import Iq
|
||||
|
||||
import logging
|
||||
import threading
|
||||
|
@ -95,6 +97,8 @@ class basexmpp(object):
|
|||
self.registerHandler(Callback('IM', MatchMany((MatchXMLMask("<message xmlns='%s' type='chat'><body /></message>" % self.default_ns),MatchXMLMask("<message xmlns='%s' type='normal'><body /></message>" % self.default_ns),MatchXMLMask("<message xmlns='%s' type='__None__'><body /></message>" % self.default_ns))), self._handleMessage, thread=False))
|
||||
self.registerHandler(Callback('Presence', MatchMany((MatchXMLMask("<presence xmlns='%s' type='available'/>" % self.default_ns),MatchXMLMask("<presence xmlns='%s' type='__None__'/>" % self.default_ns),MatchXMLMask("<presence xmlns='%s' type='unavailable'/>" % self.default_ns))), self._handlePresence, thread=False))
|
||||
self.registerHandler(Callback('PresenceSubscribe', MatchMany((MatchXMLMask("<presence xmlns='%s' type='subscribe'/>" % self.default_ns),MatchXMLMask("<presence xmlns='%s' type='unsubscribed'/>" % self.default_ns))), self._handlePresenceSubscribe))
|
||||
self.registerStanza(Message)
|
||||
self.registerStanza(Iq)
|
||||
|
||||
def set_jid(self, jid):
|
||||
"""Rip a JID apart and claim it as our own."""
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
from .. xmlstream.stanzabase import StanzaBase
|
||||
from xml.etree import cElementTree as ET
|
||||
|
||||
class Iq(StanzaBase):
|
||||
interfaces = set(('type', 'to', 'from', 'id', 'body', 'subject'))
|
||||
types = set(('get', 'result', 'set', 'error'))
|
||||
name = 'iq'
|
||||
namespace = 'jabber:client'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
StanzaBase.__init__(self, *args, **kwargs)
|
||||
if self['id'] == '':
|
||||
self['id'] = self.stream.getId()
|
||||
print("________LOADED IQ CLASS")
|
||||
|
||||
def result(self):
|
||||
self['type'] = 'result'
|
||||
return self
|
||||
|
||||
def set(self):
|
||||
self['type'] = 'set'
|
||||
return self
|
||||
|
||||
def error(self):
|
||||
#TODO add error payloads
|
||||
self['type'] = 'error'
|
||||
return self
|
||||
|
||||
def get(self):
|
||||
self['type'] = 'get'
|
||||
return self
|
||||
|
||||
def setPayload(self, value):
|
||||
self.clear()
|
||||
StanzaBase.setPayload(self, value)
|
||||
|
||||
def unhandled(self):
|
||||
pass
|
||||
# returned unhandled error
|
|
@ -0,0 +1,39 @@
|
|||
from .. xmlstream.stanzabase import StanzaBase
|
||||
from xml.etree import cElementTree as ET
|
||||
|
||||
class Message(StanzaBase):
|
||||
interfaces = set(('type', 'to', 'from', 'id', 'body', 'subject'))
|
||||
types = set((None, 'normal', 'chat', 'headline', 'error'))
|
||||
sub_interfaces = set(('body', 'subject'))
|
||||
name = 'message'
|
||||
namespace = 'jabber:client'
|
||||
|
||||
def getType(self):
|
||||
return self.xml.attrib.get('type', 'normal')
|
||||
|
||||
def chat(self):
|
||||
self['type'] = 'chat'
|
||||
return self
|
||||
|
||||
def normal(self):
|
||||
self['type'] = 'normal'
|
||||
return self
|
||||
|
||||
if __name__ == '__main__':
|
||||
m = Message()
|
||||
m['to'] = 'me'
|
||||
m['from'] = 'you'
|
||||
m['type'] = 'chat'
|
||||
m.reply()
|
||||
m['body'] = 'Hello there!'
|
||||
m['subject'] = 'whatever'
|
||||
m['id'] = 'abc'
|
||||
print(str(m))
|
||||
print(m['body'])
|
||||
print(m['subject'])
|
||||
print(m['id'])
|
||||
m['type'] = None
|
||||
m['body'] = None
|
||||
m['id'] = None
|
||||
print(str(m))
|
||||
print(m['type'])
|
|
@ -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)
|
||||
|
||||
|
||||
def _processXML(self, xml, cur_ns=''):
|
||||
if '}' in xml.tag:
|
||||
ns,tag = xml.tag[1:].split('}')
|
||||
else:
|
||||
tag = xml.tag
|
||||
|
||||
def toXML(self, xml):
|
||||
"Set outgoing XML"
|
||||
|
||||
def extend(self, extension_class, xml=None):
|
||||
"Initialize extension"
|
||||
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 self.MATCHER.match(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 __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:
|
||||
raise ValueError
|
||||
return self
|
||||
|
||||
def getPayload(self):
|
||||
return self.xml.getchildren()
|
||||
|
||||
def setPayload(self, value):
|
||||
self.xml.append(value)
|
||||
|
||||
def delPayload(self):
|
||||
self.clear()
|
||||
|
||||
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))
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue