"""Posting moderation filter.
"""
import re
from email.MIMEMessage import MIMEMessage
from email.MIMEText import MIMEText
from Mailman import mm_cfg
from Mailman import Utils
from Mailman import Message
from Mailman import Errors
from Mailman.i18n import _
from Mailman.Handlers import Hold
from Mailman.Logging.Syslog import syslog
from Mailman.MailList import MailList
class ModeratedMemberPost(Hold.ModeratedPost):
pass
def process(mlist, msg, msgdata):
if msgdata.get('approved') or msgdata.get('fromusenet'):
return
for sender in msg.get_senders():
if mlist.isMember(sender):
break
else:
sender = None
if sender:
if mlist.getMemberOption(sender, mm_cfg.Moderate):
if mlist.member_moderation_action == 0:
msgdata['sender'] = sender
Hold.hold_for_approval(mlist, msg, msgdata,
ModeratedMemberPost)
elif mlist.member_moderation_action == 1:
text = mlist.member_moderation_notice
if text:
text = Utils.wrap(text)
else:
text = None
raise Errors.RejectMessage, text
elif mlist.member_moderation_action == 2:
raise Errors.DiscardMessage
else:
assert 0, 'bad member_moderation_action'
return
else:
sender = msg.get_sender()
listname = mlist.internal_name()
if matches_p(sender, mlist.accept_these_nonmembers, listname):
return
if matches_p(sender, mlist.hold_these_nonmembers, listname):
Hold.hold_for_approval(mlist, msg, msgdata, Hold.NonMemberPost)
if matches_p(sender, mlist.reject_these_nonmembers, listname):
do_reject(mlist)
if matches_p(sender, mlist.discard_these_nonmembers, listname):
do_discard(mlist, msg)
assert 0 <= mlist.generic_nonmember_action <= 4
if mlist.generic_nonmember_action == 0:
return
elif mlist.generic_nonmember_action == 1:
Hold.hold_for_approval(mlist, msg, msgdata, Hold.NonMemberPost)
elif mlist.generic_nonmember_action == 2:
do_reject(mlist)
elif mlist.generic_nonmember_action == 3:
do_discard(mlist, msg)
def matches_p(sender, nonmembers, listname):
plainaddrs = [addr for addr in nonmembers if not (addr.startswith('^')
or addr.startswith('@'))]
addrdict = Utils.List2Dict(plainaddrs, foldcase=1)
if addrdict.has_key(sender):
return 1
for are in nonmembers:
if are.startswith('^'):
try:
cre = re.compile(are, re.IGNORECASE)
except re.error:
continue
if cre.search(sender):
return 1
elif are.startswith('@'):
try:
if are[1:] == listname:
syslog('error',
'*_these_nonmembers in %s references own list',
listname)
else:
mother = MailList(are[1:], lock=0)
if mother.isMember(sender):
return 1
except Errors.MMUnknownListError:
syslog('error',
'*_these_nonmembers in %s references non-existent list %s',
listname, are[1:])
return 0
def do_reject(mlist):
listowner = mlist.GetOwnerEmail()
if mlist.nonmember_rejection_notice:
raise Errors.RejectMessage, \
Utils.wrap(_(mlist.nonmember_rejection_notice))
else:
raise Errors.RejectMessage, Utils.wrap(_("""\
You are not allowed to post to this mailing list, and your message has been
automatically rejected. If you think that your messages are being rejected in
error, contact the mailing list owner at %(listowner)s."""))
def do_discard(mlist, msg):
sender = msg.get_sender()
if mlist.forward_auto_discards:
lang = mlist.preferred_language
varhelp = '%s/?VARHELP=privacy/sender/discard_these_nonmembers' % \
mlist.GetScriptURL('admin', absolute=1)
nmsg = Message.UserNotification(mlist.GetOwnerEmail(),
mlist.GetBouncesEmail(),
_('Auto-discard notification'),
lang=lang)
nmsg.set_type('multipart/mixed')
text = MIMEText(Utils.wrap(_(
'The attached message has been automatically discarded.')),
_charset=Utils.GetCharSet(lang))
nmsg.attach(text)
nmsg.attach(MIMEMessage(msg))
nmsg.send(mlist)
raise Errors.DiscardMessage