Moved VirtualMailManager/Exceptions to VirtualMailManager/errors.
Renamed VMM*Exception classes to *Error.
No longer add the attribute 'message' to VMMError if it doesn't exist, like in
Python 2.4. It has been deprecated as of Python 2.6.
Also removed the methods code() and msg(), the values are now accessible via
the attributes 'code' and 'msg'.
#!/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.VMMAliasException, 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 e
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()