Back to index

lightning-sunbird  0.9+nobinonly
Public Member Functions | Public Attributes | Protected Types | Protected Member Functions | Protected Attributes
nsExternalAppHandler Class Reference

An external app handler is just a small little class that presents itself as a nsIStreamListener. More...

#include <nsExternalHelperAppService.h>

Inheritance diagram for nsExternalAppHandler:
Inheritance graph
[legend]
Collaboration diagram for nsExternalAppHandler:
Collaboration graph
[legend]

List of all members.

Public Member Functions

NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSIHELPERAPPLAUNCHER
NS_DECL_NSICANCELABLE
NS_DECL_NSITIMERCALLBACK 
nsExternalAppHandler (nsIMIMEInfo *aMIMEInfo, const nsCSubstring &aFileExtension, nsIInterfaceRequestor *aWindowContext, const nsAString &aFilename, PRUint32 aReason)
 ~nsExternalAppHandler ()
void onDataAvailable (in nsIRequest aRequest, in nsISupports aContext, in nsIInputStream aInputStream, in unsigned long aOffset, in unsigned long aCount)
 Called when the next chunk of data (corresponding to the request) may be read without blocking the calling thread.
void onStartRequest (in nsIRequest aRequest, in nsISupports aContext)
 Called to signify the beginning of an asynchronous request.
void onStopRequest (in nsIRequest aRequest, in nsISupports aContext, in nsresult aStatusCode)
 Called to signify the end of an asynchronous request.
void saveToDisk (in nsIFile aNewFileLocation, in boolean aRememberThisPreference)
 Called when we want to just save the content to a particular file.
void launchWithApplication (in nsIFile aApplication, in boolean aRememberThisPreference)
 Use aApplication to launch with this content.
void setWebProgressListener (in nsIWebProgressListener2 aWebProgressListener)
 The following methods are used by the progress dialog to get or set information on the current helper app launcher download.
void closeProgressWindow ()
 when the stand alone progress window actually closes, it calls this method so we can release any local state...
void cancel (in nsresult aReason)
 Call this method to request that this object abort whatever operation it may be performing.
void notify (in nsITimer timer)

Public Attributes

readonly attribute nsIMIMEInfo MIMEInfo
 The mime info object associated with the content type this helper app launcher is currently attempting to load.
readonly attribute nsIURI source
 The source uri.
readonly attribute AString suggestedFileName
 The suggested name for this file.
readonly attribute nsIFile targetFile
 The file we are saving to.
readonly attribute PRTime timeDownloadStarted
 Time when the download started.

Protected Types

enum  ErrorType { kReadError, kWriteError, kLaunchError }

Protected Member Functions

nsresult SetUpTempFile (nsIChannel *aChannel)
 Creates the temporary file for the download and an output stream for it.
void RetargetLoadNotifications (nsIRequest *request)
 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 CreateProgressListener ()
 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 create a progress listener of some kind so they know what's going on...
nsresult PromptForSaveToFile (nsILocalFile **aNewFile, const nsAFlatString &aDefaultFile, const nsAFlatString &aDefaultFileExt)
void ProcessAnyRefreshTags ()
 After we're done prompting the user for any information, if the original channel had a refresh url associated with it (which might point to a "thank you for downloading" kind of page, then process that....It is safe to invoke this method multiple times.
nsresult MoveFile (nsIFile *aNewFileLocation)
 An internal method used to actually move the temp file to the final destination once we done receiving data AND have showed the progress dialog.
nsresult OpenWithApplication ()
 An internal method used to actually launch a helper app given the temp file once we are done receiving data AND have showed the progress dialog.
nsresult ExecuteDesiredAction ()
 Helper routine which peaks at the mime action specified by mMimeInfo and calls either MoveFile or OpenWithApplication.
PRBool GetNeverAskFlagFromPref (const char *prefName, const char *aContentType)
 Helper routine that searches a pref string for a given mime type.
nsresult InitializeDownload (nsITransfer *)
 Initialize an nsITransfer object for use as a progress object.
void EnsureSuggestedFileName ()
 Helper routine to ensure mSuggestedFileName is "correct"; this ensures that mTempFileExtension only contains an extension when it is different from mSuggestedFileName's extension.
void SendStatusChange (ErrorType type, nsresult aStatus, nsIRequest *aRequest, const nsAFlatString &path)
 Utility function to send proper error notification to web progress listener.
nsresult MaybeCloseWindow ()
 Closes the window context if it does not have a refresh header and it never displayed content before the external helper app service was invoked.

Protected Attributes

nsCOMPtr< nsIFilemTempFile
nsCOMPtr< nsIURImSourceUrl
nsString mTempFileExtension
nsCOMPtr< nsIMIMEInfomMimeInfo
 The MIME Info for this load.
