summaryrefslogtreecommitdiff
path: root/Mailman/Handlers/Moderate.py
blob: d957213b0363e50049370b03bd32ad8309b3f2d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# Copyright (C) 2001 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.

"""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



class ModeratedMemberPost(Hold.ModeratedPost):
    reason = _('Post by a moderated member')



def process(mlist, msg, msgdata):
    if msgdata.get('approved'):
        return
    # First of all, is the poster a member or not?
    sender = msg.get_sender()
    if mlist.isMember(sender):
        # If the member's moderation flag is on, then hold for approval.
        if mlist.getMemberOption(sender, mm_cfg.Moderate):
            Hold.hold_for_approval(mlist, msg, msgdata, ModeratedMemberPost)
        # Should we do anything explict to mark this message as getting past
        # this point?  No, because further pipeline handlers will need to do
        # their own thing.
        return
    # From here on out, we're dealing with non-members.
    if matches_p(sender, mlist.accept_these_nonmembers):
        return
    if matches_p(sender, mlist.hold_these_nonmembers):
        Hold.hold_for_approval(mlist, msg, msgdata, Hold.ModeratedPost)
        # No return
    if matches_p(sender, mlist.reject_these_nonmembers):
        do_reject(mlist)
        # No return
    if matches_p(sender, mlist.discard_these_nonmembers):
        do_discard(mlist, msg)
        # No return
    # Okay, so the sender wasn't specified explicitly by any of the non-member
    # moderation configuration variables.  Handle by way of generic non-member
    # action.
    assert 0 <= mlist.generic_nonmember_action <= 4
    if mlist.generic_nonmember_action == 0:
        # Accept
        return
    elif mlist.generic_nonmember_action == 1:
        Hold.hold_for_approval(mlist, msg, msgdata, Hold.ModeratedPost)
    elif mlist.generic_nonmember_action == 2:
        do_reject(mlist)
    elif mlist.generic_nonmember_action == 3:
        do_discard(mlist, msg)



def matches_p(sender, nonmembers):
    # First strip out all the regular expressions
    plainaddrs = [addr for addr in nonmembers if not addr.startswith('^')]
    addrdict = Utils.List2Dict(plainaddrs, foldcase=1)
    if addrdict.has_key(sender):
        return 1
    # Now do the regular expression matches
    for are in nonmembers:
        if are.startswith('^'):
            try:
                cre = re.compile(are, re.IGNORECASE)
            except re.error:
                continue
            if cre.search(sender):
                return 1
    return 0



def do_reject(mlist):
    listowner = mlist.GetOwnerEmail()
    raise Errors.RejectMessage, Utils.wrap(_("""\
You are not allowed to post to this mailing list, and have been automatically
rejected.  If you think that your postings are being rejected in error,
contact the mailing list owner at %(listowner)s."""))



def do_discard(mlist, msg):
    sender = msg.get_sender()
    # Do we forward auto-discards to the list owners?
    if mlist.forward_auto_discards:
        varhelp = '%s/privacy/sender/?VARHELP=discard_these_nonmembers' % \
                  mlist.GetScriptURL('admin', absolute=1)
        nmsg = Message.UserNotification(mlist.GetOwnerEmail(),
                                        mlist.GetAdminEmail(),
                                        _('Auto-discard notification'))
        nmsg['Content-Type'] = 'multipart/mixed'
        nmsg['MIME-Version'] = '1.0'
        text = MIMEText(Utils.wrap(_("""\
The attached message has been automatically discarded because the sender's
address, %(sender)s, was on the discard_these_nonmembers list.  For the list
of auto-discard addresses, see

    %(varhelp)s
""")))
        nmsg.add_payload(text)
        nmsg.add_payload(MIMEMessage(msg))
        nmsg.send(mlist)
    # Discard this sucker
    raise Errors.DiscardMessage