#!/usr/bin/env python# -*- coding: UTF-8 -*-# Copyright 2007 - 2010, Pascal Volk# See COPYING for distribution information."""This is the vmm main script."""fromtimeimportstrftime,strptimefromVirtualMailManagerimport*fromVirtualMailManager.cliimportw_std,w_err# TODO: FIXMEfromVirtualMailManager.VirtualMailManagerimportVirtualMailManagerimportVirtualMailManager.ExceptionsasVMMEimportVirtualMailManager.constants.EXITasEXITdefusage(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"""ifexcode>0:iferrMsgisNone: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)defget_vmm():try:vmm=VirtualMailManager()returnvmmexcept(VMME.VMMException,VMME.VMMNotRootException,VMME.VMMPermException,VMME.VMMConfigException),e:w_err(e.code(),_(u'Error: %s\n')%e.msg())def_getOrder():order=()ifvmm.cfgDget('misc.dovecot_version')>11:sieve_name=u'sieve'else:sieve_name=u'managesieve'ifargv[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))elifargv[1]in(u'ui',u'userinfo'):ifargc==4andargv[3]!=u'aliases'\orvmm.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))elifargv[1]in(u'gu',u'getuser'):order=((u'uid',1),(u'gid',1),(u'address',0))returnorderdef_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)))fork,uin_getOrder():ifu: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]))printdef_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)))iflen(alist)>0:iftitle!=_(u'alias domains'):forvalinalist:w_std(u'\t%s'%val)else:fordominalist:ifnotdom.startswith('xn--'):w_std(u'\t%s'%dom)else:w_std(u'\t%s (%s)'%(dom,ace2idna(dom)))else:w_std(_(u'\tNone'))printdef_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)iflen(targets)>0:fortargetintargets:w_std(u'\t * %s'%target)else:w_std(_(u'\tNone'))printdef_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)printdef_formatDom(domain,main=True):ifdomain.startswith('xn--'):domain=u'%s (%s)'%(domain,ace2idna(domain))ifmain:returnu'\t[+] %s'%domainelse:returnu'\t[-] %s'%domaindef_printDomList(dids,domains):ifargc<3:msg=_('Available domains')else:msg=_('Matching domains')w_std('%s\n%s'%(msg,'-'*len(msg)))ifnotlen(domains):w_std(_('\tNone'))else:foridindids:ifdomains[id][0]isnotNone:w_std(_formatDom(domains[id][0]))iflen(domains[id])>1:foraliasindomains[id][1:]:w_std(_formatDom(alias,main=False))printdef_printAliasDomInfo(info):msg=_('Alias domain information')forkin['alias','domain']:ifinfo[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)printdefconfigure():ifargc<3:vmm.configure()else:vmm.configure(argv[2])defdomain_add():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing domain name.'))elifargc<4:vmm.domainAdd(argv[2].lower())else:vmm.domainAdd(argv[2].lower(),argv[3])defdomain_delete():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing domain name.'))elifargc<4:vmm.domainDelete(argv[2].lower())else:vmm.domainDelete(argv[2].lower(),argv[3])defdomain_info():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing domain name.'))try:ifargc<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'))ifdetails==u'accounts':_printList(infos[1],_(u'accounts'))elifdetails==u'aliasdomains':_printList(infos[1],_(u'alias domains'))elifdetails==u'aliases':_printList(infos[1],_(u'aliases'))elifdetails==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'))exceptVMME.VMMDomainException,e:ife.code()isERR.DOMAIN_ALIAS_EXISTS:w_std(plan_a_b%{'subcommand':u'aliasdomaininfo','object':argv[2].lower()})alias_domain_info()else:raiseedefdomain_transport():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing domain name and new transport.'))ifargc<4:usage(EXIT.MISSING_ARGS,_(u'Missing new transport.'))elifargc<5:vmm.domainTransport(argv[2].lower(),argv[3])else:vmm.domainTransport(argv[2].lower(),argv[3],argv[4])defalias_domain_add():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing alias domain name and target domain name.'))elifargc<4:usage(EXIT.MISSING_ARGS,_(u'Missing target domain name.'))else:vmm.aliasDomainAdd(argv[2].lower(),argv[3].lower())defalias_domain_info():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing alias domain name.'))try:_printAliasDomInfo(vmm.aliasDomainInfo(argv[2].lower()))exceptVMME.VMMAliasDomainException,e:ife.code()isERR.ALIASDOMAIN_ISDOMAIN:w_std(plan_a_b%{'subcommand':u'domaininfo','object':argv[2].lower()})argv[1]=u'di'# necessary manipulation to get the orderdomain_info()else:raiseedefalias_domain_switch():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing alias domain name and target domain name.'))elifargc<4:usage(EXIT.MISSING_ARGS,_(u'Missing target domain name.'))else:vmm.aliasDomainSwitch(argv[2].lower(),argv[3].lower())defalias_domain_delete():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing alias domain name.'))else:vmm.aliasDomainDelete(argv[2].lower())defuser_add():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing e-mail address.'))elifargc<4:password=Noneelse:password=argv[3]vmm.userAdd(argv[2].lower(),password)defuser_delete():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing e-mail address.'))elifargc<4:vmm.userDelete(argv[2].lower())else:vmm.userDelete(argv[2].lower(),argv[3].lower())defuser_info():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing e-mail address.'))try:ifargc<4:_printInfo(vmm.userInfo(argv[2].lower()),u'Account')else:arg3=argv[3].lower()info=vmm.userInfo(argv[2].lower(),arg3)ifarg3in['aliases','full']:_printInfo(info[0],u'Account')_printList(info[1],_(u'alias addresses'))else:_printInfo(info,u'Account')exceptVMME.VMMAccountException,e:ife.code()isERR.ALIAS_EXISTS:w_std(plan_a_b%{'subcommand':u'aliasinfo','object':argv[2].lower()})alias_info()elife.code()isERR.RELOCATED_EXISTS:w_std(plan_a_b%{'subcommand':u'relocatedinfo','object':argv[2].lower()})relocated_info()else:raiseedefuser_name():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing e-mail address and user’s name.'))ifargc<4:usage(EXIT.MISSING_ARGS,_(u'Missing user’s name.'))else:vmm.userName(argv[2].lower(),argv[3])defuser_transport():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing e-mail address and transport.'))ifargc<4:usage(EXIT.MISSING_ARGS,_(u'Missing transport.'))else:vmm.userTransport(argv[2].lower(),argv[3])defuser_enable():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing e-mail address.'))elifargc<4:vmm.userEnable(argv[2].lower())else:vmm.userEnable(argv[2].lower(),argv[3].lower())defuser_disable():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing e-mail address.'))elifargc<4:vmm.userDisable(argv[2].lower())else:vmm.userDisable(argv[2].lower(),argv[3].lower())defuser_password():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing e-mail address.'))elifargc<4:password=Noneelse:password=argv[3]vmm.userPassword(argv[2].lower(),password)defalias_add():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing alias address and destination.'))elifargc<4:usage(EXIT.MISSING_ARGS,_(u'Missing destination address.'))else:vmm.aliasAdd(argv[2].lower(),argv[3])defalias_info():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing alias address'))try:_printAliases(argv[2].lower(),vmm.aliasInfo(argv[2].lower()))exceptVMME.VMMException,e:ife.code()isERR.ACCOUNT_EXISTS:w_std(plan_a_b%{'subcommand':u'userinfo','object':argv[2].lower()})argv[1]=u'ui'# necessary manipulation to get the orderuser_info()elife.code()isERR.RELOCATED_EXISTS:w_std(plan_a_b%{'subcommand':u'relocatedinfo','object':argv[2].lower()})relocated_info()else:raisedefalias_delete():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing alias address'))elifargc<4:vmm.aliasDelete(argv[2].lower())else:vmm.aliasDelete(argv[2].lower(),argv[3].lower())defrelocated_add():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing relocated address and destination.'))elifargc<4:usage(EXIT.MISSING_ARGS,_(u'Missing destination address.'))else:vmm.relocatedAdd(argv[2].lower(),argv[3])defrelocated_info():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing relocated address'))relocated=argv[2].lower()try:_printRelocated({'addr':relocated,'dest':vmm.relocatedInfo(relocated)})exceptVMME.VMMRelocatedException,e:ife.code()isERR.ACCOUNT_EXISTS:w_std(plan_a_b%{'subcommand':u'userinfo','object':relocated})argv[1]=u'ui'# necessary manipulation to get the orderuser_info()elife.code()isERR.ALIAS_EXISTS:w_std(plan_a_b%{'subcommand':u'aliasinfo','object':relocated})alias_info()else:raiseedefrelocated_delete():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing relocated address'))else:vmm.relocatedDelete(argv[2].lower())defuser_byID():ifargc<3:usage(EXIT.MISSING_ARGS,_(u'Missing userid'))else:_printInfo(vmm.userByID(argv[2]),u'Account')defdomain_list():ifargc<3:order,doms=vmm.domainList()else:order,doms=vmm.domainList(argv[2].lower())_printDomList(order,doms)defshow_warnings():ifvmm.hasWarnings():w_std(_(u'Warnings:'))forwarninginvmm.getWarnings():w_std(" * %s"%warning)defshow_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.')))defmain():subcommand=os.sys.argv[1]known_subcommand=Falsetry:fors,l,finsubcmd_func.__iter__():ifsubcommandin(s,l):known_subcommand=Truef()ifnotknown_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:ife.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)forarginos.sys.argv]argc=len(os.sys.argv)plan_a_b=_(u'Plan A failed ... trying Plan B: %(subcommand)s%(object)s')ifargc<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()