changeset 22:bb72c29f3432

added action cb mechanism for buttons. Tested with a temporary new user registration button.
author Goffi <goffi@goffi.org>
date Tue, 01 Dec 2009 04:56:08 +0100 (2009-12-01)
parents 633c5ed65701
children 925ab466c5ec
files frontends/jp/jp frontends/quick_frontend/quick_app.py frontends/sat_bridge_frontend/DBus.py frontends/sortilege/sortilege.py frontends/wix/main_window.py frontends/wix/param.py plugins/plugin_xep_0065.py plugins/plugin_xep_0096.py sat.tac sat_bridge/DBus.py tools/memory.py
diffstat 11 files changed, 226 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/jp/jp	Sun Nov 08 01:49:08 2009 +0100
+++ b/frontends/jp/jp	Tue Dec 01 04:56:08 2009 +0100
@@ -201,6 +201,9 @@
                 #we just accept one file
                 self.loop.quit()
                 
+    def actionResult(self, type, id, data):
+        #FIXME
+        info ("FIXME: actionResult not implemented")
 
     def wait_file(self):
         """Wait for a file and write it on local dir"""
--- a/frontends/quick_frontend/quick_app.py	Sun Nov 08 01:49:08 2009 +0100
+++ b/frontends/quick_frontend/quick_app.py	Tue Dec 01 04:56:08 2009 +0100
@@ -40,12 +40,14 @@
         self.bridge.register("paramUpdate", self.paramUpdate)
         self.bridge.register("contactDeleted", self.contactDeleted)
         self.bridge.register("askConfirmation", self.askConfirmation, "request")
+        self.bridge.register("actionResult", self.actionResult, "request")
         
         ###now we get the essential params###
-        self.whoami=JID(self.bridge.getParamV("JabberID","Connection"))
-        self.watched=self.bridge.getParamV("Watched", "Misc").split() #TODO: put this in a plugin
+        self.whoami=JID(self.bridge.getParamA("JabberID","Connection"))
+        self.watched=self.bridge.getParamA("Watched", "Misc").split() #TODO: put this in a plugin
 
         ## misc ##
+        self.current_action_ids = set()
         self.onlineContact = set()  #FIXME: temporary
 
         if self.bridge.isConnected():
@@ -156,3 +158,6 @@
     
     def askConfirmation(self, type, id, data):
         raise NotImplementedError
+    
+    def actionResult(self, type, id, data):
+        raise NotImplementedError
--- a/frontends/sat_bridge_frontend/DBus.py	Sun Nov 08 01:49:08 2009 +0100
+++ b/frontends/sat_bridge_frontend/DBus.py	Tue Dec 01 04:56:08 2009 +0100
@@ -64,8 +64,8 @@
     def setParam(self, name, value, category):
         return self.db_comm_iface.setParam(name, value, category)
         
-    def getParamV(self, name, category):
-        return self.db_comm_iface.getParamV(name, category)
+    def getParamA(self, name, category):
+        return self.db_comm_iface.getParamA(name, category)
 
     def getParams(self):
         return self.db_comm_iface.getParams()
@@ -88,6 +88,9 @@
     def isConnected(self):
         return self.db_comm_iface.isConnected()
 
+    def launchAction(self, type, data):
+        return self.db_req_iface.launchAction(type, data)
+
     def confirmationAnswer(self, id, accepted, data):
         return self.db_req_iface.confirmationAnswer(id, accepted, data)
 
--- a/frontends/sortilege/sortilege.py	Sun Nov 08 01:49:08 2009 +0100
+++ b/frontends/sortilege/sortilege.py	Tue Dec 01 04:56:08 2009 +0100
@@ -273,6 +273,14 @@
         self.editBar.replace_cur()
         curses.doupdate()
 
+    def askConfirmation(self, type, id, data):
+        #FIXME
+        info ("FIXME: askConfirmation not implemented")
+
+    def actionResult(self, type, id, data):
+        #FIXME
+        info ("FIXME: actionResult not implemented")
+
     def newMessage(self, from_jid, msg, type, to_jid):
         QuickApp.newMessage(self, from_jid, msg, type, to_jid)
         sender=JID(from_jid)
--- a/frontends/wix/main_window.py	Sun Nov 08 01:49:08 2009 +0100
+++ b/frontends/wix/main_window.py	Tue Dec 01 04:56:08 2009 +0100
@@ -284,11 +284,46 @@
                     answer = wx.ID_NO
             if answer==wx.ID_NO:
                     self.bridge.confirmationAnswer(id, False, answer_data)
