summaryrefslogtreecommitdiff
path: root/Mailman/MailList.py
diff options
context:
space:
mode:
authorbwarsaw2001-10-15 20:54:20 +0000
committerbwarsaw2001-10-15 20:54:20 +0000
commitaec38fef609e79c2b930b06a178523c1ab1dc04c (patch)
treefc2060321da0883256ee75fdc7bd6f8eaa2b5026 /Mailman/MailList.py
parent33e83ee21ddc441fc27ffc328291a023e9e8557d (diff)
downloadmailman-aec38fef609e79c2b930b06a178523c1ab1dc04c.tar.gz
mailman-aec38fef609e79c2b930b06a178523c1ab1dc04c.tar.zst
mailman-aec38fef609e79c2b930b06a178523c1ab1dc04c.zip
InitVars(): Remove the initializations for the obsolete list
attributes posters, forbidden_posters, moderated, and member_posting_only. Add initializations for the new sender-centric moderation attributes default_member_moderation, accept_these_nonmembers, hold_these_nonmembers, reject_these_nonmembers, discard_these_nonmembers, forward_auto_discards, generic_nonmember_action. GetConfigInfo(): Rework this framework so that it doesn't return a dictionary with keys being the category. Instead, pass the category and subcategory in as arguments and let the dispatched-to gui methods decide whether and what to return in response to these arguments. This allows the framework to be more robust, and to easily handle extensions via subcategories (as was done to the Privacy category). ApprovedAddMember(): Set the newly subscribed member's Moderate flag to self.default_member_moderation. ProcessConfirmation(): Argument userdesc_overrides -> context. In the SUBSCRIPTION clause, only add context to userdesc if context is an instance of UserDesc. Also, add a HELD_MESSAGE clause which handles admin approval/discard of held messages via email response. This code is a bit more elaborate than I'd like it to be, so perhaps it should be factored out. ;/
Diffstat (limited to 'Mailman/MailList.py')
-rw-r--r--Mailman/MailList.py88
1 files changed, 71 insertions, 17 deletions
diff --git a/Mailman/MailList.py b/Mailman/MailList.py
index c2e34082c..34afec303 100644
--- a/Mailman/MailList.py
+++ b/Mailman/MailList.py
@@ -34,6 +34,7 @@ from UserDict import UserDict
from urlparse import urlparse
from types import *
+import email.Iterators
from email.Utils import getaddresses, dump_address_pair, parseaddr
from Mailman import mm_cfg
@@ -262,12 +263,9 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin,
self.moderator = []
self.reply_goes_to_list = mm_cfg.DEFAULT_REPLY_GOES_TO_LIST
self.reply_to_address = ''
- self.posters = []
- self.forbidden_posters = []
self.admin_immed_notify = mm_cfg.DEFAULT_ADMIN_IMMED_NOTIFY
self.admin_notify_mchanges = \
mm_cfg.DEFAULT_ADMIN_NOTIFY_MCHANGES
- self.moderated = mm_cfg.DEFAULT_MODERATED
self.require_explicit_destination = \
mm_cfg.DEFAULT_REQUIRE_EXPLICIT_DESTINATION
self.acceptable_aliases = mm_cfg.DEFAULT_ACCEPTABLE_ALIASES
@@ -288,7 +286,6 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin,
self.subscribe_policy = mm_cfg.DEFAULT_SUBSCRIBE_POLICY
self.private_roster = mm_cfg.DEFAULT_PRIVATE_ROSTER
self.obscure_addresses = mm_cfg.DEFAULT_OBSCURE_ADDRESSES
- self.member_posting_only = mm_cfg.DEFAULT_MEMBER_POSTING_ONLY
self.host_name = mm_cfg.DEFAULT_HOST_NAME
self.admin_member_chunksize = mm_cfg.DEFAULT_ADMIN_MEMBER_CHUNKSIZE
self.administrivia = mm_cfg.DEFAULT_ADMINISTRIVIA
@@ -297,7 +294,15 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin,
# Analogs to these are initted in Digester.InitVars
self.nondigestable = mm_cfg.DEFAULT_NONDIGESTABLE
self.personalize = 0
-
+ # New sender-centric moderation (privacy) options
+ self.default_member_moderation = \
+ mm_cfg.DEFAULT_DEFAULT_MEMBER_MODERATION
+ self.accept_these_nonmembers = []
+ self.hold_these_nonmembers = []
+ self.reject_these_nonmembers = []
+ self.discard_these_nonmembers = []
+ self.forward_auto_discards = mm_cfg.DEFAULT_FORWARD_AUTO_DISCARDS
+ self.generic_nonmember_action = mm_cfg.DEFAULT_GENERIC_NONMEMBER_ACTION
# BAW: This should really be set in SecurityManager.InitVars()
self.password = crypted_password
@@ -350,15 +355,12 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin,
return subcat
return None
- def GetConfigInfo(self):
- info = {}
+ def GetConfigInfo(self, category, subcat=None):
for gui in self._gui:
- if hasattr(gui, 'GetConfigCategory') and \
- hasattr(gui, 'GetConfigInfo'):
- key = gui.GetConfigCategory()[0]
- value = gui.GetConfigInfo(self)
- info[key] = value
- return info
+ if hasattr(gui, 'GetConfigInfo'):
+ value = gui.GetConfigInfo(self, category, subcat)
+ if value:
+ return value
#
@@ -709,7 +711,8 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin,
password=password, language=lang)
self.setMemberOption(email, mm_cfg.DisableMime,
1 - self.mime_is_default_digest)
-
+ self.setMemberOption(email, mm_cfg.Moderate,
+ self.default_member_moderation)
# Now send and log results
if digest:
kind = ' (digest)'
@@ -856,7 +859,7 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin,
#
# Confirmation processing
#
- def ProcessConfirmation(self, cookie, userdesc_overrides=None):
+ def ProcessConfirmation(self, cookie, context=None):
data = Pending.confirm(cookie)
if data is None:
raise Errors.MMBadConfirmation, 'data is None'
@@ -876,8 +879,12 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin,
raise Errors.MMNeedApproval, _(
'subscriptions to %(name)s require administrator approval')
userdesc = UserDesc(addr, fullname, password, digest, lang)
- if userdesc_overrides is not None:
- userdesc += userdesc_overrides
+ # If confirmation comes from the web, context should be a UserDesc
+ # instance which contains overrides of the original subscription
+ # information. If it comes from email, then context is a Message
+ # and isn't relevant.
+ if isinstance(context, UserDesc):
+ userdesc += context
self.ApprovedAddMember(userdesc)
return op, addr, password, digest, lang
elif op == Pending.UNSUBSCRIPTION:
@@ -889,6 +896,53 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin,
oldaddr, newaddr, globally = data
self.ApprovedChangeMemberAddress(oldaddr, newaddr, globally)
return op, oldaddr, newaddr
+ elif op == Pending.HELD_MESSAGE:
+ id = data[0]
+ approved = None
+ # Confirmation should be coming from email, where context should
+ # be the confirming message. If the message does not have an
+ # Approved: header, this is a discard, otherwise it's an approval
+ # (if the passwords match).
+ if isinstance(context, Message.Message):
+ # See if it's got an Approved: header, either in the headers,
+ # or in the first text/plain section of the response. For
+ # robustness, we'll accept Approve: as well.
+ approved = context.get('Approved', context.get('Approve'))
+ if not approved:
+ try:
+ subpart = email.Iterators.typed_subpart_iterator(
+ context, 'text', 'plain')[0]
+ except IndexError:
+ subpart = None
+ if subpart:
+ s = StringIO(subpart.get_payload())
+ while 1:
+ line = s.readline()
+ if not line:
+ break
+ if not line.strip():
+ continue
+ i = line.find(':')
+ if i > 0:
+ if (line[:i].lower() == 'approve' or
+ line[:i].lower() == 'approved'):
+ # then
+ approved = line[i+1:].strip()
+ break
+ # Okay, does the approved header match the list password?
+ if approved and self.Authenticate([mm_cfg.AuthListAdmin,
+ mm_cfg.AuthListModerator],
+ approved) <> mm_cfg.UnAuthorized:
+ action = mm_cfg.APPROVE
+ else:
+ action = mm_cfg.DISCARD
+ try:
+ self.HandleRequest(id, action)
+ except KeyError:
+ # Most likely because the message has already been disposed of
+ # via the admindb page.
+ syslog('error', 'Could not process HELD_MESSAGE: %s', id)
+ return (op,)
def ConfirmUnsubscription(self, addr, lang=None, remote=None):
if lang is None: