##// END OF EJS Templates
mail: add methods to handle non-ascii chars...
Christian Ebert -
r7114:30e49d54 default
parent child Browse files
Show More
@@ -7,6 +7,7 b''
7
7
8 from i18n import _
8 from i18n import _
9 import os, smtplib, socket
9 import os, smtplib, socket
10 import email.Header, email.MIMEText, email.Utils
10 import util
11 import util
11
12
12 def _smtp(ui):
13 def _smtp(ui):
@@ -84,3 +85,75 b' def validateconfig(ui):'
84 if not util.find_exe(method):
85 if not util.find_exe(method):
85 raise util.Abort(_('%r specified as email transport, '
86 raise util.Abort(_('%r specified as email transport, '
86 'but not in PATH') % method)
87 'but not in PATH') % method)
88
89 def _charsets(ui):
90 '''Obtains charsets to send mail parts not containing patches.'''
91 charsets = [cs.lower() for cs in ui.configlist('email', 'charsets')]
92 fallbacks = [util._fallbackencoding.lower(),
93 util._encoding.lower(), 'utf-8']
94 for cs in fallbacks: # util.unique does not keep order
95 if cs not in charsets:
96 charsets.append(cs)
97 return [cs for cs in charsets if not cs.endswith('ascii')]
98
99 def _encode(ui, s, charsets):
100 '''Returns (converted) string, charset tuple.
101 Finds out best charset by cycling through sendcharsets in descending
102 order. Tries both _encoding and _fallbackencoding for input. Only as
103 last resort send as is in fake ascii.
104 Caveat: Do not use for mail parts containing patches!'''
105 try:
106 s.decode('ascii')
107 except UnicodeDecodeError:
108 sendcharsets = charsets or _charsets(ui)
109 for ics in (util._encoding, util._fallbackencoding):
110 try:
111 u = s.decode(ics)
112 except UnicodeDecodeError:
113 continue
114 for ocs in sendcharsets:
115 try:
116 return u.encode(ocs), ocs
117 except UnicodeEncodeError:
118 pass
119 except LookupError:
120 ui.warn(_('ignoring invalid sendcharset: %s\n') % cs)
121 # if ascii, or all conversion attempts fail, send (broken) ascii
122 return s, 'us-ascii'
123
124 def headencode(ui, s, charsets=None, display=False):
125 '''Returns RFC-2047 compliant header from given string.'''
126 if not display:
127 # split into words?
128 s, cs = _encode(ui, s, charsets)
129 return str(email.Header.Header(s, cs))
130 return s
131
132 def addressencode(ui, address, charsets=None, display=False):
133 '''Turns address into RFC-2047 compliant header.'''
134 if display or not address:
135 return address or ''
136 name, addr = email.Utils.parseaddr(address)
137 name = headencode(ui, name, charsets)
138 try:
139 acc, dom = addr.split('@')
140 acc = acc.encode('ascii')
141 dom = dom.encode('idna')
142 addr = '%s@%s' % (acc, dom)
143 except UnicodeDecodeError:
144 raise util.Abort(_('invalid email address: %s') % addr)
145 except ValueError:
146 try:
147 # too strict?
148 addr = addr.encode('ascii')
149 except UnicodeDecodeError:
150 raise util.Abort(_('invalid local address: %s') % addr)
151 return email.Utils.formataddr((name, addr))
152
153 def mimeencode(ui, s, charsets=None, display=False):
154 '''creates mime text object, encodes it if needed, and sets
155 charset and transfer-encoding accordingly.'''
156 cs = 'us-ascii'
157 if not display:
158 s, cs = _encode(ui, s, charsets)
159 return email.MIMEText.MIMEText(s, 'plain', cs)
General Comments 0
You need to be logged in to leave comments. Login now