# -*- coding: UTF-8 -*-# Copyright (c) 2008 - 2011, Pascal Volk# See COPYING for distribution information.""" VirtualMailManager.emailaddress ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Virtual Mail Manager's EmailAddress class to handle e-mail addresses."""importrefromVirtualMailManager.domainimportcheck_domainname,get_gidfromVirtualMailManager.constantsimport \DOMAIN_NO_NAME,INVALID_ADDRESS,LOCALPART_INVALID,LOCALPART_TOO_LONG, \DOMAIN_INVALIDfromVirtualMailManager.errorsimportDomainError,EmailAddressErrorasEAErrRE_LOCALPART=re.compile(r"[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]")_=lambdamsg:msgclassEmailAddress(object):"""Simple class for validated e-mail addresses."""__slots__=('_localpart','_domainname')def__init__(self,address,_validate=True):"""Creates a new instance from the string/unicode ``address``."""assertisinstance(address,basestring)self._localpart=Noneself._domainname=Noneif_validate:self._chk_address(address)@propertydeflocalpart(self):"""The local-part of the address *local-part@domain*"""returnself._localpart@propertydefdomainname(self):"""The domain part of the address *local-part@domain*"""returnself._domainnamedef__eq__(self,other):ifisinstance(other,self.__class__):returnself._localpart==other._localpartand \self._domainname==other._domainnamereturnNotImplementeddef__ne__(self,other):ifisinstance(other,self.__class__):returnself._localpart!=other._localpartor \self._domainname!=other._domainnamereturnNotImplementeddef__hash__(self):returnhash((self._localpart.lower(),self._domainname.lower()))def__repr__(self):return"EmailAddress('%s@%s')"%(self._localpart,self._domainname)def__str__(self):return'%s@%s'%(self._localpart,self._domainname)def_chk_address(self,address):"""Checks if the string ``address`` could be used for an e-mail address. If so, it will assign the corresponding values to the attributes `_localpart` and `_domainname`."""parts=address.split('@')p_len=len(parts)ifp_len<2:raiseEAErr(_(u"Missing the '@' sign in address: '%s'")%address,INVALID_ADDRESS)elifp_len>2:raiseEAErr(_(u"Too many '@' signs in address: '%s'")%address,INVALID_ADDRESS)ifnotparts[0]:raiseEAErr(_(u"Missing local-part in address: '%s'")%address,LOCALPART_INVALID)ifnotparts[1]:raiseEAErr(_(u"Missing domain name in address: '%s'")%address,DOMAIN_NO_NAME)self._localpart=check_localpart(parts[0])self._domainname=check_domainname(parts[1])classDestinationEmailAddress(EmailAddress):"""Provides additionally the domains group ID - when the domain is known in the database."""__slots__=('_gid','_localhost')def__init__(self,address,dbh,_validate=False):"""Creates a new DestinationEmailAddress instance Arguments: `address`: string/unicode a e-mail address like user@example.com `dbh`: pyPgSQL.PgSQL.Connection/pyPgSQL.PgSQL.connection a database connection for the database access """super(DestinationEmailAddress,self).__init__(address,_validate)self._localhost=Falseifnot_validate:try:self._chk_address(address)exceptDomainError,err:iferr.codeisDOMAIN_INVALIDand \address.split('@')[1]=='localhost':self._localhost=Trueself._domainname='localhost'else:raiseself._gid=0ifnotself._localhost:self._find_domain(dbh)else:self._localpart=self._localpart.lower()def_find_domain(self,dbh):"""Checks if the domain is known"""self._gid=get_gid(dbh,self._domainname)ifself._gid:self._localpart=self._localpart.lower()@propertydefat_localhost(self):"""True when the address is something@localhost."""returnself._localhost@propertydefgid(self):"""The domains group ID. 0 if the domain is not known."""returnself._giddefcheck_localpart(localpart):"""Returns the validated local-part `localpart`. Throws a `EmailAddressError` if the local-part is too long or contains invalid characters. """iflen(localpart)>64:raiseEAErr(_(u"The local-part '%s' is too long.")%localpart,LOCALPART_TOO_LONG)invalid_chars=set(RE_LOCALPART.findall(localpart))ifinvalid_chars:i_chars=u''.join((u'"%s" '%cforcininvalid_chars))raiseEAErr(_(u"The local-part '%(l_part)s' contains invalid "u"characters: %(i_chars)s")%{'l_part':localpart,'i_chars':i_chars},LOCALPART_INVALID)returnlocalpartdel_