16 commits - configure.ac kolabd/kolabd.sysconfig kolabtest.py pykolab/auth pykolab/cli pykolab/conf pykolab/constants.py.in pykolab/imap pykolab/plugins pykolab/tests pykolab/wap_client test-wallace.py wallace/__init__.py wallace/module_optout.py wallace/modules.py wallace.py
Jeroen van Meeuwen
vanmeeuwen at kolabsys.com
Fri Mar 2 16:49:36 CET 2012
configure.ac | 2
kolabd/kolabd.sysconfig | 5
kolabtest.py | 2
pykolab/auth/ldap/__init__.py | 46 ++++
pykolab/cli/cmd_list_domains.py | 25 +-
pykolab/cli/cmd_remove_mailaddress.py | 59 +++++
pykolab/cli/cmd_set_language.py | 44 ++++
pykolab/cli/cmd_set_mail.py | 44 ++++
pykolab/cli/cmd_transfer_mailbox.py | 65 +++++
pykolab/conf/__init__.py | 4
pykolab/constants.py.in | 13 +
pykolab/imap/cyrus.py | 5
pykolab/plugins/__init__.py | 4
pykolab/tests/__init__.py | 57 ++---
pykolab/tests/calendar.py | 231 ---------------------
pykolab/tests/constants.py | 92 --------
pykolab/tests/contacts.py | 147 -------------
pykolab/tests/create-contacts.py | 106 ---------
pykolab/tests/imap/test_create_mailbox.py | 44 ++++
pykolab/tests/imap/test_login.py | 61 +++++
pykolab/tests/imap/test_login_admin.py | 40 +++
pykolab/tests/mail.py | 125 -----------
pykolab/tests/tests.py | 192 +++++++++++++++++
pykolab/tests/wap/test_login.py | 40 +++
pykolab/tests/zpush/__init__.py | 63 -----
pykolab/tests/zpush/test_000_000.py | 93 --------
pykolab/tests/zpush/test_000_001.py | 55 -----
pykolab/wap_client/__init__.py | 281 +++++++++++++++++++++++++
test-wallace.py | 93 ++++++++
wallace.py | 40 +++
wallace/__init__.py | 328 ++++++++++++++++++++++++++++++
wallace/module_optout.py | 150 +++++++++++++
wallace/modules.py | 170 +++++++++++++++
33 files changed, 1758 insertions(+), 968 deletions(-)
New commits:
commit 91102c4fd11e4f4f4539bb1522d32d306e1cd904
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Mar 2 15:49:04 2012 +0000
Add the wallace run code
diff --git a/wallace.py b/wallace.py
new file mode 100755
index 0000000..3a5bd01
--- /dev/null
+++ b/wallace.py
@@ -0,0 +1,40 @@
+#!/usr/bin/python
+#
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+import sys
+
+# For development purposes
+sys.path.extend(['.', '..'])
+
+from pykolab.translate import _
+
+try:
+ from pykolab.constants import *
+except ImportError, e:
+ print >> sys.stderr, _("Cannot load pykolab/constants.py:")
+ print >> sys.stderr, "%s" % e
+ sys.exit(1)
+
+import wallace
+
+if __name__ == "__main__":
+ wallace = wallace.WallaceDaemon()
+ wallace.run()
+
commit b481dac3b79ed078879516d1d720448e3591d138
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Mar 2 15:48:33 2012 +0000
Add kolabd.sysconfig
diff --git a/kolabd/kolabd.sysconfig b/kolabd/kolabd.sysconfig
new file mode 100644
index 0000000..0705f32
--- /dev/null
+++ b/kolabd/kolabd.sysconfig
@@ -0,0 +1,5 @@
+# Configuration file for the Kolab Server daemon.
+#
+# See kolabd --help for more flags.
+#
+FLAGS="--fork -l warning"
\ No newline at end of file
commit f68403e44926e0ea3cbcf4f6f153aedade5b8dec
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Mar 2 15:47:38 2012 +0000
Update kolabtest.py to the new test suite semantics
diff --git a/kolabtest.py b/kolabtest.py
index 6a348e8..4c3e954 100755
--- a/kolabtest.py
+++ b/kolabtest.py
@@ -23,7 +23,7 @@ import os
import sys
# For development purposes
-sys.path.extend(['.', '..'])
+sys.path.append('.')
from pykolab.translate import _
from pykolab.tests import *
commit 219e2a96d15e867b220cc92ee91a03ede0984cfc
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Mar 2 15:47:14 2012 +0000
Add the bare bones of Wallace with the optout module
diff --git a/test-wallace.py b/test-wallace.py
new file mode 100755
index 0000000..84d3488
--- /dev/null
+++ b/test-wallace.py
@@ -0,0 +1,93 @@
+#!/usr/bin/python
+#
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+import smtplib
+import socket
+import sys
+
+# For development purposes
+sys.path.extend(['.', '..'])
+
+from email.MIMEMultipart import MIMEMultipart
+from email.MIMEBase import MIMEBase
+from email.MIMEText import MIMEText
+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.set_debuglevel(True)
+ subject = "This is a Kolab load test mail"
+ text = """Hi there,
+
+I am a Kolab Groupware test email, generated by a script that makes
+me send lots of email to lots of people using one account and a bunch
+of delegation blah.
+
+Your response, though completely unnecessary, would be appreciated, because
+being a fictitious character doesn't do my address book of friends any good.
+
+Kind regards,
+
+Lucy Meier.
+"""
+
+ msg = MIMEMultipart()
+ msg['From'] = send_from
+ msg['To'] = COMMASPACE.join(send_to)
+ msg['Date'] = formatdate(localtime=True)
+ msg['Subject'] = subject
+
+ msg.attach( MIMEText(text) )
+
+ #msg.attach( MIMEBase('application', open('/boot/initrd-plymouth.img').read()) )
+
+ smtp.sendmail(send_from, send_to, msg.as_string())
+
+if __name__ == "__main__":
+ #send_to = [
+ #'Jeroen van Meeuwen <jeroen.vanmeeuwen at klab.cc>',
+ #'Aleksander Machniak <aleksander.machniak at klab.cc>',
+ #'Georg Greve <georg.greve at klab.cc>',
+ #'Paul Adams <paul.adams at klab.cc>',
+ #'Thomas Broderli <thomas.broderli at klab.cc>',
+ #'Christoph Wickert <christoph.wickert at klab.cc>',
+ #'Lucy Meier <lucy.meier at klab.cc>',
+ #]
+
+
+ #send_mail(
+ #'Jeroen van Meeuwen <jeroen.vanmeeuwen at klab.cc>',
+ #send_to
+ #)
+
+ #send_mail(
+ #'Lucy Meier on behalf of Paul Adams <paul.adams at test90.kolabsys.com>',
+ #send_to
+ #)
+
+ #send_mail(
+ #'Lucy Meier on behalf of Georg Greve <georg.greve at test90.kolabsys.com>',
+ #send_to
+ #)
+
+ send_to = [ 'Jeroen van Meeuwen <jeroen.vanmeeuwen at klab.cc>' ]
+
+ send_mail('Jeroen van Meeuwen <vanmeeuwen at kolabsys.com>', send_to)
diff --git a/wallace/__init__.py b/wallace/__init__.py
new file mode 100644
index 0000000..b9df940
--- /dev/null
+++ b/wallace/__init__.py
@@ -0,0 +1,328 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+import asyncore
+import os
+from smtpd import SMTPChannel
+import sys
+import tempfile
+import threading
+import time
+import traceback
+
+import pykolab
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.wallace')
+conf = pykolab.getConf()
+
+class WallaceDaemon(object):
+ def __init__(self):
+ daemon_group = conf.add_cli_parser_option_group(_("Daemon Options"))
+
+ daemon_group.add_option(
+ "--fork",
+ dest = "fork_mode",
+ action = "store_true",
+ default = False,
+ help = _("Fork to the background.")
+ )
+
+ conf.finalize_conf()
+
+ import modules
+ modules.__init__()
+
+ def process_message(self, peer, mailfrom, rcpttos, data):
+ """
+ We have retrieved the message.
+
+ - Dispatch to virus-scanning and anti-spam filtering?
+ - Apply access policies;
+ - Maximum number of recipients,
+ - kolabAllowSMTPSender,
+ - kolabAllowSMTPRecipient,
+ - Rule-based matching against white- and/or blacklist
+ - ...
+ - Accounting
+ - Data Loss Prevention
+ """
+ inheaders = 1
+
+ (fp, filename) = tempfile.mkstemp(dir="/var/spool/pykolab/wallace/")
+
+ os.write(fp, data)
+ 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(_("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)
+
+ 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)
+ time.sleep(10)
+
+ 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)
+
+ if kw.has_key('module'):
+ 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(_("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)
+ modules.execute(kw['module'], filename, stage=kw['stage'])
+
+ return
+
+ wallace_modules = conf.get_list('wallace', 'modules')
+ if wallace_modules == None:
+ wallace_modules = []
+
+ for module in wallace_modules:
+ log.debug(_("Executing module %s") %(module), level=8)
+ modules.execute(module, filename)
+
+ def run(self):
+ """
+ Run the SASL authentication daemon.
+ """
+
+ exitcode = 0
+
+ try:
+ pid = 1
+ if conf.fork_mode:
+ self.thread_count += 1
+ pid = os.fork()
+
+ if pid == 0:
+ log.remove_stdout_handler()
+
+ self.do_wallace()
+
+ except SystemExit, e:
+ exitcode = e
+ except KeyboardInterrupt:
+ exitcode = 1
+ log.info(_("Interrupted by user"))
+ except AttributeError, e:
+ exitcode = 1
+ traceback.print_exc()
+ print >> sys.stderr, _("Traceback occurred, please report a bug at http://bugzilla.kolabsys.com")
+ except TypeError, e:
+ exitcode = 1
+ traceback.print_exc()
+ log.error(_("Type Error: %s") % e)
+ except:
+ exitcode = 2
+ traceback.print_exc()
+ print >> sys.stderr, _("Traceback occurred, please report a bug at http://bugzilla.kolabsys.com")
+ sys.exit(exitcode)
+
+ def pickup_defer(self):
+ wallace_modules = conf.get_list('wallace', 'modules')
+
+ if wallace_modules == None:
+ wallace_modules = []
+
+ base_path = '/var/spool/pykolab/wallace/'
+
+ while 1:
+ file_count = 0
+
+ log.debug(_("Picking up deferred messages for wallace"), level=8)
+
+ defer_path = os.path.join(base_path, 'DEFER')
+
+ if os.path.isdir(defer_path):
+ for root, directory, files in os.walk(defer_path):
+ for filename in files:
+ filepath = os.path.join(root, filename)
+
+ file_count += 1
+
+ for module in wallace_modules:
+ modules.execute(module, filepath)
+
+ time.sleep(1)
+
+ time.sleep(1)
+
+ for module in wallace_modules:
+ log.debug(_("Picking up deferred messages for module %s") %(module), level=8)
+
+ module_defer_path = os.path.join(base_path, module, 'DEFER')
+
+ if os.path.isdir(module_defer_path):
+ for root, directory, files in os.walk(module_defer_path):
+ for filename in files:
+ filepath = os.path.join(root, filename)
+
+ file_count += 1
+
+ modules.execute(module, filepath)
+
+ time.sleep(1)
+
+ time.sleep(1)
+
+ # Sleep longer if last time around we didn't find any deferred
+ # message files
+ if file_count > 0:
+ log.debug(_("Sleeping for 1 second"), level=8)
+ time.sleep(1)
+ else:
+ log.debug(_("Sleeping for 10 seconds"), level=8)
+ time.sleep(10)
+
+
+ def do_wallace(self):
+ import binascii
+ import socket
+ import struct
+
+ #s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+ ## TODO: The wallace socket path could be a setting.
+ #try:
+ #os.remove('/var/run/kolab/wallace')
+ #except:
+ ## TODO: Do the "could not remove, could not start dance"
+ #pass
+
+ bound = False
+ while not bound:
+ try:
+ s.bind(('localhost', 8025))
+ bound = True
+ except Exception, e:
+ log.warning(_("Could not bind to socket on port 8025"))
+ try:
+ s.shutdown(1)
+ except Exception, e:
+ log.warning(_("Could not shut down socket"))
+
+ s.close()
+
+ time.sleep(1)
+
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ #os.chmod('/var/run/kolab/wallace', 0777)
+ #os.chgrp('/var/run/wallace/mux', 'kolab')
+ #os.chown('/var/run/wallace/mux', 'kolab')
+
+ s.listen(5)
+
+ # Mind you to include the trailing slash
+ pickup_path = '/var/spool/pykolab/wallace/'
+ for root, directory, files in os.walk(pickup_path):
+ for filename in files:
+ filepath = os.path.join(root, filename)
+
+ if not root == pickup_path:
+ module = os.path.dirname(root).replace(pickup_path, '')
+
+ # 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
+ # are pending being handled by their respective plugins.
+ #
+ # TODO: Handle messages in spool directories for which a
+ # plugin had been enabled, but is not enabled any longer.
+ #
+
+ if module.lower() == "defer":
+ # Wallace was unable to deliver to re-injection smtpd.
+ # Skip it, another thread is picking up the defers.
+ continue
+
+ stage = root.replace(pickup_path, '').split('/')
+ if len(stage) < 2:
+ stage = None
+ else:
+ stage = stage[1]
+
+ if stage.lower() == "hold":
+ continue
+
+ # Do not handle messages in a defer state.
+ if stage.lower() == "defer":
+ continue
+
+ 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)
+ }
+ )
+
+ thread.start()
+ time.sleep(0.5)
+
+ 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 ])
+ thread.start()
+ time.sleep(0.5)
+
+ pid = os.fork()
+
+ if pid == 0:
+ self.pickup_defer()
+ else:
+
+ try:
+ while 1:
+ pair = s.accept()
+ log.info(_("Accepted connection"))
+ if not pair == None:
+ connection, address = pair
+ #print "Accepted connection from %r" %(address)
+ channel = SMTPChannel(self, connection, address)
+ asyncore.loop()
+ except Exception, e:
+ traceback.print_exc()
+ s.shutdown(1)
+ s.close()
diff --git a/wallace/module_optout.py b/wallace/module_optout.py
new file mode 100644
index 0000000..d4bbf33
--- /dev/null
+++ b/wallace/module_optout.py
@@ -0,0 +1,150 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+import os
+import random
+import tempfile
+import time
+
+import modules
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.wallace')
+conf = pykolab.getConf()
+
+mybasepath = '/var/spool/pykolab/wallace/optout/'
+
+def __init__():
+ if not os.path.isdir(mybasepath):
+ os.makedirs(mybasepath)
+
+ modules.register('optout', execute, description=description())
+
+def description():
+ return """Consult the opt-out service."""
+
+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))
+ return
+
+ #modules.next_module('optout')
+
+ 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', []))
+
+ recipients = {
+ "To": email.utils.getaddresses(message.get_all('To', [])),
+ "Cc": email.utils.getaddresses(message.get_all('Cc', []))
+ # TODO: Are those all recipient addresses?
+ }
+
+ # optout answers are ACCEPT, REJECT, HOLD or DEFER
+ answers = [ 'ACCEPT', 'REJECT', 'HOLD', 'DEFER' ]
+
+ # Initialize our results placeholders.
+ _recipients = {}
+
+ for answer in answers:
+ _recipients[answer] = {
+ "To": [],
+ "Cc": []
+ }
+
+ for recipient_type in recipients.keys():
+ for recipient in recipients[recipient_type]:
+ log.debug(
+ _("Running opt-out consult from envelope sender '%s " + \
+ "<%s>' to recipient %s <%s>") %(
+ envelope_sender[0][0],
+ envelope_sender[0][1],
+ recipient[0],
+ recipient[1]
+ ),
+ 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)
+
+ _recipients[optout_answer][recipient_type].append(recipient)
+
+ #print _recipients
+
+ ##
+ ## TODO
+ ##
+ ## If one of them all is DEFER, DEFER the entire message and discard the
+ ## other results.
+ ##
+
+ for answer in answers:
+ if not os.path.isdir(os.path.join(mybasepath, answer)):
+ os.makedirs(os.path.join(mybasepath, answer))
+
+ # Consider using a new mktemp()-like call
+ new_filepath = os.path.join(mybasepath, answer, os.path.basename(filepath))
+
+ # Write out a message file representing the new contents for the message
+ # use email.formataddr(recipient)
+ _message = email.message_from_file(open(filepath, 'r'))
+
+ use_this = False
+
+ 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]]))
+
+ 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)
+ exec('modules.cb_action_%s(%r, %r)' %(answer,'optout', filename))
+
+ os.unlink(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))
+ #return
diff --git a/wallace/modules.py b/wallace/modules.py
new file mode 100644
index 0000000..374f440
--- /dev/null
+++ b/wallace/modules.py
@@ -0,0 +1,170 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+import os
+import sys
+
+import pykolab
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.wallace')
+conf = pykolab.getConf()
+
+modules = {}
+
+def __init__():
+ # We only want the base path
+ modules_base_path = os.path.dirname(__file__)
+
+ for modules_path, dirnames, filenames in os.walk(modules_base_path):
+ if not modules_path == modules_base_path:
+ continue
+
+ for filename in filenames:
+ 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))
+
+ for dirname in dirnames:
+ register_group(modules_path, dirname)
+
+def list_modules(*args, **kw):
+ """
+ List modules
+ """
+
+ __modules = {}
+
+ for module in modules.keys():
+ if isinstance(module, tuple):
+ module_group, module = module
+ __modules[module_group] = {
+ module: modules[(module_group,module)]
+ }
+ else:
+ __modules[module] = modules[module]
+
+ _modules = __modules.keys()
+ _modules.sort()
+
+ for _module in _modules:
+ 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'])
+ else:
+ 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"
+ ___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'])
+ else:
+ print "%-4s%-21s" %('',__module.replace('_','-'))
+
+def execute(name, *args, **kw):
+ if not modules.has_key(name):
+ log.error(_("No such module."))
+ sys.exit(1)
+
+ if not modules[name].has_key('function') and \
+ not modules[name].has_key('group'):
+ log.error(_("No such module."))
+ sys.exit(1)
+
+ 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)
+
+def cb_action_DEFER(module, filepath):
+ log.info(_("Deferring message in %s (by module %s)") %(filepath, module))
+
+def cb_action_REJECT(module, filepath):
+ log.info(_("Rejecting message in %s (by module %s)") %(filepath, module))
+ # Send NDR, unlink file
+ 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)
+
+def register_group(dirname, module):
+ modules_base_path = os.path.join(os.path.dirname(__file__), module)
+
+ modules[module] = {}
+
+ for modules_path, dirnames, filenames in os.walk(modules_base_path):
+ if not modules_path == modules_base_path:
+ continue
+
+ for filename in filenames:
+ 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))
+
+def register(name, func, group=None, description=None, aliases=[]):
+ if not group == None:
+ module = "%s_%s" %(group,name)
+ else:
+ module = name
+
+ if isinstance(aliases, basestring):
+ aliases = [aliases]
+
+ if modules.has_key(module):
+ log.fatal(_("Module '%s' already registered") %(module))
+ sys.exit(1)
+
+ if callable(func):
+ if group == None:
+ modules[name] = {
+ 'function': func,
+ 'description': description
+ }
+ else:
+ modules[group][name] = {
+ 'function': func,
+ 'description': description
+ }
+
+ modules[module] = modules[group][name]
+ modules[module]['group'] = group
+ modules[module]['name'] = name
+
+ for alias in aliases:
+ modules[alias] = {
+ 'function': func,
+ 'description': _("Alias for %s") %(name)
+ }
+
commit 2d7c188c7bea6932918d74715c32b2575358dd4a
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Mar 2 15:46:35 2012 +0000
Redo test suites
diff --git a/pykolab/tests/__init__.py b/pykolab/tests/__init__.py
index 9b902be..3aefdc3 100644
--- a/pykolab/tests/__init__.py
+++ b/pykolab/tests/__init__.py
@@ -26,7 +26,6 @@ import time
import pykolab
from pykolab.constants import *
-from pykolab.tests.constants import *
from pykolab.translate import _
log = pykolab.getLogger('pykolab.tests')
@@ -34,16 +33,11 @@ conf = pykolab.getConf()
class Tests(object):
def __init__(self):
+ import tests
+ tests.__init__()
test_group = conf.add_cli_parser_option_group(_("Test Options"))
- for item in TEST_ITEMS:
- test_group.add_option( "--%s" %(item['name']),
- dest = "%s" %(item['name']),
- action = "store_true",
- default = False,
- help = _("Submit a number of items to the %s") %(item['mailbox']))
-
test_group.add_option( "--suite",
dest = "test_suites",
action = "append",
@@ -51,33 +45,28 @@ class Tests(object):
help = _("Run tests in suite SUITE. Implies a certain set of items being tested."),
metavar = "SUITE")
- delivery_group = conf.add_cli_parser_option_group(_("Content Delivery Options"))
-
- delivery_group.add_option( "--use-mail",
- dest = "use_mail",
- action = "store_true",
- default = False,
- help = _("Send messages containing the items through mail (requires proper infrastructure)"))
+ conf.finalize_conf()
- delivery_group.add_option( "--use-imap",
- dest = "use_imap",
- action = "store_true",
- default = False,
- help = _("Inject messages containing the items through IMAP"))
+ def run(self):
+ if len(conf.test_suites) > 0:
+ for test_suite in conf.test_suites:
+ print test_suite
+ else:
+ to_execute = []
- delivery_group.add_option( "--use-lmtp",
- dest = "use_lmtp",
- action = "store_true",
- default = False,
- help = _("Deliver messages containing the items through LMTP"))
+ arg_num = 0
+ for arg in sys.argv[1:]:
+ print "arg", arg
+ arg_num += 1
+ if not arg.startswith('-') and len(sys.argv) >= arg_num:
+ if tests.tests.has_key(sys.argv[arg_num].replace('-','_')):
+ print "tests.tests.has_key", sys.argv[arg_num].replace('-','_')
+ to_execute.append(sys.argv[arg_num].replace('-','_'))
- conf.finalize_conf()
+ print "to_execute", to_execute
+ if len(to_execute) > 0:
+ print "'_'.join(to_execute)", '_'.join(to_execute)
+ tests.execute('_'.join(to_execute))
+ else:
+ tests.execute('help')
- def run(self):
- # Execute the suites first.
- for suite in conf.test_suites:
- try:
- exec("from pykolab.tests.%s import %sTest" %(suite,suite.capitalize()))
- exec("%stest = %sTest()" %(suite,suite.capitalize()))
- except ImportError, e:
- conf.log.error(_("Tests for suite %s failed to load. Aborting.") %(suite.capitalize()))
diff --git a/pykolab/tests/calendar.py b/pykolab/tests/calendar.py
deleted file mode 100644
index f5b8f68..0000000
--- a/pykolab/tests/calendar.py
+++ /dev/null
@@ -1,231 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
-#
-# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 3 or, at your option, any later version
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Library General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-
-import calendar
-import datetime
-import os
-import random
-import time
-
-from pykolab.conf import Conf
-from pykolab.constants import *
-from pykolab.tests.constants import *
-from pykolab.translate import _
-
-class CalendarItem(object):
- def __init__(self, item_num=0, total_num=1, start=0, end=0, folder=None, user=None):
- """
- A calendar item is created from a template.
-
- The attributes that can be modified are set to defaults first.
- """
-
- if user == None:
- user = TEST_USERS[random.randint(0,(len(TEST_USERS)-1))]
-
- # Used for some randomization
- self.item_num = item_num
- self.total_num = total_num
- self.event_boundary_start = int(start)
- self.event_boundary_end = int(end)
-
- # Initial event data
- self.event_location = "one or the other meeting room"
- self.event_recurrence = ""
- self.event_summary = "Test Event %d" %(item_num)
-
- from_user = TEST_USERS[random.randint(0,(len(TEST_USERS)-1))]
- self.from_name_str = "%s %s" %(from_user['givenname'].capitalize(),from_user['sn'].capitalize())
- self.from_email_str = "%(givenname)s@%(domain)s" %(from_user)
- self.kolab_event_date_creation = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
- self.kolab_event_date_start = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
- self.kolab_event_date_end = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
- self.rfc_2822_sent_date = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime())
- self.to_name_str = "%s %s" %(user['givenname'].capitalize(),user['sn'].capitalize())
- self.to_email_str = "%(givenname)s@%(domain)s" %(user)
-
- self.uid = "%s.%s" %(str(random.randint(1000000000,9999999999)),str(random.randint(0,999)).zfill(3))
-
- if folder:
- self.mailbox = folder
- else:
- self.mailbox = "INBOX/Calendar"
-
- # Status information
- self.dates_randomized = False
-
- self.randomize_recurrence()
- self.randomize_dates()
-
- def randomize_dates(self):
- """
- Randomize all dates in the event but make sure they
- do make sense.
-
- Ergo, the start date is before the end date, and such.
-
- Also, take into account the total number of calendar items, so that
- we do not clutter.
- """
-
- if self.dates_randomized:
- return
-
- # The ratio is 1/2 goes to the past, 1/8 goes to this month, 3/8 goes to the future months.
- # Over 10.000 items, that is 5000 in the past -> 250 days a year, 4 appointments a day, 5 year
- # 125 this month
- # 4875 to future
-
- # We have two integers (epoch values), a start and an end
- mystart = random.randint(self.event_boundary_start,self.event_boundary_end)
- myend = mystart + (1800 * random.randint(1,4))
-
- self.kolab_event_date_start = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(mystart))
- self.kolab_event_date_end = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(myend))
-
- # Calculate the timespan we're serving assuming 4-6 appointments a day;
- self.dates_randomized = True
-
- def randomize_recurrence(self):
- """
- Randomize the recurrence of this event.
-
- One every so many events has recurrence.
- """
- return
-
- if not random.randint(1,15) == 1:
- return
-
- # The recurrence day (of the week)
- recur_day = random.randint(0,6)
-
-# # Seek a day somewhere in the past with this day_number
-# for days_in_week in calendar.itermonthdates():
-# # day_of_week is a list of weeks, where 0 is outside the month
-# # described in the call to calendar.itermonthdays(), and so
-# # we are able now to find the first day for this recurrence.
-# for day_date in days_in_week:
-# print day_date
-
- self.dates_randomized = True
-
- def __str__(self):
- for tpl_file_location in [ '/usr/share/kolab/tests/kcal-event.tpl', './share/tests/kcal-event.tpl' ]:
- if os.path.isfile(tpl_file_location):
- tpl_file = open(tpl_file_location, 'r')
- tpl_orig = tpl_file.read()
- tpl_file.close()
- break
- return tpl_orig % self.__dict__
-
-def create_items(conf, num=None, folder=None):
- for item in TEST_ITEMS:
- if item['name'] == 'calendar':
- info = item
-
- if num:
- info['number'] = int(num)
-
- conf.log.debug(_("Creating %d Events") %(info['number']), level=3)
-
- alloc_uids = []
-
- if os.path.isfile('./share/tests/kcal-event.tpl'):
- tpl_file = open('./share/tests/kcal-event.tpl', 'r')
- tpl_orig = tpl_file.read()
- tpl_file.close()
-
- (start_boundary,end_boundary) = set_bounds(num=num)
-
- imap = True
-
- for user in conf.testing_users:
- if conf.use_mail:
- pass
- elif conf.use_lmtp:
- pass
- elif conf.use_imap:
- import imaplib
- if imap:
- del imap
- imap = imaplib.IMAP4(conf.testing_server)
- imap.login("%(givenname)s@%(domain)s" %(user), user['password'])
- else:
- pass
-
- #print "Running for user %(givenname)s@%(domain)s" %(user)
- item_num = 0
-
- while item_num < int(info['number']):
- conf.log.debug(_("Creating Calendar item number %d") %(item_num+1), level=5)
-
- item = CalendarItem(item_num=(item_num+1), total_num=num, start=start_boundary, end=end_boundary, folder=folder, user=user)
-
- if not item.uid in alloc_uids:
- alloc_uids.append(item.uid)
- else:
- continue
-
- msg = str(item)
-
- if conf.use_mail:
- conf.log.debug(_("Sending UID message %s through SMTP targeting user %s@%s") %(item.uid,user['givenname'],user['domain']), level=9)
-
- elif conf.use_lmtp:
- conf.log.debug(_("Sending UID message %s through LMTP targeting user %s@%s") %(item.uid,user['givenname'],user['domain']), level=9)
-
- elif conf.use_imap:
- conf.log.debug(_("Saving UID message %s to IMAP (user %s, folder %s)") %(item.uid,user['givenname'],item.mailbox), level=9)
- imap.append(item.mailbox, '', imaplib.Time2Internaldate(time.time()), msg)
- else:
- conf.log.debug(_("Somehow ended up NOT sending these messages"), level=9)
-
- item_num +=1
-
-def set_bounds(num=0):
- """
- Set the lower and upper boundaries for this event, using the
- total number of events and a reasonable but random average number
- of appointments.
-
- returns a tuple epoch (start, end)
- """
-
- # Pretend anywhere between 0 and 5 events per workday,
- # Multiply by the number of workdays a week,
- # Divide that by 7 for a nice, float average.
- events_per_week_avg = float(random.randint(10,25))
- events_per_day_avg = events_per_week_avg / 7
-
- ratio = [ 6, 4 ]
-
- # Given the total number of events to be created, and the average number
- # of events per day, we can now look at what the lower boundary would be,
- # compared to today.
- days_to_go_back = (((num / events_per_day_avg) / 10 ) * ratio[0])
- days_to_go_forward = (((num / events_per_day_avg) / 10 ) * ratio[1])
-
- now = time.time()
- start_of_day = now - (now % (24 * 60 * 60))
-
- boundary_start = start_of_day - (days_to_go_back * 24 * 60 * 60)
- boundary_end = start_of_day + (days_to_go_forward * 24 * 60 * 60)
-
- return (boundary_start,boundary_end)
diff --git a/pykolab/tests/constants.py b/pykolab/tests/constants.py
deleted file mode 100644
index 6a9853f..0000000
--- a/pykolab/tests/constants.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
-#
-# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 3 or, at your option, any later version
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Library General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-
-import datetime
-import os
-import random
-import time
-
-TEST_ALPHABET = ""
-for num in range(33,256):
- TEST_ALPHABET = "%s%s" %(TEST_ALPHABET,unichr(num))
-
-TEST_ITEMS = [
- {
- 'name': 'calendar',
- 'mailbox': 'Calendar',
- 'template': 'kcal-event.tpl',
- 'number': 10,
- # 6 years ago
- 'calendar_start': "%d" %(time.time() - (60*60*24*365*6)),
- # 4 years forward
- 'calendar_end': "%d" %(time.time() - (60*60*24*365*6)),
- },
- {
- 'name': 'contacts',
- 'mailbox': 'Contacts',
- 'template': 'kaddress-contact.tpl',
- 'number': 10,
- },
-
- {
- 'name': 'mail',
- 'mailbox': 'INBOX',
- 'template': 'kaddress-contact.tpl',
- 'number': 10,
- },
- ]
-
-TEST_USERS = [
- #{
- #'givenname': 'john',
- #'sn': 'doe',
- #'domain': 'doe.org'
- #},
- {
- 'givenname': 'joe',
- 'sn': 'sixpack',
- 'domain': 'sixpack.com'
- },
- #{
- #'givenname': 'max',
- #'sn': 'sixpack',
- #'domain': 'sixpack.com'
- #},
- #{
- #'givenname': 'min',
- #'sn': 'sixpack',
- #'domain': 'sixpack.com'
- #},
- #{
- #'givenname': 'joe',
- #'sn': 'imum',
- #'domain': 'imum.net'
- #},
- {
- 'givenname': 'max',
- 'sn': 'imum',
- 'domain': 'imum.net'
- },
- #{
- #'givenname': 'min',
- #'sn': 'imum',
- #'domain': 'imum.net'
- #},
- ]
-
diff --git a/pykolab/tests/contacts.py b/pykolab/tests/contacts.py
deleted file mode 100644
index 156253c..0000000
--- a/pykolab/tests/contacts.py
+++ /dev/null
@@ -1,147 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
-#
-# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 3 or, at your option, any later version
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Library General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-
-import calendar
-import datetime
-import imaplib
-import os
-import random
-import time
-
-import pykolab
-
-from pykolab.constants import *
-from pykolab.tests.constants import *
-from pykolab.translate import _
-
-log = pykolab.getLogger('pykolab.tests.contacts')
-
-conf = pykolab.getConf()
-
-imap = pykolab.imap
-
-class ContactsItem(object):
- def __init__(self, item_num=0, total_num=1, folder=None, user=None):
- """
- A contact item is created from a template.
-
- The attributes that can be modified are set to defaults first.
- """
-
- if user == None:
- user = TEST_USERS[random.randint(0,(len(TEST_USERS)-1))]
-
- # Used for some randomization
- self.item_num = item_num
- self.total_num = total_num
-
- # Initial event data
- self.kolab_contact_given_name = "John"
- self.kolab_contact_last_name = "von Test"
- self.kolab_contact_email_str = "john at von.test"
- self.kolab_contact_mobile_number = "+31612345678"
-
- from_user = TEST_USERS[random.randint(0,(len(TEST_USERS)-1))]
-
- self.from_name_str = "%s %s" %(from_user['givenname'].capitalize(),from_user['sn'].capitalize())
- self.from_email_str = "%(givenname)s@%(domain)s" %(from_user)
-
- self.kolab_creation_date = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
-
- self.rfc_2822_sent_date = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime())
-
- self.to_name_str = "%s %s" %(user['givenname'].capitalize(),user['sn'].capitalize())
- self.to_email_str = "%(givenname)s@%(domain)s" %(user)
-
- self.uid = "%s.%s" %(str(random.randint(1000000000,9999999999)),str(random.randint(0,999)).zfill(3))
-
- if folder:
- self.mailbox = folder
- else:
- self.mailbox = "Contacts"
-
- self.randomize_contact()
-
- def randomize_contact(self):
- """
- Randomize the contact's information.
-
- """
- pass
-
- def __str__(self):
- for tpl_file_location in [ '/usr/share/kolab/tests/kaddress-contact.tpl', './share/tests/kaddress-contact.tpl', '../share/tests/kaddress-contact.tpl' ]:
- if os.path.isfile(tpl_file_location):
- tpl_file = open(tpl_file_location, 'r')
- tpl_orig = tpl_file.read()
- tpl_file.close()
- break
- return tpl_orig % self.__dict__
-
-def create_items(conf, num=None, folder=None):
- for item in TEST_ITEMS:
- if item['name'] == 'contacts':
- info = item
-
- if num:
- info['number'] = int(num)
-
- log.debug(_("Creating %d Contacts") %(info['number']), level=3)
-
- alloc_uids = []
-
- for user in eval(conf.get('testing','users')):
- if conf.use_mail:
- pass
- elif conf.use_lmtp:
- pass
- elif conf.use_imap:
- imap.connect(login=False)
- imap.login("%(givenname)s.%(sn)s@%(domain)s" %(user), user['password'])
- else:
- pass
-
- #print "Running for user %(givenname)s@%(domain)s" %(user)
- item_num = 0
-
- while item_num < int(info['number']):
- log.debug(_("Creating Contact item number %d") %(item_num+1), level=5)
-
- item = ContactsItem(item_num=(item_num+1), total_num=num, folder=folder, user=user)
-
- if not item.uid in alloc_uids:
- alloc_uids.append(item.uid)
- else:
- continue
-
- msg = str(item)
-
- if conf.use_mail:
- log.debug(_("Sending UID message %s through SMTP targeting user %s@%s") %(item.uid,user['givenname'],user['domain']), level=9)
-
- elif conf.use_lmtp:
- log.debug(_("Sending UID message %s through LMTP targeting user %s@%s") %(item.uid,user['givenname'],user['domain']), level=9)
-
- elif conf.use_imap:
- log.debug(_("Saving UID message %s to IMAP (user %s, folder %s)") %(item.uid,user['givenname'],item.mailbox), level=9)
- imap.imap.m.append(item.mailbox, '', imaplib.Time2Internaldate(time.time()), msg)
- else:
- log.debug(_("Somehow ended up NOT sending these messages"), level=9)
-
- item_num +=1
diff --git a/pykolab/tests/create-contacts.py b/pykolab/tests/create-contacts.py
deleted file mode 100644
index 8b09a25..0000000
--- a/pykolab/tests/create-contacts.py
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# -*- coding: utf-8 -*-
-# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
-#
-# Paul James Adams <adams a kolabsys.com>
-# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 3 or, at your option, any later version
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Library General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-
-import os, random, sys
-
-if __name__ == "__main__":
- wanted_num = int(sys.argv[1])
-
- contact_tpl_file = open('./kaddress-contact.tpl', 'r')
- contact_tpl_orig = contact_tpl_file.read()
- contact_tpl_file.close()
-
- users = ['john', 'joe', 'max']
- domains = ['doe.org', 'sixpack.com', 'imum.net']
- uid_alloc = []
-
- alphabet = "abcdefghijklmnopqrstuvwxwz"
-
- user_num = 0
-
- for user in users:
- num = 0
- while num <= wanted_num:
- uid = "%s.%s" %(str(random.randint(1000000000,9999999999)),str(random.randint(0,999)).zfill(3))
- if not uid in uid_alloc:
- uid_alloc.append(uid)
- else:
- continue
-
- domain = domains[random.randint(0,2)]
-
- contact_tpl = contact_tpl_orig
-
- birthday = ""
- if random.randint(0,100) >= 75:
- year = str(random.randint(1960, 2010))
- month = str(random.randint(1,12)).zfill(2)
- day = str(random.randint(1,27)).zfill(2)
- birthday = "%s-%s-%s" % (year, month, day)
-
- middle_names = ""
- if random.randint(0,100) >= 50:
- middle_names = ''.join(random.sample(alphabet, random.randint(4, 8))).capitalize()
-
- number = ""
- if random.randint(0,100) >= 25:
- number = "+441234567890"
-
- given_name = ''.join(random.sample(alphabet, random.randint(4, 8))).capitalize()
- last_name = ''.join(random.sample(alphabet, random.randint(4, 8))).capitalize()
-
- contact = {
- 'uid': uid,
- 'user': user,
- 'user_email': "%s@%s" % (user, domain),
- 'given_name': given_name,
- 'middle_names': middle_names,
- 'last_name': last_name,
- 'full_name': "%s %s %s" % (given_name, middle_names, last_name),
- 'display_name': "%s %s" % (given_name, last_name),
- 'email_address': "%s@%s" % (given_name, domain),
- 'number': number,
- 'birthday': birthday
- }
-
- directory = "/kolab/var/imapd/spool/domain/%s/%s/%s/user/%s/Contacts" %(domains[user_num][0],domains[user_num],user[0],user)
- if not os.path.isdir(directory):
- directory = "./kolab/var/imapd/spool/domain/%s/%s/%s/user/%s/Contacts" %(domains[user_num][0],domains[user_num],user[0],user)
- if not os.path.isdir(directory):
- os.makedirs(directory)
-
- out = open("%s/%d." %(directory,num), 'w')
-
- for key in contact.keys():
- contact_tpl = contact_tpl.replace("@@%s@@" % key, '%s' % contact[key])
-
- out.write(contact_tpl)
- out.close()
-
- try:
- os.chown("%s/%d." %(directory,num), 19415, 19415)
- except:
- pass
- num += 1
-
- user_num += 1
diff --git a/pykolab/tests/imap/__init__.py b/pykolab/tests/imap/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pykolab/tests/imap/test_create_mailbox.py b/pykolab/tests/imap/test_create_mailbox.py
new file mode 100644
index 0000000..e9a4901
--- /dev/null
+++ b/pykolab/tests/imap/test_create_mailbox.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+from pykolab.tests import tests
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.tests')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ tests.register('create_mailbox', execute, group='imap', description=description())
+
+def description():
+ return """Create a mailbox."""
+
+def execute(*args, **kw):
+ return
+ mailbox = conf.cli_args.pop(0)
+
+ imap.connect()
+ imap.cm(mailbox)
+
diff --git a/pykolab/tests/imap/test_login.py b/pykolab/tests/imap/test_login.py
new file mode 100644
index 0000000..951abd9
--- /dev/null
+++ b/pykolab/tests/imap/test_login.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+import time
+import traceback
+
+from pykolab.tests import tests
+
+import pykolab
+
+from pykolab.translate import _
+from pykolab import utils
+
+log = pykolab.getLogger('pykolab.tests')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ tests.register('login', execute, group='imap', description=description())
+
+def description():
+ return """Connect to IMAP and login."""
+
+def execute(*args, **kw):
+ try:
+ log.debug(_("Connecting at %s") %(time.time()), level=8)
+ imap.connect(login=False)
+ log.debug(_("Connected at %s") %(time.time()), level=8)
+ except:
+ raise TestFailureException, __file__
+
+ try:
+ 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)
+ #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))
+ utils.ask_confirmation('Would you like to log this as a bug?')
\ No newline at end of file
diff --git a/pykolab/tests/imap/test_login_admin.py b/pykolab/tests/imap/test_login_admin.py
new file mode 100644
index 0000000..6344bc7
--- /dev/null
+++ b/pykolab/tests/imap/test_login_admin.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+from pykolab.tests import tests
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.tests')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ tests.register('login_admin', execute, group='imap', description=description())
+
+def description():
+ return """Connect to IMAP and login as an administrator."""
+
+def execute(*args, **kw):
+ imap.connect()
+
diff --git a/pykolab/tests/mail.py b/pykolab/tests/mail.py
deleted file mode 100644
index 4304149..0000000
--- a/pykolab/tests/mail.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
-#
-# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 3 or, at your option, any later version
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Library General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-
-import calendar
-import datetime
-import mailbox
-import os
-import random
-import time
-
-from pykolab.conf import Conf
-from pykolab.constants import *
-from pykolab.tests.constants import *
-from pykolab.translate import _
-
-class MailItem(object):
- def __init__(self, item_num=0, total_num=1, folder=None, user=None):
- """
- A mail item is created from a template.
-
- The attributes that can be modified are set to defaults first.
- """
-
- if user == None:
- user = TEST_USERS[random.randint(0,(len(TEST_USERS)-1))]
-
- # Used for some randomization
- self.item_num = item_num
- self.total_num = total_num
-
- # Initial event data
- self.kolab_contact_given_name = "John"
- self.kolab_contact_last_name = "von Test"
- self.kolab_contact_email_str = "john at von.test"
- self.kolab_contact_mobile_number = "+31612345678"
-
- from_user = TEST_USERS[random.randint(0,(len(TEST_USERS)-1))]
-
- self.from_name_str = "%s %s" %(from_user['givenname'].capitalize(),from_user['sn'].capitalize())
- self.from_email_str = "%(givenname)s@%(domain)s" %(from_user)
-
- self.kolab_creation_date = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
-
- self.rfc_2822_sent_date = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime())
-
- self.to_name_str = "%s %s" %(user['givenname'].capitalize(),user['sn'].capitalize())
- self.to_email_str = "%(givenname)s@%(domain)s" %(user)
-
- self.uid = "%s.%s" %(str(random.randint(1000000000,9999999999)),str(random.randint(0,999)).zfill(3))
-
- if folder:
- self.mailbox = folder
- else:
- self.mailbox = "INBOX"
-
- self.randomize_mail()
-
- def randomize_mail(self):
- """
- Randomize some of the contents of the mail.
- """
-
- pass
-
- def __str__(self):
- return ""
-
-def create_items(conf, num=None, folder=None):
- for item in TEST_ITEMS:
- if item['name'] == 'mail':
- info = item
-
- if num:
- info['number'] = int(num)
-
- conf.log.debug(_("Creating %d Mails") %(info['number']), level=3)
-
- imap = True
-
- for user in conf.testing_users:
- if conf.use_mail:
- pass
- elif conf.use_lmtp:
- pass
- elif conf.use_imap:
- import imaplib
- if imap:
- del imap
- imap = imaplib.IMAP4(conf.testing_server)
- imap.login("%(givenname)s@%(domain)s" %(user), user['password'])
- else:
- pass
-
- mb = mailbox.mbox('./share/tests/mail/lists.fedoraproject.org/devel/2010-September.txt')
- for key in mb.keys():
-
- msg = mb.get_string(key)
-
- if conf.use_mail:
- conf.log.debug(_("Sending message %s through SMTP targeting user %s@%s") %(key,user['givenname'],user['domain']), level=9)
-
- elif conf.use_lmtp:
- conf.log.debug(_("Sending message %s through LMTP targeting user %s@%s") %(key,user['givenname'],user['domain']), level=9)
-
- elif conf.use_imap:
- conf.log.debug(_("Saving message %s to IMAP (user %s, folder %s)") %(key,user['givenname'],"INBOX"), level=9)
- imap.append("INBOX", '', imaplib.Time2Internaldate(time.time()), msg)
- else:
- conf.log.debug(_("Somehow ended up NOT sending these messages"), level=9)
diff --git a/pykolab/tests/tests.py b/pykolab/tests/tests.py
new file mode 100644
index 0000000..8a3c915
--- /dev/null
+++ b/pykolab/tests/tests.py
@@ -0,0 +1,192 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+import os
+import sys
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.tests')
+conf = pykolab.getConf()
+
+tests = {}
+test_groups = {}
+
+def __init__():
+ # We only want the base path
+ tests_base_path = os.path.dirname(__file__)
+
+ for tests_path, dirnames, filenames in os.walk(tests_base_path):
+ if not tests_path == tests_base_path:
+ continue
+
+ for filename in filenames:
+ #print filename
+ 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))
+
+ for dirname in dirnames:
+ register_group(tests_path, dirname)
+
+ register('help', list_tests, description=_("List tests"))
+
+def list_tests(*args, **kw):
+ """
+ List tests
+ """
+
+ __tests = {}
+
+ for test in tests.keys():
+ if isinstance(test, tuple):
+ test_group, test = test
+ __tests[test_group] = {
+ test: tests[(test_group,test)]
+ }
+ else:
+ __tests[test] = tests[test]
+
+ _tests = __tests.keys()
+ _tests.sort()
+
+ for _test in _tests:
+ if not __tests[_test].has_key('group'):
+ 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'])
+ else:
+ 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"
+ ___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'])
+ else:
+ print "%-4s%-21s" %('',__test.replace('_','-'))
+
+def execute(test_name, *args, **kw):
+ print "tests:", tests
+ print "test_name:", test_name
+
+ if not tests.has_key(test_name):
+ log.error(_("No such test."))
+ sys.exit(1)
+
+ if not tests[test_name].has_key('function') and \
+ not tests[test_name].has_key('group'):
+ log.error(_("No such test."))
+ sys.exit(1)
+
+ if tests[test_name].has_key('group'):
+ 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))
+ 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))
+ except ImportError, e:
+ pass
+
+ conf.finalize_conf()
+
+ tests[test_name]['function'](conf.cli_args, kw)
+
+def register_group(dirname, module):
+ tests_base_path = os.path.join(os.path.dirname(__file__), module)
+
+ tests[module] = {}
+
+ for tests_path, dirnames, filenames in os.walk(tests_base_path):
+ if not tests_path == tests_base_path:
+ continue
+
+ for filename in filenames:
+ 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))
+
+def register(test_name, func, group=None, description=None, aliases=[]):
+ if not group == None:
+ test = "%s_%s" %(group,test_name)
+ else:
+ test = test_name
+
+ #print "registering", test
+
+ if isinstance(aliases, basestring):
+ aliases = [aliases]
+
+ if tests.has_key(test):
+ log.fatal(_("Test '%s' already registered") %(test))
+ sys.exit(1)
+
+ if tests.has_key(test):
+ log.fatal(_("Test '%s' already registered") %(test))
+ sys.exit(1)
+
+ if callable(func):
+ if group == None:
+ tests[test_name] = {
+ 'function': func,
+ 'description': description
+ }
+ else:
+ tests[group][test_name] = {
+ 'function': func,
+ 'description': description
+ }
+
+ tests[test] = tests[group][test_name]
+ tests[test]['group'] = group
+ tests[test]['test_name'] = test_name
+
+ for alias in aliases:
+ tests[alias] = {
+ 'function': func,
+ 'description': _("Alias for %s") %(test_name)
+ }
+
+##
+## Tests not yet implemented
+##
+
+def not_yet_implemented(*args, **kw):
+ print _("Not yet implemented")
+ sys.exit(1)
\ No newline at end of file
diff --git a/pykolab/tests/wap/__init__.py b/pykolab/tests/wap/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pykolab/tests/wap/test_login.py b/pykolab/tests/wap/test_login.py
new file mode 100644
index 0000000..5eed57b
--- /dev/null
+++ b/pykolab/tests/wap/test_login.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+from pykolab.tests import tests
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.tests')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ tests.register('login', execute, group='wap', description=description())
+
+def description():
+ return """Log in to the Kolab Web Administration Panel API."""
+
+def execute(*args, **kw):
+ return
+
diff --git a/pykolab/tests/zpush/__init__.py b/pykolab/tests/zpush/__init__.py
deleted file mode 100644
index d0af89e..0000000
--- a/pykolab/tests/zpush/__init__.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
-#
-# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 3 or, at your option, any later version
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Library General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-
-import imp
-import os
-import sys
-
-import pykolab
-
-from pykolab.constants import *
-from pykolab.tests.constants import *
-from pykolab.translate import _
-
-log = pykolab.getLogger('pykolab.tests.zpush')
-conf = pykolab.getConf()
-
-class ZpushTest(object):
- def __init__(self):
- self.tests = []
-
- # Make sure we parse the [testing] section of the configuration file, if
- # available.
- conf.set_options_from_testing_section()
-
- # Attempt to create a list of modules
- for x in range(0,8):
- for y in range(0,8):
- test_num = "%s_%s" %(str(x).zfill(3),str(y).zfill(3))
- try:
- exec("from test_%s import Test_%s" %(test_num,test_num))
- self.tests.append("Test_%s" %(test_num))
- except ImportError, e:
- pass
-
- for test in self.tests:
- exec("result = %s()" %(test))
-
- #name = "from pykolab.tests.zpush.test_%s import Test_%s" %(test_num,test_num)
- #file, pathname, description = imp.find_module(name, sys.path)
-
- #try:
- #plugin = imp.load_module(mod_name, file, pathname, description)
- #finally:
- #file.close()
- #plugins[name] = plugin
-
-#print plugins
diff --git a/pykolab/tests/zpush/test_000_000.py b/pykolab/tests/zpush/test_000_000.py
deleted file mode 100644
index d5197a3..0000000
--- a/pykolab/tests/zpush/test_000_000.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
-#
-# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 3 or, at your option, any later version
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Library General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-
-import pykolab
-
-from pykolab import utils
-from pykolab.constants import *
-from pykolab.tests.constants import *
-from pykolab.translate import _
-
-log = pykolab.getLogger('pykolab.tests.zpush')
-conf = pykolab.getConf()
-
-class Test_000_000(object):
- """
- Preparations for the Test 000 series.
- """
-
- def __init__(self):
- self.suite_num = "000"
- self.suite_test_num = "000"
-
- log.info("About to execute preperation task #000 in Test Suite #000");
- log.info("We will assume the start situation has been configured");
- log.info("such as is described in the documentation.");
-
- utils.ask_confirmation("Continue?")
-
- # Delete all mailboxes
- #imap.connect()
- #for folder in imap.lm("user/%"):
- #imap.dm(folder)
-
- #for user in auth.list_users(domain):
- #for mailbox in imap.lm("user%s%s" %(imap.SEP,"%(givenname)s@%(domain)s" %(user))):
- #log.debug(_("Deleting mailbox: %s") %(mailbox), level=3)
- #try:
- #imap.dm(mailbox)
- #except cyruslib.CYRUSError, e:
- #pass
-
- ## Recreate the user top-level mailboxes
- #for user in conf.testing_users:
- #mailbox = "user%s%s" %(imap.SEP,"%(givenname)s@%(domain)s" %(user))
- #log.debug(_("Creating mailbox: %s") %(mailbox), level=3)
- #imap.cm(mailbox)
-
- #imap.logout()
-
- #del imap
-
- # Have the user themselves:
- # - create the standard folders
- # - set the standard annotations
- # - subscribe
- for user in conf.testing_users:
- imap = cyruslib.CYRUS("imap://%s:143" %(conf.testing_server))
- try:
- imap.login("%(givenname)s.%(surname)s@%(domain)s" %(user), user['password'])
- except:
- log.error(_("Authentication failure for %s") %("%(givenname)s.%(surname)s@%(domain)s" %(user)))
- continue
-
- if conf.debuglevel > 3:
- imap.VERBOSE = True
-
- imap.subscribe("INBOX")
-
- for mailbox in TEST_FOLDERS.keys():
- imap.cm("%s" %(mailbox))
- for annotation in TEST_FOLDERS[mailbox]['annotations'].keys():
- imap.setannotation("%s" %(mailbox),annotation,TEST_FOLDERS[mailbox]['annotations'][annotation])
-
- imap.subscribe("%s" %(mailbox))
-
- imap.logout()
- del imap
\ No newline at end of file
diff --git a/pykolab/tests/zpush/test_000_001.py b/pykolab/tests/zpush/test_000_001.py
deleted file mode 100644
index cadd9e5..0000000
--- a/pykolab/tests/zpush/test_000_001.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
-#
-# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 3 or, at your option, any later version
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Library General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-
-import pykolab
-
-from pykolab import utils
-from pykolab.constants import *
-from pykolab.tests.constants import *
-from pykolab.translate import _
-
-log = pykolab.getLogger('pykolab.tests.zpush')
-conf = pykolab.getConf()
-
-class Test_000_001(object):
- """
- First, basic test.
-
- Populate the previously created and existing INBOX, Calendar and Contact
- folders with a limited amount of data.
- """
-
- def __init__(self, conf):
- self.suite_num = "000"
- self.suite_test_num = "001"
-
- # Create some test calendar items
- for item in TEST_ITEMS:
- try:
- exec("from pykolab.tests.%s import %sItem, create_items as create_%s_items" %(item['name'],item['name'].capitalize(),item['name']))
- except ImportError, e:
- self.conf.log.warning(_("Could not load %sItem from %s, skipping the testing.") %(item['name'].capitalize(),item['name']))
- continue
-
- self.conf.log.debug("self.conf.%s = %r" %(item['name'], getattr(self.conf, "%s" %(item['name']))), level=9)
-
- if getattr(self.conf, "%s" %(item['name'])):
- exec("create_%s_items(self.conf, num=%d)" %(item['name'],item['number']))
- else:
- self.conf.log.info("not executing %s" %(item['name'].capitalize()))
commit 3533710ef014bf541daa2d0107bae8b34a8e9a20
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Mar 2 15:46:00 2012 +0000
Add additional commands
diff --git a/pykolab/cli/cmd_remove_mailaddress.py b/pykolab/cli/cmd_remove_mailaddress.py
new file mode 100644
index 0000000..6a4daea
--- /dev/null
+++ b/pykolab/cli/cmd_remove_mailaddress.py
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+import commands
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ commands.register('remove_mail', execute, description=description())
+
+def description():
+ return """Remove a user's mail address."""
+
+def execute(*args, **kw):
+ uid = conf.cli_args.pop(0)
+ email_address = conf.cli_args.pop(0)
+
+ user = auth.find_user('uid', uid)
+ user = {
+ 'dn': user
+ }
+
+ user['mail'] = auth.get_user_attribute('klab.cc', user, 'mail')
+ user['mailalternateaddress'] = auth.get_user_attribute('klab.cc', user, 'mailalternateaddress')
+
+ if user['mail'] == email_address:
+ auth.set_user_attribute('klab.cc', user, 'mail', '')
+
+ if email_address in user['mailalternateaddress']:
+ _user_addresses = []
+ for address in user['mailalternateaddress']:
+ if not address == email_address:
+ _user_addresses.append(address)
+
+ auth.set_user_attribute('klab.cc', user, 'mailAlternateAddress', _user_addresses)
\ No newline at end of file
diff --git a/pykolab/cli/cmd_set_language.py b/pykolab/cli/cmd_set_language.py
new file mode 100644
index 0000000..6b94d42
--- /dev/null
+++ b/pykolab/cli/cmd_set_language.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+import commands
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ commands.register('set_language', execute, description=description())
+
+def description():
+ return """Set the user's preferred language."""
+
+def execute(*args, **kw):
+ uid = conf.cli_args.pop(0)
+ language = conf.cli_args.pop(0)
+
+ user = auth.find_user('uid', uid)
+ auth.set_user_attribute('klab.cc', user, 'preferredlanguage', language)
+
diff --git a/pykolab/cli/cmd_set_mail.py b/pykolab/cli/cmd_set_mail.py
new file mode 100644
index 0000000..2d4e75c
--- /dev/null
+++ b/pykolab/cli/cmd_set_mail.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+import commands
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ commands.register('set_mail', execute, description=description())
+
+def description():
+ return """Set the user's primary email address."""
+
+def execute(*args, **kw):
+ uid = conf.cli_args.pop(0)
+ primary_mail = conf.cli_args.pop(0)
+
+ user = auth.find_user('uid', uid)
+ auth.set_user_attribute('klab.cc', user, 'mail', primary_mail)
+
diff --git a/pykolab/cli/cmd_transfer_mailbox.py b/pykolab/cli/cmd_transfer_mailbox.py
new file mode 100644
index 0000000..4f0de09
--- /dev/null
+++ b/pykolab/cli/cmd_transfer_mailbox.py
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+import commands
+
+import pykolab
+
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+auth = pykolab.auth
+imap = pykolab.imap
+
+def __init__():
+ commands.register('transfer_mailbox', execute, description="Transfer a mailbox to another server.")
+
+def execute(*args, **kw):
+ """
+ Transfer mailbox
+ """
+
+ if len(conf.cli_args) > 1:
+ mailfolder = conf.cli_args.pop(0)
+ target_server = conf.cli_args.pop(0)
+
+ if len(conf.cli_args) > 0:
+ target_partition = conf.cli_args.pop(0)
+
+ mbox_parts = imap.parse_mailfolder(mailfolder)
+
+ print "Mailbox parts:", mbox_parts
+
+ 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'])
+
+ print "User Identifier:", user_identifier
+
+ user = auth.find_user("mail", user_identifier)
+
+ print "User:", user
+
+ imap.connect()
+ imap.imap.xfer(mailfolder, target_server)
+
+ auth.set_user_attribute(mbox_parts['domain'], user, "mailHost", target_server)
commit 3334c2ed460ef138f1ed3a9f3e01c2cc6ab24531
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Mar 2 15:45:29 2012 +0000
Convert command list-domains to using the wap client
diff --git a/pykolab/cli/cmd_list_domains.py b/pykolab/cli/cmd_list_domains.py
index 7a2bfd8..0bc2d27 100644
--- a/pykolab/cli/cmd_list_domains.py
+++ b/pykolab/cli/cmd_list_domains.py
@@ -22,33 +22,30 @@ import commands
import pykolab
from pykolab.translate import _
+from pykolab import wap_client
log = pykolab.getLogger('pykolab.cli')
conf = pykolab.getConf()
-auth = pykolab.auth
-imap = pykolab.imap
-
def __init__():
commands.register('list_domains', execute, description="List Kolab domains.")
def execute(*args, **kw):
- auth.connect()
-
# Create the authentication object.
# TODO: Binds with superuser credentials!
- domains = auth.list_domains()
+ wap_client.authenticate()
+ domains = wap_client.domains_list()
+
+ #print "domains:", domains['list']
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.
- for domain,domain_aliases in domains:
- if len(domain_aliases) > 0:
- print _("%-39s %-40s") %(
- domain,
- ', '.join(domain_aliases)
- )
+ for domain_dn in domains['list'].keys():
+ 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)
else:
- print _("%-39s") %(domain)
-
+ print domains['list'][domain_dn]['associateddomain']
commit 00d655a36452fd023062ae5cafe2080c46f79441
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Mar 2 15:44:56 2012 +0000
Add the command-line wap client
diff --git a/pykolab/wap_client/__init__.py b/pykolab/wap_client/__init__.py
new file mode 100644
index 0000000..c84790d
--- /dev/null
+++ b/pykolab/wap_client/__init__.py
@@ -0,0 +1,281 @@
+
+import json
+import httplib
+import sys
+
+sys.path.append('../..')
+
+from pykolab import utils
+
+API_HOSTNAME = "admin.klab.cc"
+API_PORT = "80"
+API_SCHEME = "http"
+API_BASE = "/~vanmeeuwen/kolab-wap/public_html/api"
+
+session_id = None
+
+conn = None
+
+def authenticate(username=None, password=None):
+ global session_id
+
+ if username == None:
+ username = utils.ask_question("Login", "cn=Directory Manager")
+
+ if password == None:
+ password = utils.ask_question("Password", "5auTYwxBK1uGTpy", password=True)
+
+ params = json.dumps(
+ {
+ 'username': username,
+ 'password': password
+ }
+ )
+
+ response = request('POST', "system.authenticate", params)
+
+ if response.has_key('session_token'):
+ session_id = response['session_token']
+
+def connect():
+ global conn
+
+ if conn == None:
+ conn = httplib.HTTPConnection(API_HOSTNAME, API_PORT)
+ conn.connect()
+
+ return conn
+
+def domains_capabilities():
+ return request('GET', 'domains.capabilities')
+
+def domains_list():
+ return request('GET', 'domains.list')
+
+def get_group_input():
+ group_types = group_types_list()
+
+ if len(group_types.keys()) > 1:
+ for key in group_types.keys():
+ if not key == "status":
+ print "%s) %s" %(key,group_types[key]['name'])
+
+ group_type_id = utils.ask_question("Please select the group type")
+
+ elif len(group_types.keys()) > 0:
+ print "Automatically selected the only group type available"
+ group_type_id = group_types.keys()[0]
+
+ else:
+ print "No group types available"
+ sys.exit(1)
+
+ if group_types.has_key(group_type_id):
+ group_type_info = group_types[group_type_id]['attributes']
+ else:
+ print "No such group type"
+ sys.exit(1)
+
+ params = {
+ 'group_type_id': group_type_id
+ }
+
+ for attribute in group_type_info['form_fields'].keys():
+ 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))
+ params[attribute] = retval[attribute]
+
+ return params
+
+def get_user_input():
+ user_types = user_types_list()
+
+ if len(user_types.keys()) > 1:
+ for key in user_types.keys():
+ if not key == "status":
+ print "%s) %s" %(key,user_types[key]['name'])
+
+ user_type_id = utils.ask_question("Please select the user type")
+
+ elif len(user_types.keys()) > 0:
+ print "Automatically selected the only user type available"
+ user_type_id = user_types.keys()[0]
+
+ else:
+ print "No user types available"
+ sys.exit(1)
+
+ if user_types.has_key(user_type_id):
+ user_type_info = user_types[user_type_id]['attributes']
+ else:
+ print "No such user type"
+ sys.exit(1)
+
+ params = {
+ 'user_type_id': user_type_id
+ }
+
+ for attribute in user_type_info['form_fields'].keys():
+ params[attribute] = utils.ask_question(attribute)
+
+ for attribute in user_type_info['auto_form_fields'].keys():
+ exec("retval = form_value_generate_%s(params)" %(attribute))
+ params[attribute] = retval[attribute]
+
+ return params
+
+def group_add(params=None):
+ if params == None:
+ params = get_group_input()
+
+ params = json.dumps(params)
+
+ return request('POST', 'group.add', params)
+
+def group_form_value_generate_mail(params=None):
+ if params == None:
+ params = get_user_input()
+
+ params = json.dumps(params)
+
+ return request('POST', 'group_form_value.generate_mail', params)
+
+def group_info():
+ group = utils.ask_question("Group email address")
+ 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))
+ return group
+
+def group_types_list():
+ return request('GET', 'group_types.list')
+
+def groups_list():
+ return request('GET', 'groups.list')
+
+def request(method, api_uri, params=None, headers={}):
+ global session_id
+
+ if not session_id == None:
+ headers["X-Session-Token"] = session_id
+
+ conn = connect()
+ conn.request(method.upper(), "%s/%s" %(API_BASE,api_uri), params, headers)
+ response = conn.getresponse()
+ data = response.read()
+
+ #print method, api_uri, params
+ #print data
+
+ try:
+ response_data = json.loads(data)
+ except ValueError, e:
+ # Some data is not JSON
+ print "Response data is not JSON"
+ sys.exit(1)
+
+ #print response_data
+
+ if response_data['status'] == "OK":
+ del response_data['status']
+ return response_data['result']
+ else:
+ return response_data['result']
+
+def system_capabilities():
+ return request('GET', 'system.capabilities')
+
+def system_get_domain():
+ return request('GET', '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))
+
+def user_add(params=None):
+ if params == None:
+ params = get_user_input()
+
+ params = json.dumps(params)
+
+ return request('POST', 'user.add', params)
+
+def user_delete(params=None):
+ if params == None:
+ params = {
+ 'user': utils.ask_question("Username for user to delete", "user")
+ }
+
+ params = json.dumps(params)
+
+ return request('POST', 'user.delete', params)
+
+def user_edit(params=None):
+ if params == None:
+ params = {
+ 'user': utils.ask_question("Username for user to edit", "user")
+ }
+
+ params = json.dumps(params)
+
+ user = request('GET', 'user.info', params)
+
+ return user
+
+def user_form_value_generate_cn(params=None):
+ if params == None:
+ params = get_user_input()
+
+ params = json.dumps(params)
+
+ return request('POST', 'user_form_value.generate_cn', params)
+
+def user_form_value_generate_displayname(params=None):
+ if params == None:
+ params = get_user_input()
+
+ params = json.dumps(params)
+
+ return request('POST', 'user_form_value.generate_displayname', params)
+
+def user_form_value_generate_mail(params=None):
+ if params == None:
+ params = get_user_input()
+
+ params = json.dumps(params)
+
+ return request('POST', 'user_form_value.generate_mail', params)
+
+def user_form_value_generate_password(*args, **kw):
+ return request('GET', 'user_form_value.generate_password')
+
+def user_form_value_generate_uid(params=None):
+ if params == None:
+ params = get_user_input()
+
+ params = json.dumps(params)
+
+ return request('POST', 'user_form_value.generate_uid', params)
+
+def user_form_value_generate_userpassword(*args, **kw):
+ result = user_form_value_generate_password()
+ return { 'userpassword': result['password'] }
+
+def user_info():
+ user = utils.ask_question("User email address")
+ user = request('GET', 'user.info?user=%s' %(user))
+ return user
+
+def user_types_list():
+ return request('GET', 'user_types.list')
+
+def users_list():
+ return request('GET', 'users.list')
+
commit 5c3cb04cbc195d6e20824cb80fa12173623eb9db
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Mar 2 12:48:59 2012 +0000
conf.get_list() should always return a list
diff --git a/pykolab/conf/__init__.py b/pykolab/conf/__init__.py
index e6db94e..01282f2 100644
--- a/pykolab/conf/__init__.py
+++ b/pykolab/conf/__init__.py
@@ -463,12 +463,12 @@ class Conf(object):
setting = self.get_raw(section, key)
if setting == None:
- return None
+ return []
raw_values = setting.split(',')
if raw_values == None:
- return None
+ return []
for raw_value in raw_values:
untrimmed_values.extend(raw_value.split(' '))
commit ca23a3074be34a28b1595e9db167b7a6f7459645
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Feb 24 13:40:29 2012 +0000
Do not reset the retval for each plugin
diff --git a/pykolab/plugins/__init__.py b/pykolab/plugins/__init__.py
index d308b6a..e21c1cc 100644
--- a/pykolab/plugins/__init__.py
+++ b/pykolab/plugins/__init__.py
@@ -222,8 +222,6 @@ class KolabPlugins(object):
if not hasattr(self,plugin):
continue
- retval = None
-
if hasattr(getattr(self,plugin),hook):
try:
log.debug(_("Executing hook %s for plugin %s") %(hook,plugin), level=8)
commit b3d17f8b87a9b9a9864ec701bbf3d2105f613914
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Feb 24 13:28:52 2012 +0000
Bump prerelease
diff --git a/configure.ac b/configure.ac
index 7ec8451..ffd2f35 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_INIT([pykolab], 0.3)
-AC_SUBST([RELEASE], 0.15)
+AC_SUBST([RELEASE], 0.16)
AC_CONFIG_SRCDIR(pykolab/constants.py.in)
commit 8e8f0ce73e30e07f6edc9089bdc8f3445fbc57bc
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Feb 24 13:28:26 2012 +0000
Remove additional print statement
diff --git a/pykolab/plugins/__init__.py b/pykolab/plugins/__init__.py
index 2dff5b8..d308b6a 100644
--- a/pykolab/plugins/__init__.py
+++ b/pykolab/plugins/__init__.py
@@ -227,7 +227,7 @@ 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)
+ #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))
commit c81b96a5c629dc20cc4a79eda9f124e78f807ea6
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Feb 24 13:22:17 2012 +0000
Bump prerelease
diff --git a/configure.ac b/configure.ac
index 47a49fa..7ec8451 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_INIT([pykolab], 0.3)
-AC_SUBST([RELEASE], 0.14)
+AC_SUBST([RELEASE], 0.15)
AC_CONFIG_SRCDIR(pykolab/constants.py.in)
commit a20f3891f03a8509fd5f23025fb945995bcdde18
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Feb 24 13:21:59 2012 +0000
Do not solely support syncrepl (this is a development thing)
diff --git a/pykolab/constants.py.in b/pykolab/constants.py.in
index 68fb9b2..85f5c38 100644
--- a/pykolab/constants.py.in
+++ b/pykolab/constants.py.in
@@ -106,5 +106,18 @@ SUPPORTED_LDAP_CONTROLS = {
'desc': 'Virtual List View Control',
'oid': '2.16.840.1.113730.3.4.9',
'func': '_vlv_search'
+ },
+ 3: {
+ 'desc': 'OpenLDAP Syncrepl (RFC4533)',
+ 'oid': '1.3.6.1.4.1.4203.1.9.1.1',
+ 'func': '_sync_repl'
}
}
+
+#SUPPORTED_LDAP_CONTROLS = {
+# 0: {
+# 'desc': 'OpenLDAP Syncrepl (RFC4533)',
+# 'oid': '1.3.6.1.4.1.4203.1.9.1.1',
+# 'func': '_sync_repl'
+# }
+# }
commit ec88785a50e045fced5ed7f86efd0c6e91fc7c61
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Feb 24 13:21:18 2012 +0000
Mandatorily add uid to the list of authentication attributes to search for
Start on sync_repl support
diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py
index c0cd60a..c52bd55 100644
--- a/pykolab/auth/ldap/__init__.py
+++ b/pykolab/auth/ldap/__init__.py
@@ -254,6 +254,9 @@ class LDAP(object):
else:
auth_search_attrs = [ 'uid', 'mail' ]
+ if not 'uid' in auth_search_attrs:
+ auth_search_attrs.append('uid')
+
auth_search_filter = [ '(|' ]
for auth_search_attr in auth_search_attrs:
@@ -542,6 +545,41 @@ class LDAP(object):
):
pass
+ def _sync_repl(self,
+ base_dn,
+ scope=ldap.SCOPE_SUBTREE,
+ filterstr="(objectClass=*)",
+ attrlist=None,
+ attrsonly=0,
+ timeout=-1,
+ callback=False,
+ primary_domain=None,
+ secondary_domains=[]
+ ):
+
+ import syncrepl
+
+ ldap_sync_conn = syncrepl.DNSync(
+ '/var/lib/pykolab/syncrepl.db',
+ ldap_url.initializeUrl(),
+ trace_level=ldapmodule_trace_level,
+ trace_file=ldapmodule_trace_file
+ )
+
+ msgid = ldap_sync_conn.syncrepl_search(
+ base_dn,
+ scope,
+ mode='refreshAndPersist',
+ filterstr=filterstr
+ )
+
+ try:
+ # Here's where returns need to be taken into account...
+ while ldap_sync_conn.syncrepl_poll(all=1, msgid=msgid):
+ pass
+ except KeyboardInterrupt:
+ pass
+
def _regular_search(self,
base_dn,
scope=ldap.SCOPE_SUBTREE,
@@ -947,7 +985,13 @@ class LDAP(object):
quiet=True
)
- self.ldap.simple_bind_s(bind_dn, bind_pw)
+ 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']))
+ # TODO: Exit the fork (if fork!)
+ return
# TODO: The quota and alternative address attributes are actually
# supposed to be settings.
commit bab75f963d922fdbac6b86290f29312d74763c09
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Fri Feb 24 13:20:58 2012 +0000
Remove print statements
diff --git a/pykolab/imap/cyrus.py b/pykolab/imap/cyrus.py
index 8141dce..b9fb6e3 100644
--- a/pykolab/imap/cyrus.py
+++ b/pykolab/imap/cyrus.py
@@ -107,7 +107,11 @@ class Cyrus(cyruslib.CYRUS):
def find_mailfolder_server(self, mailfolder):
annotations = {}
+ #print "mailfolder:", mailfolder
+
_mailfolder = self.parse_mailfolder(mailfolder)
+ #print "_mailfolder:", _mailfolder
+
prefix = _mailfolder['path_parts'].pop(0)
mbox = _mailfolder['path_parts'].pop(0)
if not _mailfolder['domain'] == None:
@@ -161,6 +165,7 @@ class Cyrus(cyruslib.CYRUS):
Login to the actual backend server.
"""
server = self.find_mailfolder_server(mailfolder)
+ #print "server:", server
imap.connect('imap://%s:143' %(server))
log.debug(_("Setting quota for INBOX folder %s to %s") %(mailfolder,quota), level=8)
More information about the commits
mailing list