Logo Search packages:      
Sourcecode: galeon version File versions

ProgressListener.cpp

/*
 *  Copyright (C) 2001 Philip Langdale, Matthew Aubury
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "ProgressListener.h"

#include "gul-general.h"
#include "eel-gconf-extensions.h"
#include "egg-recent-model.h"
#include "prefs-strings.h"
#include "gul-gui.h"
#include "galeon-debug.h"

#include <unistd.h>
#include <libgnome/gnome-exec.h>
#include <libgnomevfs/gnome-vfs-utils.h>
#include <glib/gi18n.h>

#include <nsIWebBrowserPersist.h>
#include <nsCWebBrowserPersist.h>
#include <nsIFileURL.h>
#include <nsIFTPChannel.h>
#include <nsIHttpChannel.h>
#include <nsIMIMEInfo.h>
#include <nsNetError.h>                 // for NS_BINDING_ABORTED, see FIXME
#include <nsILocalFile.h>
#include <nsIObserver.h>
#include <nsCExternalHandlerService.h>
#include <nsMemory.h>

static const PRInt32 kInterval            = 500000;     /* in microsecs == 500ms == 0.5s */
static const PRInt32 kUnknownSizeInterval = 150000;     /* in microsecs == 150ms == 0.15s */

#ifdef HAVE_NSITRANSFER_H
NS_IMPL_ISUPPORTS3(GProgressListener, nsIWebProgressListener, nsITransfer, nsISupportsWeakReference)
#else
NS_IMPL_ISUPPORTS4(GProgressListener, nsIWebProgressListener, 
               nsIDownload, nsITransfer, nsISupportsWeakReference)
#endif

//---------------------------------------------------------------------------

static void
download_cancel_cb (Download *download, GProgressListener *self)
{
      self->Abort();
}

static void
download_resume_cb (Download *download, GProgressListener *self)
{
      self->Resume();
}

static void
download_pause_cb (Download *download, GProgressListener *self)
{
      self->Pause();
}

//---------------------------------------------------------------------------

GProgressListener::GProgressListener () : mPersist(nsnull),
                                mGaleonPersist(nsnull),
                                mDownload(nsnull),
                                mContentLength(-1),
                                mObserver(nsnull),
                                mMIMEInfo(nsnull)
{
      LOG ("GProgressListener ctor(%p)", this);
}

GProgressListener::~GProgressListener ()
{
      LOG ("GProgressListener dtor(%p)", this);
}

NS_METHOD GProgressListener::InitForPersist (nsIWebBrowserPersist *aPersist,
                                    nsIURI *aURI,
                                    nsIFile *aFile,
                                    GaleonEmbedPersist *galeonPersist)
{
      /* fill in download details */
      mUri = aURI;
      mFile = aFile;
      mPersist = aPersist;
      mGaleonPersist = (GaleonEmbedPersist *) g_object_ref (galeonPersist);

      mStartTime = PR_Now();

      /* do remaining init */
      nsresult rv = PrivateInit ();

      /* pick up progress messages */
      mPersist->SetProgressListener (this);

      /* done */
      return rv;
}

static void
download_weak_ref_cb (gpointer data, GObject *object)
{
      GProgressListener *progress = (GProgressListener*)data;
      NS_RELEASE (progress);
}


