VMM/cli/main: Check if we have warnings before exiting.
If so, print them and exit afterwards.
# -*- coding: UTF-8 -*-# Copyright (c) 2012 martin f. krafft# See COPYING for distribution information.""" VirtualMailManager.catchall ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Virtual Mail Manager's CatchallAlias class to manage domain catch-all aliases. This is heavily based on (more or less a copy of) the Alias class, because fundamentally, catchall aliases are aliases, but without a localpart. While Alias could potentially derive from CatchallAlias to reuse some of the functionality, it's probably not worth it. I found no sensible way to derive CatchallAlias from Alias, or at least none that would harness the powers of polymorphism. Yet, we reuse the AliasError exception class, which makes sense."""fromVirtualMailManager.domainimportget_gidfromVirtualMailManager.emailaddressimport \EmailAddress,DestinationEmailAddressasDestAddrfromVirtualMailManager.errorsimportAliasErrorasAErrfromVirtualMailManager.ext.postconfimportPostconffromVirtualMailManager.pycompatimportallfromVirtualMailManager.constantsimport \ALIAS_EXCEEDS_EXPANSION_LIMIT,NO_SUCH_ALIAS,NO_SUCH_DOMAIN_=lambdamsg:msgcfg_dget=lambdaoption:NoneclassCatchallAlias(object):"""Class to manage domain catch-all aliases."""__slots__=('_domain','_dests','_gid','_dbh')def__init__(self,dbh,domain):self._domain=domainself._dbh=dbhself._gid=get_gid(self._dbh,self.domain)ifnotself._gid:raiseAErr(_(u"The domain '%s' does not exist.")%self.domain,NO_SUCH_DOMAIN)self._dests=[]self._load_dests()def_load_dests(self):"""Loads all known destination addresses into the _dests list."""dbc=self._dbh.cursor()dbc.execute('SELECT destination FROM catchall WHERE gid = %s',(self._gid,))dests=dbc.fetchall()ifdbc.rowcount>0:self._dests.extend(DestAddr(dest[0],self._dbh)fordestindests)dbc.close()def_check_expansion(self,count_new):"""Checks the current expansion limit of the alias."""postconf=Postconf(cfg_dget('bin.postconf'))limit=long(postconf.read('virtual_alias_expansion_limit'))dcount=len(self._dests)failed=Falseifdcount==limitordcount+count_new>limit:failed=Trueerrmsg=_(u"""Cannot add %(count_new)i new destination(s) to catch-all alias fordomain '%(domain)s'. Currently this alias expands into %(count)i/%(limit)irecipients. %(count_new)i additional destination(s) will render this aliasunusable.Hint: Increase Postfix' virtual_alias_expansion_limit""")elifdcount>limit:failed=Trueerrmsg=_(u"""Cannot add %(count_new)i new destination(s) to catch-all alias for domain'%(domain)s'. This alias already exceeds its expansion limit \(%(count)i/%(limit)i).So its unusable, all messages addressed to this alias will be bounced.Hint: Delete some destination addresses.""")iffailed:raiseAErr(errmsg%{'domain':self._domain,'count':dcount,'limit':limit,'count_new':count_new},ALIAS_EXCEEDS_EXPANSION_LIMIT)def_delete(self,destination=None):"""Deletes a destination from the catchall alias, if ``destination`` is not ``None``. If ``destination`` is None, the catchall alias with all its destination addresses will be deleted. """dbc=self._dbh.cursor()ifnotdestination:dbc.execute('DELETE FROM catchall WHERE gid = %s',(self._gid,))else:dbc.execute('DELETE FROM catchall WHERE gid = %s ''AND destination = %s',(self._gid,str(destination)))ifdbc.rowcount>0:self._dbh.commit()dbc.close()def__len__(self):"""Returns the number of destinations of the catchall alias."""returnlen(self._dests)@propertydefdomain(self):"""The Alias' domain."""returnself._domaindefadd_destinations(self,destinations,warnings=None):"""Adds the `EmailAddress`es from *destinations* list to the destinations of the catchall alias. Destinations, that are already assigned to the alias, will be removed from *destinations*. When done, this method will return a set with all destinations, that were saved in the database. """destinations=set(destinations)assertdestinationsand \all(isinstance(dest,EmailAddress)fordestindestinations)ifnotwarningsisNone:assertisinstance(warnings,list)duplicates=destinations.intersection(set(self._dests))ifduplicates:destinations.difference_update(set(self._dests))ifnotwarningsisNone:warnings.extend(duplicates)ifnotdestinations:returndestinationsself._check_expansion(len(destinations))dbc=self._dbh.cursor()dbc.executemany("INSERT INTO catchall (gid, destination) ""VALUES (%d, %%s)"%self._gid,((str(destination),)fordestinationindestinations))self._dbh.commit()dbc.close()self._dests.extend(destinations)returndestinationsdefdel_destination(self,destination):"""Deletes the specified ``destination`` address from the catchall alias."""assertisinstance(destination,EmailAddress)ifnotself._dests:raiseAErr(_(u"There are no catch-all aliases defined for "u"domain '%s'.")%self._domain,NO_SUCH_ALIAS)ifnotdestinationinself._dests:raiseAErr(_(u"The address '%(addr)s' is not a destination of "u"the catch-all alias for domain '%(domain)s'.")%{'addr':destination,'domain':self._domain},NO_SUCH_ALIAS)self._delete(destination)self._dests.remove(destination)defget_destinations(self):"""Returns an iterator for all destinations of the catchall alias."""ifnotself._dests:raiseAErr(_(u"There are no catch-all aliases defined for "u"domain '%s'.")%self._domain,NO_SUCH_ALIAS)returniter(self._dests)defdelete(self):"""Deletes all catchall destinations for the domain."""ifnotself._dests:raiseAErr(_(u"There are no catch-all aliases defined for "u"domain '%s'.")%self._domain,NO_SUCH_ALIAS)self._delete()delself._dests[:]del_,cfg_dget