Re: mailcap file reader

Guido.van.Rossum@cwi.nl
Thu, 13 Apr 1995 11:05:11 +0200

> I was wondering if anyone has a routine that reads a mailcap
> file (like a netscape mailcap file) and converts it to say
> a map from mailcap kinds to actions. For simple mailcap files
> this is trivial, but as the mailcap files get more complex ..

How about this (old, but it once worked)? I have more where this came
from (essentially a whole set of MIME tools)...

# Mailcap file handling as per N.Borenstein's "Configuration" memo
# of December 1991.
# XXX I haven't checked out if everything conforms to the latest version.

import posix
import string
import tempfile

# Part 1: top-level interface.

def getcaps():
caps = {}
for mailcap in listmailcapfiles():
try:
fp = open(mailcap, 'r')
except:
continue
morecaps = readmailcapfile(fp)
fp.close()
for key in morecaps.keys():
if not caps.has_key(key):
caps[key] = morecaps[key]
return caps

def listmailcapfiles():
if posix.environ.has_key('MAILCAPS'):
str = posix.environ['MAILCAPS']
mailcaps = string.splitfields(str, ':')
else:
if posix.environ.has_key('HOME'):
home = posix.environ['HOME']
else:
home = '.' # Last resort
mailcaps = [home + '/.mailcap', '/etc/mailcap', \
'/usr/etc/mailcap', '/usr/local/etc/mailcap']
return mailcaps

# Part 2: the parser.

def readmailcapfile(fp):
caps = {}
while 1:
line = fp.readline()
if not line: break
# Ignore comments and blank lines
if line[0] == '#' or string.strip(line) == '':
continue
nextline = line
# Join continuation lines
while nextline[-2:] == '\\\n':
nextline = fp.readline()
if not nextline: nextline = '\n'
line = line[:-2] + nextline
# Parse the line
fields = parseline(line)
key, fields = fields[0], fields[1:]
# Normalize the key
types = string.splitfields(key, '/')
for j in range(len(types)):
types[j] = string.strip(types[j])
key = string.lower(string.joinfields(types, '/'))
# Update the database
if caps.has_key(key):
print '*** Duplicate key', `key`, 'in mailcap'
else:
caps[key] = fields
return caps

def parseline(line):
fields = []
i, n = 0, len(line)
while i < n:
field, i = parsefield(line, i, n)
fields.append(field)
i = i+1 # Skip semicolon
return fields

def parsefield(line, i, n):
start = i
while i < n:
c = line[i]
if c == ';':
break
elif c == '\\':
i = i+2
else:
i = i+1
return string.strip(line[start:i]), i

# Part 3: using the database.

def lookup(caps, key):
if caps.has_key(key):
return caps[key]
types = string.splitfields(key, '/')
key = types[0] + '/*'
if caps.has_key(key):
return caps[key]
return None

def subst(field, type, plist):
filename = '|'
res = ''
i, n = 0, len(field)
while i < n:
c = field[i]; i = i+1
if c <> '%':
if c == '\\':
c = field[i:i+1]; i = i+1
res = res + c
else:
c = field[i]; i = i+1
if c == '%':
res = res + c
elif c == 's':
if filename == '|':
filename = tempfile.mktemp()
res = res + filename
elif c == 't':
res = res + type
elif c == '{':
start = i
while i < n and field[i] <> '}':
i = i+1
name = field[start:i]
i = i+1
res = res + findparam(name, plist)
else:
res = res + '%' + c
return filename, res

def findparam(name, plist):
name = string.lower(name) + '='
n = len(name)
for p in plist:
if string.lower(p[:n]) == name:
return p[n:]
return ''

--Guido van Rossum, CWI, Amsterdam <mailto:guido@cwi.nl>
<http://www.cwi.nl/~guido/>