1 /**
2 *
3 * Copyright 2003-2004 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package javax.activation;
19
20 import java.io.BufferedReader;
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.FileReader;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.InputStreamReader;
27 import java.io.Reader;
28 import java.net.URL;
29 import java.security.Security;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.Enumeration;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37
38 /**
39 * @version $Rev: 376811 $ $Date: 2006-02-10 11:40:13 -0800 (Fri, 10 Feb 2006) $
40 */
41 public class MailcapCommandMap extends CommandMap {
42 private final Map preferredCommands = new HashMap();
43 private final Map allCommands = new HashMap();
44
45 private final Map fallbackCommands = new HashMap();
46 private URL url;
47
48 public MailcapCommandMap() {
49 ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
50
51 try {
52 InputStream is = MailcapCommandMap.class.getResourceAsStream("/META-INF/mailcap.default");
53 if (is != null) {
54 try {
55 parseMailcap(is);
56 } finally {
57 is.close();
58 }
59 }
60 } catch (IOException e) {
61
62 }
63
64
65 try {
66 Enumeration e = contextLoader.getResources("META-INF/mailcap");
67 while (e.hasMoreElements()) {
68 url = ((URL) e.nextElement());
69 try {
70 InputStream is = url.openStream();
71 try {
72 parseMailcap(is);
73 } finally {
74 is.close();
75 }
76 } catch (IOException e1) {
77 continue;
78 }
79 }
80 } catch (SecurityException e) {
81
82 } catch (IOException e) {
83
84 }
85
86
87 try {
88 File file = new File(System.getProperty("java.home"), "lib/mailcap");
89 InputStream is = new FileInputStream(file);
90 try {
91 parseMailcap(is);
92 } finally {
93 is.close();
94 }
95 } catch (SecurityException e) {
96
97 } catch (IOException e) {
98
99 }
100
101
102 try {
103 File file = new File(System.getProperty("user.home"), ".mailcap");
104 InputStream is = new FileInputStream(file);
105 try {
106 parseMailcap(is);
107 } finally {
108 is.close();
109 }
110 } catch (SecurityException e) {
111
112 } catch (IOException e) {
113
114 }
115 }
116
117 public MailcapCommandMap(String fileName) throws IOException {
118 this();
119 FileReader reader = new FileReader(fileName);
120 try {
121 parseMailcap(reader);
122 } finally {
123 reader.close();
124 }
125 }
126
127 public MailcapCommandMap(InputStream is) {
128 this();
129 parseMailcap(is);
130 }
131
132 private void parseMailcap(InputStream is) {
133 try {
134 parseMailcap(new InputStreamReader(is));
135 } catch (IOException e) {
136
137 }
138 }
139
140 void parseMailcap(Reader reader) throws IOException {
141 BufferedReader br = new BufferedReader(reader);
142 String line;
143 while ((line = br.readLine()) != null) {
144 addMailcap(line);
145 }
146 }
147
148 public synchronized void addMailcap(String mail_cap) {
149 int index = 0;
150
151 index = skipSpace(mail_cap, index);
152 if (index == mail_cap.length() || mail_cap.charAt(index) == '#') {
153 return;
154 }
155
156
157 int start = index;
158 index = getToken(mail_cap, index);
159 if (start == index) {
160 return;
161 }
162 String mimeType = mail_cap.substring(start, index);
163
164
165 index = skipSpace(mail_cap, index);
166 if (index == mail_cap.length() || mail_cap.charAt(index) == '#') {
167 return;
168 }
169
170
171 if (mail_cap.charAt(index) == '/') {
172 index = skipSpace(mail_cap, ++index);
173 start = index;
174 index = getToken(mail_cap, index);
175 mimeType = mimeType + '/' + mail_cap.substring(start, index);
176 } else {
177
178 mimeType = mimeType + "/*";
179 }
180
181
182 mimeType = mimeType.toLowerCase();
183
184
185 index = skipSpace(mail_cap, index);
186
187
188 if (index == mail_cap.length() || mail_cap.charAt(index) != ';') {
189 return;
190 }
191 index = getMText(mail_cap, index);
192
193 if (index == mail_cap.length() || mail_cap.charAt(index) != ';') {
194 return;
195 }
196
197
198
199 List commandList = new ArrayList();
200
201 boolean fallback = false;
202
203
204 while (index < mail_cap.length() && mail_cap.charAt(index) == ';') {
205 index = skipSpace(mail_cap, index + 1);
206 start = index;
207 index = getToken(mail_cap, index);
208 String fieldName = mail_cap.substring(start, index).toLowerCase();
209 index = skipSpace(mail_cap, index);
210 if (index < mail_cap.length() && mail_cap.charAt(index) == '=') {
211 index = skipSpace(mail_cap, index + 1);
212 start = index;
213 index = getMText(mail_cap, index);
214 String value = mail_cap.substring(start, index);
215 index = skipSpace(mail_cap, index);
216 if (fieldName.startsWith("x-java-") && fieldName.length() > 7) {
217 String command = fieldName.substring(7);
218 value = value.trim();
219 if (command.equals("fallback-entry")) {
220 if (value.equals("true")) {
221 fallback = true;
222 }
223 }
224 else {
225
226 CommandInfo info = new CommandInfo(command, value);
227 commandList.add(info);
228 }
229 }
230 }
231 }
232 addCommands(mimeType, commandList, fallback);
233 }
234
235 /**
236 * Add a parsed list of commands to the appropriate command list.
237 *
238 * @param mimeType The mimeType name this is added under.
239 * @param commands A List containing the command information.
240 * @param fallback The target list identifier.
241 */
242 private void addCommands(String mimeType, List commands, boolean fallback) {
243
244 Map target = fallback ? fallbackCommands : preferredCommands;
245
246
247 for (Iterator i = commands.iterator(); i.hasNext();) {
248 CommandInfo info = (CommandInfo)i.next();
249 addCommand(target, mimeType, info);
250
251 if (!fallback) {
252 List cmdList = (List) allCommands.get(mimeType);
253 if (cmdList == null) {
254 cmdList = new ArrayList();
255 allCommands.put(mimeType, cmdList);
256 }
257 cmdList.add(info);
258 }
259 }
260 }
261
262
263 /**
264 * Add a command to a target command list (preferred or fallback).
265 *
266 * @param commandList
267 * The target command list.
268 * @param mimeType The MIME type the command is associated with.
269 * @param command The command information.
270 */
271 private void addCommand(Map commandList, String mimeType, CommandInfo command) {
272
273 Map commands = (Map) commandList.get(mimeType);
274 if (commands == null) {
275 commands = new HashMap();
276 commandList.put(mimeType, commands);
277 }
278 commands.put(command.getCommandName(), command);
279 }
280
281
282 private int skipSpace(String s, int index) {
283 while (index < s.length() && Character.isWhitespace(s.charAt(index))) {
284 index++;
285 }
286 return index;
287 }
288
289 private int getToken(String s, int index) {
290 while (index < s.length() && s.charAt(index) != '#' && !MimeType.isSpecial(s.charAt(index))) {
291 index++;
292 }
293 return index;
294 }
295
296 private int getMText(String s, int index) {
297 while (index < s.length()) {
298 char c = s.charAt(index);
299 if (c == '#' || c == ';' || Character.isISOControl(c)) {
300 return index;
301 }
302 if (c == '\\') {
303 index++;
304 if (index == s.length()) {
305 return index;
306 }
307 }
308 index++;
309 }
310 return index;
311 }
312
313 public synchronized CommandInfo[] getPreferredCommands(String mimeType) {
314
315 mimeType = mimeType.toLowerCase();
316
317 Map commands = (Map) preferredCommands.get(mimeType);
318 if (commands == null) {
319 commands = (Map) preferredCommands.get(getWildcardMimeType(mimeType));
320 }
321
322 Map fallbackCommands = getFallbackCommands(mimeType);
323
324
325 if (fallbackCommands != null) {
326
327 if (commands == null) {
328 commands = fallbackCommands;
329 }
330 else {
331
332 commands = mergeCommandMaps(commands, fallbackCommands);
333 }
334 }
335
336
337 if (commands == null) {
338 return new CommandInfo[0];
339 }
340 return (CommandInfo[]) commands.values().toArray(new CommandInfo[commands.size()]);
341 }
342
343 private Map getFallbackCommands(String mimeType) {
344 Map commands = (Map) fallbackCommands.get(mimeType);
345
346
347
348 Map wildcardCommands = (Map)fallbackCommands.get(getWildcardMimeType(mimeType));
349
350 if (wildcardCommands == null) {
351 return commands;
352 }
353
354 return mergeCommandMaps(commands, wildcardCommands);
355 }
356
357
358 private Map mergeCommandMaps(Map main, Map fallback) {
359
360
361 Map result = new HashMap(fallback);
362 result.putAll(main);
363
364 return result;
365 }
366
367 public synchronized CommandInfo[] getAllCommands(String mimeType) {
368 mimeType = mimeType.toLowerCase();
369 List exactCommands = (List) allCommands.get(mimeType);
370 if (exactCommands == null) {
371 exactCommands = Collections.EMPTY_LIST;
372 }
373 List wildCommands = (List) allCommands.get(getWildcardMimeType(mimeType));
374 if (wildCommands == null) {
375 wildCommands = Collections.EMPTY_LIST;
376 }
377
378 Map fallbackCommands = getFallbackCommands(mimeType);
379 if (fallbackCommands == null) {
380 fallbackCommands = Collections.EMPTY_MAP;
381 }
382
383
384 CommandInfo[] result = new CommandInfo[exactCommands.size() + wildCommands.size() + fallbackCommands.size()];
385 int j = 0;
386 for (int i = 0; i < exactCommands.size(); i++) {
387 result[j++] = (CommandInfo) exactCommands.get(i);
388 }
389 for (int i = 0; i < wildCommands.size(); i++) {
390 result[j++] = (CommandInfo) wildCommands.get(i);
391 }
392
393 for (Iterator i = fallbackCommands.keySet().iterator(); i.hasNext();) {
394 result[j++] = (CommandInfo) fallbackCommands.get((String)i.next());
395 }
396 return result;
397 }
398
399 public synchronized CommandInfo getCommand(String mimeType, String cmdName) {
400 mimeType = mimeType.toLowerCase();
401
402 int i = mimeType.indexOf(';');
403 if (i != -1) {
404 mimeType = mimeType.substring(0, i).trim();
405 }
406
407
408 Map commands = (Map) preferredCommands.get(mimeType);
409 if (commands == null) {
410
411 commands = (Map) preferredCommands.get(getWildcardMimeType(mimeType));
412 if (commands == null) {
413
414 commands = (Map) fallbackCommands.get(mimeType);
415 if (commands == null) {
416 commands = (Map) fallbackCommands.get(getWildcardMimeType(mimeType));
417 }
418 if (commands == null) {
419 return null;
420 }
421 }
422 }
423 return (CommandInfo) commands.get(cmdName.toLowerCase());
424 }
425
426 private String getWildcardMimeType(String mimeType) {
427 int i = mimeType.indexOf('/');
428 if (i == -1) {
429 return mimeType + "/*";
430 } else {
431 return mimeType.substring(0, i + 1) + "*";
432 }
433 }
434
435 public synchronized DataContentHandler createDataContentHandler(String mimeType) {
436
437 CommandInfo info = getCommand(mimeType, "content-handler");
438 if (info == null) {
439 return null;
440 }
441
442 ClassLoader cl = Thread.currentThread().getContextClassLoader();
443 if (cl == null) {
444 cl = getClass().getClassLoader();
445 }
446 try {
447 return (DataContentHandler) cl.loadClass(info.getCommandClass()).newInstance();
448 } catch (ClassNotFoundException e) {
449 return null;
450 } catch (IllegalAccessException e) {
451 return null;
452 } catch (InstantiationException e) {
453 return null;
454 }
455 }
456 }