nsCOMPtr< nsIOutputStreammOutStream
 output stream to the temp file
nsCOMPtr< nsIInterfaceRequestormWindowContext
nsCOMPtr< nsIDOMWindowInternalmWindowToClose
 Used to close the window on a timer, to avoid any exceptions that are thrown if we try to close the window before it's fully loaded.
nsCOMPtr< nsITimermTimer
nsString mSuggestedFileName
 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.
PRPackedBool mCanceled
 The canceled flag is set if the user canceled the launching of this application before we finished saving the data to a temp file.
PRPackedBool mShouldCloseWindow
 This is set based on whether the channel indicates that a new window was opened specifically for this download.
PRPackedBool mReceivedDispositionInfo
 have we received information from the user about how they want to dispose of this content
PRPackedBool mStopRequestIssued
PRPackedBool mProgressListenerInitialized
PRUint32 mReason
 One of the REASON_ constants from nsIHelperAppLauncherDialog.
PRTime mTimeDownloadStarted
nsInt64 mContentLength
nsInt64 mProgress
 Number of bytes received (for sending progress notifications).
nsCOMPtr< nsIFilemFinalFileDestination
 When we are told to save the temp file to disk (in a more permament location) before we are done writing the content to a temp file, then we need to remember the final destination until we are ready to use it.
char mDataBuffer [DATA_BUFFER_SIZE]
nsCOMPtr< nsIWebProgressListener2mWebProgressListener
nsCOMPtr< nsIChannelmOriginalChannel
 in the case of a redirect, this will be the pre-redirect channel.
nsCOMPtr
< nsIHelperAppLauncherDialog
mDialog
nsIRequestmRequest
 The request that's being loaded.

Detailed Description

An external app handler is just a small little class that presents itself as a nsIStreamListener.

It saves the incoming data into a temp file. The handler is bound to an application when it is created. When it receives an OnStopRequest it launches the application using the temp file it has stored the data into. We create a handler every time we have to process data using a helper app.

Definition at line 325 of file nsExternalHelperAppService.h.


Member Enumeration Documentation

Enumerator:
kReadError 
kWriteError 
kLaunchError 

Definition at line 486 of file nsExternalHelperAppService.h.


Constructor & Destructor Documentation

NS_INTERFACE_MAP_END_THREADSAFE nsExternalAppHandler::nsExternalAppHandler ( nsIMIMEInfo aMIMEInfo,
const nsCSubstring aFileExtension,
nsIInterfaceRequestor aWindowContext,
const nsAString &  aFilename,
PRUint32  aReason 
)
Parameters:
aMIMEInfoMIMEInfo object, representing the type of the content that should be handled
aFileExtensionThe extension we need to append to our temp file, INCLUDING the ".". e.g. .mp3
aWindowContextWindow context, as passed to DoContent
aFileNameThe filename to use
aReasonA constant from nsIHelperAppLauncherDialog indicating why the request is handled by a helper app.

Definition at line 1419 of file nsExternalHelperAppService.cpp.

: mMimeInfo(aMIMEInfo)
, mWindowContext(aWindowContext)
, mWindowToClose(nsnull)
, mSuggestedFileName(aSuggestedFilename)
, mCanceled(PR_FALSE)
, mShouldCloseWindow(PR_FALSE)
, mReceivedDispositionInfo(PR_FALSE)
, mStopRequestIssued(PR_FALSE)
, mProgressListenerInitialized(PR_FALSE)
, mReason(aReason)
, mContentLength(-1)
, mProgress(0)
, mRequest(nsnull)
{

  // make sure the extention includes the '.'
  if (!aTempFileExtension.IsEmpty() && aTempFileExtension.First() != '.')
    mTempFileExtension = PRUnichar('.');
  AppendUTF8toUTF16(aTempFileExtension, mTempFileExtension);

  // replace platform specific path separator and illegal characters to avoid any confusion
  mSuggestedFileName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '-');
  mTempFileExtension.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '-');
  
  // Make sure extension is correct.
  EnsureSuggestedFileName();

  sSrv->AddRef();
}

Here is the call graph for this function:

Definition at line 1454 of file nsExternalHelperAppService.cpp.

{
  // Not using NS_RELEASE, since we don't want to set sSrv to NULL
  sSrv->Release();
}

Member Function Documentation

void nsICancelable::cancel ( in nsresult  aReason) [inherited]

Call this method to request that this object abort whatever operation it may be performing.

Parameters:
aReasonPass a failure code to indicate the reason why this operation is being canceled. It is an error to pass a success code.

when the stand alone progress window actually closes, it calls this method so we can release any local state...

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 create a progress listener of some kind so they know what's going on...

Definition at line 2214 of file nsExternalHelperAppService.cpp.

