Show More
@@ -253,17 +253,13 b' def validateconfig(ui):' | |||||
253 |
|
253 | |||
254 |
|
254 | |||
255 | def codec2iana(cs): |
|
255 | def codec2iana(cs): | |
256 |
# type: ( |
|
256 | # type: (str) -> str | |
257 | '''''' |
|
257 | '''''' | |
258 | cs = pycompat.sysbytes( |
|
258 | cs = email.charset.Charset(cs).input_charset.lower() | |
259 | email.charset.Charset( |
|
|||
260 | cs # pytype: disable=wrong-arg-types |
|
|||
261 | ).input_charset.lower() |
|
|||
262 | ) |
|
|||
263 |
|
259 | |||
264 | # "latin1" normalizes to "iso8859-1", standard calls for "iso-8859-1" |
|
260 | # "latin1" normalizes to "iso8859-1", standard calls for "iso-8859-1" | |
265 |
if cs.startswith( |
|
261 | if cs.startswith("iso") and not cs.startswith("iso-"): | |
266 |
return |
|
262 | return "iso-" + cs[3:] | |
267 | return cs |
|
263 | return cs | |
268 |
|
264 | |||
269 |
|
265 | |||
@@ -275,27 +271,30 b" def mimetextpatch(s, subtype=b'plain', d" | |||||
275 | ISO-8859-1, an encoding with that allows all byte sequences. |
|
271 | ISO-8859-1, an encoding with that allows all byte sequences. | |
276 | Transfer encodings will be used if necessary.''' |
|
272 | Transfer encodings will be used if necessary.''' | |
277 |
|
273 | |||
278 | cs = [b'us-ascii', b'utf-8', encoding.encoding, encoding.fallbackencoding] |
|
274 | cs = [ | |
|
275 | 'us-ascii', | |||
|
276 | 'utf-8', | |||
|
277 | pycompat.sysstr(encoding.encoding), | |||
|
278 | pycompat.sysstr(encoding.fallbackencoding), | |||
|
279 | ] | |||
279 | if display: |
|
280 | if display: | |
280 |
cs = [ |
|
281 | cs = ['us-ascii'] | |
281 | for charset in cs: |
|
282 | for charset in cs: | |
282 | try: |
|
283 | try: | |
283 |
s.decode( |
|
284 | s.decode(charset) | |
284 | return mimetextqp(s, subtype, codec2iana(charset)) |
|
285 | return mimetextqp(s, subtype, codec2iana(charset)) | |
285 | except UnicodeDecodeError: |
|
286 | except UnicodeDecodeError: | |
286 | pass |
|
287 | pass | |
287 |
|
288 | |||
288 |
return mimetextqp(s, subtype, |
|
289 | return mimetextqp(s, subtype, "iso-8859-1") | |
289 |
|
290 | |||
290 |
|
291 | |||
291 | def mimetextqp(body, subtype, charset): |
|
292 | def mimetextqp(body, subtype, charset): | |
292 |
# type: (bytes, bytes, |
|
293 | # type: (bytes, bytes, str) -> email.message.Message | |
293 | '''Return MIME message. |
|
294 | '''Return MIME message. | |
294 | Quoted-printable transfer encoding will be used if necessary. |
|
295 | Quoted-printable transfer encoding will be used if necessary. | |
295 | ''' |
|
296 | ''' | |
296 | # Experimentally charset is okay as a bytes even if the type |
|
297 | cs = email.charset.Charset(charset) | |
297 | # stubs disagree. |
|
|||
298 | cs = email.charset.Charset(charset) # pytype: disable=wrong-arg-types |
|
|||
299 | msg = email.message.Message() |
|
298 | msg = email.message.Message() | |
300 | msg.set_type(pycompat.sysstr(b'text/' + subtype)) |
|
299 | msg.set_type(pycompat.sysstr(b'text/' + subtype)) | |
301 |
|
300 | |||
@@ -317,24 +316,25 b' def mimetextqp(body, subtype, charset):' | |||||
317 |
|
316 | |||
318 |
|
317 | |||
319 | def _charsets(ui): |
|
318 | def _charsets(ui): | |
320 |
# type: (Any) -> List[ |
|
319 | # type: (Any) -> List[str] | |
321 | '''Obtains charsets to send mail parts not containing patches.''' |
|
320 | '''Obtains charsets to send mail parts not containing patches.''' | |
322 | charsets = [ |
|
321 | charsets = [ | |
323 | cs.lower() for cs in ui.configlist(b'email', b'charsets') |
|
322 | pycompat.sysstr(cs.lower()) | |
324 | ] # type: List[bytes] |
|
323 | for cs in ui.configlist(b'email', b'charsets') | |
|
324 | ] | |||
325 | fallbacks = [ |
|
325 | fallbacks = [ | |
326 | encoding.fallbackencoding.lower(), |
|
326 | pycompat.sysstr(encoding.fallbackencoding.lower()), | |
327 | encoding.encoding.lower(), |
|
327 | pycompat.sysstr(encoding.encoding.lower()), | |
328 |
|
|
328 | 'utf-8', | |
329 | ] # type: List[bytes] |
|
329 | ] | |
330 | for cs in fallbacks: # find unique charsets while keeping order |
|
330 | for cs in fallbacks: # find unique charsets while keeping order | |
331 | if cs not in charsets: |
|
331 | if cs not in charsets: | |
332 | charsets.append(cs) |
|
332 | charsets.append(cs) | |
333 |
return [cs for cs in charsets if not cs.endswith( |
|
333 | return [cs for cs in charsets if not cs.endswith('ascii')] | |
334 |
|
334 | |||
335 |
|
335 | |||
336 | def _encode(ui, s, charsets): |
|
336 | def _encode(ui, s, charsets): | |
337 |
# type: (Any, bytes, List[ |
|
337 | # type: (Any, bytes, List[str]) -> Tuple[bytes, str] | |
338 | '''Returns (converted) string, charset tuple. |
|
338 | '''Returns (converted) string, charset tuple. | |
339 | Finds out best charset by cycling through sendcharsets in descending |
|
339 | Finds out best charset by cycling through sendcharsets in descending | |
340 | order. Tries both encoding and fallbackencoding for input. Only as |
|
340 | order. Tries both encoding and fallbackencoding for input. Only as | |
@@ -347,14 +347,17 b' def _encode(ui, s, charsets):' | |||||
347 | # wants, and fall back to garbage-in-ascii. |
|
347 | # wants, and fall back to garbage-in-ascii. | |
348 | for ocs in sendcharsets: |
|
348 | for ocs in sendcharsets: | |
349 | try: |
|
349 | try: | |
350 |
return s.encode( |
|
350 | return s.encode(ocs), ocs | |
351 | except UnicodeEncodeError: |
|
351 | except UnicodeEncodeError: | |
352 | pass |
|
352 | pass | |
353 | except LookupError: |
|
353 | except LookupError: | |
354 | ui.warn(_(b'ignoring invalid sendcharset: %s\n') % ocs) |
|
354 | ui.warn( | |
|
355 | _(b'ignoring invalid sendcharset: %s\n') | |||
|
356 | % pycompat.sysbytes(ocs) | |||
|
357 | ) | |||
355 | else: |
|
358 | else: | |
356 | # Everything failed, ascii-armor what we've got and send it. |
|
359 | # Everything failed, ascii-armor what we've got and send it. | |
357 |
return s.encode('ascii', 'backslashreplace'), |
|
360 | return s.encode('ascii', 'backslashreplace'), 'us-ascii' | |
358 | # We have a bytes of unknown encoding. We'll try and guess a valid |
|
361 | # We have a bytes of unknown encoding. We'll try and guess a valid | |
359 | # encoding, falling back to pretending we had ascii even though we |
|
362 | # encoding, falling back to pretending we had ascii even though we | |
360 | # know that's wrong. |
|
363 | # know that's wrong. | |
@@ -369,29 +372,30 b' def _encode(ui, s, charsets):' | |||||
369 | continue |
|
372 | continue | |
370 | for ocs in sendcharsets: |
|
373 | for ocs in sendcharsets: | |
371 | try: |
|
374 | try: | |
372 |
return u.encode( |
|
375 | return u.encode(ocs), ocs | |
373 | except UnicodeEncodeError: |
|
376 | except UnicodeEncodeError: | |
374 | pass |
|
377 | pass | |
375 | except LookupError: |
|
378 | except LookupError: | |
376 | ui.warn(_(b'ignoring invalid sendcharset: %s\n') % ocs) |
|
379 | ui.warn( | |
|
380 | _(b'ignoring invalid sendcharset: %s\n') | |||
|
381 | % pycompat.sysbytes(ocs) | |||
|
382 | ) | |||
377 | # if ascii, or all conversion attempts fail, send (broken) ascii |
|
383 | # if ascii, or all conversion attempts fail, send (broken) ascii | |
378 |
return s, |
|
384 | return s, 'us-ascii' | |
379 |
|
385 | |||
380 |
|
386 | |||
381 | def headencode(ui, s, charsets=None, display=False): |
|
387 | def headencode(ui, s, charsets=None, display=False): | |
382 |
# type: (Any, Union[bytes, str], List[ |
|
388 | # type: (Any, Union[bytes, str], List[str], bool) -> str | |
383 | '''Returns RFC-2047 compliant header from given string.''' |
|
389 | '''Returns RFC-2047 compliant header from given string.''' | |
384 | if not display: |
|
390 | if not display: | |
385 | # split into words? |
|
391 | # split into words? | |
386 | s, cs = _encode(ui, s, charsets) |
|
392 | s, cs = _encode(ui, s, charsets) | |
387 | return email.header.Header( |
|
393 | return email.header.Header(s, cs).encode() | |
388 | s, cs # pytype: disable=wrong-arg-types |
|
|||
389 | ).encode() |
|
|||
390 | return encoding.strfromlocal(s) |
|
394 | return encoding.strfromlocal(s) | |
391 |
|
395 | |||
392 |
|
396 | |||
393 | def _addressencode(ui, name, addr, charsets=None): |
|
397 | def _addressencode(ui, name, addr, charsets=None): | |
394 |
# type: (Any, str, bytes, List[ |
|
398 | # type: (Any, str, bytes, List[str]) -> str | |
395 | assert isinstance(addr, bytes) |
|
399 | assert isinstance(addr, bytes) | |
396 | name = headencode(ui, name, charsets) |
|
400 | name = headencode(ui, name, charsets) | |
397 | try: |
|
401 | try: | |
@@ -411,7 +415,7 b' def _addressencode(ui, name, addr, chars' | |||||
411 |
|
415 | |||
412 |
|
416 | |||
413 | def addressencode(ui, address, charsets=None, display=False): |
|
417 | def addressencode(ui, address, charsets=None, display=False): | |
414 |
# type: (Any, bytes, List[ |
|
418 | # type: (Any, bytes, List[str], bool) -> str | |
415 | '''Turns address into RFC-2047 compliant header.''' |
|
419 | '''Turns address into RFC-2047 compliant header.''' | |
416 | if display or not address: |
|
420 | if display or not address: | |
417 | return encoding.strfromlocal(address or b'') |
|
421 | return encoding.strfromlocal(address or b'') | |
@@ -420,7 +424,7 b' def addressencode(ui, address, charsets=' | |||||
420 |
|
424 | |||
421 |
|
425 | |||
422 | def addrlistencode(ui, addrs, charsets=None, display=False): |
|
426 | def addrlistencode(ui, addrs, charsets=None, display=False): | |
423 |
# type: (Any, List[bytes], List[ |
|
427 | # type: (Any, List[bytes], List[str], bool) -> List[str] | |
424 | '''Turns a list of addresses into a list of RFC-2047 compliant headers. |
|
428 | '''Turns a list of addresses into a list of RFC-2047 compliant headers. | |
425 | A single element of input list may contain multiple addresses, but output |
|
429 | A single element of input list may contain multiple addresses, but output | |
426 | always has one address per item''' |
|
430 | always has one address per item''' | |
@@ -440,10 +444,10 b' def addrlistencode(ui, addrs, charsets=N' | |||||
440 |
|
444 | |||
441 |
|
445 | |||
442 | def mimeencode(ui, s, charsets=None, display=False): |
|
446 | def mimeencode(ui, s, charsets=None, display=False): | |
443 |
# type: (Any, bytes, List[ |
|
447 | # type: (Any, bytes, List[str], bool) -> email.message.Message | |
444 | '''creates mime text object, encodes it if needed, and sets |
|
448 | '''creates mime text object, encodes it if needed, and sets | |
445 | charset and transfer-encoding accordingly.''' |
|
449 | charset and transfer-encoding accordingly.''' | |
446 |
cs = |
|
450 | cs = 'us-ascii' | |
447 | if not display: |
|
451 | if not display: | |
448 | s, cs = _encode(ui, s, charsets) |
|
452 | s, cs = _encode(ui, s, charsets) | |
449 | return mimetextqp(s, b'plain', cs) |
|
453 | return mimetextqp(s, b'plain', cs) |
General Comments 0
You need to be logged in to leave comments.
Login now