changeset 346:ca3a041fed30

core: fixed several subscription scheme issues + removed most of profile_key default value in core.sat_main and core.xmmp (source of bugs) + contact update
author Goffi <goffi@goffi.org>
date Sat, 28 May 2011 20:28:21 +0200
parents e6047415868d
children ea3e1b82dd79
files src/core/sat_main.py src/core/xmpp.py src/tools/memory.py
diffstat 3 files changed, 81 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/sat_main.py	Sat May 28 20:24:02 2011 +0200
+++ b/src/core/sat_main.py	Sat May 28 20:28:21 2011 +0200
@@ -34,6 +34,7 @@
 from twisted.internet import reactor
 
 from wokkel import compat
+from wokkel.xmppim import RosterItem
 
 from sat.bridge.DBus import DBusBridge
 import logging
@@ -128,6 +129,7 @@
         self.bridge.register("setPresence", self.setPresence)
         self.bridge.register("subscription", self.subscription)
         self.bridge.register("addContact", self.addContact)
+        self.bridge.register("updateContact", self.updateContact)
         self.bridge.register("delContact", self.delContact)
         self.bridge.register("isConnected", self.isConnected)
         self.bridge.register("launchAction", self.launchAction)
@@ -235,7 +237,7 @@
 
         current.startService()
 
-    def disconnect(self, profile_key='@DEFAULT@'):
+    def disconnect(self, profile_key):
         """disconnect from jabber server"""
         if (not self.isConnected(profile_key)):
             info(_("not connected !"))
@@ -322,7 +324,7 @@
         else:
             self.actionResult(action_id, "SUPPRESS", {})
 
-    def submitForm(self, action, target, fields, profile_key='@DEFAULT@'):
+    def submitForm(self, action, target, fields, profile_key):
         """submit a form
         @param target: target jid where we are submitting
         @param fields: list of tuples (name, value)
@@ -351,12 +353,12 @@
 
     ## Client management ##
 
-    def setParam(self, name, value, category, profile_key='@DEFAULT@'):
+    def setParam(self, name, value, category, profile_key):
         """set wanted paramater and notice observers"""
         info (_("setting param: %(name)s=%(value)s in category %(category)s") % {'name':name, 'value':value, 'category':category})
         self.memory.setParam(name, value, category, profile_key)
 
-    def isConnected(self, profile_key='@DEFAULT@'):
+    def isConnected(self, profile_key):
         """Return connection status of profile
         @param profile_key: key_word or profile name to determine profile name
         @return True if connected
@@ -369,7 +371,7 @@
             return False
         return self.profiles[profile].isConnected()
 
-    def launchAction(self, type, data, profile_key='@DEFAULT@'):
+    def launchAction(self, type, data, profile_key):
         """Launch a specific action asked by client
         @param type: action type (button)
         @param data: needed data to launch the action
@@ -429,7 +431,7 @@
                 int(priority), statuses, profile)
         
     
-    def subscription(self, subs_type, raw_jid, profile_key='@DEFAULT@'):
+    def subscription(self, subs_type, raw_jid, profile_key):
         """Called to manage subscription
         @param subs_type: subsciption type (cf RFC 3921)
         @param raw_jid: unicode entity's jid
@@ -442,17 +444,12 @@
             self.profiles[profile].presence.subscribe(to_jid)
         elif subs_type=="subscribed":
             self.profiles[profile].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 subs_type=="unsubscribe":
             self.profiles[profile].presence.unsubscribe(to_jid)
         elif subs_type=="unsubscribed":
             self.profiles[profile].presence.unsubscribed(to_jid)
 
-
-    def addContact(self, to, profile_key='@DEFAULT@'):
+    def addContact(self, to, profile_key):
         """Add a contact in roster list"""
         profile = self.memory.getProfileName(profile_key)
         assert(profile)
@@ -460,7 +457,18 @@
         #self.profiles[profile].roster.addItem(to_jid) XXX: disabled (cf http://wokkel.ik.nu/ticket/56))
         self.profiles[profile].presence.subscribe(to_jid)
 
-    def delContact(self, to, profile_key='@DEFAULT@'):
+    def updateContact(self, to, name, groups, profile_key):
+        """update a contact in roster list"""
+        profile = self.memory.getProfileName(profile_key)
+        assert(profile)
+        to_jid = jid.JID(to)
+        groups = set(groups)
+        roster_item = RosterItem(to_jid)
+        roster_item.name = name or None
+        roster_item.groups = set(groups)
+        self.profiles[profile].roster.updateItem(roster_item)
+
+    def delContact(self, to, profile_key):
         """Remove contact from roster list"""
         profile = self.memory.getProfileName(profile_key)
         assert(profile)
--- a/src/core/xmpp.py	Sat May 28 20:24:02 2011 +0200
+++ b/src/core/xmpp.py	Sat May 28 20:28:21 2011 +0200
@@ -139,6 +139,22 @@
         #xmppim.RosterClientProtocol.addItem(self, to)
         #TODO: check IQ result"""
 