{
  // 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...
  // Also, release our reference to mDialog. We don't need it anymore, and we
  // need to break the reference cycle.
  mDialog = nsnull;
  nsresult rv;
  
  nsCOMPtr<nsITransfer> tr = do_CreateInstance(NS_TRANSFER_CONTRACTID, &rv);
  if (NS_SUCCEEDED(rv))
    InitializeDownload(tr);

  if (tr)
    tr->OnStateChange(nsnull, mRequest, nsIWebProgressListener::STATE_START, NS_OK);

  // note we might not have a listener here if the QI() failed, or if
  // there is no nsITransfer object, but we still call
  // SetWebProgressListener() to make sure our progress state is sane
  // NOTE: This will set up a reference cycle (this nsITransfer has us set up as
  // its observer). This cycle will be broken in Cancel, CloseProgressWindow or
  // OnStopRequest.
  SetWebProgressListener(tr);

  return rv;
}

Here is the call graph for this function:

Helper routine to ensure mSuggestedFileName is "correct"; this ensures that mTempFileExtension only contains an extension when it is different from mSuggestedFileName's extension.

Make mTempFileExtension contain an extension exactly when its previous value is different from mSuggestedFileName's extension, so that it can be appended to mSuggestedFileName and form a valid, useful leaf name.

This is required so that the (renamed) temporary file has the correct extension after downloading to make sure the OS will launch the application corresponding to the MIME type (which was used to calculate mTempFileExtension). This prevents a cgi-script named foobar.exe that returns application/zip from being named foobar.exe and executed as an executable file. It also blocks content that a web site might provide with a content-disposition header indicating filename="foobar.exe" from being downloaded to a file with extension .exe and executed.

Definition at line 1559 of file nsExternalHelperAppService.cpp.

{
  // Make sure there is a mTempFileExtension (not "" or ".").
  // Remember that mTempFileExtension will always have the leading "."
  // (the check for empty is just to be safe).
  if (mTempFileExtension.Length() > 1)
  {
    // Get mSuggestedFileName's current extension.
    nsAutoString fileExt;
    PRInt32 pos = mSuggestedFileName.RFindChar('.');
    if (pos != kNotFound)
      mSuggestedFileName.Right(fileExt, mSuggestedFileName.Length() - pos);

    // Now, compare fileExt to mTempFileExtension.
    if (fileExt.Equals(mTempFileExtension, nsCaseInsensitiveStringComparator()))
    {
      // Matches -> mTempFileExtension can be empty
      mTempFileExtension.Truncate();
    }
  }
}

Helper routine which peaks at the mime action specified by mMimeInfo and calls either MoveFile or OpenWithApplication.

Definition at line 2127 of file nsExternalHelperAppService.cpp.

{
  nsresult rv = NS_OK;
  if (mProgressListenerInitialized && !mCanceled)
  {
    nsMIMEInfoHandleAction action = nsIMIMEInfo::saveToDisk;
    mMimeInfo->GetPreferredAction(&action);
    if (action == nsIMIMEInfo::useHelperApp ||
        action == nsIMIMEInfo::useSystemDefault)
    {
      // Make sure the suggested name is unique since in this case we don't
      // have a file name that was guaranteed to be unique by going through
      // the File Save dialog
      rv = mFinalFileDestination->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
      if (NS_SUCCEEDED(rv))
      {
        // Source and dest dirs should be == so this should just do a rename
        rv = MoveFile(mFinalFileDestination);
        if (NS_SUCCEEDED(rv))
          rv = OpenWithApplication();
      }
    }
    else // Various unknown actions go here too
    {
      // XXX Put progress dialog in barber-pole mode
      //     and change text to say "Copying from:".
      rv = MoveFile(mFinalFileDestination);
      if (NS_SUCCEEDED(rv) && action == nsIMIMEInfo::saveToDisk)
      {
        nsCOMPtr<nsILocalFile> destfile(do_QueryInterface(mFinalFileDestination));
        sSrv->FixFilePermissions(destfile);
      }
    }
    
    // Notify dialog that download is complete.
    // By waiting till this point, it ensures that the progress dialog doesn't indicate
    // success until we're really done.
    if(mWebProgressListener)
    {
      if (!mCanceled)
      {
        mWebProgressListener->OnProgressChange64(nsnull, nsnull, mContentLength, mContentLength, mContentLength, mContentLength);
      }
      mWebProgressListener->OnStateChange(nsnull, nsnull, nsIWebProgressListener::STATE_STOP, NS_OK);
    }
  }
  
  return rv;
}

Here is the call graph for this function:

PRBool nsExternalAppHandler::GetNeverAskFlagFromPref ( const char *  prefName,
const char *  aContentType 
) [protected]