+            
+            dlg.Destroy()
+
+        elif type == "YES/NO":
+            debug ("Yes/No confirmation asked")
+            dlg = wx.MessageDialog(self, data["message"],
+                                   'Confirmation',
+                                   wx.YES_NO | wx.ICON_QUESTION
+                                  )
+            answer=dlg.ShowModal()
+            if answer==wx.ID_YES:
+                self.bridge.confirmationAnswer(id, True, {})
+            if answer==wx.ID_NO:
+                self.bridge.confirmationAnswer(id, False, {})
 
             dlg.Destroy()
 
-        
-        
+    def actionResult(self, type, id, data):
+        debug ("actionResult: type = [%s] id = [%s] data =[%s]" % (type, id, data))
+        if type == "SUPPRESS":
+            self.current_action_ids.remove(id)
+        elif type == "SUCCESS":
+            dlg = wx.MessageDialog(self, data["message"],
+                                   'Success',
+                                   wx.OK | wx.ICON_INFORMATION
+                                  )
+            dlg.ShowModal()
+            dlg.Destroy()
+        elif type == "ERROR":
+            dlg = wx.MessageDialog(self, data["message"],
+                                   'Error',
+                                   wx.OK | wx.ICON_ERROR
+                                  )
+            dlg.ShowModal()
+            dlg.Destroy()
+        else:
+            error ("FIXME FIXME FIXME: type [%s] not implemented" % type)
+            raise NotImplementedError
+
+
 
     def progressCB(self, id, title, message):
         data = self.bridge.getProgress(id)
@@ -340,7 +375,7 @@
 
     def onParam(self, e):
         debug("Param request")
-        param=Param(self.bridge)
+        param=Param(self)
 
     def onExit(self, e):
         self.Close()
--- a/frontends/wix/param.py	Sun Nov 08 01:49:08 2009 +0100
+++ b/frontends/wix/param.py	Tue Dec 01 04:56:08 2009 +0100
@@ -28,10 +28,10 @@
 
 
 class Param(wx.Frame):
-    def __init__(self, bridge, title="Configuration"):
+    def __init__(self, host, title="Configuration"):
         super(Param, self).__init__(None, title=title)
 
-        self.bridge = bridge
+        self.host = host
 
         self.modified={}  # dict of modified data (i.e. what we have to save)
 
@@ -46,7 +46,7 @@
         
         self.MakeModal()
 
-        for category in self.bridge.getParamsCategories():
+        for category in self.host.bridge.getParamsCategories():
             self.addCategory(category)
         
         self.Show()
@@ -55,7 +55,7 @@
         panel=wx.Panel(self.notebook)
         panel.sizer = wx.BoxSizer(wx.VERTICAL)
 
-        cat_dom = minidom.parseString(self.bridge.getParamsForCategory(category))
+        cat_dom = minidom.parseString(self.host.bridge.getParamsForCategory(category))
         
         for param in cat_dom.documentElement.getElementsByTagName("param"):
             name = param.getAttribute("name")
@@ -96,8 +96,12 @@
         
     def onButtonClicked(self, event):
         """Called when a paramated is modified"""
-        print "Button Clicked (%s/%s)" % event.GetEventObject().param_id#TODO: gof: appeler callback
-        #self.modified[event.GetEventObject().param_id]=event.GetString()
+        print "Button Clicked (%s/%s)" % event.GetEventObject().param_id
+        name, category = event.GetEventObject().param_id
+        data = {"name":name, "category":category}
+        id = self.host.bridge.launchAction("button", data)
+        self.host.current_action_ids.add(id)
+        print "action id:",id
         event.Skip()
 
     def onClose(self, event):
@@ -105,7 +109,7 @@
         debug("close")
         #now we save the modifier params
         for param in self.modified:
-            self.bridge.setParam(param[0], self.modified[param], param[1])
+            self.host.bridge.setParam(param[0], self.modified[param], param[1])
 
         self.MakeModal(False)
         event.Skip()
--- a/plugins/plugin_xep_0065.py	Sun Nov 08 01:49:08 2009 +0100
+++ b/plugins/plugin_xep_0065.py	Tue Dec 01 04:56:08 2009 +0100
@@ -473,7 +473,7 @@
         host.memory.importParams(self, XEP_0065.params)
         host.memory.setDefault("IP", "File Transfert", self.getExternalIP)
         
