Example #1
0
 def __init__(self, config):
     self._sender = Sender(config)
     self._mgr = MemberMgr(config)
     self._store = Store(config)
     self._cfg = config
     self._manifest = json.load(open('manifest.json'))
Example #2
0
class Distributor(object):
    '''
    This class is responsible for distributing mails to the members of the list, making sure
    the right members get mails and processing the mails according to the configuration.

    The actual process of distributing emails, be it online or offline, is left to subclasses.

    Most options are configurable via json configuration files.
    '''

    def __init__(self, config):
        self._sender = Sender(config)
        self._mgr = MemberMgr(config)
        self._store = Store(config)
        self._cfg = config
        self._manifest = json.load(open('manifest.json'))

    def _isvalid(self, msg):
        '''
        Checks if the message can be delivered.

        The rules for delivering a message are:
        - Valid if:
         - comes from a member of the list
         - comes from a whitelisted address
        - Invalid if:
         - comes from a blacklisted address
         - comes from any other address
         - a message with the same id is already present in the database
        '''
        email = self._find_sender_email(msg)
        if self._mgr.isblacklisted(email):
            logger.info('Message received from blacklisted email %s', email)
            return False
        if self._store.message_exists(msg.id):
            logger.error('Message with id %s already exists in the database', msg.id)
            return False

        if self._cfg['accept_whitelist_only']:
            return self._mgr.find_member(email) is not None or self._mgr.iswhitelisted(email)
        else:
            return True

    def _find_sender_email(self, msg):
        '''
        Finds the email of the sender of the given message. The *From* and *Return-Path* headers
        from the message are searched. An empty string is returned in case the email
        cannot be found.
        '''
        candidates = [ msg['From'], msg['Return-Path']]
        for candidate in candidates:
            match = BASIC_EMAIL.search(candidate)
            if match and len(match.groups()) == 1:
                logger.debug('_find_sender_email found %s', match.group(1))
                # Normalize
                return match.group(1).lower()
        logger.debug('_find_sender_email did not find the email in %s', candidates)
        return ''

    def _find_actual_text(self, msg):
        '''Yields all the parts of the message that can be interpreted as text.'''
        for part in msg.walk():
            if 'text' == part.get_content_maintype():
                yield part

    def _create_header(self, msg):
        '''
        Creates a header for the message, returned as a list of strings. The header contains the
        name of the sender and an introduction message.
        '''
        email = self._find_sender_email(msg)
        member = self._mgr.find_member(email)
        if member is not None:
            return self._join_header(self._mgr.choose_name(member))
        elif email != '':
            addr, _ = email.split('@')
            return self._join_header(addr)
        return ['']

    def _join_header(self, person):
        header = person + ' ' + self._choose_intro() + ':'
        logger.debug('_create_header produced: %s',  header)
        return [header]