NS_METHOD GProgressListener::PrivateInit (void)
{
      nsresult rv;

      /* setup this download */
      mCanPause            = PR_FALSE;
      mIsPaused            = PR_FALSE;
      mLastUpdate          = PR_Now ();

      guint flags = EMBED_PERSIST_ADD_TO_RECENT | EMBED_PERSIST_SHOW_PROGRESS;
        if (mGaleonPersist)
        {
                g_object_get (mGaleonPersist, "flags", &flags, NULL);
        }

      mAddToRecent = flags & EMBED_PERSIST_ADD_TO_RECENT;
 
        if (flags & EMBED_PERSIST_SHOW_PROGRESS)
      {
            GulString dest;
            GulCString source;

            rv = mFile->GetPath (dest);

            rv = mUri->GetSpec (source);

            DownloaderView *dv;
            dv = galeon_embed_shell_get_downloader_view (embed_shell);
            mDownload = downloader_view_add_download (dv, source.get(),
                                            GulCString (dest).get());
            g_signal_connect (G_OBJECT (mDownload), "cancel",
                          G_CALLBACK (download_cancel_cb), this);
            g_signal_connect (G_OBJECT (mDownload), "pause",
                          G_CALLBACK (download_pause_cb), this);
            g_signal_connect (G_OBJECT (mDownload), "resume",
                          G_CALLBACK (download_resume_cb), this);
            g_object_add_weak_pointer (G_OBJECT (mDownload), (void **) &mDownload);

            /* Ensure that we stay around while the download is alive,
             * bug 144067 */
            NS_ADDREF (this);
            g_object_weak_ref (G_OBJECT (mDownload), download_weak_ref_cb,
                           this);
      }

      /* done */
      return NS_OK;
}

NS_IMETHODIMP GProgressListener::Init(nsIURI *aSource,
                              nsIURI *aTarget,
                                      const PRUnichar *aDisplayName,
                              nsIMIMEInfo *aMIMEInfo,
                                      PRInt64 aStartTime,
                                      nsIWebBrowserPersist *aPersist)
{
        mUri = aSource;
        mStartTime = aStartTime;
        mPersist = aPersist;

      mTarget = aTarget;
      nsCOMPtr<nsIFileURL> tFileUrl = do_QueryInterface(mTarget);
      if (tFileUrl)
      {
            nsCOMPtr<nsIFile> tFileRef;
            tFileUrl->GetFile(getter_AddRefs(tFileRef));
            tFileRef->Clone(getter_AddRefs(mFile));
      }

      if (aMIMEInfo)
      {
            nsMIMEInfoHandleAction action;
            if (NS_SUCCEEDED(aMIMEInfo->GetPreferredAction(&action)))
            {
                  if (action == nsIMIMEInfo::useHelperApp)
                  {
                        mMIMEInfo = aMIMEInfo;
                  }

                  /* HACK, stop mozilla from opening the application, we
                   * do it ourselves */
                  aMIMEInfo->SetPreferredAction(nsIMIMEInfo::saveToDisk);
            }
      }

        return PrivateInit();
}

#ifndef HAVE_NSITRANSFER_H
/* attribute long long startTime; */
NS_IMETHODIMP GProgressListener::GetStartTime(PRInt64 *aStartTime)
{
        *aStartTime = mStartTime;
        return NS_OK;
}


/* attribute nsIURI source; */
NS_IMETHODIMP GProgressListener::GetSource(nsIURI * *aSource)
{
        NS_IF_ADDREF(*aSource = mUri);
        return NS_OK;
}

/* attribute nsIURI target; */
NS_IMETHODIMP GProgressListener::GetTarget(nsIURI * *aTarget)
{
      NS_IF_ADDREF(*aTarget = mTarget);
      return NS_OK;
}

/* attribute nsILocalFile targetFile; */
NS_IMETHODIMP GProgressListener::GetTargetFile(nsILocalFile * *aTarget)
{
        nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(mFile);
        NS_IF_ADDREF(*aTarget = localFile);
        return NS_OK;
}

NS_IMETHODIMP GProgressListener::GetMIMEInfo(nsIMIMEInfo * *aMIMEInfo)
{
      NS_IF_ADDREF(*aMIMEInfo = mMIMEInfo);
      return NS_OK;
}

/* readonly attribute PRInt32 percentComplete; */
NS_IMETHODIMP GProgressListener::GetPercentComplete(PRInt32 *aPercentComplete)
{
      *aPercentComplete = 0;
        return NS_OK;
}

#ifdef HAVE_NSIDOWNLOAD_GETSIZE
/* readonly attribute PRUint64 amountTransferred; */
NS_IMETHODIMP GProgressListener::GetAmountTransferred(PRUint64 *aAmountTransferred)
{
   *aAmountTransferred = 0;
   return NS_OK;
}


