source: ralphm-patches/c2s_stanza_handlers.patch @ 73:f574beee3bca

Last change on this file since 73:f574beee3bca was 73:f574beee3bca, checked in by Ralph Meijer <ralphm@…>, 7 years ago

Minor cleanups, improved error message handling, and upstreamed patch.

  • Upstreamed deprecation of prepareIDNName.
  • MessageProtocol? now properly handles error message stanzas.
  • Renamed methods for RosterServerProtocol?.
  • Prefer connectionInitialized for setting up stanza observers.
File size: 22.9 KB
  • wokkel/client.py

    # HG changeset patch
    # Parent 70ce9e97aa58780ac7f75a177fe8c0d2aaf1bfc6
    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.probePresenceCalls = 0
     2238        self.broadcastPresenceCalls = []
     2239
     2240
     2241    def probePresence(self):
     2242        self.probePresenceCalls += 1
     2243
     2244
     2245    def broadcastPresence(self, presence, available):
     2246        self.broadcastPresenceCalls.append((presence, available))
     2247
     2248
     2249
     2250class FakeUserSessionTest(unittest.TestCase):
     2251    """
     2252    Tests for L{FakeUserSessionTest}.
     2253    """
     2254
     2255    def test_interface(self):
     2256        verify.verifyObject(xmppim.IUserSession, FakeUserSession(None))
     2257
     2258
     2259
     2260class UserSessionPresenceProtocolTest(unittest.TestCase):
     2261    """
     2262    Tests for L{xmppim.UserSessionPresenceProtocol}.
     2263    """
     2264
     2265    def setUp(self):
     2266        self.stub = XmlStreamStub()
     2267        self.protocol = xmppim.UserSessionPresenceProtocol()
     2268        self.protocol.makeConnection(self.stub.xmlstream)
     2269
     2270        entity = JID(u'user@example.org')
     2271        user = xmppim.User(entity)
     2272        user.roster = xmppim.InMemoryRoster([])
     2273
     2274        self.session = FakeUserSession(user)
     2275        self.stub.xmlstream.avatar = self.session
     2276
     2277
     2278    def test_availableReceivedDirected(self):
     2279        """
     2280        The directed available stanza is passed for delivery.
     2281        """
     2282        stanza = xmppim.AvailabilityPresence(
     2283                recipient=JID(u'contact@example.org'),
     2284                sender=JID(u'user@example.org'),
     2285                available=True)
     2286
     2287        self.assertFalse(self.protocol.availableReceived(stanza))
     2288
     2289
     2290    def test_availableReceivedBroadcast(self):
     2291        """
     2292        Availabilty is broadcast to contacts and presence is probed.
     2293        """
     2294        stanza = xmppim.AvailabilityPresence(
     2295                sender=JID(u'user@example.org'),
     2296                available=True)
     2297
     2298        self.assertTrue(self.protocol.availableReceived(stanza))
     2299        self.assertEqual(1, self.session.probePresenceCalls)
     2300        self.assertEqual(1, len(self.session.broadcastPresenceCalls))
     2301        presence, available = self.session.broadcastPresenceCalls[-1]
     2302        self.assertIdentical(stanza, presence)
     2303        self.assertTrue(available)
     2304
     2305
     2306    def test_unavailableReceivedDirected(self):
     2307        """
     2308        The directed available stanza is passed for delivery.
     2309        """
     2310        stanza = xmppim.AvailabilityPresence(
     2311                recipient=JID(u'contact@example.org'),
     2312                sender=JID(u'user@example.org'),
     2313                available=False)
     2314
     2315        self.assertFalse(self.protocol.unavailableReceived(stanza))
     2316
     2317
     2318    def test_unavailableReceivedBroadcast(self):
     2319        """
     2320        Unavailabilty is broadcast to contacts.
     2321        """
     2322        stanza = xmppim.AvailabilityPresence(
     2323                sender=JID(u'user@example.org'),
     2324                available=False)
     2325
     2326        self.assertTrue(self.protocol.unavailableReceived(stanza))
     2327        self.assertEqual(0, self.session.probePresenceCalls)
     2328        self.assertEqual(1, len(self.session.broadcastPresenceCalls))
     2329        presence, available = self.session.broadcastPresenceCalls[-1]
     2330        self.assertIdentical(stanza, presence)
     2331        self.assertFalse(available)
     2332
     2333
     2334    def test_subscribedReceived(self):
     2335        """
     2336        The subscription approval 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'subscribed'
     2342
     2343        self.assertFalse(self.protocol.unsubscribedReceived(stanza))
     2344
     2345
     2346    def test_subscribedReceivedFullJID(self):
     2347        """
     2348        The resource is stripped from full JIDs for subscription approval.
     2349        """
     2350        stanza = xmppim.SubscriptionPresence(
     2351                recipient=JID(u'contact@example.org/Home'),
     2352                sender=JID(u'user@example.org'))
     2353        stanza.stanzaType = u'subscribed'
     2354        stanza.toElement()
     2355
     2356        self.protocol.subscribedReceived(stanza)
     2357        self.assertEqual(u'contact@example.org', stanza.element['to'])
     2358
     2359
     2360    def test_unsubscribedReceived(self):
     2361        """
     2362        The subscription cancellation 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'unsubscribed'
     2368
     2369        self.assertFalse(self.protocol.unsubscribedReceived(stanza))
     2370
     2371
     2372    def test_unsubscribedReceivedFullJID(self):
     2373        """
     2374        The resource is stripped from full JIDs for subscription cancellation.
     2375        """
     2376        stanza = xmppim.SubscriptionPresence(
     2377                recipient=JID(u'contact@example.org/Home'),
     2378                sender=JID(u'user@example.org'))
     2379        stanza.stanzaType = u'unsubscribed'
     2380        stanza.toElement()
     2381
     2382        self.protocol.unsubscribedReceived(stanza)
     2383        self.assertEqual(u'contact@example.org', stanza.element['to'])
     2384
     2385
     2386    def test_subscribeReceived(self):
     2387        """
     2388        The subscribe 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'subscribe'
     2394
     2395        self.assertFalse(self.protocol.subscribedReceived(stanza))
     2396
     2397
     2398    def test_subscribeReceivedFullJID(self):
     2399        """
     2400        The resource is stripped from full JIDs for subscribe 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'subscribe'
     2406        stanza.toElement()
     2407
     2408        self.protocol.subscribeReceived(stanza)
     2409        self.assertEqual(u'contact@example.org', stanza.element['to'])
     2410
     2411
     2412    def test_unsubscribeReceived(self):
     2413        """
     2414        The unsubscribe request stanza is passed for delivery.
     2415        """
     2416        stanza = xmppim.SubscriptionPresence(
     2417                recipient=JID(u'contact@example.org'),
     2418                sender=JID(u'user@example.org'))
     2419        stanza.stanzaType = u'unsubscribe'
     2420
     2421        self.assertFalse(self.protocol.unsubscribeReceived(stanza))
     2422
     2423
     2424    def test_unsubscribeReceivedFullJID(self):
     2425        """
     2426        The resource is stripped from full JIDs for unsubscribe requests.
     2427        """
     2428        stanza = xmppim.SubscriptionPresence(
     2429                recipient=JID(u'contact@example.org/Home'),
     2430                sender=JID(u'user@example.org'))
     2431        stanza.stanzaType = u'unsubscribe'
     2432        stanza.toElement()
     2433
     2434        self.protocol.unsubscribeReceived(stanza)
     2435        self.assertEqual(u'contact@example.org', stanza.element['to'])
     2436
     2437
     2438    def test_probeReceived(self):
     2439        """
     2440        The probe stanza is passed for delivery.
     2441        """
     2442        stanza = xmppim.ProbePresence(
     2443                recipient=JID(u'contact@example.org'),
     2444                sender=JID(u'user@example.org'))
     2445
     2446        self.assertFalse(self.protocol.probeReceived(stanza))
     2447
     2448
  • 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
     
    16891697            presence = ProbePresence(recipient=entity,
    16901698                                     sender=user.entity)
    16911699            self.routeOrDeliver(presence.toElement())
     1700
     1701
     1702
     1703class AccountIQHandler(XMPPHandler):
     1704
     1705    def __init__(self, realm):
     1706        XMPPHandler.__init__(self)
     1707        self.realm = realm
     1708
     1709
     1710    def connectionMade(self):
     1711        self.xmlstream.addObserver('/iq', self._onIQ, 1)
     1712
     1713
     1714    @asyncObserver
     1715    def _onIQ(self, element):
     1716        stanza = Stanza.fromElement(element)
     1717        return self.iqReceived(stanza)
     1718
     1719
     1720    def iqReceived(self, iq):
     1721        """
     1722        Handler for iq stazas to user accounts' connected resources.
     1723
     1724        If the recipient is a bare JID or there is no associated user, this
     1725        handler ignores the stanza, so that other handlers have a chance
     1726        to pick it up. If used, L{generic.FallbackHandler} will respond with a
     1727        C{'service-unavailable'} stanza error if no other handlers handle
     1728        the iq.
     1729        """
     1730        if not iq.recipient.user:
     1731            # This is not for a user.
     1732            return False
     1733        elif not iq.recipient.resource:
     1734            # This might be picked up by another handler.
     1735            return False
     1736
     1737        def gotUser(user):
     1738            user.deliverIQ(iq)
     1739
     1740        def notFound(failure):
     1741            failure.trap(NoSuchResource, NoSuchUser)
     1742            raise error.StanzaError('service-unavailable')
     1743
     1744        d = self.realm.lookupUser(iq.recipient.userhostJID())
     1745        d.addCallback(gotUser)
     1746        d.addErrback(notFound)
     1747        return d
     1748
     1749
     1750
     1751class AccountMessageHandler(MessageProtocol):
     1752
     1753    observerPriority = 1
     1754
     1755    def __init__(self, realm):
     1756        MessageProtocol.__init__(self)
     1757        self.realm = realm
     1758
     1759
     1760    def messageReceived(self, message):
     1761        """
     1762        Handler for message stanzas to user accounts.
     1763        """
     1764        if not message.recipient.user:
     1765            # This is not for a user.
     1766            return False
     1767
     1768        def gotUser(user):
     1769            user.deliverMessage(message)
     1770
     1771        def eb(failure):
     1772            failure.trap(NoSuchUser, NoSuchResource, NotImplementedError)
     1773            raise error.StanzaError('service-unavailable')
     1774
     1775        d = self.realm.lookupUser(message.recipient.userhostJID())
     1776        d.addCallback(gotUser)
     1777        d.addErrback(eb)
     1778        return d
     1779
     1780
     1781
     1782class AccountPresenceHandler(PresenceProtocol):
     1783
     1784    def __init__(self, realm):
     1785        PresenceProtocol.__init__(self)
     1786        self.realm = realm
     1787
     1788
     1789    def _deliverPresence(self, presence):
     1790        if not presence.recipient.user:
     1791            # This is not for a user.
     1792            return False
     1793
     1794        def gotUser(user):
     1795            user.deliverPresence(presence)
     1796
     1797        def notFound(failure):
     1798            failure.trap(NoSuchResource, NoSuchUser)
     1799            return
     1800
     1801        d = self.realm.lookupUser(presence.recipient.userhostJID())
     1802        d.addCallback(gotUser)
     1803        d.addErrback(notFound)
     1804        return d
     1805
     1806
     1807    def availableReceived(self, presence):
     1808        return self._deliverPresence(presence)
     1809
     1810
     1811    def unavailableReceived(self, presence):
     1812        return self._deliverPresence(presence)
     1813
     1814
     1815    def subscribedReceived(self, presence):
     1816        log.msg("%r subscribed %s to its presence" % (presence.sender,
     1817                                                      presence.recipient))
     1818        return self._deliverPresence(presence)
     1819
     1820
     1821    def unsubscribedReceived(self, presence):
     1822        log.msg("%r unsubscribed %s from its presence" % (presence.sender,
     1823                                                          presence.recipient))
     1824        return self._deliverPresence(presence)
     1825
     1826
     1827    def subscribeReceived(self, presence):
     1828        log.msg("%r requests subscription to %s" % (presence.sender,
     1829                                                    presence.recipient))
     1830        return self._deliverPresence(presence)
     1831
     1832
     1833    def unsubscribeReceived(self, presence):
     1834        log.msg("%r requests unsubscription from %s" % (presence.sender,
     1835                                                        presence.recipient))
     1836        return self._deliverPresence(presence)
     1837
     1838
     1839    def probeReceived(self, presence):
     1840        if not presence.recipient.user:
     1841            # This is not for a user.
     1842            return False
     1843
     1844        def gotUser(user):
     1845            return user.getPresences(presence.sender.userhostJID())
     1846
     1847        def notSubscribed(failure):
     1848            failure.trap(NoSuchUser, NotSubscribed)
     1849            response = SubscriptionPresence(recipient=presence.sender,
     1850                                            sender=presence.recipient)
     1851            response.stanzaType = 'unsubscribed'
     1852            return [response]
     1853
     1854        def sendPresences(userPresences):
     1855            for userPresence in userPresences:
     1856                self.parent.multicast(userPresence, [presence.sender])
     1857
     1858        d = self.realm.lookupUser(presence.recipient.userhostJID())
     1859        d.addCallback(gotUser)
     1860        d.addErrback(notSubscribed)
     1861        d.addCallback(sendPresences)
     1862        return d
     1863
     1864
     1865
     1866class UserSessionPresenceProtocol(PresenceProtocol):
     1867    """
     1868    Presence protocol for user client sessions.
     1869    """
     1870
     1871    def _stampContactJID(self, presence):
     1872        """
     1873        Stamp the contact JID to be a bare JID.
     1874        """
     1875        if presence.recipient.resource:
     1876            contactJID = presence.recipient.userhostJID()
     1877            presence.element['to'] = contactJID.userhost()
     1878
     1879
     1880    def availableReceived(self, presence):
     1881        if presence.recipient:
     1882            # Pass through directed presence.
     1883            return False
     1884        else:
     1885            session = self.xmlstream.avatar
     1886            sendProbe = not session.presence
     1887
     1888            session.broadcastPresence(presence, available=True)
     1889
     1890            if sendProbe:
     1891                session.probePresence()
     1892
     1893            return True
     1894
     1895
     1896    def unavailableReceived(self, presence):
     1897        if presence.recipient:
     1898            # Pass through directed presence.
     1899            return False
     1900        else:
     1901            session = self.xmlstream.avatar
     1902            session.broadcastPresence(presence, available=False)
     1903            return True
     1904
     1905
     1906    def subscribedReceived(self, presence):
     1907        """
     1908        Subscription approval confirmation was received.
     1909        """
     1910        self._stampContactJID(presence)
     1911        return False
     1912
     1913
     1914    def unsubscribedReceived(self, presence):
     1915        """
     1916        Unsubscription confirmation was received.
     1917        """
     1918        self._stampContactJID(presence)
     1919        return False
     1920
     1921
     1922    def subscribeReceived(self, presence):
     1923        """
     1924        Subscription request was received.
     1925        """
     1926        self._stampContactJID(presence)
     1927        return False
     1928
     1929
     1930    def unsubscribeReceived(self, presence):
     1931        """
     1932        Unsubscription request was received.
     1933        """
     1934        self._stampContactJID(presence)
     1935        return False
     1936
     1937
     1938    def probeReceived(self, presence):
     1939        """
     1940        Probe presence was received.
     1941        """
     1942        return False
Note: See TracBrowser for help on using the repository browser.