400 lines
12 KiB
C++
400 lines
12 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** 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 The Browser Profile Migrator.
|
|
*
|
|
* The Initial Developer of the Original Code is Ben Goodger.
|
|
* Portions created by the Initial Developer are Copyright (C) 2004
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Ben Goodger <ben@bengoodger.com>
|
|
*
|
|
* 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 deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* 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 ***** */
|
|
|
|
#include "nsProfileMigrator.h"
|
|
|
|
#include "nsIBrowserProfileMigrator.h"
|
|
#include "nsIComponentManager.h"
|
|
#include "nsIDOMWindowInternal.h"
|
|
#include "nsILocalFile.h"
|
|
#include "nsIObserverService.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsISupportsPrimitives.h"
|
|
#include "nsISupportsArray.h"
|
|
#include "nsIToolkitProfile.h"
|
|
#include "nsIToolkitProfileService.h"
|
|
#include "nsIWindowWatcher.h"
|
|
|
|
#include "nsCOMPtr.h"
|
|
#include "nsBrowserCompsCID.h"
|
|
#include "nsDirectoryServiceDefs.h"
|
|
|
|
#include "nsCRT.h"
|
|
#include "NSReg.h"
|
|
#include "nsReadableUtils.h"
|
|
#include "nsUnicharUtils.h"
|
|
#include "nsString.h"
|
|
#ifdef XP_WIN
|
|
#include <windows.h>
|
|
#include "nsIWindowsRegKey.h"
|
|
#include "nsILocalFileWin.h"
|
|
#endif
|
|
|
|
#include "nsAutoPtr.h"
|
|
#include "nsNativeCharsetUtils.h"
|
|
|
|
#ifndef MAXPATHLEN
|
|
#ifdef _MAX_PATH
|
|
#define MAXPATHLEN _MAX_PATH
|
|
#elif defined(CCHMAXPATH)
|
|
#define MAXPATHLEN CCHMAXPATH
|
|
#else
|
|
#define MAXPATHLEN 1024
|
|
#endif
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// nsIProfileMigrator
|
|
|
|
#define MIGRATION_WIZARD_FE_URL "chrome://browser/content/migration/migration.xul"
|
|
#define MIGRATION_WIZARD_FE_FEATURES "chrome,dialog,modal,centerscreen,titlebar"
|
|
|
|
NS_IMETHODIMP
|
|
nsProfileMigrator::Migrate(nsIProfileStartup* aStartup)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCAutoString key;
|
|
nsCOMPtr<nsIBrowserProfileMigrator> bpm;
|
|
|
|
rv = GetDefaultBrowserMigratorKey(key, bpm);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (!bpm) {
|
|
nsCAutoString contractID =
|
|
NS_LITERAL_CSTRING(NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX) + key;
|
|
|
|
bpm = do_CreateInstance(contractID.get());
|
|
if (!bpm) return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
PRBool sourceExists;
|
|
bpm->GetSourceExists(&sourceExists);
|
|
if (!sourceExists) {
|
|
#ifdef XP_WIN
|
|
// The "Default Browser" key in the registry was set to a browser for which
|
|
// no profile data exists. On Windows, this means the Default Browser settings
|
|
// in the registry are bad, and we should just fall back to IE in this case.
|
|
bpm = do_CreateInstance(NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "ie");
|
|
#else
|
|
return NS_ERROR_FAILURE;
|
|
#endif
|
|
}
|
|
|
|
nsCOMPtr<nsISupportsCString> cstr
|
|
(do_CreateInstance("@mozilla.org/supports-cstring;1"));
|
|
if (!cstr) return NS_ERROR_OUT_OF_MEMORY;
|
|
cstr->SetData(key);
|
|
|
|
// By opening the Migration FE with a supplied bpm, it will automatically
|
|
// migrate from it.
|
|
nsCOMPtr<nsIWindowWatcher> ww(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
|
|
nsCOMPtr<nsISupportsArray> params;
|
|
NS_NewISupportsArray(getter_AddRefs(params));
|
|
if (!ww || !params) return NS_ERROR_FAILURE;
|
|
|
|
params->AppendElement(cstr);
|
|
params->AppendElement(bpm);
|
|
params->AppendElement(aStartup);
|
|
|
|
nsCOMPtr<nsIDOMWindow> migrateWizard;
|
|
return ww->OpenWindow(nsnull,
|
|
MIGRATION_WIZARD_FE_URL,
|
|
"_blank",
|
|
MIGRATION_WIZARD_FE_FEATURES,
|
|
params,
|
|
getter_AddRefs(migrateWizard));
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsProfileMigrator::Import()
|
|
{
|
|
if (ImportRegistryProfiles(NS_LITERAL_CSTRING("Firefox")))
|
|
return NS_OK;
|
|
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// nsProfileMigrator
|
|
|
|
NS_IMPL_ISUPPORTS1(nsProfileMigrator, nsIProfileMigrator)
|
|
|
|
#ifdef XP_WIN
|
|
|
|
#define INTERNAL_NAME_FIREBIRD "firebird"
|
|
#define INTERNAL_NAME_FIREFOX "firefox"
|
|
#define INTERNAL_NAME_PHOENIX "phoenix"
|
|
#define INTERNAL_NAME_IEXPLORE "iexplore"
|
|
#define INTERNAL_NAME_SEAMONKEY "apprunner"
|
|
#define INTERNAL_NAME_DOGBERT "netscape"
|
|
#define INTERNAL_NAME_OPERA "opera"
|
|
#endif
|
|
|
|
nsresult
|
|
nsProfileMigrator::GetDefaultBrowserMigratorKey(nsACString& aKey,
|
|
nsCOMPtr<nsIBrowserProfileMigrator>& bpm)
|
|
{
|
|
#if XP_WIN
|
|
|
|
nsCOMPtr<nsIWindowsRegKey> regKey =
|
|
do_CreateInstance("@mozilla.org/windows-registry-key;1");
|
|
if (!regKey)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
NS_NAMED_LITERAL_STRING(kCommandKey,
|
|
"SOFTWARE\\Classes\\HTTP\\shell\\open\\command");
|
|
|
|
if (NS_FAILED(regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
|
|
kCommandKey, nsIWindowsRegKey::ACCESS_READ)))
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsAutoString value;
|
|
if (NS_FAILED(regKey->ReadStringValue(EmptyString(), value)))
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsAString::const_iterator start, end;
|
|
value.BeginReading(start);
|
|
value.EndReading(end);
|
|
nsAString::const_iterator tmp = start;
|
|
|
|
if (!FindInReadable(NS_LITERAL_STRING(".exe"), tmp, end,
|
|
nsCaseInsensitiveStringComparator()))
|
|
return NS_ERROR_FAILURE;
|
|
|
|
// skip an opening quotation mark if present
|
|
if (value.CharAt(1) != ':')
|
|
++start;
|
|
|
|
nsDependentSubstring filePath(start, end);
|
|
|
|
// We want to find out what the default browser is but the path in and of itself
|
|
// isn't enough. Why? Because sometimes on Windows paths get truncated like so:
|
|
// C:\PROGRA~1\MOZILL~2\MOZILL~1.EXE
|
|
// How do we know what product that is? Mozilla or Mozilla Firebird? etc. Mozilla's
|
|
// file objects do nothing to 'normalize' the path so we need to attain an actual
|
|
// product descriptor from the file somehow, and in this case it means getting
|
|
// the "InternalName" field of the file's VERSIONINFO resource.
|
|
//
|
|
// In the file's resource segment there is a VERSIONINFO section that is laid
|
|
// out like this:
|
|
//
|
|
// VERSIONINFO
|
|
// StringFileInfo
|
|
// <TranslationID>
|
|
// InternalName "iexplore"
|
|
// VarFileInfo
|
|
// Translation <TranslationID>
|
|
//
|
|
// By Querying the VERSIONINFO section for its Tranlations, we can find out where
|
|
// the InternalName lives. (A file can have more than one translation of its
|
|
// VERSIONINFO segment, but we just assume the first one).
|
|
|
|
nsCOMPtr<nsILocalFile> lf;
|
|
NS_NewLocalFile(filePath, PR_TRUE, getter_AddRefs(lf));
|
|
if (!lf)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsCOMPtr<nsILocalFileWin> lfw = do_QueryInterface(lf);
|
|
if (!lfw)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsAutoString internalName;
|
|
if (NS_FAILED(lfw->GetVersionInfoField("InternalName", internalName)))
|
|
return NS_ERROR_FAILURE;
|
|
|
|
if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_IEXPLORE)) {
|
|
aKey = "ie";
|
|
return NS_OK;
|
|
}
|
|
if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_SEAMONKEY)) {
|
|
aKey = "seamonkey";
|
|
return NS_OK;
|
|
}
|
|
if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_DOGBERT)) {
|
|
aKey = "dogbert";
|
|
return NS_OK;
|
|
}
|
|
if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_OPERA)) {
|
|
aKey = "opera";
|
|
return NS_OK;
|
|
}
|
|
|
|
// Migrate data from any existing Application Data\Phoenix\* installations.
|
|
if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_FIREBIRD) ||
|
|
internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_FIREFOX) ||
|
|
internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_PHOENIX)) {
|
|
aKey = "phoenix";
|
|
return NS_OK;
|
|
}
|
|
#else
|
|
PRBool exists = PR_FALSE;
|
|
#define CHECK_MIGRATOR(browser) do {\
|
|
bpm = do_CreateInstance(NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX browser);\
|
|
if (bpm)\
|
|
bpm->GetSourceExists(&exists);\
|
|
if (exists) {\
|
|
aKey = browser;\
|
|
return NS_OK;\
|
|
}} while(0)
|
|
|
|
#if defined(XP_MACOSX)
|
|
CHECK_MIGRATOR("safari");
|
|
CHECK_MIGRATOR("macie");
|
|
#endif
|
|
CHECK_MIGRATOR("phoenix");
|
|
CHECK_MIGRATOR("seamonkey");
|
|
CHECK_MIGRATOR("opera");
|
|
|
|
#undef CHECK_MIGRATOR
|
|
#endif
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
PRBool
|
|
nsProfileMigrator::ImportRegistryProfiles(const nsACString& aAppName)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIToolkitProfileService> profileSvc
|
|
(do_GetService(NS_PROFILESERVICE_CONTRACTID));
|
|
NS_ENSURE_TRUE(profileSvc, NS_ERROR_FAILURE);
|
|
|
|
nsCOMPtr<nsIProperties> dirService
|
|
(do_GetService("@mozilla.org/file/directory_service;1"));
|
|
NS_ENSURE_TRUE(dirService, NS_ERROR_FAILURE);
|
|
|
|
nsCOMPtr<nsILocalFile> regFile;
|
|
#ifdef XP_WIN
|
|
rv = dirService->Get(NS_WIN_APPDATA_DIR, NS_GET_IID(nsILocalFile),
|
|
getter_AddRefs(regFile));
|
|
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
|
regFile->AppendNative(aAppName);
|
|
regFile->AppendNative(NS_LITERAL_CSTRING("registry.dat"));
|
|
#elif defined(XP_MACOSX)
|
|
rv = dirService->Get(NS_MAC_USER_LIB_DIR, NS_GET_IID(nsILocalFile),
|
|
getter_AddRefs(regFile));
|
|
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
|
regFile->AppendNative(aAppName);
|
|
regFile->AppendNative(NS_LITERAL_CSTRING("Application Registry"));
|
|
#elif defined(XP_OS2)
|
|
rv = dirService->Get(NS_OS2_HOME_DIR, NS_GET_IID(nsILocalFile),
|
|
getter_AddRefs(regFile));
|
|
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
|
regFile->AppendNative(aAppName);
|
|
regFile->AppendNative(NS_LITERAL_CSTRING("registry.dat"));
|
|
#elif defined(XP_BEOS)
|
|
rv = dirService->Get(NS_BEOS_SETTINGS_DIR, NS_GET_IID(nsILocalFile),
|
|
getter_AddRefs(regFile));
|
|
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
|
regFile->AppendNative(aAppName);
|
|
regFile->AppendNative(NS_LITERAL_CSTRING("appreg"));
|
|
#else
|
|
rv = dirService->Get(NS_UNIX_HOME_DIR, NS_GET_IID(nsILocalFile),
|
|
getter_AddRefs(regFile));
|
|
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
|
nsCAutoString dotAppName;
|
|
ToLowerCase(aAppName, dotAppName);
|
|
dotAppName.Insert('.', 0);
|
|
|
|
regFile->AppendNative(dotAppName);
|
|
regFile->AppendNative(NS_LITERAL_CSTRING("appreg"));
|
|
#endif
|
|
|
|
nsCAutoString path;
|
|
rv = regFile->GetNativePath(path);
|
|
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
|
|
|
if (NR_StartupRegistry())
|
|
return PR_FALSE;
|
|
|
|
PRBool migrated = PR_FALSE;
|
|
HREG reg = nsnull;
|
|
RKEY profiles = 0;
|
|
REGENUM enumstate = 0;
|
|
char profileName[MAXREGNAMELEN];
|
|
|
|
if (NR_RegOpen(path.get(), ®))
|
|
goto cleanup;
|
|
|
|
if (NR_RegGetKey(reg, ROOTKEY_COMMON, "Profiles", &profiles))
|
|
goto cleanup;
|
|
|
|
while (!NR_RegEnumSubkeys(reg, profiles, &enumstate,
|
|
profileName, MAXREGNAMELEN, REGENUM_CHILDREN)) {
|
|
#ifdef DEBUG_bsmedberg
|
|
printf("Found profile %s.\n", profileName);
|
|
#endif
|
|
|
|
RKEY profile = 0;
|
|
if (NR_RegGetKey(reg, profiles, profileName, &profile)) {
|
|
NS_ERROR("Could not get the key that was enumerated.");
|
|
continue;
|
|
}
|
|
|
|
char profilePath[MAXPATHLEN];
|
|
if (NR_RegGetEntryString(reg, profile, "directory",
|
|
profilePath, MAXPATHLEN))
|
|
continue;
|
|
|
|
nsCOMPtr<nsILocalFile> profileFile
|
|
(do_CreateInstance("@mozilla.org/file/local;1"));
|
|
if (!profileFile)
|
|
continue;
|
|
|
|
#if defined (XP_MACOSX)
|
|
rv = profileFile->SetPersistentDescriptor(nsDependentCString(profilePath));
|
|
#else
|
|
NS_ConvertUTF8toUTF16 widePath(profilePath);
|
|
rv = profileFile->InitWithPath(widePath);
|
|
#endif
|
|
if (NS_FAILED(rv)) continue;
|
|
|
|
nsCOMPtr<nsIToolkitProfile> tprofile;
|
|
profileSvc->CreateProfile(profileFile, nsnull,
|
|
nsDependentCString(profileName),
|
|
getter_AddRefs(tprofile));
|
|
migrated = PR_TRUE;
|
|
}
|
|
|
|
cleanup:
|
|
if (reg)
|
|
NR_RegClose(reg);
|
|
NR_ShutdownRegistry();
|
|
return migrated;
|
|
}
|