20 commits - bin/kolab_smtp_access_policy.py configure.ac kolabd/__init__.py Makefile.am pykolab/auth pykolab/cli pykolab/conf pykolab/imap pykolab/logger.py pykolab/Makefile.am pykolab/plugins pykolab/setup pykolab.spec.in pykolab/telemetry.py pykolab/tests pykolab/utils.py pykolab/wap_client saslauthd/__init__.py test-wallace.py wallace/__init__.py wallace/Makefile.am wallace/module_optout.py wallace/modules.py

Jeroen van Meeuwen vanmeeuwen at kolabsys.com
Fri Mar 9 11:43:26 CET 2012


 Makefile.am                                        |   36 ++-
 bin/kolab_smtp_access_policy.py                    |  100 ++++++----
 configure.ac                                       |    3 
 kolabd/__init__.py                                 |   73 +++++--
 pykolab.spec.in                                    |   32 +++
 pykolab/Makefile.am                                |   21 --
 pykolab/auth/__init__.py                           |   21 +-
 pykolab/auth/ldap/__init__.py                      |  169 +++++++++++------
 pykolab/cli/cmd_export_mailbox.py                  |   12 -
 pykolab/cli/cmd_list_domains.py                    |    4 
 pykolab/cli/cmd_list_mailboxes.py                  |    2 
 pykolab/cli/cmd_sync.py                            |    6 
 pykolab/cli/cmd_transfer_mailbox.py                |    2 
 pykolab/cli/commands.py                            |   36 +--
 pykolab/cli/telemetry/cmd_examine_command_issue.py |    6 
 pykolab/cli/telemetry/cmd_examine_session.py       |    6 
 pykolab/cli/telemetry/cmd_list_sessions.py         |    2 
 pykolab/conf/__init__.py                           |   66 +++---
 pykolab/conf/entitlement.py                        |   18 -
 pykolab/imap/__init__.py                           |   92 ++++-----
 pykolab/imap/cyrus.py                              |   44 ++--
 pykolab/logger.py                                  |    2 
 pykolab/plugins/__init__.py                        |   16 -
 pykolab/plugins/defaultfolders/__init__.py         |    4 
 pykolab/plugins/dynamicquota/__init__.py           |    4 
 pykolab/plugins/recipientpolicy/__init__.py        |    6 
 pykolab/setup/components.py                        |   36 +--
 pykolab/setup/ldap_setup.py                        |    4 
 pykolab/setup/setup_ldap.py                        |    2 
 pykolab/telemetry.py                               |   12 -
 pykolab/tests/imap/test_login.py                   |   10 -
 pykolab/tests/tests.py                             |   38 +--
 pykolab/utils.py                                   |   10 -
 pykolab/wap_client/__init__.py                     |   18 -
 saslauthd/__init__.py                              |    4 
 test-wallace.py                                    |   13 +
 wallace/Makefile.am                                |    3 
 wallace/__init__.py                                |  151 ++++++++++++---
 wallace/module_optout.py                           |   74 +++++--
 wallace/modules.py                                 |  204 ++++++++++++++++++---
 40 files changed, 919 insertions(+), 443 deletions(-)

New commits:
commit 2354a1c857b163bda603f19956122a539e2b4a12
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Fri Mar 9 10:40:32 2012 +0000

    Correct the port to be 10026

diff --git a/test-wallace.py b/test-wallace.py
index 84d3488..8da3475 100755
--- a/test-wallace.py
+++ b/test-wallace.py
@@ -32,7 +32,7 @@ from email.Utils import COMMASPACE, formatdate
 from email import Encoders
 
 def send_mail(send_from, send_to, send_with=None):
