Source code for univention.admin.handlers.mail.folder

# SPDX-FileCopyrightText: 2004-2025 Univention GmbH
# SPDX-License-Identifier: AGPL-3.0-only

"""|UDM| module for mail IMAP folders"""

from __future__ import annotations

import ldap

import univention.admin.handlers
import univention.admin.localization
from univention.admin.layout import Group, Tab


translation = univention.admin.localization.translation('univention.admin.handlers.mail')
_ = translation.translate

module = 'mail/folder'
operations = ['add', 'edit', 'remove', 'search']  # removed 'move' as a workaround for bug #11664
childs = False
short_description = _('Mail folder (IMAP)')
object_name = _('IMAP mail folder')
object_name_plural = _('IMAP mail folders')
long_description = ''


[docs] class MailDomain(univention.admin.syntax.UDM_Attribute): udm_module = 'mail/domain' attribute = 'name'
# fmt: off options = { 'default': univention.admin.option( short_description=short_description, default=True, objectClasses=['univentionMailSharedFolder'], ), } property_descriptions = { 'name': univention.admin.property( short_description=_('Name'), long_description='', syntax=univention.admin.syntax.mail_folder_name, include_in_default_search=True, required=True, may_change=False, identifies=True, ), 'mailDomain': univention.admin.property( short_description=_('Mail domain'), long_description='', syntax=getattr(univention.admin.syntax, 'MailDomain', MailDomain), include_in_default_search=True, required=True, may_change=False, identifies=True, ), 'sharedFolderUserACL': univention.admin.property( short_description=_('User ACL'), long_description='', syntax=univention.admin.syntax.SharedFolderUserACL, multivalue=True, ), 'sharedFolderGroupACL': univention.admin.property( short_description=_('Group ACL'), long_description='', syntax=univention.admin.syntax.SharedFolderGroupACL, multivalue=True, ), 'mailQuota': univention.admin.property( short_description=_('Quota in MB'), long_description=_('How many MB of emails can be stored in the shared folder (independent of the users that stored them).'), syntax=univention.admin.syntax.integer, ), 'mailHomeServer': univention.admin.property( short_description=_('Mail home server'), long_description='', syntax=univention.admin.syntax.MailHomeServer, nonempty_is_default=True, required=True, ), 'mailPrimaryAddress': univention.admin.property( short_description=_('E-Mail address'), long_description='', syntax=univention.admin.syntax.emailAddressValidDomain, include_in_default_search=True, ), } layout = [ Tab(_('General'), _('Basic settings'), layout=[ Group(_('General IMAP mail folder settings'), layout=[ ["name", "mailDomain"], ["mailHomeServer"], ["mailQuota"], ["mailPrimaryAddress"], ]), ]), Tab(_('Access Rights'), _('Access rights for shared folder'), layout=[ Group(_('Access Rights'), layout=[ "sharedFolderUserACL", "sharedFolderGroupACL", ]), ]), ] mapping = univention.admin.mapping.mapping() mapping.register('mailQuota', 'univentionMailUserQuota', None, univention.admin.mapping.ListToString) mapping.register('mailHomeServer', 'univentionMailHomeServer', None, univention.admin.mapping.ListToString) mapping.register('mailPrimaryAddress', 'mailPrimaryAddress', None, univention.admin.mapping.ListToString) # fmt: on
[docs] class object(univention.admin.handlers.simpleLdap): module = module def _get_admin_diary_args(self, event): return {'module': self.module, 'nameWithMailDomain': self.description()} def _post_unmap(self, oldinfo: univention.admin.handlers._Properties, oldattr: univention.admin.handlers._Attributes) -> univention.admin.handlers._Properties: cn = oldattr.get('cn', [b''])[0].decode('UTF-8') if cn: oldinfo['name'], oldinfo['mailDomain'] = cn.split('@', 1) # fetch values for ACLs acls = oldattr.get('univentionMailACL', []) oldinfo['sharedFolderUserACL'] = [] oldinfo['sharedFolderGroupACL'] = [] if acls: for acl in [x.decode('UTF-8') for x in acls]: if acl.find('@') > 0 or acl.startswith('anyone'): oldinfo['sharedFolderUserACL'].append(acl.rsplit(' ', 1)) else: oldinfo['sharedFolderGroupACL'].append(acl.rsplit(' ', 1)) return oldinfo
[docs] def description(self): """ Returns a name that identifies the object. This may be used to override the default value that is the property marked with identifies = True """ return '%(name)s@%(mailDomain)s' % self
def _ldap_dn(self): name = '%s@%s' % (self.info['name'], self.info['mailDomain']) return 'cn=%s,%s' % (ldap.dn.escape_dn_chars(name), self.position.getDn()) def _ldap_addlist(self): al = super()._ldap_addlist() if self['mailPrimaryAddress']: value = 'univentioninternalpostuser+shared/%s@%s' % (self['name'].lower(), self['mailDomain'].lower()) al.append(('univentionMailSharedFolderDeliveryAddress', value.encode('UTF-8'))) address = '%s@%s' % (self['name'], self['mailDomain']) if self['mailPrimaryAddress'] != address: try: self.request_lock('mailPrimaryAddress', self['mailPrimaryAddress']) except univention.admin.uexceptions.noLock: raise univention.admin.uexceptions.mailAddressUsed(self['mailPrimaryAddress']) value = '%s@%s' % (self.info['name'], self.info['mailDomain']) al.append(('cn', value.encode('UTF-8'))) return al def _ldap_modlist(self): # we get a list of modifications to be done (called 'ml' down below) # this lists looks like this: # [('univentionMailHomeServer', [u'ugs-master.hosts.invalid'], u'ugs-master.hosts.invalid'), ('univentionMailUserQuota', u'100', u'101')] # we can modify those entries to conform to the LDAP schema ml = univention.admin.handlers.simpleLdap._ldap_modlist(self) if self.hasChanged('mailPrimaryAddress') and self['mailPrimaryAddress'] and not any(x[0] == 'mailPrimaryAddress' for x in self.alloc): value = 'univentioninternalpostuser+shared/%s@%s' % (self['name'].lower(), self['mailDomain'].lower()) ml.append(( 'univentionMailSharedFolderDeliveryAddress', self.oldattr.get('univentionMailSharedFolderDeliveryAddress', []), [value.encode('UTF-8')], )) # fmt: skip address = '%s@%s' % (self['name'], self['mailDomain']) if self['mailPrimaryAddress'] != address and self['mailPrimaryAddress'].lower() != self.oldinfo.get('mailPrimaryAddress', '').lower(): try: self.request_lock('mailPrimaryAddress', self['mailPrimaryAddress']) except univention.admin.uexceptions.noLock: raise univention.admin.uexceptions.mailAddressUsed(self['mailPrimaryAddress']) if not self['mailPrimaryAddress']: ml.append(('univentionMailSharedFolderDeliveryAddress', self.oldattr.get('univentionMailSharedFolderDeliveryAddress', []), [])) rewrite_acl = False new_acls_tmp = [] for attr in ['sharedFolderUserACL', 'sharedFolderGroupACL']: self.log.debug('current ACLs', attr=attr, value=self[attr]) if self.hasChanged(attr): rewrite_acl = True # re-use regular expressions from syntax definitions if attr == 'sharedFolderUserACL': _sre = univention.admin.syntax.UserMailAddress.regex else: _sre = univention.admin.syntax.GroupName.regex for acl in self[attr]: if acl == '': continue if _sre.match(acl[0]): new_acls_tmp.append(' '.join(acl)) else: for acl in self[attr]: if acl == '': continue new_acls_tmp.append(' '.join(acl)) if rewrite_acl: for a, b, c in ml[:]: if a in ['sharedFolderUserACL', 'sharedFolderGroupACL']: ml.remove((a, b, c)) new_acls_tmp = [x.encode('UTF-8') for x in new_acls_tmp] ml.append(('univentionMailACL', self.oldattr.get('univentionMailACL', []), new_acls_tmp)) return ml def _ldap_pre_remove(self): super()._ldap_pre_remove() if self.oldattr.get('mailPrimaryAddress'): self.alloc.append(('mailPrimaryAddress', self.oldattr['mailPrimaryAddress'][0].decode('UTF-8')))
lookup = object.lookup lookup_filter = object.lookup_filter identify = object.identify