summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Mailman/bin/bumpdigests.py (renamed from cron/bumpdigests)77
-rwxr-xr-xMailman/bin/checkdbs.py (renamed from cron/checkdbs)202
-rw-r--r--Mailman/bin/disabled.py (renamed from cron/disabled)182
-rwxr-xr-xMailman/bin/gate_news.py (renamed from cron/gate_news)96
-rw-r--r--Mailman/bin/nightly_gzip.py126
-rwxr-xr-xMailman/bin/senddigests.py71
-rwxr-xr-xconfigure9
-rw-r--r--configure.in9
-rw-r--r--cron/Makefile.in16
-rwxr-xr-xcron/crontab.in.in3
-rwxr-xr-xcron/mailpasswds241
-rw-r--r--cron/nightly_gzip156
-rwxr-xr-xcron/senddigests94
13 files changed, 438 insertions, 844 deletions
diff --git a/cron/bumpdigests b/Mailman/bin/bumpdigests.py
index 57cc45e1e..fe63410d6 100644
--- a/cron/bumpdigests
+++ b/Mailman/bin/bumpdigests.py
@@ -1,89 +1,66 @@
-#! @PYTHON@
-#
-# Copyright (C) 1998,1999,2000,2001,2002 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2006 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.
-
-"""Increment the digest volume number and reset the digest number to one.
-
-Usage: %(PROGRAM)s [options] [listname ...]
-
-Options:
-
- --help/-h
- Print this message and exit.
-
-The lists named on the command line are bumped. If no list names are given,
-all lists are bumped.
-"""
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
import sys
-import getopt
+import optparse
-import paths
-from Mailman import mm_cfg
-from Mailman import Utils
-from Mailman import MailList
from Mailman import Errors
+from Mailman import MailList
+from Mailman import Utils
+from Mailman import mm_cfg
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]
+__i18n_templates__ = True
-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 parseargs():
+ parser = optparse.OptionParser(version=mm_cfg.MAILMAN_VERSION,
+ usage=_("""\
+%prog [options] [listname ...]
+
+Increment the digest volume number and reset the digest number to one. All
+the lists named on the command line are bumped. If no list names are given,
+all lists are bumped."""))
+ opts, args = parser.parse_args()
+ return opts, args, parser
def main():
- try:
- opts, args = getopt.getopt(sys.argv[1:], 'h', ['help'])
- except getopt.error, msg:
- usage(1, msg)
-
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- usage(0)
-
- if args:
- listnames = args
- else:
- listnames = Utils.list_names()
+ opts, args, parser = parseargs()
+ listnames = set(args or Utils.list_names())
if not listnames:
print _('Nothing to do.')
sys.exit(0)
for listname in listnames:
try:
- # be sure the list is locked
+ # Be sure the list is locked
mlist = MailList.MailList(listname)
except Errors.MMListError, e:
- usage(1, _('No such list: %(listname)s'))
+ parser.print_help()
+ print >> sys.stderr, _('No such list: $listname')
+ sys.exit(1)
try:
mlist.bump_digest_volume()
finally:
diff --git a/cron/checkdbs b/Mailman/bin/checkdbs.py
index 126981093..ebcbdb177 100755
--- a/cron/checkdbs
+++ b/Mailman/bin/checkdbs.py
@@ -1,6 +1,4 @@
-#! @PYTHON@
-#
-# Copyright (C) 1998-2003 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2006 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
@@ -14,122 +12,47 @@
#
# 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.
-
-"""Check for pending admin requests and mail the list owners if necessary.
-
-Usage: %(PROGRAM)s [options]
-
-Options:
-
- -h/--help
- Print this message and exit.
-"""
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
import sys
import time
-import getopt
-from types import UnicodeType
-
-import paths
+import optparse
-# Import this after paths so we get Mailman's copy of the email package
from email.Charset import Charset
-from Mailman import mm_cfg
-from Mailman import Utils
from Mailman import MailList
from Mailman import Message
+from Mailman import Utils
from Mailman import i18n
-
-# Work around known problems with some RedHat cron daemons
-import signal
-signal.signal(signal.SIGCHLD, signal.SIG_DFL)
-
-NL = '\n'
-PROGRAM = sys.argv[0]
+from Mailman import mm_cfg
_ = i18n._
i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
-now = time.time()
+__i18n_templates__ = True
+# Work around known problems with some RedHat cron daemons
+import signal
+signal.signal(signal.SIGCHLD, signal.SIG_DFL)
-
-def usage(code, msg=''):
- if code:
- fd = sys.stderr
- else:
- fd = sys.stdout
- print >> fd, _(__doc__)
- if msg:
- print >> fd, msg
- sys.exit(code)
+NL = u'\n'
+now = time.time()
-def main():
- try:
- opts, args = getopt.getopt(sys.argv[1:], 'h', ['help'])
- except getopt.error, msg:
- usage(1, msg)
-
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- usage(0)
+def parseargs():
+ parser = optparse.OptionParser(version=mm_cfg.MAILMAN_VERSION,
+ usage=_("""\
+%prog [options]
+Check for pending admin requests and mail the list owners if necessary."""))
+ opts, args = parser.parse_args()
if args:
- usage(1)
-
- for name in Utils.list_names():
- # the list must be locked in order to open the requests database
- mlist = MailList.MailList(name)
- try:
- count = mlist.NumRequestsPending()
- # While we're at it, let's evict yesterday's autoresponse data
- midnightToday = Utils.midnight()
- evictions = []
- for sender in mlist.hold_and_cmd_autoresponses.keys():
- date, respcount = mlist.hold_and_cmd_autoresponses[sender]
- if Utils.midnight(date) < midnightToday:
- evictions.append(sender)
- if evictions:
- for sender in evictions:
- del mlist.hold_and_cmd_autoresponses[sender]
- # Only here have we changed the list's database
- mlist.Save()
- if count:
- i18n.set_language(mlist.preferred_language)
- realname = mlist.real_name
- discarded = auto_discard(mlist)
- if discarded:
- count = count - discarded
- text = _(
- 'Notice: %(discarded)d old request(s) automatically expired.\n\n')
- else:
- text = ''
- if count:
- text += Utils.maketext(
- 'checkdbs.txt',
- {'count' : count,
- 'host_name': mlist.host_name,
- 'adminDB' : mlist.GetScriptURL('admindb', absolute=1),
- 'real_name': realname,
- }, mlist=mlist)
- text += '\n' + pending_requests(mlist)
- subject = _(
- '%(count)d %(realname)s moderator request(s) waiting')
- else:
- subject = _(
- '%(realname)s moderator request check result')
- msg = Message.UserNotification(mlist.GetOwnerEmail(),
- mlist.GetBouncesEmail(),
- subject, text,
- mlist.preferred_language)
- msg.send(mlist, **{'tomoderators': 1})
- finally:
- mlist.Unlock()
-
+ parser.print_help()
+ print >> sys.stderr, _('Unexpected arguments')
+ sys.exit(1)
+ return opts, args, parser
@@ -137,37 +60,37 @@ def pending_requests(mlist):
# Must return a byte string
lcset = Utils.GetCharSet(mlist.preferred_language)
pending = []
- first = 1
+ first = True
for id in mlist.GetSubscriptionIds():
if first:
pending.append(_('Pending subscriptions:'))
- first = 0
+ first = False
when, addr, fullname, passwd, digest, lang = mlist.GetRecord(id)
if fullname:
- if isinstance(fullname, UnicodeType):
+ if isinstance(fullname, unicode):
fullname = fullname.encode(lcset, 'replace')
fullname = ' (%s)' % fullname
pending.append(' %s%s %s' % (addr, fullname, time.ctime(when)))
- first = 1
+ first = True
for id in mlist.GetHeldMessageIds():
if first:
pending.append(_('\nPending posts:'))
- first = 0
+ first = False
info = mlist.GetRecord(id)
when, sender, subject, reason, text, msgdata = mlist.GetRecord(id)
subject = Utils.oneline(subject, lcset)
date = time.ctime(when)
reason = _(reason)
pending.append(_("""\
-From: %(sender)s on %(date)s
-Subject: %(subject)s
-Cause: %(reason)s"""))
+From: $sender on $date
+Subject: $subject
+Cause: $reason"""))
pending.append('')
# Coerce all items in pending to a Unicode so we can join them
upending = []
charset = Utils.GetCharSet(mlist.preferred_language)
for s in pending:
- if isinstance(s, UnicodeType):
+ if isinstance(s, unicode):
upending.append(s)
else:
upending.append(unicode(s, charset, 'replace'))
@@ -175,22 +98,24 @@ Cause: %(reason)s"""))
# string in the charset of the list's language. This could fail if for
# example, the request was pended while the list's language was French,
# but then it was changed to English before checkdbs ran.
- text = u'\n'.join(upending)
+ text = NL.join(upending)
charset = Charset(Utils.GetCharSet(mlist.preferred_language))
incodec = charset.input_codec or 'ascii'
outcodec = charset.output_codec or 'ascii'
- if isinstance(text, UnicodeType):
+ if isinstance(text, unicode):
return text.encode(outcodec, 'replace')
# Be sure this is a byte string encodeable in the list's charset
utext = unicode(text, incodec, 'replace')
return utext.encode(outcodec, 'replace')
+
+
def auto_discard(mlist):
# Discard old held messages
discard_count = 0
- expire = mlist.max_days_to_hold * 86400 # days
+ expire = mm_cfg.days(mlist.max_days_to_hold)
heldmsgs = mlist.GetHeldMessageIds()
- if expire and len(heldmsgs):
+ if expire and heldmsgs:
for id in heldmsgs:
if now - mlist.GetRecord(id)[0] > expire:
mlist.HandleRequest(id, mm_cfg.DISCARD)
@@ -198,6 +123,59 @@ def auto_discard(mlist):
mlist.Save()
return discard_count
+
+
+def main():
+ opts, args, parser = parseargs()
+
+ for name in Utils.list_names():
+ # The list must be locked in order to open the requests database
+ mlist = MailList.MailList(name)
+ try:
+ count = mlist.NumRequestsPending()
+ # While we're at it, let's evict yesterday's autoresponse data
+ midnight_today = Utils.midnight()
+ evictions = []
+ for sender in mlist.hold_and_cmd_autoresponses.keys():
+ date, respcount = mlist.hold_and_cmd_autoresponses[sender]
+ if Utils.midnight(date) < midnight_today:
+ evictions.append(sender)
+ if evictions:
+ for sender in evictions:
+ del mlist.hold_and_cmd_autoresponses[sender]
+ # This is the only place we've changed the list's database
+ mlist.Save()
+ if count:
+ i18n.set_language(mlist.preferred_language)
+ realname = mlist.real_name
+ discarded = auto_discard(mlist)
+ if discarded:
+ count = count - discarded
+ text = _(
+ 'Notice: $discarded old request(s) automatically expired.\n\n')
+ else:
+ text = ''
+ if count:
+ text += Utils.maketext(
+ 'checkdbs.txt',
+ {'count' : count,
+ 'host_name': mlist.host_name,
+ 'adminDB' : mlist.GetScriptURL('admindb', absolute=1),
+ 'real_name': realname,
+ }, mlist=mlist)
+ text += '\n' + pending_requests(mlist)
+ subject = _('$count $realname moderator request(s) waiting')
+ else:
+ subject = _('$realname moderator request check result')
+ msg = Message.UserNotification(mlist.GetOwnerEmail(),
+ mlist.GetBouncesEmail(),
+ subject, text,
+ mlist.preferred_language)
+ msg.send(mlist, **{'tomoderators': True})
+ finally:
+ mlist.Unlock()
+
+
if __name__ == '__main__':
main()
diff --git a/cron/disabled b/Mailman/bin/disabled.py
index 314339f1a..161a06712 100644
--- a/cron/disabled
+++ b/Mailman/bin/disabled.py
@@ -1,5 +1,3 @@
-#! @PYTHON@
-#
# Copyright (C) 2001-2006 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
@@ -17,60 +15,10 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# 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 logging
-
-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
+import optparse
from Mailman import Errors
from Mailman import MailList
@@ -78,75 +26,101 @@ from Mailman import MemberAdaptor
from Mailman import Pending
from Mailman import Utils
from Mailman import loginit
+from Mailman import mm_cfg
from Mailman.Bouncer import _BounceInfo
from Mailman.i18n import _
+__i18n_templates__ = True
+
# Work around known problems with some RedHat cron daemons
import signal
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
-PROGRAM = sys.argv[0]
-
loginit.initialize(propagate=True)
elog = logging.getLogger('mailman.error')
blog = logging.getLogger('mailman.bounce')
+ALL = (MemberAdaptor.BYBOUNCE,
+ MemberAdaptor.BYADMIN,
+ MemberAdaptor.BYUSER,
+ MemberAdaptor.UNKNOWN,
+ )
+
-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 who_callback(option, opt, value, parser):
+ dest = getattr(parser.values, option.dest)
+ if opt in ('-o', '--byadmin'):
+ dest.add(MemberAdaptor.BYADMIN)
+ elif opt in ('-m', '--byuser'):
+ dest.add(MemberAdaptor.BYUSER)
+ elif opt in ('-u', '--unknown'):
+ dest.add(MemberAdaptor.UNKNOWN)
+ elif opt in ('-b', '--notbybounce'):
+ dest.discard(MemberAdaptor.BYBOUNCE)
+ elif opt in ('-a', '--all'):
+ dest.update(ALL)
-
-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)
+def parseargs():
+ parser = optparse.OptionParser(version=mm_cfg.MAILMAN_VERSION,
+ usage=_("""\
+%prog [options]
- if args:
- usage(1)
+Process disabled members, recommended once per day.
+
+This script iterates 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."""))
+ # This is the set of working flags for who to send notifications to. By
+ # default, we notify anybody who has been disable due to bounces.
+ parser.set_defaults(who=set([MemberAdaptor.BYBOUNCE]))
+ parser.add_option('-o', '--byadmin',
+ callback=who_callback, action='callback', dest='who',
+ help=_("""\
+Also send notifications to any member disabled by the list
+owner/administrator."""))
+ parser.add_option('-m', '--byuser',
+ callback=who_callback, action='callback', dest='who',
+ help=_("""\
+Also send notifications to any member who has disabled themself."""))
+ parser.add_option('-u', '--unknown',
+ callback=who_callback, action='callback', dest='who',
+ help=_("""\
+Also send notifications to any member disabled for unknown reasons
+(usually a legacy disabled address)."""))
+ parser.add_option('-b', '--notbybounce',
+ callback=who_callback, action='callback', dest='who',
+ help=_("""\
+Don't send notifications to members disabled because of bounces (the
+default is to notify bounce disabled members)."""))
+ parser.add_option('-a', '--all',
+ callback=who_callback, action='callback', dest='who',
+ help=_('Send notifications to all disabled members'))
+ parser.add_option('-f', '--force',
+ default=False, action='store_true',
+ help=_("""\
+Send notifications to disabled members even if they're not due a new
+notification yet."""))
+ parser.add_option('-l', '--listname',
+ dest='listnames', action='append', default=[],
+ type='string', help=_("""\
+Process only the given list, otherwise do all lists."""))
+ opts, args = parser.parse_args()
+ return opts, args, parser
- 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)
+
+def main():
+ opts, args, parser = parseargs()
- if not listnames:
- listnames = Utils.list_names()
+ listnames = set(opts.listnames or Utils.list_names())
+ who = tuple(opts.who)
msg = _('[disabled by periodic sweep and cull, no message available]')
today = time.mktime(time.localtime()[:3] + (0,) * 6)
@@ -200,7 +174,7 @@ def main():
member))
mlist.setBounceInfo(member, info)
lastnotice = time.mktime(info.lastnotice + (0,) * 6)
- if force or today >= lastnotice + interval:
+ if opts.force or today >= lastnotice + interval:
notify.append(member)
# Now, send notifications to anyone who is due
for member in notify:
diff --git a/cron/gate_news b/Mailman/bin/gate_news.py
index f0701ca8b..4c55273cd 100755
--- a/cron/gate_news
+++ b/Mailman/bin/gate_news.py
@@ -1,5 +1,3 @@
-#! @PYTHON@
-#
# Copyright (C) 1998-2006 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
@@ -17,33 +15,14 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
-"""Poll the NNTP servers for messages to be gatewayed to mailing lists.
-
-Usage: gate_news [options]
-
-Where options are
-
- --help
- -h
- Print this text and exit.
-
-"""
-
import os
import sys
import time
-import getopt
import socket
import logging
import nntplib
+import optparse
-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
-
-# Import this /after/ paths so that the sys.path is properly hacked
import email.Errors
from email.Parser import Parser
@@ -52,6 +31,7 @@ from Mailman import MailList
from Mailman import Message
from Mailman import Utils
from Mailman import loginit
+from Mailman import mm_cfg
from Mailman.Queue.sbcache import get_switchboard
from Mailman.i18n import _
@@ -67,17 +47,25 @@ NL = '\n'
loginit.initialize(propagate=True)
log = logging.getLogger('mailman.fromusenet')
+class _ContinueLoop(Exception):
+ pass
+
+__i18n_templates__ = True
+
-def usage(status, msg=''):
- if code:
- fd = sys.stderr
- else:
- fd = sys.stdout
- print >> fd, _(__doc__)
- if msg:
- print >> fd, msg
- sys.exit(code)
+def parseargs():
+ parser = optparse.OptionParser(version=mm_cfg.MAILMAN_VERSION,
+ usage=_("""\
+%prog [options]
+
+Poll the NNTP servers for messages to be gatewayed to mailing lists."""))
+ opts, args = parser.parse_args()
+ if args:
+ parser.print_help()
+ print >> sys.stderr, _('Unexpected arguments')
+ sys.exit(1)
+ return opts, args, parser
@@ -102,15 +90,12 @@ def open_newsgroup(mlist):
_hostcache[mlist.nntp_host] = conn
# Get the GROUP information for the list, but we're only really interested
# in the first article number and the last article number
- r,c,f,l,n = conn.group(mlist.linked_newsgroup)
+ r, c, f, l, n = conn.group(mlist.linked_newsgroup)
return conn, int(f), int(l)
def clearcache():
- reverse = {}
- for conn in _hostcache.values():
- reverse[conn] = 1
- for conn in reverse.keys():
+ for conn in set(_hostcache.values()):
conn.quit()
_hostcache.clear()
@@ -123,21 +108,21 @@ def poll_newsgroup(mlist, conn, first, last, glock):
for num in range(first, last):
glock.refresh()
try:
- headers = conn.head(`num`)[3]
- found_to = 0
- beenthere = 0
+ headers = conn.head(repr(num))[3]
+ found_to = False
+ beenthere = False
for header in headers:
i = header.find(':')
value = header[:i].lower()
if i > 0 and value == 'to':
- found_to = 1
+ found_to = True
if value <> 'x-beenthere':
continue
if header[i:] == ': %s' % mlist.GetListEmail():
- beenthere = 1
+ beenthere = True
break
if not beenthere:
- body = conn.body(`num`)[3]
+ body = conn.body(repr(num))[3]
# Usenet originated messages will not have a Unix envelope
# (i.e. "From " header). This breaks Pipermail archiving, so
# we will synthesize one. Be sure to use the format searched
@@ -166,8 +151,8 @@ def poll_newsgroup(mlist, conn, first, last, glock):
# Post the message to the locked list
inq = get_switchboard(mm_cfg.INQUEUE_DIR)
inq.enqueue(msg,
- listname = mlist.internal_name(),
- fromusenet = 1)
+ listname=mlist.internal_name(),
+ fromusenet=True)
log.info('posted to list %s: %7d', listname, num)
except nntplib.NNTPError, e:
log.exception('NNTP error for list %s: %7d', listname, num)
@@ -185,11 +170,11 @@ def process_lists(glock):
# Open the list unlocked just to check to see if it is gating news to
# mail. If not, we're done with the list. Otherwise, lock the list
# and gate the group.
- mlist = MailList.MailList(listname, lock=0)
+ mlist = MailList.MailList(listname, lock=False)
if not mlist.gateway_to_mail:
continue
# Get the list's watermark, i.e. the last article number that we gated
- # from news to mail. `None' means that this list has never polled its
+ # from news to mail. None means that this list has never polled its
# newsgroup and that we should do a catch up.
watermark = getattr(mlist, 'usenet_watermark', None)
# Open the newsgroup, but let most exceptions percolate up.
@@ -215,7 +200,7 @@ def process_lists(glock):
# newsgroup and the watermark. It's possible that some
# articles have been expired since the last time gate_news
# has run. Not much we can do about that.
- start = max(watermark+1, first)
+ start = max(watermark + 1, first)
if start > last:
log.info('nothing new for list %s', listname)
else:
@@ -225,7 +210,7 @@ def process_lists(glock):
# Use last+1 because poll_newsgroup() employes a for
# loop over range, and this will not include the last
# element in the list.
- poll_newsgroup(mlist, conn, start, last+1, glock)
+ poll_newsgroup(mlist, conn, start, last + 1, glock)
except LockFile.TimeOutError:
log.error('Could not acquire list lock: %s', listname)
finally:
@@ -237,8 +222,9 @@ def process_lists(glock):
def main():
+ opts, args, parser = parseargs()
lock = LockFile.LockFile(GATENEWS_LOCK_FILE,
- # it's okay to hijack this
+ # It's okay to hijack this
lifetime=LOCK_LIFETIME)
try:
lock.lock(timeout=0.5)
@@ -254,16 +240,4 @@ def main():
if __name__ == '__main__':
- try:
- opts, args = getopt.getopt(sys.argv[1:], 'h', ['help'])
- except getopt.error, msg:
- usage(1, msg)
-
- if args:
- usage(1, 'No args are expected')
-
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- usage(0)
-
main()
diff --git a/Mailman/bin/nightly_gzip.py b/Mailman/bin/nightly_gzip.py
new file mode 100644
index 000000000..037612adb
--- /dev/null
+++ b/Mailman/bin/nightly_gzip.py
@@ -0,0 +1,126 @@
+#! @PYTHON@
+#
+# Copyright (C) 1998-2006 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.
+
+import os
+import sys
+import optparse
+
+try:
+ import gzip
+except ImportError:
+ sys.exit(0)
+
+from Mailman import mm_cfg
+from Mailman import Utils
+from Mailman import MailList
+from Mailman.i18n import _
+
+__i18n_templates__ = True
+
+
+
+def parseargs():
+ parser = optparse.OptionParser(version=mm_cfg.MAILMAN_VERSION,
+ usage=_("""\
+%prog [options] [listname ...]
+
+Re-generate the Pipermail gzip'd archive flat files."""))
+ parser.add_option('-v', '--verbose',
+ default=False, action='store_true',
+ help=_("Print each file as it's being gzip'd"))
+ parser.add_option('-z', '--level',
+ default=6, type='int',
+ help=_('Specifies the compression level'))
+ opts, args = parser.parse_args()
+ if opts.level < 1 or opts.level > 9:
+ parser.print_help()
+ print >> sys.stderr, _('Illegal compression level: $opts.level')
+ sys.exit(1)
+ return opts, args, parser
+
+
+
+def compress(txtfile, opts):
+ if opts.verbose:
+ print _("gzip'ing: $txtfile")
+ infp = outfp = None
+ try:
+ infp = open(txtfile)
+ outfp = gzip.open(txtfile + '.gz', 'wb', opts.level)
+ outfp.write(infp.read())
+ finally:
+ if outfp:
+ outfp.close()
+ if infp:
+ infp.close()
+
+
+
+def main():
+ if mm_cfg.ARCHIVE_TO_MBOX not in (1, 2) or mm_cfg.GZIP_ARCHIVE_TXT_FILES:
+ # We're only going to run the nightly archiver if messages are
+ # archived to the mbox, and the gzip file is not created on demand
+ # (i.e. for every individual post). This is the normal mode of
+ # operation.
+ return
+
+ opts, args, parser = parseargs()
+
+ # Process all the specified lists
+ for listname in set(args or Utils.list_names()):
+ mlist = MailList.MailList(listname, lock=False)
+ if not mlist.archive:
+ continue
+ dir = mlist.archive_dir()
+ try:
+ allfiles = os.listdir(dir)
+ except OSError:
+ # Has the list received any messages? If not, last_post_time will
+ # be zero, so it's not really a bogus archive dir.
+ if mlist.last_post_time > 0:
+ print _('List $listname has a bogus archive_directory: $dir')
+ continue
+ if opts.verbose:
+ print _('Processing list: $listname')
+ files = []
+ for f in allfiles:
+ if os.path.splitext(f)[1] <> '.txt':
+ continue
+ # stat both the .txt and .txt.gz files and append them only if
+ # the former is newer than the latter.
+ txtfile = os.path.join(dir, f)
+ gzpfile = txtfile + '.gz'
+ txt_mtime = os.path.getmtime(txtfile)
+ try:
+ gzp_mtime = os.path.getmtime(gzpfile)
+ except OSError:
+ gzp_mtime = -1
+ if txt_mtime > gzp_mtime:
+ files.append(txtfile)
+ for f in files:
+ compress(f, opts)
+
+
+
+if __name__ == '__main__':
+ omask = os.umask(002)
+ try:
+ main()
+ finally:
+ os.umask(omask)
diff --git a/Mailman/bin/senddigests.py b/Mailman/bin/senddigests.py
new file mode 100755
index 000000000..fa01d3666
--- /dev/null
+++ b/Mailman/bin/senddigests.py
@@ -0,0 +1,71 @@
+# Copyright (C) 1998-2006 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.
+
+import sys
+import optparse
+
+from Mailman import MailList
+from Mailman import Utils
+from Mailman import mm_cfg
+from Mailman.i18n import _
+
+# Work around known problems with some RedHat cron daemons
+import signal
+signal.signal(signal.SIGCHLD, signal.SIG_DFL)
+
+__i18n_templates__ = True
+
+
+
+def parseargs():
+ parser = optparse.OptionParser(version=mm_cfg.MAILMAN_VERSION,
+ usage=_("""\
+%prog [options]
+
+Dispatch digests for lists w/pending messages and digest_send_periodic
+set."""))
+ parser.add_option('-l', '--listname',
+ type='string', default=[], action='append',
+ dest='listnames', help=_("""\
+Send the digest for the given list only, otherwise the digests for all
+lists are sent out. Multiple -l options may be given."""))
+ opts, args = parser.parse_args()
+ if args:
+ parser.print_help()
+ print >> sys.stderr, _('Unexpected arguments')
+ sys.exit(1)
+ return opts, args, parser
+
+
+
+def main():
+ opts, args, parser = parseargs()
+
+ for listname in set(opts.listnames or Utils.list_names()):
+ mlist = MailList.MailList(listname, lock=False)
+ if mlist.digest_send_periodic:
+ mlist.Lock()
+ try:
+ mlist.send_digest_now()
+ mlist.Save()
+ finally:
+ mlist.Unlock()
+
+
+
+if __name__ == '__main__':
+ main()
diff --git a/configure b/configure
index 34bfbf06c..058482c71 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
#! /bin/sh
-# From configure.in Revision: 7892 .
+# From configure.in Revision: 7893 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.59.
#
@@ -4303,13 +4303,6 @@ build/bin/po2templ.py:bin/po2templ.py \
build/contrib/check_perms_grsecurity.py:contrib/check_perms_grsecurity.py \
build/contrib/qmail-to-mailman.py:contrib/qmail-to-mailman.py \
build/contrib/rotatelogs.py:contrib/rotatelogs.py \
-build/cron/bumpdigests:cron/bumpdigests \
-build/cron/checkdbs:cron/checkdbs \
-build/cron/disabled:cron/disabled \
-build/cron/gate_news:cron/gate_news \
-build/cron/mailpasswds:cron/mailpasswds \
-build/cron/nightly_gzip:cron/nightly_gzip \
-build/cron/senddigests:cron/senddigests \
"
diff --git a/configure.in b/configure.in
index 41ad22893..8e49ab032 100644
--- a/configure.in
+++ b/configure.in
@@ -15,7 +15,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
dnl Process this file with autoconf to produce a configure script.
-AC_REVISION($Revision: 7893 $)
+AC_REVISION($Revision: 7895 $)
AC_PREREQ(2.0)
AC_INIT(src/common.h)
@@ -621,13 +621,6 @@ bin/po2templ.py \
contrib/check_perms_grsecurity.py \
contrib/qmail-to-mailman.py \
contrib/rotatelogs.py \
-cron/bumpdigests \
-cron/checkdbs \
-cron/disabled \
-cron/gate_news \
-cron/mailpasswds \
-cron/nightly_gzip \
-cron/senddigests \
])
dnl Please make sure to leave a space at the end of the last entry.
diff --git a/cron/Makefile.in b/cron/Makefile.in
index afb033705..ba2ed882e 100644
--- a/cron/Makefile.in
+++ b/cron/Makefile.in
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2003 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2006 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
@@ -12,7 +12,8 @@
#
# 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.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
# NOTE: Makefile.in is converted into Makefile by the configure script
# in the parent directory. Once configure has run, you can recreate
@@ -30,6 +31,7 @@ DESTDIR=
CC= @CC@
CHMOD= @CHMOD@
INSTALL= @INSTALL@
+LN_S= @LN_S@
DEFS= @DEFS@
@@ -38,13 +40,12 @@ DEFS= @DEFS@
OPT= @OPT@
CFLAGS= $(OPT) $(DEFS)
CRONDIR= $(prefix)/cron
+SCRIPTSDIR= ../bin
SHELL= /bin/sh
-PROGRAMS= checkdbs mailpasswds senddigests gate_news \
- nightly_gzip bumpdigests disabled
+LN_PROGRAMS= bumpdigests checkdbs disabled gate_news nightly_gzip senddigests
FILES= crontab.in
-
BUILDDIR= ../build/cron
# Modes for directories and executables created by the install
@@ -63,9 +64,10 @@ install:
do \
$(INSTALL) -m $(FILEMODE) $$f $(DESTDIR)$(CRONDIR); \
done
- for f in $(PROGRAMS); \
+ for f in $(LN_PROGRAMS); \
do \
- $(INSTALL) -m $(EXEMODE) $(BUILDDIR)/$$f $(DESTDIR)$(CRONDIR); \
+ rm -f $(DESTDIR)$(CRONDIR)/$$f; \
+ (cd $(DESTDIR)$(CRONDIR); $(LN_S) $(SCRIPTSDIR)/mmshell $$f); \
done
finish:
diff --git a/cron/crontab.in.in b/cron/crontab.in.in
index 49f27c729..5101ef2b3 100755
--- a/cron/crontab.in.in
+++ b/cron/crontab.in.in
@@ -10,9 +10,6 @@
# Noon, mail digests for lists that do periodic as well as threshhold delivery.
0 12 * * * @PYTHON@ -S @prefix@/cron/senddigests
#
-# 5 AM on the first of each month, mail out password reminders.
-0 5 1 * * @PYTHON@ -S @prefix@/cron/mailpasswds
-#
# Every 5 mins, try to gate news to mail. You can comment this one out
# if you don't want to allow gating, or don't have any going on right now,
# or want to exclusively use a callback strategy instead of polling.
diff --git a/cron/mailpasswds b/cron/mailpasswds
deleted file mode 100755
index 5745265a1..000000000
--- a/cron/mailpasswds
+++ /dev/null
@@ -1,241 +0,0 @@
-#! @PYTHON@
-#
-# Copyright (C) 1998-2003 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.
-
-"""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
-from types import UnicodeType
-
-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 tounicode(s, enc):
- if isinstance(s, UnicodeType):
- return s
- return unicode(s, enc, 'replace')
-
-
-
-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():
- # The user may have disabled reminders for this list
- if mlist.getMemberOption(member,
- mm_cfg.SuppressPasswordReminder):
- continue
- # Group by the lower-cased address, since Mailman always
- # treates person@dom.ain the same as PERSON@dom.ain.
- try:
- password = mlist.getMemberPassword(member)
- except Errors.NotAMemberError:
- # Here's a member with no passwords, which I think was
- # possible in older versions of Mailman. Log this and
- # move on.
- syslog('error', 'password-less member %s for list %s',
- member, mlist.internal_name())
- continue
- optionsurl = mlist.GetOptionsURL(member)
- lang = mlist.getMemberLanguage(member)
- info = (listaddr, password, optionsurl, lang)
- userinfo.setdefault(member, []).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
- enc = Utils.GetCharSet(poplang)
- # 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)
- # Coerce everything to Unicode
- text = tounicode(text, enc)
- table = [tounicode(_t, enc) for _t in table]
- # Translate the message and headers to user's suggested lang
- otrans = i18n.get_translation()
- try:
- i18n.set_language(poplang)
- # Craft table header after language was set
- header = '%-40s %-10s\n%-40s %-10s' % (
- _('List'), _('Password // URL'), '----', '--------')
- header = tounicode(header, enc)
- # Add the table to the end so it doesn't get wrapped/filled
- text += (header + '\n' + NL.join(table))
- msg = Message.UserNotification(
- addr, siteowner,
- _('%(host)s mailing list memberships reminder'),
- text.encode(enc, 'replace'), poplang)
- # Note that text must be encoded into 'enc' because unicode
- # cause error within email module in some language (Japanese).
- 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()
diff --git a/cron/nightly_gzip b/cron/nightly_gzip
deleted file mode 100644
index 0a0f4e332..000000000
--- a/cron/nightly_gzip
+++ /dev/null
@@ -1,156 +0,0 @@
-#! @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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-"""Re-generate the Pipermail gzip'd archive flat files.
-
-This script should be run nightly from cron. When run from the command line,
-the following usage is understood:
-
-Usage: %(program)s [-v] [-h] [listnames]
-
-Where:
- --verbose
- -v
- print each file as it's being gzip'd
-
- --help
- -h
- print this message and exit
-
- listnames
- Optionally, only compress the .txt files for the named lists. Without
- this, all archivable lists are processed.
-
-"""
-
-import sys
-import os
-import time
-from stat import *
-import getopt
-
-try:
- import gzip
-except ImportError:
- gzip = None
-
-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
-
-
-
-program = sys.argv[0]
-VERBOSE = 0
-
-def usage(code, msg=''):
- if code:
- fd = sys.stderr
- else:
- fd = sys.stdout
- print >> fd, _(__doc__) % globals()
- if msg:
- print >> fd, msg
- sys.exit(code)
-
-
-
-def compress(txtfile):
- if VERBOSE:
- print "gzip'ing:", txtfile
- infp = open(txtfile)
- outfp = gzip.open(txtfile+'.gz', 'wb', 6)
- outfp.write(infp.read())
- outfp.close()
- infp.close()
-
-
-
-def main():
- global VERBOSE
- try:
- opts, args = getopt.getopt(sys.argv[1:], 'vh', ['verbose', 'help'])
- except getopt.error, msg:
- usage(1, msg)
-
- # defaults
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- usage(0)
- elif opt in ('-v', '--verbose'):
- VERBOSE = 1
-
- # limit to the specified lists?
- if args:
- listnames = args
- else:
- listnames = Utils.list_names()
-
- # process all the specified lists
- for name in listnames:
- mlist = MailList.MailList(name, lock=0)
- if not mlist.archive:
- continue
- dir = mlist.archive_dir()
- try:
- allfiles = os.listdir(dir)
- except os.error:
- # has the list received any messages? if not, last_post_time will
- # be zero, so it's not really a bogus archive dir.
- if mlist.last_post_time > 0:
- print 'List', name, 'has a bogus archive_directory:', dir
- continue
- if VERBOSE:
- print 'Processing list:', name
- files = []
- for f in allfiles:
- if f[-4:] <> '.txt':
- continue
- # stat both the .txt and .txt.gz files and append them only if
- # the former is newer than the latter.
- txtfile = os.path.join(dir, f)
- gzpfile = txtfile + '.gz'
- txt_mtime = os.stat(txtfile)[ST_MTIME]
- try:
- gzp_mtime = os.stat(gzpfile)[ST_MTIME]
- except os.error:
- gzp_mtime = -1
- if txt_mtime > gzp_mtime:
- files.append(txtfile)
- for f in files:
- compress(f)
-
-
-
-if __name__ == '__main__' and \
- gzip is not None and \
- mm_cfg.ARCHIVE_TO_MBOX in (1, 2) and \
- not mm_cfg.GZIP_ARCHIVE_TXT_FILES:
- # we're only going to run the nightly archiver if messages are archived to
- # the mbox, and the gzip file is not created on demand (i.e. for every
- # individual post). This is the normal mode of operation. Also, be sure
- # we can actually import the gzip module!
- omask = os.umask(002)
- try:
- main()
- finally:
- os.umask(omask)
diff --git a/cron/senddigests b/cron/senddigests
deleted file mode 100755
index d3f2781bc..000000000
--- a/cron/senddigests
+++ /dev/null
@@ -1,94 +0,0 @@
-#! @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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-"""Dispatch digests for lists w/pending messages and digest_send_periodic set.
-
-Usage: %(PROGRAM)s [options]
-
-Options:
- -h / --help
- Print this message and exit.
-
- -l listname
- --listname=listname
- Send the digest for the given list only, otherwise the digests for all
- lists are sent out.
-"""
-
-import sys
-import getopt
-
-import paths
-from Mailman import mm_cfg
-from Mailman import Utils
-from Mailman import MailList
-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:', ['help', 'listname='])
- except getopt.error, msg:
- usage(1, msg)
-
- if args:
- usage(1)
-
- listnames = []
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- usage(0)
- elif opt in ('-l', '--listname'):
- listnames.append(arg)
-
- if not listnames:
- listnames = Utils.list_names()
-
- for listname in listnames:
- mlist = MailList.MailList(listname, lock=0)
- if mlist.digest_send_periodic:
- mlist.Lock()
- try:
- mlist.send_digest_now()
- mlist.Save()
- finally:
- mlist.Unlock()
-
-
-
-if __name__ == '__main__':
- main()