Split nsIHandlerInfo.launchWithURI into nsIHandlerInfo.launchWithURI and nsIMIMEInfo.launchWithFile (bug 391194) r=cbiesinger@gmx.at, sr=bzbarsky@mit.edu
authordmose@mozilla.org
Mon, 20 Aug 2007 17:47:47 -0700
changeset 4841 43bd8a5c7a7a6661280af0a7f48a8940f2c02a91
parent 4840 4b71bf03d167787826db0d65ec9c2e642f70c72f
child 4842 40068db7cf6ff787992e275eeac502085619d008
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerscbiesinger, bzbarsky
bugs391194
milestone1.9a8pre
Split nsIHandlerInfo.launchWithURI into nsIHandlerInfo.launchWithURI and nsIMIMEInfo.launchWithFile (bug 391194) r=cbiesinger@gmx.at, sr=bzbarsky@mit.edu
netwerk/mime/public/nsIMIMEInfo.idl
uriloader/exthandler/mac/nsMIMEInfoMac.cpp
uriloader/exthandler/mac/nsMIMEInfoMac.h
uriloader/exthandler/nsExternalHelperAppService.cpp
uriloader/exthandler/nsMIMEInfoImpl.cpp
uriloader/exthandler/nsMIMEInfoImpl.h
--- a/netwerk/mime/public/nsIMIMEInfo.idl
+++ b/netwerk/mime/public/nsIMIMEInfo.idl
@@ -94,19 +94,24 @@ interface nsIHandlerInfo : nsISupports {
      * usable if hasDefaultHandler is true.
      */
     readonly attribute AString defaultDescription;
 
     /**
      * Launches the application with the specified URI, in a way that
      * depends on the value of preferredAction. preferredAction must be
      * useHelperApp or useSystemDefault.
+     *  
+     * @note Only the URI scheme is used to determine how to launch.  This is
+     * essentially a pass-by-value operation.  This means that in the case of
+     * a file: URI, the handler that is registered for file: will be launched
+     * and our code will not make any decision based on the content-type or
+     * extension, though the invoked file: handler is free to do so. 
      *
-     * @param aURI The URI to launch this application with; this may or may
-     *              not be a local file.
+     * @param aURI The URI to launch this application with
      *
      * @throw NS_ERROR_INVALID_ARG if action is not valid for this function.
      * Other exceptions may be thrown.
      */
     void launchWithURI(in nsIURI aURI);
 
     /**
      * preferredAction is how the user specified they would like to handle
@@ -137,17 +142,17 @@ interface nsIHandlerInfo : nsISupports {
  * nsIMIMEInfo extends nsIHandlerInfo with a bunch of information specific to
  * MIME content-types. There is a one-to-many relationship between MIME types
  * and file extensions. This means that a MIMEInfo object may have multiple
  * file extensions associated with it.  However, the reverse is not true.
  *
  * MIMEInfo objects are generally retrieved from the MIME Service
  * @see nsIMIMEService
  */
-[scriptable, uuid(ba01eb13-c2fd-4652-94f8-b33c61e6d77e)]
+[scriptable, uuid(a4011016-81a1-47d9-b01e-19a2272ae89b)]
 interface nsIMIMEInfo : nsIHandlerInfo {
     /**
      * Gives you an array of file types associated with this type.
      *
      * @return Number of elements in the array.
      * @return Array of extensions.
      */
     nsIUTF8StringEnumerator getFileExtensions();
@@ -195,16 +200,28 @@ interface nsIMIMEInfo : nsIHandlerInfo {
 
     /**
      * Returns whether or not these two nsIMIMEInfos are logically
      * equivalent.
      *
      * @returns PR_TRUE if the two are considered equal
      */
     boolean equals(in nsIMIMEInfo aMIMEInfo);
+
+    /**
+     * Launches the application with the specified file, in a way that
+     * depends on the value of preferredAction. preferredAction must be
+     * useHelperApp or useSystemDefault.
+     *
+     * @param aFile The file to launch this application with.
+     *
+     * @throw NS_ERROR_INVALID_ARG if action is not valid for this function.
+     * Other exceptions may be thrown.
+     */
+    void launchWithFile(in nsIFile aFile);
 };
 
 /**
  * nsIHandlerApp represents an external application that can handle content
  * of some sort (either a MIME-type or a protocol).  Note that for theoretical
  * cleanliness, nsI{Local,Web}HandlerApp really ought to inherit from
  * nsIHandlerApp.  After that's done, we should also try and make
  * nsIWebContentHandlerInfo inherit from or possibly be replaced by
--- a/uriloader/exthandler/mac/nsMIMEInfoMac.cpp
+++ b/uriloader/exthandler/mac/nsMIMEInfoMac.cpp
@@ -42,97 +42,108 @@
 #include <LaunchServices.h>
 
 #include "nsMIMEInfoMac.h"
 #include "nsILocalFileMac.h"
 #include "nsIFileURL.h"
 #include "nsIInternetConfigService.h"
 
 NS_IMETHODIMP
+nsMIMEInfoMac::LaunchWithFile(nsIFile *aFile)
+{
+  nsCOMPtr<nsIFile> application;
+  nsresult rv;
+
+  NS_ASSERTION(mClass == eMIMEInfo, "only MIME infos are currently allowed"
+               "to pass content by value");
+  
+  if (mPreferredAction == useHelperApp) {
+
+    // we don't yet support passing content by value (rather than reference)
+    // to web apps.  at some point, we will probably want to.  
+    nsCOMPtr<nsILocalHandlerApp> localHandlerApp =
+        do_QueryInterface(mPreferredApplication, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+    
+    rv = localHandlerApp->GetExecutable(getter_AddRefs(application));
+    NS_ENSURE_SUCCESS(rv, rv);
+    
+  } else if (mPreferredAction == useSystemDefault) {
+    application = mDefaultApplication;
+  }
+  else
+    return NS_ERROR_INVALID_ARG;
+
+  // if we've already got an app, just QI so we have the launchWithDoc method
+  nsCOMPtr<nsILocalFileMac> app;
+  if (application) {
+    app = do_QueryInterface(application, &rv);
+    if (NS_FAILED(rv)) return rv;
+  } else {
+    // otherwise ask LaunchServices for an app directly
+    nsCOMPtr<nsILocalFileMac> tempFile = do_QueryInterface(aFile, &rv);
+    if (NS_FAILED(rv)) return rv;
+
+    FSRef tempFileRef;
+    tempFile->GetFSRef(&tempFileRef);
+
+    FSRef appFSRef;
+    if (::LSGetApplicationForItem(&tempFileRef, kLSRolesAll, &appFSRef, nsnull) == noErr)
+    {
+      app = (do_CreateInstance("@mozilla.org/file/local;1"));
+      if (!app) return NS_ERROR_FAILURE;
+      app->InitWithFSRef(&appFSRef);
+    } else {
+      return NS_ERROR_FAILURE;
+    }
+  }
+  nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(aFile);
+  return app->LaunchWithDoc(localFile, PR_FALSE); 
+}
+
+NS_IMETHODIMP
 nsMIMEInfoMac::LaunchWithURI(nsIURI* aURI)
 {
   nsCOMPtr<nsIFile> application;
   nsresult rv;
-  
+
+  // for now, this is only being called with protocol handlers; that
+  // will change once we get to more general registerContentHandler
+  // support
+  NS_ASSERTION(mClass == eProtocolInfo,
+               "nsMIMEInfoBase should be a protocol handler");
+
   if (mPreferredAction == useHelperApp) {
 
     // check for and launch with web handler app
     nsCOMPtr<nsIWebHandlerApp> webHandlerApp =
       do_QueryInterface(mPreferredApplication, &rv);
     if (NS_SUCCEEDED(rv)) {
       return LaunchWithWebHandler(webHandlerApp, aURI);         
     }
 
     // otherwise, get the application executable from the handler
     nsCOMPtr<nsILocalHandlerApp> localHandlerApp =
         do_QueryInterface(mPreferredApplication, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
     
     rv = localHandlerApp->GetExecutable(getter_AddRefs(application));
     NS_ENSURE_SUCCESS(rv, rv);
-    
-  } else if (mPreferredAction == useSystemDefault) {
 
-    // because nsMIMEInfoMac isn't yet set up with mDefaultApplication
-    // in the protocol handler case, we need to do it another way for now
-    // (which is fine, but this code would be a little more readable if we
-    // could fall through this case).
-    if (mClass == eProtocolInfo) {
-      return LoadUriInternal(aURI);      
-    }
-
-    application = mDefaultApplication;
-  }
-  else
-    return NS_ERROR_INVALID_ARG;
-
-
-  // get the nsILocalFile version of the doc to launch with
-  nsCOMPtr<nsILocalFile> docToLoad;
-  rv = GetLocalFileFromURI(aURI, getter_AddRefs(docToLoad));
-  if (NS_FAILED(rv)) {
-
-    // If we don't have a file, we must be a protocol handler
-    NS_ASSERTION(mClass == eProtocolInfo, 
-                 "nsMIMEInfoMac should be a protocol handler");
-
-    // so pass the entire URI to the handler.
+    // pass the entire URI to the handler.
     nsCAutoString spec;
     aURI->GetSpec(spec);
     return OpenApplicationWithURI(application, spec);
-  }
-
-  // note that the file pointed to by docToLoad could possibly have originated
-  // as a file: URI if we're in some non-browser application.
+  } 
   
-  // if we've already got an app, just QI so we have the launchWithDoc method
-  nsCOMPtr<nsILocalFileMac> app;
-  if (application) {
-    app = do_QueryInterface(application, &rv);
-    if (NS_FAILED(rv)) return rv;
-  } else {
-    // otherwise ask LaunchServices for an app directly
-    nsCOMPtr<nsILocalFileMac> tempFile = do_QueryInterface(docToLoad, &rv);
-    if (NS_FAILED(rv)) return rv;
-
-    FSRef tempFileRef;
-    tempFile->GetFSRef(&tempFileRef);
-
-    FSRef appFSRef;
-    if (::LSGetApplicationForItem(&tempFileRef, kLSRolesAll, &appFSRef, nsnull) == noErr)
-    {
-      app = (do_CreateInstance("@mozilla.org/file/local;1"));
-      if (!app) return NS_ERROR_FAILURE;
-      app->InitWithFSRef(&appFSRef);
-    } else {
-      return NS_ERROR_FAILURE;
-    }
+  if (mPreferredAction == useSystemDefault) {
+    return LoadUriInternal(aURI);
   }
   
-  return app->LaunchWithDoc(docToLoad, PR_FALSE); 
+  return NS_ERROR_INVALID_ARG;
 }
 
 nsresult 
 nsMIMEInfoMac::LoadUriInternal(nsIURI *aURI)
 {
   NS_ENSURE_ARG_POINTER(aURI);
   nsresult rv = NS_ERROR_FAILURE;
   
--- a/uriloader/exthandler/mac/nsMIMEInfoMac.h
+++ b/uriloader/exthandler/mac/nsMIMEInfoMac.h
@@ -42,16 +42,17 @@
 class nsMIMEInfoMac : public nsMIMEInfoImpl {
   public:
     nsMIMEInfoMac(const char* aMIMEType = "") : nsMIMEInfoImpl(aMIMEType) {}
     nsMIMEInfoMac(const nsACString& aMIMEType) : nsMIMEInfoImpl(aMIMEType) {}
     nsMIMEInfoMac(const nsACString& aType, HandlerClass aClass) :
       nsMIMEInfoImpl(aType, aClass) {}
 
     NS_IMETHOD LaunchWithURI(nsIURI* aURI);
+    NS_IMETHOD LaunchWithFile(nsIFile* aFile);
     NS_IMETHOD GetHasDefaultHandler(PRBool *_retval);
   protected:
     virtual NS_HIDDEN_(nsresult) LoadUriInternal(nsIURI *aURI);
 #ifdef DEBUG
     virtual NS_HIDDEN_(nsresult) LaunchDefaultWithFile(nsIFile* aFile) {
       NS_NOTREACHED("do not call this method, use LaunchWithFile");
       return NS_ERROR_UNEXPECTED;
     }
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -2492,21 +2492,17 @@ nsresult nsExternalAppHandler::OpenWithA
     return NS_OK;
   
   // we only should have gotten here if the on stop request had been fired already.
 
   NS_ASSERTION(mStopRequestIssued, "uhoh, how did we get here if we aren't done getting data?");
   // if a stop request was already issued then proceed with launching the application.
   if (mStopRequestIssued)
   {
-    nsCOMPtr<nsIURI> fileUri;
-    rv = NS_NewFileURI(getter_AddRefs(fileUri), mFinalFileDestination);
-    if (NS_SUCCEEDED(rv)) {
-      rv = mMimeInfo->LaunchWithURI(fileUri);        
-    }
+    rv = mMimeInfo->LaunchWithFile(mFinalFileDestination);        
     if (NS_FAILED(rv))
     {
       // Send error notification.
       nsAutoString path;
       mFinalFileDestination->GetPath(path);
       SendStatusChange(kLaunchError, rv, nsnull, path);
       Cancel(rv); // Cancel, and clean up temp file.
     }
@@ -2567,17 +2563,17 @@ NS_IMETHODIMP nsExternalAppHandler::Laun
   if (fileUrl && mIsFileChannel)
   {
     Cancel(NS_BINDING_ABORTED);
     nsCOMPtr<nsIFile> file;
     nsresult rv = fileUrl->GetFile(getter_AddRefs(file));
 
     if (NS_SUCCEEDED(rv))
     {
-      rv = mMimeInfo->LaunchWithURI(fileUrl);
+      rv = mMimeInfo->LaunchWithFile(file);
       if (NS_SUCCEEDED(rv))
         return NS_OK;
     }
     nsAutoString path;
     if (file)
       file->GetPath(path);
     // If we get here, an error happened
     SendStatusChange(kLaunchError, rv, nsnull, path);
--- a/uriloader/exthandler/nsMIMEInfoImpl.cpp
+++ b/uriloader/exthandler/nsMIMEInfoImpl.cpp
@@ -340,23 +340,65 @@ nsMIMEInfoBase::GetLocalFileFromURI(nsIU
 
   nsCOMPtr<nsIFile> file;
   rv = fileUrl->GetFile(getter_AddRefs(file));
   if (NS_FAILED(rv)) return rv;    
 
   return CallQueryInterface(file, aFile);
 }
 
+NS_IMETHODIMP
+nsMIMEInfoBase::LaunchWithFile(nsIFile* aFile)
+{
+  nsresult rv;
+
+  // it doesn't make any sense to call this on protocol handlers
+  NS_ASSERTION(mClass == eMIMEInfo,
+               "nsMIMEInfoBase should have mClass == eMIMEInfo");
+
+  if (mPreferredAction == useSystemDefault) {
+    return LaunchDefaultWithFile(aFile);
+  }
+
+  if (mPreferredAction == useHelperApp) {
+    if (!mPreferredApplication)
+      return NS_ERROR_FILE_NOT_FOUND;
+
+    // at the moment, we only know how to hand files off to local handlers
+    nsCOMPtr<nsILocalHandlerApp> localHandler = 
+      do_QueryInterface(mPreferredApplication, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIFile> executable;
+    rv = localHandler->GetExecutable(getter_AddRefs(executable));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCAutoString path;
+    aFile->GetNativePath(path);
+    return LaunchWithIProcess(executable, path);
+  }
+
+  return NS_ERROR_INVALID_ARG;
+}
 
 NS_IMETHODIMP
 nsMIMEInfoBase::LaunchWithURI(nsIURI* aURI)
 {
-  nsCOMPtr<nsILocalFile> docToLoad;
   nsresult rv;
-  
+
+  // for now, this is only being called with protocol handlers; that
+  // will change once we get to more general registerContentHandler
+  // support
+  NS_ASSERTION(mClass == eProtocolInfo,
+               "nsMIMEInfoBase should be a protocol handler");
+
+  if (mPreferredAction == useSystemDefault) {
+    return LoadUriInternal(aURI);
+  }
+
   if (mPreferredAction == useHelperApp) {
     if (!mPreferredApplication)
       return NS_ERROR_FILE_NOT_FOUND;
 
     // check for and possibly launch with web application
     nsCOMPtr<nsIWebHandlerApp> webHandler = 
       do_QueryInterface(mPreferredApplication, &rv);
     if (NS_SUCCEEDED(rv)) {
@@ -367,46 +409,21 @@ nsMIMEInfoBase::LaunchWithURI(nsIURI* aU
     nsCOMPtr<nsILocalHandlerApp> localHandler = 
       do_QueryInterface(mPreferredApplication, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIFile> executable;
     rv = localHandler->GetExecutable(getter_AddRefs(executable));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    // get the nsILocalFile version of the doc to launch with
-    rv = GetLocalFileFromURI(aURI, getter_AddRefs(docToLoad));
-    if (NS_FAILED(rv)) {
-
-      // If we don't have a file, we must be a protocol handler        
-      NS_ASSERTION(mClass == eProtocolInfo,
-                   "nsMIMEInfoBase should be a protocol handler");
-
-      // so pass the entire URI to the handler.
-      nsCAutoString spec;
-      aURI->GetSpec(spec);
-      return LaunchWithIProcess(executable, spec);
-    }
-
-    // note that the file pointed to by docToLoad could possibly have
-    // originated as a file: URI if we're in some non-browser application.
-
-    nsCAutoString path;
-    docToLoad->GetNativePath(path);
-    return LaunchWithIProcess(executable, path);
-  }
-  else if (mPreferredAction == useSystemDefault) {
-    if (mClass == eProtocolInfo)
-      return LoadUriInternal(aURI);
-
-    rv = GetLocalFileFromURI(aURI, getter_AddRefs(docToLoad));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    return LaunchDefaultWithFile(docToLoad);
-  }
+    // pass the entire URI to the handler.
+    nsCAutoString spec;
+    aURI->GetSpec(spec);
+    return LaunchWithIProcess(executable, spec);
+  } 
 
   return NS_ERROR_INVALID_ARG;
 }
 
 void
 nsMIMEInfoBase::CopyBasicDataTo(nsMIMEInfoBase* aOther)
 {
   aOther->mType = mType;
--- a/uriloader/exthandler/nsMIMEInfoImpl.h
+++ b/uriloader/exthandler/nsMIMEInfoImpl.h
@@ -83,16 +83,17 @@ class nsMIMEInfoBase : public nsIMIMEInf
     NS_IMETHOD SetMacType(PRUint32 aMacType);
     NS_IMETHOD GetMacCreator(PRUint32 *aMacCreator);
     NS_IMETHOD SetMacCreator(PRUint32 aMacCreator);
     NS_IMETHOD Equals(nsIMIMEInfo *aMIMEInfo, PRBool *_retval);
     NS_IMETHOD GetPreferredApplicationHandler(nsIHandlerApp * *aPreferredAppHandler);
     NS_IMETHOD SetPreferredApplicationHandler(nsIHandlerApp * aPreferredAppHandler);
     NS_IMETHOD GetPossibleApplicationHandlers(nsIMutableArray * *aPossibleAppHandlers);
     NS_IMETHOD GetDefaultDescription(nsAString & aDefaultDescription);
+    NS_IMETHOD LaunchWithFile(nsIFile *aFile);
     NS_IMETHOD LaunchWithURI(nsIURI *aURI);
     NS_IMETHOD GetPreferredAction(nsHandlerInfoAction *aPreferredAction);
     NS_IMETHOD SetPreferredAction(nsHandlerInfoAction aPreferredAction);
     NS_IMETHOD GetAlwaysAskBeforeHandling(PRBool *aAlwaysAskBeforeHandling);
     NS_IMETHOD SetAlwaysAskBeforeHandling(PRBool aAlwaysAskBeforeHandling); 
 
     enum HandlerClass {
       eMIMEInfo,