1
# Copyright (C) 1998-2013 by the Free Software Foundation, Inc.
1
# Copyright (C) 1998-2011 by the Free Software Foundation, Inc.
3
3
# This program is free software; you can redistribute it and/or
4
4
# modify it under the terms of the GNU General Public License
64
64
charset = 'us-ascii'
65
65
return Header(s, charset, maxlinelen, header_name, continuation_ws)
67
def change_header(name, value, mlist, msg, msgdata, delete=True, repl=True):
68
if mm_cfg.ALLOW_FROM_IS_LIST and mlist.from_is_list == 2:
69
msgdata.setdefault('add_header', {})[name] = value
70
elif repl or not msg.has_key(name):
77
69
def process(mlist, msg, msgdata):
78
70
# Set the "X-Ack: no" header if noack flag is set.
79
71
if msgdata.get('noack'):
80
change_header('X-Ack', 'no', mlist, msg, msgdata)
81
74
# Because we're going to modify various important headers in the email
82
75
# message, we want to save some of the information in the msgdata
83
76
# dictionary for later. Specifically, the sender header will get waxed,
95
88
# Mark message so we know we've been here, but leave any existing
96
89
# X-BeenThere's intact.
97
change_header('X-BeenThere', mlist.GetListEmail(),
98
mlist, msg, msgdata, delete=False)
90
msg['X-BeenThere'] = mlist.GetListEmail()
99
91
# Add Precedence: and other useful headers. None of these are standard
100
92
# and finding information on some of them are fairly difficult. Some are
101
93
# just common practice, and we'll add more here as they become necessary.
109
101
# known exploits in a particular version of Mailman and we know a site is
110
102
# using such an old version, they may be vulnerable. It's too easy to
111
103
# edit the code to add a configuration variable to handle this.
112
change_header('X-Mailman-Version', mm_cfg.VERSION,
113
mlist, msg, msgdata, repl=False)
104
if not msg.has_key('x-mailman-version'):
105
msg['X-Mailman-Version'] = mm_cfg.VERSION
114
106
# We set "Precedence: list" because this is the recommendation from the
115
107
# sendmail docs, the most authoritative source of this header's semantics.
116
change_header('Precedence', 'list',
117
mlist, msg, msgdata, repl=False)
118
# Do we change the from so the list takes ownership of the email
119
if mm_cfg.ALLOW_FROM_IS_LIST and mlist.from_is_list:
120
realname, email = parseaddr(msg['from'])
121
replies = getaddresses(msg.get('reply-to', ''))
122
reply_addrs = [x[1].lower() for x in replies]
124
if email.lower() not in reply_addrs:
125
rt = msg['reply-to'] + ', ' + msg['from']
130
change_header('Reply-To', rt, mlist, msg, msgdata)
131
change_header('From',
132
formataddr(('%s via %s' % (realname, mlist.real_name),
133
mlist.GetListEmail())),
135
if mlist.from_is_list != 2:
137
#MAS ?? mlist.include_sender_header = 0
108
if not msg.has_key('precedence'):
109
msg['Precedence'] = 'list'
138
110
# Reply-To: munging. Do not do this if the message is "fast tracked",
139
111
# meaning it is internally crafted and delivered to a specific user. BAW:
140
112
# Yuck, I really hate this feature but I've caved under the sheer pressure
170
142
if mlist.reply_goes_to_list == 1:
171
143
i18ndesc = uheader(mlist, mlist.description, 'Reply-To')
172
144
add((str(i18ndesc), mlist.GetListEmail()))
173
146
# Don't put Reply-To: back if there's nothing to add!
176
change_header('Reply-To',
177
COMMASPACE.join([formataddr(pair) for pair in new]),
149
msg['Reply-To'] = COMMASPACE.join(
150
[formataddr(pair) for pair in new])
181
151
# The To field normally contains the list posting address. However
182
152
# when messages are fully personalized, that header will get
183
153
# overwritten with the address of the recipient. We need to get the
187
157
# Cc header. BAW: should we force it into a Reply-To header in the
189
159
# Also skip Cc if this is an anonymous list as list posting address
190
# is already in From and Reply-To in this case and similarly for
191
# an 'author is list' list.
160
# is already in From and Reply-To in this case.
192
161
if mlist.personalize == 2 and mlist.reply_goes_to_list <> 1 \
193
and not mlist.anonymous_list and not (mlist.from_is_list and
194
mm_cfg.ALLOW_FROM_IS_LIST):
162
and not mlist.anonymous_list:
195
163
# Watch out for existing Cc headers, merge, and remove dups. Note
196
164
# that RFC 2822 says only zero or one Cc header is allowed.
201
169
i18ndesc = uheader(mlist, mlist.description, 'Cc')
202
170
add((str(i18ndesc), mlist.GetListEmail()))
203
# We don't worry about what AvoidDuplicates may have done with a
204
# Cc: header or using change_header here since we never get here
205
# if from_is_list is allowed and True.
207
172
msg['Cc'] = COMMASPACE.join([formataddr(pair) for pair in new])
208
173
# Add list-specific headers as defined in RFC 2369 and RFC 2919, but only
226
191
# without desc we need to ensure the MUST brackets
227
192
listid_h = '<%s>' % listid
228
193
# We always add a List-ID: header.
229
change_header('List-Id', listid_h, mlist, msg, msgdata)
195
msg['List-Id'] = listid_h
230
196
# For internally crafted messages, we also add a (nonstandard),
231
197
# "X-List-Administrivia: yes" header. For all others (i.e. those coming
232
198
# from list posts), we add a bunch of other RFC 2369 headers.
253
219
# First we delete any pre-existing headers because the RFC permits only
254
220
# one copy of each, and we want to be sure it's ours.
255
221
for h, v in headers.items():
256
223
# Wrap these lines if they are too long. 78 character width probably
257
224
# shouldn't be hardcoded, but is at least text-MUA friendly. The
258
225
# adding of 2 is for the colon-space separator.
259
226
if len(h) + 2 + len(v) > 78:
260
227
v = CONTINUATION.join(v.split(', '))
261
change_header(h, v, mlist, msg, msgdata)
335
302
h = u' '.join([prefix, subject])
336
303
h = h.encode('us-ascii')
337
304
h = uheader(mlist, h, 'Subject', continuation_ws=ws)
338
change_header('Subject', h, mlist, msg, msgdata)
339
307
ss = u' '.join([recolon, subject])
340
308
ss = ss.encode('us-ascii')
341
309
ss = uheader(mlist, ss, 'Subject', continuation_ws=ws)
353
321
# TK: Subject is concatenated and unicode string.
354
322
subject = subject.encode(cset, 'replace')
355
323
h.append(subject, cset)
356
change_header('Subject', h, mlist, msg, msgdata)
357
326
ss = uheader(mlist, recolon, 'Subject', continuation_ws=ws)
358
327
ss.append(subject, cset)
359
328
msgdata['stripped_subject'] = ss