Mozilla/mozilla/mail/components/migration/src/nsDogbertProfileMigrator.cpp
scott%scott-macgregor.org 3d0b9dfee9 fix build bustage. missing ;
git-svn-id: svn://10.0.0.236/trunk@227822 18797224-902f-48f8-a5cc-f745e15eee43
2007-06-11 16:05:02 +00:00

2219 lines
73 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is The Mail Profile Migrator.
*
* The Initial Developer of the Original Code is Scott MacGregor
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Scott MacGregor <mscott@mozilla.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
// this file is mostly a copy of nsPrefMigration.cpp.
#include "nsMailProfileMigratorUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsIObserverService.h"
#include "nsIPasswordManagerInternal.h"
#include "nsIPrefLocalizedString.h"
#include "nsIPrefService.h"
#include "nsIServiceManager.h"
#include "nsISupportsArray.h"
#include "nsISupportsPrimitives.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsDogbertProfileMigrator.h"
#include "nsIRelativeFilePref.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsVoidArray.h"
#include "prprf.h"
#include "prmem.h"
#include "prio.h"
#include "prenv.h"
#include "NSReg.h"
#include "msgCore.h"
// lots of includes required for the nsPrefMigration.cpp code that we copied:
#include "nsICharsetConverterManager.h"
#include "nsIPlatformCharset.h"
#define MIGRATION_PROPERTIES_URL "chrome://messenger/locale/migration/migration.properties"
#ifndef MAXPATHLEN
#ifdef _MAX_PATH
#define MAXPATHLEN _MAX_PATH
#elif defined(CCHMAXPATH)
#define MAXPATHLEN CCHMAXPATH
#else
#define MAXPATHLEN 1024
#endif
#endif
#if defined(XP_UNIX) && !defined(XP_MACOSX)
#define PREF_FILE_NAME_IN_4x "preferences.js"
#define IMAP_MAIL_FILTER_FILE_NAME_IN_4x "mailrule"
#define POP_MAIL_FILTER_FILE_NAME_IN_4x "mailrule"
#define MAIL_SUMMARY_SUFFIX_IN_4x ".summary"
#define NEWS_SUMMARY_SUFFIX_IN_4x ".snm"
#define NEWSRC_PREFIX_IN_4x ".newsrc-"
#define SNEWSRC_PREFIX_IN_4x ".snewsrc-"
#define POPSTATE_FILE_IN_4x "popstate"
#define PSM_CERT7_DB "cert7.db"
#define PSM_KEY3_DB "key3.db"
#define PSM_SECMODULE_DB "secmodule.db"
#define HOME_ENVIRONMENT_VARIABLE "HOME"
#define PROFILE_HOME_ENVIRONMENT_VARIABLE "PROFILE_HOME"
#define DEFAULT_UNIX_PROFILE_NAME "default"
#elif defined(XP_MACOSX)
#define OLDREG_NAME "Netscape Registry"
#define OLDREG_DIR NS_MAC_PREFS_DIR
#define PREF_FILE_NAME_IN_4x "Netscape Preferences"
#define MAC_RULES_FILE_ENDING_STRING_IN_4X " Rules"
#define IMAP_MAIL_FILTER_FILE_NAME_IN_4x "<hostname> Rules"
#define POP_MAIL_FILTER_FILE_NAME_IN_4x "Filter Rules"
#define MAIL_SUMMARY_SUFFIX_IN_4x ".snm"
#define NEWS_SUMMARY_SUFFIX_IN_4x ".snm"
#define POPSTATE_FILE_IN_4x "Pop State"
#define SECURITY_PATH "Security"
#define PSM_CERT7_DB "Certificates7"
#define PSM_KEY3_DB "Key Database3"
#define PSM_SECMODULE_DB "Security Modules"
#else /* XP_WIN || XP_OS2 */
#define PREF_FILE_NAME_IN_4x "prefs.js"
#define IMAP_MAIL_FILTER_FILE_NAME_IN_4x "rules.dat"
#define POP_MAIL_FILTER_FILE_NAME_IN_4x "rules.dat"
#define MAIL_SUMMARY_SUFFIX_IN_4x ".snm"
#define NEWS_SUMMARY_SUFFIX_IN_4x ".snm"
#define OLDREG_NAME "nsreg.dat"
#ifdef XP_WIN
#define OLDREG_DIR NS_WIN_WINDOWS_DIR
#else
#define OLDREG_DIR NS_OS2_DIR
#endif
// purposely not defined, since it was in the right place
// and with the right name in 4.x
//#define POPSTATE_FILE_IN_4x "popstate.dat"
#define PSM_CERT7_DB "cert7.db"
#define PSM_KEY3_DB "key3.db"
#define PSM_SECMODULE_DB "secmod.db"
#endif /* XP_UNIX */
#define SUMMARY_SUFFIX_IN_5x ".msf"
#define IMAP_MAIL_FILTER_FILE_NAME_IN_5x "rules.dat"
#define POP_MAIL_FILTER_FILE_NAME_IN_5x "rules.dat"
#define POPSTATE_FILE_IN_5x "popstate.dat"
// only UNIX had movemail in 4.x
#if defined(XP_UNIX) && !defined(XP_MACOSX)
#define HAVE_MOVEMAIL 1
#endif /* XP_UNIX */
#define PREMIGRATION_PREFIX "premigration."
#define PREF_FILE_HEADER_STRING "# Mozilla User Preferences "
#define MAX_PREF_LEN 1024
// this is for the hidden preference setting in mozilla/modules/libpref/src/init/mailnews.js
// pref("mail.migration.copyMailFiles", true);
//
// see bugzilla bug 80035 (http://bugzilla.mozilla.org/show_bug.cgi?id=80035)
//
// the default value for this setting is true which means when migrating from
// Netscape 4.x, mozilla will copy all the contents of Local Folders and Imap
// Folder to the newly created subfolders of migrated mozilla profile
// when this value is set to false, mozilla will not copy these contents and
// still share them with Netscape 4.x
//
// Advantages of forbidding copy operation:
// reduce the disk usage
// quick migration
// Disadvantage of forbidding copy operation:
// without perfect lock mechamism, there is possibility of data corruption
// when Netscape 4.x and mozilla run at the same time and access the same
// mail file at the same time
#define PREF_MIGRATION_MODE_FOR_MAIL "mail.migration.copyMailFiles"
#define PREF_MAIL_DIRECTORY "mail.directory"
#define PREF_NEWS_DIRECTORY "news.directory"
#define PREF_MAIL_IMAP_ROOT_DIR "mail.imap.root_dir"
#define PREF_NETWORK_HOSTS_POP_SERVER "network.hosts.pop_server"
#define PREF_4X_NETWORK_HOSTS_IMAP_SERVER "network.hosts.imap_servers"
#define PREF_MAIL_SERVER_TYPE "mail.server_type"
#define PREF_BROWSER_CACHE_DIRECTORY "browser.cache.directory"
#define POP_4X_MAIL_TYPE 0
#define IMAP_4X_MAIL_TYPE 1
#ifdef HAVE_MOVEMAIL
#define MOVEMAIL_4X_MAIL_TYPE 2
#define NEW_MOVEMAIL_DIR_NAME "movemail"
#endif /* HAVE_MOVEMAIL */
#if defined(XP_UNIX) && !defined(XP_MACOSX)
/* a 4.x profile on UNIX is rooted at something like
* "/u/sspitzer/.netscape"
* profile + OLD_MAIL_DIR_NAME = "/u/sspitzer/.netscape/../nsmail" = "/u/sspitzer/nsmail"
* profile + OLD_NEWS_DIR_NAME = "/u/sspitzer/.netscape/xover-cache"
* profile + OLD_IMAPMAIL_DIR_NAME = "/u/sspitzer/.netscape/../ns_imap" = "/u/sspitzer/ns_imap"
* which is as good as we're going to get for defaults on UNIX.
*/
#define OLD_MAIL_DIR_NAME "/../nsmail"
#define OLD_NEWS_DIR_NAME "/xover-cache"
#define OLD_IMAPMAIL_DIR_NAME "/../ns_imap"
#else
#define OLD_MAIL_DIR_NAME "Mail"
#define OLD_NEWS_DIR_NAME "News"
#define OLD_IMAPMAIL_DIR_NAME "ImapMail"
#endif /* XP_UNIX */
#define NEW_MAIL_DIR_NAME "Mail"
#define NEW_NEWS_DIR_NAME "News"
#define NEW_IMAPMAIL_DIR_NAME "ImapMail"
#define NEW_LOCAL_MAIL_DIR_NAME "Local Folders"
#define NEW_DIR_SUFFIX "5"
#define PREF_FILE_NAME_IN_5x "prefs.js"
static PRBool nsCStringEndsWith(nsCString& name, const char *ending);
#ifdef NEED_TO_COPY_AND_RENAME_NEWSRC_FILES
static PRBool nsCStringStartsWith(nsCString& name, const char *starting);
#endif
///////////////////////////////////////////////////////////////////////////////
// nsDogbertProfileMigrator
struct PrefBranchStruct {
char* prefName;
PRInt32 type;
union {
char* stringValue;
PRInt32 intValue;
PRBool boolValue;
PRUnichar* wstringValue;
};
};
NS_IMPL_ISUPPORTS2(nsDogbertProfileMigrator, nsIMailProfileMigrator, nsITimerCallback)
nsDogbertProfileMigrator::nsDogbertProfileMigrator()
{
mObserverService = do_GetService("@mozilla.org/observer-service;1");
mMaxProgress = LL_ZERO;
mCurrentProgress = LL_ZERO;
}
nsDogbertProfileMigrator::~nsDogbertProfileMigrator()
{
}
///////////////////////////////////////////////////////////////////////////////
// nsITimerCallback
NS_IMETHODIMP
nsDogbertProfileMigrator::Notify(nsITimer *timer)
{
CopyNextFolder();
return NS_OK;
}
void nsDogbertProfileMigrator::CopyNextFolder()
{
if (mFileCopyTransactionIndex < mFileCopyTransactions->Count())
{
PRUint32 percentage = 0;
fileTransactionEntry* fileTransaction = (fileTransactionEntry*) mFileCopyTransactions->SafeElementAt(mFileCopyTransactionIndex++);
if (fileTransaction) // copy the file
{
fileTransaction->srcFile->CopyTo(fileTransaction->destFile, fileTransaction->newName);
// add to our current progress
PRInt64 fileSize;
fileTransaction->srcFile->GetFileSize(&fileSize);
LL_ADD(mCurrentProgress, mCurrentProgress, fileSize);
PRInt64 percentDone;
LL_MUL(percentDone, mCurrentProgress, 100);
LL_DIV(percentDone, percentDone, mMaxProgress);
LL_L2UI(percentage, percentDone);
nsAutoString index;
index.AppendInt( percentage );
NOTIFY_OBSERVERS(MIGRATION_PROGRESS, index.get());
}
// fire a timer to handle the next one.
mFileIOTimer = do_CreateInstance("@mozilla.org/timer;1");
if (mFileIOTimer)
mFileIOTimer->InitWithCallback(NS_STATIC_CAST(nsITimerCallback *, this), percentage == 100 ? 500 : 0, nsITimer::TYPE_ONE_SHOT);
} else
EndCopyFolders();
return;
}
void nsDogbertProfileMigrator::EndCopyFolders()
{
// clear out the file transaction array
if (mFileCopyTransactions)
{
PRUint32 count = mFileCopyTransactions->Count();
for (PRUint32 i = 0; i < count; ++i)
{
fileTransactionEntry* fileTransaction = (fileTransactionEntry*) mFileCopyTransactions->ElementAt(i);
if (fileTransaction)
{
fileTransaction->srcFile = nsnull;
fileTransaction->destFile = nsnull;
delete fileTransaction;
}
}
mFileCopyTransactions->Clear();
delete mFileCopyTransactions;
}
// notify the UI that we are done with the migration process
nsAutoString index;
index.AppendInt(nsIMailProfileMigrator::MAILDATA);
NOTIFY_OBSERVERS(MIGRATION_ITEMAFTERMIGRATE, index.get());
NOTIFY_OBSERVERS(MIGRATION_ENDED, nsnull);
}
///////////////////////////////////////////////////////////////////////////////
// nsIMailProfileMigrator
NS_IMETHODIMP
nsDogbertProfileMigrator::Migrate(PRUint16 aItems, nsIProfileStartup* aStartup, const PRUnichar* aProfile)
{
nsresult rv = NS_OK;
if (!mTargetProfile) {
GetProfilePath(aStartup, mTargetProfile);
if (!mTargetProfile) return NS_ERROR_FAILURE;
}
if (!mSourceProfile)
GetSourceProfile(aProfile);
NOTIFY_OBSERVERS(MIGRATION_STARTED, nsnull);
rv = CopyPreferences();
return rv;
}
NS_IMETHODIMP
nsDogbertProfileMigrator::GetMigrateData(const PRUnichar* aProfile,
PRBool aReplace,
PRUint16* aResult)
{
// add some extra migration fields for things we also migrate
*aResult |= nsIMailProfileMigrator::ACCOUNT_SETTINGS
| nsIMailProfileMigrator::MAILDATA
| nsIMailProfileMigrator::NEWSDATA
| nsIMailProfileMigrator::ADDRESSBOOK_DATA;
return NS_OK;
}
NS_IMETHODIMP
nsDogbertProfileMigrator::GetSourceExists(PRBool* aResult)
{
nsCOMPtr<nsISupportsArray> profiles;
GetSourceProfiles(getter_AddRefs(profiles));
if (profiles) {
PRUint32 count;
profiles->Count(&count);
*aResult = count > 0;
}
else
*aResult = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsDogbertProfileMigrator::GetSourceHasMultipleProfiles(PRBool* aResult)
{
nsCOMPtr<nsISupportsArray> profiles;
GetSourceProfiles(getter_AddRefs(profiles));
if (profiles) {
PRUint32 count;
profiles->Count(&count);
*aResult = count > 1;
}
else
*aResult = PR_FALSE;
return NS_OK;
}
#if defined(XP_WIN) || defined(XP_OS2) || defined(XP_MACOSX)
NS_IMETHODIMP
nsDogbertProfileMigrator::GetSourceProfiles(nsISupportsArray** aResult)
{
if (!mProfiles) {
nsresult rv;
rv = NS_NewISupportsArray(getter_AddRefs(mProfiles));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIFile> regFile;
rv = NS_GetSpecialDirectory(OLDREG_DIR, getter_AddRefs(regFile));
NS_ENSURE_SUCCESS(rv, rv);
regFile->AppendNative(NS_LITERAL_CSTRING(OLDREG_NAME));
nsCAutoString path;
rv = regFile->GetNativePath(path);
NS_ENSURE_SUCCESS(rv, rv);
if (NR_StartupRegistry())
return NS_ERROR_FAILURE;
HREG reg = nsnull;
REGENUM enumstate = 0;
if (NR_RegOpen(path.get(), &reg)) {
NR_ShutdownRegistry();
return NS_ERROR_FAILURE;
}
char profileName[MAXREGNAMELEN];
while (!NR_RegEnumSubkeys(reg, ROOTKEY_USERS, &enumstate,
profileName, MAXREGNAMELEN, REGENUM_CHILDREN)) {
nsCOMPtr<nsISupportsString> nameString
(do_CreateInstance("@mozilla.org/supports-string;1"));
if (nameString) {
nameString->SetData(NS_ConvertUTF8toUTF16(profileName));
mProfiles->AppendElement(nameString);
}
}
}
NS_IF_ADDREF(*aResult = mProfiles);
return NS_OK;
}
#else // XP_UNIX
NS_IMETHODIMP
nsDogbertProfileMigrator::GetSourceProfiles(nsISupportsArray** aResult)
{
nsresult rv;
const char* profileDir = PR_GetEnv(PROFILE_HOME_ENVIRONMENT_VARIABLE);
if (!profileDir) {
profileDir = PR_GetEnv(HOME_ENVIRONMENT_VARIABLE);
}
if (!profileDir) return NS_ERROR_FAILURE;
nsCAutoString profilePath(profileDir);
profilePath += "/.netscape";
nsCOMPtr<nsILocalFile> profileFile;
rv = NS_NewNativeLocalFile(profilePath, PR_TRUE, getter_AddRefs(profileFile));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIFile> prefFile;
rv = profileFile->Clone(getter_AddRefs(prefFile));
NS_ENSURE_SUCCESS(rv, rv);
prefFile->AppendNative(NS_LITERAL_CSTRING("preferences.js"));
PRBool exists;
rv = prefFile->Exists(&exists);
if (NS_FAILED(rv) || !exists) {
return NS_ERROR_FAILURE;
}
mSourceProfile = profileFile;
rv = NS_NewISupportsArray(getter_AddRefs(mProfiles));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISupportsString> nameString
(do_CreateInstance("@mozilla.org/supports-string;1"));
if (!nameString) return NS_ERROR_FAILURE;
nameString->SetData(NS_LITERAL_STRING("Netscape 4.x"));
mProfiles->AppendElement(nameString);
NS_ADDREF(*aResult = mProfiles);
return NS_OK;
}
#endif // GetSourceProfiles
// on win/mac/os2, NS4x uses a registry to determine profile locations
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_OS2)
void nsDogbertProfileMigrator::GetSourceProfile(const PRUnichar* aProfile)
{
nsresult rv;
nsCOMPtr<nsIFile> regFile;
rv = NS_GetSpecialDirectory(OLDREG_DIR, getter_AddRefs(regFile));
if (NS_FAILED(rv)) return;
regFile->AppendNative(NS_LITERAL_CSTRING(OLDREG_NAME));
nsCAutoString path;
rv = regFile->GetNativePath(path);
if (NS_FAILED(rv)) return;
if (NR_StartupRegistry())
return;
HREG reg = nsnull;
RKEY profile = nsnull;
if (NR_RegOpen(path.get(), &reg))
goto cleanup;
{
// on macos, registry entries are UTF8 encoded
NS_ConvertUTF16toUTF8 profileName(aProfile);
if (NR_RegGetKey(reg, ROOTKEY_USERS, profileName.get(), &profile))
goto cleanup;
}
char profilePath[MAXPATHLEN];
if (NR_RegGetEntryString(reg, profile, "ProfileLocation", profilePath, MAXPATHLEN))
goto cleanup;
mSourceProfile = do_CreateInstance("@mozilla.org/file/local;1");
if (!mSourceProfile) goto cleanup;
{
// the string is UTF8 encoded, which forces us to do some strange string-do
rv = mSourceProfile->InitWithPath(NS_ConvertUTF8toUTF16(profilePath));
}
if (NS_FAILED(rv))
mSourceProfile = nsnull;
cleanup:
if (reg)
NR_RegClose(reg);
NR_ShutdownRegistry();
}
#else
void
nsDogbertProfileMigrator::GetSourceProfile(const PRUnichar* aProfile)
{
// if GetSourceProfiles didn't do its magic, we're screwed
}
#endif
nsresult nsDogbertProfileMigrator::CopyPreferences()
{
// Load the source pref file
nsresult rv;
mPrefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString oldProfDirStr;
nsCAutoString newProfDirStr;
nsCOMPtr<nsILocalFile> sourceProfile = do_QueryInterface(mSourceProfile);
nsCOMPtr<nsILocalFile> targetProfile = do_QueryInterface(mTargetProfile);
sourceProfile->GetPersistentDescriptor(oldProfDirStr);
targetProfile->GetPersistentDescriptor(newProfDirStr);
nsAutoString index;
index.AppendInt(nsIMailProfileMigrator::MAILDATA);
NOTIFY_OBSERVERS(MIGRATION_ITEMBEFOREMIGRATE, index.get());
ProcessPrefsCallback(oldProfDirStr.get(), newProfDirStr.get());
// Generate the max progress value now that we know all of the files we need to copy
PRUint32 count = mFileCopyTransactions->Count();
for (PRUint32 i = 0; i < count; ++i)
{
fileTransactionEntry* fileTransaction = (fileTransactionEntry*) mFileCopyTransactions->ElementAt(i);
if (fileTransaction)
{
PRInt64 fileSize;
fileTransaction->srcFile->GetFileSize(&fileSize);
LL_ADD(mMaxProgress, mMaxProgress, fileSize);
}
}
CopyNextFolder();
return NS_OK;
}
/*--------------------------------------------------------------------------
* ProcessPrefsCallback is the primary funtion for the class nsPrefMigration.
*
* Called by: The Profile Manager (nsProfile.cpp)
* INPUT: The specific profile path (prefPath) and the 5.0 installed path
* OUTPUT: The modified 5.0 prefs files
* RETURN: Success or a failure code
*
*-------------------------------------------------------------------------*/
nsresult
nsDogbertProfileMigrator::ProcessPrefsCallback(const char* oldProfilePathStr, const char * newProfilePathStr)
{
nsresult rv;
nsCOMPtr<nsILocalFile> oldProfilePath;
nsCOMPtr<nsILocalFile> newProfilePath;
nsCOMPtr<nsILocalFile> oldPOPMailPath;
nsCOMPtr<nsILocalFile> newPOPMailPath;
nsCOMPtr<nsILocalFile> oldIMAPMailPath;
nsCOMPtr<nsILocalFile> newIMAPMailPath;
nsCOMPtr<nsILocalFile> oldIMAPLocalMailPath;
nsCOMPtr<nsILocalFile> newIMAPLocalMailPath;
nsCOMPtr<nsILocalFile> oldNewsPath;
nsCOMPtr<nsILocalFile> newNewsPath;
nsCOMPtr<nsILocalFile> newPrefsFile;
#ifdef HAVE_MOVEMAIL
nsCOMPtr<nsILocalFile> oldMOVEMAILMailPath;
nsCOMPtr<nsILocalFile> newMOVEMAILMailPath;
#endif /* HAVE_MOVEMAIL */
PRBool exists = PR_FALSE,
enoughSpace = PR_TRUE,
localMailDriveDefault = PR_FALSE,
summaryMailDriveDefault = PR_FALSE,
newsDriveDefault = PR_FALSE,
copyMailFileInMigration = PR_TRUE;
nsCOMPtr <nsILocalFile> localMailFile;
nsCOMPtr <nsILocalFile> summaryMailFile;
nsCOMPtr <nsILocalFile> newsFile;
nsCOMPtr <nsILocalFile> oldProfileFile;
nsCOMPtr <nsILocalFile> newProfileFile;
PRInt32 serverType = POP_4X_MAIL_TYPE;
char *popServerName = nsnull;
PRUint32 totalRequired = 0;
PRInt64 localMailDrive = LL_Zero(),
summaryMailDrive = LL_Zero(),
newsDrive = LL_Zero(),
totalSummaryFileSize = LL_Zero(),
profileDrive = LL_Zero(),
totalLocalMailSize = LL_Zero(),
totalNewsSize = LL_Zero(),
totalProfileSize = LL_Zero();
PRInt64 DriveID[MAX_DRIVES];
PRUint32 SpaceRequired[MAX_DRIVES];
#if defined(NS_DEBUG)
printf("*Entered Actual Migration routine*\n");
#endif
nsCOMPtr<nsIPrefService> prefService = do_QueryInterface(mPrefs, &rv);
NS_ENSURE_SUCCESS(rv, rv);
for (int i=0; i < MAX_DRIVES; i++)
{
DriveID[i] = LL_Zero();
SpaceRequired[i] = 0;
}
oldProfilePath = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
newProfilePath = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
rv = ConvertPersistentStringToFile(oldProfilePathStr, oldProfilePath);
if (NS_FAILED(rv)) return rv;
rv = ConvertPersistentStringToFile(newProfilePathStr, newProfilePath);
if (NS_FAILED(rv)) return rv;
oldProfileFile = oldProfilePath;
newProfileFile = newProfilePath;
/* initialize prefs with the old prefs.js file (which is a copy of the 4.x preferences file) */
nsCOMPtr<nsILocalFile> PrefsFile4x = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
rv = PrefsFile4x->InitWithFile(oldProfilePath);
if (NS_FAILED(rv)) return rv;
rv = PrefsFile4x->AppendNative(NS_LITERAL_CSTRING(PREF_FILE_NAME_IN_4x));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIFile> systemTempDir;
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(systemTempDir));
if (NS_FAILED(rv)) return rv;
systemTempDir->AppendNative(NS_LITERAL_CSTRING("migrate"));
//Create a unique directory in the system temp dir based on the name of the 4.x prefs file
rv = systemTempDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) return rv;
rv = PrefsFile4x->CopyToNative(systemTempDir, NS_LITERAL_CSTRING(PREF_FILE_NAME_IN_4x));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIFile> cloneFile;
rv = systemTempDir->Clone(getter_AddRefs(cloneFile));
if (NS_FAILED(rv)) return rv;
m_prefsFile = do_QueryInterface(cloneFile, &rv);
if (NS_FAILED(rv)) return rv;
rv = m_prefsFile->AppendNative(NS_LITERAL_CSTRING(PREF_FILE_NAME_IN_4x));
if (NS_FAILED(rv)) return rv;
//Clear the prefs in case a previous set was read in.
prefService->ResetPrefs();
//Now read the prefs from the prefs file in the system directory
prefService->ReadUserPrefs(m_prefsFile);
// Start computing the sizes required for migration
//
rv = GetSizes(oldProfileFile, PR_FALSE, &totalProfileSize);
newProfileFile->GetDiskSpaceAvailable(&profileDrive);
rv = mPrefs->GetIntPref(PREF_MAIL_SERVER_TYPE, &serverType);
if (NS_FAILED(rv)) return rv;
// get the migration mode for mail
rv = mPrefs->GetBoolPref(PREF_MIGRATION_MODE_FOR_MAIL, &copyMailFileInMigration);
if (NS_FAILED(rv))
return rv;
if (serverType == POP_4X_MAIL_TYPE) {
summaryMailDriveDefault = PR_TRUE; //summary files are only used in IMAP so just set it to true here.
summaryMailDrive = profileDrive; //just set the drive for summary files to be the same as the new profile
rv = GetDirFromPref(oldProfilePath,newProfilePath,NEW_MAIL_DIR_NAME, PREF_MAIL_DIRECTORY,
getter_AddRefs(newPOPMailPath), getter_AddRefs(oldPOPMailPath));
if (NS_FAILED(rv)) {
rv = DetermineOldPath(oldProfilePath, OLD_MAIL_DIR_NAME, "mailDirName", oldPOPMailPath);
if (NS_FAILED(rv)) return rv;
rv = SetPremigratedFilePref(PREF_MAIL_DIRECTORY, oldPOPMailPath);
if (NS_FAILED(rv)) return rv;
newPOPMailPath->InitWithFile(newProfilePath);
if (NS_FAILED(rv)) return rv;
localMailDriveDefault = PR_TRUE;
}
localMailFile = oldPOPMailPath;
rv = GetSizes(localMailFile, PR_TRUE, &totalLocalMailSize);
localMailFile->GetDiskSpaceAvailable(&localMailDrive);
}
else if(serverType == IMAP_4X_MAIL_TYPE) {
/* First get the actual 4.x "Local Mail" files location */
rv = GetDirFromPref(oldProfilePath,newProfilePath, NEW_MAIL_DIR_NAME, PREF_MAIL_DIRECTORY,
getter_AddRefs(newIMAPLocalMailPath), getter_AddRefs(oldIMAPLocalMailPath));
if (NS_FAILED(rv)) {
rv = DetermineOldPath(oldProfilePath, OLD_MAIL_DIR_NAME, "mailDirName", oldIMAPLocalMailPath);
if (NS_FAILED(rv)) return rv;
rv = SetPremigratedFilePref(PREF_MAIL_DIRECTORY, oldIMAPLocalMailPath);
if (NS_FAILED(rv)) return rv;
rv = newIMAPLocalMailPath->InitWithFile(newProfilePath);
if (NS_FAILED(rv)) return rv;
localMailDriveDefault = PR_TRUE;
}
localMailFile = oldIMAPLocalMailPath;
rv = GetSizes(localMailFile, PR_TRUE, &totalLocalMailSize);
localMailFile->GetDiskSpaceAvailable(&localMailDrive);
/* Next get IMAP mail summary files location */
rv = GetDirFromPref(oldProfilePath,newProfilePath, NEW_IMAPMAIL_DIR_NAME, PREF_MAIL_IMAP_ROOT_DIR,
getter_AddRefs(newIMAPMailPath), getter_AddRefs(oldIMAPMailPath));
if (NS_FAILED(rv)) {
rv = oldIMAPMailPath->InitWithFile(oldProfilePath);
if (NS_FAILED(rv)) return rv;
/* we didn't over localize "ImapMail" in 4.x, so this is all we have to do */
rv = oldIMAPMailPath->AppendNative(NS_LITERAL_CSTRING(OLD_IMAPMAIL_DIR_NAME));
if (NS_FAILED(rv)) return rv;
rv = SetPremigratedFilePref(PREF_MAIL_IMAP_ROOT_DIR, oldIMAPMailPath);
if (NS_FAILED(rv)) return rv;
rv = newIMAPMailPath->InitWithFile(newProfilePath);
if (NS_FAILED(rv)) return rv;
summaryMailDriveDefault = PR_TRUE;
}
summaryMailFile = oldIMAPMailPath;
rv = GetSizes(summaryMailFile, PR_TRUE, &totalSummaryFileSize);
summaryMailFile->GetDiskSpaceAvailable(&summaryMailDrive);
}
#ifdef HAVE_MOVEMAIL
else if (serverType == MOVEMAIL_4X_MAIL_TYPE) {
summaryMailDriveDefault = PR_TRUE;
summaryMailDrive = profileDrive;
rv = GetDirFromPref(oldProfilePath,newProfilePath,NEW_MAIL_DIR_NAME, PREF_MAIL_DIRECTORY,
getter_AddRefs(newMOVEMAILMailPath), getter_AddRefs(oldMOVEMAILMailPath));
if (NS_FAILED(rv)) {
rv = oldMOVEMAILMailPath->InitWithFile(oldProfilePath);
if (NS_FAILED(rv)) return rv;
/* we didn't over localize this in 4.x, so this is all we have to do */
rv = oldMOVEMAILMailPath->AppendNative(NS_LITERAL_CSTRING(OLD_MAIL_DIR_NAME));
if (NS_FAILED(rv)) return rv;
rv = SetPremigratedFilePref(PREF_MAIL_DIRECTORY, oldMOVEMAILMailPath);
if (NS_FAILED(rv)) return rv;
rv = newMOVEMAILMailPath->InitWithFile(newProfilePath);
if (NS_FAILED(rv)) return rv;
localMailDriveDefault = PR_TRUE;
}
localMailFile = oldMOVEMAILMailPath;
rv = GetSizes(localMailFile, PR_TRUE, &totalLocalMailSize);
localMailFile->GetDiskSpaceAvailable(&localMailDrive);
}
#endif //HAVE_MOVEMAIL
////////////////////////////////////////////////////////////////////////////
// Now get the NEWS disk space requirements for migration.
////////////////////////////////////////////////////////////////////////////
rv = GetDirFromPref(oldProfilePath,newProfilePath, NEW_NEWS_DIR_NAME, PREF_NEWS_DIRECTORY,
getter_AddRefs(newNewsPath), getter_AddRefs(oldNewsPath));
if (NS_FAILED(rv)) {
rv = DetermineOldPath(oldProfilePath, OLD_NEWS_DIR_NAME, "newsDirName", oldNewsPath);
if (NS_FAILED(rv)) return rv;
rv = SetPremigratedFilePref(PREF_NEWS_DIRECTORY, oldNewsPath);
if (NS_FAILED(rv)) return rv;
rv = newNewsPath->InitWithFile(newProfilePath);
if (NS_FAILED(rv)) return rv;
newsDriveDefault = PR_TRUE;
}
rv = GetSizes(oldNewsPath, PR_TRUE, &totalNewsSize);
oldNewsPath->GetDiskSpaceAvailable(&newsDrive);
//
// Compute the space needed to migrate the profile
//
if(newsDriveDefault && localMailDriveDefault && summaryMailDriveDefault) // DEFAULT: All on the same drive
{
totalRequired = totalNewsSize + totalLocalMailSize + totalSummaryFileSize + totalProfileSize;
rv = ComputeSpaceRequirements(DriveID, SpaceRequired, profileDrive, totalRequired);
if (NS_FAILED(rv))
enoughSpace = PR_FALSE;
}
else
{
rv = ComputeSpaceRequirements(DriveID, SpaceRequired, profileDrive, totalProfileSize);
if (NS_FAILED(rv))
enoughSpace = PR_FALSE;
rv = ComputeSpaceRequirements(DriveID, SpaceRequired, localMailDrive, totalLocalMailSize);
if (NS_FAILED(rv))
enoughSpace = PR_FALSE;
rv = ComputeSpaceRequirements(DriveID, SpaceRequired, summaryMailDrive, totalSummaryFileSize);
if (NS_FAILED(rv))
enoughSpace = PR_FALSE;
rv = ComputeSpaceRequirements(DriveID, SpaceRequired, newsDrive, totalNewsSize);
if (NS_FAILED(rv))
enoughSpace = PR_FALSE;
}
// do something if not enough space
////////////////////////////////////////////////////////////////////////////
// If we reached this point, there is enough room to do a migration.
// Start creating directories and setting new pref values.
////////////////////////////////////////////////////////////////////////////
/* Create the new profile tree for 5.x */
rv = CreateNewUser5Tree(oldProfilePath, newProfilePath);
if (NS_FAILED(rv)) return rv;
if (serverType == POP_4X_MAIL_TYPE) {
rv = newPOPMailPath->Exists(&exists);
if (NS_FAILED(rv)) return rv;
if (!exists) {
rv = newPOPMailPath->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) return rv;
}
rv = newPOPMailPath->AppendNative(NS_LITERAL_CSTRING(NEW_MAIL_DIR_NAME));
if (NS_FAILED(rv)) return rv;
rv = newPOPMailPath->Exists(&exists);
if (NS_FAILED(rv)) return rv;
if (!exists) {
rv = newPOPMailPath->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) return rv;
}
rv = mPrefs->SetComplexValue(PREF_MAIL_DIRECTORY, NS_GET_IID(nsILocalFile), newPOPMailPath);
if (NS_FAILED(rv)) return rv;
mPrefs->GetCharPref(PREF_NETWORK_HOSTS_POP_SERVER, &popServerName);
nsCAutoString popServerNamewithoutPort(popServerName);
PRInt32 colonPos = popServerNamewithoutPort.FindChar(':');
if (colonPos != -1 ) {
popServerNamewithoutPort.SetLength(colonPos);
rv = newPOPMailPath->AppendNative(popServerNamewithoutPort);
}
else
rv = newPOPMailPath->AppendNative(nsDependentCString(popServerName));
if (NS_FAILED(rv)) return rv;
rv = newPOPMailPath->Exists(&exists);
if (NS_FAILED(rv)) return rv;
if (!exists) {
rv = newPOPMailPath->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) return rv;
}
}
else if (serverType == IMAP_4X_MAIL_TYPE) {
if( copyMailFileInMigration ) // copy mail files in migration
{
rv = newIMAPLocalMailPath->Exists(&exists);
if (NS_FAILED(rv)) return rv;
if (!exists) {
rv = newIMAPLocalMailPath->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) return rv;
}
rv = newIMAPLocalMailPath->AppendNative(NS_LITERAL_CSTRING(NEW_MAIL_DIR_NAME));
if (NS_FAILED(rv)) return rv;
/* Now create the new "Mail/Local Folders" directory */
rv = newIMAPLocalMailPath->Exists(&exists);
if (NS_FAILED(rv)) return rv;
if (!exists) {
newIMAPLocalMailPath->Create(nsIFile::DIRECTORY_TYPE, 0700);
}
rv = mPrefs->SetComplexValue(PREF_MAIL_DIRECTORY, NS_GET_IID(nsILocalFile), newIMAPLocalMailPath);
if (NS_FAILED(rv)) return rv;
rv = newIMAPLocalMailPath->AppendNative(NS_LITERAL_CSTRING(NEW_LOCAL_MAIL_DIR_NAME));
if (NS_FAILED(rv)) return rv;
rv = newIMAPLocalMailPath->Exists(&exists);
if (NS_FAILED(rv)) return rv;
if (!exists) {
rv = newIMAPLocalMailPath->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) return rv;
}
/* Now deal with the IMAP mail summary file location */
rv = newIMAPMailPath->Exists(&exists);
if (NS_FAILED(rv)) return rv;
if (!exists) {
rv = newIMAPMailPath->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) return rv;
}
rv = newIMAPMailPath->AppendNative(NS_LITERAL_CSTRING(NEW_IMAPMAIL_DIR_NAME));
if (NS_FAILED(rv)) return rv;
rv = newIMAPMailPath->Exists(&exists);
if (NS_FAILED(rv)) return rv;
if (!exists) {
rv = newIMAPMailPath->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) return rv;
}
{
rv = mPrefs->SetComplexValue(PREF_MAIL_IMAP_ROOT_DIR, NS_GET_IID(nsILocalFile), newIMAPMailPath);
if (NS_FAILED(rv)) return rv;
}
}
else
{
rv = mPrefs->SetComplexValue(PREF_MAIL_DIRECTORY, NS_GET_IID(nsILocalFile), oldIMAPLocalMailPath);
if (NS_FAILED(rv)) return rv;
rv = mPrefs->SetComplexValue(PREF_MAIL_IMAP_ROOT_DIR, NS_GET_IID(nsILocalFile), oldIMAPMailPath);
if (NS_FAILED(rv)) return rv;
}
}
#ifdef HAVE_MOVEMAIL
else if (serverType == MOVEMAIL_4X_MAIL_TYPE) {
rv = newMOVEMAILMailPath->Exists(&exists);
if (NS_FAILED(rv)) return rv;
if (!exists) {
rv = newMOVEMAILMailPath->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) return rv;
}
rv = newMOVEMAILMailPath->AppendNative(NS_LITERAL_CSTRING(NEW_MAIL_DIR_NAME));
if (NS_FAILED(rv)) return rv;
rv = newMOVEMAILMailPath->Exists(&exists);
if (NS_FAILED(rv)) return rv;
if (!exists) {
rv = newMOVEMAILMailPath->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) return rv;
}
rv = mPrefs->SetComplexValue(PREF_MAIL_DIRECTORY, NS_GET_IID(nsILocalFile), newMOVEMAILMailPath);
if (NS_FAILED(rv)) return rv;
rv = newMOVEMAILMailPath->AppendNative(NS_LITERAL_CSTRING(NEW_MOVEMAIL_DIR_NAME));
if (NS_FAILED(rv)) return rv;
rv = newMOVEMAILMailPath->Exists(&exists);
if (NS_FAILED(rv)) return rv;
if (!exists) {
rv = newMOVEMAILMailPath->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) return rv;
}
rv = NS_OK;
}
#endif /* HAVE_MOVEMAIL */
else {
NS_ASSERTION(0,"failure, didn't recognize your mail server type.\n");
return NS_ERROR_UNEXPECTED;
}
////////////////////////////////////////////////////////////////////////////
// Set all the appropriate NEWS prefs.
////////////////////////////////////////////////////////////////////////////
rv = newNewsPath->Exists(&exists);
if (NS_FAILED(rv)) return rv;
if (!exists) {
rv = newNewsPath->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) return rv;
}
rv = newNewsPath->AppendNative(NS_LITERAL_CSTRING(NEW_NEWS_DIR_NAME));
if (NS_FAILED(rv)) return rv;
rv = newNewsPath->Exists(&exists);
if (NS_FAILED(rv)) return rv;
if (!exists) {
rv = newNewsPath->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) return rv;
}
rv = mPrefs->SetComplexValue(PREF_NEWS_DIRECTORY, NS_GET_IID(nsILocalFile), newNewsPath);
if (NS_FAILED(rv)) return rv;
PRBool needToRenameFilterFiles;
if (PL_strcmp(IMAP_MAIL_FILTER_FILE_NAME_IN_4x,IMAP_MAIL_FILTER_FILE_NAME_IN_5x)) {
#ifdef IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x
// if we defined a format, the filter files don't live in the host directories
// (mac does this.) we'll take care of those filter files later, in DoSpecialUpdates()
needToRenameFilterFiles = PR_FALSE;
#else
needToRenameFilterFiles = PR_TRUE;
#endif /* IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x */
}
else {
// if the name was the same in 4x as in 5x, no need to rename it
needToRenameFilterFiles = PR_FALSE;
}
// just copy what we need
#ifdef XP_MACOSX
rv = DoTheCopy(oldProfilePath, newProfilePath, SECURITY_PATH, PR_TRUE);
if (NS_FAILED(rv)) return rv;
#else
rv = DoTheCopy(oldProfilePath, newProfilePath, PSM_CERT7_DB);
if (NS_FAILED(rv)) return rv;
rv = DoTheCopy(oldProfilePath, newProfilePath, PSM_KEY3_DB);
if (NS_FAILED(rv)) return rv;
rv = DoTheCopy(oldProfilePath, newProfilePath, PSM_SECMODULE_DB);
if (NS_FAILED(rv)) return rv;
#endif /* XP_MACOSX */
#ifdef XP_MACOSX
// Copy the Mac filter rule files which sits at the top level dir of a 4.x profile.
if(serverType == IMAP_4X_MAIL_TYPE) {
rv = CopyFilesByPattern(oldProfilePath, newProfilePath, MAC_RULES_FILE_ENDING_STRING_IN_4X);
NS_ENSURE_SUCCESS(rv,rv);
}
#endif
rv = DoTheCopy(oldNewsPath, newNewsPath, PR_TRUE);
if (NS_FAILED(rv)) return rv;
#ifdef NEED_TO_COPY_AND_RENAME_NEWSRC_FILES
/* in 4.x, the newsrc files were in $HOME. Now that we can have multiple
* profiles in 5.x, with the same user, this won't fly.
* when they migrate, we need to copy from $HOME/.newsrc-<host> to
* ~/.mozilla/<profile>/News/newsrc-<host>
*/
rv = CopyAndRenameNewsrcFiles(newNewsPath);
if (NS_FAILED(rv)) return rv;
#endif /* NEED_TO_COPY_AND_RENAME_NEWSRC_FILES */
if (serverType == IMAP_4X_MAIL_TYPE) {
if( copyMailFileInMigration ) // copy mail files in migration
{
rv = DoTheCopyAndRename(oldIMAPMailPath, newIMAPMailPath, PR_TRUE, needToRenameFilterFiles, IMAP_MAIL_FILTER_FILE_NAME_IN_4x, IMAP_MAIL_FILTER_FILE_NAME_IN_5x);
if (NS_FAILED(rv)) return rv;
rv = DoTheCopyAndRename(oldIMAPLocalMailPath, newIMAPLocalMailPath, PR_TRUE, needToRenameFilterFiles,IMAP_MAIL_FILTER_FILE_NAME_IN_4x,IMAP_MAIL_FILTER_FILE_NAME_IN_5x);
if (NS_FAILED(rv)) return rv;
}
else // Copy & Rename filter files
{
// IMAP path
// don't care if this fails
(void)DoTheCopyAndRename(oldIMAPMailPath, PR_TRUE, IMAP_MAIL_FILTER_FILE_NAME_IN_4x, IMAP_MAIL_FILTER_FILE_NAME_IN_5x);
// Local Folders path
// don't care if this fails
(void)DoTheCopyAndRename(oldIMAPLocalMailPath, PR_TRUE, IMAP_MAIL_FILTER_FILE_NAME_IN_4x, IMAP_MAIL_FILTER_FILE_NAME_IN_5x);
}
}
else if (serverType == POP_4X_MAIL_TYPE) {
// fix for bug #202010
// copy over the pop filter and popstate files now
// and later, in DoSpecialUpdates()
// we'll move and rename them
#ifdef POP_MAIL_FILTER_FILE_NAME_IN_4x
rv = DoTheCopy(oldProfilePath, newProfilePath, POP_MAIL_FILTER_FILE_NAME_IN_4x);
if (NS_FAILED(rv)) return rv;
#endif
#ifdef POPSTATE_FILE_IN_4x
rv = DoTheCopy(oldProfilePath, newProfilePath, POPSTATE_FILE_IN_4x);
if (NS_FAILED(rv)) return rv;
#endif
rv = DoTheCopy(oldPOPMailPath, newPOPMailPath, PR_TRUE);
if (NS_FAILED(rv)) return rv;
}
#ifdef HAVE_MOVEMAIL
else if (serverType == MOVEMAIL_4X_MAIL_TYPE) {
// in 4.x, the movemail filter name was the same as the pop filter name
// copy over the filter file now
// and later, in DoSpecialUpdates()
// we'll move and rename them
rv = DoTheCopy(oldProfilePath, newProfilePath, POP_MAIL_FILTER_FILE_NAME_IN_4x);
if (NS_FAILED(rv)) return rv;
rv = DoTheCopy(oldMOVEMAILMailPath, newMOVEMAILMailPath, PR_TRUE);
}
#endif /* HAVE_MOVEMAIL */
else {
NS_ASSERTION(0, "unknown mail server type!");
return NS_ERROR_FAILURE;
}
// Don't inherit the 4.x cache file location for mozilla!
// The cache pref later gets set with a default in nsAppRunner::InitCachePrefs().
mPrefs->ClearUserPref(PREF_BROWSER_CACHE_DIRECTORY);
rv = DoSpecialUpdates(newProfilePath);
if (NS_FAILED(rv)) return rv;
PR_FREEIF(popServerName);
nsCString path;
newProfilePath->GetNativePath(path);
NS_NewNativeLocalFile(path, PR_TRUE, getter_AddRefs(newPrefsFile));
rv = newPrefsFile->AppendNative(NS_LITERAL_CSTRING(PREF_FILE_NAME_IN_5x));
if (NS_FAILED(rv)) return rv;
rv = prefService->SavePrefFile(newPrefsFile);
if (NS_FAILED(rv)) return rv;
rv = prefService->ResetPrefs();
if (NS_FAILED(rv)) return rv;
PRBool flagExists = PR_FALSE;
m_prefsFile->Exists(&flagExists); //Delete the prefs.js file in the temp directory.
if (flagExists)
m_prefsFile->Remove(PR_FALSE);
systemTempDir->Exists(&flagExists); //Delete the unique dir in the system temp dir.
if (flagExists)
systemTempDir->Remove(PR_FALSE);
return rv;
}
nsresult nsDogbertProfileMigrator::CreateNewUser5Tree(nsILocalFile * oldProfilePath, nsILocalFile * newProfilePath)
{
nsresult rv;
PRBool exists;
NS_ASSERTION(*PREF_FILE_NAME_IN_4x, "don't know how to migrate your platform");
if (!*PREF_FILE_NAME_IN_4x) {
return NS_ERROR_UNEXPECTED;
}
/* Copy the old prefs file to the new profile directory for modification and reading.
after copying it, rename it to pref.js, the 5.x pref file name on all platforms */
nsCOMPtr<nsILocalFile> oldPrefsFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
rv = oldPrefsFile->InitWithFile(oldProfilePath);
if (NS_FAILED(rv)) return rv;
rv = oldPrefsFile->AppendNative(NS_LITERAL_CSTRING(PREF_FILE_NAME_IN_4x));
if (NS_FAILED(rv)) return rv;
/* the new prefs file */
nsCOMPtr<nsILocalFile> newPrefsFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);;
if (NS_FAILED(rv)) return rv;
rv = newPrefsFile->InitWithFile(newProfilePath);
if (NS_FAILED(rv)) return rv;
rv = newPrefsFile->Exists(&exists);
if (!exists)
rv = newPrefsFile->Create(nsIFile::DIRECTORY_TYPE, 0700);
rv = oldPrefsFile->CopyTo(newPrefsFile, EmptyString());
NS_ASSERTION(NS_SUCCEEDED(rv),"failed to copy prefs file");
rv = newPrefsFile->AppendNative(NS_LITERAL_CSTRING(PREF_FILE_NAME_IN_4x));
rv = newPrefsFile->MoveTo(nsnull, NS_LITERAL_STRING(PREF_FILE_NAME_IN_5x));
return NS_OK;
}
#ifdef NEED_TO_COPY_AND_RENAME_NEWSRC_FILES
nsresult nsDogbertProfileMigrator::CopyAndRenameNewsrcFiles(nsILocalFile * newPathFile)
{
nsresult rv;
nsCOMPtr <nsILocalFile> oldPathFile;
nsCAutoString fileOrDirNameStr;
rv = GetPremigratedFilePref(PREF_NEWS_DIRECTORY, getter_AddRefs(oldPathFile));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISimpleEnumerator> directoryEnumerator;
rv = oldPathFile->GetDirectoryEntries(getter_AddRefs(directoryEnumerator));
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasMore;
directoryEnumerator->HasMoreElements(&hasMore);
while (hasMore && NS_SUCCEEDED(rv))
{
nsCOMPtr<nsISupports> aSupport;
rv = directoryEnumerator->GetNext(getter_AddRefs(aSupport));
nsCOMPtr<nsIFile> currentFile(do_QueryInterface(aSupport, &rv));
nsCOMPtr<nsILocalFile> curLocalFile = do_QueryInterface(currentFile);
currentFile->GetNativeLeafName(fileOrDirNameStr);
if (nsCStringStartsWith(fileOrDirNameStr, NEWSRC_PREFIX_IN_4x) || nsCStringStartsWith(fileOrDirNameStr, SNEWSRC_PREFIX_IN_4x)) {
rv = currentFile->CopyTo(newPathFile, EmptyString());
NS_ASSERTION(NS_SUCCEEDED(rv),"failed to copy news file");
nsCOMPtr <nsIFile> newFile;
newPathFile->Clone(getter_AddRefs(newFile));
if (newFile)
{
newFile->AppendNative(fileOrDirNameStr);
fileOrDirNameStr.Cut(0, 1);
newFile->MoveToNative(nsnull, fileOrDirNameStr); /* rename .newsrc-news to newsrc-news, no need to keep it hidden anymore */
}
}
}
return NS_OK;
}
#endif /* NEED_TO_COPY_AND_RENAME_NEWSRC_FILES */
/*-------------------------------------------------------------------------
* DoTheCopyAndRename copies the files listed in oldPath to newPath
* and renames files, if necessary
*
* INPUT: oldPath - The old profile path plus the specific data type
* (e.g. mail or news)
* newPath - The new profile path plus the specific data type
*
* readSubdirs
*
* needToRenameFiles - do we need to search for files named oldFile
* and rename them to newFile
*
* oldFile - old file name (used for renaming)
*
* newFile - new file name (used for renaming)
*
* RETURNS: NS_OK if successful
* NS_ERROR_FAILURE if failed
*
*--------------------------------------------------------------------------*/
nsresult nsDogbertProfileMigrator::DoTheCopyAndRename(nsIFile * oldPathFile, nsIFile *newPathFile, PRBool readSubdirs, PRBool needToRenameFiles, const char *oldName, const char *newName)
{
nsresult rv;
nsCAutoString fileOrDirNameStr;
nsCOMPtr<nsISimpleEnumerator> directoryEnumerator;
rv = oldPathFile->GetDirectoryEntries(getter_AddRefs(directoryEnumerator));
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasMore;
directoryEnumerator->HasMoreElements(&hasMore);
while (hasMore && NS_SUCCEEDED(rv))
{
nsCOMPtr<nsISupports> aSupport;
rv = directoryEnumerator->GetNext(getter_AddRefs(aSupport));
nsCOMPtr<nsIFile> currentFile(do_QueryInterface(aSupport, &rv));
nsCOMPtr<nsILocalFile> curLocalFile = do_QueryInterface(currentFile);
currentFile->GetNativeLeafName(fileOrDirNameStr);
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 */
continue;
else
{
PRBool isDirectory = PR_FALSE;
currentFile->IsDirectory(&isDirectory);
if (isDirectory)
{
if(readSubdirs)
{
nsCOMPtr<nsIFile> newPathExtended;
rv = newPathFile->Clone(getter_AddRefs(newPathExtended));
NS_ENSURE_SUCCESS(rv, rv);
rv = newPathExtended->AppendNative(fileOrDirNameStr);
rv = newPathExtended->Create(nsIFile::DIRECTORY_TYPE, 0700);
DoTheCopyAndRename(curLocalFile, newPathExtended, PR_TRUE, needToRenameFiles, oldName, newName); /* re-enter the DoTheCopyAndRename function */
}
else
continue;
}
else {
// copy the file
if (fileOrDirNameStr.Equals(oldName))
AddFileCopyToList(curLocalFile, newPathFile, newName);
else
AddFileCopyToList(curLocalFile, newPathFile, "");
}
}
}
return NS_OK;
}
/*-------------------------------------------------------------------------
* DoTheCopyAndRename copies and renames files
*
* INPUT: aPath - the path
*
* aReadSubdirs - if sub directories should be handled
*
* aOldFile - old file name (used for renaming)
*
* aNewFile - new file name (used for renaming)
*
* RETURNS: NS_OK if successful
* NS_ERROR_FAILURE if failed
*
*--------------------------------------------------------------------------*/
nsresult nsDogbertProfileMigrator::DoTheCopyAndRename(nsIFile * aPathFile, PRBool aReadSubdirs, const char *aOldName, const char *aNewName)
{
if( !aOldName || !aNewName || !strcmp(aOldName, aNewName) )
return NS_ERROR_FAILURE;
nsCOMPtr <nsIFile> file;
nsresult rv = aPathFile->Clone(getter_AddRefs(file));
NS_ENSURE_SUCCESS(rv, rv);
file->AppendNative(nsDependentCString(aOldName));
nsCOMPtr<nsISimpleEnumerator> directoryEnumerator;
rv = aPathFile->GetDirectoryEntries(getter_AddRefs(directoryEnumerator));
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasMore;
directoryEnumerator->HasMoreElements(&hasMore);
while (hasMore && NS_SUCCEEDED(rv))
{
nsCOMPtr<nsISupports> aSupport;
rv = directoryEnumerator->GetNext(getter_AddRefs(aSupport));
nsCOMPtr<nsILocalFile> currentFile(do_QueryInterface(aSupport, &rv));
// Handle sub folders
PRBool isDirectory = PR_FALSE;
currentFile->IsDirectory(&isDirectory);
if (isDirectory)
{
if( aReadSubdirs )
{
nsCOMPtr<nsIFile>fileOrDirName;
currentFile->Clone(getter_AddRefs(fileOrDirName));
DoTheCopyAndRename(fileOrDirName, aReadSubdirs, aOldName, aNewName); /* re-enter the DoTheCopyAndRename function */
}
else
continue;
}
}
nsAutoString newName = NS_ConvertUTF8toUTF16(aNewName);
file->CopyTo(aPathFile, newName);
return NS_OK;
}
nsresult nsDogbertProfileMigrator::CopyFilesByPattern(nsILocalFile * oldPathFile, nsILocalFile * newPathFile, const char *pattern)
{
nsCOMPtr<nsISimpleEnumerator> directoryEnumerator;
nsresult rv = oldPathFile->GetDirectoryEntries(getter_AddRefs(directoryEnumerator));
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasMore;
directoryEnumerator->HasMoreElements(&hasMore);
while (hasMore && NS_SUCCEEDED(rv))
{
nsCOMPtr<nsISupports> aSupport;
rv = directoryEnumerator->GetNext(getter_AddRefs(aSupport));
nsCOMPtr<nsILocalFile> currentFile(do_QueryInterface(aSupport, &rv));
PRBool isDirectory = PR_FALSE;
currentFile->IsDirectory(&isDirectory);
if (isDirectory)
continue;
nsCAutoString fileOrDirNameStr;
currentFile->GetNativeLeafName(fileOrDirNameStr);
if (!nsCStringEndsWith(fileOrDirNameStr, pattern))
continue;
AddFileCopyToList(currentFile, newPathFile, "");
}
return NS_OK;
}
nsresult nsDogbertProfileMigrator::AddFileCopyToList(nsIFile * aOldPath, nsIFile * aNewPath, const char * newName)
{
fileTransactionEntry* fileEntry = new fileTransactionEntry;
fileEntry->srcFile = do_QueryInterface(aOldPath);
fileEntry->destFile = do_QueryInterface(aNewPath);
fileEntry->newName = NS_ConvertUTF8toUTF16(newName);
mFileCopyTransactions->AppendElement((void*) fileEntry);
return NS_OK;
}
nsresult nsDogbertProfileMigrator::DoTheCopy(nsIFile * oldPath, nsIFile * newPath, PRBool readSubdirs)
{
return DoTheCopyAndRename(oldPath, newPath, readSubdirs, PR_FALSE, "", "");
}
nsresult nsDogbertProfileMigrator::DoTheCopy(nsILocalFile * oldPath, nsILocalFile * newPath, const char *fileOrDirName, PRBool isDirectory)
{
nsresult rv;
if (isDirectory)
{
nsCOMPtr<nsIFile> oldSubPath;
oldPath->Clone(getter_AddRefs(oldSubPath));
rv = oldSubPath->AppendNative(nsDependentCString(fileOrDirName));
if (NS_FAILED(rv)) return rv;
PRBool exist;
rv = oldSubPath->Exists(&exist);
if (NS_FAILED(rv)) return rv;
if (!exist)
{
rv = oldSubPath->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) return rv;
}
nsCOMPtr<nsILocalFile> newSubPath = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
newSubPath->InitWithFile(newPath);
rv = newSubPath->AppendNative(nsDependentCString(fileOrDirName));
if (NS_FAILED(rv)) return rv;
rv = newSubPath->Exists(&exist);
if (NS_FAILED(rv)) return rv;
if (!exist)
{
rv = newSubPath->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) return rv;
}
DoTheCopy(oldSubPath, newSubPath, PR_TRUE);
}
else
{
nsCOMPtr<nsILocalFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
file->InitWithFile(oldPath);
rv = file->AppendNative(nsDependentCString(fileOrDirName));
if( NS_FAILED(rv) ) return rv;
PRBool exist;
rv = file->Exists(&exist);
if( NS_FAILED(rv) ) return rv;
if( exist) {
AddFileCopyToList(oldPath, newPath, "");
}
}
return rv;
}
/*----------------------------------------------------------------------------
* DoSpecialUpdates updates is a routine that does some miscellaneous updates
* like renaming certain files, etc.
*--------------------------------------------------------------------------*/
nsresult nsDogbertProfileMigrator::DoSpecialUpdates(nsILocalFile * profilePath)
{
nsresult rv;
PRInt32 serverType;
nsCOMPtr <nsILocalFile> prefFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
prefFile->InitWithFile(profilePath);
prefFile->AppendNative(NS_LITERAL_CSTRING(PREF_FILE_NAME_IN_5x));
nsCOMPtr <nsIOutputStream> fsStream;
rv = NS_NewLocalFileOutputStream(getter_AddRefs(fsStream), prefFile, PR_WRONLY | PR_APPEND | PR_CREATE_FILE, 0660);
NS_ENSURE_SUCCESS(rv, rv);
/* Need to add a string to the top of the prefs.js file to prevent it
* from being loaded as a standard javascript file which would be a
* security hole.
*/
PRUint32 bytesWritten;
nsCAutoString headerLine(PREF_FILE_HEADER_STRING MSG_LINEBREAK);
fsStream->Write(headerLine.get(), headerLine.Length(), &bytesWritten) ;
fsStream->Close();
/* Create the new mail directory from the setting in prefs.js or a default */
rv = mPrefs->GetIntPref(PREF_MAIL_SERVER_TYPE, &serverType);
if (NS_FAILED(rv)) return rv;
if (serverType == POP_4X_MAIL_TYPE) {
rv = RenameAndMove4xPopFilterFile(profilePath);
if (NS_FAILED(rv)) return rv;
rv = RenameAndMove4xPopStateFile(profilePath);
if (NS_FAILED(rv)) return rv;
}
#ifdef IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x
else if (serverType == IMAP_4X_MAIL_TYPE) {
rv = RenameAndMove4xImapFilterFiles(profilePath);
if (NS_FAILED(rv)) return rv;
}
#endif /* IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x */
return rv;
}
nsresult nsDogbertProfileMigrator::RenameAndMove4xPopFilterFile(nsILocalFile * profilePath)
{
return RenameAndMove4xPopFile(profilePath, POP_MAIL_FILTER_FILE_NAME_IN_4x, POP_MAIL_FILTER_FILE_NAME_IN_5x);
}
nsresult nsDogbertProfileMigrator::RenameAndMove4xPopStateFile(nsILocalFile * profilePath)
{
#ifdef POPSTATE_FILE_IN_4x
return RenameAndMove4xPopFile(profilePath, POPSTATE_FILE_IN_4x, POPSTATE_FILE_IN_5x);
#else
// on windows, popstate.dat was in Users\<profile>\MAIL\popstate.dat
// which is the right place, unlike linux and mac.
// so, when we migrate Users\<profile>\Mail to Users50\<profile>\Mail\<hostname>
// it just works
return NS_OK;
#endif /* POPSTATE_FILE_IN_4x */
}
nsresult nsDogbertProfileMigrator::RenameAndMove4xPopFile(nsILocalFile * profilePath, const char *fileNameIn4x, const char *fileNameIn5x)
{
nsresult rv;
nsCOMPtr <nsILocalFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
file->InitWithFile(profilePath);
// we assume the 4.x pop files live at <profile>/<fileNameIn4x>
file->AppendNative(nsDependentCString(fileNameIn4x));
// figure out where the 4.x pop mail directory got copied to
char *popServerName = nsnull;
nsCOMPtr <nsIFile> migratedPopDirectory;
profilePath->Clone(getter_AddRefs(migratedPopDirectory));
migratedPopDirectory->AppendNative(NS_LITERAL_CSTRING(NEW_MAIL_DIR_NAME));
mPrefs->GetCharPref(PREF_NETWORK_HOSTS_POP_SERVER, &popServerName);
migratedPopDirectory->AppendNative(nsDependentCString(popServerName));
PR_FREEIF(popServerName);
// copy the 4.x file from <profile>/<fileNameIn4x> to the <profile>/Mail/<hostname>/<fileNameIn4x>
rv = file->CopyTo(migratedPopDirectory, EmptyString());
NS_ASSERTION(NS_SUCCEEDED(rv),"failed to copy pop file");
// XXX todo, delete the old file
// we are leaving it behind
// make migratedPopDirectory point the the copied filter file,
// <profile>/Mail/<hostname>/<fileNameIn4x>
migratedPopDirectory->AppendNative(nsDependentCString(fileNameIn4x));
// rename <profile>/Mail/<hostname>/<fileNameIn4x>to <profile>/Mail/<hostname>/<fileNameIn5x>, if necessary
if (PL_strcmp(fileNameIn4x,fileNameIn5x))
migratedPopDirectory->MoveToNative(nsnull, nsDependentCString(fileNameIn5x));
return NS_OK;
}
#ifdef IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x
#define BUFFER_LEN 128
nsresult nsDogbertProfileMigrator::RenameAndMove4xImapFilterFile(nsILocalFile * profilePath, const char *hostname)
{
char imapFilterFileName[BUFFER_LEN];
// the 4.x imap filter file lives in "<profile>/<hostname> Rules"
nsCOMPtr <nsIFile> file;
nsresult rv = profilePath->Clone(getter_AddRefs(file));
if (NS_FAILED(rv)) return rv;
PR_snprintf(imapFilterFileName, BUFFER_LEN, IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x, hostname);
file->AppendNative(nsDependentCString(imapFilterFileName));
PRBool exists = PR_FALSE;
file->Exists(&exists);
// if that file didn't exist, because they didn't use filters for that server, return now
if (!exists) return NS_OK;
// figure out where the 4.x pop mail directory got copied to
nsCOMPtr <nsILocalFile> migratedImapDirectory = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
migratedImapDirectory->InitWithFile(profilePath);
migratedImapDirectory->AppendNative(NS_LITERAL_CSTRING(NEW_IMAPMAIL_DIR_NAME));
migratedImapDirectory->AppendNative(nsDependentCString(hostname));
// copy the 4.x file from "<profile>/<hostname> Rules" to <profile>/ImapMail/<hostname>/
rv = file->CopyTo(migratedImapDirectory, EmptyString());
NS_ASSERTION(NS_SUCCEEDED(rv),"failed to copy imap file");
// make migratedPopDirectory point the the copied filter file,
// "<profile>/ImapMail/<hostname>/<hostname> Rules"
migratedImapDirectory->AppendNative(nsDependentCString(imapFilterFileName));
// rename "<profile>/ImapMail/<hostname>/<hostname> Rules" to "<profile>/ImapMail/<hostname>/rules.dat"
migratedImapDirectory->MoveTo(nsnull, NS_LITERAL_STRING(IMAP_MAIL_FILTER_FILE_NAME_IN_5x));
return NS_OK;
}
nsresult nsDogbertProfileMigrator::RenameAndMove4xImapFilterFiles(nsILocalFile * profilePath)
{
nsresult rv;
nsCString hostList;
rv = mPrefs->GetCharPref(PREF_4X_NETWORK_HOSTS_IMAP_SERVER, getter_Copies(hostList));
if (NS_FAILED(rv)) return rv;
if (hostList.IsEmpty()) return NS_OK;
char *token = nsnull;
char *rest = hostList.BeginWriting();
nsCAutoString str;
token = NS_strtok(",", &rest);
while (token && *token) {
str = token;
str.StripWhitespace();
if (!str.IsEmpty()) {
// str is the hostname
rv = RenameAndMove4xImapFilterFile(profilePath, str.get());
if (NS_FAILED(rv)) {
// failed to migrate. bail.
return rv;
}
}
token = NS_strtok(",", &rest);
}
return NS_OK;
}
#endif /* IMAP_MAIL_FILTER_FILE_NAME_FORMAT_IN_4x */
nsresult
nsDogbertProfileMigrator::Rename4xFileAfterMigration(nsIFile * profilePath, const char *oldFileName, const char *newFileName)
{
// if they are the same, don't bother to rename the file.
if (PL_strcmp(oldFileName, newFileName) == 0)
return NS_OK;
nsCOMPtr <nsIFile> file;
nsresult rv = profilePath->Clone(getter_AddRefs(file));
if (NS_FAILED(rv)) return rv;
file->AppendNative(nsDependentCString(oldFileName));
PRBool exists = PR_FALSE;
file->Exists(&exists);
// make sure it exists before you try to rename it
if (exists)
rv = file->MoveToNative(nsnull, nsDependentCString(newFileName));
return rv;
}
#ifdef NEED_TO_COPY_AND_RENAME_NEWSRC_FILES
nsresult nsDogbertProfileMigrator::GetPremigratedFilePref(const char *pref_name, nsILocalFile **path)
{
if (!pref_name) return NS_ERROR_FAILURE;
char premigration_pref[MAX_PREF_LEN];
PR_snprintf(premigration_pref,MAX_PREF_LEN,"%s%s",PREMIGRATION_PREFIX,pref_name);
return mPrefs->GetComplexValue((const char *)premigration_pref, NS_GET_IID(nsILocalFile), (void **) path);
}
#endif /* NEED_TO_COPY_AND_RENAME_NEWSRC_FILES */
nsresult nsDogbertProfileMigrator::DetermineOldPath(nsILocalFile *profilePath, const char *oldPathName, const char *oldPathEntityName, nsILocalFile *oldPath)
{
nsresult rv;
/* set oldLocalFile to profilePath. need to convert nsILocalFile->nsILocalFile */
nsCOMPtr<nsILocalFile> oldLocalFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
oldLocalFile->InitWithFile(profilePath);
/* get the string bundle, and get the appropriate localized string out of it */
nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIStringBundle> bundle;
rv = bundleService->CreateBundle(MIGRATION_PROPERTIES_URL, getter_AddRefs(bundle));
if (NS_FAILED(rv)) return rv;
nsString localizedDirName;
nsAutoString entityName;
CopyASCIItoUTF16(oldPathEntityName, entityName);
rv = bundle->GetStringFromName(entityName.get(), getter_Copies(localizedDirName));
if (NS_FAILED(rv)) return rv;
rv = oldLocalFile->AppendRelativePath(localizedDirName);
if (NS_FAILED(rv)) return rv;
PRBool exists = PR_FALSE;
rv = oldLocalFile->Exists(&exists);
if (!exists) {
/* if the localized name doesn't exist, use the english name */
rv = oldPath->InitWithFile(profilePath);
if (NS_FAILED(rv)) return rv;
rv = oldPath->AppendNative(nsDependentCString(oldPathName));
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
/* at this point, the folder with the localized name exists, so use it */
nsCAutoString persistentDescriptor;
rv = oldLocalFile->GetPersistentDescriptor(persistentDescriptor);
if (NS_FAILED(rv)) return rv;
return oldPath->SetPersistentDescriptor(persistentDescriptor);
}
nsresult nsDogbertProfileMigrator::ConvertPersistentStringToFile(const char *str, nsILocalFile *path)
{
nsresult rv;
if (!str || !path) return NS_ERROR_NULL_POINTER;
rv = path->SetPersistentDescriptor(nsDependentCString(str));
return rv;
}
/*---------------------------------------------------------------------------------
* GetSizes reads the 4.x files in the profile tree and accumulates their sizes
*--------------------------------------------------------------------------------*/
nsresult nsDogbertProfileMigrator::GetSizes(nsILocalFile *inputPath, PRBool readSubdirs, PRInt64 *sizeTotal)
{
nsCAutoString folderName;
nsCOMPtr<nsISimpleEnumerator> directoryEnumerator;
nsresult rv = inputPath->GetDirectoryEntries(getter_AddRefs(directoryEnumerator));
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasMore;
directoryEnumerator->HasMoreElements(&hasMore);
while (hasMore && NS_SUCCEEDED(rv))
{
nsCOMPtr<nsISupports> aSupport;
rv = directoryEnumerator->GetNext(getter_AddRefs(aSupport));
nsCOMPtr<nsILocalFile> currentFile(do_QueryInterface(aSupport, &rv));
// Handle sub folders
PRBool isDirectory = PR_FALSE;
currentFile->GetNativeLeafName(folderName);
if (nsCStringEndsWith(folderName, MAIL_SUMMARY_SUFFIX_IN_4x) || nsCStringEndsWith(folderName, NEWS_SUMMARY_SUFFIX_IN_4x) || nsCStringEndsWith(folderName, SUMMARY_SUFFIX_IN_5x)) /* Don't copy the summary files */
continue;
else
{
currentFile->IsDirectory(&isDirectory);
if (isDirectory)
{
if(readSubdirs)
{
GetSizes(currentFile, PR_TRUE, sizeTotal); /* re-enter the GetSizes function */
}
else
continue;
}
else
{
PRInt64 fileSize;
currentFile->GetFileSize(&fileSize);
*sizeTotal += fileSize;
}
}
}
return NS_OK;
}
/*---------------------------------------------------------------------------------
* GetDirFromPref gets a directory based on a preference set in the 4.x
* preferences file, adds a 5 and resets the preference.
*
* INPUT:
* oldProfilePath - the path to the old 4.x profile directory.
* currently only used by UNIX
*
* newProfilePath - the path to the 5.0 profile directory
* currently only used by UNIX
*
* newDirName - the leaf name of the directory in the 5.0 world that corresponds to
* this pref. Examples: "Mail", "ImapMail", "News".
* only used on UNIX.
*
* pref - the pref in the "dot" format (e.g. mail.directory)
*
* OUTPUT: newPath - The old path with a 5 added (on mac and windows)
* the newProfilePath + "/" + newDirName (on UNIX)
* oldPath - The old path from the pref (if any)
*
*
* RETURNS: NS_OK if the pref was successfully pulled from the prefs file
*
*--------------------------------------------------------------------------------*/
nsresult
nsDogbertProfileMigrator::GetDirFromPref(nsILocalFile * oldProfilePath, nsILocalFile * newProfilePath, const char *newDirName, const char* pref, nsILocalFile** newPath, nsILocalFile** oldPath)
{
nsresult rv;
if (!oldProfilePath || !newProfilePath || !newDirName || !pref || !newPath || !oldPath)
return NS_ERROR_NULL_POINTER;
nsCOMPtr <nsILocalFile> oldPrefPath;
nsCOMPtr <nsILocalFile> newPathFile;
nsCOMPtr <nsILocalFile> oldPathFile;
nsCString oldPrefPathStr;
rv = mPrefs->GetCharPref(pref, getter_Copies(oldPrefPathStr));
if (NS_FAILED(rv)) return rv;
// the default on the mac was "". doing GetFileXPref on that would return
// the current working directory, like viewer_debug. yikes!
if (oldPrefPathStr.IsEmpty())
rv = NS_ERROR_FAILURE;
if (NS_FAILED(rv)) return rv;
rv = mPrefs->GetComplexValue(pref, NS_GET_IID(nsILocalFile), getter_AddRefs(oldPathFile));
if (NS_FAILED(rv)) return rv;
#ifdef XP_UNIX
// what if they don't want to go to <profile>/<newDirName>?
// what if unix users want "mail.directory" + "5" (like "~/ns_imap5")
// or "mail.imap.root_dir" + "5" (like "~/nsmail5")?
// should we let them? no. let's migrate them to
// <profile>/Mail and <profile>/ImapMail
// let's make all three platforms the same.
if (PR_TRUE) {
#else
nsCOMPtr <nsIFile> oldPrefPathParent;
rv = oldPrefPath->GetParent(getter_AddRefs(oldPrefPathParent));
if (NS_FAILED(rv)) return rv;
// if the pref pointed to the default directory
// treat it as if the pref wasn't set
// this way it will get migrated as the user expects
PRBool pathsMatch;
rv = oldProfilePath->Equals(oldPrefPathParent, &pathsMatch);
newPathFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_SUCCEEDED(rv) && pathsMatch)
{
#endif /* XP_UNIX */
newPathFile->InitWithFile(newProfilePath);
}
else
{
nsCAutoString leafname;
newPathFile->InitWithFile(oldPathFile);
rv = newPathFile->GetNativeLeafName(leafname);
if (NS_FAILED(rv)) return rv;
leafname.Append(NS_LITERAL_CSTRING(NEW_DIR_SUFFIX));
rv = newPathFile->SetNativeLeafName(leafname);
if (NS_FAILED(rv)) return rv;
}
rv = SetPremigratedFilePref(pref, oldPathFile);
if (NS_FAILED(rv)) return rv;
#ifdef XP_UNIX
/* on UNIX, we kept the newsrc files in "news.directory", (which was usually ~)
* and the summary files in ~/.netscape/xover-cache
* oldPath should point to ~/.netscape/xover-cache, not "news.directory"
* but we want to save the old "news.directory" in "premigration.news.directory"
* later, again for UNIX only,
* we will copy the .newsrc files (from "news.directory") into the new <profile>/News directory.
* isn't this fun?
*/
if (PL_strcmp(PREF_NEWS_DIRECTORY, pref) == 0) {
rv = oldProfilePath->AppendNative(NS_LITERAL_CSTRING(OLD_NEWS_DIR_NAME));
if (NS_FAILED(rv)) return rv;
}
#endif /* XP_UNIX */
NS_IF_ADDREF(*newPath = newPathFile);
NS_IF_ADDREF(*oldPath = oldPathFile);
return rv;
}
nsresult nsDogbertProfileMigrator::SetPremigratedFilePref(const char *pref_name, nsILocalFile *pathFile)
{
nsresult rv;
if (!pref_name) return NS_ERROR_FAILURE;
// save off the old pref, prefixed with "premigration"
// for example, we need the old "mail.directory" pref when
// migrating the copies and folder prefs in nsMsgAccountManager.cpp
//
// note we do this for all platforms.
char premigration_pref[MAX_PREF_LEN];
PR_snprintf(premigration_pref,MAX_PREF_LEN,"%s%s",PREMIGRATION_PREFIX,pref_name);
PRBool exists = PR_FALSE;
pathFile->Exists(&exists);
NS_ASSERTION(exists, "the path does not exist. see bug #55444");
if (!exists) return NS_OK;
rv = mPrefs->SetComplexValue((const char *)premigration_pref, NS_GET_IID(nsILocalFile), pathFile);
return rv;
}
nsresult nsDogbertProfileMigrator::ComputeSpaceRequirements(PRInt64 DriveArray[MAX_DRIVES],
PRUint32 SpaceReqArray[MAX_DRIVES],
PRInt64 Drive,
PRUint32 SpaceNeeded)
{
int i=0;
PRFloat64 temp;
while(LL_NE(DriveArray[i],LL_Zero()) && LL_NE(DriveArray[i], Drive) && i < MAX_DRIVES)
i++;
if (LL_EQ(DriveArray[i], LL_Zero()))
{
DriveArray[i] = Drive;
SpaceReqArray[i] += SpaceNeeded;
}
else if (LL_EQ(DriveArray[i], Drive))
SpaceReqArray[i] += SpaceNeeded;
else
return NS_ERROR_FAILURE;
LL_L2F(temp, DriveArray[i]);
if (SpaceReqArray[i] > temp)
return NS_ERROR_FAILURE;
return NS_OK;
}
static PRBool
nsCStringEndsWith(nsCString& name, const char *ending)
{
if (!ending) return PR_FALSE;
PRInt32 len = name.Length();
if (len == 0) return PR_FALSE;
PRInt32 endingLen = PL_strlen(ending);
if (len > endingLen && name.RFind(ending, PR_TRUE) == len - endingLen) {
return PR_TRUE;
}
else {
return PR_FALSE;
}
}
#ifdef NEED_TO_COPY_AND_RENAME_NEWSRC_FILES
static PRBool
nsCStringStartsWith(nsCString& name, const char *starting)
{
if (!starting) return PR_FALSE;
PRInt32 len = name.Length();
if (len == 0) return PR_FALSE;
PRInt32 startingLen = PL_strlen(starting);
if (len > startingLen && name.RFind(starting, PR_TRUE) == 0) {
return PR_TRUE;
}
else {
return PR_FALSE;
}
}
#endif
////////////////////////////////////////////////////////////////////////
// nsPrefConverter
////////////////////////////////////////////////////////////////////////
/*
these are the prefs we know we need to convert to utf8.
we'll also be converting:
Please make sure that any pref that contains native characters
in it's value is not included in this list as we do not want to
convert them into UTF-8 format. Prefs are being get and set in a
unicode format (FileXPref) now and there is no need for
conversion of those prefs.
"ldap_2.server.*.description"
"intl.font*.fixed_font"
"intl.font*.prop_font"
"mail.identity.vcard.*"
*/
static const char *prefsToConvert[] = {
"li.server.ldap.userbase",
"mail.identity.organization",
"mail.identity.username",
nsnull
};
nsPrefConverter::~nsPrefConverter()
{}
nsPrefConverter::nsPrefConverter()
{}
// Apply a charset conversion from the given charset to UTF-8 for the input C string.
static nsresult ConvertStringToUTF8(const char* aCharset, const char* inString, char** outString)
{
if (nsnull == outString)
return NS_ERROR_NULL_POINTER;
nsresult rv;
// convert result to unicode
nsCOMPtr<nsICharsetConverterManager> ccm = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
if(NS_SUCCEEDED(rv)) {
nsCOMPtr <nsIUnicodeDecoder> decoder; // this may be cached
rv = ccm->GetUnicodeDecoderRaw(aCharset, getter_AddRefs(decoder));
if(NS_SUCCEEDED(rv) && decoder) {
PRInt32 uniLength = 0;
PRInt32 srcLength = strlen(inString);
rv = decoder->GetMaxLength(inString, srcLength, &uniLength);
if (NS_SUCCEEDED(rv)) {
PRUnichar *unichars = new PRUnichar [uniLength];
if (nsnull != unichars) {
// convert to unicode
rv = decoder->Convert(inString, &srcLength, unichars, &uniLength);
if (NS_SUCCEEDED(rv)) {
nsAutoString aString;
aString.Assign(unichars, uniLength);
// convert to UTF-8
*outString = ToNewUTF8String(aString);
}
delete [] unichars;
}
else {
rv = NS_ERROR_OUT_OF_MEMORY;
}
}
}
}
return rv;
}
nsresult ConvertPrefToUTF8(const char *prefname, nsIPrefBranch *prefs, const char* charSet)
{
nsresult rv;
if (!prefname || !prefs) return NS_ERROR_FAILURE;
nsCString prefval;
rv = prefs->GetCharPref(prefname, getter_Copies(prefval));
if (NS_FAILED(rv)) return rv;
if (prefval.IsEmpty())
return NS_OK;
nsCString outval;
rv = ConvertStringToUTF8(charSet, prefval.get(), getter_Copies(outval));
// only set the pref if the conversion worked, and it convert to something non null
if (NS_SUCCEEDED(rv) && !outval.IsEmpty())
rv = prefs->SetCharPref(prefname, outval.get());
return NS_OK;
}
static PRBool charEndsWith(const char *str, const char *endStr)
{
PRUint32 endStrLen = PL_strlen(endStr);
PRUint32 strLen = PL_strlen(str);
if (strLen < endStrLen) return PR_FALSE;
PRUint32 pos = strLen - endStrLen;
if (PL_strncmp(str + pos, endStr, endStrLen) == 0)
return PR_TRUE;
else
return PR_FALSE;
}
static void getFontPrefs(nsIPrefBranch *prefs, nsCStringArray *data)
{
PRUint32 count, i;
char** childPrefs;
prefs->GetChildList("intl.font", &count, &childPrefs);
for (i = 0; i < count; ++i)
{
if (charEndsWith(childPrefs[i], ".fixed_font") || charEndsWith(childPrefs[i], ".prop_font"))
data->AppendCString(nsDependentCString(childPrefs[i]));
}
}
static void getLdapPrefs(nsIPrefBranch *prefs, nsCStringArray *data)
{
PRUint32 count, i;
char** childPrefs;
prefs->GetChildList("ldap_2.servers", &count, &childPrefs);
for (i = 0; i < count; ++i)
{
// we only want to convert "ldap_2.servers.*.description"
if (charEndsWith(childPrefs[i], ".description"))
data->AppendCString(nsDependentCString(childPrefs[i]));
}
}
static void getVCardPrefs(nsIPrefBranch *prefs, nsCStringArray *data)
{
PRUint32 count, i;
char** childPrefs;
prefs->GetChildList("mail.identity.vcard", &count, &childPrefs);
// the 4.x vCard prefs might need converting
for (i = 0; i < count; ++i)
data->AppendCString(nsDependentCString(childPrefs[i]));
}
typedef struct {
nsIPrefBranch *prefs;
const char* charSet;
} PrefEnumerationClosure;
PRBool convertPref(nsCString &aElement, void *aData)
{
PrefEnumerationClosure *closure;
closure = (PrefEnumerationClosure *)aData;
ConvertPrefToUTF8(aElement.get(), closure->prefs, closure->charSet);
return PR_TRUE;
}
nsresult nsPrefConverter::ConvertPrefsToUTF8()
{
nsresult rv;
nsCStringArray prefsToMigrate;
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if(NS_FAILED(rv)) return rv;
nsCAutoString charSet;
rv = GetPlatformCharset(charSet);
if (NS_FAILED(rv)) return rv;
for (PRUint32 i = 0; prefsToConvert[i]; i++) {
nsCString prefnameStr( prefsToConvert[i] );
prefsToMigrate.AppendCString(prefnameStr);
}
getFontPrefs(prefs, &prefsToMigrate);
getLdapPrefs(prefs, &prefsToMigrate);
getVCardPrefs(prefs, &prefsToMigrate);
PrefEnumerationClosure closure;
closure.prefs = prefs;
closure.charSet = charSet.get();
prefsToMigrate.EnumerateForwards((nsCStringArrayEnumFunc)convertPref, (void *)(&closure));
rv = prefs->SetBoolPref("prefs.converted-to-utf8",PR_TRUE);
return NS_OK;
}
// A wrapper function to call the interface to get a platform file charset.
nsresult
nsPrefConverter::GetPlatformCharset(nsCString& aCharset)
{
nsresult rv;
// we may cache it since the platform charset will not change through application life
nsCOMPtr <nsIPlatformCharset> platformCharset = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv) && platformCharset)
rv = platformCharset->GetCharset(kPlatformCharsetSel_4xPrefsJS, aCharset);
if (NS_FAILED(rv))
aCharset.Assign(NS_LITERAL_CSTRING("ISO-8859-1")); // use ISO-8859-1 in case of any error
return rv;
}