2525"""
2626
2727__all__ = [
28- 'base64_len' ,
2928 'body_decode' ,
3029 'body_encode' ,
3130 'decode' ,
3231 'decodestring' ,
3332 'encode' ,
3433 'encodestring' ,
3534 'header_encode' ,
35+ 'header_length' ,
3636 ]
3737
3838import re
3939
40+ from base64 import b64encode
4041from binascii import b2a_base64 , a2b_base64
41- from email .utils import fix_eols
4242
4343CRLF = '\r \n '
4444NL = '\n '
5050
5151
5252# Helpers
53- def base64_len ( s ):
53+ def header_length ( bytearray ):
5454 """Return the length of s when it is encoded with base64."""
55- groups_of_3 , leftover = divmod (len (s ), 3 )
55+ groups_of_3 , leftover = divmod (len (bytearray ), 3 )
5656 # 4 bytes out for each 3 bytes (or nonzero fraction thereof) in.
57- # Thanks, Tim!
5857 n = groups_of_3 * 4
5958 if leftover :
6059 n += 4
6160 return n
6261
6362
6463
65- def header_encode (header , charset = 'iso-8859-1' , keep_eols = False ,
66- maxlinelen = 76 , eol = NL ):
64+ def header_encode (header_bytes , charset = 'iso-8859-1' ):
6765 """Encode a single header line with Base64 encoding in a given charset.
6866
69- Defined in RFC 2045, this Base64 encoding is identical to normal Base64
70- encoding, except that each line must be intelligently wrapped (respecting
71- the Base64 encoding), and subsequent lines must start with a space.
72-
7367 charset names the character set to use to encode the header. It defaults
74- to iso-8859-1.
75-
76- End-of-line characters (\\ r, \\ n, \\ r\\ n) will be automatically converted
77- to the canonical email line separator \\ r\\ n unless the keep_eols
78- parameter is True (the default is False).
79-
80- Each line of the header will be terminated in the value of eol, which
81- defaults to "\\ n". Set this to "\\ r\\ n" if you are using the result of
82- this function directly in email.
83-
84- The resulting string will be in the form:
85-
86- "=?charset?b?WW/5ciBtYXp66XLrIHf8eiBhIGhhbXBzdGHuciBBIFlv+XIgbWF6euly?=\\ n
87- =?charset?b?6yB3/HogYSBoYW1wc3Rh7nIgQkMgWW/5ciBtYXp66XLrIHf8eiBhIGhh?="
88-
89- with each line wrapped at, at most, maxlinelen characters (defaults to 76
90- characters).
68+ to iso-8859-1. Base64 encoding is defined in RFC 2045.
9169 """
9270 # Return empty headers unchanged
93- if not header :
94- return header
95-
96- if not keep_eols :
97- header = fix_eols (header )
98-
99- # Base64 encode each line, in encoded chunks no greater than maxlinelen in
100- # length, after the RFC chrome is added in.
101- base64ed = []
102- max_encoded = maxlinelen - len (charset ) - MISC_LEN
103- max_unencoded = max_encoded * 3 // 4
104-
105- for i in range (0 , len (header ), max_unencoded ):
106- base64ed .append (b2a_base64 (header [i :i + max_unencoded ]))
107-
108- # Now add the RFC chrome to each encoded chunk
109- lines = []
110- for line in base64ed :
111- # Ignore the last character of each line if it is a newline
112- if line [- 1 ] == ord (NL ):
113- line = line [:- 1 ]
114- # Add the chrome
115- lines .append ('=?%s?b?%s?=' % (charset , line ))
116- # Glue the lines together and return it. BAW: should we be able to
117- # specify the leading whitespace in the joiner?
118- joiner = eol + ' '
119- return joiner .join (lines )
71+ if not header_bytes :
72+ return str (header_bytes )
73+ encoded = b64encode (header_bytes )
74+ return '=?%s?b?%s?=' % (charset , encoded )
12075
12176
12277
123- def encode ( s , binary = True , maxlinelen = 76 , eol = NL ):
78+ def body_encode ( s , maxlinelen = 76 , eol = NL ):
12479 """Encode a string with base64.
12580
12681 Each line will be wrapped at, at most, maxlinelen characters (defaults to
12782 76 characters).
12883
129- If binary is False, end-of-line characters will be converted to the
130- canonical email end-of-line sequence \\ r\\ n. Otherwise they will be left
131- verbatim (this is the default).
132-
13384 Each line of encoded text will end with eol, which defaults to "\\ n". Set
13485 this to "\r \n " if you will be using the result of this function directly
13586 in an email.
13687 """
13788 if not s :
13889 return s
13990
140- if not binary :
141- s = fix_eols (s )
142-
14391 encvec = []
14492 max_unencoded = maxlinelen * 3 // 4
14593 for i in range (0 , len (s ), max_unencoded ):
@@ -152,25 +100,26 @@ def encode(s, binary=True, maxlinelen=76, eol=NL):
152100 return EMPTYSTRING .join (encvec )
153101
154102
155- # For convenience and backwards compatibility w/ standard base64 module
156- body_encode = encode
157- encodestring = encode
158-
159-
160103
161- def decode (string ):
104+ def decode (s , convert_eols = False ):
162105 """Decode a raw base64 string, returning a bytes object.
163106
164- This function does not parse a full MIME header value encoded with base64
165- (like =?iso-8895-1?b?bmloISBuaWgh?=) -- use the high level
166- email.Header class for that functionality.
107+ If convert_eols is set to a string value, all canonical email linefeeds,
108+ e.g. "\\ r\\ n", in the decoded text will be converted to the value of
109+ convert_eols. os.linesep is a good choice for convert_eols if you are
110+ decoding a text attachment.
111+
112+ This function does not parse a full MIME header value encoded with
113+ base64 (like =?iso-8895-1?b?bmloISBuaWgh?=) -- please use the high
114+ level email.Header class for that functionality.
167115 """
168- if not string :
169- return bytes ()
170- elif isinstance (string , str ):
171- return a2b_base64 (string .encode ('raw-unicode-escape' ))
172- else :
173- return a2b_base64 (string )
116+ if not s :
117+ return s
118+
119+ dec = a2b_base64 (s )
120+ if convert_eols :
121+ return dec .replace (CRLF , convert_eols )
122+ return dec
174123
175124
176125# For convenience and backwards compatibility w/ standard base64 module
0 commit comments