Bug 463982 - Drop configure support for cairo-mac widget toolkit, r=ted
[wine-gecko.git] / profile / pref-migrator / src / nsPrefMigration.cpp
blob5e85c0502b3c03f9aa393950e3466410a5051620
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 Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Don Bragg <dbragg@netscape.com>
24 * Seth Spitzer <sspitzer@netscape.com>
25 * Pierre Phaneuf <pp@ludusdesign.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "pratom.h"
42 #include "nsIComponentManager.h"
43 #include "nsIComponentManager.h"
44 #include "nsIPromptService.h"
45 #include "nsIServiceManager.h"
46 #include "nsPIDOMWindow.h"
47 #include "nsIScriptContext.h"
48 #include "nsILocalFile.h"
49 #include "nsDirectoryServiceUtils.h"
50 #include "nsDirectoryServiceDefs.h"
51 #include "nsDependentString.h"
52 #include "nsFileStream.h"
53 #include "nsIFileSpec.h"
54 #include "nsCOMPtr.h"
55 #include "prio.h"
56 #include "prerror.h"
57 #include "prmem.h"
58 #include "nsIPrefService.h"
59 #include "plstr.h"
60 #include "prprf.h"
61 #include "nsXPIDLString.h"
62 #include "nsReadableUtils.h"
63 #include "nsIStringBundle.h"
64 #include "nsProxiedService.h"
66 #include "nsNetUtil.h"
67 #include "nsCRT.h"
69 #include "nsVoidArray.h"
71 #include "nsIBaseWindow.h"
72 #include "nsIDocShell.h"
73 #include "nsIDocShellTreeItem.h"
74 #include "nsIDocShellTreeOwner.h"
75 #include "nsIWebBrowserChrome.h"
76 #include "nsIWindowWatcher.h"
77 #include "nsEmbedCID.h"
79 #ifdef DEBUG_seth
80 #define DEBUG_UTF8_CONVERSION 1
81 #endif
83 #include "nsICharsetConverterManager.h"
84 #include "nsIPlatformCharset.h"
86 #define CHROME_STYLE nsIWebBrowserChrome::CHROME_ALL | nsIWebBrowserChrome::CHROME_CENTER_SCREEN
87 #define MIGRATION_PROPERTIES_URL "chrome://communicator/locale/profile/migration.properties"
89 /* Network */
91 #include "nsPrefMigration.h"
92 #include "nsPrefMigrationFactory.h"
94 #define PREF_FILE_HEADER_STRING "# Mozilla User Preferences "
96 #define MAX_PREF_LEN 1024
98 #if defined(XP_UNIX) && !defined(XP_MACOSX)
99 #define IMAP_MAIL_FILTER_FILE_NAME_IN_4x "mailrule"
100 #define POP_MAIL_FILTER_FILE_NAME_IN_4x "mailrule"
101 #define MAIL_SUMMARY_SUFFIX_IN_4x ".summary"
102 #define NEWS_SUMMARY_SUFFIX_IN_4x ".snm"
103 #define COOKIES_FILE_NAME_IN_4x "cookies"
104 #define BOOKMARKS_FILE_NAME_IN_4x "bookmarks.html"
105 #define NEWSRC_PREFIX_IN_4x ".newsrc-"
106 #define SNEWSRC_PREFIX_IN_4x ".snewsrc-"
107 #define POPSTATE_FILE_IN_4x "popstate"
108 #define PSM_CERT7_DB "cert7.db"
109 #define PSM_KEY3_DB "key3.db"
110 #define PSM_SECMODULE_DB "secmodule.db"
111 #elif defined(XP_MACOSX)
112 #define MAC_RULES_FILE_ENDING_STRING_IN_4X " Rules"
113 #define IMAP_MAIL_FILTER_FILE_NAME_IN_4x "<hostname> Rules"
114 #define POP_MAIL_FILTER_FILE_NAME_IN_4x "Filter Rules"
115 #define MAIL_SUMMARY_SUFFIX_IN_4x ".snm"
116 #define NEWS_SUMMARY_SUFFIX_IN_4x ".snm"
117 #define COOKIES_FILE_NAME_IN_4x "MagicCookie"
118 #define BOOKMARKS_FILE_NAME_IN_4x "Bookmarks.html"
119 #define POPSTATE_FILE_IN_4x "Pop State"
120 #define SECURITY_PATH "Security"
121 #define PSM_CERT7_DB "Certificates7"
122 #define PSM_KEY3_DB "Key Database3"
123 #define PSM_SECMODULE_DB "Security Modules"
124 #else /* XP_WIN || XP_OS2 */
125 #define IMAP_MAIL_FILTER_FILE_NAME_IN_4x "rules.dat"
126 #define POP_MAIL_FILTER_FILE_NAME_IN_4x "rules.dat"
127 #define MAIL_SUMMARY_SUFFIX_IN_4x ".snm"
128 #define NEWS_SUMMARY_SUFFIX_IN_4x ".snm"
129 #define COOKIES_FILE_NAME_IN_4x "cookies.txt"
130 #define BOOKMARKS_FILE_NAME_IN_4x "bookmark.htm"
131 // purposely not defined, since it was in the right place
132 // and with the right name in 4.x
133 //#define POPSTATE_FILE_IN_4x "popstate.dat"
134 #define PSM_CERT7_DB "cert7.db"
135 #define PSM_KEY3_DB "key3.db"
136 #define PSM_SECMODULE_DB "secmod.db"
137 #endif /* XP_UNIX */
139 #define SUMMARY_SUFFIX_IN_5x ".msf"
140 #define COOKIES_FILE_NAME_IN_5x "cookies.txt"
141 #define IMAP_MAIL_FILTER_FILE_NAME_IN_5x "rules.dat"
142 #define POP_MAIL_FILTER_FILE_NAME_IN_5x "rules.dat"
143 #define POPSTATE_FILE_IN_5x "popstate.dat"
144 #define BOOKMARKS_FILE_NAME_IN_5x "bookmarks.html"
145 #define HISTORY_FILE_NAME_IN_5x "history.dat"
147 // only UNIX had movemail in 4.x
148 #if defined(XP_UNIX) && !defined(XP_MACOSX)
149 #define HAVE_MOVEMAIL 1
150 #endif /* XP_UNIX */
152 #define PREMIGRATION_PREFIX "premigration."
154 // this is for the hidden preference setting in mozilla/modules/libpref/src/init/mailnews.js
155 // pref("mail.migration.copyMailFiles", true);
157 // see bugzilla bug 80035 (http://bugzilla.mozilla.org/show_bug.cgi?id=80035)
159 // the default value for this setting is true which means when migrating from
160 // Netscape 4.x, mozilla will copy all the contents of Local Folders and Imap
161 // Folder to the newly created subfolders of migrated mozilla profile
162 // when this value is set to false, mozilla will not copy these contents and
163 // still share them with Netscape 4.x
165 // Advantages of forbidding copy operation:
166 // reduce the disk usage
167 // quick migration
168 // Disadvantage of forbidding copy operation:
169 // without perfect lock mechamism, there is possibility of data corruption
170 // when Netscape 4.x and mozilla run at the same time and access the same
171 // mail file at the same time
172 #define PREF_MIGRATION_MODE_FOR_MAIL "mail.migration.copyMailFiles"
174 #define PREF_MAIL_DIRECTORY "mail.directory"
175 #define PREF_NEWS_DIRECTORY "news.directory"
176 #define PREF_MAIL_IMAP_ROOT_DIR "mail.imap.root_dir"
177 #define PREF_NETWORK_HOSTS_POP_SERVER "network.hosts.pop_server"
178 #define PREF_4X_NETWORK_HOSTS_IMAP_SERVER "network.hosts.imap_servers"
179 #define PREF_MAIL_SERVER_TYPE "mail.server_type"
180 #define PREF_BROWSER_CACHE_DIRECTORY "browser.cache.directory"
181 #define POP_4X_MAIL_TYPE 0
182 #define IMAP_4X_MAIL_TYPE 1
183 #ifdef HAVE_MOVEMAIL
184 #define MOVEMAIL_4X_MAIL_TYPE 2
185 #define NEW_MOVEMAIL_DIR_NAME "movemail"
186 #endif /* HAVE_MOVEMAIL */
188 #if defined(XP_UNIX) && !defined(XP_MACOSX)
189 /* a 4.x profile on UNIX is rooted at something like
190 * "/u/sspitzer/.netscape"
191 * profile + OLD_MAIL_DIR_NAME = "/u/sspitzer/.netscape/../nsmail" = "/u/sspitzer/nsmail"
192 * profile + OLD_NEWS_DIR_NAME = "/u/sspitzer/.netscape/xover-cache"
193 * profile + OLD_IMAPMAIL_DIR_NAME = "/u/sspitzer/.netscape/../ns_imap" = "/u/sspitzer/ns_imap"
194 * which is as good as we're going to get for defaults on UNIX.
196 #define OLD_MAIL_DIR_NAME "/../nsmail"
197 #define OLD_NEWS_DIR_NAME "/xover-cache"
198 #define OLD_IMAPMAIL_DIR_NAME "/../ns_imap"
199 #else
200 #define OLD_MAIL_DIR_NAME "Mail"
201 #define OLD_NEWS_DIR_NAME "News"
202 #define OLD_IMAPMAIL_DIR_NAME "ImapMail"
203 #endif /* XP_UNIX */
205 #define NEW_DIR_SUFFIX "5"
207 #define PREF_FILE_NAME_IN_5x "prefs.js"
209 #define PREF_MIGRATION_PROGRESS_URL "chrome://communicator/content/profile/profileMigrationProgress.xul"
211 typedef struct
213 const char* oldFile;
214 const char* newFile;
216 } MigrateProfileItem;
219 * In 4.x the mac cookie file used expiration times starting from
220 * 1900 whereas all the other platforms started from
221 * 1970. In 5.0 it was made cross platform so that all platforms use
222 * expiration times starting from 1970. That means that mac cookies
223 * generated in 4.x cannot be migrated to 5.0 as is -- instead the
224 * expiration time must first be decreased by
225 * the number of seconds between 1-1-1900 and 1-1-1970
227 * 70 years * 365 days/year * 86,400 secs/day = 2,207,520,000 seconds
228 * + 17 leap years * 86,400 additional sec/leapyear = 1,468,800 seconds
229 * = 2,208,988,800 seconds
231 #if defined(XP_MACOSX)
232 #define NEED_TO_FIX_4X_COOKIES 1
233 #define SECONDS_BETWEEN_1900_AND_1970 2208988800UL
234 #endif /* XP_MACOSX */
236 /*-----------------------------------------------------------------
237 * Globals
238 *-----------------------------------------------------------------*/
239 nsPrefMigration* nsPrefMigration::mInstance = nsnull;
241 nsPrefMigration *
242 nsPrefMigration::GetInstance()
244 if (mInstance == nsnull)
246 mInstance = new nsPrefMigration();
248 return mInstance;
253 nsPrefMigration::nsPrefMigration()
255 mErrorCode = NS_OK;
260 PRBool ProfilesToMigrateCleanup(void* aElement, void *aData)
262 if (aElement)
263 delete (MigrateProfileItem*)aElement;
265 return PR_TRUE;
268 nsPrefMigration::~nsPrefMigration()
270 mProfilesToMigrate.EnumerateForwards((nsVoidArrayEnumFunc)ProfilesToMigrateCleanup, nsnull);
271 mInstance = nsnull;
276 nsresult
277 nsPrefMigration::getPrefService()
279 // get the prefs service
280 nsresult rv = NS_OK;
282 nsCOMPtr<nsIPrefBranch> pIMyService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
283 if(NS_FAILED(rv)) return rv;
285 return NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD, NS_GET_IID(nsIPrefBranch),
286 pIMyService, NS_PROXY_SYNC,
287 getter_AddRefs(m_prefBranch));
291 NS_IMPL_THREADSAFE_ISUPPORTS1(nsPrefMigration, nsIPrefMigration)
293 NS_IMETHODIMP
294 nsPrefMigration::AddProfilePaths(const char * oldProfilePathStr, const char * newProfilePathStr)
296 MigrateProfileItem* item = new MigrateProfileItem();
297 if (!item)
298 return NS_ERROR_OUT_OF_MEMORY;
300 item->oldFile = oldProfilePathStr;
301 item->newFile = newProfilePathStr;
303 if (mProfilesToMigrate.AppendElement((void*)item))
304 return NS_OK;
306 return NS_ERROR_FAILURE;
310 NS_IMETHODIMP
311 nsPrefMigration::ProcessPrefs(PRBool showProgressAsModalWindow)
313 nsresult rv;
315 nsCOMPtr<nsIWindowWatcher> windowWatcher(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
316 if (NS_FAILED(rv)) return rv;
318 // WindowWatcher can work with or without parent window
319 rv = windowWatcher->OpenWindow(nsnull,
320 PREF_MIGRATION_PROGRESS_URL,
321 "_blank",
322 "centerscreen,modal,titlebar",
323 nsnull,
324 getter_AddRefs(mPMProgressWindow));
325 if (NS_FAILED(rv)) return rv;
327 return NS_OK;
331 static PRThread* gMigrationThread = nsnull;
334 extern "C" void ProfileMigrationController(void *data)
336 if (!data) return;
338 nsPrefMigration* migrator = (nsPrefMigration*)data;
339 nsIPrefMigration* interfaceM = (nsIPrefMigration*)data;
340 PRInt32 index = 0;
341 PRInt32 choice = 0;
342 nsresult rv = NS_OK;
344 nsCOMPtr<nsIPrefMigration> prefProxy;
346 do {
348 choice = 0;
349 migrator->mErrorCode = 0;
350 MigrateProfileItem* item = nsnull;
352 if (migrator->mProfilesToMigrate.Count() != 0)
353 item = (MigrateProfileItem*)migrator->mProfilesToMigrate.ElementAt(index);
354 if (item)
356 rv = migrator->ProcessPrefsCallback(item->oldFile, item->newFile);
357 if (NS_FAILED(rv))
359 migrator->mErrorCode = rv;
360 #ifdef DEBUG
361 printf("failed to migrate properly. err=%d\n",rv);
362 #endif
365 else
367 migrator->mErrorCode = NS_ERROR_FAILURE;
368 return;
371 nsCOMPtr<nsIPrefMigration> migratorInterface = do_QueryInterface(interfaceM, &rv);
372 if (NS_FAILED(rv))
374 migrator->mErrorCode = rv;
375 return;
378 if (!prefProxy)
380 rv = NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
381 NS_GET_IID(nsIPrefMigration),
382 migratorInterface, NS_PROXY_SYNC,
383 getter_AddRefs(prefProxy));
384 if (NS_FAILED(rv))
386 migrator->mErrorCode = rv;
387 return;
392 if (migrator->mErrorCode != 0)
394 if (migrator->mErrorCode == MIGRATION_RETRY)
396 rv = prefProxy->ShowSpaceDialog(&choice);
397 if (NS_FAILED(rv))
399 migrator->mErrorCode = rv;
400 return;
402 choice++;// Increment choice to match the RETRY=1, CANCEL=2 and CREATE_NEW=3 format
406 } while (choice == MIGRATION_RETRY);
408 prefProxy->WindowCloseCallback();
409 migrator->mErrorCode = choice;
413 NS_IMETHODIMP
414 nsPrefMigration::WindowCloseCallback()
416 nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mPMProgressWindow));
417 if (!window) return NS_ERROR_FAILURE;
419 nsCOMPtr<nsIDocShellTreeItem> treeItem =
420 do_QueryInterface(window->GetDocShell());
421 if (!treeItem) return NS_ERROR_FAILURE;
422 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
423 treeItem->GetTreeOwner(getter_AddRefs(treeOwner));
424 if (!treeOwner) return NS_ERROR_FAILURE;
425 nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(treeOwner));
426 if (baseWindow)
427 baseWindow->Destroy();
429 #ifdef DEBUG
430 printf("end of pref migration\n");
431 #endif
432 return NS_OK;
436 NS_IMETHODIMP
437 nsPrefMigration::ShowSpaceDialog(PRInt32 *choice)
439 nsresult rv;
440 nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
441 if (NS_FAILED(rv)) return rv;
443 nsCOMPtr<nsIStringBundle> bundle;
444 rv = bundleService->CreateBundle(MIGRATION_PROPERTIES_URL, getter_AddRefs(bundle));
445 if (NS_FAILED(rv)) return rv;
447 nsXPIDLString noSpaceTitle, noSpaceText, retryLabel, createNewLabel;
448 rv = bundle->GetStringFromName(NS_LITERAL_STRING("noSpace.title").get(), getter_Copies(noSpaceTitle));
449 if (NS_FAILED(rv)) return rv;
450 rv = bundle->GetStringFromName(NS_LITERAL_STRING("noSpace.text").get(), getter_Copies(noSpaceText));
451 if (NS_FAILED(rv)) return rv;
452 rv = bundle->GetStringFromName(NS_LITERAL_STRING("retry.label").get(), getter_Copies(retryLabel));
453 if (NS_FAILED(rv)) return rv;
454 rv = bundle->GetStringFromName(NS_LITERAL_STRING("createNew.label").get(), getter_Copies(createNewLabel));
455 if (NS_FAILED(rv)) return rv;
457 nsCOMPtr<nsIPromptService> promptService = do_GetService(NS_PROMPTSERVICE_CONTRACTID, &rv);
458 if (NS_FAILED(rv)) return rv;
460 const PRUint32 buttons =
461 (nsIPromptService::BUTTON_TITLE_IS_STRING * nsIPromptService::BUTTON_POS_0)+
462 (nsIPromptService::BUTTON_TITLE_CANCEL * nsIPromptService::BUTTON_POS_1)+
463 (nsIPromptService::BUTTON_TITLE_IS_STRING * nsIPromptService::BUTTON_POS_2);
464 return promptService->ConfirmEx(mPMProgressWindow, noSpaceTitle, noSpaceText,
465 buttons, retryLabel, nsnull, createNewLabel,
466 nsnull, nsnull, choice);
470 NS_IMETHODIMP
471 nsPrefMigration::ProcessPrefsFromJS() // called via js so that we can have progress bar that show up.
473 gMigrationThread = PR_CreateThread(PR_USER_THREAD,
474 ProfileMigrationController,
475 this,
476 PR_PRIORITY_NORMAL,
477 PR_GLOBAL_THREAD,
478 PR_UNJOINABLE_THREAD,
479 0);
480 return NS_OK;
484 NS_IMETHODIMP
485 nsPrefMigration::GetError()
487 return mErrorCode;
490 nsresult
491 nsPrefMigration::ConvertPersistentStringToFileSpec(const char *str, nsIFileSpec *path)
493 nsresult rv;
494 if (!str || !path) return NS_ERROR_NULL_POINTER;
496 rv = path->SetPersistentDescriptorString(str);
497 return rv;
500 /*--------------------------------------------------------------------------
501 * ProcessPrefsCallback is the primary funtion for the class nsPrefMigration.
503 * Called by: The Profile Manager (nsProfile.cpp)
504 * INPUT: The specific profile path (prefPath) and the 5.0 installed path
505 * OUTPUT: The modified 5.0 prefs files
506 * RETURN: Success or a failure code
508 *-------------------------------------------------------------------------*/
509 nsresult
510 nsPrefMigration::ProcessPrefsCallback(const char* oldProfilePathStr, const char * newProfilePathStr)
512 nsresult rv;
514 nsCOMPtr<nsIFileSpec> oldProfilePath;
515 nsCOMPtr<nsIFileSpec> newProfilePath;
516 nsCOMPtr<nsIFileSpec> oldPOPMailPath;
517 nsCOMPtr<nsIFileSpec> newPOPMailPath;
518 nsCOMPtr<nsIFileSpec> oldIMAPMailPath;
519 nsCOMPtr<nsIFileSpec> newIMAPMailPath;
520 nsCOMPtr<nsIFileSpec> oldIMAPLocalMailPath;
521 nsCOMPtr<nsIFileSpec> newIMAPLocalMailPath;
522 nsCOMPtr<nsIFileSpec> oldNewsPath;
523 nsCOMPtr<nsIFileSpec> newNewsPath;
524 nsCOMPtr<nsILocalFile> newPrefsFile;
525 #ifdef HAVE_MOVEMAIL
526 nsCOMPtr<nsIFileSpec> oldMOVEMAILMailPath;
527 nsCOMPtr<nsIFileSpec> newMOVEMAILMailPath;
528 #endif /* HAVE_MOVEMAIL */
529 PRBool exists = PR_FALSE,
530 enoughSpace = PR_TRUE,
531 localMailDriveDefault = PR_FALSE,
532 summaryMailDriveDefault = PR_FALSE,
533 newsDriveDefault = PR_FALSE,
534 copyMailFileInMigration = PR_TRUE;
536 nsFileSpec localMailSpec,
537 summaryMailSpec,
538 newsSpec,
539 oldProfileSpec, newProfileSpec;
541 PRInt32 serverType = POP_4X_MAIL_TYPE;
542 char *popServerName = nsnull;
544 PRUint32 totalLocalMailSize = 0,
545 totalSummaryFileSize = 0,
546 totalNewsSize = 0,
547 totalProfileSize = 0,
548 totalRequired = 0;
551 PRInt64 localMailDrive = LL_Zero(),
552 summaryMailDrive = LL_Zero(),
553 newsDrive = LL_Zero(),
554 profileDrive = LL_Zero();
556 PRInt64 DriveID[MAX_DRIVES];
557 PRUint32 SpaceRequired[MAX_DRIVES];
559 #if defined(NS_DEBUG)
560 printf("*Entered Actual Migration routine*\n");
561 #endif
563 for (int i=0; i < MAX_DRIVES; i++)
565 DriveID[i] = LL_Zero();
566 SpaceRequired[i] = 0;
569 rv = getPrefService();
570 if (NS_FAILED(rv)) return rv;
572 rv = NS_NewFileSpec(getter_AddRefs(oldProfilePath));
573 if (NS_FAILED(rv)) return rv;
574 rv = NS_NewFileSpec(getter_AddRefs(newProfilePath));
575 if (NS_FAILED(rv)) return rv;
577 rv = ConvertPersistentStringToFileSpec(oldProfilePathStr, oldProfilePath);
578 if (NS_FAILED(rv)) return rv;
579 rv = ConvertPersistentStringToFileSpec(newProfilePathStr, newProfilePath);
580 if (NS_FAILED(rv)) return rv;
582 oldProfilePath->GetFileSpec(&oldProfileSpec);
583 newProfilePath->GetFileSpec(&newProfileSpec);
586 /* initialize prefs with the old prefs.js file (which is a copy of the 4.x preferences file) */
587 nsCOMPtr<nsIFileSpec> PrefsFile4x;
589 //Get the location of the 4.x prefs file
590 rv = NS_NewFileSpec(getter_AddRefs(PrefsFile4x));
591 if (NS_FAILED(rv)) return rv;
593 rv = PrefsFile4x->FromFileSpec(oldProfilePath);
594 if (NS_FAILED(rv)) return rv;
596 rv = PrefsFile4x->AppendRelativeUnixPath(PREF_FILE_NAME_IN_4x);
597 if (NS_FAILED(rv)) return rv;
599 //Need to convert PrefsFile4x to an IFile in order to copy it to a
600 //unique name in the system temp directory.
601 nsFileSpec PrefsFile4xAsFileSpec;
602 rv = PrefsFile4x->GetFileSpec(&PrefsFile4xAsFileSpec);
603 if (NS_FAILED(rv)) return rv;
605 nsCOMPtr<nsILocalFile> PrefsFile4xAsIFile;
606 rv = NS_FileSpecToIFile(&PrefsFile4xAsFileSpec,
607 getter_AddRefs(PrefsFile4xAsIFile));
608 if (NS_FAILED(rv)) return rv;
610 nsCOMPtr<nsIFile> systemTempDir;
611 rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(systemTempDir));
612 if (NS_FAILED(rv)) return rv;
614 systemTempDir->AppendNative(NS_LITERAL_CSTRING("migrate"));
616 //Create a unique directory in the system temp dir based on the name of the 4.x prefs file
617 rv = systemTempDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700);
618 if (NS_FAILED(rv)) return rv;
620 rv = PrefsFile4xAsIFile->CopyToNative(systemTempDir, NS_LITERAL_CSTRING(PREF_FILE_NAME_IN_4x));
621 if (NS_FAILED(rv)) return rv;
623 nsCOMPtr<nsIFile> cloneFile;
624 rv = systemTempDir->Clone(getter_AddRefs(cloneFile));
625 if (NS_FAILED(rv)) return rv;
627 m_prefsFile = do_QueryInterface(cloneFile, &rv);
628 if (NS_FAILED(rv)) return rv;
630 rv = m_prefsFile->AppendNative(NS_LITERAL_CSTRING(PREF_FILE_NAME_IN_4x));
631 if (NS_FAILED(rv)) return rv;
633 nsCOMPtr<nsIPrefService> psvc(do_QueryInterface(m_prefBranch));
635 //Clear the prefs in case a previous set was read in.
636 psvc->ResetPrefs();
638 //Now read the prefs from the prefs file in the system directory
639 psvc->ReadUserPrefs(m_prefsFile);
642 // Start computing the sizes required for migration
644 rv = GetSizes(oldProfileSpec, PR_FALSE, &totalProfileSize);
645 profileDrive = newProfileSpec.GetDiskSpaceAvailable();
647 rv = m_prefBranch->GetIntPref(PREF_MAIL_SERVER_TYPE, &serverType);
648 if (NS_FAILED(rv)) return rv;
650 // get the migration mode for mail
651 rv = m_prefBranch->GetBoolPref(PREF_MIGRATION_MODE_FOR_MAIL,
652 &copyMailFileInMigration);
653 if (NS_FAILED(rv))
654 return rv;
656 if (serverType == POP_4X_MAIL_TYPE) {
657 summaryMailDriveDefault = PR_TRUE; //summary files are only used in IMAP so just set it to true here.
658 summaryMailDrive = profileDrive; //just set the drive for summary files to be the same as the new profile
660 rv = NS_NewFileSpec(getter_AddRefs(newPOPMailPath));
661 if (NS_FAILED(rv)) return rv;
663 rv = NS_NewFileSpec(getter_AddRefs(oldPOPMailPath));
664 if (NS_FAILED(rv)) return rv;
666 rv = GetDirFromPref(oldProfilePath,newProfilePath,NEW_MAIL_DIR_NAME, PREF_MAIL_DIRECTORY, newPOPMailPath, oldPOPMailPath);
667 if (NS_FAILED(rv)) {
668 rv = DetermineOldPath(oldProfilePath, OLD_MAIL_DIR_NAME, "mailDirName", oldPOPMailPath);
669 if (NS_FAILED(rv)) return rv;
671 rv = SetPremigratedFilePref(PREF_MAIL_DIRECTORY, oldPOPMailPath);
672 if (NS_FAILED(rv)) return rv;
674 rv = newPOPMailPath->FromFileSpec(newProfilePath);
675 if (NS_FAILED(rv)) return rv;
677 localMailDriveDefault = PR_TRUE;
679 oldPOPMailPath->GetFileSpec(&localMailSpec);
680 rv = GetSizes(localMailSpec, PR_TRUE, &totalLocalMailSize);
681 localMailDrive = localMailSpec.GetDiskSpaceAvailable();
683 else if(serverType == IMAP_4X_MAIL_TYPE) {
684 rv = NS_NewFileSpec(getter_AddRefs(newIMAPLocalMailPath));
685 if (NS_FAILED(rv)) return rv;
687 rv = NS_NewFileSpec(getter_AddRefs(oldIMAPLocalMailPath));
688 if (NS_FAILED(rv)) return rv;
690 /* First get the actual 4.x "Local Mail" files location */
691 rv = GetDirFromPref(oldProfilePath,newProfilePath, NEW_MAIL_DIR_NAME, PREF_MAIL_DIRECTORY, newIMAPLocalMailPath, oldIMAPLocalMailPath);
692 if (NS_FAILED(rv)) {
693 rv = DetermineOldPath(oldProfilePath, OLD_MAIL_DIR_NAME, "mailDirName", oldIMAPLocalMailPath);
694 if (NS_FAILED(rv)) return rv;
696 rv = SetPremigratedFilePref(PREF_MAIL_DIRECTORY, oldIMAPLocalMailPath);
697 if (NS_FAILED(rv)) return rv;
699 rv = newIMAPLocalMailPath->FromFileSpec(newProfilePath);
700 if (NS_FAILED(rv)) return rv;
702 localMailDriveDefault = PR_TRUE;
705 oldIMAPLocalMailPath->GetFileSpec(&localMailSpec);
706 rv = GetSizes(localMailSpec, PR_TRUE, &totalLocalMailSize);
707 localMailDrive = localMailSpec.GetDiskSpaceAvailable();
709 /* Next get IMAP mail summary files location */
710 rv = NS_NewFileSpec(getter_AddRefs(newIMAPMailPath));
711 if (NS_FAILED(rv)) return rv;
713 rv = NS_NewFileSpec(getter_AddRefs(oldIMAPMailPath));
714 if (NS_FAILED(rv)) return rv;
716 rv = GetDirFromPref(oldProfilePath,newProfilePath, NEW_IMAPMAIL_DIR_NAME, PREF_MAIL_IMAP_ROOT_DIR,newIMAPMailPath,oldIMAPMailPath);
717 if (NS_FAILED(rv)) {
718 rv = oldIMAPMailPath->FromFileSpec(oldProfilePath);
719 if (NS_FAILED(rv)) return rv;
721 /* we didn't over localize "ImapMail" in 4.x, so this is all we have to do */
722 rv = oldIMAPMailPath->AppendRelativeUnixPath(OLD_IMAPMAIL_DIR_NAME);
723 if (NS_FAILED(rv)) return rv;
725 rv = SetPremigratedFilePref(PREF_MAIL_IMAP_ROOT_DIR, oldIMAPMailPath);
726 if (NS_FAILED(rv)) return rv;
728 rv = newIMAPMailPath->FromFileSpec(newProfilePath);
729 if (NS_FAILED(rv)) return rv;
731 summaryMailDriveDefault = PR_TRUE;
734 oldIMAPMailPath->GetFileSpec(&summaryMailSpec);
735 rv = GetSizes(summaryMailSpec, PR_TRUE, &totalSummaryFileSize);
736 summaryMailDrive = summaryMailSpec.GetDiskSpaceAvailable();
739 #ifdef HAVE_MOVEMAIL
740 else if (serverType == MOVEMAIL_4X_MAIL_TYPE) {
742 summaryMailDriveDefault = PR_TRUE;
743 summaryMailDrive = profileDrive;
745 rv = NS_NewFileSpec(getter_AddRefs(newMOVEMAILMailPath));
746 if (NS_FAILED(rv)) return rv;
748 rv = NS_NewFileSpec(getter_AddRefs(oldMOVEMAILMailPath));
749 if (NS_FAILED(rv)) return rv;
751 rv = GetDirFromPref(oldProfilePath,newProfilePath,NEW_MAIL_DIR_NAME, PREF_MAIL_DIRECTORY, newMOVEMAILMailPath, oldMOVEMAILMailPath);
752 if (NS_FAILED(rv)) {
753 rv = oldMOVEMAILMailPath->FromFileSpec(oldProfilePath);
754 if (NS_FAILED(rv)) return rv;
756 /* we didn't over localize this in 4.x, so this is all we have to do */
757 rv = oldMOVEMAILMailPath->AppendRelativeUnixPath(OLD_MAIL_DIR_NAME);
758 if (NS_FAILED(rv)) return rv;
760 rv = SetPremigratedFilePref(PREF_MAIL_DIRECTORY, oldMOVEMAILMailPath);
761 if (NS_FAILED(rv)) return rv;
763 rv = newMOVEMAILMailPath->FromFileSpec(newProfilePath);
764 if (NS_FAILED(rv)) return rv;
766 localMailDriveDefault = PR_TRUE;
768 oldMOVEMAILMailPath->GetFileSpec(&localMailSpec);
769 rv = GetSizes(localMailSpec, PR_TRUE, &totalLocalMailSize);
771 localMailDrive = localMailSpec.GetDiskSpaceAvailable();
774 #endif //HAVE_MOVEMAIL
776 ////////////////////////////////////////////////////////////////////////////
777 // Now get the NEWS disk space requirements for migration.
778 ////////////////////////////////////////////////////////////////////////////
779 rv = NS_NewFileSpec(getter_AddRefs(newNewsPath));
780 if (NS_FAILED(rv)) return rv;
782 rv = NS_NewFileSpec(getter_AddRefs(oldNewsPath));
783 if (NS_FAILED(rv)) return rv;
785 rv = GetDirFromPref(oldProfilePath,newProfilePath, NEW_NEWS_DIR_NAME, PREF_NEWS_DIRECTORY, newNewsPath,oldNewsPath);
786 if (NS_FAILED(rv)) {
787 rv = DetermineOldPath(oldProfilePath, OLD_NEWS_DIR_NAME, "newsDirName", oldNewsPath);
788 if (NS_FAILED(rv)) return rv;
790 rv = SetPremigratedFilePref(PREF_NEWS_DIRECTORY, oldNewsPath);
791 if (NS_FAILED(rv)) return rv;
793 rv = newNewsPath->FromFileSpec(newProfilePath);
794 if (NS_FAILED(rv)) return rv;
796 newsDriveDefault = PR_TRUE;
798 oldNewsPath->GetFileSpec(&newsSpec);
799 rv = GetSizes(newsSpec, PR_TRUE, &totalNewsSize);
800 newsDrive = newsSpec.GetDiskSpaceAvailable();
803 // Compute the space needed to migrate the profile
805 if(newsDriveDefault && localMailDriveDefault && summaryMailDriveDefault) // DEFAULT: All on the same drive
807 totalRequired = totalNewsSize + totalLocalMailSize + totalSummaryFileSize + totalProfileSize;
808 rv = ComputeSpaceRequirements(DriveID, SpaceRequired, profileDrive, totalRequired);
809 if (NS_FAILED(rv))
810 enoughSpace = PR_FALSE;
812 else
814 rv = ComputeSpaceRequirements(DriveID, SpaceRequired, profileDrive, totalProfileSize);
815 if (NS_FAILED(rv))
816 enoughSpace = PR_FALSE;
817 rv = ComputeSpaceRequirements(DriveID, SpaceRequired, localMailDrive, totalLocalMailSize);
818 if (NS_FAILED(rv))
819 enoughSpace = PR_FALSE;
820 rv = ComputeSpaceRequirements(DriveID, SpaceRequired, summaryMailDrive, totalSummaryFileSize);
821 if (NS_FAILED(rv))
822 enoughSpace = PR_FALSE;
823 rv = ComputeSpaceRequirements(DriveID, SpaceRequired, newsDrive, totalNewsSize);
824 if (NS_FAILED(rv))
825 enoughSpace = PR_FALSE;
828 if (!enoughSpace)
830 mErrorCode = MIGRATION_RETRY;
831 return NS_OK;
834 ////////////////////////////////////////////////////////////////////////////
835 // If we reached this point, there is enough room to do a migration.
836 // Start creating directories and setting new pref values.
837 ////////////////////////////////////////////////////////////////////////////
839 /* Create the new profile tree for 5.x */
840 rv = CreateNewUser5Tree(oldProfilePath, newProfilePath);
841 if (NS_FAILED(rv)) return rv;
844 if (serverType == POP_4X_MAIL_TYPE) {
846 rv = newPOPMailPath->Exists(&exists);
847 if (NS_FAILED(rv)) return rv;
848 if (!exists) {
849 rv = newPOPMailPath->CreateDir();
850 if (NS_FAILED(rv)) return rv;
853 rv = newPOPMailPath->AppendRelativeUnixPath(NEW_MAIL_DIR_NAME);
854 if (NS_FAILED(rv)) return rv;
856 rv = newPOPMailPath->Exists(&exists);
857 if (NS_FAILED(rv)) return rv;
858 if (!exists) {
859 rv = newPOPMailPath->CreateDir();
860 if (NS_FAILED(rv)) return rv;
864 // temporarily go through nsFileSpec
865 nsFileSpec newPOPMailPathSpec;
866 newPOPMailPath->GetFileSpec(&newPOPMailPathSpec);
868 nsCOMPtr<nsILocalFile> newPOPMailPathFile;
869 NS_FileSpecToIFile(&newPOPMailPathSpec,
870 getter_AddRefs(newPOPMailPathFile));
872 rv = m_prefBranch->SetComplexValue(PREF_MAIL_DIRECTORY,
873 NS_GET_IID(nsILocalFile),
874 newPOPMailPathFile);
875 if (NS_FAILED(rv)) return rv;
878 m_prefBranch->GetCharPref(PREF_NETWORK_HOSTS_POP_SERVER, &popServerName);
880 nsCAutoString popServerNamewithoutPort(popServerName);
881 PRInt32 colonPos = popServerNamewithoutPort.FindChar(':');
883 if (colonPos != -1 ) {
884 popServerNamewithoutPort.Truncate(colonPos);
885 rv = newPOPMailPath->AppendRelativeUnixPath(popServerNamewithoutPort.get());
887 else {
888 rv = newPOPMailPath->AppendRelativeUnixPath(popServerName);
891 if (NS_FAILED(rv)) return rv;
893 rv = newPOPMailPath->Exists(&exists);
894 if (NS_FAILED(rv)) return rv;
895 if (!exists) {
896 rv = newPOPMailPath->CreateDir();
897 if (NS_FAILED(rv)) return rv;
900 else if (serverType == IMAP_4X_MAIL_TYPE) {
901 if( copyMailFileInMigration ) // copy mail files in migration
903 rv = newIMAPLocalMailPath->Exists(&exists);
904 if (NS_FAILED(rv)) return rv;
905 if (!exists) {
906 rv = newIMAPLocalMailPath->CreateDir();
907 if (NS_FAILED(rv)) return rv;
910 rv = newIMAPLocalMailPath->AppendRelativeUnixPath(NEW_MAIL_DIR_NAME);
911 if (NS_FAILED(rv)) return rv;
913 /* Now create the new "Mail/Local Folders" directory */
914 rv = newIMAPLocalMailPath->Exists(&exists);
915 if (NS_FAILED(rv)) return rv;
916 if (!exists) {
917 newIMAPLocalMailPath->CreateDir();
921 // temporarily go through nsFileSpec
922 nsFileSpec newIMAPLocalMailPathSpec;
923 newIMAPLocalMailPath->GetFileSpec(&newIMAPLocalMailPathSpec);
925 nsCOMPtr<nsILocalFile> newIMAPLocalMailPathFile;
926 NS_FileSpecToIFile(&newIMAPLocalMailPathSpec,
927 getter_AddRefs(newIMAPLocalMailPathFile));
929 rv = m_prefBranch->SetComplexValue(PREF_MAIL_DIRECTORY,
930 NS_GET_IID(nsILocalFile),
931 newIMAPLocalMailPathFile);
932 if (NS_FAILED(rv)) return rv;
935 rv = newIMAPLocalMailPath->AppendRelativeUnixPath(NEW_LOCAL_MAIL_DIR_NAME);
936 if (NS_FAILED(rv)) return rv;
937 rv = newIMAPLocalMailPath->Exists(&exists);
938 if (NS_FAILED(rv)) return rv;
939 if (!exists) {
940 rv = newIMAPLocalMailPath->CreateDir();
941 if (NS_FAILED(rv)) return rv;
944 /* Now deal with the IMAP mail summary file location */
945 rv = newIMAPMailPath->Exists(&exists);
946 if (NS_FAILED(rv)) return rv;
947 if (!exists) {
948 rv = newIMAPMailPath->CreateDir();
949 if (NS_FAILED(rv)) return rv;
952 rv = newIMAPMailPath->AppendRelativeUnixPath(NEW_IMAPMAIL_DIR_NAME);
953 if (NS_FAILED(rv)) return rv;
955 rv = newIMAPMailPath->Exists(&exists);
956 if (NS_FAILED(rv)) return rv;
957 if (!exists) {
958 rv = newIMAPMailPath->CreateDir();
959 if (NS_FAILED(rv)) return rv;
963 // temporarily go through nsFileSpec
964 nsFileSpec newIMAPMailPathSpec;
965 newIMAPMailPath->GetFileSpec(&newIMAPMailPathSpec);
967 nsCOMPtr<nsILocalFile> newIMAPMailPathFile;
968 NS_FileSpecToIFile(&newIMAPMailPathSpec,
969 getter_AddRefs(newIMAPMailPathFile));
971 rv = m_prefBranch->SetComplexValue(PREF_MAIL_IMAP_ROOT_DIR,
972 NS_GET_IID(nsILocalFile),
973 newIMAPMailPathFile);
974 if (NS_FAILED(rv)) return rv;
977 else
980 // temporarily go through nsFileSpec
981 nsFileSpec oldIMAPLocalMailPathSpec;
982 oldIMAPLocalMailPath->GetFileSpec(&oldIMAPLocalMailPathSpec);
984 nsCOMPtr<nsILocalFile> oldIMAPLocalMailPathFile;
985 NS_FileSpecToIFile(&oldIMAPLocalMailPathSpec,
986 getter_AddRefs(oldIMAPLocalMailPathFile));
988 rv = m_prefBranch->SetComplexValue(PREF_MAIL_DIRECTORY,
989 NS_GET_IID(nsILocalFile),
990 oldIMAPLocalMailPathFile);
991 if (NS_FAILED(rv)) return rv;
994 // temporarily go through nsFileSpec
995 nsFileSpec oldIMAPMailPathSpec;
996 oldIMAPMailPath->GetFileSpec(&oldIMAPMailPathSpec);
998 nsCOMPtr<nsILocalFile> oldIMAPMailPathFile;
999 NS_FileSpecToIFile(&oldIMAPMailPathSpec,
1000 getter_AddRefs(oldIMAPMailPathFile));
1002 rv = m_prefBranch->SetComplexValue(PREF_MAIL_IMAP_ROOT_DIR,
1003 NS_GET_IID(nsILocalFile),
1004 oldIMAPMailPathFile);
1005 if (NS_FAILED(rv)) return rv;
1010 #ifdef HAVE_MOVEMAIL
1011 else if (serverType == MOVEMAIL_4X_MAIL_TYPE) {
1013 rv = newMOVEMAILMailPath->Exists(&exists);
1014 if (NS_FAILED(rv)) return rv;
1015 if (!exists) {
1016 rv = newMOVEMAILMailPath->CreateDir();
1017 if (NS_FAILED(rv)) return rv;
1020 rv = newMOVEMAILMailPath->AppendRelativeUnixPath(NEW_MAIL_DIR_NAME);
1021 if (NS_FAILED(rv)) return rv;
1023 rv = newMOVEMAILMailPath->Exists(&exists);
1024 if (NS_FAILED(rv)) return rv;
1025 if (!exists) {
1026 rv = newMOVEMAILMailPath->CreateDir();
1027 if (NS_FAILED(rv)) return rv;
1031 // temporarily go through nsFileSpec
1032 nsFileSpec newMOVEMAILPathSpec;
1033 newMOVEMAILMailPath->GetFileSpec(&newMOVEMAILPathSpec);
1035 nsCOMPtr<nsILocalFile> newMOVEMAILPathFile;
1036 NS_FileSpecToIFile(&newMOVEMAILPathSpec,
1037 getter_AddRefs(newMOVEMAILPathFile));
1039 rv = m_prefBranch->SetComplexValue(PREF_MAIL_DIRECTORY,
1040 NS_GET_IID(nsILocalFile),
1041 newMOVEMAILPathFile);
1042 if (NS_FAILED(rv)) return rv;
1045 rv = newMOVEMAILMailPath->AppendRelativeUnixPath(NEW_MOVEMAIL_DIR_NAME);
1046 if (NS_FAILED(rv)) return rv;
1048 rv = newMOVEMAILMailPath->Exists(&exists);
1049 if (NS_FAILED(rv)) return rv;
1050 if (!exists) {
1051 rv = newMOVEMAILMailPath->CreateDir();
1052 if (NS_FAILED(rv)) return rv;
1054 rv = NS_OK;
1056 #endif /* HAVE_MOVEMAIL */
1057 else {
1058 NS_ASSERTION(0,"failure, didn't recognize your mail server type.\n");
1059 return NS_ERROR_UNEXPECTED;
1062 ////////////////////////////////////////////////////////////////////////////
1063 // Set all the appropriate NEWS prefs.
1064 ////////////////////////////////////////////////////////////////////////////
1066 rv = newNewsPath->Exists(&exists);
1067 if (NS_FAILED(rv)) return rv;
1068 if (!exists) {
1069 rv = newNewsPath->CreateDir();
1070 if (NS_FAILED(rv)) return rv;
1073 rv = newNewsPath->AppendRelativeUnixPath(NEW_NEWS_DIR_NAME);
1074 if (NS_FAILED(rv)) return rv;
1076 rv = newNewsPath->Exists(&exists);
1077 if (NS_FAILED(rv)) return rv;
1078 if (!exists) {
1079 rv = newNewsPath->CreateDir();
1080 if (NS_FAILED(rv)) return rv;
1084 // temporarily go through nsFileSpec
1085 nsFileSpec newNewsPathSpec;
1086 newNewsPath->GetFileSpec(&newNewsPathSpec);
1088 nsCOMPtr<nsILocalFile> newNewsPathFile;
1089 NS_FileSpecToIFile(&newNewsPathSpec,
1090 getter_AddRefs(newNewsPathFile));
1092 rv = m_prefBranch->SetComplexValue(PREF_NEWS_DIRECTORY,
1093 NS_GET_IID(nsILocalFile),
1094 newNewsPathFile);
1095 if (NS_FAILED(rv)) return rv;
1098 PRBool needToRenameFilterFiles;
1099 if (PL_strcmp(IMAP_MAIL_FILTER_FILE_NAME_IN_4x,IMAP_MAIL_FILTER_FILE_NAME_IN_5x)) {
1100 #ifdef IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x
1101 // if we defined a format, the filter files don't live in the host directories
1102 // (mac does this.) we'll take care of those filter files later, in DoSpecialUpdates()
1103 needToRenameFilterFiles = PR_FALSE;
1104 #else
1105 needToRenameFilterFiles = PR_TRUE;
1106 #endif /* IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x */
1108 else {
1109 // if the name was the same in 4x as in 5x, no need to rename it
1110 needToRenameFilterFiles = PR_FALSE;
1113 // just copy what we need
1114 rv = DoTheCopy(oldProfilePath, newProfilePath, COOKIES_FILE_NAME_IN_4x);
1115 if (NS_FAILED(rv)) return rv;
1116 rv = DoTheCopy(oldProfilePath, newProfilePath, BOOKMARKS_FILE_NAME_IN_4x);
1117 if (NS_FAILED(rv)) return rv;
1118 #if defined(XP_MACOSX)
1119 rv = DoTheCopy(oldProfilePath, newProfilePath, SECURITY_PATH, PR_TRUE);
1120 if (NS_FAILED(rv)) return rv;
1121 #else
1122 rv = DoTheCopy(oldProfilePath, newProfilePath, PSM_CERT7_DB);
1123 if (NS_FAILED(rv)) return rv;
1124 rv = DoTheCopy(oldProfilePath, newProfilePath, PSM_KEY3_DB);
1125 if (NS_FAILED(rv)) return rv;
1126 rv = DoTheCopy(oldProfilePath, newProfilePath, PSM_SECMODULE_DB);
1127 if (NS_FAILED(rv)) return rv;
1128 #endif /* XP_MACOSX */
1130 #if defined(XP_MACOSX)
1131 // Copy the Mac filter rule files which sits at the top level dir of a 4.x profile.
1132 if(serverType == IMAP_4X_MAIL_TYPE) {
1133 rv = CopyFilesByPattern(oldProfilePath, newProfilePath, MAC_RULES_FILE_ENDING_STRING_IN_4X);
1134 NS_ENSURE_SUCCESS(rv,rv);
1136 #endif
1138 rv = DoTheCopy(oldNewsPath, newNewsPath, PR_TRUE);
1139 if (NS_FAILED(rv)) return rv;
1141 #ifdef NEED_TO_COPY_AND_RENAME_NEWSRC_FILES
1142 /* in 4.x, the newsrc files were in $HOME. Now that we can have multiple
1143 * profiles in 5.x, with the same user, this won't fly.
1144 * when they migrate, we need to copy from $HOME/.newsrc-<host> to
1145 * ~/.mozilla/<profile>/News/newsrc-<host>
1147 rv = CopyAndRenameNewsrcFiles(newNewsPath);
1148 if (NS_FAILED(rv)) return rv;
1149 #endif /* NEED_TO_COPY_AND_RENAME_NEWSRC_FILES */
1151 if (serverType == IMAP_4X_MAIL_TYPE) {
1152 if( copyMailFileInMigration ) // copy mail files in migration
1154 rv = DoTheCopyAndRename(oldIMAPMailPath, newIMAPMailPath, PR_TRUE, needToRenameFilterFiles, IMAP_MAIL_FILTER_FILE_NAME_IN_4x, IMAP_MAIL_FILTER_FILE_NAME_IN_5x);
1155 if (NS_FAILED(rv)) return rv;
1156 rv = DoTheCopyAndRename(oldIMAPLocalMailPath, newIMAPLocalMailPath, PR_TRUE, needToRenameFilterFiles,IMAP_MAIL_FILTER_FILE_NAME_IN_4x,IMAP_MAIL_FILTER_FILE_NAME_IN_5x);
1157 if (NS_FAILED(rv)) return rv;
1159 else // Copy & Rename filter files
1161 // IMAP path
1162 // don't care if this fails
1163 (void)DoTheCopyAndRename(oldIMAPMailPath, PR_TRUE, IMAP_MAIL_FILTER_FILE_NAME_IN_4x, IMAP_MAIL_FILTER_FILE_NAME_IN_5x);
1165 // Local Folders path
1166 // don't care if this fails
1167 (void)DoTheCopyAndRename(oldIMAPLocalMailPath, PR_TRUE, IMAP_MAIL_FILTER_FILE_NAME_IN_4x, IMAP_MAIL_FILTER_FILE_NAME_IN_5x);
1170 else if (serverType == POP_4X_MAIL_TYPE) {
1171 // fix for bug #202010
1172 // copy over the pop filter and popstate files now
1173 // and later, in DoSpecialUpdates()
1174 // we'll move and rename them
1175 #ifdef POP_MAIL_FILTER_FILE_NAME_IN_4x
1176 rv = DoTheCopy(oldProfilePath, newProfilePath, POP_MAIL_FILTER_FILE_NAME_IN_4x);
1177 if (NS_FAILED(rv)) return rv;
1178 #endif
1180 #ifdef POPSTATE_FILE_IN_4x
1181 rv = DoTheCopy(oldProfilePath, newProfilePath, POPSTATE_FILE_IN_4x);
1182 if (NS_FAILED(rv)) return rv;
1183 #endif
1185 rv = DoTheCopy(oldPOPMailPath, newPOPMailPath, PR_TRUE);
1186 if (NS_FAILED(rv)) return rv;
1188 #ifdef HAVE_MOVEMAIL
1189 else if (serverType == MOVEMAIL_4X_MAIL_TYPE) {
1190 // in 4.x, the movemail filter name was the same as the pop filter name
1191 // copy over the filter file now
1192 // and later, in DoSpecialUpdates()
1193 // we'll move and rename them
1194 rv = DoTheCopy(oldProfilePath, newProfilePath, POP_MAIL_FILTER_FILE_NAME_IN_4x);
1195 if (NS_FAILED(rv)) return rv;
1197 rv = DoTheCopy(oldMOVEMAILMailPath, newMOVEMAILMailPath, PR_TRUE);
1199 #endif /* HAVE_MOVEMAIL */
1200 else {
1201 NS_ASSERTION(0, "unknown mail server type!");
1202 return NS_ERROR_FAILURE;
1205 // Don't inherit the 4.x cache file location for mozilla!
1206 // The cache pref later gets set with a default in nsAppRunner::InitCachePrefs().
1207 m_prefBranch->ClearUserPref(PREF_BROWSER_CACHE_DIRECTORY);
1209 rv = DoSpecialUpdates(newProfilePath);
1210 if (NS_FAILED(rv)) return rv;
1211 PR_FREEIF(popServerName);
1213 nsXPIDLCString path;
1215 newProfilePath->GetNativePath(getter_Copies(path));
1216 NS_NewNativeLocalFile(path, PR_TRUE, getter_AddRefs(newPrefsFile));
1218 rv = newPrefsFile->AppendNative(NS_LITERAL_CSTRING(PREF_FILE_NAME_IN_5x));
1219 if (NS_FAILED(rv)) return rv;
1221 rv=psvc->SavePrefFile(newPrefsFile);
1222 if (NS_FAILED(rv)) return rv;
1223 rv=psvc->ResetPrefs();
1224 if (NS_FAILED(rv)) return rv;
1226 PRBool flagExists = PR_FALSE;
1227 m_prefsFile->Exists(&flagExists); //Delete the prefs.js file in the temp directory.
1228 if (flagExists)
1229 m_prefsFile->Remove(PR_FALSE);
1231 systemTempDir->Exists(&flagExists); //Delete the unique dir in the system temp dir.
1232 if (flagExists)
1233 systemTempDir->Remove(PR_FALSE);
1235 return rv;
1239 /*----------------------------------------------------------------------------
1240 * CreateNewUsers5Tree creates the directory called users5 (parent of the
1241 * of the profile directories) and the profile directory itself
1242 *---------------------------------------------------------------------------*/
1244 nsresult
1245 nsPrefMigration::CreateNewUser5Tree(nsIFileSpec * oldProfilePath, nsIFileSpec * newProfilePath)
1247 nsresult rv;
1248 PRBool exists;
1250 NS_ASSERTION(*PREF_FILE_NAME_IN_4x, "don't know how to migrate your platform");
1251 if (!*PREF_FILE_NAME_IN_4x) {
1252 return NS_ERROR_UNEXPECTED;
1255 /* Copy the old prefs file to the new profile directory for modification and reading.
1256 after copying it, rename it to pref.js, the 5.x pref file name on all platforms */
1257 nsCOMPtr<nsIFileSpec> oldPrefsFile;
1258 rv = NS_NewFileSpec(getter_AddRefs(oldPrefsFile));
1259 if (NS_FAILED(rv)) return rv;
1261 rv = oldPrefsFile->FromFileSpec(oldProfilePath);
1262 if (NS_FAILED(rv)) return rv;
1264 rv = oldPrefsFile->AppendRelativeUnixPath(PREF_FILE_NAME_IN_4x);
1265 if (NS_FAILED(rv)) return rv;
1268 /* the new prefs file */
1269 nsCOMPtr<nsIFileSpec> newPrefsFile;
1270 rv = NS_NewFileSpec(getter_AddRefs(newPrefsFile));
1271 if (NS_FAILED(rv)) return rv;
1273 rv = newPrefsFile->FromFileSpec(newProfilePath);
1274 if (NS_FAILED(rv)) return rv;
1276 rv = newPrefsFile->Exists(&exists);
1277 if (!exists)
1279 rv = newPrefsFile->CreateDir();
1282 rv = oldPrefsFile->CopyToDir(newPrefsFile);
1283 NS_ASSERTION(NS_SUCCEEDED(rv),"failed to copy prefs file");
1285 rv = newPrefsFile->AppendRelativeUnixPath(PREF_FILE_NAME_IN_4x);
1286 rv = newPrefsFile->Rename(PREF_FILE_NAME_IN_5x);
1288 rv = getPrefService();
1289 if (NS_FAILED(rv)) return rv;
1291 return NS_OK;
1294 /*---------------------------------------------------------------------------------
1295 * GetDirFromPref gets a directory based on a preference set in the 4.x
1296 * preferences file, adds a 5 and resets the preference.
1298 * INPUT:
1299 * oldProfilePath - the path to the old 4.x profile directory.
1300 * currently only used by UNIX
1302 * newProfilePath - the path to the 5.0 profile directory
1303 * currently only used by UNIX
1305 * newDirName - the leaf name of the directory in the 5.0 world that corresponds to
1306 * this pref. Examples: "Mail", "ImapMail", "News".
1307 * only used on UNIX.
1309 * pref - the pref in the "dot" format (e.g. mail.directory)
1311 * OUTPUT: newPath - The old path with a 5 added (on mac and windows)
1312 * the newProfilePath + "/" + newDirName (on UNIX)
1313 * oldPath - The old path from the pref (if any)
1316 * RETURNS: NS_OK if the pref was successfully pulled from the prefs file
1318 *--------------------------------------------------------------------------------*/
1319 nsresult
1320 nsPrefMigration::GetDirFromPref(nsIFileSpec * oldProfilePath, nsIFileSpec * newProfilePath, const char *newDirName, const char* pref, nsIFileSpec* newPath, nsIFileSpec* oldPath)
1322 nsresult rv;
1324 if (!oldProfilePath || !newProfilePath || !newDirName || !pref || !newPath || !oldPath) return NS_ERROR_NULL_POINTER;
1326 rv = getPrefService();
1327 if (NS_FAILED(rv)) return rv;
1329 nsCOMPtr <nsIFileSpec> oldPrefPath;
1330 nsXPIDLCString oldPrefPathStr;
1331 rv = m_prefBranch->GetCharPref(pref, getter_Copies(oldPrefPathStr));
1332 if (NS_FAILED(rv)) return rv;
1334 // the default on the mac was "". doing GetFileXPref on that would return
1335 // the current working directory, like viewer_debug. yikes!
1336 if (oldPrefPathStr.IsEmpty()) {
1337 rv = NS_ERROR_FAILURE;
1339 if (NS_FAILED(rv)) return rv;
1341 nsCOMPtr <nsILocalFile> oldPrefPathFile;
1342 rv = m_prefBranch->GetComplexValue(pref, NS_GET_IID(nsILocalFile),
1343 getter_AddRefs(oldPrefPathFile));
1344 if (NS_FAILED(rv)) return rv;
1346 // convert nsILocalFile to nsIFileSpec
1347 rv = oldPrefPathFile->GetNativePath(oldPrefPathStr);
1348 if (NS_FAILED(rv)) return rv;
1350 rv = NS_NewFileSpec(getter_AddRefs(oldPrefPath));
1351 if (NS_FAILED(rv)) return rv;
1353 rv = oldPrefPath->SetNativePath(oldPrefPathStr);
1354 if (NS_FAILED(rv)) return rv;
1356 // oldPath will also needs the conversion from nsILocalFile
1357 // this is nasty, eventually we'll switch entirely over to nsILocalFile
1358 rv = oldPath->SetNativePath(oldPrefPathStr);
1359 if (NS_FAILED(rv)) return rv;
1362 #ifdef XP_UNIX
1363 // what if they don't want to go to <profile>/<newDirName>?
1364 // what if unix users want "mail.directory" + "5" (like "~/ns_imap5")
1365 // or "mail.imap.root_dir" + "5" (like "~/nsmail5")?
1366 // should we let them? no. let's migrate them to
1367 // <profile>/Mail and <profile>/ImapMail
1368 // let's make all three platforms the same.
1369 if (PR_TRUE) {
1370 #else
1371 nsCOMPtr <nsIFileSpec> oldPrefPathParent;
1372 rv = oldPrefPath->GetParent(getter_AddRefs(oldPrefPathParent));
1373 if (NS_FAILED(rv)) return rv;
1375 // if the pref pointed to the default directory
1376 // treat it as if the pref wasn't set
1377 // this way it will get migrated as the user expects
1378 PRBool pathsMatch;
1379 rv = oldProfilePath->Equals(oldPrefPathParent, &pathsMatch);
1380 if (NS_SUCCEEDED(rv) && pathsMatch) {
1381 #endif /* XP_UNIX */
1382 rv = newPath->FromFileSpec(newProfilePath);
1383 if (NS_FAILED(rv)) return rv;
1385 else {
1386 nsXPIDLCString leafname;
1387 rv = newPath->FromFileSpec(oldPath);
1388 if (NS_FAILED(rv)) return rv;
1389 rv = newPath->GetLeafName(getter_Copies(leafname));
1390 if (NS_FAILED(rv)) return rv;
1391 nsCString newleafname((const char *)leafname);
1392 newleafname += NEW_DIR_SUFFIX;
1393 rv = newPath->SetLeafName(newleafname.get());
1394 if (NS_FAILED(rv)) return rv;
1397 rv = SetPremigratedFilePref(pref, oldPath);
1398 if (NS_FAILED(rv)) return rv;
1400 #ifdef XP_UNIX
1401 /* on UNIX, we kept the newsrc files in "news.directory", (which was usually ~)
1402 * and the summary files in ~/.netscape/xover-cache
1403 * oldPath should point to ~/.netscape/xover-cache, not "news.directory"
1404 * but we want to save the old "news.directory" in "premigration.news.directory"
1405 * later, again for UNIX only,
1406 * we will copy the .newsrc files (from "news.directory") into the new <profile>/News directory.
1407 * isn't this fun?
1409 if (PL_strcmp(PREF_NEWS_DIRECTORY, pref) == 0) {
1410 rv = oldPath->FromFileSpec(oldProfilePath);
1411 if (NS_FAILED(rv)) return rv;
1412 rv = oldPath->AppendRelativeUnixPath(OLD_NEWS_DIR_NAME);
1413 if (NS_FAILED(rv)) return rv;
1415 #endif /* XP_UNIX */
1416 return rv;
1419 static PRBool
1420 nsCStringEndsWith(nsCString& name, const char *ending)
1422 if (!ending) return PR_FALSE;
1424 PRInt32 len = name.Length();
1425 if (len == 0) return PR_FALSE;
1427 PRInt32 endingLen = PL_strlen(ending);
1428 if (len > endingLen && name.RFind(ending, PR_TRUE) == len - endingLen) {
1429 return PR_TRUE;
1431 else {
1432 return PR_FALSE;
1436 #ifdef NEED_TO_COPY_AND_RENAME_NEWSRC_FILES
1437 static PRBool
1438 nsCStringStartsWith(nsCString& name, const char *starting)
1440 if (!starting) return PR_FALSE;
1441 PRInt32 len = name.Length();
1442 if (len == 0) return PR_FALSE;
1444 PRInt32 startingLen = PL_strlen(starting);
1445 if (len > startingLen && name.RFind(starting, PR_TRUE) == 0) {
1446 return PR_TRUE;
1448 else {
1449 return PR_FALSE;
1452 #endif
1454 /*---------------------------------------------------------------------------------
1455 * GetSizes reads the 4.x files in the profile tree and accumulates their sizes
1457 * INPUT:
1459 * OUPUT:
1461 * RETURNS:
1463 *--------------------------------------------------------------------------------*/
1464 nsresult
1465 nsPrefMigration::GetSizes(nsFileSpec inputPath, PRBool readSubdirs, PRUint32 *sizeTotal)
1467 nsCAutoString fileOrDirNameStr;
1469 for (nsDirectoryIterator dir(inputPath, PR_FALSE); dir.Exists(); dir++)
1471 nsFileSpec fileOrDirName = dir.Spec();
1472 char* folderName = fileOrDirName.GetLeafName();
1473 fileOrDirNameStr.Assign(folderName);
1474 if (!nsCStringEndsWith(fileOrDirNameStr, MAIL_SUMMARY_SUFFIX_IN_4x) && !nsCStringEndsWith(fileOrDirNameStr, NEWS_SUMMARY_SUFFIX_IN_4x) && !nsCStringEndsWith(fileOrDirNameStr, SUMMARY_SUFFIX_IN_5x)) /* Don't copy the summary files */
1476 if (fileOrDirName.IsDirectory())
1478 if(readSubdirs)
1480 GetSizes(fileOrDirName, PR_TRUE, sizeTotal); /* re-enter the GetSizes function */
1483 else
1484 *sizeTotal += fileOrDirName.GetFileSize();
1486 nsCRT::free(folderName);
1489 return NS_OK;
1492 /*---------------------------------------------------------------------------*
1493 * ComputeSpaceRequirments
1495 *---------------------------------------------------------------------------*/
1496 nsresult
1497 nsPrefMigration::ComputeSpaceRequirements(PRInt64 DriveArray[MAX_DRIVES],
1498 PRUint32 SpaceReqArray[MAX_DRIVES],
1499 PRInt64 Drive,
1500 PRUint32 SpaceNeeded)
1502 int i=0;
1503 PRFloat64 temp;
1505 while(LL_NE(DriveArray[i],LL_Zero()) && LL_NE(DriveArray[i], Drive) && i < MAX_DRIVES)
1506 i++;
1508 if (LL_EQ(DriveArray[i], LL_Zero()))
1510 DriveArray[i] = Drive;
1511 SpaceReqArray[i] += SpaceNeeded;
1513 else if (LL_EQ(DriveArray[i], Drive))
1514 SpaceReqArray[i] += SpaceNeeded;
1515 else
1516 return NS_ERROR_FAILURE;
1518 LL_L2F(temp, DriveArray[i]);
1519 if (SpaceReqArray[i] > temp)
1520 return NS_ERROR_FAILURE;
1522 return NS_OK;
1525 #ifdef NEED_TO_COPY_AND_RENAME_NEWSRC_FILES
1526 nsresult
1527 nsPrefMigration::CopyAndRenameNewsrcFiles(nsIFileSpec * newPathSpec)
1529 nsresult rv;
1530 nsCOMPtr <nsIFileSpec>oldPathSpec;
1531 nsFileSpec oldPath;
1532 nsFileSpec newPath;
1533 nsCAutoString fileOrDirNameStr;
1535 rv = GetPremigratedFilePref(PREF_NEWS_DIRECTORY, getter_AddRefs(oldPathSpec));
1536 if (NS_FAILED(rv)) return rv;
1537 rv = oldPathSpec->GetFileSpec(&oldPath);
1538 if (NS_FAILED(rv)) return rv;
1539 rv = newPathSpec->GetFileSpec(&newPath);
1540 if (NS_FAILED(rv)) return rv;
1542 for (nsDirectoryIterator dir(oldPath, PR_FALSE); dir.Exists(); dir++)
1544 nsFileSpec fileOrDirName = dir.Spec(); //set first file or dir to a nsFileSpec
1545 //get the filename without the full path
1546 char* folderName = fileOrDirName.GetLeafName();
1547 fileOrDirNameStr.Assign(folderName);
1549 if (nsCStringStartsWith(fileOrDirNameStr, NEWSRC_PREFIX_IN_4x) || nsCStringStartsWith(fileOrDirNameStr, SNEWSRC_PREFIX_IN_4x)) {
1550 #ifdef DEBUG_seth
1551 printf("newsrc file == %s\n",folderName);
1552 #endif /* DEBUG_seth */
1554 rv = fileOrDirName.CopyToDir(newPath);
1555 NS_ASSERTION(NS_SUCCEEDED(rv),"failed to copy news file");
1557 nsFileSpec newFile = newPath;
1558 newFile += fileOrDirNameStr.get();
1559 newFile.Rename(folderName + 1); /* rename .newsrc-news to newsrc-news, no need to keep it hidden anymore */
1561 nsCRT::free(folderName);
1564 return NS_OK;
1566 #endif /* NEED_TO_COPY_AND_RENAME_NEWSRC_FILES */
1568 /*-------------------------------------------------------------------------
1569 * DoTheCopyAndRename copies the files listed in oldPath to newPath
1570 * and renames files, if necessary
1572 * INPUT: oldPath - The old profile path plus the specific data type
1573 * (e.g. mail or news)
1574 * newPath - The new profile path plus the specific data type
1576 * readSubdirs
1578 * needToRenameFiles - do we need to search for files named oldFile
1579 * and rename them to newFile
1581 * oldFile - old file name (used for renaming)
1583 * newFile - new file name (used for renaming)
1585 * RETURNS: NS_OK if successful
1586 * NS_ERROR_FAILURE if failed
1588 *--------------------------------------------------------------------------*/
1589 nsresult
1590 nsPrefMigration::DoTheCopyAndRename(nsIFileSpec * oldPathSpec, nsIFileSpec *newPathSpec, PRBool readSubdirs, PRBool needToRenameFiles, const char *oldName, const char *newName)
1592 nsresult rv;
1593 nsCAutoString fileOrDirNameStr;
1594 nsFileSpec oldPath;
1595 nsFileSpec newPath;
1597 rv = oldPathSpec->GetFileSpec(&oldPath);
1598 if (NS_FAILED(rv)) return rv;
1599 rv = newPathSpec->GetFileSpec(&newPath);
1600 if (NS_FAILED(rv)) return rv;
1602 for (nsDirectoryIterator dir(oldPath, PR_FALSE); dir.Exists(); dir++)
1604 nsFileSpec fileOrDirName = dir.Spec(); //set first file or dir to a nsFileSpec
1605 //get the filename without the full path
1606 char* folderName = fileOrDirName.GetLeafName();
1607 fileOrDirNameStr.Assign(folderName);
1609 if (!nsCStringEndsWith(fileOrDirNameStr, MAIL_SUMMARY_SUFFIX_IN_4x) && !nsCStringEndsWith(fileOrDirNameStr, NEWS_SUMMARY_SUFFIX_IN_4x) && !nsCStringEndsWith(fileOrDirNameStr, SUMMARY_SUFFIX_IN_5x)) /* Don't copy the summary files */
1611 if (fileOrDirName.IsDirectory())
1613 if(readSubdirs)
1615 nsCOMPtr<nsIFileSpec> newPathExtended;
1616 rv = NS_NewFileSpecWithSpec(newPath, getter_AddRefs(newPathExtended));
1617 rv = newPathExtended->AppendRelativeUnixPath(folderName);
1618 rv = newPathExtended->CreateDir();
1620 nsCOMPtr<nsIFileSpec>fileOrDirNameSpec;
1621 rv = NS_NewFileSpecWithSpec(fileOrDirName, getter_AddRefs(fileOrDirNameSpec));
1622 DoTheCopyAndRename(fileOrDirNameSpec, newPathExtended, PR_TRUE, needToRenameFiles, oldName, newName); /* re-enter the DoTheCopyAndRename function */
1625 else {
1626 // copy the file
1627 rv = fileOrDirName.CopyToDir(newPath);
1628 NS_ASSERTION(NS_SUCCEEDED(rv),"failed to copy file");
1630 if (needToRenameFiles) {
1631 // rename the file, if it matches
1632 if (fileOrDirNameStr.Equals(oldName)) {
1633 nsFileSpec newFile = newPath;
1634 newFile += fileOrDirNameStr.get();
1635 newFile.Rename(newName);
1640 nsCRT::free(folderName);
1643 return NS_OK;
1646 /*-------------------------------------------------------------------------
1647 * DoTheCopyAndRename copies and renames files
1649 * INPUT: aPath - the path
1651 * aReadSubdirs - if sub directories should be handled
1653 * aOldFile - old file name (used for renaming)
1655 * aNewFile - new file name (used for renaming)
1657 * RETURNS: NS_OK if successful
1658 * NS_ERROR_FAILURE if failed
1660 *--------------------------------------------------------------------------*/
1661 nsresult
1662 nsPrefMigration::DoTheCopyAndRename(nsIFileSpec * aPathSpec, PRBool aReadSubdirs, const char *aOldName, const char *aNewName)
1664 if( !aOldName || !aNewName || !strcmp(aOldName, aNewName) )
1665 return NS_ERROR_FAILURE;
1667 nsresult rv;
1668 nsFileSpec path, file;
1670 rv = aPathSpec->GetFileSpec(&path);
1671 if (NS_FAILED(rv))
1672 return rv;
1673 rv = aPathSpec->GetFileSpec(&file);
1674 if (NS_FAILED(rv))
1675 return rv;
1676 file += aOldName;
1678 // Handle sub folders
1679 for (nsDirectoryIterator dir(path, PR_FALSE); dir.Exists(); dir++)
1681 nsFileSpec fileOrDirName = dir.Spec(); //set first file or dir to a nsFileSpec
1682 if (fileOrDirName.IsDirectory())
1684 if( aReadSubdirs )
1686 nsCOMPtr<nsIFileSpec>fileOrDirNameSpec;
1687 rv = NS_NewFileSpecWithSpec(fileOrDirName, getter_AddRefs(fileOrDirNameSpec));
1688 DoTheCopyAndRename(fileOrDirNameSpec, aReadSubdirs, aOldName, aNewName); /* re-enter the DoTheCopyAndRename function */
1690 else
1691 continue;
1695 nsCOMPtr<nsILocalFile> localFileOld, localFileDirectory;
1696 rv = NS_FileSpecToIFile(&file, getter_AddRefs(localFileOld));
1697 if (NS_FAILED(rv))
1698 return rv;
1699 rv = NS_FileSpecToIFile(&path, getter_AddRefs(localFileDirectory));
1700 if (NS_FAILED(rv))
1701 return rv;
1702 NS_ConvertUTF8toUTF16 newName(aNewName);
1703 localFileOld->CopyTo(localFileDirectory, newName);
1705 return NS_OK;
1708 nsresult
1709 nsPrefMigration::CopyFilesByPattern(nsIFileSpec * oldPathSpec, nsIFileSpec * newPathSpec, const char *pattern)
1711 nsFileSpec oldPath;
1712 nsFileSpec newPath;
1714 nsresult rv = oldPathSpec->GetFileSpec(&oldPath);
1715 NS_ENSURE_SUCCESS(rv,rv);
1716 rv = newPathSpec->GetFileSpec(&newPath);
1717 NS_ENSURE_SUCCESS(rv,rv);
1719 for (nsDirectoryIterator dir(oldPath, PR_FALSE); dir.Exists(); dir++)
1721 nsFileSpec fileOrDirName = dir.Spec(); //set first file or dir to a nsFileSpec
1723 if (fileOrDirName.IsDirectory())
1724 continue;
1726 nsCAutoString fileOrDirNameStr(fileOrDirName.GetLeafName());
1727 if (!nsCStringEndsWith(fileOrDirNameStr, pattern))
1728 continue;
1730 // copy the file
1731 rv = fileOrDirName.CopyToDir(newPath);
1732 NS_ENSURE_SUCCESS(rv,rv);
1735 return NS_OK;
1738 nsresult
1739 nsPrefMigration::DoTheCopy(nsIFileSpec * oldPath, nsIFileSpec * newPath, PRBool readSubdirs)
1741 return DoTheCopyAndRename(oldPath, newPath, readSubdirs, PR_FALSE, "", "");
1744 nsresult
1745 nsPrefMigration::DoTheCopy(nsIFileSpec * oldPath, nsIFileSpec * newPath, const char *fileOrDirName, PRBool isDirectory)
1747 nsresult rv;
1749 if (isDirectory)
1751 nsCOMPtr<nsIFileSpec> oldSubPath;
1753 NS_NewFileSpec(getter_AddRefs(oldSubPath));
1754 oldSubPath->FromFileSpec(oldPath);
1755 rv = oldSubPath->AppendRelativeUnixPath(fileOrDirName);
1756 if (NS_FAILED(rv)) return rv;
1757 PRBool exist;
1758 rv = oldSubPath->Exists(&exist);
1759 if (NS_FAILED(rv)) return rv;
1760 if (!exist)
1762 rv = oldSubPath->CreateDir();
1763 if (NS_FAILED(rv)) return rv;
1766 nsCOMPtr<nsIFileSpec> newSubPath;
1768 NS_NewFileSpec(getter_AddRefs(newSubPath));
1769 newSubPath->FromFileSpec(newPath);
1770 rv = newSubPath->AppendRelativeUnixPath(fileOrDirName);
1771 if (NS_FAILED(rv)) return rv;
1772 rv = newSubPath->Exists(&exist);
1773 if (NS_FAILED(rv)) return rv;
1774 if (!exist)
1776 rv = newSubPath->CreateDir();
1777 if (NS_FAILED(rv)) return rv;
1780 DoTheCopy(oldSubPath, newSubPath, PR_TRUE);
1782 else
1784 nsCOMPtr<nsIFileSpec> file;
1785 NS_NewFileSpec(getter_AddRefs(file));
1786 file->FromFileSpec(oldPath);
1787 rv = file->AppendRelativeUnixPath(fileOrDirName);
1788 if( NS_FAILED(rv) ) return rv;
1789 PRBool exist;
1790 rv = file->Exists(&exist);
1791 if( NS_FAILED(rv) ) return rv;
1792 if( exist) {
1793 file->CopyToDir(newPath);
1797 return rv;
1800 #if defined(NEED_TO_FIX_4X_COOKIES)
1801 /* this code only works on the mac. in 4.x, the line endings where '\r' on the mac.
1802 this code will fix the expire times and the line endings, so the code is nsCookie.cpp
1803 can read the migrate cookies. */
1804 static PRInt32
1805 GetCookieLine(nsInputFileStream &strm, nsAutoString& aLine)
1807 /* read the line */
1808 aLine.Truncate();
1809 char c;
1810 for (;;) {
1811 c = strm.get();
1813 /* note that eof is not set until we read past the end of the file */
1814 if (strm.eof()) {
1815 return -1;
1818 /* stop at the '\r' */
1819 if (c != '\r') {
1820 aLine.Append(PRUnichar(c));
1822 else {
1823 break;
1826 return 0;
1829 static nsresult
1830 PutCookieLine(nsOutputFileStream &strm, const nsString& aLine)
1832 /* allocate a buffer from the heap */
1833 char * cp = ToNewCString(aLine);
1834 if (! cp) {
1835 return NS_ERROR_FAILURE;
1838 /* output each character */
1839 char* p = cp;
1840 while (*p) {
1841 strm.put(*(p++));
1843 NS_Free(cp);
1844 // the lines in a 5.x cookie file call end with '\n', on all platforms
1845 strm.put('\n');
1846 return NS_OK;
1849 static nsresult
1850 Fix4xCookies(nsIFileSpec * profilePath) {
1851 nsAutoString inBuffer, outBuffer;
1852 nsFileSpec profileDirectory;
1853 nsresult rv = profilePath->GetFileSpec(&profileDirectory);
1854 if (NS_FAILED(rv)) {
1855 return rv;
1858 /* open input file */
1859 nsFileSpec oldCookies(profileDirectory);
1860 oldCookies += COOKIES_FILE_NAME_IN_4x;
1862 /* it is possible that the 4.x cookies file does not exist. just return normally. see #55444 */
1863 if (!oldCookies.Exists()) return NS_OK;
1865 nsInputFileStream inStream(oldCookies);
1866 if (!inStream.is_open()) {
1867 return NS_ERROR_FAILURE;
1870 /* open output file */
1871 nsFileSpec newCookies(profileDirectory);
1872 newCookies += COOKIES_FILE_NAME_IN_5x;
1874 nsOutputFileStream outStream(newCookies);
1875 if (!outStream.is_open()) {
1876 return NS_ERROR_FAILURE;
1879 while (GetCookieLine(inStream,inBuffer) != -1){
1881 /* skip line if it is a comment or null line */
1882 if (inBuffer.IsEmpty() || inBuffer.CharAt(0) == '#' ||
1883 inBuffer.CharAt(0) == nsCRT::CR || inBuffer.CharAt(0) == nsCRT::LF) {
1884 PutCookieLine(outStream, inBuffer);
1885 continue;
1888 /* locate expire field, skip line if it does not contain all its fields */
1889 int hostIndex, isDomainIndex, pathIndex, xxxIndex, expiresIndex, nameIndex, cookieIndex;
1890 hostIndex = 0;
1891 if ((isDomainIndex=inBuffer.FindChar('\t', hostIndex)+1) == 0 ||
1892 (pathIndex=inBuffer.FindChar('\t', isDomainIndex)+1) == 0 ||
1893 (xxxIndex=inBuffer.FindChar('\t', pathIndex)+1) == 0 ||
1894 (expiresIndex=inBuffer.FindChar('\t', xxxIndex)+1) == 0 ||
1895 (nameIndex=inBuffer.FindChar('\t', expiresIndex)+1) == 0 ||
1896 (cookieIndex=inBuffer.FindChar('\t', nameIndex)+1) == 0 ) {
1897 continue;
1900 /* separate the expires field from the rest of the cookie line */
1901 nsAutoString prefix, expiresString, suffix;
1902 inBuffer.Mid(prefix, hostIndex, expiresIndex-hostIndex-1);
1903 inBuffer.Mid(expiresString, expiresIndex, nameIndex-expiresIndex-1);
1904 inBuffer.Mid(suffix, nameIndex, inBuffer.Length()-nameIndex);
1906 /* correct the expires field */
1907 char * expiresCString = ToNewCString(expiresString);
1908 unsigned long expires = strtoul(expiresCString, nsnull, 10);
1909 NS_Free(expiresCString);
1911 /* if the cookie is supposed to expire at the end of the session
1912 * expires == 0. don't adjust those cookies.
1914 if (expires) {
1915 expires -= SECONDS_BETWEEN_1900_AND_1970;
1917 char dateString[36];
1918 PR_snprintf(dateString, sizeof(dateString), "%lu", expires);
1920 /* generate the output buffer and write it to file */
1921 outBuffer = prefix;
1922 outBuffer.Append(PRUnichar('\t'));
1923 outBuffer.AppendWithConversion(dateString);
1924 outBuffer.Append(PRUnichar('\t'));
1925 outBuffer.Append(suffix);
1926 PutCookieLine(outStream, outBuffer);
1929 inStream.close();
1930 outStream.close();
1931 return NS_OK;
1934 #endif /* NEED_TO_FIX_4X_COOKIES */
1936 /*----------------------------------------------------------------------------
1937 * DoSpecialUpdates updates is a routine that does some miscellaneous updates
1938 * like renaming certain files, etc.
1939 *--------------------------------------------------------------------------*/
1940 nsresult
1941 nsPrefMigration::DoSpecialUpdates(nsIFileSpec * profilePath)
1943 nsresult rv;
1944 PRInt32 serverType;
1945 nsFileSpec fs;
1947 rv = profilePath->GetFileSpec(&fs);
1948 if (NS_FAILED(rv)) return rv;
1950 fs += PREF_FILE_NAME_IN_5x;
1952 nsOutputFileStream fsStream(fs, (PR_WRONLY | PR_CREATE_FILE | PR_APPEND));
1954 if (!fsStream.is_open())
1956 return NS_ERROR_FAILURE;
1959 /* Need to add a string to the top of the prefs.js file to prevent it
1960 * from being loaded as a standard javascript file which would be a
1961 * security hole.
1963 fsStream << PREF_FILE_HEADER_STRING << nsEndl ;
1964 fsStream.close();
1966 // rename the cookies file, but only if we need to.
1967 #if defined(NEED_TO_FIX_4X_COOKIES)
1968 rv = Fix4xCookies(profilePath);
1969 if (NS_FAILED(rv)) {
1970 return rv;
1972 #else
1973 rv = Rename4xFileAfterMigration(profilePath,COOKIES_FILE_NAME_IN_4x,COOKIES_FILE_NAME_IN_5x);
1974 if (NS_FAILED(rv)) return rv;
1975 #endif /* NEED_TO_FIX_4X_COOKIES */
1977 // rename the bookmarks file, but only if we need to.
1978 rv = Rename4xFileAfterMigration(profilePath,BOOKMARKS_FILE_NAME_IN_4x,BOOKMARKS_FILE_NAME_IN_5x);
1979 if (NS_FAILED(rv)) return rv;
1981 /* Create the new mail directory from the setting in prefs.js or a default */
1982 rv = m_prefBranch->GetIntPref(PREF_MAIL_SERVER_TYPE, &serverType);
1983 if (NS_FAILED(rv)) return rv;
1984 if (serverType == POP_4X_MAIL_TYPE) {
1985 rv = RenameAndMove4xPopFilterFile(profilePath);
1986 if (NS_FAILED(rv)) return rv;
1988 rv = RenameAndMove4xPopStateFile(profilePath);
1989 if (NS_FAILED(rv)) return rv;
1991 #ifdef IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x
1992 else if (serverType == IMAP_4X_MAIL_TYPE) {
1993 rv = RenameAndMove4xImapFilterFiles(profilePath);
1994 if (NS_FAILED(rv)) return rv;
1996 #endif /* IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x */
1998 return rv;
2001 nsresult
2002 nsPrefMigration::RenameAndMove4xPopFilterFile(nsIFileSpec * profilePath)
2004 return RenameAndMove4xPopFile(profilePath, POP_MAIL_FILTER_FILE_NAME_IN_4x, POP_MAIL_FILTER_FILE_NAME_IN_5x);
2007 nsresult
2008 nsPrefMigration::RenameAndMove4xPopStateFile(nsIFileSpec * profilePath)
2010 #ifdef POPSTATE_FILE_IN_4x
2011 return RenameAndMove4xPopFile(profilePath, POPSTATE_FILE_IN_4x, POPSTATE_FILE_IN_5x);
2012 #else
2013 // on windows, popstate.dat was in Users\<profile>\MAIL\popstate.dat
2014 // which is the right place, unlike linux and mac.
2015 // so, when we migrate Users\<profile>\Mail to Users50\<profile>\Mail\<hostname>
2016 // it just works
2017 return NS_OK;
2018 #endif /* POPSTATE_FILE_IN_4x */
2021 nsresult
2022 nsPrefMigration::RenameAndMove4xPopFile(nsIFileSpec * profilePath, const char *fileNameIn4x, const char *fileNameIn5x)
2024 nsFileSpec file;
2025 nsresult rv = profilePath->GetFileSpec(&file);
2026 if (NS_FAILED(rv)) return rv;
2028 // we assume the 4.x pop files live at <profile>/<fileNameIn4x>
2029 file += fileNameIn4x;
2031 // figure out where the 4.x pop mail directory got copied to
2032 char *popServerName = nsnull;
2033 nsFileSpec migratedPopDirectory;
2034 rv = profilePath->GetFileSpec(&migratedPopDirectory);
2035 migratedPopDirectory += NEW_MAIL_DIR_NAME;
2036 m_prefBranch->GetCharPref(PREF_NETWORK_HOSTS_POP_SERVER, &popServerName);
2037 migratedPopDirectory += popServerName;
2038 PR_FREEIF(popServerName);
2040 // copy the 4.x file from <profile>/<fileNameIn4x> to the <profile>/Mail/<hostname>/<fileNameIn4x>
2041 rv = file.CopyToDir(migratedPopDirectory);
2042 NS_ASSERTION(NS_SUCCEEDED(rv),"failed to copy pop file");
2044 // XXX todo, delete the old file
2045 // we are leaving it behind
2047 // make migratedPopDirectory point the the copied filter file,
2048 // <profile>/Mail/<hostname>/<fileNameIn4x>
2049 migratedPopDirectory += fileNameIn4x;
2051 // rename <profile>/Mail/<hostname>/<fileNameIn4x>to <profile>/Mail/<hostname>/<fileNameIn5x>, if necessary
2052 if (PL_strcmp(fileNameIn4x,fileNameIn5x)) {
2053 migratedPopDirectory.Rename(fileNameIn5x);
2056 return NS_OK;
2060 #ifdef IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x
2061 #define BUFFER_LEN 128
2062 nsresult
2063 nsPrefMigration::RenameAndMove4xImapFilterFile(nsIFileSpec * profilePath, const char *hostname)
2065 nsresult rv = NS_OK;
2066 char imapFilterFileName[BUFFER_LEN];
2068 // the 4.x imap filter file lives in "<profile>/<hostname> Rules"
2069 nsFileSpec file;
2070 rv = profilePath->GetFileSpec(&file);
2071 if (NS_FAILED(rv)) return rv;
2073 PR_snprintf(imapFilterFileName, BUFFER_LEN, IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x, hostname);
2074 file += imapFilterFileName;
2076 // if that file didn't exist, because they didn't use filters for that server, return now
2077 if (!file.Exists()) return NS_OK;
2079 // figure out where the 4.x pop mail directory got copied to
2080 nsFileSpec migratedImapDirectory;
2081 rv = profilePath->GetFileSpec(&migratedImapDirectory);
2082 migratedImapDirectory += NEW_IMAPMAIL_DIR_NAME;
2083 migratedImapDirectory += hostname;
2085 // copy the 4.x file from "<profile>/<hostname> Rules" to <profile>/ImapMail/<hostname>/
2086 rv = file.CopyToDir(migratedImapDirectory);
2087 NS_ASSERTION(NS_SUCCEEDED(rv),"failed to copy imap file");
2089 // make migratedPopDirectory point the the copied filter file,
2090 // "<profile>/ImapMail/<hostname>/<hostname> Rules"
2091 migratedImapDirectory += imapFilterFileName;
2093 // rename "<profile>/ImapMail/<hostname>/<hostname> Rules" to "<profile>/ImapMail/<hostname>/rules.dat"
2094 migratedImapDirectory.Rename(IMAP_MAIL_FILTER_FILE_NAME_IN_5x);
2096 return NS_OK;
2099 nsresult
2100 nsPrefMigration::RenameAndMove4xImapFilterFiles(nsIFileSpec * profilePath)
2102 nsresult rv;
2103 char *hostList=nsnull;
2105 rv = m_prefBranch->GetCharPref(PREF_4X_NETWORK_HOSTS_IMAP_SERVER, &hostList);
2106 if (NS_FAILED(rv)) return rv;
2108 if (!hostList || !*hostList) return NS_OK;
2110 char *token = nsnull;
2111 char *rest = hostList;
2112 nsCAutoString str;
2114 token = nsCRT::strtok(rest, ",", &rest);
2115 while (token && *token) {
2116 str = token;
2117 str.StripWhitespace();
2119 if (!str.IsEmpty()) {
2120 // str is the hostname
2121 rv = RenameAndMove4xImapFilterFile(profilePath,str.get());
2122 if (NS_FAILED(rv)) {
2123 // failed to migrate. bail.
2124 return rv;
2126 str = "";
2128 token = nsCRT::strtok(rest, ",", &rest);
2130 PR_FREEIF(hostList);
2131 return NS_OK;
2133 #endif /* IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x */
2135 nsresult
2136 nsPrefMigration::Rename4xFileAfterMigration(nsIFileSpec * profilePath, const char *oldFileName, const char *newFileName)
2138 nsresult rv = NS_OK;
2139 // if they are the same, don't bother to rename the file.
2140 if (PL_strcmp(oldFileName, newFileName) == 0) {
2141 return rv;
2144 nsFileSpec file;
2145 rv = profilePath->GetFileSpec(&file);
2146 if (NS_FAILED(rv)) return rv;
2148 file += oldFileName;
2150 // make sure it exists before you try to rename it
2151 if (file.Exists()) {
2152 file.Rename(newFileName);
2154 return rv;
2157 #ifdef NEED_TO_COPY_AND_RENAME_NEWSRC_FILES
2158 nsresult
2159 nsPrefMigration::GetPremigratedFilePref(const char *pref_name, nsIFileSpec **path)
2161 nsresult rv;
2163 if (!pref_name) return NS_ERROR_FAILURE;
2165 char premigration_pref[MAX_PREF_LEN];
2166 PR_snprintf(premigration_pref,MAX_PREF_LEN,"%s%s",PREMIGRATION_PREFIX,pref_name);
2167 #ifdef DEBUG_seth
2168 printf("getting %s (into a nsFileSpec)\n", premigration_pref);
2169 #endif
2170 rv = m_prefBranch->GetComplexValue((const char *)premigration_pref,
2171 NS_GET_IID(nsIFileSpec),
2172 (void **)path);
2173 return rv;
2176 #endif /* NEED_TO_COPY_AND_RENAME_NEWSRC_FILES */
2178 nsresult
2179 nsPrefMigration::SetPremigratedFilePref(const char *pref_name, nsIFileSpec *path)
2181 nsresult rv;
2183 if (!pref_name) return NS_ERROR_FAILURE;
2185 // save off the old pref, prefixed with "premigration"
2186 // for example, we need the old "mail.directory" pref when
2187 // migrating the copies and folder prefs in nsMsgAccountManager.cpp
2189 // note we do this for all platforms.
2190 char premigration_pref[MAX_PREF_LEN];
2191 PR_snprintf(premigration_pref,MAX_PREF_LEN,"%s%s",PREMIGRATION_PREFIX,pref_name);
2192 #ifdef DEBUG_seth
2193 printf("setting %s (from a nsFileSpec) for later...\n", premigration_pref);
2194 #endif
2196 // need to convert nsIFileSpec->nsILocalFile
2197 nsFileSpec pathSpec;
2198 path->GetFileSpec(&pathSpec);
2200 nsCOMPtr<nsILocalFile> pathFile;
2201 rv = NS_FileSpecToIFile(&pathSpec, getter_AddRefs(pathFile));
2202 if (NS_FAILED(rv)) return rv;
2204 PRBool exists = PR_FALSE;
2205 pathFile->Exists(&exists);
2207 NS_ASSERTION(exists, "the path does not exist. see bug #55444");
2208 if (!exists) return NS_OK;
2210 rv = m_prefBranch->SetComplexValue((const char *)premigration_pref,
2211 NS_GET_IID(nsILocalFile), pathFile);
2212 return rv;
2215 nsresult
2216 nsPrefMigration::DetermineOldPath(nsIFileSpec *profilePath, const char *oldPathName, const char *oldPathEntityName, nsIFileSpec *oldPath)
2218 nsresult rv;
2220 /* set oldLocalFile to profilePath. need to convert nsIFileSpec->nsILocalFile */
2221 nsCOMPtr<nsILocalFile> oldLocalFile;
2222 nsFileSpec pathSpec;
2223 profilePath->GetFileSpec(&pathSpec);
2224 rv = NS_FileSpecToIFile(&pathSpec, getter_AddRefs(oldLocalFile));
2225 if (NS_FAILED(rv)) return rv;
2227 /* get the string bundle, and get the appropriate localized string out of it */
2228 nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
2229 if (NS_FAILED(rv)) return rv;
2231 nsCOMPtr<nsIStringBundle> bundle;
2232 rv = bundleService->CreateBundle(MIGRATION_PROPERTIES_URL, getter_AddRefs(bundle));
2233 if (NS_FAILED(rv)) return rv;
2235 nsXPIDLString localizedDirName;
2236 nsAutoString entityName;
2237 entityName.AssignWithConversion(oldPathEntityName);
2238 rv = bundle->GetStringFromName(entityName.get(), getter_Copies(localizedDirName));
2239 if (NS_FAILED(rv)) return rv;
2241 rv = oldLocalFile->AppendRelativePath(localizedDirName);
2242 if (NS_FAILED(rv)) return rv;
2244 PRBool exists = PR_FALSE;
2245 rv = oldLocalFile->Exists(&exists);
2246 if (!exists) {
2247 /* if the localized name doesn't exist, use the english name */
2248 rv = oldPath->FromFileSpec(profilePath);
2249 if (NS_FAILED(rv)) return rv;
2251 rv = oldPath->AppendRelativeUnixPath(oldPathName);
2252 if (NS_FAILED(rv)) return rv;
2254 return NS_OK;
2257 /* at this point, the folder with the localized name exists, so use it */
2258 nsCAutoString persistentDescriptor;
2259 rv = oldLocalFile->GetPersistentDescriptor(persistentDescriptor);
2260 if (NS_FAILED(rv)) return rv;
2261 rv = oldPath->SetPersistentDescriptorString(persistentDescriptor.get());
2262 if (NS_FAILED(rv)) return rv;
2264 return NS_OK;
2267 ////////////////////////////////////////////////////////////////////////
2268 // nsPrefConverter
2269 ////////////////////////////////////////////////////////////////////////
2272 these are the prefs we know we need to convert to utf8.
2273 we'll also be converting:
2275 Please make sure that any pref that contains native characters
2276 in its value is not included in this list as we do not want to
2277 convert them into UTF-8 format. Prefs are being get and set in a
2278 unicode format (FileXPref) now and there is no need for
2279 conversion of those prefs.
2281 "ldap_2.server.*.description"
2282 "intl.font*.fixed_font"
2283 "intl.font*.prop_font"
2284 "mail.identity.vcard.*"
2287 static const char *prefsToConvert[] = {
2288 "custtoolbar.personal_toolbar_folder",
2289 "editor.author",
2290 "li.server.ldap.userbase",
2291 "mail.identity.organization",
2292 "mail.identity.username",
2293 nsnull
2296 nsPrefConverter::~nsPrefConverter()
2301 nsPrefConverter::nsPrefConverter()
2305 NS_IMPL_ISUPPORTS1(nsPrefConverter, nsIPrefConverter)
2307 // Apply a charset conversion from the given charset to UTF-8 for the input C string.
2308 static
2309 nsresult
2310 ConvertStringToUTF8(const char* aCharset, const char* inString, char** outString)
2312 if (nsnull == outString)
2313 return NS_ERROR_NULL_POINTER;
2315 nsresult rv;
2316 // convert result to unicode
2317 nsCOMPtr<nsICharsetConverterManager> ccm =
2318 do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
2320 if(NS_SUCCEEDED(rv)) {
2321 nsCOMPtr <nsIUnicodeDecoder> decoder; // this may be cached
2323 rv = ccm->GetUnicodeDecoderRaw(aCharset, getter_AddRefs(decoder));
2324 if(NS_SUCCEEDED(rv) && decoder) {
2325 PRInt32 uniLength = 0;
2326 PRInt32 srcLength = strlen(inString);
2327 rv = decoder->GetMaxLength(inString, srcLength, &uniLength);
2328 if (NS_SUCCEEDED(rv)) {
2329 PRUnichar *unichars = new PRUnichar [uniLength];
2331 if (nsnull != unichars) {
2332 // convert to unicode
2333 rv = decoder->Convert(inString, &srcLength, unichars, &uniLength);
2334 if (NS_SUCCEEDED(rv)) {
2335 nsAutoString aString;
2336 aString.Assign(unichars, uniLength);
2337 // convert to UTF-8
2338 *outString = ToNewUTF8String(aString);
2340 delete [] unichars;
2342 else {
2343 rv = NS_ERROR_OUT_OF_MEMORY;
2349 return rv;
2352 nsresult
2353 ConvertPrefToUTF8(const char *prefname, nsIPrefBranch *prefs, const char* charSet)
2355 nsresult rv;
2357 if (!prefname || !prefs) return NS_ERROR_FAILURE;
2358 #ifdef DEBUG_UTF8_CONVERSION
2359 printf("converting %s to UTF8\n", prefname);
2360 #endif /* DEBUG_UTF8_CONVERSION */
2362 nsXPIDLCString prefval;
2364 rv = prefs->GetCharPref(prefname, getter_Copies(prefval));
2365 if (NS_FAILED(rv)) return rv;
2367 if (prefval.IsEmpty()) {
2368 // no need to convert ""
2369 return NS_OK;
2372 nsXPIDLCString outval;
2373 rv = ConvertStringToUTF8(charSet, (const char *)prefval, getter_Copies(outval));
2374 // only set the pref if the conversion worked, and it convert to something non null
2375 if (NS_SUCCEEDED(rv) && (const char *)outval && PL_strlen((const char *)outval)) {
2376 #ifdef DEBUG_UTF8_CONVERSION
2377 printf("converting %s to %s\n",(const char *)prefval, (const char *)outval);
2378 #endif /* DEBUG_UTF8_CONVERSION */
2379 rv = prefs->SetCharPref(prefname, (const char *)outval);
2382 return NS_OK;
2386 static PRBool charEndsWith(const char *str, const char *endStr)
2388 PRUint32 endStrLen = PL_strlen(endStr);
2389 PRUint32 strLen = PL_strlen(str);
2391 if (strLen < endStrLen) return PR_FALSE;
2393 PRUint32 pos = strLen - endStrLen;
2394 if (PL_strncmp(str + pos, endStr, endStrLen) == 0) {
2395 return PR_TRUE;
2397 else {
2398 return PR_FALSE;
2402 static
2403 void fontPrefEnumerationFunction(const char *name, nsCStringArray *arr)
2405 #ifdef DEBUG_UTF8_CONVERSION
2406 printf("fontPrefEnumerationFunction: %s\n", name);
2407 #endif
2409 if (charEndsWith(name,".fixed_font") || charEndsWith(name,".prop_font")) {
2410 nsCString str(name);
2411 arr->AppendCString(str);
2415 static
2416 void ldapPrefEnumerationFunction(const char *name, nsCStringArray *arr)
2418 #ifdef DEBUG_UTF8_CONVERSION
2419 printf("ldapPrefEnumerationFunction: %s\n", name);
2420 #endif
2422 // we only want to convert "ldap_2.servers.*.description"
2423 if (charEndsWith(name,".description")) {
2424 nsCString str(name);
2425 arr->AppendCString(str);
2429 static
2430 void vCardPrefEnumerationFunction(const char *name, nsCStringArray *arr)
2432 #ifdef DEBUG_UTF8_CONVERSION
2433 printf("vCardPrefEnumerationFunction: %s\n", name);
2434 #endif
2436 // the 4.x vCard prefs might need converting
2437 nsCString str(name);
2438 arr->AppendCString(str);
2442 typedef struct {
2443 nsIPrefBranch *prefs;
2444 const char* charSet;
2445 } PrefEnumerationClosure;
2447 PRBool
2448 convertPref(nsCString &aElement, void *aData)
2450 PrefEnumerationClosure *closure;
2451 closure = (PrefEnumerationClosure *)aData;
2453 ConvertPrefToUTF8(aElement.get(), closure->prefs, closure->charSet);
2454 return PR_TRUE;
2457 NS_IMETHODIMP
2458 nsPrefConverter::ConvertPrefsToUTF8()
2460 nsresult rv;
2462 nsCStringArray prefsToMigrate;
2464 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
2465 if(NS_FAILED(rv)) return rv;
2466 if (!prefs) return NS_ERROR_FAILURE;
2468 nsCAutoString charSet;
2469 rv = GetPlatformCharset(charSet);
2471 if (NS_FAILED(rv)) return rv;
2473 PRUint32 i;
2475 for (i = 0; prefsToConvert[i]; i++) {
2476 nsCString prefnameStr( prefsToConvert[i] );
2477 prefsToMigrate.AppendCString(prefnameStr);
2480 PRUint32 count;
2481 char **childArray;
2483 if (NS_SUCCEEDED(prefs->GetChildList("intl.font.", &count, &childArray))) {
2484 for (i = 0; i < count; i++)
2485 fontPrefEnumerationFunction(childArray[i], &prefsToMigrate);
2487 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, childArray);
2490 if (NS_SUCCEEDED(prefs->GetChildList("ldap_2.servers.", &count, &childArray))) {
2491 for (i = 0; i < count; i++)
2492 ldapPrefEnumerationFunction(childArray[i], &prefsToMigrate);
2494 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, childArray);
2497 if (NS_SUCCEEDED(prefs->GetChildList("mail.identity.vcard.", &count, &childArray))) {
2498 for (i = 0; i < count; i++)
2499 vCardPrefEnumerationFunction(childArray[i], &prefsToMigrate);
2501 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, childArray);
2504 PrefEnumerationClosure closure;
2506 closure.prefs = prefs;
2507 closure.charSet = charSet.get();
2509 prefsToMigrate.EnumerateForwards((nsCStringArrayEnumFunc)convertPref, (void *)(&closure));
2511 rv = prefs->SetBoolPref("prefs.converted-to-utf8", PR_TRUE);
2512 return NS_OK;
2515 // A wrapper function to call the interface to get a platform file charset.
2516 nsresult
2517 nsPrefConverter::GetPlatformCharset(nsCString& aCharset)
2519 nsresult rv;
2521 // we may cache it since the platform charset will not change through application life
2522 nsCOMPtr <nsIPlatformCharset> platformCharset = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
2523 if (NS_SUCCEEDED(rv) && platformCharset) {
2524 rv = platformCharset->GetCharset(kPlatformCharsetSel_4xPrefsJS, aCharset);
2526 if (NS_FAILED(rv)) {
2527 aCharset.AssignLiteral("ISO-8859-1"); // use ISO-8859-1 in case of any error
2530 return rv;