core: use of the new core.log module:

/!\ this is a massive refactoring and was largely automated, it probably did bring some bugs /!\
This commit is contained in:
Goffi 2014-04-19 19:19:19 +02:00
commit 501bc92528
57 changed files with 707 additions and 941 deletions

View file

@ -20,7 +20,8 @@
from sat.core.i18n import _
from bridge_frontend import BridgeFrontend
import dbus
from logging import debug, error
from sat.core.log import getLogger
log = getLogger(__name__)
from sat.core.exceptions import BridgeExceptionNoService, BridgeInitError
from dbus.mainloop.glib import DBusGMainLoop
@ -47,7 +48,7 @@ class DBusBridgeFrontend(BridgeFrontend):
if e._dbus_error_name == 'org.freedesktop.DBus.Error.ServiceUnknown':
raise BridgeExceptionNoService
elif e._dbus_error_name == 'org.freedesktop.DBus.Error.NotSupported':
print u"D-Bus is not launched, please see README to see instructions on how to launch it"
log.error(_(u"D-Bus is not launched, please see README to see instructions on how to launch it"))
raise BridgeInitError
else:
raise e
@ -59,7 +60,7 @@ class DBusBridgeFrontend(BridgeFrontend):
elif iface == "plugin":
self.db_plugin_iface.connect_to_signal(functionName, handler)
else:
error(_('Unknown interface'))
log.error(_('Unknown interface'))
def __getattribute__(self, name):
""" usual __getattribute__ if the method exists, else try to find a plugin method """

View file

@ -17,12 +17,14 @@
# 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/>.
from sat.core.i18n import _
from bridge import Bridge
import dbus
import dbus.service
import dbus.mainloop.glib
import inspect
from logging import debug, info, error
from sat.core.log import getLogger
log = getLogger(__name__)
from twisted.internet.defer import Deferred
from sat.core.exceptions import BridgeInitError
@ -69,7 +71,7 @@ class DbusObject(dbus.service.Object):
def __init__(self, bus, path):
dbus.service.Object.__init__(self, bus, path)
debug("Init DbusObject...")
log.debug("Init DbusObject...")
self.cb = {}
def register(self, name, cb):
@ -84,7 +86,7 @@ class DbusObject(dbus.service.Object):
if "callback" in kwargs:
#we must have errback too
if not "errback" in kwargs:
error("errback is missing in method call [%s]" % name)
log.error("errback is missing in method call [%s]" % name)
raise InternalError
callback = kwargs.pop("callback")
errback = kwargs.pop("errback")
@ -94,13 +96,13 @@ class DbusObject(dbus.service.Object):
result = self.cb[name](*args, **kwargs)
if async:
if not isinstance(result, Deferred):
error("Asynchronous method [%s] does not return a Deferred." % name)
log.error("Asynchronous method [%s] does not return a Deferred." % name)
raise AsyncNotDeferred
result.addCallback(lambda result: callback() if result is None else callback(result))
result.addErrback(lambda err: errback(GenericException(err)))
else:
if isinstance(result, Deferred):
error("Synchronous method [%s] return a Deferred." % name)
log.error("Synchronous method [%s] return a Deferred." % name)
raise DeferredNotAsync
return result
### signals ###
@ -502,7 +504,7 @@ class DbusObject(dbus.service.Object):
attributes = ', '.join(self.__attributes(signature))
#TODO: use doc parameter to name attributes
#code = compile ('def '+name+' (self,'+attributes+'): debug ("'+name+' signal")', '<DBus bridge>','exec') #XXX: the debug is too annoying with xmllog
#code = compile ('def '+name+' (self,'+attributes+'): log.debug ("'+name+' signal")', '<DBus bridge>','exec') #XXX: the log.debug is too annoying with xmllog
code = compile('def ' + name + ' (self,' + attributes + '): pass', '<DBus bridge>', 'exec')
exec (code)
signal = locals()[name]
@ -517,12 +519,12 @@ class DBusBridge(Bridge):
def __init__(self):
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
Bridge.__init__(self)
info("Init DBus...")
log.info("Init DBus...")
try:
self.session_bus = dbus.SessionBus()
except dbus.DBusException as e:
if e._dbus_error_name == 'org.freedesktop.DBus.Error.NotSupported':
print u"D-Bus is not launched, please see README to see instructions on how to launch it"
log.error(_(u"D-Bus is not launched, please see README to see instructions on how to launch it"))
raise BridgeInitError
self.dbus_name = dbus.service.BusName(const_INT_PREFIX, self.session_bus)
self.dbus_bridge = DbusObject(self.session_bus, const_OBJ_PATH)
@ -570,13 +572,13 @@ class DBusBridge(Bridge):
self.dbus_bridge.subscribe(sub_type, entity_jid, profile)
def register(self, name, callback):
debug("registering DBus bridge method [%s]", name)
log.debug("registering DBus bridge method [%s]" % name)
self.dbus_bridge.register(name, callback)
def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}):
"""Dynamically add a method to Dbus Bridge"""
#FIXME: doc parameter is kept only temporary, the time to remove it from calls
print ("Adding method [%s] to DBus bridge" % name)
log.debug("Adding method [%s] to DBus bridge" % name)
self.dbus_bridge.addMethod(name, int_suffix, in_sign, out_sign, method, async)
self.register(name, method)

View file

@ -17,9 +17,10 @@
# 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/>.
from logging import debug, info, error
from sat.core.log import getLogger
log = getLogger(__name__)
class Bridge(object):
def __init__(self):
info("Bridge initialization")
log.info("Bridge initialization")

View file

@ -17,12 +17,14 @@
# 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/>.
from sat.core.i18n import _
from bridge import Bridge
import dbus
import dbus.service
import dbus.mainloop.glib
import inspect
from logging import debug, info, error
from sat.core.log import getLogger
log = getLogger(__name__)
from twisted.internet.defer import Deferred
from sat.core.exceptions import BridgeInitError
@ -69,7 +71,7 @@ class DbusObject(dbus.service.Object):
def __init__(self, bus, path):
dbus.service.Object.__init__(self, bus, path)
debug("Init DbusObject...")
log.debug("Init DbusObject...")
self.cb = {}
def register(self, name, cb):
@ -84,7 +86,7 @@ class DbusObject(dbus.service.Object):
if "callback" in kwargs:
#we must have errback too
if not "errback" in kwargs:
error("errback is missing in method call [%s]" % name)
log.error("errback is missing in method call [%s]" % name)
raise InternalError
callback = kwargs.pop("callback")
errback = kwargs.pop("errback")
@ -94,13 +96,13 @@ class DbusObject(dbus.service.Object):
result = self.cb[name](*args, **kwargs)
if async:
if not isinstance(result, Deferred):
error("Asynchronous method [%s] does not return a Deferred." % name)
log.error("Asynchronous method [%s] does not return a Deferred." % name)
raise AsyncNotDeferred
result.addCallback(lambda result: callback() if result is None else callback(result))
result.addErrback(lambda err: errback(GenericException(err)))
else:
if isinstance(result, Deferred):
error("Synchronous method [%s] return a Deferred." % name)
log.error("Synchronous method [%s] return a Deferred." % name)
raise DeferredNotAsync
return result
### signals ###
@ -194,7 +196,7 @@ class DbusObject(dbus.service.Object):
attributes = ', '.join(self.__attributes(signature))
#TODO: use doc parameter to name attributes
#code = compile ('def '+name+' (self,'+attributes+'): debug ("'+name+' signal")', '<DBus bridge>','exec') #XXX: the debug is too annoying with xmllog
#code = compile ('def '+name+' (self,'+attributes+'): log.debug ("'+name+' signal")', '<DBus bridge>','exec') #XXX: the log.debug is too annoying with xmllog
code = compile('def ' + name + ' (self,' + attributes + '): pass', '<DBus bridge>', 'exec')
exec (code)
signal = locals()[name]
@ -209,25 +211,25 @@ class DBusBridge(Bridge):
def __init__(self):
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
Bridge.__init__(self)
info("Init DBus...")
log.info("Init DBus...")
try:
self.session_bus = dbus.SessionBus()
except dbus.DBusException as e:
if e._dbus_error_name == 'org.freedesktop.DBus.Error.NotSupported':
print u"D-Bus is not launched, please see README to see instructions on how to launch it"
log.error(_(u"D-Bus is not launched, please see README to see instructions on how to launch it"))
raise BridgeInitError
self.dbus_name = dbus.service.BusName(const_INT_PREFIX, self.session_bus)
self.dbus_bridge = DbusObject(self.session_bus, const_OBJ_PATH)
##DIRECT_CALLS##
def register(self, name, callback):
debug("registering DBus bridge method [%s]", name)
log.debug("registering DBus bridge method [%s]" % name)
self.dbus_bridge.register(name, callback)
def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}):
"""Dynamically add a method to Dbus Bridge"""
#FIXME: doc parameter is kept only temporary, the time to remove it from calls
print ("Adding method [%s] to DBus bridge" % name)
log.debug("Adding method [%s] to DBus bridge" % name)
self.dbus_bridge.addMethod(name, int_suffix, in_sign, out_sign, method, async)
self.register(name, method)

View file

@ -20,7 +20,8 @@
from sat.core.i18n import _
from bridge_frontend import BridgeFrontend
import dbus
from logging import debug, error
from sat.core.log import getLogger
log = getLogger(__name__)
from sat.core.exceptions import BridgeExceptionNoService, BridgeInitError
from dbus.mainloop.glib import DBusGMainLoop
@ -47,7 +48,7 @@ class DBusBridgeFrontend(BridgeFrontend):
if e._dbus_error_name == 'org.freedesktop.DBus.Error.ServiceUnknown':
raise BridgeExceptionNoService
elif e._dbus_error_name == 'org.freedesktop.DBus.Error.NotSupported':
print u"D-Bus is not launched, please see README to see instructions on how to launch it"
log.error(_(u"D-Bus is not launched, please see README to see instructions on how to launch it"))
raise BridgeInitError
else:
raise e
@ -59,7 +60,7 @@ class DBusBridgeFrontend(BridgeFrontend):
elif iface == "plugin":
self.db_plugin_iface.connect_to_signal(functionName, handler)
else:
error(_('Unknown interface'))
log.error(_('Unknown interface'))
def __getattribute__(self, name):
""" usual __getattribute__ if the method exists, else try to find a plugin method """

View file

