diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-04-08 12:21:40 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-04-08 12:21:40 +0300 |
commit | 04163ef40681ed16e7027cda3886484d5a7481ec (patch) | |
tree | b76cd27ddc89309448615cd5056e6514d7df6457 | |
parent | abb844aafca17ed8cdf04f08efaca3a19c477c8a (diff) | |
download | mailman-04163ef40681ed16e7027cda3886484d5a7481ec.tar.gz mailman-04163ef40681ed16e7027cda3886484d5a7481ec.tar.bz2 |
Add new files.
* Mailman/Cgi/listarchive.py: New file.
* templates/en/list/badperiod.html: New file.
* templates/en/list/empty.html: New file.
* templates/en/list/footer.html: New file.
* templates/en/list/header.html: New file.
* templates/en/list/listdir.html: New file.
* templates/en/list/listindex.html: New file.
-rw-r--r-- | Mailman/Cgi/listarchive.py | 294 | ||||
-rw-r--r-- | templates/en/list/badperiod.html | 23 | ||||
-rw-r--r-- | templates/en/list/empty.html | 12 | ||||
-rw-r--r-- | templates/en/list/footer.html | 11 | ||||
-rw-r--r-- | templates/en/list/header.html | 0 | ||||
-rw-r--r-- | templates/en/list/listdir.html | 29 | ||||
-rw-r--r-- | templates/en/list/listindex.html | 49 |
7 files changed, 418 insertions, 0 deletions
diff --git a/Mailman/Cgi/listarchive.py b/Mailman/Cgi/listarchive.py new file mode 100644 index 0000000..40c6fcf --- /dev/null +++ b/Mailman/Cgi/listarchive.py @@ -0,0 +1,294 @@ +# 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. + +"""Provide a password-interface wrapper around private archives.""" + +import os +import sys +import cgi +import mimetypes +import time +import glob +import stat + +from Mailman import mm_cfg +from Mailman import Utils +from Mailman import MailList +from Mailman import Errors +from Mailman import i18n +from Mailman.htmlformat import * +from Mailman.Logging.Syslog import syslog + +# 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) + +SLASH = '/' + + + +def true_path(path): + "Ensure that the path is safe by removing .." + # Workaround for path traverse vulnerability. Unsuccessful attempts will + # be logged in logs/error. + parts = [x for x in path.split(SLASH) if x not in ('.', '..')] + return SLASH.join(parts)[1:] + + + +def guess_type(url, strict): + if hasattr(mimetypes, 'common_types'): + return mimetypes.guess_type(url, strict) + return mimetypes.guess_type(url) + + +def collect_periods(privdir, listname): + os.chdir(os.path.join(privdir, listname)) + matchlist = glob.glob("[0-9][0-9][0-9][0-9]-[0-9][0-9]") + plist = [] + for dir in matchlist: + try: + st = os.stat(dir) + if stat.S_ISDIR(st.st_mode): + plist.append(dir) + except os.error: + continue + return plist + + +script_name = 'listarchive' + +def main(): + doc = Document() + doc.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE) + + script_name = os.getenv('SCRIPT_NAME') + script_base_name = script_name.split('/')[-1] + + privdir = os.path.join(mm_cfg.VAR_PREFIX, 'archives', 'html') + form = cgi.FieldStorage() + parts = Utils.GetPathPieces() + + listname = '' + period = '' + msgfile = '' + if len(form): + if form.has_key('l'): + listname = form['l'].value + if form.has_key('p'): + period = form['p'].value + if form.has_key('m'): + msgfile = form['m'].value + elif form.has_key('t'): + if form['t'].value == 'date': + msgfile = 'index.html' + elif form['t'].value == 'thread': + msgfile = 'threads.html' + + if listname: + loc = script_name + '/' + listname + if period: + loc += '/' + period + '/' + if msgfile: + loc += msgfile + if not form.has_key('d'): + print "Location: http://" + os.getenv('HTTP_HOST') + "%s\n" % loc + return + + if parts: + loc = '' + nparts = len(parts); + if nparts == 3: + msgfile = parts[2] + if nparts >= 2: + period = parts[1] + if nparts >= 1: + listname = parts[0] + + if not listname: + print 'Content-type: text/html\n\n' + advertised = [] + listnames = Utils.list_names() + for name in listnames: + mlist = MailList.MailList(name, lock=0) + if not mlist.advertised: + continue + try: + file = os.path.join(privdir, name, '.timestamp') + with open(file, 'r') as f: + r = int(f.readline().rstrip()) + advertised.append((name,r)) + except IOError: + continue + + advertised.sort(lambda x, y: int(y[1] - x[1])) + + listdir = '' + even = 0 + for item in advertised: + listdir += "<tr class=\"" + ("even" if even else "odd") + "\">\n" \ + + " <td><a href=\"%s/%s\">%s</a></td>\n" % (script_name, item[0], item[0]) \ + + " <td><a href=\"%s/%s/last/index.html\">Date</a></td>\n" % (script_name, item[0]) \ + + " <td><a href=\"%s/%s/last/threads.html\">Threads</a></td>\n" % (script_name, item[0]) \ + + " <td>%s</td>\n" % time.strftime('%c',time.localtime(item[1])) \ + + "</tr>\n"; + even = not even + + print Utils.maketext('list/listdir.html', + {'listdir': listdir}) + print Utils.maketext('list/footer.html', + {}) + return + + try: + mlist = MailList.MailList(listname, lock=0) + except Errors.MMListError, e: + # Avoid cross-site scripting attacks + safelistname = Utils.websafe(listname) + msg = _('No such list <em>%(safelistname)s</em>') + # FIXME: Private in the title + doc.SetTitle(_("Private Archive Error - %(msg)s")) + doc.AddItem(Header(2, msg)) + print doc.Format() + syslog('error', 'No such list "%s": %s\n', listname, e) + return + + if loc: + plist = collect_periods(privdir, listname) + try: + n = plist.index(period) + except ValueError: + msg = _('No such period') + doc.SetTitle(_("Archive Error - %(msg)s")) + doc.AddItem(Header(2, msg)) + print doc.Format() + syslog('error', 'No such period %s in list "%s"\n', + period, listname) + return + if form['d'].value == 'next': + n = n + 1 + elif form['d'].value == 'prev': + n = n - 1 + if n < 0 or n >= len(plist): + print 'Content-type: text/html\n\n' + print Utils.maketext('list/badperiod.html', + {'listname' : listname, + 'period' : period, + 'location' : loc, + 'script' : script_name }, + mlist = mlist) + print Utils.maketext('list/footer.html', {}) + return + + loc = script_name + '/' + listname + '/' + plist[n] + '/' + print "Location: http://mail.gnu.org.ua%s\n" % loc + return + + + realname = mlist.real_name + + i18n.set_language(mlist.preferred_language) + doc.set_language(mlist.preferred_language) + + lang = 'en' # FIXME + if mlist.archive_private: + username = form.getvalue('username', '') + password = form.getvalue('password', '') + message = '' + if not mlist.WebAuthenticate((mm_cfg.AuthUser, + mm_cfg.AuthListModerator, + mm_cfg.AuthListAdmin, + mm_cfg.AuthSiteAdmin), + password, username): + if form.has_key('submit'): + # This is a re-authorization attempt + message = Bold(FontSize('+1', _('Authorization failed.'))).Format() + # Output the password form + charset = Utils.GetCharSet(mlist.preferred_language) + print 'Content-type: text/html; charset=' + charset + '\n\n' + # Put the original full path in the authorization form, but + # avoid trailing slash if we're not adding parts. + # We add it below. + #action = mlist.GetScriptURL(script_base_name, absolute=1) + action = script_name + if parts: + action = os.path.join(action, SLASH.join(parts[0:])) + # Escape web input parameter to avoid cross-site scripting. + print Utils.maketext('private.html', + {'action' : Utils.websafe(action), + 'realname': mlist.real_name, + 'message' : message, + }, mlist=mlist) + return + lang = mlist.getMemberLanguage(username) + + i18n.set_language(lang) + doc.set_language(lang) + + if not period: + print 'Content-type: text/html\n\n' + + plist = collect_periods(privdir, listname) + if len(plist) == 0: + print Utils.maketext('list/empty.html', + {'listname' : listname }) + else: + plist.sort() + plist.reverse() + + options = '' + for dir in plist: + options += " <option value=\"%s\">%s</option>\n" % (dir, dir) + print Utils.maketext('list/listindex.html', + {'listname' : listname, + 'options' : options, + 'listdir' : script_name, + 'script' : script_name }, + mlist = mlist) + print Utils.maketext('list/footer.html', {}) + else: + if period == 'last': + plist = collect_periods(privdir, listname) + if len(plist) == 0: + print 'Content-type: text/html\n\n' + print Utils.maketext('emptyarchive.html', + {'listname': realname, + 'listinfo': mlist.GetScriptURL('listinfo', absolute=1), + }, mlist=mlist) + return + else: + plist.sort() + plist.reverse() + period = plist[0] + if not msgfile: + msgfile = 'index.html' + archive = os.path.join(privdir, listname, period, msgfile) + try: + f = open(archive, 'r') + except IOError: + msg = _('Private archive file not found') + doc.SetTitle(msg) + doc.AddItem(Header(2, msg)) + print doc.Format() + syslog('error', 'Private archive file not found: %s', archive) + return + print 'Content-type: text/html\n\n' + sys.stdout.write(f.read()) + f.close() + + diff --git a/templates/en/list/badperiod.html b/templates/en/list/badperiod.html new file mode 100644 index 0000000..0e01037 --- /dev/null +++ b/templates/en/list/badperiod.html @@ -0,0 +1,23 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> + <title>%(listname)s Archives</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <link rev="made" href="mailto:gray@gnu.org.ua" /> + <link rel="stylesheet" href="/maillist.css" type="text/css" /> +</head> +<body> +<h1>%(listname)s archives</h1> + +<ul class="idx-nav"> + <li><a href="%(listdir)s">All Lists</a></li> +</ul> + +<div id="error"> +<h1>Wrong Interval</h1> +<p>There are no messages in this interval.</p> +<p> + <a href="%(location)s">Return</a> +</p> +</div> diff --git a/templates/en/list/empty.html b/templates/en/list/empty.html new file mode 100644 index 0000000..29d593f --- /dev/null +++ b/templates/en/list/empty.html @@ -0,0 +1,12 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> + <title>%(listname)s Archives</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <link rev="made" href="mailto:gray@gnu.org.ua" /> + <link rel="stylesheet" href="/maillist.css" type="text/css" /> +</head> +<body> +<h1>%(listname)s archives</h1> +<div class="warning"><p>No messages in this list</p></div> diff --git a/templates/en/list/footer.html b/templates/en/list/footer.html new file mode 100644 index 0000000..8201050 --- /dev/null +++ b/templates/en/list/footer.html @@ -0,0 +1,11 @@ +<div id="footer"> +<p> +<address>Copyright © 2010 Sergey Poznyakoff</address>. +<span class="hint">Report problems and send sugestions to <a href="mailto:puszcza-hackers@gnu.org.ua">List Administrator</a>.</span> + +</p> +</div> +</body> +</html> + + diff --git a/templates/en/list/header.html b/templates/en/list/header.html new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/templates/en/list/header.html diff --git a/templates/en/list/listdir.html b/templates/en/list/listdir.html new file mode 100644 index 0000000..6cf6979 --- /dev/null +++ b/templates/en/list/listdir.html @@ -0,0 +1,29 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> + <title>Mail Archives</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <link rev="made" href="mailto:gray@gnu.org.ua" /> + <link rel="stylesheet" href="/maillist.css" type="text/css" /> +</head> +<body> +<h1>Mail Archives</h1> +<p> + Archives below are listed from most recently updated to oldest updated. +</p> + +<div class="dir listdir"> +<table class="listdir"> +<thead> + <tr> + <td>Name</td> + <td colspan="2">Current Index</td> + <td>Last Updated</td> + </tr> +</thead> +<tbody> +%(listdir)s +</tbody> +</table> +</div> diff --git a/templates/en/list/listindex.html b/templates/en/list/listindex.html new file mode 100644 index 0000000..2fff9e9 --- /dev/null +++ b/templates/en/list/listindex.html @@ -0,0 +1,49 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> + <title>%(listname)s Archives</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <link rev="made" href="mailto:gray@gnu.org.ua" /> + <link rel="stylesheet" href="/maillist.css" type="text/css" /> +</head> +<body> +<h1>%(listname)s archives</h1> + +<ul class="idx-nav"> + <li><a href="%(listdir)s">All Lists</a></li> +</ul> + +<div class="search-form"> + <form method="get" action="/mailman/findmail"> + <span class="input-label">Search for:</span> + <input type="text" name="query" size="40"> + <input type="submit" name="submit" value="Go!"> + <input type="hidden" name="idxname" value="%(listname)s"> + <a href="/mailman/findmail?idxname=%(listname)s">Advanced</a> + </form> +</div> + +<div class="descr"> +<p>The <b>%(listname)s</b> archives are divided into <dfn>sections</dfn>, +each section covering a period of one month. For each section, +two kinds of indices are provided: <dfn>date index</dfn> and +<dfn>thread index</dfn>.</p> +<p>Select the desired interval and index type and click on <i>Retrieve</i> +when ready:</p> +</div> + +<div class="dir"> +<form method="get" action="%(script)s"> + <span class="label">Period</span> + <select name="p">%(options)s</select> + <span class="label">Index</span> + <select name="t"> + <option value="date">Date</option> + <option value="thread">Thread</option> + </select> + <input type="submit" name="submit" value="Retrieve"> + <input type="hidden" name="l" value="%(listname)s"> +</form> +</div> + |