Esempio n. 1
0
 def process(self, mlist, msg, msgdata):
     """See `IHandler`."""
     # Remove headers that could contain passwords.
     del msg['approved']
     del msg['approve']
     del msg['x-approved']
     del msg['x-approve']
     del msg['urgent']
     # We remove other headers from anonymous lists.
     if mlist.anonymous_list:
         log.info('post to %s from %s anonymized', mlist.fqdn_listname,
                  msg.get('from'))
         del msg['from']
         del msg['reply-to']
         del msg['sender']
         # Hotmail sets this one
         del msg['x-originating-email']
         i18ndesc = str(uheader(mlist, mlist.description, 'From'))
         msg['From'] = formataddr((i18ndesc, mlist.posting_address))
         msg['Reply-To'] = mlist.posting_address
     # Some headers can be used to fish for membership.
     del msg['return-receipt-to']
     del msg['disposition-notification-to']
     del msg['x-confirm-reading-to']
     # Pegasus mail uses this one... sigh.
     del msg['x-pmrqc']
     # Don't let this header be spoofed.  See RFC 5064.
     del msg['archived-at']
Esempio n. 2
0
 def process(self, mlist, msg, msgdata):
     """See `IHandler`."""
     # Remove headers that could contain passwords.
     del msg['approved']
     del msg['approve']
     del msg['x-approved']
     del msg['x-approve']
     del msg['urgent']
     # We remove other headers from anonymous lists.
     if mlist.anonymous_list:
         log.info('post to %s from %s anonymized',
                  mlist.fqdn_listname, msg.get('from'))
         del msg['from']
         del msg['reply-to']
         del msg['sender']
         # Hotmail sets this one
         del msg['x-originating-email']
         i18ndesc = str(uheader(mlist, mlist.description, 'From'))
         msg['From'] = formataddr((i18ndesc, mlist.posting_address))
         msg['Reply-To'] = mlist.posting_address
     # Some headers can be used to fish for membership.
     del msg['return-receipt-to']
     del msg['disposition-notification-to']
     del msg['x-confirm-reading-to']
     # Pegasus mail uses this one... sigh.
     del msg['x-pmrqc']
     # Don't let this header be spoofed.  See RFC 5064.
     del msg['archived-at']
Esempio n. 3
0
 def test_uheader_multiline(self):
     # Multiline headers should be truncated (GL#273).
     mark = LogFileMark('mailman.error')
     header = cook_headers.uheader(self._mlist, 'A multiline\ndescription',
                                   'X-Header')
     self.assertEqual(header.encode(), 'A multiline [...]')
     log_messages = mark.read()
     self.assertIn('Header X-Header contains a newline, truncating it',
                   log_messages)
Esempio n. 4
0
def process(mlist, msg, msgdata):
    """Add the RFC 2369 List-* and related headers."""
    # Some people really hate the List-* headers.  It seems that the free
    # version of Eudora (possibly on for some platforms) does not hide these
    # headers by default, pissing off their users.  Too bad.  Fix the MUAs.
    if not mlist.include_rfc2369_headers:
        return
    list_id = '{0.list_name}.{0.mail_host}'.format(mlist)
    if mlist.description:
        # Don't wrap the header since here we just want to get it properly RFC
        # 2047 encoded.
        i18ndesc = uheader(mlist, mlist.description, 'List-Id', maxlinelen=998)
        listid_h = formataddr((str(i18ndesc), list_id))
    else:
        # Without a description, we need to ensure the MUST brackets.
        listid_h = '<{}>'.format(list_id)
    # No other agent should add a List-ID header except Mailman.
    del msg['list-id']
    msg['List-Id'] = listid_h
    # For internally crafted messages, we also add a (nonstandard),
    # "X-List-Administrivia: yes" header.  For all others (i.e. those coming
    # from list posts), we add a bunch of other RFC 2369 headers.
    requestaddr = mlist.request_address
    headers = []
    # XXX reduced_list_headers used to suppress List-Help, List-Subject, and
    # List-Unsubscribe from UserNotification.  That doesn't seem to make sense
    # any more, so always add those three headers (others will still be
    # suppressed).
    headers.extend((
        ('List-Help', '<mailto:{}?subject=help>'.format(requestaddr)),
        ('List-Unsubscribe', '<mailto:{}>'.format(mlist.leave_address)),
        ('List-Subscribe', '<mailto:{}>'.format(mlist.join_address)),
        ))
    if not msgdata.get('reduced_list_headers'):
        # List-Post: is controlled by a separate attribute, which is somewhat
        # misnamed.  RFC 2369 requires a value of NO if posting is not
        # allowed, i.e. for an announce-only list.
        list_post = ('<mailto:{}>'.format(mlist.posting_address)
                     if mlist.allow_list_posts
                     else 'NO')
        headers.append(('List-Post', list_post))
        # Add RFC 2369 and 5064 archiving headers, if archiving is enabled.
        if mlist.archive_policy is not ArchivePolicy.never:
            archiver_set = IListArchiverSet(mlist)
            for archiver in archiver_set.archivers:
                if not archiver.is_enabled:
                    continue
                # Watch out for exceptions in the archiver plugin.
                try:
                    archiver_url = archiver.system_archiver.list_url(mlist)
                except Exception:
                    log.exception('Exception in "{}" archiver'.format(
                        archiver.system_archiver.name))
                    archiver_url = None
                if archiver_url is not None:
                    headers.append(('List-Archive',
                                    '<{}>'.format(archiver_url)))
                try:
                    permalink = archiver.system_archiver.permalink(mlist, msg)
                except Exception:
                    log.exception('Exception in "{}" archiver'.format(
                        archiver.system_archiver.name))
                    permalink = None
                if permalink is not None:
                    headers.append(('Archived-At', '<{}>'.format(permalink)))
    # XXX RFC 2369 also defines a List-Owner header which we are not currently
    # supporting, but should.
    #
    # Some headers will appear more than once in the new set, e.g. the
    # List-Archive and Archived-At headers.  We want to delete any RFC 2369
    # headers from the original message, but make sure to preserve all of the
    # new headers we're adding.  Go through the list of new headers twice,
    # first removing any old ones, then adding all the new ones.
    for h, v in headers:
        del msg[h]
    for h, v in sorted(headers):
        # Wrap these lines if they are too long.  78 character width probably
        # shouldn't be hardcoded, but is at least text-MUA friendly.  The
        # adding of 2 is for the colon-space separator.
        if len(h) + 2 + len(v) > 78:
            v = CONTINUATION.join(v.split(', '))
        msg[h] = v
Esempio n. 5
0
def process(mlist, msg, msgdata):
    """Add the RFC 2369 List-* and related headers."""
    # Some people really hate the List-* headers.  It seems that the free
    # version of Eudora (possibly on for some platforms) does not hide these
    # headers by default, pissing off their users.  Too bad.  Fix the MUAs.
    if not mlist.include_rfc2369_headers:
        return
    list_id = '{0.list_name}.{0.mail_host}'.format(mlist)
    if mlist.description:
        # Don't wrap the header since here we just want to get it properly RFC
        # 2047 encoded.
        i18ndesc = uheader(mlist, mlist.description, 'List-Id', maxlinelen=998)
        listid_h = formataddr((str(i18ndesc), list_id))
    else:
        # Without a description, we need to ensure the MUST brackets.
        listid_h = '<{}>'.format(list_id)
    # No other agent should add a List-ID header except Mailman.
    del msg['list-id']
    msg['List-Id'] = listid_h
    # For internally crafted messages, we also add a (nonstandard),
    # "X-List-Administrivia: yes" header.  For all others (i.e. those coming
    # from list posts), we add a bunch of other RFC 2369 headers.
    requestaddr = mlist.request_address
    subfieldfmt = '<{}>, <mailto:{}>'
    listinfo = mlist.script_url('listinfo')
    headers = []
    # XXX reduced_list_headers used to suppress List-Help, List-Subject, and
    # List-Unsubscribe from UserNotification.  That doesn't seem to make sense
    # any more, so always add those three headers (others will still be
    # suppressed).
    headers.extend((
        ('List-Help', '<mailto:{}?subject=help>'.format(requestaddr)),
        ('List-Unsubscribe',
         subfieldfmt.format(listinfo, mlist.leave_address)),
        ('List-Subscribe', subfieldfmt.format(listinfo, mlist.join_address)),
        ))
    if not msgdata.get('reduced_list_headers'):
        # List-Post: is controlled by a separate attribute, which is somewhat
        # misnamed.  RFC 2369 requires a value of NO if posting is not
        # allowed, i.e. for an announce-only list.
        list_post = ('<mailto:{}>'.format(mlist.posting_address)
                     if mlist.allow_list_posts
                     else 'NO')
        headers.append(('List-Post', list_post))
        # Add RFC 2369 and 5064 archiving headers, if archiving is enabled.
        if mlist.archive_policy is not ArchivePolicy.never:
            archiver_set = IListArchiverSet(mlist)
            for archiver in archiver_set.archivers:
                if not archiver.is_enabled:
                    continue
                # Watch out for exceptions in the archiver plugin.
                try:
                    archiver_url = archiver.system_archiver.list_url(mlist)
                except Exception:
                    log.exception('Exception in "{}" archiver'.format(
                        archiver.system_archiver.name))
                    archiver_url = None
                if archiver_url is not None:
                    headers.append(('List-Archive',
                                    '<{}>'.format(archiver_url)))
                try:
                    permalink = archiver.system_archiver.permalink(mlist, msg)
                except Exception:
                    log.exception('Exception in "{}" archiver'.format(
                        archiver.system_archiver.name))
                    permalink = None
                if permalink is not None:
                    headers.append(('Archived-At', '<{}>'.format(permalink)))
    # XXX RFC 2369 also defines a List-Owner header which we are not currently
    # supporting, but should.
    #
    # Some headers will appear more than once in the new set, e.g. the
    # List-Archive and Archived-At headers.  We want to delete any RFC 2369
    # headers from the original message, but make sure to preserve all of the
    # new headers we're adding.  Go through the list of new headers twice,
    # first removing any old ones, then adding all the new ones.
    for h, v in headers:
        del msg[h]
    for h, v in sorted(headers):
        # Wrap these lines if they are too long.  78 character width probably
        # shouldn't be hardcoded, but is at least text-MUA friendly.  The
        # adding of 2 is for the colon-space separator.
        if len(h) + 2 + len(v) > 78:
            v = CONTINUATION.join(v.split(', '))
        msg[h] = v
Esempio n. 6
0
def process(mlist, msg, msgdata):
    """Add the RFC 2369 List-* and related headers."""
    # Some people really hate the List-* headers.  It seems that the free
    # version of Eudora (possibly on for some platforms) does not hide these
    # headers by default, pissing off their users.  Too bad.  Fix the MUAs.
    if not mlist.include_rfc2369_headers:
        return
    list_id = '{0.list_name}.{0.mail_host}'.format(mlist)
    if mlist.description:
        # Don't wrap the header since here we just want to get it properly RFC
        # 2047 encoded.
        i18ndesc = uheader(mlist, mlist.description, 'List-Id', maxlinelen=998)
        listid_h = formataddr((str(i18ndesc), list_id))
    else:
        # Without a description, we need to ensure the MUST brackets.
        listid_h = '<{0}>'.format(list_id)
    # No other agent should add a List-ID header except Mailman.
    del msg['list-id']
    msg['List-Id'] = listid_h
    # For internally crafted messages, we also add a (nonstandard),
    # "X-List-Administrivia: yes" header.  For all others (i.e. those coming
    # from list posts), we add a bunch of other RFC 2369 headers.
    requestaddr = mlist.request_address
    subfieldfmt = '<{0}>, <mailto:{1}>'
    listinfo = mlist.script_url('listinfo')
    headers = {}
    # XXX reduced_list_headers used to suppress List-Help, List-Subject, and
    # List-Unsubscribe from UserNotification.  That doesn't seem to make sense
    # any more, so always add those three headers (others will still be
    # suppressed).
    headers.update({
        'List-Help'       : '<mailto:{0}?subject=help>'.format(requestaddr),
        'List-Unsubscribe': subfieldfmt.format(listinfo, mlist.leave_address),
        'List-Subscribe'  : subfieldfmt.format(listinfo, mlist.join_address),
        })
    if not msgdata.get('reduced_list_headers'):
        # List-Post: is controlled by a separate attribute, which is somewhat
        # misnamed.  RFC 2369 requires a value of NO if posting is not
        # allowed, i.e. for an announce-only list.
        list_post = ('<mailto:{0}>'.format(mlist.posting_address)
                     if mlist.allow_list_posts
                     else 'NO')
        headers['List-Post'] = list_post
        # Add RFC 2369 and 5064 archiving headers, if archiving is enabled.
        if mlist.archive_policy is not ArchivePolicy.never:
            for archiver in config.archivers:
                headers['List-Archive'] = '<{0}>'.format(
                    archiver.list_url(mlist))
                permalink = archiver.permalink(mlist, msg)
                if permalink is not None:
                    headers['Archived-At'] = permalink
    # XXX RFC 2369 also defines a List-Owner header which we are not currently
    # supporting, but should.
    for h, v in headers.items():
        # First we delete any pre-existing headers because the RFC permits
        # only one copy of each, and we want to be sure it's ours.
        del msg[h]
        # Wrap these lines if they are too long.  78 character width probably
        # shouldn't be hardcoded, but is at least text-MUA friendly.  The
        # adding of 2 is for the colon-space separator.
        if len(h) + 2 + len(v) > 78:
            v = CONTINUATION.join(v.split(', '))
        msg[h] = v