import textwrap import os from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from orchestra.apps.orchestration import ServiceController from orchestra.apps.resources import ServiceMonitor from . import settings from .models import Address class MailSystemUserBackend(ServiceController): verbose_name = _("Mail system user") model = 'mails.Mailbox' # TODO related_models = ('resources__content_type') ?? needed for updating disk usage from resource.data DEFAULT_GROUP = 'postfix' def create_user(self, context): self.append(textwrap(""" if [[ $( id %(username)s ) ]]; then usermod -p '%(password)s' %(username)s else useradd %(username)s --password '%(password)s' --shell /dev/null fi""" % context )) self.append("mkdir -p %(home)s" % context) self.append("chown %(username)s.%(group)s %(home)s" % context) def generate_filter(self, mailbox, context): now = timezone.now().strftime("%B %d, %Y, %H:%M") context['filtering'] = ( "# Sieve Filter\n" "# Generated by Orchestra %s\n\n" % now ) if mailbox.custom_filtering: context['filtering'] += mailbox.custom_filtering else: context['filtering'] += settings.EMAILS_DEFAUL_FILTERING context['filter_path'] = os.path.join(context['home'], '.orchestra.sieve') self.append("echo '%(filtering)s' > %(filter_path)s" % context) def set_quota(self, mailbox, context): if not hasattr(mailbox, 'resources'): return context.update({ 'maildir_path': '~%(username)s/Maildir' % context, 'maildirsize_path': '~%(username)s/Maildir/maildirsize' % context, 'quota': mailbox.resources.disk.allocated*1000*1000, }) self.append("mkdir -p %(maildir_path)s" % context) self.append(textwrap(""" sed -i '1s/.*/%(quota)s,S/' %(maildirsize_path)s || { echo '%(quota)s,S' > %(maildirsize_path)s && chown %(username)s %(maildirsize_path)s; }""" % context )) def save(self, mailbox): context = self.get_context(mailbox) self.create_user(context) self.set_quota(mailbox, context) self.generate_filter(mailbox, context) def delete(self, mailbox): context = self.get_context(mailbox) self.append("{ sleep 2 && killall -u %(username)s -s KILL; } &" % context) self.append("killall -u %(username)s" % context) self.append("userdel %(username)s" % context) self.append("rm -fr %(home)s" % context) def get_context(self, mailbox): context = { 'name': mailbox.name, 'username': mailbox.name, 'password': mailbox.password if mailbox.is_active else '*%s' % mailbox.password, 'group': self.DEFAULT_GROUP } context['home'] = settings.EMAILS_HOME % context return context class PostfixAddressBackend(ServiceController): verbose_name = _("Postfix address") model = 'mails.Address' def include_virtdomain(self, context): self.append( '[[ $(grep "^\s*%(domain)s\s*$" %(virtdomains)s) ]]' ' || { echo "%(domain)s" >> %(virtdomains)s; UPDATED=1; }' % context ) def exclude_virtdomain(self, context): domain = context['domain'] if not Address.objects.filter(domain=domain).exists(): self.append('sed -i "s/^%(domain)s//" %(virtdomains)s' % context) def update_virtusertable(self, context): self.append(textwrap(""" LINE="%(email)s\t%(destination)s" if [[ ! $(grep "^%(email)s\s" %(virtusertable)s) ]]; then echo "$LINE" >> %(virtusertable)s UPDATED=1 else if [[ ! $(grep "^${LINE}$" %(virtusertable)s) ]]; then sed -i "s/^%(email)s\s.*$/${LINE}/" %(virtusertable)s UPDATED=1 fi fi""" % context )) def exclude_virtusertable(self, context): self.append(textwrap(""" if [[ $(grep "^%(email)s\s") ]]; then sed -i "s/^%(email)s\s.*$//" %(virtusertable)s UPDATED=1 fi""" )) def save(self, address): context = self.get_context(address) self.include_virtdomain(context) self.update_virtusertable(context) def delete(self, address): context = self.get_context(address) self.exclude_virtdomain(context) self.exclude_virtusertable(context) def commit(self): context = self.get_context_files() self.append(textwrap(""" [[ $UPDATED == 1 ]] && { postmap %(virtdomains)s postmap %(virtusertable)s }""" % context )) def get_context_files(self): return { 'virtdomains': settings.EMAILS_VIRTDOMAINS_PATH, 'virtusertable': settings.EMAILS_VIRTUSERTABLE_PATH, } def get_context(self, address): context = self.get_context_files() context.update({ 'domain': address.domain, 'email': address.email, 'destination': address.destination, }) return context class AutoresponseBackend(ServiceController): verbose_name = _("Mail autoresponse") model = 'mail.Autoresponse' class MaildirDisk(ServiceMonitor): model = 'mails.Mailbox' resource = ServiceMonitor.DISK verbose_name = _("Maildir disk usage") def monitor(self, mailbox): context = self.get_context(mailbox) self.append( "SIZE=$(sed -n '2p' %(maildir_path)s | cut -d' ' -f1)\n" "echo %(object_id)s ${SIZE:-0}" % context ) def get_context(self, mailbox): context = MailSystemUserBackend().get_context(mailbox) context['home'] = settings.EMAILS_HOME % context context['rr_path'] = os.path.join(context['home'], 'Maildir/maildirsize') context['object_id'] = mailbox.pk return context