Helper routine that searches a pref string for a given mime type.

Definition at line 2610 of file nsExternalHelperAppService.cpp.

{
  // Search the obsolete pref strings.
  nsresult rv;
  nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
  nsCOMPtr<nsIPrefBranch> prefBranch;
  if (prefs)
    rv = prefs->GetBranch(NEVER_ASK_PREF_BRANCH, getter_AddRefs(prefBranch));
  if (NS_SUCCEEDED(rv) && prefBranch)
  {
    nsXPIDLCString prefCString;
    nsCAutoString prefValue;
    rv = prefBranch->GetCharPref(prefName, getter_Copies(prefCString));
    if (NS_SUCCEEDED(rv) && !prefCString.IsEmpty())
    {
      NS_UnescapeURL(prefCString);
      nsACString::const_iterator start, end;
      prefCString.BeginReading(start);
      prefCString.EndReading(end);
      if (CaseInsensitiveFindInReadable(nsDependentCString(aContentType), start, end))
        return PR_FALSE;
    }
  }
  // Default is true, if not found in the pref string.
  return PR_TRUE;
}

Here is the call graph for this function:

Initialize an nsITransfer object for use as a progress object.

Definition at line 2198 of file nsExternalHelperAppService.cpp.

{
  nsresult rv;
  
  nsCOMPtr<nsIURI> target;
  rv = NS_NewFileURI(getter_AddRefs(target), mFinalFileDestination);
  if (NS_FAILED(rv)) return rv;
  
  nsCOMPtr<nsILocalFile> lf(do_QueryInterface(mTempFile));
  rv = aTransfer->Init(mSourceUrl, target, EmptyString(),
                       mMimeInfo, mTimeDownloadStarted, lf, this);
  if (NS_FAILED(rv)) return rv;

  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsIHelperAppLauncher::launchWithApplication ( in nsIFile  aApplication,
in boolean  aRememberThisPreference 
) [inherited]

Use aApplication to launch with this content.

NOTE: This will release the reference to the nsIHelperAppLauncherDialog.

Parameters:
aApplicationnsIFile corresponding to the location of the application to use.
aRememberThisPreferenceTRUE if we should remember this choice.

Closes the window context if it does not have a refresh header and it never displayed content before the external helper app service was invoked.

Definition at line 2637 of file nsExternalHelperAppService.cpp.

{
  nsCOMPtr<nsIDOMWindow> window(do_GetInterface(mWindowContext));
  nsCOMPtr<nsIDOMWindowInternal> internalWindow = do_QueryInterface(window);
  NS_ENSURE_STATE(internalWindow);

  if (mShouldCloseWindow) {
    // Reset the window context to the opener window so that the dependent
    // dialogs have a parent
    nsCOMPtr<nsIDOMWindowInternal> opener;
    internalWindow->GetOpener(getter_AddRefs(opener));

    PRBool isClosed;
    if (opener && NS_SUCCEEDED(opener->GetClosed(&isClosed)) && !isClosed) {
      mWindowContext = do_GetInterface(opener);

      // Now close the old window.  Do it on a timer so that we don't run
      // into issues trying to close the window before it has fully opened.
      NS_ASSERTION(!mTimer, "mTimer was already initialized once!");
      mTimer = do_CreateInstance("@mozilla.org/timer;1");
      if (!mTimer) {
        return NS_ERROR_FAILURE;
      }

      mTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT);
      mWindowToClose = internalWindow;
    }
  }

  return NS_OK;
}

Here is the call graph for this function:

nsresult nsExternalAppHandler::MoveFile ( nsIFile aNewFileLocation) [protected]

An internal method used to actually move the temp file to the final destination once we done receiving data AND have showed the progress dialog.

Definition at line 2272 of file nsExternalHelperAppService.cpp.

{
  nsresult rv = NS_OK;
  NS_ASSERTION(mStopRequestIssued, "uhoh, how did we get here if we aren't done getting data?");
 
  nsCOMPtr<nsILocalFile> fileToUse = do_QueryInterface(aNewFileLocation);

  // if the on stop request was actually issued then it's now time to actually perform the file move....
  if (mStopRequestIssued && fileToUse)
  {
    // Unfortunately, MoveTo will fail if a file already exists at the user specified location....
    // but the user has told us, this is where they want the file! (when we threw up the save to file dialog,
    // it told them the file already exists and do they wish to over write it. So it should be okay to delete
    // fileToUse if it already exists.
    PRBool equalToTempFile = PR_FALSE;
    PRBool filetoUseAlreadyExists = PR_FALSE;
    fileToUse->Equals(mTempFile, &equalToTempFile);
    fileToUse->Exists(&filetoUseAlreadyExists);
    if (filetoUseAlreadyExists && !equalToTempFile)
      fileToUse->Remove(PR_FALSE);

     // extract the new leaf name from the file location
     nsAutoString fileName;
     fileToUse->GetLeafName(fileName);
     nsCOMPtr<nsIFile> directoryLocation;
     rv = fileToUse->GetParent(getter_AddRefs(directoryLocation));
     if (directoryLocation)
     {
       rv = mTempFile->MoveTo(directoryLocation, fileName);
     }
     if (NS_FAILED(rv))
     {
       // Send error notification.        
       nsAutoString path;
       fileToUse->GetPath(path);
       SendStatusChange(kWriteError, rv, nsnull, path);
       Cancel(rv); // Cancel (and clean up temp file).
     }
#if defined(XP_OS2)
     else
     {
       // tag the file with its source URI
       nsCOMPtr<nsILocalFileOS2> localFileOS2 = do_QueryInterface(fileToUse);
       if (localFileOS2)
       {
         nsCAutoString url;
         mSourceUrl->GetSpec(url);
         localFileOS2->SetFileSource(url);
       }
     }
#endif
  }

  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsITimerCallback::notify ( in nsITimer  timer) [inherited]
Parameters:
aTimerthe timer which has expired
void nsIStreamListener::onDataAvailable ( in nsIRequest  aRequest,
in nsISupports  aContext,
in nsIInputStream  aInputStream,
in unsigned long  aOffset,
in unsigned long  aCount 
) [inherited]

Called when the next chunk of data (corresponding to the request) may be read without blocking the calling thread.

The onDataAvailable impl must read exactly |aCount| bytes of data before returning.

Parameters:
aRequestrequest corresponding to the source of the data
aContextuser defined context
aInputStreaminput stream containing the data chunk
aOffsetNumber of bytes that were sent in previous onDataAvailable calls for this request. In other words, the sum of all previous count parameters. If that number is greater than or equal to 2^32, this parameter will be PR_UINT32_MAX (2^32 - 1).
aCountnumber of bytes available in the stream

NOTE: The aInputStream parameter must implement readSegments.

An exception thrown from onDataAvailable has the side-effect of causing the request to be canceled.

void nsIRequestObserver::onStartRequest ( in nsIRequest  aRequest,
in nsISupports  aContext 
) [inherited]

Called to signify the beginning of an asynchronous request.

Parameters:
aRequestrequest being observed
aContextuser defined context

An exception thrown from onStartRequest has the side-effect of causing the request to be canceled.

Here is the caller graph for this function:

void nsIRequestObserver::onStopRequest ( in nsIRequest  aRequest,
in nsISupports  aContext,
in nsresult  aStatusCode 
) [inherited]

Called to signify the end of an asynchronous request.

This call is always preceded by a call to onStartRequest.

Parameters:
aRequestrequest being observed
aContextuser defined context
aStatusCodereason for stopping (NS_OK if completed successfully)

An exception thrown from onStopRequest is generally ignored.

Here is the caller graph for this function:

An internal method used to actually launch a helper app given the temp file once we are done receiving data AND have showed the progress dialog.

Uses the application specified in the mime info.

Definition at line 2421 of file nsExternalHelperAppService.cpp.

{
  nsresult rv = NS_OK;
  if (mCanceled)
    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)
  {
    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.
    }
    else
    {
      PRBool deleteTempFileOnExit;
      nsresult result = NS_ERROR_NOT_AVAILABLE;  // don't return this!
      nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
      if (prefs) {
        result = prefs->GetBoolPref("browser.helperApps.deleteTempFileOnExit",
                                    &deleteTempFileOnExit);
      }
      if (NS_FAILED(result)) {
        // No pref set; use default value
#if !defined(XP_MAC) && !defined (XP_MACOSX)
          // Mac users have been very verbal about temp files being deleted on
          // app exit - they don't like it - but we'll continue to do this on
          // other platforms for now.
        deleteTempFileOnExit = PR_TRUE;
#else
        deleteTempFileOnExit = PR_FALSE;
#endif
      }
      if (deleteTempFileOnExit) {
        NS_ASSERTION(sSrv, "Service gone away!?");
        sSrv->DeleteTemporaryFileOnExit(mFinalFileDestination);
      }
    }
  }

  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

After we're done prompting the user for any information, if the original channel had a refresh url associated with it (which might point to a "thank you for downloading" kind of page, then process that....It is safe to invoke this method multiple times.

We'll clear mOriginalChannel after it's called and this ensures we won't call it again....

Definition at line 2591 of file nsExternalHelperAppService.cpp.

