# A class that makes each part of a multipart message "feel" like an # ordinary file, as long as you use fp.readline(). Allows recursive # use, for nested multipart messages. Probably best used together # with module mimetools. # # Suggested use: # # real_fp = open(...) # fp = MultiFile(real_fp) # # "read some lines from fp" # fp.push(separator) # while 1: # "read lines from fp until it returns an empty string" (A) # if not fp.next(): break # fp.pop() # "read remaining lines from fp until it returns an empty string" # # The latter sequence may be used recursively at (A). # It is also allowed to use multiple push()...pop() sequences. # Note that if a nested multipart message is terminated by a separator # for an outer message, this is not reported, even though it is really # illegal input. import sys import string err = sys.stderr.write Error = 'multifile.Error' class MultiFile: # def __init__(self, fp): self.fp = fp self.stack = [] # Grows down self.level = 0 self.last = 0 self.start = self.fp.tell() self.posstack = [] # Grows down # def tell(self): if self.level > 0: return self.lastpos return self.fp.tell() - self.start # def seek(self, pos): if not 0 <= pos <= self.tell() or \ self.level > 0 and pos > self.lastpos: raise Error, 'bad MultiFile.seek() call' self.fp.seek(pos + self.start) self.level = 0 self.last = 0 # def readline(self): if self.level > 0: return '' line = self.fp.readline() if not line: self.level = len(self.stack) self.last = (self.level > 0) if self.last: err('*** Sudden EOF in MultiFile.readline()\n') return '' if line[:2] <> '--': return line n = len(line) k = n while k > 0 and line[k-1] in string.whitespace: k = k-1 mark = line[2:k] if mark[-2:] == '--': mark1 = mark[:-2] else: mark1 = None for i in range(len(self.stack)): sep = self.stack[i] if sep == mark: self.last = 0 break elif mark1 <> None and sep == mark1: self.last = 1 break else: return line # Get here after break out of loop self.lastpos = self.tell() - len(line) self.level = i+1 if self.level > 1: err('*** Missing endmarker in MultiFile.readline()\n') return '' # def readlines(self): list = [] while 1: line = self.readline() if not line: break list.append(line) return list # def read(self): # Note: no size argument -- read until EOF only! return string.joinfields(self.readlines(), '') # def next(self): while self.readline(): pass if self.level > 1 or self.last: return 0 self.level = 0 self.last = 0 self.start = self.fp.tell() return 1 # def push(self, sep): if self.level > 0: raise Error, 'bad MultiFile.push() call' self.stack.insert(0, sep) self.posstack.insert(0, self.start) self.start = self.fp.tell() # def pop(self): if self.stack == []: raise Error, 'bad MultiFile.pop() call' if self.level <= 1: self.last = 0 else: abslastpos = self.lastpos + self.start self.level = max(0, self.level - 1) del self.stack[0] self.start = self.posstack[0] del self.posstack[0] if self.level > 0: self.lastpos = abslastpos - self.start #