@ -25,20 +25,18 @@ from twisted.words.xish import domish
from twisted.internet import reactor
from wokkel.xmppim import RosterItem
from sat.bridge.DBus import DBusBridge
import logging
from logging import debug, info, warning, error
import sys
import os.path
from sat.core import xmpp
from sat.core import exceptions
from sat.core.log import getLogger
log = getLogger(__name__)
from sat.core.constants import Const as C
from sat.memory.memory import Memory
from sat.tools.misc import TriggerManager
from sat.stdui import ui_contact_list
from glob import glob
from uuid import uuid4
import sys
import os.path
try:
from collections import OrderedDict # only available from python 2.7
@ -93,7 +91,7 @@ class SAT(service.Service):
try:
self.bridge = DBusBridge()
except exceptions.BridgeInitError:
print (u"Bridge can't be initialised, can't start SàT core") # reactor is not launched yet, so we can't use error log
log.error(u"Bridge can't be initialised, can't start SàT core")
sys.exit(1)
self.bridge.register("getVersion", lambda: C.APP_VERSION)
self.bridge.register("getProfileName", self.memory.getProfileName)
@ -140,7 +138,7 @@ class SAT(service.Service):
def _postMemoryInit(self, ignore):
"""Method called after memory initialization is done"""
info(_("Memory initialised"))
log.info(_("Memory initialised"))
self._import_plugins()
ui_contact_list.ContactList(self)
@ -169,25 +167,25 @@ class SAT(service.Service):
"""
if import_name in self.plugins:
debug('Plugin [%s] already imported, passing' % import_name)
log.debug('Plugin [%s] already imported, passing' % import_name)
return
if not import_name:
import_name, (plugin_path, mod, plugin_info) = plugins_to_import.popitem()
else:
if not import_name in plugins_to_import:
if optional:
warning(_("Recommended plugin not found: %s") % import_name)
log.warning(_("Recommended plugin not found: %s") % import_name)
return
error(_("Dependency not found: %s") % import_name)
log.error(_("Dependency not found: %s") % import_name)
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", [])
recommendations = plugin_info.setdefault("recommendations", [])
for to_import in dependencies + recommendations:
if to_import not in self.plugins:
debug('Recursively import dependency of [%s]: [%s]' % (import_name, to_import))
log.debug('Recursively import dependency of [%s]: [%s]' % (import_name, to_import))
self._import_plugins_from_dict(plugins_to_import, to_import, to_import not in dependencies)
info(_("importing plugin: %s"), plugin_info['name'])
log.info(_("importing plugin: %s") % plugin_info['name'])
self.plugins[import_name] = getattr(mod, plugin_info['main'])(self)
if 'handler' in plugin_info and plugin_info['handler'] == 'yes':
self.plugins[import_name].is_handler = True
@ -205,11 +203,11 @@ class SAT(service.Service):
"""
profile = self.memory.getProfileName(profile_key)
if not profile:
error(_('Trying to connect a non-exsitant profile'))
log.error(_('Trying to connect a non-exsitant profile'))
raise exceptions.ProfileUnknownError(profile_key)
if self.isConnected(profile):
info(_("already connected !"))
log.info(_("already connected !"))
return defer.succeed("None")
def afterMemoryInit(ignore):
@ -217,7 +215,7 @@ class SAT(service.Service):
try:
port = int(self.memory.getParamA("Port", "Connection", profile_key=profile))
except ValueError:
error(_("Can't parse port value, using default value"))
log.error(_("Can't parse port value, using default value"))
port = 5222
current = self.profiles[profile] = xmpp.SatXMPPClient(
self, profile,
@ -245,7 +243,7 @@ class SAT(service.Service):
current.identityHandler = xmpp.SatIdentityHandler()
current.identityHandler.setHandlerParent(current)
debug(_("setting plugins parents"))
log.debug(_("setting plugins parents"))
plugin_conn_cb = []
for plugin in self.plugins.iteritems():
@ -270,10 +268,10 @@ class SAT(service.Service):
def logPluginResults(results):
all_succeed = all([success for success, result in results])
if not all_succeed:
error(_("Plugins initialisation error"))
log.error(_("Plugins initialisation error"))
for idx, (success, result) in enumerate(results):
if not success:
error("Error (plugin %(name)s): %(failure)s" % {'name': plugin_conn_cb[idx][0],
log.error("error (plugin %(name)s): %(failure)s" % {'name': plugin_conn_cb[idx][0],
'failure': result})
list_d.addCallback(logPluginResults)
@ -289,10 +287,10 @@ class SAT(service.Service):
def disconnect(self, profile_key):
"""disconnect from jabber server"""
if not self.isConnected(profile_key):
info(_("not connected !"))
log.info(_("not connected !"))
return
profile = self.memory.getProfileName(profile_key)
info(_("Disconnecting..."))
log.info(_("Disconnecting..."))
self.profiles[profile].stopService()
for plugin in self.plugins.iteritems():
disconnected_cb = getattr(plugin[1], "profileDisconnected", None)
@ -318,23 +316,23 @@ class SAT(service.Service):
try:
del self.profiles[profile]
except KeyError:
error(_("Trying to remove reference to a client not referenced"))
log.error(_("Trying to remove reference to a client not referenced"))
self.memory.purgeProfileSession(profile)
def startService(self):
info("Salut à toi ô mon frère !")
log.info(u"Salut à toi ô mon frère !")
#TODO: manage autoconnect
#self.connect()
def stopService(self):
info("Salut aussi à Rantanplan")
log.info("Salut aussi à Rantanplan")
def run(self):
debug(_("running app"))
log.debug(_("running app"))
reactor.run()
def stop(self):
debug(_("stopping app"))
log.debug(_("stopping app"))
reactor.stop()
## Misc methods ##
@ -415,7 +413,7 @@ class SAT(service.Service):
def setParam(self, name, value, category, security_limit, 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})
log.info(_("setting param: %(name)s=%(value)s in category %(category)s") % {'name': name, 'value': value, 'category': category})
self.memory.setParam(name, value, category, security_limit, profile_key)
def isConnected(self, profile_key):
@ -425,7 +423,7 @@ class SAT(service.Service):
"""
profile = self.memory.getProfileName(profile_key)
if not profile:
error(_('asking connection status for a non-existant profile'))
log.error(_('asking connection status for a non-existant profile'))
return
if profile not in self.profiles:
return False
@ -490,7 +488,7 @@ class SAT(service.Service):
if not self.trigger.point("sendMessage", mess_data, pre_xml_treatments, post_xml_treatments, profile):
return defer.succeed(None)
debug(_("Sending jabber message of type [%(type)s] to %(to)s...") % {"type": mess_data["type"], "to": to_jid.full()})
log.debug(_("Sending jabber message of type [%(type)s] to %(to)s...") % {"type": mess_data["type"], "to": to_jid.full()})
def generateXML(mess_data):
mess_data['xml'] = domish.Element((None, 'message'))
@ -507,12 +505,12 @@ class SAT(service.Service):
def sendErrback(e):
text = '%s: %s' % (e.value.__class__.__name__, e.getErrorMessage())
if e.check(MessageSentAndStored):
debug(text)
log.debug(text)
elif e.check(AbortSendMessage):
warning(text)
log.warning(text)
return e
else:
error("Unmanaged exception: %s" % text)
log.error("Unmanaged exception: %s" % text)
return e
pre_xml_treatments.addCallback(generateXML)
pre_xml_treatments.chainDeferred(post_xml_treatments)
@ -532,7 +530,7 @@ class SAT(service.Service):
try:
client = self.profiles[profile]
except KeyError:
error(_("Trying to send a message with no profile"))
log.error(_("Trying to send a message with no profile"))
return
current_jid = client.jid
if not skip_send:
@ -580,7 +578,7 @@ 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()})
log.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":
@ -664,7 +662,7 @@ class SAT(service.Service):
@param data: dictionary of dictionaries
"""
if action_type != "DICT_DICT":
error(_("action_type for actionResultExt must be DICT_DICT, fixing it"))
log.error(_("action_type for actionResultExt must be DICT_DICT, fixing it"))
action_type = "DICT_DICT"
self.bridge.actionResultExt(action_type, action_id, data, profile)
@ -678,7 +676,7 @@ class SAT(service.Service):
# FIXME: use XMLUI and *callback methods for dialog
client = self.getClient(profile)
if conf_id in client._waiting_conf:
error(_("Attempt to register two callbacks for the same confirmation"))
log.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)
@ -686,9 +684,9 @@ class SAT(service.Service):
def confirmationAnswer(self, conf_id, accepted, data, profile):
"""Called by frontends to answer confirmation requests"""
client = self.getClient(profile)
debug(_("Received confirmation answer for conf_id [%(conf_id)s]: %(success)s") % {'conf_id': conf_id, 'success': _("accepted") if accepted else _("refused")})
log.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})
log.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]
@ -703,7 +701,7 @@ class SAT(service.Service):
"""Remove a progress callback"""
client = self.getClient(profile)
if progress_id not in client._progress_cb_map:
error(_("Trying to remove an unknow progress callback"))
log.error(_("Trying to remove an unknow progress callback"))
else:
del client._progress_cb_map[progress_id]
@ -718,7 +716,7 @@ class SAT(service.Service):
client._progress_cb_map[progress_id](progress_id, data, profile)
except KeyError:
pass
#debug("Requested progress for unknown progress_id")
#log.debug("Requested progress for unknown progress_id")
return data
def registerCallback(self, callback, *args, **kwargs):
@ -750,7 +748,7 @@ class SAT(service.Service):
def removeCallback(self, callback_id):
""" Remove a previously registered callback
@param callback_id: id returned by [registerCallback] """
debug("Removing callback [%s]" % callback_id)
log.debug("Removing callback [%s]" % callback_id)
del self._cb_map[callback_id]
def launchCallback(self, callback_id, data=None, profile_key=C.PROF_KEY_NONE):

View file

@ -22,7 +22,8 @@ from sat.core.constants import Const as C
from twisted.internet import task, defer
from twisted.words.protocols.jabber import jid, xmlstream
from wokkel import client, disco, xmppim, generic, compat, delay, iwokkel
from logging import debug, info, warning, error
from sat.core.log import getLogger
log = getLogger(__name__)
from sat.core import exceptions
from calendar import timegm
from zope.interface import implements
@ -54,13 +55,13 @@ class SatXMPPClient(client.XMPPClient):
return
client.XMPPClient._authd(self, xmlstream)
self.__connected = True
info(_("********** [%s] CONNECTED **********") % self.profile)
log.info(_("********** [%s] CONNECTED **********") % self.profile)
self.streamInitialized()
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"))
log.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)
@ -81,7 +82,7 @@ class SatXMPPClient(client.XMPPClient):
disco_d.addCallback(finish_connection)
def initializationFailed(self, reason):
error(_("ERROR: XMPP connection failed for profile '%(profile)s': %(reason)s" % {'profile': self.profile, 'reason': reason}))
log.error(_("ERROR: XMPP connection failed for profile '%(profile)s': %(reason)s" % {'profile': self.profile, 'reason': reason}))
self.host_app.bridge.connectionError("AUTH_ERROR", self.profile)
try:
client.XMPPClient.initializationFailed(self, reason)
@ -95,11 +96,11 @@ class SatXMPPClient(client.XMPPClient):
def connectionLost(self, connector, unused_reason):
self.__connected = False
info(_("********** [%s] DISCONNECTED **********") % self.profile)
log.info(_("********** [%s] DISCONNECTED **********") % self.profile)
try:
self.keep_alife.stop()
except AttributeError:
debug(_("No keep_alife"))
log.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
@ -111,7 +112,7 @@ class SatMessageProtocol(xmppim.MessageProtocol):
self.host = host
def onMessage(self, message):
debug(_(u"got message from: %s"), message["from"])
log.debug(_(u"got message from: %s") % message["from"])
post_treat = defer.Deferred() # XXX: plugin can add their treatments to this deferred
if not self.host.trigger.point("MessageReceived", message, post_treat, profile=self.parent.profile):
@ -163,7 +164,7 @@ class SatRosterProtocol(xmppim.RosterClientProtocol):
def requestRoster(self):
""" ask the server for Roster list """
debug("requestRoster")
log.debug("requestRoster")
d = self.getRoster().addCallback(self.rosterCb)
d.chainDeferred(self.got_roster)
@ -217,11 +218,11 @@ class SatRosterProtocol(xmppim.RosterClientProtocol):
# may change in the future
self.removeItem(item.jid)
return
info(_("new contact in roster list: %s"), item.jid.full())
log.info(_("new contact in roster list: %s") % item.jid.full())
if not item.subscriptionTo:
warning(_("You are not subscribed to this contact !"))
log.warning(_("You are not subscribed to this contact !"))
if not item.subscriptionFrom:
warning(_("This contact is not subscribed to you !"))
log.warning(_("This contact is not subscribed to you !"))
#self.host.memory.addContact(item.jid, item_attr, item.groups, self.parent.profile)
bare_jid = item.jid.userhostJID()
@ -239,7 +240,7 @@ class SatRosterProtocol(xmppim.RosterClientProtocol):
try:
item = self._jids.pop(bare_jid)
except KeyError:
warning("Received a roster remove event for an item not in cache")
log.warning("Received a roster remove event for an item not in cache")
return
for group in item.groups:
try:
@ -248,7 +249,7 @@ class SatRosterProtocol(xmppim.RosterClientProtocol):
if not jids_set:
del self._groups[group]
except KeyError:
warning("there is not cache for the group [%(groups)s] of the removed roster item [%(jid)s]" %
log.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
@ -295,7 +296,7 @@ class SatPresenceProtocol(xmppim.PresenceClientProtocol):
super(SatPresenceProtocol, self).send(obj)
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})
log.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 = {}
@ -314,7 +315,7 @@ class SatPresenceProtocol(xmppim.PresenceClientProtocol):
self.parent.profile)
def unavailableReceived(self, entity, statuses=None):
debug(_("presence update for [%(entity)s] (unavailable, statuses=%(statuses)s)") % {'entity': entity, 'statuses': statuses})
log.debug(_("presence update for [%(entity)s] (unavailable, statuses=%(statuses)s)") % {'entity': entity, 'statuses': statuses})
if not statuses:
statuses = {}
@ -358,7 +359,7 @@ class SatPresenceProtocol(xmppim.PresenceClientProtocol):
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
debug(_('sending automatic "from" subscription request'))
log.debug(_('sending automatic "from" subscription request'))
self.subscribe(entity)
def unsubscribed(self, entity):
@ -366,29 +367,29 @@ class SatPresenceProtocol(xmppim.PresenceClientProtocol):
self.host.memory.delWaitingSub(entity.userhost(), self.parent.profile)
def subscribedReceived(self, entity):
debug(_("subscription approved for [%s]") % entity.userhost())
log.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())
log.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())
log.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
debug(_('sending automatic subscription acceptance'))
log.debug(_('sending automatic subscription acceptance'))
self.subscribed(entity)
else:
self.host.memory.addWaitingSub('subscribe', entity.userhost(), self.parent.profile)
self.host.bridge.subscribe('subscribe', entity.userhost(), self.parent.profile)
def unsubscribeReceived(self, entity):
debug(_("unsubscription asked for [%s]") % entity.userhost())
log.debug(_("unsubscription asked for [%s]") % entity.userhost())
item = self.parent.roster.getItem(entity)
if item and item.subscriptionFrom: # we automatically remove contact
debug(_('automatic contact deletion'))
log.debug(_('automatic contact deletion'))
self.host.delContact(entity, self.parent.profile)
self.host.bridge.subscribe('unsubscribe', entity.userhost(), self.parent.profile)
@ -405,7 +406,7 @@ class SatFallbackHandler(generic.FallbackHandler):
def iqFallback(self, iq):
if iq.handled is True:
return
debug(u"iqFallback: xml = [%s]" % (iq.toXml()))
log.debug(u"iqFallback: xml = [%s]" % (iq.toXml()))
generic.FallbackHandler.iqFallback(self, iq)
@ -441,14 +442,14 @@ class RegisteringAuthenticator(xmlstream.ConnectAuthenticator):
iq.send(self.jabber_host).addCallbacks(self.registrationAnswer, self.registrationFailure)
def registrationAnswer(self, answer):
debug(_("registration answer: %s") % answer.toXml())
log.debug(_("registration answer: %s") % answer.toXml())
answer_type = "SUCCESS"
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))
log.info(_("Registration failure: %s") % str(failure.value))
answer_type = "ERROR"
answer_data = {}
if failure.value.condition == 'conflict':

View file

