diff options
-rw-r--r-- | Mailman/Defaults.py.in | 5 | ||||
-rw-r--r-- | Mailman/Gui/NonDigest.py | 24 | ||||
-rw-r--r-- | Mailman/Handlers/CalcRecips.py | 76 | ||||
-rw-r--r-- | Mailman/MailList.py | 2 | ||||
-rw-r--r-- | Mailman/Version.py | 2 | ||||
-rw-r--r-- | Mailman/versions.py | 5 |
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) |