-        port = int(self.host.memory.getParamV("Port", "File Transfert"))
+        port = int(self.host.memory.getParamA("Port", "File Transfert"))
         info("Launching Socks5 Stream server on port %d", port)
         reactor.listenTCP(port, self.server_factory)
     
--- a/plugins/plugin_xep_0096.py	Sun Nov 08 01:49:08 2009 +0100
+++ b/plugins/plugin_xep_0096.py	Tue Dec 01 04:56:08 2009 +0100
@@ -143,8 +143,8 @@
             query=offer.addElement('query', 'http://jabber.org/protocol/bytestreams')
             query['mode']='tcp'
             streamhost=query.addElement('streamhost')
-            streamhost['host']=self.host.memory.getParamV("IP", "File Transfert")
-            streamhost['port']=self.host.memory.getParamV("Port", "File Transfert")
+            streamhost['host']=self.host.memory.getParamA("IP", "File Transfert")
+            streamhost['port']=self.host.memory.getParamA("Port", "File Transfert")
             streamhost['jid']=self.host.me.full()
             offer.send()
 
--- a/sat.tac	Sun Nov 08 01:49:08 2009 +0100
+++ b/sat.tac	Tue Dec 01 04:56:08 2009 +0100
@@ -205,6 +205,7 @@
         self.user_login = user_login
         self.user_pass = user_pass
         self.answer_id = answer_id
+        print "Registration asked for",user_login, user_pass, jabber_host
     
     def connectionMade(self):
         print "connectionMade"
@@ -223,34 +224,38 @@
 
     def registrationAnswer(self, answer):
         debug ("registration answer: %s" % answer.toXml())
-        answer_type = "success"
-        answer_data={"human":"Registration successfull"}
-        self.host.bridge.sendAnswer(answer_type, self.answer_id, answer_data)
+        answer_type = "SUCCESS"
+        answer_data={"message":"Registration successfull"}
+        self.host.bridge.actionResult(answer_type, self.answer_id, answer_data)
         self.xmlstream.sendFooter()
         
     def registrationFailure(self, error):
-        info ("Registration failure: %s" %str(error))
-        answer_type = "error"
-        answer_data={"human":"Registration failed"}
+        info ("Registration failure: %s" % str(error.value))
+        answer_type = "ERROR"
+        answer_data = {}
         if error.value.condition == 'conflict':
             answer_data['reason'] = 'conflict'
+            answer_data={"message":"Username already exists, please choose an other one"}
         else:
             answer_data['reason'] = 'unknown'
-        self.host.bridge.sendAnswer(answer_type, self.answer_id, answer_data)
+            answer_data={"message":"Registration failed"}
+        self.host.bridge.actionResult(answer_type, self.answer_id, answer_data)
         self.xmlstream.sendFooter()
         
 
 class SAT(service.Service):
     
     def __init__(self):
-        #self.reactor=reactor
-        self.memory=Memory()
+        #TODO: standardize callback system
+        self.__waiting_conf = {}  #callback called when a confirmation is received
+        self.__progress_cb_map = {}  #callback called when a progress is requested (key = progress id)
+        self.__general_cb_map = {}  #callback called for general reasons (key = name) 
+        self.__private_data = {}  #used for internal callbacks (key = id)
+        self.plugins = {}
+        
+        self.memory=Memory(self)
         self.server_features=[]  #XXX: temp dic, need to be transfered into self.memory in the future
 
-        self._waiting_conf = {}  #callback called when a confirmation is received
-        self._progress_cb_map = {}  #callback called when a progress is requested (key = progress id)
-        self.plugins = {}
-
         self.bridge=DBusBridge()
         self.bridge.register("registerNewAccount", self.registerNewAccount)
         self.bridge.register("connect", self.connect)
@@ -259,7 +264,7 @@
         self.bridge.register("getPresenceStatus", self.memory.getPresenceStatus)
         self.bridge.register("sendMessage", self.sendMessage)
         self.bridge.register("setParam", self.setParam)
-        self.bridge.register("getParamV", self.memory.getParamV)
+        self.bridge.register("getParamA", self.memory.getParamA)
         self.bridge.register("getParams", self.memory.getParams)
         self.bridge.register("getParamsForCategory", self.memory.getParamsForCategory)
         self.bridge.register("getParamsCategories", self.memory.getParamsCategories)
@@ -268,6 +273,7 @@
         self.bridge.register("addContact", self.addContact)
         self.bridge.register("delContact", self.delContact)
         self.bridge.register("isConnected", self.isConnected)
