36 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}$""" |
37 RE_DOMAIN_SRCH = """^[a-z0-9-\.]+$""" |
36 RE_DOMAIN_SRCH = """^[a-z0-9-\.]+$""" |
38 RE_LOCALPART = """[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]""" |
37 RE_LOCALPART = """[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]""" |
39 RE_MAILLOCATION = """^[\w]{1,20}$""" |
38 RE_MAILLOCATION = """^[\w]{1,20}$""" |
40 |
39 |
41 ENCODING_IN = sys.getfilesystemencoding() |
|
42 ENCODING_OUT = sys.stdout.encoding or sys.getfilesystemencoding() |
|
43 |
|
44 gettext.bindtextdomain('vmm', '/usr/local/share/locale') |
|
45 gettext.textdomain('vmm') |
|
46 _ = gettext.gettext |
|
47 |
|
48 class VirtualMailManager: |
40 class VirtualMailManager: |
49 """The main class for vmm""" |
41 """The main class for vmm""" |
50 def __init__(self): |
42 def __init__(self): |
51 """Creates a new VirtualMailManager instance. |
43 """Creates a new VirtualMailManager instance. |
52 Throws a VMMNotRootException if your uid is greater 0. |
44 Throws a VMMNotRootException if your uid is greater 0. |
53 """ |
45 """ |
54 self.__cfgFileName = '/usr/local/etc/vmm.cfg' |
46 self.__cfgFileName = '/usr/local/etc/vmm.cfg' |
55 self.__permWarnMsg = _("fix permissions for '%s'\n`chmod 0600 %s` would\ |
47 self.__permWarnMsg = _(u"fix permissions for »%s«\n`chmod 0600 %s`\ |
56 be great.") % (self.__cfgFileName, self.__cfgFileName) |
48 would be great.") % (self.__cfgFileName, self.__cfgFileName) |
57 self.__warnings = [] |
49 self.__warnings = [] |
58 self.__Cfg = None |
50 self.__Cfg = None |
59 self.__dbh = None |
51 self.__dbh = None |
60 |
52 |
61 if os.geteuid(): |
53 if os.geteuid(): |
62 raise VMMNotRootException((_("You are not root.\n\tGood bye!\n"), |
54 raise VMMNotRootException((_(u"You are not root.\n\tGood bye!\n"), |
63 ERR.CONF_NOPERM)) |
55 ERR.CONF_NOPERM)) |
64 if self.__chkCfgFile(): |
56 if self.__chkCfgFile(): |
65 self.__Cfg = Cfg(self.__cfgFileName) |
57 self.__Cfg = Cfg(self.__cfgFileName) |
66 self.__Cfg.load() |
58 self.__Cfg.load() |
67 self.__Cfg.check() |
59 self.__Cfg.check() |
71 self.__chkenv() |
63 self.__chkenv() |
72 |
64 |
73 def __chkCfgFile(self): |
65 def __chkCfgFile(self): |
74 """Checks the configuration file, returns bool""" |
66 """Checks the configuration file, returns bool""" |
75 if not os.path.isfile(self.__cfgFileName): |
67 if not os.path.isfile(self.__cfgFileName): |
76 raise VMMException((_(u"The file '%s' does not exists.") % |
68 raise VMMException((_(u"The file »%s« does not exists.") % |
77 self.__cfgFileName, ERR.CONF_NOFILE)) |
69 self.__cfgFileName, ERR.CONF_NOFILE)) |
78 fstat = os.stat(self.__cfgFileName) |
70 fstat = os.stat(self.__cfgFileName) |
79 try: |
71 try: |
80 fmode = self.__getFileMode() |
72 fmode = self.__getFileMode() |
81 except: |
73 except: |
93 os.makedirs(self.__Cfg.get('domdir', 'base'), 0771) |
85 os.makedirs(self.__Cfg.get('domdir', 'base'), 0771) |
94 os.chown(self.__Cfg.get('domdir', 'base'), 0, |
86 os.chown(self.__Cfg.get('domdir', 'base'), 0, |
95 self.__Cfg.getint('misc', 'gid_mail')) |
87 self.__Cfg.getint('misc', 'gid_mail')) |
96 os.umask(old_umask) |
88 os.umask(old_umask) |
97 elif not os.path.isdir(self.__Cfg.get('domdir', 'base')): |
89 elif not os.path.isdir(self.__Cfg.get('domdir', 'base')): |
98 raise VMMException((_('%s is not a directory') % |
90 raise VMMException((_(u'»%s« is not a directory.\n\ |
|
91 (vmm.cfg: section "domdir", option "base")') % |
99 self.__Cfg.get('domdir', 'base'), ERR.NO_SUCH_DIRECTORY)) |
92 self.__Cfg.get('domdir', 'base'), ERR.NO_SUCH_DIRECTORY)) |
100 for opt, val in self.__Cfg.items('bin'): |
93 for opt, val in self.__Cfg.items('bin'): |
101 if not os.path.exists(val): |
94 if not os.path.exists(val): |
102 raise VMMException((_("%s doesn't exists.") % val, |
95 raise VMMException((_(u'»%s« doesn\'t exists.\n\ |
103 ERR.NO_SUCH_BINARY)) |
96 (vmm.cfg: section "bin", option "%s")') % (val, opt), ERR.NO_SUCH_BINARY)) |
104 elif not os.access(val, os.X_OK): |
97 elif not os.access(val, os.X_OK): |
105 raise VMMException((_("%s is not executable.") % val, |
98 raise VMMException((_(u'»%s« is not executable.\n\ |
106 ERR.NOT_EXECUTABLE)) |
99 (vmm.cfg: section "bin", option "%s")') % (val, opt), ERR.NOT_EXECUTABLE)) |
107 |
100 |
108 def __getFileMode(self): |
101 def __getFileMode(self): |
109 """Determines the file access mode from file __cfgFileName, |
102 """Determines the file access mode from file __cfgFileName, |
110 returns int. |
103 returns int. |
111 """ |
104 """ |
127 dbc.execute("SET NAMES 'UTF8'") |
120 dbc.execute("SET NAMES 'UTF8'") |
128 dbc.close() |
121 dbc.close() |
129 except PgSQL.libpq.DatabaseError, e: |
122 except PgSQL.libpq.DatabaseError, e: |
130 raise VMMException((str(e), ERR.DATABASE_ERROR)) |
123 raise VMMException((str(e), ERR.DATABASE_ERROR)) |
131 |
124 |
132 def __chkLocalpart(self, localpart): |
125 def chkLocalpart(localpart): |
133 """Validates the local part of an e-mail address. |
126 """Validates the local part of an e-mail address. |
134 |
127 |
135 Keyword arguments: |
128 Keyword arguments: |
136 localpart -- the e-mail address that should be validated (str) |
129 localpart -- the e-mail address that should be validated (str) |
137 """ |
130 """ |
|
131 if len(localpart) < 1: |
|
132 raise VMMException((_(u'No localpart specified.'), |
|
133 ERR.LOCALPART_INVALID)) |
138 if len(localpart) > 64: |
134 if len(localpart) > 64: |
139 raise VMMException((_('The local part is too long'), |
135 raise VMMException((_(u'The local part »%s« is too long') % |
140 ERR.LOCALPART_TOO_LONG)) |
136 localpart, ERR.LOCALPART_TOO_LONG)) |
141 if re.compile(RE_LOCALPART).search(localpart): |
137 ic = re.compile(RE_LOCALPART).findall(localpart) |
|
138 if len(ic): |
|
139 ichrs = '' |
|
140 for c in set(ic): |
|
141 ichrs += u"»%s« " % c |
142 raise VMMException(( |
142 raise VMMException(( |
143 _(u"The local part '%s' contains invalid characters.") % |
143 _(u"The local part »%s« contains invalid characters: %s") % |
144 localpart, ERR.LOCALPART_INVALID)) |
144 (localpart, ichrs), ERR.LOCALPART_INVALID)) |
145 return localpart |
145 return localpart |
146 |
146 chkLocalpart = staticmethod(chkLocalpart) |
147 def idn2ascii(self, domainname): |
147 |
|
148 def idn2ascii(domainname): |
148 """Converts an idn domainname in punycode. |
149 """Converts an idn domainname in punycode. |
149 |
150 |
150 Keyword arguments: |
151 Keyword arguments: |
151 domainname -- the domainname to convert (str) |
152 domainname -- the domainname to convert (str) |
152 """ |
153 """ |
153 tmp = [] |
154 tmp = [] |
154 for label in domainname.split('.'): |
155 for label in domainname.split('.'): |
155 if len(label) == 0: |
156 if len(label) == 0: |
156 continue |
157 continue |
157 tmp.append(ToASCII(unicode(label, ENCODING_IN))) |
158 #tmp.append(ToASCII(unicode(label, ENCODING_IN))) |
|
159 tmp.append(ToASCII(label)) |
158 return '.'.join(tmp) |
160 return '.'.join(tmp) |
159 |
161 idn2ascii = staticmethod(idn2ascii) |
160 def ace2idna(self, domainname): |
162 |
|
163 def ace2idna(domainname): |
161 """Convertis a domainname from ACE according to IDNA |
164 """Convertis a domainname from ACE according to IDNA |
162 |
165 |
163 Keyword arguments: |
166 Keyword arguments: |
164 domainname -- the domainname to convert (str) |
167 domainname -- the domainname to convert (str) |
165 """ |
168 """ |
167 for label in domainname.split('.'): |
170 for label in domainname.split('.'): |
168 if len(label) == 0: |
171 if len(label) == 0: |
169 continue |
172 continue |
170 tmp.append(ToUnicode(label)) |
173 tmp.append(ToUnicode(label)) |
171 return '.'.join(tmp) |
174 return '.'.join(tmp) |
172 |
175 ace2idna = staticmethod(ace2idna) |
173 def __chkDomainname(self, domainname): |
176 |
|
177 def chkDomainname(domainname): |
174 """Validates the domain name of an e-mail address. |
178 """Validates the domain name of an e-mail address. |
175 |
179 |
176 Keyword arguments: |
180 Keyword arguments: |
177 domainname -- the domain name that should be validated |
181 domainname -- the domain name that should be validated |
178 """ |
182 """ |
179 re.compile(RE_ASCII_CHARS) |
183 re.compile(RE_ASCII_CHARS) |
180 if not re.match(RE_ASCII_CHARS, domainname): |
184 if not re.match(RE_ASCII_CHARS, domainname): |
181 domainname = self.idn2ascii(domainname) |
185 domainname = VirtualMailManager.idn2ascii(domainname) |
182 if len(domainname) > 255: |
186 if len(domainname) > 255: |
183 raise VMMException((_('The domain name is too long.'), |
187 raise VMMException((_(u'The domain name is too long.'), |
184 ERR.DOMAIN_TOO_LONG)) |
188 ERR.DOMAIN_TOO_LONG)) |
185 re.compile(RE_DOMAIN) |
189 re.compile(RE_DOMAIN) |
186 if not re.match(RE_DOMAIN, domainname): |
190 if not re.match(RE_DOMAIN, domainname): |
187 raise VMMException((_('The domain name is invalid.'), |
191 raise VMMException((_(u'The domain name is invalid.'), |
188 ERR.DOMAIN_INVALID)) |
192 ERR.DOMAIN_INVALID)) |
189 return domainname |
193 return domainname |
190 |
194 chkDomainname = staticmethod(chkDomainname) |
191 def __chkEmailAddress(self, address): |
195 |
|
196 def chkEmailAddress(address): |
192 try: |
197 try: |
193 localpart, domain = address.split('@') |
198 localpart, domain = address.split('@') |
194 except ValueError: |
199 except ValueError: |
195 raise VMMException((_(u"Missing '@' sign in e-mail address '%s'.") % |
200 raise VMMException((_(u"Missing '@' sign in e-mail address »%s«.") % |
196 address, ERR.INVALID_ADDRESS)) |
201 address, ERR.INVALID_ADDRESS)) |
197 except AttributeError: |
202 except AttributeError: |
198 raise VMMException((_(u"'%s' looks not like an e-mail address.") % |
203 raise VMMException((_(u"»%s« looks not like an e-mail address.") % |
199 address, ERR.INVALID_ADDRESS)) |
204 address, ERR.INVALID_ADDRESS)) |
200 domain = self.__chkDomainname(domain) |
205 domain = VirtualMailManager.chkDomainname(domain) |
201 localpart = self.__chkLocalpart(localpart) |
206 localpart = VirtualMailManager.chkLocalpart(localpart) |
202 return '%s@%s' % (localpart, domain) |
207 return '%s@%s' % (localpart, domain) |
|
208 chkEmailAddress = staticmethod(chkEmailAddress) |
203 |
209 |
204 def __getAccount(self, address, password=None): |
210 def __getAccount(self, address, password=None): |
205 address = self.__chkEmailAddress(address) |
|
206 self.__dbConnect() |
211 self.__dbConnect() |
207 if not password is None: |
212 if not password is None: |
208 password = self.__pwhash(password) |
213 password = self.__pwhash(password) |
209 return Account(self.__dbh, address, password) |
214 return Account(self.__dbh, address, password) |
210 |
215 |
222 clear0 = '' |
227 clear0 = '' |
223 sys.stderr.write('%s\n' % _('Sorry, passwords do not match')) |
228 sys.stderr.write('%s\n' % _('Sorry, passwords do not match')) |
224 return clear0 |
229 return clear0 |
225 |
230 |
226 def __getAlias(self, address, destination=None): |
231 def __getAlias(self, address, destination=None): |
227 address = self.__chkEmailAddress(address) |
232 address = VirtualMailManager.chkEmailAddress(address) |
228 if not destination is None: |
233 if not destination is None: |
229 if destination.count('@'): |
234 if destination.count('@'): |
230 destination = self.__chkEmailAddress(destination) |
235 destination = VirtualMailManager.chkEmailAddress(destination) |
231 else: |
236 else: |
232 destination = self.__chkLocalpart(destination) |
237 destination = VirtualMailManager.chkLocalpart(destination) |
233 self.__dbConnect() |
238 self.__dbConnect() |
234 return Alias(self.__dbh, address, destination) |
239 return Alias(self.__dbh, address, destination) |
235 |
240 |
236 def __getDomain(self, domainname, transport=None): |
241 def __getDomain(self, domainname, transport=None): |
237 domainname = self.__chkDomainname(domainname) |
242 domainname = VirtualMailManager.chkDomainname(domainname) |
238 if transport is None: |
243 if transport is None: |
239 transport = self.__Cfg.get('misc', 'transport') |
244 transport = self.__Cfg.get('misc', 'transport') |
240 self.__dbConnect() |
245 self.__dbConnect() |
241 return Domain(self.__dbh, domainname, |
246 return Domain(self.__dbh, domainname, |
242 self.__Cfg.get('domdir', 'base'), transport) |
247 self.__Cfg.get('domdir', 'base'), transport) |
312 |
317 |
313 def __maildirdelete(self, domdir, uid, gid): |
318 def __maildirdelete(self, domdir, uid, gid): |
314 if uid > 0 and gid > 0: |
319 if uid > 0 and gid > 0: |
315 maildir = '%s' % uid |
320 maildir = '%s' % uid |
316 if maildir.count('..') or domdir.count('..'): |
321 if maildir.count('..') or domdir.count('..'): |
317 raise VMMException((_('FATAL: ".." in maildir path detected.'), |
322 raise VMMException((_(u'Found ".." in maildir path.'), |
318 ERR.FOUND_DOTS_IN_PATH)) |
323 ERR.FOUND_DOTS_IN_PATH)) |
319 if os.path.isdir(domdir): |
324 if os.path.isdir(domdir): |
320 os.chdir(domdir) |
325 os.chdir(domdir) |
321 if os.path.isdir(maildir): |
326 if os.path.isdir(maildir): |
322 mdstat = os.stat(maildir) |
327 mdstat = os.stat(maildir) |
323 if (mdstat.st_uid, mdstat.st_gid) != (uid, gid): |
328 if (mdstat.st_uid, mdstat.st_gid) != (uid, gid): |
324 raise VMMException(( |
329 raise VMMException(( |
325 _('FATAL: owner/group mismatch in maildir detected'), |
330 _(u'Owner/group mismatch in maildir detected.'), |
326 ERR.MAILDIR_PERM_MISMATCH)) |
331 ERR.MAILDIR_PERM_MISMATCH)) |
327 rmtree(maildir, ignore_errors=True) |
332 rmtree(maildir, ignore_errors=True) |
328 else: |
333 else: |
329 self.__warnings.append(_('No such directory: %s/%s') % |
334 raise VMMException((_(u"No such directory: %s/%s") % |
330 (domdir,uid)) |
335 (domdir, uid), ERR.NO_SUCH_DIRECTORY)) |
331 |
336 |
332 def __domdirdelete(self, domdir, gid): |
337 def __domdirdelete(self, domdir, gid): |
333 if gid > 0: |
338 if gid > 0: |
334 if not self.__isdir(domdir): |
339 if not self.__isdir(domdir): |
335 return |
340 return |
336 basedir = '%s' % self.__Cfg.get('domdir', 'base') |
341 basedir = '%s' % self.__Cfg.get('domdir', 'base') |
337 domdirdirs = domdir.replace(basedir+'/', '').split('/') |
342 domdirdirs = domdir.replace(basedir+'/', '').split('/') |
338 if basedir.count('..') or domdir.count('..'): |
343 if basedir.count('..') or domdir.count('..'): |
339 raise VMMException( |
344 raise VMMException( |
340 (_('FATAL: ".." in domain directory path detected.'), |
345 (_(u'FATAL: ".." in domain directory path detected.'), |
341 ERR.FOUND_DOTS_IN_PATH)) |
346 ERR.FOUND_DOTS_IN_PATH)) |
342 if os.path.isdir('%s/%s' % (basedir, domdirdirs[0])): |
347 if os.path.isdir('%s/%s' % (basedir, domdirdirs[0])): |
343 os.chdir('%s/%s' % (basedir, domdirdirs[0])) |
348 os.chdir('%s/%s' % (basedir, domdirdirs[0])) |
344 if os.lstat(domdirdirs[1]).st_gid != gid: |
349 if os.lstat(domdirdirs[1]).st_gid != gid: |
345 raise VMMException( |
350 raise VMMException( |
346 (_('FATAL: group mismatch in domain directory detected'), |
351 (_(u'FATAL: group mismatch in domain directory detected'), |
347 ERR.DOMAINDIR_GROUP_MISMATCH)) |
352 ERR.DOMAINDIR_GROUP_MISMATCH)) |
348 rmtree(domdirdirs[1], ignore_errors=True) |
353 rmtree(domdirdirs[1], ignore_errors=True) |
349 |
354 |
350 def __getSalt(self): |
355 def __getSalt(self): |
351 from random import choice |
356 from random import choice |
428 def setupIsDone(self): |
433 def setupIsDone(self): |
429 """Checks if vmm is configured, returns bool""" |
434 """Checks if vmm is configured, returns bool""" |
430 try: |
435 try: |
431 return self.__Cfg.getboolean('config', 'done') |
436 return self.__Cfg.getboolean('config', 'done') |
432 except ValueError, e: |
437 except ValueError, e: |
433 raise VMMConfigException(_("""Configurtion error: "%s" |
438 raise VMMConfigException(_(u"""Configurtion error: "%s" |
434 (in section "connfig", option "done")' |
439 (in section "connfig", option "done") see also: vmm.cfg(5)\n""") % |
435 see also: vmm.cfg(5)\n""") % str(e)) |
440 str(e)) |
436 |
441 |
437 def configure(self, section=None): |
442 def configure(self, section=None): |
438 """Starts interactive configuration. |
443 """Starts interactive configuration. |
439 |
444 |
440 Configures in interactive mode options in the given section. |
445 Configures in interactive mode options in the given section. |
471 else: |
476 else: |
472 dom.updateTransport(transport, force=True) |
477 dom.updateTransport(transport, force=True) |
473 |
478 |
474 def domain_delete(self, domainname, force=None): |
479 def domain_delete(self, domainname, force=None): |
475 if not force is None and force not in ['deluser','delalias','delall']: |
480 if not force is None and force not in ['deluser','delalias','delall']: |
476 raise VMMDomainException((_(u"Invalid argument: '%s'") % force, |
481 raise VMMDomainException((_(u"Invalid argument: »%s«") % force, |
477 ERR.INVALID_OPTION)) |
482 ERR.INVALID_OPTION)) |
478 dom = self.__getDomain(domainname) |
483 dom = self.__getDomain(domainname) |
479 gid = dom.getID() |
484 gid = dom.getID() |
480 domdir = dom.getDir() |
485 domdir = dom.getDir() |
481 if self.__Cfg.getboolean('misc', 'forcedel') or force == 'delall': |
486 if self.__Cfg.getboolean('misc', 'forcedel') or force == 'delall': |
492 def domain_info(self, domainname, detailed=None): |
497 def domain_info(self, domainname, detailed=None): |
493 dom = self.__getDomain(domainname) |
498 dom = self.__getDomain(domainname) |
494 dominfo = dom.getInfo() |
499 dominfo = dom.getInfo() |
495 if dominfo['domainname'].startswith('xn--'): |
500 if dominfo['domainname'].startswith('xn--'): |
496 dominfo['domainname'] += ' (%s)'\ |
501 dominfo['domainname'] += ' (%s)'\ |
497 % self.ace2idna(dominfo['domainname']) |
502 % VirtualMailManager.ace2idna(dominfo['domainname']) |
498 if dominfo['aliases'] is None: |
503 if dominfo['aliases'] is None: |
499 dominfo['aliases'] = 0 |
504 dominfo['aliases'] = 0 |
500 if detailed is None: |
505 if detailed is None: |
501 return dominfo |
506 return dominfo |
502 elif detailed == 'detailed': |
507 elif detailed == 'detailed': |
503 return (dominfo, dom.getAliaseNames(), dom.getAccounts(), |
508 return (dominfo, dom.getAliaseNames(), dom.getAccounts(), |
504 dom.getAliases()) |
509 dom.getAliases()) |
505 else: |
510 else: |
506 raise VMMDomainException(("%s: '%s'" % (_('Invalid argument'), |
511 raise VMMDomainException((_(u'Invalid argument: »%s«') % detailed, |
507 detailed), ERR.INVALID_OPTION)) |
512 ERR.INVALID_OPTION)) |
508 |
513 |
509 def domain_alias_add(self, aliasname, domainname): |
514 def domain_alias_add(self, aliasname, domainname): |
510 """Adds an alias name to the domain. |
515 """Adds an alias name to the domain. |
511 |
516 |
512 Keyword arguments: |
517 Keyword arguments: |
513 aliasname -- the alias name of the domain (str) |
518 aliasname -- the alias name of the domain (str) |
514 domainname -- name of the target domain (str) |
519 domainname -- name of the target domain (str) |
515 """ |
520 """ |
516 dom = self.__getDomain(domainname) |
521 dom = self.__getDomain(domainname) |
517 aliasname = self.__chkDomainname(aliasname) |
522 # XXX chk by DomainAlias!!! |
|
523 aliasname = VirtualMailManager.chkDomainname(aliasname) |
518 dom.saveAlias(aliasname) |
524 dom.saveAlias(aliasname) |
519 |
525 |
520 def domain_alias_delete(self, aliasname): |
526 def domain_alias_delete(self, aliasname): |
521 """Deletes the specified alias name. |
527 """Deletes the specified alias name. |
522 |
528 |
523 Keyword arguments: |
529 Keyword arguments: |
524 aliasname -- the alias name of the domain (str) |
530 aliasname -- the alias name of the domain (str) |
525 """ |
531 """ |
526 from Domain import deleteAlias |
532 from Domain import deleteAlias |
527 aliasname = self.__chkDomainname(aliasname) |
533 aliasname = VirtualMailManager.chkDomainname(aliasname) |
|
534 # XXX chk by DomainAlias!!! |
528 self.__dbConnect() |
535 self.__dbConnect() |
529 deleteAlias(self.__dbh, aliasname) |
536 deleteAlias(self.__dbh, aliasname) |
530 |
537 |
531 def domain_list(self, pattern=None): |
538 def domain_list(self, pattern=None): |
532 from Domain import search |
539 from Domain import search |
544 if not re.match(RE_DOMAIN_SRCH, domain): |
551 if not re.match(RE_DOMAIN_SRCH, domain): |
545 raise VMMException(( |
552 raise VMMException(( |
546 _(u"The pattern '%s' contains invalid characters.") % |
553 _(u"The pattern '%s' contains invalid characters.") % |
547 pattern, ERR.DOMAIN_INVALID)) |
554 pattern, ERR.DOMAIN_INVALID)) |
548 else: |
555 else: |
549 pattern = self.__chkDomainname(pattern) |
556 pattern = VirtualMailManager.chkDomainname(pattern) |
|
557 # XXX chk by domain if not like |
550 self.__dbConnect() |
558 self.__dbConnect() |
551 return search(self.__dbh, pattern=pattern, like=like) |
559 return search(self.__dbh, pattern=pattern, like=like) |
552 |
560 |
553 def user_add(self, emailaddress, password): |
561 def user_add(self, emailaddress, password): |
554 acc = self.__getAccount(emailaddress, password) |
562 acc = self.__getAccount(emailaddress, password) |
570 acc = self.__getAccount(emailaddress) |
578 acc = self.__getAccount(emailaddress) |
571 uid = acc.getUID() |
579 uid = acc.getUID() |
572 gid = acc.getGID() |
580 gid = acc.getGID() |
573 acc.delete() |
581 acc.delete() |
574 if self.__Cfg.getboolean('maildir', 'delete'): |
582 if self.__Cfg.getboolean('maildir', 'delete'): |
575 self.__maildirdelete(acc.getDir('domain'), uid, gid) |
583 try: |
|
584 self.__maildirdelete(acc.getDir('domain'), uid, gid) |
|
585 except (VMMException), e: |
|
586 if e[0][1] in [ERR.FOUND_DOTS_IN_PATH, |
|
587 ERR.MAILDIR_PERM_MISMATCH, ERR.NO_SUCH_DIRECTORY]: |
|
588 warning = _(u"""\ |
|
589 The account has been successfully deleted from the database. |
|
590 But an error occurred while deleting the following directory: |
|
591 »%s« |
|
592 Reason: %s""") % (acc.getDir('home'), e[0][0]) |
|
593 self.__warnings.append(warning) |
|
594 else: |
|
595 raise e |
576 |
596 |
577 def alias_info(self, aliasaddress): |
597 def alias_info(self, aliasaddress): |
578 alias = self.__getAlias(aliasaddress) |
598 alias = self.__getAlias(aliasaddress) |
579 return alias.getInfo() |
599 return alias.getInfo() |
580 |
600 |
595 return getAccountByID(uid, self.__dbh) |
615 return getAccountByID(uid, self.__dbh) |
596 |
616 |
597 def user_password(self, emailaddress, password): |
617 def user_password(self, emailaddress, password): |
598 acc = self.__getAccount(emailaddress) |
618 acc = self.__getAccount(emailaddress) |
599 if acc.getUID() == 0: |
619 if acc.getUID() == 0: |
600 raise VMMException((_("Account doesn't exists"),ERR.NO_SUCH_ACCOUNT)) |
620 raise VMMException((_(u"Account doesn't exists"), |
|
621 ERR.NO_SUCH_ACCOUNT)) |
601 if password is None: |
622 if password is None: |
602 password = self._readpass() |
623 password = self._readpass() |
603 acc.modify('password', self.__pwhash(password)) |
624 acc.modify('password', self.__pwhash(password)) |
604 |
625 |
605 def user_name(self, emailaddress, name): |
626 def user_name(self, emailaddress, name): |