def test_decode(self): """Tests the decode function.""" data = ( ('\xf8\x01\xfc\x03foo', '<foo />'), ('\xf8\x03\x01\x38\x8a', '<stream:stream from="s.whatsapp.net">'), ('\xf8\x08]\xa0\xfa\xfc\x0b12345678912\x8a\xa2\x1bC\xfc\x0c' + '1343064803-1\xf8\x02\xf8\x04\xba\xbdO\xf8\x01\xf8\x01\x8c' + '\xf8\x02\x16\xfc\x04Okay', '<message to="*****@*****.**" type="chat" ' + 'id="1343064803-1"><x xmlns="jabber:x:event"><server /></x>' + '<body>Okay</body></message>') ) for o, r in data: d = funxmpp.decode(o) self.assertEqual(d, r, "Encoding incorrect:\n%s\n%s" % (repr(d), repr(r)))
def test_both(self): """Sees if a encode followed by a decode results in the same data.""" data = ['<foo x="y"><poke name="stuff" /><another thing="yay" />' + '<body>bar</body></foo>', '<message from="*****@*****.**" ' + 'id="1339831077-7" ' + 'type="chat" ' + 't="1339848755">' + '<notify xmlns="urn:xmpp:whatsapp" ' + 'name="Koen" />' + '<request xmlns="urn:xmpp:receipts" />' + '<body>Hello</body>' + '</message>', '<iq from="*****@*****.**" id="1" type="error">' + '<error code="404" type="cancel">' + '<item-not-found ' + 'xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />' + '</error></iq>'] for t in data: self.assertEqual(t, funxmpp.decode(funxmpp.encode(t)))
def recv_and_handle(self, return_single=False, parse_buffer_only=False): """Receives some data from the server and then tries to parse as much messages in the buffer as possible. The receiving part of this function will block until there is data to be read. Any received data is appended to the current buffer, and then we try to extract as many messages from the buffer as possible. For each parsed message, the corresponding handler is called. It is possible to circumvent the standard behaviour in two ways. You probably never need to to that, it is only used internally in special situations. The return_single flag circumvents the handler part of the the function. Any found message is immediately returned. If no messages were found, None is returned. The parse_buffer_only argument specifies whether the socket should receive new data from the server. This can be usefull after a call with return_single enabled, to handle the remaining messages in the buffer.""" if not self.is_connected: raise Exception("Not connected.") if not parse_buffer_only: r = self.socket.recv(1024) if not r: self.disconnect() return self.buffer += r # Smallest message possible has a length of 5 (2 for length, 1 for f8, # 1 for f8 lenth, 1 for f8 tagname) while len(self.buffer) >= 5: msglen = struct.unpack('!H', self.buffer[:2])[0] if len(self.buffer) - 2 < msglen: return msg = self.buffer[2:msglen+2] self.buffer = self.buffer[msglen+2:] if len(msg) == 0: print "BUFCRASH:", msglen, repr(self.buffer) self.buf = '' return try: parsed = funxmpp.decode(msg) print ' < ', parsed except Exception as e: print 'Crash in funxmpp.decode', repr(msg), e # Stream start needs some special care if parsed.split(' ')[0] == '<stream:stream': parsed = parsed[:-1] + ' />' # Define the stream prefix namespace thing when needed if parsed.startswith('<stream:'): parsed = re.sub(r'^<stream:([^> ]*)', r'<stream:\1 xmlns:stream="' + 'http://etherx.jabber.org/streams"', parsed) xml = ET.fromstring(parsed) if return_single: return xml self._call_handler(xml)