Resolved by always normalizing JIDs to bare form, regardless of if they
are JID objects or strings.
Also simplified related code to prefer use of JID objects instead of
strings so they don't need to be parsed multiple times.
Using the special language value '*' will return a dictionary of all
such elements keyed by language.
>>> msg = Message()
>>> msg['body'] = 'Hi!'
>>> msg['body|sv'] = 'Hej!'
>>> print(msg)
'<message xmlns="jabber:client">
<body>Hi!</body>
<body xml:lang="sv">Hej!</body>
</message>'
>>> print(msg['body|*'])
OrderedDict(
('', 'Hi!'),
('sv', 'Hej!'))
Remaining items:
- Stanza path matching does not support language specifiers for normal
interfaces, only for plugins.
Certificate host names are now matched (using DNS, SRV, XMPPAddr, and
Common Name), along with expiration check.
Scheduled event to reset the stream once the server's cert expires.
Handle invalid cert trust chains gracefully now.
All event handlers which call disconnect() MUST be registered using
`add_event_handler(..., threaded=True)` in order to prevent temporarily
deadlocking until a timeout occurs.
This is required because disconnect() waits for the main threads to
exit before returning, including the event processing thread. Since
handlers registered without `threaded=True` run in the event processing
thread, the disconnect() call will deadlock.
If calling disconnect() from a non-threaded event handler, deadlock can
happen as disconnect() is waiting for threads to close, but the event
runner is blocked by a handler waiting for disconnect() to return.
It is best to specify threaded=True for event handlers which may call
disconnect().
- Add option for disconnecting without sending </stream>:
self.disconnect(send_close=False)
- Optionally distinguish between session_end and disconnected based
on if </stream> was sent.
self.end_session_on_disconnect = False
The set of bool_interfaces provides default behaviour for
checking/setting the presence of empty subelements.
The prime example of this would be:
bool_interfaces = set(['required'])
This would mean that ``stanza['required']`` would return ``True`` for:
<stanza>
<required />
</stanza>
and ``False`` for:
<stanza />
Likewise, assigning ``stanza['required'] = True`` would add an empty
``<required />`` element, and setting it to ``False`` would remove
such an element if it exists.