(py-indent-right, py-outdent-left): new commands, bound to C-c C-r and
[python/dscho.git] / Lib / mimetools.py
blob2844fa4871f40e192fa2166a8164ac22a0c9c6e6
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):
16 rfc822.Message.__init__(self, fp)
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))
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 getencoding(self):
70 if self.encodingheader == None:
71 return '7bit'
72 return string.lower(self.encodingheader)
74 def gettype(self):
75 return self.type
77 def getmaintype(self):
78 return self.maintype
80 def getsubtype(self):
81 return self.subtype
86 # Utility functions
87 # -----------------
90 # Return a random string usable as a multipart boundary.
91 # The method used is so that it is *very* unlikely that the same
92 # string of characters will every occur again in the Universe,
93 # so the caller needn't check the data it is packing for the
94 # occurrence of the boundary.
96 # The boundary contains dots so you have to quote it in the header.
98 _prefix = None
100 def choose_boundary():
101 global _generation, _prefix, _timestamp
102 import time
103 import rand
104 if _prefix == None:
105 import socket
106 import os
107 hostid = socket.gethostbyname(socket.gethostname())
108 uid = `os.getuid()`
109 pid = `os.getpid()`
110 seed = `rand.rand()`
111 _prefix = hostid + '.' + uid + '.' + pid
112 timestamp = `int(time.time())`
113 seed = `rand.rand()`
114 return _prefix + '.' + timestamp + '.' + seed
117 # Subroutines for decoding some common content-transfer-types
119 # XXX This requires that uudecode and mmencode are in $PATH
121 def decode(input, output, encoding):
122 if decodetab.has_key(encoding):
123 pipethrough(input, decodetab[encoding], output)
124 else:
125 raise ValueError, \
126 'unknown Content-Transfer-Encoding: %s' % encoding
128 def encode(input, output, encoding):
129 if encodetab.has_key(encoding):
130 pipethrough(input, encodetab[encoding], output)
131 else:
132 raise ValueError, \
133 'unknown Content-Transfer-Encoding: %s' % encoding
135 uudecode_pipe = '''(
136 TEMP=/tmp/@uu.$$
137 sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
138 cat $TEMP
139 rm $TEMP
140 )'''
142 decodetab = {
143 'uuencode': uudecode_pipe,
144 'x-uuencode': uudecode_pipe,
145 'quoted-printable': 'mmencode -u -q',
146 'base64': 'mmencode -u -b',
149 encodetab = {
150 'x-uuencode': 'uuencode tempfile',
151 'uuencode': 'uuencode tempfile',
152 'quoted-printable': 'mmencode -q',
153 'base64': 'mmencode -b',
156 def pipeto(input, command):
157 pipe = os.popen(command, 'w')
158 copyliteral(input, pipe)
159 pipe.close()
161 def pipethrough(input, command, output):
162 tempname = tempfile.mktemp()
163 try:
164 temp = open(tempname, 'w')
165 except IOError:
166 print '*** Cannot create temp file', `tempname`
167 return
168 copyliteral(input, temp)
169 temp.close()
170 pipe = os.popen(command + ' <' + tempname, 'r')
171 copybinary(pipe, output)
172 pipe.close()
173 os.unlink(tempname)
175 def copyliteral(input, output):
176 while 1:
177 line = input.readline()
178 if not line: break
179 output.write(line)
181 def copybinary(input, output):
182 BUFSIZE = 8192
183 while 1:
184 line = input.read(BUFSIZE)
185 if not line: break
186 output.write(line)