# HG changeset patch # User Goffi # Date 1259639768 -3600 # Node ID bb72c29f3432d6f7014834d7e5fcf9b30f71968a # Parent 633c5ed657011ba46dd417800ee8ec089dfeb132 added action cb mechanism for buttons. Tested with a temporary new user registration button. diff -r 633c5ed65701 -r bb72c29f3432 frontends/jp/jp --- 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""" diff -r 633c5ed65701 -r bb72c29f3432 frontends/quick_frontend/quick_app.py --- 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 diff -r 633c5ed65701 -r bb72c29f3432 frontends/sat_bridge_frontend/DBus.py --- 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) diff -r 633c5ed65701 -r bb72c29f3432 frontends/sortilege/sortilege.py --- 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) diff -r 633c5ed65701 -r bb72c29f3432 frontends/wix/main_window.py --- 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() diff -r 633c5ed65701 -r bb72c29f3432 frontends/wix/param.py --- 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() diff -r 633c5ed65701 -r bb72c29f3432 plugins/plugin_xep_0065.py --- 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) diff -r 633c5ed65701 -r bb72c29f3432 plugins/plugin_xep_0096.py --- 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() diff -r 633c5ed65701 -r bb72c29f3432 sat.tac --- 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() diff -r 633c5ed65701 -r bb72c29f3432 sat_bridge/DBus.py --- 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) diff -r 633c5ed65701 -r bb72c29f3432 tools/memory.py --- 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()