diff options
Diffstat (limited to 'sleekxmpp/basexmpp.py')
-rw-r--r-- | sleekxmpp/basexmpp.py | 186 |
1 files changed, 91 insertions, 95 deletions
diff --git a/sleekxmpp/basexmpp.py b/sleekxmpp/basexmpp.py index 3992a4f9..91b419ba 100644 --- a/sleekxmpp/basexmpp.py +++ b/sleekxmpp/basexmpp.py @@ -15,6 +15,7 @@ import logging import sleekxmpp from sleekxmpp import plugins +import sleekxmpp.roster as roster from sleekxmpp.stanza import Message, Presence, Iq, Error, StreamError from sleekxmpp.stanza.roster import Roster from sleekxmpp.stanza.nick import Nick @@ -78,7 +79,7 @@ class BaseXMPP(XMLStream): send_presence_subscribe -- Send a subscription request. """ - def __init__(self, default_ns='jabber:client'): + def __init__(self, jid='', default_ns='jabber:client'): """ Adapt an XML stream for use with XMPP. @@ -93,12 +94,16 @@ class BaseXMPP(XMLStream): self.default_ns = default_ns self.stream_ns = 'http://etherx.jabber.org/streams' - self.boundjid = JID("") + self.boundjid = JID(jid) self.plugin = {} self.plugin_config = {} self.plugin_whitelist = [] - self.roster = {} + + self.roster = roster.Roster(self) + self.roster.add(self.boundjid.bare) + self.client_roster = self.roster[self.boundjid.bare] + self.is_component = False self.auto_authorize = True self.auto_subscribe = True @@ -119,10 +124,30 @@ class BaseXMPP(XMLStream): MatchXPath("{%s}error" % self.stream_ns), self._handle_stream_error)) - self.add_event_handler('presence_subscribe', - self._handle_subscribe) self.add_event_handler('disconnected', self._handle_disconnected) + self.add_event_handler('presence_available', + self._handle_available) + self.add_event_handler('presence_dnd', + self._handle_available) + self.add_event_handler('presence_xa', + self._handle_available) + self.add_event_handler('presence_chat', + self._handle_available) + self.add_event_handler('presence_away', + self._handle_available) + self.add_event_handler('presence_unavailable', + self._handle_unavailable) + self.add_event_handler('presence_subscribe', + self._handle_subscribe) + self.add_event_handler('presence_subscribed', + self._handle_subscribed) + self.add_event_handler('presence_unsubscribe', + self._handle_unsubscribe) + self.add_event_handler('presence_unsubscribed', + self._handle_unsubscribed) + self.add_event_handler('roster_subscription_request', + self._handle_new_subscription) # Set up the XML stream with XMPP's root stanzas. self.register_stanza(Message) @@ -568,7 +593,7 @@ class BaseXMPP(XMLStream): def _handle_disconnected(self, event): """When disconnected, reset the roster""" - self.roster = {} + self.roster.reset() def _handle_stream_error(self, error): self.event('stream_error', error) @@ -577,12 +602,72 @@ class BaseXMPP(XMLStream): """Process incoming message stanzas.""" 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_unavailable(self, presence): + pto = presence['to'].bare + pfrom = presence['from'].bare + self.roster[pto][pfrom].handle_unavailable(presence) + + def _handle_new_subscription(self, stanza): + """ + Attempt to automatically handle subscription requests. + + Subscriptions will be approved if the request is from + a whitelisted JID, of self.auto_authorize is True. They + will be rejected if self.auto_authorize is False. Setting + self.auto_authorize to None will disable automatic + subscription handling (except for whitelisted JIDs). + + If a subscription is accepted, a request for a mutual + subscription will be sent if self.auto_subscribe is True. + """ + roster = self.roster[stanza['to'].bare] + item = self.roster[stanza['to'].bare][stanza['from'].bare] + if item['whitelisted']: + item.authorize() + elif roster.auto_authorize: + item.authorize() + if roster.auto_subscribe: + item.subscribe() + 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_presence(self, presence): """ Process incoming presence stanzas. Update the roster with presence information. """ + logging.debug(presence['type']) self.event("presence_%s" % presence['type'], presence) # Check for changes in subscription state. @@ -594,96 +679,7 @@ class BaseXMPP(XMLStream): not presence['type'] in presence.showtypes: return - # Strip the information from the stanza. - jid = presence['from'].bare - resource = presence['from'].resource - show = presence['type'] - status = presence['status'] - priority = presence['priority'] - - was_offline = False - got_online = False - old_roster = self.roster.get(jid, {}).get(resource, {}) - - # Create a new roster entry if needed. - if not jid in self.roster: - self.roster[jid] = {'groups': [], - 'name': '', - 'subscription': 'none', - 'presence': {}, - 'in_roster': False} - - # Alias to simplify some references. - connections = self.roster[jid].get('presence', {}) - - # Determine if the user has just come online. - if not resource in connections: - if show == 'available' or show in presence.showtypes: - got_online = True - was_offline = True - connections[resource] = {} - - if connections[resource].get('show', 'unavailable') == 'unavailable': - was_offline = True - - # Update the roster's state for this JID's resource. - connections[resource] = {'show': show, - 'status': status, - 'priority': priority} - - name = self.roster[jid].get('name', '') - - # Remove unneeded state information after a resource - # disconnects. Determine if this was the last connection - # for the JID. - if show == 'unavailable': - log.debug("%s %s got offline" % (jid, resource)) - del connections[resource] - - if not connections and not self.roster[jid]['in_roster']: - del self.roster[jid] - if not was_offline: - self.event("got_offline", presence) - else: - return False - - name = '(%s) ' % name if name else '' - - # Presence state has changed. self.event("changed_status", presence) - if got_online: - self.event("got_online", presence) - log.debug("STATUS: %s%s/%s[%s]: %s" % (name, jid, resource, - show, status)) - - def _handle_subscribe(self, presence): - """ - Automatically managage subscription requests. - - Subscription behavior is controlled by the settings - self.auto_authorize and self.auto_subscribe. - - auto_auth auto_sub Result: - True True Create bi-directional subsriptions. - True False Create only directed subscriptions. - False * Decline all subscriptions. - None * Disable automatic handling and use - a custom handler. - """ - presence.reply() - presence['to'] = presence['to'].bare - - # We are using trinary logic, so conditions have to be - # more explicit than usual. - if self.auto_authorize == True: - presence['type'] = 'subscribed' - presence.send() - if self.auto_subscribe: - presence['type'] = 'subscribe' - presence.send() - elif self.auto_authorize == False: - presence['type'] = 'unsubscribed' - presence.send() # Restore the old, lowercased name for backwards compatibility. basexmpp = BaseXMPP |