-    smtp = smtplib.SMTP("localhost", 8025)
+    smtp = smtplib.SMTP("localhost", 10026)
     smtp.set_debuglevel(True)
     subject = "This is a Kolab load test mail"
     text = """Hi there,
@@ -88,6 +88,15 @@ if __name__ == "__main__":
             #send_to
         #)
 
-    send_to = [ 'Jeroen van Meeuwen <jeroen.vanmeeuwen at klab.cc>' ]
+    send_to = [
+            'Jeroen van Meeuwen (REJECT) <vanmeeuwen+reject at kolabsys.com>',
+            'Jeroen van Meeuwen (HOLD) <vanmeeuwen+hold at kolabsys.com>',
+            'Jeroen van Meeuwen (DEFER) <vanmeeuwen+defer at kolabsys.com>',
+            'Jeroen van Meeuwen (ACCEPT) <vanmeeuwen+accept at kolabsys.com>',
+            'Jeroen "kanarip" van Meeuwen (ACCEPT) <kanarip+accept at kolabsys.com>',
+            'Jeroen "kanarip" van Meeuwen (REJECT) <kanarip+reject at kolabsys.com>',
+            'Lucy Meier (REJECT) <meier+reject at kolabsys.com>',
+            'Georg Greve (REJECT) <greve+reject at kolabsys.com>',
+        ]
 
     send_mail('Jeroen van Meeuwen <vanmeeuwen at kolabsys.com>', send_to)
diff --git a/wallace/__init__.py b/wallace/__init__.py
index 86d933f..0230c64 100644
--- a/wallace/__init__.py
+++ b/wallace/__init__.py
@@ -56,7 +56,7 @@ class WallaceDaemon(object):
                 "-p", "--port",
                 dest    = "wallace_port",
                 action  = "store",
-                default = 10027,
+                default = 10026,
                 help    = _("Port that Wallace is supposed to use.")
             )
 


commit 8f4e77a6488d9d286d83eba6712134354ddad93c
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Fri Mar 9 10:38:37 2012 +0000

    Correct some pylint conventions

diff --git a/saslauthd/__init__.py b/saslauthd/__init__.py
index 1fa5e63..634594d 100644
--- a/saslauthd/__init__.py
+++ b/saslauthd/__init__.py
@@ -141,7 +141,7 @@ class SASLAuthDaemon(object):
                 (length,) = struct.unpack("!H", received[start:end])
                 start += 2
                 end += length
-                (value,) = struct.unpack("!%ds" %(length), received[start:end])
+                (value,) = struct.unpack("!%ds" % (length), received[start:end])
                 start += length
                 end = start + 2
                 login.append(value)
@@ -170,5 +170,5 @@ class SASLAuthDaemon(object):
     def write_pid(self):
         pid = os.getpid()
         fp = open(conf.pidfile,'w')
-        fp.write("%d\n" %(pid))
+        fp.write("%d\n" % (pid))
         fp.close()


commit 107f91157704dbc5b6b7054cf420da5ef651027f
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Fri Mar 9 10:38:13 2012 +0000

    Correct some pylint conventions

diff --git a/wallace/__init__.py b/wallace/__init__.py
index 5897ac7..86d933f 100644
--- a/wallace/__init__.py
+++ b/wallace/__init__.py
@@ -87,39 +87,80 @@ class WallaceDaemon(object):
         os.close(fp)
 
         while threading.active_count() > 25:
-            log.debug(_("Number of threads currently running: %d") %(threading.active_count()), level=8)
-            time.sleep(10)
+            log.debug(
+                    _("Number of threads currently running: %d") % (
+                            threading.active_count()
+                        ),
+                    level=8
+                )
 
-        log.debug(_("Continuing with %d threads currently running") %(threading.active_count()), level=8)
+            time.sleep(1)
+
+        log.debug(
+                _("Continuing with %d threads currently running") % (
+                        threading.active_count()
+                    ),
+                level=8
+            )
 
         # TODO: Apply throttling
-        log.debug(_("Creating thread for message in %s") %(filename), level=8)
+        log.debug(_("Creating thread for message in %s") % (filename), level=8)
 
         thread = threading.Thread(target=self.thread_run, args=[ filename ])
         thread.start()
 
     def thread_run(self, filename, *args, **kw):
         while threading.active_count() > 25:
-            log.debug(_("Number of threads currently running: %d") %(threading.active_count()), level=8)
+            log.debug(
+                    _("Number of threads currently running: %d") % (
+                            threading.active_count()
+                        ),
+                    level=8
+                )
+
             time.sleep(10)
 
-        log.debug(_("Continuing with %d threads currently running") %(threading.active_count()), level=8)
+        log.debug(
+                _("Continuing with %d threads currently running") % (
+                        threading.active_count()
+                    ),
+                level=8
+            )
 
-        log.debug(_("Running thread %s for message file %s") %(threading.current_thread().name,filename), level=8)
+        log.debug(
+                _("Running thread %s for message file %s") % (
+                        threading.current_thread().name,
+                        filename
+                    ),
+                level=8
+            )
 
         if kw.has_key('module'):
-            log.debug(_("This message was already in module %s, delegating specifically to that module") %(kw['module']), level=8)
+            log.debug(
+                    _("This message was already in module %s, delegating " + \
+                        "specifically to that module") % (
+                            kw['module']
+                        ),
+                    level=8
+                )
 
             if kw.has_key('stage'):
-                log.debug(_("It was also in a certain stage: %s, letting module %s know that") %(kw['stage'],kw['module']), level=8)
+                log.debug(
+                        _("It was also in a certain stage: %s, letting " + \
+                            "module %s know that") % (
+                                kw['stage'],
+                                kw['module']
+                            ),
+                        level=8
+                    )
 
-                log.debug(_("Executing module %s") %(kw['module']), level=8)
+                log.debug(_("Executing module %s") % (kw['module']), level=8)
 
                 modules.execute(kw['module'], filename, stage=kw['stage'])
 
                 return
 
-            log.debug(_("Executing module %s") %(kw['module']), level=8)
+            log.debug(_("Executing module %s") % (kw['module']), level=8)
             modules.execute(kw['module'], filename, stage=kw['stage'])
 
             return
@@ -129,7 +170,7 @@ class WallaceDaemon(object):
             wallace_modules = []
 
         for module in wallace_modules:
-            log.debug(_("Executing module %s") %(module), level=8)
+            log.debug(_("Executing module %s") % (module), level=8)
             modules.execute(module, filename)
 
     def run(self):
@@ -158,7 +199,9 @@ class WallaceDaemon(object):
         except AttributeError, e:
             exitcode = 1
             traceback.print_exc()
-            print >> sys.stderr, _("Traceback occurred, please report a bug at http://bugzilla.kolabsys.com")
+            print >> sys.stderr, _("Traceback occurred, please report a " + \
+                "bug at http://bugzilla.kolabsys.com")
+
         except TypeError, e:
             exitcode = 1
             traceback.print_exc()
@@ -166,7 +209,9 @@ class WallaceDaemon(object):
         except:
             exitcode = 2
             traceback.print_exc()
-            print >> sys.stderr, _("Traceback occurred, please report a bug at http://bugzilla.kolabsys.com")
+            print >> sys.stderr, _("Traceback occurred, please report a " + \
+                "bug at http://bugzilla.kolabsys.com")
+
         sys.exit(exitcode)
 
     def pickup_defer(self):
@@ -199,7 +244,12 @@ class WallaceDaemon(object):
             time.sleep(1)
 
             for module in wallace_modules:
-                log.debug(_("Picking up deferred messages for module %s") %(module), level=8)
+                log.debug(
+                        _("Picking up deferred messages for module %s") % (
+                                module
+                            ),
+                        level=8
+                    )
 
                 module_defer_path = os.path.join(base_path, module, 'DEFER')
 
@@ -222,8 +272,8 @@ class WallaceDaemon(object):
                 log.debug(_("Sleeping for 1 second"), level=8)
                 time.sleep(1)
             else:
-                log.debug(_("Sleeping for 10 seconds"), level=8)
-                time.sleep(10)
+                log.debug(_("Sleeping for 1800 seconds"), level=8)
+                time.sleep(1800)
 
 
     def do_wallace(self):
@@ -249,7 +299,7 @@ class WallaceDaemon(object):
             except Exception, e:
                 log.warning(
                         _("Could not bind to socket on port %d on bind " + \
-                            "address %s") %(
+                            "address %s") % (
                                 conf.wallace_port,
                                 conf.wallace_bind_address
                             )
@@ -280,8 +330,8 @@ class WallaceDaemon(object):
                 if not root == pickup_path:
                     module = os.path.dirname(root).replace(pickup_path, '')
 
-                    # Compare uppercase status (specifically, DEFER) with lowercase
-                    # (plugin names).
+                    # Compare uppercase status (specifically, DEFER) with
+                    # lowercase (plugin names).
                     #
                     # The messages in DEFER are supposed to be picked up by
                     # another thread, whereas the messages in other directories
@@ -309,13 +359,19 @@ class WallaceDaemon(object):
                     if stage.lower() == "defer":
                         continue
 
-                    log.debug(_("Number of threads currently running: %d") %(threading.active_count()), level=8)
+                    log.debug(
+                            _("Number of threads currently running: %d") % (
+                                    threading.active_count()
+                                ),
+                            level=8
+                        )
+
                     thread = threading.Thread(
                             target = self.thread_run,
                             args = [ filepath ],
                             kwargs = {
-                                    "module": '%s' %(module),
-                                    "stage": '%s' %(stage)
+                                    "module": '%s' % (module),
+                                    "stage": '%s' % (stage)
                                 }
                         )
 
@@ -324,9 +380,25 @@ class WallaceDaemon(object):
 
                     continue
 
-                log.debug(_("Picking up spooled email file %s") %(filepath), level=8)
-                log.debug(_("Number of threads currently running: %d") %(threading.active_count()), level=8)
-                thread = threading.Thread(target=self.thread_run, args=[ filepath ])
+                log.debug(
+                        _("Picking up spooled email file %s") % (
+                                filepath
+                            ),
+                        level=8
+                    )
+
+                log.debug(
+                        _("Number of threads currently running: %d") % (
+                                threading.active_count()
+                            ),
+                        level=8
+                    )
+
+                thread = threading.Thread(
+                        target=self.thread_run,
+                        args=[ filepath ]
+                    )
+
                 thread.start()
                 time.sleep(0.5)
 
@@ -342,7 +414,7 @@ class WallaceDaemon(object):
                     log.info(_("Accepted connection"))
                     if not pair == None:
                         connection, address = pair
-                        #print "Accepted connection from %r" %(address)
+                        #print "Accepted connection from %r" % (address)
                         channel = SMTPChannel(self, connection, address)
                         asyncore.loop()
             except Exception, e:
diff --git a/wallace/module_optout.py b/wallace/module_optout.py
index 3e2fd09..79cafb7 100644
--- a/wallace/module_optout.py
+++ b/wallace/module_optout.py
@@ -49,16 +49,16 @@ def execute(*args, **kw):
     filepath = args[0]
 
     if kw.has_key('stage'):
-        log.debug(_("Issuing callback after processing to stage %s") %(kw['stage']), level=8)
-        log.debug(_("Testing cb_action_%s()") %(kw['stage']), level=8)
-        if hasattr(modules, 'cb_action_%s' %(kw['stage'])):
-            log.debug(_("Attempting to execute cb_action_%s()") %(kw['stage']), level=8)
-            exec('modules.cb_action_%s(%r, %r)' %(kw['stage'],'optout',filepath))
+        log.debug(_("Issuing callback after processing to stage %s") % (kw['stage']), level=8)
+        log.debug(_("Testing cb_action_%s()") % (kw['stage']), level=8)
+        if hasattr(modules, 'cb_action_%s' % (kw['stage'])):
+            log.debug(_("Attempting to execute cb_action_%s()") % (kw['stage']), level=8)
+            exec('modules.cb_action_%s(%r, %r)' % (kw['stage'],'optout',filepath))
             return
 
         #modules.next_module('optout')
 
-    log.debug(_("Consulting opt-out service for %r, %r") %(args, kw), level=8)
+    log.debug(_("Consulting opt-out service for %r, %r") % (args, kw), level=8)
 
     import email
     message = email.message_from_file(open(filepath, 'r'))
@@ -86,7 +86,7 @@ def execute(*args, **kw):
         for recipient in recipients[recipient_type]:
             log.debug(
                     _("Running opt-out consult from envelope sender '%s " + \
-                        "<%s>' to recipient %s <%s>") %(
+                        "<%s>' to recipient %s <%s>") % (
                             envelope_sender[0][0],
                             envelope_sender[0][1],
                             recipient[0],
@@ -143,23 +143,23 @@ def execute(*args, **kw):
         if use_this:
             # TODO: Do not set items with an empty list.
 
-            (fp, filename) = tempfile.mkstemp(dir="/var/spool/pykolab/wallace/optout/%s" %(answer))
+            (fp, filename) = tempfile.mkstemp(dir="/var/spool/pykolab/wallace/optout/%s" % (answer))
             os.write(fp, _message.__str__())
             os.close(fp)
 
             # Callback with new filename
-            if hasattr(modules, 'cb_action_%s' %(answer)):
-                log.debug(_("Attempting to execute cb_action_%s(%r, %r)") %(answer, 'optout', filename), level=8)
-                exec('modules.cb_action_%s(%r, %r)' %(answer,'optout', filename))
+            if hasattr(modules, 'cb_action_%s' % (answer)):
+                log.debug(_("Attempting to execute cb_action_%s(%r, %r)") % (answer, 'optout', filename), level=8)
+                exec('modules.cb_action_%s(%r, %r)' % (answer,'optout', filename))
 
     os.unlink(filepath)
 
-    #print "Moving filepath %s to new_filepath %s" %(filepath, new_filepath)
+    #print "Moving filepath %s to new_filepath %s" % (filepath, new_filepath)
     #os.rename(filepath, new_filepath)
 
-    #if hasattr(modules, 'cb_action_%s' %(optout_answer)):
-        #log.debug(_("Attempting to execute cb_action_%s()") %(optout_answer), level=8)
-        #exec('modules.cb_action_%s(%r, %r)' %(optout_answer,'optout', new_filepath))
+    #if hasattr(modules, 'cb_action_%s' % (optout_answer)):
+        #log.debug(_("Attempting to execute cb_action_%s()") % (optout_answer), level=8)
+        #exec('modules.cb_action_%s(%r, %r)' % (optout_answer,'optout', new_filepath))
         #return
 
 def request(params=None):
@@ -170,7 +170,7 @@ def request(params=None):
     try:
         f = urllib.urlopen(optout_url, params)
     except Exception, e:
-        log.error(_("Could not send request to optout_url %s") %(optout_url))
+        log.error(_("Could not send request to optout_url %s") % (optout_url))
         return "DEFER"
 
     response = f.read()
diff --git a/wallace/modules.py b/wallace/modules.py
index 374f440..464cf8e 100644
--- a/wallace/modules.py
+++ b/wallace/modules.py
@@ -19,8 +19,20 @@
 
 import os
 import sys
+import time
+
+import email
+from email.mime.base import MIMEBase
+from email.mime.message import MIMEMessage
+from email.mime.multipart import MIMEMultipart
+from email.mime.text import MIMEText
+from email.utils import COMMASPACE
+from email.utils import formatdate
+
+import smtplib
 
 import pykolab
+from pykolab import constants
 from pykolab.translate import _
 
 log = pykolab.getLogger('pykolab.wallace')
@@ -40,9 +52,9 @@ def __init__():
             if filename.startswith('module_') and filename.endswith('.py'):
                 module_name = filename.replace('.py','')
                 name = module_name.replace('module_', '')
-                #print "exec(\"from %s import __init__ as %s_register\"" %(module_name,name)
-                exec("from %s import __init__ as %s_register" %(module_name,name))
-                exec("%s_register()" %(name))
+                #print "exec(\"from %s import __init__ as %s_register\"" % (module_name,name)
+                exec("from %s import __init__ as %s_register" % (module_name, name))
+                exec("%s_register()" % (name))
 
         for dirname in dirnames:
             register_group(modules_path, dirname)
@@ -70,21 +82,21 @@ def list_modules(*args, **kw):
         if __modules[_module].has_key('function'):
             # This is a top-level module
             if not __modules[_module]['description'] == None:
-                print "%-25s - %s" %(_module.replace('_','-'),__modules[_module]['description'])
+                print "%-25s - %s" % (_module.replace('_','-'),__modules[_module]['description'])
             else:
-                print "%-25s" %(_module.replace('_','-'))
+                print "%-25s" % (_module.replace('_','-'))
 
     for _module in _modules:
         if not __modules[_module].has_key('function'):
             # This is a nested module
-            print "\n" + _("Module Group: %s") %(_module) + "\n"
+            print "\n" + _("Module Group: %s") % (_module) + "\n"
             ___modules = __modules[_module].keys()
             ___modules.sort()
             for __module in ___modules:
                 if not __modules[_module][__module]['description'] == None:
-                    print "%-4s%-21s - %s" %('',__module.replace('_','-'),__modules[_module][__module]['description'])
+                    print "%-4s%-21s - %s" % ('',__module.replace('_','-'),__modules[_module][__module]['description'])
                 else:
-                    print "%-4s%-21s" %('',__module.replace('_','-'))
+                    print "%-4s%-21s" % ('',__module.replace('_','-'))
 
 def execute(name, *args, **kw):
     if not modules.has_key(name):
@@ -99,22 +111,166 @@ def execute(name, *args, **kw):
     modules[name]['function'](*args, **kw)
 
 def cb_action_HOLD(module, filepath):
-    log.info(_("Holding message in queue for manual review (%s by %s)") %(filepath, module))
-    ## Actually just unlink the file for now
-    #os.unlink(filepath)
+    log.info(_("Holding message in queue for manual review (%s by %s)") % (filepath, module))
 
 def cb_action_DEFER(module, filepath):
-    log.info(_("Deferring message in %s (by module %s)") %(filepath, module))
+    log.info(_("Deferring message in %s (by module %s)") % (filepath, module))
+    message = email.message_from_file(open(filepath, 'r'))
+
+    internal_time = email.Utils.parsedate_tz(message.__getitem__('Date'))
+    internal_time = time.mktime(internal_time[:9]) + internal_time[9]
+
+    now_time = time.time()
+
+    delta = now_time - internal_time
+
+    log.debug(_("The time when the message was sent: %r") % (internal_time), level=8)
+    log.debug(_("The time now: %r") % (now_time), level=8)
+    log.debug(_("The time delta: %r") % (delta), level=8)
+
+    if delta > 432000:
+        # TODO: Send NDR back to user
+        log.debug(_("Message in file %s older then 5 days, deleting") % (filepath), level=8)
+        os.unlink(filepath)
+
+    # Alternative method is file age.
+    #Date sent(/var/spool/pykolab/wallace/optout/DEFER/tmpIv7pDl): 'Thu, 08 Mar 2012 11:51:03 +0000'
+    #(2012, 3, 8, 11, 51, 3, 0, 1, -1)
+    # YYYY M D H m s weekday, yearday
+
+    #log.debug(datetime.datetime(*), level=8)
+
+    #import os
+    #stat = os.stat(filepath)
+
+    #fileage = datetime.datetime.fromtimestamp(stat.st_mtime)
+    #now = datetime.datetime.now()
+    #delta = now - fileage
+
+    #print "file:", filepath, "fileage:", fileage, "now:", now, "delta(seconds):", delta.seconds
+
+    #if delta.seconds > 1800:
+        ## TODO: Send NDR back to user
+        #log.debug(_("Message in file %s older then 1800 seconds, deleting") % (filepath), level=8)
+        #os.unlink(filepath)
 
 def cb_action_REJECT(module, filepath):
-    log.info(_("Rejecting message in %s (by module %s)") %(filepath, module))
-    # Send NDR, unlink file
-    os.unlink(filepath)
+    log.info(_("Rejecting message in %s (by module %s)") % (filepath, module))
+
+    message = email.message_from_file(open(filepath, 'r'))
+    envelope_sender = email.utils.getaddresses(message.get_all('From', []))
+
+    recipients = email.utils.getaddresses(message.get_all('To', [])) + \
+            email.utils.getaddresses(message.get_all('Cc', []))
+
+    _recipients = []
+
+    for recipient in recipients:
+        if not recipient[0] == '':
+            _recipients.append('%s <%s>' % (recipient[0], recipient[1]))
+        else:
+            _recipients.append('%s' % (recipient[1]))
+
+    # TODO: Find the preferredLanguage for the envelope_sender user.
+    ndr_message_subject = "Undelivered Mail Returned to Sender"
+    ndr_message_text = _("""This is the email system Wallace at %s.
+
+I'm sorry to inform you we could not deliver the attached message
+to the following recipients:
+
+- %s
+
+Your message is being delivered to any other recipients you may have
+sent your message to. There is no need to resend the message to those
+recipients.
+""") % (
+        constants.fqdn,
+        "\n- ".join(_recipients)
+        )
+
+    diagnostics = _("""X-Wallace-Module: %s
+X-Wallace-Result: REJECT
+""") % (
+            module
+        )
+
+    msg = MIMEMultipart("report")
+    msg['From'] = "MAILER-DAEMON@%s" % (constants.fqdn)
+    msg['To'] = email.utils.formataddr(envelope_sender)
+    msg['Date'] = formatdate(localtime=True)
+    msg['Subject'] = ndr_message_subject
+
+    msg.preamble = "This is a MIME-encapsulated message."
+
+    part = MIMEText(ndr_message_text)
+    part.add_header("Content-Description", "Notification")
+    msg.attach(part)
+
+    _diag_message = email.message.Message()
+    _diag_message.set_payload(diagnostics)
+    part = MIMEMessage(_diag_message, "delivery-status")
+    part.add_header("Content-Description", "Delivery Report")
+    msg.attach(part)
+
+    part = MIMEMessage(message)
+    part.add_header("Content-Description", "Undelivered Message")
+    msg.attach(part)
+
+    smtp = smtplib.SMTP("localhost", 10027)
+
+    try:
+        smtp.sendmail(
+                "MAILER-DAEMON@%s" % (constants.fqdn),
+                [email.utils.formataddr(envelope_sender)],
+                msg.as_string()
+            )
+    except smtplib.SMTPDataError, errmsg:
+        # DEFER
+        pass
+    except smtplib.SMTPHeloError, errmsg:
+        # DEFER
+        pass
+    except smtplib.SMTPRecipientsRefused, errmsg:
+        # REJECT, send NDR
+        pass
+    except smtplib.SMTPSenderRefused, errmsg:
+        # REJECT, send NDR
+        pass
+    finally:
+        os.unlink(filepath)
 
 def cb_action_ACCEPT(module, filepath):
-    log.info(_("Accepting message in %s (by module %s)") %(filepath, module))
-    # Deliver for final delivery (use re-injection smtpd), unlink file
-    os.unlink(filepath)
+    log.info(_("Accepting message in %s (by module %s)") % (filepath, module))
+    message = email.message_from_file(open(filepath, 'r'))
+    envelope_sender = email.utils.getaddresses(message.get_all('From', []))
+
+    recipients = email.utils.getaddresses(message.get_all('To', [])) + \
+            email.utils.getaddresses(message.get_all('Cc', []))
+
+    smtp = smtplib.SMTP("localhost", 10027)
+
+    try:
+        smtp.sendmail(
+                email.utils.formataddr(envelope_sender),
+                COMMASPACE.join(
+                        [email.utils.formataddr(recipient) for recipient in recipients]
+                    ),
+                message.as_string()
+            )
+    except smtplib.SMTPDataError, errmsg:
+        # DEFER
+        pass
+    except smtplib.SMTPHeloError, errmsg:
+        # DEFER
+        pass
+    except smtplib.SMTPRecipientsRefused, errmsg:
+        # DEFER
+        pass
+    except smtplib.SMTPSenderRefused, errmsg:
+        # DEFER
+        pass
+    finally:
+        os.unlink(filepath)
 
 def register_group(dirname, module):
     modules_base_path = os.path.join(os.path.dirname(__file__), module)
@@ -129,13 +285,13 @@ def register_group(dirname, module):
             if filename.startswith('module_') and filename.endswith('.py'):
                 module_name = filename.replace('.py','')
                 name = module_name.replace('module_', '')
-                #print "exec(\"from %s.%s import __init__ as %s_%s_register\"" %(module,module_name,module,name)
-                exec("from %s.%s import __init__ as %s_%s_register" %(module,module_name,module,name))
-                exec("%s_%s_register()" %(module,name))
+                #print "exec(\"from %s.%s import __init__ as %s_%s_register\"" % (module,module_name,module,name)
+                exec("from %s.%s import __init__ as %s_%s_register" % (module,module_name,module,name))
+                exec("%s_%s_register()" % (module,name))
 
 def register(name, func, group=None, description=None, aliases=[]):
     if not group == None:
-        module = "%s_%s" %(group,name)
+        module = "%s_%s" % (group,name)
     else:
         module = name
 
@@ -143,7 +299,7 @@ def register(name, func, group=None, description=None, aliases=[]):
         aliases = [aliases]
 
     if modules.has_key(module):
-        log.fatal(_("Module '%s' already registered") %(module))
+        log.fatal(_("Module '%s' already registered") % (module))
         sys.exit(1)
 
     if callable(func):
@@ -165,6 +321,6 @@ def register(name, func, group=None, description=None, aliases=[]):
         for alias in aliases:
             modules[alias] = {
                     'function': func,
-                    'description': _("Alias for %s") %(name)
+                    'description': _("Alias for %s") % (name)
                 }
 


commit 61714a5e0d99ba1bc08eeac7f0ead106d72abae3
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Fri Mar 9 10:37:49 2012 +0000

    Correct some pylint conventions

diff --git a/pykolab/auth/__init__.py b/pykolab/auth/__init__.py
index 66eb993..36e9600 100644
--- a/pykolab/auth/__init__.py
+++ b/pykolab/auth/__init__.py
@@ -104,7 +104,7 @@ class Auth(object):
             domain = self.secondary_domains[domain]
 
         log.debug(
-                _("Connecting to Authentication backend for domain %s") %(
+                _("Connecting to Authentication backend for domain %s") % (
                         domain
                     ),
                 level=8
@@ -150,7 +150,7 @@ class Auth(object):
         if self.secondary_domains.has_key(domain):
             log.debug(
                     _("Using primary domain %s instead of secondary domain %s")
-                    %(
+                    % (
                             self.secondary_domains[domain],
                             domain
                         ),
@@ -167,7 +167,7 @@ class Auth(object):
         if self.secondary_domains.has_key(domain):
             log.debug(
                     _("Using primary domain %s instead of secondary domain %s")
-                    %(
+                    % (
                             self.secondary_domains[domain],
                             domain
                         ),
diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py
index 727c395..ae06a5f 100644
--- a/pykolab/auth/ldap/__init__.py
+++ b/pykolab/auth/ldap/__init__.py
@@ -107,13 +107,13 @@ class LDAP(object):
 
     def _authenticate(self, login, domain):
         log.debug(_("Attempting to authenticate user %s in domain %s")
-            %(login, domain), level=8)
+            % (login, domain), level=8)
 
         self._connect()
         user_dn = self._find_dn(login[0], domain)
         try:
             log.debug(_("Binding with user_dn %s and password %s")
-                %(user_dn, login[1]))
+                % (user_dn, login[1]))
 
             # Needs to be synchronous or succeeds and continues setting retval
             # to True!!
@@ -121,7 +121,7 @@ class LDAP(object):
             retval = True
         except:
             log.debug(
-                    _("Failed to authenticate as user %s") %(user_dn),
+                    _("Failed to authenticate as user %s") % (user_dn),
                     level=8
                 )
 
@@ -144,7 +144,7 @@ class LDAP(object):
             key = 'uri'
 
         if conf.has_option(domain, 'uri'):
-            log.warning(_("Deprecation: Setting 'uri' for LDAP in section %s needs to be updated to 'ldap_uri'") %(domain))
+            log.warning(_("Deprecation: Setting 'uri' for LDAP in section %s needs to be updated to 'ldap_uri'") % (domain))
             section = domain
             key = 'uri'
         elif conf.has_option(domain, 'ldap_uri'):
@@ -155,7 +155,7 @@ class LDAP(object):
 
         uri = conf.get(section, key)
 
-        log.debug(_("Attempting to use LDAP URI %s") %(uri), level=8)
+        log.debug(_("Attempting to use LDAP URI %s") % (uri), level=8)
 
         trace_level = 0
 
@@ -241,7 +241,7 @@ class LDAP(object):
                         _("Deprecation warning: The setting " + \
                             "kolab_smtp_access_policy.address_search_attrs " + \
                             "is to be replaced with the 'auth_attrs' key in " + \
-                            "the 'ldap' or '%s' domain section.") %(domain)
+                            "the 'ldap' or '%s' domain section.") % (domain)
                     )
 
                 auth_search_attrs = conf.get_list(
@@ -260,14 +260,14 @@ class LDAP(object):
         auth_search_filter = [ '(|' ]
 
         for auth_search_attr in auth_search_attrs:
-            auth_search_filter.append('(%s=%s)' %(auth_search_attr,login))
-            auth_search_filter.append('(%s=%s@%s)' %(auth_search_attr,login,domain))
+            auth_search_filter.append('(%s=%s)' % (auth_search_attr,login))
+            auth_search_filter.append('(%s=%s@%s)' % (auth_search_attr,login,domain))
 
         auth_search_filter.append(')')
 
         auth_search_filter = ''.join(auth_search_filter)
 
-        search_filter = "(&%s%s)" %(
+        search_filter = "(&%s%s)" % (
                 auth_search_filter,
                 user_filter
             )
@@ -285,7 +285,7 @@ class LDAP(object):
             # Retry to find the user_dn with just uid=%s against the root_dn,
             # if the login is not fully qualified
             if len(login.split('@')) < 2:
-                search_filter = "(uid=%s)" %(login)
+                search_filter = "(uid=%s)" % (login)
                 _results = self._search(
                         domain,
                         filterstr=search_filter,
@@ -320,20 +320,20 @@ class LDAP(object):
             user_base_dn = conf.get_raw(
                     section,
                     'user_base_dn'
-                ) %({'base_dn': domain_root_dn})
+                ) % ({'base_dn': domain_root_dn})
         else:
             user_base_dn = base_dn
 
         if type(attr) == str:
-            search_filter = "(%s=%s)" %(
+            search_filter = "(%s=%s)" % (
                     attr,
                     value
                 )
         elif type(attr) == list:
             search_filter = "(|"
             for _attr in attr:
-                search_filter = "%s(%s=%s)" %(search_filter, _attr, value)
-            search_filter = "%s)" %(search_filter)
+                search_filter = "%s(%s=%s)" % (search_filter, _attr, value)
+            search_filter = "%s)" % (search_filter)
 
         if additional_filter:
             search_filter = additional_filter % {
@@ -341,7 +341,7 @@ class LDAP(object):
                 }
 
         log.debug(
-                _("Attempting to find the user with search filter: %s") %(
+                _("Attempting to find the user with search filter: %s") % (
                         search_filter
                     ),
                 level=8
@@ -379,20 +379,20 @@ class LDAP(object):
             user_base_dn = conf.get_raw(
                     section,
                     'user_base_dn'
-                ) %({'base_dn': domain_root_dn})
+                ) % ({'base_dn': domain_root_dn})
         else:
             user_base_dn = base_dn
 
         if type(attr) == str:
-            search_filter = "(%s=%s)" %(
+            search_filter = "(%s=%s)" % (
                     attr,
                     value
                 )
         elif type(attr) == list:
             search_filter = "(|"
             for _attr in attr:
-                search_filter = "%s(%s=%s)" %(search_filter, _attr, value)
-            search_filter = "%s)" %(search_filter)
+                search_filter = "%s(%s=%s)" % (search_filter, _attr, value)
+            search_filter = "%s)" % (search_filter)
 
         if additional_filter:
             search_filter = additional_filter % {
@@ -400,7 +400,7 @@ class LDAP(object):
                 }
 
         log.debug(
-                _("Attempting to find entries with search filter: %s") %(
+                _("Attempting to find entries with search filter: %s") % (
                         search_filter
                     ),
                 level=8
@@ -471,8 +471,8 @@ class LDAP(object):
 
             for dn,entry,srv_ctrls in res_data:
                 log.debug(_("LDAP Search Result Data Entry:"), level=8)
-                log.debug("    DN: %r" %(dn), level=8)
-                log.debug("    Entry: %r" %(entry), level=8)
+                log.debug("    DN: %r" % (dn), level=8)
+                log.debug("    Entry: %r" % (entry), level=8)
 
                 ecn_ctrls = [
                         c for c in srv_ctrls
@@ -491,7 +491,7 @@ class LDAP(object):
                         )
 
                     log.debug(
-                            "    " + _("Change Type: %r (%r)") %(
+                            "    " + _("Change Type: %r (%r)") % (
                                     change_type,
                                     change_type_desc
                                 ),
@@ -499,7 +499,7 @@ class LDAP(object):
                         )
 
                     log.debug(
-                            "    " + _("Previous DN: %r") %(previous_dn),
+                            "    " + _("Previous DN: %r") % (previous_dn),
                             level=8
                         )
 
@@ -553,7 +553,7 @@ class LDAP(object):
                     ) = self.ldap.result3(_search)
 
             except ldap.NO_SUCH_OBJECT, e:
-                log.warning(_("Object %s searched no longer exists") %(base_dn))
+                log.warning(_("Object %s searched no longer exists") % (base_dn))
                 break
 
             if callback:
@@ -565,7 +565,7 @@ class LDAP(object):
 
             _results.extend(_result_data)
             if (pages % 2) == 0:
-                log.debug(_("%d results...") %(len(_results)))
+                log.debug(_("%d results...") % (len(_results)))
 
             pctrls = [
                     c for c in _result_controls
@@ -699,7 +699,7 @@ class LDAP(object):
         if len(self.ldap.supported_controls) < 1:
             for control_num in SUPPORTED_LDAP_CONTROLS.keys():
                 log.debug(
-                        _("Checking for support for %s") %(
+                        _("Checking for support for %s") % (
                                 SUPPORTED_LDAP_CONTROLS[control_num]['desc']
                             ),
                         level=8
@@ -739,7 +739,7 @@ class LDAP(object):
                     callback=callback,
                     primary_domain=%r,
                     secondary_domains=%r
-                )""" %(
+                )""" % (
                         supported_control,
                         base_dn,
                         scope,
@@ -777,7 +777,7 @@ class LDAP(object):
         attribute = attribute.lower()
 
         log.debug(
-                _("Getting attribute %s for user %s") %(attribute,user),
+                _("Getting attribute %s for user %s") % (attribute,user),
                 level=8
             )
 
@@ -801,7 +801,7 @@ class LDAP(object):
             (user_dn, user_attrs) = _result_data[0]
         else:
             log.warning(_("Could not get attribute %s for user %s")
-                %(attribute,user['dn']))
+                % (attribute,user['dn']))
 
             return None
 
@@ -810,7 +810,7 @@ class LDAP(object):
         if not user_attrs.has_key(attribute):
             log.debug(
                     _("Wanted attribute %s, which does not exist for user " + \
-                    "%r") %(
+                    "%r") % (
                             attribute,
                             user_dn
                         ),
@@ -838,7 +838,7 @@ class LDAP(object):
                 domain_root_dn,
                 ldap.SCOPE_SUBTREE,
                 # TODO: Configurable
-                '(|(mail=%s)(mailalternateaddress=%s))' %(
+                '(|(mail=%s)(mailalternateaddress=%s))' % (
                         mail_address,
                         mail_address
                     ),
@@ -886,7 +886,7 @@ class LDAP(object):
         except:
             log.warning(
                     _("LDAP modification of attribute %s for %s to value " + \
-                    "%s failed") %(attribute,user_dn,value)
+                    "%s failed") % (attribute,user_dn,value)
                 )
 
     def _list_domains(self):
@@ -952,7 +952,7 @@ class LDAP(object):
     def _kolab_domain_root_dn(self, domain):
         self._bind()
 
-        log.debug(_("Finding domain root dn for domain %s") %(domain), level=8)
+        log.debug(_("Finding domain root dn for domain %s") % (domain), level=8)
 
         bind_dn = conf.get('ldap', 'bind_dn')
         bind_pw = conf.get('ldap', 'bind_pw')
@@ -967,7 +967,7 @@ class LDAP(object):
             _results = self._search(
                     domain_base_dn,
                     ldap.SCOPE_SUBTREE,
-                    "(%s=%s)" %(domain_name_attribute,domain),
+                    "(%s=%s)" % (domain_name_attribute,domain),
                     override_search='_regular_search'
                 )
 
@@ -994,7 +994,7 @@ class LDAP(object):
         self._initial_sync_done = False
 
         log.info(_("Listing users for domain %s (and %s)")
-            %(primary_domain, ', '.join(secondary_domains)))
+            % (primary_domain, ', '.join(secondary_domains)))
 
         self._bind()
 
@@ -1014,7 +1014,7 @@ class LDAP(object):
         user_base_dn = conf.get_raw(
                 section,
                 'user_base_dn'
-            ) %({'base_dn': domain_root_dn})
+            ) % ({'base_dn': domain_root_dn})
 
         if conf.has_option(primary_domain, 'kolab_user_filter'):
             section = primary_domain
@@ -1034,7 +1034,7 @@ class LDAP(object):
             kolab_user_scope = LDAP_SCOPE[_kolab_user_scope]
         else:
             log.warning(
-                    _("LDAP Search scope %s not found, using 'sub'") %(
+                    _("LDAP Search scope %s not found, using 'sub'") % (
                             _kolab_user_scope
                         )
                 )
@@ -1051,8 +1051,8 @@ class LDAP(object):
         try:
             self.ldap.simple_bind_s(bind_dn, bind_pw)
         except ldap.SERVER_DOWN, e:
-            error = eval("%s" %(e))
-            log.error(_("Error binding to LDAP: %s") %(error['desc']))
+            error = eval("%s" % (e))
+            log.error(_("Error binding to LDAP: %s") % (error['desc']))
             # TODO: Exit the fork (if fork!)
             return
 
@@ -1077,10 +1077,10 @@ class LDAP(object):
             )
 
         if callback == None:
-            log.info(_("Found %d users") %(len(_search)))
+            log.info(_("Found %d users") % (len(_search)))
 
             log.debug(_("Iterating over %d users, making sure we have the " + \
-                "necessary attributes...") %(len(_search)), level=6)
+                "necessary attributes...") % (len(_search)), level=6)
 
             users = []
 
@@ -1106,7 +1106,7 @@ class LDAP(object):
                 if (num_user % 1000) == 0:
                     log.debug(
                             _("Done iterating over user %d of %d")
-                                %(num_user,num_users),
+                                % (num_user,num_users),
                             level=3
                         )
 
@@ -1189,7 +1189,7 @@ class LDAP(object):
                 # or 1 (which should be the entry we're looking at here)
                 if len(results) == 0:
                     log.debug(
-                            _("No results for mail address %s found") %(
+                            _("No results for mail address %s found") % (
                                     _primary_mail
                                 ),
                             level=8
@@ -1200,7 +1200,7 @@ class LDAP(object):
 
                 if len(results) == 1:
                     log.debug(
-                            _("1 result for address %s found, verifying") %(
+                            _("1 result for address %s found, verifying") % (
                                     _primary_mail
                                 ),
                             level=8
@@ -1211,7 +1211,7 @@ class LDAP(object):
                         if not result[0] == user['dn']:
                             log.debug(
                                     _("Too bad, primary email address %s " + \
-                                    "already in use for %s (we are %s)") %(
+                                    "already in use for %s (we are %s)") % (
                                             _primary_mail,
                                             result[0],
                                             user['dn']
@@ -1226,7 +1226,7 @@ class LDAP(object):
                         continue
 
                 i += 1
-                _primary_mail = "%s%d@%s" %(
+                _primary_mail = "%s%d@%s" % (
                         primary_mail.split('@')[0],
                         i,
                         primary_mail.split('@')[1]
@@ -1289,7 +1289,7 @@ class LDAP(object):
                         # or 1 (which should be the entry we're looking at here)
                         if len(results) == 0:
                             log.debug(
-                                    _("No results for address %s found") %(
+                                    _("No results for address %s found") % (
                                             __secondary_mail
                                         ),
                                     level=8
@@ -1301,7 +1301,7 @@ class LDAP(object):
                         if len(results) == 1:
                             log.debug(
                                     _("1 result for address %s found, " + \
-                                    "verifying...") %(
+                                    "verifying...") % (
                                             __secondary_mail
                                         ),
                                     level=8
@@ -1313,7 +1313,7 @@ class LDAP(object):
                                     log.debug(
                                             _("Too bad, secondary email " + \
                                             "address %s already in use for " + \
-                                            "%s (we are %s)") %(
+                                            "%s (we are %s)") % (
                                                     __secondary_mail,
                                                     result[0],
                                                     user['dn']
@@ -1328,7 +1328,7 @@ class LDAP(object):
                                 continue
 
                         i += 1
-                        __secondary_mail = "%s%d@%s" %(
+                        __secondary_mail = "%s%d@%s" % (
                                 _secondary_mail.split('@')[0],
                                 i,
                                 _secondary_mail.split('@')[1]
@@ -1437,7 +1437,7 @@ class LDAP(object):
 
             elif kw['change_type'] == 2:
                 # TODO: Use Cyrus SASL authorization ID
-                folder = 'user/%s' %(user['mail'].lower())
+                folder = 'user/%s' % (user['mail'].lower())
                 # TODO: Verify if folder exists
                 pykolab.imap.delete_mailfolder(folder)
                 done = True
diff --git a/pykolab/cli/cmd_export_mailbox.py b/pykolab/cli/cmd_export_mailbox.py
index eab89d0..2e0875c 100644
--- a/pykolab/cli/cmd_export_mailbox.py
+++ b/pykolab/cli/cmd_export_mailbox.py
@@ -68,7 +68,7 @@ def execute(*args, **kw):
         )
 
     mboxlist_proc = subprocess.Popen(
-            ['grep', '-E', '\s*%s\s*.*i.*p.*' %(user)],
+            ['grep', '-E', '\s*%s\s*.*i.*p.*' % (user)],
             stdin=ctl_mboxlist.stdout,
             stdout=subprocess.PIPE
         )
@@ -78,7 +78,7 @@ def execute(*args, **kw):
     # TODO: Handle errors from ctl_mboxlist process (stderr)
     mboxlist_output = mboxlist_proc.communicate()[0]
 
-    zipper_args = [ 'zip', '-r', '%s.zip' %(user) ]
+    zipper_args = [ 'zip', '-r', '%s.zip' % (user) ]
     directories = []
 
     for mbox_internal in mboxlist_output.split('\n'):
@@ -95,7 +95,7 @@ def execute(*args, **kw):
                 )
 
             for partition in partitions:
-                mbox_dir = '%s/domain/%s/%s/%s/user/%s/' %(
+                mbox_dir = '%s/domain/%s/%s/%s/user/%s/' % (
                         partition,
                         domain[0],
                         domain,
@@ -108,7 +108,7 @@ def execute(*args, **kw):
 
                 else:
                     log.debug(
-                            _('%s is not a directory') %(mbox_dir),
+                            _('%s is not a directory') % (mbox_dir),
                             level=5
                         )
 
@@ -118,8 +118,8 @@ def execute(*args, **kw):
                 stdout=subprocess.PIPE
             ).communicate()[0]
 
-        print >> sys.stderr, _("ZIP file at %s.zip") %(user)
+        print >> sys.stderr, _("ZIP file at %s.zip") % (user)
     else:
-        print >> sys.stderr, _("No directories found for user %s") %(user)
+        print >> sys.stderr, _("No directories found for user %s") % (user)
         sys.exit(1)
 
diff --git a/pykolab/cli/cmd_list_domains.py b/pykolab/cli/cmd_list_domains.py
index 0bc2d27..cf12ee4 100644
--- a/pykolab/cli/cmd_list_domains.py
+++ b/pykolab/cli/cmd_list_domains.py
@@ -38,7 +38,7 @@ def execute(*args, **kw):
 
     #print "domains:", domains['list']
 
-    print "%-39s %-40s" %("Primary Domain Name Space","Secondary Domain Name Space(s)")
+    print "%-39s %-40s" % ("Primary Domain Name Space","Secondary Domain Name Space(s)")
 
     # TODO: Take a hint in --quiet, and otherwise print out a nice table
     # with headers and such.
@@ -46,6 +46,6 @@ def execute(*args, **kw):
         if isinstance(domains['list'][domain_dn]['associateddomain'], list):
             print domains['list'][domain_dn]['associateddomain'][0]
             for domain_alias in domains['list'][domain_dn]['associateddomain'][1:]:
-                print "%-39s %-40s" %('', domain_alias)
+                print "%-39s %-40s" % ('', domain_alias)
         else:
             print domains['list'][domain_dn]['associateddomain']
diff --git a/pykolab/cli/cmd_list_mailboxes.py b/pykolab/cli/cmd_list_mailboxes.py
index ae0444e..547eb74 100644
--- a/pykolab/cli/cmd_list_mailboxes.py
+++ b/pykolab/cli/cmd_list_mailboxes.py
@@ -31,7 +31,7 @@ imap = pykolab.imap
 
 def __init__():
     commands.register('list_mailboxes', execute, description="List mailboxes.\n" + \
-        "%-28s" %('') + \
+        "%-28s" % ('') + \
         "Use wildcards '*' and '%' for more control.\n")
 
 def cli_options():
diff --git a/pykolab/cli/cmd_sync.py b/pykolab/cli/cmd_sync.py
index 14dd87d..348c010 100644
--- a/pykolab/cli/cmd_sync.py
+++ b/pykolab/cli/cmd_sync.py
@@ -38,7 +38,7 @@ def execute(*args, **kw):
     domains = auth.list_domains()
     end_time = time.time()
     log.debug(
-            _("Found %d domains in %d seconds") %(
+            _("Found %d domains in %d seconds") % (
                     len(domains),
                     (end_time-start_time)
                 ),
@@ -48,13 +48,13 @@ def execute(*args, **kw):
     all_folders = []
 
     for primary_domain,secondary_domains in domains:
-        log.debug(_("Running for domain %s") %(primary_domain), level=8)
+        log.debug(_("Running for domain %s") % (primary_domain), level=8)
         auth.connect(primary_domain)
         start_time = time.time()
         auth.synchronize(primary_domain, secondary_domains)
         end_time = time.time()
 
         log.info(_("Synchronizing users for %s took %d seconds")
-                %(primary_domain, (end_time-start_time))
+                % (primary_domain, (end_time-start_time))
             )
 
diff --git a/pykolab/cli/cmd_transfer_mailbox.py b/pykolab/cli/cmd_transfer_mailbox.py
index 4f0de09..e7a7acc 100644
--- a/pykolab/cli/cmd_transfer_mailbox.py
+++ b/pykolab/cli/cmd_transfer_mailbox.py
@@ -51,7 +51,7 @@ def execute(*args, **kw):
     if mbox_parts['domain'] == None:
         user_identifier = mbox_parts['path_parts'][1]
     else:
-        user_identifier = "%s@%s" %(mbox_parts['path_parts'][1], mbox_parts['domain'])
+        user_identifier = "%s@%s" % (mbox_parts['path_parts'][1], mbox_parts['domain'])
 
     print "User Identifier:", user_identifier
 
diff --git a/pykolab/cli/commands.py b/pykolab/cli/commands.py
index ea083ed..7236b0b 100644
--- a/pykolab/cli/commands.py
+++ b/pykolab/cli/commands.py
@@ -42,9 +42,9 @@ def __init__():
             if filename.startswith('cmd_') and filename.endswith('.py'):
                 module_name = filename.replace('.py','')
                 cmd_name = module_name.replace('cmd_', '')
-                #print "exec(\"from %s import __init__ as %s_register\"" %(module_name,cmd_name)
-                exec("from %s import __init__ as %s_register" %(module_name,cmd_name))
-                exec("%s_register()" %(cmd_name))
+                #print "exec(\"from %s import __init__ as %s_register\"" % (module_name,cmd_name)
+                exec("from %s import __init__ as %s_register" % (module_name,cmd_name))
+                exec("%s_register()" % (cmd_name))
 
         for dirname in dirnames:
             register_group(commands_path, dirname)
@@ -85,21 +85,21 @@ def list_commands(*args, **kw):
         if __commands[_command].has_key('function'):
             # This is a top-level command
             if not __commands[_command]['description'] == None:
-                print "%-25s - %s" %(_command.replace('_','-'),__commands[_command]['description'])
+                print "%-25s - %s" % (_command.replace('_','-'),__commands[_command]['description'])
             else:
-                print "%-25s" %(_command.replace('_','-'))
+                print "%-25s" % (_command.replace('_','-'))
 
     for _command in _commands:
         if not __commands[_command].has_key('function'):
             # This is a nested command
-            print "\n" + _("Command Group: %s") %(_command) + "\n"
+            print "\n" + _("Command Group: %s") % (_command) + "\n"
             ___commands = __commands[_command].keys()
             ___commands.sort()
             for __command in ___commands:
                 if not __commands[_command][__command]['description'] == None:
-                    print "%-4s%-21s - %s" %('',__command.replace('_','-'),__commands[_command][__command]['description'])
+                    print "%-4s%-21s - %s" % ('',__command.replace('_','-'),__commands[_command][__command]['description'])
                 else:
-                    print "%-4s%-21s" %('',__command.replace('_','-'))
+                    print "%-4s%-21s" % ('',__command.replace('_','-'))
 
 def execute(cmd_name, *args, **kw):
     if not commands.has_key(cmd_name):
@@ -115,15 +115,15 @@ def execute(cmd_name, *args, **kw):
         group = commands[cmd_name]['group']
         command_name = commands[cmd_name]['cmd_name']
         try:
-            exec("from %s.cmd_%s import cli_options as %s_%s_cli_options" %(group,command_name,group,command_name))
-            exec("%s_%s_cli_options()" %(group,command_name))
+            exec("from %s.cmd_%s import cli_options as %s_%s_cli_options" % (group,command_name,group,command_name))
+            exec("%s_%s_cli_options()" % (group,command_name))
         except ImportError, e:
             pass
 
     else:
         try:
-            exec("from cmd_%s import cli_options as %s_cli_options" %(cmd_name,cmd_name))
-            exec("%s_cli_options()" %(cmd_name))
+            exec("from cmd_%s import cli_options as %s_cli_options" % (cmd_name,cmd_name))
+            exec("%s_cli_options()" % (cmd_name))
         except ImportError, e:
             pass
 
@@ -144,13 +144,13 @@ def register_group(dirname, module):
             if filename.startswith('cmd_') and filename.endswith('.py'):
                 module_name = filename.replace('.py','')
                 cmd_name = module_name.replace('cmd_', '')
-                #print "exec(\"from %s.%s import __init__ as %s_%s_register\"" %(module,module_name,module,cmd_name)
-                exec("from %s.%s import __init__ as %s_%s_register" %(module,module_name,module,cmd_name))
-                exec("%s_%s_register()" %(module,cmd_name))
+                #print "exec(\"from %s.%s import __init__ as %s_%s_register\"" % (module,module_name,module,cmd_name)
+                exec("from %s.%s import __init__ as %s_%s_register" % (module,module_name,module,cmd_name))
+                exec("%s_%s_register()" % (module,cmd_name))
 
 def register(cmd_name, func, group=None, description=None, aliases=[]):
     if not group == None:
-        command = "%s_%s" %(group,cmd_name)
+        command = "%s_%s" % (group,cmd_name)
     else:
         command = cmd_name
 
@@ -158,7 +158,7 @@ def register(cmd_name, func, group=None, description=None, aliases=[]):
         aliases = [aliases]
 
     if commands.has_key(command):
-        log.fatal(_("Command '%s' already registered") %(command))
+        log.fatal(_("Command '%s' already registered") % (command))
         sys.exit(1)
 
     if callable(func):
@@ -180,7 +180,7 @@ def register(cmd_name, func, group=None, description=None, aliases=[]):
         for alias in aliases:
             commands[alias] = {
                     'function': func,
-                    'description': _("Alias for %s") %(cmd_name)
+                    'description': _("Alias for %s") % (cmd_name)
                 }
 
 ##
diff --git a/pykolab/cli/telemetry/cmd_examine_command_issue.py b/pykolab/cli/telemetry/cmd_examine_command_issue.py
index f4248a0..fc8d3f7 100644
--- a/pykolab/cli/telemetry/cmd_examine_command_issue.py
+++ b/pykolab/cli/telemetry/cmd_examine_command_issue.py
@@ -75,7 +75,7 @@ def execute(*args, **kw):
                 id=session.server_id
             ).first()
 
-    print _("Session by %s on server %s") %(user.sasl_username,server.fqdn)
+    print _("Session by %s on server %s") % (user.sasl_username,server.fqdn)
 
     command_issues = db.query(
             telemetry.TelemetryCommandIssue
@@ -99,7 +99,7 @@ def execute(*args, **kw):
         if command_issue.id == _command_issue.id:
             print "========="
 
-        print "Client(%d): %s %s %s" %(
+        print "Client(%d): %s %s %s" % (
                 _command_issue.id,
                 _command_issue.command_tag,
                 command.command,
@@ -116,7 +116,7 @@ def execute(*args, **kw):
             server_response_lines = server_response.response.split('\n');
 
             for server_response_line in server_response_lines:
-                print "Server(%d): %s" %(
+                print "Server(%d): %s" % (
                         server_response.id,
                         server_response_line
                     )
diff --git a/pykolab/cli/telemetry/cmd_examine_session.py b/pykolab/cli/telemetry/cmd_examine_session.py
index a1273fd..38dac94 100644
--- a/pykolab/cli/telemetry/cmd_examine_session.py
+++ b/pykolab/cli/telemetry/cmd_examine_session.py
@@ -100,7 +100,7 @@ def execute(*args, **kw):
 
         return
 
-    print _("Session by %s on server %s") %(user.sasl_username,server.fqdn)
+    print _("Session by %s on server %s") % (user.sasl_username,server.fqdn)
 
     command_issues = db.query(
             telemetry.TelemetryCommandIssue
@@ -121,7 +121,7 @@ def execute(*args, **kw):
                     id=command_issue.command_arg_id
                 ).first()
 
-        print "Client(%d): %s %s %s" %(
+        print "Client(%d): %s %s %s" % (
                 command_issue.id,
                 command_issue.command_tag,
                 command.command,
@@ -137,7 +137,7 @@ def execute(*args, **kw):
         for server_response in server_responses:
             server_response_lines = server_response.response.split('\n');
             for server_response_line in server_response_lines:
-                print "Server(%d): %s" %(
+                print "Server(%d): %s" % (
                         server_response.id,
                         server_response_line
                     )
diff --git a/pykolab/cli/telemetry/cmd_list_sessions.py b/pykolab/cli/telemetry/cmd_list_sessions.py
index 1f6503e..c90ef9d 100644
--- a/pykolab/cli/telemetry/cmd_list_sessions.py
+++ b/pykolab/cli/telemetry/cmd_list_sessions.py
@@ -58,7 +58,7 @@ def execute(*args, **kw):
                     id=session.user_id
                 ).first()
 
-        print _("Session for user %s started at %s with ID %s") %(
+        print _("Session for user %s started at %s with ID %s") % (
                 user.sasl_username,
                 session.start,
                 session.id
diff --git a/pykolab/conf/__init__.py b/pykolab/conf/__init__.py
index 01282f2..7d850b6 100644
--- a/pykolab/conf/__init__.py
+++ b/pykolab/conf/__init__.py
@@ -82,7 +82,7 @@ class Conf(object):
 
         # But, they should be available in our class as well
         for option in self.defaults.__dict__.keys():
-            log.debug(_("Setting %s to %r (from defaults)") %(option, self.defaults.__dict__[option]), level=8)
+            log.debug(_("Setting %s to %r (from defaults)") % (option, self.defaults.__dict__[option]), level=8)
             setattr(self,option,self.defaults.__dict__[option])
 
         # This is where we check our parser for the defaults being set there.
@@ -94,17 +94,17 @@ class Conf(object):
         if hasattr(self,'cli_keywords') and not self.cli_keywords == None:
             for option in self.cli_keywords.__dict__.keys():
                 retval = False
-                if hasattr(self, "check_setting_%s" %(option)):
+                if hasattr(self, "check_setting_%s" % (option)):
                     exec("retval = self.check_setting_%s(%r)" % (option, self.cli_keywords.__dict__[option]))
 
                     # The warning, error or confirmation dialog is in the check_setting_%s() function
                     if not retval:
                         continue
 
-                    log.debug(_("Setting %s to %r (from CLI, verified)") %(option, self.cli_keywords.__dict__[option]), level=8)
+                    log.debug(_("Setting %s to %r (from CLI, verified)") % (option, self.cli_keywords.__dict__[option]), level=8)
                     setattr(self,option,self.cli_keywords.__dict__[option])
                 else:
-                    log.debug(_("Setting %s to %r (from CLI, not checked)") %(option, self.cli_keywords.__dict__[option]), level=8)
+                    log.debug(_("Setting %s to %r (from CLI, not checked)") % (option, self.cli_keywords.__dict__[option]), level=8)
                     setattr(self,option,self.cli_keywords.__dict__[option])
 
     def load_config(self, config):
@@ -136,8 +136,8 @@ class Conf(object):
                 elif isinstance(self.defaults.__dict__[section][key], dict):
                     value = eval(config.get(section,key))
 
-                if hasattr(self,"check_setting_%s_%s" %(section,key)):
-                    exec("retval = self.check_setting_%s_%s(%r)" %(section,key,value))
+                if hasattr(self,"check_setting_%s_%s" % (section,key)):
+                    exec("retval = self.check_setting_%s_%s(%r)" % (section,key,value))
                     if not retval:
                         # We just don't set it, check_setting_%s should have
                         # taken care of the error messages
@@ -145,10 +145,10 @@ class Conf(object):
 
                 if not self.defaults.__dict__[section][key] == value:
                     if key.count('password') >= 1:
-                        log.debug(_("Setting %s_%s to '****' (from configuration file)") %(section,key), level=8)
+                        log.debug(_("Setting %s_%s to '****' (from configuration file)") % (section,key), level=8)
                     else:
-                        log.debug(_("Setting %s_%s to %r (from configuration file)") %(section,key,value), level=8)
-                    setattr(self,"%s_%s" %(section,key),value)
+                        log.debug(_("Setting %s_%s to %r (from configuration file)") % (section,key,value), level=8)
+                    setattr(self,"%s_%s" % (section,key),value)
 
     def options_set_from_config(self):
         """
