57 # http://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage |
58 # http://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage |
58 raise AErr(_(u"The domain '%s' doesn't exist.") % |
59 raise AErr(_(u"The domain '%s' doesn't exist.") % |
59 self._addr.domainname, NO_SUCH_DOMAIN) |
60 self._addr.domainname, NO_SUCH_DOMAIN) |
60 self._uid = 0 |
61 self._uid = 0 |
61 self._mail = None |
62 self._mail = None |
|
63 self._qlimit = self._domain.quotalimit |
62 self._transport = self._domain.transport |
64 self._transport = self._domain.transport |
63 self._passwd = None |
65 self._passwd = None |
64 self._new = True |
66 self._new = True |
65 self._load() |
67 self._load() |
66 |
68 |
67 def __nonzero__(self): |
69 def __nonzero__(self): |
68 """Returns `True` if the Account is known, `False` if it's new.""" |
70 """Returns `True` if the Account is known, `False` if it's new.""" |
69 return not self._new |
71 return not self._new |
70 |
72 |
71 def _load(self): |
73 def _load(self): |
72 """Load 'uid', 'mid' and 'tid' from the database and set _new to |
74 """Load 'uid', 'mid', 'qid' and 'tid' from the database and set |
73 `False` - if the user could be found. """ |
75 _new to `False` - if the user could be found. """ |
74 dbc = self._dbh.cursor() |
76 dbc = self._dbh.cursor() |
75 dbc.execute('SELECT uid, mid, tid FROM users WHERE gid = %s AND ' |
77 dbc.execute('SELECT uid, mid, qid, tid FROM users WHERE gid = %s AND ' |
76 'local_part=%s', (self._domain.gid, self._addr.localpart)) |
78 'local_part=%s', (self._domain.gid, self._addr.localpart)) |
77 result = dbc.fetchone() |
79 result = dbc.fetchone() |
78 dbc.close() |
80 dbc.close() |
79 if result: |
81 if result: |
80 self._uid, _mid, _tid = result |
82 self._uid, _mid, _qid, _tid = result |
|
83 if _qid != self._qlimit.qid: |
|
84 self._qlimit = QuotaLimit(self._dbh, qid=_qid) |
81 if _tid != self._transport.tid: |
85 if _tid != self._transport.tid: |
82 self._transport = Transport(self._dbh, tid=_tid) |
86 self._transport = Transport(self._dbh, tid=_tid) |
83 self._mail = MailLocation(self._dbh, mid=_mid) |
87 self._mail = MailLocation(self._dbh, mid=_mid) |
84 self._new = False |
88 self._new = False |
85 |
89 |
245 sieve_col = 'managesieve' |
271 sieve_col = 'managesieve' |
246 self._prepare(MailLocation(self._dbh, mbfmt=cfg_dget('mailbox.format'), |
272 self._prepare(MailLocation(self._dbh, mbfmt=cfg_dget('mailbox.format'), |
247 directory=cfg_dget('mailbox.root'))) |
273 directory=cfg_dget('mailbox.root'))) |
248 dbc = self._dbh.cursor() |
274 dbc = self._dbh.cursor() |
249 dbc.execute('INSERT INTO users (local_part, passwd, uid, gid, mid, ' |
275 dbc.execute('INSERT INTO users (local_part, passwd, uid, gid, mid, ' |
250 'tid, smtp, pop3, imap, %s) VALUES' % (sieve_col,) + \ |
276 'qid, tid, smtp, pop3, imap, %s) VALUES' % (sieve_col,) + \ |
251 '(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)', |
277 '(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)', |
252 (self._addr.localpart, |
278 (self._addr.localpart, |
253 pwhash(self._passwd, user=self._addr), self._uid, |
279 pwhash(self._passwd, user=self._addr), self._uid, |
254 self._domain.gid, self._mail.mid, self._transport.tid, |
280 self._domain.gid, self._mail.mid, self._qlimit.qid, |
255 cfg_dget('account.smtp'), cfg_dget('account.pop3'), |
281 self._transport.tid, cfg_dget('account.smtp'), |
256 cfg_dget('account.imap'), cfg_dget('account.sieve'))) |
282 cfg_dget('account.pop3'), cfg_dget('account.imap'), |
|
283 cfg_dget('account.sieve'))) |
257 self._dbh.commit() |
284 self._dbh.commit() |
258 dbc.close() |
285 dbc.close() |
259 self._new = False |
286 self._new = False |
260 |
287 |
261 def modify(self, field, value): |
288 def modify(self, field, value): |
262 """Update the Account's *field* to the new *value*. |
289 """Update the Account's *field* to the new *value*. |
263 |
290 |
264 Possible values for *field* are: 'name', 'password' and |
291 Possible values for *field* are: 'name', 'password'. |
265 'transport'. *value* is the *field*'s new value. |
|
266 |
292 |
267 Arguments: |
293 Arguments: |
268 |
294 |
269 `field` : basestring |
295 `field` : basestring |
270 The attribute name: 'name', 'password' or 'transport' |
296 The attribute name: 'name' or 'password' |
271 `value` : basestring |
297 `value` : basestring |
272 The new value of the attribute. |
298 The new value of the attribute. |
273 """ |
299 """ |
274 if field not in ('name', 'password', 'transport'): |
300 if field not in ('name', 'password'): |
275 raise AErr(_(u"Unknown field: '%s'") % field, INVALID_ARGUMENT) |
301 raise AErr(_(u"Unknown field: '%s'") % field, INVALID_ARGUMENT) |
276 self._chk_state() |
302 self._chk_state() |
277 dbc = self._dbh.cursor() |
303 dbc = self._dbh.cursor() |
278 if field == 'password': |
304 if field == 'password': |
279 dbc.execute('UPDATE users SET passwd = %s WHERE uid = %s', |
305 dbc.execute('UPDATE users SET passwd = %s WHERE uid = %s', |
280 (pwhash(value, user=self._addr), self._uid)) |
306 (pwhash(value, user=self._addr), self._uid)) |
281 elif field == 'transport': |
|
282 if value != self._transport.transport: |
|
283 self._transport = Transport(self._dbh, transport=value) |
|
284 dbc.execute('UPDATE users SET tid = %s WHERE uid = %s', |
|
285 (self._transport.tid, self._uid)) |
|
286 else: |
307 else: |
287 dbc.execute('UPDATE users SET name = %s WHERE uid = %s', |
308 dbc.execute('UPDATE users SET name = %s WHERE uid = %s', |
288 (value, self._uid)) |
309 (value, self._uid)) |
289 if dbc.rowcount > 0: |
310 if dbc.rowcount > 0: |
290 self._dbh.commit() |
311 self._dbh.commit() |
291 dbc.close() |
312 dbc.close() |
292 |
313 |
|
314 def update_quotalimit(self, quotalimit): |
|
315 """Update the user's quota limit. |
|
316 |
|
317 Arguments: |
|
318 |
|
319 `quotalimit` : VirtualMailManager.quotalimit.QuotaLimit |
|
320 the new quota limit of the domain. |
|
321 """ |
|
322 self._chk_state() |
|
323 assert isinstance(quotalimit, QuotaLimit) |
|
324 if quotalimit == self._qlimit: |
|
325 return |
|
326 self._update_tables('qid', quotalimit.qid) |
|
327 self._qlimit = quotalimit |
|
328 |
|
329 def update_transport(self, transport): |
|
330 """Sets a new transport for the Account. |
|
331 |
|
332 Arguments: |
|
333 |
|
334 `transport` : VirtualMailManager.transport.Transport |
|
335 the new transport |
|
336 """ |
|
337 self._chk_state() |
|
338 assert isinstance(transport, Transport) |
|
339 if transport == self._transport: |
|
340 return |
|
341 if transport.transport.lower() in ('virtual', 'virtual:') and \ |
|
342 not self._mail.postfix: |
|
343 raise AErr(_(u"Invalid transport '%(transport)s' for mailbox " |
|
344 u"format '%(mbfmt)s'") % |
|
345 {'transport': transport, 'mbfmt': self._mail.mbformat}, |
|
346 INVALID_MAIL_LOCATION) |
|
347 self._update_tables('tid', transport.tid) |
|
348 self._transport = transport |
|
349 |
293 def get_info(self): |
350 def get_info(self): |
294 """Returns a dict with some information about the Account. |
351 """Returns a dict with some information about the Account. |
295 |
352 |
296 The keys of the dict are: 'address', 'gid', 'home', 'imap' |
353 The keys of the dict are: 'address', 'gid', 'home', 'imap' |
297 'mail_location', 'name', 'pop3', 'sieve', 'smtp', transport' and |
354 'mail_location', 'name', 'pop3', 'sieve', 'smtp', transport', 'uid', |
298 'uid'. |
355 'uq_bytes', 'uq_messages', 'ql_bytes', and 'ql_messages'. |
299 """ |
356 """ |
300 self._chk_state() |
357 self._chk_state() |
301 if cfg_dget('misc.dovecot_version') >= 0x10200b02: |
358 if cfg_dget('misc.dovecot_version') >= 0x10200b02: |
302 sieve_col = 'sieve' |
359 sieve_col = 'sieve' |
303 else: |
360 else: |
304 sieve_col = 'managesieve' |
361 sieve_col = 'managesieve' |
305 sql = 'SELECT name, smtp, pop3, imap, %s FROM users WHERE uid = %d' % \ |
362 dbc = self._dbh.cursor() |
306 (sieve_col, self._uid) |
363 dbc.execute('SELECT name, smtp, pop3, imap, %s, CASE WHEN bytes IS ' |
307 dbc = self._dbh.cursor() |
364 'NULL THEN 0 ELSE bytes END, CASE WHEN messages IS NULL ' |
308 dbc.execute(sql) |
365 'THEN 0 ELSE messages END FROM users LEFT JOIN userquota ' |
|
366 'USING (uid) WHERE users.uid = %u' % (sieve_col, |
|
367 self._uid)) |
309 info = dbc.fetchone() |
368 info = dbc.fetchone() |
310 dbc.close() |
369 dbc.close() |
311 if info: |
370 if info: |
312 keys = ('name', 'smtp', 'pop3', 'imap', sieve_col) |
371 keys = ('name', 'smtp', 'pop3', 'imap', sieve_col, 'uq_bytes', |
|
372 'uq_messages') |
313 info = dict(zip(keys, info)) |
373 info = dict(zip(keys, info)) |
314 for service in keys[1:]: |
374 for service in keys[1:5]: |
315 if info[service]: |
375 if info[service]: |
316 # TP: A service (pop3/imap) is enabled/usable for a user |
376 # TP: A service (pop3/imap) is enabled/usable for a user |
317 info[service] = _('enabled') |
377 info[service] = _('enabled') |
318 else: |
378 else: |
319 # TP: A service (pop3/imap) isn't enabled/usable for a user |
379 # TP: A service (pop3/imap) isn't enabled/usable for a user |
320 info[service] = _('disabled') |
380 info[service] = _('disabled') |
321 info['address'] = self._addr |
381 info['address'] = self._addr |
322 info['gid'] = self._domain.gid |
382 info['gid'] = self._domain.gid |
323 info['home'] = '%s/%s' % (self._domain.directory, self._uid) |
383 info['home'] = '%s/%s' % (self._domain.directory, self._uid) |
324 info['mail_location'] = self._mail.mail_location |
384 info['mail_location'] = self._mail.mail_location |
|
385 info['ql_bytes'] = self._qlimit.bytes |
|
386 info['ql_messages'] = self._qlimit.messages |
325 info['transport'] = self._transport.transport |
387 info['transport'] = self._transport.transport |
326 info['uid'] = self._uid |
388 info['uid'] = self._uid |
327 return info |
389 return info |
328 # nearly impossibleā½ |
390 # nearly impossibleā½ |
329 raise AErr(_(u"Could not fetch information for account: '%s'") % |
391 raise AErr(_(u"Could not fetch information for account: '%s'") % |