mercurial/mail.py
changeset 30089 040f23ed6963
parent 30072 87b8e40eb812
child 30325 f6369544bf85
equal deleted inserted replaced
30088:d1f5f158768e 30089:040f23ed6963
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 from __future__ import absolute_import, print_function
     8 from __future__ import absolute_import, print_function
     9 
     9 
    10 import email
    10 import email
       
    11 import email.charset
    11 import email.header
    12 import email.header
    12 import os
    13 import os
    13 import quopri
    14 import quopri
    14 import smtplib
    15 import smtplib
    15 import socket
    16 import socket
   202     else:
   203     else:
   203         if not util.findexe(method):
   204         if not util.findexe(method):
   204             raise error.Abort(_('%r specified as email transport, '
   205             raise error.Abort(_('%r specified as email transport, '
   205                                'but not in PATH') % method)
   206                                'but not in PATH') % method)
   206 
   207 
       
   208 def codec2iana(cs):
       
   209     ''''''
       
   210     cs = email.charset.Charset(cs).input_charset.lower()
       
   211 
       
   212     # "latin1" normalizes to "iso8859-1", standard calls for "iso-8859-1"
       
   213     if cs.startswith("iso") and not cs.startswith("iso-"):
       
   214         return "iso-" + cs[3:]
       
   215     return cs
       
   216 
   207 def mimetextpatch(s, subtype='plain', display=False):
   217 def mimetextpatch(s, subtype='plain', display=False):
   208     '''Return MIME message suitable for a patch.
   218     '''Return MIME message suitable for a patch.
   209     Charset will be detected as utf-8 or (possibly fake) us-ascii.
   219     Charset will be detected by first trying to decode as us-ascii, then utf-8,
       
   220     and finally the global encodings. If all those fail, fall back to
       
   221     ISO-8859-1, an encoding with that allows all byte sequences.
   210     Transfer encodings will be used if necessary.'''
   222     Transfer encodings will be used if necessary.'''
   211 
   223 
   212     cs = 'us-ascii'
   224     cs = ['us-ascii', 'utf-8', encoding.encoding, encoding.fallbackencoding]
   213     if not display:
   225     if display:
   214         try:
   226         return mimetextqp(s, subtype, 'us-ascii')
   215             s.decode('us-ascii')
   227     for charset in cs:
       
   228         try:
       
   229             s.decode(charset)
       
   230             return mimetextqp(s, subtype, codec2iana(charset))
   216         except UnicodeDecodeError:
   231         except UnicodeDecodeError:
   217             try:
   232             pass
   218                 s.decode('utf-8')
   233 
   219                 cs = 'utf-8'
   234     return mimetextqp(s, subtype, "iso-8859-1")
   220             except UnicodeDecodeError:
       
   221                 # We'll go with us-ascii as a fallback.
       
   222                 pass
       
   223 
       
   224     return mimetextqp(s, subtype, cs)
       
   225 
   235 
   226 def mimetextqp(body, subtype, charset):
   236 def mimetextqp(body, subtype, charset):
   227     '''Return MIME message.
   237     '''Return MIME message.
   228     Quoted-printable transfer encoding will be used if necessary.
   238     Quoted-printable transfer encoding will be used if necessary.
   229     '''
   239     '''