summaryrefslogtreecommitdiff
path: root/Mailman/MailList.py
diff options
context:
space:
mode:
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: