12 commits - cyruslib.py kolabd/__init__.py pykolab/auth pykolab/cli pykolab/imap pykolab/plugins pykolab.spec.in pykolab/utils.py saslauthd/__init__.py wallace/__init__.py
Jeroen van Meeuwen
vanmeeuwen at kolabsys.com
Wed Jun 13 12:48:20 CEST 2012
cyruslib.py | 21 +++++
kolabd/__init__.py | 6 +
pykolab.spec.in | 2
pykolab/auth/ldap/__init__.py | 106 +++++++++++++++++-----------
pykolab/cli/cmd_list_mailboxes.py | 2
pykolab/cli/cmd_list_quota.py | 64 ++++++++++++++++
pykolab/cli/cmd_sync.py | 5 +
pykolab/imap/__init__.py | 37 ++++++---
pykolab/plugins/recipientpolicy/__init__.py | 18 ++++
pykolab/utils.py | 73 +++++++++++++++++++
saslauthd/__init__.py | 12 +++
wallace/__init__.py | 6 +
12 files changed, 296 insertions(+), 56 deletions(-)
New commits:
commit 968f53e040591fce8790cd0aba030f6f6810e758
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 11:47:42 2012 +0100
Some pylint errors,
Add lq/lqr functions
diff --git a/pykolab/imap/__init__.py b/pykolab/imap/__init__.py
index dde09ff..047e908 100644
--- a/pykolab/imap/__init__.py
+++ b/pykolab/imap/__init__.py
@@ -300,12 +300,18 @@ class IMAP(object):
)
if not additional_folders == None:
- self.user_mailbox_create_additional_folders(mailbox_base_name, additional_folders)
+ self.user_mailbox_create_additional_folders(
+ mailbox_base_name,
+ additional_folders
+ )
return folder_name
def user_mailbox_create_additional_folders(self, folder, additional_folders):
- log.debug(_("Creating additional folders for user %s") % (folder), level=8)
+ log.debug(
+ _("Creating additional folders for user %s") % (folder),
+ level=8
+ )
for additional_folder in additional_folders.keys():
_add_folder = {}
@@ -397,6 +403,9 @@ class IMAP(object):
"""
return self.has_folder('user%s%s' %(self.imap.separator, mailbox_base_name))
+ def user_mailbox_quota(self, mailbox_quota):
+ pass
+
def user_mailbox_rename(self, old_name, new_name):
old_name = "user%s%s" % (self.imap.separator,old_name)
new_name = "user%s%s" % (self.imap.separator,new_name)
@@ -688,6 +697,12 @@ class IMAP(object):
self.imap.dm(mailfolder_path)
+ def get_quota(self, mailfolder_path):
+ return self.lq(mailfolder_path)
+
+ def get_quota_root(self, mailfolder_path):
+ return self.lqr(mailfolder_path)
+
def list_user_folders(self, primary_domain=None, secondary_domains=[]):
"""
List the INBOX folders in the IMAP backend. Returns a list of unique
@@ -737,5 +752,11 @@ class IMAP(object):
def lm(self, *args, **kw):
return self.imap.lm(*args, **kw)
+ def lq(self, *args, **kw):
+ return self.imap.lq(*args, **kw)
+
+ def lqr(self, *args, **kw):
+ return self.imap.lqr(*args, **kw)
+
def undelete_mailfolder(self, *args, **kw):
self.imap.undelete_mailfolder(*args, **kw)
commit 1d22592d4c67620effdbfb9fdf72b63bc8303ece
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 11:47:13 2012 +0100
Start implementing the quota enforcement again
diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py
index 32f43ff..7f25a24 100644
--- a/pykolab/auth/ldap/__init__.py
+++ b/pykolab/auth/ldap/__init__.py
@@ -792,6 +792,21 @@ class LDAP(pykolab.base.Base):
callback=self._synchronize_callback,
)
+ def user_quota(self, entry_id, folder):
+ quota_attribute = self.config_get('quota_attribute')
+
+ if quota_attribute == None:
+ return
+
+ self._bind()
+
+ entry_dn = self.entry_dn(entry_id)
+
+ current_ldap_quota = self.get_entry_attribute(entry_dn, quota_attribute)
+ current_imap_quota = self.imap.get_quota(folder)
+
+ default_quota = self.config_get('default_quota')
+
###
### API depth level increasing!
###
@@ -942,6 +957,8 @@ class LDAP(pykolab.base.Base):
if not entry[mailserver_attribute] == server:
self.set_entry_attribute(entry, mailserver_attribute, server)
+ self.user_quota(entry, folder)
+
def _change_delete_group(self, entry, change):
"""
An entry of type group was deleted.
commit dd9464f89d8a8632f5ae777b5964ff0d04be7bb9
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 11:46:45 2012 +0100
Clarify it's not UTF-7 exactly, it's IMAP UTF-7 ;-)
diff --git a/pykolab/cli/cmd_list_mailboxes.py b/pykolab/cli/cmd_list_mailboxes.py
index 185dea2..3451e7c 100644
--- a/pykolab/cli/cmd_list_mailboxes.py
+++ b/pykolab/cli/cmd_list_mailboxes.py
@@ -41,7 +41,7 @@ def cli_options():
dest = "raw",
action = "store_true",
default = False,
- help = _("Display raw UTF-7 folder names"))
+ help = _("Display raw IMAP UTF-7 folder names"))
def execute(*args, **kw):
"""
commit 8c1f5eb1594913d07d727409fb682dd5e6416b60
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 11:40:24 2012 +0100
Add command 'list-quota'
diff --git a/pykolab/cli/cmd_list_quota.py b/pykolab/cli/cmd_list_quota.py
new file mode 100644
index 0000000..d71f272
--- /dev/null
+++ b/pykolab/cli/cmd_list_quota.py
@@ -0,0 +1,64 @@
+# -*- 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 sys
+
+import commands
+
+import pykolab
+
+from pykolab.imap import IMAP
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+def __init__():
+ commands.register('list_quota', execute, description=description(), aliases=['lq'])
+
+def description():
+ return """List quota for a folder."""
+
+def execute(*args, **kw):
+ """
+ List quota for a mailbox
+ """
+
+ try:
+ quota_folder = conf.cli_args.pop(0)
+ except IndexError, e:
+ quota_folder = '*'
+
+ imap = IMAP()
+ imap.connect()
+
+ folders = []
+
+ quota_folders = imap.lm(quota_folder)
+ for quota_folder in quota_folders:
+ try:
+ (used, quota) = imap.get_quota(quota_folder)
+ percentage = round((used/quota)*100, 1)
+ print "%d (Used: %d, Percentage: %d)" % (quota, used, percentage)
+ except:
+ (quota_root, used, quota) = imap.get_quota_root(quota_folder)
+ percentage = round((used/quota)*100, 1)
+ print "%d (Root: %s, Used: %d, Percentage: %d)" % (quota, quota_root, used, percentage)
+
+
commit 9d544f1ed4f7181d11916d3cf19a00e08acfe1a3
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 11:39:54 2012 +0100
Fix command-line sync
diff --git a/pykolab/cli/cmd_sync.py b/pykolab/cli/cmd_sync.py
index 2cbb05f..4ac675a 100644
--- a/pykolab/cli/cmd_sync.py
+++ b/pykolab/cli/cmd_sync.py
@@ -19,8 +19,10 @@
import commands
+import time
import pykolab
+from pykolab.auth import Auth
from pykolab.translate import _
log = pykolab.getLogger('pykolab.cli')
@@ -30,6 +32,7 @@ def __init__():
commands.register('sync', execute, description="Synchronize Kolab Users with IMAP.")
def execute(*args, **kw):
+ auth = Auth()
log.debug(_("Listing domains..."), level=5)
start_time = time.time()
domains = auth.list_domains()
@@ -48,7 +51,7 @@ def execute(*args, **kw):
log.debug(_("Running for domain %s") % (primary_domain), level=8)
auth.connect(primary_domain)
start_time = time.time()
- auth.synchronize(primary_domain, secondary_domains)
+ auth.synchronize()
end_time = time.time()
log.info(_("Synchronizing users for %s took %d seconds")
commit f2247ae5bc393e813e3775c82e1c051dbbcabd78
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 11:39:18 2012 +0100
Add hard dependency on pyasn1{,-modules}
diff --git a/pykolab.spec.in b/pykolab.spec.in
index 5ff1d7d..332f692 100644
--- a/pykolab.spec.in
+++ b/pykolab.spec.in
@@ -31,6 +31,8 @@ BuildRequires: python-ldap
BuildRequires: python-nose
Requires: kolab-cli = %{version}-%{release}
Requires: python-ldap >= 2.4
+Requires: python-pyasn1
+Requires: python-pyasn1-modules
Requires(pre): /usr/sbin/useradd
Requires(pre): /usr/sbin/usermod
Requires(pre): /usr/sbin/groupadd
commit e3d33d10fbdbf362b89476fbdab6c7a6ca0a45fb
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 11:37:40 2012 +0100
Make use of the new ensure_directory() function (#840)
diff --git a/kolabd/__init__.py b/kolabd/__init__.py
index bf4fc7b..5283c9f 100644
--- a/kolabd/__init__.py
+++ b/kolabd/__init__.py
@@ -91,6 +91,12 @@ class KolabDaemon(object):
exitcode = 0
+ utils.ensure_directory(
+ os.path.dirname(conf.pidfile),
+ conf.process_username,
+ conf.process_groupname
+ )
+
try:
try:
(ruid, euid, suid) = os.getresuid()
diff --git a/saslauthd/__init__.py b/saslauthd/__init__.py
index 6daebf3..1497dda 100644
--- a/saslauthd/__init__.py
+++ b/saslauthd/__init__.py
@@ -60,6 +60,12 @@ class SASLAuthDaemon(object):
conf.finalize_conf()
+ utils.ensure_directory(
+ os.path.dirname(conf.pidfile),
+ conf.process_username,
+ conf.process_groupname
+ )
+
self.thread_count = 0
def run(self):
@@ -116,6 +122,12 @@ class SASLAuthDaemon(object):
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ utils.ensure_directory(
+ '/var/run/saslauthd/',
+ conf.process_username,
+ conf.process_groupname
+ )
+
# TODO: The saslauthd socket path could be a setting.
try:
os.remove('/var/run/saslauthd/mux')
diff --git a/wallace/__init__.py b/wallace/__init__.py
index 45ad211..5d056df 100644
--- a/wallace/__init__.py
+++ b/wallace/__init__.py
@@ -116,6 +116,12 @@ class WallaceDaemon(object):
conf.finalize_conf()
+ utils.ensure_directory(
+ os.path.dirname(conf.pidfile),
+ conf.process_username,
+ conf.process_groupname
+ )
+
import modules
modules.__init__()
commit 1df64e63556db23be0d701ca10c4fd35f87f9aec
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 11:37:19 2012 +0100
Add helper function to ensure a directory exists, and with the correct permissions
diff --git a/pykolab/utils.py b/pykolab/utils.py
index f0fa30a..f766983 100644
--- a/pykolab/utils.py
+++ b/pykolab/utils.py
@@ -121,6 +121,79 @@ def ask_confirmation(question, default="y", all_inclusive_no=True):
else:
return True
+def ensure_directory(_dir, _user='root', _group='root'):
+ os.makedirs(_dir)
+ try:
+ try:
+ (ruid, euid, suid) = os.getresuid()
+ (rgid, egid, sgid) = os.getresgid()
+ except AttributeError, errmsg:
+ ruid = os.getuid()
+ rgid = os.getgid()
+
+ if ruid == 0:
+ # Means we can setreuid() / setregid() / setgroups()
+ if rgid == 0:
+ # Get group entry details
+ try:
+ (
+ group_name,
+ group_password,
+ group_gid,
+ group_members
+ ) = grp.getgrnam(_group)
+
+ except KeyError:
+ print >> sys.stderr, _("Group %s does not exist") % (
+ _group
+ )
+
+ sys.exit(1)
+
+ # Set real and effective group if not the same as current.
+ if not group_gid == rgid:
+ log.debug(
+ _("Switching real and effective group id to %d") % (
+ group_gid
+ ),
+ level=8
+ )
+
+ os.chown(_dir, -1, group_gid)
+
+ if ruid == 0:
+ # Means we haven't switched yet.
+ try:
+ (
+ user_name,
+ user_password,
+ user_uid,
+ user_gid,
+ user_gecos,
+ user_homedir,
+ user_shell
+ ) = pwd.getpwnam(_user)
+
+ except KeyError:
+ print >> sys.stderr, _("User %s does not exist") % (_user)
+
+ sys.exit(1)
+
+
+ # Set real and effective user if not the same as current.
+ if not user_uid == ruid:
+ log.debug(
+ _("Switching real and effective user id to %d") % (
+ user_uid
+ ),
+ level=8
+ )
+
+ os.chown(_dir, user_uid, -1)
+
+ except:
+ log.error(_("Could not change the permissions on %s") % (_dir))
+
def generate_password():
import subprocess
commit d310f8a8ba453cc1030a6a83cbdd8332a5fb64ff
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 11:35:06 2012 +0100
Add QUOTAROOT command lqr
diff --git a/cyruslib.py b/cyruslib.py
index 7df43a0..20dd55b 100644
--- a/cyruslib.py
+++ b/cyruslib.py
@@ -586,6 +586,27 @@ class CYRUS:
self.__verbose( '[GETQUOTA %s] BAD: Error while parsing results' % mailbox )
return 0, 0
+ def lqr(self, mailbox):
+ """List Quota Root"""
+ self.__prepare('GETQUOTAROOT', mailbox)
+ res, msg = self.__docommand("getquotaroot", self.decode(mailbox))
+ (_mailbox, _root) = msg[0][0].split()
+
+ match = re_q0.match(msg[1][0])
+ if match:
+ self.__verbose( '[GETQUOTAROOT %s] QUOTAROOT (Unlimited)' % mailbox )
+ return _root, 0, 0
+
+ match = re_q.match(msg[1][0])
+ try:
+ used = int(match.group(2))
+ quota = int(match.group(3))
+ self.__verbose( '[GETQUOTAROOT %s] %s: QUOTA (%d/%d)' % (mailbox, res, used, quota) )
+ return _root, used, quota
+ except:
+ self.__verbose( '[GETQUOTAROOT %s] BAD: Error while parsing results' % mailbox )
+ return _root, 0, 0
+
def sq(self, mailbox, limit):
"""Set Quota"""
self.__prepare('SETQUOTA', mailbox)
commit 5c1c4c70bae2be6e50063434e8ec69ef89bd4983
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Tue Jun 12 13:08:50 2012 +0100
Search for or fallback to the default_locale for the user's preferredlanguage attribute. (#839)
diff --git a/pykolab/plugins/recipientpolicy/__init__.py b/pykolab/plugins/recipientpolicy/__init__.py
index ab72980..1c97857 100644
--- a/pykolab/plugins/recipientpolicy/__init__.py
+++ b/pykolab/plugins/recipientpolicy/__init__.py
@@ -61,6 +61,15 @@ class KolabRecipientpolicy(object):
elif not user_attrs['domain'] == kw['primary_domain']:
user_attrs['domain'] = kw['primary_domain']
+ if not user_attrs.has_key('preferredlanguage'):
+ default_locale = conf.get(user_attrs['domain'], 'default_locale')
+ if default_locale == None:
+ default_locale = conf.get(user_attrs['domain'], 'default_locale')
+ if default_locale == None:
+ default_locale = 'en_US'
+
+ user_attrs['preferredlanguage'] = default_locale
+
try:
mail = kw['primary_mail'] % user_attrs
mail = utils.translate(mail, user_attrs['preferredlanguage'])
@@ -91,6 +100,15 @@ class KolabRecipientpolicy(object):
elif not user_attrs['domain'] == kw['primary_domain']:
user_attrs['domain'] = kw['primary_domain']
+ if not user_attrs.has_key('preferredlanguage'):
+ default_locale = conf.get(user_attrs['domain'], 'default_locale')
+ if default_locale == None:
+ default_locale = conf.get(user_attrs['domain'], 'default_locale')
+ if default_locale == None:
+ default_locale = 'en_US'
+
+ user_attrs['preferredlanguage'] = default_locale
+
try:
exec("alternative_mail_routines = %s" % kw['secondary_mail'])
except Exception, e:
commit ac539faed494c3abdf6abbbae42fbb9dfcb4aad8
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Mon Jun 11 14:12:50 2012 +0100
Remove synchronize() function (obsolete)
diff --git a/pykolab/imap/__init__.py b/pykolab/imap/__init__.py
index 9735312..dde09ff 100644
--- a/pykolab/imap/__init__.py
+++ b/pykolab/imap/__init__.py
@@ -734,18 +734,6 @@ class IMAP(object):
return folders
- def synchronize(self, users=[], primary_domain=None, secondary_domains=[]):
- self.connect(domain=primary_domain)
- self.users.extend(users)
-
- self.move_user_folders(users, domain=primary_domain)
-
- self.inbox_folders.extend(self.create_user_folders(users, primary_domain, secondary_domains))
-
- self.set_user_folder_quota(users, primary_domain, secondary_domains, self.inbox_folders)
-
- self.set_user_mailhost(users, primary_domain, secondary_domains, self.inbox_folders)
-
def lm(self, *args, **kw):
return self.imap.lm(*args, **kw)
commit 3df45ed444e38853e683334b4a5cbdd7e3d17d2a
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Mon Jun 11 14:12:40 2012 +0100
Sort functions alphabetically
diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py
index c075742..32f43ff 100644
--- a/pykolab/auth/ldap/__init__.py
+++ b/pykolab/auth/ldap/__init__.py
@@ -818,50 +818,18 @@ class LDAP(pykolab.base.Base):
except ldap.INVALID_CREDENTIALS:
log.error(_("Invalid bind credentials"))
- def _change_add_user(self, entry, change):
- """
- An entry of type user was added.
+ def _change_add_group(self, entry, change):
"""
- mailserver_attribute = self.config_get('mailserver_attribute')
- if mailserver_attribute == None:
- mailserver_attribute = 'mailhost'
-
- result_attribute = conf.get('cyrus-sasl', 'result_attribute')
-
- if not entry.has_key(mailserver_attribute):
- entry[mailserver_attribute] = \
- self.get_entry_attribute(entry, mailserver_attribute)
-
- rcpt_addrs = self.recipient_policy(entry)
- for key in rcpt_addrs:
- entry[key] = rcpt_addrs[key]
-
- if not entry.has_key(result_attribute):
- return
-
- if entry[result_attribute] == None:
- return
-
- cache.get_entry(self.domain, entry)
-
- self.imap.connect(domain=self.domain)
-
- if not self.imap.user_mailbox_exists(entry[result_attribute]):
- folder = self.imap.user_mailbox_create(
- entry[result_attribute],
- entry[mailserver_attribute]
- )
- else:
- folder = "user%s%s" % (self.imap.separator,entry[result_attribute])
-
- server = self.imap.user_mailbox_server(folder)
+ An entry of type group was added.
- if not entry[mailserver_attribute] == server:
- self.set_entry_attribute(entry, mailserver_attribute, server)
+ The Kolab daemon has little to do for this type of action on this
+ type of entry.
+ """
+ pass
- def _change_add_group(self, entry, change):
+ def _change_add_resource(self, entry, change):
"""
- An entry of type group was added.
+ An entry of type resource was added.
The Kolab daemon has little to do for this type of action on this
type of entry.
@@ -933,6 +901,47 @@ class LDAP(pykolab.base.Base):
#if server == None:
#self.entry_set_attribute(mailserver_attribute, server)
+ def _change_add_user(self, entry, change):
+ """
+ An entry of type user was added.
+ """
+ mailserver_attribute = self.config_get('mailserver_attribute')
+ if mailserver_attribute == None:
+ mailserver_attribute = 'mailhost'
+
+ result_attribute = conf.get('cyrus-sasl', 'result_attribute')
+
+ if not entry.has_key(mailserver_attribute):
+ entry[mailserver_attribute] = \
+ self.get_entry_attribute(entry, mailserver_attribute)
+
+ rcpt_addrs = self.recipient_policy(entry)
+ for key in rcpt_addrs:
+ entry[key] = rcpt_addrs[key]
+
+ if not entry.has_key(result_attribute):
+ return
+
+ if entry[result_attribute] == None:
+ return
+
+ cache.get_entry(self.domain, entry)
+
+ self.imap.connect(domain=self.domain)
+
+ if not self.imap.user_mailbox_exists(entry[result_attribute]):
+ folder = self.imap.user_mailbox_create(
+ entry[result_attribute],
+ entry[mailserver_attribute]
+ )
+ else:
+ folder = "user%s%s" % (self.imap.separator,entry[result_attribute])
+
+ server = self.imap.user_mailbox_server(folder)
+
+ if not entry[mailserver_attribute] == server:
+ self.set_entry_attribute(entry, mailserver_attribute, server)
+
def _change_delete_group(self, entry, change):
"""
An entry of type group was deleted.
More information about the commits
mailing list