@@ -193,18 +193,18 @@ class Conf(object):
             elif isinstance(self.defaults.__dict__['testing'][key], dict):
                 value = eval(config.get('testing',key))
 
-            if hasattr(self,"check_setting_%s_%s" %('testing',key)):
+            if hasattr(self,"check_setting_%s_%s" % ('testing',key)):
                 exec("retval = self.check_setting_%s_%s(%r)" % ('testing',key,value))
                 if not retval:
                     # We just don't set it, check_setting_%s should have
                     # taken care of the error messages
                     continue
 
-            setattr(self,"%s_%s" %('testing',key),value)
+            setattr(self,"%s_%s" % ('testing',key),value)
             if key.count('password') >= 1:
-                log.debug(_("Setting %s_%s to '****' (from configuration file)") %('testing',key), level=8)
+                log.debug(_("Setting %s_%s to '****' (from configuration file)") % ('testing',key), level=8)
             else:
-                log.debug(_("Setting %s_%s to %r (from configuration file)") %('testing',key,value), level=8)
+                log.debug(_("Setting %s_%s to %r (from configuration file)") % ('testing',key,value), level=8)
 
     def check_config(self, val=None):
         """
@@ -345,21 +345,21 @@ class Conf(object):
 
         for item in items:
             mode = self.cfg_parser.get('kolab',item)
-            print "%s = %s" %(item,mode)
+            print "%s = %s" % (item,mode)
 
             if not self.cfg_parser.has_section(mode):
-                print "WARNING: No configuration section %s for item %s" %(mode,item)
+                print "WARNING: No configuration section %s for item %s" % (mode,item)
                 continue
 
             keys = self.cfg_parser.options(mode)
             keys.sort()
 
             if self.cfg_parser.has_option(mode, 'leave_this_one_to_me'):
-                print "Ignoring section %s" %(mode,)
+                print "Ignoring section %s" % (mode,)
                 continue
 
             for key in keys:
-                print "%s_%s = %s" %(mode, key ,self.cfg_parser.get(mode,key))
+                print "%s_%s = %s" % (mode, key ,self.cfg_parser.get(mode,key))
 
     def read_config(self, value=None):
         """