/* readonly attribute PRUint64 size; */
NS_IMETHODIMP GProgressListener::GetSize(PRUint64 *aSize)
{
   *aSize = 0;
   return NS_OK;
}
#endif    

/* attribute wstring displayName; */
NS_IMETHODIMP GProgressListener::GetDisplayName(PRUnichar * *aDisplayName)
{
        *aDisplayName = nsnull;
        return NS_OK;
}
NS_IMETHODIMP GProgressListener::SetDisplayName(const PRUnichar * aDisplayName)
{
        return NS_OK;
}

NS_IMETHODIMP GProgressListener::GetPersist(nsIWebBrowserPersist * *aPersist)
{
        NS_IF_ADDREF(*aPersist = mPersist);
        return NS_OK;
}

#endif

/* attribute nsIObserver observer; */
NS_IMETHODIMP GProgressListener::GetObserver(nsIObserver * *aObserver)
{
        NS_IF_ADDREF(*aObserver = mObserver);
        return NS_OK;
}
NS_IMETHODIMP GProgressListener::SetObserver(nsIObserver * aObserver)
{
        mObserver = aObserver;
        return NS_OK;
}

/* attribute nsIWebProgressListener listener; */
NS_IMETHODIMP GProgressListener::GetListener(nsIWebProgressListener * *aListener)
{
        *aListener = nsnull;
        return NS_OK;
}
NS_IMETHODIMP GProgressListener::SetListener(nsIWebProgressListener * aListener)
{
        return NS_OK;
}

static void LaunchHandler (GnomeVFSMimeApplication *aHandler, nsIFile *aFile,
                     guint32 user_time)
{
      nsCOMPtr<nsIExternalHelperAppService> helperService =
            do_GetService (NS_EXTERNALHELPERAPPSERVICE_CONTRACTID);

      nsCOMPtr<nsPIExternalAppLauncher> appLauncher =
            do_QueryInterface (helperService);
      if (appLauncher)
      {
            appLauncher->DeleteTemporaryFileOnExit(aFile);
      }

      GulString filename;
      aFile->GetPath(filename);
      
      /* FIXME: check return value */
      gul_general_launch_application (aHandler, GulCString(filename).get(), user_time);
}

/*
 * void onStateChange (in nsIWebProgress aWebProgress, 
 *                     in nsIRequest aRequest, 
 *                 in long aStateFlags, 
 *                 in unsigned long aStatus);
 */
