[Mailman-Developers] Fwd: suggested improvement for Mailman's bounce processing
Ian Eiloart
iane at sussex.ac.uk
Tue Aug 15 20:37:01 CEST 2006
--On 14 August 2006 14:06:06 -0400 Barry Warsaw <barry at python.org> wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On Aug 14, 2006, at 9:49 AM, Ian Eiloart wrote:
>
>> One thing that would make integration easier, would be a script
>> bin/may_post (or something), which takes a list name (ideally
>> qualified
>> with domain) and sender address, and returns true if the sender
>> address is
>> allowed to post, and false otherwise.
>
> Why don't you code something up and submit it here? :)
>
> - -Barry
I started to write that I've no python coding experience. Well, about 3
lines because php can't do "utf-something or other". Then I thought, well
it's about time I got some.
I had hacked up a shell script using the existing Mailman scripts, but that
was far too inefficient. Instead I've hacked up the attached. It started
life as list_config, but hopefully I've not left much trace of that. The
second issue below ***MUST*** be resolved before using this script with an
MTA.
The attached script takes these arguments:
-o --outputfile FILE_PATH can be used to specify logging of denies. use '-'
to log to stdout
-v --verbose causes logging of all results, allows as well as denies.
-h --help prints help
-s --sender EMAIL_ADDRESS is required
The script applies these tests, printing 'allow' or 'deny' to std out on
the first match.
allow list owners
allow list moderators
allow members of accept_these_nonmembers
deny members of reject_these_nonmembers
if generic_nonmember_action is 'reject':
allow members to post
deny non-members
allow by default
These issues are outstanding:
----------------------------
On allow, I say "return 1" on deny I say "return 0". I'm not sure whether
that's correct. Actually, I think I want the script to succeed every time,
so it can't be.
I've not figured out how to do a pattern match so accept_these_nonmembers
and reject_these_nonmembers are only tested for exact string matches. This
*****needs to be fixed***** for accept_these_nonmembers, otherwise some
won't be permitted to post.
It'd be nice to log to syslog, but the MTA could take care of that.
It might be nice to say 'hold' or 'discard' where appropriate. It's often
sensible to reject rather than discard a message, for example.
The list's nonmember_rejection_notice isn't used here. It could be returned
instead of 'deny' for the MTA to construct a rejection string with.
I've hard-coded '2' as the 'reject' key to generic_nonmember_action, which
is sinful.
--
Ian Eiloart
IT Services, University of Sussex
-------------- next part --------------
#! /local/bin/python
#
# Copyright (C) 1998-2003 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.
"""Find out whether list will reject a message from sender.
Usage: check_sender.py [options] -s sender listname
Options:
--outputfile filename
-o filename
optionally log denys to list file.
--sender sender
-s sender
check whether the sender is allowed to post to the list.
--verbose
-v
log allows as well as denys.
--help
-h
Print this help message and exit.
The option -s is required.
"""
import sys
import re
import time
import getopt
from types import TupleType
import paths
from Mailman import mm_cfg
from Mailman import MailList
from Mailman import Utils
from Mailman import Errors
from Mailman.i18n import _
NL = '\n'
def usage(code, msg=''):
if code:
fd = sys.stderr
else:
fd = sys.stdout
print >> fd, _(__doc__)
if msg:
print >> fd, msg
sys.exit(code)
def do_check(listname, sender, outfile, verbose):
closep = 0
try:
if outfile == '-':
outfp = sys.stdout
else:
outfp = open(outfile, 'a')
closep = 1
# Open the specified list unlocked, since we're only reading it.
try:
mlist = MailList.MailList(listname, lock=0)
except Errors.MMListError:
usage(1, _('No such list: %(listname)s'))
# get all the list config info. all this stuff is accessible via
the
# web interface
when = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())
# always allow the owner to post
if sender in mlist.owner :
if verbose:
print >> outfp, _('''%(when)s %(listname)s owner %(sender)s
allowed''')
print >> sys.stdout, 'allow'
return 1
# always allow moderators to post
if sender in mlist.moderator :
if verbose:
print >> outfp, _('''%(when)s %(listname)s moderator
%(sender)s allowed''')
print >> sys.stdout, 'allow'
return 1
# always allow accept_these_nonmembers to post
if sender in mlist.accept_these_nonmembers :
if verbose:
print >> outfp, _('''%(when)s %(listname)s
accept_these_nonmembers %(sender)s allowed''')
print >> sys.stdout, 'allow'
return 1
# deny reject_these_nonmembers
if sender in mlist.reject_these_nonmembers :
print >> outfp, _('''%(when)s %(listname)s
reject_these_nonmembers %(sender)s allowed''')
print >> sys.stdout, 'deny'
return 0
# 2 is the key for 'reject', but there's probably a global we
should use
if mlist.generic_nonmember_action == 2:
# regular members
rmembers = mlist.getRegularMemberKeys()
# digest members
dmembers = mlist.getDigestMemberKeys()
allmembers = rmembers + dmembers
# should lowercase sender
if sender.lower() in allmembers:
if verbose:
print >> outfp, _('''%(when)s %(listname)s member
%(sender)s allowed''')
print >> sys.stdout, 'allow'
return 1
else:
print >> outfp, _('''%(when)s %(listname)s member
%(sender)s denied''')
print >> sys.stdout, 'deny'
return 0
print >> outfp, _('''%(when)s %(listname)s unknow %(sender)s
allowed by default''')
print >> sys.stdout, 'allow'
return 1
finally:
if closep:
outfp.close()
def main():
try:
opts, args = getopt.getopt(
sys.argv[1:], 's:o:vh',
['list=', 'sender=', 'verbose', 'help'])
except getopt.error, msg:
usage(1, msg)
# defaults
infile = None
outfile = None
list = None
sender = None
verbose = 0
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-l', '--list'):
list = arg
elif opt in ('-s', '--sender'):
sender = arg
elif opt in ('-o', '--outputfile'):
outfile = arg
elif opt in ('-v', '--verbose'):
verbose = 1
# sanity check
if sender is None:
usage(1, _('--sender is required'))
# get the list name
if len(args) <> 1:
usage(1, _('List name is required'))
listname = args[0].lower().strip()
do_check(listname, sender, outfile, verbose)
if __name__ == '__main__':
main()
More information about the Mailman-Developers
mailing list