1.1 --- a/libxml2dom/__init__.py Sun Apr 08 00:00:25 2007 +0000
1.2 +++ b/libxml2dom/__init__.py Sun Apr 08 00:01:29 2007 +0000
1.3 @@ -534,15 +534,22 @@
1.4 def createDocument(namespaceURI, localName, doctype):
1.5 return default_impl.createDocument(namespaceURI, localName, doctype)
1.6
1.7 -def parse(stream_or_string, html=0, htmlencoding=None, impl=None):
1.8 +def parse(stream_or_string, html=0, htmlencoding=None, unfinished=0, impl=None):
1.9
1.10 """
1.11 Parse the given 'stream_or_string', where the supplied object can either be
1.12 a stream (such as a file or stream object), or a string (containing the
1.13 - filename of a document). If the optional 'html' parameter is set to a true
1.14 - value, the content to be parsed will be treated as being HTML rather than
1.15 - XML. If the optional 'htmlencoding' is specified, HTML parsing will be
1.16 - performed with the document encoding assumed to that specified.
1.17 + filename of a document). The optional parameters described below should be
1.18 + provided as keyword arguments.
1.19 +
1.20 + If the optional 'html' parameter is set to a true value, the content to be
1.21 + parsed will be treated as being HTML rather than XML. If the optional
1.22 + 'htmlencoding' is specified, HTML parsing will be performed with the
1.23 + document encoding assumed to that specified.
1.24 +
1.25 + If the optional 'unfinished' parameter is set to a true value, unfinished
1.26 + documents will be parsed, even though such documents may be missing content
1.27 + such as closing tags.
1.28
1.29 A document object is returned by this function.
1.30 """
1.31 @@ -551,48 +558,66 @@
1.32
1.33 if hasattr(stream_or_string, "read"):
1.34 stream = stream_or_string
1.35 - return parseString(stream.read(), html, htmlencoding, impl)
1.36 + return parseString(stream.read(), html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=impl)
1.37 else:
1.38 - return parseFile(stream_or_string, html, htmlencoding, impl)
1.39 + return parseFile(stream_or_string, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=impl)
1.40
1.41 -def parseFile(filename, html=0, htmlencoding=None, impl=None):
1.42 +def parseFile(filename, html=0, htmlencoding=None, unfinished=0, impl=None):
1.43
1.44 """
1.45 - Parse the file having the given 'filename'. If the optional 'html' parameter
1.46 - is set to a true value, the content to be parsed will be treated as being
1.47 - HTML rather than XML. If the optional 'htmlencoding' is specified, HTML
1.48 - parsing will be performed with the document encoding assumed to be that
1.49 - specified.
1.50 + Parse the file having the given 'filename'. The optional parameters
1.51 + described below should be provided as keyword arguments.
1.52 +
1.53 + If the optional 'html' parameter is set to a true value, the content to be
1.54 + parsed will be treated as being HTML rather than XML. If the optional
1.55 + 'htmlencoding' is specified, HTML parsing will be performed with the
1.56 + document encoding assumed to that specified.
1.57 +
1.58 + If the optional 'unfinished' parameter is set to a true value, unfinished
1.59 + documents will be parsed, even though such documents may be missing content
1.60 + such as closing tags.
1.61
1.62 A document object is returned by this function.
1.63 """
1.64
1.65 impl = impl or default_impl
1.66 - return impl.adoptDocument(Node_parseFile(filename, html, htmlencoding))
1.67 + return impl.adoptDocument(Node_parseFile(filename, html=html, htmlencoding=htmlencoding, unfinished=unfinished))
1.68
1.69 -def parseString(s, html=0, htmlencoding=None, impl=None):
1.70 +def parseString(s, html=0, htmlencoding=None, unfinished=0, impl=None):
1.71
1.72 """
1.73 - Parse the content of the given string 's'. If the optional 'html' parameter
1.74 - is set to a true value, the content to be parsed will be treated as being
1.75 - HTML rather than XML. If the optional 'htmlencoding' is specified, HTML
1.76 - parsing will be performed with the document encoding assumed to be that
1.77 - specified.
1.78 + Parse the content of the given string 's'. The optional parameters described
1.79 + below should be provided as keyword arguments.
1.80 +
1.81 + If the optional 'html' parameter is set to a true value, the content to be
1.82 + parsed will be treated as being HTML rather than XML. If the optional
1.83 + 'htmlencoding' is specified, HTML parsing will be performed with the
1.84 + document encoding assumed to that specified.
1.85 +
1.86 + If the optional 'unfinished' parameter is set to a true value, unfinished
1.87 + documents will be parsed, even though such documents may be missing content
1.88 + such as closing tags.
1.89
1.90 A document object is returned by this function.
1.91 """
1.92
1.93 impl = impl or default_impl
1.94 - return impl.adoptDocument(Node_parseString(s, html, htmlencoding))
1.95 + return impl.adoptDocument(Node_parseString(s, html=html, htmlencoding=htmlencoding, unfinished=unfinished))
1.96
1.97 -def parseURI(uri, html=0, htmlencoding=None, impl=None):
1.98 +def parseURI(uri, html=0, htmlencoding=None, unfinished=0, impl=None):
1.99
1.100 """
1.101 - Parse the content found at the given 'uri'. If the optional 'html' parameter
1.102 - is set to a true value, the content to be parsed will be treated as being
1.103 - HTML rather than XML. If the optional 'htmlencoding' is specified, HTML
1.104 - parsing will be performed with the document encoding assumed to be that
1.105 - specified.
1.106 + Parse the content found at the given 'uri'. The optional parameters
1.107 + described below should be provided as keyword arguments.
1.108 +
1.109 + If the optional 'html' parameter is set to a true value, the content to be
1.110 + parsed will be treated as being HTML rather than XML. If the optional
1.111 + 'htmlencoding' is specified, HTML parsing will be performed with the
1.112 + document encoding assumed to that specified.
1.113 +
1.114 + If the optional 'unfinished' parameter is set to a true value, unfinished
1.115 + documents will be parsed, even though such documents may be missing content
1.116 + such as closing tags.
1.117
1.118 XML documents are retrieved using libxml2's own network capabilities; HTML
1.119 documents are retrieved using the urllib module provided by Python. To
1.120 @@ -611,12 +636,12 @@
1.121 if html:
1.122 f = urllib.urlopen(uri)
1.123 try:
1.124 - return parse(f, html, htmlencoding, impl)
1.125 + return parse(f, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=impl)
1.126 finally:
1.127 f.close()
1.128 else:
1.129 impl = impl or default_impl
1.130 - return impl.adoptDocument(Node_parseURI(uri, html, htmlencoding))
1.131 + return impl.adoptDocument(Node_parseURI(uri, html=html, htmlencoding=htmlencoding, unfinished=unfinished))
1.132
1.133 def toString(node, encoding=None, prettyprint=0):
1.134
2.1 --- a/libxml2dom/svg.py Sun Apr 08 00:00:25 2007 +0000
2.2 +++ b/libxml2dom/svg.py Sun Apr 08 00:01:29 2007 +0000
2.3 @@ -857,23 +857,23 @@
2.4 def createSVGDocument():
2.5 return default_impl.createSVGDocument()
2.6
2.7 -def parse(stream_or_string, html=0, htmlencoding=None, impl=None):
2.8 - doc = libxml2dom.parse(stream_or_string, html, htmlencoding, impl or default_impl)
2.9 +def parse(stream_or_string, html=0, htmlencoding=None, unfinished=0, impl=None):
2.10 + doc = libxml2dom.parse(stream_or_string, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl))
2.11 initialiseEvents(doc)
2.12 return doc
2.13
2.14 -def parseFile(filename, html=0, htmlencoding=None, impl=None):
2.15 - doc = libxml2dom.parseFile(filename, html, htmlencoding, impl or default_impl)
2.16 +def parseFile(filename, html=0, htmlencoding=None, unfinished=0, impl=None):
2.17 + doc = libxml2dom.parseFile(filename, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl))
2.18 initialiseEvents(doc)
2.19 return doc
2.20
2.21 -def parseString(s, html=0, htmlencoding=None, impl=None):
2.22 - doc = libxml2dom.parseString(s, html, htmlencoding, impl or default_impl)
2.23 +def parseString(s, html=0, htmlencoding=None, unfinished=0, impl=None):
2.24 + doc = libxml2dom.parseString(s, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl))
2.25 initialiseEvents(doc)
2.26 return doc
2.27
2.28 -def parseURI(uri, html=0, htmlencoding=None, impl=None):
2.29 - doc = libxml2dom.parseURI(uri, html, htmlencoding, impl or default_impl)
2.30 +def parseURI(uri, html=0, htmlencoding=None, unfinished=0, impl=None):
2.31 + doc = libxml2dom.parseURI(uri, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl))
2.32 initialiseEvents(doc)
2.33 return doc
2.34
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/libxml2dom/xmpp.py Sun Apr 08 00:01:29 2007 +0000
3.3 @@ -0,0 +1,479 @@
3.4 +#!/usr/bin/env python
3.5 +
3.6 +"""
3.7 +XMPP support using libxml2dom to capture stanzas as documents. The XMPP
3.8 +specification employs an "open" or unfinished document as the basis for
3.9 +communications between client and server - this presents problems for
3.10 +DOM-oriented libraries.
3.11 +
3.12 +Various Internet standards specifications exist for XMPP.
3.13 +See: http://www.xmpp.org/rfcs/rfc3920.html
3.14 +See: http://www.xmpp.org/rfcs/rfc3921.html
3.15 +
3.16 +Copyright (C) 2007 Paul Boddie <paul@boddie.org.uk>
3.17 +
3.18 +This library is free software; you can redistribute it and/or
3.19 +modify it under the terms of the GNU Lesser General Public
3.20 +License as published by the Free Software Foundation; either
3.21 +version 2.1 of the License, or (at your option) any later version.
3.22 +
3.23 +This library is distributed in the hope that it will be useful,
3.24 +but WITHOUT ANY WARRANTY; without even the implied warranty of
3.25 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3.26 +Lesser General Public License for more details.
3.27 +
3.28 +You should have received a copy of the GNU Lesser General Public
3.29 +License along with this library; if not, write to the Free Software
3.30 +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
3.31 +
3.32 +--------
3.33 +
3.34 +The process of connecting, authenticating, and so on is quite convoluted:
3.35 +
3.36 +s = libxml2dom.xmpp.Session(("localhost", 5222))
3.37 +d = s.connect("host")
3.38 +auth = s.createAuth() # provides access to the stanza
3.39 +auth.mechanism = "PLAIN" # choose a supported mechanism
3.40 +auth.setCredentials(jid, username, password) # for PLAIN authentication only
3.41 +d = s.send(auth) # hopefully a success response
3.42 +d = s.connect("host") # have to reconnect!
3.43 +iq = s.createIq() # make an 'iq' stanza
3.44 +iq.makeBind() # set up a binding operation
3.45 +d = s.send(iq) # hopefully a success response
3.46 +iq = s.createIq() # make an 'iq' stanza
3.47 +iq.makeSession() # set up a session
3.48 +d = s.send(iq) # hopefully a success response
3.49 +
3.50 +See tests/xmpp_test.py for more details.
3.51 +"""
3.52 +
3.53 +import libxml2dom
3.54 +from libxml2dom.macrolib import *
3.55 +from libxml2dom.macrolib import \
3.56 + createDocument as Node_createDocument
3.57 +import socket
3.58 +import select
3.59 +import base64 # for auth elements
3.60 +
3.61 +XMPP_BIND_NAMESPACE = "urn:ietf:params:xml:ns:xmpp-bind"
3.62 +XMPP_CLIENT_NAMESPACE = "jabber:client"
3.63 +XMPP_REGISTER_NAMESPACE = "jabber:iq:register"
3.64 +XMPP_SASL_NAMESPACE = "urn:ietf:params:xml:ns:xmpp-sasl"
3.65 +XMPP_SESSION_NAMESPACE = "urn:ietf:params:xml:ns:xmpp-session"
3.66 +XMPP_STREAMS_NAMESPACE = "http://etherx.jabber.org/streams"
3.67 +
3.68 +class XMPPImplementation(libxml2dom.Implementation):
3.69 +
3.70 + "Contains an XMPP-specific implementation."
3.71 +
3.72 + # Wrapping of documents.
3.73 +
3.74 + def adoptDocument(self, node):
3.75 + return XMPPDocument(node, self)
3.76 +
3.77 + # Factory functions.
3.78 +
3.79 + def get_node(self, _node, context_node):
3.80 +
3.81 + """
3.82 + Get a libxml2dom node for the given low-level '_node' and libxml2dom
3.83 + 'context_node'.
3.84 + """
3.85 +
3.86 + if Node_nodeType(_node) == context_node.ELEMENT_NODE:
3.87 +
3.88 + # Make special binding elements.
3.89 +
3.90 + if Node_namespaceURI(_node) == XMPP_BIND_NAMESPACE:
3.91 + if Node_localName(_node) == "bind":
3.92 + return XMPPBindElement(_node, self, context_node.ownerDocument)
3.93 +
3.94 + # Make special client elements.
3.95 +
3.96 + elif Node_namespaceURI(_node) == XMPP_CLIENT_NAMESPACE:
3.97 + if Node_localName(_node) == "iq":
3.98 + return XMPPIqElement(_node, self, context_node.ownerDocument)
3.99 + else:
3.100 + return XMPPClientElement(_node, self, context_node.ownerDocument)
3.101 +
3.102 + # Make special registration elements.
3.103 +
3.104 + elif Node_namespaceURI(_node) == XMPP_REGISTER_NAMESPACE:
3.105 + return XMPPRegisterElement(_node, self, context_node.ownerDocument)
3.106 +
3.107 + # Make special authentication elements.
3.108 +
3.109 + elif Node_namespaceURI(_node) == XMPP_SASL_NAMESPACE:
3.110 + if Node_localName(_node) == "auth":
3.111 + return XMPPAuthElement(_node, self, context_node.ownerDocument)
3.112 +
3.113 + # Make special stream elements.
3.114 +
3.115 + elif Node_namespaceURI(_node) == XMPP_STREAMS_NAMESPACE:
3.116 + if Node_localName(_node) == "stream":
3.117 + return XMPPStreamElement(_node, self, context_node.ownerDocument)
3.118 +
3.119 + # Otherwise, make generic XMPP elements.
3.120 +
3.121 + return XMPPElement(_node, self, context_node.ownerDocument)
3.122 +
3.123 + else:
3.124 + return libxml2dom.Implementation.get_node(self, _node, context_node)
3.125 +
3.126 + # Convenience functions.
3.127 +
3.128 + def createXMPPStanza(self, namespaceURI, localName):
3.129 +
3.130 + "Create a new XMPP stanza document (fragment)."
3.131 +
3.132 + return XMPPDocument(Node_createDocument(namespaceURI, localName, None), self).documentElement
3.133 +
3.134 +# Node classes.
3.135 +
3.136 +class XMPPNode(libxml2dom.Node):
3.137 +
3.138 + "Convenience modifications to nodes specific to libxml2dom.svg."
3.139 +
3.140 + def xpath(self, expr, variables=None, namespaces=None):
3.141 +
3.142 + """
3.143 + Evaluate the given 'expr' using the optional 'variables' and
3.144 + 'namespaces'. If not otherwise specified, the "stream" prefix will be
3.145 + bound to XMPP_STREAMS_NAMESPACE as defined in this module.
3.146 + """
3.147 +
3.148 + ns = {
3.149 + "bind" : XMPP_BIND_NAMESPACE,
3.150 + "client" : XMPP_CLIENT_NAMESPACE,
3.151 + "register" : XMPP_REGISTER_NAMESPACE,
3.152 + "sasl" : XMPP_SASL_NAMESPACE,
3.153 + "session" : XMPP_SESSION_NAMESPACE,
3.154 + "stream" : XMPP_STREAMS_NAMESPACE
3.155 + }
3.156 + ns.update(namespaces or {})
3.157 + return libxml2dom.Node.xpath(self, expr, variables, ns)
3.158 +
3.159 +class XMPPDocument(libxml2dom._Document, XMPPNode):
3.160 +
3.161 + "An XMPP document fragment."
3.162 +
3.163 + pass
3.164 +
3.165 +class XMPPAuthElement(XMPPNode):
3.166 +
3.167 + "An XMPP auth element."
3.168 +
3.169 + def _mechanism(self):
3.170 + return self.getAttribute("mechanism")
3.171 +
3.172 + def _setMechanism(self, value):
3.173 + self.setAttribute("mechanism", value)
3.174 +
3.175 + def _value(self):
3.176 + return self.textContent
3.177 +
3.178 + def setCredentials(self, jid, username, password):
3.179 +
3.180 + # NOTE: This is what xmpppy does. Beware of the leopard, with respect to
3.181 + # NOTE: the specifications.
3.182 +
3.183 + b64value = base64.encodestring("%s\x00%s\x00%s" % (jid, username, password))
3.184 + text = self.ownerDocument.createTextNode(b64value)
3.185 + self.appendChild(text)
3.186 +
3.187 +
3.188 + mechanism = property(_mechanism, _setMechanism)
3.189 + value = property(_value)
3.190 +
3.191 +class XMPPBindElement(XMPPNode):
3.192 +
3.193 + "An XMPP bind element."
3.194 +
3.195 + def _resource(self):
3.196 + return "".join(self.xpath("resource/text()"))
3.197 +
3.198 + def _setResource(self, value):
3.199 + resources = self.xpath("resource")
3.200 + for resource in resources:
3.201 + self.removeChild(resource)
3.202 + resource = self.ownerDocument.createElement("resource")
3.203 + self.appendChild(resource)
3.204 + text = self.ownerDocument.createTextNode(value)
3.205 + resource.appendChild(text)
3.206 +
3.207 + resource = property(_resource, _setResource)
3.208 +
3.209 +class XMPPClientElement(XMPPNode):
3.210 +
3.211 + "An XMPP client element."
3.212 +
3.213 + def _id(self):
3.214 + return self.getAttribute("id")
3.215 +
3.216 + def _setId(self, value):
3.217 + self.setAttribute("id", value)
3.218 +
3.219 + def _delId(self):
3.220 + self.removeAttribute("id")
3.221 +
3.222 + def _from(self):
3.223 + return self.getAttribute("from")
3.224 +
3.225 + def _setFrom(self, value):
3.226 + self.setAttribute("from", value)
3.227 +
3.228 + def _delFrom(self):
3.229 + self.removeAttribute("from")
3.230 +
3.231 + def _to(self):
3.232 + return self.getAttribute("to")
3.233 +
3.234 + def _setTo(self, value):
3.235 + self.setAttribute("to", value)
3.236 +
3.237 + def _delTo(self):
3.238 + self.removeAttribute("to")
3.239 +
3.240 + def _type(self):
3.241 + return self.getAttribute("type")
3.242 +
3.243 + def _setType(self, value):
3.244 + self.setAttribute("type", value)
3.245 +
3.246 + def _delType(self):
3.247 + self.removeAttribute("type")
3.248 +
3.249 + id = property(_id, _setId, _delId)
3.250 + from_ = property(_from, _setFrom, _delFrom)
3.251 + to = property(_to, _setTo, _delTo)
3.252 + type = property(_type, _setType, _delType)
3.253 +
3.254 +class XMPPIqElement(XMPPClientElement):
3.255 +
3.256 + """
3.257 + An XMPP 'iq' element used in instant messaging and registration.
3.258 + See: http://www.xmpp.org/rfcs/rfc3921.html
3.259 + See: http://www.xmpp.org/extensions/xep-0077.html
3.260 + """
3.261 +
3.262 + def _bind(self):
3.263 + return (self.xpath("bind:bind") or [None])[0]
3.264 +
3.265 + def _query(self):
3.266 + return (self.xpath("register:query") or [None])[0]
3.267 +
3.268 + def _session(self):
3.269 + return (self.xpath("session:session") or [None])[0]
3.270 +
3.271 + bind = property(_bind)
3.272 + query = property(_query)
3.273 + session = property(_session)
3.274 +
3.275 + def createBind(self):
3.276 + return self.ownerDocument.createElementNS(XMPP_BIND_NAMESPACE, "bind")
3.277 +
3.278 + def createQuery(self):
3.279 + return self.ownerDocument.createElementNS(XMPP_REGISTER_NAMESPACE, "query")
3.280 +
3.281 + def createSession(self):
3.282 + return self.ownerDocument.createElementNS(XMPP_SESSION_NAMESPACE, "session")
3.283 +
3.284 + def makeBind(self):
3.285 + bind = self.createBind()
3.286 + self.appendChild(bind)
3.287 + self.id = "bind1"
3.288 + self.type = "set"
3.289 +
3.290 + def makeQuery(self):
3.291 + query = self.createQuery()
3.292 + self.appendChild(query)
3.293 + self.id = "register1"
3.294 + self.type = "get"
3.295 +
3.296 + def makeRegistration(self):
3.297 + self.id = "register2"
3.298 + self.type = "set"
3.299 +
3.300 + def makeSession(self, host):
3.301 + session = self.createSession()
3.302 + self.appendChild(session)
3.303 + self.id = "session1"
3.304 + self.type = "set"
3.305 + self.to = host
3.306 +
3.307 +class XMPPRegisterElement(XMPPNode):
3.308 +
3.309 + """
3.310 + A registration element.
3.311 + See: http://www.xmpp.org/extensions/xep-0077.html
3.312 + """
3.313 +
3.314 + def __setitem__(self, name, value):
3.315 + element = self.ownerDocument.createElement(name)
3.316 + text = self.ownerDocument.createTextNode(value)
3.317 + element = self.appendChild(element)
3.318 + element.appendChild(text)
3.319 +
3.320 +class XMPPStreamElement(XMPPNode):
3.321 + pass
3.322 +
3.323 +class XMPPElement(XMPPNode):
3.324 + pass
3.325 +
3.326 +# Classes providing XMPP session support.
3.327 +
3.328 +class SessionTerminated(Exception):
3.329 + pass
3.330 +
3.331 +class Session:
3.332 +
3.333 + "An XMPP session."
3.334 +
3.335 + connect_str = """\
3.336 +<?xml version="1.0"?>
3.337 +<stream:stream to='%s' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>"""
3.338 +
3.339 + disconnect_str = """\
3.340 +</stream:stream>"""
3.341 +
3.342 + def __init__(self, address, timeout=500, bufsize=1024, encoding="utf-8"):
3.343 +
3.344 + """
3.345 + Initialise an XMPP session using the given 'address': a tuple of the
3.346 + form (hostname, port). The optional 'timeout' (in milliseconds) is used
3.347 + for polling the connection for new data, and the optional 'encoding'
3.348 + specifies the character encoding employed in the communications.
3.349 + """
3.350 +
3.351 + self.timeout = timeout
3.352 + self.bufsize = bufsize
3.353 + self.encoding = encoding
3.354 + self.poller = select.poll()
3.355 + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
3.356 + self.socket.setblocking(1)
3.357 + self.socket.connect(address)
3.358 + self.poller.register(self.socket.fileno(), select.POLLIN | select.POLLHUP | select.POLLNVAL | select.POLLERR)
3.359 +
3.360 + def _ready(self, timeout):
3.361 +
3.362 + """
3.363 + Return whether data can be read from the server, waiting as long as the
3.364 + specified 'timeout' (forever if set to None).
3.365 + """
3.366 +
3.367 + return self.poller.poll(timeout)
3.368 +
3.369 + def read(self):
3.370 +
3.371 + "Read as much as possible from the server."
3.372 +
3.373 + l = []
3.374 + fds = self._ready(self.timeout)
3.375 + try:
3.376 + while fds:
3.377 + for fd, status in fds:
3.378 + if fd == self.socket.fileno():
3.379 + if status & (select.POLLHUP | select.POLLNVAL | select.POLLERR):
3.380 + raise SessionTerminated
3.381 + if status & select.POLLIN:
3.382 + c = self.socket.recv(self.bufsize)
3.383 + if c:
3.384 + l.append(c)
3.385 + else:
3.386 + raise SessionTerminated
3.387 + fds = self.poller.poll(self.timeout)
3.388 + except SessionTerminated:
3.389 + pass
3.390 + return "".join(l)
3.391 +
3.392 + def write(self, s):
3.393 +
3.394 + "Write the plain string 's' to the server."
3.395 +
3.396 + self.socket.send(s)
3.397 +
3.398 + def send(self, stanza):
3.399 +
3.400 + """
3.401 + Send the 'stanza' to the server, returning a response stanza if an
3.402 + immediate response was provided, or None otherwise.
3.403 + """
3.404 +
3.405 + stanza.toStream(self, encoding=self.encoding)
3.406 + return self._receive()
3.407 +
3.408 + def _receive(self):
3.409 +
3.410 + """
3.411 + Return either a stanza or None, depending on whether anything was read
3.412 + from the server.
3.413 + """
3.414 +
3.415 + s = self.read()
3.416 + if s:
3.417 + return parseString(s).documentElement
3.418 + else:
3.419 + return None
3.420 +
3.421 + def receive(self, timeout):
3.422 +
3.423 + """
3.424 + Wait for an incoming stanza, or as long as 'timeout' (in milliseconds),
3.425 + returning either a stanza document (fragment) or None if nothing was
3.426 + received.
3.427 + """
3.428 +
3.429 + if self._ready(timeout):
3.430 + return self._receive()
3.431 + else:
3.432 + return None
3.433 +
3.434 + # Stanza creation.
3.435 +
3.436 + def createAuth(self):
3.437 + return self.createStanza(XMPP_SASL_NAMESPACE, "auth")
3.438 +
3.439 + def createIq(self):
3.440 + return self.createStanza(XMPP_CLIENT_NAMESPACE, "iq")
3.441 +
3.442 + def createMessage(self):
3.443 + return self.createStanza(XMPP_CLIENT_NAMESPACE, "message")
3.444 +
3.445 + def createStanza(self, namespaceURI, localName):
3.446 + return createXMPPStanza(namespaceURI, localName)
3.447 +
3.448 + # High-level methods.
3.449 +
3.450 + def connect(self, host):
3.451 +
3.452 + # NOTE: Nasty sending of the raw text because it involves only a start
3.453 + # NOTE: tag.
3.454 +
3.455 + self.write(self.connect_str % host)
3.456 + return parseString(self.read(), unfinished=1).documentElement
3.457 +
3.458 +# Utility functions.
3.459 +
3.460 +createDocument = libxml2dom.createDocument
3.461 +createDocumentType = libxml2dom.createDocumentType
3.462 +
3.463 +def createXMPPStanza(namespaceURI, localName):
3.464 + return default_impl.createXMPPStanza(namespaceURI, localName)
3.465 +
3.466 +def parse(stream_or_string, html=0, htmlencoding=None, unfinished=0, impl=None):
3.467 + return libxml2dom.parse(stream_or_string, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl))
3.468 +
3.469 +def parseFile(filename, html=0, htmlencoding=None, unfinished=0, impl=None):
3.470 + return libxml2dom.parseFile(filename, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl))
3.471 +
3.472 +def parseString(s, html=0, htmlencoding=None, unfinished=0, impl=None):
3.473 + return libxml2dom.parseString(s, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl))
3.474 +
3.475 +def parseURI(uri, html=0, htmlencoding=None, unfinished=0, impl=None):
3.476 + return libxml2dom.parseURI(uri, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl))
3.477 +
3.478 +# Single instance of the implementation.
3.479 +
3.480 +default_impl = XMPPImplementation()
3.481 +
3.482 +# vim: tabstop=4 expandtab shiftwidth=4