NS_IMETHODIMP GProgressListener::OnStateChange (nsIWebProgress *aWebProgress,
                                     nsIRequest *aRequest,
                                     PRUint32 aStateFlags,
                                     PRUint32 aStatus)
{
      if (aStateFlags & nsIWebProgressListener::STATE_START &&
          aStateFlags & nsIWebProgressListener::STATE_IS_REQUEST)
      {
            // HTTP is special as the download as a byte stream can
            // complete successfully, but what you get instead of the
            // desired file is a 404 error document (or whatever depending
            // on the error.)
            //
            // Only relevant when coming from mozilla-embed-persist.cpp
            nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
            if (http)
            {
                  PRBool succeeded = PR_TRUE;
                  http->GetRequestSucceeded(&succeeded);
                  if (!succeeded)
                  {
                        Abort ();
                        return NS_OK;
                  }
            }
      }

      if ((aRequest != mRequest) && !(aStateFlags & nsIWebProgressListener::STATE_STOP))
      {
            SetRequest (aRequest);
      }

      if (aStateFlags & nsIWebProgressListener::STATE_STOP)
      {
            // We need to detach from the nsIWebBrowserPersist or it'll
                // keep us around forever.  Detaching would kill us instantly
                // so kungfu is needed to survive just long enough to do the
                // final clean up.
                nsCOMPtr<nsITransfer> kungFuDeathGrip(this);
                if (mPersist)
                {
                        mPersist->SetProgressListener(nsnull);
                        mPersist = nsnull;
                }
            
            if (NS_SUCCEEDED(aStatus))
            {
                  if (mAddToRecent)
                  {
                        EggRecentModel *model;

                        model = egg_recent_model_new (EGG_RECENT_MODEL_SORT_NONE);

                        GulString dest;
                        mFile->GetPath (dest);

                        EggRecentItem *item;
                         
                        if (mContentType.IsEmpty() || 
                            mContentType.EqualsAsciiIgnoreCase("application/octet-stream"))
                        {
                              item = egg_recent_item_new_from_uri (GulCString(dest).get());
                        }
                        else
                        {
                              item = egg_recent_item_new ();
                              egg_recent_item_set_uri (item, GulCString(dest).get());
                              egg_recent_item_set_mime_type (item, mContentType.get());
                        }

                        // keep in sync with PrintProgressListener.cpp
                        egg_recent_item_add_group (item, "Galeon");
                        egg_recent_item_add_group (item, "Web Browser");

                        egg_recent_model_add_full (model, item);
                        egg_recent_item_unref (item);

                        g_object_unref (model);
                  }

                  if (mDownload)
                  {
                        g_object_remove_weak_pointer (G_OBJECT(mDownload), (void **) &mDownload);
                        download_completed (mDownload);
                  }

                  if (G_IS_OBJECT(mGaleonPersist))
                  {
                        GnomeVFSMimeApplication *handler = NULL;
                        guint32 user_time;
                        g_object_get (mGaleonPersist,
                                          "handler", &handler,
                                    "user_time", &user_time,
                                          NULL);
                        if (handler)
                        {
                              LaunchHandler (handler, mFile, user_time);
                        }

                        g_signal_emit_by_name (mGaleonPersist, "completed");
                        g_object_unref (mGaleonPersist);
                  }
                  else if (mMIMEInfo)
                  {
                        LaunchHelperApp();
                  }
            }
            else
            {
                  if (mDownload)
                  {
                        g_object_remove_weak_pointer (G_OBJECT(mDownload), (void **) &mDownload);
                        download_cancelled (mDownload);
                  }

                  if (mGaleonPersist)
                  {
                        g_signal_emit_by_name (mGaleonPersist, "cancelled", NULL);
                        g_object_unref (mGaleonPersist);
                  }
            }

            mDownload = NULL;
            mGaleonPersist = NULL;
      }

      /* done */
      return NS_OK;
}

/*
 * void onProgressChange (in nsIWebProgress aWebProgress, 
 *                        in nsIRequest aRequest, 
 *                        in long aCurSelfProgress, 
 *                        in long aMaxSelfProgress, 
 *                        in long aCurTotalProgress, 
 *                        in long aMaxTotalProgress); 
 */
NS_IMETHODIMP GProgressListener::
                  OnProgressChange (nsIWebProgress *aWebProgress,
                                nsIRequest *aRequest,
                                PRInt32 aCurSelfProgress,
                                PRInt32 aMaxSelfProgress,
                                PRInt32 aCurTotalProgress,
                                PRInt32 aMaxTotalProgress)
{
      // no point in calculating progress if there's no one watching
      if (!mDownload) return NS_OK;

      if (aRequest != mRequest)
      {
            // FIXME when Mozilla permits
            //
            // http://bugzilla.mozilla.org/show_bug.cgi?id=152224
            //
            // When used via GContentHandler we never get OnStateChange
            // with STATE_START.  As a workaround grab the nsIRequest here
            // as well.  To be removed when sanity is found.

            SetRequest (aRequest);
      }

      /* FIXME maxsize check here */

      if (aCurTotalProgress == -1)
      {
            // This seems to be a special case which we get if the file has
            // already been completely downloaded by the time we get to
            // show the progress dialog.  (Download begins when we click on
            // a link, then the save/open dialog pops up, then we get to
            // pick a file name, and so on...)
            //
            // So lacking other reliable information, let's try the file
            // size.  <insert 32-bits for file size ought to be enough for
            // everyone joke here>
            PRInt64 fileSize;
            if (NS_SUCCEEDED(mFile->GetFileSize(&fileSize)))
            {
                  mContentLength    = fileSize;
                  aCurTotalProgress = fileSize;
                  aMaxTotalProgress = fileSize;
            }
      }
      else if (aMaxTotalProgress == -1 && mContentLength >= 0)
      {
            aMaxTotalProgress = mContentLength;
      }

      PRInt64 now = PR_Now ();

      /* get out if we're updating too quickly, but don't miss EOF */
      if (aCurTotalProgress != aMaxTotalProgress)
      {
            PRInt32 interval = (aMaxTotalProgress == -1) ? kUnknownSizeInterval : kInterval;
            if ((now - mLastUpdate) < interval)
            {
                  return NS_OK;
            }
      }

      /* compute elapsed time */
      mLastUpdate = now;

      guint elapsed = (now - mStartTime) / PR_USEC_PER_SEC;

      /* compute download rate */
      guint speed = 0;
      if (elapsed > 0)
      {
            speed = aCurTotalProgress / elapsed;
      }

      /* compute time remaining */
      guint remaining = G_MAXUINT;
      if (speed > 0 && aMaxTotalProgress >= 0)
      {
            remaining = (aMaxTotalProgress - aCurTotalProgress) / speed;
      }

      if (aMaxTotalProgress < 0)
            aMaxTotalProgress = G_MAXULONG;

      download_set_progress (mDownload,
                         elapsed,
                         remaining,
                         speed,
                         aCurTotalProgress,
                         aMaxTotalProgress);

      /* done */
      return NS_OK;
}

