1
0
Fork 1
mirror of https://github.com/coddingtonbear/django-mailbox.git synced 2026-07-10 06:48:19 +02:00

[#130] Fix handling of single-byte filenames in attachment headers; among other unicode handling fixes.

This commit is contained in:
Adam Coddington 2017-03-05 21:31:22 -08:00
parent 81d6648e8c
commit 2df2d8a4fc
4 changed files with 50 additions and 15 deletions

View file

@ -642,8 +642,12 @@ class Message(models.Model):
if they are encoded as such. if they are encoded as such.
""" """
settings = utils.get_settings()
if self.encoded: if self.encoded:
return base64.b64decode(self.body.encode('ascii')) return base64.b64decode(
self.body.encode(settings['default_charset'], 'replace')
)
return self.body.encode('utf-8') return self.body.encode('utf-8')
def set_body(self, body): def set_body(self, body):
@ -654,10 +658,16 @@ class Message(models.Model):
no fields existed for storing arbitrary bytes. no fields existed for storing arbitrary bytes.
""" """
if six.PY3: settings = utils.get_settings()
if six.PY3 and isinstance(body, six.text_type):
body = body.encode('utf-8') body = body.encode('utf-8')
self.encoded = True self.encoded = True
self.body = base64.b64encode(body).decode('ascii') self.body = base64.b64encode(body).decode(
settings['default_charset'],
'replace',
)
def get_email_object(self): def get_email_object(self):
"""Returns an `email.message.Message` instance representing the """Returns an `email.message.Message` instance representing the
@ -726,18 +736,24 @@ class MessageAttachment(models.Model):
return super(MessageAttachment, self).delete(*args, **kwargs) return super(MessageAttachment, self).delete(*args, **kwargs)
def _get_rehydrated_headers(self): def _get_rehydrated_headers(self):
settings = utils.get_settings()
headers = self.headers headers = self.headers
if headers is None: if headers is None:
return EmailMessage() return EmailMessage()
if sys.version_info < (3, 0): if not six.PY3:
try: headers = headers.encode(settings['default_charset'], 'replace')
headers = headers.encode('utf-8')
except UnicodeDecodeError:
headers = unicode(headers, 'utf-8').encode('utf-8')
return email.message_from_string(headers) return email.message_from_string(headers)
def _set_dehydrated_headers(self, email_object): def _set_dehydrated_headers(self, email_object):
self.headers = email_object.as_string() settings = utils.get_settings()
headers = email_object.as_string()
if isinstance(headers, six.binary_type):
headers = headers.decode(settings['default_charset'], 'replace')
self.headers = headers
def __delitem__(self, name): def __delitem__(self, name):
rehydrated = self._get_rehydrated_headers() rehydrated = self._get_rehydrated_headers()
@ -745,7 +761,16 @@ class MessageAttachment(models.Model):
self._set_dehydrated_headers(rehydrated) self._set_dehydrated_headers(rehydrated)
def __setitem__(self, name, value): def __setitem__(self, name, value):
settings = utils.get_settings()
rehydrated = self._get_rehydrated_headers() rehydrated = self._get_rehydrated_headers()
if isinstance(value, six.binary_type):
# Ensure that no values in the bytestring cannot be encoded
# in the default charset
value = value.decode(
settings['default_charset'],
'replace'
).encode(settings['default_charset'], 'replace')
rehydrated[name] = value rehydrated[name] = value
self._set_dehydrated_headers(rehydrated) self._set_dehydrated_headers(rehydrated)

View file

@ -4,11 +4,12 @@ import sys
import mock import mock
import six import six
from django.core.mail import EmailMessage
from django_mailbox.models import Mailbox, Message from django_mailbox.models import Mailbox, Message
from django_mailbox.utils import convert_header_to_unicode from django_mailbox.utils import convert_header_to_unicode
from django_mailbox.tests.base import EmailMessageTestCase from django_mailbox.tests.base import EmailMessageTestCase
from django.test.utils import override_settings
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.core.mail import EmailMessage
__all__ = ['TestProcessEmail'] __all__ = ['TestProcessEmail']
@ -88,7 +89,7 @@ class TestProcessEmail(EmailMessageTestCase):
) )
def test_message_with_not_decoded_attachment_header(self): def test_message_with_not_decoded_attachment_header(self):
if sys.version_info > (3, 0): if not six.PY3:
self.skipTest( self.skipTest(
"This test is only relevant on Python 2.x." "This test is only relevant on Python 2.x."
) )
@ -145,14 +146,17 @@ class TestProcessEmail(EmailMessageTestCase):
u'odpowied\u017a Burmistrza.jpg' u'odpowied\u017a Burmistrza.jpg'
) )
@override_settings(
DJANGO_MAILBOX_DEFAULT_CHARSET='iso8859-2'
)
def test_message_with_utf_headers_in_attachments(self): def test_message_with_utf_headers_in_attachments(self):
email_object = self._get_email_object( email_object = self._get_email_object(
'message_with_utf8_headers_in_attachment.eml', 'message_with_iso8859-2_attachment_filename.eml',
) )
mailbox = Mailbox.objects.create() mailbox = Mailbox.objects.create()
msg = mailbox.process_incoming_message(email_object) msg = mailbox.process_incoming_message(email_object)
expected_count = 2 expected_count = 1
actual_count = msg.attachments.count() actual_count = msg.attachments.count()
self.assertEqual( self.assertEqual(
@ -160,7 +164,13 @@ class TestProcessEmail(EmailMessageTestCase):
actual_count, actual_count,
) )
# TODO: Verify filenames expected_filename = (
u'Odp. na wniosek o udost\u0119pnienie '
u'inf. publicznej.jpg'
)
actual_filename = msg.attachments.all()[0].get_filename()
self.assertEqual(expected_filename, actual_filename)
def test_message_get_text_body(self): def test_message_get_text_body(self):
message = self._get_email_object('multipart_text.eml') message = self._get_email_object('multipart_text.eml')

View file

@ -56,7 +56,7 @@ def get_settings():
), ),
'default_charset': getattr( 'default_charset': getattr(
settings, settings,
'DJANGO_MAILBOX_default_charset', 'DJANGO_MAILBOX_DEFAULT_CHARSET',
'iso8859-1', 'iso8859-1',
) )
} }