diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 0538ad7b7f8..5d303ecff89 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1154,9 +1154,13 @@ class mail_thread(osv.AbstractModel): body = tools.append_content_to_html(u'', body, preserve=True) else: alternative = False + mixed = False + html = u'' for part in message.walk(): if part.get_content_type() == 'multipart/alternative': alternative = True + if part.get_content_type() == 'multipart/mixed': + mixed = True if part.get_content_maintype() == 'multipart': continue # skip container # part.get_filename returns decoded value if able to decode, coded otherwise. @@ -1183,8 +1187,11 @@ class mail_thread(osv.AbstractModel): encoding, errors='replace'), preserve=True) # 3) text/html -> raw elif part.get_content_type() == 'text/html': + # mutlipart/alternative have one text and a html part, keep only the second + # mixed allows several html parts, append html content + append_content = not alternative or (html and mixed) html = tools.ustr(part.get_payload(decode=True), encoding, errors='replace') - if alternative: + if not append_content: body = html else: body = tools.append_content_to_html(body, html, plaintext=False) diff --git a/addons/mail/tests/test_mail_gateway.py b/addons/mail/tests/test_mail_gateway.py index 3fbf3d40405..023a009a9ee 100644 --- a/addons/mail/tests/test_mail_gateway.py +++ b/addons/mail/tests/test_mail_gateway.py @@ -143,6 +143,53 @@ X-Attachment-Id: f_hkpb27k00 dGVzdAo= --089e01536c4ed4d17204e49b8e96--""" +MAIL_MULTIPART_MIXED_TWO = """X-Original-To: raoul@grosbedon.fr +Delivered-To: raoul@grosbedon.fr +Received: by mail1.grosbedon.com (Postfix, from userid 10002) + id E8166BFACA; Fri, 23 Aug 2013 13:18:01 +0200 (CEST) +From: "Bruce Wayne" +Content-Type: multipart/alternative; + boundary="Apple-Mail=_9331E12B-8BD2-4EC7-B53E-01F3FBEC9227" +Message-Id: <6BB1FAB2-2104-438E-9447-07AE2C8C4A92@sexample.com> +Mime-Version: 1.0 (Mac OS X Mail 7.3 \(1878.6\)) + +--Apple-Mail=_9331E12B-8BD2-4EC7-B53E-01F3FBEC9227 +Content-Transfer-Encoding: 7bit +Content-Type: text/plain; + charset=us-ascii + +First and second part + +--Apple-Mail=_9331E12B-8BD2-4EC7-B53E-01F3FBEC9227 +Content-Type: multipart/mixed; + boundary="Apple-Mail=_CA6C687E-6AA0-411E-B0FE-F0ABB4CFED1F" + +--Apple-Mail=_CA6C687E-6AA0-411E-B0FE-F0ABB4CFED1F +Content-Transfer-Encoding: 7bit +Content-Type: text/html; + charset=us-ascii + +First part + +--Apple-Mail=_CA6C687E-6AA0-411E-B0FE-F0ABB4CFED1F +Content-Disposition: inline; + filename=thetruth.pdf +Content-Type: application/pdf; + name="thetruth.pdf" +Content-Transfer-Encoding: base64 + +SSBhbSB0aGUgQmF0TWFuCg== + +--Apple-Mail=_CA6C687E-6AA0-411E-B0FE-F0ABB4CFED1F +Content-Transfer-Encoding: 7bit +Content-Type: text/html; + charset=us-ascii + +Second part +--Apple-Mail=_CA6C687E-6AA0-411E-B0FE-F0ABB4CFED1F-- + +--Apple-Mail=_9331E12B-8BD2-4EC7-B53E-01F3FBEC9227-- +""" class TestMailgateway(TestMail): @@ -164,6 +211,14 @@ class TestMailgateway(TestMail): self.assertIn('
Should create a multipart/mixed: from gmail, bold, with attachment.

', res.get('body', ''), 'message_parse: html version should be in body after parsing multipart/mixed') + res = self.mail_thread.message_parse(cr, uid, MAIL_MULTIPART_MIXED_TWO) + self.assertNotIn('First and second part', res.get('body', ''), + 'message_parse: text version should not be in body after parsing multipart/mixed') + self.assertIn('First part', res.get('body', ''), + 'message_parse: first part of the html version should be in body after parsing multipart/mixed') + self.assertIn('Second part', res.get('body', ''), + 'message_parse: second part of the html version should be in body after parsing multipart/mixed') + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.osv.orm') def test_10_message_process(self): """ Testing incoming emails processing. """ diff --git a/openerp/addons/base/ir/ir_mail_server.py b/openerp/addons/base/ir/ir_mail_server.py index a21d8e67176..9e87d393cdb 100644 --- a/openerp/addons/base/ir/ir_mail_server.py +++ b/openerp/addons/base/ir/ir_mail_server.py @@ -24,7 +24,7 @@ from email.MIMEBase import MIMEBase from email.MIMEMultipart import MIMEMultipart from email.Charset import Charset from email.Header import Header -from email.Utils import formatdate, make_msgid, COMMASPACE, parseaddr +from email.utils import formatdate, make_msgid, COMMASPACE, getaddresses, formataddr from email import Encoders import logging import re @@ -140,29 +140,14 @@ def encode_rfc2822_address_header(header_text): ``"Name"`` portion by the RFC2047-encoded version, preserving the address part untouched. """ - header_text_utf8 = tools.ustr(header_text).encode('utf-8') - header_text_ascii = try_coerce_ascii(header_text_utf8) - if header_text_ascii: - return header_text_ascii - - name, email = parseaddr(header_text_utf8) - if not name: - return email - - # non-ASCII characters are present, attempt to - # replace all "Name" patterns with the RFC2047- - # encoded version - name_encoded = str(Header(name, 'utf-8')) - header_text_utf8 = "%s <%s>" % (name_encoded, email) - # try again after encoding - header_text_ascii = try_coerce_ascii(header_text_utf8) - if header_text_ascii: - return header_text_ascii - # fallback to extracting pure addresses only, which could - # still cause a failure downstream if the actual addresses - # contain non-ASCII characters - return COMMASPACE.join(extract_rfc2822_addresses(header_text_utf8)) + def encode_addr(addr): + name, email = addr + if not try_coerce_ascii(name): + name = str(Header(name, 'utf-8')) + return formataddr((name, email)) + addresses = getaddresses([tools.ustr(header_text).encode('utf-8')]) + return COMMASPACE.join(map(encode_addr, addresses)) class ir_mail_server(osv.osv): """Represents an SMTP server, able to send outgoing emails, with SSL and TLS capabilities.""" diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index 0d6f919c557..3650fdd0e5f 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -354,7 +354,7 @@ class res_users(osv.osv): if not context: context={} ids = [] - if name: + if name and operator in ['=', 'ilike']: ids = self.search(cr, user, [('login','=',name)]+ args, limit=limit, context=context) if not ids: ids = self.search(cr, user, [('name',operator,name)]+ args, limit=limit, context=context) diff --git a/openerp/tools/mail.py b/openerp/tools/mail.py index d7882dd6b51..d793de3089b 100644 --- a/openerp/tools/mail.py +++ b/openerp/tools/mail.py @@ -569,7 +569,7 @@ def append_content_to_html(html, content, plaintext=True, preserve=False, contai elif plaintext: content = '\n%s\n' % plaintext2html(content, container_tag) else: - content = re.sub(r'(?i)(||)', '', content) + content = re.sub(r'(?i)(]*>)', '', content) content = u'\n%s\n' % ustr(content) # Force all tags to lowercase html = re.sub(r'(])',