aboutsummaryrefslogtreecommitdiffstats
path: root/Mailman/MemberAdaptor.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Mailman/MemberAdaptor.py350
1 files changed, 350 insertions, 0 deletions
diff --git a/Mailman/MemberAdaptor.py b/Mailman/MemberAdaptor.py
new file mode 100644
index 00000000..dc24ea08
--- /dev/null
+++ b/Mailman/MemberAdaptor.py
@@ -0,0 +1,350 @@
+# Copyright (C) 2001,2002 by the Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""This is an interface to list-specific membership information.
+
+This class should not be instantiated directly, but instead, it should be
+subclassed for specific adaptation to membership databases. The default
+MM2.0.x style adaptor is in OldStyleMemberships.py. Through the extend.py
+mechanism, you can instantiate different membership information adaptors to
+get info out of LDAP, Zope, other, or any combination of the above.
+
+Members have three pieces of identifying information: a unique identifying
+opaque key (KEY), a lower-cased email address (LCE), and a case-preserved
+email (CPE) address. Adaptors must ensure that both member keys and lces can
+uniquely identify a member, and that they can (usually) convert freely between
+keys and lces. Most methods must accept either a key or an lce, unless
+specifically documented otherwise.
+
+The CPE is always used to calculate the recipient address for a message. Some
+remote MTAs make a distinction based on localpart case, so we always send
+messages to the case-preserved address. Note that DNS is case insensitive so
+it doesn't matter what the case is for the domain part of an email address,
+although by default, we case-preserve that too.
+
+The adaptors must support the readable interface for getting information about
+memberships, and may optionally support the writeable interface. If they do
+not, then members cannot change their list attributes via Mailman's web or
+email interfaces. Updating membership information in that case is the
+backend's responsibility. Adaptors are allowed to support parts of the
+writeable interface.
+
+For any writeable method not supported, a NotImplemented exception should be
+raised.
+"""
+
+# Delivery statuses
+ENABLED = 0 # enabled
+UNKNOWN = 1 # legacy disabled
+BYUSER = 2 # disabled by user choice
+BYADMIN = 3 # disabled by admin choice
+BYBOUNCE = 4 # disabled by bounces
+
+
+
+class MemberAdaptor:
+ #
+ # The readable interface
+ #
+ def getMembers(self):
+ """Get the LCE for all the members of the mailing list."""
+ raise NotImplemented
+
+ def getRegularMemberKeys(self):
+ """Get the LCE for all regular delivery members (i.e. non-digest)."""
+ raise NotImplemented
+
+ def getDigestMemberKeys(self):
+ """Get the LCE for all digest delivery members."""
+ raise NotImplemented
+
+ def isMember(self, member):
+ """Return 1 if member KEY/LCE is a valid member, otherwise 0."""
+
+ def getMemberKey(self, member):
+ """Return the KEY for the member KEY/LCE.
+
+ If member does not refer to a valid member, raise NotAMemberError.
+ """
+ raise NotImplemented
+
+ def getMemberCPAddress(self, member):
+ """Return the CPE for the member KEY/LCE.
+
+ If member does not refer to a valid member, raise NotAMemberError.
+ """
+ raise NotImplemented
+
+ def getMemberCPAddresses(self, members):
+ """Return a sequence of CPEs for the given sequence of members.
+
+ The returned sequence will be the same length as members. If any of
+ the KEY/LCEs in members does not refer to a valid member, that entry
+ in the returned sequence will be None (i.e. NotAMemberError is never
+ raised).
+ """
+ raise NotImplemented
+
+ def authenticateMember(self, member, response):
+ """Authenticate the member KEY/LCE with the given response.
+
+ If the response authenticates the member, return a secret that is
+ known only to the authenticated member. This need not be the member's
+ password, but it will be used to craft a session cookie, so it should
+ be persistent for the life of the session.
+
+ If the authentication failed return 0. If member did not refer to a
+ valid member, raise NotAMemberError.
+
+ Normally, the response will be the password typed into a web form or
+ given in an email command, but it needn't be. It is up to the adaptor
+ to compare the typed response to the user's authentication token.
+ """
+ raise NotImplemented
+
+ def getMemberPassword(self, member):
+ """Return the member's password.
+
+ If the member KEY/LCE is not a member of the list, raise
+ NotAMemberError.
+ """
+ raise NotImplemented
+
+ def getMemberLanguage(self, member):
+ """Return the preferred language for the member KEY/LCE.
+
+ The language returned must be a key in mm_cfg.LC_DESCRIPTIONS and the
+ mailing list must support that language.
+
+ If member does not refer to a valid member, the list's default
+ language is returned instead of raising a NotAMemberError error.
+ """
+ raise NotImplemented
+
+ def getMemberOption(self, member, flag):
+ """Return the boolean state of the member option for member KEY/LCE.
+
+ Option flags are defined in Defaults.py.
+
+ If member does not refer to a valid member, raise NotAMemberError.
+ """
+ raise NotImplemented
+
+ def getMemberName(self, member):
+ """Return the full name of the member KEY/LCE.
+
+ None is returned if the member has no registered full name. The
+ returned value may be a Unicode string if there are non-ASCII
+ characters in the name. NotAMemberError is raised if member does not
+ refer to a valid member.
+ """
+ raise NotImplemented
+
+ def getMemberTopics(self, member):
+ """Return the list of topics this member is interested in.
+
+ The return value is a list of strings which name the topics.
+ """
+ raise NotImplemented
+
+ def getDeliveryStatus(self, member):
+ """Return the delivery status of this member.
+
+ Value is one of the module constants:
+
+ ENABLED - The deliveries to the user are not disabled
+ UNKNOWN - Deliveries are disabled for unknown reasons. The
+ primary reason for this to happen is that we've copied
+ their delivery status from a legacy version which didn't
+ keep track of disable reasons
+ BYUSER - The user explicitly disable deliveries
+ BYADMIN - The list administrator explicitly disabled deliveries
+ BYBOUNCE - The system disabled deliveries due to bouncing
+
+ If member is not a member of the list, raise NotAMemberError.
+ """
+ raise NotImplemented
+
+ def getDeliveryStatusChangeTime(self, member):
+ """Return the time of the last disabled delivery status change.
+
+ If the current delivery status is ENABLED, the status change time will
+ be zero. If member is not a member of the list, raise
+ NotAMemberError.
+ """
+ raise NotImplemented
+
+ def getDeliveryStatusMembers(self,
+ status=(UNKNOWN, BYUSER, BYADMIN, BYBOUNCE)):
+ """Return the list of members with a matching delivery status.
+
+ Optional `status' if given, must be a sequence containing one or more
+ of ENABLED, UNKNOWN, BYUSER, BYADMIN, or BYBOUNCE. The members whose
+ delivery status is in this sequence are returned.
+ """
+ raise NotImplemented
+
+ def getBouncingMembers(self):
+ """Return the list of members who have outstanding bounce information.
+
+ This list of members doesn't necessarily overlap with
+ getDeliveryStatusMembers() since getBouncingMembers() will return
+ member who have bounced but not yet reached the disable threshold.
+ """
+ raise NotImplemented
+
+ def getBounceInfo(self, member):
+ """Return the member's bounce information.
+
+ A value of None means there is no bounce information registered for
+ the member.
+
+ Bounce info is opaque to the MemberAdaptor. It is set by
+ setBounceInfo() and returned by this method without modification.
+
+ If member is not a member of the list, raise NotAMemberError.
+ """
+ raise NotImplemented
+
+
+ #
+ # The writeable interface
+ #
+ def addNewMember(self, member, **kws):
+ """Subscribes a new member to the mailing list.
+
+ member is the case-preserved address to subscribe. The LCE is
+ calculated from this argument. Return the new member KEY.
+
+ This method also takes a keyword dictionary which can be used to set
+ additional attributes on the member. The actual set of supported
+ keywords is adaptor specific, but should at least include:
+
+ - digest == subscribing to digests instead of regular delivery
+ - password == user's password
+ - language == user's preferred language
+ - realname == user's full name (should be Unicode if there are
+ non-ASCII characters in the name)
+
+ Any values not passed to **kws is set to the adaptor-specific
+ defaults.
+
+ Raise AlreadyAMemberError it the member is already subscribed to the
+ list. Raises ValueError if **kws contains an invalid option.
+ """
+ raise NotImplemented
+
+ def removeMember(self, memberkey):
+ """Unsubscribes the member from the mailing list.
+
+ Raise NotAMemberError if member is not subscribed to the list.
+ """
+ raise NotImplemented
+
+ def changeMemberAddress(self, memberkey, newaddress, nodelete=0):
+ """Change the address for the member KEY.
+
+ memberkey will be a KEY, not an LCE. newaddress should be the
+ new case-preserved address for the member; the LCE will be calculated
+ from newaddress.
+
+ If memberkey does not refer to a valid member, raise NotAMemberError.
+ No verification on the new address is done here (such assertions
+ should be performed by the caller).
+
+ If nodelete flag is true, then the old membership is not removed.
+ """
+ raise NotImplemented
+
+ def setMemberPassword(self, member, password):
+ """Set the password for member LCE/KEY.
+
+ If member does not refer to a valid member, raise NotAMemberError.
+ Also raise BadPasswordError if the password is illegal (e.g. too
+ short or easily guessed via a dictionary attack).
+
+ """
+ raise NotImplemented
+
+ def setMemberLanguage(self, member, language):
+ """Set the language for the member LCE/KEY.
+
+ If member does not refer to a valid member, raise NotAMemberError.
+ Also raise BadLanguageError if the language is invalid (e.g. the list
+ is not configured to support the given language).
+ """
+ raise NotImplemented
+
+ def setMemberOption(self, member, flag, value):
+ """Set the option for the given member to value.
+
+ member is an LCE/KEY, flag is one of the option flags defined in
+ Default.py, and value is a boolean.
+
+ If member does not refer to a valid member, raise NotAMemberError.
+ Also raise BadOptionError if the flag does not refer to a valid
+ option.
+ """
+ raise NotImplemented
+
+ def setMemberName(self, member, realname):
+ """Set the member's full name.
+
+ member is an LCE/KEY and realname is an arbitrary string. It should
+ be a Unicode string if there are non-ASCII characters in the name.
+ NotAMemberError is raised if member does not refer to a valid member.
+ """
+ raise NotImplemented
+
+ def setMemberTopics(self, member, topics):
+ """Add list of topics to member's interest.
+
+ member is an LCE/KEY and realname is an arbitrary string.
+ NotAMemberError is raised if member does not refer to a valid member.
+ topics must be a sequence of strings.
+ """
+ raise NotImplemented
+
+ def setDeliveryStatus(self, member, status):
+ """Set the delivery status of the member's address.
+
+ Status must be one of the module constants:
+
+ ENABLED - The deliveries to the user are not disabled
+ UNKNOWN - Deliveries are disabled for unknown reasons. The
+ primary reason for this to happen is that we've copied
+ their delivery status from a legacy version which didn't
+ keep track of disable reasons
+ BYUSER - The user explicitly disable deliveries
+ BYADMIN - The list administrator explicitly disabled deliveries
+ BYBOUNCE - The system disabled deliveries due to bouncing
+
+ This method also records the time (in seconds since epoch) at which
+ the last status change was made. If the delivery status is changed to
+ ENABLED, then the change time information will be deleted. This value
+ is retrievable via getDeliveryStatusChangeTime().
+ """
+ raise NotImplemented
+
+ def setBounceInfo(self, member, info):
+ """Set the member's bounce information.
+
+ When info is None, any bounce info for the member is cleared.
+
+ Bounce info is opaque to the MemberAdaptor. It is set by this method
+ and returned by getBounceInfo() without modification.
+ """
+ raise NotImplemented