@@ -384,7 +384,7 @@ class Conf(object):
 
         exec("args = %r" % args)
 
-        print "%s/%s: %r" %(args[0],args[1],self.get(args[0], args[1]))
+        print "%s/%s: %r" % (args[0],args[1],self.get(args[0], args[1]))
 
 #        if len(args) == 3:
 #            # Return non-zero if no match
@@ -411,7 +411,7 @@ class Conf(object):
             log.error(_("Insufficient options. Need section, key and value -in that order."))
 
         if not self.cfg_parser.has_section(args[0]):
-            log.error(_("No section '%s' exists.") %(args[0]))
+            log.error(_("No section '%s' exists.") % (args[0]))
 
         self.cfg_parser.set(args[0], args[1], args[2])
         fp = open(self.cli_keywords.config_file, "w+")
@@ -442,7 +442,7 @@ class Conf(object):
 
         # But, they should be available in our class as well
         for option in self.cli_parser.defaults.keys():
-            log.debug(_("Setting %s to %r (from the default values for CLI options)") %(option, self.cli_parser.defaults[option]), level=8)
+            log.debug(_("Setting %s to %r (from the default values for CLI options)") % (option, self.cli_parser.defaults[option]), level=8)
             setattr(self,option,self.cli_parser.defaults[option])
 
     def has_section(self, section):
@@ -501,11 +501,11 @@ class Conf(object):
         if self.cfg_parser.has_option(section, key):
             return self.cfg_parser.get(section,key)
 
-        if hasattr(self, "get_%s_%s" %(section,key)):
+        if hasattr(self, "get_%s_%s" % (section,key)):
             try:
-                exec("retval = self.get_%s_%s(quiet)" %(section,key))
+                exec("retval = self.get_%s_%s(quiet)" % (section,key))
             except Exception, e:
-                log.error(_("Could not execute configuration function: %s") %("get_%s_%s(quiet=%r)" %(section,key,quiet)))
+                log.error(_("Could not execute configuration function: %s") % ("get_%s_%s(quiet=%r)" % (section,key,quiet)))
                 return None
 
             return retval
@@ -513,12 +513,12 @@ class Conf(object):
         if quiet:
             return ""
         else:
-            log.warning(_("Option %s/%s does not exist in config file %s, pulling from defaults") %(section, key, self.config_file))
-            if hasattr(self.defaults, "%s_%s" %(section,key)):
-                return getattr(self.defaults, "%s_%s" %(section,key))
-            elif hasattr(self.defaults, "%s" %(section)):
-                if key in getattr(self.defaults, "%s" %(section)):
-                    _dict = getattr(self.defaults, "%s" %(section))
+            log.warning(_("Option %s/%s does not exist in config file %s, pulling from defaults") % (section, key, self.config_file))
+            if hasattr(self.defaults, "%s_%s" % (section,key)):
+                return getattr(self.defaults, "%s_%s" % (section,key))
+            elif hasattr(self.defaults, "%s" % (section)):
+                if key in getattr(self.defaults, "%s" % (section)):
+                    _dict = getattr(self.defaults, "%s" % (section))
                     return _dict[key]
                 else:
                     log.warning(_("Option does not exist in defaults."))
@@ -534,10 +534,10 @@ class Conf(object):
                 self.config_file = value
                 return True
             else:
-                log.error(_("Configuration file %s not readable.") %(value))
+                log.error(_("Configuration file %s not readable.") % (value))
                 return False
         else:
-            log.error(_("Configuration file %s does not exist.") %(value))
+            log.error(_("Configuration file %s does not exist.") % (value))
             return False
 
     def check_setting_debuglevel(self, value):
@@ -607,7 +607,7 @@ class Conf(object):
             selectively = False
             for item in [ 'calendar', 'contacts', 'mail' ]:
                 if self.cli_keywords.__dict__[item]:
-                    log.debug(_("Found you specified a specific set of items to test: %s") %(item), level=8)
+                    log.debug(_("Found you specified a specific set of items to test: %s") % (item), level=8)
                     selectively = item
 
             if not selectively:
@@ -615,7 +615,7 @@ class Conf(object):
                 self.contacts = True
                 self.mail = True
             else:
-                log.debug(_("Selectively selecting: %s") %(selectively), level=8)
+                log.debug(_("Selectively selecting: %s") % (selectively), level=8)
                 setattr(self, selectively, True)
 
             self.test_suites.append('zpush')
diff --git a/pykolab/conf/entitlement.py b/pykolab/conf/entitlement.py
index 6a85711..54370c7 100644
--- a/pykolab/conf/entitlement.py
+++ b/pykolab/conf/entitlement.py
@@ -55,7 +55,7 @@ class Entitlement(object):
 
             if (bool)(ca_cert.has_expired()):
                 raise Exception, _("Invalid entitlement verification " + \
-                        "certificate at %s" %(ca_cert_file))
+                        "certificate at %s" % (ca_cert_file))
 
             # TODO: Check validity and warn ~1-2 months in advance.
 
