VirtualMailManager/VirtualMailManager.py
changeset 35 22cc616aef61
parent 34 6d74e20c5b3b
child 38 c44ea4526546
equal deleted inserted replaced
34:6d74e20c5b3b 35:22cc616aef61
    31 from Domain import Domain
    31 from Domain import Domain
    32 
    32 
    33 SALTCHARS = './0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    33 SALTCHARS = './0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    34 RE_ASCII_CHARS = """^[\x20-\x7E]*$"""
    34 RE_ASCII_CHARS = """^[\x20-\x7E]*$"""
    35 RE_DOMAIN = """^(?:[a-z0-9-]{1,63}\.){1,}[a-z]{2,6}$"""
    35 RE_DOMAIN = """^(?:[a-z0-9-]{1,63}\.){1,}[a-z]{2,6}$"""
       
    36 RE_DOMAIN_SRCH = """^[a-z0-9-\.]+$"""
    36 RE_LOCALPART = """[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]"""
    37 RE_LOCALPART = """[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]"""
    37 RE_MAILLOCATION = """^[\w]{1,20}$"""
    38 RE_MAILLOCATION = """^[\w]{1,20}$"""
    38 re.compile(RE_ASCII_CHARS)
       
    39 re.compile(RE_DOMAIN)
       
    40 
    39 
    41 ENCODING_IN = sys.getfilesystemencoding()
    40 ENCODING_IN = sys.getfilesystemencoding()
    42 ENCODING_OUT = sys.stdout.encoding or sys.getfilesystemencoding()
    41 ENCODING_OUT = sys.stdout.encoding or sys.getfilesystemencoding()
    43 
    42 
    44 gettext.bindtextdomain('vmm', '/usr/local/share/locale')
    43 gettext.bindtextdomain('vmm', '/usr/local/share/locale')
   115             raise
   114             raise
   116 
   115 
   117     def __dbConnect(self):
   116     def __dbConnect(self):
   118         """Creates a pyPgSQL.PgSQL.connection instance."""
   117         """Creates a pyPgSQL.PgSQL.connection instance."""
   119         try:
   118         try:
   120             self.__dbh =  PgSQL.connect(
   119             self.__dbh = PgSQL.connect(
   121                     database=self.__Cfg.get('database', 'name'),
   120                     database=self.__Cfg.get('database', 'name'),
   122                     user=self.__Cfg.get('database', 'user'),
   121                     user=self.__Cfg.get('database', 'user'),
   123                     host=self.__Cfg.get('database', 'host'),
   122                     host=self.__Cfg.get('database', 'host'),
   124                     password=self.__Cfg.get('database', 'pass'),
   123                     password=self.__Cfg.get('database', 'pass'),
   125                     client_encoding='utf8', unicode_results=True)
   124                     client_encoding='utf8', unicode_results=True)
   142             raise VMMException((
   141             raise VMMException((
   143                 _(u'The local part »%s« contains invalid characters.') %
   142                 _(u'The local part »%s« contains invalid characters.') %
   144                 localpart, ERR.LOCALPART_INVALID))
   143                 localpart, ERR.LOCALPART_INVALID))
   145         return localpart
   144         return localpart
   146 
   145 
   147     def __idn2ascii(self, domainname):
   146     def idn2ascii(self, domainname):
   148         """Converts an idn domainname in punycode.
   147         """Converts an idn domainname in punycode.
   149         
   148         
   150         Keyword arguments:
   149         Keyword arguments:
   151         domainname -- the domainname to convert (str)
   150         domainname -- the domainname to convert (str)
   152         """
   151         """
   155             if len(label) == 0:
   154             if len(label) == 0:
   156                 continue
   155                 continue
   157             tmp.append(ToASCII(unicode(label, ENCODING_IN)))
   156             tmp.append(ToASCII(unicode(label, ENCODING_IN)))
   158         return '.'.join(tmp)
   157         return '.'.join(tmp)
   159 
   158 
   160     def __ace2idna(self, domainname):
   159     def ace2idna(self, domainname):
   161         """Convertis a domainname from ACE according to IDNA
   160         """Convertis a domainname from ACE according to IDNA
   162         
   161         
   163         Keyword arguments:
   162         Keyword arguments:
   164         domainname -- the domainname to convert (str)
   163         domainname -- the domainname to convert (str)
   165         """
   164         """
   174         """Validates the domain name of an e-mail address.
   173         """Validates the domain name of an e-mail address.
   175         
   174         
   176         Keyword arguments:
   175         Keyword arguments:
   177         domainname -- the domain name that should be validated
   176         domainname -- the domain name that should be validated
   178         """
   177         """
       
   178         re.compile(RE_ASCII_CHARS)
   179         if not re.match(RE_ASCII_CHARS, domainname):
   179         if not re.match(RE_ASCII_CHARS, domainname):
   180             domainname = self.__idn2ascii(domainname)
   180             domainname = self.idn2ascii(domainname)
   181         if len(domainname) > 255:
   181         if len(domainname) > 255:
   182             raise VMMException((_('The domain name is too long.'),
   182             raise VMMException((_('The domain name is too long.'),
   183                 ERR.DOMAIN_TOO_LONG))
   183                 ERR.DOMAIN_TOO_LONG))
       
   184         re.compile(RE_DOMAIN)
   184         if not re.match(RE_DOMAIN, domainname):
   185         if not re.match(RE_DOMAIN, domainname):
   185             raise VMMException((_('The domain name is invalid.'),
   186             raise VMMException((_('The domain name is invalid.'),
   186                 ERR.DOMAIN_INVALID))
   187                 ERR.DOMAIN_INVALID))
   187         return domainname
   188         return domainname
   188 
   189 
   452     def domain_info(self, domainname, detailed=None):
   453     def domain_info(self, domainname, detailed=None):
   453         dom = self.__getDomain(domainname)
   454         dom = self.__getDomain(domainname)
   454         dominfo = dom.getInfo()
   455         dominfo = dom.getInfo()
   455         if dominfo['domainname'].startswith('xn--'):
   456         if dominfo['domainname'].startswith('xn--'):
   456             dominfo['domainname'] += ' (%s)'\
   457             dominfo['domainname'] += ' (%s)'\
   457                 % self.__ace2idna(dominfo['domainname'])
   458                 % self.ace2idna(dominfo['domainname'])
   458         if dominfo['aliases'] is None:
   459         if dominfo['aliases'] is None:
   459             dominfo['aliases'] = 0
   460             dominfo['aliases'] = 0
   460         if detailed is None:
   461         if detailed is None:
   461             return dominfo
   462             return dominfo
   462         elif detailed == 'detailed':
   463         elif detailed == 'detailed':
   463             return dominfo, dom.getAccounts(), dom.getAliases()
   464             return dominfo, dom.getAccounts(), dom.getAliases()
   464         else:
   465         else:
   465             raise VMMDomainException(('%s: »%s«' % (_('Invalid argument'),
   466             raise VMMDomainException(('%s: »%s«' % (_('Invalid argument'),
   466                 detailed),  ERR.INVALID_OPTION))
   467                 detailed),  ERR.INVALID_OPTION))
   467 
   468 
       
   469     def domain_list(self, pattern=None):
       
   470         from Domain import search
       
   471         like = False
       
   472         if pattern is not None:
       
   473             if pattern.startswith('%') or pattern.endswith('%'):
       
   474                 like = True
       
   475                 if pattern.startswith('%') and pattern.endswith('%'):
       
   476                     domain = pattern[1:-1]
       
   477                 elif pattern.startswith('%'):
       
   478                     domain = pattern[1:]
       
   479                 elif pattern.endswith('%'):
       
   480                     domain = pattern[:-1]
       
   481                 re.compile(RE_DOMAIN_SRCH)
       
   482                 if not re.match(RE_DOMAIN_SRCH, domain):
       
   483                     raise VMMException((
       
   484                     _(u'The pattern »%s« contains invalid characters.') %
       
   485                     pattern, ERR.DOMAIN_INVALID))
       
   486             else:
       
   487                 pattern = self.__chkDomainname(pattern)
       
   488         self.__dbConnect()
       
   489         return search(self.__dbh, pattern=pattern, like=like)
       
   490 
   468     def user_add(self, emailaddress, password):
   491     def user_add(self, emailaddress, password):
   469         acc = self.__getAccount(emailaddress, password)
   492         acc = self.__getAccount(emailaddress, password)
   470         acc.save(self.__Cfg.get('maildir', 'folder'),
   493         acc.save(self.__Cfg.get('maildir', 'folder'),
   471                 self.__Cfg.getboolean('services', 'smtp'),
   494                 self.__Cfg.getboolean('services', 'smtp'),
   472                 self.__Cfg.getboolean('services', 'pop3'),
   495                 self.__Cfg.getboolean('services', 'pop3'),