diff options
| author | Barry Warsaw | 2007-10-10 00:16:12 -0400 |
|---|---|---|
| committer | Barry Warsaw | 2007-10-10 00:16:12 -0400 |
| commit | 15f9e73fdb96a145632e5916cc0073472c014c99 (patch) | |
| tree | d5bf1b81d4945e20586d17a5bd2002c8ce6d986c | |
| parent | 28f41bc768390f11cf817534cca67a1683f235a7 (diff) | |
| download | mailman-15f9e73fdb96a145632e5916cc0073472c014c99.tar.gz mailman-15f9e73fdb96a145632e5916cc0073472c014c99.tar.zst mailman-15f9e73fdb96a145632e5916cc0073472c014c99.zip | |
| -rw-r--r-- | Mailman/Commands/cmd_info.py | 8 | ||||
| -rw-r--r-- | Mailman/Handlers/CookHeaders.py | 6 | ||||
| -rw-r--r-- | Mailman/Handlers/SMTPDirect.py | 5 | ||||
| -rw-r--r-- | Mailman/Handlers/ToOutgoing.py | 3 | ||||
| -rw-r--r-- | Mailman/MailList.py | 3 | ||||
| -rw-r--r-- | Mailman/app/styles.py | 23 | ||||
| -rw-r--r-- | Mailman/bin/gate_news.py | 4 | ||||
| -rw-r--r-- | Mailman/bin/withlist.py | 4 | ||||
| -rw-r--r-- | Mailman/database/model/mailinglist.py | 10 | ||||
| -rw-r--r-- | Mailman/docs/cook-headers.txt | 34 | ||||
| -rw-r--r-- | Mailman/docs/news-runner.txt | 46 | ||||
| -rw-r--r-- | Mailman/docs/outgoing.txt | 5 | ||||
| -rw-r--r-- | Mailman/interfaces/__init__.py | 24 | ||||
| -rw-r--r-- | Mailman/interfaces/action.py | 31 | ||||
| -rw-r--r-- | Mailman/interfaces/mailinglist.py | 12 | ||||
| -rw-r--r-- | Mailman/queue/news.py | 6 |
16 files changed, 156 insertions, 68 deletions
diff --git a/Mailman/Commands/cmd_info.py b/Mailman/Commands/cmd_info.py index 923f7aec8..cb7834292 100644 --- a/Mailman/Commands/cmd_info.py +++ b/Mailman/Commands/cmd_info.py @@ -37,10 +37,10 @@ def process(res, args): return STOP listname = mlist.real_name description = mlist.description or _('n/a') - postaddr = mlist.GetListEmail() - requestaddr = mlist.GetRequestEmail() - owneraddr = mlist.GetOwnerEmail() - listurl = mlist.GetScriptURL('listinfo', absolute=1) + postaddr = mlist.posting_address + requestaddr = mlist.request_address + owneraddr = mlist.owner_address + listurl = mlist.script_url('listinfo') res.results.append(_('List name: %(listname)s')) res.results.append(_('Description: %(description)s')) res.results.append(_('Postings to: %(postaddr)s')) diff --git a/Mailman/Handlers/CookHeaders.py b/Mailman/Handlers/CookHeaders.py index 24bf0e829..cb14853d5 100644 --- a/Mailman/Handlers/CookHeaders.py +++ b/Mailman/Handlers/CookHeaders.py @@ -29,7 +29,7 @@ from Mailman import Version from Mailman.app.archiving import get_base_archive_url from Mailman.configuration import config from Mailman.i18n import _ -from Mailman.interfaces import ReplyToMunging +from Mailman.interfaces import Personalization, ReplyToMunging CONTINUATION = ',\n\t' COMMASPACE = ', ' @@ -148,7 +148,7 @@ def process(mlist, msg, msgdata): # above code? # Also skip Cc if this is an anonymous list as list posting address # is already in From and Reply-To in this case. - if (mlist.personalize == 2 and + if (mlist.personalize == Personalization.full and mlist.reply_goes_to_list <> ReplyToMunging.point_to_list and not mlist.anonymous_list): # Watch out for existing Cc headers, merge, and remove dups. Note @@ -158,7 +158,7 @@ def process(mlist, msg, msgdata): for pair in getaddresses(msg.get_all('cc', [])): add(pair) i18ndesc = uheader(mlist, mlist.description, 'Cc') - add((str(i18ndesc), mlist.GetListEmail())) + add((str(i18ndesc), mlist.posting_address)) del msg['Cc'] msg['Cc'] = COMMASPACE.join([formataddr(pair) for pair in new]) # Add list-specific headers as defined in RFC 2369 and RFC 2919, but only diff --git a/Mailman/Handlers/SMTPDirect.py b/Mailman/Handlers/SMTPDirect.py index b3af8ccb3..0037d676a 100644 --- a/Mailman/Handlers/SMTPDirect.py +++ b/Mailman/Handlers/SMTPDirect.py @@ -42,6 +42,7 @@ from Mailman import Utils from Mailman.Handlers import Decorate from Mailman.SafeDict import MsgSafeDict from Mailman.configuration import config +from Mailman.interfaces import Personalization DOT = '.' @@ -114,7 +115,7 @@ def process(mlist, msg, msgdata): # recipients they'll swallow in a single transaction. deliveryfunc = None if (not msgdata.has_key('personalize') or msgdata['personalize']) and ( - msgdata.get('verp') or mlist.personalize): + msgdata.get('verp') or mlist.personalize <> Personalization.none): chunks = [[recip] for recip in recips] msgdata['personalize'] = 1 deliveryfunc = verpdeliver @@ -301,7 +302,7 @@ def verpdeliver(mlist, msg, msgdata, envsender, failures, conn): 'host' : DOT.join(rdomain), } envsender = '%s@%s' % ((config.VERP_FORMAT % d), DOT.join(bdomain)) - if mlist.personalize == 2: + if mlist.personalize == Personalization.full: # When fully personalizing, we want the To address to point to the # recipient, not to the mailing list del msgcopy['to'] diff --git a/Mailman/Handlers/ToOutgoing.py b/Mailman/Handlers/ToOutgoing.py index 15ceb8311..9c8650a98 100644 --- a/Mailman/Handlers/ToOutgoing.py +++ b/Mailman/Handlers/ToOutgoing.py @@ -23,6 +23,7 @@ recipient should just be placed in the out queue directly. """ from Mailman.configuration import config +from Mailman.interfaces import Personalization from Mailman.queue import Switchboard @@ -39,7 +40,7 @@ def process(mlist, msg, msgdata): # VERP_PASSWORD_REMINDERS. Preserve any existing verp flag. if 'verp' in msgdata: pass - elif mlist.personalize: + elif mlist.personalize <> Personalization.none: if config.VERP_PERSONALIZED_DELIVERIES: msgdata['verp'] = True elif interval == 0: diff --git a/Mailman/MailList.py b/Mailman/MailList.py index da37eb6e1..d90de18f0 100644 --- a/Mailman/MailList.py +++ b/Mailman/MailList.py @@ -184,9 +184,6 @@ class MailList(object, Archiver, Digester, SecurityManager, Bouncer): else: return 'confirm ' + cookie - def GetListEmail(self): - return self.getListAddress() - def GetMemberAdminEmail(self, member): """Usually the member addr, but modified for umbrella lists. diff --git a/Mailman/app/styles.py b/Mailman/app/styles.py index 06a82cccf..39e8355db 100644 --- a/Mailman/app/styles.py +++ b/Mailman/app/styles.py @@ -17,6 +17,12 @@ """Application of list styles to new and existing lists.""" +__metaclass__ = type +__all__ = [ + 'DefaultStyle', + 'style_manager', + ] + import datetime from operator import attrgetter @@ -27,14 +33,8 @@ from Mailman import Utils from Mailman.Errors import DuplicateStyleError from Mailman.app.plugins import get_plugins from Mailman.configuration import config -from Mailman.interfaces import Action, IStyle, IStyleManager - - -__metaclass__ = type -__all__ = [ - 'DefaultStyle', - 'style_manager', - ] +from Mailman.interfaces import ( + Action, IStyle, IStyleManager, NewsModeration, Personalization) @@ -109,7 +109,7 @@ class DefaultStyle: mlist.digest_members = {} mlist.next_digest_number = 1 mlist.nondigestable = config.DEFAULT_NONDIGESTABLE - mlist.personalize = False + mlist.personalize = Personalization.none # New sender-centric moderation (privacy) options mlist.default_member_moderation = ( config.DEFAULT_DEFAULT_MEMBER_MODERATION) @@ -126,7 +126,8 @@ class DefaultStyle: 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.generic_nonmember_action = ( + config.DEFAULT_GENERIC_NONMEMBER_ACTION) mlist.nonmember_rejection_notice = '' # Ban lists mlist.ban_list = [] @@ -192,7 +193,7 @@ class DefaultStyle: 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 = False + mlist.news_moderation = NewsModeration.none # Topics # # `topics' is a list of 4-tuples of the following form: diff --git a/Mailman/bin/gate_news.py b/Mailman/bin/gate_news.py index bded31869..da78b6068 100644 --- a/Mailman/bin/gate_news.py +++ b/Mailman/bin/gate_news.py @@ -117,7 +117,7 @@ def poll_newsgroup(mlist, conn, first, last, glock): found_to = True if value <> 'x-beenthere': continue - if header[i:] == ': %s' % mlist.GetListEmail(): + if header[i:] == ': %s' % mlist.posting_address: beenthere = True break if not beenthere: @@ -146,7 +146,7 @@ def poll_newsgroup(mlist, conn, first, last, glock): del msg['X-Originally-To'] msg['X-Originally-To'] = msg['To'] del msg['To'] - msg['To'] = mlist.GetListEmail() + msg['To'] = mlist.posting_address # Post the message to the locked list inq = Switchboard(config.INQUEUE_DIR) inq.enqueue(msg, diff --git a/Mailman/bin/withlist.py b/Mailman/bin/withlist.py index f6c66a703..cf40ddabd 100644 --- a/Mailman/bin/withlist.py +++ b/Mailman/bin/withlist.py @@ -98,10 +98,10 @@ Mailman installation directory called 'listaddr.py', with the following two functions: def listaddr(mlist): - print mlist.GetListEmail() + print mlist.posting_address def requestaddr(mlist): - print mlist.GetRequestEmail() + print mlist.request_address Now, from the command line you can print the list's posting address by running the following from the command line: diff --git a/Mailman/database/model/mailinglist.py b/Mailman/database/model/mailinglist.py index 0725910ec..fff5cbb9c 100644 --- a/Mailman/database/model/mailinglist.py +++ b/Mailman/database/model/mailinglist.py @@ -23,7 +23,7 @@ from zope.interface import implements from Mailman.Utils import fqdn_listname, makedirs, split_listname from Mailman.configuration import config -from Mailman.interfaces import IMailingList +from Mailman.interfaces import IMailingList, Personalization from Mailman.database.types import EnumType, TimeDeltaType SPACE = ' ' @@ -124,7 +124,7 @@ class MailingList(Entity): has_field('msg_footer', Unicode), has_field('msg_header', Unicode), has_field('new_member_options', Integer), - has_field('news_moderation', Boolean), + has_field('news_moderation', EnumType), has_field('news_prefix_subject_too', Boolean), has_field('nntp_host', Unicode), has_field('nondigestable', Boolean), @@ -132,7 +132,7 @@ class MailingList(Entity): has_field('obscure_addresses', Boolean), has_field('pass_filename_extensions', PickleType), has_field('pass_mime_types', PickleType), - has_field('personalize', Integer), + has_field('personalize', EnumType), has_field('post_id', Integer), has_field('preferred_language', Unicode), has_field('private_roster', Boolean), @@ -174,7 +174,9 @@ class MailingList(Entity): # autoresponses sent on that date. self.hold_and_cmd_autoresponses = {} self.full_path = os.path.join(config.LIST_DATA_DIR, fqdn_listname) - self.real_name = string.capwords(SPACE.join(listname.split(UNDERSCORE))) + self.personalization = Personalization.none + self.real_name = string.capwords( + SPACE.join(listname.split(UNDERSCORE))) makedirs(self.full_path) # XXX FIXME diff --git a/Mailman/docs/cook-headers.txt b/Mailman/docs/cook-headers.txt index ffe2dfa5f..62c80b186 100644 --- a/Mailman/docs/cook-headers.txt +++ b/Mailman/docs/cook-headers.txt @@ -292,3 +292,37 @@ List-Archive header either. List-Unsubscribe: <http://lists.example.com/listinfo/_xtest@example.com>, <mailto:_xtest-leave@example.com> ---end--- + + +Personalization +--------------- + +The To field normally contains the list posting address. However when +messages are fully personalized, that header will get overwritten with the +address of the recipient. The list's posting address will be added to one of +the recipient headers so that users will be able to reply back to the list. + + >>> from Mailman.interfaces import Personalization, ReplyToMunging + >>> mlist.personalize = Personalization.full + >>> mlist.reply_goes_to_list = ReplyToMunging.no_munging + >>> flush() + >>> msg = message_from_string("""\ + ... From: aperson@example.com + ... + ... """, Message) + >>> process(mlist, msg, {}) + >>> print msg.as_string() + From: aperson@example.com + X-BeenThere: _xtest@example.com + X-Mailman-Version: ... + Precedence: list + Cc: My test mailing list <_xtest@example.com> + List-Id: My test mailing list <_xtest.example.com> + List-Unsubscribe: <http://lists.example.com/listinfo/_xtest@example.com>, + <mailto:_xtest-leave@example.com> + List-Post: <mailto:_xtest@example.com> + List-Help: <mailto:_xtest-request@example.com?subject=help> + List-Subscribe: <http://lists.example.com/listinfo/_xtest@example.com>, + <mailto:_xtest-join@example.com> + <BLANKLINE> + <BLANKLINE> diff --git a/Mailman/docs/news-runner.txt b/Mailman/docs/news-runner.txt index ecc32570f..834423c6e 100644 --- a/Mailman/docs/news-runner.txt +++ b/Mailman/docs/news-runner.txt @@ -116,4 +116,50 @@ the message. <BLANKLINE> +Newsgroup moderation +-------------------- + +When the newsgroup is moderated, an Approved: header with the list's posting +address is added for the benefit of the Usenet system. + + >>> from Mailman.interfaces import NewsModeration + >>> mlist.news_moderation = NewsModeration.open_moderated + >>> flush() + >>> msg = message_from_string("""\ + ... From: aperson@example.com + ... To: _xtest@example.com + ... Approved: this gets deleted + ... + ... """) + >>> prepare_message(mlist, msg, {}) + >>> msg['approved'] + '_xtest@example.com' + + >>> mlist.news_moderation = NewsModeration.moderated + >>> flush() + >>> msg = message_from_string("""\ + ... From: aperson@example.com + ... To: _xtest@example.com + ... Approved: this gets deleted + ... + ... """) + >>> prepare_message(mlist, msg, {}) + >>> msg['approved'] + '_xtest@example.com' + +But if the newsgroup is not moderated, the Approved: header is not chnaged. + + >>> mlist.news_moderation = NewsModeration.none + >>> flush() + >>> msg = message_from_string("""\ + ... From: aperson@example.com + ... To: _xtest@example.com + ... Approved: this doesn't get deleted + ... + ... """) + >>> prepare_message(mlist, msg, {}) + >>> msg['approved'] + "this doesn't get deleted" + + XXX More of the NewsRunner should be tested. diff --git a/Mailman/docs/outgoing.txt b/Mailman/docs/outgoing.txt index c1ecffb00..05dac1fe4 100644 --- a/Mailman/docs/outgoing.txt +++ b/Mailman/docs/outgoing.txt @@ -70,7 +70,8 @@ If the list is set to personalize deliveries, and the global configuration option to VERP personalized deliveries is set, then the message will be VERP'd. - >>> mlist.personalize = True + >>> from Mailman.interfaces import Personalization + >>> mlist.personalize = Personalization.individual >>> flush() >>> config.VERP_PERSONALIZED_DELIVERIES = True >>> msgdata = dict(foo=1, bar=2) @@ -96,7 +97,7 @@ the global configuration variable VERP_DELIVERY_INTERVAL. This variable tells Mailman how often to VERP even non-personalized mailing lists. It can be set to zero, which means non-personalized messages will never be VERP'd. - >>> mlist.personalize = False + >>> mlist.personalize = Personalization.none >>> flush() >>> config.VERP_DELIVERY_INTERVAL = 0 >>> msgdata = dict(foo=1, bar=2) diff --git a/Mailman/interfaces/__init__.py b/Mailman/interfaces/__init__.py index 7e8a3e123..c4094e365 100644 --- a/Mailman/interfaces/__init__.py +++ b/Mailman/interfaces/__init__.py @@ -22,7 +22,10 @@ from munepy import Enum from zope.interface import implementedBy from zope.interface.interfaces import IInterface -__all__ = [] +__all__ = [ + 'Action', + 'NewsModeration', + ] @@ -49,3 +52,22 @@ def _populate(): _populate() + + + +class Action(Enum): + hold = 0 + reject = 1 + discard = 2 + accept = 3 + defer = 4 + + + +class NewsModeration(Enum): + # The newsgroup is not moderated + none = 0 + # The newsgroup is moderated, but allows for an open posting policy. + open_moderated = 1 + # The newsgroup is moderated + moderated = 2 diff --git a/Mailman/interfaces/action.py b/Mailman/interfaces/action.py deleted file mode 100644 index ea8b01d6e..000000000 --- a/Mailman/interfaces/action.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (C) 2006-2007 by the Free Software Foundation, Inc. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -# USA. - -__all__ = [ - 'Action', - ] - -from munepy import Enum - - - -class Action(Enum): - hold = 0 - reject = 1 - discard = 2 - accept = 3 - defer = 4 diff --git a/Mailman/interfaces/mailinglist.py b/Mailman/interfaces/mailinglist.py index d52a6f7b5..2d3811785 100644 --- a/Mailman/interfaces/mailinglist.py +++ b/Mailman/interfaces/mailinglist.py @@ -19,6 +19,7 @@ __all__ = [ 'IMailingList', + 'Personalization', 'ReplyToMunging', ] @@ -27,6 +28,17 @@ from zope.interface import Interface, Attribute +class Personalization(Enum): + none = 0 + # Everyone gets a unique copy of the message, and there are a few more + # substitution variables, but no headers are modified. + individual = 1 + # All of the 'individual' personalization plus recipient header + # modification. + full = 2 + + + class ReplyToMunging(Enum): # The Reply-To header is passed through untouched no_munging = 0 diff --git a/Mailman/queue/news.py b/Mailman/queue/news.py index 1ed58dc0c..14bb24173 100644 --- a/Mailman/queue/news.py +++ b/Mailman/queue/news.py @@ -30,6 +30,7 @@ COMMASPACE = ', ' from Mailman import Utils from Mailman.configuration import config +from Mailman.interfaces import NewsModeration from Mailman.queue import Runner log = logging.getLogger('mailman.error') @@ -92,9 +93,10 @@ def prepare_message(mlist, msg, msgdata): # software to accept the posting, and not forward it on to the n.g.'s # moderation address. The posting would not have gotten here if it hadn't # already been approved. 1 == open list, mod n.g., 2 == moderated - if mlist.news_moderation in (1, 2): + if mlist.news_moderation in (NewsModeration.open_moderated, + NewsModeration.moderated): del msg['approved'] - msg['Approved'] = mlist.GetListEmail() + msg['Approved'] = mlist.posting_address # Should we restore the original, non-prefixed subject for gatewayed # messages? TK: We use stripped_subject (prefix stripped) which was # crafted in CookHeaders.py to ensure prefix was stripped from the subject |
