1 """Various tools used by MIME-reading or MIME-writing programs."""
7 from warnings
import filterwarnings
, catch_warnings
10 filterwarnings("ignore", ".*rfc822 has been removed", DeprecationWarning)
13 from warnings
import warnpy3k
14 warnpy3k("in 3.x, mimetools has been removed in favor of the email package",
17 __all__
= ["Message","choose_boundary","encode","decode","copyliteral",
20 class Message(rfc822
.Message
):
21 """A derived class of rfc822.Message that knows about MIME headers and
22 contains some hooks for decoding encoded and multipart messages."""
24 def __init__(self
, fp
, seekable
= 1):
25 rfc822
.Message
.__init
__(self
, fp
, seekable
)
26 self
.encodingheader
= \
27 self
.getheader('content-transfer-encoding')
29 self
.getheader('content-type')
39 self
.plisttext
= str[i
:]
43 fields
= str.split('/')
44 for i
in range(len(fields
)):
45 fields
[i
] = fields
[i
].strip().lower()
46 self
.type = '/'.join(fields
)
47 self
.maintype
= fields
[0]
48 self
.subtype
= '/'.join(fields
[1:])
56 # XXX Should parse quotes!
63 f
= f
[:i
].strip().lower() + \
65 self
.plist
.append(f
.strip())
71 def getparam(self
, name
):
72 name
= name
.lower() + '='
76 return rfc822
.unquote(p
[n
:])
79 def getparamnames(self
):
84 result
.append(p
[:i
].lower())
87 def getencoding(self
):
88 if self
.encodingheader
is None:
90 return self
.encodingheader
.lower()
95 def getmaintype(self
):
110 import dummy_thread
as thread
111 _counter_lock
= thread
.allocate_lock()
115 def _get_next_counter():
117 _counter_lock
.acquire()
120 _counter_lock
.release()
125 def choose_boundary():
126 """Return a string usable as a multipart boundary.
128 The string chosen is unique within a single program run, and
129 incorporates the user id (if available), process id (if available),
130 and current time. So it's very unlikely the returned string appears
131 in message text, but there's no guarantee.
133 The boundary contains dots so you have to quote it in the header."""
140 hostid
= socket
.gethostbyname(socket
.gethostname())
141 except socket
.gaierror
:
144 uid
= repr(os
.getuid())
145 except AttributeError:
148 pid
= repr(os
.getpid())
149 except AttributeError:
151 _prefix
= hostid
+ '.' + uid
+ '.' + pid
152 return "%s.%.3f.%d" % (_prefix
, time
.time(), _get_next_counter())
155 # Subroutines for decoding some common content-transfer-types
157 def decode(input, output
, encoding
):
158 """Decode common content-transfer-encodings (base64, quopri, uuencode)."""
159 if encoding
== 'base64':
161 return base64
.decode(input, output
)
162 if encoding
== 'quoted-printable':
164 return quopri
.decode(input, output
)
165 if encoding
in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
167 return uu
.decode(input, output
)
168 if encoding
in ('7bit', '8bit'):
169 return output
.write(input.read())
170 if encoding
in decodetab
:
171 pipethrough(input, decodetab
[encoding
], output
)
174 'unknown Content-Transfer-Encoding: %s' % encoding
176 def encode(input, output
, encoding
):
177 """Encode common content-transfer-encodings (base64, quopri, uuencode)."""
178 if encoding
== 'base64':
180 return base64
.encode(input, output
)
181 if encoding
== 'quoted-printable':
183 return quopri
.encode(input, output
, 0)
184 if encoding
in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
186 return uu
.encode(input, output
)
187 if encoding
in ('7bit', '8bit'):
188 return output
.write(input.read())
189 if encoding
in encodetab
:
190 pipethrough(input, encodetab
[encoding
], output
)
193 'unknown Content-Transfer-Encoding: %s' % encoding
195 # The following is no longer used for standard encodings
197 # XXX This requires that uudecode and mmencode are in $PATH
201 sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
207 'uuencode': uudecode_pipe
,
208 'x-uuencode': uudecode_pipe
,
209 'uue': uudecode_pipe
,
210 'x-uue': uudecode_pipe
,
211 'quoted-printable': 'mmencode -u -q',
212 'base64': 'mmencode -u -b',
216 'x-uuencode': 'uuencode tempfile',
217 'uuencode': 'uuencode tempfile',
218 'x-uue': 'uuencode tempfile',
219 'uue': 'uuencode tempfile',
220 'quoted-printable': 'mmencode -q',
221 'base64': 'mmencode -b',
224 def pipeto(input, command
):
225 pipe
= os
.popen(command
, 'w')
226 copyliteral(input, pipe
)
229 def pipethrough(input, command
, output
):
230 (fd
, tempname
) = tempfile
.mkstemp()
231 temp
= os
.fdopen(fd
, 'w')
232 copyliteral(input, temp
)
234 pipe
= os
.popen(command
+ ' <' + tempname
, 'r')
235 copybinary(pipe
, output
)
239 def copyliteral(input, output
):
241 line
= input.readline()
245 def copybinary(input, output
):
248 line
= input.read(BUFSIZE
)