local protocol handling apps can be chosen but don't work (bug 389758); patch by dolske and me, r=biesi, sr=bz, a=mconnor
authordmose@mozilla.org
Sat, 28 Jul 2007 20:38:52 -0700
changeset 4085 26dcc4302b239a86be99c2f60c676fabdc5b2b1a
parent 4084 6fb46ac22829e665ce00e1f12a8fa1a45b0dbfae
child 4086 9b946804da07d185662f19707e3e349b4ee97fb7
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbiesi, bz, mconnor
bugs389758
milestone1.9a7pre
local protocol handling apps can be chosen but don't work (bug 389758); patch by dolske and me, r=biesi, sr=bz, a=mconnor
uriloader/exthandler/mac/nsMIMEInfoMac.cpp
uriloader/exthandler/mac/nsMIMEInfoMac.h
uriloader/exthandler/nsMIMEInfoImpl.cpp
uriloader/exthandler/nsMIMEInfoImpl.h
--- a/uriloader/exthandler/mac/nsMIMEInfoMac.cpp
+++ b/uriloader/exthandler/mac/nsMIMEInfoMac.cpp
@@ -64,29 +64,50 @@ nsMIMEInfoMac::LaunchWithURI(nsIURI* aUR
     // 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)
+  } 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;
 
-  if (mClass == eProtocolInfo)
-    return LoadUriInternal(aURI);
 
   // get the nsILocalFile version of the doc to launch with
   nsCOMPtr<nsILocalFile> docToLoad;
   rv = GetLocalFileFromURI(aURI, getter_AddRefs(docToLoad));
