#! /usr/bin/python # -*- python -*- # # mzmail.py v1.1 # # Copyright (C) 2000 by Brian D. Winters # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # """Spawn a mail reader from muttzilla. I am not a very good with shell scripts, but understand python pretty well, so I use this program instead of the default shell script. It does most of the same things as the shell script, but IMO is cleaner and easier to read and maintain. When this program departs from the shell script version it is usually an improvement. """ ### Configuration options ### globalconfig = '/usr/local/etc/muttzilla.conf' ### Global variables which you can still configure here if you really, ### really want to, but should be handled in a configuration file. userconfig = '~/.muttzillarc' debug = 0 # Set some useful defaults. Settings in userconfig override # globalconfig override these constants. xterm = 'xterm' # set to None if mailer is X-capable title = 'muttzilla mail' # set to None if you don't want to pass -title name = 'muttzilla' # set to None if you don't want to pass -name # Choose your preferred mailer and the correct argument style for it. prog = 'mutt' argstyle = 'mutt' #argstyle = 'pine' #argstyle = 'dtmail' #argstyle = 'VM' ### end configuration section def errormsg(msg): import os.path, sys sys.stderr.write('%s: %s\n' % (os.path.basename(sys.argv[0]), msg)) def debugmsg(msg): if debug: errormsg(msg) def main(): import os, sys err = readconfig() if err: sys.exit(err) exec 'mailerf = %s' % argstyle args = apply(mailerf, sys.argv[1:]) cmd = [prog,] + args if xterm is not None: subcmd = [xterm,] if name is not None: subcmd = subcmd + ['-name', name] if title is not None: subcmd = subcmd + ['-title', title] cmd = subcmd + ['-e',] + cmd debugmsg('command line is: %s' % str(cmd)) os.execvp(cmd[0], cmd) ### parse configuration files ### def readconfig(): import os, re try: inf = open(globalconfig, 'r') except: pass else: debugmsg('processing %s' % globalconfig) res = parseconfig(inf, globalconfig) if res: return res infname = os.path.expandvars(os.path.expanduser(userconfig)) if re.compile(os.sep).search(infname) is None and \ (not os.altsep or re.compile(os.altsep).search(infname) is None): try: infname = os.environ['HOME'] + os.sep + infname except: pass try: inf = open(infname, 'r') except: pass else: debugmsg('processing %s' % infname) res = parseconfig(inf, infname) if res: return res return 0 def parseconfig(inf, fname): import shlex, string # format is parmname: (isvar, action) # elif isvar is 0: # action is a variable to set # if isvar is 1: # action is a function to call with one argument # else: # ignore it lang = {'tempdir': (2, None), 'debug': (0, 'debug'), 'reread': (2, None), 'userconfig':(0, 'userconfig'), 'mailscript':(2, None), 'mailprog': (0, 'prog'), 'mailargs': (0, 'argstyle'), 'mailterm': (0, 'xterm'), 'mailtitle': (0, 'title'), 'mailname': (0, 'name'), 'mailenv': (1, 'setenv'), 'newsscript':(2, None), 'newsprog': (2, None), 'newsargs': (2, None), 'newsterm': (2, None), 'newstitle': (2, None), 'newsname': (2, None), 'newsenv': (2, None)} cf = shlex.shlex(inf) cf.wordchars = cf.wordchars + r'/.\`~!@#%$%^&*()<>' langkeys = lang.keys() token = cf.get_token() while token != '': if token not in langkeys: errormsg('parse error in %s at line %u, unrecognized command "%s"'% (fname, cf.lineno, token)) return 1 cmd = token token = cf.get_token() if token != '=': errormsg('parse error in %s at line %u, expected "=" but got "%s"'% (fname, cf.lineno, token)) return 1 token = cf.get_token() if token == '': errormsg('parse error in %s at line %u, unexpected end of file ' 'while processing %s' % (fname, cf.lineno, cmd)) return 1 arg = token ll = lang[cmd] if ll[0] == 0: setval(ll[1], arg) elif ll[0] == 1: eval('%s(%s)' % (ll[1], arg)) debugmsg('calling %s(%s)' % (ll[1], arg)) token = cf.get_token() return 0 def setval(var, val): if val == 'None': exec 'global %s\n%s = None' % (var, var) debugmsg('setting %s to None' % var) else: try: num = string.atoi(val) except: exec 'global %s\n%s = val' % (var, var) debugmsg('setting %s to "%s"' % (var, eval(var))) else: exec 'global %s\n%s = num' % (var, var) debugmsg('setting %s to %i' % (var, eval(var))) def setenv(line): import os, re mo = re.compile(r'\s*(?P\w+)\s*=\s*(P?.*\S)\s*').match(line) if mo is not None: var = mo.group('var') val = mo.group('val') if val[0] == "'" and val[len(val)-1] == "'" or \ val[0] == '"' and val[len(val)-1] == '"': val = val[1:-1] os.environ[var] = val debugmsg('setting environ "%s"="%s"' % (var, val)) ### handle the differing argument styles of various mailers ### def mutt(to, cc, bcc, subject, bodyfile, org): args = [] # skip "to" initially, because it may depend on other variables normalargs = ((cc, '-c'), (bcc, '-b'), (subject, '-s'), (bodyfile, '-i')) # no facility for setting "org" from the command line, so ignore for now for i in normalargs: v, a = i if len(v) > 0: if a is not None: args.append(a) args.append(v) if len(to) > 0: args.append(to) return args def pine(to, cc, bcc, subject, bodyfile, org): """Based on the shell script by Erik Rossen """ import re args = [] if len(to) > 0: args.append(to) else: args.append('') # pine doesn't like not having a to option normalargs = ((subject, 'Subject'), (cc, 'Cc'), (bcc, 'Bcc'), (org, 'Organization')) hdrs = '' for i in normalargs: v, l = i if len(v) > 0: # pine does funny stuff if it encounters a ',' in the headers list # hdrs = '%s%s: %s, ' % (hdrs, l, re.sub(',', '_', v)) if len(hdr) > 0: args.append('-customized-hdrs=%s' % hdrs) if len(bodyfile) > 0: # This includes the body as an attachment instead of putting # it in the body. There is probably a better way to do this, # but it is good enough for now. args.append('-attach') args.append(bodyfile) return args def dtmail(to, cc, bcc, subject, bodyfile, org): args = [] normalargs = ((to, '-T'), (cc, '-c'), (bcc, '-b'), (subject, '-s'), (bodyfile, '-i')) # no facility for setting "org" from the command line, so ignore for now for i in normalargs: v, a = i if len(v) > 0: if a is not None: args.append(a) args.append(v) return args def VM(to, cc, bcc, subject, bodyfile, org): s = r'''(progn (defun mzmail-set-header (header value) (save-excursion (goto-char (point-min)) (let ((regexp (concat "^" header ": *")) (case-fold-search t)) (if (re-search-forward regexp nil t) (progn (end-of-line) (delete-region (match-end 0) (point)) (insert value) ) (progn (goto-char (point-min)) (re-search-forward "--text follows this line--" nil t) (goto-char (match-beginning 0)) (insert header ": " value "\n") ) ) ) ) ) (vm-mail "%s")''' % to if bodyfile: s = s + '\n (insert-file "%s")' % bodyfile if cc: s = s + '\n (mzmail-set-header "Cc" "%s")' % cc if bcc: s = s + '\n (mzmail-set-header "Bcc" "%s")' % bcc if subject: s = s + '\n (mzmail-set-header "Subject" "%s")' % subject if org: s = s + '\n (mzmail-set-header "Organization" "%s")' % org s = s + "\n )\n" return ["-batch", "-q", "-eval", s] if __name__ == '__main__': main()