Show More
@@ -36,6 +36,12 b' from .utils import (' | |||||
36 | stringutil, |
|
36 | stringutil, | |
37 | ) |
|
37 | ) | |
38 |
|
38 | |||
|
39 | if not globals(): # hide this from non-pytype users | |||
|
40 | from typing import Any, List, Tuple, Union | |||
|
41 | ||||
|
42 | # keep pyflakes happy | |||
|
43 | assert all((Any, List, Tuple, Union)) | |||
|
44 | ||||
39 |
|
45 | |||
40 | class STARTTLS(smtplib.SMTP): |
|
46 | class STARTTLS(smtplib.SMTP): | |
41 | '''Derived class to verify the peer certificate for STARTTLS. |
|
47 | '''Derived class to verify the peer certificate for STARTTLS. | |
@@ -99,6 +105,7 b' class SMTPS(smtplib.SMTP):' | |||||
99 |
|
105 | |||
100 |
|
106 | |||
101 | def _pyhastls(): |
|
107 | def _pyhastls(): | |
|
108 | # type: () -> bool | |||
102 | """Returns true iff Python has TLS support, false otherwise.""" |
|
109 | """Returns true iff Python has TLS support, false otherwise.""" | |
103 | try: |
|
110 | try: | |
104 | import ssl |
|
111 | import ssl | |
@@ -246,8 +253,13 b' def validateconfig(ui):' | |||||
246 |
|
253 | |||
247 |
|
254 | |||
248 | def codec2iana(cs): |
|
255 | def codec2iana(cs): | |
|
256 | # type: (bytes) -> bytes | |||
249 | '''''' |
|
257 | '''''' | |
250 | cs = pycompat.sysbytes(email.charset.Charset(cs).input_charset.lower()) |
|
258 | cs = pycompat.sysbytes( | |
|
259 | email.charset.Charset( | |||
|
260 | cs # pytype: disable=wrong-arg-types | |||
|
261 | ).input_charset.lower() | |||
|
262 | ) | |||
251 |
|
263 | |||
252 | # "latin1" normalizes to "iso8859-1", standard calls for "iso-8859-1" |
|
264 | # "latin1" normalizes to "iso8859-1", standard calls for "iso-8859-1" | |
253 | if cs.startswith(b"iso") and not cs.startswith(b"iso-"): |
|
265 | if cs.startswith(b"iso") and not cs.startswith(b"iso-"): | |
@@ -256,6 +268,7 b' def codec2iana(cs):' | |||||
256 |
|
268 | |||
257 |
|
269 | |||
258 | def mimetextpatch(s, subtype=b'plain', display=False): |
|
270 | def mimetextpatch(s, subtype=b'plain', display=False): | |
|
271 | # type: (bytes, bytes, bool) -> email.message.Message | |||
259 | '''Return MIME message suitable for a patch. |
|
272 | '''Return MIME message suitable for a patch. | |
260 | Charset will be detected by first trying to decode as us-ascii, then utf-8, |
|
273 | Charset will be detected by first trying to decode as us-ascii, then utf-8, | |
261 | and finally the global encodings. If all those fail, fall back to |
|
274 | and finally the global encodings. If all those fail, fall back to | |
@@ -276,6 +289,7 b" def mimetextpatch(s, subtype=b'plain', d" | |||||
276 |
|
289 | |||
277 |
|
290 | |||
278 | def mimetextqp(body, subtype, charset): |
|
291 | def mimetextqp(body, subtype, charset): | |
|
292 | # type: (bytes, bytes, bytes) -> email.message.Message | |||
279 | '''Return MIME message. |
|
293 | '''Return MIME message. | |
280 | Quoted-printable transfer encoding will be used if necessary. |
|
294 | Quoted-printable transfer encoding will be used if necessary. | |
281 | ''' |
|
295 | ''' | |
@@ -303,13 +317,16 b' def mimetextqp(body, subtype, charset):' | |||||
303 |
|
317 | |||
304 |
|
318 | |||
305 | def _charsets(ui): |
|
319 | def _charsets(ui): | |
|
320 | # type: (Any) -> List[bytes] | |||
306 | '''Obtains charsets to send mail parts not containing patches.''' |
|
321 | '''Obtains charsets to send mail parts not containing patches.''' | |
307 | charsets = [cs.lower() for cs in ui.configlist(b'email', b'charsets')] |
|
322 | charsets = [ | |
|
323 | cs.lower() for cs in ui.configlist(b'email', b'charsets') | |||
|
324 | ] # type: List[bytes] | |||
308 | fallbacks = [ |
|
325 | fallbacks = [ | |
309 | encoding.fallbackencoding.lower(), |
|
326 | encoding.fallbackencoding.lower(), | |
310 | encoding.encoding.lower(), |
|
327 | encoding.encoding.lower(), | |
311 | b'utf-8', |
|
328 | b'utf-8', | |
312 | ] |
|
329 | ] # type: List[bytes] | |
313 | for cs in fallbacks: # find unique charsets while keeping order |
|
330 | for cs in fallbacks: # find unique charsets while keeping order | |
314 | if cs not in charsets: |
|
331 | if cs not in charsets: | |
315 | charsets.append(cs) |
|
332 | charsets.append(cs) | |
@@ -317,6 +334,7 b' def _charsets(ui):' | |||||
317 |
|
334 | |||
318 |
|
335 | |||
319 | def _encode(ui, s, charsets): |
|
336 | def _encode(ui, s, charsets): | |
|
337 | # type: (Any, bytes, List[bytes]) -> Tuple[bytes, bytes] | |||
320 | '''Returns (converted) string, charset tuple. |
|
338 | '''Returns (converted) string, charset tuple. | |
321 | Finds out best charset by cycling through sendcharsets in descending |
|
339 | Finds out best charset by cycling through sendcharsets in descending | |
322 | order. Tries both encoding and fallbackencoding for input. Only as |
|
340 | order. Tries both encoding and fallbackencoding for input. Only as | |
@@ -361,15 +379,19 b' def _encode(ui, s, charsets):' | |||||
361 |
|
379 | |||
362 |
|
380 | |||
363 | def headencode(ui, s, charsets=None, display=False): |
|
381 | def headencode(ui, s, charsets=None, display=False): | |
|
382 | # type: (Any, Union[bytes, str], List[bytes], bool) -> str | |||
364 | '''Returns RFC-2047 compliant header from given string.''' |
|
383 | '''Returns RFC-2047 compliant header from given string.''' | |
365 | if not display: |
|
384 | if not display: | |
366 | # split into words? |
|
385 | # split into words? | |
367 | s, cs = _encode(ui, s, charsets) |
|
386 | s, cs = _encode(ui, s, charsets) | |
368 |
return email.header.Header( |
|
387 | return email.header.Header( | |
|
388 | s, cs # pytype: disable=wrong-arg-types | |||
|
389 | ).encode() | |||
369 | return encoding.strfromlocal(s) |
|
390 | return encoding.strfromlocal(s) | |
370 |
|
391 | |||
371 |
|
392 | |||
372 | def _addressencode(ui, name, addr, charsets=None): |
|
393 | def _addressencode(ui, name, addr, charsets=None): | |
|
394 | # type: (Any, str, bytes, List[bytes]) -> str | |||
373 | assert isinstance(addr, bytes) |
|
395 | assert isinstance(addr, bytes) | |
374 | name = headencode(ui, name, charsets) |
|
396 | name = headencode(ui, name, charsets) | |
375 | try: |
|
397 | try: | |
@@ -389,6 +411,7 b' def _addressencode(ui, name, addr, chars' | |||||
389 |
|
411 | |||
390 |
|
412 | |||
391 | def addressencode(ui, address, charsets=None, display=False): |
|
413 | def addressencode(ui, address, charsets=None, display=False): | |
|
414 | # type: (Any, bytes, List[bytes], bool) -> str | |||
392 | '''Turns address into RFC-2047 compliant header.''' |
|
415 | '''Turns address into RFC-2047 compliant header.''' | |
393 | if display or not address: |
|
416 | if display or not address: | |
394 | return encoding.strfromlocal(address or b'') |
|
417 | return encoding.strfromlocal(address or b'') | |
@@ -397,6 +420,7 b' def addressencode(ui, address, charsets=' | |||||
397 |
|
420 | |||
398 |
|
421 | |||
399 | def addrlistencode(ui, addrs, charsets=None, display=False): |
|
422 | def addrlistencode(ui, addrs, charsets=None, display=False): | |
|
423 | # type: (Any, List[bytes], List[bytes], bool) -> List[str] | |||
400 | '''Turns a list of addresses into a list of RFC-2047 compliant headers. |
|
424 | '''Turns a list of addresses into a list of RFC-2047 compliant headers. | |
401 | A single element of input list may contain multiple addresses, but output |
|
425 | A single element of input list may contain multiple addresses, but output | |
402 | always has one address per item''' |
|
426 | always has one address per item''' | |
@@ -416,6 +440,7 b' def addrlistencode(ui, addrs, charsets=N' | |||||
416 |
|
440 | |||
417 |
|
441 | |||
418 | def mimeencode(ui, s, charsets=None, display=False): |
|
442 | def mimeencode(ui, s, charsets=None, display=False): | |
|
443 | # type: (Any, bytes, List[bytes], bool) -> email.message.Message | |||
419 | '''creates mime text object, encodes it if needed, and sets |
|
444 | '''creates mime text object, encodes it if needed, and sets | |
420 | charset and transfer-encoding accordingly.''' |
|
445 | charset and transfer-encoding accordingly.''' | |
421 | cs = b'us-ascii' |
|
446 | cs = b'us-ascii' | |
@@ -429,6 +454,7 b' if pycompat.ispy3:' | |||||
429 | Generator = email.generator.BytesGenerator |
|
454 | Generator = email.generator.BytesGenerator | |
430 |
|
455 | |||
431 | def parse(fp): |
|
456 | def parse(fp): | |
|
457 | # type: (Any) -> email.message.Message | |||
432 | ep = email.parser.Parser() |
|
458 | ep = email.parser.Parser() | |
433 | # disable the "universal newlines" mode, which isn't binary safe. |
|
459 | # disable the "universal newlines" mode, which isn't binary safe. | |
434 | # I have no idea if ascii/surrogateescape is correct, but that's |
|
460 | # I have no idea if ascii/surrogateescape is correct, but that's | |
@@ -442,6 +468,7 b' if pycompat.ispy3:' | |||||
442 | fp.detach() |
|
468 | fp.detach() | |
443 |
|
469 | |||
444 | def parsebytes(data): |
|
470 | def parsebytes(data): | |
|
471 | # type: (bytes) -> email.message.Message | |||
445 | ep = email.parser.BytesParser() |
|
472 | ep = email.parser.BytesParser() | |
446 | return ep.parsebytes(data) |
|
473 | return ep.parsebytes(data) | |
447 |
|
474 | |||
@@ -451,15 +478,18 b' else:' | |||||
451 | Generator = email.generator.Generator |
|
478 | Generator = email.generator.Generator | |
452 |
|
479 | |||
453 | def parse(fp): |
|
480 | def parse(fp): | |
|
481 | # type: (Any) -> email.message.Message | |||
454 | ep = email.parser.Parser() |
|
482 | ep = email.parser.Parser() | |
455 | return ep.parse(fp) |
|
483 | return ep.parse(fp) | |
456 |
|
484 | |||
457 | def parsebytes(data): |
|
485 | def parsebytes(data): | |
|
486 | # type: (str) -> email.message.Message | |||
458 | ep = email.parser.Parser() |
|
487 | ep = email.parser.Parser() | |
459 | return ep.parsestr(data) |
|
488 | return ep.parsestr(data) | |
460 |
|
489 | |||
461 |
|
490 | |||
462 | def headdecode(s): |
|
491 | def headdecode(s): | |
|
492 | # type: (Union[email.header.Header, bytes]) -> bytes | |||
463 | '''Decodes RFC-2047 header''' |
|
493 | '''Decodes RFC-2047 header''' | |
464 | uparts = [] |
|
494 | uparts = [] | |
465 | for part, charset in email.header.decode_header(s): |
|
495 | for part, charset in email.header.decode_header(s): |
General Comments 0
You need to be logged in to leave comments.
Login now