Gateway registration, unregistration & edition

- default values added in form
- DBus bridge: fixed array of struct management when adding dynamically a method
- fixed doc for some methods
- ugly fix for presence status
- added dependency for XEP-0077 in XEP-0100 plugin
- Wix: added unregister button in gateways manager
- Wix: added privacy warning in gateways manager
This commit is contained in:
Goffi 2009-12-15 01:27:32 +11:00
commit e3a3c1e975
8 changed files with 159 additions and 39 deletions

View file

@ -100,8 +100,10 @@ class DBusBridgeFrontend(BridgeFrontend):
def confirmationAnswer(self, id, accepted, data):
return self.db_req_iface.confirmationAnswer(id, accepted, data)
def submitForm(self, target, data):
return self.db_req_iface.submitForm(target, data)
def gatewayRegister(self, action, target, data):
if data == None:
data = [('', '')] #XXX: we have to this awful hack because python dbus need to guess the signature
return self.db_req_iface.gatewayRegister(action, target, data)
def getProgress(self, id):
return self.db_req_iface.getProgress(id)

View file

@ -103,23 +103,21 @@ class Form(wx.Frame):
for ctrl in self.ctl_list:
data.append((ctrl["name"], ctrl["control"].GetValue()))
print "submitting:",data
id = self.host.bridge.submitForm(self.target, data)
id = self.host.bridge.gatewayRegister("SUBMIT",self.target, data)
self.host.current_action_ids.add(id)
print "action id:",id
event.Skip()
self.MakeModal(False)
self.Destroy()
def onFormCancelled(self, event):
"""Called when cancel button is clicked"""
debug("Cancelling form")
#id = self.host.bridge.submitForm("button", data)
#self.host.current_action_ids.add(id)
#print "action id:",id
event.Skip()
self.MakeModal(False)
self.Close()
def onClose(self, event):
"""Close event: we have to send the form."""
debug("close")
self.MakeModal(False)
event.Skip()

View file

@ -27,6 +27,8 @@ from xml.dom import minidom
from logging import debug, info, error
from tools.jid import JID
WARNING_MSG = u"""Be careful ! Gateways allow you to use an external IM (legacy IM), so you can see your contact as jabber contacts.
But when you do this, all your messages go throught the external legacy IM server, it is a huge privacy issue (i.e.: all your messages throught the gateway can be monitored, recorded, analyzed by the external server, most of time a private company)."""
class GatewaysManager(wx.Frame):
def __init__(self, host, gateways, title="Gateways manager"):
@ -44,8 +46,14 @@ class GatewaysManager(wx.Frame):
self.ctl_list = {} # usefull to access ctrl, key = (name, category)
self.sizer = wx.BoxSizer(wx.VERTICAL)
warning = wx.TextCtrl(self, -1, value=WARNING_MSG, style = wx.TE_MULTILINE |
wx.TE_READONLY |
wx.TE_LEFT)
warning.SetFont(self.bold_font)
self.sizer.Add(warning, 0, wx.EXPAND)
warning.ShowPosition(0)
self.panel = wx.Panel(self)
self.panel.sizer = wx.FlexGridSizer(cols=4)
self.panel.sizer = wx.FlexGridSizer(cols=5)
self.panel.SetSizer(self.panel.sizer)
self.panel.SetAutoLayout(True)
self.sizer.Add(self.panel, 1, flag=wx.EXPAND)
@ -64,12 +72,14 @@ class GatewaysManager(wx.Frame):
self.panel.sizer.Add(title_name)
self.panel.sizer.Add(title_type)
self.panel.sizer.Add(wx.Window(self.panel, -1))
self.panel.sizer.Add(wx.Window(self.panel, -1))
for gateway in gateways:
self.addGateway(gateway, gateways[gateway])
self.panel.sizer.Fit(self)
#self.panel.sizer.Fit(self)
self.sizer.Fit(self)
self.Show()
@ -121,24 +131,40 @@ class GatewaysManager(wx.Frame):
id = self.host.bridge.in_band_register(gateway_jid)
self.host.current_action_ids.add(id)
print "register id:",id
self.MakeModal(False)
self.Destroy()
event.Skip()
def unregister_cb(event):
"""Called when unregister button is clicked"""
gateway_jid = event.GetEventObject().gateway_jid
id = self.host.bridge.gatewayRegister("CANCEL",gateway_jid, None)
self.host.current_action_ids.add(id)
print "unregister id:",id
self.MakeModal(False)
self.Destroy()
event.Skip()
button_font = wx.Font(6, wx.DEFAULT, wx.NORMAL, wx.BOLD)
reg_button = wx.Button(self.panel, -1, "Register", size=wx.Size(-1, 8))
reg_button.SetFont(button_font)
reg_button.gateway_jid = JID(gateway)
self.panel.Bind(wx.EVT_BUTTON, register_cb, reg_button)
unreg_button = wx.Button(self.panel, -1, "Unregister", size=wx.Size(-1, 8))
unreg_button.SetFont(button_font)
unreg_button.gateway_jid = JID(gateway)
self.panel.Bind(wx.EVT_BUTTON, unregister_cb, unreg_button)
self.panel.sizer.Add(im_icon)
self.panel.sizer.Add(label)
self.panel.sizer.Add(type_label)
self.panel.sizer.Add(reg_button, 1, wx.EXPAND)
self.panel.sizer.Add(unreg_button, 1, wx.EXPAND)
def onClose(self, event):
"""Close event"""
debug("close")
#now we save the modifier params
self.MakeModal(False)
event.Skip()