+        self.bridge.register("launchAction", self.launchAction)
         self.bridge.register("confirmationAnswer", self.confirmationAnswer)
         self.bridge.register("getProgress", self.getProgress)
 
@@ -295,9 +301,9 @@
             info("already connected !")
             return
         print "connecting..."
-        self.me = jid.JID(self.memory.getParamV("JabberID", "Connection"))
-        self.xmppclient = SatXMPPClient(self.me, self.memory.getParamV("Password", "Connection"),
-            self.memory.getParamV("Server", "Connection"), 5222)
+        self.me = jid.JID(self.memory.getParamA("JabberID", "Connection"))
+        self.xmppclient = SatXMPPClient(self.me, self.memory.getParamA("Password", "Connection"),
+            self.memory.getParamA("Server", "Connection"), 5222)
         self.xmppclient.streamInitialized = self.streamInitialized
 
         self.messageProt = SatMessageProtocol(self)
@@ -362,27 +368,52 @@
         
         self.presence.available()
         
-        self.disco.requestInfo(jid.JID(self.memory.getParamV("Server", "Connection"))).addCallback(self.serverDisco)
+        self.disco.requestInfo(jid.JID(self.memory.getParamA("Server", "Connection"))).addCallback(self.serverDisco)
     
    ## Misc methods ##
    
-    def registerNewAccount(self, login, password, server, port = 5222):
+    def registerNewAccount(self, login, password, server, port = 5222, id = None):
         """Connect to a server and create a new account using in-band registration"""
 
-        next_id = sat_next_id()  #the id is used to send server's answer
+        next_id = id or sat_next_id()  #the id is used to send server's answer
         serverRegistrer = xmlstream.XmlStreamFactory(RegisteringAuthenticator(self, server, login, password, next_id))
         connector = reactor.connectTCP(server, port, serverRegistrer)
         serverRegistrer.clientConnectionLost = lambda conn, reason: connector.disconnect()
         
         return next_id 
 
+    def registerNewAccountCB(self, id, data):
+        user = jid.parse(self.memory.getParamA("JabberID", "Connection"))[0]
+        server = self.memory.getParamA("Server", "Connection")
+
+        confirm_id = sat_next_id()
+        self.__private_data[confirm_id]=id
+    
+        self.askConfirmation(confirm_id, "YES/NO",
+            {"message":"Are you sure to register new account [%s] to server %s ?" % (user, server)},
+            self.regisConfirmCB)
+        print ("===============+++++++++++ REGISTER NEW ACCOUNT++++++++++++++============")
+        print "id=",id
+        print "data=",data
+
+    def regisConfirmCB(self, id, accepted, data):
+        print "register Confirmation CB ! (%s)" % str(accepted)
+        action_id = self.__private_data[id]
+        del self.__private_data[id]
+        user = jid.parse(self.memory.getParamA("JabberID", "Connection"))[0]
+        password = self.memory.getParamA("Password", "Connection")
+        server = self.memory.getParamA("Server", "Connection")
+        if accepted:
+            self.registerNewAccount(user, password, server, id=action_id)
+        else:
+            self.actionResult(action_id, "SUPPRESS", {})
+
     ## Client management ##
 
     def setParam(self, name, value, category):
         """set wanted paramater and notice observers"""
         info ("setting param: %s=%s in category %s", name, value, category)
         self.memory.setParam(name, value, category)
-        self.bridge.paramUpdate(name, value, category)
 
     def failed(self,xmlstream):
         debug("failed: %s", xmlstream.getErrorMessage())
@@ -397,6 +428,27 @@
             pass
         return False
 
+    def launchAction(self, type, data):
+        """Launch a specific action asked by client
+        @param type: action type (button)
+        @data: needed data to launch the action
+
+        @return: action id for result, or empty string in case or error
+        """
+        if type=="button":
+            try:
+                cb_name = self.memory.getParamA(data["name"], data["category"], "callback")
+            except KeyError:
+                error ("Incomplete data")
+                return ""
+            id = sat_next_id()
+            self.callGeneralCB(cb_name, id, data)
+            return id
+        else:
+            error ("Unknown action type")
+            return ""
+
+
     ## jabber methods ##
     
     def sendMessage(self,to,msg,type='chat'):
@@ -457,36 +509,51 @@
             debug ("Identity found: [%s/%s] %s" % (cat, type, disco.identities[(cat,type)]))
 
     ## Generic HMI ## 
