| # Mailcap file handling.  See RFC 1524. | 
 |  | 
 | import os | 
 | 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] | 
 | 	    else: | 
 | 		caps[key] = caps[key] + morecaps[key] | 
 |     return caps | 
 |  | 
 | def listmailcapfiles(): | 
 |     # XXX Actually, this is Unix-specific | 
 |     if os.environ.has_key('MAILCAPS'): | 
 | 	str = os.environ['MAILCAPS'] | 
 | 	mailcaps = string.splitfields(str, ':') | 
 |     else: | 
 | 	if os.environ.has_key('HOME'): | 
 | 	    home = os.environ['HOME'] | 
 | 	else: | 
 | 	    # Don't bother with getpwuid() | 
 | 	    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 | 
 | 	key, fields = parseline(line) | 
 | 	if not (key and fields): | 
 | 	    cotinue | 
 | 	# 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): | 
 | 	    caps[key].append(fields) | 
 | 	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 | 
 |     if len(fields) < 2: | 
 | 	return None, None | 
 |     key, view, rest = fields[0], fields[1], fields[2:] | 
 |     fields = {'view': view} | 
 |     for field in rest: | 
 | 	i = string.find(field, '=') | 
 | 	if i < 0: | 
 | 	    fkey = field | 
 | 	    fvalue = "" | 
 | 	else: | 
 | 	    fkey = string.strip(field[:i]) | 
 | 	    fvalue = string.strip(field[i+1:]) | 
 | 	if fields.has_key(fkey): | 
 | 	    # Ignore it | 
 | 	    pass | 
 | 	else: | 
 | 	    fields[fkey] = fvalue | 
 |     return key, 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 findmatch(caps, type, key='view', filename="/dev/null", plist=[]): | 
 |     entries = lookup(caps, type, key) | 
 |     for e in entries: | 
 | 	if e.has_key('test'): | 
 | 	    test = subst(e['test'], filename, plist) | 
 | 	    if test and os.system(test) != 0: | 
 | 		continue | 
 | 	command = subst(e[key], type, filename, plist) | 
 | 	return command, e | 
 |     return None, None | 
 |  | 
 | def lookup(caps, type, key=None): | 
 |     entries = [] | 
 |     if caps.has_key(type): | 
 | 	entries = entries + caps[type] | 
 |     types = string.splitfields(type, '/') | 
 |     type = types[0] + '/*' | 
 |     if caps.has_key(type): | 
 | 	entries = entries + caps[type] | 
 |     if key is not None: | 
 | 	entries = filter(lambda e, key=key: e.has_key(key), entries) | 
 |     return entries | 
 |  | 
 | def subst(field, type, filename, plist=[]): | 
 |     # XXX Actually, this is Unix-specific | 
 |     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': | 
 | 		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) | 
 | 	    # XXX To do: | 
 | 	    # %n == number of parts if type is multipart/* | 
 | 	    # %F == list of alternating type and filename for parts | 
 | 	    else: | 
 | 		res = res + '%' + c | 
 |     return 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 '' | 
 |  | 
 |  | 
 | # Part 4: test program. | 
 |  | 
 | def test(): | 
 |     import sys | 
 |     caps = getcaps() | 
 |     if not sys.argv[1:]: | 
 | 	show(caps) | 
 | 	return | 
 |     for i in range(1, len(sys.argv), 2): | 
 | 	args = sys.argv[i:i+2] | 
 | 	if len(args) < 2: | 
 | 	    print "usage: mailcap [type file] ..." | 
 | 	    return | 
 | 	type = args[0] | 
 | 	file = args[1] | 
 | 	command, e = findmatch(caps, type, 'view', file) | 
 | 	if not command: | 
 | 	    print "No viewer found for", type | 
 | 	else: | 
 | 	    print "Executing:", command | 
 | 	    sts = os.system(command) | 
 | 	    if sts: | 
 | 		print "Exit status:", sts | 
 |  | 
 | def show(caps): | 
 |     print "Mailcap files:" | 
 |     for fn in listmailcapfiles(): print "\t" + fn | 
 |     print | 
 |     if not caps: caps = getcaps() | 
 |     print "Mailcap entries:" | 
 |     print | 
 |     ckeys = caps.keys() | 
 |     ckeys.sort() | 
 |     for type in ckeys: | 
 | 	print type | 
 | 	entries = caps[type] | 
 | 	for e in entries: | 
 | 	    keys = e.keys() | 
 | 	    keys.sort() | 
 | 	    for k in keys: | 
 | 		print "  %-15s" % k, e[k] | 
 | 	    print | 
 |  | 
 | if __name__ == '__main__': | 
 |     test() |