diff options
| author | bwarsaw | 2006-10-15 22:04:16 +0000 |
|---|---|---|
| committer | bwarsaw | 2006-10-15 22:04:16 +0000 |
| commit | e7fe84dca5681a6de55262a0eddd06758cbd1ce4 (patch) | |
| tree | a4c5a0e2778269c2a77ee0fecae45ac3f8e64de0 | |
| parent | d75f597cb3ccfdd6de9c6bb3877e5452884002c9 (diff) | |
| download | mailman-e7fe84dca5681a6de55262a0eddd06758cbd1ce4.tar.gz mailman-e7fe84dca5681a6de55262a0eddd06758cbd1ce4.tar.zst mailman-e7fe84dca5681a6de55262a0eddd06758cbd1ce4.zip | |
More work on the WSGI support. So far, I've tested most of the admin.py links
and some of the admindb.py links. There may still be breakage in other parts
of the interface and I haven't gone back to verify that traditional CGI still
works.
Changes:
- Add wsgiref-0.1.2-py2.4.egg so that we can still do WSGI in Python 2.4,
which doesn't come with wsgiref. Of course this means we /also/ have to add
setuptools-0.5c3 because eggs require setuptools.
- Style cleanups in HTTPRunner.py and wsgi_app.py. Also, use cStringIO
instead of StringIO.
- All internal links within the listinfo and admin pages are (or at least
should be ;) relative now. This should make other things better, such as
running Mailman over https or alternative ports. It does kind of mean that
web_page_url is obsolete, but I haven't looked at whether we can completely
eradicate it.
- ValidateEmail(): Use ' ' in s instead of s.count(' ') > 0.
- GetPathPieces(): When path is false, return the empty list instead of None,
so we can still len() it.
- ScriptURL(): Much simpler. To support relative urls as the default, we
change the API so that it only takes a 'target' argument (i.e. the script we
want to link to). It no longer takes 'absolute' or 'web_page_url', and it
constructs its link from GetPathPieces(), the target, and the cgi extension.
- GetRequestURI(): code style updates.
- Mailman/bin/show_config.py: De-DOS-line-ending-ification.
- export.py: A few modifications, although this is likely still not final (I'm
still working on the import script). First, for <option> elements, don't
put the value in an attribute, put it in the text body of the element.
Second, put the list <option> tags in a <configuration> element. Third, put
the preferred language on an <option> tag with a 'preferred_language'
name attribute value.
- SecurityManager: Make sure that MakeCookie() and ZapCookie() use the same
'path' cookie value by refactoring that into a separate method. That method
now returns just the SCRIPT_NAME and the full listname. web_page_url
doesn't enter into it.
- loginit.py: Add a 'debug' logger since it's just too useful to have :)
- admin.py: Remove the extra / right before the query string in ?VARHELP
urls. That extra / turns out to be problematic with the relative url scheme
we're using now.
- Auth.py: whitespace normalization and copyright years update. Also, remove
a couple of unnecessary imports. Also, make sure that the actionurl is
relative.
- create.py: Typo.
- private.py: mm_cfg -> config object
- In MailList.py: GetScriptURL() can be written in terms of Utils.ScriptURL()
now.
| -rw-r--r-- | Mailman/Archiver/Archiver.py | 18 | ||||
| -rw-r--r-- | Mailman/Cgi/Auth.py | 19 | ||||
| -rw-r--r-- | Mailman/Cgi/admin.py | 10 | ||||
| -rw-r--r-- | Mailman/Cgi/admindb.py | 2 | ||||
| -rw-r--r-- | Mailman/Cgi/create.py | 2 | ||||
| -rw-r--r-- | Mailman/Cgi/private.py | 19 | ||||
| -rw-r--r-- | Mailman/Cgi/wsgi_app.py | 60 | ||||
| -rw-r--r-- | Mailman/Defaults.py.in | 8 | ||||
| -rw-r--r-- | Mailman/Gui/Privacy.py | 2 | ||||
| -rw-r--r-- | Mailman/HTMLFormatter.py | 16 | ||||
| -rw-r--r-- | Mailman/MailList.py | 11 | ||||
| -rw-r--r-- | Mailman/Queue/HTTPRunner.py | 27 | ||||
| -rw-r--r-- | Mailman/SecurityManager.py | 15 | ||||
| -rw-r--r-- | Mailman/Utils.py | 37 | ||||
| -rw-r--r-- | Mailman/bin/export.py | 10 | ||||
| -rw-r--r-- | Mailman/bin/show_config.py | 197 | ||||
| -rw-r--r-- | Mailman/configuration.py | 2 | ||||
| -rw-r--r-- | Mailman/loginit.py | 1 | ||||
| -rw-r--r-- | bin/Makefile.in | 2 | ||||
| -rw-r--r-- | misc/Makefile.in | 22 | ||||
| -rw-r--r-- | misc/setuptools-0.6c3.tar.gz | bin | 0 -> 238544 bytes | |||
| -rw-r--r-- | misc/wsgiref-0.1.2-py2.4.egg | bin | 0 -> 39890 bytes |
22 files changed, 236 insertions, 244 deletions
diff --git a/Mailman/Archiver/Archiver.py b/Mailman/Archiver/Archiver.py index 8c8dcd238..f76992928 100644 --- a/Mailman/Archiver/Archiver.py +++ b/Mailman/Archiver/Archiver.py @@ -117,7 +117,7 @@ class Archiver: fp.write(Utils.maketext( 'emptyarchive.html', {'listname': self.real_name, - 'listinfo': self.GetScriptURL('listinfo', absolute=1), + 'listinfo': self.GetScriptURL('listinfo'), }, mlist=self)) if fp: fp.close() @@ -135,19 +135,17 @@ class Archiver: self.internal_name() + '.mbox') def GetBaseArchiveURL(self): - url = self.GetScriptURL('private', absolute=1) + '/' if self.archive_private: - return url + url = self.GetScriptURL('private') else: - hostname = re.match('[^:]*://([^/]*)/.*', url).group(1)\ - or mm_cfg.DEFAULT_URL_HOST - url = mm_cfg.PUBLIC_ARCHIVE_URL % { + web_host = config.domains.get(self.host_name, self.host_name) + url = config.PUBLIC_ARCHIVE_URL % { 'listname': self.internal_name(), - 'hostname': hostname + 'hostname': web_host, } - if not url.endswith('/'): - url += '/' - return url + if not url.endswith('/'): + url += '/' + return url def __archive_file(self, afn): """Open (creating, if necessary) the named archive file.""" diff --git a/Mailman/Cgi/Auth.py b/Mailman/Cgi/Auth.py index 8c66c4d36..98e9fe49d 100644 --- a/Mailman/Cgi/Auth.py +++ b/Mailman/Cgi/Auth.py @@ -1,26 +1,25 @@ -# Copyright (C) 1998,1999,2000,2001,2002 by the Free Software Foundation, Inc. +# Copyright (C) 1998-2006 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. """Common routines for logging in and logging out of the list administrator and list moderator interface. """ -from Mailman import mm_cfg from Mailman import Utils -from Mailman import Errors from Mailman.htmlformat import FontAttr from Mailman.i18n import _ @@ -34,12 +33,14 @@ class NotLoggedInError(Exception): -def loginpage(mlist, scriptname, msg='', frontpage=None): +def loginpage(mlist, scriptname, msg='', frontpage=False): url = mlist.GetScriptURL(scriptname) if frontpage: actionurl = url else: - actionurl = Utils.GetRequestURI(url) + request = Utils.GetRequestURI(url) + up = '../' * request.count('/') + actionurl = up + request if msg: msg = FontAttr(msg, color='#ff0000', size='+1').Format() if scriptname == 'admindb': diff --git a/Mailman/Cgi/admin.py b/Mailman/Cgi/admin.py index 001004fa0..3fbbd4ca4 100644 --- a/Mailman/Cgi/admin.py +++ b/Mailman/Cgi/admin.py @@ -99,7 +99,7 @@ def main(): # Is this a log-out request? if category == 'logout': print mlist.ZapCookie(mm_cfg.AuthListAdmin) - Auth.loginpage(mlist, 'admin', frontpage=1) + Auth.loginpage(mlist, 'admin', frontpage=True) return # Sanity check @@ -795,9 +795,9 @@ def get_item_gui_description(mlist, category, subcat, # the details page! if detailsp: if subcat: - varhelp = '/?VARHELP=%s/%s/%s' % (category, subcat, varname) + varhelp = '?VARHELP=%s/%s/%s' % (category, subcat, varname) else: - varhelp = '/?VARHELP=%s/%s' % (category, varname) + varhelp = '?VARHELP=%s/%s' % (category, varname) if descr == elaboration: linktext = _('<br>(Edit <b>%(varname)s</b>)') else: @@ -817,7 +817,7 @@ def get_item_gui_description(mlist, category, subcat, def membership_options(mlist, subcat, cgidata, doc, form): # Show the main stuff - adminurl = mlist.GetScriptURL('admin', absolute=1) + adminurl = mlist.GetScriptURL('admin') container = Container() header = Table(width="100%") # If we're in the list subcategory, show the membership list @@ -1200,7 +1200,7 @@ def mass_remove(mlist, container): def password_inputs(mlist): - adminurl = mlist.GetScriptURL('admin', absolute=1) + adminurl = mlist.GetScriptURL('admin') table = Table(cellspacing=3, cellpadding=4) table.AddRow([Center(Header(2, _('Change list ownership passwords')))]) table.AddCellInfo(table.GetCurrentRowIndex(), 0, colspan=2, diff --git a/Mailman/Cgi/admindb.py b/Mailman/Cgi/admindb.py index 188aabd1c..7d762a172 100644 --- a/Mailman/Cgi/admindb.py +++ b/Mailman/Cgi/admindb.py @@ -172,7 +172,7 @@ def main(): doc.AddItem(Header(2, title)) doc.AddItem(_('There are no pending requests.')) doc.AddItem(' ') - doc.AddItem(Link(mlist.GetScriptURL('admindb', absolute=1), + doc.AddItem(Link(mlist.GetScriptURL('admindb'), _('Click here to reload this page.'))) doc.AddItem(mlist.GetMailmanFooter()) print doc.Format() diff --git a/Mailman/Cgi/create.py b/Mailman/Cgi/create.py index 9a5ab73d8..8db59fdc7 100644 --- a/Mailman/Cgi/create.py +++ b/Mailman/Cgi/create.py @@ -154,7 +154,7 @@ def process_request(doc, cgidata): url_host = Utils.get_request_domain() email_host = config.get_email_host(url_host) if not email_host: - safehostname = Utils.websafe(email_host) + safehostname = Utils.websafe(url_host) request_creation(doc, cgidata, _('Unknown virtual host: $safehostname')) return diff --git a/Mailman/Cgi/private.py b/Mailman/Cgi/private.py index 97dc66690..c9e69944b 100644 --- a/Mailman/Cgi/private.py +++ b/Mailman/Cgi/private.py @@ -23,18 +23,17 @@ import cgi import logging import mimetypes -from Mailman import mm_cfg -from Mailman import Utils -from Mailman import MailList from Mailman import Errors +from Mailman import MailList +from Mailman import Utils from Mailman import i18n -from Mailman.htmlformat import * from Mailman.configuration import config +from Mailman.htmlformat import * # Set up i18n. Until we know which list is being requested, we use the # server's default. _ = i18n._ -i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE) +i18n.set_language(config.DEFAULT_SERVER_LANGUAGE) SLASH = '/' @@ -61,7 +60,7 @@ def guess_type(url, strict): def main(): doc = Document() - doc.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE) + doc.set_language(config.DEFAULT_SERVER_LANGUAGE) parts = Utils.GetPathPieces() if not parts: @@ -127,10 +126,10 @@ def main(): realname = mlist.real_name message = '' - if not mlist.WebAuthenticate((mm_cfg.AuthUser, - mm_cfg.AuthListModerator, - mm_cfg.AuthListAdmin, - mm_cfg.AuthSiteAdmin), + if not mlist.WebAuthenticate((config.AuthUser, + config.AuthListModerator, + config.AuthListAdmin, + config.AuthSiteAdmin), password, username): if cgidata.has_key('submit'): # This is a re-authorization attempt diff --git a/Mailman/Cgi/wsgi_app.py b/Mailman/Cgi/wsgi_app.py index b7acd45fa..8e77352d6 100644 --- a/Mailman/Cgi/wsgi_app.py +++ b/Mailman/Cgi/wsgi_app.py @@ -1,5 +1,3 @@ -# -*- python -*- - # Copyright (C) 2006 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or @@ -17,30 +15,36 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, # USA. +import os import sys + +from cStringIO import StringIO +from email import message_from_string + +from Mailman.configuration import config + +# XXX Should this be configurable in Defaults.py? STEALTH_MODE = False -# Shoul this be configurable in Defaults.py? + + def websafe(s): return s -import os -import StringIO -from email import message_from_string -from Mailman.configuration import config SCRIPTS = ['admin', 'admindb', 'confirm', 'create', 'edithtml', 'listinfo', 'options', 'private', 'rmlist', 'roster', 'subscribe'] -SLASH = '/' -NL2 = '\n\n' -CRLF2 = '\r\n\r\n' -# WSGI to CGI wrapper. Mostly copied from scripts/driver. +SLASH = '/' +NL2 = '\n\n' +CRLF2 = '\r\n\r\n' -def mailman_app(environ, start_response): - """wrapper to *.py cgi commands""" + +# WSGI to CGI wrapper. Mostly copied from scripts/driver. +def mailman_app(environ, start_response): + """Wrapper to *.py CGI commands""" global STEALTH_MODE, websafe try: try: @@ -65,7 +69,7 @@ def mailman_app(environ, start_response): environ['PATH_INFO'] = SLASH + SLASH.join(paths[2:]) else: environ['PATH_INFO'] = '' - # reverse proxy environment. + # Reverse proxy environment. if environ.has_key('HTTP_X_FORWARDED_HOST'): environ['HTTP_HOST'] = environ['HTTP_X_FORWARDED_HOST'] if environ.has_key('HTTP_X_FORWARDED_FOR'): @@ -75,14 +79,14 @@ def mailman_app(environ, start_response): os.environ['HTTP_COOKIE'] = '' for k, v in environ.items(): os.environ[k] = str(v) - # Prepare for redirection. + # Prepare for redirection save_stdin = sys.stdin # CGI writes its output to sys.stdout, while wsgi app should # return (list of) strings. save_stdout = sys.stdout save_stderr = sys.stderr - tmpstdout = StringIO.StringIO() - tmpstderr = StringIO.StringIO() + tmpstdout = StringIO() + tmpstderr = StringIO() response = '' try: try: @@ -117,7 +121,7 @@ def mailman_app(environ, start_response): except: start_response('200 OK', [('Content-Type', 'text/html')]) retstring = print_traceback(log) - retstring +=print_environment(log) + retstring += print_environment(log) return retstring @@ -133,13 +137,13 @@ def print_traceback(log=None): except ImportError: traceback = None try: - from Mailman.mm_cfg import VERSION + from Mailman.Version import VERSION except ImportError: VERSION = '<undetermined>' # Write to the log file first. if log: - outfp = StringIO.StringIO() + outfp = StringIO() print >> outfp, '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@' print >> outfp, '[----- Mailman Version: %s -----]' % VERSION @@ -155,7 +159,7 @@ def print_traceback(log=None): log.error('%s', outfp.getvalue()) # return HTML sink. - htfp = StringIO.StringIO() + htfp = StringIO() print >> htfp, """\ <head><title>Bug in Mailman version %(VERSION)s</title></head> <body bgcolor=#ffffff><h2>Bug in Mailman version %(VERSION)s</h2> @@ -192,7 +196,7 @@ def print_environment(log=None): os = None if log: - outfp = StringIO.StringIO() + outfp = StringIO() # Write some information about our Python executable to the log file. print >> outfp, '[----- Python Information -----]' @@ -204,20 +208,20 @@ def print_environment(log=None): print >> outfp, 'sys.platform =', sys.platform # Write the same information to the HTML sink. - htfp = StringIO.StringIO() + htfp = StringIO() if not STEALTH_MODE: - print >> htfp, '''\ + print >> htfp, """\ <p><hr><h4>Python information:</h4> <p><table> <tr><th>Variable</th><th>Value</th></tr> <tr><td><tt>sys.version</tt></td><td> %s </td></tr> <tr><td><tt>sys.executable</tt></td><td> %s </td></tr> -<tr><td><tt>sys.prefix</tt></td><td> %s </td></tr>' +<tr><td><tt>sys.prefix</tt></td><td> %s </td></tr> <tr><td><tt>sys.exec_prefix</tt></td><td> %s </td></tr> <tr><td><tt>sys.path</tt></td><td> %s </td></tr> <tr><td><tt>sys.platform</tt></td><td> %s </td></tr> -</table>''' % (sys.version, sys.executable, sys.prefix, +</table>""" % (sys.version, sys.executable, sys.prefix, sys.exec_prefix, sys.path, sys.platform) # Write environment variables to the log file. @@ -231,12 +235,12 @@ def print_environment(log=None): # Write environment variables to the HTML sink. if not STEALTH_MODE: - print >> htfp, '''\ + print >> htfp, """\ <p><hr><h4>Environment variables:</h4> <p><table> <tr><th>Variable</th><th>Value</th></tr> -''' +""" if os: for k, v in os.environ.items(): print >> htfp, '<tr><td><tt>' + websafe(k) + \ diff --git a/Mailman/Defaults.py.in b/Mailman/Defaults.py.in index 3c5b9e2da..1840ad998 100644 --- a/Mailman/Defaults.py.in +++ b/Mailman/Defaults.py.in @@ -716,7 +716,7 @@ USE_MAILDIR = No # # NOTE: LMTP delivery is experimental for Mailman 2.2. USE_LMTP = No -# NOTE: If you set USE_LMTP = Yes, add the following line to your mailman.cfg +# NOTE: If you set USE_LMTP = Yes, add the following line to your mailman.cfg # file (uncommented of course!) # QRUNNERS.append(('LMTPRunner', 1)) @@ -727,8 +727,10 @@ LMTP_HOST = 'localhost' LMTP_PORT = 8025 # Experimental WSGI Server. -# You must enable PROXY of Apache httpd server and configure to pass -# mailman CGI requests to this WSGI Server: +# +# You must enable PROXY of Apache httpd server and configure to pass Mailman +# CGI requests to this WSGI Server: +# # ProxyPass /mailman/ http://localhost:2580/ HTTP_HOST = 'localhost' HTTP_PORT = 2580 diff --git a/Mailman/Gui/Privacy.py b/Mailman/Gui/Privacy.py index e073c4ec7..03e756d9b 100644 --- a/Mailman/Gui/Privacy.py +++ b/Mailman/Gui/Privacy.py @@ -160,7 +160,7 @@ class Privacy(GUIBase): spammers.""")), ] - adminurl = mlist.GetScriptURL('admin', absolute=1) + adminurl = mlist.GetScriptURL('admin') sender_rtn = [ _("""When a message is posted to the list, a series of moderation steps are take to decide whether the a moderator must diff --git a/Mailman/HTMLFormatter.py b/Mailman/HTMLFormatter.py index e6afda9b5..f61ccbb82 100644 --- a/Mailman/HTMLFormatter.py +++ b/Mailman/HTMLFormatter.py @@ -1,4 +1,4 @@ -# Copyright (C) 1998-2003 by the Free Software Foundation, Inc. +# Copyright (C) 1998-2006 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -12,19 +12,18 @@ # # 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. """Routines for presentation of list-specific HTML text.""" -import time import re +import time -from Mailman import mm_cfg -from Mailman import Utils from Mailman import MemberAdaptor +from Mailman import Utils +from Mailman import mm_cfg from Mailman.htmlformat import * - from Mailman.i18n import _ @@ -42,7 +41,8 @@ class HTMLFormatter: # Remove the .Format() when htmlformat conversion is done. realname = self.real_name hostname = self.host_name - listinfo_link = Link(self.GetScriptURL('listinfo'), realname).Format() + listinfo_link = Link(self.GetScriptURL('listinfo'), + realname).Format() owner_link = Link('mailto:' + self.GetOwnerEmail(), ownertext).Format() innertext = _('%(listinfo_link)s list run by %(owner_link)s') return Container( diff --git a/Mailman/MailList.py b/Mailman/MailList.py index 575c9cc84..7cac64865 100644 --- a/Mailman/MailList.py +++ b/Mailman/MailList.py @@ -262,12 +262,10 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin, acct, host = tuple(member.split('@')) return "%s%s@%s" % (acct, self.umbrella_member_suffix, host) - def GetScriptURL(self, scriptname, absolute=False): - return '%s/%s' % ( - Utils.ScriptURL(scriptname, self.web_page_url, absolute), - self.fqdn_listname) + def GetScriptURL(self, target): + return Utils.ScriptURL(target) + '/' + self.fqdn_listname - def GetOptionsURL(self, user, obscure=0, absolute=False): + def GetOptionsURL(self, user, obscure=False, absolute=False): url = self.GetScriptURL('options', absolute) if obscure: user = Utils.ObscureEmail(user) @@ -299,8 +297,7 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin, name + '@' + self.host_name) else: - self._full_path = os.path.join(config.LIST_DATA_DIR, - name) + self._full_path = os.path.join(config.LIST_DATA_DIR, name) else: self._full_path = '' # Only one level of mixin inheritance allowed diff --git a/Mailman/Queue/HTTPRunner.py b/Mailman/Queue/HTTPRunner.py index df36db0d8..e542dc9a3 100644 --- a/Mailman/Queue/HTTPRunner.py +++ b/Mailman/Queue/HTTPRunner.py @@ -15,25 +15,24 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, # USA. -"""Mailman HTTP runner (server). - -""" +"""Mailman HTTP runner (server).""" import sys import logging -import StringIO +from cStringIO import StringIO from wsgiref.simple_server import make_server, WSGIRequestHandler +from Mailman.Cgi.wsgi_app import mailman_app from Mailman.Queue.Runner import Runner from Mailman.configuration import config -from Mailman.Cgi.wsgi_app import mailman_app hlog = logging.getLogger('mailman.http') qlog = logging.getLogger('mailman.qrunner') -class HTTPRunner(Runner): + +class HTTPRunner(Runner): def __init__(self, slice=None, numslices=1): pass @@ -41,23 +40,27 @@ class HTTPRunner(Runner): pass + class MailmanWSGIRequestHandler(WSGIRequestHandler): - def handle(self): """Handle a single HTTP request with error output to elog""" - stderr = StringIO.StringIO() - save_stderr = sys.stderr + stderr = StringIO() + saved_stderr = sys.stderr sys.stderr = stderr - WSGIRequestHandler.handle(self) - sys.stderr = save_stderr + try: + WSGIRequestHandler.handle(self) + finally: + sys.stderr = saved_stderr hlog.info(stderr.getvalue().strip()) + server = make_server(config.HTTP_HOST, config.HTTP_PORT, mailman_app, handler_class=MailmanWSGIRequestHandler) + + qlog.info('HTTPRunner qrunner started.') server.serve_forever() # We'll never get here, but just in case... qlog.info('HTTPRunner qrunner exiting.') - diff --git a/Mailman/SecurityManager.py b/Mailman/SecurityManager.py index e97084cf1..8c55d2863 100644 --- a/Mailman/SecurityManager.py +++ b/Mailman/SecurityManager.py @@ -57,8 +57,6 @@ import logging import marshal import binascii -from urlparse import urlparse - from Mailman import Errors from Mailman import mm_cfg from Mailman import Utils @@ -225,6 +223,9 @@ class SecurityManager: return True return False + def _cookie_path(self): + return '/%s/%s' % (os.environ['SCRIPT_NAME'], self.fqdn_listname) + def MakeCookie(self, authcontext, user=None): key, secret = self.AuthContextInfo(authcontext, user) if key is None or secret is None or not isinstance(secret, str): @@ -236,10 +237,7 @@ class SecurityManager: # Create the cookie object. c = Cookie.SimpleCookie() c[key] = binascii.hexlify(marshal.dumps((issued, mac))) - # The path to all Mailman stuff, minus the scheme and host, - # i.e. usually the string `/mailman' - path = urlparse(self.web_page_url)[2] - c[key]['path'] = path + c[key]['path'] = self._cookie_path() # We use session cookies, so don't set `expires' or `max-age' keys. # Set the RFC 2109 required header. c[key]['version'] = 1 @@ -253,10 +251,7 @@ class SecurityManager: # string. c = Cookie.SimpleCookie() c[key] = '' - # The path to all Mailman stuff, minus the scheme and host, - # i.e. usually the string `/mailman' - path = urlparse(self.web_page_url)[2] - c[key]['path'] = path + c[key]['path'] = self._cookie_path() c[key]['max-age'] = 0 # Don't set expires=0 here otherwise it'll force a persistent cookie c[key]['version'] = 1 diff --git a/Mailman/Utils.py b/Mailman/Utils.py index 10281bdcc..edbf25f31 100644 --- a/Mailman/Utils.py +++ b/Mailman/Utils.py @@ -202,7 +202,7 @@ _badchars = re.compile(r'[][()<>|;^,\000-\037\177-\377]') def ValidateEmail(s): """Verify that the an email address isn't grossly evil.""" # Pretty minimal, cheesy check. We could do better... - if not s or s.count(' ') > 0: + if not s or ' ' in s: raise Errors.MMBadEmailError if _badchars.search(s) or s[0] == '-': raise Errors.MMHostileAddress, s @@ -226,36 +226,13 @@ def GetPathPieces(envar='PATH_INFO'): path = CRNLpat.split(path)[0] log.error('Warning: Possible malformed path attack.') return [p for p in path.split('/') if p] - return None + return [] -def ScriptURL(target, web_page_url=None, absolute=False): - """target - scriptname only, nothing extra - web_page_url - the list's configvar of the same name - absolute - a flag which if set, generates an absolute url - """ - if web_page_url is None: - web_page_url = config.DEFAULT_URL_PATTERN % get_request_domain() - if web_page_url[-1] <> '/': - web_page_url = web_page_url + '/' - fullpath = os.environ.get('REQUEST_URI') - if fullpath is None: - 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): - # Use relative addressing - fullpath = fullpath[len(baseurl):] - i = fullpath.find('?') - if i > 0: - count = fullpath.count('/', 0, i) - else: - count = fullpath.count('/') - path = ('../' * count) + target - else: - path = web_page_url + target - return path + config.CGIEXT +def ScriptURL(target): + up = '../' * len(GetPathPieces()) + return '%s%s' % (up, target + config.CGIEXT) @@ -630,9 +607,9 @@ def GetRequestURI(fallback=None, escape=True): unless `escape' is set to 0. """ url = fallback - if os.environ.has_key('REQUEST_URI'): + if 'REQUEST_URI' in os.environ: url = os.environ['REQUEST_URI'] - elif os.environ.has_key('SCRIPT_NAME') and os.environ.has_key('PATH_INFO'): + elif 'SCRIPT_NAME' in os.environ and 'PATH_INFO' in os.environ: url = os.environ['SCRIPT_NAME'] + os.environ['PATH_INFO'] if escape: return websafe(url) diff --git a/Mailman/bin/export.py b/Mailman/bin/export.py index 4a72c4e82..1419e95df 100644 --- a/Mailman/bin/export.py +++ b/Mailman/bin/export.py @@ -156,12 +156,15 @@ class XMLDumper(object): self._element('value', v) self._pop_element('option') else: - self._element('option', name=varname, value=value) + self._element('option', value, name=varname) def _dump_list(self, mlist, with_passwords): # Write list configuration values self._push_element('list', name=mlist.fqdn_listname) - self._element('language', mlist.preferred_language) + self._push_element('configuration') + self._element('option', + mlist.preferred_language, + name='preferred_language') for k in config.ADMIN_CATEGORIES: subcats = mlist.GetConfigSubCategories(k) if subcats is None: @@ -169,6 +172,7 @@ class XMLDumper(object): else: for subcat in [t[0] for t in subcats]: self._do_list_categories(mlist, k, subcat) + self._pop_element('configuration') # Write membership self._push_element('roster') digesters = set(mlist.getDigestMemberKeys()) @@ -206,14 +210,12 @@ class XMLDumper(object): when = datetime.datetime.fromtimestamp(changed) attrs['changed'] = when.isoformat() self._element('delivery', **attrs) - self._push_element('options') for option, flag in Defaults.OPTINFO.items(): # Digest/Regular delivery flag must be handled separately if option in ('digest', 'plain'): continue value = mlist.getMemberOption(member, flag) self._element(option, value) - self._pop_element('options') topics = mlist.getMemberTopics(member) if not topics: self._element('topics') diff --git a/Mailman/bin/show_config.py b/Mailman/bin/show_config.py index ee97b16a8..3ecfd32b4 100644 --- a/Mailman/bin/show_config.py +++ b/Mailman/bin/show_config.py @@ -1,99 +1,98 @@ -# Copyright (C) 2006 by the Free Software Foundation, Inc.
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-import re
-import sys
-import pprint
-import optparse
-
-from Mailman import Version
-from Mailman.configuration import config
-from Mailman.i18n import _
-
-__i18_templates__ = True
-
-# List of names never to show even if --verbose
-NEVER_SHOW = ['__builtins__', '__doc__']
-
-
-
-def parseargs():
- parser = optparse.OptionParser(version=Version.MAILMAN_VERSION,
- usage=_("""\
-%%prog [options] [pattern ...]
-
-Show the values of various Defaults.py/mailman.cfg variables.
-If one or more patterns are given, show only those variables
-whose names match a pattern"""))
- parser.add_option('-v', '--verbose',
- default=False, action='store_true',
- help=_(
-"Show all configuration names, not just 'settings'."))
- parser.add_option('-i', '--ignorecase',
- default=False, action='store_true',
- help=_("Match patterns case-insensitively."))
- parser.add_option('-C', '--config',
- help=_('Alternative configuration file to use'))
- opts, args = parser.parse_args()
- return parser, opts, args
-
-
-
-def main():
- parser, opts, args = parseargs()
-
- patterns = []
- if opts.ignorecase:
- flag = re.IGNORECASE
- else:
- flag = 0
- for pattern in args:
- patterns.append(re.compile(pattern, flag))
-
- pp = pprint.PrettyPrinter(indent=4)
- config.load(opts.config)
- names = config.__dict__.keys()
- names.sort()
- for name in names:
- if name in NEVER_SHOW:
- continue
- if not opts.verbose:
- if name.startswith('_') or re.search('[a-z]', name):
- continue
- if patterns:
- hit = False
- for pattern in patterns:
- if pattern.search(name):
- hit = True
- break
- if not hit:
- continue
- value = config.__dict__[name]
- if isinstance(value, str):
- if re.search('\n', value):
- print '%s = """%s"""' %(name, value)
- else:
- print "%s = '%s'" % (name, value)
- else:
- print '%s = ' % name,
- pp.pprint(value)
-
-
-
-if __name__ == '__main__':
- main()
-
+# Copyright (C) 2006 by the Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. + +import re +import sys +import pprint +import optparse + +from Mailman import Version +from Mailman.configuration import config +from Mailman.i18n import _ + +__i18_templates__ = True + +# List of names never to show even if --verbose +NEVER_SHOW = ['__builtins__', '__doc__'] + + + +def parseargs(): + parser = optparse.OptionParser(version=Version.MAILMAN_VERSION, + usage=_("""\ +%%prog [options] [pattern ...] + +Show the values of various Defaults.py/mailman.cfg variables. +If one or more patterns are given, show only those variables +whose names match a pattern""")) + parser.add_option('-v', '--verbose', + default=False, action='store_true', + help=_( +"Show all configuration names, not just 'settings'.")) + parser.add_option('-i', '--ignorecase', + default=False, action='store_true', + help=_("Match patterns case-insensitively.")) + parser.add_option('-C', '--config', + help=_('Alternative configuration file to use')) + opts, args = parser.parse_args() + return parser, opts, args + + + +def main(): + parser, opts, args = parseargs() + + patterns = [] + if opts.ignorecase: + flag = re.IGNORECASE + else: + flag = 0 + for pattern in args: + patterns.append(re.compile(pattern, flag)) + + pp = pprint.PrettyPrinter(indent=4) + config.load(opts.config) + names = config.__dict__.keys() + names.sort() + for name in names: + if name in NEVER_SHOW: + continue + if not opts.verbose: + if name.startswith('_') or re.search('[a-z]', name): + continue + if patterns: + hit = False + for pattern in patterns: + if pattern.search(name): + hit = True + break + if not hit: + continue + value = config.__dict__[name] + if isinstance(value, str): + if re.search('\n', value): + print '%s = """%s"""' %(name, value) + else: + print "%s = '%s'" % (name, value) + else: + print '%s = ' % name, + pp.pprint(value) + + + +if __name__ == '__main__': + main() diff --git a/Mailman/configuration.py b/Mailman/configuration.py index 6ee94b911..66aa6c191 100644 --- a/Mailman/configuration.py +++ b/Mailman/configuration.py @@ -29,7 +29,7 @@ _missing = object() class Configuration(object): def __init__(self): - self.domains = {} + self.domains = {} # email host -> web host self._reverse = None def load(self, filename=None): diff --git a/Mailman/loginit.py b/Mailman/loginit.py index cfeb64366..2dfa00837 100644 --- a/Mailman/loginit.py +++ b/Mailman/loginit.py @@ -31,6 +31,7 @@ DATEFMT = '%b %d %H:%M:%S %Y' LOGGERS = ( 'bounce', 'config', + 'debug', 'error', 'http', 'locks', diff --git a/bin/Makefile.in b/bin/Makefile.in index a9b9c6688..f576606b3 100644 --- a/bin/Makefile.in +++ b/bin/Makefile.in @@ -54,7 +54,7 @@ SCRIPTS= mmshell \ reset_pw.py templ2pot.py po2templ.py LN_SCRIPTS= add_members arch change_pw check_perms config_list \ - export find_member genaliases inject list_lists \ + export find_member genaliases import inject list_lists \ list_members list_owners mailmanctl mmsitepass newlist \ qrunner rmlist show_config show_qfiles testall unshunt \ update version diff --git a/misc/Makefile.in b/misc/Makefile.in index 9227f63a9..f6d919f6b 100644 --- a/misc/Makefile.in +++ b/misc/Makefile.in @@ -48,14 +48,23 @@ SCRIPTSDIR= $(prefix)/scripts SHELL= /bin/sh PYTHONLIBDIR= $(prefix)/pythonlib + +# Traditional distutils packages SETUPINSTOPTS= --install-lib $(DESTDIR)$(PYTHONLIBDIR) \ --install-purelib $(DESTDIR)$(PYTHONLIBDIR) \ --install-data $(DESTDIR)$(PYTHONLIBDIR) SETUPCMD= setup.py --quiet install $(SETUPINSTOPTS) -EMAILPKG= email-4.0.1 +EMAIL= email-4.0.1 +SETUPTOOLS= setuptools-0.6c3 +SETUPPKGS= $(EMAIL) $(SETUPTOOLS) + +EZINSTOPTS= --install-dir $(DESTDIR)$(PYTHONLIBDIR) +EZCMD= $(PYTHONLIBDIR)/$(SETUPTOOLS)-py2.4.egg/easy_install.py \ + $(EZINSTALLOPTS) -PACKAGES= $(EMAILPKG) +WSGIREF= wsgiref-0.1.2-py2.4.egg +EZPKGS= $(WSGIREF) # Modes for directories and executables created by the install # process. Default to group-writable directories but @@ -86,10 +95,15 @@ install-other: $(INSTALL) -m $(FILEMODE) mailman.cfg.sample $(DESTDIR)$(ETCDIR) install-packages: - for p in $(PACKAGES); \ + for p in $(SETUPPKGS); \ do \ gunzip -c $(srcdir)/$$p.tar.gz | tar xf -; \ - (cd $$p ; umask 02 ; PYTHONPATH=$(PYTHONLIBDIR) $(PYTHON) $(SETUPCMD)); \ + (cd $$p ; umask 02 ; \ + PYTHONPATH=$(PYTHONLIBDIR) $(PYTHON) $(SETUPCMD)); \ + done + for p in $(EZPKGS); \ + do \ + (umask 02 ; PYTHONPATH=$(PYTHONLIBDIR) $(PYTHON) $(EZCMD) $$p); \ done finish: diff --git a/misc/setuptools-0.6c3.tar.gz b/misc/setuptools-0.6c3.tar.gz Binary files differnew file mode 100644 index 000000000..30a4a464a --- /dev/null +++ b/misc/setuptools-0.6c3.tar.gz diff --git a/misc/wsgiref-0.1.2-py2.4.egg b/misc/wsgiref-0.1.2-py2.4.egg Binary files differnew file mode 100644 index 000000000..b38cb8321 --- /dev/null +++ b/misc/wsgiref-0.1.2-py2.4.egg |
