summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbwarsaw2001-05-09 15:07:47 +0000
committerbwarsaw2001-05-09 15:07:47 +0000
commitea1e6c86f57d8485481c474bb6166e0088044889 (patch)
tree27fb7fa4f9cb0bda96f0b0fe83198f404baea789
parentffa133a534c3d4f7f20e7e6fd6235a9bd4cc542b (diff)
downloadmailman-ea1e6c86f57d8485481c474bb6166e0088044889.tar.gz
mailman-ea1e6c86f57d8485481c474bb6166e0088044889.tar.zst
mailman-ea1e6c86f57d8485481c474bb6166e0088044889.zip
CGI scripts for through-the-web creation and deletion of mailing lists.
-rw-r--r--Mailman/Cgi/create.py279
-rw-r--r--Mailman/Cgi/rmlist.py221
2 files changed, 500 insertions, 0 deletions
diff --git a/Mailman/Cgi/create.py b/Mailman/Cgi/create.py
new file mode 100644
index 000000000..05f6fea9c
--- /dev/null
+++ b/Mailman/Cgi/create.py
@@ -0,0 +1,279 @@
+# Copyright (C) 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Create mailing lists through the web."""
+
+import sys
+import os
+import signal
+import cgi
+import sha
+
+from Mailman import mm_cfg
+from Mailman import MailList
+from Mailman import Message
+from Mailman import Errors
+from Mailman import i18n
+from Mailman.htmlformat import *
+from Mailman.Logging.Syslog import syslog
+
+# Set up i18n
+_ = i18n._
+i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
+
+
+
+def main():
+ doc = Document()
+ doc.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
+
+ cgidata = cgi.FieldStorage()
+ parts = Utils.GetPathPieces()
+ if parts:
+ # Bad URL specification
+ title = _('Bad URL specification')
+ doc.SetTitle(title)
+ doc.AddItem(
+ Header(3, Bold(FontAttr(title, color='#ff0000', size='+2'))))
+ syslog('error', 'Bad URL specification: %s' % parts)
+ elif cgidata.has_key('listname'):
+ # We must be processing the list creation request
+ process_request(doc, cgidata)
+ else:
+ # Put up the list creation request form
+ request_creation(doc)
+ doc.AddItem('<hr>')
+ # Always add the footer and print the document
+ doc.AddItem(_('Return to the ') +
+ Link(Utils.ScriptURL('listinfo'),
+ _('general list overview')).Format())
+ doc.AddItem(_('<br>Return to the ') +
+ Link(Utils.ScriptURL('admin'),
+ _('administrative list overview')).Format())
+ doc.AddItem(MailmanLogo())
+ print doc.Format(bgcolor='#ffffff')
+
+
+
+def process_request(doc, cgidata):
+ listname = cgidata.getvalue('listname', '').strip()
+ owner = cgidata.getvalue('owner', '').strip()
+ password = cgidata.getvalue('password', '').strip()
+ confirm = cgidata.getvalue('confirm', '').strip()
+ auth = cgidata.getvalue('auth', '').strip()
+ # Sanity check
+ if '@' in listname:
+ request_creation(doc, cgidata,
+ _('List name must not include "@": %(listname)s'))
+ return
+ if Utils.list_exists(listname):
+ # BAW: should we tell them the list already exists? This could be
+ # used to mine/guess the existance of non-advertised lists. Then
+ # again, that can be done in other ways already, so oh well.
+ request_creation(doc, cgidata, _('List already exists: %(listname)s'))
+ return
+ if not owner:
+ request_creation(doc, cgidata,
+ _('You forgot to specify the list owner'))
+ return
+ if password <> confirm:
+ request_creation(doc, cgidata,
+ _('Initial list passwords do not match'))
+ return
+ if not password:
+ request_creation(doc, cgidata, _('The list password cannot be empty'))
+ return
+ # The authorization password must be non-empty, and it must match either
+ # the list creation password or the site admin password
+ ok = 0
+ if auth:
+ ok = Utils.check_global_password(auth, 0)
+ if not ok:
+ ok = Utils.check_global_password(auth)
+ if not ok:
+ request_creation(
+ doc, cgidata,
+ _('You are not authorized to create new mailing lists'))
+ return
+ # We've got all the data we need, so go ahead and try to create the list
+ # See admin.py for why we need to set up the signal handler.
+ mlist = MailList.MailList()
+
+ def sigterm_handler(signum, frame, mlist=mlist):
+ # Make sure the list gets unlocked...
+ mlist.Unlock()
+ # ...and ensure we exit, otherwise race conditions could cause us to
+ # enter MailList.Save() while we're in the unlocked state, and that
+ # could be bad!
+ sys.exit(0)
+
+ try:
+ # Install the emergency shutdown signal handler
+ signal.signal(signal.SIGTERM, sigterm_handler)
+
+ 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
+ oldmask = os.umask(002)
+ try:
+ try:
+ mlist.Create(listname, owner, pw)
+ finally:
+ os.umask(oldmask)
+ except Errors.MMBadEmailError:
+ request_creation(doc, cgidata,
+ _('Bad owner email address: %(owner)s'))
+ return
+ except Errors.MMListAlreadyExistsError:
+ request_creation(doc, cgidata,
+ _('List already exists: %(listname)s'))
+ return
+ except Errors.MMListError:
+ request_creation(
+ doc, cgidata,
+ _('''Some unknown error occurred while creating the list.
+ Please contact the site administrator for assistance.'''))
+ return
+
+ # Now do the MTA-specific list creation tasks
+ if mm_cfg.MTA:
+ modname = 'Mailman.MTA.' + mm_cfg.MTA
+ __import__(modname)
+ sys.modules[modname].create(mlist)
+
+ # And send the notice to the list owner
+ text = Utils.maketext(
+ 'newlist.txt',
+ {'listname' : listname,
+ 'password' : password,
+ 'admin_url' : mlist.GetScriptURL('admin', absolute=1),
+ 'listinfo_url': mlist.GetScriptURL('listinfo', absolute=1),
+ 'requestaddr' : "%s-request@%s" % (listname, mlist.host_name),
+ 'hostname' : mlist.host_name,
+ }, mlist.preferred_language)
+ msg = Message.UserNotification(
+ owner,
+ 'mailman-owner@' + mlist.host_name,
+ _('Your new mailing list: %(listname)s'),
+ text)
+ msg.send(mlist)
+
+ # Success!
+ listinfo_url = mlist.GetScriptURL('listinfo', absolute=1)
+ admin_url = mlist.GetScriptURL('admin', absolute=1)
+ create_url = Utils.ScriptURL('create')
+
+ title = _('Mailing list creation results')
+ doc.SetTitle(title)
+ table = Table(border=0, width='100%')
+ table.AddRow([Center(Bold(FontAttr(title, size='+1')))])
+ table.AddCellInfo(table.GetCurrentRowIndex(), 0, bgcolor='#99ccff')
+ table.AddRow([_('''You have successfully created the mailing list
+ <b>%(listname)s</b> and notification has been sent to the list owner
+ <b>%(owner)s</b>. You can now:''')])
+ ullist = UnorderedList()
+ ullist.AddItem(Link(listinfo_url, _("Visit the list's info page")))
+ ullist.AddItem(Link(admin_url, _("Visit the list's admin page")))
+ ullist.AddItem(Link(create_url, _('Create another list')))
+ table.AddRow([ullist])
+ doc.AddItem(table)
+
+ finally:
+ # Now be sure to unlock the list. It's okay if we get a signal here
+ # because essentially, the signal handler will do the same thing. And
+ # unlocking is unconditional, so it's not an error if we unlock while
+ # we're already unlocked.
+ mlist.Unlock()
+
+
+
+# For convenience
+class Dummy:
+ def getvalue(self, name, default):
+ return default
+dummy = Dummy()
+
+
+
+def request_creation(doc, cgidata=dummy, errmsg=None):
+ # What virtual domain are we using?
+ hostname = Utils.get_domain()
+ # Set up the document
+ title = _('Create a %(hostname)s Mailing List')
+ doc.SetTitle(title)
+ table = Table(border=0, width='100%')
+ table.AddRow([Center(Bold(FontAttr(title, size='+1')))])
+ table.AddCellInfo(table.GetCurrentRowIndex(), 0, bgcolor='#99ccff')
+ # Add any error message
+ if errmsg:
+ table.AddRow([Header(3, Bold(
+ FontAttr(_('Error: '), color='#ff0000', size='+2').Format() +
+ Italic(errmsg).Format()))])
+ table.AddRow([_("""You can create a new mailing list by entering the
+ relevant information into the form below. The name of the mailing list
+ will be used as the primary address for posting messages to the list, so
+ it should be lowercased. You will not be able to change this once the
+ list is created.
+
+ <p>You also need to enter the email address of the initial list owner.
+ Once the list is created, the list owner will be given notification, along
+ with the initial list password. The list owner will then be able to
+ modify the password and add or remove additional list owners.
+
+ <p>You must have the proper authorization to create new mailing lists.
+ Each site should have a <em>list creator's</em> password, which you can
+ enter in the field at the bottom. Note that the site administrator's
+ password can also be used for authentication.
+ """)])
+ # Build the form for the necessary input
+ form = Form(Utils.ScriptURL('create'))
+ ftable = Table(border=0, cols='2', width='100%',
+ cellspacing=3, cellpadding=4)
+
+ ftable.AddRow([Label(_('Name of list:')),
+ TextBox('listname', cgidata.getvalue('listname', ''))])
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 0, bgcolor="#cccccc")
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 1, bgcolor="#cccccc")
+
+ ftable.AddRow([Label(_('Initial list owner address:')),
+ TextBox('owner', cgidata.getvalue('owner', ''))])
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 0, bgcolor="#cccccc")
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 1, bgcolor="#cccccc")
+
+ ftable.AddRow([Label(_('Initial list password:')),
+ PasswordBox('password', cgidata.getvalue('password', ''))])
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 0, bgcolor="#cccccc")
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 1, bgcolor="#cccccc")
+
+ ftable.AddRow([Label(_('Confirm initial password:')),
+ PasswordBox('confirm', cgidata.getvalue('confirm', ''))])
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 0, bgcolor="#cccccc")
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 1, bgcolor="#cccccc")
+
+ ftable.AddRow(['<hr>'])
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 0, colspan=2)
+ ftable.AddRow([Label(_("List creator's (authentication) password:")),
+ PasswordBox('auth')])
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 0, bgcolor="#cccccc")
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 1, bgcolor="#cccccc")
+
+ ftable.AddRow([Center(SubmitButton('doit', _('Create List')))])
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 0, colspan=2)
+ form.AddItem(ftable)
+ table.AddRow([form])
+ doc.AddItem(table)
+ return
diff --git a/Mailman/Cgi/rmlist.py b/Mailman/Cgi/rmlist.py
new file mode 100644
index 000000000..c09a60d85
--- /dev/null
+++ b/Mailman/Cgi/rmlist.py
@@ -0,0 +1,221 @@
+# Copyright (C) 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Remove/delete mailing lists through the web."""
+
+import os
+import cgi
+import sys
+
+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
+_ = i18n._
+i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
+
+
+
+def main():
+ doc = Document()
+ doc.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
+
+ cgidata = cgi.FieldStorage()
+ parts = Utils.GetPathPieces()
+
+ if not parts:
+ # Bad URL specification
+ title = _('Bad URL specification')
+ doc.SetTitle(title)
+ doc.AddItem(
+ Header(3, Bold(FontAttr(title, color='#ff0000', size='+2'))))
+ doc.AddItem('<hr>')
+ doc.AddItem(MailmanLogo())
+ print doc.Format(bgcolor='#ffffff')
+ syslog('error', 'Bad URL specification: %s' % parts)
+ return
+
+ listname = parts[0].lower()
+ try:
+ mlist = MailList.MailList(listname, lock=0)
+ except Errors.MMListError, e:
+ title = _('No such list <em>%(listname)s</em>')
+ doc.SetTitle(title)
+ doc.AddItem(
+ Header(3,
+ Bold(FontAttr(title, color='#ff0000', size='+2'))))
+ doc.AddItem('<hr>')
+ doc.AddItem(MailmanLogo())
+ print doc.Format(bgcolor='#ffffff')
+ syslog('error', 'No such list "%s": %s\n' % (listname, e))
+ return
+
+ # Now that we have a valid mailing list, set the language
+ i18n.set_language(mlist.preferred_language)
+ doc.set_language(mlist.preferred_language)
+
+ if len(parts) <> 1:
+ # Bad URL specification
+ title = _('Bad URL specification')
+ doc.SetTitle(title)
+ doc.AddItem(
+ Header(3, Bold(FontAttr(title, color='#ff0000', size='+2'))))
+ doc.AddItem(mlist.GetMailmanFooter())
+ print doc.Format(bgcolor='#ffffff')
+ syslog('error', 'Bad URL specification: %s' % parts)
+ return
+
+ # Be sure the list owners are not sneaking around!
+ if not mm_cfg.OWNERS_CAN_DELETE_THEIR_OWN_LISTS:
+ title = _("You're being a sneaky list owner!")
+ doc.SetTitle(title)
+ doc.AddItem(
+ Header(3, Bold(FontAttr(title, color='#ff0000', size='+2'))))
+ doc.AddItem(mlist.GetMailmanFooter())
+ print doc.Format(bgcolor='#ffffff')
+ syslog('error', 'Attempt to sneakily delete a list: %s' % listname)
+ return
+
+ if cgidata.has_key('doit'):
+ process_request(doc, cgidata, mlist)
+ print doc.Format(bgcolor='#ffffff')
+ return
+
+ request_deletion(doc, mlist)
+ # Always add the footer and print the document
+ doc.AddItem(mlist.GetMailmanFooter())
+ print doc.Format(bgcolor='#ffffff')
+
+
+
+def process_request(doc, cgidata, mlist):
+ password = cgidata.getvalue('password', '').strip()
+ try:
+ delarchives = int(cgidata.getvalue('delarchives', '0'))
+ except ValueError:
+ delarchives = 0
+
+ # Make sure the password matches
+ if not mlist.ValidAdminPassword(password):
+ request_deletion(
+ doc, mlist,
+ _('You are not authorized to delete this mailing list'))
+ return
+
+ # Do the MTA-specific list deletion tasks
+ if mm_cfg.MTA:
+ modname = 'Mailman.MTA.' + mm_cfg.MTA
+ __import__(modname)
+ sys.modules[modname].remove(mlist)
+
+ REMOVABLES = ['lists/%s']
+
+ if delarchives:
+ REMOVABLES.extend(['archives/private/%s',
+ 'archives/private/%s.mbox',
+ 'archives/public/%s',
+ 'archives/public/%s.mbox',
+ ])
+
+ listname = mlist.internal_name()
+ for dirtmpl in REMOVABLES:
+ dir = os.path.join(mm_cfg.VAR_PREFIX, dirtmpl % listname)
+ if os.path.islink(dir):
+ os.unlink(dir)
+ elif os.path.isdir(dir):
+ Utils.rmdirhier(dir)
+
+ title = _('Mailing list deletion results')
+ doc.SetTitle(title)
+ table = Table(border=0, width='100%')
+ table.AddRow([Center(Bold(FontAttr(title, size='+1')))])
+ table.AddCellInfo(table.GetCurrentRowIndex(), 0, bgcolor='#99ccff')
+ table.AddRow([_('''You have successfully deleted the mailing list
+ <b>%(listname)s</b>.''')])
+ doc.AddItem(table)
+ doc.AddItem('<hr>')
+ doc.AddItem(_('Return to the ') +
+ Link(Utils.ScriptURL('listinfo'),
+ _('general list overview')).Format())
+ doc.AddItem(_('<br>Return to the ') +
+ Link(Utils.ScriptURL('admin'),
+ _('administrative list overview')).Format())
+ doc.AddItem(MailmanLogo())
+
+
+
+
+
+def request_deletion(doc, mlist, errmsg=None):
+ realname = mlist.real_name
+ title = _('Permanently remove mailing list <em>%(realname)s</em>')
+ doc.SetTitle(title)
+
+ table = Table(border=0, width='100%')
+ table.AddRow([Center(Bold(FontAttr(title, size='+1')))])
+ table.AddCellInfo(table.GetCurrentRowIndex(), 0, bgcolor='#99ccff')
+
+ # Add any error message
+ if errmsg:
+ table.AddRow([Header(3, Bold(
+ FontAttr(_('Error: '), color='#ff0000', size='+2').Format() +
+ Italic(errmsg).Format()))])
+
+ table.AddRow([_("""This page allows you as the list owner, to permanent
+ remove this mailing list from the system. <strong>This action is not
+ undoable</strong> so you should undertake it only if you are absolutely
+ sure this mailing list has served its purpose and is no longer necessary.
+
+ <p>Note that no warning will be sent to your list members and after this
+ action, any subsequent messages sent to the mailing list, or any of its
+ administrative addreses will bounce.
+
+ <p>You also have the option of removing the archives for this mailing list
+ at this time. It is almost always recommended that you do
+ <strong>not</strong> remove the archives, since they serve as the
+ historical record of your mailing list.
+
+ <p>For your safety, you will be asked to reconfirm the list password.
+ """)])
+ form = Form(mlist.GetScriptURL('rmlist'))
+ ftable = Table(border=0, cols='2', width='100%',
+ cellspacing=3, cellpadding=4)
+
+ ftable.AddRow([Label(_('List password:')), PasswordBox('password')])
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 0, bgcolor="#cccccc")
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 1, bgcolor="#cccccc")
+
+ ftable.AddRow([Label(_('Also delete archives?')),
+ RadioButtonArray('delarchives', ('No', 'Yes'),
+ checked=0, values=(0, 1))])
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 0, bgcolor="#cccccc")
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 1, bgcolor="#cccccc")
+
+ ftable.AddRow([Center(Link(
+ mlist.GetScriptURL('admin'),
+ _('<b>Cancel</b> and return to list administration')))])
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 0, colspan=2)
+
+ ftable.AddRow([Center(SubmitButton('doit', _('Delete this list')))])
+ ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 0, colspan=2)
+ form.AddItem(ftable)
+ table.AddRow([form])
+ doc.AddItem(table)