aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2015-04-08 12:21:40 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2015-04-08 12:21:40 +0300
commit04163ef40681ed16e7027cda3886484d5a7481ec (patch)
treeb76cd27ddc89309448615cd5056e6514d7df6457
parentabb844aafca17ed8cdf04f08efaca3a19c477c8a (diff)
downloadmailman-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.py294
-rw-r--r--templates/en/list/badperiod.html23
-rw-r--r--templates/en/list/empty.html12
-rw-r--r--templates/en/list/footer.html11
-rw-r--r--templates/en/list/header.html0
-rw-r--r--templates/en/list/listdir.html29
-rw-r--r--templates/en/list/listindex.html49
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 &copy; 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>
+

Return to:

Send suggestions and report system problems to the System administrator.