diff options
Diffstat (limited to 'mailman/web/Gui/Privacy.py')
| -rw-r--r-- | mailman/web/Gui/Privacy.py | 537 |
1 files changed, 0 insertions, 537 deletions
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) |
