aboutsummaryrefslogtreecommitdiffstats
path: root/Mailman
diff options
context:
space:
mode:
Diffstat (limited to 'Mailman')
-rw-r--r--Mailman/Archiver/HyperArch.py11
-rw-r--r--Mailman/Bouncers/Caiwireless.py4
-rw-r--r--Mailman/Bouncers/GroupWise.py4
-rw-r--r--Mailman/Bouncers/Microsoft.py4
-rw-r--r--Mailman/Bouncers/Netscape.py4
-rw-r--r--Mailman/Bouncers/Postfix.py6
-rw-r--r--Mailman/Cgi/admin.py16
-rw-r--r--Mailman/Cgi/admindb.py17
-rw-r--r--Mailman/Cgi/create.py6
-rw-r--r--Mailman/Cgi/edithtml.py2
-rw-r--r--Mailman/Cgi/roster.py14
-rw-r--r--Mailman/Cgi/subscribe.py9
-rw-r--r--Mailman/Defaults.py.in10
-rw-r--r--Mailman/Errors.py28
-rw-r--r--Mailman/Gui/Privacy.py6
-rw-r--r--Mailman/Gui/Topics.py2
-rw-r--r--Mailman/Handlers/Decorate.py14
-rw-r--r--Mailman/Handlers/Scrubber.py13
-rw-r--r--Mailman/Handlers/Tagger.py9
-rw-r--r--Mailman/LockFile.py6
-rw-r--r--Mailman/MailList.py2
-rw-r--r--Mailman/Pending.py6
-rw-r--r--Mailman/Queue/Switchboard.py4
-rw-r--r--Mailman/SecurityManager.py13
-rw-r--r--Mailman/Utils.py24
-rw-r--r--Mailman/Version.py8
26 files changed, 144 insertions, 98 deletions
diff --git a/Mailman/Archiver/HyperArch.py b/Mailman/Archiver/HyperArch.py
index d4fc5d9a..ad51596e 100644
--- a/Mailman/Archiver/HyperArch.py
+++ b/Mailman/Archiver/HyperArch.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2007 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2008 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
@@ -156,7 +156,12 @@ REpat = re.compile( r"\s*RE\s*(\[\d+\]\s*)?:\s*", re.IGNORECASE)
emailpat = re.compile(r'([-+,.\w]+@[-+.\w]+)')
# Argh! This pattern is buggy, and will choke on URLs with GET parameters.
-urlpat = re.compile(r'(\w+://[^>)\s]+)') # URLs in text
+# MAS: Given that people are not constrained in how they write URIs in plain
+# text, it is not possible to have a single regexp to reliably match them.
+# The regexp below is intended to match straightforward cases. Even humans
+# can't reliably tell whether various punctuation at the end of a URI is part
+# of the URI or not.
+urlpat = re.compile(r'([a-z]+://.*?)(?:_\s|_$|$|[]})>\'"\s])', re.IGNORECASE)
# Blank lines
blankpat = re.compile(r'^\s*$')
@@ -574,8 +579,8 @@ class Article(pipermail.Article):
if mm_cfg.ARCHIVER_OBSCURES_EMAILADDRS:
otrans = i18n.get_translation()
try:
- atmark = unicode(_(' at '), cset)
i18n.set_language(self._lang)
+ atmark = unicode(_(' at '), cset)
body = re.sub(r'([-+,.\w]+)@([-+.\w]+)',
'\g<1>' + atmark + '\g<2>', body)
finally:
diff --git a/Mailman/Bouncers/Caiwireless.py b/Mailman/Bouncers/Caiwireless.py
index e2909122..b71b0624 100644
--- a/Mailman/Bouncers/Caiwireless.py
+++ b/Mailman/Bouncers/Caiwireless.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998,1999,2000,2001,2002 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2008 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
@@ -27,7 +27,7 @@ acre = re.compile(r'<(?P<addr>[^>]*)>')
def process(msg):
- if msg.get_type() <> 'multipart/mixed':
+ if msg.get_content_type() <> 'multipart/mixed':
return None
# simple state machine
# 0 == nothing seen
diff --git a/Mailman/Bouncers/GroupWise.py b/Mailman/Bouncers/GroupWise.py
index 74116135..e5122f73 100644
--- a/Mailman/Bouncers/GroupWise.py
+++ b/Mailman/Bouncers/GroupWise.py
@@ -30,7 +30,7 @@ acre = re.compile(r'<(?P<addr>[^>]*)>')
def find_textplain(msg):
- if msg.get_type(msg.get_default_type()) == 'text/plain':
+ if msg.get_content_type() == 'text/plain':
return msg
if msg.is_multipart:
for part in msg.get_payload():
@@ -44,7 +44,7 @@ def find_textplain(msg):
def process(msg):
- if msg.get_type() <> 'multipart/mixed' or not msg['x-mailer']:
+ if msg.get_content_type() <> 'multipart/mixed' or not msg['x-mailer']:
return None
if msg['x-mailer'][:3].lower() not in ('nov', 'ntm', 'int'):
return None
diff --git a/Mailman/Bouncers/Microsoft.py b/Mailman/Bouncers/Microsoft.py
index d8a90b24..fec7cc93 100644
--- a/Mailman/Bouncers/Microsoft.py
+++ b/Mailman/Bouncers/Microsoft.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2003 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2008 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
@@ -25,7 +25,7 @@ scre = re.compile(r'transcript of session follows', re.IGNORECASE)
def process(msg):
- if msg.get_type() <> 'multipart/mixed':
+ if msg.get_content_type() <> 'multipart/mixed':
return None
# Find the first subpart, which has no MIME type
try:
diff --git a/Mailman/Bouncers/Netscape.py b/Mailman/Bouncers/Netscape.py
index f5974602..8c21f629 100644
--- a/Mailman/Bouncers/Netscape.py
+++ b/Mailman/Bouncers/Netscape.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998,1999,2000,2001,2002 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2008 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
@@ -61,7 +61,7 @@ def process(msg):
leaves = []
flatten(msg, leaves)
for i, subpart in zip(range(len(leaves)-1), leaves):
- if subpart.get_type() == 'text/plain':
+ if subpart.get_content_type() == 'text/plain':
plainmsg = subpart
break
if not plainmsg:
diff --git a/Mailman/Bouncers/Postfix.py b/Mailman/Bouncers/Postfix.py
index 1fab8666..3c250e95 100644
--- a/Mailman/Bouncers/Postfix.py
+++ b/Mailman/Bouncers/Postfix.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2003 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2008 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
@@ -71,14 +71,14 @@ def findaddr(msg):
def process(msg):
- if msg.get_type() not in ('multipart/mixed', 'multipart/report'):
+ if msg.get_content_type() not in ('multipart/mixed', 'multipart/report'):
return None
# We're looking for the plain/text subpart with a Content-Description: of
# `notification'.
leaves = []
flatten(msg, leaves)
for subpart in leaves:
- if subpart.get_type() == 'text/plain' and \
+ if subpart.get_content_type() == 'text/plain' and \
subpart.get('content-description', '').lower() == 'notification':
# then...
return findaddr(subpart)
diff --git a/Mailman/Cgi/admin.py b/Mailman/Cgi/admin.py
index a6251058..3d790b2e 100644
--- a/Mailman/Cgi/admin.py
+++ b/Mailman/Cgi/admin.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 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,7 +24,6 @@ import sys
import os
import re
import cgi
-import sha
import urllib
import signal
from types import *
@@ -41,6 +40,7 @@ from Mailman.UserDesc import UserDesc
from Mailman.htmlformat import *
from Mailman.Cgi import Auth
from Mailman.Logging.Syslog import syslog
+from Mailman.Utils import sha_new
# Set up i18n
_ = i18n._
@@ -852,7 +852,8 @@ def membership_options(mlist, subcat, cgidata, doc, form):
container.AddItem(header)
# Add a "search for member" button
table = Table(width='100%')
- link = Link('http://www.python.org/doc/current/lib/re-syntax.html',
+ link = Link('http://docs.python.org/library/re.html'
+ '#regular-expression-syntax',
_('(help)')).Format()
table.AddRow([Label(_('Find member %(link)s:')),
TextBox('findmember',
@@ -940,7 +941,10 @@ def membership_options(mlist, subcat, cgidata, doc, form):
if bucket:
cells = []
for letter in keys:
- url = adminurl + '/members?letter=%s' % letter
+ findfrag = ''
+ if regexp:
+ findfrag = '&findmember=' + urllib.quote(regexp)
+ url = adminurl + '/members?letter=' + letter + findfrag
if letter == bucket:
show = Bold('[%s]' % letter.upper()).Format()
else:
@@ -1269,7 +1273,7 @@ def change_options(mlist, category, subcat, cgidata, doc):
confirm = cgidata.getvalue('confirmmodpw', '').strip()
if new or confirm:
if new == confirm:
- mlist.mod_password = sha.new(new).hexdigest()
+ mlist.mod_password = sha_new(new).hexdigest()
# No re-authentication necessary because the moderator's
# password doesn't get you into these pages.
else:
@@ -1279,7 +1283,7 @@ def change_options(mlist, category, subcat, cgidata, doc):
confirm = cgidata.getvalue('confirmpw', '').strip()
if new or confirm:
if new == confirm:
- mlist.password = sha.new(new).hexdigest()
+ mlist.password = sha_new(new).hexdigest()
# Set new cookie
print mlist.MakeCookie(mm_cfg.AuthListAdmin)
else:
diff --git a/Mailman/Cgi/admindb.py b/Mailman/Cgi/admindb.py
index 75cc66a0..a20763f1 100644
--- a/Mailman/Cgi/admindb.py
+++ b/Mailman/Cgi/admindb.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2007 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 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
@@ -554,12 +554,8 @@ def show_detailed_requests(mlist, form):
def show_post_requests(mlist, id, info, total, count, form):
- # For backwards compatibility with pre 2.0beta3
- if len(info) == 5:
- ptime, sender, subject, reason, filename = info
- msgdata = {}
- else:
- ptime, sender, subject, reason, filename, msgdata = info
+ # Mailman.ListAdmin.__handlepost no longer tests for pre 2.0beta3
+ ptime, sender, subject, reason, filename, msgdata = info
form.AddItem('<hr>')
# Header shown on each held posting (including count of total)
msg = _('Posting Held for Approval')
@@ -709,10 +705,12 @@ def process_form(mlist, doc, cgidata):
preserve = actions.get('senderpreserve', 0)
forward = actions.get('senderforward', 0)
forwardaddr = actions.get('senderforwardto', '')
- comment = _('No reason given')
bysender = helds_by_sender(mlist)
for id in bysender.get(sender, []):
try:
+ msgdata = mlist.GetRecord(id)[5]
+ comment = msgdata.get('rejection_notice',
+ _('[No explanation given]'))
mlist.HandleRequest(id, action, comment, preserve,
forward, forwardaddr)
except (KeyError, Errors.LostHeldMessage):
@@ -771,7 +769,8 @@ def process_form(mlist, doc, cgidata):
forwardaddrkey = 'forward-addr-%d' % request_id
bankey = 'ban-%d' % request_id
# Defaults
- comment = _('[No reason given]')
+ msgdata = mlist.GetRecord(request_id)[5]
+ comment = msgdata.get('rejection_notice', _('[No explanation given]'))
preserve = 0
forward = 0
forwardaddr = ''
diff --git a/Mailman/Cgi/create.py b/Mailman/Cgi/create.py
index 55ec2887..7e21b981 100644
--- a/Mailman/Cgi/create.py
+++ b/Mailman/Cgi/create.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2007 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2008 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
@@ -21,7 +21,6 @@ import sys
import os
import signal
import cgi
-import sha
from types import ListType
from Mailman import mm_cfg
@@ -31,6 +30,7 @@ from Mailman import Errors
from Mailman import i18n
from Mailman.htmlformat import *
from Mailman.Logging.Syslog import syslog
+from Mailman.Utils import sha_new
# Set up i18n
_ = i18n._
@@ -180,7 +180,7 @@ def process_request(doc, cgidata):
# Install the emergency shutdown signal handler
signal.signal(signal.SIGTERM, sigterm_handler)
- pw = sha.new(password).hexdigest()
+ 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
diff --git a/Mailman/Cgi/edithtml.py b/Mailman/Cgi/edithtml.py
index 3aa8ab4e..0e34a1c7 100644
--- a/Mailman/Cgi/edithtml.py
+++ b/Mailman/Cgi/edithtml.py
@@ -168,7 +168,7 @@ must have shell access to your Mailman server.
""")))
doc.AddItem(_('See '))
doc.AddItem(Link(
-'http://www.python.org/cgi-bin/faqw-mm.py?req=show&file=faq04.048.htp',
+'http://wiki.list.org/x/jYA9',
_('FAQ 4.48.')))
doc.AddItem(Header(3,_("Page Unchanged.")))
doc.AddItem('<hr>')
diff --git a/Mailman/Cgi/roster.py b/Mailman/Cgi/roster.py
index b53e5912..8d06777d 100644
--- a/Mailman/Cgi/roster.py
+++ b/Mailman/Cgi/roster.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2007 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2008 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
@@ -72,16 +72,18 @@ def main():
# that, we check roster-email and roster-pw fields for a valid password.
# (also allowed: the list moderator, the list admin, and the site admin).
password = cgidata.getvalue('roster-pw', '')
- list_hidden = mlist.WebAuthenticate((mm_cfg.AuthListModerator,
- mm_cfg.AuthListAdmin,
- mm_cfg.AuthSiteAdmin),
- password)
+ addr = cgidata.getvalue('roster-email', '')
+ list_hidden = (not mlist.WebAuthenticate((mm_cfg.AuthUser,),
+ password, addr)
+ and mlist.WebAuthenticate((mm_cfg.AuthListModerator,
+ mm_cfg.AuthListAdmin,
+ mm_cfg.AuthSiteAdmin),
+ password))
if mlist.private_roster == 0:
# No privacy
ok = 1
elif mlist.private_roster == 1:
# Members only
- addr = cgidata.getvalue('roster-email', '')
ok = mlist.WebAuthenticate((mm_cfg.AuthUser,
mm_cfg.AuthListModerator,
mm_cfg.AuthListAdmin,
diff --git a/Mailman/Cgi/subscribe.py b/Mailman/Cgi/subscribe.py
index 3661dcde..80019581 100644
--- a/Mailman/Cgi/subscribe.py
+++ b/Mailman/Cgi/subscribe.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2003 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 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.
"""Process subscription or roster requests from listinfo form."""
@@ -204,8 +205,8 @@ your subscription.""")
if privacy_results:
results = privacy_results
else:
- # We need to interpolate into x
- x = _(x)
+ # We need to interpolate into x.__str__()
+ x = _(str(x))
results = _("""\
Your subscription request was deferred because %(x)s. Your request has been
forwarded to the list moderator. You will receive email informing you of the
diff --git a/Mailman/Defaults.py.in b/Mailman/Defaults.py.in
index fcf474a5..a10e2976 100644
--- a/Mailman/Defaults.py.in
+++ b/Mailman/Defaults.py.in
@@ -1090,10 +1090,14 @@ MIME_DIGEST_KEEP_HEADERS = [
'Message',
]
+# The order in this list controls the order of the RFC 1153 digest headers.
+# Also, any headers in this list will be kept in the MIME digest even if they
+# don't appear in the MIME list above. Finally, headers appearing in both
+# lists must be casewise the same or duplication can result in the digest.
PLAIN_DIGEST_KEEP_HEADERS = [
- 'Message', 'Date', 'From',
- 'Subject', 'To', 'Cc',
- 'Message-ID', 'Keywords',
+ 'Message',
+ # RFC 1153 headers in order
+ 'Date', 'From', 'To', 'Cc', 'Subject', 'Message-ID', 'Keywords',
'Content-Type',
]
diff --git a/Mailman/Errors.py b/Mailman/Errors.py
index 2e80f21a..d4af216e 100644
--- a/Mailman/Errors.py
+++ b/Mailman/Errors.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2003 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 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.
"""Shared mailman errors and messages."""
@@ -49,14 +50,21 @@ class MMCookieError(MMAuthenticationError): pass
class MMExpiredCookieError(MMCookieError): pass
class MMInvalidCookieError(MMCookieError): pass
-# BAW: these still need to be converted to classes.
-MMMustDigestError = "MMMustDigestError"
-MMCantDigestError = "MMCantDigestError"
-MMNeedApproval = "MMNeedApproval"
-MMSubscribeNeedsConfirmation = "MMSubscribeNeedsConfirmation"
-MMBadConfirmation = "MMBadConfirmation"
-MMAlreadyDigested = "MMAlreadyDigested"
-MMAlreadyUndigested = "MMAlreadyUndigested"
+class MMMustDigestError: pass
+class MMCantDigestError: pass
+class MMNeedApproval:
+ def __init__(self, message=None):
+ self.message = message
+ def __str__(self):
+ return self.message or ''
+class MMSubscribeNeedsConfirmation: pass
+class MMBadConfirmation:
+ def __init__(self, message=None):
+ self.message = message
+ def __str__(self):
+ return self.message or ''
+class MMAlreadyDigested: pass
+class MMAlreadyUndigested: pass
MODERATED_LIST_MSG = "Moderated list"
IMPLICIT_DEST_MSG = "Implicit destination"
diff --git a/Mailman/Gui/Privacy.py b/Mailman/Gui/Privacy.py
index 635fef52..75eff2b5 100644
--- a/Mailman/Gui/Privacy.py
+++ b/Mailman/Gui/Privacy.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2007 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2008 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
@@ -160,7 +160,7 @@ class Privacy(GUIBase):
adminurl = mlist.GetScriptURL('admin', absolute=1)
sender_rtn = [
_("""When a message is posted to the list, a series of
- moderation steps are take to decide whether the a moderator must
+ moderation steps are taken to decide whether a moderator must
first approve the message or not. This section contains the
controls for moderation of both member and non-member postings.
@@ -185,7 +185,7 @@ class Privacy(GUIBase):
<p>In the text boxes below, add one address per line; start the
line with a ^ character to designate a <a href=
- "http://www.python.org/doc/current/lib/module-re.html"
+ "http://docs.python.org/library/re.html"
>Python regular expression</a>. When entering backslashes, do so
as if you were using Python raw strings (i.e. you generally just
use a single backslash).
diff --git a/Mailman/Gui/Topics.py b/Mailman/Gui/Topics.py
index a912f3c0..14fac968 100644
--- a/Mailman/Gui/Topics.py
+++ b/Mailman/Gui/Topics.py
@@ -48,7 +48,7 @@ class Topics(GUIBase):
_("""The topic filter categorizes each incoming email message
according to <a
- href="http://www.python.org/doc/current/lib/module-re.html">regular
+ href="http://docs.python.org/library/re.html">regular
expression filters</a> you specify below. If the message's
<code>Subject:</code> or <code>Keywords:</code> header contains a
match against a topic filter, the message is logically placed
diff --git a/Mailman/Handlers/Decorate.py b/Mailman/Handlers/Decorate.py
index 81bf7d33..4a6fb8aa 100644
--- a/Mailman/Handlers/Decorate.py
+++ b/Mailman/Handlers/Decorate.py
@@ -98,8 +98,16 @@ def process(mlist, msg, msgdata):
# TK: Try to keep the message plain by converting the header/
# footer/oldpayload into unicode and encode with mcset/lcset.
# Try to decode qp/base64 also.
- uheader = unicode(header, lcset, 'ignore')
- ufooter = unicode(footer, lcset, 'ignore')
+ # It is possible header/footer is already unicode if it was
+ # interpolated with a unicode.
+ if isinstance(header, unicode):
+ uheader = header
+ else:
+ uheader = unicode(header, lcset, 'ignore')
+ if isinstance(footer, unicode):
+ ufooter = footer
+ else:
+ ufooter = unicode(footer, lcset, 'ignore')
try:
oldpayload = unicode(msg.get_payload(decode=True), mcset)
frontsep = endsep = u''
@@ -130,7 +138,7 @@ def process(mlist, msg, msgdata):
wrap = False
except (LookupError, UnicodeError):
pass
- elif msg.get_type() == 'multipart/mixed':
+ elif msg.get_content_type() == 'multipart/mixed':
# The next easiest thing to do is just prepend the header and append
# the footer as additional subparts
payload = msg.get_payload()
diff --git a/Mailman/Handlers/Scrubber.py b/Mailman/Handlers/Scrubber.py
index 1d5aed92..64b46eaf 100644
--- a/Mailman/Handlers/Scrubber.py
+++ b/Mailman/Handlers/Scrubber.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2007 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2009 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
@@ -21,7 +21,6 @@ from __future__ import nested_scopes
import os
import re
-import sha
import time
import errno
import binascii
@@ -41,6 +40,7 @@ from Mailman import Message
from Mailman.Errors import DiscardMessage
from Mailman.i18n import _
from Mailman.Logging.Syslog import syslog
+from Mailman.Utils import sha_new
# Path characters for common platforms
pre = re.compile(r'[/\\:]')
@@ -158,7 +158,7 @@ def calculate_attachments_dir(mlist, msg, msgdata):
if msgid is None:
msgid = msg['Message-ID'] = Utils.unique_message_id(mlist)
# We assume that the message id actually /is/ unique!
- digest = sha.new(msgid).hexdigest()
+ digest = sha_new(msgid).hexdigest()
return os.path.join('attachments', datedir, digest[:4] + digest[-4:])
@@ -167,6 +167,9 @@ def replace_payload_by_text(msg, text, charset):
# message by a text (scrubbing).
del msg['content-type']
del msg['content-transfer-encoding']
+ if isinstance(charset, unicode):
+ # email 3.0.1 (python 2.4) doesn't like unicode
+ charset = charset.encode('us-ascii')
msg.set_payload(text, charset)
@@ -189,7 +192,7 @@ def process(mlist, msg, msgdata=None):
# Now walk over all subparts of this message and scrub out various types
format = delsp = None
for part in msg.walk():
- ctype = part.get_type(part.get_default_type())
+ ctype = part.get_content_type()
# If the part is text/plain, we leave it alone
if ctype == 'text/plain':
# We need to choose a charset for the scrubbed message, so we'll
@@ -300,7 +303,7 @@ URL: %(url)s
# will transform the url into a hyperlink.
elif part.get_payload() and not part.is_multipart():
payload = part.get_payload(decode=True)
- ctype = part.get_type()
+ ctype = part.get_content_type()
# XXX Under email 2.5, it is possible that payload will be None.
# This can happen when you have a Content-Type: multipart/* with
# only one part and that part has two blank lines between the
diff --git a/Mailman/Handlers/Tagger.py b/Mailman/Handlers/Tagger.py
index 65ead7f6..0d3ce497 100644
--- a/Mailman/Handlers/Tagger.py
+++ b/Mailman/Handlers/Tagger.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001,2002 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2008 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
@@ -69,11 +69,12 @@ def scanbody(msg, numlines=None):
# or if the outer type is multipart/alternative and there is a text/plain
# part. Anything else, and the body is ignored for header-scan purposes.
found = None
- if msg.get_type('text/plain') == 'text/plain':
+ if msg.get_content_type() == 'text/plain':
found = msg
- elif msg.is_multipart() and msg.get_type() == 'multipart/alternative':
+ elif (msg.is_multipart() and
+ msg.get_content_type() == 'multipart/alternative'):
for found in msg.get_payload():
- if found.get_type('text/plain') == 'text/plain':
+ if found.get_content_type() == 'text/plain':
break
else:
found = None
diff --git a/Mailman/LockFile.py b/Mailman/LockFile.py
index 9b5b05f0..195615e6 100644
--- a/Mailman/LockFile.py
+++ b/Mailman/LockFile.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2003 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2008 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
@@ -546,8 +546,8 @@ def _seed():
except EnvironmentError, e:
if e.errno <> errno.ENOENT:
raise
- import sha
- d = sha.new(`os.getpid()`+`time.time()`).hexdigest()
+ from Mailman.Utils import sha_new
+ d = sha_new(`os.getpid()`+`time.time()`).hexdigest()
random.seed(d)
diff --git a/Mailman/MailList.py b/Mailman/MailList.py
index ac2d1baf..674017d1 100644
--- a/Mailman/MailList.py
+++ b/Mailman/MailList.py
@@ -491,7 +491,7 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
postingaddr = '%s@%s' % (name, emailhost)
try:
Utils.ValidateEmail(postingaddr)
- except Errors.MMBadEmailError:
+ except Errors.EmailAddressError:
raise Errors.BadListNameError, postingaddr
# Validate the admin's email address
Utils.ValidateEmail(admin)
diff --git a/Mailman/Pending.py b/Mailman/Pending.py
index 224565b5..e6372eda 100644
--- a/Mailman/Pending.py
+++ b/Mailman/Pending.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2004 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2008 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,13 +17,13 @@
"""Track pending actions which require confirmation."""
import os
-import sha
import time
import errno
import random
import cPickle
from Mailman import mm_cfg
+from Mailman.Utils import sha_new
# Types of pending records
SUBSCRIPTION = 'S'
@@ -72,7 +72,7 @@ class Pending:
while True:
now = time.time()
x = random.random() + now % 1.0 + time.clock() % 1.0
- cookie = sha.new(repr(x)).hexdigest()
+ cookie = sha_new(repr(x)).hexdigest()
# We'll never get a duplicate, but we'll be anal about checking
# anyway.
if not db.has_key(cookie):
diff --git a/Mailman/Queue/Switchboard.py b/Mailman/Queue/Switchboard.py
index 94b8efa0..bd1cd357 100644
--- a/Mailman/Queue/Switchboard.py
+++ b/Mailman/Queue/Switchboard.py
@@ -35,7 +35,6 @@
# needs.
import os
-import sha
import time
import email
import errno
@@ -46,6 +45,7 @@ from Mailman import mm_cfg
from Mailman import Utils
from Mailman import Message
from Mailman.Logging.Syslog import syslog
+from Mailman.Utils import sha_new
# 20 bytes of all bits set, maximum sha.digest() value
shamax = 0xffffffffffffffffffffffffffffffffffffffffL
@@ -118,7 +118,7 @@ class Switchboard:
# this system) and the sha hex digest.
#rcvtime = data.setdefault('received_time', now)
rcvtime = data.setdefault('received_time', now)
- filebase = `rcvtime` + '+' + sha.new(hashfood).hexdigest()
+ filebase = `rcvtime` + '+' + sha_new(hashfood).hexdigest()
filename = os.path.join(self.__whichq, filebase + '.pck')
tmpfile = filename + '.tmp'
# Always add the metadata schema version number
diff --git a/Mailman/SecurityManager.py b/Mailman/SecurityManager.py
index 572018e2..fc2ffd92 100644
--- a/Mailman/SecurityManager.py
+++ b/Mailman/SecurityManager.py
@@ -49,7 +49,6 @@
import os
import re
-import sha
import time
import Cookie
import marshal
@@ -62,12 +61,12 @@ try:
import crypt
except ImportError:
crypt = None
-import md5
from Mailman import mm_cfg
from Mailman import Utils
from Mailman import Errors
from Mailman.Logging.Syslog import syslog
+from Mailman.Utils import md5_new, sha_new
try:
True, False
@@ -171,11 +170,11 @@ class SecurityManager:
key, secret = self.AuthContextInfo(ac)
if secret is None:
continue
- sharesponse = sha.new(response).hexdigest()
+ sharesponse = sha_new(response).hexdigest()
upgrade = ok = False
if sharesponse == secret:
ok = True
- elif md5.new(response).digest() == secret:
+ elif md5_new(response).digest() == secret:
ok = upgrade = True
elif cryptmatchp(response, secret):
ok = upgrade = True
@@ -196,7 +195,7 @@ class SecurityManager:
elif ac == mm_cfg.AuthListModerator:
# The list moderator password must be sha'd
key, secret = self.AuthContextInfo(ac)
- if secret and sha.new(response).hexdigest() == secret:
+ if secret and sha_new(response).hexdigest() == secret:
return ac
elif ac == mm_cfg.AuthUser:
if user is not None:
@@ -237,7 +236,7 @@ class SecurityManager:
# Timestamp
issued = int(time.time())
# Get a digest of the secret, plus other information.
- mac = sha.new(secret + `issued`).hexdigest()
+ mac = sha_new(secret + `issued`).hexdigest()
# Create the cookie object.
c = Cookie.SimpleCookie()
c[key] = binascii.hexlify(marshal.dumps((issued, mac)))
@@ -337,7 +336,7 @@ class SecurityManager:
return False
# Calculate what the mac ought to be based on the cookie's timestamp
# and the shared secret.
- mac = sha.new(secret + `issued`).hexdigest()
+ mac = sha_new(secret + `issued`).hexdigest()
if mac <> received_mac:
return False
# Authenticated!
diff --git a/Mailman/Utils.py b/Mailman/Utils.py
index cd9faa41..847d1a82 100644
--- a/Mailman/Utils.py
+++ b/Mailman/Utils.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2008 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2009 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
@@ -27,9 +27,9 @@ the mailing lists, and whatever else doesn't belong elsewhere.
from __future__ import nested_scopes
import os
+import sys
import re
import cgi
-import sha
import time
import errno
import base64
@@ -56,6 +56,16 @@ from Mailman.SafeDict import SafeDict
from Mailman.Logging.Syslog import syslog
try:
+ import hashlib
+ md5_new = hashlib.md5
+ sha_new = hashlib.sha1
+except ImportError:
+ import md5
+ import sha
+ md5_new = md5.new
+ sha_new = sha.new
+
+try:
True, False
except NameError:
True = 1
@@ -256,7 +266,7 @@ def ScriptURL(target, web_page_url=None, absolute=False):
fullpath = os.environ.get('SCRIPT_NAME', '') + \
os.environ.get('PATH_INFO', '')
baseurl = urlparse.urlparse(web_page_url)[2]
- if not absolute and fullpath.endswith(baseurl):
+ if not absolute and fullpath.startswith(baseurl):
# Use relative addressing
fullpath = fullpath[len(baseurl):]
i = fullpath.find('?')
@@ -384,7 +394,7 @@ def set_global_password(pw, siteadmin=True):
omask = os.umask(026)
try:
fp = open(filename, 'w')
- fp.write(sha.new(pw).hexdigest() + '\n')
+ fp.write(sha_new(pw).hexdigest() + '\n')
fp.close()
finally:
os.umask(omask)
@@ -410,7 +420,7 @@ def check_global_password(response, siteadmin=True):
challenge = get_global_password(siteadmin)
if challenge is None:
return None
- return challenge == sha.new(response).hexdigest()
+ return challenge == sha_new(response).hexdigest()
@@ -895,7 +905,8 @@ def oneline(s, cset):
# Many thanks are due to Moritz Naumann for his assistance with this.
_badwords = [
'<i?frame',
- '<link',
+ # Kludge to allow the specific tag that's in the options.html template.
+ '<link(?! rel="SHORTCUT ICON" href="<mm-favicon>">)',
'<meta',
'<script',
r'(?:^|\W)j(?:ava)?script(?:\W|$)',
@@ -1034,3 +1045,4 @@ def suspiciousHTML(html):
return True
else:
return False
+
diff --git a/Mailman/Version.py b/Mailman/Version.py
index 4a559213..5bfcf8d3 100644
--- a/Mailman/Version.py
+++ b/Mailman/Version.py
@@ -16,7 +16,7 @@
# USA.
# Mailman version
-VERSION = '2.1.11'
+VERSION = '2.1.12rc1'
# And as a hex number in the manner of PY_VERSION_HEX
ALPHA = 0xa
@@ -28,10 +28,10 @@ FINAL = 0xf
MAJOR_REV = 2
MINOR_REV = 1
-MICRO_REV = 11
-REL_LEVEL = FINAL
+MICRO_REV = 12
+REL_LEVEL = GAMMA
# at most 15 beta releases!
-REL_SERIAL = 0
+REL_SERIAL = 1
HEX_VERSION = ((MAJOR_REV << 24) | (MINOR_REV << 16) | (MICRO_REV << 8) |
(REL_LEVEL << 4) | (REL_SERIAL << 0))