"""Mailcap file handling. See RFC 1524."""
__all__
= ["getcaps","findmatch"]
# Part 1: top-level interface.
"""Return a dictionary containing the mailcap database.
The dictionary maps a MIME type (in all lowercase, e.g. 'text/plain')
to a list of dictionaries corresponding to mailcap entries. The list
collects all the entries for that MIME type from all available mailcap
files. Each dictionary contains key-value pairs for that MIME type,
where the viewing command is stored with the key "view".
for mailcap
in listmailcapfiles():
morecaps
= readmailcapfile(fp
)
for key
, value
in morecaps
.iteritems():
caps
[key
] = caps
[key
] + value
"""Return a list of all mailcap files found on the system."""
# XXX Actually, this is Unix-specific
if 'MAILCAPS' in os
.environ
:
str = os
.environ
['MAILCAPS']
mailcaps
= str.split(':')
home
= os
.environ
['HOME']
# Don't bother with getpwuid()
mailcaps
= [home
+ '/.mailcap', '/etc/mailcap',
'/usr/etc/mailcap', '/usr/local/etc/mailcap']
"""Read a mailcap file and return a dictionary keyed by MIME type.
Each MIME type is mapped to an entry consisting of a list of
dictionaries; the list will contain more than one such dictionary
if a given MIME type appears more than once in the mailcap file.
Each dictionary contains key-value pairs for that MIME type, where
the viewing command is stored with the key "view".
# Ignore comments and blank lines
if line
[0] == '#' or line
.strip() == '':
# Join continuation lines
while nextline
[-2:] == '\\\n':
if not nextline
: nextline
= '\n'
line
= line
[:-2] + nextline
key
, fields
= parseline(line
)
for j
in range(len(types
)):
types
[j
] = types
[j
].strip()
key
= '/'.join(types
).lower()
"""Parse one entry in a mailcap file and return a dictionary.
The viewing command is stored as the value with the key "view",
and the rest of the fields produce key-value pairs in the dict.
field
, i
= parsefield(line
, i
, n
)
key
, view
, rest
= fields
[0], fields
[1], fields
[2:]
fvalue
= field
[i
+1:].strip()
def parsefield(line
, i
, n
):
"""Separate one key-value pair in a mailcap entry."""
return line
[start
:i
].strip(), i
# Part 3: using the database.
def findmatch(caps
, MIMEtype
, key
='view', filename
="/dev/null", plist
=[]):
"""Find a match for a mailcap entry.
Return a tuple containing the command line, and the mailcap entry
used; (None, None) if no match is found. This may invoke the
'test' command of several matching entries before deciding which
entries
= lookup(caps
, MIMEtype
, key
)
# XXX This code should somehow check for the needsterminal flag.
test
= subst(e
['test'], filename
, plist
)
if test
and os
.system(test
) != 0:
command
= subst(e
[key
], MIMEtype
, filename
, plist
)
def lookup(caps
, MIMEtype
, key
=None):
entries
= entries
+ caps
[MIMEtype
]
MIMEtypes
= MIMEtype
.split('/')
MIMEtype
= MIMEtypes
[0] + '/*'
entries
= entries
+ caps
[MIMEtype
]
entries
= filter(lambda e
, key
=key
: key
in e
, entries
)
def subst(field
, MIMEtype
, filename
, plist
=[]):
# XXX Actually, this is Unix-specific
c
= field
[i
:i
+1]; i
= i
+1
while i
< n
and field
[i
] != '}':
res
= res
+ findparam(name
, plist
)
# %n == number of parts if type is multipart/*
# %F == list of alternating type and filename for parts
def findparam(name
, plist
):
name
= name
.lower() + '='
if p
[:n
].lower() == name
:
for i
in range(1, len(sys
.argv
), 2):
print "usage: mailcap [MIMEtype file] ..."
command
, e
= findmatch(caps
, MIMEtype
, 'view', file)
print "No viewer found for", type
print "Executing:", command
print "Exit status:", sts
for fn
in listmailcapfiles(): print "\t" + fn
if not caps
: caps
= getcaps()
if __name__
== '__main__':