{
   // one last thing, try to see if the original window context supports a refresh interface...
   // Sometimes, when you download content that requires an external handler, there is
   // a refresh header associated with the download. This refresh header points to a page
   // the content provider wants the user to see after they download the content. How do we
   // pass this refresh information back to the caller? For now, try to get the refresh URI 
   // interface. If the window context where the request originated came from supports this
   // then we can force it to process the refresh information (if there is any) from this channel.
   if (mWindowContext && mOriginalChannel)
   {
     nsCOMPtr<nsIRefreshURI> refreshHandler (do_GetInterface(mWindowContext));
     if (refreshHandler) {
        refreshHandler->SetupRefreshURI(mOriginalChannel);
     }
     mOriginalChannel = nsnull;
   }
}

Here is the call graph for this function:

nsresult nsExternalAppHandler::PromptForSaveToFile ( nsILocalFile **  aNewFile,
const nsAFlatString aDefaultFile,
const nsAFlatString aDefaultFileExt 
) [protected]

Definition at line 2241 of file nsExternalHelperAppService.cpp.

{
  // invoke the dialog!!!!! use mWindowContext as the window context parameter for the dialog request
  // Convert to use file picker? No, then embeddors could not do any sort of
  // "AutoDownload" w/o showing a prompt
  nsresult rv = NS_OK;
  if (!mDialog)
  {
    // Get helper app launcher dialog.
    mDialog = do_CreateInstance( NS_IHELPERAPPLAUNCHERDLG_CONTRACTID, &rv );
    NS_ENSURE_SUCCESS(rv, rv);
  }

  // we want to explicitly unescape aDefaultFile b4 passing into the dialog. we can't unescape
  // it because the dialog is implemented by a JS component which doesn't have a window so no unescape routine is defined...

  // Now, be sure to keep |this| alive, and the dialog
  // If we don't do this, users that close the helper app dialog while the file
  // picker is up would cause Cancel() to be called, and the dialog would be
  // released, which would release this object too, which would crash.
  // See Bug 249143
  nsRefPtr<nsExternalAppHandler> kungFuDeathGrip(this);
  nsCOMPtr<nsIHelperAppLauncherDialog> dlg(mDialog);
  rv = mDialog->PromptForSaveToFile(this, 
                                    mWindowContext,
                                    aDefaultFile.get(),
                                    aFileExtension.get(),
                                    aNewFile);
  return rv;
}

Here is the call graph for this function:

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...

Definition at line 1507 of file nsExternalHelperAppService.cpp.

{
  // 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...
  nsCOMPtr<nsIChannel> aChannel = do_QueryInterface(request);
  if (!aChannel)
    return;

  nsCOMPtr<nsILoadGroup> oldLoadGroup;
  aChannel->GetLoadGroup(getter_AddRefs(oldLoadGroup));

  if(oldLoadGroup)
     oldLoadGroup->RemoveRequest(request, nsnull, NS_BINDING_RETARGETED);
      
  aChannel->SetLoadGroup(nsnull);
  aChannel->SetNotificationCallbacks(nsnull);

  // we need to store off the original (pre redirect!) channel that initiated the load. We do
  // this so later on, we can pass any refresh urls associated with the original channel back to the 
  // window context which started the whole process. More comments about that are listed below....
  // HACK ALERT: it's pretty bogus that we are getting the document channel from the doc loader. 
  // ideally we should be able to just use mChannel (the channel we are extracting content from) or
  // the default load channel associated with the original load group. Unfortunately because
  // a redirect may have occurred, the doc loader is the only one with a ptr to the original channel 
  // which is what we really want....
  nsCOMPtr<nsIDocumentLoader> origContextLoader =
    do_GetInterface(mWindowContext);
  if (origContextLoader)
    origContextLoader->GetDocumentChannel(getter_AddRefs(mOriginalChannel));
}

Here is the call graph for this function:

void nsIHelperAppLauncher::saveToDisk ( in nsIFile  aNewFileLocation,
in boolean  aRememberThisPreference 
) [inherited]

Called when we want to just save the content to a particular file.

NOTE: This will release the reference to the nsIHelperAppLauncherDialog.

Parameters:
aNewFileLocationLocation where the content should be saved

Here is the caller graph for this function:

void nsExternalAppHandler::SendStatusChange ( ErrorType  type,
nsresult  aStatus,
nsIRequest aRequest,
const nsAFlatString path 
) [protected]

Utility function to send proper error notification to web progress listener.

Definition at line 1914 of file nsExternalHelperAppService.cpp.

