127 else: |
127 else: |
128 raise |
128 raise |
129 |
129 |
130 def __dbConnect(self): |
130 def __dbConnect(self): |
131 """Creates a pyPgSQL.PgSQL.connection instance.""" |
131 """Creates a pyPgSQL.PgSQL.connection instance.""" |
132 if self.__dbh is None or (isinstance(self.__dbh, PgSQL.Connection) and |
132 if self._dbh is None or (isinstance(self._dbh, PgSQL.Connection) and |
133 not self.__dbh._isOpen): |
133 not self._dbh._isOpen): |
134 try: |
134 try: |
135 self.__dbh = PgSQL.connect( |
135 self._dbh = PgSQL.connect( |
136 database=self._Cfg.dget('database.name'), |
136 database=self._Cfg.dget('database.name'), |
137 user=self._Cfg.pget('database.user'), |
137 user=self._Cfg.pget('database.user'), |
138 host=self._Cfg.dget('database.host'), |
138 host=self._Cfg.dget('database.host'), |
139 password=self._Cfg.pget('database.pass'), |
139 password=self._Cfg.pget('database.pass'), |
140 client_encoding='utf8', unicode_results=True) |
140 client_encoding='utf8', unicode_results=True) |
141 dbc = self.__dbh.cursor() |
141 dbc = self._dbh.cursor() |
142 dbc.execute("SET NAMES 'UTF8'") |
142 dbc.execute("SET NAMES 'UTF8'") |
143 dbc.close() |
143 dbc.close() |
144 except PgSQL.libpq.DatabaseError, e: |
144 except PgSQL.libpq.DatabaseError, e: |
145 raise VMMException(str(e), ERR.DATABASE_ERROR) |
145 raise VMMException(str(e), ERR.DATABASE_ERROR) |
146 |
146 |
155 return True |
155 return True |
156 _exists = staticmethod(_exists) |
156 _exists = staticmethod(_exists) |
157 |
157 |
158 def accountExists(dbh, address): |
158 def accountExists(dbh, address): |
159 sql = "SELECT gid FROM users WHERE gid = (SELECT gid FROM domain_name\ |
159 sql = "SELECT gid FROM users WHERE gid = (SELECT gid FROM domain_name\ |
160 WHERE domainname = '%s') AND local_part = '%s'" % (address._domainname, |
160 WHERE domainname = '%s') AND local_part = '%s'" % (address.domainname, |
161 address._localpart) |
161 address.localpart) |
162 return Handler._exists(dbh, sql) |
162 return Handler._exists(dbh, sql) |
163 accountExists = staticmethod(accountExists) |
163 accountExists = staticmethod(accountExists) |
164 |
164 |
165 def aliasExists(dbh, address): |
165 def aliasExists(dbh, address): |
166 sql = "SELECT DISTINCT gid FROM alias WHERE gid = (SELECT gid FROM\ |
166 sql = "SELECT DISTINCT gid FROM alias WHERE gid = (SELECT gid FROM\ |
167 domain_name WHERE domainname = '%s') AND address = '%s'" % ( |
167 domain_name WHERE domainname = '%s') AND address = '%s'" % ( |
168 address._domainname, address._localpart) |
168 address.domainname, address.localpart) |
169 return Handler._exists(dbh, sql) |
169 return Handler._exists(dbh, sql) |
170 aliasExists = staticmethod(aliasExists) |
170 aliasExists = staticmethod(aliasExists) |
171 |
171 |
172 def relocatedExists(dbh, address): |
172 def relocatedExists(dbh, address): |
173 sql = "SELECT gid FROM relocated WHERE gid = (SELECT gid FROM\ |
173 sql = "SELECT gid FROM relocated WHERE gid = (SELECT gid FROM\ |
174 domain_name WHERE domainname = '%s') AND address = '%s'" % ( |
174 domain_name WHERE domainname = '%s') AND address = '%s'" % ( |
175 address._domainname, address._localpart) |
175 address.domainname, address.localpart) |
176 return Handler._exists(dbh, sql) |
176 return Handler._exists(dbh, sql) |
177 relocatedExists = staticmethod(relocatedExists) |
177 relocatedExists = staticmethod(relocatedExists) |
178 |
178 |
179 def __getAccount(self, address, password=None): |
179 def __getAccount(self, address, password=None): |
180 self.__dbConnect() |
180 self.__dbConnect() |
181 address = EmailAddress(address) |
181 address = EmailAddress(address) |
182 if not password is None: |
182 if not password is None: |
183 password = self.__pwhash(password) |
183 password = self.__pwhash(password) |
184 return Account(self.__dbh, address, password) |
184 return Account(self._dbh, address, password) |
185 |
185 |
186 def __getAlias(self, address, destination=None): |
186 def __getAlias(self, address): |
|
187 self.__dbConnect() |
|
188 address = EmailAddress(address) |
|
189 return Alias(self._dbh, address) |
|
190 |
|
191 def __getRelocated(self, address, destination=None): |
187 self.__dbConnect() |
192 self.__dbConnect() |
188 address = EmailAddress(address) |
193 address = EmailAddress(address) |
189 if destination is not None: |
194 if destination is not None: |
190 destination = EmailAddress(destination) |
195 destination = EmailAddress(destination) |
191 return Alias(self.__dbh, address, destination) |
196 return Relocated(self._dbh, address, destination) |
192 |
|
193 def __getRelocated(self, address, destination=None): |
|
194 self.__dbConnect() |
|
195 address = EmailAddress(address) |
|
196 if destination is not None: |
|
197 destination = EmailAddress(destination) |
|
198 return Relocated(self.__dbh, address, destination) |
|
199 |
197 |
200 def __getDomain(self, domainname, transport=None): |
198 def __getDomain(self, domainname, transport=None): |
201 if transport is None: |
199 if transport is None: |
202 transport = self._Cfg.dget('misc.transport') |
200 transport = self._Cfg.dget('misc.transport') |
203 self.__dbConnect() |
201 self.__dbConnect() |
204 return Domain(self.__dbh, domainname, |
202 return Domain(self._dbh, domainname, |
205 self._Cfg.dget('misc.base_directory'), transport) |
203 self._Cfg.dget('misc.base_directory'), transport) |
206 |
204 |
207 def __getDiskUsage(self, directory): |
205 def __getDiskUsage(self, directory): |
208 """Estimate file space usage for the given directory. |
206 """Estimate file space usage for the given directory. |
209 |
207 |
472 Keyword arguments: |
470 Keyword arguments: |
473 aliasname -- the name of the alias domain (str) |
471 aliasname -- the name of the alias domain (str) |
474 domainname -- name of the target domain (str) |
472 domainname -- name of the target domain (str) |
475 """ |
473 """ |
476 dom = self.__getDomain(domainname) |
474 dom = self.__getDomain(domainname) |
477 aliasDom = AliasDomain(self.__dbh, aliasname, dom) |
475 aliasDom = AliasDomain(self._dbh, aliasname, dom) |
478 aliasDom.save() |
476 aliasDom.save() |
479 |
477 |
480 def aliasDomainInfo(self, aliasname): |
478 def aliasDomainInfo(self, aliasname): |
481 self.__dbConnect() |
479 self.__dbConnect() |
482 aliasDom = AliasDomain(self.__dbh, aliasname, None) |
480 aliasDom = AliasDomain(self._dbh, aliasname, None) |
483 return aliasDom.info() |
481 return aliasDom.info() |
484 |
482 |
485 def aliasDomainSwitch(self, aliasname, domainname): |
483 def aliasDomainSwitch(self, aliasname, domainname): |
486 """Modifies the target domain of an existing alias domain. |
484 """Modifies the target domain of an existing alias domain. |
487 |
485 |
488 Keyword arguments: |
486 Keyword arguments: |
489 aliasname -- the name of the alias domain (str) |
487 aliasname -- the name of the alias domain (str) |
490 domainname -- name of the new target domain (str) |
488 domainname -- name of the new target domain (str) |
491 """ |
489 """ |
492 dom = self.__getDomain(domainname) |
490 dom = self.__getDomain(domainname) |
493 aliasDom = AliasDomain(self.__dbh, aliasname, dom) |
491 aliasDom = AliasDomain(self._dbh, aliasname, dom) |
494 aliasDom.switch() |
492 aliasDom.switch() |
495 |
493 |
496 def aliasDomainDelete(self, aliasname): |
494 def aliasDomainDelete(self, aliasname): |
497 """Deletes the specified alias domain. |
495 """Deletes the specified alias domain. |
498 |
496 |
499 Keyword arguments: |
497 Keyword arguments: |
500 aliasname -- the name of the alias domain (str) |
498 aliasname -- the name of the alias domain (str) |
501 """ |
499 """ |
502 self.__dbConnect() |
500 self.__dbConnect() |
503 aliasDom = AliasDomain(self.__dbh, aliasname, None) |
501 aliasDom = AliasDomain(self._dbh, aliasname, None) |
504 aliasDom.delete() |
502 aliasDom.delete() |
505 |
503 |
506 def domainList(self, pattern=None): |
504 def domainList(self, pattern=None): |
507 from Domain import search |
505 from Domain import search |
508 like = False |
506 like = False |
518 if not re.match(RE_DOMAIN_SRCH, domain): |
516 if not re.match(RE_DOMAIN_SRCH, domain): |
519 raise VMMException( |
517 raise VMMException( |
520 _(u"The pattern “%s” contains invalid characters.") % |
518 _(u"The pattern “%s” contains invalid characters.") % |
521 pattern, ERR.DOMAIN_INVALID) |
519 pattern, ERR.DOMAIN_INVALID) |
522 self.__dbConnect() |
520 self.__dbConnect() |
523 return search(self.__dbh, pattern=pattern, like=like) |
521 return search(self._dbh, pattern=pattern, like=like) |
524 |
522 |
525 def userAdd(self, emailaddress, password): |
523 def userAdd(self, emailaddress, password): |
526 if password is None or (isinstance(password, basestring) and |
524 if password is None or (isinstance(password, basestring) and |
527 not len(password)): |
525 not len(password)): |
528 raise ValueError('could not accept password: %r' % password) |
526 raise ValueError('could not accept password: %r' % password) |
534 self._Cfg.dget('account.imap'), |
532 self._Cfg.dget('account.imap'), |
535 self._Cfg.dget('account.sieve')) |
533 self._Cfg.dget('account.sieve')) |
536 self.__mailDirMake(acc.getDir('domain'), acc.getUID(), acc.getGID()) |
534 self.__mailDirMake(acc.getDir('domain'), acc.getUID(), acc.getGID()) |
537 |
535 |
538 def aliasAdd(self, aliasaddress, targetaddress): |
536 def aliasAdd(self, aliasaddress, targetaddress): |
539 alias = self.__getAlias(aliasaddress, targetaddress) |
537 """Creates a new `Alias` entry for the given *aliasaddress* with |
540 alias.save(long(self._postconf.read('virtual_alias_expansion_limit'))) |
538 the given *targetaddress*.""" |
541 gid = self.__getDomain(alias._dest._domainname).getID() |
539 alias = self.__getAlias(aliasaddress) |
542 if gid > 0 and (not Handler.accountExists(self.__dbh, alias._dest) and |
540 destination = EmailAddress(targetaddress) |
543 not Handler.aliasExists(self.__dbh, alias._dest)): |
541 alias.addDestination(destination, |
|
542 long(self._postconf.read('virtual_alias_expansion_limit'))) |
|
543 gid = self.__getDomain(destination.domainname).getID() |
|
544 if gid > 0 and (not Handler.accountExists(self._dbh, destination) and |
|
545 not Handler.aliasExists(self._dbh, destination)): |
544 self.__warnings.append( |
546 self.__warnings.append( |
545 _(u"The destination account/alias “%s” doesn't exist.") % |
547 _(u"The destination account/alias “%s” doesn't exist.") % |
546 alias._dest) |
548 destination) |
547 |
549 |
548 def userDelete(self, emailaddress, force=None): |
550 def userDelete(self, emailaddress, force=None): |
549 if force not in [None, 'delalias']: |
551 if force not in [None, 'delalias']: |
550 raise VMMException(_(u"Invalid argument: “%s”") % force, |
552 raise VMMException(_(u"Invalid argument: “%s”") % force, |
551 ERR.INVALID_AGUMENT) |
553 ERR.INVALID_AGUMENT) |
568 self.__warnings.append(warning) |
570 self.__warnings.append(warning) |
569 else: |
571 else: |
570 raise |
572 raise |
571 |
573 |
572 def aliasInfo(self, aliasaddress): |
574 def aliasInfo(self, aliasaddress): |
|
575 """Returns an iterator object for all destinations (`EmailAddress` |
|
576 instances) for the `Alias` with the given *aliasaddress*.""" |
573 alias = self.__getAlias(aliasaddress) |
577 alias = self.__getAlias(aliasaddress) |
574 return alias.getInfo() |
578 try: |
|
579 return alias.getDestinations() |
|
580 except VMMAliasException, e: |
|
581 if e.code() == ERR.NO_SUCH_ALIAS: |
|
582 if Handler.accountExists(self._dbh, alias._addr): |
|
583 raise VMMException( |
|
584 _(u'There is already an account with address “%s”.') % |
|
585 aliasaddress, ERR.ACCOUNT_EXISTS) |
|
586 if Handler.relocatedExists(self._dbh, alias._addr): |
|
587 raise VMMException(_(u'There is already a relocated user \ |
|
588 with the address “%s”.') % |
|
589 aliasaddress, ERR.RELOCATED_EXISTS) |
|
590 raise |
|
591 else: |
|
592 raise |
575 |
593 |
576 def aliasDelete(self, aliasaddress, targetaddress=None): |
594 def aliasDelete(self, aliasaddress, targetaddress=None): |
577 alias = self.__getAlias(aliasaddress, targetaddress) |
595 """Deletes the `Alias` *aliasaddress* with all its destinations from |
578 alias.delete() |
596 the database. If *targetaddress* is not ``None``, only this |
|
597 destination will be removed from the alias.""" |
|
598 alias = self.__getAlias(aliasaddress) |
|
599 if targetaddress is None: |
|
600 alias.delete() |
|
601 else: |
|
602 alias.delDestination(EmailAddress(targetaddress)) |
579 |
603 |
580 def userInfo(self, emailaddress, details=None): |
604 def userInfo(self, emailaddress, details=None): |
581 if details not in (None, 'du', 'aliases', 'full'): |
605 if details not in (None, 'du', 'aliases', 'full'): |
582 raise VMMException(_(u'Invalid argument: “%s”') % details, |
606 raise VMMException(_(u'Invalid argument: “%s”') % details, |
583 ERR.INVALID_AGUMENT) |
607 ERR.INVALID_AGUMENT) |