[Mailman-Users] Patch: list_members/sync_members and nomail/hide options
Brent J. Nordquist
brent-nordquist at bethel.edu
Tue Sep 4 00:30:54 CEST 2001
Inspired by nomail.py by Dan Mick <dmick at utopia.West.Sun.COM>, I've made
some patches to 2.0.6 (attached) that allow list_members and sync_members
to deal with the "nomail" and "hide" options (using a new -N flag). This
is to allow me to add multiple addresses for each user, with all but one
set to "nomail+hide", to solve the only-members-can-post problem.
I want to emphasise that this is pretty much a hack. I've been coding in
Python for (/me checks watch) about 2 1/2 hours now <grin> but this seems
to do what I needed, so I'm offering it in case others find it helpful.
--
Brent J. Nordquist <brent-nordquist at bethel.edu> N0BJN
Yahoo!: Brent_Nordquist / AIM: BrentJNordquist / ICQ: 76158942
-------------- next part --------------
--- list_members.orig Mon Sep 3 17:23:59 2001
+++ list_members Mon Sep 3 15:53:44 2001
@@ -18,7 +18,7 @@
"""List all the members of a mailing list.
-Usage: %(program)s [-o file] [-r] [-d] [-p] [-h] listname
+Usage: %(program)s [-o file] [-r] [-d] [-p] [-N] [-h] listname
Where:
@@ -39,6 +39,11 @@
Output member addresses case preserved the way they were added to the
list. Otherwise, addresses are printed in all lowercase.
+ --nomail
+ -N
+ After each email address, also print the status of the nomail and
+ hide options (in that order).
+
--help
-h
Print this help message and exit.
@@ -58,6 +63,7 @@
import paths
from Mailman import MailList
from Mailman import Errors
+from Mailman import mm_cfg
program = sys.argv[0]
@@ -73,8 +79,8 @@
try:
opts, args = getopt.getopt(
sys.argv[1:],
- 'dpro:h',
- ['digest', 'regular', 'preserve', 'output=', 'help'])
+ 'dpro:Nh',
+ ['digest', 'regular', 'preserve', 'output=', 'nomail', 'help'])
except getopt.error, msg:
usage(1, msg)
@@ -82,6 +88,7 @@
usage(1)
listname = string.lower(args[0])
+ nomail = None
outfile = None
regular = None
digest = None
@@ -90,6 +97,8 @@
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
+ elif opt in ('-N', '--nomail'):
+ nomail = 1
elif opt in ('-o', '--output'):
outfile = arg
elif opt in ('-r', '--regular'):
@@ -129,10 +138,46 @@
sys.stdout = fp
if regular:
for addr in rmembers:
- print addr
+ print addr,
+ if nomail:
+ try:
+ if mlist.user_options[addr] & mm_cfg.DisableDelivery:
+ print "yes",
+ else:
+ print "no",
+ except:
+ print "no",
+ pass
+ try:
+ if mlist.user_options[addr] & mm_cfg.ConcealSubscription:
+ print "yes",
+ else:
+ print "no",
+ except:
+ print "no",
+ pass
+ print
if digest:
for addr in dmembers:
- print addr
+ print addr,
+ if nomail:
+ try:
+ if mlist.user_options[addr] & mm_cfg.DisableDelivery:
+ print "yes",
+ else:
+ print "no",
+ except:
+ print "no",
+ pass
+ try:
+ if mlist.user_options[addr] & mm_cfg.ConcealSubscription:
+ print "yes",
+ else:
+ print "no",
+ except:
+ print "no",
+ pass
+ print
finally:
sys.stdout = stdout
-------------- next part --------------
#! /usr/bin/env python
#
# Copyright (C) 1998,1999,2000 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.
"""List all the members of a mailing list.
Usage: %(program)s [-o file] [-r] [-d] [-p] [-N] [-h] listname
Where:
--output file
-o file
Write output to specified file instead of standard out.
--regular
-r
Print just the regular (non-digest) members.
--digest
-d
Print just the digest members.
--preserve
-p
Output member addresses case preserved the way they were added to the
list. Otherwise, addresses are printed in all lowercase.
--nomail
-N
After each email address, also print the status of the nomail and
hide options (in that order).
--help
-h
Print this help message and exit.
listname is the name of the mailing list to use.
Note that if neither -r or -d is supplied, both regular members are printed
first, followed by digest members, but no indication is given as to address
status.
"""
import sys
import string
import getopt
import paths
from Mailman import MailList
from Mailman import Errors
from Mailman import mm_cfg
program = sys.argv[0]
def usage(status, msg=''):
print __doc__ % globals()
if msg:
print msg
sys.exit(status)
def main():
try:
opts, args = getopt.getopt(
sys.argv[1:],
'dpro:Nh',
['digest', 'regular', 'preserve', 'output=', 'nomail', 'help'])
except getopt.error, msg:
usage(1, msg)
if len(args) <> 1:
usage(1)
listname = string.lower(args[0])
nomail = None
outfile = None
regular = None
digest = None
preserve = None
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-N', '--nomail'):
nomail = 1
elif opt in ('-o', '--output'):
outfile = arg
elif opt in ('-r', '--regular'):
regular = 1
elif opt in ('-d', '--digest'):
digest = 1
elif opt in ('-p', '--preserve'):
preserve = 1
if regular is None and digest is None:
regular = digest = 1
if outfile:
try:
fp = open(outfile, 'w')
except IOError:
print 'Could not open file for writing:', outfile
sys.exit(1)
else:
fp = sys.stdout
try:
mlist = MailList.MailList(listname, lock=0)
except Errors.MMListError, e:
print 'No such list "%s"\n%s' % (listname, e)
sys.exit(1)
if preserve:
rmembers = mlist.GetDeliveryMembers()
dmembers = mlist.GetDigestDeliveryMembers()
else:
rmembers = mlist.GetMembers()
dmembers = mlist.GetDigestMembers()
stdout = sys.stdout
try:
sys.stdout = fp
if regular:
for addr in rmembers:
print addr,
if nomail:
try:
if mlist.user_options[addr] & mm_cfg.DisableDelivery:
print "yes",
else:
print "no",
except:
print "no",
pass
try:
if mlist.user_options[addr] & mm_cfg.ConcealSubscription:
print "yes",
else:
print "no",
except:
print "no",
pass
print
if digest:
for addr in dmembers:
print addr,
if nomail:
try:
if mlist.user_options[addr] & mm_cfg.DisableDelivery:
print "yes",
else:
print "no",
except:
print "no",
pass
try:
if mlist.user_options[addr] & mm_cfg.ConcealSubscription:
print "yes",
else:
print "no",
except:
print "no",
pass
print
finally:
sys.stdout = stdout
if __name__ == '__main__':
main()
-------------- next part --------------
--- sync_members.orig Mon Sep 3 17:23:55 2001
+++ sync_members Mon Sep 3 17:15:59 2001
@@ -61,6 +61,13 @@
against. Email addresses must appear one per line. If filename is
`-' then stdin is used.
+ --nomail
+ -N
+ Expect two fields following each email address, each containing
+ `yes' or `no' to reflect the status of the nomail and hide options
+ (in that order), as produced by `list_members -N'. These fields
+ are used ONLY IF ADDING the address; otherwise they are ignored.
+
--help
-h
Print this message.
@@ -76,6 +83,7 @@
from Mailman import MailList
from Mailman import Errors
from Mailman import Utils
+from Mailman import mm_cfg
@@ -116,6 +124,9 @@
filename = None
listname = None
notifyadmin = None
+ nomail = None
+ nomailopt = {}
+ hideopt = {}
i = 1
while i < len(sys.argv):
@@ -152,6 +163,9 @@
elif startswith(opt, '-a=') or startswith(opt, '--notifyadmin='):
notifyadmin = yesno(opt)
i = i + 1
+ elif opt in ('-N', '--nomail'):
+ nomail = 1
+ i = i + 1
elif opt[0] == '-':
usage(1, 'Illegal option: ' + opt)
else:
@@ -186,7 +200,15 @@
del filemembers[i]
print 'Ignore : %30s' % addr
- # first filter out any invalid addresses
+ # if in --nomail mode, split those fields out into separate lists
+ if nomail:
+ for i in range(len(filemembers)-1, -1, -1):
+ fields = string.split(filemembers[i])
+ filemembers[i] = fields[0]
+ nomailopt[fields[0]] = fields[1]
+ hideopt[fields[0]] = fields[2]
+
+ # filter out any invalid addresses
filemembers = Utils.ParseAddrs(filemembers)
invalid = 0
for addr in filemembers:
@@ -239,6 +261,17 @@
mlist.ApprovedAddMember(addr, pw, digest,
welcome, notifyadmin)
print 'Added : %30s (%30s)' % (laddr, addr)
+ # if in --nomail mode, hack the account flags
+ # (clone_member doesn't inspire us to use SetUserOption())
+ if nomail:
+ if yesno(nomailopt[addr]):
+ if not dryrun:
+ mlist.user_options[addr] = mlist.user_options[addr] | mm_cfg.DisableDelivery;
+ print 'NoMail : %30s (%30s)' % (laddr, addr)
+ if yesno(hideopt[addr]):
+ if not dryrun:
+ mlist.user_options[addr] = mlist.user_options[addr] | mm_cfg.ConcealSubscription;
+ print 'Hide : %30s (%30s)' % (laddr, addr)
except Errors.MMAlreadyAMember:
pass
-------------- next part --------------
#! /usr/bin/env python
#
# Copyright (C) 1998,1999,2000 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.
"""Synchronize a mailing list's membership with a flat file.
This script is useful if you have a Mailman mailing list and a sendmail
:include: style list of addresses (also as is used in Majordomo). For every
address in the file that does not appear in the mailing list, the address is
added. For every address in the mailing list that does not appear in the
file, the address is removed. Other options control what happens when an
address is added or removed.
Usage: %(program)s [options] -f file listname
Where `options' are:
--no-change
-n
Don't actually make the changes. Instead, print out what would be
done to the list.
--welcome-msg[=<yes|no>]
-w[=<yes|no>]
Sets whether or not to send the newly added members a welcome
message, overriding whatever the list's `send_welcome_msg' setting
is. With -w=yes or -w, the welcome message is sent. With -w=no, no
message is sent.
--digest[=<yes|no>]
-d[=<yes|no>]
Selects whether to make newly added members receive messages in
digests. With -d=yes or -d, they become digest members. With -d=no
(or if no -d option given) they are added as regular members.
--notifyadmin[=<yes|no>]
--a[=<yes|no>]
Specifies whether the admin should be notified for each subscription
or unsubscription. If you're adding a lot of addresses, you
definitely want to turn this off! With -a=yes or -a, the admin is
notified. With -a=no, the admin is not notified. With no -a option,
the default for the list is used.
--file <filename | ->
-f <filename | ->
This option is required. It specifies the flat file to synchronize
against. Email addresses must appear one per line. If filename is
`-' then stdin is used.
--nomail
-N
Expect two fields following each email address, each containing
`yes' or `no' to reflect the status of the nomail and hide options
(in that order), as produced by `list_members -N'. These fields
are used ONLY IF ADDING the address; otherwise they are ignored.
--help
-h
Print this message.
listname
Required. This specifies the list to synchronize.
"""
import sys
import string
import paths
from Mailman import MailList
from Mailman import Errors
from Mailman import Utils
from Mailman import mm_cfg
program = sys.argv[0]
def usage(status, msg=''):
print __doc__ % globals()
if msg:
print msg
sys.exit(status)
def startswith(s, prefix):
return s[:len(prefix)] == prefix
def endswith(s, suffix):
return s[-len(suffix):] == suffix
def yesno(opt):
i = string.find(opt, '=')
yesno = string.lower(opt[i+1:])
if yesno in ('y', 'yes'):
return 1
elif yesno in ('n', 'no'):
return 0
else:
usage(1, 'Bad choice: ' + yesno)
# no return
def main():
dryrun = 0
digest = 0
welcome = None
filename = None
listname = None
notifyadmin = None
nomail = None
nomailopt = {}
hideopt = {}
i = 1
while i < len(sys.argv):
opt = sys.argv[i]
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-n', '--no-change'):
dryrun = 1
i = i + 1
print 'Dry run mode'
elif opt in ('-d', '--digest'):
digest = 1
i = i + 1
elif startswith(opt, '-d=') or startswith(opt, '--digest='):
digest = yesno(opt)
i = i + 1
elif opt in ('-w', '--welcome-msg'):
welcome = 1
i = i + 1
elif startswith(opt, '-w=') or startswith(opt, '--welcome-msg='):
welcome = yesno(opt)
i = i + 1
elif opt in ('-f', '--file'):
if filename is not None:
usage(1, 'Only one -f switch allowed')
try:
filename = sys.argv[i+1]
except IndexError:
usage(1, 'No argument to -f given')
i = i + 2
elif opt in ('-a', '--notifyadmin'):
notifyadmin = 1
i = i + 1
elif startswith(opt, '-a=') or startswith(opt, '--notifyadmin='):
notifyadmin = yesno(opt)
i = i + 1
elif opt in ('-N', '--nomail'):
nomail = 1
i = i + 1
elif opt[0] == '-':
usage(1, 'Illegal option: ' + opt)
else:
try:
listname = string.lower(sys.argv[i])
i = i + 1
except IndexError:
usage(1, 'No listname given')
break
if listname is None or filename is None:
usage(1, 'Must have a listname and a filename')
# read the list of addresses to sync to from the file
if filename == '-':
filemembers = sys.stdin.readlines()
else:
try:
fp = open(filename)
except IOError, (code, msg):
usage(1, 'Cannot read address file: %s: %s' % (filename, msg))
try:
filemembers = fp.readlines()
finally:
fp.close()
# strip out lines we don't care about, they are comments (# in first
# non-whitespace) or are blank
for i in range(len(filemembers)-1, -1, -1):
addr = string.strip(filemembers[i])
if addr == '' or addr[:1] == '#':
del filemembers[i]
print 'Ignore : %30s' % addr
# if in --nomail mode, split those fields out into separate lists
if nomail:
for i in range(len(filemembers)-1, -1, -1):
fields = string.split(filemembers[i])
filemembers[i] = fields[0]
nomailopt[fields[0]] = fields[1]
hideopt[fields[0]] = fields[2]
# filter out any invalid addresses
filemembers = Utils.ParseAddrs(filemembers)
invalid = 0
for addr in filemembers:
try:
Utils.ValidateEmail(addr)
except Errors.EmailAddressError:
print 'Invalid : %30s' % addr
invalid = 1
if invalid:
print 'You must fix the preceding invalid addresses first.'
sys.exit(1)
# get the locked list object
try:
mlist = MailList.MailList(listname)
except Errors.MMListError, e:
print 'No such list "%s"\n%s' % (listname, e)
sys.exit(1)
try:
# get the list of addresses currently subscribed
addrs = {}
needsadding = {}
for addr in (mlist.GetDeliveryMembers() +
mlist.GetDigestDeliveryMembers()):
addrs[string.lower(addr)] = addr
for addr in filemembers:
# any address found in the file that is also in the list can be
# ignored. if not found in the list, it must be added later
laddr = string.lower(addr)
if addrs.has_key(laddr):
del addrs[laddr]
else:
needsadding[laddr] = addr
if not needsadding and not addrs:
print 'Nothing to do.'
sys.exit(0)
# addrs contains now all the addresses that need removing
for laddr, addr in needsadding.items():
pw = Utils.MakeRandomPassword()
# should not already be subscribed, otherwise our test above is
# broken. Bogosity is if the address is listed in the file more
# than once. Second and subsequent ones trigger an
# MMAlreadyAMember error. Just catch it and go on.
try:
if not dryrun:
mlist.ApprovedAddMember(addr, pw, digest,
welcome, notifyadmin)
print 'Added : %30s (%30s)' % (laddr, addr)
# if in --nomail mode, hack the account flags
# (clone_member doesn't inspire us to use SetUserOption())
if nomail:
if yesno(nomailopt[addr]):
if not dryrun:
mlist.user_options[addr] = mlist.user_options[addr] | mm_cfg.DisableDelivery;
print 'NoMail : %30s (%30s)' % (laddr, addr)
if yesno(hideopt[addr]):
if not dryrun:
mlist.user_options[addr] = mlist.user_options[addr] | mm_cfg.ConcealSubscription;
print 'Hide : %30s (%30s)' % (laddr, addr)
except Errors.MMAlreadyAMember:
pass
for laddr, addr in addrs.items():
# should be a member, otherwise our test above is broken
if not dryrun:
mlist.DeleteMember(addr, admin_notif=notifyadmin)
print 'Removed: %30s (%30s)' % (laddr, addr)
mlist.Save()
finally:
mlist.Unlock()
if __name__ == '__main__':
main()
More information about the Mailman-Users
mailing list