The scheduler class is now capable with dealing with tasks which remove
themselves from the scheduler during execution.
Additionally, some optimizations were applied by use of iterators and
some functions better suited for the purpose.
Please peer-review, all tests pass.
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().