From 4f76352803e036a41f62c19e34aa981407b638aa Mon Sep 17 00:00:00 2001 From: "mscott%netscape.com" Date: Wed, 4 Oct 2000 06:54:47 +0000 Subject: [PATCH] Bug #51018, 44176, 47203 implement load group retargeting and stand alone progress window after we show the helper app dialog. So progress and load information is now retargeted to a stand alone window instead of re-using the underlying browser / mail window...In order to do this, the external app handler needed to implement nsIURIContentListener. sr=r=rpotts git-svn-id: svn://10.0.0.236/trunk@80335 18797224-902f-48f8-a5cc-f745e15eee43 --- .../exthandler/mac/nsOSHelperAppService.cpp | 8 +- .../exthandler/nsExternalHelperAppService.cpp | 197 +++++++++++++++++- .../exthandler/nsExternalHelperAppService.h | 22 +- .../nsIExternalHelperAppService.idl | 12 ++ .../exthandler/unix/nsOSHelperAppService.cpp | 25 +++ 5 files changed, 251 insertions(+), 13 deletions(-) diff --git a/mozilla/uriloader/exthandler/mac/nsOSHelperAppService.cpp b/mozilla/uriloader/exthandler/mac/nsOSHelperAppService.cpp index f94bc73c550..80c2e132a8c 100644 --- a/mozilla/uriloader/exthandler/mac/nsOSHelperAppService.cpp +++ b/mozilla/uriloader/exthandler/mac/nsOSHelperAppService.cpp @@ -109,16 +109,16 @@ NS_IMETHODIMP nsOSHelperAppService::DoContent(const char *aMimeContentType, nsIU // first, try to see if we can find the content based on just the specified content type... nsCOMPtr mimeInfo; rv = GetFromMIMEType(aMimeContentType, getter_AddRefs(mimeInfo)); - if (NS_FAILED(rv) || !mimeInfo) + // if we didn't find a match OR if the extesnion is a .bin, then use internet config... + if (NS_FAILED(rv) || !mimeInfo || strcmp(aMimeContentType, APPLICATION_OCTET_STREAM) == 0) { // if the content based search failed, then try looking up based on the file extension.... if (url) { nsXPIDLCString extension; url->GetFileExtension(getter_Copies(extension)); - const char * ext = (const char *) extension; - if (ext && *ext) - rv = GetFromExtension(ext, getter_AddRefs(mimeInfo)); + if (extension) + rv = GetFromExtension(extension, getter_AddRefs(mimeInfo)); } } diff --git a/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp b/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp index b7792994093..19ea2b9cf77 100644 --- a/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -31,6 +31,10 @@ #include "nsMemory.h" #include "nsIStreamListener.h" #include "nsIMIMEService.h" +#include "nsILoadGroup.h" +#include "nsCURILoader.h" +#include "nsIWebProgress.h" +#include "nsIWebProgressListener.h" // used to manage our in memory data source of helper applications #include "nsRDFCID.h" @@ -68,6 +72,8 @@ static nsDefaultMimeTypeEntry defaultMimeEntries [] = { TEXT_PLAIN, "txt,text", "Text File", 'TEXT', 'ttxt' }, #if defined(VMS) { APPLICATION_OCTET_STREAM, "exe,bin,sav,bck,pcsi,dcx_axpexe,dcx_vaxexe,sfx_axpexe,sfx_vaxexe", "Binary Executable", PRUint32(0x3F3F3F3F), PRUint32(0x3F3F3F3F) }, +#elif defined(XP_MAC) // don't define .bin on the mac...use internet config to look that up... + { APPLICATION_OCTET_STREAM, "exe", "Binary Executable", PRUint32(0x3F3F3F3F), PRUint32(0x3F3F3F3F) }, #else { APPLICATION_OCTET_STREAM, "exe,bin", "Binary Executable", PRUint32(0x3F3F3F3F), PRUint32(0x3F3F3F3F) }, #endif @@ -462,6 +468,8 @@ NS_INTERFACE_MAP_BEGIN(nsExternalAppHandler) NS_INTERFACE_MAP_ENTRY(nsIStreamListener) NS_INTERFACE_MAP_ENTRY(nsIStreamObserver) NS_INTERFACE_MAP_ENTRY(nsIHelperAppLauncher) + NS_INTERFACE_MAP_ENTRY(nsIURIContentListener) + NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) NS_INTERFACE_MAP_END_THREADSAFE nsExternalAppHandler::nsExternalAppHandler() @@ -479,6 +487,64 @@ nsExternalAppHandler::~nsExternalAppHandler() nsMemory::Free(mDataBuffer); } +NS_IMETHODIMP nsExternalAppHandler::GetInterface(const nsIID & aIID, void * *aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + return QueryInterface(aIID, aInstancePtr); +} + + +NS_IMETHODIMP nsExternalAppHandler::SetWebProgressListener(nsIWebProgressListener * aWebProgressListener) +{ + if (mLoadCookie) + { + nsCOMPtr webProgress(do_QueryInterface(mLoadCookie)); + + if (webProgress) + { + mWebProgressListener = aWebProgressListener; + webProgress->AddProgressListener(mWebProgressListener); + } + } + return NS_OK; +} + +NS_IMETHODIMP nsExternalAppHandler::GetDownloadInfo(nsIURI ** aSourceUrl, nsIFile ** aTarget) +{ + if (mFinalFileDestination) + { + *aTarget = mFinalFileDestination; + } + else + *aTarget = mTempFile; + + NS_IF_ADDREF(*aTarget); + + *aSourceUrl = mSourceUrl; + NS_IF_ADDREF(*aSourceUrl); + + return NS_OK; +} + +NS_IMETHODIMP nsExternalAppHandler::CloseProgressWindow() +{ + // make our docloader release the progress listener from the progress window... + if (mLoadCookie && mWebProgressListener) + { + nsCOMPtr webProgress(do_QueryInterface(mLoadCookie)); + + if (webProgress) + { + webProgress->RemoveProgressListener(mWebProgressListener); + } + } + + // release extra state... + mWebProgressListener = nsnull; + mLoadCookie = nsnull; + return NS_OK; +} + void nsExternalAppHandler::ExtractSuggestedFileNameFromChannel(nsIChannel * aChannel) { // if the channel is an http channel and we have a content disposition header set, @@ -512,7 +578,7 @@ void nsExternalAppHandler::ExtractSuggestedFileNameFromChannel(nsIChannel * aCha dispFileName.Truncate(pos); // ONLY if we got here, will we remember the suggested file name... - mHTTPSuggestedFileName.AssignWithConversion(dispFileName); + mSuggestedFileName.AssignWithConversion(dispFileName); } } // if we found a file name in the header disposition field } // we had a disp header @@ -520,6 +586,31 @@ void nsExternalAppHandler::ExtractSuggestedFileNameFromChannel(nsIChannel * aCha } // if we had an http channel } +nsresult nsExternalAppHandler::RetargetLoadNotifications(nsIChannel * aChannel) +{ + // we are going to run the downloading of the helper app in our own little docloader / load group context. + // so go ahead and force the creation of a load group and doc loader for us to use... + nsresult rv = NS_OK; + + nsCOMPtr uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID)); + NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE); + + nsCOMPtr newLoadGroup; + nsCOMPtr oldLoadGroup; + uriLoader->GetLoadGroupForContext(NS_STATIC_CAST(nsIURIContentListener*, this), getter_AddRefs(newLoadGroup)); + aChannel->GetLoadGroup(getter_AddRefs(oldLoadGroup)); + + if(oldLoadGroup) + oldLoadGroup->RemoveChannel(aChannel, nsnull, NS_OK, nsnull); + + aChannel->SetLoadGroup(newLoadGroup); + nsCOMPtr req (do_QueryInterface(mLoadCookie)); + aChannel->SetNotificationCallbacks(req); + rv = newLoadGroup->AddChannel(aChannel, nsnull); + + return rv; +} + nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel * aChannel) { nsresult rv = NS_OK; @@ -547,8 +638,8 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel * aChannel) #endif nsCOMPtr uri; - aChannel->GetURI(getter_AddRefs(uri)); - nsCOMPtr url = do_QueryInterface(uri); + aChannel->GetURI(getter_AddRefs(mSourceUrl)); + nsCOMPtr url = do_QueryInterface(mSourceUrl); nsCAutoString tempLeafName; @@ -561,6 +652,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel * aChannel) if (leafName) { tempLeafName = leafName; + + // store the file name in the url so we can present it as a "suggested" file name when + // we prompt the user... + if (!tempLeafName.IsEmpty()) + mSuggestedFileName.AssignWithConversion(tempLeafName); + // strip off whatever extension this file may have and force our own extension. PRInt32 pos = tempLeafName.RFindCharInSet("."); if (pos > 0) @@ -598,6 +695,9 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIChannel * aChannel, nsISup return aChannel->Cancel(NS_BINDING_ABORTED); nsresult rv = SetUpTempFile(aChannel); + // retarget all load notifcations to our docloader instead of the original window's docloader... + RetargetLoadNotifications(aChannel); + // ignore failure... ExtractSuggestedFileNameFromChannel(aChannel); // now that the temp file is set up, find out if we need to invoke a dialog asking the user what @@ -698,6 +798,7 @@ nsresult nsExternalAppHandler::Init(nsIMIMEInfo * aMIMEInfo, const char * aTempF if (aTempFileExtension && *aTempFileExtension != '.') mTempFileExtension = "."; mTempFileExtension.Append(aTempFileExtension); + return NS_OK; } @@ -708,6 +809,18 @@ NS_IMETHODIMP nsExternalAppHandler::GetMIMEInfo(nsIMIMEInfo ** aMIMEInfo) return NS_OK; } +nsresult nsExternalAppHandler::ShowProgressDialog() +{ + // we are back from the helper app dialog (where the user chooses to save or open), but we aren't + // done processing the load. in this case, throw up a progress dialog so the user can see what's going on... + nsresult rv = NS_OK; + nsCOMPtr dlgService( do_GetService(NS_IHELPERAPPLAUNCHERDLG_CONTRACTID, &rv)); + if ( dlgService ) + dlgService->ShowProgressDialog(this, mWindowContext); + + return rv; +} + nsresult nsExternalAppHandler::PromptForSaveToFile(nsILocalFile ** aNewFile, const PRUnichar * aDefaultFile) { // invoke the dialog!!!!! use mWindowContext as the window context parameter for the dialog service @@ -715,7 +828,7 @@ nsresult nsExternalAppHandler::PromptForSaveToFile(nsILocalFile ** aNewFile, con nsresult rv = NS_OK; if ( dlgService ) rv = dlgService->PromptForSaveToFile(mWindowContext, aDefaultFile, NS_ConvertASCIItoUCS2(mTempFileExtension).get(), aNewFile); - + return rv; } @@ -730,10 +843,10 @@ NS_IMETHODIMP nsExternalAppHandler::SaveToDisk(nsIFile * aNewFileLocation, PRBoo { nsXPIDLString leafName; mTempFile->GetUnicodeLeafName(getter_Copies(leafName)); - if (mHTTPSuggestedFileName.IsEmpty()) + if (mSuggestedFileName.IsEmpty()) rv = PromptForSaveToFile(getter_AddRefs(fileToUse), leafName); else - rv = PromptForSaveToFile(getter_AddRefs(fileToUse), mHTTPSuggestedFileName.GetUnicode()); + rv = PromptForSaveToFile(getter_AddRefs(fileToUse), mSuggestedFileName.GetUnicode()); if (NS_FAILED(rv)) return Cancel(); @@ -743,6 +856,7 @@ NS_IMETHODIMP nsExternalAppHandler::SaveToDisk(nsIFile * aNewFileLocation, PRBoo fileToUse = do_QueryInterface(aNewFileLocation); mReceivedDispostionInfo = PR_TRUE; + // if the on stop request was actually issued then it's now time to actually perform the file move.... if (mStopRequestIssued && fileToUse) { @@ -756,6 +870,10 @@ NS_IMETHODIMP nsExternalAppHandler::SaveToDisk(nsIFile * aNewFileLocation, PRBoo rv = mTempFile->MoveTo(directoryLocation, fileName); } } + else + { + ShowProgressDialog(); + } return rv; } @@ -779,6 +897,10 @@ NS_IMETHODIMP nsExternalAppHandler::LaunchWithApplication(nsIFile * aApplication rv = helperAppService->LaunchAppWithTempFile(mMimeInfo, mTempFile); } } + else + { + ShowProgressDialog(); + } return NS_OK; } @@ -799,6 +921,69 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel() mTempFile->Delete(PR_TRUE); mTempFile = nsnull; } + + return NS_OK; +} + + +// nsIURIContentListener implementation +NS_IMETHODIMP nsExternalAppHandler::OnStartURIOpen(nsIURI* aURI, const char* aWindowTarget, PRBool* aAbortOpen) +{ + return NS_OK; +} + +NS_IMETHODIMP nsExternalAppHandler::GetProtocolHandler(nsIURI *aURI, nsIProtocolHandler **aProtocolHandler) +{ + *aProtocolHandler = nsnull; + return NS_OK; +} + +NS_IMETHODIMP nsExternalAppHandler::IsPreferred(const char * aContentType, nsURILoadCommand aCommand, const char * aWindowTarget, + char ** aDesiredContentType, PRBool * aCanHandleContent) + +{ + NS_NOTREACHED("IsPreferred"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsExternalAppHandler::CanHandleContent(const char * aContentType, nsURILoadCommand aCommand, + const char * aWindowTarget, char ** aDesiredContentType, + PRBool * aCanHandleContent) + +{ + NS_NOTREACHED("CanHandleContent"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsExternalAppHandler::DoContent(const char * aContentType, nsURILoadCommand aCommand, const char * aWindowTarget, + nsIChannel * aOpenedChannel, + nsIStreamListener ** aContentHandler,PRBool * aAbortProcess) +{ + NS_NOTREACHED("DoContent"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsExternalAppHandler::GetParentContentListener(nsIURIContentListener** aParent) +{ + *aParent = nsnull; + return NS_OK; +} + +NS_IMETHODIMP nsExternalAppHandler::SetParentContentListener(nsIURIContentListener* aParent) +{ + return NS_OK; +} + +NS_IMETHODIMP nsExternalAppHandler::GetLoadCookie(nsISupports ** aLoadCookie) +{ + *aLoadCookie = mLoadCookie; + NS_IF_ADDREF(*aLoadCookie); + return NS_OK; +} + +NS_IMETHODIMP nsExternalAppHandler::SetLoadCookie(nsISupports * aLoadCookie) +{ + mLoadCookie = aLoadCookie; return NS_OK; } diff --git a/mozilla/uriloader/exthandler/nsExternalHelperAppService.h b/mozilla/uriloader/exthandler/nsExternalHelperAppService.h index 78da8e1a28b..775ca96ec17 100644 --- a/mozilla/uriloader/exthandler/nsExternalHelperAppService.h +++ b/mozilla/uriloader/exthandler/nsExternalHelperAppService.h @@ -25,6 +25,8 @@ #include "nsIExternalHelperAppService.h" #include "nsIExternalProtocolService.h" +#include "nsIURIContentListener.h" +#include "nsIWebProgressListener.h" #include "nsIMIMEInfo.h" #include "nsIMIMEService.h" @@ -129,13 +131,16 @@ struct nsDefaultMimeTypeEntry { // to write the data into the output stream representing the temp file... #define DATA_BUFFER_SIZE (4096*2) -class nsExternalAppHandler : public nsIStreamListener, public nsIHelperAppLauncher +class nsExternalAppHandler : public nsIStreamListener, public nsIHelperAppLauncher, public nsIURIContentListener, + public nsIInterfaceRequestor { public: NS_DECL_ISUPPORTS NS_DECL_NSISTREAMLISTENER NS_DECL_NSISTREAMOBSERVER NS_DECL_NSIHELPERAPPLAUNCHER + NS_DECL_NSIURICONTENTLISTENER + NS_DECL_NSIINTERFACEREQUESTOR nsExternalAppHandler(); virtual ~nsExternalAppHandler(); @@ -144,13 +149,14 @@ public: protected: nsCOMPtr mTempFile; + nsCOMPtr mSourceUrl; nsCString mTempFileExtension; nsCOMPtr mMimeInfo; nsCOMPtr mOutStream; // output stream to the temp file... nsCOMPtr mWindowContext; // the following field is set if we were processing an http channel that had a content disposition header // which specified the SUGGESTED file name we should present to the user in the save to disk dialog. - nsString mHTTPSuggestedFileName; + nsString mSuggestedFileName; // the canceled flag is set if the user canceled the launching of this application before we finished // saving the data to a temp file... @@ -168,10 +174,20 @@ protected: char * mDataBuffer; nsresult SetUpTempFile(nsIChannel * aChannel); + // when we download a helper app, we are going to retarget all load notifications into our own docloader + // and load group instead of using the window which initiated the load....RetargetLoadNotifications contains + // that information... + nsresult RetargetLoadNotifications(nsIChannel * aChannel); + // if the user tells us how they want to dispose of the content and we still haven't finished downloading while + // they were deciding, then throw a progress dialog so they know what's going on... + nsresult ShowProgressDialog(); nsresult PromptForSaveToFile(nsILocalFile ** aNewFile, const PRUnichar * aDefaultFile); - // if the passed in channel is an nsIHTTPChannel, we'll attempt to extrace a suggested file name + // if the passed in channel is an nsIHTTPChannel, we'll attempt to extract a suggested file name // from the content disposition header... void ExtractSuggestedFileNameFromChannel(nsIChannel * aChannel); + + nsCOMPtr mLoadCookie; // load cookie used by the uri loader when we fetch the url + nsCOMPtr mWebProgressListener; }; #endif // nsExternalHelperAppService_h__ diff --git a/mozilla/uriloader/exthandler/nsIExternalHelperAppService.idl b/mozilla/uriloader/exthandler/nsIExternalHelperAppService.idl index cd1f493561a..c78ee21e569 100644 --- a/mozilla/uriloader/exthandler/nsIExternalHelperAppService.idl +++ b/mozilla/uriloader/exthandler/nsIExternalHelperAppService.idl @@ -30,6 +30,7 @@ interface nsIURI; interface nsIStreamListener; interface nsIFile; interface nsIMIMEInfo; +interface nsIWebProgressListener; [scriptable, uuid(663CC0AA-42EA-11d4-98D0-001083010E9B)] @@ -86,4 +87,15 @@ interface nsIHelperAppLauncher : nsISupports // called if the user decides to cancel the handling of this content type void Cancel(); + + // the following methods are used by the progress dialog to get or set information + // on the current helper app launcher download + void setWebProgressListener(in nsIWebProgressListener aWebProgressListener); + // when the stand along progress window actually closes, it calls this method + // so we can release any local state... + void closeProgressWindow(); + + // aSourceUrl--> the url we are downloading....and the file we are saving too + nsIFile getDownloadInfo(out nsIURI aSourceUrl); + }; diff --git a/mozilla/uriloader/exthandler/unix/nsOSHelperAppService.cpp b/mozilla/uriloader/exthandler/unix/nsOSHelperAppService.cpp index 9882e0e23fa..c149ac8c259 100644 --- a/mozilla/uriloader/exthandler/unix/nsOSHelperAppService.cpp +++ b/mozilla/uriloader/exthandler/unix/nsOSHelperAppService.cpp @@ -65,7 +65,32 @@ NS_IMETHODIMP nsOSHelperAppService::DoContent(const char *aMimeContentType, nsIU if (NS_SUCCEEDED(rv)) return NS_OK; // there is no registry on linux (like there is on win32) + // so we can only make up a dummy mime type for this content.... + nsCOMPtr mimeInfo (do_CreateInstance(NS_MIMEINFO_CONTRACTID)); + nsCAutoString fileExtension; + *aStreamListener = nsnull; + if (aURI) + { + nsCOMPtr url = do_QueryInterface(aURI); + nsXPIDLCString extenion; + url->GetFileExtension(getter_Copies(extenion)); + + fileExtension = "."; + fileExtension.Append(extenion); + } + + if (mimeInfo) + { + if (!fileExtension.IsEmpty()) + mimeInfo->SetFileExtensions(fileExtension); + mimeInfo->SetMIMEType(aMimeContentType); + + // this code is incomplete and just here to get things started.. + nsExternalAppHandler * handler = CreateNewExternalHandler(mimeInfo, fileExtension, aWindowContext); + handler->QueryInterface(NS_GET_IID(nsIStreamListener), (void **) aStreamListener); + } + return NS_OK; }