View file

@ -40,16 +40,21 @@ PLUGIN_INFO = {
}
class XEP_0077():
def __init__(self, host):
info("Plugin XEP_0077 initialization")
self.host = host
self.triggers = {} #used by other protocol (e.g. XEP-0100) to finish registration. key = target_jid
host.bridge.addMethod("in_band_register", ".communication", in_sign='s', out_sign='s', method=self.in_band_register)
host.bridge.addMethod("in_band_submit", ".request", in_sign='sa(ss)', out_sign='s', method=self.in_band_submit)
def addTrigger(self, target, cb):
"""Add a callback which is called when registration to target is successful"""
self.triggers[target] = cb
def reg_ok(self, answer):
"""Called after the first get IQ"""
form = data_form.Form.fromElement(answer.firstChildElement().firstChildElement())
pdb.set_trace()
xml_data = XMLTools.dataForm2xml(form)
self.host.bridge.actionResult("FORM", answer['id'], {"target":answer["from"], "type":"registration", "xml":xml_data})
@ -62,6 +67,53 @@ class XEP_0077():
answer_type = "ERROR"
self.host.bridge.actionResult(answer_type, failure.value.stanza['id'], answer_data)
def unregistrationAnswer(self, answer):
debug ("registration answer: %s" % answer.toXml())
answer_type = "SUCCESS"
answer_data={"message":"Your are now unregistred"}
self.host.bridge.actionResult(answer_type, answer['id'], answer_data)
def unregistrationFailure(self, failure):
info ("Unregistration failure: %s" % str(failure.value))
answer_type = "ERROR"
answer_data = {}
answer_data['reason'] = 'unknown'
answer_data={"message":"Unregistration failed: %s" % failure.value.condition}
self.host.bridge.actionResult(answer_type, failure.value.stanza['id'], answer_data)
def registrationAnswer(self, answer):
debug ("registration answer: %s" % answer.toXml())
answer_type = "SUCCESS"
answer_data={"message":"Registration successfull"}
self.host.bridge.actionResult(answer_type, answer['id'], answer_data)
if self.triggers.has_key(answer["from"]):
self.triggers[answer["from"]](answer["from"])
del self.triggers[answer["from"]]
def registrationFailure(self, failure):
info ("Registration failure: %s" % str(failure.value))
print failure.value.stanza.toXml()
answer_type = "ERROR"
answer_data = {}
if failure.value.condition == 'conflict':
answer_data['reason'] = 'conflict'
answer_data={"message":"Username already exists, please choose an other one"}
else:
answer_data['reason'] = 'unknown'
answer_data={"message":"Registration failed"}
self.host.bridge.actionResult(answer_type, failure.value.stanza['id'], answer_data)
if self.triggers.has_key(answer["from"]):
del self.triggers[answer["from"]]
def in_band_submit(self, action, target, fields):
"""Submit a form for registration, using data_form"""
id, deferred = self.host.submitForm(action, target, fields)
if action == 'CANCEL':
deferred.addCallbacks(self.unregistrationAnswer, self.unregistrationFailure)
else:
deferred.addCallbacks(self.registrationAnswer, self.registrationFailure)
return id
def in_band_register(self, target):
"""register to a target JID"""
to_jid = jid.JID(target)

