aboutsummaryrefslogtreecommitdiffstats
path: root/cron/disabled
diff options
context:
space:
mode:
Diffstat (limited to 'cron/disabled')
-rw-r--r--cron/disabled209
1 files changed, 209 insertions, 0 deletions
diff --git a/cron/disabled b/cron/disabled
new file mode 100644
index 00000000..dcf05f25
--- /dev/null
+++ b/cron/disabled
@@ -0,0 +1,209 @@
+#! @PYTHON@
+#
+# Copyright (C) 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.
+
+"""Process disabled members, recommended once per day.
+
+This script cruises through every mailing list looking for members whose
+delivery is disabled. If they have been disabled due to bounces, they will
+receive another notification, or they may be removed if they've received the
+maximum number of notifications.
+
+Use the --byadmin, --byuser, and --unknown flags to also send notifications to
+members whose accounts have been disabled for those reasons. Use --all to
+send the notification to all disabled members.
+
+Usage: %(PROGRAM)s [options]
+
+Options:
+ -h / --help
+ Print this message and exit.
+
+ -o / --byadmin
+ Also send notifications to any member disabled by the list
+ owner/administrator.
+
+ -m / --byuser
+ Also send notifications to any member disabled by themselves.
+
+ -u / --unknown
+ Also send notifications to any member disabled for unknown reasons
+ (usually a legacy disabled address).
+
+ -b / --notbybounce
+ Don't send notifications to members disabled because of bounces (the
+ default is to notify bounce disabled members).
+
+ -a / --all
+ Send notifications to all disabled members.
+
+ -f / --force
+ Send notifications to disabled members even if they're not due a new
+ notification yet.
+
+ -l listname
+ --listname=listname
+ Process only the given list, otherwise do all lists.
+"""
+
+import sys
+import time
+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 Utils
+from Mailman import MailList
+from Mailman import Pending
+from Mailman import MemberAdaptor
+from Mailman.Bouncer import _BounceInfo
+from Mailman.Logging.Syslog import syslog
+from Mailman.i18n import _
+
+# Work around known problems with some RedHat cron daemons
+import signal
+signal.signal(signal.SIGCHLD, signal.SIG_DFL)
+
+PROGRAM = sys.argv[0]
+
+
+
+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:], 'hl:omubaf',
+ ['byadmin', 'byuser', 'unknown', 'notbybounce', 'all',
+ 'listname=', 'help', 'force'])
+ except getopt.error, msg:
+ usage(1, msg)
+
+ if args:
+ usage(1)
+
+ force = 0
+ listnames = []
+ who = [MemberAdaptor.BYBOUNCE]
+ for opt, arg in opts:
+ if opt in ('-h', '--help'):
+ usage(0)
+ elif opt in ('-l', '--list'):
+ listnames.append(arg)
+ elif opt in ('-o', '--byadmin'):
+ who.append(MemberAdaptor.BYADMIN)
+ elif opt in ('-m', '--byuser'):
+ who.append(MemberAdaptor.BYUSER)
+ elif opt in ('-u', '--unknown'):
+ who.append(MemberAdaptor.UNKNOWN)
+ elif opt in ('-b', '--notbybounce'):
+ try:
+ who.remove(MemberAdaptor.BYBOUNCE)
+ except ValueError:
+ # Already removed
+ pass
+ elif opt in ('-a', '--all'):
+ who = [MemberAdaptor.BYBOUNCE, MemberAdaptor.BYADMIN,
+ MemberAdaptor.BYUSER, MemberAdaptor.UNKNOWN]
+ elif opt in ('-f', '--force'):
+ force = 1
+
+ who = tuple(who)
+
+ if not listnames:
+ listnames = Utils.list_names()
+
+ msg = _('[disabled by periodic sweep and cull, no message available]')
+ today = time.mktime(time.localtime()[:3] + (0,) * 6)
+ for listname in listnames:
+ # List of members to notify
+ notify = []
+ mlist = MailList.MailList(listname)
+ try:
+ interval = mlist.bounce_you_are_disabled_warnings_interval
+ # Find all the members who are currently bouncing and see if
+ # they've reached the disable threshold but haven't yet been
+ # disabled. This is a sweep through the membership catching
+ # situations where they've bounced a bunch, then the list admin
+ # lowered the threshold, but we haven't (yet) seen more bounces
+ # from the member. Note: we won't worry about stale information
+ # or anything else since the normal bounce processing code will
+ # handle that.
+ disables = []
+ for member in mlist.getBouncingMembers():
+ if mlist.getDeliveryStatus(member) <> MemberAdaptor.ENABLED:
+ continue
+ info = mlist.getBounceInfo(member)
+ if info.score >= mlist.bounce_score_threshold:
+ disables.append((member, info))
+ if disables:
+ for member, info in disables:
+ mlist.disableBouncingMember(member, info, msg)
+ # Go through all the members who have delivery disabled, and find
+ # those that are due to have another notification. If they are
+ # disabled for another reason than bouncing, and we're processing
+ # them (because of the command line switch) then they won't have a
+ # bounce info record. We can piggyback on that for all disable
+ # purposes.
+ members = mlist.getDeliveryStatusMembers(who)
+ for member in members:
+ info = mlist.getBounceInfo(member)
+ if not info:
+ # See if they are bounce disabled, or disabled for some
+ # other reason.
+ status = mlist.getDeliveryStatus(member)
+ if status == MemberAdaptor.BYBOUNCE:
+ syslog(
+ 'error',
+ '%s disabled BYBOUNCE lacks bounce info, list: %s',
+ member, mlist.internal_name())
+ continue
+ info = _BounceInfo(
+ member, 0, today,
+ mlist.bounce_you_are_disabled_warnings,
+ Pending.new(Pending.RE_ENABLE, mlist.internal_name(),
+ member))
+ mlist.setBounceInfo(member, info)
+ lastnotice = time.mktime(info.lastnotice + (0,) * 6)
+ if force or today >= lastnotice + interval:
+ notify.append(member)
+ # Now, send notifications to anyone who is due
+ for member in notify:
+ syslog('bounce', 'Notifying disabled member %s for list: %s',
+ member, mlist.internal_name())
+ mlist.sendNextNotification(member)
+ mlist.Save()
+ finally:
+ mlist.Unlock()
+
+
+
+if __name__ == '__main__':
+ main()