aboutsummaryrefslogtreecommitdiffstats
path: root/cron/mailpasswds
diff options
context:
space:
mode:
Diffstat (limited to 'cron/mailpasswds')
-rwxr-xr-xcron/mailpasswds216
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()