symbian-qemu-0.9.1-12/python-2.6.1/Lib/mailcap.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 """Mailcap file handling.  See RFC 1524."""
       
     2 
       
     3 import os
       
     4 
       
     5 __all__ = ["getcaps","findmatch"]
       
     6 
       
     7 # Part 1: top-level interface.
       
     8 
       
     9 def getcaps():
       
    10     """Return a dictionary containing the mailcap database.
       
    11 
       
    12     The dictionary maps a MIME type (in all lowercase, e.g. 'text/plain')
       
    13     to a list of dictionaries corresponding to mailcap entries.  The list
       
    14     collects all the entries for that MIME type from all available mailcap
       
    15     files.  Each dictionary contains key-value pairs for that MIME type,
       
    16     where the viewing command is stored with the key "view".
       
    17 
       
    18     """
       
    19     caps = {}
       
    20     for mailcap in listmailcapfiles():
       
    21         try:
       
    22             fp = open(mailcap, 'r')
       
    23         except IOError:
       
    24             continue
       
    25         morecaps = readmailcapfile(fp)
       
    26         fp.close()
       
    27         for key, value in morecaps.iteritems():
       
    28             if not key in caps:
       
    29                 caps[key] = value
       
    30             else:
       
    31                 caps[key] = caps[key] + value
       
    32     return caps
       
    33 
       
    34 def listmailcapfiles():
       
    35     """Return a list of all mailcap files found on the system."""
       
    36     # XXX Actually, this is Unix-specific
       
    37     if 'MAILCAPS' in os.environ:
       
    38         str = os.environ['MAILCAPS']
       
    39         mailcaps = str.split(':')
       
    40     else:
       
    41         if 'HOME' in os.environ:
       
    42             home = os.environ['HOME']
       
    43         else:
       
    44             # Don't bother with getpwuid()
       
    45             home = '.' # Last resort
       
    46         mailcaps = [home + '/.mailcap', '/etc/mailcap',
       
    47                 '/usr/etc/mailcap', '/usr/local/etc/mailcap']
       
    48     return mailcaps
       
    49 
       
    50 
       
    51 # Part 2: the parser.
       
    52 
       
    53 def readmailcapfile(fp):
       
    54     """Read a mailcap file and return a dictionary keyed by MIME type.
       
    55 
       
    56     Each MIME type is mapped to an entry consisting of a list of
       
    57     dictionaries; the list will contain more than one such dictionary
       
    58     if a given MIME type appears more than once in the mailcap file.
       
    59     Each dictionary contains key-value pairs for that MIME type, where
       
    60     the viewing command is stored with the key "view".
       
    61     """
       
    62     caps = {}
       
    63     while 1:
       
    64         line = fp.readline()
       
    65         if not line: break
       
    66         # Ignore comments and blank lines
       
    67         if line[0] == '#' or line.strip() == '':
       
    68             continue
       
    69         nextline = line
       
    70         # Join continuation lines
       
    71         while nextline[-2:] == '\\\n':
       
    72             nextline = fp.readline()
       
    73             if not nextline: nextline = '\n'
       
    74             line = line[:-2] + nextline
       
    75         # Parse the line
       
    76         key, fields = parseline(line)
       
    77         if not (key and fields):
       
    78             continue
       
    79         # Normalize the key
       
    80         types = key.split('/')
       
    81         for j in range(len(types)):
       
    82             types[j] = types[j].strip()
       
    83         key = '/'.join(types).lower()
       
    84         # Update the database
       
    85         if key in caps:
       
    86             caps[key].append(fields)
       
    87         else:
       
    88             caps[key] = [fields]
       
    89     return caps
       
    90 
       
    91 def parseline(line):
       
    92     """Parse one entry in a mailcap file and return a dictionary.
       
    93 
       
    94     The viewing command is stored as the value with the key "view",
       
    95     and the rest of the fields produce key-value pairs in the dict.
       
    96     """
       
    97     fields = []
       
    98     i, n = 0, len(line)
       
    99     while i < n:
       
   100         field, i = parsefield(line, i, n)
       
   101         fields.append(field)
       
   102         i = i+1 # Skip semicolon
       
   103     if len(fields) < 2:
       
   104         return None, None
       
   105     key, view, rest = fields[0], fields[1], fields[2:]
       
   106     fields = {'view': view}
       
   107     for field in rest:
       
   108         i = field.find('=')
       
   109         if i < 0:
       
   110             fkey = field
       
   111             fvalue = ""
       
   112         else:
       
   113             fkey = field[:i].strip()
       
   114             fvalue = field[i+1:].strip()
       
   115         if fkey in fields:
       
   116             # Ignore it
       
   117             pass
       
   118         else:
       
   119             fields[fkey] = fvalue
       
   120     return key, fields
       
   121 
       
   122 def parsefield(line, i, n):
       
   123     """Separate one key-value pair in a mailcap entry."""
       
   124     start = i
       
   125     while i < n:
       
   126         c = line[i]
       
   127         if c == ';':
       
   128             break
       
   129         elif c == '\\':
       
   130             i = i+2
       
   131         else:
       
   132             i = i+1
       
   133     return line[start:i].strip(), i
       
   134 
       
   135 
       
   136 # Part 3: using the database.
       
   137 
       
   138 def findmatch(caps, MIMEtype, key='view', filename="/dev/null", plist=[]):
       
   139     """Find a match for a mailcap entry.
       
   140 
       
   141     Return a tuple containing the command line, and the mailcap entry
       
   142     used; (None, None) if no match is found.  This may invoke the
       
   143     'test' command of several matching entries before deciding which
       
   144     entry to use.
       
   145 
       
   146     """
       
   147     entries = lookup(caps, MIMEtype, key)
       
   148     # XXX This code should somehow check for the needsterminal flag.
       
   149     for e in entries:
       
   150         if 'test' in e:
       
   151             test = subst(e['test'], filename, plist)
       
   152             if test and os.system(test) != 0:
       
   153                 continue
       
   154         command = subst(e[key], MIMEtype, filename, plist)
       
   155         return command, e
       
   156     return None, None
       
   157 
       
   158 def lookup(caps, MIMEtype, key=None):
       
   159     entries = []
       
   160     if MIMEtype in caps:
       
   161         entries = entries + caps[MIMEtype]
       
   162     MIMEtypes = MIMEtype.split('/')
       
   163     MIMEtype = MIMEtypes[0] + '/*'
       
   164     if MIMEtype in caps:
       
   165         entries = entries + caps[MIMEtype]
       
   166     if key is not None:
       
   167         entries = filter(lambda e, key=key: key in e, entries)
       
   168     return entries
       
   169 
       
   170 def subst(field, MIMEtype, filename, plist=[]):
       
   171     # XXX Actually, this is Unix-specific
       
   172     res = ''
       
   173     i, n = 0, len(field)
       
   174     while i < n:
       
   175         c = field[i]; i = i+1
       
   176         if c != '%':
       
   177             if c == '\\':
       
   178                 c = field[i:i+1]; i = i+1
       
   179             res = res + c
       
   180         else:
       
   181             c = field[i]; i = i+1
       
   182             if c == '%':
       
   183                 res = res + c
       
   184             elif c == 's':
       
   185                 res = res + filename
       
   186             elif c == 't':
       
   187                 res = res + MIMEtype
       
   188             elif c == '{':
       
   189                 start = i
       
   190                 while i < n and field[i] != '}':
       
   191                     i = i+1
       
   192                 name = field[start:i]
       
   193                 i = i+1
       
   194                 res = res + findparam(name, plist)
       
   195             # XXX To do:
       
   196             # %n == number of parts if type is multipart/*
       
   197             # %F == list of alternating type and filename for parts
       
   198             else:
       
   199                 res = res + '%' + c
       
   200     return res
       
   201 
       
   202 def findparam(name, plist):
       
   203     name = name.lower() + '='
       
   204     n = len(name)
       
   205     for p in plist:
       
   206         if p[:n].lower() == name:
       
   207             return p[n:]
       
   208     return ''
       
   209 
       
   210 
       
   211 # Part 4: test program.
       
   212 
       
   213 def test():
       
   214     import sys
       
   215     caps = getcaps()
       
   216     if not sys.argv[1:]:
       
   217         show(caps)
       
   218         return
       
   219     for i in range(1, len(sys.argv), 2):
       
   220         args = sys.argv[i:i+2]
       
   221         if len(args) < 2:
       
   222             print "usage: mailcap [MIMEtype file] ..."
       
   223             return
       
   224         MIMEtype = args[0]
       
   225         file = args[1]
       
   226         command, e = findmatch(caps, MIMEtype, 'view', file)
       
   227         if not command:
       
   228             print "No viewer found for", type
       
   229         else:
       
   230             print "Executing:", command
       
   231             sts = os.system(command)
       
   232             if sts:
       
   233                 print "Exit status:", sts
       
   234 
       
   235 def show(caps):
       
   236     print "Mailcap files:"
       
   237     for fn in listmailcapfiles(): print "\t" + fn
       
   238     print
       
   239     if not caps: caps = getcaps()
       
   240     print "Mailcap entries:"
       
   241     print
       
   242     ckeys = caps.keys()
       
   243     ckeys.sort()
       
   244     for type in ckeys:
       
   245         print type
       
   246         entries = caps[type]
       
   247         for e in entries:
       
   248             keys = e.keys()
       
   249             keys.sort()
       
   250             for k in keys:
       
   251                 print "  %-15s" % k, e[k]
       
   252             print
       
   253 
       
   254 if __name__ == '__main__':
       
   255     test()