Fix pep8 support in src/core.

This commit is contained in:
Emmanuel Gil Peyrot 2013-01-18 17:55:35 +01:00
commit 37f7912520
4 changed files with 184 additions and 183 deletions

View file

@ -20,9 +20,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
CONST = {
'client_name' : u'SàT (Salut à toi)',
'client_version' : u'0.3.0', #Please add 'D' at the end for dev versions
'local_dir' : '~/.sat'
'client_name': u'SàT (Salut à toi)',
'client_version': u'0.3.0', # Please add 'D' at the end for dev versions
'local_dir': '~/.sat'
}
### Defaut configuration values ###

View file

@ -19,23 +19,30 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
class ProfileUnknownError(Exception):
pass
class ProfileNotInCacheError(Exception):
pass
class NotConnectedProfileError(Exception):
pass
class UnknownEntityError(Exception):
pass
class UnknownGroupError(Exception):
pass
class NotFound(Exception):
pass
class DataError(Exception):
pass

View file

@ -50,19 +50,19 @@ try:
except ImportError:
from wokkel.subprotocols import XMPPHandler
### logging configuration FIXME: put this elsewhere ###
logging.basicConfig(level=logging.DEBUG,
format='%(message)s')
###
sat_id = 0
def sat_next_id():
global sat_id
sat_id+=1
return "sat_id_"+str(sat_id)
sat_id += 1
return "sat_id_" + str(sat_id)
class SAT(service.Service):
@ -74,18 +74,18 @@ class SAT(service.Service):
try:
_const = os.environ['SAT_CONST_%s' % name]
if _const:
debug(_("Constant %(name)s overrided with [%(value)s]") % {'name':name, 'value': _const})
debug(_("Constant %(name)s overrided with [%(value)s]") % {'name': name, 'value': _const})
return _const
except KeyError:
pass
if not CONST.has_key(name):
if name not in CONST:
error(_('Trying to access an undefined constant'))
raise Exception
return CONST[name]
def set_const(self, name, value):
"""Save a constant"""
if CONST.has_key(name):
if name in CONST:
error(_('Trying to redefine a constant'))
raise Exception
CONST[name] = value
@ -93,21 +93,21 @@ class SAT(service.Service):
def __init__(self):
#TODO: standardize callback system
self.__general_cb_map = {} #callback called for general reasons (key = name)
self.__private_data = {} #used for internal callbacks (key = id)
self.__general_cb_map = {} # callback called for general reasons (key = name)
self.__private_data = {} # used for internal callbacks (key = id)
self.profiles = {}
self.plugins = {}
self.menus = {} #used to know which new menus are wanted by plugins
self.menus = {} # used to know which new menus are wanted by plugins
self.memory=Memory(self)
self.memory = Memory(self)
local_dir = self.memory.getConfig('', 'local_dir')
if not os.path.exists(local_dir):
os.makedirs(local_dir)
self.trigger = TriggerManager() #trigger are used to change SàT behaviour
self.trigger = TriggerManager() # trigger are used to change SàT behaviour
self.bridge=DBusBridge()
self.bridge = DBusBridge()
self.bridge.register("getVersion", lambda: self.get_const('client_version'))
self.bridge.register("getProfileName", self.memory.getProfileName)
self.bridge.register("getProfilesList", self.memory.getProfilesList)
@ -155,15 +155,14 @@ class SAT(service.Service):
info(_("Memory initialised"))
self._import_plugins()
def _import_plugins(self):
"""Import all plugins found in plugins directory"""
import sat.plugins
plugins_path = os.path.dirname(sat.plugins.__file__)
plug_lst = [os.path.splitext(plugin)[0] for plugin in map(os.path.basename,glob(os.path.join(plugins_path,"plugin*.py")))]
__plugins_to_import = {} #plugins we still have to import
plug_lst = [os.path.splitext(plugin)[0] for plugin in map(os.path.basename, glob(os.path.join(plugins_path, "plugin*.py")))]
__plugins_to_import = {} # plugins we still have to import
for plug in plug_lst:
plugin_path = 'sat.plugins.'+plug
plugin_path = 'sat.plugins.' + plug
__import__(plugin_path)
mod = sys.modules[plugin_path]
plugin_info = mod.PLUGIN_INFO
@ -176,58 +175,58 @@ class SAT(service.Service):
def _import_plugins_from_dict(self, plugins_to_import, import_name=None):
"""Recursively import and their dependencies in the right order
@param plugins_to_import: dict where key=import_name and values= (plugin_path, module, plugin_info)"""
if self.plugins.has_key(import_name):
if import_name in self.plugins:
debug('Plugin [%s] already imported, passing' % import_name)
return
if not import_name:
import_name,(plugin_path, mod, plugin_info) = plugins_to_import.popitem()
import_name, (plugin_path, mod, plugin_info) = plugins_to_import.popitem()
else:
if not import_name in plugins_to_import:
raise ImportError(_('Dependency plugin not found: [%s]') % import_name)
plugin_path, mod, plugin_info = plugins_to_import.pop(import_name)
dependencies = plugin_info.setdefault("dependencies",[])
dependencies = plugin_info.setdefault("dependencies", [])
for dependency in dependencies:
if not self.plugins.has_key(dependency):
if dependency not in self.plugins:
debug('Recursively import dependency of [%s]: [%s]' % (import_name, dependency))
self._import_plugins_from_dict(plugins_to_import, dependency)
info (_("importing plugin: %s"), plugin_info['name'])
info(_("importing plugin: %s"), plugin_info['name'])
self.plugins[import_name] = getattr(mod, plugin_info['main'])(self)
if plugin_info.has_key('handler') and plugin_info['handler'] == 'yes':
if 'handler' in plugin_info and plugin_info['handler'] == 'yes':
self.plugins[import_name].is_handler = True
else:
self.plugins[import_name].is_handler = False
#TODO: test xmppclient presence and register handler parent
def connect(self, profile_key = '@DEFAULT@'):
def connect(self, profile_key='@DEFAULT@'):
"""Connect to jabber server"""
self.asyncConnect(profile_key)
def asyncConnect(self, profile_key = '@DEFAULT@'):
def asyncConnect(self, profile_key='@DEFAULT@'):
"""Connect to jabber server with asynchronous reply
@param profile_key: %(doc_profile)s
"""
profile = self.memory.getProfileName(profile_key)
if not profile:
error (_('Trying to connect a non-exsitant profile'))
error(_('Trying to connect a non-exsitant profile'))
raise ProfileUnknownError(profile_key)
if (self.isConnected(profile)):
if self.isConnected(profile):
info(_("already connected !"))
return defer.succeed("None")
def afterMemoryInit(ignore):
"""This part must be called when we have loaded individual parameters from memory"""
try:
port = int(self.memory.getParamA("Port", "Connection", profile_key = profile))
port = int(self.memory.getParamA("Port", "Connection", profile_key=profile))
except ValueError:
error(_("Can't parse port value, using default value"))
port = 5222
current = self.profiles[profile] = xmpp.SatXMPPClient(self, profile,
jid.JID(self.memory.getParamA("JabberID", "Connection", profile_key = profile), profile),
self.memory.getParamA("Password", "Connection", profile_key = profile),
self.memory.getParamA("Server", "Connection", profile_key = profile),
current = self.profiles[profile] = xmpp.SatXMPPClient(
self, profile,
jid.JID(self.memory.getParamA("JabberID", "Connection", profile_key=profile), profile),
self.memory.getParamA("Password", "Connection", profile_key=profile),
self.memory.getParamA("Server", "Connection", profile_key=profile),
port)
current.messageProt = xmpp.SatMessageProtocol(self)
@ -243,10 +242,10 @@ class SAT(service.Service):
current.fallBack.setHandlerParent(current)
current.versionHandler = xmpp.SatVersionHandler(self.get_const('client_name'),
self.get_const('client_version'))
self.get_const('client_version'))
current.versionHandler.setHandlerParent(current)
debug (_("setting plugins parents"))
debug(_("setting plugins parents"))
for plugin in self.plugins.iteritems():
if plugin[1].is_handler:
@ -258,7 +257,7 @@ class SAT(service.Service):
current.startService()
d = current.getConnectionDeferred()
d.addCallback(lambda x: current.roster.got_roster) #we want to be sure that we got the roster
d.addCallback(lambda x: current.roster.got_roster) # we want to be sure that we got the roster
return d
self.memory.startProfileSession(profile)
@ -266,7 +265,7 @@ class SAT(service.Service):
def disconnect(self, profile_key):
"""disconnect from jabber server"""
if (not self.isConnected(profile_key)):
if not self.isConnected(profile_key):
info(_("not connected !"))
return
profile = self.memory.getProfileName(profile_key)
@ -282,8 +281,8 @@ class SAT(service.Service):
if not client:
raise ProfileUnknownError(_('Asking contacts for a non-existant profile'))
ret = []
for item in client.roster.getItems(): #we get all items for client's roster
#and convert them to expected format
for item in client.roster.getItems(): # we get all items for client's roster
# and convert them to expected format
attr = client.roster.getAttributes(item)
ret.append([item.jid.userhost(), attr, item.groups])
return ret
@ -338,12 +337,12 @@ class SAT(service.Service):
return None
return self.profiles[profile]
def registerNewAccount(self, login, password, email, server, port = 5222, id = None, profile_key = '@DEFAULT@'):
def registerNewAccount(self, login, password, email, server, port=5222, id=None, profile_key='@DEFAULT@'):
"""Connect to a server and create a new account using in-band registration"""
profile = self.memory.getProfileName(profile_key)
assert(profile)
next_id = id or 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(xmpp.RegisteringAuthenticator(self, server, login, password, email, next_id, profile))
connector = reactor.connectTCP(server, port, serverRegistrer)
serverRegistrer.clientConnectionLost = lambda conn, reason: connector.disconnect()
@ -356,24 +355,25 @@ class SAT(service.Service):
server = self.memory.getParamA("Server", "Connection", profile_key=profile)
if not user or not password or not server:
info (_('No user or server given'))
info(_('No user or server given'))
#TODO: a proper error message must be sent to frontend
self.actionResult(id, "ERROR", {'message':_("No user, password or server given, can't register new account.")}, profile)
self.actionResult(id, "ERROR", {'message': _("No user, password or server given, can't register new account.")}, profile)
return
confirm_id = sat_next_id()
self.__private_data[confirm_id]=(id,profile)
self.__private_data[confirm_id] = (id, profile)
self.askConfirmation(confirm_id, "YES/NO",
{"message":_("Are you sure to register new account [%(user)s] to server %(server)s ?") % {'user':user, 'server':server, 'profile':profile}},
self.askConfirmation(
confirm_id, "YES/NO",
{"message": _("Are you sure to register new account [%(user)s] to server %(server)s ?") % {'user': user, 'server': server, 'profile': profile}},
self.regisConfirmCB, profile)
print ("===============+++++++++++ REGISTER NEW ACCOUNT++++++++++++++============")
print "id=",id
print "data=",data
print "===============+++++++++++ REGISTER NEW ACCOUNT++++++++++++++============"
print "id=", id
print "data=", data
def regisConfirmCB(self, id, accepted, data, profile):
print _("register Confirmation CB ! (%s)") % str(accepted)
action_id,profile = self.__private_data[id]
action_id, profile = self.__private_data[id]
del self.__private_data[id]
if accepted:
user = jid.parse(self.memory.getParamA("JabberID", "Connection", profile_key=profile))[0]
@ -398,13 +398,13 @@ class SAT(service.Service):
iq["to"] = target
iq["from"] = self.profiles[profile].jid.full()
query = iq.addElement(('jabber:iq:register', 'query'))
if action=='SUBMIT':
if action == 'SUBMIT':
form = tupleList2dataForm(fields)
query.addChild(form.toElement())
elif action=='CANCEL':
elif action == 'CANCEL':
query.addElement('remove')
else:
error (_("FIXME FIXME FIXME: Unmanaged action (%s) in submitForm") % action)
error(_("FIXME FIXME FIXME: Unmanaged action (%s) in submitForm") % action)
raise NotImplementedError
deferred = iq.send(target)
@ -414,7 +414,7 @@ class SAT(service.Service):
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})
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):
@ -424,9 +424,9 @@ class SAT(service.Service):
"""
profile = self.memory.getProfileName(profile_key)
if not profile:
error (_('asking connection status for a non-existant profile'))
error(_('asking connection status for a non-existant profile'))
return
if not self.profiles.has_key(profile):
if profile not in self.profiles:
return False
return self.profiles[profile].isConnected()
@ -439,22 +439,21 @@ class SAT(service.Service):
"""
profile = self.memory.getProfileName(profile_key)
if not profile:
error (_('trying to launch action with a non-existant profile'))
raise Exception #TODO: raise a proper exception
if type=="button":
error(_('trying to launch action with a non-existant profile'))
raise Exception # TODO: raise a proper exception
if type == "button":
try:
cb_name = data['callback_id']
except KeyError:
error (_("Incomplete data"))
error(_("Incomplete data"))
return ""
id = sat_next_id()
self.callGeneralCB(cb_name, id, data, profile = profile)
self.callGeneralCB(cb_name, id, data, profile=profile)
return id
else:
error (_("Unknown action type"))
error(_("Unknown action type"))
return ""
## jabber methods ##
def getWaitingConf(self, profile_key=None):
@ -474,19 +473,19 @@ class SAT(service.Service):
assert(profile)
client = self.profiles[profile]
current_jid = client.jid
mess_data = { #we put data in a dict, so trigger methods can change them
"to": jid.JID(to),
"message": msg,
"subject": subject,
"type": mess_type
}
mess_data = { # we put data in a dict, so trigger methods can change them
"to": jid.JID(to),
"message": msg,
"subject": subject,
"type": mess_type
}
if mess_data["type"] == "auto":
# we try to guess the type
if mess_data["subject"]:
mess_data["type"] = 'normal'
elif not mess_data["to"].resource: #if to JID has a resource, the type is not 'groupchat'
#we may have a groupchat message, we check if the we know this jid
elif not mess_data["to"].resource: # if to JID has a resource, the type is not 'groupchat'
# we may have a groupchat message, we check if the we know this jid
try:
entity_type = self.memory.getEntityData(mess_data["to"], ['type'], profile)["type"]
#FIXME: should entity_type manage ressources ?
@ -505,7 +504,7 @@ class SAT(service.Service):
return
debug(_("Sending jabber message of type [%(type)s] to %(to)s...") % {"type": mess_data["type"], "to": to})
message = domish.Element((None,'message'))
message = domish.Element((None, 'message'))
message["to"] = mess_data["to"].full()
message["from"] = current_jid.full()
message["type"] = mess_data["type"]
@ -513,25 +512,23 @@ class SAT(service.Service):
message.addElement("subject", None, subject)
message.addElement("body", None, mess_data["message"])
client.xmlstream.send(message)
if mess_data["type"]!="groupchat":
self.memory.addToHistory(current_jid, jid.JID(to), unicode(mess_data["message"]), unicode(mess_data["type"]), profile=profile) #we don't add groupchat message to history, as we get them back
#and they will be added then
self.bridge.newMessage(message['from'], unicode(mess_data["message"]), mess_type=mess_data["type"], to_jid=message['to'], extra={}, profile=profile) #We send back the message, so all clients are aware of it
if mess_data["type"] != "groupchat":
self.memory.addToHistory(current_jid, jid.JID(to), unicode(mess_data["message"]), unicode(mess_data["type"]), profile=profile) # we don't add groupchat message to history, as we get them back
# and they will be added then
self.bridge.newMessage(message['from'], unicode(mess_data["message"]), mess_type=mess_data["type"], to_jid=message['to'], extra={}, profile=profile) # We send back the message, so all clients are aware of it
def setPresence(self, to="", show="", priority = 0, statuses={}, profile_key='@DEFAULT@'):
def setPresence(self, to="", show="", priority=0, statuses={}, profile_key='@DEFAULT@'):
"""Send our presence information"""
profile = self.memory.getProfileName(profile_key)
assert(profile)
to_jid = jid.JID(to) if to else None
self.profiles[profile].presence.available(to_jid, show, statuses, priority)
#XXX: FIXME: temporary fix to work around openfire 3.7.0 bug (presence is not broadcasted to generating resource)
if statuses.has_key(''):
if '' in statuses:
statuses['default'] = statuses['']
del statuses['']
self.bridge.presenceUpdate(self.profiles[profile].jid.full(), show,
int(priority), statuses, profile)
self.bridge.presenceUpdate(self.profiles[profile].jid.full(), show,
int(priority), statuses, profile)
def subscription(self, subs_type, raw_jid, profile_key):
"""Called to manage subscription
@ -541,22 +538,22 @@ class SAT(service.Service):
profile = self.memory.getProfileName(profile_key)
assert(profile)
to_jid = jid.JID(raw_jid)
debug (_('subsciption request [%(subs_type)s] for %(jid)s') % {'subs_type':subs_type, 'jid':to_jid.full()})
if subs_type=="subscribe":
debug(_('subsciption request [%(subs_type)s] for %(jid)s') % {'subs_type': subs_type, 'jid': to_jid.full()})
if subs_type == "subscribe":
self.profiles[profile].presence.subscribe(to_jid)
elif subs_type=="subscribed":
elif subs_type == "subscribed":
self.profiles[profile].presence.subscribed(to_jid)
elif subs_type=="unsubscribe":
elif subs_type == "unsubscribe":
self.profiles[profile].presence.unsubscribe(to_jid)
elif subs_type=="unsubscribed":
elif subs_type == "unsubscribed":
self.profiles[profile].presence.unsubscribed(to_jid)
def addContact(self, to, profile_key):
"""Add a contact in roster list"""
profile = self.memory.getProfileName(profile_key)
assert(profile)
to_jid=jid.JID(to)
#self.profiles[profile].roster.addItem(to_jid) XXX: disabled (cf http://wokkel.ik.nu/ticket/56))
to_jid = jid.JID(to)
#self.profiles[profile].roster.addItem(to_jid) #XXX: disabled (cf http://wokkel.ik.nu/ticket/56))
self.profiles[profile].presence.subscribe(to_jid)
def updateContact(self, to, name, groups, profile_key):
@ -574,20 +571,19 @@ class SAT(service.Service):
"""Remove contact from roster list"""
profile = self.memory.getProfileName(profile_key)
assert(profile)
to_jid=jid.JID(to)
to_jid = jid.JID(to)
self.profiles[profile].roster.removeItem(to_jid)
self.profiles[profile].presence.unsubscribe(to_jid)
## callbacks ##
def serverDisco(self, disco, profile):
"""xep-0030 Discovery Protocol."""
for feature in disco.features:
debug (_("Feature found: %s"),feature)
debug(_("Feature found: %s"), feature)
self.memory.addServerFeature(feature, profile)
for cat, type in disco.identities:
debug (_("Identity found: [%(category)s/%(type)s] %(identity)s") % {'category':cat, 'type':type, 'identity':disco.identities[(cat,type)]})
debug(_("Identity found: [%(category)s/%(type)s] %(identity)s") % {'category': cat, 'type': type, 'identity': disco.identities[(cat, type)]})
def serverDiscoItems(self, disco_result, disco_client, profile, initialized):
"""xep-0030 Discovery Protocol.
@ -598,23 +594,21 @@ class SAT(service.Service):
def _check_entity_cb(result, entity, profile):
for category, type in result.identities:
debug (_('Identity added: (%(category)s,%(type)s) ==> %(entity)s [%(profile)s]') % {
'category':category, 'type':type, 'entity':entity, 'profile':profile})
debug(_('Identity added: (%(category)s,%(type)s) ==> %(entity)s [%(profile)s]') % {
'category': category, 'type': type, 'entity': entity, 'profile': profile})
self.memory.addServerIdentity(category, type, entity, profile)
def _errback(result, entity, profile):
warning(_("Can't get information on identity [%(entity)s] for profile [%(profile)s]") % {'entity':entity, 'profile': profile})
warning(_("Can't get information on identity [%(entity)s] for profile [%(profile)s]") % {'entity': entity, 'profile': profile})
defer_list = []
for item in disco_result._items:
if item.entity.full().count('.') == 1: #XXX: workaround for a bug on jabberfr, tmp
if item.entity.full().count('.') == 1: # XXX: workaround for a bug on jabberfr, tmp
warning(_('Using jabberfr workaround, be sure your domain has at least two levels (e.g. "example.tld", not "example" alone)'))
continue
args = [item.entity, profile]
defer_list.append(disco_client.requestInfo(item.entity).addCallbacks(_check_entity_cb, _errback, args, None, args))
defer.DeferredList(defer_list).chainDeferred(initialized)
## Generic HMI ##
def actionResult(self, action_id, action_type, data, profile):
@ -636,8 +630,6 @@ class SAT(service.Service):
action_type = "DICT_DICT"
self.bridge.actionResultExt(action_type, action_id, data, profile)
def askConfirmation(self, conf_id, conf_type, data, cb, profile):
"""Add a confirmation callback
@param conf_id: conf_id used to get answer
@ -648,21 +640,20 @@ class SAT(service.Service):
client = self.getClient(profile)
if not client:
raise ProfileUnknownError(_("Asking confirmation a non-existant profile"))
if client._waiting_conf.has_key(conf_id):
error (_("Attempt to register two callbacks for the same confirmation"))
if conf_id in client._waiting_conf:
error(_("Attempt to register two callbacks for the same confirmation"))
else:
client._waiting_conf[conf_id] = (conf_type, data, cb)
self.bridge.askConfirmation(conf_id, conf_type, data, profile)
def confirmationAnswer(self, conf_id, accepted, data, profile):
"""Called by frontends to answer confirmation requests"""
client = self.getClient(profile)
if not client:
raise ProfileUnknownError(_("Confirmation answer from a non-existant profile"))
debug (_("Received confirmation answer for conf_id [%(conf_id)s]: %(success)s") % {'conf_id': conf_id, 'success':_("accepted") if accepted else _("refused")})
if not client._waiting_conf.has_key(conf_id):
error (_("Received an unknown confirmation (%(id)s for %(profile)s)") % {'id': conf_id, 'profile': profile})
debug(_("Received confirmation answer for conf_id [%(conf_id)s]: %(success)s") % {'conf_id': conf_id, 'success': _("accepted") if accepted else _("refused")})
if conf_id not in client._waiting_conf:
error(_("Received an unknown confirmation (%(id)s for %(profile)s)") % {'id': conf_id, 'profile': profile})
else:
cb = client._waiting_conf[conf_id][-1]
del client._waiting_conf[conf_id]
@ -680,8 +671,8 @@ class SAT(service.Service):
client = self.getClient(profile)
if not client:
raise ProfileUnknownError
if not client._progress_cb_map.has_key(progress_id):
error (_("Trying to remove an unknow progress callback"))
if progress_id not in client._progress_cb_map:
error(_("Trying to remove an unknow progress callback"))
else:
del client._progress_cb_map[progress_id]
@ -707,8 +698,8 @@ class SAT(service.Service):
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"))
if name not in self.__general_cb_map:
error(_("Trying to remove an unknow general callback"))
else:
del self.__general_cb_map[name]
@ -722,15 +713,15 @@ class SAT(service.Service):
#Menus management
def importMenu(self, category, name, callback, help_string = "", type = "NORMAL"):
def importMenu(self, category, name, callback, help_string="", type="NORMAL"):
"""register a new menu for frontends
@param category: category of the menu
@param name: menu item entry
@param callback: method to be called when menuitem is selected"""
if self.menus.has_key((category,name)):
error ("Want to register a menu which already existe")
if (category, name) in self.menus:
error("Want to register a menu which already existe")
return
self.menus[(category,name,type)] = {'callback':callback, 'help_string':help_string, 'type':type}
self.menus[(category, name, type)] = {'callback': callback, 'help_string': help_string, 'type': type}
def getMenus(self):
"""Return all menus registered"""
@ -739,21 +730,21 @@ class SAT(service.Service):
def getMenuHelp(self, category, name, type="NORMAL"):
"""return the help string of the menu"""
try:
return self.menus[(category,name,type)]['help_string']
return self.menus[(category, name, type)]['help_string']
except KeyError:
error (_("Trying to access an unknown menu"))
error(_("Trying to access an unknown menu"))
return ""
def callMenu(self, category, name, type="NORMAL", profile_key='@DEFAULT@'):
"""return the id of the action"""
profile = self.memory.getProfileName(profile_key)
if not profile_key:
error (_('Non-exsitant profile'))
error(_('Non-exsitant profile'))
return ""
if self.menus.has_key((category,name,type)):
if (category, name, type) in self.menus:
id = self.get_next_id()
self.menus[(category,name,type)]['callback'](id, profile)
self.menus[(category, name, type)]['callback'](id, profile)
return id
else:
error (_("Trying to access an unknown menu (%(category)s/%(name)s/%(type)s)")%{'category':category, 'name':name,'type':type})
error(_("Trying to access an unknown menu (%(category)s/%(name)s/%(type)s)") % {'category': category, 'name': name, 'type': type})
return ""

View file

@ -22,7 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
from twisted.internet import task, defer
from twisted.words.protocols.jabber import jid, xmlstream
from wokkel import client, disco, xmppim, generic, compat, delay
from logging import debug, info, error
from logging import debug, info, warning, error
from sat.core import exceptions
from calendar import timegm
@ -32,14 +32,13 @@ class SatXMPPClient(client.XMPPClient):
def __init__(self, host_app, profile, user_jid, password, host=None, port=5222):
client.XMPPClient.__init__(self, user_jid, password, host, port)
self.factory.clientConnectionLost = self.connectionLost
self.__connected=False
self.__connected = False
self.profile = profile
self.host_app = host_app
self.client_initialized = defer.Deferred()
self.conn_deferred = defer.Deferred()
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._waiting_conf = {} # callback called when a confirmation is received
self._progress_cb_map = {} # callback called when a progress is requested (key = progress id)
def getConnectionDeferred(self):
"""Return a deferred which fire when the client is connected"""
@ -49,16 +48,15 @@ class SatXMPPClient(client.XMPPClient):
if not self.host_app.trigger.point("XML Initialized", xmlstream, self.profile):
return
client.XMPPClient._authd(self, xmlstream)
self.__connected=True
info (_("********** [%s] CONNECTED **********") % self.profile)
self.__connected = True
info(_("********** [%s] CONNECTED **********") % self.profile)
self.streamInitialized()
self.host_app.bridge.connected(self.profile) #we send the signal to the clients
self.host_app.bridge.connected(self.profile) # we send the signal to the clients
def streamInitialized(self):
"""Called after _authd"""
debug (_("XML stream is initialized"))
self.keep_alife = task.LoopingCall(self.xmlstream.send, " ") #Needed to avoid disconnection (specially with openfire)
debug(_("XML stream is initialized"))
self.keep_alife = task.LoopingCall(self.xmlstream.send, " ") # Needed to avoid disconnection (specially with openfire)
self.keep_alife.start(180)
self.disco = SatDiscoProtocol(self)
@ -73,18 +71,18 @@ class SatXMPPClient(client.XMPPClient):
self.presence.available()
self.disco.requestInfo(jid.JID(self.jid.host)).addCallback(self.host_app.serverDisco, self.profile) #FIXME: use these informations
self.disco.requestInfo(jid.JID(self.jid.host)).addCallback(self.host_app.serverDisco, self.profile) # FIXME: use these informations
self.disco.requestItems(jid.JID(self.jid.host)).addCallback(self.host_app.serverDiscoItems, self.disco, self.profile, self.client_initialized)
self.conn_deferred.callback(None)
def initializationFailed(self, reason):
print ("initializationFailed: %s" % reason)
print "initializationFailed: %s" % reason
self.host_app.bridge.connectionError("AUTH_ERROR", self.profile)
try:
client.XMPPClient.initializationFailed(self, reason)
except:
#we already send an error signal, no need to raise an exception
# we already send an error signal, no need to raise an exception
pass
self.conn_deferred.errback()
@ -92,14 +90,14 @@ class SatXMPPClient(client.XMPPClient):
return self.__connected
def connectionLost(self, connector, unused_reason):
self.__connected=False
info (_("********** [%s] DISCONNECTED **********") % self.profile)
self.__connected = False
info(_("********** [%s] DISCONNECTED **********") % self.profile)
try:
self.keep_alife.stop()
except AttributeError:
debug (_("No keep_alife"))
self.host_app.bridge.disconnected(self.profile) #we send the signal to the clients
self.host_app.purgeClient(self.profile) #and we remove references to this client
debug(_("No keep_alife"))
self.host_app.bridge.disconnected(self.profile) # we send the signal to the clients
self.host_app.purgeClient(self.profile) # and we remove references to this client
class SatMessageProtocol(xmppim.MessageProtocol):
@ -109,7 +107,7 @@ class SatMessageProtocol(xmppim.MessageProtocol):
self.host = host
def onMessage(self, message):
debug (_(u"got message from: %s"), message["from"])
debug(_(u"got message from: %s"), message["from"])
if not self.host.trigger.point("MessageReceived", message, profile=self.parent.profile):
return
for e in message.elements():
@ -120,7 +118,7 @@ class SatMessageProtocol(xmppim.MessageProtocol):
_delay = delay.Delay.fromElement(filter(lambda elm: elm.name == 'delay', message.elements())[0])
timestamp = timegm(_delay.stamp.utctimetuple())
extra = {"archive": str(timestamp)}
if mess_type != 'groupchat': #XXX: we don't save delayed messages in history for groupchats
if mess_type != 'groupchat': # XXX: we don't save delayed messages in history for groupchats
#TODO: add delayed messages to history if they aren't already in it
self.host.memory.addToHistory(jid.JID(message["from"]), jid.JID(message["to"]), mess_body, mess_type, timestamp, profile=self.parent.profile)
except IndexError:
@ -129,6 +127,7 @@ class SatMessageProtocol(xmppim.MessageProtocol):
self.host.bridge.newMessage(message["from"], mess_body, mess_type, message['to'], extra, profile=self.parent.profile)
break
class SatRosterProtocol(xmppim.RosterClientProtocol):
def __init__(self, host):
@ -136,8 +135,8 @@ class SatRosterProtocol(xmppim.RosterClientProtocol):
self.host = host
self.got_roster = defer.Deferred()
#XXX: the two following dicts keep a local copy of the roster
self._groups = {} #map from groups to bare jids: key=group value=set of bare jids
self._jids = {} #map from bare jids to RosterItem: key=jid value=RosterItem
self._groups = {} # map from groups to bare jids: key=group value=set of bare jids
self._jids = {} # map from bare jids to RosterItem: key=jid value=RosterItem
def rosterCb(self, roster):
for raw_jid, item in roster.iteritems():
@ -193,17 +192,17 @@ class SatRosterProtocol(xmppim.RosterClientProtocol):
#TODO: send a signal to frontends
if not item.subscriptionTo and not item.subscriptionFrom and not item.ask:
#XXX: current behaviour: we don't want contact in our roster list
#if there is no presence subscription
#may change in the future
# if there is no presence subscription
# may change in the future
self.removeItem(item.jid)
return
info (_("new contact in roster list: %s"), item.jid.full())
info(_("new contact in roster list: %s"), item.jid.full())
#self.host.memory.addContact(item.jid, item_attr, item.groups, self.parent.profile)
bare_jid = item.jid.userhost()
self._jids[bare_jid] = item
for group in item.groups:
self._groups.setdefault(group,set()).add(bare_jid)
self._groups.setdefault(group, set()).add(bare_jid)
self.host.bridge.newContact(item.jid.full(), self.getAttributes(item), item.groups, self.parent.profile)
def onRosterRemove(self, entity):
@ -211,11 +210,11 @@ class SatRosterProtocol(xmppim.RosterClientProtocol):
print _("removing %s from roster list") % entity.full()
bare_jid = entity.userhost()
#we first remove item from local cache (self._groups and self._jids)
# we first remove item from local cache (self._groups and self._jids)
try:
item = self._jids.pop(bare_jid)
except KeyError:
log.warning("Received a roster remove event for an item not in cache")
warning("Received a roster remove event for an item not in cache")
return
for group in item.groups:
try:
@ -224,10 +223,10 @@ class SatRosterProtocol(xmppim.RosterClientProtocol):
if not jids_set:
del self._groups[group]
except KeyError:
log.warning("there is not cache for the group [%(groups)s] of the removed roster item [%(jid)s]" %
{"group": group, "jid": bare_jid})
warning("there is not cache for the group [%(groups)s] of the removed roster item [%(jid)s]" %
{"group": group, "jid": bare_jid})
#then we send the bridge signal
# then we send the bridge signal
self.host.bridge.contactDeleted(entity.userhost(), self.parent.profile)
def getGroups(self):
@ -256,7 +255,7 @@ class SatRosterProtocol(xmppim.RosterClientProtocol):
try:
return self._groups[group]
except KeyError:
return exceptions.UnknownGroupError
return exceptions.UnknownGroupError
class SatPresenceProtocol(xmppim.PresenceClientProtocol):
@ -266,37 +265,38 @@ class SatPresenceProtocol(xmppim.PresenceClientProtocol):
self.host = host
def availableReceived(self, entity, show=None, statuses=None, priority=0):
debug (_("presence update for [%(entity)s] (available, show=%(show)s statuses=%(statuses)s priority=%(priority)d)") % {'entity':entity, 'show':show, 'statuses':statuses, 'priority':priority})
debug(_("presence update for [%(entity)s] (available, show=%(show)s statuses=%(statuses)s priority=%(priority)d)") % {'entity': entity, 'show': show, 'statuses': statuses, 'priority': priority})
if not statuses:
statuses = {}
if statuses.has_key(None): #we only want string keys
if None in statuses: # we only want string keys
statuses["default"] = statuses[None]
del statuses[None]
self.host.memory.setPresenceStatus(entity, show or "",
int(priority), statuses, self.parent.profile)
int(priority), statuses,
self.parent.profile)
#now it's time to notify frontends
self.host.bridge.presenceUpdate(entity.full(), show or "",
int(priority), statuses, self.parent.profile)
# now it's time to notify frontends
self.host.bridge.presenceUpdate(entity.full(), show or "",
int(priority), statuses,
self.parent.profile)
def unavailableReceived(self, entity, statuses=None):
debug (_("presence update for [%(entity)s] (unavailable, statuses=%(statuses)s)") % {'entity':entity, 'statuses':statuses})
debug(_("presence update for [%(entity)s] (unavailable, statuses=%(statuses)s)") % {'entity': entity, 'statuses': statuses})
if not statuses:
statuses = {}
if statuses.has_key(None): #we only want string keys
if None in statuses: # we only want string keys
statuses["default"] = statuses[None]
del statuses[None]
self.host.memory.setPresenceStatus(entity, "unavailable", 0, statuses, self.parent.profile)
#now it's time to notify frontends
# now it's time to notify frontends
self.host.bridge.presenceUpdate(entity.full(), "unavailable", 0, statuses, self.parent.profile)
def available(self, entity=None, show=None, statuses=None, priority=0):
if not statuses:
statuses = {}
@ -319,7 +319,7 @@ class SatPresenceProtocol(xmppim.PresenceClientProtocol):
xmppim.PresenceClientProtocol.subscribed(self, entity)
self.host.memory.delWaitingSub(entity.userhost(), self.parent.profile)
item = self.parent.roster.getItem(entity)
if not item or not item.subscriptionTo: #we automatically subscribe to 'to' presence
if not item or not item.subscriptionTo: # we automatically subscribe to 'to' presence
debug(_('sending automatic "from" subscription request'))
self.subscribe(entity)
@ -328,18 +328,18 @@ class SatPresenceProtocol(xmppim.PresenceClientProtocol):
self.host.memory.delWaitingSub(entity.userhost(), self.parent.profile)
def subscribedReceived(self, entity):
debug (_("subscription approved for [%s]") % entity.userhost())
debug(_("subscription approved for [%s]") % entity.userhost())
self.host.bridge.subscribe('subscribed', entity.userhost(), self.parent.profile)
def unsubscribedReceived(self, entity):
debug (_("unsubscription confirmed for [%s]") % entity.userhost())
debug(_("unsubscription confirmed for [%s]") % entity.userhost())
self.host.bridge.subscribe('unsubscribed', entity.userhost(), self.parent.profile)
def subscribeReceived(self, entity):
debug (_("subscription request from [%s]") % entity.userhost())
debug(_("subscription request from [%s]") % entity.userhost())
item = self.parent.roster.getItem(entity)
if item and item.subscriptionTo:
#We automatically accept subscription if we are already subscribed to contact presence
# We automatically accept subscription if we are already subscribed to contact presence
debug(_('sending automatic subscription acceptance'))
self.subscribed(entity)
else:
@ -347,27 +347,30 @@ class SatPresenceProtocol(xmppim.PresenceClientProtocol):
self.host.bridge.subscribe('subscribe', entity.userhost(), self.parent.profile)
def unsubscribeReceived(self, entity):
debug (_("unsubscription asked for [%s]") % entity.userhost())
debug(_("unsubscription asked for [%s]") % entity.userhost())
item = self.parent.roster.getItem(entity)
if item and item.subscriptionFrom: #we automatically remove contact
if item and item.subscriptionFrom: # 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):
def __init__(self, host):
disco.DiscoClientProtocol.__init__(self)
class SatFallbackHandler(generic.FallbackHandler):
def __init__(self, host):
generic.FallbackHandler.__init__(self)
def iqFallback(self, iq):
if iq.handled == True:
if iq.handled is True:
return
debug (u"iqFallback: xml = [%s]" % (iq.toXml()))
debug(u"iqFallback: xml = [%s]" % (iq.toXml()))
generic.FallbackHandler.iqFallback(self, iq)
class RegisteringAuthenticator(xmlstream.ConnectAuthenticator):
def __init__(self, host, jabber_host, user_login, user_pass, email, answer_id, profile):
@ -379,7 +382,7 @@ class RegisteringAuthenticator(xmlstream.ConnectAuthenticator):
self.user_email = email
self.answer_id = answer_id
self.profile = profile
print _("Registration asked for"),user_login, user_pass, jabber_host
print _("Registration asked for"), user_login, user_pass, jabber_host
def connectionMade(self):
print "connectionMade"
@ -400,25 +403,26 @@ class RegisteringAuthenticator(xmlstream.ConnectAuthenticator):
reg = iq.send(self.jabber_host).addCallbacks(self.registrationAnswer, self.registrationFailure)
def registrationAnswer(self, answer):
debug (_("registration answer: %s") % answer.toXml())
debug(_("registration answer: %s") % answer.toXml())
answer_type = "SUCCESS"
answer_data={"message":_("Registration successfull")}
answer_data = {"message": _("Registration successfull")}
self.host.bridge.actionResult(answer_type, self.answer_id, answer_data, self.profile)
self.xmlstream.sendFooter()
def registrationFailure(self, failure):
info (_("Registration failure: %s") % str(failure.value))
info(_("Registration failure: %s") % str(failure.value))
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")}
answer_data = {"message": _("Username already exists, please choose an other one")}
else:
answer_data['reason'] = 'unknown'
answer_data={"message":_("Registration failed (%s)") % str(failure.value.condition)}
answer_data = {"message": _("Registration failed (%s)") % str(failure.value.condition)}
self.host.bridge.actionResult(answer_type, self.answer_id, answer_data, self.profile)
self.xmlstream.sendFooter()
class SatVersionHandler(generic.VersionHandler):
def getDiscoInfo(self, requestor, target, node):
@ -428,4 +432,3 @@ class SatVersionHandler(generic.VersionHandler):
# disco features, and when the server (seen on ejabberd) generate its own hash for security check
# it reject our features (resulting in e.g. no notification on PEP)
return generic.VersionHandler.getDiscoInfo(self, requestor, target, None)