diff options
| author | Barry Warsaw | 2009-01-25 13:01:41 -0500 |
|---|---|---|
| committer | Barry Warsaw | 2009-01-25 13:01:41 -0500 |
| commit | eefd06f1b88b8ecbb23a9013cd223b72ca85c20d (patch) | |
| tree | 72c947fe16fce0e07e996ee74020b26585d7e846 /mailman/web/Gui | |
| parent | 07871212f74498abd56bef3919bf3e029eb8b930 (diff) | |
| download | mailman-eefd06f1b88b8ecbb23a9013cd223b72ca85c20d.tar.gz mailman-eefd06f1b88b8ecbb23a9013cd223b72ca85c20d.tar.zst mailman-eefd06f1b88b8ecbb23a9013cd223b72ca85c20d.zip | |
Diffstat (limited to 'mailman/web/Gui')
| -rw-r--r-- | mailman/web/Gui/Archive.py | 45 | ||||
| -rw-r--r-- | mailman/web/Gui/Autoresponse.py | 99 | ||||
| -rw-r--r-- | mailman/web/Gui/Bounce.py | 195 | ||||
| -rw-r--r-- | mailman/web/Gui/ContentFilter.py | 199 | ||||
| -rw-r--r-- | mailman/web/Gui/Digest.py | 161 | ||||
| -rw-r--r-- | mailman/web/Gui/GUIBase.py | 209 | ||||
| -rw-r--r-- | mailman/web/Gui/General.py | 464 | ||||
| -rw-r--r-- | mailman/web/Gui/Language.py | 128 | ||||
| -rw-r--r-- | mailman/web/Gui/Membership.py | 34 | ||||
| -rw-r--r-- | mailman/web/Gui/NonDigest.py | 158 | ||||
| -rw-r--r-- | mailman/web/Gui/Passwords.py | 31 | ||||
| -rw-r--r-- | mailman/web/Gui/Privacy.py | 537 | ||||
| -rw-r--r-- | mailman/web/Gui/Topics.py | 162 | ||||
| -rw-r--r-- | mailman/web/Gui/Usenet.py | 140 | ||||
| -rw-r--r-- | mailman/web/Gui/__init__.py | 33 |
15 files changed, 0 insertions, 2595 deletions
diff --git a/mailman/web/Gui/Archive.py b/mailman/web/Gui/Archive.py deleted file mode 100644 index 4090e74e9..000000000 --- a/mailman/web/Gui/Archive.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (C) 2001-2009 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -from Mailman.Gui.GUIBase import GUIBase -from Mailman.configuration import config -from Mailman.i18n import _ - - - -class Archive(GUIBase): - def GetConfigCategory(self): - return 'archive', _('Archiving Options') - - def GetConfigInfo(self, mlist, category, subcat=None): - if category <> 'archive': - return None - return [ - _("List traffic archival policies."), - - ('archive', config.Toggle, (_('No'), _('Yes')), 0, - _('Archive messages?')), - - ('archive_private', config.Radio, (_('public'), _('private')), 0, - _('Is archive file source for public or private archival?')), - - ('archive_volume_frequency', config.Radio, - (_('Yearly'), _('Monthly'), _('Quarterly'), - _('Weekly'), _('Daily')), - 0, - _('How often should a new archive volume be started?')), - ] diff --git a/mailman/web/Gui/Autoresponse.py b/mailman/web/Gui/Autoresponse.py deleted file mode 100644 index 72ef42cad..000000000 --- a/mailman/web/Gui/Autoresponse.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright (C) 2001-2009 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -"""Administrative GUI for the autoresponder.""" - -from Mailman import Utils -from Mailman.Gui.GUIBase import GUIBase -from Mailman.configuration import config -from Mailman.i18n import _ - -# These are the allowable string substitution variables -ALLOWEDS = ('listname', 'listurl', 'requestemail', 'adminemail', 'owneremail') - - - -class Autoresponse(GUIBase): - def GetConfigCategory(self): - return 'autoreply', _('Auto-responder') - - def GetConfigInfo(self, mlist, category, subcat=None): - if category <> 'autoreply': - return None - WIDTH = config.TEXTFIELDWIDTH - - return [ - _("""\ -Auto-responder characteristics.<p> - -In the text fields below, string interpolation is performed with -the following key/value substitutions: -<p><ul> - <li><b>listname</b> - <em>gets the name of the mailing list</em> - <li><b>listurl</b> - <em>gets the list's listinfo URL</em> - <li><b>requestemail</b> - <em>gets the list's -request address</em> - <li><b>owneremail</b> - <em>gets the list's -owner address</em> -</ul> - -<p>For each text field, you can either enter the text directly into the text -box, or you can specify a file on your local system to upload as the text."""), - - ('autorespond_postings', config.Toggle, (_('No'), _('Yes')), 0, - _('''Should Mailman send an auto-response to mailing list - posters?''')), - - ('autoresponse_postings_text', config.FileUpload, - (6, WIDTH), 0, - _('Auto-response text to send to mailing list posters.')), - - ('autorespond_admin', config.Toggle, (_('No'), _('Yes')), 0, - _('''Should Mailman send an auto-response to emails sent to the - -owner address?''')), - - ('autoresponse_admin_text', config.FileUpload, - (6, WIDTH), 0, - _('Auto-response text to send to -owner emails.')), - - ('autorespond_requests', config.Radio, - (_('No'), _('Yes, w/discard'), _('Yes, w/forward')), 0, - _('''Should Mailman send an auto-response to emails sent to the - -request address? If you choose yes, decide whether you want - Mailman to discard the original email, or forward it on to the - system as a normal mail command.''')), - - ('autoresponse_request_text', config.FileUpload, - (6, WIDTH), 0, - _('Auto-response text to send to -request emails.')), - - ('autoresponse_graceperiod', config.Number, 3, 0, - _('''Number of days between auto-responses to either the mailing - list or -request/-owner address from the same poster. Set to - zero (or negative) for no grace period (i.e. auto-respond to - every message).''')), - ] - - def _setValue(self, mlist, property, val, doc): - # Handle these specially because we may need to convert to/from - # external $-string representation. - if property in ('autoresponse_postings_text', - 'autoresponse_admin_text', - 'autoresponse_request_text'): - val = self._convertString(mlist, property, ALLOWEDS, val, doc) - if val is None: - # There was a problem, so don't set it - return - GUIBase._setValue(self, mlist, property, val, doc) diff --git a/mailman/web/Gui/Bounce.py b/mailman/web/Gui/Bounce.py deleted file mode 100644 index a2f6f887a..000000000 --- a/mailman/web/Gui/Bounce.py +++ /dev/null @@ -1,195 +0,0 @@ -# Copyright (C) 2001-2009 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -from Mailman.Gui.GUIBase import GUIBase -from Mailman.configuration import config -from Mailman.i18n import _ - - - -class Bounce(GUIBase): - def GetConfigCategory(self): - return 'bounce', _('Bounce processing') - - def GetConfigInfo(self, mlist, category, subcat=None): - if category <> 'bounce': - return None - return [ - _("""These policies control the automatic bounce processing system - in Mailman. Here's an overview of how it works. - - <p>When a bounce is received, Mailman tries to extract two pieces - of information from the message: the address of the member the - message was intended for, and the severity of the problem causing - the bounce. The severity can be either <em>hard</em> or - <em>soft</em> meaning either a fatal error occurred, or a - transient error occurred. When in doubt, a hard severity is used. - - <p>If no member address can be extracted from the bounce, then the - bounce is usually discarded. Otherwise, each member is assigned a - <em>bounce score</em> and every time we encounter a bounce from - this member we increment the score. Hard bounces increment by 1 - while soft bounces increment by 0.5. We only increment the bounce - score once per day, so even if we receive ten hard bounces from a - member per day, their score will increase by only 1 for that day. - - <p>When a member's bounce score is greater than the - <a href="?VARHELP=bounce/bounce_score_threshold">bounce score - threshold</a>, the subscription is disabled. Once disabled, the - member will not receive any postings from the list until their - membership is explicitly re-enabled (either by the list - administrator or the user). However, they will receive occasional - reminders that their membership has been disabled, and these - reminders will include information about how to re-enable their - membership. - - <p>You can control both the - <a href="?VARHELP=bounce/bounce_you_are_disabled_warnings">number - of reminders</a> the member will receive and the - <a href="?VARHELP=bounce/bounce_you_are_disabled_warnings_interval" - >frequency</a> with which these reminders are sent. - - <p>There is one other important configuration variable; after a - certain period of time -- during which no bounces from the member - are received -- the bounce information is - <a href="?VARHELP=bounce/bounce_info_stale_after">considered - stale</a> and discarded. Thus by adjusting this value, and the - score threshold, you can control how quickly bouncing members are - disabled. You should tune both of these to the frequency and - traffic volume of your list."""), - - _('Bounce detection sensitivity'), - - ('bounce_processing', config.Toggle, (_('No'), _('Yes')), 0, - _('Should Mailman perform automatic bounce processing?'), - _("""By setting this value to <em>No</em>, you disable all - automatic bounce processing for this list, however bounce - messages will still be discarded so that the list administrator - isn't inundated with them.""")), - - ('bounce_score_threshold', config.Number, 5, 0, - _("""The maximum member bounce score before the member's - subscription is disabled. This value can be a floating point - number."""), - _("""Each subscriber is assigned a bounce score, as a floating - point number. Whenever Mailman receives a bounce from a list - member, that member's score is incremented. Hard bounces (fatal - errors) increase the score by 1, while soft bounces (temporary - errors) increase the score by 0.5. Only one bounce per day - counts against a member's score, so even if 10 bounces are - received for a member on the same day, their score will increase - by just 1. - - This variable describes the upper limit for a member's bounce - score, above which they are automatically disabled, but not - removed from the mailing list.""")), - - ('bounce_info_stale_after', config.Number, 5, 0, - _("""The number of days after which a member's bounce information - is discarded, if no new bounces have been received in the - interim. This value must be an integer.""")), - - ('bounce_you_are_disabled_warnings', config.Number, 5, 0, - _("""How many <em>Your Membership Is Disabled</em> warnings a - disabled member should get before their address is removed from - the mailing list. Set to 0 to immediately remove an address from - the list once their bounce score exceeds the threshold. This - value must be an integer.""")), - - ('bounce_you_are_disabled_warnings_interval', config.Number, 5, 0, - _("""The number of days between sending the <em>Your Membership - Is Disabled</em> warnings. This value must be an integer.""")), - - _('Notifications'), - - ('bounce_unrecognized_goes_to_list_owner', config.Toggle, - (_('No'), _('Yes')), 0, - _('''Should Mailman send you, the list owner, any bounce messages - that failed to be detected by the bounce processor? <em>Yes</em> - is recommended.'''), - _("""While Mailman's bounce detector is fairly robust, it's - impossible to detect every bounce format in the world. You - should keep this variable set to <em>Yes</em> for two reasons: 1) - If this really is a permanent bounce from one of your members, - you should probably manually remove them from your list, and 2) - you might want to send the message on to the Mailman developers - so that this new format can be added to its known set. - - <p>If you really can't be bothered, then set this variable to - <em>No</em> and all non-detected bounces will be discarded - without further processing. - - <p><b>Note:</b> This setting will also affect all messages sent - to your list's -admin address. This address is deprecated and - should never be used, but some people may still send mail to this - address. If this happens, and this variable is set to - <em>No</em> those messages too will get discarded. You may want - to set up an - <a href="?VARHELP=autoreply/autoresponse_admin_text">autoresponse - message</a> for email to the -owner and -admin address.""")), - - ('bounce_notify_owner_on_disable', config.Toggle, - (_('No'), _('Yes')), 0, - _("""Should Mailman notify you, the list owner, when bounces - cause a member's subscription to be disabled?"""), - _("""By setting this value to <em>No</em>, you turn off - notification messages that are normally sent to the list owners - when a member's delivery is disabled due to excessive bounces. - An attempt to notify the member will always be made.""")), - - ('bounce_notify_owner_on_removal', config.Toggle, - (_('No'), _('Yes')), 0, - _("""Should Mailman notify you, the list owner, when bounces - cause a member to be unsubscribed?"""), - _("""By setting this value to <em>No</em>, you turn off - notification messages that are normally sent to the list owners - when a member is unsubscribed due to excessive bounces. An - attempt to notify the member will always be made.""")), - - ] - - def _setValue(self, mlist, property, val, doc): - # Do value conversion from web representation to internal - # representation. - try: - if property == 'bounce_processing': - val = int(val) - elif property == 'bounce_score_threshold': - val = float(val) - elif property == 'bounce_info_stale_after': - val = config.days(int(val)) - elif property == 'bounce_you_are_disabled_warnings': - val = int(val) - elif property == 'bounce_you_are_disabled_warnings_interval': - val = config.days(int(val)) - elif property == 'bounce_notify_owner_on_disable': - val = int(val) - elif property == 'bounce_notify_owner_on_removal': - val = int(val) - except ValueError: - doc.addError( - _("""Bad value for <a href="?VARHELP=bounce/%(property)s" - >%(property)s</a>: %(val)s"""), - tag = _('Error: ')) - return - GUIBase._setValue(self, mlist, property, val, doc) - - def getValue(self, mlist, kind, varname, params): - if varname not in ('bounce_info_stale_after', - 'bounce_you_are_disabled_warnings_interval'): - return None - return int(getattr(mlist, varname) / config.days(1)) diff --git a/mailman/web/Gui/ContentFilter.py b/mailman/web/Gui/ContentFilter.py deleted file mode 100644 index 09817f4aa..000000000 --- a/mailman/web/Gui/ContentFilter.py +++ /dev/null @@ -1,199 +0,0 @@ -# Copyright (C) 2002-2009 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -"""GUI component managing the content filtering options.""" - -from Mailman.Gui.GUIBase import GUIBase -from Mailman.configuration import config -from Mailman.i18n import _ - -NL = '\n' - - - -class ContentFilter(GUIBase): - def GetConfigCategory(self): - return 'contentfilter', _('Content filtering') - - def GetConfigInfo(self, mlist, category, subcat=None): - if category <> 'contentfilter': - return None - WIDTH = config.TEXTFIELDWIDTH - - actions = [_('Discard'), _('Reject'), _('Forward to List Owner')] - if config.OWNERS_CAN_PRESERVE_FILTERED_MESSAGES: - actions.append(_('Preserve')) - - return [ - _("""Policies concerning the content of list traffic. - - <p>Content filtering works like this: when a message is - received by the list and you have enabled content filtering, the - individual attachments are first compared to the - <a href="?VARHELP=contentfilter/filter_mime_types">filter - types</a>. If the attachment type matches an entry in the filter - types, it is discarded. - - <p>Then, if there are <a - href="?VARHELP=contentfilter/pass_mime_types">pass types</a> - defined, any attachment type that does <em>not</em> match a - pass type is also discarded. If there are no pass types defined, - this check is skipped. - - <p>After this initial filtering, any <tt>multipart</tt> - attachments that are empty are removed. If the outer message is - left empty after this filtering, then the whole message is - discarded. - - <p> Then, each <tt>multipart/alternative</tt> section will - be replaced by just the first alternative that is non-empty after - filtering if - <a href="?VARHELP=contentfilter/collapse_alternatives" - >collapse_alternatives</a> is enabled. - - <p>Finally, any <tt>text/html</tt> parts that are left in the - message may be converted to <tt>text/plain</tt> if - <a href="?VARHELP=contentfilter/convert_html_to_plaintext" - >convert_html_to_plaintext</a> is enabled and the site is - configured to allow these conversions."""), - - ('filter_content', config.Radio, (_('No'), _('Yes')), 0, - _("""Should Mailman filter the content of list traffic according - to the settings below?""")), - - ('filter_mime_types', config.Text, (10, WIDTH), 0, - _("""Remove message attachments that have a matching content - type."""), - - _("""Use this option to remove each message attachment that - matches one of these content types. Each line should contain a - string naming a MIME <tt>type/subtype</tt>, - e.g. <tt>image/gif</tt>. Leave off the subtype to remove all - parts with a matching major content type, e.g. <tt>image</tt>. - - <p>Blank lines are ignored. - - <p>See also <a href="?VARHELP=contentfilter/pass_mime_types" - >pass_mime_types</a> for a content type whitelist.""")), - - ('pass_mime_types', config.Text, (10, WIDTH), 0, - _("""Remove message attachments that don't have a matching - content type. Leave this field blank to skip this filter - test."""), - - _("""Use this option to remove each message attachment that does - not have a matching content type. Requirements and formats are - exactly like <a href="?VARHELP=contentfilter/filter_mime_types" - >filter_mime_types</a>. - - <p><b>Note:</b> if you add entries to this list but don't add - <tt>multipart</tt> to this list, any messages with attachments - will be rejected by the pass filter.""")), - - ('filter_filename_extensions', config.Text, (10, WIDTH), 0, - _("""Remove message attachments that have a matching filename - extension."""),), - - ('pass_filename_extensions', config.Text, (10, WIDTH), 0, - _("""Remove message attachments that don't have a matching - filename extension. Leave this field blank to skip this filter - test."""),), - - ('collapse_alternatives', config.Radio, (_('No'), _('Yes')), 0, - _("""Should Mailman collapse multipart/alternative to its - first part content?""")), - - ('convert_html_to_plaintext', config.Radio, (_('No'), _('Yes')), 0, - _("""Should Mailman convert <tt>text/html</tt> parts to plain - text? This conversion happens after MIME attachments have been - stripped.""")), - - ('filter_action', config.Radio, tuple(actions), 0, - - _("""Action to take when a message matches the content filtering - rules."""), - - _("""One of these actions is take when the message matches one of - the content filtering rules, meaning, the top-level - content type matches one of the <a - href="?VARHELP=contentfilter/filter_mime_types" - >filter_mime_types</a>, or the top-level content type does - <strong>not</strong> match one of the - <a href="?VARHELP=contentfilter/pass_mime_types" - >pass_mime_types</a>, or if after filtering the subparts of the - message, the message ends up empty. - - <p>Note this action is not taken if after filtering the message - still contains content. In that case the message is always - forwarded on to the list membership. - - <p>When messages are discarded, a log entry is written - containing the Message-ID of the discarded message. When - messages are rejected or forwarded to the list owner, a reason - for the rejection is included in the bounce message to the - original author. When messages are preserved, they are saved in - a special queue directory on disk for the site administrator to - view (and possibly rescue) but otherwise discarded. This last - option is only available if enabled by the site - administrator.""")), - ] - - def _setValue(self, mlist, property, val, doc): - if property in ('filter_mime_types', 'pass_mime_types'): - types = [] - for spectype in [s.strip() for s in val.splitlines()]: - ok = 1 - slashes = spectype.count('/') - if slashes == 0 and not spectype: - ok = 0 - elif slashes == 1: - maintype, subtype = [s.strip().lower() - for s in spectype.split('/')] - if not maintype or not subtype: - ok = 0 - elif slashes > 1: - ok = 0 - if not ok: - doc.addError(_('Bad MIME type ignored: %(spectype)s')) - else: - types.append(spectype.strip().lower()) - if property == 'filter_mime_types': - mlist.filter_mime_types = types - elif property == 'pass_mime_types': - mlist.pass_mime_types = types - elif property in ('filter_filename_extensions', - 'pass_filename_extensions'): - fexts = [] - for ext in [s.strip() for s in val.splitlines()]: - fexts.append(ext.lower()) - if property == 'filter_filename_extensions': - mlist.filter_filename_extensions = fexts - elif property == 'pass_filename_extensions': - mlist.pass_filename_extensions = fexts - else: - GUIBase._setValue(self, mlist, property, val, doc) - - def getValue(self, mlist, kind, property, params): - if property == 'filter_mime_types': - return NL.join(mlist.filter_mime_types) - if property == 'pass_mime_types': - return NL.join(mlist.pass_mime_types) - if property == 'filter_filename_extensions': - return NL.join(mlist.filter_filename_extensions) - if property == 'pass_filename_extensions': - return NL.join(mlist.pass_filename_extensions) - return None diff --git a/mailman/web/Gui/Digest.py b/mailman/web/Gui/Digest.py deleted file mode 100644 index 821d0684f..000000000 --- a/mailman/web/Gui/Digest.py +++ /dev/null @@ -1,161 +0,0 @@ -# Copyright (C) 1998-2009 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -"""Administrative GUI for digest deliveries.""" - -from Mailman import Utils -from Mailman.configuration import config -from Mailman.i18n import _ - -# Intra-package import -from Mailman.Gui.GUIBase import GUIBase - -# Common b/w nondigest and digest headers & footers. Personalizations may add -# to this. -ALLOWEDS = ('real_name', 'list_name', 'host_name', 'web_page_url', - 'description', 'info', 'cgiext', '_internal_name', - ) - - - -class Digest(GUIBase): - def GetConfigCategory(self): - return 'digest', _('Digest options') - - def GetConfigInfo(self, mlist, category, subcat=None): - if category <> 'digest': - return None - WIDTH = config.TEXTFIELDWIDTH - - info = [ - _("Batched-delivery digest characteristics."), - - ('digestable', config.Toggle, (_('No'), _('Yes')), 1, - _('Can list members choose to receive list traffic ' - 'bunched in digests?')), - - ('digest_is_default', config.Radio, - (_('Regular'), _('Digest')), 0, - _('Which delivery mode is the default for new users?')), - - ('mime_is_default_digest', config.Radio, - (_('Plain'), _('MIME')), 0, - _('When receiving digests, which format is default?')), - - ('digest_size_threshhold', config.Number, 3, 0, - _('How big in Kb should a digest be before it gets sent out?')), - # Should offer a 'set to 0' for no size threshhold. - - ('digest_send_periodic', config.Radio, (_('No'), _('Yes')), 1, - _('Should a digest be dispatched daily when the size threshold ' - "isn't reached?")), - - ('digest_header', config.Text, (4, WIDTH), 0, - _('Header added to every digest'), - _("Text attached (as an initial message, before the table" - " of contents) to the top of digests. ") - + Utils.maketext('headfoot.html', raw=1, mlist=mlist)), - - ('digest_footer', config.Text, (4, WIDTH), 0, - _('Footer added to every digest'), - _("Text attached (as a final message) to the bottom of digests. ") - + Utils.maketext('headfoot.html', raw=1, mlist=mlist)), - - ('digest_volume_frequency', config.Radio, - (_('Yearly'), _('Monthly'), _('Quarterly'), - _('Weekly'), _('Daily')), 0, - _('How often should a new digest volume be started?'), - _('''When a new digest volume is started, the volume number is - incremented and the issue number is reset to 1.''')), - - ('_new_volume', config.Toggle, (_('No'), _('Yes')), 0, - _('Should Mailman start a new digest volume?'), - _('''Setting this option instructs Mailman to start a new volume - with the next digest sent out.''')), - - ('_send_digest_now', config.Toggle, (_('No'), _('Yes')), 0, - _('''Should Mailman send the next digest right now, if it is not - empty?''')), - ] - -## if config.OWNERS_CAN_ENABLE_PERSONALIZATION: -## info.extend([ -## ('digest_personalize', config.Toggle, (_('No'), _('Yes')), 1, - -## _('''Should Mailman personalize each digest delivery? -## This is often useful for announce-only lists, but <a -## href="?VARHELP=digest/digest_personalize">read the details</a> -## section for a discussion of important performance -## issues.'''), - -## _("""Normally, Mailman sends the digest messages to -## the mail server in batches. This is much more efficent -## because it reduces the amount of traffic between Mailman and -## the mail server. - -## <p>However, some lists can benefit from a more personalized -## approach. In this case, Mailman crafts a new message for -## each member on the digest delivery list. Turning this on -## adds a few more expansion variables that can be included in -## the <a href="?VARHELP=digest/digest_header">message header</a> -## and <a href="?VARHELP=digest/digest_footer">message footer</a> -## but it may degrade the performance of your site as -## a whole. - -## <p>You need to carefully consider whether the trade-off is -## worth it, or whether there are other ways to accomplish what -## you want. You should also carefully monitor your system load -## to make sure it is acceptable. - -## <p>These additional substitution variables will be available -## for your headers and footers, when this feature is enabled: - -## <ul><li><b>user_address</b> - The address of the user, -## coerced to lower case. -## <li><b>user_delivered_to</b> - The case-preserved address -## that the user is subscribed with. -## <li><b>user_password</b> - The user's password. -## <li><b>user_name</b> - The user's full name. -## <li><b>user_optionsurl</b> - The url to the user's option -## page. -## """)) -## ]) - - return info - - def _setValue(self, mlist, property, val, doc): - # Watch for the special, immediate action attributes - if property == '_new_volume' and val: - mlist.bump_digest_volume() - volume = mlist.volume - number = mlist.next_digest_number - doc.AddItem(_("""The next digest will be sent as volume - %(volume)s, number %(number)s""")) - elif property == '_send_digest_now' and val: - status = mlist.send_digest_now() - if status: - doc.AddItem(_("""A digest has been sent.""")) - else: - doc.AddItem(_("""There was no digest to send.""")) - else: - # Everything else... - if property in ('digest_header', 'digest_footer'): - val = self._convertString(mlist, property, ALLOWEDS, val, doc) - if val is None: - # There was a problem, so don't set it - return - GUIBase._setValue(self, mlist, property, val, doc) diff --git a/mailman/web/Gui/GUIBase.py b/mailman/web/Gui/GUIBase.py deleted file mode 100644 index b2846eb7b..000000000 --- a/mailman/web/Gui/GUIBase.py +++ /dev/null @@ -1,209 +0,0 @@ -# Copyright (C) 2002-2009 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -"""Base class for all web GUI components.""" - -import re - -from Mailman import Defaults -from Mailman import Errors -from Mailman import Utils -from Mailman.i18n import _ - -NL = '\n' -BADJOINER = '</code>, <code>' - - - -class GUIBase: - # Providing a common interface for GUI component form processing. Most - # GUI components won't need to override anything, but some may want to - # override _setValue() to provide some specialized processing for some - # attributes. - def _getValidValue(self, mlist, property, wtype, val): - # Coerce and validate the new value. - # - # Radio buttons and boolean toggles both have integral type - if wtype in (Defaults.Radio, Defaults.Toggle): - # Let ValueErrors propagate - return int(val) - # String and Text widgets both just return their values verbatim - # but convert into unicode (for 2.2) - if wtype in (Defaults.String, Defaults.Text): - return unicode(val, Utils.GetCharSet(mlist.preferred_language)) - # This widget contains a single email address - if wtype == Defaults.Email: - # BAW: We must allow blank values otherwise reply_to_address can't - # be cleared. This is currently the only Defaults.Email type - # widget in the interface, so watch out if we ever add any new - # ones. - if val: - # Let InvalidEmailAddress propagate. - Utils.ValidateEmail(val) - return val - # These widget types contain lists of email addresses, one per line. - # The EmailListEx allows each line to contain either an email address - # or a regular expression - if wtype in (Defaults.EmailList, Defaults.EmailListEx): - # BAW: value might already be a list, if this is coming from - # config_list input. Sigh. - if isinstance(val, list): - return val - addrs = [] - for addr in [s.strip() for s in val.split(NL)]: - # Discard empty lines - if not addr: - continue - try: - # This throws an exception if the address is invalid - Utils.ValidateEmail(addr) - except Errors.EmailAddressError: - # See if this is a context that accepts regular - # expressions, and that the re is legal - if wtype == Defaults.EmailListEx and addr.startswith('^'): - try: - re.compile(addr) - except re.error: - raise ValueError - else: - raise - addrs.append(addr) - return addrs - # This is a host name, i.e. verbatim - if wtype == Defaults.Host: - return val - # This is a number, either a float or an integer - if wtype == Defaults.Number: - num = -1 - try: - num = int(val) - except ValueError: - # Let ValueErrors percolate up - num = float(val) - if num < 0: - return getattr(mlist, property) - return num - # This widget is a select box, i.e. verbatim - if wtype == Defaults.Select: - return val - # Checkboxes return a list of the selected items, even if only one is - # selected. - if wtype == Defaults.Checkbox: - if isinstance(val, list): - return val - return [val] - if wtype == Defaults.FileUpload: - return val - if wtype == Defaults.Topics: - return val - if wtype == Defaults.HeaderFilter: - return val - # Should never get here - assert 0, 'Bad gui widget type: %s' % wtype - - def _setValue(self, mlist, property, val, doc): - # Set the value, or override to take special action on the property - if not property.startswith('_') and getattr(mlist, property) <> val: - setattr(mlist, property, val) - - def _postValidate(self, mlist, doc): - # Validate all the attributes for this category - pass - - def _escape(self, property, value): - value = value.replace('<', '<') - return value - - def handleForm(self, mlist, category, subcat, cgidata, doc): - for item in self.GetConfigInfo(mlist, category, subcat): - # Skip descriptions and legacy non-attributes - if not isinstance(item, tuple) or len(item) < 5: - continue - # Unpack the gui item description - property, wtype, args, deps, desc = item[0:5] - # BAW: I know this code is a little crufty but I wanted to - # reproduce the semantics of the original code in admin.py as - # closely as possible, for now. We can clean it up later. - # - # The property may be uploadable... - uploadprop = property + '_upload' - if cgidata.has_key(uploadprop) and cgidata[uploadprop].value: - val = cgidata[uploadprop].value - elif not cgidata.has_key(property): - continue - elif isinstance(cgidata[property], list): - val = [self._escape(property, x.value) - for x in cgidata[property]] - else: - val = self._escape(property, cgidata[property].value) - # Coerce the value to the expected type, raising exceptions if the - # value is invalid. - try: - val = self._getValidValue(mlist, property, wtype, val) - except ValueError: - doc.addError(_('Invalid value for variable: %(property)s')) - # This is the parent of InvalidEmailAddress - except Errors.EmailAddressError: - doc.addError( - _('Bad email address for option %(property)s: %(val)s')) - else: - # Set the attribute, which will normally delegate to the mlist - self._setValue(mlist, property, val, doc) - # Do a final sweep once all the attributes have been set. This is how - # we can do cross-attribute assertions - self._postValidate(mlist, doc) - - # Convenience method for handling $-string attributes - def _convertString(self, mlist, property, alloweds, val, doc): - # Is the list using $-strings? - dollarp = getattr(mlist, 'use_dollar_strings', 0) - if dollarp: - ids = Utils.dollar_identifiers(val) - else: - # %-strings - ids = Utils.percent_identifiers(val) - # Here's the list of allowable interpolations - for allowed in alloweds: - if ids.has_key(allowed): - del ids[allowed] - if ids: - # What's left are not allowed - badkeys = ids.keys() - badkeys.sort() - bad = BADJOINER.join(badkeys) - doc.addError(_( - """The following illegal substitution variables were - found in the <code>%(property)s</code> string: - <code>%(bad)s</code> - <p>Your list may not operate properly until you correct this - problem."""), tag=_('Warning: ')) - return val - # Now if we're still using %-strings, do a roundtrip conversion and - # see if the converted value is the same as the new value. If not, - # then they probably left off a trailing `s'. We'll warn them and use - # the corrected string. - if not dollarp: - fixed = Utils.to_percent(Utils.to_dollar(val)) - if fixed <> val: - doc.addError(_( - """Your <code>%(property)s</code> string appeared to - have some correctable problems in its new value. - The fixed value will be used instead. Please - double check that this is what you intended. - """)) - return fixed - return val diff --git a/mailman/web/Gui/General.py b/mailman/web/Gui/General.py deleted file mode 100644 index 27ef354be..000000000 --- a/mailman/web/Gui/General.py +++ /dev/null @@ -1,464 +0,0 @@ -# Copyright (C) 2001-2009 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -"""MailList mixin class managing the general options.""" - -import re - -from Mailman import Errors -from Mailman import Utils -from Mailman.Gui.GUIBase import GUIBase -from Mailman.configuration import config -from Mailman.i18n import _ - -OPTIONS = ('hide', 'ack', 'notmetoo', 'nodupes') - - - -class General(GUIBase): - def GetConfigCategory(self): - return 'general', _('General Options') - - def GetConfigInfo(self, mlist, category, subcat): - if category <> 'general': - return None - WIDTH = config.TEXTFIELDWIDTH - - # These are for the default_options checkboxes below. - bitfields = {'hide' : config.ConcealSubscription, - 'ack' : config.AcknowledgePosts, - 'notmetoo' : config.DontReceiveOwnPosts, - 'nodupes' : config.DontReceiveDuplicates - } - bitdescrs = { - 'hide' : _("Conceal the member's address"), - 'ack' : _("Acknowledge the member's posting"), - 'notmetoo' : _("Do not send a copy of a member's own post"), - 'nodupes' : - _('Filter out duplicate messages to list members (if possible)'), - } - - optvals = [mlist.new_member_options & bitfields[o] for o in OPTIONS] - opttext = [bitdescrs[o] for o in OPTIONS] - - rtn = [ - _('''Fundamental list characteristics, including descriptive - info and basic behaviors.'''), - - _('General list personality'), - - ('real_name', config.String, WIDTH, 0, - _('The public name of this list (make case-changes only).'), - _('''The capitalization of this name can be changed to make it - presentable in polite company as a proper noun, or to make an - acronym part all upper case, etc. However, the name will be - advertised as the email address (e.g., in subscribe confirmation - notices), so it should <em>not</em> be otherwise altered. (Email - addresses are not case sensitive, but they are sensitive to - almost everything else :-)''')), - - ('owner', config.EmailList, (3, WIDTH), 0, - _("""The list administrator email addresses. Multiple - administrator addresses, each on separate line is okay."""), - - _('''There are two ownership roles associated with each mailing - list. The <em>list administrators</em> are the people who have - ultimate control over all parameters of this mailing list. They - are able to change any list configuration variable available - through these administration web pages. - - <p>The <em>list moderators</em> have more limited permissions; - they are not able to change any list configuration variable, but - they are allowed to tend to pending administration requests, - including approving or rejecting held subscription requests, and - disposing of held postings. Of course, the <em>list - administrators</em> can also tend to pending requests. - - <p>In order to split the list ownership duties into - administrators and moderators, you must - <a href="passwords">set a separate moderator password</a>, - and also provide the <a href="?VARHELP=general/moderator">email - addresses of the list moderators</a>. Note that the field you - are changing here specifies the list administrators.''')), - - ('moderator', config.EmailList, (3, WIDTH), 0, - _("""The list moderator email addresses. Multiple - moderator addresses, each on separate line is okay."""), - - _('''There are two ownership roles associated with each mailing - list. The <em>list administrators</em> are the people who have - ultimate control over all parameters of this mailing list. They - are able to change any list configuration variable available - through these administration web pages. - - <p>The <em>list moderators</em> have more limited permissions; - they are not able to change any list configuration variable, but - they are allowed to tend to pending administration requests, - including approving or rejecting held subscription requests, and - disposing of held postings. Of course, the <em>list - administrators</em> can also tend to pending requests. - - <p>In order to split the list ownership duties into - administrators and moderators, you must - <a href="passwords">set a separate moderator password</a>, - and also provide the email addresses of the list moderators in - this section. Note that the field you are changing here - specifies the list moderators.''')), - - ('description', config.String, WIDTH, 0, - _('A terse phrase identifying this list.'), - - _('''This description is used when the mailing list is listed with - other mailing lists, or in headers, and so forth. It should - be as succinct as you can get it, while still identifying what - the list is.''')), - - ('info', config.Text, (7, WIDTH), 0, - _('''An introductory description - a few paragraphs - about the - list. It will be included, as html, at the top of the listinfo - page. Carriage returns will end a paragraph - see the details - for more info.'''), - _("""The text will be treated as html <em>except</em> that - newlines will be translated to <br> - so you can use links, - preformatted text, etc, but don't put in carriage returns except - where you mean to separate paragraphs. And review your changes - - bad html (like some unterminated HTML constructs) can prevent - display of the entire listinfo page.""")), - - ('subject_prefix', config.String, WIDTH, 0, - _('Prefix for subject line of list postings.'), - _("""This text will be prepended to subject lines of messages - posted to the list, to distinguish mailing list messages in in - mailbox summaries. Brevity is premium here, it's ok to shorten - long mailing list names to something more concise, as long as it - still identifies the mailing list. - You can also add a sequencial number by %%d substitution - directive. eg.; [listname %%d] -> [listname 123] - (listname %%05d) -> (listname 00123) - """)), - - ('anonymous_list', config.Radio, (_('No'), _('Yes')), 0, - _("""Hide the sender of a message, replacing it with the list - address (Removes From, Sender and Reply-To fields)""")), - - _('''<tt>Reply-To:</tt> header munging'''), - - ('first_strip_reply_to', config.Radio, (_('No'), _('Yes')), 0, - _('''Should any existing <tt>Reply-To:</tt> header found in the - original message be stripped? If so, this will be done - regardless of whether an explict <tt>Reply-To:</tt> header is - added by Mailman or not.''')), - - ('reply_goes_to_list', config.Radio, - (_('Poster'), _('This list'), _('Explicit address')), 0, - _('''Where are replies to list messages directed? - <tt>Poster</tt> is <em>strongly</em> recommended for most mailing - lists.'''), - - # Details for reply_goes_to_list - _("""This option controls what Mailman does to the - <tt>Reply-To:</tt> header in messages flowing through this - mailing list. When set to <em>Poster</em>, no <tt>Reply-To:</tt> - header is added by Mailman, although if one is present in the - original message, it is not stripped. Setting this value to - either <em>This list</em> or <em>Explicit address</em> causes - Mailman to insert a specific <tt>Reply-To:</tt> header in all - messages, overriding the header in the original message if - necessary (<em>Explicit address</em> inserts the value of <a - href="?VARHELP=general/reply_to_address">reply_to_address</a>). - - <p>There are many reasons not to introduce or override the - <tt>Reply-To:</tt> header. One is that some posters depend on - their own <tt>Reply-To:</tt> settings to convey their valid - return address. Another is that modifying <tt>Reply-To:</tt> - makes it much more difficult to send private replies. See <a - href="http://www.unicom.com/pw/reply-to-harmful.html">`Reply-To' - Munging Considered Harmful</a> for a general discussion of this - issue. See <a - href="http://www.metasystema.net/essays/reply-to.mhtml">Reply-To - Munging Considered Useful</a> for a dissenting opinion. - - <p>Some mailing lists have restricted posting privileges, with a - parallel list devoted to discussions. Examples are `patches' or - `checkin' lists, where software changes are posted by a revision - control system, but discussion about the changes occurs on a - developers mailing list. To support these types of mailing - lists, select <tt>Explicit address</tt> and set the - <tt>Reply-To:</tt> address below to point to the parallel - list.""")), - - ('reply_to_address', config.Email, WIDTH, 0, - _('Explicit <tt>Reply-To:</tt> header.'), - # Details for reply_to_address - _("""This is the address set in the <tt>Reply-To:</tt> header - when the <a - href="?VARHELP=general/reply_goes_to_list">reply_goes_to_list</a> - option is set to <em>Explicit address</em>. - - <p>There are many reasons not to introduce or override the - <tt>Reply-To:</tt> header. One is that some posters depend on - their own <tt>Reply-To:</tt> settings to convey their valid - return address. Another is that modifying <tt>Reply-To:</tt> - makes it much more difficult to send private replies. See <a - href="http://www.unicom.com/pw/reply-to-harmful.html">`Reply-To' - Munging Considered Harmful</a> for a general discussion of this - issue. See <a - href="http://www.metasystema.net/essays/reply-to.mhtml">Reply-To - Munging Considered Useful</a> for a dissenting opinion. - - <p>Some mailing lists have restricted posting privileges, with a - parallel list devoted to discussions. Examples are `patches' or - `checkin' lists, where software changes are posted by a revision - control system, but discussion about the changes occurs on a - developers mailing list. To support these types of mailing - lists, specify the explicit <tt>Reply-To:</tt> address here. You - must also specify <tt>Explicit address</tt> in the - <tt>reply_goes_to_list</tt> - variable. - - <p>Note that if the original message contains a - <tt>Reply-To:</tt> header, it will not be changed.""")), - - _('Umbrella list settings'), - - ('umbrella_list', config.Radio, (_('No'), _('Yes')), 0, - _('''Send password reminders to, eg, "-owner" address instead of - directly to user.'''), - - _("""Set this to yes when this list is intended to cascade only - to other mailing lists. When set, meta notices like - confirmations and password reminders will be directed to an - address derived from the member\'s address - it will have the - value of "umbrella_member_suffix" appended to the member's - account name.""")), - - ('umbrella_member_suffix', config.String, WIDTH, 0, - _('''Suffix for use when this list is an umbrella for other - lists, according to setting of previous "umbrella_list" - setting.'''), - - _("""When "umbrella_list" is set to indicate that this list has - other mailing lists as members, then administrative notices like - confirmations and password reminders need to not be sent to the - member list addresses, but rather to the owner of those member - lists. In that case, the value of this setting is appended to - the member's account name for such notices. `-owner' is the - typical choice. This setting has no effect when "umbrella_list" - is "No".""")), - - _('Notifications'), - - ('send_reminders', config.Radio, (_('No'), _('Yes')), 0, - _('''Send monthly password reminders?'''), - - _('''Turn this on if you want password reminders to be sent once - per month to your members. Note that members may disable their - own individual password reminders.''')), - - ('welcome_msg', config.Text, (4, WIDTH), 0, - _('''List-specific text prepended to new-subscriber welcome - message'''), - - _("""This value, if any, will be added to the front of the - new-subscriber welcome message. The rest of the welcome message - already describes the important addresses and URLs for the - mailing list, so you don't need to include any of that kind of - stuff here. This should just contain mission-specific kinds of - things, like etiquette policies or team orientation, or that kind - of thing. - - <p>Note that this text will be wrapped, according to the - following rules: - <ul><li>Each paragraph is filled so that no line is longer than - 70 characters. - <li>Any line that begins with whitespace is not filled. - <li>A blank line separates paragraphs. - </ul>""")), - - ('send_welcome_msg', config.Radio, (_('No'), _('Yes')), 0, - _('Send welcome message to newly subscribed members?'), - _("""Turn this off only if you plan on subscribing people manually - and don't want them to know that you did so. This option is most - useful for transparently migrating lists from some other mailing - list manager to Mailman.""")), - - ('goodbye_msg', config.Text, (4, WIDTH), 0, - _('''Text sent to people leaving the list. If empty, no special - text will be added to the unsubscribe message.''')), - - ('send_goodbye_msg', config.Radio, (_('No'), _('Yes')), 0, - _('Send goodbye message to members when they are unsubscribed?')), - - ('admin_immed_notify', config.Radio, (_('No'), _('Yes')), 0, - _('''Should the list moderators get immediate notice of new - requests, as well as daily notices about collected ones?'''), - - _('''List moderators (and list administrators) are sent daily - reminders of requests pending approval, like subscriptions to a - moderated list, or postings that are being held for one reason or - another. Setting this option causes notices to be sent - immediately on the arrival of new requests as well.''')), - - ('admin_notify_mchanges', config.Radio, (_('No'), _('Yes')), 0, - _('''Should administrator get notices of subscribes and - unsubscribes?''')), - - ('respond_to_post_requests', config.Radio, - (_('No'), _('Yes')), 0, - _('Send mail to poster when their posting is held for approval?') - ), - - _('Additional settings'), - - ('emergency', config.Toggle, (_('No'), _('Yes')), 0, - _('Emergency moderation of all list traffic.'), - _("""When this option is enabled, all list traffic is emergency - moderated, i.e. held for moderation. Turn this option on when - your list is experiencing a flamewar and you want a cooling off - period.""")), - - ('new_member_options', config.Checkbox, - (opttext, optvals, 0, OPTIONS), - # The description for new_member_options includes a kludge where - # we add a hidden field so that even when all the checkboxes are - # deselected, the form data will still have a new_member_options - # key (it will always be a list). Otherwise, we'd never be able - # to tell if all were deselected! - 0, _('''Default options for new members joining this list.<input - type="hidden" name="new_member_options" value="ignore">'''), - - _("""When a new member is subscribed to this list, their initial - set of options is taken from the this variable's setting.""")), - - ('administrivia', config.Radio, (_('No'), _('Yes')), 0, - _('''(Administrivia filter) Check postings and intercept ones - that seem to be administrative requests?'''), - - _("""Administrivia tests will check postings to see whether it's - really meant as an administrative request (like subscribe, - unsubscribe, etc), and will add it to the the administrative - requests queue, notifying the administrator of the new request, - in the process.""")), - - ('max_message_size', config.Number, 7, 0, - _('''Maximum length in kilobytes (KB) of a message body. Use 0 - for no limit.''')), - - ('host_name', config.Host, WIDTH, 0, - _('Host name this list prefers for email.'), - - _("""The "host_name" is the preferred name for email to - mailman-related addresses on this host, and generally should be - the mail host's exchanger address, if any. This setting can be - useful for selecting among alternative names of a host that has - multiple addresses.""")), - - ] - - if config.ALLOW_RFC2369_OVERRIDES: - rtn.append( - ('include_rfc2369_headers', config.Radio, - (_('No'), _('Yes')), 0, - _("""Should messages from this mailing list include the - <a href="http://www.faqs.org/rfcs/rfc2369.html">RFC 2369</a> - (i.e. <tt>List-*</tt>) headers? <em>Yes</em> is highly - recommended."""), - - _("""RFC 2369 defines a set of List-* headers that are - normally added to every message sent to the list membership. - These greatly aid end-users who are using standards compliant - mail readers. They should normally always be enabled. - - <p>However, not all mail readers are standards compliant yet, - and if you have a large number of members who are using - non-compliant mail readers, they may be annoyed at these - headers. You should first try to educate your members as to - why these headers exist, and how to hide them in their mail - clients. As a last resort you can disable these headers, but - this is not recommended (and in fact, your ability to disable - these headers may eventually go away).""")) - ) - # Suppression of List-Post: headers - rtn.append( - ('include_list_post_header', config.Radio, - (_('No'), _('Yes')), 0, - _('Should postings include the <tt>List-Post:</tt> header?'), - _("""The <tt>List-Post:</tt> header is one of the headers - recommended by - <a href="http://www.faqs.org/rfcs/rfc2369.html">RFC 2369</a>. - However for some <em>announce-only</em> mailing lists, only a - very select group of people are allowed to post to the list; the - general membership is usually not allowed to post. For lists of - this nature, the <tt>List-Post:</tt> header is misleading. - Select <em>No</em> to disable the inclusion of this header. (This - does not affect the inclusion of the other <tt>List-*:</tt> - headers.)""")) - ) - - # Discard held messages after this number of days - rtn.append( - ('max_days_to_hold', config.Number, 7, 0, - _("""Discard held messages older than this number of days. - Use 0 for no automatic discarding.""")) - ) - - return rtn - - def _setValue(self, mlist, property, val, doc): - if property == 'real_name' and \ - val.lower() <> mlist.internal_name().lower(): - # These values can't differ by other than case - doc.addError(_("""<b>real_name</b> attribute not - changed! It must differ from the list's name by case - only.""")) - elif property == 'new_member_options': - newopts = 0 - for opt in OPTIONS: - bitfield = config.OPTINFO[opt] - if opt in val: - newopts |= bitfield - mlist.new_member_options = newopts - elif property == 'subject_prefix': - # Convert any html entities to Unicode - mlist.subject_prefix = Utils.canonstr( - val, mlist.preferred_language) - else: - GUIBase._setValue(self, mlist, property, val, doc) - - def _escape(self, property, value): - # The 'info' property allows HTML, but lets sanitize it to avoid XSS - # exploits. Everything else should be fully escaped. - if property <> 'info': - return GUIBase._escape(self, property, value) - # Sanitize <script> and </script> tags but nothing else. Not the best - # solution, but expedient. - return re.sub(r'<([/]?script.*?)>', r'<\1>', value) - - def _postValidate(self, mlist, doc): - if not mlist.reply_to_address.strip() and \ - mlist.reply_goes_to_list == 2: - # You can't go to an explicit address that is blank - doc.addError(_("""You cannot add a Reply-To: to an explicit - address if that address is blank. Resetting these values.""")) - mlist.reply_to_address = '' - mlist.reply_goes_to_list = 0 - - def getValue(self, mlist, kind, varname, params): - if varname <> 'subject_prefix': - return None - # The subject_prefix may be Unicode - return Utils.uncanonstr(mlist.subject_prefix, mlist.preferred_language) diff --git a/mailman/web/Gui/Language.py b/mailman/web/Gui/Language.py deleted file mode 100644 index 05824be5e..000000000 --- a/mailman/web/Gui/Language.py +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (C) 2001-2009 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -"""MailList mixin class managing the language options.""" - -import codecs - -from Mailman import Utils -from Mailman import i18n -from Mailman.Gui.GUIBase import GUIBase -from Mailman.configuration import config - -_ = i18n._ - - - -class Language(GUIBase): - def GetConfigCategory(self): - return 'language', _('Language options') - - def GetConfigInfo(self, mlist, category, subcat=None): - if category <> 'language': - return None - # Set things up for the language choices - langs = mlist.language_codes - langnames = [_(description) for description in config.enabled_names] - try: - langi = langs.index(mlist.preferred_language) - except ValueError: - # Someone must have deleted the list's preferred language. Could - # be other trouble lurking! - langi = 0 - # Only allow the admin to choose a language if the system has a - # charset for it. I think this is the best way to test for that. - def checkcodec(charset): - try: - codecs.lookup(charset) - return 1 - except LookupError: - return 0 - - all = sorted(code for code in config.languages.enabled_codes - if checkcodec(Utils.GetCharSet(code))) - checked = [L in langs for L in all] - allnames = [_(config.languages.get_description(code)) for code in all] - return [ - _('Natural language (internationalization) options.'), - - ('preferred_language', config.Select, - (langs, langnames, langi), - 0, - _('Default language for this list.'), - _('''This is the default natural language for this mailing list. - If <a href="?VARHELP=language/available_languages">more than one - language</a> is supported then users will be able to select their - own preferences for when they interact with the list. All other - interactions will be conducted in the default language. This - applies to both web-based and email-based messages, but not to - email posted by list members.''')), - - ('available_languages', config.Checkbox, - (allnames, checked, 0, all), 0, - _('Languages supported by this list.'), - - _('''These are all the natural languages supported by this list. - Note that the - <a href="?VARHELP=language/preferred_language">default - language</a> must be included.''')), - - ('encode_ascii_prefixes', config.Radio, - (_('Never'), _('Always'), _('As needed')), 0, - _("""Encode the - <a href="?VARHELP=general/subject_prefix">subject - prefix</a> even when it consists of only ASCII characters?"""), - - _("""If your mailing list's default language uses a non-ASCII - character set and the prefix contains non-ASCII characters, the - prefix will always be encoded according to the relevant - standards. However, if your prefix contains only ASCII - characters, you may want to set this option to <em>Never</em> to - disable prefix encoding. This can make the subject headers - slightly more readable for users with mail readers that don't - properly handle non-ASCII encodings. - - <p>Note however, that if your mailing list receives both encoded - and unencoded subject headers, you might want to choose <em>As - needed</em>. Using this setting, Mailman will not encode ASCII - prefixes when the rest of the header contains only ASCII - characters, but if the original header contains non-ASCII - characters, it will encode the prefix. This avoids an ambiguity - in the standards which could cause some mail readers to display - extra, or missing spaces between the prefix and the original - header.""")), - - ] - - def _setValue(self, mlist, prop, val, doc): - # If we're changing the list's preferred language, change the I18N - # context as well - if prop == 'preferred_language': - i18n.set_language(val) - doc.set_language(val) - # Language codes must be wrapped - if prop == 'available_languages': - mlist.set_languages(*val) - else: - GUIBase._setValue(self, mlist, prop, val, doc) - - def getValue(self, mlist, kind, varname, params): - if varname == 'available_languages': - # Unwrap Language instances, to return just the code - return [language.code for language in mlist.available_languages] - # Returning None tells the infrastructure to use getattr - return None diff --git a/mailman/web/Gui/Membership.py b/mailman/web/Gui/Membership.py deleted file mode 100644 index bbfdb438b..000000000 --- a/mailman/web/Gui/Membership.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (C) 2001-2009 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -"""MailList mixin class managing the membership pseudo-options.""" - -from Mailman.i18n import _ - - - -class Membership: - def GetConfigCategory(self): - return 'members', _('Membership Management...') - - def GetConfigSubCategories(self, category): - if category == 'members': - return [('list', _('Membership List')), - ('add', _('Mass Subscription')), - ('remove', _('Mass Removal')), - ] - return None diff --git a/mailman/web/Gui/NonDigest.py b/mailman/web/Gui/NonDigest.py deleted file mode 100644 index 92fb768ad..000000000 --- a/mailman/web/Gui/NonDigest.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright (C) 2001-2009 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -"""GUI component for managing the non-digest delivery options.""" - -from Mailman import Utils -from Mailman import Defaults -from Mailman.i18n import _ -from Mailman.configuration import config -from Mailman.Gui.GUIBase import GUIBase - -from Mailman.Gui.Digest import ALLOWEDS -PERSONALIZED_ALLOWEDS = ('user_address', 'user_delivered_to', 'user_password', - 'user_name', 'user_optionsurl', - ) - - - -class NonDigest(GUIBase): - def GetConfigCategory(self): - return 'nondigest', _('Non-digest options') - - def GetConfigInfo(self, mlist, category, subcat=None): - if category <> 'nondigest': - return None - WIDTH = config.TEXTFIELDWIDTH - - info = [ - _("Policies concerning immediately delivered list traffic."), - - ('nondigestable', Defaults.Toggle, (_('No'), _('Yes')), 1, - _("""Can subscribers choose to receive mail immediately, rather - than in batched digests?""")), - ] - - if config.OWNERS_CAN_ENABLE_PERSONALIZATION: - info.extend([ - ('personalize', Defaults.Radio, - (_('No'), _('Yes'), _('Full Personalization')), 1, - - _('''Should Mailman personalize each non-digest delivery? - This is often useful for announce-only lists, but <a - href="?VARHELP=nondigest/personalize">read the details</a> - section for a discussion of important performance - issues.'''), - - _("""Normally, Mailman sends the regular delivery messages to - the mail server in batches. This is much more efficent - because it reduces the amount of traffic between Mailman and - the mail server. - - <p>However, some lists can benefit from a more personalized - approach. In this case, Mailman crafts a new message for - each member on the regular delivery list. Turning this - feature on may degrade the performance of your site, so you - need to carefully consider whether the trade-off is worth it, - or whether there are other ways to accomplish what you want. - You should also carefully monitor your system load to make - sure it is acceptable. - - <p>Select <em>No</em> to disable personalization and send - messages to the members in batches. Select <em>Yes</em> to - personalize deliveries and allow additional substitution - variables in message headers and footers (see below). In - addition, by selecting <em>Full Personalization</em>, the - <code>To</code> header of posted messages will be modified to - include the member's address instead of the list's posting - address. - - <p>When personalization is enabled, a few more expansion - variables that can be included in the <a - href="?VARHELP=nondigest/msg_header">message header</a> and - <a href="?VARHELP=nondigest/msg_footer">message footer</a>. - - <p>These additional substitution variables will be available - for your headers and footers, when this feature is enabled: - - <ul><li><b>user_address</b> - The address of the user, - coerced to lower case. - <li><b>user_delivered_to</b> - The case-preserved address - that the user is subscribed with. - <li><b>user_password</b> - The user's password. - <li><b>user_name</b> - The user's full name. - <li><b>user_optionsurl</b> - The url to the user's option - page. - </ul> - """)) - ]) - # BAW: for very dumb reasons, we want the `personalize' attribute to - # show up before the msg_header and msg_footer attrs, otherwise we'll - # get a bogus warning if the header/footer contains a personalization - # substitution variable, and we're transitioning from no - # personalization to personalization enabled. - headfoot = Utils.maketext('headfoot.html', mlist=mlist, raw=1) - if config.OWNERS_CAN_ENABLE_PERSONALIZATION: - extra = _("""\ -When <a href="?VARHELP=nondigest/personalize">personalization</a> is enabled -for this list, additional substitution variables are allowed in your headers -and footers: - -<ul><li><b>user_address</b> - The address of the user, - coerced to lower case. - <li><b>user_delivered_to</b> - The case-preserved address - that the user is subscribed with. - <li><b>user_password</b> - The user's password. - <li><b>user_name</b> - The user's full name. - <li><b>user_optionsurl</b> - The url to the user's option - page. -</ul> -""") - else: - extra = '' - - info.extend([('msg_header', Defaults.Text, (10, WIDTH), 0, - _('Header added to mail sent to regular list members'), - _('''Text prepended to the top of every immediately-delivery - message. ''') + headfoot + extra), - - ('msg_footer', Defaults.Text, (10, WIDTH), 0, - _('Footer added to mail sent to regular list members'), - _('''Text appended to the bottom of every immediately-delivery - message. ''') + headfoot + extra), - ]) - - info.extend([ - ('scrub_nondigest', Defaults.Toggle, (_('No'), _('Yes')), 0, - _('Scrub attachments of regular delivery message?'), - _('''When you scrub attachments, they are stored in archive - area and links are made in the message so that the member can - access via web browser. If you want the attachments totally - disappear, you can use content filter options.''')), - ]) - return info - - def _setValue(self, mlist, property, val, doc): - alloweds = list(ALLOWEDS) - if mlist.personalize: - alloweds.extend(PERSONALIZED_ALLOWEDS) - if property in ('msg_header', 'msg_footer'): - val = self._convertString(mlist, property, alloweds, val, doc) - if val is None: - # There was a problem, so don't set it - return - GUIBase._setValue(self, mlist, property, val, doc) diff --git a/mailman/web/Gui/Passwords.py b/mailman/web/Gui/Passwords.py deleted file mode 100644 index b2fea0fb5..000000000 --- a/mailman/web/Gui/Passwords.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (C) 2001-2009 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -"""MailList mixin class managing the password pseudo-options.""" - -from Mailman.i18n import _ -from Mailman.Gui.GUIBase import GUIBase - - - -class Passwords(GUIBase): - def GetConfigCategory(self): - return 'passwords', _('Passwords') - - def handleForm(self, mlist, category, subcat, cgidata, doc): - # Nothing more needs to be done - pass diff --git a/mailman/web/Gui/Privacy.py b/mailman/web/Gui/Privacy.py deleted file mode 100644 index 8d60f9203..000000000 --- a/mailman/web/Gui/Privacy.py +++ /dev/null @@ -1,537 +0,0 @@ -# Copyright (C) 2001-2009 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -"""MailList mixin class managing the privacy options.""" - -import re - -from Mailman import Utils -from Mailman.Gui.GUIBase import GUIBase -from Mailman.configuration import config -from Mailman.i18n import _ - - - -class Privacy(GUIBase): - def GetConfigCategory(self): - return 'privacy', _('Privacy options...') - - def GetConfigSubCategories(self, category): - if category == 'privacy': - return [('subscribing', _('Subscription rules')), - ('sender', _('Sender filters')), - ('recipient', _('Recipient filters')), - ('spam', _('Spam filters')), - ] - return None - - def GetConfigInfo(self, mlist, category, subcat=None): - if category <> 'privacy': - return None - # Pre-calculate some stuff. Technically, we shouldn't do the - # sub_cfentry calculation here, but it's too ugly to indent it any - # further, and besides, that'll mess up i18n catalogs. - WIDTH = config.TEXTFIELDWIDTH - if config.ALLOW_OPEN_SUBSCRIBE: - sub_cfentry = ('subscribe_policy', config.Radio, - # choices - (_('None'), - _('Confirm'), - _('Require approval'), - _('Confirm and approve')), - 0, - _('What steps are required for subscription?<br>'), - _('''None - no verification steps (<em>Not - Recommended </em>)<br> - Confirm (*) - email confirmation step required <br> - Require approval - require list administrator - Approval for subscriptions <br> - Confirm and approve - both confirm and approve - - <p>(*) when someone requests a subscription, - Mailman sends them a notice with a unique - subscription request number that they must reply to - in order to subscribe.<br> - - This prevents mischievous (or malicious) people - from creating subscriptions for others without - their consent.''')) - else: - sub_cfentry = ('subscribe_policy', config.Radio, - # choices - (_('Confirm'), - _('Require approval'), - _('Confirm and approve')), - 1, - _('What steps are required for subscription?<br>'), - _('''Confirm (*) - email confirmation required <br> - Require approval - require list administrator - approval for subscriptions <br> - Confirm and approve - both confirm and approve - - <p>(*) when someone requests a subscription, - Mailman sends them a notice with a unique - subscription request number that they must reply to - in order to subscribe.<br> This prevents - mischievous (or malicious) people from creating - subscriptions for others without their consent.''')) - - # some helpful values - admin = mlist.GetScriptURL('admin') - - subscribing_rtn = [ - _("""This section allows you to configure subscription and - membership exposure policy. You can also control whether this - list is public or not. See also the - <a href="%(admin)s/archive">Archival Options</a> section for - separate archive-related privacy settings."""), - - _('Subscribing'), - ('advertised', config.Radio, (_('No'), _('Yes')), 0, - _('''Advertise this list when people ask what lists are on this - machine?''')), - - sub_cfentry, - - ('subscribe_auto_approval', config.EmailListEx, (10, WIDTH), 1, - _("""List of addresses (or regexps) whose subscriptions do not - require approval."""), - - _("""When subscription requires approval, addresses in this list - are allowed to subscribe without administrator approval. Add - addresses one per line. You may begin a line with a ^ character - to designate a (case insensitive) regular expression match.""")), - - ('unsubscribe_policy', config.Radio, (_('No'), _('Yes')), 0, - _("""Is the list moderator's approval required for unsubscription - requests? (<em>No</em> is recommended)"""), - - _("""When members want to leave a list, they will make an - unsubscription request, either via the web or via email. - Normally it is best for you to allow open unsubscriptions so that - users can easily remove themselves from mailing lists (they get - really upset if they can't get off lists!). - - <p>For some lists though, you may want to impose moderator - approval before an unsubscription request is processed. Examples - of such lists include a corporate mailing list that all employees - are required to be members of.""")), - - _('Ban list'), - ('ban_list', config.EmailListEx, (10, WIDTH), 1, - _("""List of addresses which are banned from membership in this - mailing list."""), - - _("""Addresses in this list are banned outright from subscribing - to this mailing list, with no further moderation required. Add - addresses one per line; start the line with a ^ character to - designate a regular expression match.""")), - - _("Membership exposure"), - ('private_roster', config.Radio, - (_('Anyone'), _('List members'), _('List admin only')), 0, - _('Who can view subscription list?'), - - _('''When set, the list of subscribers is protected by member or - admin password authentication.''')), - - ('obscure_addresses', config.Radio, (_('No'), _('Yes')), 0, - _("""Show member addresses so they're not directly recognizable - as email addresses?"""), - _("""Setting this option causes member email addresses to be - transformed when they are presented on list web pages (both in - text and as links), so they're not trivially recognizable as - email addresses. The intention is to prevent the addresses - from being snarfed up by automated web scanners for use by - spammers.""")), - ] - - adminurl = mlist.GetScriptURL('admin') - sender_rtn = [ - _("""When a message is posted to the list, a series of - moderation steps are take to decide whether the a moderator must - first approve the message or not. This section contains the - controls for moderation of both member and non-member postings. - - <p>Member postings are held for moderation if their - <b>moderation flag</b> is turned on. You can control whether - member postings are moderated by default or not. - - <p>Non-member postings can be automatically - <a href="?VARHELP=privacy/sender/accept_these_nonmembers" - >accepted</a>, - <a href="?VARHELP=privacy/sender/hold_these_nonmembers">held for - moderation</a>, - <a href="?VARHELP=privacy/sender/reject_these_nonmembers" - >rejected</a> (bounced), or - <a href="?VARHELP=privacy/sender/discard_these_nonmembers" - >discarded</a>, - either individually or as a group. Any - posting from a non-member who is not explicitly accepted, - rejected, or discarded, will have their posting filtered by the - <a href="?VARHELP=privacy/sender/generic_nonmember_action">general - non-member rules</a>. - - <p>In the text boxes below, add one address per line; start the - line with a ^ character to designate a <a href= - "http://www.python.org/doc/current/lib/module-re.html" - >Python regular expression</a>. When entering backslashes, do so - as if you were using Python raw strings (i.e. you generally just - use a single backslash). - - <p>Note that non-regexp matches are always done first."""), - - _('Member filters'), - - ('default_member_moderation', config.Radio, (_('No'), _('Yes')), - 0, _('By default, should new list member postings be moderated?'), - - _("""Each list member has a <em>moderation flag</em> which says - whether messages from the list member can be posted directly to - the list, or must first be approved by the list moderator. When - the moderation flag is turned on, list member postings must be - approved first. You, the list administrator can decide whether a - specific individual's postings will be moderated or not. - - <p>When a new member is subscribed, their initial moderation flag - takes its value from this option. Turn this option off to accept - member postings by default. Turn this option on to, by default, - moderate member postings first. You can always manually set an - individual member's moderation bit by using the - <a href="%(adminurl)s/members">membership management - screens</a>.""")), - - ('member_moderation_action', config.Radio, - (_('Hold'), _('Reject'), _('Discard')), 0, - _("""Action to take when a moderated member posts to the - list."""), - _("""<ul><li><b>Hold</b> -- this holds the message for approval - by the list moderators. - - <p><li><b>Reject</b> -- this automatically rejects the message by - sending a bounce notice to the post's author. The text of the - bounce notice can be <a - href="?VARHELP=privacy/sender/member_moderation_notice" - >configured by you</a>. - - <p><li><b>Discard</b> -- this simply discards the message, with - no notice sent to the post's author. - </ul>""")), - - ('member_moderation_notice', config.Text, (10, WIDTH), 1, - _("""Text to include in any - <a href="?VARHELP/privacy/sender/member_moderation_action" - >rejection notice</a> to - be sent to moderated members who post to this list.""")), - - _('Non-member filters'), - - ('accept_these_nonmembers', config.EmailListEx, (10, WIDTH), 1, - _("""List of non-member addresses whose postings should be - automatically accepted."""), - - _("""Postings from any of these non-members will be automatically - accepted with no further moderation applied. Add member - addresses one per line; start the line with a ^ character to - designate a regular expression match.""")), - - ('hold_these_nonmembers', config.EmailListEx, (10, WIDTH), 1, - _("""List of non-member addresses whose postings will be - immediately held for moderation."""), - - _("""Postings from any of these non-members will be immediately - and automatically held for moderation by the list moderators. - The sender will receive a notification message which will allow - them to cancel their held message. Add member addresses one per - line; start the line with a ^ character to designate a regular - expression match.""")), - - ('reject_these_nonmembers', config.EmailListEx, (10, WIDTH), 1, - _("""List of non-member addresses whose postings will be - automatically rejected."""), - - _("""Postings from any of these non-members will be automatically - rejected. In other words, their messages will be bounced back to - the sender with a notification of automatic rejection. This - option is not appropriate for known spam senders; their messages - should be - <a href="?VARHELP=privacy/sender/discard_these_nonmembers" - >automatically discarded</a>. - - <p>Add member addresses one per line; start the line with a ^ - character to designate a regular expression match.""")), - - ('discard_these_nonmembers', config.EmailListEx, (10, WIDTH), 1, - _("""List of non-member addresses whose postings will be - automatically discarded."""), - - _("""Postings from any of these non-members will be automatically - discarded. That is, the message will be thrown away with no - further processing or notification. The sender will not receive - a notification or a bounce, however the list moderators can - optionally <a href="?VARHELP=privacy/sender/forward_auto_discards" - >receive copies of auto-discarded messages.</a>. - - <p>Add member addresses one per line; start the line with a ^ - character to designate a regular expression match.""")), - - ('generic_nonmember_action', config.Radio, - (_('Accept'), _('Hold'), _('Reject'), _('Discard')), 0, - _("""Action to take for postings from non-members for which no - explicit action is defined."""), - - _("""When a post from a non-member is received, the message's - sender is matched against the list of explicitly - <a href="?VARHELP=privacy/sender/accept_these_nonmembers" - >accepted</a>, - <a href="?VARHELP=privacy/sender/hold_these_nonmembers">held</a>, - <a href="?VARHELP=privacy/sender/reject_these_nonmembers" - >rejected</a> (bounced), and - <a href="?VARHELP=privacy/sender/discard_these_nonmembers" - >discarded</a> addresses. If no match is found, then this action - is taken.""")), - - ('forward_auto_discards', config.Radio, (_('No'), _('Yes')), 0, - _("""Should messages from non-members, which are automatically - discarded, be forwarded to the list moderator?""")), - - ('nonmember_rejection_notice', config.Text, (10, WIDTH), 1, - _("""Text to include in any rejection notice to be sent to - non-members who post to this list. This notice can include - the list's owner address by %%(listowner)s and replaces the - internally crafted default message.""")), - - ] - - recip_rtn = [ - _("""This section allows you to configure various filters based on - the recipient of the message."""), - - _('Recipient filters'), - - ('require_explicit_destination', config.Radio, - (_('No'), _('Yes')), 0, - _("""Must posts have list named in destination (to, cc) field - (or be among the acceptable alias names, specified below)?"""), - - _("""Many (in fact, most) spams do not explicitly name their - myriad destinations in the explicit destination addresses - in - fact often the To: field has a totally bogus address for - obfuscation. The constraint applies only to the stuff in the - address before the '@' sign, but still catches all such spams. - - <p>The cost is that the list will not accept unhindered any - postings relayed from other addresses, unless - - <ol> - <li>The relaying address has the same name, or - - <li>The relaying address name is included on the options that - specifies acceptable aliases for the list. - - </ol>""")), - - ('acceptable_aliases', config.Text, (4, WIDTH), 0, - _("""Alias names (regexps) which qualify as explicit to or cc - destination names for this list."""), - - _("""Alternate addresses that are acceptable when - `require_explicit_destination' is enabled. This option takes a - list of regular expressions, one per line, which is matched - against every recipient address in the message. The matching is - performed with Python's re.match() function, meaning they are - anchored to the start of the string. - - <p>For backwards compatibility with Mailman 1.1, if the regexp - does not contain an `@', then the pattern is matched against just - the local part of the recipient address. If that match fails, or - if the pattern does contain an `@', then the pattern is matched - against the entire recipient address. - - <p>Matching against the local part is deprecated; in a future - release, the pattern will always be matched against the entire - recipient address.""")), - - ('max_num_recipients', config.Number, 5, 0, - _('Ceiling on acceptable number of recipients for a posting.'), - - _('''If a posting has this number, or more, of recipients, it is - held for admin approval. Use 0 for no ceiling.''')), - ] - - spam_rtn = [ - _("""This section allows you to configure various anti-spam - filters posting filters, which can help reduce the amount of spam - your list members end up receiving. - """), - - _('Header filters'), - - ('header_filter_rules', config.HeaderFilter, 0, 0, - _('Filter rules to match against the headers of a message.'), - - _("""Each header filter rule has two parts, a list of regular - expressions, one per line, and an action to take. Mailman - matches the message's headers against every regular expression in - the rule and if any match, the message is rejected, held, or - discarded based on the action you specify. Use <em>Defer</em> to - temporarily disable a rule. - - You can have more than one filter rule for your list. In that - case, each rule is matched in turn, with processing stopped after - the first match. - - Note that headers are collected from all the attachments - (except for the mailman administrivia message) and - matched against the regular expressions. With this feature, - you can effectively sort out messages with dangerous file - types or file name extensions.""")), - - _('Legacy anti-spam filters'), - - ('bounce_matching_headers', config.Text, (6, WIDTH), 0, - _('Hold posts with header value matching a specified regexp.'), - _("""Use this option to prohibit posts according to specific - header values. The target value is a regular-expression for - matching against the specified header. The match is done - disregarding letter case. Lines beginning with '#' are ignored - as comments. - - <p>For example:<pre>to: .*@public.com </pre> says to hold all - postings with a <em>To:</em> mail header containing '@public.com' - anywhere among the addresses. - - <p>Note that leading whitespace is trimmed from the regexp. This - can be circumvented in a number of ways, e.g. by escaping or - bracketing it.""")), - ] - - if subcat == 'sender': - return sender_rtn - elif subcat == 'recipient': - return recip_rtn - elif subcat == 'spam': - return spam_rtn - else: - return subscribing_rtn - - def _setValue(self, mlist, property, val, doc): - # Ignore any hdrfilter_* form variables - if property.startswith('hdrfilter_'): - return - # For subscribe_policy when ALLOW_OPEN_SUBSCRIBE is true, we need to - # add one to the value because the page didn't present an open list as - # an option. - if property == 'subscribe_policy' and not config.ALLOW_OPEN_SUBSCRIBE: - val += 1 - setattr(mlist, property, val) - - # We need to handle the header_filter_rules widgets specially, but - # everything else can be done by the base class's handleForm() method. - # However, to do this we need an awful hack. _setValue() and - # _getValidValue() will essentially ignore any hdrfilter_* form variables. - # TK: we should call this function only in subcat == 'spam' - def _handleForm(self, mlist, category, subcat, cgidata, doc): - # TK: If there is no hdrfilter_* in cgidata, we should not touch - # the header filter rules. - if not cgidata.has_key('hdrfilter_rebox_01'): - return - # First deal with - rules = [] - # We start i at 1 and keep going until we no longer find items keyed - # with the marked tags. - i = 1 - downi = None - while True: - deltag = 'hdrfilter_delete_%02d' % i - reboxtag = 'hdrfilter_rebox_%02d' % i - actiontag = 'hdrfilter_action_%02d' % i - wheretag = 'hdrfilter_where_%02d' % i - addtag = 'hdrfilter_add_%02d' % i - newtag = 'hdrfilter_new_%02d' % i - uptag = 'hdrfilter_up_%02d' % i - downtag = 'hdrfilter_down_%02d' % i - i += 1 - # Was this a delete? If so, we can just ignore this entry - if cgidata.has_key(deltag): - continue - # Get the data for the current box - pattern = cgidata.getvalue(reboxtag) - try: - action = int(cgidata.getvalue(actiontag)) - # We'll get a TypeError when the actiontag is missing and the - # .getvalue() call returns None. - except (ValueError, TypeError): - action = config.DEFER - if pattern is None: - # We came to the end of the boxes - break - if cgidata.has_key(newtag) and not pattern: - # This new entry is incomplete. - if i == 2: - # OK it is the first. - continue - doc.addError(_("""Header filter rules require a pattern. - Incomplete filter rules will be ignored.""")) - continue - # Make sure the pattern was a legal regular expression - try: - re.compile(pattern) - except (re.error, TypeError): - safepattern = Utils.websafe(pattern) - doc.addError(_("""The header filter rule pattern - '%(safepattern)s' is not a legal regular expression. This - rule will be ignored.""")) - continue - # Was this an add item? - if cgidata.has_key(addtag): - # Where should the new one be added? - where = cgidata.getvalue(wheretag) - if where == 'before': - # Add a new empty rule box before the current one - rules.append(('', config.DEFER, True)) - rules.append((pattern, action, False)) - # Default is to add it after... - else: - rules.append((pattern, action, False)) - rules.append(('', config.DEFER, True)) - # Was this an up movement? - elif cgidata.has_key(uptag): - # As long as this one isn't the first rule, move it up - if rules: - rules.insert(-1, (pattern, action, False)) - else: - rules.append((pattern, action, False)) - # Was this the down movement? - elif cgidata.has_key(downtag): - downi = i - 2 - rules.append((pattern, action, False)) - # Otherwise, just retain this one in the list - else: - rules.append((pattern, action, False)) - # Move any down button filter rule - if downi is not None: - rule = rules[downi] - del rules[downi] - rules.insert(downi+1, rule) - mlist.header_filter_rules = rules - - def handleForm(self, mlist, category, subcat, cgidata, doc): - if subcat == 'spam': - self._handleForm(mlist, category, subcat, cgidata, doc) - # Everything else is dealt with by the base handler - GUIBase.handleForm(self, mlist, category, subcat, cgidata, doc) diff --git a/mailman/web/Gui/Topics.py b/mailman/web/Gui/Topics.py deleted file mode 100644 index 00df988be..000000000 --- a/mailman/web/Gui/Topics.py +++ /dev/null @@ -1,162 +0,0 @@ -# Copyright (C) 2001-2009 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -import re - -from Mailman import Utils -from Mailman.Gui.GUIBase import GUIBase -from Mailman.configuration import config -from Mailman.i18n import _ - -OR = '|' - - - -class Topics(GUIBase): - def GetConfigCategory(self): - return 'topics', _('Topics') - - def GetConfigInfo(self, mlist, category, subcat=None): - if category <> 'topics': - return None - WIDTH = config.TEXTFIELDWIDTH - - return [ - _('List topic keywords'), - - ('topics_enabled', config.Radio, (_('Disabled'), _('Enabled')), 0, - _('''Should the topic filter be enabled or disabled?'''), - - _("""The topic filter categorizes each incoming email message - according to <a - href="http://www.python.org/doc/current/lib/module-re.html">regular - expression filters</a> you specify below. If the message's - <code>Subject:</code> or <code>Keywords:</code> header contains a - match against a topic filter, the message is logically placed - into a topic <em>bucket</em>. Each user can then choose to only - receive messages from the mailing list for a particular topic - bucket (or buckets). Any message not categorized in a topic - bucket registered with the user is not delivered to the list. - - <p>Note that this feature only works with regular delivery, not - digest delivery. - - <p>The body of the message can also be optionally scanned for - <code>Subject:</code> and <code>Keywords:</code> headers, as - specified by the <a - href="?VARHELP=topics/topics_bodylines_limit">topics_bodylines_limit</a> - configuration variable.""")), - - ('topics_bodylines_limit', config.Number, 5, 0, - _('How many body lines should the topic matcher scan?'), - - _("""The topic matcher will scan this many lines of the message - body looking for topic keyword matches. Body scanning stops when - either this many lines have been looked at, or a non-header-like - body line is encountered. By setting this value to zero, no body - lines will be scanned (i.e. only the <code>Keywords:</code> and - <code>Subject:</code> headers will be scanned). By setting this - value to a negative number, then all body lines will be scanned - until a non-header-like line is encountered. - """)), - - ('topics', config.Topics, 0, 0, - _('Topic keywords, one per line, to match against each message.'), - - _("""Each topic keyword is actually a regular expression, which is - matched against certain parts of a mail message, specifically the - <code>Keywords:</code> and <code>Subject:</code> message headers. - Note that the first few lines of the body of the message can also - contain a <code>Keywords:</code> and <code>Subject:</code> - "header" on which matching is also performed.""")), - - ] - - def handleForm(self, mlist, category, subcat, cgidata, doc): - # MAS: Did we come from the authentication page? - if not cgidata.has_key('topic_box_01'): - return - topics = [] - # We start i at 1 and keep going until we no longer find items keyed - # with the marked tags. - i = 1 - while True: - deltag = 'topic_delete_%02d' % i - boxtag = 'topic_box_%02d' % i - reboxtag = 'topic_rebox_%02d' % i - desctag = 'topic_desc_%02d' % i - wheretag = 'topic_where_%02d' % i - addtag = 'topic_add_%02d' % i - newtag = 'topic_new_%02d' % i - i += 1 - # Was this a delete? If so, we can just ignore this entry - if cgidata.has_key(deltag): - continue - # Get the data for the current box - name = cgidata.getvalue(boxtag) - pattern = cgidata.getvalue(reboxtag) - desc = cgidata.getvalue(desctag) - if name is None: - # We came to the end of the boxes - break - if cgidata.has_key(newtag) and (not name or not pattern): - # This new entry is incomplete. - doc.addError(_("""Topic specifications require both a name and - a pattern. Incomplete topics will be ignored.""")) - continue - # Make sure the pattern was a legal regular expression - name = Utils.websafe(name) - try: - orpattern = OR.join(pattern.splitlines()) - re.compile(orpattern) - except (re.error, TypeError): - safepattern = Utils.websafe(orpattern) - doc.addError(_("""The topic pattern '%(safepattern)s' is not a - legal regular expression. It will be discarded.""")) - continue - # Was this an add item? - if cgidata.has_key(addtag): - # Where should the new one be added? - where = cgidata.getvalue(wheretag) - if where == 'before': - # Add a new empty topics box before the current one - topics.append(('', '', '', True)) - topics.append((name, pattern, desc, False)) - # Default is to add it after... - else: - topics.append((name, pattern, desc, False)) - topics.append(('', '', '', True)) - # Otherwise, just retain this one in the list - else: - topics.append((name, pattern, desc, False)) - # Add these topics to the mailing list object, and deal with other - # options. - mlist.topics = topics - try: - mlist.topics_enabled = int(cgidata.getvalue( - 'topics_enabled', - mlist.topics_enabled)) - except ValueError: - # BAW: should really print a warning - pass - try: - mlist.topics_bodylines_limit = int(cgidata.getvalue( - 'topics_bodylines_limit', - mlist.topics_bodylines_limit)) - except ValueError: - # BAW: should really print a warning - pass diff --git a/mailman/web/Gui/Usenet.py b/mailman/web/Gui/Usenet.py deleted file mode 100644 index 9c1b50809..000000000 --- a/mailman/web/Gui/Usenet.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright (C) 2001-2009 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -from Mailman.Gui.GUIBase import GUIBase -from Mailman.configuration import config -from Mailman.i18n import _ - - - -class Usenet(GUIBase): - def GetConfigCategory(self): - return 'gateway', _('Mail<->News gateways') - - def GetConfigInfo(self, mlist, category, subcat=None): - if category <> 'gateway': - return None - - WIDTH = config.TEXTFIELDWIDTH - VERTICAL = 1 - - return [ - _('Mail-to-News and News-to-Mail gateway services.'), - - _('News server settings'), - - ('nntp_host', config.String, WIDTH, 0, - _('The hostname of the machine your news server is running on.'), - _('''This value may be either the name of your news server, or - optionally of the format name:port, where port is a port number. - - The news server is not part of Mailman proper. You have to - already have access to an NNTP server, and that NNTP server must - recognize the machine this mailing list runs on as a machine - capable of reading and posting news.''')), - - ('linked_newsgroup', config.String, WIDTH, 0, - _('The name of the Usenet group to gateway to and/or from.')), - - ('gateway_to_news', config.Toggle, (_('No'), _('Yes')), 0, - _('''Should new posts to the mailing list be sent to the - newsgroup?''')), - - ('gateway_to_mail', config.Toggle, (_('No'), _('Yes')), 0, - _('''Should new posts to the newsgroup be sent to the mailing - list?''')), - - _('Forwarding options'), - - ('news_moderation', config.Radio, - (_('None'), _('Open list, moderated group'), _('Moderated')), - VERTICAL, - - _("""The moderation policy of the newsgroup."""), - - _("""This setting determines the moderation policy of the - newsgroup and its interaction with the moderation policy of the - mailing list. This only applies to the newsgroup that you are - gatewaying <em>to</em>, so if you are only gatewaying from - Usenet, or the newsgroup you are gatewaying to is not moderated, - set this option to <em>None</em>. - - <p>If the newsgroup is moderated, you can set this mailing list - up to be the moderation address for the newsgroup. By selecting - <em>Moderated</em>, an additional posting hold will be placed in - the approval process. All messages posted to the mailing list - will have to be approved before being sent on to the newsgroup, - or to the mailing list membership. - - <p><em>Note that if the message has an <tt>Approved</tt> header - with the list's administrative password in it, this hold test - will be bypassed, allowing privileged posters to send messages - directly to the list and the newsgroup.</em> - - <p>Finally, if the newsgroup is moderated, but you want to have - an open posting policy anyway, you should select <em>Open list, - moderated group</em>. The effect of this is to use the normal - Mailman moderation facilities, but to add an <tt>Approved</tt> - header to all messages that are gatewayed to Usenet.""")), - - ('news_prefix_subject_too', config.Toggle, (_('No'), _('Yes')), 0, - _('Prefix <tt>Subject:</tt> headers on postings gated to news?'), - _("""Mailman prefixes <tt>Subject:</tt> headers with - <a href="?VARHELP=general/subject_prefix">text you can - customize</a> and normally, this prefix shows up in messages - gatewayed to Usenet. You can set this option to <em>No</em> to - disable the prefix on gated messages. Of course, if you turn off - normal <tt>Subject:</tt> prefixes, they won't be prefixed for - gated messages either.""")), - - _('Mass catch up'), - - ('_mass_catchup', config.Toggle, (_('No'), _('Yes')), 0, - _('Should Mailman perform a <em>catchup</em> on the newsgroup?'), - _('''When you tell Mailman to perform a catchup on the newsgroup, - this means that you want to start gating messages to the mailing - list with the next new message found. All earlier messages on - the newsgroup will be ignored. This is as if you were reading - the newsgroup yourself, and you marked all current messages as - <em>read</em>. By catching up, your mailing list members will - not see any of the earlier messages.''')), - - ] - - def _setValue(self, mlist, property, val, doc): - # Watch for the special, immediate action attributes - if property == '_mass_catchup' and val: - mlist.usenet_watermark = None - doc.AddItem(_('Mass catchup completed')) - else: - GUIBase._setValue(self, mlist, property, val, doc) - - def _postValidate(self, mlist, doc): - # Make sure that if we're gating, that the newsgroups and host - # information are not blank. - if mlist.gateway_to_news or mlist.gateway_to_mail: - # BAW: It's too expensive and annoying to ensure that both the - # host is valid and that the newsgroup is a valid n.g. on the - # server. This should be good enough. - if not mlist.nntp_host or not mlist.linked_newsgroup: - doc.addError(_("""You cannot enable gatewaying unless both the - <a href="?VARHELP=gateway/nntp_host">news server field</a> and - the <a href="?VARHELP=gateway/linked_newsgroup">linked - newsgroup</a> fields are filled in.""")) - # And reset these values - mlist.gateway_to_news = 0 - mlist.gateway_to_mail = 0 diff --git a/mailman/web/Gui/__init__.py b/mailman/web/Gui/__init__.py deleted file mode 100644 index 2e12526c0..000000000 --- a/mailman/web/Gui/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) 2001-2009 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman 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 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman 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 -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -from Archive import Archive -from Autoresponse import Autoresponse -from Bounce import Bounce -from Digest import Digest -from General import General -from Membership import Membership -from NonDigest import NonDigest -from Passwords import Passwords -from Privacy import Privacy -from Topics import Topics -from Usenet import Usenet -from Language import Language -from ContentFilter import ContentFilter - -# Don't export this symbol outside the package -del GUIBase |