+    def updateItem(self, roster_item):
+        """
+        Update an item of the contact list.
+
+        @param roster_item: item to update
+        """
+        iq = compat.IQ(self.xmlstream, 'set')
+        iq.addElement((xmppim.NS_ROSTER, 'query'))
+        item = iq.query.addElement('item')
+        item['jid'] = roster_item.jid.userhost()
+        if roster_item.name:
+            item['name'] = roster_item.name
+        for group in roster_item.groups:
+            item.addElement('group', content=group)
+        return iq.send()
+    
     def onRosterSet(self, item):
         """Called when a new/update roster item is received"""
         #TODO: send a signal to frontends
@@ -206,25 +222,44 @@
             statuses[None] = statuses['default']
             del statuses['default']
         xmppim.PresenceClientProtocol.available(self, entity, show, statuses, priority)
-    
+   
+    def subscribed(self, entity):
+        xmppim.PresenceClientProtocol.subscribed(self, entity)
+        self.host.memory.delWaitingSub(entity.userhost(), self.parent.profile)
+        contact = self.host.memory.getContact(entity, self.parent.profile) 
+        if not contact or contact[0]['to'] == 'False': #we automatically subscribe to 'to' presence
+            debug(_('sending automatic "from" subscription request'))
+            self.subscribe(entity)
+
+    def unsubscribed(self, entity):
+        xmppim.PresenceClientProtocol.unsubscribed(self, entity)
+        self.host.memory.delWaitingSub(entity.userhost(), self.parent.profile)
+
     def subscribedReceived(self, entity):
         debug (_("subscription approved for [%s]") % entity.userhost())
-        self.host.memory.delWaitingSub(entity.userhost(), self.parent.profile)
         self.host.bridge.subscribe('subscribed', entity.userhost(), self.parent.profile)
 
     def unsubscribedReceived(self, entity):
         debug (_("unsubscription confirmed for [%s]") % entity.userhost())
-        self.host.memory.delWaitingSub(entity.userhost(), self.parent.profile)
         self.host.bridge.subscribe('unsubscribed', entity.userhost(), self.parent.profile)
 
     def subscribeReceived(self, entity):
-        debug (_("subscription request for [%s]") % entity.userhost())
-        self.host.memory.addWaitingSub('subscribe', entity.userhost(), self.parent.profile)
-        self.host.bridge.subscribe('subscribe', entity.userhost(), self.parent.profile)
+        debug (_("subscription request from [%s]") % entity.userhost())
+        contact = self.host.memory.getContact(entity, self.parent.profile) 
+        if contact and contact[0]['to'] == 'True':
+            #We automatically accept subscription if we are already subscribed to contact presence
+            debug(_('sending automatic subscription acceptance'))
+            self.subscribed(entity)
+        else:
+            self.host.memory.addWaitingSub('subscribe', entity.userhost(), self.parent.profile)
+            self.host.bridge.subscribe('subscribe', entity.userhost(), self.parent.profile)
 
     def unsubscribeReceived(self, entity):
         debug (_("unsubscription asked for [%s]") % entity.userhost())
-        self.host.memory.addWaitingSub('unsubscribe', entity.userhost(), self.parent.profile)
+        contact = self.host.memory.getContact(entity, self.parent.profile) 
+        if contact and contact[0]['from'] == 'True': #we automatically remove contact
+            debug(_('automatic contact deletion'))
+            self.host.delContact(entity.userhost(), self.parent.profile)
         self.host.bridge.subscribe('unsubscribe', entity.userhost(), self.parent.profile)
 
 class SatDiscoProtocol(disco.DiscoClientProtocol):
--- a/src/tools/memory.py	Sat May 28 20:24:02 2011 +0200
+++ b/src/tools/memory.py	Sat May 28 20:28:21 2011 +0200
@@ -291,7 +291,7 @@
         return prof_xml
 
 
-    def getParamsUI(self, profile_key='@DEFAULT@'):
+    def getParamsUI(self, profile_key):
         """Return a SàT XMLUI for parameters, with given profile"""
         profile = self.getProfileName(profile_key)
         if not profile:
@@ -300,7 +300,7 @@
         param_xml = self.getParams(profile)
         return paramsXml2xmlUI(param_xml)
 
-    def getParams(self, profile_key='@DEFAULT@'):
+    def getParams(self, profile_key):
         """Construct xml for asked profile
         Take params xml as skeleton"""
         profile = self.getProfileName(profile_key)
@@ -313,7 +313,7 @@
 
         return return_xml
 
-    def getParamsForCategory(self, category, profile_key='@DEFAULT@'):
+    def getParamsForCategory(self, category, profile_key):
         """Return node's xml for selected category"""
         #TODO: manage category of general type (without existant profile)
         profile = self.getProfileName(profile_key)
