diff -r eab6243607cb -r 5443cb9b550a mailman/mailman.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mailman/mailman.patch Wed Dec 17 15:02:08 2008 +0100
@@ -0,0 +1,247 @@
+Index: Mailman/Archiver/pipermail.py
+--- Mailman/Archiver/pipermail.py.orig 2008-06-30 18:29:46 +0200
++++ Mailman/Archiver/pipermail.py 2008-07-01 20:48:10 +0200
+@@ -122,9 +122,9 @@
+ parentID = article.parentID
+ if parentID is not None and self.articleIndex.has_key(parentID):
+ parent = self.getArticle(archive, parentID)
+- myThreadKey = parent.threadKey + article.date + '-'
++ myThreadKey = parent.threadKey + article.date + '/' + article.msgid + '-'
+ else:
+- myThreadKey = article.date + '-'
++ myThreadKey = article.date + '/' + article.msgid + '-'
+ article.threadKey = myThreadKey
+ key = myThreadKey, article.msgid
+ self.setThreadKey(archive, key, article.msgid)
+@@ -418,7 +418,7 @@
+ else:
+ parent = self.database.getArticle(self.archive,
+ article.parentID)
+- article.threadKey = parent.threadKey+article.date+'-'
++ article.threadKey = parent.threadKey + article.date + '/' + article.msgid + '-'
+ self.database.setThreadKey(self.archive,
+ (article.threadKey, article.msgid),
+ msgid)
+@@ -632,9 +632,9 @@
+ article.parentID = parentID = self.get_parent_info(arch, article)
+ if parentID:
+ parent = self.database.getArticle(arch, parentID)
+- article.threadKey = parent.threadKey + article.date + '-'
++ article.threadKey = parent.threadKey + article.date + '/' + article.msgid + '-'
+ else:
+- article.threadKey = article.date + '-'
++ article.threadKey = article.date + '/' + article.msgid + '-'
+ key = article.threadKey, article.msgid
+
+ self.database.setThreadKey(arch, key, article.msgid)
+Index: Mailman/Commands/cmd_subscribe.py
+--- Mailman/Commands/cmd_subscribe.py.orig 2008-06-30 18:29:46 +0200
++++ Mailman/Commands/cmd_subscribe.py 2008-07-01 20:48:10 +0200
+@@ -84,6 +84,7 @@
+ if password is None:
+ password = Utils.MakeRandomPassword()
+ if address is None:
++ h = None
+ realname, address = parseaddr(res.msg['from'])
+ if not address:
+ # Fall back to the sender address
+Index: Mailman/HTMLFormatter.py
+--- Mailman/HTMLFormatter.py.orig 2008-06-30 18:29:46 +0200
++++ Mailman/HTMLFormatter.py 2008-07-01 20:48:10 +0200
+@@ -44,7 +44,7 @@
+ realname = self.real_name
+ hostname = self.host_name
+ listinfo_link = Link(self.GetScriptURL('listinfo'), realname).Format()
+- owner_link = Link('mailto:' + self.GetOwnerEmail(), ownertext).Format()
++ owner_link = Link('mailto:' + self.GetOwnerEmail(), realname + '-owner').Format()
+ innertext = _('%(listinfo_link)s list run by %(owner_link)s')
+ return Container(
+ '
',
+Index: Mailman/Handlers/Decorate.py
+--- Mailman/Handlers/Decorate.py.orig 2008-06-30 18:29:46 +0200
++++ Mailman/Handlers/Decorate.py 2008-07-01 20:48:10 +0200
+@@ -197,6 +197,7 @@
+ del msg['content-transfer-encoding']
+ del msg['content-disposition']
+ msg['Content-Type'] = 'multipart/mixed'
++ msg['Mime-version'] = '1.0'
+
+
+
+Index: Mailman/Handlers/Scrubber.py
+--- Mailman/Handlers/Scrubber.py.orig 2008-06-30 18:29:46 +0200
++++ Mailman/Handlers/Scrubber.py 2008-07-01 20:48:10 +0200
+@@ -385,6 +385,8 @@
+ t = unicode(t, 'ascii', 'replace')
+ try:
+ # Should use HTML-Escape, or try generalizing to UTF-8
++ if len(charset) == 0:
++ charset = 'us-ascii'
+ t = t.encode(charset, 'replace')
+ except (UnicodeError, LookupError, ValueError,
+ AssertionError):
+Index: Mailman/Queue/OutgoingRunner.py
+--- Mailman/Queue/OutgoingRunner.py.orig 2008-06-30 18:29:46 +0200
++++ Mailman/Queue/OutgoingRunner.py 2008-07-01 20:48:10 +0200
+@@ -89,6 +89,7 @@
+ syslog('error', 'Cannot connect to SMTP server %s on port %s',
+ mm_cfg.SMTPHOST, port)
+ self.__logged = True
++ self._snooze(0)
+ return True
+ except Errors.SomeRecipientsFailed, e:
+ # Handle local rejects of probe messages differently.
+Index: Mailman/htmlformat.py
+--- Mailman/htmlformat.py.orig 2008-06-30 18:29:46 +0200
++++ Mailman/htmlformat.py 2008-07-01 20:48:10 +0200
+@@ -300,7 +300,8 @@
+ charset = 'us-ascii'
+ if self.language:
+ charset = Utils.GetCharSet(self.language)
+- output = ['Content-Type: text/html; charset=%s\n' % charset]
++ output = ['Content-Type: text/html; charset=%s' % charset]
++ output.append('Cache-control: no-cache\n')
+ if not self.suppress_head:
+ kws.setdefault('bgcolor', self.bgcolor)
+ tab = ' ' * indent
+Index: bin/check_perms
+--- bin/check_perms.orig 2008-06-30 18:29:46 +0200
++++ bin/check_perms 2008-07-01 20:48:10 +0200
+@@ -82,7 +82,7 @@
+ return os.stat(path)[ST_MODE]
+
+ def statgidmode(path):
+- stat = os.stat(path)
++ stat = os.lstat(path)
+ return stat[ST_MODE], stat[ST_GID]
+
+ seen = {}
+Index: bin/config_list
+--- bin/config_list.orig 2008-06-30 18:29:46 +0200
++++ bin/config_list 2008-07-01 20:48:10 +0200
+@@ -307,6 +307,11 @@
+ in mm_cfg.OPTINFO.items()
+ if validval & bitval]
+ gui._setValue(mlist, k, validval, fakedoc)
++ # Ugly hack, but seems to be needed since
++ # new_member_options isn't really a number in gui.
++ # -- tfheen, 2003-12-06
++ if k == "new_member_options":
++ mlist.new_member_options = validval
+ # BAW: when to do gui._postValidate()???
+ finally:
+ if savelist and not checkonly:
+Index: bin/mailmanctl
+--- bin/mailmanctl.orig 2008-06-30 18:29:46 +0200
++++ bin/mailmanctl 2008-07-01 20:48:10 +0200
+@@ -417,6 +417,13 @@
+ # 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()
++
++ # Be sure to close any open std{in,out,err}
++ devnull = os.open('/dev/null', 0)
++ os.dup2(devnull, 0)
++ os.dup2(devnull, 1)
++ os.dup2(devnull, 2)
++
+ # Instead of cd'ing to root, cd to the Mailman installation home
+ os.chdir(mm_cfg.PREFIX)
+ # Set our file mode creation umask
+Index: bin/newlist
+--- bin/newlist.orig 2008-06-30 18:29:46 +0200
++++ bin/newlist 2008-07-01 20:48:10 +0200
+@@ -87,6 +87,9 @@
+ defined in your Defaults.py file or overridden by settings in mm_cfg.py).
+
+ Note that listnames are forced to lowercase.
++
++The list admin address need to be a fully-qualified address, like
++owner@example.com, not just owner.
+ """
+
+ import sys
+@@ -94,6 +97,7 @@
+ import getpass
+ import getopt
+ import sha
++import grp
+
+ import paths
+ from Mailman import mm_cfg
+@@ -122,6 +126,9 @@
+
+
+ def main():
++ gid = grp.getgrnam(mm_cfg.MAILMAN_GROUP)[2]
++ if os.getgid() != mm_cfg.MAILMAN_GROUP:
++ os.setgid(gid)
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'hql:u:e:',
+ ['help', 'quiet', 'language=',
+@@ -203,7 +210,7 @@
+ except Errors.BadListNameError, s:
+ usage(1, _('Illegal list name: %(s)s'))
+ except Errors.EmailAddressError, s:
+- usage(1, _('Bad owner email address: %(s)s'))
++ usage(1, _('Bad owner email address: %(s)s. Owner addresses need to be fully-qualified names, like "owner@example.com", not just "owner".'))
+ except Errors.MMListAlreadyExistsError:
+ usage(1, _('List already exists: %(listname)s'))
+
+Index: bin/update
+--- bin/update.orig 2008-06-30 18:29:46 +0200
++++ bin/update 2008-07-01 20:48:10 +0200
+@@ -552,9 +552,11 @@
+ file20 = os.path.join(mm_cfg.DATA_DIR, 'pending_subscriptions.db')
+ file214 = os.path.join(mm_cfg.DATA_DIR, 'pending.pck')
+ db = None
++ ver = None
+ # Try to load the Mailman 2.0 file
+ try:
+ fp = open(file20)
++ ver = "20"
+ except IOError, e:
+ if e.errno <> errno.ENOENT: raise
+ else:
+@@ -566,6 +568,7 @@
+ # Try to load the Mailman 2.1.x where x < 5, file
+ try:
+ fp = open(file214)
++ ver = "214"
+ except IOError, e:
+ if e.errno <> errno.ENOENT: raise
+ else:
+@@ -599,8 +602,12 @@
+ # data[0] is the address being unsubscribed
+ addrops_by_address.setdefault(data[0], []).append((key, val))
+ elif op == Pending.SUBSCRIPTION:
+- # data[0] is a UserDesc object
+- addr = data[0].address
++ if ver == "20":
++ # data is tuple (emailaddr, password, digest)
++ addr = data[0]
++ else:
++ # data[0] is a UserDesc object
++ addr = data[0].address
+ subs_by_address.setdefault(addr, []).append((key, val))
+ elif op == Pending.RE_ENABLE:
+ # data[0] is the mailing list's internal name
+Index: scripts/driver
+--- scripts/driver.orig 2008-06-30 18:29:46 +0200
++++ scripts/driver 2008-07-01 20:48:10 +0200
+@@ -95,6 +95,15 @@
+ module = getattr(pkg, scriptname)
+ main = getattr(module, 'main')
+ try:
++ import os
++ request_method = os.environ.get('REQUEST_METHOD')
++ if not request_method in ['GET', 'POST', 'HEAD']:
++ print "Status: 405 Method not allowed"
++ print "Content-type: text/plain"
++ print
++ print "The method is not allowed"
++ sys.exit()
++
+ try:
+ sys.stderr = logger
+ sys.stdout = tempstdout