Bump version to 1.0.
[python/dscho.git] / Lib / dos-8x3 / mimetool.py
blob27996e04cb4b3766e74591bcd3f58d22040ca2b1
1 """Various tools used by MIME-reading or MIME-writing programs."""
4 import os
5 import rfc822
6 import string
7 import tempfile
10 class Message(rfc822.Message):
11 """A derived class of rfc822.Message that knows about MIME headers and
12 contains some hooks for decoding encoded and multipart messages."""
14 def __init__(self, fp, seekable = 1):
15 rfc822.Message.__init__(self, fp, seekable)
16 self.encodingheader = \
17 self.getheader('content-transfer-encoding')
18 self.typeheader = \
19 self.getheader('content-type')
20 self.parsetype()
21 self.parseplist()
23 def parsetype(self):
24 str = self.typeheader
25 if str == None:
26 str = 'text/plain'
27 if ';' in str:
28 i = string.index(str, ';')
29 self.plisttext = str[i:]
30 str = str[:i]
31 else:
32 self.plisttext = ''
33 fields = string.splitfields(str, '/')
34 for i in range(len(fields)):
35 fields[i] = string.lower(string.strip(fields[i]))
36 self.type = string.joinfields(fields, '/')
37 self.maintype = fields[0]
38 self.subtype = string.joinfields(fields[1:], '/')
40 def parseplist(self):
41 str = self.plisttext
42 self.plist = []
43 while str[:1] == ';':
44 str = str[1:]
45 if ';' in str:
46 # XXX Should parse quotes!
47 end = string.index(str, ';')
48 else:
49 end = len(str)
50 f = str[:end]
51 if '=' in f:
52 i = string.index(f, '=')
53 f = string.lower(string.strip(f[:i])) + \
54 '=' + string.strip(f[i+1:])
55 self.plist.append(string.strip(f))
56 str = str[end:]
58 def getplist(self):
59 return self.plist
61 def getparam(self, name):
62 name = string.lower(name) + '='
63 n = len(name)
64 for p in self.plist:
65 if p[:n] == name:
66 return rfc822.unquote(p[n:])
67 return None
69 def getparamnames(self):
70 result = []
71 for p in self.plist:
72 i = string.find(p, '=')
73 if i >= 0:
74 result.append(string.lower(p[:i]))
75 return result
77 def getencoding(self):
78 if self.encodingheader == None:
79 return '7bit'
80 return string.lower(self.encodingheader)
82 def gettype(self):
83 return self.type
85 def getmaintype(self):
86 return self.maintype
88 def getsubtype(self):
89 return self.subtype
94 # Utility functions
95 # -----------------
98 _prefix = None
100 def choose_boundary():
101 """Return a random string usable as a multipart boundary.
102 The method used is so that it is *very* unlikely that the same
103 string of characters will every occur again in the Universe,
104 so the caller needn't check the data it is packing for the
105 occurrence of the boundary.
107 The boundary contains dots so you have to quote it in the header."""
109 global _prefix
110 import time
111 import random
112 if _prefix == None:
113 import socket
114 import os
115 hostid = socket.gethostbyname(socket.gethostname())
116 try:
117 uid = `os.getuid()`
118 except:
119 uid = '1'
120 try:
121 pid = `os.getpid()`
122 except:
123 pid = '1'
124 _prefix = hostid + '.' + uid + '.' + pid
125 timestamp = '%.3f' % time.time()
126 seed = `random.randint(0, 32767)`
127 return _prefix + '.' + timestamp + '.' + seed
130 # Subroutines for decoding some common content-transfer-types
132 def decode(input, output, encoding):
133 """Decode common content-transfer-encodings (base64, quopri, uuencode)."""
134 if encoding == 'base64':
135 import base64
136 return base64.decode(input, output)
137 if encoding == 'quoted-printable':
138 import quopri
139 return quopri.decode(input, output)
140 if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
141 import uu
142 return uu.decode(input, output)
143 if encoding in ('7bit', '8bit'):
144 output.write(input.read())
145 if decodetab.has_key(encoding):
146 pipethrough(input, decodetab[encoding], output)
147 else:
148 raise ValueError, \
149 'unknown Content-Transfer-Encoding: %s' % encoding
151 def encode(input, output, encoding):
152 """Encode common content-transfer-encodings (base64, quopri, uuencode)."""
153 if encoding == 'base64':
154 import base64
155 return base64.encode(input, output)
156 if encoding == 'quoted-printable':
157 import quopri
158 return quopri.encode(input, output, 0)
159 if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
160 import uu
161 return uu.encode(input, output)
162 if encoding in ('7bit', '8bit'):
163 output.write(input.read())
164 if encodetab.has_key(encoding):
165 pipethrough(input, encodetab[encoding], output)
166 else:
167 raise ValueError, \
168 'unknown Content-Transfer-Encoding: %s' % encoding
170 # The following is no longer used for standard encodings
172 # XXX This requires that uudecode and mmencode are in $PATH
174 uudecode_pipe = '''(
175 TEMP=/tmp/@uu.$$
176 sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
177 cat $TEMP
178 rm $TEMP
179 )'''
181 decodetab = {
182 'uuencode': uudecode_pipe,
183 'x-uuencode': uudecode_pipe,
184 'uue': uudecode_pipe,
185 'x-uue': uudecode_pipe,
186 'quoted-printable': 'mmencode -u -q',
187 'base64': 'mmencode -u -b',
190 encodetab = {
191 'x-uuencode': 'uuencode tempfile',
192 'uuencode': 'uuencode tempfile',
193 'x-uue': 'uuencode tempfile',
194 'uue': 'uuencode tempfile',
195 'quoted-printable': 'mmencode -q',
196 'base64': 'mmencode -b',
199 def pipeto(input, command):
200 pipe = os.popen(command, 'w')
201 copyliteral(input, pipe)
202 pipe.close()
204 def pipethrough(input, command, output):
205 tempname = tempfile.mktemp()
206 try:
207 temp = open(tempname, 'w')
208 except IOError:
209 print '*** Cannot create temp file', `tempname`
210 return
211 copyliteral(input, temp)
212 temp.close()
213 pipe = os.popen(command + ' <' + tempname, 'r')
214 copybinary(pipe, output)
215 pipe.close()
216 os.unlink(tempname)
218 def copyliteral(input, output):
219 while 1:
220 line = input.readline()
221 if not line: break
222 output.write(line)
224 def copybinary(input, output):
225 BUFSIZE = 8192
226 while 1:
227 line = input.read(BUFSIZE)
228 if not line: break
229 output.write(line)