+    
+    def actionResult(self, id, type, data):
+        """Send the result of an action
+        @param id: same id used with action
+        @type: result type ("PARAM", "SUCCESS", "ERROR")
+        @data: data (depend of result type)
+        """
+        self.bridge.actionResult(type, id, data)
+
+
 
     def askConfirmation(self, id, type, data, cb):
-        """Add a confirmation callback"""
-        if self._waiting_conf.has_key(id):
+        """Add a confirmation callback
+        @param id: id used to get answer
+        @type: confirmation type ("YES/NO", "FILE_TRANSFERT")
+        @data: data (depend of confirmation type)
+        @cb: callback called with the answer
+        """
+        if self.__waiting_conf.has_key(id):
             error ("Attempt to register two callbacks for the same confirmation")
         else:
-            self._waiting_conf[id] = cb
+            self.__waiting_conf[id] = cb
             self.bridge.askConfirmation(type, id, data)
 
 
     def confirmationAnswer(self, id, accepted, data):
         """Called by frontends to answer confirmation requests"""
         debug ("Received confirmation answer for id [%s]: %s", id, "accepted" if accepted else "refused")
-        if not self._waiting_conf.has_key(id):
+        if not self.__waiting_conf.has_key(id):
             error ("Received an unknown confirmation")
         else:
-            cb = self._waiting_conf[id]
-            del self._waiting_conf[id]
+            cb = self.__waiting_conf[id]
+            del self.__waiting_conf[id]
             cb(id, accepted, data)
 
     def registerProgressCB(self, id, CB):
         """Register a callback called when progress is requested for id"""
-        self._progress_cb_map[id] = CB
+        self.__progress_cb_map[id] = CB
 
     def removeProgressCB(self, id):
         """Remove a progress callback"""
-        if not self._progress_cb_map.has_key(id):
+        if not self.__progress_cb_map.has_key(id):
             error ("Trying to remove an unknow progress callback")
         else:
-            del self._progress_cb_map[id]
+            del self.__progress_cb_map[id]
 
     def getProgress(self, id):
         """Return a dict with progress information
@@ -495,12 +562,30 @@
         """
         data = {}
         try:
-            self._progress_cb_map[id](data)
+            self.__progress_cb_map[id](data)
         except KeyError:
             pass
             #debug("Requested progress for unknown id")
         return data
 
+    def registerGeneralCB(self, name, CB):
+        """Register a callback called for general reason"""
+        self.__general_cb_map[name] = CB
+
+    def removeGeneralCB(self, name):
+        """Remove a general callback"""
+        if not self.__general_cb_map.has_key(name):
+            error ("Trying to remove an unknow general callback")
+        else:
+            del self.__general_cb_map[name]
+
+    def callGeneralCB(self, name, *args, **kwargs):
+        """Call general function back"""
+        try:
+            return self.__general_cb_map[name](*args, **kwargs)
+        except KeyError:
+            error("Trying to call unknown function")
+            return None
 
 application = service.Application('SàT')
 service = SAT()
--- a/sat_bridge/DBus.py	Sun Nov 08 01:49:08 2009 +0100
+++ b/sat_bridge/DBus.py	Tue Dec 01 04:56:08 2009 +0100
@@ -73,10 +73,10 @@
     def askConfirmation(self, type, id, data):
         debug("asking for confirmation: id = [%s]  type = %s data = %s", id, type, data)
 