/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
NS_IMETHODIMP GProgressListener::
                  OnLocationChange(nsIWebProgress *aWebProgress,
                               nsIRequest *aRequest, nsIURI *location)
{
    return NS_OK;
}

/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
NS_IMETHODIMP GProgressListener::
                  OnStatusChange(nsIWebProgress *aWebProgress,
                               nsIRequest *aRequest, nsresult aStatus,
                               const PRUnichar *aMessage)
{
    return NS_OK;
}

/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long state); */
NS_IMETHODIMP GProgressListener::
                  OnSecurityChange(nsIWebProgress *aWebProgress,
                               nsIRequest *aRequest,
                               PRUint32 state)
{
    return NS_OK;
}

//---------------------------------------------------------------------------
NS_METHOD GProgressListener::SetRequest (nsIRequest *aRequest)
{
      mRequest = aRequest;

      nsCOMPtr<nsIChannel> channel = do_QueryInterface (mRequest);
      if (channel)
      {
            PRInt32 length;
            if (NS_SUCCEEDED(channel->GetContentLength(&length)) && length >= 0)
            {
                  mContentLength = length;
                  if (mDownload)
                  {
                        // Update the download with known content
                        // length.  OnProgressChange might never be
                        // called with aMaxTotalProgress reflecting the
                        // full length, leaving the download "too short"
                        download_set_size_total (mDownload, mContentLength);
                  }
            }

            if (mContentType.IsEmpty())
            {
                  GulCString type;
                  if (NS_SUCCEEDED(channel->GetContentType(type)))
                  {
                        mContentType = type;
                  }
            }
      }

      nsCOMPtr<nsIFTPChannel> ftp = do_QueryInterface(aRequest);
      mCanPause = ftp ? PR_TRUE : PR_FALSE;
      if (mDownload)
      {
            download_set_can_pause (mDownload, mCanPause);
      }

      return NS_OK;
}

