21 class Alias(object): |
21 class Alias(object): |
22 """Class to manage e-mail aliases.""" |
22 """Class to manage e-mail aliases.""" |
23 __slots__ = ('_addr', '_dests', '_gid', '_dbh') |
23 __slots__ = ('_addr', '_dests', '_gid', '_dbh') |
24 |
24 |
25 def __init__(self, dbh, address): |
25 def __init__(self, dbh, address): |
26 if isinstance(address, EmailAddress): |
26 if not isinstance(address, EmailAddress): |
27 self._addr = address |
|
28 else: |
|
29 raise TypeError("Argument 'address' is not an EmailAddress") |
27 raise TypeError("Argument 'address' is not an EmailAddress") |
|
28 self._addr = address |
30 self._dbh = dbh |
29 self._dbh = dbh |
31 self._gid = get_gid(self._dbh, self._addr.domainname) |
30 self._gid = get_gid(self._dbh, self._addr.domainname) |
32 self._dests = [] |
31 self._dests = [] |
33 |
32 |
34 self.__load_dests() |
33 self.__load_dests() |
51 dcount = len(self._dests) |
50 dcount = len(self._dests) |
52 failed = False |
51 failed = False |
53 if dcount == limit: |
52 if dcount == limit: |
54 failed = True |
53 failed = True |
55 errmsg = _( |
54 errmsg = _( |
56 u"""Can't add new destination to alias “%(address)s”. |
55 u"""Can't add new destination to alias %(address)r. |
57 Currently this alias expands into %(count)i/%(limit)i recipients. |
56 Currently this alias expands into %(count)i/%(limit)i recipients. |
58 One more destination will render this alias unusable. |
57 One more destination will render this alias unusable. |
59 Hint: Increase Postfix' virtual_alias_expansion_limit""") |
58 Hint: Increase Postfix' virtual_alias_expansion_limit""") |
60 elif dcount > limit: |
59 elif dcount > limit: |
61 failed = True |
60 failed = True |
62 errmsg = _( |
61 errmsg = _( |
63 u"""Can't add new destination to alias “%(address)s”. |
62 u"""Can't add new destination to alias %(address)r. |
64 This alias already exceeds it's expansion limit (%(count)i/%(limit)i). |
63 This alias already exceeds it's expansion limit (%(count)i/%(limit)i). |
65 So its unusable, all messages addressed to this alias will be bounced. |
64 So its unusable, all messages addressed to this alias will be bounced. |
66 Hint: Delete some destination addresses.""") |
65 Hint: Delete some destination addresses.""") |
67 if failed: |
66 if failed: |
68 raise VMMAE(errmsg % {'address': self._addr, 'count': dcount, |
67 raise VMMAE(errmsg % {'address': str(self._addr), 'count': dcount, |
69 'limit': limit}, |
68 'limit': limit}, |
70 ALIAS_EXCEEDS_EXPANSION_LIMIT) |
69 ALIAS_EXCEEDS_EXPANSION_LIMIT) |
71 |
70 |
72 def __delete(self, destination=None): |
71 def __delete(self, destination=None): |
73 """Deletes a destination from the alias, if ``destination`` is not |
72 """Deletes a destination from the alias, if ``destination`` is not |
74 ``None``. If ``destination`` is None, the alias with all it's |
73 ``None``. If ``destination`` is None, the alias with all it's |
75 destination addresses will be deleted.""" |
74 destination addresses will be deleted.""" |
76 dbc = self._dbh.cursor() |
75 dbc = self._dbh.cursor() |
77 if destination is None: |
76 if not destination: |
78 dbc.execute("DELETE FROM alias WHERE gid=%s AND address=%s", |
77 dbc.execute("DELETE FROM alias WHERE gid=%s AND address=%s", |
79 self._gid, self._addr.localpart) |
78 self._gid, self._addr.localpart) |
80 else: |
79 else: |
81 dbc.execute("DELETE FROM alias WHERE gid=%s AND address=%s AND \ |
80 dbc.execute("DELETE FROM alias WHERE gid=%s AND address=%s AND \ |
82 destination=%s", |
81 destination=%s", |
94 if not isinstance(destination, EmailAddress): |
93 if not isinstance(destination, EmailAddress): |
95 raise TypeError("Argument 'destination' is not an EmailAddress") |
94 raise TypeError("Argument 'destination' is not an EmailAddress") |
96 if self._addr == destination: |
95 if self._addr == destination: |
97 raise VMMAE(_(u"Address and destination are identical."), |
96 raise VMMAE(_(u"Address and destination are identical."), |
98 ALIAS_ADDR_DEST_IDENTICAL) |
97 ALIAS_ADDR_DEST_IDENTICAL) |
99 if not destination in self._dests: |
98 if destination in self._dests: |
100 self.__check_expansion(expansion_limit) |
99 raise VMMAE(_( |
101 dbc = self._dbh.cursor() |
100 u'The alias %(a)r has already the destination %(d)r.') % |
102 dbc.execute('INSERT INTO alias (gid, address, destination) \ |
101 {'a': str(self._addr), 'd': str(destination)}, |
|
102 ALIAS_EXISTS) |
|
103 self.__check_expansion(expansion_limit) |
|
104 dbc = self._dbh.cursor() |
|
105 dbc.execute('INSERT INTO alias (gid, address, destination) \ |
103 VALUES (%s, %s, %s)', |
106 VALUES (%s, %s, %s)', |
104 self._gid, self._addr.localpart, str(destination)) |
107 self._gid, self._addr.localpart, str(destination)) |
105 self._dbh.commit() |
108 self._dbh.commit() |
106 dbc.close() |
109 dbc.close() |
107 self._dests.append(destination) |
110 self._dests.append(destination) |
108 else: |
|
109 raise VMMAE(_( |
|
110 u'The alias “%(a)s” has already the destination “%(d)s”.') % |
|
111 {'a': self._addr, 'd': destination}, ALIAS_EXISTS) |
|
112 |
111 |
113 def delDestination(self, destination): |
112 def delDestination(self, destination): |
114 """Deletes the specified ``destination`` address from the alias.""" |
113 """Deletes the specified ``destination`` address from the alias.""" |
115 if not isinstance(destination, EmailAddress): |
114 if not isinstance(destination, EmailAddress): |
116 raise TypeError("Argument 'destination' is not an EmailAddress") |
115 raise TypeError("Argument 'destination' is not an EmailAddress") |
117 if not self._dests: |
116 if not self._dests: |
118 raise VMMAE(_(u"The alias “%s” doesn't exist.") % self._addr, |
117 raise VMMAE(_(u"The alias %r doesn't exist.") % str(self._addr), |
119 NO_SUCH_ALIAS) |
118 NO_SUCH_ALIAS) |
120 if not destination in self._dests: |
119 if not destination in self._dests: |
121 raise VMMAE(_(u"The address “%(d)s” isn't a destination of \ |
120 raise VMMAE(_(u"The address %(d)r isn't a destination of \ |
122 the alias “%(a)s”.") % |
121 the alias %(a)r.") % |
123 {'a': self._addr, 'd': destination}, NO_SUCH_ALIAS) |
122 {'a': str(self._addr), 'd': str(destination)}, |
|
123 NO_SUCH_ALIAS) |
124 self.__delete(destination) |
124 self.__delete(destination) |
125 self._dests.remove(destination) |
125 self._dests.remove(destination) |
126 |
126 |
127 def getDestinations(self): |
127 def getDestinations(self): |
128 """Returns an iterator for all destinations of the alias.""" |
128 """Returns an iterator for all destinations of the alias.""" |
129 if self._dests: |
129 if not self._dests: |
130 return iter(self._dests) |
130 raise VMMAE(_(u"The alias %r doesn't exist.") % str(self._addr), |
131 else: |
|
132 raise VMMAE(_(u"The alias “%s” doesn't exist.") % self._addr, |
|
133 NO_SUCH_ALIAS) |
131 NO_SUCH_ALIAS) |
|
132 return iter(self._dests) |
134 |
133 |
135 def delete(self): |
134 def delete(self): |
136 """Deletes the alias with all it's destinations.""" |
135 """Deletes the alias with all it's destinations.""" |
137 if self._dests: |
136 if not self._dests: |
138 self.__delete() |
137 raise VMMAE(_(u"The alias %r doesn't exist.") % str(self._addr), |
139 del self._dests[:] |
|
140 else: |
|
141 raise VMMAE(_(u"The alias “%s” doesn't exist.") % self._addr, |
|
142 NO_SUCH_ALIAS) |
138 NO_SUCH_ALIAS) |
|
139 self.__delete() |
|
140 del self._dests[:] |
143 |
141 |
144 |
142 |
145 del _ |
143 del _ |