VMM/handler: Restored method Handler.domain_transport().
It went somehow lost with changeset 5806fb74130b.
# -*- coding: UTF-8 -*-# Copyright (c) 2010 - 2011, Pascal Volk# See COPYING for distribution information.""" VirtualMailManager.common ~~~~~~~~~~~~~~~~~~~~~~~~~ Some common functions"""importlocaleimportosimportreimportstatfromVirtualMailManagerimportENCODINGfromVirtualMailManager.constantsimportNOT_EXECUTABLE,NO_SUCH_BINARY, \TYPE_ACCOUNT,TYPE_ALIAS,TYPE_RELOCATEDfromVirtualMailManager.errorsimportVMMErrorVERSION_RE=re.compile(r'^(\d+)\.(\d+)\.(?:(\d+)|(alpha|beta|rc)(\d+))$')_version_level=dict(alpha=0xA,beta=0xB,rc=0xC)_version_cache={}_=lambdamsg:msgdefexpand_path(path):"""Expands paths, starting with ``.`` or ``~``, to an absolute path."""ifpath.startswith('.'):returnos.path.abspath(path)ifpath.startswith('~'):returnos.path.expanduser(path)returnpathdefget_unicode(string):"""Converts `string` to `unicode`, if necessary."""ifisinstance(string,unicode):returnstringreturnunicode(string,ENCODING,'replace')deflisdir(path):"""Checks if `path` is a directory. Doesn't follow symbolic links. Returns bool. """try:lstat=os.lstat(path)exceptOSError:returnFalsereturnstat.S_ISDIR(lstat.st_mode)defexec_ok(binary):"""Checks if the `binary` exists and if it is executable. Throws a `VMMError` if the `binary` isn't a file or is not executable. """binary=expand_path(binary)ifnotos.path.isfile(binary):raiseVMMError(_(u"No such file: '%s'")%get_unicode(binary),NO_SUCH_BINARY)ifnotos.access(binary,os.X_OK):raiseVMMError(_(u"File is not executable: '%s'")%get_unicode(binary),NOT_EXECUTABLE)returnbinarydefhuman_size(size):"""Converts the `size` in bytes in human readable format."""ifnotisinstance(size,(long,int)):try:size=long(size)exceptValueError:raiseTypeError("'size' must be a positive long or int.")ifsize<0:raiseValueError("'size' must be a positive long or int.")ifsize<1024:returnstr(size)prefix_multiply=((_(u'TiB'),1<<40),(_(u'GiB'),1<<30),(_(u'MiB'),1<<20),(_(u'KiB'),1<<10))forprefix,multiplyinprefix_multiply:ifsize>=multiply:# TP: e.g.: '%(size)s %(prefix)s' -> '118.30 MiB'return_(u'%(size)s%(prefix)s')%{'size':locale.format('%.2f',float(size)/multiply,True),'prefix':prefix}defsize_in_bytes(size):"""Converts the string `size` to a long (size in bytes). The string `size` can be suffixed with *b* (bytes), *k* (kilobytes), *M* (megabytes) or *G* (gigabytes). """ifnotisinstance(size,basestring)ornotsize:raiseTypeError('size must be a non empty string.')ifsize[-1].upper()in('B','K','M','G'):try:num=int(size[:-1])exceptValueError:raiseValueError('Not a valid integer value: %r'%size[:-1])unit=size[-1].upper()ifunit=='B':returnnumelifunit=='K':returnnum<<10Lelifunit=='M':returnnum<<20Lelse:returnnum<<30Lelse:try:num=int(size)exceptValueError:raiseValueError('Not a valid size value: %r'%size)returnnumdefversion_hex(version_string):"""Converts a Dovecot version, e.g.: '1.2.3' or '2.0.beta4', to an int. Raises a `ValueError` if the *version_string* has the wrong™ format. version_hex('1.2.3') -> 270548736 hex(version_hex('1.2.3')) -> '0x10203f00' """global_version_cacheifversion_stringin_version_cache:return_version_cache[version_string]version=0version_mo=VERSION_RE.match(version_string)ifnotversion_mo:raiseValueError('Invalid version string: %r'%version_string)major,minor,patch,level,serial=version_mo.groups()major=int(major)minor=int(minor)ifpatch:patch=int(patch)ifserial:serial=int(serial)ifmajor>0xFForminor>0xFFor \patchandpatch>0xFForserialandserial>0xFF:raiseValueError('Invalid version string: %r'%version_string)version+=major<<28version+=minor<<20ifpatch:version+=patch<<12version+=_version_level.get(level,0xF)<<8ifserial:version+=serial_version_cache[version_string]=versionreturnversiondefversion_str(version):"""Converts a Dovecot version previously converted with version_hex back to a string. Raises a `TypeError` if *version* is not an int/long. Raises a `ValueError` if *version* is an incorrect int version. """global_version_cacheifversionin_version_cache:return_version_cache[version]ifnotisinstance(version,(int,long)):raiseTypeError('Argument is not a int/long: %r',version)major=(version>>28)&0xFFminor=(version>>20)&0xFFpatch=(version>>12)&0xFFlevel=(version>>8)&0x0Fserial=version&0xFFlevels=dict(zip(_version_level.values(),_version_level.keys()))iflevel==0xFandnotserial:version_string='%u.%u.%u'%(major,minor,patch)eliflevelinlevelsandnotpatch:version_string='%u.%u.%s%u'%(major,minor,levels[level],serial)else:raiseValueError('Invalid version: %r'%hex(version))_version_cache[version]=version_stringreturnversion_stringdefformat_domain_default(domaindata):"""Format info output when the value displayed is the domain default."""return_(u'%s [domain default]')%domaindatadefsearch_addresses(dbh,typelimit=None,lpattern=None,llike=False,dpattern=None,dlike=False):"""'Search' for addresses by *pattern* in the database. The search is limited by *typelimit*, a bitfield with values TYPE_ACCOUNT, TYPE_ALIAS, TYPE_RELOCATED, or a bitwise OR thereof. If no limit is specified, all types will be searched. *lpattern* may be a local part or a partial local part - starting and/or ending with a '%' sign. When the *lpattern* starts or ends with a '%' sign *llike* has to be `True` to perform a wildcard search. To retrieve all available addresses use the arguments' default values. *dpattern* and *dlike* behave analogously for the domain part of an address, allowing for separate pattern matching: testuser%@example.% The return value of this function is a tuple. The first element is a list of domain IDs sorted alphabetically by the corresponding domain names. The second element is a dictionary indexed by domain ID, holding lists to associated addresses. Each address is itself actually a tuple of address, type, and boolean indicating whether the address stems from an alias domain. """iftypelimit==None:typelimit=TYPE_ACCOUNT|TYPE_ALIAS|TYPE_RELOCATEDqueries=[]iftypelimit&TYPE_ACCOUNT:queries.append('SELECT gid, local_part, %d AS type FROM users'%TYPE_ACCOUNT)iftypelimit&TYPE_ALIAS:queries.append('SELECT gid, address as local_part, %d AS type ''FROM alias'%TYPE_ALIAS)iftypelimit&TYPE_RELOCATED:queries.append('SELECT gid, address as local_part, %d AS type ''FROM relocated'%TYPE_RELOCATED)sql="SELECT gid, local_part || '@' || domainname AS address, "sql+='type, NOT is_primary AS from_aliasdomain FROM ('sql+=' UNION '.join(queries)sql+=') a JOIN domain_name USING (gid)'nextkw='WHERE'sqlargs=[]forlike,field,patternin((dlike,'domainname',dpattern),(llike,'local_part',lpattern)):iflike:match='LIKE'else:ifnotpattern:continuematch='='sql+=' %s%s%s%%s'%(nextkw,field,match)sqlargs.append(pattern)nextkw='AND'sql+=' ORDER BY domainname, local_part'dbc=dbh.cursor()dbc.execute(sql,sqlargs)result=dbc.fetchall()dbc.close()gids=[]daddrs={}lastgid=Noneforgid,address,addrtype,aliasdomaininresult:ifgid!=lastgid:gids.append(gid)lastgid=giddaddrs[gid]=[]daddrs[gid].append((address,addrtype,aliasdomain))returngids,daddrsdel_