{
    nsAutoString msgId;
    switch(rv)
    {
    case NS_ERROR_OUT_OF_MEMORY:
        // No memory
        msgId.AssignLiteral("noMemory");
        break;

    case NS_ERROR_FILE_DISK_FULL:
    case NS_ERROR_FILE_NO_DEVICE_SPACE:
        // Out of space on target volume.
        msgId.AssignLiteral("diskFull");
        break;

    case NS_ERROR_FILE_READ_ONLY:
        // Attempt to write to read/only file.
        msgId.AssignLiteral("readOnly");
        break;

    case NS_ERROR_FILE_ACCESS_DENIED:
        if (type == kWriteError) {
          // Attempt to write without sufficient permissions.
          msgId.AssignLiteral("accessError");
        }
        else
        {
          msgId.AssignLiteral("launchError");
        }
        break;

    case NS_ERROR_FILE_NOT_FOUND:
    case NS_ERROR_FILE_TARGET_DOES_NOT_EXIST:
    case NS_ERROR_FILE_UNRECOGNIZED_PATH:
        // Helper app not found, let's verify this happened on launch
        if (type == kLaunchError) {
          msgId.AssignLiteral("helperAppNotFound");
          break;
        }
        // fall through

    default:
        // Generic read/write/launch error message.
        switch(type)
        {
        case kReadError:
          msgId.AssignLiteral("readError");
          break;
        case kWriteError:
          msgId.AssignLiteral("writeError");
          break;
        case kLaunchError:
          msgId.AssignLiteral("launchError");
          break;
        }
        break;
    }
    PR_LOG(nsExternalHelperAppService::mLog, PR_LOG_ERROR,
        ("Error: %s, type=%i, listener=0x%p, rv=0x%08X\n",
         NS_LossyConvertUTF16toASCII(msgId).get(), type, mWebProgressListener.get(), rv));
    PR_LOG(nsExternalHelperAppService::mLog, PR_LOG_ERROR,
        ("       path='%s'\n", NS_ConvertUTF16toUTF8(path).get()));

    // Get properties file bundle and extract status string.
    nsCOMPtr<nsIStringBundleService> s = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
    if (s)
    {
        nsCOMPtr<nsIStringBundle> bundle;
        if (NS_SUCCEEDED(s->CreateBundle("chrome://global/locale/nsWebBrowserPersist.properties", getter_AddRefs(bundle))))
        {
            nsXPIDLString msgText;
            const PRUnichar *strings[] = { path.get() };
            if(NS_SUCCEEDED(bundle->FormatStringFromName(msgId.get(), strings, 1, getter_Copies(msgText))))
            {
              if (mWebProgressListener)
              {
                // We have a listener, let it handle the error.
                mWebProgressListener->OnStatusChange(nsnull, (type == kReadError) ? aRequest : nsnull, rv, msgText);
              }
              else
              {
                // We don't have a listener.  Simply show the alert ourselves.
                nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mWindowContext));
                nsXPIDLString title;
                bundle->FormatStringFromName(NS_LITERAL_STRING("title").get(),
                                             strings,
                                             1,
                                             getter_Copies(title));
                if (prompter)
                {
                  prompter->Alert(title, msgText);
                }
              }
            }
        }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Creates the temporary file for the download and an output stream for it.

Upon successful return, both mTempFile and mOutStream will be valid.

Definition at line 1581 of file nsExternalHelperAppService.cpp.

{
  nsresult rv;

#if defined(XP_MAC) || defined (XP_MACOSX)
 // create a temp file for the data...and open it for writing.
 // use NS_MAC_DEFAULT_DOWNLOAD_DIR which gets download folder from InternetConfig
 // if it can't get download folder pref, then it uses desktop folder
  rv = NS_GetSpecialDirectory(NS_MAC_DEFAULT_DOWNLOAD_DIR,
                              getter_AddRefs(mTempFile));
#else
  // create a temp file for the data...and open it for writing.
  rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(mTempFile));
#endif
  NS_ENSURE_SUCCESS(rv, rv);

  // We need to generate a name for the temp file that we are going to be streaming data to. 
  // We don't want this name to be predictable for security reasons so we are going to generate a 
  // "salted" name.....
  nsAutoString saltedTempLeafName;
  // this salting code was ripped directly from the profile manager.
  PRInt32 i;
  for (i=0;i<SALT_SIZE;i++) 
  {
    saltedTempLeafName.Append(table[rand()%TABLE_SIZE]);
  }

  // now append our extension.
  nsCAutoString ext;
  mMimeInfo->GetPrimaryExtension(ext);
  if (!ext.IsEmpty()) {
    ext.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '_');
    if (ext.First() != '.')
      saltedTempLeafName.Append(PRUnichar('.'));
    AppendUTF8toUTF16(ext, saltedTempLeafName);
  }

  rv = mTempFile->Append(saltedTempLeafName); // make this file unique!!!
  NS_ENSURE_SUCCESS(rv, rv);
  rv = mTempFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
  NS_ENSURE_SUCCESS(rv, rv);

