1.1 --- a/libxml2dom/xmpp.py Sun Jan 18 19:23:20 2009 +0100
1.2 +++ b/libxml2dom/xmpp.py Thu Jul 09 20:48:31 2009 +0200
1.3 @@ -34,14 +34,16 @@
1.4 auth = s.createAuth() # provides access to the stanza
1.5 auth.mechanism = "PLAIN" # choose a supported mechanism
1.6 auth.setCredentials(jid, username, password) # for PLAIN authentication only
1.7 -d = s.send(auth) # hopefully a success response
1.8 +s.send(auth) # send the authentication request
1.9 +d = s.receive() # hopefully a success response
1.10 d = s.connect("host") # have to reconnect!
1.11 iq = s.createIq() # make an 'iq' stanza
1.12 iq.makeBind() # set up a binding operation
1.13 -d = s.send(iq) # hopefully a success response
1.14 +s.send(iq) # send the binding request
1.15 +d = s.receive() # hopefully a success response
1.16 iq = s.createIq() # make an 'iq' stanza
1.17 iq.makeSession() # set up a session
1.18 -d = s.send(iq) # hopefully a success response
1.19 +s.send(iq) # send the session request
1.20
1.21 See tests/xmpp_test.py for more details.
1.22 """
1.23 @@ -129,6 +131,8 @@
1.24 elif Node_namespaceURI(_node) == XMPP_SASL_NAMESPACE:
1.25 if Node_localName(_node) == "auth":
1.26 return XMPPAuthElement(_node, self, context_node.ownerDocument)
1.27 + elif Node_localName(_node) == "failure":
1.28 + return XMPPFailureElement(_node, self, context_node.ownerDocument)
1.29
1.30 # Make special stream elements.
1.31
1.32 @@ -267,6 +271,21 @@
1.33 to = property(_to, _setTo, _delTo)
1.34 type = property(_type, _setType, _delType)
1.35
1.36 +class XMPPFailureElement(XMPPElement):
1.37 +
1.38 + "An XMPP failure element."
1.39 +
1.40 + def _reason(self):
1.41 + return self.xpath("*")[0].localName
1.42 +
1.43 + def _setReason(self, reason_text):
1.44 + for reason in self.xpath("*"):
1.45 + self.removeChild(reason)
1.46 + element = self.ownerDocument.createElement(reason_text)
1.47 + self.appendChild(element)
1.48 +
1.49 + reason = property(_reason, _setReason)
1.50 +
1.51 class XMPPMessageElement(XMPPClientElement):
1.52
1.53 "An XMPP message element."
1.54 @@ -409,16 +428,14 @@
1.55 disconnect_str = """\
1.56 </stream:stream>"""
1.57
1.58 - def __init__(self, address, timeout=500, bufsize=1024, encoding="utf-8"):
1.59 + def __init__(self, address, bufsize=1024, encoding="utf-8"):
1.60
1.61 """
1.62 Initialise an XMPP session using the given 'address': a tuple of the
1.63 - form (hostname, port). The optional 'timeout' (in milliseconds) is used
1.64 - for polling the connection for new data, and the optional 'encoding'
1.65 - specifies the character encoding employed in the communications.
1.66 + form (hostname, port). The optional 'encoding' specifies the character
1.67 + encoding employed in the communications.
1.68 """
1.69
1.70 - self.timeout = timeout
1.71 self.bufsize = bufsize
1.72 self.encoding = encoding
1.73 self.poller = select.poll()
1.74 @@ -427,41 +444,29 @@
1.75 self.socket.connect(address)
1.76 self.poller.register(self.socket.fileno(), select.POLLIN | select.POLLHUP | select.POLLNVAL | select.POLLERR)
1.77
1.78 - def _ready(self, timeout):
1.79 + def read(self, timeout=None):
1.80
1.81 """
1.82 - Return whether data can be read from the server, waiting as long as the
1.83 - specified 'timeout' (forever if set to None).
1.84 + Read as much as possible from the server, waiting as long as the
1.85 + specified 'timeout' (forever if set to None) for a message to arrive.
1.86 """
1.87
1.88 - return self.poller.poll(timeout)
1.89 -
1.90 - def read(self):
1.91 -
1.92 - "Read as much as possible from the server."
1.93 -
1.94 context = Parser_push()
1.95 Parser_configure(context)
1.96
1.97 have_read = 0
1.98 - fds = self._ready(self.timeout)
1.99 - try:
1.100 - while fds:
1.101 - for fd, status in fds:
1.102 - if fd == self.socket.fileno():
1.103 - if status & (select.POLLHUP | select.POLLNVAL | select.POLLERR):
1.104 - raise SessionTerminated
1.105 - if status & select.POLLIN:
1.106 - have_read = 1
1.107 - c = self.socket.recv(self.bufsize)
1.108 - Parser_feed(context, c)
1.109 - if Parser_well_formed(context):
1.110 - return default_impl.adoptDocument(Parser_document(context))
1.111 + fds = self.poller.poll(timeout)
1.112
1.113 - fds = self.poller.poll(self.timeout)
1.114 -
1.115 - except SessionTerminated:
1.116 - pass
1.117 + for fd, status in fds:
1.118 + if fd == self.socket.fileno():
1.119 + if status & (select.POLLHUP | select.POLLNVAL | select.POLLERR):
1.120 + raise SessionTerminated
1.121 + if status & select.POLLIN:
1.122 + have_read = 1
1.123 + c = self.socket.recv(self.bufsize)
1.124 + Parser_feed(context, c)
1.125 + if Parser_well_formed(context):
1.126 + return default_impl.adoptDocument(Parser_document(context))
1.127
1.128 if have_read:
1.129 return default_impl.adoptDocument(Parser_document(context))
1.130 @@ -477,22 +482,10 @@
1.131 def send(self, stanza):
1.132
1.133 """
1.134 - Send the 'stanza' to the server, returning a response stanza if an
1.135 - immediate response was provided, or None otherwise.
1.136 + Send the 'stanza' to the server.
1.137 """
1.138
1.139 stanza.toStream(self, encoding=self.encoding)
1.140 - return self._receive()
1.141 -
1.142 - def _receive(self):
1.143 -
1.144 - "Return a stanza for data read from the server."
1.145 -
1.146 - doc = self.read()
1.147 - if doc is None:
1.148 - return doc
1.149 - else:
1.150 - return doc.documentElement
1.151
1.152 def receive(self, timeout=None):
1.153
1.154 @@ -502,10 +495,11 @@
1.155 stanza document (fragment) or None if nothing was received.
1.156 """
1.157
1.158 - if self._ready(timeout):
1.159 - return self._receive()
1.160 + doc = self.read(timeout)
1.161 + if doc is None:
1.162 + return None
1.163 else:
1.164 - return None
1.165 + return doc.documentElement
1.166
1.167 # Stanza creation.
1.168
1.169 @@ -532,7 +526,14 @@
1.170 # NOTE: tag.
1.171
1.172 self.write(self.connect_str % host)
1.173 - return self._receive()
1.174 + return self.receive()
1.175 +
1.176 + def disconnect(self):
1.177 +
1.178 + # NOTE: Nasty sending of the raw text because it involves only an end
1.179 + # NOTE: tag.
1.180 +
1.181 + self.write(self.disconnect_str)
1.182
1.183 # Utility functions.
1.184