Apply 01_defaults.debian.patch
[mspang/vmailman.git] / Mailman / MemberAdaptor.py
1 # Copyright (C) 2001-2003 by the Free Software Foundation, Inc.
2 #
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
17 """This is an interface to list-specific membership information.
18
19 This class should not be instantiated directly, but instead, it should be
20 subclassed for specific adaptation to membership databases.  The default
21 MM2.0.x style adaptor is in OldStyleMemberships.py.  Through the extend.py
22 mechanism, you can instantiate different membership information adaptors to
23 get info out of LDAP, Zope, other, or any combination of the above.
24
25 Members have three pieces of identifying information: a unique identifying
26 opaque key (KEY), a lower-cased email address (LCE), and a case-preserved
27 email (CPE) address.  Adaptors must ensure that both member keys and lces can
28 uniquely identify a member, and that they can (usually) convert freely between
29 keys and lces.  Most methods must accept either a key or an lce, unless
30 specifically documented otherwise.
31
32 The CPE is always used to calculate the recipient address for a message.  Some
33 remote MTAs make a distinction based on localpart case, so we always send
34 messages to the case-preserved address.  Note that DNS is case insensitive so
35 it doesn't matter what the case is for the domain part of an email address,
36 although by default, we case-preserve that too.
37
38 The adaptors must support the readable interface for getting information about
39 memberships, and may optionally support the writeable interface.  If they do
40 not, then members cannot change their list attributes via Mailman's web or
41 email interfaces.  Updating membership information in that case is the
42 backend's responsibility.  Adaptors are allowed to support parts of the
43 writeable interface.
44
45 For any writeable method not supported, a NotImplementedError exception should
46 be raised.
47 """
48
49 # Delivery statuses
50 ENABLED  = 0                                      # enabled
51 UNKNOWN  = 1                                      # legacy disabled
52 BYUSER   = 2                                      # disabled by user choice
53 BYADMIN  = 3                                      # disabled by admin choice
54 BYBOUNCE = 4                                      # disabled by bounces
55
56
57 \f
58 class MemberAdaptor:
59     #
60     # The readable interface
61     #
62     def getMembers(self):
63         """Get the LCE for all the members of the mailing list."""
64         raise NotImplementedError
65
66     def getRegularMemberKeys(self):
67         """Get the LCE for all regular delivery members (i.e. non-digest)."""
68         raise NotImplementedError
69
70     def getDigestMemberKeys(self):
71         """Get the LCE for all digest delivery members."""
72         raise NotImplementedError
73
74     def isMember(self, member):
75         """Return 1 if member KEY/LCE is a valid member, otherwise 0."""
76
77     def getMemberKey(self, member):
78         """Return the KEY for the member KEY/LCE.
79
80         If member does not refer to a valid member, raise NotAMemberError.
81         """
82         raise NotImplementedError
83
84     def getMemberCPAddress(self, member):
85         """Return the CPE for the member KEY/LCE.
86
87         If member does not refer to a valid member, raise NotAMemberError.
88         """
89         raise NotImplementedError
90
91     def getMemberCPAddresses(self, members):
92         """Return a sequence of CPEs for the given sequence of members.
93
94         The returned sequence will be the same length as members.  If any of
95         the KEY/LCEs in members does not refer to a valid member, that entry
96         in the returned sequence will be None (i.e. NotAMemberError is never
97         raised).
98         """
99         raise NotImplementedError
100
101     def authenticateMember(self, member, response):
102         """Authenticate the member KEY/LCE with the given response.
103
104         If the response authenticates the member, return a secret that is
105         known only to the authenticated member.  This need not be the member's
106         password, but it will be used to craft a session cookie, so it should
107         be persistent for the life of the session.
108
109         If the authentication failed return False.  If member did not refer to
110         a valid member, raise NotAMemberError.
111
112         Normally, the response will be the password typed into a web form or
113         given in an email command, but it needn't be.  It is up to the adaptor
114         to compare the typed response to the user's authentication token.
115         """
116         raise NotImplementedError
117
118     def getMemberPassword(self, member):
119         """Return the member's password.
120
121         If the member KEY/LCE is not a member of the list, raise
122         NotAMemberError.
123         """
124         raise NotImplementedError
125
126     def getMemberLanguage(self, member):
127         """Return the preferred language for the member KEY/LCE.
128
129         The language returned must be a key in mm_cfg.LC_DESCRIPTIONS and the
130         mailing list must support that language.
131
132         If member does not refer to a valid member, the list's default
133         language is returned instead of raising a NotAMemberError error.
134         """
135         raise NotImplementedError
136
137     def getMemberOption(self, member, flag):
138         """Return the boolean state of the member option for member KEY/LCE.
139
140         Option flags are defined in Defaults.py.
141
142         If member does not refer to a valid member, raise NotAMemberError.
143         """
144         raise NotImplementedError
145
146     def getMemberName(self, member):
147         """Return the full name of the member KEY/LCE.
148
149         None is returned if the member has no registered full name.  The
150         returned value may be a Unicode string if there are non-ASCII
151         characters in the name.  NotAMemberError is raised if member does not
152         refer to a valid member.
153         """
154         raise NotImplementedError
155
156     def getMemberTopics(self, member):
157         """Return the list of topics this member is interested in.
158
159         The return value is a list of strings which name the topics.
160         """
161         raise NotImplementedError
162
163     def getDeliveryStatus(self, member):
164         """Return the delivery status of this member.
165
166         Value is one of the module constants:
167
168             ENABLED  - The deliveries to the user are not disabled
169             UNKNOWN  - Deliveries are disabled for unknown reasons.  The
170                        primary reason for this to happen is that we've copied
171                        their delivery status from a legacy version which didn't
172                        keep track of disable reasons
173             BYUSER   - The user explicitly disable deliveries
174             BYADMIN  - The list administrator explicitly disabled deliveries
175             BYBOUNCE - The system disabled deliveries due to bouncing
176
177         If member is not a member of the list, raise NotAMemberError.
178         """
179         raise NotImplementedError
180
181     def getDeliveryStatusChangeTime(self, member):
182         """Return the time of the last disabled delivery status change.
183
184         If the current delivery status is ENABLED, the status change time will
185         be zero.  If member is not a member of the list, raise
186         NotAMemberError.
187         """
188         raise NotImplementedError
189
190     def getDeliveryStatusMembers(self,
191                                  status=(UNKNOWN, BYUSER, BYADMIN, BYBOUNCE)):
192         """Return the list of members with a matching delivery status.
193
194         Optional `status' if given, must be a sequence containing one or more
195         of ENABLED, UNKNOWN, BYUSER, BYADMIN, or BYBOUNCE.  The members whose
196         delivery status is in this sequence are returned.
197         """
198         raise NotImplementedError
199
200     def getBouncingMembers(self):
201         """Return the list of members who have outstanding bounce information.
202
203         This list of members doesn't necessarily overlap with
204         getDeliveryStatusMembers() since getBouncingMembers() will return
205         member who have bounced but not yet reached the disable threshold.
206         """
207         raise NotImplementedError
208
209     def getBounceInfo(self, member):
210         """Return the member's bounce information.
211
212         A value of None means there is no bounce information registered for
213         the member.
214
215         Bounce info is opaque to the MemberAdaptor.  It is set by
216         setBounceInfo() and returned by this method without modification.
217
218         If member is not a member of the list, raise NotAMemberError.
219         """
220         raise NotImplementedError
221
222 \f
223     #
224     # The writeable interface
225     #
226     def addNewMember(self, member, **kws):
227         """Subscribes a new member to the mailing list.
228
229         member is the case-preserved address to subscribe.  The LCE is
230         calculated from this argument.  Return the new member KEY.
231
232         This method also takes a keyword dictionary which can be used to set
233         additional attributes on the member.  The actual set of supported
234         keywords is adaptor specific, but should at least include:
235
236         - digest == subscribing to digests instead of regular delivery
237         - password == user's password
238         - language == user's preferred language
239         - realname == user's full name (should be Unicode if there are
240           non-ASCII characters in the name)
241
242         Any values not passed to **kws is set to the adaptor-specific
243         defaults.
244
245         Raise AlreadyAMemberError it the member is already subscribed to the
246         list.  Raises ValueError if **kws contains an invalid option.
247         """
248         raise NotImplementedError
249
250     def removeMember(self, memberkey):
251         """Unsubscribes the member from the mailing list.
252
253         Raise NotAMemberError if member is not subscribed to the list.
254         """
255         raise NotImplementedError
256
257     def changeMemberAddress(self, memberkey, newaddress, nodelete=0):
258         """Change the address for the member KEY.
259
260         memberkey will be a KEY, not an LCE.  newaddress should be the
261         new case-preserved address for the member; the LCE will be calculated
262         from newaddress.
263
264         If memberkey does not refer to a valid member, raise NotAMemberError.
265         No verification on the new address is done here (such assertions
266         should be performed by the caller).
267
268         If nodelete flag is true, then the old membership is not removed.
269         """
270         raise NotImplementedError
271
272     def setMemberPassword(self, member, password):
273         """Set the password for member LCE/KEY.
274
275         If member does not refer to a valid member, raise NotAMemberError.
276         Also raise BadPasswordError if the password is illegal (e.g. too
277         short or easily guessed via a dictionary attack).
278         """
279         raise NotImplementedError
280
281     def setMemberLanguage(self, member, language):
282         """Set the language for the member LCE/KEY.
283
284         If member does not refer to a valid member, raise NotAMemberError.
285         Also raise BadLanguageError if the language is invalid (e.g. the list
286         is not configured to support the given language).
287         """
288         raise NotImplementedError
289
290     def setMemberOption(self, member, flag, value):
291         """Set the option for the given member to value.
292
293         member is an LCE/KEY, flag is one of the option flags defined in
294         Default.py, and value is a boolean.
295
296         If member does not refer to a valid member, raise NotAMemberError.
297         Also raise BadOptionError if the flag does not refer to a valid
298         option.
299         """
300         raise NotImplementedError
301
302     def setMemberName(self, member, realname):
303         """Set the member's full name.
304
305         member is an LCE/KEY and realname is an arbitrary string.  It should
306         be a Unicode string if there are non-ASCII characters in the name.
307         NotAMemberError is raised if member does not refer to a valid member.
308         """
309         raise NotImplementedError
310
311     def setMemberTopics(self, member, topics):
312         """Add list of topics to member's interest.
313
314         member is an LCE/KEY and realname is an arbitrary string.
315         NotAMemberError is raised if member does not refer to a valid member.
316         topics must be a sequence of strings.
317         """
318         raise NotImplementedError
319
320     def setDeliveryStatus(self, member, status):
321         """Set the delivery status of the member's address.
322
323         Status must be one of the module constants:
324
325             ENABLED  - The deliveries to the user are not disabled
326             UNKNOWN  - Deliveries are disabled for unknown reasons.  The
327                        primary reason for this to happen is that we've copied
328                        their delivery status from a legacy version which didn't
329                        keep track of disable reasons
330             BYUSER   - The user explicitly disable deliveries
331             BYADMIN  - The list administrator explicitly disabled deliveries
332             BYBOUNCE - The system disabled deliveries due to bouncing
333
334         This method also records the time (in seconds since epoch) at which
335         the last status change was made.  If the delivery status is changed to
336         ENABLED, then the change time information will be deleted.  This value
337         is retrievable via getDeliveryStatusChangeTime().
338         """
339         raise NotImplementedError
340
341     def setBounceInfo(self, member, info):
342         """Set the member's bounce information.
343
344         When info is None, any bounce info for the member is cleared.
345
346         Bounce info is opaque to the MemberAdaptor.  It is set by this method
347         and returned by getBounceInfo() without modification.
348         """
349         raise NotImplementedError