NS_METHOD GProgressListener::LaunchHelperApp (void)
{
      if (!mMIMEInfo)
            return NS_ERROR_FAILURE;

      nsresult rv;

      GulCString cFileName;
      rv = mFile->GetNativePath(cFileName);
      if(NS_FAILED(rv)) return NS_ERROR_FAILURE;

      GulString helperDesc;
#ifdef HAVE_NSIMIMEINFO_NSASTRING
      rv = mMIMEInfo->GetApplicationDescription(helperDesc);
#else
      PRUnichar *tmp;
      rv = mMIMEInfo->GetApplicationDescription (&tmp);
      helperDesc = tmp;
      nsMemory::Free (tmp);
#endif
      if(NS_FAILED(rv)) return NS_ERROR_FAILURE;

      // XXX information passing kludge (from ContentHandler)
      // TODO: should probably use some prefix, like 'gnomevfs:'
      GulCString helperId(helperDesc);

      // Format <usertime>:<helperapp id>
      char *colon = strchr (helperId.get(), ':');
      g_return_val_if_fail (colon, NS_ERROR_FAILURE);

      const char *helperappid = colon+1;

      guint32 usertime = strtoul (helperId.get(), &colon, 0);
      
      GnomeVFSMimeApplication *helper = 
#ifdef HAVE_NEW_GNOME_VFS_MIME_API
            gnome_vfs_mime_application_new_from_desktop_id (helperappid);
#else
            gnome_vfs_mime_application_new_from_id (helperappid);
#endif

      nsCOMPtr<nsIExternalHelperAppService> helperService =
            do_GetService (NS_EXTERNALHELPERAPPSERVICE_CONTRACTID, &rv);
      if (NS_SUCCEEDED(rv))
      {
            nsCOMPtr<nsPIExternalAppLauncher> appLauncher =
                  do_QueryInterface (helperService, &rv);
            if (NS_SUCCEEDED(rv))
            {
                  appLauncher->DeleteTemporaryFileOnExit(mFile);
            }
      }

      /* FIXME: check return value */
      gul_general_launch_application (helper, cFileName.get(), usertime);
      gnome_vfs_mime_application_free (helper);

      return NS_OK;
}

nsresult GProgressListener::Pause (void)
{
      NS_ENSURE_TRUE(mCanPause && !mIsPaused, NS_ERROR_FAILURE);

        nsresult rv = mRequest->Suspend ();
      if (NS_FAILED(rv))
      {
            mCanPause = PR_FALSE;
            download_set_can_pause (mDownload, FALSE);
            return rv;
      }

      mIsPaused = PR_TRUE;
      download_paused (mDownload);
      return NS_OK;
}

nsresult GProgressListener::Resume (void)
{
      NS_ENSURE_TRUE(mCanPause && mIsPaused, NS_ERROR_FAILURE);

        nsresult rv = mRequest->Resume ();
      NS_ENSURE_SUCCESS(rv, rv);

      mIsPaused = PR_FALSE;
      download_resumed (mDownload);
        return NS_OK;
}

nsresult GProgressListener::Abort (void)
{
      // Keep ourselves alive
      nsCOMPtr<nsITransfer> kungFuDeathGrip(this);

      // Suspended request doesn't seem to reach cancelled state until it's
      // resumed.  Better resume it first so that we get the right away.
        if (mIsPaused)
        {
                mRequest->Resume ();
        }

        if (mObserver)
        {
                mObserver->Observe(NS_ISUPPORTS_CAST(nsITransfer*, this),
                           "oncancel", nsnull);
        }

        if (mPersist)
        {
                return mPersist->CancelSave ();
        }

      // Working assumption is that if mPersist is set CancelSave correctly
      // emits proper events to OnStateChange.  At the time of writing that
      // seems to be the case; mPersist is set only when the download is
      // initiated from mozilla-embed-persist.cpp
      //
      // This part is reached only if the download was initiated via
      // GContentHandler


      // FIXME remove workaround when Mozilla permits
      //
      // http://bugzilla.mozilla.org/show_bug.cgi?id=152224
      //
      // Mozilla isn't calling OnStateChange with STATE_STOP when the
      // download is cancelled, so we need to simulate it or mDownload and
      // mGaleonPersist "listeners" are left unaware of the cancellation.

      OnStateChange (nsnull, mRequest, nsIWebProgressListener::STATE_STOP, NS_BINDING_ABORTED);

      // XXX memory leak courtesy of Mozilla
      //
      // http://bugzilla.mozilla.org/show_bug.cgi?id=152224
      //
      // Mozilla is holding us hostage until someone calls
      // nsIHelperAppLauncher::CloseProgressWindow -- no one ever does.
      //
      // We could do 'delete this;' right here and plug the memory leak.
      // We'd still be leaking if the download is finished successfully.
      // We'd also crash and burn once Mozilla gets fixed.

      return NS_OK;
}

