#! @PYTHON@
#
# Copyright (C) 1998-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# argv[1] should be the name of the list.
# argv[2] should be the list of non-digested users.
# argv[3] should be the list of digested users.
# Make sure that the list of email addresses doesn't contain any comments,
# like majordomo may throw in. For now, you just have to remove them manually.
"""Add members to a list from the command line.
Usage:
add_members [options] listname
Options:
--regular-members-file=file
-r file
A file containing addresses of the members to be added, one
address per line. This list of people become non-digest
members. If file is `-', read addresses from stdin. Note that
-n/--non-digest-members-file are deprecated synonyms for this option.
--digest-members-file=file
-d file
Similar to above, but these people become digest members.
--welcome-msg=<y|n>
-w <y|n>
Set whether or not to send the list members a welcome message,
overriding whatever the list's `send_welcome_msg' setting is.
--admin-notify=<y|n>
-a <y|n>
Set whether or not to send the list administrators a notification on
the success/failure of these subscriptions, overriding whatever the
list's `admin_notify_mchanges' setting is.
--nomail
-n
Set the newly added members mail delivery to disabled by admin.
--help
-h
Print this help message and exit.
listname
The name of the Mailman list you are adding members to. It must
already exist.
You must supply at least one of -r and -d options. At most one of the
files can be `-'.
"""
import sys
import os
import getopt
from cStringIO import StringIO
import paths
# Import this /after/ paths so that the sys.path is properly hacked
from email.Utils import parseaddr
from Mailman import i18n
from Mailman import Utils
from Mailman import mm_cfg
from Mailman import Errors
from Mailman import Message
from Mailman import MailList
from Mailman import MemberAdaptor
_ = i18n._
def usage(status, msg=''):
if status:
fd = sys.stderr
else:
fd = sys.stdout
print >> fd, _(__doc__)
if msg:
print >> fd, msg
sys.exit(status)
def readfile(filename):
if filename == '-':
fp = sys.stdin
closep = 0
else:
fp = open(filename)
closep = 1
# strip all the lines of whitespace and discard blank lines
lines = filter(None, [line.strip() for line in fp.readlines()])
if closep:
fp.close()
return lines
class Tee:
def __init__(self, outfp):
self.__outfp = outfp
def write(self, msg):
sys.stdout.write(msg)
self.__outfp.write(msg)
class UserDesc: pass
def addall(mlist, members, digest, ack, outfp, nomail):
tee = Tee(outfp)
for member in members:
userdesc = UserDesc()
userdesc.fullname, userdesc.address = parseaddr(member)
userdesc.digest = digest
try:
mlist.ApprovedAddMember(userdesc,
ack=ack,
admin_notif=False,
whence='bin/add_members',
)
except Errors.MMAlreadyAMember:
print >> tee, _('Already a member: %(member)s')
except Errors.MembershipIsBanned, pattern:
print >> tee, ('%s:' %
member), _('Banned address (matched %(pattern)s)')
except Errors.MMBadEmailError:
if userdesc.address == '':
print >> tee, _('Bad/Invalid email address: blank line')
else:
print >> tee, _('Bad/Invalid email address: %(member)s')
except Errors.MMHostileAddress:
print >> tee, _('Hostile address (illegal characters): %(member)s')
else:
print >> tee, _('Subscribed: %(member)s')
if nomail:
mlist.setDeliveryStatus(member, MemberAdaptor.BYADMIN)
def main():
try:
opts, args = getopt.getopt(sys.argv[1:],
'a:r:d:w:nh',
['admin-notify=',
'regular-members-file=',
'digest-members-file=',
'welcome-msg=',
'nomail',
'help'])
except getopt.error, msg:
usage(1, msg)
if len(args) <> 1:
usage(1)
listname = args[0].lower().strip()
nfile = None
dfile = None
send_welcome_msg = None
admin_notif = None
nomail = False
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-d', '--digest-members-file'):
dfile = arg
elif opt in ('-r', '--regular-members-file'):
nfile = arg
elif opt in ('-w', '--welcome-msg'):
if arg.lower()[0] == 'y':
send_welcome_msg = 1
elif arg.lower()[0] == 'n':
send_welcome_msg = 0
else:
usage(1, _('Bad argument to -w/--welcome-msg: %(arg)s'))
elif opt in ('-a', '--admin-notify'):
if arg.lower()[0] == 'y':
admin_notif = 1
elif arg.lower()[0] == 'n':
admin_notif = 0
else:
usage(1, _('Bad argument to -a/--admin-notify: %(arg)s'))
elif opt in ('-n', '--nomail'):
nomail = True
if dfile is None and nfile is None:
usage(1)
if dfile == "-" and nfile == "-":
usage(1, _('Cannot read both digest and normal members '
'from standard input.'))
try:
mlist = MailList.MailList(listname)
except Errors.MMUnknownListError:
usage(1, _('No such list: %(listname)s'))
# Set up defaults
if send_welcome_msg is None:
send_welcome_msg = mlist.send_welcome_msg
if admin_notif is None:
admin_notif = mlist.admin_notify_mchanges
otrans = i18n.get_translation()
# Read the regular and digest member files
try:
dmembers = []
if dfile:
dmembers = readfile(dfile)
nmembers = []
if nfile:
nmembers = readfile(nfile)
if not dmembers and not nmembers:
usage(0, _('Nothing to do.'))
s = StringIO()
i18n.set_language(mlist.preferred_language)
if nmembers:
addall(mlist, nmembers, 0, send_welcome_msg, s, nomail)
if dmembers:
addall(mlist, dmembers, 1, send_welcome_msg, s, nomail)
if admin_notif:
realname = mlist.real_name
subject = _('%(realname)s subscription notification')
msg = Message.UserNotification(
mlist.owner,
Utils.get_site_email(mlist.host_name),
subject,
s.getvalue(),
mlist.preferred_language)
msg.send(mlist)
mlist.Save()
finally:
mlist.Unlock()
i18n.set_translation(otrans)
if __name__ == '__main__':
main()