1.1 --- a/README.txt Thu Jul 09 20:48:31 2009 +0200
1.2 +++ b/README.txt Sun Feb 27 18:32:58 2011 +0100
1.3 @@ -1,7 +1,10 @@
1.4 Introduction
1.5 ------------
1.6
1.7 -See docs/index.html for the libxml2dom documentation.
1.8 +The libxml2dom package provides a traditional DOM wrapper around the Python
1.9 +bindings for libxml2 providing basic support for XML and HTML processing.
1.10 +Experimental support is also provided for a number of XML technologies
1.11 +including SOAP, SVG, XML-RPC and XMPP.
1.12
1.13 Compatibility Warnings
1.14 ----------------------
1.15 @@ -71,6 +74,20 @@
1.16 libxml2dom.macrolib implementation, too). A way is needed to get libxml2 to do
1.17 the node copying itself.
1.18
1.19 +Testing the XMPP support can be awkward, particularly when trying to get user
1.20 +registration to work. If testing with ejabberd, it can be useful to run the
1.21 +'ejabberdctl register' command in order to register a user that can then be
1.22 +used with the test_xmpp.py program. Alternatively, edit the ejabberd.conf file
1.23 +(found in /etc/ejabberd on Debian, for example) changing...
1.24 +
1.25 + {access, register, [{deny, all}]}.
1.26 +
1.27 +...to...
1.28 +
1.29 + {access, register, [{allow, all}]}.
1.30 +
1.31 +...to permit in-band registration.
1.32 +
1.33 New in libxml2dom 0.5 (Changes since libxml2dom 0.4.7)
1.34 ------------------------------------------------------
1.35
2.1 --- a/libxml2dom/xmpp.py Thu Jul 09 20:48:31 2009 +0200
2.2 +++ b/libxml2dom/xmpp.py Sun Feb 27 18:32:58 2011 +0100
2.3 @@ -10,7 +10,7 @@
2.4 See: http://www.xmpp.org/rfcs/rfc3920.html
2.5 See: http://www.xmpp.org/rfcs/rfc3921.html
2.6
2.7 -Copyright (C) 2007 Paul Boddie <paul@boddie.org.uk>
2.8 +Copyright (C) 2007, 2009 Paul Boddie <paul@boddie.org.uk>
2.9
2.10 This program is free software; you can redistribute it and/or modify it under
2.11 the terms of the GNU Lesser General Public License as published by the Free
2.12 @@ -202,7 +202,7 @@
2.13 # NOTE: the specifications.
2.14
2.15 b64value = base64.encodestring("%s\x00%s\x00%s" % (jid, username, password))
2.16 - text = self.ownerDocument.createTextNode(b64value)
2.17 + text = self.ownerDocument.createTextNode(b64value.strip())
2.18 self.appendChild(text)
2.19
2.20 mechanism = property(_mechanism, _setMechanism)
2.21 @@ -361,7 +361,7 @@
2.22 return (self.xpath("session:session") or [None])[0]
2.23
2.24 bind = property(_bind)
2.25 - query = property(_query)
2.26 + registration = query = property(_query)
2.27 session = property(_session)
2.28
2.29 def createBind(self):
2.30 @@ -386,9 +386,18 @@
2.31 self.type = "get"
2.32
2.33 def makeRegistration(self):
2.34 + query = self.createQuery()
2.35 + self.appendChild(query)
2.36 self.id = "register2"
2.37 self.type = "set"
2.38
2.39 + def makeUnregistration(self):
2.40 + query = self.createQuery()
2.41 + self.appendChild(query)
2.42 + query.appendChild(self.ownerDocument.createElement("remove"))
2.43 + self.id = "unreg1"
2.44 + self.type = "set"
2.45 +
2.46 def makeSession(self, host):
2.47 session = self.createSession()
2.48 self.appendChild(session)
2.49 @@ -499,7 +508,23 @@
2.50 if doc is None:
2.51 return None
2.52 else:
2.53 - return doc.documentElement
2.54 + stanza = doc.documentElement
2.55 +
2.56 + # Add implied namespace (from the outermost element).
2.57 + # NOTE: This should possibly use the real namespace details from the
2.58 + # NOTE: stream element.
2.59 +
2.60 + if stanza.namespaceURI is None:
2.61 + new_stanza = self.createStanza(XMPP_CLIENT_NAMESPACE, stanza.name)
2.62 + new_doc = new_stanza.ownerDocument
2.63 + for attribute in stanza.attributes:
2.64 + new_stanza.attributes.setNamedItemNS(attribute)
2.65 + for child in stanza.childNodes:
2.66 + n = new_doc.importNode(child, 1)
2.67 + new_stanza.appendChild(n)
2.68 + stanza = new_stanza
2.69 +
2.70 + return stanza
2.71
2.72 # Stanza creation.
2.73
3.1 --- a/tests/xmpp_test.py Thu Jul 09 20:48:31 2009 +0200
3.2 +++ b/tests/xmpp_test.py Sun Feb 27 18:32:58 2011 +0100
3.3 @@ -1,107 +1,195 @@
3.4 #!/usr/bin/env python
3.5
3.6 +"""
3.7 +A test of XMPP support, providing a simple chat interface.
3.8 +"""
3.9 +
3.10 import libxml2dom.xmpp
3.11 +import os
3.12 import sys
3.13
3.14 -sender = "sender" in sys.argv
3.15 -receiver = "receiver" in sys.argv
3.16 -if not (sender or receiver):
3.17 - print "Please specify sender or receiver."
3.18 +try:
3.19 + username, domain, password, mode = sys.argv[1:5]
3.20 +except ValueError:
3.21 + print sys.argv[0], "<username> <domain> <password> <mode> [ <endpoint> ]"
3.22 + print
3.23 + print "For example:"
3.24 + print
3.25 + print sys.argv[0], "libxml2dom localhost jabber listen # to listen"
3.26 + print sys.argv[0], "libxml2dom localhost jabber contact 1234 # to contact a listener"
3.27 sys.exit(1)
3.28
3.29 -if len(sys.argv) > 2:
3.30 - peer = sys.argv[2]
3.31 -elif sender:
3.32 - peer = "paulb@localhost/receiver"
3.33 +receiving = mode == "listen"
3.34 +register = mode == "register"
3.35 +unregister = mode == "unregister"
3.36 +
3.37 +# Get a peer to send messages to.
3.38 +
3.39 +if not receiving and not register and not unregister:
3.40 + if len(sys.argv) > 5:
3.41 + peer = "%s@%s/%s" % (username, domain, sys.argv[5])
3.42 + else:
3.43 + print "Need to specify a peer to send messages to."
3.44 + sys.exit(1)
3.45 +
3.46 +# Connect to the XMPP server.
3.47
3.48 s = libxml2dom.xmpp.Session(("localhost", 5222))
3.49 d = s.connect("localhost")
3.50 -print "---- 1 ----"
3.51 -print d.toString()
3.52 +
3.53 +print "---- Connection ----"
3.54 +print d.toString(prettyprint=1)
3.55 +
3.56 +# Register if requested.
3.57 +
3.58 +if register:
3.59 + print "---- Register ----"
3.60 + iq = s.createIq()
3.61 + iq.makeQuery()
3.62 + print iq.toString(prettyprint=1)
3.63 + s.send(iq)
3.64 +
3.65 + print "---- Response ----"
3.66 + d = s.receive()
3.67 + print d.toString(prettyprint=1)
3.68
3.69 -auth = s.createAuth()
3.70 -auth.mechanism = "PLAIN"
3.71 -auth.setCredentials("paulb@localhost", "paulb", "jabber")
3.72 -s.send(auth)
3.73 -print "---- 2 ----"
3.74 -d = s.receive()
3.75 -print "---- 3 ----"
3.76 -print d.toString()
3.77 + if not d.query.xpath("register:registered"):
3.78 + instructions = d.query.xpath("register:instructions")
3.79 + if instructions:
3.80 + print instructions[0].textContent
3.81
3.82 -if d.localName == "failure":
3.83 - if d.reason == "not-authorized":
3.84 - print "Not authorized: must register first!"
3.85 + print "---- Completing form ----"
3.86 + iq = s.createIq()
3.87 + iq.makeRegistration()
3.88 + iq.registration["username"] = username
3.89 + iq.registration["password"] = password
3.90 + print iq.toString(prettyprint=1)
3.91 + s.send(iq)
3.92 +
3.93 + print "---- Response ----"
3.94 + d = s.receive()
3.95 + print d.toString(prettyprint=1)
3.96 +
3.97 s.disconnect()
3.98 sys.exit(1)
3.99
3.100 +print "---- Authentication ----"
3.101 +auth = s.createAuth()
3.102 +auth.mechanism = "PLAIN"
3.103 +auth.setCredentials(username, username, password)
3.104 +print auth.toString(prettyprint=1)
3.105 +s.send(auth)
3.106 +
3.107 +print "---- Response ----"
3.108 +d = s.receive()
3.109 +print d.toString(prettyprint=1)
3.110 +
3.111 +if d.localName == "failure":
3.112 + if d.reason == "not-authorized":
3.113 + print "Not authorized: perhaps register first!"
3.114 + s.disconnect()
3.115 + sys.exit(1)
3.116 +
3.117 +# Reconnect.
3.118 +
3.119 d = s.connect("localhost")
3.120 -print "---- 4 ----"
3.121 -print d.toString()
3.122
3.123 +print "---- Authenticated connection ----"
3.124 +print d.toString(prettyprint=1)
3.125 +
3.126 +print "---- Binding ----"
3.127 iq = s.createIq()
3.128 iq.makeBind()
3.129 -if sender:
3.130 - iq.bind.resource = "sender"
3.131 -else:
3.132 - iq.bind.resource = "receiver"
3.133 +iq.bind.resource = str(os.getpid())
3.134 +print iq.toString(prettyprint=1)
3.135 s.send(iq)
3.136 -print "---- 5 ----"
3.137 +
3.138 +print "---- Response ----"
3.139 d = s.receive()
3.140 -print "---- 6 ----"
3.141 -print d.toString()
3.142 +print d.toString(prettyprint=1)
3.143
3.144 +print "---- Session ----"
3.145 iq = s.createIq()
3.146 iq.makeSession("localhost")
3.147 +print iq.toString(prettyprint=1)
3.148 s.send(iq)
3.149 -print "---- 7 ----"
3.150 +
3.151 +print "---- Response ----"
3.152 d = s.receive()
3.153 -print "---- 8 ----"
3.154 -print d.toString()
3.155 +print d.toString(prettyprint=1)
3.156 +
3.157 +# Unregister if requested.
3.158
3.159 -if sender:
3.160 - message = s.createMessage()
3.161 - message.from_ = "paulb@localhost/sender"
3.162 - message.to = peer
3.163 - message.type = "chat"
3.164 - message.body = message.createBody()
3.165 - text = message.ownerDocument.createTextNode("Hello!")
3.166 - message.body.appendChild(text)
3.167 - print "Sending..."
3.168 - print message.toString()
3.169 - s.send(message)
3.170 +if unregister:
3.171 + print "---- Unregister ----"
3.172 + iq = s.createIq()
3.173 + iq.makeUnregistration()
3.174 + print iq.toString(prettyprint=1)
3.175 + s.send(iq)
3.176 +
3.177 + print "---- Response ----"
3.178 d = s.receive()
3.179 + print d.toString(prettyprint=1)
3.180
3.181 -if receiver:
3.182 + s.disconnect()
3.183 + sys.exit(1)
3.184 +
3.185 +# Otherwise, enter chat mode.
3.186 +
3.187 +print "---- Chatting ----"
3.188 +try:
3.189 while 1:
3.190 - print "Listening..."
3.191 - doc = s.receive()
3.192 - print doc.toString()
3.193 - print
3.194 - print "From:", doc.from_
3.195 - print "To:", doc.to
3.196 - print "Type:", doc.type
3.197 - print
3.198 - if doc.localName == "message":
3.199 - print "Message..."
3.200 - if doc.type == "chat" and doc.body:
3.201 - print doc.body.textContent
3.202 - elif doc.event:
3.203 - print "Composing?", doc.event.composing
3.204 - print "Delivered?", doc.event.delivered
3.205 - print "Displayed?", doc.event.displayed
3.206 - print "Offline?", doc.event.offline
3.207 - print "Id:", doc.event.id
3.208 - elif doc.localName == "presence":
3.209 - print "Presence..."
3.210 - if doc.type == "subscribe":
3.211 - presence = s.createPresence()
3.212 - presence.type = "subscribed"
3.213 - presence.from_ = doc.to
3.214 - presence.to = doc.from_
3.215 - print "Sending..."
3.216 - print presence.toString()
3.217 - s.send(presence)
3.218 - d = s.receive()
3.219 - print
3.220 + if not receiving:
3.221 + message = s.createMessage()
3.222 + message.from_ = "%s@%s/sender" % (username, domain)
3.223 + message.to = peer
3.224 + message.type = "chat"
3.225 + message.body = message.createBody()
3.226 + print "Enter message..."
3.227 + message_text = raw_input()
3.228 + text = message.ownerDocument.createTextNode(message_text)
3.229 + message.body.appendChild(text)
3.230 + print "Sending..."
3.231 + print message.toString(prettyprint=1)
3.232 + s.send(message)
3.233 + receiving = 1
3.234 +
3.235 + if receiving:
3.236 + print "Listening as %s..." % os.getpid()
3.237 + d = s.receive()
3.238 + print d.toString(prettyprint=1)
3.239 + print
3.240 + print "From:", d.from_
3.241 + print "To:", d.to
3.242 + print "Type:", d.type
3.243 + print
3.244 + if d.localName == "message":
3.245 + print "Message..."
3.246 + if d.type == "chat" and d.body:
3.247 + print d.body.textContent
3.248 + elif d.event:
3.249 + print "Composing?", d.event.composing
3.250 + print "Delivered?", d.event.delivered
3.251 + print "Displayed?", d.event.displayed
3.252 + print "Offline?", d.event.offline
3.253 + print "Id:", d.event.id
3.254 + elif d.localName == "presence":
3.255 + print "Presence..."
3.256 + if d.type == "subscribe":
3.257 + presence = s.createPresence()
3.258 + presence.type = "subscribed"
3.259 + presence.from_ = d.to
3.260 + presence.to = d.from_
3.261 + print "Sending..."
3.262 + print presence.toString(prettyprint=1)
3.263 + s.send(presence)
3.264 + d = s.receive()
3.265 + print d.toString(prettyprint=1)
3.266 + print
3.267 + receiving = 0
3.268 + peer = d.from_
3.269 +
3.270 +finally:
3.271 + s.disconnect()
3.272
3.273 # vim: tabstop=4 expandtab shiftwidth=4