[Mailman-Developers] Admin-controlled rejection text...

Brad Knowles brad at stop.mail-abuse.org
Thu Jan 20 15:56:18 CET 2005


Folks,

	I've been doing a bit of hacking on Mailman.  The issue is that 
if you set member_moderation_action to be Reject instead of Hold, you 
can supply a nice little bit of text in member_moderation_notice, or 
you can let the system supply a standard text for you.

	My problem is that I want to leave member_moderation_action set 
to Hold, and set the generic_nonmember_action to be Reject, but still 
supply my own text.


	Let's look at how these two are handled differently.  First, 
member_moderation_action, has the following lines in 
Mailman/Handlers/Moderate.py, starting at line 59:


         if mlist.getMemberOption(sender, mm_cfg.Moderate):
             # Note that for member_moderation_action, 0==Hold, 1=Reject,
             # 2==Discard
             if mlist.member_moderation_action == 0:
                 # Hold.  BAW: WIBNI we could add the member_moderation_notice
                 # to the notice sent back to the sender?
                 msgdata['sender'] = sender
                 Hold.hold_for_approval(mlist, msg, msgdata,
                                        ModeratedMemberPost)
             elif mlist.member_moderation_action == 1:
                 # Reject
                 text = mlist.member_moderation_notice
                 if text:
                     text = Utils.wrap(text)
                 else:
                     # Use the default RejectMessage notice string
                     text = None
                 raise Errors.RejectMessage, text
             elif mlist.member_moderation_action == 2:
                 # Discard.  BAW: Again, it would be nice if we could send a
                 # discard notice to the sender
                 raise Errors.DiscardMessage
             else:
                 assert 0, 'bad member_moderation_action'
         # 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.


	Okay, I don't know Python, but I can kinda follow that.  Notice 
how the value of "text" is modified depending on whether or not 
member_moderation_notice is empty or not, and how this code directly 
raises the error instead of calling a subroutine.

	Now, let's consider what happens with generic_nonmember_action. 
We have the following lines in Mailman/Handlers/Moderate.py, starting 
at line 101:


     # 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.NonMemberPost)
     elif mlist.generic_nonmember_action == 2:
         do_reject(mlist)
     elif mlist.generic_nonmember_action == 3:
         do_discard(mlist, msg)


	Note how this does very little other than decide which subroutine 
to call, then call it.  No check is made for 
member_moderation_notice, nor is any specific rejection text 
supplied.  Let's take a look at do_reject(), starting at line 136:

def do_reject(mlist):
     listowner = mlist.GetOwnerEmail()
     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."""))


	This creates a hard-coded message with a %()s substitution, and 
sends that out.

	Now, am I missing something here, or should we not be calling 
do_reject() in each of these cases and having just the one canonical 
"raise Errors.RejectMessage", and passing this routine a string to be 
used as the rejection notice, or allowing it to decide to fill one in 
for us in the case that we provide "None"?


	Okay, so I modified do_reject to at least check the value of 
member_moderation_notice and to use that text, if it is non-empty. 
Here's what I've now got:


def do_reject(mlist):
     listowner = mlist.GetOwnerEmail()
     text = mlist.member_moderation_notice
     if text:
         text = Utils.wrap(text)
     else:
         # Use the default RejectMessage notice string
         text = 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."""))
     # Reject this sucker
     raise Errors.RejectMessage, text


	This works.  Well, mostly.  I'd be submitting this as a patch and 
working on getting this put into production, if it worked completely. 
I know that what we should really have is a separate 
generic_nonmember_notice and have the routine check that instead, but 
I would be willing to take this as a small but significant 
improvement in the meanwhile.

	Problem is, while we can provide a %()s substitution ourselves in 
the text we feed to Utils.wrap, I can't do the same thing from 
member_moderation_notice.  Instead, it simply outputs the literal 
string, and gives me "&lt;" and "&gt;" as opposed to the real 
less-than/greater-than symbols that I want to use around the URLs.

	I'm stumped.  I don't even know what to search for in the 
archives of the mailman-users and mailman-developers lists.

	Can anyone here lend me a clue?

-- 
Brad Knowles, <brad at stop.mail-abuse.org>

"Those who would give up essential Liberty, to purchase a little
temporary Safety, deserve neither Liberty nor Safety."

     -- Benjamin Franklin (1706-1790), reply of the Pennsylvania
     Assembly to the Governor, November 11, 1755

   SAGE member since 1995.  See <http://www.sage.org/> for more info.


More information about the Mailman-Developers mailing list