#! @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= -w Set whether or not to send the list members a welcome message, overriding whatever the list's `send_welcome_msg' setting is. --admin-notify= -a 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()