diff options
Diffstat (limited to 'sleekxmpp/basexmpp.py')
-rw-r--r-- | sleekxmpp/basexmpp.py | 133 |
1 files changed, 75 insertions, 58 deletions
diff --git a/sleekxmpp/basexmpp.py b/sleekxmpp/basexmpp.py index da5b3e41..8cd61b63 100644 --- a/sleekxmpp/basexmpp.py +++ b/sleekxmpp/basexmpp.py @@ -18,15 +18,13 @@ import sys import logging import threading -import sleekxmpp -from sleekxmpp import plugins, features, roster +from sleekxmpp import plugins, roster, stanza from sleekxmpp.api import APIRegistry from sleekxmpp.exceptions import IqError, IqTimeout from sleekxmpp.stanza import Message, Presence, Iq, StreamError from sleekxmpp.stanza.roster import Roster from sleekxmpp.stanza.nick import Nick -from sleekxmpp.stanza.htmlim import HTMLIM from sleekxmpp.xmlstream import XMLStream, JID from sleekxmpp.xmlstream import ET, register_stanza_plugin @@ -34,8 +32,7 @@ from sleekxmpp.xmlstream.matcher import MatchXPath from sleekxmpp.xmlstream.handler import Callback from sleekxmpp.xmlstream.stanzabase import XML_NS -from sleekxmpp.features import * -from sleekxmpp.plugins import PluginManager, register_plugin, load_plugin +from sleekxmpp.plugins import PluginManager, load_plugin log = logging.getLogger(__name__) @@ -43,8 +40,8 @@ log = logging.getLogger(__name__) # In order to make sure that Unicode is handled properly # in Python 2.x, reset the default encoding. if sys.version_info < (3, 0): - reload(sys) - sys.setdefaultencoding('utf8') + from sleekxmpp.util.misc_ops import setdefaultencoding + setdefaultencoding('utf8') class BaseXMPP(XMLStream): @@ -68,10 +65,20 @@ class BaseXMPP(XMLStream): #: An identifier for the stream as given by the server. self.stream_id = None - #: The JabberID (JID) used by this connection. - self.boundjid = JID(jid) + #: The JabberID (JID) requested for this connection. + self.requested_jid = JID(jid, cache_lock=True) + + #: The JabberID (JID) used by this connection, + #: as set after session binding. This may even be a + #: different bare JID than what was requested. + self.boundjid = JID(jid, cache_lock=True) self._expected_server_name = self.boundjid.host + self._redirect_attempts = 0 + + #: The maximum number of consecutive see-other-host + #: redirections that will be followed before quitting. + self.max_redirects = 5 self.session_bind_event = threading.Event() @@ -91,19 +98,30 @@ class BaseXMPP(XMLStream): #: owner JIDs, as in the case for components. For clients #: which only have a single JID, see :attr:`client_roster`. self.roster = roster.Roster(self) - self.roster.add(self.boundjid.bare) + self.roster.add(self.boundjid) #: The single roster for the bound JID. This is the #: equivalent of:: #: #: self.roster[self.boundjid.bare] - self.client_roster = self.roster[self.boundjid.bare] + self.client_roster = self.roster[self.boundjid] #: The distinction between clients and components can be #: important, primarily for choosing how to handle the #: ``'to'`` and ``'from'`` JIDs of stanzas. self.is_component = False + #: Messages may optionally be tagged with ID values. Setting + #: :attr:`use_message_ids` to `True` will assign all outgoing + #: messages an ID. Some plugin features require enabling + #: this option. + self.use_message_ids = False + + #: Presence updates may optionally be tagged with ID values. + #: Setting :attr:`use_message_ids` to `True` will assign all + #: outgoing messages an ID. + self.use_presence_ids = False + #: The API registry is a way to process callbacks based on #: JID+node combinations. Each callback in the registry is #: marked with: @@ -127,7 +145,7 @@ class BaseXMPP(XMLStream): #: A reference to :mod:`sleekxmpp.stanza` to make accessing #: stanza classes easier. - self.stanza = sleekxmpp.stanza + self.stanza = stanza self.register_handler( Callback('IM', @@ -144,6 +162,8 @@ class BaseXMPP(XMLStream): MatchXPath("{%s}error" % self.stream_ns), self._handle_stream_error)) + self.add_event_handler('session_start', + self._handle_session_start) self.add_event_handler('disconnected', self._handle_disconnected) self.add_event_handler('presence_available', @@ -178,7 +198,6 @@ class BaseXMPP(XMLStream): # Initialize a few default stanza plugins. register_stanza_plugin(Iq, Roster) register_stanza_plugin(Message, Nick) - register_stanza_plugin(Message, HTMLIM) def start_stream_handler(self, xml): """Save the stream ID once the streams have been established. @@ -189,6 +208,10 @@ class BaseXMPP(XMLStream): self.stream_version = xml.get('version', '') self.peer_default_lang = xml.get('{%s}lang' % XML_NS, None) + if not self.is_component and not self.stream_version: + log.warning('Legacy XMPP 0.9 protocol detected.') + self.event('legacy_protocol') + def process(self, *args, **kwargs): """Initialize plugins and begin processing the XML stream. @@ -214,13 +237,6 @@ class BaseXMPP(XMLStream): - The send queue processor - The scheduler """ - if 'xep_0115' in self.plugin: - name = 'xep_0115' - if not hasattr(self.plugin[name], 'post_inited'): - if hasattr(self.plugin[name], 'post_init'): - self.plugin[name].post_init() - self.plugin[name].post_inited = True - for name in self.plugin: if not hasattr(self.plugin[name], 'post_inited'): if hasattr(self.plugin[name], 'post_init'): @@ -228,7 +244,7 @@ class BaseXMPP(XMLStream): self.plugin[name].post_inited = True return XMLStream.process(self, *args, **kwargs) - def register_plugin(self, plugin, pconfig={}, module=None): + def register_plugin(self, plugin, pconfig=None, module=None): """Register and configure a plugin for use in this stream. :param plugin: The name of the plugin class. Plugin names must @@ -591,7 +607,7 @@ class BaseXMPP(XMLStream): @resource.setter def resource(self, value): - log.warning("fulljid property deprecated. Use boundjid.full") + log.warning("fulljid property deprecated. Use boundjid.resource") self.boundjid.resource = value @property @@ -645,7 +661,7 @@ class BaseXMPP(XMLStream): def set_jid(self, jid): """Rip a JID apart and claim it as our own.""" log.debug("setting jid to %s", jid) - self.boundjid.full = jid + self.boundjid = JID(jid, cache_lock=True) def getjidresource(self, fulljid): if '/' in fulljid: @@ -656,6 +672,10 @@ class BaseXMPP(XMLStream): def getjidbare(self, fulljid): return fulljid.split('/', 1)[0] + def _handle_session_start(self, event): + """Reset redirection attempt count.""" + self._redirect_attempts = 0 + def _handle_disconnected(self, event): """When disconnected, reset the roster""" self.roster.reset() @@ -666,6 +686,15 @@ class BaseXMPP(XMLStream): if error['condition'] == 'see-other-host': other_host = error['see_other_host'] + if not other_host: + log.warning("No other host specified.") + return + + if self._redirect_attempts > self.max_redirects: + log.error("Exceeded maximum number of redirection attempts.") + return + + self._redirect_attempts += 1 host = other_host port = 5222 @@ -691,17 +720,13 @@ class BaseXMPP(XMLStream): msg['to'] = self.boundjid self.event('message', msg) - def _handle_available(self, presence): - pto = presence['to'].bare - pfrom = presence['from'].bare - self.roster[pto][pfrom].handle_available(presence) + def _handle_available(self, pres): + self.roster[pres['to']][pres['from']].handle_available(pres) - def _handle_unavailable(self, presence): - pto = presence['to'].bare - pfrom = presence['from'].bare - self.roster[pto][pfrom].handle_unavailable(presence) + def _handle_unavailable(self, pres): + self.roster[pres['to']][pres['from']].handle_unavailable(pres) - def _handle_new_subscription(self, stanza): + def _handle_new_subscription(self, pres): """Attempt to automatically handle subscription requests. Subscriptions will be approved if the request is from @@ -713,10 +738,12 @@ class BaseXMPP(XMLStream): If a subscription is accepted, a request for a mutual subscription will be sent if :attr:`auto_subscribe` is ``True``. """ - roster = self.roster[stanza['to'].bare] - item = self.roster[stanza['to'].bare][stanza['from'].bare] + roster = self.roster[pres['to']] + item = self.roster[pres['to']][pres['from']] if item['whitelisted']: item.authorize() + if roster.auto_subscribe: + item.subscribe() elif roster.auto_authorize: item.authorize() if roster.auto_subscribe: @@ -724,30 +751,20 @@ class BaseXMPP(XMLStream): elif roster.auto_authorize == False: item.unauthorize() - def _handle_removed_subscription(self, presence): - pto = presence['to'].bare - pfrom = presence['from'].bare - self.roster[pto][pfrom].unauthorize() - - def _handle_subscribe(self, presence): - pto = presence['to'].bare - pfrom = presence['from'].bare - self.roster[pto][pfrom].handle_subscribe(presence) - - def _handle_subscribed(self, presence): - pto = presence['to'].bare - pfrom = presence['from'].bare - self.roster[pto][pfrom].handle_subscribed(presence) - - def _handle_unsubscribe(self, presence): - pto = presence['to'].bare - pfrom = presence['from'].bare - self.roster[pto][pfrom].handle_unsubscribe(presence) - - def _handle_unsubscribed(self, presence): - pto = presence['to'].bare - pfrom = presence['from'].bare - self.roster[pto][pfrom].handle_unsubscribed(presence) + def _handle_removed_subscription(self, pres): + self.roster[pres['to']][pres['from']].handle_unauthorize(pres) + + def _handle_subscribe(self, pres): + self.roster[pres['to']][pres['from']].handle_subscribe(pres) + + def _handle_subscribed(self, pres): + self.roster[pres['to']][pres['from']].handle_subscribed(pres) + + def _handle_unsubscribe(self, pres): + self.roster[pres['to']][pres['from']].handle_unsubscribe(pres) + + def _handle_unsubscribed(self, pres): + self.roster[pres['to']][pres['from']].handle_unsubscribed(pres) def _handle_presence(self, presence): """Process incoming presence stanzas. |