Changeset 658

Show
Ignore:
Timestamp:
05/11/08 12:39:06 (7 months ago)
Author:
sylvain
Message:

Expanded simplechat example
Fixed presence/roster support

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • oss/headstock/headstock/api/contact.py

    r654 r658  
    1515 
    1616class Presence(Entity): 
    17     def __init__(self, from_jid, to_jid=None): 
    18         Entity.__init__(self, from_jid, to_jid
     17    def __init__(self, from_jid, to_jid=None, type=u'none', stanza_id=None): 
     18        Entity.__init__(self, from_jid, to_jid, type=type, stanza_id=stanza_id
    1919        self.status = None 
    2020        self.show = None 
    2121        self.priority = 0 
    22         self.subscription = u'none' 
    2322        self.foreign = [] 
    2423 
     
    2928    def from_element(e): 
    3029        p = Presence(JID.parse(e.get_attribute_value('from')), 
    31                      JID.parse(e.get_attribute_value('to'))) 
    32         p.subscription = e.get_attribute_value('type', None
     30                     JID.parse(e.get_attribute_value('to')), 
     31                     e.get_attribute_value('type', None)
    3332 
    3433        for child in e.xml_children: 
     
    5251        if p.to_jid: 
    5352            attrs[u'to'] = unicode(p.to_jid) 
    54         if p.subscription
    55             attrs[u'type'] = p.subscription 
     53        if p.type
     54            attrs[u'type'] = p.type 
    5655        e = E(u'presence', attributes=attrs, namespace=XMPP_CLIENT_NS) 
    5756 
     
    8584 
    8685class Roster(Entity): 
    87     def __init__(self, from_jid, to_jid): 
    88         Entity.__init__(self, from_jid, to_jid
     86    def __init__(self, from_jid, to_jid=None, type=u'get', stanza_id=None): 
     87        Entity.__init__(self, from_jid, to_jid, type=type, stanza_id=stanza_id
    8988        self.items = {} 
    9089 
     
    109108                 
    110109        return r 
     110 
     111    @staticmethod 
     112    def to_element(e): 
     113        iq = Entity.to_element(e) 
     114        if e.type != 'result': 
     115            query = E(u'query', namespace=XMPP_ROSTER_NS, parent=iq) 
     116            for item_id in e.items: 
     117                item = e.items[item_id] 
     118                attr = {u'jid': unicode(item.jid)} 
     119                if item.subscription: 
     120                    attr[u'subscription'] = item.subscription 
     121                if item.name: 
     122                    attr[u'name'] = item.name 
     123                if item.language: 
     124                    attr[u'language'] = item.language 
     125                i = E(u'item', namespace=XMPP_ROSTER_NS, 
     126                      attributes=attr, parent=query) 
     127                for group in item.groups: 
     128                    E(u'group', namespace=XMPP_ROSTER_NS, 
     129                      content=group, parent=i) 
     130        return iq 
     131         
  • oss/headstock/headstock/example/simplechat/simplechat.py

    r657 r658  
    3535     
    3636from headstock.protocol.core.stream import ClientStream, StreamError, SaslError 
    37 from headstock.protocol.core.presence import PresenceDispatcher, PresenceSubscriber 
     37from headstock.protocol.core.presence import PresenceDispatcher 
    3838from headstock.protocol.core.roster import RosterDispatcher, RosterNull 
    3939from headstock.protocol.core.message import MessageDispatcher, MessageEchoer 
     
    4545from headstock.lib.logger import Logger 
    4646from headstock.api.im import Message, Body, Event 
    47 from headstock.api.contact import Presence 
     47from headstock.api.contact import Presence, Roster, Item 
     48from headstock.api import Entity 
    4849from headstock.api.activity import Activity 
    4950from headstock.lib.utils import generate_unique 
     
    5859    Inboxes = {"inbox"        : "headstock.api.contact.Roster instance", 
    5960               "control"      : "stops the component", 
     61               "pushed"       : "roster stanzas pushed by the server", 
    6062               "jid"          : "headstock.api.jid.JID instance received from the server", 
    6163               "ask-activity" : "request activity status to the server for each roster contact"} 
     
    6466                "signal"      : "Shutdown signal", 
    6567                "message"     : "Message to send", 
     68                "result"      : "",  
    6669                "activity"    : "headstock.api.activity.Activity instance to send to the server"} 
    6770 
     
    9699                self.from_jid = self.recv('jid') 
    97100             
     101            if self.dataReady("pushed"): 
     102                roster = self.recv('pushed') 
     103                for nodeid in roster.items: 
     104                    self.send(Roster(from_jid=self.from_jid, to_jid=nodeid, 
     105                                     type=u'result', stanza_id=generate_unique()), 'result') 
     106                 
    98107            if self.dataReady("inbox"): 
    99108                roster = self.recv("inbox") 
     
    309318            yield 1 
    310319 
     320class PresenceHandler(component): 
     321    Inboxes = {"inbox"       : "headstock.api.contact.Presence instance", 
     322               "control"     : "Shutdown the client stream", 
     323               "subscribe"   : "", 
     324               "unsubscribe" : "",} 
     325     
     326    Outboxes = {"outbox" : "headstock.api.contact.Presence instance to return to the server", 
     327                "signal" : "Shutdown signal", 
     328                "roster" : "", 
     329                "log"    : "log",} 
     330     
     331    def __init__(self): 
     332        super(PresenceHandler, self).__init__() 
     333 
     334    def main(self): 
     335        while 1: 
     336            if self.dataReady("control"): 
     337                mes = self.recv("control") 
     338                 
     339                if isinstance(mes, shutdownMicroprocess) or isinstance(mes, producerFinished): 
     340                    self.send(producerFinished(), "signal") 
     341                    break 
     342 
     343            if self.dataReady("subscribe"): 
     344                p = self.recv("subscribe") 
     345                p.swap_jids() 
     346                 
     347                # Automatically accept any subscription requests 
     348                p = Presence(from_jid=p.from_jid, to_jid=unicode(p.to_jid), 
     349                             type=u'subscribed') 
     350                self.send(p, "outbox") 
     351                 
     352                # Automatically subscribe in return as well 
     353                p = Presence(from_jid=p.from_jid, to_jid=unicode(p.to_jid), 
     354                             type=u'subscribe') 
     355                self.send(p, "outbox") 
     356                 
     357            if self.dataReady("unsubscribe"): 
     358                p = self.recv("unsubscribe") 
     359                p.swap_jids() 
     360                 
     361                # We stop our subscription to the other user 
     362                p = Presence(from_jid=p.from_jid, to_jid=unicode(p.to_jid), 
     363                             type=u'unsubscribed') 
     364                self.send(p, "outbox") 
     365                 
     366                # We stop the other user's subscription 
     367                p = Presence(from_jid=p.from_jid, to_jid=unicode(p.to_jid), 
     368                             type=u'unsubscribe') 
     369                self.send(p, "outbox") 
     370 
     371                # We remove this user from our roster list 
     372                r = Roster(from_jid=p.from_jid, type=u'set') 
     373                i = Item(p.to_jid) 
     374                i.subscription = u'remove' 
     375                r.items[unicode(p.to_jid)] = i 
     376                self.send(r, 'roster') 
     377 
     378                # We tell the other user we're not available anymore 
     379                p = Presence(from_jid=p.from_jid, to_jid=unicode(p.to_jid), 
     380                             type=u'unavailable') 
     381                self.send(p, "outbox") 
     382                 
     383            if not self.anyReady(): 
     384                self.pause() 
     385   
     386            yield 1 
     387     
     388 
    311389class Client(component): 
    312390    Inboxes = {"inbox"    : "", 
     
    336414        return self.password 
    337415 
    338     def subscription_requested(self, p): 
    339         # If you don't accept the subscription request, simply return None 
    340         # otherwise returns "p" 
    341  
    342         # Note that you could for instance call your database, or ask the 
    343         # user, etc. 
    344         print "# %s wants to subscribe to you. Enter 'yes' to allow, 'no' otherwise" % str(p.from_jid) 
    345         allow = raw_input(">>> ") 
    346         if allow == 'yes': 
    347             p.swap_jids() 
    348             return p 
    349  
    350416    def shutdown(self): 
    351         p = Presence(self.jid) 
    352         p.subscription = u'unavailable' 
    353         self.send(Presence.to_element(p), 'forward') 
     417        self.send(Presence.to_element(Presence(self.jid, type=u'unavailable')), 'forward') 
    354418        self.send('OUTGOING : </stream:stream>', 'log') 
    355419        self.send('</stream:stream>', 'outbox')  
     
    408472                               rosterhandler = RosterHandler(self.jid), 
    409473                               msgdummyhandler = DummyMessageHandler(), 
     474                               presencehandler = PresenceHandler(), 
    410475                               presencedisp = PresenceDispatcher(), 
    411                                presencesub = PresenceSubscriber(self.subscription_requested), 
    412476                               rosterdisp = RosterDispatcher(), 
    413477                               msgdisp = MessageDispatcher(), 
     
    436500                                           ("xmpp", "%s.presence" % XMPP_CLIENT_NS): ("presencedisp", "inbox"), 
    437501                                           ("presencedisp", "log"): ('logger', "inbox"), 
    438                                            ("presencedisp", "xmpp.subscribe"): ("presencesub", "inbox"), 
    439                                            ("presencesub", "outbox"): ("xmpp", "forward"), 
     502                                           ("presencedisp", "xmpp.subscribe"): ("presencehandler", "subscribe"), 
     503                                           ("presencedisp", "xmpp.unsubscribe"): ("presencehandler", "unsubscribe"), 
     504                                           ("presencehandler", "outbox"): ("presencedisp", "forward"), 
     505                                           ("presencehandler", "roster"): ("rosterdisp", "forward"), 
     506                                           ("presencedisp", "outbox"): ("xmpp", "forward"), 
    440507 
    441508                                           # Roster 
    442509                                           ("xmpp", "%s.query" % XMPP_ROSTER_NS): ("rosterdisp", "inbox"), 
    443510                                           ("rosterdisp", "log"): ('logger', "inbox"), 
     511                                           ('rosterdisp', 'xmpp.set'): ('rosterhandler', 'pushed'), 
    444512                                           ('rosterdisp', 'xmpp.result'): ('rosterhandler', 'inbox'), 
     513                                           ('rosterhandler', 'result'): ('rosterdisp', 'forward'), 
     514                                           ("rosterdisp", "outbox"): ("xmpp", "forward"), 
    445515 
    446516                                           # Discovery 
  • oss/headstock/headstock/protocol/core/presence.py

    r652 r658  
    1212from bridge.common import XMPP_CLIENT_NS 
    1313 
    14 __all__ = ['PresenceDispatcher', 'PresenceSubscriber'
     14__all__ = ['PresenceDispatcher'
    1515 
    16 # Helper function 
    17 def create_presence(from_jid=None, to_jid=None, presence_type=None, status=None, show=None): 
    18     stanza = Stanza(u'presence', from_jid, to_jid, presence_type) 
    19     if status: 
    20         E(u'status', content=status, namespace=stanza.xml_ns, parent=stanza) 
    21     if show: 
    22         E(u'show', content=show, namespace=stanza.xml_ns, parent=stanza) 
    23          
    24     return stanza.to_element() 
    25      
    2616class PresenceDispatcher(component): 
    2717    Inboxes = {"inbox"              : "bridge.Element instance", 
    28                "control"            : "Shutdown the client stream", 
     18               "control"            : "stops the component", 
    2919               "forward"            : "headstock.api.contact.Presence instance to be sent back to the client. Transforms the instance to a bridge.Element instance and puts it into the 'outbox'", 
    3020               } 
     
    3424                "log"               : "log", 
    3525                "unknown"           : "Unknown element that could not be dispatched properly", 
     26                "xmpp.unavailable"  : "Notifiy an entity of one's availability", 
    3627                "xmpp.error"        : "An error has occurred regarding processing or delivery of a presence stanza", 
    3728                "xmpp.probe"        : "Server to server message to check the presence of an entity", 
     
    7869   
    7970            yield 1 
    80  
    81 class PresenceSubscriber(component): 
    82     Inboxes = {"inbox"              : "headstock.api.contact.Presence instance", 
    83                "control"            : "Shutdown the client stream", 
    84                } 
    85      
    86     Outboxes = {"outbox"            : "bridge.Element instance to sent back to the client", 
    87                 "signal"            : "Shutdown signal", 
    88                 } 
    89      
    90     def __init__(self, subscribe_cb): 
    91         """ 
    92         Component that handles passing the message to the server that a subscribtion 
    93         was either allowed or refused. 
    94  
    95         The ``subscribe_cb`` must be a callable that takes a headstock.api.contact.Presence instance 
    96         and returns either that instance to allow the subscription or None to reject it. 
    97         """ 
    98         super(PresenceSubscriber, self).__init__() 
    99         self.subscribe_cb = subscribe_cb 
    100  
    101     def main(self): 
    102         while 1: 
    103             if self.dataReady("control"): 
    104                 mes = self.recv("control") 
    105                  
    106                 if isinstance(mes, shutdownMicroprocess) or isinstance(mes, producerFinished): 
    107                     self.send(producerFinished(), "signal") 
    108                     break 
    109  
    110             if self.dataReady("inbox"): 
    111                 p = self.recv("inbox") 
    112  
    113                 action = self.subscribe_cb(p) 
    114                 if action == None: 
    115                     e = create_presence(to_jid=unicode(p.to_jid), 
    116                                         presence_type=u'unsubscribed') 
    117                 else: 
    118                     # action is now the new instance of 'p' and may have been 
    119                     # modified by the callback function 
    120                     e = create_presence(to_jid=unicode(action.to_jid), 
    121                                         presence_type=u'subscribed') 
    122  
    123                 self.send(e, "outbox") 
    124                  
    125             if not self.anyReady(): 
    126                 self.pause() 
    127    
    128             yield 1 
    129      
    130  
    131 class PresenceUnsubscriber(component): 
    132     Inboxes = {"inbox"              : "bridge.Element instance", 
    133                "control"            : "Shutdown the client stream", 
    134                } 
    135      
    136     Outboxes = {"outbox"            : "bridge.Element instance to sent back to the client", 
    137                 "signal"            : "Shutdown signal", 
    138                 "log"               : "log", 
    139                 } 
    140      
    141     def __init__(self): 
    142        super(PresenceUnsubscriber, self).__init__()  
    143  
    144     def main(self): 
    145         while 1: 
    146             if self.dataReady("control"): 
    147                 mes = self.recv("control") 
    148                  
    149                 if isinstance(mes, shutdownMicroprocess) or isinstance(mes, producerFinished): 
    150                     self.send(producerFinished(), "signal") 
    151                     break 
    152  
    153             if self.dataReady("inbox"): 
    154                 e = self.recv("inbox") 
    155                  
    156             if not self.anyReady(): 
    157                 self.pause() 
    158    
    159             yield 1 
    160