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