1 /*
   2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 package javax.activation;
  28 
  29 import java.util.*;
  30 import java.io.*;
  31 import java.net.*;
  32 import com.sun.activation.registries.MailcapFile;
  33 import com.sun.activation.registries.LogSupport;
  34 
  35 /**
  36  * MailcapCommandMap extends the CommandMap
  37  * abstract class. It implements a CommandMap whose configuration
  38  * is based on mailcap files
  39  * (<A HREF="http://www.ietf.org/rfc/rfc1524.txt">RFC 1524</A>).
  40  * The MailcapCommandMap can be configured both programmatically
  41  * and via configuration files.
  42  * <p>
  43  * <b>Mailcap file search order:</b><p>
  44  * The MailcapCommandMap looks in various places in the user's
  45  * system for mailcap file entries. When requests are made
  46  * to search for commands in the MailcapCommandMap, it searches
  47  * mailcap files in the following order:
  48  * <p>
  49  * <ol>
  50  * <li> Programatically added entries to the MailcapCommandMap instance.
  51  * <li> The file <code>.mailcap</code> in the user's home directory.
  52  * <li> The file &lt;<i>java.home</i>&gt;<code>/lib/mailcap</code>.
  53  * <li> The file or resources named <code>META-INF/mailcap</code>.
  54  * <li> The file or resource named <code>META-INF/mailcap.default</code>
  55  * (usually found only in the <code>activation.jar</code> file).
  56  * </ol>
  57  * <p>
  58  * <b>Mailcap file format:</b><p>
  59  *
  60  * Mailcap files must conform to the mailcap
  61  * file specification (RFC 1524, <i>A User Agent Configuration Mechanism
  62  * For Multimedia Mail Format Information</i>).
  63  * The file format consists of entries corresponding to
  64  * particular MIME types. In general, the specification
  65  * specifies <i>applications</i> for clients to use when they
  66  * themselves cannot operate on the specified MIME type. The
  67  * MailcapCommandMap extends this specification by using a parameter mechanism
  68  * in mailcap files that allows JavaBeans(tm) components to be specified as
  69  * corresponding to particular commands for a MIME type.<p>
  70  *
  71  * When a mailcap file is
  72  * parsed, the MailcapCommandMap recognizes certain parameter signatures,
  73  * specifically those parameter names that begin with <code>x-java-</code>.
  74  * The MailcapCommandMap uses this signature to find
  75  * command entries for inclusion into its registries.
  76  * Parameter names with the form <code>x-java-&lt;name></code>
  77  * are read by the MailcapCommandMap as identifying a command
  78  * with the name <i>name</i>. When the <i>name</i> is <code>
  79  * content-handler</code> the MailcapCommandMap recognizes the class
  80  * signified by this parameter as a <i>DataContentHandler</i>.
  81  * All other commands are handled generically regardless of command
  82  * name. The command implementation is specified by a fully qualified
  83  * class name of a JavaBean(tm) component. For example; a command for viewing
  84  * some data can be specified as: <code>x-java-view=com.foo.ViewBean</code>.<p>
  85  *
  86  * When the command name is <code>fallback-entry</code>, the value of
  87  * the command may be <code>true</code> or <code>false</code>.  An
  88  * entry for a MIME type that includes a parameter of
  89  * <code>x-java-fallback-entry=true</code> defines fallback commands
  90  * for that MIME type that will only be used if no non-fallback entry
  91  * can be found.  For example, an entry of the form <code>text/*; ;
  92  * x-java-fallback-entry=true; x-java-view=com.sun.TextViewer</code>
  93  * specifies a view command to be used for any text MIME type.  This
  94  * view command would only be used if a non-fallback view command for
  95  * the MIME type could not be found.<p>
  96  *
  97  * MailcapCommandMap aware mailcap files have the
  98  * following general form:<p>
  99  * <code>
 100  * # Comments begin with a '#' and continue to the end of the line.<br>
 101  * &lt;mime type>; ; &lt;parameter list><br>
 102  * # Where a parameter list consists of one or more parameters,<br>
 103  * # where parameters look like: x-java-view=com.sun.TextViewer<br>
 104  * # and a parameter list looks like: <br>
 105  * text/plain; ; x-java-view=com.sun.TextViewer; x-java-edit=com.sun.TextEdit
 106  * <br>
 107  * # Note that mailcap entries that do not contain 'x-java' parameters<br>
 108  * # and comply to RFC 1524 are simply ignored:<br>
 109  * image/gif; /usr/dt/bin/sdtimage %s<br>
 110  *
 111  * </code>
 112  * <p>
 113  *
 114  * @author Bart Calder
 115  * @author Bill Shannon
 116  *
 117  * @since 1.6
 118  */
 119 
 120 public class MailcapCommandMap extends CommandMap {
 121     /*
 122      * We manage a collection of databases, searched in order.
 123      */
 124     private MailcapFile[] DB;
 125     private static final int PROG = 0;  // programmatically added entries
 126 
 127     /**
 128      * The default Constructor.
 129      */
 130     public MailcapCommandMap() {
 131         super();
 132         List dbv = new ArrayList(5);    // usually 5 or less databases
 133         MailcapFile mf = null;
 134         dbv.add(null);          // place holder for PROG entry
 135 
 136         LogSupport.log("MailcapCommandMap: load HOME");
 137         try {
 138             String user_home = System.getProperty("user.home");
 139 
 140             if (user_home != null) {
 141                 String path = user_home + File.separator + ".mailcap";
 142                 mf = loadFile(path);
 143                 if (mf != null)
 144                     dbv.add(mf);
 145             }
 146         } catch (SecurityException ex) {}
 147 
 148         LogSupport.log("MailcapCommandMap: load SYS");
 149         try {
 150             // check system's home
 151             String system_mailcap = System.getProperty("java.home") +
 152                 File.separator + "lib" + File.separator + "mailcap";
 153             mf = loadFile(system_mailcap);
 154             if (mf != null)
 155                 dbv.add(mf);
 156         } catch (SecurityException ex) {}
 157 
 158         LogSupport.log("MailcapCommandMap: load JAR");
 159         // load from the app's jar file
 160         loadAllResources(dbv, "META-INF/mailcap");
 161 
 162         LogSupport.log("MailcapCommandMap: load DEF");
 163         mf = loadResource("/META-INF/mailcap.default");
 164 
 165         if (mf != null)
 166             dbv.add(mf);
 167 
 168         DB = new MailcapFile[dbv.size()];
 169         DB = (MailcapFile[])dbv.toArray(DB);
 170     }
 171 
 172     /**
 173      * Load from the named resource.
 174      */
 175     private MailcapFile loadResource(String name) {
 176         InputStream clis = null;
 177         try {
 178             clis = SecuritySupport.getResourceAsStream(this.getClass(), name);
 179             if (clis != null) {
 180                 MailcapFile mf = new MailcapFile(clis);
 181                 if (LogSupport.isLoggable())
 182                     LogSupport.log("MailcapCommandMap: successfully loaded " +
 183                         "mailcap file: " + name);
 184                 return mf;
 185             } else {
 186                 if (LogSupport.isLoggable())
 187                     LogSupport.log("MailcapCommandMap: not loading " +
 188                         "mailcap file: " + name);
 189             }
 190         } catch (IOException e) {
 191             if (LogSupport.isLoggable())
 192                 LogSupport.log("MailcapCommandMap: can't load " + name, e);
 193         } catch (SecurityException sex) {
 194             if (LogSupport.isLoggable())
 195                 LogSupport.log("MailcapCommandMap: can't load " + name, sex);
 196         } finally {
 197             try {
 198                 if (clis != null)
 199                     clis.close();
 200             } catch (IOException ex) { }        // ignore it
 201         }
 202         return null;
 203     }
 204 
 205     /**
 206      * Load all of the named resource.
 207      */
 208     private void loadAllResources(List v, String name) {
 209         boolean anyLoaded = false;
 210         try {
 211             URL[] urls;
 212             ClassLoader cld = null;
 213             // First try the "application's" class loader.
 214             cld = SecuritySupport.getContextClassLoader();
 215             if (cld == null)
 216                 cld = this.getClass().getClassLoader();
 217             if (cld != null)
 218                 urls = SecuritySupport.getResources(cld, name);
 219             else
 220                 urls = SecuritySupport.getSystemResources(name);
 221             if (urls != null) {
 222                 if (LogSupport.isLoggable())
 223                     LogSupport.log("MailcapCommandMap: getResources");
 224                 for (int i = 0; i < urls.length; i++) {
 225                     URL url = urls[i];
 226                     InputStream clis = null;
 227                     if (LogSupport.isLoggable())
 228                         LogSupport.log("MailcapCommandMap: URL " + url);
 229                     try {
 230                         clis = SecuritySupport.openStream(url);
 231                         if (clis != null) {
 232                             v.add(new MailcapFile(clis));
 233                             anyLoaded = true;
 234                             if (LogSupport.isLoggable())
 235                                 LogSupport.log("MailcapCommandMap: " +
 236                                     "successfully loaded " +
 237                                     "mailcap file from URL: " +
 238                                     url);
 239                         } else {
 240                             if (LogSupport.isLoggable())
 241                                 LogSupport.log("MailcapCommandMap: " +
 242                                     "not loading mailcap " +
 243                                     "file from URL: " + url);
 244                         }
 245                     } catch (IOException ioex) {
 246                         if (LogSupport.isLoggable())
 247                             LogSupport.log("MailcapCommandMap: can't load " +
 248                                                 url, ioex);
 249                     } catch (SecurityException sex) {
 250                         if (LogSupport.isLoggable())
 251                             LogSupport.log("MailcapCommandMap: can't load " +
 252                                                 url, sex);
 253                     } finally {
 254                         try {
 255                             if (clis != null)
 256                                 clis.close();
 257                         } catch (IOException cex) { }
 258                     }
 259                 }
 260             }
 261         } catch (Exception ex) {
 262             if (LogSupport.isLoggable())
 263                 LogSupport.log("MailcapCommandMap: can't load " + name, ex);
 264         }
 265 
 266         // if failed to load anything, fall back to old technique, just in case
 267         if (!anyLoaded) {
 268             if (LogSupport.isLoggable())
 269                 LogSupport.log("MailcapCommandMap: !anyLoaded");
 270             MailcapFile mf = loadResource("/" + name);
 271             if (mf != null)
 272                 v.add(mf);
 273         }
 274     }
 275 
 276     /**
 277      * Load from the named file.
 278      */
 279     private MailcapFile loadFile(String name) {
 280         MailcapFile mtf = null;
 281 
 282         try {
 283             mtf = new MailcapFile(name);
 284         } catch (IOException e) {
 285             //  e.printStackTrace();
 286         }
 287         return mtf;
 288     }
 289 
 290     /**
 291      * Constructor that allows the caller to specify the path
 292      * of a <i>mailcap</i> file.
 293      *
 294      * @param fileName The name of the <i>mailcap</i> file to open
 295      * @exception       IOException     if the file can't be accessed
 296      */
 297     public MailcapCommandMap(String fileName) throws IOException {
 298         this();
 299 
 300         if (LogSupport.isLoggable())
 301             LogSupport.log("MailcapCommandMap: load PROG from " + fileName);
 302         if (DB[PROG] == null) {
 303             DB[PROG] = new MailcapFile(fileName);
 304         }
 305     }
 306 
 307 
 308     /**
 309      * Constructor that allows the caller to specify an <i>InputStream</i>
 310      * containing a mailcap file.
 311      *
 312      * @param is        InputStream of the <i>mailcap</i> file to open
 313      */
 314     public MailcapCommandMap(InputStream is) {
 315         this();
 316 
 317         LogSupport.log("MailcapCommandMap: load PROG");
 318         if (DB[PROG] == null) {
 319             try {
 320                 DB[PROG] = new MailcapFile(is);
 321             } catch (IOException ex) {
 322                 // XXX - should throw it
 323             }
 324         }
 325     }
 326 
 327     /**
 328      * Get the preferred command list for a MIME Type. The MailcapCommandMap
 329      * searches the mailcap files as described above under
 330      * <i>Mailcap file search order</i>.<p>
 331      *
 332      * The result of the search is a proper subset of available
 333      * commands in all mailcap files known to this instance of
 334      * MailcapCommandMap.  The first entry for a particular command
 335      * is considered the preferred command.
 336      *
 337      * @param mimeType  the MIME type
 338      * @return the CommandInfo objects representing the preferred commands.
 339      */
 340     public synchronized CommandInfo[] getPreferredCommands(String mimeType) {
 341         List cmdList = new ArrayList();
 342         if (mimeType != null)
 343             mimeType = mimeType.toLowerCase(Locale.ENGLISH);
 344 
 345         for (int i = 0; i < DB.length; i++) {
 346             if (DB[i] == null)
 347                 continue;
 348             Map cmdMap = DB[i].getMailcapList(mimeType);
 349             if (cmdMap != null)
 350                 appendPrefCmdsToList(cmdMap, cmdList);
 351         }
 352 
 353         // now add the fallback commands
 354         for (int i = 0; i < DB.length; i++) {
 355             if (DB[i] == null)
 356                 continue;
 357             Map cmdMap = DB[i].getMailcapFallbackList(mimeType);
 358             if (cmdMap != null)
 359                 appendPrefCmdsToList(cmdMap, cmdList);
 360         }
 361 
 362         CommandInfo[] cmdInfos = new CommandInfo[cmdList.size()];
 363         cmdInfos = (CommandInfo[])cmdList.toArray(cmdInfos);
 364 
 365         return cmdInfos;
 366     }
 367 
 368     /**
 369      * Put the commands that are in the hash table, into the list.
 370      */
 371     private void appendPrefCmdsToList(Map cmdHash, List cmdList) {
 372         Iterator verb_enum = cmdHash.keySet().iterator();
 373 
 374         while (verb_enum.hasNext()) {
 375             String verb = (String)verb_enum.next();
 376             if (!checkForVerb(cmdList, verb)) {
 377                 List cmdList2 = (List)cmdHash.get(verb); // get the list
 378                 String className = (String)cmdList2.get(0);
 379                 cmdList.add(new CommandInfo(verb, className));
 380             }
 381         }
 382     }
 383 
 384     /**
 385      * Check the cmdList to see if this command exists, return
 386      * true if the verb is there.
 387      */
 388     private boolean checkForVerb(List cmdList, String verb) {
 389         Iterator ee = cmdList.iterator();
 390         while (ee.hasNext()) {
 391             String enum_verb =
 392                 (String)((CommandInfo)ee.next()).getCommandName();
 393             if (enum_verb.equals(verb))
 394                 return true;
 395         }
 396         return false;
 397     }
 398 
 399     /**
 400      * Get all the available commands in all mailcap files known to
 401      * this instance of MailcapCommandMap for this MIME type.
 402      *
 403      * @param mimeType  the MIME type
 404      * @return the CommandInfo objects representing all the commands.
 405      */
 406     public synchronized CommandInfo[] getAllCommands(String mimeType) {
 407         List cmdList = new ArrayList();
 408         if (mimeType != null)
 409             mimeType = mimeType.toLowerCase(Locale.ENGLISH);
 410 
 411         for (int i = 0; i < DB.length; i++) {
 412             if (DB[i] == null)
 413                 continue;
 414             Map cmdMap = DB[i].getMailcapList(mimeType);
 415             if (cmdMap != null)
 416                 appendCmdsToList(cmdMap, cmdList);
 417         }
 418 
 419         // now add the fallback commands
 420         for (int i = 0; i < DB.length; i++) {
 421             if (DB[i] == null)
 422                 continue;
 423             Map cmdMap = DB[i].getMailcapFallbackList(mimeType);
 424             if (cmdMap != null)
 425                 appendCmdsToList(cmdMap, cmdList);
 426         }
 427 
 428         CommandInfo[] cmdInfos = new CommandInfo[cmdList.size()];
 429         cmdInfos = (CommandInfo[])cmdList.toArray(cmdInfos);
 430 
 431         return cmdInfos;
 432     }
 433 
 434     /**
 435      * Put the commands that are in the hash table, into the list.
 436      */
 437     private void appendCmdsToList(Map typeHash, List cmdList) {
 438         Iterator verb_enum = typeHash.keySet().iterator();
 439 
 440         while (verb_enum.hasNext()) {
 441             String verb = (String)verb_enum.next();
 442             List cmdList2 = (List)typeHash.get(verb);
 443             Iterator cmd_enum = ((List)cmdList2).iterator();
 444 
 445             while (cmd_enum.hasNext()) {
 446                 String cmd = (String)cmd_enum.next();
 447                 cmdList.add(new CommandInfo(verb, cmd));
 448                 // cmdList.add(0, new CommandInfo(verb, cmd));
 449             }
 450         }
 451     }
 452 
 453     /**
 454      * Get the command corresponding to <code>cmdName</code> for the MIME type.
 455      *
 456      * @param mimeType  the MIME type
 457      * @param cmdName   the command name
 458      * @return the CommandInfo object corresponding to the command.
 459      */
 460     public synchronized CommandInfo getCommand(String mimeType,
 461                                                         String cmdName) {
 462         if (mimeType != null)
 463             mimeType = mimeType.toLowerCase(Locale.ENGLISH);
 464 
 465         for (int i = 0; i < DB.length; i++) {
 466             if (DB[i] == null)
 467                 continue;
 468             Map cmdMap = DB[i].getMailcapList(mimeType);
 469             if (cmdMap != null) {
 470                 // get the cmd list for the cmd
 471                 List v = (List)cmdMap.get(cmdName);
 472                 if (v != null) {
 473                     String cmdClassName = (String)v.get(0);
 474 
 475                     if (cmdClassName != null)
 476                         return new CommandInfo(cmdName, cmdClassName);
 477                 }
 478             }
 479         }
 480 
 481         // now try the fallback list
 482         for (int i = 0; i < DB.length; i++) {
 483             if (DB[i] == null)
 484                 continue;
 485             Map cmdMap = DB[i].getMailcapFallbackList(mimeType);
 486             if (cmdMap != null) {
 487                 // get the cmd list for the cmd
 488                 List v = (List)cmdMap.get(cmdName);
 489                 if (v != null) {
 490                     String cmdClassName = (String)v.get(0);
 491 
 492                     if (cmdClassName != null)
 493                         return new CommandInfo(cmdName, cmdClassName);
 494                 }
 495             }
 496         }
 497         return null;
 498     }
 499 
 500     /**
 501      * Add entries to the registry.  Programmatically
 502      * added entries are searched before other entries.<p>
 503      *
 504      * The string that is passed in should be in mailcap
 505      * format.
 506      *
 507      * @param mail_cap a correctly formatted mailcap string
 508      */
 509     public synchronized void addMailcap(String mail_cap) {
 510         // check to see if one exists
 511         LogSupport.log("MailcapCommandMap: add to PROG");
 512         if (DB[PROG] == null)
 513             DB[PROG] = new MailcapFile();
 514 
 515         DB[PROG].appendToMailcap(mail_cap);
 516     }
 517 
 518     /**
 519      * Return the DataContentHandler for the specified MIME type.
 520      *
 521      * @param mimeType  the MIME type
 522      * @return          the DataContentHandler
 523      */
 524     public synchronized DataContentHandler createDataContentHandler(
 525                                                         String mimeType) {
 526         if (LogSupport.isLoggable())
 527             LogSupport.log(
 528                 "MailcapCommandMap: createDataContentHandler for " + mimeType);
 529         if (mimeType != null)
 530             mimeType = mimeType.toLowerCase(Locale.ENGLISH);
 531 
 532         for (int i = 0; i < DB.length; i++) {
 533             if (DB[i] == null)
 534                 continue;
 535             if (LogSupport.isLoggable())
 536                 LogSupport.log("  search DB #" + i);
 537             Map cmdMap = DB[i].getMailcapList(mimeType);
 538             if (cmdMap != null) {
 539                 List v = (List)cmdMap.get("content-handler");
 540                 if (v != null) {
 541                     String name = (String)v.get(0);
 542                     DataContentHandler dch = getDataContentHandler(name);
 543                     if (dch != null)
 544                         return dch;
 545                 }
 546             }
 547         }
 548 
 549         // now try the fallback entries
 550         for (int i = 0; i < DB.length; i++) {
 551             if (DB[i] == null)
 552                 continue;
 553             if (LogSupport.isLoggable())
 554                 LogSupport.log("  search fallback DB #" + i);
 555             Map cmdMap = DB[i].getMailcapFallbackList(mimeType);
 556             if (cmdMap != null) {
 557                 List v = (List)cmdMap.get("content-handler");
 558                 if (v != null) {
 559                     String name = (String)v.get(0);
 560                     DataContentHandler dch = getDataContentHandler(name);
 561                     if (dch != null)
 562                         return dch;
 563                 }
 564             }
 565         }
 566         return null;
 567     }
 568 
 569     private DataContentHandler getDataContentHandler(String name) {
 570         if (LogSupport.isLoggable())
 571             LogSupport.log("    got content-handler");
 572         if (LogSupport.isLoggable())
 573             LogSupport.log("      class " + name);
 574         try {
 575             ClassLoader cld = null;
 576             // First try the "application's" class loader.
 577             cld = SecuritySupport.getContextClassLoader();
 578             if (cld == null)
 579                 cld = this.getClass().getClassLoader();
 580             Class cl = null;
 581             try {
 582                 cl = cld.loadClass(name);
 583             } catch (Exception ex) {
 584                 // if anything goes wrong, do it the old way
 585                 cl = Class.forName(name);
 586             }
 587             if (cl != null)             // XXX - always true?
 588                 return (DataContentHandler)cl.newInstance();
 589         } catch (IllegalAccessException e) {
 590             if (LogSupport.isLoggable())
 591                 LogSupport.log("Can't load DCH " + name, e);
 592         } catch (ClassNotFoundException e) {
 593             if (LogSupport.isLoggable())
 594                 LogSupport.log("Can't load DCH " + name, e);
 595         } catch (InstantiationException e) {
 596             if (LogSupport.isLoggable())
 597                 LogSupport.log("Can't load DCH " + name, e);
 598         }
 599         return null;
 600     }
 601 
 602     /**
 603      * Get all the MIME types known to this command map.
 604      *
 605      * @return          array of MIME types as strings
 606      * @since   1.6, JAF 1.1
 607      */
 608     public synchronized String[] getMimeTypes() {
 609         List mtList = new ArrayList();
 610 
 611         for (int i = 0; i < DB.length; i++) {
 612             if (DB[i] == null)
 613                 continue;
 614             String[] ts = DB[i].getMimeTypes();
 615             if (ts != null) {
 616                 for (int j = 0; j < ts.length; j++) {
 617                     // eliminate duplicates
 618                     if (!mtList.contains(ts[j]))
 619                         mtList.add(ts[j]);
 620                 }
 621             }
 622         }
 623 
 624         String[] mts = new String[mtList.size()];
 625         mts = (String[])mtList.toArray(mts);
 626 
 627         return mts;
 628     }
 629 
 630     /**
 631      * Get the native commands for the given MIME type.
 632      * Returns an array of strings where each string is
 633      * an entire mailcap file entry.  The application
 634      * will need to parse the entry to extract the actual
 635      * command as well as any attributes it needs. See
 636      * <A HREF="http://www.ietf.org/rfc/rfc1524.txt">RFC 1524</A>
 637      * for details of the mailcap entry syntax.  Only mailcap
 638      * entries that specify a view command for the specified
 639      * MIME type are returned.
 640      *
 641      * @return          array of native command entries
 642      * @since   1.6, JAF 1.1
 643      */
 644     public synchronized String[] getNativeCommands(String mimeType) {
 645         List cmdList = new ArrayList();
 646         if (mimeType != null)
 647             mimeType = mimeType.toLowerCase(Locale.ENGLISH);
 648 
 649         for (int i = 0; i < DB.length; i++) {
 650             if (DB[i] == null)
 651                 continue;
 652             String[] cmds = DB[i].getNativeCommands(mimeType);
 653             if (cmds != null) {
 654                 for (int j = 0; j < cmds.length; j++) {
 655                     // eliminate duplicates
 656                     if (!cmdList.contains(cmds[j]))
 657                         cmdList.add(cmds[j]);
 658                 }
 659             }
 660         }
 661 
 662         String[] cmds = new String[cmdList.size()];
 663         cmds = (String[])cmdList.toArray(cmds);
 664 
 665         return cmds;
 666     }
 667 
 668     /**
 669      * for debugging...
 670      *
 671     public static void main(String[] argv) throws Exception {
 672         MailcapCommandMap map = new MailcapCommandMap();
 673         CommandInfo[] cmdInfo;
 674 
 675         cmdInfo = map.getPreferredCommands(argv[0]);
 676         System.out.println("Preferred Commands:");
 677         for (int i = 0; i < cmdInfo.length; i++)
 678             System.out.println("Command " + cmdInfo[i].getCommandName() + " [" +
 679                                             cmdInfo[i].getCommandClass() + "]");
 680         cmdInfo = map.getAllCommands(argv[0]);
 681         System.out.println();
 682         System.out.println("All Commands:");
 683         for (int i = 0; i < cmdInfo.length; i++)
 684             System.out.println("Command " + cmdInfo[i].getCommandName() + " [" +
 685                                             cmdInfo[i].getCommandClass() + "]");
 686         DataContentHandler dch = map.createDataContentHandler(argv[0]);
 687         if (dch != null)
 688             System.out.println("DataContentHandler " +
 689                                                 dch.getClass().toString());
 690         System.exit(0);
 691     }
 692     */
 693 }