source: trunk/essentials/dev-lang/python/Lib/mimetools.py

Last change on this file was 3225, checked in by bird, 18 years ago

Python 2.5

File size: 6.7 KB
Line 
1"""Various tools used by MIME-reading or MIME-writing programs."""
2
3
4import os
5import rfc822
6import tempfile
7
8__all__ = ["Message","choose_boundary","encode","decode","copyliteral",
9 "copybinary"]
10
11class 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."""
14
15 def __init__(self, fp, seekable = 1):
16 rfc822.Message.__init__(self, fp, seekable)
17 self.encodingheader = \
18 self.getheader('content-transfer-encoding')
19 self.typeheader = \
20 self.getheader('content-type')
21 self.parsetype()
22 self.parseplist()
23
24 def parsetype(self):
25 str = self.typeheader
26 if str is None:
27 str = 'text/plain'
28 if ';' in str:
29 i = str.index(';')
30 self.plisttext = str[i:]
31 str = str[:i]
32 else:
33 self.plisttext = ''
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:])
40
41 def parseplist(self):
42 str = self.plisttext
43 self.plist = []
44 while str[:1] == ';':
45 str = str[1:]
46 if ';' in str:
47 # XXX Should parse quotes!
48 end = str.index(';')
49 else:
50 end = len(str)
51 f = str[:end]
52 if '=' in f:
53 i = f.index('=')
54 f = f[:i].strip().lower() + \
55 '=' + f[i+1:].strip()
56 self.plist.append(f.strip())
57 str = str[end:]
58
59 def getplist(self):
60 return self.plist
61
62 def getparam(self, name):
63 name = name.lower() + '='
64 n = len(name)
65 for p in self.plist:
66 if p[:n] == name:
67 return rfc822.unquote(p[n:])
68 return None
69
70 def getparamnames(self):
71 result = []
72 for p in self.plist:
73 i = p.find('=')
74 if i >= 0:
75 result.append(p[:i].lower())
76 return result
77
78 def getencoding(self):
79 if self.encodingheader is None:
80 return '7bit'
81 return self.encodingheader.lower()
82
83 def gettype(self):
84 return self.type
85
86 def getmaintype(self):
87 return self.maintype
88
89 def getsubtype(self):
90 return self.subtype
91
92
93
94
95# Utility functions
96# -----------------
97
98try:
99 import thread
100except ImportError:
101 import dummy_thread as thread
102_counter_lock = thread.allocate_lock()
103del thread
104
105_counter = 0
106def _get_next_counter():
107 global _counter
108 _counter_lock.acquire()
109 _counter += 1
110 result = _counter
111 _counter_lock.release()
112 return result
113
114_prefix = None
115
116def choose_boundary():
117 """Return a string usable as a multipart boundary.
118
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.
123
124 The boundary contains dots so you have to quote it in the header."""
125
126 global _prefix
127 import time
128 if _prefix is None:
129 import socket
130 try:
131 hostid = socket.gethostbyname(socket.gethostname())
132 except socket.gaierror:
133 hostid = '127.0.0.1'
134 try:
135 uid = repr(os.getuid())
136 except AttributeError:
137 uid = '1'
138 try:
139 pid = repr(os.getpid())
140 except AttributeError:
141 pid = '1'
142 _prefix = hostid + '.' + uid + '.' + pid
143 return "%s.%.3f.%d" % (_prefix, time.time(), _get_next_counter())
144
145
146# Subroutines for decoding some common content-transfer-types
147
148def decode(input, output, encoding):
149 """Decode common content-transfer-encodings (base64, quopri, uuencode)."""
150 if encoding == 'base64':
151 import base64
152 return base64.decode(input, output)
153 if encoding == 'quoted-printable':
154 import quopri
155 return quopri.decode(input, output)
156 if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
157 import uu
158 return uu.decode(input, output)
159 if encoding in ('7bit', '8bit'):
160 return output.write(input.read())
161 if encoding in decodetab:
162 pipethrough(input, decodetab[encoding], output)
163 else:
164 raise ValueError, \
165 'unknown Content-Transfer-Encoding: %s' % encoding
166
167def encode(input, output, encoding):
168 """Encode common content-transfer-encodings (base64, quopri, uuencode)."""
169 if encoding == 'base64':
170 import base64
171 return base64.encode(input, output)
172 if encoding == 'quoted-printable':
173 import quopri
174 return quopri.encode(input, output, 0)
175 if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
176 import uu
177 return uu.encode(input, output)
178 if encoding in ('7bit', '8bit'):
179 return output.write(input.read())
180 if encoding in encodetab:
181 pipethrough(input, encodetab[encoding], output)
182 else:
183 raise ValueError, \
184 'unknown Content-Transfer-Encoding: %s' % encoding
185
186# The following is no longer used for standard encodings
187
188# XXX This requires that uudecode and mmencode are in $PATH
189
190uudecode_pipe = '''(
191TEMP=/tmp/@uu.$$
192sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
193cat $TEMP
194rm $TEMP
195)'''
196
197decodetab = {
198 'uuencode': uudecode_pipe,
199 'x-uuencode': uudecode_pipe,
200 'uue': uudecode_pipe,
201 'x-uue': uudecode_pipe,
202 'quoted-printable': 'mmencode -u -q',
203 'base64': 'mmencode -u -b',
204}
205
206encodetab = {
207 'x-uuencode': 'uuencode tempfile',
208 'uuencode': 'uuencode tempfile',
209 'x-uue': 'uuencode tempfile',
210 'uue': 'uuencode tempfile',
211 'quoted-printable': 'mmencode -q',
212 'base64': 'mmencode -b',
213}
214
215def pipeto(input, command):
216 pipe = os.popen(command, 'w')
217 copyliteral(input, pipe)
218 pipe.close()
219
220def pipethrough(input, command, output):
221 (fd, tempname) = tempfile.mkstemp()
222 temp = os.fdopen(fd, 'w')
223 copyliteral(input, temp)
224 temp.close()
225 pipe = os.popen(command + ' <' + tempname, 'r')
226 copybinary(pipe, output)
227 pipe.close()
228 os.unlink(tempname)
229
230def copyliteral(input, output):
231 while 1:
232 line = input.readline()
233 if not line: break
234 output.write(line)
235
236def copybinary(input, output):
237 BUFSIZE = 8192
238 while 1:
239 line = input.read(BUFSIZE)
240 if not line: break
241 output.write(line)
Note: See TracBrowser for help on using the repository browser.