"THIS DOESN'T WORK"
from __future__ import nested_scopes
import cgi
from twisted.web import microdom, domhelpers
from twisted.python import reflect
from twisted import copyright
from twisted.internet import defer
class BadStream(Exception):
pass
class ElementWithText(microdom.Element):
def __init__(self, tagName, text, attributes=None, parentNode=None,
filename=None, markpos=None):
microdom.Element.__init__(self, tagName, attributes, parentNode,
filename, markpos)
self.text = microdom.Text(text)
self.appendChild(self.text)
class XMLStream(microdom.MicroDOMParser):
first = 1
# if we get an exception in dataReceived we must send tag end before
# losing connection
def connectionMade(self):
microdom.MicroDOMParser.connectionMade(self)
attributes = ' '.join(['%s="%s"' % (k, v) for (k, v) in
self.getGlobalAttributes().items()])
self.transport.write("<stream:stream %s>" % attributes)
def loseConnection(self):
self.transport.write("</stream:stream>")
self.transport.loseConnection()
def gotTagStart(self, name, attributes):
if self.first:
if name != "stream:stream":
raise BadStream()
self.first = 0
self.gotGlobalAttributes(attributes)
else:
microdom.MicroDOMParser.gotTagStart(self, name, attributes)
def gotTagEnd(self, name):
if not self.elementstack and name=="stream:stream":
self.transport.loseConnection()
return
microdom.MicroDOMParser.gotTagEnd(self, name)
if self.documents:
self.gotElement(self.documents[0])
self.documents.pop()
def gotElement(self, element):
raise NotImplementedError("what to do with element")
def writeElement(self, element):
element.writexml(self)
def parseJID(jid):
resource = jid.rfind('/')
if resource != -1:
jid, resource = jid[:resource], jid[resource+1:]
else:
resource = None
user = jid.find('@')
if user != -1:
user, jid = jid[:user], jid[user+1:]
else:
user = None
return user, jid, resource
def makeJID(user, host, resource):
if user is not None:
jid = user+'@'+host
else:
jid = host
if resource is not None:
jid += '/'+resource
return jid
class JabberBasic(XMLStream):
def connectionMade(self):
XMLStream.connectionMade(self)
def gotGlobalAttributes(self, attributes):
self.gotGlobalFrom(attributes.get('from'))
self.gotGlobalID(attributes.get('id'))
self.gotGlobalTo(attributes.get('to'))
# Only notify of the connection after the stream-level connection
# started
methods = reflect.prefixedMethods(self, 'notifyConnectionMade_')
for m in methods:
m()
def gotElement(self, element):
elementName = element.tagName.replace(':', '_')
m = getattr(self, "gotElement_"+elementName, self.gotUnknownElement)
m(element)
def gotElement_stream_error(self, element):
self.loseConnection()
def gotUnknownElement(self, element):
pass # degrade gracefully
def gotGlobalFrom(self, from_):
pass # usually we don't care
def gotGlobalID(self, id):
#print "got global id"
self.id = id
def gotGlobalTo(self, to):
pass # usually we don't care
# probably wanna override this for servers
def getGlobalAttributes(self):
return {'to': self.getGlobalTo()}
def getGlobalTo(self):
return ''
def _getElementNamedOrNone(element, name):
return (microdom.getElementsByTagName(element, name) or [None])[0]
class JabberMessageMixin:
def gotElement_message(self, message):
type = message.attributes.get('type')
from_ = message.attributes.get('from')
to = message.attributes.get('to')
id = message.attributes.get('id')
if type:
m = getattr(self, "gotMessage_"+type, self.gotMessageUnknown)
else:
m = self.gotMessageUnknown
m(type, from_, to, id, message)
def gotMessage_error(self, type, from_, to, id, message):
error = _getElementNamedOrNone(message, 'error')
code = error.attributes['code']
text = domhelpers.getNodeText(error)
self.gotMessageError(from_, to, id, code, text)
def gotMessageUnknown(self, type, from_, to, id, message):
body = _getElementNamedOrNone(message, 'body')
subject = _getElementNamedOrNone(message, 'subject')
thread = _getElementNamedOrNone(message, 'thread')
self.gotMessageDefault(type, from_, to, id, subject, body, thread)
def gotMessageError(self, from_, to, id, code, text):
raise NotImplementedError
def gotMessageDefault(self, type, from_, to, id, subject, body, thread):
raise NotImplementedError
def sendM(self, to_, subject, thread, body):
id = str(self.lastID)
self.lastID += 1
deferred = defer.Deferred()
query = microdom.Element("message", { "to": to })
if subject_:
subject = ElementWithText("subject", subject)
query.appendChild(subject)
if thread_:
thread = ElementWithText("thread", thread)
query.appendChild(thread)
body = ElementWithText("body", body)
query.appendChild(body)
query.writexml(self.transport)
self.requests[id] = deferred
return id, deferred
class JabberPresenceMixin:
def sendP(self, type, ashow, astatus):
id = str(self.lastID)
self.lastID += 1
deferred = defer.Deferred()
query = microdom.Element("presence", { "type": type, "id": id })
show = ElementWithText("show", ashow)
status = ElementWithText("status", astatus)
priority = ElementWithText("priority", "5")
query.appendChild(show)
query.appendChild(status)
query.appendChild(priority)
query.writexml(self.transport)
self.requests[id] = deferred
return id, deferred
def gotElement_presence(self, element):
message=element
type = message.attributes.get('type')
from_ = message.attributes.get('from')
to = message.attributes.get('to')
id = message.attributes.get('id')
if type:
m = getattr(self, "gotPresence_"+type, self.gotPresence_available)
else:
m = self.gotPresence_available
m(type, from_, to, id, message)
def gotPresence_error(self, type, from_, to, id, message):
error = _getElementNamedOrNone(message, 'error')
code = error.attributes['code']
text = domhelpers.getNodeText(error)
self.gotPresenceError(from_, to, id, code, text)
def gotPresence_available(self, type, from_, to, id, message):
show = _getElementNamedOrNone(message, 'show')
status = _getElementNamedOrNone(message, 'status')
priority = _getElementNamedOrNone(message, 'priority')
return self.gotPresenceNotification(from_, to, id, show, status,
priority)
def gotPresenceError(self, from_, to, id, code, text):
raise NotImplementedError
def gotPresenceNotification(self, from_, to, id, show, status, priority):
raise NotImplementedError
def gotPresence_unavailable(self, type, from_, to, id, message):
pass # implement
def gotPresence_subscribe(self, type, from_, to, id, message):
pass # implement
def gotPresence_subscribed(self, type, from_, to, id, message):
pass # implement
def gotPresence_probe(self, type, from_, to, id, message):
pass # implement
class IQFailure(Exception):
pass
class JabberIQMixin:
def notifyConnectionMade_IQ(self):
self.lastID = 0
self.requests = {}
def sendIQ(self, type, from_, to, query):
id = str(self.lastID)
self.lastID += 1
deferred = defer.Deferred()
attributes = []
for k, v in [('from', from_), ('to', to), ('type', type), ('id', id)]:
if v:
attributes.append('%s="%s"' % (k, v))
attributes = " ".join(attributes)
self.transport.write("<iq %s>" % attributes)
query.writexml(self.transport)
self.transport.write('</iq>')
self.requests[id] = deferred
return id, deferred
def gotElement_iq(self, element):
type = element.attributes['type']
id = element.attributes.get('id')
from_ = element.attributes.get('from')
to = element.attributes.get('to')
message=element
if type == 'result' or type == 'error':
if not self.requests.has_key(id):
return # ignore results for cancelled/non-existing requests
if type == 'result':
query = _getElementNamedOrNone(message, 'query')
self.requests[id].callback(query)
else:
error = _getElementNamedOrNone(message, 'error')
code = error.attributes['code']
text = domhelpers.getNodeText(error)
self.requests[id].errback(IQFailure(code, text))
del self.requests[id]
elif type == 'get' or type == 'set': # a remote method call!
query = _getElementNamedOrNone(message, 'query')
ns = query.attributes['xmlns']
d = self.methodCalled(type, ns, id, from_, to, query)
def _(query):
myTo, myFrom = from_, to
e = microdom.Element('iq', {'id': id, 'from': to,
'to': from_, type: 'error'})
e.appendChild(query)
self.writeElement(e)
d.addCallback(_)
def _(failure):
failure.trap(IQFailure)
code, text = failure.value
myTo, myFrom = from_, to
e = microdom.Element('iq', {'id': id, 'from': to,
'to': from_, type: 'result'})
error = microdom.Element('error', {'code': code})
error.appendChild(microdom.Text(cgi.escape(text)))
e.appendChild(error)
self.writeElement(e)
d.addErrback(_)
def methodCalled(self, type, ns, from_, to, id, query):
if ns.startswith("http://"):
return self.methodCalledURL(type, ns, from_, to, id, query)
else:
n = ns.replace(":", "_")
m = getattr(self, "methodCalled_"+n, self.methodCalledUnknown)
return m(type, ns, from_, to, id, query)
def methodCalledUnknown(self, type, ns, from_, to, id, query):
return defer.fail(IQFailure(502, "I am a silly monkey"))
methodCalledURL = methodCalledUnknown
class JabberIQAdMixin:
"Free advertisement is fun"
def methodCalled_jabber_iq_version(self, type, ns, from_, to, id, query):
e = microdom.Element(query, {'xmlns': ns})
name = microdom.Element('name')
name.appendChild(microdom.Text("TwistedJabber"))
e.appendChild(name)
version = microdom.Element('version')
version.appendChild(microdom.Text(copyright.version))
e.appendChild(version)
return defer.succeed(e)
class JabberIQLoggingInMixin(JabberIQMixin):
def notifyConnectionMade_IQ(self):
JabberIQMixin.notifyConnectionMade_IQ(self)
query = microdom.Element('query', {'xmlns':"jabber:iq:auth"})
username = microdom.Element('username')
username.appendChild(microdom.Text(cgi.escape(self.getUsername())))
digest = microdom.Element('digest')
digest.appendChild(microdom.Text(cgi.escape(self.getDigest())))
resource = microdom.Element('resource')
resource.appendChild(microdom.Text(cgi.escape(self.getResource())))
query.appendChild(username)
query.appendChild(digest)
query.appendChild(resource)
self.sendIQ(type='set', from_=None, to=None,
query=query)[1].addCallbacks(
self.loginSuccess,
self.loginFailure
)
def getDigest(self):
import sha
return sha.new(self.id+self.getPassword()).hexdigest()
def getResource(self):
return ''
def getUsername(self):
raise NotImplementedError
def getPassword(self):
raise NotImplementedError
def loginSuccess(self, arg):
raise NotImplementedError
def loginFailure(self, arg):
raise NotImplementedError
class JabberCoreMixin(JabberMessageMixin, JabberPresenceMixin, JabberIQMixin):
pass
class JabberCoreClientMixin(JabberMessageMixin, JabberPresenceMixin,
JabberIQLoggingInMixin, JabberIQAdMixin):
pass
syntax highlighted by Code2HTML, v. 0.9.1