-    @dbus.service.signal(const_INT_PREFIX+const_COMM_SUFFIX,
+    @dbus.service.signal(const_INT_PREFIX+const_REQ_SUFFIX,
                          signature='ssa{ss}')
-    def sendAnswer(self, type, id, data):
-        debug("sending answer: id = [%s]  type = %s data = %s", id, type, data)
+    def actionResult(self, type, id, data):
+        debug("result of action: id = [%s]  type = %s data = %s", id, type, data)
 
     ### methods ###    
 
@@ -128,8 +128,8 @@
         
     @dbus.service.method(const_INT_PREFIX+const_COMM_SUFFIX,
                          in_signature='ss', out_signature='s')
-    def getParamV(self, name, category="default"):
-        return self.cb["getParamV"](name, category)
+    def getParamA(self, name, category="default"):
+        return self.cb["getParamA"](name, category)
 
     @dbus.service.method(const_INT_PREFIX+const_COMM_SUFFIX,
                          in_signature='', out_signature='s')
@@ -171,6 +171,11 @@
         return self.cb["isConnected"]()
 
     @dbus.service.method(const_INT_PREFIX+const_REQ_SUFFIX,
+                         in_signature='sa{ss}', out_signature='s')
+    def launchAction(self, type, data):
+        return self.cb["launchAction"](type, data)
+    
+    @dbus.service.method(const_INT_PREFIX+const_REQ_SUFFIX,
                          in_signature='sba{ss}', out_signature='')
     def confirmationAnswer(self, id, accepted, data):
         debug("Answer for confirmation [%s]: %s", id, "Accepted" if accepted else "Refused")
@@ -247,8 +252,8 @@
     def askConfirmation(self, type, id, data):
         self.dbus_bridge.askConfirmation(type, id, data)
 
-    def sendAnswer(self, type, id, data):
-        self.dbus_bridge.sendAnswer(type, id, data)
+    def actionResult(self, type, id, data):
+        self.dbus_bridge.actionResult(type, id, data)
 
     def register(self, name, callback):
         debug("registering DBus bridge method [%s]",name)
--- a/tools/memory.py	Sun Nov 08 01:49:08 2009 +0100
+++ b/tools/memory.py	Tue Dec 01 04:56:08 2009 +0100
@@ -54,9 +54,11 @@
     def load_default_params(self):
         self.dom = minidom.parseString(Param.default_xml)
     
-    def __init__(self):
+    def __init__(self, host):
         debug("Parameters init")
+        self.host = host
         self.load_default_params()
+        host.registerGeneralCB("registerNewAccount", host.registerNewAccountCB)
 
     def __get_unique_node(self, parent, tag, name):
         """return node with given tag, create a new one if the node doesn't exist
@@ -79,7 +81,6 @@
         src_dom = minidom.parseString(xml)
 
         def import_node(tgt_parent, src_parent):
-            print "import_node [%s, %s]" % (tgt_parent.nodeName, src_parent.nodeName)
             for child in src_parent.childNodes:
                 if child.nodeName == '#text':
                     continue
@@ -105,6 +106,7 @@
         @param callback: must return a string with the value (use deferred if needed)
         @param errback: must manage the error with args failure, name, category
         """
+        #TODO: send signal param update if value changed
         node =  self.__getParamNode(name, category)
         if not node:
             error("Requested param [%s] in category [%s] doesn't exist !" , name, category)
@@ -115,14 +117,18 @@
             d.addCallback(self.__default_ok, name, category)
             d.addErrback(errback or self.__default_ko, name, category)
 
-    def getParamV(self, name, category):
-        """Helper method to get the value in the good type
-           getParamV stands for GetParamValue"""
+    def getParamA(self, name, category, attr="value"):
+        """Helper method to get a specific attribute
+           @param name: name of the parameter
+           @param category: category of the parameter
+           @param attr: name of the attribute (default: "value")
+           
+           @return: attribute"""
         node = self.__getParamNode(name, category)
         if not node:
             error("Requested param [%s] in category [%s] doesn't exist !" , name, category)
             return None
-        return node.getAttribute("value")
+        return node.getAttribute(attr)
 
     def getParams(self):
         """Return the whole params XML"""
@@ -155,16 +161,21 @@
         node = self.__getParamNode(name, category)
         if not node:
             return #TODO: throw an error
-        node.setAttribute("value", value)
+        type = node.getAttribute("type")
+        if type=="button":
+            print "clique",node.toxml()
+        else:
+            node.setAttribute("value", value)
+            self.host.bridge.paramUpdate(name, value, category)
 
 class Memory:
     """This class manage all persistent informations"""
 
-    def __init__(self):
+    def __init__(self, host):
         info ("Memory manager init")
         self.contact={}
         self.presenceStatus={}
-        self.params=Param()
+        self.params=Param(host)
         self.history={}
         self.disco={}  #XXX: maybe best in a separate class
         self.features={}
@@ -176,6 +187,7 @@
         #first parameters
         if os.path.exists(const_SAVEFILE_PARAM):
             try:
+                #gof: FIXME FIXME FIXME: sauver l'xml et non plus le pickle !!!!!!!
                 with open(const_SAVEFILE_PARAM, 'r') as params_pickle:
                     self.params=pickle.load(params_pickle)
                 debug("params loaded")
@@ -260,8 +272,8 @@
         debug ("Memory getPresenceStatus (%s)", status)
         return status
 
-    def getParamV(self, name, category):
-        return self.params.getParamV(name, category)
+    def getParamA(self, name, category, attr="value"):
+        return self.params.getParamA(name, category, attr)
     
     def getParams(self):
         return self.params.getParams()