aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Mailman/Defaults.py.in5
-rw-r--r--Mailman/Gui/NonDigest.py24
-rw-r--r--Mailman/Handlers/CalcRecips.py76
-rw-r--r--Mailman/MailList.py2
-rw-r--r--Mailman/Version.py2
-rw-r--r--Mailman/versions.py5
6 files changed, 112 insertions, 2 deletions
diff --git a/Mailman/Defaults.py.in b/Mailman/Defaults.py.in
index c456c4a3..4618fc23 100644
--- a/Mailman/Defaults.py.in
+++ b/Mailman/Defaults.py.in
@@ -905,6 +905,11 @@ DEFAULT_UMBRELLA_LIST = No
# administrative notices (subscription confirmations, password reminders):
DEFAULT_UMBRELLA_MEMBER_ADMIN_SUFFIX = "-owner"
+# Exclude/include (sibling) lists for non-digest delivery.
+DEFAULT_REGULAR_EXCLUDE_LISTS = []
+DEFAULT_REGULAR_INCLUDE_LISTS = []
+ALLOW_CROSS_DOMAIN_SIBLING = False
+
# This variable controls whether monthly password reminders are sent.
DEFAULT_SEND_REMINDERS = Yes
diff --git a/Mailman/Gui/NonDigest.py b/Mailman/Gui/NonDigest.py
index ca125a03..c319d6ef 100644
--- a/Mailman/Gui/NonDigest.py
+++ b/Mailman/Gui/NonDigest.py
@@ -143,6 +143,30 @@ and footers:
access via web browser. If you want the attachments totally
disappear, you can use content filter options.''')),
])
+
+ info.extend([
+ _('Sibling lists'),
+
+ ('regular_exclude_lists', mm_cfg.EmailList, (3, WIDTH), 0,
+ _('''Other mailing lists on this site whose members are
+ excluded from the regular (non-digest) delivery if those
+ list addresses appear in To: or Cc: header.'''),
+ _('''The list addresses should be written in full mail address
+ format (e.g. mailman@example.com). Do not specify this list
+ address mutually in the exclude list configuration page,
+ or those doubled members won't get any message. Note also that
+ the site administrator may prohibit cross domain sibling.''')),
+
+ ('regular_include_lists', mm_cfg.EmailList, (3, WIDTH), 0,
+ _('''Other mailing lists on this site whose members are
+ included in the regular (non-digest) delivery if those
+ list addresses don't appear in To: or Cc: header.'''),
+ _('''The list addresses should be written in full mail address
+ format (e.g. mailman@example.com). Note also that the site
+ administrator may prohibit cross domain sibling.''')),
+ ])
+
+
return info
def _setValue(self, mlist, property, val, doc):
diff --git a/Mailman/Handlers/CalcRecips.py b/Mailman/Handlers/CalcRecips.py
index 75a8a457..66c16f86 100644
--- a/Mailman/Handlers/CalcRecips.py
+++ b/Mailman/Handlers/CalcRecips.py
@@ -23,13 +23,22 @@ on the `recips' attribute of the message. This attribute is used by the
SendmailDeliver and BulkDeliver modules.
"""
+import email.Utils
from Mailman import mm_cfg
from Mailman import Utils
from Mailman import Message
from Mailman import Errors
from Mailman.MemberAdaptor import ENABLED
+from Mailman.MailList import MailList
from Mailman.i18n import _
from Mailman.Logging.Syslog import syslog
+from Mailman.Errors import MMUnknownListError
+
+# Use set for sibling list recipient calculation
+try:
+ set
+except NameError: # Python2.3
+ from sets import Set as set
@@ -86,6 +95,9 @@ delivery. The original message as received by Mailman is attached.
pass
# Handle topic classifications
do_topic_filters(mlist, msg, msgdata, recips)
+ # Regular delivery exclude/include (if in/not_in To: or Cc:) lists
+ recips = do_exclude(mlist, msg, msgdata, recips)
+ recips = do_include(mlist, msg, msgdata, recips)
# Bookkeeping
msgdata['recips'] = recips
@@ -135,4 +147,66 @@ def do_topic_filters(mlist, msg, msgdata, recips):
# Prune out the non-receiving users
for user in zaprecips:
recips.remove(user)
-
+
+
+def do_exclude(mlist, msg, msgdata, recips):
+ # regular_exclude_lists are the other mailing lists on this mailman
+ # installation whose members are excluded from the regular (non-digest)
+ # delivery of this list if those list addresses appear in To: or Cc:
+ # headers.
+ if not mlist.regular_exclude_lists:
+ return recips
+ recips = set(recips)
+ destinations = email.Utils.getaddresses(msg.get_all('to', []) +
+ msg.get_all('cc', []))
+ destinations = [y for x,y in destinations]
+ for listname in mlist.regular_exclude_lists:
+ if listname not in destinations:
+ continue
+ listlhs, hostname = listname.split('@')
+ try:
+ slist = MailList(listlhs, lock=False)
+ except MMUnknownListError:
+ syslog('error', 'Exclude list %s not found.', listname)
+ continue
+ if not mm_cfg.ALLOW_CROSS_DOMAIN_SIBLING \
+ and slist.host_name != hostname:
+ syslog('error', 'Exclude list %s is not in the same domain.',
+ listname)
+ continue
+ srecips = set([slist.getMemberCPAddress(m)
+ for m in slist.getRegularMemberKeys()
+ if slist.getDeliveryStatus(m) == ENABLED])
+ recips -= srecips
+ return list(recips)
+
+
+def do_include(mlist, msg, msgdata, recips):
+ # regular_include_lists are the other mailing lists on this mailman
+ # installation whose members are included in the regular (non-digest)
+ # delivery if those list addresses don't appear in To: or Cc: headers.
+ if not mlist.regular_include_lists:
+ return recips
+ recips = set(recips)
+ destinations = email.Utils.getaddresses(msg.get_all('to', []) +
+ msg.get_all('cc', []))
+ destinations = [y for x,y in destinations]
+ for listname in mlist.regular_include_lists:
+ if listname in destinations:
+ continue
+ listlhs, hostname = listname.split('@')
+ try:
+ slist = MailList(listlhs, lock=False)
+ except MMUnknownListError:
+ syslog('error', 'Include list %s not found.', listname)
+ continue
+ if not mm_cfg.ALLOW_CROSS_DOMAIN_SIBLING \
+ and slist.host_name != hostname:
+ syslog('error', 'Include list %s is not in the same domain.',
+ listname)
+ continue
+ srecips = set([slist.getMemberCPAddress(m)
+ for m in slist.getRegularMemberKeys()
+ if slist.getDeliveryStatus(m) == ENABLED])
+ recips |= srecips
+ return list(recips)
diff --git a/Mailman/MailList.py b/Mailman/MailList.py
index b08b5973..46959c16 100644
--- a/Mailman/MailList.py
+++ b/Mailman/MailList.py
@@ -337,6 +337,8 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
self.umbrella_list = mm_cfg.DEFAULT_UMBRELLA_LIST
self.umbrella_member_suffix = \
mm_cfg.DEFAULT_UMBRELLA_MEMBER_ADMIN_SUFFIX
+ self.regular_exclude_lists = mm_cfg.DEFAULT_REGULAR_EXCLUDE_LISTS
+ self.regular_include_lists = mm_cfg.DEFAULT_REGULAR_INCLUDE_LISTS
self.send_reminders = mm_cfg.DEFAULT_SEND_REMINDERS
self.send_welcome_msg = mm_cfg.DEFAULT_SEND_WELCOME_MSG
self.send_goodbye_msg = mm_cfg.DEFAULT_SEND_GOODBYE_MSG
diff --git a/Mailman/Version.py b/Mailman/Version.py
index d1945302..e45020ad 100644
--- a/Mailman/Version.py
+++ b/Mailman/Version.py
@@ -37,7 +37,7 @@ HEX_VERSION = ((MAJOR_REV << 24) | (MINOR_REV << 16) | (MICRO_REV << 8) |
(REL_LEVEL << 4) | (REL_SERIAL << 0))
# config.pck schema version number
-DATA_FILE_VERSION = 96
+DATA_FILE_VERSION = 97
# qfile/*.db schema version number
QFILE_SCHEMA_VERSION = 3
diff --git a/Mailman/versions.py b/Mailman/versions.py
index f77eb2f2..81fafd5a 100644
--- a/Mailman/versions.py
+++ b/Mailman/versions.py
@@ -409,6 +409,11 @@ def NewVars(l):
# multipart/alternative collapse
add_only_if_missing('collapse_alternatives',
mm_cfg.DEFAULT_COLLAPSE_ALTERNATIVES)
+ # exclude/include lists
+ add_only_if_missing('regular_exclude_lists',
+ mm_cfg.DEFAULT_REGULAR_EXCLUDE_LISTS)
+ add_only_if_missing('regular_include_lists',
+ mm_cfg.DEFAULT_REGULAR_INCLUDE_LISTS)