7 commits - cyruslib.py kolabd/__init__.py pykolab/auth pykolab/imap pykolab/plugins pykolab/utils.py saslauthd/__init__.py wallace/__init__.py
Jeroen van Meeuwen
vanmeeuwen at kolabsys.com
Wed Jun 13 18:01:27 CEST 2012
cyruslib.py | 10 -
kolabd/__init__.py | 1
pykolab/auth/ldap/__init__.py | 200 ++++++++++++++++++++++++++-----
pykolab/imap/__init__.py | 8 +
pykolab/imap/cyrus.py | 34 +++++
pykolab/plugins/dynamicquota/__init__.py | 67 ++++------
pykolab/utils.py | 16 +-
saslauthd/__init__.py | 1
wallace/__init__.py | 1
9 files changed, 253 insertions(+), 85 deletions(-)
New commits:
commit 44cf0065f458714edec23b1d6b093426cd493de1
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 17:01:05 2012 +0100
Add pykolab.imap.cyrus.Cyrus.connect()
diff --git a/pykolab/imap/cyrus.py b/pykolab/imap/cyrus.py
index ac580c9..af3e5b8 100644
--- a/pykolab/imap/cyrus.py
+++ b/pykolab/imap/cyrus.py
@@ -24,6 +24,7 @@ from urlparse import urlparse
import pykolab
+from pykolab.imap import IMAP
from pykolab.translate import _
log = pykolab.getLogger('pykolab.imap')
@@ -90,6 +91,37 @@ class Cyrus(cyruslib.CYRUS):
def __del__(self):
pass
+ def connect(self, uri):
+ """
+ Dummy connect function that checks if the server that we want to
+ connect to is actually the server we are connected to.
+
+ Uses pykolab.imap.IMAP.connect() in the background.
+ """
+ port = None
+
+ result = urlparse(uri)
+
+ if hasattr(result, 'hostname'):
+ scheme = result.scheme
+ hostname = result.hostname
+ port = result.port
+ else:
+ scheme = uri.split(':')[0]
+ (hostname, port) = uri.split('/')[2].split(':')
+
+ if not port:
+ if scheme == 'imap':
+ port = 143
+ else:
+ port = 993
+
+ if hostname == self.server:
+ return
+
+ imap = IMAP()
+ imap.connect(uri=uri)
+
def login(self, *args, **kw):
"""
Login to the Cyrus IMAP server through cyruslib.CYRUS, but set our
@@ -166,7 +198,7 @@ class Cyrus(cyruslib.CYRUS):
#print "server:", server
self.connect(self.uri.replace(self.server,server))
- log.debug(_("Setting quota for INBOX folder %s to %s") % (mailfolder,quota), level=8)
+ log.debug(_("Setting quota for folder %s to %s") % (mailfolder,quota), level=8)
try:
self.m.setquota(mailfolder, quota)
except:
commit 185be06162c19d9b4a5bacdfb10912829bcb79b6
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 17:00:42 2012 +0100
Add set_quota()
diff --git a/pykolab/imap/__init__.py b/pykolab/imap/__init__.py
index 047e908..25ec560 100644
--- a/pykolab/imap/__init__.py
+++ b/pykolab/imap/__init__.py
@@ -503,6 +503,9 @@ class IMAP(object):
else:
log.debug(_("Value for user is not a dictionary"), level=8)
+ def set_quota(self, folder, quota):
+ self.imap._setquota(folder, quota)
+
def set_user_folder_quota(self, users=[], primary_domain=None, secondary_domain=[], folders=[]):
"""
@@ -698,7 +701,10 @@ class IMAP(object):
self.imap.dm(mailfolder_path)
def get_quota(self, mailfolder_path):
- return self.lq(mailfolder_path)
+ try:
+ return self.lq(mailfolder_path)
+ except:
+ return
def get_quota_root(self, mailfolder_path):
return self.lqr(mailfolder_path)
commit 85e9ef8d3e5a8f4204b4bff2c546d3b1cc4dfe0d
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 16:59:33 2012 +0100
Reduce dynamicquota complexity for now
diff --git a/pykolab/plugins/dynamicquota/__init__.py b/pykolab/plugins/dynamicquota/__init__.py
index 6115dcd..62823ff 100644
--- a/pykolab/plugins/dynamicquota/__init__.py
+++ b/pykolab/plugins/dynamicquota/__init__.py
@@ -40,51 +40,42 @@ class KolabDynamicquota(object):
The arguments passed to the 'set_user_folder_quota' hook:
- used (integer, in KB)
- - current quota (integer, in KB)
- - quota (integer, in KB)
- - user
+ - imap_quota (current imap quota obtained from IMAP, integer, in KB)
+ - ldap_quota (current LDAP quota obtained from LDAP, integer, in KB)
+ - default_quota (integer, in KB)
+
+ Returns:
+
+ - None - an error has occurred and this plugin doesn't care.
+ - Negative 1 - remove quota.
+ - Zero - Absolute 0.
+ - Positive Integer - set new quota.
"""
- for keyword in [ 'used', 'current_quota', 'new_quota', 'default_quota' ]:
+ for keyword in [ 'used', 'imap_quota', 'ldap_quota', 'default_quota' ]:
if not kw.has_key(keyword):
- log.warning(_("No keyword %s passed to set_user_folder_quota") % (keyword))
- return 0
+ log.warning(
+ _("No keyword %s passed to set_user_folder_quota") % (
+ keyword
+ )
+ )
+
+ return
else:
try:
- kw[keyword] = (int)(kw[keyword])
+ if not kw[keyword] == None:
+ kw[keyword] = (int)(kw[keyword])
+
except:
log.error(_("Quota '%s' not an integer!") % (keyword))
- return 0
+ return
# Escape the user without quota
- if kw['new_quota'] == 0:
- # Unless default quota is set
- if kw['default_quota'] > 0:
- log.info(_("The new quota was set to 0, but default quota > 0, returning default quota"))
- return kw['default_quota']
-
- return 0
-
- # Make your adjustments here, for example:
- #
- # - increase the quota by 10% if the currently used storage size
- # is over 90%
-
- if kw['new_quota'] < int(float(kw['used']) * 1.1):
- _new_quota = int(float(kw['used']) * 1.1)
- elif kw['new_quota'] > int(float(kw['used']) * 1.1):
- # TODO: If the current quota in IMAP had been set to 0, but we want to apply quota, and
- # 0 is current_quota, 90% of that is still 0...
- _new_quota = int(float(kw['current_quota']) * 0.9)
-
- if kw['new_quota'] == 0:
- if kw['default_quota'] > _new_quota:
- log.info(_("The default quota is larger then the calculated new quota, using the default quota"))
- return kw['default_quota']
-
- else:
- new_quota = _new_quota
+ if kw['ldap_quota'] == None:
+ return kw['default_quota']
+ elif kw['ldap_quota'] == -1:
+ return -1
+ elif kw['ldap_quota'] > 0:
+ return kw['ldap_quota']
else:
- new_quota = kw['new_quota']
-
- return new_quota
+ return kw['default_quota']
\ No newline at end of file
commit f34e68f7c1a9b31de59a8d16a00db1fef69059d9
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 16:58:44 2012 +0100
Add user quota handling
Some lengthy line reductions
diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py
index 7f25a24..6ba82e8 100644
--- a/pykolab/auth/ldap/__init__.py
+++ b/pykolab/auth/ldap/__init__.py
@@ -438,7 +438,9 @@ class LDAP(pykolab.base.Base):
return _entry_dns
def get_latest_sync_timestamp(self):
- return cache.last_modify_timestamp(self.domain)
+ timestamp = cache.last_modify_timestamp(self.domain)
+ log.debug(_("Using timestamp %r") % (timestamp), level=9)
+ return timestamp
def list_secondary_domains(self):
"""
@@ -734,6 +736,7 @@ class LDAP(pykolab.base.Base):
return entry_modifications
def set_entry_attribute(self, entry_id, attribute, value):
+ log.debug(_("Setting entry attribute %r to %r for %r") % (attribute, value, entry_id), level=9)
self.set_entry_attributes(entry_id, { attribute: value })
def set_entry_attributes(self, entry_id, attributes):
@@ -793,19 +796,70 @@ class LDAP(pykolab.base.Base):
)
def user_quota(self, entry_id, folder):
+
+ default_quota = self.config_get('default_quota')
quota_attribute = self.config_get('quota_attribute')
if quota_attribute == None:
return
+ if default_quota == 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)
+ _imap_quota = self.imap.get_quota(folder)
+ if _imap_quota == None:
+ used = None
+ current_imap_quota = None
+ else:
+ (used, current_imap_quota) = _imap_quota
- default_quota = self.config_get('default_quota')
+ log.debug(
+ _("About to consider the user quota for %r (used: %r, " + \
+ "imap: %r, ldap: %r, default: %r") % (
+ entry_dn,
+ used,
+ current_imap_quota,
+ current_ldap_quota,
+ default_quota
+ ),
+ level=9
+ )
+
+ new_quota = conf.plugins.exec_hook("set_user_folder_quota", kw={
+ 'used': used,
+ 'imap_quota': current_imap_quota,
+ 'ldap_quota': current_ldap_quota,
+ 'default_quota': default_quota
+ }
+ )
+
+ if not current_ldap_quota == None:
+ if not new_quota == (int)(current_ldap_quota):
+ self.set_entry_attribute(
+ entry_dn,
+ quota_attribute,
+ "%s" % (new_quota)
+ )
+ else:
+ if not new_quota == None:
+ self.set_entry_attribute(
+ entry_dn,
+ quota_attribute,
+ "%s" % (new_quota)
+ )
+
+ if not current_imap_quota == None:
+ if not new_quota == current_imap_quota:
+ self.imap.set_quota(folder, new_quota)
+
+ else:
+ if not new_quota == None:
+ self.imap.set_quota(folder, new_quota)
###
### API depth level increasing!
@@ -890,7 +944,9 @@ class LDAP(pykolab.base.Base):
#'kolabmailfolderaclentry'
#)
- if entry.has_key('kolabtargetfolder') and not entry['kolabtargetfolder'] == None:
+ if entry.has_key('kolabtargetfolder') and \
+ not entry['kolabtargetfolder'] == None:
+
folder_path = entry['kolabtargetfolder']
else:
# TODO: What is *the* way to see if we need to create an @domain
@@ -907,11 +963,19 @@ class LDAP(pykolab.base.Base):
if not self.imap.shared_folder_exists(folder_path):
self.imap.shared_folder_create(folder_path, server)
- if entry.has_key('kolabfoldertype') and not entry['kolabfoldertype'] == None:
- self.imap.shared_folder_set_type(folder_path, entry['kolabfoldertype'])
+ if entry.has_key('kolabfoldertype') and \
+ not entry['kolabfoldertype'] == None:
+
+ self.imap.shared_folder_set_type(
+ folder_path,
+ entry['kolabfoldertype']
+ )
- #if entry.has_key('kolabmailfolderaclentry') and not entry['kolabmailfolderaclentry'] == None:
- #self.imap._set_kolab_mailfolder_acls(entry['kolabmailfolderaclentry'])
+ #if entry.has_key('kolabmailfolderaclentry') and \
+ #not entry['kolabmailfolderaclentry'] == None:
+ #self.imap._set_kolab_mailfolder_acls(
+ #entry['kolabmailfolderaclentry']
+ #)
#if server == None:
#self.entry_set_attribute(mailserver_attribute, server)
@@ -1071,13 +1135,19 @@ class LDAP(pykolab.base.Base):
for key in entry_changes.keys():
entry[key] = entry_changes[key]
- # Now look at entry_changes and old_canon_attr, and see if they're the
- # same value.
+ # Now look at entry_changes and old_canon_attr, and see if they're
+ # the same value.
if entry_changes.has_key(result_attribute):
if not old_canon_attr == None:
- self.imap.user_mailbox_create(entry_changes[result_attribute])
+ self.imap.user_mailbox_create(
+ entry_changes[result_attribute]
+ )
+
elif not entry_changes[result_attribute] == old_canon_attr:
- self.imap.user_mailbox_rename(old_canon_attr, entry_changes[result_attribute])
+ self.imap.user_mailbox_rename(
+ old_canon_attr,
+ entry_changes[result_attribute]
+ )
cache.get_entry(self.domain, entry)
@@ -1095,19 +1165,32 @@ class LDAP(pykolab.base.Base):
def _change_modify_user(self, entry, change):
for entry_key in conf.changelog.keys():
- log.debug(_("Current changelog entry %s with %s") % (entry_key,conf.changelog[entry_key]), level=8)
+ log.debug(
+ _("Current changelog entry %s with %s") % (
+ entry_key,
+ conf.changelog[entry_key]
+ ),
+ level=8
+ )
if conf.changelog.has_key(entry['id']):
old_canon_attr = conf.changelog[entry['id']]
entry_changes = self.recipient_policy(entry)
- log.debug(_("Result from recipient policy: %r") % (entry_changes), level=8)
+ log.debug(
+ _("Result from recipient policy: %r") % (entry_changes),
+ level=8
+ )
result_attribute = conf.get('cyrus-sasl','result_attribute')
if entry_changes.has_key(result_attribute):
if not entry_changes[result_attribute] == old_canon_attr:
- self.imap.user_mailbox_rename(old_canon_attr, entry_changes[result_attribute])
+ self.imap.user_mailbox_rename(
+ old_canon_attr,
+ entry_changes[result_attribute]
+ )
+
conf.changelog[entry['id']] = entry_changes[result_attribute]
def _change_none_group(self, entry, change):
@@ -1161,7 +1244,9 @@ class LDAP(pykolab.base.Base):
#'kolabmailfolderaclentry'
#)
- if entry.has_key('kolabtargetfolder') and not entry['kolabtargetfolder'] == None:
+ if entry.has_key('kolabtargetfolder') and \
+ not entry['kolabtargetfolder'] == None:
+
folder_path = entry['kolabtargetfolder']
else:
# TODO: What is *the* way to see if we need to create an @domain
@@ -1178,11 +1263,20 @@ class LDAP(pykolab.base.Base):
if not self.imap.shared_folder_exists(folder_path):
self.imap.shared_folder_create(folder_path, server)
- if entry.has_key('kolabfoldertype') and not entry['kolabfoldertype'] == None:
- self.imap.shared_folder_set_type(folder_path, entry['kolabfoldertype'])
+ if entry.has_key('kolabfoldertype') and \
+ not entry['kolabfoldertype'] == None:
- #if entry.has_key('kolabmailfolderaclentry') and not entry['kolabmailfolderaclentry'] == None:
- #self.imap._set_kolab_mailfolder_acls(entry['kolabmailfolderaclentry'])
+ self.imap.shared_folder_set_type(
+ folder_path,
+ entry['kolabfoldertype']
+ )
+
+ #if entry.has_key('kolabmailfolderaclentry') and \
+ #not entry['kolabmailfolderaclentry'] == None:
+
+ #self.imap._set_kolab_mailfolder_acls(
+ #entry['kolabmailfolderaclentry']
+ #)
#if server == None:
#self.entry_set_attribute(mailserver_attribute, server)
@@ -1202,10 +1296,29 @@ class LDAP(pykolab.base.Base):
self.imap.connect(domain=self.domain)
- if entry.has_key(result_attribute) and not entry.has_key(result_attribute) == None:
+ if entry.has_key(result_attribute) and \
+ not entry.has_key(result_attribute) == None:
+
if not self.imap.user_mailbox_exists(entry[result_attribute]):
folder = self.imap.user_mailbox_create(entry[result_attribute])
server = self.imap.user_mailbox_server(folder)
+ else:
+ folder = "user%s%s" % (
+ self.imap.separator,
+ entry[result_attribute]
+ )
+
+ server = self.imap.user_mailbox_server(folder)
+
+ self.user_quota(entry, folder)
+
+ mailserver_attr = self.config_get('mailserver_attribute')
+ if not entry.has_key(mailserver_attr):
+ self.set_entry_attribute(entry, mailserver_attr, server)
+ else:
+ if not entry[mailserver_attr] == server:
+ # TODO: Should actually transfer mailbox
+ self.set_entry_attribute(entry, mailserver_attr, server)
else:
log.warning(
@@ -1301,7 +1414,13 @@ class LDAP(pykolab.base.Base):
for auth_attr in auth_attrs:
auth_search_filter.append('(%s=%s)' % (auth_attr,login))
- auth_search_filter.append('(%s=%s@%s)' % (auth_attr,login,self.domain))
+ auth_search_filter.append(
+ '(%s=%s@%s)' % (
+ auth_attr,
+ login,
+ self.domain
+ )
+ )
auth_search_filter.append(')')
@@ -1435,13 +1554,18 @@ class LDAP(pykolab.base.Base):
except ldap.SERVER_DOWN, e:
raise AuthBackendError, _("Authentication database DOWN")
+ dna = self.config_get('domain_name_attribute')
+ if dna == None:
+ dna = 'associateddomain'
+
try:
_search = self._search(
domain_base_dn,
ldap.SCOPE_SUBTREE,
domain_filter,
- # TODO: Where we use associateddomain is actually configurable
- [ 'associateddomain' ],
+ # TODO: Where we use associateddomain is actually
+ # configurable
+ [ dna ],
override_search='_regular_search'
)
except:
@@ -1456,11 +1580,11 @@ class LDAP(pykolab.base.Base):
domain_attrs = utils.normalize(domain_attrs)
# TODO: Where we use associateddomain is actually configurable
- if type(domain_attrs['associateddomain']) == list:
- primary_domain = domain_attrs['associateddomain'].pop(0)
- secondary_domains = domain_attrs['associateddomain']
+ if type(domain_attrs[dna]) == list:
+ primary_domain = domain_attrs[dna].pop(0)
+ secondary_domains = domain_attrs[dna]
else:
- primary_domain = domain_attrs['associateddomain']
+ primary_domain = domain_attrs[dna]
domains.append((primary_domain,secondary_domains))
@@ -1518,8 +1642,14 @@ class LDAP(pykolab.base.Base):
# This entry was in the start result set
eval("self._change_none_%s(entry, change_dict)" % (entry['type']))
else:
- change = psearch.CHANGE_TYPES_STR[change_dict['change_type']].lower()
- eval("self._change_%s_%s(entry, change_dict)" % (change, entry['type']))
+ change = psearch.CHANGE_TYPES_STR[change_dict['change_type']]
+ change = change.lower()
+ eval(
+ "self._change_%s_%s(entry, change_dict)" % (
+ change,
+ entry['type']
+ )
+ )
# Typical for Paged Results Control
elif kw.has_key('user') and isinstance(kw['user'], list):
@@ -1543,7 +1673,10 @@ class LDAP(pykolab.base.Base):
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])
+ folder = self.imap.user_mailbox_create(
+ entry[result_attribute]
+ )
+
server = self.imap.user_mailbox_server(folder)
def _unbind(self):
@@ -1693,7 +1826,10 @@ class LDAP(pykolab.base.Base):
) = self.ldap.result3(_search)
except ldap.NO_SUCH_OBJECT, e:
- log.warning(_("Object %s searched no longer exists") % (base_dn))
+ log.warning(
+ _("Object %s searched no longer exists") % (base_dn)
+ )
+
break
if callback:
commit a154359af4f205caa694f1dcebbaf03490c1c3ae
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 16:45:13 2012 +0100
Only create directories that do not already exist
Do not use log it doesn't exist here
diff --git a/pykolab/utils.py b/pykolab/utils.py
index f766983..ba9e13c 100644
--- a/pykolab/utils.py
+++ b/pykolab/utils.py
@@ -122,7 +122,9 @@ def ask_confirmation(question, default="y", all_inclusive_no=True):
return True
def ensure_directory(_dir, _user='root', _group='root'):
- os.makedirs(_dir)
+ if not os.path.isdir(_dir):
+ os.makedirs(_dir)
+
try:
try:
(ruid, euid, suid) = os.getresuid()
@@ -182,17 +184,15 @@ def ensure_directory(_dir, _user='root', _group='root'):
# 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
- )
+ print >> sys.stderr, \
+ _("Switching real and effective user id to %d") % (
+ user_uid
+ )
os.chown(_dir, user_uid, -1)
except:
- log.error(_("Could not change the permissions on %s") % (_dir))
+ print >> sys.stderr, _("Could not change the permissions on %s") % (_dir)
def generate_password():
import subprocess
commit 957e51a28d2961d31cbac32b21c4f2ec01c20774
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 16:44:51 2012 +0100
Import the required utils
diff --git a/kolabd/__init__.py b/kolabd/__init__.py
index 5283c9f..230088c 100644
--- a/kolabd/__init__.py
+++ b/kolabd/__init__.py
@@ -32,6 +32,7 @@ import pykolab
from pykolab.auth import Auth
from pykolab import constants
+from pykolab import utils
from pykolab.translate import _
from process import KolabdProcess as Process
diff --git a/saslauthd/__init__.py b/saslauthd/__init__.py
index 1497dda..3cf6efb 100644
--- a/saslauthd/__init__.py
+++ b/saslauthd/__init__.py
@@ -35,6 +35,7 @@ import traceback
import pykolab
+from pykolab import utils
from pykolab.auth import Auth
from pykolab.constants import *
from pykolab.translate import _
diff --git a/wallace/__init__.py b/wallace/__init__.py
index 5d056df..f8e204c 100644
--- a/wallace/__init__.py
+++ b/wallace/__init__.py
@@ -32,6 +32,7 @@ import time
import traceback
import pykolab
+from pykolab import utils
from pykolab.translate import _
log = pykolab.getLogger('pykolab.wallace')
commit c4bcedbe35e24fd8264cff077044f5309855fce3
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Jun 13 16:43:03 2012 +0100
Failed or no quota should return None, not 0 (which is actually valid quota)
diff --git a/cyruslib.py b/cyruslib.py
index 20dd55b..f141059 100644
--- a/cyruslib.py
+++ b/cyruslib.py
@@ -572,11 +572,11 @@ class CYRUS:
match = re_q0.match(msg[0])
if match:
self.__verbose( '[GETQUOTA %s] QUOTA (Unlimited)' % mailbox )
- return 0, 0
+ return None, None
match = re_q.match(msg[0])
if match is None:
self.__verbose( '[GETQUOTA %s] BAD: RegExp not matched, please report' % mailbox )
- return 0, 0
+ return None, None
try:
used = int(match.group(2))
quota = int(match.group(3))
@@ -584,7 +584,7 @@ class CYRUS:
return used, quota
except:
self.__verbose( '[GETQUOTA %s] BAD: Error while parsing results' % mailbox )
- return 0, 0
+ return None, None
def lqr(self, mailbox):
"""List Quota Root"""
@@ -595,7 +595,7 @@ class CYRUS:
match = re_q0.match(msg[1][0])
if match:
self.__verbose( '[GETQUOTAROOT %s] QUOTAROOT (Unlimited)' % mailbox )
- return _root, 0, 0
+ return _root, None, None
match = re_q.match(msg[1][0])
try:
@@ -605,7 +605,7 @@ class CYRUS:
return _root, used, quota
except:
self.__verbose( '[GETQUOTAROOT %s] BAD: Error while parsing results' % mailbox )
- return _root, 0, 0
+ return _root, None, None
def sq(self, mailbox, limit):
"""Set Quota"""
More information about the commits
mailing list