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.lower() for x,y in destinations] for listname in mlist.regular_include_lists: listname = listname.lower() if listname in destinations: continue listlhs, hostname = listname.split('@') if listlhs == mlist.internal_name(): syslog('error', 'Include list %s is a self reference.', listname) continue 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)
def _update_list_subscriptions(self, list_name, subscription_info): """Update the subscription information for a single mailing list. :param list_name: The name of the mailing list to update. :type list_name: string :param subscription_info: The mailing list's new subscription information. :type subscription_info: a list of 4-tuples containing the address, real name, flags, and status of each person in the list's subscribers. """ ## syslog('xmlrpc', '%s subinfo: %s', list_name, subscription_info) # Start with an unlocked list. mlist = MailList(list_name, lock=False) # Create a mapping of email address to the member's real name, # flags, and status. Note that flags is currently unused. member_map = dict( (address, (realname, flags, status)) for address, realname, flags, status in subscription_info) # In Mailman parlance, the 'member key' is the lower-cased # address. We need a mapping from the member key to # case-preserved address for all future members of the list. key_to_case_preserved = dict( (address.lower(), address) for address in member_map) # The following modifications to membership may be made: # - Current members whose address is changing case # - New members who need to be added to the mailing list # - Old members who need to be removed from the mailing list # - Current members whose settings are being changed # # Start by getting the case-folded membership sets of all current # and future members. current_members = set(mlist.getMembers()) future_members = set(key_to_case_preserved) # Additions are all those addresses in future_members who are not # in current_members. additions = future_members - current_members # Deletions are all those addresses in current_members who are not # in future_members. deletions = current_members - future_members # Any address in both current and future members is either # changing case, updating settings, or both. updates = current_members & future_members # If there's nothing to do, just skip this list. if not additions and not deletions and not updates: # Why did we get here? This list should not have shown up in # getMembershipInformation(). syslog('xmlrpc', 'Strange subscription information for list: %s', list_name) return # Lock the list and make the modifications. Don't worry if the list # couldn't be locked, we'll just log that and try again the next time # through the loop. Eventually any existing lock will expire anyway. try: mlist.Lock(2) except TimeOutError: syslog('xmlrpc', 'Could not lock the list to update subscriptions: %s', list_name) return try: # Handle additions first. if len(additions) > 0: syslog('xmlrpc', 'Adding to %s: %s', list_name, additions) for address in additions: # When adding the new member, be sure to use the # case-preserved email address. original_address = key_to_case_preserved[address] realname, flags, status = member_map[original_address] mlist.addNewMember(original_address, realname=realname) mlist.setDeliveryStatus(original_address, status) # Handle deletions next. if len(deletions) > 0: syslog('xmlrpc', 'Removing from %s: %s', list_name, deletions) for address in deletions: mlist.removeMember(address) # Updates can be either a settings update, a change in the # case of the subscribed address, or both. found_updates = [] for address in updates: # See if the case is changing. current_address = mlist.getMemberCPAddress(address) future_address = key_to_case_preserved[address] if current_address != future_address: mlist.changeMemberAddress(address, future_address) found_updates.append('%s -> %s' % (address, future_address)) # flags are ignored for now. realname, flags, status = member_map[future_address] if realname != mlist.getMemberName(address): mlist.setMemberName(address, realname) found_updates.append('%s new name: %s' % (address, realname)) if status != mlist.getDeliveryStatus(address): mlist.setDeliveryStatus(address, status) found_updates.append('%s new status: %s' % (address, status)) if len(found_updates) > 0: syslog('xmlrpc', 'Membership updates for %s: %s', list_name, found_updates) # We're done, so flush the changes for this mailing list. mlist.Save() finally: mlist.Unlock()
def _update_list_subscriptions(self, list_name, subscription_info): """Update the subscription information for a single mailing list. :param list_name: The name of the mailing list to update. :type list_name: string :param subscription_info: The mailing list's new subscription information. :type subscription_info: a list of 4-tuples containing the address, real name, flags, and status of each person in the list's subscribers. """ ## syslog('xmlrpc', '%s subinfo: %s', list_name, subscription_info) # Start with an unlocked list. mlist = MailList(list_name, lock=False) # Create a mapping of email address to the member's real name, # flags, and status. Note that flags is currently unused. member_map = dict( (address, (realname, flags, status)) for address, realname, flags, status in subscription_info ) # In Mailman parlance, the 'member key' is the lower-cased # address. We need a mapping from the member key to # case-preserved address for all future members of the list. key_to_case_preserved = dict((address.lower(), address) for address in member_map) # The following modifications to membership may be made: # - Current members whose address is changing case # - New members who need to be added to the mailing list # - Old members who need to be removed from the mailing list # - Current members whose settings are being changed # # Start by getting the case-folded membership sets of all current # and future members. current_members = set(mlist.getMembers()) future_members = set(key_to_case_preserved) # Additions are all those addresses in future_members who are not # in current_members. additions = future_members - current_members # Deletions are all those addresses in current_members who are not # in future_members. deletions = current_members - future_members # Any address in both current and future members is either # changing case, updating settings, or both. updates = current_members & future_members # If there's nothing to do, just skip this list. if not additions and not deletions and not updates: # Why did we get here? This list should not have shown up in # getMembershipInformation(). syslog("xmlrpc", "Strange subscription information for list: %s", list_name) return # Lock the list and make the modifications. Don't worry if the list # couldn't be locked, we'll just log that and try again the next time # through the loop. Eventually any existing lock will expire anyway. try: mlist.Lock(2) except TimeOutError: syslog("xmlrpc", "Could not lock the list to update subscriptions: %s", list_name) return try: # Handle additions first. if len(additions) > 0: syslog("xmlrpc", "Adding to %s: %s", list_name, additions) for address in additions: # When adding the new member, be sure to use the # case-preserved email address. original_address = key_to_case_preserved[address] realname, flags, status = member_map[original_address] mlist.addNewMember(original_address, realname=realname) mlist.setDeliveryStatus(original_address, status) # Handle deletions next. if len(deletions) > 0: syslog("xmlrpc", "Removing from %s: %s", list_name, deletions) for address in deletions: mlist.removeMember(address) # Updates can be either a settings update, a change in the # case of the subscribed address, or both. found_updates = [] for address in updates: # See if the case is changing. current_address = mlist.getMemberCPAddress(address) future_address = key_to_case_preserved[address] if current_address != future_address: mlist.changeMemberAddress(address, future_address) found_updates.append("%s -> %s" % (address, future_address)) # flags are ignored for now. realname, flags, status = member_map[future_address] if realname != mlist.getMemberName(address): mlist.setMemberName(address, realname) found_updates.append("%s new name: %s" % (address, realname)) if status != mlist.getDeliveryStatus(address): mlist.setDeliveryStatus(address, status) found_updates.append("%s new status: %s" % (address, status)) if len(found_updates) > 0: syslog("xmlrpc", "Membership updates for %s: %s", list_name, found_updates) # We're done, so flush the changes for this mailing list. mlist.Save() finally: mlist.Unlock()