View file

@ -30,7 +30,7 @@ PLUGIN_INFO = {
"name": "Gateways Plugin",
"import_name": "XEP_0100",
"type": "XEP",
"dependencies": [],
"dependencies": ["XEP_0077"],
"main": "XEP_0100",
"description": """Implementation of Gateways protocol"""
}
@ -42,6 +42,7 @@ class XEP_0100():
self.host = host
self.__gateways = {} #dict used to construct the answer to findGateways. Key = target jid
host.bridge.addMethod("findGateways", ".communication", in_sign='s', out_sign='s', method=self.findGateways)
host.bridge.addMethod("gatewayRegister", ".request", in_sign='ssa(ss)', out_sign='s', method=self.gatewayRegister)
def discoInfo(self, disco, entity, request_id):
"""Find disco infos about entity, to check if it is a gateway"""
@ -76,6 +77,18 @@ class XEP_0100():
debug ("item found: %s", item.name)
self.host.disco.requestInfo(item.entity).addCallback(self.discoInfo, entity=item.entity, request_id=request_id)
def registrationSuccessful(self, target):
"""Called when in_band registration is ok, we must now follow the rest of procedure"""
print "Registration successful, doing the rest"
self.host.addContact(target)
self.host.setPresence(target)
def gatewayRegister(self, action, target, fields):
"""Register gateway using in-band registration, then log-in to gateway"""
if action == 'SUBMIT':
self.host.plugins["XEP_0077"].addTrigger(target, self.registrationSuccessful)
return self.host.plugins["XEP_0077"].in_band_submit(action, target, fields)
def findGateways(self, target):
"""Find gateways in the target JID, using discovery protocol
Return an id used for retrieving the list of gateways

49
sat.tac
View file

@ -42,6 +42,7 @@ import signal, sys
import os.path
from tools.memory import Memory
from tools.xml_tools import XMLTools
from glob import glob
try:
@ -278,7 +279,6 @@ class SAT(service.Service):
self.bridge.register("isConnected", self.isConnected)
self.bridge.register("launchAction", self.launchAction)
self.bridge.register("confirmationAnswer", self.confirmationAnswer)
self.bridge.register("submitForm", self.submitForm)
self.bridge.register("getProgress", self.getProgress)
self._import_plugins()
@ -373,8 +373,8 @@ class SAT(service.Service):
self.presence.available()
self.disco.requestInfo(jid.JID(self.memory.getParamA("Server", "Connection"))).addCallback(self.serverDisco)
## Misc methods ##
## Misc methods ##
def registerNewAccount(self, login, password, server, port = 5222, id = None):
"""Connect to a server and create a new account using in-band registration"""
@ -419,11 +419,29 @@ class SAT(service.Service):
else:
self.actionResult(action_id, "SUPPRESS", {})
def submitForm(self, target, fields):
"""Called when a form is submited"""
def submitForm(self, action, target, fields):
"""submit a form
@param target: target jid where we are submitting
@param fields: list of tuples (name, value)
@return: tuple: (id, deferred)
"""
to_jid = jid.JID(target)
print "Form submitted !", fields
return self.get_next_id()
iq = compat.IQ(self.xmlstream, 'set')
iq["to"] = target
iq["from"] = self.me.full()
query = iq.addElement(('jabber:iq:register', 'query'))
if action=='SUBMIT':
form = XMLTools.tupleList2dataForm(fields)
query.addChild(form.toElement())
elif action=='CANCEL':
query.addElement('remove')
else:
error ("FIXME FIXME FIXME: Unmanaged action (%s) in submitForm" % action)
raise NotImplementedError
deferred = iq.send(target)
return (iq['id'], deferred)
## Client management ##
@ -448,7 +466,7 @@ class SAT(service.Service):
def launchAction(self, type, data):
"""Launch a specific action asked by client
@param type: action type (button)
@data: needed data to launch the action
@param data: needed data to launch the action
@return: action id for result, or empty string in case or error
"""
@ -489,6 +507,7 @@ class SAT(service.Service):
#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)
@ -531,16 +550,16 @@ class SAT(service.Service):
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", "FORM")
@data: dictionary
@param type: result type ("PARAM", "SUCCESS", "ERROR", "FORM")
@param data: dictionary
"""
self.bridge.actionResult(type, id, data)
def actionResultExt(self, id, type, data):
"""Send the result of an action, extended version
@param id: same id used with action
@type: result type /!\ only "DICT_DICT" for this method
@data: dictionary of dictionaries
@param type: result type /!\ only "DICT_DICT" for this method
@param data: dictionary of dictionaries
"""
if type != "DICT_DICT":
error("type for actionResultExt must be DICT_DICT, fixing it")
@ -552,9 +571,9 @@ class SAT(service.Service):
def askConfirmation(self, id, type, data, cb):
"""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
@param type: confirmation type ("YES/NO", "FILE_TRANSFERT")
@param data: data (depend of confirmation type)
@param cb: callback called with the answer
"""
if self.__waiting_conf.has_key(id):
error ("Attempt to register two callbacks for the same confirmation")

