VMM/quotalimit: Don't fail in QuotaLimit.__init__, if we get the
deafult misc.quota_bytes value: '0'.
# -*- coding: UTF-8 -*-# Copyright 2007 - 2011, Pascal Volk# See COPYING for distribution information.""" VirtualMailManager.cli.subcommands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VirtualMailManager's cli subcommands."""importlocaleimportosfromtextwrapimportTextWrapperfromtimeimportstrftime,strptimefromVirtualMailManagerimportENCODINGfromVirtualMailManager.accountimportSERVICESfromVirtualMailManager.cliimportget_winsize,prog,w_err,w_stdfromVirtualMailManager.commonimporthuman_size,version_strfromVirtualMailManager.constantsimport__copyright__,__date__, \__version__,ACCOUNT_EXISTS,ALIAS_EXISTS,ALIASDOMAIN_ISDOMAIN, \DOMAIN_ALIAS_EXISTS,INVALID_ARGUMENT,EX_MISSING_ARGS,RELOCATED_EXISTSfromVirtualMailManager.errorsimportVMMError__all__=('Command','RunContext','cmd_map','usage','alias_add','alias_delete','alias_info','aliasdomain_add','aliasdomain_delete','aliasdomain_info','aliasdomain_switch','config_get','config_set','configure','domain_add','domain_delete','domain_info','domain_transport','get_user','help_','list_domains','relocated_add','relocated_delete','relocated_info','user_add','user_delete','user_disable','user_enable','user_info','user_name','user_password','user_transport','version',)_=lambdamsg:msgtxt_wrpr=TextWrapper(width=get_winsize()[1]-1)classCommand(object):"""Container class for command information."""__slots__=('name','alias','func','args','descr')def__init__(self,name,alias,func,args,descr):"""Create a new Command instance. Arguments: `name` : str the command name, e.g. ``addalias`` `alias` : str the command's short alias, e.g. ``aa`` `func` : callable the function to handle the command `args` : str argument placeholders, e.g. ``aliasaddress`` `descr` : str short description of the command """self.name=nameself.alias=aliasself.func=funcself.args=argsself.descr=descr@propertydefusage(self):"""the command's usage info."""returnu'%s%s%s'%(prog,self.name,self.args)classRunContext(object):"""Contains all information necessary to run a subcommand."""__slots__=('argc','args','cget','hdlr','scmd')plan_a_b=_(u'Plan A failed ... trying Plan B: %(subcommand)s%(object)s')def__init__(self,argv,handler,command):"""Create a new RunContext"""self.argc=len(argv)self.args=[unicode(arg,ENCODING)forarginargv]self.cget=handler.cfg_dgetself.hdlr=handlerself.scmd=commanddefalias_add(ctx):"""create a new alias e-mail address"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing alias address and destination.'),ctx.scmd)elifctx.argc<4:usage(EX_MISSING_ARGS,_(u'Missing destination address.'),ctx.scmd)ctx.hdlr.alias_add(ctx.args[2].lower(),*ctx.args[3:])defalias_delete(ctx):"""delete the specified alias e-mail address or one of its destinations"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing alias address.'),ctx.scmd)elifctx.argc<4:ctx.hdlr.alias_delete(ctx.args[2].lower())else:ctx.hdlr.alias_delete(ctx.args[2].lower(),ctx.args[3])defalias_info(ctx):"""show the destination(s) of the specified alias"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing alias address.'),ctx.scmd)address=ctx.args[2].lower()try:_print_aliase_info(address,ctx.hdlr.alias_info(address))exceptVMMError,err:iferr.codeisACCOUNT_EXISTS:w_err(0,ctx.plan_a_b%{'subcommand':u'userinfo','object':address})ctx.scmd=ctx.args[1]='userinfo'user_info(ctx)eliferr.codeisRELOCATED_EXISTS:w_std(0,ctx.plan_a_b%{'subcommand':u'relocatedinfo','object':address})ctx.scmd=ctx.args[1]='relocatedinfo'relocated_info(ctx)else:raisedefaliasdomain_add(ctx):"""create a new alias for an existing domain"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing alias domain name and destination 'u'domain name.'),ctx.scmd)elifctx.argc<4:usage(EX_MISSING_ARGS,_(u'Missing destination domain name.'),ctx.scmd)ctx.hdlr.aliasdomain_add(ctx.args[2].lower(),ctx.args[3].lower())defaliasdomain_delete(ctx):"""delete the specified alias domain"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing alias domain name.'),ctx.scmd)ctx.hdlr.aliasdomain_delete(ctx.args[2].lower())defaliasdomain_info(ctx):"""show the destination of the given alias domain"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing alias domain name.'),ctx.scmd)try:_print_aliasdomain_info(ctx.hdlr.aliasdomain_info(ctx.args[2].lower()))exceptVMMError,err:iferr.codeisALIASDOMAIN_ISDOMAIN:w_err(0,ctx.plan_a_b%{'subcommand':u'domaininfo','object':ctx.args[2].lower()})ctx.args[1]='domaininfo'domain_info(ctx)else:raisedefaliasdomain_switch(ctx):"""assign the given alias domain to an other domain"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing alias domain name and destination 'u'domain name.'),ctx.scmd)elifctx.argc<4:usage(EX_MISSING_ARGS,_(u'Missing destination domain name.'),ctx.scmd)ctx.hdlr.aliasdomain_switch(ctx.args[2].lower(),ctx.args[3].lower())defconfig_get(ctx):"""show the actual value of the configuration option"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u"Missing option name."),ctx.scmd)noop=lambdaoption:optionopt_formater={'misc.dovecot_version':version_str,'misc.quota_bytes':human_size,}option=ctx.args[2].lower()w_std('%s = %s'%(option,opt_formater.get(option,noop)(ctx.cget(option))))defconfig_set(ctx):"""set a new value for the configuration option"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing option and new value.'),ctx.scmd)ifctx.argc<4:usage(EX_MISSING_ARGS,_(u'Missing new configuration value.'),ctx.scmd)ctx.hdlr.cfg_set(ctx.args[2].lower(),ctx.args[3])defconfigure(ctx):"""start interactive configuration modus"""ifctx.argc<3:ctx.hdlr.configure()else:ctx.hdlr.configure(ctx.args[2].lower())defdomain_add(ctx):"""create a new domain"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing domain name.'),ctx.scmd)elifctx.argc<4:ctx.hdlr.domain_add(ctx.args[2].lower())else:ctx.hdlr.domain_add(ctx.args[2].lower(),ctx.args[3])ifnotctx.cget('domain.auto_postmaster'):returnctx.scmd='useradd'ctx.args=[prog,ctx.scmd,u'postmaster@'+ctx.args[2].lower()]ctx.argc=3user_add(ctx)defdomain_delete(ctx):"""delete the given domain and all its alias domains"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing domain name.'),ctx.scmd)elifctx.argc<4:ctx.hdlr.domain_delete(ctx.args[2].lower())elifctx.args[3].lower()=='force':ctx.hdlr.domain_delete(ctx.args[2].lower(),True)else:usage(INVALID_ARGUMENT,_(u"Invalid argument: '%s'")%ctx.args[3],ctx.scmd)defdomain_info(ctx):"""display information about the given domain"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing domain name.'),ctx.scmd)ifctx.argc<4:details=Noneelse:details=ctx.args[3].lower()ifdetailsnotin('accounts','aliasdomains','aliases','full','relocated'):usage(INVALID_ARGUMENT,_(u"Invalid argument: '%s'")%details,ctx.scmd)try:info=ctx.hdlr.domain_info(ctx.args[2].lower(),details)exceptVMMError,err:iferr.codeisDOMAIN_ALIAS_EXISTS:w_err(0,ctx.plan_a_b%{'subcommand':u'aliasdomaininfo','object':ctx.args[2].lower()})ctx.args[1]='aliasdomaininfo'aliasdomain_info(ctx)else:raiseelse:ifnotdetails:info['quota limit']=_(u'Storage: %s Messages %u')%(human_size(info['bytes']),info['messages'])_print_info(ctx,info,_(u'Domain'))else:info[0]['quota limit']=_(u'Storage: %s Messages %u')%(human_size(info[0]['bytes']),info[0]['messages'])_print_info(ctx,info[0],_(u'Domain'))ifdetails==u'accounts':_print_list(info[1],_(u'accounts'))elifdetails==u'aliasdomains':_print_list(info[1],_(u'alias domains'))elifdetails==u'aliases':_print_list(info[1],_(u'aliases'))elifdetails==u'relocated':_print_list(info[1],_(u'relocated users'))else:_print_list(info[1],_(u'alias domains'))_print_list(info[2],_(u'accounts'))_print_list(info[3],_(u'aliases'))_print_list(info[4],_(u'relocated users'))defdomain_transport(ctx):"""update the transport of the specified domain"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing domain name and new transport.'),ctx.scmd)ifctx.argc<4:usage(EX_MISSING_ARGS,_(u'Missing new transport.'),ctx.scmd)ifctx.argc<5:ctx.hdlr.domain_transport(ctx.args[2].lower(),ctx.args[3])else:force=ctx.args[4].lower()ifforce!='force':usage(INVALID_ARGUMENT,_(u"Invalid argument: '%s'")%force,ctx.scmd)ctx.hdlr.domain_transport(ctx.args[2].lower(),ctx.args[3],force)defget_user(ctx):"""get the address of the user with the given UID"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing userid.'),ctx.scmd)_print_info(ctx,ctx.hdlr.user_by_uid(ctx.args[2]),_(u'Account'))defhelp_(ctx):"""print help messgaes."""ifctx.argc>2:hlptpc=ctx.args[2].lower()ifhlptpcincmd_map:topic=hlptpcelse:forscmdincmd_map.itervalues():ifscmd.alias==hlptpc:topic=scmd.namebreakelse:usage(INVALID_ARGUMENT,_(u"Unknown help topic: '%s'")%ctx.args[2],ctx.scmd)# FIXMEw_err(1,"'help %s' not yet implemented."%topic,'see also: vmm(1)')old_ii=txt_wrpr.initial_indentold_si=txt_wrpr.subsequent_indenttxt_wrpr.initial_indent=' '# len(max(_overview.iterkeys(), key=len)) #Py25txt_wrpr.subsequent_indent=20*' 'order=cmd_map.keys()order.sort()w_std(_(u'List of available subcommands:')+'\n')forkeyinorder:w_std('\n'.join(txt_wrpr.wrap('%-18s%s'%(key,cmd_map[key].descr))))txt_wrpr.initial_indent=old_iitxt_wrpr.subsequent_indent=old_sitxt_wrpr.initial_indent=''deflist_domains(ctx):"""list all domains / search domains by pattern"""matching=ctx.argc>2ifmatching:gids,domains=ctx.hdlr.domain_list(ctx.args[2].lower())else:gids,domains=ctx.hdlr.domain_list()_print_domain_list(gids,domains,matching)defrelocated_add(ctx):"""create a new record for a relocated user"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing relocated address and destination.'),ctx.scmd)elifctx.argc<4:usage(EX_MISSING_ARGS,_(u'Missing destination address.'),ctx.scmd)ctx.hdlr.relocated_add(ctx.args[2].lower(),ctx.args[3])defrelocated_delete(ctx):"""delete the record of the relocated user"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing relocated address.'),ctx.scmd)ctx.hdlr.relocated_delete(ctx.args[2].lower())defrelocated_info(ctx):"""print information about a relocated user"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing relocated address.'),ctx.scmd)relocated=ctx.args[2].lower()try:_print_relocated_info(addr=relocated,dest=ctx.hdlr.relocated_info(relocated))exceptVMMError,err:iferr.codeisACCOUNT_EXISTS:w_err(0,ctx.plan_a_b%{'subcommand':u'userinfo','object':relocated})ctx.scmd=ctx.args[1]='userinfoi'user_info(ctx)eliferr.codeisALIAS_EXISTS:w_err(0,ctx.plan_a_b%{'subcommand':u'aliasinfo','object':relocated})ctx.scmd=ctx.args[1]='aliasinfo'alias_info(ctx)else:raisedefuser_add(ctx):"""create a new e-mail user with the given address"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing e-mail address.'),ctx.scmd)elifctx.argc<4:password=Noneelse:password=ctx.args[3]gen_pass=ctx.hdlr.user_add(ctx.args[2].lower(),password)ifgen_pass:w_std(_(u"Generated password: %s")%gen_pass)defuser_delete(ctx):"""delete the specified user"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing e-mail address.'),ctx.scmd)elifctx.argc<4:ctx.hdlr.user_delete(ctx.args[2].lower())elifctx.args[3].lower()=='force':ctx.hdlr.user_delete(ctx.args[2].lower(),True)else:usage(INVALID_ARGUMENT,_(u"Invalid argument: '%s'")%ctx.args[3],ctx.scmd)defuser_disable(ctx):"""deactivate all/the given service(s) for a user"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing e-mail address.'),ctx.scmd)elifctx.argc<4:ctx.hdlr.user_disable(ctx.args[2].lower())else:services=[service.lower()forserviceinctx.args[3:]]unknown=[serviceforserviceinservicesifservicenotinSERVICES]ifunknown:usage(INVALID_ARGUMENT,_(u"Invalid service arguments: %s")%' '.join(unknown),ctx.scmd)ctx.hdlr.user_disable(ctx.args[2].lower(),services)defuser_enable(ctx):"""activate all or the given service(s) for a user"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing e-mail address.'),ctx.scmd)elifctx.argc<4:ctx.hdlr.user_enable(ctx.args[2].lower())else:services=[service.lower()forserviceinctx.args[3:]]unknown=[serviceforserviceinservicesifservicenotinSERVICES]ifunknown:usage(INVALID_ARGUMENT,_(u"Invalid service arguments: %s")%' '.join(unknown),ctx.scmd)ctx.hdlr.user_enable(ctx.args[2].lower(),services)defuser_info(ctx):"""display information about the given address"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing e-mail address.'),ctx.scmd)ifctx.argc<4:details=Noneelse:details=ctx.args[3].lower()ifdetailsnotin('aliases','du','full'):usage(INVALID_ARGUMENT,_(u"Invalid argument: '%s'")%details,ctx.scmd)try:info=ctx.hdlr.user_info(ctx.args[2].lower(),details)exceptVMMError,err:iferr.codeisALIAS_EXISTS:w_err(0,ctx.plan_a_b%{'subcommand':u'aliasinfo','object':ctx.args[2].lower()})ctx.scmd=ctx.args[1]='aliasinfo'alias_info(ctx)eliferr.codeisRELOCATED_EXISTS:w_err(0,ctx.plan_a_b%{'subcommand':u'relocatedinfo','object':ctx.args[2].lower()})ctx.scmd=ctx.args[1]='relocatedinfo'relocated_info(ctx)else:raiseelse:ifdetailsin(None,'du'):info['quota usage']=_format_quota_usage(info['ql_bytes'],info['ql_messages'],info['uq_bytes'],info['uq_messages'])_print_info(ctx,info,_(u'Account'))else:info[0]['quota usage']=_format_quota_usage(info[0]['ql_bytes'],info[0]['ql_messages'],info[0]['uq_bytes'],info[0]['uq_messages'])_print_info(ctx,info[0],_(u'Account'))_print_list(info[1],_(u'alias addresses'))defuser_name(ctx):"""set or update the real name for an address"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u"Missing e-mail address and user's name."),ctx.scmd)ifctx.argc<4:usage(EX_MISSING_ARGS,_(u"Missing user's name."),ctx.scmd)ctx.hdlr.user_name(ctx.args[2].lower(),ctx.args[3])defuser_password(ctx):"""update the password for the given address"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing e-mail address.'),ctx.scmd)elifctx.argc<4:password=Noneelse:password=ctx.args[3]ctx.hdlr.user_password(ctx.args[2].lower(),password)defuser_transport(ctx):"""update the transport of the given address"""ifctx.argc<3:usage(EX_MISSING_ARGS,_(u'Missing e-mail address and transport.'),ctx.scmd)ifctx.argc<4:usage(EX_MISSING_ARGS,_(u'Missing transport.'),ctx.scmd)ctx.hdlr.user_transport(ctx.args[2].lower(),ctx.args[3])defusage(errno,errmsg,subcommand=None):"""print usage message for the given command or all commands. When errno > 0, sys,exit(errno) will interrupt the program. """ifsubcommandandsubcommandincmd_map:w_err(errno,_(u"Error: %s")%errmsg,_(u"usage: ")+cmd_map[subcommand].usage)# TP: Please adjust translated words like the original text.# (It's a table header.) Extract from usage text:# usage: vmm subcommand arguments# short long# subcommand arguments## da domainadd fqdn [transport]# dd domaindelete fqdn [force]u_head=_(u"""usage: %s subcommand arguments short long subcommand arguments\n""")%progorder=cmd_map.keys()order.sort()w_err(0,u_head)forkeyinorder:scmd=cmd_map[key]w_err(0,' %-5s%-19s%s'%(scmd.alias,scmd.name,scmd.args))w_err(errno,'',_(u"Error: %s")%errmsg)defversion(ctx):"""Write version and copyright information to stdout."""w_std('%s, %s%s (%s%s)\nPython %s%s%s\n\n%s\n%s%s'%(prog,# TP: The words 'from', 'version' and 'on' are used in# the version information, e.g.:# 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],__copyright__,prog,_(u'is free software and comes with ABSOLUTELY NO WARRANTY.')))cmd=Commandcmd_map={# {{{# Account commands'getuser':cmd('getuser','gu',get_user,'uid',_(u'get the address of the user with the given UID')),'useradd':cmd('useradd','ua',user_add,'address [password]',_(u'create a new e-mail user with the given address')),'userdelete':cmd('userdelete','ud',user_delete,'address [force]',_(u'delete the specified user')),'userdisable':cmd('userdisable','u0',user_disable,'address [service ...]',_(u'deactivate all/the given service(s) for a user')),'userenable':cmd('userenable','u1',user_enable,'address [service ...]',_(u'activate all or the given service(s) for a user')),'userinfo':cmd('userinfo','ui',user_info,'address [details]',_(u'display information about the given address')),'username':cmd('username','un',user_name,'address name',_(u'set or update the real name for an address')),'userpassword':cmd('userpassword','up',user_password,'address [password]',_(u'update the password for the given address')),'usertransport':cmd('usertransport','ut',user_transport,'address transport',_(u'update the transport of the given address')),# Alias commands'aliasadd':cmd('aliasadd','aa',alias_add,'address destination ...',_(u'create a new alias e-mail address')),'aliasdelete':cmd('aliasdelete','ad',alias_delete,'address [destination]',_(u'delete the specified alias e-mail address or one 'u'of its destinations')),'aliasinfo':cmd('aliasinfo','ai',alias_info,'address',_(u'show the destination(s) of the specified alias')),# AliasDomain commands'aliasdomainadd':cmd('aliasdomainadd','ada',aliasdomain_add,'fqdn destination',_(u'create a new alias for an existing domain')),'aliasdomaindelete':cmd('aliasdomaindelete','add',aliasdomain_delete,'fqdn',_(u'delete the specified alias domain')),'aliasdomaininfo':cmd('aliasdomaininfo','adi',aliasdomain_info,'fqdn',_(u'show the destination of the given alias domain')),'aliasdomainswitch':cmd('aliasdomainswitch','ads',aliasdomain_switch,'fqdn destination',_(u'assign the given alias domain to an other domain')),# Domain commands'domainadd':cmd('domainadd','da',domain_add,'fqdn [transport]',_(u'create a new domain')),'domaindelete':cmd('domaindelete','dd',domain_delete,'fqdn [force]',_(u'delete the given domain and all its alias domains')),'domaininfo':cmd('domaininfo','di',domain_info,'fqdn [details]',_(u'display information about the given domain')),'domaintransport':cmd('domaintransport','dt',domain_transport,'fqdn transport [force]',_(u'update the transport of the specified domain')),'listdomains':cmd('listdomains','ld',list_domains,'[pattern]',_(u'list all domains / search domains by pattern')),# Relocated commands'relocatedadd':cmd('relocatedadd','ra',relocated_add,'address newaddress',_(u'create a new record for a relocated user')),'relocateddelete':cmd('relocateddelete','rd',relocated_delete,'address',_(u'delete the record of the relocated user')),'relocatedinfo':cmd('relocatedinfo','ri',relocated_info,'address',_(u'print information about a relocated user')),# cli commands'configget':cmd('configget','cg',config_get,'option',_('show the actual value of the configuration option')),'configset':cmd('configset','cs',config_set,'option value',_('set a new value for the configuration option')),'configure':cmd('configure','cf',configure,'[section]',_(u'start interactive configuration modus')),'help':cmd('help','h',help_,'[subcommand]',_(u'show a help overview or help for the given subcommand')),'version':cmd('version','v',version,'',_(u'show version and copyright information')),}# }}}def_get_order(ctx):"""returns a tuple with (key, 1||0) tuples. Used by functions, which get a dict from the handler."""order=()ifctx.scmd=='domaininfo':order=((u'domainname',0),(u'gid',1),(u'transport',0),(u'domaindir',0),(u'quota limit',0),(u'aliasdomains',0),(u'accounts',0),(u'aliases',0),(u'relocated',0))elifctx.scmd=='userinfo':dc12=ctx.cget('misc.dovecot_version')>=0x10200b02sieve=(u'managesieve',u'sieve')[dc12]ifctx.argc==4andctx.args[3]!=u'aliases'or \ctx.cget('account.disk_usage'):order=((u'address',0),(u'name',0),(u'uid',1),(u'gid',1),(u'home',0),(u'mail_location',0),(u'quota usage',0),(u'disk usage',0),(u'transport',0),(u'smtp',1),(u'pop3',1),(u'imap',1),(sieve,1))else:order=((u'address',0),(u'name',0),(u'uid',1),(u'gid',1),(u'home',0),(u'mail_location',0),(u'quota usage',0),(u'transport',0),(u'smtp',1),(u'pop3',1),(u'imap',1),(sieve,1))elifctx.scmd=='getuser':order=((u'uid',1),(u'gid',1),(u'address',0))returnorderdef_format_quota_usage(ql_bytes,ql_messages,qu_bytes,qu_messages):"""Put quota limits / usage / percentage in a formatted string."""q_usage={'bytes_used':human_size(qu_bytes),'bytes_limit':human_size(ql_bytes),'msgs_used':qu_messages,'msgs_limit':ql_messages,}ifql_bytes:q_usage['bytes_percent']=100./ql_bytes*qu_byteselse:q_usage['bytes_percent']=0.ifql_messages:q_usage['msgs_percent']=100./ql_messages*qu_messageselse:q_usage['msgs_percent']=0.# TP: example of quota usage message:# XXX file in XXXtxt=_(u'Storage: %(bytes_used)s/%(bytes_limit)s (%(bytes_percent).2f%%) ''Messages: %(msgs_used)u/%(msgs_limit)u (%(msgs_percent).2f%%)') \%q_usagereturntxtdef_print_info(ctx,info,title):"""Print info dicts."""# TP: used in e.g. 'Domain information' or 'Account information'msg=u'%s%s'%(title,_(u'information'))w_std(msg,u'-'*len(msg))forkey,upperin_get_order(ctx):ifupper:w_std(u'\t%s: %s'%(key.upper().ljust(15,u'.'),info[key]))else:w_std(u'\t%s: %s'%(key.title().ljust(15,u'.'),info[key]))printdef_print_list(alist,title):"""Print a list."""# TP: used in e.g. 'Available alias addresses' or 'Available accounts'msg=u'%s%s'%(_(u'Available'),title)w_std(msg,u'-'*len(msg))ifalist:iftitle!=_(u'alias domains'):w_std(*(u'\t%s'%itemforiteminalist))else:fordomaininalist:ifnotdomain.startswith('xn--'):w_std(u'\t%s'%domain)else:w_std(u'\t%s (%s)'%(domain,domain.decode('idna')))printelse:w_std(_(u'\tNone'),'')def_print_aliase_info(alias,destinations):"""Print the alias address and all its destinations"""title=_(u'Alias information')w_std(title,u'-'*len(title))w_std(_(u'\tMail for %s will be redirected to:')%alias)w_std(*(u'\t * %s'%destfordestindestinations))printdef_print_relocated_info(**kwargs):"""Print the old and new addresses of a relocated user."""title=_(u'Relocated information')w_std(title,u'-'*len(title))w_std(_(u"\tUser '%(addr)s' has moved to '%(dest)s'")%kwargs,'')def_format_domain(domain,main=True):"""format (prefix/convert) the domain name."""ifdomain.startswith('xn--'):domain=u'%s (%s)'%(domain,domain.decode('idna'))ifmain:returnu'\t[+] %s'%domainreturnu'\t[-] %s'%domaindef_print_domain_list(dids,domains,matching):"""Print a list of (matching) domains/alias domains."""ifmatching:title=_(u'Matching domains')else:title=_(u'Available domains')w_std(title,'-'*len(title))ifdomains:fordidindids:ifdomains[did][0]isnotNone:w_std(_format_domain(domains[did][0]))iflen(domains[did])>1:w_std(*(_format_domain(a,False)foraindomains[did][1:]))else:w_std(_('\tNone'))printdef_print_aliasdomain_info(info):"""Print alias domain information."""title=_(u'Alias domain information')forkeyin('alias','domain'):ifinfo[key].startswith('xn--'):info[key]=u'%s (%s)'%(info[key],info[key].decode('idna'))w_std(title,'-'*len(title),_('\tThe alias domain %(alias)s belongs to:\n\t * %(domain)s')%info,'')del_