aboutsummaryrefslogtreecommitdiffstats
path: root/bin/add_members
diff options
context:
space:
mode:
Diffstat (limited to 'bin/add_members')
-rwxr-xr-xbin/add_members297
1 files changed, 297 insertions, 0 deletions
diff --git a/bin/add_members b/bin/add_members
new file mode 100755
index 00000000..ad4f43b8
--- /dev/null
+++ b/bin/add_members
@@ -0,0 +1,297 @@
+#! @PYTHON@
+#
+# Copyright (C) 1998,1999,2000,2001,2002 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.
+#
+# 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.
+
+ --changes-msg=<y|n>
+ -c <y|n>
+ Set whether or not to send the list members the `there's going to be
+ big changes to your list' message. defaults to no.
+
+ --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.
+
+ --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 MailList
+from Mailman import Utils
+from Mailman import Message
+from Mailman import Errors
+from Mailman import mm_cfg
+from Mailman import i18n
+
+_ = 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
+
+
+
+def SendExplanation(mlist, users):
+ listname = mlist.real_name
+ listhost = mlist.host_name
+ d = {'listname' : listname,
+ 'listhost' : listhost,
+ 'listaddr' : mlist.GetListEmail(),
+ 'listinfo_url': mlist.GetScriptURL('listinfo', absolute=1),
+ 'requestaddr' : mlist.GetRequestEmail(),
+ 'adminaddr' : mlist.GetOwnerEmail(),
+ 'version' : mm_cfg.VERSION,
+ }
+ otrans = i18n.get_translation()
+ i18n.set_language(mlist.preferred_language)
+ try:
+ text = Utils.maketext('convert.txt', d)
+ subject = _('Big change in %(listname)s@%(listhost)s mailing list')
+ msg = Message.UserNotification(users, mlist.GetBouncesEmail(),
+ subject, text,
+ mlist.preferred_language)
+ finally:
+ i18n.set_translation(otrans)
+ msg.send(mlist)
+
+
+
+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):
+ tee = Tee(outfp)
+ for member in members:
+ userdesc = UserDesc()
+ userdesc.fullname, userdesc.address = parseaddr(member)
+ userdesc.digest = digest
+
+ try:
+ mlist.ApprovedAddMember(userdesc, ack, 0)
+ except Errors.MMAlreadyAMember:
+ print >> tee, _('Already a member: %(member)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')
+
+
+
+def main():
+ try:
+ opts, args = getopt.getopt(sys.argv[1:],
+ 'a:n:r:d:c:w:h',
+ ['admin-notify=',
+ 'regular-members-file=',
+ 'non-digest-members-file=',
+ 'digest-members-file=',
+ 'changes-msg=',
+ 'welcome-msg=',
+ 'help'])
+ except getopt.error, msg:
+ usage(1, msg)
+
+ if len(args) <> 1:
+ usage(1)
+
+ listname = args[0].lower().strip()
+ nfile = None
+ dfile = None
+ send_changes_msg = 0
+ send_welcome_msg = None
+ admin_notif = None
+ for opt, arg in opts:
+ if opt in ('-h', '--help'):
+ usage(0)
+ elif opt in ('-d', '--digest-members-file'):
+ dfile = arg
+ # Deprecate -/--non-digest-members-file or consistency with
+ # list_members
+ elif opt in ('-r', '--regular-members-file'):
+ nfile = arg
+ elif opt in ('-n', '--non-digest-members-file'):
+ nfile = arg
+ # I don't think we need to use the warnings module here.
+ print >> sys.stderr, 'option', opt, \
+ 'is deprecated, use -r/--regular-members-file'
+ elif opt in ('-c', '--changes-msg'):
+ if arg.lower()[0] == 'y':
+ send_changes_msg = 1
+ elif arg.lower()[0] == 'n':
+ send_changes_msg = 0
+ else:
+ usage(1, _('Bad argument to -c/--changes-msg: %(arg)s'))
+ 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'))
+
+ 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)
+
+ if dmembers:
+ addall(mlist, dmembers, 1, send_welcome_msg, s)
+
+ if admin_notif:
+ realname = mlist.real_name
+ subject = _('%(realname)s subscription notification')
+ msg = Message.UserNotification(
+ mlist.owner, Utils.get_site_email(), subject, s.getvalue(),
+ mlist.preferred_language)
+ msg.send(mlist)
+
+ if send_changes_msg:
+ SendExplanation(mlist, nmembers + dmembers)
+
+ mlist.Save()
+ finally:
+ mlist.Unlock()
+ i18n.set_translation(otrans)
+
+
+if __name__ == '__main__':
+ main()