diff options
Diffstat (limited to 'cron/mailpasswds')
-rwxr-xr-x | cron/mailpasswds | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/cron/mailpasswds b/cron/mailpasswds new file mode 100755 index 00000000..a009e92b --- /dev/null +++ b/cron/mailpasswds @@ -0,0 +1,216 @@ +#! @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. + +"""Send password reminders for all lists to all users. + +This program scans all mailing lists and collects users and their passwords, +grouped by the list's host_name if mm_cfg.VIRTUAL_HOST_OVERVIEW is true. Then +one email message is sent to each unique user (per-virtual host) containing +the list passwords and options url for the user. The password reminder comes +from the mm_cfg.MAILMAN_SITE_LIST, which must exist. + +Usage: %(PROGRAM)s [options] + +Options: + -l listname + --listname=listname + Send password reminders for the named list only. If omitted, + reminders are sent for all lists. Multiple -l/--listname options are + allowed. + + -h/--help + Print this message and exit. +""" + +# This puppy should probably do lots of logging. +import sys +import os +import errno +import getopt + +import paths +# mm_cfg must be imported before the other modules, due to the side-effect of +# it hacking sys.paths to include site-packages. Without this, running this +# script from cron with python -S will fail. +from Mailman import mm_cfg +from Mailman import MailList +from Mailman import Errors +from Mailman import Utils +from Mailman import Message +from Mailman import i18n +from Mailman.Logging.Syslog import syslog + +# Work around known problems with some RedHat cron daemons +import signal +signal.signal(signal.SIGCHLD, signal.SIG_DFL) + +NL = '\n' +PROGRAM = sys.argv[0] + +_ = i18n._ + + + +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 main(): + try: + opts, args = getopt.getopt(sys.argv[1:], 'l:h', + ['listname=', 'help']) + except getopt.error, msg: + usage(1, msg) + + if args: + usage(1) + + listnames = None + for opt, arg in opts: + if opt in ('-h', '--help'): + usage(0) + if opt in ('-l', '--listname'): + if listnames is None: + listnames = [arg] + else: + listnames.append(arg) + + if listnames is None: + listnames = Utils.list_names() + + # This is the list that all the reminders will look like they come from, + # but with the host name coerced to the virtual host we're processing. + try: + sitelist = MailList.MailList(mm_cfg.MAILMAN_SITE_LIST, lock=0) + except Errors.MMUnknownListError: + # Do it this way for I18n's _() + sitelistname = mm_cfg.MAILMAN_SITE_LIST + print >> sys.stderr, _('Site list is missing: %(sitelistname)s') + syslog('error', 'Site list is missing: %s', mm_cfg.MAILMAN_SITE_LIST) + sys.exit(1) + + # Group lists by host_name if VIRTUAL_HOST_OVERVIEW is true, otherwise + # there's only one key in this dictionary: mm_cfg.DEFAULT_EMAIL_HOST. The + # values are lists of the unlocked MailList instances. + byhost = {} + for listname in listnames: + mlist = MailList.MailList(listname, lock=0) + if not mlist.send_reminders: + continue + if mm_cfg.VIRTUAL_HOST_OVERVIEW: + host = mlist.host_name + else: + # See the note in Defaults.py concerning DEFAULT_HOST_NAME + # vs. DEFAULT_EMAIL_HOST. + host = mm_cfg.DEFAULT_HOST_NAME or mm_cfg.DEFAULT_EMAIL_HOST + byhost.setdefault(host, []).append(mlist) + + # Now for each virtual host, collate the user information. Each user + # entry has the form (listaddr, password, optionsurl) + for host in byhost.keys(): + # Site owner is `mailman@dom.ain' + userinfo = {} + for mlist in byhost[host]: + listaddr = mlist.GetListEmail() + for member in mlist.getMembers(): + # BAW: we group by cpaddress because although it's highly + # likely, there's no guarantee that person@list1 is the same + # as PERSON@list2. Sigh. + cpaddress = mlist.getMemberCPAddress(member) + password = mlist.getMemberPassword(member) + optionsurl = mlist.GetOptionsURL(member) + lang = mlist.getMemberLanguage(member) + info = (listaddr, password, optionsurl, lang) + userinfo.setdefault(cpaddress, []).append(info) + # Now that we've collected user information for this host, send each + # user the password reminder. + for addr in userinfo.keys(): + # If the person is on more than one list, it is possible that they + # have different preferred languages, and there's no good way to + # know which one they want their password reminder in. Pick the + # most popular, and break the tie randomly. + # + # Also, we need an example -request address for cronpass.txt and + # again, there's no clear winner. Just take the first one in this + # case. + table = [] + langs = {} + for listaddr, password, optionsurl, lang in userinfo[addr]: + langs[lang] = langs.get(lang, 0) + 1 + # If the list address is really long, break it across two + # lines. + if len(listaddr) > 39: + fmt = '%s\n %-10s\n%s\n' + else: + fmt = '%-40s %-10s\n%s\n' + table.append(fmt % (listaddr, password, optionsurl)) + # Figure out which language to use + langcnt = 0 + poplang = None + for lang, cnt in langs.items(): + if cnt > langcnt: + poplang = lang + langcnt = cnt + # Craft the table header + header = '%-40s %-10s\n%-40s %-10s' % ( + _('List'), _('Password // URL'), '----', '--------') + # Now we're finally ready to send the email! + siteowner = Utils.get_site_email(host, 'owner') + sitereq = Utils.get_site_email(host, 'request') + sitebounce = Utils.get_site_email(host, 'bounces') + text = Utils.maketext( + 'cronpass.txt', + {'hostname': host, + 'useraddr': addr, + 'exreq' : sitereq, + 'owner' : siteowner, + }, lang=poplang) + # Add the table to the end so it doesn't get wrapped/filled + text += (header + '\n' + NL.join(table)) + # Translate the message and headers to user's suggested lang + otrans = i18n.get_translation() + try: + i18n.set_language(poplang) + msg = Message.UserNotification( + addr, siteowner, + _('%(host)s mailing list memberships reminder'), + text, poplang) + finally: + i18n.set_translation(otrans) + msg['X-No-Archive'] = 'yes' + # We want to make this look like it's coming from the siteowner's + # list, but we also want to be sure that the apparent host name is + # the current virtual host. Look in CookHeaders.py for why this + # trick works. Blarg. + msg.send(sitelist, **{'errorsto': sitebounce, + '_nolist' : 1, + 'verp' : mm_cfg.VERP_PASSWORD_REMINDERS, + }) + + + +if __name__ == '__main__': + main() |