diff options
| author | bwarsaw | 2001-05-09 15:07:47 +0000 |
|---|---|---|
| committer | bwarsaw | 2001-05-09 15:07:47 +0000 |
| commit | ea1e6c86f57d8485481c474bb6166e0088044889 (patch) | |
| tree | 27fb7fa4f9cb0bda96f0b0fe83198f404baea789 | |
| parent | ffa133a534c3d4f7f20e7e6fd6235a9bd4cc542b (diff) | |
| download | mailman-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.py | 279 | ||||
| -rw-r--r-- | Mailman/Cgi/rmlist.py | 221 |
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) |
