diff options
Diffstat (limited to 'Mailman')
-rw-r--r-- | Mailman/Archiver/HyperArch.py | 11 | ||||
-rw-r--r-- | Mailman/Bouncers/Caiwireless.py | 4 | ||||
-rw-r--r-- | Mailman/Bouncers/GroupWise.py | 4 | ||||
-rw-r--r-- | Mailman/Bouncers/Microsoft.py | 4 | ||||
-rw-r--r-- | Mailman/Bouncers/Netscape.py | 4 | ||||
-rw-r--r-- | Mailman/Bouncers/Postfix.py | 6 | ||||
-rw-r--r-- | Mailman/Cgi/admin.py | 16 | ||||
-rw-r--r-- | Mailman/Cgi/admindb.py | 17 | ||||
-rw-r--r-- | Mailman/Cgi/create.py | 6 | ||||
-rw-r--r-- | Mailman/Cgi/edithtml.py | 2 | ||||
-rw-r--r-- | Mailman/Cgi/roster.py | 14 | ||||
-rw-r--r-- | Mailman/Cgi/subscribe.py | 9 | ||||
-rw-r--r-- | Mailman/Defaults.py.in | 10 | ||||
-rw-r--r-- | Mailman/Errors.py | 28 | ||||
-rw-r--r-- | Mailman/Gui/Privacy.py | 6 | ||||
-rw-r--r-- | Mailman/Gui/Topics.py | 2 | ||||
-rw-r--r-- | Mailman/Handlers/Decorate.py | 14 | ||||
-rw-r--r-- | Mailman/Handlers/Scrubber.py | 13 | ||||
-rw-r--r-- | Mailman/Handlers/Tagger.py | 9 | ||||
-rw-r--r-- | Mailman/LockFile.py | 6 | ||||
-rw-r--r-- | Mailman/MailList.py | 2 | ||||
-rw-r--r-- | Mailman/Pending.py | 6 | ||||
-rw-r--r-- | Mailman/Queue/Switchboard.py | 4 | ||||
-rw-r--r-- | Mailman/SecurityManager.py | 13 | ||||
-rw-r--r-- | Mailman/Utils.py | 24 | ||||
-rw-r--r-- | Mailman/Version.py | 8 |
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)) |