vmm: minimal cleanups.
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Copyright 2007 - 2010, Pascal Volk
# See COPYING for distribution information.
"""This is the vmm main script."""
from time import strftime, strptime
from VirtualMailManager import *
from VirtualMailManager.cli import w_std, w_err
# TODO: FIXME
from VirtualMailManager.VirtualMailManager import VirtualMailManager
import VirtualMailManager.Exceptions as VMME
import VirtualMailManager.constants.EXIT as EXIT
def usage(excode=0, errMsg=None):
# TP: Please adjust translated words like the original text.
# (It's a table header.) Extract from usage text:
# Usage: vmm SUBCOMMAND OBJECT ARGS*
# short long
# subcommand object args (* = optional)
#
# da domainadd domain.tld transport*
# di domaininfo domain.tld details*
u_head = _(u"""\
Usage: %s SUBCOMMAND OBJECT ARGS*
short long
subcommand object args (* = optional)\n""")\
% __prog__
u_body = u"""\
da domainadd domain.tld transport*
di domaininfo domain.tld details*
dt domaintransport domain.tld transport force*
dd domaindelete domain.tld delalias*|deluser*|delall*
ada aliasdomainadd aliasdomain.tld domain.tld
adi aliasdomaininfo aliasdomain.tld
ads aliasdomainswitch aliasdomain.tld domain.tld
add aliasdomaindelete aliasdomain.tld
ua useradd user@domain.tld password*
ui userinfo user@domain.tld details*
un username user@domain.tld "user’s name"
up userpassword user@domain.tld password*
ut usertransport user@domain.tld transport
u0 userdisable user@domain.tld service*
u1 userenable user@domain.tld service*
ud userdelete user@domain.tld delalias*
aa aliasadd alias@domain.tld user@domain.tld
ai aliasinfo alias@domain.tld
ad aliasdelete alias@domain.tld user@domain.tld*
ra relocatedadd exaddr@domain.tld user@domain.tld
ri relocatedinfo exaddr@domain.tld
rf relocateddelete exaddr@domain.tld
gu getuser userid
ld listdomains pattern*
cf configure section*
h help
v version
"""
if excode > 0:
if errMsg is None:
w_err(excode, u_head, u_body)
else:
w_err(excode, u_head, u_body, _(u'Error: %s\n') % errMsg)
else:
w_std(u_head, u_body)
os.sys.exit(excode)
def get_vmm():
try:
vmm = VirtualMailManager()
return vmm
except (VMME.VMMException, VMME.VMMNotRootException, VMME.VMMPermException,
VMME.VMMConfigException), e:
w_err(e.code(), _(u'Error: %s\n') % e.msg())
def _getOrder():
order = ()
if vmm.cfgDget('misc.dovecot_version') > 11:
sieve_name = u'sieve'
else:
sieve_name = u'managesieve'
if argv[1] in (u'di', u'domaininfo'):
order = ((u'domainname', 0), (u'gid', 1), (u'transport', 0),
(u'domaindir', 0), (u'aliasdomains', 0), (u'accounts', 0),
(u'aliases', 0), (u'relocated', 0))
elif argv[1] in (u'ui', u'userinfo'):
if argc == 4 and argv[3] != u'aliases'\
or vmm.cfgDget('account.disk_usage'):
order = ((u'address', 0), (u'name', 0), (u'uid', 1), (u'gid', 1),
(u'transport', 0), (u'maildir', 0), (u'disk usage', 0),
(u'smtp', 1), (u'pop3', 1), (u'imap', 1), (sieve_name, 1))
else:
order = ((u'address', 0), (u'name', 0), (u'uid', 1), (u'gid', 1),
(u'transport', 0), (u'maildir', 0), (u'smtp', 1),
(u'pop3', 1), (u'imap', 1), (sieve_name, 1))
elif argv[1] in (u'gu', u'getuser'):
order = ((u'uid', 1), (u'gid', 1), (u'address', 0))
return order
def _printInfo(info, title):
# TP: e.g. 'Domain information' or 'Account information'
msg = u'%s %s' % (title, _(u'information'))
w_std (u'%s\n%s' % (msg, u'-'*len(msg)))
for k,u in _getOrder():
if u:
w_std(u'\t%s: %s' % (k.upper().ljust(15, u'.'), info[k]))
else:
w_std(u'\t%s: %s' % (k.title().ljust(15, u'.'), info[k]))
print
def _printList(alist, title):
# TP: e.g. 'Available alias addresses' or 'Available accounts'
msg = u'%s %s' % (_(u'Available'), title)
w_std(u'%s\n%s' % (msg, u'-'*len(msg)))
if len(alist) > 0:
if title != _(u'alias domains'):
for val in alist:
w_std(u'\t%s' % val)
else:
for dom in alist:
if not dom.startswith('xn--'):
w_std(u'\t%s' % dom)
else:
w_std(u'\t%s (%s)' % (dom, ace2idna(dom)))
else:
w_std(_(u'\tNone'))
print
def _printAliases(alias, targets):
msg = _(u'Alias information')
w_std(u'%s\n%s' % (msg, u'-'*len(msg)))
w_std(_(u'\tMail for %s will be redirected to:') % alias)
if len(targets) > 0:
for target in targets:
w_std(u'\t * %s' % target)
else:
w_std(_(u'\tNone'))
print
def _printRelocated(addr_dest):
msg = _(u'Relocated information')
w_std(u'%s\n%s' % (msg, u'-'*len(msg)))
w_std(_(u'\tUser “%(addr)s” has moved to “%(dest)s”') % addr_dest)
print
def _formatDom(domain, main=True):
if domain.startswith('xn--'):
domain = u'%s (%s)' % (domain, ace2idna(domain))
if main:
return u'\t[+] %s' % domain
else:
return u'\t[-] %s' % domain
def _printDomList(dids, domains):
if argc < 3:
msg = _('Available domains')
else:
msg = _('Matching domains')
w_std('%s\n%s' % (msg, '-'*len(msg)))
if not len(domains):
w_std(_('\tNone'))
else:
for id in dids:
if domains[id][0] is not None:
w_std(_formatDom(domains[id][0]))
if len(domains[id]) > 1:
for alias in domains[id][1:]:
w_std(_formatDom(alias, main=False))
print
def _printAliasDomInfo(info):
msg = _('Alias domain information')
for k in ['alias', 'domain']:
if info[k].startswith('xn--'):
info[k] = "%s (%s)" % (info[k], ace2idna(info[k]))
w_std('%s\n%s' % (msg, '-'*len(msg)))
w_std(
_('\tThe alias domain %(alias)s belongs to:\n\t * %(domain)s')%info)
print
def configure():
if argc < 3:
vmm.configure()
else:
vmm.configure(argv[2])
def domain_add():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing domain name.'))
elif argc < 4:
vmm.domainAdd(argv[2].lower())
else:
vmm.domainAdd(argv[2].lower(), argv[3])
def domain_delete():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing domain name.'))
elif argc < 4:
vmm.domainDelete(argv[2].lower())
else:
vmm.domainDelete(argv[2].lower(), argv[3])
def domain_info():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing domain name.'))
try:
if argc < 4:
_printInfo(vmm.domainInfo(argv[2].lower()), _(u'Domain'))
else:
details = argv[3].lower()
infos = vmm.domainInfo(argv[2].lower(), details)
_printInfo(infos[0], _(u'Domain'))
if details == u'accounts':
_printList(infos[1], _(u'accounts'))
elif details == u'aliasdomains':
_printList(infos[1], _(u'alias domains'))
elif details == u'aliases':
_printList(infos[1], _(u'aliases'))
elif details == u'relocated':
_printList(infos[1], _(u'relocated users'))
else:
_printList(infos[1], _(u'alias domains'))
_printList(infos[2], _(u'accounts'))
_printList(infos[3], _(u'aliases'))
_printList(infos[4], _(u'relocated users'))
except VMME.VMMDomainException, e:
if e.code() is ERR.DOMAIN_ALIAS_EXISTS:
w_std(plan_a_b % {'subcommand': u'aliasdomaininfo',
'object': argv[2].lower()})
alias_domain_info()
else:
raise e
def domain_transport():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing domain name and new transport.'))
if argc < 4:
usage(EXIT.MISSING_ARGS, _(u'Missing new transport.'))
elif argc < 5:
vmm.domainTransport(argv[2].lower(), argv[3])
else:
vmm.domainTransport(argv[2].lower(), argv[3], argv[4])
def alias_domain_add():
if argc < 3:
usage(EXIT.MISSING_ARGS,
_(u'Missing alias domain name and target domain name.'))
elif argc < 4:
usage(EXIT.MISSING_ARGS, _(u'Missing target domain name.'))
else:
vmm.aliasDomainAdd(argv[2].lower(), argv[3].lower())
def alias_domain_info():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing alias domain name.'))
try:
_printAliasDomInfo(vmm.aliasDomainInfo(argv[2].lower()))
except VMME.VMMAliasDomainException, e:
if e.code() is ERR.ALIASDOMAIN_ISDOMAIN:
w_std(plan_a_b % {'subcommand': u'domaininfo',
'object': argv[2].lower()})
argv[1] = u'di' # necessary manipulation to get the order
domain_info()
else:
raise e
def alias_domain_switch():
if argc < 3:
usage(EXIT.MISSING_ARGS,
_(u'Missing alias domain name and target domain name.'))
elif argc < 4:
usage(EXIT.MISSING_ARGS, _(u'Missing target domain name.'))
else:
vmm.aliasDomainSwitch(argv[2].lower(), argv[3].lower())
def alias_domain_delete():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing alias domain name.'))
else:
vmm.aliasDomainDelete(argv[2].lower())
def user_add():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing e-mail address.'))
elif argc < 4:
password = None
else:
password = argv[3]
vmm.userAdd(argv[2].lower(), password)
def user_delete():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing e-mail address.'))
elif argc < 4:
vmm.userDelete(argv[2].lower())
else:
vmm.userDelete(argv[2].lower(), argv[3].lower())
def user_info():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing e-mail address.'))
try:
if argc < 4:
_printInfo(vmm.userInfo(argv[2].lower()), u'Account')
else:
arg3 = argv[3].lower()
info = vmm.userInfo(argv[2].lower(), arg3)
if arg3 in ['aliases', 'full']:
_printInfo(info[0], u'Account')
_printList(info[1], _(u'alias addresses'))
else:
_printInfo(info, u'Account')
except VMME.VMMAccountException, e:
if e.code() is ERR.ALIAS_EXISTS:
w_std(plan_a_b % {'subcommand': u'aliasinfo',
'object': argv[2].lower()})
alias_info()
elif e.code() is ERR.RELOCATED_EXISTS:
w_std(plan_a_b % {'subcommand': u'relocatedinfo',
'object': argv[2].lower()})
relocated_info()
else:
raise e
def user_name():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing e-mail address and user’s name.'))
if argc < 4:
usage(EXIT.MISSING_ARGS, _(u'Missing user’s name.'))
else:
vmm.userName(argv[2].lower(), argv[3])
def user_transport():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing e-mail address and transport.'))
if argc <4:
usage(EXIT.MISSING_ARGS, _(u'Missing transport.'))
else:
vmm.userTransport(argv[2].lower(), argv[3])
def user_enable():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing e-mail address.'))
elif argc < 4:
vmm.userEnable(argv[2].lower())
else:
vmm.userEnable(argv[2].lower(), argv[3].lower())
def user_disable():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing e-mail address.'))
elif argc < 4:
vmm.userDisable(argv[2].lower())
else:
vmm.userDisable(argv[2].lower(), argv[3].lower())
def user_password():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing e-mail address.'))
elif argc < 4:
password = None
else:
password = argv[3]
vmm.userPassword(argv[2].lower(), password)
def alias_add():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing alias address and destination.'))
elif argc < 4:
usage(EXIT.MISSING_ARGS, _(u'Missing destination address.'))
else:
vmm.aliasAdd(argv[2].lower(), argv[3])
def alias_info():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing alias address'))
try:
_printAliases(argv[2].lower(), vmm.aliasInfo(argv[2].lower()))
except VMME.VMMException, e:
if e.code() is ERR.ACCOUNT_EXISTS:
w_std(plan_a_b % {'subcommand': u'userinfo',
'object': argv[2].lower()})
argv[1] = u'ui' # necessary manipulation to get the order
user_info()
elif e.code() is ERR.RELOCATED_EXISTS:
w_std(plan_a_b % {'subcommand': u'relocatedinfo',
'object': argv[2].lower()})
relocated_info()
else:
raise
def alias_delete():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing alias address'))
elif argc < 4:
vmm.aliasDelete(argv[2].lower())
else:
vmm.aliasDelete(argv[2].lower(), argv[3].lower())
def relocated_add():
if argc < 3:
usage(EXIT.MISSING_ARGS,
_(u'Missing relocated address and destination.'))
elif argc < 4:
usage(EXIT.MISSING_ARGS, _(u'Missing destination address.'))
else:
vmm.relocatedAdd(argv[2].lower(), argv[3])
def relocated_info():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing relocated address'))
relocated = argv[2].lower()
try:
_printRelocated({'addr': relocated,
'dest': vmm.relocatedInfo(relocated)})
except VMME.VMMRelocatedException, e:
if e.code() is ERR.ACCOUNT_EXISTS:
w_std(plan_a_b % {'subcommand': u'userinfo', 'object': relocated})
argv[1] = u'ui' # necessary manipulation to get the order
user_info()
elif e.code() is ERR.ALIAS_EXISTS:
w_std(plan_a_b % {'subcommand': u'aliasinfo', 'object': relocated})
alias_info()
else:
raise e
def relocated_delete():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing relocated address'))
else:
vmm.relocatedDelete(argv[2].lower())
def user_byID():
if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing userid'))
else:
_printInfo(vmm.userByID(argv[2]), u'Account')
def domain_list():
if argc < 3:
order, doms = vmm.domainList()
else:
order, doms = vmm.domainList(argv[2].lower())
_printDomList(order, doms)
def show_warnings():
if vmm.hasWarnings():
w_std(_(u'Warnings:'))
for warning in vmm.getWarnings():
w_std( " * %s" % warning)
def show_version():
w_std('%s, %s %s (%s %s)\nPython %s %s %s\n\n%s %s' % (__prog__,
# TP: The words 'from', 'version' and 'on' are used in the version
# information:
# vmm, version 0.5.2 (from 09/09/09)
# Python 2.5.4 on FreeBSD
_(u'version'), __version__, _(u'from'),
strftime(locale.nl_langinfo(locale.D_FMT),
strptime(__date__, '%Y-%m-%d')).decode(ENCODING, 'replace'),
os.sys.version.split()[0], _(u'on'), os.uname()[0], __prog__,
_(u'is free software and comes with ABSOLUTELY NO WARRANTY.')))
def main():
subcommand = os.sys.argv[1]
known_subcommand = False
try:
for s, l, f in subcmd_func.__iter__():
if subcommand in (s, l):
known_subcommand = True
f()
if not known_subcommand:
usage(EXIT.UNKNOWN_COMMAND, _(u'Unknown subcommand: “%s”')% argv[1])
show_warnings()
except (EOFError, KeyboardInterrupt):
# TP: We have to cry, because root has killed/interrupted vmm
# with Ctrl+C or Ctrl+D.
w_err(EXIT.USER_INTERRUPT, _(u'\nOuch!\n'))
except (VMME.VMMConfigException, VMME.VMMException), e:
if e.code() != ERR.DATABASE_ERROR:
w_err(e.code(), _(u'Error: %s') % e.msg())
else:
w_err(e.code(), unicode(e.msg(), ENCODING, 'replace'))
if __name__ == '__main__':
__prog__ = os.path.basename(os.sys.argv[0])
argv = [unicode(arg, ENCODING) for arg in os.sys.argv]
argc = len(os.sys.argv)
plan_a_b =_(u'Plan A failed ... trying Plan B: %(subcommand)s %(object)s')
if argc < 2:
usage(EXIT.MISSING_ARGS)
vmm = get_vmm()
subcmd_func = (
#short long function
('da', 'domainadd', domain_add),
('di', 'domaininfo', domain_info),
('dt', 'domaintransport', domain_transport),
('dd', 'domaindelete', domain_delete),
('ada', 'aliasdomainadd', alias_domain_add),
('adi', 'aliasdomaininfo', alias_domain_info),
('ads', 'aliasdomainswitch', alias_domain_switch),
('add', 'aliasdomaindelete', alias_domain_delete),
('ua', 'useradd', user_add),
('ui', 'userinfo', user_info),
('un', 'username', user_name),
('up', 'userpassword', user_password),
('ut', 'usertransport', user_transport),
('u0', 'userdisable', user_disable),
('u1', 'userenable', user_enable),
('ud', 'userdelete', user_delete),
('aa', 'aliasadd', alias_add),
('ai', 'aliasinfo', alias_info),
('ad', 'aliasdelete', alias_delete),
('ra', 'relocatedadd', relocated_add),
('ri', 'relocatedinfo', relocated_info),
('rd', 'relocateddelete', relocated_delete),
('cf', 'configure', configure),
('gu', 'getuser', user_byID),
('ld', 'listdomains', domain_list),
('h', 'help', usage),
('v', 'version', show_version),)
main()