~msapiro/mailman/topics

« back to all changes in this revision

Viewing changes to Mailman/Handlers/SpamDetect.py

  • Committer: Mark Sapiro
  • Date: 2008-12-03 00:35:43 UTC
  • mto: (1006.1.48 2.2)
  • mto: This revision was merged to the branch mainline in revision 1008.
  • Revision ID: mark@msapiro.net-20081203003543-7ylq210dxz1k5nt5
Fixed a problem in SpamDetect.py that could cause header_filter_rules
to fail to match RFC 2047 encoded headers.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 1998-2007 by the Free Software Foundation, Inc.
 
1
# Copyright (C) 1998-2008 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
26
26
"""
27
27
 
28
28
import re
29
 
from cStringIO import StringIO
30
29
 
31
 
from email.Generator import Generator
 
30
from email.Header import decode_header
32
31
 
33
32
from Mailman import mm_cfg
34
33
from Mailman import Errors
35
34
from Mailman import i18n
 
35
from Mailman.Utils import GetCharSet
36
36
from Mailman.Handlers.Hold import hold_for_approval
37
37
 
38
38
try:
60
60
 
61
61
 
62
62
 
63
 
class Tee:
64
 
    def __init__(self, outfp_a, outfp_b):
65
 
        self._outfp_a = outfp_a
66
 
        self._outfp_b = outfp_b
67
 
 
68
 
    def write(self, s):
69
 
        self._outfp_a.write(s)
70
 
        self._outfp_b.write(s)
71
 
 
72
 
 
73
 
# Class to capture the headers separate from the message body
74
 
class HeaderGenerator(Generator):
75
 
    def __init__(self, outfp, mangle_from_=True, maxheaderlen=78):
76
 
        Generator.__init__(self, outfp, mangle_from_, maxheaderlen)
77
 
        self._headertxt = ''
78
 
 
79
 
    def _write_headers(self, msg):
80
 
        sfp = StringIO()
81
 
        oldfp = self._fp
82
 
        self._fp = Tee(oldfp, sfp)
83
 
        try:
84
 
            Generator._write_headers(self, msg)
85
 
        finally:
86
 
            self._fp = oldfp
87
 
        self._headertxt = sfp.getvalue()
88
 
 
89
 
    def header_text(self):
90
 
        return self._headertxt
 
63
def getDecodedHeaders(msg, cset='utf-8'):
 
64
    """Returns a string containing all the headers of msg, unfolded and
 
65
    RFC 2047 decoded and encoded in cset.
 
66
    """
 
67
 
 
68
    headers = ''
 
69
    for h, v in msg.items():
 
70
        uvalue = u''
 
71
        v = decode_header(re.sub('\n\s', ' ', v))
 
72
        for frag, cs in v:
 
73
            if not cs:
 
74
                cs = 'us-ascii'
 
75
            uvalue += unicode(frag, cs, 'replace')
 
76
        headers += '%s: %s\n' % (h, uvalue.encode(cset, 'replace'))
 
77
    return headers
91
78
 
92
79
 
93
80
 
106
93
    # TK: Collect headers in sub-parts because attachment filename
107
94
    # extension may be a clue to possible virus/spam.
108
95
    headers = ''
 
96
    # Get the character set of the lists preferred language for headers
 
97
    lcset = GetCharSet(mlist.preferred_language)
109
98
    for p in msg.walk():
110
 
        g = HeaderGenerator(StringIO())
111
 
        g.flatten(p)
112
 
        headers += g.header_text()
113
 
    # Now reshape headers (remove extra CR and connect multiline).
114
 
    headers = re.sub('\n+', '\n', headers)
115
 
    headers = re.sub('\n\s', ' ', headers)
 
99
        headers += getDecodedHeaders(p, lcset)
116
100
    for patterns, action, empty in mlist.header_filter_rules:
117
101
        if action == mm_cfg.DEFER:
118
102
            continue