Mozilla/mozilla/mail/components/migration/src/nsSeamonkeyProfileMigrator.cpp
scott%scott-macgregor.org 3472948f44 Bug #379070--> remove nsCRT methods from mail\components.
r=prasad


git-svn-id: svn://10.0.0.236/trunk@227817 18797224-902f-48f8-a5cc-f745e15eee43
2007-06-11 15:20:09 +00:00

937 lines
33 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 Ben Goodger.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Goodger <ben@bengoodger.com>
* 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 ***** */
#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 "nsSeamonkeyProfileMigrator.h"
#include "nsIRelativeFilePref.h"
#include "nsAppDirectoryServiceDefs.h"
#include "prprf.h"
#include "nsVoidArray.h"
#include "msgCore.h"
static PRUint32 StringHash(const char *ubuf);
nsresult NS_MsgHashIfNecessary(nsCString &name);
// Mail specific folder paths
#define MAIL_DIR_50_NAME NS_LITERAL_STRING("Mail")
#define IMAP_MAIL_DIR_50_NAME NS_LITERAL_STRING("ImapMail")
#define NEWS_DIR_50_NAME NS_LITERAL_STRING("News")
///////////////////////////////////////////////////////////////////////////////
// nsSeamonkeyProfileMigrator
#define FILE_NAME_JUNKTRAINING NS_LITERAL_STRING("training.dat")
#define FILE_NAME_PERSONALDICTIONARY NS_LITERAL_STRING("persdict.dat")
#define FILE_NAME_PERSONAL_ADDRESSBOOK NS_LITERAL_STRING("abook.mab")
#define FILE_NAME_MAILVIEWS NS_LITERAL_STRING("mailviews.dat")
#define FILE_NAME_CERT8DB NS_LITERAL_STRING("cert8.db")
#define FILE_NAME_KEY3DB NS_LITERAL_STRING("key3.db")
#define FILE_NAME_SECMODDB NS_LITERAL_STRING("secmod.db")
#define FILE_NAME_MIMETYPES NS_LITERAL_STRING("mimeTypes.rdf")
#define FILE_NAME_PREFS NS_LITERAL_STRING("prefs.js")
#define FILE_NAME_USER_PREFS NS_LITERAL_STRING("user.js")
struct PrefBranchStruct {
char* prefName;
PRInt32 type;
union {
char* stringValue;
PRInt32 intValue;
PRBool boolValue;
PRUnichar* wstringValue;
};
};
NS_IMPL_ISUPPORTS2(nsSeamonkeyProfileMigrator, nsIMailProfileMigrator, nsITimerCallback)
nsSeamonkeyProfileMigrator::nsSeamonkeyProfileMigrator()
{
mObserverService = do_GetService("@mozilla.org/observer-service;1");
mMaxProgress = LL_ZERO;
mCurrentProgress = LL_ZERO;
}
nsSeamonkeyProfileMigrator::~nsSeamonkeyProfileMigrator()
{
}
///////////////////////////////////////////////////////////////////////////////
// nsITimerCallback
NS_IMETHODIMP
nsSeamonkeyProfileMigrator::Notify(nsITimer *timer)
{
CopyNextFolder();
return NS_OK;
}
void nsSeamonkeyProfileMigrator::CopyNextFolder()
{
if (mFileCopyTransactionIndex < mFileCopyTransactions->Count())
{
PRUint32 percentage = 0;
fileTransactionEntry* fileTransaction = (fileTransactionEntry*) mFileCopyTransactions->SafeElementAt(mFileCopyTransactionIndex++);
if (fileTransaction) // copy the file
{
fileTransaction->srcFile->CopyTo(fileTransaction->destFile, EmptyString());
// 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 nsSeamonkeyProfileMigrator::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
nsSeamonkeyProfileMigrator::Migrate(PRUint16 aItems, nsIProfileStartup* aStartup, const PRUnichar* aProfile)
{
nsresult rv = NS_OK;
PRBool aReplace = aStartup ? PR_TRUE : PR_FALSE;
if (!mTargetProfile) {
GetProfilePath(aStartup, mTargetProfile);
if (!mTargetProfile) return NS_ERROR_FAILURE;
}
if (!mSourceProfile)
GetSourceProfile(aProfile);
NOTIFY_OBSERVERS(MIGRATION_STARTED, nsnull);
COPY_DATA(CopyPreferences, aReplace, nsIMailProfileMigrator::SETTINGS);
// fake notifications for things we've already imported as part of CopyPreferences
COPY_DATA(DummyCopyRoutine, aReplace, nsIMailProfileMigrator::ACCOUNT_SETTINGS);
COPY_DATA(DummyCopyRoutine, aReplace, nsIMailProfileMigrator::NEWSDATA);
// copy junk mail training file
COPY_DATA(CopyJunkTraining, aReplace, nsIMailProfileMigrator::JUNKTRAINING);
COPY_DATA(CopyPasswords, aReplace, nsIMailProfileMigrator::PASSWORDS);
// the last thing to do is to actually copy over any mail folders we have marked for copying
// we want to do this last and it will be asynchronous so the UI doesn't freeze up while we perform
// this potentially very long operation.
nsAutoString index;
index.AppendInt(nsIMailProfileMigrator::MAILDATA);
NOTIFY_OBSERVERS(MIGRATION_ITEMBEFOREMIGRATE, index.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 rv;
}
NS_IMETHODIMP
nsSeamonkeyProfileMigrator::GetMigrateData(const PRUnichar* aProfile,
PRBool aReplace,
PRUint16* aResult)
{
*aResult = 0;
if (!mSourceProfile) {
GetSourceProfile(aProfile);
if (!mSourceProfile)
return NS_ERROR_FILE_NOT_FOUND;
}
MigrationData data[] = { { ToNewUnicode(FILE_NAME_PREFS),
nsIMailProfileMigrator::SETTINGS,
PR_TRUE },
{ ToNewUnicode(FILE_NAME_JUNKTRAINING),
nsIMailProfileMigrator::JUNKTRAINING,
PR_TRUE },
};
// Frees file name strings allocated above.
GetMigrateDataFromArray(data, sizeof(data)/sizeof(MigrationData),
aReplace, mSourceProfile, aResult);
// Now locate passwords
nsCString signonsFileName;
GetSignonFileName(aReplace, getter_Copies(signonsFileName));
if (!signonsFileName.IsEmpty()) {
nsAutoString fileName;
CopyASCIItoUTF16(signonsFileName, fileName);
nsCOMPtr<nsIFile> sourcePasswordsFile;
mSourceProfile->Clone(getter_AddRefs(sourcePasswordsFile));
sourcePasswordsFile->Append(fileName);
PRBool exists;
sourcePasswordsFile->Exists(&exists);
if (exists)
*aResult |= nsIMailProfileMigrator::PASSWORDS;
}
// 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
nsSeamonkeyProfileMigrator::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
nsSeamonkeyProfileMigrator::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;
}
NS_IMETHODIMP
nsSeamonkeyProfileMigrator::GetSourceProfiles(nsISupportsArray** aResult)
{
if (!mProfileNames && !mProfileLocations) {
nsresult rv = NS_NewISupportsArray(getter_AddRefs(mProfileNames));
if (NS_FAILED(rv)) return rv;
rv = NS_NewISupportsArray(getter_AddRefs(mProfileLocations));
if (NS_FAILED(rv)) return rv;
// Fills mProfileNames and mProfileLocations
FillProfileDataFromSeamonkeyRegistry();
}
NS_IF_ADDREF(*aResult = mProfileNames);
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////
// nsSeamonkeyProfileMigrator
nsresult
nsSeamonkeyProfileMigrator::GetSourceProfile(const PRUnichar* aProfile)
{
PRUint32 count;
mProfileNames->Count(&count);
for (PRUint32 i = 0; i < count; ++i) {
nsCOMPtr<nsISupportsString> str(do_QueryElementAt(mProfileNames, i));
nsString profileName;
str->GetData(profileName);
if (profileName.Equals(aProfile)) {
mSourceProfile = do_QueryElementAt(mProfileLocations, i);
break;
}
}
return NS_OK;
}
nsresult
nsSeamonkeyProfileMigrator::FillProfileDataFromSeamonkeyRegistry()
{
// Find the Seamonkey Registry
nsCOMPtr<nsIProperties> fileLocator(do_GetService("@mozilla.org/file/directory_service;1"));
nsCOMPtr<nsILocalFile> seamonkeyRegistry;
#ifdef XP_WIN
fileLocator->Get(NS_WIN_APPDATA_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(seamonkeyRegistry));
NS_ENSURE_TRUE(seamonkeyRegistry, NS_ERROR_FAILURE);
seamonkeyRegistry->Append(NS_LITERAL_STRING("Mozilla"));
seamonkeyRegistry->Append(NS_LITERAL_STRING("registry.dat"));
#elif defined(XP_MACOSX)
fileLocator->Get(NS_MAC_USER_LIB_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(seamonkeyRegistry));
NS_ENSURE_TRUE(seamonkeyRegistry, NS_ERROR_FAILURE);
seamonkeyRegistry->Append(NS_LITERAL_STRING("Mozilla"));
seamonkeyRegistry->Append(NS_LITERAL_STRING("Application Registry"));
#elif defined(XP_UNIX)
fileLocator->Get(NS_UNIX_HOME_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(seamonkeyRegistry));
NS_ENSURE_TRUE(seamonkeyRegistry, NS_ERROR_FAILURE);
seamonkeyRegistry->Append(NS_LITERAL_STRING(".mozilla"));
seamonkeyRegistry->Append(NS_LITERAL_STRING("appreg"));
#elif defined(XP_OS2)
fileLocator->Get(NS_OS2_HOME_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(seamonkeyRegistry));
NS_ENSURE_TRUE(seamonkeyRegistry, NS_ERROR_FAILURE);
seamonkeyRegistry->Append(NS_LITERAL_STRING("Mozilla"));
seamonkeyRegistry->Append(NS_LITERAL_STRING("registry.dat"));
#endif
return GetProfileDataFromRegistry(seamonkeyRegistry, mProfileNames, mProfileLocations);
}
#define F(a) nsSeamonkeyProfileMigrator::a
#define MAKEPREFTRANSFORM(pref, newpref, getmethod, setmethod) \
{ pref, newpref, F(Get##getmethod), F(Set##setmethod), PR_FALSE, -1 }
#define MAKESAMETYPEPREFTRANSFORM(pref, method) \
{ pref, 0, F(Get##method), F(Set##method), PR_FALSE, -1 }
static
nsSeamonkeyProfileMigrator::PrefTransform gTransforms[] = {
MAKESAMETYPEPREFTRANSFORM("signon.SignonFileName", String),
MAKESAMETYPEPREFTRANSFORM("mailnews.headers.showUserAgent", Bool),
MAKESAMETYPEPREFTRANSFORM("mailnews.headers.showOrganization", Bool),
MAKESAMETYPEPREFTRANSFORM("mail.collect_addressbook", String),
MAKESAMETYPEPREFTRANSFORM("mail.collect_email_address_outgoing", Bool),
MAKESAMETYPEPREFTRANSFORM("mail.wrap_long_lines", Bool),
MAKESAMETYPEPREFTRANSFORM("news.wrap_long_lines", Bool),
MAKESAMETYPEPREFTRANSFORM("mailnews.customHeaders", String),
MAKESAMETYPEPREFTRANSFORM("mail.default_html_action", Int),
MAKESAMETYPEPREFTRANSFORM("mail.forward_message_mode", Int),
MAKESAMETYPEPREFTRANSFORM("mail.SpellCheckBeforeSend", Bool),
MAKESAMETYPEPREFTRANSFORM("mail.warn_on_send_accel_key", Bool),
MAKESAMETYPEPREFTRANSFORM("mailnews.html_domains", String),
MAKESAMETYPEPREFTRANSFORM("mailnews.plaintext_domains", String),
MAKESAMETYPEPREFTRANSFORM("mailnews.headers.showUserAgent", Bool),
MAKESAMETYPEPREFTRANSFORM("mailnews.headers.showOrganization", Bool),
MAKESAMETYPEPREFTRANSFORM("mail.biff.play_sound", Bool),
MAKESAMETYPEPREFTRANSFORM("mail.biff.play_sound.type", Int),
MAKESAMETYPEPREFTRANSFORM("mail.biff.play_sound.url", String),
MAKESAMETYPEPREFTRANSFORM("mail.biff.show_alert", Bool),
MAKESAMETYPEPREFTRANSFORM("network.proxy.type", Int),
MAKESAMETYPEPREFTRANSFORM("network.proxy.http", String),
MAKESAMETYPEPREFTRANSFORM("network.proxy.http_port", Int),
MAKESAMETYPEPREFTRANSFORM("network.proxy.ftp", String),
MAKESAMETYPEPREFTRANSFORM("network.proxy.ftp_port", Int),
MAKESAMETYPEPREFTRANSFORM("network.proxy.ssl", String),
MAKESAMETYPEPREFTRANSFORM("network.proxy.ssl_port", Int),
MAKESAMETYPEPREFTRANSFORM("network.proxy.socks", String),
MAKESAMETYPEPREFTRANSFORM("network.proxy.socks_port", Int),
MAKESAMETYPEPREFTRANSFORM("network.proxy.gopher", String),
MAKESAMETYPEPREFTRANSFORM("network.proxy.gopher_port", Int),
MAKESAMETYPEPREFTRANSFORM("network.proxy.no_proxies_on", String),
MAKESAMETYPEPREFTRANSFORM("network.proxy.autoconfig_url", String),
MAKESAMETYPEPREFTRANSFORM("mail.accountmanager.accounts", String),
MAKESAMETYPEPREFTRANSFORM("mail.accountmanager.defaultaccount", String),
MAKESAMETYPEPREFTRANSFORM("mail.accountmanager.localfoldersserver", String),
MAKESAMETYPEPREFTRANSFORM("mail.smtp.defaultserver", String),
MAKESAMETYPEPREFTRANSFORM("mail.smtpservers", String),
MAKESAMETYPEPREFTRANSFORM("msgcompose.font_face", String),
MAKESAMETYPEPREFTRANSFORM("msgcompose.font_size", String),
MAKESAMETYPEPREFTRANSFORM("msgcompose.text_color", String),
MAKESAMETYPEPREFTRANSFORM("msgcompose.background_color", String),
MAKEPREFTRANSFORM("mail.pane_config","mail.pane_config.dynamic", Int, Int)
};
nsresult
nsSeamonkeyProfileMigrator::TransformPreferences(const nsAString& aSourcePrefFileName,
const nsAString& aTargetPrefFileName)
{
PrefTransform* transform;
PrefTransform* end = gTransforms + sizeof(gTransforms)/sizeof(PrefTransform);
// Load the source pref file
nsCOMPtr<nsIPrefService> psvc(do_GetService(NS_PREFSERVICE_CONTRACTID));
psvc->ResetPrefs();
nsCOMPtr<nsIFile> sourcePrefsFile;
mSourceProfile->Clone(getter_AddRefs(sourcePrefsFile));
sourcePrefsFile->Append(aSourcePrefFileName);
psvc->ReadUserPrefs(sourcePrefsFile);
nsCOMPtr<nsIPrefBranch> branch(do_QueryInterface(psvc));
for (transform = gTransforms; transform < end; ++transform)
transform->prefGetterFunc(transform, branch);
// read in the various pref branch trees for accounts, identities, servers, etc.
nsVoidArray* accounts = new nsVoidArray();
nsVoidArray* identities = new nsVoidArray();
nsVoidArray* servers = new nsVoidArray();
nsVoidArray* smtpservers = new nsVoidArray();
nsVoidArray* ldapservers = new nsVoidArray();
nsVoidArray* labelPrefs = new nsVoidArray();
if (!accounts || !identities || !servers || !smtpservers || !ldapservers)
return NS_ERROR_OUT_OF_MEMORY;
ReadBranch("mail.account.", psvc, accounts);
ReadBranch("mail.identity.", psvc, identities);
ReadBranch("mail.server.", psvc, servers);
ReadBranch("mail.smtpserver.", psvc, smtpservers);
ReadBranch("ldap_2.servers.", psvc, ldapservers);
ReadBranch("mailnews.labels.", psvc, labelPrefs);
// the signature file prefs may be paths to files in the seamonkey profile path
// so we need to copy them over and fix these paths up before we write them out to the new prefs.js
CopySignatureFiles(identities, psvc);
// certain mail prefs may actually be absolute paths instead of profile relative paths
// we need to fix these paths up before we write them out to the new prefs.js
CopyMailFolders(servers, psvc);
CopyAddressBookDirectories(ldapservers, psvc);
// Now that we have all the pref data in memory, load the target pref file,
// and write it back out
psvc->ResetPrefs();
for (transform = gTransforms; transform < end; ++transform)
transform->prefSetterFunc(transform, branch);
WriteBranch("mail.account.", psvc, accounts);
WriteBranch("mail.identity.", psvc, identities);
WriteBranch("mail.server.", psvc, servers);
WriteBranch("mail.smtpserver.", psvc, smtpservers);
WriteBranch("ldap_2.servers.", psvc, ldapservers);
WriteBranch("mailnews.labels.", psvc, labelPrefs);
delete accounts;
delete identities;
delete servers;
delete smtpservers;
delete ldapservers;
delete labelPrefs;
nsCOMPtr<nsIFile> targetPrefsFile;
mTargetProfile->Clone(getter_AddRefs(targetPrefsFile));
targetPrefsFile->Append(aTargetPrefFileName);
psvc->SavePrefFile(targetPrefsFile);
return NS_OK;
}
nsresult nsSeamonkeyProfileMigrator::CopyAddressBookDirectories(nsVoidArray* aLdapServers, nsIPrefService* aPrefService)
{
// each server has a pref ending with .filename. The value of that pref points to a profile which we
// need to migrate.
nsAutoString index;
index.AppendInt(nsIMailProfileMigrator::ADDRESSBOOK_DATA);
NOTIFY_OBSERVERS(MIGRATION_ITEMBEFOREMIGRATE, index.get());
PRUint32 count = aLdapServers->Count();
for (PRUint32 i = 0; i < count; ++i)
{
PrefBranchStruct* pref = (PrefBranchStruct*) aLdapServers->ElementAt(i);
nsDependentCString prefName (pref->prefName);
if (StringEndsWith(prefName, nsDependentCString(".filename")))
{
// should we be assuming utf-8 or ascii here?
CopyFile(NS_ConvertUTF8toUTF16(pref->stringValue), NS_ConvertUTF8toUTF16(pref->stringValue));
}
// we don't need to do anything to the fileName pref itself
}
NOTIFY_OBSERVERS(MIGRATION_ITEMAFTERMIGRATE, index.get());
return NS_OK;
}
nsresult nsSeamonkeyProfileMigrator::CopySignatureFiles(nsVoidArray* aIdentities, nsIPrefService* aPrefService)
{
nsresult rv = NS_OK;
PRUint32 count = aIdentities->Count();
for (PRUint32 i = 0; i < count; ++i)
{
PrefBranchStruct* pref = (PrefBranchStruct*)aIdentities->ElementAt(i);
nsDependentCString prefName (pref->prefName);
// a partial fix for bug #255043
// if the user's signature file from seamonkey lives in the
// seamonkey profile root, we'll copy it over to the new
// thunderbird profile root and thenn set the pref to the new value
// note, this doesn't work for multiple signatures that live
// below the seamonkey profile root
if (StringEndsWith(prefName, nsDependentCString(".sig_file")))
{
// turn the pref into a nsILocalFile
nsCOMPtr<nsILocalFile> srcSigFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
srcSigFile->SetPersistentDescriptor(nsDependentCString(pref->stringValue));
nsCOMPtr<nsIFile> targetSigFile;
rv = mTargetProfile->Clone(getter_AddRefs(targetSigFile));
NS_ENSURE_SUCCESS(rv, rv);
// now make the copy
PRBool exists;
srcSigFile->Exists(&exists);
if (exists)
{
nsAutoString leafName;
srcSigFile->GetLeafName(leafName);
srcSigFile->CopyTo(targetSigFile,leafName); // will fail if we've already copied a sig file here
targetSigFile->Append(leafName);
// now write out the new descriptor
nsCAutoString descriptorString;
nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(targetSigFile);
localFile->GetPersistentDescriptor(descriptorString);
NS_Free(pref->stringValue);
pref->stringValue = ToNewCString(descriptorString);
}
}
}
return NS_OK;
}
nsresult nsSeamonkeyProfileMigrator::CopyMailFolders(nsVoidArray* aMailServers, nsIPrefService* aPrefService)
{
// Each server has a .directory pref which points to the location of the mail data
// for that server. We need to do two things for that case...
// (1) Fix up the directory path for the new profile
// (2) copy the mail folder data from the source directory pref to the destination directory pref
nsresult rv = NS_OK;
PRUint32 count = aMailServers->Count();
for (PRUint32 i = 0; i < count; ++i)
{
PrefBranchStruct* pref = (PrefBranchStruct*)aMailServers->ElementAt(i);
nsDependentCString prefName (pref->prefName);
if (StringEndsWith(prefName, NS_LITERAL_CSTRING(".directory-rel"))) {
// When the directories are modified below, we may change the .directory
// pref. As we don't have a pref branch to modify at this stage and set
// up the relative folders properly, we'll just remove all the
// *.directory-rel prefs. Mailnews will cope with this, creating them
// when it first needs them.
if (pref->type == nsIPrefBranch::PREF_STRING)
NS_Free(pref->stringValue);
aMailServers->RemoveElementAt(i);
// Now decrease i and count to match the removed element
--i;
--count;
}
else if (StringEndsWith(prefName, nsDependentCString(".directory")))
{
// let's try to get a branch for this particular server to simplify things
prefName.Cut( prefName.Length() - strlen("directory"), strlen("directory"));
prefName.Insert("mail.server.", 0);
nsCOMPtr<nsIPrefBranch> serverBranch;
aPrefService->GetBranch(prefName.get(), getter_AddRefs(serverBranch));
if (!serverBranch)
break; // should we clear out this server pref from aMailServers?
nsCString serverType;
serverBranch->GetCharPref("type", getter_Copies(serverType));
nsCOMPtr<nsILocalFile> sourceMailFolder;
serverBranch->GetComplexValue("directory", NS_GET_IID(nsILocalFile), getter_AddRefs(sourceMailFolder));
// now based on type, we need to build a new destination path for the mail folders for this server
nsCOMPtr<nsIFile> targetMailFolder;
if (serverType.Equals("imap"))
{
mTargetProfile->Clone(getter_AddRefs(targetMailFolder));
targetMailFolder->Append(IMAP_MAIL_DIR_50_NAME);
}
else if (serverType.Equals("none") || serverType.Equals("pop3"))
{
// local folders and POP3 servers go under <profile>\Mail
mTargetProfile->Clone(getter_AddRefs(targetMailFolder));
targetMailFolder->Append(MAIL_DIR_50_NAME);
}
else if (serverType.Equals("nntp"))
{
mTargetProfile->Clone(getter_AddRefs(targetMailFolder));
targetMailFolder->Append(NEWS_DIR_50_NAME);
}
if (targetMailFolder)
{
// for all of our server types, append the host name to the directory as part of the new location
nsCString hostName;
serverBranch->GetCharPref("hostname", getter_Copies(hostName));
targetMailFolder->Append(NS_ConvertASCIItoUTF16(hostName));
// we should make sure the host name based directory we are going to migrate
// the accounts into is unique. This protects against the case where the user
// has multiple servers with the same host name.
targetMailFolder->CreateUnique(nsIFile::DIRECTORY_TYPE, 0777);
rv = RecursiveCopy(sourceMailFolder, targetMailFolder);
// now we want to make sure the actual directory pref that gets
// transformed into the new profile's pref.js has the right file
// location.
nsCAutoString descriptorString;
nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(targetMailFolder);
localFile->GetPersistentDescriptor(descriptorString);
NS_Free(pref->stringValue);
pref->stringValue = ToNewCString(descriptorString);
}
}
else if (StringEndsWith(prefName, nsDependentCString(".newsrc.file")))
{
// copy the news RC file into \News. this won't work if the user has different newsrc files for each account
// I don't know what to do in that situation.
nsCOMPtr<nsIFile> targetNewsRCFile;
mTargetProfile->Clone(getter_AddRefs(targetNewsRCFile));
targetNewsRCFile->Append(NEWS_DIR_50_NAME);
// turn the pref into a nsILocalFile
nsCOMPtr<nsILocalFile> srcNewsRCFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
srcNewsRCFile->SetPersistentDescriptor(nsDependentCString(pref->stringValue));
// now make the copy
PRBool exists;
srcNewsRCFile->Exists(&exists);
if (exists)
{
nsAutoString leafName;
srcNewsRCFile->GetLeafName(leafName);
srcNewsRCFile->CopyTo(targetNewsRCFile,leafName); // will fail if we've already copied a newsrc file here
targetNewsRCFile->Append(leafName);
// now write out the new descriptor
nsCAutoString descriptorString;
nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(targetNewsRCFile);
localFile->GetPersistentDescriptor(descriptorString);
NS_Free(pref->stringValue);
pref->stringValue = ToNewCString(descriptorString);
}
}
}
return NS_OK;
}
nsresult
nsSeamonkeyProfileMigrator::CopyPreferences(PRBool aReplace)
{
nsresult rv = NS_OK;
if (!aReplace)
return rv;
rv |= TransformPreferences(FILE_NAME_PREFS, FILE_NAME_PREFS);
rv |= CopyFile(FILE_NAME_USER_PREFS, FILE_NAME_USER_PREFS);
// Security Stuff
rv |= CopyFile(FILE_NAME_CERT8DB, FILE_NAME_CERT8DB);
rv |= CopyFile(FILE_NAME_KEY3DB, FILE_NAME_KEY3DB);
rv |= CopyFile(FILE_NAME_SECMODDB, FILE_NAME_SECMODDB);
// User MIME Type overrides
rv |= CopyFile(FILE_NAME_MIMETYPES, FILE_NAME_MIMETYPES);
rv |= CopyFile(FILE_NAME_PERSONALDICTIONARY, FILE_NAME_PERSONALDICTIONARY);
rv |= CopyFile(FILE_NAME_MAILVIEWS, FILE_NAME_MAILVIEWS);
return rv;
}
void nsSeamonkeyProfileMigrator::ReadBranch(const char * branchName, nsIPrefService* aPrefService,
nsVoidArray* aPrefs)
{
// Enumerate the branch
nsCOMPtr<nsIPrefBranch> branch;
aPrefService->GetBranch(branchName, getter_AddRefs(branch));
PRUint32 count;
char** prefs = nsnull;
nsresult rv = branch->GetChildList("", &count, &prefs);
if (NS_FAILED(rv)) return;
for (PRUint32 i = 0; i < count; ++i) {
// Save each pref's value into an array
char* currPref = prefs[i];
PRInt32 type;
branch->GetPrefType(currPref, &type);
PrefBranchStruct* pref = new PrefBranchStruct;
pref->prefName = currPref;
pref->type = type;
switch (type) {
case nsIPrefBranch::PREF_STRING:
rv = branch->GetCharPref(currPref, &pref->stringValue);
break;
case nsIPrefBranch::PREF_BOOL:
rv = branch->GetBoolPref(currPref, &pref->boolValue);
break;
case nsIPrefBranch::PREF_INT:
rv = branch->GetIntPref(currPref, &pref->intValue);
break;
case nsIPrefBranch::PREF_INVALID:
{
nsCOMPtr<nsIPrefLocalizedString> str;
rv = branch->GetComplexValue(currPref,
NS_GET_IID(nsIPrefLocalizedString),
getter_AddRefs(str));
if (NS_SUCCEEDED(rv) && str)
str->ToString(&pref->wstringValue);
}
break;
}
if (NS_SUCCEEDED(rv))
aPrefs->AppendElement((void*)pref);
}
}
void
nsSeamonkeyProfileMigrator::WriteBranch(const char * branchName, nsIPrefService* aPrefService,
nsVoidArray* aPrefs)
{
nsresult rv;
// Enumerate the branch
nsCOMPtr<nsIPrefBranch> branch;
aPrefService->GetBranch(branchName, getter_AddRefs(branch));
PRUint32 count = aPrefs->Count();
for (PRUint32 i = 0; i < count; ++i) {
PrefBranchStruct* pref = (PrefBranchStruct*)aPrefs->ElementAt(i);
switch (pref->type) {
case nsIPrefBranch::PREF_STRING:
rv = branch->SetCharPref(pref->prefName, pref->stringValue);
NS_Free(pref->stringValue);
pref->stringValue = nsnull;
break;
case nsIPrefBranch::PREF_BOOL:
rv = branch->SetBoolPref(pref->prefName, pref->boolValue);
break;
case nsIPrefBranch::PREF_INT:
rv = branch->SetIntPref(pref->prefName, pref->intValue);
break;
case nsIPrefBranch::PREF_INVALID:
nsCOMPtr<nsIPrefLocalizedString> pls(do_CreateInstance("@mozilla.org/pref-localizedstring;1"));
pls->SetData(pref->wstringValue);
rv = branch->SetComplexValue(pref->prefName,
NS_GET_IID(nsIPrefLocalizedString),
pls);
NS_Free(pref->wstringValue);
pref->wstringValue = nsnull;
break;
}
NS_Free(pref->prefName);
pref->prefName = nsnull;
delete pref;
pref = nsnull;
}
aPrefs->Clear();
}
nsresult nsSeamonkeyProfileMigrator::DummyCopyRoutine(PRBool aReplace)
{
// place holder function only to fake the UI out into showing some migration process.
return NS_OK;
}
nsresult
nsSeamonkeyProfileMigrator::CopyJunkTraining(PRBool aReplace)
{
return aReplace ? CopyFile(FILE_NAME_JUNKTRAINING, FILE_NAME_JUNKTRAINING) : NS_OK;
}
nsresult
nsSeamonkeyProfileMigrator::CopyPasswords(PRBool aReplace)
{
nsresult rv;
nsCString signonsFileName;
GetSignonFileName(aReplace, getter_Copies(signonsFileName));
if (signonsFileName.IsEmpty())
return NS_ERROR_FILE_NOT_FOUND;
nsAutoString fileName;
CopyASCIItoUTF16(signonsFileName, fileName);
if (aReplace)
rv = CopyFile(fileName, fileName);
else {
// don't do anything right now
}
return rv;
}
// helper functions for news migration
static PRUint32 StringHash(const char *ubuf)
{
unsigned char * buf = (unsigned char*) ubuf;
PRUint32 h=1;
while(*buf) {
h = 0x63c63cd9*h + 0x9c39c33d + (int32)*buf;
buf++;
}
return h;
}
nsresult NS_MsgHashIfNecessary(nsCString &name)
{
#if defined(XP_UNIX) || defined(XP_BEOS)
const PRUint32 MAX_LEN = 55;
#elif defined(XP_WIN32)
const PRUint32 MAX_LEN = 55;
#elif defined(XP_OS2)
const PRUint32 MAX_LEN = 55;
#else
#error need_to_define_your_max_filename_length
#endif
nsCAutoString illegalChars(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS);
nsCAutoString str(name);
// Given a filename, make it safe for filesystem
// certain filenames require hashing because they
// are too long or contain illegal characters
PRInt32 illegalCharacterIndex = str.FindCharInSet(illegalChars);
char hashedname[MAX_LEN + 1];
if (illegalCharacterIndex == kNotFound)
{
// no illegal chars, it's just too long
// keep the initial part of the string, but hash to make it fit
if (str.Length() > MAX_LEN)
{
PL_strncpy(hashedname, str.get(), MAX_LEN + 1);
PR_snprintf(hashedname + MAX_LEN - 8, 9, "%08lx",
(unsigned long) StringHash(str.get()));
name = hashedname;
}
}
else
{
// found illegal chars, hash the whole thing
// if we do substitution, then hash, two strings
// could hash to the same value.
// for example, on mac: "foo__bar", "foo:_bar", "foo::bar"
// would map to "foo_bar". this way, all three will map to
// different values
PR_snprintf(hashedname, 9, "%08lx",
(unsigned long) StringHash(str.get()));
name = hashedname;
}
return NS_OK;
}