-  NS_ENSURE_SUCCESS(rv, rv);
+  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.
+    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);
@@ -129,8 +150,56 @@ nsMIMEInfoMac::LoadUriInternal(nsIURI *a
 NS_IMETHODIMP
 nsMIMEInfoMac::GetHasDefaultHandler(PRBool *_retval)
 {
   // We have a default application if we have a description
   *_retval = !mDefaultAppDescription.IsEmpty();
   return NS_OK;
 }
 
+/** 
+ * static; mostly copy/pasted from nsMacShellService.cpp (which is in browser/,
+ * so we can't depend on it here).  This code probably really wants to live
+ * somewhere more central; see bug 389922.
+ */
+nsresult
+nsMIMEInfoMac::OpenApplicationWithURI(nsIFile* aApplication, 
+                                      const nsCString& aURI)
+{
+  nsresult rv;
+  nsCOMPtr<nsILocalFileMac> lfm(do_QueryInterface(aApplication, &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+  
+  CFURLRef appURL;
+  rv = lfm->GetCFURL(&appURL);
+  if (NS_FAILED(rv))
+    return rv;
+  
+  const UInt8* uriString = (const UInt8*)aURI.get();
+  CFURLRef uri = ::CFURLCreateWithBytes(NULL, uriString, aURI.Length(),
+                                        kCFStringEncodingUTF8, NULL);
+  if (!uri) {
+    ::CFRelease(appURL);
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  
+  CFArrayRef uris = ::CFArrayCreate(NULL, (const void**)&uri, 1, NULL);
+  if (!uris) {
+    ::CFRelease(uri);
+    ::CFRelease(appURL);
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  
+  LSLaunchURLSpec launchSpec;
+  launchSpec.appURL = appURL;
+  launchSpec.itemURLs = uris;
+  launchSpec.passThruParams = NULL;
+  launchSpec.launchFlags = kLSLaunchDefaults;
+  launchSpec.asyncRefCon = NULL;
+  
+  OSErr err = ::LSOpenFromURLSpec(&launchSpec, NULL);
+  
+  ::CFRelease(uris);
+  ::CFRelease(uri);
+  ::CFRelease(appURL);
+  
+  return err != noErr ? NS_ERROR_FAILURE : NS_OK;
+}
--- a/uriloader/exthandler/mac/nsMIMEInfoMac.h
+++ b/uriloader/exthandler/mac/nsMIMEInfoMac.h
@@ -51,12 +51,15 @@ class nsMIMEInfoMac : public nsMIMEInfoI
   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;
     }
 #endif
+    static NS_HIDDEN_(nsresult) OpenApplicationWithURI(nsIFile *aApplication, 
+                                                       const nsCString& aURI);
+    
 };
 
 
 #endif
--- a/uriloader/exthandler/nsMIMEInfoImpl.cpp
+++ b/uriloader/exthandler/nsMIMEInfoImpl.cpp
@@ -353,20 +353,36 @@ 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));
-    NS_ENSURE_SUCCESS(rv, rv);
+    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");
 
-    return LaunchWithIProcess(executable, docToLoad);
+      // 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);
 
@@ -384,35 +400,32 @@ nsMIMEInfoBase::CopyBasicDataTo(nsMIMEIn
   aOther->mExtensions = mExtensions;
 
   aOther->mMacType = mMacType;
   aOther->mMacCreator = mMacCreator;
 }
 
 /* static */
 nsresult
-nsMIMEInfoBase::LaunchWithIProcess(nsIFile* aApp, nsIFile* aFile)
+nsMIMEInfoBase::LaunchWithIProcess(nsIFile* aApp, const nsCString& aArg)
 {
-  NS_ASSERTION(aApp && aFile, "Unexpected null pointer, fix caller");
+  NS_ASSERTION(aApp, "Unexpected null pointer, fix caller");
 
   nsresult rv;
   nsCOMPtr<nsIProcess> process = do_CreateInstance(NS_PROCESS_CONTRACTID, &rv);
   if (NS_FAILED(rv))
     return rv;
 
   if (NS_FAILED(rv = process->Init(aApp)))
     return rv;
 
-  nsCAutoString path;
-  aFile->GetNativePath(path);
-
-  const char * strPath = path.get();
+  const char *string = aArg.get();
 
   PRUint32 pid;
-  return process->Run(PR_FALSE, &strPath, 1, &pid);
+  return process->Run(PR_FALSE, &string, 1, &pid);
 }
 
 /* static */
 nsresult
 nsMIMEInfoBase::LaunchWithWebHandler(nsIWebHandlerApp *aApp, nsIURI *aURI) 
 {
   // we'll be implementing this Real Soon Now!
   return NS_ERROR_NOT_IMPLEMENTED;
@@ -445,11 +458,14 @@ nsMIMEInfoImpl::GetHasDefaultHandler(PRB
 }
 
 nsresult
 nsMIMEInfoImpl::LaunchDefaultWithFile(nsIFile* aFile)
 {
   if (!mDefaultApplication)
     return NS_ERROR_FILE_NOT_FOUND;
 
-  return LaunchWithIProcess(mDefaultApplication, aFile);
+  nsCAutoString nativePath;
+  aFile->GetNativePath(nativePath);
+  
+  return LaunchWithIProcess(mDefaultApplication, nativePath);
 }
 
--- a/uriloader/exthandler/nsMIMEInfoImpl.h
+++ b/uriloader/exthandler/nsMIMEInfoImpl.h
@@ -135,26 +135,26 @@ class nsMIMEInfoBase : public nsIMIMEInf
     /**
      * Loads the URI with the OS default app.
      *
      * @param aURI The URI to pass off to the OS.
      */
     virtual NS_HIDDEN_(nsresult) LoadUriInternal(nsIURI *aURI) = 0;
 
     /**
-     * This method can be used to launch the file using nsIProcess, with the
-     * path of the file being the first parameter to the executable. This is
+     * This method can be used to launch the file or URI with a single 
+     * argument (typically either a file path or a URI spec).  This is 
      * meant as a helper method for implementations of
-     * LaunchWithFile/LaunchDefaultWithFile.
-     * Neither aApp nor aFile may be null.
+     * LaunchWithURI/LaunchDefaultWithFile.
      *
-     * @param aApp The application to launch
-     * @param aFile The file to open in the application
+     * @param aApp The application to launch (may not be null)
+     * @param aArg The argument to pass on the command line
      */
-    static NS_HIDDEN_(nsresult) LaunchWithIProcess(nsIFile* aApp, nsIFile* aFile);
+    static NS_HIDDEN_(nsresult) LaunchWithIProcess(nsIFile* aApp,
+                                                   const nsCString &aArg);
 
     /**
      * Used to launch a web-based handler with this URI.
      * 
      * @param aURI  The URI to launch with.
      */
     static NS_HIDDEN_(nsresult) LaunchWithWebHandler(nsIWebHandlerApp *aApp, 
                                                      nsIURI *aURI);