| 
									
										
										
										
											1997-03-25 21:58:08 +00:00
										 |  |  | """Mailcap file handling.  See RFC 1524.""" | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-24 06:27:27 +00:00
										 |  |  | __all__ = ["getcaps","findmatch"] | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Part 1: top-level interface. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def getcaps(): | 
					
						
							| 
									
										
										
										
											1997-03-25 21:58:08 +00:00
										 |  |  |     """Return a dictionary containing the mailcap database.
 | 
					
						
							| 
									
										
										
										
											2001-01-14 23:47:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-02-04 15:10:34 +00:00
										 |  |  |     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". | 
					
						
							| 
									
										
										
										
											1997-03-25 21:58:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     caps = {} | 
					
						
							|  |  |  |     for mailcap in listmailcapfiles(): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             fp = open(mailcap, 'r') | 
					
						
							| 
									
										
										
										
											2001-05-11 18:47:54 +00:00
										 |  |  |         except IOError: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |             continue | 
					
						
							|  |  |  |         morecaps = readmailcapfile(fp) | 
					
						
							|  |  |  |         fp.close() | 
					
						
							| 
									
										
										
										
											2007-02-11 06:12:03 +00:00
										 |  |  |         for key, value in morecaps.items(): | 
					
						
							| 
									
										
										
										
											2002-06-01 14:18:47 +00:00
										 |  |  |             if not key in caps: | 
					
						
							| 
									
										
										
										
											2002-06-02 18:55:56 +00:00
										 |  |  |                 caps[key] = value | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2002-06-02 18:55:56 +00:00
										 |  |  |                 caps[key] = caps[key] + value | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     return caps | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def listmailcapfiles(): | 
					
						
							| 
									
										
										
										
											1997-03-25 21:58:08 +00:00
										 |  |  |     """Return a list of all mailcap files found on the system.""" | 
					
						
							| 
									
										
										
										
											2011-08-28 00:17:31 +10:00
										 |  |  |     # This is mostly a Unix thing, but we use the OS path separator anyway | 
					
						
							| 
									
										
										
										
											2002-06-01 14:18:47 +00:00
										 |  |  |     if 'MAILCAPS' in os.environ: | 
					
						
							| 
									
										
										
										
											2011-08-28 00:17:31 +10:00
										 |  |  |         pathstr = os.environ['MAILCAPS'] | 
					
						
							|  |  |  |         mailcaps = pathstr.split(os.pathsep) | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2002-06-01 14:18:47 +00:00
										 |  |  |         if 'HOME' in os.environ: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |             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'] | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     return mailcaps | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Part 2: the parser. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def readmailcapfile(fp): | 
					
						
							| 
									
										
										
										
											2000-02-04 15:10:34 +00:00
										 |  |  |     """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". | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     caps = {} | 
					
						
							|  |  |  |     while 1: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         line = fp.readline() | 
					
						
							|  |  |  |         if not line: break | 
					
						
							|  |  |  |         # Ignore comments and blank lines | 
					
						
							| 
									
										
										
										
											2001-02-09 10:23:55 +00:00
										 |  |  |         if line[0] == '#' or line.strip() == '': | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |             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): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         # Normalize the key | 
					
						
							| 
									
										
										
										
											2001-02-09 10:23:55 +00:00
										 |  |  |         types = key.split('/') | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         for j in range(len(types)): | 
					
						
							| 
									
										
										
										
											2001-02-09 10:23:55 +00:00
										 |  |  |             types[j] = types[j].strip() | 
					
						
							|  |  |  |         key = '/'.join(types).lower() | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         # Update the database | 
					
						
							| 
									
										
										
										
											2002-06-01 14:18:47 +00:00
										 |  |  |         if key in caps: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |             caps[key].append(fields) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             caps[key] = [fields] | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     return caps | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def parseline(line): | 
					
						
							| 
									
										
										
										
											2000-02-04 15:10:34 +00:00
										 |  |  |     """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. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     fields = [] | 
					
						
							|  |  |  |     i, n = 0, len(line) | 
					
						
							|  |  |  |     while i < n: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         field, i = parsefield(line, i, n) | 
					
						
							|  |  |  |         fields.append(field) | 
					
						
							|  |  |  |         i = i+1 # Skip semicolon | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     if len(fields) < 2: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         return None, None | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     key, view, rest = fields[0], fields[1], fields[2:] | 
					
						
							|  |  |  |     fields = {'view': view} | 
					
						
							|  |  |  |     for field in rest: | 
					
						
							| 
									
										
										
										
											2001-02-09 10:23:55 +00:00
										 |  |  |         i = field.find('=') | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         if i < 0: | 
					
						
							|  |  |  |             fkey = field | 
					
						
							|  |  |  |             fvalue = "" | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2001-02-09 10:23:55 +00:00
										 |  |  |             fkey = field[:i].strip() | 
					
						
							|  |  |  |             fvalue = field[i+1:].strip() | 
					
						
							| 
									
										
										
										
											2002-06-01 14:18:47 +00:00
										 |  |  |         if fkey in fields: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |             # Ignore it | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             fields[fkey] = fvalue | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     return key, fields | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def parsefield(line, i, n): | 
					
						
							| 
									
										
										
										
											2000-02-04 15:10:34 +00:00
										 |  |  |     """Separate one key-value pair in a mailcap entry.""" | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     start = i | 
					
						
							|  |  |  |     while i < n: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         c = line[i] | 
					
						
							|  |  |  |         if c == ';': | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  |         elif c == '\\': | 
					
						
							|  |  |  |             i = i+2 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             i = i+1 | 
					
						
							| 
									
										
										
										
											2001-02-09 10:23:55 +00:00
										 |  |  |     return line[start:i].strip(), i | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Part 3: using the database. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-03-25 21:58:08 +00:00
										 |  |  | def findmatch(caps, MIMEtype, key='view', filename="/dev/null", plist=[]): | 
					
						
							|  |  |  |     """Find a match for a mailcap entry.
 | 
					
						
							| 
									
										
										
										
											2001-01-14 23:47:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-03-25 21:58:08 +00:00
										 |  |  |     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 | 
					
						
							|  |  |  |     entry to use. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     entries = lookup(caps, MIMEtype, key) | 
					
						
							| 
									
										
										
										
											2001-01-14 23:47:14 +00:00
										 |  |  |     # XXX This code should somehow check for the needsterminal flag. | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     for e in entries: | 
					
						
							| 
									
										
										
										
											2002-06-01 14:18:47 +00:00
										 |  |  |         if 'test' in e: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |             test = subst(e['test'], filename, plist) | 
					
						
							|  |  |  |             if test and os.system(test) != 0: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |         command = subst(e[key], MIMEtype, filename, plist) | 
					
						
							|  |  |  |         return command, e | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     return None, None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-03-25 21:58:08 +00:00
										 |  |  | def lookup(caps, MIMEtype, key=None): | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     entries = [] | 
					
						
							| 
									
										
										
										
											2002-06-01 14:18:47 +00:00
										 |  |  |     if MIMEtype in caps: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         entries = entries + caps[MIMEtype] | 
					
						
							| 
									
										
										
										
											2001-02-09 10:23:55 +00:00
										 |  |  |     MIMEtypes = MIMEtype.split('/') | 
					
						
							| 
									
										
										
										
											1997-03-25 21:58:08 +00:00
										 |  |  |     MIMEtype = MIMEtypes[0] + '/*' | 
					
						
							| 
									
										
										
										
											2002-06-01 14:18:47 +00:00
										 |  |  |     if MIMEtype in caps: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         entries = entries + caps[MIMEtype] | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     if key is not None: | 
					
						
							| 
									
										
										
										
											2010-04-22 13:30:10 +00:00
										 |  |  |         entries = [e for e in entries if key in e] | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     return entries | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-03-25 21:58:08 +00:00
										 |  |  | def subst(field, MIMEtype, filename, plist=[]): | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     # XXX Actually, this is Unix-specific | 
					
						
							|  |  |  |     res = '' | 
					
						
							|  |  |  |     i, n = 0, len(field) | 
					
						
							|  |  |  |     while i < n: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         c = field[i]; i = i+1 | 
					
						
							| 
									
										
										
										
											2000-12-12 23:20:45 +00:00
										 |  |  |         if c != '%': | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |             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 + MIMEtype | 
					
						
							|  |  |  |             elif c == '{': | 
					
						
							|  |  |  |                 start = i | 
					
						
							| 
									
										
										
										
											2000-12-12 23:20:45 +00:00
										 |  |  |                 while i < n and field[i] != '}': | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |                     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 | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     return res | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def findparam(name, plist): | 
					
						
							| 
									
										
										
										
											2001-02-09 10:23:55 +00:00
										 |  |  |     name = name.lower() + '=' | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     n = len(name) | 
					
						
							|  |  |  |     for p in plist: | 
					
						
							| 
									
										
										
										
											2001-02-09 10:23:55 +00:00
										 |  |  |         if p[:n].lower() == name: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |             return p[n:] | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     return '' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Part 4: test program. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def test(): | 
					
						
							|  |  |  |     import sys | 
					
						
							|  |  |  |     caps = getcaps() | 
					
						
							|  |  |  |     if not sys.argv[1:]: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         show(caps) | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     for i in range(1, len(sys.argv), 2): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         args = sys.argv[i:i+2] | 
					
						
							|  |  |  |         if len(args) < 2: | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |             print("usage: mailcap [MIMEtype file] ...") | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |             return | 
					
						
							|  |  |  |         MIMEtype = args[0] | 
					
						
							|  |  |  |         file = args[1] | 
					
						
							|  |  |  |         command, e = findmatch(caps, MIMEtype, 'view', file) | 
					
						
							|  |  |  |         if not command: | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |             print("No viewer found for", type) | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |             print("Executing:", command) | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |             sts = os.system(command) | 
					
						
							|  |  |  |             if sts: | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |                 print("Exit status:", sts) | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def show(caps): | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |     print("Mailcap files:") | 
					
						
							|  |  |  |     for fn in listmailcapfiles(): print("\t" + fn) | 
					
						
							|  |  |  |     print() | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     if not caps: caps = getcaps() | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |     print("Mailcap entries:") | 
					
						
							|  |  |  |     print() | 
					
						
							| 
									
										
										
										
											2010-04-22 13:19:31 +00:00
										 |  |  |     ckeys = sorted(caps) | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  |     for type in ckeys: | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |         print(type) | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         entries = caps[type] | 
					
						
							|  |  |  |         for e in entries: | 
					
						
							| 
									
										
										
										
											2010-04-22 13:19:31 +00:00
										 |  |  |             keys = sorted(e) | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |             for k in keys: | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |                 print("  %-15s" % k, e[k]) | 
					
						
							|  |  |  |             print() | 
					
						
							| 
									
										
										
										
											1995-09-30 16:52:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     test() |