Changeset 128:db5de9ee45fa


Ignore:
Timestamp:
Jun 4, 2009, 10:15:16 AM (11 years ago)
Author:
Ralph Meijer <ralphm@…>
Branch:
wokkel-muc-client-support-24
Parents:
127:1610e7a3b777 (diff), 60:e5e6ff37ea27 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge in trunk changes.

Location:
wokkel
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • wokkel/disco.py

    r49 r128  
    409409
    410410
     411class DiscoRequest(xmlstream.IQ):
     412    """
     413    Disco request.
     414
     415    @ivar namespace: Request namespace.
     416    @type namespace: C{str}
     417    @ivar method: Type attribute of the IQ request. Either C{'set'} or C{'get'}
     418    @type method: C{str}
     419    """
     420
     421    def __init__(self, xs, namespace=NS, method='get'):
     422        xmlstream.IQ.__init__(self, xs, method)
     423        self.addElement((namespace, 'query'))
     424
     425
     426
    411427class DiscoHandler(XMPPHandler, IQHandlerMixin):
    412428    """
  • wokkel/disco.py

    r108 r128  
    11# -*- test-case-name: wokkel.test.test_disco -*-
    22#
    3 # Copyright (c) 2003-2008 Ralph Meijer
     3# Copyright (c) 2003-2009 Ralph Meijer
    44# See LICENSE for details.
    55
     
    1515from twisted.words.xish import domish
    1616
     17from wokkel import data_form
    1718from wokkel.iwokkel import IDisco
    1819from wokkel.subprotocols import IQHandlerMixin, XMPPHandler
    1920
    20 NS = 'http://jabber.org/protocol/disco'
    21 NS_INFO = NS + '#info'
    22 NS_ITEMS = NS + '#items'
     21NS_DISCO = 'http://jabber.org/protocol/disco'
     22NS_DISCO_INFO = NS_DISCO + '#info'
     23NS_DISCO_ITEMS = NS_DISCO + '#items'
    2324
    2425IQ_GET = '/iq[@type="get"]'
    25 DISCO_INFO = IQ_GET + '/query[@xmlns="' + NS_INFO + '"]'
    26 DISCO_ITEMS = IQ_GET + '/query[@xmlns="' + NS_ITEMS + '"]'
    27 
    28 class DiscoFeature(domish.Element):
    29     """
    30     Element representing an XMPP service discovery feature.
    31     """
    32 
    33     def __init__(self, feature):
    34         domish.Element.__init__(self, (NS_INFO, 'feature'),
    35                                 attribs={'var': feature})
    36 
    37 
    38 class DiscoIdentity(domish.Element):
    39     """
    40     Element representing an XMPP service discovery identity.
    41     """
    42 
    43     def __init__(self, category, type, name = None):
    44         domish.Element.__init__(self, (NS_INFO, 'identity'),
    45                                 attribs={'category': category,
    46                                          'type': type})
    47         if name:
    48             self['name'] = name
    49 
    50 
    51 class DiscoItem(domish.Element):
    52     """
    53     Element representing an XMPP service discovery item.
    54     """
    55 
    56     def __init__(self, jid, node='', name=None):
    57         domish.Element.__init__(self, (NS_ITEMS, 'item'),
    58                                 attribs={'jid': jid.full()})
    59         if node:
    60             self['node'] = node
    61 
    62         if name:
    63             self['name'] = name
     26DISCO_INFO = IQ_GET + '/query[@xmlns="' + NS_DISCO_INFO + '"]'
     27DISCO_ITEMS = IQ_GET + '/query[@xmlns="' + NS_DISCO_ITEMS + '"]'
     28
     29class DiscoFeature(unicode):
     30    """
     31    XMPP service discovery feature.
     32
     33    This extends C{unicode} to convert to and from L{domish.Element}, but
     34    further behaves identically.
     35    """
     36
     37    def toElement(self):
     38        """
     39        Render to a DOM representation.
     40
     41        @rtype: L{domish.Element}.
     42        """
     43        element = domish.Element((NS_DISCO_INFO, 'feature'))
     44        element['var'] = unicode(self)
     45        return element
     46
     47
     48    @staticmethod
     49    def fromElement(element):
     50        """
     51        Parse a DOM representation into a L{DiscoFeature} instance.
     52
     53        @param element: Element that represents the disco feature.
     54        @type element: L{domish.Element}.
     55        @rtype L{DiscoFeature}.
     56        """
     57        featureURI = element.getAttribute('var', u'')
     58        feature = DiscoFeature(featureURI)
     59        return feature
     60
     61
     62
     63class DiscoIdentity(object):
     64    """
     65    XMPP service discovery identity.
     66
     67    @ivar category: The identity category.
     68    @type category: C{unicode}
     69    @ivar type: The identity type.
     70    @type type: C{unicode}
     71    @ivar name: The optional natural language name for this entity.
     72    @type name: C{unicode}
     73    """
     74
     75    def __init__(self, category, idType, name=None):
     76        self.category = category
     77        self.type = idType
     78        self.name = name
     79
     80
     81    def toElement(self):
     82        """
     83        Generate a DOM representation.
     84
     85        @rtype: L{domish.Element}.
     86        """
     87        element = domish.Element((NS_DISCO_INFO, 'identity'))
     88        if self.category:
     89            element['category'] = self.category
     90        if self.type:
     91            element['type'] = self.type
     92        if self.name:
     93            element['name'] = self.name
     94        return element
     95
     96
     97    @staticmethod
     98    def fromElement(element):
     99        """
     100        Parse a DOM representation into a L{DiscoIdentity} instance.
     101
     102        @param element: Element that represents the disco identity.
     103        @type element: L{domish.Element}.
     104        @rtype L{DiscoIdentity}.
     105        """
     106        category = element.getAttribute('category')
     107        idType = element.getAttribute('type')
     108        name = element.getAttribute('name')
     109        feature = DiscoIdentity(category, idType, name)
     110        return feature
     111
     112
     113
     114class DiscoInfo(object):
     115    """
     116    XMPP service discovery info.
     117
     118    @ivar nodeIdentifier: The optional node this info applies to.
     119    @type nodeIdentifier: C{unicode}
     120    @ivar features: Features as L{DiscoFeature}.
     121    @type features: C{set)
     122    @ivar identities: Identities as a mapping from (category, type) to name,
     123                      all C{unicode}.
     124    @type identities: C{dict}
     125    @ivar extensions: Service discovery extensions as a mapping from the
     126                      extension form's C{FORM_TYPE} (C{unicode}) to
     127                      L{data_form.Form}. Forms with no C{FORM_TYPE} field
     128                      are mapped as C{None}. Note that multiple forms
     129                      with the same C{FORM_TYPE} have the last in sequence
     130                      prevail.
     131    @type extensions: C{dict}
     132    @ivar _items: Sequence of added items.
     133    @type _items: C{list}
     134    """
     135
     136    def __init__(self):
     137        self.nodeIdentifier = ''
     138        self.features = set()
     139        self.identities = {}
     140        self.extensions = {}
     141        self._items = []
     142
     143
     144    def __iter__(self):
     145        """
     146        Iterator over sequence of items in the order added.
     147        """
     148        return iter(self._items)
     149
     150
     151    def append(self, item):
     152        """
     153        Add a piece of service discovery info.
     154
     155        @param item: A feature, identity or extension form.
     156        @type item: L{DiscoFeature}, L{DiscoIdentity} or L{data_form.Form}
     157        """
     158        self._items.append(item)
     159
     160        if isinstance(item, DiscoFeature):
     161            self.features.add(item)
     162        elif isinstance(item, DiscoIdentity):
     163            self.identities[(item.category, item.type)] = item.name
     164        elif isinstance(item, data_form.Form):
     165            self.extensions[item.formNamespace] = item
     166
     167
     168    def toElement(self):
     169        """
     170        Generate a DOM representation.
     171
     172        This takes the items added with C{append} to create a DOM
     173        representation of service discovery information.
     174
     175        @rtype: L{domish.Element}.
     176        """
     177        element = domish.Element((NS_DISCO_INFO, 'query'))
     178
     179        if self.nodeIdentifier:
     180            element['node'] = self.nodeIdentifier
     181
     182        for item in self:
     183            element.addChild(item.toElement())
     184
     185        return element
     186
     187
     188    @staticmethod
     189    def fromElement(element):
     190        """
     191        Parse a DOM representation into a L{DiscoInfo} instance.
     192
     193        @param element: Element that represents the disco info.
     194        @type element: L{domish.Element}.
     195        @rtype L{DiscoInfo}.
     196        """
     197
     198        info = DiscoInfo()
     199
     200        info.nodeIdentifier = element.getAttribute('node', '')
     201
     202        for child in element.elements():
     203            item = None
     204
     205            if (child.uri, child.name) == (NS_DISCO_INFO, 'feature'):
     206                item = DiscoFeature.fromElement(child)
     207            elif (child.uri, child.name) == (NS_DISCO_INFO, 'identity'):
     208                item = DiscoIdentity.fromElement(child)
     209            elif (child.uri, child.name) == (data_form.NS_X_DATA, 'x'):
     210                item = data_form.Form.fromElement(child)
     211
     212            if item:
     213                info.append(item)
     214
     215        return info
     216
     217
     218
     219class DiscoItem(object):
     220    """
     221    XMPP service discovery item.
     222
     223    @ivar entity: The entity holding the item.
     224    @type entity: L{jid.JID}
     225    @ivar nodeIdentifier: The optional node identifier for the item.
     226    @type nodeIdentifier: C{unicode}
     227    @ivar name: The optional natural language name for this entity.
     228    @type name: C{unicode}
     229    """
     230
     231    def __init__(self, entity, nodeIdentifier='', name=None):
     232        self.entity = entity
     233        self.nodeIdentifier = nodeIdentifier
     234        self.name = name
     235
     236
     237    def toElement(self):
     238        """
     239        Generate a DOM representation.
     240
     241        @rtype: L{domish.Element}.
     242        """
     243        element = domish.Element((NS_DISCO_ITEMS, 'item'))
     244        if self.entity:
     245            element['jid'] = self.entity.full()
     246        if self.nodeIdentifier:
     247            element['node'] = self.nodeIdentifier
     248        if self.name:
     249            element['name'] = self.name
     250        return element
     251
     252
     253    @staticmethod
     254    def fromElement(element):
     255        """
     256        Parse a DOM representation into a L{DiscoItem} instance.
     257
     258        @param element: Element that represents the disco iitem.
     259        @type element: L{domish.Element}.
     260        @rtype L{DiscoItem}.
     261        """
     262        try:
     263            entity = jid.JID(element.getAttribute('jid', ' '))
     264        except jid.InvalidFormat:
     265            entity = None
     266        nodeIdentifier = element.getAttribute('node', '')
     267        name = element.getAttribute('name')
     268        feature = DiscoItem(entity, nodeIdentifier, name)
     269        return feature
     270
     271
     272
     273class DiscoItems(object):
     274    """
     275    XMPP service discovery items.
     276
     277    @ivar nodeIdentifier: The optional node this info applies to.
     278    @type nodeIdentifier: C{unicode}
     279    @ivar _items: Sequence of added items.
     280    @type _items: C{list}
     281    """
     282
     283    def __init__(self):
     284        self.nodeIdentifier = ''
     285        self._items = []
     286
     287
     288    def __iter__(self):
     289        """
     290        Iterator over sequence of items in the order added.
     291        """
     292        return iter(self._items)
     293
     294
     295    def append(self, item):
     296        """
     297        Append item to the sequence of items.
     298
     299        @param item: Item to be added.
     300        @type item: L{DiscoItem}
     301        """
     302        self._items.append(item)
     303
     304
     305    def toElement(self):
     306        """
     307        Generate a DOM representation.
     308
     309        This takes the items added with C{append} to create a DOM
     310        representation of service discovery items.
     311
     312        @rtype: L{domish.Element}.
     313        """
     314        element = domish.Element((NS_DISCO_ITEMS, 'query'))
     315
     316        if self.nodeIdentifier:
     317            element['node'] = self.nodeIdentifier
     318
     319        for item in self:
     320            element.addChild(item.toElement())
     321
     322        return element
     323
     324
     325    @staticmethod
     326    def fromElement(element):
     327        """
     328        Parse a DOM representation into a L{DiscoItems} instance.
     329
     330        @param element: Element that represents the disco items.
     331        @type element: L{domish.Element}.
     332        @rtype L{DiscoItems}.
     333        """
     334
     335        info = DiscoItems()
     336
     337        info.nodeIdentifier = element.getAttribute('node', '')
     338
     339        for child in element.elements():
     340            if (child.uri, child.name) == (NS_DISCO_ITEMS, 'item'):
     341                item = DiscoItem.fromElement(child)
     342                info.append(item)
     343
     344        return info
     345
     346
     347
     348class _DiscoRequest(xmlstream.IQ):
     349    """
     350    Element representing an XMPP service discovery request.
     351    """
     352
     353    def __init__(self, xs, namespace, nodeIdentifier=''):
     354        """
     355        Initialize the request.
     356
     357        @param xs: XML Stream the request should go out on.
     358        @type xs: L{xmlstream.XmlStream}
     359        @param namespace: Request namespace.
     360        @type namespace: C{str}
     361        @param nodeIdentifier: Node to request info from.
     362        @type nodeIdentifier: C{unicode}
     363        """
     364        xmlstream.IQ.__init__(self, xs, "get")
     365        query = self.addElement((namespace, 'query'))
     366        if nodeIdentifier:
     367            query['node'] = nodeIdentifier
     368
     369
     370
     371class DiscoClientProtocol(XMPPHandler):
     372    """
     373    XMPP Service Discovery client protocol.
     374    """
     375
     376    def requestInfo(self, entity, nodeIdentifier=''):
     377        """
     378        Request information discovery from a node.
     379
     380        @param entity: Entity to send the request to.
     381        @type entity: L{jid.JID}
     382        @param nodeIdentifier: Optional node to request info from.
     383        @type nodeIdentifier: C{unicode}
     384        """
     385
     386        request = _DiscoRequest(self.xmlstream, NS_DISCO_INFO, nodeIdentifier)
     387
     388        d = request.send(entity.full())
     389        d.addCallback(lambda iq: DiscoInfo.fromElement(iq.query))
     390        return d
     391
     392
     393    def requestItems(self, entity, nodeIdentifier=''):
     394        """
     395        Request items discovery from a node.
     396
     397        @param entity: Entity to send the request to.
     398        @type entity: L{jid.JID}
     399        @param nodeIdentifier: Optional node to request info from.
     400        @type nodeIdentifier: C{unicode}
     401        """
     402
     403        request = _DiscoRequest(self.xmlstream, NS_DISCO_ITEMS, nodeIdentifier)
     404
     405        d = request.send(entity.full())
     406        d.addCallback(lambda iq: DiscoItems.fromElement(iq.query))
     407        return d
     408
    64409
    65410
     
    96441        self.xmlstream.addObserver(DISCO_ITEMS, self.handleRequest)
    97442
    98     def _error(self, failure):
    99         failure.trap(defer.FirstError)
    100         return failure.value.subFailure
    101443
    102444    def _onDiscoInfo(self, iq):
     445        """
     446        Called for incoming disco info requests.
     447
     448        @param iq: The request iq element.
     449        @type iq: L{Element<twisted.words.xish.domish.Element>}
     450        """
    103451        requestor = jid.internJID(iq["from"])
    104452        target = jid.internJID(iq["to"])
    105453        nodeIdentifier = iq.query.getAttribute("node", '')
    106454
    107         def toResponse(results):
    108             info = []
    109             for i in results:
    110                 info.extend(i[1])
    111 
     455        def toResponse(info):
    112456            if nodeIdentifier and not info:
    113457                raise error.StanzaError('item-not-found')
    114458            else:
    115                 response = domish.Element((NS_INFO, 'query'))
     459                response = DiscoInfo()
     460                response.nodeIdentifier = nodeIdentifier
    116461
    117462                for item in info:
    118                     response.addChild(item)
    119 
    120             return response
    121 
    122         dl = []
    123         for handler in self.parent:
    124             if IDisco.providedBy(handler):
    125                 dl.append(handler.getDiscoInfo(requestor, target,
    126                                                nodeIdentifier))
    127 
    128         d = defer.DeferredList(dl, fireOnOneErrback=1, consumeErrors=1)
    129         d.addCallbacks(toResponse, self._error)
     463                    response.append(item)
     464
     465            return response.toElement()
     466
     467        d = self.info(requestor, target, nodeIdentifier)
     468        d.addCallback(toResponse)
    130469        return d
    131470
     471
    132472    def _onDiscoItems(self, iq):
     473        """
     474        Called for incoming disco items requests.
     475
     476        @param iq: The request iq element.
     477        @type iq: L{Element<twisted.words.xish.domish.Element>}
     478        """
    133479        requestor = jid.internJID(iq["from"])
    134480        target = jid.internJID(iq["to"])
    135481        nodeIdentifier = iq.query.getAttribute("node", '')
    136482
    137         def toResponse(results):
    138             items = []
    139             for i in results:
    140                 items.extend(i[1])
    141 
    142             response = domish.Element((NS_ITEMS, 'query'))
     483        def toResponse(items):
     484            response = DiscoItems()
     485            response.nodeIdentifier = nodeIdentifier
    143486
    144487            for item in items:
    145                 response.addChild(item)
    146 
    147             return response
    148 
    149         dl = []
    150         for handler in self.parent:
    151             if IDisco.providedBy(handler):
    152                 dl.append(handler.getDiscoItems(requestor, target,
    153                                                 nodeIdentifier))
    154 
    155         d = defer.DeferredList(dl, fireOnOneErrback=1, consumeErrors=1)
    156         d.addCallbacks(toResponse, self._error)
     488                response.append(item)
     489
     490            return response.toElement()
     491
     492        d = self.items(requestor, target, nodeIdentifier)
     493        d.addCallback(toResponse)
    157494        return d
     495
     496
     497    def _gatherResults(self, deferredList):
     498        """
     499        Gather results from a list of deferreds.
     500
     501        Similar to L{defer.gatherResults}, but flattens the returned results,
     502        consumes errors after the first one and fires the errback of the
     503        returned deferred with the failure of the first deferred that fires its
     504        errback.
     505
     506        @param deferredList: List of deferreds for which the results should be
     507                             gathered.
     508        @type deferredList: C{list}
     509        @return: Deferred that fires with a list of gathered results.
     510        @rtype: L{defer.Deferred}
     511        """
     512        def cb(resultList):
     513            results = []
     514            for success, value in resultList:
     515                results.extend(value)
     516            return results
     517
     518        def eb(failure):
     519            failure.trap(defer.FirstError)
     520            return failure.value.subFailure
     521
     522        d = defer.DeferredList(deferredList, fireOnOneErrback=1,
     523                                             consumeErrors=1)
     524        d.addCallbacks(cb, eb)
     525        return d
     526
     527
     528    def info(self, requestor, target, nodeIdentifier):
     529        """
     530        Inspect all sibling protocol handlers for disco info.
     531
     532        Calls the L{getDiscoInfo<IDisco.getDiscoInfo>} method on all child
     533        handlers of the parent, that provide L{IDisco}.
     534
     535        @param requestor: The entity that sent the request.
     536        @type requestor: L{JID<twisted.words.protocols.jabber.jid.JID>}
     537        @param target: The entity the request was sent to.
     538        @type target: L{JID<twisted.words.protocols.jabber.jid.JID>}
     539        @param nodeIdentifier: The optional node being queried, or C{''}.
     540        @type nodeIdentifier: C{unicode}
     541        @return: Deferred with the gathered results from sibling handlers.
     542        @rtype: L{defer.Deferred}
     543        """
     544        dl = [handler.getDiscoInfo(requestor, target, nodeIdentifier)
     545              for handler in self.parent
     546              if IDisco.providedBy(handler)]
     547        return self._gatherResults(dl)
     548
     549
     550    def items(self, requestor, target, nodeIdentifier):
     551        """
     552        Inspect all sibling protocol handlers for disco items.
     553
     554        Calls the L{getDiscoItems<IDisco.getDiscoItems>} method on all child
     555        handlers of the parent, that provide L{IDisco}.
     556
     557        @param requestor: The entity that sent the request.
     558        @type requestor: L{JID<twisted.words.protocols.jabber.jid.JID>}
     559        @param target: The entity the request was sent to.
     560        @type target: L{JID<twisted.words.protocols.jabber.jid.JID>}
     561        @param nodeIdentifier: The optional node being queried, or C{''}.
     562        @type nodeIdentifier: C{unicode}
     563        @return: Deferred with the gathered results from sibling handlers.
     564        @rtype: L{defer.Deferred}
     565        """
     566        dl = [handler.getDiscoItems(requestor, target, nodeIdentifier)
     567              for handler in self.parent
     568              if IDisco.providedBy(handler)]
     569        return self._gatherResults(dl)
  • wokkel/iwokkel.py

    r59 r128  
    768768        @rtype: L{defer.Deferred}
    769769        """
     770
     771
     772
     773class IMUCClient(Interface):
     774    """
     775    Multi-User Chat Client
     776
     777    A client interface to XEP-045 : http://xmpp.org/extensions/xep-0045.html
     778
     779    """
     780
     781    def receivedSubject(room, subject):
     782        """
     783        A subject is received when you join a room and when the subject is changed. This
     784        method is triggered by one of those two events.
     785
     786        @param room: The room the subject was accepted for.
     787        @type room: L{muc.Room}
     788
     789        @param subject: The subject of the given room.
     790        @type subject: C{unicode}
     791        """
     792
     793
     794    def receivedHistory(room, user, message, history, frm=None):
     795        """
     796        Past messages from a chat room has been received. This occurs when you join a room.
     797
     798
     799        """
     800
     801   
     802    def disco(entity, type='info'):
     803        """Send disco queries to a XMPP entity
     804
     805        @param entity: A XMPP entity to send the disco request to.
     806        @type entity: C{unicode}
     807
     808        @param type: Optional argument to determine the type of discovery being done.
     809        @type type: C{str}
     810
     811        """
     812
     813       
     814
     815    def configure(room_jid, fields=[]):
     816        """Configure a room. When a user has administration privledges they can configure
     817        a room.
     818
     819        @param room_jid: A XMPP entity for the room.
     820        @type room_jid: L{jid.JID}
     821
     822        @param fields: A list of fields to change or add to the room's configuration.
     823        @type fields: C{list}
     824
     825        """
     826
     827    def getConfigureForm(room_jid):
     828        """
     829        In order to know the fields to change in a room you will need to get the form.
     830       
     831        @param room_jid: The room you want the configuration form from.
     832        @type room_jid: L{jid.JID}
     833
     834        """
     835
     836    def join(server, room, nick):
     837        """
     838        Join a multi-user chat room.
     839
     840        @param server: The server the room is on.
     841        @type server: C{str}
     842
     843        @param room: The room name.
     844        @type room: C{str}
     845       
     846        @param nick: The nick name you want when you join the room.
     847        @type nick: C{str}
     848
     849        """
     850
     851
     852    def leave(room_jid):
     853        """
     854        Leave a multi-user chat room.
     855
     856        @param room_jid: The room you want the configuration form from.
     857        @type room_jid: L{jid.JID}
     858
     859        """
     860
     861    def userJoinedRoom(room, user):
     862        """User has joined the room.
     863
     864        @param room: The room the user joined.
     865        @type  room: L{muc.Room}
     866
     867        @param user: The user that joined the room.
     868        @type  user: L{muc.User}
     869
     870        """
     871   
     872
     873    def groupChat(to, message, children=None):
     874        """Send a groupchat message to a room.
     875
     876        """
     877
     878
     879    def chat(to, message, children=None):
     880        """
     881
     882        """
     883
     884
     885    def password(to, password):
     886        """
     887        """
     888   
     889    def register(to, fields=[]):
     890        """
     891        """
     892
     893
     894    def subject(to, subject):
     895        """
     896        """
     897
     898    def voice(to):
     899        """
     900        """
     901
     902
     903    def history(to, message_list):
     904        """
     905        """
     906
     907    def ban(to, ban_jid, frm, reason=None):
     908        """
     909        """
     910
     911
     912    def kick(to, kick_jid, frm, reason=None):
     913        """
     914        """
  • wokkel/iwokkel.py

    r113 r128  
    1616    """
    1717
    18     manager = Attribute("""XML stream manager""")
     18    parent = Attribute("""XML stream manager for this handler""")
    1919    xmlstream = Attribute("""The managed XML stream""")
    2020
     
    2626        """
    2727
     28
    2829    def disownHandlerParent(parent):
    2930        """
     
    3233        @type parent: L{IXMPPHandlerCollection}
    3334        """
     35
    3436
    3537    def makeConnection(xs):
     
    4547        @type xs: L{XmlStream<twisted.words.protocols.jabber.XmlStream>}
    4648        """
     49
    4750
    4851    def connectionMade():
     
    5558        """
    5659
     60
    5761    def connectionInitialized():
    5862        """
     
    6468        """
    6569
     70
    6671    def connectionLost(reason):
    6772        """
     
    7378        @type reason: L{twisted.python.failure.Failure}
    7479        """
     80
    7581
    7682
     
    8793        """
    8894
     95
    8996    def addHandler(handler):
    9097        """
     
    94101        """
    95102
     103
    96104    def removeHandler(handler):
    97105        """
     
    100108        @type handler: L{IXMPPHandler}
    101109        """
     110
    102111
    103112
     
    270279        """
    271280
    272     def notifyDelete(service, nodeIdentifier, subscriptions):
     281
     282    def notifyDelete(service, nodeIdentifier, subscribers,
     283                     redirectURI=None):
    273284        """
    274285        Send out node deletion notifications.
     
    278289        @param nodeIdentifier: The identifier of the node that was deleted.
    279290        @type nodeIdentifier: C{unicode}
    280         @param subscriptions: The subscriptions for which a notification should
    281                               be sent out.
    282         @type subscriptions: C{list} of L{jid.JID}
     291        @param subscribers: The subscribers for which a notification should
     292                            be sent out.
     293        @type subscribers: C{list} of L{jid.JID}
     294        @param redirectURI: Optional XMPP URI of another node that subscribers
     295                            are redirected to.
     296        @type redirectURI: C{str}
    283297        """
    284298
     
    387401        that option in a dictionary:
    388402
    389         - C{'type'} (C{str}): The option's type (see
    390           L{Field<wokkel.data_form.Field>}'s doc string for possible values).
    391         - C{'label'} (C{unicode}): A human readable label for this option.
    392         - C{'options'} (C{dict}): Optional list of possible values for this
    393           option.
     403         - C{'type'} (C{str}): The option's type (see
     404           L{Field<wokkel.data_form.Field>}'s doc string for possible values).
     405         - C{'label'} (C{unicode}): A human readable label for this option.
     406         - C{'options'} (C{dict}): Optional list of possible values for this
     407           option.
    394408
    395409        Example::
     
    414428        """
    415429
    416     def getDefaultConfiguration(requestor, service):
     430    def getDefaultConfiguration(requestor, service, nodeType):
    417431        """
    418432        Called when a default node configuration request has been received.
     
    422436        @param service: The entity the request was addressed to.
    423437        @type service: L{jid.JID}
     438        @param nodeType: The type of node for which the configuration is
     439                         retrieved, C{'leaf'} or C{'collection'}.
     440        @type nodeType: C{str}
    424441        @return: A deferred that fires with a C{dict} representing the default
    425442                 node configuration. Keys are C{str}s that represent the
     
    511528        @type nodeIdentifier: C{unicode}
    512529        """
     530
     531
     532
     533class IPubSubResource(Interface):
     534
     535    def locateResource(request):
     536        """
     537        Locate a resource that will handle the request.
     538
     539        @param request: The publish-subscribe request.
     540        @type request: L{wokkel.pubsub.PubSubRequest}
     541        """
     542
     543
     544    def getInfo(requestor, service, nodeIdentifier):
     545        """
     546        Get node type and meta data.
     547
     548        @param requestor: The entity the request originated from.
     549        @type requestor: L{jid.JID}
     550        @param service: The publish-subscribe service entity.
     551        @type service: L{jid.JID}
     552        @param nodeIdentifier: Identifier of the node to request the info for.
     553        @type nodeIdentifier: L{unicode}
     554        @return: A deferred that fires with a dictionary. If not empty,
     555                 it must have the keys C{'type'} and C{'meta-data'} to keep
     556                 respectively the node type and a dictionary with the meta
     557                 data for that node.
     558        @rtype: L{defer.Deferred}
     559        """
     560
     561
     562    def getNodes(requestor, service, nodeIdentifier):
     563        """
     564        Get all nodes contained by this node.
     565
     566        @param requestor: The entity the request originated from.
     567        @type requestor: L{jid.JID}
     568        @param service: The publish-subscribe service entity.
     569        @type service: L{jid.JID}
     570        @param nodeIdentifier: Identifier of the node to request the childs for.
     571        @type nodeIdentifier: L{unicode}
     572        @return: A deferred that fires with a list of child node identifiers.
     573        @rtype: L{defer.Deferred}
     574        """
     575
     576
     577    def getConfigurationOptions():
     578        """
     579        Retrieve all known node configuration options.
     580
     581        The returned dictionary holds the possible node configuration options
     582        by option name. The value of each entry represents the specifics for
     583        that option in a dictionary:
     584
     585         - C{'type'} (C{str}): The option's type (see
     586           L{Field<wokkel.data_form.Field>}'s doc string for possible values).
     587         - C{'label'} (C{unicode}): A human readable label for this option.
     588         - C{'options'} (C{dict}): Optional list of possible values for this
     589           option.
     590
     591        Example::
     592
     593            {
     594            "pubsub#persist_items":
     595                {"type": "boolean",
     596                 "label": "Persist items to storage"},
     597            "pubsub#deliver_payloads":
     598                {"type": "boolean",
     599                 "label": "Deliver payloads with event notifications"},
     600            "pubsub#send_last_published_item":
     601                {"type": "list-single",
     602                 "label": "When to send the last published item",
     603                 "options": {
     604                     "never": "Never",
     605                     "on_sub": "When a new subscription is processed"}
     606                }
     607            }
     608
     609        @rtype: C{dict}.
     610        """
     611
     612
     613    def publish(request):
     614        """
     615        Called when a publish request has been received.
     616
     617        @param request: The publish-subscribe request.
     618        @type request: L{wokkel.pubsub.PubSubRequest}
     619        @return: deferred that fires on success.
     620        @rtype: L{defer.Deferred}
     621        """
     622
     623
     624    def subscribe(request):
     625        """
     626        Called when a subscribe request has been received.
     627
     628        @param request: The publish-subscribe request.
     629        @type request: L{wokkel.pubsub.PubSubRequest}
     630        @return: A deferred that fires with a
     631                 L{Subscription<wokkel.pubsub.Subscription>}.
     632        @rtype: L{defer.Deferred}
     633        """
     634
     635
     636    def unsubscribe(request):
     637        """
     638        Called when a subscribe request has been received.
     639
     640        @param request: The publish-subscribe request.
     641        @type request: L{wokkel.pubsub.PubSubRequest}
     642        @return: A deferred that fires with C{None} when unsubscription has
     643                 succeeded.
     644        @rtype: L{defer.Deferred}
     645        """
     646
     647
     648    def subscriptions(request):
     649        """
     650        Called when a subscriptions retrieval request has been received.
     651
     652        @param request: The publish-subscribe request.
     653        @type request: L{wokkel.pubsub.PubSubRequest}
     654        @return: A deferred that fires with a C{list} of subscriptions as
     655                 L{Subscription<wokkel.pubsub.Subscription>}.
     656        @rtype: L{defer.Deferred}
     657        """
     658
     659
     660    def affiliations(request):
     661        """
     662        Called when a affiliations retrieval request has been received.
     663
     664        @param request: The publish-subscribe request.
     665        @type request: L{wokkel.pubsub.PubSubRequest}
     666        @return: A deferred that fires with a C{list} of affiliations as
     667                 C{tuple}s of (node identifier as C{unicode}, affiliation state
     668                 as C{str}). The affiliation can be C{'owner'}, C{'publisher'},
     669                 or C{'outcast'}.
     670        @rtype: L{defer.Deferred}
     671        """
     672
     673
     674    def create(request):
     675        """
     676        Called when a node creation request has been received.
     677
     678        @param request: The publish-subscribe request.
     679        @type request: L{wokkel.pubsub.PubSubRequest}
     680        @return: A deferred that fires with a C{unicode} that represents
     681                 the identifier of the new node.
     682        @rtype: L{defer.Deferred}
     683        """
     684
     685
     686    def default(request):
     687        """
     688        Called when a default node configuration request has been received.
     689
     690        @param request: The publish-subscribe request.
     691        @type request: L{wokkel.pubsub.PubSubRequest}
     692        @return: A deferred that fires with a C{dict} representing the default
     693                 node configuration. Keys are C{str}s that represent the
     694                 field name. Values can be of types C{unicode}, C{int} or
     695                 C{bool}.
     696        @rtype: L{defer.Deferred}
     697        """
     698
     699
     700    def configureGet(request):
     701        """
     702        Called when a node configuration retrieval request has been received.
     703
     704        @param request: The publish-subscribe request.
     705        @type request: L{wokkel.pubsub.PubSubRequest}
     706        @return: A deferred that fires with a C{dict} representing the node
     707                 configuration. Keys are C{str}s that represent the field name.
     708                 Values can be of types C{unicode}, C{int} or C{bool}.
     709        @rtype: L{defer.Deferred}
     710        """
     711
     712
     713    def configureSet(request):
     714        """
     715        Called when a node configuration change request has been received.
     716
     717        @param request: The publish-subscribe request.
     718        @type request: L{wokkel.pubsub.PubSubRequest}
     719        @return: A deferred that fires with C{None} when the node's
     720                 configuration has been changed.
     721        @rtype: L{defer.Deferred}
     722        """
     723
     724
     725    def items(request):
     726        """
     727        Called when a items retrieval request has been received.
     728
     729        @param request: The publish-subscribe request.
     730        @type request: L{wokkel.pubsub.PubSubRequest}
     731        @return: A deferred that fires with a C{list} of L{pubsub.Item}.
     732        @rtype: L{defer.Deferred}
     733        """
     734
     735
     736    def retract(request):
     737        """
     738        Called when a item retraction request has been received.
     739
     740        @param request: The publish-subscribe request.
     741        @type request: L{wokkel.pubsub.PubSubRequest}
     742        @return: A deferred that fires with C{None} when the given items have
     743                 been retracted.
     744        @rtype: L{defer.Deferred}
     745        """
     746
     747
     748    def purge(request):
     749        """
     750        Called when a node purge request has been received.
     751
     752        @param request: The publish-subscribe request.
     753        @type request: L{wokkel.pubsub.PubSubRequest}
     754        @return: A deferred that fires with C{None} when the node has been
     755                 purged.
     756        @rtype: L{defer.Deferred}
     757        """
     758
     759
     760    def delete(request):
     761        """
     762        Called when a node deletion request has been received.
     763
     764        @param request: The publish-subscribe request.
     765        @type request: L{wokkel.pubsub.PubSubRequest}
     766        @return: A deferred that fires with C{None} when the node has been
     767                 deleted.
     768        @rtype: L{defer.Deferred}
     769        """
     770
    513771
    514772
     
    655913        """
    656914        """
    657 
Note: See TracChangeset for help on using the changeset viewer.