Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / browser / components / migration / src / nsProfileMigrator.cpp
blob73f615cdd3383c48f5ccf9129c6d4fc93ff3a165
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is The Browser Profile Migrator.
17 * The Initial Developer of the Original Code is Ben Goodger.
18 * Portions created by the Initial Developer are Copyright (C) 2004
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Ben Goodger <ben@bengoodger.com>
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsProfileMigrator.h"
40 #include "nsIBrowserProfileMigrator.h"
41 #include "nsIComponentManager.h"
42 #include "nsIDOMWindowInternal.h"
43 #include "nsILocalFile.h"
44 #include "nsIObserverService.h"
45 #include "nsIProperties.h"
46 #include "nsIServiceManager.h"
47 #include "nsISupportsPrimitives.h"
48 #include "nsISupportsArray.h"
49 #include "nsIToolkitProfile.h"
50 #include "nsIToolkitProfileService.h"
51 #include "nsIWindowWatcher.h"
53 #include "nsCOMPtr.h"
54 #include "nsBrowserCompsCID.h"
55 #include "nsComponentManagerUtils.h"
56 #include "nsDirectoryServiceDefs.h"
57 #include "nsServiceManagerUtils.h"
59 #include "NSReg.h"
60 #include "nsStringAPI.h"
61 #include "nsUnicharUtils.h"
62 #ifdef XP_WIN
63 #include <windows.h>
64 #include "nsIWindowsRegKey.h"
65 #include "nsILocalFileWin.h"
66 #else
67 #include <limits.h>
68 #endif
70 #include "nsAutoPtr.h"
72 #ifndef MAXPATHLEN
73 #ifdef PATH_MAX
74 #define MAXPATHLEN PATH_MAX
75 #elif defined(_MAX_PATH)
76 #define MAXPATHLEN _MAX_PATH
77 #elif defined(CCHMAXPATH)
78 #define MAXPATHLEN CCHMAXPATH
79 #else
80 #define MAXPATHLEN 1024
81 #endif
82 #endif
84 ///////////////////////////////////////////////////////////////////////////////
85 // nsIProfileMigrator
87 #define MIGRATION_WIZARD_FE_URL "chrome://browser/content/migration/migration.xul"
88 #define MIGRATION_WIZARD_FE_FEATURES "chrome,dialog,modal,centerscreen,titlebar"
90 NS_IMETHODIMP
91 nsProfileMigrator::Migrate(nsIProfileStartup* aStartup)
93 nsresult rv;
95 nsCAutoString key;
96 nsCOMPtr<nsIBrowserProfileMigrator> bpm;
98 rv = GetDefaultBrowserMigratorKey(key, bpm);
99 if (NS_FAILED(rv)) return rv;
101 if (!bpm) {
102 nsCAutoString contractID(NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX);
103 contractID.Append(key);
105 bpm = do_CreateInstance(contractID.get());
106 if (!bpm) return NS_ERROR_FAILURE;
109 PRBool sourceExists;
110 bpm->GetSourceExists(&sourceExists);
111 if (!sourceExists) {
112 #ifdef XP_WIN
113 // The "Default Browser" key in the registry was set to a browser for which
114 // no profile data exists. On Windows, this means the Default Browser settings
115 // in the registry are bad, and we should just fall back to IE in this case.
116 bpm = do_CreateInstance(NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "ie");
117 #else
118 return NS_ERROR_FAILURE;
119 #endif
122 nsCOMPtr<nsISupportsCString> cstr
123 (do_CreateInstance("@mozilla.org/supports-cstring;1"));
124 if (!cstr) return NS_ERROR_OUT_OF_MEMORY;
125 cstr->SetData(key);
127 // By opening the Migration FE with a supplied bpm, it will automatically
128 // migrate from it.
129 nsCOMPtr<nsIWindowWatcher> ww(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
130 nsCOMPtr<nsISupportsArray> params =
131 do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID);
132 if (!ww || !params) return NS_ERROR_FAILURE;
134 params->AppendElement(cstr);
135 params->AppendElement(bpm);
136 params->AppendElement(aStartup);
138 nsCOMPtr<nsIDOMWindow> migrateWizard;
139 return ww->OpenWindow(nsnull,
140 MIGRATION_WIZARD_FE_URL,
141 "_blank",
142 MIGRATION_WIZARD_FE_FEATURES,
143 params,
144 getter_AddRefs(migrateWizard));
147 NS_IMETHODIMP
148 nsProfileMigrator::Import()
150 if (ImportRegistryProfiles(NS_LITERAL_CSTRING("Firefox")))
151 return NS_OK;
153 return NS_ERROR_FAILURE;
156 ///////////////////////////////////////////////////////////////////////////////
157 // nsProfileMigrator
159 NS_IMPL_ISUPPORTS1(nsProfileMigrator, nsIProfileMigrator)
161 #ifdef XP_WIN
163 #define INTERNAL_NAME_FIREBIRD "firebird"
164 #define INTERNAL_NAME_FIREFOX "firefox"
165 #define INTERNAL_NAME_PHOENIX "phoenix"
166 #define INTERNAL_NAME_IEXPLORE "iexplore"
167 #define INTERNAL_NAME_MOZILLA_SUITE "apprunner"
168 #define INTERNAL_NAME_SEAMONKEY "seamonkey"
169 #define INTERNAL_NAME_DOGBERT "netscape"
170 #define INTERNAL_NAME_OPERA "opera"
171 #endif
173 nsresult
174 nsProfileMigrator::GetDefaultBrowserMigratorKey(nsACString& aKey,
175 nsCOMPtr<nsIBrowserProfileMigrator>& bpm)
177 #if XP_WIN
179 nsCOMPtr<nsIWindowsRegKey> regKey =
180 do_CreateInstance("@mozilla.org/windows-registry-key;1");
181 if (!regKey)
182 return NS_ERROR_FAILURE;
184 NS_NAMED_LITERAL_STRING(kCommandKey,
185 "SOFTWARE\\Classes\\HTTP\\shell\\open\\command");
187 if (NS_FAILED(regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
188 kCommandKey, nsIWindowsRegKey::ACCESS_READ)))
189 return NS_ERROR_FAILURE;
191 nsAutoString value;
192 if (NS_FAILED(regKey->ReadStringValue(EmptyString(), value)))
193 return NS_ERROR_FAILURE;
195 PRInt32 len = value.Find(NS_LITERAL_STRING(".exe"), CaseInsensitiveCompare);
196 if (len == -1)
197 return NS_ERROR_FAILURE;
199 // Move past ".exe"
200 len += 4;
202 PRUint32 start = 0;
203 // skip an opening quotation mark if present
204 if (value.get()[1] != ':') {
205 start = 1;
206 --len;
209 const nsDependentSubstring filePath(Substring(value, start, len));
211 // We want to find out what the default browser is but the path in and of itself
212 // isn't enough. Why? Because sometimes on Windows paths get truncated like so:
213 // C:\PROGRA~1\MOZILL~2\MOZILL~1.EXE
214 // How do we know what product that is? Mozilla or Mozilla Firebird? etc. Mozilla's
215 // file objects do nothing to 'normalize' the path so we need to attain an actual
216 // product descriptor from the file somehow, and in this case it means getting
217 // the "InternalName" field of the file's VERSIONINFO resource.
219 // In the file's resource segment there is a VERSIONINFO section that is laid
220 // out like this:
222 // VERSIONINFO
223 // StringFileInfo
224 // <TranslationID>
225 // InternalName "iexplore"
226 // VarFileInfo
227 // Translation <TranslationID>
229 // By Querying the VERSIONINFO section for its Tranlations, we can find out where
230 // the InternalName lives. (A file can have more than one translation of its
231 // VERSIONINFO segment, but we just assume the first one).
233 nsCOMPtr<nsILocalFile> lf;
234 NS_NewLocalFile(filePath, PR_TRUE, getter_AddRefs(lf));
235 if (!lf)
236 return NS_ERROR_FAILURE;
238 nsCOMPtr<nsILocalFileWin> lfw = do_QueryInterface(lf);
239 if (!lfw)
240 return NS_ERROR_FAILURE;
242 nsAutoString internalName;
243 if (NS_FAILED(lfw->GetVersionInfoField("InternalName", internalName)))
244 return NS_ERROR_FAILURE;
246 if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_IEXPLORE)) {
247 aKey = "ie";
248 return NS_OK;
250 if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_MOZILLA_SUITE) ||
251 internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_SEAMONKEY)) {
252 aKey = "seamonkey";
253 return NS_OK;
255 if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_DOGBERT)) {
256 aKey = "dogbert";
257 return NS_OK;
259 if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_OPERA)) {
260 aKey = "opera";
261 return NS_OK;
264 // Migrate data from any existing Application Data\Phoenix\* installations.
265 if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_FIREBIRD) ||
266 internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_FIREFOX) ||
267 internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_PHOENIX)) {
268 aKey = "phoenix";
269 return NS_OK;
271 #else
272 PRBool exists = PR_FALSE;
273 #define CHECK_MIGRATOR(browser) do {\
274 bpm = do_CreateInstance(NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX browser);\
275 if (bpm)\
276 bpm->GetSourceExists(&exists);\
277 if (exists) {\
278 aKey = browser;\
279 return NS_OK;\
280 }} while(0)
282 #if defined(XP_MACOSX)
283 CHECK_MIGRATOR("safari");
284 CHECK_MIGRATOR("macie");
285 #endif
286 CHECK_MIGRATOR("phoenix");
287 CHECK_MIGRATOR("seamonkey");
288 CHECK_MIGRATOR("opera");
290 #undef CHECK_MIGRATOR
291 #endif
292 return NS_ERROR_FAILURE;
295 PRBool
296 nsProfileMigrator::ImportRegistryProfiles(const nsACString& aAppName)
298 nsresult rv;
300 nsCOMPtr<nsIToolkitProfileService> profileSvc
301 (do_GetService(NS_PROFILESERVICE_CONTRACTID));
302 NS_ENSURE_TRUE(profileSvc, NS_ERROR_FAILURE);
304 nsCOMPtr<nsIProperties> dirService
305 (do_GetService("@mozilla.org/file/directory_service;1"));
306 NS_ENSURE_TRUE(dirService, NS_ERROR_FAILURE);
308 nsCOMPtr<nsILocalFile> regFile;
309 #ifdef XP_WIN
310 rv = dirService->Get(NS_WIN_APPDATA_DIR, NS_GET_IID(nsILocalFile),
311 getter_AddRefs(regFile));
312 NS_ENSURE_SUCCESS(rv, PR_FALSE);
313 regFile->AppendNative(aAppName);
314 regFile->AppendNative(NS_LITERAL_CSTRING("registry.dat"));
315 #elif defined(XP_MACOSX)
316 rv = dirService->Get(NS_MAC_USER_LIB_DIR, NS_GET_IID(nsILocalFile),
317 getter_AddRefs(regFile));
318 NS_ENSURE_SUCCESS(rv, PR_FALSE);
319 regFile->AppendNative(aAppName);
320 regFile->AppendNative(NS_LITERAL_CSTRING("Application Registry"));
321 #elif defined(XP_OS2)
322 rv = dirService->Get(NS_OS2_HOME_DIR, NS_GET_IID(nsILocalFile),
323 getter_AddRefs(regFile));
324 NS_ENSURE_SUCCESS(rv, PR_FALSE);
325 regFile->AppendNative(aAppName);
326 regFile->AppendNative(NS_LITERAL_CSTRING("registry.dat"));
327 #elif defined(XP_BEOS)
328 rv = dirService->Get(NS_BEOS_SETTINGS_DIR, NS_GET_IID(nsILocalFile),
329 getter_AddRefs(regFile));
330 NS_ENSURE_SUCCESS(rv, PR_FALSE);
331 regFile->AppendNative(aAppName);
332 regFile->AppendNative(NS_LITERAL_CSTRING("appreg"));
333 #else
334 rv = dirService->Get(NS_UNIX_HOME_DIR, NS_GET_IID(nsILocalFile),
335 getter_AddRefs(regFile));
336 NS_ENSURE_SUCCESS(rv, PR_FALSE);
337 nsCAutoString dotAppName;
338 ToLowerCase(aAppName, dotAppName);
339 dotAppName.Insert('.', 0);
341 regFile->AppendNative(dotAppName);
342 regFile->AppendNative(NS_LITERAL_CSTRING("appreg"));
343 #endif
345 nsCAutoString path;
346 rv = regFile->GetNativePath(path);
347 NS_ENSURE_SUCCESS(rv, PR_FALSE);
349 if (NR_StartupRegistry())
350 return PR_FALSE;
352 PRBool migrated = PR_FALSE;
353 HREG reg = nsnull;
354 RKEY profiles = 0;
355 REGENUM enumstate = 0;
356 char profileName[MAXREGNAMELEN];
358 if (NR_RegOpen(path.get(), &reg))
359 goto cleanup;
361 if (NR_RegGetKey(reg, ROOTKEY_COMMON, "Profiles", &profiles))
362 goto cleanup;
364 while (!NR_RegEnumSubkeys(reg, profiles, &enumstate,
365 profileName, MAXREGNAMELEN, REGENUM_CHILDREN)) {
366 #ifdef DEBUG_bsmedberg
367 printf("Found profile %s.\n", profileName);
368 #endif
370 RKEY profile = 0;
371 if (NR_RegGetKey(reg, profiles, profileName, &profile)) {
372 NS_ERROR("Could not get the key that was enumerated.");
373 continue;
376 char profilePath[MAXPATHLEN];
377 if (NR_RegGetEntryString(reg, profile, "directory",
378 profilePath, MAXPATHLEN))
379 continue;
381 nsCOMPtr<nsILocalFile> profileFile
382 (do_CreateInstance("@mozilla.org/file/local;1"));
383 if (!profileFile)
384 continue;
386 #if defined (XP_MACOSX)
387 rv = profileFile->SetPersistentDescriptor(nsDependentCString(profilePath));
388 #else
389 NS_ConvertUTF8toUTF16 widePath(profilePath);
390 rv = profileFile->InitWithPath(widePath);
391 #endif
392 if (NS_FAILED(rv)) continue;
394 nsCOMPtr<nsIToolkitProfile> tprofile;
395 profileSvc->CreateProfile(profileFile, nsnull,
396 nsDependentCString(profileName),
397 getter_AddRefs(tprofile));
398 migrated = PR_TRUE;
401 cleanup:
402 if (reg)
403 NR_RegClose(reg);
404 NR_ShutdownRegistry();
405 return migrated;