2006-02-08 10:34:21 -04:00
|
|
|
|
# Copyright (C) 2001-2006 Python Software Foundation
|
2004-10-03 00:16:19 -03:00
|
|
|
|
# Author: Ben Gertzfield, Barry Warsaw
|
|
|
|
|
# Contact: email-sig@python.org
|
2003-12-30 12:52:25 -04:00
|
|
|
|
|
2006-04-21 07:40:58 -03:00
|
|
|
|
__all__ = [
|
|
|
|
|
'Charset',
|
|
|
|
|
'add_alias',
|
|
|
|
|
'add_charset',
|
|
|
|
|
'add_codec',
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
import email.base64mime
|
|
|
|
|
import email.quoprimime
|
|
|
|
|
|
|
|
|
|
from email import errors
|
|
|
|
|
from email.encoders import encode_7or8bit
|
2002-09-28 14:47:56 -03:00
|
|
|
|
|
2002-04-10 18:01:31 -03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Flags for types of header encodings
|
2004-10-03 00:16:19 -03:00
|
|
|
|
QP = 1 # Quoted-Printable
|
|
|
|
|
BASE64 = 2 # Base64
|
|
|
|
|
SHORTEST = 3 # the shorter of QP and base64, but only for headers
|
2002-04-10 18:01:31 -03:00
|
|
|
|
|
|
|
|
|
# In "=?charset?q?hello_world?=", the =?, ?q?, and ?= add up to 7
|
2002-05-23 12:15:30 -03:00
|
|
|
|
MISC_LEN = 7
|
2002-04-10 18:01:31 -03:00
|
|
|
|
|
|
|
|
|
DEFAULT_CHARSET = 'us-ascii'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Defaults
|
|
|
|
|
CHARSETS = {
|
|
|
|
|
# input header enc body enc output conv
|
2002-05-23 12:15:30 -03:00
|
|
|
|
'iso-8859-1': (QP, QP, None),
|
2002-04-10 18:01:31 -03:00
|
|
|
|
'iso-8859-2': (QP, QP, None),
|
2003-01-06 20:29:07 -04:00
|
|
|
|
'iso-8859-3': (QP, QP, None),
|
|
|
|
|
'iso-8859-4': (QP, QP, None),
|
|
|
|
|
# iso-8859-5 is Cyrillic, and not especially used
|
|
|
|
|
# iso-8859-6 is Arabic, also not particularly used
|
|
|
|
|
# iso-8859-7 is Greek, QP will not make it readable
|
|
|
|
|
# iso-8859-8 is Hebrew, QP will not make it readable
|
|
|
|
|
'iso-8859-9': (QP, QP, None),
|
|
|
|
|
'iso-8859-10': (QP, QP, None),
|
|
|
|
|
# iso-8859-11 is Thai, QP will not make it readable
|
|
|
|
|
'iso-8859-13': (QP, QP, None),
|
|
|
|
|
'iso-8859-14': (QP, QP, None),
|
|
|
|
|
'iso-8859-15': (QP, QP, None),
|
Merged revisions 53538-53622 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r53545 | andrew.kuchling | 2007-01-24 21:06:41 +0100 (Wed, 24 Jan 2007) | 1 line
Strengthen warning about using lock()
........
r53556 | thomas.heller | 2007-01-25 19:34:14 +0100 (Thu, 25 Jan 2007) | 3 lines
Fix for #1643874: When calling SysAllocString, create a PyCObject
which will eventually call SysFreeString to free the BSTR resource.
........
r53563 | andrew.kuchling | 2007-01-25 21:02:13 +0100 (Thu, 25 Jan 2007) | 1 line
Add item
........
r53564 | brett.cannon | 2007-01-25 21:22:02 +0100 (Thu, 25 Jan 2007) | 8 lines
Fix time.strptime's %U support. Basically rewrote the algorithm to be more
generic so that one only has to shift certain values based on whether the week
was specified to start on Monday or Sunday. Cut out a lot of edge case code
compared to the previous version. Also broke algorithm out into its own
function (that is private to the module).
Fixes bug #1643943 (thanks Biran Nahas for the report).
........
r53570 | brett.cannon | 2007-01-26 00:30:39 +0100 (Fri, 26 Jan 2007) | 4 lines
Remove specific mention of my name and email address from modules. Not really
needed and all bug reports should go to the bug tracker, not directly to me.
Plus I am not the only person to have edited these files at this point.
........
r53573 | fred.drake | 2007-01-26 17:28:44 +0100 (Fri, 26 Jan 2007) | 1 line
fix typo (extraneous ")")
........
r53575 | georg.brandl | 2007-01-27 18:43:02 +0100 (Sat, 27 Jan 2007) | 4 lines
Patch #1638243: the compiler package is now able to correctly compile
a with statement; previously, executing code containing a with statement
compiled by the compiler package crashed the interpreter.
........
r53578 | georg.brandl | 2007-01-27 18:59:42 +0100 (Sat, 27 Jan 2007) | 3 lines
Patch #1634778: add missing encoding aliases for iso8859_15 and
iso8859_16.
........
r53579 | georg.brandl | 2007-01-27 20:38:50 +0100 (Sat, 27 Jan 2007) | 2 lines
Bug #1645944: os.access now returns bool but docstring is not updated
........
r53590 | brett.cannon | 2007-01-28 21:58:00 +0100 (Sun, 28 Jan 2007) | 2 lines
Use the thread lock's context manager instead of a try/finally statement.
........
r53591 | brett.cannon | 2007-01-29 05:41:44 +0100 (Mon, 29 Jan 2007) | 2 lines
Add a test for slicing an exception.
........
r53594 | andrew.kuchling | 2007-01-29 21:21:43 +0100 (Mon, 29 Jan 2007) | 1 line
Minor edits to the curses HOWTO
........
r53596 | andrew.kuchling | 2007-01-29 21:55:40 +0100 (Mon, 29 Jan 2007) | 1 line
Various minor edits
........
r53597 | andrew.kuchling | 2007-01-29 22:28:48 +0100 (Mon, 29 Jan 2007) | 1 line
More edits
........
r53601 | tim.peters | 2007-01-30 04:03:46 +0100 (Tue, 30 Jan 2007) | 2 lines
Whitespace normalization.
........
r53603 | georg.brandl | 2007-01-30 21:21:30 +0100 (Tue, 30 Jan 2007) | 2 lines
Bug #1648191: typo in docs.
........
r53605 | brett.cannon | 2007-01-30 22:34:36 +0100 (Tue, 30 Jan 2007) | 8 lines
No more raising of string exceptions!
The next step of PEP 352 (for 2.6) causes raising a string exception to trigger
a TypeError. Trying to catch a string exception raises a DeprecationWarning.
References to string exceptions has been removed from the docs since they are
now just an error.
........
r53618 | raymond.hettinger | 2007-02-01 22:02:59 +0100 (Thu, 01 Feb 2007) | 1 line
Bug #1648179: set.update() not recognizing __iter__ overrides in dict subclasses.
........
2007-02-04 21:24:16 -04:00
|
|
|
|
'iso-8859-16': (QP, QP, None),
|
2003-01-06 20:29:07 -04:00
|
|
|
|
'windows-1252':(QP, QP, None),
|
|
|
|
|
'viscii': (QP, QP, None),
|
2002-04-10 18:01:31 -03:00
|
|
|
|
'us-ascii': (None, None, None),
|
|
|
|
|
'big5': (BASE64, BASE64, None),
|
2002-05-23 12:15:30 -03:00
|
|
|
|
'gb2312': (BASE64, BASE64, None),
|
2002-04-10 18:01:31 -03:00
|
|
|
|
'euc-jp': (BASE64, None, 'iso-2022-jp'),
|
|
|
|
|
'shift_jis': (BASE64, None, 'iso-2022-jp'),
|
|
|
|
|
'iso-2022-jp': (BASE64, None, None),
|
|
|
|
|
'koi8-r': (BASE64, BASE64, None),
|
2002-09-28 14:47:56 -03:00
|
|
|
|
'utf-8': (SHORTEST, BASE64, 'utf-8'),
|
2002-10-14 12:06:55 -03:00
|
|
|
|
# We're making this one up to represent raw unencoded 8-bit
|
|
|
|
|
'8bit': (None, BASE64, 'utf-8'),
|
2002-04-10 18:01:31 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Aliases for other commonly-used names for character sets. Map
|
|
|
|
|
# them to the real ones used in email.
|
|
|
|
|
ALIASES = {
|
|
|
|
|
'latin_1': 'iso-8859-1',
|
|
|
|
|
'latin-1': 'iso-8859-1',
|
2003-01-06 20:29:07 -04:00
|
|
|
|
'latin_2': 'iso-8859-2',
|
|
|
|
|
'latin-2': 'iso-8859-2',
|
|
|
|
|
'latin_3': 'iso-8859-3',
|
|
|
|
|
'latin-3': 'iso-8859-3',
|
|
|
|
|
'latin_4': 'iso-8859-4',
|
|
|
|
|
'latin-4': 'iso-8859-4',
|
|
|
|
|
'latin_5': 'iso-8859-9',
|
|
|
|
|
'latin-5': 'iso-8859-9',
|
|
|
|
|
'latin_6': 'iso-8859-10',
|
|
|
|
|
'latin-6': 'iso-8859-10',
|
|
|
|
|
'latin_7': 'iso-8859-13',
|
|
|
|
|
'latin-7': 'iso-8859-13',
|
|
|
|
|
'latin_8': 'iso-8859-14',
|
|
|
|
|
'latin-8': 'iso-8859-14',
|
|
|
|
|
'latin_9': 'iso-8859-15',
|
|
|
|
|
'latin-9': 'iso-8859-15',
|
Merged revisions 53538-53622 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r53545 | andrew.kuchling | 2007-01-24 21:06:41 +0100 (Wed, 24 Jan 2007) | 1 line
Strengthen warning about using lock()
........
r53556 | thomas.heller | 2007-01-25 19:34:14 +0100 (Thu, 25 Jan 2007) | 3 lines
Fix for #1643874: When calling SysAllocString, create a PyCObject
which will eventually call SysFreeString to free the BSTR resource.
........
r53563 | andrew.kuchling | 2007-01-25 21:02:13 +0100 (Thu, 25 Jan 2007) | 1 line
Add item
........
r53564 | brett.cannon | 2007-01-25 21:22:02 +0100 (Thu, 25 Jan 2007) | 8 lines
Fix time.strptime's %U support. Basically rewrote the algorithm to be more
generic so that one only has to shift certain values based on whether the week
was specified to start on Monday or Sunday. Cut out a lot of edge case code
compared to the previous version. Also broke algorithm out into its own
function (that is private to the module).
Fixes bug #1643943 (thanks Biran Nahas for the report).
........
r53570 | brett.cannon | 2007-01-26 00:30:39 +0100 (Fri, 26 Jan 2007) | 4 lines
Remove specific mention of my name and email address from modules. Not really
needed and all bug reports should go to the bug tracker, not directly to me.
Plus I am not the only person to have edited these files at this point.
........
r53573 | fred.drake | 2007-01-26 17:28:44 +0100 (Fri, 26 Jan 2007) | 1 line
fix typo (extraneous ")")
........
r53575 | georg.brandl | 2007-01-27 18:43:02 +0100 (Sat, 27 Jan 2007) | 4 lines
Patch #1638243: the compiler package is now able to correctly compile
a with statement; previously, executing code containing a with statement
compiled by the compiler package crashed the interpreter.
........
r53578 | georg.brandl | 2007-01-27 18:59:42 +0100 (Sat, 27 Jan 2007) | 3 lines
Patch #1634778: add missing encoding aliases for iso8859_15 and
iso8859_16.
........
r53579 | georg.brandl | 2007-01-27 20:38:50 +0100 (Sat, 27 Jan 2007) | 2 lines
Bug #1645944: os.access now returns bool but docstring is not updated
........
r53590 | brett.cannon | 2007-01-28 21:58:00 +0100 (Sun, 28 Jan 2007) | 2 lines
Use the thread lock's context manager instead of a try/finally statement.
........
r53591 | brett.cannon | 2007-01-29 05:41:44 +0100 (Mon, 29 Jan 2007) | 2 lines
Add a test for slicing an exception.
........
r53594 | andrew.kuchling | 2007-01-29 21:21:43 +0100 (Mon, 29 Jan 2007) | 1 line
Minor edits to the curses HOWTO
........
r53596 | andrew.kuchling | 2007-01-29 21:55:40 +0100 (Mon, 29 Jan 2007) | 1 line
Various minor edits
........
r53597 | andrew.kuchling | 2007-01-29 22:28:48 +0100 (Mon, 29 Jan 2007) | 1 line
More edits
........
r53601 | tim.peters | 2007-01-30 04:03:46 +0100 (Tue, 30 Jan 2007) | 2 lines
Whitespace normalization.
........
r53603 | georg.brandl | 2007-01-30 21:21:30 +0100 (Tue, 30 Jan 2007) | 2 lines
Bug #1648191: typo in docs.
........
r53605 | brett.cannon | 2007-01-30 22:34:36 +0100 (Tue, 30 Jan 2007) | 8 lines
No more raising of string exceptions!
The next step of PEP 352 (for 2.6) causes raising a string exception to trigger
a TypeError. Trying to catch a string exception raises a DeprecationWarning.
References to string exceptions has been removed from the docs since they are
now just an error.
........
r53618 | raymond.hettinger | 2007-02-01 22:02:59 +0100 (Thu, 01 Feb 2007) | 1 line
Bug #1648179: set.update() not recognizing __iter__ overrides in dict subclasses.
........
2007-02-04 21:24:16 -04:00
|
|
|
|
'latin_10':'iso-8859-16',
|
|
|
|
|
'latin-10':'iso-8859-16',
|
2003-01-06 20:29:07 -04:00
|
|
|
|
'cp949': 'ks_c_5601-1987',
|
|
|
|
|
'euc_jp': 'euc-jp',
|
|
|
|
|
'euc_kr': 'euc-kr',
|
2002-04-10 18:01:31 -03:00
|
|
|
|
'ascii': 'us-ascii',
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-13 01:00:45 -03:00
|
|
|
|
|
2003-12-30 12:52:25 -04:00
|
|
|
|
# Map charsets to their Unicode codec strings.
|
2002-04-10 18:01:31 -03:00
|
|
|
|
CODEC_MAP = {
|
2003-12-30 12:52:25 -04:00
|
|
|
|
'gb2312': 'eucgb2312_cn',
|
2002-04-10 18:01:31 -03:00
|
|
|
|
'big5': 'big5_tw',
|
|
|
|
|
# Hack: We don't want *any* conversion for stuff marked us-ascii, as all
|
|
|
|
|
# sorts of garbage might be sent to us in the guise of 7-bit us-ascii.
|
|
|
|
|
# Let that stuff pass through without conversion to/from Unicode.
|
|
|
|
|
'us-ascii': None,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Convenience functions for extending the above mappings
|
|
|
|
|
def add_charset(charset, header_enc=None, body_enc=None, output_charset=None):
|
2002-09-30 21:05:24 -03:00
|
|
|
|
"""Add character set properties to the global registry.
|
2002-04-10 18:01:31 -03:00
|
|
|
|
|
|
|
|
|
charset is the input character set, and must be the canonical name of a
|
|
|
|
|
character set.
|
|
|
|
|
|
|
|
|
|
Optional header_enc and body_enc is either Charset.QP for
|
2002-09-28 14:47:56 -03:00
|
|
|
|
quoted-printable, Charset.BASE64 for base64 encoding, Charset.SHORTEST for
|
|
|
|
|
the shortest of qp or base64 encoding, or None for no encoding. SHORTEST
|
|
|
|
|
is only valid for header_enc. It describes how message headers and
|
|
|
|
|
message bodies in the input charset are to be encoded. Default is no
|
|
|
|
|
encoding.
|
2002-04-10 18:01:31 -03:00
|
|
|
|
|
|
|
|
|
Optional output_charset is the character set that the output should be
|
|
|
|
|
in. Conversions will proceed from input charset, to Unicode, to the
|
|
|
|
|
output charset when the method Charset.convert() is called. The default
|
|
|
|
|
is to output in the same character set as the input.
|
|
|
|
|
|
|
|
|
|
Both input_charset and output_charset must have Unicode codec entries in
|
|
|
|
|
the module's charset-to-codec mapping; use add_codec(charset, codecname)
|
2002-09-30 21:05:24 -03:00
|
|
|
|
to add codecs the module does not know about. See the codecs module's
|
2002-04-10 18:01:31 -03:00
|
|
|
|
documentation for more information.
|
|
|
|
|
"""
|
2002-09-28 14:47:56 -03:00
|
|
|
|
if body_enc == SHORTEST:
|
2004-10-03 00:16:19 -03:00
|
|
|
|
raise ValueError('SHORTEST not allowed for body_enc')
|
2002-04-10 18:01:31 -03:00
|
|
|
|
CHARSETS[charset] = (header_enc, body_enc, output_charset)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_alias(alias, canonical):
|
|
|
|
|
"""Add a character set alias.
|
|
|
|
|
|
|
|
|
|
alias is the alias name, e.g. latin-1
|
|
|
|
|
canonical is the character set's canonical name, e.g. iso-8859-1
|
|
|
|
|
"""
|
|
|
|
|
ALIASES[alias] = canonical
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_codec(charset, codecname):
|
|
|
|
|
"""Add a codec that map characters in the given charset to/from Unicode.
|
|
|
|
|
|
|
|
|
|
charset is the canonical name of a character set. codecname is the name
|
|
|
|
|
of a Python codec, as appropriate for the second argument to the unicode()
|
2002-09-30 21:05:24 -03:00
|
|
|
|
built-in, or to the encode() method of a Unicode string.
|
2002-04-10 18:01:31 -03:00
|
|
|
|
"""
|
|
|
|
|
CODEC_MAP[charset] = codecname
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Charset:
|
|
|
|
|
"""Map character sets to their email properties.
|
|
|
|
|
|
|
|
|
|
This class provides information about the requirements imposed on email
|
|
|
|
|
for a specific character set. It also provides convenience routines for
|
|
|
|
|
converting between character sets, given the availability of the
|
2002-09-30 21:05:24 -03:00
|
|
|
|
applicable codecs. Given a character set, it will do its best to provide
|
|
|
|
|
information on how to use that character set in an email in an
|
|
|
|
|
RFC-compliant way.
|
2002-05-23 12:15:30 -03:00
|
|
|
|
|
2002-04-10 18:01:31 -03:00
|
|
|
|
Certain character sets must be encoded with quoted-printable or base64
|
|
|
|
|
when used in email headers or bodies. Certain character sets must be
|
|
|
|
|
converted outright, and are not allowed in email. Instances of this
|
|
|
|
|
module expose the following information about a character set:
|
|
|
|
|
|
|
|
|
|
input_charset: The initial character set specified. Common aliases
|
|
|
|
|
are converted to their `official' email names (e.g. latin_1
|
|
|
|
|
is converted to iso-8859-1). Defaults to 7-bit us-ascii.
|
|
|
|
|
|
|
|
|
|
header_encoding: If the character set must be encoded before it can be
|
|
|
|
|
used in an email header, this attribute will be set to
|
2002-09-28 14:47:56 -03:00
|
|
|
|
Charset.QP (for quoted-printable), Charset.BASE64 (for
|
|
|
|
|
base64 encoding), or Charset.SHORTEST for the shortest of
|
|
|
|
|
QP or BASE64 encoding. Otherwise, it will be None.
|
2002-04-10 18:01:31 -03:00
|
|
|
|
|
|
|
|
|
body_encoding: Same as header_encoding, but describes the encoding for the
|
|
|
|
|
mail message's body, which indeed may be different than the
|
2002-09-28 14:47:56 -03:00
|
|
|
|
header encoding. Charset.SHORTEST is not allowed for
|
|
|
|
|
body_encoding.
|
2002-04-10 18:01:31 -03:00
|
|
|
|
|
|
|
|
|
output_charset: Some character sets must be converted before the can be
|
|
|
|
|
used in email headers or bodies. If the input_charset is
|
|
|
|
|
one of them, this attribute will contain the name of the
|
|
|
|
|
charset output will be converted to. Otherwise, it will
|
|
|
|
|
be None.
|
|
|
|
|
|
|
|
|
|
input_codec: The name of the Python codec used to convert the
|
|
|
|
|
input_charset to Unicode. If no conversion codec is
|
|
|
|
|
necessary, this attribute will be None.
|
|
|
|
|
|
|
|
|
|
output_codec: The name of the Python codec used to convert Unicode
|
|
|
|
|
to the output_charset. If no conversion codec is necessary,
|
|
|
|
|
this attribute will have the same value as the input_codec.
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self, input_charset=DEFAULT_CHARSET):
|
2004-10-09 18:08:30 -03:00
|
|
|
|
# RFC 2046, $4.1.2 says charsets are not case sensitive. We coerce to
|
2006-04-21 07:40:58 -03:00
|
|
|
|
# unicode because its .lower() is locale insensitive. If the argument
|
|
|
|
|
# is already a unicode, we leave it at that, but ensure that the
|
|
|
|
|
# charset is ASCII, as the standard (RFC XXX) requires.
|
|
|
|
|
try:
|
2007-05-02 16:09:54 -03:00
|
|
|
|
if isinstance(input_charset, str):
|
2006-04-21 07:40:58 -03:00
|
|
|
|
input_charset.encode('ascii')
|
|
|
|
|
else:
|
2007-05-02 16:09:54 -03:00
|
|
|
|
input_charset = str(input_charset, 'ascii')
|
2006-04-21 07:40:58 -03:00
|
|
|
|
except UnicodeError:
|
|
|
|
|
raise errors.CharsetError(input_charset)
|
|
|
|
|
input_charset = input_charset.lower()
|
2002-04-10 18:01:31 -03:00
|
|
|
|
# Set the input charset after filtering through the aliases
|
|
|
|
|
self.input_charset = ALIASES.get(input_charset, input_charset)
|
|
|
|
|
# We can try to guess which encoding and conversion to use by the
|
|
|
|
|
# charset_map dictionary. Try that first, but let the user override
|
|
|
|
|
# it.
|
|
|
|
|
henc, benc, conv = CHARSETS.get(self.input_charset,
|
2002-10-10 12:11:20 -03:00
|
|
|
|
(SHORTEST, BASE64, None))
|
2003-12-30 12:52:25 -04:00
|
|
|
|
if not conv:
|
|
|
|
|
conv = self.input_charset
|
2002-04-10 18:01:31 -03:00
|
|
|
|
# Set the attributes, allowing the arguments to override the default.
|
|
|
|
|
self.header_encoding = henc
|
|
|
|
|
self.body_encoding = benc
|
|
|
|
|
self.output_charset = ALIASES.get(conv, conv)
|
|
|
|
|
# Now set the codecs. If one isn't defined for input_charset,
|
|
|
|
|
# guess and try a Unicode codec with the same name as input_codec.
|
|
|
|
|
self.input_codec = CODEC_MAP.get(self.input_charset,
|
|
|
|
|
self.input_charset)
|
|
|
|
|
self.output_codec = CODEC_MAP.get(self.output_charset,
|
2006-02-08 10:34:21 -04:00
|
|
|
|
self.output_charset)
|
2002-04-10 18:01:31 -03:00
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.input_charset.lower()
|
|
|
|
|
|
2003-03-06 01:16:29 -04:00
|
|
|
|
__repr__ = __str__
|
|
|
|
|
|
2002-04-10 18:01:31 -03:00
|
|
|
|
def __eq__(self, other):
|
|
|
|
|
return str(self) == str(other).lower()
|
|
|
|
|
|
|
|
|
|
def __ne__(self, other):
|
|
|
|
|
return not self.__eq__(other)
|
|
|
|
|
|
|
|
|
|
def get_body_encoding(self):
|
|
|
|
|
"""Return the content-transfer-encoding used for body encoding.
|
|
|
|
|
|
|
|
|
|
This is either the string `quoted-printable' or `base64' depending on
|
|
|
|
|
the encoding used, or it is a function in which case you should call
|
|
|
|
|
the function with a single argument, the Message object being
|
2002-09-30 21:05:24 -03:00
|
|
|
|
encoded. The function should then set the Content-Transfer-Encoding
|
2002-04-10 18:01:31 -03:00
|
|
|
|
header itself to whatever is appropriate.
|
|
|
|
|
|
|
|
|
|
Returns "quoted-printable" if self.body_encoding is QP.
|
|
|
|
|
Returns "base64" if self.body_encoding is BASE64.
|
|
|
|
|
Returns "7bit" otherwise.
|
|
|
|
|
"""
|
2006-08-24 00:53:23 -03:00
|
|
|
|
assert self.body_encoding != SHORTEST
|
2002-04-10 18:01:31 -03:00
|
|
|
|
if self.body_encoding == QP:
|
|
|
|
|
return 'quoted-printable'
|
|
|
|
|
elif self.body_encoding == BASE64:
|
|
|
|
|
return 'base64'
|
|
|
|
|
else:
|
|
|
|
|
return encode_7or8bit
|
|
|
|
|
|
|
|
|
|
def convert(self, s):
|
|
|
|
|
"""Convert a string from the input_codec to the output_codec."""
|
2006-08-24 00:53:23 -03:00
|
|
|
|
if self.input_codec != self.output_codec:
|
2007-05-02 16:09:54 -03:00
|
|
|
|
return str(s, self.input_codec).encode(self.output_codec)
|
2002-04-10 18:01:31 -03:00
|
|
|
|
else:
|
|
|
|
|
return s
|
|
|
|
|
|
|
|
|
|
def to_splittable(self, s):
|
|
|
|
|
"""Convert a possibly multibyte string to a safely splittable format.
|
|
|
|
|
|
|
|
|
|
Uses the input_codec to try and convert the string to Unicode, so it
|
2002-09-30 21:05:24 -03:00
|
|
|
|
can be safely split on character boundaries (even for multibyte
|
2002-04-10 18:01:31 -03:00
|
|
|
|
characters).
|
|
|
|
|
|
2002-09-30 21:05:24 -03:00
|
|
|
|
Returns the string as-is if it isn't known how to convert it to
|
2002-04-10 18:01:31 -03:00
|
|
|
|
Unicode with the input_charset.
|
|
|
|
|
|
|
|
|
|
Characters that could not be converted to Unicode will be replaced
|
|
|
|
|
with the Unicode replacement character U+FFFD.
|
|
|
|
|
"""
|
2007-05-02 16:09:54 -03:00
|
|
|
|
if isinstance(s, str) or self.input_codec is None:
|
2002-04-10 18:01:31 -03:00
|
|
|
|
return s
|
|
|
|
|
try:
|
2007-05-02 16:09:54 -03:00
|
|
|
|
return str(s, self.input_codec, 'replace')
|
2002-04-10 18:01:31 -03:00
|
|
|
|
except LookupError:
|
|
|
|
|
# Input codec not installed on system, so return the original
|
|
|
|
|
# string unchanged.
|
|
|
|
|
return s
|
|
|
|
|
|
2002-09-28 14:47:56 -03:00
|
|
|
|
def from_splittable(self, ustr, to_output=True):
|
2002-04-10 18:01:31 -03:00
|
|
|
|
"""Convert a splittable string back into an encoded string.
|
|
|
|
|
|
2002-09-30 21:05:24 -03:00
|
|
|
|
Uses the proper codec to try and convert the string from Unicode back
|
|
|
|
|
into an encoded format. Return the string as-is if it is not Unicode,
|
|
|
|
|
or if it could not be converted from Unicode.
|
2002-04-10 18:01:31 -03:00
|
|
|
|
|
|
|
|
|
Characters that could not be converted from Unicode will be replaced
|
|
|
|
|
with an appropriate character (usually '?').
|
|
|
|
|
|
2002-09-28 14:47:56 -03:00
|
|
|
|
If to_output is True (the default), uses output_codec to convert to an
|
|
|
|
|
encoded format. If to_output is False, uses input_codec.
|
2002-04-10 18:01:31 -03:00
|
|
|
|
"""
|
|
|
|
|
if to_output:
|
|
|
|
|
codec = self.output_codec
|
|
|
|
|
else:
|
|
|
|
|
codec = self.input_codec
|
2007-05-02 16:09:54 -03:00
|
|
|
|
if not isinstance(ustr, str) or codec is None:
|
2002-04-10 18:01:31 -03:00
|
|
|
|
return ustr
|
|
|
|
|
try:
|
|
|
|
|
return ustr.encode(codec, 'replace')
|
|
|
|
|
except LookupError:
|
|
|
|
|
# Output codec not installed
|
|
|
|
|
return ustr
|
|
|
|
|
|
|
|
|
|
def get_output_charset(self):
|
|
|
|
|
"""Return the output character set.
|
|
|
|
|
|
2002-09-30 21:05:24 -03:00
|
|
|
|
This is self.output_charset if that is not None, otherwise it is
|
2002-04-10 18:01:31 -03:00
|
|
|
|
self.input_charset.
|
|
|
|
|
"""
|
|
|
|
|
return self.output_charset or self.input_charset
|
|
|
|
|
|
|
|
|
|
def encoded_header_len(self, s):
|
|
|
|
|
"""Return the length of the encoded header string."""
|
|
|
|
|
cset = self.get_output_charset()
|
|
|
|
|
# The len(s) of a 7bit encoding is len(s)
|
2002-09-28 14:47:56 -03:00
|
|
|
|
if self.header_encoding == BASE64:
|
2006-04-21 07:40:58 -03:00
|
|
|
|
return email.base64mime.base64_len(s) + len(cset) + MISC_LEN
|
2002-09-28 14:47:56 -03:00
|
|
|
|
elif self.header_encoding == QP:
|
2006-04-21 07:40:58 -03:00
|
|
|
|
return email.quoprimime.header_quopri_len(s) + len(cset) + MISC_LEN
|
2002-09-28 14:47:56 -03:00
|
|
|
|
elif self.header_encoding == SHORTEST:
|
2006-04-21 07:40:58 -03:00
|
|
|
|
lenb64 = email.base64mime.base64_len(s)
|
|
|
|
|
lenqp = email.quoprimime.header_quopri_len(s)
|
2002-09-28 14:47:56 -03:00
|
|
|
|
return min(lenb64, lenqp) + len(cset) + MISC_LEN
|
2002-04-10 18:01:31 -03:00
|
|
|
|
else:
|
|
|
|
|
return len(s)
|
|
|
|
|
|
2002-09-28 14:47:56 -03:00
|
|
|
|
def header_encode(self, s, convert=False):
|
2002-04-10 18:01:31 -03:00
|
|
|
|
"""Header-encode a string, optionally converting it to output_charset.
|
|
|
|
|
|
2002-09-28 14:47:56 -03:00
|
|
|
|
If convert is True, the string will be converted from the input
|
2002-04-10 18:01:31 -03:00
|
|
|
|
charset to the output charset automatically. This is not useful for
|
|
|
|
|
multibyte character sets, which have line length issues (multibyte
|
|
|
|
|
characters must be split on a character, not a byte boundary); use the
|
|
|
|
|
high-level Header class to deal with these issues. convert defaults
|
2002-09-28 14:47:56 -03:00
|
|
|
|
to False.
|
2002-04-10 18:01:31 -03:00
|
|
|
|
|
|
|
|
|
The type of encoding (base64 or quoted-printable) will be based on
|
|
|
|
|
self.header_encoding.
|
|
|
|
|
"""
|
|
|
|
|
cset = self.get_output_charset()
|
|
|
|
|
if convert:
|
|
|
|
|
s = self.convert(s)
|
|
|
|
|
# 7bit/8bit encodings return the string unchanged (modulo conversions)
|
2002-09-28 14:47:56 -03:00
|
|
|
|
if self.header_encoding == BASE64:
|
2006-04-21 07:40:58 -03:00
|
|
|
|
return email.base64mime.header_encode(s, cset)
|
2002-09-28 14:47:56 -03:00
|
|
|
|
elif self.header_encoding == QP:
|
2006-04-21 07:40:58 -03:00
|
|
|
|
return email.quoprimime.header_encode(s, cset, maxlinelen=None)
|
2002-09-28 14:47:56 -03:00
|
|
|
|
elif self.header_encoding == SHORTEST:
|
2006-04-21 07:40:58 -03:00
|
|
|
|
lenb64 = email.base64mime.base64_len(s)
|
|
|
|
|
lenqp = email.quoprimime.header_quopri_len(s)
|
2002-09-28 14:47:56 -03:00
|
|
|
|
if lenb64 < lenqp:
|
2006-04-21 07:40:58 -03:00
|
|
|
|
return email.base64mime.header_encode(s, cset)
|
2002-09-28 14:47:56 -03:00
|
|
|
|
else:
|
2006-04-21 07:40:58 -03:00
|
|
|
|
return email.quoprimime.header_encode(s, cset, maxlinelen=None)
|
2002-04-10 18:01:31 -03:00
|
|
|
|
else:
|
|
|
|
|
return s
|
|
|
|
|
|
2002-09-28 14:47:56 -03:00
|
|
|
|
def body_encode(self, s, convert=True):
|
2002-04-10 18:01:31 -03:00
|
|
|
|
"""Body-encode a string and convert it to output_charset.
|
|
|
|
|
|
2002-09-28 14:47:56 -03:00
|
|
|
|
If convert is True (the default), the string will be converted from
|
2002-04-10 18:01:31 -03:00
|
|
|
|
the input charset to output charset automatically. Unlike
|
|
|
|
|
header_encode(), there are no issues with byte boundaries and
|
|
|
|
|
multibyte charsets in email bodies, so this is usually pretty safe.
|
|
|
|
|
|
|
|
|
|
The type of encoding (base64 or quoted-printable) will be based on
|
|
|
|
|
self.body_encoding.
|
|
|
|
|
"""
|
|
|
|
|
if convert:
|
|
|
|
|
s = self.convert(s)
|
|
|
|
|
# 7bit/8bit encodings return the string unchanged (module conversions)
|
|
|
|
|
if self.body_encoding is BASE64:
|
2006-04-21 07:40:58 -03:00
|
|
|
|
return email.base64mime.body_encode(s)
|
2002-10-21 02:29:53 -03:00
|
|
|
|
elif self.body_encoding is QP:
|
2006-04-21 07:40:58 -03:00
|
|
|
|
return email.quoprimime.body_encode(s)
|
2002-04-10 18:01:31 -03:00
|
|
|
|
else:
|
|
|
|
|
return s
|