View file

@ -186,11 +186,6 @@ class DbusObject(dbus.service.Object):
debug("Answer for confirmation [%s]: %s", id, "Accepted" if accepted else "Refused")
return self.cb["confirmationAnswer"](id, accepted, data)
@dbus.service.method(const_INT_PREFIX+const_REQ_SUFFIX,
in_signature='sa(ss)', out_signature='s')
def submitForm(self, target, fields):
info ("Form submited")
return self.cb["submitForm"](target, fields)
@dbus.service.method(const_INT_PREFIX+const_REQ_SUFFIX,
in_signature='s', out_signature='a{ss}')
@ -214,7 +209,7 @@ class DbusObject(dbus.service.Object):
i+=1
if i>=len(in_sign):
raise Exception #FIXME: create an exception here (the '}' is not presend)
if in_sign[i] == '}':
if in_sign[i] == '}' or in_sign[i] == ')':
break
i+=1
return attr_string

View file

@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
from logging import debug, info, error
from xml.dom import minidom
from wokkel import data_form
import pdb
class XMLTools:
@ -57,10 +58,24 @@ class XMLTools:
elem.setAttribute('name', field.var)
elem.setAttribute('type', __field_type)
elem.setAttribute('label', field.label)
#text = doc.createTextNode(field.value)
#elem.appendChild(text)
if field.value:
text = doc.createTextNode(field.value)
elem.appendChild(text)
top_element.appendChild(elem)
result = doc.toxml()
doc.unlink()
return result
@staticmethod
def tupleList2dataForm(values):
"""convert a list of tuples (name,value) to a wokkel submit data form"""
form = data_form.Form('submit')
for value in values:
field = data_form.Field(var=value[0], value=value[1])
form.addField(field)
return form