Bug 395144 - Figure out what to do when we are supposed to open an application with download resume. r=sdwilsh, b-ff3=beltzner, aM9=beltzner

This commit is contained in:
edward.lee@engineering.uiuc.edu 2007-10-24 15:19:04 -07:00
Родитель 607af1ac22
Коммит 6b0e3ba0e9
4 изменённых файлов: 312 добавлений и 19 удалений

Просмотреть файл

@ -66,6 +66,7 @@ REQUIRES = xpcom \
alerts \
storage \
xulapp \
exthandler \
$(NULL)
CPPSRCS = \

Просмотреть файл

@ -74,6 +74,9 @@
#include "nsIDownloadManagerUI.h"
#include "nsTArray.h"
#include "nsIResumableChannel.h"
#include "nsCExternalHandlerService.h"
#include "nsIExternalHelperAppService.h"
#include "nsIMIMEService.h"
#ifdef XP_WIN
#include <shlobj.h>
@ -89,10 +92,11 @@ static PRBool gStoppingDownloads = PR_FALSE;
#define PREF_BDM_RETENTION "browser.download.manager.retention"
#define PREF_BDM_CLOSEWHENDONE "browser.download.manager.closeWhenDone"
#define PREF_BDM_ADDTORECENTDOCS "browser.download.manager.addToRecentDocs"
#define PREF_BH_DELETETEMPFILEONEXIT "browser.helperApps.deleteTempFileOnExit"
static const PRInt64 gUpdateInterval = 400 * PR_USEC_PER_MSEC;
#define DM_SCHEMA_VERSION 6
#define DM_SCHEMA_VERSION 7
#define DM_DB_NAME NS_LITERAL_STRING("downloads.sqlite")
#define DM_DB_CORRUPT_FILENAME NS_LITERAL_STRING("downloads.sqlite.corrupt")
@ -323,6 +327,30 @@ nsDownloadManager::InitDB(PRBool *aDoImport)
}
// Fallthrough to the next upgrade
case 6: // This version adds three columns to DB (MIME type related info)
{
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_downloads "
"ADD COLUMN mimeType TEXT"));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_downloads "
"ADD COLUMN preferredApplication TEXT"));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_downloads "
"ADD COLUMN preferredAction INTEGER NOT NULL DEFAULT 0"));
NS_ENSURE_SUCCESS(rv, rv);
// Finally, update the schemaVersion variable and the database schema
schemaVersion = 7;
rv = mDBConn->SetSchemaVersion(schemaVersion);
NS_ENSURE_SUCCESS(rv, rv);
}
// Fallthrough to next upgrade
// Extra sanity checking for developers
#ifndef DEBUG
case DM_SCHEMA_VERSION:
@ -353,7 +381,8 @@ nsDownloadManager::InitDB(PRBool *aDoImport)
nsCOMPtr<mozIStorageStatement> stmt;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT id, name, source, target, tempPath, startTime, endTime, state, "
"referrer, entityID, currBytes, maxBytes "
"referrer, entityID, currBytes, maxBytes, mimeType, "
"preferredApplication, preferredAction "
"FROM moz_downloads"), getter_AddRefs(stmt));
if (NS_SUCCEEDED(rv))
break;
@ -398,7 +427,10 @@ nsDownloadManager::CreateTable()
"referrer TEXT, "
"entityID TEXT, "
"currBytes INTEGER NOT NULL DEFAULT 0, "
"maxBytes INTEGER NOT NULL DEFAULT -1"
"maxBytes INTEGER NOT NULL DEFAULT -1, "
"mimeType TEXT, "
"preferredApplication TEXT, "
"preferredAction INTEGER NOT NULL DEFAULT 0"
")"));
}
@ -535,7 +567,8 @@ nsDownloadManager::ImportDownloadHistory()
if (NS_FAILED(rv)) continue;
(void)AddDownloadToDB(name, source, target, EmptyString(), startTime,
endTime, state);
endTime, state, EmptyCString(), EmptyCString(),
nsIMIMEInfo::saveToDisk);
}
return NS_OK;
@ -636,13 +669,17 @@ nsDownloadManager::AddDownloadToDB(const nsAString &aName,
const nsAString &aTempPath,
PRInt64 aStartTime,
PRInt64 aEndTime,
PRInt32 aState)
PRInt32 aState,
const nsACString &aMimeType,
const nsACString &aPreferredApp,
nsHandlerInfoAction aPreferredAction)
{
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"INSERT INTO moz_downloads "
"(name, source, target, tempPath, startTime, endTime, state) "
"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"), getter_AddRefs(stmt));
"(name, source, target, tempPath, startTime, endTime, state, "
"mimeType, preferredApplication, preferredAction) "
"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)"), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, 0);
PRInt32 i = 0;
@ -674,6 +711,18 @@ nsDownloadManager::AddDownloadToDB(const nsAString &aName,
rv = stmt->BindInt32Parameter(i++, aState);
NS_ENSURE_SUCCESS(rv, 0);
// mimeType
rv = stmt->BindUTF8StringParameter(i++, aMimeType);
NS_ENSURE_SUCCESS(rv, 0);
// preferredApplication
rv = stmt->BindUTF8StringParameter(i++, aPreferredApp);
NS_ENSURE_SUCCESS(rv, 0);
// preferredAction
rv = stmt->BindInt32Parameter(i++, aPreferredAction);
NS_ENSURE_SUCCESS(rv, 0);
PRBool hasMore;
rv = stmt->ExecuteStep(&hasMore); // we want to keep our lock
NS_ENSURE_SUCCESS(rv, 0);
@ -775,7 +824,8 @@ nsDownloadManager::GetDownloadFromDB(PRUint32 aID, nsDownload **retVal)
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT id, state, startTime, source, target, tempPath, name, referrer, "
"entityID, currBytes, maxBytes "
"entityID, currBytes, maxBytes, mimeType, preferredAction, "
"preferredApplication "
"FROM moz_downloads "
"WHERE id = ?1"), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, rv);
@ -833,6 +883,52 @@ nsDownloadManager::GetDownloadFromDB(PRUint32 aID, nsDownload **retVal)
PRInt64 maxBytes = stmt->AsInt64(i++);
dl->SetProgressBytes(currBytes, maxBytes);
// Build mMIMEInfo only if the mimeType in DB is not empty
nsCAutoString mimeType;
rv = stmt->GetUTF8String(i++, mimeType);
NS_ENSURE_SUCCESS(rv, rv);
if (!mimeType.IsEmpty()) {
nsCOMPtr<nsIMIMEService> mimeService =
do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = mimeService->GetFromTypeAndExtension(mimeType, EmptyCString(),
getter_AddRefs(dl->mMIMEInfo));
NS_ENSURE_SUCCESS(rv, rv);
nsHandlerInfoAction action = stmt->AsInt32(i++);
rv = dl->mMIMEInfo->SetPreferredAction(action);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString persistentDescriptor;
rv = stmt->GetUTF8String(i++, persistentDescriptor);
NS_ENSURE_SUCCESS(rv, rv);
if (!persistentDescriptor.IsEmpty()) {
nsCOMPtr<nsILocalHandlerApp> handler =
do_CreateInstance(NS_LOCALHANDLERAPP_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsILocalFile> localExecutable;
rv = NS_NewNativeLocalFile(EmptyCString(), PR_FALSE,
getter_AddRefs(localExecutable));
NS_ENSURE_SUCCESS(rv, rv);
rv = localExecutable->SetPersistentDescriptor(persistentDescriptor);
NS_ENSURE_SUCCESS(rv, rv);
rv = handler->SetExecutable(localExecutable);
NS_ENSURE_SUCCESS(rv, rv);
rv = dl->mMIMEInfo->SetPreferredApplicationHandler(handler);
NS_ENSURE_SUCCESS(rv, rv);
}
} else {
// Compensate for the i++s skipped in the true block
i += 2;
}
// Addrefing and returning
NS_ADDREF(*retVal = dl);
return NS_OK;
@ -1090,9 +1186,33 @@ nsDownloadManager::AddDownload(DownloadType aDownloadType,
if (aTempFile)
aTempFile->GetPath(tempPath);
// Break down MIMEInfo but don't panic if we can't get all the pieces - we
// can still download the file
nsCAutoString persistentDescriptor, mimeType;
nsHandlerInfoAction action = nsIMIMEInfo::saveToDisk;
if (aMIMEInfo) {
(void)aMIMEInfo->GetType(mimeType);
nsCOMPtr<nsIHandlerApp> handlerApp;
(void)aMIMEInfo->GetPreferredApplicationHandler(getter_AddRefs(handlerApp));
nsCOMPtr<nsILocalHandlerApp> locHandlerApp = do_QueryInterface(handlerApp);
if (locHandlerApp) {
nsCOMPtr<nsIFile> executable;
(void)locHandlerApp->GetExecutable(getter_AddRefs(executable));
nsCOMPtr<nsILocalFile> locExecutable = do_QueryInterface(executable);
if (locExecutable)
(void)locExecutable->GetPersistentDescriptor(persistentDescriptor);
}
(void)aMIMEInfo->GetPreferredAction(&action);
}
PRInt64 id = AddDownloadToDB(dl->mDisplayName, source, target, tempPath,
dl->mStartTime, dl->mLastUpdate,
nsIDownloadManager::DOWNLOAD_NOTSTARTED);
nsIDownloadManager::DOWNLOAD_NOTSTARTED,
mimeType, persistentDescriptor, action);
NS_ENSURE_TRUE(id, NS_ERROR_FAILURE);
dl->mID = id;
@ -2066,17 +2186,23 @@ nsDownload::ExecuteDesiredAction()
NS_ENSURE_SUCCESS(rv, rv);
}
nsresult ret = NS_OK;
nsresult retVal = NS_OK;
switch (action) {
case nsIMIMEInfo::saveToDisk:
// Move the file to the proper location
ret = MoveTempToTarget();
retVal = MoveTempToTarget();
break;
case nsIMIMEInfo::useHelperApp:
case nsIMIMEInfo::useSystemDefault:
// For these cases we have to move the file to the target location and
// open with the appropriate application
retVal = OpenWithApplication();
break;
default:
break;
}
return ret;
return retVal;
}
nsresult
@ -2107,6 +2233,60 @@ nsDownload::MoveTempToTarget()
return NS_OK;
}
nsresult
nsDownload::OpenWithApplication()
{
// First move the temporary file to the target location
nsCOMPtr<nsILocalFile> target;
nsresult rv = GetTargetFile(getter_AddRefs(target));
NS_ENSURE_SUCCESS(rv, rv);
// 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 = target->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
NS_ENSURE_SUCCESS(rv, rv);
// Move the temporary file to the target location
rv = MoveTempToTarget();
NS_ENSURE_SUCCESS(rv, rv);
// We do not verify the return value here because, irrespective of success
// or failure of the method, the deletion of temp file has to take place, as
// per the corresponding preference. But we store this separately as this is
// what we ultimately return from this function.
nsresult retVal = mMIMEInfo->LaunchWithFile(target);
PRBool deleteTempFileOnExit;
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (!prefs || NS_FAILED(prefs->GetBoolPref(PREF_BH_DELETETEMPFILEONEXIT,
&deleteTempFileOnExit))) {
// No prefservice or no pref set; use default value
#if !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) {
// Use the ExternalHelperAppService to push the temporary file to the list
// of files to be deleted on exit.
nsCOMPtr<nsPIExternalAppLauncher> appLauncher(do_GetService
(NS_EXTERNALHELPERAPPSERVICE_CONTRACTID));
// Even if we are unable to get this service we return the result
// of LaunchWithFile() which makes more sense.
if (appLauncher)
(void)appLauncher->DeleteTemporaryFileOnExit(target);
}
return retVal;
}
void
nsDownload::SetStartTime(PRInt64 aStartTime)
{
@ -2258,12 +2438,7 @@ nsDownload::IsPaused()
PRBool
nsDownload::IsResumable()
{
nsHandlerInfoAction action = nsIMIMEInfo::saveToDisk;
if (mMIMEInfo)
(void)mMIMEInfo->GetPreferredAction(&action);
// For now we can only resume saveToDisk type actions (not open with)
return action == nsIMIMEInfo::saveToDisk && !mEntityID.IsEmpty();
return !mEntityID.IsEmpty();
}
PRBool

Просмотреть файл

@ -133,7 +133,10 @@ protected:
const nsAString &aTempPath,
PRInt64 aStartTime,
PRInt64 aEndTime,
PRInt32 aState);
PRInt32 aState,
const nsACString &aMimeType,
const nsACString &aPreferredApp,
nsHandlerInfoAction aPreferredAction);
void NotifyListenersOnDownloadStateChange(PRInt16 aOldState,
nsIDownload *aDownload);
@ -300,6 +303,18 @@ protected:
*/
nsresult FailDownload(nsresult aStatus, const PRUnichar *aMessage);
/**
* Opens the downloaded file with the appropriate application, which is
* either the OS default, MIME type default, or the one selected by the user.
*
* This also adds the temporary file to the "To be deleted on Exit" list, if
* the corresponding user preference is set (except on OS X).
*
* This function was adopted from nsExternalAppHandler::OpenWithApplication
* (uriloader/exthandler/nsExternalHelperAppService.cpp).
*/
nsresult OpenWithApplication();
nsDownloadManager *mDownloadManager;
nsCOMPtr<nsIURI> mTarget;