@@ -359,7 +359,7 @@
             categories.append(cat.getAttribute("name"))
         return categories
 
-    def setParam(self, name, value, category, profile_key='@DEFAULT@'):
+    def setParam(self, name, value, category, profile_key):
         """Set a parameter, return None if the parameter is not in param xml"""
         profile = self.getProfileName(profile_key)
         if not profile:
@@ -573,7 +573,7 @@
         else:
             return list(entities)[0] if entities else None
 
-    def hasServerFeature(self, feature, profile_key='@DEFAULT@'):
+    def hasServerFeature(self, feature, profile_key):
         """Tell if the server of the profile has the required feature"""
         profile = self.getProfileName(profile_key)
         if not profile:
@@ -583,7 +583,7 @@
         return feature in self.server_features[profile]
 
 
-    def addContact(self, contact_jid, attributes, groups, profile_key='@DEFAULT@'):
+    def addContact(self, contact_jid, attributes, groups, profile_key):
         debug("Memory addContact: %s",contact_jid.userhost())
         profile = self.getProfileName(profile_key)
         if not profile:
@@ -595,7 +595,7 @@
             self.contacts[profile] = {}
         self.contacts[profile][contact_jid.userhost()]=[attributes, groups]
 
-    def delContact(self, contact_jid, profile_key='@DEFAULT@'):
+    def delContact(self, contact_jid, profile_key):
         debug("Memory delContact: %s",contact_jid.userhost())
         profile = self.getProfileName(profile_key)
         if not profile:
@@ -604,17 +604,15 @@
         if self.contacts.has_key(profile) and self.contacts[profile].has_key(contact_jid.userhost()):
             del self.contacts[profile][contact_jid.userhost()]
     
-    def getContact(self, contact_jid, profile_key='@DEFAULT@'):
+    def getContact(self, contact_jid, profile_key):
         profile = self.getProfileName(profile_key)
         if not profile:
             error(_('Asking a contact for a non-existant profile'))
             return None
         if self.contacts.has_key(profile) and self.contacts[profile].has_key(contact_jid.userhost()):
-            self.contacts[profile][contact_jid.userhost()]
-        else:
-            return None
+            return self.contacts[profile][contact_jid.userhost()]
     
-    def getContacts(self, profile_key='@DEFAULT@'):
+    def getContacts(self, profile_key):
         """Return list of contacts for given profile
         @param profile_key: profile key
         @return list of [contact, attr, groups]"""
@@ -630,7 +628,7 @@
                 ret.append([contact, attr, groups ])
         return ret
     
-    def addPresenceStatus(self, contact_jid, show, priority, statuses, profile_key='@DEFAULT@'):
+    def addPresenceStatus(self, contact_jid, show, priority, statuses, profile_key):
         profile = self.getProfileName(profile_key)
         if not profile:
             error(_('Trying to add presence status to a non-existant profile'))
@@ -657,7 +655,7 @@
         if self.subscriptions.has_key(profile) and self.subscriptions[profile].has_key(contact_jid):
             del self.subscriptions[profile][contact_jid]
     
-    def getWaitingSub(self, profile_key='@DEFAULT@'):
+    def getWaitingSub(self, profile_key):
         """Called to get a list of currently waiting subscription requests"""
         profile = self.getProfileName(profile_key)
         if not profile:
@@ -668,7 +666,7 @@
         
         return self.subscriptions[profile]
 
-    def getPresenceStatus(self, profile_key='@DEFAULT@'):
+    def getPresenceStatus(self, profile_key):
         profile = self.getProfileName(profile_key)
         if not profile:
             error(_('Asking contacts for a non-existant profile'))
@@ -678,22 +676,22 @@
         debug ("Memory getPresenceStatus (%s)", self.presenceStatus[profile])
         return self.presenceStatus[profile]
 
-    def getParamA(self, name, category, attr="value", profile_key="@DEFAULT@"):
+    def getParamA(self, name, category, attr="value", profile_key='@DEFAULT@'):
         return self.params.getParamA(name, category, attr, profile_key)
     
-    def getParamsUI(self, profile_key='@DEFAULT@'):
+    def getParamsUI(self, profile_key):
         return self.params.getParamsUI(profile_key)
   
-    def getParams(self, profile_key='@DEFAULT@'):
+    def getParams(self, profile_key):
         return self.params.getParams(profile_key) 
     
-    def getParamsForCategory(self, category, profile_key='@DEFAULT@'):
+    def getParamsForCategory(self, category, profile_key):
         return self.params.getParamsForCategory(category, profile_key) 
     
     def getParamsCategories(self):
         return self.params.getParamsCategories()
     
-    def setParam(self, name, value, category, profile_key='@DEFAULT@'):
+    def setParam(self, name, value, category, profile_key):
         return self.params.setParam(name, value, category, profile_key)
 
     def importParams(self, xml):