From 69d158b13ae9cfa37040c2e7a664ca266b42050b Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Sun, 17 Feb 2008 17:34:21 -0500 Subject: Reorganize the Handler architecture to a pipeline architecture with plugins. Now plugins can define additional handlers and the handlers can be organized into named pipelines. Modules are no longer the unit of a handler, now we use classes so we can assert interface conformance. The GLOBAL_PIPELINE is gone, replaced by the 'built-in' pipeline. The OWNER_PIPELINE is not yet replaced. I still need a few more tests of the basic pipeline architecture, although the individual handlers have pretty good coverage. Added the IHandler and IPipeline interfaces. Still broken, but not yet removed: Mailman/pipeline/moderate.py. --- Mailman/pipeline/avoid_duplicates.py | 140 ++++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 60 deletions(-) (limited to 'Mailman/pipeline/avoid_duplicates.py') diff --git a/Mailman/pipeline/avoid_duplicates.py b/Mailman/pipeline/avoid_duplicates.py index 2c52a7781..78a65c8c8 100644 --- a/Mailman/pipeline/avoid_duplicates.py +++ b/Mailman/pipeline/avoid_duplicates.py @@ -23,71 +23,91 @@ has already received a copy, we either drop the message, add a duplicate warning header, or pass it through, depending on the user's preferences. """ +__metaclass__ = type +__all__ = ['AvoidDuplicates'] + + from email.Utils import getaddresses, formataddr +from zope.interface import implements + from Mailman.configuration import config +from Mailman.i18n import _ +from Mailman.interfaces import IHandler + COMMASPACE = ', ' -def process(mlist, msg, msgdata): - recips = msgdata.get('recips') - # Short circuit - if not recips: - return - # Seed this set with addresses we don't care about dup avoiding. - listaddrs = set((mlist.posting_address, - mlist.bounces_address, - mlist.owner_address, - mlist.request_address)) - explicit_recips = listaddrs.copy() - # Figure out the set of explicit recipients - cc_addresses = {} - for header in ('to', 'cc', 'resent-to', 'resent-cc'): - addrs = getaddresses(msg.get_all(header, [])) - header_addresses = dict((addr, formataddr((name, addr))) - for name, addr in addrs - if addr) - if header == 'cc': - # Yes, it's possible that an address is mentioned in multiple CC - # headers using different names. In that case, the last real name - # will win, but that doesn't seem like such a big deal. Besides, - # how else would you chose? - cc_addresses.update(header_addresses) - # Ignore the list addresses for purposes of dup avoidance. - explicit_recips |= set(header_addresses) - # Now strip out the list addresses - explicit_recips -= listaddrs - if not explicit_recips: - # No one was explicitly addressed, so we can't do any dup collapsing - return - newrecips = set() - for r in recips: - # If this recipient is explicitly addressed... - if r in explicit_recips: - send_duplicate = True - # If the member wants to receive duplicates, or if the recipient - # is not a member at all, they will get a copy. - # header. - member = mlist.members.get_member(r) - if member and not member.receive_list_copy: - send_duplicate = False - # We'll send a duplicate unless the user doesn't wish it. If - # personalization is enabled, the add-dupe-header flag will add a - # X-Mailman-Duplicate: yes header for this user's message. - if send_duplicate: - msgdata.setdefault('add-dup-header', set()).add(r) +class AvoidDuplicates: + """If the user wishes it, do not send duplicates of the same message.""" + + implements(IHandler) + + name = 'avoid-duplicates' + description = _('Suppress some duplicates of the same message.') + + def process(self, mlist, msg, msgdata): + """See `IHandler`.""" + recips = msgdata.get('recips') + # Short circuit + if not recips: + return + # Seed this set with addresses we don't care about dup avoiding. + listaddrs = set((mlist.posting_address, + mlist.bounces_address, + mlist.owner_address, + mlist.request_address)) + explicit_recips = listaddrs.copy() + # Figure out the set of explicit recipients. + cc_addresses = {} + for header in ('to', 'cc', 'resent-to', 'resent-cc'): + addrs = getaddresses(msg.get_all(header, [])) + header_addresses = dict((addr, formataddr((name, addr))) + for name, addr in addrs + if addr) + if header == 'cc': + # Yes, it's possible that an address is mentioned in multiple + # CC headers using different names. In that case, the last + # real name will win, but that doesn't seem like such a big + # deal. Besides, how else would you chose? + cc_addresses.update(header_addresses) + # Ignore the list addresses for purposes of dup avoidance. + explicit_recips |= set(header_addresses) + # Now strip out the list addresses. + explicit_recips -= listaddrs + if not explicit_recips: + # No one was explicitly addressed, so we can't do any dup + # collapsing + return + newrecips = set() + for r in recips: + # If this recipient is explicitly addressed... + if r in explicit_recips: + send_duplicate = True + # If the member wants to receive duplicates, or if the + # recipient is not a member at all, they will get a copy. + # header. + member = mlist.members.get_member(r) + if member and not member.receive_list_copy: + send_duplicate = False + # We'll send a duplicate unless the user doesn't wish it. If + # personalization is enabled, the add-dupe-header flag will + # add a X-Mailman-Duplicate: yes header for this user's + # message. + if send_duplicate: + msgdata.setdefault('add-dup-header', set()).add(r) + newrecips.add(r) + elif r in cc_addresses: + del cc_addresses[r] + else: + # Otherwise, this is the first time they've been in the recips + # list. Add them to the newrecips list and flag them as + # having received this message. newrecips.add(r) - elif r in cc_addresses: - del cc_addresses[r] - else: - # Otherwise, this is the first time they've been in the recips - # list. Add them to the newrecips list and flag them as having - # received this message. - newrecips.add(r) - # Set the new list of recipients. XXX recips should always be a set. - msgdata['recips'] = list(newrecips) - # RFC 2822 specifies zero or one CC header - if cc_addresses: - del msg['cc'] - msg['CC'] = COMMASPACE.join(cc_addresses.values()) + # Set the new list of recipients. XXX recips should always be a set. + msgdata['recips'] = list(newrecips) + # RFC 2822 specifies zero or one CC header + if cc_addresses: + del msg['cc'] + msg['CC'] = COMMASPACE.join(cc_addresses.values()) -- cgit v1.2.3-70-g09d2