PyXR

c:\python24\lib \ mailcap.py



0001 """Mailcap file handling.  See RFC 1524."""
0002 
0003 import os
0004 
0005 __all__ = ["getcaps","findmatch"]
0006 
0007 # Part 1: top-level interface.
0008 
0009 def getcaps():
0010     """Return a dictionary containing the mailcap database.
0011 
0012     The dictionary maps a MIME type (in all lowercase, e.g. 'text/plain')
0013     to a list of dictionaries corresponding to mailcap entries.  The list
0014     collects all the entries for that MIME type from all available mailcap
0015     files.  Each dictionary contains key-value pairs for that MIME type,
0016     where the viewing command is stored with the key "view".
0017 
0018     """
0019     caps = {}
0020     for mailcap in listmailcapfiles():
0021         try:
0022             fp = open(mailcap, 'r')
0023         except IOError:
0024             continue
0025         morecaps = readmailcapfile(fp)
0026         fp.close()
0027         for key, value in morecaps.iteritems():
0028             if not key in caps:
0029                 caps[key] = value
0030             else:
0031                 caps[key] = caps[key] + value
0032     return caps
0033 
0034 def listmailcapfiles():
0035     """Return a list of all mailcap files found on the system."""
0036     # XXX Actually, this is Unix-specific
0037     if 'MAILCAPS' in os.environ:
0038         str = os.environ['MAILCAPS']
0039         mailcaps = str.split(':')
0040     else:
0041         if 'HOME' in os.environ:
0042             home = os.environ['HOME']
0043         else:
0044             # Don't bother with getpwuid()
0045             home = '.' # Last resort
0046         mailcaps = [home + '/.mailcap', '/etc/mailcap',
0047                 '/usr/etc/mailcap', '/usr/local/etc/mailcap']
0048     return mailcaps
0049 
0050 
0051 # Part 2: the parser.
0052 
0053 def readmailcapfile(fp):
0054     """Read a mailcap file and return a dictionary keyed by MIME type.
0055 
0056     Each MIME type is mapped to an entry consisting of a list of
0057     dictionaries; the list will contain more than one such dictionary
0058     if a given MIME type appears more than once in the mailcap file.
0059     Each dictionary contains key-value pairs for that MIME type, where
0060     the viewing command is stored with the key "view".
0061     """
0062     caps = {}
0063     while 1:
0064         line = fp.readline()
0065         if not line: break
0066         # Ignore comments and blank lines
0067         if line[0] == '#' or line.strip() == '':
0068             continue
0069         nextline = line
0070         # Join continuation lines
0071         while nextline[-2:] == '\\\n':
0072             nextline = fp.readline()
0073             if not nextline: nextline = '\n'
0074             line = line[:-2] + nextline
0075         # Parse the line
0076         key, fields = parseline(line)
0077         if not (key and fields):
0078             continue
0079         # Normalize the key
0080         types = key.split('/')
0081         for j in range(len(types)):
0082             types[j] = types[j].strip()
0083         key = '/'.join(types).lower()
0084         # Update the database
0085         if key in caps:
0086             caps[key].append(fields)
0087         else:
0088             caps[key] = [fields]
0089     return caps
0090 
0091 def parseline(line):
0092     """Parse one entry in a mailcap file and return a dictionary.
0093 
0094     The viewing command is stored as the value with the key "view",
0095     and the rest of the fields produce key-value pairs in the dict.
0096     """
0097     fields = []
0098     i, n = 0, len(line)
0099     while i < n:
0100         field, i = parsefield(line, i, n)
0101         fields.append(field)
0102         i = i+1 # Skip semicolon
0103     if len(fields) < 2:
0104         return None, None
0105     key, view, rest = fields[0], fields[1], fields[2:]
0106     fields = {'view': view}
0107     for field in rest:
0108         i = field.find('=')
0109         if i < 0:
0110             fkey = field
0111             fvalue = ""
0112         else:
0113             fkey = field[:i].strip()
0114             fvalue = field[i+1:].strip()
0115         if fkey in fields:
0116             # Ignore it
0117             pass
0118         else:
0119             fields[fkey] = fvalue
0120     return key, fields
0121 
0122 def parsefield(line, i, n):
0123     """Separate one key-value pair in a mailcap entry."""
0124     start = i
0125     while i < n:
0126         c = line[i]
0127         if c == ';':
0128             break
0129         elif c == '\\':
0130             i = i+2
0131         else:
0132             i = i+1
0133     return line[start:i].strip(), i
0134 
0135 
0136 # Part 3: using the database.
0137 
0138 def findmatch(caps, MIMEtype, key='view', filename="/dev/null", plist=[]):
0139     """Find a match for a mailcap entry.
0140 
0141     Return a tuple containing the command line, and the mailcap entry
0142     used; (None, None) if no match is found.  This may invoke the
0143     'test' command of several matching entries before deciding which
0144     entry to use.
0145 
0146     """
0147     entries = lookup(caps, MIMEtype, key)
0148     # XXX This code should somehow check for the needsterminal flag.
0149     for e in entries:
0150         if 'test' in e:
0151             test = subst(e['test'], filename, plist)
0152             if test and os.system(test) != 0:
0153                 continue
0154         command = subst(e[key], MIMEtype, filename, plist)
0155         return command, e
0156     return None, None
0157 
0158 def lookup(caps, MIMEtype, key=None):
0159     entries = []
0160     if MIMEtype in caps:
0161         entries = entries + caps[MIMEtype]
0162     MIMEtypes = MIMEtype.split('/')
0163     MIMEtype = MIMEtypes[0] + '/*'
0164     if MIMEtype in caps:
0165         entries = entries + caps[MIMEtype]
0166     if key is not None:
0167         entries = filter(lambda e, key=key: key in e, entries)
0168     return entries
0169 
0170 def subst(field, MIMEtype, filename, plist=[]):
0171     # XXX Actually, this is Unix-specific
0172     res = ''
0173     i, n = 0, len(field)
0174     while i < n:
0175         c = field[i]; i = i+1
0176         if c != '%':
0177             if c == '\\':
0178                 c = field[i:i+1]; i = i+1
0179             res = res + c
0180         else:
0181             c = field[i]; i = i+1
0182             if c == '%':
0183                 res = res + c
0184             elif c == 's':
0185                 res = res + filename
0186             elif c == 't':
0187                 res = res + MIMEtype
0188             elif c == '{':
0189                 start = i
0190                 while i < n and field[i] != '}':
0191                     i = i+1
0192                 name = field[start:i]
0193                 i = i+1
0194                 res = res + findparam(name, plist)
0195             # XXX To do:
0196             # %n == number of parts if type is multipart/*
0197             # %F == list of alternating type and filename for parts
0198             else:
0199                 res = res + '%' + c
0200     return res
0201 
0202 def findparam(name, plist):
0203     name = name.lower() + '='
0204     n = len(name)
0205     for p in plist:
0206         if p[:n].lower() == name:
0207             return p[n:]
0208     return ''
0209 
0210 
0211 # Part 4: test program.
0212 
0213 def test():
0214     import sys
0215     caps = getcaps()
0216     if not sys.argv[1:]:
0217         show(caps)
0218         return
0219     for i in range(1, len(sys.argv), 2):
0220         args = sys.argv[i:i+2]
0221         if len(args) < 2:
0222             print "usage: mailcap [MIMEtype file] ..."
0223             return
0224         MIMEtype = args[0]
0225         file = args[1]
0226         command, e = findmatch(caps, MIMEtype, 'view', file)
0227         if not command:
0228             print "No viewer found for", type
0229         else:
0230             print "Executing:", command
0231             sts = os.system(command)
0232             if sts:
0233                 print "Exit status:", sts
0234 
0235 def show(caps):
0236     print "Mailcap files:"
0237     for fn in listmailcapfiles(): print "\t" + fn
0238     print
0239     if not caps: caps = getcaps()
0240     print "Mailcap entries:"
0241     print
0242     ckeys = caps.keys()
0243     ckeys.sort()
0244     for type in ckeys:
0245         print type
0246         entries = caps[type]
0247         for e in entries:
0248             keys = e.keys()
0249             keys.sort()
0250             for k in keys:
0251                 print "  %-15s" % k, e[k]
0252             print
0253 
0254 if __name__ == '__main__':
0255     test()
0256 

Generated by PyXR 0.9.4
SourceForge.net Logo