Skip to content

Commit 6dc8e64

Browse files
author
Ralf Schlatterbeck
committed
Yet another fix to the mail gateway...
...messages got *all* files of an issue, not just the new ones. Thanks to Rafal Bisingier for reporting and proposing a fix. The regression test was updated. Fix version numbers in upgrade documentation, the file-unlink defect was in 1.4.17 not 1.4.16. Thanks to Rafal Bisingier.
1 parent 35a6cd2 commit 6dc8e64

File tree

3 files changed

+52
-13
lines changed

3 files changed

+52
-13
lines changed

CHANGES.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ Fixed:
1313
(Ralf)
1414
- Fix version numbers in upgrade documentation, the file-unlink defect
1515
was in 1.4.17 not 1.4.16. Thanks to Rafal Bisingier. (Ralf)
16+
- Fix encoded email header parsing if multiple encoded and non-encoded
17+
parts are present. RFC2047 specifies that spacing is removed only
18+
between encoded parts, we always removed the space. Note that this bug
19+
was present before mail gateway refactoring :-) Thanks for thorough
20+
testing of mail gateway code by Rafal Bisingier. (Ralf)
1621

1722
2011-05-29 1.4.18 (r4610)
1823

roundup/mailgw.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,22 @@ def getparts(self):
247247
parts.append(part)
248248
return parts
249249

250+
def _decode_header_to_utf8(self, hdr):
251+
l = []
252+
prev_encoded = False
253+
for part, encoding in decode_header(hdr):
254+
if encoding:
255+
part = part.decode(encoding)
256+
# RFC 2047 specifies that between encoded parts spaces are
257+
# swallowed while at the borders from encoded to non-encoded
258+
# or vice-versa we must preserve a space. Multiple adjacent
259+
# non-encoded parts should not occur.
260+
if l and prev_encoded != bool(encoding):
261+
l.append(' ')
262+
prev_encoded = bool(encoding)
263+
l.append(part)
264+
return ''.join([s.encode('utf-8') for s in l])
265+
250266
def getheader(self, name, default=None):
251267
hdr = mimetools.Message.getheader(self, name, default)
252268
# TODO are there any other False values possible?
@@ -257,24 +273,13 @@ def getheader(self, name, default=None):
257273
return ''
258274
if hdr:
259275
hdr = hdr.replace('\n','') # Inserted by rfc822.readheaders
260-
# historically this method has returned utf-8 encoded string
261-
l = []
262-
for part, encoding in decode_header(hdr):
263-
if encoding:
264-
part = part.decode(encoding)
265-
l.append(part)
266-
return ''.join([s.encode('utf-8') for s in l])
276+
return self._decode_header_to_utf8(hdr)
267277

268278
def getaddrlist(self, name):
269279
# overload to decode the name part of the address
270280
l = []
271281
for (name, addr) in mimetools.Message.getaddrlist(self, name):
272-
p = []
273-
for part, encoding in decode_header(name):
274-
if encoding:
275-
part = part.decode(encoding)
276-
p.append(part)
277-
name = ''.join([s.encode('utf-8') for s in p])
282+
name = self._decode_header_to_utf8(name)
278283
l.append((name, addr))
279284
return l
280285

test/test_mailgw.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,6 +1823,35 @@ def testNewUserAuthorEncodedName(self):
18231823
name = self.db.user.get(new, 'realname')
18241824
self.assertEquals(name, 'H€llo')
18251825

1826+
def testNewUserAuthorMixedEncodedName(self):
1827+
l = set(self.db.user.list())
1828+
# From: name has Euro symbol in it
1829+
message = '''Content-Type: text/plain;
1830+
charset="iso-8859-1"
1831+
From: Firstname =?utf-8?b?w6TDtsOf?= Last <[email protected]>
1832+
1833+
Message-Id: <dummy_test_message_id>
1834+
Subject: [issue] Test =?utf-8?b?w4TDlsOc?= umlauts
1835+
X1
1836+
X2
1837+
1838+
This is a test submission of a new issue.
1839+
'''
1840+
p = [
1841+
self.db.security.getPermission('Register', 'user'),
1842+
self.db.security.getPermission('Email Access', None),
1843+
self.db.security.getPermission('Create', 'issue'),
1844+
self.db.security.getPermission('Create', 'msg'),
1845+
]
1846+
self.db.security.role['anonymous'].permissions = p
1847+
self._handle_mail(message)
1848+
title = self.db.issue.get('1', 'title')
1849+
self.assertEquals(title, 'Test \xc3\x84\xc3\x96\xc3\x9c umlauts X1 X2')
1850+
m = set(self.db.user.list())
1851+
new = list(m - l)[0]
1852+
name = self.db.user.get(new, 'realname')
1853+
self.assertEquals(name, 'Firstname \xc3\xa4\xc3\xb6\xc3\x9f Last')
1854+
18261855
def testUnknownUser(self):
18271856
l = set(self.db.user.list())
18281857
message = '''Content-Type: text/plain;

0 commit comments

Comments
 (0)