@@ -78,7 +78,7 @@ class Entitlement(object):
 
             if not ca_cert_issuer_hash_digest in self.entitlement_verification:
                 raise Exception, _("Invalid entitlement verification " + \
-                        "certificate at %s") %(ca_cert_file)
+                        "certificate at %s") % (ca_cert_file)
 
             ca_cert_subject_hash = subprocess.Popen(
                     [
@@ -96,7 +96,7 @@ class Entitlement(object):
 
             if not ca_cert_subject_hash_digest in self.entitlement_verification:
                 raise Exception, _("Invalid entitlement verification " + \
-                        "certificate at %s") %(ca_cert_file)
+                        "certificate at %s") % (ca_cert_file)
 
             customer_cert_issuer_hash = subprocess.Popen(
                     [
@@ -114,7 +114,7 @@ class Entitlement(object):
 
             if not customer_cert_issuer_hash_digest in self.entitlement_verification:
                 raise Exception, _("Invalid entitlement verification " + \
-                        "certificate at %s") %(customer_cert_file)
+                        "certificate at %s") % (customer_cert_file)
 
             if not ca_cert_issuer.countryName == ca_cert_subject.countryName:
                 raise Exception, _("Invalid entitlement certificate")
@@ -129,7 +129,7 @@ class Entitlement(object):
                     if not root == '/etc/kolab/entitlement.d/':
                         continue
                     for entitlement_file in files:
-                        log.debug(_("Parsing entitlement file %s") %(entitlement_file), level=8)
+                        log.debug(_("Parsing entitlement file %s") % (entitlement_file), level=8)
 
                         if os.access(os.path.join(root, entitlement_file), os.R_OK):
                             self.entitlement_files.append(
@@ -138,7 +138,7 @@ class Entitlement(object):
 
                         else:
                             print >> sys.stderr, \
-                                    _("License file %s not readable!") %(
+                                    _("License file %s not readable!") % (
                                             os.path.join(root, entitlement_file)
                                         )
 
@@ -227,7 +227,7 @@ class License(object):
 
         if not customer_cert_serial == cert_serial:
             raise Exception, _("Invalid entitlement verification " + \
-                    "certificate at %s") %(customer_cert_file)
+                    "certificate at %s") % (customer_cert_file)
 
         customer_cert_issuer_hash = subprocess.Popen(
                 [
@@ -243,7 +243,7 @@ class License(object):
 
         if not customer_cert_issuer_hash == cert_issuer_hash:
             raise Exception, _("Invalid entitlement verification " + \
-                    "certificate at %s") %(customer_cert_file)
+                    "certificate at %s") % (customer_cert_file)
 
         customer_cert_subject_hash = subprocess.Popen(
                 [
@@ -259,7 +259,7 @@ class License(object):
 
         if not customer_cert_subject_hash == cert_subject_hash:
             raise Exception, _("Invalid entitlement verification " + \
-                    "certificate at %s") %(customer_cert_file)
+                    "certificate at %s") % (customer_cert_file)
 
     def get(self):
         return self.entitlement
diff --git a/pykolab/imap/__init__.py b/pykolab/imap/__init__.py
index da592c4..0c77a54 100644
--- a/pykolab/imap/__init__.py
+++ b/pykolab/imap/__init__.py
@@ -98,7 +98,7 @@ class IMAP(object):
                 self._imap[hostname] = cyrus.Cyrus(uri)
                 # Actually connect
                 if login:
-                    log.debug(_("Logging on to Cyrus IMAP server %s") %(hostname), level=8)
+                    log.debug(_("Logging on to Cyrus IMAP server %s") % (hostname), level=8)
                     self._imap[hostname].login(admin_login, admin_password)
                     self._imap[hostname].logged_in = True
 
@@ -107,7 +107,7 @@ class IMAP(object):
                 self._imap[hostname] = dovecot.Dovecot(uri)
                 # Actually connect
                 if login:
-                    log.debug(_("Logging on to Dovecot IMAP server %s") %(hostname), level=8)
+                    log.debug(_("Logging on to Dovecot IMAP server %s") % (hostname), level=8)
                     self._imap[hostname].login(admin_login, admin_password)
                     self._imap[hostname].logged_in = True
 
@@ -116,7 +116,7 @@ class IMAP(object):
                 self._imap[hostname] = imaplib.IMAP4(hostname, port)
                 # Actually connect
                 if login:
-                    log.debug(_("Logging on to generic IMAP server %s") %(hostname), level=8)
+                    log.debug(_("Logging on to generic IMAP server %s") % (hostname), level=8)
                     self._imap[hostname].login(admin_login, admin_password)
                     self._imap[hostname].logged_in = True
 
@@ -134,9 +134,9 @@ class IMAP(object):
                     elif hasattr(self._imap[hostname], 'noop') and callable(self._imap[hostname].noop):
                         self._imap[hostname].noop()
 
-                    log.debug(_("Reusing existing IMAP server connection to %s") %(hostname), level=8)
+                    log.debug(_("Reusing existing IMAP server connection to %s") % (hostname), level=8)
                 except:
-                    log.debug(_("Reconnecting to IMAP server %s") %(hostname), level=8)
+                    log.debug(_("Reconnecting to IMAP server %s") % (hostname), level=8)
                     self.disconnect(hostname)
                     self.connect()
 
@@ -159,11 +159,11 @@ class IMAP(object):
         if hasattr(self.imap, name):
             return getattr(self.imap, name)
         else:
-            raise AttributeError, _("%r has no attribute %s") %(self,name)
+            raise AttributeError, _("%r has no attribute %s") % (self,name)
 
     def has_folder(self, folder):
         folders = self.imap.lm(folder)
-        log.debug(_("Looking for folder '%s', we found folders: %r") %(folder,folders), level=8)
+        log.debug(_("Looking for folder '%s', we found folders: %r") % (folder,folders), level=8)
         # Greater then one, this folder may have subfolders.
         if len(folders) > 0:
             return True
@@ -176,20 +176,20 @@ class IMAP(object):
         for user in users:
             if type(user) == dict:
                 if user.has_key('old_mail'):
-                    inbox = "user/%s" %(user['mail'])
-                    old_inbox = "user/%s" %(user['old_mail'])
+                    inbox = "user/%s" % (user['mail'])
+                    old_inbox = "user/%s" % (user['old_mail'])
 
                     if self.has_folder(old_inbox):
-                        log.debug(_("Found old INBOX folder %s") %(old_inbox), level=8)
+                        log.debug(_("Found old INBOX folder %s") % (old_inbox), level=8)
 
                         if not self.has_folder(inbox):
-                            log.info(_("Renaming INBOX from %s to %s") %(old_inbox,inbox))
+                            log.info(_("Renaming INBOX from %s to %s") % (old_inbox,inbox))
                             self.imap.rename(old_inbox,inbox)
                             self.inbox_folders.append(inbox)
                         else:
-                            log.warning(_("Moving INBOX folder %s won't succeed as target folder %s already exists") %(old_inbox,inbox))
+                            log.warning(_("Moving INBOX folder %s won't succeed as target folder %s already exists") % (old_inbox,inbox))
                     else:
-                        log.debug(_("Did not find old folder user/%s to rename") %(user['old_mail']), level=8)
+                        log.debug(_("Did not find old folder user/%s to rename") % (user['old_mail']), level=8)
             else:
                 log.debug(_("Value for user is not a dictionary"), level=8)
 
@@ -223,15 +223,15 @@ class IMAP(object):
 
         for folder in inbox_folders:
             additional_folders = None
-            if not self.has_folder("user%s%s" %(self.imap.separator, folder)):
+            if not self.has_folder("user%s%s" % (self.imap.separator, folder)):
                 # TODO: Perhaps this block is moot
                 log.info(_("Creating new INBOX for user (%d): %s")
-                    %(1,folder))
+                    % (1,folder))
                 try:
-                    self.imap.cm("user%s%s" %(self.imap.separator, folder))
+                    self.imap.cm("user%s%s" % (self.imap.separator, folder))
                 except:
                     log.warning(
-                            _("Mailbox already exists: user%s%s") %(
+                            _("Mailbox already exists: user%s%s") % (
                                     self.imap.separator,folder
                                 )
                         )
@@ -240,7 +240,7 @@ class IMAP(object):
 
                 if conf.get('kolab', 'imap_backend') == 'cyrus-imap':
                     self.imap._setquota(
-                            "user%s%s" %(self.imap.separator, folder),
+                            "user%s%s" % (self.imap.separator, folder),
                             0
                         )
 
@@ -283,15 +283,15 @@ class IMAP(object):
             try:
                 self.imap.cm(folder_name)
             except:
-                log.warning(_("Mailbox already exists: user/%s") %(folder))
+                log.warning(_("Mailbox already exists: user/%s") % (folder))
 
             if additional_folders[additional_folder].has_key("annotations"):
                 for annotation in additional_folders[additional_folder]["annotations"].keys():
                     if conf.get('kolab', 'imap_backend') == 'cyrus-imap':
                         self.imap._setannotation(
                                 folder_name,
-                                "%s" %(annotation),
-                                "%s" %(additional_folders[additional_folder]["annotations"][annotation])
+                                "%s" % (annotation),
+                                "%s" % (additional_folders[additional_folder]["annotations"][annotation])
                             )
 
             if additional_folders[additional_folder].has_key("quota"):
@@ -304,8 +304,8 @@ class IMAP(object):
                 for acl in additional_folders[additional_folder]["acls"].keys():
                     self.imap.sam(
                             folder_name,
-                            "%s" %(acl),
-                            "%s" %(additional_folders[additional_folder]["acls"][acl])
+                            "%s" % (acl),
+                            "%s" % (additional_folders[additional_folder]["acls"][acl])
                         )
 
         backend = conf.get('kolab', 'imap_backend')
@@ -386,7 +386,7 @@ class IMAP(object):
                         folder = "user/%s" % user[_inbox_folder_attr]
             elif type(user) == str:
                 quota = auth.get_user_attribute(user, 'quota')
-                folder = "user/%s" %(user)
+                folder = "user/%s" % (user)
 
             folder = folder.lower()
 
@@ -394,7 +394,7 @@ class IMAP(object):
                 (used,current_quota) = self.imap.lq(folder)
             except:
                 # TODO: Go in fact correct the quota.
-                log.warning(_("Cannot get current IMAP quota for folder %s") %(folder))
+                log.warning(_("Cannot get current IMAP quota for folder %s") % (folder))
                 used = 0
                 current_quota = 0
 
@@ -407,18 +407,18 @@ class IMAP(object):
                     }
                 )
 
-            log.debug(_("Quota for %s currently is %s") %(folder, current_quota), level=7)
+            log.debug(_("Quota for %s currently is %s") % (folder, current_quota), level=7)
 
             if new_quota == None:
                 continue
 
             if not int(new_quota) == int(quota):
-                log.info(_("Adjusting authentication database quota for folder %s to %d") %(folder,int(new_quota)))
+                log.info(_("Adjusting authentication database quota for folder %s to %d") % (folder,int(new_quota)))
                 quota = int(new_quota)
                 auth.set_user_attribute(primary_domain, user, _quota_attr, new_quota)
 
             if not int(current_quota) == int(quota):
-                log.info(_("Correcting quota for %s to %s (currently %s)") %(folder, quota, current_quota))
+                log.info(_("Correcting quota for %s to %s (currently %s)") % (folder, quota, current_quota))
                 self.imap._setquota(folder, quota)
 
     def set_user_mailhost(self, users=[], primary_domain=None, secondary_domain=[], folders=[]):
@@ -457,7 +457,7 @@ class IMAP(object):
 
             elif type(user) == str:
                 _mailserver = auth.get_user_attribute(user, _mailserver_attr)
-                folder = "user/%s" %(user)
+                folder = "user/%s" % (user)
 
             folder = folder.lower()
 
@@ -500,17 +500,17 @@ class IMAP(object):
         folders = self.list_user_folders()
 
         for folder in folders:
-            log.debug(_("Checking folder: %s") %(folder), level=1)
+            log.debug(_("Checking folder: %s") % (folder), level=1)
             try:
                 if inbox_folders.index(folder) > -1:
                     continue
                 else:
-                    log.info(_("Folder has no corresponding user (1): %s") %(folder))
-                    self.delete_mailfolder("user/%s" %(folder))
+                    log.info(_("Folder has no corresponding user (1): %s") % (folder))
+                    self.delete_mailfolder("user/%s" % (folder))
             except:
-                log.info(_("Folder has no corresponding user (2): %s") %(folder))
+                log.info(_("Folder has no corresponding user (2): %s") % (folder))
                 try:
-                    self.delete_mailfolder("user/%s" %(folder))
+                    self.delete_mailfolder("user/%s" % (folder))
                 except:
                     pass
 
@@ -526,7 +526,7 @@ class IMAP(object):
             log.error(_("Please don't give us just a user identifier"))
             return
 
-        log.info(_("Deleting folder %s") %(mailfolder_path))
+        log.info(_("Deleting folder %s") % (mailfolder_path))
 
         self.imap.dm(mailfolder_path)
 
@@ -551,14 +551,14 @@ class IMAP(object):
             if mbox_parts['domain']:
                 # List the shared and user folders
                 shared_folders = self.imap.lm(
-                        "shared/*@%s" %(mbox_parts['domain'])
+                        "shared/*@%s" % (mbox_parts['domain'])
                     )
 
                 user_folders = self.imap.lm(
-                        "user/*@%s" %(mbox_parts['domain'])
+                        "user/*@%s" % (mbox_parts['domain'])
                     )
 
-                aci_identifier = "%s@%s" %(
+                aci_identifier = "%s@%s" % (
                         mbox_parts['path_parts'][1],
                         mbox_parts['domain']
                     )
@@ -566,10 +566,10 @@ class IMAP(object):
             else:
                 shared_folders = self.imap.lm("shared/*")
                 user_folders = self.imap.lm("user/*")
-                aci_identifier = "%s" %(mbox_parts['path_parts'][1])
+                aci_identifier = "%s" % (mbox_parts['path_parts'][1])
 
             log.debug(
-                    _("Cleaning up ACL entries referring to identifier %s") %(
+                    _("Cleaning up ACL entries referring to identifier %s") % (
                             aci_identifier
                         ),
                     level=5
@@ -578,7 +578,7 @@ class IMAP(object):
             # For all folders (shared and user), ...
             folders = user_folders + shared_folders
 
-            log.debug(_("Iterating over %d folders") %(len(folders)), level=5)
+            log.debug(_("Iterating over %d folders") % (len(folders)), level=5)
 
             # ... loop through them and ...
             for folder in folders:
@@ -609,7 +609,7 @@ class IMAP(object):
 
         if not primary_domain == None:
             for domain in [ primary_domain ] + secondary_domains:
-                acceptable_domain_name_res.append(domain_re %(domain))
+                acceptable_domain_name_res.append(domain_re % (domain))
 
         folders = []
 
@@ -624,14 +624,14 @@ class IMAP(object):
                         #print "Acceptable indeed"
                         #acceptable = True
                     #if not acceptable:
-                        #print "%s is not acceptable against %s yet using %s" %(folder.split('@')[1],folder,domain_name_re)
+                        #print "%s is not acceptable against %s yet using %s" % (folder.split('@')[1],folder,domain_name_re)
 
                 #if acceptable:
-                    #folder_name = "%s@%s" %(folder.split(self.separator)[1].split('@')[0],folder.split('@')[1])
+                    #folder_name = "%s@%s" % (folder.split(self.separator)[1].split('@')[0],folder.split('@')[1])
 
-                folder_name = "%s@%s" %(folder.split(self.imap.separator)[1].split('@')[0],folder.split('@')[1])
+                folder_name = "%s@%s" % (folder.split(self.imap.separator)[1].split('@')[0],folder.split('@')[1])
             else:
-                folder_name = "%s" %(folder.split(self.imap.separator)[1])
+                folder_name = "%s" % (folder.split(self.imap.separator)[1])
 
             if not folder_name == None:
                 if not folder_name in folders:
diff --git a/pykolab/imap/cyrus.py b/pykolab/imap/cyrus.py
index b9fb6e3..1515222 100644
--- a/pykolab/imap/cyrus.py
+++ b/pykolab/imap/cyrus.py
@@ -70,7 +70,7 @@ class Cyrus(cyruslib.CYRUS):
 
         self.server = hostname
 
-        self.uri = "%s://%s:%s" %(scheme,hostname,port)
+        self.uri = "%s://%s:%s" % (scheme,hostname,port)
 
         cyruslib.CYRUS.__init__(self, self.uri)
 
@@ -115,7 +115,7 @@ class Cyrus(cyruslib.CYRUS):
         prefix = _mailfolder['path_parts'].pop(0)
         mbox = _mailfolder['path_parts'].pop(0)
         if not _mailfolder['domain'] == None:
-            mailfolder = "%s%s%s@%s" %(prefix,self.separator,mbox,_mailfolder['domain'])
+            mailfolder = "%s%s%s@%s" % (prefix,self.separator,mbox,_mailfolder['domain'])
 
         # TODO: Workaround for undelete
         if len(self.lm(mailfolder)) < 1:
@@ -126,7 +126,7 @@ class Cyrus(cyruslib.CYRUS):
         if not self.murder:
             return self.server
 
-        log.debug(_("Checking actual backend server for folder %s through annotations") %(mailfolder), level=8)
+        log.debug(_("Checking actual backend server for folder %s through annotations") % (mailfolder), level=8)
         if self.mbox.has_key(mailfolder):
             return self.mbox[mailfolder]
 
@@ -140,11 +140,11 @@ class Cyrus(cyruslib.CYRUS):
                 break
 
             if max_tries <= num_try:
-                log.error(_("Could not get the annotations after %s tries.") %(num_try))
+                log.error(_("Could not get the annotations after %s tries.") % (num_try))
                 annotations = { mailfolder: { '/vendor/cmu/cyrus-imapd/server': self.server }}
                 break
 
-            log.warning(_("No annotations for %s: %r") %(mailfolder,annotations))
+            log.warning(_("No annotations for %s: %r") % (mailfolder,annotations))
 
             time.sleep(1)
 
@@ -156,7 +156,7 @@ class Cyrus(cyruslib.CYRUS):
                 if not imap._imap[server].mbox.has_key(mailfolder):
                     imap._imap[server].mbox[mailfolder] = server
 
-        log.debug(_("Server for INBOX folder %s is %s") %(mailfolder,server), level=8)
+        log.debug(_("Server for INBOX folder %s is %s") % (mailfolder,server), level=8)
 
         return server
 
@@ -166,22 +166,22 @@ class Cyrus(cyruslib.CYRUS):
         """
         server = self.find_mailfolder_server(mailfolder)
         #print "server:", server
-        imap.connect('imap://%s:143' %(server))
+        imap.connect('imap://%s:143' % (server))
 
-        log.debug(_("Setting quota for INBOX folder %s to %s") %(mailfolder,quota), level=8)
+        log.debug(_("Setting quota for INBOX folder %s to %s") % (mailfolder,quota), level=8)
         try:
             imap.setquota(mailfolder, quota)
         except:
-            log.error(_("Could not set quota for mailfolder %s") %(mailfolder))
+            log.error(_("Could not set quota for mailfolder %s") % (mailfolder))
 
     def _rename(self, from_mailfolder, to_mailfolder, partition=None):
         """
             Login to the actual backend server, then rename.
         """
         server = self.find_mailfolder_server(from_mailfolder)
-        imap.connect('imap://%s:143' %(server))
+        imap.connect('imap://%s:143' % (server))
 
-        log.debug(_("Moving INBOX folder %s to %s") %(from_mailfolder,to_mailfolder), level=8)
+        log.debug(_("Moving INBOX folder %s to %s") % (from_mailfolder,to_mailfolder), level=8)
         imap.rename(from_mailfolder, to_mailfolder, partition)
 
     def _getannotation(self, *args, **kw):
@@ -193,17 +193,17 @@ class Cyrus(cyruslib.CYRUS):
             Login to the actual backend server, then set annotation.
         """
         server = self.find_mailfolder_server(mailfolder)
-        imap.connect('imap://%s:143' %(server))
+        imap.connect('imap://%s:143' % (server))
 
-        log.debug(_("Setting annotation %s on folder %s") %(annotation,mailfolder), level=8)
+        log.debug(_("Setting annotation %s on folder %s") % (annotation,mailfolder), level=8)
 
         #if annotation.startswith('/private'):
 
         imap.setannotation(mailfolder, annotation, value)
 
     def _xfer(self, mailfolder, current_server, new_server):
-        imap.connect('imap://%s:143' %(current_server))
-        log.debug(_("Transferring folder %s from %s to %s") %(mailfolder, current_server, new_server), level=8)
+        imap.connect('imap://%s:143' % (current_server))
+        log.debug(_("Transferring folder %s from %s to %s") % (mailfolder, current_server, new_server), level=8)
         imap.xfer(mailfolder, new_server)
 
     def undelete_mailfolder(self, mailfolder, to_mailfolder=None, recursive=True):
@@ -250,20 +250,20 @@ class Cyrus(cyruslib.CYRUS):
                 target_folder = self.separator.join(target_mbox['path_parts'])
 
             if not to_mailfolder == None:
-                target_folder = "%s%s%s" %(target_folder,self.separator,mbox)
+                target_folder = "%s%s%s" % (target_folder,self.separator,mbox)
 
             if not len(undelete_mbox['path_parts']) == 0:
-                target_folder = "%s%s%s" %(target_folder,self.separator,self.separator.join(undelete_mbox['path_parts']))
+                target_folder = "%s%s%s" % (target_folder,self.separator,self.separator.join(undelete_mbox['path_parts']))
 
             if target_folder in target_folders:
-                target_folder = "%s%s%s" %(target_folder,self.separator,undelete_mbox['hex_timestamp'])
+                target_folder = "%s%s%s" % (target_folder,self.separator,undelete_mbox['hex_timestamp'])
 
             target_folders.append(target_folder)
 
             if not target_mbox['domain'] == None:
-                target_folder = "%s@%s" %(target_folder,target_mbox['domain'])
+                target_folder = "%s@%s" % (target_folder,target_mbox['domain'])
 
-            log.info(_("Undeleting %s to %s") %(undelete_folder,target_folder))
+            log.info(_("Undeleting %s to %s") % (undelete_folder,target_folder))
 
             target_server = self.find_mailfolder_server(target_folder)
 
@@ -315,7 +315,7 @@ class Cyrus(cyruslib.CYRUS):
                 }
 
             if not mbox['domain'] == None:
-                verify_folder_search = "%s@%s" %(verify_folder_search, mbox['domain'])
+                verify_folder_search = "%s@%s" % (verify_folder_search, mbox['domain'])
 
             folders = self.lm(verify_folder_search)
 
@@ -353,7 +353,7 @@ class Cyrus(cyruslib.CYRUS):
                 }
 
         if not mbox['domain'] == None:
-            deleted_folder_search = "%s@%s" %(deleted_folder_search,mbox['domain'])
+            deleted_folder_search = "%s@%s" % (deleted_folder_search,mbox['domain'])
 
         folders = self.lm(deleted_folder_search)
 
diff --git a/pykolab/logger.py b/pykolab/logger.py
index 2a517a8..e1d1189 100644
--- a/pykolab/logger.py
+++ b/pykolab/logger.py
@@ -99,6 +99,6 @@ class Logger(logging.Logger):
 
         if level <= self.debuglevel:
             # TODO: Not the way it's supposed to work!
-            self.log(logging.DEBUG, '[%d]: %s' %(os.getpid(),msg))
+            self.log(logging.DEBUG, '[%d]: %s' % (os.getpid(),msg))
 
 logging.setLoggerClass(Logger)
diff --git a/pykolab/plugins/__init__.py b/pykolab/plugins/__init__.py
index e21c1cc..d0ba88e 100644
--- a/pykolab/plugins/__init__.py
+++ b/pykolab/plugins/__init__.py
@@ -50,7 +50,7 @@ class KolabPlugins(object):
 
             if os.path.isdir(plugin_path):
                 for plugin in os.listdir(plugin_path):
-                    if os.path.isdir('%s/%s/' %(plugin_path,plugin,)):
+                    if os.path.isdir('%s/%s/' % (plugin_path,plugin,)):
                         self.plugins[plugin] = False
 
         self.check_plugins()
@@ -63,7 +63,7 @@ class KolabPlugins(object):
         """
         for plugin in self.plugins:
             try:
-                exec("from pykolab.plugins import %s" %(plugin))
+                exec("from pykolab.plugins import %s" % (plugin))
                 self.plugins[plugin] = True
                 self.load_plugins(plugins=[plugin])
             except ImportError, e:
@@ -186,7 +186,7 @@ class KolabPlugins(object):
                 except AttributeError, e:
                     log.error(_("Cannot check options for plugin %s: %s") % (plugin,e))
             else:
-                log.debug(_("Not checking options for plugin %s: No function 'check_options()'") %(plugin), level=5)
+                log.debug(_("Not checking options for plugin %s: No function 'check_options()'") % (plugin), level=5)
 
     def plugin_check_setting(self, func, option, val, plugins=[]):
         """
@@ -224,13 +224,13 @@ class KolabPlugins(object):
 
             if hasattr(getattr(self,plugin),hook):
                 try:
-                    log.debug(_("Executing hook %s for plugin %s") %(hook,plugin), level=8)
-                    #print "retval = self.%s.%s(%r, %r)" %(plugin,hook, args, kw)
-                    exec("retval = self.%s.%s(*args, **kw)" %(plugin,hook))
+                    log.debug(_("Executing hook %s for plugin %s") % (hook,plugin), level=8)
+                    #print "retval = self.%s.%s(%r, %r)" % (plugin,hook, args, kw)
+                    exec("retval = self.%s.%s(*args, **kw)" % (plugin,hook))
                 except TypeError, e:
-                    log.error(_("Cannot execute hook %s for plugin %s: %s") %(hook,plugin,e))
+                    log.error(_("Cannot execute hook %s for plugin %s: %s") % (hook,plugin,e))
                 except AttributeError, e:
-                    log.error(_("Cannot execute hook %s for plugin %s: %s") %(hook,plugin,e))
+                    log.error(_("Cannot execute hook %s for plugin %s: %s") % (hook,plugin,e))
 
         return retval
 
diff --git a/pykolab/plugins/defaultfolders/__init__.py b/pykolab/plugins/defaultfolders/__init__.py
index 1d53406..cee1b02 100644
--- a/pykolab/plugins/defaultfolders/__init__.py
+++ b/pykolab/plugins/defaultfolders/__init__.py
@@ -44,11 +44,11 @@ class KolabDefaultfolders(object):
         """
 
         if not kw.has_key('additional_folders'):
-            log.error(_("Plugin %s called without required keyword %s.") %("defaultfolders", "additional_folders"))
+            log.error(_("Plugin %s called without required keyword %s.") % ("defaultfolders", "additional_folders"))
             return {}
 
         try:
-            exec("additional_folders = %s" %(kw['additional_folders']))
+            exec("additional_folders = %s" % (kw['additional_folders']))
         except Exception, e:
             log.error(_("Could not parse additional_folders"))
             return {}
diff --git a/pykolab/plugins/dynamicquota/__init__.py b/pykolab/plugins/dynamicquota/__init__.py
index d19a811..6115dcd 100644
--- a/pykolab/plugins/dynamicquota/__init__.py
+++ b/pykolab/plugins/dynamicquota/__init__.py
@@ -47,13 +47,13 @@ class KolabDynamicquota(object):
 
         for keyword in [ 'used', 'current_quota', 'new_quota', 'default_quota' ]:
             if not kw.has_key(keyword):
-                log.warning(_("No keyword %s passed to set_user_folder_quota") %(keyword))
+                log.warning(_("No keyword %s passed to set_user_folder_quota") % (keyword))
                 return 0
             else:
                 try:
                     kw[keyword] = (int)(kw[keyword])
                 except:
-                    log.error(_("Quota '%s' not an integer!") %(keyword))
+                    log.error(_("Quota '%s' not an integer!") % (keyword))
                     return 0
 
         # Escape the user without quota
diff --git a/pykolab/plugins/recipientpolicy/__init__.py b/pykolab/plugins/recipientpolicy/__init__.py
index 89f05d0..6621947 100644
--- a/pykolab/plugins/recipientpolicy/__init__.py
+++ b/pykolab/plugins/recipientpolicy/__init__.py
@@ -98,7 +98,7 @@ class KolabRecipientpolicy(object):
 
         alternative_mail = []
 
-        #print "%r" %(alternative_mail_routines)
+        #print "%r" % (alternative_mail_routines)
         _domains = [ kw['primary_domain'] ] + kw['secondary_domains']
 
         for number in alternative_mail_routines.keys():
@@ -108,7 +108,7 @@ class KolabRecipientpolicy(object):
                 except KeyError, e:
                     log.warning(_("Attribute substitution for 'alternative_mail' failed in Recipient Policy"))
 
-                #log.debug(_("Appending additional mail address: %s") %(retval), level=8)
+                #log.debug(_("Appending additional mail address: %s") % (retval), level=8)
                 alternative_mail.append(utils.translate(retval, user_attrs['preferredlanguage']))
 
                 for _domain in kw['secondary_domains']:
@@ -118,7 +118,7 @@ class KolabRecipientpolicy(object):
                     except KeyError, e:
                         log.warning(_("Attribute substitution for 'alternative_mail' failed in Recipient Policy"))
 
-                    #log.debug(_("Appending additional mail address: %s") %(retval), level=8)
+                    #log.debug(_("Appending additional mail address: %s") % (retval), level=8)
                     alternative_mail.append(utils.translate(retval, user_attrs['preferredlanguage']))
 
         alternative_mail = utils.normalize(alternative_mail)
diff --git a/pykolab/setup/components.py b/pykolab/setup/components.py
index d13e21a..d17a357 100644
--- a/pykolab/setup/components.py
+++ b/pykolab/setup/components.py
@@ -43,9 +43,9 @@ def __init__():
             if filename.startswith('setup_') and filename.endswith('.py'):
                 module_name = filename.replace('.py','')
                 component_name = module_name.replace('setup_', '')
-                #print "exec(\"from %s import __init__ as %s_register\"" %(module_name,component_name)
-                exec("from %s import __init__ as %s_register" %(module_name,component_name))
-                exec("%s_register()" %(component_name))
+                #print "exec(\"from %s import __init__ as %s_register\"" % (module_name,component_name)
+                exec("from %s import __init__ as %s_register" % (module_name,component_name))
+                exec("%s_register()" % (component_name))
 
         for dirname in dirnames:
             register_group(components_path, dirname)
@@ -75,21 +75,21 @@ def list_setup(*args, **kw):
         if __components[_component].has_key('function'):
             # This is a top-level component
             if not __components[_component]['description'] == None:
-                print "%-25s - %s" %(_component.replace('_','-'),__components[_component]['description'])
+                print "%-25s - %s" % (_component.replace('_','-'),__components[_component]['description'])
             else:
-                print "%-25s" %(_component.replace('_','-'))
+                print "%-25s" % (_component.replace('_','-'))
 
     for _component in _components:
         if not __components[_component].has_key('function'):
             # This is a nested component
-            print "\n" + _("Command Group: %s") %(_component) + "\n"
+            print "\n" + _("Command Group: %s") % (_component) + "\n"
             ___components = __components[_component].keys()
             ___components.sort()
             for __component in ___components:
                 if not __components[_component][__component]['description'] == None:
-                    print "%-4s%-21s - %s" %('',__component.replace('_','-'),__components[_component][__component]['description'])
+                    print "%-4s%-21s - %s" % ('',__component.replace('_','-'),__components[_component][__component]['description'])
                 else:
-                    print "%-4s%-21s" %('',__component.replace('_','-'))
+                    print "%-4s%-21s" % ('',__component.replace('_','-'))
 
 def execute(component_name, *args, **kw):
     if not components.has_key(component_name):
@@ -105,15 +105,15 @@ def execute(component_name, *args, **kw):
         group = components[component_name]['group']
         component_name = components[component_name]['component_name']
         try:
-            exec("from %s.cmd_%s import cli_options as %s_%s_cli_options" %(group,component_name,group,component_name))
-            exec("%s_%s_cli_options()" %(group,component_name))
+            exec("from %s.cmd_%s import cli_options as %s_%s_cli_options" % (group,component_name,group,component_name))
+            exec("%s_%s_cli_options()" % (group,component_name))
         except ImportError, e:
             pass
 
     else:
         try:
-            exec("from cmd_%s import cli_options as %s_cli_options" %(component_name,component_name))
-            exec("%s_cli_options()" %(component_name))
+            exec("from cmd_%s import cli_options as %s_cli_options" % (component_name,component_name))
+            exec("%s_cli_options()" % (component_name))
         except ImportError, e:
             pass
 
@@ -134,13 +134,13 @@ def register_group(dirname, module):
             if filename.startswith('cmd_') and filename.endswith('.py'):
                 module_name = filename.replace('.py','')
                 component_name = module_name.replace('cmd_', '')
-                #print "exec(\"from %s.%s import __init__ as %s_%s_register\"" %(module,module_name,module,component_name)
-                exec("from %s.%s import __init__ as %s_%s_register" %(module,module_name,module,component_name))
-                exec("%s_%s_register()" %(module,component_name))
+                #print "exec(\"from %s.%s import __init__ as %s_%s_register\"" % (module,module_name,module,component_name)
+                exec("from %s.%s import __init__ as %s_%s_register" % (module,module_name,module,component_name))
+                exec("%s_%s_register()" % (module,component_name))
 
 def register(component_name, func, group=None, description=None, aliases=[]):
     if not group == None:
-        component = "%s_%s" %(group,component_name)
+        component = "%s_%s" % (group,component_name)
     else:
         component = component_name
 
@@ -148,7 +148,7 @@ def register(component_name, func, group=None, description=None, aliases=[]):
         aliases = [aliases]
 
     if components.has_key(component):
-        log.fatal(_("Command '%s' already registered") %(component))
+        log.fatal(_("Command '%s' already registered") % (component))
         sys.exit(1)
 
     if callable(func):
@@ -170,7 +170,7 @@ def register(component_name, func, group=None, description=None, aliases=[]):
         for alias in aliases:
             components[alias] = {
                     'function': func,
-                    'description': _("Alias for %s") %(component_name)
+                    'description': _("Alias for %s") % (component_name)
                 }
 
 ##
diff --git a/pykolab/setup/ldap_setup.py b/pykolab/setup/ldap_setup.py
index 8349b16..a99351f 100644
--- a/pykolab/setup/ldap_setup.py
+++ b/pykolab/setup/ldap_setup.py
@@ -49,10 +49,10 @@ def setup():
 
     for item in other_services:
         log.warning(_("Warning: LDAP Service '%s' is available on " + \
-                            "this system as well.") %(item))
+                            "this system as well.") % (item))
 
     if not service == None:
-        log.info(_("Found system service %s.") %(service))
+        log.info(_("Found system service %s.") % (service))
     else:
         package.Package('openldap-servers')
 
diff --git a/pykolab/setup/setup_ldap.py b/pykolab/setup/setup_ldap.py
index 59672c5..1d85da7 100644
--- a/pykolab/setup/setup_ldap.py
+++ b/pykolab/setup/setup_ldap.py
@@ -76,4 +76,4 @@ AddSampleEntries = No
 Port = 9830
 ServerAdminID = admin
 ServerAdminPwd = %(admin_pass)s
-""" %(_input)
+""" % (_input)
diff --git a/pykolab/telemetry.py b/pykolab/telemetry.py
index 6df1192..66bd1ae 100644
--- a/pykolab/telemetry.py
+++ b/pykolab/telemetry.py
@@ -189,7 +189,7 @@ class TelemetryLog(object):
 
                 line_num += 1
 
-                log.debug("%s (%d): %s" %(self.log_file,line_num,line), level=8)
+                log.debug("%s (%d): %s" % (self.log_file,line_num,line), level=8)
 
                 if line.startswith('---------- '):
                     # This is the actual start of a session
@@ -585,7 +585,7 @@ def expire_sessions(retention=7):
     """
     start_max = ((int)(time.time()) - (retention * 24 * 60 * 60))
     #start_max = (int)(time.time())
-    log.info(_("Expiring sessions that started before or on %d") %(start_max))
+    log.info(_("Expiring sessions that started before or on %d") % (start_max))
 
     db = init_db()
 
@@ -598,7 +598,7 @@ def expire_sessions(retention=7):
                 )
 
     for session in sessions:
-        log.debug(_("Expiring session ID: %d") %(session.id), level=8)
+        log.debug(_("Expiring session ID: %d") % (session.id), level=8)
 
         # Expire related information
         command_issue_ids = db.query(
@@ -617,7 +617,7 @@ def expire_sessions(retention=7):
             db.commit()
 
         log.debug(
-                _("Session with ID %d expired from database") %(session.id),
+                _("Session with ID %d expired from database") % (session.id),
                 level=8
             )
 
@@ -643,7 +643,7 @@ def init_db():
         try:
             metadata.create_all(engine)
         except sqlalchemy.exc.OperationalError, e:
-            log.error(_("Operational Error in telemetry database: %s" %(e)))
+            log.error(_("Operational Error in telemetry database: %s" % (e)))
 
         Session = sessionmaker(bind=engine)
         db = Session()
diff --git a/pykolab/tests/imap/test_login.py b/pykolab/tests/imap/test_login.py
index 951abd9..7042415 100644
--- a/pykolab/tests/imap/test_login.py
+++ b/pykolab/tests/imap/test_login.py
@@ -41,21 +41,21 @@ def description():
 
 def execute(*args, **kw):
     try:
-        log.debug(_("Connecting at %s") %(time.time()), level=8)
+        log.debug(_("Connecting at %s") % (time.time()), level=8)
         imap.connect(login=False)
-        log.debug(_("Connected at %s") %(time.time()), level=8)
+        log.debug(_("Connected at %s") % (time.time()), level=8)
     except:
         raise TestFailureException, __file__
 
     try:
-        log.debug(_("Logging in at %s") %(time.time()), level=8)
+        log.debug(_("Logging in at %s") % (time.time()), level=8)
         imap.login('doe', password='0cvRKSdluPU4ewN')
-        log.debug(_("Logged in at %s") %(time.time()), level=8)
+        log.debug(_("Logged in at %s") % (time.time()), level=8)
         #imap.login('doe', password='bla')
     except:
         raise TestFailureException(__file__)
 
 class TestFailureException(BaseException):
     def __init__(self, test_file):
-        log.error(_("Test failure in %s") %(test_file))
+        log.error(_("Test failure in %s") % (test_file))
         utils.ask_confirmation('Would you like to log this as a bug?')
\ No newline at end of file
diff --git a/pykolab/tests/tests.py b/pykolab/tests/tests.py
index 8a3c915..1f72f3f 100644
--- a/pykolab/tests/tests.py
+++ b/pykolab/tests/tests.py
@@ -43,9 +43,9 @@ def __init__():
             if filename.startswith('test_') and filename.endswith('.py'):
                 module_name = filename.replace('.py','')
                 test_name = module_name.replace('test_', '')
-                #print "exec(\"from %s import __init__ as %s_register\"" %(module_name,test_name)
-                exec("from %s import __init__ as %s_register" %(module_name,test_name))
-                exec("%s_register()" %(test_name))
+                #print "exec(\"from %s import __init__ as %s_register\"" % (module_name,test_name)
+                exec("from %s import __init__ as %s_register" % (module_name,test_name))
+                exec("%s_register()" % (test_name))
 
         for dirname in dirnames:
             register_group(tests_path, dirname)
@@ -76,21 +76,21 @@ def list_tests(*args, **kw):
             if __tests[_test].has_key('function'):
                 # This is a top-level test
                 if not __tests[_test]['description'] == None:
-                    print "%-25s - %s" %(_test.replace('_','-'),__tests[_test]['description'])
+                    print "%-25s - %s" % (_test.replace('_','-'),__tests[_test]['description'])
                 else:
-                    print "%-25s" %(_test.replace('_','-'))
+                    print "%-25s" % (_test.replace('_','-'))
 
     for _test in _tests:
         if not __tests[_test].has_key('function'):
             # This is a nested test
-            print "\n" + _("Test Suite: %s") %(_test) + "\n"
+            print "\n" + _("Test Suite: %s") % (_test) + "\n"
             ___tests = __tests[_test].keys()
             ___tests.sort()
             for __test in ___tests:
                 if not __tests[_test][__test]['description'] == None:
-                    print "%-4s%-21s - %s" %('',__test.replace('_','-'),__tests[_test][__test]['description'])
+                    print "%-4s%-21s - %s" % ('',__test.replace('_','-'),__tests[_test][__test]['description'])
                 else:
-                    print "%-4s%-21s" %('',__test.replace('_','-'))
+                    print "%-4s%-21s" % ('',__test.replace('_','-'))
 
 def execute(test_name, *args, **kw):
     print "tests:", tests
@@ -109,15 +109,15 @@ def execute(test_name, *args, **kw):
         group = tests[test_name]['group']
         _test_name = tests[test_name]['test_name']
         try:
-            exec("from %s.test_%s import cli_options as %s_%s_cli_options" %(group,_test_name,group,test_name))
-            exec("%s_%s_cli_options()" %(group,test_name))
+            exec("from %s.test_%s import cli_options as %s_%s_cli_options" % (group,_test_name,group,test_name))
+            exec("%s_%s_cli_options()" % (group,test_name))
         except ImportError, e:
             pass
 
     else:
         try:
-            exec("from test_%s import cli_options as %s_cli_options" %(test_name,test_name))
-            exec("%s_cli_options()" %(test_name))
+            exec("from test_%s import cli_options as %s_cli_options" % (test_name,test_name))
+            exec("%s_cli_options()" % (test_name))
         except ImportError, e:
             pass
 
@@ -138,13 +138,13 @@ def register_group(dirname, module):
             if filename.startswith('test_') and filename.endswith('.py'):
                 module_name = filename.replace('.py','')
                 test_name = module_name.replace('test_', '')
-                #print "exec(\"from %s.%s import __init__ as %s_%s_register\"" %(module,module_name,module,test_name)
-                exec("from %s.%s import __init__ as %s_%s_register" %(module,module_name,module,test_name))
-                exec("%s_%s_register()" %(module,test_name))
+                #print "exec(\"from %s.%s import __init__ as %s_%s_register\"" % (module,module_name,module,test_name)
+                exec("from %s.%s import __init__ as %s_%s_register" % (module,module_name,module,test_name))
+                exec("%s_%s_register()" % (module,test_name))
 
 def register(test_name, func, group=None, description=None, aliases=[]):
     if not group == None:
-        test = "%s_%s" %(group,test_name)
+        test = "%s_%s" % (group,test_name)
     else:
         test = test_name
 
@@ -154,11 +154,11 @@ def register(test_name, func, group=None, description=None, aliases=[]):
         aliases = [aliases]
 
     if tests.has_key(test):
-        log.fatal(_("Test '%s' already registered") %(test))
+        log.fatal(_("Test '%s' already registered") % (test))
         sys.exit(1)
 
     if tests.has_key(test):
-        log.fatal(_("Test '%s' already registered") %(test))
+        log.fatal(_("Test '%s' already registered") % (test))
         sys.exit(1)
 
     if callable(func):
@@ -180,7 +180,7 @@ def register(test_name, func, group=None, description=None, aliases=[]):
         for alias in aliases:
             tests[alias] = {
                     'function': func,
-                    'description': _("Alias for %s") %(test_name)
+                    'description': _("Alias for %s") % (test_name)
                 }
 
 ##
diff --git a/pykolab/utils.py b/pykolab/utils.py
index bd94a02..9198c82 100644
--- a/pykolab/utils.py
+++ b/pykolab/utils.py
@@ -36,12 +36,12 @@ def ask_question(question, default="", password=False):
         Usage: pykolab.utils.ask_question("What is the server?", default="localhost")
     """
     if password:
-        answer = getpass.getpass("%s: " %(question))
+        answer = getpass.getpass("%s: " % (question))
     else:
         if default == "":
-            answer = raw_input("%s: " %(question))
+            answer = raw_input("%s: " % (question))
         else:
-            answer = raw_input("%s [%s]: " %(question, default))
+            answer = raw_input("%s [%s]: " % (question, default))
 
     if answer == "":
         return default
@@ -71,7 +71,7 @@ def ask_confirmation(question, default="y", all_inclusive_no=True):
 
     answer = False
     while answer == False:
-        answer = raw_input("%s [%s/%s]: " %(question,default_yes,default_no))
+        answer = raw_input("%s [%s/%s]: " % (question,default_yes,default_no))
         # Parse answer and set back to False if not appropriate
         if all_inclusive_no:
             if not answer in [ "y", "Y", "yes" ]:
@@ -206,7 +206,7 @@ def pop_empty_from_list(_input_list):
             _output_list.append(item)
 
 def standard_root_dn(domain):
-    return 'dc=%s' %(',dc='.join(domain.split('.')))
+    return 'dc=%s' % (',dc='.join(domain.split('.')))
 
 def translate(mystring, locale_name='en_US'):
     import locale
diff --git a/pykolab/wap_client/__init__.py b/pykolab/wap_client/__init__.py
index c84790d..5462961 100644
--- a/pykolab/wap_client/__init__.py
+++ b/pykolab/wap_client/__init__.py
@@ -58,7 +58,7 @@ def get_group_input():
     if len(group_types.keys()) > 1:
         for key in group_types.keys():
             if not key == "status":
-                print "%s) %s" %(key,group_types[key]['name'])
+                print "%s) %s" % (key,group_types[key]['name'])
 
         group_type_id = utils.ask_question("Please select the group type")
 
@@ -84,7 +84,7 @@ def get_group_input():
         params[attribute] = utils.ask_question(attribute)
 
     for attribute in group_type_info['auto_form_fields'].keys():
-        exec("retval = group_form_value_generate_%s(params)" %(attribute))
+        exec("retval = group_form_value_generate_%s(params)" % (attribute))
         params[attribute] = retval[attribute]
 
     return params
@@ -95,7 +95,7 @@ def get_user_input():
     if len(user_types.keys()) > 1:
         for key in user_types.keys():
             if not key == "status":
-                print "%s) %s" %(key,user_types[key]['name'])
+                print "%s) %s" % (key,user_types[key]['name'])
 
         user_type_id = utils.ask_question("Please select the user type")
 
@@ -121,7 +121,7 @@ def get_user_input():
         params[attribute] = utils.ask_question(attribute)
 
     for attribute in user_type_info['auto_form_fields'].keys():
-        exec("retval = form_value_generate_%s(params)" %(attribute))
+        exec("retval = form_value_generate_%s(params)" % (attribute))
         params[attribute] = retval[attribute]
 
     return params
@@ -144,13 +144,13 @@ def group_form_value_generate_mail(params=None):
 
 def group_info():
     group = utils.ask_question("Group email address")
-    group = request('GET', 'group.info?group=%s' %(group))
+    group = request('GET', 'group.info?group=%s' % (group))
     return group
 
 def group_members_list(group=None):
     if group == None:
         group = utils.ask_question("Group email address")
-    group = request('GET', 'group.members_list?group=%s' %(group))
+    group = request('GET', 'group.members_list?group=%s' % (group))
     return group
 
 def group_types_list():
@@ -166,7 +166,7 @@ def request(method, api_uri, params=None, headers={}):
         headers["X-Session-Token"] = session_id
 
     conn = connect()
-    conn.request(method.upper(), "%s/%s" %(API_BASE,api_uri), params, headers)
+    conn.request(method.upper(), "%s/%s" % (API_BASE,api_uri), params, headers)
     response = conn.getresponse()
     data = response.read()
 
@@ -197,7 +197,7 @@ def system_get_domain():
 def system_select_domain(domain=None):
     if domain == None:
         domain = utils.ask_question("Domain name")
-    return request('GET', 'system.select_domain?domain=%s' %(domain))
+    return request('GET', 'system.select_domain?domain=%s' % (domain))
 
 def user_add(params=None):
     if params == None:
@@ -270,7 +270,7 @@ def user_form_value_generate_userpassword(*args, **kw):
 
 def user_info():
     user = utils.ask_question("User email address")
-    user = request('GET', 'user.info?user=%s' %(user))
+    user = request('GET', 'user.info?user=%s' % (user))
     return user
 
 def user_types_list():


commit 0ae2417b2c4a614fd70c512b1283be37dd0c31dd
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Fri Mar 9 10:34:47 2012 +0000

    Correct some pylint conventions/warnings/errors

diff --git a/kolabd/__init__.py b/kolabd/__init__.py
index 47175e4..b53c7c2 100644
--- a/kolabd/__init__.py
+++ b/kolabd/__init__.py
@@ -23,18 +23,16 @@
     consider providing an option to specify the pid file path.
 """
 
-from optparse import OptionParser
-from ConfigParser import SafeConfigParser
-
 import os
 import shutil
+import sys
 import time
 import traceback
 
 import pykolab
 
 from pykolab.auth import Auth
-from pykolab.constants import *
+from pykolab import constants
 from pykolab.translate import _
 
 log = pykolab.getLogger('kolabd')
@@ -87,23 +85,27 @@ class KolabDaemon(object):
             elif not conf.fork_mode:
                 self.do_sync()
 
-        except SystemExit, e:
-            exitcode = e
+        except SystemExit, errcode:
+            exitcode = errcode
         except KeyboardInterrupt:
             exitcode = 1
             log.info(_("Interrupted by user"))
-        except AttributeError, e:
+        except AttributeError, errmsg:
             exitcode = 1
             traceback.print_exc()
-            print >> sys.stderr, _("Traceback occurred, please report a bug at http://bugzilla.kolabsys.com")
-        except TypeError, e:
+            print >> sys.stderr, _("Traceback occurred, please report a " + \
+                "bug at http://bugzilla.kolabsys.com")
+
+        except TypeError, errmsg:
             exitcode = 1
             traceback.print_exc()
-            log.error(_("Type Error: %s") % e)
+            log.error(_("Type Error: %s") % errmsg)
         except:
             exitcode = 2
             traceback.print_exc()
-            print >> sys.stderr, _("Traceback occurred, please report a bug at http://bugzilla.kolabsys.com")
+            print >> sys.stderr, _("Traceback occurred, please report a " + \
+                "bug at http://bugzilla.kolabsys.com")
+
         sys.exit(exitcode)
 
     def do_sync(self):
@@ -122,25 +124,54 @@ class KolabDaemon(object):
                 time.sleep(600)
             end = time.time()
 
-            log.debug(_("Found %d domains in %d seconds") %(len(domains),(end-start)), level=8)
-
-            for primary_domain,secondary_domains in domains:
-                log.debug(_("Running for domain %s") %(primary_domain), level=5)
+            log.debug(
+                    _("Found %d domains in %d seconds") % (
+                            len(domains),
+                            (end-start)
+                        ),
+                    level=8
+                )
+
+            for primary_domain, secondary_domains in domains:
+                log.debug(
+                        _("Running for domain %s") % (
+                                primary_domain
+                            ),
+                        level=5
+                    )
 
                 if not pid == 0 and not domain_auth.has_key(primary_domain):
-                    log.debug(_("Domain %s did not have a key yet") %(primary_domain), level=5)
+                    log.debug(
+                            _("Domain %s did not have a key yet") % (
+                                    primary_domain
+                                ),
+                            level=5
+                        )
+
                     domain_auth[primary_domain] = Auth()
                     pid = os.fork()
                     if pid == 0:
                         domain_auth[primary_domain].connect(primary_domain)
                         start_time = time.time()
-                        domain_auth[primary_domain].synchronize(primary_domain, secondary_domains)
+                        domain_auth[primary_domain].synchronize(
+                                primary_domain,
+                                secondary_domains
+                            )
+
                         end_time = time.time()
 
-                        log.info(_("Synchronizing users for %s took %d seconds")
-                                %(primary_domain, (end_time-start_time))
+                        log.info(
+                                _("Synchronizing users for %s took %d seconds")
+                                    % (
+                                        primary_domain,
+                                        (end_time-start_time)
+                                    )
+                            )
+
+                        domain_auth[primary_domain].synchronize(
+                                primary_domain,
+                                secondary_domains
                             )
-                        domain_auth[primary_domain].synchronize(primary_domain, secondary_domains)
 
     def reload_config(self, *args, **kw):
         pass
@@ -158,5 +189,5 @@ class KolabDaemon(object):
     def write_pid(self):
         pid = os.getpid()
         fp = open(conf.pidfile,'w')
-        fp.write("%d\n" %(pid))
+        fp.write("%d\n" % (pid))
         fp.close()


commit 02a9568915ea6017e887cb835b20888d6a30b73d
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Fri Mar 9 10:33:44 2012 +0000

    Correct some pylint conventions/errors/warnings

diff --git a/bin/kolab_smtp_access_policy.py b/bin/kolab_smtp_access_policy.py
index 9f7a206..5ffb5b7 100755
--- a/bin/kolab_smtp_access_policy.py
+++ b/bin/kolab_smtp_access_policy.py
@@ -204,7 +204,7 @@ class PolicyRequest(object):
                 pass
 
         log.debug(
-                _("Adding policy request to instance %s") %(self.instance),
+                _("Adding policy request to instance %s") % (self.instance),
                 level=8
             )
 
@@ -478,7 +478,7 @@ class PolicyRequest(object):
                 )
 
             reject(
-                    _("Could not find envelope sender user %s") %(
+                    _("Could not find envelope sender user %s") % (
                         self.sasl_username
                         )
                 )
@@ -538,7 +538,7 @@ class PolicyRequest(object):
                     sasl_sender=self.sasl_sender
                 )
 
-            reject(_("Could not find envelope sender user %s") %(self.sender))
+            reject(_("Could not find envelope sender user %s") % (self.sender))
 
         attrs = search_attrs
         attrs.extend(
@@ -565,18 +565,18 @@ class PolicyRequest(object):
 
         if not self.sender_user.has_key('kolabdelegate'):
             reject(
-                    _("%s is unauthorized to send on behalf of %s") %(
+                    _("%s is unauthorized to send on behalf of %s") % (
                             self.sasl_user['dn'],
                             self.sender_user['dn']
                         )
                 )
 
         elif self.sender_user['kolabdelegate'] == None:
-            # No delegates for this sender could be found. The user is definitely
-            # NOT a delegate of the sender.
+            # No delegates for this sender could be found. The user is
+            # definitely NOT a delegate of the sender.
             log.warning(
                 _("User %s attempted to use envelope sender address %s " + \
-                    "without authorization") %(
+                    "without authorization") % (
                             policy_request["sasl_username"],
                             policy_request["sender"]
                         )
@@ -635,7 +635,7 @@ class PolicyRequest(object):
             for sender_delegate in sender_delegates:
                 if self.sasl_user['dn'] == sender_delegate:
                     log.debug(
-                            _("Found user %s to be a delegate user of %s") %(
+                            _("Found user %s to be a delegate user of %s") % (
                                     policy_request["sasl_username"],
                                     policy_request["sender"]
                                 ),
@@ -646,7 +646,7 @@ class PolicyRequest(object):
 
                 elif self.sasl_user['uid'] == sender_delegate:
                     log.debug(
-                            _("Found user %s to be a delegate user of %s") %(
+                            _("Found user %s to be a delegate user of %s") % (
                                     policy_request["sasl_username"],
                                     policy_request["sender"]
                                 ),
@@ -672,11 +672,11 @@ class PolicyRequest(object):
         if not self.sasl_username == '' and not self.sasl_username == None:
             log.debug(_("Verifying authenticated sender '%(sender)s' with " + \
                     "sasl_username '%(sasl_username)s' for recipient " + \
-                    "'%(recipient)s'") %(self.__dict__)
+                    "'%(recipient)s'") % (self.__dict__)
                 )
         else:
             log.debug(_("Verifying unauthenticated sender '%(sender)s' " + \
-                    "for recipient '%(recipient)s'") %(self.__dict__)
+                    "for recipient '%(recipient)s'") % (self.__dict__)
                 )
 
         recipient_verified = False
@@ -694,7 +694,7 @@ class PolicyRequest(object):
                 log.info(
                         _("Reproducing verify_recipient(%s, %s) from " + \
                             "cache, saving you queries, time and thus " + \
-                            "money.") %(self.sender, recipient)
+                            "money.") % (self.sender, recipient)
                     )
 
                 return record[0].value
@@ -709,7 +709,7 @@ class PolicyRequest(object):
         if verify_domain(sasl_domain):
             if auth.secondary_domains.has_key(sasl_domain):
                 log.debug(
-                        _("Using authentication domain %s instead of %s") %(
+                        _("Using authentication domain %s instead of %s") % (
                                 auth.secondary_domains[sasl_domain],
                                 sasl_domain
                             ),
@@ -719,7 +719,7 @@ class PolicyRequest(object):
                 sasl_domain = auth.secondary_domains[sasl_domain]
             else:
                 log.debug(
-                        _("Domain %s is a primary domain") %(
+                        _("Domain %s is a primary domain") % (
                                 sasl_domain
                         ),
                         level=8
@@ -728,7 +728,7 @@ class PolicyRequest(object):
         else:
             log.warning(
                     _("Checking the recipient for domain %s that is not " + \
-                    "ours. This is probably a configuration error.") %(
+                    "ours. This is probably a configuration error.") % (
                             sasl_domain
                         )
                 )
@@ -839,7 +839,7 @@ class PolicyRequest(object):
 
                     if not recipient_found:
                         reject(_("Sender %s is not allowed to send to " + \
-                                "recipient %s") %(self.sender,recipient))
+                                "recipient %s") % (self.sender,recipient))
 
         for recipient in self.recipients:
             recipient_verified = self.verify_recipient(recipient)
@@ -879,7 +879,7 @@ class PolicyRequest(object):
 
             if not records == None and len(records) == len(self.recipients):
                 log.info(_("Reproducing verify_sender(%r) from cache, " + \
-                        "saving you queries, time and thus money.") %(
+                        "saving you queries, time and thus money.") % (
                                 self.__dict__
                             )
                     )
@@ -892,7 +892,7 @@ class PolicyRequest(object):
 
                     if recipient_found and not record.value:
                         reject(_("Sender %s is not allowed to send to " + \
-                                "recipient %s") %(self.sender,recipient))
+                                "recipient %s") % (self.sender,recipient))
 
                 return True
 
@@ -945,7 +945,7 @@ class PolicyRequest(object):
                     'kolabAllowSMTPRecipient'
                 )
 
-        log.debug(_("Result is %r") %(recipient_policy), level=8)
+        log.debug(_("Result is %r") % (recipient_policy), level=8)
 
         # If no such attribute has been specified, allow
         if recipient_policy == None:
@@ -975,7 +975,7 @@ class PolicyRequest(object):
                 if not recipient_allowed:
                     reject(
                             _("Sender %s not allowed to send to recipient " + \
-                                "%s") %(recipient_policy_user['dn'],recipient)
+                                "%s") % (recipient_policy_user['dn'],recipient)
                         )
 
             sender_verified = True
@@ -1042,7 +1042,7 @@ def cache_init():
     try:
         metadata.create_all(engine)
     except sqlalchemy.exc.OperationalError, e:
-        log.error(_("Operational Error in caching: %s" %(e)))
+        log.error(_("Operational Error in caching: %s" % (e)))
         return False
 
     Session = sessionmaker(bind=engine)
@@ -1075,7 +1075,8 @@ def cache_select(
             ).filter(
                     PolicyResult.recipient.in_(recipients)
                 ).filter(
-                        PolicyResult.created >= ((int)(time.time()) - cache_expire)
+                        PolicyResult.created >= \
+                            ((int)(time.time()) - cache_expire)
                     ).all()
 
 def cache_insert(
@@ -1092,7 +1093,7 @@ def cache_insert(
         return []
 
     log.debug(
-            _("Caching the policy result with timestamp %d") %(
+            _("Caching the policy result with timestamp %d") % (
                     (int)(time.time())
                 ),
             level=8
@@ -1169,28 +1170,28 @@ def cache_update(
                 )
 
 def defer_if_permit(message, policy_request=None):
-    log.info(_("Returning action DEFER_IF_PERMIT: %s") %(message))
-    print "action=DEFER_IF_PERMIT %s\n\n" %(message)
+    log.info(_("Returning action DEFER_IF_PERMIT: %s") % (message))
+    print "action=DEFER_IF_PERMIT %s\n\n" % (message)
     sys.exit(0)
 
 def dunno(message, policy_request=None):
-    log.info(_("Returning action DUNNO: %s") %(message))
-    print "action=DUNNO %s\n\n" %(message)
+    log.info(_("Returning action DUNNO: %s") % (message))
+    print "action=DUNNO %s\n\n" % (message)
     sys.exit(0)
 
 def hold(message, policy_request=None):
-    log.info(_("Returning action HOLD: %s") %(message))
-    print "action=HOLD %s\n\n" %(message)
+    log.info(_("Returning action HOLD: %s") % (message))
+    print "action=HOLD %s\n\n" % (message)
     sys.exit(0)
 
 def permit(message, policy_request=None):
-    log.info(_("Returning action PERMIT: %s") %(message))
+    log.info(_("Returning action PERMIT: %s") % (message))
     print "action=PERMIT\n\n"
     sys.exit(0)
 
 def reject(message, policy_request=None):
-    log.info(_("Returning action REJECT: %s") %(message))
-    print "action=REJECT %s\n\n" %(message)
+    log.info(_("Returning action REJECT: %s") % (message))
+    print "action=REJECT %s\n\n" % (message)
     sys.exit(0)
 
 def expand_mydomains():
@@ -1218,7 +1219,7 @@ def normalize_address(email_address):
     if len(email_address.split("+")) > 1:
         # Take the first part split by recipient delimiter and the last part
         # split by '@'.
-        return "%s@%s" %(
+        return "%s@%s" % (
                 email_address.split("+")[0],
                 # TODO: Under some conditions, the recipient may not be fully
                 # qualified. We'll cross that bridge when we get there, though.
@@ -1246,7 +1247,7 @@ def read_request_input():
                 end_of_request = True
         else:
             request_line = request_line.strip()
-            log.debug(_("Getting line: %s") %(request_line), level=8)
+            log.debug(_("Getting line: %s") % (request_line), level=8)
             policy_request[request_line.split('=')[0]] = \
                 '='.join(request_line.split('=')[1:]).lower()
 
@@ -1307,7 +1308,7 @@ if __name__ == "__main__":
     while True:
         policy_request = read_request_input()
         instance = policy_request['instance']
-        log.debug(_("Got request instance %s") %(instance))
+        log.debug(_("Got request instance %s") % (instance))
         if policy_requests.has_key(instance):
             policy_requests[instance].add_request(policy_request)
         else:
@@ -1315,10 +1316,20 @@ if __name__ == "__main__":
 
         protocol_state = policy_request['protocol_state'].strip().lower()
 
-        log.debug(_("Request instance %s is in state %s") %(instance,protocol_state))
+        log.debug(
+                _("Request instance %s is in state %s") % (
+                        instance,
+                        protocol_state
+                    )
+            )
 
         if not protocol_state == 'data':
-            log.debug(_("Request instance %s is not yet in DATA state") %(instance))
+            log.debug(
+                    _("Request instance %s is not yet in DATA state") % (
+                            instance
+                        )
+                )
+
             print "action=DUNNO\n\n"
             sys.stdout.flush()
 
@@ -1326,7 +1337,7 @@ if __name__ == "__main__":
         # set to a non-zero value and the protocol_state being set to 'data'.
         # Note that the input we're getting is a string, not an integer.
         else:
-            log.debug(_("Request instance %s reached DATA state") %(instance))
+            log.debug(_("Request instance %s reached DATA state") % (instance))
 
             sender_allowed = False
             recipient_allowed = False
@@ -1337,7 +1348,9 @@ if __name__ == "__main__":
                 sender_allowed = True
 
             if conf.verify_recipient:
-                recipient_allowed = policy_requests[instance].verify_recipients()
+                recipient_allowed = \
+                        policy_requests[instance].verify_recipients()
+
             else:
                 recipient_allowed = True
 


commit fb76e19ce360ef9cbc3e9b506ad44046e511e363
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Fri Mar 9 10:32:59 2012 +0000

    Add bin/ commands to pylint,
    Make the list of files and directories to check a little more readable,
    Escape the return code for pylint.

diff --git a/Makefile.am b/Makefile.am
index 3e2504f..7668a02 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -46,7 +46,24 @@ ChangeLog: pylint
 	(GIT_DIR=.git git log $(PACKAGE)-$(VERSION) > .changelog.tmp && mv .changelog.tmp ChangeLog; rm -f .changelog.tmp) || (touch ChangeLog; echo 'git directory not found: installing possibly empty changelog.' >&2)
 
 pylint:
-	@pylint bonnie.py conf.py kolabd.py kolab.py kolabtest.py saslauthd.py setup-kolab.py wallace.py bonnie/ kolabd/ kolab/ pykolab/ saslauthd/ wallace/ > pylint.log
+	@pylint \
+		bin/kolab_smtp_access_policy.py \
+		bin/kolab_parse_telemetry.py \
+		bonnie.py \
+		conf.py \
+		kolabd.py \
+		kolab.py \
+		kolabtest.py \
+		saslauthd.py \
+		setup-kolab.py \
+		wallace.py \
+		bonnie/ \
+		kolabd/ \
+		kolab/ \
+		pykolab/ \
+		saslauthd/ \
+		wallace/ \
+		> pylint.log || :
 
 srpm: ChangeLog dist 
 	@rpmbuild -ts $(PACKAGE)-$(VERSION).tar.gz


commit 9867e7503682709ee25375eabf0f54b12acc738d
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Fri Mar 9 10:22:44 2012 +0000

    Execute and include pylint.log in the distribution tarball

diff --git a/Makefile.am b/Makefile.am
index 434a5b9..3e2504f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -30,6 +30,7 @@ EXTRA_DIST = \
 	README.tests \
 	pykolab.spec \
 	pykolab.spec.in \
+	pylint.log \
 	$(PYTHON_FILES)
 
 SUBDIRS = \
@@ -41,9 +42,12 @@ SUBDIRS = \
 	saslauthd \
 	wallace
 
-ChangeLog:
+ChangeLog: pylint
 	(GIT_DIR=.git git log $(PACKAGE)-$(VERSION) > .changelog.tmp && mv .changelog.tmp ChangeLog; rm -f .changelog.tmp) || (touch ChangeLog; echo 'git directory not found: installing possibly empty changelog.' >&2)
 
+pylint:
+	@pylint bonnie.py conf.py kolabd.py kolab.py kolabtest.py saslauthd.py setup-kolab.py wallace.py bonnie/ kolabd/ kolab/ pykolab/ saslauthd/ wallace/ > pylint.log
+
 srpm: ChangeLog dist 
 	@rpmbuild -ts $(PACKAGE)-$(VERSION).tar.gz
 


commit f213cbc49d412ab4ebb3d2ea4932be52756f5228
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Fri Mar 9 08:51:14 2012 +0000

    Replace the use of httplib with urllib
    Do not re-spool deferred messages that were already deferred

diff --git a/wallace/module_optout.py b/wallace/module_optout.py
index d4bbf33..3e2fd09 100644
--- a/wallace/module_optout.py
+++ b/wallace/module_optout.py
@@ -17,10 +17,13 @@
 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 #
 
+import json
 import os
 import random
 import tempfile
 import time
+from urlparse import urlparse
+import urllib
 
 import modules
 
@@ -57,7 +60,6 @@ def execute(*args, **kw):
 
     log.debug(_("Consulting opt-out service for %r, %r") %(args, kw), level=8)
 
-
     import email
     message = email.message_from_file(open(filepath, 'r'))
     envelope_sender = email.utils.getaddresses(message.get_all('From', []))
@@ -93,9 +95,13 @@ def execute(*args, **kw):
                     level=8
                 )
 
-            optout_answer = answers[random.randint(0,(len(answers)-1))]
-            # Let's pretend it takes two seconds to get an answer, shall we?
-            time.sleep(2)
+            optout_answer = request(
+                    {
+                            'unique-message-id': 'bogus',
+                            'envelope_sender': envelope_sender[0][1],
+                            'recipient': recipient[1]
+                        }
+                )
 
             _recipients[optout_answer][recipient_type].append(recipient)
 
@@ -109,6 +115,7 @@ def execute(*args, **kw):
     ##
 
     for answer in answers:
+        # Create the directory for the answer
         if not os.path.isdir(os.path.join(mybasepath, answer)):
             os.makedirs(os.path.join(mybasepath, answer))
 
@@ -124,19 +131,25 @@ def execute(*args, **kw):
         for recipient_type in _recipients[answer].keys():
             _message.__delitem__(recipient_type)
             if not len(_recipients[answer][recipient_type]) == 0:
-                _message.__setitem__(recipient_type, ',\n'.join([email.utils.formataddr(x) for x in _recipients[answer][recipient_type]]))
+                _message.__setitem__(
+                        recipient_type,
+                        ',\n  '.join(
+                                [email.utils.formataddr(x) for x in _recipients[answer][recipient_type]]
+                            )
+                    )
 
                 use_this = True
 
         if use_this:
             # TODO: Do not set items with an empty list.
+
             (fp, filename) = tempfile.mkstemp(dir="/var/spool/pykolab/wallace/optout/%s" %(answer))
             os.write(fp, _message.__str__())
             os.close(fp)
 
             # Callback with new filename
             if hasattr(modules, 'cb_action_%s' %(answer)):
-                log.debug(_("Attempting to execute cb_action_%s()") %(answer), level=8)
+                log.debug(_("Attempting to execute cb_action_%s(%r, %r)") %(answer, 'optout', filename), level=8)
                 exec('modules.cb_action_%s(%r, %r)' %(answer,'optout', filename))
 
     os.unlink(filepath)
@@ -148,3 +161,24 @@ def execute(*args, **kw):
         #log.debug(_("Attempting to execute cb_action_%s()") %(optout_answer), level=8)
         #exec('modules.cb_action_%s(%r, %r)' %(optout_answer,'optout', new_filepath))
         #return
+
+def request(params=None):
+    params = json.dumps(params)
+
+    optout_url = conf.get('wallace_optout', 'optout_url')
+
+    try:
+        f = urllib.urlopen(optout_url, params)
+    except Exception, e:
+        log.error(_("Could not send request to optout_url %s") %(optout_url))
+        return "DEFER"
+
+    response = f.read()
+
+    try:
+        response_data = json.loads(response)
+    except ValueError, e:
+        # Some data is not JSON
+        print "Response data is not JSON"
+
+    return response_data['result']


commit 2cb4a47d99dcd55db0db3fd11d63d3c9e6a2962a
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Thu Mar 8 10:34:20 2012 +0000

    Allow -b/--bind and -p/--port options to be specified on the command-line, for greater flexibility.
    Move the standard port to 10027.

diff --git a/wallace/__init__.py b/wallace/__init__.py
index b9df940..5897ac7 100644
--- a/wallace/__init__.py
+++ b/wallace/__init__.py
@@ -44,6 +44,22 @@ class WallaceDaemon(object):
                 help    = _("Fork to the background.")
             )
 
+        daemon_group.add_option(
+                "-b", "--bind",
+                dest    = "wallace_bind_address",
+                action  = "store",
+                default = "localhost",
+                help    = _("Bind address for Wallace.")
+            )
+
+        daemon_group.add_option(
+                "-p", "--port",
+                dest    = "wallace_port",
+                action  = "store",
+                default = 10027,
+                help    = _("Port that Wallace is supposed to use.")
+            )
+
         conf.finalize_conf()
 
         import modules
@@ -228,10 +244,17 @@ class WallaceDaemon(object):
         bound = False
         while not bound:
             try:
-                s.bind(('localhost', 8025))
+                s.bind((conf.wallace_bind_address, conf.wallace_port))
                 bound = True
             except Exception, e:
-                log.warning(_("Could not bind to socket on port 8025"))
+                log.warning(
+                        _("Could not bind to socket on port %d on bind " + \
+                            "address %s") %(
+                                conf.wallace_port,
+                                conf.wallace_bind_address
+                            )
+                    )
+
                 try:
                     s.shutdown(1)
                 except Exception, e:


commit 5e7fdbb97435fd823290c4040f01d1fe8481b9f7
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Thu Mar 8 10:03:20 2012 +0000

    Fix the empty recipient inserting at the data request state

diff --git a/bin/kolab_smtp_access_policy.py b/bin/kolab_smtp_access_policy.py
index a74d506..9f7a206 100755
--- a/bin/kolab_smtp_access_policy.py
+++ b/bin/kolab_smtp_access_policy.py
@@ -183,7 +183,8 @@ class PolicyRequest(object):
                     setattr(self, key, policy_request[key])
 
             else:
-                self.recipients.append(policy_request['recipient'])
+                if not policy_request['recipient'].strip() == '':
+                    self.recipients.append(policy_request['recipient'])
 
     def add_request(self, policy_request={}):
         """
@@ -213,7 +214,8 @@ class PolicyRequest(object):
                     policy_request['recipient']
                 )
 
-            self.recipients.append(policy_request['recipient'])
+            if not policy_request['recipient'].strip() == '':
+                self.recipients.append(policy_request['recipient'])
 
     def parse_ldap_dn(self, dn):
         """
@@ -1231,7 +1233,7 @@ def read_request_input():
         containing the request.
     """
 
-    log.debug(_("Reading request"))
+    log.debug(_("Starting to loop for new request"))
 
     policy_request = {}
 
@@ -1240,10 +1242,11 @@ def read_request_input():
         request_line = sys.stdin.readline()
         if request_line.strip() == '':
             if policy_request.has_key('request'):
-                log.debug(_("End of request"))
+                log.debug(_("End of current request"), level=8)
                 end_of_request = True
         else:
             request_line = request_line.strip()
+            log.debug(_("Getting line: %s") %(request_line), level=8)
             policy_request[request_line.split('=')[0]] = \
                 '='.join(request_line.split('=')[1:]).lower()
 
@@ -1323,6 +1326,8 @@ if __name__ == "__main__":
         # set to a non-zero value and the protocol_state being set to 'data'.
         # Note that the input we're getting is a string, not an integer.
         else:
+            log.debug(_("Request instance %s reached DATA state") %(instance))
+
             sender_allowed = False
             recipient_allowed = False
 


commit 4daf6124d0a72fe8227d3b9e6035e7050e550f6b
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue Mar 6 10:41:54 2012 +0000

    Update Makefiles

diff --git a/Makefile.am b/Makefile.am
index 0fbe791..434a5b9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -17,7 +17,8 @@ PYTHON_FILES = \
 	kolabd.py \
 	kolabtest.py \
 	saslauthd.py \
-	setup-kolab.py
+	setup-kolab.py \
+	wallace.py
 
 EXTRA_DIST = \
 	AUTHORS \
@@ -37,16 +38,13 @@ SUBDIRS = \
 	kolabd \
 	po \
 	pykolab \
-	saslauthd
-
-tarball:
-	git stash
-	make dist
+	saslauthd \
+	wallace
 
 ChangeLog:
 	(GIT_DIR=.git git log $(PACKAGE)-$(VERSION) > .changelog.tmp && mv .changelog.tmp ChangeLog; rm -f .changelog.tmp) || (touch ChangeLog; echo 'git directory not found: installing possibly empty changelog.' >&2)
 
-srpm: ChangeLog tarball
+srpm: ChangeLog dist 
 	@rpmbuild -ts $(PACKAGE)-$(VERSION).tar.gz
 
 rpm: srpm
@@ -170,6 +168,7 @@ endif
 	$(INSTALL) -p -m 755 kolab.py $(DESTDIR)/$(sbindir)/kolab
 	$(INSTALL) -p -m 755 kolabd.py $(DESTDIR)/$(sbindir)/kolabd
 	$(INSTALL) -p -m 755 saslauthd.py $(DESTDIR)/$(sbindir)/kolab-saslauthd
+	$(INSTALL) -p -m 755 wallace.py $(DESTDIR)/$(sbindir)/wallaced
 	$(INSTALL) -p -m 755 kolabtest.py $(DESTDIR)/$(bindir)/kolab-test
 	$(INSTALL) -p -m 644 cyruslib.py $(DESTDIR)/$(pythondir)
 	$(INSTALL) -p -m 755 bin/kolab_parse_telemetry.py $(DESTDIR)/$(sbindir)/kolab_parse_telemetry
diff --git a/configure.ac b/configure.ac
index 8b73c68..1b4a92b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -37,6 +37,7 @@ po/Makefile.in
 pykolab/constants.py
 pykolab/Makefile
 saslauthd/Makefile
+wallace/Makefile
 ])
 
 AC_OUTPUT
diff --git a/pykolab.spec.in b/pykolab.spec.in
index 7b408b6..3752bac 100644
--- a/pykolab.spec.in
+++ b/pykolab.spec.in
@@ -96,6 +96,19 @@ Requires:           MySQL-python
 %description -n postfix-kolab
 Kolab SMTP Access Policy for Postfix
 
+##
+## Wallace
+##
+%package -n wallace
+Summary:            Kolab Content-Filter
+Group:              Applications/System
+Requires:           pykolab = %{version}-%{release}
+Requires:           python-sqlalchemy
+Requires:           MySQL-python
+
+%description -n wallace
+This is the Kolab Content Filter, with plugins
+
 %prep
 %setup -q
 
@@ -174,6 +187,19 @@ if [ $1 = 0 ]; then
     /sbin/chkconfig --del kolabd
 fi
 
+%post -n wallace
+if [ $1 -eq  1 ] ; then
+    chkconfig --add wallace
+else
+    /sbin/service wallace condrestart
+fi
+
+%preun -n wallace
+if [ $1 = 0 ]; then
+    /sbin/service wallace stop > /dev/null 2>&1
+    /sbin/chkconfig --del wallace
+fi
+
 %clean
 rm -rf %{buildroot}
 
@@ -247,6 +273,12 @@ rm -rf %{buildroot}
 %doc AUTHORS ChangeLog COPYING
 %{_libexecdir}/postfix/kolab_smtp_access_policy
 
+%files -n wallace
+%defattr(-,root,root,-)
+%doc AUTHORS ChangeLog COPYING
+%{_sbindir}/wallaced
+%{python_sitelib}/wallace
+
 %changelog
 * @DATESTAMP@ Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com> @VERSION at -@RELEASE@
 - Initial package of new upstream version
diff --git a/pykolab/Makefile.am b/pykolab/Makefile.am
index 5e19d67..d9467a8 100644
--- a/pykolab/Makefile.am
+++ b/pykolab/Makefile.am
@@ -57,3 +57,11 @@ pykolab_testsdir = $(pythondir)/$(PACKAGE)/tests
 pykolab_tests_PYTHON = \
 	$(wildcard tests/*.py)
 
+pykolab_tests_imapdir = $(pythondir)/$(PACKAGE)/tests/imap
+pykolab_tests_imap_PYTHON = \
+	$(wildcard tests/imap/*.py)
+
+pykolab_tests_wapdir = $(pythondir)/$(PACKAGE)/tests/wap
+pykolab_tests_wap_PYTHON = \
+	$(wildcard tests/wap/*.py)
+
diff --git a/wallace/Makefile.am b/wallace/Makefile.am
new file mode 100644
index 0000000..65f107c
--- /dev/null
+++ b/wallace/Makefile.am
@@ -0,0 +1,3 @@
+wallacedir = $(pythondir)/wallace
+wallace_PYTHON = $(wildcard *.py)
+


commit 372eb6cdd8396be35bb86ec145c4881ff393c76b
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue Mar 6 10:28:32 2012 +0000

    Remove zpush tests

diff --git a/pykolab/Makefile.am b/pykolab/Makefile.am
index 51e0cde..5e19d67 100644
--- a/pykolab/Makefile.am
+++ b/pykolab/Makefile.am
@@ -57,9 +57,3 @@ pykolab_testsdir = $(pythondir)/$(PACKAGE)/tests
 pykolab_tests_PYTHON = \
 	$(wildcard tests/*.py)
 
-pykolab_tests_zpushdir = $(pythondir)/$(PACKAGE)/tests/zpush
-pykolab_tests_zpush_PYTHON = \
-	tests/zpush/test_000_000.py \
-	tests/zpush/test_000_001.py \
-	tests/zpush/__init__.py
-


commit e3a60392c58e0fb0902dfc2d3ff8299315be9e5e
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue Mar 6 10:27:52 2012 +0000

    Update the inclusion of tests files

diff --git a/pykolab/Makefile.am b/pykolab/Makefile.am
index 83a4ec3..51e0cde 100644
--- a/pykolab/Makefile.am
+++ b/pykolab/Makefile.am
@@ -55,12 +55,7 @@ pykolab_setup_PYTHON = \
 
 pykolab_testsdir = $(pythondir)/$(PACKAGE)/tests
 pykolab_tests_PYTHON = \
-	tests/calendar.py \
-	tests/constants.py \
-	tests/contacts.py \
-	tests/create-contacts.py \
-	tests/__init__.py \
-	tests/mail.py
+	$(wildcard tests/*.py)
 
 pykolab_tests_zpushdir = $(pythondir)/$(PACKAGE)/tests/zpush
 pykolab_tests_zpush_PYTHON = \


commit 3f8322c7e87c798c45f77098db400c78e6a6b677
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue Mar 6 10:16:42 2012 +0000

    Bump prerelease

diff --git a/configure.ac b/configure.ac
index ffd2f35..8b73c68 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
 AC_INIT([pykolab], 0.3)
-AC_SUBST([RELEASE], 0.16)
+AC_SUBST([RELEASE], 0.17)
 
 AC_CONFIG_SRCDIR(pykolab/constants.py.in)
 


commit 13f6d51d1055cd0feff46f348de9cd81f8755e05
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue Mar 6 10:16:11 2012 +0000

    Add search_users() to Auth as well

diff --git a/pykolab/auth/__init__.py b/pykolab/auth/__init__.py
index 2aee830..66eb993 100644
--- a/pykolab/auth/__init__.py
+++ b/pykolab/auth/__init__.py
@@ -161,6 +161,23 @@ class Auth(object):
 
         return self._auth._find_user(attr, value, domain=domain, **kw)
 
+    def search_users(self, attr, value, domain=None, **kw):
+        self.connect(domain)
+
+        if self.secondary_domains.has_key(domain):
+            log.debug(
+                    _("Using primary domain %s instead of secondary domain %s")
+                    %(
+                            self.secondary_domains[domain],
+                            domain
+                        ),
+                    level=9
+                )
+
+            domain = self.secondary_domains[domain]
+
+        return self._auth._search_users(attr, value, domain=domain, **kw)
+
     def list_domains(self):
         """
             List the domains using the auth_mechanism setting in the kolab


commit c201bf1264122105a201b68db7aa7d6843dafb90
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue Mar 6 10:15:53 2012 +0000

    Fix typo

diff --git a/pykolab/telemetry.py b/pykolab/telemetry.py
index 6dffefa..6df1192 100644
--- a/pykolab/telemetry.py
+++ b/pykolab/telemetry.py
@@ -77,7 +77,7 @@ class TelemetryCommandArg(object):
 
     command = relationship(
             'TelemetryCommand',
-            order_by='telemetry_command,id',
+            order_by='telemetry_command.id',
             backref='command_args'
         )
 


commit 9e4ca546531e36916121e12d4f68d2256592d8f7
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue Mar 6 09:29:37 2012 +0000

    Start counting at 1 for secondary addresses as well

diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py
index 637e420..727c395 100644
--- a/pykolab/auth/ldap/__init__.py
+++ b/pykolab/auth/ldap/__init__.py
@@ -1275,7 +1275,7 @@ class LDAP(object):
                 secondary_mail = []
 
                 for _secondary_mail in suggested_secondary_mail:
-                    i = 0
+                    i = 1
                     __secondary_mail = _secondary_mail
 
                     done = False


commit 1779104d7e23b481a52ce5ec3c54c268401ea62e
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue Mar 6 09:29:04 2012 +0000

    Start counting at 1

diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py
index e0ffa95..637e420 100644
--- a/pykolab/auth/ldap/__init__.py
+++ b/pykolab/auth/ldap/__init__.py
@@ -1175,7 +1175,7 @@ class LDAP(object):
                         }
                 )
 
-            i = 0
+            i = 1
             _primary_mail = primary_mail
 
             done = False


commit 708a3703149943febe0b086281c7e16d97c681a3
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue Mar 6 09:28:29 2012 +0000

    Allow overriding the base_dn for find_user()
    Add search_user()

diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py
index c52bd55..e0ffa95 100644
--- a/pykolab/auth/ldap/__init__.py
+++ b/pykolab/auth/ldap/__init__.py
@@ -302,7 +302,7 @@ class LDAP(object):
 
         return _user_dn
 
-    def _find_user(self, attr, value, domain=None, additional_filter=None):
+    def _find_user(self, attr, value, domain=None, additional_filter=None, base_dn=None):
         self._connect()
         self._bind()
 
@@ -316,10 +316,13 @@ class LDAP(object):
         else:
             section = 'ldap'
 
-        user_base_dn = conf.get_raw(
-                section,
-                'user_base_dn'
-            ) %({'base_dn': domain_root_dn})
+        if base_dn == None:
+            user_base_dn = conf.get_raw(
+                    section,
+                    'user_base_dn'
+                ) %({'base_dn': domain_root_dn})
+        else:
+            user_base_dn = base_dn
 
         if type(attr) == str:
             search_filter = "(%s=%s)" %(
@@ -358,6 +361,66 @@ class LDAP(object):
 
         return _user_dn
 
+    def _search_users(self, attr, value, domain=None, additional_filter=None, base_dn=None):
+        self._connect()
+        self._bind()
+
+        if domain == None:
+            domain = conf.get('kolab', 'primary_domain')
+
+        domain_root_dn = self._kolab_domain_root_dn(domain)
+
+        if conf.has_option(domain, 'user_base_dn'):
+            section = domain
+        else:
+            section = 'ldap'
+
+        if base_dn == None:
+            user_base_dn = conf.get_raw(
+                    section,
+                    'user_base_dn'
+                ) %({'base_dn': domain_root_dn})
+        else:
+            user_base_dn = base_dn
+
+        if type(attr) == str:
+            search_filter = "(%s=%s)" %(
+                    attr,
+                    value
+                )
+        elif type(attr) == list:
+            search_filter = "(|"
+            for _attr in attr:
+                search_filter = "%s(%s=%s)" %(search_filter, _attr, value)
+            search_filter = "%s)" %(search_filter)
+
+        if additional_filter:
+            search_filter = additional_filter % {
+                    'search_filter': search_filter
+                }
+
+        log.debug(
+                _("Attempting to find entries with search filter: %s") %(
+                        search_filter
+                    ),
+                level=8
+            )
+
+        _results = self.ldap.search_s(
+                user_base_dn,
+                scope=ldap.SCOPE_SUBTREE,
+                filterstr=search_filter,
+                attrlist=[ 'dn' ]
+            )
+
+        _user_dns = []
+
+        for _result in _results:
+            (_user_dn, _user_attrs) = _result
+            _user_dns.append(_user_dn)
+
+        return _user_dns
+
     def _persistent_search(self,
             base_dn,
             scope=ldap.SCOPE_SUBTREE,





More information about the commits mailing list