#!/usr/local/bin/python ############################################################################# # mail-tool, version 3 # adds: MMDH format (startMessage():'\1\1\1\1\n') # adds: header-line continuations (first = whitespace) # # note: '-x' here forces internal-output, and a return value # in stop(). This is an alternative to subclassing with a # 'mixin' class that provides internal output (see app.py) ############################################################################# import string from PP2E.System.App.apptools import App, appCall [BODY, HEADER] = range(2) class MtoolApp(App): mpath = '/usr/spool/mail/' marker = 'MtoolApp' + ('#' * 64) + 'MtoolApp\n' def help(self): App.help(self) for arg in [ '-f ', '-t ', '-c ', '-s ', '-x (function mode: overrides -o)', '-a (and mode: default=or)']: print arg def internalOutput(self): self.output = Output() self.output_name = '' def start(self): if not self.args: self.help() self.exit() else: self.selects = [ ('From ', self.getarg('-f')), ('To: ', self.getarg('-t')), ('Cc: ', self.getarg('-c')), ('Subject: ', self.getarg('-s')) ] self.andMode = self.getopt('-a') self.funcMode = self.getopt('-x') self.setInput(self.mpath + self.getenv('USER')) # or -i if self.funcMode: self.internalOutput() else: self.setOutput('mtool.out') # or -o self.endargs() self.context = BODY self.peek = '' def eliminates(self, line): if self.andMode: for (start, patt) in self.selects: if (patt and line[:len(start)] == start and string.find(line, patt, len(start)) < 0): # regex.search return 1 # patt !found # or ret None def qualifies(self, line): if not self.andMode: for (start, patt) in self.selects: if (patt and line[:len(start)] == start and string.find(line, patt, len(start)) >= 0): # regex.search return 1 # patt found def startHeader(self, line): # subclass hooks return line[:5] == 'From ' # unix mbox def stopHeader(self, line): return line == '\n' # unix mbox def contHeader(self, char): return char in [' ', '\t'] # unix mbox def nextline(self): # physical line line = self.peek if line != '\n': line = line + App.readline(self) # '' on eof self.peek = self.read(1) return line def readline(self): # logical line line = self.nextline() # or: sept class if self.context == BODY: if self.startHeader(line): self.context = HEADER else: if self.stopHeader(line): self.context = BODY if self.context == HEADER: while self.contHeader(self.peek): line = line + self.nextline() return line def run(self): line = self.readline() while line: if self.startHeader(line): prefix = [self.marker] match = self.andMode while line: if self.stopHeader(line): break if self.qualifies(line): match = 1 break if self.eliminates(line): match = 0 break prefix.append(line) line = self.readline() if match: self.writelines(prefix) while line: self.write(line) line = self.readline() if self.startHeader(line): break continue line = self.readline() def stop(self): if not self.funcMode: self.message('mtool finished: see "%s".' % self.output_name) else: return string.splitfields(self.output.text, self.marker)[1:] ############################################################################# # subclass for a different mbox format... ############################################################################# class MtoolMMDH(MtoolApp): def startHeader(self, line): return line[:5] == '\1\1\1\1\n' ############################################################################# # run from another program (gui...) ############################################################################# def mtoolCall(Mfile, From, To, Cc='', Subj='', And=1, Mtype=MtoolApp): cmdargs = [ ('-i', Mfile), ('-f', From ), ('-t', To ), ('-c', Cc ), ('-s', Subj )] cmdopts = [('-a', And)] args = ['-x'] # function mode for (opt, arg) in cmdargs: if arg: args.append((opt, arg)) for (opt, arg) in cmdopts: if arg: args.append(opt) return appCall(Mtype, args) # internal output def mtoolViewer(*args): msgs = apply(mtoolCall, args) for msg in msgs: print msg; t = raw_input() # pause between each ############################################################################# # run mtool as a script ############################################################################# if __name__ == '__main__': MtoolApp().main()