~tgc/mailman/2.1-da

« back to all changes in this revision

Viewing changes to Mailman/Handlers/CookHeaders.py

  • Committer: Mark Sapiro
  • Date: 2013-04-07 05:54:18 UTC
  • Revision ID: msapiro@value.net-20130407055418-3ocsw3ajga2vv82l
Defended against buggy web servers that don't include an empty
QUERY_STRING in the CGI environment.  (LP: 1160647)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 1998-2013 by the Free Software Foundation, Inc.
 
1
# Copyright (C) 1998-2011 by the Free Software Foundation, Inc.
2
2
#
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)
66
66
 
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):
71
 
        if delete:
72
 
            del msg[name]
73
 
        msg[name] = value
74
 
 
75
67
 
76
68
 
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)
 
72
        del msg['x-ack']
 
73
        msg['X-Ack'] = 'no'
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,
94
87
            pass
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]
123
 
        if reply_addrs:
124
 
            if email.lower() not in reply_addrs:
125
 
                rt = msg['reply-to'] + ', ' + msg['from']
126
 
            else:
127
 
                rt = msg['reply-to']
128
 
        else:
129
 
            rt = 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())),
134
 
                      mlist, msg, msgdata)
135
 
        if mlist.from_is_list != 2:
136
 
            del msg['sender']
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()))
 
145
        del msg['reply-to']
173
146
        # Don't put Reply-To: back if there's nothing to add!
174
147
        if new:
175
148
            # Preserve order
176
 
            change_header('Reply-To', 
177
 
                          COMMASPACE.join([formataddr(pair) for pair in new]),
178
 
                          mlist, msg, msgdata)
179
 
        else:
180
 
            del msg['reply-to']
 
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
188
158
        # above code?
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.
197
165
            new = []
200
168
                add(pair)
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.
206
171
            del msg['Cc']
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)
 
194
    del msg['list-id']
 
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():
 
222
        del msg[h]
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)
 
228
        msg[h] = v
262
229
 
263
230
 
264
231
 
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)
 
305
            del msg['subject']
 
306
            msg['Subject'] = h
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)
 
324
    del msg['subject']
 
325
    msg['Subject'] = h
357
326
    ss = uheader(mlist, recolon, 'Subject', continuation_ws=ws)
358
327
    ss.append(subject, cset)
359
328
    msgdata['stripped_subject'] = ss