diff options
| author | Barry Warsaw | 2008-09-29 09:19:52 -0400 |
|---|---|---|
| committer | Barry Warsaw | 2008-09-29 09:19:52 -0400 |
| commit | 20a97a4163774212ad9f16c5a2e3abcbf3ecf918 (patch) | |
| tree | eae145cfae3b3be448282e545a4f5ed810991f50 /mailman/core/styles.py | |
| parent | 73a3660cdf0bda56689f9fd0f7f7ac53c7aa0422 (diff) | |
| download | mailman-20a97a4163774212ad9f16c5a2e3abcbf3ecf918.tar.gz mailman-20a97a4163774212ad9f16c5a2e3abcbf3ecf918.tar.zst mailman-20a97a4163774212ad9f16c5a2e3abcbf3ecf918.zip | |
Diffstat (limited to 'mailman/core/styles.py')
| -rw-r--r-- | mailman/core/styles.py | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/mailman/core/styles.py b/mailman/core/styles.py new file mode 100644 index 000000000..96104c204 --- /dev/null +++ b/mailman/core/styles.py @@ -0,0 +1,294 @@ +# Copyright (C) 2007-2008 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/>. + +"""Application of list styles to new and existing lists.""" + +__metaclass__ = type +__all__ = [ + 'DefaultStyle', + 'style_manager', + ] + +import datetime + +from operator import attrgetter +from zope.interface import implements +from zope.interface.verify import verifyObject + +from mailman import Utils +from mailman.configuration import config +from mailman.core.plugins import get_plugins +from mailman.i18n import _ +from mailman.interfaces import ( + Action, DuplicateStyleError, IStyle, IStyleManager, NewsModeration, + Personalization) + + + +class DefaultStyle: + """The defalt (i.e. legacy) style.""" + + implements(IStyle) + + name = 'default' + priority = 0 # the lowest priority style + + def apply(self, mailing_list): + """See `IStyle`.""" + # For cut-n-paste convenience. + mlist = mailing_list + # Most of these were ripped from the old MailList.InitVars() method. + mlist.volume = 1 + mlist.post_id = 1 + mlist.new_member_options = config.DEFAULT_NEW_MEMBER_OPTIONS + # This stuff is configurable + mlist.real_name = mlist.list_name.capitalize() + mlist.respond_to_post_requests = True + mlist.advertised = config.DEFAULT_LIST_ADVERTISED + mlist.max_num_recipients = config.DEFAULT_MAX_NUM_RECIPIENTS + mlist.max_message_size = config.DEFAULT_MAX_MESSAGE_SIZE + mlist.reply_goes_to_list = config.DEFAULT_REPLY_GOES_TO_LIST + mlist.reply_to_address = u'' + mlist.first_strip_reply_to = config.DEFAULT_FIRST_STRIP_REPLY_TO + mlist.admin_immed_notify = config.DEFAULT_ADMIN_IMMED_NOTIFY + mlist.admin_notify_mchanges = ( + config.DEFAULT_ADMIN_NOTIFY_MCHANGES) + mlist.require_explicit_destination = ( + config.DEFAULT_REQUIRE_EXPLICIT_DESTINATION) + mlist.acceptable_aliases = config.DEFAULT_ACCEPTABLE_ALIASES + mlist.send_reminders = config.DEFAULT_SEND_REMINDERS + mlist.send_welcome_msg = config.DEFAULT_SEND_WELCOME_MSG + mlist.send_goodbye_msg = config.DEFAULT_SEND_GOODBYE_MSG + mlist.bounce_matching_headers = ( + config.DEFAULT_BOUNCE_MATCHING_HEADERS) + mlist.header_matches = [] + mlist.anonymous_list = config.DEFAULT_ANONYMOUS_LIST + mlist.description = u'' + mlist.info = u'' + mlist.welcome_msg = u'' + mlist.goodbye_msg = u'' + mlist.subscribe_policy = config.DEFAULT_SUBSCRIBE_POLICY + mlist.subscribe_auto_approval = config.DEFAULT_SUBSCRIBE_AUTO_APPROVAL + mlist.unsubscribe_policy = config.DEFAULT_UNSUBSCRIBE_POLICY + mlist.private_roster = config.DEFAULT_PRIVATE_ROSTER + mlist.obscure_addresses = config.DEFAULT_OBSCURE_ADDRESSES + mlist.admin_member_chunksize = config.DEFAULT_ADMIN_MEMBER_CHUNKSIZE + mlist.administrivia = config.DEFAULT_ADMINISTRIVIA + mlist.preferred_language = config.DEFAULT_SERVER_LANGUAGE + mlist.include_rfc2369_headers = True + mlist.include_list_post_header = True + mlist.filter_mime_types = config.DEFAULT_FILTER_MIME_TYPES + mlist.pass_mime_types = config.DEFAULT_PASS_MIME_TYPES + mlist.filter_filename_extensions = ( + config.DEFAULT_FILTER_FILENAME_EXTENSIONS) + mlist.pass_filename_extensions = config.DEFAULT_PASS_FILENAME_EXTENSIONS + mlist.filter_content = config.DEFAULT_FILTER_CONTENT + mlist.collapse_alternatives = config.DEFAULT_COLLAPSE_ALTERNATIVES + mlist.convert_html_to_plaintext = ( + config.DEFAULT_CONVERT_HTML_TO_PLAINTEXT) + mlist.filter_action = config.DEFAULT_FILTER_ACTION + # Digest related variables + mlist.digestable = config.DEFAULT_DIGESTABLE + mlist.digest_is_default = config.DEFAULT_DIGEST_IS_DEFAULT + mlist.mime_is_default_digest = config.DEFAULT_MIME_IS_DEFAULT_DIGEST + mlist.digest_size_threshhold = config.DEFAULT_DIGEST_SIZE_THRESHHOLD + mlist.digest_send_periodic = config.DEFAULT_DIGEST_SEND_PERIODIC + mlist.digest_header = config.DEFAULT_DIGEST_HEADER + mlist.digest_footer = config.DEFAULT_DIGEST_FOOTER + mlist.digest_volume_frequency = config.DEFAULT_DIGEST_VOLUME_FREQUENCY + mlist.one_last_digest = {} + mlist.digest_members = {} + mlist.next_digest_number = 1 + mlist.nondigestable = config.DEFAULT_NONDIGESTABLE + mlist.personalize = Personalization.none + # New sender-centric moderation (privacy) options + mlist.default_member_moderation = ( + config.DEFAULT_DEFAULT_MEMBER_MODERATION) + # Archiver + mlist.archive = config.DEFAULT_ARCHIVE + mlist.archive_private = config.DEFAULT_ARCHIVE_PRIVATE + mlist.archive_volume_frequency = ( + config.DEFAULT_ARCHIVE_VOLUME_FREQUENCY) + mlist.emergency = False + mlist.member_moderation_action = Action.hold + mlist.member_moderation_notice = u'' + mlist.accept_these_nonmembers = [] + mlist.hold_these_nonmembers = [] + mlist.reject_these_nonmembers = [] + mlist.discard_these_nonmembers = [] + mlist.forward_auto_discards = config.DEFAULT_FORWARD_AUTO_DISCARDS + mlist.generic_nonmember_action = ( + config.DEFAULT_GENERIC_NONMEMBER_ACTION) + mlist.nonmember_rejection_notice = u'' + # Ban lists + mlist.ban_list = [] + # Max autoresponses per day. A mapping between addresses and a + # 2-tuple of the date of the last autoresponse and the number of + # autoresponses sent on that date. + mlist.hold_and_cmd_autoresponses = {} + mlist.subject_prefix = _(config.DEFAULT_SUBJECT_PREFIX) + mlist.msg_header = config.DEFAULT_MSG_HEADER + mlist.msg_footer = config.DEFAULT_MSG_FOOTER + # Set this to Never if the list's preferred language uses us-ascii, + # otherwise set it to As Needed + if Utils.GetCharSet(mlist.preferred_language) == 'us-ascii': + mlist.encode_ascii_prefixes = 0 + else: + mlist.encode_ascii_prefixes = 2 + # scrub regular delivery + mlist.scrub_nondigest = config.DEFAULT_SCRUB_NONDIGEST + # automatic discarding + mlist.max_days_to_hold = config.DEFAULT_MAX_DAYS_TO_HOLD + # Autoresponder + mlist.autorespond_postings = False + mlist.autorespond_admin = False + # this value can be + # 0 - no autoresponse on the -request line + # 1 - autorespond, but discard the original message + # 2 - autorespond, and forward the message on to be processed + mlist.autorespond_requests = 0 + mlist.autoresponse_postings_text = u'' + mlist.autoresponse_admin_text = u'' + mlist.autoresponse_request_text = u'' + mlist.autoresponse_graceperiod = datetime.timedelta(days=90) + mlist.postings_responses = {} + mlist.admin_responses = {} + mlist.request_responses = {} + # Bounces + mlist.bounce_processing = config.DEFAULT_BOUNCE_PROCESSING + mlist.bounce_score_threshold = config.DEFAULT_BOUNCE_SCORE_THRESHOLD + mlist.bounce_info_stale_after = config.DEFAULT_BOUNCE_INFO_STALE_AFTER + mlist.bounce_you_are_disabled_warnings = ( + config.DEFAULT_BOUNCE_YOU_ARE_DISABLED_WARNINGS) + mlist.bounce_you_are_disabled_warnings_interval = ( + config.DEFAULT_BOUNCE_YOU_ARE_DISABLED_WARNINGS_INTERVAL) + mlist.bounce_unrecognized_goes_to_list_owner = ( + config.DEFAULT_BOUNCE_UNRECOGNIZED_GOES_TO_LIST_OWNER) + mlist.bounce_notify_owner_on_disable = ( + config.DEFAULT_BOUNCE_NOTIFY_OWNER_ON_DISABLE) + mlist.bounce_notify_owner_on_removal = ( + config.DEFAULT_BOUNCE_NOTIFY_OWNER_ON_REMOVAL) + # This holds legacy member related information. It's keyed by the + # member address, and the value is an object containing the bounce + # score, the date of the last received bounce, and a count of the + # notifications left to send. + mlist.bounce_info = {} + # New style delivery status + mlist.delivery_status = {} + # NNTP gateway + mlist.nntp_host = config.DEFAULT_NNTP_HOST + mlist.linked_newsgroup = u'' + mlist.gateway_to_news = False + mlist.gateway_to_mail = False + mlist.news_prefix_subject_too = True + # In patch #401270, this was called newsgroup_is_moderated, but the + # semantics weren't quite the same. + mlist.news_moderation = NewsModeration.none + # Topics + # + # `topics' is a list of 4-tuples of the following form: + # + # (name, pattern, description, emptyflag) + # + # name is a required arbitrary string displayed to the user when they + # get to select their topics of interest + # + # pattern is a required verbose regular expression pattern which is + # used as IGNORECASE. + # + # description is an optional description of what this topic is + # supposed to match + # + # emptyflag is a boolean used internally in the admin interface to + # signal whether a topic entry is new or not (new ones which do not + # have a name or pattern are not saved when the submit button is + # pressed). + mlist.topics = [] + mlist.topics_enabled = False + mlist.topics_bodylines_limit = 5 + # This is a mapping between user "names" (i.e. addresses) and + # information about which topics that user is interested in. The + # values are a list of topic names that the user is interested in, + # which should match the topic names in mlist.topics above. + # + # If the user has not selected any topics of interest, then the rule + # is that they will get all messages, and they will not have an entry + # in this dictionary. + mlist.topics_userinterest = {} + # The processing chain that messages coming into this list get + # processed by. + mlist.start_chain = u'built-in' + # The default pipeline to send accepted messages through. + mlist.pipeline = u'built-in' + + def match(self, mailing_list, styles): + """See `IStyle`.""" + # If no other styles have matched, then the default style matches. + if len(styles) == 0: + styles.append(self) + + + +class StyleManager: + """The built-in style manager.""" + + implements(IStyleManager) + + def __init__(self): + """Install all styles from registered plugins, and install them.""" + self._styles = {} + # Install all the styles provided by plugins. + for style_factory in get_plugins('mailman.styles'): + style = style_factory() + # Let DuplicateStyleErrors percolate up. + self.register(style) + + def get(self, name): + """See `IStyleManager`.""" + return self._styles.get(name) + + def lookup(self, mailing_list): + """See `IStyleManager`.""" + matched_styles = [] + for style in self.styles: + style.match(mailing_list, matched_styles) + for style in matched_styles: + yield style + + @property + def styles(self): + """See `IStyleManager`.""" + for style in sorted(self._styles.values(), + key=attrgetter('priority'), + reverse=True): + yield style + + def register(self, style): + """See `IStyleManager`.""" + verifyObject(IStyle, style) + if style.name in self._styles: + raise DuplicateStyleError(style.name) + self._styles[style.name] = style + + def unregister(self, style): + """See `IStyleManager`.""" + # Let KeyErrors percolate up. + del self._styles[style.name] + + + +style_manager = StyleManager() |
