encoders.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. # Copyright (C) 2001-2006 Python Software Foundation
  2. # Author: Barry Warsaw
  3. # Contact: email-sig@python.org
  4. """Encodings and related functions."""
  5. from __future__ import unicode_literals
  6. from __future__ import division
  7. from __future__ import absolute_import
  8. from future.builtins import str
  9. __all__ = [
  10. 'encode_7or8bit',
  11. 'encode_base64',
  12. 'encode_noop',
  13. 'encode_quopri',
  14. ]
  15. try:
  16. from base64 import encodebytes as _bencode
  17. except ImportError:
  18. # Py2 compatibility. TODO: test this!
  19. from base64 import encodestring as _bencode
  20. from quopri import encodestring as _encodestring
  21. def _qencode(s):
  22. enc = _encodestring(s, quotetabs=True)
  23. # Must encode spaces, which quopri.encodestring() doesn't do
  24. return enc.replace(' ', '=20')
  25. def encode_base64(msg):
  26. """Encode the message's payload in Base64.
  27. Also, add an appropriate Content-Transfer-Encoding header.
  28. """
  29. orig = msg.get_payload()
  30. encdata = str(_bencode(orig), 'ascii')
  31. msg.set_payload(encdata)
  32. msg['Content-Transfer-Encoding'] = 'base64'
  33. def encode_quopri(msg):
  34. """Encode the message's payload in quoted-printable.
  35. Also, add an appropriate Content-Transfer-Encoding header.
  36. """
  37. orig = msg.get_payload()
  38. encdata = _qencode(orig)
  39. msg.set_payload(encdata)
  40. msg['Content-Transfer-Encoding'] = 'quoted-printable'
  41. def encode_7or8bit(msg):
  42. """Set the Content-Transfer-Encoding header to 7bit or 8bit."""
  43. orig = msg.get_payload()
  44. if orig is None:
  45. # There's no payload. For backwards compatibility we use 7bit
  46. msg['Content-Transfer-Encoding'] = '7bit'
  47. return
  48. # We play a trick to make this go fast. If encoding/decode to ASCII
  49. # succeeds, we know the data must be 7bit, otherwise treat it as 8bit.
  50. try:
  51. if isinstance(orig, str):
  52. orig.encode('ascii')
  53. else:
  54. orig.decode('ascii')
  55. except UnicodeError:
  56. charset = msg.get_charset()
  57. output_cset = charset and charset.output_charset
  58. # iso-2022-* is non-ASCII but encodes to a 7-bit representation
  59. if output_cset and output_cset.lower().startswith('iso-2022-'):
  60. msg['Content-Transfer-Encoding'] = '7bit'
  61. else:
  62. msg['Content-Transfer-Encoding'] = '8bit'
  63. else:
  64. msg['Content-Transfer-Encoding'] = '7bit'
  65. if not isinstance(orig, str):
  66. msg.set_payload(orig.decode('ascii', 'surrogateescape'))
  67. def encode_noop(msg):
  68. """Do nothing."""
  69. # Well, not quite *nothing*: in Python3 we have to turn bytes into a string
  70. # in our internal surrogateescaped form in order to keep the model
  71. # consistent.
  72. orig = msg.get_payload()
  73. if not isinstance(orig, str):
  74. msg.set_payload(orig.decode('ascii', 'surrogateescape'))