@ -19,7 +19,8 @@
from sat.core.i18n import _
from sat.core import exceptions
from logging import debug, info, warning, error
from sat.core.log import getLogger
log = getLogger(__name__)
from twisted.words.protocols.jabber import jid
from twisted.words.protocols.jabber.error import StanzaError
from twisted.internet import defer
@ -126,9 +127,9 @@ class Discovery(object):
# we cache items only for our own server
try:
items = self.host.memory.getEntityData(jid_, ["DISCO_ITEMS"], client.profile)["DISCO_ITEMS"]
debug("[%s] disco items are in cache" % jid_.full())
log.debug("[%s] disco items are in cache" % jid_.full())
except KeyError:
debug("Caching [%s] disco items" % jid_.full())
log.debug("Caching [%s] disco items" % jid_.full())
items = yield client.disco.requestItems(jid_)
self.host.memory.updateEntityData(jid_, "DISCO_ITEMS", items, client.profile)
else:
@ -139,7 +140,7 @@ class Discovery(object):
def _infosEb(self, failure, entity_jid):
failure.trap(StanzaError)
warning(_("Error while requesting [%(jid)s]: %(error)s") % {'jid': entity_jid.full(),
log.warning(_("Error while requesting [%(jid)s]: %(error)s") % {'jid': entity_jid.full(),
'error': failure.getErrorMessage()})
def findServiceEntities(self, category, type_, jid_=None, profile_key=C.PROF_KEY_NONE):
@ -236,7 +237,7 @@ class Discovery(object):
s.append('<')
#TODO: manage XEP-0128 data form here
cap_hash = b64encode(sha1(''.join(s)).digest())
debug(_('Capability hash generated: [%s]') % cap_hash)
log.debug(_('Capability hash generated: [%s]') % cap_hash)
return cap_hash
@defer.inlineCallbacks

View file

@ -24,7 +24,8 @@ import csv
from xdg import BaseDirectory
from ConfigParser import SafeConfigParser, NoOptionError, NoSectionError
from uuid import uuid4
from logging import debug, info, warning, error
from sat.core.log import getLogger
log = getLogger(__name__)
from twisted.internet import defer, reactor
from twisted.words.protocols.jabber import jid
from sat.core import exceptions
@ -61,7 +62,7 @@ class Sessions(object):
def _purgeSession(self, session_id):
del self._sessions[session_id]
debug("Session [%s] purged" % session_id)
log.debug("Session [%s] purged" % session_id)
def __len__(self):
return len(self._sessions)
@ -97,7 +98,7 @@ class Sessions(object):
timer.cancel()
self._purgeSession(session_id)
except KeyError:
debug ("Session [%s] doesn't exists, timeout expired ?" % session_id)
log.debug ("Session [%s] doesn't exists, timeout expired ?" % session_id)
def keys(self):
return self._sessions.keys()
@ -110,7 +111,7 @@ class Memory(object):
"""This class manage all persistent informations"""
def __init__(self, host):
info(_("Memory manager init"))
log.info(_("Memory manager init"))
self.initialized = defer.Deferred()
self.host = host
self._entities_cache = {} # XXX: keep presence/last resource/other data in cache
@ -123,7 +124,7 @@ class Memory(object):
self.storage = SqliteStorage(database_file, host.__version__)
PersistentDict.storage = self.storage
self.params = Params(host, self.storage)
info(_("Loading default params template"))
log.info(_("Loading default params template"))
self.params.load_default_params()
d = self.storage.initialized.addCallback(lambda ignore: self.load())
self.memory_data = PersistentDict("memory")
@ -136,7 +137,7 @@ class Memory(object):
try:
config.read(C.CONFIG_FILES)
except:
error(_("Can't read main config !"))
log.error(_("Can't read main config !"))
return config
# XXX: tmp update code, will be removed in the future
@ -148,7 +149,7 @@ class Memory(object):
return # nothing to do
old_default = '~/.sat'
if os.path.isfile(os.path.expanduser(old_default) + '/' + C.SAVEFILE_DATABASE):
warning(_("A database has been found in the default local_dir for previous versions (< 0.5)"))
log.warning(_("A database has been found in the default local_dir for previous versions (< 0.5)"))
config = SafeConfigParser()
target_file = None
for file_ in C.CONFIG_FILES[::-1]:
@ -164,7 +165,7 @@ class Memory(object):
config.set('', 'local_dir', old_default)
with open(target_file, 'wb') as configfile:
config.write(configfile) # for the next time that user launches sat
warning(_("Auto-update: local_dir set to %(path)s in the file %(config_file)s") % {'path': old_default, 'config_file': file_})
log.warning(_("Auto-update: local_dir set to %(path)s in the file %(config_file)s") % {'path': old_default, 'config_file': file_})
default = old_default
else: # use the new default local_dir
default = C.DEFAULT_LOCAL_DIR
@ -200,10 +201,10 @@ class Memory(object):
if os.path.exists(filename):
try:
self.params.load_xml(filename)
debug(_("Parameters loaded from file: %s") % filename)
log.debug(_("Parameters loaded from file: %s") % filename)
return True
except Exception as e:
error(_("Can't load parameters from file: %s") % e)
log.error(_("Can't load parameters from file: %s") % e)
return False
def load(self):
@ -219,18 +220,18 @@ class Memory(object):
def startProfileSession(self, profile):
""""Iniatialise session for a profile
@param profile: %(doc_profile)s"""
info(_("[%s] Profile session started" % profile))
log.info(_("[%s] Profile session started" % profile))
self._entities_cache[profile] = {}
def purgeProfileSession(self, profile):
"""Delete cache of data of profile
@param profile: %(doc_profile)s"""
info(_("[%s] Profile session purge" % profile))
log.info(_("[%s] Profile session purge" % profile))
self.params.purgeProfile(profile)
try:
del self._entities_cache[profile]
except KeyError:
error(_("Trying to purge roster status cache for a profile not in memory: [%s]") % profile)
log.error(_("Trying to purge roster status cache for a profile not in memory: [%s]") % profile)
def save_xml(self, filename=None):
"""Save parameters template to xml file"""
@ -240,10 +241,10 @@ class Memory(object):
filename = os.path.expanduser(filename)
try:
self.params.save_xml(filename)
debug(_("Parameters saved to file: %s") % filename)
log.debug(_("Parameters saved to file: %s") % filename)
return True
except Exception as e:
error(_("Can't save parameters to file: %s") % e)
log.error(_("Can't save parameters to file: %s") % e)
return False
def getProfilesList(self):
@ -312,7 +313,7 @@ class Memory(object):
if "presence" in self._entities_cache[profile][entity]:
entities_presence[entity] = self._entities_cache[profile][entity]["presence"]
debug("Memory getPresenceStatus (%s)", entities_presence)
log.debug("Memory getPresenceStatus (%s)", entities_presence)
return entities_presence
def setPresenceStatus(self, entity_jid, show, priority, statuses, profile_key):
@ -393,7 +394,7 @@ class Memory(object):
try:
del entity_data[key]
except KeyError:
debug("Key [%s] doesn't exist for [%s] in entities_cache" % (key, entity_jid.full()))
log.debug("Key [%s] doesn't exist for [%s] in entities_cache" % (key, entity_jid.full()))
def getEntityData(self, entity_jid, keys_list, profile_key):
"""Get a list of cached values for entity
@ -454,7 +455,7 @@ class Memory(object):
try:
del self._entities_cache[profile][entity]
except KeyError:
debug("Can't delete entity [%s]: not in cache" % entity.full())
log.debug("Can't delete entity [%s]: not in cache" % entity.full())
def addWaitingSub(self, type_, entity_jid, profile_key):
"""Called when a subcription request is received"""
@ -475,7 +476,7 @@ class Memory(object):
"""Called to get a list of currently waiting subscription requests"""
profile = self.getProfileName(profile_key)
if not profile:
error(_('Asking waiting subscriptions for a non-existant profile'))
log.error(_('Asking waiting subscriptions for a non-existant profile'))
return {}
if profile not in self.subscriptions:
return {}

View file

@ -22,7 +22,8 @@ from sat.core.i18n import _
from sat.core import exceptions
from sat.core.constants import Const as C
from xml.dom import minidom, NotFoundErr
from logging import debug, info, warning, error
from sat.core.log import getLogger
log = getLogger(__name__)
from twisted.internet import defer
from twisted.python.failure import Failure
from sat.tools.xml_tools import paramsXML2XMLUI
@ -115,7 +116,7 @@ class Params(object):
try:
del self.params[profile]
except KeyError:
error(_("Trying to purge cache of a profile not in memory: [%s]") % profile)
log.error(_("Trying to purge cache of a profile not in memory: [%s]") % profile)
def save_xml(self, filename):
"""Save parameters template to xml file"""
@ -123,7 +124,7 @@ class Params(object):
xml_file.write(self.dom.toxml('utf-8'))
def __init__(self, host, storage):
debug("Parameters init")
log.debug("Parameters init")
self.host = host
self.storage = storage
self.default_profile = None
@ -138,7 +139,7 @@ class Params(object):
@return: a Deferred instance
"""
if self.storage.hasProfile(profile):
info(_('The profile name already exists'))
log.info(_('The profile name already exists'))
return defer.fail(Failure(exceptions.ConflictError))
if not self.host.trigger.point("ProfileCreation", profile):
return defer.fail(Failure(exceptions.CancelError))
@ -153,13 +154,13 @@ class Params(object):
@return: a Deferred instance
"""
if not self.storage.hasProfile(profile):
info(_('Trying to delete an unknown profile'))
log.info(_('Trying to delete an unknown profile'))
return defer.fail(Failure(exceptions.ProfileUnknownError))
if self.host.isConnected(profile):
if force:
self.host.disconnect(profile)
else:
info(_("Trying to delete a connected profile"))
log.info(_("Trying to delete a connected profile"))
return defer.fail(Failure(exceptions.ConnectedProfileError))
return self.storage.deleteProfile(profile)
@ -174,11 +175,11 @@ class Params(object):
if profile_key == '@DEFAULT@':
default = self.host.memory.memory_data.get('Profile_default')
if not default:
info(_('No default profile, returning first one')) # TODO: manage real default profile
log.info(_('No default profile, returning first one')) # TODO: manage real default profile
try:
default = self.host.memory.memory_data['Profile_default'] = self.storage.getProfilesList()[0]
except IndexError:
info(_('No profile exist yet'))
log.info(_('No profile exist yet'))
return ""
return default # FIXME: temporary, must use real default value, and fallback to first one if it doesn't exists
elif profile_key == C.PROF_KEY_NONE:
@ -186,7 +187,7 @@ class Params(object):
elif return_profile_keys and profile_key in ["@ALL@"]:
return profile_key # this value must be managed by the caller
if not self.storage.hasProfile(profile_key):
info(_('Trying to access an unknown profile'))
log.info(_('Trying to access an unknown profile'))
return "" # FIXME: raise exceptions.ProfileUnknownError here (must be well checked, this method is used in lot of places)
return profile_key
@ -267,23 +268,23 @@ class Params(object):
@param app: name of the frontend registering the parameters
"""
if not app:
warning(_("Trying to register frontends parameters with no specified app: aborted"))
log.warning(_("Trying to register frontends parameters with no specified app: aborted"))
return
if not hasattr(self, "frontends_cache"):
self.frontends_cache = []
if app in self.frontends_cache:
debug(_("Trying to register twice frontends parameters for %(app)s: aborted" % {"app": app}))
log.debug(_("Trying to register twice frontends parameters for %(app)s: aborted" % {"app": app}))
return
self.frontends_cache.append(app)
self.updateParams(xml, security_limit, app)
debug("Frontends parameters registered for %(app)s" % {'app': app})
log.debug("Frontends parameters registered for %(app)s" % {'app': app})
def __default_ok(self, value, name, category):
#FIXME: will not work with individual parameters
self.setParam(name, value, category)
def __default_ko(self, failure, name, category):
error(_("Can't determine default value for [%(category)s/%(name)s]: %(reason)s") % {'category': category, 'name': name, 'reason': str(failure.value)})
log.error(_("Can't determine default value for [%(category)s/%(name)s]: %(reason)s") % {'category': category, 'name': name, 'reason': str(failure.value)})
def setDefault(self, name, category, callback, errback=None):
"""Set default value of parameter
@ -295,17 +296,17 @@ class Params(object):
"""
#TODO: send signal param update if value changed
#TODO: manage individual paramaters
debug ("setDefault called for %(category)s/%(name)s" % {"category": category, "name": name})
log.debug ("setDefault called for %(category)s/%(name)s" % {"category": category, "name": name})
node = self._getParamNode(name, category, '@ALL@')
if not node:
error(_("Requested param [%(name)s] in category [%(category)s] doesn't exist !") % {'name': name, 'category': category})
log.error(_("Requested param [%(name)s] in category [%(category)s] doesn't exist !") % {'name': name, 'category': category})
return
if node[1].getAttribute('default_cb') == 'yes':
# del node[1].attributes['default_cb'] # default_cb is not used anymore as a flag to know if we have to set the default value,
# and we can still use it later e.g. to call a generic setDefault method
value = self._getParam(category, name, C.GENERAL)
if value is None: # no value set by the user: we have the default value
debug ("Default value to set, using callback")
log.debug ("Default value to set, using callback")
d = defer.maybeDeferred(callback)
d.addCallback(self.__default_ok, name, category)
d.addErrback(errback or self.__default_ko, name, category)
@ -343,7 +344,7 @@ class Params(object):
#FIXME: looks really dirty and buggy, need to be reviewed/refactored
node = self._getParamNode(name, category)
if not node:
error(_("Requested param [%(name)s] in category [%(category)s] doesn't exist !") % {'name': name, 'category': category})
log.error(_("Requested param [%(name)s] in category [%(category)s] doesn't exist !") % {'name': name, 'category': category})
raise exceptions.NotFound
if node[0] == C.GENERAL:
@ -354,11 +355,11 @@ class Params(object):
profile = self.getProfileName(profile_key)
if not profile:
error(_('Requesting a param for an non-existant profile'))
log.error(_('Requesting a param for an non-existant profile'))
raise exceptions.ProfileUnknownError
if profile not in self.params:
error(_('Requesting synchronous param for not connected profile'))
log.error(_('Requesting synchronous param for not connected profile'))
raise exceptions.NotConnectedProfileError(profile)
if attr == "value":
@ -378,11 +379,11 @@ class Params(object):
@param profile: owner of the param (@ALL@ for everyone)"""
node = self._getParamNode(name, category)
if not node:
error(_("Requested param [%(name)s] in category [%(category)s] doesn't exist !") % {'name': name, 'category': category})
log.error(_("Requested param [%(name)s] in category [%(category)s] doesn't exist !") % {'name': name, 'category': category})
return None
if not self.checkSecurityLimit(node[1], security_limit):
warning(_("Trying to get parameter '%(param)s' in category '%(cat)s' without authorization!!!"
log.warning(_("Trying to get parameter '%(param)s' in category '%(cat)s' without authorization!!!"
% {'param': name, 'cat': category}))
return None
@ -394,7 +395,7 @@ class Params(object):
profile = self.getProfileName(profile_key)
if not profile:
error(_('Requesting a param for a non-existant profile'))
log.error(_('Requesting a param for a non-existant profile'))
return defer.fail()
if attr != "value":
@ -538,7 +539,7 @@ class Params(object):
"""
profile = self.getProfileName(profile_key)
if not profile:
error(_("Asking params for inexistant profile"))
log.error(_("Asking params for inexistant profile"))
return ""
d = self.getParams(security_limit, app, profile)
return d.addCallback(lambda param_xml: paramsXML2XMLUI(param_xml))
@ -554,7 +555,7 @@ class Params(object):
"""
profile = self.getProfileName(profile_key)
if not profile:
error(_("Asking params for inexistant profile"))
log.error(_("Asking params for inexistant profile"))
return defer.succeed("")
def returnXML(prof_xml):
@ -577,7 +578,7 @@ class Params(object):
#TODO: manage category of general type (without existant profile)
profile = self.getProfileName(profile_key)
if not profile:
error(_("Asking params for inexistant profile"))
log.error(_("Asking params for inexistant profile"))
return ""
def returnCategoryXml(prof_xml):
@ -629,17 +630,17 @@ class Params(object):
if profile_key != C.PROF_KEY_NONE:
profile = self.getProfileName(profile_key)
if not profile:
error(_('Trying to set parameter for an unknown profile'))
log.error(_('Trying to set parameter for an unknown profile'))
return # TODO: throw an error
node = self._getParamNode(name, category, '@ALL@')
if not node:
error(_('Requesting an unknown parameter (%(category)s/%(name)s)')
log.error(_('Requesting an unknown parameter (%(category)s/%(name)s)')
% {'category': category, 'name': name})
return
if not self.checkSecurityLimit(node[1], security_limit):
warning(_("Trying to set parameter '%(param)s' in category '%(cat)s' without authorization!!!"
log.warning(_("Trying to set parameter '%(param)s' in category '%(cat)s' without authorization!!!"
% {'param': name, 'cat': category}))
return

View file

@ -18,7 +18,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from sat.core.i18n import _
from logging import debug, info, warning, error
from sat.core.log import getLogger
log = getLogger(__name__)
class MemoryNotInitializedError(Exception):
@ -35,7 +36,7 @@ class PersistentDict(object):
"""@param namespace: unique namespace for this dictionary
@param profile: profile which *MUST* exists, or None for general values"""
if not self.storage:
error(_("PersistentDict can't be used before memory initialisation"))
log.error(_("PersistentDict can't be used before memory initialisation"))
raise MemoryNotInitializedError
self._cache = {}
self.namespace = namespace

View file

@ -19,7 +19,8 @@
from sat.core.i18n import _
from sat.core import exceptions
from logging import debug, info, warning, error
from sat.core.log import getLogger
log = getLogger(__name__)
from twisted.enterprise import adbapi
from twisted.internet import defer
from collections import OrderedDict
@ -80,7 +81,7 @@ class SqliteStorage(object):
self.initialized = defer.Deferred() # triggered when memory is fully initialised and ready
self.profiles = {} # we keep cache for the profiles (key: profile name, value: profile id)
info(_("Connecting database"))
log.info(_("Connecting database"))
new_base = not os.path.exists(db_filename) # do we have to create the database ?
if new_base: # the dir may not exist if it's not the XDG recommended one
dir_ = os.path.dirname(db_filename)
@ -92,10 +93,10 @@ class SqliteStorage(object):
# XXX: foreign_keys activation doesn't seem to work, probably because of the multi-threading
# All the requests that need to use this feature should be run with runInteraction instead,
# so you can set the PRAGMA as it is done in self.deleteProfile
init_defer = self.dbpool.runOperation("PRAGMA foreign_keys = ON").addErrback(lambda x: error(_("Can't activate foreign keys")))
init_defer = self.dbpool.runOperation("PRAGMA foreign_keys = ON").addErrback(lambda x: log.error(_("Can't activate foreign keys")))
def getNewBaseSql():
info(_("The database is new, creating the tables"))
log.info(_("The database is new, creating the tables"))
database_creation = ["PRAGMA user_version=%d" % CURRENT_DB_VERSION]
database_creation.extend(Updater.createData2Raw(DATABASE_SCHEMAS['current']['CREATE']))
database_creation.extend(Updater.insertData2Raw(DATABASE_SCHEMAS['current']['INSERT']))
@ -109,7 +110,7 @@ class SqliteStorage(object):
if statements is None:
return defer.succeed(None)
debug("===== COMMITING STATEMENTS =====\n%s\n============\n\n" % '\n'.join(statements))
log.debug("===== COMMITING STATEMENTS =====\n%s\n============\n\n" % '\n'.join(statements))
d = self.dbpool.runInteraction(self._updateDb, tuple(statements))
return d
@ -166,7 +167,7 @@ class SqliteStorage(object):
@param name: name of the profile
@return: deferred triggered once profile is actually deleted"""
def deletionError(failure):
error(_("Can't delete profile [%s]") % name)
log.error(_("Can't delete profile [%s]") % name)
return failure
def delete(txn):
@ -176,7 +177,7 @@ class SqliteStorage(object):
return None
d = self.dbpool.runInteraction(delete)
d.addCallback(lambda ignore: info(_("Profile [%s] deleted") % name))
d.addCallback(lambda ignore: log.info(_("Profile [%s] deleted") % name))
d.addErrback(deletionError)
return d
@ -190,7 +191,7 @@ class SqliteStorage(object):
for param in result:
category, name, value = param
params_gen[(category, name)] = value
debug(_("loading general parameters from database"))
log.debug(_("loading general parameters from database"))
return self.dbpool.runQuery("SELECT category,name,value FROM param_gen").addCallback(fillParams)
def loadIndParams(self, params_ind, profile):
@ -203,7 +204,7 @@ class SqliteStorage(object):
for param in result:
category, name, value = param
params_ind[(category, name)] = value
debug(_("loading individual parameters from database"))
log.debug(_("loading individual parameters from database"))
d = self.dbpool.runQuery("SELECT category,name,value FROM param_ind WHERE profile_id=?", (self.profiles[profile], ))
d.addCallback(fillParams)
return d
@ -225,7 +226,7 @@ class SqliteStorage(object):
@param value: value to set
@return: deferred"""
d = self.dbpool.runQuery("REPLACE INTO param_gen(category,name,value) VALUES (?,?,?)", (category, name, value))
d.addErrback(lambda ignore: error(_("Can't set general parameter (%(category)s/%(name)s) in database" % {"category": category, "name": name})))
d.addErrback(lambda ignore: log.error(_("Can't set general parameter (%(category)s/%(name)s) in database" % {"category": category, "name": name})))
return d
def setIndParam(self, category, name, value, profile):
@ -236,7 +237,7 @@ class SqliteStorage(object):
@param profile: a profile which *must* exist
@return: deferred"""
d = self.dbpool.runQuery("REPLACE INTO param_ind(category,name,profile_id,value) VALUES (?,?,?,?)", (category, name, self.profiles[profile], value))
d.addErrback(lambda ignore: error(_("Can't set individual parameter (%(category)s/%(name)s) for [%(profile)s] in database" % {"category": category, "name": name, "profile": profile})))
d.addErrback(lambda ignore: log.error(_("Can't set individual parameter (%(category)s/%(name)s) for [%(profile)s] in database" % {"category": category, "name": name, "profile": profile})))
return d
#History
@ -256,7 +257,7 @@ class SqliteStorage(object):
d = self.dbpool.runQuery("INSERT INTO history(source, source_res, dest, dest_res, timestamp, message, type, extra, profile_id) VALUES (?,?,?,?,?,?,?,?,?)",
(from_jid.userhost(), from_jid.resource, to_jid.userhost(), to_jid.resource, timestamp or time(),
message, _type, extra_, self.profiles[profile]))
d.addErrback(lambda ignore: error(_("Can't save following message in history: from [%(from_jid)s] to [%(to_jid)s] ==> [%(message)s]" %
d.addErrback(lambda ignore: log.error(_("Can't save following message in history: from [%(from_jid)s] to [%(to_jid)s] ==> [%(message)s]" %
{"from_jid": from_jid.full(), "to_jid": to_jid.full(), "message": message})))
return d
@ -321,9 +322,9 @@ class SqliteStorage(object):
for private in result:
key, value = private
private_gen[key] = value
debug(_("loading general private values [namespace: %s] from database") % (namespace, ))
log.debug(_("loading general private values [namespace: %s] from database") % (namespace, ))
d = self.dbpool.runQuery("SELECT key,value FROM private_gen WHERE namespace=?", (namespace, )).addCallback(fillPrivates)
return d.addErrback(lambda x: debug(_("No data present in database for namespace %s") % namespace))
return d.addErrback(lambda x: log.debug(_("No data present in database for namespace %s") % namespace))
def loadIndPrivates(self, private_ind, namespace, profile):
"""Load individual private values
@ -336,10 +337,10 @@ class SqliteStorage(object):
for private in result:
key, value = private
private_ind[key] = value
debug(_("loading individual private values [namespace: %s] from database") % (namespace, ))
log.debug(_("loading individual private values [namespace: %s] from database") % (namespace, ))
d = self.dbpool.runQuery("SELECT key,value FROM private_ind WHERE namespace=? AND profile_id=?", (namespace, self.profiles[profile]))
d.addCallback(fillPrivates)
return d.addErrback(lambda x: debug(_("No data present in database for namespace %s") % namespace))
return d.addErrback(lambda x: log.debug(_("No data present in database for namespace %s") % namespace))
def setGenPrivate(self, namespace, key, value):
"""Save the general private value in database
@ -348,7 +349,7 @@ class SqliteStorage(object):
@param value: value to set
@return: deferred"""
d = self.dbpool.runQuery("REPLACE INTO private_gen(namespace,key,value) VALUES (?,?,?)", (namespace, key, value))
d.addErrback(lambda ignore: error(_("Can't set general private value (%(key)s) [namespace:%(namespace)s] in database" %
d.addErrback(lambda ignore: log.error(_("Can't set general private value (%(key)s) [namespace:%(namespace)s] in database" %
{"namespace": namespace, "key": key})))
return d
@ -360,7 +361,7 @@ class SqliteStorage(object):
@param profile: a profile which *must* exist
@return: deferred"""
d = self.dbpool.runQuery("REPLACE INTO private_ind(namespace,key,profile_id,value) VALUES (?,?,?,?)", (namespace, key, self.profiles[profile], value))
d.addErrback(lambda ignore: error(_("Can't set individual private value (%(key)s) [namespace: %(namespace)s] for [%(profile)s] in database" %
d.addErrback(lambda ignore: log.error(_("Can't set individual private value (%(key)s) [namespace: %(namespace)s] for [%(profile)s] in database" %
{"namespace": namespace, "key": key, "profile": profile})))
return d
@ -370,7 +371,7 @@ class SqliteStorage(object):
@param key: key of the private value
@return: deferred"""
d = self.dbpool.runQuery("DELETE FROM private_gen WHERE namespace=? AND key=?", (namespace, key))
d.addErrback(lambda ignore: error(_("Can't delete general private value (%(key)s) [namespace:%(namespace)s] in database" %
d.addErrback(lambda ignore: log.error(_("Can't delete general private value (%(key)s) [namespace:%(namespace)s] in database" %
{"namespace": namespace, "key": key})))
return d
@ -381,7 +382,7 @@ class SqliteStorage(object):
@param profile: a profile which *must* exist
@return: deferred"""
d = self.dbpool.runQuery("DELETE FROM private_ind WHERE namespace=? AND key=? AND profile=?)", (namespace, key, self.profiles[profile]))
d.addErrback(lambda ignore: error(_("Can't delete individual private value (%(key)s) [namespace: %(namespace)s] for [%(profile)s] in database" %
d.addErrback(lambda ignore: log.error(_("Can't delete individual private value (%(key)s) [namespace: %(namespace)s] for [%(profile)s] in database" %
{"namespace": namespace, "key": key, "profile": profile})))
return d
@ -395,9 +396,9 @@ class SqliteStorage(object):
for private in result:
key, value = private
private_gen[key] = pickle.loads(str(value))
debug(_("loading general private binary values [namespace: %s] from database") % (namespace, ))
log.debug(_("loading general private binary values [namespace: %s] from database") % (namespace, ))
d = self.dbpool.runQuery("SELECT key,value FROM private_gen_bin WHERE namespace=?", (namespace, )).addCallback(fillPrivates)
return d.addErrback(lambda x: debug(_("No binary data present in database for namespace %s") % namespace))
return d.addErrback(lambda x: log.debug(_("No binary data present in database for namespace %s") % namespace))
def loadIndPrivatesBinary(self, private_ind, namespace, profile):
"""Load individual private binary values
@ -410,10 +411,10 @@ class SqliteStorage(object):
for private in result:
key, value = private
private_ind[key] = pickle.loads(str(value))
debug(_("loading individual private binary values [namespace: %s] from database") % (namespace, ))
log.debug(_("loading individual private binary values [namespace: %s] from database") % (namespace, ))
d = self.dbpool.runQuery("SELECT key,value FROM private_ind_bin WHERE namespace=? AND profile_id=?", (namespace, self.profiles[profile]))
d.addCallback(fillPrivates)
return d.addErrback(lambda x: debug(_("No binary data present in database for namespace %s") % namespace))
return d.addErrback(lambda x: log.debug(_("No binary data present in database for namespace %s") % namespace))
def setGenPrivateBinary(self, namespace, key, value):
"""Save the general private binary value in database
@ -422,7 +423,7 @@ class SqliteStorage(object):
@param value: value to set
@return: deferred"""
d = self.dbpool.runQuery("REPLACE INTO private_gen_bin(namespace,key,value) VALUES (?,?,?)", (namespace, key, pickle.dumps(value, 0)))
d.addErrback(lambda ignore: error(_("Can't set general private binary value (%(key)s) [namespace:%(namespace)s] in database" %
d.addErrback(lambda ignore: log.error(_("Can't set general private binary value (%(key)s) [namespace:%(namespace)s] in database" %
{"namespace": namespace, "key": key})))
return d
@ -434,7 +435,7 @@ class SqliteStorage(object):
@param profile: a profile which *must* exist
@return: deferred"""
d = self.dbpool.runQuery("REPLACE INTO private_ind_bin(namespace,key,profile_id,value) VALUES (?,?,?,?)", (namespace, key, self.profiles[profile], pickle.dumps(value, 0)))
d.addErrback(lambda ignore: error(_("Can't set individual binary private value (%(key)s) [namespace: %(namespace)s] for [%(profile)s] in database" %
d.addErrback(lambda ignore: log.error(_("Can't set individual binary private value (%(key)s) [namespace: %(namespace)s] for [%(profile)s] in database" %
{"namespace": namespace, "key": key, "profile": profile})))
return d
@ -444,7 +445,7 @@ class SqliteStorage(object):
@param key: key of the private value
@return: deferred"""
d = self.dbpool.runQuery("DELETE FROM private_gen_bin WHERE namespace=? AND key=?", (namespace, key))
d.addErrback(lambda ignore: error(_("Can't delete general private binary value (%(key)s) [namespace:%(namespace)s] in database" %
d.addErrback(lambda ignore: log.error(_("Can't delete general private binary value (%(key)s) [namespace:%(namespace)s] in database" %
{"namespace": namespace, "key": key})))
return d
@ -455,7 +456,7 @@ class SqliteStorage(object):
@param profile: a profile which *must* exist
@return: deferred"""
d = self.dbpool.runQuery("DELETE FROM private_ind_bin WHERE namespace=? AND key=? AND profile=?)", (namespace, key, self.profiles[profile]))
d.addErrback(lambda ignore: error(_("Can't delete individual private binary value (%(key)s) [namespace: %(namespace)s] for [%(profile)s] in database" %
d.addErrback(lambda ignore: log.error(_("Can't delete individual private binary value (%(key)s) [namespace: %(namespace)s] for [%(profile)s] in database" %
{"namespace": namespace, "key": key, "profile": profile})))
return d
##Helper methods##
@ -521,7 +522,7 @@ class Updater(object):
if local_hash == current_hash:
if local_version != CURRENT_DB_VERSION:
warning(_("Your local schema is up-to-date, but database versions mismatch, fixing it..."))
log.warning(_("Your local schema is up-to-date, but database versions mismatch, fixing it..."))
yield self._setLocalVersion(CURRENT_DB_VERSION)
else:
# an update is needed
@ -531,17 +532,17 @@ class Updater(object):
if self._sat_version.endswith('D'):
# we are in a development version
update_data = self.generateUpdateData(local_sch, current_sch, False)
warning(_("There is a schema mismatch, but as we are on a dev version, database will be updated"))
log.warning(_("There is a schema mismatch, but as we are on a dev version, database will be updated"))
update_raw = self.update2raw(update_data, True)
defer.returnValue(update_raw)
else:
error(_(u"schema version is up-to-date, but local schema differ from expected current schema"))
log.error(_(u"schema version is up-to-date, but local schema differ from expected current schema"))
update_data = self.generateUpdateData(local_sch, current_sch, True)
warning(_(u"Here are the commands that should fix the situation, use at your own risk (do a backup before modifying database), you can go to SàT's MUC room at sat@chat.jabberfr.org for help\n### SQL###\n%s\n### END SQL ###\n") % u'\n'.join(("%s;" % statement for statement in self.update2raw(update_data))))
log.warning(_(u"Here are the commands that should fix the situation, use at your own risk (do a backup before modifying database), you can go to SàT's MUC room at sat@chat.jabberfr.org for help\n### SQL###\n%s\n### END SQL ###\n") % u'\n'.join(("%s;" % statement for statement in self.update2raw(update_data))))
raise exceptions.DatabaseError("Database mismatch")
else:
# Database is not up-to-date, we'll do the update
info(_("Database schema has changed, local database will be updated"))
log.info(_("Database schema has changed, local database will be updated"))
update_raw = []
for version in xrange(local_version+1, CURRENT_DB_VERSION+1):
try:
@ -612,12 +613,12 @@ class Updater(object):
schema_dict = {}
for create_statement in raw_statements:
if not create_statement.startswith("CREATE TABLE "):
warning("Unexpected statement, ignoring it")
log.warning("Unexpected statement, ignoring it")
continue
_create_statement = create_statement[13:]
table, raw_col_stats = _create_statement.split(' ',1)
if raw_col_stats[0] != '(' or raw_col_stats[-1] != ')':
warning("Unexpected statement structure, ignoring it")
log.warning("Unexpected statement structure, ignoring it")
continue
col_stats = [stmt.strip() for stmt in self.stmnt_regex.findall(raw_col_stats[1:-1])]
col_defs = []
@ -668,7 +669,7 @@ class Updater(object):
new_col_defs, new_constraints = new_data[table]
for obj in old_col_defs, old_constraints, new_col_defs, new_constraints:
if not isinstance(obj, tuple):
raise InternalError("Columns definitions must be tuples")
raise exceptions.InternalError("Columns definitions must be tuples")
defs_create, defs_delete, ignore = getChanges(set(old_col_defs), set(new_col_defs))
constraints_create, constraints_delete, ignore = getChanges(set(old_constraints), set(new_constraints))
created_col_names = set([name.split(' ',1)[0] for name in defs_create])
@ -706,7 +707,7 @@ class Updater(object):
drop.append(self.DROP_SQL % table)
if dev_version:
if drop:
info("Dev version, SQL NOT EXECUTED:\n--\n%s\n--\n" % "\n".join(drop))
log.info("Dev version, SQL NOT EXECUTED:\n--\n%s\n--\n" % "\n".join(drop))
else:
ret.extend(drop)
@ -717,7 +718,7 @@ class Updater(object):
cols_delete = update.get('cols delete', {})
for table in cols_delete:
info("Following columns in table [%s] are not needed anymore, but are kept for dev version: %s" % (table, ", ".join(cols_delete[table])))
log.info("Following columns in table [%s] are not needed anymore, but are kept for dev version: %s" % (table, ", ".join(cols_delete[table])))
cols_modify = update.get('cols modify', {})
for table in cols_modify:

View file

@ -1,271 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# SAT plugin for managing xep-0045
# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org)
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# 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/>.
from sat.core.i18n import _
from logging import debug, info, warning, error
from twisted.words.xish import domish
from twisted.internet import protocol, defer, threads, reactor
from twisted.words.protocols.jabber import client, jid, xmlstream
from twisted.words.protocols.jabber import error as jab_error
from twisted.words.protocols.jabber.xmlstream import IQ
from twisted.web.client import getPage
from sat.memory.persistent import PersistentBinaryDict
import os.path
import pdb
from zope.interface import implements
from wokkel import disco, iwokkel, data_form
from sat.tools.xml_tools import XMLUI
import urllib
import webbrowser
from BeautifulSoup import BeautifulSoup
import re
PLUGIN_INFO = {
"name": "CouchSurfing plugin",
"import_name": "CS",
"type": "Misc",
"protocols": [],
"dependencies": [],
"main": "CS_Plugin",
"handler": "no",
"description": _(u"""This plugin allow to manage your CouchSurfing account throught your SàT frontend""")
}
AGENT = 'Salut à Toi XMPP/CS Plugin'
class CS_Plugin(object):
params = """
<params>
<individual>
<category name="CouchSurfing">
<param name="Login" type="string" />
<param name="Password" type="password" />
</category>
</individual>
</params>
"""
def __init__(self, host):
info(_("Plugin CS initialization"))
self.host = host
#parameters
host.memory.updateParams(CS_Plugin.params)
#menu
host.importMenu(_("Plugin"), "CouchSurfing", self.menuSelected, help_string=_("Launch CoushSurfing management interface"))
self.data = {} # TODO: delete cookies/data after a while
self.host.registerGeneralCB("plugin_CS_sendMessage", self.sendMessage)
self.host.registerGeneralCB("plugin_CS_showUnreadMessages", self.showUnreadMessages)
def profileConnected(self, profile):
self.data[profile] = PersistentBinaryDict("plugin_CS", profile)
def dataLoaded(ignore):
if not self.data[profile]:
self.data[profile] = {'cookies': {}}
self.data[profile].load().addCallback(dataLoaded)
def profileDisconnected(self, profile):
del self.data[profile]
def erroCB(self, e, id):
"""Called when something is going wrong when contacting CS website"""
#pdb.set_trace()
message_data = {"reason": "connection error", "message": _(u"Impossible to contact CS website, please check your login/password, connection or try again later")}
self.host.bridge.actionResult("ERROR", id, message_data)
def menuSelected(self, id, profile):
"""Called when the couchsurfing menu item is selected"""
login = self.host.memory.getParamA("Login", "CouchSurfing", profile_key=profile)
password = self.host.memory.getParamA("Password", "CouchSurfing", profile_key=profile)
if not login or not password:
message_data = {"reason": "uncomplete", "message": _(u"You have to fill your CouchSurfing login & password in parameters before using this interface")}
self.host.bridge.actionResult("ERROR", id, message_data)
return
post_data = urllib.urlencode({'auth_login[un]': login, 'auth_login[pw]': password, 'auth_login[action]': 'Login...'})
self.data[profile]['cookies'] = {}
d = getPage('http://www.couchsurfing.org/login.html', method='POST', postdata=post_data, headers={'Content-Type': 'application/x-www-form-urlencoded'}, agent=AGENT, cookies=self.data[profile]['cookies'])
d.addCallback(self.__connectionCB, id, profile)
d.addErrback(self.erroCB, id)
#self.host.bridge.actionResult("SUPPRESS", id, {})
#pages parsing callbacks
def savePage(self, name, html):
f = open('/tmp/CS_' + name + '.html', 'w')
f.write(html)
f.close()
print "page [%s] sauvee" % name
#pdb.set_trace()
def __connectionCB(self, html, id, profile):
print 'Response received'
#self.savePage('principale',html)
soup = BeautifulSoup(html)
self.data[profile]['user_nick'] = soup.find('a', 'item_link', href='/home.html').contents[0]
self.data[profile]['user_name'] = soup.html.head.title.string.split(' - ')[1]
#unread messages
try:
self.data[profile]['unread_messages'] = int(soup.find(lambda tag: tag.name == 'div' and ('class', 'item_bubble') in tag.attrs and tag.find('a', href="/messages.html?message_status=inbox")).find(text=True))
except:
self.data[profile]['unread_messages'] = 0
#unread couchrequest messages
try:
self.data[profile]['unread_CR_messages'] = int(soup.find(lambda tag: tag.name == 'div' and ('class', 'item_bubble') in tag.attrs and tag.find('a', href="/couchmanager")).find(text=True))
except:
self.data[profile]['unread_CR_messages'] = 0
#if we have already the list of friend, no need to make new requests
if 'friends' not in self.data[profile]:
self.data[profile]['friends'] = {}
d = getPage('http://www.couchsurfing.org/connections.html?type=myfriends&show=10000', agent=AGENT, cookies=self.data[profile]['cookies'])
d.addCallback(self.__friendsPageCB, id=id, profile=profile)
d.addErrback(self.erroCB, id)
else:
self.host.bridge.actionResult("XMLUI", id, {"type": "window", "xml": self.__buildUI(self.data[profile])})
def __buildUI(self, data):
"""Build the XML UI of the plugin
@param data: data store for the profile"""
user_nick = data['user_nick']
user_name = data['user_name']
unread_mess = data['unread_messages']
unread_CR_mess = data['unread_CR_messages']
friends_list = data['friends'].keys()
friends_list.sort()
interface = XMLUI('window', 'tabs', title='CouchSurfing management')
interface.addCategory(_("Messages"), "vertical")
interface.addText(_("G'day %(name)s, you have %(nb_message)i unread message%(plural_mess)s and %(unread_CR_mess)s unread couch request message%(plural_CR)s\nIf you want to send a message, select the recipient(s) in the list below") % {'name': user_name, 'nb_message': unread_mess, 'plural_mess': 's' if unread_mess > 1 else '', 'unread_CR_mess': unread_CR_mess, 'plural_CR': 's' if unread_CR_mess > 1 else ''})
if unread_mess:
interface.addButton('plugin_CS_showUnreadMessages', 'showUnreadMessages', _('Show unread message%(plural)s in external web browser') % {'plural': 's' if unread_mess > 1 else ''})
interface.addList(friends_list, 'friends', None, style=['multi'])
interface.changeLayout('pairs')
interface.addLabel(_("Subject"))
interface.addString('subject')
interface.changeLayout('vertical')
interface.addLabel(_("Message"))
interface.addText("(use %name% for contact name and %firstname% for guessed first name)")
interface.addTextBox('message')
interface.addButton('plugin_CS_sendMessage', 'sendMessage', _('send'), fields_back=['friends', 'subject', 'message'])
#interface.addCategory(_("Events"), "vertical") #TODO: coming soon, hopefuly :)
#interface.addCategory(_("Couch search"), "vertical")
return interface.toXml()
def __meetingPageCB(self, html):
"""Called when the meeting page has been received"""
def __friendsPageCB(self, html, id, profile):
"""Called when the friends list page has been received"""
self.savePage('friends', html)
soup = BeautifulSoup(html.replace('"formtable width="400', '"formtable" width="400"')) # CS html fix #TODO: report the bug to CS dev team
friends = self.data[profile]['friends']
for _tr in soup.findAll('tr', {'class': re.compile("^msgRow*")}): # we parse the row with friends infos
_nobr = _tr.find('nobr') # contain the friend name
friend_name = unicode(_nobr.string)
friend_link = u'http://www.couchsurfing.org' + _nobr.parent['href']
regex_href = re.compile(r'/connections\.html\?id=([^&]+)')
a_tag = _tr.find('a', href=regex_href)
friend_id = regex_href.search(unicode(a_tag)).groups()[0]
debug(_("CS friend found: %(friend_name)s (id: %(friend_id)s, link: %(friend_link)s)") % {'friend_name': friend_name, 'friend_id': friend_id, 'friend_link': friend_link})
friends[friend_name] = {'link': friend_link, 'id': friend_id}
a = soup.find('td', 'barmiddle next').a # is there several pages ?
if a:
#yes, we parse the next page
d = getPage('http://www.couchsurfing.org/' + str(a['href']), agent=AGENT, cookies=self.data[profile]['cookies'])
d.addCallback(self.__friendsPageCB, id=id, profile=profile)
d.addErrback(self.erroCB, id)
else:
#no, we show the result
self.host.bridge.actionResult("XMLUI", id, {"type": "window", "xml": self.__buildUI(self.data[profile])})
def __sendMessage(self, answer, subject, message, data, recipient_list, id, profile):
"""Send actually the message
@param subject: subject of the message
@param message: body of the message
@param data: data of the profile
@param recipient_list: list of friends names, names are removed once message is sent
@param id: id of the action
@param profile: profile who launched the action
"""
if answer:
if not 'Here is a copy of the email that was sent' in answer:
error(_("INTERNAL ERROR: no confirmation of message sent by CS, maybe the site has been modified ?"))
#TODO: throw a warning to the frontend, saying that maybe the message has not been sent and to contact dev of this plugin
#debug(_('HTML answer: %s') % answer)
if recipient_list:
recipient = recipient_list.pop()
try:
friend_id = data['friends'][recipient]['id']
except KeyError:
error('INTERNAL ERROR: unknown friend')
return # send an error to the frontend
mess = message.replace('%name%', recipient).replace('%firstname%', recipient.split(' ')[0])
info(_('Sending message to %s') % recipient)
debug(_("\nsubject: %(subject)s\nmessage: \n---\n%(message)s\n---\n\n") % {'subject': subject, 'message': mess})
post_data = urllib.urlencode({'email[subject]': subject.encode('utf-8'), 'email[body]': mess.encode('utf-8'), 'email[id]': friend_id, 'email[action]': 'Send Message', 'email[replied_id]': '', 'email[couchsurf]': '', 'email[directions_to_add]': ''})
d = getPage("http://www.couchsurfing.org/send_message.html", method='POST', postdata=post_data, headers={'Content-Type': 'application/x-www-form-urlencoded'}, agent=AGENT, cookies=data['cookies'])
d.addCallback(self.__sendMessage, subject, message, data, recipient_list, id, profile)
d.addErrback(self.erroCB, id)
else:
interface = XMLUI('window', title=_('Message sent')) # TODO: create particular actionResult for alerts ?
interface.addText(_('The message has been sent to every recipients'))
self.host.bridge.actionResult("XMLUI", id, {"type": "window", "xml": interface.toXml()})
def sendMessage(self, id, data, profile):
"""Called to send a message to a friend
@param data: dict with the following keys:
friend: name of the recipient
subject: subject of the message
message: body of the message, with the following special keywords:
- %name%: name of the friend
- %firstname%: guessed first name of the friend (currently the first part of the name)
"""
if not data['friends']:
message_data = {"reason": "bad data", "message": _(u"There is not recipient selected for this message !")}
self.host.bridge.actionResult("ERROR", id, message_data)
return
friends = data['friends'].split('\t')
subject = data['subject']
message = data['message']
info(_("sending message to %(friends)s with subject [%(subject)s]" % {'friends': friends, 'subject': subject}))
self.__sendMessage(None, subject, message, self.data[profile], friends, id, profile)
def __showUnreadMessages2(self, html, id, profile):
"""Called when the inbox page has been received"""
#FIXME: that's really too fragile, only works if the unread messages are in the first page, and it would be too resources consuming for the website to DL each time all pages. In addition, the show attribute doesn't work as expected.
soup = BeautifulSoup(html)
for tag in soup.findAll(lambda tag: tag.name == 'strong' and tag.a and tag.a['href'].startswith('messages.html?message_status=inbox')):
link = "http://www.couchsurfing.org/" + str(tag.a['href'])
webbrowser.open_new_tab(link) # TODO: the web browser need to already have CS cookies (i.e. already be opened & logged on CS, or be permanently loggued), a warning to the user should be sent/or a balloon-tip
def showUnreadMessages(self, id, data, profile):
"""Called when user want to see all unread messages in the external browser"""
d = getPage("http://www.couchsurfing.org/messages.html?message_status=inbox&show=10000", agent=AGENT, cookies=self.data[profile]['cookies'])
d.addCallback(self.__showUnreadMessages2, id, profile)
d.addErrback(self.erroCB, id)

View file

@ -19,7 +19,8 @@
from sat.core.i18n import _, D_
from sat.core.constants import Const as C
from logging import debug, info, warning, error
from sat.core.log import getLogger
log = getLogger(__name__)
from twisted.words.protocols.jabber import jid
from twisted.internet import defer, reactor
from wokkel import data_form
@ -53,7 +54,7 @@ PLUGIN_INFO = {
class AdHocDBus(object):
def __init__(self, host):
info(_("plugin Ad-Hoc D-Bus initialization"))
log.info(_("plugin Ad-Hoc D-Bus initialization"))
self.host = host
host.bridge.addMethod("adHocDBusAddAuto", ".plugin", in_sign='sasasasasasass', out_sign='(sa(sss))',
method=self._adHocDBusAddAuto,
@ -97,7 +98,7 @@ class AdHocDBus(object):
@defer.inlineCallbacks
def _introspect(self, methods, bus_name, proxy):
debug("introspecting path [%s]" % proxy.object_path)
log.debug("introspecting path [%s]" % proxy.object_path)
introspect_xml = yield self._DBusIntrospect(proxy)
el = etree.fromstring(introspect_xml)
for node in el.iterchildren('node', 'interface'):
@ -108,13 +109,13 @@ class AdHocDBus(object):
elif node.tag == 'interface':
name = node.get('name')
if any(name.startswith(ignored) for ignored in IGNORED_IFACES_START):
debug('interface [%s] is ignored' % name)
log.debug('interface [%s] is ignored' % name)
continue
debug("introspecting interface [%s]" % name)
log.debug("introspecting interface [%s]" % name)
for method in node.iterchildren('method'):
if self._acceptMethod(method):
method_name = method.get('name')
debug("method accepted: [%s]" % method_name)
log.debug("method accepted: [%s]" % method_name)
methods.add((proxy.object_path, name, method_name))
def _adHocDBusAddAuto(self, prog_name, allowed_jids, allowed_groups, allowed_magics, forbidden_jids, forbidden_groups, flags, profile_key):
@ -125,13 +126,13 @@ class AdHocDBus(object):
bus_names = yield self._DBusListNames()
bus_names = [bus_name for bus_name in bus_names if '.' + prog_name in bus_name]
if not bus_names:
info("Can't find any bus for [%s]" % prog_name)
log.info("Can't find any bus for [%s]" % prog_name)
return
bus_names.sort()
for bus_name in bus_names:
if bus_name.endswith(prog_name):
break
info("bus name found: [%s]" % bus_name)
log.info("bus name found: [%s]" % bus_name)
proxy = self.session_bus.get_object(bus_name, '/', introspect=False)
methods = set()

View file

@ -18,7 +18,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from sat.core.i18n import _
from logging import debug, info, warning, error
from sat.core.log import getLogger
log = getLogger(__name__)
from twisted.words.protocols.jabber import jid
from twisted.internet import reactor, protocol
@ -47,13 +48,13 @@ class ExportCommandProtocol(protocol.ProcessProtocol):
def _clean(self, data):
if not data:
error ("data should not be empty !")
log.error ("data should not be empty !")
return u""
decoded = data.decode('utf-8', 'ignore')[:-1 if data[-1] == '\n' else None]
return clean_ustr(decoded)
def connectionMade(self):
info("connectionMade :)")
log.info("connectionMade :)")
def outReceived(self, data):
self.parent.host.sendMessage(self.target, self._clean(data), no_trigger=True, profile_key=self.profile)
@ -62,7 +63,7 @@ class ExportCommandProtocol(protocol.ProcessProtocol):
self.parent.host.sendMessage(self.target, self._clean(data), no_trigger=True, profile_key=self.profile)
def processEnded(self, reason):
info (u"process finished: %d" % (reason.value.exitCode,))
log.info (u"process finished: %d" % (reason.value.exitCode,))
self.parent.removeProcess(self.target, self)
def write(self, message):
@ -83,7 +84,7 @@ class CommandExport(object):
# this is specially true if we have other triggers.
def __init__(self, host):
info(_("Plugin command export initialization"))
log.info(_("Plugin command export initialization"))
self.host = host
self.spawned = {} # key = entity
host.trigger.add("MessageReceived", self.MessageReceivedTrigger, priority=10000)
@ -109,7 +110,7 @@ class CommandExport(object):
body = [e for e in message.elements() if e.name == 'body'][0]
except IndexError:
# do not block message without body (chat state notification...)
warning("No body element found in message, following normal behaviour")
log.warning("No body element found in message, following normal behaviour")
return True
mess_data = unicode(body) + '\n'
@ -141,7 +142,7 @@ class CommandExport(object):
"""
profile = self.host.memory.getProfileName(profile_key)
if not profile:
warning("Unknown profile [%s]" % (profile,))
log.warning("Unknown profile [%s]" % (profile,))
return
for target in targets:
@ -151,7 +152,7 @@ class CommandExport(object):
raise jid.InvalidFormat
_jid = _jid.userhostJID()
except (jid.InvalidFormat, RuntimeError):
info(u"invalid target ignored: %s" % (target,))
log.info(u"invalid target ignored: %s" % (target,))
continue
process_prot = ExportCommandProtocol(self, _jid, options, profile)
self.spawned.setdefault((_jid, profile),set()).add(process_prot)

View file

@ -19,7 +19,8 @@
from sat.core.i18n import _
from sat.core.constants import Const as C
from logging import debug, info, warning, error
from sat.core.log import getLogger
log = getLogger(__name__)
from twisted.words.protocols.jabber import jid
from sat.core.exceptions import UnknownEntityError
@ -46,14 +47,14 @@ class Exp_Parrot(object):
# /unparrot command in text commands plugin.
def __init__(self, host):
info(_("Plugin Parrot initialization"))
log.info(_("Plugin Parrot initialization"))
self.host = host
host.trigger.add("MessageReceived", self.MessageReceivedTrigger, priority=100)
#host.trigger.add("sendMessage", self.sendMessageTrigger, priority=100)
try:
self.host.plugins[C.TEXT_CMDS].registerTextCommands(self)
except KeyError:
info(_("Text commands not available"))
log.info(_("Text commands not available"))
#def sendMessageTrigger(self, mess_data, treatments, profile):
# """ Deactivate other triggers if recipient is in parrot links """
@ -64,7 +65,7 @@ class Exp_Parrot(object):
# return True
#
# if mess_data['to'].userhostJID() in _links.values():
# debug("Parrot link detected, skipping other triggers")
# log.debug("Parrot link detected, skipping other triggers")
# raise SkipOtherTriggers
def MessageReceivedTrigger(self, message, post_treat, profile):
@ -101,7 +102,7 @@ class Exp_Parrot(object):
self.host.sendMessage(jid.JID(unicode(linked)), msg, None, "auto", no_trigger=True, profile_key=profile)
else:
warning("No body element found in message, following normal behaviour")
log.warning("No body element found in message, following normal behaviour")
return True
@ -117,7 +118,7 @@ class Exp_Parrot(object):
_links = client.parrot_links = {}
_links[source_jid.userhostJID()] = dest_jid
info("Parrot mode: %s will be repeated to %s" % (source_jid.userhost(), unicode(dest_jid)))
log.info("Parrot mode: %s will be repeated to %s" % (source_jid.userhost(), unicode(dest_jid)))
def removeParrot(self, source_jid, profile):
"""Remove parrot link
@ -131,7 +132,7 @@ class Exp_Parrot(object):
def cmd_parrot(self, mess_data, profile):
"""activate Parrot mode between 2 entities, in both directions."""
debug("Catched parrot command")
log.debug("Catched parrot command")
txt_cmd = self.host.plugins[C.TEXT_CMDS]
try:
@ -153,7 +154,7 @@ class Exp_Parrot(object):
def cmd_unparrot(self, mess_data, profile):
"""remove Parrot mode between 2 entities, in both directions."""
debug("Catched unparrot command")
log.debug("Catched unparrot command")
txt_cmd = self.host.plugins[C.TEXT_CMDS]
try:

View file

@ -19,10 +19,11 @@
from sat.core.i18n import _
from sat.core.constants import Const as C
from logging import debug, info, warning, error
from sat.core.log import getLogger
log = getLogger(__name__)
from twisted.words.xish import domish
from twisted.words.protocols.jabber import jid
from twisted.words.protocols.jabber import error as jab_error
from twisted.words.protocols import jabber
from twisted.internet import reactor
from wokkel import data_form
@ -47,7 +48,7 @@ class Exp_Pipe(object):
"""This is a modified version of XEP-0096 to work with named pipes instead of files"""
def __init__(self, host):
info(_("Plugin Pipe initialization"))
log.info(_("Plugin Pipe initialization"))
self.host = host
self.managed_stream_m = [self.host.plugins["XEP-0065"].NAMESPACE,
self.host.plugins["XEP-0047"].NAMESPACE] # Stream methods managed
@ -62,12 +63,12 @@ class Exp_Pipe(object):
def _kill_id(self, approval_id, profile):
"""Delete a waiting_for_approval id, called after timeout
@param approval_id: id of _pipe_waiting_for_approval"""
info(_("SI Pipe Transfer: TimeOut reached for id %s") % approval_id)
log.info(_("SI Pipe Transfer: TimeOut reached for id %s") % approval_id)
try:
client = self.host.getClient(profile)
del client._pipe_waiting_for_approval[approval_id]
except KeyError:
warning(_("kill id called on a non existant approval id"))
log.warning(_("kill id called on a non existant approval id"))
def transferRequest(self, iq_id, from_jid, si_id, si_mime_type, si_el, profile):
"""Called when a pipe transfer is requested
@ -77,14 +78,14 @@ class Exp_Pipe(object):
@param si_mime_type: Mime type of the pipe (or default "application/octet-stream" if unknown)
@param si_el: domish.Element of the request
@param profile: %(doc_profile)s"""
info(_("EXP-PIPE file transfer requested"))
debug(si_el.toXml())
log.info(_("EXP-PIPE file transfer requested"))
log.debug(si_el.toXml())
client = self.host.getClient(profile)
pipe_elts = filter(lambda elt: elt.name == 'pipe', si_el.elements())
feature_elts = self.host.plugins["XEP-0020"].getFeatureElt(si_el)
if not pipe_elts:
warning(_("No pipe element found"))
log.warning(_("No pipe element found"))
self.host.plugins["XEP-0095"].sendBadRequestError(iq_id, from_jid, profile)
return
@ -94,15 +95,15 @@ class Exp_Pipe(object):
try:
stream_method = self.host.plugins["XEP-0020"].negociate(feature_el, 'stream-method', self.managed_stream_m)
except KeyError:
warning(_("No stream method found"))
log.warning(_("No stream method found"))
self.host.plugins["XEP-0095"].sendBadRequestError(iq_id, from_jid, profile)
return
if not stream_method:
warning(_("Can't find a valid stream method"))
log.warning(_("Can't find a valid stream method"))
self.host.plugins["XEP-0095"].sendFailedError(iq_id, from_jid, profile)
return
else:
warning(_("No feature element found"))
log.warning(_("No feature element found"))
self.host.plugins["XEP-0095"].sendBadRequestError(iq_id, from_jid, profile)
return
@ -125,7 +126,7 @@ class Exp_Pipe(object):
try:
dest_path = frontend_data['dest_path']
except KeyError:
error(_('dest path not found in frontend_data'))
log.error(_('dest path not found in frontend_data'))
del(client._pipe_waiting_for_approval[sid])
return
if stream_method == self.host.plugins["XEP-0065"].NAMESPACE:
@ -135,7 +136,7 @@ class Exp_Pipe(object):
file_obj = open(dest_path, 'w+')
self.host.plugins["XEP-0047"].prepareToReceive(jid.JID(data['from']), sid, file_obj, None, self._transferSucceeded, self._transferFailed, profile)
else:
error(_("Unknown stream method, this should not happen at this stage, cancelling transfer"))
log.error(_("Unknown stream method, this should not happen at this stage, cancelling transfer"))
del(client._pipe_waiting_for_approval[sid])
return
@ -145,7 +146,7 @@ class Exp_Pipe(object):
misc_elts.append(domish.Element((PROFILE, "file")))
self.host.plugins["XEP-0095"].acceptStream(data["id"], data['from'], feature_elt, misc_elts, profile)
else:
debug(_("Transfer [%s] refused"), sid)
log.debug(_("Transfer [%s] refused"), sid)
self.host.plugins["XEP-0095"].sendRejectedError(data["id"], data['from'], profile=profile)
del(client._pipe_waiting_for_approval[sid])
@ -154,7 +155,7 @@ class Exp_Pipe(object):
@param id: stream id"""
client = self.host.getClient(profile)
file_obj.close()
info(_('Transfer %s successfuly finished') % sid)
log.info(_('Transfer %s successfuly finished') % sid)
del(client._pipe_waiting_for_approval[sid])
def _transferFailed(self, sid, file_obj, stream_method, reason, profile):
@ -163,41 +164,41 @@ class Exp_Pipe(object):
@param reason: can be TIMEOUT, IO_ERROR, PROTOCOL_ERROR"""
client = self.host.getClient(profile)
data, timeout, stream_method, failed_methods, profile = client._pipe_waiting_for_approval[sid]
warning(_('Transfer %(id)s failed with stream method %(s_method)s') % {'id': sid,
log.warning(_('Transfer %(id)s failed with stream method %(s_method)s') % {'id': sid,
's_method': stream_method})
# filepath = file_obj.name
file_obj.close()
#TODO: session remenber (within a time limit) when a stream method fail, and avoid that stream method with full jid for the rest of the session
warning(_("All stream methods failed, can't transfer the file"))
log.warning(_("All stream methods failed, can't transfer the file"))
del(client._pipe_waiting_for_approval[sid])
def pipeCb(self, filepath, sid, profile, IQ):
if IQ['type'] == "error":
stanza_err = jab_error.exceptionFromStanza(IQ)
stanza_err = jabber.error.exceptionFromStanza(IQ)
if stanza_err.code == '403' and stanza_err.condition == 'forbidden':
debug(_("Pipe transfer refused by %s") % IQ['from'])
log.debug(_("Pipe transfer refused by %s") % IQ['from'])
self.host.bridge.newAlert(_("The contact %s refused your pipe stream") % IQ['from'], _("Pipe stream refused"), "INFO", profile)
else:
warning(_("Error during pipe stream transfer with %s") % IQ['from'])
log.warning(_("Error during pipe stream transfer with %s") % IQ['from'])
self.host.bridge.newAlert(_("Something went wrong during the pipe stream session intialisation with %s") % IQ['from'], _("Pipe stream error"), "ERROR", profile)
return
si_elt = IQ.firstChildElement()
if IQ['type'] != "result" or not si_elt or si_elt.name != "si":
error(_("Protocol error during file transfer"))
log.error(_("Protocol error during file transfer"))
return
feature_elts = self.host.plugins["XEP-0020"].getFeatureElt(si_elt)
if not feature_elts:
warning(_("No feature element"))
log.warning(_("No feature element"))
return
choosed_options = self.host.plugins["XEP-0020"].getChoosedOptions(feature_elts[0])
try:
stream_method = choosed_options["stream-method"]
except KeyError:
warning(_("No stream method choosed"))
log.warning(_("No stream method choosed"))
return
if stream_method == self.host.plugins["XEP-0065"].NAMESPACE:
@ -211,7 +212,7 @@ class Exp_Pipe(object):
file_obj = open(filepath, 'r') # XXX: we have to be sure that filepath is well opened, as reading can block it
self.host.plugins["XEP-0047"].startStream(file_obj, jid.JID(IQ['from']), sid, None, self.sendSuccessCb, self.sendFailureCb, None, profile)
else:
warning(_("Invalid stream method received"))
log.warning(_("Invalid stream method received"))
def pipeOut(self, to_jid, filepath, data={}, profile_key=C.PROF_KEY_NONE):
"""send a file using EXP-PIPE
@ -223,7 +224,7 @@ class Exp_Pipe(object):
"""
profile = self.host.memory.getProfileName(profile_key)
if not profile:
warning(_("Trying to send a file from an unknown profile"))
log.warning(_("Trying to send a file from an unknown profile"))
return ""
feature_elt = self.host.plugins["XEP-0020"].proposeFeatures({'stream-method': self.managed_stream_m})
@ -237,9 +238,9 @@ class Exp_Pipe(object):
return sid
def sendSuccessCb(self, sid, file_obj, stream_method, profile):
info(_('Transfer %s successfuly finished') % sid)
log.info(_('Transfer %s successfuly finished') % sid)
file_obj.close()
def sendFailureCb(self, sid, file_obj, stream_method, reason, profile):
file_obj.close()
warning(_('Transfer %(id)s failed with stream method %(s_method)s %(profile)s') % {'id': sid, "s_method": stream_method, "profile": profile})
log.warning(_('Transfer %(id)s failed with stream method %(s_method)s %(profile)s') % {'id': sid, "s_method": stream_method, "profile": profile})

View file

@ -18,7 +18,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from sat.core.i18n import _, D_
from logging import debug, info, warning, error
from sat.core.log import getLogger
log = getLogger(__name__)
from sat.core import exceptions
from twisted.internet import reactor, defer, protocol
from os.path import join, dirname
@ -88,10 +89,10 @@ class ProsodyRegisterProtocol(protocol.ProcessProtocol):
def processEnded(self, reason):
if (reason.value.exitCode == 0):
info(_('Prosody command succeed'))
log.info(_('Prosody command succeed'))
self.deferred.callback(None)
else:
error(_(u"Can't complete Prosody command (error code: %(code)d): %(message)s") % {'code': reason.value.exitCode, 'message': self.data})
log.error(_(u"Can't complete Prosody command (error code: %(code)d): %(message)s") % {'code': reason.value.exitCode, 'message': self.data})
self.deferred.errback(Failure(exceptions.InternalError))
@classmethod
@ -117,7 +118,7 @@ class MiscAccount(object):
# only focused on Prosody) is planed
def __init__(self, host):
info(_(u"Plugin Account initialization"))
log.info(_(u"Plugin Account initialization"))
self.host = host
host.bridge.addMethod("registerSatAccount", ".plugin", in_sign='sss', out_sign='', method=self._registerAccount, async=True)
host.bridge.addMethod("getNewAccountDomain", ".plugin", in_sign='', out_sign='s', method=self.getNewAccountDomain, async=False)
@ -126,10 +127,10 @@ class MiscAccount(object):
if self._prosody_path is None:
paths = which(self.getConfig('prosodyctl'))
if not paths:
error(_("Can't find %s") % (self.getConfig('prosodyctl'), ))
log.error(_("Can't find %s") % (self.getConfig('prosodyctl'), ))
else:
self._prosody_path = dirname(paths[0])
info(_('Prosody path found: %s') % (self._prosody_path, ))
log.info(_('Prosody path found: %s') % (self._prosody_path, ))
self.__account_cb_id = host.registerCallback(self._accountDialogCb, with_data=True)
self.__delete_account_id = host.registerCallback(self.__deleteAccountCb, with_data=True)
@ -193,7 +194,7 @@ class MiscAccount(object):
def email_ko(ignore):
#TODO: return error code to user
error("Failed to send email to %s" % email)
log.error("Failed to send email to %s" % email)
body = (u"""Welcome to Libervia, a Salut à Toi project part

View file

@ -19,7 +19,8 @@
from sat.core.i18n import _
from sat.core.constants import Const as C
from logging import debug, info, warning, error
from sat.core.log import getLogger
log = getLogger(__name__)
from twisted.internet import defer
from twisted.words.protocols.jabber import jid
from twisted.words.xish.domish import Element, generateElementsNamed
@ -83,7 +84,7 @@ class GroupBlog(object):
"""This class use a SàT PubSub Service to manage access on microblog"""
def __init__(self, host):
info(_("Group blog plugin initialization"))
log.info(_("Group blog plugin initialization"))
self.host = host
host.bridge.addMethod("sendGroupBlog", ".plugin", in_sign='sassa{ss}s', out_sign='',
@ -157,18 +158,18 @@ class GroupBlog(object):
#we first check that we have a item-access pubsub server
if not hasattr(client, "item_access_pubsub"):
debug(_('Looking for item-access powered pubsub server'))
log.debug(_('Looking for item-access powered pubsub server'))
#we don't have any pubsub server featuring item access yet
item_access_pubsubs = yield self.host.findFeaturesSet((NS_PUBSUB_AUTO_CREATE, NS_PUBSUB_CREATOR_JID_CHECK), "pubsub", "service", profile_key=profile)
# item_access_pubsubs = yield self.host.findFeaturesSet((NS_PUBSUB_ITEM_ACCESS, NS_PUBSUB_AUTO_CREATE, NS_PUBSUB_CREATOR_JID_CHECK), "pubsub", "service", profile_key=profile)
try:
client.item_access_pubsub = item_access_pubsubs.pop()
info(_("item-access powered pubsub service found: [%s]") % client.item_access_pubsub.full())
log.info(_("item-access powered pubsub service found: [%s]") % client.item_access_pubsub.full())
except KeyError:
client.item_access_pubsub = None
if not client.item_access_pubsub:
error(_("No item-access powered pubsub server found, can't use group blog"))
log.error(_("No item-access powered pubsub server found, can't use group blog"))
raise NoCompatiblePubSubServerFound
defer.returnValue((profile, client))
@ -186,7 +187,7 @@ class GroupBlog(object):
if (not (origin_host)
or len(event_host) < len(origin_host)
or event_host[-len(origin_host):] != origin_host):
warning("Host incoherence between %s and %s (hack attempt ?)" % (unicode(event.sender),
log.warning("Host incoherence between %s and %s (hack attempt ?)" % (unicode(event.sender),
unicode(publisher)))
return False
@ -243,7 +244,7 @@ class GroupBlog(object):
try:
microblog_data["groups"] = '\n'.join(form.fields[P.OPT_ROSTER_GROUPS_ALLOWED].values)
except KeyError:
warning("No group found for roster access-model")
log.warning("No group found for roster access-model")
microblog_data["groups"] = ''
break
@ -317,7 +318,7 @@ class GroupBlog(object):
elif access_type == "JID":
raise NotImplementedError
else:
error(_("Unknown access_type"))
log.error(_("Unknown access_type"))
raise BadAccessTypeError
defer_blog = self.host.plugins["XEP-0060"].publish(service, node_name, items=[mblog_item], profile_key=client.profile)
@ -373,7 +374,7 @@ class GroupBlog(object):
elif access_type == "JID":
raise NotImplementedError
else:
error(_("Unknown access type"))
log.error(_("Unknown access type"))
raise BadAccessTypeError
return self._initialise(profile_key).addCallback(initialised)
@ -395,10 +396,10 @@ class GroupBlog(object):
# remove the associated comments node
comments_service, comments_node = self.host.plugins["XEP-0277"].parseCommentUrl(comments)
d = self.host.plugins["XEP-0060"].deleteNode(comments_service, comments_node, profile_key=profile)
d.addErrback(lambda failure: error("Deletion of node %s failed: %s" % (comments_node, failure.getErrorMessage())))
d.addErrback(lambda failure: log.error("Deletion of node %s failed: %s" % (comments_node, failure.getErrorMessage())))
# remove the item itself
d = self.host.plugins["XEP-0060"].retractItems(service_jid, node, [item_id], profile_key=profile)
d.addErrback(lambda failure: error("Deletion of item %s from %s failed: %s" % (item_id, node, failure.getErrorMessage())))
d.addErrback(lambda failure: log.error("Deletion of item %s from %s failed: %s" % (item_id, node, failure.getErrorMessage())))
return d
def notify(d):
@ -447,7 +448,7 @@ class GroupBlog(object):
self.__fillCommentsElement(mblog_data, entry_id, node, service_jid)
entry_d = self.host.plugins["XEP-0277"].data2entry(mblog_data, profile)
entry_d.addCallback(lambda mblog_item: self.host.plugins["XEP-0060"].publish(service_jid, node, items=[mblog_item], profile_key=profile))
entry_d.addErrback(lambda failure: error("Modification of %s failed: %s" % (pub_data, failure.getErrorMessage())))
entry_d.addErrback(lambda failure: log.error("Modification of %s failed: %s" % (pub_data, failure.getErrorMessage())))
return entry_d
return self._initialise(profile_key).addCallback(initialised)
@ -501,7 +502,7 @@ class GroupBlog(object):
self.host.plugins["XEP-0060"].subscribe(jid.JID(gbdata["comments_service"]), gbdata["comments_node"],
profile_key=client.profile)
except KeyError:
warning("Missing key for comments")
log.warning("Missing key for comments")
defer.returnValue(ret)
def __getGroupBlogs(self, pub_jid_s, max_items=10, item_ids=None, profile_key=C.PROF_KEY_NONE):
@ -775,8 +776,8 @@ class GroupBlog(object):
main_node = self.getNodeName(jid_)
d = self.host.plugins["XEP-0060"].deleteNode(service, main_node, profile_key=profile)
d.addCallback(lambda dummy: info(_("All microblog's main items from %s have been deleted!") % jid_.userhost()))
d.addErrback(lambda failure: error(_("Deletion of node %(node)s failed: %(message)s") %
d.addCallback(lambda dummy: log.info(_("All microblog's main items from %s have been deleted!") % jid_.userhost()))
d.addErrback(lambda failure: log.error(_("Deletion of node %(node)s failed: %(message)s") %
{'node': main_node, 'message': failure.getErrorMessage()}))
return d
@ -799,7 +800,7 @@ class GroupBlog(object):
main_node = self.getNodeName(jid_)
d = self.host.plugins["XEP-0060"].getItems(service, main_node, profile_key=profile)
d.addCallback(getComments, client)
d.addErrback(lambda failure, main_node: error(_("Retrieval of items for node %(node)s failed: %(message)s") %
d.addErrback(lambda failure, main_node: log.error(_("Retrieval of items for node %(node)s failed: %(message)s") %
{'node': main_node, 'message': failure.getErrorMessage()}), main_node)
blogs.append(d)
@ -822,7 +823,7 @@ class GroupBlog(object):
service, node = self.host.plugins['XEP-0277'].parseCommentUrl(href)
d = self.host.plugins["XEP-0060"].getItems(service, node, profile_key=profile_key)
d.addCallback(lambda items, service, node: (service, node, items), service, node)
d.addErrback(lambda failure, node: error(_("Retrieval of comments for node %(node)s failed: %(message)s") %
d.addErrback(lambda failure, node: log.error(_("Retrieval of comments for node %(node)s failed: %(message)s") %
{'node': node, 'message': failure.getErrorMessage()}), node)
comments.append(d)
dlist = defer.DeferredList(comments)
@ -854,9 +855,9 @@ class GroupBlog(object):
deletions = []
if item_ids: # remove the comments of the user on the given post
d = self.host.plugins['XEP-0060'].retractItems(service, node_id, item_ids, profile_key=profile_key)
d.addCallback(lambda dummy, node_id: debug(_('Comments of user %(user)s in node %(node)s have been retracted') %
d.addCallback(lambda dummy, node_id: log.debug(_('Comments of user %(user)s in node %(node)s have been retracted') %
{'user': user_jid_s, 'node': node_id}), node_id)
d.addErrback(lambda failure, node_id: error(_("Retraction of comments from %(user)s in node %(node)s failed: %(message)s") %
d.addErrback(lambda failure, node_id: log.error(_("Retraction of comments from %(user)s in node %(node)s failed: %(message)s") %
{'user': user_jid_s, 'node': node_id, 'message': failure.getErrorMessage()}), node_id)
deletions.append(d)
return defer.DeferredList(deletions)

View file

@ -18,20 +18,17 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from sat.core.i18n import _
from logging import debug, info, error
import warnings
from sat.core.log import getLogger
log = getLogger(__name__)
from twisted.internet import protocol, defer
from twisted.words.protocols.jabber import error as jab_error
from twisted.cred import portal, checkers, credentials
from twisted.cred import error as cred_error
from twisted.mail import imap4
from twisted.python import failure
from email.parser import Parser
import email.message
import os
from cStringIO import StringIO
from twisted.internet import reactor
import pdb
from zope.interface import implements
@ -61,14 +58,14 @@ class IMAP_server(object):
"""
def __init__(self, host):
info(_("Plugin Imap Server initialization"))
log.info(_("Plugin Imap Server initialization"))
self.host = host
#parameters
host.memory.updateParams(self.params)
port = int(self.host.memory.getParamA("IMAP Port", "Mail Server"))
info(_("Launching IMAP server on port %d"), port)
log.info(_("Launching IMAP server on port %d") % port)
self.server_factory = ImapServerFactory(self.host)
reactor.listenTCP(port, self.server_factory)
@ -78,7 +75,7 @@ class Message(object):
implements(imap4.IMessage)
def __init__(self, uid, flags, mess_fp):
debug('Message Init')
log.debug('Message Init')
self.uid = uid
self.flags = flags
self.mess_fp = mess_fp
@ -87,21 +84,21 @@ class Message(object):
def getUID(self):
"""Retrieve the unique identifier associated with this message.
"""
debug('getUID (message)')
log.debug('getUID (message)')
return self.uid
def getFlags(self):
"""Retrieve the flags associated with this message.
@return: The flags, represented as strings.
"""
debug('getFlags')
log.debug('getFlags')
return self.flags
def getInternalDate(self):
"""Retrieve the date internally associated with this message.
@return: An RFC822-formatted date string.
"""
debug('getInternalDate')
log.debug('getInternalDate')
return self.message['Date']
def getHeaders(self, negate, *names):
@ -111,7 +108,7 @@ class Message(object):
should be omitted from the return value, rather than included.
@return: A mapping of header field names to header field values
"""
debug('getHeaders %s - %s' % (negate, names))
log.debug('getHeaders %s - %s' % (negate, names))
final_dict = {}
to_check = [name.lower() for name in names]
for header in self.message.keys():
@ -123,20 +120,20 @@ class Message(object):
def getBodyFile(self):
"""Retrieve a file object containing only the body of this message.
"""
debug('getBodyFile')
log.debug('getBodyFile')
return StringIO(self.message.get_payload())
def getSize(self):
"""Retrieve the total size, in octets, of this message.
"""
debug('getSize')
log.debug('getSize')
self.mess_fp.seek(0, os.SEEK_END)
return self.mess_fp.tell()
def isMultipart(self):
"""Indicate whether this message has subparts.
"""
debug('isMultipart')
log.debug('isMultipart')
return False
def getSubPart(self, part):
@ -144,7 +141,7 @@ class Message(object):
@param part: The number of the part to retrieve, indexed from 0.
@return: The specified sub-part.
"""
debug('getSubPart')
log.debug('getSubPart')
return TypeError
@ -154,14 +151,14 @@ class SatMailbox(object):
def __init__(self, host, name, profile):
self.host = host
self.listeners = set()
debug('Mailbox init (%s)', name)
log.debug('Mailbox init (%s)', name)
if name != "INBOX":
raise imap4.MailboxException("Only INBOX is managed for the moment")
self.mailbox = self.host.plugins["Maildir"].accessMessageBox(name, self.newMessage, profile)
def newMessage(self):
"""Called when a new message is in the mailbox"""
debug("newMessage signal received")
log.debug("newMessage signal received")
nb_messages = self.getMessageCount()
for listener in self.listeners:
listener.newMessages(nb_messages, None)
@ -169,13 +166,13 @@ class SatMailbox(object):
def getUIDValidity(self):
"""Return the unique validity identifier for this mailbox.
"""
debug('getUIDValidity')
log.debug('getUIDValidity')
return 0
def getUIDNext(self):
"""Return the likely UID for the next message added to this mailbox.
"""
debug('getUIDNext')
log.debug('getUIDNext')
return self.mailbox.getNextUid()
def getUID(self, message):
@ -183,41 +180,41 @@ class SatMailbox(object):
@param message: The message sequence number
@return: The UID of the message.
"""
debug('getUID (%i)' % message)
log.debug('getUID (%i)' % message)
#return self.mailbox.getUid(message-1) #XXX: it seems that this method get uid and not message sequence number
return message
def getMessageCount(self):
"""Return the number of messages in this mailbox.
"""
debug('getMessageCount')
log.debug('getMessageCount')
ret = self.mailbox.getMessageCount()
debug("count = %i" % ret)
log.debug("count = %i" % ret)
return ret
def getRecentCount(self):
"""Return the number of messages with the 'Recent' flag.
"""
debug('getRecentCount')
log.debug('getRecentCount')
return len(self.mailbox.getMessageIdsWithFlag('\\Recent'))
def getUnseenCount(self):
"""Return the number of messages with the 'Unseen' flag.
"""
debug('getUnseenCount')
log.debug('getUnseenCount')
return self.getMessageCount() - len(self.mailbox.getMessageIdsWithFlag('\\SEEN'))
def isWriteable(self):
"""Get the read/write status of the mailbox.
@return: A true value if write permission is allowed, a false value otherwise.
"""
debug('isWriteable')
log.debug('isWriteable')
return True
def destroy(self):
"""Called before this mailbox is deleted, permanently.
"""
debug('destroy')
log.debug('destroy')
def requestStatus(self, names):
"""Return status information about this mailbox.
@ -229,7 +226,7 @@ class SatMailbox(object):
information up would be costly, a deferred whose callback will
eventually be passed this dictionary is returned instead.
"""
debug('requestStatus')
log.debug('requestStatus')
return imap4.statusRequestHelper(self, names)
def addListener(self, listener):
@ -239,7 +236,7 @@ class SatMailbox(object):
@param listener: An object to add to the set of those which will
be notified when the contents of this mailbox change.
"""
debug('addListener %s' % listener)
log.debug('addListener %s' % listener)
self.listeners.add(listener)
def removeListener(self, listener):
@ -252,7 +249,7 @@ class SatMailbox(object):
@raise ValueError: Raised when the given object is not a listener for
this mailbox.
"""
debug('removeListener')
log.debug('removeListener')
if listener in self.listeners:
self.listeners.remove(listener)
else:
@ -267,7 +264,7 @@ class SatMailbox(object):
id if the message is added successfully and whose errback is
invoked otherwise.
"""
debug('addMessage')
log.debug('addMessage')
raise imap4.MailboxException("Client message addition not implemented yet")
def expunge(self):
@ -275,7 +272,7 @@ class SatMailbox(object):
@return: The list of message sequence numbers which were deleted,
or a Deferred whose callback will be invoked with such a list.
"""
debug('expunge')
log.debug('expunge')
self.mailbox.removeDeleted()
def fetch(self, messages, uid):
@ -284,13 +281,13 @@ class SatMailbox(object):
about
@param uid: If true, the IDs specified in the query are UIDs;
"""
debug('fetch (%s, %s)' % (messages, uid))
log.debug('fetch (%s, %s)' % (messages, uid))
if uid:
messages.last = self.mailbox.getMaxUid()
messages.getnext = self.mailbox.getNextExistingUid
for mess_uid in messages:
if mess_uid is None:
debug('stopping iteration')
log.debug('stopping iteration')
raise StopIteration
try:
yield (mess_uid, Message(mess_uid, self.mailbox.getFlagsUid(mess_uid), self.mailbox.getMessageUid(mess_uid)))
@ -318,7 +315,7 @@ class SatMailbox(object):
been performed, or a Deferred whose callback will be invoked with
such a dict.
"""
debug('store')
log.debug('store')
flags = [flag.upper() for flag in flags]
@ -361,13 +358,13 @@ class SatMailbox(object):
Flags with the \\ prefix are reserved for use as system flags.
@return: A list of the flags that can be set on messages in this mailbox.
"""
debug('getFlags')
log.debug('getFlags')
return ['\\SEEN', '\\ANSWERED', '\\FLAGGED', '\\DELETED', '\\DRAFT'] # TODO: add '\\RECENT'
def getHierarchicalDelimiter(self):
"""Get the character which delimits namespaces for in this mailbox.
"""
debug('getHierarchicalDelimiter')
log.debug('getHierarchicalDelimiter')
return '.'
@ -375,12 +372,12 @@ class ImapSatAccount(imap4.MemoryAccount):
#implements(imap4.IAccount)
def __init__(self, host, profile):
debug("ImapAccount init")
log.debug("ImapAccount init")
self.host = host
self.profile = profile
imap4.MemoryAccount.__init__(self, profile)
self.addMailbox("Inbox") # We only manage Inbox for the moment
debug('INBOX added')
log.debug('INBOX added')
def _emptyMailbox(self, name, id):
return SatMailbox(self.host, name, self.profile)
@ -393,7 +390,7 @@ class ImapRealm(object):
self.host = host
def requestAvatar(self, avatarID, mind, *interfaces):
debug('requestAvatar')
log.debug('requestAvatar')
profile = avatarID.decode('utf-8')
if imap4.IAccount not in interfaces:
raise NotImplementedError
@ -436,13 +433,13 @@ class ImapServerFactory(protocol.ServerFactory):
self.host = host
def startedConnecting(self, connector):
debug(_("IMAP server connection started"))
log.debug(_("IMAP server connection started"))
def clientConnectionLost(self, connector, reason):
debug(_("IMAP server connection lost (reason: %s)"), reason)
log.debug(_("IMAP server connection lost (reason: %s)"), reason)
def buildProtocol(self, addr):
debug("Building protocol")
log.debug("Building protocol")
prot = protocol.ServerFactory.buildProtocol(self, addr)
prot.portal = portal.Portal(ImapRealm(self.host))
prot.portal.registerChecker(SatProfileCredentialChecker(self.host))

Some files were not shown because too many files have changed in this diff Show more