import operator
from email import message_from_file
try:
- from email.header import Header
+ from email.header import Header, decode_header
from email.utils import parsedate_tz, mktime_tz
except ImportError:
# Python 2.4 compatibility
- from email.Header import Header
+ from email.Header import Header, decode_header
from email.Utils import parsedate_tz, mktime_tz
from patchwork.parser import parse_patch
list_id_headers = ['List-ID', 'X-Mailing-List']
+whitespace_re = re.compile('\s+')
+def normalise_space(str):
+ return whitespace_re.sub(' ', str).strip()
+
+def clean_header(header):
+ """ Decode (possibly non-ascii) headers """
+
+ def decode(fragment):
+ (frag_str, frag_encoding) = fragment
+ if frag_encoding:
+ return frag_str.decode(frag_encoding)
+ return frag_str.decode()
+
+ fragments = map(decode, decode_header(header))
+
+ return normalise_space(u' '.join(fragments))
+
def find_project(mail):
project = None
listid_re = re.compile('.*<([^>]+)>.*', re.S)
def find_author(mail):
- from_header = mail.get('From').strip()
+ from_header = clean_header(mail.get('From'))
(name, email) = (None, None)
# tuple of (regex, fn)
new_person = False
try:
- person = Person.objects.get(email = email)
+ person = Person.objects.get(email__iexact = email)
except Person.DoesNotExist:
person = Person(name = name, email = email)
new_person = True
def mail_date(mail):
t = parsedate_tz(mail.get('Date', ''))
if not t:
- print "using now()"
return datetime.datetime.utcnow()
return datetime.datetime.utcfromtimestamp(mktime_tz(t))
if part.get_content_maintype() != 'text':
continue
- #print "\t%s, %s" % \
- # (part.get_content_subtype(), part.get_content_charset())
-
- charset = part.get_content_charset()
- if not charset:
- charset = mail.get_charset()
- if not charset:
- charset = 'utf-8'
+ payload = part.get_payload(decode=True)
+ subtype = part.get_content_subtype()
- payload = unicode(part.get_payload(decode=True), charset, "replace")
-
- if part.get_content_subtype() == 'x-patch':
+ if subtype in ['x-patch', 'x-diff']:
patchbuf = payload
- if part.get_content_subtype() == 'plain':
+ elif subtype == 'plain':
if not patchbuf:
(patchbuf, c) = parse_patch(payload)
else:
re_re = re.compile('^(re|fwd?)[:\s]\s*', re.I)
prefix_re = re.compile('^\[([^\]]*)\]\s*(.*)$')
-whitespace_re = re.compile('\s+')
def clean_subject(subject, drop_prefixes = None):
""" Clean a Subject: header from an incoming patch.
# remove Re:, Fwd:, etc
subject = re_re.sub(' ', subject)
- # normalise whitespace
- subject = whitespace_re.sub(' ', subject)
+ subject = normalise_space(subject)
prefixes = []
subject = match.group(2)
match = prefix_re.match(subject)
- subject = whitespace_re.sub(' ', subject)
+ subject = normalise_space(subject)
subject = subject.strip()
if prefixes:
return subject
-sig_re = re.compile('^(-{2,3} ?|_+)\n.*', re.S | re.M)
+sig_re = re.compile('^(-- |_+)\n.*', re.S | re.M)
def clean_content(str):
+ """ Try to remove signature (-- ) and list footer (_____) cruft """
str = sig_re.sub('', str)
return str.strip()