source: ralphm-patches/c2s_stanza_handlers.patch @ 82:276bc45eb40b

Last change on this file since 82:276bc45eb40b was 82:276bc45eb40b, checked in by Ralph Meijer <ralphm@…>, 4 years ago

Move presence probe to session manager.

File size: 22.5 KB
  • wokkel/client.py

    # HG changeset patch
    # Parent 70ce9e97aa58780ac7f75a177fe8c0d2aaf1bfc6
    # Parent  92b3f7089a61a8998999b67562917675732f8a4e
    Add c2s protocol handlers for iq, message and presence stanzas.
    
    TODO:
     * Add tests.
     * Add docstrings.
     * Save last unavailable presence for future probes.
    
    diff --git a/wokkel/client.py b/wokkel/client.py
    a b  
    2020from twisted.words.protocols.jabber import client, error, sasl, xmlstream
    2121from twisted.words.xish import domish
    2222
    23 from wokkel import generic
     23from wokkel import generic, xmppim
    2424from wokkel.iwokkel import IUserSession
    2525from wokkel.subprotocols import ServerStreamManager
    2626from wokkel.subprotocols import StreamManager
     
    548548        return [
    549549            generic.StanzaForwarder(),
    550550            RecipientAddressStamper(),
     551            xmppim.UserSessionPresenceProtocol(),
     552            xmppim.UserRosterProtocol(),
    551553            ]
  • wokkel/test/test_xmppim.py

    diff --git a/wokkel/test/test_xmppim.py b/wokkel/test/test_xmppim.py
    a b  
    55Tests for L{wokkel.xmppim}.
    66"""
    77
    8 from zope.interface import verify
     8from zope.interface import implementer, verify
    99
    1010from twisted.cred import checkers, error as ecred
    1111from twisted.cred.portal import IRealm
     
    1717from twisted.words.xish import domish, utility
    1818
    1919from wokkel import ewokkel, component, xmppim
    20 from wokkel.generic import ErrorStanza, parseXml
     20from wokkel.generic import ErrorStanza, Stanza, parseXml
    2121from wokkel.test.helpers import TestableRequestHandlerMixin, XmlStreamStub
    2222from wokkel.subprotocols import IQHandlerMixin
    2323
     
    20312031        d = self.sessionManager.probePresence(user)
    20322032        d.addCallback(cb)
    20332033        return d
     2034
     2035
     2036
     2037class AccountIQHandlerTest(unittest.TestCase):
     2038    """
     2039    Tests for L{xmppim.AccountIQHandler}.
     2040    """
     2041
     2042    def setUp(self):
     2043        self.user = xmppim.User(JID(u'user@example.org'))
     2044        users = {self.user.entity: self.user}
     2045        realm = xmppim.StaticRealm(u'example.org', users)
     2046
     2047        self.stub = XmlStreamStub()
     2048        self.protocol = xmppim.AccountIQHandler(realm)
     2049        self.protocol.makeConnection(self.stub.xmlstream)
     2050        self.protocol.connectionInitialized()
     2051
     2052
     2053    def test_onIQ(self):
     2054        """
     2055        IQ stanzas are observed.
     2056        """
     2057        received = []
     2058        self.patch(self.protocol, 'iqReceived', received.append)
     2059
     2060        xml = """
     2061          <iq to='user@example.org/Home' from='contact@example.com/Work'>
     2062            <query xmlns='jabber:iq:version'/>
     2063          </iq>
     2064        """
     2065
     2066        iq = parseXml(xml)
     2067        self.stub.send(iq)
     2068
     2069        self.assertEqual(1, len(received))
     2070        stanza = received[-1]
     2071        self.assertEqual(JID(u'user@example.org/Home'), stanza.recipient)
     2072
     2073
     2074    def test_onIQNotUser(self):
     2075        """
     2076        IQs to JIDs without local part are ignored.
     2077        """
     2078        xml = """
     2079          <iq to='example.org' from='contact@example.com/Work'>
     2080            <query xmlns='jabber:iq:version'/>
     2081          </iq>
     2082        """
     2083
     2084        iq = parseXml(xml)
     2085        self.stub.send(iq)
     2086
     2087        self.assertFalse(getattr(iq, 'handled'))
     2088
     2089
     2090    def test_onIQNoResource(self):
     2091        """
     2092        IQs to JIDs without resource are ignored.
     2093        """
     2094        xml = """
     2095          <iq to='user@example.org' from='contact@example.com/Work'>
     2096            <query xmlns='jabber:iq:version'/>
     2097          </iq>
     2098        """
     2099
     2100        iq = parseXml(xml)
     2101        self.stub.send(iq)
     2102
     2103        self.assertFalse(getattr(iq, 'handled'))
     2104
     2105
     2106    def test_iqReceivedDelivered(self):
     2107        """
     2108        IQs are delivered to the user's deliverIQ method.
     2109        """
     2110        received = []
     2111        self.patch(self.user, 'deliverIQ', received.append)
     2112
     2113        stanza = Stanza(recipient=JID(u'user@example.org/Home'),
     2114                        sender=JID(u'contact@example.com/Work'))
     2115        stanza.stanzaKind = u'iq'
     2116        stanza.stanzaType = u'get'
     2117        self.protocol.iqReceived(stanza)
     2118        self.assertEqual([stanza], received)
     2119
     2120
     2121    def test_iqReceivedNoSuchUser(self):
     2122        """
     2123        IQs are delivered to the user's deliverIQ method.
     2124        """
     2125        def deliverIQ(stanza):
     2126            raise ewokkel.NoSuchUser()
     2127
     2128        def cb(error):
     2129            self.assertEqual('service-unavailable', error.condition)
     2130
     2131        self.patch(self.user, 'deliverIQ', deliverIQ)
     2132
     2133        stanza = Stanza(recipient=JID(u'other@example.org/Home'),
     2134                        sender=JID(u'contact@example.com/Work'))
     2135        stanza.stanzaKind = u'iq'
     2136        stanza.stanzaType = u'get'
     2137        d = self.protocol.iqReceived(stanza)
     2138        self.assertFailure(d, error.StanzaError)
     2139        d.addCallback(cb)
     2140        return d
     2141
     2142
     2143
     2144class AccountMessageHandlerTest(unittest.TestCase):
     2145    """
     2146    Tests for L{xmppim.AccountMessageHandler}.
     2147    """
     2148
     2149    def setUp(self):
     2150        self.user = xmppim.User(JID(u'test@example.org'))
     2151        users = {self.user.entity: self.user}
     2152        realm = xmppim.StaticRealm(u'example.org', users)
     2153
     2154        self.stub = XmlStreamStub()
     2155        self.protocol = xmppim.AccountMessageHandler(realm)
     2156        self.protocol.makeConnection(self.stub.xmlstream)
     2157        self.protocol.connectionInitialized()
     2158
     2159
     2160    def test_messageReceived(self):
     2161        """
     2162        Message stanzas are observed.
     2163        """
     2164        received = []
     2165        self.patch(self.protocol, 'messageReceived', received.append)
     2166
     2167        xml = """
     2168          <message to='example.org'>
     2169            <body>Hello</body>
     2170          </message>
     2171        """
     2172
     2173        message = parseXml(xml)
     2174        self.stub.send(message)
     2175
     2176        self.assertEqual(1, len(received))
     2177        stanza = received[-1]
     2178        self.assertEqual(u'Hello', stanza.body)
     2179
     2180
     2181    def test_messageReceivedNotUser(self):
     2182        """
     2183        Messages to JIDs without local part are ignored.
     2184
     2185        This also tests the observer that is set up to handle message stanzas.
     2186        """
     2187        xml = """
     2188          <message to='example.org'>
     2189            <body>Hello</body>
     2190          </message>
     2191        """
     2192
     2193        message = parseXml(xml)
     2194        self.stub.send(message)
     2195
     2196        self.assertFalse(getattr(message, 'handled'))
     2197
     2198
     2199    def test_messageReceivedDelivered(self):
     2200        """
     2201        Messages are delivered to the user's deliverMessage method.
     2202        """
     2203        received = []
     2204        self.patch(self.user, 'deliverMessage', received.append)
     2205
     2206        stanza = xmppim.Message(recipient=JID(u'test@example.org'),
     2207                                sender=JID(u'other@example.com'))
     2208        self.protocol.messageReceived(stanza)
     2209        self.assertEqual([stanza], received)
     2210
     2211
     2212    def test_messageReceivedNotImplemented(self):
     2213        """
     2214        If NotImplementedError is raised, service-available is returned.
     2215        """
     2216        def deliverMessage(stanza):
     2217            raise NotImplementedError()
     2218
     2219        def cb(error):
     2220            self.assertEqual('service-unavailable', error.condition)
     2221
     2222        self.patch(self.user, 'deliverMessage', deliverMessage)
     2223
     2224        stanza = xmppim.Message(recipient=JID(u'test@example.org'),
     2225                                sender=JID(u'other@example.com'))
     2226        d = self.protocol.messageReceived(stanza)
     2227        self.assertFailure(d, error.StanzaError)
     2228        d.addCallback(cb)
     2229        return d
     2230
     2231
     2232@implementer(xmppim.IUserSession)
     2233class FakeUserSession(xmppim.UserSession):
     2234
     2235    def __init__(self, *args, **kwargs):
     2236        super(FakeUserSession, self).__init__(*args, **kwargs)
     2237        self.broadcastPresenceCalls = []
     2238
     2239
     2240    def broadcastPresence(self, presence):
     2241        self.broadcastPresenceCalls.append(presence)
     2242
     2243
     2244
     2245class FakeUserSessionTest(unittest.TestCase):
     2246    """
     2247    Tests for L{FakeUserSessionTest}.
     2248    """
     2249
     2250    def test_interface(self):
     2251        verify.verifyObject(xmppim.IUserSession, FakeUserSession(None))
     2252
     2253
     2254
     2255class UserSessionPresenceProtocolTest(unittest.TestCase):
     2256    """
     2257    Tests for L{xmppim.UserSessionPresenceProtocol}.
     2258    """
     2259
     2260    def setUp(self):
     2261        self.stub = XmlStreamStub()
     2262        self.protocol = xmppim.UserSessionPresenceProtocol()
     2263        self.protocol.makeConnection(self.stub.xmlstream)
     2264
     2265        entity = JID(u'user@example.org')
     2266        user = xmppim.User(entity)
     2267        user.roster = xmppim.InMemoryRoster([])
     2268
     2269        self.session = FakeUserSession(user)
     2270        self.stub.xmlstream.avatar = self.session
     2271
     2272
     2273    def test_availableReceivedDirected(self):
     2274        """
     2275        The directed available stanza is passed for delivery.
     2276        """
     2277        stanza = xmppim.AvailabilityPresence(
     2278                recipient=JID(u'contact@example.org'),
     2279                sender=JID(u'user@example.org'),
     2280                available=True)
     2281
     2282        self.assertFalse(self.protocol.availableReceived(stanza))
     2283
     2284
     2285    def test_availableReceivedBroadcast(self):
     2286        """
     2287        Availabilty is broadcast to contacts and presence is probed.
     2288        """
     2289        stanza = xmppim.AvailabilityPresence(
     2290                sender=JID(u'user@example.org'),
     2291                available=True)
     2292
     2293        self.assertTrue(self.protocol.availableReceived(stanza))
     2294        self.assertEqual(1, len(self.session.broadcastPresenceCalls))
     2295        presence = self.session.broadcastPresenceCalls[-1]
     2296        self.assertIdentical(stanza, presence)
     2297        self.assertTrue(presence.available)
     2298
     2299
     2300    def test_unavailableReceivedDirected(self):
     2301        """
     2302        The directed available stanza is passed for delivery.
     2303        """
     2304        stanza = xmppim.AvailabilityPresence(
     2305                recipient=JID(u'contact@example.org'),
     2306                sender=JID(u'user@example.org'),
     2307                available=False)
     2308
     2309        self.assertFalse(self.protocol.unavailableReceived(stanza))
     2310
     2311
     2312    def test_unavailableReceivedBroadcast(self):
     2313        """
     2314        Unavailabilty is broadcast to contacts.
     2315        """
     2316        stanza = xmppim.AvailabilityPresence(
     2317                sender=JID(u'user@example.org'),
     2318                available=False)
     2319
     2320        self.assertTrue(self.protocol.unavailableReceived(stanza))
     2321        self.assertEqual(1, len(self.session.broadcastPresenceCalls))
     2322        presence = self.session.broadcastPresenceCalls[-1]
     2323        self.assertIdentical(stanza, presence)
     2324        self.assertFalse(presence.available)
     2325
     2326
     2327    def test_subscribedReceived(self):
     2328        """
     2329        The subscription approval stanza is passed for delivery.
     2330        """
     2331        stanza = xmppim.SubscriptionPresence(
     2332                recipient=JID(u'contact@example.org'),
     2333                sender=JID(u'user@example.org'))
     2334        stanza.stanzaType = u'subscribed'
     2335
     2336        self.assertFalse(self.protocol.unsubscribedReceived(stanza))
     2337
     2338
     2339    def test_subscribedReceivedFullJID(self):
     2340        """
     2341        The resource is stripped from full JIDs for subscription approval.
     2342        """
     2343        stanza = xmppim.SubscriptionPresence(
     2344                recipient=JID(u'contact@example.org/Home'),
     2345                sender=JID(u'user@example.org'))
     2346        stanza.stanzaType = u'subscribed'
     2347        stanza.toElement()
     2348
     2349        self.protocol.subscribedReceived(stanza)
     2350        self.assertEqual(u'contact@example.org', stanza.element['to'])
     2351
     2352
     2353    def test_unsubscribedReceived(self):
     2354        """
     2355        The subscription cancellation stanza is passed for delivery.
     2356        """
     2357        stanza = xmppim.SubscriptionPresence(
     2358                recipient=JID(u'contact@example.org'),
     2359                sender=JID(u'user@example.org'))
     2360        stanza.stanzaType = u'unsubscribed'
     2361
     2362        self.assertFalse(self.protocol.unsubscribedReceived(stanza))
     2363
     2364
     2365    def test_unsubscribedReceivedFullJID(self):
     2366        """
     2367        The resource is stripped from full JIDs for subscription cancellation.
     2368        """
     2369        stanza = xmppim.SubscriptionPresence(
     2370                recipient=JID(u'contact@example.org/Home'),
     2371                sender=JID(u'user@example.org'))
     2372        stanza.stanzaType = u'unsubscribed'
     2373        stanza.toElement()
     2374
     2375        self.protocol.unsubscribedReceived(stanza)
     2376        self.assertEqual(u'contact@example.org', stanza.element['to'])
     2377
     2378
     2379    def test_subscribeReceived(self):
     2380        """
     2381        The subscribe request stanza is passed for delivery.
     2382        """
     2383        stanza = xmppim.SubscriptionPresence(
     2384                recipient=JID(u'contact@example.org'),
     2385                sender=JID(u'user@example.org'))
     2386        stanza.stanzaType = u'subscribe'
     2387
     2388        self.assertFalse(self.protocol.subscribedReceived(stanza))
     2389
     2390
     2391    def test_subscribeReceivedFullJID(self):
     2392        """
     2393        The resource is stripped from full JIDs for subscribe requests.
     2394        """
     2395        stanza = xmppim.SubscriptionPresence(
     2396                recipient=JID(u'contact@example.org/Home'),
     2397                sender=JID(u'user@example.org'))
     2398        stanza.stanzaType = u'subscribe'
     2399        stanza.toElement()
     2400
     2401        self.protocol.subscribeReceived(stanza)
     2402        self.assertEqual(u'contact@example.org', stanza.element['to'])
     2403
     2404
     2405    def test_unsubscribeReceived(self):
     2406        """
     2407        The unsubscribe request stanza is passed for delivery.
     2408        """
     2409        stanza = xmppim.SubscriptionPresence(
     2410                recipient=JID(u'contact@example.org'),
     2411                sender=JID(u'user@example.org'))
     2412        stanza.stanzaType = u'unsubscribe'
     2413
     2414        self.assertFalse(self.protocol.unsubscribeReceived(stanza))
     2415
     2416
     2417    def test_unsubscribeReceivedFullJID(self):
     2418        """
     2419        The resource is stripped from full JIDs for unsubscribe requests.
     2420        """
     2421        stanza = xmppim.SubscriptionPresence(
     2422                recipient=JID(u'contact@example.org/Home'),
     2423                sender=JID(u'user@example.org'))
     2424        stanza.stanzaType = u'unsubscribe'
     2425        stanza.toElement()
     2426
     2427        self.protocol.unsubscribeReceived(stanza)
     2428        self.assertEqual(u'contact@example.org', stanza.element['to'])
     2429
     2430
     2431    def test_probeReceived(self):
     2432        """
     2433        The probe stanza is passed for delivery.
     2434        """
     2435        stanza = xmppim.ProbePresence(
     2436                recipient=JID(u'contact@example.org'),
     2437                sender=JID(u'user@example.org'))
     2438
     2439        self.assertFalse(self.protocol.probeReceived(stanza))
     2440
     2441
  • wokkel/xmppim.py

    diff --git a/wokkel/xmppim.py b/wokkel/xmppim.py
    a b  
    417417
    418418
    419419
     420    def parsePresence(self, element):
     421        stanza = Stanza.fromElement(element)
     422
     423        presenceType = stanza.stanzaType or 'available'
     424
     425        try:
     426            parser = self.presenceTypeParserMap[presenceType]
     427        except KeyError:
     428            return
     429
     430        return parser.fromElement(element)
     431
     432
     433    @asyncObserver
    420434    def _onPresence(self, element):
    421435        """
    422436        Called when a presence stanza has been received.
    423437        """
    424         stanza = Stanza.fromElement(element)
    425 
    426         presenceType = stanza.stanzaType or 'available'
    427 
    428         try:
    429             parser = self.presenceTypeParserMap[presenceType]
    430         except KeyError:
    431             return
    432 
    433         presence = parser.fromElement(element)
     438        presence = self.parsePresence(element)
     439        presenceType = presence.stanzaType or 'available'
    434440
    435441        try:
    436442            handler = getattr(self, '%sReceived' % presenceType)
    437443        except AttributeError:
    438             return
     444            return False
    439445        else:
    440             handler(presence)
     446            return handler(presence)
    441447
    442448
    443449
     
    11881194        L{Message}.
    11891195    """
    11901196
     1197    observerPriority = 0
    11911198    messageFactory = Message
    11921199
    11931200    def connectionInitialized(self):
    1194         self.xmlstream.addObserver("/message", self._onMessage)
     1201        self.xmlstream.addObserver("/message", self._onMessage,
     1202                                   self.observerPriority)
    11951203
    11961204
    11971205    @asyncObserver
     
    16931701            presence = ProbePresence(recipient=entity,
    16941702                                     sender=user.entity)
    16951703            self.routeOrDeliver(presence.toElement())
     1704
     1705
     1706
     1707class AccountIQHandler(XMPPHandler):
     1708
     1709    def __init__(self, realm):
     1710        XMPPHandler.__init__(self)
     1711        self.realm = realm
     1712
     1713
     1714    def connectionMade(self):
     1715        self.xmlstream.addObserver('/iq', self._onIQ, 1)
     1716
     1717
     1718    @asyncObserver
     1719    def _onIQ(self, element):
     1720        stanza = Stanza.fromElement(element)
     1721        return self.iqReceived(stanza)
     1722
     1723
     1724    def iqReceived(self, iq):
     1725        """
     1726        Handler for iq stazas to user accounts' connected resources.
     1727
     1728        If the recipient is a bare JID or there is no associated user, this
     1729        handler ignores the stanza, so that other handlers have a chance
     1730        to pick it up. If used, L{generic.FallbackHandler} will respond with a
     1731        C{'service-unavailable'} stanza error if no other handlers handle
     1732        the iq.
     1733        """
     1734        if not iq.recipient.user:
     1735            # This is not for a user.
     1736            return False
     1737        elif not iq.recipient.resource:
     1738            # This might be picked up by another handler.
     1739            return False
     1740
     1741        def gotUser(user):
     1742            user.deliverIQ(iq)
     1743
     1744        def notFound(failure):
     1745            failure.trap(NoSuchResource, NoSuchUser)
     1746            raise error.StanzaError('service-unavailable')
     1747
     1748        d = self.realm.lookupUser(iq.recipient.userhostJID())
     1749        d.addCallback(gotUser)
     1750        d.addErrback(notFound)
     1751        return d
     1752
     1753
     1754
     1755class AccountMessageHandler(MessageProtocol):
     1756
     1757    observerPriority = 1
     1758
     1759    def __init__(self, realm):
     1760        MessageProtocol.__init__(self)
     1761        self.realm = realm
     1762
     1763
     1764    def messageReceived(self, message):
     1765        """
     1766        Handler for message stanzas to user accounts.
     1767        """
     1768        if not message.recipient.user:
     1769            # This is not for a user.
     1770            return False
     1771
     1772        def gotUser(user):
     1773            user.deliverMessage(message)
     1774
     1775        def eb(failure):
     1776            failure.trap(NoSuchUser, NoSuchResource, NotImplementedError)
     1777            raise error.StanzaError('service-unavailable')
     1778
     1779        d = self.realm.lookupUser(message.recipient.userhostJID())
     1780        d.addCallback(gotUser)
     1781        d.addErrback(eb)
     1782        return d
     1783
     1784
     1785
     1786class AccountPresenceHandler(PresenceProtocol):
     1787
     1788    def __init__(self, realm):
     1789        PresenceProtocol.__init__(self)
     1790        self.realm = realm
     1791
     1792
     1793    def _deliverPresence(self, presence):
     1794        if not presence.recipient.user:
     1795            # This is not for a user.
     1796            return False
     1797
     1798        def gotUser(user):
     1799            user.deliverPresence(presence)
     1800
     1801        def notFound(failure):
     1802            failure.trap(NoSuchResource, NoSuchUser)
     1803            return
     1804
     1805        d = self.realm.lookupUser(presence.recipient.userhostJID())
     1806        d.addCallback(gotUser)
     1807        d.addErrback(notFound)
     1808        return d
     1809
     1810
     1811    def availableReceived(self, presence):
     1812        return self._deliverPresence(presence)
     1813
     1814
     1815    def unavailableReceived(self, presence):
     1816        return self._deliverPresence(presence)
     1817
     1818
     1819    def subscribedReceived(self, presence):
     1820        log.msg("%r subscribed %s to its presence" % (presence.sender,
     1821                                                      presence.recipient))
     1822        return self._deliverPresence(presence)
     1823
     1824
     1825    def unsubscribedReceived(self, presence):
     1826        log.msg("%r unsubscribed %s from its presence" % (presence.sender,
     1827                                                          presence.recipient))
     1828        return self._deliverPresence(presence)
     1829
     1830
     1831    def subscribeReceived(self, presence):
     1832        log.msg("%r requests subscription to %s" % (presence.sender,
     1833                                                    presence.recipient))
     1834        return self._deliverPresence(presence)
     1835
     1836
     1837    def unsubscribeReceived(self, presence):
     1838        log.msg("%r requests unsubscription from %s" % (presence.sender,
     1839                                                        presence.recipient))
     1840        return self._deliverPresence(presence)
     1841
     1842
     1843    def probeReceived(self, presence):
     1844        if not presence.recipient.user:
     1845            # This is not for a user.
     1846            return False
     1847
     1848        def gotUser(user):
     1849            return user.getPresences(presence.sender.userhostJID())
     1850
     1851        def notSubscribed(failure):
     1852            failure.trap(NoSuchUser, NotSubscribed)
     1853            response = SubscriptionPresence(recipient=presence.sender,
     1854                                            sender=presence.recipient)
     1855            response.stanzaType = 'unsubscribed'
     1856            return [response]
     1857
     1858        def sendPresences(userPresences):
     1859            for userPresence in userPresences:
     1860                self.parent.multicast(userPresence, [presence.sender])
     1861
     1862        d = self.realm.lookupUser(presence.recipient.userhostJID())
     1863        d.addCallback(gotUser)
     1864        d.addErrback(notSubscribed)
     1865        d.addCallback(sendPresences)
     1866        return d
     1867
     1868
     1869
     1870class UserSessionPresenceProtocol(PresenceProtocol):
     1871    """
     1872    Presence protocol for user client sessions.
     1873    """
     1874
     1875    def _stampContactJID(self, presence):
     1876        """
     1877        Stamp the contact JID to be a bare JID.
     1878        """
     1879        if presence.recipient.resource:
     1880            contactJID = presence.recipient.userhostJID()
     1881            presence.element['to'] = contactJID.userhost()
     1882
     1883
     1884    def availableReceived(self, presence):
     1885        if presence.recipient:
     1886            # Pass through directed presence.
     1887            return False
     1888        else:
     1889            session = self.xmlstream.avatar
     1890            session.broadcastPresence(presence)
     1891            return True
     1892
     1893
     1894    def unavailableReceived(self, presence):
     1895        if presence.recipient:
     1896            # Pass through directed presence.
     1897            return False
     1898        else:
     1899            session = self.xmlstream.avatar
     1900            session.broadcastPresence(presence)
     1901            return True
     1902
     1903
     1904    def subscribedReceived(self, presence):
     1905        """
     1906        Subscription approval confirmation was received.
     1907        """
     1908        self._stampContactJID(presence)
     1909        return False
     1910
     1911
     1912    def unsubscribedReceived(self, presence):
     1913        """
     1914        Unsubscription confirmation was received.
     1915        """
     1916        self._stampContactJID(presence)
     1917        return False
     1918
     1919
     1920    def subscribeReceived(self, presence):
     1921        """
     1922        Subscription request was received.
     1923        """
     1924        self._stampContactJID(presence)
     1925        return False
     1926
     1927
     1928    def unsubscribeReceived(self, presence):
     1929        """
     1930        Unsubscription request was received.
     1931        """
     1932        self._stampContactJID(presence)
     1933        return False
     1934
     1935
     1936    def probeReceived(self, presence):
     1937        """
     1938        Probe presence was received.
     1939        """
     1940        return False
Note: See TracBrowser for help on using the repository browser.