Просмотреть файл

@ -0,0 +1,102 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Download Manager Test Code.
*
* The Initial Developer of the Original Code is
* Edward Lee <edward.lee@engineering.uiuc.edu>.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by declaring the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not declare
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
function run_test()
{
// We're testing migration to this version from one version below
var targetVersion = 7;
// First import the downloads.sqlite file
importDatabaseFile("v" + (targetVersion - 1) + ".sqlite");
// Init the download manager which will try migrating to the new version
var dm = Cc["@mozilla.org/download-manager;1"].
getService(Ci.nsIDownloadManager);
var dbConn = dm.DBConnection;
// Check schema version
do_check_true(dbConn.schemaVersion >= targetVersion);
// Make sure all the columns are there
var stmt = dbConn.createStatement(
"SELECT name, source, target, tempPath, startTime, endTime, state, " +
"referrer, entityID, currBytes, maxBytes, mimeType, " +
"preferredApplication, preferredAction " +
"FROM moz_downloads " +
"WHERE id = 28");
stmt.executeStep();
// This data is based on the original values in the table
var data = [
"firefox-3.0a9pre.en-US.linux-i686.tar.bz2",
"http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/latest-trunk/firefox-3.0a9pre.en-US.linux-i686.tar.bz2",
"file:///Users/Ed/Desktop/firefox-3.0a9pre.en-US.linux-i686.tar.bz2",
"/Users/Ed/Desktop/+EZWafFQ.bz2.part",
1192469856209164,
1192469877017396,
4,
"http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/latest-trunk/",
"%2210e66c1-8a2d6b-9b33f380%22/9055595/Mon, 15 Oct 2007 11:45:34 GMT",
1210772,
9055595,
// For the new columns added, check for null or default values
true,
true,
0,
];
// Make sure the values are correct after the migration
var i = 0;
do_check_eq(data[i], stmt.getString(i++));
do_check_eq(data[i], stmt.getUTF8String(i++));
do_check_eq(data[i], stmt.getUTF8String(i++));
do_check_eq(data[i], stmt.getString(i++));
do_check_eq(data[i], stmt.getInt64(i++));
do_check_eq(data[i], stmt.getInt64(i++));
do_check_eq(data[i], stmt.getInt32(i++));
do_check_eq(data[i], stmt.getUTF8String(i++));
do_check_eq(data[i], stmt.getUTF8String(i++));
do_check_eq(data[i], stmt.getInt64(i++));
do_check_eq(data[i], stmt.getInt64(i++));
do_check_eq(data[i], stmt.getIsNull(i++));
do_check_eq(data[i], stmt.getIsNull(i++));
do_check_eq(data[i], stmt.getInt32(i++));
stmt.reset();
stmt.finalize();
cleanup();
}