#if defined(XP_MAC) || defined (XP_MACOSX)
  // Now that the file exists set Mac type if the file has no extension
  // and we can determine a type.
  if (ext.IsEmpty() && mMimeInfo)
  {
    nsCOMPtr<nsILocalFileMac> macfile = do_QueryInterface(mTempFile);
    if (macfile)
    {
      PRUint32 type;
      mMimeInfo->GetMacType(&type);
      macfile->SetFileType(type);
    }
  }
#endif

  rv = NS_NewLocalFileOutputStream(getter_AddRefs(mOutStream), mTempFile,
                                   PR_WRONLY | PR_CREATE_FILE, 0600);
  if (NS_FAILED(rv)) {
    mTempFile->Remove(PR_FALSE);
    return rv;
  }

#if defined(XP_MAC) || defined (XP_MACOSX)
    nsCAutoString contentType;
    mMimeInfo->GetMIMEType(contentType);
    if (contentType.LowerCaseEqualsLiteral(APPLICATION_APPLEFILE) ||
        contentType.LowerCaseEqualsLiteral(MULTIPART_APPLEDOUBLE))
    {
      nsCOMPtr<nsIAppleFileDecoder> appleFileDecoder = do_CreateInstance(NS_IAPPLEFILEDECODER_CONTRACTID, &rv);
      if (NS_SUCCEEDED(rv))
      {
        rv = appleFileDecoder->Initialize(mOutStream, mTempFile);
        if (NS_SUCCEEDED(rv))
          mOutStream = do_QueryInterface(appleFileDecoder, &rv);
      }
    }
#endif

  return rv;
}

Here is the call graph for this function:

The following methods are used by the progress dialog to get or set information on the current helper app launcher download.

This reference will be released when the download is finished (after the listener receives the STATE_STOP notification).


Member Data Documentation

The canceled flag is set if the user canceled the launching of this application before we finished saving the data to a temp file.

Definition at line 383 of file nsExternalHelperAppService.h.

Definition at line 408 of file nsExternalHelperAppService.h.

Definition at line 418 of file nsExternalHelperAppService.h.

Definition at line 501 of file nsExternalHelperAppService.h.

When we are told to save the temp file to disk (in a more permament location) before we are done writing the content to a temp file, then we need to remember the final destination until we are ready to use it.

Definition at line 416 of file nsExternalHelperAppService.h.

The mime info object associated with the content type this helper app launcher is currently attempting to load.

Definition at line 111 of file nsIExternalHelperAppService.idl.

The MIME Info for this load.

Will never be null.

Definition at line 361 of file nsExternalHelperAppService.h.

in the case of a redirect, this will be the pre-redirect channel.

Definition at line 500 of file nsExternalHelperAppService.h.

output stream to the temp file

Definition at line 362 of file nsExternalHelperAppService.h.

Number of bytes received (for sending progress notifications).

Definition at line 409 of file nsExternalHelperAppService.h.

Definition at line 398 of file nsExternalHelperAppService.h.

One of the REASON_ constants from nsIHelperAppLauncherDialog.

Indicates the reason the dialog was shown (unknown content type, server requested it, etc).

Definition at line 405 of file nsExternalHelperAppService.h.

have we received information from the user about how they want to dispose of this content

Definition at line 396 of file nsExternalHelperAppService.h.

The request that's being loaded.

Not used after OnStopRequest, so a weak reference suffices. Initialized in OnStartRequest.

Definition at line 507 of file nsExternalHelperAppService.h.

This is set based on whether the channel indicates that a new window was opened specifically for this download.

If so, then we close it.

Definition at line 390 of file nsExternalHelperAppService.h.

Definition at line 356 of file nsExternalHelperAppService.h.

Definition at line 397 of file nsExternalHelperAppService.h.

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.

Definition at line 377 of file nsExternalHelperAppService.h.

Definition at line 355 of file nsExternalHelperAppService.h.

Definition at line 357 of file nsExternalHelperAppService.h.

Definition at line 407 of file nsExternalHelperAppService.h.

Definition at line 370 of file nsExternalHelperAppService.h.

Definition at line 499 of file nsExternalHelperAppService.h.

Definition at line 363 of file nsExternalHelperAppService.h.

Used to close the window on a timer, to avoid any exceptions that are thrown if we try to close the window before it's fully loaded.

Definition at line 369 of file nsExternalHelperAppService.h.

The source uri.

Definition at line 116 of file nsIExternalHelperAppService.idl.

readonly attribute AString nsIHelperAppLauncher::suggestedFileName [inherited]

The suggested name for this file.

Definition at line 121 of file nsIExternalHelperAppService.idl.

The file we are saving to.

Definition at line 155 of file nsIExternalHelperAppService.idl.

Time when the download started.

Definition at line 159 of file nsIExternalHelperAppService.idl.


The documentation for this class was generated from the following files: