diff options
Diffstat (limited to 'service/pixelated/adapter/model/mail.py')
-rw-r--r-- | service/pixelated/adapter/model/mail.py | 60 |
1 files changed, 44 insertions, 16 deletions
diff --git a/service/pixelated/adapter/model/mail.py b/service/pixelated/adapter/model/mail.py index 96f2c81c..f23c2708 100644 --- a/service/pixelated/adapter/model/mail.py +++ b/service/pixelated/adapter/model/mail.py @@ -16,6 +16,7 @@ import json from uuid import uuid4 from email.mime.text import MIMEText +from email.header import decode_header from leap.mail.imap.fields import fields import leap.mail.walk as walk @@ -26,6 +27,10 @@ from email.MIMEMultipart import MIMEMultipart from pycryptopp.hash import sha256 import re from pixelated.support.functional import compact +import logging + + +logger = logging.getLogger(__name__) class Mail(object): @@ -82,7 +87,7 @@ class Mail(object): def _parse_charset_header(self, charset_header, default_charset='utf-8'): try: - return re.compile('.*charset=(.*);').match(charset_header).group(1) + return re.compile('.*charset=([a-zA-Z0-9-]+)', re.MULTILINE | re.DOTALL).match(charset_header).group(1) except: return default_charset @@ -232,14 +237,22 @@ class PixelatedMail(Mail): encoding = part['headers'].get('Content-Transfer-Encoding', '') content_type = self._parse_charset_header(part['headers'].get('Content-Type')) - decoding_map = { - 'quoted-printable': lambda content, content_type: unicode(content.decode('quopri'), content_type), - 'base64': lambda content, content_type: content.decode('base64').decode('utf-8') - } - if encoding: - return decoding_map[encoding](part['content'], content_type) - else: - return part['content'] + try: + decoding_map = { + 'quoted-printable': lambda content, content_type: unicode(content.decode('quopri'), content_type), + 'base64': lambda content, content_type: content.decode('base64').decode('utf-8'), + '7bit': lambda content, content_type: content.encode(content_type), + '8bit': lambda content, content_type: content.encode(content_type) + } + if encoding: + return decoding_map[encoding](part['content'], content_type) + else: + return part['content'] + except Exception: + logger.error('Failed to decode mail part with:') + logger.error('Content-Transfer-Encoding: %s' % encoding) + logger.error('Content-Type: %s' % part['headers'].get('Content-Type')) + raise @property def alternatives(self): @@ -269,14 +282,14 @@ class PixelatedMail(Mail): hdoc_headers = self.hdoc.content['headers'] for header in ['To', 'Cc', 'Bcc']: - header_value = hdoc_headers.get(header) + header_value = self._decode_header(hdoc_headers.get(header)) if not header_value: continue _headers[header] = header_value if type(header_value) is list else header_value.split(',') - _headers[header] = map(lambda x: x.strip(), compact(_headers[header])) + _headers[header] = [head.strip() for head in compact(_headers[header])] for header in ['From', 'Subject']: - _headers[header] = hdoc_headers.get(header) + _headers[header] = self._decode_header(hdoc_headers.get(header)) _headers['Date'] = self._get_date() @@ -290,18 +303,34 @@ class PixelatedMail(Mail): return _headers + def _decode_header(self, header): + if not header: + return None + if isinstance(header, list): + return [decode_header(entry)[0][0] for entry in header] + else: + return decode_header(header)[0][0] + def _get_date(self): date = self.hdoc.content.get('date', None) if not date: - date = self.hdoc.content['received'].split(";")[-1].strip() + received = self.hdoc.content.get('received', None) + if received: + date = received.split(";")[-1].strip() + else: + # we can't get a date for this mail, so lets just use now + logger.warning('Encountered a mail with missing date and received header fields. Subject %s' % self.hdoc.content.get('subject', None)) + date = pixelated.support.date.iso_now() return dateparser.parse(date).isoformat() @property def security_casing(self): casing = {"imprints": [], "locks": []} casing["imprints"] = self.signature_information - if self.encrypted: + if self.encrypted == "true": casing["locks"] = [{"state": "valid"}] + elif self.encrypted == "fail": + casing["locks"] = [{"state": "failure"}] return casing @property @@ -377,8 +406,7 @@ class PixelatedMail(Mail): @property def encrypted(self): - return self.hdoc.content["headers"].get("OpenPGP", None) is not None or \ - self.hdoc.content["headers"].get("X-Pixelated-encryption-status", "false") == "true" + return self.hdoc.content["headers"].get("X-Pixelated-encryption-status", "false") @property def bounced(self): |