source: ralphm-patches/c2s_stanza_handlers.patch @ 72:727b4d29c48e

Last change on this file since 72:727b4d29c48e was 72:727b4d29c48e, checked in by Ralph Meijer <ralphm@…>, 8 years ago

Major reworking of avatars, session manager and stanza handlers.

File size: 22.9 KB
  • wokkel/client.py

    # HG changeset patch
    # Parent c104dd0a9d3fb840b53661822cf06728a5b23d8f
    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
     
    20042004        d = self.sessionManager.probePresence(user)
    20052005        d.addCallback(cb)
    20062006        return d
     2007
     2008
     2009
     2010class AccountIQHandlerTest(unittest.TestCase):
     2011    """
     2012    Tests for L{xmppim.AccountIQHandler}.
     2013    """
     2014
     2015    def setUp(self):
     2016        self.user = xmppim.User(JID(u'user@example.org'))
     2017        users = {self.user.entity: self.user}
     2018        realm = xmppim.StaticRealm(u'example.org', users)
     2019
     2020        self.stub = XmlStreamStub()
     2021        self.protocol = xmppim.AccountIQHandler(realm)
     2022        self.protocol.makeConnection(self.stub.xmlstream)
     2023        self.protocol.connectionInitialized()
     2024
     2025
     2026    def test_onIQ(self):
     2027        """
     2028        IQ stanzas are observed.
     2029        """
     2030        received = []
     2031        self.patch(self.protocol, 'iqReceived', received.append)
     2032
     2033        xml = """
     2034          <iq to='user@example.org/Home' from='contact@example.com/Work'>
     2035            <query xmlns='jabber:iq:version'/>
     2036          </iq>
     2037        """
     2038
     2039        iq = parseXml(xml)
     2040        self.stub.send(iq)
     2041
     2042        self.assertEqual(1, len(received))
     2043        stanza = received[-1]
     2044        self.assertEqual(JID(u'user@example.org/Home'), stanza.recipient)
     2045
     2046
     2047    def test_onIQNotUser(self):
     2048        """
     2049        IQs to JIDs without local part are ignored.
     2050        """
     2051        xml = """
     2052          <iq to='example.org' from='contact@example.com/Work'>
     2053            <query xmlns='jabber:iq:version'/>
     2054          </iq>
     2055        """
     2056
     2057        iq = parseXml(xml)
     2058        self.stub.send(iq)
     2059
     2060        self.assertFalse(getattr(iq, 'handled'))
     2061
     2062
     2063    def test_onIQNoResource(self):
     2064        """
     2065        IQs to JIDs without resource are ignored.
     2066        """
     2067        xml = """
     2068          <iq to='user@example.org' from='contact@example.com/Work'>
     2069            <query xmlns='jabber:iq:version'/>
     2070          </iq>
     2071        """
     2072
     2073        iq = parseXml(xml)
     2074        self.stub.send(iq)
     2075
     2076        self.assertFalse(getattr(iq, 'handled'))
     2077
     2078
     2079    def test_iqReceivedDelivered(self):
     2080        """
     2081        IQs are delivered to the user's deliverIQ method.
     2082        """
     2083        received = []
     2084        self.patch(self.user, 'deliverIQ', received.append)
     2085
     2086        stanza = Stanza(recipient=JID(u'user@example.org/Home'),
     2087                        sender=JID(u'contact@example.com/Work'))
     2088        stanza.stanzaKind = u'iq'
     2089        stanza.stanzaType = u'get'
     2090        self.protocol.iqReceived(stanza)
     2091        self.assertEqual([stanza], received)
     2092
     2093
     2094    def test_iqReceivedNoSuchUser(self):
     2095        """
     2096        IQs are delivered to the user's deliverIQ method.
     2097        """
     2098        def deliverIQ(stanza):
     2099            raise ewokkel.NoSuchUser()
     2100
     2101        def cb(error):
     2102            self.assertEqual('service-unavailable', error.condition)
     2103
     2104        self.patch(self.user, 'deliverIQ', deliverIQ)
     2105
     2106        stanza = Stanza(recipient=JID(u'other@example.org/Home'),
     2107                        sender=JID(u'contact@example.com/Work'))
     2108        stanza.stanzaKind = u'iq'
     2109        stanza.stanzaType = u'get'
     2110        d = self.protocol.iqReceived(stanza)
     2111        self.assertFailure(d, error.StanzaError)
     2112        d.addCallback(cb)
     2113        return d
     2114
     2115
     2116
     2117class AccountMessageHandlerTest(unittest.TestCase):
     2118    """
     2119    Tests for L{xmppim.AccountMessageHandler}.
     2120    """
     2121
     2122    def setUp(self):
     2123        self.user = xmppim.User(JID(u'test@example.org'))
     2124        users = {self.user.entity: self.user}
     2125        realm = xmppim.StaticRealm(u'example.org', users)
     2126
     2127        self.stub = XmlStreamStub()
     2128        self.protocol = xmppim.AccountMessageHandler(realm)
     2129        self.protocol.makeConnection(self.stub.xmlstream)
     2130        self.protocol.connectionInitialized()
     2131
     2132
     2133    def test_messageReceived(self):
     2134        """
     2135        Message stanzas are observed.
     2136        """
     2137        received = []
     2138        self.patch(self.protocol, 'messageReceived', received.append)
     2139
     2140        xml = """
     2141          <message to='example.org'>
     2142            <body>Hello</body>
     2143          </message>
     2144        """
     2145
     2146        message = parseXml(xml)
     2147        self.stub.send(message)
     2148
     2149        self.assertEqual(1, len(received))
     2150        stanza = received[-1]
     2151        self.assertEqual(u'Hello', stanza.body)
     2152
     2153
     2154
     2155    def test_messageReceivedNotUser(self):
     2156        """
     2157        Messages to JIDs without local part are ignored.
     2158
     2159        This also tests the observer that is set up to handle message stanzas.
     2160        """
     2161        xml = """
     2162          <message to='example.org'>
     2163            <body>Hello</body>
     2164          </message>
     2165        """
     2166
     2167        message = parseXml(xml)
     2168        self.stub.send(message)
     2169
     2170        self.assertFalse(getattr(message, 'handled'))
     2171
     2172
     2173    def test_messageReceivedDelivered(self):
     2174        """
     2175        Messages are delivered to the user's deliverMessage method.
     2176        """
     2177        received = []
     2178        self.patch(self.user, 'deliverMessage', received.append)
     2179
     2180        stanza = xmppim.Message(recipient=JID(u'test@example.org'),
     2181                                sender=JID(u'other@example.com'))
     2182        self.protocol.messageReceived(stanza)
     2183        self.assertEqual([stanza], received)
     2184
     2185
     2186    def test_messageReceivedNotImplemented(self):
     2187        """
     2188        If NotImplementedError is raised, service-available is returned.
     2189        """
     2190        def deliverMessage(stanza):
     2191            raise NotImplementedError()
     2192
     2193        def cb(error):
     2194            self.assertEqual('service-unavailable', error.condition)
     2195
     2196        self.patch(self.user, 'deliverMessage', deliverMessage)
     2197
     2198        stanza = xmppim.Message(recipient=JID(u'test@example.org'),
     2199                                sender=JID(u'other@example.com'))
     2200        d = self.protocol.messageReceived(stanza)
     2201        self.assertFailure(d, error.StanzaError)
     2202        d.addCallback(cb)
     2203        return d
     2204
     2205
     2206@implementer(xmppim.IUserSession)
     2207class FakeUserSession(xmppim.UserSession):
     2208
     2209    def __init__(self, *args, **kwargs):
     2210        super(FakeUserSession, self).__init__(*args, **kwargs)
     2211        self.probePresenceCalls = 0
     2212        self.broadcastPresenceCalls = []
     2213
     2214
     2215    def probePresence(self):
     2216        self.probePresenceCalls += 1
     2217
     2218
     2219    def broadcastPresence(self, presence, available):
     2220        self.broadcastPresenceCalls.append((presence, available))
     2221
     2222
     2223
     2224class FakeUserSessionTest(unittest.TestCase):
     2225    """
     2226    Tests for L{FakeUserSessionTest}.
     2227    """
     2228
     2229    def test_interface(self):
     2230        verify.verifyObject(xmppim.IUserSession, FakeUserSession(None))
     2231
     2232
     2233
     2234class UserSessionPresenceProtocolTest(unittest.TestCase):
     2235    """
     2236    Tests for L{xmppim.UserSessionPresenceProtocol}.
     2237    """
     2238
     2239    def setUp(self):
     2240        self.stub = XmlStreamStub()
     2241        self.protocol = xmppim.UserSessionPresenceProtocol()
     2242        self.protocol.makeConnection(self.stub.xmlstream)
     2243
     2244        entity = JID(u'user@example.org')
     2245        user = xmppim.User(entity)
     2246        user.roster = xmppim.InMemoryRoster([])
     2247
     2248        self.session = FakeUserSession(user)
     2249        self.stub.xmlstream.avatar = self.session
     2250
     2251
     2252    def test_availableReceivedDirected(self):
     2253        """
     2254        The directed available stanza is passed for delivery.
     2255        """
     2256        stanza = xmppim.AvailabilityPresence(
     2257                recipient=JID(u'contact@example.org'),
     2258                sender=JID(u'user@example.org'),
     2259                available=True)
     2260
     2261        self.assertFalse(self.protocol.availableReceived(stanza))
     2262
     2263
     2264    def test_availableReceivedBroadcast(self):
     2265        """
     2266        Availabilty is broadcast to contacts and presence is probed.
     2267        """
     2268        stanza = xmppim.AvailabilityPresence(
     2269                sender=JID(u'user@example.org'),
     2270                available=True)
     2271
     2272        self.assertTrue(self.protocol.availableReceived(stanza))
     2273        self.assertEqual(1, self.session.probePresenceCalls)
     2274        self.assertEqual(1, len(self.session.broadcastPresenceCalls))
     2275        presence, available = self.session.broadcastPresenceCalls[-1]
     2276        self.assertIdentical(stanza, presence)
     2277        self.assertTrue(available)
     2278
     2279
     2280    def test_unavailableReceivedDirected(self):
     2281        """
     2282        The directed available stanza is passed for delivery.
     2283        """
     2284        stanza = xmppim.AvailabilityPresence(
     2285                recipient=JID(u'contact@example.org'),
     2286                sender=JID(u'user@example.org'),
     2287                available=False)
     2288
     2289        self.assertFalse(self.protocol.unavailableReceived(stanza))
     2290
     2291
     2292    def test_unavailableReceivedBroadcast(self):
     2293        """
     2294        Unavailabilty is broadcast to contacts.
     2295        """
     2296        stanza = xmppim.AvailabilityPresence(
     2297                sender=JID(u'user@example.org'),
     2298                available=False)
     2299
     2300        self.assertTrue(self.protocol.unavailableReceived(stanza))
     2301        self.assertEqual(0, self.session.probePresenceCalls)
     2302        self.assertEqual(1, len(self.session.broadcastPresenceCalls))
     2303        presence, available = self.session.broadcastPresenceCalls[-1]
     2304        self.assertIdentical(stanza, presence)
     2305        self.assertFalse(available)
     2306
     2307
     2308    def test_subscribedReceived(self):
     2309        """
     2310        The subscription approval stanza is passed for delivery.
     2311        """
     2312        stanza = xmppim.SubscriptionPresence(
     2313                recipient=JID(u'contact@example.org'),
     2314                sender=JID(u'user@example.org'))
     2315        stanza.stanzaType = u'subscribed'
     2316
     2317        self.assertFalse(self.protocol.unsubscribedReceived(stanza))
     2318
     2319
     2320    def test_subscribedReceivedFullJID(self):
     2321        """
     2322        The resource is stripped from full JIDs for subscription approval.
     2323        """
     2324        stanza = xmppim.SubscriptionPresence(
     2325                recipient=JID(u'contact@example.org/Home'),
     2326                sender=JID(u'user@example.org'))
     2327        stanza.stanzaType = u'subscribed'
     2328        stanza.toElement()
     2329
     2330        self.protocol.subscribedReceived(stanza)
     2331        self.assertEqual(u'contact@example.org', stanza.element['to'])
     2332
     2333
     2334    def test_unsubscribedReceived(self):
     2335        """
     2336        The subscription cancellation stanza is passed for delivery.
     2337        """
     2338        stanza = xmppim.SubscriptionPresence(
     2339                recipient=JID(u'contact@example.org'),
     2340                sender=JID(u'user@example.org'))
     2341        stanza.stanzaType = u'unsubscribed'
     2342
     2343        self.assertFalse(self.protocol.unsubscribedReceived(stanza))
     2344
     2345
     2346    def test_unsubscribedReceivedFullJID(self):
     2347        """
     2348        The resource is stripped from full JIDs for subscription cancellation.
     2349        """
     2350        stanza = xmppim.SubscriptionPresence(
     2351                recipient=JID(u'contact@example.org/Home'),
     2352                sender=JID(u'user@example.org'))
     2353        stanza.stanzaType = u'unsubscribed'
     2354        stanza.toElement()
     2355
     2356        self.protocol.unsubscribedReceived(stanza)
     2357        self.assertEqual(u'contact@example.org', stanza.element['to'])
     2358
     2359
     2360    def test_subscribeReceived(self):
     2361        """
     2362        The subscribe request stanza is passed for delivery.
     2363        """
     2364        stanza = xmppim.SubscriptionPresence(
     2365                recipient=JID(u'contact@example.org'),
     2366                sender=JID(u'user@example.org'))
     2367        stanza.stanzaType = u'subscribe'
     2368
     2369        self.assertFalse(self.protocol.subscribedReceived(stanza))
     2370
     2371
     2372    def test_subscribeReceivedFullJID(self):
     2373        """
     2374        The resource is stripped from full JIDs for subscribe requests.
     2375        """
     2376        stanza = xmppim.SubscriptionPresence(
     2377                recipient=JID(u'contact@example.org/Home'),
     2378                sender=JID(u'user@example.org'))
     2379        stanza.stanzaType = u'subscribe'
     2380        stanza.toElement()
     2381
     2382        self.protocol.subscribeReceived(stanza)
     2383        self.assertEqual(u'contact@example.org', stanza.element['to'])
     2384
     2385
     2386    def test_unsubscribeReceived(self):
     2387        """
     2388        The unsubscribe request stanza is passed for delivery.
     2389        """
     2390        stanza = xmppim.SubscriptionPresence(
     2391                recipient=JID(u'contact@example.org'),
     2392                sender=JID(u'user@example.org'))
     2393        stanza.stanzaType = u'unsubscribe'
     2394
     2395        self.assertFalse(self.protocol.unsubscribeReceived(stanza))
     2396
     2397
     2398    def test_unsubscribeReceivedFullJID(self):
     2399        """
     2400        The resource is stripped from full JIDs for unsubscribe requests.
     2401        """
     2402        stanza = xmppim.SubscriptionPresence(
     2403                recipient=JID(u'contact@example.org/Home'),
     2404                sender=JID(u'user@example.org'))
     2405        stanza.stanzaType = u'unsubscribe'
     2406        stanza.toElement()
     2407
     2408        self.protocol.unsubscribeReceived(stanza)
     2409        self.assertEqual(u'contact@example.org', stanza.element['to'])
     2410
     2411
     2412    def test_probeReceived(self):
     2413        """
     2414        The probe stanza is passed for delivery.
     2415        """
     2416        stanza = xmppim.ProbePresence(
     2417                recipient=JID(u'contact@example.org'),
     2418                sender=JID(u'user@example.org'))
     2419
     2420        self.assertFalse(self.protocol.probeReceived(stanza))
     2421
     2422
  • 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    stanzaFactory = 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
     
    16731681            presence = ProbePresence(recipient=entity,
    16741682                                     sender=user.entity)
    16751683            self.routeOrDeliver(presence.toElement())
     1684
     1685
     1686
     1687class AccountIQHandler(XMPPHandler):
     1688
     1689    def __init__(self, realm):
     1690        XMPPHandler.__init__(self)
     1691        self.realm = realm
     1692
     1693
     1694    def connectionMade(self):
     1695        self.xmlstream.addObserver('/iq', self._onIQ, 1)
     1696
     1697
     1698    @asyncObserver
     1699    def _onIQ(self, element):
     1700        stanza = Stanza.fromElement(element)
     1701        return self.iqReceived(stanza)
     1702
     1703
     1704    def iqReceived(self, iq):
     1705        """
     1706        Handler for iq stazas to user accounts' connected resources.
     1707
     1708        If the recipient is a bare JID or there is no associated user, this
     1709        handler ignores the stanza, so that other handlers have a chance
     1710        to pick it up. If used, L{generic.FallbackHandler} will respond with a
     1711        C{'service-unavailable'} stanza error if no other handlers handle
     1712        the iq.
     1713        """
     1714        if not iq.recipient.user:
     1715            # This is not for a user.
     1716            return False
     1717        elif not iq.recipient.resource:
     1718            # This might be picked up by another handler.
     1719            return False
     1720
     1721        def gotUser(user):
     1722            user.deliverIQ(iq)
     1723
     1724        def notFound(failure):
     1725            failure.trap(NoSuchResource, NoSuchUser)
     1726            raise error.StanzaError('service-unavailable')
     1727
     1728        d = self.realm.lookupUser(iq.recipient.userhostJID())
     1729        d.addCallback(gotUser)
     1730        d.addErrback(notFound)
     1731        return d
     1732
     1733
     1734
     1735class AccountMessageHandler(MessageProtocol):
     1736
     1737    observerPriority = 1
     1738
     1739    def __init__(self, realm):
     1740        MessageProtocol.__init__(self)
     1741        self.realm = realm
     1742
     1743
     1744    def messageReceived(self, message):
     1745        """
     1746        Handler for message stanzas to user accounts.
     1747        """
     1748        if not message.recipient.user:
     1749            # This is not for a user.
     1750            return False
     1751
     1752        def gotUser(user):
     1753            user.deliverMessage(message)
     1754
     1755        def eb(failure):
     1756            failure.trap(NoSuchUser, NoSuchResource, NotImplementedError)
     1757            raise error.StanzaError('service-unavailable')
     1758
     1759        d = self.realm.lookupUser(message.recipient.userhostJID())
     1760        d.addCallback(gotUser)
     1761        d.addErrback(eb)
     1762        return d
     1763
     1764
     1765
     1766class AccountPresenceHandler(PresenceProtocol):
     1767
     1768    def __init__(self, realm):
     1769        PresenceProtocol.__init__(self)
     1770        self.realm = realm
     1771
     1772
     1773    def _deliverPresence(self, presence):
     1774        if not presence.recipient.user:
     1775            # This is not for a user.
     1776            return False
     1777
     1778        def gotUser(user):
     1779            user.deliverPresence(presence)
     1780
     1781        def notFound(failure):
     1782            failure.trap(NoSuchResource, NoSuchUser)
     1783            return
     1784
     1785        d = self.realm.lookupUser(presence.recipient.userhostJID())
     1786        d.addCallback(gotUser)
     1787        d.addErrback(notFound)
     1788        return d
     1789
     1790
     1791    def availableReceived(self, presence):
     1792        return self._deliverPresence(presence)
     1793
     1794
     1795    def unavailableReceived(self, presence):
     1796        return self._deliverPresence(presence)
     1797
     1798
     1799    def subscribedReceived(self, presence):
     1800        log.msg("%r subscribed %s to its presence" % (presence.sender,
     1801                                                      presence.recipient))
     1802        return self._deliverPresence(presence)
     1803
     1804
     1805    def unsubscribedReceived(self, presence):
     1806        log.msg("%r unsubscribed %s from its presence" % (presence.sender,
     1807                                                          presence.recipient))
     1808        return self._deliverPresence(presence)
     1809
     1810
     1811    def subscribeReceived(self, presence):
     1812        log.msg("%r requests subscription to %s" % (presence.sender,
     1813                                                    presence.recipient))
     1814        return self._deliverPresence(presence)
     1815
     1816
     1817    def unsubscribeReceived(self, presence):
     1818        log.msg("%r requests unsubscription from %s" % (presence.sender,
     1819                                                        presence.recipient))
     1820        return self._deliverPresence(presence)
     1821
     1822
     1823    def probeReceived(self, presence):
     1824        if not presence.recipient.user:
     1825            # This is not for a user.
     1826            return False
     1827
     1828        def gotUser(user):
     1829            return user.getPresences(presence.sender.userhostJID())
     1830
     1831        def notSubscribed(failure):
     1832            failure.trap(NoSuchUser, NotSubscribed)
     1833            response = SubscriptionPresence(recipient=presence.sender,
     1834                                            sender=presence.recipient)
     1835            response.stanzaType = 'unsubscribed'
     1836            return [response]
     1837
     1838        def sendPresences(userPresences):
     1839            for userPresence in userPresences:
     1840                self.parent.multicast(userPresence, [presence.sender])
     1841
     1842        d = self.realm.lookupUser(presence.recipient.userhostJID())
     1843        d.addCallback(gotUser)
     1844        d.addErrback(notSubscribed)
     1845        d.addCallback(sendPresences)
     1846        return d
     1847
     1848
     1849
     1850class UserSessionPresenceProtocol(PresenceProtocol):
     1851    """
     1852    Presence protocol for user client sessions.
     1853    """
     1854
     1855    def _stampContactJID(self, presence):
     1856        """
     1857        Stamp the contact JID to be a bare JID.
     1858        """
     1859        if presence.recipient.resource:
     1860            contactJID = presence.recipient.userhostJID()
     1861            presence.element['to'] = contactJID.userhost()
     1862
     1863
     1864    def availableReceived(self, presence):
     1865        if presence.recipient:
     1866            # Pass through directed presence.
     1867            return False
     1868        else:
     1869            session = self.xmlstream.avatar
     1870            sendProbe = not session.presence
     1871
     1872            session.broadcastPresence(presence, available=True)
     1873
     1874            if sendProbe:
     1875                session.probePresence()
     1876
     1877            return True
     1878
     1879
     1880    def unavailableReceived(self, presence):
     1881        if presence.recipient:
     1882            # Pass through directed presence.
     1883            return False
     1884        else:
     1885            session = self.xmlstream.avatar
     1886            session.broadcastPresence(presence, available=False)
     1887            return True
     1888
     1889
     1890    def subscribedReceived(self, presence):
     1891        """
     1892        Subscription approval confirmation was received.
     1893        """
     1894        self._stampContactJID(presence)
     1895        return False
     1896
     1897
     1898    def unsubscribedReceived(self, presence):
     1899        """
     1900        Unsubscription confirmation was received.
     1901        """
     1902        self._stampContactJID(presence)
     1903        return False
     1904
     1905
     1906    def subscribeReceived(self, presence):
     1907        """
     1908        Subscription request was received.
     1909        """
     1910        self._stampContactJID(presence)
     1911        return False
     1912
     1913
     1914    def unsubscribeReceived(self, presence):
     1915        """
     1916        Unsubscription request was received.
     1917        """
     1918        self._stampContactJID(presence)
     1919        return False
     1920
     1921
     1922    def probeReceived(self, presence):
     1923        """
     1924        Probe presence was received.
     1925        """
     1926        return False
Note: See TracBrowser for help on using the repository browser.