Fix an amazing number of typos & malformed sentences reported by Detlef
[python/dscho.git] / Lib / dos-8x3 / mimetool.py
blobfc72c79ed3acef3e19704220b8a9b64730fd1133
1 # Various tools used by MIME-reading or MIME-writing programs.
4 import os
5 import rfc822
6 import string
7 import tempfile
10 # A derived class of rfc822.Message that knows about MIME headers and
11 # contains some hooks for decoding encoded and multipart messages.
13 class Message(rfc822.Message):
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()
24 def parsetype(self):
25 str = self.typeheader
26 if str == None:
27 str = 'text/plain'
28 if ';' in str:
29 i = string.index(str, ';')
30 self.plisttext = str[i:]
31 str = str[:i]
32 else:
33 self.plisttext = ''
34 fields = string.splitfields(str, '/')
35 for i in range(len(fields)):
36 fields[i] = string.lower(string.strip(fields[i]))
37 self.type = string.joinfields(fields, '/')
38 self.maintype = fields[0]
39 self.subtype = string.joinfields(fields[1:], '/')
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 = string.index(str, ';')
49 else:
50 end = len(str)
51 f = str[:end]
52 if '=' in f:
53 i = string.index(f, '=')
54 f = string.lower(string.strip(f[:i])) + \
55 '=' + string.strip(f[i+1:])
56 self.plist.append(string.strip(f))
57 str = str[end:]
59 def getplist(self):
60 return self.plist
62 def getparam(self, name):
63 name = string.lower(name) + '='
64 n = len(name)
65 for p in self.plist:
66 if p[:n] == name:
67 return rfc822.unquote(p[n:])
68 return None
70 def getparamnames(self):
71 result = []
72 for p in self.plist:
73 i = string.find(p, '=')
74 if i >= 0:
75 result.append(string.lower(p[:i]))
76 return result
78 def getencoding(self):
79 if self.encodingheader == None:
80 return '7bit'
81 return string.lower(self.encodingheader)
83 def gettype(self):
84 return self.type
86 def getmaintype(self):
87 return self.maintype
89 def getsubtype(self):
90 return self.subtype
95 # Utility functions
96 # -----------------
99 # Return a random string usable as a multipart boundary.
100 # The method used is so that it is *very* unlikely that the same
101 # string of characters will every occur again in the Universe,
102 # so the caller needn't check the data it is packing for the
103 # occurrence of the boundary.
105 # The boundary contains dots so you have to quote it in the header.
107 _prefix = None
109 def choose_boundary():
110 global _prefix
111 import time
112 import random
113 if _prefix == None:
114 import socket
115 import os
116 hostid = socket.gethostbyname(socket.gethostname())
117 try:
118 uid = `os.getuid()`
119 except:
120 uid = '1'
121 try:
122 pid = `os.getpid()`
123 except:
124 pid = '1'
125 _prefix = hostid + '.' + uid + '.' + pid
126 timestamp = '%.3f' % time.time()
127 seed = `random.randint(0, 32767)`
128 return _prefix + '.' + timestamp + '.' + seed
131 # Subroutines for decoding some common content-transfer-types
133 def decode(input, output, encoding):
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 decodetab.has_key(encoding):
144 pipethrough(input, decodetab[encoding], output)
145 else:
146 raise ValueError, \
147 'unknown Content-Transfer-Encoding: %s' % encoding
149 def encode(input, output, encoding):
150 if encoding == 'base64':
151 import base64
152 return base64.encode(input, output)
153 if encoding == 'quoted-printable':
154 import quopri
155 return quopri.encode(input, output, 0)
156 if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
157 import uu
158 return uu.encode(input, output)
159 if encodetab.has_key(encoding):
160 pipethrough(input, encodetab[encoding], output)
161 else:
162 raise ValueError, \
163 'unknown Content-Transfer-Encoding: %s' % encoding
165 # The following is no longer used for standard encodings
167 # XXX This requires that uudecode and mmencode are in $PATH
169 uudecode_pipe = '''(
170 TEMP=/tmp/@uu.$$
171 sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
172 cat $TEMP
173 rm $TEMP
174 )'''
176 decodetab = {
177 'uuencode': uudecode_pipe,
178 'x-uuencode': uudecode_pipe,
179 'uue': uudecode_pipe,
180 'x-uue': uudecode_pipe,
181 'quoted-printable': 'mmencode -u -q',
182 'base64': 'mmencode -u -b',
185 encodetab = {
186 'x-uuencode': 'uuencode tempfile',
187 'uuencode': 'uuencode tempfile',
188 'x-uue': 'uuencode tempfile',
189 'uue': 'uuencode tempfile',
190 'quoted-printable': 'mmencode -q',
191 'base64': 'mmencode -b',
194 def pipeto(input, command):
195 pipe = os.popen(command, 'w')
196 copyliteral(input, pipe)
197 pipe.close()
199 def pipethrough(input, command, output):
200 tempname = tempfile.mktemp()
201 try:
202 temp = open(tempname, 'w')
203 except IOError:
204 print '*** Cannot create temp file', `tempname`
205 return
206 copyliteral(input, temp)
207 temp.close()
208 pipe = os.popen(command + ' <' + tempname, 'r')
209 copybinary(pipe, output)
210 pipe.close()
211 os.unlink(tempname)
213 def copyliteral(input, output):
214 while 1:
215 line = input.readline()
216 if not line: break
217 output.write(line)
219 def copybinary(input, output):
220 BUFSIZE = 8192
221 while 1:
222 line = input.read(BUFSIZE)
223 if not line: break
224 output.write(line)