From 37bc21919470d8412575b9c7c48516032dac7023 Mon Sep 17 00:00:00 2001 From: "dmose@mozilla.org" Date: Sat, 28 Jul 2007 20:38:52 -0700 Subject: [PATCH] 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 | 77 ++++++++++++++++++++-- uriloader/exthandler/mac/nsMIMEInfoMac.h | 3 + uriloader/exthandler/nsMIMEInfoImpl.cpp | 36 +++++++--- uriloader/exthandler/nsMIMEInfoImpl.h | 14 ++-- 4 files changed, 109 insertions(+), 21 deletions(-) diff --git a/uriloader/exthandler/mac/nsMIMEInfoMac.cpp b/uriloader/exthandler/mac/nsMIMEInfoMac.cpp index 3d4f0a65ea6..8a10e0352d7 100755 --- a/uriloader/exthandler/mac/nsMIMEInfoMac.cpp +++ b/uriloader/exthandler/mac/nsMIMEInfoMac.cpp @@ -69,19 +69,40 @@ nsMIMEInfoMac::LaunchWithURI(nsIURI* aURI) 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 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 app; if (application) { @@ -134,3 +155,51 @@ nsMIMEInfoMac::GetHasDefaultHandler(PRBool *_retval) 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 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; +} diff --git a/uriloader/exthandler/mac/nsMIMEInfoMac.h b/uriloader/exthandler/mac/nsMIMEInfoMac.h index 388d5b7c6e1..91f5e2a12e1 100755 --- a/uriloader/exthandler/mac/nsMIMEInfoMac.h +++ b/uriloader/exthandler/mac/nsMIMEInfoMac.h @@ -56,6 +56,9 @@ class nsMIMEInfoMac : public nsMIMEInfoImpl { return NS_ERROR_UNEXPECTED; } #endif + static NS_HIDDEN_(nsresult) OpenApplicationWithURI(nsIFile *aApplication, + const nsCString& aURI); + }; diff --git a/uriloader/exthandler/nsMIMEInfoImpl.cpp b/uriloader/exthandler/nsMIMEInfoImpl.cpp index ba44e9271fa..91a917a04bb 100644 --- a/uriloader/exthandler/nsMIMEInfoImpl.cpp +++ b/uriloader/exthandler/nsMIMEInfoImpl.cpp @@ -358,10 +358,26 @@ nsMIMEInfoBase::LaunchWithURI(nsIURI* aURI) 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)) { - return LaunchWithIProcess(executable, docToLoad); + // 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) @@ -389,9 +405,9 @@ nsMIMEInfoBase::CopyBasicDataTo(nsMIMEInfoBase* aOther) /* 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 process = do_CreateInstance(NS_PROCESS_CONTRACTID, &rv); @@ -401,13 +417,10 @@ nsMIMEInfoBase::LaunchWithIProcess(nsIFile* aApp, nsIFile* aFile) 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 */ @@ -450,6 +463,9 @@ 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); } diff --git a/uriloader/exthandler/nsMIMEInfoImpl.h b/uriloader/exthandler/nsMIMEInfoImpl.h index 1acfaba4fd5..bfa6f675322 100644 --- a/uriloader/exthandler/nsMIMEInfoImpl.h +++ b/uriloader/exthandler/nsMIMEInfoImpl.h @@ -140,16 +140,16 @@ class nsMIMEInfoBase : public nsIMIMEInfo { 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.