1 """Various tools used by MIME-reading or MIME-writing programs."""
8 __all__
= ["Message","choose_boundary","encode","decode","copyliteral",
11 class Message(rfc822
.Message
):
12 """A derived class of rfc822.Message that knows about MIME headers and
13 contains some hooks for decoding encoded and multipart messages."""
15 def __init__(self
, fp
, seekable
= 1):
16 rfc822
.Message
.__init
__(self
, fp
, seekable
)
17 self
.encodingheader
= \
18 self
.getheader('content-transfer-encoding')
20 self
.getheader('content-type')
30 self
.plisttext
= str[i
:]
34 fields
= str.split('/')
35 for i
in range(len(fields
)):
36 fields
[i
] = fields
[i
].strip().lower()
37 self
.type = '/'.join(fields
)
38 self
.maintype
= fields
[0]
39 self
.subtype
= '/'.join(fields
[1:])
47 # XXX Should parse quotes!
54 f
= f
[:i
].strip().lower() + \
56 self
.plist
.append(f
.strip())
62 def getparam(self
, name
):
63 name
= name
.lower() + '='
67 return rfc822
.unquote(p
[n
:])
70 def getparamnames(self
):
75 result
.append(p
[:i
].lower())
78 def getencoding(self
):
79 if self
.encodingheader
is None:
81 return self
.encodingheader
.lower()
86 def getmaintype(self
):
101 import dummy_thread
as thread
102 _counter_lock
= thread
.allocate_lock()
106 def _get_next_counter():
108 _counter_lock
.acquire()
111 _counter_lock
.release()
116 def choose_boundary():
117 """Return a string usable as a multipart boundary.
119 The string chosen is unique within a single program run, and
120 incorporates the user id (if available), process id (if available),
121 and current time. So it's very unlikely the returned string appears
122 in message text, but there's no guarantee.
124 The boundary contains dots so you have to quote it in the header."""
130 hostid
= socket
.gethostbyname(socket
.gethostname())
133 except AttributeError:
137 except AttributeError:
139 _prefix
= hostid
+ '.' + uid
+ '.' + pid
140 return "%s.%.3f.%d" % (_prefix
, time
.time(), _get_next_counter())
143 # Subroutines for decoding some common content-transfer-types
145 def decode(input, output
, encoding
):
146 """Decode common content-transfer-encodings (base64, quopri, uuencode)."""
147 if encoding
== 'base64':
149 return base64
.decode(input, output
)
150 if encoding
== 'quoted-printable':
152 return quopri
.decode(input, output
)
153 if encoding
in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
155 return uu
.decode(input, output
)
156 if encoding
in ('7bit', '8bit'):
157 return output
.write(input.read())
158 if encoding
in decodetab
:
159 pipethrough(input, decodetab
[encoding
], output
)
162 'unknown Content-Transfer-Encoding: %s' % encoding
164 def encode(input, output
, encoding
):
165 """Encode common content-transfer-encodings (base64, quopri, uuencode)."""
166 if encoding
== 'base64':
168 return base64
.encode(input, output
)
169 if encoding
== 'quoted-printable':
171 return quopri
.encode(input, output
, 0)
172 if encoding
in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
174 return uu
.encode(input, output
)
175 if encoding
in ('7bit', '8bit'):
176 return output
.write(input.read())
177 if encoding
in encodetab
:
178 pipethrough(input, encodetab
[encoding
], output
)
181 'unknown Content-Transfer-Encoding: %s' % encoding
183 # The following is no longer used for standard encodings
185 # XXX This requires that uudecode and mmencode are in $PATH
189 sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
195 'uuencode': uudecode_pipe
,
196 'x-uuencode': uudecode_pipe
,
197 'uue': uudecode_pipe
,
198 'x-uue': uudecode_pipe
,
199 'quoted-printable': 'mmencode -u -q',
200 'base64': 'mmencode -u -b',
204 'x-uuencode': 'uuencode tempfile',
205 'uuencode': 'uuencode tempfile',
206 'x-uue': 'uuencode tempfile',
207 'uue': 'uuencode tempfile',
208 'quoted-printable': 'mmencode -q',
209 'base64': 'mmencode -b',
212 def pipeto(input, command
):
213 pipe
= os
.popen(command
, 'w')
214 copyliteral(input, pipe
)
217 def pipethrough(input, command
, output
):
218 (fd
, tempname
) = tempfile
.mkstemp()
219 temp
= os
.fdopen(fd
, 'w')
220 copyliteral(input, temp
)
222 pipe
= os
.popen(command
+ ' <' + tempname
, 'r')
223 copybinary(pipe
, output
)
227 def copyliteral(input, output
):
229 line
= input.readline()
233 def copybinary(input, output
):
236 line
= input.read(BUFSIZE
)