summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Mailman/Cgi/create.py12
-rw-r--r--Mailman/Cgi/edithtml.py11
-rw-r--r--Mailman/Handlers/Scrubber.py32
-rw-r--r--Mailman/Handlers/ToDigest.py8
-rw-r--r--Mailman/ListAdmin.py38
-rw-r--r--Mailman/LockFile.py10
-rw-r--r--Mailman/MTA/Postfix.py20
-rw-r--r--Mailman/Pending.py18
-rw-r--r--Mailman/Queue/BounceRunner.py8
-rw-r--r--Mailman/Queue/HTTPRunner.py1
-rw-r--r--Mailman/Queue/Switchboard.py28
-rw-r--r--Mailman/Utils.py7
-rw-r--r--Mailman/bin/genaliases.py7
-rw-r--r--Mailman/bin/import.py6
-rw-r--r--Mailman/bin/mailmanctl.py15
-rw-r--r--Mailman/bin/newlist.py36
-rw-r--r--Mailman/bin/nightly_gzip.py16
-rw-r--r--Mailman/bin/update.py10
-rw-r--r--Mailman/database/__init__.py17
-rw-r--r--Mailman/database/dbcontext.py30
-rw-r--r--Mailman/initialize.py11
21 files changed, 138 insertions, 203 deletions
diff --git a/Mailman/Cgi/create.py b/Mailman/Cgi/create.py
index 8c11f22e5..53001b356 100644
--- a/Mailman/Cgi/create.py
+++ b/Mailman/Cgi/create.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2007 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
@@ -17,7 +17,6 @@
"""Create mailing lists through the web."""
-import os
import cgi
import sha
import sys
@@ -162,15 +161,8 @@ def process_request(doc, cgidata):
mlist = MailList.MailList()
try:
pw = sha.new(password).hexdigest()
- # Guarantee that all newly created files have the proper permission.
- # proper group ownership should be assured by the autoconf script
- # enforcing that all directories have the group sticky bit set
- oldmask = os.umask(002)
try:
- try:
- mlist.Create(fqdn_listname, owner, pw, langs)
- finally:
- os.umask(oldmask)
+ mlist.Create(fqdn_listname, owner, pw, langs)
except Errors.EmailAddressError, s:
request_creation(doc, cgidata, _('Bad owner email address: $s'))
return
diff --git a/Mailman/Cgi/edithtml.py b/Mailman/Cgi/edithtml.py
index 6083bfdb9..bac719b6d 100644
--- a/Mailman/Cgi/edithtml.py
+++ b/Mailman/Cgi/edithtml.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2007 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
@@ -165,14 +165,7 @@ def ChangeHTML(mlist, cgi_info, template_name, doc):
code = re.sub(r'<([/]?script.*?)>', r'&lt;\1&gt;', code)
langdir = os.path.join(mlist.fullpath(), mlist.preferred_language)
# Make sure the directory exists
- omask = os.umask(0)
- try:
- try:
- os.mkdir(langdir, 02775)
- except OSError, e:
- if e.errno <> errno.EEXIST: raise
- finally:
- os.umask(omask)
+ Utils.makedirs(langdir)
fp = open(os.path.join(langdir, template_name), 'w')
try:
fp.write(code)
diff --git a/Mailman/Handlers/Scrubber.py b/Mailman/Handlers/Scrubber.py
index 0dc21d8c4..e14f9a549 100644
--- a/Mailman/Handlers/Scrubber.py
+++ b/Mailman/Handlers/Scrubber.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2007 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
@@ -176,11 +176,7 @@ def process(mlist, msg, msgdata=None):
# TK: if part is attached then check charset and scrub if none
if part.get('content-disposition') and \
not part.get_content_charset():
- omask = os.umask(002)
- try:
- url = save_attachment(mlist, part, dir)
- finally:
- os.umask(omask)
+ url = save_attachment(mlist, part, dir)
filename = part.get_filename(_('not available'))
filename = Utils.oneline(filename, lcset)
replace_payload_by_text(part, _("""\
@@ -204,11 +200,7 @@ Url: %(url)s
# Pull it out as an attachment but leave it unescaped. This
# is dangerous, but perhaps useful for heavily moderated
# lists.
- omask = os.umask(002)
- try:
- url = save_attachment(mlist, part, dir, filter_html=False)
- finally:
- os.umask(omask)
+ url = save_attachment(mlist, part, dir, filter_html=False)
replace_payload_by_text(part, _("""\
An HTML attachment was scrubbed...
URL: %(url)s
@@ -229,11 +221,7 @@ URL: %(url)s
# We're replacing the payload with the decoded payload so this
# will just get in the way.
del part['content-transfer-encoding']
- omask = os.umask(002)
- try:
- url = save_attachment(mlist, part, dir, filter_html=False)
- finally:
- os.umask(omask)
+ url = save_attachment(mlist, part, dir, filter_html=False)
replace_payload_by_text(part, _("""\
An HTML attachment was scrubbed...
URL: %(url)s
@@ -241,11 +229,7 @@ URL: %(url)s
elif ctype == 'message/rfc822':
# This part contains a submessage, so it too needs scrubbing
submsg = part.get_payload(0)
- omask = os.umask(002)
- try:
- url = save_attachment(mlist, part, dir)
- finally:
- os.umask(omask)
+ url = save_attachment(mlist, part, dir)
subject = submsg.get('subject', _('no subject'))
date = submsg.get('date', _('no date'))
who = submsg.get('from', _('unknown sender'))
@@ -273,11 +257,7 @@ Url: %(url)s
if payload is None:
continue
size = len(payload)
- omask = os.umask(002)
- try:
- url = save_attachment(mlist, part, dir)
- finally:
- os.umask(omask)
+ url = save_attachment(mlist, part, dir)
desc = part.get('content-description', _('not available'))
filename = part.get_filename(_('not available'))
filename = Utils.oneline(filename, lcset)
diff --git a/Mailman/Handlers/ToDigest.py b/Mailman/Handlers/ToDigest.py
index f759e82c8..471886afc 100644
--- a/Mailman/Handlers/ToDigest.py
+++ b/Mailman/Handlers/ToDigest.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2007 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
@@ -67,11 +67,7 @@ def process(mlist, msg, msgdata):
if not mlist.digestable or msgdata.get('isdigest'):
return
mboxfile = os.path.join(mlist.fullpath(), 'digest.mbox')
- omask = os.umask(007)
- try:
- mboxfp = open(mboxfile, 'a+')
- finally:
- os.umask(omask)
+ mboxfp = open(mboxfile, 'a+')
mbox = Mailbox(mboxfp)
mbox.AppendMessage(msg)
# Calculate the current size of the accumulation file. This will not tell
diff --git a/Mailman/ListAdmin.py b/Mailman/ListAdmin.py
index 84b97e2fd..bcef7d2c9 100644
--- a/Mailman/ListAdmin.py
+++ b/Mailman/ListAdmin.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2007 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
@@ -98,17 +98,13 @@ class ListAdmin:
# should we be as paranoid as for the config.pck file? Should we
# use pickle?
tmpfile = self.__filename + '.tmp'
- omask = os.umask(002)
+ fp = open(tmpfile, 'w')
try:
- fp = open(tmpfile, 'w')
- try:
- cPickle.dump(self.__db, fp, 1)
- fp.flush()
- os.fsync(fp.fileno())
- finally:
- fp.close()
+ cPickle.dump(self.__db, fp, 1)
+ fp.flush()
+ os.fsync(fp.fileno())
finally:
- os.umask(omask)
+ fp.close()
self.__db = None
# Do the dance
os.rename(tmpfile, self.__filename)
@@ -191,21 +187,17 @@ class ListAdmin:
else:
ext = 'txt'
filename = 'heldmsg-%s-%d.%s' % (self.internal_name(), id, ext)
- omask = os.umask(002)
+ fp = open(os.path.join(config.DATA_DIR, filename), 'w')
try:
- fp = open(os.path.join(config.DATA_DIR, filename), 'w')
- try:
- if config.HOLD_MESSAGES_AS_PICKLES:
- cPickle.dump(msg, fp, 1)
- else:
- g = Generator(fp)
- g(msg, 1)
- fp.flush()
- os.fsync(fp.fileno())
- finally:
- fp.close()
+ if config.HOLD_MESSAGES_AS_PICKLES:
+ cPickle.dump(msg, fp, 1)
+ else:
+ g = Generator(fp)
+ g(msg, 1)
+ fp.flush()
+ os.fsync(fp.fileno())
finally:
- os.umask(omask)
+ fp.close()
# save the information to the request database. for held message
# entries, each record in the database will be of the following
# format:
diff --git a/Mailman/LockFile.py b/Mailman/LockFile.py
index 06d5c5f8e..d13699ec4 100644
--- a/Mailman/LockFile.py
+++ b/Mailman/LockFile.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2007 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
@@ -369,15 +369,11 @@ class LockFile:
def _write(self):
# Make sure it's group writable
- oldmask = os.umask(002)
- fp = None
+ fp = open(self._tmpfname, 'w')
try:
- fp = open(self._tmpfname, 'w')
fp.write(self._tmpfname)
finally:
- if fp:
- fp.close()
- os.umask(oldmask)
+ fp.close()
def _read(self):
try:
diff --git a/Mailman/MTA/Postfix.py b/Mailman/MTA/Postfix.py
index 2c6f8c60e..6b43011ff 100644
--- a/Mailman/MTA/Postfix.py
+++ b/Mailman/MTA/Postfix.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2007 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
@@ -174,11 +174,7 @@ def _check_for_virtual_loopaddr(mlist, filename, func):
if func is _addtransport:
loopdest = 'local:' + loopdest
infp = open(filename)
- omask = os.umask(007)
- try:
- outfp = open(filename + '.tmp', 'w')
- finally:
- os.umask(omask)
+ outfp = open(filename + '.tmp', 'w')
try:
# Find the start of the loop address block
while True:
@@ -264,11 +260,7 @@ def _do_create(mlist, textfile, func):
fp = open(textfile, 'r+')
except IOError, e:
if e.errno <> errno.ENOENT: raise
- omask = os.umask(007)
- try:
- fp = open(textfile, 'w+')
- finally:
- os.umask(omask)
+ fp = open(textfile, 'w+')
try:
func(mlist, fp)
finally:
@@ -313,11 +305,7 @@ def _do_remove(mlist, textfile):
# Otherwise, there's no text file to filter so we're done.
return
try:
- omask = os.umask(007)
- try:
- outfp = open(textfile + '.tmp', 'w')
- finally:
- os.umask(omask)
+ outfp = open(textfile + '.tmp', 'w')
filteroutp = False
start = '# STANZA START: %s@%s' % (listname, hostname)
end = '# STANZA END: %s@%s' % (listname, hostname)
diff --git a/Mailman/Pending.py b/Mailman/Pending.py
index eb3b7950e..f5794453d 100644
--- a/Mailman/Pending.py
+++ b/Mailman/Pending.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2007 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
@@ -113,18 +113,14 @@ class Pending:
del evictions[cookie]
db['version'] = config.PENDING_FILE_SCHEMA_VERSION
tmpfile = '%s.tmp.%d.%d' % (self.__pendfile, os.getpid(), now)
- omask = os.umask(007)
+ fp = open(tmpfile, 'w')
try:
- fp = open(tmpfile, 'w')
- try:
- cPickle.dump(db, fp)
- fp.flush()
- os.fsync(fp.fileno())
- finally:
- fp.close()
- os.rename(tmpfile, self.__pendfile)
+ cPickle.dump(db, fp)
+ fp.flush()
+ os.fsync(fp.fileno())
finally:
- os.umask(omask)
+ fp.close()
+ os.rename(tmpfile, self.__pendfile)
def pend_confirm(self, cookie, expunge=True):
"""Return data for cookie, or None if not found.
diff --git a/Mailman/Queue/BounceRunner.py b/Mailman/Queue/BounceRunner.py
index 2d132708a..d398e1b4a 100644
--- a/Mailman/Queue/BounceRunner.py
+++ b/Mailman/Queue/BounceRunner.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2007 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
@@ -86,11 +86,7 @@ class BounceMixin:
def _queue_bounces(self, listname, addrs, msg):
today = time.localtime()[:3]
if self._bounce_events_fp is None:
- omask = os.umask(006)
- try:
- self._bounce_events_fp = open(self._bounce_events_file, 'a+b')
- finally:
- os.umask(omask)
+ self._bounce_events_fp = open(self._bounce_events_file, 'a+b')
for addr in addrs:
cPickle.dump((listname, addr, today, msg),
self._bounce_events_fp, 1)
diff --git a/Mailman/Queue/HTTPRunner.py b/Mailman/Queue/HTTPRunner.py
index 32620f458..1858cff58 100644
--- a/Mailman/Queue/HTTPRunner.py
+++ b/Mailman/Queue/HTTPRunner.py
@@ -61,6 +61,7 @@ server = make_server(config.HTTP_HOST, config.HTTP_PORT,
qlog.info('HTTPRunner qrunner started.')
+hlog.info('HTTPRunner listening on %s:%s', config.HTTP_HOST, config.HTTP_PORT)
try:
server.serve_forever()
# Do it this way because of exception hierarchy changes in Python 2.5. XXX
diff --git a/Mailman/Queue/Switchboard.py b/Mailman/Queue/Switchboard.py
index bc16bbd2d..faf0988e1 100644
--- a/Mailman/Queue/Switchboard.py
+++ b/Mailman/Queue/Switchboard.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2007 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
@@ -65,15 +65,7 @@ class Switchboard:
def __init__(self, whichq, slice=None, numslices=1, recover=False):
self.__whichq = whichq
# Create the directory if it doesn't yet exist.
- # FIXME
- omask = os.umask(0) # rwxrws---
- try:
- try:
- os.mkdir(self.__whichq, 0770)
- except OSError, e:
- if e.errno <> errno.EEXIST: raise
- finally:
- os.umask(omask)
+ Utils.makedirs(self.__whichq, 0770)
# Fast track for no slices
self.__lower = None
self.__upper = None
@@ -122,18 +114,14 @@ class Switchboard:
# object or not.
data['_parsemsg'] = (protocol == 0)
# Write to the pickle file the message object and metadata.
- omask = os.umask(007) # -rw-rw----
+ fp = open(tmpfile, 'w')
try:
- fp = open(tmpfile, 'w')
- try:
- fp.write(msgsave)
- cPickle.dump(data, fp, protocol)
- fp.flush()
- os.fsync(fp.fileno())
- finally:
- fp.close()
+ fp.write(msgsave)
+ cPickle.dump(data, fp, protocol)
+ fp.flush()
+ os.fsync(fp.fileno())
finally:
- os.umask(omask)
+ fp.close()
os.rename(tmpfile, filename)
return filebase
diff --git a/Mailman/Utils.py b/Mailman/Utils.py
index d89d45f59..0d46e7d32 100644
--- a/Mailman/Utils.py
+++ b/Mailman/Utils.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2007 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
@@ -347,6 +347,7 @@ def set_global_password(pw, siteadmin=True):
else:
filename = config.LISTCREATOR_PW_FILE
# rw-r-----
+ # XXX Is the default umask of 007 good enough?
omask = os.umask(026)
try:
fp = open(filename, 'w')
@@ -641,11 +642,11 @@ def reap(kids, func=None, once=False):
-def makedirs(path):
+def makedirs(path, mode=02775):
try:
omask = os.umask(0)
try:
- os.makedirs(path, 02775)
+ os.makedirs(path, mode)
finally:
os.umask(omask)
except OSError, e:
diff --git a/Mailman/bin/genaliases.py b/Mailman/bin/genaliases.py
index 2796804df..4ce8160fd 100644
--- a/Mailman/bin/genaliases.py
+++ b/Mailman/bin/genaliases.py
@@ -1,6 +1,6 @@
#! @PYTHON@
#
-# Copyright (C) 2001-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2007 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
@@ -17,7 +17,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
-import os
import sys
import optparse
@@ -72,9 +71,6 @@ def main():
for listname in Utils.list_names():
mlist = MailList.MailList(listname, lock=False)
mlists.setdefault(mlist.host_name, []).append(mlist)
- # Make sure the files are created rw-rw-xxx; it should be okay to be world
- # readable.
- omask = os.umask(002)
try:
MTA.clear()
if not mlists:
@@ -86,7 +82,6 @@ def main():
# Be verbose for only the first printed list
quiet = True
finally:
- os.umask(omask)
lock.unlock(unconditionally=True)
diff --git a/Mailman/bin/import.py b/Mailman/bin/import.py
index 68876def1..b643de389 100644
--- a/Mailman/bin/import.py
+++ b/Mailman/bin/import.py
@@ -48,12 +48,12 @@ def nodetext(node):
return u''
-def nodegen(node, *entities):
+def nodegen(node, *elements):
for child in node.childNodes:
if child.nodeType <> minidom.Node.ELEMENT_NODE:
continue
- if entities and child.tagName not in entities:
- print _('Ignoring unexpected entity: $node.tagName')
+ if elements and child.tagName not in elements:
+ print _('Ignoring unexpected element: $node.tagName')
else:
yield child
diff --git a/Mailman/bin/mailmanctl.py b/Mailman/bin/mailmanctl.py
index 5c85799bc..db74214c0 100644
--- a/Mailman/bin/mailmanctl.py
+++ b/Mailman/bin/mailmanctl.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2007 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
@@ -261,7 +261,7 @@ def start_runner(qrname, slice, count):
args.extend(['-C', opts.config])
os.execl(*args)
# Should never get here
- raise RuntimeError, 'os.execl() failed'
+ raise RuntimeError('os.execl() failed')
def start_all_runners():
@@ -371,23 +371,18 @@ def main():
return
# child
lock._take_possession()
- # First, save our pid in a file for "mailmanctl stop" rendezvous. We
- # want the perms on the .pid file to be rw-rw----
- omask = os.umask(6)
+ # Save our pid in a file for "mailmanctl stop" rendezvous.
+ fp = open(config.PIDFILE, 'w')
try:
- fp = open(config.PIDFILE, 'w')
print >> fp, os.getpid()
- fp.close()
finally:
- os.umask(omask)
+ fp.close()
# Create a new session and become the session leader, but since we
# won't be opening any terminal devices, don't do the ultra-paranoid
# suggestion of doing a second fork after the setsid() call.
os.setsid()
# Instead of cd'ing to root, cd to the Mailman installation home
os.chdir(config.PREFIX)
- # Set our file mode creation umask
- os.umask(007)
# I don't think we have any unneeded file descriptors.
#
# Now start all the qrunners. This returns a dictionary where the
diff --git a/Mailman/bin/newlist.py b/Mailman/bin/newlist.py
index edd7ad7bd..a127b25e1 100644
--- a/Mailman/bin/newlist.py
+++ b/Mailman/bin/newlist.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2007 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
@@ -15,7 +15,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
-import os
import sha
import sys
import getpass
@@ -148,27 +147,20 @@ def main():
mlist.preferred_language = opts.language
try:
pw = sha.new(listpasswd).hexdigest()
- # Guarantee that all newly created files have the proper permission.
- # proper group ownership should be assured by the autoconf script
- # enforcing that all directories have the group sticky bit set.
- oldmask = os.umask(002)
try:
- try:
- mlist.Create(fqdn_listname, owner_mail, pw)
- except Errors.BadListNameError, s:
- parser.print_help()
- print >> sys.stderr, _('Illegal list name: $s')
- sys.exit(1)
- except Errors.EmailAddressError, s:
- parser.print_help()
- print >> sys.stderr, _('Bad owner email address: $s')
- sys.exit(1)
- except Errors.MMListAlreadyExistsError:
- parser.print_help()
- print >> sys.stderr, _('List already exists: $listname')
- sys.exit(1)
- finally:
- os.umask(oldmask)
+ mlist.Create(fqdn_listname, owner_mail, pw)
+ except Errors.BadListNameError, s:
+ parser.print_help()
+ print >> sys.stderr, _('Illegal list name: $s')
+ sys.exit(1)
+ except Errors.EmailAddressError, s:
+ parser.print_help()
+ print >> sys.stderr, _('Bad owner email address: $s')
+ sys.exit(1)
+ except Errors.MMListAlreadyExistsError:
+ parser.print_help()
+ print >> sys.stderr, _('List already exists: $listname')
+ sys.exit(1)
mlist.Save()
finally:
mlist.Unlock()
diff --git a/Mailman/bin/nightly_gzip.py b/Mailman/bin/nightly_gzip.py
index f55b21493..4bd9271bc 100644
--- a/Mailman/bin/nightly_gzip.py
+++ b/Mailman/bin/nightly_gzip.py
@@ -1,6 +1,4 @@
-#! @PYTHON@
-#
-# Copyright (C) 1998-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2007 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
@@ -31,6 +29,7 @@ from Mailman import Utils
from Mailman import Version
from Mailman.configuration import config
from Mailman.i18n import _
+from Mailman.initialize import initialize
__i18n_templates__ = True
@@ -77,7 +76,7 @@ def compress(txtfile, opts):
def main():
opts, args, parser = parseargs()
- config.load(opts.config)
+ initialize(opts.config)
if config.ARCHIVE_TO_MBOX not in (1, 2) or config.GZIP_ARCHIVE_TXT_FILES:
# We're only going to run the nightly archiver if messages are
@@ -119,12 +118,3 @@ def main():
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/update.py b/Mailman/bin/update.py
index b6953e007..281f40420 100644
--- a/Mailman/bin/update.py
+++ b/Mailman/bin/update.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2007 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
@@ -255,9 +255,7 @@ def dolist(listname):
o_html_dir = makeabs('public_html/archives/%s' % (listname))
# Make the mbox directory if it's not there.
if not os.path.exists(mbox_dir):
- ou = os.umask(0)
- os.mkdir(mbox_dir, 02775)
- os.umask(ou)
+ Utils.makedirs(mbox_dir)
else:
# This shouldn't happen, but hey, just in case
if not os.path.isdir(mbox_dir):
@@ -265,9 +263,7 @@ def dolist(listname):
For some reason, $mbox_dir exists as a file. This won't work with b6, so I'm
renaming it to ${mbox_dir}.tmp and proceeding.""")
os.rename(mbox_dir, "%s.tmp" % (mbox_dir))
- ou = os.umask(0)
- os.mkdir(mbox_dir, 02775)
- os.umask(ou)
+ Utils.makedirs(mbox_dir)
# Move any existing mboxes around, but watch out for both a public and a
# private one existing
if os.path.isfile(o_pri_mbox_file) and os.path.isfile(o_pub_mbox_file):
diff --git a/Mailman/database/__init__.py b/Mailman/database/__init__.py
index a2b6c97ce..808ad9fd0 100644
--- a/Mailman/database/__init__.py
+++ b/Mailman/database/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2007 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
@@ -22,12 +22,23 @@
# from Mailman import database
# database.add_list(foo)
+import os
+
def initialize():
from Mailman import database
+ from Mailman.LockFile import LockFile
+ from Mailman.configuration import config
from Mailman.database.dbcontext import dbcontext
-
- dbcontext.connect()
+ # Serialize this so we don't get multiple processes trying to create the
+ # database at the same time.
+ lockfile = os.path.join(config.LOCK_DIR, '<dbcreatelock>')
+ lock = LockFile(lockfile)
+ lock.lock()
+ try:
+ dbcontext.connect()
+ finally:
+ lock.unlock()
for attr in dir(dbcontext):
if attr.startswith('api_'):
exposed_name = attr[4:]
diff --git a/Mailman/database/dbcontext.py b/Mailman/database/dbcontext.py
index a13f20498..b2b1fb826 100644
--- a/Mailman/database/dbcontext.py
+++ b/Mailman/database/dbcontext.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2007 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
@@ -15,10 +15,12 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
+import os
import weakref
from sqlalchemy import *
from string import Template
+from urlparse import urlparse
from Mailman import Version
from Mailman.configuration import config
@@ -49,6 +51,21 @@ class DBContext(object):
# Calculate the engine url
url = Template(config.SQLALCHEMY_ENGINE_URL).safe_substitute(
config.paths)
+ # XXX By design of SQLite, database file creation does not honor
+ # umask. See their ticket #1193:
+ # http://www.sqlite.org/cvstrac/tktview?tn=1193,31
+ #
+ # This sucks for us because the mailman.db file /must/ be group
+ # writable, however even though we guarantee our umask is 002 here, it
+ # still gets created without the necessary g+w permission, due to
+ # SQLite's policy. This should only affect SQLite engines because its
+ # the only one that creates a little file on the local file system.
+ # This kludges around their bug by "touch"ing the database file before
+ # SQLite has any chance to create it, thus honoring the umask and
+ # ensuring the right permissions. We only try to do this for SQLite
+ # engines, and yes, we could have chmod'd the file after the fact, but
+ # half dozen and all...
+ self._touch(url)
self.metadata = BoundMetaData(url)
self.metadata.engine.echo = config.SQLALCHEMY_ECHO
# Create all the table objects, and then let SA conditionally create
@@ -74,6 +91,17 @@ class DBContext(object):
raise SchemaVersionMismatchError(row.version)
self.session = create_session()
+ def _touch(self, url):
+ parts = urlparse(url)
+ # XXX Python 2.5; use parts.scheme and parts.path
+ if parts[0] <> 'sqlite':
+ return
+ path = os.path.normpath(parts[2])
+ fd = os.open(path, os.O_WRONLY | os.O_NONBLOCK | os.O_CREAT, 0666)
+ # Ignore errors
+ if fd > 0:
+ os.close(fd)
+
# Cooperative method for use with @txn decorator
def _withtxn(self, meth, *args, **kws):
try:
diff --git a/Mailman/initialize.py b/Mailman/initialize.py
index db26d15df..ddd4b1c3e 100644
--- a/Mailman/initialize.py
+++ b/Mailman/initialize.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006 by the Free Software Foundation, Inc.
+# Copyright (C) 2006-2007 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
@@ -24,6 +24,8 @@ line argument parsing, since some of the initialization behavior is controlled
by the command line arguments.
"""
+import os
+
import Mailman.configuration
import Mailman.database
import Mailman.loginit
@@ -31,6 +33,13 @@ import Mailman.loginit
def initialize(config=None, propagate_logs=False):
+ # By default, set the umask so that only owner and group can read and
+ # write our files. Specifically we must have g+rw and we probably want
+ # o-rwx although I think in most cases it doesn't hurt if other can read
+ # or write the files. Note that the Pipermail archive has more
+ # restrictive permissions in order to handle private archives, but it
+ # handles that correctly.
+ os.umask(007)
Mailman.configuration.config.load(config)
Mailman.loginit.initialize(propagate_logs)
Mailman.database.initialize()