VirtualMailManager/VirtualMailManager.py
changeset 3 a9b44e04bf01
parent 2 9b39f828aa8a
child 4 f3c30b7421b9
equal deleted inserted replaced
2:9b39f828aa8a 3:a9b44e04bf01
    40     def __init__(self):
    40     def __init__(self):
    41         """Creates a new VirtualMailManager instance.
    41         """Creates a new VirtualMailManager instance.
    42         Throws a VMMNotRootException if your uid is greater 0.
    42         Throws a VMMNotRootException if your uid is greater 0.
    43         """
    43         """
    44         self.__cfgFileName = '/usr/local/etc/vmm.cfg'
    44         self.__cfgFileName = '/usr/local/etc/vmm.cfg'
    45         self.__permWarnMsg = "fix permissions for '"+self.__cfgFileName \
    45         self.__permWarnMsg = "fix permissions for '%s'\n`chmod 0600 %s` would\
    46             +"'.\n`chmod 0600 "+self.__cfgFileName+"` would be great.\n"
    46  be great." % (self.__cfgFileName, self.__cfgFileName)
    47         self.__warnings = []
    47         self.__warnings = []
    48         self.__Cfg = None
    48         self.__Cfg = None
    49         self.__dbh = None
    49         self.__dbh = None
    50 
    50 
    51         if os.geteuid():
    51         if os.geteuid():
   112             dbc.close()
   112             dbc.close()
   113         except PgSQL.libpq.DatabaseError, e:
   113         except PgSQL.libpq.DatabaseError, e:
   114             raise VMMException((str(e), ERR.DATABASE_ERROR))
   114             raise VMMException((str(e), ERR.DATABASE_ERROR))
   115 
   115 
   116     def __chkLocalpart(self, localpart):
   116     def __chkLocalpart(self, localpart):
   117         """Validates the local part of an email address.
   117         """Validates the local part of an e-mail address.
   118         
   118         
   119         Keyword arguments:
   119         Keyword arguments:
   120         localpart -- the email address that should be validated (str)
   120         localpart -- the e-mail address that should be validated (str)
   121         """
   121         """
   122         if len(localpart) > 64:
   122         if len(localpart) > 64:
   123             raise VMMException(('The local part is too long',
   123             raise VMMException(('The local part is too long',
   124                 ERR.LOCALPART_TOO_LONG))
   124                 ERR.LOCALPART_TOO_LONG))
   125         if re.compile(RE_LOCALPART).search(localpart):
   125         if re.compile(RE_LOCALPART).search(localpart):
   126             raise VMMException((
   126             raise VMMException((
   127                 'The local part «%s» contains invalid characters.' % localpart,
   127                 'The local part »%s« contains invalid characters.' % localpart,
   128                 ERR.LOCALPART_INVALID))
   128                 ERR.LOCALPART_INVALID))
   129         return localpart
   129         return localpart
   130 
   130 
   131     def __idn2ascii(self, domainname):
   131     def __idn2ascii(self, domainname):
   132         """Converts an idn domainname in punycode.
   132         """Converts an idn domainname in punycode.
   153                 continue
   153                 continue
   154             tmp.append(ToUnicode(label))
   154             tmp.append(ToUnicode(label))
   155         return '.'.join(tmp)
   155         return '.'.join(tmp)
   156 
   156 
   157     def __chkDomainname(self, domainname):
   157     def __chkDomainname(self, domainname):
   158         """Validates the domain name of an email address.
   158         """Validates the domain name of an e-mail address.
   159         
   159         
   160         Keyword arguments:
   160         Keyword arguments:
   161         domainname -- the domain name that should be validated
   161         domainname -- the domain name that should be validated
   162         """
   162         """
   163         if not re.match(RE_ASCII_CHARS, domainname):
   163         if not re.match(RE_ASCII_CHARS, domainname):
   168         if not re.match(RE_DOMAIN, domainname):
   168         if not re.match(RE_DOMAIN, domainname):
   169             raise VMMException(('The domain name is invalid.',
   169             raise VMMException(('The domain name is invalid.',
   170                 ERR.DOMAIN_INVALID))
   170                 ERR.DOMAIN_INVALID))
   171         return domainname
   171         return domainname
   172 
   172 
   173     def __chkEmailadress(self, address):
   173     def __chkEmailAddress(self, address):
   174         try:
   174         try:
   175             localpart, domain = address.split('@')
   175             localpart, domain = address.split('@')
   176         except ValueError:
   176         except ValueError:
   177             raise VMMException(("Missing '@' sign in emailaddress «%s»." %
   177             raise VMMException(("Missing '@' sign in e-mail address »%s«." %
   178                 address, ERR.INVALID_ADDRESS))
   178                 address, ERR.INVALID_ADDRESS))
   179         except AttributeError:
   179         except AttributeError:
   180             raise VMMException(("'%s' looks not like an email address." %
   180             raise VMMException(("»%s« looks not like an e-mail address." %
   181                 address, ERR.INVALID_ADDRESS))
   181                 address, ERR.INVALID_ADDRESS))
   182         domain = self.__chkDomainname(domain)
   182         domain = self.__chkDomainname(domain)
   183         localpart = self.__chkLocalpart(localpart)
   183         localpart = self.__chkLocalpart(localpart)
   184         return '%s@%s' % (localpart, domain)
   184         return '%s@%s' % (localpart, domain)
   185 
   185 
   186     def __getAccount(self, address, password=None):
   186     def __getAccount(self, address, password=None):
   187         address = self.__chkEmailadress(address)
   187         address = self.__chkEmailAddress(address)
   188         self.__dbConnect()
   188         self.__dbConnect()
   189         if not password is None:
   189         if not password is None:
   190             password = self.__pwhash(password)
   190             password = self.__pwhash(password)
   191         return Account(self.__dbh, self.__Cfg.get('maildir', 'base'), address,
   191         return Account(self.__dbh, self.__Cfg.get('maildir', 'base'), address,
   192                 password)
   192                 password)
   193 
   193 
   194     def __getAlias(self, address, destination=None):
   194     def __getAlias(self, address, destination=None):
   195         address = self.__chkEmailadress(address)
   195         address = self.__chkEmailAddress(address)
   196         if not destination is None:
   196         if not destination is None:
   197             if destination.count('@'):
   197             if destination.count('@'):
   198                 destination = self.__chkEmailadress(destination)
   198                 destination = self.__chkEmailAddress(destination)
   199             else:
   199             else:
   200                 destination = self.__chkLocalpart(destination)
   200                 destination = self.__chkLocalpart(destination)
   201         self.__dbConnect()
   201         self.__dbConnect()
   202         return Alias(self.__dbh, address, self.__Cfg.get('maildir', 'base'),
   202         return Alias(self.__dbh, address, self.__Cfg.get('maildir', 'base'),
   203                 destination)
   203                 destination)
   337         """
   337         """
   338         try:
   338         try:
   339             if not section:
   339             if not section:
   340                 self.__Cfg.configure(self.__cfgSections)
   340                 self.__Cfg.configure(self.__cfgSections)
   341             elif section not in self.__cfgSections:
   341             elif section not in self.__cfgSections:
   342                 raise VMMException(("Invalid section: «%s»" % section,
   342                 raise VMMException(("Invalid section: »%s«" % section,
   343                     ERR.INVALID_SECTION))
   343                     ERR.INVALID_SECTION))
   344             else:
   344             else:
   345                 self.__Cfg.configure([section])
   345                 self.__Cfg.configure([section])
   346         except:
   346         except:
   347             raise
   347             raise
   355         dom = self.__getDomain(domainname, None)
   355         dom = self.__getDomain(domainname, None)
   356         dom.updateTransport(transport)
   356         dom.updateTransport(transport)
   357 
   357 
   358     def domain_delete(self, domainname, force=None):
   358     def domain_delete(self, domainname, force=None):
   359         if not force is None and force not in ['deluser','delalias','delall']:
   359         if not force is None and force not in ['deluser','delalias','delall']:
   360             raise VMMDomainException(('Invalid option: «%s»' % force,
   360             raise VMMDomainException(('Invalid argument: «%s»' % force,
   361                 ERR.INVALID_OPTION))
   361                 ERR.INVALID_OPTION))
   362         dom = self.__getDomain(domainname)
   362         dom = self.__getDomain(domainname)
   363         gid = dom.getID()
   363         gid = dom.getID()
   364         domdir = dom.getDir()
   364         domdir = dom.getDir()
   365         if self.__Cfg.getboolean('misc', 'forcedel') or force == 'delall':
   365         if self.__Cfg.getboolean('misc', 'forcedel') or force == 'delall':
   384         if detailed is None:
   384         if detailed is None:
   385             return dominfo
   385             return dominfo
   386         elif detailed == 'detailed':
   386         elif detailed == 'detailed':
   387             return dominfo, dom.getAccounts(), dom.getAliases()
   387             return dominfo, dom.getAccounts(), dom.getAliases()
   388         else:
   388         else:
   389             raise VMMDomainException(('Invalid option: «%s»' % detailed,
   389             raise VMMDomainException(('Invalid argument: »%s«' % detailed,
   390                 ERR.INVALID_OPTION))
   390                 ERR.INVALID_OPTION))
   391 
   391 
   392     def user_add(self, emailaddress, password):
   392     def user_add(self, emailaddress, password):
   393         acc = self.__getAccount(emailaddress, password)
   393         acc = self.__getAccount(emailaddress, password)
   394         acc.save(self.__Cfg.get('maildir', 'folder'))
   394         acc.save(self.__Cfg.get('maildir', 'folder'))