~tgc/mailman/2.1-da

« back to all changes in this revision

Viewing changes to Mailman/Handlers/CookHeaders.py

  • Committer: Mark Sapiro
  • Date: 2013-09-27 23:33:35 UTC
  • Revision ID: mark@msapiro.net-20130927233335-o2pmv0e5k0f77sb8
Made author_is_list a 3-way with an option to wrap the message.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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_AUTHOR_IS_LIST and mlist.author_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
 
67
75
 
68
76
 
69
77
def process(mlist, msg, msgdata):
70
78
    # Set the "X-Ack: no" header if noack flag is set.
71
79
    if msgdata.get('noack'):
72
 
        del msg['x-ack']
73
 
        msg['X-Ack'] = 'no'
 
80
        change_header('X-Ack', 'no', mlist, msg, msgdata)
74
81
    # Because we're going to modify various important headers in the email
75
82
    # message, we want to save some of the information in the msgdata
76
83
    # dictionary for later.  Specifically, the sender header will get waxed,
87
94
            pass
88
95
    # Mark message so we know we've been here, but leave any existing
89
96
    # X-BeenThere's intact.
90
 
    msg['X-BeenThere'] = mlist.GetListEmail()
 
97
    change_header('X-BeenThere', mlist.GetListEmail(),
 
98
                  mlist, msg, msgdata, delete=False)
91
99
    # Add Precedence: and other useful headers.  None of these are standard
92
100
    # and finding information on some of them are fairly difficult.  Some are
93
101
    # just common practice, and we'll add more here as they become necessary.
101
109
    # known exploits in a particular version of Mailman and we know a site is
102
110
    # using such an old version, they may be vulnerable.  It's too easy to
103
111
    # edit the code to add a configuration variable to handle this.
104
 
    if not msg.has_key('x-mailman-version'):
105
 
        msg['X-Mailman-Version'] = mm_cfg.VERSION
 
112
    change_header('X-Mailman-Version', mm_cfg.VERSION,
 
113
                  mlist, msg, msgdata, repl=False)
106
114
    # We set "Precedence: list" because this is the recommendation from the
107
115
    # sendmail docs, the most authoritative source of this header's semantics.
108
 
    if not msg.has_key('precedence'):
109
 
        msg['Precedence'] = 'list'
 
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_AUTHOR_IS_LIST and mlist.author_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.author_is_list != 2:
 
136
            del msg['sender']
 
137
        #MAS ?? mlist.include_sender_header = 0
110
138
    # Reply-To: munging.  Do not do this if the message is "fast tracked",
111
139
    # meaning it is internally crafted and delivered to a specific user.  BAW:
112
140
    # Yuck, I really hate this feature but I've caved under the sheer pressure
142
170
        if mlist.reply_goes_to_list == 1:
143
171
            i18ndesc = uheader(mlist, mlist.description, 'Reply-To')
144
172
            add((str(i18ndesc), mlist.GetListEmail()))
145
 
        del msg['reply-to']
146
173
        # Don't put Reply-To: back if there's nothing to add!
147
174
        if new:
148
175
            # Preserve order
149
 
            msg['Reply-To'] = COMMASPACE.join(
150
 
                [formataddr(pair) for pair in new])
 
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']
151
181
        # The To field normally contains the list posting address.  However
152
182
        # when messages are fully personalized, that header will get
153
183
        # overwritten with the address of the recipient.  We need to get the
170
200
                add(pair)
171
201
            i18ndesc = uheader(mlist, mlist.description, 'Cc')
172
202
            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 author_is_list is allowed and True.
173
206
            del msg['Cc']
174
207
            msg['Cc'] = COMMASPACE.join([formataddr(pair) for pair in new])
175
208
    # Add list-specific headers as defined in RFC 2369 and RFC 2919, but only
193
226
        # without desc we need to ensure the MUST brackets
194
227
        listid_h = '<%s>' % listid
195
228
    # We always add a List-ID: header.
196
 
    del msg['list-id']
197
 
    msg['List-Id'] = listid_h
 
229
    change_header('List-Id', listid_h, mlist, msg, msgdata)
198
230
    # For internally crafted messages, we also add a (nonstandard),
199
231
    # "X-List-Administrivia: yes" header.  For all others (i.e. those coming
200
232
    # from list posts), we add a bunch of other RFC 2369 headers.
221
253
    # First we delete any pre-existing headers because the RFC permits only
222
254
    # one copy of each, and we want to be sure it's ours.
223
255
    for h, v in headers.items():
224
 
        del msg[h]
225
256
        # Wrap these lines if they are too long.  78 character width probably
226
257
        # shouldn't be hardcoded, but is at least text-MUA friendly.  The
227
258
        # adding of 2 is for the colon-space separator.
228
259
        if len(h) + 2 + len(v) > 78:
229
260
            v = CONTINUATION.join(v.split(', '))
230
 
        msg[h] = v
 
261
        change_header(h, v, mlist, msg, msgdata)
231
262
 
232
263
 
233
264
 
304
335
                    h = u' '.join([prefix, subject])
305
336
            h = h.encode('us-ascii')
306
337
            h = uheader(mlist, h, 'Subject', continuation_ws=ws)
307
 
            del msg['subject']
308
 
            msg['Subject'] = h
 
338
            change_header('Subject', h, mlist, msg, msgdata)
309
339
            ss = u' '.join([recolon, subject])
310
340
            ss = ss.encode('us-ascii')
311
341
            ss = uheader(mlist, ss, 'Subject', continuation_ws=ws)
323
353
    # TK: Subject is concatenated and unicode string.
324
354
    subject = subject.encode(cset, 'replace')
325
355
    h.append(subject, cset)
326
 
    del msg['subject']
327
 
    msg['Subject'] = h
 
356
    change_header('Subject', h, mlist, msg, msgdata)
328
357
    ss = uheader(mlist, recolon, 'Subject', continuation_ws=ws)
329
358
    ss.append(subject, cset)
330
359
    msgdata['stripped_subject'] = ss