summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarry Warsaw2007-10-10 00:16:12 -0400
committerBarry Warsaw2007-10-10 00:16:12 -0400
commit15f9e73fdb96a145632e5916cc0073472c014c99 (patch)
treed5bf1b81d4945e20586d17a5bd2002c8ce6d986c
parent28f41bc768390f11cf817534cca67a1683f235a7 (diff)
downloadmailman-15f9e73fdb96a145632e5916cc0073472c014c99.tar.gz
mailman-15f9e73fdb96a145632e5916cc0073472c014c99.tar.zst
mailman-15f9e73fdb96a145632e5916cc0073472c014c99.zip
-rw-r--r--Mailman/Commands/cmd_info.py8
-rw-r--r--Mailman/Handlers/CookHeaders.py6
-rw-r--r--Mailman/Handlers/SMTPDirect.py5
-rw-r--r--Mailman/Handlers/ToOutgoing.py3
-rw-r--r--Mailman/MailList.py3
-rw-r--r--Mailman/app/styles.py23
-rw-r--r--Mailman/bin/gate_news.py4
-rw-r--r--Mailman/bin/withlist.py4
-rw-r--r--Mailman/database/model/mailinglist.py10
-rw-r--r--Mailman/docs/cook-headers.txt34
-rw-r--r--Mailman/docs/news-runner.txt46
-rw-r--r--Mailman/docs/outgoing.txt5
-rw-r--r--Mailman/interfaces/__init__.py24
-rw-r--r--Mailman/interfaces/action.py31
-rw-r--r--Mailman/interfaces/mailinglist.py12
-rw-r--r--Mailman/queue/news.py6
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