nsresult 
InitiateMozillaDownload (nsIURI *sourceURI, nsILocalFile* inDestFile,
                   GaleonEmbedPersist *embedPersist,
                   nsIDOMDocument *domDocument, 
                   nsISupports *cacheKey,
                   nsIInputStream *postData,
                   PRBool decode,
                   nsIURI *displayURI)
{
      nsresult rv = NS_OK;

      EmbedPersistFlags flags;
      flags = galeon_embed_persist_get_flags (GALEON_EMBED_PERSIST (embedPersist));

      nsCOMPtr<nsIWebBrowserPersist> webPersist = 
            do_CreateInstance(NS_WEBBROWSERPERSIST_CONTRACTID, &rv);
      NS_ENSURE_SUCCESS (rv, rv);
  
      GProgressListener *listener = new GProgressListener ();
      rv = listener->InitForPersist (webPersist, displayURI, inDestFile, embedPersist);
      NS_ENSURE_SUCCESS (rv, rv);

      PRInt32 persist_flags = nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES;
      if (!domDocument && !decode)
      {
            persist_flags |= nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION;
      }

      if (flags & EMBED_PERSIST_BYPASSCACHE)
      {
            persist_flags |= nsIWebBrowserPersist::PERSIST_FLAGS_BYPASS_CACHE;
      }
      else
      {
            persist_flags |= nsIWebBrowserPersist::PERSIST_FLAGS_FROM_CACHE;
      }

      webPersist->SetPersistFlags(persist_flags);

      if (!domDocument)
      {
            /* TODO, fix this null referrer */
            rv = webPersist->SaveURI (sourceURI, cacheKey, nsnull,
                                postData, nsnull, inDestFile);
      }
      else
      {
            nsCOMPtr<nsILocalFile> filesFolder;
            if (flags & EMBED_PERSIST_SAVE_CONTENT)
            {
                  /* Create a directory to hold the content, mozilla
                   * will create the directory as needed. */
                  GulCString nativePath;
                  inDestFile->GetNativePath(nativePath);
                  
                  nativePath.Append ("_content");

                  NS_NewNativeLocalFile(nativePath, PR_TRUE, getter_AddRefs(filesFolder));
            }

            rv = webPersist->SaveDocument (domDocument, inDestFile, filesFolder,
                                     nsnull, 0, 0);
      }
  
      return rv;
}

/**
 * Builds the download filename into the default download directory,
 *
 * returns NS_ERROR_FAILURE if the filename couldn't be generated
 */
nsresult
BuildDownloadPath (const char *defaultFileName, GtkWidget *parent,
               nsILocalFile **_retval)
{
      gchar * dirName = eel_gconf_get_string (CONF_DOWNLOADING_DIR);
      if (dirName)
      {
            char *tmp = g_filename_from_utf8 (dirName, -1, NULL, NULL, NULL);
            g_free (dirName);
            dirName = tmp;
      }

      if (dirName)
      {
            char *tmp = gnome_vfs_expand_initial_tilde (dirName);
            g_free (dirName);
            dirName = tmp;
      }

      if (!dirName || dirName[0] == '\0' || 
          !g_file_test (dirName, G_FILE_TEST_IS_DIR))
      {
            g_free (dirName);
            dirName = g_strdup (g_get_home_dir ());
      }


      char *filename = g_build_filename (dirName, defaultFileName, NULL);
      g_free (dirName);

      if (gul_gui_confirm_overwrite_file (parent, filename))
      {
            nsCOMPtr <nsILocalFile> saveFile;
            NS_NewNativeLocalFile (GulDependentCString (filename),
                               PR_TRUE,
                               getter_AddRefs(saveFile));
                  
            NS_ADDREF (*_retval = saveFile);

            g_free (filename);
            return NS_OK;
      }
      g_free (filename);

      return NS_ERROR_FAILURE;
}

Generated by  Doxygen 1.6.0   Back to index