# Copyright (C) 2011-2012 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # # GNU Mailman is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) # any later version. # # GNU Mailman is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # GNU Mailman. If not, see . """RFC 2369 List-* and related headers.""" from __future__ import absolute_import, unicode_literals __metaclass__ = type __all__ = [ 'process', ] from email.utils import formataddr from mailman.config import config from mailman.pipeline.cook_headers import uheader CONTINUATION = ',\n\t' 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}>, ' 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' : ''.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 if mlist.include_list_post_header: headers['List-Post'] = ''.format(mlist.posting_address) # Add RFC 2369 and 5064 archiving headers, if archiving is enabled. if mlist.archive: 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