aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile12
-rw-r--r--Mailman/Cgi/findmail.py74
-rw-r--r--Mailman/Cgi/listarchive.py35
-rwxr-xr-xbin/mailsync17
4 files changed, 114 insertions, 24 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 73e92b1..b5b4909 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -93,16 +93,19 @@ config:
fi
@mv .config.tmp .config
-listarchive:
- @if [ -z "$(MAILMANSRC)" ]; then \
+define build_cgi_rule =
+$(1):; @if [ -z "$(MAILMANSRC)" ]; then \
echo >&2 "Please set MAILMANSRC to point to the mailman-2.x tree"; \
exit 1; \
elif ! test -w $(MAILMANSRC)/src; then \
echo >&2 "$(MAILMANSRC)/src must be writable"; \
exit 1; \
else \
- make -C $(MAILMANSRC)/src CGI_PROGS=listarchive listarchive; \
+ make -C $(MAILMANSRC)/src CGI_PROGS=$(1) $(1); \
fi
+endef
+
+$(foreach tgt,listarchive findmail,$(eval $(call build_cgi_rule,$(tgt))))
define geninstall
install-$(1):;
@@ -126,9 +129,10 @@ TARGETS=\
$(foreach tgt,$(TARGETS),$(eval $(call geninstall,$(tgt))))
-install-cgi: listarchive
+install-cgi: listarchive findmail
install -d $(DESTDIR)$(CGIDIR)
install -o root -g mailman -m 2755 $(MAILMANSRC)/src/listarchive $(DESTDIR)$(CGIDIR)
+ install -o root -g mailman -m 2755 $(MAILMANSRC)/src/findmail $(DESTDIR)$(CGIDIR)
install: install-cgi $(foreach tgt,$(TARGETS), install-$(tgt))
diff --git a/Mailman/Cgi/findmail.py b/Mailman/Cgi/findmail.py
new file mode 100644
index 0000000..d5f3c25
--- /dev/null
+++ b/Mailman/Cgi/findmail.py
@@ -0,0 +1,74 @@
+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)
+
+script_name = 'findmail'
+
+def main():
+ env = os.environ
+ doc = Document()
+ doc.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
+
+ form = cgi.FieldStorage()
+ listname = form.getvalue('idxname','')
+
+ if listname:
+ 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>')
+ doc.SetTitle(_("Archive Error - %(msg)s"))
+ doc.AddItem(Header(2, msg))
+ print doc.Format()
+ syslog('error', 'No such list "%s": %s\n', listname, e)
+ return
+
+ 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_name, absolute=1) + \
+ '?' + os.getenv('QUERY_STRING')
+ # 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
+
+ finder = os.getenv('MAIL_FINDER_CGI')
+ os.execl(finder, os.path.basename(finder))
diff --git a/Mailman/Cgi/listarchive.py b/Mailman/Cgi/listarchive.py
index 873a7be..4e3a8a5 100644
--- a/Mailman/Cgi/listarchive.py
+++ b/Mailman/Cgi/listarchive.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2006 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2021 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
@@ -18,6 +18,7 @@
"""Provide a password-interface wrapper around private archives."""
import os
+import errno
import sys
import cgi
import mimetypes
@@ -58,16 +59,22 @@ def guess_type(url, strict):
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
+ try:
+ os.chdir(os.path.join(privdir, listname))
+ matchlist = sorted(glob.glob("[0-9][0-9][0-9][0-9]-[0-9][0-9]"))
+ for dir in matchlist:
+ try:
+ st = os.stat(dir)
+ if stat.S_ISDIR(st.st_mode):
+ plist.append(dir)
+ except os.error:
+ continue
+ except os.error as e:
+ if errno.errorcode[e.errno] != errno.ENOENT:
+ syslog('error', 'Error accessing "%s": %s\n',
+ os.path.join(privdir, listname), errno.errorcode[e.errno])
+
return plist
@@ -101,13 +108,13 @@ def main():
msgfile = 'threads.html'
if listname:
- loc = script_name + '/' + listname
+ loc = '/' + 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
+ print "Location: %s\n" % (Utils.ScriptURL('listarchive', absolute=True) + loc)
return
if parts:
@@ -195,8 +202,8 @@ def main():
print Utils.maketext('list/footer.html', {})
return
- loc = script_name + '/' + listname + '/' + plist[n] + '/'
- print "Location: %s%s\n" % (mm_cfg.DEFAULT_HOST_NAME or mm_cfg.DEFAULT_EMAIL_HOST, loc)
+ loc = '/' + listname + '/' + plist[n] + '?t=' + form['t'].value
+ print "Location: %s\n" % (Utils.ScriptURL('listarchive', absolute=True) + loc)
return
diff --git a/bin/mailsync b/bin/mailsync
index 94a4c19..97a89b4 100755
--- a/bin/mailsync
+++ b/bin/mailsync
@@ -1,5 +1,5 @@
#! /usr/bin/python
-# Copyright (C) 2014-2015 Sergey Poznyakoff
+# Copyright (C) 2014-2023 Sergey Poznyakoff
#
# 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
@@ -26,8 +26,8 @@ from time import strftime, strptime
from subprocess import Popen,PIPE,call
dbg = 0
-dry_run = 0
-reset_state = 0
+dry_run = False
+reset_state = False
EX_OK = 0
EX_FAILURE = 1
@@ -124,6 +124,7 @@ def mboxtohtml(listid):
else:
n = get_state(listid)
t = 0
+ reset_map = {}
for message in inbox.values()[n:]:
frm = message.get_from()
s = frm.split(' ', 1)
@@ -133,6 +134,10 @@ def mboxtohtml(listid):
dirname = absdir(conf['core']['htmlrootdir'] + "/" + listid + "/" + period)
if not os.path.exists(dirname):
os.makedirs(dirname, 02775)
+ reset_map[period] = True
+ elif reset_state and not period in reset_map:
+ os.remove(dirname + '/.mhonarc.db')
+ reset_map[period] = True
cmd = [ 'mhonarc',
'-add',
@@ -229,7 +234,7 @@ def read_config(file):
print("%s:%s: unknown keyword" % (file,lno),
file=sys.stderr)
err += 1
- conf[section][kw] = val
+ conf[section][kw] = os.path.expandvars(val)
if not 'core' in conf:
print("%s: [core] section missing" % (file), file=sys.stderr)
@@ -278,9 +283,9 @@ if __name__ == '__main__':
elif o in ("-c", "--config"):
config = a
elif o in ("-n", "--dry-run"):
- dry_run = 1
+ dry_run = True
elif o in ("-r", "--reset"):
- reset_state = 1
+ reset_state = True
if dry_run:
dbg += 1

Return to:

Send suggestions and report system problems to the System administrator.