# HG changeset patch # User Goffi # Date 1262783115 -39600 # Node ID daa1f01a533291928f44caf2a57e2278e07b7da3 # Parent 9c79eb49d51fa28a0e0351f6506e4f75d88cfba4 SàT improvement: - subscription & presence refactoring - multilingual statuses are now correctly sent - registration: error condition now specified in error message diff -r 9c79eb49d51f -r daa1f01a5332 sat.tac --- a/sat.tac Thu Jan 07 00:00:25 2010 +1100 +++ b/sat.tac Thu Jan 07 00:05:15 2010 +1100 @@ -70,8 +70,8 @@ class SatXMPPClient(client.XMPPClient): - def __init__(self, jid, password, host=None, port=5222): - client.XMPPClient.__init__(self, jid, password, host, port) + def __init__(self, user_jid, password, host=None, port=5222): + client.XMPPClient.__init__(self, user_jid, password, host, port) self.factory.clientConnectionLost = self.connectionLost self.__connected=False @@ -120,11 +120,8 @@ self.host = host def rosterCb(self, roster): - for jid, item in roster.iteritems(): - info ("new contact in roster list: %s", jid) - #FIXME: fill attributes - self.host.memory.addContact(jid, {}, item.groups) - self.host.bridge.newContact(jid, {}, item.groups) + for raw_jid, item in roster.iteritems(): + self.onRosterSet(item) def requestRoster(self): """ ask the server for Roster list """ @@ -133,16 +130,33 @@ def removeItem(self, to): """Remove a contact from roster list""" - to_jid=jid.JID(to) - xmppim.RosterClientProtocol.removeItem(self, to_jid) + xmppim.RosterClientProtocol.removeItem(self, to) #TODO: check IQ result def addItem(self, to): """Add a contact to roster list""" - to_jid=jid.JID(to) - xmppim.RosterClientProtocol.addItem(self, to_jid) + xmppim.RosterClientProtocol.addItem(self, to) #TODO: check IQ result + def onRosterSet(self, item): + """Called when a new/update roster item is received""" + #TODO: send a signal to frontends + item_attr = {'to': str(item.subscriptionTo), + 'from': str(item.subscriptionFrom), + 'ask': str(item.ask) + } + if item.name: + item_attr['name'] = item.name + info ("new contact in roster list: %s", item.jid.full()) + self.host.memory.addContact(item.jid, item_attr, item.groups) + self.host.bridge.newContact(item.jid.full(), item_attr, item.groups) + + def onRosterRemove(self, entity): + """Called when a roster removal event is received""" + #TODO: send a signal to frontends + print "removing %s from roster list" % entity.full() + self.host.memory.delContact(entity) + class SatPresenceProtocol(xmppim.PresenceClientProtocol): def __init__(self, host): @@ -151,42 +165,53 @@ def availableReceived(self, entity, show=None, statuses=None, priority=0): info ("presence update for [%s]", entity) + + if statuses.has_key(None): #we only want string keys + statuses["default"] = statuses[None] + del statuses[None] - ### we check if the status is not about subscription ### - #FIXME: type is not needed anymore - #TODO: management of differents statuses (differents languages) - status = statuses.values()[0] if len(statuses) else "" - self.host.memory.addPresenceStatus(entity.full(), "", show or "", - status or "", int(priority)) + self.host.memory.addPresenceStatus(entity, show or "", + int(priority), statuses) #now it's time to notify frontends - self.host.bridge.presenceUpdate(entity.full(), "", show or "", - status or "", int(priority)) + self.host.bridge.presenceUpdate(entity.full(), show or "", + int(priority), statuses) def unavailableReceived(self, entity, statuses=None): - #TODO: management of differents statuses (differents languages) - status = statuses.values()[0] if len(statuses) else "" - self.host.memory.addPresenceStatus(entity.full(), "unavailable", "", - status or "", 0) + if statuses and statuses.has_key(None): #we only want string keys + statuses["default"] = statuses[None] + del statuses[None] + self.host.memory.addPresenceStatus(entity, "unavailable", 0, statuses) #now it's time to notify frontends - self.host.bridge.presenceUpdate(entity.full(), "unavailable", "", - status or "", 0) + self.host.bridge.presenceUpdate(entity.full(), "unavailable", 0, statuses) - + + def available(self, entity=None, show=None, statuses=None, priority=0): + if statuses and statuses.has_key('default'): + statuses[None] = statuses['default'] + del statuses['default'] + xmppim.PresenceClientProtocol.available(self, entity, show, statuses, priority) + def subscribedReceived(self, entity): - debug ("subscription approved for [%s]" % entity) + debug ("subscription approved for [%s]" % entity.userhost()) + self.host.memory.delWaitingSub(entity.userhost()) + self.host.bridge.subscribe('subscribed', entity.userhost()) def unsubscribedReceived(self, entity): - debug ("unsubscription confirmed for [%s]" % entity) + debug ("unsubscription confirmed for [%s]" % entity.userhost()) + self.host.memory.delWaitingSub(entity.userhost()) + self.host.bridge.subscribe('unsubscribed', entity.userhost()) def subscribeReceived(self, entity): - #FIXME: auto answer for subscribe request, must be checked ! - debug ("subscription request for [%s]" % entity) - self.subscribed(entity) + debug ("subscription request for [%s]" % entity.userhost()) + self.host.memory.addWaitingSub('subscribe', entity.userhost()) + self.host.bridge.subscribe('subscribe', entity.userhost()) def unsubscribeReceived(self, entity): - debug ("unsubscription asked for [%s]" % entity) + debug ("unsubscription asked for [%s]" % entity.userhost()) + self.host.memory.addWaitingSub('unsubscribe', entity.userhost()) + self.host.bridge.subscribe('unsubscribe', entity.userhost()) class SatDiscoProtocol(disco.DiscoClientProtocol): def __init__(self, host): @@ -243,7 +268,7 @@ answer_data={"message":"Username already exists, please choose an other one"} else: answer_data['reason'] = 'unknown' - answer_data={"message":"Registration failed"} + answer_data={"message":"Registration failed (%s)" % str(failure.value.condition)} self.host.bridge.actionResult(answer_type, self.answer_id, answer_data) self.xmlstream.sendFooter() @@ -289,6 +314,7 @@ self.bridge.register("disconnect", self.disconnect) self.bridge.register("getContacts", self.memory.getContacts) self.bridge.register("getPresenceStatus", self.memory.getPresenceStatus) + self.bridge.register("getWaitingSub", self.memory.getWaitingSub) self.bridge.register("sendMessage", self.sendMessage) self.bridge.register("setParam", self.setParam) self.bridge.register("getParamA", self.memory.getParamA) @@ -297,6 +323,7 @@ self.bridge.register("getParamsCategories", self.memory.getParamsCategories) self.bridge.register("getHistory", self.memory.getHistory) self.bridge.register("setPresence", self.setPresence) + self.bridge.register("subscription", self.subscription) self.bridge.register("addContact", self.addContact) self.bridge.register("delContact", self.delContact) self.bridge.register("isConnected", self.isConnected) @@ -523,22 +550,23 @@ self.bridge.newMessage(message['from'], unicode(msg), to=message['to']) #We send back the message, so all clients are aware of it - def setPresence(self, to="", type="", show="", status="", priority=0): + def setPresence(self, to="", show="", priority = 0, statuses={}): """Send our presence information""" - if not type in ["", "unavailable", "subscribed", "subscribe", - "unsubscribe", "unsubscribed", "prob", "error"]: - error("Type error !") - #TODO: throw an error - return - to_jid=jid.JID(to) - status = None if not status else {None:status} #FIXME: use the proper way here (change signature to use dict) - #TODO: refactor subscription bridge API - if type=="": - self.presence.available(to_jid, show, status, priority) - elif type=="subscribe": + to_jid = jid.JID(to) if to else None + self.presence.available(to_jid, show, statuses, priority) + + def subscription(self, type, raw_jid): + """Called to manage subscription""" + to_jid = jid.JID(raw_jid) + debug ('subsciption request [%s] for %s', type, to_jid.full()) + if type=="subscribe": self.presence.subscribe(to_jid) elif type=="subscribed": self.presence.subscribed(to_jid) + contact = self.memory.getContact(to_jid) + if not contact or not bool(contact['to']): #we automatically subscribe to 'to' presence + debug('sending automatic "to" subscription request') + self.subscription('subscribe', to_jid.userhost()) elif type=="unsubscribe": self.presence.unsubscribe(to_jid) elif type=="unsubscribed": @@ -548,13 +576,14 @@ def addContact(self, to): """Add a contact in roster list""" to_jid=jid.JID(to) - self.roster.addItem(to_jid.userhost()) - self.setPresence(to_jid.userhost(), "subscribe") + self.roster.addItem(to_jid) + self.presence.subscribe(to_jid) def delContact(self, to): """Remove contact from roster list""" to_jid=jid.JID(to) - self.roster.removeItem(to_jid.userhost()) + self.roster.removeItem(to_jid) + self.presence.unsubscribe(to_jid) self.bridge.contactDeleted(to)